lattice_agent/log/
buffer_names.rs1use std::sync::Arc;
21
22use super::ai_log::SessionKey;
23
24pub fn ai_log_name(session: &SessionKey) -> String {
29 format!("*ai:{}:{}*", session.provider, session.index)
30}
31
32pub fn parse_ai_log_name(name: &str) -> Option<SessionKey> {
36 let body = name.strip_prefix("*ai:")?.strip_suffix('*')?;
37 if body.is_empty() {
38 return None;
39 }
40 let (provider, index_str) = body.split_once(':')?;
41 if provider.is_empty() {
42 return None;
43 }
44 let index = index_str.parse::<u32>().ok()?;
45 Some(SessionKey::new(Arc::<str>::from(provider), index))
46}
47
48#[cfg(test)]
49mod tests {
50 use super::*;
51
52 fn key(provider: &str, index: u32) -> SessionKey {
53 SessionKey::new(Arc::<str>::from(provider), index)
54 }
55
56 #[test]
57 fn name_round_trips() {
58 let k = key("opencode", 1);
59 let name = ai_log_name(&k);
60 assert_eq!(name, "*ai:opencode:1*");
61 let parsed = parse_ai_log_name(&name).expect("parse");
62 assert_eq!(parsed, k);
63 }
64
65 #[test]
66 fn name_round_trips_second_index() {
67 let k = key("opencode", 2);
68 let name = ai_log_name(&k);
69 assert_eq!(name, "*ai:opencode:2*");
70 let parsed = parse_ai_log_name(&name).expect("parse");
71 assert_eq!(parsed, k);
72 }
73
74 #[test]
75 fn parser_rejects_garbage_names() {
76 assert!(parse_ai_log_name("*foo*").is_none());
77 assert!(parse_ai_log_name("*ai:*").is_none());
78 assert!(parse_ai_log_name("*ai::1*").is_none());
79 assert!(parse_ai_log_name("*ai:opencode:*").is_none());
80 assert!(parse_ai_log_name("*ai:opencode:x*").is_none());
81 assert!(parse_ai_log_name("not-ai").is_none());
82 }
83}