docs(ai-chat): AI Agents documentation for v4.5#3226
Conversation
|
|
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:
WalkthroughAdds a new AI Chat documentation suite under docs/ai-chat: overview, quick-start, backend, frontend, features, compaction, pending-messages, and reference, plus a new docs/ai/prompts.mdx. Documents three backend approaches (chat.task, chat.createSession, raw primitives), lifecycle hooks, streaming/pipe behavior, stop/cancel signals, compaction, pending messages, prompt templates, frontend transport integration, persistence examples, and runtime APIs. Updates docs navigation to add an “AI” dropdown with a Chat subgroup and adds a redirect from /guides/ai-chat → /ai-chat/overview. All changes are documentation-only; no SDK source or exported/public APIs were modified. Estimated code review effort🎯 1 (Trivial) | ⏱️ ~2 minutes 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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 |
00c199b to
4bab668
Compare
2626ff2 to
22331d4
Compare
22331d4 to
a78bc05
Compare
c62b5e2 to
585b781
Compare
c017aa2 to
63d4719
Compare
63d4719 to
ea46733
Compare
ea46733 to
4c34098
Compare
- overview: new paragraph framing session.out as bounded (~one turn at steady state), trim record after each turn-complete, durable snapshot for full history, eventually-consistent trim window for resume - new "Records on session.out" subsection naming the three record kinds (data, trigger control, S2 command) and the uniform header-based filter rule custom transports need - trigger:turn-complete and trigger:upgrade-required rewritten as header-form control records under the trigger-control namespace; legacy chunk.type shape called out as the prior wire - self-contained parser example updated to route the three record kinds - refreshing-the-token and validation-error blocks updated for the public-access-token header on turn-complete - end-to-end curl recipe updated to grep on trigger-control - resuming-a-stream block spells out single-turn vs multi-turn-away resume contract - backend / chat history: cross-reference to records taxonomy and a note that the agent's accumulator (not session.out) is the source of truth for full history - changelog: headline entry for the wire change + dashboard snapshot read on the Sessions detail page
A conceptual deep dive sitting between Overview and Backend. Covers the chat session as a pair of S2 channels and a long-lived task, the run's lifecycle states (Cold start, Streaming, Idle, Suspended, Resuming, Continuation, Closed), a step-by-step trace of one turn, and the three persistence layers that survive idle gaps, deploys, refreshes, and crashes: the engine checkpoint (CRIU today, full Firecracker VM snapshots on the new microVM compute), the chat-level S3 snapshot, and the browser's lastEventId cursor. Closes with warm-vs-resumed-vs-continuation timings, a hooks pointer table, a good-fit subsection, and a single-turn Mermaid sequence diagram.
…cords Document the new sibling header that rides on every turn-complete record carrying the agent's committed-consume cursor on .in. The header is what lets the next worker boot seed its .in SSE subscribe past already-processed user messages without a wall-clock-derived dedup cutoff. - client-protocol: new row in the turn-complete header table; updated records-on-session-out summary; example block shows the third header - changelog: short paragraph under "what changed on the wire" framing the cursor as the seq-based replacement for the prior timestamp cutoff, with an explicit "custom transports should ignore" note
Document the new string-or-function baseURL and fetch override on TriggerChatTransport, AgentChat, and chat.createStartSessionAction. - New patterns/trusted-edge-signals page covering the trusted-proxy pattern: how to route .in/append + session-create through an edge worker for server-trusted metadata injection while keeping .out SSE direct, plus a complete Cloudflare Worker reference implementation, agent-side clientDataSchema example, and threat model. - reference: TriggerChatTransport options table now lists baseURL with the function shape, adds a fetch row, and drops streamBaseURL. New AgentChat options and createStartSessionAction options tables with the same shape (different endpoint enum: "sessions" | "auth"). - frontend: self-hosting section shows the function form alongside the string form, plus a one-line pointer to trusted-edge-signals. - server-chat: AgentChat options table picks up baseURL and fetch rows. - docs.json: nav entry for the new patterns page.
…release-20260519091352
…(no graceful exits)
Comprehensive pass on the AI Agents + Prompts docs ahead of cutting v4.5.0-rc.0: - RC banner across every AI chat + Prompts page (single snippet) with links to a new Compatibility table covering ai SDK v5/v6, React 18/19, and Node 18.20+ peer ranges. - Restructured the Agents sidebar into four sub-groups (Building agents, Features, Patterns, Reference) and hoisted Agents to the top level of the docs nav. - New Sessions reference page documenting sessions.start / retrieve / list / open, SessionHandle.in / .out, control records, and the authorization model. - Split the catch-all Features page into proper homes: chat.local moves to its own page under Building agents, chat.defer joins background injection, custom data parts + raw chat.stream move into Backend, and the target:"root" + ai.toolExecute walkthroughs move into the Sub-agents pattern. - Fixed broken code examples and cross-link anchors: auth.createPublicToken scopes shape, useTriggerChatTransport import path, AgentChatOptions table, runInMockTaskContext re-export, and anchor slugs that didn't match Mintlify's slugifier.
The overview was carrying internals (sequence diagrams, suspend timing, inbox patterns, "what the backend accumulates") before a reader saw a runnable line of code. Rewritten to match how the product is actually pitched: - Opener leads with "An AI chat isn't a request — it's a session" - Minimal example (chat.agent + useChat) appears in the first H2, not after three screens of mechanics - Outcome bullets cover durability, native AI SDK support, multi-turn, Head Start, production primitives, and observability - "How it fits together" names the three primitives (chat agents, Sessions, sub-agents via AgentChat) without explaining internals - CardGroup CTAs to Quick Start / How it works / Backend / Patterns Length: ~520 words (was ~1180). Internals that were duplicated here already live on how-it-works, sessions, and backend.
…t guidance
Sweep across the AI chat docs against the v4.5 release candidate:
- Every `streamText` example uses Anthropic (`anthropic("claude-sonnet-4-5")`)
instead of OpenAI, with imports rewritten. AI SDK v5+ defaults to a
single step, so every example also now sets `stopWhen: stepCountIs(15)`
to avoid the "tool calls fire but no follow-up text" gotcha.
- `startSession` destructure drops the unused `taskId` — the customer's
wrapped action is task-bound at creation time, and the SDK-side
`chat.createStartSessionAction` now accepts a typed `clientData` field
via a `<typeof yourChat>` generic.
- Quick start gains a "before you start" paragraph linking to manual
setup, and a note that the `@/*` path alias is Next.js-specific.
- Frontend page opens with a new "How the transport works" section
explaining the no-API-route architecture — the browser uses a session-
scoped PAT to call `.in/append` and subscribe to `.out` directly,
bypassing any route handler `useChat` would normally need.
- Backend page now has an explicit "Which form to call" table for
`chat.toStreamTextOptions()` — when to call with no args, when to pass
`{ registry }`, when to pass `{ tools }`.
- `auth.createPublicToken` is called out as resolving to `Promise<string>`
(the JWT), not an object — clears up a small ambiguity in the docs.
Artifact from the AI-SDK provider swap script. The original snippet had
both openai and anthropic in the registry; collapsing openai → anthropic
left { anthropic, anthropic } and a duplicate import line. Spotted in
PR review.
…cord accurately The 'what gets written to the stream on error' example was showing the old data-chunk shape for trigger:turn-complete. Updated to show the error chunk in UIMessageChunk form and link to the canonical turn-complete control-record reference for the actual wire format.
These were internal planning artifacts that landed on the branch early and were caught in review. .claude/docs-plans/ is gitignored on main.
… 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).
First release candidate cut of v4.5. Everything covered by the 0.0.0-chat-prerelease-* entries below now ships under a stable semver tag.
Two bug fixes shipping in the patch RC: - Agent Skills folders silently missing in trigger dev when task files read process.env at module top level - COULD_NOT_FIND_EXECUTOR on dynamically-imported task definitions
| onTurnComplete: async ({ chatId, uiMessages, runId, chatAccessToken, lastEventId }) => { | ||
| // Persist assistant response + stream position | ||
| await db.chat.update({ | ||
| where: { id: chatId }, | ||
| data: { messages: uiMessages }, | ||
| }); | ||
| await db.chatSession.upsert({ | ||
| where: { id: chatId }, | ||
| create: { id: chatId, runId, publicAccessToken: chatAccessToken, lastEventId }, | ||
| update: { runId, publicAccessToken: chatAccessToken, lastEventId }, | ||
| }); | ||
| }, |
There was a problem hiding this comment.
🔴 Complete example uses non-atomic DB writes, directly contradicting the warning in the same document
The "Complete example" section in docs/ai-chat/patterns/database-persistence.mdx:260-271 performs onTurnComplete persistence as two separate await calls (db.chat.update then db.chatSession.upsert). This is the exact pattern the document explicitly marks as ❌ at lines 100-104 with a <Warning> block explaining the race condition: a page refresh between the two writes sees the assistant message persisted but a stale lastEventId, causing duplicate messages on resume. The recommended db.$transaction([...]) pattern from line 90-98 is not used in the complete example that users are most likely to copy.
Complete example vs. the warning
The warning at line 86-106 shows:
// ✅ Atomic
await db.$transaction([...]);
// ❌ Two awaits — race condition
await db.chat.update(...);
await db.chatSession.upsert(...);But the "Complete example" at line 260-271 does:
await db.chat.update({ ... });
await db.chatSession.upsert({ ... });| onTurnComplete: async ({ chatId, uiMessages, runId, chatAccessToken, lastEventId }) => { | |
| // Persist assistant response + stream position | |
| await db.chat.update({ | |
| where: { id: chatId }, | |
| data: { messages: uiMessages }, | |
| }); | |
| await db.chatSession.upsert({ | |
| where: { id: chatId }, | |
| create: { id: chatId, runId, publicAccessToken: chatAccessToken, lastEventId }, | |
| update: { runId, publicAccessToken: chatAccessToken, lastEventId }, | |
| }); | |
| }, | |
| onTurnComplete: async ({ chatId, uiMessages, runId, chatAccessToken, lastEventId }) => { | |
| // Persist assistant response + stream position atomically | |
| await db.$transaction([ | |
| db.chat.update({ | |
| where: { id: chatId }, | |
| data: { messages: uiMessages }, | |
| }), | |
| db.chatSession.upsert({ | |
| where: { id: chatId }, | |
| create: { id: chatId, runId, publicAccessToken: chatAccessToken, lastEventId }, | |
| update: { runId, publicAccessToken: chatAccessToken, lastEventId }, | |
| }), | |
| ]); | |
| }, |
Was this helpful? React with 👍 or 👎 to provide feedback.
| onTurnComplete: async ({ chatId, uiMessages, runId, chatAccessToken, lastEventId }) => { | ||
| await db.chat.update({ | ||
| where: { id: chatId }, | ||
| data: { messages: uiMessages }, | ||
| }); | ||
| await db.chatSession.upsert({ | ||
| where: { id: chatId }, | ||
| create: { id: chatId, runId, publicAccessToken: chatAccessToken, lastEventId }, | ||
| update: { runId, publicAccessToken: chatAccessToken, lastEventId }, | ||
| }); |
There was a problem hiding this comment.
🔴 Lifecycle hooks reference example uses non-atomic DB writes, contradicting the persistence pattern page
The onTurnComplete example in docs/ai-chat/lifecycle-hooks.mdx:414-423 performs two separate await calls for messages and session state, which is the pattern explicitly warned against in docs/ai-chat/patterns/database-persistence.mdx:86-106. Since this is the canonical reference example for onTurnComplete and is likely to be copied by users, it should use the atomic $transaction pattern to avoid the race condition where a page refresh between the two writes causes duplicate message renders.
| onTurnComplete: async ({ chatId, uiMessages, runId, chatAccessToken, lastEventId }) => { | |
| await db.chat.update({ | |
| where: { id: chatId }, | |
| data: { messages: uiMessages }, | |
| }); | |
| await db.chatSession.upsert({ | |
| where: { id: chatId }, | |
| create: { id: chatId, runId, publicAccessToken: chatAccessToken, lastEventId }, | |
| update: { runId, publicAccessToken: chatAccessToken, lastEventId }, | |
| }); | |
| onTurnComplete: async ({ chatId, uiMessages, runId, chatAccessToken, lastEventId }) => { | |
| await db.$transaction([ | |
| db.chat.update({ | |
| where: { id: chatId }, | |
| data: { messages: uiMessages }, | |
| }), | |
| db.chatSession.upsert({ | |
| where: { id: chatId }, | |
| create: { id: chatId, runId, publicAccessToken: chatAccessToken, lastEventId }, | |
| update: { runId, publicAccessToken: chatAccessToken, lastEventId }, | |
| }), | |
| ]); | |
| }, |
Was this helpful? React with 👍 or 👎 to provide feedback.
| }); | ||
| ``` | ||
|
|
||
| The self-review runs on `gpt-4o-mini` (fast, cheap) in the background. If the user sends another message before it completes, the coaching is still injected — `chat.inject()` persists across the idle wait. |
There was a problem hiding this comment.
🟡 Prose says "gpt-4o-mini" but the code example uses "anthropic:claude-haiku-4-5"
In docs/ai-chat/background-injection.mdx:157, the text describes the self-review as running on gpt-4o-mini, but the code example at lines 91-111 uses model: "anthropic:claude-haiku-4-5" throughout (in the prompt definition and as the fallback in registry.languageModel). A user reading only the prose will assume the wrong model.
| The self-review runs on `gpt-4o-mini` (fast, cheap) in the background. If the user sends another message before it completes, the coaching is still injected — `chat.inject()` persists across the idle wait. | |
| The self-review runs on `claude-haiku-4-5` (fast, cheap) in the background. If the user sends another message before it completes, the coaching is still injected — `chat.inject()` persists across the idle wait. |
Was this helpful? React with 👍 or 👎 to provide feedback.
Summary
Lands the full AI Agents documentation surface alongside the v4.5 release candidate of
@trigger.dev/sdk. Coverschat.agentend to end — defining agents, lifecycle hooks, the frontend transport, sub-agents, recovery from cancel/crash/OOM, AI Prompts integration — and the Sessions primitive that backs it.Coverage
chat.agent/chat.createSession/ raw primitives), Lifecycle hooks, Frontend transport, Server-sideAgentChat, Sessions reference,chat.localstate primitive, TypeScript types.chat.inject+chat.defer), Actions (undo / regenerate / edit), Error handling.mockChatAgent), MCP server tools, Upgrade guide, Changelog.Structure changes
stopWhen: stepCountIs(15).