feat(protocol): deliver 'War Room' UI with Incursion Engine
We've transformed the Social-Dense Hub into a high-fidelity operational surface. - BACKEND: Implemented Global Incursion Engine in agent-sessions.ts (N^2 overlap detection) and added the 60m 'Idle' state. - API: Enriched the sessions payload with full metadata and active conflict arrays. - HEADER: Delivered 4-state agent stations (Active/Stale/Evicted/Idle) with real-time 'time-ago' timers. - FEED: Implemented the 'Fire Map' visuals: * Global Incursion Ticker: High-visibility alerts for agent collisions. * Local Conflict Badges: Pulsing pills on affected task cards. - Refactored components for React-static compliance and strict TypeScript safety. This commit completes the visibility track, allowing the human supervisor to monitor agent presence and friction in real-time. OPERATIVE: silver-castle SESSION: 2026-02-14-1430
This commit is contained in:
parent
e010e0b10b
commit
eec1d6e28f
10 changed files with 224 additions and 41 deletions
|
|
@ -2,8 +2,9 @@ import type { ActivityEvent } from './activity';
|
|||
import type { BeadIssue } from './types';
|
||||
import { listAgents, deriveLiveness } from './agent-registry';
|
||||
import { inboxAgentMessages, type AgentMessage } from './agent-mail';
|
||||
import { statusAgentReservations, classifyOverlap } from './agent-reservations';
|
||||
|
||||
export type AgentSessionState = 'active' | 'reviewing' | 'deciding' | 'needs_input' | 'completed' | 'stale' | 'evicted';
|
||||
export type AgentSessionState = 'active' | 'reviewing' | 'deciding' | 'needs_input' | 'completed' | 'stale' | 'evicted' | 'idle';
|
||||
|
||||
export interface SessionTaskCard {
|
||||
id: string;
|
||||
|
|
@ -50,6 +51,49 @@ export async function getAgentLivenessMap(): Promise<Record<string, string>> {
|
|||
return map;
|
||||
}
|
||||
|
||||
export interface Incursion {
|
||||
scope: string;
|
||||
agents: string[];
|
||||
severity: 'exact' | 'partial';
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates global incursions by comparing all active reservations.
|
||||
*/
|
||||
export async function calculateIncursions(): Promise<Incursion[]> {
|
||||
const statusResult = await statusAgentReservations({});
|
||||
if (!statusResult.ok || !statusResult.data) return [];
|
||||
|
||||
const reservations = statusResult.data.reservations;
|
||||
const incursions: Incursion[] = [];
|
||||
const processedPairs = new Set<string>();
|
||||
|
||||
for (let i = 0; i < reservations.length; i++) {
|
||||
for (let j = i + 1; j < reservations.length; j++) {
|
||||
const resA = reservations[i];
|
||||
const resB = reservations[j];
|
||||
|
||||
// Don't compare an agent against themselves
|
||||
if (resA.agent_id === resB.agent_id) continue;
|
||||
|
||||
const overlap = classifyOverlap(resA.scope, resB.scope);
|
||||
if (overlap !== 'disjoint') {
|
||||
const key = [resA.agent_id, resB.agent_id].sort().join(':') + ':' + [resA.scope, resB.scope].sort().join('|');
|
||||
if (processedPairs.has(key)) continue;
|
||||
processedPairs.add(key);
|
||||
|
||||
incursions.push({
|
||||
scope: overlap === 'exact' ? resA.scope : `${resA.scope} ↔ ${resB.scope}`,
|
||||
agents: [resA.agent_id, resB.agent_id],
|
||||
severity: overlap
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return incursions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gathers all relevant communication for all agents to build a summary for aggregation.
|
||||
*/
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue