Files
wehub-resource-sync e4dcfc49aa
Tests / Import Check (Python 3.13) (push) Has been cancelled
Tests / Import Check (Python 3.14) (push) Has been cancelled
Tests / Python Tests (Python 3.11) (push) Has been cancelled
Tests / Python Tests (Python 3.12) (push) Has been cancelled
Tests / Python Tests (Python 3.14) (push) Has been cancelled
Tests / Test Summary (push) Has been cancelled
Tests / Lint and Format (push) Has been cancelled
Tests / Web Node Tests (push) Has been cancelled
Tests / Import Check (Python 3.11) (push) Has been cancelled
Tests / Import Check (Python 3.12) (push) Has been cancelled
Tests / Python Tests (Python 3.13) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:00:43 +08:00

215 lines
6.8 KiB
Python

"""Detect or suggest a model context window during settings diagnostics."""
from __future__ import annotations
from collections.abc import Callable, Iterable, Mapping
from dataclasses import dataclass
from datetime import datetime, timezone
import logging
from typing import Any
import aiohttp
from deeptutor.services.llm.config import LLMConfig
from deeptutor.services.llm.context_window import (
coerce_positive_int,
default_context_window_for_model,
)
from deeptutor.services.llm.openai_http_client import disable_ssl_verify_enabled
from deeptutor.services.llm.utils import build_auth_headers
logger = logging.getLogger(__name__)
_CONTEXT_WINDOW_KEYS = (
"context_window",
"context_window_tokens",
"context_length",
"max_context_tokens",
"max_input_tokens",
"input_token_limit",
"max_prompt_tokens",
"max_model_len",
"max_sequence_length",
)
_KNOWN_CONTEXT_WINDOWS: tuple[tuple[str, int], ...] = (("deepseek-v4", 1_000_000),)
@dataclass(frozen=True)
class ContextWindowDetectionResult:
"""Structured context-window detection output."""
context_window: int
source: str
detail: str
detected_at: str
def _model_aliases(model: str) -> set[str]:
value = (model or "").strip().lower()
if not value:
return set()
aliases = {value}
if "/" in value:
aliases.add(value.split("/", 1)[1])
if ":" in value:
aliases.add(value.split(":", 1)[1])
return {item for item in aliases if item}
def _record_identities(item: Mapping[str, Any]) -> set[str]:
aliases: set[str] = set()
for key in ("id", "model", "name"):
aliases.update(_model_aliases(str(item.get(key, "") or "")))
return aliases
def _known_context_window(model: str) -> int | None:
normalized = (model or "").strip().lower()
if not normalized:
return None
for pattern, context_window in _KNOWN_CONTEXT_WINDOWS:
if pattern in normalized:
return context_window
return None
def _recursive_context_window(value: Any) -> int | None:
if isinstance(value, Mapping):
for key in _CONTEXT_WINDOW_KEYS:
parsed = coerce_positive_int(value.get(key))
if parsed is not None:
return parsed
for nested in value.values():
parsed = _recursive_context_window(nested)
if parsed is not None:
return parsed
elif isinstance(value, list):
for nested in value:
parsed = _recursive_context_window(nested)
if parsed is not None:
return parsed
return None
def _iter_model_records(payload: Any) -> Iterable[Mapping[str, Any]]:
if isinstance(payload, list):
for item in payload:
if isinstance(item, Mapping):
yield item
return
if not isinstance(payload, Mapping):
return
for key in ("data", "models", "result", "items"):
items = payload.get(key)
if isinstance(items, list):
for item in items:
if isinstance(item, Mapping):
yield item
def _extract_context_window_from_payload(payload: Any, model: str) -> int | None:
target_aliases = _model_aliases(model)
if not target_aliases:
return None
exact_matches: list[Mapping[str, Any]] = []
partial_matches: list[Mapping[str, Any]] = []
for item in _iter_model_records(payload):
identities = _record_identities(item)
if not identities:
continue
if identities & target_aliases:
exact_matches.append(item)
continue
if any(
item_identity.endswith(f"/{alias}") or alias.endswith(f"/{item_identity}")
for item_identity in identities
for alias in target_aliases
):
partial_matches.append(item)
for item in [*exact_matches, *partial_matches]:
parsed = _recursive_context_window(item)
if parsed is not None:
return parsed
return None
async def _detect_from_models_endpoint(
llm_config: LLMConfig,
*,
on_log: Callable[[str], None] | None = None,
) -> int | None:
base_url = str(llm_config.base_url or llm_config.effective_url or "").strip()
if not base_url:
return None
url = f"{base_url.rstrip('/')}/models"
headers = build_auth_headers(llm_config.api_key, llm_config.binding)
headers.pop("Content-Type", None)
timeout = aiohttp.ClientTimeout(total=12)
connector = aiohttp.TCPConnector(ssl=False) if disable_ssl_verify_enabled() else None
try:
async with aiohttp.ClientSession(
timeout=timeout,
connector=connector,
trust_env=True,
) as session:
async with session.get(url, headers=headers) as response:
if response.status != 200:
if on_log is not None:
on_log(
f"`GET {url}` returned HTTP {response.status}; skipping metadata detection."
)
return None
payload = await response.json()
except Exception as exc:
logger.debug("Context-window metadata request failed for %s: %s", url, exc)
if on_log is not None:
on_log(f"Could not read `{url}` for context-window metadata: {exc}")
return None
return _extract_context_window_from_payload(payload, llm_config.model)
async def detect_context_window(
llm_config: LLMConfig,
*,
on_log: Callable[[str], None] | None = None,
) -> ContextWindowDetectionResult:
"""Detect the current model's context window or fall back to the runtime default."""
detected_at = datetime.now(timezone.utc).isoformat()
metadata_window = await _detect_from_models_endpoint(llm_config, on_log=on_log)
if metadata_window is not None:
return ContextWindowDetectionResult(
context_window=metadata_window,
source="metadata",
detail="Detected from provider `/models` metadata.",
detected_at=detected_at,
)
known_window = _known_context_window(llm_config.model)
if known_window is not None:
return ContextWindowDetectionResult(
context_window=known_window,
source="known_model",
detail="Matched built-in context-window metadata for this model family.",
detected_at=detected_at,
)
fallback = default_context_window_for_model(
model=llm_config.model,
max_tokens=llm_config.max_tokens,
)
return ContextWindowDetectionResult(
context_window=fallback,
source="default",
detail="Provider metadata did not expose a window; using the runtime fallback.",
detected_at=detected_at,
)
__all__ = ["ContextWindowDetectionResult", "detect_context_window"]