Skip to content

Nous Portal subscription integration#25

Closed
rewbs wants to merge 1 commit into
mainfrom
rewbs/nous-portal-integration
Closed

Nous Portal subscription integration#25
rewbs wants to merge 1 commit into
mainfrom
rewbs/nous-portal-integration

Conversation

@rewbs

@rewbs rewbs commented Feb 19, 2026

Copy link
Copy Markdown
Contributor
  • Integration with Nous Portal via subscription, using device auth flow, standard refresh/access token flow, and short-lived API key rotation
  • Optional request dumping for debugging

The flow is:

  • User runs hermes login
  • Hermes calls Portal POST /api/oauth/device/code with client_id=hermes-cli and scope inference:mint_agent_key.
  • Hermes opens the browser to verification_uri_complete and polls POST /api/oauth/token (device_code grant).
  • After user approval on Portal, Hermes receives access_token + refresh_token (+ optional inference_base_url) and stores them in auth state.
  • Hermes immediately resolves runtime credentials:
    • refreshes access token if near expiry,
    • mints or reuses a short-lived agent inference key via POST /api/oauth/agent-key with min_ttl_seconds.
  • Hermes caches the minted key + expiry and reuses it across concurrent processes when still valid.
  • During chat/inference, Hermes auto-refreshes token and rotates agent key when needed (or preemptively when below TTL threshold), then calls the Nous OpenAI-compatible inference API with that key.

Note there are three different credentials with different jobs:

  • access_token: short-lived bearer token the CLI uses to call Portal OAuth-protected endpoints, such as the one to mind API keys.
  • refresh_token: longer-lived token used only to get a new access token, so users don’t have to re-login constantly.
  • short-lived/rotating inference api_key: minted by Portal for the inference API (since that backend only understands API keys, not user/session identity).

The access_token/refresh_token pairing is standard OAuth: keep the token used on normal requests short-lived, and use a separate long-lived credential for renewal. That limits blast radius if an access token leaks and allows safer rotation/revocation policies around refresh tokens.

…ow, standard refresh/access token flow, and short-lived API key rotation

- Optional request dumping for debugging
@teknium1

Copy link
Copy Markdown
Contributor

Ported in the fundamentals, changed the way it was executed (needed multi-provider structure) - thanks!

@teknium1 teknium1 closed this Feb 21, 2026
sudo-yf pushed a commit to sudo-yf/hermes-agent that referenced this pull request Apr 5, 2026
…verflow

fix: project picker clipped and width issues
h4x3rotab pushed a commit to Clawdi-AI/hermes-agent that referenced this pull request Apr 10, 2026
…ousResearch#25)

Replaces hardcoded authenticated=true with real auth check via /api/auth-check endpoint.

Co-authored-by: clawjasper56
h4x3rotab pushed a commit to Clawdi-AI/hermes-agent that referenced this pull request Apr 10, 2026
The auth-check endpoint had its own isBackendReachable() function that
hardcoded http://127.0.0.1:8642 and never tried the fallback port 8643.
This bypassed the multi-port auto-detection logic in gateway-capabilities.ts,
causing the startup screen to loop on 'Connecting...' when the gateway
was running on an alternate port.

Replace the standalone reachability check with ensureGatewayProbed() which
already handles port auto-detection (8642 → 8643) and caches the result.
@tradewind425

Copy link
Copy Markdown

大枠は正しい方向。但し、いくつか実装グリップを詰める必要あり:

gateway/run.py (10.3K行) は Discord 特異的な部分が ~36箇所で全体の ~1% 程度。WhatsApp等マルチプラットフォーム対応もあり、単純な移管ではなく Discord イベントハンドル + routing を抽出→Ouroboros、残りは hermes-agent に hooks として戻す設計が必要。現在 my-changes では tui_gateway/server.py が既にこのパターンを示唆している。

hermes_cli/personas.py (SOUL.md sync 方式) と model_switch.py (can_persist flag 追加) の hook パターンは良い候補。但し hook 呼び出し側と agent 側の API コントラクト(例:JSON-RPC、subprocess IPC)を明確に定義すべき。Discord.js 化するなら必須。

hermes_cli/models.py 破棄 ✓、tools/file_operations.py defer ✓ で合意。

• 本計画と分離として、agent↔Ouroboros の IPC/hook boundary spec を先行タスク化すると、以降の移管作業がスムーズになりそう。

renerocksai added a commit to renerocksai/hermes-agent that referenced this pull request Apr 28, 2026
…agents (phase 10)

The SDK landed PRs NousResearch#24/NousResearch#25/NousResearch#26 in synadia-ai/synadia-agents:
- verb-first subjects (`agents.prompt.{a}.{o}.{s}`, `agents.hb.{a}.{o}.{s}`,
  new `agents.status.{a}.{o}.{s}`) and `metadata.protocol_version="0.3"`
- pinned `_INBOX.agents` reply-inbox prefix (caller-side; no-op for us)
- `name`+`session` collapsed into a single `session_name` (the 5th subject
  token) — `Envelope.session` and the `session=` kwarg on `AgentService` /
  `Agent.prompt` are gone. One service = one session_name.

