Skip to content

Commit 5d114d0

Browse files
committed
docs(ai-chat): correct chat.agent reference drift
Fix transport.preload signature (no per-call idle option), clarify that onValidateMessages only fires on turns carrying incoming messages, soften the turn-complete token-refresh wording since the header is optional, document the onTurnComplete error field and finishReason, and correct the idle-timeout default to 30 seconds.
1 parent 459dce2 commit 5d114d0

5 files changed

Lines changed: 12 additions & 10 deletions

File tree

docs/ai-chat/client-protocol.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ Re-calling `POST /api/v1/sessions` with the same `(taskIdentifier, externalId)`
281281
282282
The `publicAccessToken` returned by `POST /api/v1/sessions` is valid for 60 minutes. Two ways to keep going past that:
283283
284-
1. **Take refreshed tokens from the stream.** Every `turn-complete` control record on `.out` carries a `public-access-token` header with a refreshed JWT (see [`turn-complete` control record](#turn-complete-control-record)). For active conversations this just rolls — replace your stored token whenever the header is present.
284+
1. **Take refreshed tokens from the stream.** Most `turn-complete` control records on `.out` carry a `public-access-token` header with a refreshed JWT (see [`turn-complete` control record](#turn-complete-control-record)). The header is optional and may be absent on some turns (for example an errored turn), so replace your stored token whenever the header is present rather than expecting it every turn. For active conversations it rolls on its own.
285285
2. **Re-call `POST /api/v1/sessions`.** Idempotent, returns `isCached: true` and a brand-new 60-minute token. Use this if a chat goes idle long enough that the SSE stream has closed and you need to resume.
286286
287287
<Note>
@@ -1048,7 +1048,7 @@ Yes. `.in` records are processed in arrival order — the agent's stop handler a
10481048
</Expandable>
10491049
10501050
<Expandable title="What's the format of the optional `X-Part-Id` header?">
1051-
Any opaque ASCII string up to ~64 characters. The built-in clients pass a `nanoid(7)` (e.g. `"V1StGXR"`) generated per request. The server uses it as a per-record idempotency key — re-POSTing the same body with the same `X-Part-Id` produces a single S2 record. If you don't send the header, the server generates one for you and idempotency is per-request only.
1051+
Any opaque ASCII string up to ~64 characters. The built-in clients generate one per logical send (the browser transport uses a UUID; the server-side clients use a short `nanoid`) and reuse it across auth retries of that send. The server uses it as a per-record idempotency key — re-POSTing the same body with the same `X-Part-Id` produces a single S2 record. If you don't send the header, the server generates one for you and idempotency is per-request only.
10521052
</Expandable>
10531053
10541054
<Expandable title="What happens on rate-limit (429)?">

docs/ai-chat/error-handling.mdx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,17 +131,17 @@ To persist errors for debugging or undo, use `onTurnComplete` (which fires even
131131

132132
### Using `onTurnComplete`
133133

134-
`onTurnComplete` fires after every turn — successful **or** errored. The `responseMessage` will be undefined or partial on errors. Use this to mark the turn as failed:
134+
`onTurnComplete` fires after every turn — successful **or** errored. On an errored turn `responseMessage` is undefined or partial and `error` carries the thrown value (with `finishReason` set to `"error"`). Use this to mark the turn as failed:
135135

136136
```ts
137-
onTurnComplete: async ({ chatId, uiMessages, responseMessage, stopped }) => {
137+
onTurnComplete: async ({ chatId, uiMessages, responseMessage, stopped, error }) => {
138138
// Persist the messages regardless of error state
139139
await db.chat.update({
140140
where: { id: chatId },
141141
data: {
142142
messages: uiMessages,
143-
// Mark the chat as errored if no response message
144-
lastTurnStatus: responseMessage ? "ok" : stopped ? "stopped" : "errored",
143+
// `error` is set when the turn threw
144+
lastTurnStatus: error ? "errored" : stopped ? "stopped" : "ok",
145145
},
146146
});
147147
},

docs/ai-chat/how-it-works.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ The agent task is running. It reads the new message off `.in`, fires `onTurnStar
4040

4141
### Idle (awaiting next message)
4242

43-
The turn is over. The task is alive but not doing work — it is parked in a waitpoint on `.in`, waiting for the next user message. If one arrives, it goes back to **Streaming** for the next turn. If `idleTimeoutInSeconds` (defaulting to a few minutes) passes with no new message, it moves to **Suspended**.
43+
The turn is over. The task is alive but not doing work — it is parked in a waitpoint on `.in`, waiting for the next user message. If one arrives, it goes back to **Streaming** for the next turn. If `idleTimeoutInSeconds` (30 seconds by default) passes with no new message, it moves to **Suspended**.
4444

4545
### Suspended
4646

docs/ai-chat/lifecycle-hooks.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ export const myChat = chat.agent({
223223

224224
## onValidateMessages
225225

226-
Validate or transform incoming `UIMessage[]` before they are converted to model messages. Fires once per turn with the raw messages from the wire payload (after cleanup of aborted tool parts), **before** accumulation and `toModelMessages()`.
226+
Validate or transform incoming `UIMessage[]` before they are converted to model messages. Fires on turns that carry incoming messages, with the raw messages from the wire payload (after cleanup of aborted tool parts), **before** accumulation and `toModelMessages()`. Turns with no incoming messages — preload, close, and regenerate with nothing re-sent — skip it.
227227

228228
Return the validated messages array. Throw to abort the turn with an error.
229229

docs/ai-chat/reference.mdx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,8 @@ Passed to the `onTurnComplete` callback.
286286
| `continuation` | `boolean` | Whether this run is continuing an existing chat |
287287
| `usage` | `LanguageModelUsage \| undefined` | Token usage for this turn |
288288
| `totalUsage` | `LanguageModelUsage` | Cumulative token usage across all turns |
289+
| `finishReason` | `FinishReason \| undefined` | Why the LLM stopped (`"stop"`, `"tool-calls"`, `"error"`, …) |
290+
| `error` | `unknown` | Set when the turn threw; `responseMessage` is then undefined or partial |
289291

290292
## BeforeTurnCompleteEvent
291293

@@ -761,10 +763,10 @@ See [Actions](/ai-chat/actions) for backend setup and [Sending actions](/ai-chat
761763
Eagerly trigger a run before the first message.
762764

763765
```ts
764-
transport.preload(chatId, { idleTimeoutInSeconds?: number }): Promise<void>
766+
transport.preload(chatId): Promise<void>
765767
```
766768

767-
No-op if a session already exists for this chatId. See [Preload](/ai-chat/fast-starts#preload) for full details.
769+
No-op if a session already exists for this chatId. The preload idle window is set by `preloadIdleTimeoutInSeconds` on the agent, not by this call. See [Preload](/ai-chat/fast-starts#preload) for full details.
768770

769771
## useTriggerChatTransport
770772

0 commit comments

Comments
 (0)