Remove deprecated AnalystAgent, PMAgent, and RiskAgent classes. All agent creation now goes through UnifiedAgentFactory creating EvoAgent instances. - Delete backend/agents/analyst.py (169 lines) - Delete backend/agents/portfolio_manager.py (420 lines) - Delete backend/agents/risk_manager.py (139 lines) - Update all imports to use EvoAgent exclusively - Clean up unused imports across 25 files - Update tests to work with simplified agent structure Constraint: EvoAgent is now the single source of truth for all agent roles Constraint: UnifiedAgentFactory handles runtime agent creation Rejected: Keep legacy aliases | creates maintenance burden Confidence: high Scope-risk: moderate (affects agent instantiation paths) Directive: All new agent features must be added to EvoAgent, not legacy classes Not-tested: Kubernetes sandbox executor (marked with TODO)
122 lines
4.6 KiB
Python
122 lines
4.6 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""Tests for the extracted agent service surface."""
|
|
|
|
|
|
from fastapi.testclient import TestClient
|
|
|
|
from backend.apps.agent_service import create_app
|
|
from backend.api import agents as agents_module
|
|
|
|
|
|
def test_agent_service_routes_include_control_plane_endpoints(tmp_path):
|
|
app = create_app(project_root=tmp_path)
|
|
|
|
paths = {route.path for route in app.routes}
|
|
|
|
assert "/health" in paths
|
|
assert "/api/status" in paths
|
|
assert "/api/workspaces" in paths
|
|
assert "/api/guard/pending" in paths
|
|
|
|
|
|
def test_agent_service_excludes_runtime_routes(tmp_path):
|
|
app = create_app(project_root=tmp_path)
|
|
paths = {route.path for route in app.routes}
|
|
|
|
assert "/api/runtime/start" not in paths
|
|
assert "/api/runtime/gateway/port" not in paths
|
|
|
|
|
|
def test_agent_service_status_includes_scope_metadata(tmp_path):
|
|
app = create_app(project_root=tmp_path)
|
|
|
|
with TestClient(app) as client:
|
|
response = client.get("/api/status")
|
|
|
|
assert response.status_code == 200
|
|
payload = response.json()
|
|
assert payload["scope"]["design_time_registry"]["root"] == str(tmp_path / "workspaces")
|
|
assert payload["scope"]["runtime_assets"]["root"] == str(tmp_path / "runs")
|
|
assert "runs/{run_id}" in payload["scope"]["agent_route_note"]
|
|
|
|
|
|
def test_agent_service_read_routes(monkeypatch, tmp_path):
|
|
class _FakeSkillsManager:
|
|
project_root = tmp_path
|
|
|
|
def get_agent_asset_dir(self, config_name, agent_id):
|
|
return tmp_path / "runs" / config_name / "agents" / agent_id
|
|
|
|
def resolve_agent_skill_names(self, config_name, agent_id, default_skills=None):
|
|
return ["demo_skill"]
|
|
|
|
def list_agent_skill_catalog(self, config_name, agent_id):
|
|
return [
|
|
type(
|
|
"Skill",
|
|
(),
|
|
{
|
|
"skill_name": "demo_skill",
|
|
"name": "Demo Skill",
|
|
"description": "demo",
|
|
"version": "1.0.0",
|
|
"source": "builtin",
|
|
"tools": [],
|
|
},
|
|
)()
|
|
]
|
|
|
|
def load_agent_skill_document(self, config_name, agent_id, skill_name):
|
|
return {"skill_name": skill_name, "content": "# demo"}
|
|
|
|
class _FakeWorkspaceManager:
|
|
def load_agent_file(self, config_name, agent_id, filename):
|
|
return f"{config_name}:{agent_id}:{filename}"
|
|
|
|
monkeypatch.setattr(agents_module, "load_agent_profiles", lambda: {"portfolio_manager": {"skills": ["demo_skill"]}})
|
|
monkeypatch.setattr(agents_module, "get_agent_model_info", lambda agent_id: ("deepseek-v3.2", "DASHSCOPE"))
|
|
monkeypatch.setattr(
|
|
agents_module,
|
|
"load_agent_workspace_config",
|
|
lambda path: type(
|
|
"Cfg",
|
|
(),
|
|
{
|
|
"active_tool_groups": ["portfolio_ops"],
|
|
"disabled_tool_groups": [],
|
|
"enabled_skills": [],
|
|
"disabled_skills": [],
|
|
"prompt_files": ["SOUL.md", "MEMORY.md"],
|
|
},
|
|
)(),
|
|
)
|
|
monkeypatch.setattr(
|
|
agents_module,
|
|
"get_bootstrap_config_for_run",
|
|
lambda project_root, config_name: type("Bootstrap", (), {"agent_override": lambda self, agent_id: {}})(),
|
|
)
|
|
|
|
app = create_app(project_root=tmp_path)
|
|
app.dependency_overrides[agents_module.get_skills_manager] = lambda: _FakeSkillsManager()
|
|
app.dependency_overrides[agents_module.get_workspace_manager] = lambda: _FakeWorkspaceManager()
|
|
|
|
with TestClient(app) as client:
|
|
profile = client.get("/api/workspaces/demo/agents/portfolio_manager/profile")
|
|
skills = client.get("/api/workspaces/demo/agents/portfolio_manager/skills")
|
|
detail = client.get("/api/workspaces/demo/agents/portfolio_manager/skills/demo_skill")
|
|
workspace_file = client.get("/api/workspaces/demo/agents/portfolio_manager/files/MEMORY.md")
|
|
|
|
assert profile.status_code == 200
|
|
assert profile.json()["profile"]["model_name"] == "deepseek-v3.2"
|
|
assert profile.json()["scope_type"] == "runtime_run"
|
|
assert skills.status_code == 200
|
|
assert skills.json()["skills"][0]["skill_name"] == "demo_skill"
|
|
assert skills.json()["scope_type"] == "runtime_run"
|
|
assert detail.status_code == 200
|
|
assert detail.json()["skill"]["content"] == "# demo"
|
|
assert detail.json()["scope_type"] == "runtime_run"
|
|
assert workspace_file.status_code == 200
|
|
assert workspace_file.json()["content"] == "demo:portfolio_manager:MEMORY.md"
|
|
assert workspace_file.json()["scope_type"] == "runtime_run"
|
|
assert "runs/<run_id>" in workspace_file.json()["scope_note"]
|