Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
4a02c45
docs: ai chat.task
ericallam Mar 16, 2026
95f028e
docs: rename warmTimeout to idleTimeout in ai-chat docs
ericallam Mar 23, 2026
4076321
add docs for prompts
ericallam Mar 24, 2026
8fadb03
better compaction support in createSession and manual tasks
ericallam Mar 24, 2026
a09b979
docs: add prompts, compaction, and pending messages docs
ericallam Mar 25, 2026
e9686a4
document the writer stuff
ericallam Mar 26, 2026
6682aba
Add background injection docs
ericallam Mar 26, 2026
b65a03e
docs(ai-chat): add Types page, link toolExecute and withUIMessage, fi…
ericallam Mar 27, 2026
031dbf8
Add run-scoped PAT renewal for chat transport
ericallam Mar 27, 2026
5da7feb
patterns and the ctx thing
ericallam Mar 27, 2026
c54d60a
docs: add onChatSuspend/onChatResume, exitAfterPreloadIdle, withClien…
ericallam Mar 28, 2026
8203d5f
code sandbox and database patterns
ericallam Mar 28, 2026
adb6ad3
docs: rename chat.task to chat.agent across all AI docs
ericallam Mar 30, 2026
6465878
subagents and AgentChat docs
ericallam Apr 2, 2026
9b557e3
remove references to the ai chat reference project from the docs
ericallam Apr 2, 2026
8e8c698
agent mcp tools docs
ericallam Apr 2, 2026
113c91f
docs for validating ui messages
ericallam Apr 2, 2026
017c922
version upgrades
ericallam Apr 3, 2026
0354f8e
docs for stopping chats after resume
ericallam Apr 11, 2026
b37fe52
docs: add tool approvals and stop-after-resume documentation
ericallam Apr 14, 2026
4292054
cover tool approvals in the client protocol
ericallam Apr 14, 2026
f44d061
Cover passing a custom message ID generator
ericallam Apr 14, 2026
0c82ab2
docs: add chat.response API, persistent data parts, transient flag, t…
ericallam Apr 14, 2026
f3782c9
add agent prerelease changelog
ericallam Apr 14, 2026
2e535f7
docs: add hydrateMessages, chat.history, and actions documentation
ericallam Apr 15, 2026
464eecc
Add branching pattern
ericallam Apr 15, 2026
4e87033
new changelog for 0.0.0-chat-prerelease-20260415164455
ericallam Apr 15, 2026
4f74de4
docs: multi-tab coordination, error stack truncation changelog
ericallam Apr 17, 2026
b7e5af2
docs(ai-chat): add testing page for chat.agent
ericallam Apr 18, 2026
1b042d0
docs(ai-chat): changelog entry for 0.0.0-chat-prerelease-20260418083610
ericallam Apr 18, 2026
563d75b
docs(ai-chat): comprehensive error handling guide
ericallam Apr 18, 2026
de4ad47
docs(ai-chat): add human-in-the-loop patterns page
ericallam Apr 18, 2026
379dfc4
docs(ai-chat): document chat.endRun()
ericallam Apr 18, 2026
f0fe035
docs(ai-chat): add user-initiated compaction pattern
ericallam Apr 18, 2026
dfa4805
docs(ai-chat): changelog entry for 0.0.0-chat-prerelease-20260418174118
ericallam Apr 18, 2026
449abc8
docs(ai-chat): add Agent Skills pattern page
ericallam Apr 18, 2026
aec1bd8
docs(ai-chat): changelog entry for 0.0.0-chat-prerelease-20260419173457
ericallam Apr 19, 2026
8e3e58d
docs: Sessions primitive + chat.agent on Sessions
ericallam Apr 24, 2026
35fa7c2
document x-peek-settled header
ericallam Apr 25, 2026
41c0226
docs: chat.agent on Sessions-as-run-manager
ericallam Apr 27, 2026
a2d85c7
docs(ai-chat): add not-released-yet banner to Sessions upgrade guide
ericallam Apr 28, 2026
ec55862
docs(ai-chat): warn against non-atomic onTurnComplete persistence
ericallam Apr 28, 2026
4967a64
docs(ai-chat): tidy Sessions changelog + sidebar
ericallam Apr 29, 2026
ce77244
docs(ai-chat): warn against chat.defer for onTurnStart message persis…
ericallam Apr 29, 2026
3d1bf55
docs(ai-chat): large-payloads pattern + ChatChunkTooLargeError reference
ericallam Apr 30, 2026
29e01b0
docs(ai-chat): unblock check-broken-links + address PR #3226 review f…
ericallam Apr 30, 2026
f98adc0
Release 0.0.0-chat-prerelease-20260501122331
ericallam May 1, 2026
c81ad7c
docs(ai-chat): resilient SSE reconnection
ericallam May 1, 2026
932396c
docs(ai-chat): mark SSE reconnection entry as Upcoming
ericallam May 1, 2026
5742c28
docs(ai-chat): tag SSE reconnection entry with chat-prerelease-202605…
ericallam May 2, 2026
d64d06b
docs(ai-chat): chat.headStart guide + reference + changelog
ericallam May 3, 2026
1d825f3
docs(ai-chat): pin chat.headStart entry to 0.0.0-chat-prerelease-2026…
ericallam May 5, 2026
abac368
docs(ai-chat): surface chat.toStreamTextOptions() in entry-point pages
ericallam May 5, 2026
9d10620
docs(ai-chat): changelog entry for suspend/resume duplicate-turn fix
ericallam May 5, 2026
ccb3023
docs(ai-chat): action turns become side-effect-only
ericallam May 6, 2026
7cc95ee
docs(ai-chat): document actions-not-turns semantics
ericallam May 6, 2026
cb50025
docs(ai-chat): pin May 6 changelog entry to 0.0.0-chat-prerelease-202…
ericallam May 6, 2026
eb741e1
docs(ai-chat): split lifecycle hooks, actions, and fast starts into p…
ericallam May 7, 2026
1e01e79
docs(ai-chat): add changelog entry for May 7 chat-prerelease
ericallam May 7, 2026
06743a1
docs(ai-chat): document oomMachine OOM-resilience pattern
ericallam May 7, 2026
f8ced85
docs(ai-chat): document delta-only wire and snapshot model
ericallam May 9, 2026
2de9c95
docs(ai-chat): onChatStart once-per-chat contract + continuation run …
ericallam May 12, 2026
8149f66
docs(ai-chat): document onBoot lifecycle hook
ericallam May 13, 2026
defb45f
add streamBaseUrl
ericallam May 16, 2026
0e64e1f
docs(ai-chat): bounded session.out + header-form control records
ericallam May 16, 2026
04a3721
docs(ai-chat): add how-it-works page
ericallam May 17, 2026
05d6ac8
docs(ai-chat): session-in-event-id header on turn-complete control re…
ericallam May 17, 2026
4109940
docs(ai-chat): functional baseURL on chat transports
ericallam May 18, 2026
0b65f53
Stop recommending run streams
ericallam May 18, 2026
4a623c3
docs(ai-chat): pin May 8 + May 16 changelog entries to 0.0.0-chat-pre…
ericallam May 19, 2026
537cef2
docs(ai-chat): recovery boot — onRecoveryBoot hook + smart context-pr…
ericallam May 19, 2026
9ddda9b
docs(ai-chat): clarify beforeBoot bubbles while onRecoveryBoot body i…
ericallam May 19, 2026
53a2d94
docs(ai-chat): onRecoveryBoot fires only on mid-stream interruptions …
ericallam May 19, 2026
69cf5b3
docs(ai-chat): prep for v4.5 release candidate
ericallam May 20, 2026
1b2ac74
Add 0.0.0-chat-prerelease-20260520150857 to changelog
ericallam May 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 98 additions & 0 deletions .claude/docs-plans/sessions-chat-agent.md
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.
114 changes: 114 additions & 0 deletions docs/ai-chat/actions.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
---
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: openai("gpt-4o"), 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: openai("gpt-4o"),
messages,
});
}
// 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: openai("gpt-4o"), 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
Loading