mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-30 19:09:28 +00:00
Companion fixes from a full dashboard QA pass (every page dogfooded live), on top of the cherry-picked #31863 header-slot fix: - ChatPage: harden the header-slot effect further — useLayoutEffect and never write the slot while inactive, so the handoff commentary and ownership rule live next to the code. - LogsPage: level classification used raw substring matching, so INFO lines carrying 'parse_errors=0' (or paths like errors.log) rendered red. New unit-tested classifier (web/src/lib/log-classify.ts) anchors on the hermes_logging level token with a word-boundary fallback. - Channels API: plugin platforms (irc, ntfy, photon, teams, …) rendered as nameless title-cased cards ('Irc', 'Ntfy') with empty descriptions. Two root causes: (1) plugin discovery never ran in the dashboard server process, so plugin_entries() was empty; (2) Platform enum pseudo-members claimed plugin ids before the registry could attach labels. The catalog now discovers plugins explicitly and resolves plugin metadata first; added descriptions + docs links for bundled plugin platforms and the msgraph_webhook / whatsapp_cloud / relay enum members. Regression test sabotage-verified against the old enum-first ordering. - Config schema: updates.refresh_cua_driver declared type 'bool' (schema vocabulary is 'boolean'), so the switch rendered as a text input holding 'true'. - Page titles: '/mcp' rendered as 'Mcp' via the naive capitalize fallback; literal-label table now covers MCP/Files/Channels/Webhooks/ Pairing/System (unit-tested). - AuthWidget: skip the guaranteed-401 /api/auth/me probe in loopback mode — every dashboard load logged a console error for nothing. - Model picker: with no filter, providers that actually have models float above the wall of '0 models' rows. - Cron: empty state now carries an actionable Create button.
36 lines
1.3 KiB
TypeScript
36 lines
1.3 KiB
TypeScript
/**
|
|
* Log-line level classification for the dashboard Logs page.
|
|
*
|
|
* Prefers the structured level token emitted by hermes_logging
|
|
* ("2026-07-26 13:07:45,228 INFO …"); falls back to word-boundary matching
|
|
* for untimestamped lines (tracebacks, wrapped continuations). Plain
|
|
* substring matching is deliberately avoided — INFO lines carrying payloads
|
|
* like "parse_errors=0" or paths like "errors.log" must not render red.
|
|
*/
|
|
|
|
export type LogLevel = "error" | "warning" | "info" | "debug";
|
|
|
|
// Level token as emitted by hermes_logging, anchored to the line head so
|
|
// payload text can't spoof the level.
|
|
const LEVEL_TOKEN_RE =
|
|
/^\d{4}-\d{2}-\d{2}[ T][\d:,.]+\s+(DEBUG|INFO|WARNING|WARN|ERROR|CRITICAL|FATAL)\b/;
|
|
|
|
export function classifyLine(line: string): LogLevel {
|
|
const token = LEVEL_TOKEN_RE.exec(line)?.[1];
|
|
if (token) {
|
|
if (token === "ERROR" || token === "CRITICAL" || token === "FATAL")
|
|
return "error";
|
|
if (token === "WARNING" || token === "WARN") return "warning";
|
|
if (token === "DEBUG") return "debug";
|
|
return "info";
|
|
}
|
|
const upper = line.toUpperCase();
|
|
if (
|
|
/\b(ERROR|CRITICAL|FATAL)\b/.test(upper) ||
|
|
upper.startsWith("TRACEBACK (")
|
|
)
|
|
return "error";
|
|
if (/\b(WARNING|WARN)\b/.test(upper)) return "warning";
|
|
if (/\bDEBUG\b/.test(upper)) return "debug";
|
|
return "info";
|
|
}
|