Refactor v2 session events as schemas (#24512)

This commit is contained in:
Dax
2026-05-02 22:09:48 -04:00
committed by GitHub
parent 1409a0715c
commit a3bc5d35b0
62 changed files with 12801 additions and 6015 deletions

View File

@@ -226,7 +226,14 @@ describe("HttpApi server", () => {
const effectRoutes = openApiRouteKeys(effectOpenApi())
expect(honoRoutes.filter((route) => !effectRoutes.includes(route))).toEqual([])
expect(effectRoutes.filter((route) => !honoRoutes.includes(route))).toEqual([])
expect(effectRoutes.filter((route) => !honoRoutes.includes(route))).toEqual([
"GET /api/session",
"GET /api/session/{sessionID}/context",
"GET /api/session/{sessionID}/message",
"POST /api/session/{sessionID}/compact",
"POST /api/session/{sessionID}/prompt",
"POST /api/session/{sessionID}/wait",
])
})
test("matches generated OpenAPI route parameters", async () => {

View File

@@ -27,6 +27,14 @@ async function readFirstChunk(response: Response) {
return new TextDecoder().decode(result.value)
}
async function readFirstEvent(response: Response) {
return JSON.parse((await readFirstChunk(response)).replace(/^data: /, "")) as {
id?: string
type: string
properties: Record<string, unknown>
}
}
afterEach(async () => {
Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = original
await disposeAllInstances()
@@ -43,7 +51,7 @@ describe("event HttpApi bridge", () => {
expect(response.headers.get("cache-control")).toBe("no-cache, no-transform")
expect(response.headers.get("x-accel-buffering")).toBe("no")
expect(response.headers.get("x-content-type-options")).toBe("nosniff")
expect(await readFirstChunk(response)).toContain('data: {"type":"server.connected","properties":{}}\n\n')
expect(await readFirstEvent(response)).toMatchObject({ type: "server.connected", properties: {} })
})
test("matches legacy first event frame", async () => {
@@ -52,6 +60,9 @@ describe("event HttpApi bridge", () => {
const legacy = await app(false).request(EventPaths.event, { headers })
const effect = await app(true).request(EventPaths.event, { headers })
expect(await readFirstChunk(effect)).toBe(await readFirstChunk(legacy))
const legacyEvent = await readFirstEvent(legacy)
const effectEvent = await readFirstEvent(effect)
expect(effectEvent.type).toBe(legacyEvent.type)
expect(effectEvent.properties).toEqual(legacyEvent.properties)
})
})

View File

@@ -17,7 +17,9 @@ import { Session } from "@/session/session"
import { MessageID, PartID, type SessionID } from "../../src/session/schema"
import { MessageV2 } from "../../src/session/message-v2"
import { Database } from "@/storage/db"
import { SessionTable } from "@/session/session.sql"
import { SessionMessageTable, SessionTable } from "@/session/session.sql"
import { SessionMessage } from "../../src/v2/session-message"
import * as DateTime from "effect/DateTime"
import * as Log from "@opencode-ai/core/util/log"
import { eq } from "drizzle-orm"
import { resetDatabase } from "../fixture/db"
@@ -203,6 +205,45 @@ describe("session HttpApi", () => {
{ headers },
),
).toMatchObject({ info: { id: message.info.id } })
yield* Effect.promise(() =>
WithInstance.provide({
directory: tmp.path,
fn: async () => {
const message = new SessionMessage.Assistant({
id: SessionMessage.ID.create(),
type: "assistant",
agent: "build",
model: { id: "model", providerID: "provider" },
time: { created: DateTime.makeUnsafe(1) },
content: [],
})
Database.use((db) =>
db
.insert(SessionMessageTable)
.values([
{
id: message.id,
session_id: parent.id,
type: message.type,
time_created: 1,
data: {
time: { created: 1 },
agent: message.agent,
model: message.model,
content: message.content,
} as NonNullable<(typeof SessionMessageTable.$inferInsert)["data"]>,
},
])
.run(),
)
},
}),
)
expect(
(yield* requestJson<{ items: SessionMessage.Message[] }>(`/api/session/${parent.id}/message`, { headers })).items,
).toMatchObject([{ type: "assistant" }])
}),
),
)