1use serde::{Deserialize, Serialize};
2
3#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
4pub struct Event {
5 pub event_id: String,
6 pub lamport: u64,
7 pub ts: String,
8 pub engine: String,
9 pub machine: String,
10 pub memory_id: String,
11 #[serde(flatten)]
12 pub kind: EventKind,
13}
14
15#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
16#[serde(tag = "kind", content = "payload")]
17pub enum EventKind {
18 MemoryAdded(MemoryData),
19 MemoryUpdated(MemoryData),
20 MemoryPatched(MemoryPatch),
21 MemoryDeleted,
22 MemoryStabilized,
23 MemoryMarkedStale {
24 reason: StaleReason,
25 },
26 MemoryReviewed,
27 RelationAsserted {
28 to_id: String,
29 relation: Relation,
30 confidence: f32,
31 reason: String,
32 judged_by: String,
33 },
34}
35
36#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
37#[serde(rename_all = "snake_case")]
38pub enum StaleReason {
39 FileGone,
40 SymbolDeleted,
41 ContentChanged,
42}
43
44#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
45#[serde(rename_all = "lowercase")]
46pub enum Scope {
47 Agent,
48 Repo,
49 Global,
50}
51
52#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
53#[serde(rename_all = "snake_case")]
54pub enum Relation {
55 ConflictsWith,
56 Supersedes,
57 Scoped,
58 Related,
59 Compatible,
60 NotConflict,
61}
62
63impl Relation {
64 pub fn as_str(&self) -> &'static str {
66 match self {
67 Relation::ConflictsWith => "conflicts_with",
68 Relation::Supersedes => "supersedes",
69 Relation::Scoped => "scoped",
70 Relation::Related => "related",
71 Relation::Compatible => "compatible",
72 Relation::NotConflict => "not_conflict",
73 }
74 }
75
76 pub fn from_label(s: &str) -> Option<Relation> {
78 match s {
79 "conflicts_with" => Some(Relation::ConflictsWith),
80 "supersedes" => Some(Relation::Supersedes),
81 "scoped" => Some(Relation::Scoped),
82 "related" => Some(Relation::Related),
83 "compatible" => Some(Relation::Compatible),
84 "not_conflict" => Some(Relation::NotConflict),
85 _ => None,
86 }
87 }
88}
89
90#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
91pub struct MemoryData {
92 pub title: String,
93 pub body: String,
94 #[serde(rename = "type")]
95 pub mem_type: String,
96 pub scope: Scope,
97 pub project: String,
98 #[serde(default)]
99 pub topic_key: Option<String>,
100 #[serde(default)]
101 pub anchors: Vec<Anchor>,
102 #[serde(default)]
103 pub tags: Vec<String>,
104}
105
106#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
112pub struct MemoryPatch {
113 #[serde(skip_serializing_if = "Option::is_none", default)]
114 pub title: Option<String>,
115 #[serde(skip_serializing_if = "Option::is_none", default)]
116 pub body: Option<String>,
117 #[serde(rename = "type", skip_serializing_if = "Option::is_none", default)]
118 pub mem_type: Option<String>,
119 #[serde(skip_serializing_if = "Option::is_none", default)]
120 pub scope: Option<Scope>,
121 #[serde(skip_serializing_if = "Option::is_none", default)]
122 pub project: Option<String>,
123 #[serde(skip_serializing_if = "Option::is_none", default)]
124 pub topic_key: Option<String>,
125 #[serde(skip_serializing_if = "Option::is_none", default)]
126 pub anchors: Option<Vec<Anchor>>,
127 #[serde(skip_serializing_if = "Option::is_none", default)]
128 pub tags: Option<Vec<String>>,
129}
130
131#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
132pub struct Anchor {
133 pub path: String,
134 #[serde(default)]
135 pub symbol: Option<String>,
136 pub line_start: u32,
137 pub line_end: u32,
138 pub content_hash: String,
139}