diff --git a/packages/opencode/src/server/routes/instance/httpapi/groups/session.ts b/packages/opencode/src/server/routes/instance/httpapi/groups/session.ts
index bc26a9e597..e1e93b7d7c 100644
--- a/packages/opencode/src/server/routes/instance/httpapi/groups/session.ts
+++ b/packages/opencode/src/server/routes/instance/httpapi/groups/session.ts
@@ -10,7 +10,6 @@ import { SessionSummary } from "@/session/summary"
import { Todo } from "@/session/todo"
import { MessageID, PartID, SessionID } from "@/session/schema"
import { Snapshot } from "@/snapshot"
-import { NonNegativeInt } from "@/util/schema"
import { Schema, SchemaGetter, Struct } from "effect"
import { HttpApi, HttpApiEndpoint, HttpApiError, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/unstable/httpapi"
import { Authorization } from "../middleware/authorization"
@@ -45,7 +44,7 @@ export const UpdatePayload = Schema.Struct({
permission: Schema.optional(Permission.Ruleset),
time: Schema.optional(
Schema.Struct({
- archived: Schema.optional(NonNegativeInt),
+ archived: Schema.optional(Schema.Number),
}),
),
})
diff --git a/packages/opencode/src/session/session.ts b/packages/opencode/src/session/session.ts
index 1be5dfffd4..a3db293ef3 100644
--- a/packages/opencode/src/session/session.ts
+++ b/packages/opencode/src/session/session.ts
@@ -146,7 +146,7 @@ const Time = Schema.Struct({
created: NonNegativeInt,
updated: NonNegativeInt,
compacting: optionalOmitUndefined(NonNegativeInt),
- archived: optionalOmitUndefined(NonNegativeInt),
+ archived: optionalOmitUndefined(Schema.Number),
})
const Revert = Schema.Struct({
@@ -215,7 +215,7 @@ export const SetTitleInput = Schema.Struct({ sessionID: SessionID, title: Schema
)
export const SetArchivedInput = Schema.Struct({
sessionID: SessionID,
- time: Schema.optional(NonNegativeInt),
+ time: Schema.optional(Schema.Number),
}).pipe(withStatics((s) => ({ zod: zod(s) })))
export const SetPermissionInput = Schema.Struct({
sessionID: SessionID,
@@ -244,7 +244,7 @@ const UpdatedTime = Schema.Struct({
created: Schema.optional(Schema.NullOr(NonNegativeInt)),
updated: Schema.optional(Schema.NullOr(NonNegativeInt)),
compacting: Schema.optional(Schema.NullOr(NonNegativeInt)),
- archived: Schema.optional(Schema.NullOr(NonNegativeInt)),
+ archived: Schema.optional(Schema.NullOr(Schema.Number)),
})
const UpdatedInfo = Schema.Struct({
diff --git a/packages/opencode/test/server/httpapi-session.test.ts b/packages/opencode/test/server/httpapi-session.test.ts
index 593f9765c7..8e1987cedf 100644
--- a/packages/opencode/test/server/httpapi-session.test.ts
+++ b/packages/opencode/test/server/httpapi-session.test.ts
@@ -18,9 +18,9 @@ void Log.init({ print: false })
const original = Flag.OPENCODE_EXPERIMENTAL_HTTPAPI
-function app() {
- Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = true
- return Server.Default().app
+function app(experimental = true) {
+ Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = experimental
+ return experimental ? Server.Default().app : Server.Legacy().app
}
function runSession(fx: Effect.Effect) {
@@ -76,6 +76,10 @@ function request(path: string, init?: RequestInit) {
return Effect.promise(async () => app().request(path, init))
}
+function requestWithBackend(experimental: boolean, path: string, init?: RequestInit) {
+ return Effect.promise(async () => app(experimental).request(path, init))
+}
+
function json(response: Response) {
return Effect.promise(async () => {
if (response.status !== 200) throw new Error(await response.text())
@@ -217,6 +221,34 @@ describe("session HttpApi", () => {
),
)
+ it.live(
+ "matches legacy archived timestamp validation",
+ withTmp({ git: true, config: { formatter: false, lsp: false } }, (tmp) =>
+ Effect.gen(function* () {
+ const headers = { "x-opencode-directory": tmp.path, "content-type": "application/json" }
+ const legacy = yield* createSession(tmp.path, { title: "legacy" })
+ const effect = yield* createSession(tmp.path, { title: "effect" })
+ const body = JSON.stringify({ time: { archived: -1 } })
+
+ const legacyResponse = yield* requestWithBackend(false, pathFor(SessionPaths.update, { sessionID: legacy.id }), {
+ method: "PATCH",
+ headers,
+ body,
+ })
+ expect(legacyResponse.status).toBe(200)
+ expect((yield* json(legacyResponse)).time.archived).toBe(-1)
+
+ const effectResponse = yield* requestWithBackend(true, pathFor(SessionPaths.update, { sessionID: effect.id }), {
+ method: "PATCH",
+ headers,
+ body,
+ })
+ expect(effectResponse.status).toBe(legacyResponse.status)
+ expect((yield* json(effectResponse)).time.archived).toBe(-1)
+ }),
+ ),
+ )
+
it.live(
"serves message mutation routes through Hono bridge",
withTmp({ git: true, config: { formatter: false, lsp: false } }, (tmp) =>