use enki_runtime::config::{AgentConfig, MemoryConfig};
use enki_runtime::core::agent::AgentContext;
use enki_runtime::core::error::Result;
use enki_runtime::core::memory::{Memory, MemoryEntry};
use enki_runtime::llm::LlmAgent;
use enki_runtime::memory::InMemoryBackend;
use enki_runtime::{LlmAgentFromConfig, MemoryFromConfig};
use serde_json::json;
struct MemoryAgent {
name: String,
agent: LlmAgent,
memory: InMemoryBackend,
}
impl MemoryAgent {
fn new(config: AgentConfig, memory_config: MemoryConfig) -> Result<Self> {
let name = config.name.clone();
let agent = LlmAgent::from_config(config)?;
let memory = InMemoryBackend::from_config(&memory_config);
println!("✓ Created agent '{}' with isolated memory", name);
Ok(Self {
name,
agent,
memory,
})
}
async fn remember(&self, key: &str, content: &str) -> Result<String> {
let entry = MemoryEntry::new(content).with_metadata("key", json!(key));
let id = self.memory.store(entry).await?;
println!(" 📝 {} remembered: '{}'", self.name, key);
Ok(id)
}
async fn ask(&mut self, question: &str, ctx: &mut AgentContext) -> Result<String> {
println!("\n🔍 Asking {}: {}", self.name, question);
let query = enki_runtime::MemoryQuery::new()
.with_semantic_query(question)
.with_limit(3);
let memories = self.memory.search(query).await?;
let context = if memories.is_empty() {
"No relevant information in memory.".to_string()
} else {
memories
.iter()
.map(|m| m.content.clone())
.collect::<Vec<_>>()
.join("\n\n")
};
println!(" 📚 {} found {} memories", self.name, memories.len());
let prompt = format!(
"Based on your knowledge:\n{}\n\nQuestion: {}\n\nAnswer concisely:",
context, question
);
let response = self
.agent
.send_message_and_get_response(&prompt, ctx)
.await?;
Ok(response)
}
}
#[tokio::main]
async fn main() -> Result<()> {
println!("=== Multi-Agent with Separate Memory ===\n");
println!("This example shows multiple agents with isolated memory systems.\n");
let tech_config = AgentConfig::new("tech_expert", "ollama::gemma3:latest")
.with_system_prompt(
"You are a technology expert. Answer questions about technology \
based on your knowledge. Be concise.",
)
.with_temperature(0.3);
let tech_memory = MemoryConfig::in_memory()
.with_max_entries(100)
.with_ttl_seconds(3600);
let mut tech_agent = MemoryAgent::new(tech_config, tech_memory)?;
let history_config = AgentConfig::new("history_expert", "ollama::gemma3:latest")
.with_system_prompt(
"You are a history expert. Answer questions about historical events \
based on your knowledge. Be concise.",
)
.with_temperature(0.3);
let history_memory = MemoryConfig::in_memory()
.with_max_entries(100)
.with_ttl_seconds(3600);
let mut history_agent = MemoryAgent::new(history_config, history_memory)?;
println!("\n--- Storing knowledge in separate memories ---\n");
tech_agent
.remember(
"rust_lang",
"Rust is a systems programming language focused on safety and performance. \
It was created by Mozilla and first released in 2015.",
)
.await?;
tech_agent
.remember(
"enki_runtime",
"Enki Runtime is a Rust-based agent framework for building AI systems. \
It supports 13+ LLM providers and has a pluggable memory system.",
)
.await?;
history_agent
.remember(
"moon_landing",
"The Apollo 11 moon landing occurred on July 20, 1969. \
Neil Armstrong was the first human to walk on the moon.",
)
.await?;
history_agent
.remember(
"world_war_2",
"World War 2 lasted from 1939 to 1945. It was the deadliest conflict \
in human history, involving most of the world's nations.",
)
.await?;
let mut tech_ctx = AgentContext::new("tech_session".to_string(), None);
let mut history_ctx = AgentContext::new("history_session".to_string(), None);
println!("\n--- Querying agents with separate memories ---");
println!("\n{}", "=".repeat(50));
match tech_agent
.ask("What is Enki Runtime?", &mut tech_ctx)
.await
{
Ok(response) => println!("💬 tech_expert:\n{}", response),
Err(e) => eprintln!("❌ Error: {}", e),
}
println!("{}", "=".repeat(50));
println!("\n{}", "=".repeat(50));
match history_agent
.ask("When did humans first walk on the moon?", &mut history_ctx)
.await
{
Ok(response) => println!("💬 history_expert:\n{}", response),
Err(e) => eprintln!("❌ Error: {}", e),
}
println!("{}", "=".repeat(50));
println!("\n--- Demonstrating Memory Isolation ---");
println!("\n{}", "=".repeat(50));
match tech_agent.ask("When did WW2 end?", &mut tech_ctx).await {
Ok(response) => {
println!(
"💬 tech_expert (asked about history - no context!):\n{}",
response
);
}
Err(e) => eprintln!("❌ Error: {}", e),
}
println!("{}", "=".repeat(50));
println!("\n{}", "=".repeat(50));
match history_agent
.ask("What is Rust programming language?", &mut history_ctx)
.await
{
Ok(response) => {
println!(
"💬 history_expert (asked about tech - no context!):\n{}",
response
);
}
Err(e) => eprintln!("❌ Error: {}", e),
}
println!("{}", "=".repeat(50));
println!("\n=== Multi-Agent Example Complete ===");
println!("\nKey takeaway: Each agent has ISOLATED memory!");
println!("- tech_expert knows about Rust and Enki, not history");
println!("- history_expert knows about moon landing and WW2, not tech");
Ok(())
}