diff --git a/internal/translator/codex/gemini-cli/codex_gemini-cli_request_test.go b/internal/translator/codex/gemini-cli/codex_gemini-cli_request_test.go new file mode 100644 index 000000000..fc41452b1 --- /dev/null +++ b/internal/translator/codex/gemini-cli/codex_gemini-cli_request_test.go @@ -0,0 +1,78 @@ +package geminiCLI + +import ( + "testing" + + "github.com/tidwall/gjson" +) + +func TestConvertGeminiCLIRequestToCodex_PreservesSchemaPropertyNamedType(t *testing.T) { + input := []byte(`{ + "request": { + "tools": [ + { + "functionDeclarations": [ + { + "name": "ask_user", + "description": "Ask the user one or more questions.", + "parametersJsonSchema": { + "type": "object", + "properties": { + "questions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "header": { + "type": "string" + }, + "type": { + "default": "choice", + "description": "Question type.", + "enum": [ + "choice", + "text", + "yesno" + ], + "type": "string" + } + }, + "required": [ + "question", + "header", + "type" + ] + } + } + }, + "required": [ + "questions" + ] + } + } + ] + } + ] + } + }`) + + out := ConvertGeminiCLIRequestToCodex("gpt-5.2", input, true) + tool := gjson.GetBytes(out, "tools.0") + if got := tool.Get("type").String(); got != "function" { + t.Fatalf("expected tool type %q, got %q; output=%s", "function", got, string(out)) + } + + typeProperty := tool.Get("parameters.properties.questions.items.properties.type") + if !typeProperty.IsObject() { + t.Fatalf("expected schema property named type to stay an object; output=%s", string(out)) + } + if got := typeProperty.Get("type").String(); got != "string" { + t.Fatalf("expected schema property type %q, got %q; output=%s", "string", got, string(out)) + } + if got := typeProperty.Get("default").String(); got != "choice" { + t.Fatalf("expected default %q, got %q; output=%s", "choice", got, string(out)) + } + if got := typeProperty.Get("enum.2").String(); got != "yesno" { + t.Fatalf("expected enum value %q, got %q; output=%s", "yesno", got, string(out)) + } +} diff --git a/internal/translator/codex/gemini/codex_gemini_request.go b/internal/translator/codex/gemini/codex_gemini_request.go index 23dae7d71..373997007 100644 --- a/internal/translator/codex/gemini/codex_gemini_request.go +++ b/internal/translator/codex/gemini/codex_gemini_request.go @@ -284,7 +284,11 @@ func ConvertGeminiRequestToCodex(modelName string, inputRawJSON []byte, _ bool) util.Walk(toolsResult, "", "type", &pathsToLower) for _, p := range pathsToLower { fullPath := fmt.Sprintf("tools.%s", p) - out, _ = sjson.SetBytes(out, fullPath, strings.ToLower(gjson.GetBytes(out, fullPath).String())) + typeValue := gjson.GetBytes(out, fullPath) + if typeValue.Type != gjson.String { + continue + } + out, _ = sjson.SetBytes(out, fullPath, strings.ToLower(typeValue.String())) } return out