docs(ai-chat): guide for migrating an AI SDK route handler to chat.agent - #4519
Conversation
Developers arriving with a working Vercel AI SDK chat app had no page telling them which parts of it survive the move to chat.agent and which parts get deleted. This walks through it with before/after code: the streamText call, model config, tools, and useChat stay; the route handler, its persistence glue, and any resumable-stream setup go; the agent task, two server actions, and useTriggerChatTransport are new. Also includes a copy-pasteable prompt that points a coding agent at the live docs and the version-pinned SDK skills, so the migration can be handed off.
|
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
WalkthroughAdds a migration guide for converting an AI chat from a 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
6d4e177 to
00e9049
Compare
|
@coderabbitai full review |
|
Note GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer. |
✅ Action performedFull review finished. |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
docs/ai-chat/migrating-from-a-route-handler.mdx (1)
248-306: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueAlign the bullet label with the code.
The code sets
resume: initialMessages.length > 0. The bullet at Line 302 is labeled**resume: true**. The explanation that follows is correct, but the label does not match the snippet. Use the conditional form so a reader does not copyresume: true.📝 Proposed wording fix
-- **`resume: true`** reconnects to an in-flight stream on mount. Only enable it when there are existing messages — a brand-new chat has nothing to reconnect to. +- **`resume`** reconnects to an in-flight stream on mount. Enable it only when there are existing messages, as in the snippet above — a brand-new chat has nothing to reconnect to.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 273ea120-5658-4623-9bd9-2029d9ecc8a4
📒 Files selected for processing (3)
docs/ai-chat/fast-starts.mdxdocs/ai-chat/migrating-from-a-route-handler.mdxdocs/docs.json
🚧 Files skipped from review as they are similar to previous changes (2)
- docs/docs.json
- docs/ai-chat/fast-starts.mdx
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
- GitHub Check: code-quality / code-quality
🧰 Additional context used
📓 Path-based instructions (1)
docs/**/*.mdx
📄 CodeRabbit inference engine (docs/CLAUDE.md)
docs/**/*.mdx: MDX documentation pages must include frontmatter with title (required), description (required), and sidebarTitle (optional) in YAML format
Use Mintlify components for structured content: , , , , , , /, /
Always import from@trigger.dev/sdkin code examples (never from@trigger.dev/sdk/v3)
Code examples must be complete and runnable where possible
Use language tags in code fences:typescript,bash,jsonDocumentation in
docs/uses MDX conventions defined by the documentation guidance.
Files:
docs/ai-chat/migrating-from-a-route-handler.mdx
🧠 Learnings (4)
📚 Learning: 2026-03-10T12:44:14.176Z
Learnt from: nicktrn
Repo: triggerdotdev/trigger.dev PR: 3200
File: docs/config/config-file.mdx:353-368
Timestamp: 2026-03-10T12:44:14.176Z
Learning: In the trigger.dev repo, docs PRs are often companions to implementation PRs. When reviewing docs PRs (MDX files under docs/), check the PR description for any companion/related PR references and verify that the documented features exist in those companion PRs before flagging missing implementations. This ensures docs stay in sync with code changes across related PRs.
Applied to files:
docs/ai-chat/migrating-from-a-route-handler.mdx
📚 Learning: 2026-04-30T20:30:29.458Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3226
File: docs/ai-chat/quick-start.mdx:13-13
Timestamp: 2026-04-30T20:30:29.458Z
Learning: In this repo’s documentation MDX files (`docs/**/*.mdx`), use `ts` and `tsx` (not `typescript`) as the code-fence language tags for TypeScript/TSX snippets. Do not flag `ts`/`tsx` code-fence language tags as incorrect in any docs MDX file, since this is the site-wide Mintlify-compatible convention.
Applied to files:
docs/ai-chat/migrating-from-a-route-handler.mdx
📚 Learning: 2026-06-16T13:14:09.440Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3964
File: docs/ai-chat/reference.mdx:482-482
Timestamp: 2026-06-16T13:14:09.440Z
Learning: When documenting or reviewing usage of `ChatTurn.complete(source?)` (in `packages/trigger-sdk/src/v3/ai.ts`), note that `source` is optional (`source?: UIMessageStreamable`). Calling `complete()` with no `source` is valid specifically for a final head-start handover (`handover.isFinal`), because the warm partial already contains the response. If examples or guidance omit `source`, ensure they are in this final-hand-over context so they remain correct.
Applied to files:
docs/ai-chat/migrating-from-a-route-handler.mdx
📚 Learning: 2026-06-16T13:14:14.382Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3964
File: docs/ai-chat/reference.mdx:478-478
Timestamp: 2026-06-16T13:14:14.382Z
Learning: When reviewing RC-gated `ai-chat` docs under `docs/ai-chat/`, don’t immediately flag missing SDK type fields or implementation details just because the field isn’t present on the docs branch yet. Instead, find and cross-check the companion implementation PR that’s intended to land alongside the docs PR, and only report missing/incorrect fields if they are also absent in the companion SDK/type changes.
Applied to files:
docs/ai-chat/migrating-from-a-route-handler.mdx
🪛 LanguageTool
docs/ai-chat/migrating-from-a-route-handler.mdx
[style] ~7-~7: Consider using “the surrounding plumbing”.
Context: ... migration unchanged. What goes away is the plumbing around them: the route handler, the persistence glu...
(NOUN_AROUND_IT)
🔇 Additional comments (4)
docs/ai-chat/migrating-from-a-route-handler.mdx (4)
1-9: LGTM!Also applies to: 11-29, 35-98, 102-176, 200-246, 363-405, 523-578
178-194: LGTM!
407-521: 📐 Maintainability & Code QualityCross-page anchors are present.
314-361: 🗄️ Data Integrity & IntegrationNo change needed. The documented
upsertIncomingMessageexport and the referencedhydrateMessages/onTurnCompletepayload fields are present in the SDK surface.
The migration trades a warm route handler for an agent run that has to boot, so the opening response of a new chat gets slower and that is the first thing a reader will notice. Head Start was only a closing aside. It is now a full section: splitting tool schemas from executes, building and mounting the handler with the original auth check intact, the transport option, and the function-timeout and bundle-isolation gotchas. Also drops a stopWhen override from the fast starts handler example. The spread pins stopWhen to stepCountIs(1), and re-setting it makes the warm handler run steps the agent is supposed to own.
00e9049 to
e797790
Compare
|
Note GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer. |
The server action examples checked only that a session existed. Since chatId comes from the browser, any signed-in user copying them could mint a token scoped read/write to someone else's chat session. Both actions now bind the two, and the head-start route handler gets the same check.
|
@coderabbitai the ownership fix landed in bd2b611, which was pushed after your verification ran. Please review the latest commit. |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo '== Commit metadata =='
git show --no-ext-diff --format=fuller --stat bd2b611f0
echo
echo '== Commit diff =='
git diff --no-ext-diff --find-renames bd2b611f0^ bd2b611f0 --
echo
echo '== Documentation structure =='
ast-grep outline docs/ai-chat/migrating-from-a-route-handler.mdx --items all 2>/dev/null || true
ast-grep outline docs/ai-chat/fast-starts.mdx --items all 2>/dev/null || true
echo
echo '== Authorization-related documentation context =='
rg -n -i -C 12 \
'chatId|chat\.authorize|authorize|authenticate|userId|session|warm|head.?start|create.*token' \
docs/ai-chat/migrating-from-a-route-handler.mdx docs/ai-chat/fast-starts.mdxLength of output: 111732
No findings. The server action examples now bind You are interacting with an AI system. |
Summary
Adds a docs page for developers who already have a working Vercel AI SDK chat app (
useChaton the client, anapp/api/chat/route.tscallingstreamText) and want to move it tochat.agent. There was no page covering that path.ai-chat/upgrade-guidereads like it should be the one, but it covers moving prereleasechat.agentcode 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
streamTextcall, 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, anduseTriggerChatTransport.Covers moving tools onto the agent config so
toModelOutputsurvives past turn one, where existing database persistence goes (hydrateMessagesplus 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.tswith 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.headStartexample onai-chat/fast-starts, which setstopWhen: stepCountIs(15)after the spread.toStreamTextOptions()pinsstopWhentostepCountIs(1), so overriding it makes the warm handler run steps the agent is supposed to own (andstepCountIswas 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 skillsfirst, so it picks up guidance version-pinned to the SDK actually installed in the project, then readquick-start.md,frontend.md, andreference.md(withllms.txtas 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.jsonunder Agents, directly after Quick Start, so it is picked up by the generatedllms.txtand the per-page.mdvariants.