@trigger.dev/sdk 0.0.0-prerelease-20260306173130 → 0.0.0-prerelease-20260310150337
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commonjs/v3/ai.d.ts +475 -8
- package/dist/commonjs/v3/ai.js +785 -40
- package/dist/commonjs/v3/ai.js.map +1 -1
- package/dist/commonjs/v3/chat.d.ts +15 -0
- package/dist/commonjs/v3/chat.js +62 -1
- package/dist/commonjs/v3/chat.js.map +1 -1
- package/dist/commonjs/v3/runs.d.ts +1 -1
- package/dist/commonjs/v3/streams.js +33 -1
- package/dist/commonjs/v3/streams.js.map +1 -1
- package/dist/commonjs/version.js +1 -1
- package/dist/esm/v3/ai.d.ts +475 -8
- package/dist/esm/v3/ai.js +785 -40
- package/dist/esm/v3/ai.js.map +1 -1
- package/dist/esm/v3/chat.d.ts +15 -0
- package/dist/esm/v3/chat.js +62 -1
- package/dist/esm/v3/chat.js.map +1 -1
- package/dist/esm/v3/streams.js +33 -1
- package/dist/esm/v3/streams.js.map +1 -1
- package/dist/esm/version.js +1 -1
- package/package.json +2 -2
package/dist/commonjs/v3/ai.d.ts
CHANGED
|
@@ -1,9 +1,24 @@
|
|
|
1
1
|
import { AnyTask, Task, type inferSchemaIn, type inferSchemaOut, type TaskIdentifier, type TaskOptions, type TaskSchema, type TaskWithSchema } from "@trigger.dev/core/v3";
|
|
2
|
-
import type { ModelMessage, UIMessage } from "ai";
|
|
3
|
-
import { Tool
|
|
2
|
+
import type { ModelMessage, UIMessage, UIMessageChunk, UIMessageStreamOptions } from "ai";
|
|
3
|
+
import { Tool } from "ai";
|
|
4
4
|
import { locals } from "./locals.js";
|
|
5
5
|
import { CHAT_MESSAGES_STREAM_ID, CHAT_STOP_STREAM_ID } from "./chat-constants.js";
|
|
6
|
-
export type ToolCallExecutionOptions =
|
|
6
|
+
export type ToolCallExecutionOptions = {
|
|
7
|
+
toolCallId: string;
|
|
8
|
+
experimental_context?: unknown;
|
|
9
|
+
/** Chat context — only present when the tool runs inside a chat.task turn. */
|
|
10
|
+
chatId?: string;
|
|
11
|
+
turn?: number;
|
|
12
|
+
continuation?: boolean;
|
|
13
|
+
clientData?: unknown;
|
|
14
|
+
};
|
|
15
|
+
/** Chat context stored in locals during each chat.task turn for auto-detection. */
|
|
16
|
+
type ChatTurnContext<TClientData = unknown> = {
|
|
17
|
+
chatId: string;
|
|
18
|
+
turn: number;
|
|
19
|
+
continuation: boolean;
|
|
20
|
+
clientData?: TClientData;
|
|
21
|
+
};
|
|
7
22
|
type ToolResultContent = Array<{
|
|
8
23
|
type: "text";
|
|
9
24
|
text: string;
|
|
@@ -18,9 +33,43 @@ export type ToolOptions<TResult> = {
|
|
|
18
33
|
declare function toolFromTask<TIdentifier extends string, TInput = void, TOutput = unknown>(task: Task<TIdentifier, TInput, TOutput>, options?: ToolOptions<TOutput>): Tool<TInput, TOutput>;
|
|
19
34
|
declare function toolFromTask<TIdentifier extends string, TTaskSchema extends TaskSchema | undefined = undefined, TOutput = unknown>(task: TaskWithSchema<TIdentifier, TTaskSchema, TOutput>, options?: ToolOptions<TOutput>): Tool<inferSchemaIn<TTaskSchema>, TOutput>;
|
|
20
35
|
declare function getToolOptionsFromMetadata(): ToolCallExecutionOptions | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* Get the current tool call ID from inside a subtask invoked via `ai.tool()`.
|
|
38
|
+
* Returns `undefined` if not running as a tool subtask.
|
|
39
|
+
*/
|
|
40
|
+
declare function getToolCallId(): string | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* Get the chat context from inside a subtask invoked via `ai.tool()` within a `chat.task`.
|
|
43
|
+
* Pass `typeof yourChatTask` as the type parameter to get typed `clientData`.
|
|
44
|
+
* Returns `undefined` if the parent is not a chat task.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* const ctx = ai.chatContext<typeof myChat>();
|
|
49
|
+
* // ctx?.clientData is typed based on myChat's clientDataSchema
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
declare function getToolChatContext<TChatTask extends AnyTask = AnyTask>(): ChatTurnContext<InferChatClientData<TChatTask>> | undefined;
|
|
53
|
+
/**
|
|
54
|
+
* Get the chat context from inside a subtask, throwing if not in a chat context.
|
|
55
|
+
* Pass `typeof yourChatTask` as the type parameter to get typed `clientData`.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```ts
|
|
59
|
+
* const ctx = ai.chatContextOrThrow<typeof myChat>();
|
|
60
|
+
* // ctx.chatId, ctx.clientData are guaranteed non-null
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
declare function getToolChatContextOrThrow<TChatTask extends AnyTask = AnyTask>(): ChatTurnContext<InferChatClientData<TChatTask>>;
|
|
21
64
|
export declare const ai: {
|
|
22
65
|
tool: typeof toolFromTask;
|
|
23
66
|
currentToolOptions: typeof getToolOptionsFromMetadata;
|
|
67
|
+
/** Get the tool call ID from inside a subtask invoked via `ai.tool()`. */
|
|
68
|
+
toolCallId: typeof getToolCallId;
|
|
69
|
+
/** Get chat context (chatId, turn, clientData, etc.) from inside a subtask of a `chat.task`. Returns undefined if not in a chat context. */
|
|
70
|
+
chatContext: typeof getToolChatContext;
|
|
71
|
+
/** Get chat context or throw if not in a chat context. Pass `typeof yourChatTask` for typed clientData. */
|
|
72
|
+
chatContextOrThrow: typeof getToolChatContextOrThrow;
|
|
24
73
|
};
|
|
25
74
|
/**
|
|
26
75
|
* Creates a public access token for a chat task.
|
|
@@ -47,6 +96,23 @@ declare function createChatAccessToken<TTask extends AnyTask>(taskId: TaskIdenti
|
|
|
47
96
|
*/
|
|
48
97
|
export declare const CHAT_STREAM_KEY = "chat";
|
|
49
98
|
export { CHAT_MESSAGES_STREAM_ID, CHAT_STOP_STREAM_ID };
|
|
99
|
+
/**
|
|
100
|
+
* The wire payload shape sent by `TriggerChatTransport`.
|
|
101
|
+
* Uses `metadata` to match the AI SDK's `ChatRequestOptions` field name.
|
|
102
|
+
*/
|
|
103
|
+
export type ChatTaskWirePayload<TMessage extends UIMessage = UIMessage, TMetadata = unknown> = {
|
|
104
|
+
messages: TMessage[];
|
|
105
|
+
chatId: string;
|
|
106
|
+
trigger: "submit-message" | "regenerate-message" | "preload";
|
|
107
|
+
messageId?: string;
|
|
108
|
+
metadata?: TMetadata;
|
|
109
|
+
/** Whether this run is continuing an existing chat whose previous run ended. */
|
|
110
|
+
continuation?: boolean;
|
|
111
|
+
/** The run ID of the previous run (only set when `continuation` is true). */
|
|
112
|
+
previousRunId?: string;
|
|
113
|
+
/** Override warm timeout for this run (seconds). Set by transport.preload(). */
|
|
114
|
+
warmTimeoutInSeconds?: number;
|
|
115
|
+
};
|
|
50
116
|
/**
|
|
51
117
|
* The payload shape passed to the `chatTask` run function.
|
|
52
118
|
*
|
|
@@ -66,12 +132,19 @@ export type ChatTaskPayload<TClientData = unknown> = {
|
|
|
66
132
|
* The trigger type:
|
|
67
133
|
* - `"submit-message"`: A new user message
|
|
68
134
|
* - `"regenerate-message"`: Regenerate the last assistant response
|
|
135
|
+
* - `"preload"`: Run was preloaded before the first message (only on turn 0)
|
|
69
136
|
*/
|
|
70
|
-
trigger: "submit-message" | "regenerate-message";
|
|
137
|
+
trigger: "submit-message" | "regenerate-message" | "preload";
|
|
71
138
|
/** The ID of the message to regenerate (only for `"regenerate-message"`) */
|
|
72
139
|
messageId?: string;
|
|
73
140
|
/** Custom data from the frontend (passed via `metadata` on `sendMessage()` or the transport). */
|
|
74
141
|
clientData?: TClientData;
|
|
142
|
+
/** Whether this run is continuing an existing chat (previous run timed out or was cancelled). False for brand new chats. */
|
|
143
|
+
continuation: boolean;
|
|
144
|
+
/** The run ID of the previous run (only set when `continuation` is true). */
|
|
145
|
+
previousRunId?: string;
|
|
146
|
+
/** Whether this run was preloaded before the first message. */
|
|
147
|
+
preloaded: boolean;
|
|
75
148
|
};
|
|
76
149
|
/**
|
|
77
150
|
* Abort signals provided to the `chatTask` run function.
|
|
@@ -108,6 +181,19 @@ export type PipeChatOptions = {
|
|
|
108
181
|
/** Override the default span name for this operation. */
|
|
109
182
|
spanName?: string;
|
|
110
183
|
};
|
|
184
|
+
/**
|
|
185
|
+
* Options for customizing the `toUIMessageStream()` call used when piping
|
|
186
|
+
* `streamText` results to the frontend.
|
|
187
|
+
*
|
|
188
|
+
* Set static defaults via `uiMessageStreamOptions` on `chat.task()`, or
|
|
189
|
+
* override per-turn via `chat.setUIMessageStreamOptions()`.
|
|
190
|
+
*
|
|
191
|
+
* `onFinish`, `originalMessages`, and `generateMessageId` are omitted because
|
|
192
|
+
* they are managed internally for response capture and message accumulation.
|
|
193
|
+
* Use `streamText`'s `onFinish` for custom finish handling, or drop down to
|
|
194
|
+
* raw task mode with `chat.pipe()` for full control.
|
|
195
|
+
*/
|
|
196
|
+
export type ChatUIMessageStreamOptions = Omit<UIMessageStreamOptions<UIMessage>, "onFinish" | "originalMessages" | "generateMessageId">;
|
|
111
197
|
/**
|
|
112
198
|
* An object with a `toUIMessageStream()` method (e.g. `StreamTextResult` from `streamText()`).
|
|
113
199
|
*/
|
|
@@ -168,6 +254,19 @@ declare function pipeChat(source: UIMessageStreamable | AsyncIterable<unknown> |
|
|
|
168
254
|
* emits a control chunk and suspends via `messagesInput.wait()`. The frontend
|
|
169
255
|
* transport resumes the same run by sending the next message via input streams.
|
|
170
256
|
*/
|
|
257
|
+
/**
|
|
258
|
+
* Event passed to the `onPreload` callback.
|
|
259
|
+
*/
|
|
260
|
+
export type PreloadEvent<TClientData = unknown> = {
|
|
261
|
+
/** The unique identifier for the chat session. */
|
|
262
|
+
chatId: string;
|
|
263
|
+
/** The Trigger.dev run ID for this conversation. */
|
|
264
|
+
runId: string;
|
|
265
|
+
/** A scoped access token for this chat run. */
|
|
266
|
+
chatAccessToken: string;
|
|
267
|
+
/** Custom data from the frontend. */
|
|
268
|
+
clientData?: TClientData;
|
|
269
|
+
};
|
|
171
270
|
/**
|
|
172
271
|
* Event passed to the `onChatStart` callback.
|
|
173
272
|
*/
|
|
@@ -182,6 +281,12 @@ export type ChatStartEvent<TClientData = unknown> = {
|
|
|
182
281
|
runId: string;
|
|
183
282
|
/** A scoped access token for this chat run. Persist this for frontend reconnection. */
|
|
184
283
|
chatAccessToken: string;
|
|
284
|
+
/** Whether this run is continuing an existing chat (previous run timed out or was cancelled). False for brand new chats. */
|
|
285
|
+
continuation: boolean;
|
|
286
|
+
/** The run ID of the previous run (only set when `continuation` is true). */
|
|
287
|
+
previousRunId?: string;
|
|
288
|
+
/** Whether this run was preloaded before the first message. */
|
|
289
|
+
preloaded: boolean;
|
|
185
290
|
};
|
|
186
291
|
/**
|
|
187
292
|
* Event passed to the `onTurnStart` callback.
|
|
@@ -201,6 +306,12 @@ export type TurnStartEvent<TClientData = unknown> = {
|
|
|
201
306
|
chatAccessToken: string;
|
|
202
307
|
/** Custom data from the frontend. */
|
|
203
308
|
clientData?: TClientData;
|
|
309
|
+
/** Whether this run is continuing an existing chat (previous run timed out or was cancelled). False for brand new chats. */
|
|
310
|
+
continuation: boolean;
|
|
311
|
+
/** The run ID of the previous run (only set when `continuation` is true). */
|
|
312
|
+
previousRunId?: string;
|
|
313
|
+
/** Whether this run was preloaded before the first message. */
|
|
314
|
+
preloaded: boolean;
|
|
204
315
|
};
|
|
205
316
|
/**
|
|
206
317
|
* Event passed to the `onTurnComplete` callback.
|
|
@@ -225,8 +336,14 @@ export type TurnCompleteEvent<TClientData = unknown> = {
|
|
|
225
336
|
* Useful for inserting individual message records instead of overwriting the full history.
|
|
226
337
|
*/
|
|
227
338
|
newUIMessages: UIMessage[];
|
|
228
|
-
/** The assistant's response for this turn
|
|
339
|
+
/** The assistant's response for this turn, with aborted parts cleaned up when `stopped` is true. Undefined if `pipeChat` was used manually. */
|
|
229
340
|
responseMessage: UIMessage | undefined;
|
|
341
|
+
/**
|
|
342
|
+
* The raw assistant response before abort cleanup. Includes incomplete tool parts
|
|
343
|
+
* (`input-available`, `partial-call`) and streaming reasoning/text parts.
|
|
344
|
+
* Use this if you need custom cleanup logic. Same as `responseMessage` when not stopped.
|
|
345
|
+
*/
|
|
346
|
+
rawResponseMessage: UIMessage | undefined;
|
|
230
347
|
/** The turn number (0-indexed). */
|
|
231
348
|
turn: number;
|
|
232
349
|
/** The Trigger.dev run ID for this conversation. */
|
|
@@ -237,6 +354,14 @@ export type TurnCompleteEvent<TClientData = unknown> = {
|
|
|
237
354
|
lastEventId?: string;
|
|
238
355
|
/** Custom data from the frontend. */
|
|
239
356
|
clientData?: TClientData;
|
|
357
|
+
/** Whether the user stopped generation during this turn. */
|
|
358
|
+
stopped: boolean;
|
|
359
|
+
/** Whether this run is continuing an existing chat (previous run timed out or was cancelled). False for brand new chats. */
|
|
360
|
+
continuation: boolean;
|
|
361
|
+
/** The run ID of the previous run (only set when `continuation` is true). */
|
|
362
|
+
previousRunId?: string;
|
|
363
|
+
/** Whether this run was preloaded before the first message. */
|
|
364
|
+
preloaded: boolean;
|
|
240
365
|
};
|
|
241
366
|
export type ChatTaskOptions<TIdentifier extends string, TClientDataSchema extends TaskSchema | undefined = undefined> = Omit<TaskOptions<TIdentifier, ChatTaskWirePayload, unknown>, "run"> & {
|
|
242
367
|
/**
|
|
@@ -268,6 +393,21 @@ export type ChatTaskOptions<TIdentifier extends string, TClientDataSchema extend
|
|
|
268
393
|
* the stream is automatically piped to the frontend.
|
|
269
394
|
*/
|
|
270
395
|
run: (payload: ChatTaskRunPayload<inferSchemaOut<TClientDataSchema>>) => Promise<unknown>;
|
|
396
|
+
/**
|
|
397
|
+
* Called when a preloaded run starts, before the first message arrives.
|
|
398
|
+
*
|
|
399
|
+
* Use this to initialize state, create DB records, and load context early —
|
|
400
|
+
* so everything is ready when the user's first message comes through.
|
|
401
|
+
*
|
|
402
|
+
* @example
|
|
403
|
+
* ```ts
|
|
404
|
+
* onPreload: async ({ chatId, clientData }) => {
|
|
405
|
+
* await db.chat.create({ data: { id: chatId } });
|
|
406
|
+
* userContext.init(await loadUser(clientData.userId));
|
|
407
|
+
* }
|
|
408
|
+
* ```
|
|
409
|
+
*/
|
|
410
|
+
onPreload?: (event: PreloadEvent<inferSchemaOut<TClientDataSchema>>) => Promise<void> | void;
|
|
271
411
|
/**
|
|
272
412
|
* Called on the first turn (turn 0) of a new run, before the `run` function executes.
|
|
273
413
|
*
|
|
@@ -346,6 +486,52 @@ export type ChatTaskOptions<TIdentifier extends string, TClientDataSchema extend
|
|
|
346
486
|
* @default "1h"
|
|
347
487
|
*/
|
|
348
488
|
chatAccessTokenTTL?: string;
|
|
489
|
+
/**
|
|
490
|
+
* How long (in seconds) to keep the run warm after `onPreload` fires,
|
|
491
|
+
* waiting for the first message before suspending.
|
|
492
|
+
*
|
|
493
|
+
* Only applies to preloaded runs (triggered via `transport.preload()`).
|
|
494
|
+
*
|
|
495
|
+
* @default Same as `warmTimeoutInSeconds`
|
|
496
|
+
*/
|
|
497
|
+
preloadWarmTimeoutInSeconds?: number;
|
|
498
|
+
/**
|
|
499
|
+
* How long to wait (suspended) for the first message after a preloaded run starts.
|
|
500
|
+
* If no message arrives within this time, the run ends.
|
|
501
|
+
*
|
|
502
|
+
* Only applies to preloaded runs.
|
|
503
|
+
*
|
|
504
|
+
* @default Same as `turnTimeout`
|
|
505
|
+
*/
|
|
506
|
+
preloadTimeout?: string;
|
|
507
|
+
/**
|
|
508
|
+
* Default options for `toUIMessageStream()` when auto-piping or using
|
|
509
|
+
* `turn.complete()` / `chat.pipeAndCapture()`.
|
|
510
|
+
*
|
|
511
|
+
* Controls how the `StreamTextResult` is converted to a `UIMessageChunk`
|
|
512
|
+
* stream — error handling, reasoning/source visibility, metadata, etc.
|
|
513
|
+
*
|
|
514
|
+
* Can be overridden per-turn by calling `chat.setUIMessageStreamOptions()`
|
|
515
|
+
* inside `run()` or lifecycle hooks. Per-turn values are merged on top
|
|
516
|
+
* of these defaults (per-turn wins on conflicts).
|
|
517
|
+
*
|
|
518
|
+
* `onFinish`, `originalMessages`, and `generateMessageId` are managed
|
|
519
|
+
* internally and cannot be overridden here. Use `streamText`'s `onFinish`
|
|
520
|
+
* for custom finish handling, or drop to raw task mode for full control.
|
|
521
|
+
*
|
|
522
|
+
* @example
|
|
523
|
+
* ```ts
|
|
524
|
+
* chat.task({
|
|
525
|
+
* id: "my-chat",
|
|
526
|
+
* uiMessageStreamOptions: {
|
|
527
|
+
* sendReasoning: true,
|
|
528
|
+
* onError: (error) => error instanceof Error ? error.message : "An error occurred.",
|
|
529
|
+
* },
|
|
530
|
+
* run: async ({ messages, signal }) => { ... },
|
|
531
|
+
* });
|
|
532
|
+
* ```
|
|
533
|
+
*/
|
|
534
|
+
uiMessageStreamOptions?: ChatUIMessageStreamOptions;
|
|
349
535
|
};
|
|
350
536
|
/**
|
|
351
537
|
* Creates a Trigger.dev task pre-configured for AI SDK chat.
|
|
@@ -427,6 +613,259 @@ declare function setTurnTimeoutInSeconds(seconds: number): void;
|
|
|
427
613
|
* ```
|
|
428
614
|
*/
|
|
429
615
|
declare function setWarmTimeoutInSeconds(seconds: number): void;
|
|
616
|
+
/**
|
|
617
|
+
* Override the `toUIMessageStream()` options for the current turn.
|
|
618
|
+
*
|
|
619
|
+
* These options control how the `StreamTextResult` is converted to a
|
|
620
|
+
* `UIMessageChunk` stream — error handling, reasoning/source visibility,
|
|
621
|
+
* message metadata, etc.
|
|
622
|
+
*
|
|
623
|
+
* Per-turn options are merged on top of the static `uiMessageStreamOptions`
|
|
624
|
+
* set on `chat.task()`. Per-turn values win on conflicts.
|
|
625
|
+
*
|
|
626
|
+
* @example
|
|
627
|
+
* ```ts
|
|
628
|
+
* run: async ({ messages, signal }) => {
|
|
629
|
+
* chat.setUIMessageStreamOptions({
|
|
630
|
+
* sendReasoning: true,
|
|
631
|
+
* onError: (error) => error instanceof Error ? error.message : "An error occurred.",
|
|
632
|
+
* });
|
|
633
|
+
* return streamText({ model, messages, abortSignal: signal });
|
|
634
|
+
* }
|
|
635
|
+
* ```
|
|
636
|
+
*/
|
|
637
|
+
declare function setUIMessageStreamOptions(options: ChatUIMessageStreamOptions): void;
|
|
638
|
+
/**
|
|
639
|
+
* Check whether the user stopped generation during the current turn.
|
|
640
|
+
*
|
|
641
|
+
* Works from **anywhere** inside a `chat.task` run — including inside
|
|
642
|
+
* `streamText`'s `onFinish` callback — without needing to thread the
|
|
643
|
+
* `stopSignal` through closures.
|
|
644
|
+
*
|
|
645
|
+
* This is especially useful when the AI SDK's `isAborted` flag is unreliable
|
|
646
|
+
* (e.g. when using `createUIMessageStream` + `writer.merge()`).
|
|
647
|
+
*
|
|
648
|
+
* @example
|
|
649
|
+
* ```ts
|
|
650
|
+
* onFinish: ({ isAborted }) => {
|
|
651
|
+
* const wasStopped = isAborted || chat.isStopped();
|
|
652
|
+
* if (wasStopped) {
|
|
653
|
+
* // handle stop
|
|
654
|
+
* }
|
|
655
|
+
* }
|
|
656
|
+
* ```
|
|
657
|
+
*/
|
|
658
|
+
declare function isStopped(): boolean;
|
|
659
|
+
/**
|
|
660
|
+
* Register a promise that runs in the background during the current turn.
|
|
661
|
+
*
|
|
662
|
+
* Use this to move non-blocking work (DB writes, analytics, etc.) out of
|
|
663
|
+
* the critical path. The promise runs in parallel with streaming and is
|
|
664
|
+
* awaited (with a 5 s timeout) before `onTurnComplete` fires.
|
|
665
|
+
*
|
|
666
|
+
* @example
|
|
667
|
+
* ```ts
|
|
668
|
+
* onTurnStart: async ({ chatId, uiMessages }) => {
|
|
669
|
+
* // Persist messages without blocking the LLM call
|
|
670
|
+
* chat.defer(db.chat.update({ where: { id: chatId }, data: { messages: uiMessages } }));
|
|
671
|
+
* },
|
|
672
|
+
* ```
|
|
673
|
+
*/
|
|
674
|
+
declare function chatDefer(promise: Promise<unknown>): void;
|
|
675
|
+
/**
|
|
676
|
+
* Clean up a UIMessage that was captured during an aborted/stopped turn.
|
|
677
|
+
*
|
|
678
|
+
* When generation is stopped mid-stream, the captured message may contain:
|
|
679
|
+
* - Tool parts stuck in incomplete states (`partial-call`, `input-available`,
|
|
680
|
+
* `input-streaming`) that cause permanent UI spinners
|
|
681
|
+
* - Reasoning parts with `state: "streaming"` instead of `"done"`
|
|
682
|
+
* - Text parts with `state: "streaming"` instead of `"done"`
|
|
683
|
+
*
|
|
684
|
+
* This function returns a cleaned copy with:
|
|
685
|
+
* - Incomplete tool parts removed entirely
|
|
686
|
+
* - Reasoning and text parts marked as `"done"`
|
|
687
|
+
*
|
|
688
|
+
* `chat.task` calls this automatically when stop is detected before passing
|
|
689
|
+
* the response to `onTurnComplete`. Use this manually when calling `pipeChat`
|
|
690
|
+
* directly and capturing response messages yourself.
|
|
691
|
+
*
|
|
692
|
+
* @example
|
|
693
|
+
* ```ts
|
|
694
|
+
* onTurnComplete: async ({ responseMessage, stopped }) => {
|
|
695
|
+
* // Already cleaned automatically by chat.task — but if you captured
|
|
696
|
+
* // your own message via pipeChat, clean it manually:
|
|
697
|
+
* const cleaned = chat.cleanupAbortedParts(myMessage);
|
|
698
|
+
* await db.messages.save(cleaned);
|
|
699
|
+
* }
|
|
700
|
+
* ```
|
|
701
|
+
*/
|
|
702
|
+
declare function cleanupAbortedParts(message: UIMessage): UIMessage;
|
|
703
|
+
/**
|
|
704
|
+
* Create a managed stop signal wired to the chat stop input stream.
|
|
705
|
+
*
|
|
706
|
+
* Call once at the start of your run. Use `signal` as the abort signal for
|
|
707
|
+
* `streamText`. Call `reset()` at the start of each turn to get a fresh
|
|
708
|
+
* per-turn signal. Call `cleanup()` when the run ends.
|
|
709
|
+
*
|
|
710
|
+
* @example
|
|
711
|
+
* ```ts
|
|
712
|
+
* const stop = chat.createStopSignal();
|
|
713
|
+
* for (let turn = 0; turn < 100; turn++) {
|
|
714
|
+
* stop.reset();
|
|
715
|
+
* const result = streamText({ model, messages, abortSignal: stop.signal });
|
|
716
|
+
* await chat.pipe(result);
|
|
717
|
+
* // ...
|
|
718
|
+
* }
|
|
719
|
+
* stop.cleanup();
|
|
720
|
+
* ```
|
|
721
|
+
*/
|
|
722
|
+
declare function createStopSignal(): {
|
|
723
|
+
readonly signal: AbortSignal;
|
|
724
|
+
reset: () => void;
|
|
725
|
+
cleanup: () => void;
|
|
726
|
+
};
|
|
727
|
+
/**
|
|
728
|
+
* Signal the frontend that the current turn is complete.
|
|
729
|
+
*
|
|
730
|
+
* The `TriggerChatTransport` intercepts this to close the ReadableStream
|
|
731
|
+
* for the current turn. Call after piping the response stream.
|
|
732
|
+
*
|
|
733
|
+
* @example
|
|
734
|
+
* ```ts
|
|
735
|
+
* await chat.pipe(result);
|
|
736
|
+
* await chat.writeTurnComplete();
|
|
737
|
+
* ```
|
|
738
|
+
*/
|
|
739
|
+
declare function chatWriteTurnComplete(options?: {
|
|
740
|
+
publicAccessToken?: string;
|
|
741
|
+
}): Promise<void>;
|
|
742
|
+
/**
|
|
743
|
+
* Pipe a `StreamTextResult` (or similar) to the chat stream and capture
|
|
744
|
+
* the assistant's response message via `onFinish`.
|
|
745
|
+
*
|
|
746
|
+
* Combines `toUIMessageStream()` + `onFinish` callback + `chat.pipe()`.
|
|
747
|
+
* Returns the captured `UIMessage`, or `undefined` if capture failed.
|
|
748
|
+
*
|
|
749
|
+
* @example
|
|
750
|
+
* ```ts
|
|
751
|
+
* const result = streamText({ model, messages, abortSignal: signal });
|
|
752
|
+
* const response = await chat.pipeAndCapture(result, { signal });
|
|
753
|
+
* if (response) conversation.addResponse(response);
|
|
754
|
+
* ```
|
|
755
|
+
*/
|
|
756
|
+
declare function pipeChatAndCapture(source: UIMessageStreamable, options?: {
|
|
757
|
+
signal?: AbortSignal;
|
|
758
|
+
spanName?: string;
|
|
759
|
+
}): Promise<UIMessage | undefined>;
|
|
760
|
+
/**
|
|
761
|
+
* Accumulates conversation messages across turns.
|
|
762
|
+
*
|
|
763
|
+
* Handles the transport protocol: turn 0 sends full history (replace),
|
|
764
|
+
* subsequent turns send only new messages (append), regenerate sends
|
|
765
|
+
* full history minus last assistant message (replace).
|
|
766
|
+
*
|
|
767
|
+
* @example
|
|
768
|
+
* ```ts
|
|
769
|
+
* const conversation = new chat.MessageAccumulator();
|
|
770
|
+
* for (let turn = 0; turn < 100; turn++) {
|
|
771
|
+
* const messages = await conversation.addIncoming(payload.messages, payload.trigger, turn);
|
|
772
|
+
* const result = streamText({ model, messages });
|
|
773
|
+
* const response = await chat.pipeAndCapture(result);
|
|
774
|
+
* if (response) await conversation.addResponse(response);
|
|
775
|
+
* }
|
|
776
|
+
* ```
|
|
777
|
+
*/
|
|
778
|
+
declare class ChatMessageAccumulator {
|
|
779
|
+
modelMessages: ModelMessage[];
|
|
780
|
+
uiMessages: UIMessage[];
|
|
781
|
+
/**
|
|
782
|
+
* Add incoming messages from the transport payload.
|
|
783
|
+
* Returns the full accumulated model messages for `streamText`.
|
|
784
|
+
*/
|
|
785
|
+
addIncoming(messages: UIMessage[], trigger: string, turn: number): Promise<ModelMessage[]>;
|
|
786
|
+
/**
|
|
787
|
+
* Add the assistant's response to the accumulator.
|
|
788
|
+
* Call after `pipeAndCapture` with the captured response.
|
|
789
|
+
*/
|
|
790
|
+
addResponse(response: UIMessage): Promise<void>;
|
|
791
|
+
}
|
|
792
|
+
export type ChatSessionOptions = {
|
|
793
|
+
/** Run-level cancel signal (from task context). */
|
|
794
|
+
signal: AbortSignal;
|
|
795
|
+
/** Seconds to stay warm between turns before suspending. @default 30 */
|
|
796
|
+
warmTimeoutInSeconds?: number;
|
|
797
|
+
/** Duration string for suspend timeout. @default "1h" */
|
|
798
|
+
timeout?: string;
|
|
799
|
+
/** Max turns before ending. @default 100 */
|
|
800
|
+
maxTurns?: number;
|
|
801
|
+
};
|
|
802
|
+
export type ChatTurn = {
|
|
803
|
+
/** Turn number (0-indexed). */
|
|
804
|
+
number: number;
|
|
805
|
+
/** Chat session ID. */
|
|
806
|
+
chatId: string;
|
|
807
|
+
/** What triggered this turn. */
|
|
808
|
+
trigger: string;
|
|
809
|
+
/** Client data from the transport (`metadata` field on the wire payload). */
|
|
810
|
+
clientData: unknown;
|
|
811
|
+
/** Full accumulated model messages — pass directly to `streamText`. */
|
|
812
|
+
messages: ModelMessage[];
|
|
813
|
+
/** Full accumulated UI messages — use for persistence. */
|
|
814
|
+
uiMessages: UIMessage[];
|
|
815
|
+
/** Combined stop+cancel AbortSignal (fresh each turn). */
|
|
816
|
+
signal: AbortSignal;
|
|
817
|
+
/** Whether the user stopped generation this turn. */
|
|
818
|
+
readonly stopped: boolean;
|
|
819
|
+
/** Whether this is a continuation run. */
|
|
820
|
+
continuation: boolean;
|
|
821
|
+
/**
|
|
822
|
+
* Easy path: pipe stream, capture response, accumulate it,
|
|
823
|
+
* clean up aborted parts if stopped, and write turn-complete chunk.
|
|
824
|
+
*/
|
|
825
|
+
complete(source: UIMessageStreamable): Promise<UIMessage | undefined>;
|
|
826
|
+
/**
|
|
827
|
+
* Manual path: just write turn-complete chunk.
|
|
828
|
+
* Use when you've already piped and accumulated manually.
|
|
829
|
+
*/
|
|
830
|
+
done(): Promise<void>;
|
|
831
|
+
/**
|
|
832
|
+
* Add the response to the accumulator manually.
|
|
833
|
+
* Use with `chat.pipeAndCapture` when you need control between pipe and done.
|
|
834
|
+
*/
|
|
835
|
+
addResponse(response: UIMessage): Promise<void>;
|
|
836
|
+
};
|
|
837
|
+
/**
|
|
838
|
+
* Create a chat session that yields turns as an async iterator.
|
|
839
|
+
*
|
|
840
|
+
* Handles: preload wait, stop signals, message accumulation, turn-complete
|
|
841
|
+
* signaling, and warm/suspend between turns. You control: initialization,
|
|
842
|
+
* model/tool selection, persistence, and any custom per-turn logic.
|
|
843
|
+
*
|
|
844
|
+
* @example
|
|
845
|
+
* ```ts
|
|
846
|
+
* import { task } from "@trigger.dev/sdk";
|
|
847
|
+
* import { chat, type ChatTaskWirePayload } from "@trigger.dev/sdk/ai";
|
|
848
|
+
* import { streamText } from "ai";
|
|
849
|
+
* import { openai } from "@ai-sdk/openai";
|
|
850
|
+
*
|
|
851
|
+
* export const myChat = task({
|
|
852
|
+
* id: "my-chat",
|
|
853
|
+
* run: async (payload: ChatTaskWirePayload, { signal }) => {
|
|
854
|
+
* const session = chat.createSession(payload, { signal });
|
|
855
|
+
*
|
|
856
|
+
* for await (const turn of session) {
|
|
857
|
+
* const result = streamText({
|
|
858
|
+
* model: openai("gpt-4o"),
|
|
859
|
+
* messages: turn.messages,
|
|
860
|
+
* abortSignal: turn.signal,
|
|
861
|
+
* });
|
|
862
|
+
* await turn.complete(result);
|
|
863
|
+
* }
|
|
864
|
+
* },
|
|
865
|
+
* });
|
|
866
|
+
* ```
|
|
867
|
+
*/
|
|
868
|
+
declare function createChatSession(payload: ChatTaskWirePayload, options: ChatSessionOptions): AsyncIterable<ChatTurn>;
|
|
430
869
|
/**
|
|
431
870
|
* A Proxy-backed, run-scoped data object that appears as `T` to users.
|
|
432
871
|
* Includes helper methods for initialization, dirty tracking, and serialization.
|
|
@@ -451,12 +890,16 @@ export type ChatLocal<T extends Record<string, unknown>> = T & {
|
|
|
451
890
|
*
|
|
452
891
|
* Multiple locals can coexist — each gets its own isolated run-scoped storage.
|
|
453
892
|
*
|
|
893
|
+
* The `id` is required and must be unique across all `chat.local()` calls in
|
|
894
|
+
* your project. It's used to serialize values into subtask metadata so that
|
|
895
|
+
* `ai.tool()` subtasks can auto-hydrate parent locals (read-only).
|
|
896
|
+
*
|
|
454
897
|
* @example
|
|
455
898
|
* ```ts
|
|
456
899
|
* import { chat } from "@trigger.dev/sdk/ai";
|
|
457
900
|
*
|
|
458
|
-
* const userPrefs = chat.local<{ theme: string; language: string }>();
|
|
459
|
-
* const gameState = chat.local<{ score: number; streak: number }>();
|
|
901
|
+
* const userPrefs = chat.local<{ theme: string; language: string }>({ id: "userPrefs" });
|
|
902
|
+
* const gameState = chat.local<{ score: number; streak: number }>({ id: "gameState" });
|
|
460
903
|
*
|
|
461
904
|
* export const myChat = chat.task({
|
|
462
905
|
* id: "my-chat",
|
|
@@ -480,7 +923,9 @@ export type ChatLocal<T extends Record<string, unknown>> = T & {
|
|
|
480
923
|
* });
|
|
481
924
|
* ```
|
|
482
925
|
*/
|
|
483
|
-
declare function chatLocal<T extends Record<string, unknown>>(
|
|
926
|
+
declare function chatLocal<T extends Record<string, unknown>>(options: {
|
|
927
|
+
id: string;
|
|
928
|
+
}): ChatLocal<T>;
|
|
484
929
|
/**
|
|
485
930
|
* Extracts the client data (metadata) type from a chat task.
|
|
486
931
|
* Use this to type the `metadata` option on the transport.
|
|
@@ -510,4 +955,26 @@ export declare const chat: {
|
|
|
510
955
|
setTurnTimeoutInSeconds: typeof setTurnTimeoutInSeconds;
|
|
511
956
|
/** Override the warm timeout at runtime. See {@link setWarmTimeoutInSeconds}. */
|
|
512
957
|
setWarmTimeoutInSeconds: typeof setWarmTimeoutInSeconds;
|
|
958
|
+
/** Override toUIMessageStream() options for the current turn. See {@link setUIMessageStreamOptions}. */
|
|
959
|
+
setUIMessageStreamOptions: typeof setUIMessageStreamOptions;
|
|
960
|
+
/** Check if the current turn was stopped by the user. See {@link isStopped}. */
|
|
961
|
+
isStopped: typeof isStopped;
|
|
962
|
+
/** Clean up aborted parts from a UIMessage. See {@link cleanupAbortedParts}. */
|
|
963
|
+
cleanupAbortedParts: typeof cleanupAbortedParts;
|
|
964
|
+
/** Register background work that runs in parallel with streaming. See {@link chatDefer}. */
|
|
965
|
+
defer: typeof chatDefer;
|
|
966
|
+
/** Typed chat output stream for writing custom chunks or piping from subtasks. */
|
|
967
|
+
stream: import("@trigger.dev/core/v3").RealtimeDefinedStream<UIMessageChunk>;
|
|
968
|
+
/** Pre-built input stream for receiving messages from the transport. */
|
|
969
|
+
messages: import("@trigger.dev/core/v3").RealtimeDefinedInputStream<ChatTaskWirePayload<UIMessage<unknown, import("ai").UIDataTypes, import("ai").UITools>, unknown>>;
|
|
970
|
+
/** Create a managed stop signal wired to the stop input stream. See {@link createStopSignal}. */
|
|
971
|
+
createStopSignal: typeof createStopSignal;
|
|
972
|
+
/** Signal the frontend that the current turn is complete. See {@link chatWriteTurnComplete}. */
|
|
973
|
+
writeTurnComplete: typeof chatWriteTurnComplete;
|
|
974
|
+
/** Pipe a stream and capture the response message. See {@link pipeChatAndCapture}. */
|
|
975
|
+
pipeAndCapture: typeof pipeChatAndCapture;
|
|
976
|
+
/** Message accumulator class for raw task chat. See {@link ChatMessageAccumulator}. */
|
|
977
|
+
MessageAccumulator: typeof ChatMessageAccumulator;
|
|
978
|
+
/** Create a chat session (async iterator). See {@link createChatSession}. */
|
|
979
|
+
createSession: typeof createChatSession;
|
|
513
980
|
};
|