fix(agent): honor auxiliary.<task>.base_url/api_key when provider is passed explicitly

_resolve_task_provider_model returns early on an explicit provider arg,
which skips the config block that consults auxiliary.<task>.base_url /
api_key. Any caller passing provider explicitly (e.g.
resolve_vision_provider_client(provider="custom", ...)) bypasses the
configured custom endpoint and falls through to main-runtime resolution,
silently routing the task to the wrong backend.

Adopt the task's configured base_url/api_key before the early returns,
but only when no explicit base_url was given and the config targets the
same provider (or names none) — a caller forcing a *different* provider
keeps full explicit-arg priority, and an explicit base_url still wins
over config.

Fixes #58515
This commit is contained in:
falkoro 2026-07-05 00:00:33 +02:00 committed by Teknium
parent e985e34659
commit 9ad912a791
2 changed files with 118 additions and 0 deletions

View file

@ -5532,6 +5532,18 @@ def _resolve_task_provider_model(
if cfg_provider:
cfg_provider, cfg_base_url = _expand_direct_api_alias(cfg_provider, cfg_base_url)
# An explicit provider arg without an explicit base_url must not bypass
# the task's configured endpoint: adopt auxiliary.<task>.base_url/api_key
# when the config targets the same provider (or names none), so the
# early `if provider:` return below carries the configured endpoint
# instead of falling through to main-runtime resolution (#58515).
# An explicit "auto" is excluded — it means "inherit / auto-detect" and
# must keep flowing through the existing auto-resolution chain.
if provider and provider != "auto" and not base_url and cfg_base_url and cfg_provider in (None, provider):
base_url = cfg_base_url
if not api_key:
api_key = cfg_api_key
if base_url and _preserve_provider_with_base_url(provider):
return provider, resolved_model, base_url, api_key, resolved_api_mode
if base_url:

View file

@ -168,6 +168,112 @@ class TestResolveTaskProviderModel:
assert api_key == "sk-test"
assert api_mode is None
def test_explicit_provider_adopts_configured_task_endpoint(self):
"""Explicit provider matching the configured one must not bypass
auxiliary.<task>.base_url/api_key (#58515)."""
task_config = {
"provider": "custom",
"model": "meta/llama-3.2-11b-vision-instruct",
"base_url": "https://integrate.api.nvidia.com/v1",
"api_key": "nvapi-secret",
}
with patch("agent.auxiliary_client._get_auxiliary_task_config", return_value=task_config):
resolved_provider, model, base_url, api_key, api_mode = _resolve_task_provider_model(
task="vision",
provider="custom",
model="meta/llama-3.2-11b-vision-instruct",
)
assert resolved_provider == "custom"
assert base_url == "https://integrate.api.nvidia.com/v1"
assert api_key == "nvapi-secret"
assert model == "meta/llama-3.2-11b-vision-instruct"
assert api_mode is None
def test_explicit_provider_adopts_endpoint_when_config_names_no_provider(self):
task_config = {
"base_url": "https://nim.example/v1",
"api_key": "cfg-key",
}
with patch("agent.auxiliary_client._get_auxiliary_task_config", return_value=task_config):
resolved_provider, model, base_url, api_key, api_mode = _resolve_task_provider_model(
task="vision",
provider="custom",
)
assert resolved_provider == "custom"
assert base_url == "https://nim.example/v1"
assert api_key == "cfg-key"
def test_explicit_first_class_provider_with_matching_config_keeps_identity(self):
task_config = {
"provider": "anthropic",
"base_url": "https://anthropic-proxy.example/v1",
"api_key": "cfg-key",
}
with patch("agent.auxiliary_client._get_auxiliary_task_config", return_value=task_config):
resolved_provider, model, base_url, api_key, api_mode = _resolve_task_provider_model(
task="compression",
provider="anthropic",
)
assert resolved_provider == "anthropic"
assert base_url == "https://anthropic-proxy.example/v1"
assert api_key == "cfg-key"
def test_explicit_auto_provider_keeps_auto_resolution(self):
"""provider="auto" is a sentinel for "inherit / auto-detect" and must
not adopt the configured endpoint the auto chain owns resolution."""
task_config = {
"base_url": "https://nim.example/v1",
"api_key": "cfg-key",
}
with patch("agent.auxiliary_client._get_auxiliary_task_config", return_value=task_config):
resolved_provider, model, base_url, api_key, api_mode = _resolve_task_provider_model(
task="vision",
provider="auto",
)
assert resolved_provider == "auto"
assert base_url is None
assert api_key is None
def test_explicit_provider_differing_from_config_ignores_config_endpoint(self):
"""A caller forcing a different provider keeps full explicit-arg
priority the configured endpoint belongs to cfg_provider only."""
task_config = {
"provider": "custom",
"base_url": "https://nim.example/v1",
"api_key": "cfg-key",
}
with patch("agent.auxiliary_client._get_auxiliary_task_config", return_value=task_config):
resolved_provider, model, base_url, api_key, api_mode = _resolve_task_provider_model(
task="vision",
provider="nous",
)
assert resolved_provider == "nous"
assert base_url is None
assert api_key is None
def test_explicit_provider_and_base_url_still_win_over_config(self):
task_config = {
"provider": "custom",
"base_url": "https://configured.example/v1",
"api_key": "cfg-key",
}
with patch("agent.auxiliary_client._get_auxiliary_task_config", return_value=task_config):
resolved_provider, model, base_url, api_key, api_mode = _resolve_task_provider_model(
task="vision",
provider="custom",
base_url="https://explicit.example/v1",
api_key="explicit-key",
)
assert resolved_provider == "custom"
assert base_url == "https://explicit.example/v1"
assert api_key == "explicit-key"
class TestBuildCallKwargsMaxTokens:
"""_build_call_kwargs should not cap output by default (#34530).