From 91a2b1f0b4cc787d2863950975f7aa3e1b91eba5 Mon Sep 17 00:00:00 2001 From: skad <1350375634@qq.com> Date: Sun, 8 Mar 2026 13:59:32 +0800 Subject: [PATCH] Fixed: preserve Responses computer tool passthrough Keep the OpenAI Responses computer tool intact when normalizing requests for the GitHub Copilot executor. This change preserves built-in computer tool definitions instead of dropping them as non-function tools, keeps explicit computer tool_choice selections unchanged, and classifies computer_call / computer_call_output items as assistant and tool turns when deriving the initiator header. Together these adjustments allow Responses requests that use the computer tool to reach the upstream executor without losing tool metadata or switching turn ownership unexpectedly. --- .../executor/github_copilot_executor.go | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/internal/runtime/executor/github_copilot_executor.go b/internal/runtime/executor/github_copilot_executor.go index dc23df97..fe724a62 100644 --- a/internal/runtime/executor/github_copilot_executor.go +++ b/internal/runtime/executor/github_copilot_executor.go @@ -522,9 +522,9 @@ func detectLastConversationRole(body []byte) string { } switch item.Get("type").String() { - case "function_call", "function_call_arguments": + case "function_call", "function_call_arguments", "computer_call": return "assistant" - case "function_call_output", "function_call_response", "tool_result": + case "function_call_output", "function_call_response", "tool_result", "computer_call_output": return "tool" } } @@ -832,6 +832,10 @@ func normalizeGitHubCopilotResponsesTools(body []byte) []byte { if tools.IsArray() { for _, tool := range tools.Array() { toolType := tool.Get("type").String() + if isGitHubCopilotResponsesBuiltinTool(toolType) { + filtered, _ = sjson.SetRaw(filtered, "-1", tool.Raw) + continue + } // Accept OpenAI format (type="function") and Claude format // (no type field, but has top-level name + input_schema). if toolType != "" && toolType != "function" { @@ -879,6 +883,10 @@ func normalizeGitHubCopilotResponsesTools(body []byte) []byte { } if toolChoice.Type == gjson.JSON { choiceType := toolChoice.Get("type").String() + if isGitHubCopilotResponsesBuiltinTool(choiceType) { + body, _ = sjson.SetRawBytes(body, "tool_choice", []byte(toolChoice.Raw)) + return body + } if choiceType == "function" { name := toolChoice.Get("name").String() if name == "" { @@ -896,6 +904,15 @@ func normalizeGitHubCopilotResponsesTools(body []byte) []byte { return body } +func isGitHubCopilotResponsesBuiltinTool(toolType string) bool { + switch strings.TrimSpace(toolType) { + case "computer", "computer_use_preview": + return true + default: + return false + } +} + func collectTextFromNode(node gjson.Result) string { if !node.Exists() { return ""