1use std::sync::Arc;
4
5use crate::memory::MemoryBackend;
6
7pub const BRIEF_NS: &str = "brief";
8pub const OPEN_LOOPS_KEY: &str = "open_loops";
9pub const TIME_CONTEXTS_KEY: &str = "time_contexts";
10
11pub fn parse_bullet_list(value: &str) -> Vec<String> {
12 value
13 .lines()
14 .map(str::trim)
15 .filter(|l| !l.is_empty() && !l.starts_with('#'))
16 .map(|l| {
17 l.trim_start_matches("- ")
18 .trim_start_matches("* ")
19 .to_string()
20 })
21 .filter(|l| !l.is_empty())
22 .collect()
23}
24
25pub async fn load_brief(memory: &Arc<dyn MemoryBackend>) -> (Vec<String>, Vec<String>) {
26 let loops = memory
27 .recall(BRIEF_NS, OPEN_LOOPS_KEY)
28 .await
29 .ok()
30 .flatten()
31 .map(|e| parse_bullet_list(&e.value))
32 .unwrap_or_default();
33 let contexts = memory
34 .recall(BRIEF_NS, TIME_CONTEXTS_KEY)
35 .await
36 .ok()
37 .flatten()
38 .map(|e| parse_bullet_list(&e.value))
39 .unwrap_or_default();
40 (contexts, loops)
41}
42
43pub fn format_brief_xml(time_contexts: &[String], open_loops: &[String]) -> Option<String> {
44 if time_contexts.is_empty() && open_loops.is_empty() {
45 return None;
46 }
47 let mut out = String::from("<memory_brief>\n");
48 if !time_contexts.is_empty() {
49 out.push_str(" <time_contexts>\n");
50 for line in time_contexts {
51 out.push_str(" - ");
52 out.push_str(line);
53 out.push('\n');
54 }
55 out.push_str(" </time_contexts>\n");
56 }
57 if !open_loops.is_empty() {
58 out.push_str(" <open_loops>\n");
59 for line in open_loops {
60 out.push_str(" - ");
61 out.push_str(line);
62 out.push('\n');
63 }
64 out.push_str(" </open_loops>\n");
65 }
66 out.push_str("</memory_brief>");
67 Some(out)
68}
69
70#[cfg(test)]
71fn demo_brief() {
72 let xml = format_brief_xml(
73 &["this week: ship memory".into()],
74 &["follow up on graph vendor".into()],
75 )
76 .unwrap();
77 assert!(xml.contains("open_loops"));
78 assert!(xml.contains("graph vendor"));
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84
85 #[test]
86 fn parse_bullets() {
87 let v = "- a\n* b\n\n# c\n- d";
88 assert_eq!(parse_bullet_list(v), vec!["a", "b", "d"]);
89 }
90
91 #[test]
92 fn brief_xml() {
93 demo_brief();
94 }
95}