@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.
Files changed (142) hide show
  1. package/dist/commonjs/imports/ai-runtime-cjs.cjs.map +1 -1
  2. package/dist/commonjs/imports/ai-runtime.js +0 -2
  3. package/dist/commonjs/v3/ai-shared.d.ts +0 -15
  4. package/dist/commonjs/v3/ai-shared.js +1 -35
  5. package/dist/commonjs/v3/ai-shared.js.map +1 -1
  6. package/dist/commonjs/v3/ai.d.ts +25 -275
  7. package/dist/commonjs/v3/ai.js +308 -1283
  8. package/dist/commonjs/v3/ai.js.map +1 -1
  9. package/dist/commonjs/v3/chat-client.d.ts +2 -11
  10. package/dist/commonjs/v3/chat-client.js +111 -227
  11. package/dist/commonjs/v3/chat-client.js.map +1 -1
  12. package/dist/commonjs/v3/chat-react.d.ts +0 -88
  13. package/dist/commonjs/v3/chat-react.js +1 -130
  14. package/dist/commonjs/v3/chat-react.js.map +1 -1
  15. package/dist/commonjs/v3/chat-server.d.ts +6 -42
  16. package/dist/commonjs/v3/chat-server.js +7 -52
  17. package/dist/commonjs/v3/chat-server.js.map +1 -1
  18. package/dist/commonjs/v3/chat.d.ts +10 -92
  19. package/dist/commonjs/v3/chat.js +73 -328
  20. package/dist/commonjs/v3/chat.js.map +1 -1
  21. package/dist/commonjs/v3/sessions.d.ts +2 -15
  22. package/dist/commonjs/v3/sessions.js +1 -12
  23. package/dist/commonjs/v3/sessions.js.map +1 -1
  24. package/dist/commonjs/v3/shared.js +36 -30
  25. package/dist/commonjs/v3/shared.js.map +1 -1
  26. package/dist/commonjs/v3/test/index.d.ts +0 -1
  27. package/dist/commonjs/v3/test/index.js +1 -3
  28. package/dist/commonjs/v3/test/index.js.map +1 -1
  29. package/dist/commonjs/v3/test/mock-chat-agent.d.ts +4 -47
  30. package/dist/commonjs/v3/test/mock-chat-agent.js +4 -115
  31. package/dist/commonjs/v3/test/mock-chat-agent.js.map +1 -1
  32. package/dist/commonjs/v3/test/test-session-handle.js +0 -6
  33. package/dist/commonjs/v3/test/test-session-handle.js.map +1 -1
  34. package/dist/commonjs/version.js +1 -1
  35. package/dist/esm/imports/ai-runtime.d.ts +2 -2
  36. package/dist/esm/imports/ai-runtime.js +2 -2
  37. package/dist/esm/imports/ai-runtime.js.map +1 -1
  38. package/dist/esm/v3/ai-shared.d.ts +0 -15
  39. package/dist/esm/v3/ai-shared.js +0 -33
  40. package/dist/esm/v3/ai-shared.js.map +1 -1
  41. package/dist/esm/v3/ai.d.ts +25 -275
  42. package/dist/esm/v3/ai.js +305 -1275
  43. package/dist/esm/v3/ai.js.map +1 -1
  44. package/dist/esm/v3/chat-client.d.ts +2 -11
  45. package/dist/esm/v3/chat-client.js +112 -228
  46. package/dist/esm/v3/chat-client.js.map +1 -1
  47. package/dist/esm/v3/chat-react.d.ts +0 -88
  48. package/dist/esm/v3/chat-react.js +1 -127
  49. package/dist/esm/v3/chat-react.js.map +1 -1
  50. package/dist/esm/v3/chat-server.d.ts +6 -42
  51. package/dist/esm/v3/chat-server.js +8 -53
  52. package/dist/esm/v3/chat-server.js.map +1 -1
  53. package/dist/esm/v3/chat.d.ts +10 -92
  54. package/dist/esm/v3/chat.js +74 -329
  55. package/dist/esm/v3/chat.js.map +1 -1
  56. package/dist/esm/v3/sessions.d.ts +2 -15
  57. package/dist/esm/v3/sessions.js +1 -11
  58. package/dist/esm/v3/sessions.js.map +1 -1
  59. package/dist/esm/v3/shared.js +23 -17
  60. package/dist/esm/v3/shared.js.map +1 -1
  61. package/dist/esm/v3/test/index.d.ts +0 -1
  62. package/dist/esm/v3/test/index.js +0 -1
  63. package/dist/esm/v3/test/index.js.map +1 -1
  64. package/dist/esm/v3/test/mock-chat-agent.d.ts +4 -47
  65. package/dist/esm/v3/test/mock-chat-agent.js +6 -117
  66. package/dist/esm/v3/test/mock-chat-agent.js.map +1 -1
  67. package/dist/esm/v3/test/test-session-handle.js +0 -6
  68. package/dist/esm/v3/test/test-session-handle.js.map +1 -1
  69. package/dist/esm/version.js +1 -1
  70. package/docs/ai-chat/actions.mdx +23 -55
  71. package/docs/ai-chat/anatomy.mdx +3 -3
  72. package/docs/ai-chat/backend.mdx +48 -125
  73. package/docs/ai-chat/background-injection.mdx +19 -69
  74. package/docs/ai-chat/client-protocol.mdx +4 -5
  75. package/docs/ai-chat/compaction.mdx +7 -13
  76. package/docs/ai-chat/custom-agents.mdx +0 -23
  77. package/docs/ai-chat/fast-starts.mdx +20 -27
  78. package/docs/ai-chat/frontend.mdx +14 -19
  79. package/docs/ai-chat/lifecycle-hooks.mdx +2 -6
  80. package/docs/ai-chat/migrating-from-a-route-handler.mdx +14 -16
  81. package/docs/ai-chat/patterns/database-persistence.mdx +2 -6
  82. package/docs/ai-chat/patterns/persistence-and-replay.mdx +23 -34
  83. package/docs/ai-chat/patterns/skills.mdx +10 -7
  84. package/docs/ai-chat/patterns/version-upgrades.mdx +6 -79
  85. package/docs/ai-chat/pending-messages.mdx +3 -3
  86. package/docs/ai-chat/prompt-caching.mdx +25 -23
  87. package/docs/ai-chat/quick-start.mdx +11 -11
  88. package/docs/ai-chat/reference.mdx +9 -67
  89. package/docs/ai-chat/sessions.mdx +1 -6
  90. package/docs/ai-chat/testing.mdx +1 -2
  91. package/docs/ai-chat/tools.mdx +13 -18
  92. package/docs/ai-chat/upgrade-guide.mdx +2 -2
  93. package/docs/apikeys.mdx +45 -27
  94. package/docs/config/extensions/syncEnvVars.mdx +0 -6
  95. package/docs/deploy-environment-variables.mdx +2 -23
  96. package/docs/deployment/overview.mdx +8 -4
  97. package/docs/deployment/preview-branches.mdx +4 -4
  98. package/docs/deployment/version-skew-protection.mdx +0 -62
  99. package/docs/manual-setup.mdx +7 -7
  100. package/docs/mcp-tools.mdx +0 -9
  101. package/docs/quick-start.mdx +3 -3
  102. package/docs/realtime/auth.mdx +1 -1
  103. package/docs/self-hosting/security.mdx +0 -5
  104. package/docs/tasks/scheduled.mdx +0 -24
  105. package/docs/triggering.mdx +1 -1
  106. package/package.json +4 -4
  107. package/skills/trigger-authoring-chat-agent/SKILL.md +29 -41
  108. package/skills/trigger-chat-agent-advanced/SKILL.md +12 -31
  109. package/dist/commonjs/v3/chatSnapshotIo.d.ts +0 -2
  110. package/dist/commonjs/v3/chatSnapshotIo.js +0 -174
  111. package/dist/commonjs/v3/chatSnapshotIo.js.map +0 -1
  112. package/dist/commonjs/v3/chatVersionSkew.d.ts +0 -12
  113. package/dist/commonjs/v3/chatVersionSkew.js +0 -30
  114. package/dist/commonjs/v3/chatVersionSkew.js.map +0 -1
  115. package/dist/commonjs/v3/externalDeploymentId.d.ts +0 -23
  116. package/dist/commonjs/v3/externalDeploymentId.js +0 -43
  117. package/dist/commonjs/v3/externalDeploymentId.js.map +0 -1
  118. package/dist/commonjs/v3/test/transcript-storage-tests.d.ts +0 -40
  119. package/dist/commonjs/v3/test/transcript-storage-tests.js +0 -258
  120. package/dist/commonjs/v3/test/transcript-storage-tests.js.map +0 -1
  121. package/dist/commonjs/v3/transcriptStorage.d.ts +0 -229
  122. package/dist/commonjs/v3/transcriptStorage.js +0 -321
  123. package/dist/commonjs/v3/transcriptStorage.js.map +0 -1
  124. package/dist/esm/v3/chatSnapshotIo.d.ts +0 -2
  125. package/dist/esm/v3/chatSnapshotIo.js +0 -166
  126. package/dist/esm/v3/chatSnapshotIo.js.map +0 -1
  127. package/dist/esm/v3/chatVersionSkew.d.ts +0 -12
  128. package/dist/esm/v3/chatVersionSkew.js +0 -27
  129. package/dist/esm/v3/chatVersionSkew.js.map +0 -1
  130. package/dist/esm/v3/externalDeploymentId.d.ts +0 -23
  131. package/dist/esm/v3/externalDeploymentId.js +0 -38
  132. package/dist/esm/v3/externalDeploymentId.js.map +0 -1
  133. package/dist/esm/v3/test/transcript-storage-tests.d.ts +0 -40
  134. package/dist/esm/v3/test/transcript-storage-tests.js +0 -255
  135. package/dist/esm/v3/test/transcript-storage-tests.js.map +0 -1
  136. package/dist/esm/v3/transcriptStorage.d.ts +0 -229
  137. package/dist/esm/v3/transcriptStorage.js +0 -309
  138. package/dist/esm/v3/transcriptStorage.js.map +0 -1
  139. package/docs/ai-chat/patterns/native-compaction.mdx +0 -310
  140. package/docs/ai-chat/transcript-storage.mdx +0 -233
  141. package/docs/reports.mdx +0 -157
  142. 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.
