Skip to content

fix: surface Codex spark models#1685

Merged
1 commit merged into
nesquena:masterfrom
Michaelyklam:fix/issue-1680-codex-spark
May 5, 2026
Merged

fix: surface Codex spark models#1685
1 commit merged into
nesquena:masterfrom
Michaelyklam:fix/issue-1680-codex-spark

Conversation

@Michaelyklam
Copy link
Copy Markdown
Contributor

Thinking Path

  • Hermes WebUI should expose the same Codex model choices a user sees in Codex itself.
  • Issue Codex spark support #1680 reports that gpt-5.3-codex-spark is present in Codex but missing from the WebUI model picker.
  • The root cause is that /api/models used WebUI's static openai-codex snapshot; the background live helper also inherits an agent filter that can drop visible Codex cache entries marked supported_in_api: false.
  • The narrow fix is to build the OpenAI Codex group from the agent Codex resolver first, then merge visible slugs from Codex's local models_cache.json before falling back to the static WebUI list.
  • Users get newly listed Codex models, including Spark, without waiting for the WebUI static catalog to be updated.

What Changed

  • Added _read_visible_codex_cache_model_ids() to read visible, non-hidden slugs from CODEX_HOME / ~/.codex/models_cache.json in priority order.
  • Changed the openai-codex /api/models group builder to use hermes_cli.models.provider_model_ids("openai-codex"), merge visible Codex cache entries, and only then fall back to _PROVIDER_MODELS.
  • Added regression tests covering both provider-model discovery and a Codex cache entry for gpt-5.3-codex-spark with supported_in_api: false.

Closes #1680.

Why It Matters

Codex model availability changes faster than the WebUI release cadence. Reading Codex's own visible catalog keeps the picker aligned with the user's installed/authenticated Codex environment and prevents newly available models like Spark from being hidden behind stale static defaults.

Verification

/home/michael/.hermes/hermes-agent/venv/bin/python -m pytest tests/test_issue1680_codex_spark.py -q
/home/michael/.hermes/hermes-agent/venv/bin/python -m pytest tests/test_issue1680_codex_spark.py tests/test_model_picker_badges.py tests/test_live_models_ttl_cache.py tests/test_issue604_all_providers_model_picker.py tests/test_issue1633_models_cache_version_stamp.py -q
git diff --check
env -u HERMES_CONFIG_PATH /home/michael/.hermes/hermes-agent/venv/bin/python -m pytest tests/ -q
env -u HERMES_CONFIG_PATH HERMES_WEBUI_HOST=127.0.0.1 /home/michael/.hermes/hermes-agent/venv/bin/python -m pytest tests/ -q
HERMES_WEBUI_STATE_DIR=/tmp/hermes-webui-issue-1680-state /home/michael/.hermes/hermes-agent/venv/bin/python - <<'PY'
from api.config import get_available_models
payload=get_available_models()
ids=[m['id'] for g in payload.get('groups',[]) if g.get('provider_id')=='openai-codex' for m in g.get('models',[])]
print('active_provider=', payload.get('active_provider'))
print('codex_count=', len(ids))
print('has_spark=', 'gpt-5.3-codex-spark' in ids)
print('codex_first_10=', ids[:10])
PY

Result:

2 passed in 1.37s
44 passed in 11.21s
git diff --check: passed
First full-suite run: 1 failed, 4478 passed, 2 skipped, 3 xpassed, 1 warning, 8 subtests passed; failure was tests/test_dashboard_probe.py::test_status_tries_default_loopback_targets_until_dashboard_found because this agent environment inherited HERMES_WEBUI_HOST=0.0.0.0.
Full-suite rerun with HERMES_WEBUI_HOST=127.0.0.1: 4479 passed, 2 skipped, 3 xpassed, 1 warning, 8 subtests passed in 405.76s.
Manual `/api/models` data check: active_provider=openai-codex, has_spark=True.

UI media:

  • Not attached; this is a backend model-catalog data fix with regression coverage and no layout/visual change.

Risks / Follow-ups

  • This reads only local Codex cache metadata and ignores hidden models; if Codex changes the cache shape, the helper fails closed and the existing provider/static fallback remains in place.
  • supported_in_api: false entries are intentionally surfaced when Codex marks them visible; if maintainers want API-supported-only picker semantics instead, Spark will remain hidden until the agent/provider contract changes.

Model Used

AI assisted.

  • Provider: OpenAI Codex
  • Model: gpt-5.5
  • Notable tool use: GitHub CLI, terminal, pytest, file editing tools

@nesquena-hermes
Copy link
Copy Markdown
Collaborator

Review

Reading the diff against origin/master and pulling the worktree at 0fe3927, this is a clean two-line story:

  1. The OpenAI Codex /api/models group is now built from hermes_cli.models.provider_model_ids("openai-codex") (which already calls get_codex_model_ids() → live chatgpt.com/backend-api/codex/models → local cache → static fallback in hermes_cli/codex_models.py:148-180).
  2. A new _read_visible_codex_cache_model_ids() helper merges visible slugs from ~/.codex/models_cache.json to recover models the agent's API helper drops via supported_in_api: false (which is exactly Spark's case in Codex spark support #1680).

