docs(ai-chat): clarify lastEventId is sessionId-keyed across run boundaries (#3700)
## Summary Two docs edits that close a footgun customers persisting transport state can hit. Clearing `lastEventId` on `chat.endRun()` looks intuitive — the Run ended, the cursor must be stale — but the cursor is sessionId-keyed, not runId-keyed. Clearing it forces the next `sendMessages` to subscribe from `seq_num=0`, which may hit the prior turn's still-durable `turn-complete` record and close the SSE empty before the new Run's chunks arrive. Spells out the invariant in the frontend transport persistence table and adds a Warning in the `chat.endRun()` reference. ## Test plan - [x] Mintlify preview renders - [x] No callout stacking
This commit is contained in:
@@ -585,6 +585,10 @@ The current turn streams through normally, `onBeforeTurnComplete` / `onTurnCompl
|
||||
|
||||
Use this when the agent knows its work is done (budget exhausted, goal achieved, one-shot response) rather than relying on the idle timeout. Unlike `chat.requestUpgrade()`, no `upgrade-required` signal is sent to the client, so there's no version-migration semantics.
|
||||
|
||||
<Warning>
|
||||
If you persist `lastEventId` to your own storage for cross-page-load resume, **don't clear it on `chat.endRun()`**. The cursor is sessionId-keyed and stays valid across Run boundaries — clearing it forces the next `sendMessages` to subscribe from `seq_num=0`, where it may hit the prior turn's stale `turn-complete` record and close the stream empty before the new Run's chunks arrive.
|
||||
</Warning>
|
||||
|
||||
### Runtime configuration
|
||||
|
||||
#### chat.setTurnTimeout()
|
||||
|
||||
@@ -113,7 +113,7 @@ Every chat is backed by a durable Session — the row that owns the chat's runs,
|
||||
| Field | Type | Notes |
|
||||
| --- | --- | --- |
|
||||
| `publicAccessToken` | `string` | Session-scoped JWT (`read:sessions:{chatId} + write:sessions:{chatId}`). Refreshed automatically on 401/403 via `accessToken`. |
|
||||
| `lastEventId` | `string \| undefined` | Last SSE event received on `.out`. Used to resume mid-stream after a reload. |
|
||||
| `lastEventId` | `string \| undefined` | Last SSE event received on `.out`. **Valid for the lifetime of the Session** — keep it across `endRun` / `requestUpgrade` / continuation-run boundaries; only clear when the Session itself closes. The cursor lets the next subscription open past the prior turn's stale `turn-complete` record. |
|
||||
| `isStreaming` | `boolean \| undefined` | **Optional.** The transport sets it internally, but you don't have to persist it — the server decides "nothing is streaming" via the session's [`X-Session-Settled`](/ai-chat/client-protocol#x-session-settled-fast-close-on-idle-reconnects) signal on reconnect. If you do persist it, the transport keeps the fast-path short-circuit. If you drop it, reconnects open the SSE and close fast on settled sessions. |
|
||||
|
||||
### Session cleanup (frontend)
|
||||
|
||||
Reference in New Issue
Block a user