1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
8#[serde(rename_all = "lowercase")]
9#[non_exhaustive]
10pub enum MemoryTier {
11 Working,
13 Episodic,
15 Semantic,
18 Persona,
21}
22
23impl MemoryTier {
24 #[must_use]
35 pub fn as_str(self) -> &'static str {
36 match self {
37 Self::Working => "working",
38 Self::Episodic => "episodic",
39 Self::Semantic => "semantic",
40 Self::Persona => "persona",
41 }
42 }
43}
44
45impl std::fmt::Display for MemoryTier {
46 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
47 f.pad(self.as_str())
48 }
49}
50
51impl std::str::FromStr for MemoryTier {
52 type Err = String;
53 fn from_str(s: &str) -> Result<Self, Self::Err> {
54 match s {
55 "working" => Ok(Self::Working),
56 "episodic" => Ok(Self::Episodic),
57 "semantic" => Ok(Self::Semantic),
58 "persona" => Ok(Self::Persona),
59 other => Err(format!("unknown memory tier: {other}")),
60 }
61 }
62}
63
64#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, sqlx::Type)]
78#[sqlx(transparent)]
79pub struct ConversationId(pub i64);
80
81impl std::fmt::Display for ConversationId {
82 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83 write!(f, "{}", self.0)
84 }
85}
86
87#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, sqlx::Type)]
101#[sqlx(transparent)]
102pub struct MessageId(pub i64);
103
104#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, sqlx::Type)]
118#[sqlx(transparent)]
119pub struct MemSceneId(pub i64);
120
121impl std::fmt::Display for MemSceneId {
122 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
123 write!(f, "{}", self.0)
124 }
125}
126
127impl std::fmt::Display for MessageId {
128 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
129 write!(f, "{}", self.0)
130 }
131}
132
133#[derive(
147 Debug,
148 Clone,
149 Copy,
150 PartialEq,
151 Eq,
152 PartialOrd,
153 Ord,
154 Hash,
155 sqlx::Type,
156 serde::Serialize,
157 serde::Deserialize,
158)]
159#[sqlx(transparent)]
160pub struct ExperienceId(pub i64);
161
162impl std::fmt::Display for ExperienceId {
163 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
164 write!(f, "{}", self.0)
165 }
166}
167
168#[derive(
182 Debug,
183 Clone,
184 Copy,
185 PartialEq,
186 Eq,
187 PartialOrd,
188 Ord,
189 Hash,
190 sqlx::Type,
191 serde::Serialize,
192 serde::Deserialize,
193)]
194#[sqlx(transparent)]
195pub struct EntityId(pub i64);
196
197impl std::fmt::Display for EntityId {
198 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
199 write!(f, "{}", self.0)
200 }
201}
202
203#[cfg(test)]
204mod tests {
205 use super::*;
206
207 #[test]
208 fn memory_tier_round_trip() {
209 for tier in [
210 MemoryTier::Working,
211 MemoryTier::Episodic,
212 MemoryTier::Semantic,
213 MemoryTier::Persona,
214 ] {
215 let s = tier.as_str();
216 let parsed: MemoryTier = s.parse().expect("should parse");
217 assert_eq!(parsed, tier);
218 assert_eq!(format!("{tier}"), s);
219 }
220 }
221
222 #[test]
223 fn memory_tier_unknown_string_errors() {
224 assert!("unknown".parse::<MemoryTier>().is_err());
225 }
226
227 #[test]
231 fn memory_tier_display_respects_width() {
232 assert_eq!(
233 format!("{:<10}", MemoryTier::Working),
234 format!("{:<10}", "working")
235 );
236 assert_eq!(
237 format!("{:>10}", MemoryTier::Semantic),
238 format!("{:>10}", "semantic")
239 );
240 }
241
242 #[test]
243 fn memory_tier_serde_round_trip() {
244 let json = serde_json::to_string(&MemoryTier::Semantic).unwrap();
245 assert_eq!(json, "\"semantic\"");
246 let parsed: MemoryTier = serde_json::from_str(&json).unwrap();
247 assert_eq!(parsed, MemoryTier::Semantic);
248 }
249
250 #[test]
251 fn conversation_id_display() {
252 let id = ConversationId(42);
253 assert_eq!(format!("{id}"), "42");
254 }
255
256 #[test]
257 fn message_id_display() {
258 let id = MessageId(7);
259 assert_eq!(format!("{id}"), "7");
260 }
261
262 #[test]
263 fn conversation_id_eq() {
264 assert_eq!(ConversationId(1), ConversationId(1));
265 assert_ne!(ConversationId(1), ConversationId(2));
266 }
267
268 #[test]
269 fn message_id_copy() {
270 let id = MessageId(5);
271 let copied = id;
272 assert_eq!(id, copied);
273 }
274
275 #[test]
276 fn experience_id_display() {
277 let id = ExperienceId(10);
278 assert_eq!(format!("{id}"), "10");
279 }
280
281 #[test]
282 fn entity_id_display() {
283 let id = EntityId(5);
284 assert_eq!(format!("{id}"), "5");
285 }
286
287 #[test]
288 fn experience_id_ord() {
289 assert!(ExperienceId(1) < ExperienceId(2));
290 assert_eq!(ExperienceId(3), ExperienceId(3));
291 }
292
293 #[test]
294 fn entity_id_hash() {
295 use std::collections::HashSet;
296 let mut set = HashSet::new();
297 set.insert(EntityId(1));
298 set.insert(EntityId(2));
299 set.insert(EntityId(1));
300 assert_eq!(set.len(), 2);
301 }
302}