1use serde::{Deserialize, Serialize};
7
8use crate::error::Result;
9use crate::types::{
10 AgentFeedbackSummary, EdgeType, FeedbackHealthResponse, FeedbackHistoryResponse,
11 FeedbackResponse, FeedbackSignal, GraphExport, GraphLinkRequest, GraphLinkResponse,
12 GraphOptions, GraphPath, MemoryFeedbackBody, MemoryGraph, MemoryImportancePatch,
13};
14use crate::DakeraClient;
15
16#[derive(Debug, Clone, Serialize, Deserialize, Default)]
22#[serde(rename_all = "lowercase")]
23pub enum MemoryType {
24 #[default]
25 Episodic,
26 Semantic,
27 Procedural,
28 Working,
29}
30
31#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct StoreMemoryRequest {
34 pub agent_id: String,
35 pub content: String,
36 #[serde(default)]
37 pub memory_type: MemoryType,
38 #[serde(default = "default_importance")]
39 pub importance: f32,
40 #[serde(default)]
41 pub tags: Vec<String>,
42 #[serde(skip_serializing_if = "Option::is_none")]
43 pub session_id: Option<String>,
44 #[serde(skip_serializing_if = "Option::is_none")]
45 pub metadata: Option<serde_json::Value>,
46 #[serde(skip_serializing_if = "Option::is_none")]
49 pub ttl_seconds: Option<u64>,
50 #[serde(skip_serializing_if = "Option::is_none")]
54 pub expires_at: Option<u64>,
55}
56
57fn default_importance() -> f32 {
58 0.5
59}
60
61impl StoreMemoryRequest {
62 pub fn new(agent_id: impl Into<String>, content: impl Into<String>) -> Self {
64 Self {
65 agent_id: agent_id.into(),
66 content: content.into(),
67 memory_type: MemoryType::default(),
68 importance: 0.5,
69 tags: Vec::new(),
70 session_id: None,
71 metadata: None,
72 ttl_seconds: None,
73 expires_at: None,
74 }
75 }
76
77 pub fn with_type(mut self, memory_type: MemoryType) -> Self {
79 self.memory_type = memory_type;
80 self
81 }
82
83 pub fn with_importance(mut self, importance: f32) -> Self {
85 self.importance = importance.clamp(0.0, 1.0);
86 self
87 }
88
89 pub fn with_tags(mut self, tags: Vec<String>) -> Self {
91 self.tags = tags;
92 self
93 }
94
95 pub fn with_session(mut self, session_id: impl Into<String>) -> Self {
97 self.session_id = Some(session_id.into());
98 self
99 }
100
101 pub fn with_metadata(mut self, metadata: serde_json::Value) -> Self {
103 self.metadata = Some(metadata);
104 self
105 }
106
107 pub fn with_ttl(mut self, ttl_seconds: u64) -> Self {
110 self.ttl_seconds = Some(ttl_seconds);
111 self
112 }
113
114 pub fn with_expires_at(mut self, expires_at: u64) -> Self {
117 self.expires_at = Some(expires_at);
118 self
119 }
120}
121
122#[derive(Debug, Clone, Serialize)]
129pub struct StoreMemoryResponse {
130 pub memory_id: String,
132 pub agent_id: String,
134 pub namespace: String,
136 pub embedding_time_ms: Option<u64>,
138}
139
140impl<'de> serde::Deserialize<'de> for StoreMemoryResponse {
141 fn deserialize<D: serde::Deserializer<'de>>(
142 deserializer: D,
143 ) -> std::result::Result<Self, D::Error> {
144 use serde::de::Error;
145 let val = serde_json::Value::deserialize(deserializer)?;
146
147 if let Some(memory) = val.get("memory") {
149 let memory_id = memory
150 .get("id")
151 .and_then(|v| v.as_str())
152 .ok_or_else(|| D::Error::missing_field("memory.id"))?
153 .to_string();
154 let agent_id = memory
155 .get("agent_id")
156 .and_then(|v| v.as_str())
157 .unwrap_or("")
158 .to_string();
159 let namespace = memory
160 .get("namespace")
161 .and_then(|v| v.as_str())
162 .unwrap_or("default")
163 .to_string();
164 let embedding_time_ms = val.get("embedding_time_ms").and_then(|v| v.as_u64());
165 return Ok(Self {
166 memory_id,
167 agent_id,
168 namespace,
169 embedding_time_ms,
170 });
171 }
172
173 let memory_id = val
175 .get("memory_id")
176 .and_then(|v| v.as_str())
177 .ok_or_else(|| D::Error::missing_field("memory_id"))?
178 .to_string();
179 let agent_id = val
180 .get("agent_id")
181 .and_then(|v| v.as_str())
182 .unwrap_or("")
183 .to_string();
184 let namespace = val
185 .get("namespace")
186 .and_then(|v| v.as_str())
187 .unwrap_or("default")
188 .to_string();
189 Ok(Self {
190 memory_id,
191 agent_id,
192 namespace,
193 embedding_time_ms: None,
194 })
195 }
196}
197
198#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
203#[serde(rename_all = "snake_case")]
204pub enum RoutingMode {
205 Auto,
207 Vector,
209 Bm25,
211 Hybrid,
213}
214
215#[derive(Debug, Clone, Serialize, Deserialize)]
217pub struct RecallRequest {
218 pub agent_id: String,
219 pub query: String,
220 #[serde(default = "default_top_k")]
221 pub top_k: usize,
222 #[serde(skip_serializing_if = "Option::is_none")]
223 pub memory_type: Option<MemoryType>,
224 #[serde(default)]
225 pub min_importance: f32,
226 #[serde(skip_serializing_if = "Option::is_none")]
227 pub session_id: Option<String>,
228 #[serde(default)]
229 pub tags: Vec<String>,
230 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
233 pub include_associated: bool,
234 #[serde(skip_serializing_if = "Option::is_none")]
236 pub associated_memories_cap: Option<u32>,
237 #[serde(skip_serializing_if = "Option::is_none")]
239 pub associated_memories_depth: Option<u8>,
240 #[serde(skip_serializing_if = "Option::is_none")]
242 pub associated_memories_min_weight: Option<f32>,
243 #[serde(skip_serializing_if = "Option::is_none")]
245 pub since: Option<String>,
246 #[serde(skip_serializing_if = "Option::is_none")]
248 pub until: Option<String>,
249 #[serde(skip_serializing_if = "Option::is_none")]
251 pub routing: Option<RoutingMode>,
252 #[serde(skip_serializing_if = "Option::is_none")]
255 pub rerank: Option<bool>,
256}
257
258fn default_top_k() -> usize {
259 5
260}
261
262impl RecallRequest {
263 pub fn new(agent_id: impl Into<String>, query: impl Into<String>) -> Self {
265 Self {
266 agent_id: agent_id.into(),
267 query: query.into(),
268 top_k: 5,
269 memory_type: None,
270 min_importance: 0.0,
271 session_id: None,
272 tags: Vec::new(),
273 include_associated: false,
274 associated_memories_cap: None,
275 associated_memories_depth: None,
276 associated_memories_min_weight: None,
277 since: None,
278 until: None,
279 routing: None,
280 rerank: None,
281 }
282 }
283
284 pub fn with_top_k(mut self, top_k: usize) -> Self {
286 self.top_k = top_k;
287 self
288 }
289
290 pub fn with_type(mut self, memory_type: MemoryType) -> Self {
292 self.memory_type = Some(memory_type);
293 self
294 }
295
296 pub fn with_min_importance(mut self, min: f32) -> Self {
298 self.min_importance = min;
299 self
300 }
301
302 pub fn with_session(mut self, session_id: impl Into<String>) -> Self {
304 self.session_id = Some(session_id.into());
305 self
306 }
307
308 pub fn with_tags(mut self, tags: Vec<String>) -> Self {
310 self.tags = tags;
311 self
312 }
313
314 pub fn with_associated(mut self) -> Self {
316 self.include_associated = true;
317 self
318 }
319
320 pub fn with_associated_cap(mut self, cap: u32) -> Self {
322 self.include_associated = true;
323 self.associated_memories_cap = Some(cap);
324 self
325 }
326
327 pub fn with_since(mut self, since: impl Into<String>) -> Self {
329 self.since = Some(since.into());
330 self
331 }
332
333 pub fn with_until(mut self, until: impl Into<String>) -> Self {
335 self.until = Some(until.into());
336 self
337 }
338
339 pub fn with_routing(mut self, routing: RoutingMode) -> Self {
341 self.routing = Some(routing);
342 self
343 }
344
345 pub fn with_rerank(mut self, rerank: bool) -> Self {
347 self.rerank = Some(rerank);
348 self
349 }
350
351 pub fn with_associated_depth(mut self, depth: u8) -> Self {
353 self.include_associated = true;
354 self.associated_memories_depth = Some(depth);
355 self
356 }
357
358 pub fn with_associated_min_weight(mut self, weight: f32) -> Self {
360 self.associated_memories_min_weight = Some(weight);
361 self
362 }
363}
364
365#[derive(Debug, Clone, Serialize)]
367pub struct RecalledMemory {
368 pub id: String,
369 pub content: String,
370 pub memory_type: MemoryType,
371 pub importance: f32,
372 pub score: f32,
373 #[serde(default)]
374 pub tags: Vec<String>,
375 #[serde(skip_serializing_if = "Option::is_none")]
376 pub session_id: Option<String>,
377 #[serde(skip_serializing_if = "Option::is_none")]
378 pub metadata: Option<serde_json::Value>,
379 pub created_at: u64,
380 pub last_accessed_at: u64,
381 pub access_count: u32,
382 #[serde(skip_serializing_if = "Option::is_none")]
384 pub depth: Option<u8>,
385}
386
387impl<'de> serde::Deserialize<'de> for RecalledMemory {
388 fn deserialize<D: serde::Deserializer<'de>>(
389 deserializer: D,
390 ) -> std::result::Result<Self, D::Error> {
391 use serde::de::Error as _;
392 let val = serde_json::Value::deserialize(deserializer)?;
393
394 let score = val
397 .get("score")
398 .and_then(|v| v.as_f64())
399 .or_else(|| val.get("weighted_score").and_then(|v| v.as_f64()))
400 .unwrap_or(0.0) as f32;
401
402 let mem = val.get("memory").unwrap_or(&val);
403
404 let id = mem
405 .get("id")
406 .and_then(|v| v.as_str())
407 .ok_or_else(|| D::Error::missing_field("id"))?
408 .to_string();
409 let content = mem
410 .get("content")
411 .and_then(|v| v.as_str())
412 .ok_or_else(|| D::Error::missing_field("content"))?
413 .to_string();
414 let memory_type: MemoryType = mem
415 .get("memory_type")
416 .and_then(|v| serde_json::from_value(v.clone()).ok())
417 .unwrap_or(MemoryType::Episodic);
418 let importance = mem
419 .get("importance")
420 .and_then(|v| v.as_f64())
421 .unwrap_or(0.5) as f32;
422 let tags: Vec<String> = mem
423 .get("tags")
424 .and_then(|v| serde_json::from_value(v.clone()).ok())
425 .unwrap_or_default();
426 let session_id = mem
427 .get("session_id")
428 .and_then(|v| v.as_str())
429 .map(String::from);
430 let metadata = mem.get("metadata").cloned().filter(|v| !v.is_null());
431 let created_at = mem.get("created_at").and_then(|v| v.as_u64()).unwrap_or(0);
432 let last_accessed_at = mem
433 .get("last_accessed_at")
434 .and_then(|v| v.as_u64())
435 .unwrap_or(0);
436 let access_count = mem
437 .get("access_count")
438 .and_then(|v| v.as_u64())
439 .unwrap_or(0) as u32;
440 let depth = mem.get("depth").and_then(|v| v.as_u64()).map(|v| v as u8);
441
442 Ok(Self {
443 id,
444 content,
445 memory_type,
446 importance,
447 score,
448 tags,
449 session_id,
450 metadata,
451 created_at,
452 last_accessed_at,
453 access_count,
454 depth,
455 })
456 }
457}
458
459#[derive(Debug, Clone, Serialize, Deserialize)]
461pub struct RecallResponse {
462 pub memories: Vec<RecalledMemory>,
463 #[serde(default)]
464 pub total_found: usize,
465 #[serde(skip_serializing_if = "Option::is_none")]
467 pub associated_memories: Option<Vec<RecalledMemory>>,
468}
469
470#[derive(Debug, Clone, Serialize, Deserialize)]
472pub struct ForgetRequest {
473 pub agent_id: String,
474 #[serde(default)]
475 pub memory_ids: Vec<String>,
476 #[serde(default)]
477 pub tags: Vec<String>,
478 #[serde(skip_serializing_if = "Option::is_none")]
479 pub session_id: Option<String>,
480 #[serde(skip_serializing_if = "Option::is_none")]
481 pub before_timestamp: Option<u64>,
482}
483
484impl ForgetRequest {
485 pub fn by_ids(agent_id: impl Into<String>, ids: Vec<String>) -> Self {
487 Self {
488 agent_id: agent_id.into(),
489 memory_ids: ids,
490 tags: Vec::new(),
491 session_id: None,
492 before_timestamp: None,
493 }
494 }
495
496 pub fn by_tags(agent_id: impl Into<String>, tags: Vec<String>) -> Self {
498 Self {
499 agent_id: agent_id.into(),
500 memory_ids: Vec::new(),
501 tags,
502 session_id: None,
503 before_timestamp: None,
504 }
505 }
506
507 pub fn by_session(agent_id: impl Into<String>, session_id: impl Into<String>) -> Self {
509 Self {
510 agent_id: agent_id.into(),
511 memory_ids: Vec::new(),
512 tags: Vec::new(),
513 session_id: Some(session_id.into()),
514 before_timestamp: None,
515 }
516 }
517}
518
519#[derive(Debug, Clone, Serialize, Deserialize)]
521pub struct ForgetResponse {
522 pub deleted_count: u64,
523}
524
525#[derive(Debug, Clone, Serialize, Deserialize)]
527pub struct SessionStartRequest {
528 pub agent_id: String,
529 #[serde(skip_serializing_if = "Option::is_none")]
530 pub metadata: Option<serde_json::Value>,
531}
532
533#[derive(Debug, Clone, Serialize, Deserialize)]
535pub struct Session {
536 pub id: String,
537 pub agent_id: String,
538 pub started_at: u64,
539 #[serde(skip_serializing_if = "Option::is_none")]
540 pub ended_at: Option<u64>,
541 #[serde(skip_serializing_if = "Option::is_none")]
542 pub summary: Option<String>,
543 #[serde(skip_serializing_if = "Option::is_none")]
544 pub metadata: Option<serde_json::Value>,
545 #[serde(default)]
547 pub memory_count: usize,
548}
549
550#[derive(Debug, Clone, Serialize, Deserialize)]
552pub struct SessionEndRequest {
553 #[serde(skip_serializing_if = "Option::is_none")]
554 pub summary: Option<String>,
555}
556
557#[derive(Debug, Clone, Serialize, Deserialize)]
559pub struct SessionStartResponse {
560 pub session: Session,
561}
562
563#[derive(Debug, Clone, Serialize, Deserialize)]
565pub struct SessionEndResponse {
566 pub session: Session,
567 pub memory_count: usize,
568}
569
570#[derive(Debug, Clone, Serialize, Deserialize)]
572pub struct UpdateMemoryRequest {
573 #[serde(skip_serializing_if = "Option::is_none")]
574 pub content: Option<String>,
575 #[serde(skip_serializing_if = "Option::is_none")]
576 pub metadata: Option<serde_json::Value>,
577 #[serde(skip_serializing_if = "Option::is_none")]
578 pub memory_type: Option<MemoryType>,
579}
580
581#[derive(Debug, Clone, Serialize, Deserialize)]
583pub struct UpdateImportanceRequest {
584 pub memory_ids: Vec<String>,
585 pub importance: f32,
586}
587
588#[derive(Debug, Clone, Serialize, Deserialize, Default)]
590pub struct ConsolidationConfig {
591 #[serde(skip_serializing_if = "Option::is_none")]
593 pub algorithm: Option<String>,
594 #[serde(skip_serializing_if = "Option::is_none")]
596 pub min_samples: Option<u32>,
597 #[serde(skip_serializing_if = "Option::is_none")]
599 pub eps: Option<f32>,
600}
601
602#[derive(Debug, Clone, Serialize, Deserialize)]
604pub struct ConsolidationLogEntry {
605 pub step: String,
606 pub memories_before: usize,
607 pub memories_after: usize,
608 pub duration_ms: f64,
609}
610
611#[derive(Debug, Clone, Serialize, Deserialize, Default)]
613pub struct ConsolidateRequest {
614 #[serde(skip_serializing_if = "Option::is_none")]
615 pub memory_type: Option<String>,
616 #[serde(skip_serializing_if = "Option::is_none")]
617 pub threshold: Option<f32>,
618 #[serde(default)]
619 pub dry_run: bool,
620 #[serde(skip_serializing_if = "Option::is_none")]
622 pub config: Option<ConsolidationConfig>,
623}
624
625#[derive(Debug, Clone, Serialize)]
630pub struct ConsolidateResponse {
631 pub consolidated_count: usize,
633 pub removed_count: usize,
635 #[serde(default)]
637 pub new_memories: Vec<String>,
638 #[serde(default, skip_serializing_if = "Vec::is_empty")]
640 pub log: Vec<ConsolidationLogEntry>,
641}
642
643impl<'de> serde::Deserialize<'de> for ConsolidateResponse {
644 fn deserialize<D: serde::Deserializer<'de>>(
645 deserializer: D,
646 ) -> std::result::Result<Self, D::Error> {
647 let val = serde_json::Value::deserialize(deserializer)?;
648 let removed = val
650 .get("memories_removed")
651 .and_then(|v| v.as_u64())
652 .or_else(|| val.get("removed_count").and_then(|v| v.as_u64()))
653 .or_else(|| val.get("consolidated_count").and_then(|v| v.as_u64()))
654 .unwrap_or(0) as usize;
655 let source_ids: Vec<String> = val
656 .get("source_memory_ids")
657 .and_then(|v| v.as_array())
658 .map(|arr| {
659 arr.iter()
660 .filter_map(|v| v.as_str().map(String::from))
661 .collect()
662 })
663 .unwrap_or_default();
664 Ok(Self {
665 consolidated_count: removed,
666 removed_count: removed,
667 new_memories: source_ids,
668 log: vec![],
669 })
670 }
671}
672
673#[derive(Debug, Clone, Serialize, Deserialize)]
679pub struct MemoryImportResponse {
680 pub imported_count: usize,
681 pub skipped_count: usize,
682 #[serde(default)]
683 pub errors: Vec<String>,
684}
685
686#[derive(Debug, Clone, Serialize, Deserialize)]
688pub struct MemoryExportResponse {
689 pub data: Vec<serde_json::Value>,
690 pub format: String,
691 pub count: usize,
692}
693
694#[derive(Debug, Clone, Serialize, Deserialize)]
700pub struct AuditEvent {
701 pub id: String,
702 pub event_type: String,
703 #[serde(skip_serializing_if = "Option::is_none")]
704 pub agent_id: Option<String>,
705 #[serde(skip_serializing_if = "Option::is_none")]
706 pub namespace: Option<String>,
707 pub timestamp: u64,
708 #[serde(default)]
709 pub details: serde_json::Value,
710}
711
712#[derive(Debug, Clone, Serialize, Deserialize)]
714pub struct AuditListResponse {
715 pub events: Vec<AuditEvent>,
716 pub total: usize,
717 #[serde(skip_serializing_if = "Option::is_none")]
718 pub cursor: Option<String>,
719}
720
721#[derive(Debug, Clone, Serialize, Deserialize)]
723pub struct AuditExportResponse {
724 pub data: String,
725 pub format: String,
726 pub count: usize,
727}
728
729#[derive(Debug, Clone, Serialize, Deserialize, Default)]
731pub struct AuditQuery {
732 #[serde(skip_serializing_if = "Option::is_none")]
733 pub agent_id: Option<String>,
734 #[serde(skip_serializing_if = "Option::is_none")]
735 pub event_type: Option<String>,
736 #[serde(skip_serializing_if = "Option::is_none")]
737 pub from: Option<u64>,
738 #[serde(skip_serializing_if = "Option::is_none")]
739 pub to: Option<u64>,
740 #[serde(skip_serializing_if = "Option::is_none")]
741 pub limit: Option<u32>,
742 #[serde(skip_serializing_if = "Option::is_none")]
743 pub cursor: Option<String>,
744}
745
746#[derive(Debug, Clone, Serialize, Deserialize)]
752pub struct ExtractionResult {
753 pub entities: Vec<serde_json::Value>,
754 pub provider: String,
755 #[serde(skip_serializing_if = "Option::is_none")]
756 pub model: Option<String>,
757 pub duration_ms: f64,
758}
759
760#[derive(Debug, Clone, Serialize, Deserialize)]
762pub struct ExtractionProviderInfo {
763 pub name: String,
764 pub available: bool,
765 #[serde(default)]
766 pub models: Vec<String>,
767}
768
769#[derive(Debug, Clone, Serialize, Deserialize)]
771#[serde(untagged)]
772pub enum ExtractProvidersResponse {
773 List(Vec<ExtractionProviderInfo>),
774 Object {
775 providers: Vec<ExtractionProviderInfo>,
776 },
777}
778
779#[derive(Debug, Clone, Serialize, Deserialize)]
785pub struct RotateEncryptionKeyRequest {
786 pub new_key: String,
788 #[serde(skip_serializing_if = "Option::is_none")]
790 pub namespace: Option<String>,
791}
792
793#[derive(Debug, Clone, Serialize, Deserialize)]
795pub struct RotateEncryptionKeyResponse {
796 pub rotated: usize,
797 pub skipped: usize,
798 #[serde(default)]
799 pub namespaces: Vec<String>,
800}
801
802#[derive(Debug, Clone, Serialize, Deserialize)]
804pub struct FeedbackRequest {
805 pub memory_id: String,
806 pub feedback: String,
807 #[serde(skip_serializing_if = "Option::is_none")]
808 pub relevance_score: Option<f32>,
809}
810
811#[derive(Debug, Clone, Serialize, Deserialize)]
813pub struct LegacyFeedbackResponse {
814 pub status: String,
815 pub updated_importance: Option<f32>,
816}
817
818#[derive(Debug, Clone, Serialize, Deserialize, Default)]
827pub struct BatchMemoryFilter {
828 #[serde(skip_serializing_if = "Option::is_none")]
830 pub tags: Option<Vec<String>>,
831 #[serde(skip_serializing_if = "Option::is_none")]
833 pub min_importance: Option<f32>,
834 #[serde(skip_serializing_if = "Option::is_none")]
836 pub max_importance: Option<f32>,
837 #[serde(skip_serializing_if = "Option::is_none")]
839 pub created_after: Option<u64>,
840 #[serde(skip_serializing_if = "Option::is_none")]
842 pub created_before: Option<u64>,
843 #[serde(skip_serializing_if = "Option::is_none")]
845 pub memory_type: Option<MemoryType>,
846 #[serde(skip_serializing_if = "Option::is_none")]
848 pub session_id: Option<String>,
849}
850
851impl BatchMemoryFilter {
852 pub fn with_tags(mut self, tags: Vec<String>) -> Self {
854 self.tags = Some(tags);
855 self
856 }
857
858 pub fn with_min_importance(mut self, min: f32) -> Self {
860 self.min_importance = Some(min);
861 self
862 }
863
864 pub fn with_max_importance(mut self, max: f32) -> Self {
866 self.max_importance = Some(max);
867 self
868 }
869
870 pub fn with_session(mut self, session_id: impl Into<String>) -> Self {
872 self.session_id = Some(session_id.into());
873 self
874 }
875}
876
877#[derive(Debug, Clone, Serialize, Deserialize)]
879pub struct BatchRecallRequest {
880 pub agent_id: String,
882 #[serde(default)]
884 pub filter: BatchMemoryFilter,
885 #[serde(default = "default_batch_limit")]
887 pub limit: usize,
888}
889
890fn default_batch_limit() -> usize {
891 100
892}
893
894impl BatchRecallRequest {
895 pub fn new(agent_id: impl Into<String>) -> Self {
897 Self {
898 agent_id: agent_id.into(),
899 filter: BatchMemoryFilter::default(),
900 limit: 100,
901 }
902 }
903
904 pub fn with_filter(mut self, filter: BatchMemoryFilter) -> Self {
906 self.filter = filter;
907 self
908 }
909
910 pub fn with_limit(mut self, limit: usize) -> Self {
912 self.limit = limit;
913 self
914 }
915}
916
917#[derive(Debug, Clone, Serialize, Deserialize)]
919pub struct BatchRecallResponse {
920 pub memories: Vec<RecalledMemory>,
921 pub total: usize,
923 pub filtered: usize,
925}
926
927#[derive(Debug, Clone, Serialize, Deserialize)]
929pub struct BatchForgetRequest {
930 pub agent_id: String,
932 pub filter: BatchMemoryFilter,
934}
935
936impl BatchForgetRequest {
937 pub fn new(agent_id: impl Into<String>, filter: BatchMemoryFilter) -> Self {
939 Self {
940 agent_id: agent_id.into(),
941 filter,
942 }
943 }
944}
945
946#[derive(Debug, Clone, Serialize, Deserialize)]
948pub struct BatchForgetResponse {
949 pub deleted_count: usize,
950}
951
952impl DakeraClient {
957 pub async fn store_memory(&self, request: StoreMemoryRequest) -> Result<StoreMemoryResponse> {
981 let url = format!("{}/v1/memory/store", self.base_url);
982 let response = self.client.post(&url).json(&request).send().await?;
983 self.handle_response(response).await
984 }
985
986 pub async fn recall(&self, request: RecallRequest) -> Result<RecallResponse> {
1007 let url = format!("{}/v1/memory/recall", self.base_url);
1008 let response = self.client.post(&url).json(&request).send().await?;
1009 self.handle_response(response).await
1010 }
1011
1012 pub async fn recall_simple(
1014 &self,
1015 agent_id: &str,
1016 query: &str,
1017 top_k: usize,
1018 ) -> Result<RecallResponse> {
1019 self.recall(RecallRequest::new(agent_id, query).with_top_k(top_k))
1020 .await
1021 }
1022
1023 pub async fn get_memory(&self, memory_id: &str) -> Result<RecalledMemory> {
1025 let url = format!("{}/v1/memory/get/{}", self.base_url, memory_id);
1026 let response = self.client.get(&url).send().await?;
1027 self.handle_response(response).await
1028 }
1029
1030 pub async fn forget(&self, request: ForgetRequest) -> Result<ForgetResponse> {
1032 let url = format!("{}/v1/memory/forget", self.base_url);
1033 let response = self.client.post(&url).json(&request).send().await?;
1034 self.handle_response(response).await
1035 }
1036
1037 pub async fn search_memories(&self, request: RecallRequest) -> Result<RecallResponse> {
1039 let url = format!("{}/v1/memory/search", self.base_url);
1040 let response = self.client.post(&url).json(&request).send().await?;
1041 self.handle_response(response).await
1042 }
1043
1044 pub async fn update_memory(
1046 &self,
1047 agent_id: &str,
1048 memory_id: &str,
1049 request: UpdateMemoryRequest,
1050 ) -> Result<StoreMemoryResponse> {
1051 let url = format!(
1052 "{}/v1/agents/{}/memories/{}",
1053 self.base_url, agent_id, memory_id
1054 );
1055 let response = self.client.put(&url).json(&request).send().await?;
1056 self.handle_response(response).await
1057 }
1058
1059 pub async fn update_importance(
1061 &self,
1062 agent_id: &str,
1063 request: UpdateImportanceRequest,
1064 ) -> Result<serde_json::Value> {
1065 let url = format!(
1066 "{}/v1/agents/{}/memories/importance",
1067 self.base_url, agent_id
1068 );
1069 let response = self.client.put(&url).json(&request).send().await?;
1070 self.handle_response(response).await
1071 }
1072
1073 pub async fn consolidate(
1075 &self,
1076 agent_id: &str,
1077 request: ConsolidateRequest,
1078 ) -> Result<ConsolidateResponse> {
1079 let url = format!("{}/v1/memory/consolidate", self.base_url);
1081 let mut body = serde_json::to_value(&request)?;
1082 body["agent_id"] = serde_json::Value::String(agent_id.to_string());
1083 let response = self.client.post(&url).json(&body).send().await?;
1084 self.handle_response(response).await
1085 }
1086
1087 pub async fn memory_feedback(
1089 &self,
1090 agent_id: &str,
1091 request: FeedbackRequest,
1092 ) -> Result<LegacyFeedbackResponse> {
1093 let url = format!("{}/v1/agents/{}/memories/feedback", self.base_url, agent_id);
1094 let response = self.client.post(&url).json(&request).send().await?;
1095 self.handle_response(response).await
1096 }
1097
1098 pub async fn feedback_memory(
1118 &self,
1119 memory_id: &str,
1120 agent_id: &str,
1121 signal: FeedbackSignal,
1122 ) -> Result<FeedbackResponse> {
1123 let url = format!("{}/v1/memories/{}/feedback", self.base_url, memory_id);
1124 let body = MemoryFeedbackBody {
1125 agent_id: agent_id.to_string(),
1126 signal,
1127 };
1128 let response = self.client.post(&url).json(&body).send().await?;
1129 self.handle_response(response).await
1130 }
1131
1132 pub async fn get_memory_feedback_history(
1134 &self,
1135 memory_id: &str,
1136 ) -> Result<FeedbackHistoryResponse> {
1137 let url = format!("{}/v1/memories/{}/feedback", self.base_url, memory_id);
1138 let response = self.client.get(&url).send().await?;
1139 self.handle_response(response).await
1140 }
1141
1142 pub async fn get_agent_feedback_summary(&self, agent_id: &str) -> Result<AgentFeedbackSummary> {
1144 let url = format!("{}/v1/agents/{}/feedback/summary", self.base_url, agent_id);
1145 let response = self.client.get(&url).send().await?;
1146 self.handle_response(response).await
1147 }
1148
1149 pub async fn patch_memory_importance(
1156 &self,
1157 memory_id: &str,
1158 agent_id: &str,
1159 importance: f32,
1160 ) -> Result<FeedbackResponse> {
1161 let url = format!("{}/v1/memories/{}/importance", self.base_url, memory_id);
1162 let body = MemoryImportancePatch {
1163 agent_id: agent_id.to_string(),
1164 importance,
1165 };
1166 let response = self.client.patch(&url).json(&body).send().await?;
1167 self.handle_response(response).await
1168 }
1169
1170 pub async fn get_feedback_health(&self, agent_id: &str) -> Result<FeedbackHealthResponse> {
1175 let url = format!("{}/v1/feedback/health?agent_id={}", self.base_url, agent_id);
1176 let response = self.client.get(&url).send().await?;
1177 self.handle_response(response).await
1178 }
1179
1180 pub async fn memory_graph(
1201 &self,
1202 memory_id: &str,
1203 options: GraphOptions,
1204 ) -> Result<MemoryGraph> {
1205 let mut url = format!("{}/v1/memories/{}/graph", self.base_url, memory_id);
1206 let depth = options.depth.unwrap_or(1);
1207 url.push_str(&format!("?depth={}", depth));
1208 if let Some(types) = &options.types {
1209 let type_strs: Vec<String> = types
1210 .iter()
1211 .map(|t| {
1212 serde_json::to_value(t)
1213 .unwrap()
1214 .as_str()
1215 .unwrap_or("")
1216 .to_string()
1217 })
1218 .collect();
1219 if !type_strs.is_empty() {
1220 url.push_str(&format!("&types={}", type_strs.join(",")));
1221 }
1222 }
1223 let response = self.client.get(&url).send().await?;
1224 self.handle_response(response).await
1225 }
1226
1227 pub async fn memory_path(&self, source_id: &str, target_id: &str) -> Result<GraphPath> {
1240 let url = format!(
1241 "{}/v1/memories/{}/path?target={}",
1242 self.base_url,
1243 source_id,
1244 urlencoding::encode(target_id)
1245 );
1246 let response = self.client.get(&url).send().await?;
1247 self.handle_response(response).await
1248 }
1249
1250 pub async fn memory_link(
1263 &self,
1264 source_id: &str,
1265 target_id: &str,
1266 edge_type: EdgeType,
1267 ) -> Result<GraphLinkResponse> {
1268 let url = format!("{}/v1/memories/{}/links", self.base_url, source_id);
1269 let request = GraphLinkRequest {
1270 target_id: target_id.to_string(),
1271 edge_type,
1272 };
1273 let response = self.client.post(&url).json(&request).send().await?;
1274 self.handle_response(response).await
1275 }
1276
1277 pub async fn agent_graph_export(&self, agent_id: &str, format: &str) -> Result<GraphExport> {
1285 let url = format!(
1286 "{}/v1/agents/{}/graph/export?format={}",
1287 self.base_url, agent_id, format
1288 );
1289 let response = self.client.get(&url).send().await?;
1290 self.handle_response(response).await
1291 }
1292
1293 pub async fn start_session(&self, agent_id: &str) -> Result<Session> {
1299 let url = format!("{}/v1/sessions/start", self.base_url);
1300 let request = SessionStartRequest {
1301 agent_id: agent_id.to_string(),
1302 metadata: None,
1303 };
1304 let response = self.client.post(&url).json(&request).send().await?;
1305 let resp: SessionStartResponse = self.handle_response(response).await?;
1306 Ok(resp.session)
1307 }
1308
1309 pub async fn start_session_with_metadata(
1311 &self,
1312 agent_id: &str,
1313 metadata: serde_json::Value,
1314 ) -> Result<Session> {
1315 let url = format!("{}/v1/sessions/start", self.base_url);
1316 let request = SessionStartRequest {
1317 agent_id: agent_id.to_string(),
1318 metadata: Some(metadata),
1319 };
1320 let response = self.client.post(&url).json(&request).send().await?;
1321 let resp: SessionStartResponse = self.handle_response(response).await?;
1322 Ok(resp.session)
1323 }
1324
1325 pub async fn end_session(
1328 &self,
1329 session_id: &str,
1330 summary: Option<String>,
1331 ) -> Result<SessionEndResponse> {
1332 let url = format!("{}/v1/sessions/{}/end", self.base_url, session_id);
1333 let request = SessionEndRequest { summary };
1334 let response = self.client.post(&url).json(&request).send().await?;
1335 self.handle_response(response).await
1336 }
1337
1338 pub async fn get_session(&self, session_id: &str) -> Result<Session> {
1340 let url = format!("{}/v1/sessions/{}", self.base_url, session_id);
1341 let response = self.client.get(&url).send().await?;
1342 self.handle_response(response).await
1343 }
1344
1345 pub async fn list_sessions(&self, agent_id: &str) -> Result<Vec<Session>> {
1347 let url = format!("{}/v1/sessions?agent_id={}", self.base_url, agent_id);
1348 let response = self.client.get(&url).send().await?;
1349 self.handle_response(response).await
1350 }
1351
1352 pub async fn session_memories(&self, session_id: &str) -> Result<RecallResponse> {
1354 let url = format!("{}/v1/sessions/{}/memories", self.base_url, session_id);
1355 let response = self.client.get(&url).send().await?;
1356 self.handle_response(response).await
1357 }
1358
1359 pub async fn batch_recall(&self, request: BatchRecallRequest) -> Result<BatchRecallResponse> {
1383 let url = format!("{}/v1/memories/recall/batch", self.base_url);
1384 let response = self.client.post(&url).json(&request).send().await?;
1385 self.handle_response(response).await
1386 }
1387
1388 pub async fn batch_forget(&self, request: BatchForgetRequest) -> Result<BatchForgetResponse> {
1408 let url = format!("{}/v1/memories/forget/batch", self.base_url);
1409 let response = self.client.delete(&url).json(&request).send().await?;
1410 self.handle_response(response).await
1411 }
1412
1413 pub async fn import_memories(
1431 &self,
1432 data: serde_json::Value,
1433 format: &str,
1434 agent_id: Option<&str>,
1435 namespace: Option<&str>,
1436 ) -> Result<MemoryImportResponse> {
1437 let mut body = serde_json::json!({"data": data, "format": format});
1438 if let Some(aid) = agent_id {
1439 body["agent_id"] = serde_json::Value::String(aid.to_string());
1440 }
1441 if let Some(ns) = namespace {
1442 body["namespace"] = serde_json::Value::String(ns.to_string());
1443 }
1444 let url = format!("{}/v1/import", self.base_url);
1445 let response = self.client.post(&url).json(&body).send().await?;
1446 self.handle_response(response).await
1447 }
1448
1449 pub async fn export_memories(
1453 &self,
1454 format: &str,
1455 agent_id: Option<&str>,
1456 namespace: Option<&str>,
1457 limit: Option<u32>,
1458 ) -> Result<MemoryExportResponse> {
1459 let mut params = vec![("format", format.to_string())];
1460 if let Some(aid) = agent_id {
1461 params.push(("agent_id", aid.to_string()));
1462 }
1463 if let Some(ns) = namespace {
1464 params.push(("namespace", ns.to_string()));
1465 }
1466 if let Some(l) = limit {
1467 params.push(("limit", l.to_string()));
1468 }
1469 let url = format!("{}/v1/export", self.base_url);
1470 let response = self.client.get(&url).query(¶ms).send().await?;
1471 self.handle_response(response).await
1472 }
1473
1474 pub async fn list_audit_events(&self, query: AuditQuery) -> Result<AuditListResponse> {
1480 let url = format!("{}/v1/audit", self.base_url);
1481 let response = self.client.get(&url).query(&query).send().await?;
1482 self.handle_response(response).await
1483 }
1484
1485 pub async fn stream_audit_events(
1489 &self,
1490 agent_id: Option<&str>,
1491 event_type: Option<&str>,
1492 ) -> Result<tokio::sync::mpsc::Receiver<Result<crate::events::DakeraEvent>>> {
1493 let mut params: Vec<(&str, String)> = Vec::new();
1494 if let Some(aid) = agent_id {
1495 params.push(("agent_id", aid.to_string()));
1496 }
1497 if let Some(et) = event_type {
1498 params.push(("event_type", et.to_string()));
1499 }
1500 let base = format!("{}/v1/audit/stream", self.base_url);
1501 let url = if params.is_empty() {
1502 base
1503 } else {
1504 let qs = params
1505 .iter()
1506 .map(|(k, v)| format!("{}={}", k, urlencoding::encode(v)))
1507 .collect::<Vec<_>>()
1508 .join("&");
1509 format!("{}?{}", base, qs)
1510 };
1511 self.stream_sse(url).await
1512 }
1513
1514 pub async fn export_audit(
1516 &self,
1517 format: &str,
1518 agent_id: Option<&str>,
1519 event_type: Option<&str>,
1520 from_ts: Option<u64>,
1521 to_ts: Option<u64>,
1522 ) -> Result<AuditExportResponse> {
1523 let mut body = serde_json::json!({"format": format});
1524 if let Some(aid) = agent_id {
1525 body["agent_id"] = serde_json::Value::String(aid.to_string());
1526 }
1527 if let Some(et) = event_type {
1528 body["event_type"] = serde_json::Value::String(et.to_string());
1529 }
1530 if let Some(f) = from_ts {
1531 body["from"] = serde_json::Value::Number(f.into());
1532 }
1533 if let Some(t) = to_ts {
1534 body["to"] = serde_json::Value::Number(t.into());
1535 }
1536 let url = format!("{}/v1/audit/export", self.base_url);
1537 let response = self.client.post(&url).json(&body).send().await?;
1538 self.handle_response(response).await
1539 }
1540
1541 pub async fn extract_text(
1550 &self,
1551 text: &str,
1552 namespace: Option<&str>,
1553 provider: Option<&str>,
1554 model: Option<&str>,
1555 ) -> Result<ExtractionResult> {
1556 let mut body = serde_json::json!({"text": text});
1557 if let Some(ns) = namespace {
1558 body["namespace"] = serde_json::Value::String(ns.to_string());
1559 }
1560 if let Some(p) = provider {
1561 body["provider"] = serde_json::Value::String(p.to_string());
1562 }
1563 if let Some(m) = model {
1564 body["model"] = serde_json::Value::String(m.to_string());
1565 }
1566 let url = format!("{}/v1/extract", self.base_url);
1567 let response = self.client.post(&url).json(&body).send().await?;
1568 self.handle_response(response).await
1569 }
1570
1571 pub async fn list_extract_providers(&self) -> Result<Vec<ExtractionProviderInfo>> {
1573 let url = format!("{}/v1/extract/providers", self.base_url);
1574 let response = self.client.get(&url).send().await?;
1575 let result: ExtractProvidersResponse = self.handle_response(response).await?;
1576 Ok(match result {
1577 ExtractProvidersResponse::List(v) => v,
1578 ExtractProvidersResponse::Object { providers } => providers,
1579 })
1580 }
1581
1582 pub async fn configure_namespace_extractor(
1584 &self,
1585 namespace: &str,
1586 provider: &str,
1587 model: Option<&str>,
1588 ) -> Result<serde_json::Value> {
1589 let mut body = serde_json::json!({"provider": provider});
1590 if let Some(m) = model {
1591 body["model"] = serde_json::Value::String(m.to_string());
1592 }
1593 let url = format!(
1594 "{}/v1/namespaces/{}/extractor",
1595 self.base_url,
1596 urlencoding::encode(namespace)
1597 );
1598 let response = self.client.patch(&url).json(&body).send().await?;
1599 self.handle_response(response).await
1600 }
1601
1602 pub async fn rotate_encryption_key(
1618 &self,
1619 new_key: &str,
1620 namespace: Option<&str>,
1621 ) -> Result<RotateEncryptionKeyResponse> {
1622 let body = RotateEncryptionKeyRequest {
1623 new_key: new_key.to_string(),
1624 namespace: namespace.map(|s| s.to_string()),
1625 };
1626 let url = format!("{}/v1/admin/encryption/rotate-key", self.base_url);
1627 let response = self.client.post(&url).json(&body).send().await?;
1628 self.handle_response(response).await
1629 }
1630}