1use hippmem_core::ids::MemoryId;
5use hippmem_core::model::links::{ActivationStep, MatchDimension, MemoryWarning};
6use hippmem_core::model::unit::MemoryUnit;
7
8#[derive(Debug, Clone)]
10pub struct Explanation {
11 pub memory_id: MemoryId,
12 pub trace: Vec<ActivationStep>,
14 pub dimensions: Vec<MatchDimension>,
16 pub warnings: Vec<MemoryWarning>,
18 pub summary: String,
20}
21
22pub fn explain_result(
24 unit: &MemoryUnit,
25 trace: &[ActivationStep],
26 dimensions: &[MatchDimension],
27 warnings: &[MemoryWarning],
28) -> Explanation {
29 let dim_strs: Vec<String> = dimensions.iter().map(|d| format!("{:?}", d)).collect();
30 let warn_strs: Vec<String> = warnings.iter().map(|w| format!("{:?}", w)).collect();
31
32 let summary = format!(
33 "Memory {} was recalled via {:?} dimension(s) ({}), hops={}. Warnings: {}.",
34 unit.id.as_u128(),
35 dimensions.len(),
36 dim_strs.join(", "),
37 trace.iter().map(|s| s.hop).max().unwrap_or(0),
38 if warn_strs.is_empty() {
39 "none".to_string()
40 } else {
41 warn_strs.join(", ")
42 },
43 );
44
45 Explanation {
46 memory_id: unit.id,
47 trace: trace.to_vec(),
48 dimensions: dimensions.to_vec(),
49 warnings: warnings.to_vec(),
50 summary,
51 }
52}
53
54#[derive(Debug)]
56pub struct InspectReport {
57 pub memory_count: usize,
58 pub link_count: usize,
59 pub stage_distribution: Vec<(String, usize)>,
60}
61
62pub fn inspect_units(units: &[MemoryUnit]) -> InspectReport {
64 let memory_count = units.len();
65 let link_count: usize = units.iter().map(|u| u.links.len()).sum();
66 let mut stage_dist: std::collections::HashMap<String, usize> = std::collections::HashMap::new();
67 for unit in units {
68 let key = format!("{:?}", unit.stage);
69 *stage_dist.entry(key).or_insert(0) += 1;
70 }
71 let stage_distribution: Vec<(String, usize)> = stage_dist.into_iter().collect();
72
73 InspectReport {
74 memory_count,
75 link_count,
76 stage_distribution,
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83
84 #[test]
85 fn explanation_generates_summary() {
86 let unit = MemoryUnit {
87 schema_version: 1,
88 id: MemoryId(42),
89 created_at: hippmem_core::time::Timestamp(0),
90 updated_at: hippmem_core::time::Timestamp(0),
91 content: hippmem_core::model::unit::MemoryContent {
92 raw: "test".into(),
93 summary: None,
94 normalized: None,
95 language: hippmem_core::model::unit::Language::Zh,
96 content_type: hippmem_core::model::unit::ContentType::UserStatement,
97 },
98 context: hippmem_core::model::unit::WriteContext {
99 conversation_id: None,
100 session_id: None,
101 project_id: None,
102 task_id: None,
103 user_id: None,
104 local_time: hippmem_core::time::Timestamp(0),
105 preceding_memory_ids: vec![],
106 source_refs: vec![],
107 },
108 understanding: hippmem_core::model::understanding::MemoryUnderstanding {
109 entities: vec![],
110 events: vec![],
111 goals: vec![],
112 decisions: vec![],
113 preferences: vec![],
114 emotions: vec![],
115 causal_claims: vec![],
116 contradictions: vec![],
117 topics: vec![],
118 importance: hippmem_core::score::UnitScore::new(0.5),
119 confidence: hippmem_core::score::UnitScore::new(0.5),
120 },
121 association_keys: hippmem_core::model::links::AssociationKeys {
122 entity_keys: vec![],
123 temporal_keys: vec![],
124 lexical_signature: hippmem_core::model::links::LexicalSignature { simhash: [0; 4] },
125 semantic_signature: hippmem_core::model::links::SemanticSignature {
126 lexical_simhash: [0; 4],
127 dense_embedding_ref: None,
128 binary_code: [0, 0],
129 topic_minhash: [0u32; 16],
130 },
131 topic_keys: vec![],
132 emotion_keys: vec![],
133 goal_keys: vec![],
134 event_keys: vec![],
135 causal_keys: vec![],
136 },
137 links: vec![],
138 activation: hippmem_core::model::links::ActivationState {
139 last_retrieved_at: None,
140 retrieval_count: 0,
141 co_activations: vec![],
142 usage_score: hippmem_core::score::UnitScore::new(0.5),
143 },
144 lifecycle: hippmem_core::model::unit::MemoryLifecycle::Active,
145 provenance: hippmem_core::model::unit::Provenance {
146 origin: hippmem_core::model::unit::SourceKind::Conversation,
147 generated_by: hippmem_core::model::unit::GeneratedBy::UserDirect,
148 reliability: hippmem_core::score::UnitScore::new(0.5),
149 evidence_refs: vec![],
150 revision_history: vec![],
151 },
152 stage: hippmem_core::model::unit::MemoryStage::Indexed,
153 };
154 let exp = explain_result(&unit, &[], &[], &[]);
155 assert!(exp.summary.contains("42"));
156 }
157
158 #[test]
159 fn inspect_counts_units() {
160 let report = inspect_units(&[]);
161 assert_eq!(report.memory_count, 0);
162 }
163}