package executor import ( "context" "encoding/json" "io" "testing" cliproxyauth "github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/auth") func TestAntigravityBuildRequest_SanitizesGeminiToolSchema(t *testing.T) { body := buildRequestBodyFromPayload(t, "gemini-2.5-pro") decl := extractFirstFunctionDeclaration(t, body) if _, ok := decl["parametersJsonSchema"]; ok { t.Fatalf("parametersJsonSchema should be renamed to parameters") } params, ok := decl["parameters"].(map[string]any) if !ok { t.Fatalf("parameters missing or invalid type") } assertSchemaSanitizedAndPropertyPreserved(t, params)} func TestAntigravityBuildRequest_SanitizesAntigravityToolSchema(t *testing.T) { body := buildRequestBodyFromPayload(t, "claude-opus-4-6") decl := extractFirstFunctionDeclaration(t, body) params, ok := decl["parameters"].(map[string]any) if !ok { t.Fatalf("parameters missing or invalid type") } assertSchemaSanitizedAndPropertyPreserved(t, params)} func buildRequestBodyFromPayload(t *testing.T, modelName string) map[string]any { t.Helper() executor := &AntigravityExecutor{} auth := &cliproxyauth.Auth{} payload := []byte(`{ "request": { "tools": [ { "function_declarations": [ { "name": "tool_1", "parametersJsonSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "$id": "root-schema", "type": "object", "properties": { "$id": {"type": "string"}, "arg": { "type": "object", "prefill": "hello", "properties": { "mode": { "type": "string", "deprecated": true, "enum": ["a", "b"], "enumTitles": ["A", "B"] } } } }, "patternProperties": { "^x-": {"type": "string"} } } } ] } ] } }`) req, err := executor.buildRequest(context.Background(), auth, "token", modelName, payload, false, "", "https://example.com") if err != nil { t.Fatalf("buildRequest error: %v", err) } raw, err := io.ReadAll(req.Body) if err != nil { t.Fatalf("read request body error: %v", err) } var body map[string]any if err := json.Unmarshal(raw, &body); err != nil { t.Fatalf("unmarshal request body error: %v, body=%s", err, string(raw)) } return body} func extractFirstFunctionDeclaration(t *testing.T, body map[string]any) map[string]any { t.Helper() request, ok := body["request"].(map[string]any) if !ok { t.Fatalf("request missing or invalid type") } tools, ok := request["tools"].([]any) if !ok || len(tools) == 0 { t.Fatalf("tools missing or empty") } tool, ok := tools[0].(map[string]any) if !ok { t.Fatalf("first tool invalid type") } decls, ok := tool["function_declarations"].([]any) if !ok || len(decls) == 0 { t.Fatalf("function_declarations missing or empty") } decl, ok := decls[0].(map[string]any) if !ok { t.Fatalf("first function declaration invalid type") } return decl} func assertSchemaSanitizedAndPropertyPreserved(t *testing.T, params map[string]any) { t.Helper() if _, ok := params["$id"]; ok { t.Fatalf("root $id should be removed from schema") } if _, ok := params["patternProperties"]; ok { t.Fatalf("patternProperties should be removed from schema") } props, ok := params["properties"].(map[string]any) if !ok { t.Fatalf("properties missing or invalid type") } if _, ok := props["$id"]; !ok { t.Fatalf("property named $id should be preserved") } arg, ok := props["arg"].(map[string]any) if !ok { t.Fatalf("arg property missing or invalid type") } if _, ok := arg["prefill"]; ok { t.Fatalf("prefill should be removed from nested schema") } argProps, ok := arg["properties"].(map[string]any) if !ok { t.Fatalf("arg.properties missing or invalid type") } mode, ok := argProps["mode"].(map[string]any) if !ok { t.Fatalf("mode property missing or invalid type") } if _, ok := mode["enumTitles"]; ok { t.Fatalf("enumTitles should be removed from nested schema") } if _, ok := mode["deprecated"]; ok { t.Fatalf("deprecated should be removed from nested schema") }}
package executor
import (
"context"
"encoding/json"
"io"
"testing"
cliproxyauth "github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/auth"
)
func TestAntigravityBuildRequest_SanitizesGeminiToolSchema(t *testing.T) {
body := buildRequestBodyFromPayload(t, "gemini-2.5-pro")
decl := extractFirstFunctionDeclaration(t, body)
if _, ok := decl["parametersJsonSchema"]; ok {
t.Fatalf("parametersJsonSchema should be renamed to parameters")
}
params, ok := decl["parameters"].(map[string]any)
if !ok {
t.Fatalf("parameters missing or invalid type")
}
assertSchemaSanitizedAndPropertyPreserved(t, params)
}
func TestAntigravityBuildRequest_SanitizesAntigravityToolSchema(t *testing.T) {
body := buildRequestBodyFromPayload(t, "claude-opus-4-6")
decl := extractFirstFunctionDeclaration(t, body)
params, ok := decl["parameters"].(map[string]any)
if !ok {
t.Fatalf("parameters missing or invalid type")
}
assertSchemaSanitizedAndPropertyPreserved(t, params)
}
func buildRequestBodyFromPayload(t *testing.T, modelName string) map[string]any {
t.Helper()
executor := &AntigravityExecutor{}
auth := &cliproxyauth.Auth{}
payload := []byte(`{
"request": {
"tools": [
{
"function_declarations": [
{
"name": "tool_1",
"parametersJsonSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "root-schema",
"type": "object",
"properties": {
"$id": {"type": "string"},
"arg": {
"type": "object",
"prefill": "hello",
"properties": {
"mode": {
"type": "string",
"deprecated": true,
"enum": ["a", "b"],
"enumTitles": ["A", "B"]
}
}
}
},
"patternProperties": {
"^x-": {"type": "string"}
}
}
}
]
}
]
}
}`)
req, err := executor.buildRequest(context.Background(), auth, "token", modelName, payload, false, "", "https://example.com")
if err != nil {
t.Fatalf("buildRequest error: %v", err)
}
raw, err := io.ReadAll(req.Body)
if err != nil {
t.Fatalf("read request body error: %v", err)
}
var body map[string]any
if err := json.Unmarshal(raw, &body); err != nil {
t.Fatalf("unmarshal request body error: %v, body=%s", err, string(raw))
}
return body
}
func extractFirstFunctionDeclaration(t *testing.T, body map[string]any) map[string]any {
t.Helper()
request, ok := body["request"].(map[string]any)
if !ok {
t.Fatalf("request missing or invalid type")
}
tools, ok := request["tools"].([]any)
if !ok || len(tools) == 0 {
t.Fatalf("tools missing or empty")
}
tool, ok := tools[0].(map[string]any)
if !ok {
t.Fatalf("first tool invalid type")
}
decls, ok := tool["function_declarations"].([]any)
if !ok || len(decls) == 0 {
t.Fatalf("function_declarations missing or empty")
}
decl, ok := decls[0].(map[string]any)
if !ok {
t.Fatalf("first function declaration invalid type")
}
return decl
}
func assertSchemaSanitizedAndPropertyPreserved(t *testing.T, params map[string]any) {
t.Helper()
if _, ok := params["$id"]; ok {
t.Fatalf("root $id should be removed from schema")
}
if _, ok := params["patternProperties"]; ok {
t.Fatalf("patternProperties should be removed from schema")
}
props, ok := params["properties"].(map[string]any)
if !ok {
t.Fatalf("properties missing or invalid type")
}
if _, ok := props["$id"]; !ok {
t.Fatalf("property named $id should be preserved")
}
arg, ok := props["arg"].(map[string]any)
if !ok {
t.Fatalf("arg property missing or invalid type")
}
if _, ok := arg["prefill"]; ok {
t.Fatalf("prefill should be removed from nested schema")
}
argProps, ok := arg["properties"].(map[string]any)
if !ok {
t.Fatalf("arg.properties missing or invalid type")
}
mode, ok := argProps["mode"].(map[string]any)
if !ok {
t.Fatalf("mode property missing or invalid type")
}
if _, ok := mode["enumTitles"]; ok {
t.Fatalf("enumTitles should be removed from nested schema")
}
if _, ok := mode["deprecated"]; ok {
t.Fatalf("deprecated should be removed from nested schema")
}
}