@tanstack/ai 0.47.3 → 0.48.0

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.
Files changed (101) hide show
  1. package/README.md +2 -1
  2. package/dist/esm/activities/chat/adapter.d.ts +5 -4
  3. package/dist/esm/activities/chat/adapter.js.map +1 -1
  4. package/dist/esm/activities/chat/index.d.ts +4 -7
  5. package/dist/esm/activities/chat/index.js +201 -243
  6. package/dist/esm/activities/chat/index.js.map +1 -1
  7. package/dist/esm/activities/chat/messages.js +115 -25
  8. package/dist/esm/activities/chat/messages.js.map +1 -1
  9. package/dist/esm/activities/chat/stream/processor.d.ts +38 -17
  10. package/dist/esm/activities/chat/stream/processor.js +186 -101
  11. package/dist/esm/activities/chat/stream/processor.js.map +1 -1
  12. package/dist/esm/activities/chat/tools/tool-calls.d.ts +3 -2
  13. package/dist/esm/activities/chat/tools/tool-calls.js +15 -10
  14. package/dist/esm/activities/chat/tools/tool-calls.js.map +1 -1
  15. package/dist/esm/activities/generateVideo/index.js +6 -6
  16. package/dist/esm/activities/generateVideo/index.js.map +1 -1
  17. package/dist/esm/activities/stream-generation-result.js +7 -8
  18. package/dist/esm/activities/stream-generation-result.js.map +1 -1
  19. package/dist/esm/activities/summarize/chat-stream-summarize.d.ts +2 -1
  20. package/dist/esm/activities/summarize/chat-stream-summarize.js +56 -53
  21. package/dist/esm/activities/summarize/chat-stream-summarize.js.map +1 -1
  22. package/dist/esm/adapter-internals.d.ts +2 -0
  23. package/dist/esm/adapter-internals.js +3 -1
  24. package/dist/esm/client.d.ts +8 -1
  25. package/dist/esm/client.js +7 -2
  26. package/dist/esm/client.js.map +1 -1
  27. package/dist/esm/index.d.ts +6 -0
  28. package/dist/esm/index.js +6 -2
  29. package/dist/esm/middlewares/otel.js +11 -4
  30. package/dist/esm/middlewares/otel.js.map +1 -1
  31. package/dist/esm/stream-to-response.js +8 -5
  32. package/dist/esm/stream-to-response.js.map +1 -1
  33. package/dist/esm/stream-to-websocket.js +4 -2
  34. package/dist/esm/stream-to-websocket.js.map +1 -1
  35. package/dist/esm/strip-to-spec-middleware.d.ts +10 -13
  36. package/dist/esm/strip-to-spec-middleware.js +24 -22
  37. package/dist/esm/strip-to-spec-middleware.js.map +1 -1
  38. package/dist/esm/types.d.ts +82 -305
  39. package/dist/esm/utilities/adapter-yield-chunk.d.ts +31 -0
  40. package/dist/esm/utilities/ag-ui-usage.d.ts +24 -0
  41. package/dist/esm/utilities/ag-ui-usage.js +66 -0
  42. package/dist/esm/utilities/ag-ui-usage.js.map +1 -0
  43. package/dist/esm/utilities/ag-ui-wire.d.ts +14 -7
  44. package/dist/esm/utilities/ag-ui-wire.js +71 -30
  45. package/dist/esm/utilities/ag-ui-wire.js.map +1 -1
  46. package/dist/esm/utilities/chat-params.d.ts +3 -3
  47. package/dist/esm/utilities/chat-params.js +10 -30
  48. package/dist/esm/utilities/chat-params.js.map +1 -1
  49. package/dist/esm/utilities/chunk-ids.d.ts +5 -0
  50. package/dist/esm/utilities/chunk-ids.js +25 -0
  51. package/dist/esm/utilities/chunk-ids.js.map +1 -0
  52. package/dist/esm/utilities/merge-metadata.d.ts +14 -0
  53. package/dist/esm/utilities/merge-metadata.js +43 -0
  54. package/dist/esm/utilities/merge-metadata.js.map +1 -0
  55. package/dist/esm/utilities/normalize-stream-chunk.d.ts +3 -0
  56. package/dist/esm/utilities/normalize-stream-chunk.js +100 -0
  57. package/dist/esm/utilities/normalize-stream-chunk.js.map +1 -0
  58. package/dist/esm/utilities/reasoning-encrypted-value.d.ts +8 -0
  59. package/dist/esm/utilities/reasoning-encrypted-value.js +16 -0
  60. package/dist/esm/utilities/reasoning-encrypted-value.js.map +1 -0
  61. package/dist/esm/utilities/restore-inbound-chunk.d.ts +15 -0
  62. package/dist/esm/utilities/restore-inbound-chunk.js +43 -0
  63. package/dist/esm/utilities/restore-inbound-chunk.js.map +1 -0
  64. package/dist/esm/utilities/spec-event-keys.d.ts +2 -0
  65. package/dist/esm/utilities/spec-event-keys.js +56 -0
  66. package/dist/esm/utilities/spec-event-keys.js.map +1 -0
  67. package/dist/esm/utilities/structured-output-events.d.ts +3 -3
  68. package/dist/esm/utilities/structured-output-events.js.map +1 -1
  69. package/package.json +2 -2
  70. package/src/activities/chat/adapter.ts +4 -4
  71. package/src/activities/chat/index.ts +398 -400
  72. package/src/activities/chat/messages.ts +174 -34
  73. package/src/activities/chat/stream/processor.ts +289 -218
  74. package/src/activities/chat/tools/tool-calls.ts +23 -22
  75. package/src/activities/generateVideo/index.ts +7 -6
  76. package/src/activities/stream-generation-result.ts +8 -12
  77. package/src/activities/summarize/chat-stream-summarize.ts +94 -70
  78. package/src/adapter-internals.ts +2 -0
  79. package/src/client.ts +13 -0
  80. package/src/index.ts +6 -0
  81. package/src/middlewares/otel.ts +16 -8
  82. package/src/stream-to-response.ts +11 -4
  83. package/src/stream-to-websocket.ts +3 -1
  84. package/src/strip-to-spec-middleware.ts +48 -24
  85. package/src/types.ts +109 -393
  86. package/src/utilities/adapter-yield-chunk.ts +30 -0
  87. package/src/utilities/ag-ui-usage.test.ts +194 -0
  88. package/src/utilities/ag-ui-usage.ts +148 -0
  89. package/src/utilities/ag-ui-wire.ts +149 -31
  90. package/src/utilities/chat-params.ts +22 -39
  91. package/src/utilities/chunk-ids.ts +24 -0
  92. package/src/utilities/merge-metadata.test.ts +117 -0
  93. package/src/utilities/merge-metadata.ts +59 -0
  94. package/src/utilities/normalize-stream-chunk.test.ts +423 -0
  95. package/src/utilities/normalize-stream-chunk.ts +186 -0
  96. package/src/utilities/reasoning-encrypted-value.ts +18 -0
  97. package/src/utilities/restore-inbound-chunk.test.ts +133 -0
  98. package/src/utilities/restore-inbound-chunk.ts +72 -0
  99. package/src/utilities/spec-event-keys.test.ts +34 -0
  100. package/src/utilities/spec-event-keys.ts +74 -0
  101. package/src/utilities/structured-output-events.ts +3 -3
