Skip to main content

Overview

The GraphSpec class defines the complete structure of an agent graph, including nodes, edges, entry/terminal points, and execution configuration.

Class: GraphSpec

from framework.graph import GraphSpec, NodeSpec, EdgeSpec, EdgeCondition

graph = GraphSpec(
    id="calculator-graph",
    goal_id="calc-001",
    entry_node="input_parser",
    terminal_nodes=["output_formatter"],
    nodes=[...],
    edges=[...]
)

Required Fields

id
str
required
Unique identifier for the graph
goal_id
str
required
ID of the goal this graph achieves
entry_node
str
required
ID of the first node to execute
nodes
list[NodeSpec]
default:"[]"
All node specifications
edges
list[EdgeSpec]
default:"[]"
All edge specifications

Optional Fields

terminal_nodes
list[str]
default:"[]"
IDs of nodes that end execution
pause_nodes
list[str]
default:"[]"
IDs of nodes that pause for human input
entry_points
dict[str, str]
default:"{}"
Named entry points for resuming. Format: {name: node_id}
async_entry_points
list[AsyncEntryPointSpec]
default:"[]"
Asynchronous entry points for concurrent execution streams
memory_keys
list[str]
default:"[]"
Keys available in shared memory
default_model
str
default:"'claude-haiku-4-5-20251001'"
Default LLM model for nodes
max_tokens
int
default:"8192"
Maximum tokens for LLM responses
max_steps
int
default:"100"
Maximum node executions before timeout
max_retries_per_node
int
default:"3"
Maximum retries per node on failure
conversation_mode
str
default:"'continuous'"
Conversation flow mode: “continuous” or “isolated”
identity_prompt
str | None
default:"None"
Agent-level identity prompt (Layer 1 of onion model)
version
str
default:"'1.0.0'"
Graph version
description
str
default:"''"
Human-readable description
created_by
str
default:"''"
Creator: “human” or “builder_agent”

Methods

get_node()

Get a node by ID.
node = graph.get_node("calculator")
if node:
    print(node.name)
node_id
str
required
The node ID to retrieve
node
NodeSpec | None
The node specification, or None if not found

get_outgoing_edges()

Get all edges leaving a node, sorted by priority.
edges = graph.get_outgoing_edges("calculator")
for edge in edges:
    print(f"{edge.target} ({edge.condition})")
node_id
str
required
The source node ID
edges
list[EdgeSpec]
List of outgoing edges, sorted by priority (highest first)

get_incoming_edges()

Get all edges entering a node.
edges = graph.get_incoming_edges("formatter")
for edge in edges:
    print(f"{edge.source} -> {edge.target}")
node_id
str
required
The target node ID
edges
list[EdgeSpec]
List of incoming edges

validate()

Validate the graph structure.
errors = graph.validate()
if errors:
    for error in errors:
        print(f"Error: {error}")
else:
    print("✓ Graph is valid")
errors
list[str]
List of validation error messages (empty if valid)

detect_fan_out_nodes()

Detect nodes that fan out to multiple targets.
fan_outs = graph.detect_fan_out_nodes()
for source, targets in fan_outs.items():
    print(f"{source} -> {targets}")
fan_outs
dict[str, list[str]]
Mapping of source_node_id to list of parallel target_node_ids

detect_fan_in_nodes()

Detect nodes that receive from multiple sources.
fan_ins = graph.detect_fan_in_nodes()
for target, sources in fan_ins.items():
    print(f"{sources} -> {target}")
fan_ins
dict[str, list[str]]
Mapping of target_node_id to list of source_node_ids

get_entry_point()

Get the appropriate entry point based on session state.
entry_node = graph.get_entry_point(session_state)
print(f"Starting at: {entry_node}")
session_state
dict | None
default:"None"
Optional session state with ‘paused_at’ or ‘resume_from’ key
entry_node
str
Node ID to start execution from

Async Entry Points

For multi-entry-point agents that handle concurrent execution streams:

Class: AsyncEntryPointSpec

from framework.graph.edge import AsyncEntryPointSpec

entry = AsyncEntryPointSpec(
    id="webhook",
    name="Zendesk Webhook Handler",
    entry_node="process-webhook",
    trigger_type="webhook",
    isolation_level="shared",
    max_concurrent=10
)
id
str
required
Unique identifier for this entry point
name
str
required
Human-readable name
entry_node
str
required
Node ID to start execution from
trigger_type
str
default:"'manual'"
How this entry point is triggered: webhook, api, timer, event, manual
trigger_config
dict[str, Any]
default:"{}"
Trigger-specific configuration (e.g., webhook URL, timer interval)
isolation_level
str
default:"'shared'"
State isolation: isolated, shared, or synchronized
priority
int
default:"0"
Execution priority (higher = more priority)
max_concurrent
int
default:"10"
Maximum concurrent executions for this entry point
max_resurrections
int
default:"3"
Auto-restart on non-fatal failure (0 to disable)

Example: Single Entry Point

from framework.graph import GraphSpec, NodeSpec, EdgeSpec, EdgeCondition

graph = GraphSpec(
    id="calculator-graph",
    goal_id="calc-001",
    entry_node="input_parser",
    terminal_nodes=["output_formatter", "error_handler"],
    nodes=[
        NodeSpec(
            id="input_parser",
            name="Input Parser",
            description="Parse user input",
            node_type="event_loop",
            input_keys=["expression"],
            output_keys=["parsed_expr"],
        ),
        NodeSpec(
            id="calculator",
            name="Calculator",
            description="Perform calculation",
            node_type="event_loop",
            input_keys=["parsed_expr"],
            output_keys=["result"],
        ),
        NodeSpec(
            id="output_formatter",
            name="Output Formatter",
            description="Format the result",
            node_type="event_loop",
            input_keys=["result"],
            output_keys=["formatted_result"],
        ),
    ],
    edges=[
        EdgeSpec(
            id="parse-to-calc",
            source="input_parser",
            target="calculator",
            condition=EdgeCondition.ON_SUCCESS,
        ),
        EdgeSpec(
            id="calc-to-format",
            source="calculator",
            target="output_formatter",
            condition=EdgeCondition.ON_SUCCESS,
        ),
    ],
    memory_keys=["expression", "parsed_expr", "result", "formatted_result"],
    max_steps=50,
)

# Validate
errors = graph.validate()
if not errors:
    print("✓ Graph is valid")

Example: Multi-Entry Point Agent

from framework.graph.edge import AsyncEntryPointSpec

graph = GraphSpec(
    id="support-agent-graph",
    goal_id="support-001",
    entry_node="process-webhook",  # Default entry
    async_entry_points=[
        AsyncEntryPointSpec(
            id="webhook",
            name="Zendesk Webhook",
            entry_node="process-webhook",
            trigger_type="webhook",
            isolation_level="shared",
            max_concurrent=20,
        ),
        AsyncEntryPointSpec(
            id="api",
            name="API Handler",
            entry_node="process-request",
            trigger_type="api",
            isolation_level="isolated",
            max_concurrent=10,
        ),
    ],
    nodes=[...],
    edges=[...],
)

Build docs developers (and LLMs) love