feat(sdk): unify session event stream

This commit is contained in:
Kit Langton 2026-06-25 23:26:07 -04:00
commit 605fb0b6c5
20 changed files with 583 additions and 95 deletions

View file

@ -22,7 +22,7 @@ test("session methods retain decoded Effect inputs and outputs", async () => {
return Effect.succeed(
HttpClientResponse.fromWeb(
request,
new Response(`data: ${JSON.stringify(modelSwitchedEvent)}\n\n`, {
new Response(`data: ${JSON.stringify(modelSwitchedEvent)}\n\ndata: ${JSON.stringify(activityEvent)}\n\n`, {
headers: { "content-type": "text/event-stream" },
}),
),
@ -93,6 +93,8 @@ test("session methods retain decoded Effect inputs and outputs", async () => {
expect(DateTime.toEpochMillis(result.admitted.timeCreated)).toBe(1_717_171_717_000)
expect(result.context).toEqual([])
expect(DateTime.toEpochMillis(result.events[0].data.timestamp)).toBe(1_717_171_717_000)
expect(result.events[1]).toEqual(activityEvent)
expect(result.events[1]).not.toHaveProperty("durable")
expect(result.message).toEqual(expect.objectContaining({ id: "msg_model", type: "model-switched" }))
})
@ -145,3 +147,9 @@ const modelSwitchedEvent = {
model: { id: "claude", providerID: "anthropic" },
},
}
const activityEvent = {
id: "evt_activity",
type: "session.activity" as const,
data: { sessionID: "ses_test", active: false },
}

View file

@ -25,9 +25,12 @@ test("session methods use the public HTTP contract", async () => {
const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url
requests.push({ url, init })
if (url.includes("/event")) {
return new Response(`data: ${JSON.stringify(modelSwitchedEvent)}\n\n`, {
headers: { "content-type": "text/event-stream" },
})
return new Response(
`data: ${JSON.stringify(modelSwitchedEvent)}\n\ndata: ${JSON.stringify(activityEvent)}\n\n`,
{
headers: { "content-type": "text/event-stream" },
},
)
}
if (url.includes("/prompt")) return Response.json(admission)
if (url.includes("/context")) return Response.json({ data: [] })
@ -65,7 +68,8 @@ test("session methods use the public HTTP contract", async () => {
expect(created.id).toBe("ses_test")
expect(admitted.id).toBe("msg_test")
expect(context).toEqual([])
expect(events).toEqual([modelSwitchedEvent])
expect(events).toEqual([modelSwitchedEvent, activityEvent])
expect(events[1]).not.toHaveProperty("durable")
expect(message).toEqual(modelSwitchedMessage)
expect(requests.map((request) => [request.init?.method, request.url])).toEqual([
["GET", "http://localhost:3000/api/session?limit=10&order=desc"],
@ -153,3 +157,9 @@ const modelSwitchedEvent = {
model: { id: "claude", providerID: "anthropic" },
},
}
const activityEvent = {
id: "evt_activity",
type: "session.activity",
data: { sessionID: "ses_test", active: false },
}