@@ -1,10 +1,12 @@
1
- import { stripToSpecMiddleware } from "../../strip-to-spec-middleware.js";
2
1
  import { isCancelRequestedReason } from "./cancel.js";
3
2
  import { CapabilityRegistry } from "./middleware/capabilities.js";
4
3
  import { getRunDetached } from "./middleware/run-store.js";
5
4
  import { publishRunDetachedSignal } from "../../delivery-detach.js";
6
5
  import { publishRunDisconnectHandler } from "../../delivery-disconnect.js";
7
6
  import { EventType } from "../../types.js";
7
+ import { rebuildTokenUsage } from "../../utilities/ag-ui-usage.js";
8
+ import { tanstackMetadata, withTanstackMetadata } from "../../utilities/merge-metadata.js";
9
+ import { normalizeStreamChunk } from "../../utilities/normalize-stream-chunk.js";
8
10
  import { resolveDebugOption } from "../../logger/resolve.js";
9
11
  import { streamToText } from "../../stream-to-response.js";
10
12
  import { canonicalInterruptJson, digestInterruptJson } from "../../interrupt-serialization.js";
@@ -14,13 +16,15 @@ import { hashSchemaInput, normalizeApprovalSchema } from "./tools/approval-schem
14
16
  import { INTERRUPT_BINDING_METADATA_KEY, InterruptResumeValidationError, readInterruptBinding, readUnopenedInterruptBinding, validateInterruptResumeBatch } from "../../interrupt-resume.js";
15
17
  import { INTERRUPT_PAYLOAD_METADATA_KEY, createInterruptBinding, rehydrateInterruptRequest } from "../../interrupt-definition.js";
16
18
  import { readGenericInterruptContinuation } from "../../generic-interrupt-continuation.js";
19
+ import { uiMessagesToWire } from "../../utilities/ag-ui-wire.js";
20
+ import { restorePublicUsage } from "../../utilities/restore-inbound-chunk.js";
17
21
  import { normalizeToolResult } from "../../utilities/tool-result.js";
18
22
  import { isProviderExecutedToolCall } from "../../utilities/provider-executed.js";
19
23
  import { LazyToolManager } from "./tools/lazy-tool-manager.js";
20
24
  import { assertUniqueToolNames } from "./tools/unique-tool-names.js";
21
25
  import { MiddlewareAbortError, ToolCallManager, executeToolCalls } from "./tools/tool-calls.js";
22
26
  import { maxIterations } from "./agent-loop-strategies.js";
23
- import { convertMessagesToModelMessages, generateMessageId, modelMessageToUIMessage, safeJsonStringify } from "./messages.js";
27
+ import { convertMessagesToModelMessages, generateMessageId, modelMessagesToUIMessages, safeJsonStringify } from "./messages.js";
24
28
  import { MiddlewareRunner } from "./middleware/compose.js";
25
29
  import { provideSandboxRuntime } from "./middleware/sandbox-runtime.js";
26
30
  import { provideRunDisconnect } from "./middleware/run-disconnect.js";
@@ -128,7 +132,6 @@ var TextEngine = class {
128
132
  accumulatedThinking = [];
129
133
  currentThinkingContent = "";
130
134
  currentThinkingSignature = "";
131
- hasSeenReasoningEvents = false;
132
135
  eventOptions;
133
136
  eventToolNames;
134
137
  finishedEvent = null;
@@ -201,11 +204,7 @@ var TextEngine = class {
201
204
  this.threadId = config.params.threadId || config.params.conversationId || this.createId("thread");
202
205
  this.runIdOverride = config.params.runId;
203
206
  this.parentRunIdOverride = config.params.parentRunId;
204
- const allMiddleware = [
205
- devtoolsMiddleware(),
206
- ...config.middleware || [],
207
- stripToSpecMiddleware()
208
- ];
207
+ const allMiddleware = [devtoolsMiddleware(), ...config.middleware || []];
209
208
  this.middlewareRunner = new MiddlewareRunner(allMiddleware, logger);
210
209
  this.middlewareAbortController = new AbortController();
211
210
  this.toolAbortSignal = combineAbortSignals(this.effectiveSignal, this.middlewareAbortController.signal);
@@ -321,7 +320,7 @@ var TextEngine = class {
321
320
  finishReason: this.lastFinishReason,
322
321
  duration: Date.now() - this.streamStartTime,
323
322
  content: this.accumulatedContent,
324
- usage: this.finishedEvent?.usage
323
+ usage: rebuildTokenUsage(this.finishedEvent?.usage, tanstackMetadata(this.finishedEvent ?? void 0)?.usage)
325
324
  });
326
325
  }
327
326
  return;
@@ -379,25 +378,24 @@ var TextEngine = class {
379
378
  finishReason: this.lastFinishReason,
380
379
  duration: Date.now() - this.streamStartTime,
381
380
  content: this.accumulatedContent,
382
- usage: this.finishedEvent?.usage
381
+ usage: rebuildTokenUsage(this.finishedEvent?.usage, tanstackMetadata(this.finishedEvent ?? void 0)?.usage)
383
382
  });
384
383
  }
385
384
  }
