Skip to main content

kmp_application/memory/
types.rs

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