From be2dd60ee74f7914229eb946864fc38a903259a1 Mon Sep 17 00:00:00 2001 From: Junyi Du Date: Thu, 19 Mar 2026 03:23:14 +0800 Subject: [PATCH] fix: normalize web_search_preview for codex responses --- .../codex_openai-responses_request.go | 24 +++++++++++++++++++ .../codex_openai-responses_request_test.go | 20 ++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/internal/translator/codex/openai/responses/codex_openai-responses_request.go b/internal/translator/codex/openai/responses/codex_openai-responses_request.go index 360c037f..fd9bf92d 100644 --- a/internal/translator/codex/openai/responses/codex_openai-responses_request.go +++ b/internal/translator/codex/openai/responses/codex_openai-responses_request.go @@ -39,6 +39,7 @@ func ConvertOpenAIResponsesRequestToCodex(modelName string, inputRawJSON []byte, // Convert role "system" to "developer" in input array to comply with Codex API requirements. rawJSON = convertSystemRoleToDeveloper(rawJSON) + rawJSON = normalizeCodexBuiltinTools(rawJSON) return rawJSON } @@ -82,3 +83,26 @@ func convertSystemRoleToDeveloper(rawJSON []byte) []byte { return result } + +// normalizeCodexBuiltinTools rewrites legacy/preview built-in tool variants to the +// stable names expected by the current Codex upstream. +func normalizeCodexBuiltinTools(rawJSON []byte) []byte { + result := rawJSON + + tools := gjson.GetBytes(result, "tools") + if tools.IsArray() { + toolArray := tools.Array() + for i := 0; i < len(toolArray); i++ { + typePath := fmt.Sprintf("tools.%d.type", i) + if gjson.GetBytes(result, typePath).String() == "web_search_preview" { + result, _ = sjson.SetBytes(result, typePath, "web_search") + } + } + } + + if gjson.GetBytes(result, "tool_choice.type").String() == "web_search_preview" { + result, _ = sjson.SetBytes(result, "tool_choice.type", "web_search") + } + + return result +} diff --git a/internal/translator/codex/openai/responses/codex_openai-responses_request_test.go b/internal/translator/codex/openai/responses/codex_openai-responses_request_test.go index a2ede1b8..49587c9b 100644 --- a/internal/translator/codex/openai/responses/codex_openai-responses_request_test.go +++ b/internal/translator/codex/openai/responses/codex_openai-responses_request_test.go @@ -264,6 +264,26 @@ func TestConvertSystemRoleToDeveloper_AssistantRole(t *testing.T) { } } +func TestConvertOpenAIResponsesRequestToCodex_NormalizesWebSearchPreview(t *testing.T) { + inputJSON := []byte(`{ + "model": "gpt-5.4-mini", + "input": "find latest OpenAI model news", + "tools": [ + {"type": "web_search_preview"} + ], + "tool_choice": {"type": "web_search_preview"} + }`) + + output := ConvertOpenAIResponsesRequestToCodex("gpt-5.4-mini", inputJSON, false) + + if got := gjson.GetBytes(output, "tools.0.type").String(); got != "web_search" { + t.Fatalf("tools.0.type = %q, want %q: %s", got, "web_search", string(output)) + } + if got := gjson.GetBytes(output, "tool_choice.type").String(); got != "web_search" { + t.Fatalf("tool_choice.type = %q, want %q: %s", got, "web_search", string(output)) + } +} + func TestUserFieldDeletion(t *testing.T) { inputJSON := []byte(`{ "model": "gpt-5.2",