feat(#1292): add GET /api/dashboard-state to hive-ag3nt
hive-ag3nt now exposes a lean DashboardState endpoint that returns the
agent-owned fields the dashboard card needs:
- status_text / status_set_at (from hyperhive-status on disk)
- ctx_tokens / context_window_tokens (from Bus)
- rate_limited (from Bus)
- links (from agent_links — includes screen link for GUI agents,
which c0re's disk-based fallback cannot determine)
The dashboard fetches `${containerBase}/api/dashboard-state` instead of
the previous c0re proxy `/api/agent/{name}/links`. For gateway deployments
this is a same-origin call to the agent via the gateway's unix-socket
upstream; for direct TCP it hits the agent port directly. Both paths fail
gracefully (empty strip) when the agent is starting up.
The main behaviour fix: GUI agents now show the screen link in the dashboard
nav strip. c0re's build_nav_links reads /etc/hyperhive/gui.json from outside
the container (not possible), so it always omitted the screen link.
This commit is contained in:
parent
750f64b7f0
commit
40845c21cd
2 changed files with 92 additions and 11 deletions
|
|
@ -724,11 +724,12 @@ window.marked = marked;
|
|||
head.append(
|
||||
el('a', { class: 'name', href: url, target: '_blank', rel: 'noopener' }, c.name),
|
||||
);
|
||||
// Icon-only nav strip — populated async from `/api/agent/{name}/links`,
|
||||
// a same-origin proxy that forwards the agent backend's own link list
|
||||
// (stats / screen-if-gui / forge profile / agent-configs / extras).
|
||||
// The agent backend is the single source of truth; no hardcoded link
|
||||
// list here. DOM-built — link strings come from the agent's process
|
||||
// Icon-only nav strip — populated async from the agent's own
|
||||
// `GET /api/dashboard-state` (via gateway when enabled, direct
|
||||
// TCP otherwise). The agent is the single source of truth for its
|
||||
// link list: stats / screen (GUI agents only — c0re's disk-based
|
||||
// fallback cannot detect this) / forge profile / agent-configs /
|
||||
// extras. DOM-built — link strings come from the agent's process
|
||||
// and must never reach the HTML parser.
|
||||
const navStrip = el('span', { class: 'nav-strip' });
|
||||
head.append(navStrip);
|
||||
|
|
@ -742,11 +743,14 @@ window.marked = marked;
|
|||
? `/agent/${encodeURIComponent(c.name)}`
|
||||
: `http://${hostname}:${c.port}`;
|
||||
if (c.running) {
|
||||
fetch(`/api/agent/${encodeURIComponent(c.name)}/links`)
|
||||
.then((r) => (r.ok ? r.json() : []))
|
||||
.then((links) => {
|
||||
if (!Array.isArray(links)) return;
|
||||
for (const lnk of links) {
|
||||
// Fetch the lean dashboard-state snapshot from the agent directly.
|
||||
// Fails gracefully (empty strip) when the agent is starting up
|
||||
// or the gateway is not yet routing to it.
|
||||
fetch(`${containerBase}/api/dashboard-state`)
|
||||
.then((r) => (r.ok ? r.json() : null))
|
||||
.then((ds) => {
|
||||
if (!ds || !Array.isArray(ds.links)) return;
|
||||
for (const lnk of ds.links) {
|
||||
const href = lnk.kind === 'forge' ? forgeBase + (lnk.url || '')
|
||||
: lnk.kind === 'external' ? (lnk.url || '')
|
||||
: /* container */ containerBase + '/' + (lnk.url || '');
|
||||
|
|
@ -762,7 +766,7 @@ window.marked = marked;
|
|||
navStrip.append(a);
|
||||
}
|
||||
})
|
||||
.catch(() => { /* graceful: agent down → no strip */ });
|
||||
.catch(() => { /* graceful: agent starting / gateway miss → no strip */ });
|
||||
}
|
||||
// Status / runtime badges. Pending transients always win
|
||||
// (start / stop / restart / rebuild is in progress). Otherwise,
|
||||
|
|
|
|||
Loading…
Reference in a new issue