Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 12 additions & 13 deletions agent/model_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -996,20 +996,19 @@ def get_model_context_length(
context_length = matched.get("context_length")
if isinstance(context_length, int):
return context_length
if not _is_known_provider_base_url(base_url):
# 3. Try querying local server directly
if is_local_endpoint(base_url):
local_ctx = _query_local_context_length(model, base_url)
if local_ctx and local_ctx > 0:
save_context_length(model, base_url, local_ctx)
return local_ctx
logger.info(
"Could not detect context length for model %r at %s — "
"defaulting to %s tokens (probe-down). Set model.context_length "
"in config.yaml to override.",
model, base_url, f"{DEFAULT_FALLBACK_CONTEXT:,}",
# Matched but no context_length — fall through to models.dev
# and hardcoded defaults rather than immediately defaulting to 128K.
logger.debug(
"Endpoint %s has model %r but no context_length metadata — "
"falling through to models.dev and hardcoded defaults.",
base_url, model,
)
return DEFAULT_FALLBACK_CONTEXT
# 3. Try querying local server directly (custom endpoints only)
if is_local_endpoint(base_url):
local_ctx = _query_local_context_length(model, base_url)
if local_ctx and local_ctx > 0:
save_context_length(model, base_url, local_ctx)
return local_ctx

# 4. Anthropic /v1/models API (only for regular API keys, not OAuth)
if provider == "anthropic" or (
Expand Down
1 change: 1 addition & 0 deletions agent/models_dev.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ class ProviderInfo:
"perplexity": "perplexity",
"cohere": "cohere",
"ollama-cloud": "ollama-cloud",
"ollama": "ollama-cloud",
}

# Reverse mapping: models.dev → Hermes (built lazily)
Expand Down
40 changes: 38 additions & 2 deletions tests/agent/test_model_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from agent.model_metadata import (
CONTEXT_PROBE_TIERS,
DEFAULT_CONTEXT_LENGTHS,
DEFAULT_FALLBACK_CONTEXT,
_strip_provider_prefix,
estimate_tokens_rough,
estimate_messages_tokens_rough,
Expand Down Expand Up @@ -290,7 +291,10 @@ def test_custom_endpoint_metadata_beats_fuzzy_default(self, mock_endpoint_fetch,

@patch("agent.model_metadata.fetch_model_metadata")
@patch("agent.model_metadata.fetch_endpoint_model_metadata")
def test_custom_endpoint_without_metadata_skips_name_based_default(self, mock_endpoint_fetch, mock_fetch):
def test_custom_endpoint_empty_metadata_falls_through_to_defaults(self, mock_endpoint_fetch, mock_fetch):
"""When a custom endpoint returns no model metadata at all,
resolution should fall through to models.dev and hardcoded defaults
rather than immediately defaulting to 128K (probe tier 0)."""
mock_fetch.return_value = {}
mock_endpoint_fetch.return_value = {}

Expand All @@ -300,7 +304,39 @@ def test_custom_endpoint_without_metadata_skips_name_based_default(self, mock_en
api_key="test-key",
)

assert result == CONTEXT_PROBE_TIERS[0]
# "glm" substring matches the hardcoded DEFAULT_CONTEXT_LENGTHS entry
# which returns 202752, rather than the probe-tier fallback of 128K
assert result == 202752

@patch("agent.model_metadata.fetch_model_metadata")
@patch("agent.model_metadata.fetch_endpoint_model_metadata")
def test_custom_endpoint_match_no_context_length_falls_through(self, mock_endpoint_fetch, mock_fetch):
"""Regression: when a custom endpoint lists a model but its metadata
has no context_length field, the resolver must fall through to models.dev
and hardcoded defaults instead of returning the 128K fallback.

Any OpenAI-compatible server (Ollama, Chutes, LM Studio, etc.) may
return {name: "model-name"} without context_length — the resolution
chain should keep trying rather than giving up at step 2.
"""
mock_fetch.return_value = {}
# Endpoint returns the model but with no context_length
mock_endpoint_fetch.return_value = {
"glm-5.1": {"name": "glm-5.1"}
}

result = get_model_context_length(
"glm-5.1",
# Use an unknown custom endpoint — known provider URLs skip
# the endpoint metadata block entirely, so the regression path
# wouldn't be exercised with e.g. ollama.com.
base_url="https://llm.chutes.ai/v1",
provider="custom",
)

# Should fall through to the hardcoded "glm": 202752 default,
# NOT return 128000 (DEFAULT_FALLBACK_CONTEXT)
assert result == 202752

@patch("agent.model_metadata.fetch_model_metadata")
@patch("agent.model_metadata.fetch_endpoint_model_metadata")
Expand Down
Loading