@trigger.dev/sdk 4.4.6 → 4.5.0-rc.1

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 (161) hide show
  1. package/dist/commonjs/v3/agentSkillsRuntime.d.ts +28 -0
  2. package/dist/commonjs/v3/agentSkillsRuntime.js +163 -0
  3. package/dist/commonjs/v3/agentSkillsRuntime.js.map +1 -0
  4. package/dist/commonjs/v3/ai-shared.d.ts +173 -0
  5. package/dist/commonjs/v3/ai-shared.js +25 -0
  6. package/dist/commonjs/v3/ai-shared.js.map +1 -0
  7. package/dist/commonjs/v3/ai.d.ts +2823 -5
  8. package/dist/commonjs/v3/ai.js +6197 -13
  9. package/dist/commonjs/v3/ai.js.map +1 -1
  10. package/dist/commonjs/v3/auth.d.ts +9 -0
  11. package/dist/commonjs/v3/auth.js.map +1 -1
  12. package/dist/commonjs/v3/chat-client.d.ts +301 -0
  13. package/dist/commonjs/v3/chat-client.js +624 -0
  14. package/dist/commonjs/v3/chat-client.js.map +1 -0
  15. package/dist/commonjs/v3/chat-react.d.ts +155 -0
  16. package/dist/commonjs/v3/chat-react.js +330 -0
  17. package/dist/commonjs/v3/chat-react.js.map +1 -0
  18. package/dist/commonjs/v3/chat-server.d.ts +206 -0
  19. package/dist/commonjs/v3/chat-server.js +737 -0
  20. package/dist/commonjs/v3/chat-server.js.map +1 -0
  21. package/dist/commonjs/v3/chat-server.test.d.ts +1 -0
  22. package/dist/commonjs/v3/chat-server.test.js +518 -0
  23. package/dist/commonjs/v3/chat-server.test.js.map +1 -0
  24. package/dist/commonjs/v3/chat-tab-coordinator.d.ts +65 -0
  25. package/dist/commonjs/v3/chat-tab-coordinator.js +235 -0
  26. package/dist/commonjs/v3/chat-tab-coordinator.js.map +1 -0
  27. package/dist/commonjs/v3/chat-tab-coordinator.test.d.ts +1 -0
  28. package/dist/commonjs/v3/chat-tab-coordinator.test.js +140 -0
  29. package/dist/commonjs/v3/chat-tab-coordinator.test.js.map +1 -0
  30. package/dist/commonjs/v3/chat.d.ts +437 -0
  31. package/dist/commonjs/v3/chat.js +968 -0
  32. package/dist/commonjs/v3/chat.js.map +1 -0
  33. package/dist/commonjs/v3/chat.test.d.ts +1 -0
  34. package/dist/commonjs/v3/chat.test.js +1180 -0
  35. package/dist/commonjs/v3/chat.test.js.map +1 -0
  36. package/dist/commonjs/v3/createStartSessionAction.test.d.ts +1 -0
  37. package/dist/commonjs/v3/createStartSessionAction.test.js +113 -0
  38. package/dist/commonjs/v3/createStartSessionAction.test.js.map +1 -0
  39. package/dist/commonjs/v3/deployments.d.ts +26 -0
  40. package/dist/commonjs/v3/deployments.js +37 -0
  41. package/dist/commonjs/v3/deployments.js.map +1 -0
  42. package/dist/commonjs/v3/index.d.ts +6 -3
  43. package/dist/commonjs/v3/index.js +7 -1
  44. package/dist/commonjs/v3/index.js.map +1 -1
  45. package/dist/commonjs/v3/runs.d.ts +22 -7
  46. package/dist/commonjs/v3/runs.js +1 -0
  47. package/dist/commonjs/v3/runs.js.map +1 -1
  48. package/dist/commonjs/v3/sessions.d.ts +228 -0
  49. package/dist/commonjs/v3/sessions.js +664 -0
  50. package/dist/commonjs/v3/sessions.js.map +1 -0
  51. package/dist/commonjs/v3/sessions.test.d.ts +1 -0
  52. package/dist/commonjs/v3/sessions.test.js +154 -0
  53. package/dist/commonjs/v3/sessions.test.js.map +1 -0
  54. package/dist/commonjs/v3/shared.d.ts +24 -2
  55. package/dist/commonjs/v3/shared.js +189 -1
  56. package/dist/commonjs/v3/shared.js.map +1 -1
  57. package/dist/commonjs/v3/skill.d.ts +99 -0
  58. package/dist/commonjs/v3/skill.js +155 -0
  59. package/dist/commonjs/v3/skill.js.map +1 -0
  60. package/dist/commonjs/v3/skills.d.ts +2 -0
  61. package/dist/commonjs/v3/skills.js +6 -0
  62. package/dist/commonjs/v3/skills.js.map +1 -0
  63. package/dist/commonjs/v3/streams.js +127 -19
  64. package/dist/commonjs/v3/streams.js.map +1 -1
  65. package/dist/commonjs/v3/tasks.d.ts +2 -1
  66. package/dist/commonjs/v3/tasks.js +1 -0
  67. package/dist/commonjs/v3/tasks.js.map +1 -1
  68. package/dist/commonjs/v3/test/index.d.ts +3 -0
  69. package/dist/commonjs/v3/test/index.js +18 -0
  70. package/dist/commonjs/v3/test/index.js.map +1 -0
  71. package/dist/commonjs/v3/test/mock-chat-agent.d.ts +259 -0
  72. package/dist/commonjs/v3/test/mock-chat-agent.js +468 -0
  73. package/dist/commonjs/v3/test/mock-chat-agent.js.map +1 -0
  74. package/dist/commonjs/v3/test/setup-catalog.d.ts +1 -0
  75. package/dist/commonjs/v3/test/setup-catalog.js +18 -0
  76. package/dist/commonjs/v3/test/setup-catalog.js.map +1 -0
  77. package/dist/commonjs/v3/test/test-session-handle.d.ts +53 -0
  78. package/dist/commonjs/v3/test/test-session-handle.js +256 -0
  79. package/dist/commonjs/v3/test/test-session-handle.js.map +1 -0
  80. package/dist/commonjs/version.js +1 -1
  81. package/dist/esm/v3/agentSkillsRuntime.d.ts +28 -0
  82. package/dist/esm/v3/agentSkillsRuntime.js +136 -0
  83. package/dist/esm/v3/agentSkillsRuntime.js.map +1 -0
  84. package/dist/esm/v3/ai-shared.d.ts +173 -0
  85. package/dist/esm/v3/ai-shared.js +22 -0
  86. package/dist/esm/v3/ai-shared.js.map +1 -0
  87. package/dist/esm/v3/ai.d.ts +2823 -5
  88. package/dist/esm/v3/ai.js +6187 -14
  89. package/dist/esm/v3/ai.js.map +1 -1
  90. package/dist/esm/v3/auth.d.ts +9 -0
  91. package/dist/esm/v3/auth.js.map +1 -1
  92. package/dist/esm/v3/chat-client.d.ts +301 -0
  93. package/dist/esm/v3/chat-client.js +619 -0
  94. package/dist/esm/v3/chat-client.js.map +1 -0
  95. package/dist/esm/v3/chat-react.d.ts +155 -0
  96. package/dist/esm/v3/chat-react.js +325 -0
  97. package/dist/esm/v3/chat-react.js.map +1 -0
  98. package/dist/esm/v3/chat-server.d.ts +206 -0
  99. package/dist/esm/v3/chat-server.js +734 -0
  100. package/dist/esm/v3/chat-server.js.map +1 -0
  101. package/dist/esm/v3/chat-server.test.d.ts +1 -0
  102. package/dist/esm/v3/chat-server.test.js +516 -0
  103. package/dist/esm/v3/chat-server.test.js.map +1 -0
  104. package/dist/esm/v3/chat-tab-coordinator.d.ts +65 -0
  105. package/dist/esm/v3/chat-tab-coordinator.js +231 -0
  106. package/dist/esm/v3/chat-tab-coordinator.js.map +1 -0
  107. package/dist/esm/v3/chat-tab-coordinator.test.d.ts +1 -0
  108. package/dist/esm/v3/chat-tab-coordinator.test.js +138 -0
  109. package/dist/esm/v3/chat-tab-coordinator.test.js.map +1 -0
  110. package/dist/esm/v3/chat.d.ts +437 -0
  111. package/dist/esm/v3/chat.js +961 -0
  112. package/dist/esm/v3/chat.js.map +1 -0
  113. package/dist/esm/v3/chat.test.d.ts +1 -0
  114. package/dist/esm/v3/chat.test.js +1178 -0
  115. package/dist/esm/v3/chat.test.js.map +1 -0
  116. package/dist/esm/v3/createStartSessionAction.test.d.ts +1 -0
  117. package/dist/esm/v3/createStartSessionAction.test.js +111 -0
  118. package/dist/esm/v3/createStartSessionAction.test.js.map +1 -0
  119. package/dist/esm/v3/deployments.d.ts +26 -0
  120. package/dist/esm/v3/deployments.js +34 -0
  121. package/dist/esm/v3/deployments.js.map +1 -0
  122. package/dist/esm/v3/index.d.ts +6 -3
  123. package/dist/esm/v3/index.js +4 -1
  124. package/dist/esm/v3/index.js.map +1 -1
  125. package/dist/esm/v3/runs.d.ts +15 -0
  126. package/dist/esm/v3/runs.js +1 -0
  127. package/dist/esm/v3/runs.js.map +1 -1
  128. package/dist/esm/v3/sessions.d.ts +228 -0
  129. package/dist/esm/v3/sessions.js +656 -0
  130. package/dist/esm/v3/sessions.js.map +1 -0
  131. package/dist/esm/v3/sessions.test.d.ts +1 -0
  132. package/dist/esm/v3/sessions.test.js +152 -0
  133. package/dist/esm/v3/sessions.test.js.map +1 -0
  134. package/dist/esm/v3/shared.d.ts +24 -2
  135. package/dist/esm/v3/shared.js +188 -1
  136. package/dist/esm/v3/shared.js.map +1 -1
  137. package/dist/esm/v3/skill.d.ts +99 -0
  138. package/dist/esm/v3/skill.js +128 -0
  139. package/dist/esm/v3/skill.js.map +1 -0
  140. package/dist/esm/v3/skills.d.ts +2 -0
  141. package/dist/esm/v3/skills.js +2 -0
  142. package/dist/esm/v3/skills.js.map +1 -0
  143. package/dist/esm/v3/streams.js +127 -20
  144. package/dist/esm/v3/streams.js.map +1 -1
  145. package/dist/esm/v3/tasks.d.ts +2 -1
  146. package/dist/esm/v3/tasks.js +2 -1
  147. package/dist/esm/v3/tasks.js.map +1 -1
  148. package/dist/esm/v3/test/index.d.ts +3 -0
  149. package/dist/esm/v3/test/index.js +13 -0
  150. package/dist/esm/v3/test/index.js.map +1 -0
  151. package/dist/esm/v3/test/mock-chat-agent.d.ts +259 -0
  152. package/dist/esm/v3/test/mock-chat-agent.js +465 -0
  153. package/dist/esm/v3/test/mock-chat-agent.js.map +1 -0
  154. package/dist/esm/v3/test/setup-catalog.d.ts +1 -0
  155. package/dist/esm/v3/test/setup-catalog.js +16 -0
  156. package/dist/esm/v3/test/setup-catalog.js.map +1 -0
  157. package/dist/esm/v3/test/test-session-handle.d.ts +53 -0
  158. package/dist/esm/v3/test/test-session-handle.js +251 -0
  159. package/dist/esm/v3/test/test-session-handle.js.map +1 -0
  160. package/dist/esm/version.js +1 -1
  161. package/package.json +87 -6
@@ -1,6 +1,35 @@
1
- import { Task, type inferSchemaIn, type TaskSchema, type TaskWithSchema } from "@trigger.dev/core/v3";
1
+ import { AnyTask, type MachinePresetName, type RealtimeDefinedInputStream, type RealtimeDefinedStream, Task, type inferSchemaIn, type inferSchemaOut, type TaskIdentifier, type TaskOptions, type TaskSchema, type TaskRunContext, type TaskWithSchema } from "@trigger.dev/core/v3";
2
+ import type { FinishReason, ModelMessage, ToolSet, UIMessage, UIMessageChunk, UIMessageStreamOptions, LanguageModelUsage } from "ai";
2
3
  import { Tool, ToolCallOptions } from "ai";
