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, PartialEq, Eq)]
134#[serde(rename_all = "snake_case")]
135pub enum RoutingMode {
136 Auto,
138 Vector,
140 Bm25,
142 Hybrid,
144}
145
146#[derive(Debug, Clone, Serialize, Deserialize)]
148pub struct RecallRequest {
149 pub agent_id: String,
150 pub query: String,
151 #[serde(default = "default_top_k")]
152 pub top_k: usize,
153 #[serde(skip_serializing_if = "Option::is_none")]
154 pub memory_type: Option<MemoryType>,
155 #[serde(default)]
156 pub min_importance: f32,
157 #[serde(skip_serializing_if = "Option::is_none")]
158 pub session_id: Option<String>,
159 #[serde(default)]
160 pub tags: Vec<String>,
161 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
164 pub include_associated: bool,
165 #[serde(skip_serializing_if = "Option::is_none")]
167 pub associated_memories_cap: Option<u32>,
168 #[serde(skip_serializing_if = "Option::is_none")]
170 pub associated_memories_depth: Option<u8>,
171 #[serde(skip_serializing_if = "Option::is_none")]
173 pub associated_memories_min_weight: Option<f32>,
174 #[serde(skip_serializing_if = "Option::is_none")]
176 pub since: Option<String>,
177 #[serde(skip_serializing_if = "Option::is_none")]
179 pub until: Option<String>,
180 #[serde(skip_serializing_if = "Option::is_none")]
182 pub routing: Option<RoutingMode>,
183}
184
185fn default_top_k() -> usize {
186 5
187}
188
189impl RecallRequest {
190 pub fn new(agent_id: impl Into<String>, query: impl Into<String>) -> Self {
192 Self {
193 agent_id: agent_id.into(),
194 query: query.into(),
195 top_k: 5,
196 memory_type: None,
197 min_importance: 0.0,
198 session_id: None,
199 tags: Vec::new(),
200 include_associated: false,
201 associated_memories_cap: None,
202 associated_memories_depth: None,
203 associated_memories_min_weight: None,
204 since: None,
205 until: None,
206 routing: None,
207 }
208 }
209
210 pub fn with_top_k(mut self, top_k: usize) -> Self {
212 self.top_k = top_k;
213 self
214 }
215
216 pub fn with_type(mut self, memory_type: MemoryType) -> Self {
218 self.memory_type = Some(memory_type);
219 self
220 }
221
222 pub fn with_min_importance(mut self, min: f32) -> Self {
224 self.min_importance = min;
225 self
226 }
227
228 pub fn with_session(mut self, session_id: impl Into<String>) -> Self {
230 self.session_id = Some(session_id.into());
231 self
232 }
233
234 pub fn with_tags(mut self, tags: Vec<String>) -> Self {
236 self.tags = tags;
237 self
238 }
239
240 pub fn with_associated(mut self) -> Self {
242 self.include_associated = true;
243 self
244 }
245
246 pub fn with_associated_cap(mut self, cap: u32) -> Self {
248 self.include_associated = true;
249 self.associated_memories_cap = Some(cap);
250 self
251 }
252
253 pub fn with_since(mut self, since: impl Into<String>) -> Self {
255 self.since = Some(since.into());
256 self
257 }
258
259 pub fn with_until(mut self, until: impl Into<String>) -> Self {
261 self.until = Some(until.into());
262 self
263 }
264
265 pub fn with_routing(mut self, routing: RoutingMode) -> Self {
267 self.routing = Some(routing);
268 self
269 }
270
271 pub fn with_associated_depth(mut self, depth: u8) -> Self {
273 self.include_associated = true;
274 self.associated_memories_depth = Some(depth);
275 self
276 }
277
278 pub fn with_associated_min_weight(mut self, weight: f32) -> Self {
280 self.associated_memories_min_weight = Some(weight);
281 self
282 }
283}
284
285#[derive(Debug, Clone, Serialize, Deserialize)]
287pub struct RecalledMemory {
288 pub id: String,
289 pub content: String,
290 pub memory_type: MemoryType,
291 pub importance: f32,
292 pub score: f32,
293 #[serde(default)]
294 pub tags: Vec<String>,
295 #[serde(skip_serializing_if = "Option::is_none")]
296 pub session_id: Option<String>,
297 #[serde(skip_serializing_if = "Option::is_none")]
298 pub metadata: Option<serde_json::Value>,
299 pub created_at: u64,
300 pub last_accessed_at: u64,
301 pub access_count: u32,
302 #[serde(skip_serializing_if = "Option::is_none")]
304 pub depth: Option<u8>,
305}
306
307#[derive(Debug, Clone, Serialize, Deserialize)]
309pub struct RecallResponse {
310 pub memories: Vec<RecalledMemory>,
311 pub total_found: usize,
312 #[serde(skip_serializing_if = "Option::is_none")]
314 pub associated_memories: Option<Vec<RecalledMemory>>,
315}
316
317#[derive(Debug, Clone, Serialize, Deserialize)]
319pub struct ForgetRequest {
320 pub agent_id: String,
321 #[serde(default)]
322 pub memory_ids: Vec<String>,
323 #[serde(default)]
324 pub tags: Vec<String>,
325 #[serde(skip_serializing_if = "Option::is_none")]
326 pub session_id: Option<String>,
327 #[serde(skip_serializing_if = "Option::is_none")]
328 pub before_timestamp: Option<u64>,
329}
330
331impl ForgetRequest {
332 pub fn by_ids(agent_id: impl Into<String>, ids: Vec<String>) -> Self {
334 Self {
335 agent_id: agent_id.into(),
336 memory_ids: ids,
337 tags: Vec::new(),
338 session_id: None,
339 before_timestamp: None,
340 }
341 }
342
343 pub fn by_tags(agent_id: impl Into<String>, tags: Vec<String>) -> Self {
345 Self {
346 agent_id: agent_id.into(),
347 memory_ids: Vec::new(),
348 tags,
349 session_id: None,
350 before_timestamp: None,
351 }
352 }
353
354 pub fn by_session(agent_id: impl Into<String>, session_id: impl Into<String>) -> Self {
356 Self {
357 agent_id: agent_id.into(),
358 memory_ids: Vec::new(),
359 tags: Vec::new(),
360 session_id: Some(session_id.into()),
361 before_timestamp: None,
362 }
363 }
364}
365
366#[derive(Debug, Clone, Serialize, Deserialize)]
368pub struct ForgetResponse {
369 pub deleted_count: u64,
370}
371
372#[derive(Debug, Clone, Serialize, Deserialize)]
374pub struct SessionStartRequest {
375 pub agent_id: String,
376 #[serde(skip_serializing_if = "Option::is_none")]
377 pub metadata: Option<serde_json::Value>,
378}
379
380#[derive(Debug, Clone, Serialize, Deserialize)]
382pub struct Session {
383 pub id: String,
384 pub agent_id: String,
385 pub started_at: u64,
386 #[serde(skip_serializing_if = "Option::is_none")]
387 pub ended_at: Option<u64>,
388 #[serde(skip_serializing_if = "Option::is_none")]
389 pub summary: Option<String>,
390 #[serde(skip_serializing_if = "Option::is_none")]
391 pub metadata: Option<serde_json::Value>,
392 #[serde(default)]
394 pub memory_count: usize,
395}
396
397#[derive(Debug, Clone, Serialize, Deserialize)]
399pub struct SessionEndRequest {
400 #[serde(skip_serializing_if = "Option::is_none")]
401 pub summary: Option<String>,
402}
403
404#[derive(Debug, Clone, Serialize, Deserialize)]
406pub struct SessionStartResponse {
407 pub session: Session,
408}
409
410#[derive(Debug, Clone, Serialize, Deserialize)]
412pub struct SessionEndResponse {
413 pub session: Session,
414 pub memory_count: usize,
415}
416
417#[derive(Debug, Clone, Serialize, Deserialize)]
419pub struct UpdateMemoryRequest {
420 #[serde(skip_serializing_if = "Option::is_none")]
421 pub content: Option<String>,
422 #[serde(skip_serializing_if = "Option::is_none")]
423 pub metadata: Option<serde_json::Value>,
424 #[serde(skip_serializing_if = "Option::is_none")]
425 pub memory_type: Option<MemoryType>,
426}
427
428#[derive(Debug, Clone, Serialize, Deserialize)]
430pub struct UpdateImportanceRequest {
431 pub memory_ids: Vec<String>,
432 pub importance: f32,
433}
434
435#[derive(Debug, Clone, Serialize, Deserialize, Default)]
437pub struct ConsolidationConfig {
438 #[serde(skip_serializing_if = "Option::is_none")]
440 pub algorithm: Option<String>,
441 #[serde(skip_serializing_if = "Option::is_none")]
443 pub min_samples: Option<u32>,
444 #[serde(skip_serializing_if = "Option::is_none")]
446 pub eps: Option<f32>,
447}
448
449#[derive(Debug, Clone, Serialize, Deserialize)]
451pub struct ConsolidationLogEntry {
452 pub step: String,
453 pub memories_before: usize,
454 pub memories_after: usize,
455 pub duration_ms: f64,
456}
457
458#[derive(Debug, Clone, Serialize, Deserialize, Default)]
460pub struct ConsolidateRequest {
461 #[serde(skip_serializing_if = "Option::is_none")]
462 pub memory_type: Option<String>,
463 #[serde(skip_serializing_if = "Option::is_none")]
464 pub threshold: Option<f32>,
465 #[serde(default)]
466 pub dry_run: bool,
467 #[serde(skip_serializing_if = "Option::is_none")]
469 pub config: Option<ConsolidationConfig>,
470}
471
472#[derive(Debug, Clone, Serialize, Deserialize)]
474pub struct ConsolidateResponse {
475 pub consolidated_count: usize,
476 pub removed_count: usize,
477 pub new_memories: Vec<String>,
478 #[serde(default, skip_serializing_if = "Vec::is_empty")]
480 pub log: Vec<ConsolidationLogEntry>,
481}
482
483#[derive(Debug, Clone, Serialize, Deserialize)]
489pub struct MemoryImportResponse {
490 pub imported_count: usize,
491 pub skipped_count: usize,
492 #[serde(default)]
493 pub errors: Vec<String>,
494}
495
496#[derive(Debug, Clone, Serialize, Deserialize)]
498pub struct MemoryExportResponse {
499 pub data: Vec<serde_json::Value>,
500 pub format: String,
501 pub count: usize,
502}
503
504#[derive(Debug, Clone, Serialize, Deserialize)]
510pub struct AuditEvent {
511 pub id: String,
512 pub event_type: String,
513 #[serde(skip_serializing_if = "Option::is_none")]
514 pub agent_id: Option<String>,
515 #[serde(skip_serializing_if = "Option::is_none")]
516 pub namespace: Option<String>,
517 pub timestamp: u64,
518 #[serde(default)]
519 pub details: serde_json::Value,
520}
521
522#[derive(Debug, Clone, Serialize, Deserialize)]
524pub struct AuditListResponse {
525 pub events: Vec<AuditEvent>,
526 pub total: usize,
527 #[serde(skip_serializing_if = "Option::is_none")]
528 pub cursor: Option<String>,
529}
530
531#[derive(Debug, Clone, Serialize, Deserialize)]
533pub struct AuditExportResponse {
534 pub data: String,
535 pub format: String,
536 pub count: usize,
537}
538
539#[derive(Debug, Clone, Serialize, Deserialize, Default)]
541pub struct AuditQuery {
542 #[serde(skip_serializing_if = "Option::is_none")]
543 pub agent_id: Option<String>,
544 #[serde(skip_serializing_if = "Option::is_none")]
545 pub event_type: Option<String>,
546 #[serde(skip_serializing_if = "Option::is_none")]
547 pub from: Option<u64>,
548 #[serde(skip_serializing_if = "Option::is_none")]
549 pub to: Option<u64>,
550 #[serde(skip_serializing_if = "Option::is_none")]
551 pub limit: Option<u32>,
552 #[serde(skip_serializing_if = "Option::is_none")]
553 pub cursor: Option<String>,
554}
555
556#[derive(Debug, Clone, Serialize, Deserialize)]
562pub struct ExtractionResult {
563 pub entities: Vec<serde_json::Value>,
564 pub provider: String,
565 #[serde(skip_serializing_if = "Option::is_none")]
566 pub model: Option<String>,
567 pub duration_ms: f64,
568}
569
570#[derive(Debug, Clone, Serialize, Deserialize)]
572pub struct ExtractionProviderInfo {
573 pub name: String,
574 pub available: bool,
575 #[serde(default)]
576 pub models: Vec<String>,
577}
578
579#[derive(Debug, Clone, Serialize, Deserialize)]
581#[serde(untagged)]
582pub enum ExtractProvidersResponse {
583 List(Vec<ExtractionProviderInfo>),
584 Object {
585 providers: Vec<ExtractionProviderInfo>,
586 },
587}
588
589#[derive(Debug, Clone, Serialize, Deserialize)]
595pub struct RotateEncryptionKeyRequest {
596 pub new_key: String,
598 #[serde(skip_serializing_if = "Option::is_none")]
600 pub namespace: Option<String>,
601}
602
603#[derive(Debug, Clone, Serialize, Deserialize)]
605pub struct RotateEncryptionKeyResponse {
606 pub rotated: usize,
607 pub skipped: usize,
608 #[serde(default)]
609 pub namespaces: Vec<String>,
610}
611
612#[derive(Debug, Clone, Serialize, Deserialize)]
614pub struct FeedbackRequest {
615 pub memory_id: String,
616 pub feedback: String,
617 #[serde(skip_serializing_if = "Option::is_none")]
618 pub relevance_score: Option<f32>,
619}
620
621#[derive(Debug, Clone, Serialize, Deserialize)]
623pub struct LegacyFeedbackResponse {
624 pub status: String,
625 pub updated_importance: Option<f32>,
626}
627
628#[derive(Debug, Clone, Serialize, Deserialize, Default)]
637pub struct BatchMemoryFilter {
638 #[serde(skip_serializing_if = "Option::is_none")]
640 pub tags: Option<Vec<String>>,
641 #[serde(skip_serializing_if = "Option::is_none")]
643 pub min_importance: Option<f32>,
644 #[serde(skip_serializing_if = "Option::is_none")]
646 pub max_importance: Option<f32>,
647 #[serde(skip_serializing_if = "Option::is_none")]
649 pub created_after: Option<u64>,
650 #[serde(skip_serializing_if = "Option::is_none")]
652 pub created_before: Option<u64>,
653 #[serde(skip_serializing_if = "Option::is_none")]
655 pub memory_type: Option<MemoryType>,
656 #[serde(skip_serializing_if = "Option::is_none")]
658 pub session_id: Option<String>,
659}
660
661impl BatchMemoryFilter {
662 pub fn with_tags(mut self, tags: Vec<String>) -> Self {
664 self.tags = Some(tags);
665 self
666 }
667
668 pub fn with_min_importance(mut self, min: f32) -> Self {
670 self.min_importance = Some(min);
671 self
672 }
673
674 pub fn with_max_importance(mut self, max: f32) -> Self {
676 self.max_importance = Some(max);
677 self
678 }
679
680 pub fn with_session(mut self, session_id: impl Into<String>) -> Self {
682 self.session_id = Some(session_id.into());
683 self
684 }
685}
686
687#[derive(Debug, Clone, Serialize, Deserialize)]
689pub struct BatchRecallRequest {
690 pub agent_id: String,
692 #[serde(default)]
694 pub filter: BatchMemoryFilter,
695 #[serde(default = "default_batch_limit")]
697 pub limit: usize,
698}
699
700fn default_batch_limit() -> usize {
701 100
702}
703
704impl BatchRecallRequest {
705 pub fn new(agent_id: impl Into<String>) -> Self {
707 Self {
708 agent_id: agent_id.into(),
709 filter: BatchMemoryFilter::default(),
710 limit: 100,
711 }
712 }
713
714 pub fn with_filter(mut self, filter: BatchMemoryFilter) -> Self {
716 self.filter = filter;
717 self
718 }
719
720 pub fn with_limit(mut self, limit: usize) -> Self {
722 self.limit = limit;
723 self
724 }
725}
726
727#[derive(Debug, Clone, Serialize, Deserialize)]
729pub struct BatchRecallResponse {
730 pub memories: Vec<RecalledMemory>,
731 pub total: usize,
733 pub filtered: usize,
735}
736
737#[derive(Debug, Clone, Serialize, Deserialize)]
739pub struct BatchForgetRequest {
740 pub agent_id: String,
742 pub filter: BatchMemoryFilter,
744}
745
746impl BatchForgetRequest {
747 pub fn new(agent_id: impl Into<String>, filter: BatchMemoryFilter) -> Self {
749 Self {
750 agent_id: agent_id.into(),
751 filter,
752 }
753 }
754}
755
756#[derive(Debug, Clone, Serialize, Deserialize)]
758pub struct BatchForgetResponse {
759 pub deleted_count: usize,
760}
761
762impl DakeraClient {
767 pub async fn store_memory(&self, request: StoreMemoryRequest) -> Result<StoreMemoryResponse> {
791 let url = format!("{}/v1/memory/store", self.base_url);
792 let response = self.client.post(&url).json(&request).send().await?;
793 self.handle_response(response).await
794 }
795
796 pub async fn recall(&self, request: RecallRequest) -> Result<RecallResponse> {
817 let url = format!("{}/v1/memory/recall", self.base_url);
818 let response = self.client.post(&url).json(&request).send().await?;
819 self.handle_response(response).await
820 }
821
822 pub async fn recall_simple(
824 &self,
825 agent_id: &str,
826 query: &str,
827 top_k: usize,
828 ) -> Result<RecallResponse> {
829 self.recall(RecallRequest::new(agent_id, query).with_top_k(top_k))
830 .await
831 }
832
833 pub async fn get_memory(&self, memory_id: &str) -> Result<RecalledMemory> {
835 let url = format!("{}/v1/memory/get/{}", self.base_url, memory_id);
836 let response = self.client.get(&url).send().await?;
837 self.handle_response(response).await
838 }
839
840 pub async fn forget(&self, request: ForgetRequest) -> Result<ForgetResponse> {
842 let url = format!("{}/v1/memory/forget", self.base_url);
843 let response = self.client.post(&url).json(&request).send().await?;
844 self.handle_response(response).await
845 }
846
847 pub async fn search_memories(&self, request: RecallRequest) -> Result<RecallResponse> {
849 let url = format!("{}/v1/memory/search", self.base_url);
850 let response = self.client.post(&url).json(&request).send().await?;
851 self.handle_response(response).await
852 }
853
854 pub async fn update_memory(
856 &self,
857 agent_id: &str,
858 memory_id: &str,
859 request: UpdateMemoryRequest,
860 ) -> Result<StoreMemoryResponse> {
861 let url = format!(
862 "{}/v1/agents/{}/memories/{}",
863 self.base_url, agent_id, memory_id
864 );
865 let response = self.client.put(&url).json(&request).send().await?;
866 self.handle_response(response).await
867 }
868
869 pub async fn update_importance(
871 &self,
872 agent_id: &str,
873 request: UpdateImportanceRequest,
874 ) -> Result<serde_json::Value> {
875 let url = format!(
876 "{}/v1/agents/{}/memories/importance",
877 self.base_url, agent_id
878 );
879 let response = self.client.put(&url).json(&request).send().await?;
880 self.handle_response(response).await
881 }
882
883 pub async fn consolidate(
885 &self,
886 agent_id: &str,
887 request: ConsolidateRequest,
888 ) -> Result<ConsolidateResponse> {
889 let url = format!(
890 "{}/v1/agents/{}/memories/consolidate",
891 self.base_url, agent_id
892 );
893 let response = self.client.post(&url).json(&request).send().await?;
894 self.handle_response(response).await
895 }
896
897 pub async fn memory_feedback(
899 &self,
900 agent_id: &str,
901 request: FeedbackRequest,
902 ) -> Result<LegacyFeedbackResponse> {
903 let url = format!("{}/v1/agents/{}/memories/feedback", self.base_url, agent_id);
904 let response = self.client.post(&url).json(&request).send().await?;
905 self.handle_response(response).await
906 }
907
908 pub async fn feedback_memory(
928 &self,
929 memory_id: &str,
930 agent_id: &str,
931 signal: FeedbackSignal,
932 ) -> Result<FeedbackResponse> {
933 let url = format!("{}/v1/memories/{}/feedback", self.base_url, memory_id);
934 let body = MemoryFeedbackBody {
935 agent_id: agent_id.to_string(),
936 signal,
937 };
938 let response = self.client.post(&url).json(&body).send().await?;
939 self.handle_response(response).await
940 }
941
942 pub async fn get_memory_feedback_history(
944 &self,
945 memory_id: &str,
946 ) -> Result<FeedbackHistoryResponse> {
947 let url = format!("{}/v1/memories/{}/feedback", self.base_url, memory_id);
948 let response = self.client.get(&url).send().await?;
949 self.handle_response(response).await
950 }
951
952 pub async fn get_agent_feedback_summary(&self, agent_id: &str) -> Result<AgentFeedbackSummary> {
954 let url = format!("{}/v1/agents/{}/feedback/summary", self.base_url, agent_id);
955 let response = self.client.get(&url).send().await?;
956 self.handle_response(response).await
957 }
958
959 pub async fn patch_memory_importance(
966 &self,
967 memory_id: &str,
968 agent_id: &str,
969 importance: f32,
970 ) -> Result<FeedbackResponse> {
971 let url = format!("{}/v1/memories/{}/importance", self.base_url, memory_id);
972 let body = MemoryImportancePatch {
973 agent_id: agent_id.to_string(),
974 importance,
975 };
976 let response = self.client.patch(&url).json(&body).send().await?;
977 self.handle_response(response).await
978 }
979
980 pub async fn get_feedback_health(&self, agent_id: &str) -> Result<FeedbackHealthResponse> {
985 let url = format!("{}/v1/feedback/health?agent_id={}", self.base_url, agent_id);
986 let response = self.client.get(&url).send().await?;
987 self.handle_response(response).await
988 }
989
990 pub async fn memory_graph(
1011 &self,
1012 memory_id: &str,
1013 options: GraphOptions,
1014 ) -> Result<MemoryGraph> {
1015 let mut url = format!("{}/v1/memories/{}/graph", self.base_url, memory_id);
1016 let depth = options.depth.unwrap_or(1);
1017 url.push_str(&format!("?depth={}", depth));
1018 if let Some(types) = &options.types {
1019 let type_strs: Vec<String> = types
1020 .iter()
1021 .map(|t| {
1022 serde_json::to_value(t)
1023 .unwrap()
1024 .as_str()
1025 .unwrap_or("")
1026 .to_string()
1027 })
1028 .collect();
1029 if !type_strs.is_empty() {
1030 url.push_str(&format!("&types={}", type_strs.join(",")));
1031 }
1032 }
1033 let response = self.client.get(&url).send().await?;
1034 self.handle_response(response).await
1035 }
1036
1037 pub async fn memory_path(&self, source_id: &str, target_id: &str) -> Result<GraphPath> {
1050 let url = format!(
1051 "{}/v1/memories/{}/path?target={}",
1052 self.base_url,
1053 source_id,
1054 urlencoding::encode(target_id)
1055 );
1056 let response = self.client.get(&url).send().await?;
1057 self.handle_response(response).await
1058 }
1059
1060 pub async fn memory_link(
1073 &self,
1074 source_id: &str,
1075 target_id: &str,
1076 edge_type: EdgeType,
1077 ) -> Result<GraphLinkResponse> {
1078 let url = format!("{}/v1/memories/{}/links", self.base_url, source_id);
1079 let request = GraphLinkRequest {
1080 target_id: target_id.to_string(),
1081 edge_type,
1082 };
1083 let response = self.client.post(&url).json(&request).send().await?;
1084 self.handle_response(response).await
1085 }
1086
1087 pub async fn agent_graph_export(&self, agent_id: &str, format: &str) -> Result<GraphExport> {
1095 let url = format!(
1096 "{}/v1/agents/{}/graph/export?format={}",
1097 self.base_url, agent_id, format
1098 );
1099 let response = self.client.get(&url).send().await?;
1100 self.handle_response(response).await
1101 }
1102
1103 pub async fn start_session(&self, agent_id: &str) -> Result<Session> {
1109 let url = format!("{}/v1/sessions/start", self.base_url);
1110 let request = SessionStartRequest {
1111 agent_id: agent_id.to_string(),
1112 metadata: None,
1113 };
1114 let response = self.client.post(&url).json(&request).send().await?;
1115 let resp: SessionStartResponse = self.handle_response(response).await?;
1116 Ok(resp.session)
1117 }
1118
1119 pub async fn start_session_with_metadata(
1121 &self,
1122 agent_id: &str,
1123 metadata: serde_json::Value,
1124 ) -> Result<Session> {
1125 let url = format!("{}/v1/sessions/start", self.base_url);
1126 let request = SessionStartRequest {
1127 agent_id: agent_id.to_string(),
1128 metadata: Some(metadata),
1129 };
1130 let response = self.client.post(&url).json(&request).send().await?;
1131 let resp: SessionStartResponse = self.handle_response(response).await?;
1132 Ok(resp.session)
1133 }
1134
1135 pub async fn end_session(
1138 &self,
1139 session_id: &str,
1140 summary: Option<String>,
1141 ) -> Result<SessionEndResponse> {
1142 let url = format!("{}/v1/sessions/{}/end", self.base_url, session_id);
1143 let request = SessionEndRequest { summary };
1144 let response = self.client.post(&url).json(&request).send().await?;
1145 self.handle_response(response).await
1146 }
1147
1148 pub async fn get_session(&self, session_id: &str) -> Result<Session> {
1150 let url = format!("{}/v1/sessions/{}", self.base_url, session_id);
1151 let response = self.client.get(&url).send().await?;
1152 self.handle_response(response).await
1153 }
1154
1155 pub async fn list_sessions(&self, agent_id: &str) -> Result<Vec<Session>> {
1157 let url = format!("{}/v1/sessions?agent_id={}", self.base_url, agent_id);
1158 let response = self.client.get(&url).send().await?;
1159 self.handle_response(response).await
1160 }
1161
1162 pub async fn session_memories(&self, session_id: &str) -> Result<RecallResponse> {
1164 let url = format!("{}/v1/sessions/{}/memories", self.base_url, session_id);
1165 let response = self.client.get(&url).send().await?;
1166 self.handle_response(response).await
1167 }
1168
1169 pub async fn batch_recall(&self, request: BatchRecallRequest) -> Result<BatchRecallResponse> {
1193 let url = format!("{}/v1/memories/recall/batch", self.base_url);
1194 let response = self.client.post(&url).json(&request).send().await?;
1195 self.handle_response(response).await
1196 }
1197
1198 pub async fn batch_forget(&self, request: BatchForgetRequest) -> Result<BatchForgetResponse> {
1218 let url = format!("{}/v1/memories/forget/batch", self.base_url);
1219 let response = self.client.delete(&url).json(&request).send().await?;
1220 self.handle_response(response).await
1221 }
1222
1223 pub async fn import_memories(
1241 &self,
1242 data: serde_json::Value,
1243 format: &str,
1244 agent_id: Option<&str>,
1245 namespace: Option<&str>,
1246 ) -> Result<MemoryImportResponse> {
1247 let mut body = serde_json::json!({"data": data, "format": format});
1248 if let Some(aid) = agent_id {
1249 body["agent_id"] = serde_json::Value::String(aid.to_string());
1250 }
1251 if let Some(ns) = namespace {
1252 body["namespace"] = serde_json::Value::String(ns.to_string());
1253 }
1254 let url = format!("{}/v1/import", self.base_url);
1255 let response = self.client.post(&url).json(&body).send().await?;
1256 self.handle_response(response).await
1257 }
1258
1259 pub async fn export_memories(
1263 &self,
1264 format: &str,
1265 agent_id: Option<&str>,
1266 namespace: Option<&str>,
1267 limit: Option<u32>,
1268 ) -> Result<MemoryExportResponse> {
1269 let mut params = vec![("format", format.to_string())];
1270 if let Some(aid) = agent_id {
1271 params.push(("agent_id", aid.to_string()));
1272 }
1273 if let Some(ns) = namespace {
1274 params.push(("namespace", ns.to_string()));
1275 }
1276 if let Some(l) = limit {
1277 params.push(("limit", l.to_string()));
1278 }
1279 let url = format!("{}/v1/export", self.base_url);
1280 let response = self.client.get(&url).query(¶ms).send().await?;
1281 self.handle_response(response).await
1282 }
1283
1284 pub async fn list_audit_events(&self, query: AuditQuery) -> Result<AuditListResponse> {
1290 let url = format!("{}/v1/audit", self.base_url);
1291 let response = self.client.get(&url).query(&query).send().await?;
1292 self.handle_response(response).await
1293 }
1294
1295 pub async fn stream_audit_events(
1299 &self,
1300 agent_id: Option<&str>,
1301 event_type: Option<&str>,
1302 ) -> Result<tokio::sync::mpsc::Receiver<Result<crate::events::DakeraEvent>>> {
1303 let mut params: Vec<(&str, String)> = Vec::new();
1304 if let Some(aid) = agent_id {
1305 params.push(("agent_id", aid.to_string()));
1306 }
1307 if let Some(et) = event_type {
1308 params.push(("event_type", et.to_string()));
1309 }
1310 let base = format!("{}/v1/audit/stream", self.base_url);
1311 let url = if params.is_empty() {
1312 base
1313 } else {
1314 let qs = params
1315 .iter()
1316 .map(|(k, v)| format!("{}={}", k, urlencoding::encode(v)))
1317 .collect::<Vec<_>>()
1318 .join("&");
1319 format!("{}?{}", base, qs)
1320 };
1321 self.stream_sse(url).await
1322 }
1323
1324 pub async fn export_audit(
1326 &self,
1327 format: &str,
1328 agent_id: Option<&str>,
1329 event_type: Option<&str>,
1330 from_ts: Option<u64>,
1331 to_ts: Option<u64>,
1332 ) -> Result<AuditExportResponse> {
1333 let mut body = serde_json::json!({"format": format});
1334 if let Some(aid) = agent_id {
1335 body["agent_id"] = serde_json::Value::String(aid.to_string());
1336 }
1337 if let Some(et) = event_type {
1338 body["event_type"] = serde_json::Value::String(et.to_string());
1339 }
1340 if let Some(f) = from_ts {
1341 body["from"] = serde_json::Value::Number(f.into());
1342 }
1343 if let Some(t) = to_ts {
1344 body["to"] = serde_json::Value::Number(t.into());
1345 }
1346 let url = format!("{}/v1/audit/export", self.base_url);
1347 let response = self.client.post(&url).json(&body).send().await?;
1348 self.handle_response(response).await
1349 }
1350
1351 pub async fn extract_text(
1360 &self,
1361 text: &str,
1362 namespace: Option<&str>,
1363 provider: Option<&str>,
1364 model: Option<&str>,
1365 ) -> Result<ExtractionResult> {
1366 let mut body = serde_json::json!({"text": text});
1367 if let Some(ns) = namespace {
1368 body["namespace"] = serde_json::Value::String(ns.to_string());
1369 }
1370 if let Some(p) = provider {
1371 body["provider"] = serde_json::Value::String(p.to_string());
1372 }
1373 if let Some(m) = model {
1374 body["model"] = serde_json::Value::String(m.to_string());
1375 }
1376 let url = format!("{}/v1/extract", self.base_url);
1377 let response = self.client.post(&url).json(&body).send().await?;
1378 self.handle_response(response).await
1379 }
1380
1381 pub async fn list_extract_providers(&self) -> Result<Vec<ExtractionProviderInfo>> {
1383 let url = format!("{}/v1/extract/providers", self.base_url);
1384 let response = self.client.get(&url).send().await?;
1385 let result: ExtractProvidersResponse = self.handle_response(response).await?;
1386 Ok(match result {
1387 ExtractProvidersResponse::List(v) => v,
1388 ExtractProvidersResponse::Object { providers } => providers,
1389 })
1390 }
1391
1392 pub async fn configure_namespace_extractor(
1394 &self,
1395 namespace: &str,
1396 provider: &str,
1397 model: Option<&str>,
1398 ) -> Result<serde_json::Value> {
1399 let mut body = serde_json::json!({"provider": provider});
1400 if let Some(m) = model {
1401 body["model"] = serde_json::Value::String(m.to_string());
1402 }
1403 let url = format!(
1404 "{}/v1/namespaces/{}/extractor",
1405 self.base_url,
1406 urlencoding::encode(namespace)
1407 );
1408 let response = self.client.patch(&url).json(&body).send().await?;
1409 self.handle_response(response).await
1410 }
1411
1412 pub async fn rotate_encryption_key(
1428 &self,
1429 new_key: &str,
1430 namespace: Option<&str>,
1431 ) -> Result<RotateEncryptionKeyResponse> {
1432 let body = RotateEncryptionKeyRequest {
1433 new_key: new_key.to_string(),
1434 namespace: namespace.map(|s| s.to_string()),
1435 };
1436 let url = format!("{}/v1/admin/encryption/rotate-key", self.base_url);
1437 let response = self.client.post(&url).json(&body).send().await?;
1438 self.handle_response(response).await
1439 }
1440}