Skip to content
This repository was archived by the owner on May 15, 2026. It is now read-only.

Commit 5050c9f

Browse files
committed
fix: remove duplicate tool_call emission from Responses API providers
The openai-native and openai-codex providers were emitting tool calls twice: 1. tool_call_partial events during streaming (handled by NativeToolCallParser) 2. Complete tool_call from response.output_item.done events This caused tools to be rendered twice in the UI. Fix: Remove the tool_call emission from response.output_item.done since the streaming path already handles tool call completion via NativeToolCallParser's finalizeRawChunks() and finalizeStreamingToolCall() methods.
1 parent d6d00de commit 5050c9f

2 files changed

Lines changed: 12 additions & 34 deletions

File tree

src/api/providers/openai-codex.ts

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -925,22 +925,12 @@ export class OpenAiCodexHandler extends BaseProvider implements SingleCompletion
925925
}
926926
}
927927

928-
// Only handle tool/function calls from done events (to ensure arguments are complete)
929-
if (
930-
(item.type === "function_call" || item.type === "tool_call") &&
931-
event.type === "response.output_item.done"
932-
) {
933-
const callId = item.call_id || item.tool_call_id || item.id
934-
if (callId) {
935-
const args = item.arguments || item.function?.arguments || item.function_arguments
936-
yield {
937-
type: "tool_call",
938-
id: callId,
939-
name: item.name || item.function?.name || item.function_name || "",
940-
arguments: typeof args === "string" ? args : "{}",
941-
}
942-
}
943-
}
928+
// Note: We intentionally do NOT emit tool_call from response.output_item.done
929+
// for function_call/tool_call items. The streaming path handles tool calls via:
930+
// 1. tool_call_partial events during argument deltas
931+
// 2. NativeToolCallParser.finalizeRawChunks() at stream end emitting tool_call_end
932+
// 3. NativeToolCallParser.finalizeStreamingToolCall() creating the final ToolUse
933+
// Emitting tool_call here would cause duplicate tool rendering.
944934
}
945935
return
946936
}

src/api/providers/openai-native.ts

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1241,24 +1241,12 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio
12411241
}
12421242
}
12431243

1244-
// Only handle tool/function calls from done events (to ensure arguments are complete)
1245-
if (
1246-
(item.type === "function_call" || item.type === "tool_call") &&
1247-
event.type === "response.output_item.done"
1248-
) {
1249-
// Handle complete tool/function call item
1250-
// Emit as tool_call for backward compatibility with non-streaming tool handling
1251-
const callId = item.call_id || item.tool_call_id || item.id
1252-
if (callId) {
1253-
const args = item.arguments || item.function?.arguments || item.function_arguments
1254-
yield {
1255-
type: "tool_call",
1256-
id: callId,
1257-
name: item.name || item.function?.name || item.function_name || "",
1258-
arguments: typeof args === "string" ? args : "{}",
1259-
}
1260-
}
1261-
}
1244+
// Note: We intentionally do NOT emit tool_call from response.output_item.done
1245+
// for function_call/tool_call items. The streaming path handles tool calls via:
1246+
// 1. tool_call_partial events during argument deltas
1247+
// 2. NativeToolCallParser.finalizeRawChunks() at stream end emitting tool_call_end
1248+
// 3. NativeToolCallParser.finalizeStreamingToolCall() creating the final ToolUse
1249+
// Emitting tool_call here would cause duplicate tool rendering.
12621250
}
12631251
return
12641252
}

0 commit comments

Comments
 (0)