vtcode_core/core/agent/
compaction_checkpoint.rs1use std::path::Path;
13
14use anyhow::Context;
15use tracing::warn;
16
17use crate::compaction::memory_envelope::SessionMemoryEnvelope;
18
19pub fn write_compaction_checkpoint(workspace_root: &Path, envelope: &SessionMemoryEnvelope) {
26 let memories_dir = workspace_root.join("memories");
27 if let Err(e) = std::fs::create_dir_all(&memories_dir) {
28 warn!(path = %memories_dir.display(), error = %e, "failed to create memories dir");
29 return;
30 }
31
32 let progress_path = memories_dir.join("progress.md");
34 let progress_content = format!(
35 "# Session Progress\n\n\
36 **Session:** {}\n\
37 **Generated:** {}\n\n\
38 ## Summary\n{}\n\n\
39 ## Objective\n{}\n\n\
40 ## Key Facts\n{}\n\n\
41 ## Touched Files\n{}\n",
42 envelope.session_id,
43 envelope.generated_at,
44 envelope.summary.trim(),
45 envelope.objective.as_deref().unwrap_or("(not set)"),
46 if envelope.grounded_facts.is_empty() {
47 "(none)".to_string()
48 } else {
49 envelope
50 .grounded_facts
51 .iter()
52 .map(|f| format!("- {}", f.fact))
53 .collect::<Vec<_>>()
54 .join("\n")
55 },
56 if envelope.touched_files.is_empty() {
57 "(none)".to_string()
58 } else {
59 envelope
60 .touched_files
61 .iter()
62 .map(|f| format!("- {f}"))
63 .collect::<Vec<_>>()
64 .join("\n")
65 },
66 );
67 if let Err(e) = std::fs::write(&progress_path, progress_content) {
68 warn!(path = %progress_path.display(), error = %e, "failed to write progress checkpoint");
69 }
70
71 let summary_path = memories_dir.join("compaction_summary.md");
73 let summary_content = format!(
74 "# Compaction Summary\n\n\
75 **Session:** {}\n\
76 **Generated:** {}\n\n\
77 ## Full Summary\n{}\n\n\
78 ## Constraints\n{}\n\n\
79 ## Open Questions\n{}\n\n\
80 ## Verification TODO\n{}\n",
81 envelope.session_id,
82 envelope.generated_at,
83 envelope.summary.trim(),
84 if envelope.constraints.is_empty() {
85 "(none)".to_string()
86 } else {
87 envelope
88 .constraints
89 .iter()
90 .map(|c| format!("- {c}"))
91 .collect::<Vec<_>>()
92 .join("\n")
93 },
94 if envelope.open_questions.is_empty() {
95 "(none)".to_string()
96 } else {
97 envelope
98 .open_questions
99 .iter()
100 .map(|q| format!("- {q}"))
101 .collect::<Vec<_>>()
102 .join("\n")
103 },
104 if envelope.verification_todo.is_empty() {
105 "(none)".to_string()
106 } else {
107 envelope
108 .verification_todo
109 .iter()
110 .map(|t| format!("- {t}"))
111 .collect::<Vec<_>>()
112 .join("\n")
113 },
114 );
115 if let Err(e) = std::fs::write(&summary_path, summary_content) {
116 warn!(path = %summary_path.display(), error = %e, "failed to write compaction summary");
117 }
118}
119
120pub async fn write_compaction_checkpoint_async(workspace_root: &Path, envelope: &SessionMemoryEnvelope) {
122 let workspace_root = workspace_root.to_path_buf();
123 let envelope = envelope.clone();
124 if let Err(error) = tokio::task::spawn_blocking(move || write_compaction_checkpoint(&workspace_root, &envelope))
125 .await
126 .context("Compaction checkpoint task panicked")
127 {
128 warn!(error = %error, "failed to persist compaction checkpoint");
129 }
130}