From 41ae2c81e7543405de48cba40f1c095a83f16715 Mon Sep 17 00:00:00 2001 From: sususu98 Date: Mon, 13 Apr 2026 17:38:43 +0800 Subject: [PATCH] fix(antigravity): discard thinking blocks with non-Claude-format signatures Proxy-generated thinking blocks may carry hex hashes or other non-Claude signatures (e.g. "d5cb9cd0823142109f451861") from Gemini responses. These are now discarded alongside empty-signature blocks during the strip phase, before validation runs. Valid Claude signatures always start with 'E' or 'R' (after stripping any cache prefix). --- .../claude/signature_validation.go | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/internal/translator/antigravity/claude/signature_validation.go b/internal/translator/antigravity/claude/signature_validation.go index f4fef08c6..63203abdc 100644 --- a/internal/translator/antigravity/claude/signature_validation.go +++ b/internal/translator/antigravity/claude/signature_validation.go @@ -73,9 +73,10 @@ type claudeSignatureTree struct { HasField7 bool } -// StripEmptySignatureThinkingBlocks removes thinking blocks with empty signatures -// from messages[].content[]. These come from proxy-generated responses (Antigravity/Gemini) -// where no real Claude signature exists. +// StripInvalidSignatureThinkingBlocks removes thinking blocks whose signatures +// are empty or not valid Claude format (must start with 'E' or 'R' after +// stripping any cache prefix). These come from proxy-generated responses +// (Antigravity/Gemini) where no real Claude signature exists. func StripEmptySignatureThinkingBlocks(payload []byte) []byte { messages := gjson.GetBytes(payload, "messages") if !messages.IsArray() { @@ -90,7 +91,7 @@ func StripEmptySignatureThinkingBlocks(payload []byte) []byte { var kept []string stripped := false for _, part := range content.Array() { - if part.Get("type").String() == "thinking" && strings.TrimSpace(part.Get("signature").String()) == "" { + if part.Get("type").String() == "thinking" && !hasValidClaudeSignature(part.Get("signature").String()) { stripped = true continue } @@ -111,6 +112,23 @@ func StripEmptySignatureThinkingBlocks(payload []byte) []byte { return payload } +// hasValidClaudeSignature returns true if sig looks like a real Claude thinking +// signature: non-empty and starts with 'E' or 'R' (after stripping optional +// cache prefix like "modelGroup#"). +func hasValidClaudeSignature(sig string) bool { + sig = strings.TrimSpace(sig) + if sig == "" { + return false + } + if idx := strings.IndexByte(sig, '#'); idx >= 0 { + sig = strings.TrimSpace(sig[idx+1:]) + } + if sig == "" { + return false + } + return sig[0] == 'E' || sig[0] == 'R' +} + func ValidateClaudeBypassSignatures(inputRawJSON []byte) error { messages := gjson.GetBytes(inputRawJSON, "messages") if !messages.IsArray() {