1use serde::{Deserialize, Serialize};
7
8use crate::error::Result;
9use crate::DakeraClient;
10
11#[derive(Debug, Clone, Serialize, Deserialize, Default)]
17pub enum MemoryType {
18 #[default]
19 Episodic,
20 Semantic,
21 Procedural,
22 Working,
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize)]
27pub struct StoreMemoryRequest {
28 pub agent_id: String,
29 pub content: String,
30 #[serde(default)]
31 pub memory_type: MemoryType,
32 #[serde(default = "default_importance")]
33 pub importance: f32,
34 #[serde(default)]
35 pub tags: Vec<String>,
36 #[serde(skip_serializing_if = "Option::is_none")]
37 pub session_id: Option<String>,
38 #[serde(skip_serializing_if = "Option::is_none")]
39 pub metadata: Option<serde_json::Value>,
40}
41
42fn default_importance() -> f32 {
43 0.5
44}
45
46impl StoreMemoryRequest {
47 pub fn new(agent_id: impl Into<String>, content: impl Into<String>) -> Self {
49 Self {
50 agent_id: agent_id.into(),
51 content: content.into(),
52 memory_type: MemoryType::default(),
53 importance: 0.5,
54 tags: Vec::new(),
55 session_id: None,
56 metadata: None,
57 }
58 }
59
60 pub fn with_type(mut self, memory_type: MemoryType) -> Self {
62 self.memory_type = memory_type;
63 self
64 }
65
66 pub fn with_importance(mut self, importance: f32) -> Self {
68 self.importance = importance.clamp(0.0, 1.0);
69 self
70 }
71
72 pub fn with_tags(mut self, tags: Vec<String>) -> Self {
74 self.tags = tags;
75 self
76 }
77
78 pub fn with_session(mut self, session_id: impl Into<String>) -> Self {
80 self.session_id = Some(session_id.into());
81 self
82 }
83
84 pub fn with_metadata(mut self, metadata: serde_json::Value) -> Self {
86 self.metadata = Some(metadata);
87 self
88 }
89}
90
91#[derive(Debug, Clone, Serialize, Deserialize)]
93pub struct StoreMemoryResponse {
94 pub memory_id: String,
95 pub agent_id: String,
96 pub namespace: String,
97}
98
99#[derive(Debug, Clone, Serialize, Deserialize)]
101pub struct RecallRequest {
102 pub agent_id: String,
103 pub query: String,
104 #[serde(default = "default_top_k")]
105 pub top_k: usize,
106 #[serde(skip_serializing_if = "Option::is_none")]
107 pub memory_type: Option<MemoryType>,
108 #[serde(default)]
109 pub min_importance: f32,
110 #[serde(skip_serializing_if = "Option::is_none")]
111 pub session_id: Option<String>,
112 #[serde(default)]
113 pub tags: Vec<String>,
114}
115
116fn default_top_k() -> usize {
117 5
118}
119
120impl RecallRequest {
121 pub fn new(agent_id: impl Into<String>, query: impl Into<String>) -> Self {
123 Self {
124 agent_id: agent_id.into(),
125 query: query.into(),
126 top_k: 5,
127 memory_type: None,
128 min_importance: 0.0,
129 session_id: None,
130 tags: Vec::new(),
131 }
132 }
133
134 pub fn with_top_k(mut self, top_k: usize) -> Self {
136 self.top_k = top_k;
137 self
138 }
139
140 pub fn with_type(mut self, memory_type: MemoryType) -> Self {
142 self.memory_type = Some(memory_type);
143 self
144 }
145
146 pub fn with_min_importance(mut self, min: f32) -> Self {
148 self.min_importance = min;
149 self
150 }
151
152 pub fn with_session(mut self, session_id: impl Into<String>) -> Self {
154 self.session_id = Some(session_id.into());
155 self
156 }
157
158 pub fn with_tags(mut self, tags: Vec<String>) -> Self {
160 self.tags = tags;
161 self
162 }
163}
164
165#[derive(Debug, Clone, Serialize, Deserialize)]
167pub struct RecalledMemory {
168 pub id: String,
169 pub content: String,
170 pub memory_type: MemoryType,
171 pub importance: f32,
172 pub score: f32,
173 #[serde(default)]
174 pub tags: Vec<String>,
175 #[serde(skip_serializing_if = "Option::is_none")]
176 pub session_id: Option<String>,
177 #[serde(skip_serializing_if = "Option::is_none")]
178 pub metadata: Option<serde_json::Value>,
179 pub created_at: u64,
180 pub last_accessed_at: u64,
181 pub access_count: u32,
182}
183
184#[derive(Debug, Clone, Serialize, Deserialize)]
186pub struct RecallResponse {
187 pub memories: Vec<RecalledMemory>,
188 pub total_found: usize,
189}
190
191#[derive(Debug, Clone, Serialize, Deserialize)]
193pub struct ForgetRequest {
194 pub agent_id: String,
195 #[serde(default)]
196 pub memory_ids: Vec<String>,
197 #[serde(default)]
198 pub tags: Vec<String>,
199 #[serde(skip_serializing_if = "Option::is_none")]
200 pub session_id: Option<String>,
201 #[serde(skip_serializing_if = "Option::is_none")]
202 pub before_timestamp: Option<u64>,
203}
204
205impl ForgetRequest {
206 pub fn by_ids(agent_id: impl Into<String>, ids: Vec<String>) -> Self {
208 Self {
209 agent_id: agent_id.into(),
210 memory_ids: ids,
211 tags: Vec::new(),
212 session_id: None,
213 before_timestamp: None,
214 }
215 }
216
217 pub fn by_tags(agent_id: impl Into<String>, tags: Vec<String>) -> Self {
219 Self {
220 agent_id: agent_id.into(),
221 memory_ids: Vec::new(),
222 tags,
223 session_id: None,
224 before_timestamp: None,
225 }
226 }
227
228 pub fn by_session(agent_id: impl Into<String>, session_id: impl Into<String>) -> Self {
230 Self {
231 agent_id: agent_id.into(),
232 memory_ids: Vec::new(),
233 tags: Vec::new(),
234 session_id: Some(session_id.into()),
235 before_timestamp: None,
236 }
237 }
238}
239
240#[derive(Debug, Clone, Serialize, Deserialize)]
242pub struct ForgetResponse {
243 pub deleted_count: u64,
244}
245
246#[derive(Debug, Clone, Serialize, Deserialize)]
248pub struct SessionStartRequest {
249 pub agent_id: String,
250 #[serde(skip_serializing_if = "Option::is_none")]
251 pub metadata: Option<serde_json::Value>,
252}
253
254#[derive(Debug, Clone, Serialize, Deserialize)]
256pub struct Session {
257 pub id: String,
258 pub agent_id: String,
259 pub started_at: u64,
260 #[serde(skip_serializing_if = "Option::is_none")]
261 pub ended_at: Option<u64>,
262 #[serde(skip_serializing_if = "Option::is_none")]
263 pub summary: Option<String>,
264 #[serde(skip_serializing_if = "Option::is_none")]
265 pub metadata: Option<serde_json::Value>,
266}
267
268#[derive(Debug, Clone, Serialize, Deserialize)]
270pub struct SessionEndRequest {
271 #[serde(skip_serializing_if = "Option::is_none")]
272 pub summary: Option<String>,
273}
274
275#[derive(Debug, Clone, Serialize, Deserialize)]
277pub struct UpdateMemoryRequest {
278 #[serde(skip_serializing_if = "Option::is_none")]
279 pub content: Option<String>,
280 #[serde(skip_serializing_if = "Option::is_none")]
281 pub metadata: Option<serde_json::Value>,
282 #[serde(skip_serializing_if = "Option::is_none")]
283 pub memory_type: Option<MemoryType>,
284}
285
286#[derive(Debug, Clone, Serialize, Deserialize)]
288pub struct UpdateImportanceRequest {
289 pub memory_ids: Vec<String>,
290 pub importance: f32,
291}
292
293#[derive(Debug, Clone, Serialize, Deserialize)]
295pub struct ConsolidateRequest {
296 #[serde(skip_serializing_if = "Option::is_none")]
297 pub memory_type: Option<String>,
298 #[serde(skip_serializing_if = "Option::is_none")]
299 pub threshold: Option<f32>,
300 #[serde(default)]
301 pub dry_run: bool,
302}
303
304#[derive(Debug, Clone, Serialize, Deserialize)]
306pub struct ConsolidateResponse {
307 pub consolidated_count: usize,
308 pub removed_count: usize,
309 pub new_memories: Vec<String>,
310}
311
312#[derive(Debug, Clone, Serialize, Deserialize)]
314pub struct FeedbackRequest {
315 pub memory_id: String,
316 pub feedback: String,
317 #[serde(skip_serializing_if = "Option::is_none")]
318 pub relevance_score: Option<f32>,
319}
320
321#[derive(Debug, Clone, Serialize, Deserialize)]
323pub struct FeedbackResponse {
324 pub status: String,
325 pub updated_importance: Option<f32>,
326}
327
328#[derive(Debug, Clone, Serialize, Deserialize, Default)]
337pub struct BatchMemoryFilter {
338 #[serde(skip_serializing_if = "Option::is_none")]
340 pub tags: Option<Vec<String>>,
341 #[serde(skip_serializing_if = "Option::is_none")]
343 pub min_importance: Option<f32>,
344 #[serde(skip_serializing_if = "Option::is_none")]
346 pub max_importance: Option<f32>,
347 #[serde(skip_serializing_if = "Option::is_none")]
349 pub created_after: Option<u64>,
350 #[serde(skip_serializing_if = "Option::is_none")]
352 pub created_before: Option<u64>,
353 #[serde(skip_serializing_if = "Option::is_none")]
355 pub memory_type: Option<MemoryType>,
356 #[serde(skip_serializing_if = "Option::is_none")]
358 pub session_id: Option<String>,
359}
360
361impl BatchMemoryFilter {
362 pub fn with_tags(mut self, tags: Vec<String>) -> Self {
364 self.tags = Some(tags);
365 self
366 }
367
368 pub fn with_min_importance(mut self, min: f32) -> Self {
370 self.min_importance = Some(min);
371 self
372 }
373
374 pub fn with_max_importance(mut self, max: f32) -> Self {
376 self.max_importance = Some(max);
377 self
378 }
379
380 pub fn with_session(mut self, session_id: impl Into<String>) -> Self {
382 self.session_id = Some(session_id.into());
383 self
384 }
385}
386
387#[derive(Debug, Clone, Serialize, Deserialize)]
389pub struct BatchRecallRequest {
390 pub agent_id: String,
392 #[serde(default)]
394 pub filter: BatchMemoryFilter,
395 #[serde(default = "default_batch_limit")]
397 pub limit: usize,
398}
399
400fn default_batch_limit() -> usize {
401 100
402}
403
404impl BatchRecallRequest {
405 pub fn new(agent_id: impl Into<String>) -> Self {
407 Self {
408 agent_id: agent_id.into(),
409 filter: BatchMemoryFilter::default(),
410 limit: 100,
411 }
412 }
413
414 pub fn with_filter(mut self, filter: BatchMemoryFilter) -> Self {
416 self.filter = filter;
417 self
418 }
419
420 pub fn with_limit(mut self, limit: usize) -> Self {
422 self.limit = limit;
423 self
424 }
425}
426
427#[derive(Debug, Clone, Serialize, Deserialize)]
429pub struct BatchRecallResponse {
430 pub memories: Vec<RecalledMemory>,
431 pub total: usize,
433 pub filtered: usize,
435}
436
437#[derive(Debug, Clone, Serialize, Deserialize)]
439pub struct BatchForgetRequest {
440 pub agent_id: String,
442 pub filter: BatchMemoryFilter,
444}
445
446impl BatchForgetRequest {
447 pub fn new(agent_id: impl Into<String>, filter: BatchMemoryFilter) -> Self {
449 Self {
450 agent_id: agent_id.into(),
451 filter,
452 }
453 }
454}
455
456#[derive(Debug, Clone, Serialize, Deserialize)]
458pub struct BatchForgetResponse {
459 pub deleted_count: usize,
460}
461
462impl DakeraClient {
467 pub async fn store_memory(&self, request: StoreMemoryRequest) -> Result<StoreMemoryResponse> {
491 let url = format!("{}/v1/memory/store", self.base_url);
492 let response = self.client.post(&url).json(&request).send().await?;
493 self.handle_response(response).await
494 }
495
496 pub async fn recall(&self, request: RecallRequest) -> Result<RecallResponse> {
517 let url = format!("{}/v1/memory/recall", self.base_url);
518 let response = self.client.post(&url).json(&request).send().await?;
519 self.handle_response(response).await
520 }
521
522 pub async fn recall_simple(
524 &self,
525 agent_id: &str,
526 query: &str,
527 top_k: usize,
528 ) -> Result<RecallResponse> {
529 self.recall(RecallRequest::new(agent_id, query).with_top_k(top_k))
530 .await
531 }
532
533 pub async fn get_memory(&self, memory_id: &str) -> Result<RecalledMemory> {
535 let url = format!("{}/v1/memory/get/{}", self.base_url, memory_id);
536 let response = self.client.get(&url).send().await?;
537 self.handle_response(response).await
538 }
539
540 pub async fn forget(&self, request: ForgetRequest) -> Result<ForgetResponse> {
542 let url = format!("{}/v1/memory/forget", self.base_url);
543 let response = self.client.post(&url).json(&request).send().await?;
544 self.handle_response(response).await
545 }
546
547 pub async fn search_memories(&self, request: RecallRequest) -> Result<RecallResponse> {
549 let url = format!("{}/v1/memory/search", self.base_url);
550 let response = self.client.post(&url).json(&request).send().await?;
551 self.handle_response(response).await
552 }
553
554 pub async fn update_memory(
556 &self,
557 agent_id: &str,
558 memory_id: &str,
559 request: UpdateMemoryRequest,
560 ) -> Result<StoreMemoryResponse> {
561 let url = format!(
562 "{}/v1/agents/{}/memories/{}",
563 self.base_url, agent_id, memory_id
564 );
565 let response = self.client.put(&url).json(&request).send().await?;
566 self.handle_response(response).await
567 }
568
569 pub async fn update_importance(
571 &self,
572 agent_id: &str,
573 request: UpdateImportanceRequest,
574 ) -> Result<serde_json::Value> {
575 let url = format!(
576 "{}/v1/agents/{}/memories/importance",
577 self.base_url, agent_id
578 );
579 let response = self.client.put(&url).json(&request).send().await?;
580 self.handle_response(response).await
581 }
582
583 pub async fn consolidate(
585 &self,
586 agent_id: &str,
587 request: ConsolidateRequest,
588 ) -> Result<ConsolidateResponse> {
589 let url = format!(
590 "{}/v1/agents/{}/memories/consolidate",
591 self.base_url, agent_id
592 );
593 let response = self.client.post(&url).json(&request).send().await?;
594 self.handle_response(response).await
595 }
596
597 pub async fn memory_feedback(
599 &self,
600 agent_id: &str,
601 request: FeedbackRequest,
602 ) -> Result<FeedbackResponse> {
603 let url = format!("{}/v1/agents/{}/memories/feedback", self.base_url, agent_id);
604 let response = self.client.post(&url).json(&request).send().await?;
605 self.handle_response(response).await
606 }
607
608 pub async fn start_session(&self, agent_id: &str) -> Result<Session> {
614 let url = format!("{}/v1/sessions/start", self.base_url);
615 let request = SessionStartRequest {
616 agent_id: agent_id.to_string(),
617 metadata: None,
618 };
619 let response = self.client.post(&url).json(&request).send().await?;
620 self.handle_response(response).await
621 }
622
623 pub async fn start_session_with_metadata(
625 &self,
626 agent_id: &str,
627 metadata: serde_json::Value,
628 ) -> Result<Session> {
629 let url = format!("{}/v1/sessions/start", self.base_url);
630 let request = SessionStartRequest {
631 agent_id: agent_id.to_string(),
632 metadata: Some(metadata),
633 };
634 let response = self.client.post(&url).json(&request).send().await?;
635 self.handle_response(response).await
636 }
637
638 pub async fn end_session(&self, session_id: &str, summary: Option<String>) -> Result<Session> {
640 let url = format!("{}/v1/sessions/{}/end", self.base_url, session_id);
641 let request = SessionEndRequest { summary };
642 let response = self.client.post(&url).json(&request).send().await?;
643 self.handle_response(response).await
644 }
645
646 pub async fn get_session(&self, session_id: &str) -> Result<Session> {
648 let url = format!("{}/v1/sessions/{}", self.base_url, session_id);
649 let response = self.client.get(&url).send().await?;
650 self.handle_response(response).await
651 }
652
653 pub async fn list_sessions(&self, agent_id: &str) -> Result<Vec<Session>> {
655 let url = format!("{}/v1/sessions?agent_id={}", self.base_url, agent_id);
656 let response = self.client.get(&url).send().await?;
657 self.handle_response(response).await
658 }
659
660 pub async fn session_memories(&self, session_id: &str) -> Result<RecallResponse> {
662 let url = format!("{}/v1/sessions/{}/memories", self.base_url, session_id);
663 let response = self.client.get(&url).send().await?;
664 self.handle_response(response).await
665 }
666
667 pub async fn batch_recall(&self, request: BatchRecallRequest) -> Result<BatchRecallResponse> {
691 let url = format!("{}/v1/memories/recall/batch", self.base_url);
692 let response = self.client.post(&url).json(&request).send().await?;
693 self.handle_response(response).await
694 }
695
696 pub async fn batch_forget(&self, request: BatchForgetRequest) -> Result<BatchForgetResponse> {
716 let url = format!("{}/v1/memories/forget/batch", self.base_url);
717 let response = self.client.delete(&url).json(&request).send().await?;
718 self.handle_response(response).await
719 }
720}