"""app/internal/llm.py: provider follows the model name (2026-11-08 consolidation).""" from types import SimpleNamespace from unittest.mock import patch from app.config import settings from app.internal import llm def test_provider_follows_model_name(): assert llm.provider_for("gpt-4o-mini") == "openai" assert llm.provider_for("gemini-3.6-flash") == "gemini" def test_available_checks_the_right_key(): with patch.object(settings, "openai_api_key", "k"), patch.object(settings, "gemini_api_key", None): assert llm.available("gpt-4o-mini") and not llm.available("gemini-3.6-flash") def test_defaults_are_openai(): assert llm.provider_for(settings.corr_cheap_model) == "openai" assert llm.provider_for(settings.transcript_correction_model) == "openai" def test_openai_path_parses_json_and_records_usage(): resp = SimpleNamespace( choices=[SimpleNamespace(message=SimpleNamespace(content='{"action": "new"}'))], usage=SimpleNamespace(prompt_tokens=120, completion_tokens=9), ) calls = {} class FakeClient: def __init__(self): self.chat = SimpleNamespace(completions=SimpleNamespace(create=self.create)) def create(self, **kw): calls.update(kw) return resp sink = {} tok = llm.collect_usage(sink) try: with patch("app.internal.ai_clients.openai_client", FakeClient): out = llm.generate_json("gpt-4o-mini", "Return JSON", purpose="correlation") finally: llm.reset_usage(tok) assert out == {"action": "new"} assert calls["response_format"] == {"type": "json_object"} assert sink["correlation:gpt-4o-mini"] == {"calls": 1, "in": 120, "out": 9, "thinking": 0}