@ai-sdk/workflow 2.0.58 → 2.0.60

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,
@@ -1330,7 +1659,8 @@ var WorkflowAgent = class {
1330
1659
  toolName: collected.toolCall.toolName,
1331
1660
  input: collected.toolCall.input,
1332
1661
  reason: collected.approvalResponse.reason,
1333
- providerExecuted: collected.toolCall.providerExecuted === true
1662
+ providerExecuted: collected.toolCall.providerExecuted === true,
1663
+ existingToolResult: collected.existingToolResult
1334
1664
  }));
1335
1665
  const providerExecutedApprovalIds = new Set([...collectedApprovals.approvedToolApprovals, ...collectedApprovals.deniedToolApprovals].filter((collected) => collected.toolCall.providerExecuted === true).map((collected) => collected.approvalResponse.approvalId));
1336
1666
  if (approvedToolApprovals.length > 0 || deniedToolApprovals.length > 0) {
@@ -1415,7 +1745,7 @@ var WorkflowAgent = class {
1415
1745
  }
1416
1746
  }
1417
1747
  for (const denial of deniedToolApprovals) {
1418
- if (denial.providerExecuted) continue;
1748
+ if (denial.providerExecuted || denial.existingToolResult !== void 0) continue;
1419
1749
  toolResultContent.push({
1420
1750
  type: "tool-result",
1421
1751
  toolCallId: denial.toolCallId,
@@ -1447,15 +1777,17 @@ var WorkflowAgent = class {
1447
1777
  content: filtered
1448
1778
  });
1449
1779
  } else cleanedMessages.push(msg);
1780
+ if (mode === "generate" && toolResultContent.length > 0) initialResponseMessages.push({
1781
+ role: "tool",
1782
+ content: toolResultContent
1783
+ });
1450
1784
  if (toolResultContent.length > 0) cleanedMessages.push({
1451
1785
  role: "tool",
1452
1786
  content: toolResultContent
1453
1787
  });
1454
1788
  prompt.messages = cleanedMessages;
1455
- if (options.writable && toolResultContent.length > 0) {
1456
- const deniedResults = toolResultContent.filter((r) => r.output.type === "execution-denied").map((r) => ({ toolCallId: r.toolCallId }));
1457
- await writeApprovalToolResults(options.writable, approvedRawResults, deniedResults);
1458
- }
1789
+ const deniedResults = deniedToolApprovals.filter((denial) => !denial.providerExecuted).map((denial) => ({ toolCallId: denial.toolCallId }));
1790
+ if (options.writable && (toolResultContent.length > 0 || deniedResults.length > 0)) await writeApprovalToolResults(options.writable, approvedRawResults, deniedResults);
1459
1791
  }
