@ai-sdk/workflow 2.0.17 → 2.0.18

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": "2.0.17",
3
+ "version": "2.0.18",
4
4
  "type": "module",
5
5
  "description": "WorkflowAgent for building AI agents with AI SDK",
6
6
  "license": "Apache-2.0",
@@ -33,7 +33,7 @@
33
33
  "dependencies": {
34
34
  "@ai-sdk/provider": "4.0.9",
35
35
  "@ai-sdk/provider-utils": "5.0.34",
36
- "ai": "7.0.87",
36
+ "ai": "7.0.88",
37
37
  "ajv": "^8.20.0"
38
38
  },
39
39
  "devDependencies": {
@@ -7,6 +7,7 @@ import type {
7
7
  import type { Context } from '@ai-sdk/provider-utils';
8
8
  import {
9
9
  experimental_filterActiveTools as filterActiveTools,
10
+ type ActiveTools,
10
11
  type Experimental_SandboxSession as SandboxSession,
11
12
  type Instructions,
12
13
  type LanguageModel,
@@ -164,7 +165,7 @@ export async function* streamTextIterator({
164
165
  let currentRuntimeContext: Context = runtimeContext ?? {};
165
166
  let currentToolsContext: Record<string, Context | undefined> =
166
167
  toolsContext ?? {};
167
- let currentActiveTools: string[] | undefined;
168
+ let currentActiveTools: ActiveTools<ToolSet>;
168
169
 
169
170
  const steps: StepResult<any, any>[] = [];
170
171
  let done = false;
@@ -28,6 +28,7 @@ import {
28
28
  type ToolCallRepairFunction,
29
29
  type ToolChoice,
30
30
  type ToolSet,
31
+ type InferUITools,
31
32
  type UIMessage,
32
33
  type LanguageModel,
33
34
  type Prompt,
@@ -84,9 +85,13 @@ export type InferWorkflowAgentTools<WORKFLOW_AGENT> =
84
85
  * Infer the UI message type of a workflow agent.
85
86
  */
86
87
  export type InferWorkflowAgentUIMessage<
87
- _WORKFLOW_AGENT,
88
+ WORKFLOW_AGENT,
88
89
  MESSAGE_METADATA = unknown,
89
- > = UIMessage<MESSAGE_METADATA>;
90
+ > = UIMessage<
91
+ MESSAGE_METADATA,
92
+ never,
93
+ InferUITools<InferWorkflowAgentTools<WORKFLOW_AGENT>>
94
+ >;
90
95
 
91
96
  /**
92
97
  * Re-export the Output helper for structured output specifications.
@@ -349,7 +354,7 @@ export interface PrepareStepResult<
349
354
  * Override the active tools for this step.
350
355
  * Limits the tools that are available for the model to call.
351
356
  */
352
- activeTools?: string[];
357
+ activeTools?: ActiveTools<NoInfer<TTools>>;
353
358
 
354
359
  /**
355
360
  * Updated runtime context for the current and subsequent steps.
@@ -605,6 +610,13 @@ export type WorkflowAgentOptions<
605
610
  /**
606
611
  * Callback called when the agent starts streaming, before any LLM calls.
607
612
  */
613
+ onStart?: WorkflowAgentOnStartCallback<TTools, TRuntimeContext>;
614
+
615
+ /**
616
+ * Callback called when the agent starts streaming, before any LLM calls.
617
+ *
618
+ * @deprecated Use `onStart` instead.
619
+ */
608
620
  experimental_onStart?: WorkflowAgentOnStartCallback<
609
621
  TTools,
610
622
  TRuntimeContext
@@ -613,6 +625,13 @@ export type WorkflowAgentOptions<
613
625
  /**
614
626
  * Callback called before each step (LLM call) begins.
615
627
  */
628
+ onStepStart?: WorkflowAgentOnStepStartCallback<TTools, TRuntimeContext>;
629
+
630
+ /**
631
+ * Callback called before each step (LLM call) begins.
632
+ *
633
+ * @deprecated Use `onStepStart` instead.
634
+ */
616
635
  experimental_onStepStart?: WorkflowAgentOnStepStartCallback<
617
636
  TTools,
618
637
  TRuntimeContext
@@ -1080,6 +1099,13 @@ export type WorkflowAgentStreamOptions<
1080
1099
  /**
1081
1100
  * Callback called when the agent starts streaming, before any LLM calls.
1082
1101
  */
1102
+ onStart?: WorkflowAgentOnStartCallback<TTools, TRuntimeContext>;
1103
+
1104
+ /**
1105
+ * Callback called when the agent starts streaming, before any LLM calls.
1106
+ *
1107
+ * @deprecated Use `onStart` instead.
1108
+ */
1083
1109
  experimental_onStart?: WorkflowAgentOnStartCallback<
1084
1110
  TTools,
1085
1111
  TRuntimeContext
@@ -1088,6 +1114,13 @@ export type WorkflowAgentStreamOptions<
1088
1114
  /**
1089
1115
  * Callback called before each step (LLM call) begins.
1090
1116
  */
1117
+ onStepStart?: WorkflowAgentOnStepStartCallback<TTools, TRuntimeContext>;
1118
+
1119
+ /**
1120
+ * Callback called before each step (LLM call) begins.
1121
+ *
1122
+ * @deprecated Use `onStepStart` instead.
1123
+ */
1091
1124
  experimental_onStepStart?: WorkflowAgentOnStepStartCallback<
1092
1125
  TTools,
1093
1126
  TRuntimeContext
@@ -1350,8 +1383,9 @@ export class WorkflowAgent<
1350
1383
  this.constructorOnStepEnd = options.onStepEnd ?? options.onStepFinish;
1351
1384
  const { onFinish, onEnd = onFinish } = options;
1352
1385
  this.constructorOnEnd = onEnd;
1353
- this.constructorOnStart = options.experimental_onStart;
1354
- this.constructorOnStepStart = options.experimental_onStepStart;
1386
+ this.constructorOnStart = options.onStart ?? options.experimental_onStart;
1387
+ this.constructorOnStepStart =
1388
+ options.onStepStart ?? options.experimental_onStepStart;
1355
1389
  this.constructorOnToolExecutionStart = options.onToolExecutionStart;
1356
1390
  this.constructorOnToolExecutionEnd = options.onToolExecutionEnd;
1357
1391
  this.prepareCall = options.prepareCall;
@@ -1518,6 +1552,14 @@ export class WorkflowAgent<
1518
1552
  } as Prompt);
1519
1553
  const download = effectiveDownloadFromPrepare;
1520
1554
  const sandbox = options.experimental_sandbox ?? this.experimentalSandbox;
1555
+ const mergedOnToolExecutionStart = mergeCallbacks(
1556
+ this.constructorOnToolExecutionStart,
1557
+ options.onToolExecutionStart,
1558
+ );
1559
+ const mergedOnToolExecutionEnd = mergeCallbacks(
1560
+ this.constructorOnToolExecutionEnd,
1561
+ options.onToolExecutionEnd,
1562
+ );
1521
1563
 
1522
1564
  // Process tool approval responses before starting the agent loop.
1523
1565
  // This mirrors how stream-text.ts handles tool-approval-response parts:
@@ -1663,110 +1705,25 @@ export class WorkflowAgent<
1663
1705
  continue;
1664
1706
  }
1665
1707
 
1666
- try {
1667
- const { execute } = tool;
1668
- const resolvedContext = await resolveToolContext({
1669
- toolName: approval.toolName,
1670
- tool,
1671
- toolsContext: effectiveToolsContext,
1672
- });
1673
- const toolCallEvent: ToolCall = {
1674
- type: 'tool-call',
1675
- toolCallId: approval.toolCallId,
1676
- toolName: approval.toolName,
1677
- input: approval.input,
1678
- };
1679
- const messages = prompt.messages as unknown as ModelMessage[];
1680
- await telemetryDispatcher.onToolExecutionStart?.({
1681
- toolCall: toolCallEvent,
1682
- stepNumber: 0,
1683
- messages,
1684
- toolContext: resolvedContext,
1685
- });
1686
- const startTime = Date.now();
1687
- const executeApprovedTool = () =>
1688
- execute(approval.input, {
1689
- toolCallId: approval.toolCallId,
1690
- messages: [],
1691
- context: resolvedContext,
1692
- experimental_sandbox: sandbox,
1693
- });
1694
- const toolResult =
1695
- telemetryDispatcher.executeTool != null
1696
- ? await telemetryDispatcher.executeTool({
1697
- callId: 'workflow-agent',
1698
- toolCallId: approval.toolCallId,
1699
- execute: executeApprovedTool,
1700
- })
1701
- : await executeApprovedTool();
1702
- await telemetryDispatcher.onToolExecutionEnd?.({
1703
- toolCall: toolCallEvent,
1704
- stepNumber: 0,
1705
- durationMs: Date.now() - startTime,
1706
- messages,
1707
- toolContext: resolvedContext,
1708
- success: true,
1709
- output: toolResult,
1710
- });
1711
- toolResultContent.push({
1712
- type: 'tool-result' as const,
1713
- toolCallId: approval.toolCallId,
1714
- toolName: approval.toolName,
1715
- output: await createLanguageModelToolResultOutput({
1716
- toolCallId: approval.toolCallId,
1717
- toolName: approval.toolName,
1718
- input: approval.input,
1719
- output: toolResult,
1720
- tool,
1721
- errorMode: 'none',
1722
- supportedUrls: {},
1723
- download,
1724
- }),
1725
- });
1726
- approvedRawResults.push({
1727
- toolCallId: approval.toolCallId,
1728
- toolName: approval.toolName,
1729
- input: approval.input,
1730
- output: toolResult,
1731
- });
1732
- } catch (error) {
1733
- const errorMessage = getErrorMessage(error);
1734
- await telemetryDispatcher.onToolExecutionEnd?.({
1735
- toolCall: {
1736
- type: 'tool-call',
1737
- toolCallId: approval.toolCallId,
1738
- toolName: approval.toolName,
1739
- input: approval.input,
1740
- },
1741
- stepNumber: 0,
1742
- durationMs: 0,
1743
- messages: prompt.messages as unknown as ModelMessage[],
1744
- toolContext: undefined,
1745
- success: false,
1746
- error,
1747
- });
1748
- toolResultContent.push({
1749
- type: 'tool-result' as const,
1750
- toolCallId: approval.toolCallId,
1751
- toolName: approval.toolName,
1752
- output: await createLanguageModelToolResultOutput({
1753
- toolCallId: approval.toolCallId,
1754
- toolName: approval.toolName,
1755
- input: approval.input,
1756
- output: errorMessage,
1757
- tool,
1758
- errorMode: 'text',
1759
- supportedUrls: {},
1760
- download,
1761
- }),
1762
- });
1763
- approvedRawResults.push({
1708
+ const result = await executeToolWithCallbacks(
1709
+ {
1764
1710
  toolCallId: approval.toolCallId,
1765
1711
  toolName: approval.toolName,
1766
1712
  input: approval.input,
1767
- output: errorMessage,
1768
- });
1769
- }
1713
+ },
1714
+ this.tools as ToolSet,
1715
+ prompt.messages as unknown as LanguageModelV4Prompt,
1716
+ effectiveToolsContext,
1717
+ 0,
1718
+ sandbox,
1719
+ );
1720
+ toolResultContent.push(result.modelResult);
1721
+ approvedRawResults.push({
1722
+ toolCallId: approval.toolCallId,
1723
+ toolName: approval.toolName,
1724
+ input: approval.input,
1725
+ output: result.rawOutput,
1726
+ });
1770
1727
  }
1771
1728
  }
1772
1729
 
@@ -1918,23 +1875,14 @@ export class WorkflowAgent<
1918
1875
  this.constructorOnStart as
1919
1876
  | WorkflowAgentOnStartCallback<TTools, TRuntimeContext>
1920
1877
  | undefined,
1921
- options.experimental_onStart,
1878
+ options.onStart ?? options.experimental_onStart,
1922
1879
  );
