Skip to content

fix(model-picker): handle list-of-dict models: in provider config - #55770

Closed
iambuddy829-del wants to merge 1 commit into
NousResearch:mainfrom
iambuddy829-del:fix/model-picker-dict-models
Closed

fix(model-picker): handle list-of-dict models: in provider config#55770
iambuddy829-del wants to merge 1 commit into
NousResearch:mainfrom
iambuddy829-del:fix/model-picker-dict-models

Conversation

@iambuddy829-del

Copy link
Copy Markdown

Summary

The desktop model picker was empty with Error: 500: {"detail":"Failed to list model options"} (Settings → Model and the composer dropdown). GET /api/model/options was throwing:

File hermes_cli/inventory.py, line 188, in build_models_payload
    user_models.update(m.lower() for m in (row.get("models") or []))
AttributeError: 'dict' object has no attribute 'lower'

Root cause

build_models_payload and its downstream consumers (inventory dedup, _apply_capabilities, _apply_pricing) all assume each provider row's models is a list[str] of model ids — they call m.lower() and use the ids as dict keys.

list_authenticated_providers builds user-provider rows from providers.<p>.models in config.yaml. It handles two shapes (per its own comment): the dict-keyed-by-id form Hermes writes, and a plain list-of-strings form. But a hand-edited config using the list-of-{id, label} dicts form:

providers:
  cerebras:
    models:
      - id: zai-glm-4.7
        label: GLM 4.7 (Cerebras)

fell into the list branch, which appended each entry verbatim — putting dicts into models_list, which then blew up every downstream m.lower() / caps[model].

Fix

In the list branch, extract the id (idmodelname) from dict entries so models stays a list[str] regardless of which config shape the user wrote. Plain-string entries are unchanged.

Test plan

  • build_models_payload(load_picker_context(), include_unconfigured=True, picker_hints=True, canonical_order=True, pricing=True, capabilities=True) → returns 41 providers, all models are strings, no AttributeError
  • user-defined rows now expose string ids, e.g. cerebras → ['zai-glm-4.7', 'qwen-3-235b-a22b-instruct-2507', 'llama3.1-8b']

🤖 Generated with Claude Code

build_models_payload and its downstream consumers (inventory dedup,
_apply_capabilities, _apply_pricing) assume each provider row's `models`
is a list of string ids — they call `m.lower()` and use the ids as dict
keys. But list_authenticated_providers appended user-provider `models:`
list entries verbatim, so a hand-edited config using the `{id, label}`
list form (instead of the dict-keyed-by-id form Hermes writes) put dicts
into the list.

Result: `GET /api/model/options` 500'd with
`AttributeError: 'dict' object has no attribute 'lower'`, leaving the
desktop model picker empty ("Failed to list model options").

Normalize list entries to their id (`id` | `model` | `name`) so `models`
stays a list[str] regardless of which config shape the user wrote.

Verified: build_models_payload(load_picker_context(), …) now returns 41
providers with string model ids and no AttributeError.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have comp/cli CLI entry point, hermes_cli/, setup wizard comp/desktop Electron desktop app (apps/desktop/*) area/config Config system, migrations, profiles labels Jun 30, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Competing/related fix: #33372 (open, earlier) fixes this same list_authenticated_providers() model-id normalization in hermes_cli/model_switch.py more broadly — it factors a _add_model_id() helper applied to both the dict and list branches (and a second call site) plus adds tests. This PR fixes only the one list branch inline. Cross-linking so a maintainer can pick; #33372 is the broader superset. Not marking either a duplicate.

@teknium1

Copy link
Copy Markdown
Contributor

Thanks for the focused reproduction and source-level fix.

Automated hermes-sweeper review found this is already implemented on current main:

  • fc18d15f4 (fix: preserve static custom provider models) introduced hermes_cli/model_switch.py:_declared_model_ids() at line 55, which normalizes list-of-dict entries to string IDs.
  • Both affected picker construction paths now consume that helper: the providers: path at hermes_cli/model_switch.py:2046 and the grouped custom-provider path at hermes_cli/model_switch.py:2274.
  • Current regression coverage includes list-of-{id: ...} models in tests/hermes_cli/test_inventory.py:65 and the static custom-provider cases added with the central fix.
  • The fix is contained in release tag v2026.7.7.

Closing as superseded by the centralized implementation on main.

@teknium1 teknium1 closed this Jul 15, 2026
@teknium1 teknium1 added the sweeper:implemented-on-main Sweeper: behavior already present on current main label Jul 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/config Config system, migrations, profiles comp/cli CLI entry point, hermes_cli/, setup wizard comp/desktop Electron desktop app (apps/desktop/*) P3 Low — cosmetic, nice to have sweeper:implemented-on-main Sweeper: behavior already present on current main type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants