test: add scenario eval runner, recorded fixtures, and baseline comparison
This commit is contained in:
parent
3dc1af5f0c
commit
0664cc2d27
38 changed files with 6986 additions and 5 deletions
|
|
@ -4,6 +4,7 @@ from collections.abc import AsyncIterator
|
|||
from contextlib import asynccontextmanager
|
||||
from pathlib import Path
|
||||
|
||||
import httpx
|
||||
import httpx2
|
||||
import structlog
|
||||
from anthropic import AsyncAnthropic
|
||||
|
|
@ -28,6 +29,7 @@ FRONTEND_DIST = Path(__file__).parent / "static"
|
|||
def create_app(
|
||||
application_settings: Settings | None = None,
|
||||
http_transport: httpx2.AsyncBaseTransport | None = None,
|
||||
anthropic_http_client: httpx.AsyncClient | None = None,
|
||||
) -> FastAPI:
|
||||
"""Build the FastAPI app: API routes plus the built SPA on one port."""
|
||||
active_settings = application_settings or settings
|
||||
|
|
@ -48,6 +50,7 @@ def create_app(
|
|||
anthropic_client = AsyncAnthropic(
|
||||
api_key=active_settings.anthropic_api_key or "unused-demo-key",
|
||||
timeout=active_settings.llm_timeout_seconds,
|
||||
http_client=anthropic_http_client,
|
||||
)
|
||||
application.state.anthropic = anthropic_client
|
||||
application.state.recommendation_pipeline = RecommendationPipeline(
|
||||
|
|
|
|||
|
|
@ -6,8 +6,10 @@ requires-python = "==3.13.*"
|
|||
dependencies = [
|
||||
"anthropic==0.121.0",
|
||||
"fastapi>=0.116",
|
||||
"httpx>=0.28",
|
||||
"httpx2>=2.10",
|
||||
"pydantic-settings>=2.10",
|
||||
"pyyaml>=6.0",
|
||||
"structlog>=25.4",
|
||||
"uvicorn[standard]>=0.35",
|
||||
]
|
||||
|
|
@ -17,6 +19,7 @@ dev = [
|
|||
"mypy>=1.17",
|
||||
"pytest>=8.4",
|
||||
"ruff>=0.12",
|
||||
"types-pyyaml>=6.0",
|
||||
]
|
||||
|
||||
[tool.ruff]
|
||||
|
|
@ -36,4 +39,5 @@ module = ["app.domain.*", "app.ports.*", "app.pipeline.*"]
|
|||
strict = true
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = ["tests"]
|
||||
pythonpath = [".", "../eval"]
|
||||
testpaths = ["tests", "../eval/tests"]
|
||||
|
|
|
|||
|
|
@ -26,4 +26,4 @@ def test_anthropic_client_uses_configured_timeout(monkeypatch: pytest.MonkeyPatc
|
|||
response = client.get("/api/health")
|
||||
|
||||
assert response.status_code == 200
|
||||
constructor.assert_called_once_with(api_key="unused-demo-key", timeout=42.0)
|
||||
constructor.assert_called_once_with(api_key="unused-demo-key", timeout=42.0, http_client=None)
|
||||
|
|
|
|||
15
backend/uv.lock
generated
15
backend/uv.lock
generated
|
|
@ -132,8 +132,10 @@ source = { virtual = "." }
|
|||
dependencies = [
|
||||
{ name = "anthropic" },
|
||||
{ name = "fastapi" },
|
||||
{ name = "httpx" },
|
||||
{ name = "httpx2" },
|
||||
{ name = "pydantic-settings" },
|
||||
{ name = "pyyaml" },
|
||||
{ name = "structlog" },
|
||||
{ name = "uvicorn", extra = ["standard"] },
|
||||
]
|
||||
|
|
@ -143,14 +145,17 @@ dev = [
|
|||
{ name = "mypy" },
|
||||
{ name = "pytest" },
|
||||
{ name = "ruff" },
|
||||
{ name = "types-pyyaml" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "anthropic", specifier = "==0.121.0" },
|
||||
{ name = "fastapi", specifier = ">=0.116" },
|
||||
{ name = "httpx", specifier = ">=0.28" },
|
||||
{ name = "httpx2", specifier = ">=2.10" },
|
||||
{ name = "pydantic-settings", specifier = ">=2.10" },
|
||||
{ name = "pyyaml", specifier = ">=6.0" },
|
||||
{ name = "structlog", specifier = ">=25.4" },
|
||||
{ name = "uvicorn", extras = ["standard"], specifier = ">=0.35" },
|
||||
]
|
||||
|
|
@ -160,6 +165,7 @@ dev = [
|
|||
{ name = "mypy", specifier = ">=1.17" },
|
||||
{ name = "pytest", specifier = ">=8.4" },
|
||||
{ name = "ruff", specifier = ">=0.12" },
|
||||
{ name = "types-pyyaml", specifier = ">=6.0" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -580,6 +586,15 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl", hash = "sha256:adaeaecf1cbb5f4de3b1959b42d41f6fab57b2b1666adb59e89cb0b53361d981", size = 18660, upload-time = "2025-08-12T18:49:01.46Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "types-pyyaml"
|
||||
version = "6.0.12.20260724"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/3f/6f/a28f44bcd56bebed42b028a2894c79853e2f5e6b5279e633cb3f287a05e7/types_pyyaml-6.0.12.20260724.tar.gz", hash = "sha256:3c1ce1bb73cd5ec02e90390c2b1f00e810d241d8825fd73ff359696839271b6b", size = 17893, upload-time = "2026-07-24T04:58:43.453Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/8b/42/0337fefc615e20ee55d1c8f71b774a9b2b734a04669139c20753b27a2a3a/types_pyyaml-6.0.12.20260724-py3-none-any.whl", hash = "sha256:d57db930a4b2efbc57cf430ec8882765d246929432fa253092f383902329a453", size = 20312, upload-time = "2026-07-24T04:58:42.486Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.16.0"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue