Skip to content

fix(cli): wire Anthropic model picker to live /v1/models discovery - #62986

Open
libreleee wants to merge 4 commits into
NousResearch:mainfrom
libreleee:fix/anthropic-model-picker-live-discovery
Open

fix(cli): wire Anthropic model picker to live /v1/models discovery#62986
libreleee wants to merge 4 commits into
NousResearch:mainfrom
libreleee:fix/anthropic-model-picker-live-discovery

Conversation

@libreleee

@libreleee libreleee commented Jul 12, 2026

Copy link
Copy Markdown

What does this PR do?

Wires the Anthropic model picker (hermes model / hermes fallback add) to the shared model resolver, so newly released Claude models appear without a Hermes release.

_model_flow_anthropic() in hermes_cli/model_setup_flows.py reads the static _PROVIDER_MODELS["anthropic"] list directly, bypassing the resolver that every other model-switch path already uses.

The fix is small because everything needed already exists in cached_provider_model_ids("anthropic")provider_model_ids("anthropic") (hermes_cli/models.py):

  • live /v1/models fetch via _fetch_anthropic_models()
  • curated-first merge, so newly-routed curated aliases stay visible even while the live endpoint lags
  • fallback to the same static _PROVIDER_MODELS["anthropic"] list when the live fetch fails or no credentials are configured
  • credential-fingerprinted TTL cache that hermes model --refresh invalidates explicitly

When the live fetch is unavailable, behavior is identical to today — so there is no regression surface.

Why this keeps mattering

Manual static-list updates keep falling behind. 07f39cf added claude-sonnet-5 to the curated Anthropic list, which closed #55846 — but the live Anthropic catalog now serves claude-opus-5, which the static list again omits. Every new Claude release repeats this cycle until the picker resolves the catalog rather than a hardcoded list.

Related Issue

Related to #55846 (now closed by the static-list update in 07f39cf). This PR addresses the recurrence path rather than the individual model, so future releases don't need a manual list edit.

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)

Changes Made

  • hermes_cli/model_setup_flows.py — inside _model_flow_anthropic():
    • import: _PROVIDER_MODELScached_provider_model_ids
    • model selection: _PROVIDER_MODELS.get("anthropic", [])cached_provider_model_ids("anthropic")
  • tests/cli/test_cli_provider_resolution.py — new flow-level regression test test_model_flow_anthropic_passes_live_discovery_list_to_picker

Per review feedback, the picker calls cached_provider_model_ids() (not provider_model_ids() directly) to match hermes_cli/model_switch.py and avoid a live catalog request each time hermes fallback add reuses this flow.

How to Test

  1. python -m pytest tests/cli/test_cli_provider_resolution.py -q — 24 passed
  2. Regression check: revert only the source change and keep the new test — test_model_flow_anthropic_passes_live_discovery_list_to_picker is the sole failure, confirming it pins the wiring
  3. Live path: with Anthropic credentials configured, hermes model → Anthropic lists the live catalog (13 models locally, including claude-opus-5), curated entries first
  4. Fallback path: with no credentials / live fetch failing, the picker shows exactly the curated static list — identical to current behavior

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits
  • I searched for existing PRs to make sure this isn't a duplicate — the static-list PRs patch catalogs; none wire the picker to the resolver
  • My PR contains only changes related to this fix
  • I've run the suites covering this flow — tests/cli/test_cli_provider_resolution.py (24), plus tests/hermes_cli/test_anthropic_picker_curated.py, test_anthropic_model_flow_stale_oauth.py, test_anthropic_provider_persistence.py, test_model_provider_persistence.py
  • I've added tests for my changes — flow-level regression test, verified to fail against the pre-fix wiring
  • I've tested on my platform: Ubuntu (WSL2)

Documentation & Housekeeping

  • I've updated relevant documentation — N/A (no user-facing docs describe the static-only picker behavior)
  • I've updated cli-config.yaml.example — N/A
  • I've updated CONTRIBUTING.md / AGENTS.md — N/A
  • Cross-platform impact considered — no platform-specific code; the test pins encoding="utf-8" on its config read for Windows locales
  • I've updated tool descriptions/schemas — N/A