@@ -55,15 +55,15 @@ bun add -D @trigger.dev/build@latest
55
55
 
56
56
  ## Environment variables
57
57
 
58
- For local development, create a named environment API key and set it as `TRIGGER_SECRET_KEY`:
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. Open your project's Development environment in the Trigger.dev dashboard.
61
- 2. Open the **API Keys** page.
62
- 3. Click **New API key**, give it a descriptive name, and select **Trigger only** access.
63
- 4. Copy the key and add it to your local environment file. Trigger.dev shows the complete value only once.
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 .env
66
- TRIGGER_SECRET_KEY=tr_dev_sk_xxxxxxxxxx
65
+ ```bash
66
+ TRIGGER_SECRET_KEY=tr_dev_xxxxxxxxxx
67
67
  ```
68
68
 
69
69
  ### Self-hosted instances
@@ -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
@@ -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. Create a named API key in my Development environment with **Trigger only** access. Set it as TRIGGER_SECRET_KEY in my .env file (or .env.local for Next.js).
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 verifies that your task works. To trigger tasks from your own code, open the API Keys page for your Development environment and create a named key with **Trigger only** access. Set the key as `TRIGGER_SECRET_KEY` in your `.env` file.
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=tr_dev_sk_...
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).
@@ -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
- Public Access Tokens cannot expire more than 30 days in the future.
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>
@@ -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
  ```
@@ -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, create a named API key with **Trigger only** access in the environment you want to target and set it as `TRIGGER_SECRET_KEY`. If you're [using a preview branch](/deployment/preview-branches), also set `TRIGGER_PREVIEW_BRANCH`. [More info on API keys](/apikeys).
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-20260909071038",
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-20260909071038",
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": "4.5.4"
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.25.56 || ^4.0.0"
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 take streamText from the run argument rather than importing it from ai,
6
- returning a StreamTextResult vs calling chat.pipe(), the two server actions (chat.createStartSessionAction +
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
- // `streamText` below is the SDK's, from the run argument. See "Common mistakes".
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, streamText }) => {
130
- await runAgentLoop(messages, streamText); // don't return; pipe inside
126
+ run: async ({ messages }) => {
127
+ await runAgentLoop(messages); // don't return; pipe inside
131
128
  },
132
129
  });
133
130
 
134
- // A loop factored out of `run` takes `streamText` as an argument, so it keeps the
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 pass back)
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 as `tools`. One declaration flows everywhere.
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, streamText }) =>
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, streamText }) =>
212
- streamText({ model, messages, tools, abortSignal: signal }),
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 -> storage.loadContext (or the deprecated hydrateMessages)
226
- -> onChatStart (chat's first message only)
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 depends on it: the `signal` passed to `run` aborts on stop or cancel. Forward it as
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, streamText }) =>
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 take `streamText` from `run`'s argument, not from `ai`.
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: calling the `streamText` imported from `ai`.**
251
+ - **CRITICAL: forgetting `...chat.toStreamTextOptions()`.**
258
252
  ```ts
