Skip to content

fix(codex): respect HERMES_CODEX_BASE_URL in all paths - #40924

Open
rjshrjndrn wants to merge 1 commit into
NousResearch:mainfrom
rjshrjndrn:main
Open

fix(codex): respect HERMES_CODEX_BASE_URL in all paths#40924
rjshrjndrn wants to merge 1 commit into
NousResearch:mainfrom
rjshrjndrn:main

Conversation

@rjshrjndrn

Copy link
Copy Markdown

The openai-codex provider hardcodes the Codex base URL in three code paths, ignoring both HERMES_CODEX_BASE_URL env var and config.yaml model.base_url. This makes proxy routing impossible.

Affected paths:

  • credential_pool._seed_from_singletons() bakes hardcoded URL into pool entries on every startup
  • runtime_provider._resolve_runtime_from_pool_entry() exits before reaching the config base_url override block
  • run_agent._swap_credential() reads pool entry base_url directly without consulting env var

Centralize resolution into resolve_codex_base_url() helper in
auth.py with priority: HERMES_CODEX_BASE_URL > pool entry >
DEFAULT_CODEX_BASE_URL. All three sites now call this helper.

Closes #40913

What does this PR do?

Adds a centralized resolve_codex_base_url() helper that makes the openai-codex provider respect HERMES_CODEX_BASE_URL across all code paths — not just the fallback
singleton resolver.

Problem: HERMES_CODEX_BASE_URL is correctly read by resolve_codex_runtime_credentials(), but that function is only the fallback path. In normal operation, the
credential pool path wins and hardcodes https://chatgpt.com/backend-api/codex in three places:

  1. _seed_from_singletons() bakes the hardcoded URL into every pool entry at startup
  2. _resolve_runtime_from_pool_entry() short-circuits before checking model.base_url from config
  3. _swap_credential() reads the pool entry's base_url directly during credential rotation

This makes it impossible to route openai-codex traffic through a proxy (Headroom, load balancer, etc.), even when the env var is correctly set.

Fix: A single resolve_codex_base_url(pool_base_url=None) helper in auth.py with a clear priority chain (env var > pool entry > default), called from all four sites.
Same class of bug as #5561 (kimi-coding pool seeding wrong base_url).

Related Issue

Fixes #

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