1923
1880
  const mergedOnStepStart = mergeCallbacks(
1924
1881
  this.constructorOnStepStart as
1925
1882
  | WorkflowAgentOnStepStartCallback<TTools, TRuntimeContext>
1926
1883
  | undefined,
1927
- options.experimental_onStepStart,
1928
- );
1929
- const mergedOnToolExecutionStart = mergeCallbacks(
1930
- this.constructorOnToolExecutionStart,
1931
- options.onToolExecutionStart,
1884
+ options.onStepStart ?? options.experimental_onStepStart,
1932
1885
  );
1933
- const mergedOnToolExecutionEnd = mergeCallbacks(
1934
- this.constructorOnToolExecutionEnd,
1935
- options.onToolExecutionEnd,
1936
- );
1937
-
1938
1886
  // Determine effective tool choice
1939
1887
  const effectiveToolChoice = effectiveToolChoiceFromPrepare;
1940
1888
 
@@ -1998,14 +1946,14 @@ export class WorkflowAgent<
1998
1946
  });
1999
1947
 
2000
1948
  // Helper to wrap executeTool with onToolExecutionStart/onToolExecutionEnd callbacks
2001
- const executeToolWithCallbacks = async (
1949
+ async function executeToolWithCallbacks(
2002
1950
  toolCall: { toolCallId: string; toolName: string; input: unknown },
2003
1951
  tools: ToolSet,
2004
1952
  messages: LanguageModelV4Prompt,
2005
1953
  perToolContexts: Record<string, Context | undefined>,
2006
1954
  currentStepNumber: number = 0,
2007
1955
  stepSandbox?: SandboxSession,
2008
- ): Promise<WorkflowToolExecutionResult> => {
1956
+ ): Promise<WorkflowToolExecutionResult> {
2009
1957
  const toolCallEvent: ToolCall = {
2010
1958
  type: 'tool-call',
2011
1959
  toolCallId: toolCall.toolCallId,
@@ -2145,7 +2093,7 @@ export class WorkflowAgent<
2145
2093
  });
2146
2094
  }
