Skip to content

feat(cli): add subagent model and reasoning picker - #76480

Open
Xipong wants to merge 1 commit into
NousResearch:mainfrom
Xipong:feat/subagent-cli-picker
Open

feat(cli): add subagent model and reasoning picker#76480
Xipong wants to merge 1 commit into
NousResearch:mainfrom
Xipong:feat/subagent-cli-picker

Conversation

@Xipong

@Xipong Xipong commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Summary

This is the intentionally CLI-only extraction of our complete cross-surface model/provider/reasoning implementation from #74375.

The source implementation was not merely a CLI picker: it covered the shared resolver/persistence contract plus Shell, Classic/TUI, and Desktop controls, superseded the Desktop scope of #67523, and was coordinated with the Dashboard picker in #67557. This PR deliberately retains the non-conflicting Shell and Classic CLI slice without introducing a competing React TUI, Desktop, Dashboard, messaging-gateway, or REST surface while Mission Control (#70899) is still taking shape.

User-facing CLI

Shell CLI:

hermes subagent
hermes subagent model
hermes subagent model <model> [--provider <provider>] [--refresh]
hermes subagent model reset
hermes subagent reasoning <effort>
hermes subagent reasoning none
hermes subagent reasoning reset

Classic prompt-toolkit CLI:

/subagent
/subagent model
/subagent model <model> [--provider <provider>]
/subagent model reset
/subagent reasoning <effort|none|reset>

Picker reuse

  • hermes subagent model reuses the full canonical hermes model provider/setup picker, including custom providers and authentication/setup flows.
  • The Classic CLI reuses its existing /model overlay with the delegated provider/model as the initial target.
  • Confirmed selections are captured at the shared model-save boundary; provider-specific setup logic is not duplicated.
  • Provider/auth setup side effects are retained, while the temporary primary model/auth route is restored before the delegated selection is committed.
  • Restore failures are reported instead of silently claiming success.
  • Provider-only delegation state is preserved and initialized consistently with runtime credential resolution, including provider-default models.

Configuration and runtime

The commands write the existing runtime keys:

delegation:
  model: <model>
  provider: <provider>
  reasoning_effort: <effort>
  • model and provider are committed together in the same config write.
  • Reasoning is independent from model/provider.
  • none is an explicit child override that disables reasoning; reset removes the child override and restores inheritance.
  • Existing delegation settings are preserved.
  • delegate_task already reloads these keys from the active profile on each dispatch.

Scope and review budget

No React TUI command handler or picker, Desktop setting, Dashboard surface, messaging command, gateway API, or REST endpoint is added.

The TUI-gateway changes are exclusion guards only: /subagent is omitted from catalog/completion metadata and rejected by slash.exec, cli.exec, command.resolve, and command.dispatch. No TUI implementation is added.

The feature diff was reduced from 16 files / +2,299 lines to 15 files / +2,065 lines. The post-audit increase is regression coverage for primary-route isolation, provider-only status, interrupt cleanup, and exact auth-store restoration. The general config.py transaction machinery and active-provider ownership tracking were removed from this PR; auth.py now only adds the small confirmed-selection callback needed because the canonical picker persists rather than returns its result.

Maintenance dividend and extraction ledger

Developing and auditing this picker surfaced an independent pre-existing cleanup bug in hermes fallback add, which reuses the same mutating provider/model setup flow. That bug is fixed separately in #76497, with the discovery explicitly attributed back to this feature work.

The source work in #74375 was our unified cross-surface implementation, not a collection of unrelated picker fragments. It superseded the Desktop scope proposed in #67523 and shared the same product direction as the Dashboard work in #67557; #76480 is the deliberately narrowed CLI extraction of that larger implementation.

While narrowing it, the current PR also closed several picker-specific correctness gaps:

  • provider-only delegation remains an active override, initializes from that provider, and resolves/reports the provider-default model instead of being mistaken for inheritance;
  • the Classic primary picker keeps its canonical provider/model route rather than reusing display labels from the secondary-target cursor state;
  • secondary picker results remain explicitly non-global, and temporary full-setup picker mutations restore the exact primary model/auth route while retaining useful setup side effects.

The same development and audit work also surfaced or confirmed adjacent upstream problem classes:

Those references were found while tracing the shared picker, auth, command-routing, and cross-surface ownership needed by this extraction. This PR does not duplicate or supersede those independent fixes.

