@ai-sdk/workflow 2.0.58 → 2.0.59

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { n as normalizeUIMessageStreamParts, t as WorkflowChatTransport } from "./workflow-chat-transport-Bduf4ZDx.js";
2
- import { asArray, asSchema, getErrorMessage, isAbortError, jsonSchema, validateTypes, withUserAgentSuffix } from "@ai-sdk/provider-utils";
3
- import { DefaultGeneratedFile, InvalidToolApprovalSignatureError, Output, dynamicTool, experimental_filterActiveTools, experimental_streamLanguageModelCall, gateway, tool, wrapLanguageModel } from "ai";
4
- import { collectToolApprovals, convertToLanguageModelPrompt, createDefaultDownloadFunction, createRestrictedTelemetryDispatcher, createToolModelOutput, createToolSearchState, downloadAssets, mapToolResultOutput, mergeAbortSignals, mergeCallbacks, prepareRetries, signToolApproval, standardizePrompt, validateApprovedToolApprovals, verifyToolApprovalSignature } from "ai/internal";
2
+ import { asArray, asSchema, convertUint8ArrayToBase64, generateId, getErrorMessage, isAbortError, jsonSchema, validateTypes, withUserAgentSuffix } from "@ai-sdk/provider-utils";
3
+ import { DefaultGeneratedFile, InvalidToolApprovalSignatureError, NoOutputGeneratedError, Output, ToolChoiceViolationError, dynamicTool, experimental_filterActiveTools, experimental_streamLanguageModelCall, gateway, isStepCount, tool, wrapLanguageModel } from "ai";
4
+ import { DefaultGenerateTextResult, DefaultStepResult, addLanguageModelUsage, asLanguageModelUsage, calculateTokensPerSecond, collectToolApprovals, convertLanguageModelContent, convertToLanguageModelPrompt, createDefaultDownloadFunction, createNullLanguageModelUsage, createRestrictedTelemetryDispatcher, createToolModelOutput, createToolSearchState, downloadAssets, mapToolResultOutput, mergeAbortSignals, mergeCallbacks, parseToolCall, prepareLanguageModelCallOptions, prepareRetries, prepareToolChoice, prepareTools, resolveLanguageModel, signToolApproval, standardizePrompt, validateApprovedToolApprovals, verifyToolApprovalSignature } from "ai/internal";
5
5
  import { getWorkflowMetadata } from "workflow";
6
6
  import Ajv from "ajv";
7
7
  //#region src/add-tool-results-to-conversation.ts
@@ -118,6 +118,265 @@ async function resolveToolContext({ toolName, tool, toolsContext }) {
118
118
  });
119
119
  }
120
120
  //#endregion
121
+ //#region src/to-model-response-messages.ts
122
+ /** Convert provider file references back to public message data without re-running tool output hooks. */
123
+ function toModelResponseMessages(messages) {
124
+ return messages.map((message) => message.role !== "assistant" ? message : {
125
+ ...message,
126
+ content: message.content.map((part) => {
127
+ if (part.type !== "file" && part.type !== "reasoning-file") return part;
128
+ return {
129
+ ...part,
130
+ data: part.data.type === "data" ? part.data.data : part.data.type === "url" ? part.data.url : part.data
131
+ };
132
+ })
133
+ });
134
+ }
135
+ //#endregion
136
+ //#region src/build-model-step-result.ts
137
+ async function buildModelStepResult(raw, toolCalls, finish, providerExecutedToolResults, opts) {
138
+ if (raw.generation != null && finish != null) {
139
+ const providerContent = [];
140
+ for (const part of raw.content) switch (part.type) {
141
+ case "reasoning":
142
+ if (!("reasoningIndex" in part)) providerContent.push(part);
143
+ break;
144
+ case "tool-call": {
145
+ const call = toolCalls[part.toolCallIndex];
146
+ providerContent.push({
147
+ ...call,
148
+ input: "",
149
+ type: "tool-call"
150
+ });
151
+ break;
152
+ }
153
+ case "provider-tool-result":
154
+ providerContent.push({
155
+ ...providerExecutedToolResults.get(part.toolCallId),
156
+ type: "tool-result"
157
+ });
158
+ break;
159
+ case "file":
160
+ providerContent.push({
161
+ ...part,
162
+ data: {
163
+ type: "data",
164
+ data: part.data
165
+ }
166
+ });
167
+ break;
168
+ default: providerContent.push(part);
169
+ }
170
+ const content = await convertLanguageModelContent({
171
+ content: providerContent,
172
+ toolCalls,
173
+ toolOutputs: [],
174
+ toolApprovalRequests: [],
175
+ toolApprovalResponses: [],
176
+ tools: opts.tools
177
+ });
178
+ const duration = raw.generation.responseTimeMs;
179
+ const rate = (tokens) => calculateTokensPerSecond({
180
+ tokens,
181
+ durationMs: duration
182
+ });
183
+ return new DefaultStepResult({
184
+ callId: "workflow-agent",
185
+ stepNumber: opts.stepNumber,
186
+ provider: raw.generation.provider,
187
+ modelId: raw.generation.modelId,
188
+ runtimeContext: opts.runtimeContext,
189
+ toolsContext: opts.toolsContext,
190
+ content,
191
+ finishReason: finish.finishReason,
192
+ rawFinishReason: finish.rawFinishReason,
193
+ usage: finish.usage,
194
+ warnings: raw.warnings,
195
+ request: {
196
+ ...raw.generation.request,
197
+ messages: opts.requestMessages
198
+ },
199
+ response: {
200
+ ...raw.responseMetadata,
201
+ messages: []
202
+ },
203
+ providerMetadata: finish.providerMetadata,
204
+ performance: {
205
+ responseTimeMs: duration,
206
+ stepTimeMs: duration,
207
+ toolExecutionMs: {},
208
+ effectiveOutputTokensPerSecond: rate(finish.usage.outputTokens),
209
+ effectiveTotalTokensPerSecond: rate(finish.usage.totalTokens),
210
+ outputTokensPerSecond: void 0,
211
+ inputTokensPerSecond: void 0,
212
+ timeToFirstOutputMs: void 0
213
+ }
214
+ });
215
+ }
216
+ const { content: rawContent, reasoning: reasoningParts, responseMetadata, warnings } = raw;
217
+ const reasoningText = reasoningParts.map((r) => r.text).join("") || void 0;
218
+ const validToolCallsByIndex = new Map(toolCalls.flatMap((tc, index) => tc.invalid ? [] : [[index, {
219
+ type: "tool-call",
220
+ toolCallId: tc.toolCallId,
221
+ toolName: tc.toolName,
222
+ input: tc.input,
223
+ ...tc.providerExecuted != null ? { providerExecuted: tc.providerExecuted } : {},
224
+ ...tc.title != null ? { title: tc.title } : {},
225
+ ...tc.toolMetadata != null ? { toolMetadata: tc.toolMetadata } : {},
226
+ ...tc.dynamic ? { dynamic: true } : {},
227
+ ...tc.providerExecuted ? { providerExecuted: true } : {},
228
+ ...tc.providerMetadata != null ? { providerMetadata: tc.providerMetadata } : {}
229
+ }]]));
230
+ const validToolCalls = [...validToolCallsByIndex.values()];
231
+ const content = [];
232
+ const files = [];
233
+ const sources = [];
234
+ let text = "";
235
+ for (const part of rawContent) switch (part.type) {
236
+ case "text":
237
+ text += part.text;
238
+ content.push({
239
+ type: "text",
240
+ text: part.text,
241
+ ...part.providerMetadata != null ? { providerMetadata: part.providerMetadata } : {}
242
+ });
243
+ break;
244
+ case "reasoning":
245
+ if ("reasoningIndex" in part) {
246
+ const reasoningPart = reasoningParts[part.reasoningIndex];
247
+ if (reasoningPart != null) content.push({
248
+ type: "reasoning",
249
+ text: reasoningPart.text,
250
+ ...reasoningPart.providerMetadata != null ? { providerMetadata: reasoningPart.providerMetadata } : {}
251
+ });
252
+ }
253
+ break;
254
+ case "file": {
255
+ const file = new DefaultGeneratedFile({
256
+ data: part.data,
257
+ mediaType: part.mediaType,
258
+ providerMetadata: part.providerMetadata
259
+ });
260
+ files.push(file);
261
+ content.push({
262
+ type: "file",
263
+ file,
264
+ ...part.providerMetadata != null ? { providerMetadata: part.providerMetadata } : {}
265
+ });
266
+ break;
267
+ }
268
+ case "source":
269
+ sources.push(part);
270
+ content.push(part);
271
+ break;
272
+ case "tool-approval-request": {
273
+ const toolCall = validToolCalls.find((call) => call.toolCallId === part.toolCallId);
274
+ if (toolCall != null) content.push({
275
+ type: "tool-approval-request",
276
+ approvalId: part.approvalId,
277
+ toolCall
278
+ });
279
+ break;
280
+ }
281
+ case "tool-call": {
282
+ const toolCall = validToolCallsByIndex.get(part.toolCallIndex);
283
+ if (toolCall != null) content.push(toolCall);
284
+ break;
285
+ }
286
+ case "provider-tool-result": {
287
+ const result = providerExecutedToolResults.get(part.toolCallId);
288
+ if (result == null) break;
289
+ const toolCall = toolCalls.find((toolCall) => toolCall.toolCallId === result.toolCallId);
290
+ const common = {
291
+ toolCallId: result.toolCallId,
292
+ toolName: result.toolName,
293
+ input: toolCall?.input,
294
+ providerExecuted: true,
295
+ ...result.dynamic === true || toolCall?.dynamic === true ? { dynamic: true } : {},
296
+ ...result.providerMetadata != null ? { providerMetadata: result.providerMetadata } : {},
297
+ ...toolCall?.toolMetadata != null ? { toolMetadata: toolCall.toolMetadata } : {}
298
+ };
299
+ content.push(result.isError ? {
300
+ type: "tool-error",
301
+ ...common,
302
+ error: result.result
303
+ } : {
304
+ type: "tool-result",
305
+ ...common,
306
+ output: result.result
307
+ });
308
+ break;
309
+ }
310
+ }
311
+ const toolResults = content.filter((part) => part.type === "tool-result");
312
+ return {
313
+ callId: "workflow-agent",
314
+ stepNumber: opts.stepNumber,
315
+ model: {
316
+ provider: responseMetadata?.modelId?.split(":")[0] ?? "unknown",
317
+ modelId: responseMetadata?.modelId ?? "unknown"
318
+ },
319
+ functionId: void 0,
320
+ metadata: void 0,
321
+ runtimeContext: opts.runtimeContext ?? {},
322
+ toolsContext: opts.toolsContext ?? {},
323
+ content,
324
+ text,
325
+ reasoning: reasoningParts.map((r) => ({
326
+ type: "reasoning",
327
+ text: r.text,
328
+ ...r.providerMetadata != null ? { providerMetadata: r.providerMetadata } : {}
329
+ })),
330
+ reasoningText,
331
+ files,
332
+ sources,
333
+ toolCalls: validToolCalls,
334
+ staticToolCalls: validToolCalls.filter((tc) => tc.dynamic !== true),
335
+ dynamicToolCalls: validToolCalls.filter((tc) => tc.dynamic),
336
+ toolResults,
337
+ staticToolResults: toolResults.filter((result) => result.dynamic !== true),
338
+ dynamicToolResults: toolResults.filter((result) => result.dynamic === true),
339
+ finishReason: finish?.finishReason ?? "other",
340
+ rawFinishReason: finish?.rawFinishReason,
341
+ usage: finish?.usage ?? {
342
+ inputTokens: 0,
343
+ inputTokenDetails: {
344
+ noCacheTokens: void 0,
345
+ cacheReadTokens: void 0,
346
+ cacheWriteTokens: void 0
347
+ },
348
+ outputTokens: 0,
349
+ outputTokenDetails: {
350
+ textTokens: void 0,
351
+ reasoningTokens: void 0
352
+ },
353
+ totalTokens: 0
354
+ },
355
+ performance: {
356
+ effectiveOutputTokensPerSecond: 0,
357
+ outputTokensPerSecond: void 0,
358
+ inputTokensPerSecond: void 0,
359
+ effectiveTotalTokensPerSecond: 0,
360
+ stepTimeMs: 0,
361
+ responseTimeMs: 0,
362
+ toolExecutionMs: {},
363
+ timeToFirstOutputMs: void 0
364
+ },
365
+ warnings,
366
+ request: {
367
+ body: "",
368
+ messages: []
369
+ },
370
+ response: {
371
+ id: responseMetadata?.id ?? "unknown",
372
+ timestamp: responseMetadata?.timestamp ?? /* @__PURE__ */ new Date(),
373
+ modelId: responseMetadata?.modelId ?? "unknown",
374
+ messages: []
375
+ },
376
+ providerMetadata: finish?.providerMetadata ?? {}
377
+ };
378
+ }
379
+ //#endregion
121
380
  //#region src/serializable-schema.ts
