Agent Import and DSL Compatibility#
Overview#
The agent canvas uses a single canonical DSL wire format for all operations (create, save, export, import). All DSL transformation logic lives in dsl-bridge.ts, which exposes four public functions: initialEmptyDsl, importDsl, dslToGraph, and graphToDsl. The frontend rebuilds components from graph on every save; the backend reads components only and ignores graph .
DSL Wire Shape#
The canonical DSL shape :
{
"globals": {...},
"graph": { "nodes": [...], "edges": [...] },
"variables": {...},
"components": { "<Name>:<UUID>": { "downstream": [...], "upstream": [...], "obj": {...} } },
"path": [...], "retrieval": {...}, "history": [...]
}
graphis the React-Flow layout surface (positions, handles) — the single source of truth for import/export.componentsis the execution topology consumed by the backend engine.
importDsl — Strict-Graph Contract#
importDsl(rawParsed, isAgent) accepts a parsed JSON object and returns a renderable DSL. Only payloads with raw.graph.nodes (non-empty array) are rendered as-is. All other inputs fall through to the empty seed:
| Input payload | Result |
|---|---|
{ graph: { nodes: [...], edges: [...] } } | Rendered from graph |
{ components: {...} } (no graph) | → Empty seed |
{ _layout: {...} } (legacy v1 export) | → Empty seed |
{} (empty file) | → Empty seed |
Tests for all four cases are in .
When graph.nodes is present but components is absent, importDsl reconstructs topology via buildDslComponentsByGraph . This was the bug fixed in PR #13992: imported DSLs were not correctly rebuilding their components from the graph structure.
Backward Compatibility#
_layout field (legacy v1 exports)#
Earlier v1 export files carried canvas positions in a _layout field. The _layout field is intentionally not consumed — it was a one-shot import-time hint and is no longer part of the wire contract since the v1/v2 split was removed . A payload with only _layout renders as an empty canvas .
Iteration node type migration ('group' → 'iterationNode')#
Old agent exports used type: 'group' for Iteration nodes. normalizeGraphNodes automatically rewrites these to type: 'iterationNode' during both importDsl and dslToGraph, so legacy canvases render correctly without manual migration. Test coverage is at .
Canvas type detection#
inferIsAgentFromImport detects whether an imported JSON is a dataflow or agent canvas by checking whether graph.nodes includes both File and Parser operators. It defaults to agent when ambiguous or when no graph block is present.
Placeholder Node Edge Rendering (PR #10485)#
Connection lines to placeholder nodes were not displaying correctly because rendering depended on a global highlightedPlaceholderEdgeId store state that wasn't properly managed. PR #10485 replaced the global state with an on-the-fly computation (isTargetPlaceholder = getOperatorTypeFromId(target) === Operator.Placeholder), removing the highlightedPlaceholderEdgeId state and its setters entirely. graphToDsl also filters out placeholder nodes and their edges before serializing .
Go/Python Runtime Parity (PR #16225)#
PR #16225 aligned the Go agent runtime with Python behavior across components, tools, and the canvas engine. Key DSL-related changes:
- DSL normalization (
internal/agent/dsl/normalize.go): v1↔v2 collapsed into a single wire format so both runtimes consume the same stored JSON . - Switch component: Added multi-target routing, legacy
clauses→itemsparameter normalization, and default fallback logic . - Canvas state reset (
internal/agent/dsl/reset.go): Per-run state reset matches Python'sCanvas.reset()semantics .
The retrieval component alignment was intentionally deferred to a follow-up PR .
Key Source Files#
| File | Purpose |
|---|---|
web/src/pages/agent/utils/dsl-bridge.ts | All DSL transform functions: importDsl, dslToGraph, graphToDsl, exportDsl, inferIsAgentFromImport |
web/src/pages/agent/utils/tests/dsl-bridge.test.ts | Contract tests for strict-graph import, legacy format migration, round-trip |
web/src/pages/agent/utils.ts | buildDslComponentsByGraph — reconstructs component topology from graph edges |