The final extraction audit classified every shared production hunk:

  • fallback picker primary-route restoration: extracted to fix(fallback): restore primary route after picker errors #76497;
  • auth selection callback and Azure confirmation hook: feature-owned capture seam, inactive without this picker;
  • initial provider/model cursor arguments: feature-owned reuse seam for the secondary target;
  • Classic picker target branch: feature implementation; the primary branch preserves the existing runtime slug/model contract;
  • TUI gateway guards: feature boundary for the newly introduced CLI-only command, not a general command-registry fix.

#24829 was also reviewed during this audit, but its saved-model/menu-order proposal is not treated here as a picker defect: starting this picker at the top remains intentional UX rather than another extracted bug.

No remaining hunk has both an independent current-main trigger and a clean standalone owner. In short: all independently useful maintenance work discovered by the picker is outside this PR where appropriate; the remaining shared lines are required by the feature itself.

Verification

  • 283 post-rebase feature and adjacent shared-picker/provider/auth tests passed.
  • React TUI catalog/execution boundary coverage is included in that gate.
  • Provider-only CLI status, picker initialization, and runtime credential-resolution parity are covered by regression tests.
  • Ruff, Python compilation, secret scan, and git diff --check passed for the changed Python surface.

Coordination graph

Hermes triage dashboard graph

Live dashboard neighbourhood: https://hermes-triage.gottz.de/?node=76480

flowchart LR
    classDef focus fill:#fef3c7,stroke:#b45309,stroke-width:3px,color:#451a03
    classDef issue fill:#ede9fe,stroke:#6d28d9,color:#2e1065
    classDef open fill:#dbeafe,stroke:#1d4ed8,color:#1e3a8a
    classDef closed fill:#e5e7eb,stroke:#6b7280,color:#1f2937
    P76480["PR #76480 (open)"]
    I51009(["issue #51009 (open)"])
    I85650(["issue #85650 (open)"])
    P751["PR #751 (closed)"]
    P791["PR #791 (closed)"]
    P3734["PR #3734 (closed)"]
    P3794["PR #3794 (closed)"]
    P5229["PR #5229 (closed)"]
    P25026["PR #25026 (closed)"]
    P37578["PR #37578 (closed)"]
    P63461["PR #63461 (closed)"]
    P67523["PR #67523 (open)"]
    P67557["PR #67557 (open)"]
    P74375["PR #74375 (closed)"]
    P76480 -->|related| I51009
    P76480 -->|closes| I85650
    P76480 -->|related| I85650
    P74375 -.->|duplicate of 0.82| P76480
    P3794 -.->|duplicate of 0.77| P76480
    P5229 -.->|duplicate of 0.77| P76480
    P37578 -.->|duplicate of 0.77| P76480
    P791 -.->|duplicate of 0.77| P76480
    P63461 -.->|duplicate of 0.77| P76480
    P751 -.->|duplicate of 0.76| P76480
    P67523 -.->|duplicate of 0.75| P76480
    P3734 -.->|duplicate of 0.74| P76480
    P25026 -.->|duplicate of 0.74| P76480
    P67557 -.->|duplicate of 0.71| P76480
    class P76480 focus
    click P76480 "https://github.com/NousResearch/hermes-agent/pull/76480"
    class I51009 issue
    click I51009 "https://github.com/NousResearch/hermes-agent/issues/51009"
    class I85650 issue
    click I85650 "https://github.com/NousResearch/hermes-agent/issues/85650"
    class P751 closed
    click P751 "https://github.com/NousResearch/hermes-agent/pull/751"
    class P791 closed
    click P791 "https://github.com/NousResearch/hermes-agent/pull/791"
    class P3734 closed
    click P3734 "https://github.com/NousResearch/hermes-agent/pull/3734"
    class P3794 closed
    click P3794 "https://github.com/NousResearch/hermes-agent/pull/3794"
    class P5229 closed
    click P5229 "https://github.com/NousResearch/hermes-agent/pull/5229"
    class P25026 closed
    click P25026 "https://github.com/NousResearch/hermes-agent/pull/25026"
    class P37578 closed
    click P37578 "https://github.com/NousResearch/hermes-agent/pull/37578"
    class P63461 closed
    click P63461 "https://github.com/NousResearch/hermes-agent/pull/63461"
    class P67523 open
    click P67523 "https://github.com/NousResearch/hermes-agent/pull/67523"
    class P67557 open
    click P67557 "https://github.com/NousResearch/hermes-agent/pull/67557"
    class P74375 closed
    click P74375 "https://github.com/NousResearch/hermes-agent/pull/74375"
Loading

