@ai-sdk/workflow 1.0.38 → 1.0.39

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/workflow",
3
- "version": "1.0.38",
3
+ "version": "1.0.39",
4
4
  "type": "module",
5
5
  "description": "WorkflowAgent for building AI agents with AI SDK",
6
6
  "license": "Apache-2.0",
@@ -28,8 +28,8 @@
28
28
  "dependencies": {
29
29
  "ajv": "^8.20.0",
30
30
  "@ai-sdk/provider": "4.0.4",
31
- "@ai-sdk/provider-utils": "5.0.13",
32
- "ai": "7.0.38"
31
+ "@ai-sdk/provider-utils": "5.0.14",
32
+ "ai": "7.0.39"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@types/node": "22.19.19",
@@ -11,7 +11,13 @@
11
11
  * to use that interface directly.
12
12
  */
13
13
  import type { JSONSchema7 } from '@ai-sdk/provider';
14
- import { asSchema, jsonSchema } from '@ai-sdk/provider-utils';
14
+ import {
15
+ asSchema,
16
+ type Experimental_SandboxSession as SandboxSession,
17
+ type InferToolSetContext,
18
+ jsonSchema,
19
+ type Tool,
20
+ } from '@ai-sdk/provider-utils';
15
21
  import { tool, type ToolSet } from 'ai';
16
22
  import Ajv from 'ajv';
17
23
 
@@ -37,13 +43,25 @@ export type SerializableToolDef = {
37
43
  * (as JSON Schema) are preserved — execute functions are stripped since they
38
44
  * run outside the step.
39
45
  */
40
- export function serializeToolSet(
41
- tools: ToolSet,
46
+ export function serializeToolSet<TOOLS extends ToolSet>(
47
+ tools: TOOLS,
48
+ {
49
+ toolsContext = {} as InferToolSetContext<TOOLS>,
50
+ experimental_sandbox: sandbox,
51
+ }: {
52
+ toolsContext?: InferToolSetContext<TOOLS>;
53
+ experimental_sandbox?: SandboxSession;
54
+ } = {},
42
55
  ): Record<string, SerializableToolDef> {
43
56
  return Object.fromEntries(
44
57
  Object.entries(tools).map(([name, t]) => {
45
58
  const def: SerializableToolDef = {
46
- description: t.description as string, // TODO support tools with function descriptions
59
+ description: resolveToolDescription({
60
+ tool: t,
61
+ toolName: name,
62
+ toolsContext,
63
+ experimental_sandbox: sandbox,
64
+ }),
47
65
  inputSchema: asSchema(t.inputSchema).jsonSchema as JSONSchema7,
48
66
  };
49
67
 
@@ -61,6 +79,27 @@ export function serializeToolSet(
61
79
  );
62
80
  }
63
81
 
82
+ function resolveToolDescription<TOOLS extends ToolSet>({
83
+ tool,
84
+ toolName,
85
+ toolsContext,
86
+ experimental_sandbox: sandbox,
87
+ }: {
88
+ tool: Tool;
89
+ toolName: string;
90
+ toolsContext: InferToolSetContext<TOOLS>;
91
+ experimental_sandbox?: SandboxSession;
92
+ }): string | undefined {
93
+ return tool.description === undefined
94
+ ? undefined
95
+ : typeof tool.description === 'string'
96
+ ? tool.description
97
+ : tool.description({
98
+ context: toolsContext[toolName as keyof InferToolSetContext<TOOLS>],
99
+ experimental_sandbox: sandbox,
100
+ });
101
+ }
102
+
64
103
  /**
65
104
  * Reconstructs tool objects from serializable tool definitions inside a step.
66
105
  *
@@ -9,6 +9,7 @@ import {
9
9
  experimental_filterActiveTools as filterActiveTools,
10
10
  type Experimental_LanguageModelStreamPart as ModelCallStreamPart,
11
11
  type Experimental_SandboxSession as SandboxSession,
12
+ type Instructions,
12
13
  type LanguageModel,
13
14
  type LanguageModelUsage,
14
15
  type ModelMessage,
@@ -40,6 +41,36 @@ import type {
40
41
  // Re-export for consumers
41
42
  export type { ProviderExecutedToolResult } from './do-stream-step.js';
42
43
 
44
+ const prepareStepGenerationSettingKeys = [
45
+ 'maxOutputTokens',
46
+ 'temperature',
47
+ 'topP',
48
+ 'topK',
49
+ 'presencePenalty',
50
+ 'frequencyPenalty',
51
+ 'stopSequences',
52
+ 'seed',
53
+ 'maxRetries',
54
+ 'headers',
55
+ 'reasoning',
56
+ 'providerOptions',
57
+ ] as const satisfies readonly (keyof GenerationSettings)[];
58
+
59
+ function mergePrepareStepGenerationSettings(
60
+ current: GenerationSettings,
61
+ overrides: Partial<GenerationSettings>,
62
+ ): GenerationSettings {
63
+ const definedOverrides: Partial<GenerationSettings> = {};
64
+
65
+ for (const key of prepareStepGenerationSettingKeys) {
66
+ if (overrides[key] !== undefined) {
67
+ Object.assign(definedOverrides, { [key]: overrides[key] });
68
+ }
69
+ }
70
+
71
+ return { ...current, ...definedOverrides };
72
+ }
73
+
43
74
  /**
44
75
  * The value yielded by the stream text iterator when tool calls are requested.
45
76
  * Contains both the tool calls and the current conversation messages.
@@ -64,6 +95,8 @@ export interface StreamTextIteratorYieldValue {
64
95
  // This runs in the workflow context
65
96
  export async function* streamTextIterator({
66
97
  prompt,
98
+ initialInstructions,
99
+ initialMessages = prompt as unknown as ModelMessage[],
67
100
  tools = {},
68
101
  writable,
69
102
  model,
@@ -84,6 +117,8 @@ export async function* streamTextIterator({
84
117
  experimental_sandbox: sandbox,
85
118
  }: {
86
119
  prompt: LanguageModelV4Prompt;
120
+ initialInstructions?: Instructions;
121
+ initialMessages?: Array<ModelMessage>;
87
122
  tools: ToolSet;
88
123
  writable?: WritableStream<ModelCallStreamPart<ToolSet>>;
89
124
  model: LanguageModel;
@@ -150,6 +185,8 @@ export async function* streamTextIterator({
150
185
  if (prepareStep) {
151
186
  const prepareResult = await prepareStep({
152
187
  model: currentModel,
188
+ initialInstructions,
189
+ initialMessages,
153
190
  stepNumber,
154
191
  steps,
155
192
  messages: conversationPrompt,
@@ -202,79 +239,10 @@ export async function* streamTextIterator({
202
239
  if (prepareResult?.activeTools !== undefined) {
203
240
  currentActiveTools = prepareResult.activeTools;
204
241
  }
205
- // Apply generation settings overrides
206
- if (prepareResult?.maxOutputTokens !== undefined) {
207
- currentGenerationSettings = {
208
- ...currentGenerationSettings,
209
- maxOutputTokens: prepareResult.maxOutputTokens,
210
- };
211
- }
212
- if (prepareResult?.temperature !== undefined) {
213
- currentGenerationSettings = {
214
- ...currentGenerationSettings,
215
- temperature: prepareResult.temperature,
216
- };
217
- }
218
- if (prepareResult?.topP !== undefined) {
219
- currentGenerationSettings = {
220
- ...currentGenerationSettings,
221
- topP: prepareResult.topP,
222
- };
223
- }
224
- if (prepareResult?.topK !== undefined) {
225
- currentGenerationSettings = {
226
- ...currentGenerationSettings,
227
- topK: prepareResult.topK,
228
- };
229
- }
230
- if (prepareResult?.presencePenalty !== undefined) {
231
- currentGenerationSettings = {
232
- ...currentGenerationSettings,
233
- presencePenalty: prepareResult.presencePenalty,
234
- };
235
- }
236
- if (prepareResult?.frequencyPenalty !== undefined) {
237
- currentGenerationSettings = {
238
- ...currentGenerationSettings,
239
- frequencyPenalty: prepareResult.frequencyPenalty,
240
- };
241
- }
242
- if (prepareResult?.stopSequences !== undefined) {
243
- currentGenerationSettings = {
244
- ...currentGenerationSettings,
245
- stopSequences: prepareResult.stopSequences,
246
- };
247
- }
248
- if (prepareResult?.seed !== undefined) {
249
- currentGenerationSettings = {
250
- ...currentGenerationSettings,
251
- seed: prepareResult.seed,
252
- };
253
- }
254
- if (prepareResult?.maxRetries !== undefined) {
255
- currentGenerationSettings = {
256
- ...currentGenerationSettings,
257
- maxRetries: prepareResult.maxRetries,
258
- };
259
- }
260
- if (prepareResult?.headers !== undefined) {
261
- currentGenerationSettings = {
262
- ...currentGenerationSettings,
263
- headers: prepareResult.headers,
264
- };
265
- }
266
- if (prepareResult?.reasoning !== undefined) {
267
- currentGenerationSettings = {
268
- ...currentGenerationSettings,
269
- reasoning: prepareResult.reasoning,
270
- };
271
- }
272
- if (prepareResult?.providerOptions !== undefined) {
273
- currentGenerationSettings = {
274
- ...currentGenerationSettings,
275
- providerOptions: prepareResult.providerOptions,
276
- };
277
- }
242
+ currentGenerationSettings = mergePrepareStepGenerationSettings(
243
+ currentGenerationSettings,
244
+ prepareResult ?? {},
245
+ );
278
246
  if (prepareResult?.toolChoice !== undefined) {
279
247
  currentToolChoice = prepareResult.toolChoice;
280
248
  }
@@ -322,7 +290,10 @@ export async function* streamTextIterator({
322
290
  // Serialize tools before crossing the step boundary — zod schemas
323
291
  // contain functions that can't be serialized by the workflow runtime.
324
292
  // Tools are reconstructed with Ajv validation inside doStreamStep.
325
- const serializedTools = serializeToolSet(effectiveTools);
293
+ const serializedTools = serializeToolSet(effectiveTools, {
294
+ toolsContext: currentToolsContext as never,
295
+ experimental_sandbox: stepSandbox,
296
+ });
326
297
  const modelCallInfo = getModelInfo(currentModel);
327
298
 
328
299
  await telemetryDispatcher.onLanguageModelCallStart?.({
@@ -256,6 +256,16 @@ export interface PrepareStepInfo<
256
256
  */
257
257
  model: LanguageModel;
258
258
 
259
+ /**
260
+ * The initial instructions passed to the stream.
261
+ */
262
+ initialInstructions: Instructions | undefined;
263
+
264
+ /**
265
+ * The initial messages passed to the stream.
266
+ */
267
+ initialMessages: Array<ModelMessage>;
268
+
259
269
  /**
260
270
  * The current step number (0-indexed).
261
271
  */
@@ -371,6 +381,11 @@ export interface PrepareCallOptions<
371
381
  tools: TTools;
372
382
  instructions?: Instructions;
373
383
  toolChoice?: ToolChoice<TTools>;
384
+ stopWhen?:
385
+ | StopCondition<NoInfer<ToolSet>, any>
386
+ | Array<StopCondition<NoInfer<ToolSet>, any>>;
387
+ activeTools?: ActiveTools<NoInfer<TTools>>;
388
+ experimental_download?: DownloadFunction;
374
389
  telemetry?: TelemetryOptions<TRuntimeContext, TTools>;
375
390
  /**
376
391
  * Runtime context that flows through the agent loop.
@@ -837,7 +852,14 @@ export type WorkflowAgentStreamOptions<
837
852
  }
838
853
  ) & {
839
854
  /**
840
- * Optional system prompt override. If provided, overrides the system prompt from the constructor.
855
+ * Instructions override for this stream call.
856
+ */
857
+ instructions?: Instructions;
858
+
859
+ /**
860
+ * Optional system prompt override.
861
+ *
862
+ * @deprecated Use `instructions` instead.
841
863
  */
842
864
  system?: string;
843
865
 
@@ -1324,7 +1346,8 @@ export class WorkflowAgent<
1324
1346
 
1325
1347
  // Call prepareCall to transform parameters before the agent loop
1326
1348
  let effectiveModel: LanguageModel = this.model;
1327
- let effectiveInstructions = options.system ?? this.instructions;
1349
+ let effectiveInstructions =
1350
+ options.instructions ?? options.system ?? this.instructions;
1328
1351
  let effectivePrompt: string | Array<ModelMessage> | undefined =
1329
1352
  options.prompt;
1330
1353
  let effectiveMessages: Array<ModelMessage> | undefined = options.messages;
@@ -1338,6 +1361,11 @@ export class WorkflowAgent<
1338
1361
  Context | undefined
1339
1362
  >;
1340
1363
  let effectiveToolChoiceFromPrepare = options.toolChoice ?? this.toolChoice;
1364
+ let effectiveStopWhenFromPrepare = options.stopWhen ?? this.stopWhen;
1365
+ let effectiveActiveToolsFromPrepare =
1366
+ options.activeTools ?? this.activeTools;
1367
+ let effectiveDownloadFromPrepare =
1368
+ options.experimental_download ?? this.experimentalDownload;
1341
1369
  let effectiveTelemetryFromPrepare = options.telemetry ?? this.telemetry;
1342
1370
 
1343
1371
  // Resolve messages for prepareCall: use messages directly, or convert prompt
@@ -1354,6 +1382,9 @@ export class WorkflowAgent<
1354
1382
  tools: this.tools,
1355
1383
  instructions: effectiveInstructions,
1356
1384
  toolChoice: effectiveToolChoiceFromPrepare as ToolChoice<TBaseTools>,
1385
+ stopWhen: effectiveStopWhenFromPrepare,
1386
+ activeTools: effectiveActiveToolsFromPrepare,
1387
+ experimental_download: effectiveDownloadFromPrepare,
1357
1388
  telemetry: effectiveTelemetryFromPrepare,
1358
1389
  runtimeContext: effectiveRuntimeContext,
1359
1390
  toolsContext: effectiveToolsContext as InferToolSetContext<TBaseTools>,
@@ -1378,6 +1409,12 @@ export class WorkflowAgent<
1378
1409
  if (prepared.toolChoice !== undefined)
1379
1410
  effectiveToolChoiceFromPrepare =
1380
1411
  prepared.toolChoice as ToolChoice<TBaseTools>;
1412
+ if (prepared.stopWhen !== undefined)
1413
+ effectiveStopWhenFromPrepare = prepared.stopWhen;
1414
+ if (prepared.activeTools !== undefined)
1415
+ effectiveActiveToolsFromPrepare = prepared.activeTools;
1416
+ if (prepared.experimental_download !== undefined)
1417
+ effectiveDownloadFromPrepare = prepared.experimental_download;
1381
1418
  if (prepared.telemetry !== undefined)
1382
1419
  effectiveTelemetryFromPrepare = prepared.telemetry;
1383
1420
  if (prepared.maxOutputTokens !== undefined)
@@ -1423,7 +1460,7 @@ export class WorkflowAgent<
1423
1460
  ? { prompt: effectivePrompt }
1424
1461
  : { messages: effectiveMessages! }),
1425
1462
  } as Prompt);
1426
- const download = options.experimental_download ?? this.experimentalDownload;
1463
+ const download = effectiveDownloadFromPrepare;
1427
1464
  const sandbox = options.experimental_sandbox ?? this.experimentalSandbox;
1428
1465
 
1429
1466
  // Process tool approval responses before starting the agent loop.
@@ -1832,7 +1869,7 @@ export class WorkflowAgent<
1832
1869
  const effectiveToolChoice = effectiveToolChoiceFromPrepare;
1833
1870
 
1834
1871
  // Filter tools if activeTools is specified (stream-level overrides constructor default)
1835
- const effectiveActiveTools = options.activeTools ?? this.activeTools;
1872
+ const effectiveActiveTools = effectiveActiveToolsFromPrepare;
1836
1873
  const effectiveTools =
1837
1874
  effectiveActiveTools && effectiveActiveTools.length > 0
1838
1875
  ? (filterActiveTools({
@@ -2100,8 +2137,9 @@ export class WorkflowAgent<
2100
2137
  tools: effectiveTools as ToolSet,
2101
2138
  writable: options.writable,
2102
2139
  prompt: modelPrompt,
2103
- stopConditions: options.stopWhen ?? this.stopWhen,
2104
-
2140
+ initialInstructions: effectiveInstructions,
2141
+ initialMessages: prompt.messages,
2142
+ stopConditions: effectiveStopWhenFromPrepare,
2105
2143
  onStepEnd: mergedOnStepEnd as any,
2106
2144
  onStepStart: mergedOnStepStart as any,
2107
2145
  onError: options.onError,