@trigger.dev/sdk 0.0.0-prerelease-20260827143549 → 0.0.0-prerelease-20260828141059

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.
@@ -171,6 +171,10 @@ export type ChatWriter = {
171
171
  /** Merge another stream's chunks into the chat stream. */
172
172
  merge(stream: ReadableStream<UIMessageChunk>): void;
173
173
  };
174
+ type ChatCustomAgentClientDataErrorHandler = (event: {
175
+ error: unknown;
176
+ payload: ChatTaskWirePayload;
177
+ }) => Promise<void> | void;
174
178
  /**
175
179
  * The payload shape passed to the `chatAgent` run function.
176
180
  *
@@ -1120,8 +1124,11 @@ export type RecoveryBootEvent<TUIM extends UIMessage = UIMessage> = {
1120
1124
  /**
1121
1125
  * User messages that arrived on `session.in` past the cursor — i.e.
1122
1126
  * the message(s) the predecessor was processing or had queued when
1123
- * it died. The runtime's default is to re-dispatch each as a fresh
1124
- * turn after the chain is restored. Return a different list via
1127
+ * it died. The runtime's default re-dispatches each as a fresh turn
1128
+ * after the chain is restored, except when a `partialAssistant` is
1129
+ * present AND there are two or more of them: the first is then
1130
+ * spliced into the chain (as the question the partial was answering)
1131
+ * rather than dispatched. Return a different list via
1125
1132
  * `recoveredTurns` to skip / reorder / collapse them.
1126
1133
  */
1127
1134
  inFlightUsers: TUIM[];
