Files
webber/webber-api/tests/test_plan_agent.py
T
jpmschweitzerandClaude Opus 4.5 b5b2346db5
Build and Push API / release (push) Successful in 5s
Build and Push API / build (push) Successful in 1m15s
feat: add Plan Agent for implementation planning
- Add PlanAgentImpl with read-only tools only
- System prompts optimized for architecture planning
- Outputs step-by-step implementation plans with critical files
- 15 unit tests for registration, tools, and API
- Update COVERAGE.md to ~70% complete

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 19:57:30 +01:00

153 lines
4.9 KiB
Python

"""
Tests for the Plan agent.
Tests registration, API endpoints, and tool restrictions.
"""
import pytest
from src.domains.agents.base import get_agent, list_agents
from src.domains.agents.plan import plan_agent, PlanAgentImpl
class TestPlanAgentRegistration:
"""Tests for Plan agent registration."""
def test_plan_agent_registered(self):
"""Test that plan agent is registered in registry."""
agent = get_agent("plan")
assert agent is not None
assert agent.name == "plan"
def test_plan_agent_in_list(self):
"""Test that plan agent appears in agent list."""
agents = list_agents()
names = [a["name"] for a in agents]
assert "plan" in names
def test_plan_agent_has_description(self):
"""Test that plan agent has a description."""
agent = get_agent("plan")
assert agent is not None
assert len(agent.description) > 0
assert "plan" in agent.description.lower() or "architect" in agent.description.lower()
def test_plan_agent_singleton(self):
"""Test that plan_agent is the registered instance."""
registered = get_agent("plan")
assert registered is plan_agent
def test_plan_agent_is_correct_type(self):
"""Test that plan agent is correct implementation type."""
assert isinstance(plan_agent, PlanAgentImpl)
class TestPlanAgentTools:
"""Tests for Plan agent tool restrictions."""
def test_plan_agent_has_read_only_tools(self):
"""Test that plan agent has read-only tools."""
# Access the underlying PydanticAI agent to check tools
agent = plan_agent.agent
tool_names = list(agent._function_toolset.tools.keys())
# Should have read-only tools
assert "read_file" in tool_names
assert "glob_files" in tool_names
assert "grep_content" in tool_names
assert "bash_readonly" in tool_names
def test_plan_agent_no_write_tools(self):
"""Test that plan agent does NOT have write tools."""
agent = plan_agent.agent
tool_names = list(agent._function_toolset.tools.keys())
# Should NOT have write tools
assert "edit_file" not in tool_names
assert "write_file" not in tool_names
assert "bash" not in tool_names
assert "web_search" not in tool_names
def test_plan_agent_tool_count(self):
"""Test that plan agent has exactly 4 tools."""
agent = plan_agent.agent
tool_count = len(agent._function_toolset.tools)
assert tool_count == 4
class TestPlanAgentAPI:
"""Tests for Plan agent REST API."""
@pytest.mark.anyio
async def test_list_agents_includes_plan(self, auth_client):
"""Test that agent list includes plan agent."""
response = await auth_client.get("/agents/")
assert response.status_code == 200
data = response.json()
names = [a["name"] for a in data["agents"]]
assert "plan" in names
@pytest.mark.anyio
async def test_get_plan_agent_info(self, auth_client):
"""Test getting plan agent info."""
response = await auth_client.get("/agents/plan")
assert response.status_code == 200
data = response.json()
assert data["name"] == "plan"
assert "description" in data
assert len(data["description"]) > 0
@pytest.mark.anyio
async def test_run_plan_with_invalid_body(self, auth_client):
"""Test running plan agent with invalid request."""
response = await auth_client.post(
"/agents/run",
json={
"agent_type": "plan",
# Missing prompt
}
)
assert response.status_code == 422
@pytest.mark.anyio
async def test_stream_plan_with_invalid_body(self, auth_client):
"""Test streaming plan agent with invalid request."""
response = await auth_client.post(
"/agents/stream",
json={
"agent_type": "plan",
# Missing prompt
}
)
assert response.status_code == 422
class TestPlanAgentProperties:
"""Tests for Plan agent properties and configuration."""
def test_plan_agent_name(self):
"""Test plan agent name property."""
assert plan_agent.name == "plan"
def test_plan_agent_description_not_empty(self):
"""Test plan agent description is not empty."""
assert plan_agent.description
assert len(plan_agent.description) > 10
def test_plan_agent_creates_agent_lazily(self):
"""Test that PydanticAI agent is created lazily."""
# Create a fresh instance
fresh_agent = PlanAgentImpl()
# _agent should be None before first access
assert fresh_agent._agent is None
# Access the agent property
_ = fresh_agent.agent
# Now _agent should be set
assert fresh_agent._agent is not None