codemem_engine/hooks/
triggers.rs1#[derive(Debug, Clone)]
5pub struct AutoInsight {
6 pub content: String,
8 pub tags: Vec<String>,
10 pub importance: f64,
12 pub dedup_tag: String,
14}
15
16pub fn check_triggers(
25 storage: &dyn codemem_core::StorageBackend,
26 session_id: &str,
27 tool_name: &str,
28 file_path: Option<&str>,
29 pattern: Option<&str>,
30) -> Vec<AutoInsight> {
31 let mut insights = Vec::new();
32
33 if tool_name == "Read" {
35 if let Some(fp) = file_path {
36 let directory = std::path::Path::new(fp)
37 .parent()
38 .map(|p| p.to_string_lossy().to_string())
39 .unwrap_or_default();
40 if !directory.is_empty() {
41 let dedup_tag = format!("dir_focus:{}", directory);
42 let already_exists = storage
43 .has_auto_insight(session_id, &dedup_tag)
44 .unwrap_or(true);
45 if !already_exists {
46 let count = storage
47 .count_directory_reads(session_id, &directory)
48 .unwrap_or(0);
49 if count >= 3 {
50 insights.push(AutoInsight {
51 content: format!(
52 "Deep exploration of directory '{}': {} files read in this session. \
53 This area may be a focus of the current task.",
54 directory, count
55 ),
56 tags: vec![
57 "auto-insight".to_string(),
58 "directory-focus".to_string(),
59 format!("dir:{}", directory),
60 ],
61 importance: 0.6,
62 dedup_tag,
63 });
64 }
65 }
66 }
67 }
68 }
69
70 if matches!(tool_name, "Edit" | "Write") {
72 if let Some(fp) = file_path {
73 let dedup_tag = format!("edit_after_read:{}", fp);
74 let already_exists = storage
75 .has_auto_insight(session_id, &dedup_tag)
76 .unwrap_or(true);
77 if !already_exists {
78 let was_read = storage
79 .was_file_read_in_session(session_id, fp)
80 .unwrap_or(false);
81 if was_read {
82 insights.push(AutoInsight {
83 content: format!(
84 "File '{}' was read and then modified in this session, \
85 indicating an informed change based on code review.",
86 fp
87 ),
88 tags: vec![
89 "auto-insight".to_string(),
90 "edit-after-read".to_string(),
91 format!(
92 "file:{}",
93 std::path::Path::new(fp)
94 .file_name()
95 .and_then(|f| f.to_str())
96 .unwrap_or("unknown")
97 ),
98 ],
99 importance: 0.5,
100 dedup_tag,
101 });
102 }
103 }
104 }
105 }
106
107 if tool_name == "Read" {
110 if let Some(fp) = file_path {
111 let directory = std::path::Path::new(fp)
112 .parent()
113 .map(|p| p.to_string_lossy().to_string())
114 .unwrap_or_default();
115 if !directory.is_empty() {
116 let module_name = std::path::Path::new(&directory)
117 .file_name()
118 .and_then(|f| f.to_str())
119 .unwrap_or("unknown");
120 let dedup_tag = format!("exploring_module:{}", directory);
121 let already_exists = storage
122 .has_auto_insight(session_id, &dedup_tag)
123 .unwrap_or(true);
124 if !already_exists {
125 let count = storage
126 .count_directory_reads(session_id, &directory)
127 .unwrap_or(0);
128 if count >= 3 {
129 insights.push(AutoInsight {
130 content: format!(
131 "Exploring '{}' module: {} files read. Building understanding of this area.",
132 module_name, count
133 ),
134 tags: vec![
135 "auto-insight".to_string(),
136 "exploring-module".to_string(),
137 format!("module:{}", module_name),
138 ],
139 importance: 0.55,
140 dedup_tag,
141 });
142 }
143 }
144 }
145 }
146 }
147
148 if tool_name == "Bash" {
150 let has_error = storage
151 .count_search_pattern_in_session(session_id, "error")
152 .unwrap_or(0)
153 > 0;
154 if has_error {
155 let area = file_path
156 .and_then(|fp| {
157 std::path::Path::new(fp)
158 .parent()
159 .and_then(|p| p.file_name())
160 .and_then(|f| f.to_str())
161 })
162 .unwrap_or("project");
163 let dedup_tag = format!("debugging:{}", area);
164 let already_exists = storage
165 .has_auto_insight(session_id, &dedup_tag)
166 .unwrap_or(true);
167 if !already_exists {
168 insights.push(AutoInsight {
169 content: format!(
170 "Debugging in '{}': error output detected in bash commands during this session.",
171 area
172 ),
173 tags: vec![
174 "auto-insight".to_string(),
175 "debugging".to_string(),
176 format!("area:{}", area),
177 ],
178 importance: 0.6,
179 dedup_tag,
180 });
181 }
182 }
183 }
184
185 if matches!(tool_name, "Grep" | "Glob") {
187 if let Some(pat) = pattern {
188 let dedup_tag = format!("repeated_search:{}", pat);
189 let already_exists = storage
190 .has_auto_insight(session_id, &dedup_tag)
191 .unwrap_or(true);
192 if !already_exists {
193 let count = storage
194 .count_search_pattern_in_session(session_id, pat)
195 .unwrap_or(0);
196 if count >= 2 {
197 insights.push(AutoInsight {
198 content: format!(
199 "Search pattern '{}' used {} times in this session. \
200 Consider storing a permanent memory for this recurring lookup.",
201 pat, count
202 ),
203 tags: vec![
204 "auto-insight".to_string(),
205 "repeated-search".to_string(),
206 format!("pattern:{}", pat),
207 ],
208 importance: 0.5,
209 dedup_tag,
210 });
211 }
212 }
213 }
214 }
215
216 insights
217}