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 RelationAsserted {
27 to_id: String,
28 relation: Relation,
29 confidence: f32,
30 reason: String,
31 judged_by: String,
32 },
33}
34
35#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
36#[serde(rename_all = "snake_case")]
37pub enum StaleReason {
38 FileGone,
39 SymbolDeleted,
40 ContentChanged,
41}
42
43#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
44#[serde(rename_all = "lowercase")]
45pub enum Scope {
46 Agent,
47 Repo,
48}
49
50#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
51#[serde(rename_all = "snake_case")]
52pub enum Relation {
53 ConflictsWith,
54 Supersedes,
55 Scoped,
56 Related,
57 Compatible,
58 NotConflict,
59}
60
61impl Relation {
62 pub fn as_str(&self) -> &'static str {
64 match self {
65 Relation::ConflictsWith => "conflicts_with",
66 Relation::Supersedes => "supersedes",
67 Relation::Scoped => "scoped",
68 Relation::Related => "related",
69 Relation::Compatible => "compatible",
70 Relation::NotConflict => "not_conflict",
71 }
72 }
73
74 pub fn from_label(s: &str) -> Option<Relation> {
76 match s {
77 "conflicts_with" => Some(Relation::ConflictsWith),
78 "supersedes" => Some(Relation::Supersedes),
79 "scoped" => Some(Relation::Scoped),
80 "related" => Some(Relation::Related),
81 "compatible" => Some(Relation::Compatible),
82 "not_conflict" => Some(Relation::NotConflict),
83 _ => None,
84 }
85 }
86}
87
88#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
89pub struct MemoryData {
90 pub title: String,
91 pub body: String,
92 #[serde(rename = "type")]
93 pub mem_type: String,
94 pub scope: Scope,
95 pub project: String,
96 #[serde(default)]
97 pub topic_key: Option<String>,
98 #[serde(default)]
99 pub anchors: Vec<Anchor>,
100 #[serde(default)]
101 pub tags: Vec<String>,
102}
103
104#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
110pub struct MemoryPatch {
111 #[serde(skip_serializing_if = "Option::is_none", default)]
112 pub title: Option<String>,
113 #[serde(skip_serializing_if = "Option::is_none", default)]
114 pub body: Option<String>,
115 #[serde(rename = "type", skip_serializing_if = "Option::is_none", default)]
116 pub mem_type: Option<String>,
117 #[serde(skip_serializing_if = "Option::is_none", default)]
118 pub scope: Option<Scope>,
119 #[serde(skip_serializing_if = "Option::is_none", default)]
120 pub project: Option<String>,
121 #[serde(skip_serializing_if = "Option::is_none", default)]
122 pub topic_key: Option<String>,
123 #[serde(skip_serializing_if = "Option::is_none", default)]
124 pub anchors: Option<Vec<Anchor>>,
125 #[serde(skip_serializing_if = "Option::is_none", default)]
126 pub tags: Option<Vec<String>>,
127}
128
129#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
130pub struct Anchor {
131 pub path: String,
132 #[serde(default)]
133 pub symbol: Option<String>,
134 pub line_start: u32,
135 pub line_end: u32,
136 pub content_hash: String,
137}