1#![allow(deprecated)]
2
3use crate::error::MemoryError;
4use serde::{Deserialize, Serialize};
5use stack_ids::{
6 ClaimId, ClaimVersionId, EntityId, EnvelopeId, EpisodeId, RelationVersionId, ScopeKey,
7};
8
9#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
19#[serde(transparent)]
20pub struct CompatTraceId(pub String);
21
22#[deprecated(since = "0.5.0", note = "Use stack_ids::TraceCtx instead")]
23pub type TraceId = CompatTraceId;
24
25impl CompatTraceId {
26 pub fn new(value: impl Into<String>) -> Self {
28 Self(value.into())
29 }
30
31 pub fn as_str(&self) -> &str {
33 &self.0
34 }
35}
36
37impl std::fmt::Display for CompatTraceId {
38 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39 f.write_str(&self.0)
40 }
41}
42
43impl From<String> for CompatTraceId {
44 fn from(value: String) -> Self {
45 Self(value)
46 }
47}
48
49impl From<&str> for CompatTraceId {
50 fn from(value: &str) -> Self {
51 Self(value.to_string())
52 }
53}
54
55#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
57#[serde(rename_all = "lowercase")]
58pub enum Role {
59 System,
61 User,
63 Assistant,
65 Tool,
67}
68
69impl Role {
70 pub fn as_str(&self) -> &'static str {
72 match self {
73 Role::System => "system",
74 Role::User => "user",
75 Role::Assistant => "assistant",
76 Role::Tool => "tool",
77 }
78 }
79
80 pub fn from_str_value(s: &str) -> Option<Self> {
82 match s {
83 "system" => Some(Role::System),
84 "user" => Some(Role::User),
85 "assistant" => Some(Role::Assistant),
86 "tool" => Some(Role::Tool),
87 _ => None,
88 }
89 }
90}
91
92impl std::fmt::Display for Role {
93 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
94 f.write_str(self.as_str())
95 }
96}
97
98impl std::str::FromStr for Role {
99 type Err = MemoryError;
100
101 fn from_str(s: &str) -> Result<Self, Self::Err> {
102 Self::from_str_value(s).ok_or_else(|| MemoryError::Other(format!("Unknown role: '{}'", s)))
103 }
104}
105
106#[derive(Debug, Clone, Copy, PartialEq, Eq)]
108pub enum SearchSourceType {
109 Facts,
111 Chunks,
113 Messages,
115 Episodes,
117}
118
119#[derive(Debug, Clone, Serialize, Deserialize)]
121pub struct ProjectionQuery {
122 pub scope: ScopeKey,
124 #[serde(default, skip_serializing_if = "Option::is_none")]
126 pub text_query: Option<String>,
127 #[serde(default, skip_serializing_if = "Option::is_none")]
129 pub valid_at: Option<String>,
130 #[serde(default, skip_serializing_if = "Option::is_none")]
132 pub recorded_at_or_before: Option<String>,
133 #[serde(default, skip_serializing_if = "Option::is_none")]
135 pub subject_entity_id: Option<EntityId>,
136 #[serde(default, skip_serializing_if = "Option::is_none")]
138 pub canonical_entity_id: Option<EntityId>,
139 #[serde(default, skip_serializing_if = "Option::is_none")]
141 pub claim_state: Option<String>,
142 #[serde(default, skip_serializing_if = "Option::is_none")]
144 pub claim_id: Option<ClaimId>,
145 #[serde(default, skip_serializing_if = "Option::is_none")]
147 pub claim_version_id: Option<ClaimVersionId>,
148 pub limit: usize,
150}
151
152impl ProjectionQuery {
153 pub fn new(scope: ScopeKey) -> Self {
154 Self {
155 scope,
156 text_query: None,
157 valid_at: None,
158 recorded_at_or_before: None,
159 subject_entity_id: None,
160 canonical_entity_id: None,
161 claim_state: None,
162 claim_id: None,
163 claim_version_id: None,
164 limit: 10,
165 }
166 }
167}
168
169#[derive(Debug, Clone, Serialize, Deserialize)]
171pub struct ProjectionClaimVersion {
172 pub claim_version_id: ClaimVersionId,
173 pub claim_id: ClaimId,
174 pub claim_state: String,
175 pub projection_family: String,
176 pub subject_entity_id: EntityId,
177 pub predicate: String,
178 pub object_anchor: serde_json::Value,
179 pub scope_key: ScopeKey,
180 pub valid_from: Option<String>,
181 pub valid_to: Option<String>,
182 pub recorded_at: String,
183 pub preferred_open: bool,
184 pub source_envelope_id: EnvelopeId,
185 pub source_authority: String,
186 pub trace_id: Option<String>,
187 pub freshness: String,
188 pub contradiction_status: String,
189 pub supersedes_claim_version_id: Option<ClaimVersionId>,
190 pub content: String,
191 pub confidence: f32,
192 pub metadata: Option<serde_json::Value>,
193 pub source_exported_at: Option<String>,
194 pub transformed_at: Option<String>,
195}
196
197#[derive(Debug, Clone, Serialize, Deserialize)]
199pub struct ProjectionRelationVersion {
200 pub relation_version_id: RelationVersionId,
201 pub subject_entity_id: EntityId,
202 pub predicate: String,
203 pub object_anchor: serde_json::Value,
204 pub scope_key: ScopeKey,
205 pub claim_id: Option<ClaimId>,
206 pub source_episode_id: Option<EpisodeId>,
207 pub valid_from: Option<String>,
208 pub valid_to: Option<String>,
209 pub recorded_at: String,
210 pub preferred_open: bool,
211 pub supersedes_relation_version_id: Option<RelationVersionId>,
212 pub contradiction_status: String,
213 pub source_confidence: f32,
214 pub projection_family: String,
215 pub source_envelope_id: EnvelopeId,
216 pub source_authority: String,
217 pub trace_id: Option<String>,
218 pub freshness: String,
219 pub metadata: Option<serde_json::Value>,
220 pub source_exported_at: Option<String>,
221 pub transformed_at: Option<String>,
222}
223
224#[derive(Debug, Clone, Serialize, Deserialize)]
226pub struct ProjectionEpisode {
227 pub episode_id: EpisodeId,
228 pub document_id: String,
229 pub cause_ids: Vec<String>,
230 pub effect_type: String,
231 pub outcome: String,
232 pub confidence: f32,
233 pub experiment_id: Option<String>,
234 pub scope_key: ScopeKey,
235 pub source_envelope_id: EnvelopeId,
236 pub source_authority: String,
237 pub trace_id: Option<String>,
238 pub recorded_at: String,
239 pub metadata: Option<serde_json::Value>,
240 pub source_exported_at: Option<String>,
241 pub transformed_at: Option<String>,
242}
243
244#[derive(Debug, Clone, Serialize, Deserialize)]
246pub struct ProjectionEntityAlias {
247 pub canonical_entity_id: EntityId,
248 pub alias_text: String,
249 pub alias_source: String,
250 pub match_evidence: Option<serde_json::Value>,
251 pub confidence: f32,
252 pub merge_decision: String,
253 pub scope_key: ScopeKey,
254 pub review_state: String,
255 pub is_human_confirmed: bool,
256 pub is_human_confirmed_final: bool,
257 pub superseded_by_entity_id: Option<EntityId>,
258 pub split_from_entity_id: Option<EntityId>,
259 pub source_envelope_id: EnvelopeId,
260 pub recorded_at: String,
261 pub source_exported_at: Option<String>,
262 pub transformed_at: Option<String>,
263}
264
265#[derive(Debug, Clone, Serialize, Deserialize)]
267pub struct ProjectionEvidenceRef {
268 pub claim_id: ClaimId,
269 pub claim_version_id: Option<ClaimVersionId>,
270 pub fetch_handle: String,
271 pub source_authority: String,
272 pub source_envelope_id: EnvelopeId,
273 pub scope_key: ScopeKey,
274 pub recorded_at: String,
275 pub metadata: Option<serde_json::Value>,
276 pub source_exported_at: Option<String>,
277 pub transformed_at: Option<String>,
278}
279
280#[derive(Debug, Clone, Serialize, Deserialize)]
282pub struct Session {
283 pub id: String,
285 pub channel: String,
287 pub created_at: String,
289 pub updated_at: String,
291 pub metadata: Option<serde_json::Value>,
293 pub message_count: u32,
295}
296
297#[derive(Debug, Clone, Serialize, Deserialize)]
299pub struct Message {
300 pub id: i64,
302 pub session_id: String,
304 pub role: Role,
306 pub content: String,
308 pub token_count: Option<u32>,
310 pub created_at: String,
312 pub metadata: Option<serde_json::Value>,
314}
315
316#[derive(Debug, Clone, Serialize, Deserialize)]
318pub struct Fact {
319 pub id: String,
321 pub namespace: String,
323 pub content: String,
325 pub source: Option<String>,
327 pub created_at: String,
329 pub updated_at: String,
331 pub metadata: Option<serde_json::Value>,
333}
334
335#[derive(Debug, Clone, Serialize, Deserialize)]
337pub struct Document {
338 pub id: String,
340 pub title: String,
342 pub source_path: Option<String>,
344 pub namespace: String,
346 pub created_at: String,
348 pub metadata: Option<serde_json::Value>,
350 pub chunk_count: u32,
352}
353
354#[derive(Debug, Clone, Serialize, Deserialize)]
356pub struct TextChunk {
357 pub index: usize,
359 pub content: String,
361 pub token_count_estimate: usize,
363}
364
365#[derive(Debug, Clone, Serialize, Deserialize)]
367pub struct SearchResult {
368 pub content: String,
370
371 pub source: SearchSource,
373
374 pub score: f64,
376
377 pub bm25_rank: Option<usize>,
379
380 pub vector_rank: Option<usize>,
382
383 pub cosine_similarity: Option<f64>,
385}
386
387#[derive(Debug, Clone, Serialize, Deserialize)]
389#[serde(rename_all = "snake_case")]
390pub enum SearchSource {
391 Fact {
393 fact_id: String,
395 namespace: String,
397 },
398 Chunk {
400 chunk_id: String,
402 document_id: String,
404 document_title: String,
406 chunk_index: usize,
408 },
409 Message {
411 message_id: i64,
413 session_id: String,
415 role: String,
417 },
418 Episode {
420 episode_id: String,
423 document_id: String,
425 effect_type: String,
427 outcome: String,
429 },
430 Projection {
432 projection_kind: String,
434 projection_id: String,
436 scope_key: ScopeKey,
438 valid_from: Option<String>,
440 valid_to: Option<String>,
442 recorded_at: String,
444 source_envelope_id: String,
446 source_authority: String,
448 },
449}
450
451#[derive(Debug, Clone, Serialize, Deserialize)]
455pub struct EpisodeMeta {
456 pub cause_ids: Vec<String>,
458 pub effect_type: String,
460 pub outcome: EpisodeOutcome,
462 pub confidence: f32,
464 pub verification_status: VerificationStatus,
466 pub experiment_id: Option<String>,
468}
469
470#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
472#[serde(rename_all = "lowercase")]
473pub enum EpisodeOutcome {
474 Confirmed,
476 Refuted,
478 Inconclusive,
480 Pending,
482}
483
484impl EpisodeOutcome {
485 pub fn as_str(&self) -> &'static str {
487 match self {
488 Self::Confirmed => "confirmed",
489 Self::Refuted => "refuted",
490 Self::Inconclusive => "inconclusive",
491 Self::Pending => "pending",
492 }
493 }
494
495 pub fn from_str_value(s: &str) -> Option<Self> {
497 match s {
498 "confirmed" => Some(Self::Confirmed),
499 "refuted" => Some(Self::Refuted),
500 "inconclusive" => Some(Self::Inconclusive),
501 "pending" => Some(Self::Pending),
502 _ => None,
503 }
504 }
505}
506
507impl std::fmt::Display for EpisodeOutcome {
508 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
509 f.write_str(self.as_str())
510 }
511}
512
513#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
515#[serde(tag = "status", rename_all = "lowercase")]
516pub enum VerificationStatus {
517 Unverified,
519 Verified {
521 method: String,
523 at: String,
525 },
526 Failed {
528 reason: String,
530 at: String,
532 },
533}
534
535#[derive(Debug, Clone, Serialize, Deserialize)]
539pub struct ScoreBreakdown {
540 pub rrf_score: f64,
542 pub bm25_score: Option<f64>,
544 pub vector_score: Option<f64>,
546 pub recency_score: Option<f64>,
548 pub bm25_rank: Option<usize>,
550 pub vector_rank: Option<usize>,
552 pub vector_source_rank: Option<usize>,
554 pub vector_source_score: Option<f64>,
556 pub bm25_contribution: Option<f64>,
558 pub vector_contribution: Option<f64>,
560 pub vector_reranked_from_f32: bool,
562 pub bm25_weight: f64,
564 pub vector_weight: f64,
566 pub recency_weight: Option<f64>,
568 pub rrf_k: f64,
570}
571
572#[derive(Debug, Clone, Serialize, Deserialize)]
574pub struct ExplainedResult {
575 pub result: SearchResult,
577 pub breakdown: ScoreBreakdown,
579}
580
581pub trait GraphView: Send + Sync {
585 fn neighbors(
587 &self,
588 node_id: &str,
589 direction: GraphDirection,
590 max_depth: usize,
591 ) -> Result<Vec<GraphEdge>, MemoryError>;
592
593 fn path(
595 &self,
596 from: &str,
597 to: &str,
598 max_depth: usize,
599 ) -> Result<Option<Vec<String>>, MemoryError>;
600}
601
602#[derive(Debug, Clone, Copy, PartialEq, Eq)]
604pub enum GraphDirection {
605 Outgoing,
607 Incoming,
609 Both,
611}
612
613#[derive(Debug, Clone, Serialize, Deserialize)]
615pub struct GraphEdge {
616 pub source: String,
618 pub target: String,
620 pub edge_type: GraphEdgeType,
622 pub weight: f64,
624 pub metadata: Option<serde_json::Value>,
626}
627
628#[derive(Debug, Clone, Serialize, Deserialize)]
630#[serde(rename_all = "snake_case")]
631pub enum GraphEdgeType {
632 Semantic {
634 cosine_similarity: f32,
636 },
637 Temporal {
639 delta_secs: u64,
641 },
642 Causal {
644 confidence: f32,
646 evidence_ids: Vec<String>,
648 },
649 Entity {
651 relation: String,
653 },
654}
655
656#[derive(Debug, Clone, Serialize, Deserialize)]
658pub struct EmbeddingDisplacement {
659 pub cosine_similarity: f32,
661 pub euclidean_distance: f32,
663 pub magnitude_a: f32,
665 pub magnitude_b: f32,
667}
668
669#[derive(Debug, Clone, Serialize, Deserialize)]
671pub struct MemoryStats {
672 pub total_facts: u64,
674 pub total_documents: u64,
676 pub total_chunks: u64,
678 pub total_sessions: u64,
680 pub total_messages: u64,
682 pub database_size_bytes: u64,
684 pub embedding_model: Option<String>,
686 pub embedding_dimensions: Option<usize>,
688}