use agentstategraph::{CommitOptions, Repository};
use agentstategraph_core::{IntentCategory, Object};
use agentstategraph_storage::SqliteStorage;
fn main() {
println!("=== AgentStateGraph Agent Workflow Demo ===\n");
let repo = Repository::new(Box::new(
SqliteStorage::in_memory().expect("in-memory sqlite"),
));
repo.init().unwrap();
repo.set_json(
"main",
"/cluster",
&serde_json::json!({
"name": "production",
"nodes": [
{"id": "node-1", "hostname": "jetson-01", "status": "healthy", "gpu_mb": 8192},
{"id": "node-2", "hostname": "jetson-02", "status": "healthy", "gpu_mb": 16384},
{"id": "node-3", "hostname": "jetson-03", "status": "unhealthy", "gpu_mb": 16384}
],
"storage": {"type": "none"},
"network": {"subnet": "10.0.0.0/24"}
}),
CommitOptions::new(
"system",
IntentCategory::Checkpoint,
"Initialize cluster state",
),
)
.unwrap();
println!("Initial state committed to 'main'.\n");
println!("--- Agent: Exploring storage options ---\n");
let nfs = repo
.speculate("main", Some("NFS shared storage".to_string()))
.unwrap();
let ceph = repo
.speculate("main", Some("Ceph distributed storage".to_string()))
.unwrap();
let local = repo
.speculate("main", Some("Local NVMe SSDs".to_string()))
.unwrap();
repo.spec_set(nfs, "/cluster/storage/type", &Object::string("nfs"))
.unwrap();
repo.spec_set(nfs, "/cluster/storage/server", &Object::string("jetson-01"))
.unwrap();
repo.spec_set(
nfs,
"/cluster/storage/mount",
&Object::string("/shared/models"),
)
.unwrap();
repo.spec_set(ceph, "/cluster/storage/type", &Object::string("ceph"))
.unwrap();
repo.spec_set(ceph, "/cluster/storage/replicas", &Object::int(3))
.unwrap();
repo.spec_set(ceph, "/cluster/storage/pool", &Object::string("ml-data"))
.unwrap();
repo.spec_set(
local,
"/cluster/storage/type",
&Object::string("local-nvme"),
)
.unwrap();
repo.spec_set(
local,
"/cluster/storage/path",
&Object::string("/dev/nvme0n1"),
)
.unwrap();
println!("--- Comparing speculations ---\n");
let comparison = repo.compare_speculations(&[nfs, ceph, local]).unwrap();
for entry in &comparison.entries {
println!(
" {:?}: {} changes from base",
entry.label,
entry.diff_from_base.len()
);
for op in &entry.diff_from_base {
println!(" {:?}", op);
}
println!();
}
println!("--- Agent: Selecting NFS ---");
println!(" Reasoning: NFS provides shared storage with minimal node requirements.");
println!(" Ceph rejected: requires 3 healthy nodes, only 2 available.");
println!(" Local rejected: not shared across nodes.\n");
repo.commit_speculation(
nfs,
CommitOptions::new(
"agent/storage-planner",
IntentCategory::Refine,
"Selected NFS — Ceph requires 3+ healthy nodes, local not shared",
)
.with_reasoning(
"NFS provides shared storage with minimal node requirements. \
Ceph requires 3 healthy replicas but node-3 is unhealthy. \
Local NVMe is fast but not shared across nodes for distributed training.",
)
.with_confidence(0.85)
.with_tags(vec!["storage".to_string(), "nfs".to_string()]),
)
.unwrap();
repo.discard_speculation(ceph).unwrap();
repo.discard_speculation(local).unwrap();
println!("--- Final state ---\n");
let storage_type = repo.get_json("main", "/cluster/storage/type").unwrap();
let storage_mount = repo.get_json("main", "/cluster/storage/mount").unwrap();
println!(" storage.type: {}", storage_type);
println!(" storage.mount: {}", storage_mount);
println!("\n--- Commit log ---\n");
let log = repo.log("main", 10).unwrap();
for commit in log.iter().rev() {
println!(" {} [{:?}]", commit.id.short(), commit.intent.category);
println!(" agent: {}", commit.agent_id);
println!(" intent: {}", commit.intent.description);
if !commit.intent.tags.is_empty() {
println!(" tags: {:?}", commit.intent.tags);
}
if let Some(ref r) = commit.reasoning {
let short = if r.len() > 80 { &r[..80] } else { r };
println!(" reasoning: {}...", short);
}
if let Some(c) = commit.confidence {
println!(" confidence: {}", c);
}
println!();
}
println!("--- Branch workflow ---\n");
repo.branch("hotfix/node3", "main").unwrap();
repo.set(
"hotfix/node3",
"/cluster/nodes/2/status",
&Object::string("draining"),
CommitOptions::new(
"agent/health-monitor",
IntentCategory::Fix,
"Drain node-3 due to GPU fault",
)
.with_reasoning("Node-3 GPU health check failed — CUDA memory test error")
.with_confidence(0.95),
)
.unwrap();
let diff = repo.diff("main", "hotfix/node3").unwrap();
println!(" Diff main → hotfix/node3:");
for op in &diff {
println!(" {:?}", op);
}
repo.merge(
"hotfix/node3",
"main",
CommitOptions::new(
"agent/health-monitor",
IntentCategory::Fix,
"Apply node-3 drain hotfix",
),
)
.unwrap();
let node3_status = repo.get_json("main", "/cluster/nodes/2/status").unwrap();
println!("\n After merge, node-3 status: {}", node3_status);
println!("\n=== Demo complete ===");
println!("Total commits: {}", repo.log("main", 100).unwrap().len());
}