fix(hermes): label port 8642 as OpenAI-compatible API, not chat UI (#2078)#2088
Conversation
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>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughAdds an explicit Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
🧹 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 returnd.labelas-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: Restoreconsole.logspy to avoid global test-state leakage.On line 34,
console.logis mocked once and never restored. The Vitest configuration does not haverestoreMocksenabled, 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
📒 Files selected for processing (5)
agents/hermes/Dockerfileagents/hermes/manifest.yamlsrc/lib/agent-defs.tssrc/lib/agent-onboard.test.tssrc/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>
|
✨ 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: |
ericksoa
left a comment
There was a problem hiding this comment.
LGTM. Clean design — manifest-level dashboard descriptor with sensible defaults keeps backward compat while fixing the misleading UI labeling for Hermes.
loadAgentnormalization 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
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.
dashboarddescriptor (kind/label/path) toagents/hermes/manifest.yamlso we can describe what a forward port actually serves.printDashboardUi(src/lib/agent-onboard.ts) on the new kind. Forapi-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".dashboard).CHAT_UI_URLbuild arg for OpenClaw interop with a comment explaining what it actually points at for Hermes.Before → after
Before:
After:
Reproduced locally by running
printDashboardUiagainst the real loaded manifest — no Docker / sandbox needed.Test plan
npm run build:clinpm run typecheck:clisrc/lib/agent-onboard.test.tscovering the api-kind and ui-kind branches (3 cases, all passing)agent-runtimetests unchanged (5/5 still passing)🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Documentation
Tests
Signed-off-by: Chengjie Wang chengjiew@nvidia.com