Package + import root rename: `natsagent` → `synadia-ai-agents`,
`synadia_ai.agents`. Service-side class `Agent` → `AgentService`.

Adapter changes:
- Adopt single-service-per-session: rely on Hermes profile isolation for
  multi-session deployments instead of building an envelope.session demuxer
  on top of `AgentService`. The `_session_locks` dict collapses to a single
  `_session_lock`.
- The SDK explicitly does not own NATS connections: callers build the
  client. Adapter calls `nats.connect(servers=...)` or
  `nats.connect(**sdk.load_context_options(name))` directly.
- Config: `extra.name` + `extra.session_default` → required
  `extra.session_name`; env var `HERMES_NATS_NAME`/`HERMES_NATS_SESSION` →
  `HERMES_NATS_SESSION_NAME`. No migration shim — branch hadn't merged.
- Lock identity rebuilt as `{agent}:{owner}:{session_name}`.

Tests + docs:
- conftest mock renamed `_ensure_natsagent_mock` → `_ensure_synadia_agents_mock`,
  installs under `sys.modules["synadia_ai.agents"]`, also stubs `nats` so
  the adapter's `nats.connect(...)` resolves under test.
- New `mock_nats` fixture in test_nats_connect.py; concurrent-distinct-
  sessions test removed (v0.2-only concept); positive test added that
  chat_id is sourced from `settings.session_name` regardless of any stray
  envelope field.
- design doc §1-§6/§11/§17 updated for v0.3; progress doc gains a Phase 10
  decision-log entry; user-facing nats.md rewritten with verb-first subject
  examples, status endpoint walkthrough, and `_INBOX.agents.>` permission
  note.

Live-verified end-to-end against `nats-server -p 4223` + `hermes-local`
context + `model: anthropic/claude-haiku-4.5` over OpenRouter: real prompt
streamed a real haiku reply through `agents.prompt.hermes.rene.local`,
multi-turn session continuity intact, `/status` slash command dispatched
through the gateway's command registry. Discovery shows
`protocol_version: 0.3`. Heartbeats fire on `agents.hb.hermes.rene.local`.
Status endpoint replies on `agents.status.hermes.rene.local`.

NATS gateway tests: 190/190 green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
renerocksai added a commit to synadia-ai/hermes-agent that referenced this pull request May 6, 2026
…agents (phase 10)

The SDK landed PRs NousResearch#24/NousResearch#25/NousResearch#26 in synadia-ai/synadia-agents:
- verb-first subjects (`agents.prompt.{a}.{o}.{s}`, `agents.hb.{a}.{o}.{s}`,
  new `agents.status.{a}.{o}.{s}`) and `metadata.protocol_version="0.3"`
- pinned `_INBOX.agents` reply-inbox prefix (caller-side; no-op for us)
- `name`+`session` collapsed into a single `session_name` (the 5th subject
  token) — `Envelope.session` and the `session=` kwarg on `AgentService` /
  `Agent.prompt` are gone. One service = one session_name.

Package + import root rename: `natsagent` → `synadia-ai-agents`,
`synadia_ai.agents`. Service-side class `Agent` → `AgentService`.

Adapter changes:
- Adopt single-service-per-session: rely on Hermes profile isolation for
  multi-session deployments instead of building an envelope.session demuxer
  on top of `AgentService`. The `_session_locks` dict collapses to a single
  `_session_lock`.
- The SDK explicitly does not own NATS connections: callers build the
  client. Adapter calls `nats.connect(servers=...)` or
  `nats.connect(**sdk.load_context_options(name))` directly.
- Config: `extra.name` + `extra.session_default` → required
  `extra.session_name`; env var `HERMES_NATS_NAME`/`HERMES_NATS_SESSION` →
  `HERMES_NATS_SESSION_NAME`. No migration shim — branch hadn't merged.
- Lock identity rebuilt as `{agent}:{owner}:{session_name}`.

Tests + docs:
- conftest mock renamed `_ensure_natsagent_mock` → `_ensure_synadia_agents_mock`,
  installs under `sys.modules["synadia_ai.agents"]`, also stubs `nats` so
  the adapter's `nats.connect(...)` resolves under test.
- New `mock_nats` fixture in test_nats_connect.py; concurrent-distinct-
  sessions test removed (v0.2-only concept); positive test added that
  chat_id is sourced from `settings.session_name` regardless of any stray
  envelope field.
- design doc §1-§6/§11/§17 updated for v0.3; progress doc gains a Phase 10
  decision-log entry; user-facing nats.md rewritten with verb-first subject
  examples, status endpoint walkthrough, and `_INBOX.agents.>` permission
  note.

