@trigger.dev/sdk 4.8.0 → 4.8.1
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/version.js +1 -1
- package/dist/esm/version.js +1 -1
- package/docs/ai/prompts.mdx +9 -6
- package/docs/ai-chat/chat-local.mdx +4 -4
- package/docs/ai-chat/fast-starts.mdx +1 -1
- package/docs/ai-chat/overview.mdx +4 -3
- package/docs/ai-chat/patterns/database-persistence.mdx +3 -3
- package/docs/ai-chat/patterns/native-compaction.mdx +6 -6
- package/docs/ai-chat/patterns/sub-agents.mdx +1 -1
- package/docs/ai-chat/patterns/version-upgrades.mdx +3 -3
- package/docs/ai-chat/side-channels.mdx +2 -2
- package/docs/ai-chat/types.mdx +5 -5
- package/docs/database-connections.mdx +2 -2
- package/docs/introduction.mdx +104 -24
- package/docs/mcp-tools.mdx +5 -0
- package/docs/self-hosting/env/supervisor.mdx +1 -0
- package/docs/self-hosting/env/webapp.mdx +24 -0
- package/docs/self-hosting/overview.mdx +2 -0
- package/package.json +2 -2
package/dist/commonjs/version.js
CHANGED
package/dist/esm/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const VERSION = "4.8.
|
|
1
|
+
export const VERSION = "4.8.1";
|
|
2
2
|
//# sourceMappingURL=version.js.map
|
package/docs/ai/prompts.mdx
CHANGED
|
@@ -219,8 +219,9 @@ Prompts integrate with `chat.agent()` via `chat.prompt` — a run-scoped store f
|
|
|
219
219
|
```ts
|
|
220
220
|
import { chat } from "@trigger.dev/sdk/ai";
|
|
221
221
|
import { prompts } from "@trigger.dev/sdk";
|
|
222
|
-
import {
|
|
222
|
+
import { createProviderRegistry, stepCountIs } from "ai";
|
|
223
223
|
import { anthropic } from "@ai-sdk/anthropic";
|
|
224
|
+
import { z } from "zod";
|
|
224
225
|
|
|
225
226
|
const registry = createProviderRegistry({ anthropic });
|
|
226
227
|
|
|
@@ -234,13 +235,14 @@ const systemPrompt = prompts.define({
|
|
|
234
235
|
|
|
235
236
|
export const myChat = chat.agent({
|
|
236
237
|
id: "my-chat",
|
|
238
|
+
registry,
|
|
239
|
+
clientDataSchema: z.object({ name: z.string() }),
|
|
237
240
|
onChatStart: async ({ clientData }) => {
|
|
238
241
|
const resolved = await systemPrompt.resolve({ name: clientData.name });
|
|
239
242
|
chat.prompt.set(resolved);
|
|
240
243
|
},
|
|
241
|
-
run: async ({ messages, signal }) => {
|
|
244
|
+
run: async ({ messages, signal, streamText }) => {
|
|
242
245
|
return streamText({
|
|
243
|
-
...chat.toStreamTextOptions({ registry }),
|
|
244
246
|
messages,
|
|
245
247
|
abortSignal: signal,
|
|
246
248
|
stopWhen: stepCountIs(15),
|
|
@@ -249,9 +251,11 @@ export const myChat = chat.agent({
|
|
|
249
251
|
});
|
|
250
252
|
```
|
|
251
253
|
|
|
254
|
+
The `streamText` passed to `run()` applies the stored prompt: its system text, its model (resolved through the agent's `registry`), its `config`, and telemetry that links each generation to the prompt version. Options you pass at the call site win, apart from `system`, which throws when a prompt already sets one.
|
|
255
|
+
|
|
252
256
|
### chat.toStreamTextOptions()
|
|
253
257
|
|
|
254
|
-
|
|
258
|
+
Inside a `chat.agent` you don't need this: the `streamText` passed to `run()` applies the same options. Use `chat.toStreamTextOptions()` when you call `streamText` yourself, as in a [custom agent](/ai-chat/custom-agents). It returns an options object ready to spread into `streamText()`. When a prompt is stored via `chat.prompt.set()`, it includes:
|
|
255
259
|
|
|
256
260
|
- `system` — the compiled prompt text
|
|
257
261
|
- `model` — resolved via the `registry` when provided
|
|
@@ -277,14 +281,13 @@ const options = chat.toStreamTextOptions();
|
|
|
277
281
|
Access the stored prompt from anywhere in the run:
|
|
278
282
|
|
|
279
283
|
```ts
|
|
280
|
-
run: async ({ messages, signal }) => {
|
|
284
|
+
run: async ({ messages, signal, streamText }) => {
|
|
281
285
|
const prompt = chat.prompt(); // Throws if not set
|
|
282
286
|
console.log(prompt.text); // The compiled prompt
|
|
283
287
|
console.log(prompt.model); // "anthropic:claude-sonnet-4-5"
|
|
284
288
|
console.log(prompt.version); // 3
|
|
285
289
|
|
|
286
290
|
return streamText({
|
|
287
|
-
...chat.toStreamTextOptions({ registry }),
|
|
288
291
|
messages,
|
|
289
292
|
abortSignal: signal,
|
|
290
293
|
stopWhen: stepCountIs(15),
|
|
@@ -16,7 +16,7 @@ Declare locals at module level with a unique `id`, then initialize them inside a
|
|
|
16
16
|
|
|
17
17
|
```ts
|
|
18
18
|
import { chat } from "@trigger.dev/sdk/ai";
|
|
19
|
-
import {
|
|
19
|
+
import { tool, stepCountIs } from "ai";
|
|
20
20
|
import { anthropic } from "@ai-sdk/anthropic";
|
|
21
21
|
import { z } from "zod";
|
|
22
22
|
import { db } from "@/lib/db";
|
|
@@ -44,7 +44,7 @@ export const myChat = chat.agent({
|
|
|
44
44
|
messageCount: user.messageCount,
|
|
45
45
|
});
|
|
46
46
|
},
|
|
47
|
-
run: async ({ messages, signal }) => {
|
|
47
|
+
run: async ({ messages, signal, streamText }) => {
|
|
48
48
|
userContext.messageCount++;
|
|
49
49
|
|
|
50
50
|
return streamText({
|
|
@@ -88,7 +88,7 @@ When you use `ai.toolExecute()` inside AI SDK `tool()` to expose a subtask, chat
|
|
|
88
88
|
```ts
|
|
89
89
|
import { chat, ai } from "@trigger.dev/sdk/ai";
|
|
90
90
|
import { schemaTask } from "@trigger.dev/sdk";
|
|
91
|
-
import {
|
|
91
|
+
import { tool, stepCountIs } from "ai";
|
|
92
92
|
import { anthropic } from "@ai-sdk/anthropic";
|
|
93
93
|
import { z } from "zod";
|
|
94
94
|
|
|
@@ -115,7 +115,7 @@ export const myChat = chat.agent({
|
|
|
115
115
|
onBoot: async ({ clientData }) => {
|
|
116
116
|
userContext.init({ name: "Alice", plan: "pro" });
|
|
117
117
|
},
|
|
118
|
-
run: async ({ messages, signal }) => {
|
|
118
|
+
run: async ({ messages, signal, streamText }) => {
|
|
119
119
|
return streamText({
|
|
120
120
|
model: anthropic("claude-sonnet-4-5"),
|
|
121
121
|
messages,
|
|
@@ -80,7 +80,7 @@ export const myChat = chat.agent({
|
|
|
80
80
|
if (preloaded) return; // Already initialized in onPreload
|
|
81
81
|
// ... fallback initialization for non-preloaded runs
|
|
82
82
|
},
|
|
83
|
-
run: async ({ messages, signal }) => {
|
|
83
|
+
run: async ({ messages, signal, streamText }) => {
|
|
84
84
|
return streamText({ model: anthropic("claude-sonnet-4-5"), messages, abortSignal: signal });
|
|
85
85
|
},
|
|
86
86
|
});
|
|
@@ -12,12 +12,12 @@ A `chat.agent` task takes `messages`, calls `streamText`, and returns the result
|
|
|
12
12
|
|
|
13
13
|
```ts trigger/chat.ts
|
|
14
14
|
import { chat } from "@trigger.dev/sdk/ai";
|
|
15
|
-
import {
|
|
15
|
+
import { stepCountIs } from "ai";
|
|
16
16
|
import { anthropic } from "@ai-sdk/anthropic";
|
|
17
17
|
|
|
18
18
|
export const myChat = chat.agent({
|
|
19
19
|
id: "my-chat",
|
|
20
|
-
run: async ({ messages, signal }) =>
|
|
20
|
+
run: async ({ messages, signal, streamText }) =>
|
|
21
21
|
streamText({
|
|
22
22
|
model: anthropic("claude-sonnet-4-5"),
|
|
23
23
|
messages,
|
|
@@ -56,11 +56,12 @@ See [Quick Start](/ai-chat/quick-start) for the matching server actions and a ru
|
|
|
56
56
|
|
|
57
57
|
## How it fits together
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
Four primitives, related but distinct:
|
|
60
60
|
|
|
61
61
|
- **Chat agents** — the SDK surface you define with [`chat.agent()`](/ai-chat/backend#chat-agent). Owns the turn loop, lifecycle hooks, and the response stream.
|
|
62
62
|
- **Sessions** — the durable, bi-directional channel keyed on `chatId` that holds the conversation across run boundaries. A chat agent runs *on top of* a [Session](/ai-chat/sessions).
|
|
63
63
|
- **Sub-agents** — Delegate work from one agent to another via [`AgentChat`](/ai-chat/patterns/sub-agents). The sub-agent runs as its own durable agent on its own session; its response streams back through the parent as preliminary tool results, so the frontend sees the sub-agent working inside the parent's tool card.
|
|
64
|
+
- **Channels** connect an agent to a surface other than your frontend. [`slack()`](/webhooks/slack) and [`linear()`](/webhooks/linear) turn an agent into a Slack or Linear agent, and [`chat.channels.custom()`](/webhooks/channels) connects any chat surface that sends webhooks. Each conversation there is still a durable session, and the reply posts back to the surface.
|
|
64
65
|
|
|
65
66
|
## Next steps
|
|
66
67
|
|
|
@@ -226,7 +226,7 @@ export const myChat = chat.agent({
|
|
|
226
226
|
}),
|
|
227
227
|
]);
|
|
228
228
|
},
|
|
229
|
-
run: async ({ messages, signal }) => {
|
|
229
|
+
run: async ({ messages, signal, streamText }) => {
|
|
230
230
|
return streamText({ model: anthropic("claude-sonnet-4-5"), messages, abortSignal: signal });
|
|
231
231
|
},
|
|
232
232
|
});
|
|
@@ -254,7 +254,7 @@ End-to-end implementation across the three files involved: agent task, server ac
|
|
|
254
254
|
<CodeGroup>
|
|
255
255
|
```ts trigger/chat.ts
|
|
256
256
|
import { chat } from "@trigger.dev/sdk/ai";
|
|
257
|
-
import {
|
|
257
|
+
import { stepCountIs } from "ai";
|
|
258
258
|
import { anthropic } from "@ai-sdk/anthropic";
|
|
259
259
|
import { z } from "zod";
|
|
260
260
|
import { db } from "@/lib/db";
|
|
@@ -296,7 +296,7 @@ export const myChat = chat.agent({
|
|
|
296
296
|
}),
|
|
297
297
|
]);
|
|
298
298
|
},
|
|
299
|
-
run: async ({ messages, signal }) => {
|
|
299
|
+
run: async ({ messages, signal, streamText }) => {
|
|
300
300
|
return streamText({
|
|
301
301
|
model: anthropic("claude-sonnet-4-5"),
|
|
302
302
|
messages,
|
|
@@ -31,7 +31,7 @@ The fix: read the `appliedEdits` counts as they stream in `onStepFinish`, then a
|
|
|
31
31
|
|
|
32
32
|
```ts /trigger/native-persist.ts
|
|
33
33
|
import { chat } from "@trigger.dev/sdk/ai";
|
|
34
|
-
import {
|
|
34
|
+
import { stepCountIs, tool, type UIMessage } from "ai";
|
|
35
35
|
import { anthropic } from "@ai-sdk/anthropic";
|
|
36
36
|
import { z } from "zod";
|
|
37
37
|
|
|
@@ -75,7 +75,7 @@ export const nativePersist = chat.agent({
|
|
|
75
75
|
id: "native-persist",
|
|
76
76
|
idleTimeoutInSeconds: 120,
|
|
77
77
|
tools: { fetchRecord },
|
|
78
|
-
run: async ({ messages, chatId, tools, signal }) => {
|
|
78
|
+
run: async ({ messages, chatId, tools, signal, streamText }) => {
|
|
79
79
|
return streamText({
|
|
80
80
|
model: anthropic("claude-sonnet-4-5"),
|
|
81
81
|
messages,
|
|
@@ -132,7 +132,7 @@ OpenAI's `store: true` keeps the thread server-side and returns a `responseId`.
|
|
|
132
132
|
|
|
133
133
|
```ts /trigger/openai-store.ts
|
|
134
134
|
import { chat } from "@trigger.dev/sdk/ai";
|
|
135
|
-
import {
|
|
135
|
+
import { stepCountIs, type ModelMessage } from "ai";
|
|
136
136
|
import { openai } from "@ai-sdk/openai";
|
|
137
137
|
|
|
138
138
|
// Persist the stored-response handle between turns. Replace with your database.
|
|
@@ -151,7 +151,7 @@ function messagesSinceLastAssistant(messages: ModelMessage[]): ModelMessage[] {
|
|
|
151
151
|
export const openaiStore = chat.agent({
|
|
152
152
|
id: "openai-store",
|
|
153
153
|
idleTimeoutInSeconds: 120,
|
|
154
|
-
run: async ({ messages, chatId, signal }) => {
|
|
154
|
+
run: async ({ messages, chatId, signal, streamText }) => {
|
|
155
155
|
const native = nativeStore.get(chatId);
|
|
156
156
|
const outbound = native ? messagesSinceLastAssistant(messages) : messages;
|
|
157
157
|
|
|
@@ -186,7 +186,7 @@ A native handle is a per-provider cache. An OpenAI `previousResponseId` means no
|
|
|
186
186
|
|
|
187
187
|
```ts /trigger/resilient-chat.ts
|
|
188
188
|
import { chat } from "@trigger.dev/sdk/ai";
|
|
189
|
-
import {
|
|
189
|
+
import { generateText, stepCountIs, generateId, type ModelMessage } from "ai";
|
|
190
190
|
import { anthropic } from "@ai-sdk/anthropic";
|
|
191
191
|
import { openai } from "@ai-sdk/openai";
|
|
192
192
|
|
|
@@ -241,7 +241,7 @@ export const resilientChat = chat.agent({
|
|
|
241
241
|
if (chatId) nativeStore.delete(chatId);
|
|
242
242
|
},
|
|
243
243
|
|
|
244
|
-
run: async ({ messages, chatId, signal }) => {
|
|
244
|
+
run: async ({ messages, chatId, signal, streamText }) => {
|
|
245
245
|
let lastError: unknown;
|
|
246
246
|
for (const providerId of FALLBACK_ORDER) {
|
|
247
247
|
const native = nativeStore.get(chatId);
|
|
@@ -275,7 +275,7 @@ const tools = { research: researchTool };
|
|
|
275
275
|
export const myAgent = chat.agent({
|
|
276
276
|
id: "orchestrator",
|
|
277
277
|
tools, // declare here so toModelOutput survives across turns
|
|
278
|
-
run: async ({ messages, tools, stopSignal }) => {
|
|
278
|
+
run: async ({ messages, tools, stopSignal, streamText }) => {
|
|
279
279
|
return streamText({
|
|
280
280
|
model: anthropic("claude-sonnet-4-6"),
|
|
281
281
|
messages,
|
|
@@ -100,7 +100,7 @@ On the agent side, declare which versions the current code supports:
|
|
|
100
100
|
|
|
101
101
|
```ts
|
|
102
102
|
import { chat } from "@trigger.dev/sdk/ai";
|
|
103
|
-
|
|
103
|
+
|
|
104
104
|
import { anthropic } from "@ai-sdk/anthropic";
|
|
105
105
|
|
|
106
106
|
// The set of frontend protocol versions this agent code supports.
|
|
@@ -121,7 +121,7 @@ export const myChat = chat
|
|
|
121
121
|
chat.requestUpgrade();
|
|
122
122
|
}
|
|
123
123
|
},
|
|
124
|
-
run: async ({ messages, signal }) => {
|
|
124
|
+
run: async ({ messages, signal, streamText }) => {
|
|
125
125
|
return streamText({ model: anthropic("claude-sonnet-4-5"), messages, abortSignal: signal });
|
|
126
126
|
},
|
|
127
127
|
});
|
|
@@ -183,7 +183,7 @@ export const myChat = chat
|
|
|
183
183
|
chat.requestUpgrade();
|
|
184
184
|
}
|
|
185
185
|
},
|
|
186
|
-
run: async ({ messages, signal }) => {
|
|
186
|
+
run: async ({ messages, signal, streamText }) => {
|
|
187
187
|
return streamText({ model: anthropic("claude-sonnet-4-5"), messages, abortSignal: signal });
|
|
188
188
|
},
|
|
189
189
|
});
|
|
@@ -38,12 +38,12 @@ Inside a `chat.agent` run, `chat.channel(...)` opens a channel on the current ru
|
|
|
38
38
|
|
|
39
39
|
```ts /trigger/browser-agent.ts
|
|
40
40
|
import { chat } from "@trigger.dev/sdk/ai";
|
|
41
|
-
|
|
41
|
+
|
|
42
42
|
import { screenshots } from "./channels";
|
|
43
43
|
|
|
44
44
|
export const browserAgent = chat.agent({
|
|
45
45
|
id: "browser-agent",
|
|
46
|
-
run: async ({ messages, signal }) => {
|
|
46
|
+
run: async ({ messages, signal, streamText }) => {
|
|
47
47
|
const frames = chat.channel(screenshots);
|
|
48
48
|
|
|
49
49
|
frames.in.on((control) => setPaused(control.paused)); // control: ViewportControl
|
package/docs/ai-chat/types.mdx
CHANGED
|
@@ -56,7 +56,7 @@ Call `withUIMessage` **once**, then chain `.agent({ ... })` instead of `chat.age
|
|
|
56
56
|
|
|
57
57
|
```ts
|
|
58
58
|
import { chat } from "@trigger.dev/sdk/ai";
|
|
59
|
-
import {
|
|
59
|
+
import { tool } from "ai";
|
|
60
60
|
import { anthropic } from "@ai-sdk/anthropic";
|
|
61
61
|
import { z } from "zod";
|
|
62
62
|
import type { MyChatUIMessage } from "./my-chat-types";
|
|
@@ -90,7 +90,7 @@ export const myChat = chat
|
|
|
90
90
|
data: { status: "preparing" },
|
|
91
91
|
});
|
|
92
92
|
},
|
|
93
|
-
run: async ({ messages, tools, signal }) => {
|
|
93
|
+
run: async ({ messages, tools, signal, streamText }) => {
|
|
94
94
|
// `tools` is myTools, typed, handed back on the payload
|
|
95
95
|
return streamText({
|
|
96
96
|
model: anthropic("claude-sonnet-4-5"),
|
|
@@ -156,7 +156,7 @@ export const myChat = chat
|
|
|
156
156
|
// clientData is typed as { userId: string; model?: string }
|
|
157
157
|
await initUser(clientData.userId);
|
|
158
158
|
},
|
|
159
|
-
run: async ({ messages, clientData, signal }) => {
|
|
159
|
+
run: async ({ messages, clientData, signal, streamText }) => {
|
|
160
160
|
return streamText({
|
|
161
161
|
model: getModel(clientData.model),
|
|
162
162
|
messages,
|
|
@@ -193,7 +193,7 @@ export const myChat = chat
|
|
|
193
193
|
})
|
|
194
194
|
.agent({
|
|
195
195
|
id: "my-chat",
|
|
196
|
-
run: async ({ messages, signal }) => {
|
|
196
|
+
run: async ({ messages, signal, streamText }) => {
|
|
197
197
|
return streamText({ model: anthropic("claude-sonnet-4-5"), messages, abortSignal: signal });
|
|
198
198
|
},
|
|
199
199
|
});
|
|
@@ -218,7 +218,7 @@ chat
|
|
|
218
218
|
// Runs second — task-specific logic
|
|
219
219
|
await createChatRecord(event.chatId);
|
|
220
220
|
},
|
|
221
|
-
run: async ({ messages, signal }) => {
|
|
221
|
+
run: async ({ messages, signal, streamText }) => {
|
|
222
222
|
return streamText({ model: anthropic("claude-sonnet-4-5"), messages, abortSignal: signal });
|
|
223
223
|
},
|
|
224
224
|
});
|
|
@@ -176,13 +176,13 @@ A chat agent runs one long-lived worker per conversation and suspends between me
|
|
|
176
176
|
|
|
177
177
|
```ts /trigger/chat.ts
|
|
178
178
|
import { chat } from "@trigger.dev/sdk/ai";
|
|
179
|
-
|
|
179
|
+
|
|
180
180
|
import { openai } from "@ai-sdk/openai";
|
|
181
181
|
import { prisma } from "@/lib/db";
|
|
182
182
|
|
|
183
183
|
export const myChat = chat.agent({
|
|
184
184
|
id: "my-chat",
|
|
185
|
-
run: async ({ messages, clientData, signal }) => {
|
|
185
|
+
run: async ({ messages, clientData, signal, streamText }) => {
|
|
186
186
|
const user = await prisma.user.findUnique({ where: { id: clientData.userId } });
|
|
187
187
|
// The connection is back in the pool before the model stream starts.
|
|
188
188
|
return streamText({
|
package/docs/introduction.mdx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "Trigger.dev docs"
|
|
3
3
|
sidebarTitle: "Introduction"
|
|
4
|
-
description: "Build and run durable AI agents and workflows in TypeScript. Long-running tasks with retries, queues, observability, and elastic scaling. Open source and self-hostable."
|
|
4
|
+
description: "Build and run durable AI agents and workflows in TypeScript. Long-running tasks with retries, queues, webhooks, observability, and elastic scaling. Open source and self-hostable."
|
|
5
5
|
mode: "center"
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -11,8 +11,8 @@ import AgentSetupPrompt from "/snippets/agent-setup-prompt.mdx";
|
|
|
11
11
|
<Card title="Quick start" icon="rocket" href="/quick-start" color="#A8FF53">
|
|
12
12
|
Go from zero to your first task in 3 minutes.
|
|
13
13
|
</Card>
|
|
14
|
-
<Card title="Build AI agents" icon="robot" href="/
|
|
15
|
-
|
|
14
|
+
<Card title="Build AI agents" icon="robot" href="/ai-chat/overview" color="#a855f7">
|
|
15
|
+
Durable, multi-turn agents with `chat.agent`, from your frontend to Slack and Linear.
|
|
16
16
|
</Card>
|
|
17
17
|
<Card title="AI coding assistants" icon="wand-magic-sparkles" href="/building-with-ai" color="#3B82F6">
|
|
18
18
|
Let Claude Code, Cursor and Windsurf write correct Trigger.dev code with the MCP server, Skills and rules.
|
|
@@ -28,48 +28,124 @@ import AgentSetupPrompt from "/snippets/agent-setup-prompt.mdx";
|
|
|
28
28
|
|
|
29
29
|
## What is Trigger.dev?
|
|
30
30
|
|
|
31
|
-
Trigger.dev is the open source platform for building and running durable AI agents and workflows in TypeScript.
|
|
31
|
+
Trigger.dev is the open source platform for building and running durable AI agents and workflows in TypeScript. You write tasks and agents in your existing codebase, and they run on Trigger.dev with retries, queues, waits, full tracing, and elastic scaling. There's no execution timeout, and no queue or worker infrastructure for you to build.
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
Trigger.dev's core is Apache-2.0 licensed. [Self-host it](/self-hosting/overview) on your own infrastructure, or let [Trigger.dev Cloud](https://cloud.trigger.dev) run it for you.
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
## Build agents with `chat.agent`
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
A `chat.agent` runs each conversation as one durable task. It wakes when a message arrives and idles between turns, and its state survives page refreshes, deploys, and crashes. Turn lifecycle, resuming a stream mid-reply, and approvals are handled for you, and your frontend connects with the AI SDK's `useChat`, with no API routes to write.
|
|
38
|
+
|
|
39
|
+
```ts trigger/chat.ts
|
|
40
|
+
import { chat } from "@trigger.dev/sdk/ai";
|
|
41
|
+
import { anthropic } from "@ai-sdk/anthropic";
|
|
42
|
+
|
|
43
|
+
export const supportAgent = chat.agent({
|
|
44
|
+
id: "support-agent",
|
|
45
|
+
run: async ({ messages, signal, streamText }) =>
|
|
46
|
+
streamText({
|
|
47
|
+
model: anthropic("claude-sonnet-4-5"),
|
|
48
|
+
messages,
|
|
49
|
+
abortSignal: signal,
|
|
50
|
+
}),
|
|
51
|
+
});
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
<CardGroup cols={3}>
|
|
55
|
+
<Card title="Agent quick start" icon="rocket" href="/ai-chat/quick-start">
|
|
56
|
+
Build a chat agent and its frontend end to end.
|
|
57
|
+
</Card>
|
|
58
|
+
<Card title="Sessions" icon="layer-group" href="/ai-chat/sessions">
|
|
59
|
+
Each conversation's durable state and two-way stream, across all its runs.
|
|
60
|
+
</Card>
|
|
61
|
+
<Card title="Tools" icon="screwdriver-wrench" href="/ai-chat/tools">
|
|
62
|
+
Declare tools on your agent and get them back typed in `run()`.
|
|
63
|
+
</Card>
|
|
64
|
+
<Card title="Human in the loop" icon="hand" href="/ai-chat/patterns/human-in-the-loop">
|
|
65
|
+
Pause a tool call for approval and resume when a person decides.
|
|
66
|
+
</Card>
|
|
67
|
+
<Card title="Slack agents" icon="slack" href="/webhooks/slack">
|
|
68
|
+
Turn an agent into a native Slack agent with `@trigger.dev/slack`.
|
|
69
|
+
</Card>
|
|
70
|
+
<Card title="Linear agents" icon="list-check" href="/webhooks/linear">
|
|
71
|
+
Assign Linear issues to an agent with `@trigger.dev/linear`.
|
|
72
|
+
</Card>
|
|
73
|
+
</CardGroup>
|
|
74
|
+
|
|
75
|
+
Version your [prompts](/ai/prompts) in code and change them from the dashboard, and see every model step and tool call, with tokens, cost and latency, in [AI observability](/ai/observability).
|
|
76
|
+
|
|
77
|
+
## Run work
|
|
38
78
|
|
|
39
79
|
<CardGroup cols={2}>
|
|
40
80
|
<Card title="Writing tasks" icon="pen-to-square" href="/tasks/overview" color="#A8FF53">
|
|
41
|
-
The durable functions at the core of Trigger.dev
|
|
81
|
+
The durable functions at the core of Trigger.dev, written in your existing codebase.
|
|
42
82
|
</Card>
|
|
43
83
|
<Card title="Triggering tasks" icon="bullseye-pointer" href="/triggering" color="#3b82f6">
|
|
44
|
-
Trigger a task from your backend, your frontend,
|
|
84
|
+
Trigger a task from your backend, your frontend, or another task.
|
|
45
85
|
</Card>
|
|
46
86
|
<Card title="Runs" icon="play" href="/runs" color="#28bf5c">
|
|
47
|
-
Every execution of a task is a run, with its status, retries, and
|
|
87
|
+
Every execution of a task is a run, with its status, retries, logs and trace.
|
|
88
|
+
</Card>
|
|
89
|
+
<Card title="Realtime" icon="bolt" href="/realtime/overview" color="#F43F5E">
|
|
90
|
+
Stream run status and LLM output to your frontend with React hooks.
|
|
91
|
+
</Card>
|
|
92
|
+
</CardGroup>
|
|
93
|
+
|
|
94
|
+
## React to events
|
|
95
|
+
|
|
96
|
+
<CardGroup cols={2}>
|
|
97
|
+
<Card title="Webhooks" icon="webhook" href="/webhooks/overview" color="#a855f7">
|
|
98
|
+
Hosted, verified endpoints for Stripe, GitHub and more, delivered to your tasks and agents.
|
|
99
|
+
</Card>
|
|
100
|
+
<Card title="Scheduled tasks" icon="clock" href="/tasks/scheduled" color="#f6cd46">
|
|
101
|
+
Run a task on a cron schedule, with timezone support.
|
|
102
|
+
</Card>
|
|
103
|
+
<Card title="Webhook waiters" icon="bell" href="/webhooks/waiters" color="#3b82f6">
|
|
104
|
+
Pause a run until a matching webhook arrives, like a payment confirmation.
|
|
48
105
|
</Card>
|
|
49
|
-
<Card title="
|
|
50
|
-
|
|
106
|
+
<Card title="Waits" icon="hourglass" href="/wait" color="#28bf5c">
|
|
107
|
+
Pause a run for a duration, until a date, or until a token is completed. A waiting run doesn't use compute.
|
|
51
108
|
</Card>
|
|
52
109
|
</CardGroup>
|
|
53
110
|
|
|
54
|
-
##
|
|
111
|
+
## Run in production
|
|
55
112
|
|
|
56
|
-
|
|
113
|
+
<CardGroup cols={2}>
|
|
114
|
+
<Card title="Queues & concurrency" icon="layer-group" href="/queues" color="#3b82f6">
|
|
115
|
+
Control how many runs execute at once, globally or per tenant.
|
|
116
|
+
</Card>
|
|
117
|
+
<Card title="Machines" icon="microchip" href="/machines" color="#a855f7">
|
|
118
|
+
Choose the CPU and memory each task runs on.
|
|
119
|
+
</Card>
|
|
120
|
+
<Card title="Deployment" icon="cloud-arrow-up" href="/deployment/overview" color="#28bf5c">
|
|
121
|
+
Atomic, versioned deploys, with preview branches and environments.
|
|
122
|
+
</Card>
|
|
123
|
+
<Card title="Errors & retries" icon="arrows-rotate" href="/errors-retrying" color="#F43F5E">
|
|
124
|
+
Retry failed attempts automatically, and decide what happens when a task throws.
|
|
125
|
+
</Card>
|
|
126
|
+
<Card title="Logs, traces & metrics" icon="chart-line" href="/logging" color="#f6cd46">
|
|
127
|
+
A full trace of every run, with your logs and spans.
|
|
128
|
+
</Card>
|
|
129
|
+
<Card title="Query & dashboards" icon="table" href="/observability/query" color="#A8FF53">
|
|
130
|
+
Query your runs with TRQL, and build dashboards from the results.
|
|
131
|
+
</Card>
|
|
132
|
+
</CardGroup>
|
|
57
133
|
|
|
58
|
-
##
|
|
134
|
+
## Frequently asked questions
|
|
59
135
|
|
|
60
|
-
|
|
136
|
+
**Can I use Trigger.dev for background jobs, not just AI?** Yes. The same durable tasks, queues, retries, and [cron schedules](/tasks/scheduled) run any background job or workflow, with or without AI.
|
|
61
137
|
|
|
62
|
-
|
|
138
|
+
**How long can a run take?** As long as it needs. Runs have no maximum duration by default, and you can set a [`maxDuration`](/runs/max-duration) for a project, a task, or a single run to cap it.
|
|
63
139
|
|
|
64
|
-
Trigger.dev
|
|
140
|
+
**Do my serverless function timeouts apply?** No. Tasks run on Trigger.dev, not inside your serverless functions, so your platform's function timeout isn't in the execution path. Your backend triggers the task and returns.
|
|
65
141
|
|
|
66
|
-
|
|
142
|
+
**Can I receive webhooks without running a server?** Yes. Declare a [webhook endpoint](/webhooks/overview) in your code, and Trigger.dev hosts its URL, verifies each request, and delivers the event to your tasks and agents.
|
|
67
143
|
|
|
68
|
-
**How do I add human-in-the-loop approval
|
|
144
|
+
**How do I add human-in-the-loop approval?** Pause the run on a [waitpoint](/wait-for-token) until a person approves, or use a [chat agent's approvals](/ai-chat/patterns/human-in-the-loop) for tool calls. A waiting run doesn't use compute, so it can wait minutes or days.
|
|
69
145
|
|
|
70
146
|
**Does Trigger.dev support tool calling and MCP?** Yes. Agents call the tools you define, and the [MCP server](/building-with-ai) lets AI coding assistants trigger tasks, deploy, and read run traces.
|
|
71
147
|
|
|
72
|
-
**Can I
|
|
148
|
+
**Can I self-host?** Yes. Trigger.dev is open source. Read the [self-hosting overview](/self-hosting/overview), or set it up with [Docker](/self-hosting/docker) or [Kubernetes](/self-hosting/kubernetes).
|
|
73
149
|
|
|
74
150
|
## Getting help
|
|
75
151
|
|
|
@@ -85,7 +161,7 @@ We'd love to hear from you or give you a hand getting started. Here are some way
|
|
|
85
161
|
Our Discord is the best place to get help with any questions about Trigger.dev.
|
|
86
162
|
</Card>
|
|
87
163
|
<Card
|
|
88
|
-
title="Follow us on X
|
|
164
|
+
title="Follow us on X"
|
|
89
165
|
icon={
|
|
90
166
|
<svg xmlns="http://www.w3.org/2000/svg" height="20" viewBox="0 0 512 512">
|
|
91
167
|
<path d="M389.2 48h70.6L305.6 224.2 487 464H345L233.7 318.6 106.5 464H35.8L200.7 275.5 26.8 48H172.4L272.9 180.9 389.2 48zM364.4 421.8h39.1L151.1 88h-42L364.4 421.8z" />
|
|
@@ -112,7 +188,7 @@ We'd love to hear from you or give you a hand getting started. Here are some way
|
|
|
112
188
|
href="https://github.com/triggerdotdev/trigger.dev"
|
|
113
189
|
color="#fbbf24"
|
|
114
190
|
>
|
|
115
|
-
Check
|
|
191
|
+
Check out our GitHub repo, and give us a star if you like what we're doing.
|
|
116
192
|
</Card>
|
|
117
193
|
</CardGroup>
|
|
118
194
|
|
|
@@ -122,12 +198,16 @@ We'd love to hear from you or give you a hand getting started. Here are some way
|
|
|
122
198
|
|
|
123
199
|
**Current major version:** v4 (`@trigger.dev/sdk` 4.x). Documentation under `/docs/v2` and `/docs/v3` describes superseded versions and should not be used.
|
|
124
200
|
|
|
125
|
-
**Execution model:** tasks run on Trigger.dev infrastructure, not inside your serverless functions, so a platform function timeout is not in the execution path.
|
|
201
|
+
**Execution model:** tasks run on Trigger.dev infrastructure, not inside your serverless functions, so a platform function timeout is not in the execution path. Runs have no maximum duration by default; `maxDuration` caps a run's compute time for a project, a task, or a single run, and `timeout.None` removes the cap.
|
|
126
202
|
|
|
127
203
|
**Deploys:** each deploy is an atomic version. A run already in progress is not affected by code shipped after it started.
|
|
128
204
|
|
|
129
205
|
**Durability and retries:** retries are automatic and configurable. A failed attempt is retried according to the task's retry settings; once retries are exhausted the run ends terminally as `FAILED`, and some crashes (for example out of memory) end the run as `CRASHED` without a retry. Idempotency keys deduplicate the task triggers and waits you key, so the same key runs once instead of again.
|
|
130
206
|
|
|
207
|
+
**Agents:** `chat.agent` is imported from `@trigger.dev/sdk/ai`, not from `@trigger.dev/sdk`. Inside `run()`, call the `streamText` passed in the run options. It records each model step and tool call as a span by default. Slack and Linear agents use the `@trigger.dev/slack` and `@trigger.dev/linear` packages, and `slack()` requires a `startOn` filter (`appMentions()` answers @mentions).
|
|
208
|
+
|
|
209
|
+
**Webhooks:** `webhooks.endpoint.define()` declares a hosted, verified endpoint that syncs on `trigger dev` and on deploy; `webhook()` subscribes a task with a filter, and `webhooks.waiter` pauses a run until a matching event arrives. Both come from `@trigger.dev/sdk`.
|
|
210
|
+
|
|
131
211
|
**License:** the platform core is Apache-2.0 and the `@trigger.dev/sdk` package is MIT, permissive open source, not fair-code or source-available. Some features are gated, but the open source core is not relicensed or held back.
|
|
132
212
|
|
|
133
213
|
**LLM observability coverage:** only Vercel AI SDK calls (`generateText`, `streamText`, `generateObject`) are recorded as spans. Raw `fetch` calls and provider SDKs used directly are not captured.
|
package/docs/mcp-tools.mdx
CHANGED
|
@@ -411,6 +411,10 @@ Generate a new signing secret for an endpoint and return it once, for providers
|
|
|
411
411
|
|
|
412
412
|
**Parameters:**
|
|
413
413
|
- `endpointId` (required): the endpoint's declared id (such as `payments`) or `wh_` id
|
|
414
|
+
- `previousSecretTtlSeconds` (optional): keep accepting the replaced secret for this many seconds (up to 604800, 7 days) while the provider switches to the new one. Omit it, or pass `0`, to replace the secret immediately, for example when it leaked. The response says when the old secret stops working.
|
|
415
|
+
|
|
416
|
+
**Example usage:**
|
|
417
|
+
- `"Rotate the GitHub endpoint's secret and keep the old one working for a day"`
|
|
414
418
|
|
|
415
419
|
### set_webhook_secret
|
|
416
420
|
|
|
@@ -419,6 +423,7 @@ Store a signing secret or public key the provider issued, such as Stripe's `whse
|
|
|
419
423
|
**Parameters:**
|
|
420
424
|
- `endpointId` (required): the endpoint's declared id (such as `payments`) or `wh_` id
|
|
421
425
|
- `secret` (required): the secret or public key
|
|
426
|
+
- `previousSecretTtlSeconds` (optional): keep accepting the replaced secret for this many seconds (up to 604800, 7 days) while the provider switches to the new one. Omit it, or pass `0`, to replace the secret immediately, for example when it leaked. The response says when the old secret stops working.
|
|
422
427
|
|
|
423
428
|
<Callout type="warning">
|
|
424
429
|
`replay_webhook_delivery`, `generate_webhook_secret` and `set_webhook_secret` are write operations and are not available in readonly mode.
|
|
@@ -52,6 +52,7 @@ mode: "wide"
|
|
|
52
52
|
| `KUBERNETES_IMAGE_PULL_SECRETS` | No | — | Image pull secrets (CSV). |
|
|
53
53
|
| `KUBERNETES_EPHEMERAL_STORAGE_SIZE_LIMIT` | No | 10Gi | Ephemeral storage size limit. Applies to all runs. |
|
|
54
54
|
| `KUBERNETES_EPHEMERAL_STORAGE_SIZE_REQUEST` | No | 2Gi | Ephemeral storage size request. Applies to all runs. |
|
|
55
|
+
| `KUBERNETES_POD_RESERVED_SOURCE_PORTS` | No | — | Ports runs never use as the source port of an outbound connection, so they can't clash with services on those ports. CSV of ports or ranges, e.g. `50080,50081` or `50080-50090`. Sets the pod's `net.ipv4.ip_local_reserved_ports` sysctl. |
|
|
55
56
|
| **Metrics** | | | |
|
|
56
57
|
| `METRICS_ENABLED` | No | true | Enable metrics. |
|
|
57
58
|
| `METRICS_COLLECT_DEFAULTS` | No | true | Collect default metrics. |
|
|
@@ -192,6 +192,18 @@ mode: "wide"
|
|
|
192
192
|
| `RUN_ENGINE_DEFAULT_MAX_TTL` | No | — | Maximum TTL for all runs (e.g. "14d"). Runs without a TTL use this as default; runs with a larger TTL are clamped. |
|
|
193
193
|
| `MAXIMUM_DEV_QUEUE_SIZE` | No | — | Maximum queued runs per queue in development environments. |
|
|
194
194
|
| `MAXIMUM_DEPLOYED_QUEUE_SIZE` | No | — | Maximum queued runs per queue in deployed (staging/prod) environments. |
|
|
195
|
+
| **Webhooks** | | | |
|
|
196
|
+
| `WEBHOOK_ENABLED` | No | 0 | Set to `1` to run hosted webhooks: ingest, delivery and waiters. See [Webhooks](#webhooks). |
|
|
197
|
+
| `WEBHOOK_REDIS_HOST` | No | localhost | A node of the Redis cluster webhooks use for their queue and waiters. It must run in cluster mode. |
|
|
198
|
+
| `WEBHOOK_REDIS_PORT` | No | 6379 | Port of that node. |
|
|
199
|
+
| `WEBHOOK_REDIS_USERNAME` | No | — | Webhooks Redis username. |
|
|
200
|
+
| `WEBHOOK_REDIS_PASSWORD` | No | — | Webhooks Redis password. |
|
|
201
|
+
| `WEBHOOK_REDIS_TLS_DISABLED` | No | `REDIS_TLS_DISABLED` | Set to `true` to connect to the webhooks Redis without TLS. |
|
|
202
|
+
| `WEBHOOK_INGRESS_ORIGIN` | No | `API_ORIGIN` | Public origin of the webhook URLs, for when you serve them from their own host. |
|
|
203
|
+
| `WEBHOOK_INGRESS_BODY_SIZE_LIMIT_MB` | No | 1 | Largest webhook request body accepted, in MB. |
|
|
204
|
+
| `WEBHOOK_DATABASE_URL` | No | `DATABASE_URL` | A separate PostgreSQL database for webhook endpoints and deliveries. |
|
|
205
|
+
| `WEBHOOK_DELIVERY_RETENTION_DAYS` | No | 30 | How many days of deliveries the dashboard and API show. It doesn't delete anything: deliveries are kept for `WEBHOOK_DELIVERY_STORAGE_DAYS`, or longer when this is higher. |
|
|
206
|
+
| `WEBHOOK_DELIVERY_STORAGE_DAYS` | No | 30 | How long deliveries are stored before they're deleted. Must be one of `3`, `7`, `30`, `90`, `180` or `365`; any other value stops the webapp from starting. |
|
|
195
207
|
| **Misc** | | | |
|
|
196
208
|
| `TRIGGER_TELEMETRY_DISABLED` | No | — | Disable telemetry. |
|
|
197
209
|
| `NODE_MAX_OLD_SPACE_SIZE` | No | 8192 | Maximum memory allocation for Node.js heap in MiB (e.g. "4096" for 4GB). |
|
|
@@ -202,6 +214,18 @@ mode: "wide"
|
|
|
202
214
|
| `ADMIN_DASHBOARD_ENABLED` | No | 1 | Set to anything other than `1` or `true` to disable the admin dashboard and user impersonation on this instance. |
|
|
203
215
|
| `EVENT_LOOP_MONITOR_ENABLED` | No | 1 | Node.js event loop lag monitor. |
|
|
204
216
|
|
|
217
|
+
## Webhooks
|
|
218
|
+
|
|
219
|
+
Hosted webhooks are off on a self-hosted instance until you turn them on:
|
|
220
|
+
|
|
221
|
+
1. Run a Redis (or Valkey) cluster for webhooks and point `WEBHOOK_REDIS_HOST` and `WEBHOOK_REDIS_PORT` at one of its nodes. The webhook engine connects in cluster mode, so a standalone Redis won't work.
|
|
222
|
+
2. Set `WEBHOOK_ENABLED=1` on the webapp.
|
|
223
|
+
3. Give organizations access with the `hasWebhooksAccess` feature flag: turn it on for everyone on the admin dashboard's **Global Feature Flags** page, or for one organization from its feature flags on the **Organizations** page. An organization without it doesn't see Webhooks in the dashboard, and its deploys don't sync endpoints.
|
|
224
|
+
|
|
225
|
+
Webhook URLs are served from `WEBHOOK_INGRESS_ORIGIN`, which defaults to `API_ORIGIN`, so providers need to reach that origin from the internet.
|
|
226
|
+
|
|
227
|
+
The Docker Compose setup only passes the variables listed under the webapp service's `environment` in `hosting/docker/webapp/docker-compose.yml`, so add the webhook variables there. With the Helm chart, set them in `webapp.extraEnvVars`.
|
|
228
|
+
|
|
205
229
|
## Multi-Provider Object Storage
|
|
206
230
|
|
|
207
231
|
The object storage system supports multiple S3-compatible providers (R2, S3, GCS, MinIO, etc.) using protocol prefixes. This enables migrating between providers without breaking existing runs.
|
|
@@ -121,6 +121,8 @@ You own a custom base image. It must provide:
|
|
|
121
121
|
|
|
122
122
|
A `DEPLOY_BUILD_BASE_IMAGES` image needs everything the base image provides, plus `python3`, `make` and `g++`. Build extensions that add image instructions are replayed on it. Without an entry, the build stage uses the published build image, except for projects whose build extensions add image instructions: those build from your base image and install the toolchain with `apt-get`, so that base must be Debian-based. To avoid the published images entirely, set both variables.
|
|
123
123
|
|
|
124
|
+
A custom image is yours to harden. Deploys on the published images remove trust in publicly compromised certificate authorities and point Node.js and Python at the OS trust store. Stages built on a custom image get neither, and run with the certificate settings the image ships with. Keeping a custom image patched, trust store included, is your responsibility.
|
|
125
|
+
|
|
124
126
|
<Warning>
|
|
125
127
|
`image.pkgs` and build extensions that run `apt-get` (such as `aptGet` and `playwright`) assume a
|
|
126
128
|
Debian base. On other distributions, install those packages in your base image instead.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trigger.dev/sdk",
|
|
3
|
-
"version": "4.8.
|
|
3
|
+
"version": "4.8.1",
|
|
4
4
|
"description": "trigger.dev Node.JS SDK",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
"dependencies": {
|
|
70
70
|
"@opentelemetry/api": "1.9.1",
|
|
71
71
|
"@opentelemetry/semantic-conventions": "1.41.1",
|
|
72
|
-
"@trigger.dev/core": "4.8.
|
|
72
|
+
"@trigger.dev/core": "4.8.1",
|
|
73
73
|
"uncrypto": "^0.1.3"
|
|
74
74
|
},
|
|
75
75
|
"devDependencies": {
|