use std::sync::Arc;
use std::time::Instant;
use ipld_core::ipld::Ipld;
use mnem_core::id::{EdgeId, NodeId};
use mnem_core::store::{Blockstore, MemoryBlockstore, MemoryOpHeadsStore, OpHeadsStore};
use mnem_core::{Edge, Node, QueryHit, ReadonlyRepo};
const NUM_PEOPLE: usize = 1_000;
const NUM_EDGES: usize = 5_000;
const COMPANIES: &[&str] = &["Acme", "Globex", "Initech", "Umbrella", "Wayne"];
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("# mnem killer demo - agent-native memory, {NUM_PEOPLE} people, {NUM_EDGES} edges");
println!("# mnem-core {}", mnem_core::VERSION);
println!();
let bs: Arc<dyn Blockstore> = Arc::new(MemoryBlockstore::new());
let ohs: Arc<dyn OpHeadsStore> = Arc::new(MemoryOpHeadsStore::new());
let repo0 = ReadonlyRepo::init(bs.clone(), ohs.clone())?;
let t0 = Instant::now();
let mut tx = repo0.start_transaction();
let mut people: Vec<NodeId> = Vec::with_capacity(NUM_PEOPLE);
for i in 0..NUM_PEOPLE {
let name = format!("Person_{i:04}");
let company = COMPANIES[i % COMPANIES.len()];
let role = if i % 3 == 0 {
"Engineer"
} else if i % 3 == 1 {
"Manager"
} else {
"Sales"
};
let node = Node::new(NodeId::new_v7(), "Person")
.with_prop("name", Ipld::String(name))
.with_prop("company", Ipld::String(company.into()))
.with_prop("role", Ipld::String(role.into()));
tx.add_node(&node)?;
people.push(node.id);
}
for i in 0..NUM_EDGES {
let from = people[i % NUM_PEOPLE];
let to = people[(i * 31 + 7) % NUM_PEOPLE];
if from == to {
continue;
}
let label = if i % 2 == 0 { "knows" } else { "works_with" };
let edge = Edge::new(EdgeId::new_v7(), label, from, to);
tx.add_edge(&edge)?;
}
let repo1 = tx.commit("agent:A", "seed org graph")?;
let seed_dur = t0.elapsed();
println!(
"step 1. seed: {:>6} ms ({} people, {} edges, signed + indexed + versioned)",
seed_dur.as_millis(),
NUM_PEOPLE,
NUM_EDGES
);
let t1 = Instant::now();
let hits = repo1
.query()
.label("Person")
.where_eq("name", "Person_0042")
.execute()?;
let query_dur = t1.elapsed();
assert_eq!(hits.len(), 1, "exactly one Person_0042 expected");
let target = hits[0].node.clone();
let target_id = target.id;
let company = match target.props.get("company") {
Some(Ipld::String(s)) => s.clone(),
_ => "?".to_string(),
};
println!(
"step 2. retrieve: {:>6} µs Person_0042 at {} (prop-index point lookup)",
query_dur.as_micros(),
company
);
let t2 = Instant::now();
let hits = repo1
.query()
.label("Person")
.where_eq("name", "Person_0042")
.with_outgoing("knows")
.execute()?;
let traverse_dur = t2.elapsed();
let edges_out = hits.first().map_or(0, |h| h.edges.len());
println!(
"step 3. traverse: {:>6} µs {} outgoing 'knows' edges via adjacency index",
traverse_dur.as_micros(),
edges_out
);
let t3 = Instant::now();
let mut tx = repo1.start_transaction();
let updated = Node::new(target_id, "Person")
.with_prop("name", Ipld::String("Person_0042".into()))
.with_prop("company", Ipld::String("Beta".into()))
.with_prop("role", Ipld::String("Director".into()));
tx.add_node(&updated)?;
let repo2 = tx.commit("agent:C", "promote Person_0042")?;
let mutate_dur = t3.elapsed();
let post = repo2
.query()
.label("Person")
.where_eq("name", "Person_0042")
.execute()?;
let post_company = match post[0].node.props.get("company") {
Some(Ipld::String(s)) => s.clone(),
_ => "?".to_string(),
};
println!(
"step 4. mutate: {:>6} ms Person_0042 is now at {} (new commit, old still queryable)",
mutate_dur.as_millis(),
post_company
);
let hist = repo1
.query()
.label("Person")
.where_eq("name", "Person_0042")
.execute()?;
let hist_company = match hist[0].node.props.get("company") {
Some(Ipld::String(s)) => s.clone(),
_ => "?".to_string(),
};
println!(" history check: old commit still reports {hist_company} (full time-travel)");
let markdown_bytes = estimate_markdown_bytes();
let answer = hits.first().unwrap();
let answer_bytes = estimate_answer_bytes(answer);
println!();
println!("# context-window comparison (rough byte proxy for tokens)");
println!(
" markdown dump: {markdown_bytes:>6} bytes (every person + every edge in the prompt)"
);
println!(
" mnem answer: {answer_bytes:>6} bytes (just Person_0042 + its requested edges)"
);
println!(
" reduction factor: {:>6}x",
markdown_bytes.saturating_div(answer_bytes.max(1))
);
println!();
println!("# summary");
println!(
" - all retrieval paths sub-millisecond on 1k-node repo (prop + label + adjacency indexes)"
);
println!(" - every commit signed-ready, content-addressed, versioned");
println!(" - agent B never saw the full graph; only the slice it asked for");
println!(
" - agent C updated one node; everyone else sees it instantly, audit trail is automatic"
);
println!();
println!(" this is the shape of 'memory that scales' for multi-agent workflows.");
Ok(())
}
const fn estimate_markdown_bytes() -> usize {
70 * NUM_PEOPLE + 40 * NUM_EDGES + 60
}
fn estimate_answer_bytes(hit: &QueryHit) -> usize {
30 + 40 * hit.node.props.len() + 30 * hit.edges.len()
}