oxios_kernel/
persona_store.rs1use anyhow::{anyhow, Result};
7use parking_lot::RwLock;
8use std::collections::HashMap;
9use std::sync::Arc;
10
11use super::persona::Persona;
12
13#[derive(Debug, Default)]
15pub struct PersonaStore {
16 personas: RwLock<HashMap<String, Persona>>,
17}
18
19impl PersonaStore {
20 pub fn new() -> Self {
22 Self {
23 personas: RwLock::new(HashMap::new()),
24 }
25 }
26
27 pub fn register(&self, persona: Persona) {
29 let mut personas = self.personas.write();
30 personas.insert(persona.id.clone(), persona);
31 }
32
33 pub fn get(&self, id: &str) -> Option<Persona> {
35 let personas = self.personas.read();
36 personas.get(id).cloned()
37 }
38
39 pub fn list_enabled(&self) -> Vec<Persona> {
41 let personas = self.personas.read();
42 personas.values().filter(|p| p.enabled).cloned().collect()
43 }
44
45 pub fn list_all(&self) -> Vec<Persona> {
47 let personas = self.personas.read();
48 personas.values().cloned().collect()
49 }
50
51 pub fn set_enabled(&self, id: &str, enabled: bool) -> Result<()> {
53 let mut personas = self.personas.write();
54 match personas.get_mut(id) {
55 Some(p) => {
56 p.enabled = enabled;
57 Ok(())
58 }
59 None => Err(anyhow!("Persona '{}' not found", id)),
60 }
61 }
62
63 pub fn delete(&self, id: &str) -> Result<()> {
65 let mut personas = self.personas.write();
66 if personas.remove(id).is_some() {
67 Ok(())
68 } else {
69 Err(anyhow!("Persona '{}' not found", id))
70 }
71 }
72
73 pub fn update(&self, id: &str, updated: Persona) -> Result<()> {
75 let mut personas = self.personas.write();
76 if personas.contains_key(id) {
77 personas.insert(id.to_string(), updated);
78 Ok(())
79 } else {
80 Err(anyhow!("Persona '{}' not found", id))
81 }
82 }
83
84 pub fn len(&self) -> usize {
86 let personas = self.personas.read();
87 personas.len()
88 }
89
90 pub fn is_empty(&self) -> bool {
92 let personas = self.personas.read();
93 personas.is_empty()
94 }
95
96 pub fn load_from_slice(&self, personas: &[Persona]) {
98 let mut store = self.personas.write();
99 for p in personas {
100 store.insert(p.id.clone(), p.clone());
101 }
102 }
103}
104
105#[derive(Clone)]
107pub struct PersonaStoreHandle {
108 store: Arc<PersonaStore>,
109}
110
111impl PersonaStoreHandle {
112 pub fn from_store(store: Arc<PersonaStore>) -> Self {
114 Self { store }
115 }
116
117 pub fn inner(&self) -> Arc<PersonaStore> {
119 Arc::clone(&self.store)
120 }
121}
122
123impl Default for PersonaStoreHandle {
124 fn default() -> Self {
125 Self {
126 store: Arc::new(PersonaStore::new()),
127 }
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134
135 #[test]
136 fn test_register_and_get() {
137 let store = PersonaStore::new();
138 let persona = Persona::new("Test", "assistant", "A test persona", "You are a test.");
139 store.register(persona.clone());
140 assert_eq!(store.get(&persona.id).unwrap().name, "Test");
141 }
142
143 #[test]
144 fn test_list_enabled() {
145 let store = PersonaStore::new();
146 let mut p1 = Persona::new("A", "dev", "Desc A", "Prompt A");
147 p1.enabled = true;
148 let mut p2 = Persona::new("B", "dev", "Desc B", "Prompt B");
149 p2.enabled = false;
150 store.register(p1);
151 store.register(p2);
152
153 let enabled = store.list_enabled();
154 assert_eq!(enabled.len(), 1);
155 assert_eq!(enabled[0].name, "A");
156 }
157
158 #[test]
159 fn test_set_enabled() {
160 let store = PersonaStore::new();
161 let persona = Persona::new("Test", "dev", "Desc", "Prompt");
162 store.register(persona.clone());
163 store.set_enabled(&persona.id, false).unwrap();
164 assert!(store.list_enabled().is_empty());
165
166 store.set_enabled(&persona.id, true).unwrap();
167 assert_eq!(store.list_enabled().len(), 1);
168 }
169
170 #[test]
171 fn test_delete() {
172 let store = PersonaStore::new();
173 let persona = Persona::new("Test", "dev", "Desc", "Prompt");
174 let id = persona.id.clone();
175 store.register(persona);
176 store.delete(&id).unwrap();
177 assert!(store.get(&id).is_none());
178 }
179}