ADR-0007: Canvas UI and live run streaming¶
- Status: Accepted
- Date: 2026-06-05
- Deciders: AOP core
Context¶
Phase 4 delivers the visual canvas: a node-based UI to build, connect, run, and inspect agents and their data flows, with live agent state. It builds on the Phase 3 orchestrator + FastAPI.
Decisions¶
1. React Flow (@xyflow/react) + zustand¶
The canvas uses @xyflow/react (v12) with custom node types — AgentNode,
ToolNode, CollectionNode — and a zustand store holding nodes, edges,
selection, and per-node run state. The store is the single source of truth; the
inspector and nodes read from it reactively.
2. Live state via a Redis Streams event bus¶
A run is started with POST /runs (returns a run_id); the agent executes in a
background task that publishes lifecycle/step events to a per-run Redis Stream
(run:<id>). Clients open WS /ws/runs/{run_id} and tail the stream.
Why Streams, not raw pub/sub: raw pub/sub drops messages published before a
subscriber connects — the canvas would miss the early steps between POST /runs
and the WebSocket opening. Streams replay from offset 0, so a late subscriber
still receives every event. This satisfies the "FastAPI + Redis pub/sub" intent
with correct delivery, and lets multiple canvases watch the same run.
3. Per-step callback bridges agents → bus¶
The Phase-3 Agent.on_step callback is the seam: the run task wires on_step to
bus.publish(...). Agents stay transport-agnostic.
4. CORS for the browser¶
The API enables CORS for the Next.js dev origin (AOP_API_CORS_ORIGINS) so the
canvas can call the REST/WS endpoints cross-origin.
5. Portable canvas graphs¶
The canvas exports to / imports from a versioned JSON graph (exportGraph /
importGraph); run state is stripped on export so graphs are reproducible.
Consequences¶
- Positive: real-time, multi-viewer agent visualisation with no missed events; agents remain decoupled from the transport; graphs are portable.
- Verification: the frontend is verified by
pnpm lint+tsc --noEmit+next build(production build must pass) and a live integration check (server boots, serves the canvas HTML, and CORS permits the backend calls). No browser automation (Playwright) was added — a deliberate scope choice. - Caveats / future:
- Edges currently express data flow visually; wiring a connected collection's name into an agent's tool calls (so the graph drives tool parameters) is a follow-up.
- The background run-task registry is in-process; horizontal scaling would move run ownership fully into Redis.
- A "memory snapshot" inspector tab is deferred (no REST endpoint yet).