test/gemini_ref_sibling_test.go
Rama main · réplica de lectura del repositorio original.
package test
import (
"testing"
_ "github.com/router-for-me/CLIProxyAPI/v8/internal/translator"
"github.com/MoeForge/moego/ojson"
sdktranslator "github.com/router-for-me/CLIProxyAPI/v8/sdk/translator"
)
func TestIssue6897_GeminiToolParametersPreserveRefSiblingConstraints(t *testing.T) {
schema := `{"$schema":"https://json-schema.org/draft/2020-12/schema","$defs":{"A":{"type":"string","minLength":5}},"type":"object","properties":{"x":{"$ref":"#/$defs/A","minLength":1}}}`
cases := []struct {
name string
format sdktranslator.Format
body string
}{
{
name: "chat_completions", format: sdktranslator.FormatOpenAI,
body: `{"messages":[{"role":"user","content":"test"}],"tools":[{"type":"function","function":{"name":"check","parameters":` + schema + `}}]}`,
},
{
name: "responses", format: sdktranslator.FormatOpenAIResponse,
body: `{"input":"test","tools":[{"type":"function","name":"check","parameters":` + schema + `}]}`,
},
{
name: "claude", format: sdktranslator.FormatClaude,
body: `{"messages":[{"role":"user","content":"test"}],"tools":[{"name":"check","input_schema":` + schema + `}]}`,
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
out := sdktranslator.TranslateRequest(tc.format, sdktranslator.FormatGemini, "gemini-3-flash", []byte(tc.body), false)
parameters := ojson.GetBytesNoCopy(out, "tools.0.functionDeclarations.0.parametersJsonSchema")
if parameters.Get("properties.x.allOf.0.minLength").Int() != 5 || parameters.Get("properties.x.minLength").Int() != 1 {
t.Fatalf("translated tool parameters lost the reference conjunction: %s", out)
}
if parameters.Get("$defs").Exists() || parameters.Get("properties.x.$ref").Exists() {
t.Fatalf("local reference was not fully expanded: %s", out)
}
})
}
}
func TestIssue7149_GeminiToolParametersNumericConstraintsNormalizedAcrossTargets(t *testing.T) {
geminiBody := `{
"contents":[{"role":"user","parts":[{"text":"hi"}]}],
"tools":[{
"functionDeclarations":[{
"name":"run_command",
"description":"Run a command",
"parameters":{
"type":"OBJECT",
"minProperties":"1",
"maxProperties":"10",
"properties":{
"Message":{
"type":"STRING",
"minLength":"1",
"maxLength":"200",
"enum":["1","2"],
"default":"1"
},
"Items":{
"type":"ARRAY",
"minItems":"1",
"maxItems":"5",
"items":{"type":"STRING","minLength":"2"}
}
}
}
}]
}]
}`
targets := []struct {
name string
to sdktranslator.Format
schemaPath string
}{
{"gemini", sdktranslator.FormatGemini, "tools.0.function_declarations.0.parametersJsonSchema"},
{"antigravity", sdktranslator.FormatAntigravity, "request.tools.0.functionDeclarations.0.parametersJsonSchema"},
{"openai", sdktranslator.FormatOpenAI, "tools.0.function.parameters"},
{"claude", sdktranslator.FormatClaude, "tools.0.input_schema"},
{"codex", sdktranslator.FormatCodex, "tools.0.parameters"},
{"interactions", sdktranslator.FormatInteractions, "tools.0.parameters"},
}
for _, tc := range targets {
t.Run(tc.name, func(t *testing.T) {
out := sdktranslator.TranslateRequest(sdktranslator.FormatGemini, tc.to, "gemini-2.5-pro", []byte(geminiBody), false)
schema := ojson.GetBytesNoCopy(out, tc.schemaPath)
if !schema.Exists() {
t.Fatalf("expected schema at %s, got: %s", tc.schemaPath, out)
}
for _, check := range []struct {
path string
want int64
}{
{"minProperties", 1},
{"maxProperties", 10},
{"properties.Message.minLength", 1},
{"properties.Message.maxLength", 200},
{"properties.Items.minItems", 1},
{"properties.Items.maxItems", 5},
{"properties.Items.items.minLength", 2},
} {
got := schema.Get(check.path)
if got.Type != ojson.Number || got.Int() != check.want {
t.Errorf("[%s] %s = %s (type %v), want number %d; schema=%s", tc.name, check.path, got.Raw, got.Type, check.want, schema.Raw)
}
}
if got := schema.Get("properties.Message.enum.0"); got.Type != ojson.String || got.String() != "1" {
t.Errorf("[%s] enum.0 = %s (type %v), want string \"1\"", tc.name, got.Raw, got.Type)
}
if got := schema.Get("properties.Message.default"); got.Type != ojson.String || got.String() != "1" {
t.Errorf("[%s] default = %s (type %v), want string \"1\"", tc.name, got.Raw, got.Type)
}
})
}
}