-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
docs(ai-chat): AI Agents documentation for v4.5 #3226
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
ericallam
merged 83 commits into
main
from
docs/tri-7532-ai-sdk-chat-transport-and-chat-task-system
May 21, 2026
Merged
Changes from 79 commits
Commits
Show all changes
83 commits
Select commit
Hold shift + click to select a range
8f557ee
docs: ai chat.task
ericallam 5ea1c1d
docs: rename warmTimeout to idleTimeout in ai-chat docs
ericallam db951cb
add docs for prompts
ericallam 65c1548
better compaction support in createSession and manual tasks
ericallam fff5e08
docs: add prompts, compaction, and pending messages docs
ericallam e7f577f
document the writer stuff
ericallam 7264cc5
Add background injection docs
ericallam 24aae42
docs(ai-chat): add Types page, link toolExecute and withUIMessage, fi…
ericallam 0c65122
Add run-scoped PAT renewal for chat transport
ericallam 23fb1eb
patterns and the ctx thing
ericallam 83f0ee8
docs: add onChatSuspend/onChatResume, exitAfterPreloadIdle, withClien…
ericallam 0439ea3
code sandbox and database patterns
ericallam 4370927
docs: rename chat.task to chat.agent across all AI docs
ericallam 886bbce
subagents and AgentChat docs
ericallam 62c6c64
remove references to the ai chat reference project from the docs
ericallam cb8cd99
agent mcp tools docs
ericallam 2256426
docs for validating ui messages
ericallam c6bab90
version upgrades
ericallam ae68d78
docs for stopping chats after resume
ericallam fecda84
docs: add tool approvals and stop-after-resume documentation
ericallam 45fb492
cover tool approvals in the client protocol
ericallam 47df9be
Cover passing a custom message ID generator
ericallam 22d9855
docs: add chat.response API, persistent data parts, transient flag, t…
ericallam 2509748
add agent prerelease changelog
ericallam bdb6343
docs: add hydrateMessages, chat.history, and actions documentation
ericallam 81e7ebc
Add branching pattern
ericallam 51bc393
new changelog for 0.0.0-chat-prerelease-20260415164455
ericallam fb43438
docs: multi-tab coordination, error stack truncation changelog
ericallam 0e59236
docs(ai-chat): add testing page for chat.agent
ericallam d62c1bd
docs(ai-chat): changelog entry for 0.0.0-chat-prerelease-20260418083610
ericallam 1aaf3cc
docs(ai-chat): comprehensive error handling guide
ericallam e23f37c
docs(ai-chat): add human-in-the-loop patterns page
ericallam 318d9d8
docs(ai-chat): document chat.endRun()
ericallam b195bf8
docs(ai-chat): add user-initiated compaction pattern
ericallam 70ad661
docs(ai-chat): changelog entry for 0.0.0-chat-prerelease-20260418174118
ericallam 92d293c
docs(ai-chat): add Agent Skills pattern page
ericallam 5cd512c
docs(ai-chat): changelog entry for 0.0.0-chat-prerelease-20260419173457
ericallam 13e1bd4
docs: Sessions primitive + chat.agent on Sessions
ericallam 0e19f27
document x-peek-settled header
ericallam 0c010fe
docs: chat.agent on Sessions-as-run-manager
ericallam 3b2bdf4
docs(ai-chat): add not-released-yet banner to Sessions upgrade guide
ericallam 07d3064
docs(ai-chat): warn against non-atomic onTurnComplete persistence
ericallam b19e093
docs(ai-chat): tidy Sessions changelog + sidebar
ericallam f882cdf
docs(ai-chat): warn against chat.defer for onTurnStart message persis…
ericallam f82eaa1
docs(ai-chat): large-payloads pattern + ChatChunkTooLargeError reference
ericallam b4c29eb
docs(ai-chat): unblock check-broken-links + address PR #3226 review f…
ericallam d90269c
Release 0.0.0-chat-prerelease-20260501122331
ericallam d8ba4ee
docs(ai-chat): resilient SSE reconnection
ericallam 27941bc
docs(ai-chat): mark SSE reconnection entry as Upcoming
ericallam 02aa51e
docs(ai-chat): tag SSE reconnection entry with chat-prerelease-202605…
ericallam ebdc408
docs(ai-chat): chat.headStart guide + reference + changelog
ericallam f87e0fb
docs(ai-chat): pin chat.headStart entry to 0.0.0-chat-prerelease-2026…
ericallam c104d5b
docs(ai-chat): surface chat.toStreamTextOptions() in entry-point pages
ericallam a23ed7d
docs(ai-chat): changelog entry for suspend/resume duplicate-turn fix
ericallam c332c1a
docs(ai-chat): action turns become side-effect-only
ericallam e729269
docs(ai-chat): document actions-not-turns semantics
ericallam 96d8ef3
docs(ai-chat): pin May 6 changelog entry to 0.0.0-chat-prerelease-202…
ericallam 0f357ef
docs(ai-chat): split lifecycle hooks, actions, and fast starts into p…
ericallam ee34650
docs(ai-chat): add changelog entry for May 7 chat-prerelease
ericallam 1f99b6d
docs(ai-chat): document oomMachine OOM-resilience pattern
ericallam b1ee852
docs(ai-chat): document delta-only wire and snapshot model
ericallam be53065
docs(ai-chat): onChatStart once-per-chat contract + continuation run …
ericallam b88776a
docs(ai-chat): document onBoot lifecycle hook
ericallam 0e48546
add streamBaseUrl
ericallam 5c02eec
docs(ai-chat): bounded session.out + header-form control records
ericallam 967c9aa
docs(ai-chat): add how-it-works page
ericallam 47a0d7f
docs(ai-chat): session-in-event-id header on turn-complete control re…
ericallam 50f8bef
docs(ai-chat): functional baseURL on chat transports
ericallam 3cc5297
Stop recommending run streams
ericallam ab12b88
docs(ai-chat): pin May 8 + May 16 changelog entries to 0.0.0-chat-pre…
ericallam 556a04c
docs(ai-chat): recovery boot — onRecoveryBoot hook + smart context-pr…
ericallam c7d7a9d
docs(ai-chat): clarify beforeBoot bubbles while onRecoveryBoot body i…
ericallam d2a7e9a
docs(ai-chat): onRecoveryBoot fires only on mid-stream interruptions …
ericallam dd31165
docs(ai-chat): prep for v4.5 release candidate
ericallam 6ceb79a
Add 0.0.0-chat-prerelease-20260520150857 to changelog
ericallam 76f391c
docs(ai-chat): rewrite overview to lead with the session framing
ericallam 82dad78
docs(ai-chat): swap examples to Anthropic, add stopWhen, fix transpor…
ericallam 236f9a5
docs(prompts): drop duplicate anthropic import and registry key
ericallam 0133dc2
docs(error-handling): describe error chunk + turn-complete control re…
ericallam 84d5156
chore: remove .claude/docs-plans authoring notes from docs PR
ericallam a8df7eb
docs(ai-chat): correct action lifecycle — run() and onTurnComplete do…
ericallam 58a8f2e
docs(ai-chat): add 4.5.0-rc.0 release entry to changelog
ericallam dab496a
docs(ai-chat): add 4.5.0-rc.1 changelog entry
ericallam File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,98 @@ | ||
| # Docs plan — Sessions primitive + chat.agent migration | ||
|
|
||
| Plan for updating Mintlify docs to cover: | ||
|
|
||
| 1. **Sessions** — net-new public primitive (`sessions.create/open/list/close`, `SessionHandle`, `.in`/`.out`) that doesn't exist in docs yet. | ||
| 2. **chat.agent on Sessions** — 14 ai-chat pages reference the old run-scoped wire protocol. Public `chat.agent()` surface is unchanged, but the underlying transport, persistence shape, and wire endpoints all moved. | ||
| 3. **Session-settled signal** — recent improvement (`X-Session-Settled` response header, `wait=0` drain on settled reconnects). Needs mention on frontend/server-chat pages. | ||
|
|
||
| Architecture reference (what the system actually does, for doc writers): | ||
| `.claude/architecture/chat-agent-sessions.md`. | ||
|
|
||
| ## Relationship to other doc plans | ||
|
|
||
| Coordinate with the hydration/history/actions plan saved in | ||
| `project_docs_update_plan.md` (memory). Sessions should land **first** — | ||
| it's the foundational primitive the other features reference. | ||
|
|
||
| --- | ||
|
|
||
| ## Phase 1 — Sessions primitive docs (net-new) | ||
|
|
||
| New top-level section `docs/sessions/`, added as a dropdown group in | ||
| `docs.json`. Should ship as its own PR and merge before Phase 2 so | ||
| chat.agent docs can link into it. | ||
|
|
||
| | File | Covers | | ||
| |---|---| | ||
| | `sessions/overview.mdx` | What a Session is. Identity (`sessionId` + `externalId`, `session_*` friendly format, externalId idempotency on create). `.in` / `.out` channels as a durable typed I/O pair. Durability across runs. When to use Sessions vs. run-scoped streams. That `chat.agent` is built on Sessions. | | ||
| | `sessions/quick-start.mdx` | Minimal end-to-end: `sessions.create` → `sessions.open` → `.out.append` + `.in.on` → `sessions.close`. Model on `ai-chat/quick-start.mdx` shape. | | ||
| | `sessions/channels.mdx` | Deep dive. `.out` producer API (`append`, `pipe`, `writer({execute})` matching `streams.define`) and external consumer API (`read`). `.in` consumer API (`on`, `once`, `peek`, `wait`, `waitWithIdleTimeout` matching `streams.input`) and external producer API (`send`). Suspend-while-idle via session-stream waitpoints. Uniform serialization on `.out` (subscribers always get parsed objects). | | ||
| | `sessions/reference.mdx` | API reference. `sessions.create / retrieve / update / close / list / open`. `SessionHandle`, `SessionInputChannel`, `SessionOutputChannel`. Token scopes: `read:sessions`, `write:sessions`, `admin:sessions`, super-scopes. | | ||
| | `sessions/patterns.mdx` *(optional — can defer)* | Cross-run resume. Inbox via `sessions.list({type, tags})`. Multi-agent shared channels (two agents coordinating on one session). Custom transports keyed on `externalId`. | | ||
|
|
||
| Navigation: add `Sessions` dropdown to `docs.json`, placed adjacent to | ||
| `AI Chat` so readers see the relationship. | ||
|
|
||
| --- | ||
|
|
||
| ## Phase 2 — Update chat.agent docs | ||
|
|
||
| Ships after Phase 1 merges. One PR. | ||
|
|
||
| | File | Change | | ||
| |---|---| | ||
| | `ai-chat/client-protocol.mdx` | **Full rewrite.** Old run-scoped endpoints (`POST /api/v1/tasks/:id/trigger`, `GET /realtime/v1/streams/:runId/chat`, `POST /realtime/v1/streams/:runId/input/chat-messages`) are gone. New surface: `POST /api/v1/sessions` (create, idempotent on externalId), `POST /realtime/v1/sessions/:session/:io/append` (input chunks — note `io="in"` for chat), `GET /realtime/v1/sessions/:session/:io` (SSE subscribe, `io="out"`). Document `ChatInputChunk` tagged union (`{kind: "message", payload}` / `{kind: "stop", message?}`). Document `Last-Event-ID` resume. Document `X-Session-Settled: true` response header and when it fires (server peeks `.out` tail; if last record is `trigger:turn-complete`, SSE uses `wait=0` and closes fast with this header). | | ||
| | `ai-chat/frontend.mdx` | Update `TriggerChatTransport`. Persistence shape grew: `{sessionId, publicAccessToken, lastEventId, runId?, isStreaming?}` — `sessionId` is the durable identity now, `runId` is a live-run hint. `isStreaming` is **optional** after the settled-signal work; callers that drop it get server-decided settled behavior with no 60s hang. `onSessionChange` now carries `sessionId`. Note: cross-run resume is free — same chat persists across page reloads, across day boundaries, across process exits. | | ||
| | `ai-chat/server-chat.mdx` | Same persistence shape update for `AgentChat`. `ChatSession` type gained `sessionId`. Same cross-run resume story. | | ||
| | `ai-chat/backend.mdx` | `ChatTaskWirePayload` / `ChatTaskPayload` / `ChatTaskRunPayload` grew optional `sessionId`. Agent code rarely needs to touch it — `chat.stream`, `chat.messages`, `chat.stopSignal` still work identically. Show `sessions.open(payload.sessionId)` as an escape hatch for advanced cases (e.g., writing to the session from a sub-agent or from outside the turn loop). | | ||
| | `ai-chat/reference.mdx` | Add `ChatInputChunk<TMessage, TMetadata>` type. Update `ChatSession` shape. Document `TriggerChatTaskResult.sessionId`. Session scopes list. Link to `sessions/reference`. | | ||
| | `ai-chat/overview.mdx` | Conceptual: chats now outlive individual runs. Inbox pattern via `sessions.list({type: "chat.agent"})`. Link to `/sessions/overview`. | | ||
| | `ai-chat/quick-start.mdx` | Minimal edit. One sentence: sessions power the chat primitive; link out to `/sessions/overview` for the underlying model. | | ||
| | `ai-chat/changelog.mdx` | New entry covering (a) the session migration, (b) the settled-signal improvement (optional `isStreaming`). | | ||
| | `ai-chat/testing.mdx` | `mockChatAgent` now drives `.in` via `drivers.sessions.in.send(sessionId, {kind, payload})` instead of the old input-stream manager. `TestSessionStreamManager` + `TestSessionOutputChannel` replace the stream-based harness. Update any code examples. | | ||
| | `ai-chat/patterns/version-upgrades.mdx` | `trigger:upgrade-required` flow now reuses `sessionId` across runs — a single line clarifying that only `runId` + PAT refresh, `sessionId` stays. | | ||
| | `ai-chat/patterns/human-in-the-loop.mdx` | Audit for stale stream-ID references; likely only a small update if any. | | ||
|
|
||
| --- | ||
|
|
||
| ## Phase 3 — Cross-references in realtime docs | ||
|
|
||
| Tacked onto the Phase 2 PR. Trivial edits. | ||
|
|
||
| | File | Change | | ||
| |---|---| | ||
| | `realtime/backend/streams.mdx` | Callout: "For durable, long-lived channels that outlive a single run (e.g. chat agents), see [Sessions](/sessions/overview)." Run-scoped streams are not deprecated — they're still correct for ephemeral run I/O. | | ||
| | `realtime/backend/input-streams.mdx` | Same callout. | | ||
|
|
||
| --- | ||
|
|
||
| ## Out of scope | ||
|
|
||
| - **Deprecation of run-scoped streams.** They remain the right primitive for ephemeral per-run I/O. Sessions is additive, not a replacement. | ||
| - **Rewriting pattern pages that happen to work unchanged.** `code-sandbox`, `skills`, `sub-agents`, `branching-conversations`, `database-persistence`, `compaction`, `pending-messages`, `background-injection`, `error-handling`, `mcp` — only touch if there's a concrete stale reference. Audit quickly; don't rewrite prophylactically. | ||
| - **Wire-protocol examples for non-chat session uses.** If `sessions/patterns.mdx` gets written, covers this lightly. Otherwise defer — Sessions is general-purpose but chat is the primary motivating use case for v1 docs. | ||
| - **Migration guide for external callers of the old wire protocol.** The `chat-constants.ts` commit already documented the mapping in its commit message (`streams.writer(CHAT_STREAM_KEY)` → `sessions.open(sessionId).out.writer(...)`, etc.). If we hear from users building custom non-`TriggerChatTransport` clients, we can write a dedicated migration page then. | ||
|
|
||
| --- | ||
|
|
||
| ## Sizing | ||
|
|
||
| Rough effort estimates, in full dedicated doc passes: | ||
|
|
||
| - Phase 1 — ~1 pass. 4 net-new pages, `sessions/overview` and `sessions/channels` are the meaty ones; `sessions/patterns` is optional and can be Phase 1.5. | ||
| - Phase 2 — ~1 pass. `client-protocol.mdx` is the single biggest rewrite (~half a pass); the other 10 edits are paragraph-level. | ||
| - Phase 3 — rounds to zero; fold into Phase 2 PR. | ||
|
|
||
| Total: ~2 dedicated doc passes, ideally across two PRs. | ||
|
|
||
| --- | ||
|
|
||
| ## Sequencing decision | ||
|
|
||
| Phase 1 **before** Phase 2. Two reasons: | ||
|
|
||
| 1. Phase 2 pages will link into `/sessions/*`; merging Phase 2 first creates broken links in published docs. | ||
| 2. Readers encountering `sessionId` in updated chat docs need somewhere to go to learn what a Session is. That page has to exist first. | ||
|
|
||
| Phase 1.5 (the optional `sessions/patterns.mdx` page) can ship either with Phase 1 or as a follow-up — it's not on the critical path for Phase 2. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,115 @@ | ||
| --- | ||
| title: "Actions" | ||
| sidebarTitle: "Actions" | ||
| description: "Custom commands sent from the frontend that mutate chat state without consuming a turn — undo, rollback, edit, regenerate." | ||
| --- | ||
|
|
||
| import RcBanner from "/snippets/ai-chat-rc-banner.mdx"; | ||
|
|
||
| <RcBanner /> | ||
|
|
||
| ## Overview | ||
|
|
||
| Custom actions let the frontend send structured commands (undo, rollback, edit, regenerate) that modify the conversation state. **Actions are not turns**: they fire `hydrateMessages` (if set) and `onAction` only. No turn lifecycle hooks (`onTurnStart` / `prepareMessages` / `onBeforeTurnComplete` / `onTurnComplete`), no `run()`, no turn-counter increment. The trace span is named `chat action`. | ||
|
|
||
| Actions wake the agent from suspension the same way a new message does, run their handler against the latest accumulator state, and emit a `trigger:turn-complete` chunk so the frontend's `useChat` knows the action has been applied. | ||
|
|
||
| ## Defining an action handler | ||
|
|
||
| Define an `actionSchema` for validation and an `onAction` handler that uses [`chat.history`](/ai-chat/backend#chat-history) to modify state: | ||
|
|
||
| ```ts | ||
| import { z } from "zod"; | ||
|
|
||
| export const myChat = chat.agent({ | ||
| id: "my-chat", | ||
| actionSchema: z.discriminatedUnion("type", [ | ||
| z.object({ type: z.literal("undo") }), | ||
| z.object({ type: z.literal("rollback"), targetMessageId: z.string() }), | ||
| z.object({ type: z.literal("edit"), messageId: z.string(), text: z.string() }), | ||
| ]), | ||
|
|
||
| onAction: async ({ action }) => { | ||
| switch (action.type) { | ||
| case "undo": | ||
| chat.history.slice(0, -2); // Remove last user + assistant exchange | ||
| break; | ||
| case "rollback": | ||
| chat.history.rollbackTo(action.targetMessageId); | ||
| break; | ||
| case "edit": | ||
| chat.history.replace(action.messageId, { | ||
| id: action.messageId, | ||
| role: "user", | ||
| parts: [{ type: "text", text: action.text }], | ||
| }); | ||
| break; | ||
| } | ||
| // returning void → side-effect-only, no model call | ||
| }, | ||
|
|
||
| run: async ({ messages, signal }) => { | ||
| return streamText({ model: anthropic("claude-sonnet-4-5"), messages, abortSignal: signal }); | ||
| }, | ||
| }); | ||
| ``` | ||
|
|
||
| **Lifecycle flow:** Wake → parse action against `actionSchema` → `hydrateMessages` (if set) → **`onAction`** → apply `chat.history` mutations → emit `trigger:turn-complete` → wait for next message. | ||
|
|
||
| ## Returning a model response from an action | ||
|
|
||
| `onAction` can return a `StreamTextResult`, `string`, or `UIMessage` to produce a response. The returned stream is auto-piped to the frontend just like a normal turn, but the rest of the turn machinery (`onTurnStart`, `onTurnComplete`, etc.) still does not fire. | ||
|
|
||
| ```ts | ||
| onAction: async ({ action, messages }) => { | ||
| if (action.type === "regenerate") { | ||
| chat.history.slice(0, -1); // drop the last assistant | ||
| return streamText({ | ||
| model: anthropic("claude-sonnet-4-5"), | ||
| messages, | ||
| stopWhen: stepCountIs(15), | ||
| }); | ||
| } | ||
| // other actions return void → side-effect only | ||
| } | ||
| ``` | ||
|
|
||
| This is useful for actions that both mutate state and want a fresh model response (regenerate-from-here, retry-with-different-style). Persistence is your responsibility inside `onAction` itself; you have access to the streamed response object. | ||
|
|
||
| ## Gating actions on HITL state | ||
|
|
||
| If you have a [human-in-the-loop](/ai-chat/patterns/human-in-the-loop) tool waiting on `addToolOutput`, you usually want to refuse competing actions like `regenerate` until the answer arrives. [`chat.history.getPendingToolCalls()`](/ai-chat/backend#chat-history) gives you exactly that signal: | ||
|
|
||
| ```ts | ||
| onAction: async ({ action, messages, signal }) => { | ||
| if (action.type === "regenerate") { | ||
| if (chat.history.getPendingToolCalls().length > 0) return; // gated | ||
| chat.history.slice(0, -1); | ||
| return streamText({ model: anthropic("claude-sonnet-4-5"), messages, abortSignal: signal }); | ||
| } | ||
| }, | ||
| ``` | ||
|
|
||
| ## Sending actions from the frontend | ||
|
|
||
| ```ts | ||
| // Browser — TriggerChatTransport | ||
| const stream = await transport.sendAction(chatId, { type: "undo" }); | ||
|
|
||
| // Server — AgentChat | ||
| const stream = await agentChat.sendAction({ type: "rollback", targetMessageId: "msg-3" }); | ||
| ``` | ||
|
|
||
| The action payload is validated against `actionSchema` on the backend; invalid actions throw and surface as a stream error. The `action` parameter in `onAction` is fully typed from the schema. | ||
|
|
||
| <Note> | ||
| For silent state changes that should never appear as a turn (e.g. injecting background context), use [`chat.inject()`](/ai-chat/background-injection) instead. Actions are explicit user-driven mutations; injections are agent-side context updates. | ||
| </Note> | ||
|
|
||
| ## See also | ||
|
|
||
| - [`chat.history`](/ai-chat/backend#chat-history) — the imperative API actions use to mutate state | ||
| - [Sending actions from the frontend](/ai-chat/frontend#sending-actions) — `transport.sendAction` ergonomics | ||
| - [`hydrateMessages`](/ai-chat/lifecycle-hooks#hydratemessages) — fires before `onAction` when set | ||
| - [Branching conversations](/ai-chat/patterns/branching-conversations) — pairs action handlers with backend-controlled history | ||
| - [Human-in-the-loop](/ai-chat/patterns/human-in-the-loop) — gating fresh actions while a tool is waiting |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.