feat(cli): make hermes portal run the full quick-setup Nous flow (model picker)

`hermes portal` / `hermes setup --portal` previously logged in and set
provider=nous but left the model UNSELECTED (blank -> runtime default) and
never showed a picker — unlike the first-time quick setup, which runs the
model picker.

Route `_run_portal_one_shot` through `_model_flow_nous` — the exact same
routine quick setup (`_run_first_time_quick_setup`) and `hermes model` -> Nous
use. It handles both the logged-out path (device-code OAuth, which picks a
model internally) and the logged-in path (curated Nous model picker), then
offers the Tool Gateway opt-in and sets provider=nous. Net effect: `hermes
portal` now offers a model picker every time and is a true single-command
collapse of quick setup's Nous step.

Removes the hand-rolled auth_add_command + manual provider write + separate
Tool Gateway prompt (now a single source of truth). Re-syncs the in-memory
config from disk afterward so a caller's later save_config can't clobber the
model/provider written by the login flow.

Docs (CLI help, portal_cli docstrings, nous-portal EN + zh-Hans) updated to
mention model selection. New regression test asserts `_run_portal_one_shot`
delegates to `_model_flow_nous`.

Verified live: `hermes portal` now shows the 27-model curated picker, 'Skip
(keep current)' preserves prior provider/model.
This commit is contained in:
kshitijk4poor
2026-06-04 02:20:31 +05:30
parent d4787d3e2e
commit cd188b814e
5 changed files with 85 additions and 89 deletions
+26
View File
@@ -109,3 +109,29 @@ def test_parser_registers_subcommands():
for sub in ("login", "info", "status", "open", "tools"):
ns = parser.parse_args(["portal", sub])
assert ns.portal_command == sub
def test_one_shot_delegates_to_model_flow_nous(monkeypatch):
"""`hermes portal` must run the quick-setup Nous flow (login + MODEL PICK +
provider + Tool Gateway), i.e. delegate to `_model_flow_nous` — not the
lighter auth-only path that skipped model selection.
"""
import hermes_cli.setup as setup_mod
calls = {"model_flow": 0}
def fake_model_flow(config):
calls["model_flow"] += 1
# _model_flow_nous lives in hermes_cli.main and is imported lazily inside
# _run_portal_one_shot, so patch it at the source module.
monkeypatch.setattr("hermes_cli.main._model_flow_nous", fake_model_flow)
# Keep the disk re-sync a no-op so the test never touches real config.
monkeypatch.setattr("hermes_cli.config.load_config", lambda: {})
setup_mod._run_portal_one_shot({})
assert calls["model_flow"] == 1, (
"`hermes portal` must route through _model_flow_nous so the model "
"picker runs every time (matching quick setup)."
)