feat(cli): add subagent model and reasoning picker - #76480
Conversation
teknium1
left a comment
There was a problem hiding this comment.
Thanks for building this as a CLI-scoped path and reusing the existing model flow.
Problems
hermes_cli/subagent_model.py:61treats a provider-only delegation configuration as inheritance and discards the provider. That configuration is active on current main:tools/delegate_tool.py:3500-3501readsmodelandproviderindependently, andtools/delegate_tool.py:3574-3601resolves 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_configand picker initialization, then add a regression test proving the CLI state agrees with current runtime credential resolution.
This is an automated hermes-sweeper review.
| # 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: |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
997cee4 to
d57216a
Compare
d57216a to
7a8ea35
Compare
|
Rebased onto current Verification: |
818779c to
18323d0
Compare
18323d0 to
70579d3
Compare
|
Latest-rebase status update: the failed Fixed by restoring the intended CLI-only boundary in Canonical verification on the corrected tree:
Corrected head: |
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:
Classic prompt-toolkit CLI:
Picker reuse
hermes subagent modelreuses the full canonicalhermes modelprovider/setup picker, including custom providers and authentication/setup flows./modeloverlay with the delegated provider/model as the initial target.Configuration and runtime
The commands write the existing runtime keys:
modelandproviderare committed together in the same config write.noneis an explicit child override that disables reasoning;resetremoves the child override and restores inheritance.delegate_taskalready 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:
/subagentis omitted from catalog/completion metadata and rejected byslash.exec,cli.exec,command.resolve, andcommand.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.pytransaction machinery and active-provider ownership tracking were removed from this PR;auth.pynow 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:
The same development and audit work also surfaced or confirmed adjacent upstream problem classes:
save_configlost-update — three-way merge-preserve + loud CAS conflict refusal at theatomic_config_writeseam #62232;active_providerhijacking and lockless auth-store reads: already addressed by fix(auth,env): prevent active_provider hijack, guard pipe FDs, lock auth reads #6650;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:
#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
git diff --checkpassed for the changed Python surface.Coordination graph
hermes_cli/model_setup_flows.py; Shard hermes_cli/auth.py (god-file decomposition) #78637 plus refactor(auth): extract SSH/browser helpers into auth_browser_helpers (s2) #80428/refactor(auth): extract auth errors and telemetry (S1) #80673/refactor(auth): extract TLS verification helpers (S3) #80676 coordinate extraction fromhermes_cli/auth.py; feat(tui): async delegation view — docked agents panel + live steering #70899 overlaps delegation/TUI surface files. Preserve their canonical provider lookup, secret-scope, and UI ownership changes when rebasingHermes 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"Dashboard interpretation:
closes/related);0.88and file overlap0.75;duplicate ofedge below the fold threshold is a similarity lead for review, not an accepted duplicate or merge-order edge;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.