@ai-sdk/workflow 1.0.0-beta.9 → 1.0.0-canary.33
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 +233 -0
- package/dist/index.d.mts +36 -26
- package/dist/index.mjs +120 -94
- package/dist/index.mjs.map +1 -1
- package/package.json +8 -6
- package/src/do-stream-step.ts +7 -6
- package/src/index.ts +3 -3
- package/src/serializable-schema.ts +4 -0
- package/src/stream-text-iterator.ts +17 -37
- package/src/telemetry.ts +5 -5
- package/src/test/agent-e2e-workflows.ts +9 -9
- package/src/to-ui-message-chunk.ts +5 -2
- package/src/workflow-agent.ts +132 -89
- package/src/workflow-chat-transport.ts +2 -2
package/src/workflow-agent.ts
CHANGED
|
@@ -7,21 +7,24 @@ import type {
|
|
|
7
7
|
SharedV4ProviderOptions,
|
|
8
8
|
} from '@ai-sdk/provider';
|
|
9
9
|
import {
|
|
10
|
-
|
|
10
|
+
Output,
|
|
11
|
+
experimental_filterActiveTools as filterActiveTools,
|
|
11
12
|
type FinishReason,
|
|
12
13
|
type LanguageModelResponseMetadata,
|
|
13
14
|
type LanguageModelUsage,
|
|
15
|
+
type Experimental_LanguageModelStreamPart as ModelCallStreamPart,
|
|
14
16
|
type ModelMessage,
|
|
15
|
-
Output,
|
|
16
17
|
type StepResult,
|
|
17
18
|
type StopCondition,
|
|
18
|
-
type
|
|
19
|
+
type GenerateTextOnStepFinishCallback,
|
|
19
20
|
type SystemModelMessage,
|
|
21
|
+
type ActiveTools,
|
|
20
22
|
type ToolCallRepairFunction,
|
|
21
23
|
type ToolChoice,
|
|
22
24
|
type ToolSet,
|
|
23
25
|
type UIMessage,
|
|
24
|
-
LanguageModel,
|
|
26
|
+
type LanguageModel,
|
|
27
|
+
type Prompt,
|
|
25
28
|
} from 'ai';
|
|
26
29
|
import {
|
|
27
30
|
convertToLanguageModelPrompt,
|
|
@@ -30,19 +33,18 @@ import {
|
|
|
30
33
|
standardizePrompt,
|
|
31
34
|
} from 'ai/internal';
|
|
32
35
|
import { streamTextIterator } from './stream-text-iterator.js';
|
|
33
|
-
import type { CompatibleLanguageModel } from './types.js';
|
|
34
36
|
|
|
35
37
|
// Re-export for consumers
|
|
36
38
|
export type { CompatibleLanguageModel } from './types.js';
|
|
37
39
|
|
|
38
40
|
/**
|
|
39
41
|
* Callback function to be called after each step completes.
|
|
40
|
-
* Alias for the AI SDK's
|
|
42
|
+
* Alias for the AI SDK's GenerateTextOnStepFinishCallback, using
|
|
41
43
|
* WorkflowAgent-consistent naming.
|
|
42
44
|
*/
|
|
43
45
|
export type WorkflowAgentOnStepFinishCallback<
|
|
44
46
|
TTools extends ToolSet = ToolSet,
|
|
45
|
-
> =
|
|
47
|
+
> = GenerateTextOnStepFinishCallback<TTools, any>;
|
|
46
48
|
|
|
47
49
|
/**
|
|
48
50
|
* Infer the type of the tools of a workflow agent.
|
|
@@ -92,7 +94,7 @@ export type ProviderOptions = SharedV4ProviderOptions;
|
|
|
92
94
|
/**
|
|
93
95
|
* Telemetry settings for observability.
|
|
94
96
|
*/
|
|
95
|
-
export interface
|
|
97
|
+
export interface TelemetryOptions {
|
|
96
98
|
/**
|
|
97
99
|
* Enable or disable telemetry. Defaults to true.
|
|
98
100
|
*/
|
|
@@ -339,7 +341,11 @@ export interface PrepareCallOptions<
|
|
|
339
341
|
tools: TTools;
|
|
340
342
|
instructions?: string | SystemModelMessage | Array<SystemModelMessage>;
|
|
341
343
|
toolChoice?: ToolChoice<TTools>;
|
|
342
|
-
|
|
344
|
+
telemetry?: TelemetryOptions;
|
|
345
|
+
/**
|
|
346
|
+
* @deprecated Use `telemetry` instead. This alias will be removed in a future major release.
|
|
347
|
+
*/
|
|
348
|
+
experimental_telemetry?: TelemetryOptions;
|
|
343
349
|
experimental_context?: unknown;
|
|
344
350
|
messages: ModelMessage[];
|
|
345
351
|
}
|
|
@@ -405,9 +411,16 @@ export interface WorkflowAgentOptions<
|
|
|
405
411
|
toolChoice?: ToolChoice<TTools>;
|
|
406
412
|
|
|
407
413
|
/**
|
|
408
|
-
* Optional telemetry configuration
|
|
414
|
+
* Optional telemetry configuration.
|
|
409
415
|
*/
|
|
410
|
-
|
|
416
|
+
telemetry?: TelemetryOptions;
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Optional telemetry configuration.
|
|
420
|
+
*
|
|
421
|
+
* @deprecated Use `telemetry` instead. This alias will be removed in a future major release.
|
|
422
|
+
*/
|
|
423
|
+
experimental_telemetry?: TelemetryOptions;
|
|
411
424
|
|
|
412
425
|
/**
|
|
413
426
|
* Default context that is passed into tool execution for every stream call on this agent.
|
|
@@ -434,7 +447,7 @@ export interface WorkflowAgentOptions<
|
|
|
434
447
|
*
|
|
435
448
|
* Per-stream `activeTools` values passed to `stream()` override this default.
|
|
436
449
|
*/
|
|
437
|
-
activeTools?:
|
|
450
|
+
activeTools?: ActiveTools<NoInfer<TTools>>;
|
|
438
451
|
|
|
439
452
|
/**
|
|
440
453
|
* Default output specification for structured outputs.
|
|
@@ -490,12 +503,12 @@ export interface WorkflowAgentOptions<
|
|
|
490
503
|
/**
|
|
491
504
|
* Callback called before a tool's execute function runs.
|
|
492
505
|
*/
|
|
493
|
-
|
|
506
|
+
experimental_onToolExecutionStart?: WorkflowAgentOnToolExecutionStartCallback;
|
|
494
507
|
|
|
495
508
|
/**
|
|
496
509
|
* Callback called after a tool execution completes.
|
|
497
510
|
*/
|
|
498
|
-
|
|
511
|
+
experimental_onToolExecutionEnd?: WorkflowAgentOnToolExecutionEndCallback;
|
|
499
512
|
|
|
500
513
|
/**
|
|
501
514
|
* Prepare the parameters for the stream call.
|
|
@@ -595,7 +608,7 @@ export type WorkflowAgentOnStepStartCallback<TTools extends ToolSet = ToolSet> =
|
|
|
595
608
|
/**
|
|
596
609
|
* Callback that is called before a tool's execute function runs.
|
|
597
610
|
*/
|
|
598
|
-
export type
|
|
611
|
+
export type WorkflowAgentOnToolExecutionStartCallback = (event: {
|
|
599
612
|
/** The tool call being executed */
|
|
600
613
|
readonly toolCall: ToolCall;
|
|
601
614
|
/** The current step number (0-based) */
|
|
@@ -607,7 +620,7 @@ export type WorkflowAgentOnToolCallStartCallback = (event: {
|
|
|
607
620
|
* Uses a discriminated union pattern: check `success` to determine
|
|
608
621
|
* whether `output` or `error` is available.
|
|
609
622
|
*/
|
|
610
|
-
export type
|
|
623
|
+
export type WorkflowAgentOnToolExecutionEndCallback = (
|
|
611
624
|
event:
|
|
612
625
|
| {
|
|
613
626
|
/** The tool call that was executed */
|
|
@@ -714,13 +727,6 @@ export type WorkflowAgentStreamOptions<
|
|
|
714
727
|
| StopCondition<NoInfer<ToolSet>, any>
|
|
715
728
|
| Array<StopCondition<NoInfer<ToolSet>, any>>;
|
|
716
729
|
|
|
717
|
-
/**
|
|
718
|
-
* Maximum number of sequential LLM calls (steps), e.g. when you use tool calls.
|
|
719
|
-
* A maximum number can be set to prevent infinite loops in the case of misconfigured tools.
|
|
720
|
-
* By default, it's unlimited (the agent loops until completion).
|
|
721
|
-
*/
|
|
722
|
-
maxSteps?: number;
|
|
723
|
-
|
|
724
730
|
/**
|
|
725
731
|
* The tool choice strategy. Default: 'auto'.
|
|
726
732
|
* Overrides the toolChoice from the constructor if provided.
|
|
@@ -731,12 +737,19 @@ export type WorkflowAgentStreamOptions<
|
|
|
731
737
|
* Limits the tools that are available for the model to call without
|
|
732
738
|
* changing the tool call and result types in the result.
|
|
733
739
|
*/
|
|
734
|
-
activeTools?:
|
|
740
|
+
activeTools?: ActiveTools<NoInfer<TTools>>;
|
|
741
|
+
|
|
742
|
+
/**
|
|
743
|
+
* Optional telemetry configuration.
|
|
744
|
+
*/
|
|
745
|
+
telemetry?: TelemetryOptions;
|
|
735
746
|
|
|
736
747
|
/**
|
|
737
|
-
* Optional telemetry configuration
|
|
748
|
+
* Optional telemetry configuration.
|
|
749
|
+
*
|
|
750
|
+
* @deprecated Use `telemetry` instead. This alias will be removed in a future major release.
|
|
738
751
|
*/
|
|
739
|
-
experimental_telemetry?:
|
|
752
|
+
experimental_telemetry?: TelemetryOptions;
|
|
740
753
|
|
|
741
754
|
/**
|
|
742
755
|
* Context that is passed into tool execution.
|
|
@@ -833,12 +846,12 @@ export type WorkflowAgentStreamOptions<
|
|
|
833
846
|
/**
|
|
834
847
|
* Callback called before a tool's execute function runs.
|
|
835
848
|
*/
|
|
836
|
-
|
|
849
|
+
experimental_onToolExecutionStart?: WorkflowAgentOnToolExecutionStartCallback;
|
|
837
850
|
|
|
838
851
|
/**
|
|
839
852
|
* Callback called after a tool execution completes.
|
|
840
853
|
*/
|
|
841
|
-
|
|
854
|
+
experimental_onToolExecutionEnd?: WorkflowAgentOnToolExecutionEndCallback;
|
|
842
855
|
|
|
843
856
|
/**
|
|
844
857
|
* Callback function called before each step in the agent loop.
|
|
@@ -1005,12 +1018,12 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1005
1018
|
| Array<SystemModelMessage>;
|
|
1006
1019
|
private generationSettings: GenerationSettings;
|
|
1007
1020
|
private toolChoice?: ToolChoice<TBaseTools>;
|
|
1008
|
-
private telemetry?:
|
|
1021
|
+
private telemetry?: TelemetryOptions;
|
|
1009
1022
|
private experimentalContext: unknown;
|
|
1010
1023
|
private stopWhen?:
|
|
1011
1024
|
| StopCondition<ToolSet, any>
|
|
1012
1025
|
| Array<StopCondition<ToolSet, any>>;
|
|
1013
|
-
private activeTools?:
|
|
1026
|
+
private activeTools?: ActiveTools<TBaseTools>;
|
|
1014
1027
|
private output?: OutputSpecification<any, any>;
|
|
1015
1028
|
private experimentalRepairToolCall?: ToolCallRepairFunction<TBaseTools>;
|
|
1016
1029
|
private experimentalDownload?: DownloadFunction;
|
|
@@ -1019,8 +1032,8 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1019
1032
|
private constructorOnFinish?: WorkflowAgentOnFinishCallback<ToolSet>;
|
|
1020
1033
|
private constructorOnStart?: WorkflowAgentOnStartCallback;
|
|
1021
1034
|
private constructorOnStepStart?: WorkflowAgentOnStepStartCallback;
|
|
1022
|
-
private
|
|
1023
|
-
private
|
|
1035
|
+
private constructorOnToolExecutionStart?: WorkflowAgentOnToolExecutionStartCallback;
|
|
1036
|
+
private constructorOnToolExecutionEnd?: WorkflowAgentOnToolExecutionEndCallback;
|
|
1024
1037
|
private prepareCall?: PrepareCallCallback<TBaseTools>;
|
|
1025
1038
|
|
|
1026
1039
|
constructor(options: WorkflowAgentOptions<TBaseTools>) {
|
|
@@ -1030,7 +1043,7 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1030
1043
|
// `instructions` takes precedence over deprecated `system`
|
|
1031
1044
|
this.instructions = options.instructions ?? options.system;
|
|
1032
1045
|
this.toolChoice = options.toolChoice;
|
|
1033
|
-
this.telemetry = options.experimental_telemetry;
|
|
1046
|
+
this.telemetry = options.telemetry ?? options.experimental_telemetry;
|
|
1034
1047
|
this.experimentalContext = options.experimental_context;
|
|
1035
1048
|
this.stopWhen = options.stopWhen;
|
|
1036
1049
|
this.activeTools = options.activeTools;
|
|
@@ -1042,8 +1055,10 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1042
1055
|
this.constructorOnFinish = options.onFinish;
|
|
1043
1056
|
this.constructorOnStart = options.experimental_onStart;
|
|
1044
1057
|
this.constructorOnStepStart = options.experimental_onStepStart;
|
|
1045
|
-
this.
|
|
1046
|
-
|
|
1058
|
+
this.constructorOnToolExecutionStart =
|
|
1059
|
+
options.experimental_onToolExecutionStart;
|
|
1060
|
+
this.constructorOnToolExecutionEnd =
|
|
1061
|
+
options.experimental_onToolExecutionEnd;
|
|
1047
1062
|
this.prepareCall = options.prepareCall;
|
|
1048
1063
|
|
|
1049
1064
|
// Extract generation settings
|
|
@@ -1085,7 +1100,7 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1085
1100
|
options.experimental_context ?? this.experimentalContext;
|
|
1086
1101
|
let effectiveToolChoiceFromPrepare = options.toolChoice ?? this.toolChoice;
|
|
1087
1102
|
let effectiveTelemetryFromPrepare =
|
|
1088
|
-
options.experimental_telemetry ?? this.telemetry;
|
|
1103
|
+
options.telemetry ?? options.experimental_telemetry ?? this.telemetry;
|
|
1089
1104
|
|
|
1090
1105
|
// Resolve messages for prepareCall: use messages directly, or convert prompt
|
|
1091
1106
|
const resolvedMessagesForPrepareCall: ModelMessage[] =
|
|
@@ -1101,6 +1116,7 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1101
1116
|
tools: this.tools,
|
|
1102
1117
|
instructions: effectiveInstructions,
|
|
1103
1118
|
toolChoice: effectiveToolChoiceFromPrepare as ToolChoice<TBaseTools>,
|
|
1119
|
+
telemetry: effectiveTelemetryFromPrepare,
|
|
1104
1120
|
experimental_telemetry: effectiveTelemetryFromPrepare,
|
|
1105
1121
|
experimental_context: effectiveExperimentalContext,
|
|
1106
1122
|
messages: resolvedMessagesForPrepareCall,
|
|
@@ -1119,7 +1135,9 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1119
1135
|
if (prepared.toolChoice !== undefined)
|
|
1120
1136
|
effectiveToolChoiceFromPrepare =
|
|
1121
1137
|
prepared.toolChoice as ToolChoice<TBaseTools>;
|
|
1122
|
-
if (prepared.
|
|
1138
|
+
if (prepared.telemetry !== undefined)
|
|
1139
|
+
effectiveTelemetryFromPrepare = prepared.telemetry;
|
|
1140
|
+
else if (prepared.experimental_telemetry !== undefined)
|
|
1123
1141
|
effectiveTelemetryFromPrepare = prepared.experimental_telemetry;
|
|
1124
1142
|
if (prepared.maxOutputTokens !== undefined)
|
|
1125
1143
|
effectiveGenerationSettings.maxOutputTokens = prepared.maxOutputTokens;
|
|
@@ -1146,10 +1164,11 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1146
1164
|
|
|
1147
1165
|
const prompt = await standardizePrompt({
|
|
1148
1166
|
system: effectiveInstructions,
|
|
1167
|
+
allowSystemInMessages: true, // TODO: consider exposing this as a parameter
|
|
1149
1168
|
...(effectivePrompt != null
|
|
1150
1169
|
? { prompt: effectivePrompt }
|
|
1151
1170
|
: { messages: effectiveMessages! }),
|
|
1152
|
-
});
|
|
1171
|
+
} as Prompt);
|
|
1153
1172
|
|
|
1154
1173
|
// Process tool approval responses before starting the agent loop.
|
|
1155
1174
|
// This mirrors how stream-text.ts handles tool-approval-response parts:
|
|
@@ -1282,9 +1301,7 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1282
1301
|
|
|
1283
1302
|
const effectiveAbortSignal = mergeAbortSignals(
|
|
1284
1303
|
options.abortSignal ?? effectiveGenerationSettings.abortSignal,
|
|
1285
|
-
options.timeout
|
|
1286
|
-
? AbortSignal.timeout(options.timeout)
|
|
1287
|
-
: undefined,
|
|
1304
|
+
options.timeout,
|
|
1288
1305
|
);
|
|
1289
1306
|
|
|
1290
1307
|
// Merge generation settings: constructor defaults < prepareCall < stream options
|
|
@@ -1341,13 +1358,13 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1341
1358
|
this.constructorOnStepStart,
|
|
1342
1359
|
options.experimental_onStepStart,
|
|
1343
1360
|
);
|
|
1344
|
-
const
|
|
1345
|
-
this.
|
|
1346
|
-
options.
|
|
1361
|
+
const mergedOnToolExecutionStart = mergeCallbacks(
|
|
1362
|
+
this.constructorOnToolExecutionStart,
|
|
1363
|
+
options.experimental_onToolExecutionStart,
|
|
1347
1364
|
);
|
|
1348
|
-
const
|
|
1349
|
-
this.
|
|
1350
|
-
options.
|
|
1365
|
+
const mergedOnToolExecutionEnd = mergeCallbacks(
|
|
1366
|
+
this.constructorOnToolExecutionEnd,
|
|
1367
|
+
options.experimental_onToolExecutionEnd,
|
|
1351
1368
|
);
|
|
1352
1369
|
|
|
1353
1370
|
// Determine effective tool choice
|
|
@@ -1360,7 +1377,10 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1360
1377
|
const effectiveActiveTools = options.activeTools ?? this.activeTools;
|
|
1361
1378
|
const effectiveTools =
|
|
1362
1379
|
effectiveActiveTools && effectiveActiveTools.length > 0
|
|
1363
|
-
?
|
|
1380
|
+
? (filterActiveTools({
|
|
1381
|
+
tools: this.tools,
|
|
1382
|
+
activeTools: effectiveActiveTools,
|
|
1383
|
+
}) ?? this.tools)
|
|
1364
1384
|
: this.tools;
|
|
1365
1385
|
|
|
1366
1386
|
// Initialize context
|
|
@@ -1380,7 +1400,7 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1380
1400
|
});
|
|
1381
1401
|
}
|
|
1382
1402
|
|
|
1383
|
-
// Helper to wrap executeTool with
|
|
1403
|
+
// Helper to wrap executeTool with onToolExecutionStart/onToolExecutionEnd callbacks
|
|
1384
1404
|
const executeToolWithCallbacks = async (
|
|
1385
1405
|
toolCall: { toolCallId: string; toolName: string; input: unknown },
|
|
1386
1406
|
tools: ToolSet,
|
|
@@ -1395,8 +1415,8 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1395
1415
|
input: toolCall.input,
|
|
1396
1416
|
};
|
|
1397
1417
|
|
|
1398
|
-
if (
|
|
1399
|
-
await
|
|
1418
|
+
if (mergedOnToolExecutionStart) {
|
|
1419
|
+
await mergedOnToolExecutionStart({
|
|
1400
1420
|
toolCall: toolCallEvent,
|
|
1401
1421
|
stepNumber: currentStepNumber,
|
|
1402
1422
|
});
|
|
@@ -1408,8 +1428,8 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1408
1428
|
result = await executeTool(toolCall, tools, messages, context);
|
|
1409
1429
|
} catch (err) {
|
|
1410
1430
|
const durationMs = Date.now() - startTime;
|
|
1411
|
-
if (
|
|
1412
|
-
await
|
|
1431
|
+
if (mergedOnToolExecutionEnd) {
|
|
1432
|
+
await mergedOnToolExecutionEnd({
|
|
1413
1433
|
toolCall: toolCallEvent,
|
|
1414
1434
|
stepNumber: currentStepNumber,
|
|
1415
1435
|
durationMs,
|
|
@@ -1421,14 +1441,14 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1421
1441
|
}
|
|
1422
1442
|
|
|
1423
1443
|
const durationMs = Date.now() - startTime;
|
|
1424
|
-
if (
|
|
1444
|
+
if (mergedOnToolExecutionEnd) {
|
|
1425
1445
|
const isError =
|
|
1426
1446
|
result.output &&
|
|
1427
1447
|
'type' in result.output &&
|
|
1428
1448
|
(result.output.type === 'error-text' ||
|
|
1429
1449
|
result.output.type === 'error-json');
|
|
1430
1450
|
if (isError) {
|
|
1431
|
-
await
|
|
1451
|
+
await mergedOnToolExecutionEnd({
|
|
1432
1452
|
toolCall: toolCallEvent,
|
|
1433
1453
|
stepNumber: currentStepNumber,
|
|
1434
1454
|
durationMs,
|
|
@@ -1436,7 +1456,7 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1436
1456
|
error: 'value' in result.output ? result.output.value : undefined,
|
|
1437
1457
|
});
|
|
1438
1458
|
} else {
|
|
1439
|
-
await
|
|
1459
|
+
await mergedOnToolExecutionEnd({
|
|
1440
1460
|
toolCall: toolCallEvent,
|
|
1441
1461
|
stepNumber: currentStepNumber,
|
|
1442
1462
|
durationMs,
|
|
@@ -1471,7 +1491,7 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1471
1491
|
writable: options.writable,
|
|
1472
1492
|
prompt: modelPrompt,
|
|
1473
1493
|
stopConditions: options.stopWhen ?? this.stopWhen,
|
|
1474
|
-
|
|
1494
|
+
|
|
1475
1495
|
onStepFinish: mergedOnStepFinish,
|
|
1476
1496
|
onStepStart: mergedOnStepStart,
|
|
1477
1497
|
onError: options.onError,
|
|
@@ -1481,7 +1501,7 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1481
1501
|
generationSettings: mergedGenerationSettings,
|
|
1482
1502
|
toolChoice: effectiveToolChoice as ToolChoice<ToolSet>,
|
|
1483
1503
|
experimental_context: experimentalContext,
|
|
1484
|
-
|
|
1504
|
+
telemetry: effectiveTelemetry,
|
|
1485
1505
|
includeRawChunks: options.includeRawChunks ?? false,
|
|
1486
1506
|
repairToolCall: (options.experimental_repairToolCall ??
|
|
1487
1507
|
this.experimentalRepairToolCall) as
|
|
@@ -1525,11 +1545,16 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1525
1545
|
|
|
1526
1546
|
// Only execute tools if there are tool calls
|
|
1527
1547
|
if (toolCalls.length > 0) {
|
|
1548
|
+
const invalidToolCalls = toolCalls.filter(tc => tc.invalid === true);
|
|
1549
|
+
const validToolCalls = toolCalls.filter(tc => tc.invalid !== true);
|
|
1550
|
+
|
|
1528
1551
|
// Separate provider-executed tool calls from client-executed ones
|
|
1529
|
-
const nonProviderToolCalls =
|
|
1552
|
+
const nonProviderToolCalls = validToolCalls.filter(
|
|
1530
1553
|
tc => !tc.providerExecuted,
|
|
1531
1554
|
);
|
|
1532
|
-
const providerToolCalls =
|
|
1555
|
+
const providerToolCalls = validToolCalls.filter(
|
|
1556
|
+
tc => tc.providerExecuted,
|
|
1557
|
+
);
|
|
1533
1558
|
|
|
1534
1559
|
// Check which tools need approval (can be async)
|
|
1535
1560
|
const approvalNeeded = await Promise.all(
|
|
@@ -1593,7 +1618,15 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1593
1618
|
),
|
|
1594
1619
|
);
|
|
1595
1620
|
|
|
1596
|
-
const
|
|
1621
|
+
const continuationInvalidResults = invalidToolCalls.map(
|
|
1622
|
+
createInvalidToolResult,
|
|
1623
|
+
);
|
|
1624
|
+
const resolvedResults = [
|
|
1625
|
+
...executableResults,
|
|
1626
|
+
...providerResults,
|
|
1627
|
+
...continuationInvalidResults,
|
|
1628
|
+
];
|
|
1629
|
+
const executedResults = [...executableResults, ...providerResults];
|
|
1597
1630
|
|
|
1598
1631
|
const allToolCalls: ToolCall[] = toolCalls.map(tc => ({
|
|
1599
1632
|
type: 'tool-call' as const,
|
|
@@ -1602,7 +1635,7 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1602
1635
|
input: tc.input,
|
|
1603
1636
|
}));
|
|
1604
1637
|
|
|
1605
|
-
const allToolResults: ToolResult[] =
|
|
1638
|
+
const allToolResults: ToolResult[] = executedResults.map(r => ({
|
|
1606
1639
|
type: 'tool-result' as const,
|
|
1607
1640
|
toolCallId: r.toolCallId,
|
|
1608
1641
|
toolName: r.toolName,
|
|
@@ -1690,25 +1723,32 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1690
1723
|
providerToolCalls.map(toolCall =>
|
|
1691
1724
|
resolveProviderToolResult(toolCall, providerExecutedToolResults),
|
|
1692
1725
|
);
|
|
1726
|
+
const continuationInvalidToolResults = invalidToolCalls.map(
|
|
1727
|
+
createInvalidToolResult,
|
|
1728
|
+
);
|
|
1693
1729
|
|
|
1694
|
-
// Combine results in the original order
|
|
1695
|
-
|
|
1730
|
+
// Combine executable/provider results in the original order,
|
|
1731
|
+
// while preserving invalid tool calls as error results for the
|
|
1732
|
+
// next model step without emitting them as synthetic UI success.
|
|
1733
|
+
const continuationToolResults = toolCalls.flatMap(tc => {
|
|
1734
|
+
const invalidResult = continuationInvalidToolResults.find(
|
|
1735
|
+
r => r.toolCallId === tc.toolCallId,
|
|
1736
|
+
);
|
|
1737
|
+
if (invalidResult) return [invalidResult];
|
|
1696
1738
|
const clientResult = clientToolResults.find(
|
|
1697
1739
|
r => r.toolCallId === tc.toolCallId,
|
|
1698
1740
|
);
|
|
1699
|
-
if (clientResult) return clientResult;
|
|
1741
|
+
if (clientResult) return [clientResult];
|
|
1700
1742
|
const providerResult = providerToolResults.find(
|
|
1701
1743
|
r => r.toolCallId === tc.toolCallId,
|
|
1702
1744
|
);
|
|
1703
|
-
if (providerResult) return providerResult;
|
|
1704
|
-
|
|
1705
|
-
return {
|
|
1706
|
-
type: 'tool-result' as const,
|
|
1707
|
-
toolCallId: tc.toolCallId,
|
|
1708
|
-
toolName: tc.toolName,
|
|
1709
|
-
output: { type: 'text' as const, value: '' },
|
|
1710
|
-
};
|
|
1745
|
+
if (providerResult) return [providerResult];
|
|
1746
|
+
return [];
|
|
1711
1747
|
});
|
|
1748
|
+
const executedToolResults = continuationToolResults.filter(
|
|
1749
|
+
result =>
|
|
1750
|
+
!invalidToolCalls.some(tc => tc.toolCallId === result.toolCallId),
|
|
1751
|
+
);
|
|
1712
1752
|
|
|
1713
1753
|
// Write tool results and step boundaries to the stream so the
|
|
1714
1754
|
// UI can transition tool parts to output-available state and
|
|
@@ -1716,7 +1756,7 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1716
1756
|
if (options.writable) {
|
|
1717
1757
|
await writeToolResultsWithStepBoundary(
|
|
1718
1758
|
options.writable,
|
|
1719
|
-
|
|
1759
|
+
executedToolResults.map(r => ({
|
|
1720
1760
|
toolCallId: r.toolCallId,
|
|
1721
1761
|
toolName: r.toolName,
|
|
1722
1762
|
input: toolCalls.find(tc => tc.toolCallId === r.toolCallId)
|
|
@@ -1733,7 +1773,7 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1733
1773
|
toolName: tc.toolName,
|
|
1734
1774
|
input: tc.input,
|
|
1735
1775
|
}));
|
|
1736
|
-
lastStepToolResults =
|
|
1776
|
+
lastStepToolResults = executedToolResults.map(r => ({
|
|
1737
1777
|
type: 'tool-result' as const,
|
|
1738
1778
|
toolCallId: r.toolCallId,
|
|
1739
1779
|
toolName: r.toolName,
|
|
@@ -1741,7 +1781,7 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1741
1781
|
output: 'value' in r.output ? r.output.value : undefined,
|
|
1742
1782
|
}));
|
|
1743
1783
|
|
|
1744
|
-
result = await iterator.next(
|
|
1784
|
+
result = await iterator.next(continuationToolResults);
|
|
1745
1785
|
} else {
|
|
1746
1786
|
// Final step with no tool calls - reset tracking
|
|
1747
1787
|
lastStepToolCalls = [];
|
|
@@ -1979,19 +2019,6 @@ function aggregateUsage(steps: StepResult<any, any>[]): LanguageModelUsage {
|
|
|
1979
2019
|
} as LanguageModelUsage;
|
|
1980
2020
|
}
|
|
1981
2021
|
|
|
1982
|
-
function filterTools<TTools extends ToolSet>(
|
|
1983
|
-
tools: TTools,
|
|
1984
|
-
activeTools: string[],
|
|
1985
|
-
): ToolSet {
|
|
1986
|
-
const filtered: ToolSet = {};
|
|
1987
|
-
for (const toolName of activeTools) {
|
|
1988
|
-
if (toolName in tools) {
|
|
1989
|
-
filtered[toolName] = tools[toolName];
|
|
1990
|
-
}
|
|
1991
|
-
}
|
|
1992
|
-
return filtered;
|
|
1993
|
-
}
|
|
1994
|
-
|
|
1995
2022
|
// Matches AI SDK's getErrorMessage from @ai-sdk/provider-utils
|
|
1996
2023
|
function getErrorMessage(error: unknown): string {
|
|
1997
2024
|
if (error == null) {
|
|
@@ -2056,6 +2083,22 @@ function resolveProviderToolResult(
|
|
|
2056
2083
|
};
|
|
2057
2084
|
}
|
|
2058
2085
|
|
|
2086
|
+
function createInvalidToolResult(toolCall: {
|
|
2087
|
+
toolCallId: string;
|
|
2088
|
+
toolName: string;
|
|
2089
|
+
error?: unknown;
|
|
2090
|
+
}): LanguageModelV4ToolResultPart {
|
|
2091
|
+
return {
|
|
2092
|
+
type: 'tool-result' as const,
|
|
2093
|
+
toolCallId: toolCall.toolCallId,
|
|
2094
|
+
toolName: toolCall.toolName,
|
|
2095
|
+
output: {
|
|
2096
|
+
type: 'error-text' as const,
|
|
2097
|
+
value: getErrorMessage(toolCall.error),
|
|
2098
|
+
},
|
|
2099
|
+
};
|
|
2100
|
+
}
|
|
2101
|
+
|
|
2059
2102
|
async function executeTool(
|
|
2060
2103
|
toolCall: { toolCallId: string; toolName: string; input: unknown },
|
|
2061
2104
|
tools: ToolSet,
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
|
+
parseJsonEventStream,
|
|
3
|
+
uiMessageChunkSchema,
|
|
2
4
|
type ChatRequestOptions,
|
|
3
5
|
type ChatTransport,
|
|
4
6
|
type PrepareReconnectToStreamRequest,
|
|
5
7
|
type PrepareSendMessagesRequest,
|
|
6
|
-
parseJsonEventStream,
|
|
7
8
|
type UIMessage,
|
|
8
9
|
type UIMessageChunk,
|
|
9
|
-
uiMessageChunkSchema,
|
|
10
10
|
} from 'ai';
|
|
11
11
|
import {
|
|
12
12
|
convertAsyncIteratorToReadableStream,
|