diff --git a/agent.py b/agent.py index 0c7ae71..9f6ae6c 100644 --- a/agent.py +++ b/agent.py @@ -69,6 +69,18 @@ class AgentReviewer(A2AAgent[ReviewerConfig, NoAuth]): if not ctx.cp_jwt or not ctx.cp_url: return {"error": "no cp_jwt; this agent must run through the orchestrator"} + creds = ctx.llm + if not creds.api_key: + return { + "error": "llm_credentials_missing", + "final": ( + "LLM credentials were not available for this review. " + "Hosted reviewer runs should receive a platform LLM grant." + ), + "agent_name": agent_name, + "ref": ref, + } + await ctx.emit_progress(f"requesting read-only Gitea token for {agent_name}@{ref}") try: mint = await ctx.mint_gitea_token( @@ -88,7 +100,6 @@ class AgentReviewer(A2AAgent[ReviewerConfig, NoAuth]): f"minted token {token_name} (read on {gitea_owner}/{agent_name})" ) - creds = ctx.llm await ctx.emit_progress(f"llm: {creds.model} via {creds.source}") completion_box: dict[str, ReviewReport] = {} diff --git a/tests/test_agent.py b/tests/test_agent.py index 454bcb5..b1ab0f4 100644 --- a/tests/test_agent.py +++ b/tests/test_agent.py @@ -11,6 +11,7 @@ ROOT = Path(__file__).resolve().parent.parent if str(ROOT) not in sys.path: sys.path.insert(0, str(ROOT)) +from a2a_pack import LocalRunContext, NoAuth # noqa: E402 from agent import AgentReviewer # noqa: E402 from agent_reviewer.tools import Finding, ReviewReport, ToolContext, build_tools # noqa: E402 from agent_reviewer.config import load_settings # noqa: E402 @@ -54,6 +55,28 @@ def test_review_report_round_trips() -> None: assert again.findings[0].severity == "critical" +@pytest.mark.asyncio +async def test_review_returns_structured_error_without_llm_credentials( + monkeypatch: pytest.MonkeyPatch, +) -> None: + monkeypatch.delenv("AGENT_LLM_KEY", raising=False) + monkeypatch.delenv("A2A_LITELLM_KEY", raising=False) + ctx = LocalRunContext(auth=NoAuth()) + ctx._cp_jwt = "jwt-123" # noqa: SLF001 + ctx._cp_url = "http://control-plane.local" # noqa: SLF001 + + async def fail_mint(*_args: object, **_kwargs: object) -> dict[str, str]: + raise AssertionError("review should not mint a Gitea token without LLM creds") + + monkeypatch.setattr(ctx, "mint_gitea_token", fail_mint) + + result = await AgentReviewer().review(ctx, agent_name="hello-agent") + + assert result["error"] == "llm_credentials_missing" + assert result["agent_name"] == "hello-agent" + assert result["ref"] == "main" + + def test_invalid_severity_rejected() -> None: with pytest.raises(Exception): Finding(