1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
8#[serde(rename_all = "lowercase")]
9pub enum MemoryTier {
10 Working,
12 Episodic,
14 Semantic,
17 Persona,
20}
21
22impl MemoryTier {
23 #[must_use]
34 pub fn as_str(self) -> &'static str {
35 match self {
36 Self::Working => "working",
37 Self::Episodic => "episodic",
38 Self::Semantic => "semantic",
39 Self::Persona => "persona",
40 }
41 }
42}
43
44impl std::fmt::Display for MemoryTier {
45 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46 f.write_str(self.as_str())
47 }
48}
49
50impl std::str::FromStr for MemoryTier {
51 type Err = String;
52 fn from_str(s: &str) -> Result<Self, Self::Err> {
53 match s {
54 "working" => Ok(Self::Working),
55 "episodic" => Ok(Self::Episodic),
56 "semantic" => Ok(Self::Semantic),
57 "persona" => Ok(Self::Persona),
58 other => Err(format!("unknown memory tier: {other}")),
59 }
60 }
61}
62
63#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, sqlx::Type)]
77#[sqlx(transparent)]
78pub struct ConversationId(pub i64);
79
80#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, sqlx::Type)]
94#[sqlx(transparent)]
95pub struct MessageId(pub i64);
96
97#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, sqlx::Type)]
111#[sqlx(transparent)]
112pub struct MemSceneId(pub i64);
113
114impl std::fmt::Display for MemSceneId {
115 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
116 write!(f, "{}", self.0)
117 }
118}
119
120impl std::fmt::Display for ConversationId {
121 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122 write!(f, "{}", self.0)
123 }
124}
125
126impl std::fmt::Display for MessageId {
127 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
128 write!(f, "{}", self.0)
129 }
130}
131
132#[cfg(test)]
133mod tests {
134 use super::*;
135
136 #[test]
137 fn memory_tier_round_trip() {
138 for tier in [
139 MemoryTier::Working,
140 MemoryTier::Episodic,
141 MemoryTier::Semantic,
142 MemoryTier::Persona,
143 ] {
144 let s = tier.as_str();
145 let parsed: MemoryTier = s.parse().expect("should parse");
146 assert_eq!(parsed, tier);
147 assert_eq!(format!("{tier}"), s);
148 }
149 }
150
151 #[test]
152 fn memory_tier_unknown_string_errors() {
153 assert!("unknown".parse::<MemoryTier>().is_err());
154 }
155
156 #[test]
157 fn memory_tier_serde_round_trip() {
158 let json = serde_json::to_string(&MemoryTier::Semantic).unwrap();
159 assert_eq!(json, "\"semantic\"");
160 let parsed: MemoryTier = serde_json::from_str(&json).unwrap();
161 assert_eq!(parsed, MemoryTier::Semantic);
162 }
163
164 #[test]
165 fn conversation_id_display() {
166 let id = ConversationId(42);
167 assert_eq!(format!("{id}"), "42");
168 }
169
170 #[test]
171 fn message_id_display() {
172 let id = MessageId(7);
173 assert_eq!(format!("{id}"), "7");
174 }
175
176 #[test]
177 fn conversation_id_eq() {
178 assert_eq!(ConversationId(1), ConversationId(1));
179 assert_ne!(ConversationId(1), ConversationId(2));
180 }
181
182 #[test]
183 fn message_id_copy() {
184 let id = MessageId(5);
185 let copied = id;
186 assert_eq!(id, copied);
187 }
188}