From 9336fb11cd63f7b7bd11cbaf9389649b4f1f2936 Mon Sep 17 00:00:00 2001 From: teknium1 <127238744+teknium1@users.noreply.github.com> Date: Mon, 14 Sep 2026 21:16:16 -0700 Subject: [PATCH] fix: honour HERMES_CODEX_BASE_URL on the raw Codex client too The raw_codex branch of _resolve_openai_codex_branch (main agent built without explicit creds via agent_init._routed_client_kwargs, and the mid-turn fallback chain) still hardcoded the official Codex endpoint while the pooled/aux/singleton paths honoured the override, so a proxy user's main agent silently bypassed it. Hoist the profile-scoped read into _codex_base_url_override and use it in both builders; the Cloudflare identity headers follow the resolved base_url. Review finding: raw_codex client ignored HERMES_CODEX_BASE_URL while pooled/aux/singleton honoured it. --- agent/auxiliary_client.py | 15 ++++++++++----- tests/agent/test_auxiliary_client.py | 16 ++++++++++++++++ 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/agent/auxiliary_client.py b/agent/auxiliary_client.py index 045bf64c11..b01b764098 100644 --- a/agent/auxiliary_client.py +++ b/agent/auxiliary_client.py @@ -2774,6 +2774,12 @@ def _build_xai_oauth_aux_client(model: str) -> Tuple[Optional[Any], Optional[str return CodexAuxiliaryClient(real_client, model), model +def _codex_base_url_override() -> str: + """Profile-scoped ``HERMES_CODEX_BASE_URL`` (same read as the API-key env vars: under a + multiplexer the routed profile's .env decides the endpoint, never a sibling's process env).""" + return _scoped_key_env("HERMES_CODEX_BASE_URL").rstrip("/") + + def _build_codex_client(model: str) -> Tuple[Optional[Any], Optional[str]]: """CodexAuxiliaryClient for an explicit model; (None, None) without a Codex OAuth token. @@ -2787,9 +2793,7 @@ def _build_codex_client(model: str) -> Tuple[Optional[Any], Optional[str]]: return None, None pool_present, entry = _select_pool_entry("openai-codex") codex_token = _pool_runtime_api_key(entry) if pool_present else None - # Same profile-scoped read as the API-key env vars: under a multiplexer the routed profile's - # .env decides the endpoint, never a sibling profile's process env. - codex_override = _scoped_key_env("HERMES_CODEX_BASE_URL").rstrip("/") + codex_override = _codex_base_url_override() if codex_token: base_url = codex_override or _pool_runtime_base_url(entry, _CODEX_AUX_BASE_URL) or _CODEX_AUX_BASE_URL else: @@ -4672,8 +4676,9 @@ def _resolve_openai_codex_branch(req: _ResolveRequest) -> _ResolveResult: if not codex_token: logger.warning(no_token_msg) return None, None - raw_client = _create_openai_client(api_key=codex_token, base_url=_CODEX_AUX_BASE_URL, - default_headers=_codex_cloudflare_headers(codex_token)) + base_url = _codex_base_url_override() or _CODEX_AUX_BASE_URL + raw_client = _create_openai_client(api_key=codex_token, base_url=base_url, + default_headers=_codex_cloudflare_headers(codex_token, base_url=base_url)) return raw_client, _normalize_resolved_model(model, req.provider) client, default = _build_codex_client(model) return _route_or_warn(req, client, default, no_token_msg) diff --git a/tests/agent/test_auxiliary_client.py b/tests/agent/test_auxiliary_client.py index c25064cd44..8f53381a99 100644 --- a/tests/agent/test_auxiliary_client.py +++ b/tests/agent/test_auxiliary_client.py @@ -744,6 +744,22 @@ class TestBuildCodexClient: assert model == "gpt-5.4" assert mock_openai.call_args.kwargs["base_url"] == "http://127.0.0.1:8787/v1" + def test_profile_codex_base_url_applies_to_raw_codex_client(self, monkeypatch): + """The main agent's raw Codex client honours the same endpoint override.""" + with ( + patch("agent.auxiliary_client._read_codex_access_token", return_value="codex-auth-token"), + patch("agent.auxiliary_client.OpenAI") as mock_openai, + ): + monkeypatch.setenv("HERMES_CODEX_BASE_URL", "http://127.0.0.1:8787/v1") + mock_openai.return_value = MagicMock() + from agent.auxiliary_client import resolve_provider_client + + client, model = resolve_provider_client("openai-codex", "gpt-5.4", raw_codex=True) + + assert client is not None + assert model == "gpt-5.4" + assert mock_openai.call_args.kwargs["base_url"] == "http://127.0.0.1:8787/v1" + def test_rejects_missing_model(self): """Callers must pass an explicit model; no hardcoded default.""" from agent.auxiliary_client import _build_codex_client