feat(mcp_client): add MUTATING_TOOLS frozenset sentinel for HITL enforcement
This commit is contained in:
@@ -40,6 +40,17 @@ import urllib.parse
|
|||||||
from html.parser import HTMLParser
|
from html.parser import HTMLParser
|
||||||
import re as _re
|
import re as _re
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------ mutating tools sentinel
|
||||||
|
|
||||||
|
# Tools that write or modify files. ai_client checks this set before dispatch
|
||||||
|
# and routes to pre_tool_callback (GUI approval) if the tool name is present.
|
||||||
|
MUTATING_TOOLS: frozenset[str] = frozenset({
|
||||||
|
"set_file_slice",
|
||||||
|
"py_update_definition",
|
||||||
|
"py_set_signature",
|
||||||
|
"py_set_var_declaration",
|
||||||
|
})
|
||||||
|
|
||||||
# ------------------------------------------------------------------ state
|
# ------------------------------------------------------------------ state
|
||||||
|
|
||||||
# Set by configure() before the AI send loop starts.
|
# Set by configure() before the AI send loop starts.
|
||||||
|
|||||||
@@ -67,3 +67,29 @@ def test_gui_agent_tool_names_exposes_all_dispatch_tools():
|
|||||||
gui_tools = set(AGENT_TOOL_NAMES)
|
gui_tools = set(AGENT_TOOL_NAMES)
|
||||||
missing = ALL_DISPATCH_TOOLS - gui_tools
|
missing = ALL_DISPATCH_TOOLS - gui_tools
|
||||||
assert not missing, f"Tools missing from gui_2.AGENT_TOOL_NAMES: {missing}"
|
assert not missing, f"Tools missing from gui_2.AGENT_TOOL_NAMES: {missing}"
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Task 2.3: MUTATING_TOOLS constant in mcp_client.py
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
def test_mcp_client_has_mutating_tools_constant():
|
||||||
|
"""mcp_client must expose a MUTATING_TOOLS frozenset."""
|
||||||
|
import mcp_client
|
||||||
|
assert hasattr(mcp_client, "MUTATING_TOOLS"), "MUTATING_TOOLS missing from mcp_client"
|
||||||
|
assert isinstance(mcp_client.MUTATING_TOOLS, frozenset)
|
||||||
|
|
||||||
|
|
||||||
|
def test_mutating_tools_contains_write_tools():
|
||||||
|
"""MUTATING_TOOLS must include all four write tools."""
|
||||||
|
import mcp_client
|
||||||
|
for tool in MUTATING_TOOLS:
|
||||||
|
assert tool in mcp_client.MUTATING_TOOLS, f"{tool} missing from mcp_client.MUTATING_TOOLS"
|
||||||
|
|
||||||
|
|
||||||
|
def test_mutating_tools_excludes_read_tools():
|
||||||
|
"""MUTATING_TOOLS must not include read-only tools."""
|
||||||
|
import mcp_client
|
||||||
|
read_only = {"read_file", "get_file_slice", "py_get_definition", "py_get_skeleton"}
|
||||||
|
for tool in read_only:
|
||||||
|
assert tool not in mcp_client.MUTATING_TOOLS, f"Read-only tool '{tool}' must not be in MUTATING_TOOLS"
|
||||||
|
|||||||
Reference in New Issue
Block a user