"""Tests for POST /agent/run — uses a stub orchestrator factory.""" from __future__ import annotations from typing import Any from unittest.mock import patch import pytest from fastapi.testclient import TestClient from src.agents.schemas import AgentResult, ToolTraceItem from src.api.main import app client = TestClient(app) class _FakeOrchestrator: """Returns a canned AgentResult; ignores input.""" def __init__(self, *args: Any, **kwargs: Any) -> None: pass def run(self, user_input: str, context: dict[str, Any] | None = None) -> AgentResult: return AgentResult( text=f"Synthesized answer for: {user_input}", trace=[ ToolTraceItem(name="run_bbb_pipeline", args={"smiles": user_input}, result={"label": 1, "label_text": "permeable"}), ToolTraceItem(name="retrieve_context", args={"query": "BBB"}, result={"chunks": []}), ], model="stub-model", finish_reason="complete", ) class TestAgentRoute: def test_post_returns_synthesized_text_and_trace(self) -> None: with patch("src.api.routes._build_orchestrator", return_value=_FakeOrchestrator()): r = client.post("/agent/run", json={"user_input": "CCO"}) assert r.status_code == 200 body = r.json() assert "Synthesized answer for: CCO" in body["text"] assert len(body["trace"]) == 2 assert body["trace"][0]["name"] == "run_bbb_pipeline" assert body["model"] == "stub-model" assert body["finish_reason"] == "complete" def test_empty_user_input_422(self) -> None: r = client.post("/agent/run", json={"user_input": ""}) assert r.status_code == 422 def test_missing_user_input_422(self) -> None: r = client.post("/agent/run", json={}) assert r.status_code == 422