agentic_memory/v3/
migration.rs1use super::block::*;
4use super::engine::MemoryEngineV3;
5use std::path::Path;
6
7pub struct V2ToV3Migration;
9
10impl V2ToV3Migration {
11 pub fn migrate(
19 v2_path: &Path,
20 v3_engine: &MemoryEngineV3,
21 ) -> Result<MigrationReport, std::io::Error> {
22 let mut report = MigrationReport::default();
23
24 if !Self::is_v2_format(v2_path) {
26 return Err(std::io::Error::new(
27 std::io::ErrorKind::InvalidData,
28 "Not a V2 .amem file (missing AMEM magic bytes)",
29 ));
30 }
31
32 #[cfg(feature = "format")]
34 {
35 use crate::format::AmemReader;
36
37 match AmemReader::read_from_file(v2_path) {
38 Ok(graph) => {
39 report.v2_nodes = graph.node_count();
40 report.v2_edges = graph.edge_count();
41
42 for node in graph.nodes() {
44 match v3_engine.capture_user_message(&node.content, None) {
45 Ok(_) => report.blocks_created += 1,
46 Err(e) => report.errors.push(format!("Node {}: {}", node.id, e)),
47 }
48 }
49
50 let _ = v3_engine.capture_boundary(
52 BoundaryType::SessionStart,
53 0,
54 0,
55 &format!(
56 "Migrated from V2: {} nodes, {} edges",
57 report.v2_nodes, report.v2_edges
58 ),
59 Some("V3 immortal mode active"),
60 );
61
62 report.success = report.errors.is_empty();
63 }
64 Err(e) => {
65 report.errors.push(format!("Failed to read V2 file: {}", e));
66 }
67 }
68 }
69
70 #[cfg(not(feature = "format"))]
71 {
72 let _ = v3_engine;
73 report
74 .errors
75 .push("V2 migration requires 'format' feature".to_string());
76 }
77
78 Ok(report)
79 }
80
81 pub fn is_v2_format(path: &Path) -> bool {
83 if let Ok(data) = std::fs::read(path) {
84 data.len() >= 4 && &data[0..4] == b"AMEM"
86 } else {
87 false
88 }
89 }
90
91 pub fn is_v3_format(path: &Path) -> bool {
93 if let Ok(data) = std::fs::read(path) {
94 if data.len() >= 4 {
97 let block_len = u32::from_le_bytes([data[0], data[1], data[2], data[3]]) as usize;
98 if data.len() >= 4 + block_len && block_len > 0 {
99 return serde_json::from_slice::<Block>(&data[4..4 + block_len]).is_ok();
100 }
101 }
102 false
103 } else {
104 false
105 }
106 }
107}
108
109#[derive(Debug, Default)]
111pub struct MigrationReport {
112 pub success: bool,
113 pub v2_nodes: usize,
114 pub v2_edges: usize,
115 pub blocks_created: usize,
116 pub errors: Vec<String>,
117}