package claude import ( "context" "strings" "testing" "github.com/router-for-me/CLIProxyAPI/v6/internal/cache" ) // ============================================================================ // Signature Caching Tests // ============================================================================ func TestConvertAntigravityResponseToClaude_ParamsInitialized(t *testing.T) { cache.ClearSignatureCache("") // Request with user message - should initialize params requestJSON := []byte(`{ "messages": [ {"role": "user", "content": [{"type": "text", "text": "Hello world"}]} ] }`) // First response chunk with thinking responseJSON := []byte(`{ "response": { "candidates": [{ "content": { "parts": [{"text": "Let me think...", "thought": true}] } }] } }`) var param any ctx := context.Background() ConvertAntigravityResponseToClaude(ctx, "claude-sonnet-4-5-thinking", requestJSON, requestJSON, responseJSON, ¶m) params := param.(*Params) if !params.HasFirstResponse { t.Error("HasFirstResponse should be set after first chunk") } if params.CurrentThinkingText.Len() == 0 { t.Error("Thinking text should be accumulated") } } func TestConvertAntigravityResponseToClaude_ThinkingTextAccumulated(t *testing.T) { cache.ClearSignatureCache("") requestJSON := []byte(`{ "messages": [{"role": "user", "content": [{"type": "text", "text": "Test"}]}] }`) // First thinking chunk chunk1 := []byte(`{ "response": { "candidates": [{ "content": { "parts": [{"text": "First part of thinking...", "thought": true}] } }] } }`) // Second thinking chunk (continuation) chunk2 := []byte(`{ "response": { "candidates": [{ "content": { "parts": [{"text": " Second part of thinking...", "thought": true}] } }] } }`) var param any ctx := context.Background() // Process first chunk - starts new thinking block ConvertAntigravityResponseToClaude(ctx, "claude-sonnet-4-5-thinking", requestJSON, requestJSON, chunk1, ¶m) params := param.(*Params) if params.CurrentThinkingText.Len() == 0 { t.Error("Thinking text should be accumulated after first chunk") } // Process second chunk - continues thinking block ConvertAntigravityResponseToClaude(ctx, "claude-sonnet-4-5-thinking", requestJSON, requestJSON, chunk2, ¶m) text := params.CurrentThinkingText.String() if !strings.Contains(text, "First part") || !strings.Contains(text, "Second part") { t.Errorf("Thinking text should accumulate both parts, got: %s", text) } } func TestConvertAntigravityResponseToClaude_SignatureCached(t *testing.T) { cache.ClearSignatureCache("") requestJSON := []byte(`{ "model": "claude-sonnet-4-5-thinking", "messages": [{"role": "user", "content": [{"type": "text", "text": "Cache test"}]}] }`) // Thinking chunk thinkingChunk := []byte(`{ "response": { "candidates": [{ "content": { "parts": [{"text": "My thinking process here", "thought": true}] } }] } }`) // Signature chunk validSignature := "abc123validSignature1234567890123456789012345678901234567890" signatureChunk := []byte(`{ "response": { "candidates": [{ "content": { "parts": [{"text": "", "thought": true, "thoughtSignature": "` + validSignature + `"}] } }] } }`) var param any ctx := context.Background() // Process thinking chunk ConvertAntigravityResponseToClaude(ctx, "claude-sonnet-4-5-thinking", requestJSON, requestJSON, thinkingChunk, ¶m) params := param.(*Params) thinkingText := params.CurrentThinkingText.String() if thinkingText == "" { t.Fatal("Thinking text should be accumulated") } // Process signature chunk - should cache the signature ConvertAntigravityResponseToClaude(ctx, "claude-sonnet-4-5-thinking", requestJSON, requestJSON, signatureChunk, ¶m) // Verify signature was cached cachedSig := cache.GetCachedSignature("claude-sonnet-4-5-thinking", thinkingText) if cachedSig != validSignature { t.Errorf("Expected cached signature '%s', got '%s'", validSignature, cachedSig) } // Verify thinking text was reset after caching if params.CurrentThinkingText.Len() != 0 { t.Error("Thinking text should be reset after signature is cached") } } func TestConvertAntigravityResponseToClaude_MultipleThinkingBlocks(t *testing.T) { cache.ClearSignatureCache("") requestJSON := []byte(`{ "model": "claude-sonnet-4-5-thinking", "messages": [{"role": "user", "content": [{"type": "text", "text": "Multi block test"}]}] }`) validSig1 := "signature1_12345678901234567890123456789012345678901234567" validSig2 := "signature2_12345678901234567890123456789012345678901234567" // First thinking block with signature block1Thinking := []byte(`{ "response": { "candidates": [{ "content": { "parts": [{"text": "First thinking block", "thought": true}] } }] } }`) block1Sig := []byte(`{ "response": { "candidates": [{ "content": { "parts": [{"text": "", "thought": true, "thoughtSignature": "` + validSig1 + `"}] } }] } }`) // Text content (breaks thinking) textBlock := []byte(`{ "response": { "candidates": [{ "content": { "parts": [{"text": "Regular text output"}] } }] } }`) // Second thinking block with signature block2Thinking := []byte(`{ "response": { "candidates": [{ "content": { "parts": [{"text": "Second thinking block", "thought": true}] } }] } }`) block2Sig := []byte(`{ "response": { "candidates": [{ "content": { "parts": [{"text": "", "thought": true, "thoughtSignature": "` + validSig2 + `"}] } }] } }`) var param any ctx := context.Background() // Process first thinking block ConvertAntigravityResponseToClaude(ctx, "claude-sonnet-4-5-thinking", requestJSON, requestJSON, block1Thinking, ¶m) params := param.(*Params) firstThinkingText := params.CurrentThinkingText.String() ConvertAntigravityResponseToClaude(ctx, "claude-sonnet-4-5-thinking", requestJSON, requestJSON, block1Sig, ¶m) // Verify first signature cached if cache.GetCachedSignature("claude-sonnet-4-5-thinking", firstThinkingText) != validSig1 { t.Error("First thinking block signature should be cached") } // Process text (transitions out of thinking) ConvertAntigravityResponseToClaude(ctx, "claude-sonnet-4-5-thinking", requestJSON, requestJSON, textBlock, ¶m) // Process second thinking block ConvertAntigravityResponseToClaude(ctx, "claude-sonnet-4-5-thinking", requestJSON, requestJSON, block2Thinking, ¶m) secondThinkingText := params.CurrentThinkingText.String() ConvertAntigravityResponseToClaude(ctx, "claude-sonnet-4-5-thinking", requestJSON, requestJSON, block2Sig, ¶m) // Verify second signature cached if cache.GetCachedSignature("claude-sonnet-4-5-thinking", secondThinkingText) != validSig2 { t.Error("Second thinking block signature should be cached") } }