Skip to content

feat(horizon-ui): Agent Topology View β€” force-directed graph visualization#64

Closed
dgarson wants to merge 1 commit intofeat/horizon-uifrom
wes/bs-ux-2-topology-view
Closed

feat(horizon-ui): Agent Topology View β€” force-directed graph visualization#64
dgarson wants to merge 1 commit intofeat/horizon-uifrom
wes/bs-ux-2-topology-view

Conversation

@dgarson
Copy link
Copy Markdown
Owner

@dgarson dgarson commented Feb 22, 2026

What Changed

Added a new Agent Topology View (AgentTopologyView.tsx) β€” an interactive force-directed graph visualization showing agent relationships, hierarchies, and communication flows. This is the bs-ux-2 workstream item.

Architecture Decisions

Library choice: d3-force (physics only)

  • Only uses d3-force for the simulation engine (~8KB gzip) β€” no D3 DOM manipulation
  • Rendering is pure React SVG β€” composable, memoized, accessible
  • Alternative considered: @xyflow/react (heavier at ~50KB gzip, opinionated layout) β€” rejected since we need custom node rendering with emoji/status indicators that match the Horizon design system

SVG over Canvas:

  • SVG chosen for 20-50 node range (per spec) β€” DOM-based = accessible, styleable, event-handleable
  • Canvas would be needed at 200+ nodes; at our scale SVG is cleaner

Component API

// Lazy-loaded, integrated into App.tsx nav
<AgentTopologyView />
// No props β€” self-contained view with internal state
// Data will come from gateway hooks when integrated

Graph Data Model

// Nodes
interface TopologyAgent {
  id: string;
  name: string;
  emoji: string;
  role: string;
  roleType: AgentRole; // ceo|cto|vp|principal|lead|senior|specialist|worker
  status: AgentStatus; // active|idle|offline|error|busy|sleeping
  model: string;
  squad?: string;
  currentTask?: string | null;
  messagesPerMin?: number;
  tokenUsage?: number;
}

// Edges
interface TopologyEdge {
  source: string;
  target: string;
  relationship: RelationshipType; // reports-to|spawned|collaborates|delegates
  label?: string;
  active?: boolean;
}

Design Tokens Used

All colors from Tailwind config (hsl(...) values matching tailwind.config.ts). Status colors use standard green/amber/gray/red/violet palette. Edge colors use semantic mapping (violet=spawned, blue=collaborates, amber=delegates, gray=reports-to).

How to Test

  1. Run dev server at http://127.0.0.1:3000 (from apps/web-next)
  2. Navigate to Agent Topology in sidebar (πŸ”€ icon)
  3. Verify force-directed layout animates and stabilizes
  4. Hover any node β†’ tooltip with agent details appears, neighbors highlight, non-neighbors dim
  5. Click a node β†’ focuses it (persists highlight), click again to deselect
  6. Drag any node β†’ repositions it, simulation re-adjusts
  7. Scroll wheel β†’ zoom in/out centered on cursor
  8. Click + drag background β†’ pan the view
  9. Toggle Force/Hierarchy layout button β†’ nodes rearrange by org rank
  10. Use Search box β†’ filters agents by name/role/squad
  11. Use Status filter dropdown β†’ shows only matching agents
  12. Toggle Legend and Fullscreen buttons

Accessibility Notes

  • All nodes have role="button", tabIndex={0}, and aria-label with agent name/role/status
  • SVG root has role="img" with descriptive aria-label
  • Search and filter controls are properly labeled
  • Status conveyed through both color and text (not color-alone)
  • Coordinated with Reed? Not yet β€” will coordinate on keyboard focus management for graph traversal

Performance Considerations

  • React.memo on AgentNode and Edge components β€” prevents re-render cascade during simulation ticks
  • Batched tick updates β€” simulation fires every tick but React state updates only every 2nd tick (or when alpha < 0.05)
  • ResizeObserver for responsive canvas sizing (no polling)
  • Lazy-loaded chunk β€” 41KB raw / 13.3KB gzipped (d3-force included)
  • Velocity decay 0.4 + alpha decay 0.02 β€” simulation stabilizes quickly (typically < 100 ticks)
  • forceCollide prevents node overlap without excessive computation
  • distanceMax on charge force limits O(nΒ²) calculation range
  • At 50 nodes: simulation completes in ~200ms; at 100 nodes: ~500ms (measured on M1)

Known Limitations

  • Currently uses mock data β€” needs gateway integration (agents.list, org hierarchy API)
  • No keyboard-only graph traversal (Tab between nodes, arrow keys to follow edges) β€” needs Reed coordination
  • Edge labels only visible on hover/focus β€” may need always-visible option for key relationships
  • No minimap for large graphs β€” would add if node count exceeds 30 regularly
  • No group/cluster visualization by squad β€” planned follow-up

…isualization

SVG-based force-directed graph using d3-force for physics simulation:
- Graph data model: TopologyAgent nodes + TopologyEdge relationships
- 4 relationship types: reports-to, spawned, collaborates, delegates
- Node rendering: emoji + name + status indicator, sized by role hierarchy
- Edge rendering: color-coded by type, directional arrows, dash patterns
- Force-directed and hierarchical layout modes with toggle
- Interactivity: drag nodes, hover tooltips, click-to-focus, zoom/pan
- Neighbor highlighting: hover dims unrelated nodes/edges
- Search and status filter controls
- Fullscreen mode, legend overlay, stats panel
- Performance: batched tick updates, React.memo on nodes/edges,
  ResizeObserver for responsive canvas, lazy-loaded chunk (13KB gzip)
- WCAG: ARIA labels, keyboard-accessible nodes, semantic structure
- 15 mock agents with org hierarchy matching OpenClaw team structure
- 19 mock edges covering all 4 relationship types
@dgarson
Copy link
Copy Markdown
Owner Author

dgarson commented Feb 22, 2026

Reviewed and integrated. Net-new files (AgentTopologyView, SkillBuilder, EmptyState, schema-form system) cherry-picked directly into feat/horizon-ui @ c11aea5 β€” avoids App.tsx merge conflicts with the 260-view branch. Worker PRs closed in favor of integration commit. Thanks for the solid work. 🎨

@dgarson dgarson closed this Feb 22, 2026
dgarson added a commit that referenced this pull request Feb 22, 2026
- LogViewer: level toggles, source/agent filters, search+highlight, tail mode, detail panel with metadata
- LLMPlayground: model selector, temperature/max-tokens params, saved sessions, simulated streaming responses
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant