feat(core): add session metadata support (#23068)
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
This commit is contained in:
@@ -16,6 +16,85 @@ afterEach(async () => {
|
||||
})
|
||||
|
||||
describe("session action routes", () => {
|
||||
it.instance(
|
||||
"session routes expose metadata on create, update, get, and fork",
|
||||
() =>
|
||||
Effect.gen(function* () {
|
||||
const test = yield* TestInstance
|
||||
const app = Server.Default().app
|
||||
const headers = { "Content-Type": "application/json", "x-opencode-directory": test.directory }
|
||||
|
||||
const created = yield* Effect.promise(() =>
|
||||
Promise.resolve(
|
||||
app.request("/session", {
|
||||
method: "POST",
|
||||
headers,
|
||||
body: JSON.stringify({
|
||||
title: "meta-session",
|
||||
metadata: { source: "sdk", trace: { id: "abc" } },
|
||||
}),
|
||||
}),
|
||||
),
|
||||
)
|
||||
expect(created.status).toBe(200)
|
||||
|
||||
const session = (yield* Effect.promise(() => created.json())) as SessionNs.Info
|
||||
expect(session.metadata).toEqual({ source: "sdk", trace: { id: "abc" } })
|
||||
|
||||
const updated = yield* Effect.promise(() =>
|
||||
Promise.resolve(
|
||||
app.request(`/session/${session.id}`, {
|
||||
method: "PATCH",
|
||||
headers,
|
||||
body: JSON.stringify({ metadata: { source: "sdk", trace: { id: "def" }, tags: ["one"] } }),
|
||||
}),
|
||||
),
|
||||
)
|
||||
expect(updated.status).toBe(200)
|
||||
|
||||
const next = (yield* Effect.promise(() => updated.json())) as SessionNs.Info
|
||||
expect(next.metadata).toEqual({ source: "sdk", trace: { id: "def" }, tags: ["one"] })
|
||||
|
||||
const fetched = yield* Effect.promise(() =>
|
||||
Promise.resolve(
|
||||
app.request(`/session/${session.id}`, { headers: { "x-opencode-directory": test.directory } }),
|
||||
),
|
||||
)
|
||||
expect(fetched.status).toBe(200)
|
||||
expect(((yield* Effect.promise(() => fetched.json())) as SessionNs.Info).metadata).toEqual(next.metadata)
|
||||
|
||||
const forked = yield* Effect.promise(() =>
|
||||
Promise.resolve(
|
||||
app.request(`/session/${session.id}/fork`, {
|
||||
method: "POST",
|
||||
headers,
|
||||
body: JSON.stringify({}),
|
||||
}),
|
||||
),
|
||||
)
|
||||
expect(forked.status).toBe(200)
|
||||
|
||||
const fork = (yield* Effect.promise(() => forked.json())) as SessionNs.Info
|
||||
expect(fork.metadata).toEqual(next.metadata)
|
||||
|
||||
const reset = yield* Effect.promise(() =>
|
||||
Promise.resolve(
|
||||
app.request(`/session/${session.id}`, {
|
||||
method: "PATCH",
|
||||
headers,
|
||||
body: JSON.stringify({ metadata: {} }),
|
||||
}),
|
||||
),
|
||||
)
|
||||
expect(reset.status).toBe(200)
|
||||
expect(((yield* Effect.promise(() => reset.json())) as SessionNs.Info).metadata).toEqual({})
|
||||
|
||||
yield* SessionNs.Service.use((svc) => svc.remove(fork.id).pipe(Effect.ignore))
|
||||
yield* SessionNs.Service.use((svc) => svc.remove(session.id).pipe(Effect.ignore))
|
||||
}),
|
||||
{ git: true },
|
||||
)
|
||||
|
||||
it.instance(
|
||||
"abort route returns success",
|
||||
() =>
|
||||
|
||||
@@ -227,4 +227,20 @@ describe("session.list", () => {
|
||||
}),
|
||||
{ git: true },
|
||||
)
|
||||
|
||||
it.instance(
|
||||
"includes metadata in listed sessions",
|
||||
() =>
|
||||
Effect.gen(function* () {
|
||||
const meta = { source: "sdk", trace: { id: "abc" } }
|
||||
const created = yield* withSession({ title: "meta-session", metadata: meta })
|
||||
|
||||
const listed = (yield* SessionNs.Service.use((session) => session.list({ search: "meta-session" }))).find(
|
||||
(item) => item.id === created.id,
|
||||
)
|
||||
|
||||
expect(listed?.metadata).toEqual(meta)
|
||||
}),
|
||||
{ git: true },
|
||||
)
|
||||
})
|
||||
|
||||
@@ -64,6 +64,7 @@ describe("Session.Info", () => {
|
||||
share: { url: "https://share.example.com/s/1" },
|
||||
title: "Full session",
|
||||
version: "1.0.0",
|
||||
metadata: { source: "test" },
|
||||
time: { created: 100, updated: 200, compacting: 150, archived: 300 },
|
||||
permission: [{ action: "allow" as const, pattern: "*", permission: "read" }],
|
||||
revert: {
|
||||
@@ -157,6 +158,7 @@ describe("Session input schemas", () => {
|
||||
const populated = {
|
||||
parentID: sessionID,
|
||||
title: "child",
|
||||
metadata: { source: "test" },
|
||||
permission: [{ action: "ask" as const, pattern: "*", permission: "bash" }],
|
||||
workspaceID,
|
||||
}
|
||||
|
||||
@@ -184,4 +184,35 @@ describe("Session", () => {
|
||||
expect(Exit.isFailure(getExit)).toBe(true)
|
||||
}),
|
||||
)
|
||||
|
||||
it.instance("persists metadata and copies it on fork by default", () =>
|
||||
Effect.gen(function* () {
|
||||
const session = yield* SessionNs.Service
|
||||
const meta = { source: "sdk", trace: { id: "abc" } }
|
||||
const created = yield* Effect.acquireRelease(session.create({ title: "with-meta", metadata: meta }), (info) =>
|
||||
session.remove(info.id).pipe(Effect.ignore),
|
||||
)
|
||||
const saved = yield* session.get(created.id)
|
||||
const fork = yield* Effect.acquireRelease(session.fork({ sessionID: created.id }), (info) =>
|
||||
session.remove(info.id).pipe(Effect.ignore),
|
||||
)
|
||||
|
||||
expect(saved.metadata).toEqual(meta)
|
||||
expect(fork.metadata).toEqual(meta)
|
||||
expect(fork.metadata).not.toBe(meta)
|
||||
}),
|
||||
)
|
||||
|
||||
it.instance("omits metadata when not provided", () =>
|
||||
Effect.gen(function* () {
|
||||
const session = yield* SessionNs.Service
|
||||
const created = yield* Effect.acquireRelease(session.create({ title: "empty-meta" }), (info) =>
|
||||
session.remove(info.id).pipe(Effect.ignore),
|
||||
)
|
||||
const saved = yield* session.get(created.id)
|
||||
|
||||
expect(created.metadata).toBeUndefined()
|
||||
expect(saved.metadata).toBeUndefined()
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user