259
253
  // Wrong - compaction / steering / background injection silently no-op
260
- import { streamText } from "ai";
261
- run: async ({ messages, signal }) => streamText({ model, messages, abortSignal: signal });
262
- // Correct - the run argument's streamText carries the managed options
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
- The SDK's one carries the `prepareStep` behind compaction, mid-turn steering and background
266
- injection, the system prompt from `chat.prompt()` or `chat.agent({ system })`, the registry-resolved
267
- model, and telemetry. The imported one carries none of it, with no error.
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 that set as `tools`. Otherwise each tool's
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
- registry,
164
- run: async ({ messages, signal, streamText }) =>
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 rides the managed `streamText`, which composes a `prepareStep`
174
- you pass after it. Spreading `chat.toStreamTextOptions()` and then passing your own replaces it,
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, built with the `streamText` from `onAction`'s own argument so it
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, streamText }) =>
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
- // `streamText` from the run argument owns `messages`, `prompt`, `stopWhen`
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
- tools: headStartTools,
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 managed
269
- `streamText`'s `prepareStep` folds them in at the next boundary. An injected steering message is part
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
 
@@ -1,2 +0,0 @@
1
- export declare function __setReadChatSnapshotImplForTests(impl: ReadChatSnapshotImpl | undefined): void;
2
- export declare function __setWriteChatSnapshotImplForTests(impl: WriteChatSnapshotImpl | undefined): void;