1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3
4pub trait Embedder: Send + Sync {
9 fn embed(&self, text: &str) -> std::result::Result<Vec<f32>, Box<dyn std::error::Error + Send + Sync>>;
11
12 fn embed_batch(&self, texts: &[&str]) -> std::result::Result<Vec<Vec<f32>>, Box<dyn std::error::Error + Send + Sync>> {
14 texts.iter().map(|t| self.embed(t)).collect()
15 }
16
17 fn dim(&self) -> usize;
19}
20
21#[derive(Debug, Clone, Serialize, Deserialize)]
23pub struct Memory {
24 pub rid: String,
25 pub memory_type: String,
26 pub text: String,
27 pub created_at: f64,
28 pub importance: f64,
29 pub valence: f64,
30 pub half_life: f64,
31 pub last_access: f64,
32 pub access_count: u32,
33 pub consolidation_status: String,
34 pub storage_tier: String,
35 pub consolidated_into: Option<String>,
36 pub metadata: serde_json::Value,
37 pub namespace: String,
38 pub certainty: f64,
40 pub domain: String,
41 pub source: String,
42 pub emotional_state: Option<String>,
43 pub session_id: Option<String>,
45 pub due_at: Option<f64>,
46 pub temporal_kind: Option<String>,
47}
48
49#[derive(Debug, Clone, Serialize, Deserialize)]
51pub struct ScoreBreakdown {
52 pub similarity: f64,
53 pub decay: f64,
54 pub recency: f64,
55 pub importance: f64,
56 pub graph_proximity: f64,
57 pub contributions: ScoreContributions,
59 pub valence_multiplier: f64,
61}
62
63#[derive(Debug, Clone, Serialize, Deserialize)]
65pub struct ScoreContributions {
66 pub similarity: f64,
67 pub decay: f64,
68 pub recency: f64,
69 pub importance: f64,
70 pub graph_proximity: f64,
71}
72
73#[derive(Debug, Clone, Serialize, Deserialize)]
75pub struct RecallResult {
76 pub rid: String,
77 pub memory_type: String,
78 pub text: String,
79 pub created_at: f64,
80 pub importance: f64,
81 pub valence: f64,
82 pub score: f64,
83 pub scores: ScoreBreakdown,
84 pub why_retrieved: Vec<String>,
85 pub metadata: serde_json::Value,
86 pub namespace: String,
87 pub certainty: f64,
89 pub domain: String,
90 pub source: String,
91 pub emotional_state: Option<String>,
92}
93
94#[derive(Debug, Clone, Serialize, Deserialize)]
96pub struct RecallResponse {
97 pub results: Vec<RecallResult>,
98 pub confidence: f64,
99 pub certainty_reasons: Vec<String>,
101 pub retrieval_summary: RetrievalSummary,
102 pub hints: Vec<RefinementHint>,
103}
104
105#[derive(Debug, Clone, Serialize, Deserialize)]
107pub struct RetrievalSummary {
108 pub top_similarity: f64,
109 pub score_spread: f64,
110 pub sources_used: Vec<String>,
111 pub candidate_count: usize,
112}
113
114#[derive(Debug, Clone, Serialize, Deserialize)]
116pub struct RefinementHint {
117 pub hint_type: String,
118 pub suggestion: String,
119 pub related_entities: Vec<String>,
120}
121
122#[derive(Debug, Clone, Serialize, Deserialize)]
124pub struct Edge {
125 pub edge_id: String,
126 pub src: String,
127 pub dst: String,
128 pub rel_type: String,
129 pub weight: f64,
130}
131
132#[derive(Debug, Clone, Serialize, Deserialize)]
134pub struct Entity {
135 pub name: String,
136 pub entity_type: String,
137 pub first_seen: f64,
138 pub last_seen: f64,
139 pub mention_count: i64,
140}
141
142#[derive(Debug, Clone, Serialize, Deserialize)]
144pub struct Stats {
145 pub active_memories: i64,
146 pub consolidated_memories: i64,
147 pub tombstoned_memories: i64,
148 pub archived_memories: i64,
149 pub edges: i64,
150 pub entities: i64,
151 pub operations: i64,
152 pub open_conflicts: i64,
153 pub resolved_conflicts: i64,
154 pub pending_triggers: i64,
155 pub active_patterns: i64,
156 pub scoring_cache_entries: usize,
157 pub vec_index_entries: usize,
158 pub graph_index_entities: usize,
159 pub graph_index_edges: usize,
160}
161
162#[derive(Debug, Clone, Serialize, Deserialize)]
164pub struct Trigger {
165 pub trigger_type: String,
166 pub reason: String,
167 pub urgency: f64,
168 pub source_rids: Vec<String>,
169 pub suggested_action: String,
170 pub context: HashMap<String, serde_json::Value>,
171}
172
173#[derive(Debug, Clone, Serialize, Deserialize)]
175pub struct ConsolidationResult {
176 pub consolidated_rid: String,
177 pub source_rids: Vec<String>,
178 pub cluster_size: usize,
179 pub summary: String,
180 pub importance: f64,
181 pub entities_linked: usize,
182}
183
184#[derive(Debug, Clone, Serialize, Deserialize)]
186pub struct ConsolidationPreview {
187 pub cluster_size: usize,
188 pub texts: Vec<String>,
189 pub preview_summary: String,
190 pub source_rids: Vec<String>,
191}
192
193#[derive(Debug, Clone)]
195pub struct MemoryWithEmbedding {
196 pub rid: String,
197 pub memory_type: String,
198 pub text: String,
199 pub embedding: Vec<f32>,
200 pub created_at: f64,
201 pub importance: f64,
202 pub valence: f64,
203 pub half_life: f64,
204 pub last_access: f64,
205 pub metadata: serde_json::Value,
206 pub namespace: String,
207}
208
209#[derive(Debug, Clone, Serialize, Deserialize)]
211pub struct DecayedMemory {
212 pub rid: String,
213 pub text: String,
214 pub memory_type: String,
215 pub original_importance: f64,
216 pub current_score: f64,
217 pub days_since_access: f64,
218}
219
220#[derive(Debug, Clone)]
223pub struct ScoringRow {
224 pub created_at: f64,
225 pub importance: f64,
226 pub half_life: f64,
227 pub last_access: f64,
228 pub access_count: u32,
229 pub valence: f64,
230 pub consolidation_status: String,
231 pub memory_type: String,
232 pub namespace: String,
233 pub certainty: f64,
235 pub domain: String,
236 pub source: String,
237 pub emotional_state: Option<String>,
238}
239
240#[derive(Debug, Clone)]
242pub struct RecordInput {
243 pub text: String,
244 pub memory_type: String,
245 pub importance: f64,
246 pub valence: f64,
247 pub half_life: f64,
248 pub metadata: serde_json::Value,
249 pub embedding: Vec<f32>,
250 pub namespace: String,
251 pub certainty: f64,
253 pub domain: String,
254 pub source: String,
255 pub emotional_state: Option<String>,
256}
257
258#[derive(Debug, Clone, PartialEq)]
262pub enum ConflictType {
263 IdentityFact,
264 Preference,
265 Temporal,
266 Consolidation,
267 Minor,
268}
269
270impl ConflictType {
271 pub fn as_str(&self) -> &'static str {
272 match self {
273 ConflictType::IdentityFact => "identity_fact",
274 ConflictType::Preference => "preference",
275 ConflictType::Temporal => "temporal",
276 ConflictType::Consolidation => "consolidation",
277 ConflictType::Minor => "minor",
278 }
279 }
280
281 pub fn from_str(s: &str) -> Self {
282 match s {
283 "identity_fact" => ConflictType::IdentityFact,
284 "preference" => ConflictType::Preference,
285 "temporal" => ConflictType::Temporal,
286 "consolidation" => ConflictType::Consolidation,
287 _ => ConflictType::Minor,
288 }
289 }
290
291 pub fn default_priority(&self) -> &'static str {
292 match self {
293 ConflictType::IdentityFact => "critical",
294 ConflictType::Preference => "high",
295 ConflictType::Temporal => "high",
296 ConflictType::Consolidation => "medium",
297 ConflictType::Minor => "low",
298 }
299 }
300}
301
302#[derive(Debug, Clone, Serialize, Deserialize)]
304pub struct Conflict {
305 pub conflict_id: String,
306 pub conflict_type: String,
307 pub priority: String,
308 pub status: String,
309 pub memory_a: String,
310 pub memory_b: String,
311 pub entity: Option<String>,
312 pub rel_type: Option<String>,
313 pub detected_at: f64,
314 pub detected_by: String,
315 pub detection_reason: String,
316 pub resolved_at: Option<f64>,
317 pub resolved_by: Option<String>,
318 pub strategy: Option<String>,
319 pub winner_rid: Option<String>,
320 pub resolution_note: Option<String>,
321}
322
323#[derive(Debug, Clone, Serialize, Deserialize)]
325pub struct ConflictResolutionResult {
326 pub conflict_id: String,
327 pub strategy: String,
328 pub winner_rid: Option<String>,
329 pub loser_tombstoned: bool,
330 pub new_memory_rid: Option<String>,
331}
332
333#[derive(Debug, Clone, Serialize, Deserialize)]
335pub struct CorrectionResult {
336 pub original_rid: String,
337 pub corrected_rid: String,
338 pub original_tombstoned: bool,
339}
340
341#[derive(Debug, Clone, PartialEq)]
345pub enum TriggerType {
346 DecayReview,
347 ConsolidationReady,
348 ConflictEscalation,
349 TemporalDrift,
350 Redundancy,
351 RelationshipInsight,
352 ValenceTrend,
353 EntityAnomaly,
354 PatternDiscovered,
355}
356
357impl TriggerType {
358 pub fn as_str(&self) -> &'static str {
359 match self {
360 TriggerType::DecayReview => "decay_review",
361 TriggerType::ConsolidationReady => "consolidation_ready",
362 TriggerType::ConflictEscalation => "conflict_escalation",
363 TriggerType::TemporalDrift => "temporal_drift",
364 TriggerType::Redundancy => "redundancy",
365 TriggerType::RelationshipInsight => "relationship_insight",
366 TriggerType::ValenceTrend => "valence_trend",
367 TriggerType::EntityAnomaly => "entity_anomaly",
368 TriggerType::PatternDiscovered => "pattern_discovered",
369 }
370 }
371
372 pub fn from_str(s: &str) -> Self {
373 match s {
374 "decay_review" => TriggerType::DecayReview,
375 "consolidation_ready" => TriggerType::ConsolidationReady,
376 "conflict_escalation" => TriggerType::ConflictEscalation,
377 "temporal_drift" => TriggerType::TemporalDrift,
378 "redundancy" => TriggerType::Redundancy,
379 "relationship_insight" => TriggerType::RelationshipInsight,
380 "valence_trend" => TriggerType::ValenceTrend,
381 "entity_anomaly" => TriggerType::EntityAnomaly,
382 "pattern_discovered" => TriggerType::PatternDiscovered,
383 _ => TriggerType::DecayReview,
384 }
385 }
386
387 pub fn default_cooldown_secs(&self) -> f64 {
388 match self {
389 TriggerType::DecayReview => 86400.0 * 3.0,
390 TriggerType::ConsolidationReady => 86400.0,
391 TriggerType::ConflictEscalation => 86400.0 * 2.0,
392 TriggerType::TemporalDrift => 86400.0 * 14.0,
393 TriggerType::Redundancy => 86400.0,
394 TriggerType::RelationshipInsight => 86400.0 * 7.0,
395 TriggerType::ValenceTrend => 86400.0 * 7.0,
396 TriggerType::EntityAnomaly => 86400.0 * 7.0,
397 TriggerType::PatternDiscovered => 86400.0 * 7.0,
398 }
399 }
400
401 pub fn default_expiry_secs(&self) -> f64 {
402 match self {
403 TriggerType::DecayReview => 86400.0 * 7.0,
404 TriggerType::ConsolidationReady => 86400.0 * 3.0,
405 TriggerType::ConflictEscalation => 86400.0 * 14.0,
406 _ => 86400.0 * 7.0,
407 }
408 }
409}
410
411#[derive(Debug, Clone, Serialize, Deserialize)]
413pub struct ThinkConfig {
414 pub importance_threshold: f64,
415 pub decay_threshold: f64,
416 pub max_triggers: usize,
417 pub run_consolidation: bool,
418 pub run_conflict_scan: bool,
419 pub run_pattern_mining: bool,
420 pub consolidation_sim_threshold: f64,
421 pub consolidation_time_window_days: f64,
422 pub consolidation_min_cluster: usize,
423 pub min_active_memories: i64,
424 pub run_personality: bool,
425}
426
427impl Default for ThinkConfig {
428 fn default() -> Self {
429 Self {
430 importance_threshold: 0.5,
431 decay_threshold: 0.1,
432 max_triggers: 10,
433 run_consolidation: true,
434 run_conflict_scan: true,
435 run_pattern_mining: true,
436 consolidation_sim_threshold: 0.6,
437 consolidation_time_window_days: 7.0,
438 consolidation_min_cluster: 2,
439 min_active_memories: 10,
440 run_personality: true,
441 }
442 }
443}
444
445#[derive(Debug, Clone, Serialize, Deserialize)]
447pub struct ThinkResult {
448 pub triggers: Vec<Trigger>,
449 pub consolidation_count: usize,
450 pub conflicts_found: usize,
451 pub patterns_new: usize,
452 pub patterns_updated: usize,
453 pub expired_triggers: usize,
454 pub personality_updated: bool,
455 pub duration_ms: u64,
456}
457
458#[derive(Debug, Clone, Serialize, Deserialize)]
460pub struct PersistedTrigger {
461 pub trigger_id: String,
462 pub trigger_type: String,
463 pub urgency: f64,
464 pub status: String,
465 pub reason: String,
466 pub suggested_action: String,
467 pub source_rids: Vec<String>,
468 pub context: serde_json::Value,
469 pub created_at: f64,
470 pub delivered_at: Option<f64>,
471 pub acknowledged_at: Option<f64>,
472 pub acted_at: Option<f64>,
473 pub expires_at: Option<f64>,
474}
475
476#[derive(Debug, Clone, Serialize, Deserialize)]
478pub struct Pattern {
479 pub pattern_id: String,
480 pub pattern_type: String,
481 pub status: String,
482 pub confidence: f64,
483 pub description: String,
484 pub evidence_rids: Vec<String>,
485 pub entity_names: Vec<String>,
486 pub context: serde_json::Value,
487 pub first_seen: f64,
488 pub last_confirmed: f64,
489 pub occurrence_count: i64,
490}
491
492#[derive(Debug, Clone, Serialize, Deserialize)]
494pub struct PatternMiningResult {
495 pub new_patterns: usize,
496 pub updated_patterns: usize,
497 pub stale_patterns: usize,
498}
499
500#[derive(Debug, Clone)]
502pub struct PatternConfig {
503 pub co_occurrence_min_count: usize,
504 pub temporal_cluster_min_events: usize,
505 pub valence_trend_delta_threshold: f64,
506 pub topic_cluster_sim_threshold: f64,
507 pub topic_cluster_time_window_days: f64,
508 pub entity_hub_min_degree: usize,
509 pub max_patterns: usize,
510 pub cross_domain_candidates_per_domain: usize,
512 pub cross_domain_sim_threshold: f64,
513 pub cross_domain_max_per_pair: usize,
514 pub entity_bridge_min_domains: usize,
515 pub entity_bridge_min_mentions_per_domain: usize,
516 pub run_cross_domain: bool,
517}
518
519#[cfg(feature = "profiling")]
523#[derive(Debug, Clone)]
524pub struct RecallTimings {
525 pub vec_search_ms: f64,
526 pub cache_score_ms: f64,
527 pub fetch_ms: f64,
528 pub scoring_ms: f64,
529 pub graph_ms: f64,
530 pub reinforce_ms: f64,
531 pub sort_truncate_ms: f64,
532 pub total_ms: f64,
533 pub candidate_count: usize,
534 pub graph_expansion_count: usize,
535}
536
537#[cfg(feature = "profiling")]
539#[derive(Debug, Clone)]
540pub struct RecallProfiledResult {
541 pub results: Vec<RecallResult>,
542 pub timings: RecallTimings,
543}
544
545#[derive(Debug, Clone)]
557pub struct RecallQuery {
558 pub embedding: Vec<f32>,
559 pub top_k: usize,
560 pub time_window: Option<(f64, f64)>,
561 pub memory_type: Option<String>,
562 pub include_consolidated: bool,
563 pub expand_entities: bool,
564 pub query_text: Option<String>,
565 pub skip_reinforce: bool,
566 pub namespace: Option<String>,
567 pub domain: Option<String>,
569 pub source: Option<String>,
570}
571
572impl RecallQuery {
573 pub fn new(embedding: Vec<f32>) -> Self {
575 Self {
576 embedding,
577 top_k: 10,
578 time_window: None,
579 memory_type: None,
580 include_consolidated: false,
581 expand_entities: false,
582 query_text: None,
583 skip_reinforce: false,
584 namespace: None,
585 domain: None,
586 source: None,
587 }
588 }
589
590 pub fn top_k(mut self, k: usize) -> Self {
592 self.top_k = k;
593 self
594 }
595
596 pub fn memory_type(mut self, mt: &str) -> Self {
598 self.memory_type = Some(mt.to_string());
599 self
600 }
601
602 pub fn namespace(mut self, ns: &str) -> Self {
604 self.namespace = Some(ns.to_string());
605 self
606 }
607
608 pub fn time_window(mut self, start: f64, end: f64) -> Self {
610 self.time_window = Some((start, end));
611 self
612 }
613
614 pub fn expand_entities(mut self, query_text: &str) -> Self {
616 self.expand_entities = true;
617 self.query_text = Some(query_text.to_string());
618 self
619 }
620
621 pub fn include_consolidated(mut self) -> Self {
623 self.include_consolidated = true;
624 self
625 }
626
627 pub fn skip_reinforce(mut self) -> Self {
629 self.skip_reinforce = true;
630 self
631 }
632
633 pub fn domain(mut self, d: &str) -> Self {
635 self.domain = Some(d.to_string());
636 self
637 }
638
639 pub fn source(mut self, s: &str) -> Self {
641 self.source = Some(s.to_string());
642 self
643 }
644}
645
646#[derive(Debug, Clone, Serialize, Deserialize)]
648pub struct LearnedWeights {
649 pub w_sim: f64,
650 pub w_decay: f64,
651 pub w_recency: f64,
652 pub gate_tau: f64,
653 pub alpha_imp: f64,
654 pub keyword_boost: f64,
655 pub generation: i64,
656}
657
658impl Default for LearnedWeights {
659 fn default() -> Self {
660 Self {
661 w_sim: 0.50,
662 w_decay: 0.20,
663 w_recency: 0.30,
664 gate_tau: 0.25,
665 alpha_imp: 0.80,
666 keyword_boost: 0.31,
667 generation: 0,
668 }
669 }
670}
671
672#[derive(Debug, Clone, Serialize, Deserialize)]
676pub struct PersonalityTrait {
677 pub trait_name: String,
678 pub score: f64,
679 pub confidence: f64,
680 pub sample_count: i64,
681 pub updated_at: f64,
682}
683
684#[derive(Debug, Clone, Serialize, Deserialize)]
686pub struct PersonalityProfile {
687 pub traits: Vec<PersonalityTrait>,
688 pub updated_at: f64,
689}
690
691#[derive(Debug, Clone, Serialize, Deserialize)]
695pub struct Session {
696 pub session_id: String,
697 pub namespace: String,
698 pub client_id: String,
699 pub status: String,
700 pub started_at: f64,
701 pub ended_at: Option<f64>,
702 pub summary: Option<String>,
703 pub avg_valence: Option<f64>,
704 pub memory_count: i64,
705 pub topics: Vec<String>,
706 pub metadata: serde_json::Value,
707}
708
709#[derive(Debug, Clone, Serialize, Deserialize)]
711pub struct SessionSummary {
712 pub session_id: String,
713 pub duration_secs: f64,
714 pub memory_count: i64,
715 pub avg_valence: f64,
716 pub topics: Vec<String>,
717}
718
719#[derive(Debug, Clone, Serialize, Deserialize)]
723pub struct EntityProfile {
724 pub entity: String,
725 pub entity_type: String,
726 pub mention_count: i64,
727 pub session_count: i64,
728 pub domains: Vec<DomainCount>,
729 pub avg_valence: f64,
730 pub valence_trend: f64,
731 pub dominant_emotion: Option<String>,
732 pub interaction_frequency: f64,
733 pub last_mentioned_at: f64,
734 pub first_seen: f64,
735 pub window_days: f64,
736}
737
738#[derive(Debug, Clone, Serialize, Deserialize)]
740pub struct DomainCount {
741 pub domain: String,
742 pub count: i64,
743}
744
745#[derive(Debug, Clone, Serialize, Deserialize)]
749pub struct CrossDomainLink {
750 pub rid_a: String,
751 pub rid_b: String,
752 pub domain_a: String,
753 pub domain_b: String,
754 pub similarity: f64,
755 pub text_a: String,
756 pub text_b: String,
757 pub score: f64,
758}
759
760#[derive(Debug, Clone, Serialize, Deserialize)]
762pub struct EntityBridge {
763 pub entity: String,
764 pub domains: Vec<DomainCount>,
765 pub bridge_score: f64,
766 pub total_mentions: i64,
767}
768
769#[derive(Debug, Clone, Serialize, Deserialize)]
775pub struct RelationshipDepth {
776 pub entity: String,
778 pub entity_type: String,
780 pub sessions_together: i64,
782 pub memories_mentioning: i64,
784 pub avg_valence: f64,
786 pub domains_spanning: Vec<String>,
788 pub relationship_types: Vec<String>,
790 pub connection_count: i64,
792 pub depth_score: f64,
795 pub first_seen: f64,
797 pub last_seen: f64,
799 pub interaction_frequency: f64,
801}
802
803#[derive(Debug, Clone, Serialize, Deserialize)]
807pub struct SubstitutionCategory {
808 pub id: String,
809 pub name: String,
810 pub conflict_mode: String,
811 pub status: String,
812 pub member_count: i64,
813}
814
815#[derive(Debug, Clone, Serialize, Deserialize)]
817pub struct SubstitutionMember {
818 pub id: String,
819 pub category_name: String,
820 pub token_normalized: String,
821 pub token_display: String,
822 pub confidence: f64,
823 pub source: String,
824 pub status: String,
825}
826
827#[derive(Debug, Clone, Serialize, Deserialize)]
829pub struct ReclassifyResult {
830 pub conflict_id: String,
831 pub old_type: String,
832 pub new_type: String,
833 pub learned_members: Vec<LearnedMember>,
834 pub category_created: Option<String>,
835}
836
837#[derive(Debug, Clone, Serialize, Deserialize)]
839pub struct LearnedMember {
840 pub token: String,
841 pub category_name: String,
842 pub is_new: bool,
843}
844
845impl Default for PatternConfig {
846 fn default() -> Self {
847 Self {
848 co_occurrence_min_count: 3,
849 temporal_cluster_min_events: 3,
850 valence_trend_delta_threshold: 0.3,
851 topic_cluster_sim_threshold: 0.55,
852 topic_cluster_time_window_days: 30.0,
853 entity_hub_min_degree: 5,
854 max_patterns: 50,
855 cross_domain_candidates_per_domain: 15,
856 cross_domain_sim_threshold: 0.50,
857 cross_domain_max_per_pair: 3,
858 entity_bridge_min_domains: 2,
859 entity_bridge_min_mentions_per_domain: 3,
860 run_cross_domain: true,
861 }
862 }
863}