"""LLM provider registry and non-streaming call helpers.""" from __future__ import annotations import httpx class RateLimitError(Exception): """Raised when all attempted providers return HTTP 429.""" _PROVIDERS: dict[str, dict] = { "groq": {"env": "GROQ_API_KEY", "model": "llama-3.3-70b-versatile"}, "mistral": {"env": "MISTRAL_API_KEY", "model": "codestral-latest"}, "gemini": {"env": "GEMINI_API_KEY", "model": "gemini-2.0-flash"}, "cohere": {"env": "COHERE_API_KEY", "model": "command-r-plus-08-2024"}, } def get_provider_cfg(provider: str) -> dict: return _PROVIDERS.get(provider, _PROVIDERS["groq"]) async def _call_groq(prompt: str, model: str, key: str) -> str: async with httpx.AsyncClient(timeout=30) as client: resp = await client.post( "https://api.groq.com/openai/v1/chat/completions", headers={"Authorization": f"Bearer {key}", "Content-Type": "application/json"}, json={ "model": model, "messages": [{"role": "user", "content": prompt}], "stream": False, "max_tokens": 512, "temperature": 0.1, }, ) if resp.status_code == 429: raise RateLimitError("groq") resp.raise_for_status() return resp.json()["choices"][0]["message"]["content"] async def _call_gemini(prompt: str, model: str, key: str) -> str: url = ( f"https://generativelanguage.googleapis.com/v1beta/models/" f"{model}:generateContent?key={key}" ) async with httpx.AsyncClient(timeout=30) as client: resp = await client.post( url, json={ "contents": [{"role": "user", "parts": [{"text": prompt}]}], "generationConfig": {"maxOutputTokens": 512, "temperature": 0.1}, }, ) if resp.status_code == 429: raise RateLimitError("gemini") resp.raise_for_status() return resp.json()["candidates"][0]["content"]["parts"][0]["text"] async def _call_mistral(prompt: str, model: str, key: str) -> str: async with httpx.AsyncClient(timeout=30) as client: resp = await client.post( "https://api.mistral.ai/v1/chat/completions", headers={"Authorization": f"Bearer {key}", "Content-Type": "application/json"}, json={ "model": model, "messages": [{"role": "user", "content": prompt}], "stream": False, "max_tokens": 512, "temperature": 0.1, }, ) if resp.status_code == 429: raise RateLimitError("mistral") resp.raise_for_status() return resp.json()["choices"][0]["message"]["content"] async def _call_cohere(prompt: str, model: str, key: str) -> str: async with httpx.AsyncClient(timeout=30) as client: resp = await client.post( "https://api.cohere.ai/v2/chat", headers={"Authorization": f"Bearer {key}", "Content-Type": "application/json"}, json={ "model": model, "messages": [{"role": "user", "content": prompt}], "stream": False, "max_tokens": 512, "temperature": 0.1, }, ) if resp.status_code == 429: raise RateLimitError("cohere") resp.raise_for_status() return resp.json()["message"]["content"][0]["text"] _CALLERS = { "groq": _call_groq, "mistral": _call_mistral, "gemini": _call_gemini, "cohere": _call_cohere, } async def call_provider(provider: str, prompt: str, model: str, key: str) -> str: """Dispatch a prompt to the named provider (unknown names fall back to groq).""" fn = _CALLERS.get(provider, _call_groq) return await fn(prompt, model, key)