88a1dab810
---ci--- phase: 7 milestone: v0.2 status: complete requirements: covered: [REQ-2-001, REQ-2-002, REQ-2-003, REQ-2-004, REQ-2-005, REQ-2-006, REQ-2-007, REQ-2-008, REQ-2-009, REQ-2-010, REQ-2-011, REQ-2-012] partial: [] ---/ci--- Milestone v0.2 (ai-tutor-architecture) merged to main. Escalation record (audit remediation, durable): P1 executor delegation failed twice (empty subagent results, zero files created); auto-resolved at full autonomy to inline execution with identical plan fidelity (commit 3271373, reflog-only after phase branch squash-delete).
133 lines
4.4 KiB
Python
133 lines
4.4 KiB
Python
"""Agent registry tests — register/get round-trip, error paths (G-4), builtins."""
|
|
|
|
|
|
import pytest
|
|
|
|
from ai_service.agents.base import BaseAgent
|
|
from ai_service.agents.coach import CoachAgent
|
|
from ai_service.agents.registry import (
|
|
AgentRegistry,
|
|
DuplicateAgentError,
|
|
UnknownAgentError,
|
|
register_builtin_agents,
|
|
)
|
|
from ai_service.agents.tutor import TutorAgent
|
|
from ai_service.config import Settings
|
|
from ai_service.llm.mock import MockProvider
|
|
|
|
|
|
class DummyAgent(BaseAgent):
|
|
name = "dummy"
|
|
|
|
def system_prompt(self, learner_context=None) -> str:
|
|
return "dummy"
|
|
|
|
|
|
def make_factory():
|
|
def factory(provider, settings):
|
|
return DummyAgent(provider, settings)
|
|
return factory
|
|
|
|
|
|
def test_register_and_get():
|
|
registry = AgentRegistry()
|
|
registry.register("dummy", make_factory())
|
|
agent = registry.get(MockProvider(), Settings(provider="mock"), "dummy")
|
|
assert isinstance(agent, DummyAgent)
|
|
assert agent.name == "dummy"
|
|
|
|
|
|
def test_unknown_agent_raises():
|
|
registry = AgentRegistry()
|
|
with pytest.raises(UnknownAgentError):
|
|
registry.get(MockProvider(), Settings(provider="mock"), "ghost")
|
|
|
|
|
|
def test_duplicate_registration_raises():
|
|
registry = AgentRegistry()
|
|
registry.register("dummy", make_factory())
|
|
with pytest.raises(DuplicateAgentError):
|
|
registry.register("dummy", make_factory())
|
|
|
|
|
|
def test_names_sorted():
|
|
registry = AgentRegistry()
|
|
registry.register("zeta", make_factory())
|
|
registry.register("alpha", make_factory())
|
|
assert registry.names() == ["alpha", "zeta"]
|
|
|
|
|
|
def test_builtin_agents_register_and_resolve():
|
|
registry = AgentRegistry()
|
|
register_builtin_agents(registry)
|
|
assert set(registry.names()) >= {"coach", "tutor"}
|
|
settings = Settings(provider="mock")
|
|
coach = registry.get(MockProvider(), settings, "coach")
|
|
tutor = registry.get(MockProvider(), settings, "tutor")
|
|
assert isinstance(coach, CoachAgent)
|
|
assert isinstance(tutor, TutorAgent)
|
|
|
|
|
|
def test_lab_and_assessor_resolve_via_registry():
|
|
"""Phase 4: lab + assessor registered centrally (Task 4-3-01)."""
|
|
from ai_service.agents.assessor import AssessorAgent
|
|
from ai_service.agents.lab import LabAgent
|
|
|
|
registry = AgentRegistry()
|
|
register_builtin_agents(registry)
|
|
assert {"lab", "assessor"} <= set(registry.names())
|
|
settings = Settings(provider="mock")
|
|
lab = registry.get(MockProvider(), settings, "lab")
|
|
assessor = registry.get(MockProvider(), settings, "assessor")
|
|
assert isinstance(lab, LabAgent)
|
|
assert isinstance(assessor, AssessorAgent)
|
|
|
|
|
|
def test_proctor_and_mentor_resolve_via_registry():
|
|
"""Phase 5: proctor + mentor registered centrally (Tasks 5-1-02/5-2-01)."""
|
|
from ai_service.agents.mentor import MentorAgent
|
|
from ai_service.agents.proctor import ProctorAgent
|
|
|
|
registry = AgentRegistry()
|
|
register_builtin_agents(registry)
|
|
settings = Settings(provider="mock")
|
|
proctor = registry.get(MockProvider(), settings, "proctor")
|
|
mentor = registry.get(MockProvider(), settings, "mentor")
|
|
assert isinstance(proctor, ProctorAgent)
|
|
assert isinstance(mentor, MentorAgent)
|
|
|
|
|
|
def test_registry_resolves_all_six_agents():
|
|
"""Must-Have (Phase 5): the full roster — coach/tutor/lab/assessor/proctor/mentor."""
|
|
from ai_service.agents.assessor import AssessorAgent
|
|
from ai_service.agents.coach import CoachAgent
|
|
from ai_service.agents.lab import LabAgent
|
|
from ai_service.agents.mentor import MentorAgent
|
|
from ai_service.agents.proctor import ProctorAgent
|
|
from ai_service.agents.tutor import TutorAgent
|
|
|
|
registry = AgentRegistry()
|
|
register_builtin_agents(registry)
|
|
assert registry.names() == ["assessor", "coach", "lab", "mentor", "proctor", "tutor"]
|
|
settings = Settings(provider="mock")
|
|
expected = {
|
|
"coach": CoachAgent,
|
|
"tutor": TutorAgent,
|
|
"lab": LabAgent,
|
|
"assessor": AssessorAgent,
|
|
"proctor": ProctorAgent,
|
|
"mentor": MentorAgent,
|
|
}
|
|
for name, cls in expected.items():
|
|
agent = registry.get(MockProvider(), settings, name)
|
|
assert isinstance(agent, cls), f"{name} resolved to {type(agent).__name__}"
|
|
assert agent.name == name
|
|
|
|
|
|
def test_builtin_registration_is_idempotent_safe():
|
|
"""Duplicate registration raises — builtin bootstrap must be called once."""
|
|
registry = AgentRegistry()
|
|
register_builtin_agents(registry)
|
|
with pytest.raises(DuplicateAgentError):
|
|
register_builtin_agents(registry)
|