Skip to content

Commit f8e1c91

Browse files
authored
docs(ai-chat): guide for migrating an AI SDK route handler to chat.agent (#4519)
## Summary Adds a docs page for developers who already have a working Vercel AI SDK chat app (`useChat` on the client, an `app/api/chat/route.ts` calling `streamText`) and want to move it to `chat.agent`. There was no page covering that path. `ai-chat/upgrade-guide` reads like it should be the one, but it covers moving prerelease `chat.agent` code to the Sessions release, which is a different reader. The page is structured around what stays, what goes, and what is new, because the reassuring part of this migration is how much is untouched: the `streamText` call, model config, tool definitions, `useChat`, and all message rendering carry over as-is. What gets deleted is the route handler, the persistence glue wired into it, and any resumable-stream setup. What is new is the agent task, two server actions, and `useTriggerChatTransport`. Covers moving tools onto the agent config so `toModelOutput` survives past turn one, where existing database persistence goes (`hydrateMessages` plus the turn hooks), a short section on what durability you get once you are across, a note that Hono/SvelteKit/Express follow the same shape, and a gotchas list built from the mistakes this specific migration produces. ## Head Start The one thing this migration makes worse is the opening response of a new chat. The route handler answered out of a warm process; the agent run has to be dequeued and booted first. That is the complaint the page has to answer head on, so Head Start gets a full section rather than a closing aside, plus a callout up top next to the "what changes" table so nobody plans the migration without knowing it exists. The section walks the four steps: splitting tool schemas away from tool executes (the bundle-isolation constraint the whole feature rests on), building the handler, mounting it back at `app/api/chat/route.ts` with the original auth check wrapped around it, and the transport option. Both server actions stay, because Head Start only owns the first turn. Three gotchas go with it: a slow first turn without Head Start, Head Start on but the route bundle still heavy, and the route timing out because the handler holds the SSE response open for the whole turn rather than just step 1. The coding-agent prompt names Head Start as explicitly out of scope, so an agent handed the migration does not attempt the tool split unprompted. Also fixes the `chat.headStart` example on `ai-chat/fast-starts`, which set `stopWhen: stepCountIs(15)` after the spread. `toStreamTextOptions()` pins `stopWhen` to `stepCountIs(1)`, so overriding it makes the warm handler run steps the agent is supposed to own (and `stepCountIs` was never imported in that snippet either). ## Migration prompt The page also ships a copy-pasteable prompt for handing the migration to a coding agent. It tells the agent to run `npx trigger.dev@latest skills` first, so it picks up guidance version-pinned to the SDK actually installed in the project, then read `quick-start.md`, `frontend.md`, and `reference.md` (with `llms.txt` as the index) before editing anything. The instructions are explicit about preserving the existing model, prompt, and tool schemas rather than rewriting them. Registered in `docs.json` under Agents, directly after Quick Start, so it is picked up by the generated `llms.txt` and the per-page `.md` variants.
1 parent 088f68b commit f8e1c91

3 files changed

Lines changed: 597 additions & 1 deletion

File tree

docs/ai-chat/fast-starts.mdx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,11 +266,14 @@ This is an **import-chain** problem, not a runtime one. A "we'll strip the execu
266266
...helper.toStreamTextOptions({ tools: headStartTools }),
267267
model: anthropic("claude-sonnet-4-6"),
268268
system: "You are a helpful assistant.",
269-
stopWhen: stepCountIs(15),
270269
}),
271270
});
272271
```
273272

273+
<Warning>
274+
Don't set `stopWhen` here. The spread pins it to `stepCountIs(1)`, and overriding it makes the handler run steps the agent is supposed to own — the handover then splices a stream that has already moved past step 1.
275+
</Warning>
276+
274277
<Tip>
275278
Use the **same model** on both sides (route handler and `chat.agent`) to avoid a tone or style shift between step 1 and step 2+. Your LLM provider keys stay server-side in your warm process — Trigger.dev never holds them in this design.
276279
</Tip>

0 commit comments

Comments
 (0)