Skip to content

docs(ai-chat): AI Agents documentation for v4.5#3226

Merged
ericallam merged 83 commits into
mainfrom
docs/tri-7532-ai-sdk-chat-transport-and-chat-task-system
May 21, 2026
Merged

docs(ai-chat): AI Agents documentation for v4.5#3226
ericallam merged 83 commits into
mainfrom
docs/tri-7532-ai-sdk-chat-transport-and-chat-task-system

Conversation

@ericallam
Copy link
Copy Markdown
Member

@ericallam ericallam commented Mar 16, 2026

Summary

Lands the full AI Agents documentation surface alongside the v4.5 release candidate of @trigger.dev/sdk. Covers chat.agent end 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

  • Conceptual: Overview, Quick Start, How it works.
  • Building agents: Backend (chat.agent / chat.createSession / raw primitives), Lifecycle hooks, Frontend transport, Server-side AgentChat, Sessions reference, chat.local state primitive, TypeScript types.
  • Features: AI Prompts integration, Fast starts (Preload + Head Start), Compaction, Pending Messages (steering), Background Injection (chat.inject + chat.defer), Actions (undo / regenerate / edit), Error handling.
  • Patterns (13): Sub-agents, Branching conversations, Code sandbox, Database persistence, Persistence and replay, HITL, Tool result auditing, Large payloads, Agent skills, OOM resilience, Recovery boot, Trusted edge signals, Version upgrades.
  • Reference: API Reference, Client Protocol (wire format), Testing harness (mockChatAgent), MCP server tools, Upgrade guide, Changelog.

Structure changes

  • Top-level nav: AI → Agents, with sub-groups for Building agents / Features / Patterns / Reference.
  • New RC banner snippet on every page links to the supported AI SDK versions table on the API Reference.
  • All examples use Anthropic with stopWhen: stepCountIs(15).

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Mar 16, 2026

⚠️ No Changeset found

Latest commit: dab496a

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 16, 2026

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds 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)

Check name Status Explanation Resolution
Description check ⚠️ Warning The pull request has no description provided, leaving the template sections (Closes, Checklist, Testing, Changelog, Screenshots) entirely unfilled. Add a pull request description following the provided template, including which issue is closed, testing steps, and a changelog summary of the new documentation pages added.
✅ Passed checks (2 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title check ✅ Passed The title 'docs(ai-chat): AI Agents documentation for v4.5' accurately summarizes the pull request, which adds comprehensive AI Chat documentation including quick-start, backend, frontend, features, reference, compaction, and pending-messages guides.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docs/tri-7532-ai-sdk-chat-transport-and-chat-task-system

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

coderabbitai[bot]

This comment was marked as resolved.

@ericallam ericallam force-pushed the docs/tri-7532-ai-sdk-chat-transport-and-chat-task-system branch from 00c199b to 4bab668 Compare March 23, 2026 10:27
coderabbitai[bot]

This comment was marked as resolved.

@ericallam ericallam force-pushed the docs/tri-7532-ai-sdk-chat-transport-and-chat-task-system branch from 2626ff2 to 22331d4 Compare March 25, 2026 14:52
@ericallam ericallam force-pushed the docs/tri-7532-ai-sdk-chat-transport-and-chat-task-system branch from 22331d4 to a78bc05 Compare March 25, 2026 17:01
@ericallam ericallam force-pushed the docs/tri-7532-ai-sdk-chat-transport-and-chat-task-system branch from c62b5e2 to 585b781 Compare March 26, 2026 15:32
@ericallam ericallam force-pushed the docs/tri-7532-ai-sdk-chat-transport-and-chat-task-system branch from c017aa2 to 63d4719 Compare March 30, 2026 20:59
@ericallam ericallam force-pushed the docs/tri-7532-ai-sdk-chat-transport-and-chat-task-system branch from 63d4719 to ea46733 Compare April 1, 2026 07:07
@ericallam ericallam force-pushed the docs/tri-7532-ai-sdk-chat-transport-and-chat-task-system branch from ea46733 to 4c34098 Compare April 1, 2026 13:57
ericallam added 15 commits May 21, 2026 12:13
- 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.
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.
devin-ai-integration[bot]

This comment was marked as resolved.

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.
devin-ai-integration[bot]

This comment was marked as resolved.

…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.
devin-ai-integration[bot]

This comment was marked as resolved.

Comment thread .claude/docs-plans/sessions-chat-agent.md Outdated
These were internal planning artifacts that landed on the branch early
and were caught in review. .claude/docs-plans/ is gitignored on main.
devin-ai-integration[bot]

This comment was marked as resolved.

ericallam added 2 commits May 21, 2026 12:58
… 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.
devin-ai-integration[bot]

This comment was marked as resolved.

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
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 3 new potential issues.

View 16 additional findings in Devin Review.

Open in Devin Review

Comment on lines +260 to +271
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 },
});
},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 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({ ... });
Suggested change
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 },
}),
]);
},
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +414 to +423
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 },
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 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.

Suggested change
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 },
}),
]);
},
Open in Devin Review

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.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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.

Suggested change
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.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants