Studio: scope the confirm_code_execution stream requirement to code-execution tools

The streaming requirement for confirm_code_execution now fires only when a
local code-execution tool (python/terminal) could actually run, so a
non-streaming request that enables only non-code tools (web_search,
render_html, ...) is no longer rejected. This matches the documented behavior
that confirm_code_execution leaves non-code tools unaffected.

- Per-handler (GGUF and safetensors): gate on the resolved tool list
  intersecting python/terminal.
- Pre-switch: gate on a payload-level predicate that mirrors
  _select_request_tools (built-ins off unless the tool loop is enabled; an
  explicit enabled_tools filter must list python/terminal).
- External-provider and Anthropic server-tool rejections stay broad: the local
  confirm gate cannot apply there at all.

Tests: predicate coverage for both the resolved and payload-level checks.
This commit is contained in:
danielhanchen 2026-07-07 09:24:28 +00:00
commit dbf503e9a5
2 changed files with 96 additions and 15 deletions

View file

@ -1763,6 +1763,32 @@ async def _select_request_tools(
return tools
def _enables_code_execution_tool(tools: list[dict]) -> bool:
"""True when a resolved tool list includes a local code-execution tool
(python/terminal). ``confirm_code_execution`` only gates those, so the
streaming requirement is scoped to requests that actually expose one."""
from core.inference.tools import CODE_EXECUTION_TOOL_NAMES
return any(
(t.get("function") or {}).get("name") in CODE_EXECUTION_TOOL_NAMES for t in (tools or [])
)
def _payload_may_enable_code_execution(payload) -> bool:
"""True when a request could resolve a local code-execution tool before the
tool list is built (used by the pre-switch guard). Mirrors
``_select_request_tools``: built-ins are off unless the tool loop is enabled,
and an explicit ``enabled_tools`` filter must then list python/terminal
(MCP/client tools are never code execution)."""
from core.inference.tools import CODE_EXECUTION_TOOL_NAMES
if not _effective_enable_tools(payload):
return False
if payload.enabled_tools is not None:
return bool(set(payload.enabled_tools) & CODE_EXECUTION_TOOL_NAMES)
return True
def _apply_rag_nudge(nudge: str, tools: list[dict], *, rag_scope) -> str:
"""Append the RAG grounding nudge to ``nudge`` when the knowledge-base tool
is active (search_knowledge_base present and a retrieval scope is set). The
@ -5772,26 +5798,22 @@ async def openai_chat_completions(
param = "confirm_tool_calls",
),
)
# Same pre-switch guard for confirm_code_execution: the code-execution
# confirm gate also needs streaming, so a non-stream request must not evict
# the resident model only to 400 after the swap.
# Same pre-switch guard for confirm_code_execution, but scoped to requests
# that could actually run a local code-execution tool: the gate only
# applies to python/terminal, so a non-code tool request (e.g. web_search)
# must not be rejected, and a code-execution one must not evict the
# resident model only to 400 after the swap.
if (
payload.confirm_code_execution
and not payload.bypass_permissions
and not payload.stream
and (
_effective_enable_tools(payload)
or (bool(payload.mcp_enabled) and _confirm_cli_policy is not False)
or bool(payload.enabled_tools)
or bool(payload.tools)
or bool(payload.openai_code_exec_container_id)
or bool(payload.anthropic_code_exec_container_id)
)
and _payload_may_enable_code_execution(payload)
):
raise HTTPException(
status_code = 400,
detail = openai_error_body(
"confirm_code_execution requires stream=true for local tool execution.",
"confirm_code_execution requires stream=true when a "
"code-execution tool (python/terminal) is enabled.",
status = 400,
code = "invalid_request_error",
param = "confirm_code_execution",
@ -6273,11 +6295,13 @@ async def openai_chat_completions(
payload.confirm_code_execution
and not payload.bypass_permissions
and not payload.stream
and _enables_code_execution_tool(tools_to_use)
):
raise _reject(
400,
openai_error_body(
"confirm_code_execution requires stream=true for local tool execution.",
"confirm_code_execution requires stream=true when a "
"code-execution tool (python/terminal) is enabled.",
status = 400,
code = "invalid_request_error",
param = "confirm_code_execution",
@ -7009,11 +7033,17 @@ async def openai_chat_completions(
param = "confirm_tool_calls",
),
)
if payload.confirm_code_execution and not payload.bypass_permissions and not payload.stream:
if (
payload.confirm_code_execution
and not payload.bypass_permissions
and not payload.stream
and _enables_code_execution_tool(_sf_tools_to_use)
):
raise _reject(
400,
openai_error_body(
"confirm_code_execution requires stream=true for local tool execution.",
"confirm_code_execution requires stream=true when a "
"code-execution tool (python/terminal) is enabled.",
status = 400,
code = "invalid_request_error",
param = "confirm_code_execution",

View file

@ -179,3 +179,54 @@ def test_confirm_tool_calls_still_gates_every_tool():
starts = _starts(events)
assert starts[0]["awaiting_confirmation"] is True
assert calls == [("web_search", {"query": "cats"})]
# ── scoping predicates used by the route streaming requirement ───────────────
def _spec(name):
return {"type": "function", "function": {"name": name}}
def test_enables_code_execution_tool_predicate():
from routes.inference import _enables_code_execution_tool
assert _enables_code_execution_tool([_spec("python")]) is True
assert _enables_code_execution_tool([_spec("terminal")]) is True
assert _enables_code_execution_tool([_spec("web_search"), _spec("python")]) is True
# A non-code tool list must not trip the streaming requirement.
assert _enables_code_execution_tool([_spec("web_search"), _spec("render_html")]) is False
assert _enables_code_execution_tool([]) is False
assert _enables_code_execution_tool(None) is False
def test_payload_may_enable_code_execution_predicate(monkeypatch):
import routes.inference as inf
monkeypatch.setattr("state.tool_policy.get_tool_policy", lambda: None)
class _P:
def __init__(self, enable_tools = None, enabled_tools = None):
self.enable_tools = enable_tools
self.enabled_tools = enabled_tools
# Built-ins off -> never code execution, even if enabled_tools lists python.
assert inf._payload_may_enable_code_execution(_P(enable_tools = None)) is False
assert (
inf._payload_may_enable_code_execution(_P(enable_tools = False, enabled_tools = ["python"]))
is False
)
# Built-ins on, explicit filter without a code tool -> not code execution (the fix).
assert (
inf._payload_may_enable_code_execution(
_P(enable_tools = True, enabled_tools = ["web_search"])
)
is False
)
# Built-ins on, code tool in the filter -> code execution.
assert (
inf._payload_may_enable_code_execution(_P(enable_tools = True, enabled_tools = ["terminal"]))
is True
)
# Built-ins on, no filter -> all built-ins including python/terminal.
assert inf._payload_may_enable_code_execution(_P(enable_tools = True)) is True