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 since: Option<String>,
154 #[serde(skip_serializing_if = "Option::is_none")]
156 pub until: Option<String>,
157}
158
159fn default_top_k() -> usize {
160 5
161}
162
163impl RecallRequest {
164 pub fn new(agent_id: impl Into<String>, query: impl Into<String>) -> Self {
166 Self {
167 agent_id: agent_id.into(),
168 query: query.into(),
169 top_k: 5,
170 memory_type: None,
171 min_importance: 0.0,
172 session_id: None,
173 tags: Vec::new(),
174 include_associated: false,
175 associated_memories_cap: None,
176 since: None,
177 until: None,
178 }
179 }
180
181 pub fn with_top_k(mut self, top_k: usize) -> Self {
183 self.top_k = top_k;
184 self
185 }
186
187 pub fn with_type(mut self, memory_type: MemoryType) -> Self {
189 self.memory_type = Some(memory_type);
190 self
191 }
192
193 pub fn with_min_importance(mut self, min: f32) -> Self {
195 self.min_importance = min;
196 self
197 }
198
199 pub fn with_session(mut self, session_id: impl Into<String>) -> Self {
201 self.session_id = Some(session_id.into());
202 self
203 }
204
205 pub fn with_tags(mut self, tags: Vec<String>) -> Self {
207 self.tags = tags;
208 self
209 }
210
211 pub fn with_associated(mut self) -> Self {
213 self.include_associated = true;
214 self
215 }
216
217 pub fn with_associated_cap(mut self, cap: u32) -> Self {
219 self.include_associated = true;
220 self.associated_memories_cap = Some(cap);
221 self
222 }
223
224 pub fn with_since(mut self, since: impl Into<String>) -> Self {
226 self.since = Some(since.into());
227 self
228 }
229
230 pub fn with_until(mut self, until: impl Into<String>) -> Self {
232 self.until = Some(until.into());
233 self
234 }
235}
236
237#[derive(Debug, Clone, Serialize, Deserialize)]
239pub struct RecalledMemory {
240 pub id: String,
241 pub content: String,
242 pub memory_type: MemoryType,
243 pub importance: f32,
244 pub score: f32,
245 #[serde(default)]
246 pub tags: Vec<String>,
247 #[serde(skip_serializing_if = "Option::is_none")]
248 pub session_id: Option<String>,
249 #[serde(skip_serializing_if = "Option::is_none")]
250 pub metadata: Option<serde_json::Value>,
251 pub created_at: u64,
252 pub last_accessed_at: u64,
253 pub access_count: u32,
254}
255
256#[derive(Debug, Clone, Serialize, Deserialize)]
258pub struct RecallResponse {
259 pub memories: Vec<RecalledMemory>,
260 pub total_found: usize,
261 #[serde(skip_serializing_if = "Option::is_none")]
263 pub associated_memories: Option<Vec<RecalledMemory>>,
264}
265
266#[derive(Debug, Clone, Serialize, Deserialize)]
268pub struct ForgetRequest {
269 pub agent_id: String,
270 #[serde(default)]
271 pub memory_ids: Vec<String>,
272 #[serde(default)]
273 pub tags: Vec<String>,
274 #[serde(skip_serializing_if = "Option::is_none")]
275 pub session_id: Option<String>,
276 #[serde(skip_serializing_if = "Option::is_none")]
277 pub before_timestamp: Option<u64>,
278}
279
280impl ForgetRequest {
281 pub fn by_ids(agent_id: impl Into<String>, ids: Vec<String>) -> Self {
283 Self {
284 agent_id: agent_id.into(),
285 memory_ids: ids,
286 tags: Vec::new(),
287 session_id: None,
288 before_timestamp: None,
289 }
290 }
291
292 pub fn by_tags(agent_id: impl Into<String>, tags: Vec<String>) -> Self {
294 Self {
295 agent_id: agent_id.into(),
296 memory_ids: Vec::new(),
297 tags,
298 session_id: None,
299 before_timestamp: None,
300 }
301 }
302
303 pub fn by_session(agent_id: impl Into<String>, session_id: impl Into<String>) -> Self {
305 Self {
306 agent_id: agent_id.into(),
307 memory_ids: Vec::new(),
308 tags: Vec::new(),
309 session_id: Some(session_id.into()),
310 before_timestamp: None,
311 }
312 }
313}
314
315#[derive(Debug, Clone, Serialize, Deserialize)]
317pub struct ForgetResponse {
318 pub deleted_count: u64,
319}
320
321#[derive(Debug, Clone, Serialize, Deserialize)]
323pub struct SessionStartRequest {
324 pub agent_id: String,
325 #[serde(skip_serializing_if = "Option::is_none")]
326 pub metadata: Option<serde_json::Value>,
327}
328
329#[derive(Debug, Clone, Serialize, Deserialize)]
331pub struct Session {
332 pub id: String,
333 pub agent_id: String,
334 pub started_at: u64,
335 #[serde(skip_serializing_if = "Option::is_none")]
336 pub ended_at: Option<u64>,
337 #[serde(skip_serializing_if = "Option::is_none")]
338 pub summary: Option<String>,
339 #[serde(skip_serializing_if = "Option::is_none")]
340 pub metadata: Option<serde_json::Value>,
341}
342
343#[derive(Debug, Clone, Serialize, Deserialize)]
345pub struct SessionEndRequest {
346 #[serde(skip_serializing_if = "Option::is_none")]
347 pub summary: Option<String>,
348}
349
350#[derive(Debug, Clone, Serialize, Deserialize)]
352pub struct UpdateMemoryRequest {
353 #[serde(skip_serializing_if = "Option::is_none")]
354 pub content: Option<String>,
355 #[serde(skip_serializing_if = "Option::is_none")]
356 pub metadata: Option<serde_json::Value>,
357 #[serde(skip_serializing_if = "Option::is_none")]
358 pub memory_type: Option<MemoryType>,
359}
360
361#[derive(Debug, Clone, Serialize, Deserialize)]
363pub struct UpdateImportanceRequest {
364 pub memory_ids: Vec<String>,
365 pub importance: f32,
366}
367
368#[derive(Debug, Clone, Serialize, Deserialize, Default)]
370pub struct ConsolidationConfig {
371 #[serde(skip_serializing_if = "Option::is_none")]
373 pub algorithm: Option<String>,
374 #[serde(skip_serializing_if = "Option::is_none")]
376 pub min_samples: Option<u32>,
377 #[serde(skip_serializing_if = "Option::is_none")]
379 pub eps: Option<f32>,
380}
381
382#[derive(Debug, Clone, Serialize, Deserialize)]
384pub struct ConsolidationLogEntry {
385 pub step: String,
386 pub memories_before: usize,
387 pub memories_after: usize,
388 pub duration_ms: f64,
389}
390
391#[derive(Debug, Clone, Serialize, Deserialize, Default)]
393pub struct ConsolidateRequest {
394 #[serde(skip_serializing_if = "Option::is_none")]
395 pub memory_type: Option<String>,
396 #[serde(skip_serializing_if = "Option::is_none")]
397 pub threshold: Option<f32>,
398 #[serde(default)]
399 pub dry_run: bool,
400 #[serde(skip_serializing_if = "Option::is_none")]
402 pub config: Option<ConsolidationConfig>,
403}
404
405#[derive(Debug, Clone, Serialize, Deserialize)]
407pub struct ConsolidateResponse {
408 pub consolidated_count: usize,
409 pub removed_count: usize,
410 pub new_memories: Vec<String>,
411 #[serde(default, skip_serializing_if = "Vec::is_empty")]
413 pub log: Vec<ConsolidationLogEntry>,
414}
415
416#[derive(Debug, Clone, Serialize, Deserialize)]
422pub struct MemoryImportResponse {
423 pub imported_count: usize,
424 pub skipped_count: usize,
425 #[serde(default)]
426 pub errors: Vec<String>,
427}
428
429#[derive(Debug, Clone, Serialize, Deserialize)]
431pub struct MemoryExportResponse {
432 pub data: Vec<serde_json::Value>,
433 pub format: String,
434 pub count: usize,
435}
436
437#[derive(Debug, Clone, Serialize, Deserialize)]
443pub struct AuditEvent {
444 pub id: String,
445 pub event_type: String,
446 #[serde(skip_serializing_if = "Option::is_none")]
447 pub agent_id: Option<String>,
448 #[serde(skip_serializing_if = "Option::is_none")]
449 pub namespace: Option<String>,
450 pub timestamp: u64,
451 #[serde(default)]
452 pub details: serde_json::Value,
453}
454
455#[derive(Debug, Clone, Serialize, Deserialize)]
457pub struct AuditListResponse {
458 pub events: Vec<AuditEvent>,
459 pub total: usize,
460 #[serde(skip_serializing_if = "Option::is_none")]
461 pub cursor: Option<String>,
462}
463
464#[derive(Debug, Clone, Serialize, Deserialize)]
466pub struct AuditExportResponse {
467 pub data: String,
468 pub format: String,
469 pub count: usize,
470}
471
472#[derive(Debug, Clone, Serialize, Deserialize, Default)]
474pub struct AuditQuery {
475 #[serde(skip_serializing_if = "Option::is_none")]
476 pub agent_id: Option<String>,
477 #[serde(skip_serializing_if = "Option::is_none")]
478 pub event_type: Option<String>,
479 #[serde(skip_serializing_if = "Option::is_none")]
480 pub from: Option<u64>,
481 #[serde(skip_serializing_if = "Option::is_none")]
482 pub to: Option<u64>,
483 #[serde(skip_serializing_if = "Option::is_none")]
484 pub limit: Option<u32>,
485 #[serde(skip_serializing_if = "Option::is_none")]
486 pub cursor: Option<String>,
487}
488
489#[derive(Debug, Clone, Serialize, Deserialize)]
495pub struct ExtractionResult {
496 pub entities: Vec<serde_json::Value>,
497 pub provider: String,
498 #[serde(skip_serializing_if = "Option::is_none")]
499 pub model: Option<String>,
500 pub duration_ms: f64,
501}
502
503#[derive(Debug, Clone, Serialize, Deserialize)]
505pub struct ExtractionProviderInfo {
506 pub name: String,
507 pub available: bool,
508 #[serde(default)]
509 pub models: Vec<String>,
510}
511
512#[derive(Debug, Clone, Serialize, Deserialize)]
514#[serde(untagged)]
515pub enum ExtractProvidersResponse {
516 List(Vec<ExtractionProviderInfo>),
517 Object {
518 providers: Vec<ExtractionProviderInfo>,
519 },
520}
521
522#[derive(Debug, Clone, Serialize, Deserialize)]
528pub struct RotateEncryptionKeyRequest {
529 pub new_key: String,
531 #[serde(skip_serializing_if = "Option::is_none")]
533 pub namespace: Option<String>,
534}
535
536#[derive(Debug, Clone, Serialize, Deserialize)]
538pub struct RotateEncryptionKeyResponse {
539 pub rotated: usize,
540 pub skipped: usize,
541 #[serde(default)]
542 pub namespaces: Vec<String>,
543}
544
545#[derive(Debug, Clone, Serialize, Deserialize)]
547pub struct FeedbackRequest {
548 pub memory_id: String,
549 pub feedback: String,
550 #[serde(skip_serializing_if = "Option::is_none")]
551 pub relevance_score: Option<f32>,
552}
553
554#[derive(Debug, Clone, Serialize, Deserialize)]
556pub struct LegacyFeedbackResponse {
557 pub status: String,
558 pub updated_importance: Option<f32>,
559}
560
561#[derive(Debug, Clone, Serialize, Deserialize, Default)]
570pub struct BatchMemoryFilter {
571 #[serde(skip_serializing_if = "Option::is_none")]
573 pub tags: Option<Vec<String>>,
574 #[serde(skip_serializing_if = "Option::is_none")]
576 pub min_importance: Option<f32>,
577 #[serde(skip_serializing_if = "Option::is_none")]
579 pub max_importance: Option<f32>,
580 #[serde(skip_serializing_if = "Option::is_none")]
582 pub created_after: Option<u64>,
583 #[serde(skip_serializing_if = "Option::is_none")]
585 pub created_before: Option<u64>,
586 #[serde(skip_serializing_if = "Option::is_none")]
588 pub memory_type: Option<MemoryType>,
589 #[serde(skip_serializing_if = "Option::is_none")]
591 pub session_id: Option<String>,
592}
593
594impl BatchMemoryFilter {
595 pub fn with_tags(mut self, tags: Vec<String>) -> Self {
597 self.tags = Some(tags);
598 self
599 }
600
601 pub fn with_min_importance(mut self, min: f32) -> Self {
603 self.min_importance = Some(min);
604 self
605 }
606
607 pub fn with_max_importance(mut self, max: f32) -> Self {
609 self.max_importance = Some(max);
610 self
611 }
612
613 pub fn with_session(mut self, session_id: impl Into<String>) -> Self {
615 self.session_id = Some(session_id.into());
616 self
617 }
618}
619
620#[derive(Debug, Clone, Serialize, Deserialize)]
622pub struct BatchRecallRequest {
623 pub agent_id: String,
625 #[serde(default)]
627 pub filter: BatchMemoryFilter,
628 #[serde(default = "default_batch_limit")]
630 pub limit: usize,
631}
632
633fn default_batch_limit() -> usize {
634 100
635}
636
637impl BatchRecallRequest {
638 pub fn new(agent_id: impl Into<String>) -> Self {
640 Self {
641 agent_id: agent_id.into(),
642 filter: BatchMemoryFilter::default(),
643 limit: 100,
644 }
645 }
646
647 pub fn with_filter(mut self, filter: BatchMemoryFilter) -> Self {
649 self.filter = filter;
650 self
651 }
652
653 pub fn with_limit(mut self, limit: usize) -> Self {
655 self.limit = limit;
656 self
657 }
658}
659
660#[derive(Debug, Clone, Serialize, Deserialize)]
662pub struct BatchRecallResponse {
663 pub memories: Vec<RecalledMemory>,
664 pub total: usize,
666 pub filtered: usize,
668}
669
670#[derive(Debug, Clone, Serialize, Deserialize)]
672pub struct BatchForgetRequest {
673 pub agent_id: String,
675 pub filter: BatchMemoryFilter,
677}
678
679impl BatchForgetRequest {
680 pub fn new(agent_id: impl Into<String>, filter: BatchMemoryFilter) -> Self {
682 Self {
683 agent_id: agent_id.into(),
684 filter,
685 }
686 }
687}
688
689#[derive(Debug, Clone, Serialize, Deserialize)]
691pub struct BatchForgetResponse {
692 pub deleted_count: usize,
693}
694
695impl DakeraClient {
700 pub async fn store_memory(&self, request: StoreMemoryRequest) -> Result<StoreMemoryResponse> {
724 let url = format!("{}/v1/memory/store", self.base_url);
725 let response = self.client.post(&url).json(&request).send().await?;
726 self.handle_response(response).await
727 }
728
729 pub async fn recall(&self, request: RecallRequest) -> Result<RecallResponse> {
750 let url = format!("{}/v1/memory/recall", self.base_url);
751 let response = self.client.post(&url).json(&request).send().await?;
752 self.handle_response(response).await
753 }
754
755 pub async fn recall_simple(
757 &self,
758 agent_id: &str,
759 query: &str,
760 top_k: usize,
761 ) -> Result<RecallResponse> {
762 self.recall(RecallRequest::new(agent_id, query).with_top_k(top_k))
763 .await
764 }
765
766 pub async fn get_memory(&self, memory_id: &str) -> Result<RecalledMemory> {
768 let url = format!("{}/v1/memory/get/{}", self.base_url, memory_id);
769 let response = self.client.get(&url).send().await?;
770 self.handle_response(response).await
771 }
772
773 pub async fn forget(&self, request: ForgetRequest) -> Result<ForgetResponse> {
775 let url = format!("{}/v1/memory/forget", self.base_url);
776 let response = self.client.post(&url).json(&request).send().await?;
777 self.handle_response(response).await
778 }
779
780 pub async fn search_memories(&self, request: RecallRequest) -> Result<RecallResponse> {
782 let url = format!("{}/v1/memory/search", self.base_url);
783 let response = self.client.post(&url).json(&request).send().await?;
784 self.handle_response(response).await
785 }
786
787 pub async fn update_memory(
789 &self,
790 agent_id: &str,
791 memory_id: &str,
792 request: UpdateMemoryRequest,
793 ) -> Result<StoreMemoryResponse> {
794 let url = format!(
795 "{}/v1/agents/{}/memories/{}",
796 self.base_url, agent_id, memory_id
797 );
798 let response = self.client.put(&url).json(&request).send().await?;
799 self.handle_response(response).await
800 }
801
802 pub async fn update_importance(
804 &self,
805 agent_id: &str,
806 request: UpdateImportanceRequest,
807 ) -> Result<serde_json::Value> {
808 let url = format!(
809 "{}/v1/agents/{}/memories/importance",
810 self.base_url, agent_id
811 );
812 let response = self.client.put(&url).json(&request).send().await?;
813 self.handle_response(response).await
814 }
815
816 pub async fn consolidate(
818 &self,
819 agent_id: &str,
820 request: ConsolidateRequest,
821 ) -> Result<ConsolidateResponse> {
822 let url = format!(
823 "{}/v1/agents/{}/memories/consolidate",
824 self.base_url, agent_id
825 );
826 let response = self.client.post(&url).json(&request).send().await?;
827 self.handle_response(response).await
828 }
829
830 pub async fn memory_feedback(
832 &self,
833 agent_id: &str,
834 request: FeedbackRequest,
835 ) -> Result<LegacyFeedbackResponse> {
836 let url = format!("{}/v1/agents/{}/memories/feedback", self.base_url, agent_id);
837 let response = self.client.post(&url).json(&request).send().await?;
838 self.handle_response(response).await
839 }
840
841 pub async fn feedback_memory(
861 &self,
862 memory_id: &str,
863 agent_id: &str,
864 signal: FeedbackSignal,
865 ) -> Result<FeedbackResponse> {
866 let url = format!("{}/v1/memories/{}/feedback", self.base_url, memory_id);
867 let body = MemoryFeedbackBody {
868 agent_id: agent_id.to_string(),
869 signal,
870 };
871 let response = self.client.post(&url).json(&body).send().await?;
872 self.handle_response(response).await
873 }
874
875 pub async fn get_memory_feedback_history(
877 &self,
878 memory_id: &str,
879 ) -> Result<FeedbackHistoryResponse> {
880 let url = format!("{}/v1/memories/{}/feedback", self.base_url, memory_id);
881 let response = self.client.get(&url).send().await?;
882 self.handle_response(response).await
883 }
884
885 pub async fn get_agent_feedback_summary(&self, agent_id: &str) -> Result<AgentFeedbackSummary> {
887 let url = format!("{}/v1/agents/{}/feedback/summary", self.base_url, agent_id);
888 let response = self.client.get(&url).send().await?;
889 self.handle_response(response).await
890 }
891
892 pub async fn patch_memory_importance(
899 &self,
900 memory_id: &str,
901 agent_id: &str,
902 importance: f32,
903 ) -> Result<FeedbackResponse> {
904 let url = format!("{}/v1/memories/{}/importance", self.base_url, memory_id);
905 let body = MemoryImportancePatch {
906 agent_id: agent_id.to_string(),
907 importance,
908 };
909 let response = self.client.patch(&url).json(&body).send().await?;
910 self.handle_response(response).await
911 }
912
913 pub async fn get_feedback_health(&self, agent_id: &str) -> Result<FeedbackHealthResponse> {
918 let url = format!("{}/v1/feedback/health?agent_id={}", self.base_url, agent_id);
919 let response = self.client.get(&url).send().await?;
920 self.handle_response(response).await
921 }
922
923 pub async fn memory_graph(
944 &self,
945 memory_id: &str,
946 options: GraphOptions,
947 ) -> Result<MemoryGraph> {
948 let mut url = format!("{}/v1/memories/{}/graph", self.base_url, memory_id);
949 let depth = options.depth.unwrap_or(1);
950 url.push_str(&format!("?depth={}", depth));
951 if let Some(types) = &options.types {
952 let type_strs: Vec<String> = types
953 .iter()
954 .map(|t| {
955 serde_json::to_value(t)
956 .unwrap()
957 .as_str()
958 .unwrap_or("")
959 .to_string()
960 })
961 .collect();
962 if !type_strs.is_empty() {
963 url.push_str(&format!("&types={}", type_strs.join(",")));
964 }
965 }
966 let response = self.client.get(&url).send().await?;
967 self.handle_response(response).await
968 }
969
970 pub async fn memory_path(&self, source_id: &str, target_id: &str) -> Result<GraphPath> {
983 let url = format!(
984 "{}/v1/memories/{}/path?target={}",
985 self.base_url,
986 source_id,
987 urlencoding::encode(target_id)
988 );
989 let response = self.client.get(&url).send().await?;
990 self.handle_response(response).await
991 }
992
993 pub async fn memory_link(
1006 &self,
1007 source_id: &str,
1008 target_id: &str,
1009 edge_type: EdgeType,
1010 ) -> Result<GraphLinkResponse> {
1011 let url = format!("{}/v1/memories/{}/links", self.base_url, source_id);
1012 let request = GraphLinkRequest {
1013 target_id: target_id.to_string(),
1014 edge_type,
1015 };
1016 let response = self.client.post(&url).json(&request).send().await?;
1017 self.handle_response(response).await
1018 }
1019
1020 pub async fn agent_graph_export(&self, agent_id: &str, format: &str) -> Result<GraphExport> {
1028 let url = format!(
1029 "{}/v1/agents/{}/graph/export?format={}",
1030 self.base_url, agent_id, format
1031 );
1032 let response = self.client.get(&url).send().await?;
1033 self.handle_response(response).await
1034 }
1035
1036 pub async fn start_session(&self, agent_id: &str) -> Result<Session> {
1042 let url = format!("{}/v1/sessions/start", self.base_url);
1043 let request = SessionStartRequest {
1044 agent_id: agent_id.to_string(),
1045 metadata: None,
1046 };
1047 let response = self.client.post(&url).json(&request).send().await?;
1048 self.handle_response(response).await
1049 }
1050
1051 pub async fn start_session_with_metadata(
1053 &self,
1054 agent_id: &str,
1055 metadata: serde_json::Value,
1056 ) -> Result<Session> {
1057 let url = format!("{}/v1/sessions/start", self.base_url);
1058 let request = SessionStartRequest {
1059 agent_id: agent_id.to_string(),
1060 metadata: Some(metadata),
1061 };
1062 let response = self.client.post(&url).json(&request).send().await?;
1063 self.handle_response(response).await
1064 }
1065
1066 pub async fn end_session(&self, session_id: &str, summary: Option<String>) -> Result<Session> {
1068 let url = format!("{}/v1/sessions/{}/end", self.base_url, session_id);
1069 let request = SessionEndRequest { summary };
1070 let response = self.client.post(&url).json(&request).send().await?;
1071 self.handle_response(response).await
1072 }
1073
1074 pub async fn get_session(&self, session_id: &str) -> Result<Session> {
1076 let url = format!("{}/v1/sessions/{}", self.base_url, session_id);
1077 let response = self.client.get(&url).send().await?;
1078 self.handle_response(response).await
1079 }
1080
1081 pub async fn list_sessions(&self, agent_id: &str) -> Result<Vec<Session>> {
1083 let url = format!("{}/v1/sessions?agent_id={}", self.base_url, agent_id);
1084 let response = self.client.get(&url).send().await?;
1085 self.handle_response(response).await
1086 }
1087
1088 pub async fn session_memories(&self, session_id: &str) -> Result<RecallResponse> {
1090 let url = format!("{}/v1/sessions/{}/memories", self.base_url, session_id);
1091 let response = self.client.get(&url).send().await?;
1092 self.handle_response(response).await
1093 }
1094
1095 pub async fn batch_recall(&self, request: BatchRecallRequest) -> Result<BatchRecallResponse> {
1119 let url = format!("{}/v1/memories/recall/batch", self.base_url);
1120 let response = self.client.post(&url).json(&request).send().await?;
1121 self.handle_response(response).await
1122 }
1123
1124 pub async fn batch_forget(&self, request: BatchForgetRequest) -> Result<BatchForgetResponse> {
1144 let url = format!("{}/v1/memories/forget/batch", self.base_url);
1145 let response = self.client.delete(&url).json(&request).send().await?;
1146 self.handle_response(response).await
1147 }
1148
1149 pub async fn import_memories(
1167 &self,
1168 data: serde_json::Value,
1169 format: &str,
1170 agent_id: Option<&str>,
1171 namespace: Option<&str>,
1172 ) -> Result<MemoryImportResponse> {
1173 let mut body = serde_json::json!({"data": data, "format": format});
1174 if let Some(aid) = agent_id {
1175 body["agent_id"] = serde_json::Value::String(aid.to_string());
1176 }
1177 if let Some(ns) = namespace {
1178 body["namespace"] = serde_json::Value::String(ns.to_string());
1179 }
1180 let url = format!("{}/v1/import", self.base_url);
1181 let response = self.client.post(&url).json(&body).send().await?;
1182 self.handle_response(response).await
1183 }
1184
1185 pub async fn export_memories(
1189 &self,
1190 format: &str,
1191 agent_id: Option<&str>,
1192 namespace: Option<&str>,
1193 limit: Option<u32>,
1194 ) -> Result<MemoryExportResponse> {
1195 let mut params = vec![("format", format.to_string())];
1196 if let Some(aid) = agent_id {
1197 params.push(("agent_id", aid.to_string()));
1198 }
1199 if let Some(ns) = namespace {
1200 params.push(("namespace", ns.to_string()));
1201 }
1202 if let Some(l) = limit {
1203 params.push(("limit", l.to_string()));
1204 }
1205 let url = format!("{}/v1/export", self.base_url);
1206 let response = self.client.get(&url).query(¶ms).send().await?;
1207 self.handle_response(response).await
1208 }
1209
1210 pub async fn list_audit_events(&self, query: AuditQuery) -> Result<AuditListResponse> {
1216 let url = format!("{}/v1/audit", self.base_url);
1217 let response = self.client.get(&url).query(&query).send().await?;
1218 self.handle_response(response).await
1219 }
1220
1221 pub async fn stream_audit_events(
1225 &self,
1226 agent_id: Option<&str>,
1227 event_type: Option<&str>,
1228 ) -> Result<tokio::sync::mpsc::Receiver<Result<crate::events::DakeraEvent>>> {
1229 let mut params: Vec<(&str, String)> = Vec::new();
1230 if let Some(aid) = agent_id {
1231 params.push(("agent_id", aid.to_string()));
1232 }
1233 if let Some(et) = event_type {
1234 params.push(("event_type", et.to_string()));
1235 }
1236 let base = format!("{}/v1/audit/stream", self.base_url);
1237 let url = if params.is_empty() {
1238 base
1239 } else {
1240 let qs = params
1241 .iter()
1242 .map(|(k, v)| format!("{}={}", k, urlencoding::encode(v)))
1243 .collect::<Vec<_>>()
1244 .join("&");
1245 format!("{}?{}", base, qs)
1246 };
1247 self.stream_sse(url).await
1248 }
1249
1250 pub async fn export_audit(
1252 &self,
1253 format: &str,
1254 agent_id: Option<&str>,
1255 event_type: Option<&str>,
1256 from_ts: Option<u64>,
1257 to_ts: Option<u64>,
1258 ) -> Result<AuditExportResponse> {
1259 let mut body = serde_json::json!({"format": format});
1260 if let Some(aid) = agent_id {
1261 body["agent_id"] = serde_json::Value::String(aid.to_string());
1262 }
1263 if let Some(et) = event_type {
1264 body["event_type"] = serde_json::Value::String(et.to_string());
1265 }
1266 if let Some(f) = from_ts {
1267 body["from"] = serde_json::Value::Number(f.into());
1268 }
1269 if let Some(t) = to_ts {
1270 body["to"] = serde_json::Value::Number(t.into());
1271 }
1272 let url = format!("{}/v1/audit/export", self.base_url);
1273 let response = self.client.post(&url).json(&body).send().await?;
1274 self.handle_response(response).await
1275 }
1276
1277 pub async fn extract_text(
1286 &self,
1287 text: &str,
1288 namespace: Option<&str>,
1289 provider: Option<&str>,
1290 model: Option<&str>,
1291 ) -> Result<ExtractionResult> {
1292 let mut body = serde_json::json!({"text": text});
1293 if let Some(ns) = namespace {
1294 body["namespace"] = serde_json::Value::String(ns.to_string());
1295 }
1296 if let Some(p) = provider {
1297 body["provider"] = serde_json::Value::String(p.to_string());
1298 }
1299 if let Some(m) = model {
1300 body["model"] = serde_json::Value::String(m.to_string());
1301 }
1302 let url = format!("{}/v1/extract", self.base_url);
1303 let response = self.client.post(&url).json(&body).send().await?;
1304 self.handle_response(response).await
1305 }
1306
1307 pub async fn list_extract_providers(&self) -> Result<Vec<ExtractionProviderInfo>> {
1309 let url = format!("{}/v1/extract/providers", self.base_url);
1310 let response = self.client.get(&url).send().await?;
1311 let result: ExtractProvidersResponse = self.handle_response(response).await?;
1312 Ok(match result {
1313 ExtractProvidersResponse::List(v) => v,
1314 ExtractProvidersResponse::Object { providers } => providers,
1315 })
1316 }
1317
1318 pub async fn configure_namespace_extractor(
1320 &self,
1321 namespace: &str,
1322 provider: &str,
1323 model: Option<&str>,
1324 ) -> Result<serde_json::Value> {
1325 let mut body = serde_json::json!({"provider": provider});
1326 if let Some(m) = model {
1327 body["model"] = serde_json::Value::String(m.to_string());
1328 }
1329 let url = format!(
1330 "{}/v1/namespaces/{}/extractor",
1331 self.base_url,
1332 urlencoding::encode(namespace)
1333 );
1334 let response = self.client.patch(&url).json(&body).send().await?;
1335 self.handle_response(response).await
1336 }
1337
1338 pub async fn rotate_encryption_key(
1354 &self,
1355 new_key: &str,
1356 namespace: Option<&str>,
1357 ) -> Result<RotateEncryptionKeyResponse> {
1358 let body = RotateEncryptionKeyRequest {
1359 new_key: new_key.to_string(),
1360 namespace: namespace.map(|s| s.to_string()),
1361 };
1362 let url = format!("{}/v1/admin/encryption/rotate-key", self.base_url);
1363 let response = self.client.post(&url).json(&body).send().await?;
1364 self.handle_response(response).await
1365 }
1366}