@ai-sdk/workflow 2.0.20 → 2.0.21
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 +12 -0
- package/dist/index.d.ts +7 -6
- package/dist/index.js +480 -106
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/do-stream-step.ts +165 -12
- package/src/resolve-tool-context.ts +28 -0
- package/src/serializable-schema.ts +99 -30
- package/src/stream-text-iterator.ts +273 -51
- package/src/workflow-agent.ts +153 -78
package/src/workflow-agent.ts
CHANGED
|
@@ -8,7 +8,6 @@ import type {
|
|
|
8
8
|
import {
|
|
9
9
|
getErrorMessage,
|
|
10
10
|
isAbortError,
|
|
11
|
-
validateTypes,
|
|
12
11
|
withUserAgentSuffix,
|
|
13
12
|
type Context,
|
|
14
13
|
type HasRequiredKey,
|
|
@@ -53,6 +52,7 @@ import type {
|
|
|
53
52
|
ModelCallStreamPart,
|
|
54
53
|
ModelStopCondition,
|
|
55
54
|
} from './do-stream-step.js';
|
|
55
|
+
import { resolveToolContext } from './resolve-tool-context.js';
|
|
56
56
|
import { streamTextIterator } from './stream-text-iterator.js';
|
|
57
57
|
|
|
58
58
|
// Re-export for consumers
|
|
@@ -83,7 +83,9 @@ export type WorkflowAgentOnStepFinishCallback<
|
|
|
83
83
|
* Infer the type of the tools of a workflow agent.
|
|
84
84
|
*/
|
|
85
85
|
export type InferWorkflowAgentTools<WORKFLOW_AGENT> =
|
|
86
|
-
WORKFLOW_AGENT extends WorkflowAgent<infer TOOLS, any
|
|
86
|
+
WORKFLOW_AGENT extends WorkflowAgent<infer TOOLS, any, any, any>
|
|
87
|
+
? TOOLS
|
|
88
|
+
: never;
|
|
87
89
|
|
|
88
90
|
/**
|
|
89
91
|
* Infer the UI message type of a workflow agent.
|
|
@@ -123,6 +125,8 @@ export interface OutputSpecification<OUTPUT, PARTIAL> {
|
|
|
123
125
|
): Promise<OUTPUT>;
|
|
124
126
|
}
|
|
125
127
|
|
|
128
|
+
type DefaultWorkflowAgentOutput<OUTPUT> = 0 extends 1 & OUTPUT ? never : OUTPUT;
|
|
129
|
+
|
|
126
130
|
/**
|
|
127
131
|
* Provider-specific options type. This is equivalent to SharedV4ProviderOptions from @ai-sdk/provider.
|
|
128
132
|
*/
|
|
@@ -450,6 +454,8 @@ export type PrepareCallCallback<
|
|
|
450
454
|
export type WorkflowAgentOptions<
|
|
451
455
|
TTools extends ToolSet = ToolSet,
|
|
452
456
|
TRuntimeContext extends Context = Context,
|
|
457
|
+
OUTPUT = any,
|
|
458
|
+
PARTIAL_OUTPUT = any,
|
|
453
459
|
> = GenerationSettings &
|
|
454
460
|
WorkflowAgentToolsContextParameter<TTools> & {
|
|
455
461
|
/**
|
|
@@ -533,7 +539,7 @@ export type WorkflowAgentOptions<
|
|
|
533
539
|
*
|
|
534
540
|
* Per-stream `output` values passed to `stream()` override this default.
|
|
535
541
|
*/
|
|
536
|
-
output?: OutputSpecification<
|
|
542
|
+
output?: OutputSpecification<OUTPUT, PARTIAL_OUTPUT>;
|
|
537
543
|
|
|
538
544
|
/**
|
|
539
545
|
* Default function that attempts to repair a tool call that failed to parse.
|
|
@@ -1216,6 +1222,64 @@ type WorkflowToolExecutionResult = {
|
|
|
1216
1222
|
isError: boolean;
|
|
1217
1223
|
};
|
|
1218
1224
|
|
|
1225
|
+
function addToolResultsToStep(
|
|
1226
|
+
step: StepResult<ToolSet, any> | undefined,
|
|
1227
|
+
executedResults: WorkflowToolExecutionResult[],
|
|
1228
|
+
) {
|
|
1229
|
+
if (step == null || executedResults.length === 0) {
|
|
1230
|
+
return;
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
const toolOutputs = executedResults.map(result => {
|
|
1234
|
+
const toolCall = step.toolCalls.find(
|
|
1235
|
+
toolCall => toolCall.toolCallId === result.modelResult.toolCallId,
|
|
1236
|
+
);
|
|
1237
|
+
|
|
1238
|
+
const common = {
|
|
1239
|
+
toolCallId: result.modelResult.toolCallId,
|
|
1240
|
+
toolName: result.modelResult.toolName,
|
|
1241
|
+
input: toolCall?.input,
|
|
1242
|
+
...(toolCall?.dynamic === true ? { dynamic: true as const } : {}),
|
|
1243
|
+
...(toolCall?.providerExecuted === true
|
|
1244
|
+
? { providerExecuted: true }
|
|
1245
|
+
: {}),
|
|
1246
|
+
};
|
|
1247
|
+
|
|
1248
|
+
return result.isError
|
|
1249
|
+
? {
|
|
1250
|
+
type: 'tool-error' as const,
|
|
1251
|
+
...common,
|
|
1252
|
+
error: result.rawOutput,
|
|
1253
|
+
}
|
|
1254
|
+
: {
|
|
1255
|
+
type: 'tool-result' as const,
|
|
1256
|
+
...common,
|
|
1257
|
+
output: result.rawOutput,
|
|
1258
|
+
};
|
|
1259
|
+
});
|
|
1260
|
+
|
|
1261
|
+
step.content.push(...(toolOutputs as StepResult<ToolSet, any>['content']));
|
|
1262
|
+
|
|
1263
|
+
const toolResults = toolOutputs.filter(
|
|
1264
|
+
result => result.type === 'tool-result',
|
|
1265
|
+
);
|
|
1266
|
+
step.toolResults.push(
|
|
1267
|
+
...(toolResults as StepResult<ToolSet, any>['toolResults']),
|
|
1268
|
+
);
|
|
1269
|
+
step.staticToolResults.push(
|
|
1270
|
+
...(toolResults.filter(result => result.dynamic !== true) as StepResult<
|
|
1271
|
+
ToolSet,
|
|
1272
|
+
any
|
|
1273
|
+
>['staticToolResults']),
|
|
1274
|
+
);
|
|
1275
|
+
step.dynamicToolResults.push(
|
|
1276
|
+
...(toolResults.filter(result => result.dynamic === true) as StepResult<
|
|
1277
|
+
ToolSet,
|
|
1278
|
+
any
|
|
1279
|
+
>['dynamicToolResults']),
|
|
1280
|
+
);
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1219
1283
|
/**
|
|
1220
1284
|
* Result of the WorkflowAgent.stream method.
|
|
1221
1285
|
*/
|
|
@@ -1316,6 +1380,8 @@ export interface WorkflowAgentStreamResult<
|
|
|
1316
1380
|
export class WorkflowAgent<
|
|
1317
1381
|
TBaseTools extends ToolSet = ToolSet,
|
|
1318
1382
|
TRuntimeContext extends Context = Context,
|
|
1383
|
+
OUTPUT = any,
|
|
1384
|
+
PARTIAL_OUTPUT = any,
|
|
1319
1385
|
> {
|
|
1320
1386
|
/**
|
|
1321
1387
|
* The id of the agent.
|
|
@@ -1337,7 +1403,7 @@ export class WorkflowAgent<
|
|
|
1337
1403
|
| StopCondition<TBaseTools, TRuntimeContext>
|
|
1338
1404
|
| Array<StopCondition<TBaseTools, TRuntimeContext>>;
|
|
1339
1405
|
private activeTools?: ActiveTools<TBaseTools>;
|
|
1340
|
-
private output?: OutputSpecification<
|
|
1406
|
+
private output?: OutputSpecification<OUTPUT, PARTIAL_OUTPUT>;
|
|
1341
1407
|
private repairToolCall?: ToolCallRepairFunction<TBaseTools>;
|
|
1342
1408
|
private experimentalDownload?: DownloadFunction;
|
|
1343
1409
|
private experimentalSandbox?: SandboxSession;
|
|
@@ -1364,7 +1430,14 @@ export class WorkflowAgent<
|
|
|
1364
1430
|
private constructorOnToolExecutionEnd?: WorkflowAgentOnToolExecutionEndCallback<TBaseTools>;
|
|
1365
1431
|
private prepareCall?: PrepareCallCallback<TBaseTools, TRuntimeContext>;
|
|
1366
1432
|
|
|
1367
|
-
constructor(
|
|
1433
|
+
constructor(
|
|
1434
|
+
options: WorkflowAgentOptions<
|
|
1435
|
+
TBaseTools,
|
|
1436
|
+
TRuntimeContext,
|
|
1437
|
+
OUTPUT,
|
|
1438
|
+
PARTIAL_OUTPUT
|
|
1439
|
+
>,
|
|
1440
|
+
) {
|
|
1368
1441
|
this.id = options.id;
|
|
1369
1442
|
this.model = options.model;
|
|
1370
1443
|
this.tools = (options.tools ?? {}) as TBaseTools;
|
|
@@ -1419,16 +1492,16 @@ export class WorkflowAgent<
|
|
|
1419
1492
|
|
|
1420
1493
|
async stream<
|
|
1421
1494
|
TTools extends TBaseTools = TBaseTools,
|
|
1422
|
-
|
|
1423
|
-
|
|
1495
|
+
TOutput = DefaultWorkflowAgentOutput<OUTPUT>,
|
|
1496
|
+
TPartialOutput = DefaultWorkflowAgentOutput<PARTIAL_OUTPUT>,
|
|
1424
1497
|
>(
|
|
1425
1498
|
options: WorkflowAgentStreamOptions<
|
|
1426
1499
|
TTools,
|
|
1427
1500
|
TRuntimeContext,
|
|
1428
|
-
|
|
1429
|
-
|
|
1501
|
+
TOutput,
|
|
1502
|
+
TPartialOutput
|
|
1430
1503
|
>,
|
|
1431
|
-
): Promise<WorkflowAgentStreamResult<TTools,
|
|
1504
|
+
): Promise<WorkflowAgentStreamResult<TTools, TOutput>> {
|
|
1432
1505
|
const { onFinish, onEnd = onFinish } = options;
|
|
1433
1506
|
|
|
1434
1507
|
// Call prepareCall to transform parameters before the agent loop
|
|
@@ -1872,7 +1945,7 @@ export class WorkflowAgent<
|
|
|
1872
1945
|
);
|
|
1873
1946
|
const mergedOnEnd = mergeCallbacks(
|
|
1874
1947
|
this.constructorOnEnd as
|
|
1875
|
-
| WorkflowAgentOnEndCallback<TTools, TRuntimeContext,
|
|
1948
|
+
| WorkflowAgentOnEndCallback<TTools, TRuntimeContext, TOutput>
|
|
1876
1949
|
| undefined,
|
|
1877
1950
|
onEnd,
|
|
1878
1951
|
);
|
|
@@ -2152,7 +2225,7 @@ export class WorkflowAgent<
|
|
|
2152
2225
|
toolResults: [],
|
|
2153
2226
|
finishReason: 'other',
|
|
2154
2227
|
totalUsage: aggregateUsage(steps),
|
|
2155
|
-
output: undefined as
|
|
2228
|
+
output: undefined as TOutput,
|
|
2156
2229
|
};
|
|
2157
2230
|
}
|
|
2158
2231
|
|
|
@@ -2303,27 +2376,34 @@ export class WorkflowAgent<
|
|
|
2303
2376
|
);
|
|
2304
2377
|
|
|
2305
2378
|
// Collect provider tool results
|
|
2306
|
-
const
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
toolCall,
|
|
2311
|
-
providerExecutedToolResults,
|
|
2312
|
-
effectiveTools as ToolSet,
|
|
2313
|
-
download,
|
|
2314
|
-
),
|
|
2315
|
-
),
|
|
2316
|
-
);
|
|
2317
|
-
await Promise.all(
|
|
2318
|
-
providerToolCalls.map((toolCall, index) =>
|
|
2319
|
-
recordProviderExecutedToolTelemetry(
|
|
2379
|
+
const providerResultEntries = await Promise.all(
|
|
2380
|
+
providerToolCalls.map(async toolCall => ({
|
|
2381
|
+
toolCall,
|
|
2382
|
+
result: await resolveProviderToolResult(
|
|
2320
2383
|
toolCall,
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2384
|
+
providerExecutedToolResults,
|
|
2385
|
+
effectiveTools as ToolSet,
|
|
2386
|
+
download,
|
|
2324
2387
|
),
|
|
2388
|
+
})),
|
|
2389
|
+
);
|
|
2390
|
+
await Promise.all(
|
|
2391
|
+
providerResultEntries.flatMap(({ toolCall, result }) =>
|
|
2392
|
+
result == null
|
|
2393
|
+
? []
|
|
2394
|
+
: [
|
|
2395
|
+
recordProviderExecutedToolTelemetry(
|
|
2396
|
+
toolCall,
|
|
2397
|
+
result,
|
|
2398
|
+
iterMessages,
|
|
2399
|
+
currentStepNumber,
|
|
2400
|
+
),
|
|
2401
|
+
],
|
|
2325
2402
|
),
|
|
2326
2403
|
);
|
|
2404
|
+
const providerResults = providerResultEntries.flatMap(
|
|
2405
|
+
({ result }) => (result == null ? [] : [result]),
|
|
2406
|
+
);
|
|
2327
2407
|
|
|
2328
2408
|
const continuationInvalidResults = invalidToolCalls.map(
|
|
2329
2409
|
createInvalidToolResult,
|
|
@@ -2352,6 +2432,8 @@ export class WorkflowAgent<
|
|
|
2352
2432
|
output: r.rawOutput,
|
|
2353
2433
|
}));
|
|
2354
2434
|
|
|
2435
|
+
addToolResultsToStep(step, executedResults);
|
|
2436
|
+
|
|
2355
2437
|
if (resolvedResults.length > 0) {
|
|
2356
2438
|
iterMessages.push({
|
|
2357
2439
|
role: 'tool',
|
|
@@ -2375,7 +2457,7 @@ export class WorkflowAgent<
|
|
|
2375
2457
|
runtimeContext,
|
|
2376
2458
|
toolsContext:
|
|
2377
2459
|
toolsContext as unknown as InferToolSetContext<TTools>,
|
|
2378
|
-
output: undefined as
|
|
2460
|
+
output: undefined as TOutput,
|
|
2379
2461
|
});
|
|
2380
2462
|
}
|
|
2381
2463
|
if (!wasAborted && steps.length > 0) {
|
|
@@ -2459,7 +2541,7 @@ export class WorkflowAgent<
|
|
|
2459
2541
|
toolResults: allToolResults,
|
|
2460
2542
|
finishReason,
|
|
2461
2543
|
totalUsage,
|
|
2462
|
-
output: undefined as
|
|
2544
|
+
output: undefined as TOutput,
|
|
2463
2545
|
};
|
|
2464
2546
|
}
|
|
2465
2547
|
|
|
@@ -2479,27 +2561,34 @@ export class WorkflowAgent<
|
|
|
2479
2561
|
);
|
|
2480
2562
|
|
|
2481
2563
|
// For provider-executed tools, use the results from the stream
|
|
2482
|
-
const
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
toolCall,
|
|
2487
|
-
providerExecutedToolResults,
|
|
2488
|
-
effectiveTools as ToolSet,
|
|
2489
|
-
download,
|
|
2490
|
-
),
|
|
2491
|
-
),
|
|
2492
|
-
);
|
|
2493
|
-
await Promise.all(
|
|
2494
|
-
providerToolCalls.map((toolCall, index) =>
|
|
2495
|
-
recordProviderExecutedToolTelemetry(
|
|
2564
|
+
const providerToolResultEntries = await Promise.all(
|
|
2565
|
+
providerToolCalls.map(async toolCall => ({
|
|
2566
|
+
toolCall,
|
|
2567
|
+
result: await resolveProviderToolResult(
|
|
2496
2568
|
toolCall,
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2569
|
+
providerExecutedToolResults,
|
|
2570
|
+
effectiveTools as ToolSet,
|
|
2571
|
+
download,
|
|
2500
2572
|
),
|
|
2573
|
+
})),
|
|
2574
|
+
);
|
|
2575
|
+
await Promise.all(
|
|
2576
|
+
providerToolResultEntries.flatMap(({ toolCall, result }) =>
|
|
2577
|
+
result == null
|
|
2578
|
+
? []
|
|
2579
|
+
: [
|
|
2580
|
+
recordProviderExecutedToolTelemetry(
|
|
2581
|
+
toolCall,
|
|
2582
|
+
result,
|
|
2583
|
+
iterMessages,
|
|
2584
|
+
currentStepNumber,
|
|
2585
|
+
),
|
|
2586
|
+
],
|
|
2501
2587
|
),
|
|
2502
2588
|
);
|
|
2589
|
+
const providerToolResults = providerToolResultEntries.flatMap(
|
|
2590
|
+
({ result }) => (result == null ? [] : [result]),
|
|
2591
|
+
);
|
|
2503
2592
|
const continuationInvalidToolResults = invalidToolCalls.map(
|
|
2504
2593
|
createInvalidToolResult,
|
|
2505
2594
|
);
|
|
@@ -2566,6 +2655,8 @@ export class WorkflowAgent<
|
|
|
2566
2655
|
output: r.rawOutput,
|
|
2567
2656
|
}));
|
|
2568
2657
|
|
|
2658
|
+
addToolResultsToStep(step, executedToolResults);
|
|
2659
|
+
|
|
2569
2660
|
result = await iterator.next(continuationToolResults);
|
|
2570
2661
|
} else {
|
|
2571
2662
|
// Final step with no tool calls - reset tracking
|
|
@@ -2622,8 +2713,10 @@ export class WorkflowAgent<
|
|
|
2622
2713
|
prompt.messages) as unknown as ModelMessage[];
|
|
2623
2714
|
|
|
2624
2715
|
// Parse structured output if output is specified (stream-level overrides constructor default)
|
|
2625
|
-
const effectiveOutput = options.output ?? this.output
|
|
2626
|
-
|
|
2716
|
+
const effectiveOutput = (options.output ?? this.output) as
|
|
2717
|
+
| OutputSpecification<TOutput, TPartialOutput>
|
|
2718
|
+
| undefined;
|
|
2719
|
+
let experimentalOutput: TOutput = undefined as TOutput;
|
|
2627
2720
|
if (effectiveOutput && steps.length > 0) {
|
|
2628
2721
|
const lastStep = steps[steps.length - 1];
|
|
2629
2722
|
const text = lastStep.text;
|
|
@@ -2980,33 +3073,6 @@ async function writeApprovalToolResults(
|
|
|
2980
3073
|
}
|
|
2981
3074
|
}
|
|
2982
3075
|
|
|
2983
|
-
/**
|
|
2984
|
-
* Resolve the per-tool context that gets passed into a tool's `execute`
|
|
2985
|
-
* (and `needsApproval`) function. When the tool declares a `contextSchema`,
|
|
2986
|
-
* the entry is validated against it.
|
|
2987
|
-
*/
|
|
2988
|
-
async function resolveToolContext({
|
|
2989
|
-
toolName,
|
|
2990
|
-
tool,
|
|
2991
|
-
toolsContext,
|
|
2992
|
-
}: {
|
|
2993
|
-
toolName: string;
|
|
2994
|
-
tool: ToolSet[string];
|
|
2995
|
-
toolsContext: Record<string, Context | undefined> | undefined;
|
|
2996
|
-
}): Promise<unknown> {
|
|
2997
|
-
const contextSchema = (tool as { contextSchema?: unknown }).contextSchema;
|
|
2998
|
-
const entry = toolsContext?.[toolName];
|
|
2999
|
-
if (contextSchema == null) {
|
|
3000
|
-
return entry;
|
|
3001
|
-
}
|
|
3002
|
-
|
|
3003
|
-
return await validateTypes({
|
|
3004
|
-
value: entry,
|
|
3005
|
-
schema: contextSchema as Parameters<typeof validateTypes>[0]['schema'],
|
|
3006
|
-
context: { field: 'tool context', entityName: toolName },
|
|
3007
|
-
});
|
|
3008
|
-
}
|
|
3009
|
-
|
|
3010
3076
|
function aggregateUsage(steps: StepResult<any, any>[]): LanguageModelUsage {
|
|
3011
3077
|
let inputTokens = 0;
|
|
3012
3078
|
let outputTokens = 0;
|
|
@@ -3029,9 +3095,18 @@ async function resolveProviderToolResult(
|
|
|
3029
3095
|
>,
|
|
3030
3096
|
tools?: ToolSet,
|
|
3031
3097
|
download?: DownloadFunction,
|
|
3032
|
-
): Promise<WorkflowToolExecutionResult> {
|
|
3098
|
+
): Promise<WorkflowToolExecutionResult | undefined> {
|
|
3033
3099
|
const streamResult = providerExecutedToolResults?.get(toolCall.toolCallId);
|
|
3034
3100
|
if (!streamResult) {
|
|
3101
|
+
const tool = tools?.[toolCall.toolName];
|
|
3102
|
+
if (
|
|
3103
|
+
tool?.type === 'provider' &&
|
|
3104
|
+
tool.isProviderExecuted &&
|
|
3105
|
+
tool.supportsDeferredResults
|
|
3106
|
+
) {
|
|
3107
|
+
return undefined;
|
|
3108
|
+
}
|
|
3109
|
+
|
|
3035
3110
|
console.warn(
|
|
3036
3111
|
`[WorkflowAgent] Provider-executed tool "${toolCall.toolName}" (${toolCall.toolCallId}) ` +
|
|
3037
3112
|
`did not receive a result from the stream. This may indicate a provider issue.`,
|