3
- export type ToolCallExecutionOptions = Omit<ToolCallOptions, "abortSignal">;
4
+ import { locals } from "./locals.js";
5
+ import type { ResolvedPrompt } from "./prompt.js";
6
+ import type { ResolvedSkill } from "./skill.js";
7
+ import { type SessionTriggerConfig } from "@trigger.dev/core/v3";
8
+ /** Re-export for typing `ctx` in `chat.agent` hooks without importing `@trigger.dev/core`. */
9
+ export type { TaskRunContext } from "@trigger.dev/core/v3";
10
+ export type ToolCallExecutionOptions = {
11
+ toolCallId: string;
12
+ experimental_context?: unknown;
13
+ /** Chat context — only present when the tool runs inside a chat.agent turn. */
14
+ chatId?: string;
15
+ turn?: number;
16
+ continuation?: boolean;
17
+ clientData?: unknown;
18
+ };
19
+ /** Chat context stored in locals during each chat.agent turn for auto-detection. */
20
+ type ChatTurnContext<TClientData = unknown> = {
21
+ chatId: string;
22
+ turn: number;
23
+ continuation: boolean;
24
+ clientData?: TClientData;
25
+ };
26
+ export declare function __setReadChatSnapshotImplForTests(impl: ReadChatSnapshotImpl | undefined): void;
27
+ export declare function __setWriteChatSnapshotImplForTests(impl: WriteChatSnapshotImpl | undefined): void;
28
+ type ReplaySessionOutTailImpl = <TUIMessage extends UIMessage>(sessionId: string, options?: {
29
+ lastEventId?: string;
30
+ }) => Promise<ReplaySessionOutTailResult<TUIMessage>>;
31
+ export declare function __setReplaySessionOutTailImplForTests(impl: ReplaySessionOutTailImpl | undefined): void;
32
+ export declare function __setReplaySessionInTailImplForTests(impl: ReplaySessionInTailImpl | undefined): void;
4
33
  type ToolResultContent = Array<{
5
34
  type: "text";
6
35
  text: string;
@@ -12,11 +41,2800 @@ type ToolResultContent = Array<{
12
41
  export type ToolOptions<TResult> = {
13
42
  experimental_toToolResultContent?: (result: TResult) => ToolResultContent;
14
43
  };
15
- declare function toolFromTask<TIdentifier extends string, TInput = void, TOutput = unknown>(task: Task<TIdentifier, TInput, TOutput>, options?: ToolOptions<TOutput>): Tool<TInput, TOutput>;
16
- 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>;
44
+ /** Satisfies AI SDK `ToolSet` index signature alongside concrete `Tool` input/output types. */
45
+ type ToolSetCompatible<T extends Tool<any, any>> = T & NonNullable<ToolSet[string]>;
46
+ /**
47
+ * Returns an `execute` function for the AI SDK `tool()` helper (or any compatible tool definition).
48
+ * Preferred API for task-backed tools: the same Trigger wiring as the deprecated `ai.tool()`
49
+ * (`triggerAndSubscribe`, tool-call metadata, chat context, `chat.local` serialization) without
50
+ * building the tool object. You supply `description`, `inputSchema`, and any AI-SDK-only options
51
+ * (e.g. `experimental_toToolResultContent`) on `tool()` yourself.
52
+ *
53
+ * @example
54
+ * ```ts
55
+ * import { tool } from "ai";
56
+ * import { z } from "zod";
57
+ * import { ai } from "@trigger.dev/sdk/ai";
58
+ * import { myTask } from "./trigger/myTask";
59
+ *
60
+ * export const myTool = tool({
61
+ * description: myTask.description ?? "",
62
+ * inputSchema: z.object({ id: z.string() }),
63
+ * execute: ai.toolExecute(myTask),
64
+ * });
65
+ * ```
66
+ */
67
+ declare function toolExecute<TIdentifier extends string, TInput = void, TOutput = unknown>(task: Task<TIdentifier, TInput, TOutput>): (input: TInput, toolOpts: ToolCallOptions) => Promise<TOutput>;
68
+ declare function toolExecute<TIdentifier extends string, TTaskSchema extends TaskSchema | undefined = undefined, TOutput = unknown>(task: TaskWithSchema<TIdentifier, TTaskSchema, TOutput>): (input: inferSchemaIn<TTaskSchema>, toolOpts: ToolCallOptions) => Promise<TOutput>;
69
+ /**
70
+ * @deprecated Use `tool()` from the `ai` package with `execute: ai.toolExecute(task)` instead.
71
+ * This helper may be removed in a future major release.
72
+ */
73
+ declare function toolFromTask<TIdentifier extends string, TInput = void, TOutput = unknown>(task: Task<TIdentifier, TInput, TOutput>, options?: ToolOptions<TOutput>): ToolSetCompatible<Tool<TInput, TOutput>>;
74
+ /** @deprecated Use `tool()` from `ai` with `execute: ai.toolExecute(task)`. */
75
+ declare function toolFromTask<TIdentifier extends string, TTaskSchema extends TaskSchema | undefined = undefined, TOutput = unknown>(task: TaskWithSchema<TIdentifier, TTaskSchema, TOutput>, options?: ToolOptions<TOutput>): ToolSetCompatible<Tool<inferSchemaIn<TTaskSchema>, TOutput>>;
17
76
  declare function getToolOptionsFromMetadata(): ToolCallExecutionOptions | undefined;
77
+ /**
78
+ * Get the current tool call ID from inside a subtask invoked via `ai.toolExecute()` (or legacy `ai.tool()`).
79
+ * Returns `undefined` if not running as a tool subtask.
80
+ */
81
+ declare function getToolCallId(): string | undefined;
82
+ /**
83
+ * Get the chat context from inside a subtask invoked via `ai.toolExecute()` (or legacy `ai.tool()`) within a `chat.agent`.
84
+ * Pass `typeof yourChatTask` as the type parameter to get typed `clientData`.
85
+ * Returns `undefined` if the parent is not a chat task.
86
+ *
87
+ * @example
88
+ * ```ts
89
+ * const ctx = ai.chatContext<typeof myChat>();
90
+ * // ctx?.clientData is typed based on myChat's clientDataSchema
91
+ * ```
92
+ */
93
+ declare function getToolChatContext<TChatTask extends AnyTask = AnyTask>(): ChatTurnContext<InferChatClientData<TChatTask>> | undefined;
94
+ /**
95
+ * Get the chat context from inside a subtask, throwing if not in a chat context.
96
+ * Pass `typeof yourChatTask` as the type parameter to get typed `clientData`.
97
+ *
98
+ * @example
99
+ * ```ts
100
+ * const ctx = ai.chatContextOrThrow<typeof myChat>();
101
+ * // ctx.chatId, ctx.clientData are guaranteed non-null
102
+ * ```
103
+ */
104
+ declare function getToolChatContextOrThrow<TChatTask extends AnyTask = AnyTask>(): ChatTurnContext<InferChatClientData<TChatTask>>;
18
105
  export declare const ai: {
106
+ /**
107
+ * @deprecated Use `tool()` from the `ai` package with `execute: ai.toolExecute(task)` instead.
108
+ */
19
109
  tool: typeof toolFromTask;
110
+ /**
111
+ * Preferred: return value for the `execute` field of AI SDK `tool()`. Keeps Trigger subtask and
112
+ * metadata behavior without coupling to a specific `ai` version’s `Tool` / `ToolSet` types.
113
+ */
114
+ toolExecute: typeof toolExecute;
20
115
  currentToolOptions: typeof getToolOptionsFromMetadata;
116
+ /** Get the tool call ID from inside a subtask invoked via `ai.toolExecute()` (or legacy `ai.tool()`). */
117
+ toolCallId: typeof getToolCallId;
118
+ /** Get chat context (chatId, turn, clientData, etc.) from inside a subtask of a `chat.agent`. Returns undefined if not in a chat context. */
119
+ chatContext: typeof getToolChatContext;
120
+ /** Get chat context or throw if not in a chat context. Pass `typeof yourChatTask` for typed clientData. */
121
+ chatContextOrThrow: typeof getToolChatContextOrThrow;
122
+ };
123
+ /**
124
+ * Creates a public access token for a chat task.
125
+ *
126
+ * This is a convenience helper that creates a multi-use trigger public token
127
+ * scoped to the given task. Use it in a server action to provide the frontend
128
+ * `TriggerChatTransport` with an `accessToken`.
129
+ *
130
+ * @example
131
+ * ```ts
132
+ * // actions.ts
133
+ * "use server";
134
+ * import { chat } from "@trigger.dev/sdk/ai";
135
+ * import type { myChat } from "@/trigger/chat";
136
+ *
137
+ * export const getChatToken = () => chat.createAccessToken<typeof myChat>("my-chat");
138
+ * ```
139
+ */
140
+ declare function createChatAccessToken<TTask extends AnyTask>(taskId: TaskIdentifier<TTask>): Promise<string>;
141
+ /**
142
+ * A stream writer passed to chat lifecycle callbacks (`onPreload`, `onChatStart`,
143
+ * `onTurnStart`, `onTurnComplete`, `onCompacted`).
144
+ *
145
+ * Write custom `UIMessageChunk` parts (e.g. `data-*` parts) directly to the chat
146
+ * stream without the ceremony of `chat.stream.writer({ execute })`.
147
+ *
148
+ * The writer is lazy — no stream overhead if you don't call `write()` or `merge()`.
149
+ *
150
+ * @example
151
+ * ```ts
152
+ * onTurnStart: async ({ writer }) => {
153
+ * writer.write({ type: "data-status", data: { loading: true } });
154
+ * },
155
+ * onTurnComplete: async ({ writer, uiMessages }) => {
156
+ * writer.write({ type: "data-analytics", data: { messageCount: uiMessages.length } });
157
+ * },
158
+ * ```
159
+ */
160
+ export type ChatWriter = {
161
+ /** Write a single UIMessageChunk to the chat stream. */
162
+ write(part: UIMessageChunk): void;
163
+ /** Merge another stream's chunks into the chat stream. */
164
+ merge(stream: ReadableStream<UIMessageChunk>): void;
165
+ };
166
+ import type { ChatTaskWirePayload } from "./ai-shared.js";
167
+ export type { ChatTaskWirePayload, ChatInputChunk } from "./ai-shared.js";
168
+ /**
169
+ * The payload shape passed to the `chatAgent` run function.
170
+ *
171
+ * - `messages` contains model-ready messages (converted via `convertToModelMessages`) —
172
+ * pass these directly to `streamText`.
173
+ * - `clientData` contains custom data from the frontend (the `metadata` field from `sendMessage()`).
174
+ *
175
+ * The backend accumulates the full conversation history across turns, so the frontend
176
+ * only needs to send new messages after the first turn.
177
+ */
178
+ export type ChatTaskPayload<TClientData = unknown> = {
179
+ /** Model-ready messages — pass directly to `streamText({ messages })`. */
180
+ messages: ModelMessage[];
181
+ /** The unique identifier for the chat session */
182
+ chatId: string;
183
+ /**
184
+ * The trigger type:
185
+ * - `"submit-message"`: A new user message
186
+ * - `"regenerate-message"`: Regenerate the last assistant response
187
+ * - `"preload"`: Run was preloaded before the first message (only on turn 0)
188
+ * - `"action"`: A typed action from the frontend (see `actionSchema` + `onAction`).
189
+ * The action has already been applied before `run()` fires — check `trigger === "action"`
190
+ * to short-circuit the LLM call when an action doesn't need a response.
191
+ * - `"close"`: The chat session is being closed (internal; `run()` is not called).
192
+ */
193
+ trigger: "submit-message" | "regenerate-message" | "preload" | "action" | "close";
194
+ /** The ID of the message to regenerate (only for `"regenerate-message"`) */
195
+ messageId?: string;
196
+ /** Custom data from the frontend (passed via `metadata` on `sendMessage()` or the transport). */
197
+ clientData?: TClientData;
198
+ /** Whether this run is continuing an existing chat (previous run timed out or was cancelled). False for brand new chats. */
199
+ continuation: boolean;
200
+ /** The run ID of the previous run (only set when `continuation` is true). */
201
+ previousRunId?: string;
202
+ /** Whether this run was preloaded before the first message. */
203
+ preloaded: boolean;
204
+ /**
205
+ * The friendlyId of the Session primitive backing this chat. Use with
206
+ * `sessions.open(sessionId)` when you need direct access to the session's
207
+ * `.in` / `.out` channels outside the hooks the agent already wires for
208
+ * you. Undefined only for legacy transports that predate the sessions
209
+ * migration.
210
+ */
211
+ sessionId?: string;
212
+ };
213
+ /**
214
+ * Abort signals provided to the `chatAgent` run function.
215
+ */
216
+ export type ChatTaskSignals = {
217
+ /** Combined signal — fires on run cancel OR stop generation. Pass to `streamText`. */
218
+ signal: AbortSignal;
219
+ /** Fires only when the run is cancelled, expired, or exceeds maxDuration. */
220
+ cancelSignal: AbortSignal;
221
+ /** Fires only when the frontend stops generation for this turn (per-turn, reset each turn). */
222
+ stopSignal: AbortSignal;
223
+ };
224
+ /**
225
+ * The full payload passed to a `chatAgent` run function.
226
+ * Extends `ChatTaskPayload` (the wire payload) with abort signals.
227
+ */
228
+ export type ChatTaskRunPayload<TClientData = unknown> = ChatTaskPayload<TClientData> & ChatTaskSignals & {
229
+ /**
230
+ * Task run context — same object as the `ctx` passed to a standard `task({ run })` handler’s second argument.
231
+ * Use for tags, metadata, parent run links, or any API that needs the full run record.
232
+ */
233
+ ctx: TaskRunContext;
234
+ /** Token usage from the previous turn. Undefined on turn 0. */
235
+ previousTurnUsage?: LanguageModelUsage;
236
+ /** Cumulative token usage across all completed turns so far. */
237
+ totalUsage: LanguageModelUsage;
238
+ };
239
+ /** Convenience re-export of the AI SDK's `LanguageModelUsage` type. */
240
+ export type ChatTurnUsage = LanguageModelUsage;
241
+ /**
242
+ * Replace the accumulated conversation messages for the current run.
243
+ *
244
+ * Call from `onTurnStart` to compact before `run()` executes, or from
245
+ * `onTurnComplete` to compact before the next turn. Takes `UIMessage[]`
246
+ * and converts to `ModelMessage[]` internally.
247
+ */
248
+ declare function setChatMessages<TUIM extends UIMessage = UIMessage>(uiMessages: TUIM[]): void;
249
+ /**
250
+ * A tool call surfaced by `chat.history.getPendingToolCalls()` /
251
+ * `getResolvedToolCalls()`. Identifies the call by its `toolCallId` plus
252
+ * the `messageId` of the assistant message that hosts it, so callers can
253
+ * locate the part precisely without re-walking the chain.
254
+ */
255
+ export type ChatToolCallRef = {
256
+ toolCallId: string;
257
+ toolName: string;
258
+ messageId: string;
259
+ };
260
+ /**
261
+ * A new tool result surfaced by `chat.history.extractNewToolResults()`.
262
+ * `errorText` is set iff the part is in `output-error` state; otherwise
263
+ * `output` carries the resolved value.
264
+ */
265
+ export type ChatNewToolResult = {
266
+ toolCallId: string;
267
+ toolName: string;
268
+ output: unknown;
269
+ errorText?: string;
270
+ };
271
+ /** State stored in locals during prepareStep compaction. */
272
+ interface CompactionState {
273
+ summary: string;
274
+ baseResponseMessageCount: number;
275
+ }
276
+ /**
277
+ * Event passed to `summarize` callbacks.
278
+ */
279
+ export type SummarizeEvent = {
280
+ /** The current model messages to summarize. */
281
+ messages: ModelMessage[];
282
+ /** Full usage object from the triggering step/turn. */
283
+ usage?: LanguageModelUsage;
284
+ /** Cumulative token usage across all completed turns. Present in chat.agent contexts. */
285
+ totalUsage?: LanguageModelUsage;
286
+ /** The chat session ID (if running inside a chat.agent). */
287
+ chatId?: string;
288
+ /** The current turn number (0-indexed, if inside a chat.agent). */
289
+ turn?: number;
290
+ /** Custom data from the frontend (if inside a chat.agent). */
291
+ clientData?: unknown;
292
+ /**
293
+ * Where compaction is running:
294
+ * - `"inner"` — between tool-call steps (prepareStep)
295
+ * - `"outer"` — between turns
296
+ */
297
+ source?: "inner" | "outer";
298
+ /** The step number (0-indexed). Only present when `source` is `"inner"`. */
299
+ stepNumber?: number;
300
+ };
301
+ /**
302
+ * Event passed to `compactUIMessages` and `compactModelMessages` callbacks.
303
+ */
304
+ export type CompactMessagesEvent<TUIM extends UIMessage = UIMessage> = {
305
+ /** The generated summary text. */
306
+ summary: string;
307
+ /** The current UI messages (full conversation). */
308
+ uiMessages: TUIM[];
309
+ /** The current model messages (full conversation). */
310
+ modelMessages: ModelMessage[];
311
+ /** The chat session ID. */
312
+ chatId: string;
313
+ /** The current turn number (0-indexed). */
314
+ turn: number;
315
+ /** Custom data from the frontend. */
316
+ clientData?: unknown;
317
+ /**
318
+ * Where compaction is running:
319
+ * - `"inner"` — between tool-call steps (prepareStep)
320
+ * - `"outer"` — between turns
321
+ */
322
+ source: "inner" | "outer";
323
+ };
324
+ /**
325
+ * Options for the `compaction` field on `chat.agent()`.
326
+ *
327
+ * Handles compaction automatically in both the inner loop (prepareStep, between
328
+ * tool-call steps) and the outer loop (between turns, for single-step responses
329
+ * where prepareStep never fires).
330
+ */
331
+ export type ChatAgentCompactionOptions<TUIM extends UIMessage = UIMessage> = {
332
+ /** Decide whether to compact. Return true to trigger compaction. */
333
+ shouldCompact: (event: ShouldCompactEvent) => boolean | Promise<boolean>;
334
+ /** Generate a summary from the current messages. Return the summary text. */
335
+ summarize: (event: SummarizeEvent) => Promise<string>;
336
+ /**
337
+ * Transform UI messages after compaction (what gets persisted and displayed).
338
+ * Default: preserve all UI messages unchanged.
339
+ *
340
+ * @example
341
+ * ```ts
342
+ * // Flatten to summary
343
+ * compactUIMessages: ({ summary }) => [{
344
+ * id: generateId(), role: "assistant",
345
+ * parts: [{ type: "text", text: `[Summary]\n\n${summary}` }],
346
+ * }],
347
+ *
348
+ * // Summary + keep last 4 messages
349
+ * compactUIMessages: ({ uiMessages, summary }) => [
350
+ * { id: generateId(), role: "assistant",
351
+ * parts: [{ type: "text", text: `[Summary]\n\n${summary}` }] },
352
+ * ...uiMessages.slice(-4),
353
+ * ],
354
+ * ```
355
+ */
356
+ compactUIMessages?: (event: CompactMessagesEvent<TUIM>) => TUIM[] | Promise<TUIM[]>;
357
+ /**
358
+ * Transform model messages after compaction (what gets sent to the LLM).
359
+ * Default: replace all with a single summary message.
360
+ *
361
+ * @example
362
+ * ```ts
363
+ * // Summary + keep last 2 model messages
364
+ * compactModelMessages: ({ modelMessages, summary }) => [
365
+ * { role: "user", content: summary },
366
+ * ...modelMessages.slice(-2),
367
+ * ],
368
+ * ```
369
+ */
370
+ compactModelMessages?: (event: CompactMessagesEvent<TUIM>) => ModelMessage[] | Promise<ModelMessage[]>;
371
+ };
372
+ /**
373
+ * Event passed to `shouldInject` and `prepareMessages` callbacks.
374
+ */
375
+ export type PendingMessagesBatchEvent<TUIM extends UIMessage = UIMessage> = {
376
+ /** All pending UI messages that arrived during streaming (batch). */
377
+ messages: TUIM[];
378
+ /** Current model messages in the conversation. */
379
+ modelMessages: ModelMessage[];
380
+ /** Completed steps so far. */
381
+ steps: CompactionStep[];
382
+ /** Current step number (0-indexed). */
383
+ stepNumber: number;
384
+ /** Chat session ID. */
385
+ chatId: string;
386
+ /** Current turn number (0-indexed). */
387
+ turn: number;
388
+ /** Custom data from the frontend. */
389
+ clientData?: unknown;
390
+ };
391
+ /**
392
+ * Event passed to `onReceived` callback (per-message, as they arrive).
393
+ */
394
+ export type PendingMessageReceivedEvent<TUIM extends UIMessage = UIMessage> = {
395
+ /** The UI message that arrived during streaming. */
396
+ message: TUIM;
397
+ /** Chat session ID. */
398
+ chatId: string;
399
+ /** Current turn number (0-indexed). */
400
+ turn: number;
401
+ };
402
+ /**
403
+ * Event passed to `onInjected` callback (batch, after injection).
404
+ */
405
+ export type PendingMessagesInjectedEvent<TUIM extends UIMessage = UIMessage> = {
406
+ /** All UI messages that were injected. */
407
+ messages: TUIM[];
408
+ /** The model messages that were injected. */
409
+ injectedModelMessages: ModelMessage[];
410
+ /** Chat session ID. */
411
+ chatId: string;
412
+ /** Current turn number (0-indexed). */
413
+ turn: number;
414
+ /** Step number where injection occurred. */
415
+ stepNumber: number;
416
+ };
417
+ /**
418
+ * Options for the `pendingMessages` field on `chat.agent()`, `chat.createSession()`,
419
+ * or `ChatMessageAccumulator`.
420
+ *
421
+ * Configures how messages that arrive during streaming are handled. When
422
+ * `shouldInject` is provided and returns `true`, the full batch of pending
423
+ * messages is injected between tool-call steps via `prepareStep`.
424
+ * Otherwise, messages queue for the next turn.
425
+ */
426
+ export type PendingMessagesOptions<TUIM extends UIMessage = UIMessage> = {
427
+ /**
428
+ * Decide whether to inject pending messages between tool-call steps.
429
+ * Called once per step boundary with the full batch of pending messages.
430
+ * If absent, no injection happens — messages only queue for the next turn.
431
+ */
432
+ shouldInject?: (event: PendingMessagesBatchEvent<TUIM>) => boolean | Promise<boolean>;
433
+ /**
434
+ * Transform the batch of pending messages before injection.
435
+ * Return the model messages to inject.
436
+ * Default: convert each UI message via `convertToModelMessages`.
437
+ */
438
+ prepare?: (event: PendingMessagesBatchEvent<TUIM>) => ModelMessage[] | Promise<ModelMessage[]>;
439
+ /** Called when a message arrives during streaming (per-message). */
440
+ onReceived?: (event: PendingMessageReceivedEvent<TUIM>) => void | Promise<void>;
441
+ /** Called after a batch of messages is injected via `prepareStep`. */
442
+ onInjected?: (event: PendingMessagesInjectedEvent<TUIM>) => void | Promise<void>;
443
+ };
444
+ /**
445
+ * The data part type used to signal that pending messages were injected
446
+ * between tool-call steps. The frontend can match on this to render
447
+ * injection points inline in the assistant response.
448
+ */
449
+ export { PENDING_MESSAGE_INJECTED_TYPE } from "./ai-shared.js";
450
+ /**
451
+ * Event passed to the `prepareMessages` hook.
452
+ */
453
+ export type PrepareMessagesEvent<TClientData = unknown> = {
454
+ /** The messages to transform. Return the transformed array. */
455
+ messages: ModelMessage[];
456
+ /** Why messages are being prepared. */
457
+ reason: "run" | "compaction-rebuild" | "compaction-result";
458
+ /** The chat session ID. */
459
+ chatId: string;
460
+ /** The current turn number (0-indexed). */
461
+ turn: number;
462
+ /** Custom data from the frontend. */
463
+ clientData?: TClientData;
464
+ };
465
+ /**
466
+ * Data shape for `data-compaction` stream chunks emitted during compaction.
467
+ * Use to type the `data` field when rendering compaction parts in the frontend.
468
+ */
469
+ export type CompactionChunkData = {
470
+ status: "compacting" | "complete";
471
+ totalTokens: number | undefined;
472
+ };
473
+ /**
474
+ * Event passed to the `onCompacted` callback.
475
+ */
476
+ export type CompactedEvent = {
477
+ /** Task run context — same as `task` lifecycle hooks and `chat.agent` `run({ ctx })`. */
478
+ ctx: TaskRunContext;
479
+ /** The generated summary text. */
480
+ summary: string;
481
+ /** The messages that were compacted (pre-compaction). */
482
+ messages: ModelMessage[];
483
+ /** Number of messages before compaction. */
484
+ messageCount: number;
485
+ /** Token usage from the step that triggered compaction. */
486
+ usage: LanguageModelUsage;
487
+ /** Total token count that triggered compaction. */
488
+ totalTokens: number | undefined;
489
+ /** Input token count from the triggering step. */
490
+ inputTokens: number | undefined;
491
+ /** Output token count from the triggering step. */
492
+ outputTokens: number | undefined;
493
+ /** The step number where compaction occurred (0-indexed). */
494
+ stepNumber: number;
495
+ /** The chat session ID (if running inside a chat.agent). */
496
+ chatId?: string;
497
+ /** The current turn number (if running inside a chat.agent). */
498
+ turn?: number;
499
+ /** Stream writer — write custom `UIMessageChunk` parts to the chat stream. Lazy: no overhead if unused. */
500
+ writer: ChatWriter;
501
+ };
502
+ /**
503
+ * Event passed to `shouldCompact` callbacks.
504
+ */
505
+ export type ShouldCompactEvent = {
506
+ /** The current model messages (full conversation). */
507
+ messages: ModelMessage[];
508
+ /** Total token count from the triggering step/turn. */
509
+ totalTokens: number | undefined;
510
+ /** Input token count from the triggering step/turn. */
511
+ inputTokens: number | undefined;
512
+ /** Output token count from the triggering step/turn. */
513
+ outputTokens: number | undefined;
514
+ /** Full usage object from the triggering step/turn. */
515
+ usage?: LanguageModelUsage;
516
+ /** Cumulative token usage across all completed turns. Present in chat.agent contexts. */
517
+ totalUsage?: LanguageModelUsage;
518
+ /** The chat session ID (if running inside a chat.agent). */
519
+ chatId?: string;
520
+ /** The current turn number (0-indexed, if inside a chat.agent). */
521
+ turn?: number;
522
+ /** Custom data from the frontend (if inside a chat.agent). */
523
+ clientData?: unknown;
524
+ /**
525
+ * Where this check is running:
526
+ * - `"inner"` — between tool-call steps (prepareStep)
527
+ * - `"outer"` — between turns (after response, before onBeforeTurnComplete)
528
+ */
529
+ source?: "inner" | "outer";
530
+ /** The step number (0-indexed). Only present when `source` is `"inner"`. */
531
+ stepNumber?: number;
532
+ /** The steps array from prepareStep. Only present when `source` is `"inner"`. */
533
+ steps?: CompactionStep[];
534
+ };
535
+ /**
536
+ * Options for `chat.compaction()` — the high-level prepareStep factory.
537
+ */
538
+ export type CompactionOptions = {
539
+ /** Generate a summary from the current messages. Return the summary text. */
540
+ summarize: (messages: ModelMessage[]) => Promise<string>;
541
+ /** Token threshold — compact when totalTokens exceeds this. Ignored if `shouldCompact` is provided. */
542
+ threshold?: number;
543
+ /** Custom compaction trigger. When provided, used instead of `threshold`. */
544
+ shouldCompact?: (event: ShouldCompactEvent) => boolean | Promise<boolean>;
545
+ };
546
+ /** A step object as received in prepareStep's `steps` array. */
547
+ export type CompactionStep = {
548
+ usage: LanguageModelUsage;
549
+ finishReason: string;
550
+ content: Array<{
551
+ type: string;
552
+ toolCallId?: string;
553
+ }>;
554
+ response: {
555
+ messages: Array<any>;
556
+ };
557
+ };
558
+ /**
559
+ * Result of `chat.compact()`. Discriminated union so you can inspect
560
+ * what happened, but also directly compatible with prepareStep's return type.
561
+ *
562
+ * - `"skipped"` — no compaction needed (first step, boundary unsafe, or under threshold). Return `undefined` to prepareStep.
563
+ * - `"rebuilt"` — previous compaction exists, messages rebuilt from summary + new response messages.
564
+ * - `"compacted"` — compaction just happened, includes the generated summary.
565
+ */
566
+ export type CompactResult = {
567
+ type: "skipped";
568
+ } | {
569
+ type: "rebuilt";
570
+ messages: ModelMessage[];
571
+ } | {
572
+ type: "compacted";
573
+ messages: ModelMessage[];
574
+ summary: string;
575
+ };
576
+ /**
577
+ * Options for `chat.compact()` — the low-level compaction function.
578
+ */
579
+ export type CompactOptions = {
580
+ /** Generate a summary from the current messages. Return the summary text. */
581
+ summarize: (messages: ModelMessage[]) => Promise<string>;
582
+ /** Token threshold — compact when totalTokens exceeds this. Ignored if `shouldCompact` is provided. */
583
+ threshold?: number;
584
+ /** Custom compaction trigger. When provided, used instead of `threshold`. */
585
+ shouldCompact?: (event: ShouldCompactEvent) => boolean | Promise<boolean>;
586
+ };
587
+ /**
588
+ * Read the current compaction state. Returns the summary and base message count
589
+ * if compaction has occurred in this turn, or `undefined` if not.
590
+ *
591
+ * Use in a custom `prepareStep` to rebuild from a previous compaction:
592
+ * ```ts
593
+ * const state = chat.getCompactionState();
594
+ * if (state) {
595
+ * return { messages: [{ role: "user", content: state.summary }, ...newMsgs] };
596
+ * }
597
+ * ```
598
+ */
599
+ declare function getCompactionState(): CompactionState | undefined;
600
+ /**
601
+ * Low-level compaction for use inside a custom `prepareStep`.
602
+ *
603
+ * Handles the full decision tree: first step, already-compacted rebuild,
604
+ * boundary safety, threshold check, summarization, stream chunks, state
605
+ * storage, and accumulator update.
606
+ *
607
+ * Returns a `CompactResult` — inspect `result.type` to see what happened,
608
+ * or convert to a prepareStep return with `result.type === "skipped" ? undefined : result`.
609
+ *
610
+ * @example
611
+ * ```ts
612
+ * prepareStep: async ({ messages, steps }) => {
613
+ * // your custom logic here...
614
+ * const result = await chat.compact(messages, steps, {
615
+ * threshold: 80_000,
616
+ * summarize: async (msgs) => generateText({ model, messages: msgs }).then(r => r.text),
617
+ * });
618
+ * if (result.type === "compacted") {
619
+ * logger.info("Compacted!", { summary: result.summary });
620
+ * }
621
+ * return result.type === "skipped" ? undefined : result;
622
+ * },
623
+ * ```
624
+ */
625
+ declare function chatCompact(messages: ModelMessage[], steps: CompactionStep[], options: CompactOptions): Promise<CompactResult>;
626
+ /**
627
+ * Returns a `prepareStep` function that handles context compaction automatically.
628
+ *
629
+ * Monitors token usage between tool-call steps. When `totalTokens` exceeds
630
+ * the threshold, generates a summary via `summarize()`, replaces the message
631
+ * history, and emits `data-compaction` stream chunks for the frontend.
632
+ *
633
+ * @example
634
+ * ```ts
635
+ * return streamText({
636
+ * ...chat.toStreamTextOptions({ registry }),
637
+ * messages: chat.addCacheBreaks(messages),
638
+ * prepareStep: chat.compactionStep({
639
+ * threshold: 80_000,
640
+ * summarize: async (messages) => {
641
+ * return generateText({ model, messages: [...messages, { role: "user", content: "Summarize." }] })
642
+ * .then((r) => r.text);
643
+ * },
644
+ * }),
645
+ * tools: { ... },
646
+ * });
647
+ * ```
648
+ */
649
+ declare function chatCompactionStep(options: CompactionOptions): (args: {
650
+ messages: ModelMessage[];
651
+ steps: CompactionStep[];
652
+ }) => Promise<{
653
+ messages: ModelMessage[];
654
+ } | undefined>;
655
+ /**
656
+ * Checks whether it's safe to compact the message history. Returns `false`
657
+ * if any tool calls are in-flight (incomplete tool invocations without results).
658
+ *
659
+ * Call before `chat.setMessages()` to avoid corrupting tool-call state.
660
+ */
661
+ declare function isCompactionSafe(messages: UIMessage[]): boolean;
662
+ /**
663
+ * A resolved prompt stored via `chat.prompt.set()`. Either a full `ResolvedPrompt`
664
+ * from `prompts.define().resolve()`, or a lightweight wrapper around a plain string.
665
+ */
666
+ export type ChatPromptValue = ResolvedPrompt | {
667
+ text: string;
668
+ model: undefined;
669
+ config: undefined;
670
+ promptId: string;
671
+ version: number;
672
+ labels: string[];
673
+ toAISDKTelemetry: (additionalMetadata?: Record<string, string>) => {
674
+ experimental_telemetry: {
675
+ isEnabled: true;
676
+ metadata: Record<string, string>;
677
+ };
678
+ };
679
+ };
680
+ /**
681
+ * Store a resolved prompt (or plain string) for the current run.
682
+ * Call from any hook (`onPreload`, `onChatStart`, `onTurnStart`) or `run()`.
683
+ */
684
+ declare function setChatPrompt(resolved: ResolvedPrompt | string): void;
685
+ /**
686
+ * Read the stored prompt. Throws if `chat.prompt.set()` has not been called.
687
+ */
688
+ declare function getChatPrompt(): ChatPromptValue;
689
+ /**
690
+ * Store resolved skills for the current run. Call from any hook
691
+ * (`onPreload`, `onChatStart`, `onTurnStart`) or `run()`.
692
+ */
693
+ declare function setChatSkills(skills: ResolvedSkill[]): void;
694
+ /** Read the stored skills. Returns `undefined` if none set. */
695
+ declare function getChatSkills(): ResolvedSkill[] | undefined;
696
+ /**
697
+ * Build the three tools we auto-inject into `streamText` when skills are
698
+ * set: `loadSkill`, `readFile`, `bash`. Scoped per-skill by name.
699
+ *
700
+ * Exported so callers can use the same tools outside the auto-wired path
701
+ * (e.g. in a `chat.createSession` loop with custom streamText).
702
+ */
703
+ export declare function buildSkillTools(skills: ResolvedSkill[]): Record<string, Tool>;
704
+ /**
705
+ * Options for {@link toStreamTextOptions}.
706
+ */
707
+ export type ToStreamTextOptionsOptions = {
708
+ /** Additional telemetry metadata merged into `experimental_telemetry.metadata`. */
709
+ telemetry?: Record<string, string>;
710
+ /**
711
+ * An AI SDK provider registry (from `createProviderRegistry`) or any object
712
+ * with a `languageModel(id)` method. When provided and the stored prompt has
713
+ * a `model` string, the resolved `LanguageModel` is included in the returned
714
+ * options so `streamText` uses it directly.
715
+ *
716
+ * The model string should use the `"provider:model-id"` format
717
+ * (e.g. `"openai:gpt-4o"`, `"anthropic:claude-sonnet-4-6"`).
718
+ */
719
+ registry?: {
720
+ languageModel(modelId: string): unknown;
721
+ };
722
+ /**
723
+ * User-defined tools to merge alongside the auto-injected skill tools
724
+ * (`loadSkill`, `readFile`, `bash`). User tools win on name conflicts.
725
+ *
726
+ * If you don't pass `tools` here and skills are set, the returned options
727
+ * will include just the skill tools — spread after any `tools` you pass
728
+ * directly to `streamText` and they'll be replaced. Easiest: pass all
729
+ * your tools here.
730
+ */
731
+ tools?: Record<string, Tool>;
732
+ };
733
+ /**
734
+ * Returns an options object ready to spread into `streamText()`.
735
+ *
736
+ * Includes `system`, `experimental_telemetry`, and any config fields
737
+ * (temperature, maxTokens, etc.) from the stored prompt.
738
+ *
739
+ * When a `registry` is provided and the prompt has a `model` string,
740
+ * the resolved `LanguageModel` is included as `model`.
741
+ *
742
+ * If no prompt has been set, returns `{}` (no-op spread).
743
+ */
744
+ declare function toStreamTextOptions(options?: ToStreamTextOptionsOptions): Record<string, unknown>;
745
+ /**
746
+ * Options for `pipeChat`.
747
+ */
748
+ export type PipeChatOptions = {
749
+ /**
750
+ * Override the stream key. Must match the `streamKey` on `TriggerChatTransport`.
751
+ * @default "chat"
752
+ */
753
+ streamKey?: string;
754
+ /** An AbortSignal to cancel the stream. */
755
+ signal?: AbortSignal;
756
+ /**
757
+ * The target run ID to pipe to.
758
+ * @default "self" (current run)
759
+ */
760
+ target?: string;
761
+ /** Override the default span name for this operation. */
762
+ spanName?: string;
763
+ };
764
+ /**
765
+ * Options for customizing the `toUIMessageStream()` call used when piping
766
+ * `streamText` results to the frontend.
767
+ *
768
+ * Set static defaults via `uiMessageStreamOptions` on `chat.agent()`, or
769
+ * override per-turn via `chat.setUIMessageStreamOptions()`.
770
+ *
771
+ * `onFinish` is omitted because it is managed internally for response capture.
772
+ * Use `streamText`'s `onFinish` for custom finish handling, or drop down to
773
+ * raw task mode with `chat.pipe()` for full control.
774
+ *
775
+ * `originalMessages` is omitted because it is automatically set from the
776
+ * accumulated conversation history, ensuring message IDs are reused across
777
+ * turns (e.g. for tool approval continuations).
778
+ *
779
+ * `generateMessageId` can be set to control ID generation for response
780
+ * messages (e.g. UUID-v7). If not set, the AI SDK's default `generateId` is used.
781
+ */
782
+ export type ChatUIMessageStreamOptions<TUIM extends UIMessage = UIMessage> = Omit<UIMessageStreamOptions<TUIM>, "onFinish" | "originalMessages">;
783
+ /**
784
+ * An object with a `toUIMessageStream()` method (e.g. `StreamTextResult` from `streamText()`).
785
+ */
786
+ type UIMessageStreamable = {
787
+ toUIMessageStream: (...args: any[]) => AsyncIterable<unknown> | ReadableStream<unknown>;
788
+ };
789
+ /**
790
+ * Pipes a chat stream to the realtime stream, making it available to the
791
+ * `TriggerChatTransport` on the frontend.
792
+ *
793
+ * Accepts:
794
+ * - A `StreamTextResult` from `streamText()` (has `.toUIMessageStream()`)
795
+ * - An `AsyncIterable` of `UIMessageChunk`s
796
+ * - A `ReadableStream` of `UIMessageChunk`s
797
+ *
798
+ * Must be called from inside a Trigger.dev task's `run` function.
799
+ *
800
+ * @example
801
+ * ```ts
802
+ * import { task } from "@trigger.dev/sdk";
803
+ * import { chat, type ChatTaskPayload } from "@trigger.dev/sdk/ai";
804
+ * import { streamText, convertToModelMessages } from "ai";
805
+ *
806
+ * export const myChatTask = task({
807
+ * id: "my-chat-task",
808
+ * run: async (payload: ChatTaskPayload) => {
809
+ * const result = streamText({
810
+ * model: openai("gpt-4o"),
811
+ * messages: payload.messages,
812
+ * });
813
+ *
814
+ * await chat.pipe(result);
815
+ * },
816
+ * });
817
+ * ```
818
+ *
819
+ * @example
820
+ * ```ts
821
+ * // Works from anywhere inside a task — even deep in your agent code
822
+ * async function runAgentLoop(messages: CoreMessage[]) {
823
+ * const result = streamText({ model, messages });
824
+ * await chat.pipe(result);
825
+ * }
826
+ * ```
827
+ */
828
+ declare function pipeChat(source: UIMessageStreamable | AsyncIterable<unknown> | ReadableStream<unknown>, options?: PipeChatOptions): Promise<void>;
829
+ /**
830
+ * Options for defining a chat task.
831
+ *
832
+ * Extends the standard `TaskOptions` but pre-types the payload as `ChatTaskPayload`
833
+ * and overrides `run` to accept `ChatTaskRunPayload` (with abort signals).
834
+ *
835
+ * **Auto-piping:** If the `run` function returns a value with `.toUIMessageStream()`
836
+ * (like a `StreamTextResult`), the stream is automatically piped to the frontend.
837
+ *
838
+ * **Single-run mode:** By default, the task uses input streams so that the
839
+ * entire conversation lives inside one run. After each AI response, the task
840
+ * emits a control chunk and suspends via `messagesInput.wait()`. The frontend
841
+ * transport resumes the same run by sending the next message via input streams.
842
+ */
843
+ /**
844
+ * Event passed to the `onPreload` callback.
845
+ */
846
+ export type PreloadEvent<TClientData = unknown> = {
847
+ /** Task run context — same as `task({ run })` second-argument `ctx`. */
848
+ ctx: TaskRunContext;
849
+ /** The unique identifier for the chat session. */
850
+ chatId: string;
851
+ /** The Trigger.dev run ID for this conversation. */
852
+ runId: string;
853
+ /** A scoped access token for this chat run. */
854
+ chatAccessToken: string;
855
+ /** Custom data from the frontend. */
856
+ clientData?: TClientData;
857
+ /** Stream writer — write custom `UIMessageChunk` parts to the chat stream. Lazy: no overhead if unused. */
858
+ writer: ChatWriter;
859
+ };
860
+ /**
861
+ * Event passed to the `onBoot` callback.
862
+ *
863
+ * Fires once at the start of every run boot — for the initial first-message
864
+ * run, for preloaded runs, AND for reactive continuation runs (post-cancel,
865
+ * post-crash, post-`endRun`, `chat.requestUpgrade`, OOM-retry attempts).
866
+ * Does NOT fire when the SAME run resumes from snapshot via the
867
+ * idle-window suspend/resume path — use `onChatResume` for that.
868
+ *
869
+ * Use this for per-process setup that needs to run every time a fresh
870
+ * worker picks up the chat: initialize `chat.local` state, open
871
+ * per-process resources (DB connections, sandboxes, etc.), or
872
+ * re-hydrate customer state from your DB on continuation.
873
+ *
874
+ * Ordering:
875
+ * - First message of a chat: `onBoot` → `onChatStart` → `onTurnStart` → `run()`
876
+ * - Preloaded run: `onBoot` → `onPreload` → (wait) → `onChatStart` → ...
877
+ * - Continuation run: `onBoot` → (wait for first message) → `onTurnStart` → `run()`
878
+ * (`onChatStart` does NOT fire on continuation runs)
879
+ */
880
+ export type BootEvent<TClientData = unknown> = {
881
+ /** Task run context — same as `task({ run })` second-argument `ctx`. */
882
+ ctx: TaskRunContext;
883
+ /** The unique identifier for the chat session. */
884
+ chatId: string;
885
+ /** The Trigger.dev run ID for this run boot. */
886
+ runId: string;
887
+ /** A scoped access token for this chat run. Persist this for frontend reconnection. */
888
+ chatAccessToken: string;
889
+ /** Custom data from the frontend (passed via `metadata` on `sendMessage()` or the transport). */
890
+ clientData: TClientData;
891
+ /**
892
+ * True when this run is a reactive continuation — the prior run died
893
+ * (cancel / crash / `endRun` / `requestUpgrade` / OOM retry) and this
894
+ * fresh worker is taking over the chat. Branch on this to re-load
895
+ * customer-owned state from your DB.
896
+ */
897
+ continuation: boolean;
898
+ /** Public id of the prior run when `continuation` is true. */
899
+ previousRunId?: string;
900
+ /** Whether this run was triggered as a preload. */
901
+ preloaded: boolean;
902
+ };
903
+ /**
904
+ * A tool call extracted from the partial assistant message of a dead run.
905
+ * Surfaced on `RecoveryBootEvent.pendingToolCalls` so the customer can
906
+ * decide how to repair the chain (synthesize a result, drop the partial,
907
+ * etc.).
908
+ */
909
+ export type RecoveryPendingToolCall = {
910
+ /** The AI SDK tool call id. */
911
+ toolCallId: string;
912
+ /** The tool name (the `tool-${name}` suffix). */
913
+ toolName: string;
914
+ /** The input the model produced for the tool call. */
915
+ input: unknown;
916
+ /** The part index inside `partialAssistant.parts` for in-place edits. */
917
+ partIndex: number;
918
+ };
919
+ /**
920
+ * Event passed to the `onRecoveryBoot` callback.
921
+ *
922
+ * Fires once at boot when a continuation run inherits in-flight state from
923
+ * a dead predecessor (cancel / crash / OOM / deploy eviction / graceful
924
+ * `chat.requestUpgrade`). The runtime reads both `session.in` and
925
+ * `session.out` past the last `turn-complete` cursor and surfaces the
926
+ * recovered pieces here so the customer can shape the conversational
927
+ * chain before the first turn fires.
928
+ *
929
+ * Does NOT fire when there's nothing to recover (clean continuation after
930
+ * `chat.endRun()` with no buffered user messages, fresh chat, OOM retry
931
+ * after a successful turn-complete with no in-flight tail).
932
+ *
933
+ * Does NOT fire when `hydrateMessages` is registered (the customer owns
934
+ * persistence; recovery decisions live in their own DB query).
935
+ */
936
+ export type RecoveryBootEvent<TUIM extends UIMessage = UIMessage> = {
937
+ /** Task run context — same as `task({ run })` second-argument `ctx`. */
938
+ ctx: TaskRunContext;
939
+ /** The unique identifier for the chat session. */
940
+ chatId: string;
941
+ /** The Trigger.dev run ID for this run boot. */
942
+ runId: string;
943
+ /** Public id of the prior run that died. */
944
+ previousRunId: string;
945
+ /**
946
+ * Best-effort cause of the predecessor's death. Currently always
947
+ * `"unknown"` — the run engine doesn't yet plumb the real reason
948
+ * into the continuation payload. Future SDK versions will narrow
949
+ * this. Don't branch behavior on it yet.
950
+ */
951
+ cause: "cancelled" | "crashed" | "unknown";
952
+ /**
953
+ * The conversation chain that was successfully persisted by the
954
+ * predecessor's last `onTurnComplete`. Empty if the predecessor died
955
+ * before turn 1 ever completed.
956
+ */
957
+ settledMessages: TUIM[];
958
+ /**
959
+ * User messages that arrived on `session.in` past the cursor — i.e.
960
+ * the message(s) the predecessor was processing or had queued when
961
+ * it died. The runtime's default is to re-dispatch each as a fresh
962
+ * turn after the chain is restored. Return a different list via
963
+ * `recoveredTurns` to skip / reorder / collapse them.
964
+ */
965
+ inFlightUsers: TUIM[];
966
+ /**
967
+ * The trailing assistant message the predecessor was streaming when
968
+ * it died — the orphan whose `turn-complete` never fired. Undefined
969
+ * if the predecessor died before any assistant output reached
970
+ * `session.out` (cancel-before-first-token, snapshot-only path).
971
+ */
972
+ partialAssistant: TUIM | undefined;
973
+ /**
974
+ * Tool calls extracted from `partialAssistant.parts` that the model
975
+ * had started but the tool runtime never resolved. Empty when
976
+ * `partialAssistant` is undefined or carries no `input-available`
977
+ * tool parts.
978
+ */
979
+ pendingToolCalls: RecoveryPendingToolCall[];
980
+ /**
981
+ * Lazy session.out writer — identical to the `writer` passed to
982
+ * `onTurnStart` / `onTurnComplete` / `onChatStart`. Use this to emit
983
+ * a recovery signal (e.g. a `data-chat-recovery` UIMessage chunk)
984
+ * BEFORE the first recovered turn fires so the bridge can render a
985
+ * "recovering..." banner. Lazy: no overhead if unused.
986
+ */
987
+ writer: ChatWriter;
988
+ };
989
+ /**
990
+ * Return shape for the `onRecoveryBoot` callback. Every field is optional —
991
+ * omit one to accept the default.
992
+ */
993
+ export type RecoveryBootResult<TUIM extends UIMessage = UIMessage> = {
994
+ /**
995
+ * The chain the new run boots with. Replaces the default
996
+ * (`settledMessages`). Use this to keep the partial assistant in
997
+ * context, mutate its tool parts to inject synthesized results,
998
+ * collapse history, etc.
999
+ *
1000
+ * Ignored when `hydrateMessages` is registered (the hydrate hook
1001
+ * runs per-turn and overwrites the chain).
1002
+ */
1003
+ chain?: TUIM[];
1004
+ /**
1005
+ * The user messages to re-dispatch as fresh turns after the chain is
1006
+ * restored. Default: `inFlightUsers` (re-process every in-flight
1007
+ * user). Return `[]` to suppress all of them; return a filtered /
1008
+ * reordered subset to skip specific ones.
1009
+ */
1010
+ recoveredTurns?: TUIM[];
1011
+ /**
1012
+ * Awaitable run AFTER the writer flushes and BEFORE the first
1013
+ * recovered turn fires. Use for blocking persistence (e.g. write the
1014
+ * partial assistant to your DB so a follow-up turn can reference
1015
+ * it). Errors bubble — wrap your own try/catch if you want to soft-
1016
+ * fail.
1017
+ */
1018
+ beforeBoot?: () => Promise<void>;
1019
+ };
1020
+ /**
1021
+ * Event passed to the `onChatStart` callback.
1022
+ *
1023
+ * Fires exactly once per chat, on the very first user message of the chat's
1024
+ * lifetime. Does NOT fire on continuation runs (post-`endRun`,
1025
+ * post-waitpoint-timeout, `chat.requestUpgrade`) or on OOM-retry attempts —
1026
+ * those are runs of an already-started chat.
1027
+ */
1028
+ export type ChatStartEvent<TClientData = unknown> = {
1029
+ /** Task run context — same as `task({ run })` second-argument `ctx`. */
1030
+ ctx: TaskRunContext;
1031
+ /** The unique identifier for the chat session. */
1032
+ chatId: string;
1033
+ /**
1034
+ * The initial model-ready messages for this conversation. Typically just
1035
+ * the first user message (or empty if `chat.headStart` is in play and the
1036
+ * seed message is supplied elsewhere). Since this hook only fires for the
1037
+ * chat's very first message, there's no prior history to load here.
1038
+ */
1039
+ messages: ModelMessage[];
1040
+ /** Custom data from the frontend (passed via `metadata` on `sendMessage()` or the transport). */
1041
+ clientData: TClientData;
1042
+ /** The Trigger.dev run ID for this conversation. */
1043
+ runId: string;
1044
+ /** A scoped access token for this chat run. Persist this for frontend reconnection. */
1045
+ chatAccessToken: string;
1046
+ /**
1047
+ * @deprecated Always `false` — `onChatStart` no longer fires on continuation
1048
+ * runs. Kept for backward compatibility; remove your `continuation` checks
1049
+ * from `onChatStart` and rely on the contract (this hook fires exactly once
1050
+ * per chat, on the very first message).
1051
+ */
1052
+ continuation: boolean;
1053
+ /**
1054
+ * @deprecated Always `undefined` — `onChatStart` no longer fires on
1055
+ * continuation runs.
1056
+ */
1057
+ previousRunId?: string;
1058
+ /** Whether this run was preloaded before the first message. */
1059
+ preloaded: boolean;
1060
+ /** Stream writer — write custom `UIMessageChunk` parts to the chat stream. Lazy: no overhead if unused. */
1061
+ writer: ChatWriter;
1062
+ };
1063
+ /**
1064
+ * Event passed to the `hydrateMessages` callback.
1065
+ */
1066
+ export type HydrateMessagesEvent<TClientData = unknown, TUIM extends UIMessage = UIMessage> = {
1067
+ /** The unique identifier for the chat session. */
1068
+ chatId: string;
1069
+ /** The turn number (0-indexed). */
1070
+ turn: number;
1071
+ /** The trigger type for this turn. */
1072
+ trigger: "submit-message" | "regenerate-message" | "action";
1073
+ /** Validated incoming UI messages from the wire payload (what the frontend sent). Empty for actions. */
1074
+ incomingMessages: TUIM[];
1075
+ /** The accumulated UI messages before this turn (empty on turn 0). */
1076
+ previousMessages: TUIM[];
1077
+ /** Parsed client data from the transport metadata. */
1078
+ clientData?: TClientData;
1079
+ /** Whether this run is continuing from a previous run. */
1080
+ continuation: boolean;
1081
+ /** The ID of the previous run (if continuation). */
1082
+ previousRunId?: string;
1083
+ };
1084
+ /**
1085
+ * Event passed to the `onValidateMessages` callback.
1086
+ */
1087
+ export type ValidateMessagesEvent<TUIM extends UIMessage = UIMessage> = {
1088
+ /** The incoming UI messages for this turn (after cleanup of aborted tool parts). */
1089
+ messages: TUIM[];
1090
+ /** The unique identifier for the chat session. */
1091
+ chatId: string;
1092
+ /** The turn number (0-indexed). */
1093
+ turn: number;
1094
+ /** The trigger type for this turn. */
1095
+ trigger: "submit-message" | "regenerate-message" | "preload" | "close";
1096
+ };
1097
+ /**
1098
+ * Event passed to the `onAction` callback.
1099
+ */
1100
+ export type ActionEvent<TAction = unknown, TClientData = unknown, TUIM extends UIMessage = UIMessage> = {
1101
+ /** The parsed and validated action payload. */
1102
+ action: TAction;
1103
+ /** The unique identifier for the chat session. */
1104
+ chatId: string;
1105
+ /** The turn number (0-indexed). */
1106
+ turn: number;
1107
+ /** Parsed client data from the transport metadata. */
1108
+ clientData?: TClientData;
1109
+ /** The accumulated UI messages (after hydration, if set). */
1110
+ uiMessages: TUIM[];
1111
+ /** The accumulated model messages (after hydration, if set). */
1112
+ messages: ModelMessage[];
1113
+ };
1114
+ /**
1115
+ * Event passed to the `onTurnStart` callback.
1116
+ */
1117
+ export type TurnStartEvent<TClientData = unknown, TUIM extends UIMessage = UIMessage> = {
1118
+ /** Task run context — same as `task({ run })` second-argument `ctx`. */
1119
+ ctx: TaskRunContext;
1120
+ /** The unique identifier for the chat session. */
1121
+ chatId: string;
1122
+ /** The accumulated model-ready messages (all turns so far, including new user message). */
1123
+ messages: ModelMessage[];
1124
+ /** The accumulated UI messages (all turns so far, including new user message). */
1125
+ uiMessages: TUIM[];
1126
+ /** The turn number (0-indexed). */
1127
+ turn: number;
1128
+ /** The Trigger.dev run ID for this conversation. */
1129
+ runId: string;
1130
+ /** A scoped access token for this chat run. */
1131
+ chatAccessToken: string;
1132
+ /** Custom data from the frontend. */
1133
+ clientData?: TClientData;
1134
+ /** Whether this run is continuing an existing chat (previous run timed out or was cancelled). False for brand new chats. */
1135
+ continuation: boolean;
1136
+ /** The run ID of the previous run (only set when `continuation` is true). */
1137
+ previousRunId?: string;
1138
+ /** Whether this run was preloaded before the first message. */
1139
+ preloaded: boolean;
1140
+ /** Token usage from the previous turn. Undefined on turn 0. */
1141
+ previousTurnUsage?: LanguageModelUsage;
1142
+ /** Cumulative token usage across all completed turns so far. */
1143
+ totalUsage: LanguageModelUsage;
1144
+ /** Stream writer — write custom `UIMessageChunk` parts to the chat stream. Lazy: no overhead if unused. */
1145
+ writer: ChatWriter;
1146
+ };
1147
+ /**
1148
+ * Event passed to the `onTurnComplete` callback.
1149
+ */
1150
+ export type TurnCompleteEvent<TClientData = unknown, TUIM extends UIMessage = UIMessage> = {
1151
+ /** Task run context — same as `task({ run })` second-argument `ctx`. */
1152
+ ctx: TaskRunContext;
1153
+ /** The unique identifier for the chat session. */
1154
+ chatId: string;
1155
+ /** The full accumulated conversation in model format (all turns so far). */
1156
+ messages: ModelMessage[];
1157
+ /**
1158
+ * The full accumulated conversation in UI format (all turns so far).
1159
+ * This is the format expected by `useChat` — store this for persistence.
1160
+ */
1161
+ uiMessages: TUIM[];
1162
+ /**
1163
+ * Only the new model messages from this turn (user message(s) + assistant response).
1164
+ * Useful for appending to an existing conversation record.
1165
+ */
1166
+ newMessages: ModelMessage[];
1167
+ /**
1168
+ * Only the new UI messages from this turn (user message(s) + assistant response).
1169
+ * Useful for inserting individual message records instead of overwriting the full history.
1170
+ */
1171
+ newUIMessages: TUIM[];
1172
+ /** The assistant's response for this turn, with aborted parts cleaned up when `stopped` is true. Undefined if `pipeChat` was used manually. */
1173
+ responseMessage: TUIM | undefined;
1174
+ /**
1175
+ * The raw assistant response before abort cleanup. Includes incomplete tool parts
1176
+ * (`input-available`, `partial-call`) and streaming reasoning/text parts.
1177
+ * Use this if you need custom cleanup logic. Same as `responseMessage` when not stopped.
1178
+ */
1179
+ rawResponseMessage: TUIM | undefined;
1180
+ /** The turn number (0-indexed). */
1181
+ turn: number;
1182
+ /** The Trigger.dev run ID for this conversation. */
1183
+ runId: string;
1184
+ /** A fresh scoped access token for this chat run (renewed each turn). Persist this for frontend reconnection. */
1185
+ chatAccessToken: string;
1186
+ /** The last event ID from the stream writer. Use this with `resume: true` to avoid replaying events after refresh. */
1187
+ lastEventId?: string;
1188
+ /** Custom data from the frontend. */
1189
+ clientData?: TClientData;
1190
+ /** Whether the user stopped generation during this turn. */
1191
+ stopped: boolean;
1192
+ /** Whether this run is continuing an existing chat (previous run timed out or was cancelled). False for brand new chats. */
1193
+ continuation: boolean;
1194
+ /** The run ID of the previous run (only set when `continuation` is true). */
1195
+ previousRunId?: string;
1196
+ /** Whether this run was preloaded before the first message. */
1197
+ preloaded: boolean;
1198
+ /** Token usage for this turn. Undefined if usage couldn't be captured (e.g. manual pipeChat). */
1199
+ usage?: LanguageModelUsage;
1200
+ /** Cumulative token usage across all turns in this run (including this turn). */
1201
+ totalUsage: LanguageModelUsage;
1202
+ /**
1203
+ * Why the LLM stopped generating this turn:
1204
+ * - `"stop"` — model generated a stop sequence (normal completion)
1205
+ * - `"tool-calls"` — model stopped on one or more tool calls. If any tool
1206
+ * has no `execute` function (e.g. an `ask_user` HITL tool), the turn is
1207
+ * paused awaiting user input; inspect `responseMessage.parts` for tool
1208
+ * parts in `input-available` state to distinguish.
1209
+ * - `"length"` — max tokens reached
1210
+ * - `"content-filter"` — content filter stopped the model
1211
+ * - `"error"` — model errored
1212
+ * - `"other"` — provider-specific reason
1213
+ *
1214
+ * Undefined if the underlying stream didn't provide a finish reason (e.g.
1215
+ * manual `pipeChat()` or an aborted stream).
1216
+ */
1217
+ finishReason?: FinishReason;
1218
+ };
1219
+ /**
1220
+ * Event passed to the `onBeforeTurnComplete` callback.
1221
+ * Same as `TurnCompleteEvent` but includes a `writer` since the stream is still open.
1222
+ */
1223
+ export type BeforeTurnCompleteEvent<TClientData = unknown, TUIM extends UIMessage = UIMessage> = TurnCompleteEvent<TClientData, TUIM> & {
1224
+ /** Stream writer — write custom `UIMessageChunk` parts to the chat stream. Lazy: no overhead if unused. */
1225
+ writer: ChatWriter;
1226
+ };
1227
+ /**
1228
+ * Discriminated event passed to the `onChatSuspend` callback.
1229
+ * Use `phase` to distinguish preload vs turn suspension.
1230
+ */
1231
+ export type ChatSuspendEvent<TClientData = unknown, TUIM extends UIMessage = UIMessage> = {
1232
+ /** Suspend is happening after onPreload, before the first message. */
1233
+ phase: "preload";
1234
+ /** Task run context. */
1235
+ ctx: TaskRunContext;
1236
+ /** The chat session ID. */
1237
+ chatId: string;
1238
+ /** The Trigger.dev run ID. */
1239
+ runId: string;
1240
+ /** Custom data from the frontend. */
1241
+ clientData?: TClientData;
1242
+ } | {
1243
+ /**
1244
+ * Suspend is happening on a continuation run that booted with no incoming
1245
+ * message (post-`endRun`, post-waitpoint-timeout, etc.) and is waiting
1246
+ * for the next session.in record before running any turn. Distinct from
1247
+ * `phase: "preload"` — the chat already started; `onPreload` has not
1248
+ * fired and will not fire on this run.
1249
+ */
1250
+ phase: "continuation";
1251
+ /** Task run context. */
1252
+ ctx: TaskRunContext;
1253
+ /** The chat session ID. */
1254
+ chatId: string;
1255
+ /** The Trigger.dev run ID. */
1256
+ runId: string;
1257
+ /** Custom data from the frontend. */
1258
+ clientData?: TClientData;
1259
+ } | {
1260
+ /** Suspend is happening after a completed turn, waiting for the next message. */
1261
+ phase: "turn";
1262
+ /** Task run context. */
1263
+ ctx: TaskRunContext;
1264
+ /** The chat session ID. */
1265
+ chatId: string;
1266
+ /** The Trigger.dev run ID. */
1267
+ runId: string;
1268
+ /** The turn number (0-indexed) that just completed. */
1269
+ turn: number;
1270
+ /** The accumulated model messages after the completed turn. */
1271
+ messages: ModelMessage[];
1272
+ /** The accumulated UI messages after the completed turn. */
1273
+ uiMessages: TUIM[];
1274
+ /** Custom data from the frontend. */
1275
+ clientData?: TClientData;
1276
+ };
1277
+ /**
1278
+ * Discriminated event passed to the `onChatResume` callback.
1279
+ * Use `phase` to distinguish preload vs turn resumption.
1280
+ */
1281
+ export type ChatResumeEvent<TClientData = unknown, TUIM extends UIMessage = UIMessage> = {
1282
+ /** First message arrived after preload suspension. */
1283
+ phase: "preload";
1284
+ /** Task run context. */
1285
+ ctx: TaskRunContext;
1286
+ /** The chat session ID. */
1287
+ chatId: string;
1288
+ /** The Trigger.dev run ID. */
1289
+ runId: string;
1290
+ /** Custom data from the frontend. */
1291
+ clientData?: TClientData;
1292
+ } | {
1293
+ /**
1294
+ * First message arrived after continuation-wait suspension. Distinct
1295
+ * from `phase: "preload"` — the chat already started; this is a new
1296
+ * run picking up after a prior run ended (`endRun`, waitpoint timeout,
1297
+ * etc.).
1298
+ */
1299
+ phase: "continuation";
1300
+ /** Task run context. */
1301
+ ctx: TaskRunContext;
1302
+ /** The chat session ID. */
1303
+ chatId: string;
1304
+ /** The Trigger.dev run ID. */
1305
+ runId: string;
1306
+ /** Custom data from the frontend. */
1307
+ clientData?: TClientData;
1308
+ } | {
1309
+ /** Next message arrived after turn suspension. */
1310
+ phase: "turn";
1311
+ /** Task run context. */
1312
+ ctx: TaskRunContext;
1313
+ /** The chat session ID. */
1314
+ chatId: string;
1315
+ /** The Trigger.dev run ID. */
1316
+ runId: string;
1317
+ /** The turn number that was completed before suspension. */
1318
+ turn: number;
1319
+ /** The accumulated model messages (from before suspension). */
1320
+ messages: ModelMessage[];
1321
+ /** The accumulated UI messages (from before suspension). */
1322
+ uiMessages: TUIM[];
1323
+ /** Custom data from the frontend. */
1324
+ clientData?: TClientData;
1325
+ };
1326
+ export type ChatAgentOptions<TIdentifier extends string, TClientDataSchema extends TaskSchema | undefined = undefined, TUIMessage extends UIMessage = UIMessage, TActionSchema extends TaskSchema | undefined = undefined> = Omit<TaskOptions<TIdentifier, ChatTaskWirePayload<TUIMessage, inferSchemaIn<TClientDataSchema>>, unknown>, "run" | "retry"> & {
1327
+ /**
1328
+ * Fallback machine preset to use when an attempt fails with an
1329
+ * out-of-memory (OOM) error. Setting this enables a single OOM retry:
1330
+ * the next attempt boots on the larger machine, and the chat picks
1331
+ * up via the standard continuation path (same `chatId` / Session,
1332
+ * accumulator rebuilds via `hydrateMessages` or post-`onTurnStart`
1333
+ * persisted state).
1334
+ *
1335
+ * Set `machine` (top-level `TaskOptions`) to control the *default*
1336
+ * machine the agent runs on. `oomMachine` is the *retry-only* swap.
1337
+ *
1338
+ * Note: an OOM retry restarts the entire turn from the top — the
1339
+ * model call and any in-flight tool executes re-run on the larger
1340
+ * machine. Make tool executes idempotent or persist results before
1341
+ * returning if you can't tolerate re-execution.
1342
+ *
1343
+ * Generic `retry` options are not exposed on `chat.agent` because
1344
+ * arbitrary retries against an LLM-driven loop tend to be expensive
1345
+ * and side-effecting. If you need richer retry semantics, drop down
1346
+ * to `chat.task` (the raw primitive).
1347
+ *
1348
+ * @example
1349
+ * ```ts
1350
+ * chat.agent({
1351
+ * id: "my-chat",
1352
+ * machine: "small-1x",
1353
+ * oomMachine: "medium-2x",
1354
+ * run: async ({ messages, signal }) =>
1355
+ * streamText({ model, messages, abortSignal: signal }),
1356
+ * });
1357
+ * ```
1358
+ */
1359
+ oomMachine?: MachinePresetName;
1360
+ /**
1361
+ * Schema for validating `clientData` from the frontend.
1362
+ * Accepts Zod, ArkType, Valibot, or any supported schema library.
1363
+ * When provided, `clientData` is parsed and typed in all hooks and `run`.
1364
+ *
1365
+ * @example
1366
+ * ```ts
1367
+ * import { z } from "zod";
1368
+ *
1369
+ * chat.agent({
1370
+ * id: "my-chat",
1371
+ * clientDataSchema: z.object({ model: z.string().optional(), userId: z.string() }),
1372
+ * run: async ({ messages, clientData, ctx, signal }) => {
1373
+ * // clientData is typed as { model?: string; userId: string }
1374
+ * // ctx is the same TaskRunContext as in task({ run: (payload, { ctx }) => ... })
1375
+ * },
1376
+ * });
1377
+ * ```
1378
+ */
1379
+ clientDataSchema?: TClientDataSchema;
1380
+ /**
1381
+ * Schema for validating custom actions sent via `transport.sendAction()`.
1382
+ *
1383
+ * When the frontend sends `trigger: "action"`, the `action` payload is
1384
+ * parsed against this schema before reaching `onAction`. Invalid actions
1385
+ * throw and abort the turn.
1386
+ *
1387
+ * @example
1388
+ * ```ts
1389
+ * import { z } from "zod";
1390
+ *
1391
+ * chat.agent({
1392
+ * id: "my-chat",
1393
+ * actionSchema: z.discriminatedUnion("type", [
1394
+ * z.object({ type: z.literal("undo") }),
1395
+ * z.object({ type: z.literal("rollback"), targetMessageId: z.string() }),
1396
+ * ]),
1397
+ * onAction: async ({ action }) => {
1398
+ * if (action.type === "undo") chat.history.slice(0, -2);
1399
+ * if (action.type === "rollback") chat.history.rollbackTo(action.targetMessageId);
1400
+ * },
1401
+ * run: async ({ messages, signal }) => { ... },
1402
+ * });
1403
+ * ```
1404
+ */
1405
+ actionSchema?: TActionSchema;
1406
+ /**
1407
+ * Called when the frontend sends a custom action via `transport.sendAction()`.
1408
+ *
1409
+ * Actions are not turns. They fire `hydrateMessages` (if configured) and
1410
+ * `onAction` only — no `onTurnStart` / `prepareMessages` /
1411
+ * `onBeforeTurnComplete` / `onTurnComplete`, no `run()`. Use
1412
+ * `chat.history.*` inside `onAction` to mutate state.
1413
+ *
1414
+ * To produce a model response from an action, return a
1415
+ * `StreamTextResult` (auto-piped), `string`, or `UIMessage`. Returning
1416
+ * `void` or nothing is the side-effect-only default.
1417
+ */
1418
+ onAction?: (event: ActionEvent<[
1419
+ TActionSchema
1420
+ ] extends [TaskSchema] ? inferSchemaOut<TActionSchema> : unknown, inferSchemaOut<TClientDataSchema>, TUIMessage>) => Promise<unknown> | unknown;
1421
+ /**
1422
+ * The run function for the chat task.
1423
+ *
1424
+ * Receives a `ChatTaskRunPayload` with the conversation messages, chat session ID,
1425
+ * trigger type, task `ctx` (same as `task({ run })`’s second argument), and abort signals
1426
+ * (`signal`, `cancelSignal`, `stopSignal`).
1427
+ *
1428
+ * **Auto-piping:** If this function returns a value with `.toUIMessageStream()`,
1429
+ * the stream is automatically piped to the frontend.
1430
+ */
1431
+ run: (payload: ChatTaskRunPayload<inferSchemaOut<TClientDataSchema>>) => Promise<unknown>;
1432
+ /**
1433
+ * Called once at the start of every run boot — for the initial run, for
1434
+ * preloaded runs, AND for reactive continuation runs (post-cancel /
1435
+ * crash / `endRun` / `requestUpgrade` / OOM retry).
1436
+ *
1437
+ * Use this for per-process setup that needs to run every time a fresh
1438
+ * worker picks up the chat: initialize `chat.local` state, open
1439
+ * per-process resources, or re-hydrate customer state from your DB
1440
+ * on continuation. Branch on `continuation` to decide whether to load
1441
+ * existing state vs. start fresh.
1442
+ *
1443
+ * Fires BEFORE `onPreload` (preloaded path) and `onChatStart`
1444
+ * (first-message path), so `chat.local` is safe to read in those hooks.
1445
+ *
1446
+ * Does NOT fire when the same run resumes from snapshot via the
1447
+ * idle-window suspend/resume path — use `onChatResume` for that.
1448
+ *
1449
+ * @example
1450
+ * ```ts
1451
+ * onBoot: async ({ chatId, clientData, continuation }) => {
1452
+ * const user = await db.user.findFirst({ where: { id: clientData.userId } });
1453
+ * userContext.init({ name: user.name, plan: user.plan });
1454
+ * if (continuation) {
1455
+ * // re-hydrate any per-chat in-memory state from your DB
1456
+ * }
1457
+ * }
1458
+ * ```
1459
+ */
1460
+ onBoot?: (event: BootEvent<inferSchemaOut<TClientDataSchema>>) => Promise<void> | void;
1461
+ /**
1462
+ * Recovery boot hook — fires once on a continuation run that inherited
1463
+ * in-flight state from a dead predecessor (cancel / crash / OOM /
1464
+ * deploy eviction / `chat.requestUpgrade()`). The runtime reads both
1465
+ * stream tails past the last `turn-complete` cursor and hands the
1466
+ * customer the recovered pieces (settled chain, in-flight users,
1467
+ * partial assistant, pending tool calls) so the chain can be shaped
1468
+ * before the first recovered turn fires.
1469
+ *
1470
+ * Does NOT fire when there's nothing to recover — e.g. a clean
1471
+ * continuation after `chat.endRun()` with no buffered user, a fresh
1472
+ * chat, or an OOM retry on top of a complete snapshot.
1473
+ *
1474
+ * Does NOT fire when `hydrateMessages` is registered — that hook owns
1475
+ * the per-turn chain and overlapping recovery decisions belong in the
1476
+ * customer's DB.
1477
+ *
1478
+ * Defaults (returned when the hook is omitted or returns no field):
1479
+ * - `chain` = `settledMessages` (drop the orphan partial)
1480
+ * - `recoveredTurns` = `inFlightUsers` (re-dispatch every user)
1481
+ *
1482
+ * @example
1483
+ * ```ts
1484
+ * onRecoveryBoot: async ({ partialAssistant, inFlightUsers, writer, cause }) => {
1485
+ * writer.write({
1486
+ * type: "data-chat-recovery",
1487
+ * id: generateId(),
1488
+ * data: { cause, partial: partialAssistant?.id },
1489
+ * });
1490
+ * return {}; // accept defaults: drop partial, re-dispatch users
1491
+ * }
1492
+ * ```
1493
+ */
1494
+ onRecoveryBoot?: (event: RecoveryBootEvent<TUIMessage>) => Promise<RecoveryBootResult<TUIMessage> | void> | RecoveryBootResult<TUIMessage> | void;
1495
+ /**
1496
+ * Called when a preloaded run starts, before the first message arrives.
1497
+ *
1498
+ * Use this to initialize state, create DB records, and load context early —
1499
+ * so everything is ready when the user's first message comes through.
1500
+ *
1501
+ * @example
1502
+ * ```ts
1503
+ * onPreload: async ({ ctx, chatId, clientData }) => {
1504
+ * await db.chat.create({ data: { id: chatId } });
1505
+ * userContext.init(await loadUser(clientData.userId));
1506
+ * }
1507
+ * ```
1508
+ */
1509
+ onPreload?: (event: PreloadEvent<inferSchemaOut<TClientDataSchema>>) => Promise<void> | void;
1510
+ /**
1511
+ * Called exactly once per chat, on the very first user message of the
1512
+ * chat's lifetime. Does NOT fire on continuation runs (post-`endRun`,
1513
+ * post-waitpoint-timeout, `chat.requestUpgrade`) or on OOM-retry attempts —
1514
+ * those are runs of an already-started chat.
1515
+ *
1516
+ * Use this for one-time chat-setup work — creating the Chat DB row,
1517
+ * initializing per-chat in-memory state, minting resources tied to the
1518
+ * chat's lifetime. Safe to assume no prior history exists here.
1519
+ *
1520
+ * For per-turn work, use `onTurnStart`.
1521
+ *
1522
+ * @example
1523
+ * ```ts
1524
+ * onChatStart: async ({ ctx, chatId, messages, clientData }) => {
1525
+ * await db.chat.create({ data: { id: chatId, userId: clientData.userId } });
1526
+ * }
1527
+ * ```
1528
+ */
1529
+ onChatStart?: (event: ChatStartEvent<inferSchemaOut<TClientDataSchema>>) => Promise<void> | void;
1530
+ /**
1531
+ * Validate or transform incoming UI messages before they are converted to model
1532
+ * messages and accumulated. Fires once per turn with the raw `UIMessage[]` from
1533
+ * the wire payload (after cleanup of aborted tool parts).
1534
+ *
1535
+ * Return the validated messages array. Throw to abort the turn with an error.
1536
+ *
1537
+ * This is the right place to call the AI SDK's `validateUIMessages` to catch
1538
+ * malformed messages from storage or untrusted input before they reach the model.
1539
+ *
1540
+ * @example
1541
+ * ```ts
1542
+ * import { validateUIMessages } from "ai";
1543
+ *
1544
+ * chat.agent({
1545
+ * id: "my-chat",
1546
+ * onValidateMessages: async ({ messages }) => {
1547
+ * return validateUIMessages({ messages, tools: chatTools });
1548
+ * },
1549
+ * run: async ({ messages }) => {
1550
+ * return streamText({ model, messages, tools: chatTools });
1551
+ * },
1552
+ * });
1553
+ * ```
1554
+ */
1555
+ onValidateMessages?: (event: ValidateMessagesEvent<TUIMessage>) => TUIMessage[] | Promise<TUIMessage[]>;
1556
+ /**
1557
+ * Load the full message history from your backend on every turn,
1558
+ * replacing the built-in linear accumulator.
1559
+ *
1560
+ * When set, the returned messages become the accumulated state for this turn.
1561
+ * The normal accumulation logic (append for submit, replace for regenerate)
1562
+ * is skipped entirely — the hook is the source of truth.
1563
+ *
1564
+ * After the hook returns, any incoming wire messages with matching IDs are
1565
+ * auto-merged (handles tool approval responses transparently).
1566
+ *
1567
+ * Use cases:
1568
+ * - Backend trust: prevent clients from injecting fabricated history
1569
+ * - Branching conversations (DAGs): load only the active branch
1570
+ * - Rollback/undo: exclude undone messages from history
1571
+ *
1572
+ * @example
1573
+ * ```ts
1574
+ * chat.agent({
1575
+ * id: "my-chat",
1576
+ * hydrateMessages: async ({ chatId, trigger, incomingMessages }) => {
1577
+ * // Persist the new message
1578
+ * const newMsg = incomingMessages[incomingMessages.length - 1];
1579
+ * if (newMsg && trigger === "submit-message") {
1580
+ * await db.chatMessages.create({ chatId, message: newMsg });
1581
+ * }
1582
+ * // Return the full authoritative history
1583
+ * return db.chatMessages.findMany({ where: { chatId } });
1584
+ * },
1585
+ * run: async ({ messages, signal }) => {
1586
+ * return streamText({ model: openai("gpt-4o"), messages, abortSignal: signal });
1587
+ * },
1588
+ * });
1589
+ * ```
1590
+ */
1591
+ hydrateMessages?: (event: HydrateMessagesEvent<inferSchemaOut<TClientDataSchema>, TUIMessage>) => TUIMessage[] | Promise<TUIMessage[]>;
1592
+ /**
1593
+ * Called at the start of every turn, after message accumulation and `onChatStart` (turn 0),
1594
+ * but before the `run` function executes.
1595
+ *
1596
+ * Use this to persist messages before streaming begins, so a mid-stream page refresh
1597
+ * still shows the user's message.
1598
+ *
1599
+ * @example
1600
+ * ```ts
1601
+ * onTurnStart: async ({ ctx, chatId, uiMessages }) => {
1602
+ * await db.chat.update({ where: { id: chatId }, data: { messages: uiMessages } });
1603
+ * }
1604
+ * ```
1605
+ */
1606
+ onTurnStart?: (event: TurnStartEvent<inferSchemaOut<TClientDataSchema>, TUIMessage>) => Promise<void> | void;
1607
+ /**
1608
+ * Called after the response is captured but before the stream closes.
1609
+ * The stream is still open, so you can write custom chunks to the frontend
1610
+ * (e.g. compaction progress). Use this for compaction, post-processing,
1611
+ * or any work where the user should see real-time status updates.
1612
+ *
1613
+ * @example
1614
+ * ```ts
1615
+ * onBeforeTurnComplete: async ({ ctx, writer, usage }) => {
1616
+ * if (usage?.inputTokens && usage.inputTokens > 5000) {
1617
+ * writer.write({ type: "data-compaction", id: generateId(), data: { status: "compacting" } });
1618
+ * // ... compact messages ...
1619
+ * chat.setMessages(compactedMessages);
1620
+ * writer.write({ type: "data-compaction", id: generateId(), data: { status: "complete" } });
1621
+ * }
1622
+ * }
1623
+ * ```
1624
+ */
1625
+ onBeforeTurnComplete?: (event: BeforeTurnCompleteEvent<inferSchemaOut<TClientDataSchema>, TUIMessage>) => Promise<void> | void;
1626
+ /**
1627
+ * Called when conversation compaction occurs (via `chat.compact()` or
1628
+ * `chat.compactionStep()`). Use for logging, billing, or persisting the summary.
1629
+ *
1630
+ * @example
1631
+ * ```ts
1632
+ * onCompacted: async ({ ctx, summary, totalTokens, chatId }) => {
1633
+ * logger.info("Compacted", { totalTokens, chatId });
1634
+ * await db.compactionLog.create({ data: { chatId, summary } });
1635
+ * }
1636
+ * ```
1637
+ */
1638
+ onCompacted?: (event: CompactedEvent) => Promise<void> | void;
1639
+ /**
1640
+ * Automatic context compaction. When provided, compaction runs automatically
1641
+ * in both the inner loop (prepareStep, between tool-call steps) and the
1642
+ * outer loop (between turns, for single-step responses where prepareStep
1643
+ * never fires).
1644
+ *
1645
+ * The `shouldCompact` callback decides when to compact, and `summarize`
1646
+ * generates the summary. The prepareStep is auto-injected into
1647
+ * `chat.toStreamTextOptions()` — if you provide your own `prepareStep`
1648
+ * after spreading, it overrides the auto-injected one.
1649
+ *
1650
+ * @example
1651
+ * ```ts
1652
+ * chat.agent({
1653
+ * id: "my-chat",
1654
+ * compaction: {
1655
+ * shouldCompact: ({ totalTokens }) => (totalTokens ?? 0) > 80_000,
1656
+ * summarize: async (messages) =>
1657
+ * generateText({ model, messages: [...messages, { role: "user", content: "Summarize." }] })
1658
+ * .then((r) => r.text),
1659
+ * },
1660
+ * run: async ({ messages, signal }) => {
1661
+ * return streamText({ ...chat.toStreamTextOptions({ registry }), messages });
1662
+ * },
1663
+ * });
1664
+ * ```
1665
+ */
1666
+ compaction?: ChatAgentCompactionOptions<TUIMessage>;
1667
+ /**
1668
+ * Configure how messages that arrive during streaming are handled.
1669
+ *
1670
+ * By default, messages queue for the next turn. When `shouldInject` is provided
1671
+ * and returns `true`, messages are injected between tool-call steps via
1672
+ * `prepareStep` — allowing users to steer the agent mid-execution.
1673
+ *
1674
+ * @example
1675
+ * ```ts
1676
+ * pendingMessages: {
1677
+ * shouldInject: ({ steps }) => steps.length > 0,
1678
+ * onReceived: ({ message }) => logger.info("Steering message received"),
1679
+ * },
1680
+ * ```
1681
+ */
1682
+ pendingMessages?: PendingMessagesOptions<TUIMessage>;
1683
+ /**
1684
+ * Called after each assistant response completes. Use to persist the
1685
+ * conversation to your database after each assistant response.
1686
+ *
1687
+ * @example
1688
+ * ```ts
1689
+ * onTurnComplete: async ({ ctx, chatId, messages }) => {
1690
+ * await db.chat.update({ where: { id: chatId }, data: { messages } });
1691
+ * }
1692
+ * ```
1693
+ */
1694
+ onTurnComplete?: (event: TurnCompleteEvent<inferSchemaOut<TClientDataSchema>, TUIMessage>) => Promise<void> | void;
1695
+ /**
1696
+ * Maximum number of conversational turns (message round-trips) a single run
1697
+ * will handle before ending. After this many turns the run completes
1698
+ * normally and the next message will start a fresh run.
1699
+ *
1700
+ * @default 100
1701
+ */
1702
+ maxTurns?: number;
1703
+ /**
1704
+ * How long to wait for the next message before timing out and ending the run.
1705
+ * Accepts any duration string (e.g. `"1h"`, `"30m"`).
1706
+ *
1707
+ * @default "1h"
1708
+ */
1709
+ turnTimeout?: string;
1710
+ /**
1711
+ * How long (in seconds) the run stays idle (active, using compute) after each
1712
+ * turn, waiting for the next message. During this window responses are instant.
1713
+ * After this timeout the run suspends (frees compute) and waits via
1714
+ * `inputStream.wait()`.
1715
+ *
1716
+ * Set to `0` to suspend immediately after each turn.
1717
+ *
1718
+ * @default 30
1719
+ */
1720
+ idleTimeoutInSeconds?: number;
1721
+ /**
1722
+ * How long the `chatAccessToken` (scoped to this run) remains valid.
1723
+ * A fresh token is minted after each turn, so this only needs to cover
1724
+ * the gap between turns.
1725
+ *
1726
+ * Accepts a duration string (e.g. `"1h"`, `"30m"`, `"2h"`).
1727
+ *
1728
+ * @default "1h"
1729
+ */
1730
+ chatAccessTokenTTL?: string;
1731
+ /**
1732
+ * How long (in seconds) the run stays idle after `onPreload` fires,
1733
+ * waiting for the first message before suspending.
1734
+ *
1735
+ * Only applies to preloaded runs (triggered via `transport.preload()`).
1736
+ * Takes precedence over `transport.preload(..., { idleTimeoutInSeconds })`
1737
+ * and over {@link ChatAgentOptions.idleTimeoutInSeconds}.
1738
+ *
1739
+ * @default Same as `idleTimeoutInSeconds`
1740
+ */
1741
+ preloadIdleTimeoutInSeconds?: number;
1742
+ /**
1743
+ * How long to wait (suspended) for the first message after a preloaded run starts.
1744
+ * If no message arrives within this time, the run ends.
1745
+ *
1746
+ * Only applies to preloaded runs.
1747
+ *
1748
+ * @default Same as `turnTimeout`
1749
+ */
1750
+ preloadTimeout?: string;
1751
+ /**
1752
+ * Transform model messages before they're used anywhere — in `run()`,
1753
+ * in compaction rebuilds, and in compaction results.
1754
+ *
1755
+ * Define once, applied everywhere. Use for Anthropic cache breaks,
1756
+ * injecting system context, stripping PII, etc.
1757
+ *
1758
+ * @example
1759
+ * ```ts
1760
+ * prepareMessages: async ({ messages, reason }) => {
1761
+ * // Add Anthropic cache breaks to the last message
1762
+ * if (messages.length === 0) return messages;
1763
+ * const last = messages[messages.length - 1];
1764
+ * return [...messages.slice(0, -1), {
1765
+ * ...last,
1766
+ * providerOptions: { ...last.providerOptions, anthropic: { cacheControl: { type: "ephemeral" } } },
1767
+ * }];
1768
+ * }
1769
+ * ```
1770
+ */
1771
+ prepareMessages?: (event: PrepareMessagesEvent<inferSchemaOut<TClientDataSchema>>) => ModelMessage[] | Promise<ModelMessage[]>;
1772
+ /**
1773
+ * Default options for `toUIMessageStream()` when auto-piping or using
1774
+ * `turn.complete()` / `chat.pipeAndCapture()`.
1775
+ *
1776
+ * Controls how the `StreamTextResult` is converted to a `UIMessageChunk`
1777
+ * stream — error handling, reasoning/source visibility, metadata, etc.
1778
+ *
1779
+ * Can be overridden per-turn by calling `chat.setUIMessageStreamOptions()`
1780
+ * inside `run()` or lifecycle hooks. Per-turn values are merged on top
1781
+ * of these defaults (per-turn wins on conflicts).
1782
+ *
1783
+ * `onFinish` and `originalMessages` are managed internally and cannot be
1784
+ * overridden here. Use `streamText`'s `onFinish` for custom finish
1785
+ * handling. `generateMessageId` can be set to control response message
1786
+ * ID generation (e.g. UUID-v7).
1787
+ *
1788
+ * @example
1789
+ * ```ts
1790
+ * chat.agent({
1791
+ * id: "my-chat",
1792
+ * uiMessageStreamOptions: {
1793
+ * sendReasoning: true,
1794
+ * onError: (error) => error instanceof Error ? error.message : "An error occurred.",
1795
+ * },
1796
+ * run: async ({ messages, signal }) => { ... },
1797
+ * });
1798
+ * ```
1799
+ */
1800
+ uiMessageStreamOptions?: ChatUIMessageStreamOptions<TUIMessage>;
1801
+ /**
1802
+ * Called right before the run suspends to wait for a message.
1803
+ *
1804
+ * The `phase` discriminator tells you when the suspend happened:
1805
+ * - `"preload"`: after `onPreload`, waiting for the first message
1806
+ * - `"turn"`: after `onTurnComplete`, waiting for the next message
1807
+ *
1808
+ * Use this for cleanup before suspension (e.g. disposing sandboxes, closing connections).
1809
+ *
1810
+ * @example
1811
+ * ```ts
1812
+ * onChatSuspend: async (event) => {
1813
+ * await disposeExpensiveResources(event.ctx.run.id);
1814
+ * if (event.phase === "turn") {
1815
+ * logger.info("Suspending after turn", { turn: event.turn });
1816
+ * }
1817
+ * }
1818
+ * ```
1819
+ */
1820
+ onChatSuspend?: (event: ChatSuspendEvent<inferSchemaOut<TClientDataSchema>, TUIMessage>) => Promise<void> | void;
1821
+ /**
1822
+ * Called right after the run resumes from suspension with a new message.
1823
+ *
1824
+ * The `phase` discriminator tells you when the resume happened:
1825
+ * - `"preload"`: first message arrived after preload suspension
1826
+ * - `"turn"`: next message arrived after turn suspension
1827
+ *
1828
+ * Use this for re-initialization after wake (e.g. warming caches, reconnecting).
1829
+ *
1830
+ * @example
1831
+ * ```ts
1832
+ * onChatResume: async (event) => {
1833
+ * warmCache(event.ctx.run.id);
1834
+ * if (event.phase === "turn") {
1835
+ * logger.info("Resumed after turn", { turn: event.turn });
1836
+ * }
1837
+ * }
1838
+ * ```
1839
+ */
1840
+ onChatResume?: (event: ChatResumeEvent<inferSchemaOut<TClientDataSchema>, TUIMessage>) => Promise<void> | void;
1841
+ /**
1842
+ * When `true`, the run exits successfully after the preload idle timeout
1843
+ * instead of suspending and waiting. The run completes with no turn executed.
1844
+ *
1845
+ * Use this for "fire and forget" preloads where you only want to do eager
1846
+ * initialization. If the user doesn't send a message during the idle window,
1847
+ * the run ends cleanly.
1848
+ *
1849
+ * Only applies to preloaded runs (triggered via `transport.preload()`).
1850
+ *
1851
+ * @default false
1852
+ */
1853
+ exitAfterPreloadIdle?: boolean;
1854
+ };
1855
+ /**
1856
+ * Creates a Trigger.dev task pre-configured for AI SDK chat.
1857
+ *
1858
+ * - **Pre-types the payload** as `ChatTaskRunPayload` — includes abort signals
1859
+ * - **Auto-pipes the stream** if `run` returns a `StreamTextResult`
1860
+ * - **Multi-turn**: keeps the conversation in a single run using input streams
1861
+ * - **Stop support**: frontend can stop generation mid-stream via the stop input stream
1862
+ * - For complex flows, use `pipeChat()` from anywhere inside your task code
1863
+ *
1864
+ * @example
1865
+ * ```ts
1866
+ * import { chat } from "@trigger.dev/sdk/ai";
1867
+ * import { streamText, convertToModelMessages } from "ai";
1868
+ * import { openai } from "@ai-sdk/openai";
1869
+ *
1870
+ * export const myChat = chat.agent({
1871
+ * id: "my-chat",
1872
+ * run: async ({ messages, signal }) => {
1873
+ * return streamText({
1874
+ * model: openai("gpt-4o"),
1875
+ * messages, // already converted via convertToModelMessages
1876
+ * abortSignal: signal,
1877
+ * });
1878
+ * },
1879
+ * });
1880
+ * ```
1881
+ */
1882
+ type ChatCustomAgentOptions<TIdentifier extends string, TClientDataSchema extends TaskSchema | undefined = undefined, TUIMessage extends UIMessage = UIMessage> = Omit<TaskOptions<TIdentifier, ChatTaskWirePayload<TUIMessage, inferSchemaIn<TClientDataSchema>>, unknown>, "triggerSource" | "agentConfig"> & {
1883
+ clientDataSchema?: TClientDataSchema;
1884
+ };
1885
+ 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>;
1886
+ declare function chatAgent<TIdentifier extends string, TClientDataSchema extends TaskSchema | undefined = undefined, TUIMessage extends UIMessage = UIMessage, TActionSchema extends TaskSchema | undefined = undefined>(options: ChatAgentOptions<TIdentifier, TClientDataSchema, TUIMessage, TActionSchema>): Task<TIdentifier, ChatTaskWirePayload<TUIMessage, inferSchemaIn<TClientDataSchema>>, unknown>;
1887
+ /**
1888
+ * Optional config for {@link chat.withUIMessage}. `streamOptions` become default
1889
+ * static `toUIMessageStream()` settings; inner `chat.agent({ uiMessageStreamOptions })`
1890
+ * shallow-merges on top (task wins on conflicts).
1891
+ */
1892
+ export type ChatWithUIMessageConfig<TUIM extends UIMessage = UIMessage> = {
1893
+ streamOptions?: ChatUIMessageStreamOptions<TUIM>;
1894
+ };
1895
+ /**
1896
+ * A chainable builder for configuring chat tasks with fixed UI message types,
1897
+ * client data schemas, and builder-level hooks that compose with task-level hooks.
1898
+ *
1899
+ * Obtain a builder via {@link chat.withUIMessage} or {@link chat.withClientData}.
1900
+ *
1901
+ * @example
1902
+ * ```ts
1903
+ * export const myChat = chat
1904
+ * .withUIMessage<AgentUiMessage>({ streamOptions: { sendReasoning: true } })
1905
+ * .withClientData({ schema: z.object({ userId: z.string() }) })
1906
+ * .onChatSuspend(async ({ ctx }) => { await disposeResources(ctx.run.id) })
1907
+ * .task({
1908
+ * id: "my-chat",
1909
+ * run: async ({ messages, signal }) => streamText({ model, messages, abortSignal: signal }),
1910
+ * });
1911
+ * ```
1912
+ */
1913
+ export interface ChatBuilder<TUIMessage extends UIMessage = UIMessage, TClientDataSchema extends TaskSchema | undefined = undefined> {
1914
+ /** Fix the UI message type. Returns a new builder preserving all accumulated state. */
1915
+ withUIMessage<TUIM extends UIMessage = UIMessage>(config?: ChatWithUIMessageConfig<TUIM>): ChatBuilder<TUIM, TClientDataSchema>;
1916
+ /** Fix the client data schema. Returns a new builder preserving all accumulated state. */
1917
+ withClientData<TSchema extends TaskSchema>(config: {
1918
+ schema: TSchema;
1919
+ }): ChatBuilder<TUIMessage, TSchema>;
1920
+ /** Register a builder-level `onBoot` hook. Runs before the task-level hook if both are set. */
1921
+ onBoot(fn: (event: BootEvent<inferSchemaOut<TClientDataSchema>>) => Promise<void> | void): ChatBuilder<TUIMessage, TClientDataSchema>;
1922
+ /** Register a builder-level `onPreload` hook. Runs before the task-level hook if both are set. */
1923
+ onPreload(fn: (event: PreloadEvent<inferSchemaOut<TClientDataSchema>>) => Promise<void> | void): ChatBuilder<TUIMessage, TClientDataSchema>;
1924
+ /** Register a builder-level `onChatStart` hook. Runs before the task-level hook if both are set. */
1925
+ onChatStart(fn: (event: ChatStartEvent<inferSchemaOut<TClientDataSchema>>) => Promise<void> | void): ChatBuilder<TUIMessage, TClientDataSchema>;
1926
+ /** Register a builder-level `onTurnStart` hook. Runs before the task-level hook if both are set. */
1927
+ onTurnStart(fn: (event: TurnStartEvent<inferSchemaOut<TClientDataSchema>, TUIMessage>) => Promise<void> | void): ChatBuilder<TUIMessage, TClientDataSchema>;
1928
+ /** Register a builder-level `onBeforeTurnComplete` hook. Runs before the task-level hook if both are set. */
1929
+ onBeforeTurnComplete(fn: (event: BeforeTurnCompleteEvent<inferSchemaOut<TClientDataSchema>, TUIMessage>) => Promise<void> | void): ChatBuilder<TUIMessage, TClientDataSchema>;
1930
+ /** Register a builder-level `onTurnComplete` hook. Runs before the task-level hook if both are set. */
1931
+ onTurnComplete(fn: (event: TurnCompleteEvent<inferSchemaOut<TClientDataSchema>, TUIMessage>) => Promise<void> | void): ChatBuilder<TUIMessage, TClientDataSchema>;
1932
+ /** Register a builder-level `onCompacted` hook. Runs before the task-level hook if both are set. */
1933
+ onCompacted(fn: (event: CompactedEvent) => Promise<void> | void): ChatBuilder<TUIMessage, TClientDataSchema>;
1934
+ /** Register a builder-level `onChatSuspend` hook. Runs before the task-level hook if both are set. */
1935
+ onChatSuspend(fn: (event: ChatSuspendEvent<inferSchemaOut<TClientDataSchema>, TUIMessage>) => Promise<void> | void): ChatBuilder<TUIMessage, TClientDataSchema>;
1936
+ /** Register a builder-level `onChatResume` hook. Runs before the task-level hook if both are set. */
1937
+ onChatResume(fn: (event: ChatResumeEvent<inferSchemaOut<TClientDataSchema>, TUIMessage>) => Promise<void> | void): ChatBuilder<TUIMessage, TClientDataSchema>;
1938
+ /**
1939
+ * Create the chat agent with the accumulated builder configuration.
1940
+ *
1941
+ * When `withClientData` was called, `clientDataSchema` is injected automatically
1942
+ * and omitted from options. Otherwise, it can still be set directly in options
1943
+ * (backwards compatible).
1944
+ */
1945
+ agent: [TClientDataSchema] extends [undefined] ? <TId extends string, TInfer extends TaskSchema | undefined = undefined, TAction extends TaskSchema | undefined = undefined>(options: ChatAgentOptions<TId, TInfer, TUIMessage, TAction>) => Task<TId, ChatTaskWirePayload<TUIMessage, inferSchemaIn<TInfer>>, unknown> : <TId extends string, TAction extends TaskSchema | undefined = undefined>(options: Omit<ChatAgentOptions<TId, TClientDataSchema, TUIMessage, TAction>, "clientDataSchema">) => Task<TId, ChatTaskWirePayload<TUIMessage, inferSchemaIn<TClientDataSchema>>, unknown>;
1946
+ /**
1947
+ * Create a custom agent with manual lifecycle control.
1948
+ *
1949
+ * The agent appears in the playground but you manage the turn loop,
1950
+ * message waiting, and streaming yourself using composable primitives
1951
+ * (`chat.messages`, `chat.MessageAccumulator`, `chat.pipeAndCapture`, etc.).
1952
+ *
1953
+ * Builder hooks (`onPreload`, `onChatStart`, etc.) are not applied —
1954
+ * those are managed-lifecycle concepts handled by `.agent()`.
1955
+ */
1956
+ 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>;
1957
+ }
1958
+ /**
1959
+ * Fix the UI message type for a chat task (AI SDK `UIMessage` generics) while
1960
+ * keeping `id` and `clientDataSchema` inference on the inner {@link chat.agent} call.
1961
+ *
1962
+ * Returns a {@link ChatBuilder} that supports chaining `.withClientData()`,
1963
+ * hook methods (`.onPreload()`, `.onChatSuspend()`, etc.), and `.task()`.
1964
+ *
1965
+ * @example
1966
+ * ```ts
1967
+ * type AgentUiMessage = UIMessage<unknown, UIDataTypes, UITools>;
1968
+ *
1969
+ * export const myChat = chat.withUIMessage<AgentUiMessage>({
1970
+ * streamOptions: { sendReasoning: true },
1971
+ * }).task({
1972
+ * id: "my-chat",
1973
+ * run: async ({ messages, signal }) => { ... },
1974
+ * });
1975
+ * ```
1976
+ */
1977
+ declare function withUIMessage<TUIM extends UIMessage = UIMessage>(config?: ChatWithUIMessageConfig<TUIM>): ChatBuilder<TUIM, undefined>;
1978
+ /**
1979
+ * Fix the client data schema for a chat task, providing typed `clientData`
1980
+ * in all hooks and the `run` function.
1981
+ *
1982
+ * Returns a {@link ChatBuilder} that supports chaining `.withUIMessage()`,
1983
+ * hook methods (`.onPreload()`, `.onChatSuspend()`, etc.), and `.task()`.
1984
+ *
1985
+ * @example
1986
+ * ```ts
1987
+ * export const myChat = chat
1988
+ * .withClientData({ schema: z.object({ userId: z.string() }) })
1989
+ * .task({
1990
+ * id: "my-chat",
1991
+ * onPreload: async ({ clientData }) => {
1992
+ * // clientData is typed as { userId: string }
1993
+ * },
1994
+ * run: async ({ messages, signal }) => { ... },
1995
+ * });
1996
+ * ```
1997
+ */
1998
+ declare function withClientData<TSchema extends TaskSchema>(config: {
1999
+ schema: TSchema;
2000
+ }): ChatBuilder<UIMessage, TSchema>;
2001
+ /**
2002
+ * Override the turn timeout for subsequent turns in the current run.
2003
+ *
2004
+ * The turn timeout controls how long the run stays suspended (freeing compute)
2005
+ * waiting for the next user message. When it expires, the run completes
2006
+ * gracefully and the next message starts a fresh run.
2007
+ *
2008
+ * Call from inside a `chatAgent` run function to adjust based on context.
2009
+ *
2010
+ * @param duration - A duration string (e.g. `"5m"`, `"1h"`, `"30s"`)
2011
+ *
2012
+ * @example
2013
+ * ```ts
2014
+ * run: async ({ messages, signal }) => {
2015
+ * chat.setTurnTimeout("2h");
2016
+ * return streamText({ model, messages, abortSignal: signal });
2017
+ * }
2018
+ * ```
2019
+ */
2020
+ declare function setTurnTimeout(duration: string): void;
2021
+ /**
2022
+ * Override the turn timeout in seconds for subsequent turns in the current run.
2023
+ *
2024
+ * @param seconds - Number of seconds to wait for the next message before ending the run
2025
+ *
2026
+ * @example
2027
+ * ```ts
2028
+ * run: async ({ messages, signal }) => {
2029
+ * chat.setTurnTimeoutInSeconds(3600); // 1 hour
2030
+ * return streamText({ model, messages, abortSignal: signal });
2031
+ * }
2032
+ * ```
2033
+ */
2034
+ declare function setTurnTimeoutInSeconds(seconds: number): void;
2035
+ /**
2036
+ * Override the idle timeout for subsequent turns in the current run.
2037
+ *
2038
+ * The idle timeout controls how long the run stays active (using compute)
2039
+ * after each turn, waiting for the next message. During this window,
2040
+ * responses are instant. After it expires, the run suspends.
2041
+ *
2042
+ * @param seconds - Number of seconds to stay idle (0 to suspend immediately)
2043
+ *
2044
+ * @example
2045
+ * ```ts
2046
+ * run: async ({ messages, signal }) => {
2047
+ * chat.setIdleTimeoutInSeconds(60);
2048
+ * return streamText({ model, messages, abortSignal: signal });
2049
+ * }
2050
+ * ```
2051
+ */
2052
+ declare function setIdleTimeoutInSeconds(seconds: number): void;
2053
+ /**
2054
+ * Override the `toUIMessageStream()` options for the current turn.
2055
+ *
2056
+ * These options control how the `StreamTextResult` is converted to a
2057
+ * `UIMessageChunk` stream — error handling, reasoning/source visibility,
2058
+ * message metadata, etc.
2059
+ *
2060
+ * Per-turn options are merged on top of the static `uiMessageStreamOptions`
2061
+ * set on `chat.agent()`. Per-turn values win on conflicts.
2062
+ *
2063
+ * @example
2064
+ * ```ts
2065
+ * run: async ({ messages, signal }) => {
2066
+ * chat.setUIMessageStreamOptions({
2067
+ * sendReasoning: true,
2068
+ * onError: (error) => error instanceof Error ? error.message : "An error occurred.",
2069
+ * });
2070
+ * return streamText({ model, messages, abortSignal: signal });
2071
+ * }
2072
+ * ```
2073
+ */
2074
+ declare function setUIMessageStreamOptions(options: ChatUIMessageStreamOptions<UIMessage>): void;
2075
+ /**
2076
+ * Check whether the user stopped generation during the current turn.
2077
+ *
2078
+ * Works from **anywhere** inside a `chat.agent` run — including inside
2079
+ * `streamText`'s `onFinish` callback — without needing to thread the
2080
+ * `stopSignal` through closures.
2081
+ *
2082
+ * This is especially useful when the AI SDK's `isAborted` flag is unreliable
2083
+ * (e.g. when using `createUIMessageStream` + `writer.merge()`).
2084
+ *
2085
+ * @example
2086
+ * ```ts
2087
+ * onFinish: ({ isAborted }) => {
2088
+ * const wasStopped = isAborted || chat.isStopped();
2089
+ * if (wasStopped) {
2090
+ * // handle stop
2091
+ * }
2092
+ * }
2093
+ * ```
2094
+ */
2095
+ declare function isStopped(): boolean;
2096
+ /**
2097
+ * Request that the current run exits so the next message starts on the latest
2098
+ * deployed version (via the standard continuation mechanism).
2099
+ *
2100
+ * When called from `onTurnStart` or `onValidateMessages`, `run()` is skipped
2101
+ * entirely — the run exits immediately and the transport re-triggers the
2102
+ * same message on the new version.
2103
+ *
2104
+ * When called from `run()` or `chat.defer()`, the current turn completes
2105
+ * normally and the run exits afterward instead of waiting for the next message.
2106
+ *
2107
+ * Call from `onTurnStart`, `onValidateMessages`, `onChatResume`, `run()`,
2108
+ * or inside `chat.defer()`.
2109
+ *
2110
+ * @example
2111
+ * ```ts
2112
+ * const SUPPORTED_VERSIONS = new Set(["v2", "v3"]);
2113
+ *
2114
+ * chat.agent({
2115
+ * id: "my-chat",
2116
+ * onTurnStart: async ({ clientData }) => {
2117
+ * if (clientData?.protocolVersion && !SUPPORTED_VERSIONS.has(clientData.protocolVersion)) {
2118
+ * chat.requestUpgrade();
2119
+ * }
2120
+ * },
2121
+ * run: async ({ messages }) => { ... },
2122
+ * });
2123
+ * ```
2124
+ */
2125
+ declare function requestUpgrade(): void;
2126
+ /**
2127
+ * Exit the run after the current turn completes, without waiting for the
2128
+ * next message. Unlike {@link requestUpgrade}, no upgrade-required signal
2129
+ * is sent to the client — the turn finishes normally, `onTurnComplete`
2130
+ * fires, and the loop exits instead of going idle.
2131
+ *
2132
+ * Call from `run()`, `chat.defer()`, `onBeforeTurnComplete`, or
2133
+ * `onTurnComplete` to end the run on your own terms (budget exhausted,
2134
+ * task complete, goal achieved, etc.).
2135
+ *
2136
+ * The next user message on the same `chatId` starts a fresh run via the
2137
+ * normal continuation mechanism.
2138
+ *
2139
+ * @example
2140
+ * ```ts
2141
+ * chat.agent({
2142
+ * id: "one-shot-agent",
2143
+ * run: async ({ messages, signal }) => {
2144
+ * const result = streamText({ model: openai("gpt-4o"), messages, abortSignal: signal });
2145
+ * // Single-response agent — exit after this turn.
2146
+ * chat.endRun();
2147
+ * return result;
2148
+ * },
2149
+ * });
2150
+ * ```
2151
+ */
2152
+ declare function endRun(): void;
2153
+ /**
2154
+ * Register a promise that runs in the background during the current turn.
2155
+ *
2156
+ * Use this to move non-blocking work (DB writes, analytics, etc.) out of
2157
+ * the critical path. The promise runs in parallel with streaming and is
2158
+ * awaited (with a 5 s timeout) before `onTurnComplete` fires.
2159
+ *
2160
+ * @example
2161
+ * ```ts
2162
+ * onTurnStart: async ({ chatId, uiMessages }) => {
2163
+ * // Pass a promise directly
2164
+ * chat.defer(db.chat.update({ where: { id: chatId }, data: { messages: uiMessages } }));
2165
+ *
2166
+ * // Or pass an async function — cleaner for multi-step work
2167
+ * chat.defer(async () => {
2168
+ * const flags = await getFeatureFlags();
2169
+ * if (flags.forceUpgrade) chat.requestUpgrade();
2170
+ * });
2171
+ * },
2172
+ * ```
2173
+ */
2174
+ declare function chatDefer(promiseOrFn: Promise<unknown> | (() => Promise<unknown>)): void;
2175
+ /**
2176
+ * Queue model messages for injection at the next `prepareStep` boundary.
2177
+ *
2178
+ * Use this to inject context from background work into the agent's conversation.
2179
+ * Messages are appended to the model messages before the next LLM inference call.
2180
+ *
2181
+ * Combine with `chat.defer()` to run background analysis and inject results:
2182
+ *
2183
+ * @example
2184
+ * ```ts
2185
+ * onTurnComplete: async ({ messages }) => {
2186
+ * chat.defer((async () => {
2187
+ * const review = await generateObject({
2188
+ * model: openai("gpt-4o-mini"),
2189
+ * messages: [...messages, { role: "user", content: "Review the last response." }],
2190
+ * schema: z.object({ suggestions: z.array(z.string()) }),
2191
+ * });
2192
+ * if (review.object.suggestions.length > 0) {
2193
+ * chat.inject([{
2194
+ * role: "system",
2195
+ * content: `Improvements for next response:\n${review.object.suggestions.join("\n")}`,
2196
+ * }]);
2197
+ * }
2198
+ * })());
2199
+ * },
2200
+ * ```
2201
+ */
2202
+ declare function injectBackgroundContext(messages: ModelMessage[]): void;
2203
+ /**
2204
+ * Clean up a UIMessage that was captured during an aborted/stopped turn.
2205
+ *
2206
+ * When generation is stopped mid-stream, the captured message may contain:
2207
+ * - Tool parts stuck in incomplete states (`partial-call`, `input-available`,
2208
+ * `input-streaming`) that cause permanent UI spinners
2209
+ * - Reasoning parts with `state: "streaming"` instead of `"done"`
2210
+ * - Text parts with `state: "streaming"` instead of `"done"`
2211
+ *
2212
+ * This function returns a cleaned copy with:
2213
+ * - Incomplete tool parts removed entirely
2214
+ * - Reasoning and text parts marked as `"done"`
2215
+ *
2216
+ * `chat.agent` calls this automatically when stop is detected before passing
2217
+ * the response to `onTurnComplete`. Use this manually when calling `pipeChat`
2218
+ * directly and capturing response messages yourself.
2219
+ *
2220
+ * @example
2221
+ * ```ts
2222
+ * onTurnComplete: async ({ responseMessage, stopped }) => {
2223
+ * // Already cleaned automatically by chat.agent — but if you captured
2224
+ * // your own message via pipeChat, clean it manually:
2225
+ * const cleaned = chat.cleanupAbortedParts(myMessage);
2226
+ * await db.messages.save(cleaned);
2227
+ * }
2228
+ * ```
2229
+ */
2230
+ declare function cleanupAbortedParts<TUIM extends UIMessage>(message: TUIM): TUIM;
2231
+ /**
2232
+ * Create a managed stop signal wired to the chat stop input stream.
2233
+ *
2234
+ * Call once at the start of your run. Use `signal` as the abort signal for
2235
+ * `streamText`. Call `reset()` at the start of each turn to get a fresh
2236
+ * per-turn signal. Call `cleanup()` when the run ends.
2237
+ *
2238
+ * @example
2239
+ * ```ts
2240
+ * const stop = chat.createStopSignal();
2241
+ * for (let turn = 0; turn < 100; turn++) {
2242
+ * stop.reset();
2243
+ * const result = streamText({ model, messages, abortSignal: stop.signal });
2244
+ * await chat.pipe(result);
2245
+ * // ...
2246
+ * }
2247
+ * stop.cleanup();
2248
+ * ```
2249
+ */
2250
+ declare function createStopSignal(): {
2251
+ readonly signal: AbortSignal;
2252
+ reset: () => void;
2253
+ cleanup: () => void;
2254
+ };
2255
+ /**
2256
+ * Signal the frontend that the current turn is complete.
2257
+ *
2258
+ * The `TriggerChatTransport` intercepts this to close the ReadableStream
2259
+ * for the current turn. Call after piping the response stream.
2260
+ *
2261
+ * @example
2262
+ * ```ts
2263
+ * await chat.pipe(result);
2264
+ * await chat.writeTurnComplete();
2265
+ * ```
2266
+ */
2267
+ declare function chatWriteTurnComplete(options?: {
2268
+ publicAccessToken?: string;
2269
+ }): Promise<void>;
2270
+ /**
2271
+ * Pipe a `StreamTextResult` (or similar) to the chat stream and capture
2272
+ * the assistant's response message via `onFinish`.
2273
+ *
2274
+ * Combines `toUIMessageStream()` + `onFinish` callback + `chat.pipe()`.
2275
+ * Returns the captured `UIMessage`, or `undefined` if capture failed.
2276
+ *
2277
+ * @example
2278
+ * ```ts
2279
+ * const result = streamText({ model, messages, abortSignal: signal });
2280
+ * const response = await chat.pipeAndCapture(result, { signal });
2281
+ * if (response) conversation.addResponse(response);
2282
+ * ```
2283
+ */
2284
+ declare function pipeChatAndCapture(source: UIMessageStreamable, options?: {
2285
+ signal?: AbortSignal;
2286
+ spanName?: string;
2287
+ }): Promise<UIMessage | undefined>;
2288
+ /**
2289
+ * Accumulates conversation messages across turns.
2290
+ *
2291
+ * Handles the transport protocol: turn 0 sends full history (replace),
2292
+ * subsequent turns send only new messages (append), regenerate sends
2293
+ * full history minus last assistant message (replace).
2294
+ *
2295
+ * @example
2296
+ * ```ts
2297
+ * const conversation = new chat.MessageAccumulator();
2298
+ * for (let turn = 0; turn < 100; turn++) {
2299
+ * const messages = await conversation.addIncoming(payload.messages, payload.trigger, turn);
2300
+ * const result = streamText({ model, messages });
2301
+ * const response = await chat.pipeAndCapture(result);
2302
+ * if (response) await conversation.addResponse(response);
2303
+ * }
2304
+ * ```
2305
+ */
2306
+ declare class ChatMessageAccumulator {
2307
+ modelMessages: ModelMessage[];
2308
+ uiMessages: UIMessage[];
2309
+ private _compaction?;
2310
+ private _pendingMessages?;
2311
+ private _steeringQueue;
2312
+ constructor(options?: {
2313
+ compaction?: ChatAgentCompactionOptions;
2314
+ pendingMessages?: PendingMessagesOptions;
2315
+ });
2316
+ /**
2317
+ * Add incoming messages from the transport payload.
2318
+ * Returns the full accumulated model messages for `streamText`.
2319
+ */
2320
+ addIncoming(messages: UIMessage[], trigger: string, turn: number): Promise<ModelMessage[]>;
2321
+ /**
2322
+ * Add the assistant's response to the accumulator.
2323
+ * Call after `pipeAndCapture` with the captured response.
2324
+ */
2325
+ /**
2326
+ * Replace all accumulated messages (for compaction).
2327
+ * Converts UIMessages to ModelMessages internally.
2328
+ */
2329
+ setMessages(uiMessages: UIMessage[]): Promise<void>;
2330
+ addResponse(response: UIMessage): Promise<void>;
2331
+ /**
2332
+ * Queue a message for injection via `prepareStep`. Call from a
2333
+ * `messagesInput.on()` listener when a message arrives during streaming.
2334
+ */
2335
+ steer(message: UIMessage, modelMessages?: ModelMessage[]): void;
2336
+ /**
2337
+ * Queue a message for injection, converting to model messages automatically.
2338
+ */
2339
+ steerAsync(message: UIMessage): Promise<void>;
2340
+ /**
2341
+ * Get and clear unconsumed steering messages.
2342
+ */
2343
+ drainSteering(): UIMessage[];
2344
+ /**
2345
+ * Returns a `prepareStep` function that handles both compaction and
2346
+ * pending message injection. Pass to `streamText({ prepareStep: conversation.prepareStep() })`.
2347
+ */
2348
+ prepareStep(): ((args: {
2349
+ messages: ModelMessage[];
2350
+ steps: CompactionStep[];
2351
+ }) => Promise<{
2352
+ messages: ModelMessage[];
2353
+ } | undefined>) | undefined;
2354
+ /**
2355
+ * Run outer-loop compaction if needed. Call after adding the response
2356
+ * and capturing usage. Applies `compactModelMessages` and `compactUIMessages`
2357
+ * callbacks if configured.
2358
+ *
2359
+ * @returns `true` if compaction was performed, `false` otherwise.
2360
+ */
2361
+ compactIfNeeded(usage: LanguageModelUsage | undefined, context?: {
2362
+ chatId?: string;
2363
+ turn?: number;
2364
+ clientData?: unknown;
2365
+ totalUsage?: LanguageModelUsage;
2366
+ }): Promise<boolean>;
2367
+ }
2368
+ export type ChatSessionOptions = {
2369
+ /** Run-level cancel signal (from task context). */
2370
+ signal: AbortSignal;
2371
+ /** Seconds to stay idle between turns before suspending. @default 30 */
2372
+ idleTimeoutInSeconds?: number;
2373
+ /** Duration string for suspend timeout. @default "1h" */
2374
+ timeout?: string;
2375
+ /** Max turns before ending. @default 100 */
2376
+ maxTurns?: number;
2377
+ /** Automatic context compaction — same options as `chat.agent({ compaction })`. */
2378
+ compaction?: ChatAgentCompactionOptions;
2379
+ /** Configure mid-execution message injection — same options as `chat.agent({ pendingMessages })`. */
2380
+ pendingMessages?: PendingMessagesOptions;
2381
+ };
2382
+ export type ChatTurn = {
2383
+ /** Turn number (0-indexed). */
2384
+ number: number;
2385
+ /** Chat session ID. */
2386
+ chatId: string;
2387
+ /** What triggered this turn. */
2388
+ trigger: string;
2389
+ /** Client data from the transport (`metadata` field on the wire payload). */
2390
+ clientData: unknown;
2391
+ /** Full accumulated model messages — pass directly to `streamText`. */
2392
+ readonly messages: ModelMessage[];
2393
+ /** Full accumulated UI messages — use for persistence. */
2394
+ readonly uiMessages: UIMessage[];
2395
+ /** Combined stop+cancel AbortSignal (fresh each turn). */
2396
+ signal: AbortSignal;
2397
+ /** Whether the user stopped generation this turn. */
2398
+ readonly stopped: boolean;
2399
+ /** Whether this is a continuation run. */
2400
+ continuation: boolean;
2401
+ /** Token usage from the previous turn. Undefined on turn 0. */
2402
+ previousTurnUsage?: LanguageModelUsage;
2403
+ /** Cumulative token usage across all completed turns so far. */
2404
+ totalUsage: LanguageModelUsage;
2405
+ /**
2406
+ * Replace accumulated messages (for compaction). Takes UIMessages and
2407
+ * converts to ModelMessages internally. After calling this, `turn.messages`
2408
+ * reflects the compacted history.
2409
+ */
2410
+ setMessages(uiMessages: UIMessage[]): Promise<void>;
2411
+ /**
2412
+ * Easy path: pipe stream, capture response, accumulate it,
2413
+ * clean up aborted parts if stopped, and write turn-complete chunk.
2414
+ */
2415
+ complete(source: UIMessageStreamable): Promise<UIMessage | undefined>;
2416
+ /**
2417
+ * Manual path: just write turn-complete chunk.
2418
+ * Use when you've already piped and accumulated manually.
2419
+ */
2420
+ done(): Promise<void>;
2421
+ /**
2422
+ * Add the response to the accumulator manually.
2423
+ * Use with `chat.pipeAndCapture` when you need control between pipe and done.
2424
+ */
2425
+ addResponse(response: UIMessage): Promise<void>;
2426
+ /**
2427
+ * Returns a `prepareStep` function that handles both compaction and
2428
+ * pending message injection. Pass to `streamText({ prepareStep: turn.prepareStep() })`.
2429
+ * Only needed when not using `chat.toStreamTextOptions()` (which auto-injects it).
2430
+ */
2431
+ prepareStep(): ((args: {
2432
+ messages: ModelMessage[];
2433
+ steps: CompactionStep[];
2434
+ }) => Promise<{
2435
+ messages: ModelMessage[];
2436
+ } | undefined>) | undefined;
2437
+ };
2438
+ /**
2439
+ * Create a chat session that yields turns as an async iterator.
2440
+ *
2441
+ * Handles: preload wait, stop signals, message accumulation, turn-complete
2442
+ * signaling, and idle/suspend between turns. You control: initialization,
2443
+ * model/tool selection, persistence, and any custom per-turn logic.
2444
+ *
2445
+ * @example
2446
+ * ```ts
2447
+ * import { task } from "@trigger.dev/sdk";
2448
+ * import { chat, type ChatTaskWirePayload } from "@trigger.dev/sdk/ai";
2449
+ * import { streamText } from "ai";
2450
+ * import { openai } from "@ai-sdk/openai";
2451
+ *
2452
+ * export const myChat = task({
2453
+ * id: "my-chat",
2454
+ * run: async (payload: ChatTaskWirePayload, { signal }) => {
2455
+ * const session = chat.createSession(payload, { signal });
2456
+ *
2457
+ * for await (const turn of session) {
2458
+ * const result = streamText({
2459
+ * model: openai("gpt-4o"),
2460
+ * messages: turn.messages,
2461
+ * abortSignal: turn.signal,
2462
+ * });
2463
+ * await turn.complete(result);
2464
+ * }
2465
+ * },
2466
+ * });
2467
+ * ```
2468
+ */
2469
+ declare function createChatSession(payload: ChatTaskWirePayload, options: ChatSessionOptions): AsyncIterable<ChatTurn>;
2470
+ /**
2471
+ * A Proxy-backed, run-scoped data object that appears as `T` to users.
2472
+ * Includes helper methods for initialization, dirty tracking, and serialization.
2473
+ * Internal metadata is stored behind Symbols and invisible to
2474
+ * `Object.keys()`, `JSON.stringify()`, and spread.
2475
+ */
2476
+ export type ChatLocal<T extends Record<string, unknown>> = T & {
2477
+ /** Initialize the local with a value. Call in `onChatStart` or `run()`. */
2478
+ init(value: T): void;
2479
+ /** Returns `true` if any property was set since the last check. Resets the dirty flag. */
2480
+ hasChanged(): boolean;
2481
+ /** Returns a plain object copy of the current value. Useful for persistence. */
2482
+ get(): T;
2483
+ readonly [CHAT_LOCAL_KEY]: ReturnType<typeof locals.create<T>>;
2484
+ readonly [CHAT_LOCAL_DIRTY_KEY]: ReturnType<typeof locals.create<boolean>>;
2485
+ };
2486
+ /**
2487
+ * Creates a per-run typed data object accessible from anywhere during task execution.
2488
+ *
2489
+ * Declare at module level, then initialize inside `onBoot` (recommended — fires
2490
+ * on every fresh worker including continuation runs). Do NOT initialize in
2491
+ * `onChatStart` alone: `onChatStart` only fires on the chat's very first
2492
+ * message, so `chat.local` would be uninitialized on continuation runs and
2493
+ * `run()` would throw.
2494
+ *
2495
+ * Multiple locals can coexist — each gets its own isolated run-scoped storage.
2496
+ *
2497
+ * The `id` is required and must be unique across all `chat.local()` calls in
2498
+ * your project. It's used to serialize values into subtask metadata so that
2499
+ * `ai.toolExecute()` (or legacy `ai.tool()`) subtasks can auto-hydrate parent locals (read-only).
2500
+ *
2501
+ * @example
2502
+ * ```ts
2503
+ * import { chat } from "@trigger.dev/sdk/ai";
2504
+ *
2505
+ * const userPrefs = chat.local<{ theme: string; language: string }>({ id: "userPrefs" });
2506
+ * const gameState = chat.local<{ score: number; streak: number }>({ id: "gameState" });
2507
+ *
2508
+ * export const myChat = chat.agent({
2509
+ * id: "my-chat",
2510
+ * onBoot: async ({ clientData }) => {
2511
+ * const prefs = await db.prefs.findUnique({ where: { userId: clientData.userId } });
2512
+ * userPrefs.init(prefs ?? { theme: "dark", language: "en" });
2513
+ * gameState.init({ score: 0, streak: 0 });
2514
+ * },
2515
+ * onTurnComplete: async ({ chatId }) => {
2516
+ * if (gameState.hasChanged()) {
2517
+ * await db.save({ where: { chatId }, data: gameState.get() });
2518
+ * }
2519
+ * },
2520
+ * run: async ({ messages }) => {
2521
+ * gameState.score++;
2522
+ * return streamText({
2523
+ * system: `User prefers ${userPrefs.theme} theme. Score: ${gameState.score}`,
2524
+ * messages,
2525
+ * });
2526
+ * },
2527
+ * });
2528
+ * ```
2529
+ */
2530
+ declare function chatLocal<T extends Record<string, unknown>>(options: {
2531
+ id: string;
2532
+ }): ChatLocal<T>;
2533
+ /**
2534
+ * Extracts the client data (metadata) type from a chat task.
2535
+ * Use this to type the `metadata` option on the transport.
2536
+ *
2537
+ * @example
2538
+ * ```ts
2539
+ * import type { InferChatClientData } from "@trigger.dev/sdk/ai";
2540
+ * import type { myChat } from "@/trigger/chat";
2541
+ *
2542
+ * type MyClientData = InferChatClientData<typeof myChat>;
2543
+ * // { model?: string; userId: string }
2544
+ * ```
2545
+ */
2546
+ import type { InferChatClientData } from "./ai-shared.js";
2547
+ export type { InferChatClientData, InferChatUIMessage } from "./ai-shared.js";
2548
+ /**
2549
+ * Options for {@link createChatStartSessionAction}.
2550
+ */
2551
+ /**
2552
+ * Discriminator for per-endpoint `baseURL` / `fetch` callbacks on
2553
+ * `createChatStartSessionAction`.
2554
+ *
2555
+ * - `"sessions"` — `POST /api/v1/sessions` (session create + first run trigger).
2556
+ * - `"auth"` — `POST /api/v1/auth/jwt/claims` (only fired when
2557
+ * `tokenTTL` is set; otherwise the publicAccessToken from session create
2558
+ * is reused as-is).
2559
+ */
2560
+ export type ChatStartSessionEndpoint = "sessions" | "auth";
2561
+ export type ChatStartSessionEndpointContext = {
2562
+ endpoint: ChatStartSessionEndpoint;
2563
+ chatId: string;
2564
+ };
2565
+ export type ChatStartSessionBaseURLResolver = (ctx: ChatStartSessionEndpointContext) => string;
2566
+ export type ChatStartSessionFetchOverride = (url: string, init: RequestInit, ctx: ChatStartSessionEndpointContext) => Promise<Response>;
2567
+ export type CreateChatStartSessionActionOptions = {
2568
+ /** TTL for the session-scoped public access token. @default "1h" */
2569
+ tokenTTL?: string | number | Date;
2570
+ /**
2571
+ * Default trigger config used when starting a new session for a chat.
2572
+ * Per-call `params.triggerConfig` shallow-merges on top.
2573
+ */
2574
+ triggerConfig?: Partial<SessionTriggerConfig>;
2575
+ /**
2576
+ * Override the Trigger.dev API base URL. String applies to both
2577
+ * `/api/v1/sessions` and `/api/v1/auth/jwt/claims`; function picks per
2578
+ * endpoint. When unset, falls back to `apiClientManager.baseURL`
2579
+ * (typically the `TRIGGER_API_URL` env var). Set this to route session
2580
+ * create through a trusted edge proxy that injects server-side signal
2581
+ * into `basePayload.metadata` before forwarding upstream.
2582
+ */
2583
+ baseURL?: string | ChatStartSessionBaseURLResolver;
2584
+ /**
2585
+ * Per-request fetch override. Receives the resolved URL, RequestInit,
2586
+ * and endpoint context. Use for header injection, proxy routing, or
2587
+ * custom retry. Applies to both session-create and JWT-claims POSTs.
2588
+ */
2589
+ fetch?: ChatStartSessionFetchOverride;
2590
+ };
2591
+ /**
2592
+ * Params for the function returned by {@link createChatStartSessionAction}.
2593
+ */
2594
+ export type ChatStartSessionParams<TChat extends AnyTask = AnyTask> = {
2595
+ /** Conversation id (mapped to the Session's `externalId`). */
2596
+ chatId: string;
2597
+ /**
2598
+ * Typed client data — folded into the first run's `payload.metadata` so
2599
+ * `onPreload`, `onChatStart`, etc. see the same `clientData` shape on the
2600
+ * first turn as subsequent turns get via the transport's `clientData`
2601
+ * option. Typed via the agent's `clientDataSchema` when the action is
2602
+ * parameterised with `createStartSessionAction<typeof myChat>(...)`.
2603
+ */
2604
+ clientData?: InferChatClientData<TChat>;
2605
+ /**
2606
+ * Per-call trigger config. Shallow-merged over the action's default
2607
+ * `triggerConfig`. `basePayload` is the customer's wire payload (for
2608
+ * `chat.agent`: anything beyond `chatId`/`messages`/`trigger`/`metadata`,
2609
+ * which the runtime injects automatically).
2610
+ */
2611
+ triggerConfig?: Partial<SessionTriggerConfig>;
2612
+ /**
2613
+ * Opaque session-level metadata stored on the Session row. Separate from
2614
+ * the per-turn `clientData` above. Use this when you want to attach
2615
+ * server-side metadata that doesn't go through the agent's `clientDataSchema`.
2616
+ */
2617
+ metadata?: Record<string, unknown>;
2618
+ };
2619
+ /**
2620
+ * Result from {@link createChatStartSessionAction}'s returned function.
2621
+ */
2622
+ export type ChatStartSessionResult = {
2623
+ /**
2624
+ * Session-scoped public access token (`read:sessions:{chatId} +
2625
+ * write:sessions:{chatId}`). Pass this to the browser; the transport
2626
+ * uses it to call `.in/append`, `.out`, `end-and-continue`.
2627
+ */
2628
+ publicAccessToken: string;
2629
+ /** Friendly id of the run triggered alongside session create. */
2630
+ runId: string;
2631
+ /** Session friendlyId — informational. */
2632
+ sessionId: string;
2633
+ };
2634
+ /**
2635
+ * Creates a server-side helper that starts (or resumes) a Session for a
2636
+ * given chatId — atomically creating the row, triggering the first run,
2637
+ * and returning a session-scoped PAT for the browser to use.
2638
+ *
2639
+ * Wrap in a Next.js server action (or any server-side handler) so the
2640
+ * customer's secret key never crosses to the browser.
2641
+ *
2642
+ * Parameterise the action with `<typeof yourChatAgent>` to type the
2643
+ * `clientData` field against your agent's `clientDataSchema`.
2644
+ *
2645
+ * @example
2646
+ * ```ts
2647
+ * // actions.ts
2648
+ * "use server";
2649
+ * import { chat } from "@trigger.dev/sdk/ai";
2650
+ * import type { myChat } from "@/trigger/chat";
2651
+ *
2652
+ * export const startChatSession = chat.createStartSessionAction<typeof myChat>(
2653
+ * "my-chat",
2654
+ * { triggerConfig: { machine: "small-1x" } }
2655
+ * );
2656
+ * ```
2657
+ *
2658
+ * Then in the browser, threading the typed `clientData` from the transport:
2659
+ * ```tsx
2660
+ * const transport = useTriggerChatTransport<typeof myChat>({
2661
+ * task: "my-chat",
2662
+ * accessToken: ({ chatId }) => mintChatAccessToken(chatId),
2663
+ * startSession: ({ chatId, clientData }) =>
2664
+ * startChatSession({ chatId, clientData }),
2665
+ * });
2666
+ * ```
2667
+ */
2668
+ declare function createChatStartSessionAction<TChat extends AnyTask = AnyTask>(taskId: string, options?: CreateChatStartSessionActionOptions): (params: ChatStartSessionParams<TChat>) => Promise<ChatStartSessionResult>;
2669
+ export declare const chat: {
2670
+ /** Create a chat agent. See {@link chatAgent}. */
2671
+ agent: typeof chatAgent;
2672
+ /** Create a custom agent with manual lifecycle control. See {@link chatCustomAgent}. */
2673
+ customAgent: typeof chatCustomAgent;
2674
+ /** Create a chat task with a fixed {@link UIMessage} subtype and optional default stream options. See {@link withUIMessage}. */
2675
+ withUIMessage: typeof withUIMessage;
2676
+ /** Create a chat task with a fixed client data schema. See {@link withClientData}. */
2677
+ withClientData: typeof withClientData;
2678
+ /** Create a server-side helper for starting (or resuming) a Session for a chatId. See {@link createChatStartSessionAction}. */
2679
+ createStartSessionAction: typeof createChatStartSessionAction;
2680
+ /** Pipe a stream to the chat transport. See {@link pipeChat}. */
2681
+ pipe: typeof pipeChat;
2682
+ /** Create a per-run typed local. See {@link chatLocal}. */
2683
+ local: typeof chatLocal;
2684
+ /** Create a public access token for a chat task. See {@link createChatAccessToken}. */
2685
+ createAccessToken: typeof createChatAccessToken;
2686
+ /** Override the turn timeout at runtime (duration string). See {@link setTurnTimeout}. */
2687
+ setTurnTimeout: typeof setTurnTimeout;
2688
+ /** Override the turn timeout at runtime (seconds). See {@link setTurnTimeoutInSeconds}. */
2689
+ setTurnTimeoutInSeconds: typeof setTurnTimeoutInSeconds;
2690
+ /** Override the idle timeout at runtime. See {@link setIdleTimeoutInSeconds}. */
2691
+ setIdleTimeoutInSeconds: typeof setIdleTimeoutInSeconds;
2692
+ /** Override toUIMessageStream() options for the current turn. See {@link setUIMessageStreamOptions}. */
2693
+ setUIMessageStreamOptions: typeof setUIMessageStreamOptions;
2694
+ /** Check if the current turn was stopped by the user. See {@link isStopped}. */
2695
+ isStopped: typeof isStopped;
2696
+ /** Request that the run exits after the current turn so the next message starts on the latest version. See {@link requestUpgrade}. */
2697
+ requestUpgrade: typeof requestUpgrade;
2698
+ /** Exit the run after the current turn completes, without any upgrade signal. See {@link endRun}. */
2699
+ endRun: typeof endRun;
2700
+ /** Clean up aborted parts from a UIMessage. See {@link cleanupAbortedParts}. */
2701
+ cleanupAbortedParts: typeof cleanupAbortedParts;
2702
+ /** Register background work that runs in parallel with streaming. See {@link chatDefer}. */
2703
+ defer: typeof chatDefer;
2704
+ /** Queue model messages for injection at the next `prepareStep` boundary. See {@link injectBackgroundContext}. */
2705
+ inject: typeof injectBackgroundContext;
2706
+ /** Typed chat output stream for writing custom chunks or piping from subtasks. */
2707
+ stream: RealtimeDefinedStream<UIMessageChunk>;
2708
+ /** Write data parts that persist to the response message. See {@link chatResponse}. */
2709
+ response: {
2710
+ /**
2711
+ * Write a single chunk. Non-transient data parts are accumulated into the
2712
+ * response message; everything else is stream-only.
2713
+ */
2714
+ write(part: UIMessageChunk): void;
2715
+ };
2716
+ /** Pre-built input stream for receiving messages from the transport. */
2717
+ messages: RealtimeDefinedInputStream<ChatTaskWirePayload>;
2718
+ /** Create a managed stop signal wired to the stop input stream. See {@link createStopSignal}. */
2719
+ createStopSignal: typeof createStopSignal;
2720
+ /** Signal the frontend that the current turn is complete. See {@link chatWriteTurnComplete}. */
2721
+ writeTurnComplete: typeof chatWriteTurnComplete;
2722
+ /** Pipe a stream and capture the response message. See {@link pipeChatAndCapture}. */
2723
+ pipeAndCapture: typeof pipeChatAndCapture;
2724
+ /** Message accumulator class for raw task chat. See {@link ChatMessageAccumulator}. */
2725
+ MessageAccumulator: typeof ChatMessageAccumulator;
2726
+ /** Create a chat session (async iterator). See {@link createChatSession}. */
2727
+ createSession: typeof createChatSession;
2728
+ /**
2729
+ * Store and retrieve a resolved prompt for the current run.
2730
+ *
2731
+ * - `chat.prompt.set(resolved)` — store a `ResolvedPrompt` or plain string
2732
+ * - `chat.prompt()` — read the stored prompt (throws if not set)
2733
+ */
2734
+ prompt: typeof getChatPrompt & {
2735
+ set: typeof setChatPrompt;
2736
+ };
2737
+ /**
2738
+ * Store and retrieve resolved agent skills for the current run.
2739
+ *
2740
+ * - `chat.skills.set([...])` — store an array of `ResolvedSkill`s
2741
+ * - `chat.skills()` — read the stored skills (returns undefined if none)
2742
+ *
2743
+ * Skills set here are automatically injected into `streamText` by
2744
+ * `chat.toStreamTextOptions()`: skill descriptions land in the system
2745
+ * prompt and `loadSkill` / `readFile` / `bash` tools are added to the
2746
+ * tool set.
2747
+ */
2748
+ skills: typeof getChatSkills & {
2749
+ set: typeof setChatSkills;
2750
+ };
2751
+ /**
2752
+ * Returns an options object ready to spread into `streamText()`.
2753
+ * Reads the stored prompt and returns `{ system, experimental_telemetry, ...config }`.
2754
+ * Returns `{}` if no prompt has been set.
2755
+ */
2756
+ toStreamTextOptions: typeof toStreamTextOptions;
2757
+ /**
2758
+ * Replace the accumulated conversation messages for compaction.
2759
+ * Call from `onTurnStart` or `onTurnComplete`. Takes `UIMessage[]` and
2760
+ * converts to `ModelMessage[]` internally.
2761
+ */
2762
+ setMessages: typeof setChatMessages;
2763
+ /**
2764
+ * Imperative API for modifying the accumulated message history.
2765
+ * Supports rollback, remove, replace, slice, and full replacement.
2766
+ * Can be called from any hook or `run()`.
2767
+ */
2768
+ history: {
2769
+ /** Read the current accumulated UI messages (copy). */
2770
+ all(): UIMessage[];
2771
+ /**
2772
+ * Read the current chain as an ordered `UIMessage[]`. Identical to
2773
+ * `all()`; use whichever name reads better in context.
2774
+ */
2775
+ getChain(): UIMessage[];
2776
+ /**
2777
+ * Find a message by id. Returns `undefined` if no message with that id
2778
+ * is present in the current chain.
2779
+ */
2780
+ findMessage(messageId: string): UIMessage | undefined;
2781
+ /**
2782
+ * Tool calls on the *most recent* assistant message that are still in
2783
+ * `input-available` state (waiting on an `addToolOutput` answer). The
2784
+ * scan walks back from the tail and stops at the first assistant
2785
+ * message it finds, so a trailing user message does not change the
2786
+ * result — pending tool calls remain pending until they're resolved
2787
+ * on that assistant or the assistant is removed.
2788
+ *
2789
+ * Use this to gate fresh user turns or actions during HITL flows: if
2790
+ * `getPendingToolCalls().length > 0`, an `addToolOutput` is expected.
2791
+ *
2792
+ * Returns `[]` if there is no assistant message yet, or if the most
2793
+ * recent assistant has no pending tool calls.
2794
+ *
2795
+ * Approval flows (`approval-requested` / `approval-responded` states)
2796
+ * are not surfaced here. Those are about the user authorizing a tool
2797
+ * to run; "pending" is about the user *answering* a tool call.
2798
+ */
2799
+ getPendingToolCalls(): ChatToolCallRef[];
2800
+ /**
2801
+ * Tool calls across the chain with a final result (`output-available`
2802
+ * or `output-error`). Use this to dedup re-saves when the AI SDK
2803
+ * resends an assistant message with progressively more answered parts.
2804
+ */
2805
+ getResolvedToolCalls(): ChatToolCallRef[];
2806
+ /**
2807
+ * Pure helper: returns the tool parts in `message` whose results are
2808
+ * not already represented in the current chain. Use this when
2809
+ * persisting tool results to your own store: each call surfaces only
2810
+ * the *new* answers, so writes stay idempotent across re-streams.
2811
+ * Duplicate `toolCallId`s within `message` itself are also collapsed
2812
+ * to a single entry.
2813
+ */
2814
+ extractNewToolResults(message: UIMessage): ChatNewToolResult[];
2815
+ /** Replace all accumulated messages. Same as `chat.setMessages()`. */
2816
+ set(messages: UIMessage[]): void;
2817
+ /** Remove a specific message by ID. */
2818
+ remove(messageId: string): void;
2819
+ /** Keep messages up to and including the given ID (undo/rollback). */
2820
+ rollbackTo(messageId: string): void;
2821
+ /** Replace a specific message by ID (edit). */
2822
+ replace(messageId: string, message: UIMessage): void;
2823
+ /** Keep only messages in the given range. */
2824
+ slice(start: number, end?: number): void;
2825
+ };
2826
+ /** Check if it's safe to compact messages (no in-flight tool calls). */
2827
+ isCompactionSafe: typeof isCompactionSafe;
2828
+ /** Returns a `prepareStep` function that handles context compaction automatically. */
2829
+ compactionStep: typeof chatCompactionStep;
2830
+ /** Low-level compaction for use inside a custom `prepareStep`. */
2831
+ compact: typeof chatCompact;
2832
+ /** Read the current compaction state (summary + base message count). */
2833
+ getCompactionState: typeof getCompactionState;
2834
+ /**
2835
+ * The friendlyId (`session_*`) of the backing Session for the current chat.agent run.
2836
+ * Useful for persisting alongside `runId` so reloads can resume the same session.
2837
+ * Throws if called outside a chat.agent `run()` or hook.
2838
+ */
2839
+ readonly sessionId: string;
21
2840
  };
22
- export {};