Definition

A visual agent system designer is a user interface that lets users define an agentic workflow as a graph of nodes, edges, parameters, tools, conditions, and state mappings.

The visual designer is not the agent runtime.

It produces an intermediate graph schema. A backend compiler turns that schema into executable orchestration on top of an engine such as LangGraph (1.2.10), XState (1.2.9), Temporal, or a custom runtime.

Examples: Flowise, LangFlow, n8n, Dify, Coze, Vellum, Wordware, Vertex AI Agent Builder, AWS Bedrock Agent Builder, Microsoft Copilot Studio.


Core Architecture

visual editor
→ canonical graph schema (JSON)
→ schema validation
→ compiler
→ execution engine (LangGraph / XState / Temporal)
→ runtime traces
→ visual replay

The product is the graph schema, not the canvas.


Visual Editor

The visual editor renders nodes and edges. Common libraries:

  1. React Flow — typed nodes, custom edges, React-native
  2. Rete.js — TypeScript-first, framework-agnostic (React, Angular, Vue)
  3. JointJS — diagramming and BPMN-style workflows
  4. LogicFlow — workflow-oriented Chinese-stack alternative

Pick by frontend stack: React Flow for React, Rete.js for Angular or framework-neutral builds.

The editor is replaceable. The graph schema is not.


Graph Schema

The canonical schema is the stable internal representation of a workflow. It must be independent of the UI library — never persist React Flow or Rete objects as the production contract.

type AgentGraph = {
  id: string;
  version: number;
  nodes: AgentNode[];
  edges: AgentEdge[];
  stateSchema: StateField[];
};

type AgentNode = {
  id: string;
  type: 'llm' | 'tool' | 'router' | 'approval' | 'retrieval' | 'end';
  label: string;
  config: Record<string, unknown>;
};

type AgentEdge = {
  id: string;
  source: string;
  target: string;
  condition?: ConditionSpec;
};

A persisted instance:

{
  "id": "refund-agent",
  "version": 3,
  "nodes": [
    { "id": "classify", "type": "llm-router",
      "config": { "model": "gemini-2.5-pro", "outputSchema": "RefundRouteDecision" } },
    { "id": "approval", "type": "human-approval",
      "config": { "role": "manager" } }
  ],
  "edges": [
    { "source": "classify", "target": "approval",
      "condition": { "field": "risk", "operator": "eq", "value": "high" } }
  ]
}

Compiler Layer

The compiler transforms the graph schema into executable runtime code. There are two common targets.

Target: LangGraph

LangGraph is graph-shaped natively, so the mapping is direct.

Visual concept LangGraph concept
Node Node function
Edge Edge
Conditional edge Conditional edge
Shared memory State
Start START
End END
Tool node Tool node
Human approval Interrupt / pause
function compileToLangGraph(spec: AgentGraph) {
  const graph = new StateGraph(State);
  for (const node of spec.nodes) {
    graph.addNode(node.id, nodeFactory(node));
  }
  for (const edge of spec.edges) {
    if (edge.condition) {
      graph.addConditionalEdges(edge.source, conditionFactory(edge.condition));
    } else {
      graph.addEdge(edge.source, edge.target);
    }
  }
  return graph.compile();
}

Use LangGraph as the target for agent loops, tool routing, retrieval, HIL pauses, and shared state workflows.


Target: XState

XState fits when the visual workflow has explicit states, events, and transitions — approval flows, deterministic business processes, UI ↔ backend coordination.

Visual concept XState concept
Node State
Edge Transition
Event label Event
Condition Guard
Side effect Action
Async node Invoked actor
Nested group Compound state
Parallel lanes Parallel states
function compileToXState(spec: AgentGraph) {
  return createMachine({
    id: spec.id,
    initial: findStartState(spec),
    context: buildInitialContext(spec),
    states: buildStates(spec)
  });
}

Graph in Canvas vs Graph in Code

Two authoring modes share the same execution engine.

graph in code:    developer writes executable graph directly
graph in canvas:  user edits schema; compiler emits executable graph

