From e7faa34199f553d2b1d30c4009856a983cc87707 Mon Sep 17 00:00:00 2001 From: MiniMax-M3 Date: Mon, 22 Jun 2026 11:20:28 +0800 Subject: [PATCH] fix(model_tools): honor model.context_length to skip OpenRouter probe on banner _cli's show_banner() calls _resolve_active_context_length() at every startup. For non-OpenRouter providers (e.g. minimax-cn, kimi-coding, custom endpoints) the resolver falls through to step 6 (OpenRouter live /models fetch), which blocks ~2-3s per CLI launch and adds up to 7+ minutes when openrouter.ai is unreachable through a proxy that 403s CONNECT (#46620). Two complementary changes: 1. model_tools.py: read model.context_length from config.yaml and pass it as config_context_length to get_model_context_length. The step-0 config override short-circuits the entire resolution chain including the OpenRouter fetch. No network call is made when the user has set the value explicitly. 2. agent/model_metadata.py: replace flat timeout=10 with (5, 10) tuple at all five sites (fetch_model_metadata + four endpoint probes). urllib3 can otherwise block for 10s per retry stage through proxies that 403 CONNECT. The tuple bounds connect at 5s while still allowing slow reads. Complements the in-flight PR #46685 (which adds HERMES_DISABLE_MODEL_METADATA env var + same timeout tuple change for fetch_model_metadata). This PR extends the timeout fix to the other four endpoint probes and adds the config-override path that addresses the slow-but-reachable scenario where env-var disable is too heavy-handed. Refs #46620, PR #46685. --- agent/model_metadata.py | 13 ++++++++----- model_tools.py | 8 +++++++- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/agent/model_metadata.py b/agent/model_metadata.py index 4493eae5f1f..01a96a735cd 100644 --- a/agent/model_metadata.py +++ b/agent/model_metadata.py @@ -700,7 +700,10 @@ def fetch_model_metadata(force_refresh: bool = False) -> Dict[str, Dict[str, Any return _model_metadata_cache try: - response = requests.get(OPENROUTER_MODELS_URL, timeout=10, verify=_resolve_requests_verify()) + # Tuple (connect, read) — flat timeout=10 means urllib3 can block 10s per + # retry stage through proxies that 403 CONNECT, ballooning to minutes + # (#46620). 5s connect / 10s read fails fast on unreachable hosts. + response = requests.get(OPENROUTER_MODELS_URL, timeout=(5, 10), verify=_resolve_requests_verify()) response.raise_for_status() data = response.json() @@ -778,7 +781,7 @@ def fetch_endpoint_model_metadata( response = requests.get( server_url.rstrip("/") + "/api/v1/models", headers=headers, - timeout=10, + timeout=(5, 10), verify=_resolve_requests_verify(), ) response.raise_for_status() @@ -826,7 +829,7 @@ def fetch_endpoint_model_metadata( for candidate in candidates: url = candidate.rstrip("/") + "/models" try: - response = requests.get(url, headers=headers, timeout=10, verify=_resolve_requests_verify()) + response = requests.get(url, headers=headers, timeout=(5, 10), verify=_resolve_requests_verify()) response.raise_for_status() payload = response.json() cache: Dict[str, Dict[str, Any]] = {} @@ -1406,7 +1409,7 @@ def _query_anthropic_context_length(model: str, base_url: str, api_key: str) -> "x-api-key": api_key, "anthropic-version": "2023-06-01", } - resp = requests.get(url, headers=headers, timeout=10, verify=_resolve_requests_verify()) + resp = requests.get(url, headers=headers, timeout=(5, 10), verify=_resolve_requests_verify()) if resp.status_code != 200: return None data = resp.json() @@ -1473,7 +1476,7 @@ def _fetch_codex_oauth_context_lengths(access_token: str) -> Dict[str, int]: resp = requests.get( "https://chatgpt.com/backend-api/codex/models?client_version=1.0.0", headers={"Authorization": f"Bearer {access_token}"}, - timeout=10, + timeout=(5, 10), verify=_resolve_requests_verify(), ) if resp.status_code != 200: diff --git a/model_tools.py b/model_tools.py index 0618138aa9a..5c1338f7fe1 100644 --- a/model_tools.py +++ b/model_tools.py @@ -552,7 +552,13 @@ def _resolve_active_context_length() -> int: if not model_id: return 0 from agent.model_metadata import get_model_context_length - return int(get_model_context_length(model_id) or 0) + # Honor explicit `model.context_length` in config.yaml — short-circuits + # the OpenRouter /models probe at get_model_context_length step 0, so + # non-OpenRouter providers don't pay the ~2-3s OpenRouter fetch at every + # CLI startup. See issue #46620. + raw_ctx = model_cfg.get("context_length") + config_ctx = raw_ctx if isinstance(raw_ctx, int) and raw_ctx > 0 else None + return int(get_model_context_length(model_id, config_context_length=config_ctx) or 0) except Exception as e: logger.debug("Could not resolve active context length: %s", e) return 0