From 772ae0146db393fcb2f8a362d5af8839951cf491 Mon Sep 17 00:00:00 2001 From: danielhanchen Date: Tue, 7 Jul 2026 08:31:41 +0000 Subject: [PATCH] Studio: extend confirm_code_execution to the GGUF provisional card and Anthropic server tools Follow-up polish from review, both only reachable when the new flag is set: - gguf loop: suppress the streamed provisional "running" card for a python/terminal call when confirm_code_execution gates it, so a large code-execution call no longer flashes a card before the approve/deny prompt (mirrors the confirm_tool_calls suppression). - routes: reject confirm_code_execution for Anthropic Messages server tools with a 400, matching the existing confirm_tool_calls rejection, instead of silently ignoring it. --- studio/backend/core/inference/llama_cpp.py | 12 ++++++++++-- studio/backend/routes/inference.py | 15 +++++++++++++++ studio/backend/tests/test_anthropic_messages.py | 13 +++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/studio/backend/core/inference/llama_cpp.py b/studio/backend/core/inference/llama_cpp.py index 5af194cc9e..7371a2d8ea 100644 --- a/studio/backend/core/inference/llama_cpp.py +++ b/studio/backend/core/inference/llama_cpp.py @@ -8818,9 +8818,17 @@ class LlamaCppBackend: in provisional_started_tool_calls.values() ) # Later parallel cards only reconcile when parallel use is enabled. + # Suppress the early card whenever this call will be + # gated for confirmation, so a python/terminal call under + # confirm_code_execution never flashes "running" before the + # approve/deny prompt. _confirm_gated = ( - confirm_tool_calls and not bypass_permissions - ) + confirm_tool_calls + or ( + confirm_code_execution + and current_name in CODE_EXECUTION_TOOL_NAMES + ) + ) and not bypass_permissions # Keep small-argument tools on the normal path. _args_len = len( tool_calls_acc[idx]["function"].get("arguments", "") diff --git a/studio/backend/routes/inference.py b/studio/backend/routes/inference.py index 52f52e33af..091edd768f 100644 --- a/studio/backend/routes/inference.py +++ b/studio/backend/routes/inference.py @@ -10378,6 +10378,21 @@ async def anthropic_messages( err_type = "invalid_request_error", ), ) + if bool(getattr(payload, "confirm_code_execution", False)) and not bool( + getattr(payload, "bypass_permissions", False) + ): + api_monitor.fail( + monitor_id, + "confirm_code_execution is not supported for Anthropic Messages server tools.", + ) + raise HTTPException( + status_code = 400, + detail = anthropic_error_body( + "confirm_code_execution is not supported for Anthropic Messages server tools.", + status = 400, + err_type = "invalid_request_error", + ), + ) from core.inference.tools import ALL_TOOLS openai_tools = _select_anthropic_server_tools( diff --git a/studio/backend/tests/test_anthropic_messages.py b/studio/backend/tests/test_anthropic_messages.py index 170b456eac..1c265f7890 100644 --- a/studio/backend/tests/test_anthropic_messages.py +++ b/studio/backend/tests/test_anthropic_messages.py @@ -1718,6 +1718,19 @@ class TestAnthropicMessagesToolRouting: assert "confirm_tool_calls is not supported" in exc.value.detail["error"]["message"] assert backend.calls == [] + def test_confirm_code_execution_rejected_for_server_tools(self, monkeypatch): + backend = _mock_backend(monkeypatch) + payload = _basic_payload( + confirm_code_execution = True, + tools = [{"type": "web_search_20250305", "name": "web_search"}], + ) + + with pytest.raises(HTTPException) as exc: + _drive(anthropic_messages(payload, request = None, current_subject = "t")) + assert exc.value.status_code == 400 + assert "confirm_code_execution is not supported" in exc.value.detail["error"]["message"] + assert backend.calls == [] + def test_per_request_enable_tools_false_blocks_server_tool_alias(self, monkeypatch): backend = _mock_backend(monkeypatch) payload = _basic_payload(