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;
9pub 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 pub label_policy: LabelPolicy,
24}
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
30pub enum LabelPolicy {
31 #[default]
34 Warn,
35 Refuse,
38}
39
40#[derive(Debug, Clone, PartialEq, Eq)]
42pub struct ResemblingLabelData {
43 pub key: String,
44 pub value: String,
45 pub existing_key: String,
46 pub existing_value: String,
47 pub kind: String,
48 pub why: String,
49}
50
51#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)]
52pub struct MemoryData {
53 pub dimensions: Vec<MemoryDimensionData>,
54 pub entries: Vec<MemoryEntryData>,
55 pub relations: Vec<MemoryRelationData>,
56 pub evidence: Vec<MemoryEvidenceData>,
57}
58
59#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)]
60pub struct MemoryDimensionData {
61 pub id: String,
62 pub kind: String,
63 #[serde(skip_serializing_if = "Option::is_none")]
64 pub title: Option<String>,
65 #[serde(default, skip_serializing_if = "std::collections::BTreeMap::is_empty")]
66 pub metadata: std::collections::BTreeMap<String, String>,
67}
68
69#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)]
70pub struct MemoryEntryData {
71 pub id: String,
72 pub kind: String,
73 pub text: String,
74 pub coordinates: Vec<MemoryCoordinateData>,
75 #[serde(default, skip_serializing_if = "std::collections::BTreeMap::is_empty")]
76 pub metadata: std::collections::BTreeMap<String, String>,
77}
78
79#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)]
80pub struct MemoryCoordinateData {
81 pub dimension: String,
82 pub scope_id: String,
83 #[serde(skip_serializing_if = "Option::is_none")]
84 pub occurred_at: Option<String>,
85 #[serde(skip_serializing_if = "Option::is_none")]
86 pub observed_at: Option<String>,
87 #[serde(skip_serializing_if = "Option::is_none")]
88 pub ingested_at: Option<String>,
89 #[serde(skip_serializing_if = "Option::is_none")]
90 pub valid_from: Option<String>,
91 #[serde(skip_serializing_if = "Option::is_none")]
92 pub valid_until: Option<String>,
93 #[serde(skip_serializing_if = "Option::is_none")]
94 pub sequence: Option<u32>,
95 #[serde(skip_serializing_if = "Option::is_none")]
96 pub rank: Option<u32>,
97 #[serde(default, skip_serializing_if = "std::collections::BTreeMap::is_empty")]
98 pub metadata: std::collections::BTreeMap<String, String>,
99}
100
101#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)]
102pub struct MemoryRelationData {
103 #[serde(rename = "from")]
104 pub source_ref: String,
105 #[serde(rename = "to")]
106 pub target_ref: String,
107 pub rel: String,
108 #[serde(rename = "class")]
109 pub semantic_class: String,
110 #[serde(skip_serializing_if = "Option::is_none")]
111 pub why: Option<String>,
112 #[serde(skip_serializing_if = "Option::is_none")]
113 pub evidence: Option<String>,
114 #[serde(skip_serializing_if = "Option::is_none")]
115 pub confidence: Option<String>,
116 #[serde(skip_serializing_if = "Option::is_none")]
117 pub sequence: Option<u32>,
118 #[serde(skip_serializing_if = "Option::is_none")]
119 pub motivation: Option<String>,
120 #[serde(skip_serializing_if = "Option::is_none")]
121 pub method: Option<String>,
122 #[serde(skip_serializing_if = "Option::is_none")]
123 pub decision_id: Option<String>,
124 #[serde(skip_serializing_if = "Option::is_none")]
125 pub caused_by_node_id: Option<String>,
126 #[serde(skip_serializing_if = "Option::is_none")]
127 pub coordinate: Option<MemoryCoordinateData>,
128}
129
130#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)]
131pub struct MemoryEvidenceData {
132 pub id: String,
133 pub supports: Vec<String>,
134 pub text: String,
135 #[serde(skip_serializing_if = "Option::is_none")]
136 pub source: Option<String>,
137 #[serde(skip_serializing_if = "Option::is_none")]
138 pub time: Option<String>,
139 #[serde(default, skip_serializing_if = "std::collections::BTreeMap::is_empty")]
140 pub metadata: std::collections::BTreeMap<String, String>,
141}
142
143#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)]
144pub struct MemoryProvenanceData {
145 pub source_kind: String,
146 pub source_agent: String,
147 pub observed_at: String,
148 pub correlation_id: Option<String>,
149 pub causation_id: Option<String>,
150}
151
152#[derive(Debug, Clone, PartialEq, Eq)]
153pub struct MemoryAcceptedCounts {
154 pub entries: usize,
155 pub relations: usize,
156 pub evidence: usize,
157}
158
159#[derive(Debug, Clone, PartialEq, Eq)]
160pub struct MemoryIngestOutcome {
161 pub about: String,
162 pub memory_id: String,
163 pub accepted: MemoryAcceptedCounts,
164 pub read_after_write_ready: bool,
165 pub warnings: Vec<String>,
166 pub created_dimensions: Vec<String>,
169 pub resembling_labels: Vec<ResemblingLabelData>,
172}
173
174#[derive(Debug, Clone, PartialEq, Eq)]
175pub struct WakeMemoryQuery {
176 pub about: String,
177 pub role: String,
178 pub intent: String,
179 pub dimensions: DimensionSelection,
180 pub token_budget: u32,
181 pub depth: u32,
182 pub max_tier: Option<ResolutionTier>,
183 pub max_entries: Option<usize>,
187 pub temporal: TemporalSelection,
190}
191
192#[derive(Debug, Clone, PartialEq, Eq)]
193pub struct AskMemoryQuery {
194 pub about: String,
195 pub question: String,
196 pub asked_as: Option<String>,
200 pub answer_policy: MemoryAnswerPolicy,
201 pub dimensions: DimensionSelection,
202 pub token_budget: u32,
203 pub depth: u32,
204 pub max_tier: Option<ResolutionTier>,
205 pub max_entries: Option<usize>,
207 pub temporal: TemporalSelection,
211}
212
213#[derive(Debug, Clone, PartialEq, Eq)]
214pub struct TemporalMemoryQuery {
215 pub about: String,
216 pub direction: TemporalDirection,
217 pub axis: TemporalAxis,
218 pub cursor: TemporalCursor,
219 pub dimensions: DimensionSelection,
220 pub window: TemporalWindow,
221 pub limit_entries: Option<usize>,
222 pub include: TemporalIncludeOptions,
223 pub token_budget: u32,
224 pub depth: u32,
225 pub max_tier: Option<ResolutionTier>,
226}
227
228#[derive(Debug, Clone, PartialEq, Eq)]
231pub struct RelateMemoryQuery {
232 pub about: String,
233 pub dimensions: DimensionSelection,
234 pub temporal: TemporalSelection,
237 pub token_budget: u32,
238 pub depth: u32,
239 pub max_tier: Option<ResolutionTier>,
240 pub page: RelatePageRequest,
241}
242
243#[derive(Debug, Clone, PartialEq, Eq, Default)]
244pub struct RelatePageRequest {
245 pub entries: Option<usize>,
246 pub cursor: Option<usize>,
247}
248
249impl RelatePageRequest {
250 pub fn offset(&self) -> usize {
251 self.cursor.unwrap_or_default()
252 }
253
254 pub fn entries_or_default(&self) -> usize {
255 self.entries.unwrap_or(DEFAULT_RELATE_PAGE_ENTRIES)
256 }
257}
258
259#[derive(Debug, Clone, PartialEq, Eq)]
260pub struct TraceMemoryQuery {
261 pub about: String,
262 pub from: String,
263 pub to: String,
264 pub role: String,
265 pub token_budget: u32,
266 pub page: TracePageRequest,
267}
268
269#[derive(Debug, Clone, PartialEq, Eq, Default)]
270pub struct TracePageRequest {
271 pub entries: Option<usize>,
272 pub cursor: Option<usize>,
273}
274
275impl TracePageRequest {
276 pub fn offset(&self) -> usize {
277 self.cursor.unwrap_or_default()
278 }
279
280 pub fn entries_or_default(&self) -> usize {
281 self.entries.unwrap_or(DEFAULT_TRACE_PAGE_ENTRIES)
282 }
283}
284
285#[derive(Debug, Clone, PartialEq, Eq)]
286pub struct InspectMemoryQuery {
287 pub about: String,
288 pub ref_id: String,
289 pub include_details: bool,
290 pub include_incoming: bool,
291 pub include_outgoing: bool,
292 pub include_raw: bool,
293}
294
295#[derive(Clone, PartialEq, Eq)]
296pub struct InspectMemoryResult {
297 pub detail: GetNodeDetailResult,
298 pub incoming: Vec<GraphRelationshipView>,
299 pub outgoing: Vec<GraphRelationshipView>,
300 pub evidence: Vec<InspectedEvidence>,
301 pub raw_coordinates: Vec<TemporalCoordinate>,
302 pub include_details: bool,
303 pub include_raw: bool,
304}
305
306#[derive(Clone, PartialEq, Eq)]
307pub struct InspectedEvidence {
308 pub detail: GetNodeDetailResult,
309 pub supports: Vec<String>,
310}
311
312#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
313pub enum MemoryAnswerPolicy {
314 #[default]
315 EvidenceOrUnknown,
316 ShowConflicts,
317 BestEffort,
318}
319
320#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
321pub struct TemporalIncludeOptions {
322 pub evidence: bool,
323 pub relations: bool,
324 pub raw_refs: bool,
325}
326
327#[derive(Debug, Clone, PartialEq)]
328pub struct TemporalMemoryResult {
329 pub traversal: kmp_domain::TemporalTraversalResult,
330 pub source_bundle: kmp_domain::KmpBundle,
331 pub include: TemporalIncludeOptions,
332 pub quality: kmp_domain::BundleQualityMetrics,
333}
334
335#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, serde::Serialize)]
338pub struct EntryLabelData {
339 pub key: String,
340 pub value: String,
341}
342
343#[derive(Debug, Clone, PartialEq, Eq)]
347pub struct MemoryRelabelCommand {
348 pub about: String,
349 pub ref_id: String,
350 pub add: Vec<EntryLabelData>,
351 pub remove: Vec<EntryLabelData>,
352 pub why: String,
353 pub provenance: Option<MemoryProvenanceData>,
354 pub idempotency_key: String,
355 pub dry_run: bool,
356 pub label_policy: LabelPolicy,
357 pub intended_new: std::collections::BTreeSet<String>,
361}
362
363#[derive(Debug, Clone, PartialEq, Eq)]
364pub struct MemoryRelabelOutcome {
365 pub about: String,
366 pub ref_id: String,
367 pub added: Vec<EntryLabelData>,
368 pub removed: Vec<EntryLabelData>,
369 pub labels: Vec<EntryLabelData>,
371 pub created_dimensions: Vec<String>,
374 pub resembling_labels: Vec<ResemblingLabelData>,
377 pub read_after_write_ready: bool,
378 pub warnings: Vec<String>,
379}