Skip to main content

kmp_application/memory/
types.rs

1use kmp_domain::{
2    DimensionSelection, ResolutionTier, TemporalAxis, TemporalCoordinate, TemporalCursor,
3    TemporalDirection, TemporalWindow,
4};
5
6use crate::queries::{GetNodeDetailResult, GraphRelationshipView};
7
8pub const DEFAULT_TRACE_PAGE_ENTRIES: usize = 64;
9pub const MAX_TRACE_PAGE_ENTRIES: usize = 256;
10
11#[derive(Debug, Clone, PartialEq, Eq)]
12pub struct MemoryIngestCommand {
13    pub about: String,
14    pub memory: MemoryData,
15    pub provenance: Option<MemoryProvenanceData>,
16    pub idempotency_key: String,
17    pub dry_run: bool,
18}
19
20#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)]
21pub struct MemoryData {
22    pub dimensions: Vec<MemoryDimensionData>,
23    pub entries: Vec<MemoryEntryData>,
24    pub relations: Vec<MemoryRelationData>,
25    pub evidence: Vec<MemoryEvidenceData>,
26}
27
28#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)]
29pub struct MemoryDimensionData {
30    pub id: String,
31    pub kind: String,
32    #[serde(skip_serializing_if = "Option::is_none")]
33    pub title: Option<String>,
34    #[serde(default, skip_serializing_if = "std::collections::BTreeMap::is_empty")]
35    pub metadata: std::collections::BTreeMap<String, String>,
36}
37
38#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)]
39pub struct MemoryEntryData {
40    pub id: String,
41    pub kind: String,
42    pub text: String,
43    pub coordinates: Vec<MemoryCoordinateData>,
44    #[serde(default, skip_serializing_if = "std::collections::BTreeMap::is_empty")]
45    pub metadata: std::collections::BTreeMap<String, String>,
46}
47
48#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)]
49pub struct MemoryCoordinateData {
50    pub dimension: String,
51    pub scope_id: String,
52    #[serde(skip_serializing_if = "Option::is_none")]
53    pub occurred_at: Option<String>,
54    #[serde(skip_serializing_if = "Option::is_none")]
55    pub observed_at: Option<String>,
56    #[serde(skip_serializing_if = "Option::is_none")]
57    pub ingested_at: Option<String>,
58    #[serde(skip_serializing_if = "Option::is_none")]
59    pub valid_from: Option<String>,
60    #[serde(skip_serializing_if = "Option::is_none")]
61    pub valid_until: Option<String>,
62    #[serde(skip_serializing_if = "Option::is_none")]
63    pub sequence: Option<u32>,
64    #[serde(skip_serializing_if = "Option::is_none")]
65    pub rank: Option<u32>,
66    #[serde(default, skip_serializing_if = "std::collections::BTreeMap::is_empty")]
67    pub metadata: std::collections::BTreeMap<String, String>,
68}
69
70#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)]
71pub struct MemoryRelationData {
72    #[serde(rename = "from")]
73    pub source_ref: String,
74    #[serde(rename = "to")]
75    pub target_ref: String,
76    pub rel: String,
77    #[serde(rename = "class")]
78    pub semantic_class: String,
79    #[serde(skip_serializing_if = "Option::is_none")]
80    pub why: Option<String>,
81    #[serde(skip_serializing_if = "Option::is_none")]
82    pub evidence: Option<String>,
83    #[serde(skip_serializing_if = "Option::is_none")]
84    pub confidence: Option<String>,
85    #[serde(skip_serializing_if = "Option::is_none")]
86    pub sequence: Option<u32>,
87    #[serde(skip_serializing_if = "Option::is_none")]
88    pub motivation: Option<String>,
89    #[serde(skip_serializing_if = "Option::is_none")]
90    pub method: Option<String>,
91    #[serde(skip_serializing_if = "Option::is_none")]
92    pub decision_id: Option<String>,
93    #[serde(skip_serializing_if = "Option::is_none")]
94    pub caused_by_node_id: Option<String>,
95    #[serde(skip_serializing_if = "Option::is_none")]
96    pub coordinate: Option<MemoryCoordinateData>,
97}
98
99#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)]
100pub struct MemoryEvidenceData {
101    pub id: String,
102    pub supports: Vec<String>,
103    pub text: String,
104    #[serde(skip_serializing_if = "Option::is_none")]
105    pub source: Option<String>,
106    #[serde(skip_serializing_if = "Option::is_none")]
107    pub time: Option<String>,
108    #[serde(default, skip_serializing_if = "std::collections::BTreeMap::is_empty")]
109    pub metadata: std::collections::BTreeMap<String, String>,
110}
111
112#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)]
113pub struct MemoryProvenanceData {
114    pub source_kind: String,
115    pub source_agent: String,
116    pub observed_at: String,
117    pub correlation_id: Option<String>,
118    pub causation_id: Option<String>,
119}
120
121#[derive(Debug, Clone, PartialEq, Eq)]
122pub struct MemoryAcceptedCounts {
123    pub entries: usize,
124    pub relations: usize,
125    pub evidence: usize,
126}
127
128#[derive(Debug, Clone, PartialEq, Eq)]
129pub struct MemoryIngestOutcome {
130    pub about: String,
131    pub memory_id: String,
132    pub accepted: MemoryAcceptedCounts,
133    pub read_after_write_ready: bool,
134    pub warnings: Vec<String>,
135}
136
137#[derive(Debug, Clone, PartialEq, Eq)]
138pub struct WakeMemoryQuery {
139    pub about: String,
140    pub role: String,
141    pub intent: String,
142    pub dimensions: DimensionSelection,
143    pub token_budget: u32,
144    pub depth: u32,
145    pub max_tier: Option<ResolutionTier>,
146    /// Cap on surfaced proof.evidence entries (None = unbounded). When set and
147    /// the about has more, Wake returns the first `max_entries` and reports the
148    /// withheld count via proof.frontier_size so the client near-expands.
149    pub max_entries: Option<usize>,
150}
151
152#[derive(Debug, Clone, PartialEq, Eq)]
153pub struct AskMemoryQuery {
154    pub about: String,
155    pub question: String,
156    /// The user's own words when `question` is the agent's rendering of them
157    /// in the kernel's search language. Searched never; echoed and read
158    /// against the question so a rendering that lost something says so.
159    pub asked_as: Option<String>,
160    pub answer_policy: MemoryAnswerPolicy,
161    pub dimensions: DimensionSelection,
162    pub token_budget: u32,
163    pub depth: u32,
164    pub max_tier: Option<ResolutionTier>,
165    /// Cap on answer evidence entries after relevance filtering.
166    pub max_entries: Option<usize>,
167}
168
169#[derive(Debug, Clone, PartialEq, Eq)]
170pub struct TemporalMemoryQuery {
171    pub about: String,
172    pub direction: TemporalDirection,
173    pub axis: TemporalAxis,
174    pub cursor: TemporalCursor,
175    pub dimensions: DimensionSelection,
176    pub window: TemporalWindow,
177    pub limit_entries: Option<usize>,
178    pub include: TemporalIncludeOptions,
179    pub token_budget: u32,
180    pub depth: u32,
181    pub max_tier: Option<ResolutionTier>,
182}
183
184#[derive(Debug, Clone, PartialEq, Eq)]
185pub struct TraceMemoryQuery {
186    pub about: String,
187    pub from: String,
188    pub to: String,
189    pub role: String,
190    pub token_budget: u32,
191    pub page: TracePageRequest,
192}
193
194#[derive(Debug, Clone, PartialEq, Eq, Default)]
195pub struct TracePageRequest {
196    pub entries: Option<usize>,
197    pub cursor: Option<usize>,
198}
199
200impl TracePageRequest {
201    pub fn offset(&self) -> usize {
202        self.cursor.unwrap_or_default()
203    }
204
205    pub fn entries_or_default(&self) -> usize {
206        self.entries.unwrap_or(DEFAULT_TRACE_PAGE_ENTRIES)
207    }
208}
209
210#[derive(Debug, Clone, PartialEq, Eq)]
211pub struct InspectMemoryQuery {
212    pub about: String,
213    pub ref_id: String,
214    pub include_details: bool,
215    pub include_incoming: bool,
216    pub include_outgoing: bool,
217    pub include_raw: bool,
218}
219
220#[derive(Clone, PartialEq, Eq)]
221pub struct InspectMemoryResult {
222    pub detail: GetNodeDetailResult,
223    pub incoming: Vec<GraphRelationshipView>,
224    pub outgoing: Vec<GraphRelationshipView>,
225    pub evidence: Vec<InspectedEvidence>,
226    pub raw_coordinates: Vec<TemporalCoordinate>,
227    pub include_details: bool,
228    pub include_raw: bool,
229}
230
231#[derive(Clone, PartialEq, Eq)]
232pub struct InspectedEvidence {
233    pub detail: GetNodeDetailResult,
234    pub supports: Vec<String>,
235}
236
237#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
238pub enum MemoryAnswerPolicy {
239    #[default]
240    EvidenceOrUnknown,
241    ShowConflicts,
242    BestEffort,
243}
244
245#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
246pub struct TemporalIncludeOptions {
247    pub evidence: bool,
248    pub relations: bool,
249    pub raw_refs: bool,
250}
251
252#[derive(Debug, Clone, PartialEq)]
253pub struct TemporalMemoryResult {
254    pub traversal: kmp_domain::TemporalTraversalResult,
255    pub source_bundle: kmp_domain::KmpBundle,
256    pub include: TemporalIncludeOptions,
257    pub quality: kmp_domain::BundleQualityMetrics,
258}