feat(antigravity): add function ID to FunctionCall and FunctionResponse models

This commit is contained in:
Luis Pater
2025-12-05 23:05:35 +08:00
parent d28258501a
commit 412148af0e
6 changed files with 44 additions and 30 deletions

View File

@@ -85,6 +85,9 @@ type InlineData struct {
// FunctionCall represents a tool call requested by the model. // FunctionCall represents a tool call requested by the model.
// It includes the function name and its arguments that the model wants to execute. // It includes the function name and its arguments that the model wants to execute.
type FunctionCall struct { type FunctionCall struct {
// ID is the identifier of the function to be called.
ID string `json:"id,omitempty"`
// Name is the identifier of the function to be called. // Name is the identifier of the function to be called.
Name string `json:"name"` Name string `json:"name"`
@@ -95,6 +98,9 @@ type FunctionCall struct {
// FunctionResponse represents the result of a tool execution. // FunctionResponse represents the result of a tool execution.
// This is sent back to the model after a tool call has been processed. // This is sent back to the model after a tool call has been processed.
type FunctionResponse struct { type FunctionResponse struct {
// ID is the identifier of the function to be called.
ID string `json:"id,omitempty"`
// Name is the identifier of the function that was called. // Name is the identifier of the function that was called.
Name string `json:"name"` Name string `json:"name"`

View File

@@ -89,10 +89,11 @@ func ConvertClaudeRequestToAntigravity(modelName string, inputRawJSON []byte, _
} else if contentTypeResult.Type == gjson.String && contentTypeResult.String() == "tool_use" { } else if contentTypeResult.Type == gjson.String && contentTypeResult.String() == "tool_use" {
functionName := contentResult.Get("name").String() functionName := contentResult.Get("name").String()
functionArgs := contentResult.Get("input").String() functionArgs := contentResult.Get("input").String()
functionID := contentResult.Get("id").String()
var args map[string]any var args map[string]any
if err := json.Unmarshal([]byte(functionArgs), &args); err == nil { if err := json.Unmarshal([]byte(functionArgs), &args); err == nil {
clientContent.Parts = append(clientContent.Parts, client.Part{ clientContent.Parts = append(clientContent.Parts, client.Part{
FunctionCall: &client.FunctionCall{Name: functionName, Args: args}, FunctionCall: &client.FunctionCall{ID: functionID, Name: functionName, Args: args},
ThoughtSignature: geminiCLIClaudeThoughtSignature, ThoughtSignature: geminiCLIClaudeThoughtSignature,
}) })
} }
@@ -105,7 +106,7 @@ func ConvertClaudeRequestToAntigravity(modelName string, inputRawJSON []byte, _
funcName = strings.Join(toolCallIDs[0:len(toolCallIDs)-1], "-") funcName = strings.Join(toolCallIDs[0:len(toolCallIDs)-1], "-")
} }
responseData := contentResult.Get("content").Raw responseData := contentResult.Get("content").Raw
functionResponse := client.FunctionResponse{Name: funcName, Response: map[string]interface{}{"result": responseData}} functionResponse := client.FunctionResponse{ID: toolCallID, Name: funcName, Response: map[string]interface{}{"result": responseData}}
clientContent.Parts = append(clientContent.Parts, client.Part{FunctionResponse: &functionResponse}) clientContent.Parts = append(clientContent.Parts, client.Part{FunctionResponse: &functionResponse})
} }
} }

View File

@@ -141,6 +141,8 @@ func ConvertAntigravityResponseToClaude(_ context.Context, _ string, originalReq
params.ResponseType = 2 // Set state to thinking params.ResponseType = 2 // Set state to thinking
} }
} else { } else {
finishReasonResult := gjson.GetBytes(rawJSON, "response.candidates.0.finishReason")
if partTextResult.String() != "" || !finishReasonResult.Exists() {
// Process regular text content (user-visible output) // Process regular text content (user-visible output)
// Continue existing text block if already in content state // Continue existing text block if already in content state
if params.ResponseType == 1 { if params.ResponseType == 1 {
@@ -172,6 +174,7 @@ func ConvertAntigravityResponseToClaude(_ context.Context, _ string, originalReq
params.ResponseType = 1 // Set state to content params.ResponseType = 1 // Set state to content
} }
} }
}
} else if functionCallResult.Exists() { } else if functionCallResult.Exists() {
// Handle function/tool calls from the AI model // Handle function/tool calls from the AI model
// This processes tool usage requests and formats them for Claude Code API compatibility // This processes tool usage requests and formats them for Claude Code API compatibility

View File

@@ -251,6 +251,7 @@ func ConvertOpenAIRequestToAntigravity(modelName string, inputRawJSON []byte, _
fid := tc.Get("id").String() fid := tc.Get("id").String()
fname := tc.Get("function.name").String() fname := tc.Get("function.name").String()
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.name", fname) node, _ = sjson.SetBytes(node, "parts."+itoa(p)+".functionCall.name", fname)
node, _ = sjson.SetRawBytes(node, "parts."+itoa(p)+".functionCall.args", []byte(fargs)) node, _ = sjson.SetRawBytes(node, "parts."+itoa(p)+".functionCall.args", []byte(fargs))
node, _ = sjson.SetBytes(node, "parts."+itoa(p)+".thoughtSignature", geminiCLIFunctionThoughtSignature) node, _ = sjson.SetBytes(node, "parts."+itoa(p)+".thoughtSignature", geminiCLIFunctionThoughtSignature)
@@ -266,6 +267,7 @@ func ConvertOpenAIRequestToAntigravity(modelName string, inputRawJSON []byte, _
pp := 0 pp := 0
for _, fid := range fIDs { for _, fid := range fIDs {
if name, ok := tcID2Name[fid]; ok { if name, ok := tcID2Name[fid]; ok {
toolNode, _ = sjson.SetBytes(toolNode, "parts."+itoa(pp)+".functionResponse.id", fid)
toolNode, _ = sjson.SetBytes(toolNode, "parts."+itoa(pp)+".functionResponse.name", name) toolNode, _ = sjson.SetBytes(toolNode, "parts."+itoa(pp)+".functionResponse.name", name)
resp := toolResponses[fid] resp := toolResponses[fid]
if resp == "" { if resp == "" {

View File

@@ -327,7 +327,7 @@ func buildReverseMapFromGeminiOriginal(original []byte) map[string]string {
func mustMarshalJSON(v interface{}) string { func mustMarshalJSON(v interface{}) string {
data, err := json.Marshal(v) data, err := json.Marshal(v)
if err != nil { if err != nil {
panic(err) return ""
} }
return string(data) return string(data)
} }

View File

@@ -249,6 +249,7 @@ func ConvertOpenAIResponsesRequestToGemini(modelName string, inputRawJSON []byte
functionCall := `{"functionCall":{"name":"","args":{}}}` functionCall := `{"functionCall":{"name":"","args":{}}}`
functionCall, _ = sjson.Set(functionCall, "functionCall.name", name) functionCall, _ = sjson.Set(functionCall, "functionCall.name", name)
functionCall, _ = sjson.Set(functionCall, "thoughtSignature", geminiResponsesThoughtSignature) functionCall, _ = sjson.Set(functionCall, "thoughtSignature", geminiResponsesThoughtSignature)
functionCall, _ = sjson.Set(functionCall, "functionCall.id", item.Get("call_id").String())
// Parse arguments JSON string and set as args object // Parse arguments JSON string and set as args object
if arguments != "" { if arguments != "" {
@@ -285,6 +286,7 @@ func ConvertOpenAIResponsesRequestToGemini(modelName string, inputRawJSON []byte
} }
functionResponse, _ = sjson.Set(functionResponse, "functionResponse.name", functionName) functionResponse, _ = sjson.Set(functionResponse, "functionResponse.name", functionName)
functionResponse, _ = sjson.Set(functionResponse, "functionResponse.id", callID)
// Set the raw JSON output directly (preserves string encoding) // Set the raw JSON output directly (preserves string encoding)
if outputRaw != "" && outputRaw != "null" { if outputRaw != "" && outputRaw != "null" {