@ai-sdk/workflow 1.0.15 → 1.0.17
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 +16 -0
- package/dist/index.d.mts +8 -0
- package/dist/index.mjs +173 -123
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -2
- package/src/do-stream-step.ts +25 -121
- package/src/stream-text-iterator.ts +114 -4
- package/src/workflow-agent.ts +30 -12
- package/src/workflow-chat-transport.ts +94 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @ai-sdk/workflow
|
|
2
2
|
|
|
3
|
+
## 1.0.17
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 148babc: `WorkflowChatTransport` now drops orphan UI chunks (deltas/ends and tool output/approval chunks whose part was started before the resumed window) when reconnecting with a negative `initialStartIndex`, instead of crashing the AI SDK client. Self-contained `tool-input-available`/`tool-input-error` chunks establish the tool part and are never dropped. A one-time warning links to docs on rewinding to a step boundary server-side.
|
|
8
|
+
- e660e45: Reduce the `doStreamStep` step-boundary payload by returning minimal raw aggregates and reconstructing the `StepResult` outside the step, instead of serializing the full `StepResult` plus the per-chunk array into the durable event log.
|
|
9
|
+
- cc773bc: Expose `totalUsage` and `finishReason` on the `WorkflowAgent.stream()` result, mirroring `GenerateTextResult`/`StreamTextResult` and the existing `onEnd` event payload.
|
|
10
|
+
- ai@7.0.17
|
|
11
|
+
|
|
12
|
+
## 1.0.16
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- Updated dependencies [a8f9b6d]
|
|
17
|
+
- ai@7.0.16
|
|
18
|
+
|
|
3
19
|
## 1.0.15
|
|
4
20
|
|
|
5
21
|
### Patch Changes
|
package/dist/index.d.mts
CHANGED
|
@@ -876,6 +876,14 @@ interface WorkflowAgentStreamResult<TTools extends ToolSet = ToolSet, OUTPUT = n
|
|
|
876
876
|
* This matches the AI SDK's `GenerateTextResult.toolResults` behavior.
|
|
877
877
|
*/
|
|
878
878
|
toolResults: ToolResult[];
|
|
879
|
+
/**
|
|
880
|
+
* The finish reason from the last step.
|
|
881
|
+
*/
|
|
882
|
+
finishReason: FinishReason;
|
|
883
|
+
/**
|
|
884
|
+
* The total token usage across all steps.
|
|
885
|
+
*/
|
|
886
|
+
totalUsage: LanguageModelUsage;
|
|
879
887
|
/**
|
|
880
888
|
* The generated structured output. It uses the `output` specification.
|
|
881
889
|
* Only available when `output` is specified.
|
package/dist/index.mjs
CHANGED
|
@@ -144,7 +144,6 @@ function resolveSerializableTools(tools) {
|
|
|
144
144
|
// src/do-stream-step.ts
|
|
145
145
|
async function doStreamStep(conversationPrompt, modelInit, writable, serializedTools, options) {
|
|
146
146
|
"use step";
|
|
147
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
|
|
148
147
|
const model = typeof modelInit === "string" ? gateway.languageModel(modelInit) : modelInit;
|
|
149
148
|
const tools = serializedTools ? resolveSerializableTools(serializedTools) : void 0;
|
|
150
149
|
const { stream: modelStream } = await streamModelCall({
|
|
@@ -176,15 +175,11 @@ async function doStreamStep(conversationPrompt, modelInit, writable, serializedT
|
|
|
176
175
|
let finish;
|
|
177
176
|
let text = "";
|
|
178
177
|
const reasoningParts = [];
|
|
179
|
-
const chunks = [];
|
|
180
178
|
let responseMetadata;
|
|
181
179
|
let warnings;
|
|
182
180
|
const writer = writable == null ? void 0 : writable.getWriter();
|
|
183
181
|
try {
|
|
184
182
|
for await (const part of modelStream) {
|
|
185
|
-
if (part.type !== "model-call-start" && part.type !== "model-call-end" && part.type !== "model-call-response-metadata") {
|
|
186
|
-
chunks.push(part);
|
|
187
|
-
}
|
|
188
183
|
switch (part.type) {
|
|
189
184
|
case "text-delta":
|
|
190
185
|
text += part.text;
|
|
@@ -251,99 +246,15 @@ async function doStreamStep(conversationPrompt, modelInit, writable, serializedT
|
|
|
251
246
|
} finally {
|
|
252
247
|
writer == null ? void 0 : writer.releaseLock();
|
|
253
248
|
}
|
|
254
|
-
const reasoningText = reasoningParts.map((r) => r.text).join("") || void 0;
|
|
255
|
-
const step = {
|
|
256
|
-
callId: "workflow-agent",
|
|
257
|
-
stepNumber: (_a = options == null ? void 0 : options.stepNumber) != null ? _a : 0,
|
|
258
|
-
model: {
|
|
259
|
-
provider: (_c = (_b = responseMetadata == null ? void 0 : responseMetadata.modelId) == null ? void 0 : _b.split(":")[0]) != null ? _c : "unknown",
|
|
260
|
-
modelId: (_d = responseMetadata == null ? void 0 : responseMetadata.modelId) != null ? _d : "unknown"
|
|
261
|
-
},
|
|
262
|
-
functionId: void 0,
|
|
263
|
-
metadata: void 0,
|
|
264
|
-
runtimeContext: (_e = options == null ? void 0 : options.runtimeContext) != null ? _e : {},
|
|
265
|
-
toolsContext: (_f = options == null ? void 0 : options.toolsContext) != null ? _f : {},
|
|
266
|
-
content: [
|
|
267
|
-
...text ? [{ type: "text", text }] : [],
|
|
268
|
-
...toolCalls.filter((tc) => !tc.invalid).map((tc) => ({
|
|
269
|
-
type: "tool-call",
|
|
270
|
-
toolCallId: tc.toolCallId,
|
|
271
|
-
toolName: tc.toolName,
|
|
272
|
-
input: tc.input,
|
|
273
|
-
...tc.dynamic ? { dynamic: true } : {}
|
|
274
|
-
}))
|
|
275
|
-
],
|
|
276
|
-
text,
|
|
277
|
-
reasoning: reasoningParts.map((r) => ({
|
|
278
|
-
type: "reasoning",
|
|
279
|
-
text: r.text
|
|
280
|
-
})),
|
|
281
|
-
reasoningText,
|
|
282
|
-
files: [],
|
|
283
|
-
sources: [],
|
|
284
|
-
toolCalls: toolCalls.filter((tc) => !tc.invalid).map((tc) => ({
|
|
285
|
-
type: "tool-call",
|
|
286
|
-
toolCallId: tc.toolCallId,
|
|
287
|
-
toolName: tc.toolName,
|
|
288
|
-
input: tc.input,
|
|
289
|
-
...tc.dynamic ? { dynamic: true } : {}
|
|
290
|
-
})),
|
|
291
|
-
staticToolCalls: [],
|
|
292
|
-
dynamicToolCalls: toolCalls.filter((tc) => !tc.invalid && tc.dynamic).map((tc) => ({
|
|
293
|
-
type: "tool-call",
|
|
294
|
-
toolCallId: tc.toolCallId,
|
|
295
|
-
toolName: tc.toolName,
|
|
296
|
-
input: tc.input,
|
|
297
|
-
dynamic: true
|
|
298
|
-
})),
|
|
299
|
-
toolResults: [],
|
|
300
|
-
staticToolResults: [],
|
|
301
|
-
dynamicToolResults: [],
|
|
302
|
-
finishReason: (_g = finish == null ? void 0 : finish.finishReason) != null ? _g : "other",
|
|
303
|
-
rawFinishReason: finish == null ? void 0 : finish.rawFinishReason,
|
|
304
|
-
usage: (_h = finish == null ? void 0 : finish.usage) != null ? _h : {
|
|
305
|
-
inputTokens: 0,
|
|
306
|
-
inputTokenDetails: {
|
|
307
|
-
noCacheTokens: void 0,
|
|
308
|
-
cacheReadTokens: void 0,
|
|
309
|
-
cacheWriteTokens: void 0
|
|
310
|
-
},
|
|
311
|
-
outputTokens: 0,
|
|
312
|
-
outputTokenDetails: {
|
|
313
|
-
textTokens: void 0,
|
|
314
|
-
reasoningTokens: void 0
|
|
315
|
-
},
|
|
316
|
-
totalTokens: 0
|
|
317
|
-
},
|
|
318
|
-
performance: {
|
|
319
|
-
effectiveOutputTokensPerSecond: 0,
|
|
320
|
-
outputTokensPerSecond: void 0,
|
|
321
|
-
inputTokensPerSecond: void 0,
|
|
322
|
-
effectiveTotalTokensPerSecond: 0,
|
|
323
|
-
stepTimeMs: 0,
|
|
324
|
-
responseTimeMs: 0,
|
|
325
|
-
toolExecutionMs: {},
|
|
326
|
-
timeToFirstOutputMs: void 0
|
|
327
|
-
},
|
|
328
|
-
warnings,
|
|
329
|
-
request: {
|
|
330
|
-
body: "",
|
|
331
|
-
messages: []
|
|
332
|
-
// TODO implement step request messages
|
|
333
|
-
},
|
|
334
|
-
response: {
|
|
335
|
-
id: (_i = responseMetadata == null ? void 0 : responseMetadata.id) != null ? _i : "unknown",
|
|
336
|
-
timestamp: (_j = responseMetadata == null ? void 0 : responseMetadata.timestamp) != null ? _j : /* @__PURE__ */ new Date(),
|
|
337
|
-
modelId: (_k = responseMetadata == null ? void 0 : responseMetadata.modelId) != null ? _k : "unknown",
|
|
338
|
-
messages: []
|
|
339
|
-
},
|
|
340
|
-
providerMetadata: (_l = finish == null ? void 0 : finish.providerMetadata) != null ? _l : {}
|
|
341
|
-
};
|
|
342
249
|
return {
|
|
343
250
|
toolCalls,
|
|
344
251
|
finish,
|
|
345
|
-
|
|
346
|
-
|
|
252
|
+
raw: {
|
|
253
|
+
text,
|
|
254
|
+
reasoning: reasoningParts,
|
|
255
|
+
responseMetadata,
|
|
256
|
+
warnings
|
|
257
|
+
},
|
|
347
258
|
providerExecutedToolResults
|
|
348
259
|
};
|
|
349
260
|
}
|
|
@@ -562,7 +473,7 @@ async function* streamTextIterator({
|
|
|
562
473
|
providerOptions: currentGenerationSettings.providerOptions,
|
|
563
474
|
headers: currentGenerationSettings.headers
|
|
564
475
|
}));
|
|
565
|
-
const { toolCalls, finish,
|
|
476
|
+
const { toolCalls, finish, raw, providerExecutedToolResults } = await doStreamStep(
|
|
566
477
|
conversationPrompt,
|
|
567
478
|
currentModel,
|
|
568
479
|
writable,
|
|
@@ -572,12 +483,14 @@ async function* streamTextIterator({
|
|
|
572
483
|
toolChoice: currentToolChoice,
|
|
573
484
|
includeRawChunks,
|
|
574
485
|
repairToolCall,
|
|
575
|
-
responseFormat
|
|
576
|
-
runtimeContext: currentRuntimeContext,
|
|
577
|
-
toolsContext: currentToolsContext,
|
|
578
|
-
stepNumber
|
|
486
|
+
responseFormat
|
|
579
487
|
}
|
|
580
488
|
);
|
|
489
|
+
const step = buildStepResult(raw, toolCalls, finish, {
|
|
490
|
+
stepNumber,
|
|
491
|
+
runtimeContext: currentRuntimeContext,
|
|
492
|
+
toolsContext: currentToolsContext
|
|
493
|
+
});
|
|
581
494
|
await ((_j = telemetryDispatcher.onLanguageModelCallEnd) == null ? void 0 : _j.call(telemetryDispatcher, {
|
|
582
495
|
callId: step.callId,
|
|
583
496
|
provider: (_g = (_f = step.model) == null ? void 0 : _f.provider) != null ? _g : "unknown",
|
|
@@ -692,6 +605,87 @@ function normalizeStepForTelemetry(step) {
|
|
|
692
605
|
model: (_a = step.model) != null ? _a : { provider: "unknown", modelId: "unknown" }
|
|
693
606
|
};
|
|
694
607
|
}
|
|
608
|
+
function buildStepResult(raw, toolCalls, finish, opts) {
|
|
609
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
|
|
610
|
+
const { text, reasoning: reasoningParts, responseMetadata, warnings } = raw;
|
|
611
|
+
const reasoningText = reasoningParts.map((r) => r.text).join("") || void 0;
|
|
612
|
+
const validToolCalls = toolCalls.filter((tc) => !tc.invalid).map((tc) => ({
|
|
613
|
+
type: "tool-call",
|
|
614
|
+
toolCallId: tc.toolCallId,
|
|
615
|
+
toolName: tc.toolName,
|
|
616
|
+
input: tc.input,
|
|
617
|
+
...tc.dynamic ? { dynamic: true } : {}
|
|
618
|
+
}));
|
|
619
|
+
return {
|
|
620
|
+
callId: "workflow-agent",
|
|
621
|
+
stepNumber: opts.stepNumber,
|
|
622
|
+
model: {
|
|
623
|
+
provider: (_b = (_a = responseMetadata == null ? void 0 : responseMetadata.modelId) == null ? void 0 : _a.split(":")[0]) != null ? _b : "unknown",
|
|
624
|
+
modelId: (_c = responseMetadata == null ? void 0 : responseMetadata.modelId) != null ? _c : "unknown"
|
|
625
|
+
},
|
|
626
|
+
functionId: void 0,
|
|
627
|
+
metadata: void 0,
|
|
628
|
+
runtimeContext: (_d = opts.runtimeContext) != null ? _d : {},
|
|
629
|
+
toolsContext: (_e = opts.toolsContext) != null ? _e : {},
|
|
630
|
+
content: [
|
|
631
|
+
...text ? [{ type: "text", text }] : [],
|
|
632
|
+
...validToolCalls
|
|
633
|
+
],
|
|
634
|
+
text,
|
|
635
|
+
reasoning: reasoningParts.map((r) => ({
|
|
636
|
+
type: "reasoning",
|
|
637
|
+
text: r.text
|
|
638
|
+
})),
|
|
639
|
+
reasoningText,
|
|
640
|
+
files: [],
|
|
641
|
+
sources: [],
|
|
642
|
+
toolCalls: validToolCalls,
|
|
643
|
+
staticToolCalls: [],
|
|
644
|
+
dynamicToolCalls: validToolCalls.filter((tc) => tc.dynamic),
|
|
645
|
+
toolResults: [],
|
|
646
|
+
staticToolResults: [],
|
|
647
|
+
dynamicToolResults: [],
|
|
648
|
+
finishReason: (_f = finish == null ? void 0 : finish.finishReason) != null ? _f : "other",
|
|
649
|
+
rawFinishReason: finish == null ? void 0 : finish.rawFinishReason,
|
|
650
|
+
usage: (_g = finish == null ? void 0 : finish.usage) != null ? _g : {
|
|
651
|
+
inputTokens: 0,
|
|
652
|
+
inputTokenDetails: {
|
|
653
|
+
noCacheTokens: void 0,
|
|
654
|
+
cacheReadTokens: void 0,
|
|
655
|
+
cacheWriteTokens: void 0
|
|
656
|
+
},
|
|
657
|
+
outputTokens: 0,
|
|
658
|
+
outputTokenDetails: {
|
|
659
|
+
textTokens: void 0,
|
|
660
|
+
reasoningTokens: void 0
|
|
661
|
+
},
|
|
662
|
+
totalTokens: 0
|
|
663
|
+
},
|
|
664
|
+
performance: {
|
|
665
|
+
effectiveOutputTokensPerSecond: 0,
|
|
666
|
+
outputTokensPerSecond: void 0,
|
|
667
|
+
inputTokensPerSecond: void 0,
|
|
668
|
+
effectiveTotalTokensPerSecond: 0,
|
|
669
|
+
stepTimeMs: 0,
|
|
670
|
+
responseTimeMs: 0,
|
|
671
|
+
toolExecutionMs: {},
|
|
672
|
+
timeToFirstOutputMs: void 0
|
|
673
|
+
},
|
|
674
|
+
warnings,
|
|
675
|
+
request: {
|
|
676
|
+
body: "",
|
|
677
|
+
messages: []
|
|
678
|
+
// TODO implement step request messages
|
|
679
|
+
},
|
|
680
|
+
response: {
|
|
681
|
+
id: (_h = responseMetadata == null ? void 0 : responseMetadata.id) != null ? _h : "unknown",
|
|
682
|
+
timestamp: (_i = responseMetadata == null ? void 0 : responseMetadata.timestamp) != null ? _i : /* @__PURE__ */ new Date(),
|
|
683
|
+
modelId: (_j = responseMetadata == null ? void 0 : responseMetadata.modelId) != null ? _j : "unknown",
|
|
684
|
+
messages: []
|
|
685
|
+
},
|
|
686
|
+
providerMetadata: (_k = finish == null ? void 0 : finish.providerMetadata) != null ? _k : {}
|
|
687
|
+
};
|
|
688
|
+
}
|
|
695
689
|
function sanitizeProviderMetadataForToolCall(metadata) {
|
|
696
690
|
if (metadata == null) return void 0;
|
|
697
691
|
const meta = metadata;
|
|
@@ -1356,6 +1350,8 @@ var WorkflowAgent = class {
|
|
|
1356
1350
|
steps,
|
|
1357
1351
|
toolCalls: [],
|
|
1358
1352
|
toolResults: [],
|
|
1353
|
+
finishReason: "other",
|
|
1354
|
+
totalUsage: aggregateUsage(steps),
|
|
1359
1355
|
output: void 0
|
|
1360
1356
|
};
|
|
1361
1357
|
}
|
|
@@ -1515,16 +1511,17 @@ var WorkflowAgent = class {
|
|
|
1515
1511
|
});
|
|
1516
1512
|
}
|
|
1517
1513
|
const messages2 = iterMessages;
|
|
1514
|
+
const lastStep2 = steps[steps.length - 1];
|
|
1515
|
+
const totalUsage2 = aggregateUsage(steps);
|
|
1516
|
+
const finishReason2 = (_E = lastStep2 == null ? void 0 : lastStep2.finishReason) != null ? _E : "other";
|
|
1518
1517
|
if (mergedOnEnd && !wasAborted) {
|
|
1519
|
-
const lastStep = steps[steps.length - 1];
|
|
1520
|
-
const totalUsage = aggregateUsage(steps);
|
|
1521
1518
|
await mergedOnEnd({
|
|
1522
1519
|
steps,
|
|
1523
1520
|
messages: messages2,
|
|
1524
|
-
text: (
|
|
1525
|
-
finishReason:
|
|
1526
|
-
usage:
|
|
1527
|
-
totalUsage,
|
|
1521
|
+
text: (_F = lastStep2 == null ? void 0 : lastStep2.text) != null ? _F : "",
|
|
1522
|
+
finishReason: finishReason2,
|
|
1523
|
+
usage: totalUsage2,
|
|
1524
|
+
totalUsage: totalUsage2,
|
|
1528
1525
|
runtimeContext,
|
|
1529
1526
|
toolsContext,
|
|
1530
1527
|
output: void 0
|
|
@@ -1532,13 +1529,12 @@ var WorkflowAgent = class {
|
|
|
1532
1529
|
}
|
|
1533
1530
|
if (!wasAborted && steps.length > 0) {
|
|
1534
1531
|
const telemetrySteps = steps.map(normalizeStepForTelemetry2);
|
|
1535
|
-
const
|
|
1536
|
-
const totalUsage = aggregateUsage(steps);
|
|
1532
|
+
const lastTelemetryStep = telemetrySteps[telemetrySteps.length - 1];
|
|
1537
1533
|
await ((_G = telemetryDispatcher.onEnd) == null ? void 0 : _G.call(telemetryDispatcher, {
|
|
1538
|
-
...
|
|
1534
|
+
...lastTelemetryStep,
|
|
1539
1535
|
steps: telemetrySteps,
|
|
1540
|
-
usage:
|
|
1541
|
-
totalUsage
|
|
1536
|
+
usage: totalUsage2,
|
|
1537
|
+
totalUsage: totalUsage2
|
|
1542
1538
|
}));
|
|
1543
1539
|
}
|
|
1544
1540
|
if (options.writable) {
|
|
@@ -1570,6 +1566,8 @@ var WorkflowAgent = class {
|
|
|
1570
1566
|
steps,
|
|
1571
1567
|
toolCalls: allToolCalls,
|
|
1572
1568
|
toolResults: allToolResults,
|
|
1569
|
+
finishReason: finishReason2,
|
|
1570
|
+
totalUsage: totalUsage2,
|
|
1573
1571
|
output: void 0
|
|
1574
1572
|
};
|
|
1575
1573
|
}
|
|
@@ -1690,16 +1688,16 @@ var WorkflowAgent = class {
|
|
|
1690
1688
|
const effectiveOutput = (_K = options.output) != null ? _K : this.output;
|
|
1691
1689
|
let experimentalOutput = void 0;
|
|
1692
1690
|
if (effectiveOutput && steps.length > 0) {
|
|
1693
|
-
const
|
|
1694
|
-
const text =
|
|
1691
|
+
const lastStep2 = steps[steps.length - 1];
|
|
1692
|
+
const text = lastStep2.text;
|
|
1695
1693
|
if (text) {
|
|
1696
1694
|
try {
|
|
1697
1695
|
experimentalOutput = await effectiveOutput.parseCompleteOutput(
|
|
1698
1696
|
{ text },
|
|
1699
1697
|
{
|
|
1700
|
-
response:
|
|
1701
|
-
usage:
|
|
1702
|
-
finishReason:
|
|
1698
|
+
response: lastStep2.response,
|
|
1699
|
+
usage: lastStep2.usage,
|
|
1700
|
+
finishReason: lastStep2.finishReason
|
|
1703
1701
|
}
|
|
1704
1702
|
);
|
|
1705
1703
|
} catch (parseError) {
|
|
@@ -1709,14 +1707,15 @@ var WorkflowAgent = class {
|
|
|
1709
1707
|
}
|
|
1710
1708
|
}
|
|
1711
1709
|
}
|
|
1710
|
+
const lastStep = steps[steps.length - 1];
|
|
1711
|
+
const totalUsage = aggregateUsage(steps);
|
|
1712
|
+
const finishReason = (_L = lastStep == null ? void 0 : lastStep.finishReason) != null ? _L : "other";
|
|
1712
1713
|
if (mergedOnEnd && !wasAborted) {
|
|
1713
|
-
const lastStep = steps[steps.length - 1];
|
|
1714
|
-
const totalUsage = aggregateUsage(steps);
|
|
1715
1714
|
await mergedOnEnd({
|
|
1716
1715
|
steps,
|
|
1717
1716
|
messages,
|
|
1718
|
-
text: (
|
|
1719
|
-
finishReason
|
|
1717
|
+
text: (_M = lastStep == null ? void 0 : lastStep.text) != null ? _M : "",
|
|
1718
|
+
finishReason,
|
|
1720
1719
|
usage: totalUsage,
|
|
1721
1720
|
totalUsage,
|
|
1722
1721
|
runtimeContext,
|
|
@@ -1726,10 +1725,9 @@ var WorkflowAgent = class {
|
|
|
1726
1725
|
}
|
|
1727
1726
|
if (!wasAborted && steps.length > 0) {
|
|
1728
1727
|
const telemetrySteps = steps.map(normalizeStepForTelemetry2);
|
|
1729
|
-
const
|
|
1730
|
-
const totalUsage = aggregateUsage(steps);
|
|
1728
|
+
const lastTelemetryStep = telemetrySteps[telemetrySteps.length - 1];
|
|
1731
1729
|
await ((_N = telemetryDispatcher.onEnd) == null ? void 0 : _N.call(telemetryDispatcher, {
|
|
1732
|
-
...
|
|
1730
|
+
...lastTelemetryStep,
|
|
1733
1731
|
steps: telemetrySteps,
|
|
1734
1732
|
usage: totalUsage,
|
|
1735
1733
|
totalUsage
|
|
@@ -1757,6 +1755,8 @@ var WorkflowAgent = class {
|
|
|
1757
1755
|
steps,
|
|
1758
1756
|
toolCalls: lastStepToolCalls,
|
|
1759
1757
|
toolResults: lastStepToolResults,
|
|
1758
|
+
finishReason,
|
|
1759
|
+
totalUsage,
|
|
1760
1760
|
output: experimentalOutput
|
|
1761
1761
|
};
|
|
1762
1762
|
}
|
|
@@ -2249,6 +2249,54 @@ async function* normalizeUIMessageStreamParts(source) {
|
|
|
2249
2249
|
}
|
|
2250
2250
|
|
|
2251
2251
|
// src/workflow-chat-transport.ts
|
|
2252
|
+
function createOrphanFilter() {
|
|
2253
|
+
const seenStartedIds = /* @__PURE__ */ new Set();
|
|
2254
|
+
const seenStartedToolCallIds = /* @__PURE__ */ new Set();
|
|
2255
|
+
let warnedOnce = false;
|
|
2256
|
+
function warnOnce(orphanKind, orphanRef) {
|
|
2257
|
+
if (warnedOnce) return;
|
|
2258
|
+
warnedOnce = true;
|
|
2259
|
+
console.warn(
|
|
2260
|
+
`[WorkflowChatTransport] Dropping orphan UI chunk (${orphanKind} for id "${orphanRef}") on resume \u2014 the resume position landed mid-part. The dropped chunk(s) reference a part whose start chunk wasn't in the resumed window. To preserve the full message, configure your stream endpoint to rewind to a step boundary before returning the readable. See: https://workflow.dev/docs/ai/resumable-streams#mid-part-resumes`
|
|
2261
|
+
);
|
|
2262
|
+
}
|
|
2263
|
+
function shouldDrop(chunk) {
|
|
2264
|
+
switch (chunk.type) {
|
|
2265
|
+
case "text-start":
|
|
2266
|
+
case "reasoning-start":
|
|
2267
|
+
seenStartedIds.add(chunk.id);
|
|
2268
|
+
return false;
|
|
2269
|
+
case "tool-input-start":
|
|
2270
|
+
// `tool-input-available` / `tool-input-error` are self-contained: the
|
|
2271
|
+
// AI SDK creates the tool part from them directly (non-streamed tool
|
|
2272
|
+
// calls are emitted as a bare `tool-input-available`), so they must
|
|
2273
|
+
// never be dropped. They also carry the full input, so they recover a
|
|
2274
|
+
// tool call whose `tool-input-start` fell outside the resumed window.
|
|
2275
|
+
case "tool-input-available":
|
|
2276
|
+
case "tool-input-error":
|
|
2277
|
+
seenStartedToolCallIds.add(chunk.toolCallId);
|
|
2278
|
+
return false;
|
|
2279
|
+
case "text-delta":
|
|
2280
|
+
case "text-end":
|
|
2281
|
+
case "reasoning-delta":
|
|
2282
|
+
case "reasoning-end":
|
|
2283
|
+
if (seenStartedIds.has(chunk.id)) return false;
|
|
2284
|
+
warnOnce(chunk.type, chunk.id);
|
|
2285
|
+
return true;
|
|
2286
|
+
case "tool-input-delta":
|
|
2287
|
+
case "tool-approval-request":
|
|
2288
|
+
case "tool-output-available":
|
|
2289
|
+
case "tool-output-error":
|
|
2290
|
+
case "tool-output-denied":
|
|
2291
|
+
if (seenStartedToolCallIds.has(chunk.toolCallId)) return false;
|
|
2292
|
+
warnOnce(chunk.type, chunk.toolCallId);
|
|
2293
|
+
return true;
|
|
2294
|
+
default:
|
|
2295
|
+
return false;
|
|
2296
|
+
}
|
|
2297
|
+
}
|
|
2298
|
+
return { shouldDrop };
|
|
2299
|
+
}
|
|
2252
2300
|
var WorkflowChatTransport = class {
|
|
2253
2301
|
/**
|
|
2254
2302
|
* Creates a new WorkflowChatTransport instance.
|
|
@@ -2394,6 +2442,7 @@ var WorkflowChatTransport = class {
|
|
|
2394
2442
|
let gotFinish = false;
|
|
2395
2443
|
let consecutiveErrors = 0;
|
|
2396
2444
|
let replayFromStart = false;
|
|
2445
|
+
const orphanFilter = useExplicitStartIndex && explicitStartIndex < 0 ? createOrphanFilter() : null;
|
|
2397
2446
|
while (!gotFinish) {
|
|
2398
2447
|
const startIndex = useExplicitStartIndex ? explicitStartIndex : replayFromStart ? 0 : chunkIndex;
|
|
2399
2448
|
const url = `${baseUrl}?startIndex=${startIndex}`;
|
|
@@ -2434,6 +2483,7 @@ var WorkflowChatTransport = class {
|
|
|
2434
2483
|
throw chunk.error;
|
|
2435
2484
|
}
|
|
2436
2485
|
chunkIndex++;
|
|
2486
|
+
if (orphanFilter == null ? void 0 : orphanFilter.shouldDrop(chunk.value)) continue;
|
|
2437
2487
|
yield chunk.value;
|
|
2438
2488
|
if (chunk.value.type === "finish") {
|
|
2439
2489
|
gotFinish = true;
|