mission-control-v2 / core /llm_client.py
vfven's picture
Create core/llm_client.py
c46013c verified
Raw
History Blame
2.62 kB
# core/llm_client.py
import asyncio
import httpx
from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type
from agents.registry import PROVIDERS, AGENT_REGISTRY
class LLMClient:
def __init__(self):
self.semaphore = asyncio.Semaphore(6) # evitar saturar proveedores
async def call(self, agent_key: str, messages: list, temperature: float = 0.7):
agent = AGENT_REGISTRY.get(agent_key)
if not agent:
raise ValueError(f"Agente {agent_key} no encontrado")
system_prompt = agent["role"]
provider = PROVIDERS[agent["provider"]]
full_messages = [{"role": "system", "content": system_prompt}] + messages
@retry(
stop=stop_after_attempt(5),
wait=wait_exponential(multiplier=1, min=2, max=30),
retry=retry_if_exception_type((httpx.HTTPStatusError, httpx.TimeoutException))
)
async def try_provider(base_url, model, api_key, headers):
async with self.semaphore:
payload = {
"model": model,
"messages": full_messages,
"temperature": temperature,
"max_tokens": 4096,
"top_p": 0.92
}
async with httpx.AsyncClient(timeout=90) as client:
resp = await client.post(
f"{base_url}/chat/completions",
headers={"Authorization": f"Bearer {api_key}", **headers},
json=payload
)
resp.raise_for_status()
return resp.json()["choices"][0]["message"]["content"]
# Intentar modelos del proveedor principal
for model in agent.get("models", []):
try:
return await try_provider(
provider["base_url"],
model,
provider["key"],
provider.get("headers", {})
)
except Exception as e:
print(f"Error con {model}: {e}")
# Fallback a openrouter si no es el principal
if agent["provider"] != "openrouter" and PROVIDERS["openrouter"]["key"]:
or_p = PROVIDERS["openrouter"]
for model in or_p["models"]:
try:
return await try_provider(or_p["base_url"], model, or_p["key"], or_p.get("headers", {}))
except:
continue
raise Exception("Todos los proveedores fallaron")
# Instancia global
llm = LLMClient()