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
+12-8Lines changed: 12 additions & 8 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -146,21 +146,25 @@ Without this, a resumed chat silently loses its history: the model sees only the
146
146
147
147
### Rotating to a new deployment
148
148
149
-
`chat.createSession()` consumes `chat.requestUpgrade()` through its managed iterator. In a fully hand-rolled custom agent, hand the Session to a fresh run with `chat.endAndContinue()`. Finish the current turn and persist its state first, then make the handoff the last operation in `run()`:
149
+
With `chat.createSession()`, use `chat.requestUpgrade()` to leave the current run after the turn. In a fully hand-rolled custom agent, use `chat.endAndContinue()` to immediately hand the Session to a fresh run.
150
+
151
+
Call it between turns, after detaching the old run's input listeners. If the old run completed its current turn, persist its state and write the turn-complete boundary before the handoff:
150
152
151
153
```ts
152
-
awaitchat.writeTurnComplete();
154
+
messageSubscription.off();
155
+
stop.cleanup();
153
156
awaitpersistMessages(conversation.uiMessages);
154
-
155
-
if (shouldRotateToLatestVersion()) {
156
-
returnchat.endAndContinue();
157
-
}
157
+
awaitchat.writeTurnComplete();
158
+
awaitchat.endAndContinue();
159
+
return;
158
160
```
159
161
160
162
The server starts a continuation run using the Session's existing trigger configuration and atomically makes it the current run. The Session and its streams stay open, so input that the old run has not consumed remains on `.in` for the continuation run. The new run uses the latest deployed task version unless the Session's trigger configuration sets `lockToVersion`.
161
163
164
+
If input arrives that the old run should leave for the continuation, detach the listeners and do not write another turn-complete boundary before handing off. `chat.writeTurnComplete()` acknowledges the latest input dispatched to the old run; writing it after receiving the deferred input would make the continuation resume after that input.
165
+
162
166
<Warning>
163
-
Call `chat.endAndContinue()`only at a completed turn boundary, after `chat.writeTurnComplete()` and after detaching the old run's input listeners. The operation starts the new run but does not stop the caller. Await it and return from `run()` immediately; continuing to read or write can race the new run on the same Session.
167
+
`chat.endAndContinue()` starts the new run but does not stop the caller. Await it and return from `run()` immediately; continuing to read or write can race the new run on the same Session. If the handoff fails, the promise rejects.
164
168
</Warning>
165
169
166
170
### turn.complete() vs manual control
@@ -236,7 +240,7 @@ For full control, skip `createSession` and compose the primitives directly:
236
240
|`chat.createStopSignal()`| Create a managed stop signal wired to the stop input stream |
237
241
|`chat.pipeAndCapture(result)`| Pipe a stream and capture the response; returns `{ message, status, error }`|
Copy file name to clipboardExpand all lines: docs/ai-chat/patterns/version-upgrades.mdx
+10-5Lines changed: 10 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -6,7 +6,7 @@ description: "Gracefully migrate chat agents to a new deployment using chat.requ
6
6
7
7
Chat agent runs are pinned to the worker version they started on. When you deploy a new version, suspended runs resume on the **old** code. If your deploy includes breaking changes (new tools, changed schemas, updated API contracts), this can cause issues.
8
8
9
-
`chat.requestUpgrade()`lets `chat.agent()` and the `chat.createSession()` iterator opt out of the current run so the transport triggers a new one on the latest version. Fully hand-rolled custom agents use `chat.endAndContinue()`at a completed turn boundary for the same Session handoff.
9
+
`chat.requestUpgrade()`is the managed upgrade signal for `chat.agent()` and the `chat.createSession()` iterator. Fully hand-rolled custom agents use `chat.endAndContinue()`between turns to immediately hand the Session to a new run.
10
10
11
11
## How it works
12
12
@@ -153,18 +153,23 @@ This upgrades on **every** deploy, not just breaking changes. Good for fast-movi
153
153
154
154
## Custom agents
155
155
156
-
`chat.requestUpgrade()`is consumed by both `chat.agent()` and the `chat.createSession()` iterator. In a fully hand-rolled `chat.customAgent()` task, finish the turn, persist any application state, then call `chat.endAndContinue()` and return immediately:
156
+
Use `chat.requestUpgrade()`with `chat.agent()` and the `chat.createSession()` iterator. In a fully hand-rolled `chat.customAgent()` task, detach input listeners, persist the completed turn, write its boundary, then call `chat.endAndContinue()` and return immediately:
157
157
158
158
```ts
159
-
awaitchat.writeTurnComplete();
159
+
messageSubscription.off();
160
+
stop.cleanup();
160
161
awaitpersistMessages(conversation.uiMessages);
161
-
returnchat.endAndContinue();
162
+
awaitchat.writeTurnComplete();
163
+
awaitchat.endAndContinue();
164
+
return;
162
165
```
163
166
164
167
The continuation uses the same durable Session and receives `.in` records that the old run has not consumed. It starts on the latest deployed task version unless the Session's trigger configuration sets `lockToVersion`.
165
168
169
+
If input arrives that the continuation should process, detach the old listeners and skip the final `chat.writeTurnComplete()`. A turn-complete boundary acknowledges the latest input dispatched to the old run, so writing one after that input would cause the continuation to resume past it.
170
+
166
171
<Warning>
167
-
`chat.endAndContinue()` starts the successor but does not stop the calling run. Call it only after `chat.writeTurnComplete()` and after detaching the old run's input listeners, then perform no more Session reads or writes and return from the task.
172
+
`chat.endAndContinue()` starts the successor but does not stop the calling run. Perform no more Session reads or writes after calling it, and return from the task. If the handoff fails, the promise rejects.
Copy file name to clipboardExpand all lines: docs/ai-chat/reference.mdx
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -511,7 +511,7 @@ All methods available on the `chat` object from `@trigger.dev/sdk/ai`.
511
511
|`chat.createStartSessionAction(taskId, options?)`| Returns a server action that creates a chat Session + triggers the first run + returns a session-scoped PAT. Idempotent on `(env, externalId)`. |
512
512
|`chat.waitForHandover(options)`| Wait for a [`chat.headStart`](/ai-chat/fast-starts#handover-with-custom-agents) handover signal in a custom loop. Returns the signal or `null`. `chat.MessageAccumulator` wraps this as `consumeHandover()` / `applyHandover()`|
513
513
|`chat.requestUpgrade()`| End the current run after this turn so the next message starts on the latest agent version. Server-orchestrated handoff. |
514
-
|`chat.endAndContinue()`| In a hand-rolled custom agent, hand off the Session to a fresh continuation run. Finish the turn, detach input listeners, call this method, then return immediately. |
514
+
|`chat.endAndContinue()`| In a hand-rolled custom agent, hand off the Session to a fresh continuation run. Call between turns after detaching input listeners, then return immediately. The promise rejects if the handoff fails. |
515
515
|`chat.setTurnTimeout(duration)`| Override turn timeout at runtime (e.g. `"2h"`) |
516
516
|`chat.setTurnTimeoutInSeconds(seconds)`| Override turn timeout at runtime (in seconds) |
517
517
|`chat.setIdleTimeoutInSeconds(seconds)`| Override idle timeout at runtime |
0 commit comments