b15955c80e
Staged-but-not-yet-fixed file artifacts from the post_module_taxonomy_de_cruft followup. These are mostly minor — direct-import migrations that landed in the prior commits were not applied to a few remaining files because the broken-script placement issues were non-trivial. For Tier 1 followup: - src/commands.py — unused 'from src import models' removed by migration - src/mcp_client.py — verified to no longer have the circular self-import - src/models.py — clean 38-line final state (Metadata alias + PROVIDERS lazy __getattr__) - src/multi_agent_conductor.py, src/project_manager.py, src/rag_engine.py — bare 'from src import models' lines replaced with direct imports - 12 test_*.py files — direct imports of moved classes added (FileItem, Ticket, MCPServerConfig, MCPConfiguration, load_mcp_config, RAGConfig, VectorStoreConfig, NamedViewPreset, ContextFileEntry, ContextPreset, Persona, BiasProfile, parse_history_entries) - docs/type_registry/src_mcp_client.md — regenerated via type_registry script No production behavior changes here. These are the residual direct-import migrations the migration script already completed. Some are tracked in the end_of_session report for Tier 1 followup.
89 lines
2.5 KiB
Python
89 lines
2.5 KiB
Python
import pytest
|
|
import asyncio
|
|
from src import ai_client
|
|
from src import mcp_client
|
|
from src import models
|
|
from src.tool_presets import ToolPreset, Tool, Tool, ToolPreset
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_tool_auto_approval():
|
|
# Setup a preset with read_file as auto
|
|
preset = ToolPreset(name="AutoTest", categories={
|
|
"General": [Tool(name="read_file", approval="auto")]
|
|
})
|
|
|
|
with patch("src.tool_presets.ToolPresetManager.load_all", return_value={"AutoTest": preset}):
|
|
ai_client.set_tool_preset("AutoTest")
|
|
|
|
# Mock mcp_client.async_dispatch to avoid actual file reads
|
|
with patch("src.mcp_client.async_dispatch", return_value="File Content") as mock_dispatch:
|
|
# pre_tool_callback should NOT be called
|
|
mock_cb = MagicMock()
|
|
|
|
name, call_id, out, _ = await ai_client._execute_single_tool_call_async(
|
|
name="read_file",
|
|
args={"path": "test.txt"},
|
|
call_id="call_1",
|
|
base_dir=".",
|
|
pre_tool_callback=mock_cb,
|
|
qa_callback=None,
|
|
r_idx=0
|
|
)
|
|
|
|
assert out == "File Content"
|
|
mock_cb.assert_not_called()
|
|
mock_dispatch.assert_called_once()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_tool_ask_approval():
|
|
# Setup a preset with run_powershell as ask
|
|
preset = ToolPreset(name="AskTest", categories={
|
|
"General": [Tool(name="run_powershell", approval="ask")]
|
|
})
|
|
|
|
with patch("src.tool_presets.ToolPresetManager.load_all", return_value={"AskTest": preset}):
|
|
ai_client.set_tool_preset("AskTest")
|
|
|
|
# pre_tool_callback SHOULD be called
|
|
mock_cb = MagicMock(return_value="Success")
|
|
|
|
name, call_id, out, _ = await ai_client._execute_single_tool_call_async(
|
|
name="run_powershell",
|
|
args={"script": "dir"},
|
|
call_id="call_2",
|
|
base_dir=".",
|
|
pre_tool_callback=mock_cb,
|
|
qa_callback=None,
|
|
r_idx=0
|
|
)
|
|
|
|
assert out == "Success"
|
|
mock_cb.assert_called_once()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_tool_rejection():
|
|
# Setup a preset with run_powershell as ask
|
|
preset = ToolPreset(name="AskTest", categories={
|
|
"General": [Tool(name="run_powershell", approval="ask")]
|
|
})
|
|
|
|
with patch("src.tool_presets.ToolPresetManager.load_all", return_value={"AskTest": preset}):
|
|
ai_client.set_tool_preset("AskTest")
|
|
|
|
# mock_cb returns None (rejected)
|
|
mock_cb = MagicMock(return_value=None)
|
|
|
|
name, call_id, out, _ = await ai_client._execute_single_tool_call_async(
|
|
name="run_powershell",
|
|
args={"script": "dir"},
|
|
call_id="call_3",
|
|
base_dir=".",
|
|
pre_tool_callback=mock_cb,
|
|
qa_callback=None,
|
|
r_idx=0
|
|
)
|
|
|
|
assert "USER REJECTED" in out
|
|
mock_cb.assert_called_once()
|