@trigger.dev/sdk 0.0.0-prerelease-20260909071038 → 0.0.0-prerelease-streamfix-20260909094302
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commonjs/imports/ai-runtime-cjs.cjs.map +1 -1
- package/dist/commonjs/imports/ai-runtime.js +0 -2
- package/dist/commonjs/v3/ai-shared.d.ts +0 -15
- package/dist/commonjs/v3/ai-shared.js +1 -35
- package/dist/commonjs/v3/ai-shared.js.map +1 -1
- package/dist/commonjs/v3/ai.d.ts +25 -275
- package/dist/commonjs/v3/ai.js +308 -1283
- package/dist/commonjs/v3/ai.js.map +1 -1
- package/dist/commonjs/v3/chat-client.d.ts +2 -11
- package/dist/commonjs/v3/chat-client.js +111 -227
- package/dist/commonjs/v3/chat-client.js.map +1 -1
- package/dist/commonjs/v3/chat-react.d.ts +0 -88
- package/dist/commonjs/v3/chat-react.js +1 -130
- package/dist/commonjs/v3/chat-react.js.map +1 -1
- package/dist/commonjs/v3/chat-server.d.ts +6 -42
- package/dist/commonjs/v3/chat-server.js +7 -52
- package/dist/commonjs/v3/chat-server.js.map +1 -1
- package/dist/commonjs/v3/chat.d.ts +10 -92
- package/dist/commonjs/v3/chat.js +73 -328
- package/dist/commonjs/v3/chat.js.map +1 -1
- package/dist/commonjs/v3/sessions.d.ts +2 -15
- package/dist/commonjs/v3/sessions.js +1 -12
- package/dist/commonjs/v3/sessions.js.map +1 -1
- package/dist/commonjs/v3/shared.js +36 -30
- package/dist/commonjs/v3/shared.js.map +1 -1
- package/dist/commonjs/v3/test/index.d.ts +0 -1
- package/dist/commonjs/v3/test/index.js +1 -3
- package/dist/commonjs/v3/test/index.js.map +1 -1
- package/dist/commonjs/v3/test/mock-chat-agent.d.ts +4 -47
- package/dist/commonjs/v3/test/mock-chat-agent.js +4 -115
- package/dist/commonjs/v3/test/mock-chat-agent.js.map +1 -1
- package/dist/commonjs/v3/test/test-session-handle.js +0 -6
- package/dist/commonjs/v3/test/test-session-handle.js.map +1 -1
- package/dist/commonjs/version.js +1 -1
- package/dist/esm/imports/ai-runtime.d.ts +2 -2
- package/dist/esm/imports/ai-runtime.js +2 -2
- package/dist/esm/imports/ai-runtime.js.map +1 -1
- package/dist/esm/v3/ai-shared.d.ts +0 -15
- package/dist/esm/v3/ai-shared.js +0 -33
- package/dist/esm/v3/ai-shared.js.map +1 -1
- package/dist/esm/v3/ai.d.ts +25 -275
- package/dist/esm/v3/ai.js +305 -1275
- package/dist/esm/v3/ai.js.map +1 -1
- package/dist/esm/v3/chat-client.d.ts +2 -11
- package/dist/esm/v3/chat-client.js +112 -228
- package/dist/esm/v3/chat-client.js.map +1 -1
- package/dist/esm/v3/chat-react.d.ts +0 -88
- package/dist/esm/v3/chat-react.js +1 -127
- package/dist/esm/v3/chat-react.js.map +1 -1
- package/dist/esm/v3/chat-server.d.ts +6 -42
- package/dist/esm/v3/chat-server.js +8 -53
- package/dist/esm/v3/chat-server.js.map +1 -1
- package/dist/esm/v3/chat.d.ts +10 -92
- package/dist/esm/v3/chat.js +74 -329
- package/dist/esm/v3/chat.js.map +1 -1
- package/dist/esm/v3/sessions.d.ts +2 -15
- package/dist/esm/v3/sessions.js +1 -11
- package/dist/esm/v3/sessions.js.map +1 -1
- package/dist/esm/v3/shared.js +23 -17
- package/dist/esm/v3/shared.js.map +1 -1
- package/dist/esm/v3/test/index.d.ts +0 -1
- package/dist/esm/v3/test/index.js +0 -1
- package/dist/esm/v3/test/index.js.map +1 -1
- package/dist/esm/v3/test/mock-chat-agent.d.ts +4 -47
- package/dist/esm/v3/test/mock-chat-agent.js +6 -117
- package/dist/esm/v3/test/mock-chat-agent.js.map +1 -1
- package/dist/esm/v3/test/test-session-handle.js +0 -6
- package/dist/esm/v3/test/test-session-handle.js.map +1 -1
- package/dist/esm/version.js +1 -1
- package/docs/ai-chat/actions.mdx +23 -55
- package/docs/ai-chat/anatomy.mdx +3 -3
- package/docs/ai-chat/backend.mdx +48 -125
- package/docs/ai-chat/background-injection.mdx +19 -69
- package/docs/ai-chat/client-protocol.mdx +4 -5
- package/docs/ai-chat/compaction.mdx +7 -13
- package/docs/ai-chat/custom-agents.mdx +0 -23
- package/docs/ai-chat/fast-starts.mdx +20 -27
- package/docs/ai-chat/frontend.mdx +14 -19
- package/docs/ai-chat/lifecycle-hooks.mdx +2 -6
- package/docs/ai-chat/migrating-from-a-route-handler.mdx +14 -16
- package/docs/ai-chat/patterns/database-persistence.mdx +2 -6
- package/docs/ai-chat/patterns/persistence-and-replay.mdx +23 -34
- package/docs/ai-chat/patterns/skills.mdx +10 -7
- package/docs/ai-chat/patterns/version-upgrades.mdx +6 -79
- package/docs/ai-chat/pending-messages.mdx +3 -3
- package/docs/ai-chat/prompt-caching.mdx +25 -23
- package/docs/ai-chat/quick-start.mdx +11 -11
- package/docs/ai-chat/reference.mdx +9 -67
- package/docs/ai-chat/sessions.mdx +1 -6
- package/docs/ai-chat/testing.mdx +1 -2
- package/docs/ai-chat/tools.mdx +13 -18
- package/docs/ai-chat/upgrade-guide.mdx +2 -2
- package/docs/apikeys.mdx +45 -27
- package/docs/config/extensions/syncEnvVars.mdx +0 -6
- package/docs/deploy-environment-variables.mdx +2 -23
- package/docs/deployment/overview.mdx +8 -4
- package/docs/deployment/preview-branches.mdx +4 -4
- package/docs/deployment/version-skew-protection.mdx +0 -62
- package/docs/manual-setup.mdx +7 -7
- package/docs/mcp-tools.mdx +0 -9
- package/docs/quick-start.mdx +3 -3
- package/docs/realtime/auth.mdx +1 -1
- package/docs/self-hosting/security.mdx +0 -5
- package/docs/tasks/scheduled.mdx +0 -24
- package/docs/triggering.mdx +1 -1
- package/package.json +4 -4
- package/skills/trigger-authoring-chat-agent/SKILL.md +29 -41
- package/skills/trigger-chat-agent-advanced/SKILL.md +12 -31
- package/dist/commonjs/v3/chatSnapshotIo.d.ts +0 -2
- package/dist/commonjs/v3/chatSnapshotIo.js +0 -174
- package/dist/commonjs/v3/chatSnapshotIo.js.map +0 -1
- package/dist/commonjs/v3/chatVersionSkew.d.ts +0 -12
- package/dist/commonjs/v3/chatVersionSkew.js +0 -30
- package/dist/commonjs/v3/chatVersionSkew.js.map +0 -1
- package/dist/commonjs/v3/externalDeploymentId.d.ts +0 -23
- package/dist/commonjs/v3/externalDeploymentId.js +0 -43
- package/dist/commonjs/v3/externalDeploymentId.js.map +0 -1
- package/dist/commonjs/v3/test/transcript-storage-tests.d.ts +0 -40
- package/dist/commonjs/v3/test/transcript-storage-tests.js +0 -258
- package/dist/commonjs/v3/test/transcript-storage-tests.js.map +0 -1
- package/dist/commonjs/v3/transcriptStorage.d.ts +0 -229
- package/dist/commonjs/v3/transcriptStorage.js +0 -321
- package/dist/commonjs/v3/transcriptStorage.js.map +0 -1
- package/dist/esm/v3/chatSnapshotIo.d.ts +0 -2
- package/dist/esm/v3/chatSnapshotIo.js +0 -166
- package/dist/esm/v3/chatSnapshotIo.js.map +0 -1
- package/dist/esm/v3/chatVersionSkew.d.ts +0 -12
- package/dist/esm/v3/chatVersionSkew.js +0 -27
- package/dist/esm/v3/chatVersionSkew.js.map +0 -1
- package/dist/esm/v3/externalDeploymentId.d.ts +0 -23
- package/dist/esm/v3/externalDeploymentId.js +0 -38
- package/dist/esm/v3/externalDeploymentId.js.map +0 -1
- package/dist/esm/v3/test/transcript-storage-tests.d.ts +0 -40
- package/dist/esm/v3/test/transcript-storage-tests.js +0 -255
- package/dist/esm/v3/test/transcript-storage-tests.js.map +0 -1
- package/dist/esm/v3/transcriptStorage.d.ts +0 -229
- package/dist/esm/v3/transcriptStorage.js +0 -309
- package/dist/esm/v3/transcriptStorage.js.map +0 -1
- package/docs/ai-chat/patterns/native-compaction.mdx +0 -310
- package/docs/ai-chat/transcript-storage.mdx +0 -233
- package/docs/reports.mdx +0 -157
- package/docs/troubleshooting-zod.mdx +0 -158
|
@@ -276,68 +276,6 @@ An empty or whitespace-only value counts as "not supplied" rather than an error,
|
|
|
276
276
|
|
|
277
277
|
Batch triggers carry the id too. `batchTrigger` resolves it per item exactly as `trigger` does, and it survives the asynchronous materialisation of batch items — so a large batch triggered during a deploy waits and releases item by item, each pinned to the deployment its calling code came from.
|
|
278
278
|
|
|
279
|
-
## Chat sessions
|
|
280
|
-
|
|
281
|
-
[Chat agents](/ai-chat/overview) are covered by the same mechanism, with one difference: the id belongs to the **session**, not to a single trigger. It is resolved wherever you start the session — your server action, your route handler, `sessions.start()` — using the same order of precedence as a task trigger, and stored on the session. Every run that session goes on to schedule carries it: the first run, each continuation after an idle suspend, and each recovery after a crash.
|
|
282
|
-
|
|
283
|
-
That is what you want for a conversation. A chat started by one release of your app keeps talking to the agent build that release shipped with, however many turns and however many runs that takes.
|
|
284
|
-
|
|
285
|
-
Chats need the same two halves as tasks, and no more: a deployment carrying an id, and an app that sends the same one (explicitly, through `TRIGGER_EXTERNAL_DEPLOYMENT_ID`, or through [automatic discovery](#automatic-discovery)). There is nothing chat-specific to switch on, so an app already pinning its task runs gets pinned chats with no code change.
|
|
286
|
-
|
|
287
|
-
```ts
|
|
288
|
-
// app/actions.ts
|
|
289
|
-
"use server";
|
|
290
|
-
import { chat } from "@trigger.dev/sdk/ai";
|
|
291
|
-
import type { myChat } from "@/trigger/chat";
|
|
292
|
-
|
|
293
|
-
// No chat-specific setup: the id is discovered per call, exactly as it is for `trigger()`.
|
|
294
|
-
export const startChatSession = chat.createStartSessionAction<typeof myChat>("my-chat");
|
|
295
|
-
```
|
|
296
|
-
|
|
297
|
-
Three things follow from the pin living on the session:
|
|
298
|
-
|
|
299
|
-
- **Starting the session again refreshes it, and the conversation follows.** `sessions.start()` is idempotent on `chatId` and rewrites the stored config, so when your transport calls `startSession` after a redeploy, the session re-pins. A **running** agent then hands the conversation over at the next turn boundary, so the next message is answered by the deployment you just named — not several turns later when the old run happens to end. The turn already in flight finishes on the code it started on. Set [`versionSkew: "hold"`](/ai-chat/patterns/version-upgrades#staying-put) on an agent that should stay put instead.
|
|
300
|
-
- **There is one pin per `chatId`.** If the same conversation is open in two tabs on two different releases of your app, whichever called `startSession` most recently sets the pin for both.
|
|
301
|
-
- **A parked chat is waiting, not broken.** A run pinned to a deployment that hasn't landed parks, and every message sent meanwhile is stored durably and delivered once the deployment arrives. Nothing is lost — but nothing answers either, so tell the user. Re-pinning does not release a parked run: it keeps waiting for the deployment it was created for. If that deployment never lands, the run waits until its park deadline elapses, and the next message after that starts a fresh run on the session's current pin. Pass `pendingVersion` through your `startSession` callback and the transport emits a `run-pending-version` event:
|
|
302
|
-
|
|
303
|
-
```tsx
|
|
304
|
-
const transport = useTriggerChatTransport({
|
|
305
|
-
task: "my-chat",
|
|
306
|
-
accessToken: ({ chatId }) => mintChatAccessToken(chatId),
|
|
307
|
-
startSession: ({ chatId, clientData }) => startChatSession({ chatId, clientData }),
|
|
308
|
-
onEvent: (event) => {
|
|
309
|
-
if (event.type === "run-pending-version") setDeploying(true);
|
|
310
|
-
if (event.type === "first-chunk") setDeploying(false);
|
|
311
|
-
},
|
|
312
|
-
});
|
|
313
|
-
```
|
|
314
|
-
|
|
315
|
-
The event repeats on every message sent while the chat is parked, so a notice driven off it stays accurate. Its `source` says where the park was learned: `start` from creating the session, `send` from an append, `head-start` from the route's response header, and `upgrade` when a session followed its pin onto a deployment that hasn't landed yet — that last one arrives as soon as the handoff happens, without waiting for another message.
|
|
316
|
-
|
|
317
|
-
[Head Start](/ai-chat/fast-starts#head-start) softens this considerably: turn 1 runs in your own warm process, so a parked deployment costs nothing until step 2. The handover signal is durable, so the agent picks the turn up where it left off once the deployment lands. The transport emits `run-pending-version` with `source: "head-start"` for that case, and `chat.startHeadStart` returns `pendingVersion` for the detached flow.
|
|
318
|
-
|
|
319
|
-
### Opting a chat out
|
|
320
|
-
|
|
321
|
-
Pass `null` and that chat is never pinned, whatever the environment says:
|
|
322
|
-
|
|
323
|
-
```ts
|
|
324
|
-
export const startChatSession = chat.createStartSessionAction<typeof myChat>("my-chat", {
|
|
325
|
-
triggerConfig: { externalDeploymentId: null },
|
|
326
|
-
});
|
|
327
|
-
```
|
|
328
|
-
|
|
329
|
-
Use this for a conversation that should always run on the current version — a long-lived support thread, say — while the rest of your chats stay pinned. To turn pinning off everywhere instead, set `TRIGGER_AUTOMATIC_SKEW_VERSION_PROTECTION` to `0` and don't set `TRIGGER_EXTERNAL_DEPLOYMENT_ID`.
|
|
330
|
-
|
|
331
|
-
### Escaping the pin from inside the agent
|
|
332
|
-
|
|
333
|
-
[`chat.requestUpgrade()`](/ai-chat/patterns/version-upgrades) clears the session's external deployment id as part of the handoff, so the new run is free to land on the current version. Pass a target to move to a specific deployment instead:
|
|
334
|
-
|
|
335
|
-
```ts
|
|
336
|
-
chat.requestUpgrade({ externalDeploymentId: clientData.commitSha });
|
|
337
|
-
```
|
|
338
|
-
|
|
339
|
-
Either way the change is persisted on the session, so the next continuation doesn't fall back to the id the agent just rejected. `lockToVersion` is a separate, explicit pin and is never cleared — `requestUpgrade()` cannot escape it, which is also why a session using it never follows its external deployment id automatically.
|
|
340
|
-
|
|
341
279
|
## Waiting and expiry
|
|
342
280
|
|
|
343
281
|
When a run arrives with an id that isn't deployed yet, it doesn't fail — it **waits**. This is the ordinary case, not an edge case: your app frequently goes live a few seconds before your task build finishes.
|
package/docs/manual-setup.mdx
CHANGED
|
@@ -55,15 +55,15 @@ bun add -D @trigger.dev/build@latest
|
|
|
55
55
|
|
|
56
56
|
## Environment variables
|
|
57
57
|
|
|
58
|
-
For local development,
|
|
58
|
+
For local development, you need to set up the `TRIGGER_SECRET_KEY` environment variable. This key authenticates your application with Trigger.dev.
|
|
59
59
|
|
|
60
|
-
1.
|
|
61
|
-
2.
|
|
62
|
-
3.
|
|
63
|
-
4.
|
|
60
|
+
1. Go to your project dashboard in Trigger.dev
|
|
61
|
+
2. Navigate to the "API Keys" page
|
|
62
|
+
3. Copy the **DEV** secret key
|
|
63
|
+
4. Add it to your local environment file:
|
|
64
64
|
|
|
65
|
-
```bash
|
|
66
|
-
TRIGGER_SECRET_KEY=
|
|
65
|
+
```bash
|
|
66
|
+
TRIGGER_SECRET_KEY=tr_dev_xxxxxxxxxx
|
|
67
67
|
```
|
|
68
68
|
|
|
69
69
|
### Self-hosted instances
|
package/docs/mcp-tools.mdx
CHANGED
|
@@ -189,15 +189,6 @@ Execute a single widget query from a built-in dashboard. Use `list_dashboards` f
|
|
|
189
189
|
- `"Run the total runs widget from the overview dashboard"`
|
|
190
190
|
- `"Show me the LLM cost over time from the AI dashboard"`
|
|
191
191
|
|
|
192
|
-
### get_report
|
|
193
|
-
|
|
194
|
-
Render an interpreted [health report](/reports) — a deterministic verdict, not a raw panel — as text with sparklines. The `health` report answers whether work is flowing, whether the runs that start are healthy, and whether the telemetry is fresh, with a headline verdict and a suggested next action. Returns markdown by default, or ANSI when `color` is set. Read-only.
|
|
195
|
-
|
|
196
|
-
**Example usage:**
|
|
197
|
-
- `"Is my production project healthy?"`
|
|
198
|
-
- `"Run the health report for the last 24 hours"`
|
|
199
|
-
- `"Why are my runs backing up?"`
|
|
200
|
-
|
|
201
192
|
## Dev Server Tools
|
|
202
193
|
|
|
203
194
|
### start_dev_server
|
package/docs/quick-start.mdx
CHANGED
|
@@ -26,7 +26,7 @@ Help me add Trigger.dev to this project.
|
|
|
26
26
|
- Install the "Hello World" example task when prompted.
|
|
27
27
|
3. Run `npx trigger.dev@latest dev` to start the dev server.
|
|
28
28
|
4. Once the dev server is running, test the example task from the Trigger.dev dashboard.
|
|
29
|
-
5.
|
|
29
|
+
5. Set TRIGGER_SECRET_KEY in my .env file (or .env.local for Next.js). I can find it on the API Keys page in the dashboard.
|
|
30
30
|
6. Ask me what framework I'm using and show me how to trigger the task from my backend code.
|
|
31
31
|
|
|
32
32
|
If I've already run init and want the MCP server, run: npx trigger.dev@latest install-mcp
|
|
@@ -70,10 +70,10 @@ Sign up at [Trigger.dev Cloud](https://cloud.trigger.dev) (or [self-host](/self-
|
|
|
70
70
|
|
|
71
71
|
## Triggering tasks from your app
|
|
72
72
|
|
|
73
|
-
The test page in the dashboard
|
|
73
|
+
The test page in the dashboard is great for verifying your task works. To trigger tasks from your own code, you'll need to set the `TRIGGER_SECRET_KEY` environment variable. Grab it from the API Keys page in the dashboard and add it to your `.env` file.
|
|
74
74
|
|
|
75
75
|
```bash .env
|
|
76
|
-
TRIGGER_SECRET_KEY=
|
|
76
|
+
TRIGGER_SECRET_KEY=tr_dev_...
|
|
77
77
|
```
|
|
78
78
|
|
|
79
79
|
See [Triggering](/triggering) for the full guide, or jump straight to framework-specific setup for [Next.js](/guides/frameworks/nextjs), [Remix](/guides/frameworks/remix), or [Node.js](/guides/frameworks/nodejs).
|
package/docs/realtime/auth.mdx
CHANGED
|
@@ -131,7 +131,7 @@ const publicToken = await auth.createPublicToken({
|
|
|
131
131
|
- If `expirationTime` is a number, it will be treated as a Unix timestamp in **seconds**
|
|
132
132
|
- If `expirationTime` is a `Date`, it will be treated as a date
|
|
133
133
|
|
|
134
|
-
|
|
134
|
+
When using non-root API keys (recommended), the expiration cannot be more than 30 days in the future.
|
|
135
135
|
|
|
136
136
|
The format used for a time span is the same as the [jose package](https://github.com/panva/jose), which is a number followed by a unit. Valid units are: "sec", "secs", "second", "seconds", "s", "minute", "minutes", "min", "mins", "m", "hour", "hours", "hr", "hrs", "h", "day", "days", "d", "week", "weeks", "w", "year", "years", "yr", "yrs", and "y". It is not possible to specify months. 365.25 days is used as an alias for a year. If the string is suffixed with "ago", or prefixed with a "-", the resulting time span gets subtracted from the current unix timestamp. A "from now" suffix can also be used for readability when adding to the current unix timestamp.
|
|
137
137
|
|
|
@@ -6,11 +6,6 @@ sidebarTitle: "Security"
|
|
|
6
6
|
|
|
7
7
|
We take the security of Trigger.dev seriously, for both Cloud and self-hosted deployments. This page covers how to report a vulnerability, what to expect, and how to stay informed about security releases.
|
|
8
8
|
|
|
9
|
-
<Note>
|
|
10
|
-
Unlike Trigger.dev Cloud, the self-hosted setup is optimized for single-tenant use, with code and
|
|
11
|
-
users you trust. It is not designed to run untrusted code or untrusted payloads.
|
|
12
|
-
</Note>
|
|
13
|
-
|
|
14
9
|
<Warning>
|
|
15
10
|
Do not report security vulnerabilities through public GitHub issues, pull requests, or Discord. Use one of the private channels below.
|
|
16
11
|
</Warning>
|
package/docs/tasks/scheduled.mdx
CHANGED
|
@@ -184,30 +184,6 @@ const createdSchedule = await schedules.create({
|
|
|
184
184
|
is the assigned time the run will actually start.
|
|
185
185
|
</Note>
|
|
186
186
|
|
|
187
|
-
### Free-plan minimum window
|
|
188
|
-
|
|
189
|
-
Schedules created while an organization is on a free plan run no more than once per hour and use a minimum 60-minute window.
|
|
190
|
-
|
|
191
|
-
- The minimum applies to the **cron cadence**: creating or deploying a schedule whose cron fires more often than once an hour is rejected with an actionable error. Change the cron expression or upgrade before saving.
|
|
192
|
-
- Omitted, zero (`"0m"` / `"0%"`), or smaller windows are treated as the 60-minute minimum. A larger configured window still wins, subject to the usual cap at the next cron occurrence.
|
|
193
|
-
- The policy applies to **all environment types**, including Development.
|
|
194
|
-
- It is captured when the schedule is created. Existing schedules — and schedules created while paid, even after a later downgrade — are **grandfathered** and keep running unchanged.
|
|
195
|
-
- Upgrading does not immediately rewrite existing schedules. A free-created restriction is cleared the next time the schedule is saved (imperative/dashboard) or redeployed (declarative) while the organization is paying.
|
|
196
|
-
- No runs are ever skipped or coalesced: unsupported high-frequency schedules are rejected at create/update time rather than silently thinned out.
|
|
197
|
-
- Self-hosted deployments, and any case where the billing plan can't be determined, are unrestricted.
|
|
198
|
-
|
|
199
|
-
When a schedule is subject to this policy, the API returns an `appliedSchedulePolicy` object alongside the configured `window`:
|
|
200
|
-
|
|
201
|
-
```json
|
|
202
|
-
{
|
|
203
|
-
"window": "0m",
|
|
204
|
-
"appliedSchedulePolicy": {
|
|
205
|
-
"minimumWindowSeconds": 3600,
|
|
206
|
-
"reason": "free_schedule"
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
```
|
|
210
|
-
|
|
211
187
|
## Supported cron syntax
|
|
212
188
|
|
|
213
189
|
```
|
package/docs/triggering.mdx
CHANGED
|
@@ -27,7 +27,7 @@ Trigger tasks **from inside a another task**:
|
|
|
27
27
|
|
|
28
28
|
## Triggering from your backend
|
|
29
29
|
|
|
30
|
-
When you trigger a task from your backend code,
|
|
30
|
+
When you trigger a task from your backend code, you need to set the `TRIGGER_SECRET_KEY` environment variable. If you're [using a preview branch](/deployment/preview-branches), you also need to set the `TRIGGER_PREVIEW_BRANCH` environment variable. You can find the value on the API keys page in the Trigger.dev dashboard. [More info on API keys](/apikeys).
|
|
31
31
|
|
|
32
32
|
If a single process needs to trigger across multiple projects, environments, or preview branches, use [`new TriggerClient({...})`](/management/multiple-clients) for each target instead of relying on the global env vars.
|
|
33
33
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trigger.dev/sdk",
|
|
3
|
-
"version": "0.0.0-prerelease-
|
|
3
|
+
"version": "0.0.0-prerelease-streamfix-20260909094302",
|
|
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": "0.0.0-prerelease-
|
|
72
|
+
"@trigger.dev/core": "0.0.0-prerelease-streamfix-20260909094302",
|
|
73
73
|
"uncrypto": "^0.1.3"
|
|
74
74
|
},
|
|
75
75
|
"devDependencies": {
|
|
@@ -82,13 +82,13 @@
|
|
|
82
82
|
"tshy": "^4.1.3",
|
|
83
83
|
"tsx": "4.17.0",
|
|
84
84
|
"typescript": "7.0.2",
|
|
85
|
-
"zod": "
|
|
85
|
+
"zod": "3.25.76"
|
|
86
86
|
},
|
|
87
87
|
"peerDependencies": {
|
|
88
88
|
"@ai-sdk/otel": ">=1.0.0-0 <2",
|
|
89
89
|
"ai": "^5.0.0 || ^6.0.0 || >=7.0.0-canary <8",
|
|
90
90
|
"react": "^18.0 || ^19.0",
|
|
91
|
-
"zod": "^3.
|
|
91
|
+
"zod": "^3.0.0 || ^4.0.0"
|
|
92
92
|
},
|
|
93
93
|
"peerDependenciesMeta": {
|
|
94
94
|
"@ai-sdk/otel": {
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
name: trigger-authoring-chat-agent
|
|
3
3
|
description: >
|
|
4
4
|
Author and run a durable AI chat agent with chat.agent from @trigger.dev/sdk/ai: the per-turn
|
|
5
|
-
run loop, why you MUST
|
|
6
|
-
|
|
5
|
+
run loop, why you MUST spread ...chat.toStreamTextOptions() first, returning a StreamTextResult
|
|
6
|
+
vs calling chat.pipe(), the two server actions (chat.createStartSessionAction +
|
|
7
7
|
auth.createPublicToken), and wiring useChat to useTriggerChatTransport. Load this when building,
|
|
8
8
|
modifying, or debugging a chat backend (the agent task or its lifecycle hooks) or its React
|
|
9
9
|
transport, when declaring typed tools or custom data parts, or when migrating a plain AI SDK
|
|
@@ -47,9 +47,10 @@ import { anthropic } from "@ai-sdk/anthropic";
|
|
|
47
47
|
|
|
48
48
|
export const myChat = chat.agent({
|
|
49
49
|
id: "my-chat",
|
|
50
|
-
|
|
51
|
-
run: async ({ messages, signal, streamText }) =>
|
|
50
|
+
run: async ({ messages, signal }) =>
|
|
52
51
|
streamText({
|
|
52
|
+
// Spread this FIRST. See "Common mistakes".
|
|
53
|
+
...chat.toStreamTextOptions(),
|
|
53
54
|
model: anthropic("claude-sonnet-4-5"),
|
|
54
55
|
messages,
|
|
55
56
|
abortSignal: signal,
|
|
@@ -120,22 +121,16 @@ inside nested helpers, call `await chat.pipe(result)` from anywhere in the task
|
|
|
120
121
|
`run` resolve `void`.
|
|
121
122
|
|
|
122
123
|
```ts
|
|
123
|
-
import { chat, type ChatStreamText } from "@trigger.dev/sdk/ai";
|
|
124
|
-
import { anthropic } from "@ai-sdk/anthropic";
|
|
125
|
-
import type { ModelMessage } from "ai";
|
|
126
|
-
|
|
127
124
|
export const agentChat = chat.agent({
|
|
128
125
|
id: "agent-chat",
|
|
129
|
-
run: async ({ messages
|
|
130
|
-
await runAgentLoop(messages
|
|
126
|
+
run: async ({ messages }) => {
|
|
127
|
+
await runAgentLoop(messages); // don't return; pipe inside
|
|
131
128
|
},
|
|
132
129
|
});
|
|
133
130
|
|
|
134
|
-
|
|
135
|
-
// managed options. `ChatStreamText` (from `@trigger.dev/sdk/ai`) types the parameter.
|
|
136
|
-
// `chat.toStreamTextOptions()` is the alternative when threading it down is impractical.
|
|
137
|
-
async function runAgentLoop(messages: ModelMessage[], streamText: ChatStreamText) {
|
|
131
|
+
async function runAgentLoop(messages: ModelMessage[]) {
|
|
138
132
|
const result = streamText({
|
|
133
|
+
...chat.toStreamTextOptions(),
|
|
139
134
|
model: anthropic("claude-sonnet-4-5"),
|
|
140
135
|
messages,
|
|
141
136
|
});
|
|
@@ -143,10 +138,10 @@ async function runAgentLoop(messages: ModelMessage[], streamText: ChatStreamText
|
|
|
143
138
|
}
|
|
144
139
|
```
|
|
145
140
|
|
|
146
|
-
### 2. Typed tools (declare on config AND
|
|
141
|
+
### 2. Typed tools (declare on config AND spread back)
|
|
147
142
|
|
|
148
143
|
Declare tools on `chat.agent({ tools })`, read them back typed from the `run()` payload, and pass
|
|
149
|
-
that set
|
|
144
|
+
that set to `chat.toStreamTextOptions({ tools })`. One declaration flows everywhere.
|
|
150
145
|
|
|
151
146
|
```ts
|
|
152
147
|
import { tool, stepCountIs } from "ai";
|
|
@@ -163,11 +158,11 @@ const tools = {
|
|
|
163
158
|
export const myChat = chat.agent({
|
|
164
159
|
id: "my-chat",
|
|
165
160
|
tools, // so toModelOutput survives across turns
|
|
166
|
-
run: async ({ messages, tools, signal
|
|
161
|
+
run: async ({ messages, tools, signal }) =>
|
|
167
162
|
streamText({
|
|
163
|
+
...chat.toStreamTextOptions({ tools }), // same set, handed back typed
|
|
168
164
|
model: anthropic("claude-sonnet-4-5"),
|
|
169
165
|
messages,
|
|
170
|
-
tools, // same set, handed back typed
|
|
171
166
|
abortSignal: signal,
|
|
172
167
|
stopWhen: stepCountIs(15),
|
|
173
168
|
}),
|
|
@@ -208,8 +203,8 @@ export const myChat = chat
|
|
|
208
203
|
onTurnStart: async ({ uiMessages, writer }) => {
|
|
209
204
|
writer.write({ type: "data-turn-status", data: { status: "preparing" } });
|
|
210
205
|
},
|
|
211
|
-
run: async ({ messages, tools, signal
|
|
212
|
-
streamText({ model, messages,
|
|
206
|
+
run: async ({ messages, tools, signal }) =>
|
|
207
|
+
streamText({ ...chat.toStreamTextOptions({ tools }), model, messages, abortSignal: signal }),
|
|
213
208
|
});
|
|
214
209
|
```
|
|
215
210
|
|
|
@@ -222,9 +217,8 @@ frontend, narrow `useChat` with `InferChatUIMessage<typeof myChat>` from `@trigg
|
|
|
222
217
|
`chat.agent` accepts hooks that fire in a fixed per-turn order:
|
|
223
218
|
|
|
224
219
|
```text
|
|
225
|
-
onValidateMessages ->
|
|
226
|
-
->
|
|
227
|
-
-> onTurnStart -> run() -> onBeforeTurnComplete -> onTurnComplete -> storage.save
|
|
220
|
+
onValidateMessages -> hydrateMessages -> onChatStart (chat's first message only)
|
|
221
|
+
-> onTurnStart -> run() -> onBeforeTurnComplete -> onTurnComplete
|
|
228
222
|
```
|
|
229
223
|
|
|
230
224
|
`onBoot` fires once per worker process (every fresh boot, including continuation runs) and is where
|
|
@@ -234,13 +228,13 @@ first message. Suspend/resume use `onChatSuspend` / `onChatResume`. Config optio
|
|
|
234
228
|
`uiMessageStreamOptions`, and `exitAfterPreloadIdle`. There is no generic `retry`; `chat.agent`
|
|
235
229
|
runs with `maxAttempts: 1` internally.
|
|
236
230
|
|
|
237
|
-
Stop
|
|
231
|
+
Stop is load-bearing: the `signal` passed to `run` aborts on stop or cancel. Forward it as
|
|
238
232
|
`abortSignal` to `streamText`, or the Stop button updates the UI while the model keeps generating
|
|
239
233
|
server-side.
|
|
240
234
|
|
|
241
235
|
```ts
|
|
242
|
-
run: async ({ messages, signal
|
|
243
|
-
streamText({ model, messages, abortSignal: signal, stopWhen: stepCountIs(15) });
|
|
236
|
+
run: async ({ messages, signal }) =>
|
|
237
|
+
streamText({ ...chat.toStreamTextOptions(), model, messages, abortSignal: signal, stopWhen: stepCountIs(15) });
|
|
244
238
|
```
|
|
245
239
|
|
|
246
240
|
### 6. Migrating from a plain AI SDK `streamText` route
|
|
@@ -249,30 +243,24 @@ There is no API route in this model. The transport replaces the route round-trip
|
|
|
249
243
|
|
|
250
244
|
- Delete the route handler. Move per-request auth into the two server actions from Setup step 2.
|
|
251
245
|
- Move the `streamText` call into `run`. It already receives pre-converted `ModelMessage[]`.
|
|
252
|
-
- Return the `StreamTextResult` (it auto-pipes) and
|
|
246
|
+
- Return the `StreamTextResult` (it auto-pipes) and add `...chat.toStreamTextOptions()` first.
|
|
253
247
|
- On the client, swap the `api` URL for `useTriggerChatTransport`; `useChat` stays the same shape.
|
|
254
248
|
|
|
255
249
|
## Common mistakes
|
|
256
250
|
|
|
257
|
-
- **CRITICAL:
|
|
251
|
+
- **CRITICAL: forgetting `...chat.toStreamTextOptions()`.**
|
|
258
252
|
```ts
|
|
259
253
|
// Wrong - compaction / steering / background injection silently no-op
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
run: async ({ messages, signal, streamText }) => streamText({ model, messages, abortSignal: signal });
|
|
254
|
+
return streamText({ model, messages, abortSignal: signal });
|
|
255
|
+
// Correct - spread FIRST so explicit overrides win
|
|
256
|
+
return streamText({ ...chat.toStreamTextOptions(), model, messages, abortSignal: signal });
|
|
264
257
|
```
|
|
265
|
-
|
|
266
|
-
injection, the system prompt from `chat.prompt()
|
|
267
|
-
|
|
268
|
-
`...chat.toStreamTextOptions()` does the same job by hand, and is what a custom agent has to use,
|
|
269
|
-
since it has no `run` argument. A `chat.headStart` route gets a bound `streamText` too, and there it
|
|
270
|
-
also owns `messages`, `prompt`, `stopWhen` and `abortSignal`. Spreading it and then re-setting
|
|
271
|
-
`tools` or `prepareStep` replaces the managed ones; the run argument's `streamText` merges `tools`
|
|
272
|
-
and composes `prepareStep` instead.
|
|
258
|
+
It wires the `prepareStep` callback behind compaction, mid-turn steering, and background
|
|
259
|
+
injection, injects the system prompt from `chat.prompt()`, resolves the registry model, and adds
|
|
260
|
+
telemetry. Omitting it makes all of those silently no-op with no error.
|
|
273
261
|
|
|
274
262
|
- **Declaring tools only on `streamText`.** Also declare them on `chat.agent({ tools })`, read them
|
|
275
|
-
back from `run`, and pass
|
|
263
|
+
back from `run`, and pass `chat.toStreamTextOptions({ tools })`. Otherwise each tool's
|
|
276
264
|
`toModelOutput` runs on turn 1 but is dropped when history is re-converted on later turns.
|
|
277
265
|
|
|
278
266
|
- **Not forwarding `signal` for stop.** Without `abortSignal: signal`, Stop updates the UI but the
|
|
@@ -143,12 +143,6 @@ await waitUntilComplete();
|
|
|
143
143
|
5s timeout, before `onTurnComplete`). `chat.inject(messages)` queues `ModelMessage[]` that drain at
|
|
144
144
|
the next turn start or `prepareStep` boundary.
|
|
145
145
|
|
|
146
|
-
Two lanes, decided by role. A `role: "system"` message goes to the model's instructions, where it is
|
|
147
|
-
trusted like the system prompt, and applies to the next turn only. Any other role joins the
|
|
148
|
-
conversation and is untrusted by construction, so put checkable facts there and directives in the
|
|
149
|
-
system lane. The instructions lane reaches the model only through the managed `streamText` (or a
|
|
150
|
-
`chat.toStreamTextOptions()` spread), since that is where the SDK can set instructions.
|
|
151
|
-
|
|
152
146
|
```ts
|
|
153
147
|
export const myChat = chat.agent({
|
|
154
148
|
id: "my-chat",
|
|
@@ -160,9 +154,8 @@ export const myChat = chat.agent({
|
|
|
160
154
|
})()
|
|
161
155
|
);
|
|
162
156
|
},
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
streamText({ messages, abortSignal: signal, stopWhen: stepCountIs(15) }),
|
|
157
|
+
run: async ({ messages, signal }) =>
|
|
158
|
+
streamText({ ...chat.toStreamTextOptions({ registry }), messages, abortSignal: signal, stopWhen: stepCountIs(15) }),
|
|
166
159
|
});
|
|
167
160
|
```
|
|
168
161
|
|
|
@@ -170,9 +163,8 @@ export const myChat = chat.agent({
|
|
|
170
163
|
|
|
171
164
|
`compaction.shouldCompact` decides when, `summarize` produces the summary that replaces the model
|
|
172
165
|
messages. UI messages are preserved by default (customize via `compactUIMessages`). The `prepareStep`
|
|
173
|
-
that performs inner-loop compaction
|
|
174
|
-
you pass after
|
|
175
|
-
switching compaction off.
|
|
166
|
+
that performs inner-loop compaction is auto-injected by `chat.toStreamTextOptions()`; a `prepareStep`
|
|
167
|
+
you pass after the spread wins.
|
|
176
168
|
|
|
177
169
|
```ts
|
|
178
170
|
compaction: {
|
|
@@ -190,14 +182,7 @@ compaction: {
|
|
|
190
182
|
`actionSchema` validates; `onAction` mutates via `chat.history` (`slice`, `replace`, `rollbackTo`,
|
|
191
183
|
`remove`, `getPendingToolCalls`, `extractNewToolResults`). Actions fire `hydrateMessages` and
|
|
192
184
|
`onAction` only, never `run()` or the turn hooks. Return a `StreamTextResult`, string, or `UIMessage`
|
|
193
|
-
to also emit a model response
|
|
194
|
-
carries the agent's prompt and tools like any other turn.
|
|
195
|
-
|
|
196
|
-
Persistence goes through the agent's transcript storage (`storage` on `chat.agent`; the platform
|
|
197
|
-
snapshot by default). After an action that changed the conversation the runtime hands the storage a
|
|
198
|
-
changeset: an undo is one `truncateAfter`, a regenerate is a `truncateAfter` plus the new answer's
|
|
199
|
-
`put`. With the deprecated `hydrateMessages` your store is the source of truth and the runtime does
|
|
200
|
-
not write, so mirror every mutation yourself: a regenerate is a delete and an insert.
|
|
185
|
+
to also emit a model response.
|
|
201
186
|
|
|
202
187
|
```ts
|
|
203
188
|
export const myChat = chat.agent({
|
|
@@ -210,8 +195,7 @@ export const myChat = chat.agent({
|
|
|
210
195
|
if (action.type === "undo") chat.history.slice(0, -2);
|
|
211
196
|
if (action.type === "rollback") chat.history.rollbackTo(action.targetMessageId);
|
|
212
197
|
},
|
|
213
|
-
run: async ({ messages, signal
|
|
214
|
-
streamText({ model: anthropic("claude-sonnet-4-5"), messages, abortSignal: signal }),
|
|
198
|
+
run: async ({ messages, signal }) => streamText({ model: anthropic("claude-sonnet-4-5"), messages, abortSignal: signal }),
|
|
215
199
|
});
|
|
216
200
|
```
|
|
217
201
|
|
|
@@ -226,19 +210,18 @@ must be **schema-only** (a module importing `ai` + `zod` only); heavy executes s
|
|
|
226
210
|
|
|
227
211
|
```ts
|
|
228
212
|
import { chat } from "@trigger.dev/sdk/chat-server";
|
|
213
|
+
import { streamText, stepCountIs } from "ai";
|
|
229
214
|
import { anthropic } from "@ai-sdk/anthropic";
|
|
230
215
|
import { headStartTools } from "@/lib/chat-tools/schemas";
|
|
231
216
|
|
|
232
217
|
export const chatHandler = chat.headStart({
|
|
233
218
|
agentId: "my-chat",
|
|
234
|
-
|
|
235
|
-
// and `abortSignal`: the handover needs `stopWhen: stepCountIs(1)` so the agent,
|
|
236
|
-
// not this handler, runs step 2 onward. Passing any of them is a type error.
|
|
237
|
-
run: async ({ streamText }) =>
|
|
219
|
+
run: async ({ chat: helper }) =>
|
|
238
220
|
streamText({
|
|
221
|
+
...helper.toStreamTextOptions({ tools: headStartTools }),
|
|
239
222
|
model: anthropic("claude-sonnet-4-6"),
|
|
240
223
|
system: "You are helpful.",
|
|
241
|
-
|
|
224
|
+
stopWhen: stepCountIs(15),
|
|
242
225
|
}),
|
|
243
226
|
});
|
|
244
227
|
// Next.js: export const POST = chatHandler; Transport: headStart: "/api/chat"
|
|
@@ -265,10 +248,8 @@ export const myChat = chat.agent({
|
|
|
265
248
|
### 8. Pending messages (mid-stream user input)
|
|
266
249
|
|
|
267
250
|
A message sent while a turn is streaming should NOT cancel the stream. Configure
|
|
268
|
-
`pendingMessages` (`shouldInject`, `prepare`, `onReceived`, `onInjected`) on the agent so the
|
|
269
|
-
|
|
270
|
-
of the conversation your hooks see, so it arrives in `uiMessages` and `newUIMessages` at
|
|
271
|
-
`onTurnComplete` and an app persisting from there stores it without extra work. On the frontend, `usePendingMessages`
|
|
251
|
+
`pendingMessages` (`shouldInject`, `prepare`, `onReceived`, `onInjected`) on the agent so the SDK's
|
|
252
|
+
auto-injected `prepareStep` folds them in at the next boundary. On the frontend, `usePendingMessages`
|
|
272
253
|
returns `pending`, `steer(text)`, `queue(text)`, and `promoteToSteering(id)`; send via
|
|
273
254
|
`transport.sendPendingMessage(chatId, uiMessage, metadata?)`.
|
|
274
255
|
|