386
385
  } catch (error) {
387
386
  if (error instanceof Error && error.name === "InterruptReplaySignal" && "continuationRunId" in error && typeof error.continuationRunId === "string") {
388
387
  this.terminalHookCalled = true;
389
- yield {
388
+ yield* this.pipeThroughMiddleware({
390
389
  type: EventType.RUN_FINISHED,
391
390
  timestamp: Date.now(),
392
391
  threadId: this.threadId,
393
392
  runId: this.runIdOverride ?? this.requestId,
394
- finishReason: "stop",
395
393
  outcome: { type: "success" },
396
394
  result: {
397
395
  replayed: true,
398
396
  continuationRunId: error.continuationRunId
399
397
  }
400
- };
398
+ });
401
399
  return;
402
400
  }
403
401
  const interruptFailure = structuralInterruptFailure(error);
@@ -477,7 +475,6 @@ var TextEngine = class {
477
475
  this.accumulatedThinking = [];
478
476
  this.currentThinkingContent = "";
479
477
  this.currentThinkingSignature = "";
480
- this.hasSeenReasoningEvents = false;
481
478
  this.finishedEvent = null;
482
479
  this.streamedToolErrorResults.clear();
483
480
  this.middlewareCtx.currentMessageId = this.currentMessageId;
@@ -506,7 +503,7 @@ var TextEngine = class {
506
503
  const { approvals } = this.collectClientState();
507
504
  const adapterApprovals = /* @__PURE__ */ new Map();
508
505
  for (const [approvalId, resolution] of approvals) adapterApprovals.set(approvalId, typeof resolution === "boolean" ? resolution : resolution.approved);
509
- for await (const chunk of this.adapter.chatStream({
506
+ for await (const raw of this.adapter.chatStream({
510
507
  model: this.params.model,
511
508
  messages: this.messages,
512
509
  tools: toolsWithJsonSchemas,
@@ -524,18 +521,18 @@ var TextEngine = class {
524
521
  })) {
525
522
  if (this.isCancelled()) break;
526
523
  this.totalChunkCount++;
527
- this.handleStreamChunk(chunk);
528
- if (chunk.type === EventType.CUSTOM && chunk.name === "structured-output.start") {
524
+ this.handleStreamChunk(raw);
525
+ if (raw.type === EventType.CUSTOM && raw.name === "structured-output.start") {
529
526
  this.combinedStartEmitted = true;
530
- const startValue = chunk.value;
527
+ const startValue = raw.value;
531
528
  if (startValue && typeof startValue === "object" && "messageId" in startValue && typeof startValue.messageId === "string") {
532
529
  this.combinedStructuredMessageId = startValue.messageId;
533
530
  this.captureStructuredOutputMessageIdentity(startValue.messageId);
534
531
  }
535
532
  }
536
- let outboundChunk = chunk;
537
- if (this.finalStructuredOutput?.source === "event" && chunk.type === EventType.CUSTOM && chunk.name === "structured-output.complete") {
538
- const parsed = readStructuredOutputCompleteValue(chunk.value);
533
+ let outboundChunk = raw;
534
+ if (this.finalStructuredOutput?.source === "event" && raw.type === EventType.CUSTOM && raw.name === "structured-output.complete") {
535
+ const parsed = readStructuredOutputCompleteValue(raw.value);
539
536
  if (parsed) {
540
537
  const object = this.finalStructuredOutput.normalize ? this.finalStructuredOutput.normalize(parsed.object) : parsed.object;
541
538
  this.structuredOutputResult = {
@@ -543,14 +540,14 @@ var TextEngine = class {
543
540
  rawText: parsed.raw
544
541
  };
545
542
  this.combinedCompleteEmitted = true;
546
- const value = chunk.value;
543
+ const value = raw.value;
547
544
  const completeMessageId = readCustomEventMessageId(value);
548
545
  if (completeMessageId) {
549
546
  this.combinedStructuredMessageId = completeMessageId;
550
547
  this.captureStructuredOutputMessageIdentity(completeMessageId);
551
548
  }
552
549
  if (object !== parsed.object && value && typeof value === "object") outboundChunk = {
553
- ...chunk,
550
+ ...raw,
554
551
  value: {
555
552
  ...value,
556
553
  object
@@ -558,43 +555,38 @@ var TextEngine = class {
558
555
  };
559
556
  }
560
557
  }
561
- if (this.finalStructuredOutput?.nativeCombined === true && this.finalStructuredOutput.yieldChunks && this.finalStructuredOutput.source !== "event" && !this.combinedStartEmitted && chunk.type === EventType.TEXT_MESSAGE_START) {
558
+ if (this.finalStructuredOutput?.nativeCombined === true && this.finalStructuredOutput.yieldChunks && this.finalStructuredOutput.source !== "event" && !this.combinedStartEmitted && raw.type === EventType.TEXT_MESSAGE_START) {
562
559
  this.combinedStartEmitted = true;
563
- const messageId = typeof chunk.messageId === "string" && chunk.messageId !== "" ? chunk.messageId : generateMessageId();
560
+ const messageId = typeof raw.messageId === "string" && raw.messageId !== "" ? raw.messageId : generateMessageId();
564
561
  this.combinedStructuredMessageId = messageId;
565
562
  const synthStart = {
566
563
  type: EventType.CUSTOM,
567
564
  name: "structured-output.start",
568
565
  value: { messageId },
569
- model: this.params.model,
570
- timestamp: Date.now(),
571
- threadId: this.threadId,
572
- ...this.runIdOverride ? { runId: this.runIdOverride } : {}
566
+ timestamp: Date.now()
573
567
  };
574
568
  const synthOutputs = await this.middlewareRunner.runOnChunk(this.middlewareCtx, synthStart);
575
- for (const outputChunk of synthOutputs) {
576
- yield outputChunk;
577
- this.middlewareCtx.chunkIndex++;
578
- }
569
+ yield* this.emitPublicChunks(synthOutputs);
579
570
  }
580
571
  const outputChunks = await this.middlewareRunner.runOnChunk(this.middlewareCtx, outboundChunk);
581
572
  const suppressAgentLifecycle = !!this.finalStructuredOutput && this.finalStructuredOutput.yieldChunks && this.finalStructuredOutput.nativeCombined !== true;
582
- for (const outputChunk of outputChunks) {
583
- if (suppressAgentLifecycle && (outputChunk.type === EventType.RUN_STARTED || outputChunk.type === EventType.RUN_FINISHED)) continue;
584
- if (outputChunk.type === EventType.RUN_FINISHED) {
585
- this.deferredModelRunFinishedChunks.push(outputChunk);
573
+ for (const outputChunk of outputChunks) for (const spec of normalizeStreamChunk(outputChunk)) {
574
+ restorePublicUsage(spec);
575
+ if (suppressAgentLifecycle && (spec.type === EventType.RUN_STARTED || spec.type === EventType.RUN_FINISHED)) continue;
576
+ if (spec.type === EventType.RUN_FINISHED) {
577
+ this.deferredModelRunFinishedChunks.push(spec);
586
578
  continue;
587
579
  }
588
- if (this.shouldDeferToolCallRunFinished(outputChunk)) {
589
- this.deferredToolCallRunFinishedChunks.push(outputChunk);
580
+ if (this.shouldDeferToolCallRunFinished(spec)) {
581
+ this.deferredToolCallRunFinishedChunks.push(spec);
590
582
  continue;
591
583
  }
592
- if (outputChunk.type === EventType.RUN_STARTED) this.hasPublicRunStarted = true;
593
- this.logger.output(`type=${outputChunk.type}`, { chunk: outputChunk });
594
- yield outputChunk;
584
+ if (spec.type === EventType.RUN_STARTED) this.hasPublicRunStarted = true;
585
+ this.logger.output(`type=${spec.type}`, { chunk: spec });
586
+ yield spec;
595
587
  this.middlewareCtx.chunkIndex++;
596
588
  }
597
- if (chunk.type === "RUN_FINISHED" && chunk.usage) await this.middlewareRunner.runOnUsage(this.middlewareCtx, chunk.usage);
589
+ if (raw.type === EventType.RUN_FINISHED) await this.runOnUsageFromChunk(raw);
598
590
  yield* this.drainSandboxFileQueue();
599
591
  if (this.earlyTermination) break;
600
592
  }
@@ -617,6 +609,9 @@ var TextEngine = class {
617
609
  case "TOOL_CALL_END":
618
610
  this.handleToolCallEndEvent(chunk);
619
611
  break;
612
+ case "TOOL_CALL_RESULT":
613
+ this.handleToolCallResultEvent(chunk);
614
+ break;
620
615
  case "RUN_FINISHED":
621
616
  this.handleRunFinishedEvent(chunk);
622
617
  break;
@@ -629,11 +624,15 @@ var TextEngine = class {
629
624
  case "STEP_FINISHED":
630
625
  this.handleStepFinishedEvent(chunk);
631
626
  break;
632
- case "REASONING_MESSAGE_CONTENT": this.handleReasoningMessageContentEvent(chunk);
627
+ case "REASONING_MESSAGE_CONTENT":
628
+ this.handleReasoningMessageContentEvent(chunk);
629
+ break;
630
+ case "REASONING_ENCRYPTED_VALUE": this.handleReasoningEncryptedValueEvent(chunk);
633
631
  }
634
632
  }
635
633
  handleTextMessageContentEvent(chunk) {
636
- if (chunk.content) this.accumulatedContent = chunk.content;
634
+ const extra = chunk;
635
+ if (typeof extra.content === "string" && extra.content !== "") this.accumulatedContent = extra.content;
637
636
  else this.accumulatedContent += chunk.delta;
638
637
  this.middlewareCtx.accumulatedContent = this.accumulatedContent;
639
638
  }
@@ -652,34 +651,58 @@ var TextEngine = class {
652
651
  handleToolCallStartEvent(chunk) {
653
652
  if (typeof chunk.parentMessageId === "string" && chunk.parentMessageId !== "") this.captureStreamMessageIdentity(chunk.parentMessageId);
654
653
  this.toolCallManager.addToolCallStartEvent(chunk);
654
+ const metadata = chunk.metadata;
655
+ const thoughtSignature = metadata != null && typeof metadata === "object" && "thoughtSignature" in metadata && typeof metadata.thoughtSignature === "string" && metadata.thoughtSignature !== "" ? metadata.thoughtSignature : void 0;
656
+ if (thoughtSignature === void 0) return;
657
+ const call = this.toolCallManager.getToolCalls().find((candidate) => candidate.id === chunk.toolCallId);
658
+ if (!call) return;
659
+ call.metadata = {
660
+ ...call.metadata != null && typeof call.metadata === "object" ? call.metadata : {},
661
+ thoughtSignature
662
+ };
655
663
  }
656
664
  handleToolCallArgsEvent(chunk) {
657
665
  this.toolCallManager.addToolCallArgsEvent(chunk);
658
666
  }
659
667
  handleToolCallEndEvent(chunk) {
660
668
  this.toolCallManager.completeToolCall(chunk);
661
- if (chunk.state !== "output-error" || chunk.result === void 0) return;
669
+ const end = chunk;
670
+ if ((end.state ?? tanstackMetadata(end)?.state) !== "output-error" || end.result === void 0) return;
671
+ this.handleToolCallResultEvent({
672
+ type: EventType.TOOL_CALL_RESULT,
673
+ toolCallId: chunk.toolCallId,
674
+ content: Array.isArray(end.result) ? JSON.stringify(end.result) : end.result,
675
+ messageId: chunk.toolCallId,
676
+ metadata: { tanstack: { state: "output-error" } }
677
+ });
678
+ }
679
+ handleToolCallResultEvent(chunk) {
680
+ if (!(tanstackMetadata(chunk)?.state === "output-error")) return;
662
681
  const toolCall = this.toolCallManager.getToolCalls().find((candidate) => candidate.id === chunk.toolCallId);
663
682
  if (!toolCall) return;
664
683
  this.streamedToolErrorResults.set(chunk.toolCallId, {
665
684
  toolCallId: chunk.toolCallId,
666
685
  toolName: toolCall.function.name,
667
- result: chunk.result,
668
- ...chunk.input !== void 0 && { input: chunk.input },
686
+ result: chunk.content,
669
687
  state: "output-error"
670
688
  });
671
689
  }
672
690
  handleRunFinishedEvent(chunk) {
673
691
  this.finishedEvent = chunk;
674
- this.lastFinishReason = chunk.finishReason ?? null;
692
+ const top = chunk.finishReason;
693
+ this.lastFinishReason = top === "stop" || top === "length" || top === "content_filter" || top === "tool_calls" || top === null ? top : tanstackMetadata(chunk)?.finishReason ?? null;
694
+ }
695
+ async runOnUsageFromChunk(chunk) {
696
+ const rebuilt = rebuildTokenUsage(chunk.usage, tanstackMetadata(chunk)?.usage);
697
+ if (rebuilt) await this.middlewareRunner.runOnUsage(this.middlewareCtx, rebuilt);
675
698
  }
676
699
  handleRunErrorEvent(chunk) {
677
700
  this.earlyTermination = true;
678
701
  if (this.finalizationError === null) {
679
- const message = chunk.message || chunk.error?.message || "Run failed";
702
+ const message = chunk.message || "Run failed";
680
703
  this.finalizationError = {
681
704
  message,
682
- ...chunk.code !== void 0 ? { code: chunk.code } : chunk.error?.code !== void 0 ? { code: chunk.error.code } : {}
705
+ ...chunk.code !== void 0 ? { code: chunk.code } : {}
683
706
  };
684
707
  }
685
708
  }
@@ -697,19 +720,22 @@ var TextEngine = class {
697
720
  this.finalizeCurrentThinkingStep();
698
721
  }
699
722
  handleStepFinishedEvent(chunk) {
700
- if (!this.hasSeenReasoningEvents) {
701
- if (chunk.delta) this.currentThinkingContent += chunk.delta;
702
- else if (chunk.content) {
703
- if (chunk.content.startsWith(this.currentThinkingContent)) this.currentThinkingContent = chunk.content;
704
- else if (!this.currentThinkingContent.startsWith(chunk.content)) this.currentThinkingContent += chunk.content;
705
- }
706
- }
707
- if (chunk.signature) this.currentThinkingSignature = chunk.signature;
723
+ if (typeof chunk.signature === "string" && chunk.signature !== "") this.currentThinkingSignature = chunk.signature;
708
724
  }
709
725
  handleReasoningMessageContentEvent(chunk) {
710
- this.hasSeenReasoningEvents = true;
711
726
  this.currentThinkingContent += chunk.delta;
712
727
  }
728
+ handleReasoningEncryptedValueEvent(chunk) {
729
+ if (chunk.subtype === "tool-call") {
730
+ const call = this.messages.flatMap((message) => message.toolCalls ?? []).find((toolCall) => toolCall.id === chunk.entityId);
731
+ if (call) call.metadata = {
732
+ ...call.metadata != null && typeof call.metadata === "object" ? call.metadata : {},
733
+ thoughtSignature: chunk.encryptedValue
734
+ };
735
+ return;
736
+ }
737
+ this.currentThinkingSignature = chunk.encryptedValue;
738
+ }
713
739
  /**
714
740
  * Tools available for execution this turn. The discovery tool is dropped
715
741
  * from the advertised set (`this.tools`) once every lazy tool is discovered,
@@ -910,7 +936,7 @@ var TextEngine = class {
910
936
  this.setToolPhase("continue");
911
937
  }
912
938
  shouldDeferToolCallRunFinished(chunk) {
913
- return chunk.type === EventType.RUN_FINISHED && this.finishedEvent?.finishReason === "tool_calls" && this.tools.length > 0 && this.toolCallManager.hasToolCalls();
939
+ return chunk.type === EventType.RUN_FINISHED && this.lastFinishReason === "tool_calls" && this.tools.length > 0 && this.toolCallManager.hasToolCalls();
914
940
  }
915
941
  *flushDeferredToolCallRunFinishedChunks() {
916
942
  for (const chunk of this.deferredToolCallRunFinishedChunks) {
@@ -934,16 +960,12 @@ var TextEngine = class {
934
960
  type: EventType.RUN_STARTED,
935
961
  runId: finishEvent.runId,
936
962
  threadId: finishEvent.threadId,
937
- model: finishEvent.model,
938
963
  timestamp: Date.now()
939
964
  });
940
965
  }
941
966
  async *emitSuccessfulEarlyTermination() {
942
967
  this.lastFinishReason = "stop";
943
- const finishEvent = {
944
- ...this.createSyntheticFinishedEvent(),
945
- finishReason: "stop"
946
- };
968
+ const finishEvent = this.createSyntheticFinishedEvent("stop");
947
969
  yield* this.emitSyntheticRunStarted(finishEvent);
948
970
  yield* this.pipeThroughMiddleware({
949
971
  ...finishEvent,
@@ -955,7 +977,7 @@ var TextEngine = class {
955
977
  this.deferredToolCallRunFinishedChunks = [];
956
978
  }
957
979
  shouldExecuteToolPhase() {
958
- return this.finishedEvent?.finishReason === "tool_calls" && this.tools.length > 0 && this.toolCallManager.hasToolCalls();
980
+ return this.lastFinishReason === "tool_calls" && this.tools.length > 0 && this.toolCallManager.hasToolCalls();
959
981
  }
960
982
  addAssistantToolCallMessage(toolCalls) {
961
983
  this.finalizeCurrentThinkingStep();
@@ -1168,24 +1190,14 @@ var TextEngine = class {
1168
1190
  };
1169
1191
  }
1170
1192
  buildMessagesSnapshotChunk() {
1171
- const messages = this.messages.map((message, index) => {
1172
- const content = typeof message.content === "string" ? message.content : message.content === null ? void 0 : JSON.stringify(message.content);
1173
- const id = message.id || `snapshot_${this.runIdOverride ?? this.requestId}_${index}`;
1174
- const parts = message.role === "assistant" && (message.thinking?.length || message.structuredOutput) ? modelMessageToUIMessage(message, id).parts : void 0;
1175
- return {
1176
- id,
1177
- role: message.role,
1178
- ...content !== void 0 ? { content } : {},
1179
- ...parts ? { parts } : {},
1180
- ..."toolCalls" in message && message.toolCalls ? { toolCalls: message.toolCalls } : {},
1181
- ..."toolCallId" in message && message.toolCallId ? { toolCallId: message.toolCallId } : {}
1182
- };
1183
- });
1193
+ const withIds = this.messages.map((message, index) => ({
1194
+ ...message,
1195
+ id: message.id || `snapshot_${this.runIdOverride ?? this.requestId}_${index}`
1196
+ }));
1184
1197
  return {
1185
1198
  type: EventType.MESSAGES_SNAPSHOT,
1186
1199
  timestamp: Date.now(),
1187
- model: this.params.model,
1188
- messages
1200
+ messages: uiMessagesToWire(modelMessagesToUIMessages(withIds))
1189
1201
  };
1190
1202
  }
1191
1203
  publicInterruptTerminal(chunk) {
@@ -1232,19 +1244,16 @@ var TextEngine = class {
1232
1244
  }
1233
1245
  buildInterruptRunErrorChunk(error) {
1234
1246
  const failure = this.interruptFailure(error);
1235
- return {
1247
+ return withTanstackMetadata({
1236
1248
  type: EventType.RUN_ERROR,
1237
1249
  timestamp: Date.now(),
1250
+ message: failure.message,
1251
+ code: failure.code
1252
+ }, {
1238
1253
  runId: this.runIdOverride ?? this.requestId,
1239
1254
  threadId: this.threadId,
1240
- message: failure.message,
1241
- code: failure.code,
1242
- error: {
1243
- message: failure.message,
1244
- code: failure.code
1245
- },
1246
- ...failure.errors !== void 0 ? { "tanstack:interruptErrors": failure.errors } : {}
1247
- };
1255
+ ...failure.errors !== void 0 ? { interruptErrors: failure.errors } : {}
1256
+ });
1248
1257
  }
1249
1258
  async *emitInterruptRunError(error) {
1250
1259
  const failure = this.interruptFailure(error);
@@ -1261,7 +1270,7 @@ var TextEngine = class {
1261
1270
  const terminal = this.completeEphemeralInterruptBindings(this.buildInterruptFinishedChunk(finishEvent, approvals, clientRequests, genericRequests, genericInterruptIds));
1262
1271
  let terminalOutputs;
1263
1272
  try {
1264
- terminalOutputs = await this.middlewareRunner.runOnChunk(this.middlewareCtx, terminal);
1273
+ terminalOutputs = [...this.emitPublicChunks(await this.middlewareRunner.runOnChunk(this.middlewareCtx, terminal))];
1265
1274
  } catch (error) {
1266
1275
  yield* this.emitInterruptRunError(error);
1267
1276
  return false;
@@ -1270,13 +1279,9 @@ var TextEngine = class {
1270
1279
  if (this.params.state !== void 0) yield* this.pipeThroughMiddleware({
1271
1280
  type: EventType.STATE_SNAPSHOT,
1272
1281
  timestamp: Date.now(),
1273
- model: this.params.model,
1274
1282
  snapshot: this.params.state
1275
1283
  });
1276
- for (const output of terminalOutputs) {
1277
- yield this.publicInterruptTerminal(output);
1278
- this.middlewareCtx.chunkIndex++;
1279
- }
1284
+ for (const output of terminalOutputs) yield this.publicInterruptTerminal(output);
1280
1285
  return true;
1281
1286
  }
1282
1287
  async *emitBoundaryInterrupts(phase, finishEvent, toolCalls = [], requests) {
@@ -1357,52 +1362,42 @@ var TextEngine = class {
1357
1362
  }
1358
1363
  };
1359
1364
  }
1360
- buildToolResultChunks(results, finishEvent, argsMap) {
1365
+ buildToolResultChunks(results, _finishEvent, argsMap) {
1361
1366
  const chunks = [];
1362
1367
  for (const result of results) {
1363
1368
  const content = normalizeToolResult(result.result);
1364
1369
  const wireContent = typeof content === "string" ? content : JSON.stringify(content);
1365
1370
  if (argsMap) {
1366
1371
  chunks.push({
1367
- type: "TOOL_CALL_START",
1372
+ type: EventType.TOOL_CALL_START,
1368
1373
  timestamp: Date.now(),
1369
- model: finishEvent.model,
1370
1374
  toolCallId: result.toolCallId,
1371
1375
  toolCallName: result.toolName,
1372
1376
  toolName: result.toolName
1373
1377
  });
1374
1378
  const args = argsMap.get(result.toolCallId) ?? "{}";
1375
1379
  chunks.push({
1376
- type: "TOOL_CALL_ARGS",
1380
+ type: EventType.TOOL_CALL_ARGS,
1377
1381
  timestamp: Date.now(),
1378
- model: finishEvent.model,
1379
1382
  toolCallId: result.toolCallId,
1380
- delta: args,
1381
- args
1383
+ delta: args
1382
1384
  });
1383
1385
  chunks.push({
1384
- type: "TOOL_CALL_END",
1386
+ type: EventType.TOOL_CALL_END,
1385
1387
  timestamp: Date.now(),
1386
- model: finishEvent.model,
1387
- toolCallId: result.toolCallId,
1388
- toolCallName: result.toolName,
1389
- toolName: result.toolName,
1390
- result: wireContent,
1391
- ...result.input !== void 0 && { input: result.input },
1392
- ...result.output !== void 0 && { output: result.output },
1393
- ...result.state !== void 0 && { state: result.state }
1388
+ toolCallId: result.toolCallId
1394
1389
  });
1395
1390
  }
1396
- chunks.push({
1397
- type: "TOOL_CALL_RESULT",
1391
+ const parentMessageId = [...this.messages].reverse().find((message) => message.role === "assistant")?.id;
1392
+ const resultChunk = {
1393
+ type: EventType.TOOL_CALL_RESULT,
1398
1394
  timestamp: Date.now(),
1399
- model: finishEvent.model,
1400
- messageId: this.createId("tool-result"),
1395
+ messageId: parentMessageId || result.toolCallId,
1401
1396
  toolCallId: result.toolCallId,
1402
1397
  content: wireContent,
1403
- role: "tool",
1404
- ...result.state !== void 0 && { state: result.state }
1405
- });
1398
+ role: "tool"
1399
+ };
1400
+ chunks.push(result.state === "output-error" ? withTanstackMetadata(resultChunk, { state: result.state }) : resultChunk);
1406
1401
  const placeholderIdx = this.messages.findIndex((m) => {
1407
1402
  if (m.role !== "tool" || m.toolCallId !== result.toolCallId) return false;
1408
1403
  if (typeof m.content !== "string") return false;
@@ -1475,15 +1470,16 @@ var TextEngine = class {
1475
1470
  }
1476
1471
  return pending;
1477
1472
  }
1478
- createSyntheticFinishedEvent() {
1479
- return {
1480
- type: "RUN_FINISHED",
1473
+ createSyntheticFinishedEvent(finishReason = "tool_calls") {
1474
+ return withTanstackMetadata({
1475
+ type: EventType.RUN_FINISHED,
1481
1476
  runId: this.runIdOverride ?? this.requestId,
1482
1477
  threadId: this.threadId,
1483
- model: this.params.model,
1484
- timestamp: Date.now(),
1485
- finishReason: "tool_calls"
1486
- };
1478
+ timestamp: Date.now()
1479
+ }, {
1480
+ finishReason,
1481
+ model: this.params.model
1482
+ });
1487
1483
  }
1488
1484
  async shouldContinue() {
1489
1485
  if (this.cyclePhase === "executeToolCalls") return true;
@@ -1669,75 +1665,69 @@ var TextEngine = class {
1669
1665
  type: EventType.CUSTOM,
1670
1666
  name: "structured-output.start",
1671
1667
  value: { messageId: idForStart },
1672
- model: this.params.model,
1673
- timestamp,
1674
- threadId: this.threadId,
1675
- ...this.runIdOverride ? { runId: this.runIdOverride } : {}
1668
+ timestamp
1676
1669
  };
1677
1670
  };
1678
- const pipeThroughMiddleware = async (synthChunk) => this.middlewareRunner.runOnChunk(this.middlewareCtx, synthChunk);
1671
+ const runChunkMiddleware = (synthChunk) => this.middlewareRunner.runOnChunk(this.middlewareCtx, synthChunk);
1679
1672
  let runErrorYielded = false;
1680
- for await (const chunk of providerStream) {
1673
+ for await (const raw of providerStream) {
1681
1674
  if (this.isCancelled()) break;
1682
- if (!startEmitted && chunk.type === EventType.CUSTOM && chunk.name === "structured-output.start") startEmitted = true;
1683
- if (!structuredMessageId) {
1684
- const extracted = extractMessageId(chunk);
1685
- if (extracted) {
1686
- structuredMessageId = extracted;
1687
- this.captureStructuredOutputMessageIdentity(extracted);
1675
+ {
1676
+ const chunk = raw;
1677
+ if (!startEmitted && chunk.type === EventType.CUSTOM && chunk.name === "structured-output.start") startEmitted = true;
1678
+ if (!structuredMessageId) {
1679
+ const extracted = extractMessageId(chunk);
1680
+ if (extracted) {
1681
+ structuredMessageId = extracted;
1682
+ this.captureStructuredOutputMessageIdentity(extracted);
1683
+ }
1688
1684
  }
1689
- }
1690
- if (this.finalStructuredOutput.yieldChunks) {
1691
- if (!startEmitted && (chunk.type === EventType.TEXT_MESSAGE_START || chunk.type === EventType.TEXT_MESSAGE_CONTENT || chunk.type === EventType.TEXT_MESSAGE_END)) {
1692
- startEmitted = true;
1693
- const synthOutputs = await pipeThroughMiddleware(buildSynthesizedStart(chunk.timestamp));
1694
- for (const outputChunk of synthOutputs) {
1695
- yield outputChunk;
1696
- this.middlewareCtx.chunkIndex++;
1685
+ if (this.finalStructuredOutput.yieldChunks) {
1686
+ if (!startEmitted && (chunk.type === EventType.TEXT_MESSAGE_START || chunk.type === EventType.TEXT_MESSAGE_CONTENT || chunk.type === EventType.TEXT_MESSAGE_END)) {
1687
+ startEmitted = true;
1688
+ const synthStart = buildSynthesizedStart(chunk.timestamp);
1689
+ yield* this.emitPublicChunks(await runChunkMiddleware(synthStart));
1690
+ }
1691
+ if (!startEmitted && chunk.type === EventType.RUN_ERROR) {
1692
+ startEmitted = true;
1693
+ const synthStart = buildSynthesizedStart(chunk.timestamp);
1694
+ yield* this.emitPublicChunks(await runChunkMiddleware(synthStart));
1697
1695
  }
1698
1696
  }
1699
- if (!startEmitted && chunk.type === EventType.RUN_ERROR) {
1700
- startEmitted = true;
1701
- const synthOutputs = await pipeThroughMiddleware(buildSynthesizedStart(chunk.timestamp));
1702
- for (const outputChunk of synthOutputs) {
1703
- yield outputChunk;
1704
- this.middlewareCtx.chunkIndex++;
1697
+ let outboundChunk = chunk;
1698
+ if (chunk.type === EventType.CUSTOM && chunk.name === "structured-output.complete") {
1699
+ const parsed = readStructuredOutputCompleteValue(chunk.value);
1700
+ if (parsed) {
1701
+ const object = this.finalStructuredOutput.normalize ? this.finalStructuredOutput.normalize(parsed.object) : parsed.object;
1702
+ this.structuredOutputResult = {
1703
+ data: object,
1704
+ rawText: parsed.raw,
1705
+ ...parsed.reasoning !== void 0 ? { reasoning: parsed.reasoning } : {}
1706
+ };
1707
+ const value = chunk.value;
1708
+ if (object !== parsed.object && value && typeof value === "object") outboundChunk = {
1709
+ ...chunk,
1710
+ value: {
1711
+ ...value,
1712
+ object
1713
+ }
1714
+ };
1705
1715
  }
1706
1716
  }
1707
- }
1708
- let outboundChunk = chunk;
1709
- if (chunk.type === EventType.CUSTOM && chunk.name === "structured-output.complete") {
1710
- const parsed = readStructuredOutputCompleteValue(chunk.value);
1711
- if (parsed) {
1712
- const object = this.finalStructuredOutput.normalize ? this.finalStructuredOutput.normalize(parsed.object) : parsed.object;
1713
- this.structuredOutputResult = {
1714
- data: object,
1715
- rawText: parsed.raw,
1716
- ...parsed.reasoning !== void 0 ? { reasoning: parsed.reasoning } : {}
1717
- };
1718
- const value = chunk.value;
1719
- if (object !== parsed.object && value && typeof value === "object") outboundChunk = {
1720
- ...chunk,
1721
- value: {
1722
- ...value,
1723
- object
1724
- }
1725
- };
1717
+ if (chunk.type === EventType.RUN_FINISHED) await this.runOnUsageFromChunk(chunk);
1718
+ if (chunk.type === EventType.RUN_ERROR) this.finalizationError = {
1719
+ message: chunk.message,
1720
+ ...chunk.code ? { code: chunk.code } : {},
1721
+ ...fallbackAdapterError !== void 0 ? { cause: fallbackAdapterError } : {}
1722
+ };
1723
+ const outputChunks = await this.middlewareRunner.runOnChunk(this.middlewareCtx, outboundChunk);
1724
+ if (this.finalStructuredOutput.yieldChunks) for (const spec of this.emitPublicChunks(outputChunks)) {
1725
+ if (spec.type === EventType.RUN_ERROR) runErrorYielded = true;
1726
+ yield spec;
1726
1727
  }
1728
+ if (this.finalizationError) break;
1727
1729
  }
1728
- if (chunk.type === EventType.RUN_FINISHED && chunk.usage) await this.middlewareRunner.runOnUsage(this.middlewareCtx, chunk.usage);
1729
- if (chunk.type === EventType.RUN_ERROR) this.finalizationError = {
1730
- message: chunk.message,
1731
- ...chunk.code ? { code: chunk.code } : {},
1732
- ...fallbackAdapterError !== void 0 ? { cause: fallbackAdapterError } : {}
1733
- };
1734
- const outputChunks = await this.middlewareRunner.runOnChunk(this.middlewareCtx, outboundChunk);
1735
- if (this.finalStructuredOutput.yieldChunks) for (const outputChunk of outputChunks) {
1736
- if (outputChunk.type === EventType.RUN_ERROR) runErrorYielded = true;
1737
- yield outputChunk;
1738
- this.middlewareCtx.chunkIndex++;
1739
- }
1740
- if (this.finalizationError) break;
1730
+ if (this.isCancelled() || this.finalizationError) break;
1741
1731
  }
1742
1732
  if (this.isCancelled()) return;
1743
1733
  if (!this.structuredOutputResult && !this.finalizationError) this.finalizationError = {
@@ -1758,31 +1748,17 @@ var TextEngine = class {
1758
1748
  }
1759
1749
  if (this.finalizationError && this.finalStructuredOutput.yieldChunks && !runErrorYielded) {
1760
1750
  if (!startEmitted) {
1761
- const startOutputs = await pipeThroughMiddleware(buildSynthesizedStart());
1762
- for (const outputChunk of startOutputs) {
1763
- yield outputChunk;
1764
- this.middlewareCtx.chunkIndex++;
1765
- }
1751
+ const synthStart = buildSynthesizedStart();
1752
+ yield* this.emitPublicChunks(await runChunkMiddleware(synthStart));
1766
1753
  startEmitted = true;
1767
1754
  }
1768
1755
  const errChunk = {
1769
1756
  type: EventType.RUN_ERROR,
1770
- runId: this.runIdOverride ?? this.requestId,
1771
- model: this.params.model,
1772
1757
  timestamp: Date.now(),
1773
- threadId: this.threadId,
1774
1758
  message: this.finalizationError.message,
1775
- ...this.finalizationError.code ? { code: this.finalizationError.code } : {},
1776
- error: {
1777
- message: this.finalizationError.message,
1778
- ...this.finalizationError.code ? { code: this.finalizationError.code } : {}
1779
- }
1759
+ ...this.finalizationError.code ? { code: this.finalizationError.code } : {}
1780
1760
  };
1781
- const outputChunks = await this.middlewareRunner.runOnChunk(this.middlewareCtx, errChunk);
1782
- for (const outputChunk of outputChunks) {
1783
- yield outputChunk;
1784
- this.middlewareCtx.chunkIndex++;
1785
- }
1761
+ yield* this.emitPublicChunks(await this.middlewareRunner.runOnChunk(this.middlewareCtx, errChunk));
1786
1762
  }
1787
1763
  }
1788
1764
  /**
@@ -1853,16 +1829,9 @@ var TextEngine = class {
1853
1829
  type: EventType.CUSTOM,
1854
1830
  name: "structured-output.start",
1855
1831
  value: { messageId },
1856
- model: this.params.model,
1857
- timestamp: Date.now(),
1858
- threadId: this.threadId,
1859
- ...this.runIdOverride ? { runId: this.runIdOverride } : {}
1832
+ timestamp: Date.now()
1860
1833
  };
1861
- const startOutputs = await this.middlewareRunner.runOnChunk(this.middlewareCtx, synthStart);
1862
- for (const outputChunk of startOutputs) {
1863
- yield outputChunk;
1864
- this.middlewareCtx.chunkIndex++;
1865
- }
1834
+ yield* this.emitPublicChunks(await this.middlewareRunner.runOnChunk(this.middlewareCtx, synthStart));
1866
1835
  }
1867
1836
  if (this.structuredOutputResult && !this.finalizationError && !this.combinedCompleteEmitted) {
1868
1837
  const completeChunk = {
@@ -1873,36 +1842,18 @@ var TextEngine = class {
1873
1842
  raw: this.structuredOutputResult.rawText,
1874
1843
  ...this.combinedStructuredMessageId ? { messageId: this.combinedStructuredMessageId } : {}
1875
1844
  },
1876
- model: this.params.model,
1877
- timestamp: Date.now(),
1878
- threadId: this.threadId,
1879
- ...this.runIdOverride ? { runId: this.runIdOverride } : {}
1845
+ timestamp: Date.now()
1880
1846
  };
1881
- const completeOutputs = await this.middlewareRunner.runOnChunk(this.middlewareCtx, completeChunk);
1882
- for (const outputChunk of completeOutputs) {
1883
- yield outputChunk;
1884
- this.middlewareCtx.chunkIndex++;
1885
- }
1847
+ yield* this.emitPublicChunks(await this.middlewareRunner.runOnChunk(this.middlewareCtx, completeChunk));
1886
1848
  }
1887
1849
  if (this.finalizationError) {
1888
1850
  const errChunk = {
1889
1851
  type: EventType.RUN_ERROR,
1890
- runId: this.runIdOverride ?? this.requestId,
1891
- model: this.params.model,
1892
1852
  timestamp: Date.now(),
1893
- threadId: this.threadId,
1894
1853
  message: this.finalizationError.message,
1895
- ...this.finalizationError.code ? { code: this.finalizationError.code } : {},
1896
- error: {
1897
- message: this.finalizationError.message,
1898
- ...this.finalizationError.code ? { code: this.finalizationError.code } : {}
1899
- }
1854
+ ...this.finalizationError.code ? { code: this.finalizationError.code } : {}
1900
1855
  };
1901
- const errOutputs = await this.middlewareRunner.runOnChunk(this.middlewareCtx, errChunk);
1902
- for (const outputChunk of errOutputs) {
1903
- yield outputChunk;
1904
- this.middlewareCtx.chunkIndex++;
1905
- }
1856
+ yield* this.emitPublicChunks(await this.middlewareRunner.runOnChunk(this.middlewareCtx, errChunk));
1906
1857
  }
1907
1858
  }
1908
1859
  buildMiddlewareConfig() {
@@ -2139,18 +2090,26 @@ var TextEngine = class {
2139
2090
  this.toolPhase = phase;
2140
2091
  }
2141
2092
  /**
2142
- * Pipe a single chunk through the middleware pipeline (strip-to-spec, devtools, etc.)
2143
- * and yield all resulting output chunks.
2093
+ * Spec-normalize middleware output, then yield to the public iterable.
2094
+ * Engine state and `onChunk` already saw the raw chunk.
2144
2095
  */
2145
- async *pipeThroughMiddleware(chunk) {
2146
- const outputChunks = await this.middlewareRunner.runOnChunk(this.middlewareCtx, chunk);
2147
- for (const outputChunk of outputChunks) {
2148
- if (outputChunk.type === EventType.RUN_STARTED) this.hasPublicRunStarted = true;
2149
- yield outputChunk;
2096
+ *emitPublicChunks(outputs) {
2097
+ for (const output of outputs) for (const spec of normalizeStreamChunk(output)) {
2098
+ restorePublicUsage(spec);
2099
+ if (spec.type === EventType.RUN_STARTED) this.hasPublicRunStarted = true;
2100
+ yield spec;
2150
2101
  this.middlewareCtx.chunkIndex++;
2151
2102
  }
2152
2103
  }
2153
2104
  /**
2105
+ * Pipe a single internal chunk through middleware, then spec-normalize
2106
+ * before the public `for await` stream.
2107
+ */
2108
+ async *pipeThroughMiddleware(chunk) {
2109
+ const afterMw = await this.middlewareRunner.runOnChunk(this.middlewareCtx, chunk);
2110
+ yield* this.emitPublicChunks(afterMw);
2111
+ }
2112
+ /**
2154
2113
  * Drain queued `sandbox.file` chunks (emitted via the SandboxRuntime sink)
2155
2114
  * through the middleware pipeline and into the public stream.
2156
2115
  */
@@ -2174,9 +2133,8 @@ var TextEngine = class {
2174
2133
  }
2175
2134
  createCustomEventChunk(eventName, value) {
2176
2135
  return {
2177
- type: "CUSTOM",
2136
+ type: EventType.CUSTOM,
2178
2137
  timestamp: Date.now(),
2179
- model: this.params.model,
2180
2138
  name: eventName,
2181
2139
  value
2182
2140
  };