@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.
Files changed (191) hide show
  1. package/dist/commonjs/v3/ai.d.ts +171 -5
  2. package/dist/commonjs/v3/ai.js +309 -22
  3. package/dist/commonjs/v3/ai.js.map +1 -1
  4. package/dist/commonjs/v3/chat-server.d.ts +8 -0
  5. package/dist/commonjs/v3/chat-server.js +32 -10
  6. package/dist/commonjs/v3/chat-server.js.map +1 -1
  7. package/dist/commonjs/v3/chat-server.test.js +51 -0
  8. package/dist/commonjs/v3/chat-server.test.js.map +1 -1
  9. package/dist/commonjs/v3/createStartSessionAction.test.js +30 -0
  10. package/dist/commonjs/v3/createStartSessionAction.test.js.map +1 -1
  11. package/dist/commonjs/v3/sessions.d.ts +3 -2
  12. package/dist/commonjs/v3/sessions.js +3 -2
  13. package/dist/commonjs/v3/sessions.js.map +1 -1
  14. package/dist/commonjs/version.js +1 -1
  15. package/dist/esm/v3/ai.d.ts +171 -5
  16. package/dist/esm/v3/ai.js +309 -22
  17. package/dist/esm/v3/ai.js.map +1 -1
  18. package/dist/esm/v3/chat-server.d.ts +8 -0
  19. package/dist/esm/v3/chat-server.js +32 -10
  20. package/dist/esm/v3/chat-server.js.map +1 -1
  21. package/dist/esm/v3/chat-server.test.js +51 -0
  22. package/dist/esm/v3/chat-server.test.js.map +1 -1
  23. package/dist/esm/v3/createStartSessionAction.test.js +30 -0
  24. package/dist/esm/v3/createStartSessionAction.test.js.map +1 -1
  25. package/dist/esm/v3/sessions.d.ts +3 -2
  26. package/dist/esm/v3/sessions.js +3 -2
  27. package/dist/esm/v3/sessions.js.map +1 -1
  28. package/dist/esm/version.js +1 -1
  29. package/docs/ai/prompts.mdx +430 -0
  30. package/docs/ai-chat/actions.mdx +115 -0
  31. package/docs/ai-chat/anatomy.mdx +71 -0
  32. package/docs/ai-chat/backend.mdx +817 -0
  33. package/docs/ai-chat/background-injection.mdx +221 -0
  34. package/docs/ai-chat/changelog.mdx +850 -0
  35. package/docs/ai-chat/chat-local.mdx +174 -0
  36. package/docs/ai-chat/client-protocol.mdx +1081 -0
  37. package/docs/ai-chat/compaction.mdx +411 -0
  38. package/docs/ai-chat/custom-agents.mdx +364 -0
  39. package/docs/ai-chat/error-handling.mdx +415 -0
  40. package/docs/ai-chat/fast-starts.mdx +672 -0
  41. package/docs/ai-chat/frontend.mdx +580 -0
  42. package/docs/ai-chat/how-it-works.mdx +230 -0
  43. package/docs/ai-chat/lifecycle-hooks.mdx +530 -0
  44. package/docs/ai-chat/mcp.mdx +101 -0
  45. package/docs/ai-chat/overview.mdx +90 -0
  46. package/docs/ai-chat/patterns/branching-conversations.mdx +284 -0
  47. package/docs/ai-chat/patterns/code-sandbox.mdx +126 -0
  48. package/docs/ai-chat/patterns/database-persistence.mdx +414 -0
  49. package/docs/ai-chat/patterns/human-in-the-loop.mdx +275 -0
  50. package/docs/ai-chat/patterns/large-payloads.mdx +169 -0
  51. package/docs/ai-chat/patterns/oom-resilience.mdx +120 -0
  52. package/docs/ai-chat/patterns/persistence-and-replay.mdx +211 -0
  53. package/docs/ai-chat/patterns/recovery-boot.mdx +230 -0
  54. package/docs/ai-chat/patterns/skills.mdx +221 -0
  55. package/docs/ai-chat/patterns/sub-agents.mdx +383 -0
  56. package/docs/ai-chat/patterns/tool-result-auditing.mdx +148 -0
  57. package/docs/ai-chat/patterns/trusted-edge-signals.mdx +337 -0
  58. package/docs/ai-chat/patterns/version-upgrades.mdx +172 -0
  59. package/docs/ai-chat/pending-messages.mdx +343 -0
  60. package/docs/ai-chat/prompt-caching.mdx +206 -0
  61. package/docs/ai-chat/quick-start.mdx +161 -0
  62. package/docs/ai-chat/reference.mdx +909 -0
  63. package/docs/ai-chat/server-chat.mdx +263 -0
  64. package/docs/ai-chat/sessions.mdx +333 -0
  65. package/docs/ai-chat/testing.mdx +682 -0
  66. package/docs/ai-chat/tools.mdx +191 -0
  67. package/docs/ai-chat/types.mdx +242 -0
  68. package/docs/ai-chat/upgrade-guide.mdx +515 -0
  69. package/docs/apikeys.mdx +54 -0
  70. package/docs/building-with-ai.mdx +261 -0
  71. package/docs/bulk-actions.mdx +49 -0
  72. package/docs/changelog.mdx +6 -0
  73. package/docs/cli-deploy-commands.mdx +9 -0
  74. package/docs/cli-dev-commands.mdx +9 -0
  75. package/docs/cli-dev.mdx +8 -0
  76. package/docs/cli-init-commands.mdx +58 -0
  77. package/docs/cli-introduction.mdx +25 -0
  78. package/docs/cli-list-profiles-commands.mdx +42 -0
  79. package/docs/cli-login-commands.mdx +33 -0
  80. package/docs/cli-logout-commands.mdx +33 -0
  81. package/docs/cli-preview-archive.mdx +59 -0
  82. package/docs/cli-promote-commands.mdx +9 -0
  83. package/docs/cli-switch.mdx +43 -0
  84. package/docs/cli-update-commands.mdx +42 -0
  85. package/docs/cli-whoami-commands.mdx +33 -0
  86. package/docs/community.mdx +6 -0
  87. package/docs/config/config-file.mdx +602 -0
  88. package/docs/config/extensions/additionalFiles.mdx +38 -0
  89. package/docs/config/extensions/additionalPackages.mdx +40 -0
  90. package/docs/config/extensions/aptGet.mdx +34 -0
  91. package/docs/config/extensions/audioWaveform.mdx +20 -0
  92. package/docs/config/extensions/custom.mdx +380 -0
  93. package/docs/config/extensions/emitDecoratorMetadata.mdx +29 -0
  94. package/docs/config/extensions/esbuildPlugin.mdx +31 -0
  95. package/docs/config/extensions/ffmpeg.mdx +45 -0
  96. package/docs/config/extensions/lightpanda.mdx +56 -0
  97. package/docs/config/extensions/overview.mdx +67 -0
  98. package/docs/config/extensions/playwright.mdx +195 -0
  99. package/docs/config/extensions/prismaExtension.mdx +1014 -0
  100. package/docs/config/extensions/puppeteer.mdx +30 -0
  101. package/docs/config/extensions/pythonExtension.mdx +182 -0
  102. package/docs/config/extensions/syncEnvVars.mdx +291 -0
  103. package/docs/context.mdx +235 -0
  104. package/docs/database-connections.mdx +213 -0
  105. package/docs/deploy-environment-variables.mdx +435 -0
  106. package/docs/deployment/atomic-deployment.mdx +172 -0
  107. package/docs/deployment/overview.mdx +257 -0
  108. package/docs/deployment/preview-branches.mdx +224 -0
  109. package/docs/errors-retrying.mdx +379 -0
  110. package/docs/github-actions.mdx +222 -0
  111. package/docs/github-integration.mdx +136 -0
  112. package/docs/github-repo.mdx +8 -0
  113. package/docs/help-email.mdx +6 -0
  114. package/docs/help-slack.mdx +11 -0
  115. package/docs/hidden-tasks.mdx +56 -0
  116. package/docs/how-it-works.mdx +454 -0
  117. package/docs/how-to-reduce-your-spend.mdx +217 -0
  118. package/docs/idempotency.mdx +504 -0
  119. package/docs/introduction.mdx +223 -0
  120. package/docs/limits.mdx +241 -0
  121. package/docs/logging.mdx +195 -0
  122. package/docs/machines.mdx +952 -0
  123. package/docs/manual-setup.mdx +632 -0
  124. package/docs/mcp-agent-rules.mdx +41 -0
  125. package/docs/mcp-introduction.mdx +385 -0
  126. package/docs/mcp-tools.mdx +273 -0
  127. package/docs/migrating-from-v3.mdx +334 -0
  128. package/docs/observability/dashboards.mdx +102 -0
  129. package/docs/observability/query.mdx +585 -0
  130. package/docs/open-source-contributing.mdx +16 -0
  131. package/docs/open-source-self-hosting.mdx +541 -0
  132. package/docs/private-networking/aws-console-setup.mdx +304 -0
  133. package/docs/private-networking/overview.mdx +144 -0
  134. package/docs/private-networking/troubleshooting.mdx +78 -0
  135. package/docs/queue-concurrency.mdx +354 -0
  136. package/docs/quick-start.mdx +97 -0
  137. package/docs/realtime/auth.mdx +208 -0
  138. package/docs/realtime/backend/overview.mdx +45 -0
  139. package/docs/realtime/backend/streams.mdx +418 -0
  140. package/docs/realtime/backend/subscribe.mdx +225 -0
  141. package/docs/realtime/how-it-works.mdx +94 -0
  142. package/docs/realtime/overview.mdx +63 -0
  143. package/docs/realtime/react-hooks/overview.mdx +73 -0
  144. package/docs/realtime/react-hooks/streams.mdx +449 -0
  145. package/docs/realtime/react-hooks/subscribe.mdx +674 -0
  146. package/docs/realtime/react-hooks/swr.mdx +87 -0
  147. package/docs/realtime/react-hooks/triggering.mdx +194 -0
  148. package/docs/realtime/react-hooks/use-wait-token.mdx +34 -0
  149. package/docs/realtime/run-object.mdx +174 -0
  150. package/docs/replaying.mdx +72 -0
  151. package/docs/request-feature.mdx +6 -0
  152. package/docs/roadmap.mdx +6 -0
  153. package/docs/run-tests.mdx +20 -0
  154. package/docs/run-usage.mdx +113 -0
  155. package/docs/runs/heartbeats.mdx +38 -0
  156. package/docs/runs/max-duration.mdx +139 -0
  157. package/docs/runs/metadata.mdx +734 -0
  158. package/docs/runs/priority.mdx +31 -0
  159. package/docs/runs.mdx +396 -0
  160. package/docs/self-hosting/docker.mdx +458 -0
  161. package/docs/self-hosting/env/supervisor.mdx +74 -0
  162. package/docs/self-hosting/env/webapp.mdx +276 -0
  163. package/docs/self-hosting/kubernetes.mdx +601 -0
  164. package/docs/self-hosting/overview.mdx +108 -0
  165. package/docs/skills.mdx +85 -0
  166. package/docs/tags.mdx +120 -0
  167. package/docs/tasks/overview.mdx +697 -0
  168. package/docs/tasks/scheduled.mdx +382 -0
  169. package/docs/tasks/schemaTask.mdx +413 -0
  170. package/docs/tasks/streams.mdx +884 -0
  171. package/docs/triggering.mdx +1320 -0
  172. package/docs/troubleshooting-alerts.mdx +385 -0
  173. package/docs/troubleshooting-debugging-in-vscode.mdx +8 -0
  174. package/docs/troubleshooting-github-issues.mdx +6 -0
  175. package/docs/troubleshooting-uptime-status.mdx +6 -0
  176. package/docs/troubleshooting.mdx +398 -0
  177. package/docs/upgrading-packages.mdx +80 -0
  178. package/docs/vercel-integration.mdx +207 -0
  179. package/docs/versioning.mdx +56 -0
  180. package/docs/video-walkthrough.mdx +23 -0
  181. package/docs/wait-for-token.mdx +540 -0
  182. package/docs/wait-for.mdx +42 -0
  183. package/docs/wait-until.mdx +53 -0
  184. package/docs/wait.mdx +18 -0
  185. package/docs/writing-tasks-introduction.mdx +33 -0
  186. package/package.json +8 -5
  187. package/skills/trigger-authoring-chat-agent/SKILL.md +296 -0
  188. package/skills/trigger-authoring-tasks/SKILL.md +254 -0
  189. package/skills/trigger-chat-agent-advanced/SKILL.md +368 -0
  190. package/skills/trigger-cost-savings/SKILL.md +116 -0
  191. package/skills/trigger-realtime-and-frontend/SKILL.md +276 -0
