diff --git a/internal/translator/antigravity/claude/antigravity_claude_request.go b/internal/translator/antigravity/claude/antigravity_claude_request.go index 406a41d9..e87a7d6b 100644 --- a/internal/translator/antigravity/claude/antigravity_claude_request.go +++ b/internal/translator/antigravity/claude/antigravity_claude_request.go @@ -7,8 +7,6 @@ package claude import ( "bytes" - "crypto/sha256" - "encoding/hex" "strings" "github.com/router-for-me/CLIProxyAPI/v6/internal/cache" @@ -19,33 +17,6 @@ import ( "github.com/tidwall/sjson" ) -// deriveSessionID generates a stable session ID from the request. -// Uses the hash of the first user message to identify the conversation. -func deriveSessionID(rawJSON []byte) string { - userIDResult := gjson.GetBytes(rawJSON, "metadata.user_id") - if userIDResult.Exists() { - userID := userIDResult.String() - idx := strings.Index(userID, "session_") - if idx != -1 { - return userID[idx+8:] - } - } - messages := gjson.GetBytes(rawJSON, "messages") - if !messages.IsArray() { - return "" - } - for _, msg := range messages.Array() { - if msg.Get("role").String() == "user" { - content := msg.Get("content").Raw - if content != "" { - h := sha256.Sum256([]byte(content)) - return hex.EncodeToString(h[:16]) - } - } - } - return "" -} - // ConvertClaudeRequestToAntigravity parses and transforms a Claude Code API request into Gemini CLI API format. // It extracts the model name, system instruction, message contents, and tool declarations // from the raw JSON request and returns them in the format expected by the Gemini CLI API. @@ -68,9 +39,6 @@ func ConvertClaudeRequestToAntigravity(modelName string, inputRawJSON []byte, _ enableThoughtTranslate := true rawJSON := bytes.Clone(inputRawJSON) - // Derive session ID for signature caching - sessionID := deriveSessionID(rawJSON) - // system instruction systemInstructionJSON := "" hasSystemInstruction := false @@ -133,7 +101,7 @@ func ConvertClaudeRequestToAntigravity(modelName string, inputRawJSON []byte, _ // Always try cached signature first (more reliable than client-provided) // Client may send stale or invalid signatures from different sessions signature := "" - if sessionID != "" && thinkingText != "" { + if thinkingText != "" { if cachedSig := cache.GetCachedSignature(modelName, thinkingText); cachedSig != "" { signature = cachedSig // log.Debugf("Using cached signature for thinking block") diff --git a/internal/translator/antigravity/claude/antigravity_claude_request_test.go b/internal/translator/antigravity/claude/antigravity_claude_request_test.go index 5e61b393..6eb58795 100644 --- a/internal/translator/antigravity/claude/antigravity_claude_request_test.go +++ b/internal/translator/antigravity/claude/antigravity_claude_request_test.go @@ -98,10 +98,7 @@ func TestConvertClaudeRequestToAntigravity_ThinkingBlocks(t *testing.T) { ] }`) - // Derive session ID and cache the signature - sessionID := deriveSessionID(inputJSON) - cache.CacheSignature("claude-sonnet-4-5-thinking", sessionID, thinkingText, validSignature) - defer cache.ClearSignatureCache(sessionID) + cache.CacheSignature("claude-sonnet-4-5-thinking", thinkingText, validSignature) output := ConvertClaudeRequestToAntigravity("claude-sonnet-4-5-thinking", inputJSON, false) outputStr := string(output) @@ -266,10 +263,7 @@ func TestConvertClaudeRequestToAntigravity_ToolUse_WithSignature(t *testing.T) { ] }`) - // Derive session ID and cache the signature - sessionID := deriveSessionID(inputJSON) - cache.CacheSignature("claude-sonnet-4-5-thinking", sessionID, thinkingText, validSignature) - defer cache.ClearSignatureCache(sessionID) + cache.CacheSignature("claude-sonnet-4-5-thinking", thinkingText, validSignature) output := ConvertClaudeRequestToAntigravity("claude-sonnet-4-5-thinking", inputJSON, false) outputStr := string(output) @@ -306,10 +300,7 @@ func TestConvertClaudeRequestToAntigravity_ReorderThinking(t *testing.T) { ] }`) - // Derive session ID and cache the signature - sessionID := deriveSessionID(inputJSON) - cache.CacheSignature("claude-sonnet-4-5-thinking", sessionID, thinkingText, validSignature) - defer cache.ClearSignatureCache(sessionID) + cache.CacheSignature("claude-sonnet-4-5-thinking", thinkingText, validSignature) output := ConvertClaudeRequestToAntigravity("claude-sonnet-4-5-thinking", inputJSON, false) outputStr := string(output) @@ -517,10 +508,7 @@ func TestConvertClaudeRequestToAntigravity_TrailingSignedThinking_Kept(t *testin ] }`) - // Derive session ID and cache the signature - sessionID := deriveSessionID(inputJSON) - cache.CacheSignature("claude-sonnet-4-5-thinking", sessionID, thinkingText, validSignature) - defer cache.ClearSignatureCache(sessionID) + cache.CacheSignature("claude-sonnet-4-5-thinking", thinkingText, validSignature) output := ConvertClaudeRequestToAntigravity("claude-sonnet-4-5-thinking", inputJSON, false) outputStr := string(output) diff --git a/internal/translator/antigravity/claude/antigravity_claude_response.go b/internal/translator/antigravity/claude/antigravity_claude_response.go index f22e0f1d..acad9a4f 100644 --- a/internal/translator/antigravity/claude/antigravity_claude_response.go +++ b/internal/translator/antigravity/claude/antigravity_claude_response.go @@ -70,7 +70,6 @@ func ConvertAntigravityResponseToClaude(_ context.Context, _ string, originalReq HasFirstResponse: false, ResponseType: 0, ResponseIndex: 0, - SessionID: deriveSessionID(originalRequestRawJSON), } } modelName := gjson.GetBytes(requestRawJSON, "model").String() diff --git a/internal/translator/antigravity/claude/antigravity_claude_response_test.go b/internal/translator/antigravity/claude/antigravity_claude_response_test.go index ef6c0afe..9dd1eedd 100644 --- a/internal/translator/antigravity/claude/antigravity_claude_response_test.go +++ b/internal/translator/antigravity/claude/antigravity_claude_response_test.go @@ -144,7 +144,7 @@ func TestConvertAntigravityResponseToClaude_SignatureCached(t *testing.T) { ConvertAntigravityResponseToClaude(ctx, "claude-sonnet-4-5-thinking", requestJSON, requestJSON, signatureChunk, ¶m) // Verify signature was cached - cachedSig := cache.GetCachedSignature("claude-sonnet-4-5-thinking", sessionID, thinkingText) + cachedSig := cache.GetCachedSignature("claude-sonnet-4-5-thinking", thinkingText) if cachedSig != validSignature { t.Errorf("Expected cached signature '%s', got '%s'", validSignature, cachedSig) } @@ -223,13 +223,12 @@ func TestConvertAntigravityResponseToClaude_MultipleThinkingBlocks(t *testing.T) // Process first thinking block ConvertAntigravityResponseToClaude(ctx, "claude-sonnet-4-5-thinking", requestJSON, requestJSON, block1Thinking, ¶m) params := param.(*Params) - sessionID := params.SessionID 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", sessionID, firstThinkingText) != validSig1 { + if cache.GetCachedSignature("claude-sonnet-4-5-thinking", firstThinkingText) != validSig1 { t.Error("First thinking block signature should be cached") } @@ -243,76 +242,7 @@ func TestConvertAntigravityResponseToClaude_MultipleThinkingBlocks(t *testing.T) ConvertAntigravityResponseToClaude(ctx, "claude-sonnet-4-5-thinking", requestJSON, requestJSON, block2Sig, ¶m) // Verify second signature cached - if cache.GetCachedSignature("claude-sonnet-4-5-thinking", sessionID, secondThinkingText) != validSig2 { + if cache.GetCachedSignature("claude-sonnet-4-5-thinking", secondThinkingText) != validSig2 { t.Error("Second thinking block signature should be cached") } } - -func TestDeriveSessionIDFromRequest(t *testing.T) { - tests := []struct { - name string - input []byte - wantEmpty bool - }{ - { - name: "valid user message", - input: []byte(`{"messages": [{"role": "user", "content": "Hello"}]}`), - wantEmpty: false, - }, - { - name: "user message with content array", - input: []byte(`{"messages": [{"role": "user", "content": [{"type": "text", "text": "Hello"}]}]}`), - wantEmpty: false, - }, - { - name: "no user message", - input: []byte(`{"messages": [{"role": "assistant", "content": "Hi"}]}`), - wantEmpty: true, - }, - { - name: "empty messages", - input: []byte(`{"messages": []}`), - wantEmpty: true, - }, - { - name: "no messages field", - input: []byte(`{}`), - wantEmpty: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := deriveSessionID(tt.input) - if tt.wantEmpty && result != "" { - t.Errorf("Expected empty session ID, got '%s'", result) - } - if !tt.wantEmpty && result == "" { - t.Error("Expected non-empty session ID") - } - }) - } -} - -func TestDeriveSessionIDFromRequest_Deterministic(t *testing.T) { - input := []byte(`{"messages": [{"role": "user", "content": "Same message"}]}`) - - id1 := deriveSessionID(input) - id2 := deriveSessionID(input) - - if id1 != id2 { - t.Errorf("Session ID should be deterministic: '%s' != '%s'", id1, id2) - } -} - -func TestDeriveSessionIDFromRequest_DifferentMessages(t *testing.T) { - input1 := []byte(`{"messages": [{"role": "user", "content": "Message A"}]}`) - input2 := []byte(`{"messages": [{"role": "user", "content": "Message B"}]}`) - - id1 := deriveSessionID(input1) - id2 := deriveSessionID(input2) - - if id1 == id2 { - t.Error("Different messages should produce different session IDs") - } -}