@ai-sdk/workflow 2.0.59 → 2.0.61
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 +28 -0
- package/README.md +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +42 -38
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
- package/src/build-model-step-result.ts +18 -10
- package/src/do-stream-step.ts +4 -0
- package/src/model-call.ts +8 -0
- package/src/serializable-schema.ts +33 -26
- package/src/workflow-agent.ts +12 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-sdk/workflow",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.61",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "WorkflowAgent for building AI agents with AI SDK",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -36,9 +36,9 @@
|
|
|
36
36
|
}
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@ai-sdk/provider": "4.0.
|
|
40
|
-
"@ai-sdk/provider-utils": "5.0.
|
|
41
|
-
"ai": "7.0.
|
|
39
|
+
"@ai-sdk/provider": "4.0.23",
|
|
40
|
+
"@ai-sdk/provider-utils": "5.0.55",
|
|
41
|
+
"ai": "7.0.129",
|
|
42
42
|
"ajv": "^8.20.0"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"@vercel/ai-tsconfig": "0.0.0",
|
|
47
47
|
"@workflow/vitest": "5.0.0-beta.42",
|
|
48
48
|
"tsdown": "^0.23.0",
|
|
49
|
-
"typescript": "
|
|
49
|
+
"typescript": "6.0.3",
|
|
50
50
|
"vitest": "4.1.6",
|
|
51
51
|
"workflow": "5.0.0-beta.42",
|
|
52
52
|
"zod": "4.4.3"
|
|
@@ -105,6 +105,7 @@ export async function buildModelStepResult(
|
|
|
105
105
|
const {
|
|
106
106
|
content: rawContent,
|
|
107
107
|
reasoning: reasoningParts,
|
|
108
|
+
performance: modelCallPerformance,
|
|
108
109
|
responseMetadata,
|
|
109
110
|
warnings,
|
|
110
111
|
} = raw;
|
|
@@ -303,16 +304,23 @@ export async function buildModelStepResult(
|
|
|
303
304
|
},
|
|
304
305
|
totalTokens: 0,
|
|
305
306
|
} as LanguageModelUsage),
|
|
306
|
-
performance:
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
307
|
+
performance:
|
|
308
|
+
modelCallPerformance == null
|
|
309
|
+
? {
|
|
310
|
+
effectiveOutputTokensPerSecond: 0,
|
|
311
|
+
outputTokensPerSecond: undefined,
|
|
312
|
+
inputTokensPerSecond: undefined,
|
|
313
|
+
effectiveTotalTokensPerSecond: 0,
|
|
314
|
+
stepTimeMs: 0,
|
|
315
|
+
responseTimeMs: 0,
|
|
316
|
+
toolExecutionMs: {},
|
|
317
|
+
timeToFirstOutputMs: undefined,
|
|
318
|
+
}
|
|
319
|
+
: {
|
|
320
|
+
...modelCallPerformance,
|
|
321
|
+
stepTimeMs: modelCallPerformance.responseTimeMs,
|
|
322
|
+
toolExecutionMs: {},
|
|
323
|
+
},
|
|
316
324
|
warnings,
|
|
317
325
|
request: {
|
|
318
326
|
body: '',
|
package/src/do-stream-step.ts
CHANGED
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
import type {
|
|
23
23
|
ModelCallFinish as StreamFinish,
|
|
24
24
|
ModelCallOptions as DoStreamStepOptions,
|
|
25
|
+
ModelCallPerformance,
|
|
25
26
|
ModelCallRawContentPart as DoStreamStepRawContentPart,
|
|
26
27
|
ModelCallResult as DoStreamStepResult,
|
|
27
28
|
ModelCallStreamPart,
|
|
@@ -212,6 +213,7 @@ export async function doStreamStep(
|
|
|
212
213
|
| { id?: string; timestamp?: Date; modelId?: string }
|
|
213
214
|
| undefined;
|
|
214
215
|
let warnings: unknown[] | undefined;
|
|
216
|
+
let performance: ModelCallPerformance | undefined;
|
|
215
217
|
let terminalError: unknown;
|
|
216
218
|
let hasTerminalError = false;
|
|
217
219
|
const ongoingToolCallToolNames = new Map<string, string>();
|
|
@@ -400,6 +402,7 @@ export async function doStreamStep(
|
|
|
400
402
|
| Record<string, unknown>
|
|
401
403
|
| undefined,
|
|
402
404
|
};
|
|
405
|
+
performance = part.performance;
|
|
403
406
|
break;
|
|
404
407
|
case 'model-call-start':
|
|
405
408
|
warnings = part.warnings;
|
|
@@ -456,6 +459,7 @@ export async function doStreamStep(
|
|
|
456
459
|
content,
|
|
457
460
|
reasoning: reasoningParts,
|
|
458
461
|
responseMetadata,
|
|
462
|
+
performance,
|
|
459
463
|
warnings,
|
|
460
464
|
},
|
|
461
465
|
providerExecutedToolResults,
|
package/src/model-call.ts
CHANGED
|
@@ -9,6 +9,7 @@ import type {
|
|
|
9
9
|
Experimental_LanguageModelStreamPart,
|
|
10
10
|
FinishReason,
|
|
11
11
|
LanguageModelUsage,
|
|
12
|
+
StepResultPerformance,
|
|
12
13
|
StopCondition,
|
|
13
14
|
ToolCallRepairFunction,
|
|
14
15
|
ToolChoice,
|
|
@@ -99,6 +100,11 @@ export interface ModelCallFinish {
|
|
|
99
100
|
providerMetadata?: Record<string, unknown>;
|
|
100
101
|
}
|
|
101
102
|
|
|
103
|
+
export type ModelCallPerformance = Omit<
|
|
104
|
+
StepResultPerformance,
|
|
105
|
+
'stepTimeMs' | 'toolExecutionMs'
|
|
106
|
+
>;
|
|
107
|
+
|
|
102
108
|
export type ModelCallRawContentPart =
|
|
103
109
|
| Extract<
|
|
104
110
|
LanguageModelV4Content,
|
|
@@ -175,6 +181,8 @@ export interface ModelCallRawResult {
|
|
|
175
181
|
request?: { body?: unknown };
|
|
176
182
|
responseTimeMs: number;
|
|
177
183
|
};
|
|
184
|
+
/** Present on streamed results produced after performance tracking was added. */
|
|
185
|
+
performance?: ModelCallPerformance;
|
|
178
186
|
warnings?: unknown[];
|
|
179
187
|
}
|
|
180
188
|
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
} from '@ai-sdk/provider-utils';
|
|
21
21
|
import { dynamicTool, tool, type ToolSet } from 'ai';
|
|
22
22
|
import Ajv from 'ajv';
|
|
23
|
+
import Ajv2020 from 'ajv/dist/2020.js';
|
|
23
24
|
|
|
24
25
|
/**
|
|
25
26
|
* Serializable tool definition — plain objects only, safe for workflow steps.
|
|
@@ -142,7 +143,36 @@ function resolveToolDescription<TOOLS extends ToolSet>({
|
|
|
142
143
|
export function resolveSerializableTools(
|
|
143
144
|
tools: Record<string, SerializableToolDef>,
|
|
144
145
|
): ToolSet {
|
|
145
|
-
const
|
|
146
|
+
const ajvOptions = {
|
|
147
|
+
strict: false,
|
|
148
|
+
validateFormats: false,
|
|
149
|
+
} as const;
|
|
150
|
+
const ajv = new Ajv(ajvOptions);
|
|
151
|
+
const ajv2020 = new Ajv2020(ajvOptions);
|
|
152
|
+
|
|
153
|
+
const createValidatedInputSchema = (inputSchema: JSONSchema7) => {
|
|
154
|
+
const schemaDialect =
|
|
155
|
+
typeof inputSchema.$schema === 'string'
|
|
156
|
+
? inputSchema.$schema.replace(/#$/, '')
|
|
157
|
+
: undefined;
|
|
158
|
+
const schemaAjv =
|
|
159
|
+
schemaDialect === 'https://json-schema.org/draft/2020-12/schema'
|
|
160
|
+
? ajv2020
|
|
161
|
+
: ajv;
|
|
162
|
+
const validateFn = schemaAjv.compile(inputSchema);
|
|
163
|
+
|
|
164
|
+
return jsonSchema(inputSchema, {
|
|
165
|
+
validate: value => {
|
|
166
|
+
if (validateFn(value)) {
|
|
167
|
+
return { success: true, value: value as any };
|
|
168
|
+
}
|
|
169
|
+
return {
|
|
170
|
+
success: false,
|
|
171
|
+
error: new Error(schemaAjv.errorsText(validateFn.errors)),
|
|
172
|
+
};
|
|
173
|
+
},
|
|
174
|
+
});
|
|
175
|
+
};
|
|
146
176
|
|
|
147
177
|
return Object.fromEntries(
|
|
148
178
|
Object.entries(tools).map(([name, t]) => {
|
|
@@ -175,30 +205,17 @@ export function resolveSerializableTools(
|
|
|
175
205
|
}
|
|
176
206
|
|
|
177
207
|
if (t.type === 'dynamic') {
|
|
178
|
-
const validateFn = ajv.compile(t.inputSchema);
|
|
179
|
-
|
|
180
208
|
return [
|
|
181
209
|
name,
|
|
182
210
|
dynamicTool({
|
|
183
211
|
description: t.description,
|
|
184
212
|
inputExamples: t.inputExamples,
|
|
185
213
|
providerOptions: t.providerOptions,
|
|
186
|
-
inputSchema:
|
|
187
|
-
validate: value => {
|
|
188
|
-
if (validateFn(value)) {
|
|
189
|
-
return { success: true, value };
|
|
190
|
-
}
|
|
191
|
-
return {
|
|
192
|
-
success: false,
|
|
193
|
-
error: new Error(ajv.errorsText(validateFn.errors)),
|
|
194
|
-
};
|
|
195
|
-
},
|
|
196
|
-
}),
|
|
214
|
+
inputSchema: createValidatedInputSchema(t.inputSchema),
|
|
197
215
|
}),
|
|
198
216
|
];
|
|
199
217
|
}
|
|
200
218
|
|
|
201
|
-
const validateFn = ajv.compile(t.inputSchema);
|
|
202
219
|
const functionTool = {
|
|
203
220
|
title: t.title,
|
|
204
221
|
metadata: t.metadata,
|
|
@@ -206,17 +223,7 @@ export function resolveSerializableTools(
|
|
|
206
223
|
strict: t.strict,
|
|
207
224
|
inputExamples: t.inputExamples,
|
|
208
225
|
providerOptions: t.providerOptions,
|
|
209
|
-
inputSchema:
|
|
210
|
-
validate: value => {
|
|
211
|
-
if (validateFn(value)) {
|
|
212
|
-
return { success: true, value: value as any };
|
|
213
|
-
}
|
|
214
|
-
return {
|
|
215
|
-
success: false,
|
|
216
|
-
error: new Error(ajv.errorsText(validateFn.errors)),
|
|
217
|
-
};
|
|
218
|
-
},
|
|
219
|
-
}),
|
|
226
|
+
inputSchema: createValidatedInputSchema(t.inputSchema),
|
|
220
227
|
};
|
|
221
228
|
|
|
222
229
|
return [
|
package/src/workflow-agent.ts
CHANGED
|
@@ -1950,6 +1950,7 @@ export class WorkflowAgent<
|
|
|
1950
1950
|
input: collected.toolCall.input,
|
|
1951
1951
|
reason: collected.approvalResponse.reason,
|
|
1952
1952
|
providerExecuted: collected.toolCall.providerExecuted === true,
|
|
1953
|
+
existingToolResult: collected.existingToolResult,
|
|
1953
1954
|
}),
|
|
1954
1955
|
);
|
|
1955
1956
|
|
|
@@ -2092,7 +2093,10 @@ export class WorkflowAgent<
|
|
|
2092
2093
|
for (const denial of deniedToolApprovals) {
|
|
2093
2094
|
// Provider-executed denials are forwarded to the provider via the
|
|
2094
2095
|
// preserved approval response below, not turned into a local result.
|
|
2095
|
-
if (
|
|
2096
|
+
if (
|
|
2097
|
+
denial.providerExecuted ||
|
|
2098
|
+
denial.existingToolResult !== undefined
|
|
2099
|
+
) {
|
|
2096
2100
|
continue;
|
|
2097
2101
|
}
|
|
2098
2102
|
toolResultContent.push({
|
|
@@ -2161,10 +2165,13 @@ export class WorkflowAgent<
|
|
|
2161
2165
|
// Write tool results and step boundaries to the stream so the UI
|
|
2162
2166
|
// can transition approved/denied tool parts to the correct state
|
|
2163
2167
|
// and properly separate them from the subsequent model step.
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
+
const deniedResults = deniedToolApprovals
|
|
2169
|
+
.filter(denial => !denial.providerExecuted)
|
|
2170
|
+
.map(denial => ({ toolCallId: denial.toolCallId }));
|
|
2171
|
+
if (
|
|
2172
|
+
options.writable &&
|
|
2173
|
+
(toolResultContent.length > 0 || deniedResults.length > 0)
|
|
2174
|
+
) {
|
|
2168
2175
|
await writeApprovalToolResults(
|
|
2169
2176
|
options.writable,
|
|
2170
2177
|
approvedRawResults,
|