Skip to content

feat(cli): resolve direct aliases at dispatch time - #29198

Closed
StartupBros wants to merge 1 commit into
NousResearch:mainfrom
StartupBros-com:feat/cli-direct-alias-resolution
Closed

StartupBros wants to merge 1 commit into
NousResearch:mainfrom
StartupBros-com:feat/cli-direct-alias-resolution

Conversation

@StartupBros

@StartupBros StartupBros commented May 20, 2026 •

Copy link
Copy Markdown
Contributor

Problem

When hermes chat is invoked with a model id that lives in hermes_cli.model_switch.DIRECT_ALIASES (custom providers, local runtimes, ad-hoc base_url overrides), the CLI hands the raw alias to AIAgent and the agent emits "unknown provider/model" — the alias never gets translated to its underlying (provider, base_url, model_id, api_mode) triple.

Same surface as:

Other call sites already perform direct-alias resolution at their dispatch points (hermes_cli/oneshot.py:269, hermes_cli/commands.py:1542-1544). The interactive hermes chat path was missing.

Fix

Two pure helpers in cli.py:

  • _resolve_direct_alias_for_chat(effective_model, current_provider) — wraps model_switch.resolve_alias and returns a small dict, or None when the input isn't a known alias.
  • _apply_resolved_alias(resolved, runtime) — folds the resolved triple into a copy of the runtime dict; recomputes api_mode via determine_api_mode; preserves any caller-supplied api_key; only sets no-key-required for local targets that have no key.

HermesCLI._init_agent calls them before constructing AIAgent.

Behavioural notes a reviewer will want to see

  1. Explicit overrides still win. self.model / self.provider / self.base_url / self.api_mode are mutated only when both model_override and runtime_override are None — i.e. the interactive default path. Callers passing --model or --runtime get the resolved triple in the agent but self.* is left alone.
  2. ImportError, not bare Exception. Trimmed embedded installs may omit hermes_cli.model_switch. The resolver catches ImportError specifically so a real AttributeError or KeyError from inside resolve_alias still propagates.
  3. No double _ensure_direct_aliases() call. resolve_alias already does this internally (hermes_cli/model_switch.py:469).
  4. Caller's runtime dict isn't mutated. _apply_resolved_alias copies before writing.

Test plan

5 new tests in tests/hermes_cli/test_regression_16767.py, class TestChatDispatchDirectAliasResolution:

  • test_alias_resolution_swaps_in_runtime — happy path, asserts model/provider/base_url/api_mode swap and the caller's dict isn't mutated
  • test_unknown_alias_returns_none — non-alias inputs fall through
  • test_existing_api_key_is_preserved — no-key-required placeholder doesn't clobber real keys
  • test_alias_without_base_url_does_not_set_one — catalog-only aliases don't blank an existing base_url
  • test_missing_model_switch_module_returns_none — ImportError path degrades gracefully

All 8 tests in the file pass (3 existing + 5 new).

@alt-glitch alt-glitch added type/bug Something isn't working duplicate This issue or pull request already exists comp/cli CLI entry point, hermes_cli/, setup wizard area/config Config system, migrations, profiles P2 Medium — degraded but workaround exists labels May 20, 2026
@alt-glitch

Copy link
Copy Markdown
Contributor

Duplicate of #19213 (open) and #21674 (open, by same author). Same fix: resolve DIRECT_ALIASES before constructing AIAgent in CLI. #21674 was already triaged as duplicate of #19213.

When `hermes chat` is invoked with a model id that lives in
``hermes_cli.model_switch.DIRECT_ALIASES`` (custom providers, local
runtimes, ad-hoc base_url overrides), the CLI hands the raw alias to
``AIAgent`` and the agent emits "unknown provider/model" — the alias
never gets translated to its underlying (provider, base_url, model_id,
api_mode) triple.

Fixes the dispatch-time gap for #18954 (model aliases not resolved for
custom providers); same surface as the regression test file for #16767
(chat --provider / -m <alias>).

Resolution is factored into two pure helpers — ``_resolve_direct_alias_for_chat``
and ``_apply_resolved_alias`` — so it's testable without an AIAgent. Explicit
``--model`` / ``--runtime`` overrides still win: ``self.*`` is only mutated
when neither was passed (i.e. the user's interactive default), so callers
that introspect ``self.model`` after a chat exit see the post-resolution
value rather than the raw alias.

``ImportError`` (not bare ``Exception``) is caught around the model_switch
import so trimmed embedded installs that don't ship the module fall through
to the generic provider lookup instead of crashing.
@StartupBros

Copy link
Copy Markdown
Contributor Author

Status re: @alt-glitch's note above: #21674 closed (its tests landed in tests/cli/, a directory that doesn't exist in the repo, so they never actually ran in CI). Left a rescope note on #19213 — that PR is genuinely broader (fixes at three callers via a new model_switch.resolve_direct_alias() API), so #19213 and this one could land complementarily if #19213 narrows to just the gateway + oneshot callers this PR doesn't touch.

@StartupBros

Copy link
Copy Markdown
Contributor Author

Closing in favor of #19213 (@LeonSGP43).

After tracing the call flow on current main:

  • _init_agent calls _ensure_runtime_credentials() at line 4502 before any of the code this PR added would run.
  • Both real _init_agent callers (cli.py:11017 and cli.py:14442) pass model_override=turn_route["model"], and _resolve_turn_agent_config sets turn_route["model"] = self.model with no transformation.
  • fix(config): resolve direct model aliases at runtime #19213 patches _ensure_runtime_credentials and writes the resolved value back to self.model. Once fix(config): resolve direct model aliases at runtime #19213 lands, self.model is canonical by the time _init_agent runs, so this PR's resolution would be a no-op.

#19213 is also architecturally cleaner — it adds a proper resolve_direct_alias() API on hermes_cli.model_switch, threads target_model= through resolve_runtime_provider, and patches all 4 affected call paths (chat, gateway, oneshot, credentials) with tests at each.

Going to validate #19213 against current main and post results there. Sorry for the duplicate noise.

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 duplicate This issue or pull request already exists P2 Medium — degraded but workaround exists type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants