diff --git a/apps/edge/internal/openai/provider_model_rewrite.go b/apps/edge/internal/openai/provider_model_rewrite.go index 5b2d4f1a..1a93236c 100644 --- a/apps/edge/internal/openai/provider_model_rewrite.go +++ b/apps/edge/internal/openai/provider_model_rewrite.go @@ -215,7 +215,9 @@ func prepareHotPathSelectorCanonicalTools(tunnel edgeservice.SubmitProviderTunne }, }, }} - root["tool_choice"] = "required" + root["tool_choice"] = map[string]any{ + "type": "function", "function": map[string]any{"name": hotPathArtifactPairToolName}, + } delete(root, "parallel_tool_calls") return json.Marshal(root) } diff --git a/apps/edge/internal/openai/provider_model_rewrite_test.go b/apps/edge/internal/openai/provider_model_rewrite_test.go index 77d44704..396cc68b 100644 --- a/apps/edge/internal/openai/provider_model_rewrite_test.go +++ b/apps/edge/internal/openai/provider_model_rewrite_test.go @@ -394,7 +394,9 @@ func TestHotPathSelectorCanonicalWriteToolReplacesCallerCommandSchema(t *testing if function["name"] != hotPathArtifactPairToolName || properties["plan_content"] == nil || properties["review_content"] == nil || properties["command"] != nil { t.Fatalf("canonical write function=%+v", function) } - if request["tool_choice"] != "required" || request["parallel_tool_calls"] != nil { + choice := request["tool_choice"].(map[string]any) + chosenFunction := choice["function"].(map[string]any) + if choice["type"] != "function" || chosenFunction["name"] != hotPathArtifactPairToolName || request["parallel_tool_calls"] != nil { t.Fatalf("pair-write must force one atomic tool call: %+v", request) } } @@ -447,7 +449,8 @@ func TestAnthropicCallerWorkspaceSelectorUsesCanonicalProviderOperation(t *testi t.Fatalf("OpenAI selector tunnel=%+v", prepared) } tool := tools[0].(map[string]any) - if tool["name"] != hotPathArtifactPairToolName || request["tool_choice"] != "required" || request["max_output_tokens"] != float64(maxHotPathSelectorOutputTokens) { + choice := request["tool_choice"].(map[string]any) + if tool["name"] != hotPathArtifactPairToolName || choice["type"] != "function" || choice["name"] != hotPathArtifactPairToolName || request["max_output_tokens"] != float64(maxHotPathSelectorOutputTokens) { t.Fatalf("OpenAI selector request=%+v", request) } if !strings.Contains(request["instructions"].(string), "Operation: pair-write") { @@ -459,7 +462,9 @@ func TestAnthropicCallerWorkspaceSelectorUsesCanonicalProviderOperation(t *testi t.Fatalf("Gemini selector tunnel=%+v", prepared) } function := tools[0].(map[string]any)["function"].(map[string]any) - if function["name"] != hotPathArtifactPairToolName || request["tool_choice"] != "required" || request["max_tokens"] != float64(maxHotPathSelectorOutputTokens) { + choice := request["tool_choice"].(map[string]any) + chosenFunction := choice["function"].(map[string]any) + if function["name"] != hotPathArtifactPairToolName || choice["type"] != "function" || chosenFunction["name"] != hotPathArtifactPairToolName || request["max_tokens"] != float64(maxHotPathSelectorOutputTokens) { t.Fatalf("Gemini selector request=%+v", request) } messages := anySlice(request["messages"])