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}
145
146fn default_top_k() -> usize {
147 5
148}
149
150impl RecallRequest {
151 pub fn new(agent_id: impl Into<String>, query: impl Into<String>) -> Self {
153 Self {
154 agent_id: agent_id.into(),
155 query: query.into(),
156 top_k: 5,
157 memory_type: None,
158 min_importance: 0.0,
159 session_id: None,
160 tags: Vec::new(),
161 }
162 }
163
164 pub fn with_top_k(mut self, top_k: usize) -> Self {
166 self.top_k = top_k;
167 self
168 }
169
170 pub fn with_type(mut self, memory_type: MemoryType) -> Self {
172 self.memory_type = Some(memory_type);
173 self
174 }
175
176 pub fn with_min_importance(mut self, min: f32) -> Self {
178 self.min_importance = min;
179 self
180 }
181
182 pub fn with_session(mut self, session_id: impl Into<String>) -> Self {
184 self.session_id = Some(session_id.into());
185 self
186 }
187
188 pub fn with_tags(mut self, tags: Vec<String>) -> Self {
190 self.tags = tags;
191 self
192 }
193}
194
195#[derive(Debug, Clone, Serialize, Deserialize)]
197pub struct RecalledMemory {
198 pub id: String,
199 pub content: String,
200 pub memory_type: MemoryType,
201 pub importance: f32,
202 pub score: f32,
203 #[serde(default)]
204 pub tags: Vec<String>,
205 #[serde(skip_serializing_if = "Option::is_none")]
206 pub session_id: Option<String>,
207 #[serde(skip_serializing_if = "Option::is_none")]
208 pub metadata: Option<serde_json::Value>,
209 pub created_at: u64,
210 pub last_accessed_at: u64,
211 pub access_count: u32,
212}
213
214#[derive(Debug, Clone, Serialize, Deserialize)]
216pub struct RecallResponse {
217 pub memories: Vec<RecalledMemory>,
218 pub total_found: usize,
219}
220
221#[derive(Debug, Clone, Serialize, Deserialize)]
223pub struct ForgetRequest {
224 pub agent_id: String,
225 #[serde(default)]
226 pub memory_ids: Vec<String>,
227 #[serde(default)]
228 pub tags: Vec<String>,
229 #[serde(skip_serializing_if = "Option::is_none")]
230 pub session_id: Option<String>,
231 #[serde(skip_serializing_if = "Option::is_none")]
232 pub before_timestamp: Option<u64>,
233}
234
235impl ForgetRequest {
236 pub fn by_ids(agent_id: impl Into<String>, ids: Vec<String>) -> Self {
238 Self {
239 agent_id: agent_id.into(),
240 memory_ids: ids,
241 tags: Vec::new(),
242 session_id: None,
243 before_timestamp: None,
244 }
245 }
246
247 pub fn by_tags(agent_id: impl Into<String>, tags: Vec<String>) -> Self {
249 Self {
250 agent_id: agent_id.into(),
251 memory_ids: Vec::new(),
252 tags,
253 session_id: None,
254 before_timestamp: None,
255 }
256 }
257
258 pub fn by_session(agent_id: impl Into<String>, session_id: impl Into<String>) -> Self {
260 Self {
261 agent_id: agent_id.into(),
262 memory_ids: Vec::new(),
263 tags: Vec::new(),
264 session_id: Some(session_id.into()),
265 before_timestamp: None,
266 }
267 }
268}
269
270#[derive(Debug, Clone, Serialize, Deserialize)]
272pub struct ForgetResponse {
273 pub deleted_count: u64,
274}
275
276#[derive(Debug, Clone, Serialize, Deserialize)]
278pub struct SessionStartRequest {
279 pub agent_id: String,
280 #[serde(skip_serializing_if = "Option::is_none")]
281 pub metadata: Option<serde_json::Value>,
282}
283
284#[derive(Debug, Clone, Serialize, Deserialize)]
286pub struct Session {
287 pub id: String,
288 pub agent_id: String,
289 pub started_at: u64,
290 #[serde(skip_serializing_if = "Option::is_none")]
291 pub ended_at: Option<u64>,
292 #[serde(skip_serializing_if = "Option::is_none")]
293 pub summary: Option<String>,
294 #[serde(skip_serializing_if = "Option::is_none")]
295 pub metadata: Option<serde_json::Value>,
296}
297
298#[derive(Debug, Clone, Serialize, Deserialize)]
300pub struct SessionEndRequest {
301 #[serde(skip_serializing_if = "Option::is_none")]
302 pub summary: Option<String>,
303}
304
305#[derive(Debug, Clone, Serialize, Deserialize)]
307pub struct UpdateMemoryRequest {
308 #[serde(skip_serializing_if = "Option::is_none")]
309 pub content: Option<String>,
310 #[serde(skip_serializing_if = "Option::is_none")]
311 pub metadata: Option<serde_json::Value>,
312 #[serde(skip_serializing_if = "Option::is_none")]
313 pub memory_type: Option<MemoryType>,
314}
315
316#[derive(Debug, Clone, Serialize, Deserialize)]
318pub struct UpdateImportanceRequest {
319 pub memory_ids: Vec<String>,
320 pub importance: f32,
321}
322
323#[derive(Debug, Clone, Serialize, Deserialize, Default)]
325pub struct ConsolidationConfig {
326 #[serde(skip_serializing_if = "Option::is_none")]
328 pub algorithm: Option<String>,
329 #[serde(skip_serializing_if = "Option::is_none")]
331 pub min_samples: Option<u32>,
332 #[serde(skip_serializing_if = "Option::is_none")]
334 pub eps: Option<f32>,
335}
336
337#[derive(Debug, Clone, Serialize, Deserialize)]
339pub struct ConsolidationLogEntry {
340 pub step: String,
341 pub memories_before: usize,
342 pub memories_after: usize,
343 pub duration_ms: f64,
344}
345
346#[derive(Debug, Clone, Serialize, Deserialize, Default)]
348pub struct ConsolidateRequest {
349 #[serde(skip_serializing_if = "Option::is_none")]
350 pub memory_type: Option<String>,
351 #[serde(skip_serializing_if = "Option::is_none")]
352 pub threshold: Option<f32>,
353 #[serde(default)]
354 pub dry_run: bool,
355 #[serde(skip_serializing_if = "Option::is_none")]
357 pub config: Option<ConsolidationConfig>,
358}
359
360#[derive(Debug, Clone, Serialize, Deserialize)]
362pub struct ConsolidateResponse {
363 pub consolidated_count: usize,
364 pub removed_count: usize,
365 pub new_memories: Vec<String>,
366 #[serde(default, skip_serializing_if = "Vec::is_empty")]
368 pub log: Vec<ConsolidationLogEntry>,
369}
370
371#[derive(Debug, Clone, Serialize, Deserialize)]
377pub struct MemoryImportResponse {
378 pub imported_count: usize,
379 pub skipped_count: usize,
380 #[serde(default)]
381 pub errors: Vec<String>,
382}
383
384#[derive(Debug, Clone, Serialize, Deserialize)]
386pub struct MemoryExportResponse {
387 pub data: Vec<serde_json::Value>,
388 pub format: String,
389 pub count: usize,
390}
391
392#[derive(Debug, Clone, Serialize, Deserialize)]
398pub struct AuditEvent {
399 pub id: String,
400 pub event_type: String,
401 #[serde(skip_serializing_if = "Option::is_none")]
402 pub agent_id: Option<String>,
403 #[serde(skip_serializing_if = "Option::is_none")]
404 pub namespace: Option<String>,
405 pub timestamp: u64,
406 #[serde(default)]
407 pub details: serde_json::Value,
408}
409
410#[derive(Debug, Clone, Serialize, Deserialize)]
412pub struct AuditListResponse {
413 pub events: Vec<AuditEvent>,
414 pub total: usize,
415 #[serde(skip_serializing_if = "Option::is_none")]
416 pub cursor: Option<String>,
417}
418
419#[derive(Debug, Clone, Serialize, Deserialize)]
421pub struct AuditExportResponse {
422 pub data: String,
423 pub format: String,
424 pub count: usize,
425}
426
427#[derive(Debug, Clone, Serialize, Deserialize, Default)]
429pub struct AuditQuery {
430 #[serde(skip_serializing_if = "Option::is_none")]
431 pub agent_id: Option<String>,
432 #[serde(skip_serializing_if = "Option::is_none")]
433 pub event_type: Option<String>,
434 #[serde(skip_serializing_if = "Option::is_none")]
435 pub from: Option<u64>,
436 #[serde(skip_serializing_if = "Option::is_none")]
437 pub to: Option<u64>,
438 #[serde(skip_serializing_if = "Option::is_none")]
439 pub limit: Option<u32>,
440 #[serde(skip_serializing_if = "Option::is_none")]
441 pub cursor: Option<String>,
442}
443
444#[derive(Debug, Clone, Serialize, Deserialize)]
450pub struct ExtractionResult {
451 pub entities: Vec<serde_json::Value>,
452 pub provider: String,
453 #[serde(skip_serializing_if = "Option::is_none")]
454 pub model: Option<String>,
455 pub duration_ms: f64,
456}
457
458#[derive(Debug, Clone, Serialize, Deserialize)]
460pub struct ExtractionProviderInfo {
461 pub name: String,
462 pub available: bool,
463 #[serde(default)]
464 pub models: Vec<String>,
465}
466
467#[derive(Debug, Clone, Serialize, Deserialize)]
469#[serde(untagged)]
470pub enum ExtractProvidersResponse {
471 List(Vec<ExtractionProviderInfo>),
472 Object {
473 providers: Vec<ExtractionProviderInfo>,
474 },
475}
476
477#[derive(Debug, Clone, Serialize, Deserialize)]
483pub struct RotateEncryptionKeyRequest {
484 pub new_key: String,
486 #[serde(skip_serializing_if = "Option::is_none")]
488 pub namespace: Option<String>,
489}
490
491#[derive(Debug, Clone, Serialize, Deserialize)]
493pub struct RotateEncryptionKeyResponse {
494 pub rotated: usize,
495 pub skipped: usize,
496 #[serde(default)]
497 pub namespaces: Vec<String>,
498}
499
500#[derive(Debug, Clone, Serialize, Deserialize)]
502pub struct FeedbackRequest {
503 pub memory_id: String,
504 pub feedback: String,
505 #[serde(skip_serializing_if = "Option::is_none")]
506 pub relevance_score: Option<f32>,
507}
508
509#[derive(Debug, Clone, Serialize, Deserialize)]
511pub struct LegacyFeedbackResponse {
512 pub status: String,
513 pub updated_importance: Option<f32>,
514}
515
516#[derive(Debug, Clone, Serialize, Deserialize, Default)]
525pub struct BatchMemoryFilter {
526 #[serde(skip_serializing_if = "Option::is_none")]
528 pub tags: Option<Vec<String>>,
529 #[serde(skip_serializing_if = "Option::is_none")]
531 pub min_importance: Option<f32>,
532 #[serde(skip_serializing_if = "Option::is_none")]
534 pub max_importance: Option<f32>,
535 #[serde(skip_serializing_if = "Option::is_none")]
537 pub created_after: Option<u64>,
538 #[serde(skip_serializing_if = "Option::is_none")]
540 pub created_before: Option<u64>,
541 #[serde(skip_serializing_if = "Option::is_none")]
543 pub memory_type: Option<MemoryType>,
544 #[serde(skip_serializing_if = "Option::is_none")]
546 pub session_id: Option<String>,
547}
548
549impl BatchMemoryFilter {
550 pub fn with_tags(mut self, tags: Vec<String>) -> Self {
552 self.tags = Some(tags);
553 self
554 }
555
556 pub fn with_min_importance(mut self, min: f32) -> Self {
558 self.min_importance = Some(min);
559 self
560 }
561
562 pub fn with_max_importance(mut self, max: f32) -> Self {
564 self.max_importance = Some(max);
565 self
566 }
567
568 pub fn with_session(mut self, session_id: impl Into<String>) -> Self {
570 self.session_id = Some(session_id.into());
571 self
572 }
573}
574
575#[derive(Debug, Clone, Serialize, Deserialize)]
577pub struct BatchRecallRequest {
578 pub agent_id: String,
580 #[serde(default)]
582 pub filter: BatchMemoryFilter,
583 #[serde(default = "default_batch_limit")]
585 pub limit: usize,
586}
587
588fn default_batch_limit() -> usize {
589 100
590}
591
592impl BatchRecallRequest {
593 pub fn new(agent_id: impl Into<String>) -> Self {
595 Self {
596 agent_id: agent_id.into(),
597 filter: BatchMemoryFilter::default(),
598 limit: 100,
599 }
600 }
601
602 pub fn with_filter(mut self, filter: BatchMemoryFilter) -> Self {
604 self.filter = filter;
605 self
606 }
607
608 pub fn with_limit(mut self, limit: usize) -> Self {
610 self.limit = limit;
611 self
612 }
613}
614
615#[derive(Debug, Clone, Serialize, Deserialize)]
617pub struct BatchRecallResponse {
618 pub memories: Vec<RecalledMemory>,
619 pub total: usize,
621 pub filtered: usize,
623}
624
625#[derive(Debug, Clone, Serialize, Deserialize)]
627pub struct BatchForgetRequest {
628 pub agent_id: String,
630 pub filter: BatchMemoryFilter,
632}
633
634impl BatchForgetRequest {
635 pub fn new(agent_id: impl Into<String>, filter: BatchMemoryFilter) -> Self {
637 Self {
638 agent_id: agent_id.into(),
639 filter,
640 }
641 }
642}
643
644#[derive(Debug, Clone, Serialize, Deserialize)]
646pub struct BatchForgetResponse {
647 pub deleted_count: usize,
648}
649
650impl DakeraClient {
655 pub async fn store_memory(&self, request: StoreMemoryRequest) -> Result<StoreMemoryResponse> {
679 let url = format!("{}/v1/memory/store", self.base_url);
680 let response = self.client.post(&url).json(&request).send().await?;
681 self.handle_response(response).await
682 }
683
684 pub async fn recall(&self, request: RecallRequest) -> Result<RecallResponse> {
705 let url = format!("{}/v1/memory/recall", self.base_url);
706 let response = self.client.post(&url).json(&request).send().await?;
707 self.handle_response(response).await
708 }
709
710 pub async fn recall_simple(
712 &self,
713 agent_id: &str,
714 query: &str,
715 top_k: usize,
716 ) -> Result<RecallResponse> {
717 self.recall(RecallRequest::new(agent_id, query).with_top_k(top_k))
718 .await
719 }
720
721 pub async fn get_memory(&self, memory_id: &str) -> Result<RecalledMemory> {
723 let url = format!("{}/v1/memory/get/{}", self.base_url, memory_id);
724 let response = self.client.get(&url).send().await?;
725 self.handle_response(response).await
726 }
727
728 pub async fn forget(&self, request: ForgetRequest) -> Result<ForgetResponse> {
730 let url = format!("{}/v1/memory/forget", 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 search_memories(&self, request: RecallRequest) -> Result<RecallResponse> {
737 let url = format!("{}/v1/memory/search", self.base_url);
738 let response = self.client.post(&url).json(&request).send().await?;
739 self.handle_response(response).await
740 }
741
742 pub async fn update_memory(
744 &self,
745 agent_id: &str,
746 memory_id: &str,
747 request: UpdateMemoryRequest,
748 ) -> Result<StoreMemoryResponse> {
749 let url = format!(
750 "{}/v1/agents/{}/memories/{}",
751 self.base_url, agent_id, memory_id
752 );
753 let response = self.client.put(&url).json(&request).send().await?;
754 self.handle_response(response).await
755 }
756
757 pub async fn update_importance(
759 &self,
760 agent_id: &str,
761 request: UpdateImportanceRequest,
762 ) -> Result<serde_json::Value> {
763 let url = format!(
764 "{}/v1/agents/{}/memories/importance",
765 self.base_url, agent_id
766 );
767 let response = self.client.put(&url).json(&request).send().await?;
768 self.handle_response(response).await
769 }
770
771 pub async fn consolidate(
773 &self,
774 agent_id: &str,
775 request: ConsolidateRequest,
776 ) -> Result<ConsolidateResponse> {
777 let url = format!(
778 "{}/v1/agents/{}/memories/consolidate",
779 self.base_url, agent_id
780 );
781 let response = self.client.post(&url).json(&request).send().await?;
782 self.handle_response(response).await
783 }
784
785 pub async fn memory_feedback(
787 &self,
788 agent_id: &str,
789 request: FeedbackRequest,
790 ) -> Result<LegacyFeedbackResponse> {
791 let url = format!("{}/v1/agents/{}/memories/feedback", self.base_url, agent_id);
792 let response = self.client.post(&url).json(&request).send().await?;
793 self.handle_response(response).await
794 }
795
796 pub async fn feedback_memory(
816 &self,
817 memory_id: &str,
818 agent_id: &str,
819 signal: FeedbackSignal,
820 ) -> Result<FeedbackResponse> {
821 let url = format!("{}/v1/memories/{}/feedback", self.base_url, memory_id);
822 let body = MemoryFeedbackBody {
823 agent_id: agent_id.to_string(),
824 signal,
825 };
826 let response = self.client.post(&url).json(&body).send().await?;
827 self.handle_response(response).await
828 }
829
830 pub async fn get_memory_feedback_history(
832 &self,
833 memory_id: &str,
834 ) -> Result<FeedbackHistoryResponse> {
835 let url = format!("{}/v1/memories/{}/feedback", 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 get_agent_feedback_summary(&self, agent_id: &str) -> Result<AgentFeedbackSummary> {
842 let url = format!("{}/v1/agents/{}/feedback/summary", self.base_url, agent_id);
843 let response = self.client.get(&url).send().await?;
844 self.handle_response(response).await
845 }
846
847 pub async fn patch_memory_importance(
854 &self,
855 memory_id: &str,
856 agent_id: &str,
857 importance: f32,
858 ) -> Result<FeedbackResponse> {
859 let url = format!("{}/v1/memories/{}/importance", self.base_url, memory_id);
860 let body = MemoryImportancePatch {
861 agent_id: agent_id.to_string(),
862 importance,
863 };
864 let response = self.client.patch(&url).json(&body).send().await?;
865 self.handle_response(response).await
866 }
867
868 pub async fn get_feedback_health(&self, agent_id: &str) -> Result<FeedbackHealthResponse> {
873 let url = format!("{}/v1/feedback/health?agent_id={}", self.base_url, agent_id);
874 let response = self.client.get(&url).send().await?;
875 self.handle_response(response).await
876 }
877
878 pub async fn memory_graph(
899 &self,
900 memory_id: &str,
901 options: GraphOptions,
902 ) -> Result<MemoryGraph> {
903 let mut url = format!("{}/v1/memories/{}/graph", self.base_url, memory_id);
904 let depth = options.depth.unwrap_or(1);
905 url.push_str(&format!("?depth={}", depth));
906 if let Some(types) = &options.types {
907 let type_strs: Vec<String> = types
908 .iter()
909 .map(|t| {
910 serde_json::to_value(t)
911 .unwrap()
912 .as_str()
913 .unwrap_or("")
914 .to_string()
915 })
916 .collect();
917 if !type_strs.is_empty() {
918 url.push_str(&format!("&types={}", type_strs.join(",")));
919 }
920 }
921 let response = self.client.get(&url).send().await?;
922 self.handle_response(response).await
923 }
924
925 pub async fn memory_path(&self, source_id: &str, target_id: &str) -> Result<GraphPath> {
938 let url = format!(
939 "{}/v1/memories/{}/path?target={}",
940 self.base_url,
941 source_id,
942 urlencoding::encode(target_id)
943 );
944 let response = self.client.get(&url).send().await?;
945 self.handle_response(response).await
946 }
947
948 pub async fn memory_link(
961 &self,
962 source_id: &str,
963 target_id: &str,
964 edge_type: EdgeType,
965 ) -> Result<GraphLinkResponse> {
966 let url = format!("{}/v1/memories/{}/links", self.base_url, source_id);
967 let request = GraphLinkRequest {
968 target_id: target_id.to_string(),
969 edge_type,
970 };
971 let response = self.client.post(&url).json(&request).send().await?;
972 self.handle_response(response).await
973 }
974
975 pub async fn agent_graph_export(&self, agent_id: &str, format: &str) -> Result<GraphExport> {
983 let url = format!(
984 "{}/v1/agents/{}/graph/export?format={}",
985 self.base_url, agent_id, format
986 );
987 let response = self.client.get(&url).send().await?;
988 self.handle_response(response).await
989 }
990
991 pub async fn start_session(&self, agent_id: &str) -> Result<Session> {
997 let url = format!("{}/v1/sessions/start", self.base_url);
998 let request = SessionStartRequest {
999 agent_id: agent_id.to_string(),
1000 metadata: None,
1001 };
1002 let response = self.client.post(&url).json(&request).send().await?;
1003 self.handle_response(response).await
1004 }
1005
1006 pub async fn start_session_with_metadata(
1008 &self,
1009 agent_id: &str,
1010 metadata: serde_json::Value,
1011 ) -> Result<Session> {
1012 let url = format!("{}/v1/sessions/start", self.base_url);
1013 let request = SessionStartRequest {
1014 agent_id: agent_id.to_string(),
1015 metadata: Some(metadata),
1016 };
1017 let response = self.client.post(&url).json(&request).send().await?;
1018 self.handle_response(response).await
1019 }
1020
1021 pub async fn end_session(&self, session_id: &str, summary: Option<String>) -> Result<Session> {
1023 let url = format!("{}/v1/sessions/{}/end", self.base_url, session_id);
1024 let request = SessionEndRequest { summary };
1025 let response = self.client.post(&url).json(&request).send().await?;
1026 self.handle_response(response).await
1027 }
1028
1029 pub async fn get_session(&self, session_id: &str) -> Result<Session> {
1031 let url = format!("{}/v1/sessions/{}", self.base_url, session_id);
1032 let response = self.client.get(&url).send().await?;
1033 self.handle_response(response).await
1034 }
1035
1036 pub async fn list_sessions(&self, agent_id: &str) -> Result<Vec<Session>> {
1038 let url = format!("{}/v1/sessions?agent_id={}", self.base_url, agent_id);
1039 let response = self.client.get(&url).send().await?;
1040 self.handle_response(response).await
1041 }
1042
1043 pub async fn session_memories(&self, session_id: &str) -> Result<RecallResponse> {
1045 let url = format!("{}/v1/sessions/{}/memories", self.base_url, session_id);
1046 let response = self.client.get(&url).send().await?;
1047 self.handle_response(response).await
1048 }
1049
1050 pub async fn batch_recall(&self, request: BatchRecallRequest) -> Result<BatchRecallResponse> {
1074 let url = format!("{}/v1/memories/recall/batch", self.base_url);
1075 let response = self.client.post(&url).json(&request).send().await?;
1076 self.handle_response(response).await
1077 }
1078
1079 pub async fn batch_forget(&self, request: BatchForgetRequest) -> Result<BatchForgetResponse> {
1099 let url = format!("{}/v1/memories/forget/batch", self.base_url);
1100 let response = self.client.delete(&url).json(&request).send().await?;
1101 self.handle_response(response).await
1102 }
1103
1104 pub async fn import_memories(
1122 &self,
1123 data: serde_json::Value,
1124 format: &str,
1125 agent_id: Option<&str>,
1126 namespace: Option<&str>,
1127 ) -> Result<MemoryImportResponse> {
1128 let mut body = serde_json::json!({"data": data, "format": format});
1129 if let Some(aid) = agent_id {
1130 body["agent_id"] = serde_json::Value::String(aid.to_string());
1131 }
1132 if let Some(ns) = namespace {
1133 body["namespace"] = serde_json::Value::String(ns.to_string());
1134 }
1135 let url = format!("{}/v1/import", self.base_url);
1136 let response = self.client.post(&url).json(&body).send().await?;
1137 self.handle_response(response).await
1138 }
1139
1140 pub async fn export_memories(
1144 &self,
1145 format: &str,
1146 agent_id: Option<&str>,
1147 namespace: Option<&str>,
1148 limit: Option<u32>,
1149 ) -> Result<MemoryExportResponse> {
1150 let mut params = vec![("format", format.to_string())];
1151 if let Some(aid) = agent_id {
1152 params.push(("agent_id", aid.to_string()));
1153 }
1154 if let Some(ns) = namespace {
1155 params.push(("namespace", ns.to_string()));
1156 }
1157 if let Some(l) = limit {
1158 params.push(("limit", l.to_string()));
1159 }
1160 let url = format!("{}/v1/export", self.base_url);
1161 let response = self.client.get(&url).query(¶ms).send().await?;
1162 self.handle_response(response).await
1163 }
1164
1165 pub async fn list_audit_events(&self, query: AuditQuery) -> Result<AuditListResponse> {
1171 let url = format!("{}/v1/audit", self.base_url);
1172 let response = self.client.get(&url).query(&query).send().await?;
1173 self.handle_response(response).await
1174 }
1175
1176 pub async fn stream_audit_events(
1180 &self,
1181 agent_id: Option<&str>,
1182 event_type: Option<&str>,
1183 ) -> Result<tokio::sync::mpsc::Receiver<Result<crate::events::DakeraEvent>>> {
1184 let mut params: Vec<(&str, String)> = Vec::new();
1185 if let Some(aid) = agent_id {
1186 params.push(("agent_id", aid.to_string()));
1187 }
1188 if let Some(et) = event_type {
1189 params.push(("event_type", et.to_string()));
1190 }
1191 let base = format!("{}/v1/audit/stream", self.base_url);
1192 let url = if params.is_empty() {
1193 base
1194 } else {
1195 let qs = params
1196 .iter()
1197 .map(|(k, v)| format!("{}={}", k, urlencoding::encode(v)))
1198 .collect::<Vec<_>>()
1199 .join("&");
1200 format!("{}?{}", base, qs)
1201 };
1202 self.stream_sse(url).await
1203 }
1204
1205 pub async fn export_audit(
1207 &self,
1208 format: &str,
1209 agent_id: Option<&str>,
1210 event_type: Option<&str>,
1211 from_ts: Option<u64>,
1212 to_ts: Option<u64>,
1213 ) -> Result<AuditExportResponse> {
1214 let mut body = serde_json::json!({"format": format});
1215 if let Some(aid) = agent_id {
1216 body["agent_id"] = serde_json::Value::String(aid.to_string());
1217 }
1218 if let Some(et) = event_type {
1219 body["event_type"] = serde_json::Value::String(et.to_string());
1220 }
1221 if let Some(f) = from_ts {
1222 body["from"] = serde_json::Value::Number(f.into());
1223 }
1224 if let Some(t) = to_ts {
1225 body["to"] = serde_json::Value::Number(t.into());
1226 }
1227 let url = format!("{}/v1/audit/export", self.base_url);
1228 let response = self.client.post(&url).json(&body).send().await?;
1229 self.handle_response(response).await
1230 }
1231
1232 pub async fn extract_text(
1241 &self,
1242 text: &str,
1243 namespace: Option<&str>,
1244 provider: Option<&str>,
1245 model: Option<&str>,
1246 ) -> Result<ExtractionResult> {
1247 let mut body = serde_json::json!({"text": text});
1248 if let Some(ns) = namespace {
1249 body["namespace"] = serde_json::Value::String(ns.to_string());
1250 }
1251 if let Some(p) = provider {
1252 body["provider"] = serde_json::Value::String(p.to_string());
1253 }
1254 if let Some(m) = model {
1255 body["model"] = serde_json::Value::String(m.to_string());
1256 }
1257 let url = format!("{}/v1/extract", self.base_url);
1258 let response = self.client.post(&url).json(&body).send().await?;
1259 self.handle_response(response).await
1260 }
1261
1262 pub async fn list_extract_providers(&self) -> Result<Vec<ExtractionProviderInfo>> {
1264 let url = format!("{}/v1/extract/providers", self.base_url);
1265 let response = self.client.get(&url).send().await?;
1266 let result: ExtractProvidersResponse = self.handle_response(response).await?;
1267 Ok(match result {
1268 ExtractProvidersResponse::List(v) => v,
1269 ExtractProvidersResponse::Object { providers } => providers,
1270 })
1271 }
1272
1273 pub async fn configure_namespace_extractor(
1275 &self,
1276 namespace: &str,
1277 provider: &str,
1278 model: Option<&str>,
1279 ) -> Result<serde_json::Value> {
1280 let mut body = serde_json::json!({"provider": provider});
1281 if let Some(m) = model {
1282 body["model"] = serde_json::Value::String(m.to_string());
1283 }
1284 let url = format!(
1285 "{}/v1/namespaces/{}/extractor",
1286 self.base_url,
1287 urlencoding::encode(namespace)
1288 );
1289 let response = self.client.patch(&url).json(&body).send().await?;
1290 self.handle_response(response).await
1291 }
1292
1293 pub async fn rotate_encryption_key(
1309 &self,
1310 new_key: &str,
1311 namespace: Option<&str>,
1312 ) -> Result<RotateEncryptionKeyResponse> {
1313 let body = RotateEncryptionKeyRequest {
1314 new_key: new_key.to_string(),
1315 namespace: namespace.map(|s| s.to_string()),
1316 };
1317 let url = format!("{}/v1/admin/encryption/rotate-key", self.base_url);
1318 let response = self.client.post(&url).json(&body).send().await?;
1319 self.handle_response(response).await
1320 }
1321}