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}
152
153fn default_top_k() -> usize {
154 5
155}
156
157impl RecallRequest {
158 pub fn new(agent_id: impl Into<String>, query: impl Into<String>) -> Self {
160 Self {
161 agent_id: agent_id.into(),
162 query: query.into(),
163 top_k: 5,
164 memory_type: None,
165 min_importance: 0.0,
166 session_id: None,
167 tags: Vec::new(),
168 include_associated: false,
169 associated_memories_cap: None,
170 }
171 }
172
173 pub fn with_top_k(mut self, top_k: usize) -> Self {
175 self.top_k = top_k;
176 self
177 }
178
179 pub fn with_type(mut self, memory_type: MemoryType) -> Self {
181 self.memory_type = Some(memory_type);
182 self
183 }
184
185 pub fn with_min_importance(mut self, min: f32) -> Self {
187 self.min_importance = min;
188 self
189 }
190
191 pub fn with_session(mut self, session_id: impl Into<String>) -> Self {
193 self.session_id = Some(session_id.into());
194 self
195 }
196
197 pub fn with_tags(mut self, tags: Vec<String>) -> Self {
199 self.tags = tags;
200 self
201 }
202
203 pub fn with_associated(mut self) -> Self {
205 self.include_associated = true;
206 self
207 }
208
209 pub fn with_associated_cap(mut self, cap: u32) -> Self {
211 self.include_associated = true;
212 self.associated_memories_cap = Some(cap);
213 self
214 }
215}
216
217#[derive(Debug, Clone, Serialize, Deserialize)]
219pub struct RecalledMemory {
220 pub id: String,
221 pub content: String,
222 pub memory_type: MemoryType,
223 pub importance: f32,
224 pub score: f32,
225 #[serde(default)]
226 pub tags: Vec<String>,
227 #[serde(skip_serializing_if = "Option::is_none")]
228 pub session_id: Option<String>,
229 #[serde(skip_serializing_if = "Option::is_none")]
230 pub metadata: Option<serde_json::Value>,
231 pub created_at: u64,
232 pub last_accessed_at: u64,
233 pub access_count: u32,
234}
235
236#[derive(Debug, Clone, Serialize, Deserialize)]
238pub struct RecallResponse {
239 pub memories: Vec<RecalledMemory>,
240 pub total_found: usize,
241 #[serde(skip_serializing_if = "Option::is_none")]
243 pub associated_memories: Option<Vec<RecalledMemory>>,
244}
245
246#[derive(Debug, Clone, Serialize, Deserialize)]
248pub struct ForgetRequest {
249 pub agent_id: String,
250 #[serde(default)]
251 pub memory_ids: Vec<String>,
252 #[serde(default)]
253 pub tags: Vec<String>,
254 #[serde(skip_serializing_if = "Option::is_none")]
255 pub session_id: Option<String>,
256 #[serde(skip_serializing_if = "Option::is_none")]
257 pub before_timestamp: Option<u64>,
258}
259
260impl ForgetRequest {
261 pub fn by_ids(agent_id: impl Into<String>, ids: Vec<String>) -> Self {
263 Self {
264 agent_id: agent_id.into(),
265 memory_ids: ids,
266 tags: Vec::new(),
267 session_id: None,
268 before_timestamp: None,
269 }
270 }
271
272 pub fn by_tags(agent_id: impl Into<String>, tags: Vec<String>) -> Self {
274 Self {
275 agent_id: agent_id.into(),
276 memory_ids: Vec::new(),
277 tags,
278 session_id: None,
279 before_timestamp: None,
280 }
281 }
282
283 pub fn by_session(agent_id: impl Into<String>, session_id: impl Into<String>) -> Self {
285 Self {
286 agent_id: agent_id.into(),
287 memory_ids: Vec::new(),
288 tags: Vec::new(),
289 session_id: Some(session_id.into()),
290 before_timestamp: None,
291 }
292 }
293}
294
295#[derive(Debug, Clone, Serialize, Deserialize)]
297pub struct ForgetResponse {
298 pub deleted_count: u64,
299}
300
301#[derive(Debug, Clone, Serialize, Deserialize)]
303pub struct SessionStartRequest {
304 pub agent_id: String,
305 #[serde(skip_serializing_if = "Option::is_none")]
306 pub metadata: Option<serde_json::Value>,
307}
308
309#[derive(Debug, Clone, Serialize, Deserialize)]
311pub struct Session {
312 pub id: String,
313 pub agent_id: String,
314 pub started_at: u64,
315 #[serde(skip_serializing_if = "Option::is_none")]
316 pub ended_at: Option<u64>,
317 #[serde(skip_serializing_if = "Option::is_none")]
318 pub summary: Option<String>,
319 #[serde(skip_serializing_if = "Option::is_none")]
320 pub metadata: Option<serde_json::Value>,
321}
322
323#[derive(Debug, Clone, Serialize, Deserialize)]
325pub struct SessionEndRequest {
326 #[serde(skip_serializing_if = "Option::is_none")]
327 pub summary: Option<String>,
328}
329
330#[derive(Debug, Clone, Serialize, Deserialize)]
332pub struct UpdateMemoryRequest {
333 #[serde(skip_serializing_if = "Option::is_none")]
334 pub content: Option<String>,
335 #[serde(skip_serializing_if = "Option::is_none")]
336 pub metadata: Option<serde_json::Value>,
337 #[serde(skip_serializing_if = "Option::is_none")]
338 pub memory_type: Option<MemoryType>,
339}
340
341#[derive(Debug, Clone, Serialize, Deserialize)]
343pub struct UpdateImportanceRequest {
344 pub memory_ids: Vec<String>,
345 pub importance: f32,
346}
347
348#[derive(Debug, Clone, Serialize, Deserialize, Default)]
350pub struct ConsolidationConfig {
351 #[serde(skip_serializing_if = "Option::is_none")]
353 pub algorithm: Option<String>,
354 #[serde(skip_serializing_if = "Option::is_none")]
356 pub min_samples: Option<u32>,
357 #[serde(skip_serializing_if = "Option::is_none")]
359 pub eps: Option<f32>,
360}
361
362#[derive(Debug, Clone, Serialize, Deserialize)]
364pub struct ConsolidationLogEntry {
365 pub step: String,
366 pub memories_before: usize,
367 pub memories_after: usize,
368 pub duration_ms: f64,
369}
370
371#[derive(Debug, Clone, Serialize, Deserialize, Default)]
373pub struct ConsolidateRequest {
374 #[serde(skip_serializing_if = "Option::is_none")]
375 pub memory_type: Option<String>,
376 #[serde(skip_serializing_if = "Option::is_none")]
377 pub threshold: Option<f32>,
378 #[serde(default)]
379 pub dry_run: bool,
380 #[serde(skip_serializing_if = "Option::is_none")]
382 pub config: Option<ConsolidationConfig>,
383}
384
385#[derive(Debug, Clone, Serialize, Deserialize)]
387pub struct ConsolidateResponse {
388 pub consolidated_count: usize,
389 pub removed_count: usize,
390 pub new_memories: Vec<String>,
391 #[serde(default, skip_serializing_if = "Vec::is_empty")]
393 pub log: Vec<ConsolidationLogEntry>,
394}
395
396#[derive(Debug, Clone, Serialize, Deserialize)]
402pub struct MemoryImportResponse {
403 pub imported_count: usize,
404 pub skipped_count: usize,
405 #[serde(default)]
406 pub errors: Vec<String>,
407}
408
409#[derive(Debug, Clone, Serialize, Deserialize)]
411pub struct MemoryExportResponse {
412 pub data: Vec<serde_json::Value>,
413 pub format: String,
414 pub count: usize,
415}
416
417#[derive(Debug, Clone, Serialize, Deserialize)]
423pub struct AuditEvent {
424 pub id: String,
425 pub event_type: String,
426 #[serde(skip_serializing_if = "Option::is_none")]
427 pub agent_id: Option<String>,
428 #[serde(skip_serializing_if = "Option::is_none")]
429 pub namespace: Option<String>,
430 pub timestamp: u64,
431 #[serde(default)]
432 pub details: serde_json::Value,
433}
434
435#[derive(Debug, Clone, Serialize, Deserialize)]
437pub struct AuditListResponse {
438 pub events: Vec<AuditEvent>,
439 pub total: usize,
440 #[serde(skip_serializing_if = "Option::is_none")]
441 pub cursor: Option<String>,
442}
443
444#[derive(Debug, Clone, Serialize, Deserialize)]
446pub struct AuditExportResponse {
447 pub data: String,
448 pub format: String,
449 pub count: usize,
450}
451
452#[derive(Debug, Clone, Serialize, Deserialize, Default)]
454pub struct AuditQuery {
455 #[serde(skip_serializing_if = "Option::is_none")]
456 pub agent_id: Option<String>,
457 #[serde(skip_serializing_if = "Option::is_none")]
458 pub event_type: Option<String>,
459 #[serde(skip_serializing_if = "Option::is_none")]
460 pub from: Option<u64>,
461 #[serde(skip_serializing_if = "Option::is_none")]
462 pub to: Option<u64>,
463 #[serde(skip_serializing_if = "Option::is_none")]
464 pub limit: Option<u32>,
465 #[serde(skip_serializing_if = "Option::is_none")]
466 pub cursor: Option<String>,
467}
468
469#[derive(Debug, Clone, Serialize, Deserialize)]
475pub struct ExtractionResult {
476 pub entities: Vec<serde_json::Value>,
477 pub provider: String,
478 #[serde(skip_serializing_if = "Option::is_none")]
479 pub model: Option<String>,
480 pub duration_ms: f64,
481}
482
483#[derive(Debug, Clone, Serialize, Deserialize)]
485pub struct ExtractionProviderInfo {
486 pub name: String,
487 pub available: bool,
488 #[serde(default)]
489 pub models: Vec<String>,
490}
491
492#[derive(Debug, Clone, Serialize, Deserialize)]
494#[serde(untagged)]
495pub enum ExtractProvidersResponse {
496 List(Vec<ExtractionProviderInfo>),
497 Object {
498 providers: Vec<ExtractionProviderInfo>,
499 },
500}
501
502#[derive(Debug, Clone, Serialize, Deserialize)]
508pub struct RotateEncryptionKeyRequest {
509 pub new_key: String,
511 #[serde(skip_serializing_if = "Option::is_none")]
513 pub namespace: Option<String>,
514}
515
516#[derive(Debug, Clone, Serialize, Deserialize)]
518pub struct RotateEncryptionKeyResponse {
519 pub rotated: usize,
520 pub skipped: usize,
521 #[serde(default)]
522 pub namespaces: Vec<String>,
523}
524
525#[derive(Debug, Clone, Serialize, Deserialize)]
527pub struct FeedbackRequest {
528 pub memory_id: String,
529 pub feedback: String,
530 #[serde(skip_serializing_if = "Option::is_none")]
531 pub relevance_score: Option<f32>,
532}
533
534#[derive(Debug, Clone, Serialize, Deserialize)]
536pub struct LegacyFeedbackResponse {
537 pub status: String,
538 pub updated_importance: Option<f32>,
539}
540
541#[derive(Debug, Clone, Serialize, Deserialize, Default)]
550pub struct BatchMemoryFilter {
551 #[serde(skip_serializing_if = "Option::is_none")]
553 pub tags: Option<Vec<String>>,
554 #[serde(skip_serializing_if = "Option::is_none")]
556 pub min_importance: Option<f32>,
557 #[serde(skip_serializing_if = "Option::is_none")]
559 pub max_importance: Option<f32>,
560 #[serde(skip_serializing_if = "Option::is_none")]
562 pub created_after: Option<u64>,
563 #[serde(skip_serializing_if = "Option::is_none")]
565 pub created_before: Option<u64>,
566 #[serde(skip_serializing_if = "Option::is_none")]
568 pub memory_type: Option<MemoryType>,
569 #[serde(skip_serializing_if = "Option::is_none")]
571 pub session_id: Option<String>,
572}
573
574impl BatchMemoryFilter {
575 pub fn with_tags(mut self, tags: Vec<String>) -> Self {
577 self.tags = Some(tags);
578 self
579 }
580
581 pub fn with_min_importance(mut self, min: f32) -> Self {
583 self.min_importance = Some(min);
584 self
585 }
586
587 pub fn with_max_importance(mut self, max: f32) -> Self {
589 self.max_importance = Some(max);
590 self
591 }
592
593 pub fn with_session(mut self, session_id: impl Into<String>) -> Self {
595 self.session_id = Some(session_id.into());
596 self
597 }
598}
599
600#[derive(Debug, Clone, Serialize, Deserialize)]
602pub struct BatchRecallRequest {
603 pub agent_id: String,
605 #[serde(default)]
607 pub filter: BatchMemoryFilter,
608 #[serde(default = "default_batch_limit")]
610 pub limit: usize,
611}
612
613fn default_batch_limit() -> usize {
614 100
615}
616
617impl BatchRecallRequest {
618 pub fn new(agent_id: impl Into<String>) -> Self {
620 Self {
621 agent_id: agent_id.into(),
622 filter: BatchMemoryFilter::default(),
623 limit: 100,
624 }
625 }
626
627 pub fn with_filter(mut self, filter: BatchMemoryFilter) -> Self {
629 self.filter = filter;
630 self
631 }
632
633 pub fn with_limit(mut self, limit: usize) -> Self {
635 self.limit = limit;
636 self
637 }
638}
639
640#[derive(Debug, Clone, Serialize, Deserialize)]
642pub struct BatchRecallResponse {
643 pub memories: Vec<RecalledMemory>,
644 pub total: usize,
646 pub filtered: usize,
648}
649
650#[derive(Debug, Clone, Serialize, Deserialize)]
652pub struct BatchForgetRequest {
653 pub agent_id: String,
655 pub filter: BatchMemoryFilter,
657}
658
659impl BatchForgetRequest {
660 pub fn new(agent_id: impl Into<String>, filter: BatchMemoryFilter) -> Self {
662 Self {
663 agent_id: agent_id.into(),
664 filter,
665 }
666 }
667}
668
669#[derive(Debug, Clone, Serialize, Deserialize)]
671pub struct BatchForgetResponse {
672 pub deleted_count: usize,
673}
674
675impl DakeraClient {
680 pub async fn store_memory(&self, request: StoreMemoryRequest) -> Result<StoreMemoryResponse> {
704 let url = format!("{}/v1/memory/store", self.base_url);
705 let response = self.client.post(&url).json(&request).send().await?;
706 self.handle_response(response).await
707 }
708
709 pub async fn recall(&self, request: RecallRequest) -> Result<RecallResponse> {
730 let url = format!("{}/v1/memory/recall", self.base_url);
731 let response = self.client.post(&url).json(&request).send().await?;
732 self.handle_response(response).await
733 }
734
735 pub async fn recall_simple(
737 &self,
738 agent_id: &str,
739 query: &str,
740 top_k: usize,
741 ) -> Result<RecallResponse> {
742 self.recall(RecallRequest::new(agent_id, query).with_top_k(top_k))
743 .await
744 }
745
746 pub async fn get_memory(&self, memory_id: &str) -> Result<RecalledMemory> {
748 let url = format!("{}/v1/memory/get/{}", self.base_url, memory_id);
749 let response = self.client.get(&url).send().await?;
750 self.handle_response(response).await
751 }
752
753 pub async fn forget(&self, request: ForgetRequest) -> Result<ForgetResponse> {
755 let url = format!("{}/v1/memory/forget", self.base_url);
756 let response = self.client.post(&url).json(&request).send().await?;
757 self.handle_response(response).await
758 }
759
760 pub async fn search_memories(&self, request: RecallRequest) -> Result<RecallResponse> {
762 let url = format!("{}/v1/memory/search", self.base_url);
763 let response = self.client.post(&url).json(&request).send().await?;
764 self.handle_response(response).await
765 }
766
767 pub async fn update_memory(
769 &self,
770 agent_id: &str,
771 memory_id: &str,
772 request: UpdateMemoryRequest,
773 ) -> Result<StoreMemoryResponse> {
774 let url = format!(
775 "{}/v1/agents/{}/memories/{}",
776 self.base_url, agent_id, memory_id
777 );
778 let response = self.client.put(&url).json(&request).send().await?;
779 self.handle_response(response).await
780 }
781
782 pub async fn update_importance(
784 &self,
785 agent_id: &str,
786 request: UpdateImportanceRequest,
787 ) -> Result<serde_json::Value> {
788 let url = format!(
789 "{}/v1/agents/{}/memories/importance",
790 self.base_url, agent_id
791 );
792 let response = self.client.put(&url).json(&request).send().await?;
793 self.handle_response(response).await
794 }
795
796 pub async fn consolidate(
798 &self,
799 agent_id: &str,
800 request: ConsolidateRequest,
801 ) -> Result<ConsolidateResponse> {
802 let url = format!(
803 "{}/v1/agents/{}/memories/consolidate",
804 self.base_url, agent_id
805 );
806 let response = self.client.post(&url).json(&request).send().await?;
807 self.handle_response(response).await
808 }
809
810 pub async fn memory_feedback(
812 &self,
813 agent_id: &str,
814 request: FeedbackRequest,
815 ) -> Result<LegacyFeedbackResponse> {
816 let url = format!("{}/v1/agents/{}/memories/feedback", self.base_url, agent_id);
817 let response = self.client.post(&url).json(&request).send().await?;
818 self.handle_response(response).await
819 }
820
821 pub async fn feedback_memory(
841 &self,
842 memory_id: &str,
843 agent_id: &str,
844 signal: FeedbackSignal,
845 ) -> Result<FeedbackResponse> {
846 let url = format!("{}/v1/memories/{}/feedback", self.base_url, memory_id);
847 let body = MemoryFeedbackBody {
848 agent_id: agent_id.to_string(),
849 signal,
850 };
851 let response = self.client.post(&url).json(&body).send().await?;
852 self.handle_response(response).await
853 }
854
855 pub async fn get_memory_feedback_history(
857 &self,
858 memory_id: &str,
859 ) -> Result<FeedbackHistoryResponse> {
860 let url = format!("{}/v1/memories/{}/feedback", self.base_url, memory_id);
861 let response = self.client.get(&url).send().await?;
862 self.handle_response(response).await
863 }
864
865 pub async fn get_agent_feedback_summary(&self, agent_id: &str) -> Result<AgentFeedbackSummary> {
867 let url = format!("{}/v1/agents/{}/feedback/summary", self.base_url, agent_id);
868 let response = self.client.get(&url).send().await?;
869 self.handle_response(response).await
870 }
871
872 pub async fn patch_memory_importance(
879 &self,
880 memory_id: &str,
881 agent_id: &str,
882 importance: f32,
883 ) -> Result<FeedbackResponse> {
884 let url = format!("{}/v1/memories/{}/importance", self.base_url, memory_id);
885 let body = MemoryImportancePatch {
886 agent_id: agent_id.to_string(),
887 importance,
888 };
889 let response = self.client.patch(&url).json(&body).send().await?;
890 self.handle_response(response).await
891 }
892
893 pub async fn get_feedback_health(&self, agent_id: &str) -> Result<FeedbackHealthResponse> {
898 let url = format!("{}/v1/feedback/health?agent_id={}", self.base_url, agent_id);
899 let response = self.client.get(&url).send().await?;
900 self.handle_response(response).await
901 }
902
903 pub async fn memory_graph(
924 &self,
925 memory_id: &str,
926 options: GraphOptions,
927 ) -> Result<MemoryGraph> {
928 let mut url = format!("{}/v1/memories/{}/graph", self.base_url, memory_id);
929 let depth = options.depth.unwrap_or(1);
930 url.push_str(&format!("?depth={}", depth));
931 if let Some(types) = &options.types {
932 let type_strs: Vec<String> = types
933 .iter()
934 .map(|t| {
935 serde_json::to_value(t)
936 .unwrap()
937 .as_str()
938 .unwrap_or("")
939 .to_string()
940 })
941 .collect();
942 if !type_strs.is_empty() {
943 url.push_str(&format!("&types={}", type_strs.join(",")));
944 }
945 }
946 let response = self.client.get(&url).send().await?;
947 self.handle_response(response).await
948 }
949
950 pub async fn memory_path(&self, source_id: &str, target_id: &str) -> Result<GraphPath> {
963 let url = format!(
964 "{}/v1/memories/{}/path?target={}",
965 self.base_url,
966 source_id,
967 urlencoding::encode(target_id)
968 );
969 let response = self.client.get(&url).send().await?;
970 self.handle_response(response).await
971 }
972
973 pub async fn memory_link(
986 &self,
987 source_id: &str,
988 target_id: &str,
989 edge_type: EdgeType,
990 ) -> Result<GraphLinkResponse> {
991 let url = format!("{}/v1/memories/{}/links", self.base_url, source_id);
992 let request = GraphLinkRequest {
993 target_id: target_id.to_string(),
994 edge_type,
995 };
996 let response = self.client.post(&url).json(&request).send().await?;
997 self.handle_response(response).await
998 }
999
1000 pub async fn agent_graph_export(&self, agent_id: &str, format: &str) -> Result<GraphExport> {
1008 let url = format!(
1009 "{}/v1/agents/{}/graph/export?format={}",
1010 self.base_url, agent_id, format
1011 );
1012 let response = self.client.get(&url).send().await?;
1013 self.handle_response(response).await
1014 }
1015
1016 pub async fn start_session(&self, agent_id: &str) -> Result<Session> {
1022 let url = format!("{}/v1/sessions/start", self.base_url);
1023 let request = SessionStartRequest {
1024 agent_id: agent_id.to_string(),
1025 metadata: None,
1026 };
1027 let response = self.client.post(&url).json(&request).send().await?;
1028 self.handle_response(response).await
1029 }
1030
1031 pub async fn start_session_with_metadata(
1033 &self,
1034 agent_id: &str,
1035 metadata: serde_json::Value,
1036 ) -> Result<Session> {
1037 let url = format!("{}/v1/sessions/start", self.base_url);
1038 let request = SessionStartRequest {
1039 agent_id: agent_id.to_string(),
1040 metadata: Some(metadata),
1041 };
1042 let response = self.client.post(&url).json(&request).send().await?;
1043 self.handle_response(response).await
1044 }
1045
1046 pub async fn end_session(&self, session_id: &str, summary: Option<String>) -> Result<Session> {
1048 let url = format!("{}/v1/sessions/{}/end", self.base_url, session_id);
1049 let request = SessionEndRequest { summary };
1050 let response = self.client.post(&url).json(&request).send().await?;
1051 self.handle_response(response).await
1052 }
1053
1054 pub async fn get_session(&self, session_id: &str) -> Result<Session> {
1056 let url = format!("{}/v1/sessions/{}", self.base_url, session_id);
1057 let response = self.client.get(&url).send().await?;
1058 self.handle_response(response).await
1059 }
1060
1061 pub async fn list_sessions(&self, agent_id: &str) -> Result<Vec<Session>> {
1063 let url = format!("{}/v1/sessions?agent_id={}", self.base_url, agent_id);
1064 let response = self.client.get(&url).send().await?;
1065 self.handle_response(response).await
1066 }
1067
1068 pub async fn session_memories(&self, session_id: &str) -> Result<RecallResponse> {
1070 let url = format!("{}/v1/sessions/{}/memories", self.base_url, session_id);
1071 let response = self.client.get(&url).send().await?;
1072 self.handle_response(response).await
1073 }
1074
1075 pub async fn batch_recall(&self, request: BatchRecallRequest) -> Result<BatchRecallResponse> {
1099 let url = format!("{}/v1/memories/recall/batch", self.base_url);
1100 let response = self.client.post(&url).json(&request).send().await?;
1101 self.handle_response(response).await
1102 }
1103
1104 pub async fn batch_forget(&self, request: BatchForgetRequest) -> Result<BatchForgetResponse> {
1124 let url = format!("{}/v1/memories/forget/batch", self.base_url);
1125 let response = self.client.delete(&url).json(&request).send().await?;
1126 self.handle_response(response).await
1127 }
1128
1129 pub async fn import_memories(
1147 &self,
1148 data: serde_json::Value,
1149 format: &str,
1150 agent_id: Option<&str>,
1151 namespace: Option<&str>,
1152 ) -> Result<MemoryImportResponse> {
1153 let mut body = serde_json::json!({"data": data, "format": format});
1154 if let Some(aid) = agent_id {
1155 body["agent_id"] = serde_json::Value::String(aid.to_string());
1156 }
1157 if let Some(ns) = namespace {
1158 body["namespace"] = serde_json::Value::String(ns.to_string());
1159 }
1160 let url = format!("{}/v1/import", self.base_url);
1161 let response = self.client.post(&url).json(&body).send().await?;
1162 self.handle_response(response).await
1163 }
1164
1165 pub async fn export_memories(
1169 &self,
1170 format: &str,
1171 agent_id: Option<&str>,
1172 namespace: Option<&str>,
1173 limit: Option<u32>,
1174 ) -> Result<MemoryExportResponse> {
1175 let mut params = vec![("format", format.to_string())];
1176 if let Some(aid) = agent_id {
1177 params.push(("agent_id", aid.to_string()));
1178 }
1179 if let Some(ns) = namespace {
1180 params.push(("namespace", ns.to_string()));
1181 }
1182 if let Some(l) = limit {
1183 params.push(("limit", l.to_string()));
1184 }
1185 let url = format!("{}/v1/export", self.base_url);
1186 let response = self.client.get(&url).query(¶ms).send().await?;
1187 self.handle_response(response).await
1188 }
1189
1190 pub async fn list_audit_events(&self, query: AuditQuery) -> Result<AuditListResponse> {
1196 let url = format!("{}/v1/audit", self.base_url);
1197 let response = self.client.get(&url).query(&query).send().await?;
1198 self.handle_response(response).await
1199 }
1200
1201 pub async fn stream_audit_events(
1205 &self,
1206 agent_id: Option<&str>,
1207 event_type: Option<&str>,
1208 ) -> Result<tokio::sync::mpsc::Receiver<Result<crate::events::DakeraEvent>>> {
1209 let mut params: Vec<(&str, String)> = Vec::new();
1210 if let Some(aid) = agent_id {
1211 params.push(("agent_id", aid.to_string()));
1212 }
1213 if let Some(et) = event_type {
1214 params.push(("event_type", et.to_string()));
1215 }
1216 let base = format!("{}/v1/audit/stream", self.base_url);
1217 let url = if params.is_empty() {
1218 base
1219 } else {
1220 let qs = params
1221 .iter()
1222 .map(|(k, v)| format!("{}={}", k, urlencoding::encode(v)))
1223 .collect::<Vec<_>>()
1224 .join("&");
1225 format!("{}?{}", base, qs)
1226 };
1227 self.stream_sse(url).await
1228 }
1229
1230 pub async fn export_audit(
1232 &self,
1233 format: &str,
1234 agent_id: Option<&str>,
1235 event_type: Option<&str>,
1236 from_ts: Option<u64>,
1237 to_ts: Option<u64>,
1238 ) -> Result<AuditExportResponse> {
1239 let mut body = serde_json::json!({"format": format});
1240 if let Some(aid) = agent_id {
1241 body["agent_id"] = serde_json::Value::String(aid.to_string());
1242 }
1243 if let Some(et) = event_type {
1244 body["event_type"] = serde_json::Value::String(et.to_string());
1245 }
1246 if let Some(f) = from_ts {
1247 body["from"] = serde_json::Value::Number(f.into());
1248 }
1249 if let Some(t) = to_ts {
1250 body["to"] = serde_json::Value::Number(t.into());
1251 }
1252 let url = format!("{}/v1/audit/export", self.base_url);
1253 let response = self.client.post(&url).json(&body).send().await?;
1254 self.handle_response(response).await
1255 }
1256
1257 pub async fn extract_text(
1266 &self,
1267 text: &str,
1268 namespace: Option<&str>,
1269 provider: Option<&str>,
1270 model: Option<&str>,
1271 ) -> Result<ExtractionResult> {
1272 let mut body = serde_json::json!({"text": text});
1273 if let Some(ns) = namespace {
1274 body["namespace"] = serde_json::Value::String(ns.to_string());
1275 }
1276 if let Some(p) = provider {
1277 body["provider"] = serde_json::Value::String(p.to_string());
1278 }
1279 if let Some(m) = model {
1280 body["model"] = serde_json::Value::String(m.to_string());
1281 }
1282 let url = format!("{}/v1/extract", self.base_url);
1283 let response = self.client.post(&url).json(&body).send().await?;
1284 self.handle_response(response).await
1285 }
1286
1287 pub async fn list_extract_providers(&self) -> Result<Vec<ExtractionProviderInfo>> {
1289 let url = format!("{}/v1/extract/providers", self.base_url);
1290 let response = self.client.get(&url).send().await?;
1291 let result: ExtractProvidersResponse = self.handle_response(response).await?;
1292 Ok(match result {
1293 ExtractProvidersResponse::List(v) => v,
1294 ExtractProvidersResponse::Object { providers } => providers,
1295 })
1296 }
1297
1298 pub async fn configure_namespace_extractor(
1300 &self,
1301 namespace: &str,
1302 provider: &str,
1303 model: Option<&str>,
1304 ) -> Result<serde_json::Value> {
1305 let mut body = serde_json::json!({"provider": provider});
1306 if let Some(m) = model {
1307 body["model"] = serde_json::Value::String(m.to_string());
1308 }
1309 let url = format!(
1310 "{}/v1/namespaces/{}/extractor",
1311 self.base_url,
1312 urlencoding::encode(namespace)
1313 );
1314 let response = self.client.patch(&url).json(&body).send().await?;
1315 self.handle_response(response).await
1316 }
1317
1318 pub async fn rotate_encryption_key(
1334 &self,
1335 new_key: &str,
1336 namespace: Option<&str>,
1337 ) -> Result<RotateEncryptionKeyResponse> {
1338 let body = RotateEncryptionKeyRequest {
1339 new_key: new_key.to_string(),
1340 namespace: namespace.map(|s| s.to_string()),
1341 };
1342 let url = format!("{}/v1/admin/encryption/rotate-key", self.base_url);
1343 let response = self.client.post(&url).json(&body).send().await?;
1344 self.handle_response(response).await
1345 }
1346}