| """F-0.8 smoke test β hits the real Gemini API. |
| |
| Gated behind ENABLE_LIVE_LLM_TESTS=true. CI skips by default. |
| Run locally with: |
| cd engine && uv run pytest llm/test_gemini.py -v |
| (assumes GEMINI_API_KEY is set in engine/.env and ENABLE_LIVE_LLM_TESTS=true) |
| """ |
|
|
| import os |
|
|
| import pytest |
|
|
| from api.config import get_settings |
| from llm.client import Message, Role |
| from llm.gemini import GeminiClient |
|
|
| pytestmark = pytest.mark.skipif( |
| os.getenv("ENABLE_LIVE_LLM_TESTS", "false").lower() not in ("true", "1", "yes"), |
| reason="set ENABLE_LIVE_LLM_TESTS=true to hit the live Gemini API", |
| ) |
|
|
|
|
| @pytest.mark.asyncio |
| async def test_gemini_flash_returns_text_within_budget() -> None: |
| get_settings.cache_clear() |
| settings = get_settings() |
| assert settings.gemini_api_key, "GEMINI_API_KEY must be set in engine/.env" |
|
|
| client = GeminiClient(settings) |
|
|
| response = await client.complete( |
| role=Role.SUMMARIZER, |
| messages=[ |
| Message(role="system", content="You answer with one short word."), |
| Message(role="user", content="What color is the sky on a clear day?"), |
| ], |
| max_tokens=32, |
| temperature=0.0, |
| timeout_ms=10_000, |
| correlation_id="smoke-test-flash", |
| thinking_budget=0, |
| ) |
|
|
| assert response.raw_text.strip(), "expected non-empty response text" |
| assert response.input_tokens > 0 |
| assert response.output_tokens > 0 |
| assert response.model == settings.model_summarizer == "gemini-2.5-flash" |
| assert response.latency_ms < 10_000 |
| assert response.cost_usd >= 0.0 |
|
|
|
|
| @pytest.mark.asyncio |
| async def test_gemini_pro_reasoner_path() -> None: |
| get_settings.cache_clear() |
| settings = get_settings() |
| assert settings.gemini_api_key |
|
|
| client = GeminiClient(settings) |
|
|
| response = await client.complete( |
| role=Role.REASONER, |
| messages=[ |
| Message( |
| role="system", |
| content="Respond with one short sentence. No explanation.", |
| ), |
| Message(role="user", content="Reply with exactly: pong"), |
| ], |
| |
| |
| max_tokens=512, |
| temperature=0.0, |
| timeout_ms=45_000, |
| correlation_id="smoke-test-pro", |
| |
| |
| thinking_budget=128, |
| ) |
|
|
| assert response.raw_text.strip() |
| assert response.model == settings.model_reasoner == "gemini-2.5-pro" |
| assert "pong" in response.raw_text.lower() |
|
|