diff --git a/packages/core/src/session.ts b/packages/core/src/session.ts index cdd4a4a7c..2b6225bcf 100644 --- a/packages/core/src/session.ts +++ b/packages/core/src/session.ts @@ -36,7 +36,7 @@ const ListInputBase = { workspaceID: WorkspaceV2.ID.pipe(Schema.optional), search: Schema.String.pipe(Schema.optional), limit: Schema.Int.pipe(Schema.optional), - order: Schema.Literal("asc").pipe(Schema.optional), + order: Schema.Literals(["asc", "desc"]).pipe(Schema.optional), cursor: ListCursor.pipe(Schema.optional), } diff --git a/packages/opencode/src/server/routes/instance/httpapi/groups/v2/message.ts b/packages/opencode/src/server/routes/instance/httpapi/groups/v2/message.ts index be2fdb5ba..a1244adda 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/groups/v2/message.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/groups/v2/message.ts @@ -2,7 +2,7 @@ import { SessionID } from "@/session/schema" import { SessionMessage } from "@opencode-ai/core/session/message" import { Schema } from "effect" import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi" -import { InvalidCursorError, SessionNotFoundError, UnknownError } from "../../errors" +import { InvalidCursorError, SessionNotFoundError } from "../../errors" import { V2Authorization } from "../../middleware/authorization" import { WorkspaceRoutingQueryFields } from "../../middleware/workspace-routing" @@ -36,7 +36,7 @@ export const MessageGroup = HttpApiGroup.make("v2.message") next: Schema.String.pipe(Schema.optional), }), }).annotate({ identifier: "V2SessionMessagesResponse" }), - error: [InvalidCursorError, SessionNotFoundError, UnknownError], + error: [InvalidCursorError, SessionNotFoundError], }).annotateMerge( OpenApi.annotations({ identifier: "v2.session.messages", diff --git a/packages/opencode/src/server/routes/instance/httpapi/groups/v2/session.ts b/packages/opencode/src/server/routes/instance/httpapi/groups/v2/session.ts index 058ff1a05..328603166 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/groups/v2/session.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/groups/v2/session.ts @@ -6,9 +6,7 @@ import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/un import { InvalidCursorError, InvalidRequestError, - ServiceUnavailableError, SessionNotFoundError, - UnknownError, } from "../../errors" import { V2Authorization } from "../../middleware/authorization" import { WorkspaceRoutingQuery, WorkspaceRoutingQueryFields } from "../../middleware/workspace-routing" @@ -62,7 +60,7 @@ export const SessionGroup = HttpApiGroup.make("v2.session") params: { sessionID: SessionID }, query: WorkspaceRoutingQuery, success: HttpApiSchema.NoContent, - error: [SessionNotFoundError, ServiceUnavailableError], + error: [SessionNotFoundError], }).annotateMerge( OpenApi.annotations({ identifier: "v2.session.compact", @@ -76,7 +74,7 @@ export const SessionGroup = HttpApiGroup.make("v2.session") params: { sessionID: SessionID }, query: WorkspaceRoutingQuery, success: HttpApiSchema.NoContent, - error: [SessionNotFoundError, ServiceUnavailableError], + error: [SessionNotFoundError], }).annotateMerge( OpenApi.annotations({ identifier: "v2.session.wait", @@ -90,7 +88,7 @@ export const SessionGroup = HttpApiGroup.make("v2.session") params: { sessionID: SessionID }, query: WorkspaceRoutingQuery, success: Schema.Array(SessionMessage.Message), - error: [SessionNotFoundError, UnknownError], + error: [SessionNotFoundError], }).annotateMerge( OpenApi.annotations({ identifier: "v2.session.context", diff --git a/packages/opencode/src/server/routes/instance/httpapi/handlers/v2/message.ts b/packages/opencode/src/server/routes/instance/httpapi/handlers/v2/message.ts index c9cfe33bc..d97a32e89 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/handlers/v2/message.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/handlers/v2/message.ts @@ -4,7 +4,7 @@ import { Effect, Schema } from "effect" import * as DateTime from "effect/DateTime" import { HttpApiBuilder } from "effect/unstable/httpapi" import { InstanceHttpApi } from "../../api" -import { InvalidCursorError, SessionNotFoundError, UnknownError } from "../../errors" +import { InvalidCursorError, SessionNotFoundError } from "../../errors" const DefaultMessagesLimit = 50 @@ -58,20 +58,6 @@ export const messageHandlers = HttpApiBuilder.group(InstanceHttpApi, "v2.message }), ), ), - Effect.catchTag("Session.MessageDecodeError", (error) => { - const ref = `err_${crypto.randomUUID().slice(0, 8)}` - return Effect.logError("failed to decode v2 session message").pipe( - Effect.annotateLogs({ ref, sessionID: error.sessionID, messageID: error.messageID }), - Effect.andThen( - Effect.fail( - new UnknownError({ - message: "Unexpected server error. Check server logs for details.", - ref, - }), - ), - ), - ) - }), ) const first = messages[0] const last = messages.at(-1) diff --git a/packages/opencode/src/server/routes/instance/httpapi/handlers/v2/session.ts b/packages/opencode/src/server/routes/instance/httpapi/handlers/v2/session.ts index 0de8a1224..c472eabda 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/handlers/v2/session.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/handlers/v2/session.ts @@ -1,15 +1,10 @@ import { WorkspaceV2 } from "@opencode-ai/core/workspace" import { SessionV2 } from "@opencode-ai/core/session" +import { AbsolutePath } from "@opencode-ai/core/schema" import { DateTime, Effect, Option, Schema } from "effect" import { HttpApiBuilder, HttpApiSchema } from "effect/unstable/httpapi" import { InstanceHttpApi } from "../../api" -import { - InvalidCursorError, - InvalidRequestError, - ServiceUnavailableError, - SessionNotFoundError, - UnknownError, -} from "../../errors" +import { InvalidCursorError, InvalidRequestError, SessionNotFoundError } from "../../errors" const DefaultSessionsLimit = 50 @@ -114,17 +109,21 @@ export const sessionHandlers = HttpApiBuilder.group(InstanceHttpApi, "v2.session start: ctx.query.start, search: ctx.query.search, } - const sessions = yield* session.list({ + const input = { limit: ctx.query.limit ?? DefaultSessionsLimit, order, - directory: filters.directory, - path: filters.path, workspaceID: filters.workspaceID, - roots: filters.roots, - start: filters.start, search: filters.search, cursor: decoded ? { id: decoded.id, time: decoded.time, direction: decoded.direction } : undefined, - }) + } + const sessions = yield* session.list( + filters.directory + ? { + ...input, + directory: AbsolutePath.make(filters.directory), + } + : input, + ) const first = sessions[0] const last = sessions.at(-1) return { @@ -139,7 +138,7 @@ export const sessionHandlers = HttpApiBuilder.group(InstanceHttpApi, "v2.session .handle( "compact", Effect.fn(function* (ctx) { - yield* session.compact(ctx.params.sessionID).pipe( + yield* session.compact({ sessionID: ctx.params.sessionID }).pipe( Effect.catchTag("Session.NotFoundError", (error) => Effect.fail( new SessionNotFoundError({ @@ -148,14 +147,6 @@ export const sessionHandlers = HttpApiBuilder.group(InstanceHttpApi, "v2.session }), ), ), - Effect.catchTag("Session.OperationUnavailableError", (error) => - Effect.fail( - new ServiceUnavailableError({ - message: `V2 session ${error.operation} is not available yet`, - service: `v2.session.${error.operation}`, - }), - ), - ), ) return HttpApiSchema.NoContent.make() }), @@ -172,14 +163,6 @@ export const sessionHandlers = HttpApiBuilder.group(InstanceHttpApi, "v2.session }), ), ), - Effect.catchTag("Session.OperationUnavailableError", (error) => - Effect.fail( - new ServiceUnavailableError({ - message: `V2 session ${error.operation} is not available yet`, - service: `v2.session.${error.operation}`, - }), - ), - ), ) return HttpApiSchema.NoContent.make() }), @@ -196,20 +179,6 @@ export const sessionHandlers = HttpApiBuilder.group(InstanceHttpApi, "v2.session }), ), ), - Effect.catchTag("Session.MessageDecodeError", (error) => { - const ref = `err_${crypto.randomUUID().slice(0, 8)}` - return Effect.logError("failed to decode v2 session message").pipe( - Effect.annotateLogs({ ref, sessionID: error.sessionID, messageID: error.messageID }), - Effect.andThen( - Effect.fail( - new UnknownError({ - message: "Unexpected server error. Check server logs for details.", - ref, - }), - ), - ), - ) - }), ) }), )