"""Integration tests for PLAN_EXEC autonomy mode wiring (IQ-Boost U2). Verifies that ``_build_phase_engine`` in chat.py constructs a PLAN_EXEC engine with ``autonomy_mode=True`` and ``dangerous_tools_config`` injected from ``ServerConfig``. This is the integration seam between U1 (config) and U2 (engine gate). """ from __future__ import annotations from unittest.mock import MagicMock from agentkit.chat.skill_routing import ExecutionMode from agentkit.core.react import ReActEngine from agentkit.server.config import DangerousToolsConfig, ServerConfig def _make_server_config(dangerous_tools: DangerousToolsConfig | None = None) -> ServerConfig: """Build a minimal ServerConfig with the dangerous_tools section.""" cfg = ServerConfig.from_dict({}) if dangerous_tools is not None: cfg.dangerous_tools = dangerous_tools return cfg class TestBuildPhaseEngineAutonomyWiring: """_build_phase_engine injects autonomy config into the PLAN_EXEC engine.""" def test_plan_exec_engine_gets_autonomy_mode(self): """When PLAN_EXEC is engaged, the engine has autonomy_mode=True.""" # Import here to avoid module-level FastAPI app construction. from agentkit.server.routes.chat import _build_phase_engine server_cfg = _make_server_config(DangerousToolsConfig()) engine, tools, err = _build_phase_engine( server_config=server_cfg, llm_gateway=MagicMock(), execution_mode=ExecutionMode.PLAN_EXEC, base_tools=[], session_id="test-session", ) assert err is None assert engine is not None assert isinstance(engine, ReActEngine) assert engine._autonomy_mode is True assert engine._dangerous_tools_config is not None assert engine._dangerous_tools_config.is_dangerous("rm") is True def test_plan_exec_engine_gets_custom_dangerous_config(self): """Custom dangerous_tools config (disabled) propagates to the engine.""" from agentkit.server.routes.chat import _build_phase_engine server_cfg = _make_server_config(DangerousToolsConfig(enabled=False)) engine, _, err = _build_phase_engine( server_config=server_cfg, llm_gateway=MagicMock(), execution_mode=ExecutionMode.PLAN_EXEC, base_tools=[], session_id="test", ) assert err is None assert engine is not None assert engine._dangerous_tools_config.enabled is False # Disabled whitelist → nothing is dangerous assert engine._dangerous_tools_config.is_dangerous("rm") is False def test_non_plan_exec_mode_returns_none_engine(self): """Non-PLAN_EXEC mode → (None, None, None) — no autonomy engine built.""" from agentkit.server.routes.chat import _build_phase_engine server_cfg = _make_server_config(DangerousToolsConfig()) engine, tools, err = _build_phase_engine( server_config=server_cfg, llm_gateway=MagicMock(), execution_mode=ExecutionMode.REACT, base_tools=[], session_id="test", ) assert engine is None assert tools is None assert err is None def test_plan_exec_engine_gets_default_dangerous_config_when_server_config_missing( self, ): """When server_config is None or lacks dangerous_tools, the engine still gets autonomy_mode=True (config defaults to None — gate is a no-op, but autonomy flag is set for future wiring).""" from agentkit.server.routes.chat import _build_phase_engine # server_config=None simulates tests/misconfigured deployments. engine, _, err = _build_phase_engine( server_config=None, llm_gateway=MagicMock(), execution_mode=ExecutionMode.PLAN_EXEC, base_tools=[], session_id="test", ) assert err is None assert engine is not None assert engine._autonomy_mode is True # dangerous_tools_config is None when server_config is None — gate # becomes a transparent no-op (backward compat for tests without config). assert engine._dangerous_tools_config is None def test_plan_exec_engine_includes_advance_phase_tool(self): """PLAN_EXEC engine's tool list includes AdvancePhaseTool.""" from agentkit.server.routes.chat import _build_phase_engine server_cfg = _make_server_config(DangerousToolsConfig()) engine, tools, err = _build_phase_engine( server_config=server_cfg, llm_gateway=MagicMock(), execution_mode=ExecutionMode.PLAN_EXEC, base_tools=[], session_id="test", ) assert err is None assert engine is not None assert tools is not None # AdvancePhaseTool appended to the base tool list. assert len(tools) == 1 assert type(tools[0]).__name__ == "AdvancePhaseTool"