Overview

Edges define the connections between nodes in your agent graph. They control how the conversation flows from one node to another based on conditions.

Complete example

from kapso.builder import Agent
from kapso.builder.nodes import DefaultNode, SubagentNode, WarmEndNode
from kapso.builder.agent.constants import START_NODE, END_NODE

agent = Agent(name="customer_service")

# Add nodes
agent.add_node(START_NODE)
agent.add_node(END_NODE)

triage = DefaultNode(name="triage", prompt="Understand what the user needs")
orders = SubagentNode(name="orders", prompt="Handle order inquiries")
support = SubagentNode(name="support", prompt="Provide technical support")
goodbye = WarmEndNode(name="goodbye", timeout_minutes=5)

agent.add_node(triage)
agent.add_node(orders)
agent.add_node(support)
agent.add_node(goodbye)

# Create edge flow with conditions
agent.add_edge(START_NODE, "triage")

# From triage to specialized handlers
agent.add_edge("triage", "orders", 
    condition="user asks about orders, shipping, or tracking")
agent.add_edge("triage", "support", 
    condition="user has technical issues or needs help")
agent.add_edge("triage", "goodbye", 
    condition="user just saying hi or bye")

# From handlers to end
agent.add_edge("orders", "goodbye", 
    condition="order inquiry resolved")
agent.add_edge("support", "goodbye", 
    condition="support issue resolved")

# Final edge
agent.add_edge("goodbye", END_NODE)

# Validate the complete flow
agent.validate()

Creating edges

Basic syntax

agent.add_edge(source, target, condition=None)

Parameters:

  • source (str): Name of the source node or START_NODE
  • target (str): Name of the target node or END_NODE
  • condition (str, optional): Natural language condition for when to follow this edge

Simple edge

Connect two nodes without conditions:

from kapso.builder.agent.constants import START_NODE, END_NODE

# Connect START to greeting node
agent.add_edge(START_NODE, "greeting")

# Connect greeting to END
agent.add_edge("greeting", END_NODE)

Conditional edges

Add conditions to control flow based on conversation context:

# Multiple paths from one node
agent.add_edge("greeting", "order_status", 
    condition="user asks about their order or shipment")

agent.add_edge("greeting", "product_info", 
    condition="user asks about products or pricing")

agent.add_edge("greeting", "support", 
    condition="user has a problem or complaint")

# Default path (no condition)
agent.add_edge("greeting", "general_help")

Edge class

The Edge class represents connections between nodes:

from kapso.builder import Edge, create_edge

# Using the Edge class directly
edge = Edge(
    source="node1",
    target="node2",
    condition="user confirms"
)

# Using the factory function
edge = create_edge(
    source="node1",
    target="node2",
    condition="user confirms"
)

Flow control rules

START_NODE rules

  • Must have exactly one outgoing edge
  • Cannot have incoming edges
  • Cannot have conditions on its outgoing edge
# ✅ Correct
agent.add_edge(START_NODE, "first_node")

# ❌ Wrong - Multiple edges from START
agent.add_edge(START_NODE, "node1")
agent.add_edge(START_NODE, "node2")  # Error!

# ❌ Wrong - Condition on START edge
agent.add_edge(START_NODE, "node1", condition="some condition")  # Error!

END_NODE rules

  • Can have multiple incoming edges
  • Cannot have outgoing edges
# ✅ Correct - Multiple paths to END
agent.add_edge("success", END_NODE)
agent.add_edge("failure", END_NODE)
agent.add_edge("cancelled", END_NODE)

Global node rules

  • Global nodes don’t need explicit edges
  • They’re accessible from any node when their condition is met
  • Flow returns to the calling node after global node execution
# Global node - no edges needed
handoff = HandoffNode(
    name="human",
    global_=True,
    global_condition="user requests human"
)
agent.add_node(handoff)
# No add_edge() calls needed!

Condition best practices

Write natural language conditions

# ✅ Good - Natural, clear conditions
agent.add_edge("menu", "orders", 
    condition="user selects option 1 or asks about orders")

# ❌ Avoid - Technical or code-like conditions
agent.add_edge("menu", "orders", 
    condition="input == '1' || contains(message, 'order')")

Make conditions mutually exclusive

# ✅ Good - Clear, non-overlapping conditions
agent.add_edge("triage", "billing", 
    condition="user has billing or payment questions")

agent.add_edge("triage", "technical", 
    condition="user has technical issues or error messages")

agent.add_edge("triage", "general", 
    condition="user has general questions or other inquiries")

Provide a default path

# Specific conditions first
agent.add_edge("router", "urgent", 
    condition="user mentions emergency or urgent")

agent.add_edge("router", "appointment", 
    condition="user wants to schedule or reschedule")

# Default catch-all (no condition)
agent.add_edge("router", "general_inquiry")

Common edge patterns

Linear flow

# Simple A → B → C flow
agent.add_edge("collect_info", "process_request")
agent.add_edge("process_request", "show_results")
agent.add_edge("show_results", "end")

Branching

# User choice determines path
agent.add_edge("menu", "option_a", condition="user chooses A")
agent.add_edge("menu", "option_b", condition="user chooses B")
agent.add_edge("menu", "option_c", condition="user chooses C")

# All paths converge
agent.add_edge("option_a", "confirmation")
agent.add_edge("option_b", "confirmation")
agent.add_edge("option_c", "confirmation")

Loop with exit

# Retry pattern
agent.add_edge("input", "validation")
agent.add_edge("validation", "input", 
    condition="validation failed, ask user to try again")
agent.add_edge("validation", "success", 
    condition="validation passed")

Multi-criteria routing

# Complex routing logic
agent.add_edge("analyze_request", "urgent_human", 
    condition="high priority AND complex issue")

agent.add_edge("analyze_request", "automated_urgent", 
    condition="high priority AND simple issue")

agent.add_edge("analyze_request", "queue", 
    condition="normal priority")

agent.add_edge("analyze_request", "self_service", 
    condition="low priority OR informational request")

Edge validation

The agent validates edges during agent.validate():

Common validation errors

  1. Unreachable nodes: All nodes must have a path from START_NODE
# This will fail validation - node2 is unreachable
agent.add_edge(START_NODE, "node1")
agent.add_edge("node1", END_NODE)
agent.add_node(DefaultNode("node2"))  # No edges to/from node2!
  1. Missing terminal paths: All paths must eventually reach END_NODE
# This will fail - no path to END_NODE
agent.add_edge(START_NODE, "node1")
agent.add_edge("node1", "node2")
agent.add_edge("node2", "node1")  # Infinite loop!
  1. Multiple START edges: START_NODE can only have one outgoing edge
# This will fail validation
agent.add_edge(START_NODE, "path1")
agent.add_edge(START_NODE, "path2")  # Error!

Debugging edge issues

Check reachability

# During development, print the graph structure
for edge in agent.edges:
    print(f"{edge.source}{edge.target}")
    if edge.condition:
        print(f"  Condition: {edge.condition}")

Test edge conditions

# Create test scenarios for each edge condition
test_cases = [
    ("I need help with my order", "order_support"),
    ("What products do you have?", "product_info"),
    ("I want to speak to a human", "handoff")
]

Best practices

  1. Use descriptive conditions: Write conditions as if explaining to a human
  2. Avoid ambiguity: Ensure conditions don’t overlap
  3. Always provide fallbacks: Include default paths without conditions
  4. Keep graphs simple: Prefer clarity over complexity
  5. Test all paths: Ensure every edge can be reached in practice
  6. Document complex flows: Add comments explaining routing logic