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)]
22pub enum MemoryType {
23 #[default]
24 Episodic,
25 Semantic,
26 Procedural,
27 Working,
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize)]
32pub struct StoreMemoryRequest {
33 pub agent_id: String,
34 pub content: String,
35 #[serde(default)]
36 pub memory_type: MemoryType,
37 #[serde(default = "default_importance")]
38 pub importance: f32,
39 #[serde(default)]
40 pub tags: Vec<String>,
41 #[serde(skip_serializing_if = "Option::is_none")]
42 pub session_id: Option<String>,
43 #[serde(skip_serializing_if = "Option::is_none")]
44 pub metadata: Option<serde_json::Value>,
45 #[serde(skip_serializing_if = "Option::is_none")]
48 pub ttl_seconds: Option<u64>,
49 #[serde(skip_serializing_if = "Option::is_none")]
53 pub expires_at: Option<u64>,
54}
55
56fn default_importance() -> f32 {
57 0.5
58}
59
60impl StoreMemoryRequest {
61 pub fn new(agent_id: impl Into<String>, content: impl Into<String>) -> Self {
63 Self {
64 agent_id: agent_id.into(),
65 content: content.into(),
66 memory_type: MemoryType::default(),
67 importance: 0.5,
68 tags: Vec::new(),
69 session_id: None,
70 metadata: None,
71 ttl_seconds: None,
72 expires_at: None,
73 }
74 }
75
76 pub fn with_type(mut self, memory_type: MemoryType) -> Self {
78 self.memory_type = memory_type;
79 self
80 }
81
82 pub fn with_importance(mut self, importance: f32) -> Self {
84 self.importance = importance.clamp(0.0, 1.0);
85 self
86 }
87
88 pub fn with_tags(mut self, tags: Vec<String>) -> Self {
90 self.tags = tags;
91 self
92 }
93
94 pub fn with_session(mut self, session_id: impl Into<String>) -> Self {
96 self.session_id = Some(session_id.into());
97 self
98 }
99
100 pub fn with_metadata(mut self, metadata: serde_json::Value) -> Self {
102 self.metadata = Some(metadata);
103 self
104 }
105
106 pub fn with_ttl(mut self, ttl_seconds: u64) -> Self {
109 self.ttl_seconds = Some(ttl_seconds);
110 self
111 }
112
113 pub fn with_expires_at(mut self, expires_at: u64) -> Self {
116 self.expires_at = Some(expires_at);
117 self
118 }
119}
120
121#[derive(Debug, Clone, Serialize, Deserialize)]
123pub struct StoreMemoryResponse {
124 pub memory_id: String,
125 pub agent_id: String,
126 pub namespace: String,
127}
128
129#[derive(Debug, Clone, Serialize, Deserialize)]
131pub struct RecallRequest {
132 pub agent_id: String,
133 pub query: String,
134 #[serde(default = "default_top_k")]
135 pub top_k: usize,
136 #[serde(skip_serializing_if = "Option::is_none")]
137 pub memory_type: Option<MemoryType>,
138 #[serde(default)]
139 pub min_importance: f32,
140 #[serde(skip_serializing_if = "Option::is_none")]
141 pub session_id: Option<String>,
142 #[serde(default)]
143 pub tags: Vec<String>,
144 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
147 pub include_associated: bool,
148 #[serde(skip_serializing_if = "Option::is_none")]
150 pub associated_memories_cap: Option<u32>,
151 #[serde(skip_serializing_if = "Option::is_none")]
153 pub associated_memories_depth: Option<u8>,
154 #[serde(skip_serializing_if = "Option::is_none")]
156 pub associated_memories_min_weight: Option<f32>,
157 #[serde(skip_serializing_if = "Option::is_none")]
159 pub since: Option<String>,
160 #[serde(skip_serializing_if = "Option::is_none")]
162 pub until: Option<String>,
163}
164
165fn default_top_k() -> usize {
166 5
167}
168
169impl RecallRequest {
170 pub fn new(agent_id: impl Into<String>, query: impl Into<String>) -> Self {
172 Self {
173 agent_id: agent_id.into(),
174 query: query.into(),
175 top_k: 5,
176 memory_type: None,
177 min_importance: 0.0,
178 session_id: None,
179 tags: Vec::new(),
180 include_associated: false,
181 associated_memories_cap: None,
182 associated_memories_depth: None,
183 associated_memories_min_weight: None,
184 since: None,
185 until: None,
186 }
187 }
188
189 pub fn with_top_k(mut self, top_k: usize) -> Self {
191 self.top_k = top_k;
192 self
193 }
194
195 pub fn with_type(mut self, memory_type: MemoryType) -> Self {
197 self.memory_type = Some(memory_type);
198 self
199 }
200
201 pub fn with_min_importance(mut self, min: f32) -> Self {
203 self.min_importance = min;
204 self
205 }
206
207 pub fn with_session(mut self, session_id: impl Into<String>) -> Self {
209 self.session_id = Some(session_id.into());
210 self
211 }
212
213 pub fn with_tags(mut self, tags: Vec<String>) -> Self {
215 self.tags = tags;
216 self
217 }
218
219 pub fn with_associated(mut self) -> Self {
221 self.include_associated = true;
222 self
223 }
224
225 pub fn with_associated_cap(mut self, cap: u32) -> Self {
227 self.include_associated = true;
228 self.associated_memories_cap = Some(cap);
229 self
230 }
231
232 pub fn with_since(mut self, since: impl Into<String>) -> Self {
234 self.since = Some(since.into());
235 self
236 }
237
238 pub fn with_until(mut self, until: impl Into<String>) -> Self {
240 self.until = Some(until.into());
241 self
242 }
243
244 pub fn with_associated_depth(mut self, depth: u8) -> Self {
246 self.include_associated = true;
247 self.associated_memories_depth = Some(depth);
248 self
249 }
250
251 pub fn with_associated_min_weight(mut self, weight: f32) -> Self {
253 self.associated_memories_min_weight = Some(weight);
254 self
255 }
256}
257
258#[derive(Debug, Clone, Serialize, Deserialize)]
260pub struct RecalledMemory {
261 pub id: String,
262 pub content: String,
263 pub memory_type: MemoryType,
264 pub importance: f32,
265 pub score: f32,
266 #[serde(default)]
267 pub tags: Vec<String>,
268 #[serde(skip_serializing_if = "Option::is_none")]
269 pub session_id: Option<String>,
270 #[serde(skip_serializing_if = "Option::is_none")]
271 pub metadata: Option<serde_json::Value>,
272 pub created_at: u64,
273 pub last_accessed_at: u64,
274 pub access_count: u32,
275 #[serde(skip_serializing_if = "Option::is_none")]
277 pub depth: Option<u8>,
278}
279
280#[derive(Debug, Clone, Serialize, Deserialize)]
282pub struct RecallResponse {
283 pub memories: Vec<RecalledMemory>,
284 pub total_found: usize,
285 #[serde(skip_serializing_if = "Option::is_none")]
287 pub associated_memories: Option<Vec<RecalledMemory>>,
288}
289
290#[derive(Debug, Clone, Serialize, Deserialize)]
292pub struct ForgetRequest {
293 pub agent_id: String,
294 #[serde(default)]
295 pub memory_ids: Vec<String>,
296 #[serde(default)]
297 pub tags: Vec<String>,
298 #[serde(skip_serializing_if = "Option::is_none")]
299 pub session_id: Option<String>,
300 #[serde(skip_serializing_if = "Option::is_none")]
301 pub before_timestamp: Option<u64>,
302}
303
304impl ForgetRequest {
305 pub fn by_ids(agent_id: impl Into<String>, ids: Vec<String>) -> Self {
307 Self {
308 agent_id: agent_id.into(),
309 memory_ids: ids,
310 tags: Vec::new(),
311 session_id: None,
312 before_timestamp: None,
313 }
314 }
315
316 pub fn by_tags(agent_id: impl Into<String>, tags: Vec<String>) -> Self {
318 Self {
319 agent_id: agent_id.into(),
320 memory_ids: Vec::new(),
321 tags,
322 session_id: None,
323 before_timestamp: None,
324 }
325 }
326
327 pub fn by_session(agent_id: impl Into<String>, session_id: impl Into<String>) -> Self {
329 Self {
330 agent_id: agent_id.into(),
331 memory_ids: Vec::new(),
332 tags: Vec::new(),
333 session_id: Some(session_id.into()),
334 before_timestamp: None,
335 }
336 }
337}
338
339#[derive(Debug, Clone, Serialize, Deserialize)]
341pub struct ForgetResponse {
342 pub deleted_count: u64,
343}
344
345#[derive(Debug, Clone, Serialize, Deserialize)]
347pub struct SessionStartRequest {
348 pub agent_id: String,
349 #[serde(skip_serializing_if = "Option::is_none")]
350 pub metadata: Option<serde_json::Value>,
351}
352
353#[derive(Debug, Clone, Serialize, Deserialize)]
355pub struct Session {
356 pub id: String,
357 pub agent_id: String,
358 pub started_at: u64,
359 #[serde(skip_serializing_if = "Option::is_none")]
360 pub ended_at: Option<u64>,
361 #[serde(skip_serializing_if = "Option::is_none")]
362 pub summary: Option<String>,
363 #[serde(skip_serializing_if = "Option::is_none")]
364 pub metadata: Option<serde_json::Value>,
365}
366
367#[derive(Debug, Clone, Serialize, Deserialize)]
369pub struct SessionEndRequest {
370 #[serde(skip_serializing_if = "Option::is_none")]
371 pub summary: Option<String>,
372}
373
374#[derive(Debug, Clone, Serialize, Deserialize)]
376pub struct UpdateMemoryRequest {
377 #[serde(skip_serializing_if = "Option::is_none")]
378 pub content: Option<String>,
379 #[serde(skip_serializing_if = "Option::is_none")]
380 pub metadata: Option<serde_json::Value>,
381 #[serde(skip_serializing_if = "Option::is_none")]
382 pub memory_type: Option<MemoryType>,
383}
384
385#[derive(Debug, Clone, Serialize, Deserialize)]
387pub struct UpdateImportanceRequest {
388 pub memory_ids: Vec<String>,
389 pub importance: f32,
390}
391
392#[derive(Debug, Clone, Serialize, Deserialize, Default)]
394pub struct ConsolidationConfig {
395 #[serde(skip_serializing_if = "Option::is_none")]
397 pub algorithm: Option<String>,
398 #[serde(skip_serializing_if = "Option::is_none")]
400 pub min_samples: Option<u32>,
401 #[serde(skip_serializing_if = "Option::is_none")]
403 pub eps: Option<f32>,
404}
405
406#[derive(Debug, Clone, Serialize, Deserialize)]
408pub struct ConsolidationLogEntry {
409 pub step: String,
410 pub memories_before: usize,
411 pub memories_after: usize,
412 pub duration_ms: f64,
413}
414
415#[derive(Debug, Clone, Serialize, Deserialize, Default)]
417pub struct ConsolidateRequest {
418 #[serde(skip_serializing_if = "Option::is_none")]
419 pub memory_type: Option<String>,
420 #[serde(skip_serializing_if = "Option::is_none")]
421 pub threshold: Option<f32>,
422 #[serde(default)]
423 pub dry_run: bool,
424 #[serde(skip_serializing_if = "Option::is_none")]
426 pub config: Option<ConsolidationConfig>,
427}
428
429#[derive(Debug, Clone, Serialize, Deserialize)]
431pub struct ConsolidateResponse {
432 pub consolidated_count: usize,
433 pub removed_count: usize,
434 pub new_memories: Vec<String>,
435 #[serde(default, skip_serializing_if = "Vec::is_empty")]
437 pub log: Vec<ConsolidationLogEntry>,
438}
439
440#[derive(Debug, Clone, Serialize, Deserialize)]
446pub struct MemoryImportResponse {
447 pub imported_count: usize,
448 pub skipped_count: usize,
449 #[serde(default)]
450 pub errors: Vec<String>,
451}
452
453#[derive(Debug, Clone, Serialize, Deserialize)]
455pub struct MemoryExportResponse {
456 pub data: Vec<serde_json::Value>,
457 pub format: String,
458 pub count: usize,
459}
460
461#[derive(Debug, Clone, Serialize, Deserialize)]
467pub struct AuditEvent {
468 pub id: String,
469 pub event_type: String,
470 #[serde(skip_serializing_if = "Option::is_none")]
471 pub agent_id: Option<String>,
472 #[serde(skip_serializing_if = "Option::is_none")]
473 pub namespace: Option<String>,
474 pub timestamp: u64,
475 #[serde(default)]
476 pub details: serde_json::Value,
477}
478
479#[derive(Debug, Clone, Serialize, Deserialize)]
481pub struct AuditListResponse {
482 pub events: Vec<AuditEvent>,
483 pub total: usize,
484 #[serde(skip_serializing_if = "Option::is_none")]
485 pub cursor: Option<String>,
486}
487
488#[derive(Debug, Clone, Serialize, Deserialize)]
490pub struct AuditExportResponse {
491 pub data: String,
492 pub format: String,
493 pub count: usize,
494}
495
496#[derive(Debug, Clone, Serialize, Deserialize, Default)]
498pub struct AuditQuery {
499 #[serde(skip_serializing_if = "Option::is_none")]
500 pub agent_id: Option<String>,
501 #[serde(skip_serializing_if = "Option::is_none")]
502 pub event_type: Option<String>,
503 #[serde(skip_serializing_if = "Option::is_none")]
504 pub from: Option<u64>,
505 #[serde(skip_serializing_if = "Option::is_none")]
506 pub to: Option<u64>,
507 #[serde(skip_serializing_if = "Option::is_none")]
508 pub limit: Option<u32>,
509 #[serde(skip_serializing_if = "Option::is_none")]
510 pub cursor: Option<String>,
511}
512
513#[derive(Debug, Clone, Serialize, Deserialize)]
519pub struct ExtractionResult {
520 pub entities: Vec<serde_json::Value>,
521 pub provider: String,
522 #[serde(skip_serializing_if = "Option::is_none")]
523 pub model: Option<String>,
524 pub duration_ms: f64,
525}
526
527#[derive(Debug, Clone, Serialize, Deserialize)]
529pub struct ExtractionProviderInfo {
530 pub name: String,
531 pub available: bool,
532 #[serde(default)]
533 pub models: Vec<String>,
534}
535
536#[derive(Debug, Clone, Serialize, Deserialize)]
538#[serde(untagged)]
539pub enum ExtractProvidersResponse {
540 List(Vec<ExtractionProviderInfo>),
541 Object {
542 providers: Vec<ExtractionProviderInfo>,
543 },
544}
545
546#[derive(Debug, Clone, Serialize, Deserialize)]
552pub struct RotateEncryptionKeyRequest {
553 pub new_key: String,
555 #[serde(skip_serializing_if = "Option::is_none")]
557 pub namespace: Option<String>,
558}
559
560#[derive(Debug, Clone, Serialize, Deserialize)]
562pub struct RotateEncryptionKeyResponse {
563 pub rotated: usize,
564 pub skipped: usize,
565 #[serde(default)]
566 pub namespaces: Vec<String>,
567}
568
569#[derive(Debug, Clone, Serialize, Deserialize)]
571pub struct FeedbackRequest {
572 pub memory_id: String,
573 pub feedback: String,
574 #[serde(skip_serializing_if = "Option::is_none")]
575 pub relevance_score: Option<f32>,
576}
577
578#[derive(Debug, Clone, Serialize, Deserialize)]
580pub struct LegacyFeedbackResponse {
581 pub status: String,
582 pub updated_importance: Option<f32>,
583}
584
585#[derive(Debug, Clone, Serialize, Deserialize, Default)]
594pub struct BatchMemoryFilter {
595 #[serde(skip_serializing_if = "Option::is_none")]
597 pub tags: Option<Vec<String>>,
598 #[serde(skip_serializing_if = "Option::is_none")]
600 pub min_importance: Option<f32>,
601 #[serde(skip_serializing_if = "Option::is_none")]
603 pub max_importance: Option<f32>,
604 #[serde(skip_serializing_if = "Option::is_none")]
606 pub created_after: Option<u64>,
607 #[serde(skip_serializing_if = "Option::is_none")]
609 pub created_before: Option<u64>,
610 #[serde(skip_serializing_if = "Option::is_none")]
612 pub memory_type: Option<MemoryType>,
613 #[serde(skip_serializing_if = "Option::is_none")]
615 pub session_id: Option<String>,
616}
617
618impl BatchMemoryFilter {
619 pub fn with_tags(mut self, tags: Vec<String>) -> Self {
621 self.tags = Some(tags);
622 self
623 }
624
625 pub fn with_min_importance(mut self, min: f32) -> Self {
627 self.min_importance = Some(min);
628 self
629 }
630
631 pub fn with_max_importance(mut self, max: f32) -> Self {
633 self.max_importance = Some(max);
634 self
635 }
636
637 pub fn with_session(mut self, session_id: impl Into<String>) -> Self {
639 self.session_id = Some(session_id.into());
640 self
641 }
642}
643
644#[derive(Debug, Clone, Serialize, Deserialize)]
646pub struct BatchRecallRequest {
647 pub agent_id: String,
649 #[serde(default)]
651 pub filter: BatchMemoryFilter,
652 #[serde(default = "default_batch_limit")]
654 pub limit: usize,
655}
656
657fn default_batch_limit() -> usize {
658 100
659}
660
661impl BatchRecallRequest {
662 pub fn new(agent_id: impl Into<String>) -> Self {
664 Self {
665 agent_id: agent_id.into(),
666 filter: BatchMemoryFilter::default(),
667 limit: 100,
668 }
669 }
670
671 pub fn with_filter(mut self, filter: BatchMemoryFilter) -> Self {
673 self.filter = filter;
674 self
675 }
676
677 pub fn with_limit(mut self, limit: usize) -> Self {
679 self.limit = limit;
680 self
681 }
682}
683
684#[derive(Debug, Clone, Serialize, Deserialize)]
686pub struct BatchRecallResponse {
687 pub memories: Vec<RecalledMemory>,
688 pub total: usize,
690 pub filtered: usize,
692}
693
694#[derive(Debug, Clone, Serialize, Deserialize)]
696pub struct BatchForgetRequest {
697 pub agent_id: String,
699 pub filter: BatchMemoryFilter,
701}
702
703impl BatchForgetRequest {
704 pub fn new(agent_id: impl Into<String>, filter: BatchMemoryFilter) -> Self {
706 Self {
707 agent_id: agent_id.into(),
708 filter,
709 }
710 }
711}
712
713#[derive(Debug, Clone, Serialize, Deserialize)]
715pub struct BatchForgetResponse {
716 pub deleted_count: usize,
717}
718
719impl DakeraClient {
724 pub async fn store_memory(&self, request: StoreMemoryRequest) -> Result<StoreMemoryResponse> {
748 let url = format!("{}/v1/memory/store", self.base_url);
749 let response = self.client.post(&url).json(&request).send().await?;
750 self.handle_response(response).await
751 }
752
753 pub async fn recall(&self, request: RecallRequest) -> Result<RecallResponse> {
774 let url = format!("{}/v1/memory/recall", self.base_url);
775 let response = self.client.post(&url).json(&request).send().await?;
776 self.handle_response(response).await
777 }
778
779 pub async fn recall_simple(
781 &self,
782 agent_id: &str,
783 query: &str,
784 top_k: usize,
785 ) -> Result<RecallResponse> {
786 self.recall(RecallRequest::new(agent_id, query).with_top_k(top_k))
787 .await
788 }
789
790 pub async fn get_memory(&self, memory_id: &str) -> Result<RecalledMemory> {
792 let url = format!("{}/v1/memory/get/{}", self.base_url, memory_id);
793 let response = self.client.get(&url).send().await?;
794 self.handle_response(response).await
795 }
796
797 pub async fn forget(&self, request: ForgetRequest) -> Result<ForgetResponse> {
799 let url = format!("{}/v1/memory/forget", self.base_url);
800 let response = self.client.post(&url).json(&request).send().await?;
801 self.handle_response(response).await
802 }
803
804 pub async fn search_memories(&self, request: RecallRequest) -> Result<RecallResponse> {
806 let url = format!("{}/v1/memory/search", self.base_url);
807 let response = self.client.post(&url).json(&request).send().await?;
808 self.handle_response(response).await
809 }
810
811 pub async fn update_memory(
813 &self,
814 agent_id: &str,
815 memory_id: &str,
816 request: UpdateMemoryRequest,
817 ) -> Result<StoreMemoryResponse> {
818 let url = format!(
819 "{}/v1/agents/{}/memories/{}",
820 self.base_url, agent_id, memory_id
821 );
822 let response = self.client.put(&url).json(&request).send().await?;
823 self.handle_response(response).await
824 }
825
826 pub async fn update_importance(
828 &self,
829 agent_id: &str,
830 request: UpdateImportanceRequest,
831 ) -> Result<serde_json::Value> {
832 let url = format!(
833 "{}/v1/agents/{}/memories/importance",
834 self.base_url, agent_id
835 );
836 let response = self.client.put(&url).json(&request).send().await?;
837 self.handle_response(response).await
838 }
839
840 pub async fn consolidate(
842 &self,
843 agent_id: &str,
844 request: ConsolidateRequest,
845 ) -> Result<ConsolidateResponse> {
846 let url = format!(
847 "{}/v1/agents/{}/memories/consolidate",
848 self.base_url, agent_id
849 );
850 let response = self.client.post(&url).json(&request).send().await?;
851 self.handle_response(response).await
852 }
853
854 pub async fn memory_feedback(
856 &self,
857 agent_id: &str,
858 request: FeedbackRequest,
859 ) -> Result<LegacyFeedbackResponse> {
860 let url = format!("{}/v1/agents/{}/memories/feedback", self.base_url, agent_id);
861 let response = self.client.post(&url).json(&request).send().await?;
862 self.handle_response(response).await
863 }
864
865 pub async fn feedback_memory(
885 &self,
886 memory_id: &str,
887 agent_id: &str,
888 signal: FeedbackSignal,
889 ) -> Result<FeedbackResponse> {
890 let url = format!("{}/v1/memories/{}/feedback", self.base_url, memory_id);
891 let body = MemoryFeedbackBody {
892 agent_id: agent_id.to_string(),
893 signal,
894 };
895 let response = self.client.post(&url).json(&body).send().await?;
896 self.handle_response(response).await
897 }
898
899 pub async fn get_memory_feedback_history(
901 &self,
902 memory_id: &str,
903 ) -> Result<FeedbackHistoryResponse> {
904 let url = format!("{}/v1/memories/{}/feedback", self.base_url, memory_id);
905 let response = self.client.get(&url).send().await?;
906 self.handle_response(response).await
907 }
908
909 pub async fn get_agent_feedback_summary(&self, agent_id: &str) -> Result<AgentFeedbackSummary> {
911 let url = format!("{}/v1/agents/{}/feedback/summary", self.base_url, agent_id);
912 let response = self.client.get(&url).send().await?;
913 self.handle_response(response).await
914 }
915
916 pub async fn patch_memory_importance(
923 &self,
924 memory_id: &str,
925 agent_id: &str,
926 importance: f32,
927 ) -> Result<FeedbackResponse> {
928 let url = format!("{}/v1/memories/{}/importance", self.base_url, memory_id);
929 let body = MemoryImportancePatch {
930 agent_id: agent_id.to_string(),
931 importance,
932 };
933 let response = self.client.patch(&url).json(&body).send().await?;
934 self.handle_response(response).await
935 }
936
937 pub async fn get_feedback_health(&self, agent_id: &str) -> Result<FeedbackHealthResponse> {
942 let url = format!("{}/v1/feedback/health?agent_id={}", self.base_url, agent_id);
943 let response = self.client.get(&url).send().await?;
944 self.handle_response(response).await
945 }
946
947 pub async fn memory_graph(
968 &self,
969 memory_id: &str,
970 options: GraphOptions,
971 ) -> Result<MemoryGraph> {
972 let mut url = format!("{}/v1/memories/{}/graph", self.base_url, memory_id);
973 let depth = options.depth.unwrap_or(1);
974 url.push_str(&format!("?depth={}", depth));
975 if let Some(types) = &options.types {
976 let type_strs: Vec<String> = types
977 .iter()
978 .map(|t| {
979 serde_json::to_value(t)
980 .unwrap()
981 .as_str()
982 .unwrap_or("")
983 .to_string()
984 })
985 .collect();
986 if !type_strs.is_empty() {
987 url.push_str(&format!("&types={}", type_strs.join(",")));
988 }
989 }
990 let response = self.client.get(&url).send().await?;
991 self.handle_response(response).await
992 }
993
994 pub async fn memory_path(&self, source_id: &str, target_id: &str) -> Result<GraphPath> {
1007 let url = format!(
1008 "{}/v1/memories/{}/path?target={}",
1009 self.base_url,
1010 source_id,
1011 urlencoding::encode(target_id)
1012 );
1013 let response = self.client.get(&url).send().await?;
1014 self.handle_response(response).await
1015 }
1016
1017 pub async fn memory_link(
1030 &self,
1031 source_id: &str,
1032 target_id: &str,
1033 edge_type: EdgeType,
1034 ) -> Result<GraphLinkResponse> {
1035 let url = format!("{}/v1/memories/{}/links", self.base_url, source_id);
1036 let request = GraphLinkRequest {
1037 target_id: target_id.to_string(),
1038 edge_type,
1039 };
1040 let response = self.client.post(&url).json(&request).send().await?;
1041 self.handle_response(response).await
1042 }
1043
1044 pub async fn agent_graph_export(&self, agent_id: &str, format: &str) -> Result<GraphExport> {
1052 let url = format!(
1053 "{}/v1/agents/{}/graph/export?format={}",
1054 self.base_url, agent_id, format
1055 );
1056 let response = self.client.get(&url).send().await?;
1057 self.handle_response(response).await
1058 }
1059
1060 pub async fn start_session(&self, agent_id: &str) -> Result<Session> {
1066 let url = format!("{}/v1/sessions/start", self.base_url);
1067 let request = SessionStartRequest {
1068 agent_id: agent_id.to_string(),
1069 metadata: None,
1070 };
1071 let response = self.client.post(&url).json(&request).send().await?;
1072 self.handle_response(response).await
1073 }
1074
1075 pub async fn start_session_with_metadata(
1077 &self,
1078 agent_id: &str,
1079 metadata: serde_json::Value,
1080 ) -> Result<Session> {
1081 let url = format!("{}/v1/sessions/start", self.base_url);
1082 let request = SessionStartRequest {
1083 agent_id: agent_id.to_string(),
1084 metadata: Some(metadata),
1085 };
1086 let response = self.client.post(&url).json(&request).send().await?;
1087 self.handle_response(response).await
1088 }
1089
1090 pub async fn end_session(&self, session_id: &str, summary: Option<String>) -> Result<Session> {
1092 let url = format!("{}/v1/sessions/{}/end", self.base_url, session_id);
1093 let request = SessionEndRequest { summary };
1094 let response = self.client.post(&url).json(&request).send().await?;
1095 self.handle_response(response).await
1096 }
1097
1098 pub async fn get_session(&self, session_id: &str) -> Result<Session> {
1100 let url = format!("{}/v1/sessions/{}", self.base_url, session_id);
1101 let response = self.client.get(&url).send().await?;
1102 self.handle_response(response).await
1103 }
1104
1105 pub async fn list_sessions(&self, agent_id: &str) -> Result<Vec<Session>> {
1107 let url = format!("{}/v1/sessions?agent_id={}", self.base_url, agent_id);
1108 let response = self.client.get(&url).send().await?;
1109 self.handle_response(response).await
1110 }
1111
1112 pub async fn session_memories(&self, session_id: &str) -> Result<RecallResponse> {
1114 let url = format!("{}/v1/sessions/{}/memories", self.base_url, session_id);
1115 let response = self.client.get(&url).send().await?;
1116 self.handle_response(response).await
1117 }
1118
1119 pub async fn batch_recall(&self, request: BatchRecallRequest) -> Result<BatchRecallResponse> {
1143 let url = format!("{}/v1/memories/recall/batch", self.base_url);
1144 let response = self.client.post(&url).json(&request).send().await?;
1145 self.handle_response(response).await
1146 }
1147
1148 pub async fn batch_forget(&self, request: BatchForgetRequest) -> Result<BatchForgetResponse> {
1168 let url = format!("{}/v1/memories/forget/batch", self.base_url);
1169 let response = self.client.delete(&url).json(&request).send().await?;
1170 self.handle_response(response).await
1171 }
1172
1173 pub async fn import_memories(
1191 &self,
1192 data: serde_json::Value,
1193 format: &str,
1194 agent_id: Option<&str>,
1195 namespace: Option<&str>,
1196 ) -> Result<MemoryImportResponse> {
1197 let mut body = serde_json::json!({"data": data, "format": format});
1198 if let Some(aid) = agent_id {
1199 body["agent_id"] = serde_json::Value::String(aid.to_string());
1200 }
1201 if let Some(ns) = namespace {
1202 body["namespace"] = serde_json::Value::String(ns.to_string());
1203 }
1204 let url = format!("{}/v1/import", self.base_url);
1205 let response = self.client.post(&url).json(&body).send().await?;
1206 self.handle_response(response).await
1207 }
1208
1209 pub async fn export_memories(
1213 &self,
1214 format: &str,
1215 agent_id: Option<&str>,
1216 namespace: Option<&str>,
1217 limit: Option<u32>,
1218 ) -> Result<MemoryExportResponse> {
1219 let mut params = vec![("format", format.to_string())];
1220 if let Some(aid) = agent_id {
1221 params.push(("agent_id", aid.to_string()));
1222 }
1223 if let Some(ns) = namespace {
1224 params.push(("namespace", ns.to_string()));
1225 }
1226 if let Some(l) = limit {
1227 params.push(("limit", l.to_string()));
1228 }
1229 let url = format!("{}/v1/export", self.base_url);
1230 let response = self.client.get(&url).query(¶ms).send().await?;
1231 self.handle_response(response).await
1232 }
1233
1234 pub async fn list_audit_events(&self, query: AuditQuery) -> Result<AuditListResponse> {
1240 let url = format!("{}/v1/audit", self.base_url);
1241 let response = self.client.get(&url).query(&query).send().await?;
1242 self.handle_response(response).await
1243 }
1244
1245 pub async fn stream_audit_events(
1249 &self,
1250 agent_id: Option<&str>,
1251 event_type: Option<&str>,
1252 ) -> Result<tokio::sync::mpsc::Receiver<Result<crate::events::DakeraEvent>>> {
1253 let mut params: Vec<(&str, String)> = Vec::new();
1254 if let Some(aid) = agent_id {
1255 params.push(("agent_id", aid.to_string()));
1256 }
1257 if let Some(et) = event_type {
1258 params.push(("event_type", et.to_string()));
1259 }
1260 let base = format!("{}/v1/audit/stream", self.base_url);
1261 let url = if params.is_empty() {
1262 base
1263 } else {
1264 let qs = params
1265 .iter()
1266 .map(|(k, v)| format!("{}={}", k, urlencoding::encode(v)))
1267 .collect::<Vec<_>>()
1268 .join("&");
1269 format!("{}?{}", base, qs)
1270 };
1271 self.stream_sse(url).await
1272 }
1273
1274 pub async fn export_audit(
1276 &self,
1277 format: &str,
1278 agent_id: Option<&str>,
1279 event_type: Option<&str>,
1280 from_ts: Option<u64>,
1281 to_ts: Option<u64>,
1282 ) -> Result<AuditExportResponse> {
1283 let mut body = serde_json::json!({"format": format});
1284 if let Some(aid) = agent_id {
1285 body["agent_id"] = serde_json::Value::String(aid.to_string());
1286 }
1287 if let Some(et) = event_type {
1288 body["event_type"] = serde_json::Value::String(et.to_string());
1289 }
1290 if let Some(f) = from_ts {
1291 body["from"] = serde_json::Value::Number(f.into());
1292 }
1293 if let Some(t) = to_ts {
1294 body["to"] = serde_json::Value::Number(t.into());
1295 }
1296 let url = format!("{}/v1/audit/export", self.base_url);
1297 let response = self.client.post(&url).json(&body).send().await?;
1298 self.handle_response(response).await
1299 }
1300
1301 pub async fn extract_text(
1310 &self,
1311 text: &str,
1312 namespace: Option<&str>,
1313 provider: Option<&str>,
1314 model: Option<&str>,
1315 ) -> Result<ExtractionResult> {
1316 let mut body = serde_json::json!({"text": text});
1317 if let Some(ns) = namespace {
1318 body["namespace"] = serde_json::Value::String(ns.to_string());
1319 }
1320 if let Some(p) = provider {
1321 body["provider"] = serde_json::Value::String(p.to_string());
1322 }
1323 if let Some(m) = model {
1324 body["model"] = serde_json::Value::String(m.to_string());
1325 }
1326 let url = format!("{}/v1/extract", self.base_url);
1327 let response = self.client.post(&url).json(&body).send().await?;
1328 self.handle_response(response).await
1329 }
1330
1331 pub async fn list_extract_providers(&self) -> Result<Vec<ExtractionProviderInfo>> {
1333 let url = format!("{}/v1/extract/providers", self.base_url);
1334 let response = self.client.get(&url).send().await?;
1335 let result: ExtractProvidersResponse = self.handle_response(response).await?;
1336 Ok(match result {
1337 ExtractProvidersResponse::List(v) => v,
1338 ExtractProvidersResponse::Object { providers } => providers,
1339 })
1340 }
1341
1342 pub async fn configure_namespace_extractor(
1344 &self,
1345 namespace: &str,
1346 provider: &str,
1347 model: Option<&str>,
1348 ) -> Result<serde_json::Value> {
1349 let mut body = serde_json::json!({"provider": provider});
1350 if let Some(m) = model {
1351 body["model"] = serde_json::Value::String(m.to_string());
1352 }
1353 let url = format!(
1354 "{}/v1/namespaces/{}/extractor",
1355 self.base_url,
1356 urlencoding::encode(namespace)
1357 );
1358 let response = self.client.patch(&url).json(&body).send().await?;
1359 self.handle_response(response).await
1360 }
1361
1362 pub async fn rotate_encryption_key(
1378 &self,
1379 new_key: &str,
1380 namespace: Option<&str>,
1381 ) -> Result<RotateEncryptionKeyResponse> {
1382 let body = RotateEncryptionKeyRequest {
1383 new_key: new_key.to_string(),
1384 namespace: namespace.map(|s| s.to_string()),
1385 };
1386 let url = format!("{}/v1/admin/encryption/rotate-key", self.base_url);
1387 let response = self.client.post(&url).json(&body).send().await?;
1388 self.handle_response(response).await
1389 }
1390}