brainos_backends/
memory.rs1use std::sync::Arc;
4
5#[derive(Clone)]
6pub struct DefaultMemoryBackend {
7 pub semantic: Option<hippocampus::SemanticStore>,
8 pub embedder: Arc<tokio::sync::Mutex<Option<hippocampus::Embedder>>>,
9 pub embedding_dim: usize,
10}
11
12#[async_trait::async_trait]
13impl cortex::actions::MemoryBackend for DefaultMemoryBackend {
14 async fn store_fact(
15 &self,
16 namespace: &str,
17 _category: &str,
18 subject: &str,
19 predicate: &str,
20 object: &str,
21 ) -> Result<String, cortex::actions::ActionError> {
22 let Some(semantic) = &self.semantic else {
23 return Err(cortex::actions::ActionError::ExecutionFailed(
24 "Semantic store unavailable".to_string(),
25 ));
26 };
27
28 let content = format!("{subject} {predicate} {object}");
29 let vector = {
30 let mut guard = self.embedder.lock().await;
31 if let Some(embedder) = guard.as_mut() {
32 match embedder.embed(&content).await {
33 Ok(v) => {
34 hippocampus::embedding::sanitize_embedding(v, self.embedding_dim, &content)
35 }
36 Err(e) => {
37 tracing::warn!("ActionDispatcher embedding failed: {e}");
38 hippocampus::embedding::deterministic_fallback_embedding(
39 &content,
40 self.embedding_dim,
41 )
42 }
43 }
44 } else {
45 hippocampus::embedding::deterministic_fallback_embedding(
46 &content,
47 self.embedding_dim,
48 )
49 }
50 };
51
52 semantic
53 .store_fact(
54 namespace, _category, subject, predicate, object, 1.0, None, vector, None,
55 )
56 .await
57 .map_err(|e| cortex::actions::ActionError::ExecutionFailed(e.to_string()))
58 }
59
60 async fn recall(
61 &self,
62 query: &str,
63 top_k: usize,
64 namespace: Option<&str>,
65 ) -> Result<Vec<cortex::actions::MemoryFact>, cortex::actions::ActionError> {
66 let Some(semantic) = &self.semantic else {
67 return Err(cortex::actions::ActionError::ExecutionFailed(
68 "Semantic store unavailable".to_string(),
69 ));
70 };
71
72 let vector = {
73 let mut guard = self.embedder.lock().await;
74 if let Some(embedder) = guard.as_mut() {
75 match embedder.embed(query).await {
76 Ok(v) => {
77 hippocampus::embedding::sanitize_embedding(v, self.embedding_dim, query)
78 }
79 Err(e) => {
80 tracing::warn!("ActionDispatcher embedding failed: {e}");
81 hippocampus::embedding::deterministic_fallback_embedding(
82 query,
83 self.embedding_dim,
84 )
85 }
86 }
87 } else {
88 hippocampus::embedding::deterministic_fallback_embedding(query, self.embedding_dim)
89 }
90 };
91
92 let results = semantic
93 .search_similar(vector, top_k.max(1), namespace, None)
94 .await
95 .map_err(|e| cortex::actions::ActionError::ExecutionFailed(e.to_string()))?;
96
97 Ok(results
98 .into_iter()
99 .map(|r| cortex::actions::MemoryFact {
100 namespace: r.fact.namespace,
101 subject: r.fact.subject,
102 predicate: r.fact.predicate,
103 object: r.fact.object,
104 confidence: r.fact.confidence,
105 })
106 .collect())
107 }
108}