@copilotkit/aimock 1.43.0 → 1.45.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.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +46 -0
- package/README.md +14 -2
- package/dist/agui-handler.d.ts.map +1 -1
- package/dist/aimock-cli.cjs +31 -5
- package/dist/aimock-cli.cjs.map +1 -1
- package/dist/aimock-cli.d.cts.map +1 -1
- package/dist/aimock-cli.d.ts.map +1 -1
- package/dist/aimock-cli.js +31 -5
- package/dist/aimock-cli.js.map +1 -1
- package/dist/bedrock-converse.cjs +344 -43
- package/dist/bedrock-converse.cjs.map +1 -1
- package/dist/bedrock-converse.d.cts.map +1 -1
- package/dist/bedrock-converse.d.ts.map +1 -1
- package/dist/bedrock-converse.js +345 -44
- package/dist/bedrock-converse.js.map +1 -1
- package/dist/bedrock.cjs +195 -42
- package/dist/bedrock.cjs.map +1 -1
- package/dist/bedrock.d.cts.map +1 -1
- package/dist/bedrock.d.ts.map +1 -1
- package/dist/bedrock.js +196 -43
- package/dist/bedrock.js.map +1 -1
- package/dist/chaos.cjs +9 -5
- package/dist/chaos.cjs.map +1 -1
- package/dist/chaos.d.cts.map +1 -1
- package/dist/chaos.d.ts.map +1 -1
- package/dist/chaos.js +10 -7
- package/dist/chaos.js.map +1 -1
- package/dist/cli.cjs +238 -9
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +242 -13
- package/dist/cli.js.map +1 -1
- package/dist/cohere.cjs +159 -72
- package/dist/cohere.cjs.map +1 -1
- package/dist/cohere.d.cts.map +1 -1
- package/dist/cohere.d.ts.map +1 -1
- package/dist/cohere.js +160 -73
- package/dist/cohere.js.map +1 -1
- package/dist/config-loader.cjs +63 -5
- package/dist/config-loader.cjs.map +1 -1
- package/dist/config-loader.d.cts +37 -4
- package/dist/config-loader.d.cts.map +1 -1
- package/dist/config-loader.d.ts +37 -4
- package/dist/config-loader.d.ts.map +1 -1
- package/dist/config-loader.js +63 -5
- package/dist/config-loader.js.map +1 -1
- package/dist/constants.cjs +8 -0
- package/dist/constants.cjs.map +1 -1
- package/dist/constants.d.cts +6 -2
- package/dist/constants.d.ts +6 -2
- package/dist/constants.js +8 -1
- package/dist/constants.js.map +1 -1
- package/dist/echo-text.cjs +65 -0
- package/dist/echo-text.cjs.map +1 -0
- package/dist/echo-text.d.cts +22 -0
- package/dist/echo-text.d.cts.map +1 -0
- package/dist/echo-text.d.ts +22 -0
- package/dist/echo-text.d.ts.map +1 -0
- package/dist/echo-text.js +65 -0
- package/dist/echo-text.js.map +1 -0
- package/dist/embeddings.cjs +18 -1
- package/dist/embeddings.cjs.map +1 -1
- package/dist/embeddings.d.cts +1 -1
- package/dist/embeddings.d.cts.map +1 -1
- package/dist/embeddings.d.ts +1 -1
- package/dist/embeddings.d.ts.map +1 -1
- package/dist/embeddings.js +18 -1
- package/dist/embeddings.js.map +1 -1
- package/dist/fakes-plugin.cjs +131 -0
- package/dist/fakes-plugin.cjs.map +1 -0
- package/dist/fakes-plugin.d.cts +23 -0
- package/dist/fakes-plugin.d.cts.map +1 -0
- package/dist/fakes-plugin.d.ts +23 -0
- package/dist/fakes-plugin.d.ts.map +1 -0
- package/dist/fakes-plugin.js +127 -0
- package/dist/fakes-plugin.js.map +1 -0
- package/dist/files.cjs +9 -11
- package/dist/files.cjs.map +1 -1
- package/dist/files.d.cts.map +1 -1
- package/dist/files.d.ts.map +1 -1
- package/dist/files.js +10 -13
- package/dist/files.js.map +1 -1
- package/dist/fine-tuning.cjs +1 -19
- package/dist/fine-tuning.cjs.map +1 -1
- package/dist/fine-tuning.d.cts.map +1 -1
- package/dist/fine-tuning.d.ts.map +1 -1
- package/dist/fine-tuning.js +2 -20
- package/dist/fine-tuning.js.map +1 -1
- package/dist/fixture-loader-services.cjs +116 -0
- package/dist/fixture-loader-services.cjs.map +1 -0
- package/dist/fixture-loader-services.d.cts +48 -0
- package/dist/fixture-loader-services.d.cts.map +1 -0
- package/dist/fixture-loader-services.d.ts +48 -0
- package/dist/fixture-loader-services.d.ts.map +1 -0
- package/dist/fixture-loader-services.js +114 -0
- package/dist/fixture-loader-services.js.map +1 -0
- package/dist/fixture-loader.cjs +552 -29
- package/dist/fixture-loader.cjs.map +1 -1
- package/dist/fixture-loader.d.cts +140 -2
- package/dist/fixture-loader.d.cts.map +1 -1
- package/dist/fixture-loader.d.ts +140 -2
- package/dist/fixture-loader.d.ts.map +1 -1
- package/dist/fixture-loader.js +542 -31
- package/dist/fixture-loader.js.map +1 -1
- package/dist/gemini-embeddings.cjs +42 -2
- package/dist/gemini-embeddings.cjs.map +1 -1
- package/dist/gemini-embeddings.js +43 -3
- package/dist/gemini-embeddings.js.map +1 -1
- package/dist/gemini-interactions.cjs +288 -52
- package/dist/gemini-interactions.cjs.map +1 -1
- package/dist/gemini-interactions.d.cts.map +1 -1
- package/dist/gemini-interactions.d.ts.map +1 -1
- package/dist/gemini-interactions.js +289 -53
- package/dist/gemini-interactions.js.map +1 -1
- package/dist/gemini.cjs +234 -38
- package/dist/gemini.cjs.map +1 -1
- package/dist/gemini.d.cts.map +1 -1
- package/dist/gemini.d.ts.map +1 -1
- package/dist/gemini.js +235 -39
- package/dist/gemini.js.map +1 -1
- package/dist/helpers.cjs +1157 -12
- package/dist/helpers.cjs.map +1 -1
- package/dist/helpers.d.cts +85 -4
- package/dist/helpers.d.cts.map +1 -1
- package/dist/helpers.d.ts +85 -4
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +1113 -14
- package/dist/helpers.js.map +1 -1
- package/dist/images.cjs +3 -2
- package/dist/images.cjs.map +1 -1
- package/dist/images.js +3 -2
- package/dist/images.js.map +1 -1
- package/dist/index.cjs +39 -1
- package/dist/index.d.cts +11 -4
- package/dist/index.d.ts +11 -4
- package/dist/index.js +11 -4
- package/dist/jest.cjs +43 -14
- package/dist/jest.cjs.map +1 -1
- package/dist/jest.d.cts +47 -5
- package/dist/jest.d.cts.map +1 -1
- package/dist/jest.d.ts +47 -5
- package/dist/jest.d.ts.map +1 -1
- package/dist/jest.js +45 -16
- package/dist/jest.js.map +1 -1
- package/dist/journal.cjs +155 -13
- package/dist/journal.cjs.map +1 -1
- package/dist/journal.d.cts +54 -4
- package/dist/journal.d.cts.map +1 -1
- package/dist/journal.d.ts +54 -4
- package/dist/journal.d.ts.map +1 -1
- package/dist/journal.js +155 -13
- package/dist/journal.js.map +1 -1
- package/dist/live-sanitize.cjs +4 -32
- package/dist/live-sanitize.cjs.map +1 -1
- package/dist/live-sanitize.js +4 -32
- package/dist/live-sanitize.js.map +1 -1
- package/dist/llmock.cjs +204 -39
- package/dist/llmock.cjs.map +1 -1
- package/dist/llmock.d.cts +51 -1
- package/dist/llmock.d.cts.map +1 -1
- package/dist/llmock.d.ts +51 -1
- package/dist/llmock.d.ts.map +1 -1
- package/dist/llmock.js +206 -41
- package/dist/llmock.js.map +1 -1
- package/dist/mcp-fakes-mount.cjs +217 -0
- package/dist/mcp-fakes-mount.cjs.map +1 -0
- package/dist/mcp-fakes-mount.js +211 -0
- package/dist/mcp-fakes-mount.js.map +1 -0
- package/dist/mcp-fakes-report.cjs +111 -0
- package/dist/mcp-fakes-report.cjs.map +1 -0
- package/dist/mcp-fakes-report.d.cts +40 -0
- package/dist/mcp-fakes-report.d.cts.map +1 -0
- package/dist/mcp-fakes-report.d.ts +40 -0
- package/dist/mcp-fakes-report.d.ts.map +1 -0
- package/dist/mcp-fakes-report.js +107 -0
- package/dist/mcp-fakes-report.js.map +1 -0
- package/dist/mcp-fakes.cjs +1942 -0
- package/dist/mcp-fakes.cjs.map +1 -0
- package/dist/mcp-fakes.d.cts +504 -0
- package/dist/mcp-fakes.d.cts.map +1 -0
- package/dist/mcp-fakes.d.ts +504 -0
- package/dist/mcp-fakes.d.ts.map +1 -0
- package/dist/mcp-fakes.js +1937 -0
- package/dist/mcp-fakes.js.map +1 -0
- package/dist/mcp-handler.cjs +534 -27
- package/dist/mcp-handler.cjs.map +1 -1
- package/dist/mcp-handler.d.cts +49 -0
- package/dist/mcp-handler.d.cts.map +1 -0
- package/dist/mcp-handler.d.ts +49 -0
- package/dist/mcp-handler.d.ts.map +1 -0
- package/dist/mcp-handler.js +530 -28
- package/dist/mcp-handler.js.map +1 -1
- package/dist/mcp-mock.cjs +326 -47
- package/dist/mcp-mock.cjs.map +1 -1
- package/dist/mcp-mock.d.cts +97 -1
- package/dist/mcp-mock.d.cts.map +1 -1
- package/dist/mcp-mock.d.ts +97 -1
- package/dist/mcp-mock.d.ts.map +1 -1
- package/dist/mcp-mock.js +327 -48
- package/dist/mcp-mock.js.map +1 -1
- package/dist/mcp-recorder.cjs +1224 -0
- package/dist/mcp-recorder.cjs.map +1 -0
- package/dist/mcp-recorder.d.cts +108 -0
- package/dist/mcp-recorder.d.cts.map +1 -0
- package/dist/mcp-recorder.d.ts +108 -0
- package/dist/mcp-recorder.d.ts.map +1 -0
- package/dist/mcp-recorder.js +1215 -0
- package/dist/mcp-recorder.js.map +1 -0
- package/dist/mcp-stub.cjs +5 -1
- package/dist/mcp-stub.d.cts +3 -1
- package/dist/mcp-stub.d.ts +3 -1
- package/dist/mcp-stub.js +3 -1
- package/dist/mcp-types.d.cts +6 -0
- package/dist/mcp-types.d.ts +6 -0
- package/dist/message-text.cjs +192 -0
- package/dist/message-text.cjs.map +1 -0
- package/dist/message-text.d.cts +31 -0
- package/dist/message-text.d.cts.map +1 -0
- package/dist/message-text.d.ts +31 -0
- package/dist/message-text.d.ts.map +1 -0
- package/dist/message-text.js +184 -0
- package/dist/message-text.js.map +1 -0
- package/dist/messages.cjs +400 -56
- package/dist/messages.cjs.map +1 -1
- package/dist/messages.d.cts.map +1 -1
- package/dist/messages.d.ts.map +1 -1
- package/dist/messages.js +401 -58
- package/dist/messages.js.map +1 -1
- package/dist/metrics.cjs +46 -66
- package/dist/metrics.cjs.map +1 -1
- package/dist/metrics.d.cts +14 -6
- package/dist/metrics.d.cts.map +1 -1
- package/dist/metrics.d.ts +14 -6
- package/dist/metrics.d.ts.map +1 -1
- package/dist/metrics.js +32 -40
- package/dist/metrics.js.map +1 -1
- package/dist/misbehavior.cjs +1523 -0
- package/dist/misbehavior.cjs.map +1 -0
- package/dist/misbehavior.d.cts +43 -0
- package/dist/misbehavior.d.cts.map +1 -0
- package/dist/misbehavior.d.ts +43 -0
- package/dist/misbehavior.d.ts.map +1 -0
- package/dist/misbehavior.js +1511 -0
- package/dist/misbehavior.js.map +1 -0
- package/dist/ollama.cjs +315 -113
- package/dist/ollama.cjs.map +1 -1
- package/dist/ollama.d.cts.map +1 -1
- package/dist/ollama.d.ts.map +1 -1
- package/dist/ollama.js +316 -114
- package/dist/ollama.js.map +1 -1
- package/dist/openapi.cjs +3405 -0
- package/dist/openapi.cjs.map +1 -0
- package/dist/openapi.d.cts +30 -0
- package/dist/openapi.d.cts.map +1 -0
- package/dist/openapi.d.ts +30 -0
- package/dist/openapi.d.ts.map +1 -0
- package/dist/openapi.js +3404 -0
- package/dist/openapi.js.map +1 -0
- package/dist/openrouter-video.cjs +4 -4
- package/dist/openrouter-video.cjs.map +1 -1
- package/dist/openrouter-video.d.cts.map +1 -1
- package/dist/openrouter-video.d.ts.map +1 -1
- package/dist/openrouter-video.js +4 -4
- package/dist/openrouter-video.js.map +1 -1
- package/dist/record-sanitize.cjs +231 -0
- package/dist/record-sanitize.cjs.map +1 -0
- package/dist/record-sanitize.js +224 -0
- package/dist/record-sanitize.js.map +1 -0
- package/dist/recorder.cjs +115 -6
- package/dist/recorder.cjs.map +1 -1
- package/dist/recorder.d.cts +2 -1
- package/dist/recorder.d.cts.map +1 -1
- package/dist/recorder.d.ts +2 -1
- package/dist/recorder.d.ts.map +1 -1
- package/dist/recorder.js +116 -8
- package/dist/recorder.js.map +1 -1
- package/dist/responses.cjs +701 -166
- package/dist/responses.cjs.map +1 -1
- package/dist/responses.d.cts +5 -13
- package/dist/responses.d.cts.map +1 -1
- package/dist/responses.d.ts +5 -13
- package/dist/responses.d.ts.map +1 -1
- package/dist/responses.js +699 -169
- package/dist/responses.js.map +1 -1
- package/dist/route-registry.cjs +951 -0
- package/dist/route-registry.cjs.map +1 -0
- package/dist/route-registry.d.cts +33 -0
- package/dist/route-registry.d.cts.map +1 -0
- package/dist/route-registry.d.ts +33 -0
- package/dist/route-registry.d.ts.map +1 -0
- package/dist/route-registry.js +866 -0
- package/dist/route-registry.js.map +1 -0
- package/dist/router.cjs +24 -2
- package/dist/router.cjs.map +1 -1
- package/dist/router.d.cts.map +1 -1
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +25 -4
- package/dist/router.js.map +1 -1
- package/dist/server.cjs +1159 -264
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +4 -1
- package/dist/server.d.cts.map +1 -1
- package/dist/server.d.ts +4 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +1067 -172
- package/dist/server.js.map +1 -1
- package/dist/speech.cjs +4 -2
- package/dist/speech.cjs.map +1 -1
- package/dist/speech.js +4 -2
- package/dist/speech.js.map +1 -1
- package/dist/stream-collapse.cjs +236 -34
- package/dist/stream-collapse.cjs.map +1 -1
- package/dist/stream-collapse.d.cts +39 -4
- package/dist/stream-collapse.d.cts.map +1 -1
- package/dist/stream-collapse.d.ts +39 -4
- package/dist/stream-collapse.d.ts.map +1 -1
- package/dist/stream-collapse.js +235 -35
- package/dist/stream-collapse.js.map +1 -1
- package/dist/suite.cjs +1 -1
- package/dist/suite.js +1 -1
- package/dist/transcription.cjs +2 -2
- package/dist/transcription.cjs.map +1 -1
- package/dist/transcription.d.cts.map +1 -1
- package/dist/transcription.d.ts.map +1 -1
- package/dist/transcription.js +2 -2
- package/dist/transcription.js.map +1 -1
- package/dist/types.cjs +18 -0
- package/dist/types.cjs.map +1 -0
- package/dist/types.d.cts +516 -5
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.ts +516 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +17 -0
- package/dist/types.js.map +1 -0
- package/dist/validate-cli.cjs +123 -33
- package/dist/validate-cli.cjs.map +1 -1
- package/dist/validate-cli.js +125 -35
- package/dist/validate-cli.js.map +1 -1
- package/dist/vector-stores.cjs +1180 -0
- package/dist/vector-stores.cjs.map +1 -0
- package/dist/vector-stores.d.cts +106 -0
- package/dist/vector-stores.d.cts.map +1 -0
- package/dist/vector-stores.d.ts +106 -0
- package/dist/vector-stores.d.ts.map +1 -0
- package/dist/vector-stores.js +1164 -0
- package/dist/vector-stores.js.map +1 -0
- package/dist/vector-types.d.cts.map +1 -1
- package/dist/version.cjs +45 -0
- package/dist/version.cjs.map +1 -0
- package/dist/version.js +44 -0
- package/dist/version.js.map +1 -0
- package/dist/video.cjs +19 -0
- package/dist/video.cjs.map +1 -1
- package/dist/video.d.cts.map +1 -1
- package/dist/video.d.ts.map +1 -1
- package/dist/video.js +19 -0
- package/dist/video.js.map +1 -1
- package/dist/vitest.cjs +77 -16
- package/dist/vitest.cjs.map +1 -1
- package/dist/vitest.d.cts +38 -5
- package/dist/vitest.d.cts.map +1 -1
- package/dist/vitest.d.ts +38 -5
- package/dist/vitest.d.ts.map +1 -1
- package/dist/vitest.js +78 -17
- package/dist/vitest.js.map +1 -1
- package/dist/watcher.cjs +6 -2
- package/dist/watcher.cjs.map +1 -1
- package/dist/watcher.js +6 -2
- package/dist/watcher.js.map +1 -1
- package/dist/ws-gemini-live.cjs +210 -101
- package/dist/ws-gemini-live.cjs.map +1 -1
- package/dist/ws-gemini-live.d.cts +9 -3
- package/dist/ws-gemini-live.d.cts.map +1 -1
- package/dist/ws-gemini-live.d.ts +9 -3
- package/dist/ws-gemini-live.d.ts.map +1 -1
- package/dist/ws-gemini-live.js +211 -102
- package/dist/ws-gemini-live.js.map +1 -1
- package/dist/ws-realtime.cjs +175 -62
- package/dist/ws-realtime.cjs.map +1 -1
- package/dist/ws-realtime.d.cts +8 -3
- package/dist/ws-realtime.d.cts.map +1 -1
- package/dist/ws-realtime.d.ts +8 -3
- package/dist/ws-realtime.d.ts.map +1 -1
- package/dist/ws-realtime.js +176 -63
- package/dist/ws-realtime.js.map +1 -1
- package/dist/ws-responses.cjs +121 -16
- package/dist/ws-responses.cjs.map +1 -1
- package/dist/ws-responses.d.cts +8 -12
- package/dist/ws-responses.d.cts.map +1 -1
- package/dist/ws-responses.d.ts +8 -12
- package/dist/ws-responses.d.ts.map +1 -1
- package/dist/ws-responses.js +123 -18
- package/dist/ws-responses.js.map +1 -1
- package/package.json +13 -2
- package/skills/write-fixtures/SKILL.md +179 -21
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream-collapse.cjs","names":["isHarmonyContent","parseHarmonyContent"],"sources":["../src/stream-collapse.ts"],"sourcesContent":["/**\n * Stream collapsing functions for record-and-replay.\n *\n * Each function takes a raw streaming response body (SSE, NDJSON, or binary\n * EventStream) and collapses it into a non-streaming fixture response\n * containing `{ content }`, `{ toolCalls }`, or both when the stream includes\n * text followed by tool calls.\n */\n\nimport { crc32 } from \"node:zlib\";\nimport type { FixtureBlock, RecordProviderKey, ToolCall } from \"./types.js\";\nimport type { Logger } from \"./logger.js\";\nimport { isHarmonyContent, parseHarmonyContent } from \"./harmony.js\";\n\n// ---------------------------------------------------------------------------\n// Accumulated-string cap (RangeError: Invalid string length guard)\n// ---------------------------------------------------------------------------\n\n/**\n * Hard ceiling (UTF-16 code units) for any SINGLE string a collapser\n * accumulates across deltas (`content`, `reasoning`, a tool call's\n * `arguments`, `audioB64`, `argsStr`, and the coalesced text of `orderAtoms`).\n *\n * V8's maximum string length on 64-bit is 2^29 - 1 (~536.8M UTF-16 code\n * units); appending past it throws `RangeError: Invalid string length`. The\n * proxy path bounds the raw BYTE buffer under `PROXY_BUFFER_HARD_CEILING`\n * (256 MiB) before collapse, but the collapser is ALSO reachable directly\n * (exported from index.ts) and — even on the proxy path — a single accumulator\n * can approach the byte budget in code units, so it needs its own guard rather\n * than relying on the byte cap alone. 256Mi code units is comfortably below\n * V8's limit while leaving huge headroom for any real completion (whose\n * accumulated content can never exceed the total streamed body).\n *\n * When an append would cross the ceiling the accumulator keeps the ceiling's\n * worth of characters, drops the overflow, and marks itself truncated — never\n * throwing — mirroring the proxy buffer's \"bound then mark truncated, never\n * fail the client\" discipline.\n */\nexport const MAX_COLLAPSE_STRING_LENGTH = 256 * 1024 * 1024; // 256 Mi UTF-16 code units\n\n/**\n * Test-only override of {@link MAX_COLLAPSE_STRING_LENGTH}. Lets the cap suite\n * exercise the truncation path with a tiny budget instead of building a\n * multi-hundred-MB string. `undefined` (the default) uses the real ceiling.\n * NEVER set from production code.\n */\nlet collapseStringLimitOverride: number | undefined;\n\n/** @internal test-only — see {@link collapseStringLimitOverride}. */\nexport function setCollapseStringLimitForTests(value: number | undefined): void {\n collapseStringLimitOverride = value;\n}\n\n/** Effective accumulated-string ceiling, honoring any active test-only override. */\nfunction effectiveCollapseStringLimit(): number {\n return collapseStringLimitOverride ?? MAX_COLLAPSE_STRING_LENGTH;\n}\n\n/**\n * Guard a raw collapse-input body against V8's max string length BEFORE any\n * per-delta accumulation begins. Every collapser accumulates `content` /\n * `reasoning` / a tool call's `arguments` / `audioB64` / `argsStr` (and the\n * coalesced text of `orderAtoms`) from fragments of `body`; the sum of any one\n * of those accumulators can never exceed the total input length, so bounding\n * the INPUT under the ceiling bounds EVERY accumulator at once — no per-`+=`\n * site can then build a string past the limit and throw\n * `RangeError: Invalid string length` (the ~1/sec prod crash).\n *\n * Returns the body UNCHANGED when it is within the ceiling. When it exceeds the\n * ceiling this returns a hard-truncated prefix (never throwing) — the collapse\n * result the caller builds from it is marked incomplete via `truncated: true`\n * (see {@link isCollapseInputTruncated}). This mirrors the proxy buffer's\n * \"bound then mark truncated, never fail the client\" discipline: on the proxy\n * path a body this large has already tripped the byte cap and skipped recording,\n * so this is a defense-in-depth backstop that also covers the direct (exported)\n * collapse callers where no byte cap ran.\n */\nfunction guardCollapseBody(body: string): string {\n const limit = effectiveCollapseStringLimit();\n if (body.length <= limit) return body;\n return body.slice(0, limit);\n}\n\n/**\n * True when a body exceeded the accumulated-string ceiling and had to be\n * truncated by {@link guardCollapseBody}. Collapsers stamp `truncated: true` on\n * their result in this case so the recorder skips journaling a partial fixture,\n * exactly like a transport-truncated stream.\n */\nfunction isCollapseInputTruncated(body: string): boolean {\n return body.length > effectiveCollapseStringLimit();\n}\n\n// ---------------------------------------------------------------------------\n// Result type shared by all collapse functions\n// ---------------------------------------------------------------------------\n\nexport interface CollapseResult {\n content?: string;\n transcription?: {\n text: string;\n languages?: Array<{ code: string }>;\n usage?: Record<string, unknown>;\n };\n reasoning?: string;\n /**\n * The real cryptographic `signature` value captured from an Anthropic\n * `signature_delta`. Carried so a recorded real-provider thinking turn can\n * replay its ACTUAL signature instead of aimock's placeholder. Absent when the\n * stream carried no signature. Single-signature assumption: a turn with\n * MULTIPLE thinking blocks collapses to one merged `reasoning` string carrying\n * only the FINAL block's signature (last-signature-wins) — per-block fidelity\n * is not preserved. The recorder persists this only alongside a non-empty\n * `reasoning` (a bare signature has nothing to attach to on replay); see\n * `TextResponse.reasoningSignature` in types.ts.\n */\n reasoningSignature?: string;\n /**\n * The opaque `data` payload(s) of any Anthropic `redacted_thinking` blocks, in\n * stream order. Captured so a recorded redacted-thinking turn round-trips its\n * encrypted reasoning faithfully. Absent when none present.\n */\n redactedThinking?: string[];\n webSearches?: string[];\n /**\n * The provider-reported `usage` object from the stream's final usage frame,\n * captured VERBATIM (#368). OpenAI-compatible streams (including OpenRouter)\n * close with a `chat.completion.chunk` whose `choices` is empty and whose\n * `usage` carries the real token counts — plus, on OpenRouter,\n * `cost` / `cost_details` / `native_tokens_*`. Collapsing dropped that frame,\n * so a recorded fixture could only ever replay estimated (`ceil(len/4)`) token\n * counts and never a provider-reported cost. Last-usage-wins: a stream that\n * emits several usage frames keeps the final one. Absent when the upstream\n * stream carried no usage (e.g. `stream_options.include_usage` unset).\n *\n * Kept as a loose record because the field set is provider-specific and\n * forward-extending; the recorder sanitizes it into the fixture\n * `response.usage` override shape before persisting.\n */\n usage?: Record<string, unknown>;\n toolCalls?: ToolCall[];\n droppedChunks?: number;\n firstDroppedSample?: string;\n truncated?: boolean;\n audioB64?: string;\n audioMimeType?: string;\n /**\n * Set when harmony channel tokens were present in the accumulated content but\n * could NOT be parsed into a complete, valid harmony structure. The content\n * is preserved VERBATIM, so this is NOT transport loss — it is distinct from\n * `droppedChunks` / `truncated`, which are reserved for genuine transport loss\n * (malformed SSE/NDJSON frames, CRC mismatch). The caller surfaces this as a\n * dedicated warning rather than a dropped/truncated-chunk warning.\n */\n harmonyUnparsed?: true;\n /** Short human-readable note accompanying {@link harmonyUnparsed}. */\n harmonyNote?: string;\n /**\n * Ordered cross-channel block list, in STREAM order, populated ONLY when the\n * stream is \"interleaved\" — i.e. a tool-call delta appeared STRICTLY BEFORE\n * the first content delta, OR a content delta appeared AFTER any tool-call\n * delta. The flat `content` / `toolCalls` fields stay populated UNCHANGED for\n * replay back-compat and non-block consumers; `blocks` is purely additive\n * positional instrumentation the recorder consults to decide whether to\n * persist the ordered shape. Absent (undefined) for text-first, text-only,\n * and tool-only streams — i.e. anything NOT interleaved — so the recorder\n * keeps the legacy `{ content, toolCalls }` shape byte-identical.\n *\n * Each text block coalesces all contiguous content deltas between tool\n * atoms; each toolCall block carries the fully-assembled name/arguments/id\n * for one tool call in the position its FIRST delta arrived.\n */\n blocks?: FixtureBlock[];\n}\n\n// ---------------------------------------------------------------------------\n// Cross-channel block-order instrumentation (#274)\n// ---------------------------------------------------------------------------\n\n/**\n * Atom recorded during a collapse pass, in stream arrival order. A `text` atom\n * carries one content delta's text (contiguous text atoms are coalesced when\n * building blocks); a `toolCall` atom is a stable reference to a tool-call\n * accumulator whose name/arguments/id are filled in across later deltas. The\n * `ref` is the SAME object stored in the collapser's `toolCallMap` (or pushed\n * to a flat `toolCalls` array), so block identity is reconciled with the flat\n * representation at finalize time — see {@link buildOrderedBlocks}.\n */\ntype OrderAtom =\n | { kind: \"text\"; text: string }\n | { kind: \"toolCall\"; ref: { name: string; arguments: string; id?: string } };\n\n/**\n * Normalize a tool call's accumulated `arguments` into valid JSON exactly like\n * the flat-`toolCalls` recorder path: an empty / whitespace-only / missing\n * value becomes `\"{}\"`, never `\"\"`. Mirrors `recorder.ts` `toToolCallArguments`\n * so a `blocks[].arguments` value is always parseable JSON and never disagrees\n * with the flat `toolCalls` entry for the same call.\n */\nfunction normalizeToolArguments(args: string | undefined): string {\n if (args === undefined || args.trim() === \"\") return \"{}\";\n return args;\n}\n\n/**\n * Build a finalized {@link FixtureBlock.toolCall} from a tool-call accumulator,\n * normalizing `arguments` so the block agrees byte-for-byte with the flat\n * `toolCalls` entry built from the SAME accumulator object.\n */\nfunction toToolCallBlock(ref: { name: string; arguments: string; id?: string }): FixtureBlock {\n return {\n type: \"toolCall\",\n name: ref.name,\n arguments: normalizeToolArguments(ref.arguments),\n ...(ref.id ? { id: ref.id } : {}),\n };\n}\n\n/**\n * Decide whether a recorded atom sequence is \"interleaved\" and, if so, build\n * the ordered {@link FixtureBlock} list. Returns `undefined` when NOT\n * interleaved (text-first, text-only, or tool-only) so callers leave\n * `CollapseResult.blocks` unset and the recorder keeps the legacy shape.\n *\n * Interleaved ⇔ (a tool atom appears strictly before the first text atom) OR\n * (a text atom appears after any tool atom). A stream with no tool atoms, or\n * with no text atoms, is never interleaved. Text-first-then-tools is the common\n * legacy case and is explicitly NOT interleaved.\n *\n * CONSISTENCY (#274): each toolCall block is derived from the SAME accumulator\n * object referenced by its atom and normalized identically to the flat\n * `toolCalls` path ({@link toToolCallBlock} / {@link normalizeToolArguments}).\n * Because the atom `ref` is the very object the flat list is built from, the\n * block and its flat counterpart describe the same call by identity — even when\n * upstream tool-call indices do not match stream-arrival order. Empty/missing\n * arguments normalize to `\"{}\"` in BOTH representations, never `\"\"`.\n */\nfunction buildOrderedBlocks(atoms: OrderAtom[]): FixtureBlock[] | undefined {\n let firstTextIndex = -1;\n let firstToolIndex = -1;\n let textAfterTool = false;\n let sawTool = false;\n let sawText = false;\n for (let i = 0; i < atoms.length; i++) {\n const a = atoms[i];\n if (a.kind === \"text\") {\n sawText = true;\n if (firstTextIndex === -1) firstTextIndex = i;\n if (sawTool) textAfterTool = true;\n } else {\n sawTool = true;\n if (firstToolIndex === -1) firstToolIndex = i;\n }\n }\n // No cross-channel ordering to express unless BOTH channels appear.\n if (!sawTool || !sawText) return undefined;\n const toolBeforeText = firstToolIndex < firstTextIndex;\n if (!toolBeforeText && !textAfterTool) return undefined;\n\n // Coalesce contiguous text atoms into one text block; emit each tool atom as\n // a toolCall block reflecting its fully-assembled, normalized accumulator.\n const blocks: FixtureBlock[] = [];\n let pendingText = \"\";\n let hasPendingText = false;\n const flushText = () => {\n if (hasPendingText) {\n blocks.push({ type: \"text\", text: pendingText });\n pendingText = \"\";\n hasPendingText = false;\n }\n };\n for (const a of atoms) {\n if (a.kind === \"text\") {\n pendingText += a.text;\n hasPendingText = true;\n } else {\n flushText();\n blocks.push(toToolCallBlock(a.ref));\n }\n }\n flushText();\n return blocks;\n}\n\n/**\n * The opaque `data` of a non-empty Anthropic `redacted_thinking` block, or\n * `undefined` if `block` is not a redacted_thinking block or carries empty/no\n * data. NON-EMPTY is required: the replay-side validator rejects a leading\n * empty-data redacted_thinking block, so recording `data: \"\"` would yield a\n * fixture that 400s under strict replay. Shared by every capture site (SSE,\n * Anthropic-native binary, non-streaming recorder) so the rule stays in one\n * place.\n */\nexport function capturedRedactedData(\n block: Record<string, unknown> | undefined,\n): string | undefined {\n if (\n block?.type === \"redacted_thinking\" &&\n typeof block.data === \"string\" &&\n block.data.length > 0\n ) {\n return block.data;\n }\n return undefined;\n}\n\n/**\n * Slice the first `max` UTF-16 code units of `s` for a diagnostic sample,\n * trimming a trailing lone high-surrogate so the resulting sample never ends on\n * a lone high surrogate (i.e. never mid-surrogate-pair).\n */\nfunction surrogateSafeSlice(s: string, max: number): string {\n let out = s.slice(0, max);\n if (out.length > 0) {\n const last = out.charCodeAt(out.length - 1);\n // A high surrogate (U+D800..U+DBFF) at the end is the lead of a split pair.\n if (last >= 0xd800 && last <= 0xdbff) {\n out = out.slice(0, -1);\n }\n }\n return out;\n}\n\n/**\n * Split a raw SSE body into per-event blocks.\n *\n * Events are delimited by a blank line. Real HTTP/SSE transports use CRLF\n * (`\\r\\n`) line endings, so the inter-event delimiter is `\\r\\n\\r\\n` (which\n * contains no `\\n\\n` substring) and each line ends with a trailing `\\r`.\n * Splitting on `/\\r?\\n\\r?\\n/` handles LF, CRLF, and mixed streams; per-line\n * `\\r` trimming happens in {@link splitSSELines}. Blank blocks are dropped.\n */\nfunction splitSSEEvents(body: string): string[] {\n return body.split(/\\r?\\n\\r?\\n/).filter((block) => block.trim().length > 0);\n}\n\n/**\n * Split a single SSE event block into its lines, trimming a trailing `\\r` so\n * CRLF streams parse identically to LF streams.\n */\nfunction splitSSELines(block: string): string[] {\n return block.split(\"\\n\").map((line) => (line.endsWith(\"\\r\") ? line.slice(0, -1) : line));\n}\n\n/**\n * Extract the SSE `data` field from a single event block's lines.\n *\n * Per the SSE spec a single event may carry MULTIPLE `data:` lines; the field\n * value is every data line's content joined with \"\\n\". Collecting only the\n * first `data:` line (e.g. via `.find`) corrupts payloads that a server split\n * across lines. Callers MUST pass lines produced by {@link splitSSELines} so\n * any trailing `\\r` is already stripped. Returns the joined payload (with the\n * leading \"data:\" prefix and one optional leading space stripped per line), or\n * `undefined` when the block contains no `data:` line.\n */\nfunction extractSSEData(lines: string[]): string | undefined {\n const dataParts: string[] = [];\n for (const line of lines) {\n if (!line.startsWith(\"data:\")) continue;\n // Strip \"data:\" then a single optional leading space, per the SSE spec.\n let part = line.slice(5);\n if (part.startsWith(\" \")) part = part.slice(1);\n dataParts.push(part);\n }\n if (dataParts.length === 0) return undefined;\n return dataParts.join(\"\\n\");\n}\n\n// ---------------------------------------------------------------------------\n// 1. OpenAI SSE\n// ---------------------------------------------------------------------------\n\n/**\n * Collapse OpenAI Chat Completions SSE stream into a single response.\n *\n * Format:\n * data: {\"id\":\"chatcmpl-123\",\"choices\":[{\"delta\":{\"content\":\"Hello\"}}]}\\n\\n\n * data: [DONE]\\n\\n\n */\nexport function collapseOpenAISSE(rawBody: string): CollapseResult {\n const inputTruncated = isCollapseInputTruncated(rawBody);\n const body = guardCollapseBody(rawBody);\n const lines = splitSSEEvents(body);\n let content = \"\";\n let transcript = \"\";\n let transcriptSeen = false;\n let transcriptLanguages: Array<{ code: string }> | undefined;\n let transcriptUsage: Record<string, unknown> | undefined;\n let reasoning = \"\";\n const webSearchQueries: string[] = [];\n // Provider-reported usage from the stream's final usage frame (#368).\n let usage: Record<string, unknown> | undefined;\n let droppedChunks = 0;\n let firstDroppedSample: string | undefined;\n let harmonyUnparsed = false;\n let harmonyNote: string | undefined;\n const toolCallMap = new Map<number, { id: string; name: string; arguments: string }>();\n // Fallback keying for deltas that OMIT `index`. Without this, every\n // index-less delta collapses under one `undefined`/NaN key, merging distinct\n // tool calls and corrupting arguments. Index-less fragments that share an\n // `id` correlate via `idKeyMap`; otherwise each gets a fresh synthetic key\n // assigned from a counter kept above any real index so sort order is stable.\n // The 1_000_000 sentinel assumes real provider tool-call indices stay below\n // it (they are small per-stream counters), so synthetic keys never collide.\n let nextSyntheticIndex = 1_000_000;\n const idKeyMap = new Map<string, number>();\n // The key of the most-recently-opened tool call (real, id-correlated, or\n // synthetic). A delta that omits BOTH `index` and `id` carries no identity of\n // its own; without a fallback each such fragment would mint a fresh synthetic\n // key, splitting one call's arguments streamed across multiple bare deltas\n // into separate tool-call entries with no drop/truncation signal. Correlate\n // it to the last-open call instead (real OpenAI always streams `index`, so\n // this only affects the degenerate index-and-id-less case).\n let lastToolCallKey: number | undefined;\n // Cross-channel order atoms (#274), in stream arrival order. A toolCall atom\n // references the same accumulator object stored in toolCallMap, so later arg\n // deltas mutate the block in place.\n const orderAtoms: OrderAtom[] = [];\n\n for (const line of lines) {\n const data = extractSSEData(splitSSELines(line));\n if (data === undefined) continue;\n\n const payload = data.trim();\n if (payload === \"[DONE]\") continue;\n\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(payload) as Record<string, unknown>;\n } catch (err) {\n droppedChunks++;\n if (droppedChunks === 1) {\n const msg = err instanceof Error ? err.message : \"unknown\";\n firstDroppedSample = `parse failed (${msg}): ${surrogateSafeSlice(payload, 200)}`;\n }\n continue;\n }\n\n // Responses API reasoning events\n if (parsed.type === \"transcript.text.delta\" && typeof parsed.delta === \"string\") {\n transcript += parsed.delta;\n transcriptSeen = true;\n continue;\n }\n if (parsed.type === \"transcript.text.done\" && typeof parsed.text === \"string\") {\n transcript = parsed.text;\n transcriptSeen = true;\n if (Array.isArray(parsed.languages)) {\n transcriptLanguages = parsed.languages\n .filter(\n (language): language is Record<string, unknown> =>\n typeof language === \"object\" &&\n language !== null &&\n typeof language.code === \"string\",\n )\n .map((language) => ({ code: language.code as string }));\n }\n // Only capture a real usage OBJECT. `typeof === \"object\"` alone admits an\n // array (a type lie once cast to Record) and an empty `{}` (meaningless);\n // guard against both, exactly like any chat usage capture would.\n if (\n parsed.usage &&\n typeof parsed.usage === \"object\" &&\n !Array.isArray(parsed.usage) &&\n Object.keys(parsed.usage).length > 0\n ) {\n transcriptUsage = parsed.usage as Record<string, unknown>;\n }\n continue;\n }\n if (\n parsed.type === \"response.reasoning_summary_text.delta\" &&\n typeof parsed.delta === \"string\"\n ) {\n reasoning += parsed.delta;\n continue;\n }\n\n // Responses API web search + function-call completion events\n if (parsed.type === \"response.output_item.done\") {\n const item = parsed.item as Record<string, unknown> | undefined;\n if (item?.type === \"web_search_call\") {\n const action = item.action as Record<string, unknown> | undefined;\n if (action && typeof action.query === \"string\") {\n webSearchQueries.push(action.query);\n continue;\n }\n }\n if (item?.type === \"function_call\" && typeof parsed.output_index === \"number\") {\n // Finalize the accumulated tool call. Fill id/name when the opening\n // `.added` event was absent, and adopt the full `arguments` ONLY when\n // the delta stream produced none — never re-append, since the deltas\n // already carry the complete string.\n const entry = toolCallMap.get(parsed.output_index);\n if (entry) {\n if (!entry.id && typeof item.call_id === \"string\") entry.id = item.call_id;\n if (!entry.name && typeof item.name === \"string\") entry.name = item.name;\n if (entry.arguments === \"\" && typeof item.arguments === \"string\") {\n entry.arguments = item.arguments;\n }\n } else {\n const created = {\n id: typeof item.call_id === \"string\" ? item.call_id : \"\",\n name: typeof item.name === \"string\" ? item.name : \"\",\n arguments: typeof item.arguments === \"string\" ? item.arguments : \"\",\n };\n toolCallMap.set(parsed.output_index, created);\n orderAtoms.push({ kind: \"toolCall\", ref: created });\n }\n continue;\n }\n }\n\n // Responses API function-call streaming events. A tool call arrives as\n // `response.output_item.added` (a `function_call` item) → one or more\n // `response.function_call_arguments.delta` → `response.function_call_arguments.done`\n // (plus the closing `response.output_item.done` handled above). Mirror the\n // Chat-Completions tool-call accumulation below so a tool-call-only turn\n // collapses to `toolCalls` instead of being silently dropped by the\n // `response.*` catch-all. Key by `output_index` (present on every one of\n // these events); its integer space is disjoint from the Chat-Completions\n // `tool_calls[].index` space because a single stream is never both shapes.\n if (parsed.type === \"response.output_item.added\") {\n const item = parsed.item as Record<string, unknown> | undefined;\n if (item?.type === \"function_call\" && typeof parsed.output_index === \"number\") {\n if (!toolCallMap.has(parsed.output_index)) {\n const created = {\n // The Responses API `call_id` is what a tool result references, so\n // capture THAT (not the internal `fc_…` item id) as the tool-call\n // id — matching what the replay path treats as `toolCall.id`.\n id: typeof item.call_id === \"string\" ? item.call_id : \"\",\n name: typeof item.name === \"string\" ? item.name : \"\",\n arguments: \"\",\n };\n toolCallMap.set(parsed.output_index, created);\n orderAtoms.push({ kind: \"toolCall\", ref: created });\n }\n continue;\n }\n }\n if (\n parsed.type === \"response.function_call_arguments.delta\" &&\n typeof parsed.delta === \"string\" &&\n typeof parsed.output_index === \"number\"\n ) {\n let entry = toolCallMap.get(parsed.output_index);\n if (!entry) {\n entry = { id: \"\", name: \"\", arguments: \"\" };\n toolCallMap.set(parsed.output_index, entry);\n orderAtoms.push({ kind: \"toolCall\", ref: entry });\n }\n entry.arguments += parsed.delta;\n continue;\n }\n if (\n parsed.type === \"response.function_call_arguments.done\" &&\n typeof parsed.output_index === \"number\"\n ) {\n // The `.done` event repeats the fully-assembled `arguments`; adopt it only\n // when the deltas produced nothing (a delta-less stream) so we never\n // double-append.\n const entry = toolCallMap.get(parsed.output_index);\n if (entry) {\n if (entry.arguments === \"\" && typeof parsed.arguments === \"string\") {\n entry.arguments = parsed.arguments;\n }\n } else if (typeof parsed.arguments === \"string\") {\n const created = { id: \"\", name: \"\", arguments: parsed.arguments };\n toolCallMap.set(parsed.output_index, created);\n orderAtoms.push({ kind: \"toolCall\", ref: created });\n }\n continue;\n }\n\n // Responses API text content events\n if (parsed.type === \"response.output_text.delta\" && typeof parsed.delta === \"string\") {\n content += parsed.delta;\n if (parsed.delta.length > 0) {\n orderAtoms.push({ kind: \"text\", text: parsed.delta });\n }\n continue;\n }\n\n // Skip other Responses API structural events\n if (typeof parsed.type === \"string\" && parsed.type.startsWith(\"response.\")) {\n continue;\n }\n\n // Final usage frame (#368). OpenAI-compatible providers close an\n // include_usage stream with a `chat.completion.chunk` carrying EMPTY\n // `choices` and a populated `usage` — the only frame with the real token\n // counts, and on OpenRouter the only one with `cost`. Capture it BEFORE the\n // empty-`choices` guard below, which would otherwise skip the frame\n // entirely. Some providers also attach `usage` to the finish chunk (non-empty\n // choices), so this runs for every chat chunk, last-NON-EMPTY-usage-wins:\n // a trailing bare `usage: {}` frame must not clobber a good capture (#369).\n if (\n parsed.usage &&\n typeof parsed.usage === \"object\" &&\n !Array.isArray(parsed.usage) &&\n Object.keys(parsed.usage).length > 0\n ) {\n usage = parsed.usage as Record<string, unknown>;\n }\n\n const choices = parsed.choices as Array<Record<string, unknown>> | undefined;\n if (!choices || choices.length === 0) continue;\n\n const delta = choices[0].delta as Record<string, unknown> | undefined;\n if (!delta) continue;\n\n // Reasoning content (OpenRouter / chat completions format)\n if (typeof delta.reasoning_content === \"string\") {\n reasoning += delta.reasoning_content;\n }\n\n // Text content\n if (typeof delta.content === \"string\") {\n content += delta.content;\n if (delta.content.length > 0) {\n orderAtoms.push({ kind: \"text\", text: delta.content });\n }\n }\n\n // Tool calls\n const toolCalls = delta.tool_calls as Array<Record<string, unknown>> | undefined;\n if (toolCalls) {\n for (const tc of toolCalls) {\n const fn = tc.function as Record<string, unknown> | undefined;\n const rawId = typeof tc.id === \"string\" ? tc.id : undefined;\n\n // Resolve a stable map key. Prefer the streamed `index`; when it is\n // absent, correlate by `id` if present, else mint a fresh synthetic\n // key so distinct index-less calls never merge.\n let index: number;\n if (typeof tc.index === \"number\") {\n index = tc.index;\n } else if (rawId !== undefined) {\n const existing = idKeyMap.get(rawId);\n if (existing !== undefined) {\n index = existing;\n } else {\n index = nextSyntheticIndex++;\n idKeyMap.set(rawId, index);\n }\n } else if (lastToolCallKey !== undefined) {\n // No `index` AND no `id`: correlate to the last-open tool call so a\n // call's arguments streamed across multiple bare deltas concatenate\n // into one entry instead of fragmenting under fresh synthetic keys.\n index = lastToolCallKey;\n } else {\n index = nextSyntheticIndex++;\n }\n // Remember this key so a following index-and-id-less delta correlates\n // to whichever call most recently opened.\n lastToolCallKey = index;\n\n if (!toolCallMap.has(index)) {\n const created = {\n id: rawId ?? \"\",\n name: (fn?.name as string) ?? \"\",\n arguments: \"\",\n };\n toolCallMap.set(index, created);\n // Record the tool atom at the position its FIRST delta arrived; it\n // references `created` so later name/arg deltas fill it in place.\n orderAtoms.push({ kind: \"toolCall\", ref: created });\n }\n\n const entry = toolCallMap.get(index)!;\n if (fn?.name && typeof fn.name === \"string\" && !entry.name) {\n entry.name = fn.name;\n }\n if (tc.id && typeof tc.id === \"string\" && !entry.id) {\n entry.id = tc.id;\n }\n if (fn?.arguments && typeof fn.arguments === \"string\") {\n entry.arguments += fn.arguments;\n }\n }\n }\n }\n\n // Open-weight gpt-oss models (Ollama / vLLM / OpenRouter) stream tool calls\n // as raw harmony channel tokens inside delta.content rather than structured\n // delta.tool_calls. Harmony parsing is FALLBACK-ONLY: attempt it ONLY when\n // there are NO structured delta.tool_calls. If structured tool calls exist,\n // any harmony-looking content is prose — never merged (no phantom tool call),\n // never stamped as truncated/dropped. When harmony IS the only source, a\n // successful parse routes channels (content/reasoning/toolCalls); a failure\n // preserves content VERBATIM and surfaces the distinct `harmonyUnparsed`\n // signal (NOT droppedChunks/truncated — the bytes are not lost).\n const harmonyToolCalls: ToolCall[] = [];\n if (toolCallMap.size === 0 && isHarmonyContent(content)) {\n const parsed = parseHarmonyContent(content);\n if (parsed.failed) {\n harmonyUnparsed = true;\n harmonyNote = `harmony tokens present but unparseable; content preserved verbatim: ${surrogateSafeSlice(content, 200)}`;\n } else {\n content = parsed.content;\n if (parsed.reasoning) {\n reasoning += parsed.reasoning;\n }\n harmonyToolCalls.push(...parsed.toolCalls);\n }\n }\n\n if (toolCallMap.size > 0 || harmonyToolCalls.length > 0) {\n const blocks = buildOrderedBlocks(orderAtoms);\n // When the stream is interleaved we persist ordered `blocks`; the flat\n // `toolCalls` MUST then describe the same calls in the same order so the two\n // representations never disagree (#274). The toolCall atoms reference the\n // same accumulator objects as `toolCallMap`, so derive the flat list from\n // those atoms (stream-arrival order, matching blocks) when blocks exist;\n // otherwise keep the legacy index-sorted order for byte-identical fixtures.\n const orderedToolCalls = orderAtoms\n .filter(\n (a): a is { kind: \"toolCall\"; ref: { name: string; arguments: string; id?: string } } =>\n a.kind === \"toolCall\",\n )\n .map((a) => ({\n name: a.ref.name,\n arguments: normalizeToolArguments(a.ref.arguments),\n ...(a.ref.id ? { id: a.ref.id } : {}),\n }));\n const indexSortedToolCalls = Array.from(toolCallMap.entries())\n .sort(([a], [b]) => a - b)\n .map(([, tc]) => ({\n name: tc.name,\n arguments: normalizeToolArguments(tc.arguments),\n ...(tc.id ? { id: tc.id } : {}),\n }));\n return {\n ...(transcriptSeen\n ? {\n transcription: {\n text: transcript,\n ...(transcriptLanguages ? { languages: transcriptLanguages } : {}),\n ...(transcriptUsage ? { usage: transcriptUsage } : {}),\n },\n }\n : {}),\n ...(blocks ? { blocks } : {}),\n ...(content ? { content } : {}),\n // Fallback-only: harmonyToolCalls are populated ONLY in the\n // no-structured-calls branch, so this is never a merge of both sources.\n toolCalls: [...(blocks ? orderedToolCalls : indexSortedToolCalls), ...harmonyToolCalls],\n // Reasoning is preserved alongside tool calls for ALL structured streams\n // (DeepSeek/OpenRouter reasoning_content, harmony analysis channel), at\n // parity with every other collapser and the non-streaming path.\n ...(reasoning ? { reasoning } : {}),\n // webSearches parity with the text-only return branch.\n ...(webSearchQueries.length > 0 ? { webSearches: webSearchQueries } : {}),\n // Provider-reported usage parity with the text-only return branch (#368).\n ...(usage ? { usage } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n ...(harmonyUnparsed ? { harmonyUnparsed: true } : {}),\n ...(harmonyNote ? { harmonyNote } : {}),\n ...(inputTruncated ? { truncated: true } : {}),\n };\n }\n\n return {\n ...(transcriptSeen\n ? {\n transcription: {\n text: transcript,\n ...(transcriptLanguages ? { languages: transcriptLanguages } : {}),\n ...(transcriptUsage ? { usage: transcriptUsage } : {}),\n },\n }\n : {}),\n content,\n ...(reasoning ? { reasoning } : {}),\n ...(webSearchQueries.length > 0 ? { webSearches: webSearchQueries } : {}),\n ...(usage ? { usage } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n ...(harmonyUnparsed ? { harmonyUnparsed: true } : {}),\n ...(harmonyNote ? { harmonyNote } : {}),\n ...(inputTruncated ? { truncated: true } : {}),\n };\n}\n\n// ---------------------------------------------------------------------------\n// 2. Anthropic SSE\n// ---------------------------------------------------------------------------\n\n/**\n * Collapse Anthropic Claude Messages SSE stream into a single response.\n *\n * Format:\n * event: message_start\\ndata: {...}\\n\\n\n * event: content_block_delta\\ndata: {\"delta\":{\"type\":\"text_delta\",\"text\":\"Hello\"}}\\n\\n\n */\nexport function collapseAnthropicSSE(rawBody: string): CollapseResult {\n const inputTruncated = isCollapseInputTruncated(rawBody);\n const body = guardCollapseBody(rawBody);\n const blocks = splitSSEEvents(body);\n let content = \"\";\n let reasoning = \"\";\n // Real cryptographic signature captured from a `signature_delta`; stays\n // undefined when the stream carried none (e.g. aimock's own placeholder turns\n // or non-thinking turns). Carried so a recorded real-provider thinking turn\n // can replay its ACTUAL signature instead of aimock's placeholder.\n let reasoningSignature: string | undefined;\n // Opaque `data` payloads of any `redacted_thinking` content blocks, in stream\n // order. Stays empty when none present. Carried so a recorded redacted-thinking\n // turn round-trips its encrypted reasoning faithfully on replay.\n const redactedThinking: string[] = [];\n let droppedChunks = 0;\n let firstDroppedSample: string | undefined;\n const toolCallMap = new Map<number, { id: string; name: string; arguments: string }>();\n // Fallback keying for content blocks that OMIT `index` (mirrors the OpenAI /\n // Cohere / Bedrock guards). Without it, every index-less block collapses\n // under one `undefined` key, merging distinct tool_use blocks. Index-less\n // starts mint a fresh synthetic key (kept above any real index so sort order\n // is stable). Despite its name, `lastSyntheticIndex` tracks whichever\n // tool_use start most recently opened REGARDLESS of whether its index was\n // real or synthetic (it is set on every tool_use start; thinking /\n // redacted_thinking starts do not touch it), so an index-less delta\n // correlates to the most-recent tool_use start — not just to the last\n // synthetic one. The 1_000_000 sentinel assumes real provider indices stay\n // below it.\n let nextSyntheticIndex = 1_000_000;\n let lastSyntheticIndex: number | undefined;\n // Cross-channel order atoms (#274), in stream arrival order.\n const orderAtoms: OrderAtom[] = [];\n\n for (const block of blocks) {\n const lines = splitSSELines(block);\n const eventLine = lines.find((l) => l.startsWith(\"event:\"));\n const data = extractSSEData(lines);\n if (data === undefined) continue;\n\n const eventType = eventLine ? eventLine.slice(6).trim() : \"\";\n const payload = data.trim();\n\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(payload) as Record<string, unknown>;\n } catch (err) {\n droppedChunks++;\n if (droppedChunks === 1) {\n const msg = err instanceof Error ? err.message : \"unknown\";\n firstDroppedSample = `parse failed (${msg}): ${surrogateSafeSlice(payload, 200)}`;\n }\n continue;\n }\n\n if (eventType === \"content_block_start\") {\n const contentBlock = parsed.content_block as Record<string, unknown> | undefined;\n // A `redacted_thinking` block carries its encrypted reasoning in an opaque\n // `data` string on the start event (no deltas follow). Capture it so the\n // recorded turn can replay the redacted block faithfully\n // (see capturedRedactedData for the non-empty rule).\n const redactedData = capturedRedactedData(contentBlock);\n if (redactedData !== undefined) {\n redactedThinking.push(redactedData);\n }\n if (contentBlock?.type === \"tool_use\") {\n // Prefer the streamed `index`; when absent, mint a fresh synthetic key\n // so distinct index-less tool_use blocks never merge.\n let index: number;\n if (typeof parsed.index === \"number\") {\n index = parsed.index;\n } else {\n index = nextSyntheticIndex++;\n }\n lastSyntheticIndex = index;\n const created = {\n id: (contentBlock.id as string) ?? \"\",\n name: (contentBlock.name as string) ?? \"\",\n arguments: \"\",\n };\n toolCallMap.set(index, created);\n // Record the tool atom at the position the tool_use block opened; it\n // references `created` so later input_json_delta fragments fill it in.\n orderAtoms.push({ kind: \"toolCall\", ref: created });\n }\n }\n\n if (eventType === \"content_block_delta\") {\n const delta = parsed.delta as Record<string, unknown> | undefined;\n if (!delta) continue;\n\n if (delta.type === \"text_delta\" && typeof delta.text === \"string\") {\n content += delta.text;\n if (delta.text.length > 0) {\n orderAtoms.push({ kind: \"text\", text: delta.text });\n }\n }\n\n if (delta.type === \"thinking_delta\" && typeof delta.thinking === \"string\") {\n reasoning += delta.thinking;\n }\n\n // The real cryptographic signature arrives via a trailing\n // `signature_delta` (the `content_block_start` carried \"\"). Capture the\n // last one seen so a recorded thinking turn replays its actual signature.\n // Last-signature-wins: a turn with MULTIPLE thinking blocks overwrites this\n // on each block, so the merged `reasoning` string ends up bound only to the\n // FINAL block's signature — per-block signatures are not preserved.\n if (delta.type === \"signature_delta\" && typeof delta.signature === \"string\") {\n reasoningSignature = delta.signature;\n }\n\n if (delta.type === \"input_json_delta\" && typeof delta.partial_json === \"string\") {\n // Use the streamed `index` when present; otherwise correlate to the\n // most recent tool_use start (mirrors the start-side fallback).\n const index = typeof parsed.index === \"number\" ? parsed.index : lastSyntheticIndex;\n // A delta that cannot correlate to any known start (no streamed index\n // AND no prior start, or a stale index with no entry) would otherwise\n // silently lose its args. Account for it as a dropped chunk instead of\n // vanishing (mirrors the Cohere uncorrelated-delta path).\n const entry = index !== undefined ? toolCallMap.get(index) : undefined;\n if (entry) {\n entry.arguments += delta.partial_json;\n } else {\n droppedChunks++;\n if (droppedChunks === 1) {\n firstDroppedSample = `input_json_delta with no correlating tool_use start: ${surrogateSafeSlice(\n payload,\n 200,\n )}`;\n }\n }\n }\n }\n }\n\n if (toolCallMap.size > 0) {\n const orderedBlocks = buildOrderedBlocks(orderAtoms);\n // When interleaved (`blocks` present) the flat `toolCalls` MUST match the\n // blocks' order/identity (#274). The toolCall atoms reference the same\n // accumulator objects as `toolCallMap`, so derive the flat list from those\n // atoms (stream-arrival order) when blocks exist; otherwise keep the legacy\n // index-sorted order for byte-identical fixtures.\n const orderedToolCalls = orderAtoms\n .filter(\n (a): a is { kind: \"toolCall\"; ref: { name: string; arguments: string; id?: string } } =>\n a.kind === \"toolCall\",\n )\n .map((a) => ({\n name: a.ref.name,\n arguments: normalizeToolArguments(a.ref.arguments),\n ...(a.ref.id ? { id: a.ref.id } : {}),\n }));\n const indexSortedToolCalls = Array.from(toolCallMap.entries())\n .sort(([a], [b]) => a - b)\n .map(([, tc]) => ({\n name: tc.name,\n arguments: normalizeToolArguments(tc.arguments),\n ...(tc.id ? { id: tc.id } : {}),\n }));\n return {\n ...(orderedBlocks ? { blocks: orderedBlocks } : {}),\n ...(content ? { content } : {}),\n toolCalls: orderedBlocks ? orderedToolCalls : indexSortedToolCalls,\n ...(reasoning ? { reasoning } : {}),\n ...(reasoningSignature ? { reasoningSignature } : {}),\n ...(redactedThinking.length > 0 ? { redactedThinking } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n ...(inputTruncated ? { truncated: true } : {}),\n };\n }\n\n return {\n content,\n ...(reasoning ? { reasoning } : {}),\n ...(reasoningSignature ? { reasoningSignature } : {}),\n ...(redactedThinking.length > 0 ? { redactedThinking } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n ...(inputTruncated ? { truncated: true } : {}),\n };\n}\n\n// ---------------------------------------------------------------------------\n// 3. Gemini SSE\n// ---------------------------------------------------------------------------\n\n/**\n * Collapse Gemini SSE stream into a single response.\n *\n * Format (data-only, no event prefix, no [DONE]):\n * data: {\"candidates\":[{\"content\":{\"parts\":[{\"text\":\"Hello\"}]}}]}\\n\\n\n */\nexport function collapseGeminiSSE(rawBody: string): CollapseResult {\n const inputTruncated = isCollapseInputTruncated(rawBody);\n const body = guardCollapseBody(rawBody);\n const lines = splitSSEEvents(body);\n let content = \"\";\n let reasoning = \"\";\n let droppedChunks = 0;\n let firstDroppedSample: string | undefined;\n let audioB64 = \"\";\n let audioMimeType: string | undefined;\n const toolCalls: ToolCall[] = [];\n // Cross-channel order atoms (#274), in stream arrival order.\n const orderAtoms: OrderAtom[] = [];\n\n for (const line of lines) {\n const data = extractSSEData(splitSSELines(line));\n if (data === undefined) continue;\n\n const payload = data.trim();\n\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(payload) as Record<string, unknown>;\n } catch (err) {\n droppedChunks++;\n if (droppedChunks === 1) {\n const msg = err instanceof Error ? err.message : \"unknown\";\n firstDroppedSample = `parse failed (${msg}): ${surrogateSafeSlice(payload, 200)}`;\n }\n continue;\n }\n\n const candidates = parsed.candidates as Array<Record<string, unknown>> | undefined;\n if (!candidates || candidates.length === 0) continue;\n\n const candidateContent = candidates[0].content as Record<string, unknown> | undefined;\n if (!candidateContent) continue;\n\n const parts = candidateContent.parts as Array<Record<string, unknown>> | undefined;\n if (!parts || parts.length === 0) continue;\n\n for (const part of parts) {\n if (part.functionCall) {\n const fc = part.functionCall as Record<string, unknown>;\n const created: ToolCall = {\n name: String(fc.name ?? \"\"),\n // Default undefined/object args to a JSON object string (matches\n // collapseGeminiInteractionsSSE / Ollama). JSON.stringify(undefined)\n // would otherwise yield the VALUE undefined, violating the\n // ToolCall.arguments:string contract.\n arguments:\n typeof fc.args === \"string\" ? (fc.args as string) : JSON.stringify(fc.args ?? {}),\n };\n toolCalls.push(created);\n // Record the tool atom at the position this functionCall part arrived.\n orderAtoms.push({ kind: \"toolCall\", ref: created });\n } else if (\n part.inlineData &&\n typeof (part.inlineData as Record<string, unknown>).mimeType === \"string\" &&\n ((part.inlineData as Record<string, unknown>).mimeType as string).startsWith(\"audio/\")\n ) {\n const inlineData = part.inlineData as Record<string, unknown>;\n if (!audioMimeType) {\n audioMimeType = inlineData.mimeType as string;\n }\n if (typeof inlineData.data === \"string\") {\n audioB64 += inlineData.data;\n }\n } else if (typeof part.text === \"string\") {\n if (part.thought) {\n reasoning += part.text;\n } else {\n content += part.text;\n if (part.text.length > 0) {\n orderAtoms.push({ kind: \"text\", text: part.text });\n }\n }\n }\n }\n }\n\n // Normalize the flat tool calls' arguments identically to the block path so\n // the two representations never disagree (#274). The toolCall atoms reference\n // the same `created` objects pushed here, so blocks and flat describe the same\n // calls in the same order; this only reconciles empty/missing → \"{}\".\n const normalizedToolCalls = toolCalls.map((tc) => ({\n ...tc,\n arguments: normalizeToolArguments(tc.arguments),\n }));\n\n if (audioB64) {\n // Preserve any content / reasoning / tool calls accumulated in the same\n // stream — a Gemini turn can interleave audio with text and functionCall\n // parts, and the early return must not silently drop them.\n //\n // Deliberately do NOT build ordered `blocks` here (#274, R2-N2): the audio\n // collapse shape maps to AudioResponse, which has no `blocks` slot, and the\n // recorder's audio branch never persists `collapsed.blocks`. Producing block\n // ordering on this path would be silently produced-then-dropped, advertising\n // a field this result shape can't carry. Block ordering is built only on the\n // content+toolCalls path below, which can actually carry it.\n return {\n audioB64,\n audioMimeType,\n ...(content ? { content } : {}),\n ...(reasoning ? { reasoning } : {}),\n ...(normalizedToolCalls.length > 0 ? { toolCalls: normalizedToolCalls } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n ...(inputTruncated ? { truncated: true } : {}),\n };\n }\n\n if (toolCalls.length > 0) {\n const blocks = buildOrderedBlocks(orderAtoms);\n return {\n ...(blocks ? { blocks } : {}),\n ...(content ? { content } : {}),\n toolCalls: normalizedToolCalls,\n ...(reasoning ? { reasoning } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n ...(inputTruncated ? { truncated: true } : {}),\n };\n }\n\n return {\n content,\n ...(reasoning ? { reasoning } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n ...(inputTruncated ? { truncated: true } : {}),\n };\n}\n\n// ---------------------------------------------------------------------------\n// 4. Ollama NDJSON\n// ---------------------------------------------------------------------------\n\n/**\n * Collapse Ollama NDJSON stream into a single response.\n *\n * /api/chat format:\n * {\"model\":\"llama3\",\"message\":{\"role\":\"assistant\",\"content\":\"Hello\"},\"done\":false}\\n\n *\n * /api/generate format:\n * {\"model\":\"llama3\",\"response\":\"Hello\",\"done\":false}\\n\n *\n * Open-weight gpt-oss served via Ollama streams harmony channel tokens inside\n * `message.content` (just like the OpenAI SSE path), so after accumulation the\n * content is run through the same fail-safe {@link parseHarmonyContent} gate to\n * capture structured tool calls / reasoning instead of leaking raw tokens.\n */\nexport function collapseOllamaNDJSON(rawBody: string): CollapseResult {\n const inputTruncated = isCollapseInputTruncated(rawBody);\n const body = guardCollapseBody(rawBody);\n const lines = body.split(\"\\n\").filter((l) => l.trim().length > 0);\n let content = \"\";\n let reasoning = \"\";\n let droppedChunks = 0;\n let firstDroppedSample: string | undefined;\n let harmonyUnparsed = false;\n let harmonyNote: string | undefined;\n const toolCalls: ToolCall[] = [];\n // Cross-channel order atoms (#274), in stream arrival order.\n const orderAtoms: OrderAtom[] = [];\n\n for (const line of lines) {\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(line.trim()) as Record<string, unknown>;\n } catch (err) {\n droppedChunks++;\n if (droppedChunks === 1) {\n const msg = err instanceof Error ? err.message : \"unknown\";\n firstDroppedSample = `parse failed (${msg}): ${surrogateSafeSlice(line.trim(), 200)}`;\n }\n continue;\n }\n\n // /api/chat format\n const message = parsed.message as Record<string, unknown> | undefined;\n if (message) {\n if (typeof message.content === \"string\") {\n content += message.content;\n if (message.content.length > 0) {\n orderAtoms.push({ kind: \"text\", text: message.content });\n }\n }\n\n // Tool calls\n if (Array.isArray(message.tool_calls)) {\n for (const tc of message.tool_calls as Array<Record<string, unknown>>) {\n const fn = tc.function as Record<string, unknown> | undefined;\n if (fn) {\n const created: ToolCall = {\n name: String(fn.name ?? \"\"),\n // Default undefined/object args to a JSON object (matching\n // collapseGeminiInteractionsSSE) — JSON.stringify(undefined)\n // would otherwise yield the literal string \"undefined\".\n arguments:\n typeof fn.arguments === \"string\"\n ? fn.arguments\n : JSON.stringify(fn.arguments ?? {}),\n };\n toolCalls.push(created);\n orderAtoms.push({ kind: \"toolCall\", ref: created });\n }\n }\n }\n }\n\n // /api/generate format\n else if (typeof parsed.response === \"string\") {\n content += parsed.response;\n if (parsed.response.length > 0) {\n orderAtoms.push({ kind: \"text\", text: parsed.response });\n }\n }\n }\n\n // Open-weight gpt-oss served via Ollama streams harmony channel tokens inside\n // message.content (same as the OpenAI SSE path). Harmony parsing is\n // FALLBACK-ONLY: attempt it ONLY when there are NO structured message\n // tool_calls. If structured tool calls exist, harmony-looking content is\n // prose — never merged (no phantom), never stamped truncated/dropped. On a\n // harmony failure the content is preserved VERBATIM and surfaced via the\n // distinct `harmonyUnparsed` signal (NOT droppedChunks/truncated).\n if (toolCalls.length === 0 && isHarmonyContent(content)) {\n const parsedHarmony = parseHarmonyContent(content);\n if (parsedHarmony.failed) {\n harmonyUnparsed = true;\n harmonyNote = `harmony tokens present but unparseable; content preserved verbatim: ${surrogateSafeSlice(content, 200)}`;\n } else {\n content = parsedHarmony.content;\n if (parsedHarmony.reasoning) {\n reasoning += parsedHarmony.reasoning;\n }\n toolCalls.push(...parsedHarmony.toolCalls);\n }\n }\n\n if (toolCalls.length > 0) {\n const blocks = buildOrderedBlocks(orderAtoms);\n // Normalize flat arguments identically to the block path so the two\n // representations never disagree (#274); same `created` refs, same order.\n const normalizedToolCalls = toolCalls.map((tc) => ({\n ...tc,\n arguments: normalizeToolArguments(tc.arguments),\n }));\n return {\n ...(blocks ? { blocks } : {}),\n ...(content ? { content } : {}),\n toolCalls: normalizedToolCalls,\n ...(reasoning ? { reasoning } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n ...(harmonyUnparsed ? { harmonyUnparsed: true } : {}),\n ...(harmonyNote ? { harmonyNote } : {}),\n ...(inputTruncated ? { truncated: true } : {}),\n };\n }\n\n return {\n content,\n ...(reasoning ? { reasoning } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n ...(harmonyUnparsed ? { harmonyUnparsed: true } : {}),\n ...(harmonyNote ? { harmonyNote } : {}),\n ...(inputTruncated ? { truncated: true } : {}),\n };\n}\n\n// ---------------------------------------------------------------------------\n// 5. Cohere SSE\n// ---------------------------------------------------------------------------\n\n/**\n * Collapse Cohere SSE stream into a single response.\n *\n * Format:\n * event: content-delta\\ndata: {\"type\":\"content-delta\",\"delta\":{\"message\":{\"content\":{\"text\":\"Hello\"}}}}\\n\\n\n */\nexport function collapseCohereSSE(rawBody: string): CollapseResult {\n const inputTruncated = isCollapseInputTruncated(rawBody);\n const body = guardCollapseBody(rawBody);\n const blocks = splitSSEEvents(body);\n let content = \"\";\n // Reasoning text assembled from `thinking` content-delta blocks. Cohere's\n // reasoning models stream a `content.type === \"thinking\"` block carrying a\n // `thinking` string before the `text` block; capture it so a recorded\n // reasoning turn round-trips its reasoning instead of dropping it.\n let reasoning = \"\";\n let droppedChunks = 0;\n let firstDroppedSample: string | undefined;\n const toolCallMap = new Map<number, { id: string; name: string; arguments: string }>();\n // Fallback keying for tool-call events that OMIT `index` (mirrors the\n // OpenAI guard). Without it, every index-less tool-call-start collapses\n // under one `undefined`/NaN key, merging distinct calls. Index-less starts\n // mint a fresh synthetic key. `lastStartKey` tracks the most-recent\n // tool-call-start key REGARDLESS of whether it was real or synthetic, so an\n // index-less tool-call-delta correlates to whichever start most recently\n // opened — not just to the last synthetic one. The 1_000_000 sentinel\n // assumes real provider indices stay below it.\n let nextSyntheticIndex = 1_000_000;\n let lastStartKey: number | undefined;\n // Cross-channel order atoms (#274), in stream arrival order. Cohere v2 SSE is\n // a single ordered stream (content-delta / tool-call-start interleave on the\n // wire), so a toolCall atom references the same accumulator object stored in\n // toolCallMap and later tool-call-delta fragments mutate it in place.\n const orderAtoms: OrderAtom[] = [];\n\n for (const block of blocks) {\n const lines = splitSSELines(block);\n const eventLine = lines.find((l) => l.startsWith(\"event:\"));\n const data = extractSSEData(lines);\n if (data === undefined) continue;\n\n const eventType = eventLine ? eventLine.slice(6).trim() : \"\";\n const payload = data.trim();\n\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(payload) as Record<string, unknown>;\n } catch (err) {\n droppedChunks++;\n if (droppedChunks === 1) {\n const msg = err instanceof Error ? err.message : \"unknown\";\n firstDroppedSample = `parse failed (${msg}): ${surrogateSafeSlice(payload, 200)}`;\n }\n continue;\n }\n\n if (eventType === \"content-delta\") {\n const delta = parsed.delta as Record<string, unknown> | undefined;\n const message = delta?.message as Record<string, unknown> | undefined;\n const contentObj = message?.content as Record<string, unknown> | undefined;\n if (contentObj && contentObj.type === \"thinking\" && typeof contentObj.thinking === \"string\") {\n reasoning += contentObj.thinking;\n } else if (contentObj && typeof contentObj.text === \"string\") {\n content += contentObj.text;\n // Reasoning (`thinking`) is intentionally NOT pushed as an order atom —\n // it is not a block channel (mirrors the other collapsers).\n if (contentObj.text.length > 0) {\n orderAtoms.push({ kind: \"text\", text: contentObj.text });\n }\n }\n }\n\n if (eventType === \"tool-call-start\") {\n let index: number;\n if (typeof parsed.index === \"number\") {\n index = parsed.index;\n } else {\n index = nextSyntheticIndex++;\n }\n const delta = parsed.delta as Record<string, unknown> | undefined;\n const message = delta?.message as Record<string, unknown> | undefined;\n const toolCalls = message?.tool_calls as Record<string, unknown> | undefined;\n if (toolCalls) {\n const fn = toolCalls.function as Record<string, unknown> | undefined;\n const created = {\n id: (toolCalls.id as string) ?? \"\",\n name: (fn?.name as string) ?? \"\",\n arguments: \"\",\n };\n toolCallMap.set(index, created);\n // Track the most-recent start key (real OR synthetic) so a following\n // index-less delta correlates to whichever call just opened. Advance it\n // ONLY after confirming this start actually carried a tool_calls payload\n // and created an entry; a payload-less start must not steal correlation\n // from a prior valid start (which would miscount the next index-less\n // delta as a dropped chunk).\n lastStartKey = index;\n // Record the tool atom at the position its tool-call-start arrived; it\n // references `created` so later tool-call-delta args fill it in place.\n orderAtoms.push({ kind: \"toolCall\", ref: created });\n }\n }\n\n if (eventType === \"tool-call-delta\") {\n // Use the streamed `index` when present; otherwise correlate to the most\n // recent tool-call-start (real or synthetic key).\n const index = typeof parsed.index === \"number\" ? parsed.index : lastStartKey;\n const delta = parsed.delta as Record<string, unknown> | undefined;\n const message = delta?.message as Record<string, unknown> | undefined;\n const toolCalls = message?.tool_calls as Record<string, unknown> | undefined;\n if (toolCalls) {\n const fn = toolCalls.function as Record<string, unknown> | undefined;\n if (fn && typeof fn.arguments === \"string\") {\n // A delta that cannot correlate to any known start (no streamed\n // index AND no prior start) would otherwise silently lose its args.\n // Account for it as a dropped chunk instead of vanishing.\n const entry = index !== undefined ? toolCallMap.get(index) : undefined;\n if (entry) {\n entry.arguments += fn.arguments;\n } else {\n droppedChunks++;\n if (droppedChunks === 1) {\n firstDroppedSample = `tool-call-delta with no correlating start: ${surrogateSafeSlice(\n payload,\n 200,\n )}`;\n }\n }\n }\n }\n }\n }\n\n if (toolCallMap.size > 0) {\n const orderedBlocks = buildOrderedBlocks(orderAtoms);\n // When interleaved, persist ordered `blocks` and derive the flat `toolCalls`\n // from the SAME tool atoms (stream-arrival order) so the two never disagree\n // (#274 F4/F5). Otherwise keep the legacy index-sorted order so non-\n // interleaved fixtures stay byte-identical. Both paths normalize arguments\n // so a zero-arg call persists \"{}\" rather than \"\".\n const orderedToolCalls = orderAtoms\n .filter(\n (a): a is { kind: \"toolCall\"; ref: { name: string; arguments: string; id?: string } } =>\n a.kind === \"toolCall\",\n )\n .map((a) => ({\n name: a.ref.name,\n arguments: normalizeToolArguments(a.ref.arguments),\n ...(a.ref.id ? { id: a.ref.id } : {}),\n }));\n const indexSortedToolCalls = Array.from(toolCallMap.entries())\n .sort(([a], [b]) => a - b)\n .map(([, tc]) => ({\n name: tc.name,\n arguments: normalizeToolArguments(tc.arguments),\n ...(tc.id ? { id: tc.id } : {}),\n }));\n return {\n ...(orderedBlocks ? { blocks: orderedBlocks } : {}),\n ...(content ? { content } : {}),\n toolCalls: orderedBlocks ? orderedToolCalls : indexSortedToolCalls,\n ...(reasoning ? { reasoning } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n ...(inputTruncated ? { truncated: true } : {}),\n };\n }\n\n return {\n content,\n ...(reasoning ? { reasoning } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n ...(inputTruncated ? { truncated: true } : {}),\n };\n}\n\n// ---------------------------------------------------------------------------\n// 6. Bedrock EventStream (binary)\n// ---------------------------------------------------------------------------\n\n/**\n * Decode AWS Event Stream binary frames and extract JSON payloads.\n *\n * Binary frame layout:\n * [total_length: 4B uint32-BE]\n * [headers_length: 4B uint32-BE]\n * [prelude_crc32: 4B]\n * [headers: variable]\n * [payload: variable]\n * [message_crc32: 4B]\n */\nfunction decodeEventStreamFrames(buf: Buffer): {\n frames: Array<{ headers: Record<string, string>; payload: Buffer }>;\n truncated: boolean;\n} {\n const frames: Array<{ headers: Record<string, string>; payload: Buffer }> = [];\n let offset = 0;\n\n while (offset < buf.length) {\n if (offset + 12 > buf.length) break;\n\n const totalLength = buf.readUInt32BE(offset);\n const headersLength = buf.readUInt32BE(offset + 4);\n\n // Validate bounds: ensure the full frame is within the buffer\n if (totalLength < 12 || offset + totalLength > buf.length) {\n return { frames, truncated: true };\n }\n\n // Validate prelude CRC\n const preludeCrc = buf.readUInt32BE(offset + 8);\n const computedPreludeCrc = crc32(buf.subarray(offset, offset + 8));\n if (preludeCrc >>> 0 !== computedPreludeCrc >>> 0) {\n return { frames, truncated: true }; // Prelude CRC mismatch — stop parsing\n }\n\n // Parse headers\n const headersStart = offset + 12;\n const headersEnd = headersStart + headersLength;\n const payloadEnd = offset + totalLength - 4; // minus message CRC\n\n // Validate the headers region fits inside the frame. A frame can carry a\n // valid prelude CRC yet declare a `headersLength` that overruns the payload\n // region (the prelude CRC only covers total/headers length, not the body).\n // Without this guard a per-header read walks off the buffer and throws an\n // uncaught RangeError; treat it as truncation instead.\n if (headersEnd > payloadEnd || headersEnd > buf.length) {\n return { frames, truncated: true };\n }\n\n const headers: Record<string, string> = {};\n let hOffset = headersStart;\n let headerOverrun = false;\n\n while (hOffset < headersEnd) {\n // Each read must stay within the declared headers region. Bail out\n // (truncated) on any overrun rather than reading past the boundary.\n if (hOffset + 1 > headersEnd) {\n headerOverrun = true;\n break;\n }\n const nameLen = buf.readUInt8(hOffset);\n hOffset += 1;\n if (hOffset + nameLen + 1 + 2 > headersEnd) {\n headerOverrun = true;\n break;\n }\n const name = buf.subarray(hOffset, hOffset + nameLen).toString(\"utf8\");\n hOffset += nameLen;\n // Skip header type byte (type 7 = STRING)\n hOffset += 1;\n const valueLen = buf.readUInt16BE(hOffset);\n hOffset += 2;\n if (hOffset + valueLen > headersEnd) {\n headerOverrun = true;\n break;\n }\n const value = buf.subarray(hOffset, hOffset + valueLen).toString(\"utf8\");\n hOffset += valueLen;\n headers[name] = value;\n }\n\n if (headerOverrun) {\n return { frames, truncated: true };\n }\n\n // Extract payload\n const payloadStart = headersEnd;\n const payload = buf.subarray(payloadStart, payloadEnd);\n\n // Validate message CRC (covers entire frame minus last 4 bytes)\n const messageCrc = buf.readUInt32BE(offset + totalLength - 4);\n const computedMessageCrc = crc32(buf.subarray(offset, offset + totalLength - 4));\n if (messageCrc >>> 0 !== computedMessageCrc >>> 0) {\n return { frames, truncated: true }; // Message CRC mismatch — stop parsing\n }\n\n frames.push({ headers, payload });\n offset += totalLength;\n }\n\n return { frames, truncated: false };\n}\n\n/**\n * Collapse Bedrock binary Event Stream into a single response.\n *\n * Each frame contains a JSON payload with event types like:\n * contentBlockDelta, contentBlockStart, etc.\n */\nexport function collapseBedrockEventStream(rawBody: Buffer): CollapseResult {\n // Bound the input under V8's max string length before decoding: `content` /\n // `reasoning` / a tool call's `arguments` accumulate across frames and can\n // never exceed the total decoded bytes, so capping the input buffer bounds\n // every accumulator and prevents `RangeError: Invalid string length`. An\n // over-ceiling buffer is truncated (a partial trailing frame simply fails CRC\n // and stops parsing) and the result is marked `truncated`.\n const limit = effectiveCollapseStringLimit();\n const inputTruncated = rawBody.byteLength > limit;\n const body = inputTruncated ? rawBody.subarray(0, limit) : rawBody;\n const { frames, truncated: frameTruncated } = decodeEventStreamFrames(body);\n const truncated = frameTruncated || inputTruncated;\n let content = \"\";\n // Reasoning text assembled from Converse `reasoningContent.text` deltas. The\n // Bedrock Converse stream interleaves a `delta.reasoningContent` block carrying\n // the model's reasoning; capture it so a recorded reasoning turn round-trips\n // its reasoning instead of dropping it.\n let reasoning = \"\";\n // Anthropic-native extended-thinking fields (invoke-with-response-stream).\n // The native binary branch carries the same thinking/signature/redacted\n // channel as the Anthropic SSE collapser; it mirrors that path's\n // thinking/signature/redacted capture rules so a recorded reasoning turn\n // round-trips instead of silently dropping it. Unlike the SSE path, binary\n // tool_use correlation has no index-less fallback and relies on an explicit\n // `index`.\n let reasoningSignature: string | undefined;\n const redactedThinking: string[] = [];\n let droppedChunks = 0;\n let firstDroppedSample: string | undefined;\n const toolCallMap = new Map<number, { id: string; name: string; arguments: string }>();\n // Cross-channel order atoms (#274), in frame (stream) arrival order. Both the\n // Anthropic-native and Converse sub-protocols append text and tool deltas in\n // frame order, so a toolCall atom references the same accumulator object stored\n // in toolCallMap and later arg deltas mutate it in place.\n const orderAtoms: OrderAtom[] = [];\n\n for (const frame of frames) {\n const frameStr = frame.payload.toString(\"utf8\");\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(frameStr) as Record<string, unknown>;\n } catch (err) {\n droppedChunks++;\n if (droppedChunks === 1) {\n const msg = err instanceof Error ? err.message : \"unknown\";\n firstDroppedSample = `parse failed (${msg}): ${surrogateSafeSlice(frameStr, 200)}`;\n }\n continue;\n }\n\n // Anthropic Messages format (invoke-with-response-stream): flat payload with \"type\" field\n if (parsed.type === \"content_block_delta\") {\n const delta = parsed.delta as Record<string, unknown> | undefined;\n if (delta?.type === \"text_delta\" && typeof delta.text === \"string\") {\n content += delta.text;\n if (delta.text.length > 0) {\n orderAtoms.push({ kind: \"text\", text: delta.text });\n }\n }\n if (delta?.type === \"thinking_delta\" && typeof delta.thinking === \"string\") {\n reasoning += delta.thinking;\n }\n // Last-signature-wins: a turn with MULTIPLE thinking blocks overwrites\n // this on each block, so the merged `reasoning` ends up bound only to the\n // FINAL block's signature (mirrors collapseAnthropicSSE).\n if (delta?.type === \"signature_delta\" && typeof delta.signature === \"string\") {\n reasoningSignature = delta.signature;\n }\n if (delta?.type === \"input_json_delta\" && typeof delta.partial_json === \"string\") {\n const index = parsed.index as number | undefined;\n // An arg delta that cannot correlate to a known tool_use start would\n // otherwise silently lose its args. Account for it as a dropped chunk\n // instead of vanishing (mirrors the Cohere uncorrelated-delta path).\n const entry = index !== undefined ? toolCallMap.get(index) : undefined;\n if (entry) {\n entry.arguments += delta.partial_json;\n } else {\n droppedChunks++;\n if (droppedChunks === 1) {\n firstDroppedSample = `input_json_delta with no correlating tool_use start: ${surrogateSafeSlice(\n frameStr,\n 200,\n )}`;\n }\n }\n }\n continue;\n }\n if (parsed.type === \"content_block_start\") {\n const block = parsed.content_block as Record<string, unknown> | undefined;\n const index = parsed.index as number | undefined;\n // A `redacted_thinking` block carries its encrypted reasoning in an\n // opaque `data` string on the start event (no deltas follow). Capture it\n // so the recorded turn replays the redacted block faithfully\n // (mirrors collapseAnthropicSSE; see capturedRedactedData).\n const redactedData = capturedRedactedData(block);\n if (redactedData !== undefined) {\n redactedThinking.push(redactedData);\n }\n if (block?.type === \"tool_use\") {\n if (index !== undefined) {\n const created = {\n id: (block.id as string) ?? \"\",\n name: (block.name as string) ?? \"\",\n arguments: \"\",\n };\n toolCallMap.set(index, created);\n orderAtoms.push({ kind: \"toolCall\", ref: created });\n } else {\n // A tool_use start with no block index cannot be keyed, so no later\n // input_json_delta can ever correlate to it and the tool call's\n // identity is silently lost. Account for it as a dropped chunk —\n // matching the sibling uncorrelated arg-delta path below — rather\n // than vanishing without a trace.\n droppedChunks++;\n if (droppedChunks === 1) {\n firstDroppedSample = `tool_use content_block_start with no index — tool call identity lost: ${surrogateSafeSlice(\n frameStr,\n 200,\n )}`;\n }\n }\n }\n continue;\n }\n\n // Converse format (converse-stream): camelCase wrapper keys\n // contentBlockStart — may initiate a tool_use block\n if (parsed.contentBlockStart) {\n const blockStart = parsed.contentBlockStart as Record<string, unknown>;\n const index = (parsed.contentBlockIndex ?? blockStart.contentBlockIndex) as\n | number\n | undefined;\n const start = blockStart.start as Record<string, unknown> | undefined;\n if (start?.toolUse) {\n if (index !== undefined) {\n const toolUse = start.toolUse as Record<string, unknown>;\n const created = {\n id: (toolUse.toolUseId as string) ?? \"\",\n name: (toolUse.name as string) ?? \"\",\n arguments: \"\",\n };\n toolCallMap.set(index, created);\n orderAtoms.push({ kind: \"toolCall\", ref: created });\n } else {\n // Same accounting as the native path: an unkeyable toolUse start\n // would lose its identity, so count it as a dropped chunk rather\n // than dropping it silently.\n droppedChunks++;\n if (droppedChunks === 1) {\n firstDroppedSample = `contentBlockStart toolUse with no index — tool call identity lost: ${surrogateSafeSlice(\n frameStr,\n 200,\n )}`;\n }\n }\n }\n }\n\n // contentBlockDelta\n if (parsed.contentBlockDelta) {\n const blockDelta = parsed.contentBlockDelta as Record<string, unknown>;\n const index = (parsed.contentBlockIndex ?? blockDelta.contentBlockIndex) as\n | number\n | undefined;\n const delta = blockDelta.delta as Record<string, unknown> | undefined;\n if (!delta) continue;\n\n // Text delta\n if (typeof delta.text === \"string\") {\n content += delta.text;\n if (delta.text.length > 0) {\n orderAtoms.push({ kind: \"text\", text: delta.text });\n }\n }\n\n // Reasoning delta — Converse carries reasoning in `reasoningContent.text`.\n // The Converse branch intentionally captures no signature/redacted channel:\n // Converse has no `signature_delta`/`redacted_thinking` wire shape, so the\n // asymmetry with the Anthropic-native branch above is by design, not a gap\n // to be \"fixed\" later.\n if (typeof delta.reasoningContent === \"object\" && delta.reasoningContent !== null) {\n const reasoningDelta = delta.reasoningContent as Record<string, unknown>;\n if (typeof reasoningDelta.text === \"string\") {\n reasoning += reasoningDelta.text;\n }\n }\n\n // Tool use input JSON delta\n if (typeof delta.toolUse === \"object\" && delta.toolUse !== null) {\n const toolUseDelta = delta.toolUse as Record<string, unknown>;\n if (typeof toolUseDelta.input === \"string\") {\n // An arg delta that cannot correlate to a known tool_use start would\n // otherwise silently lose its args. Account for it as a dropped chunk\n // instead of vanishing (mirrors the Cohere uncorrelated-delta path).\n const entry = index !== undefined ? toolCallMap.get(index) : undefined;\n if (entry) {\n entry.arguments += toolUseDelta.input;\n } else {\n droppedChunks++;\n if (droppedChunks === 1) {\n firstDroppedSample = `toolUse.input delta with no correlating tool_use start: ${surrogateSafeSlice(\n frameStr,\n 200,\n )}`;\n }\n }\n }\n }\n }\n }\n\n if (toolCallMap.size > 0) {\n const orderedBlocks = buildOrderedBlocks(orderAtoms);\n // When interleaved, persist ordered `blocks` and derive the flat `toolCalls`\n // from the SAME tool atoms (frame-arrival order) so the two never disagree\n // (#274 F4/F5); otherwise keep the legacy index-sorted order so non-\n // interleaved fixtures stay byte-identical. Both paths normalize arguments\n // so a zero-arg tool_use persists \"{}\" rather than \"\".\n const orderedToolCalls = orderAtoms\n .filter(\n (a): a is { kind: \"toolCall\"; ref: { name: string; arguments: string; id?: string } } =>\n a.kind === \"toolCall\",\n )\n .map((a) => ({\n name: a.ref.name,\n arguments: normalizeToolArguments(a.ref.arguments),\n ...(a.ref.id ? { id: a.ref.id } : {}),\n }));\n const indexSortedToolCalls = Array.from(toolCallMap.entries())\n .sort(([a], [b]) => a - b)\n .map(([, tc]) => ({\n name: tc.name,\n arguments: normalizeToolArguments(tc.arguments),\n ...(tc.id ? { id: tc.id } : {}),\n }));\n return {\n ...(orderedBlocks ? { blocks: orderedBlocks } : {}),\n // A tool-bearing turn that ALSO streamed text previously DROPPED `content`\n // here. Spread it when present so the interleaved blocks are persistable\n // (the recorder only emits blocks when content+toolCalls coexist) and the\n // text is no longer silently lost (#274).\n ...(content ? { content } : {}),\n toolCalls: orderedBlocks ? orderedToolCalls : indexSortedToolCalls,\n ...(reasoning ? { reasoning } : {}),\n ...(reasoningSignature ? { reasoningSignature } : {}),\n ...(redactedThinking.length > 0 ? { redactedThinking } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n ...(truncated ? { truncated } : {}),\n };\n }\n\n return {\n content,\n ...(reasoning ? { reasoning } : {}),\n ...(reasoningSignature ? { reasoningSignature } : {}),\n ...(redactedThinking.length > 0 ? { redactedThinking } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n ...(truncated ? { truncated } : {}),\n };\n}\n\n// ---------------------------------------------------------------------------\n// 7. Gemini Interactions SSE\n// ---------------------------------------------------------------------------\n\n/**\n * Collapse Gemini Interactions SSE stream into a single response.\n *\n * Handles the SDK 2.x event protocol (the \"Interactions breaking changes,\n * May 2026\" shapes):\n * data: {\"event_type\":\"step.start\",\"index\":1,\"step\":{\"type\":\"function_call\",\"id\":\"call_1\",\"name\":\"fn\",\"arguments\":{}}}\n * data: {\"event_type\":\"step.delta\",\"index\":0,\"delta\":{\"type\":\"text\",\"text\":\"Hello\"}}\n * data: {\"event_type\":\"step.delta\",\"index\":1,\"delta\":{\"type\":\"arguments_delta\",\"arguments\":\"{\\\"x\\\":1}\"}}\n * data: {\"event_type\":\"interaction.completed\",\"interaction\":{\"id\":\"...\",\"usage\":{...}}}\n *\n * The legacy SDK 1.x shapes (`content.delta` with an inline `function_call`\n * delta) are still accepted for backward compatibility with previously\n * recorded fixtures.\n */\nexport function collapseGeminiInteractionsSSE(rawBody: string): CollapseResult {\n const inputTruncated = isCollapseInputTruncated(rawBody);\n const body = guardCollapseBody(rawBody);\n const lines = splitSSEEvents(body);\n let content = \"\";\n let reasoning = \"\";\n let droppedChunks = 0;\n let firstDroppedSample: string | undefined;\n // Legacy 1.x tool calls arrive fully formed in a single content.delta.\n const toolCalls: ToolCall[] = [];\n // 2.x tool calls are assembled across step.start (identity) + arguments_delta\n // (string fragments), keyed by step index.\n const stepToolCalls = new Map<\n number,\n { id?: string; name: string; argsObj?: unknown; argsStr: string }\n >();\n // Synthetic keys for function_call step.start events that arrive without an\n // index (matches the sibling collapsers); seeded high to avoid colliding with\n // real step indices.\n let nextSyntheticStepIndex = 1_000_000;\n\n for (const line of lines) {\n const data = extractSSEData(splitSSELines(line));\n if (data === undefined) continue;\n\n const payload = data.trim();\n\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(payload) as Record<string, unknown>;\n } catch (err) {\n droppedChunks++;\n if (droppedChunks === 1) {\n const msg = err instanceof Error ? err.message : \"unknown\";\n firstDroppedSample = `parse failed (${msg}): ${surrogateSafeSlice(payload, 200)}`;\n }\n continue;\n }\n\n const eventType = parsed.event_type as string | undefined;\n if (!eventType) continue;\n\n const index = typeof parsed.index === \"number\" ? parsed.index : undefined;\n\n if (eventType === \"step.start\") {\n // 2.x — tool-call identity lives on step.start, not in a delta.\n const step = parsed.step as Record<string, unknown> | undefined;\n if (step && step.type === \"function_call\") {\n // An index-less start can't correlate later arguments_delta fragments,\n // but minting a synthetic key preserves the call's identity instead of\n // dropping it silently.\n const key = index ?? nextSyntheticStepIndex++;\n stepToolCalls.set(key, {\n id: step.id ? String(step.id) : undefined,\n name: String(step.name ?? \"\"),\n // step.start may carry a fully-populated `arguments` object (non-\n // streamed calls) or an empty `{}` placeholder (streamed calls).\n argsObj: step.arguments,\n argsStr: \"\",\n });\n }\n } else if (eventType === \"step.delta\" || eventType === \"content.delta\") {\n const delta = parsed.delta as Record<string, unknown> | undefined;\n if (!delta) continue;\n\n if (delta.type === \"text\" && typeof delta.text === \"string\") {\n content += delta.text;\n } else if (delta.type === \"arguments_delta\") {\n // 2.x — argument fragment (a JSON string) keyed by step index.\n const entry = index !== undefined ? stepToolCalls.get(index) : undefined;\n if (entry) {\n if (typeof delta.arguments === \"string\") {\n entry.argsStr += delta.arguments;\n }\n } else {\n droppedChunks++;\n if (droppedChunks === 1) {\n firstDroppedSample = `arguments_delta with no correlating step.start: ${surrogateSafeSlice(\n payload,\n 200,\n )}`;\n }\n }\n } else if (delta.type === \"function_call\") {\n // Legacy 1.x — full tool call inline in a content.delta. Normalize the\n // string branch so a literal `arguments: \"\"` persists \"{}\" not \"\".\n toolCalls.push({\n name: String(delta.name ?? \"\"),\n arguments:\n typeof delta.arguments === \"string\"\n ? normalizeToolArguments(delta.arguments)\n : JSON.stringify(delta.arguments ?? {}),\n ...(delta.id ? { id: String(delta.id) } : {}),\n });\n } else if (delta.type === \"thought_summary\") {\n // 2.x nests the text under `content.text`; 1.x used a flat `text`.\n const summaryContent = delta.content as Record<string, unknown> | undefined;\n if (summaryContent && typeof summaryContent.text === \"string\") {\n reasoning += summaryContent.text;\n } else if (typeof delta.text === \"string\") {\n reasoning += delta.text;\n }\n }\n }\n }\n\n // BLOCK-CAPTURE DECISION (#274): this collapser is ARGS-ONLY — it intentionally\n // does NOT emit `blocks`. Unlike the delta-stream collapsers, the 2.x protocol\n // is step/index-addressed: tool identity arrives on `step.start` and its args\n // on indexed `arguments_delta` fragments, finalized here in SORTED step-index\n // order — interleaved with legacy 1.x calls that are arrival-pushed above. That\n // hybrid flat order cannot be reconciled with arrival-order OrderAtoms by\n // identity, so any emitted `blocks` would risk disagreeing with the flat\n // `toolCalls` (violating the #274 F4/F5 byte-consistency invariant). We\n // therefore only normalize arguments and leave `blocks` unset. Revisit only if\n // the finalizer is reworked to a single arrival-ordered pass.\n\n // Finalize 2.x tool calls in step-index order.\n for (const [, tc] of Array.from(stepToolCalls.entries()).sort(([a], [b]) => a - b)) {\n let args: string;\n if (tc.argsStr !== \"\") {\n args = tc.argsStr;\n // The arguments_delta fragments must concatenate into valid JSON by\n // step.stop. A truncated/interrupted stream can leave them malformed;\n // surface that via droppedChunks rather than writing a corrupt fixture\n // silently (mirrors the per-chunk parse guard above). On failure we MUST\n // NOT persist the invalid-JSON string — it would fail `validateFixtures`\n // on reload (the loader does `JSON.parse(tc.arguments)`). Fall back to\n // \"{}\" so the persisted `arguments` is always valid JSON, exactly like\n // the empty/unusable-args path below (mirrors the OpenAI/Anthropic\n // sibling collapsers, which never persist unparseable tool args).\n try {\n JSON.parse(args);\n } catch {\n droppedChunks++;\n if (droppedChunks === 1) {\n firstDroppedSample = `assembled arguments_delta not valid JSON for \"${tc.name}\": ${surrogateSafeSlice(\n args,\n 200,\n )}`;\n }\n args = \"{}\";\n }\n } else {\n args = typeof tc.argsObj === \"string\" ? tc.argsObj : JSON.stringify(tc.argsObj ?? {});\n }\n // Normalize so a step.start with no arguments / a whitespace-only argsStr\n // persists \"{}\" rather than \"\" (a valid-JSON non-empty argsStr is unchanged).\n toolCalls.push({\n name: tc.name,\n arguments: normalizeToolArguments(args),\n ...(tc.id ? { id: tc.id } : {}),\n });\n }\n\n if (toolCalls.length > 0) {\n return {\n ...(content ? { content } : {}),\n toolCalls,\n ...(reasoning ? { reasoning } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n ...(inputTruncated ? { truncated: true } : {}),\n };\n }\n\n return {\n content,\n ...(reasoning ? { reasoning } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n ...(inputTruncated ? { truncated: true } : {}),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Dispatch helper — pick the right collapse function by provider\n// ---------------------------------------------------------------------------\n\n/**\n * Collapse a streaming response body into a non-streaming fixture response.\n * Returns null if the content type is not a known streaming format.\n * Falls back to OpenAI SSE parsing for unrecognized provider keys with text/event-stream.\n */\nexport function collapseStreamingResponse(\n contentType: string,\n providerKey: RecordProviderKey,\n body: string | Buffer,\n logger?: Logger,\n): CollapseResult | null {\n const ct = contentType.toLowerCase();\n\n if (ct.includes(\"application/vnd.amazon.eventstream\")) {\n const buf = typeof body === \"string\" ? Buffer.from(body, \"binary\") : body;\n return collapseBedrockEventStream(buf);\n }\n\n if (ct.includes(\"application/x-ndjson\")) {\n const str = typeof body === \"string\" ? body : body.toString(\"utf8\");\n return collapseOllamaNDJSON(str);\n }\n\n if (ct.includes(\"text/event-stream\")) {\n const str = typeof body === \"string\" ? body : body.toString(\"utf8\");\n switch (providerKey) {\n // OpenRouter belongs here with OpenAI/Azure: it IS the OpenAI SSE wire\n // format (it is the OpenAI-compatible gateway), and `openrouter` is a\n // first-class RecordProviderKey set by every `/api/v1/chat/completions`\n // record. Without this case it fell to the `default` arm, which collapsed\n // it correctly but logged `unknown SSE provider \"openrouter\"` on EVERY\n // recorded OpenRouter stream — telling users aimock does not recognize a\n // provider it ships first-class support for.\n // `byteplus` joins them for the same reason: Ark's /chat/completions is\n // OpenAI-compatible and is driven through the OpenAI SDK\n // (@tanstack/ai-byteplus adapters/text.ts), so its SSE IS the OpenAI wire\n // format. Omitting the case would reintroduce the exact warn described\n // above for every recorded Ark chat stream.\n case \"openai\":\n case \"azure\":\n case \"openrouter\":\n case \"byteplus\":\n return collapseOpenAISSE(str);\n case \"anthropic\":\n return collapseAnthropicSSE(str);\n case \"gemini\":\n case \"vertexai\":\n return collapseGeminiSSE(str);\n case \"gemini-interactions\":\n return collapseGeminiInteractionsSSE(str);\n case \"cohere\":\n return collapseCohereSSE(str);\n case \"bedrock\":\n return collapseAnthropicSSE(str);\n default:\n logger?.warn(\n `[stream-collapse] unknown SSE provider \"${providerKey}\", falling back to OpenAI SSE format`,\n );\n return collapseOpenAISSE(str);\n }\n }\n\n return null;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"stream-collapse.cjs","names":["isHarmonyContent","parseHarmonyContent"],"sources":["../src/stream-collapse.ts"],"sourcesContent":["/**\n * Stream collapsing functions for record-and-replay.\n *\n * Each function takes a raw streaming response body (SSE, NDJSON, or binary\n * EventStream) and collapses it into a non-streaming fixture response\n * containing `{ content }`, `{ toolCalls }`, or both when the stream includes\n * text followed by tool calls.\n */\n\nimport { crc32 } from \"node:zlib\";\nimport type {\n CustomToolCall,\n FixtureBlock,\n RecordProviderKey,\n ResponsesFixtureBlock,\n ToolCall,\n} from \"./types.js\";\nimport type { Logger } from \"./logger.js\";\nimport { isHarmonyContent, parseHarmonyContent } from \"./harmony.js\";\n\n// ---------------------------------------------------------------------------\n// Accumulated-string cap (RangeError: Invalid string length guard)\n// ---------------------------------------------------------------------------\n\n/**\n * Hard ceiling (UTF-16 code units) for any SINGLE string a collapser\n * accumulates across deltas (`content`, `reasoning`, a tool call's\n * `arguments`, `audioB64`, `argsStr`, and the coalesced text of `orderAtoms`).\n *\n * V8's maximum string length on 64-bit is 2^29 - 1 (~536.8M UTF-16 code\n * units); appending past it throws `RangeError: Invalid string length`. The\n * proxy path bounds the raw BYTE buffer under `PROXY_BUFFER_HARD_CEILING`\n * (256 MiB) before collapse, but the collapser is ALSO reachable directly\n * (exported from index.ts) and — even on the proxy path — a single accumulator\n * can approach the byte budget in code units, so it needs its own guard rather\n * than relying on the byte cap alone. 256Mi code units is comfortably below\n * V8's limit while leaving huge headroom for any real completion (whose\n * accumulated content can never exceed the total streamed body).\n *\n * When an append would cross the ceiling the accumulator keeps the ceiling's\n * worth of characters, drops the overflow, and marks itself truncated — never\n * throwing — mirroring the proxy buffer's \"bound then mark truncated, never\n * fail the client\" discipline.\n */\nexport const MAX_COLLAPSE_STRING_LENGTH = 256 * 1024 * 1024; // 256 Mi UTF-16 code units\n\n/**\n * Test-only override of {@link MAX_COLLAPSE_STRING_LENGTH}. Lets the cap suite\n * exercise the truncation path with a tiny budget instead of building a\n * multi-hundred-MB string. `undefined` (the default) uses the real ceiling.\n * NEVER set from production code.\n */\nlet collapseStringLimitOverride: number | undefined;\n\n/** @internal test-only — see {@link collapseStringLimitOverride}. */\nexport function setCollapseStringLimitForTests(value: number | undefined): void {\n collapseStringLimitOverride = value;\n}\n\n/** Effective accumulated-string ceiling, honoring any active test-only override. */\nfunction effectiveCollapseStringLimit(): number {\n return collapseStringLimitOverride ?? MAX_COLLAPSE_STRING_LENGTH;\n}\n\n/**\n * Guard a raw collapse-input body against V8's max string length BEFORE any\n * per-delta accumulation begins. Every collapser accumulates `content` /\n * `reasoning` / a tool call's `arguments` / `audioB64` / `argsStr` (and the\n * coalesced text of `orderAtoms`) from fragments of `body`; the sum of any one\n * of those accumulators can never exceed the total input length, so bounding\n * the INPUT under the ceiling bounds EVERY accumulator at once — no per-`+=`\n * site can then build a string past the limit and throw\n * `RangeError: Invalid string length` (the ~1/sec prod crash).\n *\n * Returns the body UNCHANGED when it is within the ceiling. When it exceeds the\n * ceiling this returns a hard-truncated prefix (never throwing) — the collapse\n * result the caller builds from it is marked incomplete via `truncated: true`\n * (see {@link isCollapseInputTruncated}). This mirrors the proxy buffer's\n * \"bound then mark truncated, never fail the client\" discipline: on the proxy\n * path a body this large has already tripped the byte cap and skipped recording,\n * so this is a defense-in-depth backstop that also covers the direct (exported)\n * collapse callers where no byte cap ran.\n */\nfunction guardCollapseBody(body: string): string {\n const limit = effectiveCollapseStringLimit();\n if (body.length <= limit) return body;\n return body.slice(0, limit);\n}\n\n/**\n * True when a body exceeded the accumulated-string ceiling and had to be\n * truncated by {@link guardCollapseBody}. Collapsers stamp `truncated: true` on\n * their result in this case so the recorder skips journaling a partial fixture,\n * exactly like a transport-truncated stream.\n */\nfunction isCollapseInputTruncated(body: string): boolean {\n return body.length > effectiveCollapseStringLimit();\n}\n\n// ---------------------------------------------------------------------------\n// Result type shared by all collapse functions\n// ---------------------------------------------------------------------------\n\nexport interface CollapseResult {\n content?: string;\n transcription?: {\n text: string;\n languages?: Array<{ code: string }>;\n usage?: Record<string, unknown>;\n };\n reasoning?: string;\n /**\n * The real cryptographic `signature` value captured from an Anthropic\n * `signature_delta`. Carried so a recorded real-provider thinking turn can\n * replay its ACTUAL signature instead of aimock's placeholder. Absent when the\n * stream carried no signature. Single-signature assumption: a turn with\n * MULTIPLE thinking blocks collapses to one merged `reasoning` string carrying\n * only the FINAL block's signature (last-signature-wins) — per-block fidelity\n * is not preserved. The recorder persists this only alongside a non-empty\n * `reasoning` (a bare signature has nothing to attach to on replay); see\n * `TextResponse.reasoningSignature` in types.ts.\n */\n reasoningSignature?: string;\n /**\n * The opaque `data` payload(s) of any Anthropic `redacted_thinking` blocks, in\n * stream order. Captured so a recorded redacted-thinking turn round-trips its\n * encrypted reasoning faithfully. Absent when none present.\n */\n redactedThinking?: string[];\n webSearches?: string[];\n /**\n * The provider-reported `usage` object from the stream's final usage frame,\n * captured VERBATIM (#368). OpenAI-compatible streams (including OpenRouter)\n * close with a `chat.completion.chunk` whose `choices` is empty and whose\n * `usage` carries the real token counts — plus, on OpenRouter,\n * `cost` / `cost_details` / `native_tokens_*`. Collapsing dropped that frame,\n * so a recorded fixture could only ever replay estimated (`ceil(len/4)`) token\n * counts and never a provider-reported cost. Last-usage-wins: a stream that\n * emits several usage frames keeps the final one. Absent when the upstream\n * stream carried no usage (e.g. `stream_options.include_usage` unset).\n *\n * Kept as a loose record because the field set is provider-specific and\n * forward-extending; the recorder sanitizes it into the fixture\n * `response.usage` override shape before persisting.\n */\n usage?: Record<string, unknown>;\n /**\n * Function calls. An OpenAI Responses `function_call` item's `namespace` is\n * kept on its entry (internal {@link collapseOpenAISSEWithResponsesTools} only).\n */\n toolCalls?: ToolCall[];\n /**\n * OpenAI Responses custom tool calls (`custom_tool_call` items), in output\n * order (internal {@link collapseOpenAISSEWithResponsesTools} only). They are never part of `toolCalls`\n * or `blocks`.\n */\n customToolCalls?: CustomToolCall[];\n droppedChunks?: number;\n firstDroppedSample?: string;\n truncated?: boolean;\n audioB64?: string;\n audioMimeType?: string;\n /**\n * Set when harmony channel tokens were present in the accumulated content but\n * could NOT be parsed into a complete, valid harmony structure. The content\n * is preserved VERBATIM, so this is NOT transport loss — it is distinct from\n * `droppedChunks` / `truncated`, which are reserved for genuine transport loss\n * (malformed SSE/NDJSON frames, CRC mismatch). The caller surfaces this as a\n * dedicated warning rather than a dropped/truncated-chunk warning.\n */\n harmonyUnparsed?: true;\n /** Short human-readable note accompanying {@link harmonyUnparsed}. */\n harmonyNote?: string;\n /**\n * Ordered cross-channel block list, in STREAM order, populated ONLY when the\n * stream is \"interleaved\" — i.e. a tool-call delta appeared STRICTLY BEFORE\n * the first content delta, OR a content delta appeared AFTER any tool-call\n * delta. The flat `content` / `toolCalls` fields stay populated UNCHANGED for\n * replay back-compat and non-block consumers; `blocks` is purely additive\n * positional instrumentation the recorder consults to decide whether to\n * persist the ordered shape. Absent (undefined) for text-first, text-only,\n * and tool-only streams — i.e. anything NOT interleaved — so the recorder\n * keeps the legacy `{ content, toolCalls }` shape byte-identical.\n *\n * Each text block coalesces all contiguous content deltas between tool\n * atoms. Each tool block sits in the position where its FIRST delta arrived:\n * a function call becomes a `toolCall` block with the fully-assembled\n * name/arguments/id, and an OpenAI Responses custom call becomes a\n * `customToolCall` block with name/input/id, where `input` is kept verbatim.\n * Custom calls are left out of `blocks` (which, like `toolCalls`, describes\n * function calls and text only); see {@link CollapseResult.responsesBlocks}.\n */\n blocks?: FixtureBlock[];\n /**\n * OpenAI Responses only: the full ordered output (text, function calls and\n * custom calls) when the stream carried a custom call whose position the\n * `content` + `toolCalls` + `customToolCalls` shape cannot express (it is\n * interleaved with text, or comes before a function call).\n */\n responsesBlocks?: ResponsesFixtureBlock[];\n}\n\n// ---------------------------------------------------------------------------\n// Cross-channel block-order instrumentation (#274)\n// ---------------------------------------------------------------------------\n\n/**\n * Atom recorded during a collapse pass, in stream arrival order. A `text` atom\n * carries one content delta's text (contiguous text atoms are coalesced when\n * building blocks). A `toolCall` atom is a stable reference to a function-call\n * accumulator whose name/arguments/id are filled in across later deltas. A\n * `customToolCall` atom is a stable reference to a custom-call accumulator\n * whose name/input/id are filled in the same way. The `ref` is the SAME object stored in the collapser's `toolCallMap` (or pushed\n * to a flat `toolCalls` array), so block identity is reconciled with the flat\n * representation at finalize time — see {@link buildOrderedBlocks}.\n */\ntype OrderAtom =\n | { kind: \"text\"; text: string }\n | { kind: \"toolCall\"; ref: FunctionCallAcc }\n | { kind: \"customToolCall\"; ref: CustomCallAcc };\n\n/** Accumulator for a function call. `namespace` is set only by the Responses API. */\ninterface FunctionCallAcc {\n name: string;\n arguments: string;\n id?: string;\n namespace?: string;\n}\n\n/** Accumulator for an OpenAI Responses `custom_tool_call` (free-text `input`). */\ninterface CustomCallAcc {\n name: string;\n input: string;\n id?: string;\n namespace?: string;\n}\n\n/**\n * A tool-call accumulator in {@link collapseOpenAISSEWithResponsesTools}'s `toolCallMap`. The\n * Responses API puts function and custom calls in one `output_index` space, so\n * the map holds both kinds.\n */\ntype ToolCallAcc = ({ kind: \"function\" } & FunctionCallAcc) | ({ kind: \"custom\" } & CustomCallAcc);\n\n/** A Responses `namespace` field when it is a non-empty string, else undefined. */\nfunction responsesNamespace(item: Record<string, unknown>): string | undefined {\n return typeof item.namespace === \"string\" && item.namespace !== \"\" ? item.namespace : undefined;\n}\n\n/**\n * Normalize a tool call's accumulated `arguments` into valid JSON exactly like\n * the flat-`toolCalls` recorder path: an empty / whitespace-only / missing\n * value becomes `\"{}\"`, never `\"\"`. Mirrors `recorder.ts` `toToolCallArguments`\n * so a `blocks[].arguments` value is always parseable JSON and never disagrees\n * with the flat `toolCalls` entry for the same call.\n */\nfunction normalizeToolArguments(args: string | undefined): string {\n if (args === undefined || args.trim() === \"\") return \"{}\";\n return args;\n}\n\n/**\n * Build a finalized {@link FixtureBlock.toolCall} from a tool-call accumulator,\n * normalizing `arguments` so the block agrees byte-for-byte with the flat\n * `toolCalls` entry built from the SAME accumulator object.\n */\nfunction toToolCallBlock(ref: FunctionCallAcc): FixtureBlock & { type: \"toolCall\" } {\n return {\n type: \"toolCall\",\n name: ref.name,\n arguments: normalizeToolArguments(ref.arguments),\n ...(ref.id ? { id: ref.id } : {}),\n ...(ref.namespace ? { namespace: ref.namespace } : {}),\n };\n}\n\n/**\n * Build a `customToolCall` block from a custom-call accumulator. The `input` is\n * free text: it is kept as is, never normalized to `\"{}\"`.\n */\nfunction toCustomToolCallBlock(ref: CustomCallAcc): ResponsesFixtureBlock {\n return {\n type: \"customToolCall\",\n name: ref.name,\n input: ref.input,\n ...(ref.id ? { id: ref.id } : {}),\n ...(ref.namespace ? { namespace: ref.namespace } : {}),\n };\n}\n\n/** Project a function-call accumulator to a flat fixture tool call. */\nfunction toFunctionToolCall(ref: FunctionCallAcc): ToolCall {\n return {\n name: ref.name,\n arguments: normalizeToolArguments(ref.arguments),\n ...(ref.id ? { id: ref.id } : {}),\n ...(ref.namespace ? { namespace: ref.namespace } : {}),\n };\n}\n\n/** Project a custom-call accumulator to a flat fixture custom tool call. */\nfunction toCustomToolCall(ref: CustomCallAcc): CustomToolCall {\n return {\n type: \"custom\",\n name: ref.name,\n input: ref.input,\n ...(ref.id ? { id: ref.id } : {}),\n ...(ref.namespace ? { namespace: ref.namespace } : {}),\n };\n}\n\n/**\n * Decide whether a recorded atom sequence is \"interleaved\" and, if so, build\n * the ordered {@link FixtureBlock} list. Returns `undefined` when NOT\n * interleaved (text-first, text-only, or tool-only) so callers leave\n * `CollapseResult.blocks` unset and the recorder keeps the legacy shape.\n *\n * Interleaved ⇔ (a tool atom appears strictly before the first text atom) OR\n * (a text atom appears after any tool atom). Tool atoms are `toolCall` and\n * `customToolCall` atoms. A stream with no tool atoms, or\n * with no text atoms, is never interleaved. Text-first-then-tools is the common\n * legacy case and is explicitly NOT interleaved.\n *\n * CONSISTENCY (#274): each tool block is derived from the SAME accumulator\n * object referenced by its atom. Because the atom `ref` is the very object the\n * flat list is built from, the block and its flat counterpart describe the same\n * call by identity — even when upstream tool-call indices do not match\n * stream-arrival order. A `toolCall` block is normalized identically to the\n * flat `toolCalls` path ({@link toToolCallBlock} / {@link normalizeToolArguments}):\n * empty/missing arguments become `\"{}\"` in BOTH representations, never `\"\"`. A\n * `customToolCall` block ({@link toCustomToolCallBlock}) keeps `input` verbatim,\n * the same as the flat custom tool call ({@link toCustomToolCall}); it is never\n * normalized to `\"{}\"`.\n */\nfunction buildOrderedBlocks(atoms: OrderAtom[]): FixtureBlock[] | undefined {\n return orderedBlocksFrom(atoms.filter((a) => a.kind !== \"customToolCall\"))?.filter(\n (block): block is FixtureBlock => block.type !== \"customToolCall\",\n );\n}\n\n/**\n * {@link buildOrderedBlocks} over every atom, custom calls included, for\n * `CollapseResult.responsesBlocks`. With `force`, the blocks are built even\n * when text and tools are not interleaved.\n */\nfunction orderedBlocksFrom(atoms: OrderAtom[], force = false): ResponsesFixtureBlock[] | undefined {\n let firstTextIndex = -1;\n let firstToolIndex = -1;\n let textAfterTool = false;\n let sawTool = false;\n let sawText = false;\n for (let i = 0; i < atoms.length; i++) {\n const a = atoms[i];\n if (a.kind === \"text\") {\n sawText = true;\n if (firstTextIndex === -1) firstTextIndex = i;\n if (sawTool) textAfterTool = true;\n } else {\n sawTool = true;\n if (firstToolIndex === -1) firstToolIndex = i;\n }\n }\n // No cross-channel ordering to express unless BOTH channels appear.\n if (!force) {\n if (!sawTool || !sawText) return undefined;\n const toolBeforeText = firstToolIndex < firstTextIndex;\n if (!toolBeforeText && !textAfterTool) return undefined;\n }\n\n // Coalesce contiguous text atoms into one text block; emit each function-call\n // atom as a normalized toolCall block and each custom-call atom as a\n // customToolCall block with its input kept verbatim.\n const blocks: ResponsesFixtureBlock[] = [];\n let pendingText = \"\";\n let hasPendingText = false;\n const flushText = () => {\n if (hasPendingText) {\n blocks.push({ type: \"text\", text: pendingText });\n pendingText = \"\";\n hasPendingText = false;\n }\n };\n for (const a of atoms) {\n if (a.kind === \"text\") {\n pendingText += a.text;\n hasPendingText = true;\n } else {\n flushText();\n blocks.push(\n a.kind === \"customToolCall\" ? toCustomToolCallBlock(a.ref) : toToolCallBlock(a.ref),\n );\n }\n }\n flushText();\n return blocks;\n}\n\n/**\n * The opaque `data` of a non-empty Anthropic `redacted_thinking` block, or\n * `undefined` if `block` is not a redacted_thinking block or carries empty/no\n * data. NON-EMPTY is required: the replay-side validator rejects a leading\n * empty-data redacted_thinking block, so recording `data: \"\"` would yield a\n * fixture that 400s under strict replay. Shared by every capture site (SSE,\n * Anthropic-native binary, non-streaming recorder) so the rule stays in one\n * place.\n */\nexport function capturedRedactedData(\n block: Record<string, unknown> | undefined,\n): string | undefined {\n if (\n block?.type === \"redacted_thinking\" &&\n typeof block.data === \"string\" &&\n block.data.length > 0\n ) {\n return block.data;\n }\n return undefined;\n}\n\n/**\n * Slice the first `max` UTF-16 code units of `s` for a diagnostic sample,\n * trimming a trailing lone high-surrogate so the resulting sample never ends on\n * a lone high surrogate (i.e. never mid-surrogate-pair).\n */\nfunction surrogateSafeSlice(s: string, max: number): string {\n let out = s.slice(0, max);\n if (out.length > 0) {\n const last = out.charCodeAt(out.length - 1);\n // A high surrogate (U+D800..U+DBFF) at the end is the lead of a split pair.\n if (last >= 0xd800 && last <= 0xdbff) {\n out = out.slice(0, -1);\n }\n }\n return out;\n}\n\n/**\n * Split a raw SSE body into per-event blocks.\n *\n * Events are delimited by a blank line. Real HTTP/SSE transports use CRLF\n * (`\\r\\n`) line endings, so the inter-event delimiter is `\\r\\n\\r\\n` (which\n * contains no `\\n\\n` substring) and each line ends with a trailing `\\r`.\n * Splitting on `/\\r?\\n\\r?\\n/` handles LF, CRLF, and mixed streams; per-line\n * `\\r` trimming happens in {@link splitSSELines}. Blank blocks are dropped.\n */\nfunction splitSSEEvents(body: string): string[] {\n return body.split(/\\r?\\n\\r?\\n/).filter((block) => block.trim().length > 0);\n}\n\n/**\n * Split a single SSE event block into its lines, trimming a trailing `\\r` so\n * CRLF streams parse identically to LF streams.\n */\nfunction splitSSELines(block: string): string[] {\n return block.split(\"\\n\").map((line) => (line.endsWith(\"\\r\") ? line.slice(0, -1) : line));\n}\n\n/**\n * Extract the SSE `data` field from a single event block's lines.\n *\n * Per the SSE spec a single event may carry MULTIPLE `data:` lines; the field\n * value is every data line's content joined with \"\\n\". Collecting only the\n * first `data:` line (e.g. via `.find`) corrupts payloads that a server split\n * across lines. Callers MUST pass lines produced by {@link splitSSELines} so\n * any trailing `\\r` is already stripped. Returns the joined payload (with the\n * leading \"data:\" prefix and one optional leading space stripped per line), or\n * `undefined` when the block contains no `data:` line.\n */\nfunction extractSSEData(lines: string[]): string | undefined {\n const dataParts: string[] = [];\n for (const line of lines) {\n if (!line.startsWith(\"data:\")) continue;\n // Strip \"data:\" then a single optional leading space, per the SSE spec.\n let part = line.slice(5);\n if (part.startsWith(\" \")) part = part.slice(1);\n dataParts.push(part);\n }\n if (dataParts.length === 0) return undefined;\n return dataParts.join(\"\\n\");\n}\n\n// ---------------------------------------------------------------------------\n// 1. OpenAI SSE\n// ---------------------------------------------------------------------------\n\n/**\n * Collapse OpenAI Chat Completions SSE stream into a single response.\n *\n * Format:\n * data: {\"id\":\"chatcmpl-123\",\"choices\":[{\"delta\":{\"content\":\"Hello\"}}]}\\n\\n\n * data: [DONE]\\n\\n\n *\n * Public, with the 1.44.0 result: an OpenAI Responses `namespace` and custom\n * tool calls are dropped. The recorder uses {@link collapseOpenAISSEWithResponsesTools}.\n */\nexport function collapseOpenAISSE(rawBody: string): CollapseResult {\n return withoutResponsesToolFields(collapseOpenAISSEWithResponsesTools(rawBody));\n}\n\n/**\n * A collapse result as 1.44.0 returned and recorded it: no `namespace` on a\n * function call or `toolCall` block, and no custom tool calls.\n */\nexport function withoutResponsesToolFields(collapsed: CollapseResult): CollapseResult {\n if (\n collapsed.customToolCalls === undefined &&\n collapsed.responsesBlocks === undefined &&\n !collapsed.toolCalls?.some((tc) => tc.namespace !== undefined) &&\n !collapsed.blocks?.some((block) => block.type !== \"text\" && block.namespace !== undefined)\n ) {\n return collapsed;\n }\n const result: CollapseResult = { ...collapsed };\n delete result.customToolCalls;\n delete result.responsesBlocks;\n if (result.toolCalls) {\n result.toolCalls = result.toolCalls.map((tc) => {\n if (tc.namespace === undefined) return tc;\n const copy = { ...tc };\n delete copy.namespace;\n return copy;\n });\n }\n if (result.blocks) {\n result.blocks = result.blocks.map((block) => {\n if (block.type === \"text\" || block.namespace === undefined) return block;\n const copy = { ...block };\n delete copy.namespace;\n return copy;\n });\n }\n return result;\n}\n\n/**\n * @internal {@link collapseOpenAISSE} keeping an OpenAI Responses `namespace`\n * and custom tool calls, for the recorder with `responsesTools: \"extended\"`.\n */\nexport function collapseOpenAISSEWithResponsesTools(rawBody: string): CollapseResult {\n const inputTruncated = isCollapseInputTruncated(rawBody);\n const body = guardCollapseBody(rawBody);\n const lines = splitSSEEvents(body);\n let content = \"\";\n let transcript = \"\";\n let transcriptSeen = false;\n let transcriptLanguages: Array<{ code: string }> | undefined;\n let transcriptUsage: Record<string, unknown> | undefined;\n let reasoning = \"\";\n const webSearchQueries: string[] = [];\n // Provider-reported usage from the stream's final usage frame (#368).\n let usage: Record<string, unknown> | undefined;\n let droppedChunks = 0;\n let firstDroppedSample: string | undefined;\n let harmonyUnparsed = false;\n let harmonyNote: string | undefined;\n const toolCallMap = new Map<number, ToolCallAcc>();\n // Fallback keying for deltas that OMIT `index`. Without this, every\n // index-less delta collapses under one `undefined`/NaN key, merging distinct\n // tool calls and corrupting arguments. Index-less fragments that share an\n // `id` correlate via `idKeyMap`; otherwise each gets a fresh synthetic key\n // assigned from a counter kept above any real index so sort order is stable.\n // The 1_000_000 sentinel assumes real provider tool-call indices stay below\n // it (they are small per-stream counters), so synthetic keys never collide.\n let nextSyntheticIndex = 1_000_000;\n const idKeyMap = new Map<string, number>();\n // The key of the most-recently-opened tool call (real, id-correlated, or\n // synthetic). A delta that omits BOTH `index` and `id` carries no identity of\n // its own; without a fallback each such fragment would mint a fresh synthetic\n // key, splitting one call's arguments streamed across multiple bare deltas\n // into separate tool-call entries with no drop/truncation signal. Correlate\n // it to the last-open call instead (real OpenAI always streams `index`, so\n // this only affects the degenerate index-and-id-less case).\n let lastToolCallKey: number | undefined;\n // Cross-channel order atoms (#274), in stream arrival order. A toolCall atom\n // references the same accumulator object stored in toolCallMap, so later arg\n // deltas mutate the block in place.\n const orderAtoms: OrderAtom[] = [];\n\n for (const line of lines) {\n const data = extractSSEData(splitSSELines(line));\n if (data === undefined) continue;\n\n const payload = data.trim();\n if (payload === \"[DONE]\") continue;\n\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(payload) as Record<string, unknown>;\n } catch (err) {\n droppedChunks++;\n if (droppedChunks === 1) {\n const msg = err instanceof Error ? err.message : \"unknown\";\n firstDroppedSample = `parse failed (${msg}): ${surrogateSafeSlice(payload, 200)}`;\n }\n continue;\n }\n\n // Responses API reasoning events\n if (parsed.type === \"transcript.text.delta\" && typeof parsed.delta === \"string\") {\n transcript += parsed.delta;\n transcriptSeen = true;\n continue;\n }\n if (parsed.type === \"transcript.text.done\" && typeof parsed.text === \"string\") {\n transcript = parsed.text;\n transcriptSeen = true;\n if (Array.isArray(parsed.languages)) {\n transcriptLanguages = parsed.languages\n .filter(\n (language): language is Record<string, unknown> =>\n typeof language === \"object\" &&\n language !== null &&\n typeof language.code === \"string\",\n )\n .map((language) => ({ code: language.code as string }));\n }\n // Only capture a real usage OBJECT. `typeof === \"object\"` alone admits an\n // array (a type lie once cast to Record) and an empty `{}` (meaningless);\n // guard against both, exactly like any chat usage capture would.\n if (\n parsed.usage &&\n typeof parsed.usage === \"object\" &&\n !Array.isArray(parsed.usage) &&\n Object.keys(parsed.usage).length > 0\n ) {\n transcriptUsage = parsed.usage as Record<string, unknown>;\n }\n continue;\n }\n if (\n parsed.type === \"response.reasoning_summary_text.delta\" &&\n typeof parsed.delta === \"string\"\n ) {\n reasoning += parsed.delta;\n continue;\n }\n\n // Responses API web search + function-call completion events\n if (parsed.type === \"response.output_item.done\") {\n const item = parsed.item as Record<string, unknown> | undefined;\n if (item?.type === \"web_search_call\") {\n const action = item.action as Record<string, unknown> | undefined;\n if (action && typeof action.query === \"string\") {\n webSearchQueries.push(action.query);\n continue;\n }\n }\n if (item?.type === \"function_call\" && typeof parsed.output_index === \"number\") {\n // Finalize the accumulated tool call. Fill id/name/namespace when the\n // opening `.added` event lacked them, and adopt the full `arguments`\n // ONLY when the delta stream produced none — never re-append, since the\n // deltas already carry the complete string.\n const entry = toolCallMap.get(parsed.output_index);\n if (entry) {\n if (entry.kind === \"function\") {\n if (!entry.id && typeof item.call_id === \"string\") entry.id = item.call_id;\n if (!entry.name && typeof item.name === \"string\") entry.name = item.name;\n if (!entry.namespace) entry.namespace = responsesNamespace(item);\n if (entry.arguments === \"\" && typeof item.arguments === \"string\") {\n entry.arguments = item.arguments;\n }\n }\n } else {\n const created: ToolCallAcc = {\n kind: \"function\",\n id: typeof item.call_id === \"string\" ? item.call_id : \"\",\n name: typeof item.name === \"string\" ? item.name : \"\",\n arguments: typeof item.arguments === \"string\" ? item.arguments : \"\",\n namespace: responsesNamespace(item),\n };\n toolCallMap.set(parsed.output_index, created);\n orderAtoms.push({ kind: \"toolCall\", ref: created });\n }\n continue;\n }\n if (item?.type === \"custom_tool_call\" && typeof parsed.output_index === \"number\") {\n // Same rules as a function call, for the free-text `input`.\n const entry = toolCallMap.get(parsed.output_index);\n if (entry) {\n if (entry.kind === \"custom\") {\n if (!entry.id && typeof item.call_id === \"string\") entry.id = item.call_id;\n if (!entry.name && typeof item.name === \"string\") entry.name = item.name;\n if (!entry.namespace) entry.namespace = responsesNamespace(item);\n if (entry.input === \"\" && typeof item.input === \"string\") entry.input = item.input;\n }\n } else {\n const created: ToolCallAcc = {\n kind: \"custom\",\n id: typeof item.call_id === \"string\" ? item.call_id : \"\",\n name: typeof item.name === \"string\" ? item.name : \"\",\n input: typeof item.input === \"string\" ? item.input : \"\",\n namespace: responsesNamespace(item),\n };\n toolCallMap.set(parsed.output_index, created);\n orderAtoms.push({ kind: \"customToolCall\", ref: created });\n }\n continue;\n }\n }\n\n // Responses API function-call streaming events. A tool call arrives as\n // `response.output_item.added` (a `function_call` item) → one or more\n // `response.function_call_arguments.delta` → `response.function_call_arguments.done`\n // (plus the closing `response.output_item.done` handled above). Mirror the\n // Chat-Completions tool-call accumulation below so a tool-call-only turn\n // collapses to `toolCalls` instead of being silently dropped by the\n // `response.*` catch-all. Key by `output_index` (present on every one of\n // these events); its integer space is disjoint from the Chat-Completions\n // `tool_calls[].index` space because a single stream is never both shapes.\n if (parsed.type === \"response.output_item.added\") {\n const item = parsed.item as Record<string, unknown> | undefined;\n if (item?.type === \"function_call\" && typeof parsed.output_index === \"number\") {\n if (!toolCallMap.has(parsed.output_index)) {\n const created: ToolCallAcc = {\n kind: \"function\",\n // The Responses API `call_id` is what a tool result references, so\n // capture THAT (not the internal `fc_…` item id) as the tool-call\n // id — matching what the replay path treats as `toolCall.id`.\n id: typeof item.call_id === \"string\" ? item.call_id : \"\",\n name: typeof item.name === \"string\" ? item.name : \"\",\n arguments: \"\",\n namespace: responsesNamespace(item),\n };\n toolCallMap.set(parsed.output_index, created);\n orderAtoms.push({ kind: \"toolCall\", ref: created });\n }\n continue;\n }\n // A custom (freeform) tool call: `output_item.added` (custom_tool_call)\n // → `custom_tool_call_input.delta`* → `custom_tool_call_input.done` →\n // `output_item.done`. It shares the function calls' `output_index` space.\n if (item?.type === \"custom_tool_call\" && typeof parsed.output_index === \"number\") {\n if (!toolCallMap.has(parsed.output_index)) {\n const created: ToolCallAcc = {\n kind: \"custom\",\n id: typeof item.call_id === \"string\" ? item.call_id : \"\",\n name: typeof item.name === \"string\" ? item.name : \"\",\n input: \"\",\n namespace: responsesNamespace(item),\n };\n toolCallMap.set(parsed.output_index, created);\n orderAtoms.push({ kind: \"customToolCall\", ref: created });\n }\n continue;\n }\n }\n if (\n parsed.type === \"response.custom_tool_call_input.delta\" &&\n typeof parsed.delta === \"string\" &&\n typeof parsed.output_index === \"number\"\n ) {\n let entry = toolCallMap.get(parsed.output_index);\n if (!entry) {\n entry = { kind: \"custom\", id: \"\", name: \"\", input: \"\" };\n toolCallMap.set(parsed.output_index, entry);\n orderAtoms.push({ kind: \"customToolCall\", ref: entry });\n }\n if (entry.kind === \"custom\") {\n entry.input += parsed.delta;\n }\n continue;\n }\n if (\n parsed.type === \"response.custom_tool_call_input.done\" &&\n typeof parsed.output_index === \"number\"\n ) {\n // Adopt the full `input` only when the deltas produced none.\n const entry = toolCallMap.get(parsed.output_index);\n if (entry) {\n if (entry.kind === \"custom\" && entry.input === \"\" && typeof parsed.input === \"string\") {\n entry.input = parsed.input;\n }\n } else if (typeof parsed.input === \"string\") {\n const created: ToolCallAcc = { kind: \"custom\", id: \"\", name: \"\", input: parsed.input };\n toolCallMap.set(parsed.output_index, created);\n orderAtoms.push({ kind: \"customToolCall\", ref: created });\n }\n continue;\n }\n if (\n parsed.type === \"response.function_call_arguments.delta\" &&\n typeof parsed.delta === \"string\" &&\n typeof parsed.output_index === \"number\"\n ) {\n let entry = toolCallMap.get(parsed.output_index);\n if (!entry) {\n entry = { kind: \"function\", id: \"\", name: \"\", arguments: \"\" };\n toolCallMap.set(parsed.output_index, entry);\n orderAtoms.push({ kind: \"toolCall\", ref: entry });\n }\n if (entry.kind === \"function\") entry.arguments += parsed.delta;\n continue;\n }\n if (\n parsed.type === \"response.function_call_arguments.done\" &&\n typeof parsed.output_index === \"number\"\n ) {\n // The `.done` event repeats the fully-assembled `arguments`; adopt it only\n // when the deltas produced nothing (a delta-less stream) so we never\n // double-append.\n const entry = toolCallMap.get(parsed.output_index);\n if (entry) {\n if (\n entry.kind === \"function\" &&\n entry.arguments === \"\" &&\n typeof parsed.arguments === \"string\"\n ) {\n entry.arguments = parsed.arguments;\n }\n } else if (typeof parsed.arguments === \"string\") {\n const created: ToolCallAcc = {\n kind: \"function\",\n id: \"\",\n name: \"\",\n arguments: parsed.arguments,\n };\n toolCallMap.set(parsed.output_index, created);\n orderAtoms.push({ kind: \"toolCall\", ref: created });\n }\n continue;\n }\n\n // Responses API text content events\n if (parsed.type === \"response.output_text.delta\" && typeof parsed.delta === \"string\") {\n content += parsed.delta;\n if (parsed.delta.length > 0) {\n orderAtoms.push({ kind: \"text\", text: parsed.delta });\n }\n continue;\n }\n\n // Skip other Responses API structural events\n if (typeof parsed.type === \"string\" && parsed.type.startsWith(\"response.\")) {\n continue;\n }\n\n // Final usage frame (#368). OpenAI-compatible providers close an\n // include_usage stream with a `chat.completion.chunk` carrying EMPTY\n // `choices` and a populated `usage` — the only frame with the real token\n // counts, and on OpenRouter the only one with `cost`. Capture it BEFORE the\n // empty-`choices` guard below, which would otherwise skip the frame\n // entirely. Some providers also attach `usage` to the finish chunk (non-empty\n // choices), so this runs for every chat chunk, last-NON-EMPTY-usage-wins:\n // a trailing bare `usage: {}` frame must not clobber a good capture (#369).\n if (\n parsed.usage &&\n typeof parsed.usage === \"object\" &&\n !Array.isArray(parsed.usage) &&\n Object.keys(parsed.usage).length > 0\n ) {\n usage = parsed.usage as Record<string, unknown>;\n }\n\n const choices = parsed.choices as Array<Record<string, unknown>> | undefined;\n if (!choices || choices.length === 0) continue;\n\n const delta = choices[0].delta as Record<string, unknown> | undefined;\n if (!delta) continue;\n\n // Reasoning content (OpenRouter / chat completions format)\n if (typeof delta.reasoning_content === \"string\") {\n reasoning += delta.reasoning_content;\n }\n\n // Text content\n if (typeof delta.content === \"string\") {\n content += delta.content;\n if (delta.content.length > 0) {\n orderAtoms.push({ kind: \"text\", text: delta.content });\n }\n }\n\n // Tool calls\n const toolCalls = delta.tool_calls as Array<Record<string, unknown>> | undefined;\n if (toolCalls) {\n for (const tc of toolCalls) {\n const fn = tc.function as Record<string, unknown> | undefined;\n const rawId = typeof tc.id === \"string\" ? tc.id : undefined;\n\n // Resolve a stable map key. Prefer the streamed `index`; when it is\n // absent, correlate by `id` if present, else mint a fresh synthetic\n // key so distinct index-less calls never merge.\n let index: number;\n if (typeof tc.index === \"number\") {\n index = tc.index;\n } else if (rawId !== undefined) {\n const existing = idKeyMap.get(rawId);\n if (existing !== undefined) {\n index = existing;\n } else {\n index = nextSyntheticIndex++;\n idKeyMap.set(rawId, index);\n }\n } else if (lastToolCallKey !== undefined) {\n // No `index` AND no `id`: correlate to the last-open tool call so a\n // call's arguments streamed across multiple bare deltas concatenate\n // into one entry instead of fragmenting under fresh synthetic keys.\n index = lastToolCallKey;\n } else {\n index = nextSyntheticIndex++;\n }\n // Remember this key so a following index-and-id-less delta correlates\n // to whichever call most recently opened.\n lastToolCallKey = index;\n\n if (!toolCallMap.has(index)) {\n const created: ToolCallAcc = {\n kind: \"function\",\n id: rawId ?? \"\",\n name: (fn?.name as string) ?? \"\",\n arguments: \"\",\n };\n toolCallMap.set(index, created);\n // Record the tool atom at the position its FIRST delta arrived; it\n // references `created` so later name/arg deltas fill it in place.\n orderAtoms.push({ kind: \"toolCall\", ref: created });\n }\n\n const entry = toolCallMap.get(index)!;\n if (fn?.name && typeof fn.name === \"string\" && !entry.name) {\n entry.name = fn.name;\n }\n if (tc.id && typeof tc.id === \"string\" && !entry.id) {\n entry.id = tc.id;\n }\n if (entry.kind === \"function\" && fn?.arguments && typeof fn.arguments === \"string\") {\n entry.arguments += fn.arguments;\n }\n }\n }\n }\n\n // Open-weight gpt-oss models (Ollama / vLLM / OpenRouter) stream tool calls\n // as raw harmony channel tokens inside delta.content rather than structured\n // delta.tool_calls. Harmony parsing is FALLBACK-ONLY: attempt it ONLY when\n // there are NO structured delta.tool_calls. If structured tool calls exist,\n // any harmony-looking content is prose — never merged (no phantom tool call),\n // never stamped as truncated/dropped. When harmony IS the only source, a\n // successful parse routes channels (content/reasoning/toolCalls); a failure\n // preserves content VERBATIM and surfaces the distinct `harmonyUnparsed`\n // signal (NOT droppedChunks/truncated — the bytes are not lost).\n const harmonyToolCalls: ToolCall[] = [];\n // Custom tool calls do not count as structured calls here, as before they\n // were collapsed at all.\n const hasFunctionCalls = Array.from(toolCallMap.values()).some((tc) => tc.kind === \"function\");\n if (!hasFunctionCalls && isHarmonyContent(content)) {\n const parsed = parseHarmonyContent(content);\n if (parsed.failed) {\n harmonyUnparsed = true;\n harmonyNote = `harmony tokens present but unparseable; content preserved verbatim: ${surrogateSafeSlice(content, 200)}`;\n } else {\n content = parsed.content;\n if (parsed.reasoning) {\n reasoning += parsed.reasoning;\n }\n harmonyToolCalls.push(...parsed.toolCalls);\n }\n }\n\n // OpenAI Responses custom tool calls ride in their own fields, so\n // `toolCalls` and `blocks` describe exactly what earlier releases recorded\n // (function calls and text). `responsesBlocks` keeps the full order when the\n // flat fields cannot: a custom call interleaved with text, or placed before\n // a function call.\n const sortedEntries = Array.from(toolCallMap.entries()).sort(([a], [b]) => a - b);\n const customEntries = sortedEntries.flatMap(([, tc]) => (tc.kind === \"custom\" ? [tc] : []));\n const functionEntries = sortedEntries.flatMap(([, tc]) => (tc.kind === \"function\" ? [tc] : []));\n let customFields: Pick<CollapseResult, \"customToolCalls\" | \"responsesBlocks\"> = {};\n if (customEntries.length > 0) {\n const firstCustomAtom = orderAtoms.findIndex((a) => a.kind === \"customToolCall\");\n const customBeforeFunction = orderAtoms.some(\n (a, i) => a.kind === \"toolCall\" && i > firstCustomAtom,\n );\n const responsesBlocks = orderedBlocksFrom(orderAtoms, customBeforeFunction);\n customFields = {\n customToolCalls: responsesBlocks\n ? orderAtoms.flatMap((a) => (a.kind === \"customToolCall\" ? [toCustomToolCall(a.ref)] : []))\n : customEntries.map(toCustomToolCall),\n ...(responsesBlocks ? { responsesBlocks } : {}),\n };\n }\n\n if (functionEntries.length > 0 || harmonyToolCalls.length > 0) {\n const blocks = buildOrderedBlocks(orderAtoms);\n // When the stream is interleaved we persist ordered `blocks`; the flat\n // `toolCalls` MUST then describe the same calls in the same order so the two\n // representations never disagree (#274). The toolCall atoms reference the\n // same accumulator objects as `toolCallMap`, so derive the flat list from\n // those atoms (stream-arrival order, matching blocks) when blocks exist;\n // otherwise keep the legacy index-sorted order for byte-identical fixtures.\n // `namespace` is kept on a Responses function call.\n const orderedToolCalls = orderAtoms.flatMap((a) =>\n a.kind === \"toolCall\" ? [toFunctionToolCall(a.ref)] : [],\n );\n const indexSortedToolCalls = functionEntries.map(toFunctionToolCall);\n return {\n ...(transcriptSeen\n ? {\n transcription: {\n text: transcript,\n ...(transcriptLanguages ? { languages: transcriptLanguages } : {}),\n ...(transcriptUsage ? { usage: transcriptUsage } : {}),\n },\n }\n : {}),\n ...(blocks ? { blocks } : {}),\n ...(content ? { content } : {}),\n // Fallback-only: harmonyToolCalls are populated ONLY in the\n // no-structured-calls branch, so this is never a merge of both sources.\n toolCalls: [...(blocks ? orderedToolCalls : indexSortedToolCalls), ...harmonyToolCalls],\n ...customFields,\n // Reasoning is preserved alongside tool calls for ALL structured streams\n // (DeepSeek/OpenRouter reasoning_content, harmony analysis channel), at\n // parity with every other collapser and the non-streaming path.\n ...(reasoning ? { reasoning } : {}),\n // webSearches parity with the text-only return branch.\n ...(webSearchQueries.length > 0 ? { webSearches: webSearchQueries } : {}),\n // Provider-reported usage parity with the text-only return branch (#368).\n ...(usage ? { usage } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n ...(harmonyUnparsed ? { harmonyUnparsed: true } : {}),\n ...(harmonyNote ? { harmonyNote } : {}),\n ...(inputTruncated ? { truncated: true } : {}),\n };\n }\n\n return {\n ...(transcriptSeen\n ? {\n transcription: {\n text: transcript,\n ...(transcriptLanguages ? { languages: transcriptLanguages } : {}),\n ...(transcriptUsage ? { usage: transcriptUsage } : {}),\n },\n }\n : {}),\n content,\n ...customFields,\n ...(reasoning ? { reasoning } : {}),\n ...(webSearchQueries.length > 0 ? { webSearches: webSearchQueries } : {}),\n ...(usage ? { usage } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n ...(harmonyUnparsed ? { harmonyUnparsed: true } : {}),\n ...(harmonyNote ? { harmonyNote } : {}),\n ...(inputTruncated ? { truncated: true } : {}),\n };\n}\n\n// ---------------------------------------------------------------------------\n// 2. Anthropic SSE\n// ---------------------------------------------------------------------------\n\n/**\n * Collapse Anthropic Claude Messages SSE stream into a single response.\n *\n * Format:\n * event: message_start\\ndata: {...}\\n\\n\n * event: content_block_delta\\ndata: {\"delta\":{\"type\":\"text_delta\",\"text\":\"Hello\"}}\\n\\n\n */\nexport function collapseAnthropicSSE(rawBody: string): CollapseResult {\n const inputTruncated = isCollapseInputTruncated(rawBody);\n const body = guardCollapseBody(rawBody);\n const blocks = splitSSEEvents(body);\n let content = \"\";\n let reasoning = \"\";\n // Real cryptographic signature captured from a `signature_delta`; stays\n // undefined when the stream carried none (e.g. aimock's own placeholder turns\n // or non-thinking turns). Carried so a recorded real-provider thinking turn\n // can replay its ACTUAL signature instead of aimock's placeholder.\n let reasoningSignature: string | undefined;\n // Opaque `data` payloads of any `redacted_thinking` content blocks, in stream\n // order. Stays empty when none present. Carried so a recorded redacted-thinking\n // turn round-trips its encrypted reasoning faithfully on replay.\n const redactedThinking: string[] = [];\n let droppedChunks = 0;\n let firstDroppedSample: string | undefined;\n const toolCallMap = new Map<number, { id: string; name: string; arguments: string }>();\n // Fallback keying for content blocks that OMIT `index` (mirrors the OpenAI /\n // Cohere / Bedrock guards). Without it, every index-less block collapses\n // under one `undefined` key, merging distinct tool_use blocks. Index-less\n // starts mint a fresh synthetic key (kept above any real index so sort order\n // is stable). Despite its name, `lastSyntheticIndex` tracks whichever\n // tool_use start most recently opened REGARDLESS of whether its index was\n // real or synthetic (it is set on every tool_use start; thinking /\n // redacted_thinking starts do not touch it), so an index-less delta\n // correlates to the most-recent tool_use start — not just to the last\n // synthetic one. The 1_000_000 sentinel assumes real provider indices stay\n // below it.\n let nextSyntheticIndex = 1_000_000;\n let lastSyntheticIndex: number | undefined;\n // Cross-channel order atoms (#274), in stream arrival order.\n const orderAtoms: OrderAtom[] = [];\n\n for (const block of blocks) {\n const lines = splitSSELines(block);\n const eventLine = lines.find((l) => l.startsWith(\"event:\"));\n const data = extractSSEData(lines);\n if (data === undefined) continue;\n\n const eventType = eventLine ? eventLine.slice(6).trim() : \"\";\n const payload = data.trim();\n\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(payload) as Record<string, unknown>;\n } catch (err) {\n droppedChunks++;\n if (droppedChunks === 1) {\n const msg = err instanceof Error ? err.message : \"unknown\";\n firstDroppedSample = `parse failed (${msg}): ${surrogateSafeSlice(payload, 200)}`;\n }\n continue;\n }\n\n if (eventType === \"content_block_start\") {\n const contentBlock = parsed.content_block as Record<string, unknown> | undefined;\n // A `redacted_thinking` block carries its encrypted reasoning in an opaque\n // `data` string on the start event (no deltas follow). Capture it so the\n // recorded turn can replay the redacted block faithfully\n // (see capturedRedactedData for the non-empty rule).\n const redactedData = capturedRedactedData(contentBlock);\n if (redactedData !== undefined) {\n redactedThinking.push(redactedData);\n }\n if (contentBlock?.type === \"tool_use\") {\n // Prefer the streamed `index`; when absent, mint a fresh synthetic key\n // so distinct index-less tool_use blocks never merge.\n let index: number;\n if (typeof parsed.index === \"number\") {\n index = parsed.index;\n } else {\n index = nextSyntheticIndex++;\n }\n lastSyntheticIndex = index;\n const created = {\n id: (contentBlock.id as string) ?? \"\",\n name: (contentBlock.name as string) ?? \"\",\n arguments: \"\",\n };\n toolCallMap.set(index, created);\n // Record the tool atom at the position the tool_use block opened; it\n // references `created` so later input_json_delta fragments fill it in.\n orderAtoms.push({ kind: \"toolCall\", ref: created });\n }\n }\n\n if (eventType === \"content_block_delta\") {\n const delta = parsed.delta as Record<string, unknown> | undefined;\n if (!delta) continue;\n\n if (delta.type === \"text_delta\" && typeof delta.text === \"string\") {\n content += delta.text;\n if (delta.text.length > 0) {\n orderAtoms.push({ kind: \"text\", text: delta.text });\n }\n }\n\n if (delta.type === \"thinking_delta\" && typeof delta.thinking === \"string\") {\n reasoning += delta.thinking;\n }\n\n // The real cryptographic signature arrives via a trailing\n // `signature_delta` (the `content_block_start` carried \"\"). Capture the\n // last one seen so a recorded thinking turn replays its actual signature.\n // Last-signature-wins: a turn with MULTIPLE thinking blocks overwrites this\n // on each block, so the merged `reasoning` string ends up bound only to the\n // FINAL block's signature — per-block signatures are not preserved.\n if (delta.type === \"signature_delta\" && typeof delta.signature === \"string\") {\n reasoningSignature = delta.signature;\n }\n\n if (delta.type === \"input_json_delta\" && typeof delta.partial_json === \"string\") {\n // Use the streamed `index` when present; otherwise correlate to the\n // most recent tool_use start (mirrors the start-side fallback).\n const index = typeof parsed.index === \"number\" ? parsed.index : lastSyntheticIndex;\n // A delta that cannot correlate to any known start (no streamed index\n // AND no prior start, or a stale index with no entry) would otherwise\n // silently lose its args. Account for it as a dropped chunk instead of\n // vanishing (mirrors the Cohere uncorrelated-delta path).\n const entry = index !== undefined ? toolCallMap.get(index) : undefined;\n if (entry) {\n entry.arguments += delta.partial_json;\n } else {\n droppedChunks++;\n if (droppedChunks === 1) {\n firstDroppedSample = `input_json_delta with no correlating tool_use start: ${surrogateSafeSlice(\n payload,\n 200,\n )}`;\n }\n }\n }\n }\n }\n\n if (toolCallMap.size > 0) {\n const orderedBlocks = buildOrderedBlocks(orderAtoms);\n // When interleaved (`blocks` present) the flat `toolCalls` MUST match the\n // blocks' order/identity (#274). The toolCall atoms reference the same\n // accumulator objects as `toolCallMap`, so derive the flat list from those\n // atoms (stream-arrival order) when blocks exist; otherwise keep the legacy\n // index-sorted order for byte-identical fixtures.\n const orderedToolCalls = orderAtoms\n .filter(\n (a): a is { kind: \"toolCall\"; ref: { name: string; arguments: string; id?: string } } =>\n a.kind === \"toolCall\",\n )\n .map((a) => ({\n name: a.ref.name,\n arguments: normalizeToolArguments(a.ref.arguments),\n ...(a.ref.id ? { id: a.ref.id } : {}),\n }));\n const indexSortedToolCalls = Array.from(toolCallMap.entries())\n .sort(([a], [b]) => a - b)\n .map(([, tc]) => ({\n name: tc.name,\n arguments: normalizeToolArguments(tc.arguments),\n ...(tc.id ? { id: tc.id } : {}),\n }));\n return {\n ...(orderedBlocks ? { blocks: orderedBlocks } : {}),\n ...(content ? { content } : {}),\n toolCalls: orderedBlocks ? orderedToolCalls : indexSortedToolCalls,\n ...(reasoning ? { reasoning } : {}),\n ...(reasoningSignature ? { reasoningSignature } : {}),\n ...(redactedThinking.length > 0 ? { redactedThinking } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n ...(inputTruncated ? { truncated: true } : {}),\n };\n }\n\n return {\n content,\n ...(reasoning ? { reasoning } : {}),\n ...(reasoningSignature ? { reasoningSignature } : {}),\n ...(redactedThinking.length > 0 ? { redactedThinking } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n ...(inputTruncated ? { truncated: true } : {}),\n };\n}\n\n// ---------------------------------------------------------------------------\n// 3. Gemini SSE\n// ---------------------------------------------------------------------------\n\n/**\n * Collapse Gemini SSE stream into a single response.\n *\n * Format (data-only, no event prefix, no [DONE]):\n * data: {\"candidates\":[{\"content\":{\"parts\":[{\"text\":\"Hello\"}]}}]}\\n\\n\n */\nexport function collapseGeminiSSE(rawBody: string): CollapseResult {\n const inputTruncated = isCollapseInputTruncated(rawBody);\n const body = guardCollapseBody(rawBody);\n const lines = splitSSEEvents(body);\n let content = \"\";\n let reasoning = \"\";\n let droppedChunks = 0;\n let firstDroppedSample: string | undefined;\n let audioB64 = \"\";\n let audioMimeType: string | undefined;\n const toolCalls: ToolCall[] = [];\n // Cross-channel order atoms (#274), in stream arrival order.\n const orderAtoms: OrderAtom[] = [];\n\n for (const line of lines) {\n const data = extractSSEData(splitSSELines(line));\n if (data === undefined) continue;\n\n const payload = data.trim();\n\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(payload) as Record<string, unknown>;\n } catch (err) {\n droppedChunks++;\n if (droppedChunks === 1) {\n const msg = err instanceof Error ? err.message : \"unknown\";\n firstDroppedSample = `parse failed (${msg}): ${surrogateSafeSlice(payload, 200)}`;\n }\n continue;\n }\n\n const candidates = parsed.candidates as Array<Record<string, unknown>> | undefined;\n if (!candidates || candidates.length === 0) continue;\n\n const candidateContent = candidates[0].content as Record<string, unknown> | undefined;\n if (!candidateContent) continue;\n\n const parts = candidateContent.parts as Array<Record<string, unknown>> | undefined;\n if (!parts || parts.length === 0) continue;\n\n for (const part of parts) {\n if (part.functionCall) {\n const fc = part.functionCall as Record<string, unknown>;\n const created: ToolCall = {\n name: String(fc.name ?? \"\"),\n // Default undefined/object args to a JSON object string (matches\n // collapseGeminiInteractionsSSE / Ollama). JSON.stringify(undefined)\n // would otherwise yield the VALUE undefined, violating the\n // ToolCall.arguments:string contract.\n arguments:\n typeof fc.args === \"string\" ? (fc.args as string) : JSON.stringify(fc.args ?? {}),\n };\n toolCalls.push(created);\n // Record the tool atom at the position this functionCall part arrived.\n orderAtoms.push({ kind: \"toolCall\", ref: created });\n } else if (\n part.inlineData &&\n typeof (part.inlineData as Record<string, unknown>).mimeType === \"string\" &&\n ((part.inlineData as Record<string, unknown>).mimeType as string).startsWith(\"audio/\")\n ) {\n const inlineData = part.inlineData as Record<string, unknown>;\n if (!audioMimeType) {\n audioMimeType = inlineData.mimeType as string;\n }\n if (typeof inlineData.data === \"string\") {\n audioB64 += inlineData.data;\n }\n } else if (typeof part.text === \"string\") {\n if (part.thought) {\n reasoning += part.text;\n } else {\n content += part.text;\n if (part.text.length > 0) {\n orderAtoms.push({ kind: \"text\", text: part.text });\n }\n }\n }\n }\n }\n\n // Normalize the flat tool calls' arguments identically to the block path so\n // the two representations never disagree (#274). The toolCall atoms reference\n // the same `created` objects pushed here, so blocks and flat describe the same\n // calls in the same order; this only reconciles empty/missing → \"{}\".\n const normalizedToolCalls = toolCalls.map((tc) => ({\n ...tc,\n arguments: normalizeToolArguments(tc.arguments),\n }));\n\n if (audioB64) {\n // Preserve any content / reasoning / tool calls accumulated in the same\n // stream — a Gemini turn can interleave audio with text and functionCall\n // parts, and the early return must not silently drop them.\n //\n // Deliberately do NOT build ordered `blocks` here (#274, R2-N2): the audio\n // collapse shape maps to AudioResponse, which has no `blocks` slot, and the\n // recorder's audio branch never persists `collapsed.blocks`. Producing block\n // ordering on this path would be silently produced-then-dropped, advertising\n // a field this result shape can't carry. Block ordering is built only on the\n // content+toolCalls path below, which can actually carry it.\n return {\n audioB64,\n audioMimeType,\n ...(content ? { content } : {}),\n ...(reasoning ? { reasoning } : {}),\n ...(normalizedToolCalls.length > 0 ? { toolCalls: normalizedToolCalls } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n ...(inputTruncated ? { truncated: true } : {}),\n };\n }\n\n if (toolCalls.length > 0) {\n const blocks = buildOrderedBlocks(orderAtoms);\n return {\n ...(blocks ? { blocks } : {}),\n ...(content ? { content } : {}),\n toolCalls: normalizedToolCalls,\n ...(reasoning ? { reasoning } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n ...(inputTruncated ? { truncated: true } : {}),\n };\n }\n\n return {\n content,\n ...(reasoning ? { reasoning } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n ...(inputTruncated ? { truncated: true } : {}),\n };\n}\n\n// ---------------------------------------------------------------------------\n// 4. Ollama NDJSON\n// ---------------------------------------------------------------------------\n\n/**\n * Collapse Ollama NDJSON stream into a single response.\n *\n * /api/chat format:\n * {\"model\":\"llama3\",\"message\":{\"role\":\"assistant\",\"content\":\"Hello\"},\"done\":false}\\n\n *\n * /api/generate format:\n * {\"model\":\"llama3\",\"response\":\"Hello\",\"done\":false}\\n\n *\n * Open-weight gpt-oss served via Ollama streams harmony channel tokens inside\n * `message.content` (just like the OpenAI SSE path), so after accumulation the\n * content is run through the same fail-safe {@link parseHarmonyContent} gate to\n * capture structured tool calls / reasoning instead of leaking raw tokens.\n */\nexport function collapseOllamaNDJSON(rawBody: string): CollapseResult {\n const inputTruncated = isCollapseInputTruncated(rawBody);\n const body = guardCollapseBody(rawBody);\n const lines = body.split(\"\\n\").filter((l) => l.trim().length > 0);\n let content = \"\";\n let reasoning = \"\";\n let droppedChunks = 0;\n let firstDroppedSample: string | undefined;\n let harmonyUnparsed = false;\n let harmonyNote: string | undefined;\n const toolCalls: ToolCall[] = [];\n // Cross-channel order atoms (#274), in stream arrival order.\n const orderAtoms: OrderAtom[] = [];\n\n for (const line of lines) {\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(line.trim()) as Record<string, unknown>;\n } catch (err) {\n droppedChunks++;\n if (droppedChunks === 1) {\n const msg = err instanceof Error ? err.message : \"unknown\";\n firstDroppedSample = `parse failed (${msg}): ${surrogateSafeSlice(line.trim(), 200)}`;\n }\n continue;\n }\n\n // /api/chat format\n const message = parsed.message as Record<string, unknown> | undefined;\n if (message) {\n if (typeof message.content === \"string\") {\n content += message.content;\n if (message.content.length > 0) {\n orderAtoms.push({ kind: \"text\", text: message.content });\n }\n }\n\n // Tool calls\n if (Array.isArray(message.tool_calls)) {\n for (const tc of message.tool_calls as Array<Record<string, unknown>>) {\n const fn = tc.function as Record<string, unknown> | undefined;\n if (fn) {\n const created: ToolCall = {\n name: String(fn.name ?? \"\"),\n // Default undefined/object args to a JSON object (matching\n // collapseGeminiInteractionsSSE) — JSON.stringify(undefined)\n // would otherwise yield the literal string \"undefined\".\n arguments:\n typeof fn.arguments === \"string\"\n ? fn.arguments\n : JSON.stringify(fn.arguments ?? {}),\n };\n toolCalls.push(created);\n orderAtoms.push({ kind: \"toolCall\", ref: created });\n }\n }\n }\n }\n\n // /api/generate format\n else if (typeof parsed.response === \"string\") {\n content += parsed.response;\n if (parsed.response.length > 0) {\n orderAtoms.push({ kind: \"text\", text: parsed.response });\n }\n }\n }\n\n // Open-weight gpt-oss served via Ollama streams harmony channel tokens inside\n // message.content (same as the OpenAI SSE path). Harmony parsing is\n // FALLBACK-ONLY: attempt it ONLY when there are NO structured message\n // tool_calls. If structured tool calls exist, harmony-looking content is\n // prose — never merged (no phantom), never stamped truncated/dropped. On a\n // harmony failure the content is preserved VERBATIM and surfaced via the\n // distinct `harmonyUnparsed` signal (NOT droppedChunks/truncated).\n if (toolCalls.length === 0 && isHarmonyContent(content)) {\n const parsedHarmony = parseHarmonyContent(content);\n if (parsedHarmony.failed) {\n harmonyUnparsed = true;\n harmonyNote = `harmony tokens present but unparseable; content preserved verbatim: ${surrogateSafeSlice(content, 200)}`;\n } else {\n content = parsedHarmony.content;\n if (parsedHarmony.reasoning) {\n reasoning += parsedHarmony.reasoning;\n }\n toolCalls.push(...parsedHarmony.toolCalls);\n }\n }\n\n if (toolCalls.length > 0) {\n const blocks = buildOrderedBlocks(orderAtoms);\n // Normalize flat arguments identically to the block path so the two\n // representations never disagree (#274); same `created` refs, same order.\n const normalizedToolCalls = toolCalls.map((tc) => ({\n ...tc,\n arguments: normalizeToolArguments(tc.arguments),\n }));\n return {\n ...(blocks ? { blocks } : {}),\n ...(content ? { content } : {}),\n toolCalls: normalizedToolCalls,\n ...(reasoning ? { reasoning } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n ...(harmonyUnparsed ? { harmonyUnparsed: true } : {}),\n ...(harmonyNote ? { harmonyNote } : {}),\n ...(inputTruncated ? { truncated: true } : {}),\n };\n }\n\n return {\n content,\n ...(reasoning ? { reasoning } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n ...(harmonyUnparsed ? { harmonyUnparsed: true } : {}),\n ...(harmonyNote ? { harmonyNote } : {}),\n ...(inputTruncated ? { truncated: true } : {}),\n };\n}\n\n// ---------------------------------------------------------------------------\n// 5. Cohere SSE\n// ---------------------------------------------------------------------------\n\n/**\n * Collapse Cohere SSE stream into a single response.\n *\n * Format:\n * event: content-delta\\ndata: {\"type\":\"content-delta\",\"delta\":{\"message\":{\"content\":{\"text\":\"Hello\"}}}}\\n\\n\n */\nexport function collapseCohereSSE(rawBody: string): CollapseResult {\n const inputTruncated = isCollapseInputTruncated(rawBody);\n const body = guardCollapseBody(rawBody);\n const blocks = splitSSEEvents(body);\n let content = \"\";\n // Reasoning text assembled from `thinking` content-delta blocks. Cohere's\n // reasoning models stream a `content.type === \"thinking\"` block carrying a\n // `thinking` string before the `text` block; capture it so a recorded\n // reasoning turn round-trips its reasoning instead of dropping it.\n let reasoning = \"\";\n let droppedChunks = 0;\n let firstDroppedSample: string | undefined;\n const toolCallMap = new Map<number, { id: string; name: string; arguments: string }>();\n // Fallback keying for tool-call events that OMIT `index` (mirrors the\n // OpenAI guard). Without it, every index-less tool-call-start collapses\n // under one `undefined`/NaN key, merging distinct calls. Index-less starts\n // mint a fresh synthetic key. `lastStartKey` tracks the most-recent\n // tool-call-start key REGARDLESS of whether it was real or synthetic, so an\n // index-less tool-call-delta correlates to whichever start most recently\n // opened — not just to the last synthetic one. The 1_000_000 sentinel\n // assumes real provider indices stay below it.\n let nextSyntheticIndex = 1_000_000;\n let lastStartKey: number | undefined;\n // Cross-channel order atoms (#274), in stream arrival order. Cohere v2 SSE is\n // a single ordered stream (content-delta / tool-call-start interleave on the\n // wire), so a toolCall atom references the same accumulator object stored in\n // toolCallMap and later tool-call-delta fragments mutate it in place.\n const orderAtoms: OrderAtom[] = [];\n\n for (const block of blocks) {\n const lines = splitSSELines(block);\n const eventLine = lines.find((l) => l.startsWith(\"event:\"));\n const data = extractSSEData(lines);\n if (data === undefined) continue;\n\n const eventType = eventLine ? eventLine.slice(6).trim() : \"\";\n const payload = data.trim();\n\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(payload) as Record<string, unknown>;\n } catch (err) {\n droppedChunks++;\n if (droppedChunks === 1) {\n const msg = err instanceof Error ? err.message : \"unknown\";\n firstDroppedSample = `parse failed (${msg}): ${surrogateSafeSlice(payload, 200)}`;\n }\n continue;\n }\n\n if (eventType === \"content-delta\") {\n const delta = parsed.delta as Record<string, unknown> | undefined;\n const message = delta?.message as Record<string, unknown> | undefined;\n const contentObj = message?.content as Record<string, unknown> | undefined;\n if (contentObj && contentObj.type === \"thinking\" && typeof contentObj.thinking === \"string\") {\n reasoning += contentObj.thinking;\n } else if (contentObj && typeof contentObj.text === \"string\") {\n content += contentObj.text;\n // Reasoning (`thinking`) is intentionally NOT pushed as an order atom —\n // it is not a block channel (mirrors the other collapsers).\n if (contentObj.text.length > 0) {\n orderAtoms.push({ kind: \"text\", text: contentObj.text });\n }\n }\n }\n\n if (eventType === \"tool-call-start\") {\n let index: number;\n if (typeof parsed.index === \"number\") {\n index = parsed.index;\n } else {\n index = nextSyntheticIndex++;\n }\n const delta = parsed.delta as Record<string, unknown> | undefined;\n const message = delta?.message as Record<string, unknown> | undefined;\n const toolCalls = message?.tool_calls as Record<string, unknown> | undefined;\n if (toolCalls) {\n const fn = toolCalls.function as Record<string, unknown> | undefined;\n const created = {\n id: (toolCalls.id as string) ?? \"\",\n name: (fn?.name as string) ?? \"\",\n arguments: \"\",\n };\n toolCallMap.set(index, created);\n // Track the most-recent start key (real OR synthetic) so a following\n // index-less delta correlates to whichever call just opened. Advance it\n // ONLY after confirming this start actually carried a tool_calls payload\n // and created an entry; a payload-less start must not steal correlation\n // from a prior valid start (which would miscount the next index-less\n // delta as a dropped chunk).\n lastStartKey = index;\n // Record the tool atom at the position its tool-call-start arrived; it\n // references `created` so later tool-call-delta args fill it in place.\n orderAtoms.push({ kind: \"toolCall\", ref: created });\n }\n }\n\n if (eventType === \"tool-call-delta\") {\n // Use the streamed `index` when present; otherwise correlate to the most\n // recent tool-call-start (real or synthetic key).\n const index = typeof parsed.index === \"number\" ? parsed.index : lastStartKey;\n const delta = parsed.delta as Record<string, unknown> | undefined;\n const message = delta?.message as Record<string, unknown> | undefined;\n const toolCalls = message?.tool_calls as Record<string, unknown> | undefined;\n if (toolCalls) {\n const fn = toolCalls.function as Record<string, unknown> | undefined;\n if (fn && typeof fn.arguments === \"string\") {\n // A delta that cannot correlate to any known start (no streamed\n // index AND no prior start) would otherwise silently lose its args.\n // Account for it as a dropped chunk instead of vanishing.\n const entry = index !== undefined ? toolCallMap.get(index) : undefined;\n if (entry) {\n entry.arguments += fn.arguments;\n } else {\n droppedChunks++;\n if (droppedChunks === 1) {\n firstDroppedSample = `tool-call-delta with no correlating start: ${surrogateSafeSlice(\n payload,\n 200,\n )}`;\n }\n }\n }\n }\n }\n }\n\n if (toolCallMap.size > 0) {\n const orderedBlocks = buildOrderedBlocks(orderAtoms);\n // When interleaved, persist ordered `blocks` and derive the flat `toolCalls`\n // from the SAME tool atoms (stream-arrival order) so the two never disagree\n // (#274 F4/F5). Otherwise keep the legacy index-sorted order so non-\n // interleaved fixtures stay byte-identical. Both paths normalize arguments\n // so a zero-arg call persists \"{}\" rather than \"\".\n const orderedToolCalls = orderAtoms\n .filter(\n (a): a is { kind: \"toolCall\"; ref: { name: string; arguments: string; id?: string } } =>\n a.kind === \"toolCall\",\n )\n .map((a) => ({\n name: a.ref.name,\n arguments: normalizeToolArguments(a.ref.arguments),\n ...(a.ref.id ? { id: a.ref.id } : {}),\n }));\n const indexSortedToolCalls = Array.from(toolCallMap.entries())\n .sort(([a], [b]) => a - b)\n .map(([, tc]) => ({\n name: tc.name,\n arguments: normalizeToolArguments(tc.arguments),\n ...(tc.id ? { id: tc.id } : {}),\n }));\n return {\n ...(orderedBlocks ? { blocks: orderedBlocks } : {}),\n ...(content ? { content } : {}),\n toolCalls: orderedBlocks ? orderedToolCalls : indexSortedToolCalls,\n ...(reasoning ? { reasoning } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n ...(inputTruncated ? { truncated: true } : {}),\n };\n }\n\n return {\n content,\n ...(reasoning ? { reasoning } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n ...(inputTruncated ? { truncated: true } : {}),\n };\n}\n\n// ---------------------------------------------------------------------------\n// 6. Bedrock EventStream (binary)\n// ---------------------------------------------------------------------------\n\n/**\n * Decode AWS Event Stream binary frames and extract JSON payloads.\n *\n * Binary frame layout:\n * [total_length: 4B uint32-BE]\n * [headers_length: 4B uint32-BE]\n * [prelude_crc32: 4B]\n * [headers: variable]\n * [payload: variable]\n * [message_crc32: 4B]\n */\nfunction decodeEventStreamFrames(buf: Buffer): {\n frames: Array<{ headers: Record<string, string>; payload: Buffer }>;\n truncated: boolean;\n} {\n const frames: Array<{ headers: Record<string, string>; payload: Buffer }> = [];\n let offset = 0;\n\n while (offset < buf.length) {\n if (offset + 12 > buf.length) break;\n\n const totalLength = buf.readUInt32BE(offset);\n const headersLength = buf.readUInt32BE(offset + 4);\n\n // Validate bounds: ensure the full frame is within the buffer\n if (totalLength < 12 || offset + totalLength > buf.length) {\n return { frames, truncated: true };\n }\n\n // Validate prelude CRC\n const preludeCrc = buf.readUInt32BE(offset + 8);\n const computedPreludeCrc = crc32(buf.subarray(offset, offset + 8));\n if (preludeCrc >>> 0 !== computedPreludeCrc >>> 0) {\n return { frames, truncated: true }; // Prelude CRC mismatch — stop parsing\n }\n\n // Parse headers\n const headersStart = offset + 12;\n const headersEnd = headersStart + headersLength;\n const payloadEnd = offset + totalLength - 4; // minus message CRC\n\n // Validate the headers region fits inside the frame. A frame can carry a\n // valid prelude CRC yet declare a `headersLength` that overruns the payload\n // region (the prelude CRC only covers total/headers length, not the body).\n // Without this guard a per-header read walks off the buffer and throws an\n // uncaught RangeError; treat it as truncation instead.\n if (headersEnd > payloadEnd || headersEnd > buf.length) {\n return { frames, truncated: true };\n }\n\n const headers: Record<string, string> = {};\n let hOffset = headersStart;\n let headerOverrun = false;\n\n while (hOffset < headersEnd) {\n // Each read must stay within the declared headers region. Bail out\n // (truncated) on any overrun rather than reading past the boundary.\n if (hOffset + 1 > headersEnd) {\n headerOverrun = true;\n break;\n }\n const nameLen = buf.readUInt8(hOffset);\n hOffset += 1;\n if (hOffset + nameLen + 1 + 2 > headersEnd) {\n headerOverrun = true;\n break;\n }\n const name = buf.subarray(hOffset, hOffset + nameLen).toString(\"utf8\");\n hOffset += nameLen;\n // Skip header type byte (type 7 = STRING)\n hOffset += 1;\n const valueLen = buf.readUInt16BE(hOffset);\n hOffset += 2;\n if (hOffset + valueLen > headersEnd) {\n headerOverrun = true;\n break;\n }\n const value = buf.subarray(hOffset, hOffset + valueLen).toString(\"utf8\");\n hOffset += valueLen;\n headers[name] = value;\n }\n\n if (headerOverrun) {\n return { frames, truncated: true };\n }\n\n // Extract payload\n const payloadStart = headersEnd;\n const payload = buf.subarray(payloadStart, payloadEnd);\n\n // Validate message CRC (covers entire frame minus last 4 bytes)\n const messageCrc = buf.readUInt32BE(offset + totalLength - 4);\n const computedMessageCrc = crc32(buf.subarray(offset, offset + totalLength - 4));\n if (messageCrc >>> 0 !== computedMessageCrc >>> 0) {\n return { frames, truncated: true }; // Message CRC mismatch — stop parsing\n }\n\n frames.push({ headers, payload });\n offset += totalLength;\n }\n\n return { frames, truncated: false };\n}\n\n/**\n * Collapse Bedrock binary Event Stream into a single response.\n *\n * Each frame contains a JSON payload with event types like:\n * contentBlockDelta, contentBlockStart, etc.\n */\nexport function collapseBedrockEventStream(rawBody: Buffer): CollapseResult {\n // Bound the input under V8's max string length before decoding: `content` /\n // `reasoning` / a tool call's `arguments` accumulate across frames and can\n // never exceed the total decoded bytes, so capping the input buffer bounds\n // every accumulator and prevents `RangeError: Invalid string length`. An\n // over-ceiling buffer is truncated (a partial trailing frame simply fails CRC\n // and stops parsing) and the result is marked `truncated`.\n const limit = effectiveCollapseStringLimit();\n const inputTruncated = rawBody.byteLength > limit;\n const body = inputTruncated ? rawBody.subarray(0, limit) : rawBody;\n const { frames, truncated: frameTruncated } = decodeEventStreamFrames(body);\n const truncated = frameTruncated || inputTruncated;\n let content = \"\";\n // Reasoning text assembled from Converse `reasoningContent.text` deltas. The\n // Bedrock Converse stream interleaves a `delta.reasoningContent` block carrying\n // the model's reasoning; capture it so a recorded reasoning turn round-trips\n // its reasoning instead of dropping it.\n let reasoning = \"\";\n // Anthropic-native extended-thinking fields (invoke-with-response-stream).\n // The native binary branch carries the same thinking/signature/redacted\n // channel as the Anthropic SSE collapser; it mirrors that path's\n // thinking/signature/redacted capture rules so a recorded reasoning turn\n // round-trips instead of silently dropping it. Unlike the SSE path, binary\n // tool_use correlation has no index-less fallback and relies on an explicit\n // `index`.\n let reasoningSignature: string | undefined;\n const redactedThinking: string[] = [];\n let droppedChunks = 0;\n let firstDroppedSample: string | undefined;\n const toolCallMap = new Map<number, { id: string; name: string; arguments: string }>();\n // Cross-channel order atoms (#274), in frame (stream) arrival order. Both the\n // Anthropic-native and Converse sub-protocols append text and tool deltas in\n // frame order, so a toolCall atom references the same accumulator object stored\n // in toolCallMap and later arg deltas mutate it in place.\n const orderAtoms: OrderAtom[] = [];\n\n for (const frame of frames) {\n const frameStr = frame.payload.toString(\"utf8\");\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(frameStr) as Record<string, unknown>;\n if (\n frame.headers[\":event-type\"] === \"chunk\" &&\n parsed !== null &&\n typeof parsed === \"object\" &&\n Object.hasOwn(parsed, \"bytes\")\n ) {\n try {\n const bytes = parsed.bytes;\n if (\n typeof bytes !== \"string\" ||\n bytes.length === 0 ||\n !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(bytes)\n ) {\n throw new TypeError(\"bytes must be a nonempty base64 string\");\n }\n const event: unknown = JSON.parse(Buffer.from(bytes, \"base64\").toString(\"utf8\"));\n if (\n event === null ||\n typeof event !== \"object\" ||\n Array.isArray(event) ||\n !(\"type\" in event) ||\n typeof event.type !== \"string\"\n ) {\n throw new TypeError(\"decoded bytes must contain a Claude event object\");\n }\n parsed = event;\n } catch (err) {\n const message = err instanceof Error ? err.message : \"unknown\";\n throw new TypeError(`Invalid Invoke PayloadPart: ${message}`);\n }\n }\n } catch (err) {\n droppedChunks++;\n if (droppedChunks === 1) {\n const msg = err instanceof Error ? err.message : \"unknown\";\n firstDroppedSample = `parse failed (${msg}): ${surrogateSafeSlice(frameStr, 200)}`;\n }\n continue;\n }\n\n // InvokeModel Claude event: decoded PayloadPart or legacy flat payload with \"type\" field\n if (parsed.type === \"content_block_delta\") {\n const delta = parsed.delta as Record<string, unknown> | undefined;\n if (delta?.type === \"text_delta\" && typeof delta.text === \"string\") {\n content += delta.text;\n if (delta.text.length > 0) {\n orderAtoms.push({ kind: \"text\", text: delta.text });\n }\n }\n if (delta?.type === \"thinking_delta\" && typeof delta.thinking === \"string\") {\n reasoning += delta.thinking;\n }\n // Last-signature-wins: a turn with MULTIPLE thinking blocks overwrites\n // this on each block, so the merged `reasoning` ends up bound only to the\n // FINAL block's signature (mirrors collapseAnthropicSSE).\n if (delta?.type === \"signature_delta\" && typeof delta.signature === \"string\") {\n reasoningSignature = delta.signature;\n }\n if (delta?.type === \"input_json_delta\" && typeof delta.partial_json === \"string\") {\n const index = parsed.index as number | undefined;\n // An arg delta that cannot correlate to a known tool_use start would\n // otherwise silently lose its args. Account for it as a dropped chunk\n // instead of vanishing (mirrors the Cohere uncorrelated-delta path).\n const entry = index !== undefined ? toolCallMap.get(index) : undefined;\n if (entry) {\n entry.arguments += delta.partial_json;\n } else {\n droppedChunks++;\n if (droppedChunks === 1) {\n firstDroppedSample = `input_json_delta with no correlating tool_use start: ${surrogateSafeSlice(\n frameStr,\n 200,\n )}`;\n }\n }\n }\n continue;\n }\n if (parsed.type === \"content_block_start\") {\n const block = parsed.content_block as Record<string, unknown> | undefined;\n const index = parsed.index as number | undefined;\n // A `redacted_thinking` block carries its encrypted reasoning in an\n // opaque `data` string on the start event (no deltas follow). Capture it\n // so the recorded turn replays the redacted block faithfully\n // (mirrors collapseAnthropicSSE; see capturedRedactedData).\n const redactedData = capturedRedactedData(block);\n if (redactedData !== undefined) {\n redactedThinking.push(redactedData);\n }\n if (block?.type === \"tool_use\") {\n if (index !== undefined) {\n const created = {\n id: (block.id as string) ?? \"\",\n name: (block.name as string) ?? \"\",\n arguments: \"\",\n };\n toolCallMap.set(index, created);\n orderAtoms.push({ kind: \"toolCall\", ref: created });\n } else {\n // A tool_use start with no block index cannot be keyed, so no later\n // input_json_delta can ever correlate to it and the tool call's\n // identity is silently lost. Account for it as a dropped chunk —\n // matching the sibling uncorrelated arg-delta path below — rather\n // than vanishing without a trace.\n droppedChunks++;\n if (droppedChunks === 1) {\n firstDroppedSample = `tool_use content_block_start with no index — tool call identity lost: ${surrogateSafeSlice(\n frameStr,\n 200,\n )}`;\n }\n }\n }\n continue;\n }\n\n // Converse format (converse-stream): camelCase wrapper keys\n // contentBlockStart — may initiate a tool_use block\n if (parsed.contentBlockStart) {\n const blockStart = parsed.contentBlockStart as Record<string, unknown>;\n const index = (parsed.contentBlockIndex ?? blockStart.contentBlockIndex) as\n | number\n | undefined;\n const start = blockStart.start as Record<string, unknown> | undefined;\n if (start?.toolUse) {\n if (index !== undefined) {\n const toolUse = start.toolUse as Record<string, unknown>;\n const created = {\n id: (toolUse.toolUseId as string) ?? \"\",\n name: (toolUse.name as string) ?? \"\",\n arguments: \"\",\n };\n toolCallMap.set(index, created);\n orderAtoms.push({ kind: \"toolCall\", ref: created });\n } else {\n // Same accounting as the native path: an unkeyable toolUse start\n // would lose its identity, so count it as a dropped chunk rather\n // than dropping it silently.\n droppedChunks++;\n if (droppedChunks === 1) {\n firstDroppedSample = `contentBlockStart toolUse with no index — tool call identity lost: ${surrogateSafeSlice(\n frameStr,\n 200,\n )}`;\n }\n }\n }\n }\n\n // contentBlockDelta\n if (parsed.contentBlockDelta) {\n const blockDelta = parsed.contentBlockDelta as Record<string, unknown>;\n const index = (parsed.contentBlockIndex ?? blockDelta.contentBlockIndex) as\n | number\n | undefined;\n const delta = blockDelta.delta as Record<string, unknown> | undefined;\n if (!delta) continue;\n\n // Text delta\n if (typeof delta.text === \"string\") {\n content += delta.text;\n if (delta.text.length > 0) {\n orderAtoms.push({ kind: \"text\", text: delta.text });\n }\n }\n\n // Reasoning delta — Converse carries reasoning in `reasoningContent.text`.\n // The Converse branch intentionally captures no signature/redacted channel:\n // Converse has no `signature_delta`/`redacted_thinking` wire shape, so the\n // asymmetry with the Anthropic-native branch above is by design, not a gap\n // to be \"fixed\" later.\n if (typeof delta.reasoningContent === \"object\" && delta.reasoningContent !== null) {\n const reasoningDelta = delta.reasoningContent as Record<string, unknown>;\n if (typeof reasoningDelta.text === \"string\") {\n reasoning += reasoningDelta.text;\n }\n }\n\n // Tool use input JSON delta\n if (typeof delta.toolUse === \"object\" && delta.toolUse !== null) {\n const toolUseDelta = delta.toolUse as Record<string, unknown>;\n if (typeof toolUseDelta.input === \"string\") {\n // An arg delta that cannot correlate to a known tool_use start would\n // otherwise silently lose its args. Account for it as a dropped chunk\n // instead of vanishing (mirrors the Cohere uncorrelated-delta path).\n const entry = index !== undefined ? toolCallMap.get(index) : undefined;\n if (entry) {\n entry.arguments += toolUseDelta.input;\n } else {\n droppedChunks++;\n if (droppedChunks === 1) {\n firstDroppedSample = `toolUse.input delta with no correlating tool_use start: ${surrogateSafeSlice(\n frameStr,\n 200,\n )}`;\n }\n }\n }\n }\n }\n }\n\n if (toolCallMap.size > 0) {\n const orderedBlocks = buildOrderedBlocks(orderAtoms);\n // When interleaved, persist ordered `blocks` and derive the flat `toolCalls`\n // from the SAME tool atoms (frame-arrival order) so the two never disagree\n // (#274 F4/F5); otherwise keep the legacy index-sorted order so non-\n // interleaved fixtures stay byte-identical. Both paths normalize arguments\n // so a zero-arg tool_use persists \"{}\" rather than \"\".\n const orderedToolCalls = orderAtoms\n .filter(\n (a): a is { kind: \"toolCall\"; ref: { name: string; arguments: string; id?: string } } =>\n a.kind === \"toolCall\",\n )\n .map((a) => ({\n name: a.ref.name,\n arguments: normalizeToolArguments(a.ref.arguments),\n ...(a.ref.id ? { id: a.ref.id } : {}),\n }));\n const indexSortedToolCalls = Array.from(toolCallMap.entries())\n .sort(([a], [b]) => a - b)\n .map(([, tc]) => ({\n name: tc.name,\n arguments: normalizeToolArguments(tc.arguments),\n ...(tc.id ? { id: tc.id } : {}),\n }));\n return {\n ...(orderedBlocks ? { blocks: orderedBlocks } : {}),\n // A tool-bearing turn that ALSO streamed text previously DROPPED `content`\n // here. Spread it when present so the interleaved blocks are persistable\n // (the recorder only emits blocks when content+toolCalls coexist) and the\n // text is no longer silently lost (#274).\n ...(content ? { content } : {}),\n toolCalls: orderedBlocks ? orderedToolCalls : indexSortedToolCalls,\n ...(reasoning ? { reasoning } : {}),\n ...(reasoningSignature ? { reasoningSignature } : {}),\n ...(redactedThinking.length > 0 ? { redactedThinking } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n ...(truncated ? { truncated } : {}),\n };\n }\n\n return {\n content,\n ...(reasoning ? { reasoning } : {}),\n ...(reasoningSignature ? { reasoningSignature } : {}),\n ...(redactedThinking.length > 0 ? { redactedThinking } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n ...(truncated ? { truncated } : {}),\n };\n}\n\n// ---------------------------------------------------------------------------\n// 7. Gemini Interactions SSE\n// ---------------------------------------------------------------------------\n\n/**\n * Collapse Gemini Interactions SSE stream into a single response.\n *\n * Handles the SDK 2.x event protocol (the \"Interactions breaking changes,\n * May 2026\" shapes):\n * data: {\"event_type\":\"step.start\",\"index\":1,\"step\":{\"type\":\"function_call\",\"id\":\"call_1\",\"name\":\"fn\",\"arguments\":{}}}\n * data: {\"event_type\":\"step.delta\",\"index\":0,\"delta\":{\"type\":\"text\",\"text\":\"Hello\"}}\n * data: {\"event_type\":\"step.delta\",\"index\":1,\"delta\":{\"type\":\"arguments_delta\",\"arguments\":\"{\\\"x\\\":1}\"}}\n * data: {\"event_type\":\"interaction.completed\",\"interaction\":{\"id\":\"...\",\"usage\":{...}}}\n *\n * The legacy SDK 1.x shapes (`content.delta` with an inline `function_call`\n * delta) are still accepted for backward compatibility with previously\n * recorded fixtures.\n */\nexport function collapseGeminiInteractionsSSE(rawBody: string): CollapseResult {\n const inputTruncated = isCollapseInputTruncated(rawBody);\n const body = guardCollapseBody(rawBody);\n const lines = splitSSEEvents(body);\n let content = \"\";\n let reasoning = \"\";\n let droppedChunks = 0;\n let firstDroppedSample: string | undefined;\n // Legacy 1.x tool calls arrive fully formed in a single content.delta.\n const toolCalls: ToolCall[] = [];\n // 2.x tool calls are assembled across step.start (identity) + arguments_delta\n // (string fragments), keyed by step index.\n const stepToolCalls = new Map<\n number,\n { id?: string; name: string; argsObj?: unknown; argsStr: string }\n >();\n // Synthetic keys for function_call step.start events that arrive without an\n // index (matches the sibling collapsers); seeded high to avoid colliding with\n // real step indices.\n let nextSyntheticStepIndex = 1_000_000;\n\n for (const line of lines) {\n const data = extractSSEData(splitSSELines(line));\n if (data === undefined) continue;\n\n const payload = data.trim();\n\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(payload) as Record<string, unknown>;\n } catch (err) {\n droppedChunks++;\n if (droppedChunks === 1) {\n const msg = err instanceof Error ? err.message : \"unknown\";\n firstDroppedSample = `parse failed (${msg}): ${surrogateSafeSlice(payload, 200)}`;\n }\n continue;\n }\n\n const eventType = parsed.event_type as string | undefined;\n if (!eventType) continue;\n\n const index = typeof parsed.index === \"number\" ? parsed.index : undefined;\n\n if (eventType === \"step.start\") {\n // 2.x — tool-call identity lives on step.start, not in a delta.\n const step = parsed.step as Record<string, unknown> | undefined;\n if (step && step.type === \"function_call\") {\n // An index-less start can't correlate later arguments_delta fragments,\n // but minting a synthetic key preserves the call's identity instead of\n // dropping it silently.\n const key = index ?? nextSyntheticStepIndex++;\n stepToolCalls.set(key, {\n id: step.id ? String(step.id) : undefined,\n name: String(step.name ?? \"\"),\n // step.start may carry a fully-populated `arguments` object (non-\n // streamed calls) or an empty `{}` placeholder (streamed calls).\n argsObj: step.arguments,\n argsStr: \"\",\n });\n }\n } else if (eventType === \"step.delta\" || eventType === \"content.delta\") {\n const delta = parsed.delta as Record<string, unknown> | undefined;\n if (!delta) continue;\n\n if (delta.type === \"text\" && typeof delta.text === \"string\") {\n content += delta.text;\n } else if (delta.type === \"arguments_delta\") {\n // 2.x — argument fragment (a JSON string) keyed by step index.\n const entry = index !== undefined ? stepToolCalls.get(index) : undefined;\n if (entry) {\n if (typeof delta.arguments === \"string\") {\n entry.argsStr += delta.arguments;\n }\n } else {\n droppedChunks++;\n if (droppedChunks === 1) {\n firstDroppedSample = `arguments_delta with no correlating step.start: ${surrogateSafeSlice(\n payload,\n 200,\n )}`;\n }\n }\n } else if (delta.type === \"function_call\") {\n // Legacy 1.x — full tool call inline in a content.delta. Normalize the\n // string branch so a literal `arguments: \"\"` persists \"{}\" not \"\".\n toolCalls.push({\n name: String(delta.name ?? \"\"),\n arguments:\n typeof delta.arguments === \"string\"\n ? normalizeToolArguments(delta.arguments)\n : JSON.stringify(delta.arguments ?? {}),\n ...(delta.id ? { id: String(delta.id) } : {}),\n });\n } else if (delta.type === \"thought_summary\") {\n // 2.x nests the text under `content.text`; 1.x used a flat `text`.\n const summaryContent = delta.content as Record<string, unknown> | undefined;\n if (summaryContent && typeof summaryContent.text === \"string\") {\n reasoning += summaryContent.text;\n } else if (typeof delta.text === \"string\") {\n reasoning += delta.text;\n }\n }\n }\n }\n\n // BLOCK-CAPTURE DECISION (#274): this collapser is ARGS-ONLY — it intentionally\n // does NOT emit `blocks`. Unlike the delta-stream collapsers, the 2.x protocol\n // is step/index-addressed: tool identity arrives on `step.start` and its args\n // on indexed `arguments_delta` fragments, finalized here in SORTED step-index\n // order — interleaved with legacy 1.x calls that are arrival-pushed above. That\n // hybrid flat order cannot be reconciled with arrival-order OrderAtoms by\n // identity, so any emitted `blocks` would risk disagreeing with the flat\n // `toolCalls` (violating the #274 F4/F5 byte-consistency invariant). We\n // therefore only normalize arguments and leave `blocks` unset. Revisit only if\n // the finalizer is reworked to a single arrival-ordered pass.\n\n // Finalize 2.x tool calls in step-index order.\n for (const [, tc] of Array.from(stepToolCalls.entries()).sort(([a], [b]) => a - b)) {\n let args: string;\n if (tc.argsStr !== \"\") {\n args = tc.argsStr;\n // The arguments_delta fragments must concatenate into valid JSON by\n // step.stop. A truncated/interrupted stream can leave them malformed;\n // surface that via droppedChunks rather than writing a corrupt fixture\n // silently (mirrors the per-chunk parse guard above). On failure we MUST\n // NOT persist the invalid-JSON string — it would fail `validateFixtures`\n // on reload (the loader does `JSON.parse(tc.arguments)`). Fall back to\n // \"{}\" so the persisted `arguments` is always valid JSON, exactly like\n // the empty/unusable-args path below (mirrors the OpenAI/Anthropic\n // sibling collapsers, which never persist unparseable tool args).\n try {\n JSON.parse(args);\n } catch {\n droppedChunks++;\n if (droppedChunks === 1) {\n firstDroppedSample = `assembled arguments_delta not valid JSON for \"${tc.name}\": ${surrogateSafeSlice(\n args,\n 200,\n )}`;\n }\n args = \"{}\";\n }\n } else {\n args = typeof tc.argsObj === \"string\" ? tc.argsObj : JSON.stringify(tc.argsObj ?? {});\n }\n // Normalize so a step.start with no arguments / a whitespace-only argsStr\n // persists \"{}\" rather than \"\" (a valid-JSON non-empty argsStr is unchanged).\n toolCalls.push({\n name: tc.name,\n arguments: normalizeToolArguments(args),\n ...(tc.id ? { id: tc.id } : {}),\n });\n }\n\n if (toolCalls.length > 0) {\n return {\n ...(content ? { content } : {}),\n toolCalls,\n ...(reasoning ? { reasoning } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n ...(inputTruncated ? { truncated: true } : {}),\n };\n }\n\n return {\n content,\n ...(reasoning ? { reasoning } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n ...(inputTruncated ? { truncated: true } : {}),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Dispatch helper — pick the right collapse function by provider\n// ---------------------------------------------------------------------------\n\n/**\n * Collapse a streaming response body into a non-streaming fixture response.\n * Returns null if the content type is not a known streaming format.\n * Falls back to OpenAI SSE parsing for unrecognized provider keys with text/event-stream.\n *\n * Public, with the 1.44.0 result (see {@link collapseOpenAISSE}). The recorder\n * uses {@link collapseStreamingResponseWithResponsesTools}.\n */\nexport function collapseStreamingResponse(\n contentType: string,\n providerKey: RecordProviderKey,\n body: string | Buffer,\n logger?: Logger,\n): CollapseResult | null {\n const collapsed = collapseStreamingResponseWithResponsesTools(\n contentType,\n providerKey,\n body,\n logger,\n );\n return collapsed && withoutResponsesToolFields(collapsed);\n}\n\n/**\n * @internal {@link collapseStreamingResponse} keeping an OpenAI Responses\n * `namespace` and custom tool calls.\n */\nexport function collapseStreamingResponseWithResponsesTools(\n contentType: string,\n providerKey: RecordProviderKey,\n body: string | Buffer,\n logger?: Logger,\n): CollapseResult | null {\n const ct = contentType.toLowerCase();\n\n if (ct.includes(\"application/vnd.amazon.eventstream\")) {\n const buf = typeof body === \"string\" ? Buffer.from(body, \"binary\") : body;\n return collapseBedrockEventStream(buf);\n }\n\n if (ct.includes(\"application/x-ndjson\")) {\n const str = typeof body === \"string\" ? body : body.toString(\"utf8\");\n return collapseOllamaNDJSON(str);\n }\n\n if (ct.includes(\"text/event-stream\")) {\n const str = typeof body === \"string\" ? body : body.toString(\"utf8\");\n switch (providerKey) {\n // OpenRouter belongs here with OpenAI/Azure: it IS the OpenAI SSE wire\n // format (it is the OpenAI-compatible gateway), and `openrouter` is a\n // first-class RecordProviderKey set by every `/api/v1/chat/completions`\n // record. Without this case it fell to the `default` arm, which collapsed\n // it correctly but logged `unknown SSE provider \"openrouter\"` on EVERY\n // recorded OpenRouter stream — telling users aimock does not recognize a\n // provider it ships first-class support for.\n // `byteplus` joins them for the same reason: Ark's /chat/completions is\n // OpenAI-compatible and is driven through the OpenAI SDK\n // (@tanstack/ai-byteplus adapters/text.ts), so its SSE IS the OpenAI wire\n // format. Omitting the case would reintroduce the exact warn described\n // above for every recorded Ark chat stream.\n case \"openai\":\n case \"azure\":\n case \"openrouter\":\n case \"byteplus\":\n return collapseOpenAISSEWithResponsesTools(str);\n case \"anthropic\":\n return collapseAnthropicSSE(str);\n case \"gemini\":\n case \"vertexai\":\n return collapseGeminiSSE(str);\n case \"gemini-interactions\":\n return collapseGeminiInteractionsSSE(str);\n case \"cohere\":\n return collapseCohereSSE(str);\n case \"bedrock\":\n return collapseAnthropicSSE(str);\n default:\n logger?.warn(\n `[stream-collapse] unknown SSE provider \"${providerKey}\", falling back to OpenAI SSE format`,\n );\n return collapseOpenAISSEWithResponsesTools(str);\n }\n }\n\n return null;\n}\n"],"mappings":"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"}
|