fix(provider): bound OpenAI-compatible request timeouts

This commit is contained in:
hanyuanling
2026-04-27 17:47:31 +08:00
committed by Xubin Ren
parent b8932bc041
commit 9dc99d1b34
2 changed files with 77 additions and 0 deletions
@@ -60,6 +60,7 @@ _KIMI_THINKING_MODELS: frozenset[str] = frozenset({
"kimi-k2.6",
"k2.6-code-preview",
})
_OPENAI_COMPAT_REQUEST_TIMEOUT_S = 120.0
# Maps ProviderSpec.thinking_style → extra_body builder.
# Each builder takes a bool (thinking_enabled) and returns the dict to
@@ -90,6 +91,26 @@ def _is_kimi_thinking_model(model_name: str) -> bool:
return False
def _openai_compat_timeout_s() -> float:
"""Return the bounded request timeout used for OpenAI-compatible providers."""
return _float_env("NANOBOT_OPENAI_COMPAT_TIMEOUT_S", _OPENAI_COMPAT_REQUEST_TIMEOUT_S)
def _float_env(name: str, default: float) -> float:
raw = os.environ.get(name)
if raw is None or not raw.strip():
return default
try:
value = float(raw)
except (TypeError, ValueError):
logger.warning("Ignoring invalid {}={!r}; using {}", name, raw, default)
return default
if value <= 0:
logger.warning("Ignoring non-positive {}={!r}; using {}", name, raw, default)
return default
return value
def _short_tool_id() -> str:
"""9-char alphanumeric ID compatible with all providers (incl. Mistral)."""
return "".join(secrets.choice(_ALNUM) for _ in range(9))
@@ -251,10 +272,12 @@ class OpenAICompatProvider(LLMProvider):
# opening a fresh connection for each request, which is cheap on a
# LAN. Cloud providers benefit from keepalive, so we leave the
# default pool settings for them.
timeout_s = _openai_compat_timeout_s()
http_client: httpx.AsyncClient | None = None
if _is_local_endpoint(spec, effective_base):
http_client = httpx.AsyncClient(
limits=httpx.Limits(keepalive_expiry=0),
timeout=timeout_s,
)
self._client = AsyncOpenAI(
@@ -262,6 +285,7 @@ class OpenAICompatProvider(LLMProvider):
base_url=effective_base,
default_headers=default_headers,
max_retries=0,
timeout=timeout_s,
http_client=http_client,
)