1460
1792
  const modelPrompt = await convertToLanguageModelPrompt({
1461
1793
  prompt,
@@ -1658,16 +1990,22 @@ var WorkflowAgent = class {
1658
1990
  if (mergedGenerationSettings.abortSignal?.aborted) {
1659
1991
  if (options.onAbort) await options.onAbort({ steps });
1660
1992
  return {
1661
- messages: prompt.messages,
1662
- steps,
1663
- toolCalls: [],
1664
- toolResults: [],
1665
- finishReason: "other",
1666
- totalUsage: aggregateUsage(steps),
1667
- output: void 0
1993
+ outcome: { status: "aborted" },
1994
+ abortReason: abortReason(),
1995
+ data: {
1996
+ messages: prompt.messages,
1997
+ steps,
1998
+ toolCalls: [],
1999
+ toolResults: [],
2000
+ finishReason: "other",
2001
+ totalUsage: aggregateExecutionUsage(steps, mode),
2002
+ output: void 0
2003
+ }
1668
2004
  };
1669
2005
  }
1670
- const iterator = streamTextIterator({
2006
+ const iterator = modelCallIterator({
2007
+ mode,
2008
+ include: options.include,
1671
2009
  model: effectiveModel,
1672
2010
  tools: effectiveTools,
1673
2011
  writable: options.writable,
@@ -1705,6 +2043,16 @@ var WorkflowAgent = class {
1705
2043
  break;
1706
2044
  }
1707
2045
  const { toolCalls, tools: stepTools = effectiveTools, messages: iterMessages, step, runtimeContext: yieldedRuntimeContext, toolsContext: yieldedToolsContext, experimental_sandbox: stepSandbox, providerExecutedToolResults, providerExecutedToolResultPositions } = result.value;
2046
+ if (mode === "generate" && step != null) {
2047
+ for (const call of toolCalls) if (call.invalid && !call.providerExecuted) step.content.push({
2048
+ type: "tool-error",
2049
+ toolCallId: call.toolCallId,
2050
+ toolName: call.toolName,
2051
+ input: call.input,
2052
+ error: call.error,
2053
+ dynamic: true
2054
+ });
2055
+ }
1708
2056
  const capturedProviderToolResults = providerExecutedToolResults ?? /* @__PURE__ */ new Map();
1709
2057
  const toolExecutionSandbox = stepSandbox ?? sandbox;
1710
2058
  const currentStepNumber = steps.length;
@@ -1748,9 +2096,10 @@ var WorkflowAgent = class {
1748
2096
  const tool = stepTools[tc.toolName];
1749
2097
  return tool && typeof tool.execute !== "function" || approvalNeeded[i];
1750
2098
  });
1751
- if (pausedToolCalls.length > 0) {
2099
+ const providerApprovalRequests = step?.content.filter((part) => part.type === "tool-approval-request").filter((part) => part.toolCall.providerExecuted) ?? [];
2100
+ if (pausedToolCalls.length > 0 || providerApprovalRequests.length > 0) {
1752
2101
  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) => ({
2102
+ const providerResultEntries = await Promise.all(providerToolCallsForResults.filter((call) => !providerApprovalRequests.some((request) => request.toolCall.toolCallId === call.toolCallId)).map(async (toolCall) => ({
1754
2103
  toolCall,
1755
2104
  result: await resolveProviderToolResult(toolCall, capturedProviderToolResults, stepTools, download)
1756
2105
  })));
@@ -1776,39 +2125,60 @@ var WorkflowAgent = class {
1776
2125
  input: toolCalls.find((tc) => tc.toolCallId === r.modelResult.toolCallId)?.input,
1777
2126
  output: r.rawOutput
1778
2127
  }));
1779
- addToolResultsToStep(step, executedResults);
2128
+ addToolResultsToStep(step, executedResults, mode);
2129
+ const approvalToolCalls = pausedToolCalls.filter((tc) => approvalNeeded[nonProviderToolCalls.indexOf(tc)]);
2130
+ const approvalRequests = await Promise.all(approvalToolCalls.map(async (tc) => {
2131
+ const approvalId = `approval-${tc.toolCallId}`;
2132
+ const signature = effectiveToolApprovalSecret == null ? void 0 : await signWorkflowToolApproval({
2133
+ secret: effectiveToolApprovalSecret,
2134
+ approvalId,
2135
+ toolCallId: tc.toolCallId,
2136
+ toolName: tc.toolName,
2137
+ input: tc.input
2138
+ });
2139
+ return {
2140
+ type: "tool-approval-request",
2141
+ approvalId,
2142
+ toolCall: {
2143
+ ...tc,
2144
+ type: "tool-call"
2145
+ },
2146
+ ...signature != null ? { signature } : {}
2147
+ };
2148
+ }));
2149
+ step?.content.push(...approvalRequests);
2150
+ const approvalMessages = approvalRequests.map(({ toolCall, ...request }) => ({
2151
+ ...request,
2152
+ toolCallId: toolCall.toolCallId
2153
+ }));
1780
2154
  const responseMessages = addToolResultsToConversation({
1781
2155
  messages: iterMessages,
1782
2156
  toolResults: resolvedResults,
1783
2157
  providerExecutedToolCallIds: new Set(providerToolCallsForResults.map((toolCall) => toolCall.toolCallId)),
1784
2158
  providerExecutedToolResultPositions
1785
2159
  });
1786
- step?.response.messages.push(...responseMessages);
1787
- const messages = iterMessages;
2160
+ const publicResponseMessages = addApprovalRequestsToMessages(mode === "generate" ? toModelResponseMessages(responseMessages) : responseMessages, [...approvalMessages, ...providerApprovalRequests.map(({ toolCall, ...request }) => ({
2161
+ ...request,
2162
+ toolCallId: toolCall.toolCallId
2163
+ }))]);
2164
+ step?.response.messages.push(...publicResponseMessages);
2165
+ const messages = publicResponseMessages === responseMessages ? iterMessages : [...iterMessages.slice(0, iterMessages.length - responseMessages.length), ...publicResponseMessages];
1788
2166
  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,
2167
+ const totalUsage = aggregateExecutionUsage(steps, mode);
2168
+ const data = {
1793
2169
  messages,
1794
- text: lastStep?.text ?? "",
1795
- finishReason,
1796
- usage: totalUsage,
2170
+ steps,
2171
+ toolCalls: allToolCalls,
2172
+ toolResults: allToolResults,
2173
+ finishReason: lastStep?.finishReason ?? "other",
1797
2174
  totalUsage,
1798
- runtimeContext,
1799
- toolsContext,
1800
2175
  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
- });
2176
+ };
2177
+ if (mode === "generate" && step != null) {
2178
+ await mergedOnStepEnd?.(step);
2179
+ await telemetryDispatcher.onStepEnd?.(normalizeStepForTelemetry(step));
1811
2180
  }
2181
+ await notifyEnd(data, wasAborted);
1812
2182
  if (options.writable) {
1813
2183
  if (allToolResults.length > 0) await writeToolResults(options.writable, executedResults.map((r) => ({
1814
2184
  toolCallId: r.modelResult.toolCallId,
@@ -1817,42 +2187,13 @@ var WorkflowAgent = class {
1817
2187
  output: r.rawOutput,
1818
2188
  isError: r.isError
1819
2189
  })));
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);
2190
+ if (approvalMessages.length > 0) await writeApprovalRequests(options.writable, approvalMessages);
1847
2191
  }
2192
+ await closeOutput();
1848
2193
  return {
1849
- messages,
1850
- steps,
1851
- toolCalls: allToolCalls,
1852
- toolResults: allToolResults,
1853
- finishReason,
1854
- totalUsage,
1855
- output: void 0
2194
+ data,
2195
+ outcome: { status: "completed" },
2196
+ initialResponseMessages
1856
2197
  };
1857
2198
  }
1858
2199
  const clientToolResults = await Promise.all(nonProviderToolCalls.map((toolCall) => executeToolWithCallbacks(toolCall, stepTools, iterMessages, toolsContext, currentStepNumber, toolExecutionSandbox)));
@@ -1900,7 +2241,7 @@ var WorkflowAgent = class {
1900
2241
  input: toolCalls.find((tc) => tc.toolCallId === r.modelResult.toolCallId)?.input,
1901
2242
  output: r.rawOutput
1902
2243
  }));
1903
- addToolResultsToStep(step, executedToolResults);
2244
+ addToolResultsToStep(step, executedToolResults, mode);
1904
2245
  result = await iterator.next(continuationToolResults);
1905
2246
  } else {
1906
2247
  lastStepToolCalls = [];
@@ -1936,7 +2277,7 @@ var WorkflowAgent = class {
1936
2277
  const messages = finalMessages ?? prompt.messages;
1937
2278
  const effectiveOutput = options.output ?? this.output;
1938
2279
  let experimentalOutput = void 0;
1939
- if (effectiveOutput && steps.length > 0) {
2280
+ if (mode === "stream" && effectiveOutput && steps.length > 0) {
1940
2281
  const lastStep = steps[steps.length - 1];
1941
2282
  const text = lastStep.text;
1942
2283
  if (text) try {
@@ -1953,52 +2294,67 @@ var WorkflowAgent = class {
1953
2294
  }
1954
2295
  }
1955
2296
  const lastStep = steps[steps.length - 1];
1956
- const totalUsage = aggregateUsage(steps);
2297
+ const totalUsage = aggregateExecutionUsage(steps, mode);
1957
2298
  const finishReason = lastStep?.finishReason ?? "other";
1958
- if (mergedOnEnd && !wasAborted) await mergedOnEnd({
1959
- steps,
2299
+ const data = {
1960
2300
  messages,
1961
- text: lastStep?.text ?? "",
2301
+ steps,
2302
+ toolCalls: lastStepToolCalls,
2303
+ toolResults: lastStepToolResults,
1962
2304
  finishReason,
1963
- usage: totalUsage,
1964
2305
  totalUsage,
1965
- runtimeContext,
1966
- toolsContext,
1967
2306
  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
2307
+ };
2308
+ if (mode === "stream" || !hasEncounteredError && !hasTerminalError) await notifyEnd(data, wasAborted);
2309
+ await closeOutput();
2310
+ const outcome = hasEncounteredError ? wasAborted ? {
2311
+ status: "aborted",
2312
+ rejection: { value: encounteredError }
2313
+ } : {
2314
+ status: "failed",
2315
+ source: "execution",
2316
+ error: encounteredError
2317
+ } : hasTerminalError ? {
2318
+ status: "failed",
2319
+ source: "model-stream",
2320
+ error: terminalError
2321
+ } : wasAborted ? { status: "aborted" } : { status: "completed" };
2322
+ return {
2323
+ data,
2324
+ outcome,
2325
+ initialResponseMessages,
2326
+ ...outcome.status === "aborted" ? { abortReason: abortReason() } : {}
2327
+ };
2328
+ async function notifyEnd(data, aborted) {
2329
+ if (aborted) return;
2330
+ if (mergedOnEnd) await mergedOnEnd({
2331
+ steps: data.steps,
2332
+ messages: data.messages,
2333
+ text: data.steps.at(-1)?.text ?? "",
2334
+ finishReason: data.finishReason,
2335
+ usage: data.totalUsage,
2336
+ totalUsage: data.totalUsage,
2337
+ runtimeContext,
2338
+ toolsContext,
2339
+ output: data.output
1977
2340
  });
2341
+ if (data.steps.length > 0) {
2342
+ const telemetrySteps = data.steps.map(normalizeStepForTelemetry);
2343
+ await telemetryDispatcher.onEnd?.({
2344
+ ...telemetrySteps[telemetrySteps.length - 1],
2345
+ steps: telemetrySteps,
2346
+ usage: data.totalUsage,
2347
+ totalUsage: data.totalUsage
2348
+ });
2349
+ }
1978
2350
  }
1979
- if (hasEncounteredError) {
2351
+ async function closeOutput() {
1980
2352
  if (options.writable) {
1981
2353
  const sendFinish = options.sendFinish ?? true;
1982
2354
  const preventClose = options.preventClose ?? false;
1983
2355
  if (sendFinish || !preventClose) await closeStream(options.writable, preventClose, sendFinish);
1984
2356
  }
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
2357
  }
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
2358
  }
2003
2359
  };
2004
2360
  function getModelInfo(model) {
@@ -2287,6 +2643,31 @@ async function executeTool(toolCall, tools, messages, context, abortSignal, down
2287
2643
  isError: false
2288
2644
  };
2289
2645
  }
2646
+ function aggregateExecutionUsage(steps, mode) {
2647
+ return mode === "stream" ? aggregateUsage(steps) : steps.reduce((usage, step) => addLanguageModelUsage(usage, step.usage), createNullLanguageModelUsage());
2648
+ }
2649
+ function addApprovalRequestsToMessages(messages, requests) {
2650
+ if (requests.length === 0) return messages;
2651
+ const result = [...messages];
2652
+ for (let index = result.length - 1; index >= 0; index--) {
2653
+ const message = result[index];
2654
+ if (message.role === "assistant") {
2655
+ result[index] = {
2656
+ ...message,
2657
+ content: [...typeof message.content === "string" ? [{
2658
+ type: "text",
2659
+ text: message.content
2660
+ }] : message.content, ...requests]
2661
+ };
2662
+ return result;
2663
+ }
2664
+ }
2665
+ result.unshift({
2666
+ role: "assistant",
2667
+ content: requests
2668
+ });
2669
+ return result;
2670
+ }
2290
2671
  //#endregion
2291
2672
  //#region src/to-ui-message-chunk.ts
2292
2673
  /**