diff --git a/agent/auxiliary_client.py b/agent/auxiliary_client.py index 853d01b1ec..1ea6f21384 100644 --- a/agent/auxiliary_client.py +++ b/agent/auxiliary_client.py @@ -4369,6 +4369,12 @@ def _to_async_client(sync_client, model: str, is_vision: bool = False): except Exception: inferred = "" headers = _endpoint_default_headers(sync_base_url, inferred, is_vision=is_vision, xai=True) + # Headers are rebuilt from scratch here, so re-apply the OpenCode keyless policy from + # _create_openai_client: the placeholder must never ship as a bearer (see #110831). + with contextlib.suppress(Exception): + from hermes_cli.models import OPENCODE_ZEN_FREE_KEYLESS_PLACEHOLDER, opencode_zen_free_headers + if sync_client.api_key == OPENCODE_ZEN_FREE_KEYLESS_PLACEHOLDER: + headers = {**(headers or {}), **opencode_zen_free_headers()} if headers: async_kwargs["default_headers"] = headers _apply_required_codex_headers(async_kwargs, access_token=sync_client.api_key, base_url=sync_base_url) diff --git a/tests/agent/test_opencode_free_client_headers.py b/tests/agent/test_opencode_free_client_headers.py index 84c702c4e1..d75ab1824e 100644 --- a/tests/agent/test_opencode_free_client_headers.py +++ b/tests/agent/test_opencode_free_client_headers.py @@ -111,3 +111,17 @@ def test_keyless_placeholder_blanks_authorization_under_paid_opencode_profile(mo shared=False, ) assert _zen_call_headers(mock_openai).get("Authorization") == "" + + +def test_async_aux_wrapper_keeps_keyless_authorization_blank(): + """``_to_async_client`` rebuilds default_headers; the keyless placeholder must stay + blanked on the async twin too, or every async aux call ships the placeholder bearer.""" + import openai + import agent.auxiliary_client as aux + + sync_client = aux._create_openai_client(api_key="opencode-zen-free-keyless", base_url=ZEN_V1) + async_client, _ = aux._to_async_client(sync_client, "x-preview-f-free") + request = async_client._build_request( + openai._models.FinalRequestOptions.construct(method="post", url="/chat/completions", json_data={}) + ) + assert request.headers.get("authorization") == ""