From 19e1a4447a83f5791d371ecda857ece8bef4da84 Mon Sep 17 00:00:00 2001 From: Darley Date: Tue, 17 Mar 2026 19:17:41 +0800 Subject: [PATCH 1/2] fix(claude): honor disable_parallel_tool_use --- .../codex/claude/codex_claude_request.go | 8 +++- .../codex/claude/codex_claude_request_test.go | 46 +++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/internal/translator/codex/claude/codex_claude_request.go b/internal/translator/codex/claude/codex_claude_request.go index 4bc116b9f..a9ed46b01 100644 --- a/internal/translator/codex/claude/codex_claude_request.go +++ b/internal/translator/codex/claude/codex_claude_request.go @@ -271,8 +271,14 @@ func ConvertClaudeRequestToCodex(modelName string, inputRawJSON []byte, _ bool) } } + // Default to parallel tool calls unless the client explicitly disables them. + parallelToolCalls := true + if disableParallelToolUse := rootResult.Get("disable_parallel_tool_use"); disableParallelToolUse.Exists() { + parallelToolCalls = !disableParallelToolUse.Bool() + } + // Add additional configuration parameters for the Codex API. - template, _ = sjson.Set(template, "parallel_tool_calls", true) + template, _ = sjson.Set(template, "parallel_tool_calls", parallelToolCalls) // Convert thinking.budget_tokens to reasoning.effort. reasoningEffort := "medium" diff --git a/internal/translator/codex/claude/codex_claude_request_test.go b/internal/translator/codex/claude/codex_claude_request_test.go index bdd41639c..aba1ef981 100644 --- a/internal/translator/codex/claude/codex_claude_request_test.go +++ b/internal/translator/codex/claude/codex_claude_request_test.go @@ -87,3 +87,49 @@ func TestConvertClaudeRequestToCodex_SystemMessageScenarios(t *testing.T) { }) } } + +func TestConvertClaudeRequestToCodex_ParallelToolCalls(t *testing.T) { + tests := []struct { + name string + inputJSON string + wantParallelToolCalls bool + }{ + { + name: "Default to true when disable_parallel_tool_use is absent", + inputJSON: `{ + "model": "claude-3-opus", + "messages": [{"role": "user", "content": "hello"}] + }`, + wantParallelToolCalls: true, + }, + { + name: "Disable parallel tool calls when client opts out", + inputJSON: `{ + "model": "claude-3-opus", + "disable_parallel_tool_use": true, + "messages": [{"role": "user", "content": "hello"}] + }`, + wantParallelToolCalls: false, + }, + { + name: "Keep parallel tool calls enabled when client explicitly allows them", + inputJSON: `{ + "model": "claude-3-opus", + "disable_parallel_tool_use": false, + "messages": [{"role": "user", "content": "hello"}] + }`, + wantParallelToolCalls: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := ConvertClaudeRequestToCodex("test-model", []byte(tt.inputJSON), false) + resultJSON := gjson.ParseBytes(result) + + if got := resultJSON.Get("parallel_tool_calls").Bool(); got != tt.wantParallelToolCalls { + t.Fatalf("parallel_tool_calls = %v, want %v. Output: %s", got, tt.wantParallelToolCalls, string(result)) + } + }) + } +} From 9c6c3612a890d86652aac79055a1e30e2d9c5d75 Mon Sep 17 00:00:00 2001 From: Darley Date: Tue, 17 Mar 2026 19:35:41 +0800 Subject: [PATCH 2/2] fix(claude): read disable_parallel_tool_use from tool_choice --- internal/translator/codex/claude/codex_claude_request.go | 4 ++-- .../translator/codex/claude/codex_claude_request_test.go | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/translator/codex/claude/codex_claude_request.go b/internal/translator/codex/claude/codex_claude_request.go index a9ed46b01..e873dddc3 100644 --- a/internal/translator/codex/claude/codex_claude_request.go +++ b/internal/translator/codex/claude/codex_claude_request.go @@ -271,9 +271,9 @@ func ConvertClaudeRequestToCodex(modelName string, inputRawJSON []byte, _ bool) } } - // Default to parallel tool calls unless the client explicitly disables them. + // Default to parallel tool calls unless tool_choice explicitly disables them. parallelToolCalls := true - if disableParallelToolUse := rootResult.Get("disable_parallel_tool_use"); disableParallelToolUse.Exists() { + if disableParallelToolUse := rootResult.Get("tool_choice.disable_parallel_tool_use"); disableParallelToolUse.Exists() { parallelToolCalls = !disableParallelToolUse.Bool() } diff --git a/internal/translator/codex/claude/codex_claude_request_test.go b/internal/translator/codex/claude/codex_claude_request_test.go index aba1ef981..3cf023696 100644 --- a/internal/translator/codex/claude/codex_claude_request_test.go +++ b/internal/translator/codex/claude/codex_claude_request_test.go @@ -95,7 +95,7 @@ func TestConvertClaudeRequestToCodex_ParallelToolCalls(t *testing.T) { wantParallelToolCalls bool }{ { - name: "Default to true when disable_parallel_tool_use is absent", + name: "Default to true when tool_choice.disable_parallel_tool_use is absent", inputJSON: `{ "model": "claude-3-opus", "messages": [{"role": "user", "content": "hello"}] @@ -106,7 +106,7 @@ func TestConvertClaudeRequestToCodex_ParallelToolCalls(t *testing.T) { name: "Disable parallel tool calls when client opts out", inputJSON: `{ "model": "claude-3-opus", - "disable_parallel_tool_use": true, + "tool_choice": {"disable_parallel_tool_use": true}, "messages": [{"role": "user", "content": "hello"}] }`, wantParallelToolCalls: false, @@ -115,7 +115,7 @@ func TestConvertClaudeRequestToCodex_ParallelToolCalls(t *testing.T) { name: "Keep parallel tool calls enabled when client explicitly allows them", inputJSON: `{ "model": "claude-3-opus", - "disable_parallel_tool_use": false, + "tool_choice": {"disable_parallel_tool_use": false}, "messages": [{"role": "user", "content": "hello"}] }`, wantParallelToolCalls: true,