From 379e935006a16d4fbbca693e7e9a1ca79d6f0576 Mon Sep 17 00:00:00 2001 From: Hannes Rudolph Date: Wed, 26 Nov 2025 11:45:44 -0700 Subject: [PATCH 1/2] feat: wire MULTIPLE_NATIVE_TOOL_CALLS experiment to OpenAI parallel_tool_calls - Add parallelToolCalls field to ApiHandlerCreateMessageMetadata interface - Pass experiment state from Task.ts to API metadata when building request - OpenAI Native provider now sets parallel_tool_calls based on experiment - Add temporary console.log for debugging API request body When the MULTIPLE_NATIVE_TOOL_CALLS experiment is enabled: 1. OpenAI API receives parallel_tool_calls=true (can return multiple tools) 2. Client-side execution allows multiple tools per response (sequential) --- src/api/index.ts | 7 +++++++ src/api/providers/openai-native.ts | 9 +++++++-- src/core/task/Task.ts | 10 +++++++++- 3 files changed, 23 insertions(+), 3 deletions(-) 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..888b11c4f1f 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 @@ -323,6 +325,9 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio // Create AbortController for cancellation this.abortController = new AbortController() + // TEMPORARY: Log the raw API request body for debugging parallel tool calls + console.log("[OpenAI Native] API Request Body:", requestBody) + try { // Use the official SDK const stream = (await (this.client as any).responses.create(requestBody, { 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 From f925e17e7d79860a7f96869a9d80f8a63f971fd7 Mon Sep 17 00:00:00 2001 From: Hannes Rudolph Date: Wed, 26 Nov 2025 12:25:45 -0700 Subject: [PATCH 2/2] fix: remove temporary logging of API request body in OpenAiNativeHandler --- src/api/providers/openai-native.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/api/providers/openai-native.ts b/src/api/providers/openai-native.ts index 888b11c4f1f..b5fb417ee3a 100644 --- a/src/api/providers/openai-native.ts +++ b/src/api/providers/openai-native.ts @@ -325,9 +325,6 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio // Create AbortController for cancellation this.abortController = new AbortController() - // TEMPORARY: Log the raw API request body for debugging parallel tool calls - console.log("[OpenAI Native] API Request Body:", requestBody) - try { // Use the official SDK const stream = (await (this.client as any).responses.create(requestBody, {