@trigger.dev/sdk 4.5.0-rc.6 → 4.5.0-rc.7
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/v3/ai.d.ts +171 -5
- package/dist/commonjs/v3/ai.js +309 -22
- package/dist/commonjs/v3/ai.js.map +1 -1
- package/dist/commonjs/v3/chat-server.d.ts +8 -0
- package/dist/commonjs/v3/chat-server.js +32 -10
- package/dist/commonjs/v3/chat-server.js.map +1 -1
- package/dist/commonjs/v3/chat-server.test.js +51 -0
- package/dist/commonjs/v3/chat-server.test.js.map +1 -1
- package/dist/commonjs/v3/createStartSessionAction.test.js +30 -0
- package/dist/commonjs/v3/createStartSessionAction.test.js.map +1 -1
- package/dist/commonjs/v3/sessions.d.ts +3 -2
- package/dist/commonjs/v3/sessions.js +3 -2
- package/dist/commonjs/v3/sessions.js.map +1 -1
- package/dist/commonjs/version.js +1 -1
- package/dist/esm/v3/ai.d.ts +171 -5
- package/dist/esm/v3/ai.js +309 -22
- package/dist/esm/v3/ai.js.map +1 -1
- package/dist/esm/v3/chat-server.d.ts +8 -0
- package/dist/esm/v3/chat-server.js +32 -10
- package/dist/esm/v3/chat-server.js.map +1 -1
- package/dist/esm/v3/chat-server.test.js +51 -0
- package/dist/esm/v3/chat-server.test.js.map +1 -1
- package/dist/esm/v3/createStartSessionAction.test.js +30 -0
- package/dist/esm/v3/createStartSessionAction.test.js.map +1 -1
- package/dist/esm/v3/sessions.d.ts +3 -2
- package/dist/esm/v3/sessions.js +3 -2
- package/dist/esm/v3/sessions.js.map +1 -1
- package/dist/esm/version.js +1 -1
- package/docs/ai/prompts.mdx +430 -0
- package/docs/ai-chat/actions.mdx +115 -0
- package/docs/ai-chat/anatomy.mdx +71 -0
- package/docs/ai-chat/backend.mdx +817 -0
- package/docs/ai-chat/background-injection.mdx +221 -0
- package/docs/ai-chat/changelog.mdx +850 -0
- package/docs/ai-chat/chat-local.mdx +174 -0
- package/docs/ai-chat/client-protocol.mdx +1081 -0
- package/docs/ai-chat/compaction.mdx +411 -0
- package/docs/ai-chat/custom-agents.mdx +364 -0
- package/docs/ai-chat/error-handling.mdx +415 -0
- package/docs/ai-chat/fast-starts.mdx +672 -0
- package/docs/ai-chat/frontend.mdx +580 -0
- package/docs/ai-chat/how-it-works.mdx +230 -0
- package/docs/ai-chat/lifecycle-hooks.mdx +530 -0
- package/docs/ai-chat/mcp.mdx +101 -0
- package/docs/ai-chat/overview.mdx +90 -0
- package/docs/ai-chat/patterns/branching-conversations.mdx +284 -0
- package/docs/ai-chat/patterns/code-sandbox.mdx +126 -0
- package/docs/ai-chat/patterns/database-persistence.mdx +414 -0
- package/docs/ai-chat/patterns/human-in-the-loop.mdx +275 -0
- package/docs/ai-chat/patterns/large-payloads.mdx +169 -0
- package/docs/ai-chat/patterns/oom-resilience.mdx +120 -0
- package/docs/ai-chat/patterns/persistence-and-replay.mdx +211 -0
- package/docs/ai-chat/patterns/recovery-boot.mdx +230 -0
- package/docs/ai-chat/patterns/skills.mdx +221 -0
- package/docs/ai-chat/patterns/sub-agents.mdx +383 -0
- package/docs/ai-chat/patterns/tool-result-auditing.mdx +148 -0
- package/docs/ai-chat/patterns/trusted-edge-signals.mdx +337 -0
- package/docs/ai-chat/patterns/version-upgrades.mdx +172 -0
- package/docs/ai-chat/pending-messages.mdx +343 -0
- package/docs/ai-chat/prompt-caching.mdx +206 -0
- package/docs/ai-chat/quick-start.mdx +161 -0
- package/docs/ai-chat/reference.mdx +909 -0
- package/docs/ai-chat/server-chat.mdx +263 -0
- package/docs/ai-chat/sessions.mdx +333 -0
- package/docs/ai-chat/testing.mdx +682 -0
- package/docs/ai-chat/tools.mdx +191 -0
- package/docs/ai-chat/types.mdx +242 -0
- package/docs/ai-chat/upgrade-guide.mdx +515 -0
- package/docs/apikeys.mdx +54 -0
- package/docs/building-with-ai.mdx +261 -0
- package/docs/bulk-actions.mdx +49 -0
- package/docs/changelog.mdx +6 -0
- package/docs/cli-deploy-commands.mdx +9 -0
- package/docs/cli-dev-commands.mdx +9 -0
- package/docs/cli-dev.mdx +8 -0
- package/docs/cli-init-commands.mdx +58 -0
- package/docs/cli-introduction.mdx +25 -0
- package/docs/cli-list-profiles-commands.mdx +42 -0
- package/docs/cli-login-commands.mdx +33 -0
- package/docs/cli-logout-commands.mdx +33 -0
- package/docs/cli-preview-archive.mdx +59 -0
- package/docs/cli-promote-commands.mdx +9 -0
- package/docs/cli-switch.mdx +43 -0
- package/docs/cli-update-commands.mdx +42 -0
- package/docs/cli-whoami-commands.mdx +33 -0
- package/docs/community.mdx +6 -0
- package/docs/config/config-file.mdx +602 -0
- package/docs/config/extensions/additionalFiles.mdx +38 -0
- package/docs/config/extensions/additionalPackages.mdx +40 -0
- package/docs/config/extensions/aptGet.mdx +34 -0
- package/docs/config/extensions/audioWaveform.mdx +20 -0
- package/docs/config/extensions/custom.mdx +380 -0
- package/docs/config/extensions/emitDecoratorMetadata.mdx +29 -0
- package/docs/config/extensions/esbuildPlugin.mdx +31 -0
- package/docs/config/extensions/ffmpeg.mdx +45 -0
- package/docs/config/extensions/lightpanda.mdx +56 -0
- package/docs/config/extensions/overview.mdx +67 -0
- package/docs/config/extensions/playwright.mdx +195 -0
- package/docs/config/extensions/prismaExtension.mdx +1014 -0
- package/docs/config/extensions/puppeteer.mdx +30 -0
- package/docs/config/extensions/pythonExtension.mdx +182 -0
- package/docs/config/extensions/syncEnvVars.mdx +291 -0
- package/docs/context.mdx +235 -0
- package/docs/database-connections.mdx +213 -0
- package/docs/deploy-environment-variables.mdx +435 -0
- package/docs/deployment/atomic-deployment.mdx +172 -0
- package/docs/deployment/overview.mdx +257 -0
- package/docs/deployment/preview-branches.mdx +224 -0
- package/docs/errors-retrying.mdx +379 -0
- package/docs/github-actions.mdx +222 -0
- package/docs/github-integration.mdx +136 -0
- package/docs/github-repo.mdx +8 -0
- package/docs/help-email.mdx +6 -0
- package/docs/help-slack.mdx +11 -0
- package/docs/hidden-tasks.mdx +56 -0
- package/docs/how-it-works.mdx +454 -0
- package/docs/how-to-reduce-your-spend.mdx +217 -0
- package/docs/idempotency.mdx +504 -0
- package/docs/introduction.mdx +223 -0
- package/docs/limits.mdx +241 -0
- package/docs/logging.mdx +195 -0
- package/docs/machines.mdx +952 -0
- package/docs/manual-setup.mdx +632 -0
- package/docs/mcp-agent-rules.mdx +41 -0
- package/docs/mcp-introduction.mdx +385 -0
- package/docs/mcp-tools.mdx +273 -0
- package/docs/migrating-from-v3.mdx +334 -0
- package/docs/observability/dashboards.mdx +102 -0
- package/docs/observability/query.mdx +585 -0
- package/docs/open-source-contributing.mdx +16 -0
- package/docs/open-source-self-hosting.mdx +541 -0
- package/docs/private-networking/aws-console-setup.mdx +304 -0
- package/docs/private-networking/overview.mdx +144 -0
- package/docs/private-networking/troubleshooting.mdx +78 -0
- package/docs/queue-concurrency.mdx +354 -0
- package/docs/quick-start.mdx +97 -0
- package/docs/realtime/auth.mdx +208 -0
- package/docs/realtime/backend/overview.mdx +45 -0
- package/docs/realtime/backend/streams.mdx +418 -0
- package/docs/realtime/backend/subscribe.mdx +225 -0
- package/docs/realtime/how-it-works.mdx +94 -0
- package/docs/realtime/overview.mdx +63 -0
- package/docs/realtime/react-hooks/overview.mdx +73 -0
- package/docs/realtime/react-hooks/streams.mdx +449 -0
- package/docs/realtime/react-hooks/subscribe.mdx +674 -0
- package/docs/realtime/react-hooks/swr.mdx +87 -0
- package/docs/realtime/react-hooks/triggering.mdx +194 -0
- package/docs/realtime/react-hooks/use-wait-token.mdx +34 -0
- package/docs/realtime/run-object.mdx +174 -0
- package/docs/replaying.mdx +72 -0
- package/docs/request-feature.mdx +6 -0
- package/docs/roadmap.mdx +6 -0
- package/docs/run-tests.mdx +20 -0
- package/docs/run-usage.mdx +113 -0
- package/docs/runs/heartbeats.mdx +38 -0
- package/docs/runs/max-duration.mdx +139 -0
- package/docs/runs/metadata.mdx +734 -0
- package/docs/runs/priority.mdx +31 -0
- package/docs/runs.mdx +396 -0
- package/docs/self-hosting/docker.mdx +458 -0
- package/docs/self-hosting/env/supervisor.mdx +74 -0
- package/docs/self-hosting/env/webapp.mdx +276 -0
- package/docs/self-hosting/kubernetes.mdx +601 -0
- package/docs/self-hosting/overview.mdx +108 -0
- package/docs/skills.mdx +85 -0
- package/docs/tags.mdx +120 -0
- package/docs/tasks/overview.mdx +697 -0
- package/docs/tasks/scheduled.mdx +382 -0
- package/docs/tasks/schemaTask.mdx +413 -0
- package/docs/tasks/streams.mdx +884 -0
- package/docs/triggering.mdx +1320 -0
- package/docs/troubleshooting-alerts.mdx +385 -0
- package/docs/troubleshooting-debugging-in-vscode.mdx +8 -0
- package/docs/troubleshooting-github-issues.mdx +6 -0
- package/docs/troubleshooting-uptime-status.mdx +6 -0
- package/docs/troubleshooting.mdx +398 -0
- package/docs/upgrading-packages.mdx +80 -0
- package/docs/vercel-integration.mdx +207 -0
- package/docs/versioning.mdx +56 -0
- package/docs/video-walkthrough.mdx +23 -0
- package/docs/wait-for-token.mdx +540 -0
- package/docs/wait-for.mdx +42 -0
- package/docs/wait-until.mdx +53 -0
- package/docs/wait.mdx +18 -0
- package/docs/writing-tasks-introduction.mdx +33 -0
- package/package.json +8 -5
- package/skills/trigger-authoring-chat-agent/SKILL.md +296 -0
- package/skills/trigger-authoring-tasks/SKILL.md +254 -0
- package/skills/trigger-chat-agent-advanced/SKILL.md +368 -0
- package/skills/trigger-cost-savings/SKILL.md +116 -0
- package/skills/trigger-realtime-and-frontend/SKILL.md +276 -0
|
@@ -0,0 +1,515 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Upgrade Guide: prerelease → Sessions-as-run-manager"
|
|
3
|
+
sidebarTitle: "Sessions Upgrade Guide"
|
|
4
|
+
description: "Migrating chat.agent code from the prerelease API to the Sessions-as-run-manager release."
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
import RcBanner from "/snippets/ai-chat-rc-banner.mdx";
|
|
8
|
+
|
|
9
|
+
<RcBanner />
|
|
10
|
+
|
|
11
|
+
This guide is for customers who tried `chat.agent` during the prerelease period.
|
|
12
|
+
The public surface of `chat.agent({...})`, `useTriggerChatTransport`,
|
|
13
|
+
`AgentChat`, `chat.defer`, and `chat.history` is largely
|
|
14
|
+
unchanged — but the transport's auth callbacks and the server-side helpers
|
|
15
|
+
that feed them were reshaped, so most prerelease apps need a small wiring
|
|
16
|
+
update.
|
|
17
|
+
|
|
18
|
+
## TL;DR
|
|
19
|
+
|
|
20
|
+
<CodeGroup>
|
|
21
|
+
|
|
22
|
+
```ts before.ts
|
|
23
|
+
// Single accessToken callback, dispatches on purpose
|
|
24
|
+
accessToken: async ({ chatId, purpose }) => {
|
|
25
|
+
if (purpose === "trigger") {
|
|
26
|
+
return chat.createAccessToken<typeof myChat>("my-chat");
|
|
27
|
+
}
|
|
28
|
+
// purpose === "preload" — same call, same trigger token
|
|
29
|
+
return chat.createAccessToken<typeof myChat>("my-chat");
|
|
30
|
+
};
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
```ts after.ts
|
|
34
|
+
// Two callbacks: pure refresh + server action that creates the session
|
|
35
|
+
accessToken: ({ chatId }) => mintChatAccessToken(chatId),
|
|
36
|
+
startSession: ({ chatId, clientData }) =>
|
|
37
|
+
startChatSession({ chatId, clientData }),
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
</CodeGroup>
|
|
41
|
+
|
|
42
|
+
What changed:
|
|
43
|
+
|
|
44
|
+
- `accessToken` is now a **pure session-PAT mint** — called only on 401/403
|
|
45
|
+
to refresh. It must return a token scoped to the session, not a
|
|
46
|
+
`trigger:tasks` JWT.
|
|
47
|
+
- `startSession` is a **new callback** that wraps a server action calling
|
|
48
|
+
`chat.createStartSessionAction(taskId)`. The transport invokes it on
|
|
49
|
+
`transport.preload(chatId)` and lazily on the first `sendMessage` for
|
|
50
|
+
any chatId without a cached PAT.
|
|
51
|
+
- `ChatSession` persistable state drops `runId` — store only
|
|
52
|
+
`{publicAccessToken, lastEventId?}`.
|
|
53
|
+
- Per-call options on `transport.preload(chatId, ...)` are gone. Trigger
|
|
54
|
+
config (machine, idleTimeoutInSeconds, tags, queue, maxAttempts) lives
|
|
55
|
+
server-side in `chat.createStartSessionAction(taskId, options)`.
|
|
56
|
+
|
|
57
|
+
<Note>
|
|
58
|
+
The architectural shift is that `chat.agent` no longer rolls its own
|
|
59
|
+
per-run streams. It runs on top of a durable **Session** row that owns
|
|
60
|
+
its current run, persists across run lifecycles, and orchestrates
|
|
61
|
+
upgrades server-side. The customer-facing surface is similar; the wire
|
|
62
|
+
path beneath it changed completely.
|
|
63
|
+
</Note>
|
|
64
|
+
|
|
65
|
+
## Step 1: Replace your access-token server action with two server actions
|
|
66
|
+
|
|
67
|
+
The old pattern was a single helper that minted a trigger token:
|
|
68
|
+
|
|
69
|
+
```ts app/actions.ts (before)
|
|
70
|
+
"use server";
|
|
71
|
+
|
|
72
|
+
import { chat } from "@trigger.dev/sdk/ai";
|
|
73
|
+
import type { myChat } from "@/trigger/chat";
|
|
74
|
+
|
|
75
|
+
export const getChatToken = () =>
|
|
76
|
+
chat.createAccessToken<typeof myChat>("my-chat");
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Replace with two helpers — one for session creation, one for PAT refresh:
|
|
80
|
+
|
|
81
|
+
```ts app/actions.ts (after)
|
|
82
|
+
"use server";
|
|
83
|
+
|
|
84
|
+
import { auth } from "@trigger.dev/sdk";
|
|
85
|
+
import { chat } from "@trigger.dev/sdk/ai";
|
|
86
|
+
|
|
87
|
+
// Server-side wrapper for session creation. Idempotent on (env, chatId).
|
|
88
|
+
// The customer's server is the only entry point that creates Session rows;
|
|
89
|
+
// the browser never holds a `trigger:tasks` JWT.
|
|
90
|
+
export const startChatSession = chat.createStartSessionAction("my-chat");
|
|
91
|
+
|
|
92
|
+
// Pure session-PAT mint for the transport's 401/403 retry path.
|
|
93
|
+
export async function mintChatAccessToken(chatId: string) {
|
|
94
|
+
return auth.createPublicToken({
|
|
95
|
+
scopes: {
|
|
96
|
+
read: { sessions: chatId },
|
|
97
|
+
write: { sessions: chatId },
|
|
98
|
+
},
|
|
99
|
+
expirationTime: "1h",
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
`chat.createStartSessionAction(taskId)` returns a server action that:
|
|
105
|
+
|
|
106
|
+
1. Creates the Session row for `chatId` (idempotent on the
|
|
107
|
+
`(env, externalId)` unique pair).
|
|
108
|
+
2. Triggers the agent task's first run with
|
|
109
|
+
`basePayload: {messages: [], trigger: "preload"}` defaults plus any
|
|
110
|
+
overrides you pass.
|
|
111
|
+
3. Returns `{sessionId, runId, publicAccessToken}` to the browser.
|
|
112
|
+
|
|
113
|
+
## Step 2: Update the transport wiring
|
|
114
|
+
|
|
115
|
+
The transport now takes two callbacks instead of one:
|
|
116
|
+
|
|
117
|
+
```tsx app/components/chat.tsx (after)
|
|
118
|
+
"use client";
|
|
119
|
+
|
|
120
|
+
import { useChat } from "@ai-sdk/react";
|
|
121
|
+
import { useTriggerChatTransport } from "@trigger.dev/sdk/chat/react";
|
|
122
|
+
import type { myChat } from "@/trigger/chat";
|
|
123
|
+
import { mintChatAccessToken, startChatSession } from "@/app/actions";
|
|
124
|
+
|
|
125
|
+
export function Chat() {
|
|
126
|
+
const transport = useTriggerChatTransport<typeof myChat>({
|
|
127
|
+
task: "my-chat",
|
|
128
|
+
accessToken: ({ chatId }) => mintChatAccessToken(chatId),
|
|
129
|
+
startSession: ({ chatId, clientData }) =>
|
|
130
|
+
startChatSession({ chatId, clientData }),
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
const { messages, sendMessage, status } = useChat({ transport });
|
|
134
|
+
// ...
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
The transport calls them in two distinct flows:
|
|
139
|
+
|
|
140
|
+
| Trigger | Callback fired |
|
|
141
|
+
|---|---|
|
|
142
|
+
| `transport.preload(chatId)` | `startSession` |
|
|
143
|
+
| First `sendMessage` for a chatId with no cached PAT | `startSession` (auto) |
|
|
144
|
+
| Any 401/403 from `.in/append`, `.out` SSE, or `end-and-continue` | `accessToken` |
|
|
145
|
+
| Page hydrates with `sessions: { [chatId]: ... }` | Neither (uses hydrated PAT) |
|
|
146
|
+
|
|
147
|
+
`startSession` is deduped via an in-flight promise — concurrent
|
|
148
|
+
`preload` + `sendMessage` calls converge to one server action invocation.
|
|
149
|
+
|
|
150
|
+
## Step 3: Drop transport-level trigger config
|
|
151
|
+
|
|
152
|
+
The prerelease transport accepted `triggerConfig`, `triggerOptions`, and
|
|
153
|
+
per-call options on `preload`. All of that moved server-side:
|
|
154
|
+
|
|
155
|
+
```ts before
|
|
156
|
+
const transport = useTriggerChatTransport({
|
|
157
|
+
task: "my-chat",
|
|
158
|
+
accessToken: getChatToken,
|
|
159
|
+
triggerConfig: { basePayload: { /* ... */ } },
|
|
160
|
+
triggerOptions: { tags: [...], machine: "small-1x", maxAttempts: 3 },
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
transport.preload(chatId, { idleTimeoutInSeconds: 60, metadata: { ... } });
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
```ts after
|
|
167
|
+
// Trigger config now lives in chat.createStartSessionAction
|
|
168
|
+
export const startChatSession = chat.createStartSessionAction("my-chat", {
|
|
169
|
+
triggerConfig: {
|
|
170
|
+
machine: "small-1x",
|
|
171
|
+
maxAttempts: 3,
|
|
172
|
+
tags: ["my-tag"],
|
|
173
|
+
idleTimeoutInSeconds: 60,
|
|
174
|
+
},
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
// Browser side
|
|
178
|
+
const transport = useTriggerChatTransport<typeof myChat>({
|
|
179
|
+
task: "my-chat",
|
|
180
|
+
accessToken: ({ chatId }) => mintChatAccessToken(chatId),
|
|
181
|
+
startSession: ({ chatId, clientData }) =>
|
|
182
|
+
startChatSession({ chatId, clientData }),
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
transport.preload(chatId); // no second arg
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
For metadata that varies per chat, use `clientData` on the transport (see
|
|
189
|
+
the next step) — it's typed and threaded through `startSession` automatically.
|
|
190
|
+
|
|
191
|
+
## Step 4: Use `clientData` for typed payload metadata
|
|
192
|
+
|
|
193
|
+
If your agent uses `withClientData({schema})`, the transport's `clientData`
|
|
194
|
+
option is now the canonical place to set it. The same value:
|
|
195
|
+
|
|
196
|
+
- Is passed to your `startSession` callback as `params.clientData`, where
|
|
197
|
+
you forward it into `chat.createStartSessionAction`'s
|
|
198
|
+
`triggerConfig.basePayload.metadata`. The agent's first run sees it in
|
|
199
|
+
`payload.metadata` (visible to `onPreload` / `onChatStart`).
|
|
200
|
+
- Merges into per-turn `metadata` on every `.in/append` chunk
|
|
201
|
+
(visible to `onTurnStart` / inside `run` via `turn.clientData`).
|
|
202
|
+
|
|
203
|
+
```tsx
|
|
204
|
+
const transport = useTriggerChatTransport<typeof myChat>({
|
|
205
|
+
task: "my-chat",
|
|
206
|
+
accessToken: ({ chatId }) => mintChatAccessToken(chatId),
|
|
207
|
+
startSession: ({ chatId, clientData }) =>
|
|
208
|
+
startChatSession({ chatId, clientData }),
|
|
209
|
+
clientData: {
|
|
210
|
+
userId: currentUser.id,
|
|
211
|
+
plan: currentUser.plan,
|
|
212
|
+
},
|
|
213
|
+
});
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
The `clientData` value is live-updated when the option changes (the hook
|
|
217
|
+
calls `setClientData` under the hood), so dynamic values work without
|
|
218
|
+
reconstructing the transport.
|
|
219
|
+
|
|
220
|
+
<Tip>
|
|
221
|
+
Server-side authorization can still override or augment the
|
|
222
|
+
browser-claimed `clientData` inside `startSession` — never trust the
|
|
223
|
+
browser's identity claim. A typical pattern: the server action looks up
|
|
224
|
+
the user from the request session, then merges the trusted server fields
|
|
225
|
+
on top of `params.clientData`.
|
|
226
|
+
</Tip>
|
|
227
|
+
|
|
228
|
+
## Step 5: Update your `ChatSession` persistence
|
|
229
|
+
|
|
230
|
+
If you persist session state across page loads, drop the `runId` field:
|
|
231
|
+
|
|
232
|
+
```ts before
|
|
233
|
+
type ChatSession = {
|
|
234
|
+
runId: string;
|
|
235
|
+
publicAccessToken: string;
|
|
236
|
+
lastEventId?: string;
|
|
237
|
+
};
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
```ts after
|
|
241
|
+
type ChatSession = {
|
|
242
|
+
publicAccessToken: string;
|
|
243
|
+
lastEventId?: string;
|
|
244
|
+
};
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
If your DB has a `runId` column, you can drop it (the transport doesn't
|
|
248
|
+
read it) or keep it for telemetry. The current run ID lives on the
|
|
249
|
+
Session row server-side now.
|
|
250
|
+
|
|
251
|
+
Hydration on page reload is unchanged:
|
|
252
|
+
|
|
253
|
+
```tsx
|
|
254
|
+
const transport = useTriggerChatTransport<typeof myChat>({
|
|
255
|
+
// ...
|
|
256
|
+
sessions: persistedSession
|
|
257
|
+
? { [chatId]: persistedSession }
|
|
258
|
+
: {},
|
|
259
|
+
});
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
## `chat.requestUpgrade()`: same call, faster handoff
|
|
263
|
+
|
|
264
|
+
Calling `chat.requestUpgrade()` inside `onTurnStart` /
|
|
265
|
+
`onValidateMessages` still ends the current run so the next message starts
|
|
266
|
+
on the latest version. What changed is the mechanism:
|
|
267
|
+
|
|
268
|
+
- **Before:** the agent emitted a `trigger:upgrade-required` chunk on
|
|
269
|
+
`.out`; the transport consumed it browser-side and triggered a new run.
|
|
270
|
+
- **After:** the agent calls `endAndContinueSession` server-to-server;
|
|
271
|
+
the webapp triggers a new run and atomically swaps `Session.currentRunId`
|
|
272
|
+
via optimistic locking. The browser's existing SSE subscription keeps
|
|
273
|
+
receiving chunks across the swap — no transport-side bookkeeping.
|
|
274
|
+
|
|
275
|
+
The new run is recorded in a `SessionRun` audit row with
|
|
276
|
+
`reason: "upgrade"` for dashboard provenance.
|
|
277
|
+
|
|
278
|
+
## Hitting raw URLs
|
|
279
|
+
|
|
280
|
+
If your code talks to the realtime API directly instead of going through
|
|
281
|
+
the SDK, the URL shapes changed:
|
|
282
|
+
|
|
283
|
+
| Before | After |
|
|
284
|
+
|---|---|
|
|
285
|
+
| `GET /realtime/v1/streams/{runId}/chat` | `GET /realtime/v1/sessions/{chatId}/out` |
|
|
286
|
+
| `POST /realtime/v1/streams/{runId}/{target}/chat-messages/append` | `POST /realtime/v1/sessions/{chatId}/in/append` (body: `{kind: "message", payload}`) |
|
|
287
|
+
| `POST /realtime/v1/streams/{runId}/{target}/chat-stop/append` | `POST /realtime/v1/sessions/{chatId}/in/append` (body: `{kind: "stop"}`) |
|
|
288
|
+
|
|
289
|
+
The session-scoped PAT
|
|
290
|
+
(`read:sessions:{chatId} + write:sessions:{chatId}`) authorizes both the
|
|
291
|
+
externalId form (`/sessions/my-chat-id/...`) and the friendlyId form
|
|
292
|
+
(`/sessions/session_abc.../...`). The transport always uses the
|
|
293
|
+
externalId form; the friendlyId form is available for dashboard tooling
|
|
294
|
+
and direct API consumers.
|
|
295
|
+
|
|
296
|
+
## What didn't change
|
|
297
|
+
|
|
298
|
+
- `chat.agent({...})` definition — `id`, `idleTimeoutInSeconds`,
|
|
299
|
+
`clientDataSchema`, `actionSchema`, `hydrateMessages`, `onPreload`,
|
|
300
|
+
`onChatStart`, `onValidateMessages`, `onTurnStart`, `onTurnComplete`,
|
|
301
|
+
`onChatSuspend`, `run`. All callbacks have the same signature and
|
|
302
|
+
fire at the same lifecycle points.
|
|
303
|
+
- `onAction` is still defined the same way, but its semantics changed
|
|
304
|
+
in the [May 6 prerelease](/ai-chat/changelog) — actions are no longer
|
|
305
|
+
turns, and `onAction` returning a `StreamTextResult` produces a model
|
|
306
|
+
response.
|
|
307
|
+
- `chat.customAgent({...})` and the `chat.createSession(payload, ...)`
|
|
308
|
+
helper for building a session loop manually inside a custom agent.
|
|
309
|
+
- `chat.defer` (deferred work) and `chat.history` (imperative history
|
|
310
|
+
mutations from inside `onAction`).
|
|
311
|
+
- `AgentChat` (server-side chat client) — `agent`, `id`, `clientData`,
|
|
312
|
+
`session`, `onTriggered`, `onTurnComplete`, `sendMessage`, `text()`.
|
|
313
|
+
- `useTriggerChatTransport` React semantics (created once, kept in a
|
|
314
|
+
ref, callbacks updated under the hood).
|
|
315
|
+
- Multi-tab coordination (`multiTab: true`),
|
|
316
|
+
[pending messages / steering](/ai-chat/pending-messages),
|
|
317
|
+
[background injection](/ai-chat/background-injection),
|
|
318
|
+
[compaction](/ai-chat/compaction).
|
|
319
|
+
- Per-turn `metadata` flowing through
|
|
320
|
+
`sendMessage({ text }, { metadata })` to `turn.metadata` server-side.
|
|
321
|
+
|
|
322
|
+
## Verifying the migration
|
|
323
|
+
|
|
324
|
+
After updating, the smoke check is the same as before: send a message,
|
|
325
|
+
confirm the assistant streams a response, reload mid-stream, confirm
|
|
326
|
+
resume.
|
|
327
|
+
|
|
328
|
+
A few new things worth verifying once you've cut over:
|
|
329
|
+
|
|
330
|
+
- **Eager preload.** Click the button (or call `transport.preload(id)`
|
|
331
|
+
programmatically) — your `startSession` callback should fire and a
|
|
332
|
+
Session row + first run should be created before you send a message.
|
|
333
|
+
- **Idle-timeout continuation.** Wait past the agent's
|
|
334
|
+
`idleTimeoutInSeconds` so the run exits, then send another message —
|
|
335
|
+
the transport's `.in/append` should boot a new run on the same
|
|
336
|
+
Session, with a `SessionRun` row of `reason: "continuation"`.
|
|
337
|
+
- **PAT refresh.** Force a stale PAT in your DB (corrupt the signature)
|
|
338
|
+
and reload — the first request should 401, your `accessToken`
|
|
339
|
+
callback should fire, and the retry should succeed.
|
|
340
|
+
|
|
341
|
+
If any of those misfire, check that:
|
|
342
|
+
|
|
343
|
+
- Your `accessToken` callback returns a token minted via
|
|
344
|
+
`auth.createPublicToken({ scopes: { read: { sessions: chatId }, write: { sessions: chatId } } })`, **not**
|
|
345
|
+
`chat.createAccessToken` or `auth.createTriggerPublicToken`. The
|
|
346
|
+
transport rejects trigger tokens now.
|
|
347
|
+
- Your `startSession` callback returns
|
|
348
|
+
`{publicAccessToken: string}` — the result of
|
|
349
|
+
`chat.createStartSessionAction(taskId)({chatId, ...})` already has
|
|
350
|
+
this shape.
|
|
351
|
+
- You haven't left a stale `getStartToken` option on the transport;
|
|
352
|
+
it's not part of `TriggerChatTransportOptions` anymore.
|
|
353
|
+
|
|
354
|
+
## v4.5 wire format change
|
|
355
|
+
|
|
356
|
+
A second migration lands on top of the Sessions release. v4.5 removes the full-history wire payload — clients now ship at most one new `UIMessage` per `.in/append`, and the agent rebuilds prior history from a durable JSON snapshot in object storage plus a replay of the `session.out` tail.
|
|
357
|
+
|
|
358
|
+
If you use the built-in `TriggerChatTransport` / `AgentChat` and don't reach into the wire shape directly, **most apps need no changes** — the change is below the customer-facing surface. Customers who built custom transports, hit `/realtime/v1/sessions/{id}/in/append` directly, or rely on specific behaviors of `hydrateMessages` / `onChatStart` should read this section.
|
|
359
|
+
|
|
360
|
+
### Why the change
|
|
361
|
+
|
|
362
|
+
Long chats with heavy tool results were hitting the realtime API's 512 KiB body cap on `/in/append` once the accumulated `UIMessage[]` history (which the wire shipped in full on every send) crossed the limit. The 413 surfaced as a CORS error in browsers and stalled chats around turn 10–30 with tool use.
|
|
363
|
+
|
|
364
|
+
The wire is now **delta-only**: each `.in/append` carries at most one new `UIMessage`. The agent rebuilds prior history at run boot. The 512 KiB ceiling stops being pressure — typical payloads are a few KB regardless of chat length.
|
|
365
|
+
|
|
366
|
+
### Object-store configuration
|
|
367
|
+
|
|
368
|
+
Snapshot read/write uses Trigger.dev's existing object-store infrastructure — the same presigned-URL routes used for large payloads. Set the standard `OBJECT_STORE_*` env vars on your webapp deployment if you haven't already; MinIO and S3-compatible stores work via `OBJECT_STORE_DEFAULT_PROTOCOL`.
|
|
369
|
+
|
|
370
|
+
| Env var | Purpose |
|
|
371
|
+
|---|---|
|
|
372
|
+
| `OBJECT_STORE_BASE_URL` | Endpoint URL (S3, MinIO, R2, etc.) |
|
|
373
|
+
| `OBJECT_STORE_ACCESS_KEY_ID` | Access key |
|
|
374
|
+
| `OBJECT_STORE_SECRET_ACCESS_KEY` | Secret key |
|
|
375
|
+
| `OBJECT_STORE_DEFAULT_PROTOCOL` | `s3` (default), `minio`, etc. |
|
|
376
|
+
|
|
377
|
+
Snapshots are written under `packets/{projectRef}/{envSlug}/sessions/{sessionId}/snapshot.json`. Each snapshot is small (typically tens of KB) and overwritten every turn — no append-only growth.
|
|
378
|
+
|
|
379
|
+
<Warning>
|
|
380
|
+
**No object store + no `hydrateMessages` = conversations don't survive run boundaries.** With neither piece of state, a continuation boots empty and the agent can't reconstruct prior turns. Either configure an object store or register `hydrateMessages`. The runtime logs a warning at agent registration time when both are missing.
|
|
381
|
+
</Warning>
|
|
382
|
+
|
|
383
|
+
### Custom transports
|
|
384
|
+
|
|
385
|
+
If you've built your own transport (Slack bot, CLI, native app) against the [Client Protocol](/ai-chat/client-protocol), the `ChatTaskWirePayload` shape changed:
|
|
386
|
+
|
|
387
|
+
```ts before
|
|
388
|
+
type ChatTaskWirePayload = {
|
|
389
|
+
messages: UIMessage[]; // full history
|
|
390
|
+
chatId: string;
|
|
391
|
+
trigger: "submit-message" | "regenerate-message" | "preload" | "close" | "action";
|
|
392
|
+
// ...
|
|
393
|
+
};
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
```ts after
|
|
397
|
+
type ChatTaskWirePayload = {
|
|
398
|
+
message?: UIMessage; // singular, optional
|
|
399
|
+
headStartMessages?: UIMessage[]; // chat.headStart only, "handover-prepare"
|
|
400
|
+
chatId: string;
|
|
401
|
+
trigger:
|
|
402
|
+
| "submit-message"
|
|
403
|
+
| "regenerate-message"
|
|
404
|
+
| "preload"
|
|
405
|
+
| "close"
|
|
406
|
+
| "action"
|
|
407
|
+
| "handover-prepare";
|
|
408
|
+
// ...
|
|
409
|
+
};
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
What to send per trigger:
|
|
413
|
+
|
|
414
|
+
| Trigger | What to put in the payload |
|
|
415
|
+
|---|---|
|
|
416
|
+
| `submit-message` | The new user message (or a tool-approval-responded assistant message) in `message` |
|
|
417
|
+
| `regenerate-message` | No `message` — the agent trims its own tail |
|
|
418
|
+
| `preload` / `close` / `action` | No `message` |
|
|
419
|
+
| `handover-prepare` (head-start only) | Full prior history in `headStartMessages` (route handler — not on `/in/append`) |
|
|
420
|
+
|
|
421
|
+
The full wire breakdown is in the rewritten [Client Protocol](/ai-chat/client-protocol).
|
|
422
|
+
|
|
423
|
+
### `hydrateMessages` consumers
|
|
424
|
+
|
|
425
|
+
The hook signature is unchanged. Two behavior tightenings worth knowing:
|
|
426
|
+
|
|
427
|
+
1. **`incomingMessages` is now consistently 0-or-1-length.** Previously some triggers (`regenerate-message`, continuation) shipped full history; now all triggers ship at most one. If you assumed `incomingMessages` could contain multiple messages and acted on them as a batch, the loop now runs zero or one times. Patterns like the one below work the same — they just iterate fewer messages:
|
|
428
|
+
|
|
429
|
+
```ts
|
|
430
|
+
hydrateMessages: async ({ incomingMessages }) => {
|
|
431
|
+
for (const msg of incomingMessages) { // 0-or-1 iterations
|
|
432
|
+
for (const r of chat.history.extractNewToolResults(msg)) {
|
|
433
|
+
await auditLog.record({ id: r.toolCallId, output: r.output });
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
return await db.getMessages(chatId);
|
|
437
|
+
}
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
2. **Registering `hydrateMessages` short-circuits snapshot+replay.** The runtime trusts your hook to be the source of truth, so it doesn't read or write the JSON snapshot or replay `session.out`. Zero object-store traffic. Trade-off: you own persistence end-to-end.
|
|
441
|
+
|
|
442
|
+
### `onChatStart` is now once-per-chat
|
|
443
|
+
|
|
444
|
+
`onChatStart` no longer fires on continuation runs (post-`endRun`, post-waitpoint-timeout, post-`chat.requestUpgrade`, post-cancel, post-crash) or on OOM-retry attempts. It fires **exactly once per chat**, on the very first user message of the chat's lifetime. The `continuation` and `previousRunId` fields on `ChatStartEvent` are now `@deprecated` (always `false` / `undefined` when the hook fires).
|
|
445
|
+
|
|
446
|
+
This makes once-per-chat setup code (create the Chat DB row, mint chat-scoped resources) safe to write without continuation gates. Drop any `if (continuation) return;` checks from `onChatStart`:
|
|
447
|
+
|
|
448
|
+
```ts before
|
|
449
|
+
onChatStart: async ({ continuation, chatId, clientData }) => {
|
|
450
|
+
if (continuation) return; // ❌ no longer needed — fires only on first message ever
|
|
451
|
+
await db.chat.create({ /* ... */ });
|
|
452
|
+
}
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
```ts after
|
|
456
|
+
onChatStart: async ({ chatId, clientData }) => {
|
|
457
|
+
await db.chat.create({ /* ... */ }); // ✅ guaranteed first-message-of-chat
|
|
458
|
+
}
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
If you need per-turn setup that **does** run on continuations, move it to [`onTurnStart`](/ai-chat/lifecycle-hooks#onturnstart) — that hook still fires on every turn, including the first turn of a continuation run.
|
|
462
|
+
|
|
463
|
+
### Move `chat.local` init from `onChatStart` to `onBoot`
|
|
464
|
+
|
|
465
|
+
Because `onChatStart` no longer fires on continuation runs, **`chat.local`** state initialized there will be missing when a continuation run starts — `run()` then crashes with `"chat.local can only be modified after initialization"`. The fix is to move per-process initialization to the new [`onBoot`](/ai-chat/lifecycle-hooks#onboot) hook, which fires once per worker boot (initial, preloaded, AND continuation):
|
|
466
|
+
|
|
467
|
+
```ts before
|
|
468
|
+
const userContext = chat.local<{ name: string; plan: string }>({ id: "userContext" });
|
|
469
|
+
|
|
470
|
+
onChatStart: async ({ clientData }) => {
|
|
471
|
+
const user = await db.user.findUnique({ where: { id: clientData.userId } });
|
|
472
|
+
userContext.init({ name: user.name, plan: user.plan }); // ❌ never runs on continuation
|
|
473
|
+
}
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
```ts after
|
|
477
|
+
const userContext = chat.local<{ name: string; plan: string }>({ id: "userContext" });
|
|
478
|
+
|
|
479
|
+
onBoot: async ({ clientData }) => {
|
|
480
|
+
const user = await db.user.findUnique({ where: { id: clientData.userId } });
|
|
481
|
+
userContext.init({ name: user.name, plan: user.plan }); // ✅ runs on every fresh worker
|
|
482
|
+
}
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
Anything else that's per-process (DB connection pools, sandbox handles, in-memory caches) belongs in `onBoot` for the same reason. Branch on `continuation` inside `onBoot` if you need to re-load state from your DB on takeover.
|
|
486
|
+
|
|
487
|
+
### Client-side `setMessages` doesn't round-trip
|
|
488
|
+
|
|
489
|
+
The new wire makes one thing explicit that was implicit before: **mutating `useChat()`'s messages on the client doesn't change the agent's history.** Full-history mutations were silently overwritten by the wire's accumulator before this release; now they aren't even shipped.
|
|
490
|
+
|
|
491
|
+
For history compaction, summarization, or branch-swap, mutate the agent's accumulator inside `onTurnStart` using [`chat.setMessages()`](/ai-chat/backend) or [`chat.history.set()`](/ai-chat/backend#chat-history). The client's `useChat` will reconcile against the next `session.out` payload.
|
|
492
|
+
|
|
493
|
+
### Verifying the v4.5 migration
|
|
494
|
+
|
|
495
|
+
After updating, the smoke check is the same as for v4.4:
|
|
496
|
+
|
|
497
|
+
- Send a message, confirm the assistant streams a response.
|
|
498
|
+
- Reload mid-stream, confirm resume.
|
|
499
|
+
- Send 30+ turns with tool calls — `.in/append` body sizes stay under ~5 KB the entire time. (Pre-change baseline: payloads grew past 512 KB around turn 10-30.)
|
|
500
|
+
- Idle out a run, send another message — the new run reads the snapshot, replays the tail, and continues seamlessly.
|
|
501
|
+
|
|
502
|
+
If continuations boot empty:
|
|
503
|
+
|
|
504
|
+
- Confirm `OBJECT_STORE_*` env vars are set on the webapp.
|
|
505
|
+
- Confirm the bucket key `packets/{projectRef}/{envSlug}/sessions/{sessionId}/snapshot.json` exists after a successful turn.
|
|
506
|
+
- Or — register `hydrateMessages` and let your DB be the source of truth.
|
|
507
|
+
|
|
508
|
+
## Reference
|
|
509
|
+
|
|
510
|
+
- [TriggerChatTransport options](/ai-chat/reference#triggerchattransport-options)
|
|
511
|
+
- [`chat.createStartSessionAction`](/ai-chat/reference)
|
|
512
|
+
- [Backend setup](/ai-chat/backend)
|
|
513
|
+
- [Frontend setup](/ai-chat/frontend)
|
|
514
|
+
- [Client Protocol](/ai-chat/client-protocol) — wire format reference
|
|
515
|
+
- [Persistence and replay](/ai-chat/patterns/persistence-and-replay) — snapshot model end-to-end
|
package/docs/apikeys.mdx
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "API keys"
|
|
3
|
+
description: "How to authenticate with Trigger.dev so you can trigger tasks."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
### Authentication and your secret keys
|
|
7
|
+
|
|
8
|
+
When you [trigger a task](/triggering) from your backend code, you need to set the `TRIGGER_SECRET_KEY` environment variable.
|
|
9
|
+
|
|
10
|
+
Each environment has its own secret key. You can find the value on the API keys page in the Trigger.dev dashboard:
|
|
11
|
+
|
|
12
|
+

|
|
13
|
+
|
|
14
|
+
<Note>
|
|
15
|
+
For preview branches, you need to also set the `TRIGGER_PREVIEW_BRANCH` environment variable as
|
|
16
|
+
well. You can find the value on the API keys page when you're on the preview branch.
|
|
17
|
+
</Note>
|
|
18
|
+
|
|
19
|
+
### Automatically Configuring the SDK
|
|
20
|
+
|
|
21
|
+
To automatically configure the SDK with your secret key, you can set the `TRIGGER_SECRET_KEY` environment variable. The SDK will automatically use this value when calling API methods (like `trigger`).
|
|
22
|
+
|
|
23
|
+
```bash .env
|
|
24
|
+
TRIGGER_SECRET_KEY="tr_dev_…"
|
|
25
|
+
TRIGGER_PREVIEW_BRANCH="my-branch" # Only needed for preview branches
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
You can do the same if you are self-hosting and need to change the default URL by using `TRIGGER_API_URL`.
|
|
29
|
+
|
|
30
|
+
```bash .env
|
|
31
|
+
TRIGGER_API_URL="https://trigger.example.com"
|
|
32
|
+
TRIGGER_PREVIEW_BRANCH="my-branch" # Only needed for preview branches
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The default URL is `https://api.trigger.dev`.
|
|
36
|
+
|
|
37
|
+
### Manually Configuring the SDK
|
|
38
|
+
|
|
39
|
+
If you prefer to manually configure the SDK, you can call the `configure` method:
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import { configure } from "@trigger.dev/sdk";
|
|
43
|
+
import { myTask } from "./trigger/myTasks";
|
|
44
|
+
|
|
45
|
+
configure({
|
|
46
|
+
secretKey: "tr_dev_1234", // WARNING: Never actually hardcode your secret key like this
|
|
47
|
+
previewBranch: "my-branch", // Only needed for preview branches
|
|
48
|
+
baseURL: "https://mytrigger.example.com", // Optional
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
async function triggerTask() {
|
|
52
|
+
await myTask.trigger({ userId: "1234" }); // This will use the secret key and base URL you configured
|
|
53
|
+
}
|
|
54
|
+
```
|