@copilotkit/aimock 1.27.3 → 1.29.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 +36 -0
- package/dist/agui-types.d.ts.map +1 -1
- package/dist/config-loader.d.ts.map +1 -1
- package/dist/gemini.cjs +18 -8
- 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 +18 -8
- package/dist/gemini.js.map +1 -1
- package/dist/harmony.cjs +419 -0
- package/dist/harmony.cjs.map +1 -0
- package/dist/harmony.js +417 -0
- package/dist/harmony.js.map +1 -0
- package/dist/journal.cjs +10 -0
- package/dist/journal.cjs.map +1 -1
- package/dist/journal.d.cts +8 -0
- package/dist/journal.d.ts +8 -0
- package/dist/journal.js +10 -0
- package/dist/journal.js.map +1 -1
- package/dist/recorder.cjs +57 -13
- package/dist/recorder.cjs.map +1 -1
- package/dist/recorder.d.cts +6 -1
- package/dist/recorder.d.cts.map +1 -1
- package/dist/recorder.d.ts +6 -1
- package/dist/recorder.d.ts.map +1 -1
- package/dist/recorder.js +57 -13
- package/dist/recorder.js.map +1 -1
- package/dist/server.cjs +40 -10
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +40 -10
- package/dist/server.js.map +1 -1
- package/dist/stream-collapse.cjs +219 -57
- package/dist/stream-collapse.cjs.map +1 -1
- package/dist/stream-collapse.d.cts +16 -0
- package/dist/stream-collapse.d.cts.map +1 -1
- package/dist/stream-collapse.d.ts +16 -0
- package/dist/stream-collapse.d.ts.map +1 -1
- package/dist/stream-collapse.js +219 -57
- package/dist/stream-collapse.js.map +1 -1
- package/dist/types.d.cts +9 -0
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.ts +9 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/vector-types.d.cts.map +1 -1
- package/dist/vector-types.d.ts.map +1 -1
- package/dist/video.cjs +17 -1
- 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 +17 -1
- package/dist/video.js.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream-collapse.js","names":[],"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 { RecordProviderKey, ToolCall } from \"./types.js\";\nimport type { Logger } from \"./logger.js\";\n\n// ---------------------------------------------------------------------------\n// Result type shared by all collapse functions\n// ---------------------------------------------------------------------------\n\nexport interface CollapseResult {\n content?: string;\n reasoning?: string;\n webSearches?: string[];\n toolCalls?: ToolCall[];\n droppedChunks?: number;\n firstDroppedSample?: string;\n truncated?: boolean;\n audioB64?: string;\n audioMimeType?: string;\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(body: string): CollapseResult {\n const lines = body.split(\"\\n\\n\").filter((l) => l.trim().length > 0);\n let content = \"\";\n let reasoning = \"\";\n const webSearchQueries: string[] = [];\n let droppedChunks = 0;\n let firstDroppedSample: string | undefined;\n const toolCallMap = new Map<number, { id: string; name: string; arguments: string }>();\n\n for (const line of lines) {\n const dataLine = line.split(\"\\n\").find((l) => l.startsWith(\"data:\"));\n if (!dataLine) continue;\n\n const payload = dataLine.slice(5).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}): ${payload.slice(0, 200)}`;\n }\n continue;\n }\n\n // Responses API reasoning events\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 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 }\n\n // Responses API text content events\n if (parsed.type === \"response.output_text.delta\" && typeof parsed.delta === \"string\") {\n content += parsed.delta;\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 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 }\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 index = tc.index as number;\n const fn = tc.function as Record<string, unknown> | undefined;\n\n if (!toolCallMap.has(index)) {\n toolCallMap.set(index, {\n id: (tc.id as string) ?? \"\",\n name: (fn?.name as string) ?? \"\",\n arguments: \"\",\n });\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 if (toolCallMap.size > 0) {\n const sorted = Array.from(toolCallMap.entries()).sort(([a], [b]) => a - b);\n return {\n ...(content ? { content } : {}),\n toolCalls: sorted.map(([, tc]) => ({\n name: tc.name,\n arguments: tc.arguments,\n ...(tc.id ? { id: tc.id } : {}),\n })),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n };\n }\n\n return {\n content,\n ...(reasoning ? { reasoning } : {}),\n ...(webSearchQueries.length > 0 ? { webSearches: webSearchQueries } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\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(body: string): CollapseResult {\n const blocks = body.split(\"\\n\\n\").filter((b) => b.trim().length > 0);\n let content = \"\";\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\n for (const block of blocks) {\n const lines = block.split(\"\\n\");\n const eventLine = lines.find((l) => l.startsWith(\"event:\"));\n const dataLine = lines.find((l) => l.startsWith(\"data:\"));\n if (!dataLine) continue;\n\n const eventType = eventLine ? eventLine.slice(6).trim() : \"\";\n const payload = dataLine.slice(5).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}): ${payload.slice(0, 200)}`;\n }\n continue;\n }\n\n if (eventType === \"content_block_start\") {\n const index = parsed.index as number;\n const contentBlock = parsed.content_block as Record<string, unknown> | undefined;\n if (contentBlock?.type === \"tool_use\") {\n toolCallMap.set(index, {\n id: (contentBlock.id as string) ?? \"\",\n name: (contentBlock.name as string) ?? \"\",\n arguments: \"\",\n });\n }\n }\n\n if (eventType === \"content_block_delta\") {\n const index = parsed.index as number;\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 }\n\n if (delta.type === \"thinking_delta\" && typeof delta.thinking === \"string\") {\n reasoning += delta.thinking;\n }\n\n if (delta.type === \"input_json_delta\" && typeof delta.partial_json === \"string\") {\n const entry = toolCallMap.get(index);\n if (entry) {\n entry.arguments += delta.partial_json;\n }\n }\n }\n }\n\n if (toolCallMap.size > 0) {\n const sorted = Array.from(toolCallMap.entries()).sort(([a], [b]) => a - b);\n return {\n ...(content ? { content } : {}),\n toolCalls: sorted.map(([, tc]) => ({\n name: tc.name,\n arguments: tc.arguments,\n ...(tc.id ? { id: tc.id } : {}),\n })),\n ...(reasoning ? { reasoning } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n };\n }\n\n return {\n content,\n ...(reasoning ? { reasoning } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\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(body: string): CollapseResult {\n const lines = body.split(\"\\n\\n\").filter((l) => l.trim().length > 0);\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\n for (const line of lines) {\n const dataLine = line.split(\"\\n\").find((l) => l.startsWith(\"data:\"));\n if (!dataLine) continue;\n\n const payload = dataLine.slice(5).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}): ${payload.slice(0, 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 toolCalls.push({\n name: String(fc.name ?? \"\"),\n arguments: typeof fc.args === \"string\" ? (fc.args as string) : JSON.stringify(fc.args),\n });\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 }\n }\n }\n }\n\n if (audioB64) {\n return {\n audioB64,\n audioMimeType,\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\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 };\n }\n\n return {\n content,\n ...(reasoning ? { reasoning } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\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 */\nexport function collapseOllamaNDJSON(body: string): CollapseResult {\n const lines = body.split(\"\\n\").filter((l) => l.trim().length > 0);\n let content = \"\";\n let droppedChunks = 0;\n let firstDroppedSample: string | undefined;\n const toolCalls: ToolCall[] = [];\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}): ${line.trim().slice(0, 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 }\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 toolCalls.push({\n name: String(fn.name ?? \"\"),\n arguments:\n typeof fn.arguments === \"string\" ? fn.arguments : JSON.stringify(fn.arguments),\n });\n }\n }\n }\n }\n\n // /api/generate format\n else if (typeof parsed.response === \"string\") {\n content += parsed.response;\n }\n }\n\n if (toolCalls.length > 0) {\n return {\n ...(content ? { content } : {}),\n toolCalls,\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n };\n }\n\n return {\n content,\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\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(body: string): CollapseResult {\n const blocks = body.split(\"\\n\\n\").filter((b) => b.trim().length > 0);\n let content = \"\";\n let droppedChunks = 0;\n let firstDroppedSample: string | undefined;\n const toolCallMap = new Map<number, { id: string; name: string; arguments: string }>();\n\n for (const block of blocks) {\n const lines = block.split(\"\\n\");\n const eventLine = lines.find((l) => l.startsWith(\"event:\"));\n const dataLine = lines.find((l) => l.startsWith(\"data:\"));\n if (!dataLine) continue;\n\n const eventType = eventLine ? eventLine.slice(6).trim() : \"\";\n const payload = dataLine.slice(5).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}): ${payload.slice(0, 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 && typeof contentObj.text === \"string\") {\n content += contentObj.text;\n }\n }\n\n if (eventType === \"tool-call-start\") {\n const index = parsed.index as number;\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 toolCallMap.set(index, {\n id: (toolCalls.id as string) ?? \"\",\n name: (fn?.name as string) ?? \"\",\n arguments: \"\",\n });\n }\n }\n\n if (eventType === \"tool-call-delta\") {\n const index = parsed.index as number;\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 const entry = toolCallMap.get(index);\n if (entry) {\n entry.arguments += fn.arguments;\n }\n }\n }\n }\n }\n\n if (toolCallMap.size > 0) {\n const sorted = Array.from(toolCallMap.entries()).sort(([a], [b]) => a - b);\n return {\n ...(content ? { content } : {}),\n toolCalls: sorted.map(([, tc]) => ({\n name: tc.name,\n arguments: tc.arguments,\n ...(tc.id ? { id: tc.id } : {}),\n })),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n };\n }\n\n return {\n content,\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\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 headers: Record<string, string> = {};\n let hOffset = headersStart;\n\n while (hOffset < headersEnd) {\n const nameLen = buf.readUInt8(hOffset);\n hOffset += 1;\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 const value = buf.subarray(hOffset, hOffset + valueLen).toString(\"utf8\");\n hOffset += valueLen;\n headers[name] = value;\n }\n\n // Extract payload\n const payloadStart = headersEnd;\n const payloadEnd = offset + totalLength - 4; // minus message CRC\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(body: Buffer): CollapseResult {\n const { frames, truncated } = decodeEventStreamFrames(body);\n let content = \"\";\n let droppedChunks = 0;\n let firstDroppedSample: string | undefined;\n const toolCallMap = new Map<number, { id: string; name: string; arguments: string }>();\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}): ${frameStr.slice(0, 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 }\n if (delta?.type === \"input_json_delta\" && typeof delta.partial_json === \"string\") {\n const index = parsed.index as number | undefined;\n if (index !== undefined) {\n const entry = toolCallMap.get(index);\n if (entry) entry.arguments += delta.partial_json;\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 if (block?.type === \"tool_use\" && index !== undefined) {\n toolCallMap.set(index, {\n id: (block.id as string) ?? \"\",\n name: (block.name as string) ?? \"\",\n arguments: \"\",\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 && index !== undefined) {\n const toolUse = start.toolUse as Record<string, unknown>;\n toolCallMap.set(index, {\n id: (toolUse.toolUseId as string) ?? \"\",\n name: (toolUse.name as string) ?? \"\",\n arguments: \"\",\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 }\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\" && index !== undefined) {\n const entry = toolCallMap.get(index);\n if (entry) {\n entry.arguments += toolUseDelta.input;\n }\n }\n }\n }\n }\n\n if (toolCallMap.size > 0) {\n const sorted = Array.from(toolCallMap.entries()).sort(([a], [b]) => a - b);\n return {\n toolCalls: sorted.map(([, tc]) => ({\n name: tc.name,\n arguments: tc.arguments,\n ...(tc.id ? { id: tc.id } : {}),\n })),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n ...(truncated ? { truncated } : {}),\n };\n }\n\n return {\n content,\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 * Format (data-only, event_type inside JSON):\n * data: {\"event_type\":\"content.delta\",\"index\":0,\"delta\":{\"type\":\"text\",\"text\":\"Hello\"}}\\n\\n\n * data: {\"event_type\":\"interaction.complete\",\"interaction\":{\"id\":\"...\",\"usage\":{...}}}\\n\\n\n */\nexport function collapseGeminiInteractionsSSE(body: string): CollapseResult {\n const lines = body.split(\"\\n\\n\").filter((l) => l.trim().length > 0);\n let content = \"\";\n let reasoning = \"\";\n let droppedChunks = 0;\n let firstDroppedSample: string | undefined;\n const toolCalls: ToolCall[] = [];\n\n for (const line of lines) {\n const dataLine = line.split(\"\\n\").find((l) => l.startsWith(\"data:\"));\n if (!dataLine) continue;\n\n const payload = dataLine.slice(5).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}): ${payload.slice(0, 200)}`;\n }\n continue;\n }\n\n const eventType = parsed.event_type as string | undefined;\n if (!eventType) continue;\n\n if (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 === \"function_call\") {\n toolCalls.push({\n name: String(delta.name ?? \"\"),\n arguments:\n typeof delta.arguments === \"string\"\n ? delta.arguments\n : JSON.stringify(delta.arguments ?? {}),\n ...(delta.id ? { id: String(delta.id) } : {}),\n });\n } else if (delta.type === \"thought_summary\" && typeof delta.text === \"string\") {\n reasoning += delta.text;\n }\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 };\n }\n\n return {\n content,\n ...(reasoning ? { reasoning } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\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 case \"openai\":\n case \"azure\":\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.js","names":[],"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 { RecordProviderKey, ToolCall } from \"./types.js\";\nimport type { Logger } from \"./logger.js\";\nimport { isHarmonyContent, parseHarmonyContent } from \"./harmony.js\";\n\n// ---------------------------------------------------------------------------\n// Result type shared by all collapse functions\n// ---------------------------------------------------------------------------\n\nexport interface CollapseResult {\n content?: string;\n reasoning?: string;\n webSearches?: string[];\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\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(body: string): CollapseResult {\n const lines = splitSSEEvents(body);\n let content = \"\";\n let reasoning = \"\";\n const webSearchQueries: string[] = [];\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\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 (\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 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 }\n\n // Responses API text content events\n if (parsed.type === \"response.output_text.delta\" && typeof parsed.delta === \"string\") {\n content += parsed.delta;\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 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 }\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 {\n index = nextSyntheticIndex++;\n }\n\n if (!toolCallMap.has(index)) {\n toolCallMap.set(index, {\n id: rawId ?? \"\",\n name: (fn?.name as string) ?? \"\",\n arguments: \"\",\n });\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 sorted = Array.from(toolCallMap.entries()).sort(([a], [b]) => a - b);\n return {\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: [\n ...sorted.map(([, tc]) => ({\n name: tc.name,\n arguments: tc.arguments,\n ...(tc.id ? { id: tc.id } : {}),\n })),\n ...harmonyToolCalls,\n ],\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 ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n ...(harmonyUnparsed ? { harmonyUnparsed: true } : {}),\n ...(harmonyNote ? { harmonyNote } : {}),\n };\n }\n\n return {\n content,\n ...(reasoning ? { reasoning } : {}),\n ...(webSearchQueries.length > 0 ? { webSearches: webSearchQueries } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n ...(harmonyUnparsed ? { harmonyUnparsed: true } : {}),\n ...(harmonyNote ? { harmonyNote } : {}),\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(body: string): CollapseResult {\n const blocks = splitSSEEvents(body);\n let content = \"\";\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 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 start), so an index-less delta\n // correlates to the most-recent start — not just to the last synthetic one.\n // The 1_000_000 sentinel assumes real provider indices stay below it.\n let nextSyntheticIndex = 1_000_000;\n let lastSyntheticIndex: number | undefined;\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 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 toolCallMap.set(index, {\n id: (contentBlock.id as string) ?? \"\",\n name: (contentBlock.name as string) ?? \"\",\n arguments: \"\",\n });\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 }\n\n if (delta.type === \"thinking_delta\" && typeof delta.thinking === \"string\") {\n reasoning += delta.thinking;\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 sorted = Array.from(toolCallMap.entries()).sort(([a], [b]) => a - b);\n return {\n ...(content ? { content } : {}),\n toolCalls: sorted.map(([, tc]) => ({\n name: tc.name,\n arguments: tc.arguments,\n ...(tc.id ? { id: tc.id } : {}),\n })),\n ...(reasoning ? { reasoning } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n };\n }\n\n return {\n content,\n ...(reasoning ? { reasoning } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\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(body: string): CollapseResult {\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\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 toolCalls.push({\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 } 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 }\n }\n }\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 return {\n audioB64,\n audioMimeType,\n ...(content ? { content } : {}),\n ...(reasoning ? { reasoning } : {}),\n ...(toolCalls.length > 0 ? { toolCalls } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\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 };\n }\n\n return {\n content,\n ...(reasoning ? { reasoning } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\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(body: string): CollapseResult {\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\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 }\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 toolCalls.push({\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 }\n }\n }\n }\n\n // /api/generate format\n else if (typeof parsed.response === \"string\") {\n content += parsed.response;\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 return {\n ...(content ? { content } : {}),\n toolCalls,\n ...(reasoning ? { reasoning } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n ...(harmonyUnparsed ? { harmonyUnparsed: true } : {}),\n ...(harmonyNote ? { harmonyNote } : {}),\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 };\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(body: string): CollapseResult {\n const blocks = splitSSEEvents(body);\n let content = \"\";\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\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 && typeof contentObj.text === \"string\") {\n content += contentObj.text;\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 // Track the most-recent start key (real OR synthetic) so a following\n // index-less delta correlates to whichever call just opened.\n lastStartKey = index;\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 toolCallMap.set(index, {\n id: (toolCalls.id as string) ?? \"\",\n name: (fn?.name as string) ?? \"\",\n arguments: \"\",\n });\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 sorted = Array.from(toolCallMap.entries()).sort(([a], [b]) => a - b);\n return {\n ...(content ? { content } : {}),\n toolCalls: sorted.map(([, tc]) => ({\n name: tc.name,\n arguments: tc.arguments,\n ...(tc.id ? { id: tc.id } : {}),\n })),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n };\n }\n\n return {\n content,\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\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(body: Buffer): CollapseResult {\n const { frames, truncated } = decodeEventStreamFrames(body);\n let content = \"\";\n let droppedChunks = 0;\n let firstDroppedSample: string | undefined;\n const toolCallMap = new Map<number, { id: string; name: string; arguments: string }>();\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 }\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 if (block?.type === \"tool_use\" && index !== undefined) {\n toolCallMap.set(index, {\n id: (block.id as string) ?? \"\",\n name: (block.name as string) ?? \"\",\n arguments: \"\",\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 && index !== undefined) {\n const toolUse = start.toolUse as Record<string, unknown>;\n toolCallMap.set(index, {\n id: (toolUse.toolUseId as string) ?? \"\",\n name: (toolUse.name as string) ?? \"\",\n arguments: \"\",\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 }\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 sorted = Array.from(toolCallMap.entries()).sort(([a], [b]) => a - b);\n return {\n toolCalls: sorted.map(([, tc]) => ({\n name: tc.name,\n arguments: tc.arguments,\n ...(tc.id ? { id: tc.id } : {}),\n })),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\n ...(truncated ? { truncated } : {}),\n };\n }\n\n return {\n content,\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 * Format (data-only, event_type inside JSON):\n * data: {\"event_type\":\"content.delta\",\"index\":0,\"delta\":{\"type\":\"text\",\"text\":\"Hello\"}}\\n\\n\n * data: {\"event_type\":\"interaction.complete\",\"interaction\":{\"id\":\"...\",\"usage\":{...}}}\\n\\n\n */\nexport function collapseGeminiInteractionsSSE(body: string): CollapseResult {\n const lines = splitSSEEvents(body);\n let content = \"\";\n let reasoning = \"\";\n let droppedChunks = 0;\n let firstDroppedSample: string | undefined;\n const toolCalls: ToolCall[] = [];\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 if (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 === \"function_call\") {\n toolCalls.push({\n name: String(delta.name ?? \"\"),\n arguments:\n typeof delta.arguments === \"string\"\n ? delta.arguments\n : JSON.stringify(delta.arguments ?? {}),\n ...(delta.id ? { id: String(delta.id) } : {}),\n });\n } else if (delta.type === \"thought_summary\" && typeof delta.text === \"string\") {\n reasoning += delta.text;\n }\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 };\n }\n\n return {\n content,\n ...(reasoning ? { reasoning } : {}),\n ...(droppedChunks > 0 ? { droppedChunks } : {}),\n ...(firstDroppedSample ? { firstDroppedSample } : {}),\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 case \"openai\":\n case \"azure\":\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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"}
|
package/dist/types.d.cts
CHANGED
|
@@ -180,6 +180,15 @@ interface AudioResponse {
|
|
|
180
180
|
contentType?: string;
|
|
181
181
|
};
|
|
182
182
|
format?: string;
|
|
183
|
+
/**
|
|
184
|
+
* Companion modalities that can accompany streamed audio. A single Gemini turn
|
|
185
|
+
* may interleave inlineData audio with a functionCall and/or text/thought
|
|
186
|
+
* parts; the recorder preserves them here so the tool call / content / reasoning
|
|
187
|
+
* are not silently discarded when audio is also present.
|
|
188
|
+
*/
|
|
189
|
+
toolCalls?: ToolCall[];
|
|
190
|
+
content?: string;
|
|
191
|
+
reasoning?: string;
|
|
183
192
|
}
|
|
184
193
|
interface TranscriptionResponse {
|
|
185
194
|
transcription: {
|
package/dist/types.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.cts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":";;;;;;;UAQiB,SAAA;qBAER,MAAA,CAAK,sBACL,MAAA,CAAK,mCAET;EALY,aAAS,EAAA,MAAA,EAMD,GAAA,CAAI,MANH,EAAA,IAAA,EAMiB,MANjB,EAAA,QAAA,EAAA,MAAA,CAAA,EAM4C,OAN5C,CAAA,OAAA,CAAA;EAAA,MAAA,GAAA,EAAA;IAEjB,MAAK,EAAA,MAAA;IACL,CAAA,GAAA,EAAK,MAAA,CAAA,EAAA,OAAA;;YAGe,EAAA,OAAA,EAEN,OAFM,CAAA,EAAA,IAAA;YAAc,EAAA,GAAA,EAAA,MAAA,CAAA,EAAA,IAAA;aAA2B,EAAA,QAAA,EAI7C,eAJ6C,CAAA,EAAA,IAAA;;AAI7C,UAGR,WAAA,CAHQ;EAAe,IAAA,EAAA,MAAA;EAGvB,IAAA,CAAA,EAAA,MAAA;EAMA,CAAA,GAAA,EAAA,MAAA,CAAA,EAAW,OAAA;;AAER,UAFH,WAAA,CAEG;MAEL,EAAA,QAAA,GAAA,MAAA,GAAA,WAAA,GAAA,MAAA;EAAe,OAAA,EAAA,MAAA,GAFV,WAEU,EAAA,GAAA,IAAA;EAIb,IAAA,CAAA,EAAA,MAAA;EAMA,UAAA,CAAA,EAVF,eAUuB,EAAA;EAAA,YAAA,CAAA,EAAA,MAAA;;AAO5B,UAbO,eAAA,CAaP;EAAc,EAAA,EAAA,MAAA;EAYP,IAAA,EAAA,UAAA;EAOA,QAAA,EAAA;IAAY,IAAA,EAAA,MAAA;IACJ,SAAA,EAAA,MAAA;;;AAmBN,UA9CF,qBAAA,CA8CE;OAEC,EAAA,MAAA;EAAqB,QAAA,EA9C7B,WA8C6B,EAAA;EAwCxB,MAAA,CAAA,EAAA,OAAA;EAmBA,cAAA,CAAa,EAAA;IAMb,aAAQ,CAAA,EAAA,OAAA;IAMR,CAAA,GAAA,EAAA,MAAA,CAAA,EAAiB,OAAA;EAAA,CAAA;aACrB,CAAA,EAAA,MAAA;YAD6B,CAAA,EAAA,MAAA;EAAiB,KAAA,CAAA,EAhHjD,cAgHiD,EAAA;EAK1C,WAAA,CAAA,EAAA,MAAA,GAAA,MAAA;EAA6B,eAAA,CAAA,EAAA;IAEjC,IAAA,EAAA,MAAA;IAFyC,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,OAAA;EAAiB,CAAA;EAOtD;EAOA,cAAA,CAAA,EAAA,MAAiB;EAIjB;EAMA,aAAA,CAAA,EAAa,MAAA;EAAA;UACpB,CAAA,EAAA,MAAA;MACC,EAAA,MAAA,CAAA,EAAA,OAAA;;
|
|
1
|
+
{"version":3,"file":"types.d.cts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -180,6 +180,15 @@ interface AudioResponse {
|
|
|
180
180
|
contentType?: string;
|
|
181
181
|
};
|
|
182
182
|
format?: string;
|
|
183
|
+
/**
|
|
184
|
+
* Companion modalities that can accompany streamed audio. A single Gemini turn
|
|
185
|
+
* may interleave inlineData audio with a functionCall and/or text/thought
|
|
186
|
+
* parts; the recorder preserves them here so the tool call / content / reasoning
|
|
187
|
+
* are not silently discarded when audio is also present.
|
|
188
|
+
*/
|
|
189
|
+
toolCalls?: ToolCall[];
|
|
190
|
+
content?: string;
|
|
191
|
+
reasoning?: string;
|
|
183
192
|
}
|
|
184
193
|
interface TranscriptionResponse {
|
|
185
194
|
transcription: {
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":";;;;;;;UAQiB,SAAA;qBAER,MAAA,CAAK,sBACL,MAAA,CAAK,mCAET;EALY,aAAS,EAAA,MAAA,EAMD,GAAA,CAAI,MANH,EAAA,IAAA,EAMiB,MANjB,EAAA,QAAA,EAAA,MAAA,CAAA,EAM4C,OAN5C,CAAA,OAAA,CAAA;EAAA,MAAA,GAAA,EAAA;IAEjB,MAAK,EAAA,MAAA;IACL,CAAA,GAAA,EAAK,MAAA,CAAA,EAAA,OAAA;;YAGe,EAAA,OAAA,EAEN,OAFM,CAAA,EAAA,IAAA;YAAc,EAAA,GAAA,EAAA,MAAA,CAAA,EAAA,IAAA;aAA2B,EAAA,QAAA,EAI7C,eAJ6C,CAAA,EAAA,IAAA;;AAI7C,UAGR,WAAA,CAHQ;EAAe,IAAA,EAAA,MAAA;EAGvB,IAAA,CAAA,EAAA,MAAA;EAMA,CAAA,GAAA,EAAA,MAAA,CAAA,EAAW,OAAA;;AAER,UAFH,WAAA,CAEG;MAEL,EAAA,QAAA,GAAA,MAAA,GAAA,WAAA,GAAA,MAAA;EAAe,OAAA,EAAA,MAAA,GAFV,WAEU,EAAA,GAAA,IAAA;EAIb,IAAA,CAAA,EAAA,MAAA;EAMA,UAAA,CAAA,EAVF,eAUuB,EAAA;EAAA,YAAA,CAAA,EAAA,MAAA;;AAO5B,UAbO,eAAA,CAaP;EAAc,EAAA,EAAA,MAAA;EAYP,IAAA,EAAA,UAAA;EAOA,QAAA,EAAA;IAAY,IAAA,EAAA,MAAA;IACJ,SAAA,EAAA,MAAA;;;AAmBN,UA9CF,qBAAA,CA8CE;OAEC,EAAA,MAAA;EAAqB,QAAA,EA9C7B,WA8C6B,EAAA;EAwCxB,MAAA,CAAA,EAAA,OAAA;EAmBA,cAAA,CAAa,EAAA;IAMb,aAAQ,CAAA,EAAA,OAAA;IAMR,CAAA,GAAA,EAAA,MAAA,CAAA,EAAiB,OAAA;EAAA,CAAA;aACrB,CAAA,EAAA,MAAA;YAD6B,CAAA,EAAA,MAAA;EAAiB,KAAA,CAAA,EAhHjD,cAgHiD,EAAA;EAK1C,WAAA,CAAA,EAAA,MAAA,GAAA,MAAA;EAA6B,eAAA,CAAA,EAAA;IAEjC,IAAA,EAAA,MAAA;IAFyC,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,OAAA;EAAiB,CAAA;EAOtD;EAOA,cAAA,CAAA,EAAA,MAAiB;EAIjB;EAMA,aAAA,CAAA,EAAa,MAAA;EAAA;UACpB,CAAA,EAAA,MAAA;MACC,EAAA,MAAA,CAAA,EAAA,OAAA;;
|
|
1
|
+
{"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":";;;;;;;UAQiB,SAAA;qBAER,MAAA,CAAK,sBACL,MAAA,CAAK,mCAET;EALY,aAAS,EAAA,MAAA,EAMD,GAAA,CAAI,MANH,EAAA,IAAA,EAMiB,MANjB,EAAA,QAAA,EAAA,MAAA,CAAA,EAM4C,OAN5C,CAAA,OAAA,CAAA;EAAA,MAAA,GAAA,EAAA;IAEjB,MAAK,EAAA,MAAA;IACL,CAAA,GAAA,EAAK,MAAA,CAAA,EAAA,OAAA;;YAGe,EAAA,OAAA,EAEN,OAFM,CAAA,EAAA,IAAA;YAAc,EAAA,GAAA,EAAA,MAAA,CAAA,EAAA,IAAA;aAA2B,EAAA,QAAA,EAI7C,eAJ6C,CAAA,EAAA,IAAA;;AAI7C,UAGR,WAAA,CAHQ;EAAe,IAAA,EAAA,MAAA;EAGvB,IAAA,CAAA,EAAA,MAAA;EAMA,CAAA,GAAA,EAAA,MAAA,CAAA,EAAW,OAAA;;AAER,UAFH,WAAA,CAEG;MAEL,EAAA,QAAA,GAAA,MAAA,GAAA,WAAA,GAAA,MAAA;EAAe,OAAA,EAAA,MAAA,GAFV,WAEU,EAAA,GAAA,IAAA;EAIb,IAAA,CAAA,EAAA,MAAA;EAMA,UAAA,CAAA,EAVF,eAUuB,EAAA;EAAA,YAAA,CAAA,EAAA,MAAA;;AAO5B,UAbO,eAAA,CAaP;EAAc,EAAA,EAAA,MAAA;EAYP,IAAA,EAAA,UAAA;EAOA,QAAA,EAAA;IAAY,IAAA,EAAA,MAAA;IACJ,SAAA,EAAA,MAAA;;;AAmBN,UA9CF,qBAAA,CA8CE;OAEC,EAAA,MAAA;EAAqB,QAAA,EA9C7B,WA8C6B,EAAA;EAwCxB,MAAA,CAAA,EAAA,OAAA;EAmBA,cAAA,CAAa,EAAA;IAMb,aAAQ,CAAA,EAAA,OAAA;IAMR,CAAA,GAAA,EAAA,MAAA,CAAA,EAAiB,OAAA;EAAA,CAAA;aACrB,CAAA,EAAA,MAAA;YAD6B,CAAA,EAAA,MAAA;EAAiB,KAAA,CAAA,EAhHjD,cAgHiD,EAAA;EAK1C,WAAA,CAAA,EAAA,MAAA,GAAA,MAAA;EAA6B,eAAA,CAAA,EAAA;IAEjC,IAAA,EAAA,MAAA;IAFyC,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,OAAA;EAAiB,CAAA;EAOtD;EAOA,cAAA,CAAA,EAAA,MAAiB;EAIjB;EAMA,aAAA,CAAA,EAAa,MAAA;EAAA;UACpB,CAAA,EAAA,MAAA;MACC,EAAA,MAAA,CAAA,EAAA,OAAA;;AAQM,UA3IA,cAAA,CAoJH;EAKG,IAAA,EAAA,UAAA;EAAqB,QAAA,EAAA;IAK1B,IAAA,EAAA,MAAA;IACG,WAAA,CAAA,EAAA,MAAA;IAAK,UAAA,CAAA,EAAA,MAAA;EAIH,CAAA;AAajB;AAKY,UA9KK,YAAA,CA8KU;EAAA,WAAA,CAAA,EAAA,MAAA,GA7KF,MA6KE;;;;;;;;;;;;AAwC3B;AAWA;AAeA;EAMY,aAAA,CAAW,EAAA,MAAA,GAAA,MAAA,EAAA,GAtOe,MAsOf;EAIX,SAAA,CAAA,EAAA,MAAe,GAzOJ,MAyOI;EAAA,UAAA,CAAA,EAAA,MAAA;UACpB,CAAA,EAAA,MAAA;OACF,CAAA,EAAA,MAAA,GAxOc,MAwOd;gBAA0B,CAAA,EAAA,MAAA;WAAR,CAAA,EAAA,CAAA,GAAA,EAtOH,qBAsOG,EAAA,GAAA,OAAA;EAAO;EAIb,aAAO,CAAA,EAAA,MAAA;EAAA,SAAA,CAAA,EAAA,MAAA;eACf,CAAA,EAAA,OAAA;UACG,CAAA,EAAA,MAAA,GAAA,OAAA,GAAA,QAAA,GAAA,eAAA,GAAA,aAAA,GAAA,OAAA,GAAA,WAAA,GAAA,WAAA,GAAA,gBAAA,GAAA,WAAA,GAAA,KAAA,GAAA,UAAA,GAAA,wBAAA,GAAA,sBAAA;SAAkB,CAAA,EAAA,MAAA;;;;;AAe9B;;;;;AACA;;;;;AASA;AAOA;AAA6C,UApO5B,iBAAA,CAoO4B;KAChC,EAAA,MAAA;SADwC,CAAA,EAAA,MAAA;EAAiB,KAAA,CAAA,EAAA,MAAA;EAKrD,KAAA,CAAA,EAAA;IAAwB,aAAA,CAAA,EAAA,MAAA;IAErB,iBAAA,CAAA,EAAA,MAAA;IAF6B,YAAA,CAAA,EAAA,MAAA;IAAiB,YAAA,CAAA,EAAA,MAAA;IAOjD,aAAA,CAAA,EAAA,MAAA;IAAwC,gBAAA,CAAA,EAAA,MAAA;IAErC,oBAAA,CAAA,EAAA,MAAA;IACP,eAAA,CAAA,EAAA,MAAA;;EAHqE,iBAAA,CAAA,EAAA,MAAA;EAQtE,YAAA,CAAA,EAAA,MAAA;EAAmB,IAAA,CAAA,EAAA,MAAA;;AAE3B,UAvOa,YAAA,SAAqB,iBAuOlC,CAAA;SACA,EAAA,MAAA;WACA,CAAA,EAAA,MAAA;aACA,CAAA,EAAA,MAAA,EAAA;;AAEA,UAtOa,QAAA,CAsOb;MACA,EAAA,MAAA;WACA,EAAA,MAAA;KACA,EAAA,MAAA;;AAEa,UArOA,gBAAA,SAAyB,iBAsOd,CAAA;EAGX,SAAA,EAxOJ,QAwOoB,EAAA;EAAA,WAAA,CAAA,EAAA,MAAA,EAAA;;AAwCZ,UA5QJ,4BAAA,SAAqC,iBA4QjC,CAAA;SACD,EAAA,MAAA;WAEV,EA7QG,QA6QH,EAAA;EAAW,SAAA,CAAA,EAAA,MAAA;EASJ,WAAA,CAAA,EAAA,MAAY,EAAA;;AAKlB,UAtRM,aAAA,CAsRN;OACH,EAAA;IAIK,OAAA,EAAA,MAAA;IAUK,IAAA,CAAA,EAAA,MAAA;IAAW,KAAA,CAAA,EAAA,MAAA,GAAA,IAAA;IAQZ,IAAA,CAAA,EAAQ,MAAA;EAUR,CAAA;EAOA,MAAA,CAAA,EAAA,MAAQ;EAOR;EASA,UAAA,CAAA,EAAA,MAAc;AAU/B;AAOiB,UAxVA,iBAAA,CAwVqB;EAU1B,SAAA,EAAA,MAAA,EAAA;AAaZ;AAA6B,UA3WZ,SAAA,CA2WY;KACD,CAAA,EAAA,MAAA;SAAP,CAAA,EAAA,MAAA;eAAR,CAAA,EAAA,MAAA;;AAgBU,UAtXN,aAAA,CAsXM;EAkBN,KAAA,CAAA,EAvYP,SAuYO;EAOA,MAAA,CAAA,EA7YN,SA6YM,EAAiB;;AAQxB,UA7YO,aAAA,CA6YP;OAMC,EAAA,MAAA,GAAA;IAkCgB,OAAA,EAAA,MAAA;IAA0B,WAAA,CAAA,EAAA,MAAA;;EAW1B,MAAA,CAAA,EAAA,MAAA;EAGV;AAqBjB;;;;;WAOW,CAAA,EAtdG,QAsdH,EAAA;SAEgB,CAAA,EAAA,MAAA;WAA0B,CAAA,EAAA,MAAA;;AAC1B,UApdV,qBAAA,CAodU;;;;;YA/cf;;;;;eACG;;;;;;;;UAIE,aAAA;;;;;;;;;;;;UAaA,eAAA,SAAwB;;;;KAK7B,eAAA,GACR,eACA,mBACA,+BACA,gBACA,oBACA,gBACA,gBACA,wBACA,gBACA;UA8Ba,gBAAA;;;;;;;;;;UAWA,eAAA;;;;;;;;;;;;;;UAeA,WAAA;;;;;KAML,WAAA;KAIA,eAAA,SACL,0BACF,kBAAkB,QAAQ;UAId,OAAA;SACR;YACG,kBAAkB;;;;;qBAKT;oBACD;;UAEV;;;;;;KAOE,WAAA,GAAc,KAAK;KACnB,oBAAA,GAAuB,KAAK;UASvB,mBAAA;;;sBAGK;;;UAIL,2BAAA,SAAoC;aACxC;;;UAII,uBAAA,SAAgC;;oBAE7B;;;;UAKH,uCAAA,SAAgD;;oBAE7C;aACP;;;;KAKD,mBAAA,GACR,0BACA,8BACA,0CACA,gBACA,oBACA,gBACA,gBACA,wBACA,gBACA;UAEa,WAAA;YACL;;UAGK,gBAAA;;;;;;;;;;;;;;;;;;;;YAmCL;;;;;qBAKS;oBACD;;UAEV;;;;;;UASO,YAAA;;;;;WAKN;QACH;;;;aAIK;;;;;;;;;;kBAUK;;;;;UAQD,QAAA;;;;;WAKN;;;;;;;;UAKM,SAAA;;SAER;;;;UAKQ,QAAA;;;;eAIF;;UAGE,gBAAA;;;;;;;;;UASA,cAAA;;;;;WAKN;;;;;;;;UAKM,oBAAA;;WAEN;;;;UAKM,qBAAA;;;;;eAKF;;KAKH,iBAAA;UAaK,YAAA;aACJ,QAAQ,OAAO;;;;;;;;;;;;;;;;QAgBpB;;;;;;;;;;;;;;;;;UAkBS,eAAA;;;;;;UAOA,iBAAA;;;;;;;;UAQP;;;;;;WAMC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAkCgB,0BAA0B;;;;;;;;;;;aAWxC;;UAGI,cAAA;;;;;;;;;;;;;;;;UAqBA,eAAA;;;;UAIP;UACA;aACG;WACF;;2BAEgB,0BAA0B;aACxC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vector-types.d.cts","names":[],"sources":["../src/vector-types.ts"],"sourcesContent":[],"mappings":";UAAiB,iBAAA;EAAA,IAAA,CAAA,EAAA,MAAA;EAKA,IAAA,CAAA,EAAA,MAAA;;AAGM,UAHN,gBAAA,CAGM;MAAZ,EAAA,MAAA;EAAG,SAAA,EAAA,MAAA;EAGG,OAAA,EAHN,GAGM,CAAA,MAAW,EAHL,
|
|
1
|
+
{"version":3,"file":"vector-types.d.cts","names":[],"sources":["../src/vector-types.ts"],"sourcesContent":[],"mappings":";UAAiB,iBAAA;EAAA,IAAA,CAAA,EAAA,MAAA;EAKA,IAAA,CAAA,EAAA,MAAA;;AAGM,UAHN,gBAAA,CAGM;MAAZ,EAAA,MAAA;EAAG,SAAA,EAAA,MAAA;EAGG,OAAA,EAHN,GAGM,CAAA,MAAW,EAHL,WAMJ,CAAA;AAGnB;AAOiB,UAbA,WAAA,CAaW;EAOhB,EAAA,EAAA,MAAA;EAAY,MAAA,EAAA,MAAA,EAAA;UAAG,CAAA,EAjBd,MAiBc,CAAA,MAAA,EAAA,OAAA,CAAA;;AAAyC,UAdnD,WAAA,CAcmD;EAAW,EAAA,EAAA,MAAA;;aAXlE;;;UAII,WAAA;;;;;;KAOL,YAAA,GAAe,yBAAyB,gBAAgB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vector-types.d.ts","names":[],"sources":["../src/vector-types.ts"],"sourcesContent":[],"mappings":";UAAiB,iBAAA;EAAA,IAAA,CAAA,EAAA,MAAA;EAKA,IAAA,CAAA,EAAA,MAAA;;AAGM,UAHN,gBAAA,CAGM;MAAZ,EAAA,MAAA;EAAG,SAAA,EAAA,MAAA;EAGG,OAAA,EAHN,GAGM,CAAA,MAAW,EAHL,
|
|
1
|
+
{"version":3,"file":"vector-types.d.ts","names":[],"sources":["../src/vector-types.ts"],"sourcesContent":[],"mappings":";UAAiB,iBAAA;EAAA,IAAA,CAAA,EAAA,MAAA;EAKA,IAAA,CAAA,EAAA,MAAA;;AAGM,UAHN,gBAAA,CAGM;MAAZ,EAAA,MAAA;EAAG,SAAA,EAAA,MAAA;EAGG,OAAA,EAHN,GAGM,CAAA,MAAW,EAHL,WAMV,CAAM;AAGnB;AAOiB,UAbA,WAAA,CAaW;EAOhB,EAAA,EAAA,MAAA;EAAY,MAAA,EAAA,MAAA,EAAA;UAAG,CAAA,EAjBd,MAiBc,CAAA,MAAA,EAAA,OAAA,CAAA;;AAAyC,UAdnD,WAAA,CAcmD;EAAW,EAAA,EAAA,MAAA;;aAXlE;;;UAII,WAAA;;;;;;KAOL,YAAA,GAAe,yBAAyB,gBAAgB"}
|
package/dist/video.cjs
CHANGED
|
@@ -3,6 +3,7 @@ const require_router = require('./router.cjs');
|
|
|
3
3
|
const require_sse_writer = require('./sse-writer.cjs');
|
|
4
4
|
const require_chaos = require('./chaos.cjs');
|
|
5
5
|
const require_recorder = require('./recorder.cjs');
|
|
6
|
+
const require_transcription = require('./transcription.cjs');
|
|
6
7
|
|
|
7
8
|
//#region src/video.ts
|
|
8
9
|
const VIDEO_STATE_MAX_ENTRIES = 1e4;
|
|
@@ -70,8 +71,23 @@ async function handleVideoCreate(req, res, raw, fixtures, journal, defaults, set
|
|
|
70
71
|
setCorsHeaders(res);
|
|
71
72
|
const path = req.url ?? "/v1/videos";
|
|
72
73
|
const method = req.method ?? "POST";
|
|
74
|
+
const contentType = Array.isArray(req.headers["content-type"]) ? req.headers["content-type"][0] : req.headers["content-type"];
|
|
75
|
+
const isMultipart = (contentType ?? "").toLowerCase().includes("multipart/form-data");
|
|
73
76
|
let videoReq;
|
|
74
|
-
|
|
77
|
+
if (isMultipart) {
|
|
78
|
+
const boundary = require_transcription.extractBoundary(contentType);
|
|
79
|
+
const prompt = require_transcription.extractFormField(raw, "prompt", boundary);
|
|
80
|
+
const model = require_transcription.extractFormField(raw, "model", boundary);
|
|
81
|
+
const size = require_transcription.extractFormField(raw, "size", boundary);
|
|
82
|
+
const secondsRaw = require_transcription.extractFormField(raw, "seconds", boundary);
|
|
83
|
+
videoReq = { prompt: prompt ?? "" };
|
|
84
|
+
if (model !== void 0) videoReq.model = model;
|
|
85
|
+
if (size !== void 0) videoReq.size = size;
|
|
86
|
+
if (secondsRaw !== void 0) {
|
|
87
|
+
const secondsNum = Number(secondsRaw);
|
|
88
|
+
videoReq.seconds = Number.isNaN(secondsNum) ? secondsRaw : secondsNum;
|
|
89
|
+
}
|
|
90
|
+
} else try {
|
|
75
91
|
videoReq = JSON.parse(raw);
|
|
76
92
|
} catch (parseErr) {
|
|
77
93
|
const detail = parseErr instanceof Error ? parseErr.message : "unknown";
|
package/dist/video.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"video.cjs","names":["flattenHeaders","getContext","getTestId","matchFixture","applyChaos","resolveStrictMode","strictOverrideField","proxyAndRecord","resolveResponse","isErrorResponse","serializeErrorResponse","isVideoResponse"],"sources":["../src/video.ts"],"sourcesContent":["import type * as http from \"node:http\";\nimport type { ChatCompletionRequest, Fixture, HandlerDefaults, VideoResponse } from \"./types.js\";\nimport {\n isVideoResponse,\n isErrorResponse,\n serializeErrorResponse,\n flattenHeaders,\n getTestId,\n resolveResponse,\n resolveStrictMode,\n strictOverrideField,\n getContext,\n} from \"./helpers.js\";\nimport { matchFixture } from \"./router.js\";\nimport { writeErrorResponse } from \"./sse-writer.js\";\nimport type { Journal } from \"./journal.js\";\nimport { applyChaos } from \"./chaos.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\n\ninterface VideoRequest {\n model?: string;\n prompt: string;\n [key: string]: unknown;\n}\n\n// ─── VideoStateMap with TTL and size bound ────────────────────────────────\n\nconst VIDEO_STATE_MAX_ENTRIES = 10_000;\nconst VIDEO_STATE_TTL_MS = 3_600_000; // 1 hour\n\ninterface VideoStateEntry {\n video: VideoResponse[\"video\"];\n createdAt: number;\n}\n\n/**\n * A Map wrapper for video state that enforces a maximum size and per-entry TTL.\n * Entries older than VIDEO_STATE_TTL_MS are lazily evicted on `get`.\n * When the map exceeds VIDEO_STATE_MAX_ENTRIES on `set`, the oldest entries\n * are removed to stay within bounds.\n */\nexport class VideoStateMap {\n private readonly entries = new Map<string, VideoStateEntry>();\n private readonly sweepTimer: ReturnType<typeof setInterval>;\n\n constructor() {\n // Proactive sweep every 60 seconds to evict expired entries\n this.sweepTimer = setInterval(() => {\n const now = Date.now();\n for (const [key, entry] of this.entries) {\n if (now - entry.createdAt > VIDEO_STATE_TTL_MS) {\n this.entries.delete(key);\n }\n }\n }, 60_000);\n // Allow the process to exit even if the timer is still running\n if (this.sweepTimer.unref) {\n this.sweepTimer.unref();\n }\n }\n\n getEntry(key: string): { video: VideoResponse[\"video\"]; createdAtUnix: number } | undefined {\n const entry = this.entries.get(key);\n if (!entry) return undefined;\n if (Date.now() - entry.createdAt > VIDEO_STATE_TTL_MS) {\n this.entries.delete(key);\n return undefined;\n }\n return { video: entry.video, createdAtUnix: Math.floor(entry.createdAt / 1000) };\n }\n\n getCreatedAtUnix(key: string): number | undefined {\n const e = this.getEntry(key);\n return e?.createdAtUnix;\n }\n\n set(key: string, video: VideoResponse[\"video\"]): void {\n this.entries.set(key, { video, createdAt: Date.now() });\n // Evict oldest entries if over capacity\n if (this.entries.size > VIDEO_STATE_MAX_ENTRIES) {\n const excess = this.entries.size - VIDEO_STATE_MAX_ENTRIES;\n const iter = this.entries.keys();\n for (let i = 0; i < excess; i++) {\n const next = iter.next();\n if (!next.done) this.entries.delete(next.value);\n }\n }\n }\n\n delete(key: string): boolean {\n return this.entries.delete(key);\n }\n\n clear(): void {\n this.entries.clear();\n }\n\n destroy(): void {\n clearInterval(this.sweepTimer);\n this.entries.clear();\n }\n\n get size(): number {\n return this.entries.size;\n }\n}\n\nexport async function handleVideoCreate(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n raw: string,\n fixtures: Fixture[],\n journal: Journal,\n defaults: HandlerDefaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n videoStates: VideoStateMap,\n): Promise<void> {\n setCorsHeaders(res);\n const path = req.url ?? \"/v1/videos\";\n const method = req.method ?? \"POST\";\n\n let videoReq: VideoRequest;\n try {\n videoReq = JSON.parse(raw) as VideoRequest;\n } catch (parseErr) {\n const detail = parseErr instanceof Error ? parseErr.message : \"unknown\";\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n error: {\n message: `Malformed JSON: ${detail}`,\n type: \"invalid_request_error\",\n code: \"invalid_json\",\n },\n }),\n );\n return;\n }\n\n if (!videoReq.prompt) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n error: { message: \"Missing required parameter: 'prompt'\", type: \"invalid_request_error\" },\n }),\n );\n return;\n }\n\n const syntheticReq: ChatCompletionRequest = {\n model: videoReq.model ?? \"sora-2\",\n messages: [{ role: \"user\", content: videoReq.prompt }],\n _endpointType: \"video\",\n _context: getContext(req),\n };\n\n const testId = getTestId(req);\n const fixture = matchFixture(\n fixtures,\n syntheticReq,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\n );\n\n if (fixture) {\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n defaults.logger.debug(`Fixture matched: ${JSON.stringify(fixture.match).slice(0, 120)}`);\n } else {\n defaults.logger.debug(`No fixture matched for request`);\n }\n\n if (\n applyChaos(\n res,\n fixture,\n defaults.chaos,\n req.headers,\n journal,\n { method, path, headers: flattenHeaders(req.headers), body: syntheticReq },\n fixture ? \"fixture\" : \"proxy\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n if (!fixture) {\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n if (effectiveStrict) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: 503,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 503,\n JSON.stringify({\n error: {\n message: \"Strict mode: no fixture matched\",\n type: \"invalid_request_error\",\n code: \"no_fixture_match\",\n },\n }),\n );\n return;\n }\n if (defaults.record) {\n const outcome = await proxyAndRecord(\n req,\n res,\n syntheticReq,\n \"openai\",\n req.url ?? \"/v1/videos\",\n fixtures,\n defaults,\n raw,\n );\n if (outcome === \"handled_by_hook\") return;\n if (outcome !== \"not_configured\") {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: res.statusCode ?? 200, fixture: null, source: \"proxy\" },\n });\n return;\n }\n }\n\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: 404,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 404,\n JSON.stringify({\n error: {\n message: \"No fixture matched\",\n type: \"invalid_request_error\",\n code: \"no_fixture_match\",\n },\n }),\n );\n return;\n }\n\n const response = await resolveResponse(fixture, syntheticReq);\n\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status, fixture },\n });\n writeErrorResponse(res, status, serializeErrorResponse(response), {\n retryAfter: response.retryAfter,\n });\n return;\n }\n\n if (!isVideoResponse(response)) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 500, fixture },\n });\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({\n error: { message: \"Fixture response is not a video type\", type: \"server_error\" },\n }),\n );\n return;\n }\n\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 200, fixture },\n });\n\n const video = response.video;\n\n // Store for GET status checks\n const stateKey = `${testId}:${video.id}`;\n videoStates.set(stateKey, video);\n const created_at = videoStates.getCreatedAtUnix(stateKey)!;\n\n if (video.status === \"completed\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ id: video.id, status: video.status, url: video.url, created_at }));\n } else {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ id: video.id, status: video.status, created_at }));\n }\n}\n\nexport function handleVideoStatus(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n videoId: string,\n journal: Journal,\n defaults: HandlerDefaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n videoStates: VideoStateMap,\n): void {\n setCorsHeaders(res);\n const path = req.url ?? `/v1/videos/${videoId}`;\n const method = req.method ?? \"GET\";\n\n if (\n applyChaos(\n res,\n null,\n defaults.chaos,\n req.headers,\n journal,\n { method, path, headers: flattenHeaders(req.headers), body: null },\n \"internal\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n const testId = getTestId(req);\n const stateKey = `${testId}:${videoId}`;\n const entry = videoStates.getEntry(stateKey);\n\n if (!entry) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 404, fixture: null },\n });\n writeErrorResponse(\n res,\n 404,\n JSON.stringify({ error: { message: `Video ${videoId} not found`, type: \"not_found\" } }),\n );\n return;\n }\n\n const { video, createdAtUnix: created_at } = entry;\n\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 200, fixture: null },\n });\n\n const body: Record<string, unknown> = {\n id: video.id,\n status: video.status,\n created_at,\n };\n if (video.url) body.url = video.url;\n\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"video.cjs","names":["extractBoundary","extractFormField","flattenHeaders","getContext","getTestId","matchFixture","applyChaos","resolveStrictMode","strictOverrideField","proxyAndRecord","resolveResponse","isErrorResponse","serializeErrorResponse","isVideoResponse"],"sources":["../src/video.ts"],"sourcesContent":["import type * as http from \"node:http\";\nimport type { ChatCompletionRequest, Fixture, HandlerDefaults, VideoResponse } from \"./types.js\";\nimport {\n isVideoResponse,\n isErrorResponse,\n serializeErrorResponse,\n flattenHeaders,\n getTestId,\n resolveResponse,\n resolveStrictMode,\n strictOverrideField,\n getContext,\n} from \"./helpers.js\";\nimport { matchFixture } from \"./router.js\";\nimport { writeErrorResponse } from \"./sse-writer.js\";\nimport type { Journal } from \"./journal.js\";\nimport { applyChaos } from \"./chaos.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\nimport { extractBoundary, extractFormField } from \"./transcription.js\";\n\ninterface VideoRequest {\n model?: string;\n prompt: string;\n [key: string]: unknown;\n}\n\n// ─── VideoStateMap with TTL and size bound ────────────────────────────────\n\nconst VIDEO_STATE_MAX_ENTRIES = 10_000;\nconst VIDEO_STATE_TTL_MS = 3_600_000; // 1 hour\n\ninterface VideoStateEntry {\n video: VideoResponse[\"video\"];\n createdAt: number;\n}\n\n/**\n * A Map wrapper for video state that enforces a maximum size and per-entry TTL.\n * Entries older than VIDEO_STATE_TTL_MS are lazily evicted on `get`.\n * When the map exceeds VIDEO_STATE_MAX_ENTRIES on `set`, the oldest entries\n * are removed to stay within bounds.\n */\nexport class VideoStateMap {\n private readonly entries = new Map<string, VideoStateEntry>();\n private readonly sweepTimer: ReturnType<typeof setInterval>;\n\n constructor() {\n // Proactive sweep every 60 seconds to evict expired entries\n this.sweepTimer = setInterval(() => {\n const now = Date.now();\n for (const [key, entry] of this.entries) {\n if (now - entry.createdAt > VIDEO_STATE_TTL_MS) {\n this.entries.delete(key);\n }\n }\n }, 60_000);\n // Allow the process to exit even if the timer is still running\n if (this.sweepTimer.unref) {\n this.sweepTimer.unref();\n }\n }\n\n getEntry(key: string): { video: VideoResponse[\"video\"]; createdAtUnix: number } | undefined {\n const entry = this.entries.get(key);\n if (!entry) return undefined;\n if (Date.now() - entry.createdAt > VIDEO_STATE_TTL_MS) {\n this.entries.delete(key);\n return undefined;\n }\n return { video: entry.video, createdAtUnix: Math.floor(entry.createdAt / 1000) };\n }\n\n getCreatedAtUnix(key: string): number | undefined {\n const e = this.getEntry(key);\n return e?.createdAtUnix;\n }\n\n set(key: string, video: VideoResponse[\"video\"]): void {\n this.entries.set(key, { video, createdAt: Date.now() });\n // Evict oldest entries if over capacity\n if (this.entries.size > VIDEO_STATE_MAX_ENTRIES) {\n const excess = this.entries.size - VIDEO_STATE_MAX_ENTRIES;\n const iter = this.entries.keys();\n for (let i = 0; i < excess; i++) {\n const next = iter.next();\n if (!next.done) this.entries.delete(next.value);\n }\n }\n }\n\n delete(key: string): boolean {\n return this.entries.delete(key);\n }\n\n clear(): void {\n this.entries.clear();\n }\n\n destroy(): void {\n clearInterval(this.sweepTimer);\n this.entries.clear();\n }\n\n get size(): number {\n return this.entries.size;\n }\n}\n\nexport async function handleVideoCreate(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n raw: string,\n fixtures: Fixture[],\n journal: Journal,\n defaults: HandlerDefaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n videoStates: VideoStateMap,\n): Promise<void> {\n setCorsHeaders(res);\n const path = req.url ?? \"/v1/videos\";\n const method = req.method ?? \"POST\";\n\n const contentType = Array.isArray(req.headers[\"content-type\"])\n ? req.headers[\"content-type\"][0]\n : req.headers[\"content-type\"];\n const isMultipart = (contentType ?? \"\").toLowerCase().includes(\"multipart/form-data\");\n\n let videoReq: VideoRequest;\n if (isMultipart) {\n // The OpenAI SDK (6.28.0+) sends POST /v1/videos as multipart/form-data;\n // older SDKs sent JSON for a File-less body. Parse the form fields into the\n // same shape the JSON path produces, reusing the transcription multipart\n // helpers. Numeric fields (e.g. `seconds`) arrive as strings and are\n // coerced to numbers to match the JSON body's types.\n const boundary = extractBoundary(contentType);\n const prompt = extractFormField(raw, \"prompt\", boundary);\n const model = extractFormField(raw, \"model\", boundary);\n const size = extractFormField(raw, \"size\", boundary);\n const secondsRaw = extractFormField(raw, \"seconds\", boundary);\n videoReq = { prompt: prompt ?? \"\" };\n if (model !== undefined) videoReq.model = model;\n if (size !== undefined) videoReq.size = size;\n if (secondsRaw !== undefined) {\n const secondsNum = Number(secondsRaw);\n videoReq.seconds = Number.isNaN(secondsNum) ? secondsRaw : secondsNum;\n }\n } else {\n try {\n videoReq = JSON.parse(raw) as VideoRequest;\n } catch (parseErr) {\n const detail = parseErr instanceof Error ? parseErr.message : \"unknown\";\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n error: {\n message: `Malformed JSON: ${detail}`,\n type: \"invalid_request_error\",\n code: \"invalid_json\",\n },\n }),\n );\n return;\n }\n }\n\n if (!videoReq.prompt) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n error: { message: \"Missing required parameter: 'prompt'\", type: \"invalid_request_error\" },\n }),\n );\n return;\n }\n\n const syntheticReq: ChatCompletionRequest = {\n model: videoReq.model ?? \"sora-2\",\n messages: [{ role: \"user\", content: videoReq.prompt }],\n _endpointType: \"video\",\n _context: getContext(req),\n };\n\n const testId = getTestId(req);\n const fixture = matchFixture(\n fixtures,\n syntheticReq,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\n );\n\n if (fixture) {\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n defaults.logger.debug(`Fixture matched: ${JSON.stringify(fixture.match).slice(0, 120)}`);\n } else {\n defaults.logger.debug(`No fixture matched for request`);\n }\n\n if (\n applyChaos(\n res,\n fixture,\n defaults.chaos,\n req.headers,\n journal,\n { method, path, headers: flattenHeaders(req.headers), body: syntheticReq },\n fixture ? \"fixture\" : \"proxy\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n if (!fixture) {\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n if (effectiveStrict) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: 503,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 503,\n JSON.stringify({\n error: {\n message: \"Strict mode: no fixture matched\",\n type: \"invalid_request_error\",\n code: \"no_fixture_match\",\n },\n }),\n );\n return;\n }\n if (defaults.record) {\n const outcome = await proxyAndRecord(\n req,\n res,\n syntheticReq,\n \"openai\",\n req.url ?? \"/v1/videos\",\n fixtures,\n defaults,\n raw,\n );\n if (outcome === \"handled_by_hook\") return;\n if (outcome !== \"not_configured\") {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: res.statusCode ?? 200, fixture: null, source: \"proxy\" },\n });\n return;\n }\n }\n\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: 404,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 404,\n JSON.stringify({\n error: {\n message: \"No fixture matched\",\n type: \"invalid_request_error\",\n code: \"no_fixture_match\",\n },\n }),\n );\n return;\n }\n\n const response = await resolveResponse(fixture, syntheticReq);\n\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status, fixture },\n });\n writeErrorResponse(res, status, serializeErrorResponse(response), {\n retryAfter: response.retryAfter,\n });\n return;\n }\n\n if (!isVideoResponse(response)) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 500, fixture },\n });\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({\n error: { message: \"Fixture response is not a video type\", type: \"server_error\" },\n }),\n );\n return;\n }\n\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 200, fixture },\n });\n\n const video = response.video;\n\n // Store for GET status checks\n const stateKey = `${testId}:${video.id}`;\n videoStates.set(stateKey, video);\n const created_at = videoStates.getCreatedAtUnix(stateKey)!;\n\n if (video.status === \"completed\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ id: video.id, status: video.status, url: video.url, created_at }));\n } else {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ id: video.id, status: video.status, created_at }));\n }\n}\n\nexport function handleVideoStatus(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n videoId: string,\n journal: Journal,\n defaults: HandlerDefaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n videoStates: VideoStateMap,\n): void {\n setCorsHeaders(res);\n const path = req.url ?? `/v1/videos/${videoId}`;\n const method = req.method ?? \"GET\";\n\n if (\n applyChaos(\n res,\n null,\n defaults.chaos,\n req.headers,\n journal,\n { method, path, headers: flattenHeaders(req.headers), body: null },\n \"internal\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n const testId = getTestId(req);\n const stateKey = `${testId}:${videoId}`;\n const entry = videoStates.getEntry(stateKey);\n\n if (!entry) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 404, fixture: null },\n });\n writeErrorResponse(\n res,\n 404,\n JSON.stringify({ error: { message: `Video ${videoId} not found`, type: \"not_found\" } }),\n );\n return;\n }\n\n const { video, createdAtUnix: created_at } = entry;\n\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 200, fixture: null },\n });\n\n const body: Record<string, unknown> = {\n id: video.id,\n status: video.status,\n created_at,\n };\n if (video.url) body.url = video.url;\n\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n}\n"],"mappings":"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"}
|
package/dist/video.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"video.d.cts","names":[],"sources":["../src/video.ts"],"sourcesContent":[],"mappings":";;;;;;;;
|
|
1
|
+
{"version":3,"file":"video.d.cts","names":[],"sources":["../src/video.ts"],"sourcesContent":[],"mappings":";;;;;;;;AA0CA;;;;AAmCuC,cAnC1B,aAAA,CAmC0B;EA+BjB,iBAAA,OAAiB;EAAA,iBAAA,UAAA;aAC3B,CAAA;UACL,CAAA,GAAK,EAAA,MAAA,CAAA,EAAA;IAEA,KAAA,EAlDsB,aAkDtB,CAAA,OAAA,CAAA;IACD,aAAA,EAAA,MAAA;MACC,SAAA;kBACiB,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,MAAA,GAAA,SAAA;KACd,CAAA,GAAA,EAAA,MAAA,EAAA,KAAA,EAvCW,aAuCX,CAAA,OAAA,CAAA,CAAA,EAAA,IAAA;QACZ,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,OAAA;EAAO,KAAA,CAAA,CAAA,EAAA,IAAA;EAsPM,OAAA,CAAA,CAAA,EAAA,IAAA;EAAiB,IAAA,IAAA,CAAA,CAAA,EAAA,MAAA;;AAE1B,iBAjQe,iBAAA,CAiQV,GAAA,EAhQL,MAAA,CAAK,eAgQA,EAAA,GAAA,EA/PL,MAAA,CAAK,cA+PA,EAAA,GAAA,EAAA,MAAA,EAAA,QAAA,EA7PA,OA6PA,EAAA,EAAA,OAAA,EA5PD,OA4PC,EAAA,QAAA,EA3PA,eA2PA,EAAA,cAAA,EAAA,CAAA,GAAA,EA1PY,MAAA,CAAK,cA0PjB,EAAA,GAAA,IAAA,EAAA,WAAA,EAzPG,aAyPH,CAAA,EAxPT,OAwPS,CAAA,IAAA,CAAA;AAED,iBAJK,iBAAA,CAIL,GAAA,EAHJ,MAAA,CAAK,eAGD,EAAA,GAAA,EAFJ,MAAA,CAAK,cAED,EAAA,OAAA,EAAA,MAAA,EAAA,OAAA,EAAA,OAAA,EAAA,QAAA,EACC,eADD,EAAA,cAAA,EAAA,CAAA,GAAA,EAEa,MAAA,CAAK,cAFlB,EAAA,GAAA,IAAA,EAAA,WAAA,EAGI,aAHJ,CAAA,EAAA,IAAA"}
|
package/dist/video.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"video.d.ts","names":[],"sources":["../src/video.ts"],"sourcesContent":[],"mappings":";;;;;;;;
|
|
1
|
+
{"version":3,"file":"video.d.ts","names":[],"sources":["../src/video.ts"],"sourcesContent":[],"mappings":";;;;;;;;AA0CA;;;;AAmCuC,cAnC1B,aAAA,CAmC0B;EA+BjB,iBAAA,OAAiB;EAAA,iBAAA,UAAA;aAC3B,CAAA;UACL,CAAA,GAAK,EAAA,MAAA,CAAA,EAAA;IAEA,KAAA,EAlDsB,aAkDtB,CAAA,OAAA,CAAA;IACD,aAAA,EAAA,MAAA;MACC,SAAA;kBACiB,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,MAAA,GAAA,SAAA;KACd,CAAA,GAAA,EAAA,MAAA,EAAA,KAAA,EAvCW,aAuCX,CAAA,OAAA,CAAA,CAAA,EAAA,IAAA;QACZ,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,OAAA;EAAO,KAAA,CAAA,CAAA,EAAA,IAAA;EAsPM,OAAA,CAAA,CAAA,EAAA,IAAA;EAAiB,IAAA,IAAA,CAAA,CAAA,EAAA,MAAA;;AAE1B,iBAjQe,iBAAA,CAiQV,GAAA,EAhQL,MAAA,CAAK,eAgQA,EAAA,GAAA,EA/PL,MAAA,CAAK,cA+PA,EAAA,GAAA,EAAA,MAAA,EAAA,QAAA,EA7PA,OA6PA,EAAA,EAAA,OAAA,EA5PD,OA4PC,EAAA,QAAA,EA3PA,eA2PA,EAAA,cAAA,EAAA,CAAA,GAAA,EA1PY,MAAA,CAAK,cA0PjB,EAAA,GAAA,IAAA,EAAA,WAAA,EAzPG,aAyPH,CAAA,EAxPT,OAwPS,CAAA,IAAA,CAAA;AAED,iBAJK,iBAAA,CAIL,GAAA,EAHJ,MAAA,CAAK,eAGD,EAAA,GAAA,EAFJ,MAAA,CAAK,cAED,EAAA,OAAA,EAAA,MAAA,EAAA,OAAA,EAAA,OAAA,EAAA,QAAA,EACC,eADD,EAAA,cAAA,EAAA,CAAA,GAAA,EAEa,MAAA,CAAK,cAFlB,EAAA,GAAA,IAAA,EAAA,WAAA,EAGI,aAHJ,CAAA,EAAA,IAAA"}
|
package/dist/video.js
CHANGED
|
@@ -3,6 +3,7 @@ import { matchFixture } from "./router.js";
|
|
|
3
3
|
import { writeErrorResponse } from "./sse-writer.js";
|
|
4
4
|
import { applyChaos } from "./chaos.js";
|
|
5
5
|
import { proxyAndRecord } from "./recorder.js";
|
|
6
|
+
import { extractBoundary, extractFormField } from "./transcription.js";
|
|
6
7
|
|
|
7
8
|
//#region src/video.ts
|
|
8
9
|
const VIDEO_STATE_MAX_ENTRIES = 1e4;
|
|
@@ -70,8 +71,23 @@ async function handleVideoCreate(req, res, raw, fixtures, journal, defaults, set
|
|
|
70
71
|
setCorsHeaders(res);
|
|
71
72
|
const path = req.url ?? "/v1/videos";
|
|
72
73
|
const method = req.method ?? "POST";
|
|
74
|
+
const contentType = Array.isArray(req.headers["content-type"]) ? req.headers["content-type"][0] : req.headers["content-type"];
|
|
75
|
+
const isMultipart = (contentType ?? "").toLowerCase().includes("multipart/form-data");
|
|
73
76
|
let videoReq;
|
|
74
|
-
|
|
77
|
+
if (isMultipart) {
|
|
78
|
+
const boundary = extractBoundary(contentType);
|
|
79
|
+
const prompt = extractFormField(raw, "prompt", boundary);
|
|
80
|
+
const model = extractFormField(raw, "model", boundary);
|
|
81
|
+
const size = extractFormField(raw, "size", boundary);
|
|
82
|
+
const secondsRaw = extractFormField(raw, "seconds", boundary);
|
|
83
|
+
videoReq = { prompt: prompt ?? "" };
|
|
84
|
+
if (model !== void 0) videoReq.model = model;
|
|
85
|
+
if (size !== void 0) videoReq.size = size;
|
|
86
|
+
if (secondsRaw !== void 0) {
|
|
87
|
+
const secondsNum = Number(secondsRaw);
|
|
88
|
+
videoReq.seconds = Number.isNaN(secondsNum) ? secondsRaw : secondsNum;
|
|
89
|
+
}
|
|
90
|
+
} else try {
|
|
75
91
|
videoReq = JSON.parse(raw);
|
|
76
92
|
} catch (parseErr) {
|
|
77
93
|
const detail = parseErr instanceof Error ? parseErr.message : "unknown";
|