2147
2095
  return result;
2148
- };
2096
+ }
2149
2097
 
2150
2098
  const recordProviderExecutedToolTelemetry = async (
2151
2099
  toolCall: { toolCallId: string; toolName: string; input: unknown },
@@ -2437,7 +2385,18 @@ export class WorkflowAgent<
2437
2385
  // so useChat can show the approval UI
2438
2386
  if (options.writable) {
2439
2387
  if (allToolResults.length > 0) {
2440
- await writeToolResults(options.writable, allToolResults);
2388
+ await writeToolResults(
2389
+ options.writable,
2390
+ executedResults.map(r => ({
2391
+ toolCallId: r.modelResult.toolCallId,
2392
+ toolName: r.modelResult.toolName,
2393
+ input: toolCalls.find(
2394
+ tc => tc.toolCallId === r.modelResult.toolCallId,
2395
+ )?.input,
2396
+ output: r.rawOutput,
2397
+ isError: r.isError,
2398
+ })),
2399
+ );
2441
2400
  }
2442
2401
 
2443
2402
  const approvalToolCalls = pausedToolCalls.filter((_, i) => {
@@ -2562,9 +2521,9 @@ export class WorkflowAgent<
2562
2521
  return [];
2563
2522
  });
2564
2523
 
2565
- // Write tool results and step boundaries to the stream so the
2566
- // UI can transition tool parts to output-available state and
2567
- // properly separate multi-step model calls in the message history.
2524
+ // Write tool results and step boundaries to the stream so the UI can
2525
+ // transition tool parts to the appropriate output state and properly
2526
+ // separate multi-step model calls in the message history.
2568
2527
  if (options.writable) {
2569
2528
  await writeToolResults(
2570
2529
  options.writable,
@@ -2575,6 +2534,7 @@ export class WorkflowAgent<
2575
2534
  tc => tc.toolCallId === r.modelResult.toolCallId,
2576
2535
  )?.input,
2577
2536
  output: r.rawOutput,
2537
+ isError: r.isError,
2578
2538
  })),
