use std::collections::BTreeMap;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct MemoryNodeView {
pub node_id: String,
pub node_kind: String,
pub title: String,
pub summary: String,
pub status: String,
pub labels: Vec<String>,
pub properties: BTreeMap<String, String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct MemoryRelationshipView {
pub source_node_id: String,
pub target_node_id: String,
pub relationship_type: String,
pub why: Option<String>,
pub evidence: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct MemoryDetailView {
pub node_id: String,
pub detail: String,
pub content_hash: String,
pub revision: u64,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct MemoryQualityView {
pub raw_equivalent_tokens: u32,
pub compression_ratio: f64,
pub causal_density: f64,
pub noise_ratio: f64,
pub detail_coverage: f64,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RenderedMemoryView {
pub content: String,
pub content_hash: String,
pub token_count: u32,
pub quality: MemoryQualityView,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct MemoryRecallView {
pub about: String,
pub revision: u64,
pub content_hash: String,
pub root: MemoryNodeView,
pub neighbors: Vec<MemoryNodeView>,
pub relationships: Vec<MemoryRelationshipView>,
pub details: Vec<MemoryDetailView>,
pub rendered: RenderedMemoryView,
}
#[cfg(test)]
mod tests {
use super::*;
fn node(id: &str) -> MemoryNodeView {
MemoryNodeView {
node_id: id.to_string(),
node_kind: "decision".to_string(),
title: "First decision".to_string(),
summary: "What was decided".to_string(),
status: "active".to_string(),
labels: vec!["timeline".to_string()],
properties: BTreeMap::new(),
}
}
#[test]
fn a_recall_survives_the_wire() {
let view = MemoryRecallView {
about: "project:checkout".to_string(),
revision: 7,
content_hash: "snapshot-hash".to_string(),
root: node("about:project:checkout"),
neighbors: vec![node("decision:first")],
relationships: vec![MemoryRelationshipView {
source_node_id: "about:project:checkout".to_string(),
target_node_id: "decision:first".to_string(),
relationship_type: "contains".to_string(),
why: Some("the about holds its decisions".to_string()),
evidence: None,
}],
details: vec![MemoryDetailView {
node_id: "decision:first".to_string(),
detail: "The full text.".to_string(),
content_hash: "abc".to_string(),
revision: 1,
}],
rendered: RenderedMemoryView {
content: "# Context".to_string(),
content_hash: "def".to_string(),
token_count: 3,
quality: MemoryQualityView {
raw_equivalent_tokens: 12,
compression_ratio: 4.0,
causal_density: 0.5,
noise_ratio: 0.1,
detail_coverage: 0.9,
},
},
};
let bytes = serde_json::to_vec(&view).expect("serializes");
assert_eq!(
serde_json::from_slice::<MemoryRecallView>(&bytes).expect("deserializes"),
view
);
}
}