The canvas does not execute business logic. The canvas produces a versioned specification. The backend executes the compiled specification.


Node Registry

A node registry catalogs the allowed node types and their schemas. This is the key system boundary — users may drag any box; only registered boxes can execute.

const nodeRegistry = {
  'llm-router': {
    configSchema:        LlmRouterConfigSchema,
    compileToLangGraph:  compileLlmRouter,
    compileToXState:     compileLlmRouterState
  },
  'human-approval': {
    configSchema:        ApprovalConfigSchema,
    compileToLangGraph:  compileApprovalNode,
    compileToXState:     compileApprovalState
  }
};

Per node type, the registry must declare:

  1. display name
  2. input and output handles
  3. config schema (Zod or JSON Schema)
  4. validation rules
  5. runtime compiler(s)
  6. permission requirements

Validation Layer

Validation runs before save, publish, and execution.

Required checks:

  1. exactly one start node
  2. at least one terminal node
  3. no orphan nodes
  4. no illegal cycles
  5. all required configs present
  6. edge conditions valid against state schema
  7. tool permissions respected
  8. model output schemas match downstream node inputs
  9. approval required for sensitive tools

For TypeScript builders, Zod is the most direct schema implementation.


Execution Boundary

The execution boundary separates design-time configuration from runtime authority.

Design-time users may define:

  1. prompts
  2. tools
  3. routing conditions
  4. approval steps
  5. retrieval sources

Runtime still enforces:

  1. permissions
  2. secrets access
  3. rate limits
  4. tool allowlists
  5. tenant isolation
  6. approval requirements
  7. audit logging

A visual graph must never become a privilege-escalation surface. For the broader runtime concerns — durability, idempotency, tool authority, approval gates — see 1.1.1 State machines in agentic systems.


Runtime Persistence

Graph definition and graph execution instance must be persisted separately.

{ "graphId": "refund-agent", "version": 3 }
{
  "runId":        "run_123",
  "graphId":      "refund-agent",
  "graphVersion": 3,
  "currentNode":  "approval",
  "state":        {},
  "status":       "paused"
}

Definitions are versioned and immutable once published. Runs reference a specific definition version so a redesign mid-flight does not corrupt in-flight executions.


Visual Replay

Visual replay renders runtime traces back onto the canvas.

Required trace events:

  1. node started
  2. node completed
  3. edge selected
  4. LLM output received
  5. tool called
  6. tool failed
  7. approval requested / granted
  8. run completed / failed
{
  "runId":  "run_123",
  "event":  "edge_selected",
  "source": "classify",
  "target": "approval",
  "reason": "risk=high"
}

Without replay, visual builders are nearly impossible to debug.


Production Rule

The visual editor must not generate arbitrary executable code.

It must generate validated, declarative graph JSON. The backend compiles that JSON into a bounded runtime.

Good:

canvas → JSON spec → compiler → runtime

Bad:

canvas → user-generated JavaScript → eval

Final Pipeline

user drags boxes
→ editor updates canonical graph JSON
→ validator checks the graph
→ graph is versioned and published
→ backend compiles the graph
→ LangGraph or XState executes the graph
→ runtime persists state
→ traces stream back to canvas
→ user sees execution path on the same diagram

Core Rule

A visual agent builder is not a replacement for LangGraph or XState. It is an authoring layer above them.

The design problem is not drawing boxes. The design problem is compiling boxes into safe, typed, versioned, executable orchestration.


Cross-references

  • 1.2.10 LangGraph — graph-over-state runtime; primary compiler target for agent-loop workflows.
  • 1.2.9 XState — statechart runtime; primary compiler target for deterministic workflows.
  • 1.1.1 State machines in agentic systems — runtime concerns shared by both targets: durability, idempotency, tool authority, approval gates.

References

  1. React Flow — reactflow.dev
  2. Rete.js — retejs.org
  3. LangGraph Graph API (JS) — docs.langchain.com/oss/javascript/langgraph/graph-api
  4. XState Actors — stately.ai/docs/actors
  5. XState Persistence — stately.ai/docs/persistence