Skip to content

fix(hermes): label port 8642 as OpenAI-compatible API, not chat UI (#2078)#2088

Merged
ericksoa merged 2 commits into
mainfrom
fix/2078-hermes-chat-ui-port
Apr 20, 2026
Merged

fix(hermes): label port 8642 as OpenAI-compatible API, not chat UI (#2078)#2088
ericksoa merged 2 commits into
mainfrom
fix/2078-hermes-chat-ui-port

Conversation

@chengjiew

@chengjiew chengjiew commented Apr 20, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #2078. Onboarding told users "Hermes Agent UI" with a tokenized URL for port 8642, but that port serves the OpenAI-compatible API — not a browser dashboard — and the endpoint authenticates via a bearer header, so the URL-fragment token was misleading as well.

  • Added a dashboard descriptor (kind / label / path) to agents/hermes/manifest.yaml so we can describe what a forward port actually serves.
  • Branched printDashboardUi (src/lib/agent-onboard.ts) on the new kind. For api-kind agents we print the label ("OpenAI-compatible API"), drop the #token=… fragment, append the configured path (/v1), and switch the verb to "connecting" instead of "opening this URL".
  • UI-kind agents render identically to before (default kind when the manifest omits dashboard).
  • Kept the legacy CHAT_UI_URL build arg for OpenClaw interop with a comment explaining what it actually points at for Hermes.

Before → after

Before:

  Hermes Agent UI (tokenized URL; treat it like a password)
  Port 8642 must be forwarded before opening this URL.
  http://127.0.0.1:8642/#token=abc123def456

After:

  Hermes Agent OpenAI-compatible API
  Port 8642 must be forwarded before connecting.
  http://127.0.0.1:8642/v1

Reproduced locally by running printDashboardUi against the real loaded manifest — no Docker / sandbox needed.

Test plan

  • npm run build:cli
  • npm run typecheck:cli
  • New regression tests in src/lib/agent-onboard.test.ts covering the api-kind and ui-kind branches (3 cases, all passing)
  • agent-runtime tests unchanged (5/5 still passing)
  • CI full suite
  • Manual onboard of a Hermes sandbox to confirm the rendered text

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Configurable agent dashboards with explicit kind (UI or API) and normalized path handling
    • UI display now shows a label and path for API-style dashboards; Hermes registered as OpenAI-compatible API
  • Documentation

    • Clarified Bearer token authentication and endpoint/path expectations for API dashboards
    • Added notes about port-forwarding and separate Hermes web UI availability
  • Tests

    • Added regression tests covering dashboard output for API vs UI agents

Signed-off-by: Chengjie Wang chengjiew@nvidia.com

Onboarding told users "Hermes Agent UI" with a tokenized URL for port
8642, but that port serves the OpenAI-compatible API — not a browser
dashboard — and the endpoint authenticates via a bearer header, so the
URL-fragment token was misleading as well.

Add a dashboard descriptor to the agent manifest (kind, label, path) and
branch printDashboardUi on it. For api-kind agents we print the label
("OpenAI-compatible API"), drop the token fragment, and append the path
("/v1"). UI-kind behavior is unchanged. The legacy CHAT_UI_URL build arg
is kept for interop with OpenClaw, with a comment explaining what it
actually points at for Hermes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Apr 20, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: b813b113-f75f-4473-95d3-2d90cfd5608d

📥 Commits

Reviewing files that changed from the base of the PR and between 3c999d1 and b46f5d1.

📒 Files selected for processing (2)
  • src/lib/agent-defs.ts
  • src/lib/agent-onboard.test.ts
✅ Files skipped from review due to trivial changes (1)
  • src/lib/agent-onboard.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/lib/agent-defs.ts

📝 Walkthrough

Walkthrough

Adds an explicit dashboard configuration for agents (kind, label, path), documents Hermes as an OpenAI-compatible API (port 8642, /v1, Bearer auth) and updates onboarding to branch on dashboard.kind so API vs UI agents print appropriate endpoint and messaging.

Changes

Cohort / File(s) Summary
Hermes agent metadata & Dockerfile
agents/hermes/Dockerfile, agents/hermes/manifest.yaml
Added documentation and a dashboard: block (kind: api, label: "OpenAI-compatible API", path: "/v1") clarifying port 8642 is an OpenAI-compatible API endpoint and that clients should use a Bearer Authorization header.
Types & agent loader
src/lib/agent-defs.ts
Introduced AgentDashboardKind and AgentDashboard exports; added required dashboard field to AgentDefinition; loadAgent normalizes kind, label, and path with defaults and ensures path starts with /.
Onboarding logic & tests
src/lib/agent-onboard.ts, src/lib/agent-onboard.test.ts
printDashboardUi now branches on dashboard.kind: for api prints manifest label, port-forward note, and endpoint URLs with manifest path and without #token fragments; for ui preserves tokenized UI messaging. Added tests covering both flows.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I hopped in to fix a tiny cue,
Port 8642 now shows what it's due.
API or UI the dashboard will say,
Paths and labels guide the way,
Hermès speaks OpenAI — hop hooray! 🚀

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: clarifying that port 8642 serves an OpenAI-compatible API, not a chat UI.
Linked Issues check ✅ Passed The PR addresses all coding requirements from issue #2078: updated manifest to specify dashboard kind/label/path, branched printDashboardUi logic based on kind, and ensured API endpoints exclude token fragments and include proper paths.
Out of Scope Changes check ✅ Passed All changes are directly scoped to issue #2078 objectives: Dockerfile documentation, manifest configuration, dashboard typing, and onboarding logic for the API endpoint distinction.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/2078-hermes-chat-ui-port

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot 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.

🧹 Nitpick comments (2)
src/lib/agent-defs.ts (1)

157-157: Normalize custom dashboard labels before returning.

On Line [157], you validate d.label.trim() but return d.label as-is. Leading/trailing spaces can leak into output.

♻️ Proposed small normalization tweak
     get dashboard(): AgentDashboard {
       const d = (raw.dashboard as Partial<AgentDashboard>) || {};
       const kind: AgentDashboardKind = d.kind === "api" ? "api" : "ui";
       const defaultLabel = kind === "api" ? "API" : "UI";
+      const normalizedLabel = typeof d.label === "string" ? d.label.trim() : "";
       const rawPath = typeof d.path === "string" ? d.path.trim() : "";
       const path = rawPath ? (rawPath.startsWith("/") ? rawPath : `/${rawPath}`) : "/";
       return {
         kind,
-        label: typeof d.label === "string" && d.label.trim() ? d.label : defaultLabel,
+        label: normalizedLabel || defaultLabel,
         path,
       };
     },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/agent-defs.ts` at line 157, The label return currently validates
d.label with d.label.trim() but returns the original string, allowing
leading/trailing whitespace to persist; update the logic that builds the label
(the property using d.label) to return the trimmed string (e.g., use
d.label.trim()) when d.label is a non-empty string, otherwise fall back to
defaultLabel—optionally compute a normalizedLabel variable before returning to
avoid double-trimming and improve readability.
src/lib/agent-onboard.test.ts (1)

34-44: Restore console.log spy to avoid global test-state leakage.

On line 34, console.log is mocked once and never restored. The Vitest configuration does not have restoreMocks enabled, so the spy will persist across tests. Add a restore hook to ensure this file doesn't leak mock state to other tests.

Suggested fix
-import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
+import { describe, it, expect, beforeEach, afterEach, afterAll, vi } from "vitest";
@@
   afterEach(() => {
     logSpy.mockClear();
   });
+
+  afterAll(() => {
+    logSpy.mockRestore();
+  });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/agent-onboard.test.ts` around lines 34 - 44, The console.log spy
(logSpy) is mocked but never restored which can leak mock state; add a restore
hook (e.g., call logSpy.mockRestore() in an afterAll or at the end of afterEach)
so the spy is removed after tests complete; update the test file to call
logSpy.mockRestore() (referencing the existing logSpy variable) in a teardown
hook (afterAll or afterEach) instead of only clearing mocks.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/lib/agent-defs.ts`:
- Line 157: The label return currently validates d.label with d.label.trim() but
returns the original string, allowing leading/trailing whitespace to persist;
update the logic that builds the label (the property using d.label) to return
the trimmed string (e.g., use d.label.trim()) when d.label is a non-empty
string, otherwise fall back to defaultLabel—optionally compute a normalizedLabel
variable before returning to avoid double-trimming and improve readability.

In `@src/lib/agent-onboard.test.ts`:
- Around line 34-44: The console.log spy (logSpy) is mocked but never restored
which can leak mock state; add a restore hook (e.g., call logSpy.mockRestore()
in an afterAll or at the end of afterEach) so the spy is removed after tests
complete; update the test file to call logSpy.mockRestore() (referencing the
existing logSpy variable) in a teardown hook (afterAll or afterEach) instead of
only clearing mocks.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 88349fdf-2feb-4274-b2d2-d6fba2a97766

📥 Commits

Reviewing files that changed from the base of the PR and between 67db244 and 3c999d1.

📒 Files selected for processing (5)
  • agents/hermes/Dockerfile
  • agents/hermes/manifest.yaml
  • src/lib/agent-defs.ts
  • src/lib/agent-onboard.test.ts
  • src/lib/agent-onboard.ts

Two nits:
- agent-defs.ts: validated `d.label.trim()` but returned the un-trimmed
  `d.label`; pull the trim into `normalizedLabel` so custom labels cannot
  leak leading/trailing whitespace into onboarding output.
- agent-onboard.test.ts: restore the `console.log` spy with an `afterAll`
  hook so the file doesn't leak mock state to later tests (vitest config
  does not enable `restoreMocks`).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@chengjiew chengjiew requested a review from ericksoa April 20, 2026 08:30
@wscurran wscurran added bug Something fails against expected or documented behavior fix labels Apr 20, 2026
@wscurran

Copy link
Copy Markdown
Contributor

✨ Thanks for submitting this PR that proposes a fix to label port 8642 correctly. The changes and test plan you provided will help us review this further.


Possibly related open issues:

@wscurran wscurran added the integration: hermes Hermes integration behavior label Apr 20, 2026

@ericksoa ericksoa 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.

LGTM. Clean design — manifest-level dashboard descriptor with sensible defaults keeps backward compat while fixing the misleading UI labeling for Hermes.

  • loadAgent normalization is solid (trim, leading-slash, kind/label defaults)
  • Both CodeRabbit nits (label trim leak, spy restoration) addressed in commit 2
  • Test coverage for API-kind, API-kind without token, and UI-kind branches
  • CI all green

@ericksoa ericksoa merged commit 8dee23f into main Apr 20, 2026
16 of 17 checks passed
@wscurran wscurran added bug-fix PR fixes a bug or regression and removed fix bug Something fails against expected or documented behavior labels Jun 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug-fix PR fixes a bug or regression integration: hermes Hermes integration behavior

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Port 8642 in Hermes Agent is not a Chat UI

3 participants