@copilotkit/aimock 1.46.0 → 1.47.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 +12 -1
- package/README.md +4 -1
- package/dist/aws-event-stream.cjs +20 -23
- package/dist/aws-event-stream.cjs.map +1 -1
- package/dist/aws-event-stream.d.cts +0 -1
- package/dist/aws-event-stream.d.ts +0 -1
- package/dist/aws-event-stream.js +20 -24
- package/dist/aws-event-stream.js.map +1 -1
- package/dist/bedrock-converse.cjs +79 -82
- package/dist/bedrock-converse.cjs.map +1 -1
- package/dist/bedrock-converse.d.cts.map +1 -1
- package/dist/bedrock-converse.d.ts.map +1 -1
- package/dist/bedrock-converse.js +80 -83
- package/dist/bedrock-converse.js.map +1 -1
- package/dist/bedrock.cjs +112 -121
- package/dist/bedrock.cjs.map +1 -1
- package/dist/bedrock.d.cts.map +1 -1
- package/dist/bedrock.d.ts.map +1 -1
- package/dist/bedrock.js +113 -122
- package/dist/bedrock.js.map +1 -1
- package/dist/cohere.cjs +58 -106
- package/dist/cohere.cjs.map +1 -1
- package/dist/cohere.d.cts.map +1 -1
- package/dist/cohere.d.ts.map +1 -1
- package/dist/cohere.js +60 -108
- package/dist/cohere.js.map +1 -1
- package/dist/config-loader.d.cts.map +1 -1
- package/dist/config-loader.d.ts.map +1 -1
- package/dist/fixture-loader.cjs +103 -2
- package/dist/fixture-loader.cjs.map +1 -1
- package/dist/fixture-loader.d.cts.map +1 -1
- package/dist/fixture-loader.d.ts.map +1 -1
- package/dist/fixture-loader.js +104 -4
- package/dist/fixture-loader.js.map +1 -1
- package/dist/gemini-interactions.cjs +63 -121
- package/dist/gemini-interactions.cjs.map +1 -1
- package/dist/gemini-interactions.d.cts.map +1 -1
- package/dist/gemini-interactions.d.ts.map +1 -1
- package/dist/gemini-interactions.js +65 -123
- package/dist/gemini-interactions.js.map +1 -1
- package/dist/gemini.cjs +242 -155
- 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 +244 -157
- package/dist/gemini.js.map +1 -1
- package/dist/helpers.cjs +400 -7
- package/dist/helpers.cjs.map +1 -1
- package/dist/helpers.d.cts +51 -1
- package/dist/helpers.d.cts.map +1 -1
- package/dist/helpers.d.ts +51 -1
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +391 -8
- package/dist/helpers.js.map +1 -1
- package/dist/index.cjs +4 -2
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +4 -4
- package/dist/mcp-fakes.d.cts.map +1 -1
- package/dist/messages.cjs +159 -141
- package/dist/messages.cjs.map +1 -1
- package/dist/messages.d.cts.map +1 -1
- package/dist/messages.d.ts.map +1 -1
- package/dist/messages.js +161 -143
- package/dist/messages.js.map +1 -1
- package/dist/misbehavior.cjs +62 -3
- package/dist/misbehavior.cjs.map +1 -1
- package/dist/misbehavior.d.cts.map +1 -1
- package/dist/misbehavior.d.ts.map +1 -1
- package/dist/misbehavior.js +63 -4
- package/dist/misbehavior.js.map +1 -1
- package/dist/ndjson-writer.cjs +21 -23
- package/dist/ndjson-writer.cjs.map +1 -1
- package/dist/ndjson-writer.d.cts +0 -1
- package/dist/ndjson-writer.d.cts.map +1 -1
- package/dist/ndjson-writer.d.ts +0 -1
- package/dist/ndjson-writer.d.ts.map +1 -1
- package/dist/ndjson-writer.js +21 -24
- package/dist/ndjson-writer.js.map +1 -1
- package/dist/ollama.cjs +153 -147
- package/dist/ollama.cjs.map +1 -1
- package/dist/ollama.d.cts.map +1 -1
- package/dist/ollama.d.ts.map +1 -1
- package/dist/ollama.js +155 -149
- package/dist/ollama.js.map +1 -1
- package/dist/openrouter-chat.cjs +1 -1
- package/dist/openrouter-chat.js +1 -1
- package/dist/raw-validation.cjs +177 -0
- package/dist/raw-validation.cjs.map +1 -0
- package/dist/raw-validation.js +176 -0
- package/dist/raw-validation.js.map +1 -0
- package/dist/response/deliver.cjs +144 -0
- package/dist/response/deliver.cjs.map +1 -0
- package/dist/response/deliver.js +143 -0
- package/dist/response/deliver.js.map +1 -0
- package/dist/response/frame-loop.cjs +102 -0
- package/dist/response/frame-loop.cjs.map +1 -0
- package/dist/response/frame-loop.js +100 -0
- package/dist/response/frame-loop.js.map +1 -0
- package/dist/response/lifecycle.cjs +223 -0
- package/dist/response/lifecycle.cjs.map +1 -0
- package/dist/response/lifecycle.js +211 -0
- package/dist/response/lifecycle.js.map +1 -0
- package/dist/response/proxy.cjs +71 -0
- package/dist/response/proxy.cjs.map +1 -0
- package/dist/response/proxy.js +70 -0
- package/dist/response/proxy.js.map +1 -0
- package/dist/response/raw.cjs +228 -0
- package/dist/response/raw.cjs.map +1 -0
- package/dist/response/raw.js +227 -0
- package/dist/response/raw.js.map +1 -0
- package/dist/response/timing.cjs +157 -0
- package/dist/response/timing.cjs.map +1 -0
- package/dist/response/timing.js +150 -0
- package/dist/response/timing.js.map +1 -0
- package/dist/responses.cjs +269 -148
- package/dist/responses.cjs.map +1 -1
- package/dist/responses.d.cts.map +1 -1
- package/dist/responses.d.ts.map +1 -1
- package/dist/responses.js +270 -149
- package/dist/responses.js.map +1 -1
- package/dist/router.cjs +20 -4
- package/dist/router.cjs.map +1 -1
- package/dist/router.d.cts +7 -1
- package/dist/router.d.cts.map +1 -1
- package/dist/router.d.ts +7 -1
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +21 -5
- package/dist/router.js.map +1 -1
- package/dist/server.cjs +89 -120
- 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 +91 -122
- package/dist/server.js.map +1 -1
- package/dist/sse-writer.cjs +49 -30
- package/dist/sse-writer.cjs.map +1 -1
- package/dist/sse-writer.d.cts +0 -1
- package/dist/sse-writer.d.cts.map +1 -1
- package/dist/sse-writer.d.ts +0 -1
- package/dist/sse-writer.d.ts.map +1 -1
- package/dist/sse-writer.js +49 -31
- package/dist/sse-writer.js.map +1 -1
- package/dist/transcription.cjs +19 -33
- package/dist/transcription.cjs.map +1 -1
- package/dist/transcription.d.cts.map +1 -1
- package/dist/transcription.d.ts.map +1 -1
- package/dist/transcription.js +20 -34
- package/dist/transcription.js.map +1 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +173 -10
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.ts +173 -10
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/ws-framing.cjs +12 -6
- package/dist/ws-framing.cjs.map +1 -1
- package/dist/ws-framing.d.cts +2 -0
- package/dist/ws-framing.d.cts.map +1 -1
- package/dist/ws-framing.d.ts +2 -0
- package/dist/ws-framing.d.ts.map +1 -1
- package/dist/ws-framing.js +12 -6
- package/dist/ws-framing.js.map +1 -1
- package/dist/ws-gemini-live.cjs +120 -93
- package/dist/ws-gemini-live.cjs.map +1 -1
- package/dist/ws-gemini-live.js +120 -93
- package/dist/ws-gemini-live.js.map +1 -1
- package/dist/ws-realtime.cjs +80 -70
- package/dist/ws-realtime.cjs.map +1 -1
- package/dist/ws-realtime.d.cts.map +1 -1
- package/dist/ws-realtime.d.ts.map +1 -1
- package/dist/ws-realtime.js +80 -70
- package/dist/ws-realtime.js.map +1 -1
- package/dist/ws-responses.cjs +72 -53
- package/dist/ws-responses.cjs.map +1 -1
- package/dist/ws-responses.d.cts.map +1 -1
- package/dist/ws-responses.d.ts.map +1 -1
- package/dist/ws-responses.js +73 -54
- package/dist/ws-responses.js.map +1 -1
- package/package.json +1 -1
- package/skills/write-fixtures/SKILL.md +34 -2
package/dist/gemini.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gemini.cjs","names":["validateToolsField","mapGeminiFinish","renderGeminiUsage","servedToolArgs","resolveFixtureBlockOutcome","formatToMime","calculateDelay","delay","isCombinedFixtureResponse","isToolCallResponse","isTextResponse","extractOverrides","resolveReasoningForModel","flattenHeaders","renderError","isJsonObject","getContext","getTestId","matchFixtureDiagnostic","recordMatchOptions","applyChaosAsync","resolveRequestDecisions","strictNoMatchMessage","strictNoMatchLogLine","strictOverrideField","proxyAndRecord","resolveResponse","planMisbehavior","createInterruptionSignal","isErrorResponse","isAudioResponse","requireServedFunctionToolCalls","requireEmittedFunctionToolCalls"],"sources":["../src/gemini.ts"],"sourcesContent":["/**\n * Google Gemini GenerateContent API support.\n *\n * Translates incoming Gemini requests into the ChatCompletionRequest format\n * used by the fixture router, and converts fixture responses back into the\n * Gemini GenerateContent streaming (or non-streaming) format.\n */\nimport { resolveRequestDecisions, strictOverrideField } from \"./response/policy.js\";\nimport { renderError } from \"./response/errors.js\";\n\nimport type * as http from \"node:http\";\nimport type {\n AudioResponse,\n ChatCompletionRequest,\n ChatMessage,\n Fixture,\n FixtureBlock,\n HandlerDefaults,\n RecordedTimings,\n RecordProviderKey,\n ResponseOverrides,\n StreamingProfile,\n ToolCall,\n ToolDefinition,\n} from \"./types.js\";\nimport {\n isTextResponse,\n isToolCallResponse,\n isCombinedFixtureResponse,\n isErrorResponse,\n isAudioResponse,\n extractOverrides,\n requireServedFunctionToolCalls,\n requireEmittedFunctionToolCalls,\n validateToolsField,\n formatToMime,\n flattenHeaders,\n isJsonObject,\n getContext,\n getTestId,\n resolveFixtureBlockOutcome,\n resolveResponse,\n resolveReasoningForModel,\n strictNoMatchMessage,\n strictNoMatchLogLine,\n servedToolArgs,\n} from \"./helpers.js\";\nimport { matchFixtureDiagnostic, recordMatchOptions } from \"./router.js\";\nimport { writeErrorResponse, delay, calculateDelay } from \"./sse-writer.js\";\nimport { createInterruptionSignal } from \"./interruption.js\";\nimport type { Journal } from \"./journal.js\";\nimport type { Logger } from \"./logger.js\";\nimport { applyChaosAsync } from \"./chaos.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\nimport { planMisbehavior, recordMisbehaviorOutcome, type MisbehaviorPlan } from \"./misbehavior.js\";\nimport { mapGeminiFinish } from \"./response/finish.js\";\nimport { render as renderGeminiUsage } from \"./response/usage/codecs/gemini.js\";\n\n// ─── Gemini request types ───────────────────────────────────────────────────\n\ninterface GeminiPart {\n text?: string;\n thought?: boolean;\n functionCall?: { name: string; args: Record<string, unknown>; id?: string };\n functionResponse?: { name: string; response: unknown; id?: string };\n inlineData?: { mimeType: string; data: string };\n}\n\ninterface GeminiContent {\n role?: string;\n parts: GeminiPart[];\n}\n\ninterface GeminiFunctionDeclaration {\n name: string;\n description?: string;\n parameters?: object;\n parametersJsonSchema?: object;\n}\n\ninterface GeminiToolDef {\n functionDeclarations?: GeminiFunctionDeclaration[];\n}\n\ninterface GeminiRequest {\n contents?: GeminiContent[];\n systemInstruction?: GeminiContent;\n tools?: GeminiToolDef[];\n generationConfig?: {\n temperature?: number;\n maxOutputTokens?: number;\n [key: string]: unknown;\n };\n [key: string]: unknown;\n}\n\n// ─── Input conversion: Gemini → ChatCompletions messages ────────────────────\n\n/**\n * Validate the shape of a Gemini `generateContent` body.\n *\n * Returns an error detail string when the shape is wrong, or null when\n * `geminiToCompletionRequest` can safely consume it. Wrong types here used\n * to throw inside the converter (`parts.filter` on a missing `parts`,\n * iterating the characters of a string `contents`, `.flatMap` on a string\n * `tools`) and surface as 500s. A present-but-part-less content or\n * systemInstruction is tolerated (treated as no text) rather than rejected.\n */\nfunction validateGeminiBody(req: GeminiRequest): string | null {\n if (req.contents !== undefined && req.contents !== null && !Array.isArray(req.contents)) {\n return \"contents must be an array\";\n }\n if (Array.isArray(req.contents)) {\n for (let i = 0; i < req.contents.length; i++) {\n const content = req.contents[i] as unknown;\n if (content === null || typeof content !== \"object\" || Array.isArray(content)) {\n return `contents[${i}] must be an object`;\n }\n const parts = (content as { parts?: unknown }).parts;\n if (parts !== undefined && parts !== null && !Array.isArray(parts)) {\n return `contents[${i}].parts must be an array`;\n }\n }\n }\n if (req.systemInstruction !== undefined && req.systemInstruction !== null) {\n if (typeof req.systemInstruction !== \"object\" || Array.isArray(req.systemInstruction)) {\n return \"systemInstruction must be an object\";\n }\n const parts = req.systemInstruction.parts as unknown;\n if (parts !== undefined && parts !== null && !Array.isArray(parts)) {\n return \"systemInstruction.parts must be an array\";\n }\n }\n const toolsError = validateToolsField(req.tools);\n if (toolsError) return toolsError;\n if (Array.isArray(req.tools)) {\n for (const [toolIndex, tool] of req.tools.entries()) {\n if (!Array.isArray(tool.functionDeclarations)) continue;\n const declarationIndex = tool.functionDeclarations.findIndex(\n (declaration) => declaration === null,\n );\n if (declarationIndex !== -1) {\n return `tools[${toolIndex}].functionDeclarations[${declarationIndex}] must not be null`;\n }\n }\n }\n return null;\n}\n\nexport function geminiToCompletionRequest(\n req: GeminiRequest,\n model: string,\n stream: boolean,\n): ChatCompletionRequest {\n const messages: ChatMessage[] = [];\n\n // systemInstruction → system message\n if (req.systemInstruction) {\n const text = (req.systemInstruction.parts ?? [])\n .filter((p) => p !== null && p !== undefined && p.text !== undefined)\n .map((p) => p.text!)\n .join(\"\");\n if (text) {\n messages.push({ role: \"system\", content: text });\n }\n }\n\n if (req.contents) {\n let callCounter = 0;\n for (const content of req.contents) {\n const role = content.role ?? \"user\";\n\n if (role === \"user\") {\n // Check for functionResponse parts\n const parts = content.parts ?? [];\n const funcResponses = parts.filter(\n (p) => p !== null && p !== undefined && p.functionResponse,\n );\n const textParts = parts.filter(\n (p) => p !== null && p !== undefined && p.text !== undefined && !p.thought,\n );\n\n if (funcResponses.length > 0) {\n // functionResponse → tool message; match IDs from the preceding assistant's tool_calls\n const lastAssistant = [...messages]\n .reverse()\n .find((m) => m.role === \"assistant\" && m.tool_calls);\n const matchedToolCallIds = new Set<string>();\n for (const part of funcResponses) {\n const matchingCall = lastAssistant?.tool_calls?.find(\n (tc) =>\n tc.function.name === part.functionResponse!.name && !matchedToolCallIds.has(tc.id),\n );\n if (matchingCall) matchedToolCallIds.add(matchingCall.id);\n const toolCallId =\n matchingCall?.id ?? `call_gemini_${part.functionResponse!.name}_${callCounter++}`;\n messages.push({\n role: \"tool\",\n content:\n typeof part.functionResponse!.response === \"string\"\n ? part.functionResponse!.response\n : JSON.stringify(part.functionResponse!.response),\n tool_call_id: toolCallId,\n });\n }\n // Any text parts alongside → user message\n if (textParts.length > 0) {\n messages.push({\n role: \"user\",\n content: textParts.map((p) => p.text!).join(\"\"),\n });\n }\n } else {\n // Regular user text\n const text = textParts.map((p) => p.text!).join(\"\");\n messages.push({ role: \"user\", content: text });\n }\n } else if (role === \"model\") {\n // Check for functionCall parts\n const parts = content.parts ?? [];\n const funcCalls = parts.filter((p) => p !== null && p !== undefined && p.functionCall);\n const textParts = parts.filter(\n (p) => p !== null && p !== undefined && p.text !== undefined && !p.thought,\n );\n\n if (funcCalls.length > 0) {\n const text = textParts.map((p) => p.text!).join(\"\");\n messages.push({\n role: \"assistant\",\n content: text || null,\n tool_calls: funcCalls.map((fc, i) => ({\n id: fc.functionCall!.id ?? `call_gemini_${fc.functionCall!.name}_${i}`,\n type: \"function\" as const,\n function: {\n name: fc.functionCall!.name,\n arguments: JSON.stringify(fc.functionCall!.args ?? {}),\n },\n })),\n });\n } else {\n const text = textParts.map((p) => p.text!).join(\"\");\n messages.push({ role: \"assistant\", content: text });\n }\n }\n // Unrecognized roles (not \"user\" or \"model\") are silently dropped.\n // Gemini only defines \"user\" and \"model\"; any other value indicates\n // a malformed request or an unsupported future role.\n }\n }\n\n // Convert tools\n let tools: ToolDefinition[] | undefined;\n if (req.tools && req.tools.length > 0) {\n const decls = req.tools.flatMap((t) => t.functionDeclarations ?? []);\n if (decls.length > 0) {\n tools = decls.map((d) => ({\n type: \"function\" as const,\n function: {\n name: d.name,\n description: d.description,\n parameters: d.parameters ?? d.parametersJsonSchema,\n },\n }));\n }\n }\n\n return {\n model,\n messages,\n stream,\n temperature: req.generationConfig?.temperature,\n max_tokens: req.generationConfig?.maxOutputTokens,\n top_p: req.generationConfig?.topP as number | undefined,\n top_k: req.generationConfig?.topK as number | undefined,\n tools,\n };\n}\n\n// ─── Response building: fixture → Gemini format ─────────────────────────────\n\nfunction geminiFinishReason(finishReason: string | undefined, defaultReason: string): string {\n if (!finishReason) return defaultReason;\n return mapGeminiFinish(finishReason);\n}\n\nfunction geminiUsageMetadata(overrides?: ResponseOverrides): {\n promptTokenCount: number;\n candidatesTokenCount: number;\n totalTokenCount: number;\n} {\n return renderGeminiUsage(overrides);\n}\n\ninterface GeminiResponseChunk {\n candidates: {\n content?: { role: string; parts: GeminiPart[] };\n finishReason?: string;\n finishMessage?: string;\n safetyRatings?: { category: string; probability: string; blocked: boolean }[];\n index: number;\n }[];\n usageMetadata?: {\n promptTokenCount: number;\n candidatesTokenCount: number;\n totalTokenCount: number;\n };\n}\n\nfunction buildGeminiTextStreamChunks(\n content: string,\n chunkSize: number,\n reasoning?: string,\n overrides?: ResponseOverrides,\n): GeminiResponseChunk[] {\n const chunks: GeminiResponseChunk[] = [];\n const effectiveFinish = geminiFinishReason(overrides?.finishReason, \"STOP\");\n const usage = geminiUsageMetadata(overrides);\n\n // Reasoning chunks (thought: true)\n if (reasoning) {\n for (let i = 0; i < reasoning.length; i += chunkSize) {\n const slice = reasoning.slice(i, i + chunkSize);\n chunks.push({\n candidates: [\n {\n content: { role: \"model\", parts: [{ text: slice, thought: true }] },\n index: 0,\n },\n ],\n });\n }\n }\n\n // Content chunks\n for (let i = 0; i < content.length; i += chunkSize) {\n const slice = content.slice(i, i + chunkSize);\n const isLast = i + chunkSize >= content.length;\n const chunk: GeminiResponseChunk = {\n candidates: [\n {\n content: { role: \"model\", parts: [{ text: slice }] },\n index: 0,\n ...(isLast ? { finishReason: effectiveFinish } : {}),\n },\n ],\n ...(isLast ? { usageMetadata: usage } : {}),\n };\n chunks.push(chunk);\n }\n\n // Handle empty content\n if (content.length === 0) {\n chunks.push({\n candidates: [\n {\n content: { role: \"model\", parts: [{ text: \"\" }] },\n finishReason: effectiveFinish,\n index: 0,\n },\n ],\n usageMetadata: usage,\n });\n }\n\n return chunks;\n}\n\nfunction parseToolCallPart(tc: ToolCall, logger: Logger): GeminiPart {\n const args = servedToolArgs(tc, \"object\", logger);\n // Surface the fixture's tool_call.id on the Gemini functionCall response\n // so clients can preserve it across the round-trip and any\n // toolCallId-keyed follow-up fixtures match. Pairs with v1.23.1's\n // INGEST-direction fix (#196) which preserves the id when aimock parses\n // an incoming Gemini request — that fix only helps if the id was in the\n // response body to begin with. Without this egress fix, aimock emits\n // `{ functionCall: { name, args } }` (no id), so even clients that\n // diligently preserve `functionCall.id` across the round-trip never see\n // an id to preserve. Backward-compatible: fixtures that don't pin a\n // tc.id continue to serialize without one (the ingest path's fallback\n // generator handles those).\n const functionCall: GeminiPart[\"functionCall\"] = {\n name: tc.name,\n args: args.value as Record<string, unknown>,\n };\n if (tc.id) {\n functionCall.id = tc.id;\n }\n return { functionCall };\n}\n\nfunction buildGeminiToolCallStreamChunks(\n toolCalls: ToolCall[],\n chunkSize: number,\n logger: Logger,\n reasoning?: string,\n overrides?: ResponseOverrides,\n): GeminiResponseChunk[] {\n const chunks: GeminiResponseChunk[] = [];\n\n // Reasoning chunks (thought: true) — mirror the content+tool / text paths so a\n // tool-only fixture on a reasoning-capable model still emits its thought channel.\n if (reasoning) {\n for (let i = 0; i < reasoning.length; i += chunkSize) {\n const slice = reasoning.slice(i, i + chunkSize);\n chunks.push({\n candidates: [\n {\n content: { role: \"model\", parts: [{ text: slice, thought: true }] },\n index: 0,\n },\n ],\n });\n }\n }\n\n const parts: GeminiPart[] = toolCalls.map((tc) => parseToolCallPart(tc, logger));\n\n // Gemini sends all tool calls in a single response chunk\n chunks.push({\n candidates: [\n {\n content: { role: \"model\", parts },\n finishReason: geminiFinishReason(overrides?.finishReason, \"FUNCTION_CALL\"),\n index: 0,\n },\n ],\n usageMetadata: geminiUsageMetadata(overrides),\n });\n\n return chunks;\n}\n\n// Non-streaming response builders\n\nfunction buildGeminiTextResponse(\n content: string,\n reasoning?: string,\n overrides?: ResponseOverrides,\n): GeminiResponseChunk {\n const parts: GeminiPart[] = [];\n if (reasoning) {\n parts.push({ text: reasoning, thought: true });\n }\n parts.push({ text: content });\n\n return {\n candidates: [\n {\n content: { role: \"model\", parts },\n finishReason: geminiFinishReason(overrides?.finishReason, \"STOP\"),\n index: 0,\n },\n ],\n usageMetadata: geminiUsageMetadata(overrides),\n };\n}\n\nfunction buildGeminiToolCallResponse(\n toolCalls: ToolCall[],\n logger: Logger,\n reasoning?: string,\n overrides?: ResponseOverrides,\n): GeminiResponseChunk {\n const parts: GeminiPart[] = [];\n if (reasoning) {\n parts.push({ text: reasoning, thought: true });\n }\n parts.push(...toolCalls.map((tc) => parseToolCallPart(tc, logger)));\n\n return {\n candidates: [\n {\n content: { role: \"model\", parts },\n finishReason: geminiFinishReason(overrides?.finishReason, \"FUNCTION_CALL\"),\n index: 0,\n },\n ],\n usageMetadata: geminiUsageMetadata(overrides),\n };\n}\n\nfunction buildGeminiContentWithToolCallsStreamChunks(\n content: string,\n toolCalls: ToolCall[],\n chunkSize: number,\n logger: Logger,\n reasoning?: string,\n overrides?: ResponseOverrides,\n blocks?: FixtureBlock[],\n): GeminiResponseChunk[] {\n const chunks: GeminiResponseChunk[] = [];\n\n // Reasoning chunks (thought: true)\n if (reasoning) {\n for (let i = 0; i < reasoning.length; i += chunkSize) {\n const slice = reasoning.slice(i, i + chunkSize);\n chunks.push({\n candidates: [\n {\n content: { role: \"model\", parts: [{ text: slice, thought: true }] },\n index: 0,\n },\n ],\n });\n }\n }\n\n if (blocks && blocks.length > 0) {\n // NEW path (#274): stream chunks whose parts follow the blocks' ARRAY ORDER,\n // so a tool-first / interleaved fixture emits its functionCall part before\n // its text part. Gemini's ordered `parts` make this fully expressible. The\n // terminal block carries the finishReason regardless of its type. Legacy\n // fixtures (no `blocks`) never enter here — see the else branch below.\n const outcome = resolveFixtureBlockOutcome(blocks);\n const resolved = outcome.ordered;\n resolved.forEach((block, i) => {\n const isLast = i === resolved.length - 1;\n const finishReason = isLast\n ? geminiFinishReason(\n overrides?.finishReason,\n outcome.hasToolCalls ? \"FUNCTION_CALL\" : \"STOP\",\n )\n : undefined;\n if (block.type === \"toolCall\") {\n const part = parseToolCallPart(\n { name: block.name, arguments: block.arguments, id: block.id },\n logger,\n );\n chunks.push({\n candidates: [\n {\n content: { role: \"model\", parts: [part] },\n ...(finishReason ? { finishReason } : {}),\n index: 0,\n },\n ],\n ...(isLast ? { usageMetadata: geminiUsageMetadata(overrides) } : {}),\n });\n } else {\n const text = block.text;\n if (text.length === 0) {\n chunks.push({\n candidates: [\n {\n content: { role: \"model\", parts: [{ text: \"\" }] },\n ...(finishReason ? { finishReason } : {}),\n index: 0,\n },\n ],\n ...(isLast ? { usageMetadata: geminiUsageMetadata(overrides) } : {}),\n });\n } else {\n for (let j = 0; j < text.length; j += chunkSize) {\n const slice = text.slice(j, j + chunkSize);\n const lastSlice = j + chunkSize >= text.length;\n const sliceFinish = isLast && lastSlice ? finishReason : undefined;\n chunks.push({\n candidates: [\n {\n content: { role: \"model\", parts: [{ text: slice }] },\n ...(sliceFinish ? { finishReason: sliceFinish } : {}),\n index: 0,\n },\n ],\n ...(isLast && lastSlice ? { usageMetadata: geminiUsageMetadata(overrides) } : {}),\n });\n }\n }\n }\n });\n\n return chunks;\n }\n\n if (content.length === 0) {\n chunks.push({\n candidates: [\n {\n content: { role: \"model\", parts: [{ text: \"\" }] },\n index: 0,\n },\n ],\n });\n } else {\n for (let i = 0; i < content.length; i += chunkSize) {\n const slice = content.slice(i, i + chunkSize);\n chunks.push({\n candidates: [\n {\n content: { role: \"model\", parts: [{ text: slice }] },\n index: 0,\n },\n ],\n });\n }\n }\n\n const parts: GeminiPart[] = toolCalls.map((tc) => parseToolCallPart(tc, logger));\n\n chunks.push({\n candidates: [\n {\n content: { role: \"model\", parts },\n finishReason: geminiFinishReason(overrides?.finishReason, \"FUNCTION_CALL\"),\n index: 0,\n },\n ],\n usageMetadata: geminiUsageMetadata(overrides),\n });\n\n return chunks;\n}\n\nfunction buildGeminiContentWithToolCallsResponse(\n content: string,\n toolCalls: ToolCall[],\n logger: Logger,\n reasoning?: string,\n overrides?: ResponseOverrides,\n blocks?: FixtureBlock[],\n): GeminiResponseChunk {\n const parts: GeminiPart[] = [];\n if (reasoning) {\n parts.push({ text: reasoning, thought: true });\n }\n\n let blockHasTools: boolean | undefined;\n if (blocks && blocks.length > 0) {\n // NEW PATH: the non-streaming `parts[]` array is positionally observable, so\n // emit parts in the fixture's ARRAY ORDER (after any leading thought part).\n // A toolCall block before a text block therefore yields a functionCall part\n // ahead of the text — matching the streaming path for the same `blocks`.\n const outcome = resolveFixtureBlockOutcome(blocks);\n const resolved = outcome.ordered;\n blockHasTools = outcome.hasToolCalls;\n for (const block of resolved) {\n if (block.type === \"toolCall\") {\n parts.push(\n parseToolCallPart({ name: block.name, arguments: block.arguments, id: block.id }, logger),\n );\n } else {\n parts.push({ text: block.text });\n }\n }\n } else {\n // LEGACY PATH (unchanged): text part first, then functionCall parts.\n parts.push({ text: content });\n parts.push(...toolCalls.map((tc) => parseToolCallPart(tc, logger)));\n }\n\n return {\n candidates: [\n {\n content: { role: \"model\", parts },\n finishReason: geminiFinishReason(\n overrides?.finishReason,\n blockHasTools === false ? \"STOP\" : \"FUNCTION_CALL\",\n ),\n index: 0,\n },\n ],\n usageMetadata: geminiUsageMetadata(overrides),\n };\n}\n\n// ─── Audio response builders ────────────────────────────────────────────────\n\nfunction resolveAudioInlineData(audio: AudioResponse): { mimeType: string; data: string } {\n if (typeof audio.audio === \"string\") {\n return { mimeType: formatToMime(audio.format ?? \"mp3\"), data: audio.audio };\n }\n return {\n mimeType: audio.audio.contentType ?? \"audio/mpeg\",\n data: audio.audio.b64Json,\n };\n}\n\n// Build the ordered Gemini parts for an audio turn: inlineData audio first,\n// then any companion modalities (reasoning/thought, text content, tool calls)\n// the recorder preserved on the AudioResponse. Without this, a recorded turn\n// that interleaves audio with a functionCall and/or text silently drops the\n// companions on replay.\n// NOTE: audio companions are only re-emitted on this Gemini replay path because\n// `audioB64` collapse is currently Gemini-only — a cross-provider audio fixture\n// would not replay its companions.\n// `effReasoning` is the capability-gated reasoning string (already passed\n// through resolveReasoningForModel at the dispatch). When the requested model\n// is not reasoning-capable (and strict mode is on), it is undefined and the\n// companion `thought` part is suppressed — mirroring the text/content+tool\n// branches so the audio path does not replay reasoning a real Gemini model\n// would never emit.\nfunction buildGeminiAudioParts(\n audio: AudioResponse,\n toolCalls: ToolCall[],\n logger: Logger,\n effReasoning: string | undefined,\n): GeminiPart[] {\n const inlineData = resolveAudioInlineData(audio);\n const parts: GeminiPart[] = [{ inlineData }];\n if (effReasoning) {\n parts.push({ text: effReasoning, thought: true });\n }\n if (audio.content) {\n parts.push({ text: audio.content });\n }\n if (toolCalls.length) {\n parts.push(...toolCalls.map((tc) => parseToolCallPart(tc, logger)));\n }\n return parts;\n}\n\nfunction buildGeminiAudioResponse(\n audio: AudioResponse,\n toolCalls: ToolCall[],\n logger: Logger,\n effReasoning: string | undefined,\n): GeminiResponseChunk {\n return {\n candidates: [\n {\n content: {\n role: \"model\",\n parts: buildGeminiAudioParts(audio, toolCalls, logger, effReasoning),\n },\n finishReason: toolCalls.length ? \"FUNCTION_CALL\" : \"STOP\",\n index: 0,\n },\n ],\n usageMetadata: renderGeminiUsage(),\n };\n}\n\nfunction buildGeminiAudioStreamChunks(\n audio: AudioResponse,\n toolCalls: ToolCall[],\n logger: Logger,\n effReasoning: string | undefined,\n): GeminiResponseChunk[] {\n return [\n {\n candidates: [\n {\n content: {\n role: \"model\",\n parts: buildGeminiAudioParts(audio, toolCalls, logger, effReasoning),\n },\n finishReason: toolCalls.length ? \"FUNCTION_CALL\" : \"STOP\",\n index: 0,\n },\n ],\n usageMetadata: renderGeminiUsage(),\n },\n ];\n}\n\n// ─── SSE writer for Gemini streaming ────────────────────────────────────────\n\ninterface GeminiStreamOptions {\n latency?: number;\n streamingProfile?: StreamingProfile;\n recordedTimings?: RecordedTimings;\n replaySpeed?: number;\n signal?: AbortSignal;\n onChunkSent?: () => void;\n}\n\nasync function writeGeminiSSEStream(\n res: http.ServerResponse,\n chunks: GeminiResponseChunk[],\n optionsOrLatency?: number | GeminiStreamOptions,\n): Promise<boolean> {\n const opts: GeminiStreamOptions =\n typeof optionsOrLatency === \"number\" ? { latency: optionsOrLatency } : (optionsOrLatency ?? {});\n const latency = opts.latency ?? 0;\n const profile = opts.streamingProfile;\n const { recordedTimings, replaySpeed } = opts;\n const signal = opts.signal;\n const onChunkSent = opts.onChunkSent;\n\n if (res.writableEnded) return true;\n res.setHeader(\"Content-Type\", \"text/event-stream\");\n res.setHeader(\"Cache-Control\", \"no-cache\");\n res.setHeader(\"Connection\", \"keep-alive\");\n\n let chunkIndex = 0;\n for (const chunk of chunks) {\n const chunkDelay = calculateDelay(chunkIndex, profile, latency, recordedTimings, replaySpeed);\n if (chunkDelay > 0) await delay(chunkDelay, signal);\n if (signal?.aborted) return false;\n if (res.writableEnded) return true;\n // Gemini uses data-only SSE (no event: prefix, no [DONE])\n res.write(`data: ${JSON.stringify(chunk)}\\n\\n`);\n onChunkSent?.();\n if (signal?.aborted) return false;\n chunkIndex++;\n }\n\n if (!res.writableEnded) {\n res.end();\n }\n return true;\n}\n\n/** Prepare native fault output once; the journal describes these exact parts. */\nfunction prepareGeminiMisbehavior(\n plan: MisbehaviorPlan,\n request: ChatCompletionRequest,\n streaming: boolean,\n chunkSize: number,\n logger: Logger,\n strict: boolean,\n): { chunks: GeminiResponseChunk[]; summary: MisbehaviorPlan[\"summary\"] } {\n const response = plan.response;\n const combined = isCombinedFixtureResponse(response);\n if (!(combined || isToolCallResponse(response) || isTextResponse(response))) {\n throw new Error(\"Applied Gemini misbehavior requires a chat response\");\n }\n const outcome =\n combined && response.blocks?.length ? resolveFixtureBlockOutcome(response.blocks) : undefined;\n const content = outcome?.content ?? (\"content\" in response ? (response.content ?? \"\") : \"\");\n // The planner skips a custom-call fixture on this wire, so this narrowing\n // never throws; the normal path's guard rejects it instead.\n const calls = outcome?.toolCalls ?? (\"toolCalls\" in response ? (response.toolCalls ?? []) : []);\n const overrides = extractOverrides(response);\n delete overrides.usage;\n const fault = plan.summary.fault;\n const candidate: GeminiResponseChunk[\"candidates\"][number] & { content: GeminiContent } = {\n content: { role: \"model\", parts: [] },\n index: 0,\n };\n let chunks: GeminiResponseChunk[];\n if (fault === \"tool-args-invalid-json\") {\n const target = calls[plan.target?.index ?? 0];\n if (!target) throw new Error(\"Gemini malformed-call plan requires its selected tool call\");\n chunks = [\n {\n candidates: [\n {\n index: 0,\n finishReason: \"MALFORMED_FUNCTION_CALL\",\n finishMessage: `Malformed function call: ${target.name}(${target.arguments})`,\n },\n ],\n },\n ];\n } else if (fault === \"tool-unknown-name\" && !request.tools?.length) {\n candidate.finishReason = \"UNEXPECTED_TOOL_CALL\";\n chunks = [{ candidates: [candidate] }];\n } else if (fault === \"stop-length-mid-tool\") {\n // Object arguments cannot be partial; preserve only text preceding the cut.\n candidate.content.parts = content ? [{ text: content }] : [];\n candidate.finishReason = \"MAX_TOKENS\";\n chunks = [{ candidates: [candidate] }];\n } else if (fault === \"empty-response\") {\n candidate.content.parts = [{ text: \"\" }];\n candidate.finishReason = \"STOP\";\n chunks = [{ candidates: [candidate] }];\n } else if (fault === \"content-filter\") {\n candidate.finishReason = \"SAFETY\";\n candidate.safetyRatings = [\n { category: \"HARM_CATEGORY_DANGEROUS_CONTENT\", probability: \"HIGH\", blocked: true },\n ];\n chunks = [{ candidates: [candidate] }];\n } else if (fault === \"reasoning-only\") {\n candidate.content.parts = [{ text: plan.reasoning ?? \"\", thought: true }];\n candidate.finishReason = \"MAX_TOKENS\";\n chunks = [{ candidates: [candidate] }];\n } else {\n const reasoning = resolveReasoningForModel(response.reasoning, request.model, strict, logger);\n if (fault === \"tool-unknown-name\") overrides.finishReason = \"stop\";\n if (combined) {\n chunks = streaming\n ? buildGeminiContentWithToolCallsStreamChunks(\n content,\n calls,\n chunkSize,\n logger,\n reasoning,\n overrides,\n response.blocks,\n )\n : [\n buildGeminiContentWithToolCallsResponse(\n content,\n calls,\n logger,\n reasoning,\n overrides,\n response.blocks,\n ),\n ];\n } else if (isToolCallResponse(response)) {\n chunks = streaming\n ? buildGeminiToolCallStreamChunks(calls, chunkSize, logger, reasoning, overrides)\n : [buildGeminiToolCallResponse(calls, logger, reasoning, overrides)];\n } else {\n chunks = streaming\n ? buildGeminiTextStreamChunks(content, chunkSize, reasoning, overrides)\n : [buildGeminiTextResponse(content, reasoning, overrides)];\n }\n }\n const parts = chunks.flatMap((chunk) =>\n chunk.candidates.flatMap((item) => item.content?.parts ?? []),\n );\n const servedToolCalls = parts.flatMap((part) =>\n part.functionCall\n ? [\n {\n name: part.functionCall.name,\n arguments: JSON.stringify(part.functionCall.args),\n ...(part.functionCall.id ? { id: part.functionCall.id } : {}),\n },\n ]\n : [],\n );\n const prompt = request.messages\n .map((message) =>\n typeof message.content === \"string\"\n ? message.content\n : (message.content ?? []).map((part) => part.text ?? \"\").join(\"\"),\n )\n .join(\"\");\n const output = parts\n .map(\n (part) =>\n part.text ??\n (part.functionCall ? part.functionCall.name + JSON.stringify(part.functionCall.args) : \"\"),\n )\n .join(\"\");\n for (const chunk of chunks) delete chunk.usageMetadata;\n chunks[chunks.length - 1].usageMetadata = renderGeminiUsage(undefined, {\n kind: \"applied-misbehavior\",\n promptText: prompt,\n completionText: output,\n });\n return { chunks, summary: { ...plan.summary, servedToolCalls } };\n}\n\n// ─── Request handler ────────────────────────────────────────────────────────\n\nexport async function handleGemini(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n raw: string,\n model: string,\n streaming: boolean,\n fixtures: Fixture[],\n journal: Journal,\n defaults: HandlerDefaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n providerKey: RecordProviderKey = \"gemini\",\n): Promise<void> {\n const { logger } = defaults;\n const wire = providerKey === \"vertexai\" ? \"Vertex AI\" : \"Gemini\";\n setCorsHeaders(res);\n\n let geminiReq: GeminiRequest;\n try {\n geminiReq = JSON.parse(raw) as GeminiRequest;\n } catch (parseErr) {\n const detail = parseErr instanceof Error ? parseErr.message : \"unknown\";\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? `/v1beta/models/${model}:generateContent`,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n renderError(\"gemini\", \"validation\", {\n message: `Malformed JSON body: ${detail}`,\n bodyCode: 400,\n status: \"INVALID_ARGUMENT\",\n }).body,\n );\n return;\n }\n\n // Reject non-object bodies (e.g. `null`) before touching fields —\n // otherwise the converter dereference throws a TypeError that surfaces as\n // a 500 instead of a 400.\n if (!isJsonObject(geminiReq)) {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? `/v1beta/models/${model}:generateContent`,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n renderError(\"gemini\", \"validation\", {\n message: \"Request body must be a JSON object\",\n bodyCode: 400,\n status: \"INVALID_ARGUMENT\",\n }).body,\n );\n return;\n }\n\n // Reject wrong-typed fields before the converter dereferences them.\n const geminiShapeError = validateGeminiBody(geminiReq);\n if (geminiShapeError) {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? `/v1beta/models/${model}:generateContent`,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n renderError(\"gemini\", \"validation\", {\n message: `Invalid argument: ${geminiShapeError}`,\n bodyCode: 400,\n status: \"INVALID_ARGUMENT\",\n }).body,\n );\n return;\n }\n\n // Convert to ChatCompletionRequest for fixture matching\n const completionReq = geminiToCompletionRequest(geminiReq, model, streaming);\n completionReq._endpointType = \"chat\";\n completionReq._context = getContext(req);\n\n const testId = getTestId(req);\n const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(\n fixtures,\n completionReq,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\n // Record mode proxies on a miss to capture a fresh turn (see record gate\n // below), so keep turnIndex strict to prevent an earlier-turn fixture from\n // shadowing a longer request and skipping the new turn's recording.\n recordMatchOptions(!!defaults.record, defaults.logger),\n );\n const path = req.url ?? `/v1beta/models/${model}:generateContent`;\n\n if (fixture) {\n logger.debug(`Fixture matched: ${JSON.stringify(fixture.match).slice(0, 120)}`);\n } else {\n logger.debug(`No fixture matched for request`);\n }\n\n if (fixture) {\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n }\n\n if (\n await applyChaosAsync(\n res,\n fixture,\n defaults.chaos,\n req.headers,\n req.url,\n journal,\n {\n method: req.method ?? \"POST\",\n path,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n },\n fixture ? \"fixture\" : \"proxy\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n if (!fixture) {\n const decisions = resolveRequestDecisions(defaults.strict, req.headers);\n if (decisions.fixtureMiss) {\n const strictMessage = strictNoMatchMessage(skippedBySequenceOrTurn);\n logger.error(strictNoMatchLogLine(req.method ?? \"POST\", path, skippedBySequenceOrTurn));\n journal.add({\n method: req.method ?? \"POST\",\n path,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: {\n status: 503,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 503,\n renderError(\"gemini\", \"strict-miss\", {\n message: strictMessage,\n bodyCode: 503,\n status: \"UNAVAILABLE\",\n }).body,\n );\n return;\n }\n\n if (decisions.upstream && defaults.record) {\n const outcome = await proxyAndRecord(\n req,\n res,\n completionReq,\n providerKey,\n path,\n fixtures,\n defaults,\n raw,\n );\n if (outcome === \"handled_by_hook\") return;\n if (outcome !== \"not_configured\") {\n journal.add({\n method: req.method ?? \"POST\",\n path,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: res.statusCode ?? 200, fixture: null, source: \"proxy\" },\n });\n return;\n }\n }\n journal.add({\n method: req.method ?? \"POST\",\n path,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: {\n status: 404,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 404,\n renderError(\"gemini\", \"fixture-miss\", {\n message: \"No fixture matched\",\n bodyCode: 404,\n status: \"NOT_FOUND\",\n }).body,\n );\n return;\n }\n\n const response = await resolveResponse(fixture, completionReq);\n const misbehavior = planMisbehavior({\n wire: \"gemini\",\n toolCallIdMode: \"authored-nonempty\",\n fixture,\n response,\n request: completionReq,\n stream: streaming,\n defaults,\n rawHeaders: req.headers,\n url: req.url,\n });\n if (misbehavior.kind === \"error\") {\n const entry = journal.add({\n method: req.method ?? \"POST\",\n path,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: misbehavior.status, fixture, error: misbehavior.message },\n });\n recordMisbehaviorOutcome({ entry, summary: misbehavior.summary, defaults, testId });\n if (misbehavior.summary?.evaluations.length === 0) {\n logger.error(`${req.method ?? \"POST\"} ${path}: ${misbehavior.message}`);\n }\n writeErrorResponse(\n res,\n misbehavior.status,\n renderError(\"gemini\", \"misbehavior\", {\n bodyCode: misbehavior.status,\n message: misbehavior.message,\n status: misbehavior.status === 400 ? \"INVALID_ARGUMENT\" : \"UNIMPLEMENTED\",\n }).body,\n );\n return;\n }\n\n const latency = fixture.latency ?? defaults.latency;\n const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);\n const replaySpeed = fixture.replaySpeed ?? defaults.replaySpeed;\n\n if (misbehavior.kind === \"applied\") {\n const prepared = prepareGeminiMisbehavior(\n misbehavior,\n completionReq,\n streaming,\n chunkSize,\n logger,\n resolveRequestDecisions(defaults.strict, req.headers).reasoningSuppression,\n );\n const entry = journal.add({\n method: req.method ?? \"POST\",\n path,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n recordMisbehaviorOutcome({ entry, summary: prepared.summary, defaults, testId });\n if (!streaming) {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(prepared.chunks[0]));\n } else {\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeGeminiSSEStream(res, prepared.chunks, {\n latency,\n streamingProfile: fixture.streamingProfile,\n recordedTimings: fixture.recordedTimings,\n replaySpeed,\n signal: interruption?.signal,\n onChunkSent: interruption?.tick,\n });\n if (!completed) {\n if (!res.writableEnded) res.destroy();\n entry.response.interrupted = true;\n entry.response.interruptReason = interruption?.reason();\n }\n interruption?.cleanup();\n }\n return;\n }\n\n // Error response\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n const errorEntry = journal.add({\n method: req.method ?? \"POST\",\n path,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status, fixture },\n });\n recordMisbehaviorOutcome({ entry: errorEntry, summary: misbehavior.summary, defaults, testId });\n writeErrorResponse(\n res,\n status,\n renderError(\"gemini\", \"fixture\", {\n bodyCode: status,\n message: response.error.message,\n status: response.error.type ?? \"ERROR\",\n }).body,\n { retryAfter: response.retryAfter },\n );\n return;\n }\n\n // Audio response\n if (isAudioResponse(response)) {\n const effectiveStrict = resolveRequestDecisions(\n defaults.strict,\n req.headers,\n ).reasoningSuppression;\n const effReasoning = resolveReasoningForModel(\n response.reasoning,\n model,\n effectiveStrict,\n defaults.logger,\n );\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n recordMisbehaviorOutcome({\n entry: journalEntry,\n summary: misbehavior.summary,\n defaults,\n testId,\n });\n // A non-array companion `toolCalls` emits no tool parts, as before custom calls existed.\n const audioToolCalls = Array.isArray(response.toolCalls)\n ? requireServedFunctionToolCalls(response, wire)\n : [];\n if (!streaming) {\n const body = buildGeminiAudioResponse(response, audioToolCalls, logger, effReasoning);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const chunks = buildGeminiAudioStreamChunks(response, audioToolCalls, logger, effReasoning);\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeGeminiSSEStream(res, chunks, {\n latency,\n streamingProfile: fixture.streamingProfile,\n recordedTimings: fixture.recordedTimings,\n replaySpeed,\n signal: interruption?.signal,\n onChunkSent: interruption?.tick,\n });\n if (!completed) {\n if (!res.writableEnded) res.destroy();\n journalEntry.response.interrupted = true;\n journalEntry.response.interruptReason = interruption?.reason();\n }\n interruption?.cleanup();\n }\n return;\n }\n\n // Content + tool calls response (must be checked before isTextResponse / isToolCallResponse)\n if (isCombinedFixtureResponse(response)) {\n if (response.webSearches?.length) {\n logger.warn(\"webSearches in fixture response are not supported for Gemini API — ignoring\");\n }\n const overrides = extractOverrides(response);\n const effectiveStrict = resolveRequestDecisions(\n defaults.strict,\n req.headers,\n ).reasoningSuppression;\n const effReasoning = resolveReasoningForModel(\n response.reasoning,\n model,\n effectiveStrict,\n defaults.logger,\n );\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n recordMisbehaviorOutcome({\n entry: journalEntry,\n summary: misbehavior.summary,\n defaults,\n testId,\n });\n const functionToolCalls = requireEmittedFunctionToolCalls(response, wire);\n if (!streaming) {\n const body = buildGeminiContentWithToolCallsResponse(\n response.content ?? \"\",\n functionToolCalls,\n logger,\n effReasoning,\n overrides,\n response.blocks,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const chunks = buildGeminiContentWithToolCallsStreamChunks(\n response.content ?? \"\",\n functionToolCalls,\n chunkSize,\n logger,\n effReasoning,\n overrides,\n response.blocks,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeGeminiSSEStream(res, chunks, {\n latency,\n streamingProfile: fixture.streamingProfile,\n recordedTimings: fixture.recordedTimings,\n replaySpeed,\n signal: interruption?.signal,\n onChunkSent: interruption?.tick,\n });\n if (!completed) {\n if (!res.writableEnded) res.destroy();\n journalEntry.response.interrupted = true;\n journalEntry.response.interruptReason = interruption?.reason();\n }\n interruption?.cleanup();\n }\n return;\n }\n\n // Text response\n if (isTextResponse(response)) {\n if (response.webSearches?.length) {\n logger.warn(\"webSearches in fixture response are not supported for Gemini API — ignoring\");\n }\n const overrides = extractOverrides(response);\n const effectiveStrict = resolveRequestDecisions(\n defaults.strict,\n req.headers,\n ).reasoningSuppression;\n const effReasoning = resolveReasoningForModel(\n response.reasoning,\n model,\n effectiveStrict,\n defaults.logger,\n );\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n recordMisbehaviorOutcome({\n entry: journalEntry,\n summary: misbehavior.summary,\n defaults,\n testId,\n });\n if (!streaming) {\n const body = buildGeminiTextResponse(response.content, effReasoning, overrides);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const chunks = buildGeminiTextStreamChunks(\n response.content,\n chunkSize,\n effReasoning,\n overrides,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeGeminiSSEStream(res, chunks, {\n latency,\n streamingProfile: fixture.streamingProfile,\n recordedTimings: fixture.recordedTimings,\n replaySpeed,\n signal: interruption?.signal,\n onChunkSent: interruption?.tick,\n });\n if (!completed) {\n if (!res.writableEnded) res.destroy();\n journalEntry.response.interrupted = true;\n journalEntry.response.interruptReason = interruption?.reason();\n }\n interruption?.cleanup();\n }\n return;\n }\n\n // Tool call response\n if (isToolCallResponse(response)) {\n if (response.webSearches?.length) {\n logger.warn(\"webSearches in fixture response are not supported for Gemini API — ignoring\");\n }\n const overrides = extractOverrides(response);\n const effectiveStrict = resolveRequestDecisions(\n defaults.strict,\n req.headers,\n ).reasoningSuppression;\n const effReasoning = resolveReasoningForModel(\n response.reasoning,\n model,\n effectiveStrict,\n defaults.logger,\n );\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n recordMisbehaviorOutcome({\n entry: journalEntry,\n summary: misbehavior.summary,\n defaults,\n testId,\n });\n const functionToolCalls = requireEmittedFunctionToolCalls(response, wire);\n if (!streaming) {\n const body = buildGeminiToolCallResponse(functionToolCalls, logger, effReasoning, overrides);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const chunks = buildGeminiToolCallStreamChunks(\n functionToolCalls,\n chunkSize,\n logger,\n effReasoning,\n overrides,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeGeminiSSEStream(res, chunks, {\n latency,\n streamingProfile: fixture.streamingProfile,\n recordedTimings: fixture.recordedTimings,\n replaySpeed,\n signal: interruption?.signal,\n onChunkSent: interruption?.tick,\n });\n if (!completed) {\n if (!res.writableEnded) res.destroy();\n journalEntry.response.interrupted = true;\n journalEntry.response.interruptReason = interruption?.reason();\n }\n interruption?.cleanup();\n }\n return;\n }\n\n // Unknown response type\n const unknownEntry = journal.add({\n method: req.method ?? \"POST\",\n path,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 500, fixture },\n });\n recordMisbehaviorOutcome({ entry: unknownEntry, summary: misbehavior.summary, defaults, testId });\n writeErrorResponse(\n res,\n 500,\n renderError(\"gemini\", \"unknown-response\", {\n message: \"Fixture response did not match any known type\",\n bodyCode: 500,\n status: \"INTERNAL\",\n }).body,\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4GA,SAAS,mBAAmB,KAAmC;AAC7D,KAAI,IAAI,aAAa,UAAa,IAAI,aAAa,QAAQ,CAAC,MAAM,QAAQ,IAAI,SAAS,CACrF,QAAO;AAET,KAAI,MAAM,QAAQ,IAAI,SAAS,CAC7B,MAAK,IAAI,IAAI,GAAG,IAAI,IAAI,SAAS,QAAQ,KAAK;EAC5C,MAAM,UAAU,IAAI,SAAS;AAC7B,MAAI,YAAY,QAAQ,OAAO,YAAY,YAAY,MAAM,QAAQ,QAAQ,CAC3E,QAAO,YAAY,EAAE;EAEvB,MAAM,QAAS,QAAgC;AAC/C,MAAI,UAAU,UAAa,UAAU,QAAQ,CAAC,MAAM,QAAQ,MAAM,CAChE,QAAO,YAAY,EAAE;;AAI3B,KAAI,IAAI,sBAAsB,UAAa,IAAI,sBAAsB,MAAM;AACzE,MAAI,OAAO,IAAI,sBAAsB,YAAY,MAAM,QAAQ,IAAI,kBAAkB,CACnF,QAAO;EAET,MAAM,QAAQ,IAAI,kBAAkB;AACpC,MAAI,UAAU,UAAa,UAAU,QAAQ,CAAC,MAAM,QAAQ,MAAM,CAChE,QAAO;;CAGX,MAAM,aAAaA,mCAAmB,IAAI,MAAM;AAChD,KAAI,WAAY,QAAO;AACvB,KAAI,MAAM,QAAQ,IAAI,MAAM,CAC1B,MAAK,MAAM,CAAC,WAAW,SAAS,IAAI,MAAM,SAAS,EAAE;AACnD,MAAI,CAAC,MAAM,QAAQ,KAAK,qBAAqB,CAAE;EAC/C,MAAM,mBAAmB,KAAK,qBAAqB,WAChD,gBAAgB,gBAAgB,KAClC;AACD,MAAI,qBAAqB,GACvB,QAAO,SAAS,UAAU,yBAAyB,iBAAiB;;AAI1E,QAAO;;AAGT,SAAgB,0BACd,KACA,OACA,QACuB;CACvB,MAAM,WAA0B,EAAE;AAGlC,KAAI,IAAI,mBAAmB;EACzB,MAAM,QAAQ,IAAI,kBAAkB,SAAS,EAAE,EAC5C,QAAQ,MAAM,MAAM,QAAQ,MAAM,UAAa,EAAE,SAAS,OAAU,CACpE,KAAK,MAAM,EAAE,KAAM,CACnB,KAAK,GAAG;AACX,MAAI,KACF,UAAS,KAAK;GAAE,MAAM;GAAU,SAAS;GAAM,CAAC;;AAIpD,KAAI,IAAI,UAAU;EAChB,IAAI,cAAc;AAClB,OAAK,MAAM,WAAW,IAAI,UAAU;GAClC,MAAM,OAAO,QAAQ,QAAQ;AAE7B,OAAI,SAAS,QAAQ;IAEnB,MAAM,QAAQ,QAAQ,SAAS,EAAE;IACjC,MAAM,gBAAgB,MAAM,QACzB,MAAM,MAAM,QAAQ,MAAM,UAAa,EAAE,iBAC3C;IACD,MAAM,YAAY,MAAM,QACrB,MAAM,MAAM,QAAQ,MAAM,UAAa,EAAE,SAAS,UAAa,CAAC,EAAE,QACpE;AAED,QAAI,cAAc,SAAS,GAAG;KAE5B,MAAM,gBAAgB,CAAC,GAAG,SAAS,CAChC,SAAS,CACT,MAAM,MAAM,EAAE,SAAS,eAAe,EAAE,WAAW;KACtD,MAAM,qCAAqB,IAAI,KAAa;AAC5C,UAAK,MAAM,QAAQ,eAAe;MAChC,MAAM,eAAe,eAAe,YAAY,MAC7C,OACC,GAAG,SAAS,SAAS,KAAK,iBAAkB,QAAQ,CAAC,mBAAmB,IAAI,GAAG,GAAG,CACrF;AACD,UAAI,aAAc,oBAAmB,IAAI,aAAa,GAAG;MACzD,MAAM,aACJ,cAAc,MAAM,eAAe,KAAK,iBAAkB,KAAK,GAAG;AACpE,eAAS,KAAK;OACZ,MAAM;OACN,SACE,OAAO,KAAK,iBAAkB,aAAa,WACvC,KAAK,iBAAkB,WACvB,KAAK,UAAU,KAAK,iBAAkB,SAAS;OACrD,cAAc;OACf,CAAC;;AAGJ,SAAI,UAAU,SAAS,EACrB,UAAS,KAAK;MACZ,MAAM;MACN,SAAS,UAAU,KAAK,MAAM,EAAE,KAAM,CAAC,KAAK,GAAG;MAChD,CAAC;WAEC;KAEL,MAAM,OAAO,UAAU,KAAK,MAAM,EAAE,KAAM,CAAC,KAAK,GAAG;AACnD,cAAS,KAAK;MAAE,MAAM;MAAQ,SAAS;MAAM,CAAC;;cAEvC,SAAS,SAAS;IAE3B,MAAM,QAAQ,QAAQ,SAAS,EAAE;IACjC,MAAM,YAAY,MAAM,QAAQ,MAAM,MAAM,QAAQ,MAAM,UAAa,EAAE,aAAa;IACtF,MAAM,YAAY,MAAM,QACrB,MAAM,MAAM,QAAQ,MAAM,UAAa,EAAE,SAAS,UAAa,CAAC,EAAE,QACpE;AAED,QAAI,UAAU,SAAS,GAAG;KACxB,MAAM,OAAO,UAAU,KAAK,MAAM,EAAE,KAAM,CAAC,KAAK,GAAG;AACnD,cAAS,KAAK;MACZ,MAAM;MACN,SAAS,QAAQ;MACjB,YAAY,UAAU,KAAK,IAAI,OAAO;OACpC,IAAI,GAAG,aAAc,MAAM,eAAe,GAAG,aAAc,KAAK,GAAG;OACnE,MAAM;OACN,UAAU;QACR,MAAM,GAAG,aAAc;QACvB,WAAW,KAAK,UAAU,GAAG,aAAc,QAAQ,EAAE,CAAC;QACvD;OACF,EAAE;MACJ,CAAC;WACG;KACL,MAAM,OAAO,UAAU,KAAK,MAAM,EAAE,KAAM,CAAC,KAAK,GAAG;AACnD,cAAS,KAAK;MAAE,MAAM;MAAa,SAAS;MAAM,CAAC;;;;;CAU3D,IAAI;AACJ,KAAI,IAAI,SAAS,IAAI,MAAM,SAAS,GAAG;EACrC,MAAM,QAAQ,IAAI,MAAM,SAAS,MAAM,EAAE,wBAAwB,EAAE,CAAC;AACpE,MAAI,MAAM,SAAS,EACjB,SAAQ,MAAM,KAAK,OAAO;GACxB,MAAM;GACN,UAAU;IACR,MAAM,EAAE;IACR,aAAa,EAAE;IACf,YAAY,EAAE,cAAc,EAAE;IAC/B;GACF,EAAE;;AAIP,QAAO;EACL;EACA;EACA;EACA,aAAa,IAAI,kBAAkB;EACnC,YAAY,IAAI,kBAAkB;EAClC,OAAO,IAAI,kBAAkB;EAC7B,OAAO,IAAI,kBAAkB;EAC7B;EACD;;AAKH,SAAS,mBAAmB,cAAkC,eAA+B;AAC3F,KAAI,CAAC,aAAc,QAAO;AAC1B,QAAOC,+BAAgB,aAAa;;AAGtC,SAAS,oBAAoB,WAI3B;AACA,QAAOC,sBAAkB,UAAU;;AAkBrC,SAAS,4BACP,SACA,WACA,WACA,WACuB;CACvB,MAAM,SAAgC,EAAE;CACxC,MAAM,kBAAkB,mBAAmB,WAAW,cAAc,OAAO;CAC3E,MAAM,QAAQ,oBAAoB,UAAU;AAG5C,KAAI,UACF,MAAK,IAAI,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK,WAAW;EACpD,MAAM,QAAQ,UAAU,MAAM,GAAG,IAAI,UAAU;AAC/C,SAAO,KAAK,EACV,YAAY,CACV;GACE,SAAS;IAAE,MAAM;IAAS,OAAO,CAAC;KAAE,MAAM;KAAO,SAAS;KAAM,CAAC;IAAE;GACnE,OAAO;GACR,CACF,EACF,CAAC;;AAKN,MAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK,WAAW;EAClD,MAAM,QAAQ,QAAQ,MAAM,GAAG,IAAI,UAAU;EAC7C,MAAM,SAAS,IAAI,aAAa,QAAQ;EACxC,MAAM,QAA6B;GACjC,YAAY,CACV;IACE,SAAS;KAAE,MAAM;KAAS,OAAO,CAAC,EAAE,MAAM,OAAO,CAAC;KAAE;IACpD,OAAO;IACP,GAAI,SAAS,EAAE,cAAc,iBAAiB,GAAG,EAAE;IACpD,CACF;GACD,GAAI,SAAS,EAAE,eAAe,OAAO,GAAG,EAAE;GAC3C;AACD,SAAO,KAAK,MAAM;;AAIpB,KAAI,QAAQ,WAAW,EACrB,QAAO,KAAK;EACV,YAAY,CACV;GACE,SAAS;IAAE,MAAM;IAAS,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAAE;GACjD,cAAc;GACd,OAAO;GACR,CACF;EACD,eAAe;EAChB,CAAC;AAGJ,QAAO;;AAGT,SAAS,kBAAkB,IAAc,QAA4B;CACnE,MAAM,OAAOC,+BAAe,IAAI,UAAU,OAAO;CAYjD,MAAM,eAA2C;EAC/C,MAAM,GAAG;EACT,MAAM,KAAK;EACZ;AACD,KAAI,GAAG,GACL,cAAa,KAAK,GAAG;AAEvB,QAAO,EAAE,cAAc;;AAGzB,SAAS,gCACP,WACA,WACA,QACA,WACA,WACuB;CACvB,MAAM,SAAgC,EAAE;AAIxC,KAAI,UACF,MAAK,IAAI,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK,WAAW;EACpD,MAAM,QAAQ,UAAU,MAAM,GAAG,IAAI,UAAU;AAC/C,SAAO,KAAK,EACV,YAAY,CACV;GACE,SAAS;IAAE,MAAM;IAAS,OAAO,CAAC;KAAE,MAAM;KAAO,SAAS;KAAM,CAAC;IAAE;GACnE,OAAO;GACR,CACF,EACF,CAAC;;CAIN,MAAM,QAAsB,UAAU,KAAK,OAAO,kBAAkB,IAAI,OAAO,CAAC;AAGhF,QAAO,KAAK;EACV,YAAY,CACV;GACE,SAAS;IAAE,MAAM;IAAS;IAAO;GACjC,cAAc,mBAAmB,WAAW,cAAc,gBAAgB;GAC1E,OAAO;GACR,CACF;EACD,eAAe,oBAAoB,UAAU;EAC9C,CAAC;AAEF,QAAO;;AAKT,SAAS,wBACP,SACA,WACA,WACqB;CACrB,MAAM,QAAsB,EAAE;AAC9B,KAAI,UACF,OAAM,KAAK;EAAE,MAAM;EAAW,SAAS;EAAM,CAAC;AAEhD,OAAM,KAAK,EAAE,MAAM,SAAS,CAAC;AAE7B,QAAO;EACL,YAAY,CACV;GACE,SAAS;IAAE,MAAM;IAAS;IAAO;GACjC,cAAc,mBAAmB,WAAW,cAAc,OAAO;GACjE,OAAO;GACR,CACF;EACD,eAAe,oBAAoB,UAAU;EAC9C;;AAGH,SAAS,4BACP,WACA,QACA,WACA,WACqB;CACrB,MAAM,QAAsB,EAAE;AAC9B,KAAI,UACF,OAAM,KAAK;EAAE,MAAM;EAAW,SAAS;EAAM,CAAC;AAEhD,OAAM,KAAK,GAAG,UAAU,KAAK,OAAO,kBAAkB,IAAI,OAAO,CAAC,CAAC;AAEnE,QAAO;EACL,YAAY,CACV;GACE,SAAS;IAAE,MAAM;IAAS;IAAO;GACjC,cAAc,mBAAmB,WAAW,cAAc,gBAAgB;GAC1E,OAAO;GACR,CACF;EACD,eAAe,oBAAoB,UAAU;EAC9C;;AAGH,SAAS,4CACP,SACA,WACA,WACA,QACA,WACA,WACA,QACuB;CACvB,MAAM,SAAgC,EAAE;AAGxC,KAAI,UACF,MAAK,IAAI,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK,WAAW;EACpD,MAAM,QAAQ,UAAU,MAAM,GAAG,IAAI,UAAU;AAC/C,SAAO,KAAK,EACV,YAAY,CACV;GACE,SAAS;IAAE,MAAM;IAAS,OAAO,CAAC;KAAE,MAAM;KAAO,SAAS;KAAM,CAAC;IAAE;GACnE,OAAO;GACR,CACF,EACF,CAAC;;AAIN,KAAI,UAAU,OAAO,SAAS,GAAG;EAM/B,MAAM,UAAUC,2CAA2B,OAAO;EAClD,MAAM,WAAW,QAAQ;AACzB,WAAS,SAAS,OAAO,MAAM;GAC7B,MAAM,SAAS,MAAM,SAAS,SAAS;GACvC,MAAM,eAAe,SACjB,mBACE,WAAW,cACX,QAAQ,eAAe,kBAAkB,OAC1C,GACD;AACJ,OAAI,MAAM,SAAS,YAAY;IAC7B,MAAM,OAAO,kBACX;KAAE,MAAM,MAAM;KAAM,WAAW,MAAM;KAAW,IAAI,MAAM;KAAI,EAC9D,OACD;AACD,WAAO,KAAK;KACV,YAAY,CACV;MACE,SAAS;OAAE,MAAM;OAAS,OAAO,CAAC,KAAK;OAAE;MACzC,GAAI,eAAe,EAAE,cAAc,GAAG,EAAE;MACxC,OAAO;MACR,CACF;KACD,GAAI,SAAS,EAAE,eAAe,oBAAoB,UAAU,EAAE,GAAG,EAAE;KACpE,CAAC;UACG;IACL,MAAM,OAAO,MAAM;AACnB,QAAI,KAAK,WAAW,EAClB,QAAO,KAAK;KACV,YAAY,CACV;MACE,SAAS;OAAE,MAAM;OAAS,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;OAAE;MACjD,GAAI,eAAe,EAAE,cAAc,GAAG,EAAE;MACxC,OAAO;MACR,CACF;KACD,GAAI,SAAS,EAAE,eAAe,oBAAoB,UAAU,EAAE,GAAG,EAAE;KACpE,CAAC;QAEF,MAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK,WAAW;KAC/C,MAAM,QAAQ,KAAK,MAAM,GAAG,IAAI,UAAU;KAC1C,MAAM,YAAY,IAAI,aAAa,KAAK;KACxC,MAAM,cAAc,UAAU,YAAY,eAAe;AACzD,YAAO,KAAK;MACV,YAAY,CACV;OACE,SAAS;QAAE,MAAM;QAAS,OAAO,CAAC,EAAE,MAAM,OAAO,CAAC;QAAE;OACpD,GAAI,cAAc,EAAE,cAAc,aAAa,GAAG,EAAE;OACpD,OAAO;OACR,CACF;MACD,GAAI,UAAU,YAAY,EAAE,eAAe,oBAAoB,UAAU,EAAE,GAAG,EAAE;MACjF,CAAC;;;IAIR;AAEF,SAAO;;AAGT,KAAI,QAAQ,WAAW,EACrB,QAAO,KAAK,EACV,YAAY,CACV;EACE,SAAS;GAAE,MAAM;GAAS,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;GAAE;EACjD,OAAO;EACR,CACF,EACF,CAAC;KAEF,MAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK,WAAW;EAClD,MAAM,QAAQ,QAAQ,MAAM,GAAG,IAAI,UAAU;AAC7C,SAAO,KAAK,EACV,YAAY,CACV;GACE,SAAS;IAAE,MAAM;IAAS,OAAO,CAAC,EAAE,MAAM,OAAO,CAAC;IAAE;GACpD,OAAO;GACR,CACF,EACF,CAAC;;CAIN,MAAM,QAAsB,UAAU,KAAK,OAAO,kBAAkB,IAAI,OAAO,CAAC;AAEhF,QAAO,KAAK;EACV,YAAY,CACV;GACE,SAAS;IAAE,MAAM;IAAS;IAAO;GACjC,cAAc,mBAAmB,WAAW,cAAc,gBAAgB;GAC1E,OAAO;GACR,CACF;EACD,eAAe,oBAAoB,UAAU;EAC9C,CAAC;AAEF,QAAO;;AAGT,SAAS,wCACP,SACA,WACA,QACA,WACA,WACA,QACqB;CACrB,MAAM,QAAsB,EAAE;AAC9B,KAAI,UACF,OAAM,KAAK;EAAE,MAAM;EAAW,SAAS;EAAM,CAAC;CAGhD,IAAI;AACJ,KAAI,UAAU,OAAO,SAAS,GAAG;EAK/B,MAAM,UAAUA,2CAA2B,OAAO;EAClD,MAAM,WAAW,QAAQ;AACzB,kBAAgB,QAAQ;AACxB,OAAK,MAAM,SAAS,SAClB,KAAI,MAAM,SAAS,WACjB,OAAM,KACJ,kBAAkB;GAAE,MAAM,MAAM;GAAM,WAAW,MAAM;GAAW,IAAI,MAAM;GAAI,EAAE,OAAO,CAC1F;MAED,OAAM,KAAK,EAAE,MAAM,MAAM,MAAM,CAAC;QAG/B;AAEL,QAAM,KAAK,EAAE,MAAM,SAAS,CAAC;AAC7B,QAAM,KAAK,GAAG,UAAU,KAAK,OAAO,kBAAkB,IAAI,OAAO,CAAC,CAAC;;AAGrE,QAAO;EACL,YAAY,CACV;GACE,SAAS;IAAE,MAAM;IAAS;IAAO;GACjC,cAAc,mBACZ,WAAW,cACX,kBAAkB,QAAQ,SAAS,gBACpC;GACD,OAAO;GACR,CACF;EACD,eAAe,oBAAoB,UAAU;EAC9C;;AAKH,SAAS,uBAAuB,OAA0D;AACxF,KAAI,OAAO,MAAM,UAAU,SACzB,QAAO;EAAE,UAAUC,6BAAa,MAAM,UAAU,MAAM;EAAE,MAAM,MAAM;EAAO;AAE7E,QAAO;EACL,UAAU,MAAM,MAAM,eAAe;EACrC,MAAM,MAAM,MAAM;EACnB;;AAiBH,SAAS,sBACP,OACA,WACA,QACA,cACc;CAEd,MAAM,QAAsB,CAAC,EAAE,YADZ,uBAAuB,MAAM,EACL,CAAC;AAC5C,KAAI,aACF,OAAM,KAAK;EAAE,MAAM;EAAc,SAAS;EAAM,CAAC;AAEnD,KAAI,MAAM,QACR,OAAM,KAAK,EAAE,MAAM,MAAM,SAAS,CAAC;AAErC,KAAI,UAAU,OACZ,OAAM,KAAK,GAAG,UAAU,KAAK,OAAO,kBAAkB,IAAI,OAAO,CAAC,CAAC;AAErE,QAAO;;AAGT,SAAS,yBACP,OACA,WACA,QACA,cACqB;AACrB,QAAO;EACL,YAAY,CACV;GACE,SAAS;IACP,MAAM;IACN,OAAO,sBAAsB,OAAO,WAAW,QAAQ,aAAa;IACrE;GACD,cAAc,UAAU,SAAS,kBAAkB;GACnD,OAAO;GACR,CACF;EACD,eAAeH,uBAAmB;EACnC;;AAGH,SAAS,6BACP,OACA,WACA,QACA,cACuB;AACvB,QAAO,CACL;EACE,YAAY,CACV;GACE,SAAS;IACP,MAAM;IACN,OAAO,sBAAsB,OAAO,WAAW,QAAQ,aAAa;IACrE;GACD,cAAc,UAAU,SAAS,kBAAkB;GACnD,OAAO;GACR,CACF;EACD,eAAeA,uBAAmB;EACnC,CACF;;AAcH,eAAe,qBACb,KACA,QACA,kBACkB;CAClB,MAAM,OACJ,OAAO,qBAAqB,WAAW,EAAE,SAAS,kBAAkB,GAAI,oBAAoB,EAAE;CAChG,MAAM,UAAU,KAAK,WAAW;CAChC,MAAM,UAAU,KAAK;CACrB,MAAM,EAAE,iBAAiB,gBAAgB;CACzC,MAAM,SAAS,KAAK;CACpB,MAAM,cAAc,KAAK;AAEzB,KAAI,IAAI,cAAe,QAAO;AAC9B,KAAI,UAAU,gBAAgB,oBAAoB;AAClD,KAAI,UAAU,iBAAiB,WAAW;AAC1C,KAAI,UAAU,cAAc,aAAa;CAEzC,IAAI,aAAa;AACjB,MAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,aAAaI,kCAAe,YAAY,SAAS,SAAS,iBAAiB,YAAY;AAC7F,MAAI,aAAa,EAAG,OAAMC,yBAAM,YAAY,OAAO;AACnD,MAAI,QAAQ,QAAS,QAAO;AAC5B,MAAI,IAAI,cAAe,QAAO;AAE9B,MAAI,MAAM,SAAS,KAAK,UAAU,MAAM,CAAC,MAAM;AAC/C,iBAAe;AACf,MAAI,QAAQ,QAAS,QAAO;AAC5B;;AAGF,KAAI,CAAC,IAAI,cACP,KAAI,KAAK;AAEX,QAAO;;;AAIT,SAAS,yBACP,MACA,SACA,WACA,WACA,QACA,QACwE;CACxE,MAAM,WAAW,KAAK;CACtB,MAAM,WAAWC,0CAA0B,SAAS;AACpD,KAAI,EAAE,YAAYC,mCAAmB,SAAS,IAAIC,+BAAe,SAAS,EACxE,OAAM,IAAI,MAAM,sDAAsD;CAExE,MAAM,UACJ,YAAY,SAAS,QAAQ,SAASN,2CAA2B,SAAS,OAAO,GAAG;CACtF,MAAM,UAAU,SAAS,YAAY,aAAa,WAAY,SAAS,WAAW,KAAM;CAGxF,MAAM,QAAQ,SAAS,cAAc,eAAe,WAAY,SAAS,aAAa,EAAE,GAAI,EAAE;CAC9F,MAAM,YAAYO,iCAAiB,SAAS;AAC5C,QAAO,UAAU;CACjB,MAAM,QAAQ,KAAK,QAAQ;CAC3B,MAAM,YAAoF;EACxF,SAAS;GAAE,MAAM;GAAS,OAAO,EAAE;GAAE;EACrC,OAAO;EACR;CACD,IAAI;AACJ,KAAI,UAAU,0BAA0B;EACtC,MAAM,SAAS,MAAM,KAAK,QAAQ,SAAS;AAC3C,MAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,6DAA6D;AAC1F,WAAS,CACP,EACE,YAAY,CACV;GACE,OAAO;GACP,cAAc;GACd,eAAe,4BAA4B,OAAO,KAAK,GAAG,OAAO,UAAU;GAC5E,CACF,EACF,CACF;YACQ,UAAU,uBAAuB,CAAC,QAAQ,OAAO,QAAQ;AAClE,YAAU,eAAe;AACzB,WAAS,CAAC,EAAE,YAAY,CAAC,UAAU,EAAE,CAAC;YAC7B,UAAU,wBAAwB;AAE3C,YAAU,QAAQ,QAAQ,UAAU,CAAC,EAAE,MAAM,SAAS,CAAC,GAAG,EAAE;AAC5D,YAAU,eAAe;AACzB,WAAS,CAAC,EAAE,YAAY,CAAC,UAAU,EAAE,CAAC;YAC7B,UAAU,kBAAkB;AACrC,YAAU,QAAQ,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;AACxC,YAAU,eAAe;AACzB,WAAS,CAAC,EAAE,YAAY,CAAC,UAAU,EAAE,CAAC;YAC7B,UAAU,kBAAkB;AACrC,YAAU,eAAe;AACzB,YAAU,gBAAgB,CACxB;GAAE,UAAU;GAAmC,aAAa;GAAQ,SAAS;GAAM,CACpF;AACD,WAAS,CAAC,EAAE,YAAY,CAAC,UAAU,EAAE,CAAC;YAC7B,UAAU,kBAAkB;AACrC,YAAU,QAAQ,QAAQ,CAAC;GAAE,MAAM,KAAK,aAAa;GAAI,SAAS;GAAM,CAAC;AACzE,YAAU,eAAe;AACzB,WAAS,CAAC,EAAE,YAAY,CAAC,UAAU,EAAE,CAAC;QACjC;EACL,MAAM,YAAYC,yCAAyB,SAAS,WAAW,QAAQ,OAAO,QAAQ,OAAO;AAC7F,MAAI,UAAU,oBAAqB,WAAU,eAAe;AAC5D,MAAI,SACF,UAAS,YACL,4CACE,SACA,OACA,WACA,QACA,WACA,WACA,SAAS,OACV,GACD,CACE,wCACE,SACA,OACA,QACA,WACA,WACA,SAAS,OACV,CACF;WACIH,mCAAmB,SAAS,CACrC,UAAS,YACL,gCAAgC,OAAO,WAAW,QAAQ,WAAW,UAAU,GAC/E,CAAC,4BAA4B,OAAO,QAAQ,WAAW,UAAU,CAAC;MAEtE,UAAS,YACL,4BAA4B,SAAS,WAAW,WAAW,UAAU,GACrE,CAAC,wBAAwB,SAAS,WAAW,UAAU,CAAC;;CAGhE,MAAM,QAAQ,OAAO,SAAS,UAC5B,MAAM,WAAW,SAAS,SAAS,KAAK,SAAS,SAAS,EAAE,CAAC,CAC9D;CACD,MAAM,kBAAkB,MAAM,SAAS,SACrC,KAAK,eACD,CACE;EACE,MAAM,KAAK,aAAa;EACxB,WAAW,KAAK,UAAU,KAAK,aAAa,KAAK;EACjD,GAAI,KAAK,aAAa,KAAK,EAAE,IAAI,KAAK,aAAa,IAAI,GAAG,EAAE;EAC7D,CACF,GACD,EAAE,CACP;CACD,MAAM,SAAS,QAAQ,SACpB,KAAK,YACJ,OAAO,QAAQ,YAAY,WACvB,QAAQ,WACP,QAAQ,WAAW,EAAE,EAAE,KAAK,SAAS,KAAK,QAAQ,GAAG,CAAC,KAAK,GAAG,CACpE,CACA,KAAK,GAAG;CACX,MAAM,SAAS,MACZ,KACE,SACC,KAAK,SACJ,KAAK,eAAe,KAAK,aAAa,OAAO,KAAK,UAAU,KAAK,aAAa,KAAK,GAAG,IAC1F,CACA,KAAK,GAAG;AACX,MAAK,MAAM,SAAS,OAAQ,QAAO,MAAM;AACzC,QAAO,OAAO,SAAS,GAAG,gBAAgBP,sBAAkB,QAAW;EACrE,MAAM;EACN,YAAY;EACZ,gBAAgB;EACjB,CAAC;AACF,QAAO;EAAE;EAAQ,SAAS;GAAE,GAAG,KAAK;GAAS;GAAiB;EAAE;;AAKlE,eAAsB,aACpB,KACA,KACA,KACA,OACA,WACA,UACA,SACA,UACA,gBACA,cAAiC,UAClB;CACf,MAAM,EAAE,WAAW;CACnB,MAAM,OAAO,gBAAgB,aAAa,cAAc;AACxD,gBAAe,IAAI;CAEnB,IAAI;AACJ,KAAI;AACF,cAAY,KAAK,MAAM,IAAI;UACpB,UAAU;EACjB,MAAM,SAAS,oBAAoB,QAAQ,SAAS,UAAU;AAC9D,UAAQ,IAAI;GACV,QAAQ,IAAI,UAAU;GACtB,MAAM,IAAI,OAAO,kBAAkB,MAAM;GACzC,SAASW,+BAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE,QAAQ;IAAK,SAAS;IAAM;GACzC,CAAC;AACF,wCACE,KACA,KACAC,2BAAY,UAAU,cAAc;GAClC,SAAS,wBAAwB;GACjC,UAAU;GACV,QAAQ;GACT,CAAC,CAAC,KACJ;AACD;;AAMF,KAAI,CAACC,6BAAa,UAAU,EAAE;AAC5B,UAAQ,IAAI;GACV,QAAQ,IAAI,UAAU;GACtB,MAAM,IAAI,OAAO,kBAAkB,MAAM;GACzC,SAASF,+BAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE,QAAQ;IAAK,SAAS;IAAM;GACzC,CAAC;AACF,wCACE,KACA,KACAC,2BAAY,UAAU,cAAc;GAClC,SAAS;GACT,UAAU;GACV,QAAQ;GACT,CAAC,CAAC,KACJ;AACD;;CAIF,MAAM,mBAAmB,mBAAmB,UAAU;AACtD,KAAI,kBAAkB;AACpB,UAAQ,IAAI;GACV,QAAQ,IAAI,UAAU;GACtB,MAAM,IAAI,OAAO,kBAAkB,MAAM;GACzC,SAASD,+BAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE,QAAQ;IAAK,SAAS;IAAM;GACzC,CAAC;AACF,wCACE,KACA,KACAC,2BAAY,UAAU,cAAc;GAClC,SAAS,qBAAqB;GAC9B,UAAU;GACV,QAAQ;GACT,CAAC,CAAC,KACJ;AACD;;CAIF,MAAM,gBAAgB,0BAA0B,WAAW,OAAO,UAAU;AAC5E,eAAc,gBAAgB;AAC9B,eAAc,WAAWE,2BAAW,IAAI;CAExC,MAAM,SAASC,0BAAU,IAAI;CAC7B,MAAM,EAAE,SAAS,4BAA4BC,sCAC3C,UACA,eACA,QAAQ,6BAA6B,OAAO,EAC5C,SAAS,kBAITC,kCAAmB,CAAC,CAAC,SAAS,QAAQ,SAAS,OAAO,CACvD;CACD,MAAM,OAAO,IAAI,OAAO,kBAAkB,MAAM;AAEhD,KAAI,QACF,QAAO,MAAM,oBAAoB,KAAK,UAAU,QAAQ,MAAM,CAAC,MAAM,GAAG,IAAI,GAAG;KAE/E,QAAO,MAAM,iCAAiC;AAGhD,KAAI,QACF,SAAQ,2BAA2B,SAAS,UAAU,OAAO;AAG/D,KACE,MAAMC,8BACJ,KACA,SACA,SAAS,OACT,IAAI,SACJ,IAAI,KACJ,SACA;EACE,QAAQ,IAAI,UAAU;EACtB;EACA,SAASP,+BAAe,IAAI,QAAQ;EACpC,MAAM;EACP,EACD,UAAU,YAAY,SACtB,SAAS,UACT,SAAS,OACV,CAED;AAEF,KAAI,CAAC,SAAS;EACZ,MAAM,YAAYQ,uCAAwB,SAAS,QAAQ,IAAI,QAAQ;AACvE,MAAI,UAAU,aAAa;GACzB,MAAM,gBAAgBC,qCAAqB,wBAAwB;AACnE,UAAO,MAAMC,qCAAqB,IAAI,UAAU,QAAQ,MAAM,wBAAwB,CAAC;AACvF,WAAQ,IAAI;IACV,QAAQ,IAAI,UAAU;IACtB;IACA,SAASV,+BAAe,IAAI,QAAQ;IACpC,MAAM;IACN,UAAU;KACR,QAAQ;KACR,SAAS;KACT,GAAGW,mCAAoB,SAAS,QAAQ,IAAI,QAAQ;KACrD;IACF,CAAC;AACF,yCACE,KACA,KACAV,2BAAY,UAAU,eAAe;IACnC,SAAS;IACT,UAAU;IACV,QAAQ;IACT,CAAC,CAAC,KACJ;AACD;;AAGF,MAAI,UAAU,YAAY,SAAS,QAAQ;GACzC,MAAM,UAAU,MAAMW,gCACpB,KACA,KACA,eACA,aACA,MACA,UACA,UACA,IACD;AACD,OAAI,YAAY,kBAAmB;AACnC,OAAI,YAAY,kBAAkB;AAChC,YAAQ,IAAI;KACV,QAAQ,IAAI,UAAU;KACtB;KACA,SAASZ,+BAAe,IAAI,QAAQ;KACpC,MAAM;KACN,UAAU;MAAE,QAAQ,IAAI,cAAc;MAAK,SAAS;MAAM,QAAQ;MAAS;KAC5E,CAAC;AACF;;;AAGJ,UAAQ,IAAI;GACV,QAAQ,IAAI,UAAU;GACtB;GACA,SAASA,+BAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IACR,QAAQ;IACR,SAAS;IACT,GAAGW,mCAAoB,SAAS,QAAQ,IAAI,QAAQ;IACrD;GACF,CAAC;AACF,wCACE,KACA,KACAV,2BAAY,UAAU,gBAAgB;GACpC,SAAS;GACT,UAAU;GACV,QAAQ;GACT,CAAC,CAAC,KACJ;AACD;;CAGF,MAAM,WAAW,MAAMY,gCAAgB,SAAS,cAAc;CAC9D,MAAM,cAAcC,oCAAgB;EAClC,MAAM;EACN,gBAAgB;EAChB;EACA;EACA,SAAS;EACT,QAAQ;EACR;EACA,YAAY,IAAI;EAChB,KAAK,IAAI;EACV,CAAC;AACF,KAAI,YAAY,SAAS,SAAS;AAQhC,+CAAyB;GAAE,OAPb,QAAQ,IAAI;IACxB,QAAQ,IAAI,UAAU;IACtB;IACA,SAASd,+BAAe,IAAI,QAAQ;IACpC,MAAM;IACN,UAAU;KAAE,QAAQ,YAAY;KAAQ;KAAS,OAAO,YAAY;KAAS;IAC9E,CAAC;GACgC,SAAS,YAAY;GAAS;GAAU;GAAQ,CAAC;AACnF,MAAI,YAAY,SAAS,YAAY,WAAW,EAC9C,QAAO,MAAM,GAAG,IAAI,UAAU,OAAO,GAAG,KAAK,IAAI,YAAY,UAAU;AAEzE,wCACE,KACA,YAAY,QACZC,2BAAY,UAAU,eAAe;GACnC,UAAU,YAAY;GACtB,SAAS,YAAY;GACrB,QAAQ,YAAY,WAAW,MAAM,qBAAqB;GAC3D,CAAC,CAAC,KACJ;AACD;;CAGF,MAAM,UAAU,QAAQ,WAAW,SAAS;CAC5C,MAAM,YAAY,KAAK,IAAI,GAAG,QAAQ,aAAa,SAAS,UAAU;CACtE,MAAM,cAAc,QAAQ,eAAe,SAAS;AAEpD,KAAI,YAAY,SAAS,WAAW;EAClC,MAAM,WAAW,yBACf,aACA,eACA,WACA,WACA,QACAO,uCAAwB,SAAS,QAAQ,IAAI,QAAQ,CAAC,qBACvD;EACD,MAAM,QAAQ,QAAQ,IAAI;GACxB,QAAQ,IAAI,UAAU;GACtB;GACA,SAASR,+BAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE,QAAQ;IAAK;IAAS;GACnC,CAAC;AACF,+CAAyB;GAAE;GAAO,SAAS,SAAS;GAAS;GAAU;GAAQ,CAAC;AAChF,MAAI,CAAC,WAAW;AACd,OAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,OAAI,IAAI,KAAK,UAAU,SAAS,OAAO,GAAG,CAAC;SACtC;GACL,MAAM,eAAee,8CAAyB,QAAQ;AAStD,OAAI,CARc,MAAM,qBAAqB,KAAK,SAAS,QAAQ;IACjE;IACA,kBAAkB,QAAQ;IAC1B,iBAAiB,QAAQ;IACzB;IACA,QAAQ,cAAc;IACtB,aAAa,cAAc;IAC5B,CAAC,EACc;AACd,QAAI,CAAC,IAAI,cAAe,KAAI,SAAS;AACrC,UAAM,SAAS,cAAc;AAC7B,UAAM,SAAS,kBAAkB,cAAc,QAAQ;;AAEzD,iBAAc,SAAS;;AAEzB;;AAIF,KAAIC,gCAAgB,SAAS,EAAE;EAC7B,MAAM,SAAS,SAAS,UAAU;AAQlC,+CAAyB;GAAE,OAPR,QAAQ,IAAI;IAC7B,QAAQ,IAAI,UAAU;IACtB;IACA,SAAShB,+BAAe,IAAI,QAAQ;IACpC,MAAM;IACN,UAAU;KAAE;KAAQ;KAAS;IAC9B,CAAC;GAC4C,SAAS,YAAY;GAAS;GAAU;GAAQ,CAAC;AAC/F,wCACE,KACA,QACAC,2BAAY,UAAU,WAAW;GAC/B,UAAU;GACV,SAAS,SAAS,MAAM;GACxB,QAAQ,SAAS,MAAM,QAAQ;GAChC,CAAC,CAAC,MACH,EAAE,YAAY,SAAS,YAAY,CACpC;AACD;;AAIF,KAAIgB,gCAAgB,SAAS,EAAE;EAC7B,MAAM,kBAAkBT,uCACtB,SAAS,QACT,IAAI,QACL,CAAC;EACF,MAAM,eAAeT,yCACnB,SAAS,WACT,OACA,iBACA,SAAS,OACV;EACD,MAAM,eAAe,QAAQ,IAAI;GAC/B,QAAQ,IAAI,UAAU;GACtB;GACA,SAASC,+BAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE,QAAQ;IAAK;IAAS;GACnC,CAAC;AACF,+CAAyB;GACvB,OAAO;GACP,SAAS,YAAY;GACrB;GACA;GACD,CAAC;EAEF,MAAM,iBAAiB,MAAM,QAAQ,SAAS,UAAU,GACpDkB,+CAA+B,UAAU,KAAK,GAC9C,EAAE;AACN,MAAI,CAAC,WAAW;GACd,MAAM,OAAO,yBAAyB,UAAU,gBAAgB,QAAQ,aAAa;AACrF,OAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,OAAI,IAAI,KAAK,UAAU,KAAK,CAAC;SACxB;GACL,MAAM,SAAS,6BAA6B,UAAU,gBAAgB,QAAQ,aAAa;GAC3F,MAAM,eAAeH,8CAAyB,QAAQ;AAStD,OAAI,CARc,MAAM,qBAAqB,KAAK,QAAQ;IACxD;IACA,kBAAkB,QAAQ;IAC1B,iBAAiB,QAAQ;IACzB;IACA,QAAQ,cAAc;IACtB,aAAa,cAAc;IAC5B,CAAC,EACc;AACd,QAAI,CAAC,IAAI,cAAe,KAAI,SAAS;AACrC,iBAAa,SAAS,cAAc;AACpC,iBAAa,SAAS,kBAAkB,cAAc,QAAQ;;AAEhE,iBAAc,SAAS;;AAEzB;;AAIF,KAAIpB,0CAA0B,SAAS,EAAE;AACvC,MAAI,SAAS,aAAa,OACxB,QAAO,KAAK,8EAA8E;EAE5F,MAAM,YAAYG,iCAAiB,SAAS;EAC5C,MAAM,kBAAkBU,uCACtB,SAAS,QACT,IAAI,QACL,CAAC;EACF,MAAM,eAAeT,yCACnB,SAAS,WACT,OACA,iBACA,SAAS,OACV;EACD,MAAM,eAAe,QAAQ,IAAI;GAC/B,QAAQ,IAAI,UAAU;GACtB;GACA,SAASC,+BAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE,QAAQ;IAAK;IAAS;GACnC,CAAC;AACF,+CAAyB;GACvB,OAAO;GACP,SAAS,YAAY;GACrB;GACA;GACD,CAAC;EACF,MAAM,oBAAoBmB,gDAAgC,UAAU,KAAK;AACzE,MAAI,CAAC,WAAW;GACd,MAAM,OAAO,wCACX,SAAS,WAAW,IACpB,mBACA,QACA,cACA,WACA,SAAS,OACV;AACD,OAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,OAAI,IAAI,KAAK,UAAU,KAAK,CAAC;SACxB;GACL,MAAM,SAAS,4CACb,SAAS,WAAW,IACpB,mBACA,WACA,QACA,cACA,WACA,SAAS,OACV;GACD,MAAM,eAAeJ,8CAAyB,QAAQ;AAStD,OAAI,CARc,MAAM,qBAAqB,KAAK,QAAQ;IACxD;IACA,kBAAkB,QAAQ;IAC1B,iBAAiB,QAAQ;IACzB;IACA,QAAQ,cAAc;IACtB,aAAa,cAAc;IAC5B,CAAC,EACc;AACd,QAAI,CAAC,IAAI,cAAe,KAAI,SAAS;AACrC,iBAAa,SAAS,cAAc;AACpC,iBAAa,SAAS,kBAAkB,cAAc,QAAQ;;AAEhE,iBAAc,SAAS;;AAEzB;;AAIF,KAAIlB,+BAAe,SAAS,EAAE;AAC5B,MAAI,SAAS,aAAa,OACxB,QAAO,KAAK,8EAA8E;EAE5F,MAAM,YAAYC,iCAAiB,SAAS;EAC5C,MAAM,kBAAkBU,uCACtB,SAAS,QACT,IAAI,QACL,CAAC;EACF,MAAM,eAAeT,yCACnB,SAAS,WACT,OACA,iBACA,SAAS,OACV;EACD,MAAM,eAAe,QAAQ,IAAI;GAC/B,QAAQ,IAAI,UAAU;GACtB;GACA,SAASC,+BAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE,QAAQ;IAAK;IAAS;GACnC,CAAC;AACF,+CAAyB;GACvB,OAAO;GACP,SAAS,YAAY;GACrB;GACA;GACD,CAAC;AACF,MAAI,CAAC,WAAW;GACd,MAAM,OAAO,wBAAwB,SAAS,SAAS,cAAc,UAAU;AAC/E,OAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,OAAI,IAAI,KAAK,UAAU,KAAK,CAAC;SACxB;GACL,MAAM,SAAS,4BACb,SAAS,SACT,WACA,cACA,UACD;GACD,MAAM,eAAee,8CAAyB,QAAQ;AAStD,OAAI,CARc,MAAM,qBAAqB,KAAK,QAAQ;IACxD;IACA,kBAAkB,QAAQ;IAC1B,iBAAiB,QAAQ;IACzB;IACA,QAAQ,cAAc;IACtB,aAAa,cAAc;IAC5B,CAAC,EACc;AACd,QAAI,CAAC,IAAI,cAAe,KAAI,SAAS;AACrC,iBAAa,SAAS,cAAc;AACpC,iBAAa,SAAS,kBAAkB,cAAc,QAAQ;;AAEhE,iBAAc,SAAS;;AAEzB;;AAIF,KAAInB,mCAAmB,SAAS,EAAE;AAChC,MAAI,SAAS,aAAa,OACxB,QAAO,KAAK,8EAA8E;EAE5F,MAAM,YAAYE,iCAAiB,SAAS;EAC5C,MAAM,kBAAkBU,uCACtB,SAAS,QACT,IAAI,QACL,CAAC;EACF,MAAM,eAAeT,yCACnB,SAAS,WACT,OACA,iBACA,SAAS,OACV;EACD,MAAM,eAAe,QAAQ,IAAI;GAC/B,QAAQ,IAAI,UAAU;GACtB;GACA,SAASC,+BAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE,QAAQ;IAAK;IAAS;GACnC,CAAC;AACF,+CAAyB;GACvB,OAAO;GACP,SAAS,YAAY;GACrB;GACA;GACD,CAAC;EACF,MAAM,oBAAoBmB,gDAAgC,UAAU,KAAK;AACzE,MAAI,CAAC,WAAW;GACd,MAAM,OAAO,4BAA4B,mBAAmB,QAAQ,cAAc,UAAU;AAC5F,OAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,OAAI,IAAI,KAAK,UAAU,KAAK,CAAC;SACxB;GACL,MAAM,SAAS,gCACb,mBACA,WACA,QACA,cACA,UACD;GACD,MAAM,eAAeJ,8CAAyB,QAAQ;AAStD,OAAI,CARc,MAAM,qBAAqB,KAAK,QAAQ;IACxD;IACA,kBAAkB,QAAQ;IAC1B,iBAAiB,QAAQ;IACzB;IACA,QAAQ,cAAc;IACtB,aAAa,cAAc;IAC5B,CAAC,EACc;AACd,QAAI,CAAC,IAAI,cAAe,KAAI,SAAS;AACrC,iBAAa,SAAS,cAAc;AACpC,iBAAa,SAAS,kBAAkB,cAAc,QAAQ;;AAEhE,iBAAc,SAAS;;AAEzB;;AAWF,8CAAyB;EAAE,OAPN,QAAQ,IAAI;GAC/B,QAAQ,IAAI,UAAU;GACtB;GACA,SAASf,+BAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE,QAAQ;IAAK;IAAS;GACnC,CAAC;EAC8C,SAAS,YAAY;EAAS;EAAU;EAAQ,CAAC;AACjG,uCACE,KACA,KACAC,2BAAY,UAAU,oBAAoB;EACxC,SAAS;EACT,UAAU;EACV,QAAQ;EACT,CAAC,CAAC,KACJ"}
|
|
1
|
+
{"version":3,"file":"gemini.cjs","names":["validateToolsField","mapGeminiFinish","renderGeminiUsage","resolveCitations","surrogateSafeChunks","fixtureFiles","servedToolArgs","resolveFixtureBlockOutcome","formatToMime","sseCodec","Logger","isCombinedFixtureResponse","isTextResponse","isToolCallResponse","resolveReasoningForModel","extractOverrides","flattenHeaders","renderError","isJsonObject","getContext","getTestId","matchFixtureDiagnostic","recordMatchOptions","applyChaosAsync","resolveRequestDecisions","strictNoMatchMessage","strictNoMatchLogLine","strictOverrideField","withHangUpDetection","proxyAndRecord","proxyInterruption","resolveResponse","planMisbehavior","deliverJson","misbehaviorPayloadLength","deliverStream","isRawResponse","serveRawResponse","isErrorResponse","isAudioResponse","requireServedFunctionToolCalls","servedPayloadLength","requireEmittedFunctionToolCalls"],"sources":["../src/gemini.ts"],"sourcesContent":["/**\n * Google Gemini GenerateContent API support.\n *\n * Translates incoming Gemini requests into the ChatCompletionRequest format\n * used by the fixture router, and converts fixture responses back into the\n * Gemini GenerateContent streaming (or non-streaming) format.\n */\nimport { resolveRequestDecisions, strictOverrideField } from \"./response/policy.js\";\nimport { renderError } from \"./response/errors.js\";\nimport { serveRawResponse } from \"./response/raw.js\";\n\nimport type * as http from \"node:http\";\nimport type {\n AudioResponse,\n ChatCompletionRequest,\n ChatMessage,\n Fixture,\n FixtureBlock,\n HandlerDefaults,\n RecordProviderKey,\n ResponseOverrides,\n ToolCall,\n ToolDefinition,\n} from \"./types.js\";\nimport {\n isTextResponse,\n isToolCallResponse,\n isCombinedFixtureResponse,\n isErrorResponse,\n isRawResponse,\n isAudioResponse,\n extractOverrides,\n requireServedFunctionToolCalls,\n requireEmittedFunctionToolCalls,\n validateToolsField,\n formatToMime,\n flattenHeaders,\n isJsonObject,\n getContext,\n getTestId,\n resolveFixtureBlockOutcome,\n resolveCitations,\n resolveResponse,\n resolveReasoningForModel,\n strictNoMatchMessage,\n strictNoMatchLogLine,\n servedToolArgs,\n fixtureFiles,\n type ResolvedCitation,\n surrogateSafeChunks,\n} from \"./helpers.js\";\nimport { matchFixtureDiagnostic, recordMatchOptions } from \"./router.js\";\nimport { writeErrorResponse, sseCodec } from \"./sse-writer.js\";\nimport type { Journal } from \"./journal.js\";\nimport { Logger } from \"./logger.js\";\nimport { applyChaosAsync } from \"./chaos.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\nimport { planMisbehavior, recordMisbehaviorOutcome, type MisbehaviorPlan } from \"./misbehavior.js\";\nimport { mapGeminiFinish } from \"./response/finish.js\";\nimport { deliverJson, deliverStream } from \"./response/deliver.js\";\nimport { proxyInterruption, withHangUpDetection } from \"./response/proxy.js\";\nimport { misbehaviorPayloadLength, servedPayloadLength } from \"./response/timing.js\";\nimport { render as renderGeminiUsage } from \"./response/usage/codecs/gemini.js\";\n\n// ─── Gemini request types ───────────────────────────────────────────────────\n\ninterface GeminiPart {\n text?: string;\n thought?: boolean;\n functionCall?: { name: string; args: Record<string, unknown>; id?: string };\n functionResponse?: { name: string; response: unknown; id?: string };\n inlineData?: { mimeType: string; data: string };\n}\n\ninterface GeminiContent {\n role?: string;\n parts: GeminiPart[];\n}\n\ninterface GeminiFunctionDeclaration {\n name: string;\n description?: string;\n parameters?: object;\n parametersJsonSchema?: object;\n}\n\ninterface GeminiToolDef {\n functionDeclarations?: GeminiFunctionDeclaration[];\n}\n\ninterface GeminiRequest {\n contents?: GeminiContent[];\n systemInstruction?: GeminiContent;\n tools?: GeminiToolDef[];\n generationConfig?: {\n temperature?: number;\n maxOutputTokens?: number;\n [key: string]: unknown;\n };\n [key: string]: unknown;\n}\n\n// ─── Input conversion: Gemini → ChatCompletions messages ────────────────────\n\n/**\n * Validate the shape of a Gemini `generateContent` body.\n *\n * Returns an error detail string when the shape is wrong, or null when\n * `geminiToCompletionRequest` can safely consume it. Wrong types here used\n * to throw inside the converter (`parts.filter` on a missing `parts`,\n * iterating the characters of a string `contents`, `.flatMap` on a string\n * `tools`) and surface as 500s. A present-but-part-less content or\n * systemInstruction is tolerated (treated as no text) rather than rejected.\n */\nfunction validateGeminiBody(req: GeminiRequest): string | null {\n if (req.contents !== undefined && req.contents !== null && !Array.isArray(req.contents)) {\n return \"contents must be an array\";\n }\n if (Array.isArray(req.contents)) {\n for (let i = 0; i < req.contents.length; i++) {\n const content = req.contents[i] as unknown;\n if (content === null || typeof content !== \"object\" || Array.isArray(content)) {\n return `contents[${i}] must be an object`;\n }\n const parts = (content as { parts?: unknown }).parts;\n if (parts !== undefined && parts !== null && !Array.isArray(parts)) {\n return `contents[${i}].parts must be an array`;\n }\n }\n }\n if (req.systemInstruction !== undefined && req.systemInstruction !== null) {\n if (typeof req.systemInstruction !== \"object\" || Array.isArray(req.systemInstruction)) {\n return \"systemInstruction must be an object\";\n }\n const parts = req.systemInstruction.parts as unknown;\n if (parts !== undefined && parts !== null && !Array.isArray(parts)) {\n return \"systemInstruction.parts must be an array\";\n }\n }\n const toolsError = validateToolsField(req.tools);\n if (toolsError) return toolsError;\n if (Array.isArray(req.tools)) {\n for (const [toolIndex, tool] of req.tools.entries()) {\n if (!Array.isArray(tool.functionDeclarations)) continue;\n const declarationIndex = tool.functionDeclarations.findIndex(\n (declaration) => declaration === null,\n );\n if (declarationIndex !== -1) {\n return `tools[${toolIndex}].functionDeclarations[${declarationIndex}] must not be null`;\n }\n }\n }\n return null;\n}\n\nexport function geminiToCompletionRequest(\n req: GeminiRequest,\n model: string,\n stream: boolean,\n): ChatCompletionRequest {\n const messages: ChatMessage[] = [];\n\n // systemInstruction → system message\n if (req.systemInstruction) {\n const text = (req.systemInstruction.parts ?? [])\n .filter((p) => p !== null && p !== undefined && p.text !== undefined)\n .map((p) => p.text!)\n .join(\"\");\n if (text) {\n messages.push({ role: \"system\", content: text });\n }\n }\n\n if (req.contents) {\n let callCounter = 0;\n for (const content of req.contents) {\n const role = content.role ?? \"user\";\n\n if (role === \"user\") {\n // Check for functionResponse parts\n const parts = content.parts ?? [];\n const funcResponses = parts.filter(\n (p) => p !== null && p !== undefined && p.functionResponse,\n );\n const textParts = parts.filter(\n (p) => p !== null && p !== undefined && p.text !== undefined && !p.thought,\n );\n\n if (funcResponses.length > 0) {\n // functionResponse → tool message; match IDs from the preceding assistant's tool_calls\n const lastAssistant = [...messages]\n .reverse()\n .find((m) => m.role === \"assistant\" && m.tool_calls);\n const matchedToolCallIds = new Set<string>();\n for (const part of funcResponses) {\n const matchingCall = lastAssistant?.tool_calls?.find(\n (tc) =>\n tc.function.name === part.functionResponse!.name && !matchedToolCallIds.has(tc.id),\n );\n if (matchingCall) matchedToolCallIds.add(matchingCall.id);\n const toolCallId =\n matchingCall?.id ?? `call_gemini_${part.functionResponse!.name}_${callCounter++}`;\n messages.push({\n role: \"tool\",\n content:\n typeof part.functionResponse!.response === \"string\"\n ? part.functionResponse!.response\n : JSON.stringify(part.functionResponse!.response),\n tool_call_id: toolCallId,\n });\n }\n // Any text parts alongside → user message\n if (textParts.length > 0) {\n messages.push({\n role: \"user\",\n content: textParts.map((p) => p.text!).join(\"\"),\n });\n }\n } else {\n // Regular user text\n const text = textParts.map((p) => p.text!).join(\"\");\n messages.push({ role: \"user\", content: text });\n }\n } else if (role === \"model\") {\n // Check for functionCall parts\n const parts = content.parts ?? [];\n const funcCalls = parts.filter((p) => p !== null && p !== undefined && p.functionCall);\n const textParts = parts.filter(\n (p) => p !== null && p !== undefined && p.text !== undefined && !p.thought,\n );\n\n if (funcCalls.length > 0) {\n const text = textParts.map((p) => p.text!).join(\"\");\n messages.push({\n role: \"assistant\",\n content: text || null,\n tool_calls: funcCalls.map((fc, i) => ({\n id: fc.functionCall!.id ?? `call_gemini_${fc.functionCall!.name}_${i}`,\n type: \"function\" as const,\n function: {\n name: fc.functionCall!.name,\n arguments: JSON.stringify(fc.functionCall!.args ?? {}),\n },\n })),\n });\n } else {\n const text = textParts.map((p) => p.text!).join(\"\");\n messages.push({ role: \"assistant\", content: text });\n }\n }\n // Unrecognized roles (not \"user\" or \"model\") are silently dropped.\n // Gemini only defines \"user\" and \"model\"; any other value indicates\n // a malformed request or an unsupported future role.\n }\n }\n\n // Convert tools\n let tools: ToolDefinition[] | undefined;\n if (req.tools && req.tools.length > 0) {\n const decls = req.tools.flatMap((t) => t.functionDeclarations ?? []);\n if (decls.length > 0) {\n tools = decls.map((d) => ({\n type: \"function\" as const,\n function: {\n name: d.name,\n description: d.description,\n parameters: d.parameters ?? d.parametersJsonSchema,\n },\n }));\n }\n }\n\n return {\n model,\n messages,\n stream,\n temperature: req.generationConfig?.temperature,\n max_tokens: req.generationConfig?.maxOutputTokens,\n top_p: req.generationConfig?.topP as number | undefined,\n top_k: req.generationConfig?.topK as number | undefined,\n tools,\n };\n}\n\n// ─── Response building: fixture → Gemini format ─────────────────────────────\n\nfunction geminiFinishReason(finishReason: string | undefined, defaultReason: string): string {\n if (!finishReason) return defaultReason;\n return mapGeminiFinish(finishReason);\n}\n\nfunction geminiUsageMetadata(overrides?: ResponseOverrides): {\n promptTokenCount: number;\n candidatesTokenCount: number;\n totalTokenCount: number;\n} {\n return renderGeminiUsage(overrides);\n}\n\ninterface GeminiResponseChunk {\n candidates: {\n content?: { role: string; parts: GeminiPart[] };\n finishReason?: string;\n finishMessage?: string;\n safetyRatings?: { category: string; probability: string; blocked: boolean }[];\n groundingMetadata?: GeminiGroundingMetadata;\n index: number;\n }[];\n usageMetadata?: {\n promptTokenCount: number;\n candidatesTokenCount: number;\n totalTokenCount: number;\n };\n}\n\ninterface GeminiGroundingMetadata {\n groundingChunks: { web: { uri: string; title: string } }[];\n groundingSupports: {\n segment: { partIndex: number; startIndex: number; endIndex: number; text: string };\n groundingChunkIndices: number[];\n }[];\n}\n\n// A text part of the Content that carries the grounding: its index in that\n// Content's `parts`, and the character span [start, end) of the cited text\n// it holds.\ninterface GeminiCitedTextPart {\n partIndex: number;\n start: number;\n end: number;\n}\n\ntype GeminiGroundingSupport = GeminiGroundingMetadata[\"groundingSupports\"][number];\n\n// The whole cited text as the single text part `partIndex`.\nfunction geminiWholeTextPart(text: string, partIndex: number): GeminiCitedTextPart[] {\n return [{ partIndex, start: 0, end: text.length }];\n}\n\n// Fixture `citations` as Gemini grounding supports, one or more per citation,\n// each pointing at grounding chunk `i` (the citation's index). The @google/genai\n// `Segment` type documents `startIndex` / `endIndex` as byte offsets \"in the\n// given Part\" — the Part at `partIndex` within its parent Content — so every\n// segment holds UTF-8 byte offsets into the text of one part. A citation that\n// spans several text parts becomes one support per part, in text order, all\n// naming the same grounding chunk; a client joining their segments gets the\n// whole cited text. An empty citation names the part holding its start.\nfunction geminiGroundingSupports(\n text: string,\n citations: ResolvedCitation[],\n textParts: GeminiCitedTextPart[],\n): GeminiGroundingSupport[] {\n const segment = (\n part: GeminiCitedTextPart,\n from: number,\n to: number,\n ): GeminiGroundingSupport[\"segment\"] => {\n const partText = text.slice(part.start, part.end);\n const start = Math.min(Math.max(from - part.start, 0), partText.length);\n const end = Math.min(Math.max(to - part.start, start), partText.length);\n const byteOffset = (charIndex: number) =>\n Buffer.byteLength(partText.slice(0, charIndex), \"utf8\");\n return {\n partIndex: part.partIndex,\n startIndex: byteOffset(start),\n endIndex: byteOffset(end),\n text: partText.slice(start, end),\n };\n };\n return citations.flatMap((c, i) => {\n const spanned = textParts.filter(\n (p) => Math.max(c.startIndex, p.start) < Math.min(c.endIndex, p.end),\n );\n const parts =\n spanned.length > 0\n ? spanned\n : [textParts.find((p) => c.startIndex < p.end) ?? textParts[textParts.length - 1]];\n return parts.map((p) => ({\n segment: segment(p, c.startIndex, c.endIndex),\n groundingChunkIndices: [i],\n }));\n });\n}\n\n// Fixture `citations` as Gemini `groundingMetadata` for one Content holding\n// `textParts`: one `web` grounding chunk per citation and the supports from\n// {@link geminiGroundingSupports}. File citations are skipped (see\n// resolveCitations): grounding chunks carry no file IDs. Nothing when the\n// fixture has no URL citations or the Content has no text part to cite.\nfunction geminiGroundingMetadata(\n text: string,\n overrides: ResponseOverrides | undefined,\n textParts: GeminiCitedTextPart[],\n): GeminiGroundingMetadata | undefined {\n const citations = resolveCitations(text, overrides?.citations);\n if (citations.length === 0 || textParts.length === 0) return undefined;\n return {\n groundingChunks: geminiGroundingChunks(citations),\n groundingSupports: geminiGroundingSupports(text, citations, textParts),\n };\n}\n\nfunction geminiGroundingChunks(\n citations: ResolvedCitation[],\n): GeminiGroundingMetadata[\"groundingChunks\"] {\n return citations.map((c) => ({ web: { uri: c.url, title: c.title } }));\n}\n\n// `{ groundingMetadata }` for the candidate holding `textParts`, or nothing\n// when {@link geminiGroundingMetadata} yields none.\nfunction geminiGroundingField(\n text: string,\n overrides: ResponseOverrides | undefined,\n textParts: GeminiCitedTextPart[],\n): { groundingMetadata?: GeminiGroundingMetadata } {\n const groundingMetadata = geminiGroundingMetadata(text, overrides, textParts);\n return groundingMetadata ? { groundingMetadata } : {};\n}\n\n// Streaming form of {@link geminiGroundingField}. `spans` are the character\n// spans of `text` that the streamed text chunks carry, in stream order, each\n// as part 0 of its own chunk. Each chunk's Content holds only that chunk's\n// text, so, per the `Segment` contract above, a chunk's supports must index\n// that chunk's part. (Neither @google/genai nor Google's public Gemini API\n// docs say streamed segments index the accumulated text instead.) Every chunk\n// holding some cited text carries groundingMetadata whose supports cover just\n// its part (partIndex 0, byte offsets into the chunk's text), splitting a\n// citation across chunks as across parts. Each grounded chunk lists every grounding\n// chunk, so `groundingChunkIndices` mean the same in every chunk and in the\n// non-streaming response. Returns one field per span; empty for a span that\n// holds no cited text.\nfunction geminiStreamGroundingFields(\n text: string,\n overrides: ResponseOverrides | undefined,\n spans: { start: number; end: number }[],\n): { groundingMetadata?: GeminiGroundingMetadata }[] {\n const fields: { groundingMetadata?: GeminiGroundingMetadata }[] = spans.map(() => ({}));\n const citations = resolveCitations(text, overrides?.citations);\n if (citations.length === 0 || spans.length === 0) return fields;\n // Number the spans as parts so each support says which chunk it belongs to.\n const textParts = spans.map((s, k) => ({ partIndex: k, start: s.start, end: s.end }));\n const groundingChunks = geminiGroundingChunks(citations);\n for (const support of geminiGroundingSupports(text, citations, textParts)) {\n const k = support.segment.partIndex;\n const metadata = (fields[k].groundingMetadata ??= { groundingChunks, groundingSupports: [] });\n metadata.groundingSupports.push({ ...support, segment: { ...support.segment, partIndex: 0 } });\n }\n return fields;\n}\n\n// The [start, end) spans of the chunks that streaming `text` as\n// {@link surrogateSafeChunks} yields, as offsets into the joined text, where\n// `text` starts at `offset`. Empty `text` yields one empty span at `offset`.\nfunction geminiTextChunkSpans(\n text: string,\n chunkSize: number,\n offset = 0,\n): { start: number; end: number }[] {\n if (text.length === 0) return [{ start: offset, end: offset }];\n const spans: { start: number; end: number }[] = [];\n let start = offset;\n for (const slice of surrogateSafeChunks(text, chunkSize)) {\n spans.push({ start, end: start + slice.length });\n start += slice.length;\n }\n return spans;\n}\n\n// Fixture `files` as Gemini `inlineData` parts. Every text and tool-call builder\n// emits these after any thought parts and before the text / functionCall parts.\nfunction geminiFileParts(overrides?: ResponseOverrides): GeminiPart[] {\n return fixtureFiles(overrides?.files).map((f) => ({\n inlineData: { mimeType: f.mimeType, data: f.data },\n }));\n}\n\n// Streaming form of {@link geminiFileParts}: one chunk holding every file part,\n// or nothing when the fixture has no files.\nfunction geminiFileChunks(overrides?: ResponseOverrides): GeminiResponseChunk[] {\n const parts = geminiFileParts(overrides);\n if (parts.length === 0) return [];\n return [{ candidates: [{ content: { role: \"model\", parts }, index: 0 }] }];\n}\n\nfunction buildGeminiTextStreamChunks(\n content: string,\n chunkSize: number,\n reasoning?: string,\n overrides?: ResponseOverrides,\n): GeminiResponseChunk[] {\n const chunks: GeminiResponseChunk[] = [];\n const effectiveFinish = geminiFinishReason(overrides?.finishReason, \"STOP\");\n const usage = geminiUsageMetadata(overrides);\n\n // Reasoning chunks (thought: true)\n if (reasoning) {\n for (let i = 0; i < reasoning.length; i += chunkSize) {\n const slice = reasoning.slice(i, i + chunkSize);\n chunks.push({\n candidates: [\n {\n content: { role: \"model\", parts: [{ text: slice, thought: true }] },\n index: 0,\n },\n ],\n });\n }\n }\n\n chunks.push(...geminiFileChunks(overrides));\n\n // Each content chunk carries the grounding for the cited text it holds.\n const grounding = geminiStreamGroundingFields(\n content,\n overrides,\n geminiTextChunkSpans(content, chunkSize),\n );\n\n // Content chunks, never cutting a surrogate pair, so each chunk is valid\n // UTF-16 and its grounding byte offsets count whole characters.\n const contentSlices = surrogateSafeChunks(content, chunkSize);\n contentSlices.forEach((slice, k) => {\n const isLast = k === contentSlices.length - 1;\n const chunk: GeminiResponseChunk = {\n candidates: [\n {\n content: { role: \"model\", parts: [{ text: slice }] },\n index: 0,\n ...(isLast ? { finishReason: effectiveFinish } : {}),\n ...grounding[k],\n },\n ],\n ...(isLast ? { usageMetadata: usage } : {}),\n };\n chunks.push(chunk);\n });\n\n // Handle empty content\n if (content.length === 0) {\n chunks.push({\n candidates: [\n {\n content: { role: \"model\", parts: [{ text: \"\" }] },\n finishReason: effectiveFinish,\n ...grounding[0],\n index: 0,\n },\n ],\n usageMetadata: usage,\n });\n }\n\n return chunks;\n}\n\nfunction parseToolCallPart(tc: ToolCall, logger: Logger): GeminiPart {\n const args = servedToolArgs(tc, \"object\", logger);\n // Surface the fixture's tool_call.id on the Gemini functionCall response\n // so clients can preserve it across the round-trip and any\n // toolCallId-keyed follow-up fixtures match. Pairs with v1.23.1's\n // INGEST-direction fix (#196) which preserves the id when aimock parses\n // an incoming Gemini request — that fix only helps if the id was in the\n // response body to begin with. Without this egress fix, aimock emits\n // `{ functionCall: { name, args } }` (no id), so even clients that\n // diligently preserve `functionCall.id` across the round-trip never see\n // an id to preserve. Backward-compatible: fixtures that don't pin a\n // tc.id continue to serialize without one (the ingest path's fallback\n // generator handles those).\n const functionCall: GeminiPart[\"functionCall\"] = {\n name: tc.name,\n args: args.value as Record<string, unknown>,\n };\n if (tc.id) {\n functionCall.id = tc.id;\n }\n return { functionCall };\n}\n\nfunction buildGeminiToolCallStreamChunks(\n toolCalls: ToolCall[],\n chunkSize: number,\n logger: Logger,\n reasoning?: string,\n overrides?: ResponseOverrides,\n): GeminiResponseChunk[] {\n const chunks: GeminiResponseChunk[] = [];\n\n // Reasoning chunks (thought: true) — mirror the content+tool / text paths so a\n // tool-only fixture on a reasoning-capable model still emits its thought channel.\n if (reasoning) {\n for (let i = 0; i < reasoning.length; i += chunkSize) {\n const slice = reasoning.slice(i, i + chunkSize);\n chunks.push({\n candidates: [\n {\n content: { role: \"model\", parts: [{ text: slice, thought: true }] },\n index: 0,\n },\n ],\n });\n }\n }\n\n chunks.push(...geminiFileChunks(overrides));\n\n // A tool-only turn has no text for `citations` to point at.\n resolveCitations(\"\", overrides?.citations);\n const parts: GeminiPart[] = toolCalls.map((tc) => parseToolCallPart(tc, logger));\n\n // Gemini sends all tool calls in a single response chunk\n chunks.push({\n candidates: [\n {\n content: { role: \"model\", parts },\n finishReason: geminiFinishReason(overrides?.finishReason, \"FUNCTION_CALL\"),\n index: 0,\n },\n ],\n usageMetadata: geminiUsageMetadata(overrides),\n });\n\n return chunks;\n}\n\n// Non-streaming response builders\n\nfunction buildGeminiTextResponse(\n content: string,\n reasoning?: string,\n overrides?: ResponseOverrides,\n): GeminiResponseChunk {\n const parts: GeminiPart[] = [];\n if (reasoning) {\n parts.push({ text: reasoning, thought: true });\n }\n parts.push(...geminiFileParts(overrides));\n const textParts = geminiWholeTextPart(content, parts.length);\n parts.push({ text: content });\n\n return {\n candidates: [\n {\n content: { role: \"model\", parts },\n finishReason: geminiFinishReason(overrides?.finishReason, \"STOP\"),\n ...geminiGroundingField(content, overrides, textParts),\n index: 0,\n },\n ],\n usageMetadata: geminiUsageMetadata(overrides),\n };\n}\n\nfunction buildGeminiToolCallResponse(\n toolCalls: ToolCall[],\n logger: Logger,\n reasoning?: string,\n overrides?: ResponseOverrides,\n): GeminiResponseChunk {\n // A tool-only turn has no text for `citations` to point at.\n resolveCitations(\"\", overrides?.citations);\n const parts: GeminiPart[] = [];\n if (reasoning) {\n parts.push({ text: reasoning, thought: true });\n }\n parts.push(...geminiFileParts(overrides));\n parts.push(...toolCalls.map((tc) => parseToolCallPart(tc, logger)));\n\n return {\n candidates: [\n {\n content: { role: \"model\", parts },\n finishReason: geminiFinishReason(overrides?.finishReason, \"FUNCTION_CALL\"),\n index: 0,\n },\n ],\n usageMetadata: geminiUsageMetadata(overrides),\n };\n}\n\nfunction buildGeminiContentWithToolCallsStreamChunks(\n content: string,\n toolCalls: ToolCall[],\n chunkSize: number,\n logger: Logger,\n reasoning?: string,\n overrides?: ResponseOverrides,\n blocks?: FixtureBlock[],\n): GeminiResponseChunk[] {\n const chunks: GeminiResponseChunk[] = [];\n\n // Reasoning chunks (thought: true)\n if (reasoning) {\n for (let i = 0; i < reasoning.length; i += chunkSize) {\n const slice = reasoning.slice(i, i + chunkSize);\n chunks.push({\n candidates: [\n {\n content: { role: \"model\", parts: [{ text: slice, thought: true }] },\n index: 0,\n },\n ],\n });\n }\n }\n\n chunks.push(...geminiFileChunks(overrides));\n\n if (blocks && blocks.length > 0) {\n // NEW path (#274): stream chunks whose parts follow the blocks' ARRAY ORDER,\n // so a tool-first / interleaved fixture emits its functionCall part before\n // its text part. Gemini's ordered `parts` make this fully expressible. The\n // terminal block carries the finishReason regardless of its type. Legacy\n // fixtures (no `blocks`) never enter here — see the else branch below.\n // The grounding rides on the text chunks holding the cited text, never on\n // a functionCall chunk: each text block streams as chunks whose part 0 is\n // the text their offsets refer to.\n const outcome = resolveFixtureBlockOutcome(blocks);\n const resolved = outcome.ordered;\n const spans: { start: number; end: number }[] = [];\n let offset = 0;\n for (const block of resolved) {\n if (block.type !== \"text\") continue;\n spans.push(...geminiTextChunkSpans(block.text, chunkSize, offset));\n offset += block.text.length;\n }\n const grounding = geminiStreamGroundingFields(outcome.content, overrides, spans);\n let textChunk = 0;\n resolved.forEach((block, i) => {\n const isLast = i === resolved.length - 1;\n const finishReason = isLast\n ? geminiFinishReason(\n overrides?.finishReason,\n outcome.hasToolCalls ? \"FUNCTION_CALL\" : \"STOP\",\n )\n : undefined;\n if (block.type === \"toolCall\") {\n const part = parseToolCallPart(\n { name: block.name, arguments: block.arguments, id: block.id },\n logger,\n );\n chunks.push({\n candidates: [\n {\n content: { role: \"model\", parts: [part] },\n ...(finishReason ? { finishReason } : {}),\n index: 0,\n },\n ],\n ...(isLast ? { usageMetadata: geminiUsageMetadata(overrides) } : {}),\n });\n } else {\n const text = block.text;\n if (text.length === 0) {\n chunks.push({\n candidates: [\n {\n content: { role: \"model\", parts: [{ text: \"\" }] },\n ...(finishReason ? { finishReason } : {}),\n ...grounding[textChunk++],\n index: 0,\n },\n ],\n ...(isLast ? { usageMetadata: geminiUsageMetadata(overrides) } : {}),\n });\n } else {\n const slices = surrogateSafeChunks(text, chunkSize);\n slices.forEach((slice, j) => {\n const lastSlice = j === slices.length - 1;\n const sliceFinish = isLast && lastSlice ? finishReason : undefined;\n chunks.push({\n candidates: [\n {\n content: { role: \"model\", parts: [{ text: slice }] },\n ...(sliceFinish ? { finishReason: sliceFinish } : {}),\n ...grounding[textChunk++],\n index: 0,\n },\n ],\n ...(isLast && lastSlice ? { usageMetadata: geminiUsageMetadata(overrides) } : {}),\n });\n });\n }\n }\n });\n\n return chunks;\n }\n\n // The grounding rides on the text chunks holding the cited text, not on the\n // functionCall chunk, so their part 0 is the text the offsets refer to.\n const grounding = geminiStreamGroundingFields(\n content,\n overrides,\n geminiTextChunkSpans(content, chunkSize),\n );\n if (content.length === 0) {\n chunks.push({\n candidates: [\n {\n content: { role: \"model\", parts: [{ text: \"\" }] },\n ...grounding[0],\n index: 0,\n },\n ],\n });\n } else {\n surrogateSafeChunks(content, chunkSize).forEach((slice, k) => {\n chunks.push({\n candidates: [\n {\n content: { role: \"model\", parts: [{ text: slice }] },\n ...grounding[k],\n index: 0,\n },\n ],\n });\n });\n }\n\n const parts: GeminiPart[] = toolCalls.map((tc) => parseToolCallPart(tc, logger));\n\n chunks.push({\n candidates: [\n {\n content: { role: \"model\", parts },\n finishReason: geminiFinishReason(overrides?.finishReason, \"FUNCTION_CALL\"),\n index: 0,\n },\n ],\n usageMetadata: geminiUsageMetadata(overrides),\n });\n\n return chunks;\n}\n\nfunction buildGeminiContentWithToolCallsResponse(\n content: string,\n toolCalls: ToolCall[],\n logger: Logger,\n reasoning?: string,\n overrides?: ResponseOverrides,\n blocks?: FixtureBlock[],\n): GeminiResponseChunk {\n const parts: GeminiPart[] = [];\n if (reasoning) {\n parts.push({ text: reasoning, thought: true });\n }\n parts.push(...geminiFileParts(overrides));\n\n let blockHasTools: boolean | undefined;\n let groundingText = content;\n // Each text part, with the span of `groundingText` it holds.\n const textParts: GeminiCitedTextPart[] = [];\n if (blocks && blocks.length > 0) {\n // NEW PATH: the non-streaming `parts[]` array is positionally observable, so\n // emit parts in the fixture's ARRAY ORDER (after any leading thought part).\n // A toolCall block before a text block therefore yields a functionCall part\n // ahead of the text — matching the streaming path for the same `blocks`.\n const outcome = resolveFixtureBlockOutcome(blocks);\n const resolved = outcome.ordered;\n blockHasTools = outcome.hasToolCalls;\n groundingText = outcome.content;\n for (const block of resolved) {\n if (block.type === \"toolCall\") {\n parts.push(\n parseToolCallPart({ name: block.name, arguments: block.arguments, id: block.id }, logger),\n );\n } else {\n const start = textParts.length > 0 ? textParts[textParts.length - 1].end : 0;\n textParts.push({ partIndex: parts.length, start, end: start + block.text.length });\n parts.push({ text: block.text });\n }\n }\n } else {\n // LEGACY PATH: text part first, then functionCall parts.\n textParts.push(...geminiWholeTextPart(content, parts.length));\n parts.push({ text: content });\n parts.push(...toolCalls.map((tc) => parseToolCallPart(tc, logger)));\n }\n\n return {\n candidates: [\n {\n content: { role: \"model\", parts },\n finishReason: geminiFinishReason(\n overrides?.finishReason,\n blockHasTools === false ? \"STOP\" : \"FUNCTION_CALL\",\n ),\n ...geminiGroundingField(groundingText, overrides, textParts),\n index: 0,\n },\n ],\n usageMetadata: geminiUsageMetadata(overrides),\n };\n}\n\n// ─── Audio response builders ────────────────────────────────────────────────\n\nfunction resolveAudioInlineData(audio: AudioResponse): { mimeType: string; data: string } {\n if (typeof audio.audio === \"string\") {\n return { mimeType: formatToMime(audio.format ?? \"mp3\"), data: audio.audio };\n }\n return {\n mimeType: audio.audio.contentType ?? \"audio/mpeg\",\n data: audio.audio.b64Json,\n };\n}\n\n// Build the ordered Gemini parts for an audio turn: inlineData audio first,\n// then any companion modalities (reasoning/thought, text content, tool calls)\n// the recorder preserved on the AudioResponse. Without this, a recorded turn\n// that interleaves audio with a functionCall and/or text silently drops the\n// companions on replay.\n// NOTE: audio companions are only re-emitted on this Gemini replay path because\n// `audioB64` collapse is currently Gemini-only — a cross-provider audio fixture\n// would not replay its companions.\n// `effReasoning` is the capability-gated reasoning string (already passed\n// through resolveReasoningForModel at the dispatch). When the requested model\n// is not reasoning-capable (and strict mode is on), it is undefined and the\n// companion `thought` part is suppressed — mirroring the text/content+tool\n// branches so the audio path does not replay reasoning a real Gemini model\n// would never emit.\nfunction buildGeminiAudioParts(\n audio: AudioResponse,\n toolCalls: ToolCall[],\n logger: Logger,\n effReasoning: string | undefined,\n): GeminiPart[] {\n const inlineData = resolveAudioInlineData(audio);\n const parts: GeminiPart[] = [{ inlineData }];\n if (effReasoning) {\n parts.push({ text: effReasoning, thought: true });\n }\n if (audio.content) {\n parts.push({ text: audio.content });\n }\n if (toolCalls.length) {\n parts.push(...toolCalls.map((tc) => parseToolCallPart(tc, logger)));\n }\n return parts;\n}\n\nfunction buildGeminiAudioResponse(\n audio: AudioResponse,\n toolCalls: ToolCall[],\n logger: Logger,\n effReasoning: string | undefined,\n): GeminiResponseChunk {\n return {\n candidates: [\n {\n content: {\n role: \"model\",\n parts: buildGeminiAudioParts(audio, toolCalls, logger, effReasoning),\n },\n finishReason: toolCalls.length ? \"FUNCTION_CALL\" : \"STOP\",\n index: 0,\n },\n ],\n usageMetadata: renderGeminiUsage(),\n };\n}\n\nfunction buildGeminiAudioStreamChunks(\n audio: AudioResponse,\n toolCalls: ToolCall[],\n logger: Logger,\n effReasoning: string | undefined,\n): GeminiResponseChunk[] {\n return [\n {\n candidates: [\n {\n content: {\n role: \"model\",\n parts: buildGeminiAudioParts(audio, toolCalls, logger, effReasoning),\n },\n finishReason: toolCalls.length ? \"FUNCTION_CALL\" : \"STOP\",\n index: 0,\n },\n ],\n usageMetadata: renderGeminiUsage(),\n },\n ];\n}\n\n// ─── SSE writer for Gemini streaming ────────────────────────────────────────\n\n// Gemini streams data-only SSE frames (no `event:` prefix) and sends no\n// `[DONE]` trailer.\nconst GEMINI_SSE = sseCodec<GeminiResponseChunk>({ done: false });\n\nconst SILENT_LOGGER = new Logger(\"silent\");\n\n/**\n * The reasoning a misbehavior reply's non-streaming wait is sized with: the\n * plan response's reasoning through the same model and strict gate the\n * builders apply. The gate runs with a silent logger, so the builder's own\n * warning stays the only one. A reasoning-only plan carries its reasoning on\n * the plan, and `misbehaviorPayloadLength` reads it there.\n */\nfunction misbehaviorPayloadReasoning(\n plan: MisbehaviorPlan,\n model: string | undefined,\n strict: boolean,\n): string | undefined {\n const response = plan.response;\n if (\n plan.reasoning !== undefined ||\n !(\n isCombinedFixtureResponse(response) ||\n isTextResponse(response) ||\n isToolCallResponse(response)\n )\n ) {\n return undefined;\n }\n return resolveReasoningForModel(response.reasoning, model, strict, SILENT_LOGGER);\n}\n\n/** Prepare native fault output once; the journal describes these exact parts. */\nfunction prepareGeminiMisbehavior(\n plan: MisbehaviorPlan,\n request: ChatCompletionRequest,\n streaming: boolean,\n chunkSize: number,\n logger: Logger,\n strict: boolean,\n): { chunks: GeminiResponseChunk[]; summary: MisbehaviorPlan[\"summary\"] } {\n const response = plan.response;\n const combined = isCombinedFixtureResponse(response);\n if (!(combined || isToolCallResponse(response) || isTextResponse(response))) {\n throw new Error(\"Applied Gemini misbehavior requires a chat response\");\n }\n const outcome =\n combined && response.blocks?.length ? resolveFixtureBlockOutcome(response.blocks) : undefined;\n const content = outcome?.content ?? (\"content\" in response ? (response.content ?? \"\") : \"\");\n // The planner skips a custom-call fixture on this wire, so this narrowing\n // never throws; the normal path's guard rejects it instead.\n const calls = outcome?.toolCalls ?? (\"toolCalls\" in response ? (response.toolCalls ?? []) : []);\n const overrides = extractOverrides(response);\n delete overrides.usage;\n const fault = plan.summary.fault;\n const candidate: GeminiResponseChunk[\"candidates\"][number] & { content: GeminiContent } = {\n content: { role: \"model\", parts: [] },\n index: 0,\n };\n let chunks: GeminiResponseChunk[];\n if (fault === \"tool-args-invalid-json\") {\n const target = calls[plan.target?.index ?? 0];\n if (!target) throw new Error(\"Gemini malformed-call plan requires its selected tool call\");\n chunks = [\n {\n candidates: [\n {\n index: 0,\n finishReason: \"MALFORMED_FUNCTION_CALL\",\n finishMessage: `Malformed function call: ${target.name}(${target.arguments})`,\n },\n ],\n },\n ];\n } else if (fault === \"tool-unknown-name\" && !request.tools?.length) {\n candidate.finishReason = \"UNEXPECTED_TOOL_CALL\";\n chunks = [{ candidates: [candidate] }];\n } else if (fault === \"stop-length-mid-tool\") {\n // Object arguments cannot be partial; preserve only text preceding the cut.\n // The fixture's files precede that text, as on the normal path.\n const parts = geminiFileParts(overrides);\n const textPartIndex = parts.length;\n if (content) parts.push({ text: content });\n candidate.content.parts = parts;\n // The planner drops `citations` whenever the fault changes the served\n // text in any way, not only when the cut removes cited text.\n if (content)\n Object.assign(\n candidate,\n geminiGroundingField(content, overrides, geminiWholeTextPart(content, textPartIndex)),\n );\n candidate.finishReason = \"MAX_TOKENS\";\n chunks = [{ candidates: [candidate] }];\n } else if (fault === \"empty-response\") {\n candidate.content.parts = [{ text: \"\" }];\n candidate.finishReason = \"STOP\";\n chunks = [{ candidates: [candidate] }];\n } else if (fault === \"content-filter\") {\n candidate.finishReason = \"SAFETY\";\n candidate.safetyRatings = [\n { category: \"HARM_CATEGORY_DANGEROUS_CONTENT\", probability: \"HIGH\", blocked: true },\n ];\n chunks = [{ candidates: [candidate] }];\n } else if (fault === \"reasoning-only\") {\n candidate.content.parts = [{ text: plan.reasoning ?? \"\", thought: true }];\n candidate.finishReason = \"MAX_TOKENS\";\n chunks = [{ candidates: [candidate] }];\n } else {\n const reasoning = resolveReasoningForModel(response.reasoning, request.model, strict, logger);\n if (fault === \"tool-unknown-name\") overrides.finishReason = \"stop\";\n if (combined) {\n chunks = streaming\n ? buildGeminiContentWithToolCallsStreamChunks(\n content,\n calls,\n chunkSize,\n logger,\n reasoning,\n overrides,\n response.blocks,\n )\n : [\n buildGeminiContentWithToolCallsResponse(\n content,\n calls,\n logger,\n reasoning,\n overrides,\n response.blocks,\n ),\n ];\n } else if (isToolCallResponse(response)) {\n chunks = streaming\n ? buildGeminiToolCallStreamChunks(calls, chunkSize, logger, reasoning, overrides)\n : [buildGeminiToolCallResponse(calls, logger, reasoning, overrides)];\n } else {\n chunks = streaming\n ? buildGeminiTextStreamChunks(content, chunkSize, reasoning, overrides)\n : [buildGeminiTextResponse(content, reasoning, overrides)];\n }\n }\n const parts = chunks.flatMap((chunk) =>\n chunk.candidates.flatMap((item) => item.content?.parts ?? []),\n );\n const servedToolCalls = parts.flatMap((part) =>\n part.functionCall\n ? [\n {\n name: part.functionCall.name,\n arguments: JSON.stringify(part.functionCall.args),\n ...(part.functionCall.id ? { id: part.functionCall.id } : {}),\n },\n ]\n : [],\n );\n const prompt = request.messages\n .map((message) =>\n typeof message.content === \"string\"\n ? message.content\n : (message.content ?? []).map((part) => part.text ?? \"\").join(\"\"),\n )\n .join(\"\");\n const output = parts\n .map(\n (part) =>\n part.text ??\n (part.functionCall ? part.functionCall.name + JSON.stringify(part.functionCall.args) : \"\"),\n )\n .join(\"\");\n for (const chunk of chunks) delete chunk.usageMetadata;\n chunks[chunks.length - 1].usageMetadata = renderGeminiUsage(undefined, {\n kind: \"applied-misbehavior\",\n promptText: prompt,\n completionText: output,\n });\n return { chunks, summary: { ...plan.summary, servedToolCalls } };\n}\n\n// ─── Request handler ────────────────────────────────────────────────────────\n\nexport async function handleGemini(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n raw: string,\n model: string,\n streaming: boolean,\n fixtures: Fixture[],\n journal: Journal,\n defaults: HandlerDefaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n providerKey: RecordProviderKey = \"gemini\",\n): Promise<void> {\n const { logger } = defaults;\n const wire = providerKey === \"vertexai\" ? \"Vertex AI\" : \"Gemini\";\n setCorsHeaders(res);\n\n let geminiReq: GeminiRequest;\n try {\n geminiReq = JSON.parse(raw) as GeminiRequest;\n } catch (parseErr) {\n const detail = parseErr instanceof Error ? parseErr.message : \"unknown\";\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? `/v1beta/models/${model}:generateContent`,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n renderError(\"gemini\", \"validation\", {\n message: `Malformed JSON body: ${detail}`,\n bodyCode: 400,\n status: \"INVALID_ARGUMENT\",\n }).body,\n );\n return;\n }\n\n // Reject non-object bodies (e.g. `null`) before touching fields —\n // otherwise the converter dereference throws a TypeError that surfaces as\n // a 500 instead of a 400.\n if (!isJsonObject(geminiReq)) {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? `/v1beta/models/${model}:generateContent`,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n renderError(\"gemini\", \"validation\", {\n message: \"Request body must be a JSON object\",\n bodyCode: 400,\n status: \"INVALID_ARGUMENT\",\n }).body,\n );\n return;\n }\n\n // Reject wrong-typed fields before the converter dereferences them.\n const geminiShapeError = validateGeminiBody(geminiReq);\n if (geminiShapeError) {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? `/v1beta/models/${model}:generateContent`,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n renderError(\"gemini\", \"validation\", {\n message: `Invalid argument: ${geminiShapeError}`,\n bodyCode: 400,\n status: \"INVALID_ARGUMENT\",\n }).body,\n );\n return;\n }\n\n // Convert to ChatCompletionRequest for fixture matching\n const completionReq = geminiToCompletionRequest(geminiReq, model, streaming);\n completionReq._endpointType = \"chat\";\n completionReq._context = getContext(req);\n\n const testId = getTestId(req);\n const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(\n fixtures,\n completionReq,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\n // Record mode proxies on a miss to capture a fresh turn (see record gate\n // below), so keep turnIndex strict to prevent an earlier-turn fixture from\n // shadowing a longer request and skipping the new turn's recording.\n { ...recordMatchOptions(!!defaults.record, defaults.logger), wire: \"gemini\" },\n );\n const path = req.url ?? `/v1beta/models/${model}:generateContent`;\n\n if (fixture) {\n logger.debug(`Fixture matched: ${JSON.stringify(fixture.match).slice(0, 120)}`);\n } else {\n logger.debug(`No fixture matched for request`);\n }\n\n if (fixture) {\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n }\n\n if (\n await applyChaosAsync(\n res,\n fixture,\n defaults.chaos,\n req.headers,\n req.url,\n journal,\n {\n method: req.method ?? \"POST\",\n path,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n },\n fixture ? \"fixture\" : \"proxy\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n if (!fixture) {\n const decisions = resolveRequestDecisions(defaults.strict, req.headers);\n if (decisions.fixtureMiss) {\n const strictMessage = strictNoMatchMessage(skippedBySequenceOrTurn);\n logger.error(strictNoMatchLogLine(req.method ?? \"POST\", path, skippedBySequenceOrTurn));\n journal.add({\n method: req.method ?? \"POST\",\n path,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: {\n status: 503,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 503,\n renderError(\"gemini\", \"strict-miss\", {\n message: strictMessage,\n bodyCode: 503,\n status: \"UNAVAILABLE\",\n }).body,\n );\n return;\n }\n\n if (decisions.upstream && defaults.record) {\n const { outcome, clientHungUp } = await withHangUpDetection(req, res, () =>\n proxyAndRecord(req, res, completionReq, providerKey, path, fixtures, defaults, raw),\n );\n if (outcome === \"handled_by_hook\") return;\n if (outcome !== \"not_configured\") {\n journal.add({\n method: req.method ?? \"POST\",\n path,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: {\n status: res.statusCode ?? 200,\n fixture: null,\n source: \"proxy\",\n ...proxyInterruption(res, clientHungUp),\n },\n });\n return;\n }\n }\n journal.add({\n method: req.method ?? \"POST\",\n path,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: {\n status: 404,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 404,\n renderError(\"gemini\", \"fixture-miss\", {\n message: \"No fixture matched\",\n bodyCode: 404,\n status: \"NOT_FOUND\",\n }).body,\n );\n return;\n }\n\n const response = await resolveResponse(fixture, completionReq);\n const misbehavior = planMisbehavior({\n wire: \"gemini\",\n toolCallIdMode: \"authored-nonempty\",\n fixture,\n response,\n request: completionReq,\n stream: streaming,\n defaults,\n rawHeaders: req.headers,\n url: req.url,\n });\n if (misbehavior.kind === \"error\") {\n const entry = journal.add({\n method: req.method ?? \"POST\",\n path,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: misbehavior.status, fixture, error: misbehavior.message },\n });\n recordMisbehaviorOutcome({ entry, summary: misbehavior.summary, defaults, testId });\n if (misbehavior.summary?.evaluations.length === 0) {\n logger.error(`${req.method ?? \"POST\"} ${path}: ${misbehavior.message}`);\n }\n writeErrorResponse(\n res,\n misbehavior.status,\n renderError(\"gemini\", \"misbehavior\", {\n bodyCode: misbehavior.status,\n message: misbehavior.message,\n status: misbehavior.status === 400 ? \"INVALID_ARGUMENT\" : \"UNIMPLEMENTED\",\n }).body,\n );\n return;\n }\n\n const latency = fixture.latency ?? defaults.latency;\n const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);\n const replaySpeed = fixture.replaySpeed ?? defaults.replaySpeed;\n const streamTiming = {\n latency,\n streamingProfile: fixture.streamingProfile,\n recordedTimings: fixture.recordedTimings,\n replaySpeed,\n };\n const jsonOpts = (payloadLength: number, duplicateId = false) => ({\n surface: \"other\" as const,\n payloadLength,\n chunkSize,\n recordedTimings: fixture.recordedTimings,\n duplicateId,\n replaySpeed,\n });\n\n if (misbehavior.kind === \"applied\") {\n // Journal first, as the success branches do, so a fixture error thrown\n // while building leaves a 500 entry that keeps the fixture. Record the\n // fault only once the reply is built: a thrown error was not served.\n const entry = journal.add({\n method: req.method ?? \"POST\",\n path,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n const strictReasoning = resolveRequestDecisions(\n defaults.strict,\n req.headers,\n ).reasoningSuppression;\n const prepared = prepareGeminiMisbehavior(\n misbehavior,\n completionReq,\n streaming,\n chunkSize,\n logger,\n strictReasoning,\n );\n recordMisbehaviorOutcome({ entry, summary: prepared.summary, defaults, testId });\n if (!streaming) {\n const preparedBody = prepared.chunks[0];\n await deliverJson(\n res,\n entry,\n fixture,\n () => preparedBody,\n jsonOpts(\n misbehaviorPayloadLength(\n misbehavior,\n misbehaviorPayloadReasoning(misbehavior, completionReq.model, strictReasoning),\n ),\n !!misbehavior.duplicateId,\n ),\n );\n } else {\n await deliverStream(res, entry, fixture, GEMINI_SSE, prepared.chunks, streamTiming);\n }\n return;\n }\n\n // Raw passthrough (#549): the authored chunks or JSON, framed for this wire.\n // Covers the Vertex AI route, which shares this handler.\n if (isRawResponse(response)) {\n await serveRawResponse({\n wire: \"gemini\",\n stream: streaming,\n req,\n res,\n fixture,\n response,\n body: completionReq,\n journal,\n defaults,\n testId,\n misbehaviorSummary: misbehavior.summary,\n errorWire: \"gemini\",\n });\n return;\n }\n\n // Error response\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n const errorEntry = journal.add({\n method: req.method ?? \"POST\",\n path,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status, fixture },\n });\n recordMisbehaviorOutcome({ entry: errorEntry, summary: misbehavior.summary, defaults, testId });\n writeErrorResponse(\n res,\n status,\n renderError(\"gemini\", \"fixture\", {\n bodyCode: status,\n message: response.error.message,\n status: response.error.type ?? \"ERROR\",\n }).body,\n { retryAfter: response.retryAfter },\n );\n return;\n }\n\n // Audio response\n if (isAudioResponse(response)) {\n const effectiveStrict = resolveRequestDecisions(\n defaults.strict,\n req.headers,\n ).reasoningSuppression;\n const effReasoning = resolveReasoningForModel(\n response.reasoning,\n model,\n effectiveStrict,\n defaults.logger,\n );\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n recordMisbehaviorOutcome({\n entry: journalEntry,\n summary: misbehavior.summary,\n defaults,\n testId,\n });\n // A non-array companion `toolCalls` emits no tool parts, as before custom calls existed.\n const audioToolCalls = Array.isArray(response.toolCalls)\n ? requireServedFunctionToolCalls(response, wire)\n : [];\n if (!streaming) {\n await deliverJson(\n res,\n journalEntry,\n fixture,\n () => buildGeminiAudioResponse(response, audioToolCalls, logger, effReasoning),\n jsonOpts(servedPayloadLength(response, effReasoning)),\n );\n } else {\n const chunks = buildGeminiAudioStreamChunks(response, audioToolCalls, logger, effReasoning);\n await deliverStream(res, journalEntry, fixture, GEMINI_SSE, chunks, streamTiming);\n }\n return;\n }\n\n // Content + tool calls response (must be checked before isTextResponse / isToolCallResponse)\n if (isCombinedFixtureResponse(response)) {\n if (response.webSearches?.length) {\n logger.warn(\"webSearches in fixture response are not supported for Gemini API — ignoring\");\n }\n const overrides = extractOverrides(response);\n const effectiveStrict = resolveRequestDecisions(\n defaults.strict,\n req.headers,\n ).reasoningSuppression;\n const effReasoning = resolveReasoningForModel(\n response.reasoning,\n model,\n effectiveStrict,\n defaults.logger,\n );\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n recordMisbehaviorOutcome({\n entry: journalEntry,\n summary: misbehavior.summary,\n defaults,\n testId,\n });\n const functionToolCalls = requireEmittedFunctionToolCalls(response, wire);\n if (!streaming) {\n await deliverJson(\n res,\n journalEntry,\n fixture,\n () =>\n buildGeminiContentWithToolCallsResponse(\n response.content ?? \"\",\n functionToolCalls,\n logger,\n effReasoning,\n overrides,\n response.blocks,\n ),\n jsonOpts(servedPayloadLength(response, effReasoning)),\n );\n } else {\n const chunks = buildGeminiContentWithToolCallsStreamChunks(\n response.content ?? \"\",\n functionToolCalls,\n chunkSize,\n logger,\n effReasoning,\n overrides,\n response.blocks,\n );\n await deliverStream(res, journalEntry, fixture, GEMINI_SSE, chunks, streamTiming);\n }\n return;\n }\n\n // Text response\n if (isTextResponse(response)) {\n if (response.webSearches?.length) {\n logger.warn(\"webSearches in fixture response are not supported for Gemini API — ignoring\");\n }\n const overrides = extractOverrides(response);\n const effectiveStrict = resolveRequestDecisions(\n defaults.strict,\n req.headers,\n ).reasoningSuppression;\n const effReasoning = resolveReasoningForModel(\n response.reasoning,\n model,\n effectiveStrict,\n defaults.logger,\n );\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n recordMisbehaviorOutcome({\n entry: journalEntry,\n summary: misbehavior.summary,\n defaults,\n testId,\n });\n if (!streaming) {\n await deliverJson(\n res,\n journalEntry,\n fixture,\n () => buildGeminiTextResponse(response.content, effReasoning, overrides),\n jsonOpts(servedPayloadLength(response, effReasoning)),\n );\n } else {\n const chunks = buildGeminiTextStreamChunks(\n response.content,\n chunkSize,\n effReasoning,\n overrides,\n );\n await deliverStream(res, journalEntry, fixture, GEMINI_SSE, chunks, streamTiming);\n }\n return;\n }\n\n // Tool call response\n if (isToolCallResponse(response)) {\n if (response.webSearches?.length) {\n logger.warn(\"webSearches in fixture response are not supported for Gemini API — ignoring\");\n }\n const overrides = extractOverrides(response);\n const effectiveStrict = resolveRequestDecisions(\n defaults.strict,\n req.headers,\n ).reasoningSuppression;\n const effReasoning = resolveReasoningForModel(\n response.reasoning,\n model,\n effectiveStrict,\n defaults.logger,\n );\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n recordMisbehaviorOutcome({\n entry: journalEntry,\n summary: misbehavior.summary,\n defaults,\n testId,\n });\n const functionToolCalls = requireEmittedFunctionToolCalls(response, wire);\n if (!streaming) {\n await deliverJson(\n res,\n journalEntry,\n fixture,\n () => buildGeminiToolCallResponse(functionToolCalls, logger, effReasoning, overrides),\n jsonOpts(servedPayloadLength(response, effReasoning)),\n );\n } else {\n const chunks = buildGeminiToolCallStreamChunks(\n functionToolCalls,\n chunkSize,\n logger,\n effReasoning,\n overrides,\n );\n await deliverStream(res, journalEntry, fixture, GEMINI_SSE, chunks, streamTiming);\n }\n return;\n }\n\n // Unknown response type\n const unknownEntry = journal.add({\n method: req.method ?? \"POST\",\n path,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 500, fixture },\n });\n recordMisbehaviorOutcome({ entry: unknownEntry, summary: misbehavior.summary, defaults, testId });\n writeErrorResponse(\n res,\n 500,\n renderError(\"gemini\", \"unknown-response\", {\n message: \"Fixture response did not match any known type\",\n bodyCode: 500,\n status: \"INTERNAL\",\n }).body,\n );\n}\n"],"mappings":"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"}
|
package/dist/gemini.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gemini.d.cts","names":[],"sources":["../src/gemini.ts"],"sourcesContent":[],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"gemini.d.cts","names":[],"sources":["../src/gemini.ts"],"sourcesContent":[],"mappings":";;;;;;iBAgpCsB,YAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,0EAIA,oBACD,mBACC,uCACY,MAAA,CAAK,uCACd,oBACZ"}
|
package/dist/gemini.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gemini.d.ts","names":[],"sources":["../src/gemini.ts"],"sourcesContent":[],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"gemini.d.ts","names":[],"sources":["../src/gemini.ts"],"sourcesContent":[],"mappings":";;;;;;iBAgpCsB,YAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,0EAIA,oBACD,mBACC,uCACY,MAAA,CAAK,uCACd,oBACZ"}
|