@ai-sdk/workflow 2.0.71 → 2.0.72
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 +8 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +85 -62
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/test/concurrency-workflows.ts +66 -0
- package/src/workflow-agent.ts +158 -114
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-sdk/workflow",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.72",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "WorkflowAgent for building AI agents with AI SDK",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -38,11 +38,11 @@
|
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"@ai-sdk/provider": "4.0.27",
|
|
40
40
|
"@ai-sdk/provider-utils": "5.0.59",
|
|
41
|
-
"ai": "7.0.
|
|
41
|
+
"ai": "7.0.140",
|
|
42
42
|
"ajv": "^8.20.0"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@ai-sdk/otel": "1.0.
|
|
45
|
+
"@ai-sdk/otel": "1.0.140",
|
|
46
46
|
"@opentelemetry/api": "1.9.1",
|
|
47
47
|
"@opentelemetry/sdk-trace-base": "2.7.1",
|
|
48
48
|
"@types/node": "22.19.19",
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { tool, type ModelMessage } from 'ai';
|
|
2
|
+
import { createHook } from 'workflow';
|
|
3
|
+
import { z } from 'zod/v4';
|
|
4
|
+
import { mockTextModel } from '../providers/mock.js';
|
|
5
|
+
import { WorkflowAgent } from '../workflow-agent.js';
|
|
6
|
+
|
|
7
|
+
async function completeAction(id: string) {
|
|
8
|
+
'use step';
|
|
9
|
+
return id;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export async function resumeSequentialApprovals(mode: 'generate' | 'stream') {
|
|
13
|
+
'use workflow';
|
|
14
|
+
const events: string[] = [];
|
|
15
|
+
const agent = new WorkflowAgent({
|
|
16
|
+
model: mockTextModel('Done.'),
|
|
17
|
+
toolCallConcurrency: 1,
|
|
18
|
+
tools: {
|
|
19
|
+
action: tool({
|
|
20
|
+
inputSchema: z.object({ id: z.string() }),
|
|
21
|
+
needsApproval: true,
|
|
22
|
+
execute: async ({ id }) => {
|
|
23
|
+
events.push(`start:${id}`);
|
|
24
|
+
if (id === 'first') {
|
|
25
|
+
using hook = createHook<string>();
|
|
26
|
+
await hook;
|
|
27
|
+
}
|
|
28
|
+
const result = await completeAction(id);
|
|
29
|
+
events.push(`end:${id}`);
|
|
30
|
+
return result;
|
|
31
|
+
},
|
|
32
|
+
}),
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
const ids = ['first', 'second'];
|
|
36
|
+
const messages: ModelMessage[] = [
|
|
37
|
+
{ role: 'user', content: 'Run the tools.' },
|
|
38
|
+
{
|
|
39
|
+
role: 'assistant',
|
|
40
|
+
content: ids.flatMap(id => [
|
|
41
|
+
{
|
|
42
|
+
type: 'tool-call' as const,
|
|
43
|
+
toolCallId: id,
|
|
44
|
+
toolName: 'action',
|
|
45
|
+
input: { id },
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
type: 'tool-approval-request' as const,
|
|
49
|
+
toolCallId: id,
|
|
50
|
+
approvalId: `approval-${id}`,
|
|
51
|
+
},
|
|
52
|
+
]),
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
role: 'tool',
|
|
56
|
+
content: [...ids].reverse().map(id => ({
|
|
57
|
+
type: 'tool-approval-response' as const,
|
|
58
|
+
approvalId: `approval-${id}`,
|
|
59
|
+
approved: true,
|
|
60
|
+
})),
|
|
61
|
+
},
|
|
62
|
+
];
|
|
63
|
+
if (mode === 'generate') await agent.generate({ messages });
|
|
64
|
+
else await agent.stream({ messages });
|
|
65
|
+
return events;
|
|
66
|
+
}
|
package/src/workflow-agent.ts
CHANGED
|
@@ -51,6 +51,8 @@ import {
|
|
|
51
51
|
convertToLanguageModelPrompt,
|
|
52
52
|
mergeAbortSignals,
|
|
53
53
|
mergeCallbacks,
|
|
54
|
+
mapWithConcurrency,
|
|
55
|
+
prepareToolCallConcurrency,
|
|
54
56
|
signToolApproval,
|
|
55
57
|
standardizePrompt,
|
|
56
58
|
validateApprovedToolApprovals,
|
|
@@ -426,6 +428,7 @@ export interface PrepareCallOptions<
|
|
|
426
428
|
tools: TTools;
|
|
427
429
|
instructions?: Instructions;
|
|
428
430
|
toolChoice?: ToolChoice<TTools>;
|
|
431
|
+
toolCallConcurrency?: number;
|
|
429
432
|
stopWhen?:
|
|
430
433
|
| StopCondition<NoInfer<TTools>, TRuntimeContext>
|
|
431
434
|
| Array<StopCondition<NoInfer<TTools>, TRuntimeContext>>;
|
|
@@ -514,6 +517,13 @@ export type WorkflowAgentOptions<
|
|
|
514
517
|
*/
|
|
515
518
|
toolChoice?: ToolChoice<TTools>;
|
|
516
519
|
|
|
520
|
+
/**
|
|
521
|
+
* Maximum number of local tool calls that may execute concurrently within a step.
|
|
522
|
+
* Set to `1` to execute calls sequentially in model order, including approved
|
|
523
|
+
* calls. By default, all local tool calls execute concurrently.
|
|
524
|
+
*/
|
|
525
|
+
toolCallConcurrency?: number;
|
|
526
|
+
|
|
517
527
|
/**
|
|
518
528
|
* Optional telemetry configuration.
|
|
519
529
|
*/
|
|
@@ -999,6 +1009,13 @@ export type WorkflowAgentCallOptions<
|
|
|
999
1009
|
*/
|
|
1000
1010
|
toolChoice?: ToolChoice<TTools>;
|
|
1001
1011
|
|
|
1012
|
+
/**
|
|
1013
|
+
* Maximum number of local tool calls that may execute concurrently within a step.
|
|
1014
|
+
* Set to `1` to execute calls sequentially in model order, including approved
|
|
1015
|
+
* calls. By default, all local tool calls execute concurrently.
|
|
1016
|
+
*/
|
|
1017
|
+
toolCallConcurrency?: number;
|
|
1018
|
+
|
|
1002
1019
|
/**
|
|
1003
1020
|
* Limits the tools that are available for the model to call without
|
|
1004
1021
|
* changing the tool call and result types in the result.
|
|
@@ -1540,6 +1557,7 @@ export class WorkflowAgent<
|
|
|
1540
1557
|
private instructions?: Instructions;
|
|
1541
1558
|
private generationSettings: GenerationSettings;
|
|
1542
1559
|
private toolChoice?: ToolChoice<TBaseTools>;
|
|
1560
|
+
private toolCallConcurrency?: number;
|
|
1543
1561
|
private telemetry?: TelemetryOptions<TRuntimeContext, TBaseTools>;
|
|
1544
1562
|
private runtimeContext?: TRuntimeContext;
|
|
1545
1563
|
private toolsContext?: InferToolSetContext<TBaseTools>;
|
|
@@ -1588,6 +1606,7 @@ export class WorkflowAgent<
|
|
|
1588
1606
|
// `instructions` takes precedence over deprecated `system`
|
|
1589
1607
|
this.instructions = options.instructions ?? options.system;
|
|
1590
1608
|
this.toolChoice = options.toolChoice;
|
|
1609
|
+
this.toolCallConcurrency = options.toolCallConcurrency;
|
|
1591
1610
|
this.telemetry = options.telemetry;
|
|
1592
1611
|
this.runtimeContext = options.runtimeContext;
|
|
1593
1612
|
this.toolsContext = options.toolsContext;
|
|
@@ -1727,6 +1746,8 @@ export class WorkflowAgent<
|
|
|
1727
1746
|
Context | undefined
|
|
1728
1747
|
>;
|
|
1729
1748
|
let effectiveToolChoiceFromPrepare = options.toolChoice ?? this.toolChoice;
|
|
1749
|
+
let effectiveToolCallConcurrency =
|
|
1750
|
+
options.toolCallConcurrency ?? this.toolCallConcurrency;
|
|
1730
1751
|
let effectiveStopWhenFromPrepare =
|
|
1731
1752
|
options.stopWhen ??
|
|
1732
1753
|
this.stopWhen ??
|
|
@@ -1754,6 +1775,7 @@ export class WorkflowAgent<
|
|
|
1754
1775
|
tools: this.tools,
|
|
1755
1776
|
instructions: effectiveInstructions,
|
|
1756
1777
|
toolChoice: effectiveToolChoiceFromPrepare as ToolChoice<TBaseTools>,
|
|
1778
|
+
toolCallConcurrency: effectiveToolCallConcurrency,
|
|
1757
1779
|
stopWhen: effectiveStopWhenFromPrepare,
|
|
1758
1780
|
activeTools: effectiveActiveToolsFromPrepare,
|
|
1759
1781
|
experimental_download: effectiveDownloadFromPrepare,
|
|
@@ -1781,6 +1803,8 @@ export class WorkflowAgent<
|
|
|
1781
1803
|
if (prepared.toolChoice !== undefined)
|
|
1782
1804
|
effectiveToolChoiceFromPrepare =
|
|
1783
1805
|
prepared.toolChoice as ToolChoice<TBaseTools>;
|
|
1806
|
+
if (prepared.toolCallConcurrency !== undefined)
|
|
1807
|
+
effectiveToolCallConcurrency = prepared.toolCallConcurrency;
|
|
1784
1808
|
if (prepared.stopWhen !== undefined)
|
|
1785
1809
|
effectiveStopWhenFromPrepare = prepared.stopWhen;
|
|
1786
1810
|
if (prepared.activeTools !== undefined)
|
|
@@ -1818,6 +1842,9 @@ export class WorkflowAgent<
|
|
|
1818
1842
|
effectiveGenerationSettings.providerOptions = prepared.providerOptions;
|
|
1819
1843
|
}
|
|
1820
1844
|
|
|
1845
|
+
const toolCallConcurrency = prepareToolCallConcurrency(
|
|
1846
|
+
options.toolCallConcurrency ?? effectiveToolCallConcurrency,
|
|
1847
|
+
);
|
|
1821
1848
|
const effectiveTelemetry = effectiveTelemetryFromPrepare;
|
|
1822
1849
|
const telemetryDispatcher = createRestrictedTelemetryDispatcher<
|
|
1823
1850
|
any,
|
|
@@ -1869,6 +1896,7 @@ export class WorkflowAgent<
|
|
|
1869
1896
|
effectiveRuntimeContext,
|
|
1870
1897
|
effectiveToolsContext,
|
|
1871
1898
|
effectiveToolChoiceFromPrepare,
|
|
1899
|
+
toolCallConcurrency,
|
|
1872
1900
|
effectiveStopWhenFromPrepare,
|
|
1873
1901
|
effectiveActiveToolsFromPrepare,
|
|
1874
1902
|
effectiveToolApprovalSecret,
|
|
@@ -1906,6 +1934,7 @@ export class WorkflowAgent<
|
|
|
1906
1934
|
effectiveRuntimeContext,
|
|
1907
1935
|
effectiveToolsContext,
|
|
1908
1936
|
effectiveToolChoiceFromPrepare,
|
|
1937
|
+
toolCallConcurrency,
|
|
1909
1938
|
effectiveStopWhenFromPrepare,
|
|
1910
1939
|
effectiveActiveToolsFromPrepare,
|
|
1911
1940
|
effectiveToolApprovalSecret,
|
|
@@ -1985,52 +2014,56 @@ export class WorkflowAgent<
|
|
|
1985
2014
|
output: unknown;
|
|
1986
2015
|
}> = [];
|
|
1987
2016
|
|
|
1988
|
-
// Execute approved
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
if (
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2017
|
+
// Execute approved calls in model order with the same limit as new calls.
|
|
2018
|
+
const approvedResults = await mapWithConcurrency({
|
|
2019
|
+
items: approvedToolApprovals.filter(
|
|
2020
|
+
approval => !approval.providerExecuted,
|
|
2021
|
+
),
|
|
2022
|
+
concurrency: toolCallConcurrency,
|
|
2023
|
+
abortSignal: effectiveAbortSignal,
|
|
2024
|
+
execute: async approval => {
|
|
2025
|
+
const tool = (this.tools as ToolSet)[approval.toolName];
|
|
2026
|
+
if (tool && typeof tool.execute === 'function') {
|
|
2027
|
+
if (!tool.needsApproval) {
|
|
2028
|
+
const reason = `Tool "${approval.toolName}" does not require approval`;
|
|
2029
|
+
return {
|
|
2030
|
+
modelResult: {
|
|
2031
|
+
type: 'tool-result' as const,
|
|
2032
|
+
toolCallId: approval.toolCallId,
|
|
2033
|
+
toolName: approval.toolName,
|
|
2034
|
+
output: await createLanguageModelToolResultOutput({
|
|
2035
|
+
toolCallId: approval.toolCallId,
|
|
2036
|
+
toolName: approval.toolName,
|
|
2037
|
+
input: approval.input,
|
|
2038
|
+
output: reason,
|
|
2039
|
+
tool,
|
|
2040
|
+
errorMode: 'text',
|
|
2041
|
+
supportedUrls: {},
|
|
2042
|
+
download: workflowDownload,
|
|
2043
|
+
}),
|
|
2044
|
+
},
|
|
2045
|
+
};
|
|
2046
|
+
}
|
|
2047
|
+
|
|
2048
|
+
// Re-validate through the shared core implementation: input schema,
|
|
2049
|
+
// approval signature (when configured), and approval policy.
|
|
2050
|
+
// Convert invalid input, denial, or signature errors to a tool error
|
|
2051
|
+
// result so the agent loop can continue gracefully.
|
|
2052
|
+
let revalidationReason: string | undefined;
|
|
2053
|
+
try {
|
|
2054
|
+
await validateWorkflowToolApprovalSignature({
|
|
2055
|
+
secret: effectiveToolApprovalSecret,
|
|
2056
|
+
approvalId: approval.collected.approvalRequest.approvalId,
|
|
2004
2057
|
toolCallId: approval.toolCallId,
|
|
2005
2058
|
toolName: approval.toolName,
|
|
2006
2059
|
input: approval.input,
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
errorMode: 'text',
|
|
2010
|
-
supportedUrls: {},
|
|
2011
|
-
download: workflowDownload,
|
|
2012
|
-
}),
|
|
2013
|
-
});
|
|
2014
|
-
continue;
|
|
2015
|
-
}
|
|
2016
|
-
|
|
2017
|
-
// Re-validate through the shared core implementation: input schema,
|
|
2018
|
-
// approval signature (when configured), and approval policy.
|
|
2019
|
-
// Convert invalid input, denial, or signature errors to a tool error
|
|
2020
|
-
// result so the agent loop can continue gracefully.
|
|
2021
|
-
let revalidationReason: string | undefined;
|
|
2022
|
-
try {
|
|
2023
|
-
await validateWorkflowToolApprovalSignature({
|
|
2024
|
-
secret: effectiveToolApprovalSecret,
|
|
2025
|
-
approvalId: approval.collected.approvalRequest.approvalId,
|
|
2026
|
-
toolCallId: approval.toolCallId,
|
|
2027
|
-
toolName: approval.toolName,
|
|
2028
|
-
input: approval.input,
|
|
2029
|
-
signature: approval.collected.approvalRequest.signature,
|
|
2030
|
-
});
|
|
2060
|
+
signature: approval.collected.approvalRequest.signature,
|
|
2061
|
+
});
|
|
2031
2062
|
|
|
2032
|
-
|
|
2033
|
-
|
|
2063
|
+
const {
|
|
2064
|
+
deniedToolApprovals: policyDenied,
|
|
2065
|
+
invalidToolApprovals,
|
|
2066
|
+
} = await validateApprovedToolApprovals({
|
|
2034
2067
|
approvedToolApprovals: [approval.collected],
|
|
2035
2068
|
tools: this.tools as ToolSet,
|
|
2036
2069
|
toolApproval: undefined,
|
|
@@ -2040,58 +2073,67 @@ export class WorkflowAgent<
|
|
|
2040
2073
|
runtimeContext: effectiveRuntimeContext,
|
|
2041
2074
|
});
|
|
2042
2075
|
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2076
|
+
if (invalidToolApprovals.length > 0) {
|
|
2077
|
+
revalidationReason = getErrorMessage(
|
|
2078
|
+
invalidToolApprovals[0].error,
|
|
2079
|
+
);
|
|
2080
|
+
} else if (policyDenied.length > 0) {
|
|
2081
|
+
revalidationReason =
|
|
2082
|
+
policyDenied[0].approvalResponse.reason ??
|
|
2083
|
+
'Tool approval denied';
|
|
2084
|
+
}
|
|
2085
|
+
} catch (error) {
|
|
2086
|
+
revalidationReason = getErrorMessage(error);
|
|
2051
2087
|
}
|
|
2052
|
-
} catch (error) {
|
|
2053
|
-
revalidationReason = getErrorMessage(error);
|
|
2054
|
-
}
|
|
2055
2088
|
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2089
|
+
if (revalidationReason != null) {
|
|
2090
|
+
return {
|
|
2091
|
+
modelResult: {
|
|
2092
|
+
type: 'tool-result' as const,
|
|
2093
|
+
toolCallId: approval.toolCallId,
|
|
2094
|
+
toolName: approval.toolName,
|
|
2095
|
+
output: await createLanguageModelToolResultOutput({
|
|
2096
|
+
toolCallId: approval.toolCallId,
|
|
2097
|
+
toolName: approval.toolName,
|
|
2098
|
+
input: approval.input,
|
|
2099
|
+
output: revalidationReason,
|
|
2100
|
+
tool,
|
|
2101
|
+
errorMode: 'text',
|
|
2102
|
+
supportedUrls: {},
|
|
2103
|
+
download: workflowDownload,
|
|
2104
|
+
}),
|
|
2105
|
+
},
|
|
2106
|
+
};
|
|
2107
|
+
}
|
|
2108
|
+
|
|
2109
|
+
const result = await executeToolWithCallbacks(
|
|
2110
|
+
{
|
|
2062
2111
|
toolCallId: approval.toolCallId,
|
|
2063
2112
|
toolName: approval.toolName,
|
|
2064
2113
|
input: approval.input,
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2114
|
+
},
|
|
2115
|
+
this.tools as ToolSet,
|
|
2116
|
+
prompt.messages as unknown as LanguageModelV4Prompt,
|
|
2117
|
+
effectiveToolsContext,
|
|
2118
|
+
0,
|
|
2119
|
+
sandbox,
|
|
2120
|
+
);
|
|
2121
|
+
return {
|
|
2122
|
+
modelResult: result.modelResult,
|
|
2123
|
+
rawResult: {
|
|
2124
|
+
toolCallId: approval.toolCallId,
|
|
2125
|
+
toolName: approval.toolName,
|
|
2126
|
+
input: approval.input,
|
|
2127
|
+
output: result.rawOutput,
|
|
2128
|
+
},
|
|
2129
|
+
};
|
|
2073
2130
|
}
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
},
|
|
2081
|
-
this.tools as ToolSet,
|
|
2082
|
-
prompt.messages as unknown as LanguageModelV4Prompt,
|
|
2083
|
-
effectiveToolsContext,
|
|
2084
|
-
0,
|
|
2085
|
-
sandbox,
|
|
2086
|
-
);
|
|
2087
|
-
toolResultContent.push(result.modelResult);
|
|
2088
|
-
approvedRawResults.push({
|
|
2089
|
-
toolCallId: approval.toolCallId,
|
|
2090
|
-
toolName: approval.toolName,
|
|
2091
|
-
input: approval.input,
|
|
2092
|
-
output: result.rawOutput,
|
|
2093
|
-
});
|
|
2094
|
-
}
|
|
2131
|
+
},
|
|
2132
|
+
});
|
|
2133
|
+
for (const result of approvedResults) {
|
|
2134
|
+
if (result == null) continue;
|
|
2135
|
+
toolResultContent.push(result.modelResult);
|
|
2136
|
+
if (result.rawResult != null) approvedRawResults.push(result.rawResult);
|
|
2095
2137
|
}
|
|
2096
2138
|
|
|
2097
2139
|
// Create denial results for denied tools
|
|
@@ -2711,19 +2753,20 @@ export class WorkflowAgent<
|
|
|
2711
2753
|
providerApprovalRequests.length > 0
|
|
2712
2754
|
) {
|
|
2713
2755
|
// Execute any executable tools that were also called in this step
|
|
2714
|
-
const executableResults = await
|
|
2715
|
-
executableToolCalls
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2756
|
+
const executableResults = await mapWithConcurrency({
|
|
2757
|
+
items: executableToolCalls,
|
|
2758
|
+
concurrency: toolCallConcurrency,
|
|
2759
|
+
abortSignal: effectiveAbortSignal,
|
|
2760
|
+
execute: toolCall =>
|
|
2761
|
+
executeToolWithCallbacks(
|
|
2762
|
+
toolCall,
|
|
2763
|
+
stepTools,
|
|
2764
|
+
iterMessages,
|
|
2765
|
+
toolsContext,
|
|
2766
|
+
currentStepNumber,
|
|
2767
|
+
toolExecutionSandbox,
|
|
2768
|
+
),
|
|
2769
|
+
});
|
|
2727
2770
|
|
|
2728
2771
|
// Collect provider tool results
|
|
2729
2772
|
const providerResultEntries = await Promise.all(
|
|
@@ -2926,19 +2969,20 @@ export class WorkflowAgent<
|
|
|
2926
2969
|
}
|
|
2927
2970
|
|
|
2928
2971
|
// Execute client tools (all have execute functions at this point)
|
|
2929
|
-
const clientToolResults = await
|
|
2930
|
-
nonProviderToolCalls
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2972
|
+
const clientToolResults = await mapWithConcurrency({
|
|
2973
|
+
items: nonProviderToolCalls,
|
|
2974
|
+
concurrency: toolCallConcurrency,
|
|
2975
|
+
abortSignal: effectiveAbortSignal,
|
|
2976
|
+
execute: toolCall =>
|
|
2977
|
+
executeToolWithCallbacks(
|
|
2978
|
+
toolCall,
|
|
2979
|
+
stepTools,
|
|
2980
|
+
iterMessages,
|
|
2981
|
+
toolsContext,
|
|
2982
|
+
currentStepNumber,
|
|
2983
|
+
toolExecutionSandbox,
|
|
2984
|
+
),
|
|
2985
|
+
});
|
|
2942
2986
|
|
|
2943
2987
|
// For provider-executed tools, use the results from the stream
|
|
2944
2988
|
const providerToolResultEntries = await Promise.all(
|