_model_flow_anthropic() read the static _PROVIDER_MODELS["anthropic"]
list directly instead of calling provider_model_ids("anthropic"),
so new Claude releases never appeared in `hermes model` / `/model
--provider anthropic` without a Hermes code change.

provider_model_ids("anthropic") already implements everything
needed: live /v1/models fetch via _fetch_anthropic_models(),
curated-first merge so newly-routed aliases stay visible, and a
fallback to the same static _PROVIDER_MODELS["anthropic"] list
when the live fetch fails. This is a two-line change that wires
the picker flow to that existing path — behavior is identical to
today whenever the live fetch is unavailable.

Complements NousResearch#55915 and NousResearch#55853, which add claude-sonnet-5 to the
static fallback lists. NousResearch#56617 (merged) illustrates the failure
mode of manual list updates: it added anthropic/claude-sonnet-5
to the OpenRouter curated list but the native anthropic list was
missed, so the picker still omits it.

Fixes NousResearch#55846 (the recurrence path — this PR fixes the underlying
cause so future Claude releases don't need a manual list update).

@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 isolating this to the existing catalog-resolution path. The current-main premise is confirmed: hermes_cli/model_setup_flows.py:2950 bypasses provider_model_ids("anthropic"), while hermes_cli/models.py:2352-2381 already implements the live fetch, curated-first merge, and static fallback.

Problems

  • The changed integration has no direct regression coverage. tests/hermes_cli/test_anthropic_picker_curated.py:19-57 validates provider_model_ids() only, and tests/cli/test_cli_provider_resolution.py:438-471 does not assert the list passed by _model_flow_anthropic().

Suggested changes

  • Add a focused flow test that patches provider_model_ids("anthropic") to return a sentinel live-only model and verifies _prompt_model_selection() receives it.

Automated hermes-sweeper review.

Comment thread hermes_cli/model_setup_flows.py Outdated
@alt-glitch alt-glitch added type/bug Something isn't working comp/cli CLI entry point, hermes_cli/, setup wizard provider/anthropic Anthropic native Messages API P3 Low — cosmetic, nice to have labels Jul 12, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Related: this is the root-cause fix for the recurring "new Claude model missing from the picker" class — it points _model_flow_anthropic() at the existing provider_model_ids("anthropic") live /v1/models path (with the same static list as offline fallback), rather than editing the static list again. It composes cleanly with the static-list PRs #55915 / #55853 whichever lands; not a duplicate of them (different mechanism: live discovery vs manual list edits).

@teknium1 teknium1 added sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 12, 2026
…y wiring

Review feedback on NousResearch#62986 (teknium1/hermes-sweeper) noted that the
provider_model_ids("anthropic") wiring in _model_flow_anthropic() had
no direct regression coverage: test_anthropic_picker_curated.py only
validates the helper itself, and the existing model_setup_flows tests
never assert what list reaches _prompt_model_selection().

Add test_model_flow_anthropic_passes_live_discovery_list_to_picker,
which patches provider_model_ids("anthropic") with a live-only
sentinel absent from the static catalog and asserts
_prompt_model_selection() receives exactly that list. Verified this
test fails against the pre-fix code (reading _PROVIDER_MODELS
directly) and passes against the fix.
@libreleee

Copy link
Copy Markdown
Author

Added test_model_flow_anthropic_passes_live_discovery_list_to_picker in tests/cli/test_cli_provider_resolution.py (4efc29f) per @teknium1's review: it patches provider_model_ids("anthropic") with a live-only sentinel absent from the static catalog and asserts _prompt_model_selection() receives exactly that list. Confirmed it fails against the pre-fix code (reading _PROVIDER_MODELS directly) and passes against the fix.

config.yaml written by save_config() contains non-ASCII template
comments (box-drawing characters), so a bare read_text() decodes with
the platform locale and can fail on Windows (e.g. cp949). Pin
encoding="utf-8" so the final config assertion is portable.

