From 30cf91e27258a46d405de0084305d9d9adc516c0 Mon Sep 17 00:00:00 2001 From: csoftware-arigpt Date: Mon, 27 Jul 2026 20:18:20 +0300 Subject: [PATCH] Preserve #3440 coverage under signature replay Seed a connection-scoped Gemini thought signature before exercising the Claude-to-Gemini id assertions. This keeps the regression focused on the public-Gemini versus Vertex id contract while honoring the new signature replay behavior. Constraint: Signature-less historical Claude tool calls are intentionally converted to context text. Rejected: Emit unsigned functionCall parts in the fixture | Gemini 3+ rejects that production behavior. Confidence: high Scope-risk: narrow Tested: Prettier, repository ESLint hook, vertex-functioncall-id-3440 Node test, git diff --check Not-tested: Full repository test suite --- .../unit/vertex-functioncall-id-3440.test.ts | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/tests/unit/vertex-functioncall-id-3440.test.ts b/tests/unit/vertex-functioncall-id-3440.test.ts index 8609755c36..758557e374 100644 --- a/tests/unit/vertex-functioncall-id-3440.test.ts +++ b/tests/unit/vertex-functioncall-id-3440.test.ts @@ -11,15 +11,24 @@ import test from "node:test"; import assert from "node:assert/strict"; -const { openaiToGeminiRequest } = await import( - "../../open-sse/translator/request/openai-to-gemini.ts" -); -const { claudeToGeminiRequest } = await import( - "../../open-sse/translator/request/claude-to-gemini.ts" -); +const { openaiToGeminiRequest } = + await import("../../open-sse/translator/request/openai-to-gemini.ts"); +const { claudeToGeminiRequest } = + await import("../../open-sse/translator/request/claude-to-gemini.ts"); +const { buildGeminiThoughtSignatureKey, storeGeminiThoughtSignature } = + await import("../../open-sse/services/geminiThoughtSignatureStore.ts"); type UnknownRecord = Record; +const CLAUDE_SIGNATURE_NAMESPACE = "regression-3440"; + +function seedClaudeThoughtSignature() { + storeGeminiThoughtSignature( + buildGeminiThoughtSignatureKey(CLAUDE_SIGNATURE_NAMESPACE, "tu_weather_1"), + "SIG_3440" + ); +} + function findFunctionCall(result: any): UnknownRecord | undefined { for (const content of result.contents ?? []) { for (const part of content.parts ?? []) { @@ -126,10 +135,16 @@ test("#3440 OpenAI->Gemini: no provider hint PRESERVES id (default, non-vertex)" }); test("#3440 Claude->Gemini: vertex provider omits id from functionCall and functionResponse", () => { + seedClaudeThoughtSignature(); const result = claudeToGeminiRequest("gemini-2.5-pro", CLAUDE_TOOL_BODY, false, { _provider: "vertex", + _signatureNamespace: CLAUDE_SIGNATURE_NAMESPACE, }); - assert.equal(findFunctionCall(result)?.id, undefined, "functionCall.id must be omitted for Vertex"); + assert.equal( + findFunctionCall(result)?.id, + undefined, + "functionCall.id must be omitted for Vertex" + ); assert.equal( findFunctionResponse(result)?.id, undefined, @@ -138,6 +153,9 @@ test("#3440 Claude->Gemini: vertex provider omits id from functionCall and funct }); test("#3440 Claude->Gemini: no provider hint PRESERVES id (default, non-vertex)", () => { - const result = claudeToGeminiRequest("gemini-2.5-pro", CLAUDE_TOOL_BODY, false); + seedClaudeThoughtSignature(); + const result = claudeToGeminiRequest("gemini-2.5-pro", CLAUDE_TOOL_BODY, false, { + _signatureNamespace: CLAUDE_SIGNATURE_NAMESPACE, + }); assert.equal(findFunctionCall(result)?.id, "tu_weather_1"); });