@@ -76,23 +76,25 @@ pub fn extract_lessons(outcomes: &[ToolOutcome], user_message: &str) -> Vec<Less
7676
7777 // Deduplicate lessons by (tool_name, error_summary prefix)
7878 lessons. dedup_by ( |a, b| {
79- a. tool_name == b. tool_name && truncate_error ( & a. error_summary , 60 ) == truncate_error ( & b. error_summary , 60 )
79+ a. tool_name == b. tool_name
80+ && truncate_error ( & a. error_summary , 60 ) == truncate_error ( & b. error_summary , 60 )
8081 } ) ;
8182
8283 lessons
8384}
8485
8586/// Persist extracted lessons to memory, skipping duplicates.
86- pub async fn persist_lessons (
87- memory : & dyn Memory ,
88- lessons : & [ Lesson ] ,
89- ) -> usize {
87+ pub async fn persist_lessons ( memory : & dyn Memory , lessons : & [ Lesson ] ) -> usize {
9088 let mut stored = 0 ;
9189 let category = MemoryCategory :: Custom ( LESSON_CATEGORY . to_string ( ) ) ;
9290
9391 for lesson in lessons {
9492 // Check for existing similar lesson to avoid duplicates
95- let query = format ! ( "{} {}" , lesson. tool_name, truncate_error( & lesson. error_summary, 80 ) ) ;
93+ let query = format ! (
94+ "{} {}" ,
95+ lesson. tool_name,
96+ truncate_error( & lesson. error_summary, 80 )
97+ ) ;
9698 if let Ok ( existing) = memory. recall ( & query, 3 , None ) . await {
9799 let dominated = existing. iter ( ) . any ( |entry| {
98100 entry. category == category
@@ -170,7 +172,10 @@ fn truncate_error(s: &str, max_chars: usize) -> String {
170172 if first_line. chars ( ) . count ( ) <= max_chars {
171173 first_line. to_string ( )
172174 } else {
173- let truncated: String = first_line. chars ( ) . take ( max_chars. saturating_sub ( 3 ) ) . collect ( ) ;
175+ let truncated: String = first_line
176+ . chars ( )
177+ . take ( max_chars. saturating_sub ( 3 ) )
178+ . collect ( ) ;
174179 format ! ( "{truncated}..." )
175180 }
176181}
@@ -222,10 +227,9 @@ fn value_preview(val: &serde_json::Value, max_len: usize) -> String {
222227fn extract_task_keywords ( user_message : & str ) -> String {
223228 // Extract meaningful words (>3 chars, lowercase, deduplicated)
224229 let stopwords = [
225- "the" , "and" , "for" , "that" , "this" , "with" , "from" , "have" , "will" ,
226- "what" , "when" , "where" , "which" , "your" , "about" , "been" , "could" ,
227- "would" , "should" , "their" , "there" , "these" , "those" , "than" ,
228- "them" , "then" , "they" , "were" , "also" , "into" , "just" , "some" ,
230+ "the" , "and" , "for" , "that" , "this" , "with" , "from" , "have" , "will" , "what" , "when" ,
231+ "where" , "which" , "your" , "about" , "been" , "could" , "would" , "should" , "their" , "there" ,
232+ "these" , "those" , "than" , "them" , "then" , "they" , "were" , "also" , "into" , "just" , "some" ,
229233 "very" , "make" , "like" , "please" , "want" , "need" , "can" ,
230234 ] ;
231235
@@ -277,14 +281,12 @@ mod tests {
277281
278282 #[ test]
279283 fn extract_lessons_no_lesson_when_all_succeed ( ) {
280- let outcomes = vec ! [
281- ToolOutcome {
282- tool_name: "shell" . into( ) ,
283- arguments: serde_json:: json!( { "command" : "ls" } ) ,
284- success: true ,
285- output: "file1 file2" . into( ) ,
286- } ,
287- ] ;
284+ let outcomes = vec ! [ ToolOutcome {
285+ tool_name: "shell" . into( ) ,
286+ arguments: serde_json:: json!( { "command" : "ls" } ) ,
287+ success: true ,
288+ output: "file1 file2" . into( ) ,
289+ } ] ;
288290
289291 let lessons = extract_lessons ( & outcomes, "list files" ) ;
290292 assert ! ( lessons. is_empty( ) ) ;
0 commit comments