api/config.py (new branch starting at the diff @ ~2723):

elif pid == "openai-codex":
    raw_models = []
    codex_ids = []
    try:
        from hermes_cli.models import provider_model_ids as _provider_model_ids
        codex_ids = [mid for mid in (_provider_model_ids("openai-codex") or []) if mid]
    except Exception:
        logger.warning("Failed to load OpenAI Codex models from hermes_cli")
    for mid in _read_visible_codex_cache_model_ids():
        if mid not in codex_ids:
            codex_ids.append(mid)
    raw_models = [{"id": mid, "label": _get_label_for_model(mid, [])} for mid in codex_ids]
    if not raw_models:
        raw_models = copy.deepcopy(_PROVIDER_MODELS.get("openai-codex", []))

This matches the ollama-cloud and nous precedents above (api/config.py:2662-2680, 2685-2710) — same pattern, same fallback discipline. Verified the agent contract: hermes_cli/models.py:1917-1932 routes openai-codex through get_codex_model_ids(access_token=...), which itself filters supported_in_api: false at codex_models.py:81-82 and 131-132. So merging the visible cache is the only way Spark surfaces today.

Two notes

1. Cache-merge contract diverges from the agent. The agent's _read_cache_models() at ~/.hermes/hermes-agent/hermes_cli/codex_models.py:131-132 excludes entries where item.get("supported_in_api") is False. Your WebUI helper deliberately keeps them — that's the whole point — but it means WebUI may surface a Codex model the user cannot send through the codex_responses API path. If the user picks Spark in the UI and the gateway routes to the Codex API which then 400s on an unsupported slug, the model_not_found error path in api/streaming.py catches it but the picker entry was misleading. Worth either (a) adding a UI badge ("Codex picker only") for those merged-from-cache entries, or (b) leaving a CHANGELOG note that Spark may not work in API-mode sessions until the agent flips Spark's supported_in_api. The PR description ("Risks / Follow-ups") already acknowledges this — no action required, just flagging for the merge note.

2. CODEX_HOME env precedence. The helper at _read_visible_codex_cache_model_ids() reads CODEX_HOME env first, then falls back to ~/.codex. That matches hermes_cli/codex_models.py:152-153. ✅

Tests

tests/test_issue1680_codex_spark.py (104 lines, two tests) covers both branches:

  • test_openai_codex_group_uses_provider_model_ids_for_spark — agent-resolved live IDs flow through, including a Spark-shaped slug.
  • test_openai_codex_group_merges_visible_codex_cache_models — Spark shows up via the cache-merge path even when supported_in_api: false, and visibility: hide entries are filtered (correctly mirroring the agent helper's hidden filter at codex_models.py:83-85).

The tests are well-scoped and the _install_fake_hermes_models shim (creating fake hermes_cli and hermes_cli.models modules) is the same trick the existing live-models test files use.

Verdict

LGTM. The fix is narrow, mirrors existing live-fetch precedents, fails closed if the cache is missing or malformed, and has regression coverage for both the live-id and cache-merge paths. Closes #1680.

@nesquena-hermes nesquena-hermes closed this pull request by merging all changes into nesquena:master in 4daa238 May 5, 2026
Michaelyklam pushed a commit to Michaelyklam/hermes-webui that referenced this pull request May 5, 2026
Michaelyklam added a commit to Michaelyklam/hermes-webui that referenced this pull request May 5, 2026
10 PRs (3 surfaces additions, 7 fixes):
- nesquena#1644 model picker chip + group count (@bergeouss, closes nesquena#1425)
- nesquena#1684 update network failures UX (@Michaelyklam, closes nesquena#1321)
- nesquena#1685 Codex spark models (@Michaelyklam, closes nesquena#1680)
- nesquena#1689 normalize profile base homes (@Michaelyklam, refs nesquena#749)
- nesquena#1693 adaptive title refresh deadlock (@ai-ag2026)
- nesquena#1701 normalize update banner URL (@Michaelyklam, closes nesquena#1691)
- nesquena#1702 workspace double-click rename (@Michaelyklam, closes nesquena#1698)
- nesquena#1703 cache invalidation on auth-store drift (@Michaelyklam, closes nesquena#1699)
- nesquena#1704 markdown fence lengths (@Michaelyklam, closes nesquena#1696)
- nesquena#1706 multi-image paste fix (@Michaelyklam, closes nesquena#1697)

Tests: 4477 → 4503 (+26). Opus: SHIP, 7/7 verification clean.

Co-authored-by: Michael Lam <Michaelyklam1@gmail.com>
Co-authored-by: ai-ag2026 <noreply@github.com>
Co-authored-by: bergeouss <noreply@github.com>
@nesquena-hermes
Copy link
Copy Markdown
Collaborator

Closed by the v0.51.4 release in PR #1707 (merged at 4daa238, deployed to production).

Live on production: https://github.com/nesquena/hermes-webui/releases/tag/v0.51.4

🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Codex spark support

2 participants