vv_agent/memory/session/
parse.rs1use super::{SessionMemory, SessionMemoryEntry};
2use crate::memory::SessionMemoryOutputInvalidReason;
3
4impl SessionMemory {
5 pub fn parse_extraction_result(&self, raw: &str, cycle: i32) -> Vec<SessionMemoryEntry> {
6 self.parse_extraction_result_checked(raw, cycle)
7 .unwrap_or_default()
8 }
9
10 pub(crate) fn parse_extraction_result_checked(
11 &self,
12 raw: &str,
13 cycle: i32,
14 ) -> Result<Vec<SessionMemoryEntry>, SessionMemoryOutputInvalidReason> {
15 if raw.trim().is_empty() {
16 return Err(SessionMemoryOutputInvalidReason::EmptyOutput);
17 }
18 let Some(array_text) = extract_first_json_array(raw) else {
19 return Err(SessionMemoryOutputInvalidReason::JsonArrayMissing);
20 };
21 let Ok(value) = serde_json::from_str::<serde_json::Value>(array_text) else {
22 return Err(SessionMemoryOutputInvalidReason::JsonArrayMissing);
23 };
24 let Some(items) = value.as_array() else {
25 return Err(SessionMemoryOutputInvalidReason::JsonArrayMissing);
26 };
27 let entries = items
28 .iter()
29 .filter_map(|item| {
30 let object = item.as_object()?;
31 let content = object.get("content")?.as_str()?.trim();
32 if content.is_empty() {
33 return None;
34 }
35 let category = object
36 .get("category")
37 .and_then(serde_json::Value::as_str)
38 .unwrap_or("key_fact");
39 let importance = object
40 .get("importance")
41 .and_then(serde_json::Value::as_u64)
42 .unwrap_or(5)
43 .min(10) as u8;
44 Some(SessionMemoryEntry::new(
45 category,
46 content,
47 cycle,
48 importance.max(1),
49 ))
50 })
51 .collect::<Vec<_>>();
52 if entries.is_empty() {
53 Err(SessionMemoryOutputInvalidReason::NoValidEntries)
54 } else {
55 Ok(entries)
56 }
57 }
58}
59
60fn extract_first_json_array(raw: &str) -> Option<&str> {
61 let start = raw.find('[')?;
62 let mut depth = 0_i32;
63 let mut in_string = false;
64 let mut escaped = false;
65 for (offset, ch) in raw[start..].char_indices() {
66 if escaped {
67 escaped = false;
68 continue;
69 }
70 match ch {
71 '\\' if in_string => escaped = true,
72 '"' => in_string = !in_string,
73 '[' if !in_string => depth += 1,
74 ']' if !in_string => {
75 depth -= 1;
76 if depth == 0 {
77 return Some(&raw[start..start + offset + ch.len_utf8()]);
78 }
79 }
80 _ => {}
81 }
82 }
83 None
84}