Skip to main content

velesdb_memory/
model.rs

1//! Domain data model: the request/response value types of the memory layer.
2//!
3//! These are pure data — the shapes a caller links, recalls, filters on, and
4//! gets back — with no dependency on [`MemoryService`](crate::service::MemoryService)
5//! itself. Keeping them here separates *what the memory layer exchanges* from
6//! *how the service computes it*, and gives every adapter (MCP, bindings) one
7//! canonical place to import the contract from.
8
9use schemars::JsonSchema;
10use serde::{Deserialize, Serialize};
11use serde_json::Value;
12
13/// A typed link from a freshly remembered fact to an existing memory.
14#[derive(Debug, Clone, Deserialize, JsonSchema)]
15#[schemars(transform = crate::schema::strip_int_formats)]
16pub struct Link {
17    /// Id of the memory being linked to.
18    pub target: u64,
19    /// Relationship label (e.g. `"decided_in"`, `"references"`, `"depends_on"`).
20    pub relation: String,
21}
22
23/// One semantically recalled memory.
24#[derive(Debug, Clone, Serialize, JsonSchema)]
25#[schemars(transform = crate::schema::strip_int_formats)]
26pub struct Recollection {
27    /// Stable id of the memory.
28    pub id: u64,
29    /// Similarity score (higher is closer).
30    pub score: f32,
31    /// Stored fact content.
32    pub content: String,
33}
34
35/// Comparison operator for a [`ColumnFilter`] in
36/// [`MemoryService::recall_where`](crate::service::MemoryService::recall_where).
37#[derive(Debug, Clone, Copy, Deserialize, JsonSchema)]
38#[serde(rename_all = "lowercase")]
39pub enum ColumnOp {
40    /// `=`
41    Eq,
42    /// `!=`
43    Ne,
44    /// `<`
45    Lt,
46    /// `<=`
47    Le,
48    /// `>`
49    Gt,
50    /// `>=`
51    Ge,
52}
53
54impl ColumnOp {
55    /// The `VelesQL` operator token.
56    #[must_use]
57    pub(crate) fn as_sql(self) -> &'static str {
58        match self {
59            Self::Eq => "=",
60            Self::Ne => "!=",
61            Self::Lt => "<",
62            Self::Le => "<=",
63            Self::Gt => ">",
64            Self::Ge => ">=",
65        }
66    }
67}
68
69/// A structured predicate over a memory's metadata column, for the fused
70/// vector+`ColumnStore` recall
71/// [`MemoryService::recall_where`](crate::service::MemoryService::recall_where).
72/// Unlike the exact-match filter on
73/// [`MemoryService::recall`](crate::service::MemoryService::recall), this supports
74/// ranges and comparisons (e.g. `timestamp >= …`), so temporal and numeric facets
75/// become queryable, not just equal-matchable.
76#[derive(Debug, Clone, Deserialize, JsonSchema)]
77pub struct ColumnFilter {
78    /// Metadata field name (alphanumeric/underscore).
79    pub field: String,
80    /// Comparison operator.
81    pub op: ColumnOp,
82    /// Value to compare against (numbers, strings, booleans).
83    pub value: Value,
84}
85
86/// A node in an [`Explanation`] subgraph.
87#[derive(Debug, Clone, Serialize, JsonSchema)]
88#[schemars(transform = crate::schema::strip_int_formats)]
89pub struct MemoryNode {
90    /// Stable id of the memory.
91    pub id: u64,
92    /// Stored fact content.
93    pub content: String,
94    /// Distance in hops from the seed memory (the seed is hop `0`).
95    pub hop: usize,
96}
97
98/// A typed edge in an [`Explanation`] subgraph.
99#[derive(Debug, Clone, Serialize, JsonSchema)]
100#[schemars(transform = crate::schema::strip_int_formats)]
101pub struct MemoryEdge {
102    /// Source memory id.
103    pub from: u64,
104    /// Target memory id.
105    pub to: u64,
106    /// Relationship label.
107    pub relation: String,
108}
109
110/// The connected answer to a `why` question: the best-matching seed memory plus
111/// everything reachable from it within a hop budget. This connected subgraph is
112/// the differentiator — it surfaces related memories a purely vector recall is
113/// blind to (no textual similarity required).
114#[derive(Debug, Clone, Default, Serialize, JsonSchema)]
115pub struct Explanation {
116    /// Memories in the subgraph, seed first.
117    pub nodes: Vec<MemoryNode>,
118    /// Typed edges connecting the nodes.
119    pub edges: Vec<MemoryEdge>,
120}