122
381
  /**
123
382
  * Converts a ToolSet (with Zod/standard schemas and execute functions) to a
@@ -233,6 +492,136 @@ function resolveSerializableTools(tools) {
233
492
  }));
234
493
  }
235
494
  //#endregion
495
+ //#region src/do-generate-step.ts
496
+ /** A single durable provider call; orchestration and callbacks stay in the workflow. */
497
+ async function doGenerateStep(prompt, modelInit, serializedTools, options = {}) {
498
+ "use step";
499
+ try {
500
+ return await generateModelCall(prompt, modelInit, serializedTools, options);
501
+ } catch (error) {
502
+ return {
503
+ toolCalls: [],
504
+ finish: void 0,
505
+ raw: {
506
+ content: [],
507
+ reasoning: []
508
+ },
509
+ providerExecutedToolResults: /* @__PURE__ */ new Map(),
510
+ terminalError: error
511
+ };
512
+ }
513
+ }
514
+ async function generateModelCall(prompt, modelInit, serializedTools, options) {
515
+ const remaining = options.timeoutAt == null ? void 0 : options.timeoutAt - Date.now();
516
+ options.abortSignal?.throwIfAborted();
517
+ if (remaining != null && remaining <= 0) throw new DOMException("The generation deadline expired.", "TimeoutError");
518
+ const abortSignal = remaining == null ? options.abortSignal : AbortSignal.any([...options.abortSignal == null ? [] : [options.abortSignal], AbortSignal.timeout(remaining)]);
519
+ const model = resolveLanguageModel(modelInit);
520
+ const tools = resolveSerializableTools(serializedTools);
521
+ const toolChoice = prepareToolChoice({ toolChoice: options.toolChoice });
522
+ const modelTools = await prepareTools({ tools });
523
+ const settings = prepareLanguageModelCallOptions(options);
524
+ const { retry } = prepareRetries({
525
+ maxRetries: options.maxRetries,
526
+ abortSignal
527
+ });
528
+ const start = Date.now();
529
+ const response = await retry(async () => {
530
+ abortSignal?.throwIfAborted();
531
+ if (options.timeoutAt != null && options.timeoutAt <= Date.now()) throw new DOMException("The generation deadline expired.", "TimeoutError");
532
+ return model.doGenerate({
533
+ ...settings,
534
+ prompt: [...prompt],
535
+ tools: modelTools,
536
+ toolChoice,
537
+ responseFormat: options.responseFormat,
538
+ providerOptions: options.providerOptions,
539
+ headers: options.headers,
540
+ abortSignal
541
+ });
542
+ });
543
+ abortSignal?.throwIfAborted();
544
+ const responseTimeMs = Date.now() - start;
545
+ const toolCalls = await Promise.all(response.content.filter((part) => part.type === "tool-call").map((toolCall) => parseToolCall({
546
+ toolCall,
547
+ tools,
548
+ repairToolCall: options.repairToolCall,
549
+ instructions: prompt.filter((message) => message.role === "system").map((message) => message.content).join("\n") || void 0,
550
+ messages: prompt.filter((message) => message.role !== "system")
551
+ })));
552
+ if ((toolChoice.type === "required" || toolChoice.type === "tool") && !toolCalls.some((call) => toolChoice.type === "required" || call.toolName === toolChoice.toolName)) throw new ToolChoiceViolationError({
553
+ toolChoice,
554
+ finishReason: response.finishReason.unified,
555
+ provider: model.provider,
556
+ modelId: model.modelId,
557
+ content: response.content
558
+ });
559
+ const providerExecutedToolResults = /* @__PURE__ */ new Map();
560
+ const content = response.content.map((part) => {
561
+ switch (part.type) {
562
+ case "tool-call": return {
563
+ type: "tool-call",
564
+ toolCallIndex: toolCalls.findIndex((call) => call.toolCallId === part.toolCallId)
565
+ };
566
+ case "tool-result":
567
+ providerExecutedToolResults.set(part.toolCallId, part);
568
+ return {
569
+ type: "provider-tool-result",
570
+ toolCallId: part.toolCallId
571
+ };
572
+ case "file": return {
573
+ type: "file",
574
+ data: part.data.type === "data" ? typeof part.data.data === "string" ? part.data.data : convertUint8ArrayToBase64(part.data.data) : part.data.url.toString(),
575
+ mediaType: part.mediaType,
576
+ providerMetadata: part.providerMetadata
577
+ };
578
+ default: return part;
579
+ }
580
+ });
581
+ const toolInputLifecycleEvents = toolCalls.flatMap((call) => {
582
+ const tool = serializedTools[call.toolName];
583
+ if (call.invalid || tool == null) return [];
584
+ const events = [];
585
+ if (tool.hasOnInputStart || tool.hasOnInputAvailable) events.push([
586
+ "start",
587
+ call.toolCallId,
588
+ call.toolName
589
+ ]);
590
+ if (tool.hasOnInputAvailable) events.push(["available", call.toolCallId]);
591
+ return events;
592
+ });
593
+ return {
594
+ toolCalls,
595
+ finish: {
596
+ finishReason: response.finishReason.unified,
597
+ rawFinishReason: response.finishReason.raw,
598
+ usage: asLanguageModelUsage(response.usage),
599
+ providerMetadata: response.providerMetadata
600
+ },
601
+ raw: {
602
+ content,
603
+ reasoning: [],
604
+ warnings: response.warnings,
605
+ responseMetadata: {
606
+ id: response.response?.id ?? generateId(),
607
+ timestamp: response.response?.timestamp ?? /* @__PURE__ */ new Date(),
608
+ modelId: response.response?.modelId ?? model.modelId,
609
+ headers: response.response?.headers,
610
+ ...options.include?.responseBody ? { body: response.response?.body } : {}
611
+ },
612
+ generation: {
613
+ provider: model.provider,
614
+ modelId: model.modelId,
615
+ responseTimeMs,
616
+ request: options.include?.requestBody ? response.request : void 0
617
+ }
618
+ },
619
+ providerExecutedToolResults,
620
+ toolInputLifecycleEvents
621
+ };
622
+ }
623
+ doGenerateStep.maxRetries = 0;
624
+ //#endregion
236
625
  //#region src/do-stream-step.ts
