From 22ddac4b1451182cff5d6c9b6258b792baa7e9ed Mon Sep 17 00:00:00 2001 From: teknium1 Date: Tue, 28 Apr 2026 01:44:31 -0700 Subject: [PATCH] fix(auxiliary): widen URL rewrite + main_runtime to sibling custom branches Follow-up to PR #16819 applying the same treatment to the two sibling fallback sites in resolve_provider_client() that carry the identical bug class as the anonymous-custom branch: - Named custom provider (providers: / custom_providers: config entries): apply _to_openai_base_url() on the OpenAI-wire path (chat_completions / codex_responses), leave custom_base untouched on the anthropic_messages path where the /anthropic surface is intentional. Prefer main_runtime.get('model') over _read_main_model() so the entry model still wins first. The ImportError fallback for anthropic_messages now redoes query-param extraction against the rewritten URL so the final OpenAI client hits /v1. - external_process branch (copilot-acp): same main_runtime.get('model') fallback before _read_main_model() so auxiliary tasks on this provider track live /model switches instead of stale config.yaml. Keeps the fix consistent across all three custom-endpoint fallback sites in resolve_provider_client(). --- agent/auxiliary_client.py | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/agent/auxiliary_client.py b/agent/auxiliary_client.py index 246f081bc3..b2027cd42b 100644 --- a/agent/auxiliary_client.py +++ b/agent/auxiliary_client.py @@ -1895,10 +1895,22 @@ def resolve_provider_client( entry_api_mode = (api_mode or custom_entry.get("api_mode") or "").strip() if custom_base: final_model = _normalize_resolved_model( - model or custom_entry.get("model") or _read_main_model() or "gpt-4o-mini", + model + or custom_entry.get("model") + or (main_runtime.get("model") if main_runtime else None) + or _read_main_model() + or "gpt-4o-mini", provider, ) - _clean_base2, _dq2 = _extract_url_query_params(custom_base) + # anthropic_messages talks to the /anthropic surface directly; + # OpenAI-wire paths (chat_completions / codex_responses) need the + # /v1 equivalent. Rewrite only on the OpenAI-wire path so the + # Anthropic fallback SDK still sees the original URL. + if entry_api_mode == "anthropic_messages": + openai_base = custom_base + else: + openai_base = _to_openai_base_url(custom_base) + _clean_base2, _dq2 = _extract_url_query_params(openai_base) _extra2 = {"default_query": _dq2} if _dq2 else {} logger.debug( "resolve_provider_client: named custom provider %r (%s, api_mode=%s)", @@ -1917,7 +1929,12 @@ def resolve_provider_client( "installed — falling back to OpenAI-wire.", provider, ) - client = OpenAI(api_key=custom_key, base_url=_clean_base2, **_extra2) + # Fallback went OpenAI-wire after all — redo the query + # extraction against the rewritten /v1 URL. + _fallback_base = _to_openai_base_url(custom_base) + _fb_clean, _fb_dq = _extract_url_query_params(_fallback_base) + _fb_extra = {"default_query": _fb_dq} if _fb_dq else {} + client = OpenAI(api_key=custom_key, base_url=_fb_clean, **_fb_extra) return (_to_async_client(client, final_model, is_vision=is_vision) if async_mode else (client, final_model)) sync_anthropic = AnthropicAuxiliaryClient( @@ -1936,7 +1953,7 @@ def resolve_provider_client( ): client = CodexAuxiliaryClient(client, final_model) else: - client = _wrap_if_needed(client, final_model, custom_base) + client = _wrap_if_needed(client, final_model, openai_base) return (_to_async_client(client, final_model, is_vision=is_vision) if async_mode else (client, final_model)) logger.warning( @@ -2038,7 +2055,12 @@ def resolve_provider_client( if pconfig.auth_type == "external_process": creds = resolve_external_process_provider_credentials(provider) - final_model = _normalize_resolved_model(model or _read_main_model(), provider) + final_model = _normalize_resolved_model( + model + or (main_runtime.get("model") if main_runtime else None) + or _read_main_model(), + provider, + ) if provider == "copilot-acp": api_key = str(creds.get("api_key", "")).strip() base_url = str(creds.get("base_url", "")).strip()