Agents page: reorganize into the Agent Command Center (per-agent live metrics)
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:
co-authored by
Claude Opus 4.8
parent
731adb6449
commit
11a1f22daa
@@ -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
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user