#![allow(deprecated)]
use crate::error::MemoryError;
use serde::{Deserialize, Serialize};
use stack_ids::{
ClaimId, ClaimVersionId, EntityId, EnvelopeId, EpisodeId, RelationVersionId, ScopeKey,
};
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(transparent)]
pub struct CompatTraceId(pub String);
#[deprecated(since = "0.5.0", note = "Use stack_ids::TraceCtx instead")]
pub type TraceId = CompatTraceId;
impl CompatTraceId {
pub fn new(value: impl Into<String>) -> Self {
Self(value.into())
}
pub fn as_str(&self) -> &str {
&self.0
}
}
impl std::fmt::Display for CompatTraceId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.0)
}
}
impl From<String> for CompatTraceId {
fn from(value: String) -> Self {
Self(value)
}
}
impl From<&str> for CompatTraceId {
fn from(value: &str) -> Self {
Self(value.to_string())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Role {
System,
User,
Assistant,
Tool,
}
impl Role {
pub fn as_str(&self) -> &'static str {
match self {
Role::System => "system",
Role::User => "user",
Role::Assistant => "assistant",
Role::Tool => "tool",
}
}
pub fn from_str_value(s: &str) -> Option<Self> {
match s {
"system" => Some(Role::System),
"user" => Some(Role::User),
"assistant" => Some(Role::Assistant),
"tool" => Some(Role::Tool),
_ => None,
}
}
}
impl std::fmt::Display for Role {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
impl std::str::FromStr for Role {
type Err = MemoryError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::from_str_value(s).ok_or_else(|| MemoryError::Other(format!("Unknown role: '{}'", s)))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SearchSourceType {
Facts,
Chunks,
Messages,
Episodes,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProjectionQuery {
pub scope: ScopeKey,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub text_query: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub valid_at: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub recorded_at_or_before: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub subject_entity_id: Option<EntityId>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub canonical_entity_id: Option<EntityId>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub claim_state: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub claim_id: Option<ClaimId>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub claim_version_id: Option<ClaimVersionId>,
pub limit: usize,
}
impl ProjectionQuery {
pub fn new(scope: ScopeKey) -> Self {
Self {
scope,
text_query: None,
valid_at: None,
recorded_at_or_before: None,
subject_entity_id: None,
canonical_entity_id: None,
claim_state: None,
claim_id: None,
claim_version_id: None,
limit: 10,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProjectionClaimVersion {
pub claim_version_id: ClaimVersionId,
pub claim_id: ClaimId,
pub claim_state: String,
pub projection_family: String,
pub subject_entity_id: EntityId,
pub predicate: String,
pub object_anchor: serde_json::Value,
pub scope_key: ScopeKey,
pub valid_from: Option<String>,
pub valid_to: Option<String>,
pub recorded_at: String,
pub preferred_open: bool,
pub source_envelope_id: EnvelopeId,
pub source_authority: String,
pub trace_id: Option<String>,
pub freshness: String,
pub contradiction_status: String,
pub supersedes_claim_version_id: Option<ClaimVersionId>,
pub content: String,
pub confidence: f32,
pub metadata: Option<serde_json::Value>,
pub source_exported_at: Option<String>,
pub transformed_at: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProjectionRelationVersion {
pub relation_version_id: RelationVersionId,
pub subject_entity_id: EntityId,
pub predicate: String,
pub object_anchor: serde_json::Value,
pub scope_key: ScopeKey,
pub claim_id: Option<ClaimId>,
pub source_episode_id: Option<EpisodeId>,
pub valid_from: Option<String>,
pub valid_to: Option<String>,
pub recorded_at: String,
pub preferred_open: bool,
pub supersedes_relation_version_id: Option<RelationVersionId>,
pub contradiction_status: String,
pub source_confidence: f32,
pub projection_family: String,
pub source_envelope_id: EnvelopeId,
pub source_authority: String,
pub trace_id: Option<String>,
pub freshness: String,
pub metadata: Option<serde_json::Value>,
pub source_exported_at: Option<String>,
pub transformed_at: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProjectionEpisode {
pub episode_id: EpisodeId,
pub document_id: String,
pub cause_ids: Vec<String>,
pub effect_type: String,
pub outcome: String,
pub confidence: f32,
pub experiment_id: Option<String>,
pub scope_key: ScopeKey,
pub source_envelope_id: EnvelopeId,
pub source_authority: String,
pub trace_id: Option<String>,
pub recorded_at: String,
pub metadata: Option<serde_json::Value>,
pub source_exported_at: Option<String>,
pub transformed_at: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProjectionEntityAlias {
pub canonical_entity_id: EntityId,
pub alias_text: String,
pub alias_source: String,
pub match_evidence: Option<serde_json::Value>,
pub confidence: f32,
pub merge_decision: String,
pub scope_key: ScopeKey,
pub review_state: String,
pub is_human_confirmed: bool,
pub is_human_confirmed_final: bool,
pub superseded_by_entity_id: Option<EntityId>,
pub split_from_entity_id: Option<EntityId>,
pub source_envelope_id: EnvelopeId,
pub recorded_at: String,
pub source_exported_at: Option<String>,
pub transformed_at: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProjectionEvidenceRef {
pub claim_id: ClaimId,
pub claim_version_id: Option<ClaimVersionId>,
pub fetch_handle: String,
pub source_authority: String,
pub source_envelope_id: EnvelopeId,
pub scope_key: ScopeKey,
pub recorded_at: String,
pub metadata: Option<serde_json::Value>,
pub source_exported_at: Option<String>,
pub transformed_at: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Session {
pub id: String,
pub channel: String,
pub created_at: String,
pub updated_at: String,
pub metadata: Option<serde_json::Value>,
pub message_count: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Message {
pub id: i64,
pub session_id: String,
pub role: Role,
pub content: String,
pub token_count: Option<u32>,
pub created_at: String,
pub metadata: Option<serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Fact {
pub id: String,
pub namespace: String,
pub content: String,
pub source: Option<String>,
pub created_at: String,
pub updated_at: String,
pub metadata: Option<serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Document {
pub id: String,
pub title: String,
pub source_path: Option<String>,
pub namespace: String,
pub created_at: String,
pub metadata: Option<serde_json::Value>,
pub chunk_count: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TextChunk {
pub index: usize,
pub content: String,
pub token_count_estimate: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SearchResult {
pub content: String,
pub source: SearchSource,
pub score: f64,
pub bm25_rank: Option<usize>,
pub vector_rank: Option<usize>,
pub cosine_similarity: Option<f64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum SearchSource {
Fact {
fact_id: String,
namespace: String,
},
Chunk {
chunk_id: String,
document_id: String,
document_title: String,
chunk_index: usize,
},
Message {
message_id: i64,
session_id: String,
role: String,
},
Episode {
episode_id: String,
document_id: String,
effect_type: String,
outcome: String,
},
Projection {
projection_kind: String,
projection_id: String,
scope_key: ScopeKey,
valid_from: Option<String>,
valid_to: Option<String>,
recorded_at: String,
source_envelope_id: String,
source_authority: String,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EpisodeMeta {
pub cause_ids: Vec<String>,
pub effect_type: String,
pub outcome: EpisodeOutcome,
pub confidence: f32,
pub verification_status: VerificationStatus,
pub experiment_id: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum EpisodeOutcome {
Confirmed,
Refuted,
Inconclusive,
Pending,
}
impl EpisodeOutcome {
pub fn as_str(&self) -> &'static str {
match self {
Self::Confirmed => "confirmed",
Self::Refuted => "refuted",
Self::Inconclusive => "inconclusive",
Self::Pending => "pending",
}
}
pub fn from_str_value(s: &str) -> Option<Self> {
match s {
"confirmed" => Some(Self::Confirmed),
"refuted" => Some(Self::Refuted),
"inconclusive" => Some(Self::Inconclusive),
"pending" => Some(Self::Pending),
_ => None,
}
}
}
impl std::fmt::Display for EpisodeOutcome {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "status", rename_all = "lowercase")]
pub enum VerificationStatus {
Unverified,
Verified {
method: String,
at: String,
},
Failed {
reason: String,
at: String,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ScoreBreakdown {
pub rrf_score: f64,
pub bm25_score: Option<f64>,
pub vector_score: Option<f64>,
pub recency_score: Option<f64>,
pub bm25_rank: Option<usize>,
pub vector_rank: Option<usize>,
pub vector_source_rank: Option<usize>,
pub vector_source_score: Option<f64>,
pub bm25_contribution: Option<f64>,
pub vector_contribution: Option<f64>,
pub vector_reranked_from_f32: bool,
pub bm25_weight: f64,
pub vector_weight: f64,
pub recency_weight: Option<f64>,
pub rrf_k: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExplainedResult {
pub result: SearchResult,
pub breakdown: ScoreBreakdown,
}
pub trait GraphView: Send + Sync {
fn neighbors(
&self,
node_id: &str,
direction: GraphDirection,
max_depth: usize,
) -> Result<Vec<GraphEdge>, MemoryError>;
fn path(
&self,
from: &str,
to: &str,
max_depth: usize,
) -> Result<Option<Vec<String>>, MemoryError>;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GraphDirection {
Outgoing,
Incoming,
Both,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GraphEdge {
pub source: String,
pub target: String,
pub edge_type: GraphEdgeType,
pub weight: f64,
pub metadata: Option<serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum GraphEdgeType {
Semantic {
cosine_similarity: f32,
},
Temporal {
delta_secs: u64,
},
Causal {
confidence: f32,
evidence_ids: Vec<String>,
},
Entity {
relation: String,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EmbeddingDisplacement {
pub cosine_similarity: f32,
pub euclidean_distance: f32,
pub magnitude_a: f32,
pub magnitude_b: f32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MemoryStats {
pub total_facts: u64,
pub total_documents: u64,
pub total_chunks: u64,
pub total_sessions: u64,
pub total_messages: u64,
pub database_size_bytes: u64,
pub embedding_model: Option<String>,
pub embedding_dimensions: Option<usize>,
}