@ai-sdk/workflow 0.0.0-bf6e4b15-20260402200305
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 +52 -0
- package/LICENSE +13 -0
- package/README.md +62 -0
- package/dist/index.d.mts +739 -0
- package/dist/index.mjs +1261 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +77 -0
- package/src/do-stream-step.ts +329 -0
- package/src/index.ts +37 -0
- package/src/providers/mock-function-wrapper.ts +11 -0
- package/src/providers/mock.ts +123 -0
- package/src/serializable-schema.ts +81 -0
- package/src/stream-iterator.ts +46 -0
- package/src/stream-text-iterator.ts +444 -0
- package/src/telemetry.ts +199 -0
- package/src/test/agent-e2e-workflows.ts +507 -0
- package/src/test/calculate-workflow.ts +19 -0
- package/src/to-ui-message-chunk.ts +214 -0
- package/src/types.ts +11 -0
- package/src/workflow-agent.ts +1647 -0
- package/src/workflow-chat-transport.ts +359 -0
|
@@ -0,0 +1,507 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration test workflows for WorkflowAgent using mock providers.
|
|
3
|
+
*/
|
|
4
|
+
import { tool } from 'ai';
|
|
5
|
+
import { WorkflowAgent } from '../workflow-agent.js';
|
|
6
|
+
import { mockTextModel, mockSequenceModel } from '../providers/mock.js';
|
|
7
|
+
import { FatalError, getWritable } from 'workflow';
|
|
8
|
+
import z from 'zod';
|
|
9
|
+
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// Tool step functions
|
|
12
|
+
// ============================================================================
|
|
13
|
+
|
|
14
|
+
async function addNumbers(input: { a: number; b: number }): Promise<number> {
|
|
15
|
+
'use step';
|
|
16
|
+
return input.a + input.b;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async function echoStep(input: { step: number }): Promise<string> {
|
|
20
|
+
'use step';
|
|
21
|
+
return `step-${input.step}-done`;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function throwingStep(): Promise<string> {
|
|
25
|
+
'use step';
|
|
26
|
+
throw new FatalError('Tool execution failed fatally');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// ============================================================================
|
|
30
|
+
// Core agent tests
|
|
31
|
+
// ============================================================================
|
|
32
|
+
|
|
33
|
+
export async function agentBasicE2e(prompt: string) {
|
|
34
|
+
'use workflow';
|
|
35
|
+
const agent = new WorkflowAgent({
|
|
36
|
+
model: mockTextModel(`Echo: ${prompt}`),
|
|
37
|
+
instructions: 'You are a helpful assistant.',
|
|
38
|
+
});
|
|
39
|
+
const result = await agent.stream({
|
|
40
|
+
messages: [{ role: 'user', content: prompt }],
|
|
41
|
+
writable: getWritable(),
|
|
42
|
+
});
|
|
43
|
+
return {
|
|
44
|
+
stepCount: result.steps.length,
|
|
45
|
+
lastStepText: result.steps[result.steps.length - 1]?.text,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export async function agentToolCallE2e(a: number, b: number) {
|
|
50
|
+
'use workflow';
|
|
51
|
+
const agent = new WorkflowAgent({
|
|
52
|
+
model: mockSequenceModel([
|
|
53
|
+
{
|
|
54
|
+
type: 'tool-call',
|
|
55
|
+
toolName: 'addNumbers',
|
|
56
|
+
input: JSON.stringify({ a, b }),
|
|
57
|
+
},
|
|
58
|
+
{ type: 'text', text: `The sum is ${a + b}` },
|
|
59
|
+
]),
|
|
60
|
+
tools: {
|
|
61
|
+
addNumbers: {
|
|
62
|
+
description: 'Add two numbers',
|
|
63
|
+
inputSchema: z.object({ a: z.number(), b: z.number() }),
|
|
64
|
+
execute: addNumbers,
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
instructions: 'You are a calculator assistant.',
|
|
68
|
+
});
|
|
69
|
+
const result = await agent.stream({
|
|
70
|
+
messages: [{ role: 'user', content: `Add ${a} and ${b}` }],
|
|
71
|
+
writable: getWritable(),
|
|
72
|
+
});
|
|
73
|
+
return {
|
|
74
|
+
stepCount: result.steps.length,
|
|
75
|
+
toolResults: result.toolResults,
|
|
76
|
+
lastStepText: result.steps[result.steps.length - 1]?.text,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export async function agentMultiStepE2e() {
|
|
81
|
+
'use workflow';
|
|
82
|
+
const agent = new WorkflowAgent({
|
|
83
|
+
model: mockSequenceModel([
|
|
84
|
+
{
|
|
85
|
+
type: 'tool-call',
|
|
86
|
+
toolName: 'echoStep',
|
|
87
|
+
input: JSON.stringify({ step: 1 }),
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
type: 'tool-call',
|
|
91
|
+
toolName: 'echoStep',
|
|
92
|
+
input: JSON.stringify({ step: 2 }),
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
type: 'tool-call',
|
|
96
|
+
toolName: 'echoStep',
|
|
97
|
+
input: JSON.stringify({ step: 3 }),
|
|
98
|
+
},
|
|
99
|
+
{ type: 'text', text: 'All done!' },
|
|
100
|
+
]),
|
|
101
|
+
tools: {
|
|
102
|
+
echoStep: {
|
|
103
|
+
description: 'Echo the step number',
|
|
104
|
+
inputSchema: z.object({ step: z.number() }),
|
|
105
|
+
execute: echoStep,
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
const result = await agent.stream({
|
|
110
|
+
messages: [{ role: 'user', content: 'Run 3 steps' }],
|
|
111
|
+
writable: getWritable(),
|
|
112
|
+
});
|
|
113
|
+
return {
|
|
114
|
+
stepCount: result.steps.length,
|
|
115
|
+
lastStepText: result.steps[result.steps.length - 1]?.text,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export async function agentErrorToolE2e() {
|
|
120
|
+
'use workflow';
|
|
121
|
+
const agent = new WorkflowAgent({
|
|
122
|
+
model: mockSequenceModel([
|
|
123
|
+
{ type: 'tool-call', toolName: 'throwingTool', input: '{}' },
|
|
124
|
+
{ type: 'text', text: 'Tool failed but I recovered.' },
|
|
125
|
+
]),
|
|
126
|
+
tools: {
|
|
127
|
+
throwingTool: {
|
|
128
|
+
description: 'A tool that always fails',
|
|
129
|
+
inputSchema: z.object({}),
|
|
130
|
+
execute: throwingStep,
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
const result = await agent.stream({
|
|
135
|
+
messages: [{ role: 'user', content: 'Call the throwing tool' }],
|
|
136
|
+
writable: getWritable(),
|
|
137
|
+
});
|
|
138
|
+
return {
|
|
139
|
+
stepCount: result.steps.length,
|
|
140
|
+
lastStepText: result.steps[result.steps.length - 1]?.text,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// ============================================================================
|
|
145
|
+
// experimental_repairToolCall serialization
|
|
146
|
+
// ============================================================================
|
|
147
|
+
|
|
148
|
+
async function repairToolCall({
|
|
149
|
+
toolCall,
|
|
150
|
+
}: {
|
|
151
|
+
toolCall: { toolCallId: string; toolName: string; input: string };
|
|
152
|
+
}) {
|
|
153
|
+
'use step';
|
|
154
|
+
// Fix the malformed JSON
|
|
155
|
+
return { ...toolCall, input: '{"a": 3, "b": 7}' };
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export async function agentRepairToolCallE2e() {
|
|
159
|
+
'use workflow';
|
|
160
|
+
const agent = new WorkflowAgent({
|
|
161
|
+
model: mockSequenceModel([
|
|
162
|
+
{
|
|
163
|
+
type: 'tool-call',
|
|
164
|
+
toolName: 'addNumbers',
|
|
165
|
+
// Malformed input: missing closing brace
|
|
166
|
+
input: '{"a": 3, "b": 7',
|
|
167
|
+
},
|
|
168
|
+
{ type: 'text', text: 'The sum is 10' },
|
|
169
|
+
]),
|
|
170
|
+
tools: {
|
|
171
|
+
addNumbers: {
|
|
172
|
+
description: 'Add two numbers',
|
|
173
|
+
inputSchema: z.object({ a: z.number(), b: z.number() }),
|
|
174
|
+
execute: addNumbers,
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
});
|
|
178
|
+
const result = await agent.stream({
|
|
179
|
+
messages: [{ role: 'user', content: 'add 3 and 7' }],
|
|
180
|
+
writable: getWritable(),
|
|
181
|
+
experimental_repairToolCall: repairToolCall as any,
|
|
182
|
+
});
|
|
183
|
+
return {
|
|
184
|
+
stepCount: result.steps.length,
|
|
185
|
+
lastStepText: result.steps[result.steps.length - 1]?.text,
|
|
186
|
+
repaired: result.steps.length === 2, // If repair worked, we get 2 steps (tool call + text)
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// ============================================================================
|
|
191
|
+
// Callback tests — onStepFinish
|
|
192
|
+
// ============================================================================
|
|
193
|
+
|
|
194
|
+
export async function agentOnStepFinishE2e() {
|
|
195
|
+
'use workflow';
|
|
196
|
+
const callSources: string[] = [];
|
|
197
|
+
let capturedStepResult: any = null;
|
|
198
|
+
const agent = new WorkflowAgent({
|
|
199
|
+
model: mockTextModel('hello'),
|
|
200
|
+
onStepFinish: async () => {
|
|
201
|
+
callSources.push('constructor');
|
|
202
|
+
},
|
|
203
|
+
});
|
|
204
|
+
const result = await agent.stream({
|
|
205
|
+
messages: [{ role: 'user', content: 'test' }],
|
|
206
|
+
writable: getWritable(),
|
|
207
|
+
onStepFinish: async stepResult => {
|
|
208
|
+
callSources.push('method');
|
|
209
|
+
capturedStepResult = {
|
|
210
|
+
text: stepResult.text,
|
|
211
|
+
finishReason: stepResult.finishReason,
|
|
212
|
+
stepNumber: (stepResult as any).stepNumber,
|
|
213
|
+
};
|
|
214
|
+
},
|
|
215
|
+
});
|
|
216
|
+
return { callSources, capturedStepResult, stepCount: result.steps.length };
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// ============================================================================
|
|
220
|
+
// Callback tests — onFinish
|
|
221
|
+
// ============================================================================
|
|
222
|
+
|
|
223
|
+
export async function agentOnFinishE2e() {
|
|
224
|
+
'use workflow';
|
|
225
|
+
const callSources: string[] = [];
|
|
226
|
+
let capturedEvent: any = null;
|
|
227
|
+
const agent = new WorkflowAgent({
|
|
228
|
+
model: mockTextModel('hello from finish'),
|
|
229
|
+
onFinish: async () => {
|
|
230
|
+
callSources.push('constructor');
|
|
231
|
+
},
|
|
232
|
+
});
|
|
233
|
+
const result = await agent.stream({
|
|
234
|
+
messages: [{ role: 'user', content: 'test' }],
|
|
235
|
+
writable: getWritable(),
|
|
236
|
+
onFinish: async event => {
|
|
237
|
+
callSources.push('method');
|
|
238
|
+
capturedEvent = {
|
|
239
|
+
text: (event as any).text,
|
|
240
|
+
finishReason: (event as any).finishReason,
|
|
241
|
+
stepsLength: event.steps.length,
|
|
242
|
+
hasMessages: event.messages.length > 0,
|
|
243
|
+
hasTotalUsage: (event as any).totalUsage != null,
|
|
244
|
+
};
|
|
245
|
+
},
|
|
246
|
+
});
|
|
247
|
+
return { callSources, capturedEvent, stepCount: result.steps.length };
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// ============================================================================
|
|
251
|
+
// Instructions test
|
|
252
|
+
// ============================================================================
|
|
253
|
+
|
|
254
|
+
export async function agentInstructionsStringE2e() {
|
|
255
|
+
'use workflow';
|
|
256
|
+
const agent = new WorkflowAgent({
|
|
257
|
+
model: mockTextModel('ok'),
|
|
258
|
+
instructions: 'You are a pirate.',
|
|
259
|
+
});
|
|
260
|
+
const result = await agent.stream({
|
|
261
|
+
messages: [{ role: 'user', content: 'ahoy' }],
|
|
262
|
+
writable: getWritable(),
|
|
263
|
+
});
|
|
264
|
+
return {
|
|
265
|
+
stepCount: result.steps.length,
|
|
266
|
+
lastStepText: result.steps[result.steps.length - 1]?.text,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// ============================================================================
|
|
271
|
+
// Timeout test
|
|
272
|
+
// ============================================================================
|
|
273
|
+
|
|
274
|
+
export async function agentTimeoutE2e() {
|
|
275
|
+
'use workflow';
|
|
276
|
+
const agent = new WorkflowAgent({
|
|
277
|
+
model: mockTextModel('fast response'),
|
|
278
|
+
});
|
|
279
|
+
const result = await agent.stream({
|
|
280
|
+
messages: [{ role: 'user', content: 'test' }],
|
|
281
|
+
writable: getWritable(),
|
|
282
|
+
timeout: 30000,
|
|
283
|
+
});
|
|
284
|
+
return {
|
|
285
|
+
stepCount: result.steps.length,
|
|
286
|
+
lastStepText: result.steps[result.steps.length - 1]?.text,
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// ============================================================================
|
|
291
|
+
// GAP tests — experimental_onStart
|
|
292
|
+
// ============================================================================
|
|
293
|
+
|
|
294
|
+
export async function agentOnStartE2e() {
|
|
295
|
+
'use workflow';
|
|
296
|
+
const callSources: string[] = [];
|
|
297
|
+
const agent = new WorkflowAgent({
|
|
298
|
+
model: mockTextModel('hello'),
|
|
299
|
+
experimental_onStart: async () => {
|
|
300
|
+
callSources.push('constructor');
|
|
301
|
+
},
|
|
302
|
+
} as any);
|
|
303
|
+
await agent.stream({
|
|
304
|
+
messages: [{ role: 'user', content: 'test' }],
|
|
305
|
+
writable: getWritable(),
|
|
306
|
+
experimental_onStart: async () => {
|
|
307
|
+
callSources.push('method');
|
|
308
|
+
},
|
|
309
|
+
} as any);
|
|
310
|
+
return { callSources };
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// ============================================================================
|
|
314
|
+
// GAP tests — experimental_onStepStart
|
|
315
|
+
// ============================================================================
|
|
316
|
+
|
|
317
|
+
export async function agentOnStepStartE2e() {
|
|
318
|
+
'use workflow';
|
|
319
|
+
const callSources: string[] = [];
|
|
320
|
+
const agent = new WorkflowAgent({
|
|
321
|
+
model: mockTextModel('hello'),
|
|
322
|
+
experimental_onStepStart: async () => {
|
|
323
|
+
callSources.push('constructor');
|
|
324
|
+
},
|
|
325
|
+
} as any);
|
|
326
|
+
await agent.stream({
|
|
327
|
+
messages: [{ role: 'user', content: 'test' }],
|
|
328
|
+
writable: getWritable(),
|
|
329
|
+
experimental_onStepStart: async () => {
|
|
330
|
+
callSources.push('method');
|
|
331
|
+
},
|
|
332
|
+
} as any);
|
|
333
|
+
return { callSources };
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// ============================================================================
|
|
337
|
+
// GAP tests — experimental_onToolCallStart
|
|
338
|
+
// ============================================================================
|
|
339
|
+
|
|
340
|
+
export async function agentOnToolCallStartE2e() {
|
|
341
|
+
'use workflow';
|
|
342
|
+
const calls: string[] = [];
|
|
343
|
+
const agent = new WorkflowAgent({
|
|
344
|
+
model: mockSequenceModel([
|
|
345
|
+
{
|
|
346
|
+
type: 'tool-call',
|
|
347
|
+
toolName: 'echoStep',
|
|
348
|
+
input: JSON.stringify({ step: 1 }),
|
|
349
|
+
},
|
|
350
|
+
{ type: 'text', text: 'done' },
|
|
351
|
+
]),
|
|
352
|
+
tools: {
|
|
353
|
+
echoStep: {
|
|
354
|
+
description: 'Echo',
|
|
355
|
+
inputSchema: z.object({ step: z.number() }),
|
|
356
|
+
execute: echoStep,
|
|
357
|
+
},
|
|
358
|
+
},
|
|
359
|
+
experimental_onToolCallStart: async () => {
|
|
360
|
+
calls.push('constructor');
|
|
361
|
+
},
|
|
362
|
+
} as any);
|
|
363
|
+
await agent.stream({
|
|
364
|
+
messages: [{ role: 'user', content: 'test' }],
|
|
365
|
+
writable: getWritable(),
|
|
366
|
+
experimental_onToolCallStart: async () => {
|
|
367
|
+
calls.push('method');
|
|
368
|
+
},
|
|
369
|
+
} as any);
|
|
370
|
+
return { calls };
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// ============================================================================
|
|
374
|
+
// GAP tests — experimental_onToolCallFinish
|
|
375
|
+
// ============================================================================
|
|
376
|
+
|
|
377
|
+
export async function agentOnToolCallFinishE2e() {
|
|
378
|
+
'use workflow';
|
|
379
|
+
const calls: string[] = [];
|
|
380
|
+
let capturedEvent: any = null;
|
|
381
|
+
const agent = new WorkflowAgent({
|
|
382
|
+
model: mockSequenceModel([
|
|
383
|
+
{
|
|
384
|
+
type: 'tool-call',
|
|
385
|
+
toolName: 'addNumbers',
|
|
386
|
+
input: JSON.stringify({ a: 1, b: 2 }),
|
|
387
|
+
},
|
|
388
|
+
{ type: 'text', text: 'done' },
|
|
389
|
+
]),
|
|
390
|
+
tools: {
|
|
391
|
+
addNumbers: {
|
|
392
|
+
description: 'Add two numbers',
|
|
393
|
+
inputSchema: z.object({ a: z.number(), b: z.number() }),
|
|
394
|
+
execute: addNumbers,
|
|
395
|
+
},
|
|
396
|
+
},
|
|
397
|
+
experimental_onToolCallFinish: async () => {
|
|
398
|
+
calls.push('constructor');
|
|
399
|
+
},
|
|
400
|
+
} as any);
|
|
401
|
+
await agent.stream({
|
|
402
|
+
messages: [{ role: 'user', content: 'test' }],
|
|
403
|
+
writable: getWritable(),
|
|
404
|
+
experimental_onToolCallFinish: async (event: any) => {
|
|
405
|
+
calls.push('method');
|
|
406
|
+
capturedEvent = {
|
|
407
|
+
toolName: event?.toolCall?.toolName,
|
|
408
|
+
success: event?.success,
|
|
409
|
+
output: event?.output,
|
|
410
|
+
};
|
|
411
|
+
},
|
|
412
|
+
} as any);
|
|
413
|
+
return { calls, capturedEvent };
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// ============================================================================
|
|
417
|
+
// GAP tests — prepareCall
|
|
418
|
+
// ============================================================================
|
|
419
|
+
|
|
420
|
+
export async function agentPrepareCallE2e() {
|
|
421
|
+
'use workflow';
|
|
422
|
+
const agent = new WorkflowAgent({
|
|
423
|
+
model: mockTextModel('ok'),
|
|
424
|
+
prepareCall: ({ options, ...rest }: any) => ({
|
|
425
|
+
...rest,
|
|
426
|
+
providerOptions: { test: { value: options?.value } },
|
|
427
|
+
}),
|
|
428
|
+
} as any);
|
|
429
|
+
const result = await agent.stream({
|
|
430
|
+
messages: [{ role: 'user', content: 'test' }],
|
|
431
|
+
writable: getWritable(),
|
|
432
|
+
});
|
|
433
|
+
return {
|
|
434
|
+
stepCount: result.steps.length,
|
|
435
|
+
lastStepText: result.steps[result.steps.length - 1]?.text,
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// ============================================================================
|
|
440
|
+
// GAP tests — tool approval (needsApproval)
|
|
441
|
+
// ============================================================================
|
|
442
|
+
|
|
443
|
+
export async function agentToolApprovalE2e() {
|
|
444
|
+
'use workflow';
|
|
445
|
+
const agent = new WorkflowAgent({
|
|
446
|
+
model: mockSequenceModel([
|
|
447
|
+
{
|
|
448
|
+
type: 'tool-call',
|
|
449
|
+
toolName: 'riskyTool',
|
|
450
|
+
input: JSON.stringify({ action: 'delete' }),
|
|
451
|
+
},
|
|
452
|
+
{ type: 'text', text: 'done' },
|
|
453
|
+
]),
|
|
454
|
+
tools: {
|
|
455
|
+
riskyTool: {
|
|
456
|
+
description: 'A dangerous tool that needs approval',
|
|
457
|
+
inputSchema: z.object({ action: z.string() }),
|
|
458
|
+
execute: echoStep as any,
|
|
459
|
+
needsApproval: true,
|
|
460
|
+
} as any,
|
|
461
|
+
},
|
|
462
|
+
});
|
|
463
|
+
const result = await agent.stream({
|
|
464
|
+
messages: [{ role: 'user', content: 'do something risky' }],
|
|
465
|
+
writable: getWritable(),
|
|
466
|
+
});
|
|
467
|
+
return {
|
|
468
|
+
toolCallsCount: result.toolCalls.length,
|
|
469
|
+
toolResultsCount: result.toolResults.length,
|
|
470
|
+
stepCount: result.steps.length,
|
|
471
|
+
firstToolCallName: result.toolCalls[0]?.toolName,
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// ============================================================================
|
|
476
|
+
// Tool with input schema (tests serialization across step boundary)
|
|
477
|
+
// ============================================================================
|
|
478
|
+
|
|
479
|
+
export async function agentToolInputSchemaE2e(a: number, b: number) {
|
|
480
|
+
'use workflow';
|
|
481
|
+
const agent = new WorkflowAgent({
|
|
482
|
+
model: mockSequenceModel([
|
|
483
|
+
{
|
|
484
|
+
type: 'tool-call',
|
|
485
|
+
toolName: 'addNumbers',
|
|
486
|
+
input: JSON.stringify({ a, b }),
|
|
487
|
+
},
|
|
488
|
+
{ type: 'text', text: `The sum is ${a + b}` },
|
|
489
|
+
]),
|
|
490
|
+
tools: {
|
|
491
|
+
addNumbers: tool({
|
|
492
|
+
description: 'Add two numbers',
|
|
493
|
+
inputSchema: z.object({ a: z.number(), b: z.number() }),
|
|
494
|
+
execute: async (input: { a: number; b: number }) => input.a + input.b,
|
|
495
|
+
}),
|
|
496
|
+
},
|
|
497
|
+
instructions: 'You are a calculator.',
|
|
498
|
+
});
|
|
499
|
+
const result = await agent.stream({
|
|
500
|
+
messages: [{ role: 'user', content: `Add ${a} and ${b}` }],
|
|
501
|
+
writable: getWritable(),
|
|
502
|
+
});
|
|
503
|
+
return {
|
|
504
|
+
stepCount: result.steps.length,
|
|
505
|
+
lastStepText: result.steps[result.steps.length - 1]?.text,
|
|
506
|
+
};
|
|
507
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export async function calculateWorkflow(a: number, b: number) {
|
|
2
|
+
'use workflow';
|
|
3
|
+
|
|
4
|
+
const sum = await add(a, b);
|
|
5
|
+
const product = await multiply(a, b);
|
|
6
|
+
const combined = await add(sum, product);
|
|
7
|
+
|
|
8
|
+
return { sum, product, combined };
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async function add(a: number, b: number): Promise<number> {
|
|
12
|
+
'use step';
|
|
13
|
+
return a + b;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async function multiply(a: number, b: number): Promise<number> {
|
|
17
|
+
'use step';
|
|
18
|
+
return a * b;
|
|
19
|
+
}
|