1use serde::{Deserialize, Serialize};
2use serde_json::{Map, Value};
3use std::fmt;
4
5pub type Metadata = Map<String, Value>;
6pub fn default_namespace() -> String { "default".into() }
7pub fn public_scope() -> String { "public".into() }
8pub fn default_limit() -> usize { 50 }
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
11#[serde(rename_all = "snake_case")]
12pub enum RecordKind { Memory, Entity, Relation, Event, Note, Chunk }
13
14impl RecordKind {
15 pub fn as_str(self) -> &'static str {
16 match self {
17 Self::Memory => "memory", Self::Entity => "entity", Self::Relation => "relation",
18 Self::Event => "event", Self::Note => "note", Self::Chunk => "chunk",
19 }
20 }
21 pub fn code(self) -> i64 {
23 match self {
24 Self::Memory => 0, Self::Entity => 1, Self::Relation => 2,
25 Self::Event => 3, Self::Note => 4, Self::Chunk => 5,
26 }
27 }
28 pub fn from_code(code: i64) -> Option<Self> {
29 Some(match code {
30 0 => Self::Memory, 1 => Self::Entity, 2 => Self::Relation,
31 3 => Self::Event, 4 => Self::Note, 5 => Self::Chunk, _ => return None,
32 })
33 }
34}
35
36impl fmt::Display for RecordKind {
37 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(self.as_str()) }
38}
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
42pub struct RecordKey {
43 pub id: i64,
44}
45
46impl RecordKey {
47 pub fn new(id: i64) -> Self { Self { id } }
48 pub(crate) fn index_key(&self) -> String { self.id.to_string() }
49}
50
51#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
53pub struct Evidence {
54 pub source: String,
55 #[serde(default)]
56 pub source_revision: Option<String>,
57 #[serde(default)]
58 pub chunk_id: Option<i64>,
59 #[serde(default)]
61 pub offset: Option<usize>,
62 #[serde(default)]
63 pub limit: Option<usize>,
64 #[serde(default)]
65 pub quote: String,
66 #[serde(default)]
67 pub metadata: Metadata,
68}
69
70#[derive(Debug, Clone, Serialize, Deserialize)]
71pub struct RecordInput {
72 #[serde(default)]
74 pub id: Option<i64>,
75 #[serde(default = "default_namespace")]
76 pub namespace: String,
77 #[serde(default = "public_scope")]
78 pub scope: String,
79 #[serde(default)]
80 pub tags: Vec<String>,
81 #[serde(default)]
82 pub evidence: Vec<Evidence>,
83 #[serde(default)]
84 pub metadata: Metadata,
85 #[serde(default)]
86 pub created_at_us: Option<i64>,
87 #[serde(default)]
88 pub updated_at_us: Option<i64>,
89 #[serde(default)]
90 pub expected_revision: Option<i64>,
91}
92
93impl Default for RecordInput {
94 fn default() -> Self {
95 Self { id: None, namespace: default_namespace(), scope: public_scope(), tags: vec![],
96 evidence: vec![], metadata: Metadata::new(), created_at_us: None,
97 updated_at_us: None, expected_revision: None }
98 }
99}
100
101#[derive(Debug, Clone, Serialize, Deserialize)]
102pub struct RecordHeader {
103 pub id: i64,
104 pub namespace: String,
105 pub kind: RecordKind,
106 pub scope: String,
107 pub tags: Vec<String>,
108 pub evidence: Vec<Evidence>,
109 pub metadata: Metadata,
110 pub created_at_us: i64,
111 pub updated_at_us: i64,
112 pub revision: i64,
113}
114
115impl RecordHeader {
116 pub fn key(&self) -> RecordKey { RecordKey { id: self.id } }
117 pub fn as_input(&self) -> RecordInput {
118 RecordInput { id: Some(self.id), namespace: self.namespace.clone(), scope: self.scope.clone(), tags: self.tags.clone(),
119 evidence: self.evidence.clone(), metadata: self.metadata.clone(), created_at_us: Some(self.created_at_us),
120 updated_at_us: None, expected_revision: Some(self.revision) }
121 }
122}
123
124#[derive(Debug, Clone, Serialize, Deserialize)]
125pub struct ReadFilter {
126 #[serde(default = "default_namespace")]
127 pub namespace: String,
128 #[serde(default = "default_scopes")]
129 pub scopes: Vec<String>,
130 #[serde(default)]
132 pub tags: Vec<String>,
133}
134
135fn default_scopes() -> Vec<String> { vec![public_scope()] }
136impl Default for ReadFilter {
137 fn default() -> Self { Self { namespace: default_namespace(), scopes: default_scopes(), tags: vec![] } }
138}
139
140#[derive(Debug, Clone, Serialize, Deserialize)]
141pub struct PageRequest {
142 #[serde(default)]
143 pub filter: ReadFilter,
144 #[serde(default = "default_limit")]
145 pub limit: usize,
146 #[serde(default)]
147 pub after: Option<String>,
148}
149
150impl Default for PageRequest {
151 fn default() -> Self { Self { filter: ReadFilter::default(), limit: default_limit(), after: None } }
152}
153
154#[derive(Debug, Clone, Serialize, Deserialize)]
155pub struct Page<T> { pub items: Vec<T>, pub next_cursor: Option<String> }
156
157#[derive(Debug, Clone, Serialize, Deserialize)]
160pub struct WriteReceipt<T> {
161 pub value: T,
162 pub revision: i64,
163}
164
165#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
167#[serde(rename_all = "snake_case")]
168pub enum Degrade {
169 NamespaceDisabled,
171 NoEmbedder,
173 EmbedFailed,
175 VectorNotReady,
177 RerankFailed,
179 TextIndexUnavailable,
181}
182
183#[derive(Debug, Clone, Default, Serialize, Deserialize)]
185pub struct SearchDiagnostics {
186 pub text_used: bool,
187 pub vector_used: bool,
188 pub reranked: bool,
189 pub rerank_candidates: usize,
191 pub rerank_truncated: usize,
193 #[serde(default)]
194 pub degraded: Vec<Degrade>,
195}
196
197#[derive(Debug, Clone, Serialize, Deserialize)]
198pub struct HealthReport {
199 pub schema_version: i64,
200 pub revision: i64,
201 pub indexed_revision: i64,
202 pub record_count: usize,
203 pub index_document_count: usize,
204 pub pending_index_updates: usize,
205 pub sqlite_integrity: String,
206 pub foreign_key_errors: usize,
207 pub counts: std::collections::BTreeMap<String, usize>,
208 pub embedder_spaces: Vec<String>,
210 pub reranker_registered: bool,
211 pub last_degraded: Vec<Degrade>,
213}
214
215#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
218#[serde(rename_all = "snake_case")]
219pub enum MatchField {
220 #[default]
222 All,
223 Text,
225 Name,
227 Path,
229}
230
231#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
234pub struct RebuildProgressReport {
235 pub active: bool,
236 pub processed: u64,
237 pub total: u64,
238}