fix(moa): config/CLI plumbing — doctor, non-interactive presets, lossless saves, slot hygiene, vertex registration (cluster salvage) - #70282
Merged
Conversation
hermes chat -Q -m moa:strategy failed with 'model moa:strategy is not supported' (HTTP 401/400): the raw model string was passed straight to the real provider. The MoA virtual provider only got wired up through the interactive /moa command and the model picker, never through the -Q one-shot startup path. resolve_runtime_provider already handles requested_provider == 'moa', and agent_init builds the MoAClient off provider == 'moa' (surface-agnostic). The only gap was mapping the moa:<preset> model string to that provider. Add _normalize_moa_model() and apply it in HermesCLI.__init__ before provider resolution: a moa:<preset> model sets requested_provider='moa' and model=<preset>, so the existing MoA path runs in non-interactive mode too. The moa: prefix wins over an explicit --provider (previously --provider deepseek -m moa:strategy silently dropped MoA). Fixes #56828
…ovider The existing tests cover _normalize_moa_model() in isolation and a local precedence expression, but not the __init__ wiring itself. Add two init-level regression tests: constructing HermesCLI(model='moa:strategy') strips the prefix to model='strategy' and forces requested_provider='moa', and the moa: prefix wins over an explicit --provider. Both fail if the override is dropped from the requested_provider resolution. Refs #56828
MoA (Mixture of Agents) is a legitimate internal provider used by Diagnosis presets and multi-model aggregation. When a MoA preset sets model.provider to 'moa', hermes doctor incorrectly reports it as 'unrecognised' and suggests changing it, which would break the MoA setup. Add 'moa' to the known_providers set alongside 'openrouter', 'custom', and 'auto' so doctor recognises it as valid. Fixes #58759
When reference_models is stored as a JSON string (e.g. from hermes moa configure or hand-edited config.yaml), _normalize_preset silently falls back to hardcoded defaults because the string fails both isinstance(x, list) and isinstance(x, dict) checks. Add json.loads() parsing before the type checks so both formats work.
MoaConfigPayload does not declare save_traces or trace_dir, so set_moa_models() overwrites cfg["moa"] with a dict that lacks these hand-edited keys. Use dict.update() to merge instead of replace. Fixes #58819
…LAYS The Vertex AI provider (added same-day, commit c73e743) was never added to either of the two provider registries that agent/auxiliary_client.py and the MoA slot-resolution chain depend on, breaking Vertex outside the main conversation loop: 1. hermes_cli/auth.py::PROVIDER_REGISTRY had no "vertex" entry. The plugin-auto-extend loop that normally fills gaps explicitly skips non-api_key auth types (`if _pp.auth_type != "api_key": continue`), and Vertex was never hand-declared like "bedrock" is. Because resolve_provider_client() in agent/auxiliary_client.py gates everything on `pconfig = PROVIDER_REGISTRY.get(provider)` and returns (None, None) immediately when pconfig is None, its `elif pconfig.auth_type == "vertex"` branch was permanently dead code — every auxiliary Vertex call (vision, title generation, reflection, context compression, MoA reference/ aggregator slots) failed outright, not just a MoA-specific edge case. 2. hermes_cli/providers.py::HERMES_OVERLAYS also had no "vertex" entry, so hermes_cli.providers.get_provider("vertex") returned None. This backs _preserve_provider_with_base_url() in agent/auxiliary_client.py, which a MoA slot's resolved (base_url, api_key) pair needs to keep its "vertex" identity instead of silently collapsing to "custom" — losing the identity _refresh_provider_credentials() needs to re-mint an expired OAuth2 token (~1h lifetime) on a 401, and permanently breaking every subsequent call in that MoA preset for the rest of the session. Fix mirrors the existing "bedrock"/aws_sdk entries in both registries exactly, plus adds a "vertex" branch to _refresh_provider_credentials() (it had branches for openai-codex/nous/anthropic/xai-oauth but not vertex, so a 401 fell through to `return False` without evicting the stale cached client). - hermes_cli/auth.py: hand-declared vertex ProviderConfig(auth_type="vertex") in PROVIDER_REGISTRY, matching bedrock's shape. - hermes_cli/providers.py: vertex HermesOverlay(auth_type="vertex") in HERMES_OVERLAYS + "Google Vertex AI" label override. - agent/auxiliary_client.py: vertex branch in _refresh_provider_credentials that re-mints the token via get_vertex_config() and evicts the stale cached client. - 8 new regression tests across tests/hermes_cli/test_vertex_provider.py and tests/agent/test_auxiliary_client.py: registry membership, end-to-end resolve_provider_client("vertex", ...) building a working client (proving the previously-dead branch is now reachable), and the 401-refresh/cache- eviction path.
…curated model list Community verification of #56688 (zmack12344321) found two follow-up gaps that kept Vertex invisible in the /model menu even after registry registration: 1. hermes_cli/model_switch.py: list_authenticated_providers() had a credential gate hard-coded to API keys (with an aws_sdk special case only) — add a vertex branch using has_vertex_credentials(), mirroring the aws_sdk shape. 2. hermes_cli/models.py: Vertex's OpenAI-compatible endpoint has no /models listing route, so without a curated _PROVIDER_MODELS entry the picker only ever showed the current model — add a Gemini curated list. Follow-up to #56688.
Contributor
૮ >ﻌ< ა ci reviewran on 49d38b1 ℹ️ InfoDesktop E2E visual evidence · View test artifacts · View job1 visual diff. inline evidence upload failed. Failed to upload diff-665a0833239e-onboarding-overlay-diff.png with gh image (exit code 1): Error uploading /home/runner/work/_temp/e2e-evidence/diff-665a0833239e-onboarding-overlay-diff.png: step 0 (get upload token): uploadToken not found on repo page — do you have write access to NousResearch/hermes-agent? (or, if NousResearch enforces SAML SSO, authorize at https://github.com/orgs/NousResearch/sso) |
This was referenced Jul 24, 2026
This was referenced Jul 30, 2026
1 task
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Six MoA config/CLI plumbing gaps closed in one pass: doctor accepts the virtual provider,
moa:<preset>resolves in non-interactive mode, JSON-string advisor lists parse instead of silently falling back to defaults, GUI saves stop dropping hand-edited trace keys, the slot picker filters invalid providers, and the dead vertex auth branch becomes reachable. Consolidated salvage (cluster: MoA config plumbing) — all components touch disjoint files.Changes (10 commits, authorship preserved)
hermes -Q -m moa:<preset>previously sent the raw string to the real provider (401/400) — init-level resolution now routes it through the virtual provider; sweeper feedback already incorporated by the author, tests verified locally pre-salvage.moatoknown_providers— kills the false "provider not recognised" warning on valid MoA configs. (Dupe fix(doctor): recognize configured MoA orchestration #64203 closed with credit to @mudrii; fix(doctor): recognize moa as an internal provider #59016 was previously closed as the same dupe.)_normalize_presetjson.loads a stringreference_models(fromhermes config setstring storage or hand-edits) instead of silently using factory defaults; our regression tests cover round-trip + malformed-string fallback.set_moa_modelsdidcfg["moa"] = normalized, dropping undeclared keys likesave_traces/trace_dir(real consumers in agent/moa_trace.py). Fix shape (key-preserving merge) reapplied at the rewritten post-[Bug]: MoA preset editor — changing reference provider triggers defaults explosion from half-filled autosave #64156 function site; 146-line test file carried over.moa_cmd._model_optionsfilters the virtualmoarow (recursive presets are rejected by_clean_slotanyway — picking it silently fell back to OpenRouter) and passesinclude_unconfigured=False. Maintainer flag: the latter is a deliberate behavior change — slot pickers no longer offer unconfigured providers.vertexregistered in PROVIDER_REGISTRY + HERMES_OVERLAYS so the existing-but-deadauth_type == "vertex"branch in the auxiliary client is reachable (every aux Vertex call failed before); our fix-up adds the community-identifiedmodel_switch.pycredential gate viahas_vertex_credentials()+ curated model list.Contributor mappings for wen0531 + iniak committed alongside.
Validation
Salvages #56852, #58771, #59497, #58820, #63331, #56688. #64203 closed as dupe with credit.
Infographic