@ai-sdk/workflow 1.0.0-beta.26 → 1.0.0-beta.28
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 +44 -0
- package/dist/index.d.mts +5 -5
- package/dist/index.mjs +51 -17
- package/dist/index.mjs.map +1 -1
- package/package.json +8 -6
- package/src/do-stream-step.ts +1 -0
- package/src/serializable-schema.ts +4 -0
- package/src/workflow-agent.ts +65 -26
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-sdk/workflow",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.28",
|
|
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-beta.
|
|
31
|
-
"@ai-sdk/provider-utils": "5.0.0-beta.
|
|
32
|
-
"ai": "7.0.0-beta.
|
|
30
|
+
"@ai-sdk/provider": "4.0.0-beta.13",
|
|
31
|
+
"@ai-sdk/provider-utils": "5.0.0-beta.28",
|
|
32
|
+
"ai": "7.0.0-beta.113"
|
|
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
|
@@ -115,6 +115,7 @@ export async function doStreamStep(
|
|
|
115
115
|
// pre-converted LanguageModelV4Prompt. standardizePrompt inside
|
|
116
116
|
// streamModelCall handles both formats.
|
|
117
117
|
messages: conversationPrompt as unknown as ModelMessage[],
|
|
118
|
+
allowSystemInMessages: true,
|
|
118
119
|
tools,
|
|
119
120
|
toolChoice: options?.toolChoice,
|
|
120
121
|
includeRawChunks: options?.includeRawChunks,
|
|
@@ -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
|
];
|
package/src/workflow-agent.ts
CHANGED
|
@@ -14,10 +14,12 @@ import {
|
|
|
14
14
|
type Experimental_LanguageModelStreamPart as ModelCallStreamPart,
|
|
15
15
|
type ModelMessage,
|
|
16
16
|
Output,
|
|
17
|
+
Prompt,
|
|
17
18
|
type StepResult,
|
|
18
19
|
type StopCondition,
|
|
19
|
-
type
|
|
20
|
+
type GenerateTextOnStepFinishCallback,
|
|
20
21
|
type SystemModelMessage,
|
|
22
|
+
type ActiveTools,
|
|
21
23
|
type ToolCallRepairFunction,
|
|
22
24
|
type ToolChoice,
|
|
23
25
|
type ToolSet,
|
|
@@ -37,12 +39,12 @@ export type { CompatibleLanguageModel } from './types.js';
|
|
|
37
39
|
|
|
38
40
|
/**
|
|
39
41
|
* Callback function to be called after each step completes.
|
|
40
|
-
* Alias for the AI SDK's
|
|
42
|
+
* Alias for the AI SDK's GenerateTextOnStepFinishCallback, using
|
|
41
43
|
* WorkflowAgent-consistent naming.
|
|
42
44
|
*/
|
|
43
45
|
export type WorkflowAgentOnStepFinishCallback<
|
|
44
46
|
TTools extends ToolSet = ToolSet,
|
|
45
|
-
> =
|
|
47
|
+
> = GenerateTextOnStepFinishCallback<TTools, any>;
|
|
46
48
|
|
|
47
49
|
/**
|
|
48
50
|
* Infer the type of the tools of a workflow agent.
|
|
@@ -445,7 +447,7 @@ export interface WorkflowAgentOptions<
|
|
|
445
447
|
*
|
|
446
448
|
* Per-stream `activeTools` values passed to `stream()` override this default.
|
|
447
449
|
*/
|
|
448
|
-
activeTools?:
|
|
450
|
+
activeTools?: ActiveTools<NoInfer<TTools>>;
|
|
449
451
|
|
|
450
452
|
/**
|
|
451
453
|
* Default output specification for structured outputs.
|
|
@@ -735,7 +737,7 @@ export type WorkflowAgentStreamOptions<
|
|
|
735
737
|
* Limits the tools that are available for the model to call without
|
|
736
738
|
* changing the tool call and result types in the result.
|
|
737
739
|
*/
|
|
738
|
-
activeTools?:
|
|
740
|
+
activeTools?: ActiveTools<NoInfer<TTools>>;
|
|
739
741
|
|
|
740
742
|
/**
|
|
741
743
|
* Optional telemetry configuration.
|
|
@@ -1021,7 +1023,7 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1021
1023
|
private stopWhen?:
|
|
1022
1024
|
| StopCondition<ToolSet, any>
|
|
1023
1025
|
| Array<StopCondition<ToolSet, any>>;
|
|
1024
|
-
private activeTools?:
|
|
1026
|
+
private activeTools?: ActiveTools<TBaseTools>;
|
|
1025
1027
|
private output?: OutputSpecification<any, any>;
|
|
1026
1028
|
private experimentalRepairToolCall?: ToolCallRepairFunction<TBaseTools>;
|
|
1027
1029
|
private experimentalDownload?: DownloadFunction;
|
|
@@ -1162,10 +1164,11 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1162
1164
|
|
|
1163
1165
|
const prompt = await standardizePrompt({
|
|
1164
1166
|
system: effectiveInstructions,
|
|
1167
|
+
allowSystemInMessages: true, // TODO: consider exposing this as a parameter
|
|
1165
1168
|
...(effectivePrompt != null
|
|
1166
1169
|
? { prompt: effectivePrompt }
|
|
1167
1170
|
: { messages: effectiveMessages! }),
|
|
1168
|
-
});
|
|
1171
|
+
} as Prompt);
|
|
1169
1172
|
|
|
1170
1173
|
// Process tool approval responses before starting the agent loop.
|
|
1171
1174
|
// This mirrors how stream-text.ts handles tool-approval-response parts:
|
|
@@ -1376,7 +1379,7 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1376
1379
|
effectiveActiveTools && effectiveActiveTools.length > 0
|
|
1377
1380
|
? (filterActiveTools({
|
|
1378
1381
|
tools: this.tools,
|
|
1379
|
-
activeTools: effectiveActiveTools
|
|
1382
|
+
activeTools: effectiveActiveTools,
|
|
1380
1383
|
}) ?? this.tools)
|
|
1381
1384
|
: this.tools;
|
|
1382
1385
|
|
|
@@ -1542,11 +1545,16 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1542
1545
|
|
|
1543
1546
|
// Only execute tools if there are tool calls
|
|
1544
1547
|
if (toolCalls.length > 0) {
|
|
1548
|
+
const invalidToolCalls = toolCalls.filter(tc => tc.invalid === true);
|
|
1549
|
+
const validToolCalls = toolCalls.filter(tc => tc.invalid !== true);
|
|
1550
|
+
|
|
1545
1551
|
// Separate provider-executed tool calls from client-executed ones
|
|
1546
|
-
const nonProviderToolCalls =
|
|
1552
|
+
const nonProviderToolCalls = validToolCalls.filter(
|
|
1547
1553
|
tc => !tc.providerExecuted,
|
|
1548
1554
|
);
|
|
1549
|
-
const providerToolCalls =
|
|
1555
|
+
const providerToolCalls = validToolCalls.filter(
|
|
1556
|
+
tc => tc.providerExecuted,
|
|
1557
|
+
);
|
|
1550
1558
|
|
|
1551
1559
|
// Check which tools need approval (can be async)
|
|
1552
1560
|
const approvalNeeded = await Promise.all(
|
|
@@ -1610,7 +1618,15 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1610
1618
|
),
|
|
1611
1619
|
);
|
|
1612
1620
|
|
|
1613
|
-
const
|
|
1621
|
+
const continuationInvalidResults = invalidToolCalls.map(
|
|
1622
|
+
createInvalidToolResult,
|
|
1623
|
+
);
|
|
1624
|
+
const resolvedResults = [
|
|
1625
|
+
...executableResults,
|
|
1626
|
+
...providerResults,
|
|
1627
|
+
...continuationInvalidResults,
|
|
1628
|
+
];
|
|
1629
|
+
const executedResults = [...executableResults, ...providerResults];
|
|
1614
1630
|
|
|
1615
1631
|
const allToolCalls: ToolCall[] = toolCalls.map(tc => ({
|
|
1616
1632
|
type: 'tool-call' as const,
|
|
@@ -1619,7 +1635,7 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1619
1635
|
input: tc.input,
|
|
1620
1636
|
}));
|
|
1621
1637
|
|
|
1622
|
-
const allToolResults: ToolResult[] =
|
|
1638
|
+
const allToolResults: ToolResult[] = executedResults.map(r => ({
|
|
1623
1639
|
type: 'tool-result' as const,
|
|
1624
1640
|
toolCallId: r.toolCallId,
|
|
1625
1641
|
toolName: r.toolName,
|
|
@@ -1707,25 +1723,32 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1707
1723
|
providerToolCalls.map(toolCall =>
|
|
1708
1724
|
resolveProviderToolResult(toolCall, providerExecutedToolResults),
|
|
1709
1725
|
);
|
|
1726
|
+
const continuationInvalidToolResults = invalidToolCalls.map(
|
|
1727
|
+
createInvalidToolResult,
|
|
1728
|
+
);
|
|
1710
1729
|
|
|
1711
|
-
// Combine results in the original order
|
|
1712
|
-
|
|
1730
|
+
// Combine executable/provider results in the original order,
|
|
1731
|
+
// while preserving invalid tool calls as error results for the
|
|
1732
|
+
// next model step without emitting them as synthetic UI success.
|
|
1733
|
+
const continuationToolResults = toolCalls.flatMap(tc => {
|
|
1734
|
+
const invalidResult = continuationInvalidToolResults.find(
|
|
1735
|
+
r => r.toolCallId === tc.toolCallId,
|
|
1736
|
+
);
|
|
1737
|
+
if (invalidResult) return [invalidResult];
|
|
1713
1738
|
const clientResult = clientToolResults.find(
|
|
1714
1739
|
r => r.toolCallId === tc.toolCallId,
|
|
1715
1740
|
);
|
|
1716
|
-
if (clientResult) return clientResult;
|
|
1741
|
+
if (clientResult) return [clientResult];
|
|
1717
1742
|
const providerResult = providerToolResults.find(
|
|
1718
1743
|
r => r.toolCallId === tc.toolCallId,
|
|
1719
1744
|
);
|
|
1720
|
-
if (providerResult) return providerResult;
|
|
1721
|
-
|
|
1722
|
-
return {
|
|
1723
|
-
type: 'tool-result' as const,
|
|
1724
|
-
toolCallId: tc.toolCallId,
|
|
1725
|
-
toolName: tc.toolName,
|
|
1726
|
-
output: { type: 'text' as const, value: '' },
|
|
1727
|
-
};
|
|
1745
|
+
if (providerResult) return [providerResult];
|
|
1746
|
+
return [];
|
|
1728
1747
|
});
|
|
1748
|
+
const executedToolResults = continuationToolResults.filter(
|
|
1749
|
+
result =>
|
|
1750
|
+
!invalidToolCalls.some(tc => tc.toolCallId === result.toolCallId),
|
|
1751
|
+
);
|
|
1729
1752
|
|
|
1730
1753
|
// Write tool results and step boundaries to the stream so the
|
|
1731
1754
|
// UI can transition tool parts to output-available state and
|
|
@@ -1733,7 +1756,7 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1733
1756
|
if (options.writable) {
|
|
1734
1757
|
await writeToolResultsWithStepBoundary(
|
|
1735
1758
|
options.writable,
|
|
1736
|
-
|
|
1759
|
+
executedToolResults.map(r => ({
|
|
1737
1760
|
toolCallId: r.toolCallId,
|
|
1738
1761
|
toolName: r.toolName,
|
|
1739
1762
|
input: toolCalls.find(tc => tc.toolCallId === r.toolCallId)
|
|
@@ -1750,7 +1773,7 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1750
1773
|
toolName: tc.toolName,
|
|
1751
1774
|
input: tc.input,
|
|
1752
1775
|
}));
|
|
1753
|
-
lastStepToolResults =
|
|
1776
|
+
lastStepToolResults = executedToolResults.map(r => ({
|
|
1754
1777
|
type: 'tool-result' as const,
|
|
1755
1778
|
toolCallId: r.toolCallId,
|
|
1756
1779
|
toolName: r.toolName,
|
|
@@ -1758,7 +1781,7 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1758
1781
|
output: 'value' in r.output ? r.output.value : undefined,
|
|
1759
1782
|
}));
|
|
1760
1783
|
|
|
1761
|
-
result = await iterator.next(
|
|
1784
|
+
result = await iterator.next(continuationToolResults);
|
|
1762
1785
|
} else {
|
|
1763
1786
|
// Final step with no tool calls - reset tracking
|
|
1764
1787
|
lastStepToolCalls = [];
|
|
@@ -2060,6 +2083,22 @@ function resolveProviderToolResult(
|
|
|
2060
2083
|
};
|
|
2061
2084
|
}
|
|
2062
2085
|
|
|
2086
|
+
function createInvalidToolResult(toolCall: {
|
|
2087
|
+
toolCallId: string;
|
|
2088
|
+
toolName: string;
|
|
2089
|
+
error?: unknown;
|
|
2090
|
+
}): LanguageModelV4ToolResultPart {
|
|
2091
|
+
return {
|
|
2092
|
+
type: 'tool-result' as const,
|
|
2093
|
+
toolCallId: toolCall.toolCallId,
|
|
2094
|
+
toolName: toolCall.toolName,
|
|
2095
|
+
output: {
|
|
2096
|
+
type: 'error-text' as const,
|
|
2097
|
+
value: getErrorMessage(toolCall.error),
|
|
2098
|
+
},
|
|
2099
|
+
};
|
|
2100
|
+
}
|
|
2101
|
+
|
|
2063
2102
|
async function executeTool(
|
|
2064
2103
|
toolCall: { toolCallId: string; toolName: string; input: unknown },
|
|
2065
2104
|
tools: ToolSet,
|