Skip to main content

kyma_memory/
types.rs

1//! Memory domain types.
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5use uuid::Uuid;
6
7/// The kind of a memory. Mirrors agentcy's taxonomy.
8///
9/// `Procedure` captures "how things are done" (conventions, runbooks) and
10/// `Entity` is a lightweight, embeddable node minted for an extracted entity
11/// that is then linked (`RESOLVES_TO`) to the real catalog graph node.
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
13#[serde(rename_all = "snake_case")]
14pub enum MemoryType {
15    Fact,
16    Decision,
17    Preference,
18    Learning,
19    Summary,
20    Procedure,
21    Entity,
22}
23
24impl MemoryType {
25    pub fn as_str(self) -> &'static str {
26        match self {
27            MemoryType::Fact => "fact",
28            MemoryType::Decision => "decision",
29            MemoryType::Preference => "preference",
30            MemoryType::Learning => "learning",
31            MemoryType::Summary => "summary",
32            MemoryType::Procedure => "procedure",
33            MemoryType::Entity => "entity",
34        }
35    }
36
37    /// Parse loosely; unrecognized values fall back to `Fact`.
38    pub fn parse(s: &str) -> MemoryType {
39        match s.trim().to_ascii_lowercase().as_str() {
40            "decision" => MemoryType::Decision,
41            "preference" => MemoryType::Preference,
42            "learning" => MemoryType::Learning,
43            "summary" => MemoryType::Summary,
44            "procedure" => MemoryType::Procedure,
45            "entity" => MemoryType::Entity,
46            _ => MemoryType::Fact,
47        }
48    }
49}
50
51impl Default for MemoryType {
52    fn default() -> Self {
53        MemoryType::Fact
54    }
55}
56
57/// Lifecycle status. `archived` memories are hidden from recall.
58#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
59#[serde(rename_all = "snake_case")]
60pub enum MemoryStatus {
61    Active,
62    Background,
63    Archived,
64}
65
66impl MemoryStatus {
67    pub fn as_str(self) -> &'static str {
68        match self {
69            MemoryStatus::Active => "active",
70            MemoryStatus::Background => "background",
71            MemoryStatus::Archived => "archived",
72        }
73    }
74
75    pub fn parse(s: &str) -> Option<MemoryStatus> {
76        match s.trim().to_ascii_lowercase().as_str() {
77            "active" => Some(MemoryStatus::Active),
78            "background" => Some(MemoryStatus::Background),
79            "archived" => Some(MemoryStatus::Archived),
80            _ => None,
81        }
82    }
83}
84
85/// Input to [`crate::MemoryWriter::save`].
86#[derive(Debug, Clone)]
87pub struct CreateMemory {
88    pub content: String,
89    pub title: Option<String>,
90    pub memory_type: MemoryType,
91    pub tags: Vec<String>,
92    pub realm: String,
93    pub importance: f32,
94    /// Existing graph node ids this memory is about (become `REFERENCES` edges).
95    pub references: Vec<String>,
96    pub source_session_id: Option<Uuid>,
97    pub source_run_id: Option<Uuid>,
98    /// When the fact became true (bi-temporal). Defaults to `created_at`.
99    pub valid_at: Option<String>,
100    /// How this memory was formed: `{source, run_id, watermark, extracted_from_ids, confidence}`.
101    pub provenance: Option<Value>,
102    /// Deterministic upsert key (e.g. `architecture/auth-model`). When set, a
103    /// save with the same `(realm, topic_key)` updates the existing memory in
104    /// place instead of creating a new one. `None` = always create.
105    pub topic_key: Option<String>,
106}
107
108impl CreateMemory {
109    pub fn new(content: impl Into<String>) -> Self {
110        Self {
111            content: content.into(),
112            title: None,
113            memory_type: MemoryType::Fact,
114            tags: Vec::new(),
115            realm: crate::DEFAULT_REALM.to_string(),
116            importance: 0.5,
117            references: Vec::new(),
118            source_session_id: None,
119            source_run_id: None,
120            valid_at: None,
121            provenance: None,
122            topic_key: None,
123        }
124    }
125}
126
127/// Filters for recall / listing.
128#[derive(Debug, Clone, Default)]
129pub struct RecallFilter {
130    /// Realms to include (the project ∪ global set). Empty = all realms.
131    pub realms: Vec<String>,
132    pub memory_type: Option<MemoryType>,
133    /// Statuses to include. Empty = active + background (archived always excluded).
134    pub statuses: Vec<MemoryStatus>,
135    pub tags: Vec<String>,
136    pub importance_min: Option<f32>,
137    pub since: Option<String>,
138    pub until: Option<String>,
139    /// Point-in-time recall: only memories valid at this instant
140    /// (`valid_at <= as_of < invalid_at`). `None` = "now".
141    pub as_of: Option<String>,
142    /// Include superseded/invalidated memories (default false). Used for audit.
143    pub include_invalidated: bool,
144}