Compare commits

..

3 Commits

Author SHA1 Message Date
Luis Pater 4e572ec8b9 fix(translators): handle string system instructions in Claude translators
docker-image / docker (push) Has been cancelled
goreleaser / goreleaser (push) Has been cancelled
Updated Antigravity, Gemini, and Gemini-CLI translators to process `systemResult` of type `string` for system instructions. Ensures properly formatted JSON with dynamic content assignment.
2025-12-23 08:44:36 +08:00
Luis Pater 24bc9cba67 Fixed: #639
docker-image / docker (push) Has been cancelled
goreleaser / goreleaser (push) Has been cancelled
fix(antigravity): validate function arguments before serialization

Ensure `function.arguments` is a valid JSON before setting raw bytes, fallback to setting as parameterized content if invalid.
2025-12-23 03:49:45 +08:00
Luis Pater 1084b53fba Fixed: #655
docker-image / docker (push) Has been cancelled
goreleaser / goreleaser (push) Has been cancelled
refactor(antigravity): clean up tool key filtering and improve signature caching logic
2025-12-23 03:16:51 +08:00
4 changed files with 41 additions and 27 deletions
@@ -86,6 +86,10 @@ func ConvertClaudeRequestToAntigravity(modelName string, inputRawJSON []byte, _
hasSystemInstruction = true hasSystemInstruction = true
} }
} }
} else if systemResult.Type == gjson.String {
systemInstructionJSON = `{"role":"user","parts":[{"text":""}]}`
systemInstructionJSON, _ = sjson.Set(systemInstructionJSON, "parts.0.text", systemResult.String())
hasSystemInstruction = true
} }
// contents // contents
@@ -121,32 +125,31 @@ func ConvertClaudeRequestToAntigravity(modelName string, inputRawJSON []byte, _
// Use GetThinkingText to handle wrapped thinking objects // Use GetThinkingText to handle wrapped thinking objects
thinkingText := util.GetThinkingText(contentResult) thinkingText := util.GetThinkingText(contentResult)
signatureResult := contentResult.Get("signature") signatureResult := contentResult.Get("signature")
clientSignature := "" clientSignature := ""
if signatureResult.Exists() && signatureResult.String() != "" { if signatureResult.Exists() && signatureResult.String() != "" {
clientSignature = signatureResult.String() clientSignature = signatureResult.String()
}
// 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 cachedSig := cache.GetCachedSignature(sessionID, thinkingText); cachedSig != "" {
signature = cachedSig
log.Debugf("Using cached signature for thinking block")
} }
}
// Fallback to client signature only if cache miss and client signature is valid // Always try cached signature first (more reliable than client-provided)
if signature == "" && cache.HasValidSignature(clientSignature) { // Client may send stale or invalid signatures from different sessions
signature = clientSignature signature := ""
log.Debugf("Using client-provided signature for thinking block") if sessionID != "" && thinkingText != "" {
} if cachedSig := cache.GetCachedSignature(sessionID, thinkingText); cachedSig != "" {
signature = cachedSig
log.Debugf("Using cached signature for thinking block")
}
}
// Store for subsequent tool_use in the same message // Fallback to client signature only if cache miss and client signature is valid
if cache.HasValidSignature(signature) { if signature == "" && cache.HasValidSignature(clientSignature) {
currentMessageThinkingSignature = signature signature = clientSignature
} log.Debugf("Using client-provided signature for thinking block")
}
// Store for subsequent tool_use in the same message
if cache.HasValidSignature(signature) {
currentMessageThinkingSignature = signature
}
// Skip trailing unsigned thinking blocks on last assistant message // Skip trailing unsigned thinking blocks on last assistant message
isUnsigned := !cache.HasValidSignature(signature) isUnsigned := !cache.HasValidSignature(signature)
@@ -321,6 +324,7 @@ func ConvertClaudeRequestToAntigravity(modelName string, inputRawJSON []byte, _
// tools // tools
toolsJSON := "" toolsJSON := ""
toolDeclCount := 0 toolDeclCount := 0
allowedToolKeys := []string{"name", "description", "behavior", "parameters", "parametersJsonSchema", "response", "responseJsonSchema"}
toolsResult := gjson.GetBytes(rawJSON, "tools") toolsResult := gjson.GetBytes(rawJSON, "tools")
if toolsResult.IsArray() { if toolsResult.IsArray() {
toolsJSON = `[{"functionDeclarations":[]}]` toolsJSON = `[{"functionDeclarations":[]}]`
@@ -333,10 +337,12 @@ func ConvertClaudeRequestToAntigravity(modelName string, inputRawJSON []byte, _
inputSchema := util.CleanJSONSchemaForAntigravity(inputSchemaResult.Raw) inputSchema := util.CleanJSONSchemaForAntigravity(inputSchemaResult.Raw)
tool, _ := sjson.Delete(toolResult.Raw, "input_schema") tool, _ := sjson.Delete(toolResult.Raw, "input_schema")
tool, _ = sjson.SetRaw(tool, "parametersJsonSchema", inputSchema) tool, _ = sjson.SetRaw(tool, "parametersJsonSchema", inputSchema)
tool, _ = sjson.Delete(tool, "strict") for toolKey := range gjson.Parse(tool).Map() {
tool, _ = sjson.Delete(tool, "input_examples") if util.InArray(allowedToolKeys, toolKey) {
tool, _ = sjson.Delete(tool, "type") continue
tool, _ = sjson.Delete(tool, "cache_control") }
tool, _ = sjson.Delete(tool, toolKey)
}
toolsJSON, _ = sjson.SetRaw(toolsJSON, "0.functionDeclarations.-1", tool) toolsJSON, _ = sjson.SetRaw(toolsJSON, "0.functionDeclarations.-1", tool)
toolDeclCount++ toolDeclCount++
} }
@@ -266,7 +266,11 @@ func ConvertOpenAIRequestToAntigravity(modelName string, inputRawJSON []byte, _
fargs := tc.Get("function.arguments").String() fargs := tc.Get("function.arguments").String()
node, _ = sjson.SetBytes(node, "parts."+itoa(p)+".functionCall.id", fid) node, _ = sjson.SetBytes(node, "parts."+itoa(p)+".functionCall.id", fid)
node, _ = sjson.SetBytes(node, "parts."+itoa(p)+".functionCall.name", fname) node, _ = sjson.SetBytes(node, "parts."+itoa(p)+".functionCall.name", fname)
node, _ = sjson.SetRawBytes(node, "parts."+itoa(p)+".functionCall.args", []byte(fargs)) if gjson.Valid(fargs) {
node, _ = sjson.SetRawBytes(node, "parts."+itoa(p)+".functionCall.args", []byte(fargs))
} else {
node, _ = sjson.SetBytes(node, "parts."+itoa(p)+".functionCall.args.params", []byte(fargs))
}
node, _ = sjson.SetBytes(node, "parts."+itoa(p)+".thoughtSignature", geminiCLIFunctionThoughtSignature) node, _ = sjson.SetBytes(node, "parts."+itoa(p)+".thoughtSignature", geminiCLIFunctionThoughtSignature)
p++ p++
if fid != "" { if fid != "" {
@@ -62,6 +62,8 @@ func ConvertClaudeRequestToCLI(modelName string, inputRawJSON []byte, _ bool) []
if hasSystemParts { if hasSystemParts {
out, _ = sjson.SetRaw(out, "request.systemInstruction", systemInstruction) out, _ = sjson.SetRaw(out, "request.systemInstruction", systemInstruction)
} }
} else if systemResult.Type == gjson.String {
out, _ = sjson.Set(out, "request.systemInstruction.parts.-1.text", systemResult.String())
} }
// contents // contents
@@ -55,6 +55,8 @@ func ConvertClaudeRequestToGemini(modelName string, inputRawJSON []byte, _ bool)
if hasSystemParts { if hasSystemParts {
out, _ = sjson.SetRaw(out, "system_instruction", systemInstruction) out, _ = sjson.SetRaw(out, "system_instruction", systemInstruction)
} }
} else if systemResult.Type == gjson.String {
out, _ = sjson.Set(out, "request.system_instruction.parts.-1.text", systemResult.String())
} }
// contents // contents