Live-verified end-to-end against `nats-server -p 4223` + `hermes-local`
context + `model: anthropic/claude-haiku-4.5` over OpenRouter: real prompt
streamed a real haiku reply through `agents.prompt.hermes.rene.local`,
multi-turn session continuity intact, `/status` slash command dispatched
through the gateway's command registry. Discovery shows
`protocol_version: 0.3`. Heartbeats fire on `agents.hb.hermes.rene.local`.
Status endpoint replies on `agents.status.hermes.rene.local`.

NATS gateway tests: 190/190 green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
renerocksai added a commit to synadia-ai/hermes-agent-work that referenced this pull request May 18, 2026
…agents (phase 10)

The SDK landed PRs NousResearch#24/NousResearch#25/NousResearch#26 in synadia-ai/synadia-agents:
- verb-first subjects (`agents.prompt.{a}.{o}.{s}`, `agents.hb.{a}.{o}.{s}`,
  new `agents.status.{a}.{o}.{s}`) and `metadata.protocol_version="0.3"`
- pinned `_INBOX.agents` reply-inbox prefix (caller-side; no-op for us)
- `name`+`session` collapsed into a single `session_name` (the 5th subject
  token) — `Envelope.session` and the `session=` kwarg on `AgentService` /
  `Agent.prompt` are gone. One service = one session_name.

Package + import root rename: `natsagent` → `synadia-ai-agents`,
`synadia_ai.agents`. Service-side class `Agent` → `AgentService`.

Adapter changes:
- Adopt single-service-per-session: rely on Hermes profile isolation for
  multi-session deployments instead of building an envelope.session demuxer
  on top of `AgentService`. The `_session_locks` dict collapses to a single
  `_session_lock`.
- The SDK explicitly does not own NATS connections: callers build the
  client. Adapter calls `nats.connect(servers=...)` or
  `nats.connect(**sdk.load_context_options(name))` directly.
- Config: `extra.name` + `extra.session_default` → required
  `extra.session_name`; env var `HERMES_NATS_NAME`/`HERMES_NATS_SESSION` →
  `HERMES_NATS_SESSION_NAME`. No migration shim — branch hadn't merged.
- Lock identity rebuilt as `{agent}:{owner}:{session_name}`.

Tests + docs:
- conftest mock renamed `_ensure_natsagent_mock` → `_ensure_synadia_agents_mock`,
  installs under `sys.modules["synadia_ai.agents"]`, also stubs `nats` so
  the adapter's `nats.connect(...)` resolves under test.
- New `mock_nats` fixture in test_nats_connect.py; concurrent-distinct-
  sessions test removed (v0.2-only concept); positive test added that
  chat_id is sourced from `settings.session_name` regardless of any stray
  envelope field.
- design doc §1-§6/§11/§17 updated for v0.3; progress doc gains a Phase 10
  decision-log entry; user-facing nats.md rewritten with verb-first subject
  examples, status endpoint walkthrough, and `_INBOX.agents.>` permission
  note.

Live-verified end-to-end against `nats-server -p 4223` + `hermes-local`
context + `model: anthropic/claude-haiku-4.5` over OpenRouter: real prompt
streamed a real haiku reply through `agents.prompt.hermes.rene.local`,
multi-turn session continuity intact, `/status` slash command dispatched
through the gateway's command registry. Discovery shows
`protocol_version: 0.3`. Heartbeats fire on `agents.hb.hermes.rene.local`.
Status endpoint replies on `agents.status.hermes.rene.local`.

NATS gateway tests: 190/190 green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
difeizheng pushed a commit to difeizheng/zdf-hermes-agent that referenced this pull request Jun 3, 2026
Fixes 12 remaining MEDIUM issues from the deep audit (19 total, 7 fixed in Round 12):

design_agent:
- NousResearch#15: add asyncio.wait_for(300s) around LLM API call to prevent infinite hangs
- NousResearch#17: replace 2x hardcoded 'claude-opus-4-8' with shared DEFAULT_MODEL constant

qa_agent / validate_agent:
- NousResearch#20,NousResearch#22,NousResearch#23: already fixed in Round 12 (verified — dynamic timeout/threshold values used)

memory.py:
- NousResearch#24: frontmatter parser uses regex r'^---$' instead of str.split('---',2),
  preventing false splits on content containing '---' (SQL, markdown tables)
- NousResearch#25: parse and preserve 'description' field from frontmatter in metadata,
  fixing write→load roundtrip data loss

profiles.py:
- NousResearch#26: ProfileConfig now frozen=True (immutable dataclass per coding standards)

deploy_agent:
- NousResearch#31: replace 2x sync subprocess.run with asyncio.create_subprocess_exec
- fix 5x .decode() → .decode('utf-8', errors='replace') for Windows CJK safety
- remove unused import subprocess

db.py:
- NousResearch#27: add class docstring explaining RLock + _unlocked pattern
- NousResearch#28: FK constraints already in DDL (verified PRAGMA foreign_keys=ON active)
- NousResearch#29: add _ensure_connection() with PRAGMA integrity_check(1) + auto-reconnect
       on 4 critical methods (create_task, get_task, claim_task, submit_result)
- extract _create_connection() static method for reuse by reconnect

Tests: 79 passed, 0 failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants