@copilotkit/aimock 1.19.3 → 1.19.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/CHANGELOG.md +35 -0
  3. package/dist/agui-types.d.cts.map +1 -1
  4. package/dist/agui-types.d.ts.map +1 -1
  5. package/dist/bedrock-converse.cjs +11 -13
  6. package/dist/bedrock-converse.cjs.map +1 -1
  7. package/dist/bedrock-converse.d.cts.map +1 -1
  8. package/dist/bedrock-converse.d.ts.map +1 -1
  9. package/dist/bedrock-converse.js +11 -13
  10. package/dist/bedrock-converse.js.map +1 -1
  11. package/dist/bedrock.cjs +28 -3
  12. package/dist/bedrock.cjs.map +1 -1
  13. package/dist/bedrock.d.cts.map +1 -1
  14. package/dist/bedrock.d.ts.map +1 -1
  15. package/dist/bedrock.js +28 -3
  16. package/dist/bedrock.js.map +1 -1
  17. package/dist/cohere.cjs +59 -35
  18. package/dist/cohere.cjs.map +1 -1
  19. package/dist/cohere.d.cts +14 -2
  20. package/dist/cohere.d.cts.map +1 -1
  21. package/dist/cohere.d.ts +14 -2
  22. package/dist/cohere.d.ts.map +1 -1
  23. package/dist/cohere.js +59 -35
  24. package/dist/cohere.js.map +1 -1
  25. package/dist/gemini.cjs +4 -2
  26. package/dist/gemini.cjs.map +1 -1
  27. package/dist/gemini.d.cts.map +1 -1
  28. package/dist/gemini.d.ts.map +1 -1
  29. package/dist/gemini.js +5 -3
  30. package/dist/gemini.js.map +1 -1
  31. package/dist/messages.cjs +24 -4
  32. package/dist/messages.cjs.map +1 -1
  33. package/dist/messages.d.cts.map +1 -1
  34. package/dist/messages.d.ts.map +1 -1
  35. package/dist/messages.js +24 -4
  36. package/dist/messages.js.map +1 -1
  37. package/dist/moderation.cjs +6 -2
  38. package/dist/moderation.cjs.map +1 -1
  39. package/dist/moderation.d.cts.map +1 -1
  40. package/dist/moderation.d.ts.map +1 -1
  41. package/dist/moderation.js +6 -2
  42. package/dist/moderation.js.map +1 -1
  43. package/dist/ollama.cjs +25 -8
  44. package/dist/ollama.cjs.map +1 -1
  45. package/dist/ollama.d.cts +7 -0
  46. package/dist/ollama.d.cts.map +1 -1
  47. package/dist/ollama.d.ts +7 -0
  48. package/dist/ollama.d.ts.map +1 -1
  49. package/dist/ollama.js +25 -8
  50. package/dist/ollama.js.map +1 -1
  51. package/dist/rerank.cjs +4 -10
  52. package/dist/rerank.cjs.map +1 -1
  53. package/dist/rerank.js +4 -10
  54. package/dist/rerank.js.map +1 -1
  55. package/dist/responses.cjs +3 -1
  56. package/dist/responses.cjs.map +1 -1
  57. package/dist/responses.d.cts.map +1 -1
  58. package/dist/responses.d.ts.map +1 -1
  59. package/dist/responses.js +3 -1
  60. package/dist/responses.js.map +1 -1
  61. package/dist/search.cjs +7 -1
  62. package/dist/search.cjs.map +1 -1
  63. package/dist/search.js +7 -1
  64. package/dist/search.js.map +1 -1
  65. package/dist/server.cjs +12 -2
  66. package/dist/server.cjs.map +1 -1
  67. package/dist/server.d.cts.map +1 -1
  68. package/dist/server.d.ts.map +1 -1
  69. package/dist/server.js +12 -2
  70. package/dist/server.js.map +1 -1
  71. package/dist/transcription.cjs +7 -6
  72. package/dist/transcription.cjs.map +1 -1
  73. package/dist/transcription.js +7 -6
  74. package/dist/transcription.js.map +1 -1
  75. package/dist/vector-types.d.ts.map +1 -1
  76. package/dist/ws-gemini-live.cjs +37 -29
  77. package/dist/ws-gemini-live.cjs.map +1 -1
  78. package/dist/ws-gemini-live.d.cts.map +1 -1
  79. package/dist/ws-gemini-live.d.ts.map +1 -1
  80. package/dist/ws-gemini-live.js +37 -29
  81. package/dist/ws-gemini-live.js.map +1 -1
  82. package/dist/ws-realtime.cjs +84 -15
  83. package/dist/ws-realtime.cjs.map +1 -1
  84. package/dist/ws-realtime.d.cts.map +1 -1
  85. package/dist/ws-realtime.d.ts.map +1 -1
  86. package/dist/ws-realtime.js +84 -16
  87. package/dist/ws-realtime.js.map +1 -1
  88. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"gemini.js","names":[],"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 */\n\nimport type * as http from \"node:http\";\nimport type {\n AudioResponse,\n ChatCompletionRequest,\n ChatMessage,\n Fixture,\n HandlerDefaults,\n RecordProviderKey,\n ResponseOverrides,\n StreamingProfile,\n ToolCall,\n ToolDefinition,\n} from \"./types.js\";\nimport {\n isTextResponse,\n isToolCallResponse,\n isContentWithToolCallsResponse,\n isErrorResponse,\n isAudioResponse,\n extractOverrides,\n formatToMime,\n generateToolCallId,\n flattenHeaders,\n getTestId,\n resolveResponse,\n} from \"./helpers.js\";\nimport { matchFixture } 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 { applyChaos } from \"./chaos.js\";\nimport { proxyAndRecord } from \"./recorder.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 };\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}\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\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.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 funcResponses = content.parts.filter((p) => p.functionResponse);\n const textParts = content.parts.filter((p) => p.text !== undefined && !p.thought);\n\n if (funcResponses.length > 0) {\n // functionResponse → tool message\n for (const part of funcResponses) {\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: `call_gemini_${part.functionResponse!.name}_${callCounter++}`,\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 funcCalls = content.parts.filter((p) => p.functionCall);\n const textParts = content.parts.filter((p) => p.text !== undefined && !p.thought);\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) => ({\n id: `call_gemini_${fc.functionCall!.name}_${callCounter++}`,\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,\n },\n }));\n }\n }\n\n return {\n model,\n messages,\n stream,\n temperature: req.generationConfig?.temperature,\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 if (finishReason === \"stop\") return \"STOP\";\n if (finishReason === \"tool_calls\") return \"FUNCTION_CALL\";\n if (finishReason === \"length\") return \"MAX_TOKENS\";\n if (finishReason === \"content_filter\") return \"SAFETY\";\n // Pass through unrecognized values as-is\n return finishReason;\n}\n\nfunction geminiUsageMetadata(overrides?: ResponseOverrides): {\n promptTokenCount: number;\n candidatesTokenCount: number;\n totalTokenCount: number;\n} {\n if (!overrides?.usage)\n return { promptTokenCount: 0, candidatesTokenCount: 0, totalTokenCount: 0 };\n const prompt = overrides.usage.promptTokenCount ?? 0;\n const candidates = overrides.usage.candidatesTokenCount ?? 0;\n const total = overrides.usage.totalTokenCount ?? prompt + candidates;\n return {\n promptTokenCount: prompt,\n candidatesTokenCount: candidates,\n totalTokenCount: total,\n };\n}\n\ninterface GeminiResponseChunk {\n candidates: {\n content: { role: string; parts: GeminiPart[] };\n finishReason?: string;\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 let argsObj: Record<string, unknown>;\n try {\n argsObj = JSON.parse(tc.arguments || \"{}\") as Record<string, unknown>;\n } catch {\n logger.warn(`Malformed JSON in fixture tool call arguments for \"${tc.name}\": ${tc.arguments}`);\n argsObj = {};\n }\n return { functionCall: { name: tc.name, args: argsObj, id: tc.id || generateToolCallId() } };\n}\n\nfunction buildGeminiToolCallStreamChunks(\n toolCalls: ToolCall[],\n logger: Logger,\n overrides?: ResponseOverrides,\n): GeminiResponseChunk[] {\n const parts: GeminiPart[] = toolCalls.map((tc) => parseToolCallPart(tc, logger));\n\n // Gemini sends all tool calls in a single response chunk\n return [\n {\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}\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 overrides?: ResponseOverrides,\n): GeminiResponseChunk {\n const parts: GeminiPart[] = 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): 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 (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): GeminiResponseChunk {\n const parts: GeminiPart[] = [];\n if (reasoning) {\n parts.push({ text: reasoning, thought: true });\n }\n parts.push({ text: content });\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\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\nfunction buildGeminiAudioResponse(audio: AudioResponse): GeminiResponseChunk {\n const inlineData = resolveAudioInlineData(audio);\n return {\n candidates: [\n {\n content: { role: \"model\", parts: [{ inlineData }] },\n finishReason: \"STOP\",\n index: 0,\n },\n ],\n usageMetadata: { promptTokenCount: 0, candidatesTokenCount: 0, totalTokenCount: 0 },\n };\n}\n\nfunction buildGeminiAudioStreamChunks(audio: AudioResponse): GeminiResponseChunk[] {\n const inlineData = resolveAudioInlineData(audio);\n return [\n {\n candidates: [\n {\n content: { role: \"model\", parts: [{ inlineData }] },\n finishReason: \"STOP\",\n index: 0,\n },\n ],\n usageMetadata: { promptTokenCount: 0, candidatesTokenCount: 0, totalTokenCount: 0 },\n },\n ];\n}\n\n// ─── SSE writer for Gemini streaming ────────────────────────────────────────\n\ninterface GeminiStreamOptions {\n latency?: number;\n streamingProfile?: StreamingProfile;\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 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);\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// ─── 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 setCorsHeaders(res);\n\n let geminiReq: GeminiRequest;\n try {\n geminiReq = JSON.parse(raw) as GeminiRequest;\n } catch {\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 JSON.stringify({\n error: {\n message: \"Malformed JSON\",\n code: 400,\n status: \"INVALID_ARGUMENT\",\n },\n }),\n );\n return;\n }\n\n // Convert to ChatCompletionRequest for fixture matching\n const completionReq = geminiToCompletionRequest(geminiReq, model, streaming);\n completionReq._endpointType = \"chat\";\n\n const testId = getTestId(req);\n const fixture = matchFixture(\n fixtures,\n completionReq,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\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 applyChaos(\n res,\n fixture,\n defaults.chaos,\n req.headers,\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 if (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 !== \"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 const strictStatus = defaults.strict ? 503 : 404;\n const strictMessage = defaults.strict\n ? \"Strict mode: no fixture matched\"\n : \"No fixture matched\";\n if (defaults.strict) {\n logger.error(`STRICT: No fixture matched for ${req.method ?? \"POST\"} ${path}`);\n }\n journal.add({\n method: req.method ?? \"POST\",\n path,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: strictStatus, fixture: null },\n });\n writeErrorResponse(\n res,\n strictStatus,\n JSON.stringify({\n error: {\n message: strictMessage,\n code: strictStatus,\n status: defaults.strict ? \"UNAVAILABLE\" : \"NOT_FOUND\",\n },\n }),\n );\n return;\n }\n\n const response = await resolveResponse(fixture, completionReq);\n const latency = fixture.latency ?? defaults.latency;\n const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);\n\n // Error response\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n journal.add({\n method: req.method ?? \"POST\",\n path,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status, fixture },\n });\n // Gemini-style error format: { error: { code, message, status } }\n const geminiError = {\n error: {\n code: status,\n message: response.error.message,\n status: response.error.type ?? \"ERROR\",\n },\n };\n writeErrorResponse(res, status, JSON.stringify(geminiError));\n return;\n }\n\n // Audio response\n if (isAudioResponse(response)) {\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 if (!streaming) {\n const body = buildGeminiAudioResponse(response);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const chunks = buildGeminiAudioStreamChunks(response);\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeGeminiSSEStream(res, chunks, {\n latency,\n streamingProfile: fixture.streamingProfile,\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 (isContentWithToolCallsResponse(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 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 if (!streaming) {\n const body = buildGeminiContentWithToolCallsResponse(\n response.content,\n response.toolCalls,\n logger,\n response.reasoning,\n overrides,\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 response.toolCalls,\n chunkSize,\n logger,\n response.reasoning,\n overrides,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeGeminiSSEStream(res, chunks, {\n latency,\n streamingProfile: fixture.streamingProfile,\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 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 if (!streaming) {\n const body = buildGeminiTextResponse(response.content, response.reasoning, 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 response.reasoning,\n overrides,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeGeminiSSEStream(res, chunks, {\n latency,\n streamingProfile: fixture.streamingProfile,\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 const overrides = extractOverrides(response);\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 if (!streaming) {\n const body = buildGeminiToolCallResponse(response.toolCalls, logger, overrides);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const chunks = buildGeminiToolCallStreamChunks(response.toolCalls, logger, overrides);\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeGeminiSSEStream(res, chunks, {\n latency,\n streamingProfile: fixture.streamingProfile,\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 journal.add({\n method: req.method ?? \"POST\",\n path,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 500, fixture },\n });\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({\n error: {\n message: \"Fixture response did not match any known type\",\n code: 500,\n status: \"INTERNAL\",\n },\n }),\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"gemini.js","names":[],"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 */\n\nimport type * as http from \"node:http\";\nimport type {\n AudioResponse,\n ChatCompletionRequest,\n ChatMessage,\n Fixture,\n HandlerDefaults,\n RecordProviderKey,\n ResponseOverrides,\n StreamingProfile,\n ToolCall,\n ToolDefinition,\n} from \"./types.js\";\nimport {\n isTextResponse,\n isToolCallResponse,\n isContentWithToolCallsResponse,\n isErrorResponse,\n isAudioResponse,\n extractOverrides,\n formatToMime,\n flattenHeaders,\n getTestId,\n resolveResponse,\n} from \"./helpers.js\";\nimport { matchFixture } 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 { applyChaos } from \"./chaos.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\n\n// ─── Gemini request types ───────────────────────────────────────────────────\n\ninterface GeminiPart {\n text?: string;\n thought?: boolean;\n functionCall?: { name: string; args: Record<string, unknown> };\n functionResponse?: { name: string; response: unknown };\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}\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\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.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 funcResponses = content.parts.filter((p) => p.functionResponse);\n const textParts = content.parts.filter((p) => p.text !== undefined && !p.thought);\n\n if (funcResponses.length > 0) {\n // functionResponse → tool message\n for (const part of funcResponses) {\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: `call_gemini_${part.functionResponse!.name}_${callCounter++}`,\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 funcCalls = content.parts.filter((p) => p.functionCall);\n const textParts = content.parts.filter((p) => p.text !== undefined && !p.thought);\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) => ({\n id: `call_gemini_${fc.functionCall!.name}_${callCounter++}`,\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,\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 if (finishReason === \"stop\") return \"STOP\";\n if (finishReason === \"tool_calls\") return \"FUNCTION_CALL\";\n if (finishReason === \"length\") return \"MAX_TOKENS\";\n if (finishReason === \"content_filter\") return \"SAFETY\";\n // Pass through unrecognized values as-is\n return finishReason;\n}\n\nfunction geminiUsageMetadata(overrides?: ResponseOverrides): {\n promptTokenCount: number;\n candidatesTokenCount: number;\n totalTokenCount: number;\n} {\n if (!overrides?.usage)\n return { promptTokenCount: 0, candidatesTokenCount: 0, totalTokenCount: 0 };\n const prompt = overrides.usage.promptTokenCount ?? 0;\n const candidates = overrides.usage.candidatesTokenCount ?? 0;\n const total = overrides.usage.totalTokenCount ?? prompt + candidates;\n return {\n promptTokenCount: prompt,\n candidatesTokenCount: candidates,\n totalTokenCount: total,\n };\n}\n\ninterface GeminiResponseChunk {\n candidates: {\n content: { role: string; parts: GeminiPart[] };\n finishReason?: string;\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 let argsObj: Record<string, unknown>;\n try {\n argsObj = JSON.parse(tc.arguments || \"{}\") as Record<string, unknown>;\n } catch {\n logger.warn(`Malformed JSON in fixture tool call arguments for \"${tc.name}\": ${tc.arguments}`);\n argsObj = {};\n }\n return { functionCall: { name: tc.name, args: argsObj } };\n}\n\nfunction buildGeminiToolCallStreamChunks(\n toolCalls: ToolCall[],\n logger: Logger,\n overrides?: ResponseOverrides,\n): GeminiResponseChunk[] {\n const parts: GeminiPart[] = toolCalls.map((tc) => parseToolCallPart(tc, logger));\n\n // Gemini sends all tool calls in a single response chunk\n return [\n {\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}\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 overrides?: ResponseOverrides,\n): GeminiResponseChunk {\n const parts: GeminiPart[] = 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): 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 (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): GeminiResponseChunk {\n const parts: GeminiPart[] = [];\n if (reasoning) {\n parts.push({ text: reasoning, thought: true });\n }\n parts.push({ text: content });\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\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\nfunction buildGeminiAudioResponse(audio: AudioResponse): GeminiResponseChunk {\n const inlineData = resolveAudioInlineData(audio);\n return {\n candidates: [\n {\n content: { role: \"model\", parts: [{ inlineData }] },\n finishReason: \"STOP\",\n index: 0,\n },\n ],\n usageMetadata: { promptTokenCount: 0, candidatesTokenCount: 0, totalTokenCount: 0 },\n };\n}\n\nfunction buildGeminiAudioStreamChunks(audio: AudioResponse): GeminiResponseChunk[] {\n const inlineData = resolveAudioInlineData(audio);\n return [\n {\n candidates: [\n {\n content: { role: \"model\", parts: [{ inlineData }] },\n finishReason: \"STOP\",\n index: 0,\n },\n ],\n usageMetadata: { promptTokenCount: 0, candidatesTokenCount: 0, totalTokenCount: 0 },\n },\n ];\n}\n\n// ─── SSE writer for Gemini streaming ────────────────────────────────────────\n\ninterface GeminiStreamOptions {\n latency?: number;\n streamingProfile?: StreamingProfile;\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 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);\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// ─── 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 setCorsHeaders(res);\n\n let geminiReq: GeminiRequest;\n try {\n geminiReq = JSON.parse(raw) as GeminiRequest;\n } catch {\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 JSON.stringify({\n error: {\n message: \"Malformed JSON\",\n code: 400,\n status: \"INVALID_ARGUMENT\",\n },\n }),\n );\n return;\n }\n\n // Convert to ChatCompletionRequest for fixture matching\n const completionReq = geminiToCompletionRequest(geminiReq, model, streaming);\n completionReq._endpointType = \"chat\";\n\n const testId = getTestId(req);\n const fixture = matchFixture(\n fixtures,\n completionReq,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\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 applyChaos(\n res,\n fixture,\n defaults.chaos,\n req.headers,\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 if (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 !== \"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 const strictStatus = defaults.strict ? 503 : 404;\n const strictMessage = defaults.strict\n ? \"Strict mode: no fixture matched\"\n : \"No fixture matched\";\n if (defaults.strict) {\n logger.error(`STRICT: No fixture matched for ${req.method ?? \"POST\"} ${path}`);\n }\n journal.add({\n method: req.method ?? \"POST\",\n path,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: strictStatus, fixture: null },\n });\n writeErrorResponse(\n res,\n strictStatus,\n JSON.stringify({\n error: {\n message: strictMessage,\n code: strictStatus,\n status: defaults.strict ? \"UNAVAILABLE\" : \"NOT_FOUND\",\n },\n }),\n );\n return;\n }\n\n const response = await resolveResponse(fixture, completionReq);\n const latency = fixture.latency ?? defaults.latency;\n const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);\n\n // Error response\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n journal.add({\n method: req.method ?? \"POST\",\n path,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status, fixture },\n });\n // Gemini-style error format: { error: { code, message, status } }\n const geminiError = {\n error: {\n code: status,\n message: response.error.message,\n status: response.error.type ?? \"ERROR\",\n },\n };\n writeErrorResponse(res, status, JSON.stringify(geminiError));\n return;\n }\n\n // Audio response\n if (isAudioResponse(response)) {\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 if (!streaming) {\n const body = buildGeminiAudioResponse(response);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const chunks = buildGeminiAudioStreamChunks(response);\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeGeminiSSEStream(res, chunks, {\n latency,\n streamingProfile: fixture.streamingProfile,\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 (isContentWithToolCallsResponse(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 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 if (!streaming) {\n const body = buildGeminiContentWithToolCallsResponse(\n response.content,\n response.toolCalls,\n logger,\n response.reasoning,\n overrides,\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 response.toolCalls,\n chunkSize,\n logger,\n response.reasoning,\n overrides,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeGeminiSSEStream(res, chunks, {\n latency,\n streamingProfile: fixture.streamingProfile,\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 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 if (!streaming) {\n const body = buildGeminiTextResponse(response.content, response.reasoning, 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 response.reasoning,\n overrides,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeGeminiSSEStream(res, chunks, {\n latency,\n streamingProfile: fixture.streamingProfile,\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 const overrides = extractOverrides(response);\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 if (!streaming) {\n const body = buildGeminiToolCallResponse(response.toolCalls, logger, overrides);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const chunks = buildGeminiToolCallStreamChunks(response.toolCalls, logger, overrides);\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeGeminiSSEStream(res, chunks, {\n latency,\n streamingProfile: fixture.streamingProfile,\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 journal.add({\n method: req.method ?? \"POST\",\n path,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 500, fixture },\n });\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({\n error: {\n message: \"Fixture response did not match any known type\",\n code: 500,\n status: \"INTERNAL\",\n },\n }),\n );\n}\n"],"mappings":"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"}
