Skip to content

Commit a8df7eb

Browse files
committed
docs(ai-chat): correct action lifecycle — run() and onTurnComplete do not fire
Three pages still described the pre-May-6 behavior where actions triggered run() and onTurnComplete. Aligned compaction, reference, and client-protocol with the actions page: actions fire onAction (plus hydrateMessages if set) only. If onAction returns a StreamTextResult, the response auto-pipes — but no run() and no turn lifecycle hooks fire. Removed the dead `if (trigger === "action") return;` guard from the compaction code example. Also fixes a chat.local typing error in the version-upgrades pattern: chat.local<T> requires T extends Record<string, unknown>, so the <string> primitive form was wrong. Wrapped in { version: string } and moved the init from onChatStart to onBoot (matches the canonical guidance on the chat.local page).
1 parent 84d5156 commit a8df7eb

4 files changed

Lines changed: 8 additions & 11 deletions

File tree

docs/ai-chat/client-protocol.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -830,7 +830,7 @@ Custom actions (undo, rollback, edit) ride on the same `.in` channel using `kind
830830
}
831831
```
832832
833-
Actions wake the agent from suspension (same as messages), fire the `onAction` hook, then optionally trigger a normal `run()` turn (when `onAction` returns a `StreamTextResult`). The `action` payload is validated against the agent's `actionSchema`. If the agent didn't register an `actionSchema` (or your `action` payload doesn't match it), validation fails the same way `metadata` does — `.in/append` returns `200 OK`, but the run trace shows `chat turn N [ERROR]` and the wire emits a `turn-complete` control record with no other chunks. See [Actions](/ai-chat/actions) for the agent-side schema setup.
833+
Actions wake the agent from suspension (same as messages) and fire the `onAction` hook — they are not turns, so `run()` and turn lifecycle hooks do not fire. If `onAction` returns a `StreamTextResult`, the response is auto-piped to the frontend (but still no `run()` or `onTurnComplete`). The `action` payload is validated against the agent's `actionSchema`. If the agent didn't register an `actionSchema` (or your `action` payload doesn't match it), validation fails the same way `metadata` does — `.in/append` returns `200 OK`, but the run trace shows `chat turn N [ERROR]` and the wire emits a `turn-complete` control record with no other chunks. See [Actions](/ai-chat/actions) for the agent-side schema setup.
834834
835835
### Regenerating the last response
836836

docs/ai-chat/compaction.mdx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -247,16 +247,13 @@ export const myChat = chat.agent({
247247
]);
248248
},
249249

250-
run: async ({ messages, trigger, signal }) => {
251-
// Compact action doesn't need an LLM response — just exit.
252-
if (trigger === "action") return;
253-
250+
run: async ({ messages, signal }) => {
254251
return streamText({ model: anthropic("claude-sonnet-4-5"), messages, abortSignal: signal });
255252
},
256253
});
257254
```
258255

259-
Actions fire `onAction`, apply any `chat.history.*` mutations, then call `run()`. For compaction there's no new user message to respond to, so `run()` returns early when `trigger === "action"`. `onTurnComplete` still fires with the compacted `uiMessages` — use it to persist the new state.
256+
Actions fire `onAction` only (plus `hydrateMessages` if set) — `run()` and `onTurnComplete` do not fire for actions. Persist the compacted state directly inside `onAction` after the `chat.history.set` call. See [Actions](/ai-chat/actions) for the full lifecycle.
260257

261258
### Frontend
262259

docs/ai-chat/patterns/version-upgrades.mdx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ export function Chat() {
128128
```
129129

130130
```ts title="trigger/chat.ts"
131-
const initialAppVersion = chat.local<string>({ id: "appVersion" });
131+
const initialAppVersion = chat.local<{ version: string }>({ id: "appVersion" });
132132

133133
export const myChat = chat
134134
.withClientData({
@@ -139,11 +139,11 @@ export const myChat = chat
139139
})
140140
.agent({
141141
id: "my-chat",
142-
onChatStart: async ({ clientData }) => {
143-
initialAppVersion.init(clientData.appVersion);
142+
onBoot: async ({ clientData }) => {
143+
initialAppVersion.init({ version: clientData.appVersion });
144144
},
145145
onTurnStart: async ({ clientData }) => {
146-
if (clientData?.appVersion && clientData.appVersion !== initialAppVersion.value) {
146+
if (clientData?.appVersion && clientData.appVersion !== initialAppVersion.version) {
147147
chat.requestUpgrade();
148148
}
149149
},

docs/ai-chat/reference.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -700,7 +700,7 @@ See [Stop generation](/ai-chat/frontend#stop-generation) for full details.
700700

701701
### transport.sendAction()
702702

703-
Send a custom action to the agent. Actions wake the agent from suspension, fire `onAction`, then trigger a normal `run()` turn.
703+
Send a custom action to the agent. Actions wake the agent from suspension and fire `onAction`. They are not turns — `run()` and turn lifecycle hooks do not fire. If `onAction` returns a `StreamTextResult`, the response is auto-piped to the frontend.
704704

705705
```ts
706706
transport.sendAction(chatId: string, action: unknown): Promise<ReadableStream<UIMessageChunk>>

0 commit comments

Comments
 (0)