@ai-sdk/workflow 2.0.71 → 2.0.73
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/CHANGELOG.md +19 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +241 -85
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/src/build-model-step-result.ts +6 -1
- package/src/do-generate-step.ts +15 -1
- package/src/do-stream-step.ts +28 -2
- package/src/model-call-iterator.ts +219 -4
- package/src/model-call-telemetry.ts +3 -3
- package/src/model-call.ts +14 -0
- package/src/serializable-schema.ts +18 -6
- package/src/test/concurrency-workflows.ts +66 -0
- package/src/test/telemetry-workflows.ts +30 -4
- package/src/to-ui-message-chunk.ts +3 -0
- package/src/workflow-agent.ts +175 -116
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { n as normalizeUIMessageStreamParts, t as WorkflowChatTransport } from "./workflow-chat-transport-Dj1poviu.js";
|
|
2
|
-
import { asArray, asSchema, convertUint8ArrayToBase64, createIdGenerator, 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, createTelemetryDispatcher, createToolModelOutput, createToolSearchState, downloadAssets, isOutputChunk, mapToolResultOutput, mergeAbortSignals, mergeCallbacks, parseToolCall, prepareLanguageModelCallOptions, prepareRetries, prepareToolChoice, prepareTools, resolveLanguageModel, signToolApproval, standardizePrompt, validateApprovedToolApprovals, verifyToolApprovalSignature } from "ai/internal";
|
|
2
|
+
import { asArray, asSchema, convertUint8ArrayToBase64, createIdGenerator, generateId, getErrorMessage, isAbortError, jsonSchema, safeParseJSON, validateTypes, withUserAgentSuffix } from "@ai-sdk/provider-utils";
|
|
3
|
+
import { DefaultGeneratedFile, InvalidToolApprovalSignatureError, InvalidToolInputError, NoOutputGeneratedError, Output, ToolChoiceViolationError, dynamicTool, experimental_filterActiveTools, experimental_streamLanguageModelCall, gateway, isDeepEqualData, isStepCount, tool, wrapLanguageModel } from "ai";
|
|
4
|
+
import { DefaultGenerateTextResult, DefaultStepResult, addLanguageModelUsage, asLanguageModelUsage, calculateTokensPerSecond, collectToolApprovals, convertLanguageModelContent, convertToLanguageModelPrompt, createDefaultDownloadFunction, createNullLanguageModelUsage, createRestrictedTelemetryDispatcher, createTelemetryDispatcher, createToolModelOutput, createToolSearchState, downloadAssets, filterIncludedContext, isOutputChunk, mapToolResultOutput, mapWithConcurrency, mergeAbortSignals, mergeCallbacks, parseToolCall, prepareLanguageModelCallOptions, prepareRetries, prepareToolCallConcurrency, prepareToolChoice, prepareTools, resolveLanguageModel, signToolApproval, standardizePrompt, validateApprovedToolApprovals, verifyToolApprovalSignature } from "ai/internal";
|
|
5
5
|
import { getWorkflowMetadata } from "workflow";
|
|
6
6
|
import Ajv from "ajv";
|
|
7
7
|
import Ajv2020 from "ajv/dist/2020.js";
|
|
@@ -143,9 +143,9 @@ async function buildModelStepResult(raw, toolCalls, finish, providerExecutedTool
|
|
|
143
143
|
if (!("reasoningIndex" in part)) providerContent.push(part);
|
|
144
144
|
break;
|
|
145
145
|
case "tool-call": {
|
|
146
|
-
const
|
|
146
|
+
const { inputSchemaInput: _inputSchemaInput, ...publicCall } = toolCalls[part.toolCallIndex];
|
|
147
147
|
providerContent.push({
|
|
148
|
-
...
|
|
148
|
+
...publicCall,
|
|
149
149
|
input: "",
|
|
150
150
|
type: "tool-call"
|
|
151
151
|
});
|
|
@@ -410,6 +410,7 @@ function languageModelPromptToModelMessages(prompt) {
|
|
|
410
410
|
*/
|
|
411
411
|
function serializeToolSet(tools, { toolsContext = {}, experimental_sandbox: sandbox } = {}) {
|
|
412
412
|
return Object.fromEntries(Object.entries(tools).map(([name, t]) => {
|
|
413
|
+
const inputSchema = asSchema(t.inputSchema);
|
|
413
414
|
const def = {
|
|
414
415
|
title: t.title,
|
|
415
416
|
metadata: t.metadata,
|
|
@@ -419,11 +420,12 @@ function serializeToolSet(tools, { toolsContext = {}, experimental_sandbox: sand
|
|
|
419
420
|
toolsContext,
|
|
420
421
|
experimental_sandbox: sandbox
|
|
421
422
|
}),
|
|
422
|
-
inputSchema:
|
|
423
|
+
inputSchema: inputSchema.jsonSchema,
|
|
423
424
|
strict: t.strict,
|
|
424
425
|
inputExamples: t.inputExamples,
|
|
425
426
|
providerOptions: t.providerOptions
|
|
426
427
|
};
|
|
428
|
+
if (inputSchema.validate != null) def.hasOwnValidator = true;
|
|
427
429
|
if (t.type === "dynamic") def.type = "dynamic";
|
|
428
430
|
if (t.onInputStart != null) def.hasOnInputStart = true;
|
|
429
431
|
if (t.onInputDelta != null) def.hasOnInputDelta = true;
|
|
@@ -457,9 +459,9 @@ function formatAjvError(error) {
|
|
|
457
459
|
/**
|
|
458
460
|
* Reconstructs tool objects from serializable tool definitions inside a step.
|
|
459
461
|
*
|
|
460
|
-
* Wraps each tool's JSON Schema with `jsonSchema()
|
|
461
|
-
*
|
|
462
|
-
*
|
|
462
|
+
* Wraps each tool's JSON Schema with `jsonSchema()`. Tools without their own
|
|
463
|
+
* validator are validated with Ajv. Tools with their own validator are
|
|
464
|
+
* validated after the workflow step, where the original schema is available.
|
|
463
465
|
*/
|
|
464
466
|
function resolveSerializableTools(tools) {
|
|
465
467
|
const ajvOptions = {
|
|
@@ -482,6 +484,7 @@ function resolveSerializableTools(tools) {
|
|
|
482
484
|
};
|
|
483
485
|
} });
|
|
484
486
|
};
|
|
487
|
+
const createInputSchema = (tool) => tool.hasOwnValidator ? jsonSchema(tool.inputSchema) : createValidatedInputSchema(tool.inputSchema);
|
|
485
488
|
return Object.fromEntries(Object.entries(tools).map(([name, t]) => {
|
|
486
489
|
if (t.type === "provider") {
|
|
487
490
|
const providerTool = {
|
|
@@ -506,7 +509,7 @@ function resolveSerializableTools(tools) {
|
|
|
506
509
|
description: t.description,
|
|
507
510
|
inputExamples: t.inputExamples,
|
|
508
511
|
providerOptions: t.providerOptions,
|
|
509
|
-
inputSchema:
|
|
512
|
+
inputSchema: createInputSchema(t)
|
|
510
513
|
})];
|
|
511
514
|
const functionTool = {
|
|
512
515
|
title: t.title,
|
|
@@ -515,7 +518,7 @@ function resolveSerializableTools(tools) {
|
|
|
515
518
|
strict: t.strict,
|
|
516
519
|
inputExamples: t.inputExamples,
|
|
517
520
|
providerOptions: t.providerOptions,
|
|
518
|
-
inputSchema:
|
|
521
|
+
inputSchema: createInputSchema(t)
|
|
519
522
|
};
|
|
520
523
|
return [name, t.type === "dynamic" ? tool({
|
|
521
524
|
...functionTool,
|
|
@@ -573,7 +576,7 @@ async function runModelCallWithTelemetry({ telemetry, modelInit, prompt, seriali
|
|
|
573
576
|
reasoning: options?.reasoning,
|
|
574
577
|
providerOptions: options?.providerOptions,
|
|
575
578
|
output: void 0,
|
|
576
|
-
runtimeContext: {},
|
|
579
|
+
runtimeContext: telemetry.runtimeContext ?? {},
|
|
577
580
|
toolsContext: {}
|
|
578
581
|
});
|
|
579
582
|
await dispatcher.onStepStart?.({
|
|
@@ -589,7 +592,7 @@ async function runModelCallWithTelemetry({ telemetry, modelInit, prompt, seriali
|
|
|
589
592
|
steps: [],
|
|
590
593
|
providerOptions: options?.providerOptions,
|
|
591
594
|
output: void 0,
|
|
592
|
-
runtimeContext: {},
|
|
595
|
+
runtimeContext: telemetry.runtimeContext ?? {},
|
|
593
596
|
toolsContext: {}
|
|
594
597
|
});
|
|
595
598
|
let result;
|
|
@@ -625,7 +628,7 @@ async function runModelCallWithTelemetry({ telemetry, modelInit, prompt, seriali
|
|
|
625
628
|
callId,
|
|
626
629
|
tools,
|
|
627
630
|
stepNumber: telemetry.stepNumber,
|
|
628
|
-
runtimeContext: {},
|
|
631
|
+
runtimeContext: telemetry.runtimeContext ?? {},
|
|
629
632
|
toolsContext: {}
|
|
630
633
|
});
|
|
631
634
|
await dispatcher.onStepEnd?.(step);
|
|
@@ -733,10 +736,17 @@ async function generateModelCall(prompt, modelInit, serializedTools, options, la
|
|
|
733
736
|
performance: { responseTimeMs }
|
|
734
737
|
});
|
|
735
738
|
abortSignal?.throwIfAborted();
|
|
739
|
+
const repairedToolCallIds = /* @__PURE__ */ new Set();
|
|
740
|
+
const repairToolCall = options.repairToolCall;
|
|
741
|
+
const trackedRepairToolCall = repairToolCall ? async (repairOptions) => {
|
|
742
|
+
const repaired = await repairToolCall(repairOptions);
|
|
743
|
+
if (repaired != null) repairedToolCallIds.add(repairOptions.toolCall.toolCallId);
|
|
744
|
+
return repaired;
|
|
745
|
+
} : void 0;
|
|
736
746
|
const toolCalls = await Promise.all(response.content.filter((part) => part.type === "tool-call").map((toolCall) => parseToolCall({
|
|
737
747
|
toolCall,
|
|
738
748
|
tools,
|
|
739
|
-
repairToolCall:
|
|
749
|
+
repairToolCall: trackedRepairToolCall,
|
|
740
750
|
instructions: modelPrompt.filter((message) => message.role === "system").map((message) => message.content).join("\n") || void 0,
|
|
741
751
|
messages: prompt.filter((message) => message.role !== "system")
|
|
742
752
|
})));
|
|
@@ -808,7 +818,8 @@ async function generateModelCall(prompt, modelInit, serializedTools, options, la
|
|
|
808
818
|
}
|
|
809
819
|
},
|
|
810
820
|
providerExecutedToolResults,
|
|
811
|
-
toolInputLifecycleEvents
|
|
821
|
+
toolInputLifecycleEvents,
|
|
822
|
+
repairedToolCallIds: [...repairedToolCallIds]
|
|
812
823
|
};
|
|
813
824
|
}
|
|
814
825
|
doGenerateStep.maxRetries = 0;
|
|
@@ -832,6 +843,13 @@ async function streamModelStep(conversationPrompt, modelInit, writable, serializ
|
|
|
832
843
|
const abortSignal = timeout == null ? options?.abortSignal : options?.abortSignal == null ? AbortSignal.timeout(timeout) : AbortSignal.any([options.abortSignal, AbortSignal.timeout(timeout)]);
|
|
833
844
|
const model = typeof modelInit === "string" ? gateway.languageModel(modelInit) : modelInit;
|
|
834
845
|
const toolInputLifecycleEvents = [];
|
|
846
|
+
const repairedToolCallIds = /* @__PURE__ */ new Set();
|
|
847
|
+
const repairToolCall = options?.repairToolCall;
|
|
848
|
+
const trackedRepairToolCall = repairToolCall ? async (repairOptions) => {
|
|
849
|
+
const repaired = await repairToolCall(repairOptions);
|
|
850
|
+
if (repaired != null) repairedToolCallIds.add(repairOptions.toolCall.toolCallId);
|
|
851
|
+
return repaired;
|
|
852
|
+
} : void 0;
|
|
835
853
|
const tools = serializedTools ? resolveSerializableTools(serializedTools) : void 0;
|
|
836
854
|
const modelWithTransforms = options?.experimental_transform == null ? model : wrapLanguageModel({
|
|
837
855
|
model,
|
|
@@ -885,7 +903,7 @@ async function streamModelStep(conversationPrompt, modelInit, writable, serializ
|
|
|
885
903
|
frequencyPenalty: options?.frequencyPenalty,
|
|
886
904
|
stopSequences: options?.stopSequences,
|
|
887
905
|
seed: options?.seed,
|
|
888
|
-
repairToolCall:
|
|
906
|
+
repairToolCall: trackedRepairToolCall,
|
|
889
907
|
download: options?.download,
|
|
890
908
|
...languageModelCallTelemetry
|
|
891
909
|
}));
|
|
@@ -1086,7 +1104,7 @@ async function streamModelStep(conversationPrompt, modelInit, writable, serializ
|
|
|
1086
1104
|
toolCallId: part.toolCall.toolCallId,
|
|
1087
1105
|
...part.signature != null ? { signature: part.signature } : {}
|
|
1088
1106
|
});
|
|
1089
|
-
else await writer.write(part);
|
|
1107
|
+
else if (!((part.type === "tool-call" || part.type === "tool-error" && !part.providerExecuted) && serializedTools?.[part.toolName]?.hasOwnValidator)) await writer.write(part);
|
|
1090
1108
|
}
|
|
1091
1109
|
if (part.type === "error" && !hasTerminalError) {
|
|
1092
1110
|
terminalError = part.error;
|
|
@@ -1116,6 +1134,7 @@ async function streamModelStep(conversationPrompt, modelInit, writable, serializ
|
|
|
1116
1134
|
},
|
|
1117
1135
|
providerExecutedToolResults,
|
|
1118
1136
|
toolInputLifecycleEvents,
|
|
1137
|
+
repairedToolCallIds: [...repairedToolCallIds],
|
|
1119
1138
|
...hasTerminalError ? { terminalError } : {}
|
|
1120
1139
|
};
|
|
1121
1140
|
}
|
|
@@ -1343,7 +1362,12 @@ async function* modelCallIterator({ prompt, mode = "stream", include, initialIns
|
|
|
1343
1362
|
functionId: telemetry?.functionId,
|
|
1344
1363
|
recordInputs: telemetry?.recordInputs,
|
|
1345
1364
|
recordOutputs: telemetry?.recordOutputs,
|
|
1346
|
-
stepNumber
|
|
1365
|
+
stepNumber,
|
|
1366
|
+
includeRuntimeContext: telemetry?.includeRuntimeContext,
|
|
1367
|
+
runtimeContext: filterIncludedContext({
|
|
1368
|
+
context: currentRuntimeContext,
|
|
1369
|
+
includeContext: telemetry?.includeRuntimeContext
|
|
1370
|
+
})
|
|
1347
1371
|
} : void 0
|
|
1348
1372
|
};
|
|
1349
1373
|
const modelCallResult = mode === "generate" ? await doGenerateStep(conversationPrompt, currentModel, serializedTools, callOptions) : await doStreamStep(conversationPrompt, currentModel, writable, serializedTools, callOptions);
|
|
@@ -1356,7 +1380,18 @@ async function* modelCallIterator({ prompt, mode = "stream", include, initialIns
|
|
|
1356
1380
|
terminalError = modelCallResult.terminalError;
|
|
1357
1381
|
hasTerminalError = true;
|
|
1358
1382
|
}
|
|
1359
|
-
const { toolCalls, finish, raw, providerExecutedToolResults, toolInputLifecycleEvents } = modelCallResult;
|
|
1383
|
+
const { toolCalls: serializedToolCalls, finish, raw, providerExecutedToolResults, toolInputLifecycleEvents, repairedToolCallIds } = modelCallResult;
|
|
1384
|
+
const toolCalls = await validateToolCallInputs({
|
|
1385
|
+
toolCalls: serializedToolCalls,
|
|
1386
|
+
tools: effectiveTools,
|
|
1387
|
+
serializedTools,
|
|
1388
|
+
repairToolCall,
|
|
1389
|
+
repairedToolCallIds: new Set(repairedToolCallIds),
|
|
1390
|
+
instructions: conversationPrompt.filter((message) => message.role === "system").map((message) => message.content).join("\n") || initialInstructions,
|
|
1391
|
+
messages: stepInputMessages.filter((message) => message.role !== "system"),
|
|
1392
|
+
abortSignal: currentGenerationSettings.abortSignal
|
|
1393
|
+
});
|
|
1394
|
+
if (mode === "stream" && writable != null) await writeDeferredToolCalls(writable, toolCalls.filter((_, index) => serializedTools[serializedToolCalls[index].toolName]?.hasOwnValidator));
|
|
1360
1395
|
await invokeToolInputLifecycleCallbacks({
|
|
1361
1396
|
events: toolInputLifecycleEvents ?? [],
|
|
1362
1397
|
toolCalls,
|
|
@@ -1460,6 +1495,100 @@ async function* modelCallIterator({ prompt, mode = "stream", include, initialIns
|
|
|
1460
1495
|
};
|
|
1461
1496
|
return conversationPrompt;
|
|
1462
1497
|
}
|
|
1498
|
+
async function validateToolCallInputs({ toolCalls, tools, serializedTools, repairToolCall, repairedToolCallIds, instructions, messages, abortSignal }) {
|
|
1499
|
+
return Promise.all(toolCalls.map(async (toolCall) => {
|
|
1500
|
+
if (toolCall.invalid || toolCall.providerExecuted) return toolCall;
|
|
1501
|
+
const tool = tools[toolCall.toolName];
|
|
1502
|
+
if (tool == null) return toolCall;
|
|
1503
|
+
if (asSchema(tool.inputSchema).validate == null) return toolCall;
|
|
1504
|
+
let repairedInput;
|
|
1505
|
+
const parsedToolCall = await parseToolCall({
|
|
1506
|
+
toolCall: {
|
|
1507
|
+
type: "tool-call",
|
|
1508
|
+
toolCallId: toolCall.toolCallId,
|
|
1509
|
+
toolName: toolCall.toolName,
|
|
1510
|
+
input: JSON.stringify(toolCall.input) ?? (toolCall.input == null ? "" : String(toolCall.input)),
|
|
1511
|
+
providerExecuted: toolCall.providerExecuted,
|
|
1512
|
+
providerMetadata: toolCall.providerMetadata
|
|
1513
|
+
},
|
|
1514
|
+
tools,
|
|
1515
|
+
repairToolCall: repairToolCall == null || repairedToolCallIds.has(toolCall.toolCallId) ? void 0 : async (options) => {
|
|
1516
|
+
const repairedToolCall = await repairToolCallInStep({
|
|
1517
|
+
repairToolCall,
|
|
1518
|
+
serializedTools,
|
|
1519
|
+
toolCall: options.toolCall,
|
|
1520
|
+
error: {
|
|
1521
|
+
toolName: options.toolCall.toolName,
|
|
1522
|
+
toolInput: options.toolCall.input,
|
|
1523
|
+
message: getErrorMessage(options.error)
|
|
1524
|
+
},
|
|
1525
|
+
instructions,
|
|
1526
|
+
messages: options.messages
|
|
1527
|
+
});
|
|
1528
|
+
if (repairedToolCall != null) {
|
|
1529
|
+
const parsedRepairedInput = repairedToolCall.input.trim() === "" ? {
|
|
1530
|
+
success: true,
|
|
1531
|
+
value: {}
|
|
1532
|
+
} : await safeParseJSON({ text: repairedToolCall.input });
|
|
1533
|
+
if (parsedRepairedInput.success) repairedInput = { value: parsedRepairedInput.value };
|
|
1534
|
+
}
|
|
1535
|
+
return repairedToolCall;
|
|
1536
|
+
},
|
|
1537
|
+
instructions,
|
|
1538
|
+
messages,
|
|
1539
|
+
abortSignal
|
|
1540
|
+
});
|
|
1541
|
+
const inputSchemaInput = repairedInput ?? { value: toolCall.input };
|
|
1542
|
+
return {
|
|
1543
|
+
...toolCall,
|
|
1544
|
+
...parsedToolCall,
|
|
1545
|
+
...!parsedToolCall.invalid && !isDeepEqualData(inputSchemaInput.value, parsedToolCall.input) ? { inputSchemaInput: inputSchemaInput.value } : {}
|
|
1546
|
+
};
|
|
1547
|
+
}));
|
|
1548
|
+
}
|
|
1549
|
+
/**
|
|
1550
|
+
* Runs `repairToolCall` inside a step. The callback may be a `'use step'`
|
|
1551
|
+
* function, so its arguments must be serializable: the tools and the
|
|
1552
|
+
* `inputSchema` accessor are rebuilt here instead of crossing the boundary
|
|
1553
|
+
* from the workflow body.
|
|
1554
|
+
*/
|
|
1555
|
+
async function repairToolCallInStep({ repairToolCall, serializedTools, toolCall, error, instructions, messages }) {
|
|
1556
|
+
"use step";
|
|
1557
|
+
const tools = resolveSerializableTools(serializedTools);
|
|
1558
|
+
return repairToolCall({
|
|
1559
|
+
toolCall,
|
|
1560
|
+
tools,
|
|
1561
|
+
inputSchema: async ({ toolName }) => asSchema(tools[toolName]?.inputSchema).jsonSchema,
|
|
1562
|
+
instructions,
|
|
1563
|
+
system: instructions,
|
|
1564
|
+
messages,
|
|
1565
|
+
error: new InvalidToolInputError({
|
|
1566
|
+
toolName: error.toolName,
|
|
1567
|
+
toolInput: error.toolInput,
|
|
1568
|
+
cause: new Error(error.message),
|
|
1569
|
+
message: error.message
|
|
1570
|
+
})
|
|
1571
|
+
});
|
|
1572
|
+
}
|
|
1573
|
+
async function writeDeferredToolCalls(writable, toolCalls) {
|
|
1574
|
+
"use step";
|
|
1575
|
+
const writer = writable.getWriter();
|
|
1576
|
+
try {
|
|
1577
|
+
for (const toolCall of toolCalls) {
|
|
1578
|
+
await writer.write(toolCall);
|
|
1579
|
+
if (toolCall.invalid && !toolCall.providerExecuted) await writer.write({
|
|
1580
|
+
type: "tool-error",
|
|
1581
|
+
toolCallId: toolCall.toolCallId,
|
|
1582
|
+
toolName: toolCall.toolName,
|
|
1583
|
+
input: toolCall.input,
|
|
1584
|
+
error: getErrorMessage(toolCall.error),
|
|
1585
|
+
dynamic: true
|
|
1586
|
+
});
|
|
1587
|
+
}
|
|
1588
|
+
} finally {
|
|
1589
|
+
writer.releaseLock();
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1463
1592
|
async function invokeToolInputLifecycleCallbacks({ events, toolCalls, tools, messages, abortSignal, toolsContext, experimental_sandbox }) {
|
|
1464
1593
|
const toolNamesByCallId = /* @__PURE__ */ new Map();
|
|
1465
1594
|
const toolCallsById = new Map(toolCalls.map((toolCall) => [toolCall.toolCallId, toolCall]));
|
|
@@ -1499,7 +1628,7 @@ async function invokeToolInputLifecycleCallbacks({ events, toolCalls, tools, mes
|
|
|
1499
1628
|
break;
|
|
1500
1629
|
case "available": {
|
|
1501
1630
|
const toolCall = toolCallsById.get(toolCallId);
|
|
1502
|
-
if (toolCall == null) break;
|
|
1631
|
+
if (toolCall == null || toolCall.invalid) break;
|
|
1503
1632
|
await tool.onInputAvailable?.({
|
|
1504
1633
|
...options,
|
|
1505
1634
|
input: toolCall.input
|
|
@@ -1686,6 +1815,7 @@ var WorkflowAgent = class {
|
|
|
1686
1815
|
this.tools = options.tools ?? {};
|
|
1687
1816
|
this.instructions = options.instructions ?? options.system;
|
|
1688
1817
|
this.toolChoice = options.toolChoice;
|
|
1818
|
+
this.toolCallConcurrency = options.toolCallConcurrency;
|
|
1689
1819
|
this.telemetry = options.telemetry;
|
|
1690
1820
|
this.runtimeContext = options.runtimeContext;
|
|
1691
1821
|
this.toolsContext = options.toolsContext;
|
|
@@ -1759,6 +1889,7 @@ var WorkflowAgent = class {
|
|
|
1759
1889
|
let effectiveRuntimeContext = options.runtimeContext ?? this.runtimeContext ?? {};
|
|
1760
1890
|
let effectiveToolsContext = options.toolsContext ?? this.toolsContext ?? {};
|
|
1761
1891
|
let effectiveToolChoiceFromPrepare = options.toolChoice ?? this.toolChoice;
|
|
1892
|
+
let effectiveToolCallConcurrency = options.toolCallConcurrency ?? this.toolCallConcurrency;
|
|
1762
1893
|
let effectiveStopWhenFromPrepare = options.stopWhen ?? this.stopWhen ?? (mode === "generate" ? isStepCount(20) : void 0);
|
|
1763
1894
|
let effectiveActiveToolsFromPrepare = options.activeTools ?? this.activeTools;
|
|
1764
1895
|
let effectiveDownloadFromPrepare = options.experimental_download ?? this.experimentalDownload;
|
|
@@ -1774,6 +1905,7 @@ var WorkflowAgent = class {
|
|
|
1774
1905
|
tools: this.tools,
|
|
1775
1906
|
instructions: effectiveInstructions,
|
|
1776
1907
|
toolChoice: effectiveToolChoiceFromPrepare,
|
|
1908
|
+
toolCallConcurrency: effectiveToolCallConcurrency,
|
|
1777
1909
|
stopWhen: effectiveStopWhenFromPrepare,
|
|
1778
1910
|
activeTools: effectiveActiveToolsFromPrepare,
|
|
1779
1911
|
experimental_download: effectiveDownloadFromPrepare,
|
|
@@ -1792,6 +1924,7 @@ var WorkflowAgent = class {
|
|
|
1792
1924
|
if (prepared.runtimeContext !== void 0) effectiveRuntimeContext = prepared.runtimeContext;
|
|
1793
1925
|
if (prepared.toolsContext !== void 0) effectiveToolsContext = prepared.toolsContext;
|
|
1794
1926
|
if (prepared.toolChoice !== void 0) effectiveToolChoiceFromPrepare = prepared.toolChoice;
|
|
1927
|
+
if (prepared.toolCallConcurrency !== void 0) effectiveToolCallConcurrency = prepared.toolCallConcurrency;
|
|
1795
1928
|
if (prepared.stopWhen !== void 0) effectiveStopWhenFromPrepare = prepared.stopWhen;
|
|
1796
1929
|
if (prepared.activeTools !== void 0) effectiveActiveToolsFromPrepare = prepared.activeTools;
|
|
1797
1930
|
if (prepared.experimental_download !== void 0) effectiveDownloadFromPrepare = prepared.experimental_download;
|
|
@@ -1810,6 +1943,7 @@ var WorkflowAgent = class {
|
|
|
1810
1943
|
if (prepared.reasoning !== void 0) effectiveGenerationSettings.reasoning = prepared.reasoning;
|
|
1811
1944
|
if (prepared.providerOptions !== void 0) effectiveGenerationSettings.providerOptions = prepared.providerOptions;
|
|
1812
1945
|
}
|
|
1946
|
+
const toolCallConcurrency = prepareToolCallConcurrency(options.toolCallConcurrency ?? effectiveToolCallConcurrency);
|
|
1813
1947
|
const effectiveTelemetry = effectiveTelemetryFromPrepare;
|
|
1814
1948
|
const telemetryDispatcher = createRestrictedTelemetryDispatcher({
|
|
1815
1949
|
telemetry: effectiveTelemetry,
|
|
@@ -1836,6 +1970,7 @@ var WorkflowAgent = class {
|
|
|
1836
1970
|
effectiveRuntimeContext,
|
|
1837
1971
|
effectiveToolsContext,
|
|
1838
1972
|
effectiveToolChoiceFromPrepare,
|
|
1973
|
+
toolCallConcurrency,
|
|
1839
1974
|
effectiveStopWhenFromPrepare,
|
|
1840
1975
|
effectiveActiveToolsFromPrepare,
|
|
1841
1976
|
effectiveToolApprovalSecret,
|
|
@@ -1852,7 +1987,7 @@ var WorkflowAgent = class {
|
|
|
1852
1987
|
};
|
|
1853
1988
|
}
|
|
1854
1989
|
async execute(options, mode = "stream") {
|
|
1855
|
-
const { onEnd, effectiveModel, effectiveInstructions, effectiveGenerationSettings, effectiveRuntimeContext, effectiveToolsContext, effectiveToolChoiceFromPrepare, effectiveStopWhenFromPrepare, effectiveActiveToolsFromPrepare, effectiveToolApprovalSecret, effectiveTelemetry, telemetryDispatcher, prompt, download, workflowDownload, sandbox, effectiveAbortSignal, timeoutAt, mergedOnToolExecutionStart, mergedOnToolExecutionEnd } = await this.prepareInvocation(options, mode);
|
|
1990
|
+
const { onEnd, effectiveModel, effectiveInstructions, effectiveGenerationSettings, effectiveRuntimeContext, effectiveToolsContext, effectiveToolChoiceFromPrepare, toolCallConcurrency, effectiveStopWhenFromPrepare, effectiveActiveToolsFromPrepare, effectiveToolApprovalSecret, effectiveTelemetry, telemetryDispatcher, prompt, download, workflowDownload, sandbox, effectiveAbortSignal, timeoutAt, mergedOnToolExecutionStart, mergedOnToolExecutionEnd } = await this.prepareInvocation(options, mode);
|
|
1856
1991
|
const initialResponseMessages = [];
|
|
1857
1992
|
const abortReason = () => effectiveAbortSignal?.reason === void 0 ? void 0 : { value: effectiveAbortSignal.reason };
|
|
1858
1993
|
const collectedApprovals = collectToolApprovals({ messages: prompt.messages });
|
|
@@ -1876,13 +2011,55 @@ var WorkflowAgent = class {
|
|
|
1876
2011
|
if (approvedToolApprovals.length > 0 || deniedToolApprovals.length > 0) {
|
|
1877
2012
|
const toolResultContent = [];
|
|
1878
2013
|
const approvedRawResults = [];
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
2014
|
+
const approvedResults = await mapWithConcurrency({
|
|
2015
|
+
items: approvedToolApprovals.filter((approval) => !approval.providerExecuted),
|
|
2016
|
+
concurrency: toolCallConcurrency,
|
|
2017
|
+
abortSignal: effectiveAbortSignal,
|
|
2018
|
+
execute: async (approval) => {
|
|
2019
|
+
const tool = this.tools[approval.toolName];
|
|
2020
|
+
if (tool && typeof tool.execute === "function") {
|
|
2021
|
+
if (!tool.needsApproval) {
|
|
2022
|
+
const reason = `Tool "${approval.toolName}" does not require approval`;
|
|
2023
|
+
return { modelResult: {
|
|
2024
|
+
type: "tool-result",
|
|
2025
|
+
toolCallId: approval.toolCallId,
|
|
2026
|
+
toolName: approval.toolName,
|
|
2027
|
+
output: await createLanguageModelToolResultOutput({
|
|
2028
|
+
toolCallId: approval.toolCallId,
|
|
2029
|
+
toolName: approval.toolName,
|
|
2030
|
+
input: approval.input,
|
|
2031
|
+
output: reason,
|
|
2032
|
+
tool,
|
|
2033
|
+
errorMode: "text",
|
|
2034
|
+
supportedUrls: {},
|
|
2035
|
+
download: workflowDownload
|
|
2036
|
+
})
|
|
2037
|
+
} };
|
|
2038
|
+
}
|
|
2039
|
+
let revalidationReason;
|
|
2040
|
+
try {
|
|
2041
|
+
await validateWorkflowToolApprovalSignature({
|
|
2042
|
+
secret: effectiveToolApprovalSecret,
|
|
2043
|
+
approvalId: approval.collected.approvalRequest.approvalId,
|
|
2044
|
+
toolCallId: approval.toolCallId,
|
|
2045
|
+
toolName: approval.toolName,
|
|
2046
|
+
input: approval.input,
|
|
2047
|
+
signature: approval.collected.approvalRequest.signature
|
|
2048
|
+
});
|
|
2049
|
+
const { deniedToolApprovals: policyDenied, invalidToolApprovals } = await validateApprovedToolApprovals({
|
|
2050
|
+
approvedToolApprovals: [approval.collected],
|
|
2051
|
+
tools: this.tools,
|
|
2052
|
+
toolApproval: void 0,
|
|
2053
|
+
messages: prompt.messages,
|
|
2054
|
+
toolsContext: effectiveToolsContext,
|
|
2055
|
+
runtimeContext: effectiveRuntimeContext
|
|
2056
|
+
});
|
|
2057
|
+
if (invalidToolApprovals.length > 0) revalidationReason = getErrorMessage(invalidToolApprovals[0].error);
|
|
2058
|
+
else if (policyDenied.length > 0) revalidationReason = policyDenied[0].approvalResponse.reason ?? "Tool approval denied";
|
|
2059
|
+
} catch (error) {
|
|
2060
|
+
revalidationReason = getErrorMessage(error);
|
|
2061
|
+
}
|
|
2062
|
+
if (revalidationReason != null) return { modelResult: {
|
|
1886
2063
|
type: "tool-result",
|
|
1887
2064
|
toolCallId: approval.toolCallId,
|
|
1888
2065
|
toolName: approval.toolName,
|
|
@@ -1890,69 +2067,34 @@ var WorkflowAgent = class {
|
|
|
1890
2067
|
toolCallId: approval.toolCallId,
|
|
1891
2068
|
toolName: approval.toolName,
|
|
1892
2069
|
input: approval.input,
|
|
1893
|
-
output:
|
|
2070
|
+
output: revalidationReason,
|
|
1894
2071
|
tool,
|
|
1895
2072
|
errorMode: "text",
|
|
1896
2073
|
supportedUrls: {},
|
|
1897
2074
|
download: workflowDownload
|
|
1898
2075
|
})
|
|
1899
|
-
}
|
|
1900
|
-
|
|
1901
|
-
}
|
|
1902
|
-
let revalidationReason;
|
|
1903
|
-
try {
|
|
1904
|
-
await validateWorkflowToolApprovalSignature({
|
|
1905
|
-
secret: effectiveToolApprovalSecret,
|
|
1906
|
-
approvalId: approval.collected.approvalRequest.approvalId,
|
|
1907
|
-
toolCallId: approval.toolCallId,
|
|
1908
|
-
toolName: approval.toolName,
|
|
1909
|
-
input: approval.input,
|
|
1910
|
-
signature: approval.collected.approvalRequest.signature
|
|
1911
|
-
});
|
|
1912
|
-
const { deniedToolApprovals: policyDenied, invalidToolApprovals } = await validateApprovedToolApprovals({
|
|
1913
|
-
approvedToolApprovals: [approval.collected],
|
|
1914
|
-
tools: this.tools,
|
|
1915
|
-
toolApproval: void 0,
|
|
1916
|
-
messages: prompt.messages,
|
|
1917
|
-
toolsContext: effectiveToolsContext,
|
|
1918
|
-
runtimeContext: effectiveRuntimeContext
|
|
1919
|
-
});
|
|
1920
|
-
if (invalidToolApprovals.length > 0) revalidationReason = getErrorMessage(invalidToolApprovals[0].error);
|
|
1921
|
-
else if (policyDenied.length > 0) revalidationReason = policyDenied[0].approvalResponse.reason ?? "Tool approval denied";
|
|
1922
|
-
} catch (error) {
|
|
1923
|
-
revalidationReason = getErrorMessage(error);
|
|
1924
|
-
}
|
|
1925
|
-
if (revalidationReason != null) {
|
|
1926
|
-
toolResultContent.push({
|
|
1927
|
-
type: "tool-result",
|
|
2076
|
+
} };
|
|
2077
|
+
const result = await executeToolWithCallbacks({
|
|
1928
2078
|
toolCallId: approval.toolCallId,
|
|
1929
2079
|
toolName: approval.toolName,
|
|
1930
|
-
|
|
2080
|
+
input: approval.input
|
|
2081
|
+
}, this.tools, prompt.messages, effectiveToolsContext, 0, sandbox);
|
|
2082
|
+
return {
|
|
2083
|
+
modelResult: result.modelResult,
|
|
2084
|
+
rawResult: {
|
|
1931
2085
|
toolCallId: approval.toolCallId,
|
|
1932
2086
|
toolName: approval.toolName,
|
|
1933
2087
|
input: approval.input,
|
|
1934
|
-
output:
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
supportedUrls: {},
|
|
1938
|
-
download: workflowDownload
|
|
1939
|
-
})
|
|
1940
|
-
});
|
|
1941
|
-
continue;
|
|
2088
|
+
output: result.rawOutput
|
|
2089
|
+
}
|
|
2090
|
+
};
|
|
1942
2091
|
}
|
|
1943
|
-
const result = await executeToolWithCallbacks({
|
|
1944
|
-
toolCallId: approval.toolCallId,
|
|
1945
|
-
toolName: approval.toolName,
|
|
1946
|
-
input: approval.input
|
|
1947
|
-
}, this.tools, prompt.messages, effectiveToolsContext, 0, sandbox);
|
|
1948
|
-
toolResultContent.push(result.modelResult);
|
|
1949
|
-
approvedRawResults.push({
|
|
1950
|
-
toolCallId: approval.toolCallId,
|
|
1951
|
-
toolName: approval.toolName,
|
|
1952
|
-
input: approval.input,
|
|
1953
|
-
output: result.rawOutput
|
|
1954
|
-
});
|
|
1955
2092
|
}
|
|
2093
|
+
});
|
|
2094
|
+
for (const result of approvedResults) {
|
|
2095
|
+
if (result == null) continue;
|
|
2096
|
+
toolResultContent.push(result.modelResult);
|
|
2097
|
+
if (result.rawResult != null) approvedRawResults.push(result.rawResult);
|
|
1956
2098
|
}
|
|
1957
2099
|
for (const denial of deniedToolApprovals) {
|
|
1958
2100
|
if (denial.providerExecuted || denial.existingToolResult !== void 0) continue;
|
|
@@ -2309,7 +2451,12 @@ var WorkflowAgent = class {
|
|
|
2309
2451
|
});
|
|
2310
2452
|
const providerApprovalRequests = step?.content.filter((part) => part.type === "tool-approval-request").filter((part) => part.toolCall.providerExecuted) ?? [];
|
|
2311
2453
|
if (pausedToolCalls.length > 0 || providerApprovalRequests.length > 0) {
|
|
2312
|
-
const executableResults = await
|
|
2454
|
+
const executableResults = await mapWithConcurrency({
|
|
2455
|
+
items: executableToolCalls,
|
|
2456
|
+
concurrency: toolCallConcurrency,
|
|
2457
|
+
abortSignal: effectiveAbortSignal,
|
|
2458
|
+
execute: (toolCall) => executeToolWithCallbacks(toolCall, stepTools, iterMessages, toolsContext, currentStepNumber, toolExecutionSandbox)
|
|
2459
|
+
});
|
|
2313
2460
|
const providerResultEntries = await Promise.all(providerToolCallsForResults.filter((call) => !providerApprovalRequests.some((request) => request.toolCall.toolCallId === call.toolCallId)).map(async (toolCall) => ({
|
|
2314
2461
|
toolCall,
|
|
2315
2462
|
result: await resolveProviderToolResult(toolCall, capturedProviderToolResults, stepTools, workflowDownload)
|
|
@@ -2339,6 +2486,7 @@ var WorkflowAgent = class {
|
|
|
2339
2486
|
addToolResultsToStep(step, executedResults, mode);
|
|
2340
2487
|
const approvalToolCalls = pausedToolCalls.filter((tc) => approvalNeeded[nonProviderToolCalls.indexOf(tc)]);
|
|
2341
2488
|
const approvalRequests = await Promise.all(approvalToolCalls.map(async (tc) => {
|
|
2489
|
+
const { inputSchemaInput, ...toolCallWithoutInputSchemaInput } = tc;
|
|
2342
2490
|
const approvalId = `approval-${tc.toolCallId}`;
|
|
2343
2491
|
const signature = effectiveToolApprovalSecret == null ? void 0 : await signWorkflowToolApproval({
|
|
2344
2492
|
secret: effectiveToolApprovalSecret,
|
|
@@ -2350,14 +2498,15 @@ var WorkflowAgent = class {
|
|
|
2350
2498
|
return {
|
|
2351
2499
|
type: "tool-approval-request",
|
|
2352
2500
|
approvalId,
|
|
2501
|
+
...inputSchemaInput !== void 0 ? { inputSchemaInput } : {},
|
|
2353
2502
|
toolCall: {
|
|
2354
|
-
...
|
|
2503
|
+
...toolCallWithoutInputSchemaInput,
|
|
2355
2504
|
type: "tool-call"
|
|
2356
2505
|
},
|
|
2357
2506
|
...signature != null ? { signature } : {}
|
|
2358
2507
|
};
|
|
2359
2508
|
}));
|
|
2360
|
-
step?.content.push(...approvalRequests);
|
|
2509
|
+
step?.content.push(...approvalRequests.map(({ inputSchemaInput: _inputSchemaInput, ...request }) => request));
|
|
2361
2510
|
const approvalMessages = approvalRequests.map(({ toolCall, ...request }) => ({
|
|
2362
2511
|
...request,
|
|
2363
2512
|
toolCallId: toolCall.toolCallId
|
|
@@ -2407,7 +2556,12 @@ var WorkflowAgent = class {
|
|
|
2407
2556
|
initialResponseMessages
|
|
2408
2557
|
};
|
|
2409
2558
|
}
|
|
2410
|
-
const clientToolResults = await
|
|
2559
|
+
const clientToolResults = await mapWithConcurrency({
|
|
2560
|
+
items: nonProviderToolCalls,
|
|
2561
|
+
concurrency: toolCallConcurrency,
|
|
2562
|
+
abortSignal: effectiveAbortSignal,
|
|
2563
|
+
execute: (toolCall) => executeToolWithCallbacks(toolCall, stepTools, iterMessages, toolsContext, currentStepNumber, toolExecutionSandbox)
|
|
2564
|
+
});
|
|
2411
2565
|
const providerToolResultEntries = await Promise.all(providerToolCallsForResults.map(async (toolCall) => ({
|
|
2412
2566
|
toolCall,
|
|
2413
2567
|
result: await resolveProviderToolResult(toolCall, capturedProviderToolResults, stepTools, workflowDownload)
|
|
@@ -2621,7 +2775,8 @@ async function writeApprovalRequests(writable, approvalRequests) {
|
|
|
2621
2775
|
type: "tool-approval-request",
|
|
2622
2776
|
approvalId: request.approvalId,
|
|
2623
2777
|
toolCallId: request.toolCallId,
|
|
2624
|
-
...request.signature != null ? { signature: request.signature } : {}
|
|
2778
|
+
...request.signature != null ? { signature: request.signature } : {},
|
|
2779
|
+
...request.inputSchemaInput !== void 0 ? { inputSchemaInput: request.inputSchemaInput } : {}
|
|
2625
2780
|
});
|
|
2626
2781
|
} finally {
|
|
2627
2782
|
writer.releaseLock();
|
|
@@ -3000,6 +3155,7 @@ function toUIMessageChunk(part) {
|
|
|
3000
3155
|
type: "tool-approval-request",
|
|
3001
3156
|
approvalId: part.approvalId,
|
|
3002
3157
|
toolCallId: "toolCallId" in part ? part.toolCallId : part.toolCall.toolCallId,
|
|
3158
|
+
..."inputSchemaInput" in part && part.inputSchemaInput !== void 0 ? { inputSchemaInput: part.inputSchemaInput } : {},
|
|
3003
3159
|
...part.signature != null ? { signature: part.signature } : {}
|
|
3004
3160
|
};
|
|
3005
3161
|
default: {
|