@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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-sdk/workflow",
|
|
3
|
-
"version": "1.0.0-
|
|
3
|
+
"version": "1.0.0-canary.33",
|
|
4
4
|
"description": "WorkflowAgent for building AI agents with AI SDK",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -27,9 +27,9 @@
|
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"ajv": "^8.18.0",
|
|
30
|
-
"@ai-sdk/provider": "4.0.0-
|
|
31
|
-
"@ai-sdk/provider-utils": "5.0.0-
|
|
32
|
-
"ai": "7.0.0-
|
|
30
|
+
"@ai-sdk/provider": "4.0.0-canary.15",
|
|
31
|
+
"@ai-sdk/provider-utils": "5.0.0-canary.31",
|
|
32
|
+
"ai": "7.0.0-canary.118"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@types/node": "20.17.24",
|
|
@@ -47,12 +47,14 @@
|
|
|
47
47
|
"node": ">=18"
|
|
48
48
|
},
|
|
49
49
|
"publishConfig": {
|
|
50
|
-
"access": "public"
|
|
50
|
+
"access": "public",
|
|
51
|
+
"provenance": true
|
|
51
52
|
},
|
|
52
53
|
"homepage": "https://ai-sdk.dev/docs",
|
|
53
54
|
"repository": {
|
|
54
55
|
"type": "git",
|
|
55
|
-
"url": "
|
|
56
|
+
"url": "https://github.com/vercel/ai",
|
|
57
|
+
"directory": "packages/workflow"
|
|
56
58
|
},
|
|
57
59
|
"bugs": {
|
|
58
60
|
"url": "https://github.com/vercel/ai/issues"
|
package/src/do-stream-step.ts
CHANGED
|
@@ -3,8 +3,9 @@ import type {
|
|
|
3
3
|
LanguageModelV4Prompt,
|
|
4
4
|
} from '@ai-sdk/provider';
|
|
5
5
|
import {
|
|
6
|
-
type Experimental_LanguageModelStreamPart as ModelCallStreamPart,
|
|
7
6
|
experimental_streamLanguageModelCall as streamModelCall,
|
|
7
|
+
gateway,
|
|
8
|
+
type Experimental_LanguageModelStreamPart as ModelCallStreamPart,
|
|
8
9
|
type FinishReason,
|
|
9
10
|
type LanguageModel,
|
|
10
11
|
type LanguageModelUsage,
|
|
@@ -15,13 +16,11 @@ import {
|
|
|
15
16
|
type ToolChoice,
|
|
16
17
|
type ToolSet,
|
|
17
18
|
} from 'ai';
|
|
18
|
-
import {
|
|
19
|
-
import type { ProviderOptions, TelemetrySettings } from './workflow-agent.js';
|
|
19
|
+
import type { ProviderOptions, TelemetryOptions } from './workflow-agent.js';
|
|
20
20
|
import {
|
|
21
21
|
resolveSerializableTools,
|
|
22
22
|
type SerializableToolDef,
|
|
23
23
|
} from './serializable-schema.js';
|
|
24
|
-
|
|
25
24
|
export type { Experimental_LanguageModelStreamPart as ModelCallStreamPart } from 'ai';
|
|
26
25
|
|
|
27
26
|
export type ModelStopCondition = StopCondition<NoInfer<ToolSet>, any>;
|
|
@@ -54,7 +53,7 @@ export interface DoStreamStepOptions {
|
|
|
54
53
|
providerOptions?: ProviderOptions;
|
|
55
54
|
toolChoice?: ToolChoice<ToolSet>;
|
|
56
55
|
includeRawChunks?: boolean;
|
|
57
|
-
|
|
56
|
+
telemetry?: TelemetryOptions;
|
|
58
57
|
repairToolCall?: ToolCallRepairFunction<ToolSet>;
|
|
59
58
|
responseFormat?: LanguageModelV4CallOptions['responseFormat'];
|
|
60
59
|
}
|
|
@@ -115,6 +114,7 @@ export async function doStreamStep(
|
|
|
115
114
|
// pre-converted LanguageModelV4Prompt. standardizePrompt inside
|
|
116
115
|
// streamModelCall handles both formats.
|
|
117
116
|
messages: conversationPrompt as unknown as ModelMessage[],
|
|
117
|
+
allowSystemInMessages: true,
|
|
118
118
|
tools,
|
|
119
119
|
toolChoice: options?.toolChoice,
|
|
120
120
|
includeRawChunks: options?.includeRawChunks,
|
|
@@ -241,7 +241,8 @@ export async function doStreamStep(
|
|
|
241
241
|
},
|
|
242
242
|
functionId: undefined,
|
|
243
243
|
metadata: undefined,
|
|
244
|
-
|
|
244
|
+
runtimeContext: undefined,
|
|
245
|
+
toolsContext: {},
|
|
245
246
|
content: [
|
|
246
247
|
...(text ? [{ type: 'text' as const, text }] : []),
|
|
247
248
|
...toolCalls
|
package/src/index.ts
CHANGED
|
@@ -22,12 +22,12 @@ export {
|
|
|
22
22
|
type WorkflowAgentOnFinishCallback,
|
|
23
23
|
type WorkflowAgentOnStepFinishCallback,
|
|
24
24
|
type StreamTextTransform,
|
|
25
|
-
type
|
|
25
|
+
type TelemetryOptions,
|
|
26
26
|
type ToolCallRepairFunction,
|
|
27
27
|
type WorkflowAgentOnStartCallback,
|
|
28
28
|
type WorkflowAgentOnStepStartCallback,
|
|
29
|
-
type
|
|
30
|
-
type
|
|
29
|
+
type WorkflowAgentOnToolExecutionStartCallback,
|
|
30
|
+
type WorkflowAgentOnToolExecutionEndCallback,
|
|
31
31
|
} from './workflow-agent.js';
|
|
32
32
|
|
|
33
33
|
export {
|
|
@@ -23,6 +23,8 @@ export type SerializableToolDef = {
|
|
|
23
23
|
inputSchema: JSONSchema7;
|
|
24
24
|
/** Present on provider tools (e.g. anthropic.tools.webSearch). */
|
|
25
25
|
type?: 'provider';
|
|
26
|
+
/** Provider tool is executed by the provider. */
|
|
27
|
+
isProviderExecuted?: boolean;
|
|
26
28
|
/** Provider tool ID, e.g. 'anthropic.web_search_20250305'. */
|
|
27
29
|
id?: `${string}.${string}`;
|
|
28
30
|
/** Provider tool configuration args (maxUses, allowedDomains, etc.). */
|
|
@@ -49,6 +51,7 @@ export function serializeToolSet(
|
|
|
49
51
|
// them as provider-executed tools (e.g. anthropic webSearch).
|
|
50
52
|
if ((t as any).type === 'provider') {
|
|
51
53
|
def.type = 'provider';
|
|
54
|
+
def.isProviderExecuted = (t as any).isProviderExecuted ?? false;
|
|
52
55
|
def.id = (t as any).id;
|
|
53
56
|
def.args = (t as any).args;
|
|
54
57
|
}
|
|
@@ -81,6 +84,7 @@ export function resolveSerializableTools(
|
|
|
81
84
|
type: 'provider' as const,
|
|
82
85
|
id: t.id!,
|
|
83
86
|
args: t.args ?? {},
|
|
87
|
+
isProviderExecuted: t.isProviderExecuted ?? false,
|
|
84
88
|
inputSchema: jsonSchema(t.inputSchema),
|
|
85
89
|
}),
|
|
86
90
|
];
|
|
@@ -3,14 +3,15 @@ import type {
|
|
|
3
3
|
LanguageModelV4Prompt,
|
|
4
4
|
LanguageModelV4ToolResultPart,
|
|
5
5
|
} from '@ai-sdk/provider';
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
6
|
+
import {
|
|
7
|
+
experimental_filterActiveTools as filterActiveTools,
|
|
8
|
+
type Experimental_LanguageModelStreamPart as ModelCallStreamPart,
|
|
9
|
+
type LanguageModel,
|
|
10
|
+
type ModelMessage,
|
|
11
|
+
type StepResult,
|
|
12
|
+
type ToolCallRepairFunction,
|
|
13
|
+
type ToolChoice,
|
|
14
|
+
type ToolSet,
|
|
14
15
|
} from 'ai';
|
|
15
16
|
import {
|
|
16
17
|
doStreamStep,
|
|
@@ -24,7 +25,7 @@ import type {
|
|
|
24
25
|
PrepareStepCallback,
|
|
25
26
|
WorkflowAgentOnErrorCallback,
|
|
26
27
|
WorkflowAgentOnStepFinishCallback,
|
|
27
|
-
|
|
28
|
+
TelemetryOptions,
|
|
28
29
|
WorkflowAgentOnStepStartCallback,
|
|
29
30
|
} from './workflow-agent.js';
|
|
30
31
|
|
|
@@ -55,7 +56,6 @@ export async function* streamTextIterator({
|
|
|
55
56
|
writable,
|
|
56
57
|
model,
|
|
57
58
|
stopConditions,
|
|
58
|
-
maxSteps,
|
|
59
59
|
onStepFinish,
|
|
60
60
|
onStepStart,
|
|
61
61
|
onError,
|
|
@@ -63,7 +63,7 @@ export async function* streamTextIterator({
|
|
|
63
63
|
generationSettings,
|
|
64
64
|
toolChoice,
|
|
65
65
|
experimental_context,
|
|
66
|
-
|
|
66
|
+
telemetry,
|
|
67
67
|
includeRawChunks = false,
|
|
68
68
|
repairToolCall,
|
|
69
69
|
responseFormat,
|
|
@@ -73,7 +73,6 @@ export async function* streamTextIterator({
|
|
|
73
73
|
writable?: WritableStream<ModelCallStreamPart<ToolSet>>;
|
|
74
74
|
model: LanguageModel;
|
|
75
75
|
stopConditions?: ModelStopCondition[] | ModelStopCondition;
|
|
76
|
-
maxSteps?: number;
|
|
77
76
|
onStepFinish?: WorkflowAgentOnStepFinishCallback<any>;
|
|
78
77
|
onStepStart?: WorkflowAgentOnStepStartCallback;
|
|
79
78
|
onError?: WorkflowAgentOnErrorCallback;
|
|
@@ -81,7 +80,7 @@ export async function* streamTextIterator({
|
|
|
81
80
|
generationSettings?: GenerationSettings;
|
|
82
81
|
toolChoice?: ToolChoice<ToolSet>;
|
|
83
82
|
experimental_context?: unknown;
|
|
84
|
-
|
|
83
|
+
telemetry?: TelemetryOptions;
|
|
85
84
|
includeRawChunks?: boolean;
|
|
86
85
|
repairToolCall?: ToolCallRepairFunction<ToolSet>;
|
|
87
86
|
responseFormat?: LanguageModelV4CallOptions['responseFormat'];
|
|
@@ -104,16 +103,7 @@ export async function* streamTextIterator({
|
|
|
104
103
|
let lastStep: StepResult<any, any> | undefined;
|
|
105
104
|
let lastStepWasToolCalls = false;
|
|
106
105
|
|
|
107
|
-
// Default maxSteps to Infinity to preserve backwards compatibility
|
|
108
|
-
// (agent loops until completion unless explicitly limited)
|
|
109
|
-
const effectiveMaxSteps = maxSteps ?? Infinity;
|
|
110
|
-
|
|
111
106
|
while (!done) {
|
|
112
|
-
// Check if we've exceeded the maximum number of steps
|
|
113
|
-
if (stepNumber >= effectiveMaxSteps) {
|
|
114
|
-
break;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
107
|
// Check for abort signal
|
|
118
108
|
if (currentGenerationSettings.abortSignal?.aborted) {
|
|
119
109
|
break;
|
|
@@ -250,7 +240,10 @@ export async function* streamTextIterator({
|
|
|
250
240
|
// Filter tools if activeTools is specified
|
|
251
241
|
const effectiveTools =
|
|
252
242
|
currentActiveTools && currentActiveTools.length > 0
|
|
253
|
-
?
|
|
243
|
+
? (filterActiveTools({
|
|
244
|
+
tools,
|
|
245
|
+
activeTools: currentActiveTools,
|
|
246
|
+
}) ?? tools)
|
|
254
247
|
: tools;
|
|
255
248
|
|
|
256
249
|
// Serialize tools before crossing the step boundary — zod schemas
|
|
@@ -268,7 +261,7 @@ export async function* streamTextIterator({
|
|
|
268
261
|
...currentGenerationSettings,
|
|
269
262
|
toolChoice: currentToolChoice,
|
|
270
263
|
includeRawChunks,
|
|
271
|
-
|
|
264
|
+
telemetry,
|
|
272
265
|
repairToolCall,
|
|
273
266
|
responseFormat,
|
|
274
267
|
},
|
|
@@ -394,19 +387,6 @@ export async function* streamTextIterator({
|
|
|
394
387
|
return conversationPrompt;
|
|
395
388
|
}
|
|
396
389
|
|
|
397
|
-
/**
|
|
398
|
-
* Filter a tool set to only include the specified active tools.
|
|
399
|
-
*/
|
|
400
|
-
function filterToolSet(tools: ToolSet, activeTools: string[]): ToolSet {
|
|
401
|
-
const filtered: ToolSet = {};
|
|
402
|
-
for (const toolName of activeTools) {
|
|
403
|
-
if (toolName in tools) {
|
|
404
|
-
filtered[toolName] = tools[toolName];
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
return filtered;
|
|
408
|
-
}
|
|
409
|
-
|
|
410
390
|
/**
|
|
411
391
|
* Strip OpenAI's itemId from providerMetadata (requires reasoning items we don't preserve).
|
|
412
392
|
* Preserves all other provider metadata (e.g., Gemini's thoughtSignature).
|
package/src/telemetry.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { TelemetryOptions } from './workflow-agent.js';
|
|
2
2
|
|
|
3
3
|
// Minimal OTel type shims so we don't depend on @opentelemetry/api at compile time.
|
|
4
4
|
type Attributes = Record<string, unknown>;
|
|
@@ -62,7 +62,7 @@ async function ensureOtelApi(): Promise<OtelApi | null> {
|
|
|
62
62
|
* Returns a no-op–equivalent `null` when telemetry is disabled, so callers
|
|
63
63
|
* don't need a separate init step.
|
|
64
64
|
*/
|
|
65
|
-
function getTracer(telemetry?:
|
|
65
|
+
function getTracer(telemetry?: TelemetryOptions): Tracer | null {
|
|
66
66
|
if (!telemetry?.isEnabled || !otelApi) return null;
|
|
67
67
|
if (telemetry.tracer) return telemetry.tracer as Tracer;
|
|
68
68
|
return otelApi.trace.getTracer('ai');
|
|
@@ -76,7 +76,7 @@ function getTracer(telemetry?: TelemetrySettings): Tracer | null {
|
|
|
76
76
|
*/
|
|
77
77
|
function assembleOperationName(
|
|
78
78
|
operationId: string,
|
|
79
|
-
telemetry?:
|
|
79
|
+
telemetry?: TelemetryOptions,
|
|
80
80
|
): Attributes {
|
|
81
81
|
return {
|
|
82
82
|
'operation.name': `${operationId}${
|
|
@@ -94,7 +94,7 @@ function assembleOperationName(
|
|
|
94
94
|
*/
|
|
95
95
|
function buildAttributes(
|
|
96
96
|
operationId: string,
|
|
97
|
-
telemetry:
|
|
97
|
+
telemetry: TelemetryOptions | undefined,
|
|
98
98
|
extra?: Attributes,
|
|
99
99
|
): Attributes {
|
|
100
100
|
if (!telemetry?.isEnabled) return {};
|
|
@@ -154,7 +154,7 @@ function recordErrorOnSpan(span: Span, error: unknown): void {
|
|
|
154
154
|
*/
|
|
155
155
|
export async function recordSpan<T>(options: {
|
|
156
156
|
name: string;
|
|
157
|
-
telemetry?:
|
|
157
|
+
telemetry?: TelemetryOptions;
|
|
158
158
|
attributes?: Attributes;
|
|
159
159
|
fn: (span?: Span) => PromiseLike<T> | T;
|
|
160
160
|
}): Promise<T> {
|
|
@@ -5,7 +5,7 @@ import { tool } from 'ai';
|
|
|
5
5
|
import { WorkflowAgent } from '../workflow-agent.js';
|
|
6
6
|
import { mockTextModel, mockSequenceModel } from '../providers/mock.js';
|
|
7
7
|
import { FatalError, getWritable } from 'workflow';
|
|
8
|
-
import z from 'zod';
|
|
8
|
+
import { z } from 'zod';
|
|
9
9
|
|
|
10
10
|
// ============================================================================
|
|
11
11
|
// Tool step functions
|
|
@@ -334,10 +334,10 @@ export async function agentOnStepStartE2e() {
|
|
|
334
334
|
}
|
|
335
335
|
|
|
336
336
|
// ============================================================================
|
|
337
|
-
// GAP tests —
|
|
337
|
+
// GAP tests — experimental_onToolExecutionStart
|
|
338
338
|
// ============================================================================
|
|
339
339
|
|
|
340
|
-
export async function
|
|
340
|
+
export async function agentonToolExecutionStartE2e() {
|
|
341
341
|
'use workflow';
|
|
342
342
|
const calls: string[] = [];
|
|
343
343
|
const agent = new WorkflowAgent({
|
|
@@ -356,14 +356,14 @@ export async function agentOnToolCallStartE2e() {
|
|
|
356
356
|
execute: echoStep,
|
|
357
357
|
},
|
|
358
358
|
},
|
|
359
|
-
|
|
359
|
+
experimental_onToolExecutionStart: async () => {
|
|
360
360
|
calls.push('constructor');
|
|
361
361
|
},
|
|
362
362
|
} as any);
|
|
363
363
|
await agent.stream({
|
|
364
364
|
messages: [{ role: 'user', content: 'test' }],
|
|
365
365
|
writable: getWritable(),
|
|
366
|
-
|
|
366
|
+
experimental_onToolExecutionStart: async () => {
|
|
367
367
|
calls.push('method');
|
|
368
368
|
},
|
|
369
369
|
} as any);
|
|
@@ -371,10 +371,10 @@ export async function agentOnToolCallStartE2e() {
|
|
|
371
371
|
}
|
|
372
372
|
|
|
373
373
|
// ============================================================================
|
|
374
|
-
// GAP tests —
|
|
374
|
+
// GAP tests — experimental_onToolExecutionEnd
|
|
375
375
|
// ============================================================================
|
|
376
376
|
|
|
377
|
-
export async function
|
|
377
|
+
export async function agentonToolExecutionEndE2e() {
|
|
378
378
|
'use workflow';
|
|
379
379
|
const calls: string[] = [];
|
|
380
380
|
let capturedEvent: any = null;
|
|
@@ -394,14 +394,14 @@ export async function agentOnToolCallFinishE2e() {
|
|
|
394
394
|
execute: addNumbers,
|
|
395
395
|
},
|
|
396
396
|
},
|
|
397
|
-
|
|
397
|
+
experimental_onToolExecutionEnd: async () => {
|
|
398
398
|
calls.push('constructor');
|
|
399
399
|
},
|
|
400
400
|
} as any);
|
|
401
401
|
await agent.stream({
|
|
402
402
|
messages: [{ role: 'user', content: 'test' }],
|
|
403
403
|
writable: getWritable(),
|
|
404
|
-
|
|
404
|
+
experimental_onToolExecutionEnd: async (event: any) => {
|
|
405
405
|
calls.push('method');
|
|
406
406
|
capturedEvent = {
|
|
407
407
|
toolName: event?.toolCall?.toolName,
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import type {
|
|
2
|
+
Experimental_LanguageModelStreamPart as ModelCallStreamPart,
|
|
3
|
+
ToolSet,
|
|
4
|
+
UIMessageChunk,
|
|
5
|
+
} from 'ai';
|
|
3
6
|
|
|
4
7
|
/**
|
|
5
8
|
* Convert a single ModelCallStreamPart to a UIMessageChunk.
|