AutoGen + HatiData: State Branch & Merge
Use HatiData branching to let AutoGen agent groups explore multiple solution paths simultaneously, then merge the best outcome.
What You'll Build
An AutoGen multi-agent conversation that uses branching to explore multiple solution paths simultaneously.
Prerequisites
$pip install autogen-agentchat hatidata-agent
$hati init
$OpenAI API key
Architecture
┌──────────────┐ ┌──────────────────┐
│ AutoGen │───▶│ HatiData │
│ GroupChat │ │ Branching │
└──────────────┘ └────────┬─────────┘
┌───────┼───────┐
▼ ▼ ▼
Branch A Main Branch B
(plan 1) (plan 2)
└───────┬───────┘
Merge bestKey Concepts
- ●Parallel exploration: create multiple branches to test competing strategies without risk to the main state
- ●Schema isolation: each branch is a separate isolated schema, so writes in one branch never leak to another
- ●Merge strategies: branch_wins overwrites main, main_wins keeps main, manual does row-level conflict resolution
- ●Automatic cleanup: discarded branches are garbage-collected, reclaiming disk space and schema entries
- ●Zero-copy reads: branches start as views over main state, only materializing tables on first write
Step-by-Step Implementation
Install Dependencies
Install AutoGen and the HatiData agent SDK.
pip install autogen-agentchat hatidata-agent
hati initHatiData initialized successfully.
Proxy running on localhost:5439Note: Branching creates isolated schemas. Each branch can have independent writes without affecting main state.
Create Baseline State
Set up the main data state that agents will branch from.
from hatidata_agent import HatiDataAgent
hati = HatiDataAgent(host="localhost", port=5439, agent_id="autogen-planner")
# Create deployment configurations table
hati.execute("""
CREATE TABLE deploy_config (
service VARCHAR, replicas INTEGER,
cpu_limit VARCHAR, memory_limit VARCHAR,
region VARCHAR
)
""")
hati.execute("""
INSERT INTO deploy_config VALUES
('api-gateway', 3, '500m', '512Mi', 'us-east-1'),
('ml-inference', 2, '2000m', '4Gi', 'us-east-1'),
('data-pipeline', 1, '1000m', '2Gi', 'us-east-1')
""")
result = hati.query("SELECT service, replicas, region FROM deploy_config")
print("Baseline deployment config:")
for r in result:
print(f" {r['service']}: {r['replicas']} replicas in {r['region']}")Baseline deployment config:
api-gateway: 3 replicas in us-east-1
ml-inference: 2 replicas in us-east-1
data-pipeline: 1 replicas in us-east-1Create Parallel Exploration Branches
Create two branches for different scaling strategies.
# Branch A: horizontal scaling (more replicas, same resources)
hati.execute("SELECT branch_create('horizontal-scale')")
hati.execute("""
SELECT branch_query(
'horizontal-scale',
'UPDATE deploy_config SET replicas = replicas * 3'
)
""")
hati.execute("""
SELECT branch_query(
'horizontal-scale',
'INSERT INTO deploy_config VALUES (''cache-layer'', 6, ''250m'', ''256Mi'', ''us-east-1'')'
)
""")
# Branch B: vertical scaling (more resources, multi-region)
hati.execute("SELECT branch_create('vertical-scale')")
hati.execute("""
SELECT branch_query(
'vertical-scale',
'UPDATE deploy_config SET cpu_limit = ''4000m'', memory_limit = ''8Gi'' WHERE service = ''ml-inference'''
)
""")
hati.execute("""
SELECT branch_query(
'vertical-scale',
'INSERT INTO deploy_config VALUES (''ml-inference'', 2, ''4000m'', ''8Gi'', ''eu-west-1'')'
)
""")
print("Created branches: horizontal-scale, vertical-scale")Created branches: horizontal-scale, vertical-scaleNote: Each branch gets its own isolated schema. Writes in one branch never affect the other or main.
Compare Branch Outcomes
Query both branches to compare the two scaling strategies.
for branch in ['horizontal-scale', 'vertical-scale']:
result = hati.query(f"""
SELECT branch_query(
'{branch}',
'SELECT service, replicas, cpu_limit, memory_limit, region FROM deploy_config ORDER BY service'
)
""")
total_replicas = sum(int(r['replicas']) for r in result)
print(f"\n=== {branch} ===")
for r in result:
print(f" {r['service']}: {r['replicas']}x ({r['cpu_limit']} CPU, {r['memory_limit']} RAM) in {r['region']}")
print(f" Total replicas: {total_replicas}")
# Main is unchanged
main = hati.query("SELECT SUM(replicas) AS total FROM deploy_config")
print(f"\nMain state total replicas: {main[0]['total']} (unchanged)")=== horizontal-scale ===
api-gateway: 9x (500m CPU, 512Mi RAM) in us-east-1
cache-layer: 6x (250m CPU, 256Mi RAM) in us-east-1
data-pipeline: 3x (1000m CPU, 2Gi RAM) in us-east-1
ml-inference: 6x (2000m CPU, 4Gi RAM) in us-east-1
Total replicas: 24
=== vertical-scale ===
api-gateway: 3x (500m CPU, 512Mi RAM) in us-east-1
data-pipeline: 1x (1000m CPU, 2Gi RAM) in us-east-1
ml-inference: 2x (4000m CPU, 8Gi RAM) in us-east-1
ml-inference: 2x (4000m CPU, 8Gi RAM) in eu-west-1
Total replicas: 8
Main state total replicas: 6 (unchanged)Merge Winner and Clean Up
Merge the chosen strategy into main state and discard the other branch.
# Choose vertical scaling (fewer replicas, more efficient)
hati.execute("SELECT branch_merge('vertical-scale', 'branch_wins')")
hati.execute("SELECT branch_discard('horizontal-scale')")
print("Merged vertical-scale, discarded horizontal-scale")
# Verify final state
result = hati.query("SELECT service, replicas, cpu_limit, region FROM deploy_config ORDER BY service")
print("\nFinal deployment config:")
for r in result:
print(f" {r['service']}: {r['replicas']}x ({r['cpu_limit']} CPU) in {r['region']}")
# Verify no branches remain
branches = hati.query("SELECT branch_list()")
print(f"\nActive branches: {len(branches)}")Merged vertical-scale, discarded horizontal-scale
Final deployment config:
api-gateway: 3x (500m CPU) in us-east-1
data-pipeline: 1x (1000m CPU) in us-east-1
ml-inference: 2x (4000m CPU) in us-east-1
ml-inference: 2x (4000m CPU) in eu-west-1
Active branches: 0Note: After merging, the branch schema is cleaned up by the garbage collector. Active branch count should return to 0.