2579
2539
  true,
2580
2540
  );
@@ -2937,6 +2897,7 @@ async function writeToolResults(
2937
2897
  toolName: string;
2938
2898
  input: unknown;
2939
2899
  output: unknown;
2900
+ isError: boolean;
2940
2901
  }>,
2941
2902
  writeStepBoundary = false,
2942
2903
  ) {
@@ -2944,13 +2905,23 @@ async function writeToolResults(
2944
2905
  const writer = writable.getWriter();
2945
2906
  try {
2946
2907
  for (const r of results) {
2947
- await writer.write({
2948
- type: 'tool-result',
2949
- toolCallId: r.toolCallId,
2950
- toolName: r.toolName,
2951
- input: r.input,
2952
- output: r.output,
2953
- });
2908
+ await writer.write(
2909
+ r.isError
2910
+ ? {
2911
+ type: 'tool-error',
2912
+ toolCallId: r.toolCallId,
2913
+ toolName: r.toolName,
2914
+ input: r.input,
2915
+ error: r.output,
2916
+ }
2917
+ : {
2918
+ type: 'tool-result',
2919
+ toolCallId: r.toolCallId,
2920
+ toolName: r.toolName,
2921
+ input: r.input,
2922
+ output: r.output,
2923
+ },
2924
+ );
2954
2925
  }
2955
2926
  if (writeStepBoundary) {
2956
2927
  // Emit step boundaries so the UI message history properly separates