diff --git a/src/api/index.ts b/src/api/index.ts index dd9208aa967..0eba26c52a6 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -89,6 +89,13 @@ export interface ApiHandlerCreateMessageMetadata { * Used by providers to determine whether to include native tool definitions. */ toolProtocol?: ToolProtocol + /** + * Controls whether the model can return multiple tool calls in a single response. + * When true, parallel tool calls are enabled (OpenAI's parallel_tool_calls=true). + * When false (default), only one tool call is returned per response. + * Only applies when toolProtocol is "native". + */ + parallelToolCalls?: boolean } export interface ApiHandler { diff --git a/src/api/providers/openai-native.ts b/src/api/providers/openai-native.ts index 34829d0810f..b5fb417ee3a 100644 --- a/src/api/providers/openai-native.ts +++ b/src/api/providers/openai-native.ts @@ -299,10 +299,12 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio ...(metadata?.tool_choice && { tool_choice: metadata.tool_choice }), } - // For native tool protocol, explicitly disable parallel tool calls. + // For native tool protocol, control parallel tool calls based on the metadata flag. + // When parallelToolCalls is true, allow parallel tool calls (OpenAI's parallel_tool_calls=true). + // When false (default), explicitly disable parallel tool calls (false). // For XML or when protocol is unset, omit the field entirely so the API default applies. if (metadata?.toolProtocol === "native") { - body.parallel_tool_calls = false + body.parallel_tool_calls = metadata.parallelToolCalls ?? false } // Include text.verbosity only when the model explicitly supports it diff --git a/src/core/task/Task.ts b/src/core/task/Task.ts index fd908e89abd..dc7ac548f0e 100644 --- a/src/core/task/Task.ts +++ b/src/core/task/Task.ts @@ -3452,11 +3452,19 @@ export class Task extends EventEmitter implements TaskLike { }) } + // Resolve parallel tool calls setting from experiment (will move to per-API-profile setting later) + const parallelToolCallsEnabled = experiments.isEnabled( + state?.experiments ?? {}, + EXPERIMENT_IDS.MULTIPLE_NATIVE_TOOL_CALLS, + ) + const metadata: ApiHandlerCreateMessageMetadata = { mode: mode, taskId: this.taskId, // Include tools and tool protocol when using native protocol and model supports it - ...(shouldIncludeTools ? { tools: allTools, tool_choice: "auto", toolProtocol } : {}), + ...(shouldIncludeTools + ? { tools: allTools, tool_choice: "auto", toolProtocol, parallelToolCalls: parallelToolCallsEnabled } + : {}), } // Create an AbortController to allow cancelling the request mid-stream