From 19e1a4447a83f5791d371ecda857ece8bef4da84 Mon Sep 17 00:00:00 2001 From: Darley Date: Tue, 17 Mar 2026 19:17:41 +0800 Subject: [PATCH] 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 4bc116b9..a9ed46b0 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 bdd41639..aba1ef98 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)) + } + }) + } +}