1use std::collections::HashMap;
2use std::fmt;
3
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
9#[serde(rename_all = "snake_case")]
10pub enum EntityType {
11 Person,
12 Project,
13 Tool,
14 Service,
15 Preference,
16 Decision,
17 Event,
18 Concept,
19 Case,
20 Pattern,
21 Thread,
22 Thought,
23 Question,
24 Observation,
25 Policy,
26 Measurement,
27 Outcome,
28}
29
30impl EntityType {
31 pub fn is_mutable(&self) -> bool {
32 !matches!(
33 self,
34 Self::Decision
35 | Self::Event
36 | Self::Case
37 | Self::Observation
38 | Self::Measurement
39 | Self::Outcome
40 )
41 }
42}
43
44impl fmt::Display for EntityType {
45 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46 let s = serde_json::to_value(self)
47 .ok()
48 .and_then(|v| v.as_str().map(String::from))
49 .unwrap_or_else(|| format!("{:?}", self));
50 write!(f, "{}", s)
51 }
52}
53
54impl std::str::FromStr for EntityType {
55 type Err = String;
56
57 fn from_str(s: &str) -> Result<Self, Self::Err> {
58 serde_json::from_value(serde_json::Value::String(s.to_string()))
59 .map_err(|_| format!("unknown entity type: {}", s))
60 }
61}
62
63#[derive(Debug, Clone)]
65pub struct NewEntity {
66 pub name: String,
67 pub entity_type: EntityType,
68 pub abstract_text: String,
69 pub overview: Option<String>,
70 pub content: Option<String>,
71 pub attributes: Option<serde_json::Value>,
72 pub source: Option<String>,
73}
74
75#[derive(Debug, Clone, Serialize, Deserialize)]
77pub struct Entity {
78 pub id: serde_json::Value,
79 pub name: String,
80 pub entity_type: EntityType,
81 #[serde(rename = "abstract")]
82 pub abstract_text: String,
83 pub overview: String,
84 pub content: Option<String>,
85 pub attributes: Option<serde_json::Value>,
86 #[serde(default)]
87 pub embedding: Option<Vec<f32>>,
88 #[serde(default = "default_true")]
89 pub mutable: bool,
90 #[serde(default)]
91 pub access_count: i64,
92 pub created_at: serde_json::Value,
93 pub updated_at: serde_json::Value,
94 pub source: Option<String>,
95}
96
97impl Entity {
98 pub fn id_string(&self) -> String {
100 match &self.id {
101 serde_json::Value::String(s) => s.clone(),
102 other => other.to_string(),
103 }
104 }
105
106 pub fn updated_at_string(&self) -> String {
108 match &self.updated_at {
109 serde_json::Value::String(s) => s.clone(),
110 other => other.to_string(),
111 }
112 }
113}
114
115fn default_true() -> bool {
116 true
117}
118
119#[derive(Debug, Clone, Default, Serialize)]
121pub struct EntityUpdate {
122 #[serde(skip_serializing_if = "Option::is_none")]
123 pub abstract_text: Option<String>,
124 #[serde(skip_serializing_if = "Option::is_none")]
125 pub overview: Option<String>,
126 #[serde(skip_serializing_if = "Option::is_none")]
127 pub content: Option<String>,
128 #[serde(skip_serializing_if = "Option::is_none")]
129 pub attributes: Option<serde_json::Value>,
130}
131
132#[derive(Debug, Clone)]
134pub struct NewRelationship {
135 pub from_entity: String,
136 pub to_entity: String,
137 pub rel_type: String,
138 pub description: Option<String>,
139 pub confidence: Option<f32>,
140 pub source: Option<String>,
141}
142
143#[derive(Debug, Clone, Serialize, Deserialize)]
145pub struct Relationship {
146 pub id: serde_json::Value,
147 #[serde(rename = "in")]
148 pub from_id: serde_json::Value,
149 #[serde(rename = "out")]
150 pub to_id: serde_json::Value,
151 pub rel_type: String,
152 pub description: Option<String>,
153 pub valid_from: serde_json::Value,
154 pub valid_until: Option<serde_json::Value>,
155 pub confidence: f64,
156 pub source: Option<String>,
157}
158
159impl Relationship {
160 pub fn id_string(&self) -> String {
162 match &self.id {
163 serde_json::Value::String(s) => s.clone(),
164 other => other.to_string(),
165 }
166 }
167}
168
169#[derive(Debug, Clone, Copy)]
171pub enum Direction {
172 Outgoing,
173 Incoming,
174 Both,
175}
176
177#[derive(Debug, Clone, Serialize, Deserialize)]
181pub struct EntitySummary {
182 pub id: serde_json::Value,
183 pub name: String,
184 pub entity_type: EntityType,
185 #[serde(rename = "abstract")]
186 pub abstract_text: String,
187}
188
189impl EntitySummary {
190 pub fn id_string(&self) -> String {
191 match &self.id {
192 serde_json::Value::String(s) => s.clone(),
193 other => other.to_string(),
194 }
195 }
196}
197
198#[derive(Debug, Clone, Serialize, Deserialize)]
200pub struct EntityDetail {
201 pub id: serde_json::Value,
202 pub name: String,
203 pub entity_type: EntityType,
204 #[serde(rename = "abstract")]
205 pub abstract_text: String,
206 pub overview: String,
207 pub attributes: Option<serde_json::Value>,
208 #[serde(default)]
209 pub access_count: i64,
210 pub updated_at: serde_json::Value,
211 pub source: Option<String>,
212}
213
214impl EntityDetail {
215 pub fn id_string(&self) -> String {
216 match &self.id {
217 serde_json::Value::String(s) => s.clone(),
218 other => other.to_string(),
219 }
220 }
221
222 pub fn updated_at_string(&self) -> String {
223 match &self.updated_at {
224 serde_json::Value::String(s) => s.clone(),
225 other => other.to_string(),
226 }
227 }
228}
229
230#[derive(Debug, Clone, Default)]
234pub struct SearchOptions {
235 pub limit: usize,
236 pub entity_type: Option<String>,
237 pub keyword: Option<String>,
238}
239
240#[derive(Debug, Clone)]
242pub enum MatchSource {
243 Semantic,
245 Graph { parent: String, rel_type: String },
247 Keyword,
249}
250
251#[derive(Debug, Clone)]
253pub struct ScoredEntity {
254 pub entity: EntityDetail,
255 pub score: f64,
256 pub source: MatchSource,
257}
258
259#[derive(Debug, Clone)]
261pub struct EpisodeSearchResult {
262 pub episode: Episode,
263 pub score: f64,
264 pub distance: f64,
265}
266
267#[derive(Debug, Clone)]
269pub struct QueryOptions {
270 pub limit: usize,
271 pub entity_type: Option<String>,
272 pub keyword: Option<String>,
273 pub graph_depth: u32,
274 pub include_episodes: bool,
275}
276
277impl Default for QueryOptions {
278 fn default() -> Self {
279 Self {
280 limit: 10,
281 entity_type: None,
282 keyword: None,
283 graph_depth: 1,
284 include_episodes: false,
285 }
286 }
287}
288
289#[derive(Debug, Clone)]
291pub struct QueryResult {
292 pub entities: Vec<ScoredEntity>,
293 pub episodes: Vec<EpisodeSearchResult>,
294}
295
296#[derive(Debug, Clone)]
298pub struct SearchResult {
299 pub entity: Entity,
300 pub score: f64,
301 pub distance: f64,
302}
303
304#[derive(Debug, Clone)]
306pub struct TraversalNode {
307 pub entity: EntitySummary,
308 pub edges: Vec<TraversalEdge>,
309}
310
311#[derive(Debug, Clone)]
313pub struct TraversalEdge {
314 pub rel_type: String,
315 pub direction: String,
316 pub target: TraversalNode,
317 pub valid_from: serde_json::Value,
318 pub valid_until: Option<serde_json::Value>,
319 pub confidence: f64,
320}
321
322#[derive(Debug, Clone, serde::Deserialize)]
324pub struct EdgeRow {
325 pub rel_type: String,
326 pub valid_from: serde_json::Value,
327 pub valid_until: Option<serde_json::Value>,
328 pub target_id: serde_json::Value,
329 #[serde(default = "default_confidence")]
330 pub confidence: f64,
331}
332
333fn default_confidence() -> f64 {
334 1.0
335}
336
337impl EdgeRow {
338 pub fn target_id_string(&self) -> String {
339 match &self.target_id {
340 serde_json::Value::String(s) => s.clone(),
341 other => other.to_string(),
342 }
343 }
344}
345
346#[derive(Debug, Clone)]
348pub struct GraphStats {
349 pub entity_count: u64,
350 pub relationship_count: u64,
351 pub episode_count: u64,
352 pub entity_type_counts: HashMap<String, u64>,
353}
354
355#[derive(Debug, Clone)]
359pub struct NewEpisode {
360 pub session_id: String,
361 pub abstract_text: String,
362 pub overview: Option<String>,
363 pub content: Option<String>,
364 pub log_number: Option<u32>,
365}
366
367#[derive(Debug, Clone, Serialize, Deserialize)]
369pub struct Episode {
370 pub id: serde_json::Value,
371 pub session_id: String,
372 pub timestamp: serde_json::Value,
373 #[serde(rename = "abstract")]
374 pub abstract_text: String,
375 pub overview: Option<String>,
376 pub content: Option<String>,
377 #[serde(default)]
378 pub embedding: Option<Vec<f32>>,
379 pub log_number: Option<i64>,
380}
381
382impl Episode {
383 pub fn id_string(&self) -> String {
384 match &self.id {
385 serde_json::Value::String(s) => s.clone(),
386 other => other.to_string(),
387 }
388 }
389}
390
391#[derive(Debug, Clone, Serialize, Deserialize)]
393pub struct ExtractedEntity {
394 pub name: String,
395 #[serde(rename = "type")]
396 pub entity_type: EntityType,
397 #[serde(rename = "abstract")]
398 pub abstract_text: String,
399 pub overview: Option<String>,
400 pub content: Option<String>,
401 pub attributes: Option<serde_json::Value>,
402}
403
404#[derive(Debug, Clone, Serialize, Deserialize)]
406pub struct ExtractedRelationship {
407 pub source: String,
408 pub target: String,
409 pub rel_type: String,
410 pub description: Option<String>,
411 #[serde(default)]
412 pub confidence: Option<String>,
413}
414
415#[derive(Debug, Clone, Serialize, Deserialize)]
417pub struct ExtractedCase {
418 pub problem: String,
419 pub solution: String,
420 pub context: Option<String>,
421}
422
423#[derive(Debug, Clone, Serialize, Deserialize)]
425pub struct ExtractedPattern {
426 pub name: String,
427 pub process: String,
428 pub conditions: Option<String>,
429}
430
431#[derive(Debug, Clone, Serialize, Deserialize)]
433pub struct ExtractedPreference {
434 pub facet: String,
435 pub value: String,
436 pub context: Option<String>,
437}
438
439#[derive(Debug, Clone, Serialize, Deserialize, Default)]
441pub struct ExtractionResult {
442 #[serde(default)]
443 pub entities: Vec<ExtractedEntity>,
444 #[serde(default)]
445 pub relationships: Vec<ExtractedRelationship>,
446 #[serde(default)]
447 pub cases: Vec<ExtractedCase>,
448 #[serde(default)]
449 pub patterns: Vec<ExtractedPattern>,
450 #[serde(default)]
451 pub preferences: Vec<ExtractedPreference>,
452}
453
454#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
456#[serde(rename_all = "snake_case")]
457pub enum DedupDecision {
458 Skip,
459 Create,
460 Merge { target: String },
461}
462
463pub mod pipeline_rels {
467 pub const EVOLVED_FROM: &str = "EVOLVED_FROM";
468 pub const CRYSTALLIZED_FROM: &str = "CRYSTALLIZED_FROM";
469 pub const INFORMED_BY: &str = "INFORMED_BY";
470 pub const EXPLORES: &str = "EXPLORES";
471 pub const GRADUATED_TO: &str = "GRADUATED_TO";
472 pub const ARCHIVED_FROM: &str = "ARCHIVED_FROM";
473 pub const CONNECTED_TO: &str = "CONNECTED_TO";
474}
475
476pub mod vigil_rels {
478 pub const MEASURED_DURING: &str = "MEASURED_DURING";
479 pub const RESULTED_IN: &str = "RESULTED_IN";
480 pub const TRIGGERED_BY: &str = "TRIGGERED_BY";
481}
482
483#[derive(Debug, Clone, Default)]
485pub struct VigilSyncReport {
486 pub measurements_created: u32,
487 pub outcomes_created: u32,
488 pub events_created: u32,
489 pub relationships_created: u32,
490 pub skipped: u32,
491 pub errors: Vec<String>,
492}
493
494#[derive(Debug, Clone, Default)]
496pub struct PipelineDocuments {
497 pub learning: String,
498 pub thoughts: String,
499 pub curiosity: String,
500 pub reflections: String,
501 pub praxis: String,
502}
503
504#[derive(Debug, Clone, Default)]
506pub struct PipelineSyncReport {
507 pub entities_created: u32,
508 pub entities_updated: u32,
509 pub entities_archived: u32,
510 pub relationships_created: u32,
511 pub relationships_skipped: u32,
512 pub errors: Vec<String>,
513}
514
515#[derive(Debug, Clone, Default)]
517pub struct PipelineGraphStats {
518 pub by_stage: HashMap<String, HashMap<String, u64>>,
519 pub stale_thoughts: Vec<EntityDetail>,
520 pub stale_questions: Vec<EntityDetail>,
521 pub total_entities: u64,
522 pub last_movement: Option<String>,
523}
524
525#[derive(Debug, Clone)]
527pub struct PipelineEntry {
528 pub title: String,
530 pub body: String,
532 pub status: String,
534 pub stage: String,
536 pub entity_type: EntityType,
538 pub date: Option<String>,
540 pub source_ref: Option<String>,
542 pub destination: Option<String>,
544 pub connected_to: Vec<String>,
546 pub sub_type: Option<String>,
548}
549
550#[derive(Debug, Clone, Default)]
552pub struct IngestionReport {
553 pub episodes_created: u32,
554 pub entities_created: u32,
555 pub entities_merged: u32,
556 pub entities_skipped: u32,
557 pub relationships_created: u32,
558 pub relationships_skipped: u32,
559 pub errors: Vec<String>,
560}