"""OpenAI-compatible HTTP client, persistent per-endpoint.""" from __future__ import annotations from typing import Any from openai import OpenAI # Bound every LLM call. Without this the SDK default (600s) lets a stalled # endpoint hang the worker thread that ran the tool; enough such threads exhaust # FastMCP's pool and wedge the whole stdio server. 90s is well above a healthy # deepseek-v4-flash response yet short enough to fail fast and free the thread. DEFAULT_REQUEST_TIMEOUT = 90.0 def _resolve_timeout(endpoint_cfg: dict[str, Any]) -> float: """Per-endpoint request timeout in seconds; falls back to the bounded default.""" return float(endpoint_cfg.get("request_timeout", DEFAULT_REQUEST_TIMEOUT)) def make_client(endpoint_cfg: dict[str, Any], api_key: str) -> OpenAI: """Create a persistent OpenAI client for an endpoint.""" kwargs: dict[str, Any] = { "base_url": endpoint_cfg["base_url"], "api_key": api_key, "timeout": _resolve_timeout(endpoint_cfg), } defaults = endpoint_cfg.get("request_defaults", {}) if "extra_body" in defaults: kwargs["default_query"] = {} return OpenAI(**kwargs) class ClientPool: """Manages persistent HTTP clients per endpoint.""" def __init__(self) -> None: self._clients: dict[str, OpenAI] = {} def get(self, name: str, endpoint_cfg: dict[str, Any], api_key: str) -> OpenAI: if name not in self._clients: self._clients[name] = make_client(endpoint_cfg, api_key) return self._clients[name]