feat(core): API-managed per-session context entries (#34941)

This commit is contained in:
Kit Langton 2026-07-02 10:05:47 -04:00 committed by GitHub
commit 7843f8fb38
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 783 additions and 146 deletions

View file

@ -1,4 +1,5 @@
import { SessionV2 } from "@opencode-ai/core/session"
import { SessionContextEntry } from "@opencode-ai/core/session/context-entry"
import { DateTime, Effect, Stream } from "effect"
import { HttpApiBuilder, HttpApiSchema } from "effect/unstable/httpapi"
import { Api } from "../api"
@ -218,45 +219,49 @@ export const SessionHandler = HttpApiBuilder.group(Api, "server.session", (handl
.handle(
"session.skill",
Effect.fn(function* (ctx) {
yield* session.skill({
sessionID: ctx.params.sessionID,
id: ctx.payload.id,
skill: ctx.payload.skill,
resume: ctx.payload.resume,
}).pipe(
Effect.catchTag("Session.NotFoundError", (error) =>
Effect.fail(
new SessionNotFoundError({
sessionID: error.sessionID,
message: `Session not found: ${error.sessionID}`,
}),
yield* session
.skill({
sessionID: ctx.params.sessionID,
id: ctx.payload.id,
skill: ctx.payload.skill,
resume: ctx.payload.resume,
})
.pipe(
Effect.catchTag("Session.NotFoundError", (error) =>
Effect.fail(
new SessionNotFoundError({
sessionID: error.sessionID,
message: `Session not found: ${error.sessionID}`,
}),
),
),
),
Effect.catchTag("Session.SkillNotFoundError", (error) =>
Effect.fail(new SkillNotFoundError({ skill: error.skill, message: `Skill not found: ${error.skill}` })),
),
)
Effect.catchTag("Session.SkillNotFoundError", (error) =>
Effect.fail(new SkillNotFoundError({ skill: error.skill, message: `Skill not found: ${error.skill}` })),
),
)
return HttpApiSchema.NoContent.make()
}),
)
.handle(
"session.synthetic",
Effect.fn(function* (ctx) {
yield* session.synthetic({
sessionID: ctx.params.sessionID,
text: ctx.payload.text,
description: ctx.payload.description,
metadata: ctx.payload.metadata,
}).pipe(
Effect.catchTag("Session.NotFoundError", (error) =>
Effect.fail(
new SessionNotFoundError({
sessionID: error.sessionID,
message: `Session not found: ${error.sessionID}`,
}),
yield* session
.synthetic({
sessionID: ctx.params.sessionID,
text: ctx.payload.text,
description: ctx.payload.description,
metadata: ctx.payload.metadata,
})
.pipe(
Effect.catchTag("Session.NotFoundError", (error) =>
Effect.fail(
new SessionNotFoundError({
sessionID: error.sessionID,
message: `Session not found: ${error.sessionID}`,
}),
),
),
),
)
)
return HttpApiSchema.NoContent.make()
}),
)
@ -462,6 +467,29 @@ export const SessionHandler = HttpApiBuilder.group(Api, "server.session", (handl
}
}),
)
.handle(
"session.context.entry.list",
Effect.fn(function* (ctx) {
const contextEntries = yield* SessionContextEntry.Service
return { data: yield* contextEntries.list(ctx.params.sessionID) }
}),
)
.handle(
"session.context.entry.put",
Effect.fn(function* (ctx) {
const contextEntries = yield* SessionContextEntry.Service
yield* contextEntries.put({ sessionID: ctx.params.sessionID, key: ctx.params.key, value: ctx.payload.value })
return HttpApiSchema.NoContent.make()
}),
)
.handle(
"session.context.entry.remove",
Effect.fn(function* (ctx) {
const contextEntries = yield* SessionContextEntry.Service
yield* contextEntries.remove({ sessionID: ctx.params.sessionID, key: ctx.params.key })
return HttpApiSchema.NoContent.make()
}),
)
.handle(
"session.history",
Effect.fn(function* (ctx) {