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 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 pub answer_policy: MemoryAnswerPolicy,
157 pub dimensions: DimensionSelection,
158 pub token_budget: u32,
159 pub depth: u32,
160 pub max_tier: Option<ResolutionTier>,
161 pub max_entries: Option<usize>,
163}
164
165#[derive(Debug, Clone, PartialEq, Eq)]
166pub struct TemporalMemoryQuery {
167 pub about: String,
168 pub direction: TemporalDirection,
169 pub axis: TemporalAxis,
170 pub cursor: TemporalCursor,
171 pub dimensions: DimensionSelection,
172 pub window: TemporalWindow,
173 pub limit_entries: Option<usize>,
174 pub include: TemporalIncludeOptions,
175 pub token_budget: u32,
176 pub depth: u32,
177 pub max_tier: Option<ResolutionTier>,
178}
179
180#[derive(Debug, Clone, PartialEq, Eq)]
181pub struct TraceMemoryQuery {
182 pub about: String,
183 pub from: String,
184 pub to: String,
185 pub role: String,
186 pub token_budget: u32,
187 pub page: TracePageRequest,
188}
189
190#[derive(Debug, Clone, PartialEq, Eq, Default)]
191pub struct TracePageRequest {
192 pub entries: Option<usize>,
193 pub cursor: Option<usize>,
194}
195
196impl TracePageRequest {
197 pub fn offset(&self) -> usize {
198 self.cursor.unwrap_or_default()
199 }
200
201 pub fn entries_or_default(&self) -> usize {
202 self.entries.unwrap_or(DEFAULT_TRACE_PAGE_ENTRIES)
203 }
204}
205
206#[derive(Debug, Clone, PartialEq, Eq)]
207pub struct InspectMemoryQuery {
208 pub about: String,
209 pub ref_id: String,
210 pub include_details: bool,
211 pub include_incoming: bool,
212 pub include_outgoing: bool,
213 pub include_raw: bool,
214}
215
216#[derive(Clone, PartialEq, Eq)]
217pub struct InspectMemoryResult {
218 pub detail: GetNodeDetailResult,
219 pub incoming: Vec<GraphRelationshipView>,
220 pub outgoing: Vec<GraphRelationshipView>,
221 pub evidence: Vec<InspectedEvidence>,
222 pub raw_coordinates: Vec<TemporalCoordinate>,
223 pub include_details: bool,
224 pub include_raw: bool,
225}
226
227#[derive(Clone, PartialEq, Eq)]
228pub struct InspectedEvidence {
229 pub detail: GetNodeDetailResult,
230 pub supports: Vec<String>,
231}
232
233#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
234pub enum MemoryAnswerPolicy {
235 #[default]
236 EvidenceOrUnknown,
237 ShowConflicts,
238 BestEffort,
239}
240
241#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
242pub struct TemporalIncludeOptions {
243 pub evidence: bool,
244 pub relations: bool,
245 pub raw_refs: bool,
246}
247
248#[derive(Debug, Clone, PartialEq)]
249pub struct TemporalMemoryResult {
250 pub traversal: kmp_domain::TemporalTraversalResult,
251 pub source_bundle: kmp_domain::KmpBundle,
252 pub include: TemporalIncludeOptions,
253 pub quality: kmp_domain::BundleQualityMetrics,
254}