Skip to content

Commit fc04b88

Browse files
committed
docs(ai-chat): bounded session.out + header-form control records
- 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
1 parent d5b4ae0 commit fc04b88

3 files changed

Lines changed: 225 additions & 58 deletions

File tree

docs/ai-chat/backend.mdx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,10 @@ See [Actions](/ai-chat/actions).
357357

358358
Imperative API for reading and modifying the accumulated message history. Works from any hook (`onAction`, `onTurnStart`, `onBeforeTurnComplete`, `onTurnComplete`, `hydrateMessages`) or from `run()` and AI SDK tools.
359359

360+
<Note>
361+
The agent's accumulator — not `session.out` — is the source of truth for the full conversation. The `.out` stream is a bounded sliding window (roughly one turn at steady state, see [Records on `session.out`](/ai-chat/client-protocol#records-on-session-out)); the durable history lives in the agent's accumulator and is persisted to S3 between turns for fast next-run boots. `chat.history` reads and mutates that accumulator directly.
362+
</Note>
363+
360364
**Reads.** Synchronous against the current accumulator state.
361365

362366
| Method | Description |

docs/ai-chat/changelog.mdx

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,67 @@ sidebarTitle: "Changelog"
44
description: "Pre-release updates for AI chat agents."
55
---
66

7+
<Update label="May 16, 2026" description="0.0.0-chat-prerelease-pending" tags={["SDK", "Breaking"]}>
8+
9+
## `session.out` is now bounded — header-form control records + per-turn trim
10+
11+
Long-lived chats were accumulating `session.out` records forever (every turn appends; nothing trimmed). The Sessions dashboard re-streamed the entire history from `seq_num=0` on every page load, and OOM-retry boot scanned the whole stream to find the last turn-complete. Surfaced by Arena AI: "what's the lifetime of these streams?"
12+
13+
After this release `session.out` stays roughly **one turn long forever** at steady state. After each `turn-complete`, the agent appends an S2 `trim` command record pointing back to the previous turn-complete's seq_num. Full conversation history continues to live in the durable S3 snapshot, not on the stream. Resume across a single turn boundary still works (the previous `turn-complete` is still on the stream and S2's eventually-consistent trim window gives 10-60s of grace); resume across multiple turns of inactivity falls back to the snapshot.
14+
15+
### What changed on the wire
16+
17+
`trigger:turn-complete` and `trigger:upgrade-required` are no longer JSON data chunks on `session.out`. They're now **header-form control records** under a uniform `trigger-control` namespace:
18+
19+
```
20+
headers:
21+
["trigger-control", "turn-complete"]
22+
["public-access-token", "eyJ..."] // optional, refreshed JWT on turn-complete
23+
body: ""
24+
```
25+
26+
```
27+
headers:
28+
["trigger-control", "upgrade-required"]
29+
body: ""
30+
```
31+
32+
The control event names ("turn-complete", "upgrade-required") are unchanged conceptually — they just moved from `chunk.type` into a `trigger-control` header value. Body is always empty; metadata that previously rode in the chunk (e.g. `publicAccessToken`) now rides on sibling headers.
33+
34+
### Custom transport implementers
35+
36+
Built-in SDK transports (`TriggerChatTransport`, `AgentChat`) handle this transparently — `onTurnComplete` fires the same way with the same payload. Custom transports filtering on `chunk.type === "trigger:turn-complete"` need to switch to the header-based filter:
37+
38+
```ts
39+
import { controlSubtype } from "@trigger.dev/core/v3";
40+
41+
const control = controlSubtype(record.headers);
42+
if (control === "turn-complete") {
43+
// refresh token from record.headers, end turn, etc.
44+
}
45+
```
46+
47+
The full uniform filter rule (data records vs control records vs S2 command records like `trim`) is documented at [Records on `session.out`](/ai-chat/client-protocol#records-on-session-out).
48+
49+
### Sessions dashboard snapshot read
50+
51+
The Sessions detail page in the trigger.dev dashboard now reads the agent's S3 snapshot first via a presigned URL, then SSE-tails from `snapshot.lastOutEventId`. Bandwidth and time-to-first-render are O(unread turns) instead of O(session lifetime). Sessions that registered a `hydrateMessages` hook (which skips snapshot writes) show only the most recent turn — those customers typically have their own DB-backed dashboards.
52+
53+
### Breaking surface
54+
55+
- Custom transports parsing `chunk.type` for turn-complete / upgrade-required must switch to the `trigger-control` header check.
56+
- Snapshot consumers should import `ChatSnapshotV1` / `ChatSnapshotV1Schema` from `@trigger.dev/core/v3` (now an exported shape, not SDK-internal).
57+
58+
Hard cutover — no compat shim. v4.5 is prerelease.
59+
60+
### Docs
61+
62+
- [Records on `session.out`](/ai-chat/client-protocol#records-on-session-out) — full filter rule for data / control / command records.
63+
- [Resuming a stream](/ai-chat/client-protocol#resuming-a-stream) — explicit single-turn vs multi-turn-away semantics.
64+
- [`turn-complete` control record](/ai-chat/client-protocol#turn-complete-control-record) and [`upgrade-required` control record](/ai-chat/client-protocol#upgrade-required-control-record) — replaced the old chunk-shape docs.
65+
66+
</Update>
67+
768
<Update label="May 8, 2026" description="0.0.0-chat-prerelease-pending" tags={["SDK", "Breaking"]}>
869

970
## 512 KiB `/in/append` ceiling removed for long chats — slim wire + S3 snapshot

0 commit comments

Comments
 (0)