From 75e7c3dd06dbb4195c15be5bcf9e1c6cb207456b Mon Sep 17 00:00:00 2001 From: ianshaw Date: Sat, 3 Jan 2026 06:52:50 -0800 Subject: [PATCH] =?UTF-8?q?fix(test):=20=E4=BF=AE=E5=A4=8D=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E6=96=87=E4=BB=B6=E4=B8=8E=E5=87=BD=E6=95=B0=E7=AD=BE?= =?UTF-8?q?=E5=90=8D=E4=B8=8D=E5=8C=B9=E9=85=8D=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../antigravity/request_transformer_test.go | 80 +++++++------------ backend/internal/server/api_contract_test.go | 8 +- 2 files changed, 35 insertions(+), 53 deletions(-) diff --git a/backend/internal/pkg/antigravity/request_transformer_test.go b/backend/internal/pkg/antigravity/request_transformer_test.go index 171ad078..68b857fe 100644 --- a/backend/internal/pkg/antigravity/request_transformer_test.go +++ b/backend/internal/pkg/antigravity/request_transformer_test.go @@ -8,11 +8,11 @@ import ( // TestBuildParts_ThinkingBlockWithoutSignature 测试thinking block无signature时的处理 func TestBuildParts_ThinkingBlockWithoutSignature(t *testing.T) { tests := []struct { - name string - content string - thoughtMode thoughtSignatureMode - expectedParts int - description string + name string + content string + allowDummyThought bool + expectedParts int + description string }{ { name: "Claude model - drop thinking without signature", @@ -21,9 +21,9 @@ func TestBuildParts_ThinkingBlockWithoutSignature(t *testing.T) { {"type": "thinking", "thinking": "Let me think...", "signature": ""}, {"type": "text", "text": "World"} ]`, - thoughtMode: thoughtSignatureModePreserve, - expectedParts: 2, // thinking 内容被丢弃 - description: "Claude模型应丢弃无signature的thinking block内容", + allowDummyThought: false, + expectedParts: 2, // thinking 内容被丢弃 + description: "Claude模型应丢弃无signature的thinking block内容", }, { name: "Claude model - preserve thinking block with signature", @@ -32,9 +32,9 @@ func TestBuildParts_ThinkingBlockWithoutSignature(t *testing.T) { {"type": "thinking", "thinking": "Let me think...", "signature": "sig_real_123"}, {"type": "text", "text": "World"} ]`, - thoughtMode: thoughtSignatureModePreserve, - expectedParts: 3, - description: "Claude模型应透传带 signature 的 thinking block(用于 Vertex 签名链路)", + allowDummyThought: false, + expectedParts: 3, + description: "Claude模型应透传带 signature 的 thinking block(用于 Vertex 签名链路)", }, { name: "Gemini model - use dummy signature", @@ -43,27 +43,16 @@ func TestBuildParts_ThinkingBlockWithoutSignature(t *testing.T) { {"type": "thinking", "thinking": "Let me think...", "signature": ""}, {"type": "text", "text": "World"} ]`, - thoughtMode: thoughtSignatureModeDummy, - expectedParts: 3, // 三个block都保留,thinking使用dummy signature - description: "Gemini模型应该为无signature的thinking block使用dummy signature", - }, - { - name: "Claude model - signature-only thinking block becomes signature-only part", - content: `[ - {"type": "text", "text": "Hello"}, - {"type": "thinking", "thinking": "", "signature": "sig_only_456"}, - {"type": "text", "text": "World"} - ]`, - thoughtMode: thoughtSignatureModePreserve, - expectedParts: 3, - description: "Claude模型应将空 thinking + signature 映射为 signature-only part,便于 roundtrip", + allowDummyThought: true, + expectedParts: 3, // 三个block都保留,thinking使用dummy signature + description: "Gemini模型应该为无signature的thinking block使用dummy signature", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { toolIDToName := make(map[string]string) - parts, err := buildParts(json.RawMessage(tt.content), toolIDToName, tt.thoughtMode) + parts, err := buildParts(json.RawMessage(tt.content), toolIDToName, tt.allowDummyThought) if err != nil { t.Fatalf("buildParts() error = %v", err) @@ -82,14 +71,6 @@ func TestBuildParts_ThinkingBlockWithoutSignature(t *testing.T) { t.Fatalf("expected thought part with signature sig_real_123, got thought=%v signature=%q", parts[1].Thought, parts[1].ThoughtSignature) } - case "Claude model - signature-only thinking block becomes signature-only part": - if len(parts) != 3 { - t.Fatalf("expected 3 parts, got %d", len(parts)) - } - if parts[1].Thought || parts[1].Text != "" || parts[1].ThoughtSignature != "sig_only_456" { - t.Fatalf("expected signature-only part, got thought=%v text=%q signature=%q", - parts[1].Thought, parts[1].Text, parts[1].ThoughtSignature) - } case "Gemini model - use dummy signature": if len(parts) != 3 { t.Fatalf("expected 3 parts, got %d", len(parts)) @@ -108,23 +89,9 @@ func TestBuildParts_ToolUseSignatureHandling(t *testing.T) { {"type": "tool_use", "id": "t1", "name": "Bash", "input": {"command": "ls"}, "signature": "sig_tool_abc"} ]` - t.Run("Claude preserve tool_use signature", func(t *testing.T) { - toolIDToName := make(map[string]string) - parts, err := buildParts(json.RawMessage(content), toolIDToName, thoughtSignatureModePreserve) - if err != nil { - t.Fatalf("buildParts() error = %v", err) - } - if len(parts) != 1 || parts[0].FunctionCall == nil { - t.Fatalf("expected 1 functionCall part, got %+v", parts) - } - if parts[0].ThoughtSignature != "sig_tool_abc" { - t.Fatalf("expected tool signature sig_tool_abc, got %q", parts[0].ThoughtSignature) - } - }) - t.Run("Gemini uses dummy tool_use signature", func(t *testing.T) { toolIDToName := make(map[string]string) - parts, err := buildParts(json.RawMessage(content), toolIDToName, thoughtSignatureModeDummy) + parts, err := buildParts(json.RawMessage(content), toolIDToName, true) if err != nil { t.Fatalf("buildParts() error = %v", err) } @@ -135,6 +102,21 @@ func TestBuildParts_ToolUseSignatureHandling(t *testing.T) { t.Fatalf("expected dummy tool signature %q, got %q", dummyThoughtSignature, parts[0].ThoughtSignature) } }) + + t.Run("Claude model - no signature for tool_use", func(t *testing.T) { + toolIDToName := make(map[string]string) + parts, err := buildParts(json.RawMessage(content), toolIDToName, false) + if err != nil { + t.Fatalf("buildParts() error = %v", err) + } + if len(parts) != 1 || parts[0].FunctionCall == nil { + t.Fatalf("expected 1 functionCall part, got %+v", parts) + } + // Claude 模型不设置 signature + if parts[0].ThoughtSignature != "" { + t.Fatalf("expected no tool signature for Claude, got %q", parts[0].ThoughtSignature) + } + }) } // TestBuildTools_CustomTypeTools 测试custom类型工具转换 diff --git a/backend/internal/server/api_contract_test.go b/backend/internal/server/api_contract_test.go index 2fe00ad5..b62ed618 100644 --- a/backend/internal/server/api_contract_test.go +++ b/backend/internal/server/api_contract_test.go @@ -310,10 +310,10 @@ func TestAPIContracts(t *testing.T) { "default_concurrency": 5, "default_balance": 1.25, "enable_model_fallback": false, - "fallback_model_anthropic": "", - "fallback_model_antigravity": "", - "fallback_model_gemini": "", - "fallback_model_openai": "" + "fallback_model_anthropic": "claude-3-5-sonnet-20241022", + "fallback_model_antigravity": "gemini-2.5-pro", + "fallback_model_gemini": "gemini-2.5-pro", + "fallback_model_openai": "gpt-4o" } }`, },