@ai-sdk/workflow 1.0.67 → 1.0.68
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 +8 -0
- package/dist/index.d.ts +9 -2
- package/dist/index.js +90 -44
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/do-stream-step.ts +59 -30
- package/src/providers/mock-function-wrapper.ts +24 -14
- package/src/providers/mock.ts +2 -1
- package/src/stream-text-iterator.ts +25 -2
- package/src/test/agent-e2e-workflows.ts +41 -0
- package/src/test/retrying-model.ts +79 -0
- package/src/workflow-agent.ts +29 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# @ai-sdk/workflow
|
|
2
2
|
|
|
3
|
+
## 1.0.68
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- e6064c5: Honor `WorkflowAgent` model-call retry settings without stacking workflow step retries.
|
|
8
|
+
- 83f9b12: Expose the original value from model stream error parts on resolved WorkflowAgent results without retrying the durable model step.
|
|
9
|
+
- ai@7.0.67
|
|
10
|
+
|
|
3
11
|
## 1.0.67
|
|
4
12
|
|
|
5
13
|
### Patch Changes
|
package/dist/index.d.ts
CHANGED
|
@@ -137,8 +137,7 @@ interface GenerationSettings {
|
|
|
137
137
|
*/
|
|
138
138
|
seed?: number;
|
|
139
139
|
/**
|
|
140
|
-
* Maximum number of retries. Set to 0 to disable retries.
|
|
141
|
-
* Note: In workflow context, retries are typically handled by the workflow step mechanism.
|
|
140
|
+
* Maximum number of retries for retryable model call failures. Set to 0 to disable retries.
|
|
142
141
|
* @default 2
|
|
143
142
|
*/
|
|
144
143
|
maxRetries?: number;
|
|
@@ -911,6 +910,14 @@ interface WorkflowAgentStreamResult<TTools extends ToolSet = ToolSet, OUTPUT = n
|
|
|
911
910
|
* The finish reason from the last step.
|
|
912
911
|
*/
|
|
913
912
|
finishReason: FinishReason;
|
|
913
|
+
/**
|
|
914
|
+
* The original value from a model stream error part.
|
|
915
|
+
*
|
|
916
|
+
* This property is present when the model emitted an error part, including
|
|
917
|
+
* when the supplied value is `undefined`. Check with `'error' in result` to
|
|
918
|
+
* distinguish that case from a result without a model stream error.
|
|
919
|
+
*/
|
|
920
|
+
error?: unknown;
|
|
914
921
|
/**
|
|
915
922
|
* The total token usage across all steps.
|
|
916
923
|
*/
|
package/dist/index.js
CHANGED
|
@@ -79,6 +79,7 @@ import {
|
|
|
79
79
|
experimental_streamLanguageModelCall as streamModelCall,
|
|
80
80
|
gateway
|
|
81
81
|
} from "ai";
|
|
82
|
+
import { prepareRetries } from "ai/internal";
|
|
82
83
|
|
|
83
84
|
// src/serializable-schema.ts
|
|
84
85
|
import {
|
|
@@ -189,36 +190,47 @@ async function doStreamStep(conversationPrompt, modelInit, writable, serializedT
|
|
|
189
190
|
return void 0;
|
|
190
191
|
}
|
|
191
192
|
};
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
// pre-converted LanguageModelV4Prompt. standardizePrompt inside
|
|
196
|
-
// streamModelCall handles both formats.
|
|
197
|
-
messages: conversationPrompt,
|
|
198
|
-
allowSystemInMessages: true,
|
|
199
|
-
tools,
|
|
200
|
-
toolChoice: options == null ? void 0 : options.toolChoice,
|
|
201
|
-
includeRawChunks: options == null ? void 0 : options.includeRawChunks,
|
|
202
|
-
providerOptions: options == null ? void 0 : options.providerOptions,
|
|
203
|
-
abortSignal,
|
|
204
|
-
headers: options == null ? void 0 : options.headers,
|
|
205
|
-
reasoning: options == null ? void 0 : options.reasoning,
|
|
206
|
-
output,
|
|
207
|
-
maxOutputTokens: options == null ? void 0 : options.maxOutputTokens,
|
|
208
|
-
temperature: options == null ? void 0 : options.temperature,
|
|
209
|
-
topP: options == null ? void 0 : options.topP,
|
|
210
|
-
topK: options == null ? void 0 : options.topK,
|
|
211
|
-
presencePenalty: options == null ? void 0 : options.presencePenalty,
|
|
212
|
-
frequencyPenalty: options == null ? void 0 : options.frequencyPenalty,
|
|
213
|
-
stopSequences: options == null ? void 0 : options.stopSequences,
|
|
214
|
-
seed: options == null ? void 0 : options.seed,
|
|
215
|
-
repairToolCall: options == null ? void 0 : options.repairToolCall
|
|
216
|
-
}).then((result) => result.stream).catch((error) => {
|
|
217
|
-
if ((abortSignal == null ? void 0 : abortSignal.aborted) && isAbortError(error)) {
|
|
218
|
-
return void 0;
|
|
219
|
-
}
|
|
220
|
-
throw error;
|
|
193
|
+
const { retry } = prepareRetries({
|
|
194
|
+
maxRetries: options == null ? void 0 : options.maxRetries,
|
|
195
|
+
abortSignal
|
|
221
196
|
});
|
|
197
|
+
const modelStream = await (async () => {
|
|
198
|
+
try {
|
|
199
|
+
const { stream } = await retry(
|
|
200
|
+
() => streamModelCall({
|
|
201
|
+
model,
|
|
202
|
+
// streamModelCall expects Prompt (ModelMessage[]) but we pass the
|
|
203
|
+
// pre-converted LanguageModelV4Prompt. standardizePrompt inside
|
|
204
|
+
// streamModelCall handles both formats.
|
|
205
|
+
messages: conversationPrompt,
|
|
206
|
+
allowSystemInMessages: true,
|
|
207
|
+
tools,
|
|
208
|
+
toolChoice: options == null ? void 0 : options.toolChoice,
|
|
209
|
+
includeRawChunks: options == null ? void 0 : options.includeRawChunks,
|
|
210
|
+
providerOptions: options == null ? void 0 : options.providerOptions,
|
|
211
|
+
abortSignal,
|
|
212
|
+
headers: options == null ? void 0 : options.headers,
|
|
213
|
+
reasoning: options == null ? void 0 : options.reasoning,
|
|
214
|
+
output,
|
|
215
|
+
maxOutputTokens: options == null ? void 0 : options.maxOutputTokens,
|
|
216
|
+
temperature: options == null ? void 0 : options.temperature,
|
|
217
|
+
topP: options == null ? void 0 : options.topP,
|
|
218
|
+
topK: options == null ? void 0 : options.topK,
|
|
219
|
+
presencePenalty: options == null ? void 0 : options.presencePenalty,
|
|
220
|
+
frequencyPenalty: options == null ? void 0 : options.frequencyPenalty,
|
|
221
|
+
stopSequences: options == null ? void 0 : options.stopSequences,
|
|
222
|
+
seed: options == null ? void 0 : options.seed,
|
|
223
|
+
repairToolCall: options == null ? void 0 : options.repairToolCall
|
|
224
|
+
})
|
|
225
|
+
);
|
|
226
|
+
return stream;
|
|
227
|
+
} catch (error) {
|
|
228
|
+
if ((abortSignal == null ? void 0 : abortSignal.aborted) && isAbortError(error)) {
|
|
229
|
+
return void 0;
|
|
230
|
+
}
|
|
231
|
+
throw error;
|
|
232
|
+
}
|
|
233
|
+
})();
|
|
222
234
|
if (modelStream == null) {
|
|
223
235
|
return { aborted: true };
|
|
224
236
|
}
|
|
@@ -229,6 +241,8 @@ async function doStreamStep(conversationPrompt, modelInit, writable, serializedT
|
|
|
229
241
|
const reasoningParts = [];
|
|
230
242
|
let responseMetadata;
|
|
231
243
|
let warnings;
|
|
244
|
+
let terminalError;
|
|
245
|
+
let hasTerminalError = false;
|
|
232
246
|
const writer = writable == null ? void 0 : writable.getWriter();
|
|
233
247
|
try {
|
|
234
248
|
for await (const part of modelStream) {
|
|
@@ -294,6 +308,10 @@ async function doStreamStep(conversationPrompt, modelInit, writable, serializedT
|
|
|
294
308
|
if (writer) {
|
|
295
309
|
await writer.write(part);
|
|
296
310
|
}
|
|
311
|
+
if (part.type === "error" && !hasTerminalError) {
|
|
312
|
+
terminalError = part.error;
|
|
313
|
+
hasTerminalError = true;
|
|
314
|
+
}
|
|
297
315
|
}
|
|
298
316
|
} catch (error) {
|
|
299
317
|
if ((abortSignal == null ? void 0 : abortSignal.aborted) && isAbortError(error)) {
|
|
@@ -315,9 +333,11 @@ async function doStreamStep(conversationPrompt, modelInit, writable, serializedT
|
|
|
315
333
|
responseMetadata,
|
|
316
334
|
warnings
|
|
317
335
|
},
|
|
318
|
-
providerExecutedToolResults
|
|
336
|
+
providerExecutedToolResults,
|
|
337
|
+
...hasTerminalError ? { terminalError } : {}
|
|
319
338
|
};
|
|
320
339
|
}
|
|
340
|
+
doStreamStep.maxRetries = 0;
|
|
321
341
|
|
|
322
342
|
// src/stream-text-iterator.ts
|
|
323
343
|
var prepareStepGenerationSettingKeys = [
|
|
@@ -382,6 +402,8 @@ async function* streamTextIterator({
|
|
|
382
402
|
let lastStep;
|
|
383
403
|
let lastStepWasToolCalls = false;
|
|
384
404
|
let wasAborted = false;
|
|
405
|
+
let terminalError;
|
|
406
|
+
let hasTerminalError = false;
|
|
385
407
|
const telemetryDispatcher = createRestrictedTelemetryDispatcher({
|
|
386
408
|
telemetry,
|
|
387
409
|
includeRuntimeContext: telemetry == null ? void 0 : telemetry.includeRuntimeContext,
|
|
@@ -515,6 +537,10 @@ async function* streamTextIterator({
|
|
|
515
537
|
wasAborted = true;
|
|
516
538
|
break;
|
|
517
539
|
}
|
|
540
|
+
if ("terminalError" in streamStepResult) {
|
|
541
|
+
terminalError = streamStepResult.terminalError;
|
|
542
|
+
hasTerminalError = true;
|
|
543
|
+
}
|
|
518
544
|
const { toolCalls, finish, raw, providerExecutedToolResults } = streamStepResult;
|
|
519
545
|
const step = buildStepResult(raw, toolCalls, finish, {
|
|
520
546
|
stepNumber,
|
|
@@ -537,7 +563,9 @@ async function* streamTextIterator({
|
|
|
537
563
|
lastStep = step;
|
|
538
564
|
lastStepWasToolCalls = false;
|
|
539
565
|
const finishReason = finish == null ? void 0 : finish.finishReason;
|
|
540
|
-
if (
|
|
566
|
+
if (hasTerminalError) {
|
|
567
|
+
done = true;
|
|
568
|
+
} else if (finishReason === "tool-calls") {
|
|
541
569
|
lastStepWasToolCalls = true;
|
|
542
570
|
const textContent = step.content.filter(
|
|
543
571
|
(item) => item.type === "text"
|
|
@@ -634,6 +662,9 @@ async function* streamTextIterator({
|
|
|
634
662
|
if (wasAborted) {
|
|
635
663
|
return { aborted: true, messages: conversationPrompt };
|
|
636
664
|
}
|
|
665
|
+
if (hasTerminalError) {
|
|
666
|
+
return { error: terminalError, messages: conversationPrompt };
|
|
667
|
+
}
|
|
637
668
|
return conversationPrompt;
|
|
638
669
|
}
|
|
639
670
|
function getModelInfo(model) {
|
|
@@ -797,7 +828,7 @@ var WorkflowAgent = class {
|
|
|
797
828
|
throw new Error("Not implemented");
|
|
798
829
|
}
|
|
799
830
|
async stream(options) {
|
|
800
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P, _Q, _R, _S, _T;
|
|
831
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P, _Q, _R, _S, _T, _U;
|
|
801
832
|
const { onFinish, onEnd = onFinish } = options;
|
|
802
833
|
let effectiveModel = this.model;
|
|
803
834
|
let effectiveInstructions = (_b = (_a = options.instructions) != null ? _a : options.system) != null ? _b : this.instructions;
|
|
@@ -1421,7 +1452,6 @@ var WorkflowAgent = class {
|
|
|
1421
1452
|
stopConditions: effectiveStopWhenFromPrepare,
|
|
1422
1453
|
onStepEnd: mergedOnStepEnd,
|
|
1423
1454
|
onStepStart: mergedOnStepStart,
|
|
1424
|
-
onError: options.onError,
|
|
1425
1455
|
prepareStep: (_z = options.prepareStep) != null ? _z : this.prepareStep,
|
|
1426
1456
|
generationSettings: mergedGenerationSettings,
|
|
1427
1457
|
toolChoice: effectiveToolChoice,
|
|
@@ -1436,7 +1466,10 @@ var WorkflowAgent = class {
|
|
|
1436
1466
|
});
|
|
1437
1467
|
let finalMessages;
|
|
1438
1468
|
let encounteredError;
|
|
1469
|
+
let hasEncounteredError = false;
|
|
1439
1470
|
let wasAborted = false;
|
|
1471
|
+
let terminalError;
|
|
1472
|
+
let hasTerminalError = false;
|
|
1440
1473
|
try {
|
|
1441
1474
|
let result = await iterator.next();
|
|
1442
1475
|
while (!result.done) {
|
|
@@ -1735,6 +1768,10 @@ var WorkflowAgent = class {
|
|
|
1735
1768
|
if (result.done) {
|
|
1736
1769
|
if (Array.isArray(result.value)) {
|
|
1737
1770
|
finalMessages = result.value;
|
|
1771
|
+
} else if ("error" in result.value) {
|
|
1772
|
+
finalMessages = result.value.messages;
|
|
1773
|
+
terminalError = result.value.error;
|
|
1774
|
+
hasTerminalError = true;
|
|
1738
1775
|
} else {
|
|
1739
1776
|
finalMessages = result.value.messages;
|
|
1740
1777
|
wasAborted = true;
|
|
@@ -1745,6 +1782,7 @@ var WorkflowAgent = class {
|
|
|
1745
1782
|
}
|
|
1746
1783
|
} catch (error) {
|
|
1747
1784
|
encounteredError = error;
|
|
1785
|
+
hasEncounteredError = true;
|
|
1748
1786
|
if (isAbortError2(error)) {
|
|
1749
1787
|
wasAborted = true;
|
|
1750
1788
|
if (options.onAbort) {
|
|
@@ -1755,8 +1793,14 @@ var WorkflowAgent = class {
|
|
|
1755
1793
|
}
|
|
1756
1794
|
await ((_L = telemetryDispatcher.onError) == null ? void 0 : _L.call(telemetryDispatcher, error));
|
|
1757
1795
|
}
|
|
1796
|
+
if (hasTerminalError) {
|
|
1797
|
+
if (options.onError) {
|
|
1798
|
+
await options.onError({ error: terminalError });
|
|
1799
|
+
}
|
|
1800
|
+
await ((_M = telemetryDispatcher.onError) == null ? void 0 : _M.call(telemetryDispatcher, terminalError));
|
|
1801
|
+
}
|
|
1758
1802
|
const messages = finalMessages != null ? finalMessages : prompt.messages;
|
|
1759
|
-
const effectiveOutput = (
|
|
1803
|
+
const effectiveOutput = (_N = options.output) != null ? _N : this.output;
|
|
1760
1804
|
let experimentalOutput = void 0;
|
|
1761
1805
|
if (effectiveOutput && steps.length > 0) {
|
|
1762
1806
|
const lastStep2 = steps[steps.length - 1];
|
|
@@ -1772,20 +1816,21 @@ var WorkflowAgent = class {
|
|
|
1772
1816
|
}
|
|
1773
1817
|
);
|
|
1774
1818
|
} catch (parseError) {
|
|
1775
|
-
if (!
|
|
1819
|
+
if (!hasEncounteredError) {
|
|
1776
1820
|
encounteredError = parseError;
|
|
1821
|
+
hasEncounteredError = true;
|
|
1777
1822
|
}
|
|
1778
1823
|
}
|
|
1779
1824
|
}
|
|
1780
1825
|
}
|
|
1781
1826
|
const lastStep = steps[steps.length - 1];
|
|
1782
1827
|
const totalUsage = aggregateUsage(steps);
|
|
1783
|
-
const finishReason = (
|
|
1828
|
+
const finishReason = (_O = lastStep == null ? void 0 : lastStep.finishReason) != null ? _O : "other";
|
|
1784
1829
|
if (mergedOnEnd && !wasAborted) {
|
|
1785
1830
|
await mergedOnEnd({
|
|
1786
1831
|
steps,
|
|
1787
1832
|
messages,
|
|
1788
|
-
text: (
|
|
1833
|
+
text: (_P = lastStep == null ? void 0 : lastStep.text) != null ? _P : "",
|
|
1789
1834
|
finishReason,
|
|
1790
1835
|
usage: totalUsage,
|
|
1791
1836
|
totalUsage,
|
|
@@ -1797,17 +1842,17 @@ var WorkflowAgent = class {
|
|
|
1797
1842
|
if (!wasAborted && steps.length > 0) {
|
|
1798
1843
|
const telemetrySteps = steps.map(normalizeStepForTelemetry2);
|
|
1799
1844
|
const lastTelemetryStep = telemetrySteps[telemetrySteps.length - 1];
|
|
1800
|
-
await ((
|
|
1845
|
+
await ((_Q = telemetryDispatcher.onEnd) == null ? void 0 : _Q.call(telemetryDispatcher, {
|
|
1801
1846
|
...lastTelemetryStep,
|
|
1802
1847
|
steps: telemetrySteps,
|
|
1803
1848
|
usage: totalUsage,
|
|
1804
1849
|
totalUsage
|
|
1805
1850
|
}));
|
|
1806
1851
|
}
|
|
1807
|
-
if (
|
|
1852
|
+
if (hasEncounteredError) {
|
|
1808
1853
|
if (options.writable) {
|
|
1809
|
-
const sendFinish = (
|
|
1810
|
-
const preventClose = (
|
|
1854
|
+
const sendFinish = (_R = options.sendFinish) != null ? _R : true;
|
|
1855
|
+
const preventClose = (_S = options.preventClose) != null ? _S : false;
|
|
1811
1856
|
if (sendFinish || !preventClose) {
|
|
1812
1857
|
await closeStream(options.writable, preventClose, sendFinish);
|
|
1813
1858
|
}
|
|
@@ -1815,8 +1860,8 @@ var WorkflowAgent = class {
|
|
|
1815
1860
|
throw encounteredError;
|
|
1816
1861
|
}
|
|
1817
1862
|
if (options.writable) {
|
|
1818
|
-
const sendFinish = (
|
|
1819
|
-
const preventClose = (
|
|
1863
|
+
const sendFinish = (_T = options.sendFinish) != null ? _T : true;
|
|
1864
|
+
const preventClose = (_U = options.preventClose) != null ? _U : false;
|
|
1820
1865
|
if (sendFinish || !preventClose) {
|
|
1821
1866
|
await closeStream(options.writable, preventClose, sendFinish);
|
|
1822
1867
|
}
|
|
@@ -1828,7 +1873,8 @@ var WorkflowAgent = class {
|
|
|
1828
1873
|
toolResults: lastStepToolResults,
|
|
1829
1874
|
finishReason,
|
|
1830
1875
|
totalUsage,
|
|
1831
|
-
output: experimentalOutput
|
|
1876
|
+
output: experimentalOutput,
|
|
1877
|
+
...hasTerminalError ? { error: terminalError } : {}
|
|
1832
1878
|
};
|
|
1833
1879
|
}
|
|
1834
1880
|
};
|