Skip to main content

llm_consolidation/
llm_consolidation.rs

1//! Demonstrates `consolidate()`: episodic memories → semantic facts + graph.
2//!
3//! Uses a `FakeLlm` that returns a hard-coded JSON extraction — no real LLM
4//! or model files needed.
5//!
6//! Run: `cargo run --example llm_consolidation -p basemyai`
7
8use basemyai::{AgentId, LlmInference, Memory, MemoryLayer, consolidate};
9use basemyai_core::{Embedder, Store};
10
11struct FakeEmbedder;
12
13impl Embedder for FakeEmbedder {
14    fn embed(&self, _text: &str) -> basemyai_core::Result<Vec<f32>> {
15        Ok(vec![0.0; 384])
16    }
17    fn embed_batch(&self, texts: &[String]) -> basemyai_core::Result<Vec<Vec<f32>>> {
18        Ok(texts.iter().map(|_| vec![0.0; 384]).collect())
19    }
20    fn model_id(&self) -> &str {
21        "fake-384"
22    }
23    fn dim(&self) -> usize {
24        384
25    }
26}
27
28struct FakeLlm;
29
30#[async_trait::async_trait]
31impl LlmInference for FakeLlm {
32    async fn complete(&self, _prompt: &str) -> basemyai::Result<String> {
33        Ok(r#"{
34            "facts": ["Paris is the capital of France"],
35            "entities": [
36                {"id": "paris",  "kind": "city",    "label": "Paris"},
37                {"id": "france", "kind": "country",  "label": "France"}
38            ],
39            "relations": [
40                {"src": "paris", "relation": "capital_of", "dst": "france"}
41            ]
42        }"#
43        .to_string())
44    }
45
46    fn model_id(&self) -> &str {
47        "fake-llm"
48    }
49}
50
51#[tokio::main]
52async fn main() -> Result<(), Box<dyn std::error::Error>> {
53    let store = Store::open_in_memory().await?;
54    let agent = AgentId::new("consolidation-demo").expect("non-empty id");
55    let memory = Memory::open(store, Box::new(FakeEmbedder), agent).await?;
56
57    // Store a raw episode (what happened).
58    memory
59        .remember(
60            "Alice attended a conference in Paris, the capital of France.",
61            MemoryLayer::Episodic,
62        )
63        .await?;
64
65    // Consolidate: extract facts + populate graph via FakeLlm.
66    let report = consolidate(&memory, &FakeLlm).await?;
67    println!(
68        "Consolidation: {} episode(s) seen, {} fact(s) added, {} entity(ies) upserted, {} relation(s).",
69        report.episodes_seen, report.facts_added, report.entities_upserted, report.relations_upserted,
70    );
71
72    // The extracted fact should now be searchable in semantic layer.
73    let facts = memory
74        .recall_by_layer("What is the capital of France?", MemoryLayer::Semantic, 5)
75        .await?;
76    println!("\nSemantic facts after consolidation ({}):", facts.len());
77    for f in &facts {
78        println!("  • {}", f.text);
79    }
80
81    Ok(())
82}