Dashboard interpretation:

  • solid edges are structural GitHub links (closes / related);
  • dashed edges are embedding-discovery candidates and show the dashboard score;
  • the fold thresholds reported by the dashboard are embedding 0.88 and file overlap 0.75;
  • a dashed duplicate of edge below the fold threshold is a similarity lead for review, not an accepted duplicate or merge-order edge;
  • the gold node is this PR; purple nodes are issues; blue/gray nodes are open/closed neighbouring PRs.

This graph is additive to the hand-audited coordination block above: the dashboard supplies discovery neighbourhoods, while the declared dependency, collision, ownership, and merge-order edges remain the reviewed coordination contract.

@alt-glitch alt-glitch added type/feature New feature or request comp/cli CLI entry point, hermes_cli/, setup wizard comp/tui Terminal UI (ui-tui/ + tui_gateway/) tool/delegate Subagent delegation area/config Config system, migrations, profiles P3 Low — cosmetic, nice to have sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades labels Aug 2, 2026

@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 building this as a CLI-scoped path and reusing the existing model flow.

Problems

  • hermes_cli/subagent_model.py:61 treats a provider-only delegation configuration as inheritance and discards the provider. That configuration is active on current main: tools/delegate_tool.py:3500-3501 reads model and provider independently, and tools/delegate_tool.py:3574-3601 resolves a configured provider even when no model is set. The new status and picker would therefore show/use the parent provider while spawned children use the configured delegation provider.

Suggested changes

  • Preserve provider-only state in _status_from_config and picker initialization, then add a regression test proving the CLI state agrees with current runtime credential resolution.

This is an automated hermes-sweeper review.

Comment thread hermes_cli/subagent_model.py Outdated
# A provider without a model is not a usable override. Treat legacy or
# partially-written config as inheritance instead of constructing a child
# with an empty model.
if not model:

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.

A provider without a model is valid on current main: _resolve_delegation_credentials() reads both keys independently and resolves the configured provider's default model (tools/delegate_tool.py:3500-3501,3574-3601). Returning inheritance here hides that active provider override and initializes the picker from the wrong route. Preserve provider-only state and cover it with a regression test.

@Xipong Xipong Aug 2, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed on current head d57216a. Provider-only delegation state is preserved, initializes the picker from that provider, reports it as provider default rather than inheritance/None, and is covered against the runtime credential resolver/provider-default model path.

@teknium1 teknium1 added sweeper:risk-platform-windows Sweeper risk: may break or behave differently on native Windows sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Aug 2, 2026
@Xipong
Xipong force-pushed the feat/subagent-cli-picker branch 2 times, most recently from 997cee4 to d57216a Compare August 2, 2026 02:21
@Xipong
Xipong requested a review from teknium1 August 2, 2026 09:24
@Xipong
Xipong force-pushed the feat/subagent-cli-picker branch from d57216a to 7a8ea35 Compare August 7, 2026 20:22
@Xipong

Xipong commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto current main (a8c50eb1d). Patch is unchanged apart from the new base — verified identical to the previous head.

Verification: tests/cli/test_subagent_command.py + tests/hermes_cli/test_subagent_model.py 39/39, py_compile clean.

@Xipong
Xipong force-pushed the feat/subagent-cli-picker branch from 18323d0 to 70579d3 Compare August 13, 2026 20:22
@Xipong

Xipong commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

Latest-rebase status update: the failed Python tests / Run tests slice 6/12 was a real regression, not a generic CI flake. Reproducing the canonical per-file runner locally showed test_tui_slash_exec_rejects_cli_only_subagent_command failing because /subagent was again visible in fuzzy slash completion after the upstream rebase.

Fixed by restoring the intended CLI-only boundary in tui_gateway/methods_complete.py: the command remains executable in Shell/Classic CLI, but is not advertised by the React TUI completion surface.

Canonical verification on the corrected tree:

  • scripts/run_tests.sh tests/cli/test_subagent_command.py tests/hermes_cli/test_subagent_model.py tests/test_tui_gateway_server.py -q
  • 591 passed, 0 failed across 3 isolated test-file subprocesses;
  • git diff --check: clean.

Corrected head: 70579d35694a6edba5160a45df96f74a7825e482. A fresh CI run is now attached to this head.

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/tui Terminal UI (ui-tui/ + tui_gateway/) P3 Low — cosmetic, nice to have 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 sweeper:risk-platform-windows Sweeper risk: may break or behave differently on native Windows tool/delegate Subagent delegation type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CLI: configure the delegated model, provider, and reasoning override

3 participants