fix(vision): forward custom-endpoint credentials in vision auto-detect

A custom:<name> main provider resolves at runtime to the bare provider id
"custom". In the vision auto-detect chain, the main-provider branch called
resolve_provider_client("custom", ...) WITHOUT explicit_base_url/api_key,
so it returned (None, None) ("no endpoint credentials found") and the whole
chain fell through to OpenRouter/Nous. A user on a custom endpoint with no
aggregator configured then got "No LLM provider configured for task=vision
provider=auto" on every image, even though their main model fully supports
vision.

Recover the live endpoint that set_runtime_main() records each turn
(_RUNTIME_MAIN_BASE_URL/_API_KEY/_API_MODE) and forward it to Step 1, with
a fallback to _resolve_custom_runtime() for non-gateway callers. Mirrors the
existing explicit-base_url branch directly above.

Adds TestResolveVisionCustomProvider covering custom, custom:<name>, and the
no-runtime fallback path.
This commit is contained in:
Jacky Zeng 2026-06-22 15:37:42 +08:00 committed by Teknium
parent 8bf797f1c2
commit 25aa626cb4
2 changed files with 145 additions and 1 deletions

View file

@ -4940,9 +4940,35 @@ def resolve_vision_provider_client(
main_provider,
)
else:
# Custom endpoints (``custom`` / ``custom:<name>``) carry no
# built-in base_url/api_key — resolve_provider_client("custom")
# would return None ("no endpoint credentials found") and the
# whole chain would fall through to the aggregators, breaking
# vision for every user on a custom provider that has no
# separate ``auxiliary.vision`` block. Recover the live main
# endpoint that ``set_runtime_main()`` recorded for this turn so
# Step 1 can build a working client.
rpc_base_url = None
rpc_api_key = None
rpc_api_mode = resolved_api_mode
if main_provider == "custom" or main_provider.startswith("custom:"):
if _RUNTIME_MAIN_BASE_URL:
rpc_base_url = _RUNTIME_MAIN_BASE_URL
rpc_api_key = _RUNTIME_MAIN_API_KEY or None
rpc_api_mode = resolved_api_mode or _RUNTIME_MAIN_API_MODE or None
else:
# No live runtime recorded (non-gateway caller): fall
# back to resolving the configured custom endpoint.
custom_base, custom_key, custom_mode = _resolve_custom_runtime()
if custom_base:
rpc_base_url = custom_base
rpc_api_key = custom_key
rpc_api_mode = resolved_api_mode or custom_mode or None
rpc_client, rpc_model = resolve_provider_client(
main_provider, vision_model,
api_mode=resolved_api_mode,
api_mode=rpc_api_mode,
explicit_base_url=rpc_base_url,
explicit_api_key=rpc_api_key,
is_vision=True)
if rpc_client is not None:
logger.info(