Skip to content

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).