Copy link
Copy Markdown
Author

#55846 has been resolved by 07f39cf through the static catalog update. This PR addresses a separate recurrence path by wiring the Anthropic native picker to the existing live-discovery mechanism while preserving the static fallback.

I’ve also added the requested flow-level regression test and the Windows UTF-8 portability fix. The CI workflow is currently awaiting approval. Could a maintainer approve the run when convenient?

@s-a-s-k-i-a

Copy link
Copy Markdown

Tested this fix in a current downstream integration. The picker wiring is correct, but current main now has the shared credential-aware model cache in hermes_cli.models.cached_provider_model_ids() (including explicit hermes model --refresh invalidation).

To keep the Anthropic picker aligned with the other current model-switch paths, I recommend importing and calling cached_provider_model_ids("anthropic") here instead of calling provider_model_ids("anthropic") directly. This preserves the PR's authenticated /v1/models discovery and static fallback while avoiding a live catalog request every time hermes fallback add reuses the picker.

Downstream verification after that substitution:

  • live local resolver: 13 Anthropic models, including claude-opus-5
  • picker/fallback/provider-resolution regression set: 73/73 passing
  • surrounding Anthropic whitespace, primary restore, stale-stream, gateway reload, and Telegram fallback set: 165/165 passing
  • real CLI path: OpenAI Codex primary preserved; claude-opus-5 appended as Anthropic fallback

@AIalliAI

Copy link
Copy Markdown
Contributor

Can confirm the premise on today's main (0157180): the picker behind hermes fallback add still reads the static list at model_setup_flows.py:3066, while the live Anthropic catalog serves claude-opus-5. Ran tests/cli/test_cli_provider_resolution.py with the patch applied — 30 passed. Reverting just the source change while keeping the new test, test_model_flow_anthropic_passes_live_discovery_list_to_picker is the only failure, so the regression test genuinely bites. The diff also applies with --3way onto current main despite the base drift. Small nit: the Fixes #55846 trailer and the Sonnet-5 example have gone stale — claude-sonnet-5 landed in the static list via 07f39cf.

Switch _model_flow_anthropic() from provider_model_ids("anthropic") to
cached_provider_model_ids("anthropic") so the picker matches the other
model-switch paths (hermes_cli/model_switch.py) instead of issuing a
live catalog request on every invocation.

cached_provider_model_ids() wraps the same resolver, so authenticated
/v1/models discovery and the static fallback are preserved; it adds a
credential-fingerprinted TTL cache that `hermes model --refresh`
invalidates explicitly. This matters because `hermes fallback add`
reuses this flow, which would otherwise re-fetch the catalog each time.

Suggested by @s-a-s-k-i-a in review.
@libreleee

Copy link
Copy Markdown
Author

@s-a-s-k-i-a Thanks — adopted in e039c02. The picker now calls cached_provider_model_ids("anthropic"), matching the hermes_cli/model_switch.py paths, so hermes fallback add no longer re-fetches the catalog on every reuse while keeping authenticated /v1/models discovery, the curated-first merge, and the static fallback. The regression test patches the cached resolver accordingly and still fails against the pre-fix wiring.

@AIalliAI Thanks for the independent verification, and you're right that the framing had gone stale: 07f39cf landed claude-sonnet-5 in the static list and closed #55846. I've updated the PR description — the trailer is now "Related to #55846" rather than Fixes, and the worked example is claude-opus-5, which the live catalog serves today but the static list still omits. That drift is exactly the recurrence this PR removes.

Not rebasing onto current main: the PR is still MERGEABLE despite the base drift, and a force-push would mark the resolved review thread outdated for no diff benefit. Happy to rebase if a maintainer prefers it.

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

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard P3 Low — cosmetic, nice to have provider/anthropic Anthropic native Messages 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 type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Model picker/catalog omits Claude Sonnet 5 despite Anthropic availability

5 participants