@@ -1165,8 +1172,12 @@ export type RecoveryBootResult<TUIM extends UIMessage = UIMessage> = {
1165
1172
  chain?: TUIM[];
1166
1173
  /**
1167
1174
  * The user messages to re-dispatch as fresh turns after the chain is
1168
- * restored. Default: `inFlightUsers` (re-process every in-flight
1169
- * user). Return `[]` to suppress all of them; return a filtered /
1175
+ * restored. Default: `inFlightUsers.slice(1)` when a
1176
+ * `partialAssistant` is present and there are two or more in-flight
1177
+ * users (the first one is spliced into the chain instead), otherwise
1178
+ * `inFlightUsers` — including the single-user case, where the
1179
+ * interrupted user is re-dispatched and the orphan partial is
1180
+ * dropped. Return `[]` to suppress all of them; return a filtered /
1170
1181
  * reordered subset to skip specific ones.
1171
1182
  */
1172
1183
  recoveredTurns?: TUIM[];
@@ -1684,8 +1695,13 @@ export type ChatAgentOptions<TIdentifier extends string, TClientDataSchema exten
1684
1695
  * customer's DB.
1685
1696
  *
1686
1697
  * Defaults (returned when the hook is omitted or returns no field):
1687
- * - `chain` = `settledMessages` (drop the orphan partial)
1688
- * - `recoveredTurns` = `inFlightUsers` (re-dispatch every user)
1698
+ * - With two or more in-flight users, the partial and the user it
1699
+ * was answering are spliced into the chain:
1700
+ * `chain` = `[...settledMessages, inFlightUsers[0], partialAssistant]`
1701
+ * and `recoveredTurns` = `inFlightUsers.slice(1)`.
1702
+ * - Otherwise `chain` = `settledMessages` (drop the orphan partial)
1703
+ * and `recoveredTurns` = `inFlightUsers` (re-dispatch every user)
1704
+ * — so a single interrupted user is answered on the new run.
1689
1705
  *
1690
1706
  * @example
1691
1707
  * ```ts
@@ -2096,8 +2112,48 @@ export type ChatAgentOptions<TIdentifier extends string, TClientDataSchema exten
2096
2112
  * });
2097
2113
  * ```
2098
2114
  */
2099
- type ChatCustomAgentOptions<TIdentifier extends string, TClientDataSchema extends TaskSchema | undefined = undefined, TUIMessage extends UIMessage = UIMessage> = Omit<TaskOptions<TIdentifier, ChatTaskWirePayload<TUIMessage, inferSchemaIn<TClientDataSchema>>, unknown>, "triggerSource" | "agentConfig"> & {
2115
+ type ChatCustomAgentOptions<TIdentifier extends string, TClientDataSchema extends TaskSchema | undefined = undefined, TUIMessage extends UIMessage = UIMessage> = Omit<TaskOptions<TIdentifier, ChatTaskWirePayload<TUIMessage, inferSchemaIn<TClientDataSchema>>, unknown>, "triggerSource" | "agentConfig" | "run"> & {
2116
+ /**
2117
+ * Schema for validating `metadata` from the frontend.
2118
+ *
2119
+ * The initial payload and later `chat.messages` frames are parsed before
2120
+ * user code receives them. Invalid submitted turns and async reads write an
2121
+ * error chunk followed by `turn-complete`. Messageless boots and active
2122
+ * subscriptions use `onClientDataValidationError` and the task log because
2123
+ * there is no submitted turn to complete or a response may still be streaming.
2124
+ * This validates `metadata` only; raw `action` payloads remain `unknown`.
2125
+ */
2100
2126
  clientDataSchema?: TClientDataSchema;
2127
+ /**
2128
+ * Called when a custom-agent input fails `clientDataSchema` validation.
2129
+ *
2130
+ * Submitted turns and async reads also write an error chunk followed by
2131
+ * `turn-complete`. Messageless boots and active `chat.messages.on()`
2132
+ * subscriptions are reported through this callback and the task log only.
2133
+ *
2134
+ * `payload.metadata` is typed `unknown`: this callback only fires when
2135
+ * the metadata failed to parse, so it can be any shape the client sent.
2136
+ */
2137
+ onClientDataValidationError?: (event: {
2138
+ error: unknown;
2139
+ payload: ChatTaskWirePayload<TUIMessage, unknown>;
2140
+ }) => Promise<void> | void;
2141
+ /**
2142
+ * When a frame that arrived mid-turn fails `clientDataSchema` validation,
2143
+ * decides when the terminal error reaches the client.
2144
+ *
2145
+ * - `"turn-end"` (default) waits until the turn has closed. A terminal error
2146
+ * written into a live response can close it, so this keeps a bad client
2147
+ * send from truncating an answer the user is already reading.
2148
+ * - `"arrival"` writes it as soon as validation fails, which surfaces the
2149
+ * problem sooner at the cost of ending the response in progress.
2150
+ *
2151
+ * `onClientDataValidationError` and the task log fire on arrival either way;
2152
+ * this only governs the stream-visible error. The frame is never delivered as
2153
+ * a turn in either mode.
2154
+ */
2155
+ clientDataReportErrorAt?: "turn-end" | "arrival";
2156
+ run: TaskOptions<TIdentifier, ChatTaskWirePayload<TUIMessage, inferSchemaOut<TClientDataSchema>>, unknown>["run"];
2101
2157
  };
2102
2158
  declare function chatCustomAgent<TIdentifier extends string, TClientDataSchema extends TaskSchema | undefined = undefined, TUIMessage extends UIMessage = UIMessage>(options: ChatCustomAgentOptions<TIdentifier, TClientDataSchema, TUIMessage>): Task<TIdentifier, ChatTaskWirePayload<TUIMessage, inferSchemaIn<TClientDataSchema>>, unknown>;
2103
2159
  declare function chatAgent<TIdentifier extends string, TClientDataSchema extends TaskSchema | undefined = undefined, TUIMessage extends UIMessage = UIMessage, TActionSchema extends TaskSchema | undefined = undefined, TTools extends ToolSet = ToolSet>(options: ChatAgentOptions<TIdentifier, TClientDataSchema, TUIMessage, TActionSchema, TTools>): Task<TIdentifier, ChatTaskWirePayload<TUIMessage, inferSchemaIn<TClientDataSchema>>, unknown>;
@@ -2130,9 +2186,29 @@ export type ChatWithUIMessageConfig<TUIM extends UIMessage = UIMessage> = {
2130
2186
  export interface ChatBuilder<TUIMessage extends UIMessage = UIMessage, TClientDataSchema extends TaskSchema | undefined = undefined> {
2131
2187
  /** Fix the UI message type. Returns a new builder preserving all accumulated state. */
2132
2188
  withUIMessage<TUIM extends UIMessage = UIMessage>(config?: ChatWithUIMessageConfig<TUIM>): ChatBuilder<TUIM, TClientDataSchema>;
2133
- /** Fix the client data schema. Returns a new builder preserving all accumulated state. */
2189
+ /**
2190
+ * Fix the client data schema, and how validation failures are handled.
2191
+ * Returns a new builder preserving all accumulated state.
2192
+ */
2134
2193
  withClientData<TSchema extends TaskSchema>(config: {
2135
2194
  schema: TSchema;
2195
+ /**
2196
+ * When a frame that arrived mid-turn fails validation, decides when the
2197
+ * client-visible error is written.
2198
+ *
2199
+ * `"turn-end"` (default) waits for the turn to close, so a bad send cannot
2200
+ * truncate an answer already being read. `"arrival"` writes it as soon as
2201
+ * validation fails, ending the response in progress.
2202
+ *
2203
+ * `onValidationError` and the task log fire on arrival either way, and the
2204
+ * frame is never delivered as a turn.
2205
+ */
2206
+ reportErrorAt?: "turn-end" | "arrival";
2207
+ /** Called when an input fails validation. Composes with the task-level hook. */
2208
+ onValidationError?: (event: {
2209
+ error: unknown;
2210
+ payload: ChatTaskWirePayload<TUIMessage, unknown>;
2211
+ }) => Promise<void> | void;
2136
2212
  }): ChatBuilder<TUIMessage, TSchema>;
2137
2213
  /** Register a builder-level `onBoot` hook. Runs before the task-level hook if both are set. */
2138
2214
  onBoot(fn: (event: BootEvent<inferSchemaOut<TClientDataSchema>>) => Promise<void> | void): ChatBuilder<TUIMessage, TClientDataSchema>;
@@ -2170,7 +2246,7 @@ export interface ChatBuilder<TUIMessage extends UIMessage = UIMessage, TClientDa
2170
2246
  * Builder hooks (`onPreload`, `onChatStart`, etc.) are not applied —
2171
2247
  * those are managed-lifecycle concepts handled by `.agent()`.
2172
2248
  */
2173
- customAgent: [TClientDataSchema] extends [undefined] ? <TId extends string>(options: ChatCustomAgentOptions<TId, undefined, TUIMessage>) => Task<TId, ChatTaskWirePayload<TUIMessage, undefined>, unknown> : <TId extends string>(options: ChatCustomAgentOptions<TId, TClientDataSchema, TUIMessage>) => Task<TId, ChatTaskWirePayload<TUIMessage, inferSchemaIn<TClientDataSchema>>, unknown>;
2249
+ customAgent: [TClientDataSchema] extends [undefined] ? <TId extends string>(options: ChatCustomAgentOptions<TId, undefined, TUIMessage>) => Task<TId, ChatTaskWirePayload<TUIMessage, undefined>, unknown> : <TId extends string>(options: Omit<ChatCustomAgentOptions<TId, TClientDataSchema, TUIMessage>, "clientDataSchema">) => Task<TId, ChatTaskWirePayload<TUIMessage, inferSchemaIn<TClientDataSchema>>, unknown>;
2174
2250
  }
2175
2251
  /**
2176
2252
  * Fix the UI message type for a chat task (AI SDK `UIMessage` generics) while
@@ -2214,6 +2290,8 @@ declare function withUIMessage<TUIM extends UIMessage = UIMessage>(config?: Chat
2214
2290
  */
2215
2291
  declare function withClientData<TSchema extends TaskSchema>(config: {
2216
2292
  schema: TSchema;
2293
+ reportErrorAt?: "turn-end" | "arrival";
2294
+ onValidationError?: ChatCustomAgentClientDataErrorHandler;
2217
2295
  }): ChatBuilder<UIMessage, TSchema>;
2218
2296
  /**
2219
2297
  * Override the turn timeout for subsequent turns in the current run.
@@ -2340,6 +2418,37 @@ declare function isStopped(): boolean;
2340
2418
  * ```
2341
2419
  */
2342
2420
  declare function requestUpgrade(): void;
2421
+ /**
2422
+ * Hand off the current custom agent Session to a fresh run.
2423
+ *
2424
+ * This is the low-level handoff for a fully hand-rolled
2425
+ * `chat.customAgent()` loop. This method rejects while a
2426
+ * `chat.createSession()` iterator is active. Close the iterator before calling
2427
+ * it. If `return()` races an active `next()`, it waits for that read to settle
2428
+ * before releasing the handoff guard. Call only between turns and after
2429
+ * detaching input listeners for the old run. If the old run completed its
2430
+ * current turn, persist its state and call {@link chatWriteTurnComplete} before
2431
+ * handing off.
2432
+ * Do not write a new turn boundary after input that the continuation run should
2433
+ * process has been dispatched: the boundary acknowledges that input.
2434
+ *
2435
+ * The server starts the continuation run but does not stop this run, so return
2436
+ * from the task immediately after awaiting this function. The promise rejects
2437
+ * if the server cannot complete the handoff.
2438
+ *
2439
+ * Pending Session input that the old run has not consumed remains on the
2440
+ * durable `.in` stream and is delivered to the continuation run.
2441
+ *
2442
+ * @example
2443
+ * ```ts
2444
+ * // Detach any chat.messages.on() subscriptions you created.
2445
+ * await persistMessages();
2446
+ * await chat.writeTurnComplete();
2447
+ * await chat.endAndContinue();
2448
+ * return;
2449
+ * ```
2450
+ */
2451
+ declare function endAndContinue(): Promise<void>;
2343
2452
  /**
2344
2453
  * Exit the run after the current turn completes, without waiting for the
2345
2454
  * next message. Unlike {@link requestUpgrade}, no upgrade-required signal
@@ -2678,7 +2787,7 @@ export type ChatSessionOptions = {
2678
2787
  /** Configure mid-execution message injection — same options as `chat.agent({ pendingMessages })`. */
2679
2788
  pendingMessages?: PendingMessagesOptions;
2680
2789
  };
2681
- export type ChatTurn = {
2790
+ export type ChatTurn<TClientData = unknown> = {
2682
2791
  /** Turn number (0-indexed). */
2683
2792
  number: number;
2684
2793
  /** Chat session ID. */
@@ -2686,7 +2795,7 @@ export type ChatTurn = {
2686
2795
  /** What triggered this turn. */
2687
2796
  trigger: string;
2688
2797
  /** Client data from the transport (`metadata` field on the wire payload). */
2689
- clientData: unknown;
2798
+ clientData: TClientData;
2690
2799
  /** Full accumulated model messages — pass directly to `streamText`. */
2691
2800
  readonly messages: ModelMessage[];
2692
2801
  /** Full accumulated UI messages — use for persistence. */
@@ -2781,7 +2890,7 @@ export type ChatTurn = {
2781
2890
  * });
2782
2891
  * ```
2783
2892
  */
2784
- declare function createChatSession(payload: ChatTaskWirePayload, options: ChatSessionOptions): AsyncIterable<ChatTurn>;
2893
+ declare function createChatSession<TClientData = unknown>(payload: ChatTaskWirePayload<UIMessage, TClientData>, options: ChatSessionOptions): AsyncIterable<ChatTurn<TClientData>>;
2785
2894
  /**
2786
2895
  * A Proxy-backed, run-scoped data object that appears as `T` to users.
2787
2896
  * Includes helper methods for initialization, dirty tracking, and serialization.
@@ -3014,6 +3123,8 @@ export declare const chat: {
3014
3123
  isStopped: typeof isStopped;
3015
3124
  /** Request that the run exits after the current turn so the next message starts on the latest version. See {@link requestUpgrade}. */
3016
3125
  requestUpgrade: typeof requestUpgrade;
3126
+ /** Hand off a custom agent Session to a fresh run. See {@link endAndContinue}. */
3127
+ endAndContinue: typeof endAndContinue;
3017
3128
  /** Exit the run after the current turn completes, without any upgrade signal. See {@link endRun}. */
3018
3129
  endRun: typeof endRun;
3019
3130
  /** Clean up aborted parts from a UIMessage. See {@link cleanupAbortedParts}. */