Skip to main content

kmp_memory_api/
memory_requests.rs

1use serde::{Deserialize, Serialize};
2
3/// How much of the memory a recall may resolve.
4///
5/// Mirrors the kernel's resolution ladder without importing it: a summary, the
6/// causal spine, or the full evidence pack. The contract names the rungs;
7/// what each costs is the implementation's business.
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
9pub enum MemoryTier {
10    Summary,
11    CausalSpine,
12    EvidencePack,
13}
14
15/// How `ask` may answer when the evidence is thin.
16///
17/// The default is the strict one. A memory that answers beyond its evidence is
18/// worse than one that says it does not know, and a consumer that wants the
19/// looser policies must ask for them by name.
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
21pub enum MemoryAnswerPolicy {
22    #[default]
23    EvidenceOrUnknown,
24    ShowConflicts,
25    BestEffort,
26}
27
28/// Recall the bounded context of one about.
29#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
30pub struct MemoryWakeRequest {
31    /// What the memory is about. The kernel's addressing, opaque to it: a
32    /// consumer puts its own reference here and gets it back unchanged.
33    pub about: String,
34    /// Who is asking, for the kernel's own accounting.
35    pub role: String,
36    /// Why, in a sentence. Carried into the kernel's telemetry so a recall can
37    /// be explained later.
38    pub intent: String,
39    /// Restrict recall to these dimension kinds. Empty means all of them.
40    pub dimension_kinds: Vec<String>,
41    /// Restrict recall to the current about's own scopes.
42    pub scoped_to_about: bool,
43    pub token_budget: u32,
44    pub depth: u32,
45    pub max_tier: Option<MemoryTier>,
46    /// Cap on surfaced evidence entries. `None` is unbounded; when set and the
47    /// about holds more, the kernel returns the first `max_entries` and says
48    /// how much it withheld.
49    pub max_entries: Option<u32>,
50}
51
52/// Ask one question of the memory.
53#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
54pub struct MemoryAskRequest {
55    pub about: String,
56    pub question: String,
57    pub answer_policy: MemoryAnswerPolicy,
58    pub dimension_kinds: Vec<String>,
59    pub scoped_to_about: bool,
60    pub token_budget: u32,
61    pub depth: u32,
62    pub max_tier: Option<MemoryTier>,
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68
69    #[test]
70    fn the_default_answer_policy_is_the_strict_one() {
71        assert_eq!(
72            MemoryAnswerPolicy::default(),
73            MemoryAnswerPolicy::EvidenceOrUnknown,
74            "a memory that answers beyond its evidence is worse than one that \
75             says it does not know"
76        );
77    }
78
79    #[test]
80    fn a_request_survives_the_wire() {
81        let request = MemoryWakeRequest {
82            about: "project:checkout".to_string(),
83            role: "resumer".to_string(),
84            intent: "resume after restart".to_string(),
85            dimension_kinds: vec!["timeline".to_string()],
86            scoped_to_about: true,
87            token_budget: 4096,
88            depth: 2,
89            max_tier: Some(MemoryTier::EvidencePack),
90            max_entries: Some(50),
91        };
92        let bytes = serde_json::to_vec(&request).expect("serializes");
93        assert_eq!(
94            serde_json::from_slice::<MemoryWakeRequest>(&bytes).expect("deserializes"),
95            request
96        );
97    }
98}