feat(cli): make hermes portal the human-readable Portal onboarding alias
`hermes portal` (no subcommand) now runs the one-shot Nous Portal onboarding — OAuth login, switch provider to Nous, offer Tool Gateway — identical to `hermes setup --portal` and the human-readable alias for `hermes auth add nous --type oauth` (which still works). The prior status default moves to `hermes portal info`; `status` is kept as a hidden back-compat alias. `open`/`tools` subcommands are unchanged. User-facing hints and docs (status.py, conversation_loop 401 guidance, SystemPage, README, website docs + zh-Hans) now point at `hermes portal` / `hermes portal info`. `--manual-paste` references keep the explicit auth command since `hermes portal` does not expose that flag.
This commit is contained in:
@ -94,7 +94,7 @@ One command from a fresh install:
|
||||
hermes setup --portal
|
||||
```
|
||||
|
||||
That logs you in via OAuth, sets Nous as your provider, and turns on the Tool Gateway. Check what's wired up any time with `hermes portal status`. Full details on the [Tool Gateway docs page](https://hermes-agent.nousresearch.com/docs/user-guide/features/tool-gateway).
|
||||
That logs you in via OAuth, sets Nous as your provider, and turns on the Tool Gateway. Check what's wired up any time with `hermes portal info`. Full details on the [Tool Gateway docs page](https://hermes-agent.nousresearch.com/docs/user-guide/features/tool-gateway).
|
||||
|
||||
You can still bring your own keys per-tool whenever you want — the gateway is per-backend, not all-or-nothing.
|
||||
|
||||
|
||||
@ -80,7 +80,7 @@ Hermes 始终允许你使用任意服务商,这点不会改变。但如果你
|
||||
hermes setup --portal
|
||||
```
|
||||
|
||||
它会通过 OAuth 登录、把 Nous 设为推理服务商,并启用 Tool Gateway。随时用 `hermes portal status` 查看路由状态。完整说明见 [Tool Gateway 文档](https://hermes-agent.nousresearch.com/docs/user-guide/features/tool-gateway)。
|
||||
它会通过 OAuth 登录、把 Nous 设为推理服务商,并启用 Tool Gateway。随时用 `hermes portal info` 查看路由状态。完整说明见 [Tool Gateway 文档](https://hermes-agent.nousresearch.com/docs/user-guide/features/tool-gateway)。
|
||||
|
||||
你随时可以按工具单独切回自己的 API Key — Gateway 是按工具粒度生效的,不是一刀切。
|
||||
|
||||
|
||||
@ -3255,7 +3255,7 @@ def run_conversation(
|
||||
else: # nous
|
||||
agent._vprint(f"{agent.log_prefix} 💡 Nous Portal OAuth token was rejected (HTTP 401). Your token may be", force=True)
|
||||
agent._vprint(f"{agent.log_prefix} expired, revoked, or your account may be out of credits. To fix:", force=True)
|
||||
agent._vprint(f"{agent.log_prefix} 1. Re-authenticate: hermes auth add nous --type oauth", force=True)
|
||||
agent._vprint(f"{agent.log_prefix} 1. Re-authenticate: hermes portal", force=True)
|
||||
agent._vprint(f"{agent.log_prefix} 2. Check your portal account: https://portal.nousresearch.com", force=True)
|
||||
# ``:free`` is OpenRouter slug syntax; Nous Portal will reject
|
||||
# the model name even after a successful re-auth.
|
||||
|
||||
@ -1,12 +1,20 @@
|
||||
"""``hermes portal`` — small CLI surface for Nous Portal users.
|
||||
"""``hermes portal`` — the human-readable entry point for Nous Portal.
|
||||
|
||||
Running ``hermes portal`` with no subcommand performs the one-shot Portal
|
||||
onboarding: OAuth login, switch the inference provider to Nous, and offer to
|
||||
enable the Tool Gateway. It is the friendly alias for
|
||||
``hermes auth add nous --type oauth`` (which still works) and is identical to
|
||||
``hermes setup --portal``.
|
||||
|
||||
Subcommands:
|
||||
status Show Portal auth state + which Tool Gateway tools are routed.
|
||||
(none) Log in to Nous Portal + set it up (one-shot onboarding).
|
||||
login Explicit alias for the default one-shot onboarding.
|
||||
info Show Portal auth state + which Tool Gateway tools are routed.
|
||||
open Open the Portal subscription page in the user's default browser.
|
||||
tools List Tool Gateway tools and which are active in the current config.
|
||||
|
||||
This command is intentionally minimal — it does not duplicate functionality
|
||||
already in ``hermes auth`` or ``hermes tools``. It's a discovery + status
|
||||
already in ``hermes auth`` or ``hermes tools``. It's the onboarding + discovery
|
||||
surface for the Portal subscription itself.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
@ -49,7 +57,7 @@ def _cmd_status(args) -> int:
|
||||
else:
|
||||
print(f" Auth: {color('not logged in', Colors.YELLOW)}")
|
||||
print(f" Sign up: {SUBSCRIPTION_URL}")
|
||||
print(f" Login: hermes auth add nous --type oauth")
|
||||
print(f" Login: hermes portal")
|
||||
|
||||
# Provider selection (independent of auth)
|
||||
model_cfg = config.get("model") if isinstance(config.get("model"), dict) else {}
|
||||
@ -134,7 +142,7 @@ def _cmd_tools(args) -> int:
|
||||
print(color(" ────────────────────", Colors.MAGENTA))
|
||||
|
||||
if not features.nous_auth_present:
|
||||
print(color(" Not logged into Nous Portal — sign in with `hermes auth add nous --type oauth`.", Colors.YELLOW))
|
||||
print(color(" Not logged into Nous Portal — sign in with `hermes portal`.", Colors.YELLOW))
|
||||
print()
|
||||
|
||||
label_width = max(len(label) for _, label, _ in catalog)
|
||||
@ -158,14 +166,36 @@ def _cmd_tools(args) -> int:
|
||||
return 0
|
||||
|
||||
|
||||
def _cmd_login(args) -> int:
|
||||
"""Run the one-shot Nous Portal onboarding (OAuth + provider + Tool Gateway).
|
||||
|
||||
This is the human-readable front door for `hermes auth add nous --type
|
||||
oauth`. It reuses the exact wiring behind `hermes setup --portal` so the
|
||||
two commands stay in lockstep: device-code login, switch the inference
|
||||
provider to Nous, then offer the Tool Gateway opt-in.
|
||||
"""
|
||||
from hermes_cli.setup import _run_portal_one_shot
|
||||
|
||||
config = load_config() or {}
|
||||
try:
|
||||
_run_portal_one_shot(config)
|
||||
except (KeyboardInterrupt, EOFError):
|
||||
print()
|
||||
print("Portal setup cancelled.")
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
def portal_command(args) -> int:
|
||||
"""Top-level dispatch for `hermes portal <subcommand>`."""
|
||||
sub = getattr(args, "portal_command", None)
|
||||
if sub in {None, ""}:
|
||||
# Default to status — matches gh / kubectl conventions where the
|
||||
# subcommand-less form gives a useful overview.
|
||||
return _cmd_status(args)
|
||||
if sub == "status":
|
||||
if sub in {None, "", "login"}:
|
||||
# Default to the one-shot onboarding — `hermes portal` is the
|
||||
# human-readable alias for `hermes auth add nous --type oauth` /
|
||||
# `hermes setup --portal`.
|
||||
return _cmd_login(args)
|
||||
if sub in {"info", "status"}:
|
||||
# `status` kept as a back-compat alias for the prior default.
|
||||
return _cmd_status(args)
|
||||
if sub == "open":
|
||||
return _cmd_open(args)
|
||||
@ -180,19 +210,26 @@ def add_parser(subparsers) -> None:
|
||||
"""Register `hermes portal` on the given argparse subparsers object."""
|
||||
portal_parser = subparsers.add_parser(
|
||||
"portal",
|
||||
help="Nous Portal status, subscription, and Tool Gateway routing",
|
||||
help="Set up Nous Portal (OAuth login + Tool Gateway); see also `portal info`",
|
||||
description=(
|
||||
"Inspect Nous Portal auth, Tool Gateway routing, and open the "
|
||||
"Portal subscription page. Subcommands: status (default), "
|
||||
"open, tools."
|
||||
"Run `hermes portal` with no subcommand to log in to Nous Portal "
|
||||
"and set it up (the human-readable alias for `hermes auth add nous "
|
||||
"--type oauth`, identical to `hermes setup --portal`). Subcommands: "
|
||||
"login (default), info, open, tools."
|
||||
),
|
||||
)
|
||||
portal_sub = portal_parser.add_subparsers(dest="portal_command")
|
||||
|
||||
portal_sub.add_parser(
|
||||
"status",
|
||||
help="Show Portal auth + Tool Gateway routing summary (default)",
|
||||
"login",
|
||||
help="Log in to Nous Portal + set it up (default; one-shot onboarding)",
|
||||
)
|
||||
portal_sub.add_parser(
|
||||
"info",
|
||||
help="Show Portal auth + Tool Gateway routing summary",
|
||||
)
|
||||
# `status` retained as a hidden back-compat alias for `info`.
|
||||
portal_sub.add_parser("status")
|
||||
portal_sub.add_parser(
|
||||
"open",
|
||||
help="Open the Portal subscription page in your default browser",
|
||||
|
||||
@ -2828,7 +2828,7 @@ def _run_portal_one_shot(config: dict) -> None:
|
||||
|
||||
print()
|
||||
print_success("Portal setup complete.")
|
||||
print_info(" Run `hermes portal status` to inspect routing.")
|
||||
print_info(" Run `hermes portal info` to inspect routing.")
|
||||
print_info(" Run `hermes` to start chatting.")
|
||||
|
||||
|
||||
|
||||
@ -223,7 +223,7 @@ def show_status(args):
|
||||
elif nous_inference_present:
|
||||
nous_label = "not logged in (Nous inference key configured)"
|
||||
else:
|
||||
nous_label = "not logged in (run: hermes auth add nous --type oauth)"
|
||||
nous_label = "not logged in (run: hermes portal)"
|
||||
print(
|
||||
f" {'Nous Portal':<12} {check_mark(nous_logged_in)} "
|
||||
f"{nous_label}"
|
||||
|
||||
@ -48,8 +48,8 @@ def test_nous_401_guidance_strings_present():
|
||||
# (Nous Portal has no API key path — auth_type=oauth_device_code only).
|
||||
assert "Nous Portal OAuth token was rejected" in source
|
||||
|
||||
# Must give the exact re-auth command, not a generic "hermes setup".
|
||||
assert "hermes auth add nous --type oauth" in source
|
||||
# Must give a concrete re-auth command, not a generic "hermes setup".
|
||||
assert "hermes portal" in source
|
||||
|
||||
# Must point at the portal so users can check account/credit status.
|
||||
assert "portal.nousresearch.com" in source
|
||||
|
||||
111
tests/hermes_cli/test_portal_cli.py
Normal file
111
tests/hermes_cli/test_portal_cli.py
Normal file
@ -0,0 +1,111 @@
|
||||
"""Tests for `hermes portal` dispatch.
|
||||
|
||||
`hermes portal` (no subcommand) is the human-readable alias for the Nous Portal
|
||||
one-shot onboarding (`hermes auth add nous --type oauth` / `hermes setup
|
||||
--portal`). The prior status default moved to `hermes portal info`, with
|
||||
`status` retained as a back-compat alias.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
from types import SimpleNamespace
|
||||
|
||||
import pytest
|
||||
|
||||
from hermes_cli import portal_cli
|
||||
|
||||
|
||||
def _args(portal_command):
|
||||
return SimpleNamespace(portal_command=portal_command)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("sub", [None, "", "login"])
|
||||
def test_bare_portal_and_login_run_one_shot(monkeypatch, sub):
|
||||
"""`hermes portal`, `hermes portal login` -> one-shot onboarding."""
|
||||
calls = {"login": 0, "status": 0}
|
||||
|
||||
def fake_one_shot(config):
|
||||
calls["login"] += 1
|
||||
|
||||
def fake_status(args):
|
||||
calls["status"] += 1
|
||||
return 0
|
||||
|
||||
monkeypatch.setattr(
|
||||
"hermes_cli.setup._run_portal_one_shot", fake_one_shot
|
||||
)
|
||||
monkeypatch.setattr(portal_cli, "_cmd_status", fake_status)
|
||||
monkeypatch.setattr(portal_cli, "load_config", lambda: {})
|
||||
|
||||
rc = portal_cli.portal_command(_args(sub))
|
||||
|
||||
assert rc == 0
|
||||
assert calls["login"] == 1
|
||||
assert calls["status"] == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize("sub", ["info", "status"])
|
||||
def test_info_and_status_alias_run_status(monkeypatch, sub):
|
||||
"""`hermes portal info` and the `status` back-compat alias -> status."""
|
||||
calls = {"login": 0, "status": 0}
|
||||
|
||||
monkeypatch.setattr(
|
||||
"hermes_cli.setup._run_portal_one_shot",
|
||||
lambda config: calls.__setitem__("login", calls["login"] + 1),
|
||||
)
|
||||
|
||||
def fake_status(args):
|
||||
calls["status"] += 1
|
||||
return 0
|
||||
|
||||
monkeypatch.setattr(portal_cli, "_cmd_status", fake_status)
|
||||
|
||||
rc = portal_cli.portal_command(_args(sub))
|
||||
|
||||
assert rc == 0
|
||||
assert calls["status"] == 1
|
||||
assert calls["login"] == 0
|
||||
|
||||
|
||||
def test_open_and_tools_dispatch(monkeypatch):
|
||||
seen = []
|
||||
monkeypatch.setattr(portal_cli, "_cmd_open", lambda a: seen.append("open") or 0)
|
||||
monkeypatch.setattr(portal_cli, "_cmd_tools", lambda a: seen.append("tools") or 0)
|
||||
|
||||
assert portal_cli.portal_command(_args("open")) == 0
|
||||
assert portal_cli.portal_command(_args("tools")) == 0
|
||||
assert seen == ["open", "tools"]
|
||||
|
||||
|
||||
def test_unknown_subcommand_returns_error(capsys):
|
||||
rc = portal_cli.portal_command(_args("bogus"))
|
||||
assert rc == 1
|
||||
err = capsys.readouterr().err
|
||||
assert "Unknown portal subcommand" in err
|
||||
|
||||
|
||||
def test_login_cancelled_returns_one(monkeypatch):
|
||||
def boom(config):
|
||||
raise KeyboardInterrupt
|
||||
|
||||
monkeypatch.setattr("hermes_cli.setup._run_portal_one_shot", boom)
|
||||
monkeypatch.setattr(portal_cli, "load_config", lambda: {})
|
||||
|
||||
rc = portal_cli.portal_command(_args(None))
|
||||
assert rc == 1
|
||||
|
||||
|
||||
def test_parser_registers_subcommands():
|
||||
parser = argparse.ArgumentParser()
|
||||
subparsers = parser.add_subparsers(dest="command")
|
||||
portal_cli.add_parser(subparsers)
|
||||
|
||||
# Bare `portal` resolves to portal_command with no portal_command set.
|
||||
ns = parser.parse_args(["portal"])
|
||||
assert ns.func is portal_cli.portal_command
|
||||
assert getattr(ns, "portal_command", None) in (None, "")
|
||||
|
||||
# All documented subcommands parse.
|
||||
for sub in ("login", "info", "status", "open", "tools"):
|
||||
ns = parser.parse_args(["portal", sub])
|
||||
assert ns.portal_command == sub
|
||||
@ -77,7 +77,7 @@ def test_show_status_reports_nous_auth_error(monkeypatch, capsys, tmp_path):
|
||||
status_mod.show_status(SimpleNamespace(all=False, deep=False))
|
||||
|
||||
output = capsys.readouterr().out
|
||||
assert "Nous Portal ✗ not logged in (run: hermes auth add nous --type oauth)" in output
|
||||
assert "Nous Portal ✗ not logged in (run: hermes portal)" in output
|
||||
assert "Error: Refresh session has been revoked" in output
|
||||
assert "Access exp:" in output
|
||||
assert "Key exp:" in output
|
||||
|
||||
@ -775,7 +775,7 @@ export default function SystemPage() {
|
||||
)}
|
||||
{!portal?.logged_in && (
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Log in with <span className="font-mono">hermes auth add nous --type oauth</span>.
|
||||
Log in with <span className="font-mono">hermes portal</span>.
|
||||
</p>
|
||||
)}
|
||||
</CardContent>
|
||||
|
||||
@ -57,7 +57,7 @@ See [OAuth over SSH / Remote Hosts](/guides/oauth-over-ssh) for the full walkthr
|
||||
## 3. Verify it worked
|
||||
|
||||
```bash
|
||||
hermes portal status
|
||||
hermes portal info
|
||||
```
|
||||
|
||||
You should see:
|
||||
@ -178,12 +178,12 @@ For team setups where multiple humans share a machine, each human has their own
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### `hermes portal status` shows "not logged in" after `hermes setup --portal`
|
||||
### `hermes portal info` shows "not logged in" after `hermes setup --portal`
|
||||
|
||||
The OAuth flow didn't complete. Re-run it:
|
||||
|
||||
```bash
|
||||
hermes auth add nous --type oauth
|
||||
hermes portal
|
||||
```
|
||||
|
||||
If your browser doesn't open or the callback fails, you're likely on a remote/headless host — see [OAuth over SSH](/guides/oauth-over-ssh) for the port-forwarding and manual-paste workarounds.
|
||||
@ -203,7 +203,7 @@ hermes model
|
||||
# pick Nous Portal
|
||||
```
|
||||
|
||||
Re-verify with `hermes portal status`.
|
||||
Re-verify with `hermes portal info`.
|
||||
|
||||
### Tool Gateway tools showing partner names instead of "via Nous Portal"
|
||||
|
||||
@ -239,7 +239,7 @@ If a model is genuinely unavailable, [open an issue](https://github.com/NousRese
|
||||
|
||||
### Billing not appearing on my Portal account
|
||||
|
||||
`hermes portal status` will tell you whether you're actually routing through the Portal or some other provider. Common causes:
|
||||
`hermes portal info` will tell you whether you're actually routing through the Portal or some other provider. Common causes:
|
||||
|
||||
- `model.provider` set to `openrouter`/`anthropic`/etc. instead of `nous`
|
||||
- An OAuth refresh failure that fell back to a different configured provider
|
||||
|
||||
@ -130,12 +130,15 @@ If you use [Hermes profiles](/user-guide/profiles), the Portal refresh token is
|
||||
### Inspecting what's wired up
|
||||
|
||||
```bash
|
||||
hermes portal status # login status, subscription info, model + gateway routing
|
||||
hermes portal # log in to Nous Portal + set it up (one-shot onboarding)
|
||||
hermes portal info # login status, subscription info, model + gateway routing
|
||||
hermes portal tools # detailed Tool Gateway catalog with per-tool routing
|
||||
hermes portal open # open the subscription management page in your browser
|
||||
```
|
||||
|
||||
`hermes portal status` (or just `hermes portal`) gives you the high-level overview:
|
||||
`hermes portal` (with no subcommand) is the human-readable alias for `hermes auth add nous --type oauth` — it logs you in, sets Nous as your inference provider, and offers the Tool Gateway opt-in (identical to `hermes setup --portal`).
|
||||
|
||||
`hermes portal info` gives you the high-level overview:
|
||||
|
||||
```
|
||||
Nous Portal
|
||||
@ -234,12 +237,12 @@ If the Portal invalidates the refresh token (password change, manual revoke, ses
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### `hermes portal status` shows "not logged in"
|
||||
### `hermes portal info` shows "not logged in"
|
||||
|
||||
You haven't completed the OAuth flow, or your refresh token was wiped. Run:
|
||||
|
||||
```bash
|
||||
hermes auth add nous --type oauth
|
||||
hermes portal
|
||||
```
|
||||
|
||||
or use `hermes model` and re-select Nous Portal.
|
||||
@ -260,7 +263,7 @@ If a model is genuinely missing, [open an issue](https://github.com/NousResearch
|
||||
|
||||
### Bills not appearing on my Portal account
|
||||
|
||||
Check `hermes portal status` first — if it shows you're using a different provider (`Model: currently openrouter` instead of `using Nous as inference provider`), your local config has drifted. Run `hermes model`, pick Nous Portal, and the next request will route through your subscription.
|
||||
Check `hermes portal info` first — if it shows you're using a different provider (`Model: currently openrouter` instead of `using Nous as inference provider`), your local config has drifted. Run `hermes model`, pick Nous Portal, and the next request will route through your subscription.
|
||||
|
||||
## See also
|
||||
|
||||
|
||||
@ -66,7 +66,7 @@ In the `model:` config section, you can use either `default:` or `model:` as the
|
||||
```bash
|
||||
hermes setup --portal # fresh install — OAuth + provider + gateway in one command
|
||||
hermes model # existing install — pick "Nous Portal" from the list
|
||||
hermes portal status # inspect login + routing at any time
|
||||
hermes portal info # inspect login + routing at any time
|
||||
```
|
||||
|
||||
Don't have a subscription yet? Get one at [portal.nousresearch.com/manage-subscription](https://portal.nousresearch.com/manage-subscription).
|
||||
@ -89,7 +89,7 @@ Even when using Nous Portal, Codex, or a custom endpoint, some tools (vision, we
|
||||
:::
|
||||
|
||||
:::tip Nous Tool Gateway
|
||||
Paid Nous Portal subscribers also get access to the **[Tool Gateway](/user-guide/features/tool-gateway)** — web search, image generation, TTS, and browser automation routed through your subscription. No extra API keys needed. On a fresh install, `hermes setup --portal` logs you in, sets Nous as your provider, and turns the gateway on in one command. Existing users can enable it from `hermes model` or per-tool from `hermes tools`. Inspect routing at any time with `hermes portal status`.
|
||||
Paid Nous Portal subscribers also get access to the **[Tool Gateway](/user-guide/features/tool-gateway)** — web search, image generation, TTS, and browser automation routed through your subscription. No extra API keys needed. On a fresh install, `hermes setup --portal` logs you in, sets Nous as your provider, and turns the gateway on in one command. Existing users can enable it from `hermes model` or per-tool from `hermes tools`. Inspect routing at any time with `hermes portal info`.
|
||||
:::
|
||||
|
||||
### Two Commands for Model Management
|
||||
|
||||
@ -12,7 +12,7 @@ Hermes uses two kinds of model slots:
|
||||
This page covers configuring both from the dashboard. If you prefer config files or the CLI, jump to [Alternative methods](#alternative-methods) at the bottom.
|
||||
|
||||
:::tip Fastest path: Nous Portal
|
||||
[Nous Portal](/user-guide/features/tool-gateway) provides 300+ models under one subscription. On a fresh install, run `hermes setup --portal` to log in and set Nous as your provider in one command. Inspect what's wired up with `hermes portal status`.
|
||||
[Nous Portal](/user-guide/features/tool-gateway) provides 300+ models under one subscription. On a fresh install, run `hermes setup --portal` to log in and set Nous as your provider in one command. Inspect what's wired up with `hermes portal info`.
|
||||
|
||||
- Portal subscribers also get **10% off token-billed providers**.
|
||||
:::
|
||||
|
||||
@ -29,7 +29,7 @@ proxy when you just want **the model** through your subscription.
|
||||
### 1. Log into your provider (one-time)
|
||||
|
||||
```bash
|
||||
hermes auth add nous
|
||||
hermes portal
|
||||
```
|
||||
|
||||
This opens your browser for the Nous Portal OAuth flow. Hermes stores
|
||||
@ -88,10 +88,10 @@ Hermes proxy upstream adapters
|
||||
[nous ] Nous Portal — ready (bearer expires 2026-05-15T06:43:21Z)
|
||||
```
|
||||
|
||||
If you see `not logged in`, run `hermes auth add nous`. If you see
|
||||
If you see `not logged in`, run `hermes portal`. If you see
|
||||
`credentials need attention`, your refresh token was revoked (rare —
|
||||
happens if you signed out from the Portal web UI) — just re-run
|
||||
`hermes auth add nous`.
|
||||
`hermes portal`.
|
||||
|
||||
## Allowed paths
|
||||
|
||||
|
||||
@ -60,12 +60,12 @@ hermes tools # Enable the gateway per-tool — pick "Nous Subscript
|
||||
Check what's active at any time:
|
||||
|
||||
```bash
|
||||
hermes portal status # Portal auth + Tool Gateway routing summary
|
||||
hermes portal info # Portal auth + Tool Gateway routing summary
|
||||
hermes portal tools # Gateway catalog with current routing per tool
|
||||
hermes status # Full system status (Tool Gateway is one section)
|
||||
```
|
||||
|
||||
`hermes portal status` shows a section like:
|
||||
`hermes portal info` shows a section like:
|
||||
|
||||
```
|
||||
◆ Nous Tool Gateway
|
||||
|
||||
@ -57,7 +57,7 @@ hermes auth add nous --type oauth --manual-paste
|
||||
## 3. 验证配置是否成功
|
||||
|
||||
```bash
|
||||
hermes portal status
|
||||
hermes portal info
|
||||
```
|
||||
|
||||
你应该看到:
|
||||
@ -175,12 +175,12 @@ hermes cron add "Daily AI news summary" "every day at 9am" \
|
||||
|
||||
## 故障排查
|
||||
|
||||
### 运行 `hermes setup --portal` 后,`hermes portal status` 显示"not logged in"
|
||||
### 运行 `hermes setup --portal` 后,`hermes portal info` 显示"not logged in"
|
||||
|
||||
OAuth 流程未完成。重新运行:
|
||||
|
||||
```bash
|
||||
hermes auth add nous --type oauth
|
||||
hermes portal
|
||||
```
|
||||
|
||||
如果浏览器未打开或回调失败,你可能在远程/无头主机上——参见 [OAuth over SSH](/guides/oauth-over-ssh) 了解端口转发和手动粘贴的解决方案。
|
||||
@ -200,7 +200,7 @@ hermes model
|
||||
# 选择 Nous Portal
|
||||
```
|
||||
|
||||
使用 `hermes portal status` 重新验证。
|
||||
使用 `hermes portal info` 重新验证。
|
||||
|
||||
### Tool Gateway 工具显示合作方名称而非"via Nous Portal"
|
||||
|
||||
@ -236,7 +236,7 @@ Portal 目录镜像了 OpenRouter 的模型列表(300+ 个)。如果某个
|
||||
|
||||
### 账单未出现在我的 Portal 账号中
|
||||
|
||||
`hermes portal status` 会告诉你是否真的在通过 Portal 路由,还是使用了其他 provider。常见原因:
|
||||
`hermes portal info` 会告诉你是否真的在通过 Portal 路由,还是使用了其他 provider。常见原因:
|
||||
|
||||
- `model.provider` 设置为 `openrouter`/`anthropic`/等,而非 `nous`
|
||||
- OAuth refresh 失败后回退到了其他已配置的 provider
|
||||
|
||||
@ -126,12 +126,15 @@ OAuth 需要浏览器,但回调的 loopback 运行在 Hermes 所在的机器
|
||||
### 查看当前配置状态
|
||||
|
||||
```bash
|
||||
hermes portal status # 登录状态、订阅信息、模型与 gateway 路由
|
||||
hermes portal # 登录 Nous Portal 并完成配置(一键引导)
|
||||
hermes portal info # 登录状态、订阅信息、模型与 gateway 路由
|
||||
hermes portal tools # 详细的 Tool Gateway 目录及每个工具的路由信息
|
||||
hermes portal open # 在浏览器中打开订阅管理页面
|
||||
```
|
||||
|
||||
`hermes portal status`(或直接 `hermes portal`)给出高层概览:
|
||||
`hermes portal`(不带子命令)是 `hermes auth add nous --type oauth` 的易记别名——它会登录、把 Nous 设为推理服务商,并提供 Tool Gateway 启用选项(与 `hermes setup --portal` 等价)。
|
||||
|
||||
`hermes portal info` 给出高层概览:
|
||||
|
||||
```
|
||||
Nous Portal
|
||||
@ -230,12 +233,12 @@ Hermes 在每次推理调用时从存储的 Portal refresh token 生成短期 JW
|
||||
|
||||
## 故障排查
|
||||
|
||||
### `hermes portal status` 显示"not logged in"
|
||||
### `hermes portal info` 显示"not logged in"
|
||||
|
||||
你尚未完成 OAuth 流程,或 refresh token 已被清除。运行:
|
||||
|
||||
```bash
|
||||
hermes auth add nous --type oauth
|
||||
hermes portal
|
||||
```
|
||||
|
||||
或使用 `hermes model` 重新选择 Nous Portal。
|
||||
@ -256,7 +259,7 @@ Portal 通过 OpenRouter 代理,因此 OpenRouter 支持的所有模型通常
|
||||
|
||||
### 账单未出现在我的 Portal 账号中
|
||||
|
||||
先检查 `hermes portal status`——如果显示你正在使用其他提供商(`Model: currently openrouter` 而非 `using Nous as inference provider`),说明本地配置已偏离。运行 `hermes model`,选择 Nous Portal,下一次请求将通过你的订阅路由。
|
||||
先检查 `hermes portal info`——如果显示你正在使用其他提供商(`Model: currently openrouter` 而非 `using Nous as inference provider`),说明本地配置已偏离。运行 `hermes model`,选择 Nous Portal,下一次请求将通过你的订阅路由。
|
||||
|
||||
## 另请参阅
|
||||
|
||||
|
||||
@ -58,7 +58,7 @@ sidebar_position: 1
|
||||
```bash
|
||||
hermes setup --portal # 全新安装——一条命令完成 OAuth + 提供商 + 网关配置
|
||||
hermes model # 已有安装——从列表中选择"Nous Portal"
|
||||
hermes portal status # 随时查看登录状态和路由信息
|
||||
hermes portal info # 随时查看登录状态和路由信息
|
||||
```
|
||||
|
||||
还没有订阅?前往 [portal.nousresearch.com/manage-subscription](https://portal.nousresearch.com/manage-subscription) 购买。
|
||||
@ -77,7 +77,7 @@ OpenAI Codex 提供商通过设备码(device code)认证——打开一个 U
|
||||
:::
|
||||
|
||||
:::tip Nous Tool Gateway
|
||||
付费 Nous Portal 订阅者还可访问 **[Tool Gateway](/user-guide/features/tool-gateway)**——网页搜索、图像生成、TTS 和浏览器自动化,均通过你的订阅路由。无需额外 API key。全新安装时,`hermes setup --portal` 一条命令即可完成登录、设置 Nous 为提供商并开启网关。现有用户可通过 `hermes model` 或 `hermes tools` 按工具启用。随时使用 `hermes portal status` 查看路由状态。
|
||||
付费 Nous Portal 订阅者还可访问 **[Tool Gateway](/user-guide/features/tool-gateway)**——网页搜索、图像生成、TTS 和浏览器自动化,均通过你的订阅路由。无需额外 API key。全新安装时,`hermes setup --portal` 一条命令即可完成登录、设置 Nous 为提供商并开启网关。现有用户可通过 `hermes model` 或 `hermes tools` 按工具启用。随时使用 `hermes portal info` 查看路由状态。
|
||||
:::
|
||||
|
||||
### 模型管理的两个命令
|
||||
|
||||
@ -12,7 +12,7 @@ Hermes 使用两类模型槽位:
|
||||
本页介绍如何通过仪表板配置上述两类模型。如需使用配置文件或 CLI,请跳至底部的[其他方法](#alternative-methods)。
|
||||
|
||||
:::tip 最快路径:Nous Portal
|
||||
[Nous Portal](/user-guide/features/tool-gateway) 在单一订阅下提供 300+ 个模型。全新安装后,运行 `hermes setup --portal` 即可登录并一键将 Nous 设为提供商。使用 `hermes portal status` 查看当前配置。
|
||||
[Nous Portal](/user-guide/features/tool-gateway) 在单一订阅下提供 300+ 个模型。全新安装后,运行 `hermes setup --portal` 即可登录并一键将 Nous 设为提供商。使用 `hermes portal info` 查看当前配置。
|
||||
:::
|
||||
|
||||
## Models 页面
|
||||
|
||||
@ -24,7 +24,7 @@ description: "将你的 Nous Portal 订阅(或其他 OAuth 提供商)用作
|
||||
### 1. 登录你的提供商(仅需一次)
|
||||
|
||||
```bash
|
||||
hermes auth add nous
|
||||
hermes portal
|
||||
```
|
||||
|
||||
这会打开浏览器进行 Nous Portal OAuth 流程。Hermes 将刷新令牌存储在 `~/.hermes/auth.json` 中——与所有 Hermes 提供商登录信息存放在同一位置。
|
||||
@ -76,7 +76,7 @@ Hermes proxy upstream adapters
|
||||
[nous ] Nous Portal — ready (bearer expires 2026-05-15T06:43:21Z)
|
||||
```
|
||||
|
||||
如果显示 `not logged in`,请运行 `hermes auth add nous`。如果显示 `credentials need attention`,说明你的刷新令牌已被撤销(较少见——通常发生在你从 Portal Web UI 退出登录时)——重新运行 `hermes auth add nous` 即可。
|
||||
如果显示 `not logged in`,请运行 `hermes portal`。如果显示 `credentials need attention`,说明你的刷新令牌已被撤销(较少见——通常发生在你从 Portal Web UI 退出登录时)——重新运行 `hermes portal` 即可。
|
||||
|
||||
## 允许的路径
|
||||
|
||||
|
||||
Reference in New Issue
Block a user