1use serde::{Deserialize, Serialize};
7use uuid::Uuid;
8
9use meerkat_core::types::SessionId;
10
11#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
13pub struct RuntimeEventId(pub Uuid);
14
15impl RuntimeEventId {
16 pub fn new() -> Self {
17 Self(meerkat_core::time_compat::new_uuid_v7())
18 }
19}
20
21impl Default for RuntimeEventId {
22 fn default() -> Self {
23 Self::new()
24 }
25}
26
27impl std::fmt::Display for RuntimeEventId {
28 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29 write!(f, "{}", self.0)
30 }
31}
32
33#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
35pub struct LogicalRuntimeId(pub String);
36
37impl LogicalRuntimeId {
38 const SESSION_RUNTIME_PREFIX: &'static str = "rt:session:";
39
40 pub fn new(id: impl Into<String>) -> Self {
41 Self(id.into())
42 }
43
44 pub fn for_session(session_id: &SessionId) -> Self {
45 Self(format!("{}{session_id}", Self::SESSION_RUNTIME_PREFIX))
46 }
47
48 pub fn legacy_session_uuid_alias(session_id: &SessionId) -> Self {
49 Self(session_id.to_string())
50 }
51
52 pub(crate) fn session_id(&self) -> Option<SessionId> {
53 let raw = self
54 .0
55 .strip_prefix(Self::SESSION_RUNTIME_PREFIX)
56 .unwrap_or(self.0.as_str());
57 SessionId::parse(raw).ok()
58 }
59}
60
61impl std::fmt::Display for LogicalRuntimeId {
62 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63 write!(f, "{}", self.0)
64 }
65}
66
67#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
69pub struct ConversationId(pub Uuid);
70
71impl ConversationId {
72 pub fn new() -> Self {
73 Self(meerkat_core::time_compat::new_uuid_v7())
74 }
75}
76
77impl Default for ConversationId {
78 fn default() -> Self {
79 Self::new()
80 }
81}
82
83impl std::fmt::Display for ConversationId {
84 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85 write!(f, "{}", self.0)
86 }
87}
88
89#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
91pub struct CausationId(pub Uuid);
92
93impl Default for CausationId {
94 fn default() -> Self {
95 Self::new()
96 }
97}
98
99impl CausationId {
100 pub fn new() -> Self {
101 Self(meerkat_core::time_compat::new_uuid_v7())
102 }
103
104 pub fn from_uuid(uuid: Uuid) -> Self {
105 Self(uuid)
106 }
107}
108
109impl std::fmt::Display for CausationId {
110 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111 write!(f, "{}", self.0)
112 }
113}
114
115#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
117pub struct CorrelationId(pub Uuid);
118
119impl Default for CorrelationId {
120 fn default() -> Self {
121 Self::new()
122 }
123}
124
125impl CorrelationId {
126 pub fn new() -> Self {
127 Self(meerkat_core::time_compat::new_uuid_v7())
128 }
129
130 pub fn from_uuid(uuid: Uuid) -> Self {
131 Self(uuid)
132 }
133}
134
135impl std::fmt::Display for CorrelationId {
136 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
137 write!(f, "{}", self.0)
138 }
139}
140
141#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
143pub struct IdempotencyKey(pub String);
144
145impl IdempotencyKey {
146 pub fn new(key: impl Into<String>) -> Self {
147 Self(key.into())
148 }
149}
150
151impl std::fmt::Display for IdempotencyKey {
152 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
153 write!(f, "{}", self.0)
154 }
155}
156
157#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
159pub struct SupersessionKey(pub String);
160
161impl SupersessionKey {
162 pub fn new(key: impl Into<String>) -> Self {
163 Self(key.into())
164 }
165}
166
167impl std::fmt::Display for SupersessionKey {
168 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
169 write!(f, "{}", self.0)
170 }
171}
172
173#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
175pub struct PolicyVersion(pub u64);
176
177impl std::fmt::Display for PolicyVersion {
178 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
179 write!(f, "{}", self.0)
180 }
181}
182
183#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
189#[serde(rename_all = "snake_case")]
190#[non_exhaustive]
191pub enum InputKind {
192 Prompt,
194 PeerMessage,
196 PeerRequest,
198 PeerResponseProgress,
200 PeerResponseTerminal,
202 FlowStep,
204 ExternalEvent,
206 Continuation,
208 Operation,
210}
211
212impl InputKind {
213 pub fn as_str(self) -> &'static str {
216 match self {
217 InputKind::Prompt => "prompt",
218 InputKind::PeerMessage => "peer_message",
219 InputKind::PeerRequest => "peer_request",
220 InputKind::PeerResponseProgress => "peer_response_progress",
221 InputKind::PeerResponseTerminal => "peer_response_terminal",
222 InputKind::FlowStep => "flow_step",
223 InputKind::ExternalEvent => "external_event",
224 InputKind::Continuation => "continuation",
225 InputKind::Operation => "operation",
226 }
227 }
228}
229
230impl std::fmt::Display for InputKind {
231 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
232 f.write_str(self.as_str())
233 }
234}
235
236#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
238pub struct KindId(pub InputKind);
239
240impl KindId {
241 pub const fn new(kind: InputKind) -> Self {
242 Self(kind)
243 }
244
245 pub const fn kind(self) -> InputKind {
246 self.0
247 }
248}
249
250impl From<InputKind> for KindId {
251 fn from(kind: InputKind) -> Self {
252 Self(kind)
253 }
254}
255
256impl std::fmt::Display for KindId {
257 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
258 std::fmt::Display::fmt(&self.0, f)
259 }
260}
261
262#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
264pub struct SchemaId(pub String);
265
266impl SchemaId {
267 pub fn new(id: impl Into<String>) -> Self {
268 Self(id.into())
269 }
270}
271
272impl std::fmt::Display for SchemaId {
273 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
274 write!(f, "{}", self.0)
275 }
276}
277
278#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
280pub struct ProjectionRuleId(pub String);
281
282impl ProjectionRuleId {
283 pub fn new(id: impl Into<String>) -> Self {
284 Self(id.into())
285 }
286}
287
288impl std::fmt::Display for ProjectionRuleId {
289 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
290 write!(f, "{}", self.0)
291 }
292}
293
294#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
296pub struct EventCodeId(pub String);
297
298impl EventCodeId {
299 pub fn new(id: impl Into<String>) -> Self {
300 Self(id.into())
301 }
302}
303
304impl std::fmt::Display for EventCodeId {
305 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
306 write!(f, "{}", self.0)
307 }
308}
309
310#[cfg(test)]
311#[allow(clippy::unwrap_used)]
312mod tests {
313 use super::*;
314
315 #[test]
316 fn runtime_event_id_unique() {
317 let a = RuntimeEventId::new();
318 let b = RuntimeEventId::new();
319 assert_ne!(a, b);
320 }
321
322 #[test]
323 fn runtime_event_id_serde() {
324 let id = RuntimeEventId::new();
325 let json = serde_json::to_string(&id).unwrap();
326 let parsed: RuntimeEventId = serde_json::from_str(&json).unwrap();
327 assert_eq!(id, parsed);
328 }
329
330 #[test]
331 fn logical_runtime_id_serde() {
332 let id = LogicalRuntimeId::new("agent-1");
333 let json = serde_json::to_string(&id).unwrap();
334 let parsed: LogicalRuntimeId = serde_json::from_str(&json).unwrap();
335 assert_eq!(id, parsed);
336 assert_eq!(id.to_string(), "agent-1");
337 }
338
339 #[test]
340 fn conversation_id_unique() {
341 let a = ConversationId::new();
342 let b = ConversationId::new();
343 assert_ne!(a, b);
344 }
345
346 #[test]
347 fn idempotency_key_serde() {
348 let key = IdempotencyKey::new("req-abc-123");
349 let json = serde_json::to_string(&key).unwrap();
350 let parsed: IdempotencyKey = serde_json::from_str(&json).unwrap();
351 assert_eq!(key, parsed);
352 }
353
354 #[test]
355 fn supersession_key_serde() {
356 let key = SupersessionKey::new("peer-status");
357 let json = serde_json::to_string(&key).unwrap();
358 let parsed: SupersessionKey = serde_json::from_str(&json).unwrap();
359 assert_eq!(key, parsed);
360 }
361
362 #[test]
363 fn policy_version_serde() {
364 let v = PolicyVersion(42);
365 let json = serde_json::to_string(&v).unwrap();
366 let parsed: PolicyVersion = serde_json::from_str(&json).unwrap();
367 assert_eq!(v, parsed);
368 }
369
370 #[test]
371 fn kind_id_display() {
372 let id = KindId::new(InputKind::Prompt);
373 assert_eq!(id.to_string(), "prompt");
374 assert_eq!(
375 KindId::new(InputKind::PeerResponseProgress).to_string(),
376 "peer_response_progress"
377 );
378 }
379
380 #[test]
381 fn kind_id_serde_roundtrips_typed_variant() {
382 let id = KindId::new(InputKind::PeerResponseTerminal);
383 let json = serde_json::to_string(&id).unwrap();
384 let parsed: KindId = serde_json::from_str(&json).unwrap();
385 assert_eq!(id, parsed);
386 }
387}