@@ -0,0 +1,430 @@
1
+ ---
2
+ title: "Prompts"
3
+ sidebarTitle: "Prompts"
4
+ description: "Define prompt templates as code, version them on deploy, and override from the dashboard without redeploying."
5
+ ---
6
+
7
+ import RcBanner from "/snippets/ai-chat-rc-banner.mdx";
8
+
9
+ <RcBanner />
10
+
11
+ ## Overview
12
+
13
+ AI Prompts let you define prompt templates in your codebase alongside your tasks. When you deploy, Trigger.dev automatically versions your prompts. You can then:
14
+
15
+ - View all prompt versions in the dashboard
16
+ - Create **overrides** to change the prompt text or model without redeploying
17
+ - Track every generation that used each prompt version
18
+ - See token usage, cost, and latency metrics per prompt
19
+ - Manage prompts programmatically via SDK methods
20
+
21
+ ## Defining a prompt
22
+
23
+ Use `prompts.define()` to create a prompt with typed variables:
24
+
25
+ ```ts
26
+ import { prompts } from "@trigger.dev/sdk";
27
+ import { z } from "zod";
28
+
29
+ export const supportPrompt = prompts.define({
30
+ id: "customer-support",
31
+ description: "System prompt for customer support interactions",
32
+ model: "gpt-4o",
33
+ config: { temperature: 0.7 },
34
+ variables: z.object({
35
+ customerName: z.string(),
36
+ plan: z.string(),
37
+ issue: z.string(),
38
+ }),
39
+ content: `You are a support agent for Acme SaaS.
40
+
41
+ ## Customer context
42
+
43
+ - **Name:** {{customerName}}
44
+ - **Plan:** {{plan}}
45
+ - **Issue:** {{issue}}
46
+
47
+ Respond to the customer's issue. Be concise and helpful.`,
48
+ });
49
+ ```
50
+
51
+ ### Options
52
+
53
+ | Option | Type | Required | Description |
54
+ |--------|------|----------|-------------|
55
+ | `id` | `string` | Yes | Unique identifier (becomes the prompt slug) |
56
+ | `description` | `string` | No | Shown in the dashboard |
57
+ | `model` | `string` | No | Default model (e.g. `"gpt-4o"`, `"claude-sonnet-4-6"`) |
58
+ | `config` | `object` | No | Default config (temperature, maxTokens, etc.) |
59
+ | `variables` | Zod/ArkType schema | No | Schema for template variables (enables validation and dashboard UI) |
60
+ | `content` | `string` | Yes | The prompt template with `{{variable}}` placeholders |
61
+
62
+ ### Template syntax
63
+
64
+ Templates use Mustache-style placeholders:
65
+
66
+ - `{{variableName}}` — replaced with the variable value
67
+ - `{{#conditionalVar}}...{{/conditionalVar}}` — content only included if the variable is truthy
68
+
69
+ ```ts
70
+ export const prompt = prompts.define({
71
+ id: "summarizer",
72
+ model: "gpt-4o-mini",
73
+ variables: z.object({
74
+ text: z.string(),
75
+ maxSentences: z.string().optional(),
76
+ }),
77
+ content: `Summarize the following text{{#maxSentences}} in {{maxSentences}} sentences or fewer{{/maxSentences}}:
78
+
79
+ {{text}}`,
80
+ });
81
+ ```
82
+
83
+ ## Resolving a prompt
84
+
85
+ ### Via prompt handle
86
+
87
+ Call `.resolve()` on the handle returned by `define()`:
88
+
89
+ ```ts
90
+ const resolved = await supportPrompt.resolve({
91
+ customerName: "Alice",
92
+ plan: "Pro",
93
+ issue: "Cannot access billing dashboard",
94
+ });
95
+
96
+ console.log(resolved.text); // The compiled prompt with variables filled in
97
+ console.log(resolved.version); // e.g. 3
98
+ console.log(resolved.model); // "gpt-4o"
99
+ console.log(resolved.labels); // ["current"] or ["override"]
100
+ ```
101
+
102
+ ### Via standalone prompts.resolve()
103
+
104
+ Resolve any prompt by slug without needing a handle. Pass the prompt handle as a type parameter for full type safety:
105
+
106
+ ```ts
107
+ import { prompts } from "@trigger.dev/sdk";
108
+ import type { supportPrompt } from "./prompts";
109
+
110
+ // Fully typesafe — ID and variables are checked at compile time
111
+ const resolved = await prompts.resolve<typeof supportPrompt>("customer-support", {
112
+ customerName: "Alice",
113
+ plan: "Pro",
114
+ issue: "Cannot access billing dashboard",
115
+ });
116
+ ```
117
+
118
+ Without the generic, the function still works but accepts any string slug and `Record<string, unknown>` variables.
119
+
120
+ ### Resolve options
121
+
122
+ You can resolve a specific version or label:
123
+
124
+ ```ts
125
+ // Resolve a specific version
126
+ const v2 = await supportPrompt.resolve(variables, { version: 2 });
127
+
128
+ // Resolve by label
129
+ const current = await supportPrompt.resolve(variables, { label: "current" });
130
+ ```
131
+
132
+ By default, `resolve()` returns the **override** version if one is active, otherwise the **current** (latest deployed) version.
133
+
134
+ <Note>
135
+ Both `promptHandle.resolve()` and `prompts.resolve()` call the Trigger.dev API when a client is configured. During local dev with `trigger dev`, this means you'll always get the server version (including overrides).
136
+ </Note>
137
+
138
+ ## Using with the AI SDK
139
+
140
+ The resolved prompt integrates with the [Vercel AI SDK](https://ai-sdk.dev) via `toAISDKTelemetry()`. This links AI generation spans to the prompt in the dashboard.
141
+
142
+ ### generateText
143
+
144
+ ```ts
145
+ import { task } from "@trigger.dev/sdk";
146
+ import { generateText, stepCountIs } from "ai";
147
+ import { anthropic } from "@ai-sdk/anthropic";
148
+
149
+ export const supportTask = task({
150
+ id: "handle-support",
151
+ run: async (payload) => {
152
+ const resolved = await supportPrompt.resolve({
153
+ customerName: payload.name,
154
+ plan: payload.plan,
155
+ issue: payload.issue,
156
+ });
157
+
158
+ const result = await generateText({
159
+ model: openai(resolved.model ?? "gpt-4o"),
160
+ system: resolved.text,
161
+ prompt: payload.issue,
162
+ ...resolved.toAISDKTelemetry(),
163
+ });
164
+
165
+ return { response: result.text };
166
+ },
167
+ });
168
+ ```
169
+
170
+ ### streamText
171
+
172
+ ```ts
173
+ import { streamText } from "ai";
174
+
175
+ export const streamTask = task({
176
+ id: "stream-support",
177
+ run: async (payload) => {
178
+ const resolved = await supportPrompt.resolve({
179
+ customerName: payload.name,
180
+ plan: payload.plan,
181
+ issue: payload.issue,
182
+ });
183
+
184
+ const result = streamText({
185
+ model: openai(resolved.model ?? "gpt-4o"),
186
+ system: resolved.text,
187
+ prompt: payload.issue,
188
+ ...resolved.toAISDKTelemetry(),
189
+ stopWhen: stepCountIs(15),
190
+ });
191
+
192
+ let fullText = "";
193
+ for await (const chunk of result.textStream) {
194
+ fullText += chunk;
195
+ }
196
+
197
+ return { response: fullText };
198
+ },
199
+ });
200
+ ```
201
+
202
+ ### Custom telemetry metadata
203
+
204
+ Pass additional metadata to `toAISDKTelemetry()` that will appear on the generation span:
205
+
206
+ ```ts
207
+ const result = await generateText({
208
+ model: anthropic("claude-sonnet-4-5"),
209
+ prompt: resolved.text,
210
+ ...resolved.toAISDKTelemetry({
211
+ "task.type": "summarization",
212
+ "customer.tier": "enterprise",
213
+ }),
214
+ });
215
+ ```
216
+
217
+ ## Using with chat.agent()
218
+
219
+ Prompts integrate with `chat.agent()` via `chat.prompt` — a run-scoped store for the resolved prompt. Store a prompt once in a lifecycle hook, then access it anywhere during the run.
220
+
221
+ ### chat.prompt.set() and chat.prompt()
222
+
223
+ ```ts
224
+ import { chat } from "@trigger.dev/sdk/ai";
225
+ import { prompts } from "@trigger.dev/sdk";
226
+ import { streamText, createProviderRegistry } from "ai";
227
+ import { anthropic } from "@ai-sdk/anthropic";
228
+
229
+ const registry = createProviderRegistry({ anthropic });
230
+
231
+ const systemPrompt = prompts.define({
232
+ id: "my-chat-system",
233
+ model: "anthropic:claude-sonnet-4-5",
234
+ config: { temperature: 0.7 },
235
+ variables: z.object({ name: z.string() }),
236
+ content: `You are a helpful assistant for {{name}}.`,
237
+ });
238
+
239
+ export const myChat = chat.agent({
240
+ id: "my-chat",
241
+ onChatStart: async ({ clientData }) => {
242
+ const resolved = await systemPrompt.resolve({ name: clientData.name });
243
+ chat.prompt.set(resolved);
244
+ },
245
+ run: async ({ messages, signal }) => {
246
+ return streamText({
247
+ ...chat.toStreamTextOptions({ registry }),
248
+ messages,
249
+ abortSignal: signal,
250
+ stopWhen: stepCountIs(15),
251
+ });
252
+ },
253
+ });
254
+ ```
255
+
256
+ ### chat.toStreamTextOptions()
257
+
258
+ Returns an options object ready to spread into `streamText()`. When a prompt is stored via `chat.prompt.set()`, it includes:
259
+
260
+ - `system` — the compiled prompt text
261
+ - `model` — resolved via the `registry` when provided
262
+ - `temperature`, `maxTokens`, etc. — from the prompt's `config`
263
+ - `experimental_telemetry` — links generations to the prompt in the dashboard
264
+
265
+ ```ts
266
+ // With registry — model is resolved automatically
267
+ const options = chat.toStreamTextOptions({ registry });
268
+ // { system: "...", model: LanguageModel, temperature: 0.7, experimental_telemetry: { ... } }
269
+
270
+ // Without registry — model is not included
271
+ const options = chat.toStreamTextOptions();
272
+ // { system: "...", temperature: 0.7, experimental_telemetry: { ... } }
273
+ ```
274
+
275
+ <Tip>
276
+ When the user provides a `registry` and the prompt has a `model` string (e.g. `"anthropic:claude-sonnet-4-5"`), the model is resolved via `registry.languageModel()` and included in the returned options. This means `streamText` uses the prompt's model by default — no manual model selection needed.
277
+ </Tip>
278
+
279
+ ### Reading the prompt
280
+
281
+ Access the stored prompt from anywhere in the run:
282
+
283
+ ```ts
284
+ run: async ({ messages, signal }) => {
285
+ const prompt = chat.prompt(); // Throws if not set
286
+ console.log(prompt.text); // The compiled prompt
287
+ console.log(prompt.model); // "anthropic:claude-sonnet-4-5"
288
+ console.log(prompt.version); // 3
289
+
290
+ return streamText({
291
+ ...chat.toStreamTextOptions({ registry }),
292
+ messages,
293
+ abortSignal: signal,
294
+ stopWhen: stepCountIs(15),
295
+ });
296
+ },
297
+ ```
298
+
299
+ You can also set a plain string if you don't need the full prompt system:
300
+
301
+ ```ts
302
+ chat.prompt.set("You are a helpful assistant.");
303
+ ```
304
+
305
+ ## Prompt management SDK
306
+
307
+ The `prompts` namespace includes methods for managing prompts programmatically. These work both inside tasks and outside (e.g. scripts, API handlers) as long as an API client is configured.
308
+
309
+ ### List prompts
310
+
311
+ ```ts
312
+ const allPrompts = await prompts.list();
313
+ ```
314
+
315
+ ### List versions
316
+
317
+ ```ts
318
+ const versions = await prompts.versions("customer-support");
319
+ ```
320
+
321
+ ### Create an override
322
+
323
+ Create a new override that takes priority over the deployed version:
324
+
325
+ ```ts
326
+ const result = await prompts.createOverride("customer-support", {
327
+ textContent: "New prompt template: Hello {{customerName}}!",
328
+ model: "gpt-4o-mini",
329
+ commitMessage: "Shorter prompt",
330
+ });
331
+ ```
332
+
333
+ ### Update an override
334
+
335
+ ```ts
336
+ await prompts.updateOverride("customer-support", {
337
+ textContent: "Updated template: Hi {{customerName}}!",
338
+ model: "gpt-4o",
339
+ });
340
+ ```
341
+
342
+ ### Remove an override
343
+
344
+ Remove the active override, reverting to the deployed version:
345
+
346
+ ```ts
347
+ await prompts.removeOverride("customer-support");
348
+ ```
349
+
350
+ ### Promote a version
351
+
352
+ ```ts
353
+ await prompts.promote("customer-support", 2);
354
+ ```
355
+
356
+ ### All management methods
357
+
358
+ | Method | Description |
359
+ |--------|-------------|
360
+ | `prompts.list()` | List all prompts in the current environment |
361
+ | `prompts.versions(slug)` | List all versions for a prompt |
362
+ | `prompts.resolve(slug, variables?, options?)` | Resolve a prompt by slug |
363
+ | `prompts.promote(slug, version)` | Promote a version to current |
364
+ | `prompts.createOverride(slug, body)` | Create an override |
365
+ | `prompts.updateOverride(slug, body)` | Update the active override |
366
+ | `prompts.removeOverride(slug)` | Remove the active override |
367
+ | `prompts.reactivateOverride(slug, version)` | Reactivate a removed override |
368
+
369
+ ## Overrides
370
+
371
+ Overrides let you change a prompt's template or model from the dashboard or SDK without redeploying your code. When an override is active, `resolve()` returns the override version instead of the deployed version.
372
+
373
+ ### How overrides work
374
+
375
+ - Overrides take priority over the deployed ("current") version
376
+ - Only one override can be active at a time
377
+ - Creating a new override replaces the previous one
378
+ - Removing an override reverts to the deployed version
379
+ - Overrides are environment-scoped (dev, staging, production are independent)
380
+
381
+ ### Creating an override (dashboard)
382
+
383
+ 1. Go to the prompt detail page
384
+ 2. Click **Create Override**
385
+ 3. Edit the template text and/or model
386
+ 4. Add an optional commit message
387
+ 5. Click **Create override**
388
+
389
+ ### Version resolution order
390
+
391
+ When `resolve()` is called, versions are resolved in this order:
392
+
393
+ 1. **Specific version** — if `{ version: N }` is passed
394
+ 2. **Override** — if an override is active in this environment
395
+ 3. **Label** — if `{ label: "..." }` is passed (defaults to `"current"`)
396
+ 4. **Current** — the latest deployed version with the "current" label
397
+
398
+ ## Dashboard
399
+
400
+ ### Prompts list
401
+
402
+ The prompts list page shows all prompts in the current environment with the current or override version, default model, and a usage sparkline.
403
+
404
+ ### Prompt detail
405
+
406
+ Click a prompt to see:
407
+
408
+ - **Template panel** — the prompt template for the selected version
409
+ - **Details tab** — slug, description, model, config, source file, and variable schema
410
+ - **Versions tab** — all versions with labels, source, and commit messages
411
+ - **Generations tab** — every AI generation that used this prompt, with live polling
412
+ - **Metrics tab** — token usage, cost, and latency charts
413
+
414
+ ### AI span inspectors
415
+
416
+ When you use `toAISDKTelemetry()`, AI generation spans in the run trace get a custom inspector showing:
417
+
418
+ - **Overview** — model, provider, token usage, cost, input/output preview
419
+ - **Messages** — the full message thread
420
+ - **Tools** — tool definitions and tool call details
421
+ - **Prompt** — the linked prompt's metadata, input variables, and template content
422
+
423
+ ## Type utilities
424
+
425
+ ```ts
426
+ import type { PromptHandle, PromptIdentifier, PromptVariables } from "@trigger.dev/sdk";
427
+
428
+ type Id = PromptIdentifier<typeof supportPrompt>; // "customer-support"
429
+ type Vars = PromptVariables<typeof supportPrompt>; // { customerName: string; plan: string; issue: string }
430
+ ```
@@ -0,0 +1,115 @@
1
+ ---
2
+ title: "Actions"
3
+ sidebarTitle: "Actions"
4
+ description: "Custom commands sent from the frontend that mutate chat state without consuming a turn — undo, rollback, edit, regenerate."
5
+ ---
6
+
7
+ import RcBanner from "/snippets/ai-chat-rc-banner.mdx";
8
+
9
+ <RcBanner />
10
+
11
+ ## Overview
12
+
13
+ Custom actions let the frontend send structured commands (undo, rollback, edit, regenerate) that modify the conversation state. **Actions are not turns**: they fire `hydrateMessages` (if set) and `onAction` only. No turn lifecycle hooks (`onTurnStart` / `prepareMessages` / `onBeforeTurnComplete` / `onTurnComplete`), no `run()`, no turn-counter increment. The trace span is named `chat action`.
14
+
15
+ Actions wake the agent from suspension the same way a new message does, run their handler against the latest accumulator state, and emit a `trigger:turn-complete` chunk so the frontend's `useChat` knows the action has been applied.
16
+
17
+ ## Defining an action handler
18
+
19
+ Define an `actionSchema` for validation and an `onAction` handler that uses [`chat.history`](/ai-chat/backend#chat-history) to modify state:
20
+
21
+ ```ts
22
+ import { z } from "zod";
23
+
24
+ export const myChat = chat.agent({
25
+ id: "my-chat",
26
+ actionSchema: z.discriminatedUnion("type", [
27
+ z.object({ type: z.literal("undo") }),
28
+ z.object({ type: z.literal("rollback"), targetMessageId: z.string() }),
29
+ z.object({ type: z.literal("edit"), messageId: z.string(), text: z.string() }),
30
+ ]),
31
+
32
+ onAction: async ({ action }) => {
33
+ switch (action.type) {
34
+ case "undo":
35
+ chat.history.slice(0, -2); // Remove last user + assistant exchange
36
+ break;
37
+ case "rollback":
38
+ chat.history.rollbackTo(action.targetMessageId);
39
+ break;
40
+ case "edit":
41
+ chat.history.replace(action.messageId, {
42
+ id: action.messageId,
43
+ role: "user",
44
+ parts: [{ type: "text", text: action.text }],
45
+ });
46
+ break;
47
+ }
48
+ // returning void → side-effect-only, no model call
49
+ },
50
+
51
+ run: async ({ messages, signal }) => {
52
+ return streamText({ model: anthropic("claude-sonnet-4-5"), messages, abortSignal: signal });
53
+ },
54
+ });
55
+ ```
56
+
57
+ **Lifecycle flow:** Wake → parse action against `actionSchema` → `hydrateMessages` (if set) → **`onAction`** → apply `chat.history` mutations → emit `trigger:turn-complete` → wait for next message.
58
+
59
+ ## Returning a model response from an action
60
+
61
+ `onAction` can return a `StreamTextResult`, `string`, or `UIMessage` to produce a response. The returned stream is auto-piped to the frontend just like a normal turn, but the rest of the turn machinery (`onTurnStart`, `onTurnComplete`, etc.) still does not fire.
62
+
63
+ ```ts
64
+ onAction: async ({ action, messages }) => {
65
+ if (action.type === "regenerate") {
66
+ chat.history.slice(0, -1); // drop the last assistant
67
+ return streamText({
68
+ model: anthropic("claude-sonnet-4-5"),
69
+ messages,
70
+ stopWhen: stepCountIs(15),
71
+ });
72
+ }
73
+ // other actions return void → side-effect only
74
+ }
75
+ ```
76
+
77
+ This is useful for actions that both mutate state and want a fresh model response (regenerate-from-here, retry-with-different-style). Persistence is your responsibility inside `onAction` itself; you have access to the streamed response object.
78
+
79
+ ## Gating actions on HITL state
80
+
81
+ If you have a [human-in-the-loop](/ai-chat/patterns/human-in-the-loop) tool waiting on `addToolOutput`, you usually want to refuse competing actions like `regenerate` until the answer arrives. [`chat.history.getPendingToolCalls()`](/ai-chat/backend#chat-history) gives you exactly that signal:
82
+
83
+ ```ts
84
+ onAction: async ({ action, messages, signal }) => {
85
+ if (action.type === "regenerate") {
86
+ if (chat.history.getPendingToolCalls().length > 0) return; // gated
87
+ chat.history.slice(0, -1);
88
+ return streamText({ model: anthropic("claude-sonnet-4-5"), messages, abortSignal: signal });
89
+ }
90
+ },
91
+ ```
92
+
93
+ ## Sending actions from the frontend
94
+
95
+ ```ts
96
+ // Browser — TriggerChatTransport
97
+ const stream = await transport.sendAction(chatId, { type: "undo" });
98
+
99
+ // Server — AgentChat
100
+ const stream = await agentChat.sendAction({ type: "rollback", targetMessageId: "msg-3" });
101
+ ```
102
+
103
+ The action payload is validated against `actionSchema` on the backend; invalid actions throw and surface as a stream error. The `action` parameter in `onAction` is fully typed from the schema.
104
+
105
+ <Note>
106
+ For silent state changes that should never appear as a turn (e.g. injecting background context), use [`chat.inject()`](/ai-chat/background-injection) instead. Actions are explicit user-driven mutations; injections are agent-side context updates.
107
+ </Note>
108
+
109
+ ## See also
110
+
111
+ - [`chat.history`](/ai-chat/backend#chat-history) — the imperative API actions use to mutate state
112
+ - [Sending actions from the frontend](/ai-chat/frontend#sending-actions) — `transport.sendAction` ergonomics
113
+ - [`hydrateMessages`](/ai-chat/lifecycle-hooks#hydratemessages) — fires before `onAction` when set
114
+ - [Branching conversations](/ai-chat/patterns/branching-conversations) — pairs action handlers with backend-controlled history
115
+ - [Human-in-the-loop](/ai-chat/patterns/human-in-the-loop) — gating fresh actions while a tool is waiting
@@ -0,0 +1,71 @@
1
+ ---
2
+ title: "Anatomy of an agent"
3
+ sidebarTitle: "Anatomy"
4
+ description: "The moving parts of a chat agent — the agent task, the session, the frontend transport — and which page covers each."
5
+ ---
6
+
7
+ import RcBanner from "/snippets/ai-chat-rc-banner.mdx";
8
+
9
+ <RcBanner />
10
+
11
+ **A chat agent is three parts: a long-lived agent task that runs the turn loop, a durable Session carrying messages in and the response stream out, and a frontend transport that plugs the session into `useChat`.** The pages in this section each own one part of that picture. This page is the map — if you'd rather read mechanics end to end, skip to [How it works](/ai-chat/how-it-works).
12
+
13
+ ```mermaid
14
+ flowchart LR
15
+ FE["Frontend<br/>useChat + transport"] -- "user messages" --> IN([Session .in])
16
+ IN --> AGENT["Agent task<br/>turn loop + hooks"]
17
+ AGENT --> OUT([Session .out])
18
+ OUT -- "streamed response" --> FE
19
+ ```
20
+
21
+ Everything below maps onto one annotated agent:
22
+
23
+ ```ts trigger/my-agent.ts
24
+ import { chat } from "@trigger.dev/sdk/ai";
25
+ import { streamText, stepCountIs } from "ai";
26
+ import { anthropic } from "@ai-sdk/anthropic";
27
+
28
+ export const myAgent = chat.agent({
29
+ id: "my-agent",
30
+
31
+ // Tools declared on the config survive history re-conversion
32
+ // across turns — see Tools.
33
+ tools: { searchDocs },
34
+
35
+ // Hooks fire around each turn: validation, persistence,
36
+ // post-turn work — see Lifecycle hooks.
37
+ onTurnComplete: async ({ responseMessage }) => {
38
+ await db.messages.save(responseMessage);
39
+ },
40
+
41
+ // The turn loop. Messages arrive accumulated; you stream back.
42
+ // Options, levels, and alternatives — see Backend.
43
+ run: async ({ messages, tools, signal }) =>
44
+ streamText({
45
+ ...chat.toStreamTextOptions({ tools }),
46
+ model: anthropic("claude-sonnet-4-5"),
47
+ messages,
48
+ abortSignal: signal,
49
+ stopWhen: stepCountIs(15),
50
+ }),
51
+ });
52
+ ```
53
+
54
+ The frontend side is one hook — `useTriggerChatTransport` connects `useChat` to the agent's session, no API routes ([Frontend](/ai-chat/frontend)). Underneath, the conversation lives on a [Session](/ai-chat/sessions): a pair of durable streams keyed on your `chatId` that survives refreshes, deploys, and run boundaries.
55
+
56
+ ## Where each part is covered
57
+
58
+ | Part | Page |
59
+ | ----------------------------------------------------- | ---------------------------------------------- |
60
+ | `chat.agent()` options, the turn loop, piping | [Backend](/ai-chat/backend) |
61
+ | Hooks around each turn (`onTurnComplete`, hydration) | [Lifecycle hooks](/ai-chat/lifecycle-hooks) |
62
+ | Declaring tools, typed payloads, `toModelOutput` | [Tools](/ai-chat/tools) |
63
+ | `useChat` wiring, tokens, starting sessions | [Frontend](/ai-chat/frontend) |
64
+ | Driving a chat from your server instead of a browser | [Server-side chat](/ai-chat/server-chat) |
65
+ | The durable substrate under every agent | [Sessions](/ai-chat/sessions) |
66
+ | Per-run typed state inside the loop | [chat.local](/ai-chat/chat-local) |
67
+ | Type-safe payloads, client data, and messages | [Types](/ai-chat/types) |
68
+ | Building without the managed lifecycle | [Custom agents](/ai-chat/custom-agents) |
69
+ | End-to-end mechanics: what survives a refresh and why | [How it works](/ai-chat/how-it-works) |
70
+
71
+ Beyond this section: [Features](/ai-chat/fast-starts) covers opt-in capabilities (Head Start, compaction, steering, actions), and [Patterns](/ai-chat/patterns/sub-agents) covers production recipes (sub-agents, HITL approvals, persistence, recovery).