@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
@@ -44,19 +44,14 @@ Options for `chat.agent()`.
44
44
  | `onPreload` | `(event: PreloadEvent) => Promise<void> \| void` | — | Fires on preloaded runs before the first message |
45
45
  | `onChatStart` | `(event: ChatStartEvent) => Promise<void> \| void` | — | Fires once per chat, on the very first user message. Does NOT fire on continuation runs or OOM-retries — see [onChatStart](/ai-chat/lifecycle-hooks#onchatstart). |
46
46
  | `onValidateMessages` | `(event: ValidateMessagesEvent) => UIMessage[] \| Promise<UIMessage[]>` | — | Validate/transform UIMessages before model conversion. See [onValidateMessages](/ai-chat/lifecycle-hooks#onvalidatemessages) |
47
- | `storage` | `TranscriptStorage` | `defaultStorage` | Where the conversation is persisted and read back. The platform snapshot by default; bring your own to write each change to your database. See [Transcript storage](/ai-chat/transcript-storage) |
48
- | `hydrateMessages` | `(event: HydrateMessagesEvent) => UIMessage[] \| Promise<UIMessage[]>` | — | **Deprecated.** Load message history from backend, replacing the linear accumulator. Use `loadContext` on a `storage` instead; cannot be combined with `storage`. See [hydrateMessages](/ai-chat/lifecycle-hooks#hydratemessages) |
47
+ | `hydrateMessages` | `(event: HydrateMessagesEvent) => UIMessage[] \| Promise<UIMessage[]>` | — | Load message history from backend, replacing the linear accumulator. See [hydrateMessages](/ai-chat/lifecycle-hooks#hydratemessages) |
49
48
  | `actionSchema` | `TaskSchema` | — | Schema for validating custom actions sent via `transport.sendAction()`. See [Actions](/ai-chat/actions) |
50
- | `onAction` | `(event: ActionEvent) => Promise<void \| ActionTurn> \| void \| ActionTurn` | — | Handle custom actions. Actions are state edits: only `hydrateMessages` (or a storage's `loadContext`) + `onAction` fire. Return `chat.turn()` to run a turn on the edited history, or nothing for an edit only. See [Actions](/ai-chat/actions) |
49
+ | `onAction` | `(event: ActionEvent) => Promise<unknown> \| unknown` | — | Handle custom actions. Actions are not turns — only `hydrateMessages` + `onAction` fire. Return a `StreamTextResult` (or `string` / `UIMessage`) for a model response; return `void` for side-effect-only. See [Actions](/ai-chat/actions) |
51
50
  | `onTurnStart` | `(event: TurnStartEvent) => Promise<void> \| void` | — | Fires every turn before `run()` |
52
51
  | `onBeforeTurnComplete` | `(event: BeforeTurnCompleteEvent) => Promise<void> \| void` | — | Fires after response but before stream closes. Includes `writer`. |
53
52
  | `onTurnComplete` | `(event: TurnCompleteEvent) => Promise<void> \| void` | — | Fires after each turn completes (stream closed) |
54
53
  | `onCompacted` | `(event: CompactedEvent) => Promise<void> \| void` | — | Fires when compaction occurs. Includes `writer`. See [Compaction](/ai-chat/compaction) |
55
54
  | `compaction` | `ChatAgentCompactionOptions` | — | Automatic context compaction. See [Compaction](/ai-chat/compaction) |
56
- | `registry` | `{ languageModel(id: string): unknown }` | — | A provider registry, so the managed `streamText` can resolve a model set through `chat.prompt.set()` |
57
- | `system` | `string \| SystemModelMessage` | — | The agent's system prompt. Injected instructions append to it. Set it here, at the `streamText` call site, or through `chat.prompt.set()`, but only in one of them |
58
- | `cacheControl` | `SystemCacheControl` | — | Mark the system prompt for provider-side caching. See [Prompt caching](/ai-chat/prompt-caching) |
59
- | `systemProviderOptions` | `ProviderMetadata` | — | Raw provider options for the system block. Takes precedence over `cacheControl` |
60
55
  | `pendingMessages` | `PendingMessagesOptions` | — | Mid-execution message injection. See [Pending Messages](/ai-chat/pending-messages) |
61
56
  | `prepareMessages` | `(event: PrepareMessagesEvent) => ModelMessage[]` | — | Transform model messages before use (cache breaks, context injection, etc.) |
62
57
  | `tools` | `ToolSet \| ((event: ResolveToolsEvent) => ToolSet \| Promise<ToolSet>)` | — | Tools for this agent. Threads each tool's `toModelOutput` through cross-turn history re-conversion, and hands the resolved set back on the run payload. Static set or per-turn function. See [Tools](/ai-chat/tools). |
@@ -103,10 +98,9 @@ The payload passed to the `run` function.
103
98
  | `ctx` | `TaskRunContext` | Full task run context — same as `task` `run`’s `{ ctx }` |
104
99
  | `messages` | `ModelMessage[]` | Model-ready messages — pass directly to `streamText` |
105
100
  | `tools` | `ToolSet` | Resolved tools declared on the agent config (empty object when none). Pass straight to `streamText`. See [Tools](/ai-chat/tools). |
106
- | `streamText` | `typeof streamText` | The AI SDK's `streamText` with this agent's managed options already applied: the prompt, skill tools, telemetry, and the `prepareStep` that delivers steering, compaction and injected context. Prefer it over importing `streamText` from `ai`. See [The managed streamText](/ai-chat/backend#the-managed-streamtext). |
107
101
  | `chatId` | `string` | Your conversation ID (the session's `externalId`) |
108
102
  | `sessionId` | `string` | Friendly ID of the backing Session (`session_*`). Use with `sessions.open()` for advanced cases. Always set — every chat.agent run is bound to a Session. |
109
- | `trigger` | `"submit-message" \| "regenerate-message" \| "action-turn"` | What triggered the request; `"action-turn"` is a turn requested by `chat.turn()` |
103
+ | `trigger` | `"submit-message" \| "regenerate-message"` | What triggered the request |
110
104
  | `messageId` | `string \| undefined` | Message ID (for regenerate) |
111
105
  | `clientData` | Typed by `clientDataSchema` | Custom data from the frontend (typed when schema is provided) |
112
106
  | `continuation` | `boolean` | Whether this run is continuing an existing chat (previous run ended) |
@@ -219,38 +213,9 @@ Passed to the `tools` function form on `chat.agent`, once per turn, to resolve t
219
213
  | `continuation` | `boolean` | Whether this run is continuing an existing chat |
220
214
  | `clientData` | Typed by `clientDataSchema` | Custom data from the frontend |
221
215
 
222
- ## TranscriptStorage
223
-
224
- The persistence adapter set through `chat.agent({ storage })`. See [Transcript storage](/ai-chat/transcript-storage). All types below are exported from `@trigger.dev/sdk/ai`.
225
-
226
- | Member | Signature | Description |
227
- | --- | --- | --- |
228
- | `load` | `(scope: TranscriptScope, opts?: TranscriptLoadOptions) => Promise<TranscriptLoadResult>` | The conversation, in order. Called once at a continuation boot and by `chat.createLoadTranscriptAction` for rendering. |
229
- | `save` | `(ctx: TranscriptStorageContext, changeset: TranscriptChangeset) => Promise<void>` | Apply the changes since the last save. Called after every turn, failed turn and history-changing action. |
230
- | `loadContext?` | `(scope: TranscriptScope, event: LoadContextEvent) => Promise<UIMessage[]>` | Optional. When present, the storage owns the model's context: called on every turn and action in place of the runtime's transcript. Same event shape as `HydrateMessagesEvent`. |
231
-
232
- | Type | Shape |
233
- | --- | --- |
234
- | `TranscriptScope<TClientData>` | `{ chatId: string; clientData: TClientData }` |
235
- | `TranscriptStorageContext<TClientData>` | `TranscriptScope` plus `{ turn: number; trigger: "submit-message" \| "regenerate-message" \| "action"; runId: string; ctx: TaskRunContext }` |
236
- | `TranscriptChange` | `{ op: "put"; message: UIMessage; final?: boolean }` \| `{ op: "remove"; id: string }` \| `{ op: "truncateAfter"; afterId: string }` \| `{ op: "state"; value: unknown \| null }` |
237
- | `TranscriptChangeset` | `{ reason: "turn-complete" \| "turn-error" \| "action" \| "compaction" \| "recovery"; changes: TranscriptChange[]; transcript: TranscriptState; cursors?: TranscriptCursors }` |
238
- | `TranscriptState` | `{ entries: Array<{ id: string; final: boolean; message: UIMessage }>; state: unknown \| null }`: the whole conversation after the changeset's changes, for stores that write one document |
239
- | `TranscriptCursors` | `{ lastOutEventId?: string; lastInEventId?: string }` |
240
- | `TranscriptLoadOptions` | `{ limit?: number; before?: string }` |
241
- | `TranscriptLoadResult` | `{ messages: UIMessage[]; state: unknown \| null; cursors?: TranscriptCursors; nextCursor?: string }` |
242
-
243
- | Export | Description |
244
- | --- | --- |
245
- | `defaultStorage` | The platform snapshot storage the agent uses when `storage` is not set. Equal to `snapshotTranscriptStorage()`. |
246
- | `snapshotTranscriptStorage()` | Factory for the platform snapshot storage. |
247
- | `memoryTranscriptStorage()` | An in-process storage that also records every changeset it receives. The reference implementation. |
248
- | `reduceTranscriptChanges(state, changes)` | Pure reducer that applies changes to `{ entries, state }`. Useful for building a storage over a document store. |
249
- | `runTranscriptStorageTests(makeStorage, options?)` | From `@trigger.dev/sdk/ai/test`. The conformance suite for a storage implementation. Pass `{ api: { describe, it, expect } }` when test globals are off, and `clientData` when your storage scopes by it. |
250
-
251
216
  ## HydrateMessagesEvent
252
217
 
253
- Passed to the `hydrateMessages` callback. See [hydrateMessages](/ai-chat/lifecycle-hooks#hydratemessages). `hydrateMessages` is deprecated; `LoadContextEvent`, passed to a storage's `loadContext`, has the same shape.
218
+ Passed to the `hydrateMessages` callback. See [hydrateMessages](/ai-chat/lifecycle-hooks#hydratemessages).
254
219
 
255
220
  | Field | Type | Description |
256
221
  | ------------------ | ----------------------------------------------------- | --------------------------------------------------------- |
@@ -399,8 +364,8 @@ Passed to `compactUIMessages` and `compactModelMessages` callbacks.
399
364
  | Field | Type | Description |
400
365
  | --------------- | -------------------- | ---------------------------------------------------- |
401
366
  | `summary` | `string` | The generated summary text |
402
- | `uiMessages` | `UIMessage[]` | Current UI messages (the transcript) |
403
- | `modelMessages` | `ModelMessage[]` | Current model messages (the lane the model is sent; after a compaction this is the summary plus what followed it, not the whole transcript) |
367
+ | `uiMessages` | `UIMessage[]` | Current UI messages (full conversation) |
368
+ | `modelMessages` | `ModelMessage[]` | Current model messages (full conversation) |
404
369
  | `chatId` | `string` | Chat session ID |
405
370
  | `turn` | `number` | Current turn (0-indexed) |
406
371
  | `clientData` | `unknown` | Custom data from the frontend |
@@ -525,9 +490,9 @@ Options for [`chat.headStart()`](/ai-chat/fast-starts#head-start), the warm-serv
525
490
  | `agentId` | `string` | required | The `chat.agent` / `chat.customAgent` id to hand off to |
526
491
  | `run` | `(args: HeadStartRunArgs) => Promise<StreamTextResult>` | required | First-turn callback. Call `streamText` and spread `chat.toStreamTextOptions({ tools })` |
527
492
  | `idleTimeoutInSeconds` | `number` | `60` | How long the agent waits for the handover signal |
528
- | `triggerConfig` | `Partial<SessionTriggerConfig>` | `undefined` | Run options (tags, queue, machine, maxAttempts, maxDuration, region, lockToVersion, externalDeploymentId) for the auto-triggered handover-prepare run. The `chat:{chatId}` tag is prepended automatically and counts toward the 10-tag limit |
493
+ | `triggerConfig` | `Partial<SessionTriggerConfig>` | `undefined` | Run options (tags, queue, machine, maxAttempts, maxDuration, region, lockToVersion) for the auto-triggered handover-prepare run. The `chat:{chatId}` tag is prepended automatically and counts toward the 10-tag limit |
529
494
 
530
- `chat.headStart(options)` returns the handler `(req: Request) => Promise<Response>`. The `run` callback receives `HeadStartRunArgs`: `{ messages: UIMessage[], signal: AbortSignal, chat: HeadStartChatHelper }`, where the helper exposes `chat.toStreamTextOptions({ tools })` and a `chat.session` escape hatch (whose `pendingVersion` says whether the agent run is parked waiting for its deployment). See [Head Start](/ai-chat/fast-starts#head-start) for the full guide.
495
+ `chat.headStart(options)` returns the handler `(req: Request) => Promise<Response>`. The `run` callback receives `HeadStartRunArgs`: `{ messages: UIMessage[], signal: AbortSignal, chat: HeadStartChatHelper }`, where the helper exposes `chat.toStreamTextOptions({ tools })` and a `chat.session` escape hatch. See [Head Start](/ai-chat/fast-starts#head-start) for the full guide.
531
496
 
532
497
  ## chat namespace
533
498
 
@@ -544,10 +509,8 @@ All methods available on the `chat` object from `@trigger.dev/sdk/ai`.
544
509
  | `chat.messages` | Incoming message mailbox; supports non-consuming `.peek()` / `.hasPending()`, single-record `.next()`, `.on()`, and suspend-aware `.waitWithIdleTimeout()` |
545
510
  | `chat.local<T>({ id })` | Create a per-run typed local (see [`chat.local`](/ai-chat/chat-local)) |
546
511
  | `chat.createStartSessionAction(taskId, options?)` | Returns a server action that creates a chat Session + triggers the first run + returns a session-scoped PAT. Idempotent on `(env, externalId)`. |
547
- | `chat.createLoadTranscriptAction(storage, options?)` | Returns a server action that reads a conversation from a transcript storage (`{ chatId, clientData?, limit?, before? }` → `TranscriptLoadResult`). Pair with `useLoadTranscript`. Performs no application authorization: authorize `chatId` for the signed-in user in your own code. See [Transcript storage](/ai-chat/transcript-storage#reading-the-transcript) |
548
512
  | `chat.waitForHandover(options)` | Wait for a [`chat.headStart`](/ai-chat/fast-starts#handover-with-custom-agents) handover signal in a custom loop. Returns the signal or `null`. `chat.MessageAccumulator` wraps this as `consumeHandover()` / `applyHandover()` |
549
513
  | `chat.requestUpgrade()` | End the current run after this turn so the next message starts on the latest agent version. Server-orchestrated handoff. |
550
- | `chat.close({ reason })` | End the conversation permanently: close the session row, write a terminal `session-closed` record, and exit without a continuation. Decide it before the turn ends (`onBeforeTurnComplete`, not `onTurnComplete`) so the client sees the closed state on that turn. |
551
514
  | `chat.endAndContinue()` | In a hand-rolled custom agent, hand off the Session to a fresh continuation run. Call between turns after detaching input listeners, then return immediately. The promise rejects if the handoff fails. |
552
515
  | `chat.setTurnTimeout(duration)` | Override turn timeout at runtime (e.g. `"2h"`) |
553
516
  | `chat.setTurnTimeoutInSeconds(seconds)` | Override turn timeout at runtime (in seconds) |
@@ -696,7 +659,6 @@ The `onEvent` callback receives a `ChatTransportEvent` (exported from `@trigger.
696
659
  | --- | --- | --- |
697
660
  | `message-sent` | `messageId?`, `source`, `durationMs`, `partId?`, `bodyBytes?` | A send was durably acknowledged — a 2xx from the session input stream append (or the `headStart` POST), after any internal token-refresh retries. This means the message is durably written to the stream the agent consumes from, not merely "request accepted". `partId` is the append's idempotency key, also stored on the server-side record. |
698
661
  | `message-send-failed` | `messageId?`, `source`, `error`, `status?`, `durationMs`, `partId?`, `bodyBytes?` | A send definitively failed after internal retries. Fires in addition to `useChat`'s `onError`. |
699
- | `run-pending-version` | `source` | The chat's run is parked waiting for the deployment carrying its external deployment id ([version skew protection](/deployment/version-skew-protection#chat-sessions)). Everything already sent is durable and answered once the deployment lands. `source` is `"start"` (learned while starting the session), `"send"` (from a message append, re-emitted on every send while parked) `"head-start"` (from the `headStart` POST, where step 1 still streams from your server and only step 2 waits) or `"upgrade"` (an automatic version handover whose successor is parked on a deployment that has not landed). |
700
662
  | `stream-connected` | `resumed`, `lastEventId?`, `messageId?` | The SSE subscription to the session's output stream started delivering. `resumed: true` when reconnecting from a stored cursor (page reload) rather than following a fresh send. `lastEventId` is the cursor it connected from. |
701
663
  | `first-chunk` | `chunkType?`, `lastEventId?`, `messageId?`, `sinceSendMs?` | The first response chunk of a turn arrived. `sinceSendMs` is the delta from the last turn-producing send — time to first token without any bookkeeping. |
702
664
  | `turn-completed` | `lastEventId?`, `sessionInEventId?`, `messageId?`, `sinceSendMs?` | The agent's turn-complete control record arrived — the "finished answering" signal. `sinceSendMs` is the full turn latency; `sessionInEventId` is the cursor the agent can safely resume its input stream from. Treat it as a lower bound: it is held back behind any message still waiting to be handled, so it can be below the sequence of the record this turn answered. Do not use it to decide whether a turn boundary belongs to your own send. |
@@ -832,7 +794,7 @@ See [Stop generation](/ai-chat/frontend#stop-generation) for full details.
832
794
 
833
795
  ### transport.sendAction()
834
796
 
835
- Send a custom action to the agent, outside `useChat`. Actions wake the agent from suspension and fire `onAction`. An action that returns `chat.turn()` is followed by a turn; its answer arrives on the returned stream, which the caller must read. From a `useChat` app, send actions as requests instead (`sendMessage(undefined, { body: { action } })` or the `useChatActions` hook) so `useChat` renders the answer.
797
+ Send a custom action to the agent. Actions wake the agent from suspension and fire `onAction`. They are not turns — `run()` and turn lifecycle hooks do not fire. If `onAction` returns a `StreamTextResult`, the response is auto-piped to the frontend.
836
798
 
837
799
  ```ts
838
800
  transport.sendAction(chatId: string, action: unknown): Promise<ReadableStream<UIMessageChunk>>
@@ -907,26 +869,6 @@ Second argument to `chat.createStartSessionAction(taskId, options?)`. Controls h
907
869
  | `baseURL` | `string \| (ctx: { endpoint: "sessions" \| "auth"; chatId: string }) => string` | `apiClientManager.baseURL` | API base URL. `endpoint` is `"sessions"` for `POST /api/v1/sessions` or `"auth"` for `POST /api/v1/auth/jwt/claims` (only fires when `tokenTTL` is set). |
908
870
  | `fetch` | `(url: string, init: RequestInit, ctx: { endpoint: "sessions" \| "auth"; chatId: string }) => Promise<Response>` | — | Per-request fetch override. Use to route session-create through a trusted edge proxy so `basePayload.metadata` is rewritten before reaching `api.trigger.dev`. |
909
871
 
910
- ## createLoadTranscriptAction options
911
-
912
- Second argument to `chat.createLoadTranscriptAction(storage, options?)`.
913
-
914
- | Option | Type | Default | Description |
915
- | ----------- | ------------------------ | -------------------------- | --------------------------------------------------------------------------- |
916
- | `limit` | `number` | — | Page size when the caller passes none. Returns the most recent messages and a `nextCursor`. |
917
- | `apiClient` | `ApiClientConfiguration` | `apiClientManager` config | Scope the read to a specific API client (secret key, base URL). The default storage reads through it. |
918
-
919
- ## useLoadTranscript
920
-
921
- `useLoadTranscript(chatId, load, options?)` from `@trigger.dev/sdk/chat/react`. Loads a conversation through a `chat.createLoadTranscriptAction` action, for rendering before the chat connects. Re-runs when `chatId` changes.
922
-
923
- | Option | Type | Description |
924
- | ----------- | ---------------------- | -------------------------------------------------------------------------------------------- |
925
- | `transport` | `TriggerChatTransport` | Seed the transport's resume cursor for this chat from the transcript, once it knows the session. |
926
- | `limit` | `number` | Page size passed to the action. |
927
-
928
- Returns `{ messages, isLoading, error, nextCursor }`. `nextCursor` is the id to pass as `before` to the action for the page before this one.
929
-
930
872
  ## useMultiTabChat
931
873
 
932
874
  React hook for multi-tab message coordination. Import from `@trigger.dev/sdk/chat/react`.
@@ -111,7 +111,7 @@ const { id, runId, publicAccessToken, isCached } = await sessions.start({
111
111
  | `type` | `string` | Free-form discriminator. `chat.agent` uses `"chat.agent"`. |
112
112
  | `externalId` | `string?` | Your stable identity. Cannot start with `session_` (reserved). |
113
113
  | `taskIdentifier` | `string` | Task this session triggers runs against. |
114
- | `triggerConfig` | `SessionTriggerConfig` | Trigger options applied to every run: `tags` (up to 10, same as [run tags](/tags); the chat helpers such as `chat.createStartSessionAction` and `AgentChat` add a `chat:{chatId}` tag themselves, which uses one slot. Direct `sessions.start` callers get all 10 and must add any chat tag themselves), `queue`, `machine`, `maxAttempts`, `maxDuration`, `region`, `idleTimeoutInSeconds`, `basePayload`, and the version pins `lockToVersion` / [`externalDeploymentId`](/deployment/version-skew-protection#chat-sessions). |
114
+ | `triggerConfig` | `SessionTriggerConfig` | Trigger options applied to every run: `tags` (up to 10, same as [run tags](/tags); the chat helpers such as `chat.createStartSessionAction` and `AgentChat` add a `chat:{chatId}` tag themselves, which uses one slot. Direct `sessions.start` callers get all 10 and must add any chat tag themselves), `queue`, `machine`, `maxAttempts`, `idleTimeoutInSeconds`, `basePayload`. |
115
115
  | `tags` | `string[]?` | Up to 10 tags on the Session row (separate from `triggerConfig.tags`). |
116
116
  | `metadata` | `Record<string, unknown>?` | Arbitrary JSON. |
117
117
  | `expiresAt` | `Date?` | Hard retention deadline. |
@@ -146,11 +146,6 @@ Mark a Session as closed. Terminal and idempotent. The optional `reason` is stor
146
146
  await sessions.close(chatId, { reason: "user signed out" });
147
147
  ```
148
148
 
149
- Closing tells a live run too: the close lands on the session's input channel, so an idle or suspended agent exits its loop on the next wake rather than waiting out its idle timeout. After it lands, appends to `.in` are refused with HTTP 409 and `code: "session_closed"`.
150
-
151
- To close from inside the agent instead, call [`chat.close()`](/ai-chat/backend#ending-the-conversation). It writes a terminal record to the response stream so the browser learns the reason, then closes the row.
152
-
153
-
154
149
  ### `sessions.list(options?, requestOptions?)`
155
150
 
156
151
  Cursor-paginated list of Sessions in the current environment. Returns a `CursorPagePromise` you can iterate with `for await`.
@@ -203,7 +203,7 @@ Equivalent to the frontend's `useChat().regenerate()` — replays a turn with th
203
203
 
204
204
  ### sendAction
205
205
 
206
- Routes a payload through `actionSchema` + `onAction`. An action is a state edit: only `hydrateMessages` and `onAction` fire, unless `onAction` returns `chat.turn()`, in which case a turn runs on the edited history and the returned `turn.rawChunks` carries that turn's answer.
206
+ Routes a payload through `actionSchema` + `onAction`. Actions are not turns: only `hydrateMessages` and `onAction` fire on the agent side — no turn lifecycle hooks, no `run()`. The returned `turn.rawChunks` contains whatever `onAction` produced (a streamed model response if it returned a `StreamTextResult`, otherwise just `trigger:turn-complete`):
207
207
 
208
208
  ```ts
209
209
  const turn = await harness.sendAction({ type: "undo" });
@@ -634,7 +634,6 @@ The harness's initial wire payload depends on `mode`:
634
634
  | `sendHandover({ partialAssistantMessage, isFinal?, messageId? })` | Dispatch a `handover` signal — only meaningful when started with `mode: "handover-prepare"`. The agent picks up partial assistant messages and continues the turn. |
635
635
  | `sendHandoverSkip()` | Dispatch a `handover-skip` signal — only meaningful when started with `mode: "handover-prepare"`. The agent exits cleanly without firing turn hooks. |
636
636
  | `sendAction(action)` | Route a custom action through `actionSchema` + `onAction`. |
637
- | `sendPendingMessage(message)` | Append a user message mid-turn without waiting for a turn to complete, so it reaches the running turn as a steering message. Resolves once the record has landed on `session.in`. |
638
637
  | `sendStop(message?)` | Fire a stop signal. Does not wait for the turn — the run's `signal.aborted` becomes `true`. |
639
638
  | `seedSnapshot(snapshot)` | Pre-seed the snapshot read for the next boot. Effective on the next run boot only. |
640
639
  | `seedSessionOutTail(chunks?)` | Pre-seed `session.out` chunks for the next boot's replay. Reduces to settled assistant turns. |
@@ -8,7 +8,7 @@ description: "Declare tools on chat.agent so toModelOutput survives across turns
8
8
 
9
9
  ```ts
10
10
  import { chat } from "@trigger.dev/sdk/ai";
11
- import { stepCountIs, tool } from "ai";
11
+ import { streamText, stepCountIs, tool } from "ai";
12
12
  import { anthropic } from "@ai-sdk/anthropic";
13
13
  import { z } from "zod";
14
14
 
@@ -23,9 +23,9 @@ const tools = {
23
23
  export const myChat = chat.agent({
24
24
  id: "my-chat",
25
25
  tools, // ← declare here
26
- run: async ({ messages, tools, signal, streamText }) =>
26
+ run: async ({ messages, tools, signal }) =>
27
27
  streamText({
28
- tools,
28
+ ...chat.toStreamTextOptions({ tools }), // ← the same set, handed back on the payload
29
29
  model: anthropic("claude-sonnet-4-5"),
30
30
  messages,
31
31
  abortSignal: signal,
@@ -46,15 +46,10 @@ There are three places a tool set shows up. Declare once, reuse:
46
46
  | Surface | What it's for |
47
47
  | --- | --- |
48
48
  | `chat.agent({ tools })` | Re-applies `toModelOutput` on prior-turn history; hands the set back typed on the `run()` payload. |
49
- | `streamText({ tools })` on the `run` argument's `streamText` | What the model actually calls. Detects which calls need [HITL approval](/ai-chat/patterns/human-in-the-loop) (`needsApproval`) and merges the auto-injected [skill](/ai-chat/patterns/skills) tools on top. Naming `tools` replaces the config set for that call, so you can narrow it; omitting `tools` falls back to the config set. |
50
- | `chat.toStreamTextOptions({ tools })` | The same job by hand, for a [custom agent](#manual-turn-loops-chatcustomagent), which has no `run` argument. |
49
+ | `chat.toStreamTextOptions({ tools })` | Detects which tool calls need [HITL approval](/ai-chat/patterns/human-in-the-loop) (`needsApproval`) and merges any auto-injected [skill](/ai-chat/patterns/skills) tools. |
50
+ | `streamText({ tools })` | What the model actually calls. `chat.toStreamTextOptions({ tools })` already sets this, so spread it instead of passing `tools` twice. |
51
51
 
52
- The canonical pattern: declare `tools` on the config, read them back from the `run()` payload, and pass that set to the `streamText` the payload also carries.
53
-
54
- ```ts
55
- run: async ({ messages, tools, signal, streamText }) =>
56
- streamText({ model, messages, tools, abortSignal: signal }),
57
- ```
52
+ The canonical pattern: declare `tools` on the config, read them back from the `run()` payload, and pass that to `chat.toStreamTextOptions({ tools })`. One declaration flows everywhere.
58
53
 
59
54
  <Tip>
60
55
  Conversion only reads each tool's `inputSchema` and `toModelOutput`, never `execute`. If you keep heavy `execute` dependencies out of a module (for bundle reasons), you can declare a lightweight schema-only tool map on the config and add the executes where you call `streamText`.
@@ -85,9 +80,9 @@ const tools = {
85
80
  export const chartChat = chat.agent({
86
81
  id: "chart-chat",
87
82
  tools, // ← without this, the image is "remembered" on turn 1 and gone from turn 2
88
- run: async ({ messages, tools, signal, streamText }) =>
83
+ run: async ({ messages, tools, signal }) =>
89
84
  streamText({
90
- tools,
85
+ ...chat.toStreamTextOptions({ tools }),
91
86
  model: anthropic("claude-sonnet-4-5"),
92
87
  messages,
93
88
  abortSignal: signal,
@@ -109,9 +104,9 @@ export const myChat = chat
109
104
  searchDocs,
110
105
  ...(clientData?.plan === "pro" ? { deepResearch } : {}),
111
106
  }),
112
- run: async ({ messages, tools, signal, streamText }) =>
107
+ run: async ({ messages, tools, signal }) =>
113
108
  streamText({
114
- tools,
109
+ ...chat.toStreamTextOptions({ tools }),
115
110
  model: anthropic("claude-sonnet-4-5"),
116
111
  messages,
117
112
  abortSignal: signal,
@@ -136,10 +131,10 @@ The resolved set is what lands on the `run()` payload's `tools`.
136
131
  The `run()` payload's `tools` is typed to whatever you declared, so you can pass it straight through without re-importing the map:
137
132
 
138
133
  ```ts
139
- run: async ({ messages, tools, signal, streamText }) => {
134
+ run: async ({ messages, tools, signal }) => {
140
135
  // `tools` is typed as your tool set, not a broad `ToolSet`
141
136
  return streamText({
142
- tools,
137
+ ...chat.toStreamTextOptions({ tools }),
143
138
  model: anthropic("claude-sonnet-4-5"),
144
139
  messages,
145
140
  abortSignal: signal,
@@ -165,7 +160,7 @@ This is shorthand for `UIMessage<unknown, UIDataTypes, InferUITools<typeof tools
165
160
 
166
161
  ## Skills
167
162
 
168
- [Agent skills](/ai-chat/patterns/skills) are auto-injected as tools (`loadSkill`, `readFile`, `bash`) by the managed `streamText`, or by `chat.toStreamTextOptions()` if you build the options yourself. They're separate from your config `tools`: declare your own tools on the config (so their `toModelOutput` survives across turns), and the merge happens at call time. Skill tools don't define `toModelOutput`, so they don't need to be on the config.
163
+ [Agent skills](/ai-chat/patterns/skills) are auto-injected as tools (`loadSkill`, `readFile`, `bash`) by `chat.toStreamTextOptions()`. They're separate from your config `tools`: declare your own tools on the config (so their `toModelOutput` survives across turns), and let `toStreamTextOptions` merge the skill tools on top at call time. Skill tools don't define `toModelOutput`, so they don't need to be on the config.
169
164
 
170
165
  ## Manual turn loops (`chat.customAgent`)
171
166
 
@@ -298,8 +298,8 @@ and direct API consumers.
298
298
  fire at the same lifecycle points.
299
299
  - `onAction` is still defined the same way, but its semantics changed
300
300
  in the [May 6 prerelease](/ai-chat/changelog) — actions are no longer
301
- turns. To answer after an action's edit, return `chat.turn()`; returning
302
- a `StreamTextResult` is no longer supported.
301
+ turns, and `onAction` returning a `StreamTextResult` produces a model
302
+ response.
303
303
  - `chat.customAgent({...})` and the `chat.createSession(payload, ...)`
304
304
  helper for building a session loop manually inside a custom agent.
305
305
  - `chat.defer` (deferred work) and `chat.history` (imperative history
package/docs/apikeys.mdx CHANGED
@@ -10,35 +10,17 @@ description: "Authenticate backend requests with environment-specific API keys."
10
10
  environment variable, never commit them to source control, and never expose them in frontend code.
11
11
  </Warning>
12
12
 
13
- ## Create an API key
13
+ ## Find your API keys
14
14
 
15
- Create a separate named key for each service or integration that accesses Trigger.dev.
15
+ Open your project in the dashboard, select an environment, and open the [**API keys**](https://cloud.trigger.dev/_/apikeys) page.
16
16
 
17
- API keys belong to one environment. A Development key cannot access Production, and a Production key cannot access Staging. Every team member has their own Development environment, so create local-development keys in your own environment.
17
+ API keys belong to one environment. A Development key cannot access Production, and a Production key cannot access Staging.
18
18
 
19
19
  <Note>
20
- Creating and revoking keys requires permission to manage API keys for the selected environment.
21
- The dashboard disables these actions when your role does not have permission.
20
+ Every team member has their own Development environment and keys. Copy the Development key from
21
+ your own API keys page so local requests run against your machine.
22
22
  </Note>
23
23
 
24
- <Steps titleSize="h3">
25
- <Step title="Open the API keys page">
26
- Select the project and environment the integration needs to access, then open [**API keys**](https://cloud.trigger.dev/_/apikeys).
27
- </Step>
28
- <Step title="Create the key">
29
- Click **New API key**, enter a descriptive name, and optionally set an expiration date. Names can
30
- contain up to 64 characters.
31
- </Step>
32
- <Step title="Choose its access">
33
- Select the narrowest access preset that supports the integration. For task-aware presets, choose
34
- all tasks or up to 10 task identifiers.
35
- </Step>
36
- <Step title="Copy and store the secret">
37
- Copy the key into your secret manager or backend environment. Trigger.dev shows the complete
38
- value only once.
39
- </Step>
40
- </Steps>
41
-
42
24
  ## Configure the SDK
43
25
 
44
26
  Set `TRIGGER_SECRET_KEY` in your backend environment. The SDK reads it automatically for operations such as triggering tasks and retrieving runs.
@@ -67,12 +49,38 @@ await tasks.trigger<typeof sendEmail>("send-email", {
67
49
  If you self-host Trigger.dev, set `TRIGGER_API_URL` or pass `baseURL` to `configure`:
68
50
 
69
51
  ```bash .env
70
- TRIGGER_SECRET_KEY="tr_prod_sk_…"
52
+ TRIGGER_SECRET_KEY="tr_prod_…"
71
53
  TRIGGER_API_URL="https://trigger.example.com"
72
54
  ```
73
55
 
74
56
  The default API URL is `https://api.trigger.dev`.
75
57
 
58
+ ## Create a key
59
+
60
+ Create a separate key for each service or integration that accesses Trigger.dev.
61
+
62
+ <Note>
63
+ Creating and revoking keys requires permission to manage API keys for the selected environment.
64
+ The dashboard disables these actions when your role does not have permission.
65
+ </Note>
66
+
67
+ <Steps titleSize="h3">
68
+ <Step title="Open the API keys page">
69
+ Select the project and environment the integration needs to access, then open [**API keys**](https://cloud.trigger.dev/_/apikeys).
70
+ </Step>
71
+ <Step title="Create the key">
72
+ Click **New API key**, enter a descriptive name, and optionally set an expiration date. Names can
73
+ contain up to 64 characters.
74
+ </Step>
75
+ <Step title="Choose its access">
76
+ Select an access preset. For task-aware presets, choose all tasks or up to 10 task identifiers.
77
+ </Step>
78
+ <Step title="Copy and store the secret">
79
+ Copy the key into your secret manager or backend environment. Trigger.dev shows the complete
80
+ value only once.
81
+ </Step>
82
+ </Steps>
83
+
76
84
  ## Access presets
77
85
 
78
86
  Access presets define what a key can do. Some presets require a paid plan. The dashboard shows which presets your organization can use — see [pricing](https://trigger.dev/pricing).
@@ -116,18 +124,28 @@ Revoking a key takes effect immediately and cannot be reversed. Requests using t
116
124
 
117
125
  Removing a team member does not revoke keys they created. Review and revoke their keys separately when their access changes.
118
126
 
127
+ ## Root keys
128
+
129
+ <Warning>
130
+ Root keys are legacy, and are likely to be deprecated in the future. We recommend against using them.
131
+ </Warning>
132
+
133
+ Each environment has a single legacy root key. It can be regenerated, which creates a new value immediately. The previous root key remains valid for 24 hours so you can update services without downtime, then stops authenticating.
134
+
135
+ Public access tokens signed with the previous root key remain valid until the earlier of their own expiration and the end of the 24-hour grace period.
136
+
119
137
  ## Create public access tokens
120
138
 
121
139
  API keys can be used to create scoped [Public Access Tokens](/realtime/auth) using `auth.createPublicToken()`.
122
140
 
123
- Use `@trigger.dev/sdk` version 4.5.8 or later to create public tokens with environment API keys. Public tokens have the following restrictions:
141
+ To do so with the newer non-root keys, you must use `@trigger.dev/sdk` version 4.5.8 or later. Creating public tokens with non-root keys has the following restrictions:
124
142
 
125
143
  - The token must request at least one scope.
126
144
  - Its scopes cannot exceed the key's access.
127
145
  - Its expiration cannot exceed 30 days.
128
146
 
129
147
  <Note>
130
- Revoking or expiring an API key does not revoke tokens it already created. Those tokens remain valid until their own expiration.
148
+ Revoking or expiring an API key does not revoke tokens it already created. Those tokens remain valid until their own expiration, unless the environment's root key is regenerated.
131
149
  </Note>
132
150
 
133
151
  ## Target Preview and Development branches
@@ -145,7 +163,7 @@ The SDK sends the branch automatically. When calling the API directly, send the
145
163
 
146
164
  Self-hosted installations support multiple keys with **No restrictions**. The restricted access presets are available in Trigger.dev Cloud.
147
165
 
148
- Keep your instance and SDK current before creating keys. Calling a public-token API with a key on a server that does not support server-minted tokens returns an upgrade error. Upgrade the instance before creating public tokens with an environment API key.
166
+ Keep your instance and SDK current before creating keys. Calling a public-token API with a key on a server that does not support server-minted tokens returns an upgrade error; use the root key until the server is upgraded.
149
167
 
150
168
  ## Security recommendations
151
169
 
@@ -63,12 +63,6 @@ export default defineConfig({
63
63
 
64
64
  In this example we're using env vars from [Infisical](https://infisical.com).
65
65
 
66
- <Tip>
67
- Infisical also offers a native [Secret Sync](/deploy-environment-variables#infisical-secret-sync)
68
- that pushes secrets to Trigger.dev without a build extension or a redeploy. Use `syncEnvVars` when
69
- you want to resolve secrets at deploy time in code, or for a service without a native sync.
70
- </Tip>
71
-
72
66
  ```ts trigger.config.ts
73
67
  import { defineConfig } from "@trigger.dev/sdk";
74
68
  import { syncEnvVars } from "@trigger.dev/build/extensions/core";
@@ -184,35 +184,14 @@ For more information about the context object, see the [Context documentation](/
184
184
 
185
185
  ### Sync env vars from another service
186
186
 
187
- There are two ways to pull secrets from another service into Trigger.dev: a native **Secret Sync** (currently [Infisical](https://infisical.com)), or the `syncEnvVars` build extension for any other service.
188
-
189
- #### Infisical Secret Sync
190
-
191
- If your secrets live in [Infisical](https://infisical.com), sync them natively, without a build extension or a redeploy. You configure the sync in the Infisical dashboard, and it pushes secrets straight to your [Environment Variables page](#in-the-dashboard) in Trigger.dev. When a secret changes in Infisical the sync updates the matching variable, and your tasks pick up the new value on their next run.
192
-
193
- Set it up in Infisical in two steps:
194
-
195
- 1. Add a **Trigger.dev App Connection** using a Trigger.dev Personal Access Token from your account settings. Self-hosted instances are supported.
196
- 2. Create a **Secret Sync**: choose the connection, pick the target organization, project and environment (Production, Staging, Development, or Preview), and set the secret path to sync.
197
-
198
- Follow the [Trigger.dev Secret Sync guide](https://infisical.com/docs/integrations/secret-syncs/trigger-dev) in the Infisical docs for the full walkthrough.
199
-
200
- <Note>
201
- A Secret Sync only overwrites the keys it manages, leaving variables you set manually untouched.
202
- Synced variables are marked as [secret](#secret-environment-variables) by default, so they appear
203
- redacted on the Environment Variables page.
204
- </Note>
205
-
206
- #### Using the `syncEnvVars` build extension
207
-
208
- For any other service, use our `syncEnvVars` build extension in your `trigger.config` file to resolve secrets at deploy time.
187
+ You could use the SDK functions above but it's much easier to use our `syncEnvVars` build extension in your `trigger.config` file.
209
188
 
210
189
  <Note>
211
190
  To use the `syncEnvVars` build extension, you should first install the `@trigger.dev/build`
212
191
  package into your devDependencies.
213
192
  </Note>
214
193
 
215
- In this example we're using env vars from [Infisical](https://infisical.com), but you can adapt it to any secrets manager.
194
+ In this example we're using env vars from [Infisical](https://infisical.com).
216
195
 
217
196
  ```ts trigger.config.ts
218
197
  import { defineConfig } from "@trigger.dev/sdk";
@@ -69,10 +69,14 @@ Now if you visit your Trigger.dev dashboard you should see the new version deplo
69
69
 
70
70
  ## Triggering deployed tasks
71
71
 
72
- Once you have deployed your tasks, open the API Keys page for the Production environment and create a named key with **Trigger only** access. Set the key as `TRIGGER_SECRET_KEY` in your backend environment. Tasks triggered with this key run against the deployed Production version:
72
+ Once you have deployed your tasks, you can trigger tasks exactly the same way you did locally, but with the "PROD" API key:
73
+
74
+ ![Trigger.dev dashboard showing the API key](/deployment/api-key.png)
75
+
76
+ Copy the API key from the dashboard and set the `TRIGGER_SECRET_KEY` environment variable, and then any tasks you trigger will run against the deployed version:
73
77
 
74
78
  ```txt .env
75
- TRIGGER_SECRET_KEY="tr_prod_sk_abc123"
79
+ TRIGGER_SECRET_KEY="tr_prod_abc123"
76
80
  ```
77
81
 
78
82
  Now you can trigger your tasks:
@@ -176,10 +180,10 @@ This will create an entirely new version of your tasks for the `staging` environ
176
180
 
177
181
  ![Trigger.dev dashboard showing the staging environment](/deployment/staging-deploy.png)
178
182
 
179
- To trigger tasks against Staging, create a named key in the Staging environment with **Trigger only** access and set it as `TRIGGER_SECRET_KEY`:
183
+ Now you can trigger tasks against the staging environment by setting the `TRIGGER_SECRET_KEY` environment variable to the staging API key:
180
184
 
181
185
  ```txt .env
182
- TRIGGER_SECRET_KEY="tr_stg_sk_abcd123"
186
+ TRIGGER_SECRET_KEY="tr_stg_abcd123"
183
187
  ```
184
188
 
185
189
  For additional environments beyond `prod` and `staging`, you can use [preview branches](/deployment/preview-branches), which allow you to create isolated environments for each branch of your code.
@@ -15,7 +15,7 @@ The process to use preview branches looks like this:
15
15
 
16
16
  1. Create a preview branch
17
17
  2. Deploy to the preview branch (1+ times)
18
- 3. Create a named **Trigger only** API key in the Preview environment, then trigger runs using the key (`TRIGGER_SECRET_KEY`) and branch name (`TRIGGER_PREVIEW_BRANCH`).
18
+ 3. Trigger runs using your Preview API key (`TRIGGER_SECRET_KEY`) and the branch name (`TRIGGER_PREVIEW_BRANCH`).
19
19
  4. Archive the preview branch when the branch is done.
20
20
 
21
21
  There are two main ways to do this:
@@ -41,12 +41,12 @@ For full details see our [pricing page](https://trigger.dev/pricing).
41
41
 
42
42
  ## Triggering runs and using the SDK
43
43
 
44
- Create a named API key in the Preview environment and set it as `TRIGGER_SECRET_KEY`. Set `TRIGGER_PREVIEW_BRANCH` to select the branch that receives the runs.
44
+ Before we talk about how to deploy to preview branches, one important thing to understand is that you must set the `TRIGGER_PREVIEW_BRANCH` environment variable as well as the `TRIGGER_SECRET_KEY` environment variable.
45
45
 
46
46
  When deploying to somewhere that supports `process.env` (like Node.js runtimes) you can just set the environment variables:
47
47
 
48
48
  ```bash
49
- TRIGGER_SECRET_KEY="tr_preview_sk_1234567890"
49
+ TRIGGER_SECRET_KEY="tr_preview_1234567890"
50
50
  TRIGGER_PREVIEW_BRANCH="your-branch-name"
51
51
  ```
52
52
 
@@ -57,7 +57,7 @@ import { configure } from "@trigger.dev/sdk";
57
57
  import { myTask } from "./trigger/myTasks";
58
58
 
59
59
  configure({
60
- secretKey: "tr_preview_sk_1234567890", // WARNING: Never actually hardcode your secret key like this
60
+ secretKey: "tr_preview_1234567890", // WARNING: Never actually hardcode your secret key like this
61
61
  previewBranch: "your-branch-name",
62
62
  });
63
63