Agents page: reorganize into the Agent Command Center (per-agent live metrics)
ci / gates (push) Failing after 13s
ci / rust (push) Has been skipped
ci / sandbox-k8s (push) Has been skipped
ci / frontend (push) Has been skipped
ci / e2e (push) Has been skipped

Replace the single centered "anatomy profile" + resizable chat split with an
operator command center: compact 62px identity strip → 5-tile per-agent metrics
band → three independently-scrolling LIVE · BRAIN · SURFACE columns. Chat moves to
the computer's Chat app; the right computer pullout (DevicePanel) is untouched.

- backend: cm-api/routes/world.rs emits per-agent `telemetry{agentId,tokensPerMin,
  costPerHr,loops,doorsPending}` in the SSE loop, from 4 batched GROUP BY queries
  (usage_events tokens/min + credits/hr, active routines, pending approvals) — all
  real, no migration. taxonomy `telemetry` gains optional agentId; stateKey now
  keys it per-agent so slices don't clobber.
- frontend: new ClawCommandCenter + anatomy-cards (shared cards extracted from
  Dashboard); useAgentTelemetry(agentId) feeds the metric band (Doors amber>0/
  green=0); LIVE column streams the agent's task.update / reasoning.delta /
  tool.call (replaces the mocked VitalsCard heatmap with a live activity chart).
- Dashboard: left region → full-height ClawCommandCenter; chat launcher opens the
  computer Chat app; removed the dead anatomy cluster + unused imports.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
Omar Sobh
2026-06-26 11:34:12 -07:00
co-authored by Claude Opus 4.8
parent 731adb6449
commit 11a1f22daa
9 changed files with 2883 additions and 261 deletions
+8 -3
View File
@@ -43,8 +43,9 @@ export interface TaxonomyEvents {
nodes?: { id: string; tier: NodeTier; label?: string; parentId?: string }[];
edges?: { from: string; to: string; kind?: "parent" | "peer" | "flow" }[];
};
/** Top-bar pills + Observe System telemetry strip. */
telemetry: { tokensPerMin?: number; costPerHr?: number; loops?: number; doorsPending?: number };
/** Top-bar pills + Observe System telemetry strip. With `agentId` it's the
* per-agent slice for the command-center metric band; without, workspace-wide. */
telemetry: { agentId?: string; tokensPerMin?: number; costPerHr?: number; loops?: number; doorsPending?: number };
/** Observe System → ROUTINES & LOOPS; the scheduler view. */
"routine.update": {
routineId: string;
@@ -97,5 +98,9 @@ export function stateKey<T extends TaxonomyType>(type: T, d: TaxonomyPayload<T>)
return `${type}:${(d as TaxonomyEvents["agent.status"]).agentId}`;
if (type === "node.activity") return `${type}:${(d as TaxonomyEvents["node.activity"]).nodeId}`;
if (type === "routine.update") return `${type}:${(d as TaxonomyEvents["routine.update"]).routineId}`;
return type; // telemetry, topology.update
if (type === "telemetry") {
const a = (d as TaxonomyEvents["telemetry"]).agentId;
return a ? `telemetry:${a}` : "telemetry"; // per-agent slice vs workspace-wide
}
return type; // topology.update
}
+15
View File
@@ -186,6 +186,21 @@ export function useLiveState<T extends TaxonomyType, S>(
return state;
}
/** The per-agent telemetry slice for the command-center metric band. Re-subscribes
* when the agent changes so the replayed last-known value paints immediately. */
export function useAgentTelemetry(agentId: string | null): TaxonomyPayload<"telemetry"> | null {
const client = useClawmatesLive();
const [t, setT] = useState<TaxonomyPayload<"telemetry"> | null>(null);
useEffect(() => {
setT(null);
if (!agentId) return;
return client.on("telemetry", (d) => {
if (d.agentId === agentId) setT(d);
});
}, [client, agentId]);
return t;
}
// --- synthetic generator (no backend) — ports the demo loop so the World/Observe
// views breathe even with nothing wired. Stops the moment a real feed connects. --
type Emit = <T extends TaxonomyType>(type: T, data: TaxonomyPayload<T>) => void;