237
626
  async function doStreamStep(conversationPrompt, modelInit, writable, serializedTools, options) {
238
627
  "use step";
@@ -276,7 +665,13 @@ async function doStreamStep(conversationPrompt, modelInit, writable, serializedT
276
665
  try {
277
666
  const { stream } = await retry(() => experimental_streamLanguageModelCall({
278
667
  model: modelWithTransforms,
279
- messages: conversationPrompt,
668
+ messages: conversationPrompt.map((message) => message.role !== "tool" ? message : {
669
+ ...message,
670
+ content: message.content.map((part) => part.type === "tool-approval-response" ? {
671
+ ...part,
672
+ providerExecuted: true
673
+ } : part)
674
+ }),
280
675
  allowSystemInMessages: true,
281
676
  tools,
282
677
  toolChoice: options?.toolChoice,
@@ -403,6 +798,13 @@ async function doStreamStep(conversationPrompt, modelInit, writable, serializedT
403
798
  case "source":
404
799
  content.push(part);
405
800
  break;
801
+ case "tool-approval-request":
802
+ content.push({
803
+ type: "tool-approval-request",
804
+ approvalId: part.approvalId,
805
+ toolCallId: part.toolCall.toolCallId
806
+ });
807
+ break;
406
808
  case "tool-call": {
407
809
  const toolCallPart = part;
408
810
  const toolCallIndex = toolCalls.length;
@@ -576,7 +978,7 @@ function upsertReasoningContentPart({ content, reasoningParts, reasoningPartInde
576
978
  if (providerMetadata != null) part.providerMetadata = providerMetadata;
577
979
  }
578
980
  //#endregion
579
- //#region src/stream-text-iterator.ts
981
+ //#region src/model-call-iterator.ts
580
982
  const prepareStepGenerationSettingKeys = [
581
983
  "maxOutputTokens",
582
984
  "temperature",
@@ -599,7 +1001,7 @@ function mergePrepareStepGenerationSettings(current, overrides) {
599
1001
  ...definedOverrides
600
1002
  };
601
1003
  }
602
- async function* streamTextIterator({ prompt, initialInstructions, initialMessages = prompt, tools = {}, writable, model, stopConditions, onStepEnd, onStepFinish, onStepStart, onError, prepareStep, generationSettings, toolChoice, runtimeContext, toolsContext, telemetry, includeRawChunks = false, timeoutAt, repairToolCall, responseFormat, experimental_transform, experimental_sandbox: sandbox }) {
1004
+ async function* modelCallIterator({ prompt, mode = "stream", include, initialInstructions, initialMessages = prompt, tools = {}, writable, model, stopConditions, onStepEnd, onStepFinish, onStepStart, onError, prepareStep, generationSettings, toolChoice, runtimeContext, toolsContext, telemetry, includeRawChunks = false, timeoutAt, repairToolCall, responseFormat, experimental_transform, experimental_sandbox: sandbox }) {
603
1005
  let conversationPrompt = [...prompt];
604
1006
  let currentModel = model;
605
1007
  let currentGenerationSettings = generationSettings ?? {};
@@ -626,7 +1028,10 @@ async function* streamTextIterator({ prompt, initialInstructions, initialMessage
626
1028
  includeToolsContext: telemetry?.includeToolsContext
627
1029
  });
628
1030
  while (!done) {
629
- if (currentGenerationSettings.abortSignal?.aborted) break;
1031
+ if (currentGenerationSettings.abortSignal?.aborted) {
1032
+ if (mode === "generate") currentGenerationSettings.abortSignal.throwIfAborted();
1033
+ break;
1034
+ }
630
1035
  let stepSandbox = sandbox;
631
1036
  if (prepareStep) {
632
1037
  const prepareResult = await prepareStep({
@@ -716,25 +1121,28 @@ async function* streamTextIterator({ prompt, initialInstructions, initialMessage
716
1121
  providerOptions: currentGenerationSettings.providerOptions,
717
1122
  headers: currentGenerationSettings.headers
718
1123
  });
719
- const stepInputMessages = conversationPrompt;
720
- const streamStepResult = await doStreamStep(conversationPrompt, currentModel, writable, serializedTools, {
1124
+ const stepInputMessages = mode === "generate" ? [...conversationPrompt] : conversationPrompt;
1125
+ const callOptions = {
721
1126
  ...currentGenerationSettings,
722
1127
  toolChoice: currentToolChoice,
723
1128
  includeRawChunks,
724
1129
  timeoutAt,
725
1130
  repairToolCall,
726
1131
  responseFormat,
1132
+ include,
727
1133
  experimental_transform
728
- });
729
- if (streamStepResult.aborted) {
1134
+ };
1135
+ const modelCallResult = mode === "generate" ? await doGenerateStep(conversationPrompt, currentModel, serializedTools, callOptions) : await doStreamStep(conversationPrompt, currentModel, writable, serializedTools, callOptions);
1136
+ if (modelCallResult.aborted) {
730
1137
  wasAborted = true;
731
1138
  break;
732
1139
  }
733
- if ("terminalError" in streamStepResult) {
734
- terminalError = streamStepResult.terminalError;
1140
+ if ("terminalError" in modelCallResult) {
1141
+ if (mode === "generate") throw modelCallResult.terminalError;
1142
+ terminalError = modelCallResult.terminalError;
735
1143
  hasTerminalError = true;
736
1144
  }
737
- const { toolCalls, finish, raw, providerExecutedToolResults, toolInputLifecycleEvents } = streamStepResult;
1145
+ const { toolCalls, finish, raw, providerExecutedToolResults, toolInputLifecycleEvents } = modelCallResult;
738
1146
  await invokeToolInputLifecycleCallbacks({
739
1147
  events: toolInputLifecycleEvents ?? [],
740
1148
  toolCalls,
@@ -744,7 +1152,9 @@ async function* streamTextIterator({ prompt, initialInstructions, initialMessage
744
1152
  toolsContext: currentToolsContext,
745
1153
  experimental_sandbox: stepSandbox
746
1154
  });
747
- const step = buildStepResult(raw, toolCalls, finish, providerExecutedToolResults, {
1155
+ const step = await buildModelStepResult(raw, toolCalls, finish, providerExecutedToolResults, {
1156
+ tools: effectiveTools,
1157
+ requestMessages: mode === "generate" && include?.requestMessages ? stepInputMessages : void 0,
748
1158
  stepNumber,
749
1159
  runtimeContext: currentRuntimeContext,
750
1160
  toolsContext: currentToolsContext
@@ -771,7 +1181,7 @@ async function* streamTextIterator({ prompt, initialInstructions, initialMessage
771
1181
  if (hasTerminalError) done = true;
772
1182
  else if (shouldProcessTools) {
773
1183
  lastStepWasYielded = true;
774
- const { content: assistantContent, providerExecutedToolResultPositions } = getAssistantMessageContent(step);
1184
+ const { content: assistantContent, providerExecutedToolResultPositions } = getAssistantMessageContent(step, mode);
775
1185
  const includedToolCallIds = new Set(assistantContent.flatMap((part) => part.type === "tool-call" ? [part.toolCallId] : []));
776
1186
  conversationPrompt.push({
777
1187
  role: "assistant",
@@ -794,23 +1204,22 @@ async function* streamTextIterator({ prompt, initialInstructions, initialMessage
794
1204
  providerExecutedToolCallIds: /* @__PURE__ */ new Set([...toolCalls.flatMap((toolCall) => toolCall.providerExecuted ? [toolCall.toolCallId] : []), ...providerExecutedToolResults.keys()]),
795
1205
  providerExecutedToolResultPositions
796
1206
  });
797
- step.response.messages.push(...responseMessages);
1207
+ step.response.messages.push(...mode === "generate" ? toModelResponseMessages(responseMessages) : responseMessages);
798
1208
  const stopConditionMet = (stopConditions == null ? [] : Array.isArray(stopConditions) ? stopConditions : [stopConditions]).some((test) => test({ steps }));
799
1209
  const hasClientToolCalls = toolCalls.some((toolCall) => !toolCall.providerExecuted);
800
1210
  done = stopConditionMet || !hasClientToolCalls && pendingDeferredToolCallIds.size === 0;
801
- } else if (finishReason === "stop" || finishReason === "tool-calls") {
802
- const { content: assistantContent } = getAssistantMessageContent(step);
1211
+ } else if (mode === "generate" || finishReason === "stop" || finishReason === "tool-calls" || finishReason === "length") {
1212
+ const { content: assistantContent } = getAssistantMessageContent(step, mode);
803
1213
  if (assistantContent.length > 0) {
804
1214
  const assistantMessage = {
805
1215
  role: "assistant",
806
1216
  content: assistantContent
807
1217
  };
808
1218
  conversationPrompt.push(assistantMessage);
809
- step.response.messages.push(assistantMessage);
1219
+ step.response.messages.push(...mode === "generate" ? toModelResponseMessages([assistantMessage]) : [assistantMessage]);
810
1220
  }
811
1221
  done = true;
812
- } else if (finishReason === "length") done = true;
813
- else if (finishReason === "content-filter") done = true;
1222
+ } else if (finishReason === "content-filter") done = true;
814
1223
  else if (finishReason === "error") done = true;
815
1224
  else if (finishReason === "other") done = true;
816
1225
  else if (finishReason === "unknown") done = true;
@@ -909,193 +1318,45 @@ function normalizeStepForTelemetry$1(step) {
909
1318
  }
910
1319
  };
911
1320
  }
912
- /**
913
- * Reconstruct a full `StepResult` from the minimal aggregates returned by
914
- * `doStreamStep`. Runs outside the step boundary so StepResult's redundant
915
- * fields (duplicate tool-call lists, `text`, `files`, `sources`, and
916
- * `reasoningText`) and the per-chunk snapshot don't cross it. Tool-result
917
- * arrays are initialized here and populated after execution. The shape matches
918
- * what the AI SDK's `streamText` exposes to callers.
919
- */
920
- function buildStepResult(raw, toolCalls, finish, providerExecutedToolResults, opts) {
921
- const { content: rawContent, reasoning: reasoningParts, responseMetadata, warnings } = raw;
922
- const reasoningText = reasoningParts.map((r) => r.text).join("") || void 0;
923
- const validToolCallsByIndex = new Map(toolCalls.flatMap((tc, index) => tc.invalid ? [] : [[index, {
924
- type: "tool-call",
925
- toolCallId: tc.toolCallId,
926
- toolName: tc.toolName,
927
- input: tc.input,
928
- ...tc.providerExecuted != null ? { providerExecuted: tc.providerExecuted } : {},
929
- ...tc.title != null ? { title: tc.title } : {},
930
- ...tc.toolMetadata != null ? { toolMetadata: tc.toolMetadata } : {},
931
- ...tc.dynamic ? { dynamic: true } : {},
932
- ...tc.providerExecuted ? { providerExecuted: true } : {},
933
- ...tc.providerMetadata != null ? { providerMetadata: tc.providerMetadata } : {}
934
- }]]));
935
- const validToolCalls = [...validToolCallsByIndex.values()];
936
- const content = [];
937
- const files = [];
938
- const sources = [];
939
- let text = "";
940
- for (const part of rawContent) switch (part.type) {
941
- case "text":
942
- text += part.text;
943
- content.push({
944
- type: "text",
945
- text: part.text,
946
- ...part.providerMetadata != null ? { providerMetadata: part.providerMetadata } : {}
947
- });
948
- break;
949
- case "reasoning": {
950
- const reasoningPart = reasoningParts[part.reasoningIndex];
951
- if (reasoningPart != null) content.push({
952
- type: "reasoning",
953
- text: reasoningPart.text,
954
- ...reasoningPart.providerMetadata != null ? { providerMetadata: reasoningPart.providerMetadata } : {}
955
- });
956
- break;
957
- }
958
- case "file": {
959
- const file = new DefaultGeneratedFile({
960
- data: part.data,
961
- mediaType: part.mediaType,
962
- providerMetadata: part.providerMetadata
963
- });
964
- files.push(file);
965
- content.push({
966
- type: "file",
967
- file,
968
- ...part.providerMetadata != null ? { providerMetadata: part.providerMetadata } : {}
969
- });
970
- break;
971
- }
972
- case "source":
973
- sources.push(part);
974
- content.push(part);
975
- break;
976
- case "tool-call": {
977
- const toolCall = validToolCallsByIndex.get(part.toolCallIndex);
978
- if (toolCall != null) content.push(toolCall);
979
- break;
980
- }
981
- case "provider-tool-result": {
982
- const result = providerExecutedToolResults.get(part.toolCallId);
983
- if (result == null) break;
984
- const toolCall = toolCalls.find((toolCall) => toolCall.toolCallId === result.toolCallId);
985
- const common = {
986
- toolCallId: result.toolCallId,
987
- toolName: result.toolName,
988
- input: toolCall?.input,
989
- providerExecuted: true,
990
- ...result.dynamic === true || toolCall?.dynamic === true ? { dynamic: true } : {},
991
- ...result.providerMetadata != null ? { providerMetadata: result.providerMetadata } : {},
992
- ...toolCall?.toolMetadata != null ? { toolMetadata: toolCall.toolMetadata } : {}
993
- };
994
- content.push(result.isError ? {
995
- type: "tool-error",
996
- ...common,
997
- error: result.result
998
- } : {
999
- type: "tool-result",
1000
- ...common,
1001
- output: result.result
1002
- });
1003
- break;
1004
- }
1005
- }
1006
- const toolResults = content.filter((part) => part.type === "tool-result");
1007
- return {
1008
- callId: "workflow-agent",
1009
- stepNumber: opts.stepNumber,
1010
- model: {
1011
- provider: responseMetadata?.modelId?.split(":")[0] ?? "unknown",
1012
- modelId: responseMetadata?.modelId ?? "unknown"
1013
- },
1014
- functionId: void 0,
1015
- metadata: void 0,
1016
- runtimeContext: opts.runtimeContext ?? {},
1017
- toolsContext: opts.toolsContext ?? {},
1018
- content,
1019
- text,
1020
- reasoning: reasoningParts.map((r) => ({
1021
- type: "reasoning",
1022
- text: r.text,
1023
- ...r.providerMetadata != null ? { providerMetadata: r.providerMetadata } : {}
1024
- })),
1025
- reasoningText,
1026
- files,
1027
- sources,
1028
- toolCalls: validToolCalls,
1029
- staticToolCalls: validToolCalls.filter((tc) => tc.dynamic !== true),
1030
- dynamicToolCalls: validToolCalls.filter((tc) => tc.dynamic),
1031
- toolResults,
1032
- staticToolResults: toolResults.filter((result) => result.dynamic !== true),
1033
- dynamicToolResults: toolResults.filter((result) => result.dynamic === true),
1034
- finishReason: finish?.finishReason ?? "other",
1035
- rawFinishReason: finish?.rawFinishReason,
1036
- usage: finish?.usage ?? {
1037
- inputTokens: 0,
1038
- inputTokenDetails: {
1039
- noCacheTokens: void 0,
1040
- cacheReadTokens: void 0,
1041
- cacheWriteTokens: void 0
1042
- },
1043
- outputTokens: 0,
1044
- outputTokenDetails: {
1045
- textTokens: void 0,
1046
- reasoningTokens: void 0
1047
- },
1048
- totalTokens: 0
1049
- },
1050
- performance: {
1051
- effectiveOutputTokensPerSecond: 0,
1052
- outputTokensPerSecond: void 0,
1053
- inputTokensPerSecond: void 0,
1054
- effectiveTotalTokensPerSecond: 0,
1055
- stepTimeMs: 0,
1056
- responseTimeMs: 0,
1057
- toolExecutionMs: {},
1058
- timeToFirstOutputMs: void 0
1059
- },
1060
- warnings,
1061
- request: {
1062
- body: "",
1063
- messages: []
1064
- },
1065
- response: {
1066
- id: responseMetadata?.id ?? "unknown",
1067
- timestamp: responseMetadata?.timestamp ?? /* @__PURE__ */ new Date(),
1068
- modelId: responseMetadata?.modelId ?? "unknown",
1069
- messages: []
1070
- },
1071
- providerMetadata: finish?.providerMetadata ?? {}
1072
- };
1073
- }
1074
- function getAssistantMessageContent(step) {
1321
+ /** Preserve assistant ordering and positions for provider-executed results. */
1322
+ function getAssistantMessageContent(step, mode) {
1075
1323
  const content = [];
1076
1324
  const providerExecutedToolResultPositions = [];
1077
1325
  let contentIndex = 0;
1078
1326
  for (const part of step.content) switch (part.type) {
1079
- case "reasoning":
1327
+ case "text":
1328
+ if (part.text.length > 0) {
1329
+ content.push({
1330
+ type: "text",
1331
+ text: part.text,
1332
+ ...part.providerMetadata != null ? { providerOptions: part.providerMetadata } : {}
1333
+ });
1334
+ contentIndex++;
1335
+ }
1336
+ break;
1337
+ case "reasoning": {
1338
+ const { providerMetadata, ...messagePart } = part;
1080
1339
  content.push({
1081
- type: "reasoning",
1082
- text: part.text,
1083
- ...part.providerMetadata != null ? { providerOptions: part.providerMetadata } : {}
1340
+ ...messagePart,
1341
+ ...providerMetadata != null ? { providerOptions: providerMetadata } : {}
1084
1342
  });
1085
1343
  contentIndex++;
1086
1344
  break;
1087
- case "text":
1088
- if (part.text.length > 0) {
1345
+ }
1346
+ case "custom":
1347
+ if (mode === "generate") {
1348
+ const { providerMetadata, ...messagePart } = part;
1089
1349
  content.push({
1090
- type: "text",
1091
- text: part.text
1350
+ ...messagePart,
1351
+ providerOptions: providerMetadata
1092
1352
  });
1093
1353
  contentIndex++;
1094
1354
  }
1095
1355
  break;
1356
+ case "reasoning-file": if (mode !== "generate") break;
1096
1357
  case "file":
1097
1358
  content.push({
1098
- type: "file",
1359
+ type: part.type,
1099
1360
  data: {
1100
1361
  type: "data",
1101
1362
  data: part.file.base64
@@ -1134,8 +1395,21 @@ function toAssistantToolCallContent(toolCall) {
1134
1395
  };
1135
1396
  }
1136
1397
  //#endregion
1398
+ //#region src/workflow-execution-result.ts
1399
+ function resolveWorkflowStreamResult({ data, outcome }) {
1400
+ if (outcome.status === "failed") {
1401
+ if (outcome.source === "execution") throw outcome.error;
1402
+ return {
1403
+ ...data,
1404
+ error: outcome.error
1405
+ };
1406
+ }
1407
+ if (outcome.status === "aborted" && outcome.rejection != null) throw outcome.rejection.value;
1408
+ return data;
1409
+ }
1410
+ //#endregion
1137
1411
  //#region src/workflow-agent.ts
1138
- function addToolResultsToStep(step, executedResults) {
1412
+ function addToolResultsToStep(step, executedResults, mode = "stream") {
1139
1413
  if (step == null || executedResults.length === 0) return;
1140
1414
  const existingProviderResultIds = new Set(step.content.flatMap((part) => (part.type === "tool-result" || part.type === "tool-error") && part.providerExecuted ? [part.toolCallId] : []));
1141
1415
  const toolOutputs = executedResults.flatMap((result) => {
@@ -1145,6 +1419,10 @@ function addToolResultsToStep(step, executedResults) {
1145
1419
  toolCallId: result.modelResult.toolCallId,
1146
1420
  toolName: result.modelResult.toolName,
1147
1421
  input: toolCall?.input,
1422
+ ...mode === "generate" ? {
1423
+ dynamic: toolCall?.dynamic === true,
1424
+ ...toolCall?.toolMetadata != null ? { toolMetadata: toolCall.toolMetadata } : {}
1425
+ } : {},
1148
1426
  ...toolCall?.dynamic === true ? { dynamic: true } : {},
1149
1427
  ...toolCall?.providerExecuted === true ? { providerExecuted: true } : {}
1150
1428
  };
@@ -1159,6 +1437,7 @@ function addToolResultsToStep(step, executedResults) {
1159
1437
  }];
1160
1438
  });
1161
1439
  step.content.push(...toolOutputs);
1440
+ if (mode === "generate") return;
1162
1441
  const toolResults = toolOutputs.filter((result) => result.type === "tool-result");
1163
1442
  step.toolResults.push(...toolResults);
1164
1443
  step.staticToolResults.push(...toolResults.filter((result) => result.dynamic !== true));
@@ -1234,10 +1513,34 @@ var WorkflowAgent = class {
1234
1513
  providerOptions: options.providerOptions
1235
1514
  };
1236
1515
  }
1237
- generate() {
1238
- throw new Error("Not implemented");
1516
+ async generate(options) {
1517
+ const { data, outcome, abortReason, initialResponseMessages = [] } = await this.execute(options, "generate");
1518
+ if (outcome.status === "failed") throw outcome.error;
1519
+ if (outcome.status === "aborted") {
1520
+ if (outcome.rejection != null) throw outcome.rejection.value;
1521
+ if (abortReason != null) throw abortReason.value;
1522
+ options.abortSignal?.throwIfAborted();
1523
+ throw new DOMException("Generation aborted.", "AbortError");
1524
+ }
1525
+ const lastStep = data.steps.at(-1);
1526
+ if (lastStep == null) throw new NoOutputGeneratedError();
1527
+ let output;
1528
+ if (lastStep.finishReason === "stop" || lastStep.finishReason !== "tool-calls" && lastStep.text.length > 0) output = await (options.output ?? this.output ?? Output.text()).parseCompleteOutput({ text: lastStep.text }, {
1529
+ response: lastStep.response,
1530
+ usage: lastStep.usage,
1531
+ finishReason: lastStep.finishReason
1532
+ });
1533
+ return new DefaultGenerateTextResult({
1534
+ initialResponseMessages,
1535
+ steps: data.steps,
1536
+ totalUsage: data.totalUsage,
1537
+ output
1538
+ });
1239
1539
  }
1240
1540
  async stream(options) {
1541
+ return resolveWorkflowStreamResult(await this.execute(options));
1542
+ }
1543
+ async prepareInvocation(options, mode = "stream") {
1241
1544
  const { onFinish, onEnd = onFinish } = options;
1242
1545
  let effectiveModel = this.model;
1243
1546
  let effectiveInstructions = options.instructions ?? options.system ?? this.instructions;
@@ -1247,7 +1550,7 @@ var WorkflowAgent = class {
1247
1550
  let effectiveRuntimeContext = options.runtimeContext ?? this.runtimeContext ?? {};
1248
1551
  let effectiveToolsContext = options.toolsContext ?? this.toolsContext ?? {};
1249
1552
  let effectiveToolChoiceFromPrepare = options.toolChoice ?? this.toolChoice;
1250
- let effectiveStopWhenFromPrepare = options.stopWhen ?? this.stopWhen;
1553
+ let effectiveStopWhenFromPrepare = options.stopWhen ?? this.stopWhen ?? (mode === "generate" ? isStepCount(20) : void 0);
1251
1554
  let effectiveActiveToolsFromPrepare = options.activeTools ?? this.activeTools;
1252
1555
  let effectiveDownloadFromPrepare = options.experimental_download ?? this.experimentalDownload;
1253
1556
  const effectiveToolApprovalSecret = options.experimental_toolApprovalSecret ?? this.experimentalToolApprovalSecret;
@@ -1316,6 +1619,32 @@ var WorkflowAgent = class {
1316
1619
  const timeoutAt = options.timeout == null ? void 0 : Date.now() + options.timeout;
1317
1620
  const mergedOnToolExecutionStart = mergeCallbacks(this.constructorOnToolExecutionStart, options.onToolExecutionStart);
1318
1621
  const mergedOnToolExecutionEnd = mergeCallbacks(this.constructorOnToolExecutionEnd, options.onToolExecutionEnd);
1622
+ return {
1623
+ onEnd,
1624
+ effectiveModel,
1625
+ effectiveInstructions,
1626
+ effectiveGenerationSettings,
1627
+ effectiveRuntimeContext,
1628
+ effectiveToolsContext,
1629
+ effectiveToolChoiceFromPrepare,
1630
+ effectiveStopWhenFromPrepare,
1631
+ effectiveActiveToolsFromPrepare,
1632
+ effectiveToolApprovalSecret,
1633
+ effectiveTelemetry,
1634
+ telemetryDispatcher,
1635
+ prompt,
1636
+ download,
1637
+ sandbox,
1638
+ effectiveAbortSignal,
1639
+ timeoutAt,
1640
+ mergedOnToolExecutionStart,
1641
+ mergedOnToolExecutionEnd
1642
+ };
1643
+ }
1644
+ async execute(options, mode = "stream") {
1645
+ const { onEnd, effectiveModel, effectiveInstructions, effectiveGenerationSettings, effectiveRuntimeContext, effectiveToolsContext, effectiveToolChoiceFromPrepare, effectiveStopWhenFromPrepare, effectiveActiveToolsFromPrepare, effectiveToolApprovalSecret, effectiveTelemetry, telemetryDispatcher, prompt, download, sandbox, effectiveAbortSignal, timeoutAt, mergedOnToolExecutionStart, mergedOnToolExecutionEnd } = await this.prepareInvocation(options, mode);
1646
+ const initialResponseMessages = [];
1647
+ const abortReason = () => effectiveAbortSignal?.reason === void 0 ? void 0 : { value: effectiveAbortSignal.reason };
1319
1648
  const collectedApprovals = collectToolApprovals({ messages: prompt.messages });
1320
1649
  const approvedToolApprovals = collectedApprovals.approvedToolApprovals.map((collected) => ({
1321
1650
  toolCallId: collected.toolCall.toolCallId,
@@ -1447,6 +1776,10 @@ var WorkflowAgent = class {
1447
1776
  content: filtered
1448
1777
  });
1449
1778
  } else cleanedMessages.push(msg);
1779
+ if (mode === "generate" && toolResultContent.length > 0) initialResponseMessages.push({
1780
+ role: "tool",
1781
+ content: toolResultContent
1782
+ });
1450
1783
  if (toolResultContent.length > 0) cleanedMessages.push({
1451
1784
  role: "tool",
1452
1785
  content: toolResultContent
@@ -1658,16 +1991,22 @@ var WorkflowAgent = class {
1658
1991
  if (mergedGenerationSettings.abortSignal?.aborted) {
1659
1992
  if (options.onAbort) await options.onAbort({ steps });
1660
1993
  return {
1661
- messages: prompt.messages,
1662
- steps,
1663
- toolCalls: [],
1664
- toolResults: [],
1665
- finishReason: "other",
1666
- totalUsage: aggregateUsage(steps),
1667
- output: void 0
1994
+ outcome: { status: "aborted" },
1995
+ abortReason: abortReason(),
1996
+ data: {
1997
+ messages: prompt.messages,
1998
+ steps,
1999
+ toolCalls: [],
2000
+ toolResults: [],
2001
+ finishReason: "other",
2002
+ totalUsage: aggregateExecutionUsage(steps, mode),
2003
+ output: void 0
2004
+ }
1668
2005
  };
1669
2006
  }
1670
- const iterator = streamTextIterator({
2007
+ const iterator = modelCallIterator({
2008
+ mode,
2009
+ include: options.include,
1671
2010
  model: effectiveModel,
1672
2011
  tools: effectiveTools,
1673
2012
  writable: options.writable,
@@ -1705,6 +2044,16 @@ var WorkflowAgent = class {
1705
2044
  break;
1706
2045
  }
1707
2046
  const { toolCalls, tools: stepTools = effectiveTools, messages: iterMessages, step, runtimeContext: yieldedRuntimeContext, toolsContext: yieldedToolsContext, experimental_sandbox: stepSandbox, providerExecutedToolResults, providerExecutedToolResultPositions } = result.value;
2047
+ if (mode === "generate" && step != null) {
2048
+ for (const call of toolCalls) if (call.invalid && !call.providerExecuted) step.content.push({
2049
+ type: "tool-error",
2050
+ toolCallId: call.toolCallId,
2051
+ toolName: call.toolName,
2052
+ input: call.input,
2053
+ error: call.error,
2054
+ dynamic: true
2055
+ });
2056
+ }
1708
2057
  const capturedProviderToolResults = providerExecutedToolResults ?? /* @__PURE__ */ new Map();
1709
2058
  const toolExecutionSandbox = stepSandbox ?? sandbox;
1710
2059
  const currentStepNumber = steps.length;
@@ -1748,9 +2097,10 @@ var WorkflowAgent = class {
1748
2097
  const tool = stepTools[tc.toolName];
1749
2098
  return tool && typeof tool.execute !== "function" || approvalNeeded[i];
1750
2099
  });
1751
- if (pausedToolCalls.length > 0) {
2100
+ const providerApprovalRequests = step?.content.filter((part) => part.type === "tool-approval-request").filter((part) => part.toolCall.providerExecuted) ?? [];
2101
+ if (pausedToolCalls.length > 0 || providerApprovalRequests.length > 0) {
1752
2102
  const executableResults = await Promise.all(executableToolCalls.map((toolCall) => executeToolWithCallbacks(toolCall, stepTools, iterMessages, toolsContext, currentStepNumber, toolExecutionSandbox)));
1753
- const providerResultEntries = await Promise.all(providerToolCallsForResults.map(async (toolCall) => ({
2103
+ const providerResultEntries = await Promise.all(providerToolCallsForResults.filter((call) => !providerApprovalRequests.some((request) => request.toolCall.toolCallId === call.toolCallId)).map(async (toolCall) => ({
1754
2104
  toolCall,
1755
2105
  result: await resolveProviderToolResult(toolCall, capturedProviderToolResults, stepTools, download)
1756
2106
  })));
@@ -1776,39 +2126,60 @@ var WorkflowAgent = class {
1776
2126
  input: toolCalls.find((tc) => tc.toolCallId === r.modelResult.toolCallId)?.input,
1777
2127
  output: r.rawOutput
1778
2128
  }));
1779
- addToolResultsToStep(step, executedResults);
2129
+ addToolResultsToStep(step, executedResults, mode);
2130
+ const approvalToolCalls = pausedToolCalls.filter((tc) => approvalNeeded[nonProviderToolCalls.indexOf(tc)]);
2131
+ const approvalRequests = await Promise.all(approvalToolCalls.map(async (tc) => {
2132
+ const approvalId = `approval-${tc.toolCallId}`;
2133
+ const signature = effectiveToolApprovalSecret == null ? void 0 : await signWorkflowToolApproval({
2134
+ secret: effectiveToolApprovalSecret,
2135
+ approvalId,
2136
+ toolCallId: tc.toolCallId,
2137
+ toolName: tc.toolName,
2138
+ input: tc.input
2139
+ });
2140
+ return {
2141
+ type: "tool-approval-request",
2142
+ approvalId,
2143
+ toolCall: {
2144
+ ...tc,
2145
+ type: "tool-call"
2146
+ },
2147
+ ...signature != null ? { signature } : {}
2148
+ };
2149
+ }));
2150
+ step?.content.push(...approvalRequests);
2151
+ const approvalMessages = approvalRequests.map(({ toolCall, ...request }) => ({
2152
+ ...request,
2153
+ toolCallId: toolCall.toolCallId
2154
+ }));
1780
2155
  const responseMessages = addToolResultsToConversation({
1781
2156
  messages: iterMessages,
1782
2157
  toolResults: resolvedResults,
1783
2158
  providerExecutedToolCallIds: new Set(providerToolCallsForResults.map((toolCall) => toolCall.toolCallId)),
1784
2159
  providerExecutedToolResultPositions
1785
2160
  });
1786
- step?.response.messages.push(...responseMessages);
1787
- const messages = iterMessages;
2161
+ const publicResponseMessages = addApprovalRequestsToMessages(mode === "generate" ? toModelResponseMessages(responseMessages) : responseMessages, [...approvalMessages, ...providerApprovalRequests.map(({ toolCall, ...request }) => ({
2162
+ ...request,
2163
+ toolCallId: toolCall.toolCallId
2164
+ }))]);
2165
+ step?.response.messages.push(...publicResponseMessages);
2166
+ const messages = publicResponseMessages === responseMessages ? iterMessages : [...iterMessages.slice(0, iterMessages.length - responseMessages.length), ...publicResponseMessages];
1788
2167
  const lastStep = steps[steps.length - 1];
1789
- const totalUsage = aggregateUsage(steps);
1790
- const finishReason = lastStep?.finishReason ?? "other";
1791
- if (mergedOnEnd && !wasAborted) await mergedOnEnd({
1792
- steps,
2168
+ const totalUsage = aggregateExecutionUsage(steps, mode);
2169
+ const data = {
1793
2170
  messages,
1794
- text: lastStep?.text ?? "",
1795
- finishReason,
1796
- usage: totalUsage,
2171
+ steps,
2172
+ toolCalls: allToolCalls,
2173
+ toolResults: allToolResults,
2174
+ finishReason: lastStep?.finishReason ?? "other",
1797
2175
  totalUsage,
1798
- runtimeContext,
1799
- toolsContext,
1800
2176
  output: void 0
1801
- });
1802
- if (!wasAborted && steps.length > 0) {
1803
- const telemetrySteps = steps.map(normalizeStepForTelemetry);
1804
- const lastTelemetryStep = telemetrySteps[telemetrySteps.length - 1];
1805
- await telemetryDispatcher.onEnd?.({
1806
- ...lastTelemetryStep,
1807
- steps: telemetrySteps,
1808
- usage: totalUsage,
1809
- totalUsage
1810
- });
2177
+ };
2178
+ if (mode === "generate" && step != null) {
2179
+ await mergedOnStepEnd?.(step);
2180
+ await telemetryDispatcher.onStepEnd?.(normalizeStepForTelemetry(step));
1811
2181
  }
2182
+ await notifyEnd(data, wasAborted);
1812
2183
  if (options.writable) {
1813
2184
  if (allToolResults.length > 0) await writeToolResults(options.writable, executedResults.map((r) => ({
1814
2185
  toolCallId: r.modelResult.toolCallId,
@@ -1817,42 +2188,13 @@ var WorkflowAgent = class {
1817
2188
  output: r.rawOutput,
1818
2189
  isError: r.isError
1819
2190
  })));
1820
- const approvalToolCalls = pausedToolCalls.filter((_, i) => {
1821
- const tcIndex = nonProviderToolCalls.indexOf(pausedToolCalls[i]);
1822
- return approvalNeeded[tcIndex];
1823
- });
1824
- if (approvalToolCalls.length > 0) {
1825
- const approvalRequests = await Promise.all(approvalToolCalls.map(async (tc) => {
1826
- const approvalId = `approval-${tc.toolCallId}`;
1827
- const signature = effectiveToolApprovalSecret == null ? void 0 : await signWorkflowToolApproval({
1828
- secret: effectiveToolApprovalSecret,
1829
- approvalId,
1830
- toolCallId: tc.toolCallId,
1831
- toolName: tc.toolName,
1832
- input: tc.input
1833
- });
1834
- return {
1835
- approvalId,
1836
- toolCallId: tc.toolCallId,
1837
- ...signature != null ? { signature } : {}
1838
- };
1839
- }));
1840
- await writeApprovalRequests(options.writable, approvalRequests);
1841
- }
1842
- }
1843
- if (options.writable) {
1844
- const sendFinish = options.sendFinish ?? true;
1845
- const preventClose = options.preventClose ?? false;
1846
- if (sendFinish || !preventClose) await closeStream(options.writable, preventClose, sendFinish);
2191
+ if (approvalMessages.length > 0) await writeApprovalRequests(options.writable, approvalMessages);
1847
2192
  }
2193
+ await closeOutput();
1848
2194
  return {
1849
- messages,
1850
- steps,
1851
- toolCalls: allToolCalls,
1852
- toolResults: allToolResults,
1853
- finishReason,
1854
- totalUsage,
1855
- output: void 0
2195
+ data,
2196
+ outcome: { status: "completed" },
2197
+ initialResponseMessages
1856
2198
  };
1857
2199
  }
1858
2200
  const clientToolResults = await Promise.all(nonProviderToolCalls.map((toolCall) => executeToolWithCallbacks(toolCall, stepTools, iterMessages, toolsContext, currentStepNumber, toolExecutionSandbox)));
@@ -1900,7 +2242,7 @@ var WorkflowAgent = class {
1900
2242
  input: toolCalls.find((tc) => tc.toolCallId === r.modelResult.toolCallId)?.input,
1901
2243
  output: r.rawOutput
1902
2244
  }));
1903
- addToolResultsToStep(step, executedToolResults);
2245
+ addToolResultsToStep(step, executedToolResults, mode);
1904
2246
  result = await iterator.next(continuationToolResults);
1905
2247
  } else {
1906
2248
  lastStepToolCalls = [];
@@ -1936,7 +2278,7 @@ var WorkflowAgent = class {
1936
2278
  const messages = finalMessages ?? prompt.messages;
1937
2279
  const effectiveOutput = options.output ?? this.output;
1938
2280
  let experimentalOutput = void 0;
1939
- if (effectiveOutput && steps.length > 0) {
2281
+ if (mode === "stream" && effectiveOutput && steps.length > 0) {
1940
2282
  const lastStep = steps[steps.length - 1];
1941
2283
  const text = lastStep.text;
1942
2284
  if (text) try {
@@ -1953,52 +2295,67 @@ var WorkflowAgent = class {
1953
2295
  }
1954
2296
  }
1955
2297
  const lastStep = steps[steps.length - 1];
1956
- const totalUsage = aggregateUsage(steps);
2298
+ const totalUsage = aggregateExecutionUsage(steps, mode);
1957
2299
  const finishReason = lastStep?.finishReason ?? "other";
1958
- if (mergedOnEnd && !wasAborted) await mergedOnEnd({
1959
- steps,
2300
+ const data = {
1960
2301
  messages,
1961
- text: lastStep?.text ?? "",
2302
+ steps,
2303
+ toolCalls: lastStepToolCalls,
2304
+ toolResults: lastStepToolResults,
1962
2305
  finishReason,
1963
- usage: totalUsage,
1964
2306
  totalUsage,
1965
- runtimeContext,
1966
- toolsContext,
1967
2307
  output: experimentalOutput
1968
- });
1969
- if (!wasAborted && steps.length > 0) {
1970
- const telemetrySteps = steps.map(normalizeStepForTelemetry);
1971
- const lastTelemetryStep = telemetrySteps[telemetrySteps.length - 1];
1972
- await telemetryDispatcher.onEnd?.({
1973
- ...lastTelemetryStep,
1974
- steps: telemetrySteps,
1975
- usage: totalUsage,
1976
- totalUsage
2308
+ };
2309
+ if (mode === "stream" || !hasEncounteredError && !hasTerminalError) await notifyEnd(data, wasAborted);
2310
+ await closeOutput();
2311
+ const outcome = hasEncounteredError ? wasAborted ? {
2312
+ status: "aborted",
2313
+ rejection: { value: encounteredError }
2314
+ } : {
2315
+ status: "failed",
2316
+ source: "execution",
2317
+ error: encounteredError
2318
+ } : hasTerminalError ? {
2319
+ status: "failed",
2320
+ source: "model-stream",
2321
+ error: terminalError
2322
+ } : wasAborted ? { status: "aborted" } : { status: "completed" };
2323
+ return {
2324
+ data,
2325
+ outcome,
2326
+ initialResponseMessages,
2327
+ ...outcome.status === "aborted" ? { abortReason: abortReason() } : {}
2328
+ };
2329
+ async function notifyEnd(data, aborted) {
2330
+ if (aborted) return;
2331
+ if (mergedOnEnd) await mergedOnEnd({
2332
+ steps: data.steps,
2333
+ messages: data.messages,
2334
+ text: data.steps.at(-1)?.text ?? "",
2335
+ finishReason: data.finishReason,
2336
+ usage: data.totalUsage,
2337
+ totalUsage: data.totalUsage,
2338
+ runtimeContext,
2339
+ toolsContext,
2340
+ output: data.output
1977
2341
  });
2342
+ if (data.steps.length > 0) {
2343
+ const telemetrySteps = data.steps.map(normalizeStepForTelemetry);
2344
+ await telemetryDispatcher.onEnd?.({
2345
+ ...telemetrySteps[telemetrySteps.length - 1],
2346
+ steps: telemetrySteps,
2347
+ usage: data.totalUsage,
2348
+ totalUsage: data.totalUsage
2349
+ });
2350
+ }
1978
2351
  }
1979
- if (hasEncounteredError) {
2352
+ async function closeOutput() {
1980
2353
  if (options.writable) {
1981
2354
  const sendFinish = options.sendFinish ?? true;
1982
2355
  const preventClose = options.preventClose ?? false;
1983
2356
  if (sendFinish || !preventClose) await closeStream(options.writable, preventClose, sendFinish);
1984
2357
  }
1985
- throw encounteredError;
1986
- }
1987
- if (options.writable) {
1988
- const sendFinish = options.sendFinish ?? true;
1989
- const preventClose = options.preventClose ?? false;
1990
- if (sendFinish || !preventClose) await closeStream(options.writable, preventClose, sendFinish);
1991
2358
  }
1992
- return {
1993
- messages,
1994
- steps,
1995
- toolCalls: lastStepToolCalls,
1996
- toolResults: lastStepToolResults,
1997
- finishReason,
1998
- totalUsage,
1999
- output: experimentalOutput,
2000
- ...hasTerminalError ? { error: terminalError } : {}
2001
- };
2002
2359
  }
2003
2360
  };
2004
2361
  function getModelInfo(model) {
@@ -2287,6 +2644,31 @@ async function executeTool(toolCall, tools, messages, context, abortSignal, down
2287
2644
  isError: false
2288
2645
  };
2289
2646
  }
2647
+ function aggregateExecutionUsage(steps, mode) {
2648
+ return mode === "stream" ? aggregateUsage(steps) : steps.reduce((usage, step) => addLanguageModelUsage(usage, step.usage), createNullLanguageModelUsage());
2649
+ }
2650
+ function addApprovalRequestsToMessages(messages, requests) {
2651
+ if (requests.length === 0) return messages;
2652
+ const result = [...messages];
2653
+ for (let index = result.length - 1; index >= 0; index--) {
2654
+ const message = result[index];
2655
+ if (message.role === "assistant") {
2656
+ result[index] = {
2657
+ ...message,
2658
+ content: [...typeof message.content === "string" ? [{
2659
+ type: "text",
2660
+ text: message.content
2661
+ }] : message.content, ...requests]
2662
+ };
2663
+ return result;
2664
+ }
2665
+ }
2666
+ result.unshift({
2667
+ role: "assistant",
2668
+ content: requests
2669
+ });
2670
+ return result;
2671
+ }
2290
2672
  //#endregion
2291
2673
  //#region src/to-ui-message-chunk.ts
2292
2674
  /**