You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/ai-chat/custom-agents.mdx
+32Lines changed: 32 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -179,6 +179,38 @@ for await (const turn of session) {
179
179
}
180
180
```
181
181
182
+
## Stopping generation
183
+
184
+
The frontend stops a turn with [`transport.stopGeneration(chatId)`](/ai-chat/frontend#stop-generation), which writes a stop signal to the session's input stream. It aborts the current turn's generation but keeps the run alive, so the next message continues on the same session.
185
+
186
+
`turn.signal` is a combined stop-and-cancel `AbortSignal`, fresh each turn. Pass it to `streamText` so the stop reaches the model, then let `turn.complete()` finish the turn:
187
+
188
+
```ts trigger/my-chat.ts
189
+
forawait (const turn ofsession) {
190
+
const result =streamText({
191
+
model: anthropic("claude-sonnet-4-5"),
192
+
messages: turn.messages,
193
+
abortSignal: turn.signal, // fires on a user stop OR a run cancel
194
+
stopWhen: stepCountIs(15),
195
+
});
196
+
197
+
awaitturn.complete(result);
198
+
199
+
if (turn.stopped) {
200
+
// user stopped this turn — the partial response is already accumulated
201
+
}
202
+
}
203
+
```
204
+
205
+
On a stop, `turn.complete()` cleans up the aborted parts of the partial response, accumulates it as its own assistant message, and writes turn-complete. The run does not end — the loop continues to the next turn.
206
+
207
+
Read `turn.stopped` to tell a user stop from a full run cancel:
208
+
209
+
-**User stop** (`transport.stopGeneration`): `turn.signal` aborts, `turn.stopped` is `true`, the partial response is accumulated, and the run stays alive for the next message.
210
+
-**Run cancel** (cancelled, expired, or `maxDuration` exceeded): `turn.signal` aborts, `turn.stopped` is `false`, and `turn.complete()` returns without accumulating because the run is ending.
211
+
212
+
A hand-rolled loop wires this itself with `chat.createStopSignal()` and `chat.cleanupAbortedParts()`. Two things `createSession` handles for you are easy to get wrong there — see the [hand-rolled loop checklist](#hand-rolled-loop-checklist).
213
+
182
214
## Hand-rolled loop with primitives
183
215
184
216
For full control, skip `createSession` and compose the primitives directly:
0 commit comments