fix(context-length): restore base_url for two guarded configs (#7743)

The #7535 ownership guard skipped the global model.base_url backfill for
two shapes that master handled:

- A `model` section with `base_url` but no `provider` declares no owner,
  so `_providers_match_for_context("", <session provider>)` was false and
  the endpoint was dropped, silently falling back to 256,000 instead of
  querying the configured /v1/models (the profile-setup path writes this
  shape).
- `opencode_go` and `opencode-go` are two spellings of the same built-in
  provider, but `_canonical_context_provider` does not fold underscores,
  so the owner session lost its URL.

Allow the backfill when no owner is declared, and compare both sides
through api.config._canonicalise_provider_id, which folds `_` to `-` while
keeping distinct `custom:*` slugs distinct. The #7535 case (a custom:ark
owner vs an opencode-go session) still resolves to an empty base_url.
This commit is contained in:
webtecnica committed 2026-09-23 09:26:24 -03:00
1 parent a44e329997
commit 301ed54ab7
2 files changed
+109 -2

No files matched your search

+20 -2
View File
@@ -7189,9 +7189,27 @@ def _context_length_lookup_inputs_for_model(
# _context_length_config_api_key_for_provider). A built-in registry
# provider (empty base_url by design) must keep the slot empty so
# the registry endpoint resolves instead of another provider's URL.
#
# Two shapes cannot own the slot and therefore cannot conflict, so
# they keep master's backfill: a config that declares no provider
# at all (the profile-setup path writes model.base_url without one)
# and the two spellings of the same built-in id (opencode_go ==
# opencode-go), folded through api.config._canonicalise_provider_id
# so distinct custom:* slugs stay distinct.
_model_cfg_provider = _canonical_context_provider(model_cfg.get("provider"))
if not effective_provider or _providers_match_for_context(
_model_cfg_provider, effective_provider
_owner_provider = _model_cfg_provider
_session_provider = effective_provider
try:
from api.config import _canonicalise_provider_id as _canon_provider_id
_owner_provider = _canon_provider_id(_owner_provider) or _owner_provider
_session_provider = _canon_provider_id(_session_provider) or _session_provider
except Exception:
pass
if (
not effective_provider
or not _model_cfg_provider
or _providers_match_for_context(_owner_provider, _session_provider)
):
effective_base_url = str(model_cfg.get("base_url") or "").strip()
@@ -704,3 +704,92 @@ def test_same_provider_session_keeps_global_base_url_backfill():
assert lookup.base_url == ark_base, (
"same-owner sessions must keep the model.base_url backfill (#7535 compat)"
)
def test_base_url_only_config_without_provider_keeps_endpoint():
"""Regression (PR #7743 gate): a ``model`` section that declares
``base_url`` but NO ``provider`` has no owner that could conflict, so any
session must still receive the URL — exactly as master did. The profile
setup path writes this shape (api/profiles.py), and dropping the URL made
the lookup skip the endpoint and silently fall back to 256,000."""
from api.routes import _context_length_lookup_inputs_for_model
only_base_url = "http://127.0.0.1:9/v1"
cfg = {
"model": {
"base_url": only_base_url,
"default": "some-model",
},
}
for session_provider in ("custom", "openrouter"):
lookup = _context_length_lookup_inputs_for_model(
"some-model",
session_provider,
cfg=cfg,
)
assert lookup.provider == session_provider
assert lookup.base_url == only_base_url, (
f"a config with no declared provider owner cannot conflict with the "
f"{session_provider!r} session, so the base_url must survive the "
f"ownership guard"
)
def test_underscore_provider_owner_matches_hyphen_session():
"""Regression (PR #7743 gate): ``opencode_go`` and ``opencode-go`` are two
spellings of the SAME built-in provider, so the owner session must still
receive ``model.base_url``. Comparing the ids through the repo's
canonicaliser folds the underscore without collapsing distinct
``custom:*`` slugs."""
from api.routes import _context_length_lookup_inputs_for_model
owner_base = "http://127.0.0.1:9/v1"
cfg = {
"model": {
"provider": "opencode_go",
"base_url": owner_base,
"default": "some-model",
},
}
lookup = _context_length_lookup_inputs_for_model(
"some-model",
"opencode-go",
cfg=cfg,
)
assert lookup.provider == "opencode-go"
assert lookup.base_url == owner_base, (
"opencode_go and opencode-go are the same built-in provider, so the "
"owner session must keep the base_url backfill"
)
def test_underscore_provider_still_blocks_distinct_custom_owner():
"""Counterpart to test_underscore_provider_owner_matches_hyphen_session:
folding underscores must not open the #7535 guard. ``custom:my_box`` and a
session on the unrelated built-in ``opencode-go`` are still different
providers, so the custom owner's URL stays out of the registry slot."""
from api.routes import _context_length_lookup_inputs_for_model
cfg = {
"model": {
"provider": "custom:my_box",
"base_url": "http://127.0.0.1:9/v1",
"default": "some-model",
},
}
lookup = _context_length_lookup_inputs_for_model(
"some-model",
"opencode-go",
cfg=cfg,
)
assert lookup.provider == "opencode-go"
assert lookup.base_url == "", (
"underscore folding must not let a distinct custom provider's "
"base_url leak onto another provider's session (#7535 guard)"
)