Commit 8aec280
committed
feat(sdk): chat.agent → Sessions migration (phases B + C + min E)
Rewires chat.agent's internal I/O and TriggerChatTransport's send +
subscribe paths onto the Session primitive. Minimum token-scope work
included so the transport's session endpoints actually authenticate.
Phase B — chat.agent internals (ai.ts)
- New ChatInputChunk tagged union (`kind: "message" | "stop"`) —
replaces the two-stream split (chat-messages + chat-stop) with a
single Session `.in` channel.
- New chatSessionHandleKey locals slot populated at run start from
`payload.sessionId ?? payload.chatId`. Every module-level helper
now resolves to the per-run session handle.
- Module-level `chatStream`, `messagesInput`, `stopInput` become thin
facades over the session. `chatStream` mirrors
`RealtimeDefinedStream<UIMessageChunk>` and delegates to
`handle.out`. `messagesInput` / `stopInput` mirror
`RealtimeDefinedInputStream<…>` and filter `.in` by kind — the two
internal `.on()`/`.waitWithIdleTimeout()` callers and the
`chat.messages` / `chat.createStopSignal` public exposures keep
their existing shapes.
- Every `streams.writer(CHAT_STREAM_KEY, …)` callsite swaps to
`chatStream.writer(…)` so all chat output flows through
`session.out` → `SessionStreamInstance` → direct-to-S2.
- Threaded `sessionId` through `ChatTaskWirePayload` /
`ChatTaskPayload` / `ChatTaskRunPayload` so advanced users can
`sessions.open(sessionId)` directly from `run()`.
Phase C — TriggerChatTransport (chat.ts)
- `ChatSessionState` keys durable identity on `sessionId` (friendlyId);
`runId` becomes an optional hint about whether a run is live.
- `ensureSession(chatId)` lazily upserts the Session via
`apiClient.createSession({type: "chat.agent", externalId: chatId})`
on the direct `accessToken` path. Idempotent — two tabs on the
same chat converge.
- `sendMessages`, `sendPendingMessage`, `stopGeneration`,
`sendAction` all go through `appendToSessionStream(sessionId, "in",
serializeInputChunk({kind: …}))` — one endpoint, one tag per
record.
- SSE subscribe URL moves from `/realtime/v1/streams/{runId}/chat` to
`/realtime/v1/sessions/{sessionId}/out`. The old run-scoped
`subscribeToStream` is replaced by `subscribeToSessionStream`.
Incoming chunks come back as JSON strings on the session channel
(server wraps records as `{data, id}` on S2), so the subscribe
loop parses them back into objects to keep the rest of the control
flow (turn-complete / upgrade-required / skipToTurnComplete)
unchanged.
- Upgrade-required re-trigger keeps the same Session and swaps only
the runId + token.
- `getSession` / `setSession` / `setOnSessionChange` / persistence
shape all grow a `sessionId` field (runId now optional).
Phase E — minimum token scopes
- `chat.createTriggerAction` (server side) now creates the Session
before triggering so it can (a) thread `sessionId` into the run
payload and (b) mint a token with both run and session scopes.
Returns `sessionId` in its result so the transport can skip its
own `sessions.create` call on the server-side-trigger path.
- `TriggerChatTaskResult` gains optional `sessionId`.
- The two in-run PAT refresh sites (preloadAccessToken,
turnAccessToken) add `read:sessions:{sessionId}` +
`write:sessions:{sessionId}` alongside the existing run scopes.
Known follow-ups (deferred to later passes)
- Phase D: `AgentChat` / `ChatStream` in chat-client.ts still uses
the old `/realtime/v1/streams/{runId}/chat` path. Used by server-
side task-to-task compositions, not the browser transport.
- Phase F: delete CHAT_STREAM_KEY, CHAT_MESSAGES_STREAM_ID,
CHAT_STOP_STREAM_ID from chat-constants.ts + ai-chat smoke verify.1 parent 1e16248 commit 8aec280
3 files changed
Lines changed: 823 additions & 238 deletions
0 commit comments