from typing import cast import pytest from agentci.engine.model import Job, JobKind from agentci.engine.run import JobRun from agentci.workflows import dispatch as dispatch_module from agentci.workflows.services import WorkflowServices ROUTES = [ (JobKind.PLAN, "create_plan"), (JobKind.DISCUSS, "discuss_plan"), (JobKind.ITERATE_PLAN, "iterate_plan"), (JobKind.IMPLEMENT, "implement"), (JobKind.ITERATE_IMPLEMENT, "iterate_implementation"), (JobKind.FIX, "fix_pull_request"), ] def make_job(kind: JobKind | None) -> Job: return Job( id="job-1", kind=kind, target_key="org/repo:issue:7", repo_owner="org", repo_name="repo", issue_number=7, pr_number=None, requester="alice", comment_id=11, delivery_id="delivery-1", receive_sequence=1, command_body="/agent plan", message="request", ) @pytest.mark.parametrize(("kind", "expected_route"), ROUTES) async def test_dispatch_routes_every_job_kind_and_returns_body( monkeypatch: pytest.MonkeyPatch, kind: JobKind, expected_route: str, ) -> None: assert {route_kind for route_kind, _ in ROUTES} == set(JobKind) calls: list[tuple[str, Job]] = [] def route(name: str): async def invoke(job: Job, _run: JobRun, _services: WorkflowServices) -> str: calls.append((name, job)) return f"body from {name}" return invoke for _, name in ROUTES: monkeypatch.setattr(dispatch_module, name, route(name)) job = make_job(kind) body = await dispatch_module.dispatch( job, cast(JobRun, object()), cast(WorkflowServices, object()), ) assert body == f"body from {expected_route}" assert calls == [(expected_route, job)] async def test_dispatch_rejects_unparsed_command() -> None: with pytest.raises(RuntimeError, match="Cannot dispatch an unparsed command"): await dispatch_module.dispatch( make_job(None), cast(JobRun, object()), cast(WorkflowServices, object()), )