veryfront 0.1.1208 → 0.1.1209
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/esm/deno.js +1 -1
- package/esm/src/agent/runtime/chat-stream-handler.d.ts +1 -0
- package/esm/src/agent/runtime/chat-stream-handler.d.ts.map +1 -1
- package/esm/src/agent/runtime/chat-stream-handler.js +536 -418
- package/esm/src/html/hydration-script-builder/hydration-runtime.generated.js +1 -1
- package/esm/src/html/utils.d.ts.map +1 -1
- package/esm/src/html/utils.js +6 -0
- package/esm/src/modules/import-map/default-import-map.d.ts.map +1 -1
- package/esm/src/modules/import-map/default-import-map.js +2 -0
- package/esm/src/platform/compat/http/pinned-fetch.d.ts +1 -1
- package/esm/src/react/components/ui/index.d.ts +1 -1
- package/esm/src/react/components/ui/index.d.ts.map +1 -1
- package/esm/src/react/components/ui/index.js +5 -1
- package/esm/src/release-assets/build-executor.d.ts.map +1 -1
- package/esm/src/release-assets/build-executor.js +64 -14
- package/esm/src/release-assets/manifest-schema.d.ts.map +1 -1
- package/esm/src/release-assets/manifest-schema.js +93 -0
- package/esm/src/security/http/platform-asset-origins.d.ts +19 -3
- package/esm/src/security/http/platform-asset-origins.d.ts.map +1 -1
- package/esm/src/security/http/platform-asset-origins.js +20 -2
- package/esm/src/security/http/response/security-handler.d.ts.map +1 -1
- package/esm/src/security/http/response/security-handler.js +7 -5
- package/esm/src/server/handlers/dev/framework-candidates.generated.d.ts.map +1 -1
- package/esm/src/server/handlers/dev/framework-candidates.generated.js +6 -1
- package/esm/src/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- package/package.json +8 -8
|
@@ -297,14 +297,80 @@ export function processStreamInternal(resultOrSource, state, controller, encoder
|
|
|
297
297
|
? new Set(callbacks.availableToolNames)
|
|
298
298
|
: null;
|
|
299
299
|
const suppressedToolCallIds = new Set();
|
|
300
|
+
// Provider-executed calls whose input completed but whose result has not
|
|
301
|
+
// arrived yet. While any is outstanding the local-tool commit grace must not
|
|
302
|
+
// truncate the stream: the provider result can arrive after a separate HTTP
|
|
303
|
+
// continuation.
|
|
304
|
+
const pendingProviderExecutedToolCallIds = new Set();
|
|
300
305
|
const isUnavailableTool = (toolName) => availableToolNames !== null && !availableToolNames.has(toolName);
|
|
301
306
|
const suppressToolCall = (toolCallId, toolName) => {
|
|
302
307
|
if (!toolCallId || suppressedToolCallIds.has(toolCallId)) {
|
|
303
308
|
return;
|
|
304
309
|
}
|
|
305
310
|
suppressedToolCallIds.add(toolCallId);
|
|
311
|
+
pendingProviderExecutedToolCallIds.delete(toolCallId);
|
|
306
312
|
state.suppressedToolCalls.push({ id: toolCallId, name: toolName });
|
|
307
313
|
};
|
|
314
|
+
/**
|
|
315
|
+
* Record a provider-executed call as outstanding.
|
|
316
|
+
*
|
|
317
|
+
* Only call this where the tool call reaches `inputAvailable: true`. That
|
|
318
|
+
* keeps the invariant `id ∈ pending ⟹ toolCalls.get(id).inputAvailable`, so
|
|
319
|
+
* `finalizeUnresolvedProviderToolCalls` always drains the set. Tracking a
|
|
320
|
+
* call whose input never completed (or one already suppressed, which no
|
|
321
|
+
* later part will resolve) would leave an id nothing removes, disabling the
|
|
322
|
+
* local-tool commit grace for the rest of the step.
|
|
323
|
+
*/
|
|
324
|
+
const trackProviderExecutedToolCall = (toolCallId, providerExecuted) => {
|
|
325
|
+
if (!toolCallId || providerExecuted !== true || suppressedToolCallIds.has(toolCallId)) {
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
pendingProviderExecutedToolCallIds.add(toolCallId);
|
|
329
|
+
};
|
|
330
|
+
/**
|
|
331
|
+
* Close out provider-executed calls the provider never resolved.
|
|
332
|
+
*
|
|
333
|
+
* Without a terminal event the call stays `input-available` forever: the UI
|
|
334
|
+
* card spins and persistence judges the part incomplete and drops it.
|
|
335
|
+
* Emitting an error is honest: there genuinely is no content.
|
|
336
|
+
*
|
|
337
|
+
* The synthesized event is stream-only on purpose. Recording it in
|
|
338
|
+
* `state.toolResults` would make the runtime believe the provider answered:
|
|
339
|
+
* `shouldContinueAfterStreamStep()` would flip to true and bill another
|
|
340
|
+
* model call per unresolved call, and the fabricated result would be
|
|
341
|
+
* persisted into model history. The runtime keeps its unchanged view (no
|
|
342
|
+
* result arrived) while the client still gets a terminal part.
|
|
343
|
+
*/
|
|
344
|
+
const finalizeUnresolvedProviderToolCalls = () => {
|
|
345
|
+
if (pendingProviderExecutedToolCallIds.size === 0) {
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
// A preliminary result is recorded like any other, so it must not count as
|
|
349
|
+
// proof the provider answered. Reading it as terminal here would skip the
|
|
350
|
+
// synthesized event and strand the call, which is the failure this whole
|
|
351
|
+
// finalizer exists to close.
|
|
352
|
+
const terminalToolCallIds = new Set(state.toolResults
|
|
353
|
+
.filter((result) => result.preliminary !== true)
|
|
354
|
+
.map((result) => result.toolCallId));
|
|
355
|
+
for (const toolCall of state.toolCalls.values()) {
|
|
356
|
+
if (!pendingProviderExecutedToolCallIds.has(toolCall.id))
|
|
357
|
+
continue;
|
|
358
|
+
if (toolCall.providerExecuted !== true || toolCall.inputAvailable !== true)
|
|
359
|
+
continue;
|
|
360
|
+
if (terminalToolCallIds.has(toolCall.id))
|
|
361
|
+
continue;
|
|
362
|
+
if (suppressedToolCallIds.has(toolCall.id))
|
|
363
|
+
continue;
|
|
364
|
+
sendSSE(controller, encoder, {
|
|
365
|
+
type: "tool-output-error",
|
|
366
|
+
toolCallId: toolCall.id,
|
|
367
|
+
errorText: `Provider-executed tool "${toolCall.name}" returned no result before the model turn ended.`,
|
|
368
|
+
providerExecuted: true,
|
|
369
|
+
...(toolCall.dynamic ? { dynamic: true } : {}),
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
pendingProviderExecutedToolCallIds.clear();
|
|
373
|
+
};
|
|
308
374
|
const resolveProviderExecuted = (toolName, providerExecuted) => providerExecuted ?? (providerExecutedToolNames.has(toolName) ? true : undefined);
|
|
309
375
|
const normalizeReasoningId = (part) => typeof part.id === "string" && part.id.length > 0 ? part.id : "reasoning";
|
|
310
376
|
const openTextSegment = () => {
|
|
@@ -476,479 +542,531 @@ export function processStreamInternal(resultOrSource, state, controller, encoder
|
|
|
476
542
|
});
|
|
477
543
|
};
|
|
478
544
|
throwIfAborted(abortSignal);
|
|
545
|
+
// Terminal events for unresolved provider-executed calls must reach the
|
|
546
|
+
// client even when the stream aborts or throws, so the finalizer runs in a
|
|
547
|
+
// `finally`. It runs after the shadow compare so a synthesized event can
|
|
548
|
+
// never perturb the legacy-vs-reducer snapshot the rollout gate reads.
|
|
479
549
|
const streamIterator = result.fullStream[Symbol.asyncIterator]();
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
const next = hasActiveLocalToolInput
|
|
486
|
-
? await readNextStreamPartWithTimeout(streamIterator, state, callbacks?.localToolInputIdleTimeoutMs ?? LOCAL_TOOL_INPUT_IDLE_MS)
|
|
487
|
-
: shouldStopForCommittedLocalToolCall
|
|
488
|
-
? await readNextStreamPartWithTimeout(streamIterator, state, LOCAL_TOOL_COMMIT_GRACE_MS)
|
|
489
|
-
: shouldStopForIdleOutput
|
|
490
|
-
? await readNextStreamPartWithTimeout(streamIterator, state, callbacks?.streamIdleTimeoutMs ?? STREAM_OUTPUT_IDLE_MS)
|
|
491
|
-
: shouldStopForIdleStart
|
|
492
|
-
? await readNextStreamPartWithTimeout(streamIterator, state, callbacks?.streamIdleTimeoutMs ?? STREAM_START_IDLE_MS)
|
|
493
|
-
: await readNextStreamPart(streamIterator, state);
|
|
494
|
-
if (next === "timeout") {
|
|
495
|
-
state.finishReason ??= shouldStopForIdleOutput || shouldStopForIdleStart
|
|
496
|
-
? "stop"
|
|
497
|
-
: "tool-calls";
|
|
498
|
-
requestStreamIteratorReturn(streamIterator);
|
|
499
|
-
break;
|
|
500
|
-
}
|
|
501
|
-
if (next.done) {
|
|
502
|
-
break;
|
|
503
|
-
}
|
|
504
|
-
const part = next.value;
|
|
505
|
-
throwIfAborted(abortSignal);
|
|
506
|
-
try {
|
|
507
|
-
shadowLifecycle?.observePart(part);
|
|
508
|
-
}
|
|
509
|
-
catch {
|
|
510
|
-
shadowLifecycleFailed = true;
|
|
511
|
-
shadowLifecycle = null;
|
|
512
|
-
}
|
|
513
|
-
eventCount++;
|
|
514
|
-
if (!isRecord(part) || typeof part.type !== "string") {
|
|
515
|
-
continue;
|
|
516
|
-
}
|
|
517
|
-
const typedPart = part;
|
|
518
|
-
if (typedPart.type.startsWith("data-")) {
|
|
519
|
-
sendSSE(controller, encoder, {
|
|
520
|
-
type: typedPart.type,
|
|
521
|
-
data: "data" in typedPart ? typedPart.data : undefined,
|
|
522
|
-
});
|
|
523
|
-
continue;
|
|
550
|
+
let streamIteratorReturned = false;
|
|
551
|
+
/** Release the upstream iterator exactly once, whichever exit is taken. */
|
|
552
|
+
const returnStreamIteratorOnce = () => {
|
|
553
|
+
if (streamIteratorReturned) {
|
|
554
|
+
return;
|
|
524
555
|
}
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
556
|
+
streamIteratorReturned = true;
|
|
557
|
+
requestStreamIteratorReturn(streamIterator);
|
|
558
|
+
};
|
|
559
|
+
try {
|
|
560
|
+
while (true) {
|
|
561
|
+
// A pending provider-executed call outranks the local commit grace: its
|
|
562
|
+
// result can arrive on a later provider continuation request. This picks
|
|
563
|
+
// a longer timeout only. It must not change what a timeout *means*, so
|
|
564
|
+
// the finish-reason classification below stays on the ungated flag.
|
|
565
|
+
const shouldStopForCommittedLocalToolCallNow = shouldStopForCommittedLocalToolCall &&
|
|
566
|
+
pendingProviderExecutedToolCallIds.size === 0;
|
|
567
|
+
const shouldStopForIdleOutput = !hasActiveLocalToolInput &&
|
|
568
|
+
!shouldStopForCommittedLocalToolCallNow && hasStreamOutput(state);
|
|
569
|
+
const shouldStopForIdleStart = !hasActiveLocalToolInput &&
|
|
570
|
+
!shouldStopForCommittedLocalToolCallNow && !hasStreamOutput(state);
|
|
571
|
+
// A timeout means "the turn is over" only when nothing local is in flight
|
|
572
|
+
// and nothing local was committed. Classifying a committed local tool call
|
|
573
|
+
// as "stop" makes shouldContinueAfterStreamStep() bail, so the tool never
|
|
574
|
+
// executes and its card is stranded at input-available.
|
|
575
|
+
const wouldTimeOutIdle = !hasActiveLocalToolInput && !shouldStopForCommittedLocalToolCall;
|
|
576
|
+
const next = hasActiveLocalToolInput
|
|
577
|
+
? await readNextStreamPartWithTimeout(streamIterator, state, callbacks?.localToolInputIdleTimeoutMs ?? LOCAL_TOOL_INPUT_IDLE_MS)
|
|
578
|
+
: shouldStopForCommittedLocalToolCallNow
|
|
579
|
+
? await readNextStreamPartWithTimeout(streamIterator, state, callbacks?.localToolCommitGraceMs ?? LOCAL_TOOL_COMMIT_GRACE_MS)
|
|
580
|
+
: shouldStopForIdleOutput
|
|
581
|
+
? await readNextStreamPartWithTimeout(streamIterator, state, callbacks?.streamIdleTimeoutMs ?? STREAM_OUTPUT_IDLE_MS)
|
|
582
|
+
: shouldStopForIdleStart
|
|
583
|
+
? await readNextStreamPartWithTimeout(streamIterator, state, callbacks?.streamIdleTimeoutMs ?? STREAM_START_IDLE_MS)
|
|
584
|
+
: await readNextStreamPart(streamIterator, state);
|
|
585
|
+
if (next === "timeout") {
|
|
586
|
+
state.finishReason ??= wouldTimeOutIdle ? "stop" : "tool-calls";
|
|
587
|
+
returnStreamIteratorOnce();
|
|
536
588
|
break;
|
|
537
589
|
}
|
|
538
|
-
|
|
539
|
-
closeTextSegment();
|
|
540
|
-
openReasoningSegment(normalizeReasoningId(typedPart));
|
|
590
|
+
if (next.done) {
|
|
541
591
|
break;
|
|
542
592
|
}
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
const reasoningPart = reasoningParts.get(reasoningId);
|
|
548
|
-
if (reasoningPart) {
|
|
549
|
-
reasoningPart.text += typeof typedPart.delta === "string" ? typedPart.delta : "";
|
|
550
|
-
}
|
|
551
|
-
sendSSE(controller, encoder, {
|
|
552
|
-
type: "reasoning-delta",
|
|
553
|
-
id: reasoningId,
|
|
554
|
-
delta: typeof typedPart.delta === "string" ? typedPart.delta : "",
|
|
555
|
-
});
|
|
556
|
-
break;
|
|
593
|
+
const part = next.value;
|
|
594
|
+
throwIfAborted(abortSignal);
|
|
595
|
+
try {
|
|
596
|
+
shadowLifecycle?.observePart(part);
|
|
557
597
|
}
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
activeReasoningId = normalizeReasoningId(typedPart);
|
|
562
|
-
}
|
|
563
|
-
const reasoningPart = reasoningParts.get(activeReasoningId);
|
|
564
|
-
if (reasoningPart) {
|
|
565
|
-
if (typeof typedPart.signature === "string") {
|
|
566
|
-
reasoningPart.signature = typedPart.signature;
|
|
567
|
-
}
|
|
568
|
-
if (typeof typedPart.redactedData === "string") {
|
|
569
|
-
reasoningPart.redactedData = typedPart.redactedData;
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
closeReasoningSegment();
|
|
573
|
-
break;
|
|
598
|
+
catch {
|
|
599
|
+
shadowLifecycleFailed = true;
|
|
600
|
+
shadowLifecycle = null;
|
|
574
601
|
}
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
}
|
|
585
|
-
const providerExecuted = resolveProviderExecuted(typedPart.toolName, typedPart.providerExecuted);
|
|
586
|
-
hasActiveLocalToolInput = providerExecuted !== true;
|
|
587
|
-
state.toolCalls.set(toolId, {
|
|
588
|
-
id: toolId,
|
|
589
|
-
name: typedPart.toolName,
|
|
590
|
-
arguments: "",
|
|
591
|
-
inputAvailable: false,
|
|
592
|
-
providerExecuted,
|
|
593
|
-
dynamic: typedPart.dynamic,
|
|
594
|
-
inputDeltas: [],
|
|
595
|
-
inputAnnounced: false,
|
|
602
|
+
eventCount++;
|
|
603
|
+
if (!isRecord(part) || typeof part.type !== "string") {
|
|
604
|
+
continue;
|
|
605
|
+
}
|
|
606
|
+
const typedPart = part;
|
|
607
|
+
if (typedPart.type.startsWith("data-")) {
|
|
608
|
+
sendSSE(controller, encoder, {
|
|
609
|
+
type: typedPart.type,
|
|
610
|
+
data: "data" in typedPart ? typedPart.data : undefined,
|
|
596
611
|
});
|
|
597
|
-
|
|
612
|
+
continue;
|
|
598
613
|
}
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
614
|
+
switch (typedPart.type) {
|
|
615
|
+
case "text-delta": {
|
|
616
|
+
closeReasoningSegment();
|
|
617
|
+
openTextSegment();
|
|
618
|
+
state.accumulatedText += typedPart.text;
|
|
619
|
+
sendSSE(controller, encoder, {
|
|
620
|
+
type: "text-delta",
|
|
621
|
+
id: textPartId,
|
|
622
|
+
delta: typedPart.text,
|
|
623
|
+
});
|
|
624
|
+
callbacks?.onChunk?.(typedPart.text);
|
|
606
625
|
break;
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
}
|
|
612
|
-
case "tool-input-end": {
|
|
613
|
-
closeTextSegment();
|
|
614
|
-
closeReasoningSegment();
|
|
615
|
-
const toolId = typedPart.id;
|
|
616
|
-
if (suppressedToolCallIds.has(toolId)) {
|
|
617
|
-
hasActiveLocalToolInput = false;
|
|
626
|
+
}
|
|
627
|
+
case "reasoning-start": {
|
|
628
|
+
closeTextSegment();
|
|
629
|
+
openReasoningSegment(normalizeReasoningId(typedPart));
|
|
618
630
|
break;
|
|
619
631
|
}
|
|
620
|
-
|
|
621
|
-
|
|
632
|
+
case "reasoning-delta": {
|
|
633
|
+
closeTextSegment();
|
|
634
|
+
const reasoningId = normalizeReasoningId(typedPart);
|
|
635
|
+
openReasoningSegment(reasoningId);
|
|
636
|
+
const reasoningPart = reasoningParts.get(reasoningId);
|
|
637
|
+
if (reasoningPart) {
|
|
638
|
+
reasoningPart.text += typeof typedPart.delta === "string" ? typedPart.delta : "";
|
|
639
|
+
}
|
|
640
|
+
sendSSE(controller, encoder, {
|
|
641
|
+
type: "reasoning-delta",
|
|
642
|
+
id: reasoningId,
|
|
643
|
+
delta: typeof typedPart.delta === "string" ? typedPart.delta : "",
|
|
644
|
+
});
|
|
622
645
|
break;
|
|
623
|
-
tc.inputAvailable = true;
|
|
624
|
-
hasActiveLocalToolInput = false;
|
|
625
|
-
const dynamic = tc.dynamic ?? isDynamicTool(tc.name);
|
|
626
|
-
if (dynamic) {
|
|
627
|
-
tc.dynamic = true;
|
|
628
646
|
}
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
647
|
+
case "reasoning-end": {
|
|
648
|
+
closeTextSegment();
|
|
649
|
+
if (activeReasoningId === null) {
|
|
650
|
+
activeReasoningId = normalizeReasoningId(typedPart);
|
|
651
|
+
}
|
|
652
|
+
const reasoningPart = reasoningParts.get(activeReasoningId);
|
|
653
|
+
if (reasoningPart) {
|
|
654
|
+
if (typeof typedPart.signature === "string") {
|
|
655
|
+
reasoningPart.signature = typedPart.signature;
|
|
656
|
+
}
|
|
657
|
+
if (typeof typedPart.redactedData === "string") {
|
|
658
|
+
reasoningPart.redactedData = typedPart.redactedData;
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
closeReasoningSegment();
|
|
662
|
+
break;
|
|
640
663
|
}
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
664
|
+
case "tool-input-start": {
|
|
665
|
+
closeTextSegment();
|
|
666
|
+
closeReasoningSegment();
|
|
667
|
+
shouldStopForCommittedLocalToolCall = false;
|
|
668
|
+
const toolId = typedPart.id;
|
|
669
|
+
// A restart drops the call back to `inputAvailable: false`, so an
|
|
670
|
+
// earlier tracking of the same id no longer holds. Leaving it pending
|
|
671
|
+
// would disable the local commit grace for the rest of the step.
|
|
672
|
+
pendingProviderExecutedToolCallIds.delete(toolId);
|
|
673
|
+
if (isUnavailableTool(typedPart.toolName)) {
|
|
674
|
+
suppressToolCall(toolId, typedPart.toolName);
|
|
675
|
+
hasActiveLocalToolInput = false;
|
|
676
|
+
break;
|
|
677
|
+
}
|
|
678
|
+
const providerExecuted = resolveProviderExecuted(typedPart.toolName, typedPart.providerExecuted);
|
|
679
|
+
hasActiveLocalToolInput = providerExecuted !== true;
|
|
680
|
+
state.toolCalls.set(toolId, {
|
|
681
|
+
id: toolId,
|
|
682
|
+
name: typedPart.toolName,
|
|
683
|
+
arguments: "",
|
|
684
|
+
inputAvailable: false,
|
|
685
|
+
providerExecuted,
|
|
686
|
+
dynamic: typedPart.dynamic,
|
|
687
|
+
inputDeltas: [],
|
|
688
|
+
inputAnnounced: false,
|
|
689
|
+
});
|
|
648
690
|
break;
|
|
649
691
|
}
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
692
|
+
case "tool-input-delta": {
|
|
693
|
+
closeReasoningSegment();
|
|
694
|
+
const toolId = typedPart.id;
|
|
695
|
+
if (suppressedToolCallIds.has(toolId))
|
|
696
|
+
break;
|
|
697
|
+
const tc = state.toolCalls.get(toolId);
|
|
698
|
+
if (!tc)
|
|
699
|
+
break;
|
|
700
|
+
tc.arguments = mergeToolInputDelta(tc.arguments, typedPart.delta);
|
|
701
|
+
tc.inputDeltas ??= [];
|
|
702
|
+
tc.inputDeltas.push(typedPart.delta);
|
|
653
703
|
break;
|
|
654
704
|
}
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
dynamic
|
|
670
|
-
|
|
671
|
-
|
|
705
|
+
case "tool-input-end": {
|
|
706
|
+
closeTextSegment();
|
|
707
|
+
closeReasoningSegment();
|
|
708
|
+
const toolId = typedPart.id;
|
|
709
|
+
if (suppressedToolCallIds.has(toolId)) {
|
|
710
|
+
hasActiveLocalToolInput = false;
|
|
711
|
+
break;
|
|
712
|
+
}
|
|
713
|
+
const tc = state.toolCalls.get(toolId);
|
|
714
|
+
if (!tc)
|
|
715
|
+
break;
|
|
716
|
+
tc.inputAvailable = true;
|
|
717
|
+
trackProviderExecutedToolCall(toolId, tc.providerExecuted);
|
|
718
|
+
hasActiveLocalToolInput = false;
|
|
719
|
+
const dynamic = tc.dynamic ?? isDynamicTool(tc.name);
|
|
720
|
+
if (dynamic) {
|
|
721
|
+
tc.dynamic = true;
|
|
722
|
+
}
|
|
723
|
+
announceToolInputStart(tc);
|
|
672
724
|
sendSSE(controller, encoder, {
|
|
673
725
|
type: "tool-input-available",
|
|
674
726
|
toolCallId: toolId,
|
|
675
|
-
toolName:
|
|
676
|
-
input: parseToolInputObject(
|
|
677
|
-
...(providerExecuted !== undefined
|
|
727
|
+
toolName: tc.name,
|
|
728
|
+
input: parseToolInputObject(tc.arguments),
|
|
729
|
+
...(tc.providerExecuted !== undefined
|
|
730
|
+
? { providerExecuted: tc.providerExecuted }
|
|
731
|
+
: {}),
|
|
678
732
|
...(dynamic ? { dynamic: true } : {}),
|
|
679
733
|
});
|
|
734
|
+
if (tc.providerExecuted !== true) {
|
|
735
|
+
shouldStopForCommittedLocalToolCall = true;
|
|
736
|
+
}
|
|
737
|
+
break;
|
|
680
738
|
}
|
|
681
|
-
|
|
682
|
-
|
|
739
|
+
case "tool-input-available": {
|
|
740
|
+
closeTextSegment();
|
|
741
|
+
closeReasoningSegment();
|
|
742
|
+
const toolId = typedPart.toolCallId ?? typedPart.id;
|
|
743
|
+
if (!toolId) {
|
|
744
|
+
break;
|
|
745
|
+
}
|
|
746
|
+
if (isUnavailableTool(typedPart.toolName)) {
|
|
747
|
+
suppressToolCall(toolId, typedPart.toolName);
|
|
748
|
+
hasActiveLocalToolInput = false;
|
|
749
|
+
break;
|
|
750
|
+
}
|
|
751
|
+
const providerExecuted = resolveProviderExecuted(typedPart.toolName, typedPart.providerExecuted);
|
|
752
|
+
hasActiveLocalToolInput = false;
|
|
753
|
+
trackProviderExecutedToolCall(toolId, providerExecuted);
|
|
754
|
+
const inputStr = normalizeToolInputString(typedPart.input);
|
|
755
|
+
const previous = state.toolCalls.get(toolId);
|
|
756
|
+
const previousArguments = previous?.arguments ?? "";
|
|
757
|
+
const resolvedArguments = mergeToolCallInput(previousArguments, inputStr);
|
|
758
|
+
const wasInputAvailable = previous?.inputAvailable === true;
|
|
759
|
+
const dynamic = typedPart.dynamic ?? isDynamicTool(typedPart.toolName);
|
|
760
|
+
state.toolCalls.set(toolId, {
|
|
761
|
+
id: toolId,
|
|
762
|
+
name: typedPart.toolName,
|
|
763
|
+
arguments: resolvedArguments,
|
|
764
|
+
inputAvailable: true,
|
|
765
|
+
providerExecuted,
|
|
766
|
+
dynamic,
|
|
767
|
+
});
|
|
768
|
+
if (!wasInputAvailable) {
|
|
769
|
+
sendSSE(controller, encoder, {
|
|
770
|
+
type: "tool-input-available",
|
|
771
|
+
toolCallId: toolId,
|
|
772
|
+
toolName: typedPart.toolName,
|
|
773
|
+
input: parseToolInputObject(resolvedArguments),
|
|
774
|
+
...(providerExecuted !== undefined ? { providerExecuted } : {}),
|
|
775
|
+
...(dynamic ? { dynamic: true } : {}),
|
|
776
|
+
});
|
|
777
|
+
}
|
|
778
|
+
if (providerExecuted !== true) {
|
|
779
|
+
shouldStopForCommittedLocalToolCall = true;
|
|
780
|
+
}
|
|
781
|
+
break;
|
|
683
782
|
}
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
783
|
+
case "tool-call": {
|
|
784
|
+
closeTextSegment();
|
|
785
|
+
closeReasoningSegment();
|
|
786
|
+
// tool-call fires when the full tool call is available
|
|
787
|
+
const toolId = typedPart.toolCallId;
|
|
788
|
+
if (isUnavailableTool(typedPart.toolName)) {
|
|
789
|
+
suppressToolCall(toolId, typedPart.toolName);
|
|
790
|
+
hasActiveLocalToolInput = false;
|
|
791
|
+
break;
|
|
792
|
+
}
|
|
793
|
+
const providerExecuted = resolveProviderExecuted(typedPart.toolName, typedPart.providerExecuted);
|
|
693
794
|
hasActiveLocalToolInput = false;
|
|
795
|
+
trackProviderExecutedToolCall(toolId, providerExecuted);
|
|
796
|
+
const inputStr = normalizeToolInputString(typedPart.input);
|
|
797
|
+
const previous = state.toolCalls.get(toolId);
|
|
798
|
+
const previousArguments = previous?.arguments ?? "";
|
|
799
|
+
const resolvedArguments = mergeToolCallInput(previousArguments, inputStr);
|
|
800
|
+
const wasInputAvailable = previous?.inputAvailable === true;
|
|
801
|
+
const toolCall = {
|
|
802
|
+
id: toolId,
|
|
803
|
+
name: typedPart.toolName,
|
|
804
|
+
arguments: resolvedArguments,
|
|
805
|
+
inputDeltas: previous?.inputDeltas ?? [],
|
|
806
|
+
inputAnnounced: previous?.inputAnnounced ?? false,
|
|
807
|
+
inputAvailable: true,
|
|
808
|
+
providerExecuted,
|
|
809
|
+
dynamic: typedPart.dynamic,
|
|
810
|
+
};
|
|
811
|
+
state.toolCalls.set(toolId, toolCall);
|
|
812
|
+
const dynamic = isDynamicTool(typedPart.toolName);
|
|
813
|
+
const inputObj = parseToolInputObject(typedPart.input);
|
|
814
|
+
announceToolInputStart(toolCall);
|
|
815
|
+
if (!wasInputAvailable) {
|
|
816
|
+
sendSSE(controller, encoder, {
|
|
817
|
+
type: "tool-input-available",
|
|
818
|
+
toolCallId: toolId,
|
|
819
|
+
toolName: typedPart.toolName,
|
|
820
|
+
input: inputObj,
|
|
821
|
+
...(providerExecuted !== undefined ? { providerExecuted } : {}),
|
|
822
|
+
...(dynamic ? { dynamic: true } : {}),
|
|
823
|
+
});
|
|
824
|
+
}
|
|
825
|
+
if (providerExecuted !== true) {
|
|
826
|
+
shouldStopForCommittedLocalToolCall = true;
|
|
827
|
+
}
|
|
694
828
|
break;
|
|
695
829
|
}
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
830
|
+
case "tool-result": {
|
|
831
|
+
closeTextSegment();
|
|
832
|
+
closeReasoningSegment();
|
|
833
|
+
if (suppressedToolCallIds.has(typedPart.toolCallId) ||
|
|
834
|
+
isUnavailableTool(typedPart.toolName)) {
|
|
835
|
+
suppressToolCall(typedPart.toolCallId, typedPart.toolName);
|
|
836
|
+
break;
|
|
837
|
+
}
|
|
838
|
+
const providerExecuted = resolveProviderExecuted(typedPart.toolName, typedPart.providerExecuted);
|
|
839
|
+
// A preliminary result is not terminal: the provider is still
|
|
840
|
+
// working. Releasing the call here would re-arm the local commit
|
|
841
|
+
// grace and truncate the stream before the final result arrives,
|
|
842
|
+
// which is the failure this tracking exists to prevent.
|
|
843
|
+
if (typedPart.preliminary !== true) {
|
|
844
|
+
pendingProviderExecutedToolCallIds.delete(typedPart.toolCallId);
|
|
845
|
+
}
|
|
846
|
+
ensureToolLifecycle({
|
|
847
|
+
toolCallId: typedPart.toolCallId,
|
|
848
|
+
toolName: typedPart.toolName,
|
|
849
|
+
input: typedPart.input,
|
|
850
|
+
providerExecuted,
|
|
851
|
+
dynamic: typedPart.dynamic,
|
|
852
|
+
});
|
|
853
|
+
const toolResultOutput = resolveToolResultOutput(typedPart);
|
|
854
|
+
const inferredToolError = getToolResultError(toolResultOutput);
|
|
855
|
+
const isExplicitError = typedPart.isError === true &&
|
|
856
|
+
!isIntegrationAuthenticationActionResult(toolResultOutput);
|
|
857
|
+
const isError = isExplicitError || inferredToolError !== undefined;
|
|
858
|
+
const toolResultError = isExplicitError
|
|
859
|
+
? toolResultOutput
|
|
860
|
+
: inferredToolError ?? toolResultOutput;
|
|
861
|
+
logProviderToolPart("tool-result", {
|
|
862
|
+
toolCallId: typedPart.toolCallId,
|
|
863
|
+
toolName: typedPart.toolName,
|
|
864
|
+
providerExecuted,
|
|
865
|
+
dynamic: typedPart.dynamic,
|
|
866
|
+
output: toolResultOutput,
|
|
867
|
+
input: typedPart.input,
|
|
868
|
+
preliminary: typedPart.preliminary,
|
|
869
|
+
isError,
|
|
870
|
+
});
|
|
871
|
+
if (isError) {
|
|
872
|
+
state.toolResults.push({
|
|
873
|
+
toolCallId: typedPart.toolCallId,
|
|
874
|
+
toolName: typedPart.toolName,
|
|
875
|
+
error: toolResultError,
|
|
876
|
+
...(providerExecuted !== undefined ? { providerExecuted } : {}),
|
|
877
|
+
...(typedPart.dynamic ? { dynamic: true } : {}),
|
|
878
|
+
});
|
|
879
|
+
sendSSE(controller, encoder, {
|
|
880
|
+
type: "tool-output-error",
|
|
881
|
+
toolCallId: typedPart.toolCallId,
|
|
882
|
+
errorText: stringifyToolError(toolResultError),
|
|
883
|
+
...(providerExecuted !== undefined ? { providerExecuted } : {}),
|
|
884
|
+
...(typedPart.dynamic ? { dynamic: true } : {}),
|
|
885
|
+
});
|
|
886
|
+
break;
|
|
887
|
+
}
|
|
888
|
+
state.toolResults.push({
|
|
889
|
+
toolCallId: typedPart.toolCallId,
|
|
721
890
|
toolName: typedPart.toolName,
|
|
722
|
-
|
|
891
|
+
output: toolResultOutput,
|
|
723
892
|
...(providerExecuted !== undefined ? { providerExecuted } : {}),
|
|
724
|
-
...(dynamic ? { dynamic: true } : {}),
|
|
893
|
+
...(typedPart.dynamic ? { dynamic: true } : {}),
|
|
894
|
+
...(typedPart.preliminary !== undefined
|
|
895
|
+
? { preliminary: typedPart.preliminary }
|
|
896
|
+
: {}),
|
|
897
|
+
});
|
|
898
|
+
sendSSE(controller, encoder, {
|
|
899
|
+
type: "tool-output-available",
|
|
900
|
+
toolCallId: typedPart.toolCallId,
|
|
901
|
+
output: toolResultOutput,
|
|
902
|
+
...(providerExecuted !== undefined ? { providerExecuted } : {}),
|
|
903
|
+
...(typedPart.dynamic ? { dynamic: true } : {}),
|
|
904
|
+
...(typedPart.preliminary !== undefined
|
|
905
|
+
? { preliminary: typedPart.preliminary }
|
|
906
|
+
: {}),
|
|
725
907
|
});
|
|
726
|
-
}
|
|
727
|
-
if (providerExecuted !== true) {
|
|
728
|
-
shouldStopForCommittedLocalToolCall = true;
|
|
729
|
-
}
|
|
730
|
-
break;
|
|
731
|
-
}
|
|
732
|
-
case "tool-result": {
|
|
733
|
-
closeTextSegment();
|
|
734
|
-
closeReasoningSegment();
|
|
735
|
-
if (suppressedToolCallIds.has(typedPart.toolCallId) ||
|
|
736
|
-
isUnavailableTool(typedPart.toolName)) {
|
|
737
|
-
suppressToolCall(typedPart.toolCallId, typedPart.toolName);
|
|
738
908
|
break;
|
|
739
909
|
}
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
dynamic: typedPart.dynamic,
|
|
761
|
-
output: toolResultOutput,
|
|
762
|
-
input: typedPart.input,
|
|
763
|
-
preliminary: typedPart.preliminary,
|
|
764
|
-
isError,
|
|
765
|
-
});
|
|
766
|
-
if (isError) {
|
|
910
|
+
case "tool-error": {
|
|
911
|
+
closeTextSegment();
|
|
912
|
+
closeReasoningSegment();
|
|
913
|
+
const providerExecuted = resolveProviderExecuted(typedPart.toolName, typedPart.providerExecuted);
|
|
914
|
+
pendingProviderExecutedToolCallIds.delete(typedPart.toolCallId);
|
|
915
|
+
ensureToolLifecycle({
|
|
916
|
+
toolCallId: typedPart.toolCallId,
|
|
917
|
+
toolName: typedPart.toolName,
|
|
918
|
+
input: typedPart.input,
|
|
919
|
+
providerExecuted,
|
|
920
|
+
dynamic: typedPart.dynamic,
|
|
921
|
+
});
|
|
922
|
+
logProviderToolPart("tool-error", {
|
|
923
|
+
toolCallId: typedPart.toolCallId,
|
|
924
|
+
toolName: typedPart.toolName,
|
|
925
|
+
providerExecuted,
|
|
926
|
+
dynamic: typedPart.dynamic,
|
|
927
|
+
error: typedPart.error,
|
|
928
|
+
input: typedPart.input,
|
|
929
|
+
});
|
|
767
930
|
state.toolResults.push({
|
|
768
931
|
toolCallId: typedPart.toolCallId,
|
|
769
932
|
toolName: typedPart.toolName,
|
|
770
|
-
error:
|
|
933
|
+
error: typedPart.error,
|
|
771
934
|
...(providerExecuted !== undefined ? { providerExecuted } : {}),
|
|
772
935
|
...(typedPart.dynamic ? { dynamic: true } : {}),
|
|
773
936
|
});
|
|
774
937
|
sendSSE(controller, encoder, {
|
|
775
938
|
type: "tool-output-error",
|
|
776
939
|
toolCallId: typedPart.toolCallId,
|
|
777
|
-
errorText: stringifyToolError(
|
|
940
|
+
errorText: stringifyToolError(typedPart.error),
|
|
778
941
|
...(providerExecuted !== undefined ? { providerExecuted } : {}),
|
|
779
942
|
...(typedPart.dynamic ? { dynamic: true } : {}),
|
|
780
943
|
});
|
|
781
944
|
break;
|
|
782
945
|
}
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
946
|
+
case "finish": {
|
|
947
|
+
closeTextSegment();
|
|
948
|
+
closeReasoningSegment();
|
|
949
|
+
state.finishReason = typedPart.finishReason ?? null;
|
|
950
|
+
if (state.finishReason) {
|
|
951
|
+
setActiveSpanAttributes({
|
|
952
|
+
"gen_ai.response.finish_reasons": [state.finishReason],
|
|
953
|
+
});
|
|
954
|
+
}
|
|
955
|
+
if (state.finishReason === "tool-calls") {
|
|
956
|
+
commitParseablePendingToolInputs();
|
|
957
|
+
}
|
|
958
|
+
if (typedPart.totalUsage) {
|
|
959
|
+
const input = typedPart.totalUsage.inputTokens ?? 0;
|
|
960
|
+
const output = typedPart.totalUsage.outputTokens ?? 0;
|
|
961
|
+
const cacheReadInputTokens = typedPart.totalUsage.cacheReadInputTokens;
|
|
962
|
+
const cacheCreationInputTokens = typedPart.totalUsage.cacheCreationInputTokens;
|
|
963
|
+
const cachedInputTokens = typedPart.totalUsage.cachedInputTokens ??
|
|
964
|
+
cacheReadInputTokens;
|
|
965
|
+
state.usage = {
|
|
966
|
+
promptTokens: input,
|
|
967
|
+
completionTokens: output,
|
|
968
|
+
totalTokens: typedPart.totalUsage.totalTokens ?? input + output,
|
|
969
|
+
...(cachedInputTokens !== undefined ? { cachedInputTokens } : {}),
|
|
970
|
+
...(cacheCreationInputTokens !== undefined ? { cacheCreationInputTokens } : {}),
|
|
971
|
+
...(cacheReadInputTokens !== undefined ? { cacheReadInputTokens } : {}),
|
|
972
|
+
...(typedPart.totalUsage.reasoningTokens !== undefined
|
|
973
|
+
? { reasoningTokens: typedPart.totalUsage.reasoningTokens }
|
|
974
|
+
: {}),
|
|
975
|
+
...(typedPart.totalUsage.billableInputTokens !== undefined
|
|
976
|
+
? { billableInputTokens: typedPart.totalUsage.billableInputTokens }
|
|
977
|
+
: {}),
|
|
978
|
+
...(typedPart.totalUsage.billableOutputTokens !== undefined
|
|
979
|
+
? { billableOutputTokens: typedPart.totalUsage.billableOutputTokens }
|
|
980
|
+
: {}),
|
|
981
|
+
...(typedPart.totalUsage.costUsd !== undefined
|
|
982
|
+
? { costUsd: typedPart.totalUsage.costUsd }
|
|
983
|
+
: {}),
|
|
984
|
+
...(typedPart.totalUsage.providerInputCostUsd !== undefined
|
|
985
|
+
? { providerInputCostUsd: typedPart.totalUsage.providerInputCostUsd }
|
|
986
|
+
: {}),
|
|
987
|
+
...(typedPart.totalUsage.providerOutputCostUsd !== undefined
|
|
988
|
+
? { providerOutputCostUsd: typedPart.totalUsage.providerOutputCostUsd }
|
|
989
|
+
: {}),
|
|
990
|
+
...(typedPart.totalUsage.providerCostUsd !== undefined
|
|
991
|
+
? { providerCostUsd: typedPart.totalUsage.providerCostUsd }
|
|
992
|
+
: {}),
|
|
993
|
+
...(typedPart.totalUsage.veryfrontInputChargeUsd !== undefined
|
|
994
|
+
? { veryfrontInputChargeUsd: typedPart.totalUsage.veryfrontInputChargeUsd }
|
|
995
|
+
: {}),
|
|
996
|
+
...(typedPart.totalUsage.veryfrontOutputChargeUsd !== undefined
|
|
997
|
+
? { veryfrontOutputChargeUsd: typedPart.totalUsage.veryfrontOutputChargeUsd }
|
|
998
|
+
: {}),
|
|
999
|
+
...(typedPart.totalUsage.veryfrontChargeUsd !== undefined
|
|
1000
|
+
? { veryfrontChargeUsd: typedPart.totalUsage.veryfrontChargeUsd }
|
|
1001
|
+
: {}),
|
|
1002
|
+
...(typedPart.totalUsage.veryfrontBilledUsd !== undefined
|
|
1003
|
+
? { veryfrontBilledUsd: typedPart.totalUsage.veryfrontBilledUsd }
|
|
1004
|
+
: {}),
|
|
1005
|
+
...(typedPart.totalUsage.costCredits !== undefined
|
|
1006
|
+
? { costCredits: typedPart.totalUsage.costCredits }
|
|
1007
|
+
: {}),
|
|
1008
|
+
...(typedPart.totalUsage.costSource !== undefined
|
|
1009
|
+
? { costSource: typedPart.totalUsage.costSource }
|
|
1010
|
+
: {}),
|
|
1011
|
+
...(typedPart.totalUsage.billingMode !== undefined
|
|
1012
|
+
? { billingMode: typedPart.totalUsage.billingMode }
|
|
1013
|
+
: {}),
|
|
1014
|
+
...(typedPart.totalUsage.usageCaptureStatus !== undefined
|
|
1015
|
+
? { usageCaptureStatus: typedPart.totalUsage.usageCaptureStatus }
|
|
1016
|
+
: {}),
|
|
1017
|
+
};
|
|
1018
|
+
callbacks?.onUsage?.(state.usage);
|
|
1019
|
+
setActiveSpanAttributes(buildRuntimeUsageTraceAttributes(state.usage));
|
|
1020
|
+
}
|
|
1021
|
+
break;
|
|
847
1022
|
}
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
...(cachedInputTokens !== undefined ? { cachedInputTokens } : {}),
|
|
860
|
-
...(cacheCreationInputTokens !== undefined ? { cacheCreationInputTokens } : {}),
|
|
861
|
-
...(cacheReadInputTokens !== undefined ? { cacheReadInputTokens } : {}),
|
|
862
|
-
...(typedPart.totalUsage.reasoningTokens !== undefined
|
|
863
|
-
? { reasoningTokens: typedPart.totalUsage.reasoningTokens }
|
|
864
|
-
: {}),
|
|
865
|
-
...(typedPart.totalUsage.billableInputTokens !== undefined
|
|
866
|
-
? { billableInputTokens: typedPart.totalUsage.billableInputTokens }
|
|
867
|
-
: {}),
|
|
868
|
-
...(typedPart.totalUsage.billableOutputTokens !== undefined
|
|
869
|
-
? { billableOutputTokens: typedPart.totalUsage.billableOutputTokens }
|
|
870
|
-
: {}),
|
|
871
|
-
...(typedPart.totalUsage.costUsd !== undefined
|
|
872
|
-
? { costUsd: typedPart.totalUsage.costUsd }
|
|
873
|
-
: {}),
|
|
874
|
-
...(typedPart.totalUsage.providerInputCostUsd !== undefined
|
|
875
|
-
? { providerInputCostUsd: typedPart.totalUsage.providerInputCostUsd }
|
|
876
|
-
: {}),
|
|
877
|
-
...(typedPart.totalUsage.providerOutputCostUsd !== undefined
|
|
878
|
-
? { providerOutputCostUsd: typedPart.totalUsage.providerOutputCostUsd }
|
|
879
|
-
: {}),
|
|
880
|
-
...(typedPart.totalUsage.providerCostUsd !== undefined
|
|
881
|
-
? { providerCostUsd: typedPart.totalUsage.providerCostUsd }
|
|
882
|
-
: {}),
|
|
883
|
-
...(typedPart.totalUsage.veryfrontInputChargeUsd !== undefined
|
|
884
|
-
? { veryfrontInputChargeUsd: typedPart.totalUsage.veryfrontInputChargeUsd }
|
|
885
|
-
: {}),
|
|
886
|
-
...(typedPart.totalUsage.veryfrontOutputChargeUsd !== undefined
|
|
887
|
-
? { veryfrontOutputChargeUsd: typedPart.totalUsage.veryfrontOutputChargeUsd }
|
|
888
|
-
: {}),
|
|
889
|
-
...(typedPart.totalUsage.veryfrontChargeUsd !== undefined
|
|
890
|
-
? { veryfrontChargeUsd: typedPart.totalUsage.veryfrontChargeUsd }
|
|
891
|
-
: {}),
|
|
892
|
-
...(typedPart.totalUsage.veryfrontBilledUsd !== undefined
|
|
893
|
-
? { veryfrontBilledUsd: typedPart.totalUsage.veryfrontBilledUsd }
|
|
894
|
-
: {}),
|
|
895
|
-
...(typedPart.totalUsage.costCredits !== undefined
|
|
896
|
-
? { costCredits: typedPart.totalUsage.costCredits }
|
|
897
|
-
: {}),
|
|
898
|
-
...(typedPart.totalUsage.costSource !== undefined
|
|
899
|
-
? { costSource: typedPart.totalUsage.costSource }
|
|
900
|
-
: {}),
|
|
901
|
-
...(typedPart.totalUsage.billingMode !== undefined
|
|
902
|
-
? { billingMode: typedPart.totalUsage.billingMode }
|
|
903
|
-
: {}),
|
|
904
|
-
...(typedPart.totalUsage.usageCaptureStatus !== undefined
|
|
905
|
-
? { usageCaptureStatus: typedPart.totalUsage.usageCaptureStatus }
|
|
906
|
-
: {}),
|
|
907
|
-
};
|
|
908
|
-
callbacks?.onUsage?.(state.usage);
|
|
909
|
-
setActiveSpanAttributes(buildRuntimeUsageTraceAttributes(state.usage));
|
|
1023
|
+
case "error": {
|
|
1024
|
+
closeTextSegment();
|
|
1025
|
+
closeReasoningSegment();
|
|
1026
|
+
logger.warn("Runtime stream error:", typedPart.error);
|
|
1027
|
+
sendSSE(controller, encoder, {
|
|
1028
|
+
type: "error",
|
|
1029
|
+
error: typedPart.error instanceof Error
|
|
1030
|
+
? typedPart.error.message
|
|
1031
|
+
: String(typedPart.error),
|
|
1032
|
+
});
|
|
1033
|
+
break;
|
|
910
1034
|
}
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
closeTextSegment();
|
|
915
|
-
closeReasoningSegment();
|
|
916
|
-
logger.warn("Runtime stream error:", typedPart.error);
|
|
917
|
-
sendSSE(controller, encoder, {
|
|
918
|
-
type: "error",
|
|
919
|
-
error: typedPart.error instanceof Error
|
|
920
|
-
? typedPart.error.message
|
|
921
|
-
: String(typedPart.error),
|
|
922
|
-
});
|
|
923
|
-
break;
|
|
1035
|
+
default:
|
|
1036
|
+
// Ignore other stream parts (source, file, reasoning-*, etc.)
|
|
1037
|
+
break;
|
|
924
1038
|
}
|
|
925
|
-
|
|
926
|
-
// Ignore other stream parts (source, file, reasoning-*, etc.)
|
|
927
|
-
break;
|
|
1039
|
+
throwIfAborted(abortSignal);
|
|
928
1040
|
}
|
|
929
1041
|
throwIfAborted(abortSignal);
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
1042
|
+
if (callbacks?.streamLifecycleMode === "shadow") {
|
|
1043
|
+
let observed = { count: 0, categories: [] };
|
|
1044
|
+
try {
|
|
1045
|
+
observed = shadowLifecycle?.compareLegacySnapshot(state) ?? observed;
|
|
1046
|
+
}
|
|
1047
|
+
catch {
|
|
1048
|
+
shadowLifecycleFailed = true;
|
|
1049
|
+
}
|
|
1050
|
+
const categories = new Set(observed.categories);
|
|
1051
|
+
if (shadowLifecycleFailed)
|
|
1052
|
+
categories.add("shadow_error");
|
|
1053
|
+
const report = {
|
|
1054
|
+
count: categories.size,
|
|
1055
|
+
categories: [...categories].sort(),
|
|
1056
|
+
};
|
|
1057
|
+
callbacks.onLifecycleShadowReport?.(report);
|
|
1058
|
+
setActiveSpanAttributes({
|
|
1059
|
+
"stream.lifecycle_shadow.divergence_count": report.count,
|
|
1060
|
+
"stream.lifecycle_shadow.divergence_categories": [...report.categories],
|
|
1061
|
+
});
|
|
939
1062
|
}
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
callbacks.onLifecycleShadowReport?.(report);
|
|
948
|
-
setActiveSpanAttributes({
|
|
949
|
-
"stream.lifecycle_shadow.divergence_count": report.count,
|
|
950
|
-
"stream.lifecycle_shadow.divergence_categories": [...report.categories],
|
|
951
|
-
});
|
|
1063
|
+
}
|
|
1064
|
+
finally {
|
|
1065
|
+
finalizeUnresolvedProviderToolCalls();
|
|
1066
|
+
// `throwIfAborted` and `streamIterator.next()` can both throw past the
|
|
1067
|
+
// loop, so the upstream iterator is released here rather than only on the
|
|
1068
|
+
// timeout path.
|
|
1069
|
+
returnStreamIteratorOnce();
|
|
952
1070
|
}
|
|
953
1071
|
setActiveSpanAttributes({
|
|
954
1072
|
"stream.event_count": eventCount,
|