How to Test

  1. Start a Codex-compatible proxy on :8787 (e.g. Headroom (https://github.com/chopratejas/headroom)):
      headroom proxy --port 8787
  2. Set the env override:
      echo 'HERMES_CODEX_BASE_URL=http://localhost:8787/v1' >> ~/.hermes/.env
  3. Restart the gateway:
      systemctl --user restart hermes-gateway
  4. Send a message via Telegram/Discord and check the agent log:
      tail -10 ~/.hermes/logs/agent.log | grep base_url
    Before fix: provider=openai-codex base_url=https://chatgpt.com/backend-api/codex
    After fix: provider=openai-codex base_url=http://localhost:8787/v1
  5. Confirm credential rotation also uses the override (visible in logs after 401/429 retry):
      OpenAI client created (credential_rotation, shared=True) ... base_url=http://localhost:8787/v1
    
  6. Verify proxy received the traffic:
      curl -s http://127.0.0.1:8787/stats | python3 -c "
      import json, sys; d = json.load(sys.stdin)
      print('/v1/responses:', d['proxy_inbound']['by_path'].get('/v1/responses', 0))
      print('gpt-5.5:', d['requests']['by_model'].get('gpt-5.5', 0))
      "
    Should show non-zero counts for both.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform:

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — or N/A
  • I've updated cli-config.yaml.example if I added/changed config keys — or N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — or N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — or N/A
  • I've updated tool descriptions/schemas if I changed tool behavior — or N/A

The openai-codex provider hardcodes the Codex base URL in three
code paths, ignoring both HERMES_CODEX_BASE_URL env var and
config.yaml model.base_url. This makes proxy routing impossible.

Affected paths:
- credential_pool._seed_from_singletons() bakes hardcoded URL
  into pool entries on every startup
- runtime_provider._resolve_runtime_from_pool_entry() exits
  before reaching the config base_url override block
- run_agent._swap_credential() reads pool entry base_url
  directly without consulting env var

Centralize resolution into resolve_codex_base_url() helper in
auth.py with priority: HERMES_CODEX_BASE_URL > pool entry >
DEFAULT_CODEX_BASE_URL. All three sites now call this helper.

Closes NousResearch#40913
@alt-glitch alt-glitch added type/bug Something isn't working provider/openai OpenAI / Codex Responses API codex comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P2 Medium — degraded but workaround exists labels Jun 7, 2026
@rjshrjndrn

Copy link
Copy Markdown
Author

Hi @austinpickett Hope, its okay to loop you in. But is there something I've to improve to merge this PR?

@robinbraemer

Copy link
Copy Markdown

I hit this same bug on a live gateway today while routing openai-codex through a local Codex-compatible proxy. A few observations that may help this PR land:

  • The standard Hermes runtime already resolves openai-codex to codex_responses; the failure mode was the resolved base_url staying on https://chatgpt.com/backend-api/codex instead of the configured local endpoint.
  • In the live gateway, setting model.base_url: http://127.0.0.1:31415/backend-api/codex and patching runtime resolution made the default-profile gateway route through the proxy without switching to codex_app_server.
  • Verified live: hermes chat -q "Reply with exactly: NATIVE-SUBROUTER" returned successfully, and the proxy logged POST /backend-api/codex/responses from OpenAI/Python 2.24.0.

One gap I noticed in this PR as currently written: resolve_codex_base_url(pool_base_url=None) honors HERMES_CODEX_BASE_URL and pool URLs, but it does not appear to consume config.yaml model.base_url as the issue also requests. I opened and then closed #60198 as a duplicate, but it contains focused regression tests for the model.base_url path that may be useful here:

  • credential-pool entry with no base URL + model.provider: openai-codex + model.base_url should resolve to the configured base URL
  • singleton Codex auth fallback should also resolve to the configured base URL

Those tests passed in a clean clone with:

uv run --with pytest python -m pytest tests/hermes_cli/test_runtime_provider_resolution.py -q

If helpful, the relevant patch is in commit 6b2fa000589b64f792ea6f5ff677b37c1f7c6dc3 on robinbraemer:fix/openai-codex-config-base-url. I closed my PR to avoid competing with this one per the contribution guide.

@DeamonDev888

Copy link
Copy Markdown

This issue is part of a systemic credential resolution cascade documented in #62435, with unit test proof in PR #62434.

Root cause: (gateway/desktop path) never calls any provider-specific resolver (, , etc.). Only the auxiliary path () does. When a manual pool entry has , the override also fails due to the trap ().

Cross-provider impact: Z.AI (critical), MiniMax-CN (medium), DeepSeek (low), openai-codex (critical). 7 unit tests prove the inconsistency across 3 providers.

See #62435 for the full cascade analysis and PR #62434 for the test file.

@alt-glitch alt-glitch added comp/cli CLI entry point, hermes_cli/, setup wizard area/auth Authentication, OAuth, credential pools labels Jul 11, 2026

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for targeting a real Codex routing defect. Current main still selects a credential-pool entry before the singleton resolver (hermes_cli/runtime_provider.py:1753-1760) and then defaults Codex to the hardcoded endpoint (:418-420); pool seeding also persists that endpoint (agent/credential_pool.py:2103).

Problems

  • The proposed helper only resolves HERMES_CODEX_BASE_URL > pool URL > default. It has no model configuration input, so it cannot satisfy the PR's stated model.base_url support. Current generic config handling is in the separate else branch at hermes_cli/runtime_provider.py:480-491, which Codex never reaches.
  • tests/agent/test_resolve_codex_base_url.py tests the helper alone, not the pool-first resolver or rotation path. The affected rotation path is run_agent.py:4516-4544.

Suggested changes

  • Add the matching-provider/default-pool-url config fallback while preserving non-default pool endpoints, then cover pool resolution, singleton fallback, and rotation with regression tests.

Automated hermes-sweeper review.

@@ -308,7 +309,7 @@ def _resolve_runtime_from_pool_entry(
api_mode = "chat_completions"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This applies the environment override, but resolve_codex_base_url(base_url) cannot honor model.base_url because it receives no model configuration. Please add the matching-provider config fallback for an empty/default pool URL (while preserving a non-default pool endpoint), as the PR description and #60198 discussion require.

@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Related to the openai-codex base_url resolution cluster: fixes #40913, sibling to the raw_codex path #5875 / fix PR #5988, and the api_mode-resolution PR #56094. Independently reproduced on a live gateway by @robinbraemer.

Two notes for reviewers:

@teknium1 teknium1 added sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/auth Authentication, OAuth, credential pools codex comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/cli CLI entry point, hermes_cli/, setup wizard P2 Medium — degraded but workaround exists provider/openai OpenAI / Codex Responses API sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: openai-codex provider ignores model.base_url and HERMES_CODEX_BASE_URL in credential pool paths

5 participants