@trigger.dev/sdk 4.5.16 → 4.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commonjs/imports/ai-runtime-cjs.cjs.map +1 -1
- package/dist/commonjs/imports/ai-runtime.js +2 -0
- package/dist/commonjs/v3/ai-shared.d.ts +15 -0
- package/dist/commonjs/v3/ai-shared.js +35 -1
- package/dist/commonjs/v3/ai-shared.js.map +1 -1
- package/dist/commonjs/v3/ai.d.ts +311 -25
- package/dist/commonjs/v3/ai.js +1633 -380
- package/dist/commonjs/v3/ai.js.map +1 -1
- package/dist/commonjs/v3/auth.d.ts +10 -4
- package/dist/commonjs/v3/auth.js.map +1 -1
- package/dist/commonjs/v3/chat-client.d.ts +11 -2
- package/dist/commonjs/v3/chat-client.js +227 -111
- package/dist/commonjs/v3/chat-client.js.map +1 -1
- package/dist/commonjs/v3/chat-react.d.ts +88 -0
- package/dist/commonjs/v3/chat-react.js +130 -1
- package/dist/commonjs/v3/chat-react.js.map +1 -1
- package/dist/commonjs/v3/chat-server.d.ts +42 -6
- package/dist/commonjs/v3/chat-server.js +52 -7
- package/dist/commonjs/v3/chat-server.js.map +1 -1
- package/dist/commonjs/v3/chat.d.ts +92 -10
- package/dist/commonjs/v3/chat.js +328 -73
- package/dist/commonjs/v3/chat.js.map +1 -1
- package/dist/commonjs/v3/chatSnapshotIo.d.ts +2 -0
- package/dist/commonjs/v3/chatSnapshotIo.js +173 -0
- package/dist/commonjs/v3/chatSnapshotIo.js.map +1 -0
- package/dist/commonjs/v3/chatVersionSkew.d.ts +12 -0
- package/dist/commonjs/v3/chatVersionSkew.js +30 -0
- package/dist/commonjs/v3/chatVersionSkew.js.map +1 -0
- package/dist/commonjs/v3/externalDeploymentId.d.ts +23 -0
- package/dist/commonjs/v3/externalDeploymentId.js +43 -0
- package/dist/commonjs/v3/externalDeploymentId.js.map +1 -0
- package/dist/commonjs/v3/retry.d.ts +4 -0
- package/dist/commonjs/v3/retry.js +22 -13
- package/dist/commonjs/v3/retry.js.map +1 -1
- package/dist/commonjs/v3/sessions.d.ts +15 -2
- package/dist/commonjs/v3/sessions.js +12 -1
- package/dist/commonjs/v3/sessions.js.map +1 -1
- package/dist/commonjs/v3/shared.js +30 -36
- package/dist/commonjs/v3/shared.js.map +1 -1
- package/dist/commonjs/v3/test/index.d.ts +1 -0
- package/dist/commonjs/v3/test/index.js +3 -1
- package/dist/commonjs/v3/test/index.js.map +1 -1
- package/dist/commonjs/v3/test/mock-chat-agent.d.ts +47 -4
- package/dist/commonjs/v3/test/mock-chat-agent.js +116 -10
- package/dist/commonjs/v3/test/mock-chat-agent.js.map +1 -1
- package/dist/commonjs/v3/test/test-session-handle.js +6 -0
- package/dist/commonjs/v3/test/test-session-handle.js.map +1 -1
- package/dist/commonjs/v3/test/transcript-storage-tests.d.ts +40 -0
- package/dist/commonjs/v3/test/transcript-storage-tests.js +258 -0
- package/dist/commonjs/v3/test/transcript-storage-tests.js.map +1 -0
- package/dist/commonjs/v3/transcriptStorage.d.ts +261 -0
- package/dist/commonjs/v3/transcriptStorage.js +374 -0
- package/dist/commonjs/v3/transcriptStorage.js.map +1 -0
- package/dist/commonjs/version.js +1 -1
- package/dist/esm/imports/ai-runtime.d.ts +2 -2
- package/dist/esm/imports/ai-runtime.js +2 -2
- package/dist/esm/imports/ai-runtime.js.map +1 -1
- package/dist/esm/v3/ai-shared.d.ts +15 -0
- package/dist/esm/v3/ai-shared.js +33 -0
- package/dist/esm/v3/ai-shared.js.map +1 -1
- package/dist/esm/v3/ai.d.ts +311 -25
- package/dist/esm/v3/ai.js +1625 -377
- package/dist/esm/v3/ai.js.map +1 -1
- package/dist/esm/v3/auth.d.ts +10 -4
- package/dist/esm/v3/auth.js.map +1 -1
- package/dist/esm/v3/chat-client.d.ts +11 -2
- package/dist/esm/v3/chat-client.js +228 -112
- package/dist/esm/v3/chat-client.js.map +1 -1
- package/dist/esm/v3/chat-react.d.ts +88 -0
- package/dist/esm/v3/chat-react.js +127 -1
- package/dist/esm/v3/chat-react.js.map +1 -1
- package/dist/esm/v3/chat-server.d.ts +42 -6
- package/dist/esm/v3/chat-server.js +53 -8
- package/dist/esm/v3/chat-server.js.map +1 -1
- package/dist/esm/v3/chat.d.ts +92 -10
- package/dist/esm/v3/chat.js +329 -74
- package/dist/esm/v3/chat.js.map +1 -1
- package/dist/esm/v3/chatSnapshotIo.d.ts +2 -0
- package/dist/esm/v3/chatSnapshotIo.js +165 -0
- package/dist/esm/v3/chatSnapshotIo.js.map +1 -0
- package/dist/esm/v3/chatVersionSkew.d.ts +12 -0
- package/dist/esm/v3/chatVersionSkew.js +27 -0
- package/dist/esm/v3/chatVersionSkew.js.map +1 -0
- package/dist/esm/v3/externalDeploymentId.d.ts +23 -0
- package/dist/esm/v3/externalDeploymentId.js +38 -0
- package/dist/esm/v3/externalDeploymentId.js.map +1 -0
- package/dist/esm/v3/retry.d.ts +4 -0
- package/dist/esm/v3/retry.js +14 -8
- package/dist/esm/v3/retry.js.map +1 -1
- package/dist/esm/v3/sessions.d.ts +15 -2
- package/dist/esm/v3/sessions.js +11 -1
- package/dist/esm/v3/sessions.js.map +1 -1
- package/dist/esm/v3/shared.js +17 -23
- package/dist/esm/v3/shared.js.map +1 -1
- package/dist/esm/v3/test/index.d.ts +1 -0
- package/dist/esm/v3/test/index.js +1 -0
- package/dist/esm/v3/test/index.js.map +1 -1
- package/dist/esm/v3/test/mock-chat-agent.d.ts +47 -4
- package/dist/esm/v3/test/mock-chat-agent.js +118 -12
- package/dist/esm/v3/test/mock-chat-agent.js.map +1 -1
- package/dist/esm/v3/test/test-session-handle.js +6 -0
- package/dist/esm/v3/test/test-session-handle.js.map +1 -1
- package/dist/esm/v3/test/transcript-storage-tests.d.ts +40 -0
- package/dist/esm/v3/test/transcript-storage-tests.js +255 -0
- package/dist/esm/v3/test/transcript-storage-tests.js.map +1 -0
- package/dist/esm/v3/transcriptStorage.d.ts +261 -0
- package/dist/esm/v3/transcriptStorage.js +360 -0
- package/dist/esm/v3/transcriptStorage.js.map +1 -0
- package/dist/esm/version.js +1 -1
- package/docs/ai-chat/actions.mdx +55 -23
- package/docs/ai-chat/anatomy.mdx +47 -27
- package/docs/ai-chat/backend.mdx +125 -48
- package/docs/ai-chat/background-injection.mdx +122 -19
- package/docs/ai-chat/client-protocol.mdx +5 -4
- package/docs/ai-chat/compaction.mdx +13 -7
- package/docs/ai-chat/custom-agents.mdx +23 -0
- package/docs/ai-chat/fast-starts.mdx +27 -20
- package/docs/ai-chat/frontend.mdx +19 -14
- package/docs/ai-chat/how-it-works.mdx +1 -1
- package/docs/ai-chat/lifecycle-hooks.mdx +6 -2
- package/docs/ai-chat/migrating-from-a-route-handler.mdx +16 -14
- package/docs/ai-chat/migrating-from-hydrate-messages.mdx +299 -0
- package/docs/ai-chat/patterns/database-persistence.mdx +24 -9
- package/docs/ai-chat/patterns/native-compaction.mdx +310 -0
- package/docs/ai-chat/patterns/persistence-and-replay.mdx +34 -23
- package/docs/ai-chat/patterns/skills.mdx +7 -10
- package/docs/ai-chat/patterns/version-upgrades.mdx +79 -6
- package/docs/ai-chat/pending-messages.mdx +3 -3
- package/docs/ai-chat/prompt-caching.mdx +23 -25
- package/docs/ai-chat/quick-start.mdx +11 -11
- package/docs/ai-chat/reference.mdx +69 -10
- package/docs/ai-chat/sessions.mdx +6 -1
- package/docs/ai-chat/side-channels.mdx +1 -1
- package/docs/ai-chat/testing.mdx +2 -1
- package/docs/ai-chat/tools.mdx +18 -13
- package/docs/ai-chat/transcript-storage.mdx +247 -0
- package/docs/ai-chat/upgrade-guide.mdx +2 -2
- package/docs/apikeys.mdx +27 -45
- package/docs/config/extensions/syncEnvVars.mdx +6 -0
- package/docs/deploy-environment-variables.mdx +23 -2
- package/docs/deployment/overview.mdx +4 -8
- package/docs/deployment/preview-branches.mdx +4 -4
- package/docs/deployment/version-skew-protection.mdx +62 -0
- package/docs/introduction.mdx +58 -152
- package/docs/manual-setup.mdx +7 -7
- package/docs/mcp-tools.mdx +9 -0
- package/docs/quick-start.mdx +3 -3
- package/docs/realtime/auth.mdx +1 -1
- package/docs/reports.mdx +157 -0
- package/docs/self-hosting/security.mdx +17 -0
- package/docs/tasks/scheduled.mdx +24 -0
- package/docs/triggering.mdx +1 -1
- package/docs/troubleshooting-zod.mdx +158 -0
- package/package.json +4 -4
- package/skills/trigger-authoring-chat-agent/SKILL.md +41 -29
- package/skills/trigger-chat-agent-advanced/SKILL.md +54 -19
|
@@ -30,18 +30,18 @@ Add `pendingMessages` to your `chat.agent` configuration:
|
|
|
30
30
|
|
|
31
31
|
```ts
|
|
32
32
|
import { chat } from "@trigger.dev/sdk/ai";
|
|
33
|
-
import {
|
|
33
|
+
import { stepCountIs } from "ai";
|
|
34
34
|
import { anthropic } from "@ai-sdk/anthropic";
|
|
35
35
|
|
|
36
36
|
export const myChat = chat.agent({
|
|
37
37
|
id: "my-chat",
|
|
38
|
+
registry,
|
|
38
39
|
pendingMessages: {
|
|
39
40
|
// Only inject when there are completed steps (tool calls happened)
|
|
40
41
|
shouldInject: ({ steps }) => steps.length > 0,
|
|
41
42
|
},
|
|
42
|
-
run: async ({ messages, signal }) => {
|
|
43
|
+
run: async ({ messages, signal, streamText }) => {
|
|
43
44
|
return streamText({
|
|
44
|
-
...chat.toStreamTextOptions({ registry }),
|
|
45
45
|
messages,
|
|
46
46
|
tools: { /* ... */ },
|
|
47
47
|
abortSignal: signal,
|
|
@@ -16,7 +16,7 @@ A request renders as `tools` → `system` → `messages`. There are three prefix
|
|
|
16
16
|
|
|
17
17
|
| Region | How to cache it | Stability |
|
|
18
18
|
| --- | --- | --- |
|
|
19
|
-
| System prompt (+ tools) | `cacheControl` / `systemProviderOptions` on `chat.
|
|
19
|
+
| System prompt (+ tools) | `cacheControl` / `systemProviderOptions` on `chat.agent()`, or `providerOptions` on `chat.prompt.set()` | Set once, never changes — the highest-value target |
|
|
20
20
|
| Conversation history | `prepareMessages` adds a breakpoint to the last message | Grows append-only across turns |
|
|
21
21
|
| Tool definitions | Stable as long as your tool set doesn't change between turns | Render at position 0 — changing them invalidates everything |
|
|
22
22
|
|
|
@@ -32,23 +32,22 @@ The system prompt (your `chat.prompt` text plus any skills preamble) is usually
|
|
|
32
32
|
|
|
33
33
|
Three ways to opt in, depending on where you'd rather express it.
|
|
34
34
|
|
|
35
|
-
**`cacheControl`
|
|
35
|
+
**`cacheControl` on the agent** — the Anthropic-flavored one-liner:
|
|
36
36
|
|
|
37
37
|
```ts /trigger/chat.ts
|
|
38
38
|
import { chat } from "@trigger.dev/sdk/ai";
|
|
39
|
-
import { streamText } from "ai";
|
|
40
39
|
import { anthropic } from "@ai-sdk/anthropic";
|
|
41
40
|
|
|
42
41
|
export const myChat = chat.agent({
|
|
43
42
|
id: "my-chat",
|
|
43
|
+
cacheControl: { type: "ephemeral" },
|
|
44
44
|
onChatStart: async () => {
|
|
45
45
|
chat.prompt.set(SYSTEM_PROMPT); // a large, stable instruction block
|
|
46
46
|
},
|
|
47
|
-
run: async ({ messages, signal }) => {
|
|
47
|
+
run: async ({ messages, signal, streamText }) => {
|
|
48
48
|
return streamText({
|
|
49
49
|
model: anthropic("claude-sonnet-4-6"),
|
|
50
50
|
// Caches the system block with a 5-minute breakpoint.
|
|
51
|
-
...chat.toStreamTextOptions({ cacheControl: { type: "ephemeral" } }),
|
|
52
51
|
messages,
|
|
53
52
|
abortSignal: signal,
|
|
54
53
|
});
|
|
@@ -59,17 +58,19 @@ export const myChat = chat.agent({
|
|
|
59
58
|
**`systemProviderOptions`** is the provider-agnostic form — pass the raw `providerOptions` so it composes with any provider:
|
|
60
59
|
|
|
61
60
|
```ts /trigger/chat.ts
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
61
|
+
export const myChat = chat.agent({
|
|
62
|
+
id: "my-chat",
|
|
63
|
+
systemProviderOptions: { anthropic: { cacheControl: { type: "ephemeral" } } },
|
|
64
|
+
run: async ({ messages, signal, streamText }) =>
|
|
65
|
+
streamText({
|
|
66
|
+
model: anthropic("claude-sonnet-4-6"),
|
|
67
|
+
messages,
|
|
68
|
+
abortSignal: signal,
|
|
69
|
+
}),
|
|
69
70
|
});
|
|
70
71
|
```
|
|
71
72
|
|
|
72
|
-
**`providerOptions` on `chat.prompt.set()`** co-locates the intent with where the prompt is defined. It carries through to `
|
|
73
|
+
**`providerOptions` on `chat.prompt.set()`** co-locates the intent with where the prompt is defined. It carries through to the managed `streamText` with no call-site change:
|
|
73
74
|
|
|
74
75
|
```ts /trigger/chat.ts
|
|
75
76
|
onChatStart: async () => {
|
|
@@ -77,17 +78,16 @@ onChatStart: async () => {
|
|
|
77
78
|
providerOptions: { anthropic: { cacheControl: { type: "ephemeral" } } },
|
|
78
79
|
});
|
|
79
80
|
},
|
|
80
|
-
run: async ({ messages, signal }) => {
|
|
81
|
+
run: async ({ messages, signal, streamText }) => {
|
|
81
82
|
return streamText({
|
|
82
83
|
model: anthropic("claude-sonnet-4-6"),
|
|
83
|
-
...chat.toStreamTextOptions(), // already cached
|
|
84
84
|
messages,
|
|
85
85
|
abortSignal: signal,
|
|
86
86
|
});
|
|
87
87
|
},
|
|
88
88
|
```
|
|
89
89
|
|
|
90
|
-
If more than one is set, the
|
|
90
|
+
If more than one is set, the most specific wins: `systemProviderOptions` overrides `cacheControl`, and both override `chat.prompt.set`'s `providerOptions`. There's no deep merge — the most specific option replaces the rest.
|
|
91
91
|
|
|
92
92
|
<Note>
|
|
93
93
|
Use the 1-hour cache for prefixes that sit idle longer than 5 minutes between turns: `cacheControl: { type: "ephemeral", ttl: "1h" }`. Writes cost more (2× vs 1.25×), so it pays off only when reads span the longer window.
|
|
@@ -100,6 +100,7 @@ Place a breakpoint on the last message and the entire conversation prefix up to
|
|
|
100
100
|
```ts /trigger/chat.ts
|
|
101
101
|
export const myChat = chat.agent({
|
|
102
102
|
id: "my-chat",
|
|
103
|
+
cacheControl: { type: "ephemeral" },
|
|
103
104
|
prepareMessages: async ({ messages }) => {
|
|
104
105
|
if (messages.length === 0) return messages;
|
|
105
106
|
const last = messages[messages.length - 1];
|
|
@@ -114,10 +115,9 @@ export const myChat = chat.agent({
|
|
|
114
115
|
},
|
|
115
116
|
];
|
|
116
117
|
},
|
|
117
|
-
run: async ({ messages, signal }) => {
|
|
118
|
+
run: async ({ messages, signal, streamText }) => {
|
|
118
119
|
return streamText({
|
|
119
120
|
model: anthropic("claude-sonnet-4-6"),
|
|
120
|
-
...chat.toStreamTextOptions({ cacheControl: { type: "ephemeral" } }),
|
|
121
121
|
messages,
|
|
122
122
|
abortSignal: signal,
|
|
123
123
|
});
|
|
@@ -149,11 +149,10 @@ Caching is provider-specific, and most providers don't use per-block breakpoints
|
|
|
149
149
|
|
|
150
150
|
```ts /trigger/chat.ts
|
|
151
151
|
// Amazon Bedrock
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
}),
|
|
156
|
-
messages,
|
|
152
|
+
export const myChat = chat.agent({
|
|
153
|
+
id: "my-chat",
|
|
154
|
+
systemProviderOptions: { bedrock: { cachePoint: { type: "default" } } },
|
|
155
|
+
run: async ({ messages, streamText }) => streamText({ messages }),
|
|
157
156
|
});
|
|
158
157
|
```
|
|
159
158
|
|
|
@@ -166,14 +165,13 @@ Usage reporting is normalized. Each provider reports cache tokens under its own
|
|
|
166
165
|
The turn's usage carries cache token counts. `chat.agent` accumulates them across turns and hands them to `run` as `previousTurnUsage` (last turn) and `totalUsage` (whole chat), both `LanguageModelUsage`:
|
|
167
166
|
|
|
168
167
|
```ts /trigger/chat.ts
|
|
169
|
-
run: async ({ messages, signal, previousTurnUsage }) => {
|
|
168
|
+
run: async ({ messages, signal, previousTurnUsage, streamText }) => {
|
|
170
169
|
// After turn 1, cacheReadTokens should be > 0 on a stable prefix.
|
|
171
170
|
console.log("cache read", previousTurnUsage?.inputTokenDetails?.cacheReadTokens);
|
|
172
171
|
console.log("cache write", previousTurnUsage?.inputTokenDetails?.cacheWriteTokens);
|
|
173
172
|
|
|
174
173
|
return streamText({
|
|
175
174
|
model: anthropic("claude-sonnet-4-6"),
|
|
176
|
-
...chat.toStreamTextOptions({ cacheControl: { type: "ephemeral" } }),
|
|
177
175
|
messages,
|
|
178
176
|
abortSignal: signal,
|
|
179
177
|
});
|
|
@@ -16,19 +16,16 @@ The chat surface works with Vercel AI SDK **v5, v6, or v7**; install whichever m
|
|
|
16
16
|
|
|
17
17
|
```ts trigger/chat.ts
|
|
18
18
|
import { chat } from "@trigger.dev/sdk/ai";
|
|
19
|
-
import {
|
|
19
|
+
import { stepCountIs } from "ai";
|
|
20
20
|
import { anthropic } from "@ai-sdk/anthropic";
|
|
21
21
|
|
|
22
22
|
export const myChat = chat.agent({
|
|
23
23
|
id: "my-chat",
|
|
24
|
-
|
|
24
|
+
// `streamText` here is the SDK's, not the one from `ai`: it carries
|
|
25
|
+
// compaction, steering, background injection, the system prompt and
|
|
26
|
+
// telemetry, so none of them have to be wired up by hand.
|
|
27
|
+
run: async ({ messages, signal, streamText }) => {
|
|
25
28
|
return streamText({
|
|
26
|
-
// Spread chat.toStreamTextOptions() FIRST — it wires up
|
|
27
|
-
// prepareStep (compaction, steering, background injection),
|
|
28
|
-
// the system prompt set via chat.prompt(), and telemetry.
|
|
29
|
-
// Skipping this is the single most common cause of subtle
|
|
30
|
-
// bugs (silent broken compaction, missing steering, etc.).
|
|
31
|
-
...chat.toStreamTextOptions(),
|
|
32
29
|
model: anthropic("claude-sonnet-4-5"),
|
|
33
30
|
messages,
|
|
34
31
|
abortSignal: signal,
|
|
@@ -38,9 +35,12 @@ The chat surface works with Vercel AI SDK **v5, v6, or v7**; install whichever m
|
|
|
38
35
|
});
|
|
39
36
|
```
|
|
40
37
|
|
|
41
|
-
<
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
<Note>
|
|
39
|
+
Take `streamText` from `run`'s argument rather than importing it from `ai`. The
|
|
40
|
+
imported one drives no `prepareStep`, so compaction, mid-turn steering and
|
|
41
|
+
background injection never run, and nothing reports it. Spreading
|
|
42
|
+
`chat.toStreamTextOptions()` into the imported one does the same job by hand.
|
|
43
|
+
</Note>
|
|
44
44
|
|
|
45
45
|
<Tip>
|
|
46
46
|
For a **custom** [`UIMessage`](https://sdk.vercel.ai/docs/reference/ai-sdk-core/ui-message) subtype (typed `data-*` parts, tool map, etc.), define the agent with [`chat.withUIMessage<...>().agent({...})`](/ai-chat/types) instead of `chat.agent`.
|
|
@@ -44,14 +44,19 @@ Options for `chat.agent()`.
|
|
|
44
44
|
| `onPreload` | `(event: PreloadEvent) => Promise<void> \| void` | — | Fires on preloaded runs before the first message |
|
|
45
45
|
| `onChatStart` | `(event: ChatStartEvent) => Promise<void> \| void` | — | Fires once per chat, on the very first user message. Does NOT fire on continuation runs or OOM-retries — see [onChatStart](/ai-chat/lifecycle-hooks#onchatstart). |
|
|
46
46
|
| `onValidateMessages` | `(event: ValidateMessagesEvent) => UIMessage[] \| Promise<UIMessage[]>` | — | Validate/transform UIMessages before model conversion. See [onValidateMessages](/ai-chat/lifecycle-hooks#onvalidatemessages) |
|
|
47
|
-
| `
|
|
47
|
+
| `storage` | `TranscriptStorage` | `defaultStorage` | Where the conversation is persisted and read back. The platform snapshot by default; bring your own to write each change to your database. See [Transcript storage](/ai-chat/transcript-storage) |
|
|
48
|
+
| `hydrateMessages` | `(event: HydrateMessagesEvent) => UIMessage[] \| Promise<UIMessage[]>` | — | **Deprecated.** Load message history from backend, replacing the linear accumulator. Use `loadContext` on a `storage` instead; cannot be combined with `storage`. See [hydrateMessages](/ai-chat/lifecycle-hooks#hydratemessages) |
|
|
48
49
|
| `actionSchema` | `TaskSchema` | — | Schema for validating custom actions sent via `transport.sendAction()`. See [Actions](/ai-chat/actions) |
|
|
49
|
-
| `onAction` | `(event: ActionEvent) => Promise<
|
|
50
|
+
| `onAction` | `(event: ActionEvent) => Promise<void \| ActionTurn> \| void \| ActionTurn` | — | Handle custom actions. Actions are state edits: only `hydrateMessages` (or a storage's `loadContext`) + `onAction` fire. Return `chat.turn()` to run a turn on the edited history, or nothing for an edit only. See [Actions](/ai-chat/actions) |
|
|
50
51
|
| `onTurnStart` | `(event: TurnStartEvent) => Promise<void> \| void` | — | Fires every turn before `run()` |
|
|
51
52
|
| `onBeforeTurnComplete` | `(event: BeforeTurnCompleteEvent) => Promise<void> \| void` | — | Fires after response but before stream closes. Includes `writer`. |
|
|
52
53
|
| `onTurnComplete` | `(event: TurnCompleteEvent) => Promise<void> \| void` | — | Fires after each turn completes (stream closed) |
|
|
53
54
|
| `onCompacted` | `(event: CompactedEvent) => Promise<void> \| void` | — | Fires when compaction occurs. Includes `writer`. See [Compaction](/ai-chat/compaction) |
|
|
54
55
|
| `compaction` | `ChatAgentCompactionOptions` | — | Automatic context compaction. See [Compaction](/ai-chat/compaction) |
|
|
56
|
+
| `registry` | `{ languageModel(id: string): unknown }` | — | A provider registry, so the managed `streamText` can resolve a model set through `chat.prompt.set()` |
|
|
57
|
+
| `system` | `string \| SystemModelMessage` | — | The agent's system prompt. Injected instructions append to it. Set it here, at the `streamText` call site, or through `chat.prompt.set()`, but only in one of them |
|
|
58
|
+
| `cacheControl` | `SystemCacheControl` | — | Mark the system prompt for provider-side caching. See [Prompt caching](/ai-chat/prompt-caching) |
|
|
59
|
+
| `systemProviderOptions` | `ProviderMetadata` | — | Raw provider options for the system block. Takes precedence over `cacheControl` |
|
|
55
60
|
| `pendingMessages` | `PendingMessagesOptions` | — | Mid-execution message injection. See [Pending Messages](/ai-chat/pending-messages) |
|
|
56
61
|
| `prepareMessages` | `(event: PrepareMessagesEvent) => ModelMessage[]` | — | Transform model messages before use (cache breaks, context injection, etc.) |
|
|
57
62
|
| `tools` | `ToolSet \| ((event: ResolveToolsEvent) => ToolSet \| Promise<ToolSet>)` | — | Tools for this agent. Threads each tool's `toModelOutput` through cross-turn history re-conversion, and hands the resolved set back on the run payload. Static set or per-turn function. See [Tools](/ai-chat/tools). |
|
|
@@ -98,9 +103,10 @@ The payload passed to the `run` function.
|
|
|
98
103
|
| `ctx` | `TaskRunContext` | Full task run context — same as `task` `run`’s `{ ctx }` |
|
|
99
104
|
| `messages` | `ModelMessage[]` | Model-ready messages — pass directly to `streamText` |
|
|
100
105
|
| `tools` | `ToolSet` | Resolved tools declared on the agent config (empty object when none). Pass straight to `streamText`. See [Tools](/ai-chat/tools). |
|
|
106
|
+
| `streamText` | `typeof streamText` | The AI SDK's `streamText` with this agent's managed options already applied: the prompt, skill tools, telemetry, and the `prepareStep` that delivers steering, compaction and injected context. Prefer it over importing `streamText` from `ai`. See [The managed streamText](/ai-chat/backend#the-managed-streamtext). |
|
|
101
107
|
| `chatId` | `string` | Your conversation ID (the session's `externalId`) |
|
|
102
108
|
| `sessionId` | `string` | Friendly ID of the backing Session (`session_*`). Use with `sessions.open()` for advanced cases. Always set — every chat.agent run is bound to a Session. |
|
|
103
|
-
| `trigger` | `"submit-message" \| "regenerate-message"` | What triggered the request
|
|
109
|
+
| `trigger` | `"submit-message" \| "regenerate-message" \| "action-turn"` | What triggered the request; `"action-turn"` is a turn requested by `chat.turn()` |
|
|
104
110
|
| `messageId` | `string \| undefined` | Message ID (for regenerate) |
|
|
105
111
|
| `clientData` | Typed by `clientDataSchema` | Custom data from the frontend (typed when schema is provided) |
|
|
106
112
|
| `continuation` | `boolean` | Whether this run is continuing an existing chat (previous run ended) |
|
|
@@ -213,9 +219,38 @@ Passed to the `tools` function form on `chat.agent`, once per turn, to resolve t
|
|
|
213
219
|
| `continuation` | `boolean` | Whether this run is continuing an existing chat |
|
|
214
220
|
| `clientData` | Typed by `clientDataSchema` | Custom data from the frontend |
|
|
215
221
|
|
|
222
|
+
## TranscriptStorage
|
|
223
|
+
|
|
224
|
+
The persistence adapter set through `chat.agent({ storage })`. See [Transcript storage](/ai-chat/transcript-storage). All types below are exported from `@trigger.dev/sdk/ai`.
|
|
225
|
+
|
|
226
|
+
| Member | Signature | Description |
|
|
227
|
+
| --- | --- | --- |
|
|
228
|
+
| `load` | `(scope: TranscriptScope, opts?: TranscriptLoadOptions) => Promise<TranscriptLoadResult>` | The conversation, in order. Called once at a continuation boot and by `chat.createLoadTranscriptAction` for rendering. |
|
|
229
|
+
| `save` | `(ctx: TranscriptStorageContext, changeset: TranscriptChangeset) => Promise<void>` | Apply the changes since the last save. Called after every turn, failed turn and history-changing action. |
|
|
230
|
+
| `loadContext?` | `(scope: TranscriptScope, event: LoadContextEvent) => Promise<UIMessage[]>` | Optional. When present, the storage owns the model's context: called on every turn and action in place of the runtime's transcript. Same event shape as `HydrateMessagesEvent`. |
|
|
231
|
+
|
|
232
|
+
| Type | Shape |
|
|
233
|
+
| --- | --- |
|
|
234
|
+
| `TranscriptScope<TClientData>` | `{ chatId: string; clientData: TClientData }` |
|
|
235
|
+
| `TranscriptStorageContext<TClientData>` | `TranscriptScope` plus `{ turn: number; trigger: "submit-message" \| "regenerate-message" \| "action"; runId: string; ctx: TaskRunContext }` |
|
|
236
|
+
| `TranscriptChange` | `{ op: "put"; message: UIMessage; final?: boolean }` \| `{ op: "remove"; id: string }` \| `{ op: "truncateAfter"; afterId: string }` \| `{ op: "state"; value: unknown \| null }` |
|
|
237
|
+
| `TranscriptChangeset` | `{ reason: "turn-complete" \| "turn-error" \| "action" \| "compaction" \| "recovery"; changes: TranscriptChange[]; transcript: TranscriptState; cursors?: TranscriptCursors }` |
|
|
238
|
+
| `TranscriptState` | `{ entries: Array<{ id: string; final: boolean; message: UIMessage }>; state: unknown \| null }`: the whole conversation after the changeset's changes, for stores that write one document |
|
|
239
|
+
| `TranscriptCursors` | `{ lastOutEventId?: string; lastInEventId?: string }` |
|
|
240
|
+
| `TranscriptLoadOptions` | `{ limit?: number; before?: string }` |
|
|
241
|
+
| `TranscriptLoadResult` | `{ messages: UIMessage[]; state: unknown \| null; cursors?: TranscriptCursors; nextCursor?: string }` |
|
|
242
|
+
|
|
243
|
+
| Export | Description |
|
|
244
|
+
| --- | --- |
|
|
245
|
+
| `defaultStorage` | The platform snapshot storage the agent uses when `storage` is not set. Equal to `snapshotTranscriptStorage()`. |
|
|
246
|
+
| `snapshotTranscriptStorage()` | Factory for the platform snapshot storage. |
|
|
247
|
+
| `memoryTranscriptStorage()` | An in-process storage that also records every changeset it receives. The reference implementation. |
|
|
248
|
+
| `reduceTranscriptChanges(state, changes)` | Pure reducer that applies changes to `{ entries, state }`. Useful for building a storage over a document store. |
|
|
249
|
+
| `runTranscriptStorageTests(makeStorage, options?)` | From `@trigger.dev/sdk/ai/test`. The conformance suite for a storage implementation. Pass `{ api: { describe, it, expect } }` when test globals are off, and `clientData` when your storage scopes by it. |
|
|
250
|
+
|
|
216
251
|
## HydrateMessagesEvent
|
|
217
252
|
|
|
218
|
-
Passed to the `hydrateMessages` callback. See [hydrateMessages](/ai-chat/lifecycle-hooks#hydratemessages).
|
|
253
|
+
Passed to the `hydrateMessages` callback. See [hydrateMessages](/ai-chat/lifecycle-hooks#hydratemessages). `hydrateMessages` is deprecated; `LoadContextEvent`, passed to a storage's `loadContext`, has the same shape.
|
|
219
254
|
|
|
220
255
|
| Field | Type | Description |
|
|
221
256
|
| ------------------ | ----------------------------------------------------- | --------------------------------------------------------- |
|
|
@@ -364,8 +399,8 @@ Passed to `compactUIMessages` and `compactModelMessages` callbacks.
|
|
|
364
399
|
| Field | Type | Description |
|
|
365
400
|
| --------------- | -------------------- | ---------------------------------------------------- |
|
|
366
401
|
| `summary` | `string` | The generated summary text |
|
|
367
|
-
| `uiMessages` | `UIMessage[]` | Current UI messages (
|
|
368
|
-
| `modelMessages` | `ModelMessage[]` | Current model messages (
|
|
402
|
+
| `uiMessages` | `UIMessage[]` | Current UI messages (the transcript) |
|
|
403
|
+
| `modelMessages` | `ModelMessage[]` | Current model messages (the lane the model is sent; after a compaction this is the summary plus what followed it, not the whole transcript) |
|
|
369
404
|
| `chatId` | `string` | Chat session ID |
|
|
370
405
|
| `turn` | `number` | Current turn (0-indexed) |
|
|
371
406
|
| `clientData` | `unknown` | Custom data from the frontend |
|
|
@@ -490,9 +525,9 @@ Options for [`chat.headStart()`](/ai-chat/fast-starts#head-start), the warm-serv
|
|
|
490
525
|
| `agentId` | `string` | required | The `chat.agent` / `chat.customAgent` id to hand off to |
|
|
491
526
|
| `run` | `(args: HeadStartRunArgs) => Promise<StreamTextResult>` | required | First-turn callback. Call `streamText` and spread `chat.toStreamTextOptions({ tools })` |
|
|
492
527
|
| `idleTimeoutInSeconds` | `number` | `60` | How long the agent waits for the handover signal |
|
|
493
|
-
| `triggerConfig` | `Partial<SessionTriggerConfig>` | `undefined` | Run options (tags, queue, machine, maxAttempts, maxDuration, region, lockToVersion) for the auto-triggered handover-prepare run. The `chat:{chatId}` tag is prepended automatically and counts toward the 10-tag limit |
|
|
528
|
+
| `triggerConfig` | `Partial<SessionTriggerConfig>` | `undefined` | Run options (tags, queue, machine, maxAttempts, maxDuration, region, lockToVersion, externalDeploymentId) for the auto-triggered handover-prepare run. The `chat:{chatId}` tag is prepended automatically and counts toward the 10-tag limit |
|
|
494
529
|
|
|
495
|
-
`chat.headStart(options)` returns the handler `(req: Request) => Promise<Response>`. The `run` callback receives `HeadStartRunArgs`: `{ messages: UIMessage[], signal: AbortSignal, chat: HeadStartChatHelper }`, where the helper exposes `chat.toStreamTextOptions({ tools })` and a `chat.session` escape hatch. See [Head Start](/ai-chat/fast-starts#head-start) for the full guide.
|
|
530
|
+
`chat.headStart(options)` returns the handler `(req: Request) => Promise<Response>`. The `run` callback receives `HeadStartRunArgs`: `{ messages: UIMessage[], signal: AbortSignal, chat: HeadStartChatHelper }`, where the helper exposes `chat.toStreamTextOptions({ tools })` and a `chat.session` escape hatch (whose `pendingVersion` says whether the agent run is parked waiting for its deployment). See [Head Start](/ai-chat/fast-starts#head-start) for the full guide.
|
|
496
531
|
|
|
497
532
|
## chat namespace
|
|
498
533
|
|
|
@@ -509,8 +544,10 @@ All methods available on the `chat` object from `@trigger.dev/sdk/ai`.
|
|
|
509
544
|
| `chat.messages` | Incoming message mailbox; supports non-consuming `.peek()` / `.hasPending()`, single-record `.next()`, `.on()`, and suspend-aware `.waitWithIdleTimeout()` |
|
|
510
545
|
| `chat.local<T>({ id })` | Create a per-run typed local (see [`chat.local`](/ai-chat/chat-local)) |
|
|
511
546
|
| `chat.createStartSessionAction(taskId, options?)` | Returns a server action that creates a chat Session + triggers the first run + returns a session-scoped PAT. Idempotent on `(env, externalId)`. |
|
|
547
|
+
| `chat.createLoadTranscriptAction(storage, options?)` | Returns a server action that reads a conversation from a transcript storage (`{ chatId, clientData?, limit?, before? }` → `TranscriptLoadResult`). Pair with `useLoadTranscript`. Performs no application authorization: authorize `chatId` for the signed-in user in your own code. See [Transcript storage](/ai-chat/transcript-storage#reading-the-transcript) |
|
|
512
548
|
| `chat.waitForHandover(options)` | Wait for a [`chat.headStart`](/ai-chat/fast-starts#handover-with-custom-agents) handover signal in a custom loop. Returns the signal or `null`. `chat.MessageAccumulator` wraps this as `consumeHandover()` / `applyHandover()` |
|
|
513
549
|
| `chat.requestUpgrade()` | End the current run after this turn so the next message starts on the latest agent version. Server-orchestrated handoff. |
|
|
550
|
+
| `chat.close({ reason })` | End the conversation permanently: close the session row, write a terminal `session-closed` record, and exit without a continuation. Decide it before the turn ends (`onBeforeTurnComplete`, not `onTurnComplete`) so the client sees the closed state on that turn. |
|
|
514
551
|
| `chat.endAndContinue()` | In a hand-rolled custom agent, hand off the Session to a fresh continuation run. Call between turns after detaching input listeners, then return immediately. The promise rejects if the handoff fails. |
|
|
515
552
|
| `chat.setTurnTimeout(duration)` | Override turn timeout at runtime (e.g. `"2h"`) |
|
|
516
553
|
| `chat.setTurnTimeoutInSeconds(seconds)` | Override turn timeout at runtime (in seconds) |
|
|
@@ -659,6 +696,7 @@ The `onEvent` callback receives a `ChatTransportEvent` (exported from `@trigger.
|
|
|
659
696
|
| --- | --- | --- |
|
|
660
697
|
| `message-sent` | `messageId?`, `source`, `durationMs`, `partId?`, `bodyBytes?` | A send was durably acknowledged — a 2xx from the session input stream append (or the `headStart` POST), after any internal token-refresh retries. This means the message is durably written to the stream the agent consumes from, not merely "request accepted". `partId` is the append's idempotency key, also stored on the server-side record. |
|
|
661
698
|
| `message-send-failed` | `messageId?`, `source`, `error`, `status?`, `durationMs`, `partId?`, `bodyBytes?` | A send definitively failed after internal retries. Fires in addition to `useChat`'s `onError`. |
|
|
699
|
+
| `run-pending-version` | `source` | The chat's run is parked waiting for the deployment carrying its external deployment id ([version skew protection](/deployment/version-skew-protection#chat-sessions)). Everything already sent is durable and answered once the deployment lands. `source` is `"start"` (learned while starting the session), `"send"` (from a message append, re-emitted on every send while parked) `"head-start"` (from the `headStart` POST, where step 1 still streams from your server and only step 2 waits) or `"upgrade"` (an automatic version handover whose successor is parked on a deployment that has not landed). |
|
|
662
700
|
| `stream-connected` | `resumed`, `lastEventId?`, `messageId?` | The SSE subscription to the session's output stream started delivering. `resumed: true` when reconnecting from a stored cursor (page reload) rather than following a fresh send. `lastEventId` is the cursor it connected from. |
|
|
663
701
|
| `first-chunk` | `chunkType?`, `lastEventId?`, `messageId?`, `sinceSendMs?` | The first response chunk of a turn arrived. `sinceSendMs` is the delta from the last turn-producing send — time to first token without any bookkeeping. |
|
|
664
702
|
| `turn-completed` | `lastEventId?`, `sessionInEventId?`, `messageId?`, `sinceSendMs?` | The agent's turn-complete control record arrived — the "finished answering" signal. `sinceSendMs` is the full turn latency; `sessionInEventId` is the cursor the agent can safely resume its input stream from. Treat it as a lower bound: it is held back behind any message still waiting to be handled, so it can be below the sequence of the record this turn answered. Do not use it to decide whether a turn boundary belongs to your own send. |
|
|
@@ -794,7 +832,7 @@ See [Stop generation](/ai-chat/frontend#stop-generation) for full details.
|
|
|
794
832
|
|
|
795
833
|
### transport.sendAction()
|
|
796
834
|
|
|
797
|
-
Send a custom action to the agent
|
|
835
|
+
Send a custom action to the agent, outside `useChat`. Actions wake the agent from suspension and fire `onAction`. An action that returns `chat.turn()` is followed by a turn; its answer arrives on the returned stream, which the caller must read. From a `useChat` app, send actions as requests instead (`sendMessage(undefined, { body: { action } })` or the `useChatActions` hook) so `useChat` renders the answer.
|
|
798
836
|
|
|
799
837
|
```ts
|
|
800
838
|
transport.sendAction(chatId: string, action: unknown): Promise<ReadableStream<UIMessageChunk>>
|
|
@@ -869,6 +907,26 @@ Second argument to `chat.createStartSessionAction(taskId, options?)`. Controls h
|
|
|
869
907
|
| `baseURL` | `string \| (ctx: { endpoint: "sessions" \| "auth"; chatId: string }) => string` | `apiClientManager.baseURL` | API base URL. `endpoint` is `"sessions"` for `POST /api/v1/sessions` or `"auth"` for `POST /api/v1/auth/jwt/claims` (only fires when `tokenTTL` is set). |
|
|
870
908
|
| `fetch` | `(url: string, init: RequestInit, ctx: { endpoint: "sessions" \| "auth"; chatId: string }) => Promise<Response>` | — | Per-request fetch override. Use to route session-create through a trusted edge proxy so `basePayload.metadata` is rewritten before reaching `api.trigger.dev`. |
|
|
871
909
|
|
|
910
|
+
## createLoadTranscriptAction options
|
|
911
|
+
|
|
912
|
+
Second argument to `chat.createLoadTranscriptAction(storage, options?)`.
|
|
913
|
+
|
|
914
|
+
| Option | Type | Default | Description |
|
|
915
|
+
| ----------- | ------------------------ | -------------------------- | --------------------------------------------------------------------------- |
|
|
916
|
+
| `limit` | `number` | — | Page size when the caller passes none. Returns the most recent messages and a `nextCursor`. |
|
|
917
|
+
| `apiClient` | `ApiClientConfiguration` | `apiClientManager` config | Scope the read to a specific API client (secret key, base URL). The default storage reads through it. |
|
|
918
|
+
|
|
919
|
+
## useLoadTranscript
|
|
920
|
+
|
|
921
|
+
`useLoadTranscript(chatId, load, options?)` from `@trigger.dev/sdk/chat/react`. Loads a conversation through a `chat.createLoadTranscriptAction` action, for rendering before the chat connects. Re-runs when `chatId` changes.
|
|
922
|
+
|
|
923
|
+
| Option | Type | Description |
|
|
924
|
+
| ----------- | ---------------------- | -------------------------------------------------------------------------------------------- |
|
|
925
|
+
| `transport` | `TriggerChatTransport` | Seed the transport's resume cursor for this chat from the transcript, once it knows the session. |
|
|
926
|
+
| `limit` | `number` | Page size passed to the action. |
|
|
927
|
+
|
|
928
|
+
Returns `{ messages, isLoading, error, nextCursor }`. `nextCursor` is the id to pass as `before` to the action for the page before this one.
|
|
929
|
+
|
|
872
930
|
## useMultiTabChat
|
|
873
931
|
|
|
874
932
|
React hook for multi-tab message coordination. Import from `@trigger.dev/sdk/chat/react`.
|
|
@@ -929,9 +987,10 @@ Tokens minted for `TriggerChatTransport` and `AgentChat` are session-scoped —
|
|
|
929
987
|
| Scope | Grants |
|
|
930
988
|
| --- | --- |
|
|
931
989
|
| `read:sessions:<chatId>` | Subscribe to `.out`, HEAD probe the stream, retrieve the session row |
|
|
990
|
+
| `read:sessions:<chatId>:out` | Subscribe to `.out` and HEAD probe the stream only. Use this when the browser needs nothing but the response stream. |
|
|
932
991
|
| `write:sessions:<chatId>` | Append to `.in`, close the session, end-and-continue, update metadata |
|
|
933
992
|
|
|
934
|
-
Tokens are produced by `auth.createPublicToken({ scopes: { read: { sessions: chatId }, write: { sessions: chatId } } })` (used by the customer's `accessToken` server action) or returned automatically from `chat.createStartSessionAction` / `POST /api/v1/sessions`. Either form authorizes both URL forms (`/sessions/{chatId}/...` and `/sessions/session_*/...`) on every read and write route.
|
|
993
|
+
Reading `.in` requires a secret key, so no browser token can replay what clients sent. Tokens are produced by `auth.createPublicToken({ scopes: { read: { sessions: chatId }, write: { sessions: chatId } } })` (used by the customer's `accessToken` server action) or returned automatically from `chat.createStartSessionAction` / `POST /api/v1/sessions`. Either form authorizes both URL forms (`/sessions/{chatId}/...` and `/sessions/session_*/...`) on every read and write route.
|
|
935
994
|
|
|
936
995
|
## Related
|
|
937
996
|
|
|
@@ -111,7 +111,7 @@ const { id, runId, publicAccessToken, isCached } = await sessions.start({
|
|
|
111
111
|
| `type` | `string` | Free-form discriminator. `chat.agent` uses `"chat.agent"`. |
|
|
112
112
|
| `externalId` | `string?` | Your stable identity. Cannot start with `session_` (reserved). |
|
|
113
113
|
| `taskIdentifier` | `string` | Task this session triggers runs against. |
|
|
114
|
-
| `triggerConfig` | `SessionTriggerConfig` | Trigger options applied to every run: `tags` (up to 10, same as [run tags](/tags); the chat helpers such as `chat.createStartSessionAction` and `AgentChat` add a `chat:{chatId}` tag themselves, which uses one slot. Direct `sessions.start` callers get all 10 and must add any chat tag themselves), `queue`, `machine`, `maxAttempts`, `idleTimeoutInSeconds`, `basePayload
|
|
114
|
+
| `triggerConfig` | `SessionTriggerConfig` | Trigger options applied to every run: `tags` (up to 10, same as [run tags](/tags); the chat helpers such as `chat.createStartSessionAction` and `AgentChat` add a `chat:{chatId}` tag themselves, which uses one slot. Direct `sessions.start` callers get all 10 and must add any chat tag themselves), `queue`, `machine`, `maxAttempts`, `maxDuration`, `region`, `idleTimeoutInSeconds`, `basePayload`, and the version pins `lockToVersion` / [`externalDeploymentId`](/deployment/version-skew-protection#chat-sessions). |
|
|
115
115
|
| `tags` | `string[]?` | Up to 10 tags on the Session row (separate from `triggerConfig.tags`). |
|
|
116
116
|
| `metadata` | `Record<string, unknown>?` | Arbitrary JSON. |
|
|
117
117
|
| `expiresAt` | `Date?` | Hard retention deadline. |
|
|
@@ -146,6 +146,11 @@ Mark a Session as closed. Terminal and idempotent. The optional `reason` is stor
|
|
|
146
146
|
await sessions.close(chatId, { reason: "user signed out" });
|
|
147
147
|
```
|
|
148
148
|
|
|
149
|
+
Closing tells a live run too: the close lands on the session's input channel, so an idle or suspended agent exits its loop on the next wake rather than waiting out its idle timeout. After it lands, appends to `.in` are refused with HTTP 409 and `code: "session_closed"`.
|
|
150
|
+
|
|
151
|
+
To close from inside the agent instead, call [`chat.close()`](/ai-chat/backend#ending-the-conversation). It writes a terminal record to the response stream so the browser learns the reason, then closes the row.
|
|
152
|
+
|
|
153
|
+
|
|
149
154
|
### `sessions.list(options?, requestOptions?)`
|
|
150
155
|
|
|
151
156
|
Cursor-paginated list of Sessions in the current environment. Returns a `CursorPagePromise` you can iterate with `for await`.
|
|
@@ -138,7 +138,7 @@ A side channel's streams are bounded by the same retention as the rest of your r
|
|
|
138
138
|
|
|
139
139
|
## Auth
|
|
140
140
|
|
|
141
|
-
A side channel is covered by the session's public access token: a token scoped to `read:sessions:{id}` / `write:sessions:{id}` grants every channel of that session. Mint a narrower token scoped to a single channel with `read:sessions:{id}:channels:{name}`. Writing a channel's `.out` requires secret-key auth (only the agent run), so a browser cannot forge frames; `.in` is writable with the session token. See [Realtime auth](/realtime/auth).
|
|
141
|
+
A side channel is covered by the session's public access token: a token scoped to `read:sessions:{id}` / `write:sessions:{id}` grants every channel of that session. Mint a narrower token scoped to a single channel with `read:sessions:{id}:channels:{name}`, or to one direction of it with `read:sessions:{id}:channels:{name}:out`. Writing a channel's `.out` requires secret-key auth (only the agent run), so a browser cannot forge frames; `.in` is writable with the session token. See [Realtime auth](/realtime/auth).
|
|
142
142
|
|
|
143
143
|
### Scope tokens to the channel, not the whole session
|
|
144
144
|
|
package/docs/ai-chat/testing.mdx
CHANGED
|
@@ -203,7 +203,7 @@ Equivalent to the frontend's `useChat().regenerate()` — replays a turn with th
|
|
|
203
203
|
|
|
204
204
|
### sendAction
|
|
205
205
|
|
|
206
|
-
Routes a payload through `actionSchema` + `onAction`.
|
|
206
|
+
Routes a payload through `actionSchema` + `onAction`. An action is a state edit: only `hydrateMessages` and `onAction` fire, unless `onAction` returns `chat.turn()`, in which case a turn runs on the edited history and the returned `turn.rawChunks` carries that turn's answer.
|
|
207
207
|
|
|
208
208
|
```ts
|
|
209
209
|
const turn = await harness.sendAction({ type: "undo" });
|
|
@@ -634,6 +634,7 @@ The harness's initial wire payload depends on `mode`:
|
|
|
634
634
|
| `sendHandover({ partialAssistantMessage, isFinal?, messageId? })` | Dispatch a `handover` signal — only meaningful when started with `mode: "handover-prepare"`. The agent picks up partial assistant messages and continues the turn. |
|
|
635
635
|
| `sendHandoverSkip()` | Dispatch a `handover-skip` signal — only meaningful when started with `mode: "handover-prepare"`. The agent exits cleanly without firing turn hooks. |
|
|
636
636
|
| `sendAction(action)` | Route a custom action through `actionSchema` + `onAction`. |
|
|
637
|
+
| `sendPendingMessage(message)` | Append a user message mid-turn without waiting for a turn to complete, so it reaches the running turn as a steering message. Resolves once the record has landed on `session.in`. |
|
|
637
638
|
| `sendStop(message?)` | Fire a stop signal. Does not wait for the turn — the run's `signal.aborted` becomes `true`. |
|
|
638
639
|
| `seedSnapshot(snapshot)` | Pre-seed the snapshot read for the next boot. Effective on the next run boot only. |
|
|
639
640
|
| `seedSessionOutTail(chunks?)` | Pre-seed `session.out` chunks for the next boot's replay. Reduces to settled assistant turns. |
|
package/docs/ai-chat/tools.mdx
CHANGED
|
@@ -8,7 +8,7 @@ description: "Declare tools on chat.agent so toModelOutput survives across turns
|
|
|
8
8
|
|
|
9
9
|
```ts
|
|
10
10
|
import { chat } from "@trigger.dev/sdk/ai";
|
|
11
|
-
import {
|
|
11
|
+
import { stepCountIs, tool } from "ai";
|
|
12
12
|
import { anthropic } from "@ai-sdk/anthropic";
|
|
13
13
|
import { z } from "zod";
|
|
14
14
|
|
|
@@ -23,9 +23,9 @@ const tools = {
|
|
|
23
23
|
export const myChat = chat.agent({
|
|
24
24
|
id: "my-chat",
|
|
25
25
|
tools, // ← declare here
|
|
26
|
-
run: async ({ messages, tools, signal }) =>
|
|
26
|
+
run: async ({ messages, tools, signal, streamText }) =>
|
|
27
27
|
streamText({
|
|
28
|
-
|
|
28
|
+
tools,
|
|
29
29
|
model: anthropic("claude-sonnet-4-5"),
|
|
30
30
|
messages,
|
|
31
31
|
abortSignal: signal,
|
|
@@ -46,10 +46,15 @@ There are three places a tool set shows up. Declare once, reuse:
|
|
|
46
46
|
| Surface | What it's for |
|
|
47
47
|
| --- | --- |
|
|
48
48
|
| `chat.agent({ tools })` | Re-applies `toModelOutput` on prior-turn history; hands the set back typed on the `run()` payload. |
|
|
49
|
-
| `
|
|
50
|
-
| `
|
|
49
|
+
| `streamText({ tools })` on the `run` argument's `streamText` | What the model actually calls. Detects which calls need [HITL approval](/ai-chat/patterns/human-in-the-loop) (`needsApproval`) and merges the auto-injected [skill](/ai-chat/patterns/skills) tools on top. Naming `tools` replaces the config set for that call, so you can narrow it; omitting `tools` falls back to the config set. |
|
|
50
|
+
| `chat.toStreamTextOptions({ tools })` | The same job by hand, for a [custom agent](#manual-turn-loops-chatcustomagent), which has no `run` argument. |
|
|
51
51
|
|
|
52
|
-
The canonical pattern: declare `tools` on the config, read them back from the `run()` payload, and pass that to `
|
|
52
|
+
The canonical pattern: declare `tools` on the config, read them back from the `run()` payload, and pass that set to the `streamText` the payload also carries.
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
run: async ({ messages, tools, signal, streamText }) =>
|
|
56
|
+
streamText({ model, messages, tools, abortSignal: signal }),
|
|
57
|
+
```
|
|
53
58
|
|
|
54
59
|
<Tip>
|
|
55
60
|
Conversion only reads each tool's `inputSchema` and `toModelOutput`, never `execute`. If you keep heavy `execute` dependencies out of a module (for bundle reasons), you can declare a lightweight schema-only tool map on the config and add the executes where you call `streamText`.
|
|
@@ -80,9 +85,9 @@ const tools = {
|
|
|
80
85
|
export const chartChat = chat.agent({
|
|
81
86
|
id: "chart-chat",
|
|
82
87
|
tools, // ← without this, the image is "remembered" on turn 1 and gone from turn 2
|
|
83
|
-
run: async ({ messages, tools, signal }) =>
|
|
88
|
+
run: async ({ messages, tools, signal, streamText }) =>
|
|
84
89
|
streamText({
|
|
85
|
-
|
|
90
|
+
tools,
|
|
86
91
|
model: anthropic("claude-sonnet-4-5"),
|
|
87
92
|
messages,
|
|
88
93
|
abortSignal: signal,
|
|
@@ -104,9 +109,9 @@ export const myChat = chat
|
|
|
104
109
|
searchDocs,
|
|
105
110
|
...(clientData?.plan === "pro" ? { deepResearch } : {}),
|
|
106
111
|
}),
|
|
107
|
-
run: async ({ messages, tools, signal }) =>
|
|
112
|
+
run: async ({ messages, tools, signal, streamText }) =>
|
|
108
113
|
streamText({
|
|
109
|
-
|
|
114
|
+
tools,
|
|
110
115
|
model: anthropic("claude-sonnet-4-5"),
|
|
111
116
|
messages,
|
|
112
117
|
abortSignal: signal,
|
|
@@ -131,10 +136,10 @@ The resolved set is what lands on the `run()` payload's `tools`.
|
|
|
131
136
|
The `run()` payload's `tools` is typed to whatever you declared, so you can pass it straight through without re-importing the map:
|
|
132
137
|
|
|
133
138
|
```ts
|
|
134
|
-
run: async ({ messages, tools, signal }) => {
|
|
139
|
+
run: async ({ messages, tools, signal, streamText }) => {
|
|
135
140
|
// `tools` is typed as your tool set, not a broad `ToolSet`
|
|
136
141
|
return streamText({
|
|
137
|
-
|
|
142
|
+
tools,
|
|
138
143
|
model: anthropic("claude-sonnet-4-5"),
|
|
139
144
|
messages,
|
|
140
145
|
abortSignal: signal,
|
|
@@ -160,7 +165,7 @@ This is shorthand for `UIMessage<unknown, UIDataTypes, InferUITools<typeof tools
|
|
|
160
165
|
|
|
161
166
|
## Skills
|
|
162
167
|
|
|
163
|
-
[Agent skills](/ai-chat/patterns/skills) are auto-injected as tools (`loadSkill`, `readFile`, `bash`) by `chat.toStreamTextOptions()
|
|
168
|
+
[Agent skills](/ai-chat/patterns/skills) are auto-injected as tools (`loadSkill`, `readFile`, `bash`) by the managed `streamText`, or by `chat.toStreamTextOptions()` if you build the options yourself. They're separate from your config `tools`: declare your own tools on the config (so their `toModelOutput` survives across turns), and the merge happens at call time. Skill tools don't define `toModelOutput`, so they don't need to be on the config.
|
|
164
169
|
|
|
165
170
|
## Manual turn loops (`chat.customAgent`)
|
|
166
171
|
|