package/dist/messages.cjs CHANGED
@@ -128,7 +128,8 @@ function buildClaudeTextStreamEvents(content, model, chunkSize, reasoning, overr
128
128
  index: blockIndex,
129
129
  content_block: {
130
130
  type: "thinking",
131
- thinking: ""
131
+ thinking: "",
132
+ signature: ""
132
133
  }
133
134
  });
134
135
  for (let i = 0; i < reasoning.length; i += chunkSize) {
@@ -142,6 +143,14 @@ function buildClaudeTextStreamEvents(content, model, chunkSize, reasoning, overr
142
143
  }
143
144
  });
144
145
  }
146
+ events.push({
147
+ type: "content_block_delta",
148
+ index: blockIndex,
149
+ delta: {
150
+ type: "signature_delta",
151
+ signature: ""
152
+ }
153
+ });
145
154
  events.push({
146
155
  type: "content_block_stop",
147
156
  index: blockIndex
@@ -251,7 +260,8 @@ function buildClaudeTextResponse(content, model, reasoning, overrides) {
251
260
  const contentBlocks = [];
252
261
  if (reasoning) contentBlocks.push({
253
262
  type: "thinking",
254
- thinking: reasoning
263
+ thinking: reasoning,
264
+ signature: ""
255
265
  });
256
266
  contentBlocks.push({
257
267
  type: "text",
@@ -318,7 +328,8 @@ function buildClaudeContentWithToolCallsStreamEvents(content, toolCalls, model,
318
328
  index: blockIndex,
319
329
  content_block: {
320
330
  type: "thinking",
321
- thinking: ""
331
+ thinking: "",
332
+ signature: ""
322
333
  }
323
334
  });
324
335
  for (let i = 0; i < reasoning.length; i += chunkSize) {
@@ -332,6 +343,14 @@ function buildClaudeContentWithToolCallsStreamEvents(content, toolCalls, model,
332
343
  }
333
344
  });
334
345
  }
346
+ events.push({
347
+ type: "content_block_delta",
348
+ index: blockIndex,
349
+ delta: {
350
+ type: "signature_delta",
351
+ signature: ""
352
+ }
353
+ });
335
354
  events.push({
336
355
  type: "content_block_stop",
337
356
  index: blockIndex
@@ -414,7 +433,8 @@ function buildClaudeContentWithToolCallsResponse(content, toolCalls, model, logg
414
433
  const contentBlocks = [];
415
434
  if (reasoning) contentBlocks.push({
416
435
  type: "thinking",
417
- thinking: reasoning
436
+ thinking: reasoning,
437
+ signature: ""
418
438
  });
419
439
  contentBlocks.push({
420
440
  type: "text",
@@ -1 +1 @@
1
- {"version":3,"file":"messages.cjs","names":["generateToolUseId","generateMessageId","calculateDelay","delay","flattenHeaders","getTestId","matchFixture","applyChaos","proxyAndRecord","resolveResponse","isErrorResponse","isContentWithToolCallsResponse","extractOverrides","createInterruptionSignal","isTextResponse","isToolCallResponse"],"sources":["../src/messages.ts"],"sourcesContent":["/**\n * Anthropic Claude Messages API support.\n *\n * Translates incoming /v1/messages requests into the ChatCompletionRequest\n * format used by the fixture router, and converts fixture responses back into\n * the Claude Messages API streaming (or non-streaming) format.\n */\n\nimport type * as http from \"node:http\";\nimport type {\n ChatCompletionRequest,\n ChatMessage,\n Fixture,\n HandlerDefaults,\n ResponseOverrides,\n StreamingProfile,\n ToolCall,\n ToolDefinition,\n} from \"./types.js\";\nimport {\n generateMessageId,\n generateToolUseId,\n extractOverrides,\n isTextResponse,\n isToolCallResponse,\n isContentWithToolCallsResponse,\n isErrorResponse,\n flattenHeaders,\n getTestId,\n resolveResponse,\n} from \"./helpers.js\";\nimport { matchFixture } 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 { applyChaos } from \"./chaos.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\n\n// ─── Claude Messages API request types ──────────────────────────────────────\n\ninterface ClaudeContentBlock {\n type: \"text\" | \"tool_use\" | \"tool_result\" | \"image\" | \"document\";\n text?: string;\n id?: string;\n name?: string;\n input?: unknown;\n tool_use_id?: string;\n content?: string | ClaudeContentBlock[];\n is_error?: boolean;\n}\n\ninterface ClaudeMessage {\n role: \"user\" | \"assistant\";\n content: string | ClaudeContentBlock[];\n}\n\ninterface ClaudeToolDef {\n name: string;\n description?: string;\n input_schema?: object;\n}\n\ninterface ClaudeRequest {\n model: string;\n messages: ClaudeMessage[];\n system?: string | ClaudeContentBlock[];\n tools?: ClaudeToolDef[];\n tool_choice?: unknown;\n stream?: boolean;\n max_tokens: number;\n temperature?: number;\n [key: string]: unknown;\n}\n\n// ─── Input conversion: Claude → ChatCompletions messages ────────────────────\n\nfunction extractClaudeTextContent(content: string | ClaudeContentBlock[]): string {\n if (typeof content === \"string\") return content;\n return content\n .filter((b) => b.type === \"text\")\n .map((b) => b.text ?? \"\")\n .join(\"\");\n}\n\nexport function claudeToCompletionRequest(req: ClaudeRequest): ChatCompletionRequest {\n const messages: ChatMessage[] = [];\n\n // system field → system message\n if (req.system) {\n const systemText =\n typeof req.system === \"string\"\n ? req.system\n : req.system\n .filter((b) => b.type === \"text\")\n .map((b) => b.text ?? \"\")\n .join(\"\");\n if (systemText) {\n messages.push({ role: \"system\", content: systemText });\n }\n }\n\n for (const msg of req.messages) {\n if (msg.role === \"user\") {\n // Check for tool_result blocks\n if (typeof msg.content !== \"string\" && Array.isArray(msg.content)) {\n const toolResults = msg.content.filter((b) => b.type === \"tool_result\");\n const textBlocks = msg.content.filter((b) => b.type === \"text\");\n\n if (toolResults.length > 0) {\n // Each tool_result → tool message\n for (const tr of toolResults) {\n const resultContent =\n typeof tr.content === \"string\"\n ? tr.content\n : Array.isArray(tr.content)\n ? tr.content\n .filter((b) => b.type === \"text\")\n .map((b) => b.text ?? \"\")\n .join(\"\")\n : \"\";\n messages.push({\n role: \"tool\",\n content: resultContent,\n tool_call_id: tr.tool_use_id,\n });\n }\n // Any accompanying text blocks → user message\n if (textBlocks.length > 0) {\n messages.push({\n role: \"user\",\n content: textBlocks.map((b) => b.text ?? \"\").join(\"\"),\n });\n }\n continue;\n }\n }\n // Regular user message\n messages.push({\n role: \"user\",\n content: extractClaudeTextContent(msg.content),\n });\n } else if (msg.role === \"assistant\") {\n if (typeof msg.content === \"string\") {\n messages.push({ role: \"assistant\", content: msg.content });\n } else if (Array.isArray(msg.content)) {\n const toolUseBlocks = msg.content.filter((b) => b.type === \"tool_use\");\n const textContent = extractClaudeTextContent(msg.content);\n\n if (toolUseBlocks.length > 0) {\n messages.push({\n role: \"assistant\",\n content: textContent || null,\n tool_calls: toolUseBlocks.map((b) => ({\n id: b.id ?? generateToolUseId(),\n type: \"function\" as const,\n function: {\n name: b.name ?? \"\",\n arguments: typeof b.input === \"string\" ? b.input : JSON.stringify(b.input ?? {}),\n },\n })),\n });\n } else {\n messages.push({ role: \"assistant\", content: textContent || null });\n }\n } else {\n // null/undefined content — tool-only assistant turn\n messages.push({ role: \"assistant\", content: null });\n }\n }\n }\n\n // Convert tools\n let tools: ToolDefinition[] | undefined;\n if (req.tools && req.tools.length > 0) {\n tools = req.tools.map((t) => ({\n type: \"function\" as const,\n function: {\n name: t.name,\n description: t.description,\n parameters: t.input_schema,\n },\n }));\n }\n\n return {\n model: req.model,\n messages,\n stream: req.stream,\n temperature: req.temperature,\n tools,\n };\n}\n\n// ─── Response building: fixture → Claude Messages API format ────────────────\n\nfunction claudeStopReason(finishReason: string | undefined, defaultReason: string): string {\n if (!finishReason) return defaultReason;\n if (finishReason === \"stop\") return \"end_turn\";\n if (finishReason === \"tool_calls\") return \"tool_use\";\n if (finishReason === \"length\") return \"max_tokens\";\n return finishReason;\n}\n\nfunction claudeUsage(overrides?: ResponseOverrides): {\n input_tokens: number;\n output_tokens: number;\n} {\n if (!overrides?.usage) return { input_tokens: 0, output_tokens: 0 };\n return {\n input_tokens: overrides.usage.input_tokens ?? 0,\n output_tokens: overrides.usage.output_tokens ?? 0,\n };\n}\n\ninterface ClaudeSSEEvent {\n type: string;\n [key: string]: unknown;\n}\n\nfunction buildClaudeTextStreamEvents(\n content: string,\n model: string,\n chunkSize: number,\n reasoning?: string,\n overrides?: ResponseOverrides,\n): ClaudeSSEEvent[] {\n const msgId = overrides?.id ?? generateMessageId();\n const effectiveModel = overrides?.model ?? model;\n const events: ClaudeSSEEvent[] = [];\n\n // message_start\n events.push({\n type: \"message_start\",\n message: {\n id: msgId,\n type: \"message\",\n role: overrides?.role ?? \"assistant\",\n content: [],\n model: effectiveModel,\n stop_reason: null,\n stop_sequence: null,\n usage: claudeUsage(overrides),\n },\n });\n\n let blockIndex = 0;\n\n // Thinking block (emitted before text when reasoning is present)\n if (reasoning) {\n events.push({\n type: \"content_block_start\",\n index: blockIndex,\n content_block: { type: \"thinking\", thinking: \"\" },\n });\n\n for (let i = 0; i < reasoning.length; i += chunkSize) {\n const slice = reasoning.slice(i, i + chunkSize);\n events.push({\n type: \"content_block_delta\",\n index: blockIndex,\n delta: { type: \"thinking_delta\", thinking: slice },\n });\n }\n\n events.push({\n type: \"content_block_stop\",\n index: blockIndex,\n });\n\n blockIndex++;\n }\n\n // content_block_start (text)\n events.push({\n type: \"content_block_start\",\n index: blockIndex,\n content_block: { type: \"text\", text: \"\" },\n });\n\n // content_block_delta — text chunks\n for (let i = 0; i < content.length; i += chunkSize) {\n const slice = content.slice(i, i + chunkSize);\n events.push({\n type: \"content_block_delta\",\n index: blockIndex,\n delta: { type: \"text_delta\", text: slice },\n });\n }\n\n // content_block_stop\n events.push({\n type: \"content_block_stop\",\n index: blockIndex,\n });\n\n // message_delta\n events.push({\n type: \"message_delta\",\n delta: {\n stop_reason: claudeStopReason(overrides?.finishReason, \"end_turn\"),\n stop_sequence: null,\n },\n usage: { output_tokens: claudeUsage(overrides).output_tokens },\n });\n\n // message_stop\n events.push({ type: \"message_stop\" });\n\n return events;\n}\n\nfunction buildClaudeToolCallStreamEvents(\n toolCalls: ToolCall[],\n model: string,\n chunkSize: number,\n logger: Logger,\n overrides?: ResponseOverrides,\n): ClaudeSSEEvent[] {\n const msgId = overrides?.id ?? generateMessageId();\n const effectiveModel = overrides?.model ?? model;\n const events: ClaudeSSEEvent[] = [];\n\n // message_start\n events.push({\n type: \"message_start\",\n message: {\n id: msgId,\n type: \"message\",\n role: overrides?.role ?? \"assistant\",\n content: [],\n model: effectiveModel,\n stop_reason: null,\n stop_sequence: null,\n usage: claudeUsage(overrides),\n },\n });\n\n for (let idx = 0; idx < toolCalls.length; idx++) {\n const tc = toolCalls[idx];\n const toolUseId = tc.id || generateToolUseId();\n\n // Parse arguments to JSON object (Claude uses objects, not strings)\n let argsObj: unknown;\n try {\n argsObj = JSON.parse(tc.arguments || \"{}\");\n } catch {\n logger.warn(\n `Malformed JSON in fixture tool call arguments for \"${tc.name}\": ${tc.arguments}`,\n );\n argsObj = {};\n }\n const argsJson = JSON.stringify(argsObj);\n\n // content_block_start\n events.push({\n type: \"content_block_start\",\n index: idx,\n content_block: {\n type: \"tool_use\",\n id: toolUseId,\n name: tc.name,\n input: {},\n },\n });\n\n // content_block_delta — input_json_delta chunks\n for (let i = 0; i < argsJson.length; i += chunkSize) {\n const slice = argsJson.slice(i, i + chunkSize);\n events.push({\n type: \"content_block_delta\",\n index: idx,\n delta: { type: \"input_json_delta\", partial_json: slice },\n });\n }\n\n // content_block_stop\n events.push({\n type: \"content_block_stop\",\n index: idx,\n });\n }\n\n // message_delta\n events.push({\n type: \"message_delta\",\n delta: {\n stop_reason: claudeStopReason(overrides?.finishReason, \"tool_use\"),\n stop_sequence: null,\n },\n usage: { output_tokens: claudeUsage(overrides).output_tokens },\n });\n\n // message_stop\n events.push({ type: \"message_stop\" });\n\n return events;\n}\n\n// Non-streaming response builders\n\nfunction buildClaudeTextResponse(\n content: string,\n model: string,\n reasoning?: string,\n overrides?: ResponseOverrides,\n): object {\n const contentBlocks: object[] = [];\n\n if (reasoning) {\n contentBlocks.push({ type: \"thinking\", thinking: reasoning });\n }\n\n contentBlocks.push({ type: \"text\", text: content });\n\n return {\n id: overrides?.id ?? generateMessageId(),\n type: \"message\",\n role: overrides?.role ?? \"assistant\",\n content: contentBlocks,\n model: overrides?.model ?? model,\n stop_reason: claudeStopReason(overrides?.finishReason, \"end_turn\"),\n stop_sequence: null,\n usage: claudeUsage(overrides),\n };\n}\n\nfunction buildClaudeToolCallResponse(\n toolCalls: ToolCall[],\n model: string,\n logger: Logger,\n overrides?: ResponseOverrides,\n): object {\n return {\n id: overrides?.id ?? generateMessageId(),\n type: \"message\",\n role: overrides?.role ?? \"assistant\",\n content: toolCalls.map((tc) => {\n let argsObj: unknown;\n try {\n argsObj = JSON.parse(tc.arguments || \"{}\");\n } catch {\n logger.warn(\n `Malformed JSON in fixture tool call arguments for \"${tc.name}\": ${tc.arguments}`,\n );\n argsObj = {};\n }\n return {\n type: \"tool_use\",\n id: tc.id || generateToolUseId(),\n name: tc.name,\n input: argsObj,\n };\n }),\n model: overrides?.model ?? model,\n stop_reason: claudeStopReason(overrides?.finishReason, \"tool_use\"),\n stop_sequence: null,\n usage: claudeUsage(overrides),\n };\n}\n\nfunction buildClaudeContentWithToolCallsStreamEvents(\n content: string,\n toolCalls: ToolCall[],\n model: string,\n chunkSize: number,\n logger: Logger,\n reasoning?: string,\n overrides?: ResponseOverrides,\n): ClaudeSSEEvent[] {\n const msgId = overrides?.id ?? generateMessageId();\n const effectiveModel = overrides?.model ?? model;\n const events: ClaudeSSEEvent[] = [];\n\n // message_start\n events.push({\n type: \"message_start\",\n message: {\n id: msgId,\n type: \"message\",\n role: overrides?.role ?? \"assistant\",\n content: [],\n model: effectiveModel,\n stop_reason: null,\n stop_sequence: null,\n usage: claudeUsage(overrides),\n },\n });\n\n let blockIndex = 0;\n\n // Optional thinking block\n if (reasoning) {\n events.push({\n type: \"content_block_start\",\n index: blockIndex,\n content_block: { type: \"thinking\", thinking: \"\" },\n });\n\n for (let i = 0; i < reasoning.length; i += chunkSize) {\n const slice = reasoning.slice(i, i + chunkSize);\n events.push({\n type: \"content_block_delta\",\n index: blockIndex,\n delta: { type: \"thinking_delta\", thinking: slice },\n });\n }\n\n events.push({\n type: \"content_block_stop\",\n index: blockIndex,\n });\n\n blockIndex++;\n }\n\n // Text content block\n events.push({\n type: \"content_block_start\",\n index: blockIndex,\n content_block: { type: \"text\", text: \"\" },\n });\n\n for (let i = 0; i < content.length; i += chunkSize) {\n const slice = content.slice(i, i + chunkSize);\n events.push({\n type: \"content_block_delta\",\n index: blockIndex,\n delta: { type: \"text_delta\", text: slice },\n });\n }\n\n events.push({\n type: \"content_block_stop\",\n index: blockIndex,\n });\n\n blockIndex++;\n\n // Tool use blocks\n for (const tc of toolCalls) {\n const toolUseId = tc.id || generateToolUseId();\n\n let argsObj: unknown;\n try {\n argsObj = JSON.parse(tc.arguments || \"{}\");\n } catch {\n logger.warn(\n `Malformed JSON in fixture tool call arguments for \"${tc.name}\": ${tc.arguments}`,\n );\n argsObj = {};\n }\n const argsJson = JSON.stringify(argsObj);\n\n events.push({\n type: \"content_block_start\",\n index: blockIndex,\n content_block: {\n type: \"tool_use\",\n id: toolUseId,\n name: tc.name,\n input: {},\n },\n });\n\n for (let i = 0; i < argsJson.length; i += chunkSize) {\n const slice = argsJson.slice(i, i + chunkSize);\n events.push({\n type: \"content_block_delta\",\n index: blockIndex,\n delta: { type: \"input_json_delta\", partial_json: slice },\n });\n }\n\n events.push({\n type: \"content_block_stop\",\n index: blockIndex,\n });\n\n blockIndex++;\n }\n\n // message_delta\n events.push({\n type: \"message_delta\",\n delta: {\n stop_reason: claudeStopReason(overrides?.finishReason, \"tool_use\"),\n stop_sequence: null,\n },\n usage: { output_tokens: claudeUsage(overrides).output_tokens },\n });\n\n // message_stop\n events.push({ type: \"message_stop\" });\n\n return events;\n}\n\nfunction buildClaudeContentWithToolCallsResponse(\n content: string,\n toolCalls: ToolCall[],\n model: string,\n logger: Logger,\n reasoning?: string,\n overrides?: ResponseOverrides,\n): object {\n const contentBlocks: object[] = [];\n\n if (reasoning) {\n contentBlocks.push({ type: \"thinking\", thinking: reasoning });\n }\n\n contentBlocks.push({ type: \"text\", text: content });\n\n for (const tc of toolCalls) {\n let argsObj: unknown;\n try {\n argsObj = JSON.parse(tc.arguments || \"{}\");\n } catch {\n logger.warn(\n `Malformed JSON in fixture tool call arguments for \"${tc.name}\": ${tc.arguments}`,\n );\n argsObj = {};\n }\n contentBlocks.push({\n type: \"tool_use\",\n id: tc.id || generateToolUseId(),\n name: tc.name,\n input: argsObj,\n });\n }\n\n return {\n id: overrides?.id ?? generateMessageId(),\n type: \"message\",\n role: overrides?.role ?? \"assistant\",\n content: contentBlocks,\n model: overrides?.model ?? model,\n stop_reason: claudeStopReason(overrides?.finishReason, \"tool_use\"),\n stop_sequence: null,\n usage: claudeUsage(overrides),\n };\n}\n\n// ─── SSE writer for Claude Messages API ─────────────────────────────────────\n\ninterface ClaudeStreamOptions {\n latency?: number;\n streamingProfile?: StreamingProfile;\n signal?: AbortSignal;\n onChunkSent?: () => void;\n}\n\nasync function writeClaudeSSEStream(\n res: http.ServerResponse,\n events: ClaudeSSEEvent[],\n optionsOrLatency?: number | ClaudeStreamOptions,\n): Promise<boolean> {\n const opts: ClaudeStreamOptions =\n typeof optionsOrLatency === \"number\" ? { latency: optionsOrLatency } : (optionsOrLatency ?? {});\n const latency = opts.latency ?? 0;\n const profile = opts.streamingProfile;\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 event of events) {\n const chunkDelay = calculateDelay(chunkIndex, profile, latency);\n if (chunkDelay > 0) await delay(chunkDelay, signal);\n if (signal?.aborted) return false;\n if (res.writableEnded) return true;\n res.write(`event: ${event.type}\\ndata: ${JSON.stringify(event)}\\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// ─── Request handler ────────────────────────────────────────────────────────\n\nexport async function handleMessages(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n raw: string,\n fixtures: Fixture[],\n journal: Journal,\n defaults: HandlerDefaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n): Promise<void> {\n const { logger } = defaults;\n setCorsHeaders(res);\n\n let claudeReq: ClaudeRequest;\n try {\n claudeReq = JSON.parse(raw) as ClaudeRequest;\n } catch {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/messages\",\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n error: {\n message: \"Malformed JSON\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Convert to ChatCompletionRequest for fixture matching\n const completionReq = claudeToCompletionRequest(claudeReq);\n completionReq._endpointType = \"chat\";\n\n const testId = getTestId(req);\n const fixture = matchFixture(\n fixtures,\n completionReq,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\n );\n\n if (fixture) {\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n logger.debug(`Fixture matched: ${JSON.stringify(fixture.match).slice(0, 120)}`);\n } else {\n const lastUserMsg = completionReq.messages.filter((m) => m.role === \"user\").pop();\n const snippet =\n typeof lastUserMsg?.content === \"string\" ? lastUserMsg.content.slice(0, 80) : \"\";\n logger.debug(\n `No fixture matched for request (model=${completionReq.model ?? \"?\"}, msg=\"${snippet}\")`,\n );\n }\n\n if (\n applyChaos(\n res,\n fixture,\n defaults.chaos,\n req.headers,\n journal,\n {\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/messages\",\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 if (defaults.record) {\n const outcome = await proxyAndRecord(\n req,\n res,\n completionReq,\n \"anthropic\",\n req.url ?? \"/v1/messages\",\n fixtures,\n defaults,\n raw,\n );\n if (outcome !== \"not_configured\") {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/messages\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: res.statusCode ?? 200, fixture: null, source: \"proxy\" },\n });\n return;\n }\n }\n const strictStatus = defaults.strict ? 503 : 404;\n const strictMessage = defaults.strict\n ? \"Strict mode: no fixture matched\"\n : \"No fixture matched\";\n if (defaults.strict) {\n logger.error(\n `STRICT: No fixture matched for ${req.method ?? \"POST\"} ${req.url ?? \"/v1/messages\"}`,\n );\n }\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/messages\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: strictStatus, fixture: null },\n });\n writeErrorResponse(\n res,\n strictStatus,\n JSON.stringify({\n error: {\n message: strictMessage,\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n const response = await resolveResponse(fixture, completionReq);\n const latency = fixture.latency ?? defaults.latency;\n const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);\n\n // Error response\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/messages\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status, fixture },\n });\n // Anthropic-style error format: { type: \"error\", error: { type, message } }\n const anthropicError = {\n type: \"error\",\n error: {\n type: response.error.type ?? \"api_error\",\n message: response.error.message,\n },\n };\n writeErrorResponse(res, status, JSON.stringify(anthropicError));\n return;\n }\n\n // Content + tool calls response (must be checked before text/tool-only branches)\n if (isContentWithToolCallsResponse(response)) {\n if (response.webSearches?.length) {\n logger.warn(\n \"webSearches in fixture response are not supported for Claude Messages API — ignoring\",\n );\n }\n const overrides = extractOverrides(response);\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/messages\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n if (claudeReq.stream !== true) {\n const body = buildClaudeContentWithToolCallsResponse(\n response.content,\n response.toolCalls,\n completionReq.model,\n logger,\n response.reasoning,\n overrides,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const events = buildClaudeContentWithToolCallsStreamEvents(\n response.content,\n response.toolCalls,\n completionReq.model,\n chunkSize,\n logger,\n response.reasoning,\n overrides,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeClaudeSSEStream(res, events, {\n latency,\n streamingProfile: fixture.streamingProfile,\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(\n \"webSearches in fixture response are not supported for Claude Messages API — ignoring\",\n );\n }\n const overrides = extractOverrides(response);\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/messages\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n if (claudeReq.stream !== true) {\n const body = buildClaudeTextResponse(\n response.content,\n completionReq.model,\n response.reasoning,\n overrides,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const events = buildClaudeTextStreamEvents(\n response.content,\n completionReq.model,\n chunkSize,\n response.reasoning,\n overrides,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeClaudeSSEStream(res, events, {\n latency,\n streamingProfile: fixture.streamingProfile,\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 const overrides = extractOverrides(response);\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/messages\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n if (claudeReq.stream !== true) {\n const body = buildClaudeToolCallResponse(\n response.toolCalls,\n completionReq.model,\n logger,\n overrides,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const events = buildClaudeToolCallStreamEvents(\n response.toolCalls,\n completionReq.model,\n chunkSize,\n logger,\n overrides,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeClaudeSSEStream(res, events, {\n latency,\n streamingProfile: fixture.streamingProfile,\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 journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/messages\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 500, fixture },\n });\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({\n error: {\n message: \"Fixture response did not match any known type\",\n type: \"server_error\",\n },\n }),\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"messages.cjs","names":["generateToolUseId","generateMessageId","calculateDelay","delay","flattenHeaders","getTestId","matchFixture","applyChaos","proxyAndRecord","resolveResponse","isErrorResponse","isContentWithToolCallsResponse","extractOverrides","createInterruptionSignal","isTextResponse","isToolCallResponse"],"sources":["../src/messages.ts"],"sourcesContent":["/**\n * Anthropic Claude Messages API support.\n *\n * Translates incoming /v1/messages requests into the ChatCompletionRequest\n * format used by the fixture router, and converts fixture responses back into\n * the Claude Messages API streaming (or non-streaming) format.\n */\n\nimport type * as http from \"node:http\";\nimport type {\n ChatCompletionRequest,\n ChatMessage,\n Fixture,\n HandlerDefaults,\n ResponseOverrides,\n StreamingProfile,\n ToolCall,\n ToolDefinition,\n} from \"./types.js\";\nimport {\n generateMessageId,\n generateToolUseId,\n extractOverrides,\n isTextResponse,\n isToolCallResponse,\n isContentWithToolCallsResponse,\n isErrorResponse,\n flattenHeaders,\n getTestId,\n resolveResponse,\n} from \"./helpers.js\";\nimport { matchFixture } 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 { applyChaos } from \"./chaos.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\n\n// ─── Claude Messages API request types ──────────────────────────────────────\n\ninterface ClaudeContentBlock {\n type: \"text\" | \"tool_use\" | \"tool_result\" | \"image\" | \"document\";\n text?: string;\n id?: string;\n name?: string;\n input?: unknown;\n tool_use_id?: string;\n content?: string | ClaudeContentBlock[];\n is_error?: boolean;\n}\n\ninterface ClaudeMessage {\n role: \"user\" | \"assistant\";\n content: string | ClaudeContentBlock[];\n}\n\ninterface ClaudeToolDef {\n name: string;\n description?: string;\n input_schema?: object;\n}\n\ninterface ClaudeRequest {\n model: string;\n messages: ClaudeMessage[];\n system?: string | ClaudeContentBlock[];\n tools?: ClaudeToolDef[];\n tool_choice?: unknown;\n stream?: boolean;\n max_tokens: number;\n temperature?: number;\n [key: string]: unknown;\n}\n\n// ─── Input conversion: Claude → ChatCompletions messages ────────────────────\n\nfunction extractClaudeTextContent(content: string | ClaudeContentBlock[]): string {\n if (typeof content === \"string\") return content;\n return content\n .filter((b) => b.type === \"text\")\n .map((b) => b.text ?? \"\")\n .join(\"\");\n}\n\nexport function claudeToCompletionRequest(req: ClaudeRequest): ChatCompletionRequest {\n const messages: ChatMessage[] = [];\n\n // system field → system message\n if (req.system) {\n const systemText =\n typeof req.system === \"string\"\n ? req.system\n : req.system\n .filter((b) => b.type === \"text\")\n .map((b) => b.text ?? \"\")\n .join(\"\");\n if (systemText) {\n messages.push({ role: \"system\", content: systemText });\n }\n }\n\n for (const msg of req.messages) {\n if (msg.role === \"user\") {\n // Check for tool_result blocks\n if (typeof msg.content !== \"string\" && Array.isArray(msg.content)) {\n const toolResults = msg.content.filter((b) => b.type === \"tool_result\");\n const textBlocks = msg.content.filter((b) => b.type === \"text\");\n\n if (toolResults.length > 0) {\n // Each tool_result → tool message\n for (const tr of toolResults) {\n const resultContent =\n typeof tr.content === \"string\"\n ? tr.content\n : Array.isArray(tr.content)\n ? tr.content\n .filter((b) => b.type === \"text\")\n .map((b) => b.text ?? \"\")\n .join(\"\")\n : \"\";\n messages.push({\n role: \"tool\",\n content: resultContent,\n tool_call_id: tr.tool_use_id,\n });\n }\n // Any accompanying text blocks → user message\n if (textBlocks.length > 0) {\n messages.push({\n role: \"user\",\n content: textBlocks.map((b) => b.text ?? \"\").join(\"\"),\n });\n }\n continue;\n }\n }\n // Regular user message\n messages.push({\n role: \"user\",\n content: extractClaudeTextContent(msg.content),\n });\n } else if (msg.role === \"assistant\") {\n if (typeof msg.content === \"string\") {\n messages.push({ role: \"assistant\", content: msg.content });\n } else if (Array.isArray(msg.content)) {\n const toolUseBlocks = msg.content.filter((b) => b.type === \"tool_use\");\n const textContent = extractClaudeTextContent(msg.content);\n\n if (toolUseBlocks.length > 0) {\n messages.push({\n role: \"assistant\",\n content: textContent || null,\n tool_calls: toolUseBlocks.map((b) => ({\n id: b.id ?? generateToolUseId(),\n type: \"function\" as const,\n function: {\n name: b.name ?? \"\",\n arguments: typeof b.input === \"string\" ? b.input : JSON.stringify(b.input ?? {}),\n },\n })),\n });\n } else {\n messages.push({ role: \"assistant\", content: textContent || null });\n }\n } else {\n // null/undefined content — tool-only assistant turn\n messages.push({ role: \"assistant\", content: null });\n }\n }\n }\n\n // Convert tools\n let tools: ToolDefinition[] | undefined;\n if (req.tools && req.tools.length > 0) {\n tools = req.tools.map((t) => ({\n type: \"function\" as const,\n function: {\n name: t.name,\n description: t.description,\n parameters: t.input_schema,\n },\n }));\n }\n\n return {\n model: req.model,\n messages,\n stream: req.stream,\n temperature: req.temperature,\n tools,\n };\n}\n\n// ─── Response building: fixture → Claude Messages API format ────────────────\n\nfunction claudeStopReason(finishReason: string | undefined, defaultReason: string): string {\n if (!finishReason) return defaultReason;\n if (finishReason === \"stop\") return \"end_turn\";\n if (finishReason === \"tool_calls\") return \"tool_use\";\n if (finishReason === \"length\") return \"max_tokens\";\n return finishReason;\n}\n\nfunction claudeUsage(overrides?: ResponseOverrides): {\n input_tokens: number;\n output_tokens: number;\n} {\n if (!overrides?.usage) return { input_tokens: 0, output_tokens: 0 };\n return {\n input_tokens: overrides.usage.input_tokens ?? 0,\n output_tokens: overrides.usage.output_tokens ?? 0,\n };\n}\n\ninterface ClaudeSSEEvent {\n type: string;\n [key: string]: unknown;\n}\n\nfunction buildClaudeTextStreamEvents(\n content: string,\n model: string,\n chunkSize: number,\n reasoning?: string,\n overrides?: ResponseOverrides,\n): ClaudeSSEEvent[] {\n const msgId = overrides?.id ?? generateMessageId();\n const effectiveModel = overrides?.model ?? model;\n const events: ClaudeSSEEvent[] = [];\n\n // message_start\n events.push({\n type: \"message_start\",\n message: {\n id: msgId,\n type: \"message\",\n role: overrides?.role ?? \"assistant\",\n content: [],\n model: effectiveModel,\n stop_reason: null,\n stop_sequence: null,\n usage: claudeUsage(overrides),\n },\n });\n\n let blockIndex = 0;\n\n // Thinking block (emitted before text when reasoning is present)\n if (reasoning) {\n events.push({\n type: \"content_block_start\",\n index: blockIndex,\n content_block: { type: \"thinking\", thinking: \"\", signature: \"\" },\n });\n\n for (let i = 0; i < reasoning.length; i += chunkSize) {\n const slice = reasoning.slice(i, i + chunkSize);\n events.push({\n type: \"content_block_delta\",\n index: blockIndex,\n delta: { type: \"thinking_delta\", thinking: slice },\n });\n }\n\n events.push({\n type: \"content_block_delta\",\n index: blockIndex,\n delta: { type: \"signature_delta\", signature: \"\" },\n });\n\n events.push({\n type: \"content_block_stop\",\n index: blockIndex,\n });\n\n blockIndex++;\n }\n\n // content_block_start (text)\n events.push({\n type: \"content_block_start\",\n index: blockIndex,\n content_block: { type: \"text\", text: \"\" },\n });\n\n // content_block_delta — text chunks\n for (let i = 0; i < content.length; i += chunkSize) {\n const slice = content.slice(i, i + chunkSize);\n events.push({\n type: \"content_block_delta\",\n index: blockIndex,\n delta: { type: \"text_delta\", text: slice },\n });\n }\n\n // content_block_stop\n events.push({\n type: \"content_block_stop\",\n index: blockIndex,\n });\n\n // message_delta\n events.push({\n type: \"message_delta\",\n delta: {\n stop_reason: claudeStopReason(overrides?.finishReason, \"end_turn\"),\n stop_sequence: null,\n },\n usage: { output_tokens: claudeUsage(overrides).output_tokens },\n });\n\n // message_stop\n events.push({ type: \"message_stop\" });\n\n return events;\n}\n\nfunction buildClaudeToolCallStreamEvents(\n toolCalls: ToolCall[],\n model: string,\n chunkSize: number,\n logger: Logger,\n overrides?: ResponseOverrides,\n): ClaudeSSEEvent[] {\n const msgId = overrides?.id ?? generateMessageId();\n const effectiveModel = overrides?.model ?? model;\n const events: ClaudeSSEEvent[] = [];\n\n // message_start\n events.push({\n type: \"message_start\",\n message: {\n id: msgId,\n type: \"message\",\n role: overrides?.role ?? \"assistant\",\n content: [],\n model: effectiveModel,\n stop_reason: null,\n stop_sequence: null,\n usage: claudeUsage(overrides),\n },\n });\n\n for (let idx = 0; idx < toolCalls.length; idx++) {\n const tc = toolCalls[idx];\n const toolUseId = tc.id || generateToolUseId();\n\n // Parse arguments to JSON object (Claude uses objects, not strings)\n let argsObj: unknown;\n try {\n argsObj = JSON.parse(tc.arguments || \"{}\");\n } catch {\n logger.warn(\n `Malformed JSON in fixture tool call arguments for \"${tc.name}\": ${tc.arguments}`,\n );\n argsObj = {};\n }\n const argsJson = JSON.stringify(argsObj);\n\n // content_block_start\n events.push({\n type: \"content_block_start\",\n index: idx,\n content_block: {\n type: \"tool_use\",\n id: toolUseId,\n name: tc.name,\n input: {},\n },\n });\n\n // content_block_delta — input_json_delta chunks\n for (let i = 0; i < argsJson.length; i += chunkSize) {\n const slice = argsJson.slice(i, i + chunkSize);\n events.push({\n type: \"content_block_delta\",\n index: idx,\n delta: { type: \"input_json_delta\", partial_json: slice },\n });\n }\n\n // content_block_stop\n events.push({\n type: \"content_block_stop\",\n index: idx,\n });\n }\n\n // message_delta\n events.push({\n type: \"message_delta\",\n delta: {\n stop_reason: claudeStopReason(overrides?.finishReason, \"tool_use\"),\n stop_sequence: null,\n },\n usage: { output_tokens: claudeUsage(overrides).output_tokens },\n });\n\n // message_stop\n events.push({ type: \"message_stop\" });\n\n return events;\n}\n\n// Non-streaming response builders\n\nfunction buildClaudeTextResponse(\n content: string,\n model: string,\n reasoning?: string,\n overrides?: ResponseOverrides,\n): object {\n const contentBlocks: object[] = [];\n\n if (reasoning) {\n contentBlocks.push({ type: \"thinking\", thinking: reasoning, signature: \"\" });\n }\n\n contentBlocks.push({ type: \"text\", text: content });\n\n return {\n id: overrides?.id ?? generateMessageId(),\n type: \"message\",\n role: overrides?.role ?? \"assistant\",\n content: contentBlocks,\n model: overrides?.model ?? model,\n stop_reason: claudeStopReason(overrides?.finishReason, \"end_turn\"),\n stop_sequence: null,\n usage: claudeUsage(overrides),\n };\n}\n\nfunction buildClaudeToolCallResponse(\n toolCalls: ToolCall[],\n model: string,\n logger: Logger,\n overrides?: ResponseOverrides,\n): object {\n return {\n id: overrides?.id ?? generateMessageId(),\n type: \"message\",\n role: overrides?.role ?? \"assistant\",\n content: toolCalls.map((tc) => {\n let argsObj: unknown;\n try {\n argsObj = JSON.parse(tc.arguments || \"{}\");\n } catch {\n logger.warn(\n `Malformed JSON in fixture tool call arguments for \"${tc.name}\": ${tc.arguments}`,\n );\n argsObj = {};\n }\n return {\n type: \"tool_use\",\n id: tc.id || generateToolUseId(),\n name: tc.name,\n input: argsObj,\n };\n }),\n model: overrides?.model ?? model,\n stop_reason: claudeStopReason(overrides?.finishReason, \"tool_use\"),\n stop_sequence: null,\n usage: claudeUsage(overrides),\n };\n}\n\nfunction buildClaudeContentWithToolCallsStreamEvents(\n content: string,\n toolCalls: ToolCall[],\n model: string,\n chunkSize: number,\n logger: Logger,\n reasoning?: string,\n overrides?: ResponseOverrides,\n): ClaudeSSEEvent[] {\n const msgId = overrides?.id ?? generateMessageId();\n const effectiveModel = overrides?.model ?? model;\n const events: ClaudeSSEEvent[] = [];\n\n // message_start\n events.push({\n type: \"message_start\",\n message: {\n id: msgId,\n type: \"message\",\n role: overrides?.role ?? \"assistant\",\n content: [],\n model: effectiveModel,\n stop_reason: null,\n stop_sequence: null,\n usage: claudeUsage(overrides),\n },\n });\n\n let blockIndex = 0;\n\n // Optional thinking block\n if (reasoning) {\n events.push({\n type: \"content_block_start\",\n index: blockIndex,\n content_block: { type: \"thinking\", thinking: \"\", signature: \"\" },\n });\n\n for (let i = 0; i < reasoning.length; i += chunkSize) {\n const slice = reasoning.slice(i, i + chunkSize);\n events.push({\n type: \"content_block_delta\",\n index: blockIndex,\n delta: { type: \"thinking_delta\", thinking: slice },\n });\n }\n\n events.push({\n type: \"content_block_delta\",\n index: blockIndex,\n delta: { type: \"signature_delta\", signature: \"\" },\n });\n\n events.push({\n type: \"content_block_stop\",\n index: blockIndex,\n });\n\n blockIndex++;\n }\n\n // Text content block\n events.push({\n type: \"content_block_start\",\n index: blockIndex,\n content_block: { type: \"text\", text: \"\" },\n });\n\n for (let i = 0; i < content.length; i += chunkSize) {\n const slice = content.slice(i, i + chunkSize);\n events.push({\n type: \"content_block_delta\",\n index: blockIndex,\n delta: { type: \"text_delta\", text: slice },\n });\n }\n\n events.push({\n type: \"content_block_stop\",\n index: blockIndex,\n });\n\n blockIndex++;\n\n // Tool use blocks\n for (const tc of toolCalls) {\n const toolUseId = tc.id || generateToolUseId();\n\n let argsObj: unknown;\n try {\n argsObj = JSON.parse(tc.arguments || \"{}\");\n } catch {\n logger.warn(\n `Malformed JSON in fixture tool call arguments for \"${tc.name}\": ${tc.arguments}`,\n );\n argsObj = {};\n }\n const argsJson = JSON.stringify(argsObj);\n\n events.push({\n type: \"content_block_start\",\n index: blockIndex,\n content_block: {\n type: \"tool_use\",\n id: toolUseId,\n name: tc.name,\n input: {},\n },\n });\n\n for (let i = 0; i < argsJson.length; i += chunkSize) {\n const slice = argsJson.slice(i, i + chunkSize);\n events.push({\n type: \"content_block_delta\",\n index: blockIndex,\n delta: { type: \"input_json_delta\", partial_json: slice },\n });\n }\n\n events.push({\n type: \"content_block_stop\",\n index: blockIndex,\n });\n\n blockIndex++;\n }\n\n // message_delta\n events.push({\n type: \"message_delta\",\n delta: {\n stop_reason: claudeStopReason(overrides?.finishReason, \"tool_use\"),\n stop_sequence: null,\n },\n usage: { output_tokens: claudeUsage(overrides).output_tokens },\n });\n\n // message_stop\n events.push({ type: \"message_stop\" });\n\n return events;\n}\n\nfunction buildClaudeContentWithToolCallsResponse(\n content: string,\n toolCalls: ToolCall[],\n model: string,\n logger: Logger,\n reasoning?: string,\n overrides?: ResponseOverrides,\n): object {\n const contentBlocks: object[] = [];\n\n if (reasoning) {\n contentBlocks.push({ type: \"thinking\", thinking: reasoning, signature: \"\" });\n }\n\n contentBlocks.push({ type: \"text\", text: content });\n\n for (const tc of toolCalls) {\n let argsObj: unknown;\n try {\n argsObj = JSON.parse(tc.arguments || \"{}\");\n } catch {\n logger.warn(\n `Malformed JSON in fixture tool call arguments for \"${tc.name}\": ${tc.arguments}`,\n );\n argsObj = {};\n }\n contentBlocks.push({\n type: \"tool_use\",\n id: tc.id || generateToolUseId(),\n name: tc.name,\n input: argsObj,\n });\n }\n\n return {\n id: overrides?.id ?? generateMessageId(),\n type: \"message\",\n role: overrides?.role ?? \"assistant\",\n content: contentBlocks,\n model: overrides?.model ?? model,\n stop_reason: claudeStopReason(overrides?.finishReason, \"tool_use\"),\n stop_sequence: null,\n usage: claudeUsage(overrides),\n };\n}\n\n// ─── SSE writer for Claude Messages API ─────────────────────────────────────\n\ninterface ClaudeStreamOptions {\n latency?: number;\n streamingProfile?: StreamingProfile;\n signal?: AbortSignal;\n onChunkSent?: () => void;\n}\n\nasync function writeClaudeSSEStream(\n res: http.ServerResponse,\n events: ClaudeSSEEvent[],\n optionsOrLatency?: number | ClaudeStreamOptions,\n): Promise<boolean> {\n const opts: ClaudeStreamOptions =\n typeof optionsOrLatency === \"number\" ? { latency: optionsOrLatency } : (optionsOrLatency ?? {});\n const latency = opts.latency ?? 0;\n const profile = opts.streamingProfile;\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 event of events) {\n const chunkDelay = calculateDelay(chunkIndex, profile, latency);\n if (chunkDelay > 0) await delay(chunkDelay, signal);\n if (signal?.aborted) return false;\n if (res.writableEnded) return true;\n res.write(`event: ${event.type}\\ndata: ${JSON.stringify(event)}\\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// ─── Request handler ────────────────────────────────────────────────────────\n\nexport async function handleMessages(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n raw: string,\n fixtures: Fixture[],\n journal: Journal,\n defaults: HandlerDefaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n): Promise<void> {\n const { logger } = defaults;\n setCorsHeaders(res);\n\n let claudeReq: ClaudeRequest;\n try {\n claudeReq = JSON.parse(raw) as ClaudeRequest;\n } catch {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/messages\",\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n error: {\n message: \"Malformed JSON\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Convert to ChatCompletionRequest for fixture matching\n const completionReq = claudeToCompletionRequest(claudeReq);\n completionReq._endpointType = \"chat\";\n\n const testId = getTestId(req);\n const fixture = matchFixture(\n fixtures,\n completionReq,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\n );\n\n if (fixture) {\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n logger.debug(`Fixture matched: ${JSON.stringify(fixture.match).slice(0, 120)}`);\n } else {\n const lastUserMsg = completionReq.messages.filter((m) => m.role === \"user\").pop();\n const snippet =\n typeof lastUserMsg?.content === \"string\" ? lastUserMsg.content.slice(0, 80) : \"\";\n logger.debug(\n `No fixture matched for request (model=${completionReq.model ?? \"?\"}, msg=\"${snippet}\")`,\n );\n }\n\n if (\n applyChaos(\n res,\n fixture,\n defaults.chaos,\n req.headers,\n journal,\n {\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/messages\",\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 if (defaults.record) {\n const outcome = await proxyAndRecord(\n req,\n res,\n completionReq,\n \"anthropic\",\n req.url ?? \"/v1/messages\",\n fixtures,\n defaults,\n raw,\n );\n if (outcome !== \"not_configured\") {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/messages\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: res.statusCode ?? 200, fixture: null, source: \"proxy\" },\n });\n return;\n }\n }\n const strictStatus = defaults.strict ? 503 : 404;\n const strictMessage = defaults.strict\n ? \"Strict mode: no fixture matched\"\n : \"No fixture matched\";\n if (defaults.strict) {\n logger.error(\n `STRICT: No fixture matched for ${req.method ?? \"POST\"} ${req.url ?? \"/v1/messages\"}`,\n );\n }\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/messages\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: strictStatus, fixture: null },\n });\n writeErrorResponse(\n res,\n strictStatus,\n JSON.stringify({\n error: {\n message: strictMessage,\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n const response = await resolveResponse(fixture, completionReq);\n const latency = fixture.latency ?? defaults.latency;\n const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);\n\n // Error response\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/messages\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status, fixture },\n });\n // Anthropic-style error format: { type: \"error\", error: { type, message } }\n const anthropicError = {\n type: \"error\",\n error: {\n type: response.error.type ?? \"api_error\",\n message: response.error.message,\n },\n };\n writeErrorResponse(res, status, JSON.stringify(anthropicError));\n return;\n }\n\n // Content + tool calls response (must be checked before text/tool-only branches)\n if (isContentWithToolCallsResponse(response)) {\n if (response.webSearches?.length) {\n logger.warn(\n \"webSearches in fixture response are not supported for Claude Messages API — ignoring\",\n );\n }\n const overrides = extractOverrides(response);\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/messages\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n if (claudeReq.stream !== true) {\n const body = buildClaudeContentWithToolCallsResponse(\n response.content,\n response.toolCalls,\n completionReq.model,\n logger,\n response.reasoning,\n overrides,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const events = buildClaudeContentWithToolCallsStreamEvents(\n response.content,\n response.toolCalls,\n completionReq.model,\n chunkSize,\n logger,\n response.reasoning,\n overrides,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeClaudeSSEStream(res, events, {\n latency,\n streamingProfile: fixture.streamingProfile,\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(\n \"webSearches in fixture response are not supported for Claude Messages API — ignoring\",\n );\n }\n const overrides = extractOverrides(response);\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/messages\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n if (claudeReq.stream !== true) {\n const body = buildClaudeTextResponse(\n response.content,\n completionReq.model,\n response.reasoning,\n overrides,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const events = buildClaudeTextStreamEvents(\n response.content,\n completionReq.model,\n chunkSize,\n response.reasoning,\n overrides,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeClaudeSSEStream(res, events, {\n latency,\n streamingProfile: fixture.streamingProfile,\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 const overrides = extractOverrides(response);\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/messages\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n if (claudeReq.stream !== true) {\n const body = buildClaudeToolCallResponse(\n response.toolCalls,\n completionReq.model,\n logger,\n overrides,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const events = buildClaudeToolCallStreamEvents(\n response.toolCalls,\n completionReq.model,\n chunkSize,\n logger,\n overrides,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeClaudeSSEStream(res, events, {\n latency,\n streamingProfile: fixture.streamingProfile,\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 journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/messages\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 500, fixture },\n });\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({\n error: {\n message: \"Fixture response did not match any known type\",\n type: \"server_error\",\n },\n }),\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"messages.d.cts","names":[],"sources":["../src/messages.ts"],"sourcesContent":[],"mappings":";;;;;;iBAkrBsB,cAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,uCAEA,oBACD,mBACC,uCACY,MAAA,CAAK,0BAC1B"}
1
+ {"version":3,"file":"messages.d.cts","names":[],"sources":["../src/messages.ts"],"sourcesContent":[],"mappings":";;;;;;iBA8rBsB,cAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,uCAEA,oBACD,mBACC,uCACY,MAAA,CAAK,0BAC1B"}
@@ -1 +1 @@
1
- {"version":3,"file":"messages.d.ts","names":[],"sources":["../src/messages.ts"],"sourcesContent":[],"mappings":";;;;;;iBAkrBsB,cAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,uCAEA,oBACD,mBACC,uCACY,MAAA,CAAK,0BAC1B"}
1
+ {"version":3,"file":"messages.d.ts","names":[],"sources":["../src/messages.ts"],"sourcesContent":[],"mappings":";;;;;;iBA8rBsB,cAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,uCAEA,oBACD,mBACC,uCACY,MAAA,CAAK,0BAC1B"}
package/dist/messages.js CHANGED
@@ -128,7 +128,8 @@ function buildClaudeTextStreamEvents(content, model, chunkSize, reasoning, overr
128
128
  index: blockIndex,
129
129
  content_block: {
130
130
  type: "thinking",
131
- thinking: ""
131
+ thinking: "",
132
+ signature: ""
132
133
  }
133
134
  });
134
135
  for (let i = 0; i < reasoning.length; i += chunkSize) {
@@ -142,6 +143,14 @@ function buildClaudeTextStreamEvents(content, model, chunkSize, reasoning, overr
142
143
  }
143
144
  });
144
145
  }
146
+ events.push({
147
+ type: "content_block_delta",
148
+ index: blockIndex,
149
+ delta: {
150
+ type: "signature_delta",
151
+ signature: ""
152
+ }
153
+ });
145
154
  events.push({
146
155
  type: "content_block_stop",
147
156
  index: blockIndex
@@ -251,7 +260,8 @@ function buildClaudeTextResponse(content, model, reasoning, overrides) {
251
260
  const contentBlocks = [];
252
261
  if (reasoning) contentBlocks.push({
253
262
  type: "thinking",
254
- thinking: reasoning
263
+ thinking: reasoning,
264
+ signature: ""
255
265
  });
256
266
  contentBlocks.push({
257
267
  type: "text",
@@ -318,7 +328,8 @@ function buildClaudeContentWithToolCallsStreamEvents(content, toolCalls, model,
318
328
  index: blockIndex,
319
329
  content_block: {
320
330
  type: "thinking",
321
- thinking: ""
331
+ thinking: "",
332
+ signature: ""
322
333
  }
323
334
  });
324
335
  for (let i = 0; i < reasoning.length; i += chunkSize) {
@@ -332,6 +343,14 @@ function buildClaudeContentWithToolCallsStreamEvents(content, toolCalls, model,
332
343
  }
333
344
  });
334
345
  }
346
+ events.push({
347
+ type: "content_block_delta",
348
+ index: blockIndex,
349
+ delta: {
350
+ type: "signature_delta",
351
+ signature: ""
352
+ }
353
+ });
335
354
  events.push({
336
355
  type: "content_block_stop",
337
356
  index: blockIndex
@@ -414,7 +433,8 @@ function buildClaudeContentWithToolCallsResponse(content, toolCalls, model, logg
414
433
  const contentBlocks = [];
415
434
  if (reasoning) contentBlocks.push({
416
435
  type: "thinking",
417
- thinking: reasoning
436
+ thinking: reasoning,
437
+ signature: ""
418
438
  });
419
439
  contentBlocks.push({
420
440
  type: "text",