1use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6#[derive(Debug, Clone)]
12pub struct RetryConfig {
13 pub max_retries: u32,
15 pub base_delay: std::time::Duration,
17 pub max_delay: std::time::Duration,
19 pub jitter: bool,
21}
22
23impl Default for RetryConfig {
24 fn default() -> Self {
25 Self {
26 max_retries: 3,
27 base_delay: std::time::Duration::from_millis(100),
28 max_delay: std::time::Duration::from_secs(60),
29 jitter: true,
30 }
31 }
32}
33
34#[derive(Debug, Clone, Default)]
43pub struct RateLimitHeaders {
44 pub limit: Option<u64>,
46 pub remaining: Option<u64>,
48 pub reset: Option<u64>,
50 pub quota_used: Option<u64>,
52 pub quota_limit: Option<u64>,
54}
55
56impl RateLimitHeaders {
57 pub fn from_response(response: &reqwest::Response) -> Self {
59 let headers = response.headers();
60 fn parse(h: &reqwest::header::HeaderMap, name: &str) -> Option<u64> {
61 h.get(name)
62 .and_then(|v| v.to_str().ok())
63 .and_then(|s| s.parse().ok())
64 }
65 Self {
66 limit: parse(headers, "X-RateLimit-Limit"),
67 remaining: parse(headers, "X-RateLimit-Remaining"),
68 reset: parse(headers, "X-RateLimit-Reset"),
69 quota_used: parse(headers, "X-Quota-Used"),
70 quota_limit: parse(headers, "X-Quota-Limit"),
71 }
72 }
73}
74
75#[derive(Debug, Clone, Serialize, Deserialize)]
81pub struct HealthResponse {
82 pub healthy: bool,
84 pub version: Option<String>,
86 pub uptime_seconds: Option<u64>,
88}
89
90#[derive(Debug, Clone, Serialize, Deserialize)]
92pub struct ReadinessResponse {
93 pub ready: bool,
95 pub components: Option<HashMap<String, bool>>,
97}
98
99#[derive(Debug, Clone, Serialize, Deserialize)]
105pub struct NamespaceInfo {
106 #[serde(alias = "namespace")]
108 pub name: String,
109 #[serde(default)]
111 pub vector_count: u64,
112 #[serde(alias = "dimension")]
114 pub dimensions: Option<u32>,
115 pub index_type: Option<String>,
117 #[serde(default)]
119 pub created: Option<bool>,
120}
121
122#[derive(Debug, Clone, Serialize, Deserialize)]
124pub struct ListNamespacesResponse {
125 pub namespaces: Vec<String>,
127}
128
129#[derive(Debug, Clone, Serialize, Deserialize)]
135pub struct Vector {
136 pub id: String,
138 pub values: Vec<f32>,
140 #[serde(skip_serializing_if = "Option::is_none")]
142 pub metadata: Option<HashMap<String, serde_json::Value>>,
143}
144
145impl Vector {
146 pub fn new(id: impl Into<String>, values: Vec<f32>) -> Self {
148 Self {
149 id: id.into(),
150 values,
151 metadata: None,
152 }
153 }
154
155 pub fn with_metadata(
157 id: impl Into<String>,
158 values: Vec<f32>,
159 metadata: HashMap<String, serde_json::Value>,
160 ) -> Self {
161 Self {
162 id: id.into(),
163 values,
164 metadata: Some(metadata),
165 }
166 }
167}
168
169#[derive(Debug, Clone, Serialize, Deserialize)]
171pub struct UpsertRequest {
172 pub vectors: Vec<Vector>,
174}
175
176impl UpsertRequest {
177 pub fn single(vector: Vector) -> Self {
179 Self {
180 vectors: vec![vector],
181 }
182 }
183
184 pub fn batch(vectors: Vec<Vector>) -> Self {
186 Self { vectors }
187 }
188}
189
190#[derive(Debug, Clone, Serialize, Deserialize)]
192pub struct UpsertResponse {
193 pub upserted_count: u64,
195}
196
197#[derive(Debug, Clone, Serialize, Deserialize)]
214pub struct ColumnUpsertRequest {
215 pub ids: Vec<String>,
217 pub vectors: Vec<Vec<f32>>,
219 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
222 pub attributes: HashMap<String, Vec<serde_json::Value>>,
223 #[serde(skip_serializing_if = "Option::is_none")]
225 pub ttl_seconds: Option<u64>,
226 #[serde(skip_serializing_if = "Option::is_none")]
228 pub dimension: Option<usize>,
229}
230
231impl ColumnUpsertRequest {
232 pub fn new(ids: Vec<String>, vectors: Vec<Vec<f32>>) -> Self {
234 Self {
235 ids,
236 vectors,
237 attributes: HashMap::new(),
238 ttl_seconds: None,
239 dimension: None,
240 }
241 }
242
243 pub fn with_attribute(
245 mut self,
246 name: impl Into<String>,
247 values: Vec<serde_json::Value>,
248 ) -> Self {
249 self.attributes.insert(name.into(), values);
250 self
251 }
252
253 pub fn with_ttl(mut self, seconds: u64) -> Self {
255 self.ttl_seconds = Some(seconds);
256 self
257 }
258
259 pub fn with_dimension(mut self, dim: usize) -> Self {
261 self.dimension = Some(dim);
262 self
263 }
264
265 pub fn len(&self) -> usize {
267 self.ids.len()
268 }
269
270 pub fn is_empty(&self) -> bool {
272 self.ids.is_empty()
273 }
274}
275
276#[derive(Debug, Clone, Serialize, Deserialize)]
278pub struct DeleteRequest {
279 pub ids: Vec<String>,
281}
282
283impl DeleteRequest {
284 pub fn single(id: impl Into<String>) -> Self {
286 Self {
287 ids: vec![id.into()],
288 }
289 }
290
291 pub fn batch(ids: Vec<String>) -> Self {
293 Self { ids }
294 }
295}
296
297#[derive(Debug, Clone, Serialize, Deserialize)]
299pub struct DeleteResponse {
300 pub deleted_count: u64,
302}
303
304#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
310#[serde(rename_all = "snake_case")]
311pub enum ReadConsistency {
312 Strong,
314 #[default]
316 Eventual,
317 #[serde(rename = "bounded_staleness")]
319 BoundedStaleness,
320}
321
322#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
324pub struct StalenessConfig {
325 #[serde(default = "default_max_staleness_ms")]
327 pub max_staleness_ms: u64,
328}
329
330fn default_max_staleness_ms() -> u64 {
331 5000 }
333
334impl StalenessConfig {
335 pub fn new(max_staleness_ms: u64) -> Self {
337 Self { max_staleness_ms }
338 }
339}
340
341#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
343#[serde(rename_all = "snake_case")]
344pub enum DistanceMetric {
345 #[default]
347 Cosine,
348 Euclidean,
350 DotProduct,
352}
353
354#[derive(Debug, Clone, Serialize, Deserialize)]
356pub struct QueryRequest {
357 pub vector: Vec<f32>,
359 pub top_k: u32,
361 #[serde(default)]
363 pub distance_metric: DistanceMetric,
364 #[serde(skip_serializing_if = "Option::is_none")]
366 pub filter: Option<serde_json::Value>,
367 #[serde(default = "default_true")]
369 pub include_metadata: bool,
370 #[serde(default)]
372 pub include_vectors: bool,
373 #[serde(default)]
375 pub consistency: ReadConsistency,
376 #[serde(skip_serializing_if = "Option::is_none")]
378 pub staleness_config: Option<StalenessConfig>,
379}
380
381fn default_true() -> bool {
382 true
383}
384
385impl QueryRequest {
386 pub fn new(vector: Vec<f32>, top_k: u32) -> Self {
388 Self {
389 vector,
390 top_k,
391 distance_metric: DistanceMetric::default(),
392 filter: None,
393 include_metadata: true,
394 include_vectors: false,
395 consistency: ReadConsistency::default(),
396 staleness_config: None,
397 }
398 }
399
400 pub fn with_filter(mut self, filter: serde_json::Value) -> Self {
402 self.filter = Some(filter);
403 self
404 }
405
406 pub fn include_metadata(mut self, include: bool) -> Self {
408 self.include_metadata = include;
409 self
410 }
411
412 pub fn include_vectors(mut self, include: bool) -> Self {
414 self.include_vectors = include;
415 self
416 }
417
418 pub fn with_distance_metric(mut self, metric: DistanceMetric) -> Self {
420 self.distance_metric = metric;
421 self
422 }
423
424 pub fn with_consistency(mut self, consistency: ReadConsistency) -> Self {
426 self.consistency = consistency;
427 self
428 }
429
430 pub fn with_bounded_staleness(mut self, max_staleness_ms: u64) -> Self {
432 self.consistency = ReadConsistency::BoundedStaleness;
433 self.staleness_config = Some(StalenessConfig::new(max_staleness_ms));
434 self
435 }
436
437 pub fn with_strong_consistency(mut self) -> Self {
439 self.consistency = ReadConsistency::Strong;
440 self
441 }
442}
443
444#[derive(Debug, Clone, Serialize, Deserialize)]
446pub struct Match {
447 pub id: String,
449 pub score: f32,
451 #[serde(skip_serializing_if = "Option::is_none")]
453 pub metadata: Option<HashMap<String, serde_json::Value>>,
454}
455
456#[derive(Debug, Clone, Serialize, Deserialize)]
458pub struct QueryResponse {
459 #[serde(alias = "matches")]
461 pub results: Vec<Match>,
462}
463
464#[derive(Debug, Clone, Serialize, Deserialize)]
470pub struct Document {
471 pub id: String,
473 pub text: String,
475 #[serde(skip_serializing_if = "Option::is_none")]
477 pub metadata: Option<HashMap<String, serde_json::Value>>,
478}
479
480impl Document {
481 pub fn new(id: impl Into<String>, text: impl Into<String>) -> Self {
483 Self {
484 id: id.into(),
485 text: text.into(),
486 metadata: None,
487 }
488 }
489
490 pub fn with_metadata(
492 id: impl Into<String>,
493 text: impl Into<String>,
494 metadata: HashMap<String, serde_json::Value>,
495 ) -> Self {
496 Self {
497 id: id.into(),
498 text: text.into(),
499 metadata: Some(metadata),
500 }
501 }
502}
503
504#[derive(Debug, Clone, Serialize, Deserialize)]
506pub struct IndexDocumentsRequest {
507 pub documents: Vec<Document>,
509}
510
511#[derive(Debug, Clone, Serialize, Deserialize)]
513pub struct IndexDocumentsResponse {
514 pub indexed_count: u64,
516}
517
518#[derive(Debug, Clone, Serialize, Deserialize)]
520pub struct FullTextSearchRequest {
521 pub query: String,
523 pub top_k: u32,
525 #[serde(skip_serializing_if = "Option::is_none")]
527 pub filter: Option<serde_json::Value>,
528}
529
530impl FullTextSearchRequest {
531 pub fn new(query: impl Into<String>, top_k: u32) -> Self {
533 Self {
534 query: query.into(),
535 top_k,
536 filter: None,
537 }
538 }
539
540 pub fn with_filter(mut self, filter: serde_json::Value) -> Self {
542 self.filter = Some(filter);
543 self
544 }
545}
546
547#[derive(Debug, Clone, Serialize, Deserialize)]
549pub struct FullTextMatch {
550 pub id: String,
552 pub score: f32,
554 #[serde(skip_serializing_if = "Option::is_none")]
556 pub text: Option<String>,
557 #[serde(skip_serializing_if = "Option::is_none")]
559 pub metadata: Option<HashMap<String, serde_json::Value>>,
560}
561
562#[derive(Debug, Clone, Serialize, Deserialize)]
564pub struct FullTextSearchResponse {
565 #[serde(alias = "matches")]
567 pub results: Vec<FullTextMatch>,
568}
569
570#[derive(Debug, Clone, Serialize, Deserialize)]
572pub struct FullTextStats {
573 pub document_count: u64,
575 pub term_count: u64,
577}
578
579#[derive(Debug, Clone, Serialize, Deserialize)]
588pub struct HybridSearchRequest {
589 #[serde(skip_serializing_if = "Option::is_none")]
591 pub vector: Option<Vec<f32>>,
592 pub text: String,
594 pub top_k: u32,
596 #[serde(default = "default_vector_weight")]
598 pub vector_weight: f32,
599 #[serde(skip_serializing_if = "Option::is_none")]
601 pub filter: Option<serde_json::Value>,
602}
603
604fn default_vector_weight() -> f32 {
605 0.5
606}
607
608impl HybridSearchRequest {
609 pub fn new(vector: Vec<f32>, text: impl Into<String>, top_k: u32) -> Self {
611 Self {
612 vector: Some(vector),
613 text: text.into(),
614 top_k,
615 vector_weight: 0.5,
616 filter: None,
617 }
618 }
619
620 pub fn text_only(text: impl Into<String>, top_k: u32) -> Self {
622 Self {
623 vector: None,
624 text: text.into(),
625 top_k,
626 vector_weight: 0.5,
627 filter: None,
628 }
629 }
630
631 pub fn with_vector_weight(mut self, weight: f32) -> Self {
633 self.vector_weight = weight.clamp(0.0, 1.0);
634 self
635 }
636
637 pub fn with_filter(mut self, filter: serde_json::Value) -> Self {
639 self.filter = Some(filter);
640 self
641 }
642}
643
644#[derive(Debug, Clone, Serialize, Deserialize)]
646pub struct HybridSearchResponse {
647 #[serde(alias = "matches")]
649 pub results: Vec<Match>,
650}
651
652#[derive(Debug, Clone, Serialize, Deserialize)]
658pub struct SystemDiagnostics {
659 pub system: SystemInfo,
661 pub resources: ResourceUsage,
663 pub components: ComponentHealth,
665 pub active_jobs: u64,
667}
668
669#[derive(Debug, Clone, Serialize, Deserialize)]
671pub struct SystemInfo {
672 pub version: String,
674 pub rust_version: String,
676 pub uptime_seconds: u64,
678 pub pid: u32,
680}
681
682#[derive(Debug, Clone, Serialize, Deserialize)]
684pub struct ResourceUsage {
685 pub memory_bytes: u64,
687 pub thread_count: u64,
689 pub open_fds: u64,
691 pub cpu_percent: Option<f64>,
693}
694
695#[derive(Debug, Clone, Serialize, Deserialize)]
697pub struct ComponentHealth {
698 pub storage: HealthStatus,
700 pub search_engine: HealthStatus,
702 pub cache: HealthStatus,
704 pub grpc: HealthStatus,
706}
707
708#[derive(Debug, Clone, Serialize, Deserialize)]
710pub struct HealthStatus {
711 pub healthy: bool,
713 pub message: String,
715 pub last_check: u64,
717}
718
719#[derive(Debug, Clone, Serialize, Deserialize)]
721pub struct JobInfo {
722 pub id: String,
724 pub job_type: String,
726 pub status: String,
728 pub created_at: u64,
730 pub started_at: Option<u64>,
732 pub completed_at: Option<u64>,
734 pub progress: u8,
736 pub message: Option<String>,
738}
739
740#[derive(Debug, Clone, Serialize, Deserialize)]
742pub struct CompactionRequest {
743 #[serde(skip_serializing_if = "Option::is_none")]
745 pub namespace: Option<String>,
746 #[serde(default)]
748 pub force: bool,
749}
750
751#[derive(Debug, Clone, Serialize, Deserialize)]
753pub struct CompactionResponse {
754 pub job_id: String,
756 pub message: String,
758}
759
760#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
766#[serde(rename_all = "snake_case")]
767pub enum WarmingPriority {
768 Critical,
770 High,
772 #[default]
774 Normal,
775 Low,
777 Background,
779}
780
781#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
783#[serde(rename_all = "snake_case")]
784pub enum WarmingTargetTier {
785 L1,
787 #[default]
789 L2,
790 Both,
792}
793
794#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
796#[serde(rename_all = "snake_case")]
797pub enum AccessPatternHint {
798 #[default]
800 Random,
801 Sequential,
803 Temporal,
805 Spatial,
807}
808
809#[derive(Debug, Clone, Serialize, Deserialize)]
811pub struct WarmCacheRequest {
812 pub namespace: String,
814 #[serde(skip_serializing_if = "Option::is_none")]
816 pub vector_ids: Option<Vec<String>>,
817 #[serde(default)]
819 pub priority: WarmingPriority,
820 #[serde(default)]
822 pub target_tier: WarmingTargetTier,
823 #[serde(default)]
825 pub background: bool,
826 #[serde(skip_serializing_if = "Option::is_none")]
828 pub ttl_hint_seconds: Option<u64>,
829 #[serde(default)]
831 pub access_pattern: AccessPatternHint,
832 #[serde(skip_serializing_if = "Option::is_none")]
834 pub max_vectors: Option<usize>,
835}
836
837impl WarmCacheRequest {
838 pub fn new(namespace: impl Into<String>) -> Self {
840 Self {
841 namespace: namespace.into(),
842 vector_ids: None,
843 priority: WarmingPriority::default(),
844 target_tier: WarmingTargetTier::default(),
845 background: false,
846 ttl_hint_seconds: None,
847 access_pattern: AccessPatternHint::default(),
848 max_vectors: None,
849 }
850 }
851
852 pub fn with_vector_ids(mut self, ids: Vec<String>) -> Self {
854 self.vector_ids = Some(ids);
855 self
856 }
857
858 pub fn with_priority(mut self, priority: WarmingPriority) -> Self {
860 self.priority = priority;
861 self
862 }
863
864 pub fn with_target_tier(mut self, tier: WarmingTargetTier) -> Self {
866 self.target_tier = tier;
867 self
868 }
869
870 pub fn in_background(mut self) -> Self {
872 self.background = true;
873 self
874 }
875
876 pub fn with_ttl(mut self, seconds: u64) -> Self {
878 self.ttl_hint_seconds = Some(seconds);
879 self
880 }
881
882 pub fn with_access_pattern(mut self, pattern: AccessPatternHint) -> Self {
884 self.access_pattern = pattern;
885 self
886 }
887
888 pub fn with_max_vectors(mut self, max: usize) -> Self {
890 self.max_vectors = Some(max);
891 self
892 }
893}
894
895#[derive(Debug, Clone, Serialize, Deserialize)]
897pub struct WarmCacheResponse {
898 pub success: bool,
900 pub entries_warmed: u64,
902 pub entries_skipped: u64,
904 #[serde(skip_serializing_if = "Option::is_none")]
906 pub job_id: Option<String>,
907 pub message: String,
909 #[serde(skip_serializing_if = "Option::is_none")]
911 pub estimated_completion: Option<String>,
912 pub target_tier: WarmingTargetTier,
914 pub priority: WarmingPriority,
916 #[serde(skip_serializing_if = "Option::is_none")]
918 pub bytes_warmed: Option<u64>,
919}
920
921#[derive(Debug, Clone, Serialize, Deserialize)]
927pub struct ExportRequest {
928 #[serde(default = "default_export_top_k")]
930 pub top_k: usize,
931 #[serde(skip_serializing_if = "Option::is_none")]
933 pub cursor: Option<String>,
934 #[serde(default = "default_true")]
936 pub include_vectors: bool,
937 #[serde(default = "default_true")]
939 pub include_metadata: bool,
940}
941
942fn default_export_top_k() -> usize {
943 1000
944}
945
946impl Default for ExportRequest {
947 fn default() -> Self {
948 Self {
949 top_k: 1000,
950 cursor: None,
951 include_vectors: true,
952 include_metadata: true,
953 }
954 }
955}
956
957impl ExportRequest {
958 pub fn new() -> Self {
960 Self::default()
961 }
962
963 pub fn with_top_k(mut self, top_k: usize) -> Self {
965 self.top_k = top_k;
966 self
967 }
968
969 pub fn with_cursor(mut self, cursor: impl Into<String>) -> Self {
971 self.cursor = Some(cursor.into());
972 self
973 }
974
975 pub fn include_vectors(mut self, include: bool) -> Self {
977 self.include_vectors = include;
978 self
979 }
980
981 pub fn include_metadata(mut self, include: bool) -> Self {
983 self.include_metadata = include;
984 self
985 }
986}
987
988#[derive(Debug, Clone, Serialize, Deserialize)]
990pub struct ExportedVector {
991 pub id: String,
993 #[serde(skip_serializing_if = "Option::is_none")]
995 pub values: Option<Vec<f32>>,
996 #[serde(skip_serializing_if = "Option::is_none")]
998 pub metadata: Option<serde_json::Value>,
999 #[serde(skip_serializing_if = "Option::is_none")]
1001 pub ttl_seconds: Option<u64>,
1002}
1003
1004#[derive(Debug, Clone, Serialize, Deserialize)]
1006pub struct ExportResponse {
1007 pub vectors: Vec<ExportedVector>,
1009 #[serde(skip_serializing_if = "Option::is_none")]
1011 pub next_cursor: Option<String>,
1012 pub total_count: usize,
1014 pub returned_count: usize,
1016}
1017
1018#[derive(Debug, Clone, Serialize, Deserialize)]
1024pub struct BatchQueryItem {
1025 #[serde(skip_serializing_if = "Option::is_none")]
1027 pub id: Option<String>,
1028 pub vector: Vec<f32>,
1030 #[serde(default = "default_batch_top_k")]
1032 pub top_k: u32,
1033 #[serde(skip_serializing_if = "Option::is_none")]
1035 pub filter: Option<serde_json::Value>,
1036 #[serde(default)]
1038 pub include_metadata: bool,
1039 #[serde(default)]
1041 pub consistency: ReadConsistency,
1042 #[serde(skip_serializing_if = "Option::is_none")]
1044 pub staleness_config: Option<StalenessConfig>,
1045}
1046
1047fn default_batch_top_k() -> u32 {
1048 10
1049}
1050
1051impl BatchQueryItem {
1052 pub fn new(vector: Vec<f32>, top_k: u32) -> Self {
1054 Self {
1055 id: None,
1056 vector,
1057 top_k,
1058 filter: None,
1059 include_metadata: true,
1060 consistency: ReadConsistency::default(),
1061 staleness_config: None,
1062 }
1063 }
1064
1065 pub fn with_id(mut self, id: impl Into<String>) -> Self {
1067 self.id = Some(id.into());
1068 self
1069 }
1070
1071 pub fn with_filter(mut self, filter: serde_json::Value) -> Self {
1073 self.filter = Some(filter);
1074 self
1075 }
1076
1077 pub fn include_metadata(mut self, include: bool) -> Self {
1079 self.include_metadata = include;
1080 self
1081 }
1082
1083 pub fn with_consistency(mut self, consistency: ReadConsistency) -> Self {
1085 self.consistency = consistency;
1086 self
1087 }
1088
1089 pub fn with_bounded_staleness(mut self, max_staleness_ms: u64) -> Self {
1091 self.consistency = ReadConsistency::BoundedStaleness;
1092 self.staleness_config = Some(StalenessConfig::new(max_staleness_ms));
1093 self
1094 }
1095}
1096
1097#[derive(Debug, Clone, Serialize, Deserialize)]
1099pub struct BatchQueryRequest {
1100 pub queries: Vec<BatchQueryItem>,
1102}
1103
1104impl BatchQueryRequest {
1105 pub fn new(queries: Vec<BatchQueryItem>) -> Self {
1107 Self { queries }
1108 }
1109
1110 pub fn single(query: BatchQueryItem) -> Self {
1112 Self {
1113 queries: vec![query],
1114 }
1115 }
1116}
1117
1118#[derive(Debug, Clone, Serialize, Deserialize)]
1120pub struct BatchQueryResult {
1121 #[serde(skip_serializing_if = "Option::is_none")]
1123 pub id: Option<String>,
1124 pub results: Vec<Match>,
1126 pub latency_ms: f64,
1128 #[serde(skip_serializing_if = "Option::is_none")]
1130 pub error: Option<String>,
1131}
1132
1133#[derive(Debug, Clone, Serialize, Deserialize)]
1135pub struct BatchQueryResponse {
1136 pub results: Vec<BatchQueryResult>,
1138 pub total_latency_ms: f64,
1140 pub query_count: usize,
1142}
1143
1144#[derive(Debug, Clone, Serialize, Deserialize)]
1150pub struct MultiVectorSearchRequest {
1151 pub positive_vectors: Vec<Vec<f32>>,
1153 #[serde(skip_serializing_if = "Option::is_none")]
1155 pub positive_weights: Option<Vec<f32>>,
1156 #[serde(skip_serializing_if = "Option::is_none")]
1158 pub negative_vectors: Option<Vec<Vec<f32>>>,
1159 #[serde(skip_serializing_if = "Option::is_none")]
1161 pub negative_weights: Option<Vec<f32>>,
1162 #[serde(default = "default_multi_vector_top_k")]
1164 pub top_k: u32,
1165 #[serde(default)]
1167 pub distance_metric: DistanceMetric,
1168 #[serde(skip_serializing_if = "Option::is_none")]
1170 pub score_threshold: Option<f32>,
1171 #[serde(default)]
1173 pub enable_mmr: bool,
1174 #[serde(default = "default_mmr_lambda")]
1176 pub mmr_lambda: f32,
1177 #[serde(default = "default_true")]
1179 pub include_metadata: bool,
1180 #[serde(default)]
1182 pub include_vectors: bool,
1183 #[serde(skip_serializing_if = "Option::is_none")]
1185 pub filter: Option<serde_json::Value>,
1186 #[serde(default)]
1188 pub consistency: ReadConsistency,
1189 #[serde(skip_serializing_if = "Option::is_none")]
1191 pub staleness_config: Option<StalenessConfig>,
1192}
1193
1194fn default_multi_vector_top_k() -> u32 {
1195 10
1196}
1197
1198fn default_mmr_lambda() -> f32 {
1199 0.5
1200}
1201
1202impl MultiVectorSearchRequest {
1203 pub fn new(positive_vectors: Vec<Vec<f32>>) -> Self {
1205 Self {
1206 positive_vectors,
1207 positive_weights: None,
1208 negative_vectors: None,
1209 negative_weights: None,
1210 top_k: 10,
1211 distance_metric: DistanceMetric::default(),
1212 score_threshold: None,
1213 enable_mmr: false,
1214 mmr_lambda: 0.5,
1215 include_metadata: true,
1216 include_vectors: false,
1217 filter: None,
1218 consistency: ReadConsistency::default(),
1219 staleness_config: None,
1220 }
1221 }
1222
1223 pub fn with_top_k(mut self, top_k: u32) -> Self {
1225 self.top_k = top_k;
1226 self
1227 }
1228
1229 pub fn with_positive_weights(mut self, weights: Vec<f32>) -> Self {
1231 self.positive_weights = Some(weights);
1232 self
1233 }
1234
1235 pub fn with_negative_vectors(mut self, vectors: Vec<Vec<f32>>) -> Self {
1237 self.negative_vectors = Some(vectors);
1238 self
1239 }
1240
1241 pub fn with_negative_weights(mut self, weights: Vec<f32>) -> Self {
1243 self.negative_weights = Some(weights);
1244 self
1245 }
1246
1247 pub fn with_distance_metric(mut self, metric: DistanceMetric) -> Self {
1249 self.distance_metric = metric;
1250 self
1251 }
1252
1253 pub fn with_score_threshold(mut self, threshold: f32) -> Self {
1255 self.score_threshold = Some(threshold);
1256 self
1257 }
1258
1259 pub fn with_mmr(mut self, lambda: f32) -> Self {
1261 self.enable_mmr = true;
1262 self.mmr_lambda = lambda.clamp(0.0, 1.0);
1263 self
1264 }
1265
1266 pub fn include_metadata(mut self, include: bool) -> Self {
1268 self.include_metadata = include;
1269 self
1270 }
1271
1272 pub fn include_vectors(mut self, include: bool) -> Self {
1274 self.include_vectors = include;
1275 self
1276 }
1277
1278 pub fn with_filter(mut self, filter: serde_json::Value) -> Self {
1280 self.filter = Some(filter);
1281 self
1282 }
1283
1284 pub fn with_consistency(mut self, consistency: ReadConsistency) -> Self {
1286 self.consistency = consistency;
1287 self
1288 }
1289}
1290
1291#[derive(Debug, Clone, Serialize, Deserialize)]
1293pub struct MultiVectorSearchResult {
1294 pub id: String,
1296 pub score: f32,
1298 #[serde(skip_serializing_if = "Option::is_none")]
1300 pub mmr_score: Option<f32>,
1301 #[serde(skip_serializing_if = "Option::is_none")]
1303 pub original_rank: Option<usize>,
1304 #[serde(skip_serializing_if = "Option::is_none")]
1306 pub metadata: Option<HashMap<String, serde_json::Value>>,
1307 #[serde(skip_serializing_if = "Option::is_none")]
1309 pub vector: Option<Vec<f32>>,
1310}
1311
1312#[derive(Debug, Clone, Serialize, Deserialize)]
1314pub struct MultiVectorSearchResponse {
1315 pub results: Vec<MultiVectorSearchResult>,
1317 #[serde(skip_serializing_if = "Option::is_none")]
1319 pub computed_query_vector: Option<Vec<f32>>,
1320}
1321
1322#[derive(Debug, Clone, Serialize, Deserialize)]
1328#[serde(untagged)]
1329pub enum AggregateFunction {
1330 Count,
1332 Sum { field: String },
1334 Avg { field: String },
1336 Min { field: String },
1338 Max { field: String },
1340}
1341
1342#[derive(Debug, Clone, Serialize, Deserialize)]
1344pub struct AggregationRequest {
1345 pub aggregate_by: HashMap<String, serde_json::Value>,
1348 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1351 pub group_by: Vec<String>,
1352 #[serde(skip_serializing_if = "Option::is_none")]
1354 pub filter: Option<serde_json::Value>,
1355 #[serde(default = "default_agg_limit")]
1357 pub limit: usize,
1358}
1359
1360fn default_agg_limit() -> usize {
1361 100
1362}
1363
1364impl AggregationRequest {
1365 pub fn new() -> Self {
1367 Self {
1368 aggregate_by: HashMap::new(),
1369 group_by: Vec::new(),
1370 filter: None,
1371 limit: 100,
1372 }
1373 }
1374
1375 pub fn with_count(mut self, name: impl Into<String>) -> Self {
1377 self.aggregate_by
1378 .insert(name.into(), serde_json::json!(["Count"]));
1379 self
1380 }
1381
1382 pub fn with_sum(mut self, name: impl Into<String>, field: impl Into<String>) -> Self {
1384 self.aggregate_by
1385 .insert(name.into(), serde_json::json!(["Sum", field.into()]));
1386 self
1387 }
1388
1389 pub fn with_avg(mut self, name: impl Into<String>, field: impl Into<String>) -> Self {
1391 self.aggregate_by
1392 .insert(name.into(), serde_json::json!(["Avg", field.into()]));
1393 self
1394 }
1395
1396 pub fn with_min(mut self, name: impl Into<String>, field: impl Into<String>) -> Self {
1398 self.aggregate_by
1399 .insert(name.into(), serde_json::json!(["Min", field.into()]));
1400 self
1401 }
1402
1403 pub fn with_max(mut self, name: impl Into<String>, field: impl Into<String>) -> Self {
1405 self.aggregate_by
1406 .insert(name.into(), serde_json::json!(["Max", field.into()]));
1407 self
1408 }
1409
1410 pub fn group_by(mut self, fields: Vec<String>) -> Self {
1412 self.group_by = fields;
1413 self
1414 }
1415
1416 pub fn with_group_by(mut self, field: impl Into<String>) -> Self {
1418 self.group_by.push(field.into());
1419 self
1420 }
1421
1422 pub fn with_filter(mut self, filter: serde_json::Value) -> Self {
1424 self.filter = Some(filter);
1425 self
1426 }
1427
1428 pub fn with_limit(mut self, limit: usize) -> Self {
1430 self.limit = limit;
1431 self
1432 }
1433}
1434
1435impl Default for AggregationRequest {
1436 fn default() -> Self {
1437 Self::new()
1438 }
1439}
1440
1441#[derive(Debug, Clone, Serialize, Deserialize)]
1443pub struct AggregationResponse {
1444 #[serde(skip_serializing_if = "Option::is_none")]
1446 pub aggregations: Option<HashMap<String, serde_json::Value>>,
1447 #[serde(skip_serializing_if = "Option::is_none")]
1449 pub aggregation_groups: Option<Vec<AggregationGroup>>,
1450}
1451
1452#[derive(Debug, Clone, Serialize, Deserialize)]
1454pub struct AggregationGroup {
1455 #[serde(flatten)]
1457 pub group_key: HashMap<String, serde_json::Value>,
1458 #[serde(flatten)]
1460 pub aggregations: HashMap<String, serde_json::Value>,
1461}
1462
1463#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
1469pub enum VectorSearchMethod {
1470 #[default]
1472 ANN,
1473 #[serde(rename = "kNN")]
1475 KNN,
1476}
1477
1478#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
1480#[serde(rename_all = "lowercase")]
1481pub enum SortDirection {
1482 Asc,
1484 #[default]
1486 Desc,
1487}
1488
1489#[derive(Debug, Clone, Serialize, Deserialize)]
1492#[serde(untagged)]
1493pub enum RankBy {
1494 VectorSearch {
1496 field: String,
1497 method: VectorSearchMethod,
1498 query_vector: Vec<f32>,
1499 },
1500 FullTextSearch {
1502 field: String,
1503 method: String, query: String,
1505 },
1506 AttributeOrder {
1508 field: String,
1509 direction: SortDirection,
1510 },
1511 Sum(Vec<RankBy>),
1513 Max(Vec<RankBy>),
1515 Product { weight: f32, ranking: Box<RankBy> },
1517}
1518
1519impl RankBy {
1520 pub fn vector_ann(field: impl Into<String>, query_vector: Vec<f32>) -> Self {
1522 RankBy::VectorSearch {
1523 field: field.into(),
1524 method: VectorSearchMethod::ANN,
1525 query_vector,
1526 }
1527 }
1528
1529 pub fn ann(query_vector: Vec<f32>) -> Self {
1531 Self::vector_ann("vector", query_vector)
1532 }
1533
1534 pub fn vector_knn(field: impl Into<String>, query_vector: Vec<f32>) -> Self {
1536 RankBy::VectorSearch {
1537 field: field.into(),
1538 method: VectorSearchMethod::KNN,
1539 query_vector,
1540 }
1541 }
1542
1543 pub fn knn(query_vector: Vec<f32>) -> Self {
1545 Self::vector_knn("vector", query_vector)
1546 }
1547
1548 pub fn bm25(field: impl Into<String>, query: impl Into<String>) -> Self {
1550 RankBy::FullTextSearch {
1551 field: field.into(),
1552 method: "BM25".to_string(),
1553 query: query.into(),
1554 }
1555 }
1556
1557 pub fn asc(field: impl Into<String>) -> Self {
1559 RankBy::AttributeOrder {
1560 field: field.into(),
1561 direction: SortDirection::Asc,
1562 }
1563 }
1564
1565 pub fn desc(field: impl Into<String>) -> Self {
1567 RankBy::AttributeOrder {
1568 field: field.into(),
1569 direction: SortDirection::Desc,
1570 }
1571 }
1572
1573 pub fn sum(rankings: Vec<RankBy>) -> Self {
1575 RankBy::Sum(rankings)
1576 }
1577
1578 pub fn max(rankings: Vec<RankBy>) -> Self {
1580 RankBy::Max(rankings)
1581 }
1582
1583 pub fn product(weight: f32, ranking: RankBy) -> Self {
1585 RankBy::Product {
1586 weight,
1587 ranking: Box::new(ranking),
1588 }
1589 }
1590}
1591
1592#[derive(Debug, Clone, Serialize, Deserialize)]
1610pub struct UnifiedQueryRequest {
1611 pub rank_by: serde_json::Value,
1613 #[serde(default = "default_unified_top_k")]
1615 pub top_k: usize,
1616 #[serde(skip_serializing_if = "Option::is_none")]
1618 pub filter: Option<serde_json::Value>,
1619 #[serde(default = "default_true")]
1621 pub include_metadata: bool,
1622 #[serde(default)]
1624 pub include_vectors: bool,
1625 #[serde(default)]
1627 pub distance_metric: DistanceMetric,
1628}
1629
1630fn default_unified_top_k() -> usize {
1631 10
1632}
1633
1634impl UnifiedQueryRequest {
1635 pub fn vector_search(query_vector: Vec<f32>, top_k: usize) -> Self {
1637 Self {
1638 rank_by: serde_json::json!(["ANN", query_vector]),
1639 top_k,
1640 filter: None,
1641 include_metadata: true,
1642 include_vectors: false,
1643 distance_metric: DistanceMetric::default(),
1644 }
1645 }
1646
1647 pub fn vector_knn_search(query_vector: Vec<f32>, top_k: usize) -> Self {
1649 Self {
1650 rank_by: serde_json::json!(["kNN", query_vector]),
1651 top_k,
1652 filter: None,
1653 include_metadata: true,
1654 include_vectors: false,
1655 distance_metric: DistanceMetric::default(),
1656 }
1657 }
1658
1659 pub fn fulltext_search(
1661 field: impl Into<String>,
1662 query: impl Into<String>,
1663 top_k: usize,
1664 ) -> Self {
1665 Self {
1666 rank_by: serde_json::json!([field.into(), "BM25", query.into()]),
1667 top_k,
1668 filter: None,
1669 include_metadata: true,
1670 include_vectors: false,
1671 distance_metric: DistanceMetric::default(),
1672 }
1673 }
1674
1675 pub fn attribute_order(
1677 field: impl Into<String>,
1678 direction: SortDirection,
1679 top_k: usize,
1680 ) -> Self {
1681 let dir = match direction {
1682 SortDirection::Asc => "asc",
1683 SortDirection::Desc => "desc",
1684 };
1685 Self {
1686 rank_by: serde_json::json!([field.into(), dir]),
1687 top_k,
1688 filter: None,
1689 include_metadata: true,
1690 include_vectors: false,
1691 distance_metric: DistanceMetric::default(),
1692 }
1693 }
1694
1695 pub fn with_rank_by(rank_by: serde_json::Value, top_k: usize) -> Self {
1697 Self {
1698 rank_by,
1699 top_k,
1700 filter: None,
1701 include_metadata: true,
1702 include_vectors: false,
1703 distance_metric: DistanceMetric::default(),
1704 }
1705 }
1706
1707 pub fn with_filter(mut self, filter: serde_json::Value) -> Self {
1709 self.filter = Some(filter);
1710 self
1711 }
1712
1713 pub fn include_metadata(mut self, include: bool) -> Self {
1715 self.include_metadata = include;
1716 self
1717 }
1718
1719 pub fn include_vectors(mut self, include: bool) -> Self {
1721 self.include_vectors = include;
1722 self
1723 }
1724
1725 pub fn with_distance_metric(mut self, metric: DistanceMetric) -> Self {
1727 self.distance_metric = metric;
1728 self
1729 }
1730
1731 pub fn with_top_k(mut self, top_k: usize) -> Self {
1733 self.top_k = top_k;
1734 self
1735 }
1736}
1737
1738#[derive(Debug, Clone, Serialize, Deserialize)]
1740pub struct UnifiedSearchResult {
1741 pub id: String,
1743 #[serde(rename = "$dist", skip_serializing_if = "Option::is_none")]
1746 pub dist: Option<f32>,
1747 #[serde(skip_serializing_if = "Option::is_none")]
1749 pub metadata: Option<serde_json::Value>,
1750 #[serde(skip_serializing_if = "Option::is_none")]
1752 pub vector: Option<Vec<f32>>,
1753}
1754
1755#[derive(Debug, Clone, Serialize, Deserialize)]
1757pub struct UnifiedQueryResponse {
1758 pub results: Vec<UnifiedSearchResult>,
1760 #[serde(skip_serializing_if = "Option::is_none")]
1762 pub next_cursor: Option<String>,
1763}
1764
1765fn default_explain_top_k() -> usize {
1770 10
1771}
1772
1773#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1775#[serde(rename_all = "snake_case")]
1776#[derive(Default)]
1777pub enum ExplainQueryType {
1778 #[default]
1780 VectorSearch,
1781 FullTextSearch,
1783 HybridSearch,
1785 MultiVector,
1787 BatchQuery,
1789}
1790
1791#[derive(Debug, Clone, Serialize, Deserialize)]
1793pub struct QueryExplainRequest {
1794 #[serde(default)]
1796 pub query_type: ExplainQueryType,
1797 #[serde(skip_serializing_if = "Option::is_none")]
1799 pub vector: Option<Vec<f32>>,
1800 #[serde(default = "default_explain_top_k")]
1802 pub top_k: usize,
1803 #[serde(skip_serializing_if = "Option::is_none")]
1805 pub filter: Option<serde_json::Value>,
1806 #[serde(skip_serializing_if = "Option::is_none")]
1808 pub text_query: Option<String>,
1809 #[serde(default = "default_distance_metric")]
1811 pub distance_metric: String,
1812 #[serde(default)]
1814 pub execute: bool,
1815 #[serde(default)]
1817 pub verbose: bool,
1818}
1819
1820fn default_distance_metric() -> String {
1821 "cosine".to_string()
1822}
1823
1824impl QueryExplainRequest {
1825 pub fn vector_search(vector: Vec<f32>, top_k: usize) -> Self {
1827 Self {
1828 query_type: ExplainQueryType::VectorSearch,
1829 vector: Some(vector),
1830 top_k,
1831 filter: None,
1832 text_query: None,
1833 distance_metric: "cosine".to_string(),
1834 execute: false,
1835 verbose: false,
1836 }
1837 }
1838
1839 pub fn fulltext_search(text_query: impl Into<String>, top_k: usize) -> Self {
1841 Self {
1842 query_type: ExplainQueryType::FullTextSearch,
1843 vector: None,
1844 top_k,
1845 filter: None,
1846 text_query: Some(text_query.into()),
1847 distance_metric: "bm25".to_string(),
1848 execute: false,
1849 verbose: false,
1850 }
1851 }
1852
1853 pub fn hybrid_search(vector: Vec<f32>, text_query: impl Into<String>, top_k: usize) -> Self {
1855 Self {
1856 query_type: ExplainQueryType::HybridSearch,
1857 vector: Some(vector),
1858 top_k,
1859 filter: None,
1860 text_query: Some(text_query.into()),
1861 distance_metric: "hybrid".to_string(),
1862 execute: false,
1863 verbose: false,
1864 }
1865 }
1866
1867 pub fn with_filter(mut self, filter: serde_json::Value) -> Self {
1869 self.filter = Some(filter);
1870 self
1871 }
1872
1873 pub fn with_distance_metric(mut self, metric: impl Into<String>) -> Self {
1875 self.distance_metric = metric.into();
1876 self
1877 }
1878
1879 pub fn with_execution(mut self) -> Self {
1881 self.execute = true;
1882 self
1883 }
1884
1885 pub fn with_verbose(mut self) -> Self {
1887 self.verbose = true;
1888 self
1889 }
1890}
1891
1892#[derive(Debug, Clone, Serialize, Deserialize)]
1894pub struct ExecutionStage {
1895 pub name: String,
1897 pub description: String,
1899 pub order: u32,
1901 pub estimated_input: u64,
1903 pub estimated_output: u64,
1905 pub estimated_cost: f64,
1907 #[serde(default)]
1909 pub details: HashMap<String, serde_json::Value>,
1910}
1911
1912#[derive(Debug, Clone, Serialize, Deserialize)]
1914pub struct CostEstimate {
1915 pub total_cost: f64,
1917 pub estimated_time_ms: u64,
1919 pub estimated_memory_bytes: u64,
1921 pub estimated_io_ops: u64,
1923 #[serde(default)]
1925 pub cost_breakdown: HashMap<String, f64>,
1926 pub confidence: f64,
1928}
1929
1930#[derive(Debug, Clone, Serialize, Deserialize)]
1932pub struct ActualStats {
1933 pub execution_time_ms: u64,
1935 pub results_returned: usize,
1937 pub vectors_scanned: u64,
1939 pub vectors_after_filter: u64,
1941 pub index_lookups: u64,
1943 pub cache_hits: u64,
1945 pub cache_misses: u64,
1947 pub memory_used_bytes: u64,
1949}
1950
1951#[derive(Debug, Clone, Serialize, Deserialize)]
1953pub struct Recommendation {
1954 pub recommendation_type: String,
1956 pub priority: String,
1958 pub description: String,
1960 pub expected_improvement: String,
1962 pub implementation: String,
1964}
1965
1966#[derive(Debug, Clone, Serialize, Deserialize)]
1968pub struct IndexSelection {
1969 pub index_type: String,
1971 pub selection_reason: String,
1973 #[serde(default)]
1975 pub alternatives_considered: Vec<IndexAlternative>,
1976 #[serde(default)]
1978 pub index_config: HashMap<String, serde_json::Value>,
1979 pub index_stats: IndexStatistics,
1981}
1982
1983#[derive(Debug, Clone, Serialize, Deserialize)]
1985pub struct IndexAlternative {
1986 pub index_type: String,
1988 pub rejection_reason: String,
1990 pub estimated_cost: f64,
1992}
1993
1994#[derive(Debug, Clone, Serialize, Deserialize)]
1996pub struct IndexStatistics {
1997 pub vector_count: u64,
1999 pub dimension: usize,
2001 pub memory_bytes: u64,
2003 #[serde(skip_serializing_if = "Option::is_none")]
2005 pub build_time_ms: Option<u64>,
2006 #[serde(skip_serializing_if = "Option::is_none")]
2008 pub last_updated: Option<u64>,
2009}
2010
2011#[derive(Debug, Clone, Serialize, Deserialize)]
2013pub struct QueryParams {
2014 pub top_k: usize,
2016 pub has_filter: bool,
2018 pub filter_complexity: String,
2020 #[serde(skip_serializing_if = "Option::is_none")]
2022 pub vector_dimension: Option<usize>,
2023 pub distance_metric: String,
2025 #[serde(skip_serializing_if = "Option::is_none")]
2027 pub text_query_length: Option<usize>,
2028}
2029
2030#[derive(Debug, Clone, Serialize, Deserialize)]
2032pub struct QueryExplainResponse {
2033 pub query_type: ExplainQueryType,
2035 pub namespace: String,
2037 pub index_selection: IndexSelection,
2039 pub stages: Vec<ExecutionStage>,
2041 pub cost_estimate: CostEstimate,
2043 #[serde(skip_serializing_if = "Option::is_none")]
2045 pub actual_stats: Option<ActualStats>,
2046 #[serde(default)]
2048 pub recommendations: Vec<Recommendation>,
2049 pub summary: String,
2051 pub query_params: QueryParams,
2053}
2054
2055#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
2061#[serde(rename_all = "kebab-case")]
2062pub enum EmbeddingModel {
2063 #[default]
2065 BgeLarge,
2066 Minilm,
2068 BgeSmall,
2070 E5Small,
2072}
2073
2074#[derive(Debug, Clone, Serialize, Deserialize)]
2076pub struct TextDocument {
2077 pub id: String,
2079 pub text: String,
2081 #[serde(skip_serializing_if = "Option::is_none")]
2083 pub metadata: Option<HashMap<String, serde_json::Value>>,
2084 #[serde(skip_serializing_if = "Option::is_none")]
2086 pub ttl_seconds: Option<u64>,
2087}
2088
2089impl TextDocument {
2090 pub fn new(id: impl Into<String>, text: impl Into<String>) -> Self {
2092 Self {
2093 id: id.into(),
2094 text: text.into(),
2095 metadata: None,
2096 ttl_seconds: None,
2097 }
2098 }
2099
2100 pub fn with_metadata(mut self, metadata: HashMap<String, serde_json::Value>) -> Self {
2102 self.metadata = Some(metadata);
2103 self
2104 }
2105
2106 pub fn with_ttl(mut self, ttl_seconds: u64) -> Self {
2108 self.ttl_seconds = Some(ttl_seconds);
2109 self
2110 }
2111}
2112
2113#[derive(Debug, Clone, Serialize, Deserialize)]
2115pub struct UpsertTextRequest {
2116 pub documents: Vec<TextDocument>,
2118 #[serde(skip_serializing_if = "Option::is_none")]
2120 pub model: Option<EmbeddingModel>,
2121}
2122
2123impl UpsertTextRequest {
2124 pub fn new(documents: Vec<TextDocument>) -> Self {
2126 Self {
2127 documents,
2128 model: None,
2129 }
2130 }
2131
2132 pub fn with_model(mut self, model: EmbeddingModel) -> Self {
2134 self.model = Some(model);
2135 self
2136 }
2137}
2138
2139#[derive(Debug, Clone, Serialize, Deserialize)]
2141pub struct TextUpsertResponse {
2142 pub upserted_count: u64,
2144 pub tokens_processed: u64,
2146 pub model: EmbeddingModel,
2148 pub embedding_time_ms: u64,
2150}
2151
2152#[derive(Debug, Clone, Serialize, Deserialize)]
2154pub struct TextSearchResult {
2155 pub id: String,
2157 pub score: f32,
2159 #[serde(skip_serializing_if = "Option::is_none")]
2161 pub text: Option<String>,
2162 #[serde(skip_serializing_if = "Option::is_none")]
2164 pub metadata: Option<HashMap<String, serde_json::Value>>,
2165 #[serde(skip_serializing_if = "Option::is_none")]
2167 pub vector: Option<Vec<f32>>,
2168}
2169
2170#[derive(Debug, Clone, Serialize, Deserialize)]
2172pub struct QueryTextRequest {
2173 pub text: String,
2175 pub top_k: u32,
2177 #[serde(skip_serializing_if = "Option::is_none")]
2179 pub filter: Option<serde_json::Value>,
2180 pub include_text: bool,
2182 pub include_vectors: bool,
2184 #[serde(skip_serializing_if = "Option::is_none")]
2186 pub model: Option<EmbeddingModel>,
2187}
2188
2189impl QueryTextRequest {
2190 pub fn new(text: impl Into<String>, top_k: u32) -> Self {
2192 Self {
2193 text: text.into(),
2194 top_k,
2195 filter: None,
2196 include_text: true,
2197 include_vectors: false,
2198 model: None,
2199 }
2200 }
2201
2202 pub fn with_filter(mut self, filter: serde_json::Value) -> Self {
2204 self.filter = Some(filter);
2205 self
2206 }
2207
2208 pub fn include_text(mut self, include: bool) -> Self {
2210 self.include_text = include;
2211 self
2212 }
2213
2214 pub fn include_vectors(mut self, include: bool) -> Self {
2216 self.include_vectors = include;
2217 self
2218 }
2219
2220 pub fn with_model(mut self, model: EmbeddingModel) -> Self {
2222 self.model = Some(model);
2223 self
2224 }
2225}
2226
2227#[derive(Debug, Clone, Serialize, Deserialize)]
2229pub struct TextQueryResponse {
2230 pub results: Vec<TextSearchResult>,
2232 pub model: EmbeddingModel,
2234 pub embedding_time_ms: u64,
2236 pub search_time_ms: u64,
2238}
2239
2240#[derive(Debug, Clone, Serialize, Deserialize)]
2242pub struct BatchQueryTextRequest {
2243 pub queries: Vec<String>,
2245 pub top_k: u32,
2247 #[serde(skip_serializing_if = "Option::is_none")]
2249 pub filter: Option<serde_json::Value>,
2250 pub include_vectors: bool,
2252 #[serde(skip_serializing_if = "Option::is_none")]
2254 pub model: Option<EmbeddingModel>,
2255}
2256
2257impl BatchQueryTextRequest {
2258 pub fn new(queries: Vec<String>, top_k: u32) -> Self {
2260 Self {
2261 queries,
2262 top_k,
2263 filter: None,
2264 include_vectors: false,
2265 model: None,
2266 }
2267 }
2268}
2269
2270#[derive(Debug, Clone, Serialize, Deserialize)]
2272pub struct BatchQueryTextResponse {
2273 pub results: Vec<Vec<TextSearchResult>>,
2275 pub model: EmbeddingModel,
2277 pub embedding_time_ms: u64,
2279 pub search_time_ms: u64,
2281}
2282
2283#[derive(Debug, Clone, Serialize, Deserialize)]
2289pub struct FetchRequest {
2290 pub ids: Vec<String>,
2292 pub include_values: bool,
2294 pub include_metadata: bool,
2296}
2297
2298impl FetchRequest {
2299 pub fn new(ids: Vec<String>) -> Self {
2301 Self {
2302 ids,
2303 include_values: true,
2304 include_metadata: true,
2305 }
2306 }
2307}
2308
2309#[derive(Debug, Clone, Serialize, Deserialize)]
2311pub struct FetchResponse {
2312 pub vectors: Vec<Vector>,
2314}
2315
2316#[derive(Debug, Clone, Serialize, Deserialize, Default)]
2322pub struct CreateNamespaceRequest {
2323 #[serde(rename = "dimension", skip_serializing_if = "Option::is_none")]
2325 pub dimensions: Option<u32>,
2326 #[serde(skip_serializing_if = "Option::is_none")]
2328 pub index_type: Option<String>,
2329 #[serde(skip_serializing_if = "Option::is_none")]
2331 pub metadata: Option<HashMap<String, serde_json::Value>>,
2332}
2333
2334impl CreateNamespaceRequest {
2335 pub fn new() -> Self {
2337 Self::default()
2338 }
2339
2340 pub fn with_dimensions(mut self, dimensions: u32) -> Self {
2342 self.dimensions = Some(dimensions);
2343 self
2344 }
2345
2346 pub fn with_index_type(mut self, index_type: impl Into<String>) -> Self {
2348 self.index_type = Some(index_type.into());
2349 self
2350 }
2351}
2352
2353#[derive(Debug, Clone, Serialize, Deserialize)]
2358pub struct ConfigureNamespaceRequest {
2359 pub dimension: usize,
2361 #[serde(skip_serializing_if = "Option::is_none")]
2363 pub distance: Option<DistanceMetric>,
2364}
2365
2366impl ConfigureNamespaceRequest {
2367 pub fn new(dimension: usize) -> Self {
2369 Self {
2370 dimension,
2371 distance: None,
2372 }
2373 }
2374
2375 pub fn with_distance(mut self, distance: DistanceMetric) -> Self {
2377 self.distance = Some(distance);
2378 self
2379 }
2380}
2381
2382#[derive(Debug, Clone, Serialize, Deserialize)]
2384pub struct ConfigureNamespaceResponse {
2385 pub namespace: String,
2387 pub dimension: usize,
2389 pub distance: DistanceMetric,
2391 pub created: bool,
2393}
2394
2395#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
2401#[serde(rename_all = "snake_case")]
2402pub enum EdgeType {
2403 RelatedTo,
2405 SharesEntity,
2407 Precedes,
2409 #[default]
2411 LinkedBy,
2412}
2413
2414#[derive(Debug, Clone, Serialize, Deserialize)]
2416pub struct GraphEdge {
2417 pub id: String,
2419 pub source_id: String,
2421 pub target_id: String,
2423 pub edge_type: EdgeType,
2425 pub weight: f64,
2427 pub created_at: i64,
2429}
2430
2431#[derive(Debug, Clone, Serialize, Deserialize)]
2433pub struct GraphNode {
2434 pub memory_id: String,
2436 pub content_preview: String,
2438 pub importance: f64,
2440 pub depth: u32,
2442}
2443
2444#[derive(Debug, Clone, Serialize, Deserialize)]
2446pub struct MemoryGraph {
2447 pub root_id: String,
2449 pub depth: u32,
2451 pub nodes: Vec<GraphNode>,
2453 pub edges: Vec<GraphEdge>,
2455}
2456
2457#[derive(Debug, Clone, Serialize, Deserialize)]
2459pub struct GraphPath {
2460 pub source_id: String,
2462 pub target_id: String,
2464 pub path: Vec<String>,
2466 pub hops: i32,
2468 pub edges: Vec<GraphEdge>,
2470}
2471
2472#[derive(Debug, Clone, Serialize, Deserialize)]
2474pub struct GraphLinkRequest {
2475 pub target_id: String,
2477 pub edge_type: EdgeType,
2479}
2480
2481#[derive(Debug, Clone, Serialize, Deserialize)]
2483pub struct GraphLinkResponse {
2484 pub edge: GraphEdge,
2486}
2487
2488#[derive(Debug, Clone, Serialize, Deserialize)]
2490pub struct GraphExport {
2491 pub agent_id: String,
2493 pub format: String,
2495 pub data: String,
2497 pub node_count: u64,
2499 pub edge_count: u64,
2501}
2502
2503#[derive(Debug, Clone, Default)]
2505pub struct GraphOptions {
2506 pub depth: Option<u32>,
2508 pub types: Option<Vec<EdgeType>>,
2510}
2511
2512impl GraphOptions {
2513 pub fn new() -> Self {
2515 Self::default()
2516 }
2517
2518 pub fn depth(mut self, depth: u32) -> Self {
2520 self.depth = Some(depth);
2521 self
2522 }
2523
2524 pub fn types(mut self, types: Vec<EdgeType>) -> Self {
2526 self.types = Some(types);
2527 self
2528 }
2529}
2530
2531#[derive(Debug, Clone, Serialize, Deserialize, Default)]
2537pub struct NamespaceNerConfig {
2538 pub extract_entities: bool,
2539 #[serde(skip_serializing_if = "Option::is_none")]
2540 pub entity_types: Option<Vec<String>>,
2541}
2542
2543#[derive(Debug, Clone, Serialize, Deserialize)]
2545pub struct ExtractedEntity {
2546 pub entity_type: String,
2547 pub value: String,
2548 pub score: f64,
2549}
2550
2551#[derive(Debug, Clone, Serialize, Deserialize)]
2553pub struct EntityExtractionResponse {
2554 pub entities: Vec<ExtractedEntity>,
2555}
2556
2557#[derive(Debug, Clone, Serialize, Deserialize)]
2559pub struct MemoryEntitiesResponse {
2560 pub memory_id: String,
2561 pub entities: Vec<ExtractedEntity>,
2562}
2563
2564#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2576#[serde(rename_all = "lowercase")]
2577pub enum FeedbackSignal {
2578 Upvote,
2579 Downvote,
2580 Flag,
2581 Positive,
2582 Negative,
2583}
2584
2585#[derive(Debug, Clone, Serialize, Deserialize)]
2587pub struct FeedbackHistoryEntry {
2588 pub signal: FeedbackSignal,
2589 pub timestamp: u64,
2591 pub old_importance: f32,
2592 pub new_importance: f32,
2593}
2594
2595#[derive(Debug, Clone, Serialize, Deserialize)]
2597pub struct MemoryFeedbackBody {
2598 pub agent_id: String,
2599 pub signal: FeedbackSignal,
2600}
2601
2602#[derive(Debug, Clone, Serialize, Deserialize)]
2604pub struct MemoryImportancePatch {
2605 pub agent_id: String,
2606 pub importance: f32,
2607}
2608
2609#[derive(Debug, Clone, Serialize, Deserialize)]
2611pub struct FeedbackResponse {
2612 pub memory_id: String,
2613 pub new_importance: f32,
2615 pub signal: FeedbackSignal,
2616}
2617
2618#[derive(Debug, Clone, Serialize, Deserialize)]
2620pub struct FeedbackHistoryResponse {
2621 pub memory_id: String,
2622 pub entries: Vec<FeedbackHistoryEntry>,
2624}
2625
2626#[derive(Debug, Clone, Serialize, Deserialize)]
2628pub struct AgentFeedbackSummary {
2629 pub agent_id: String,
2630 pub upvotes: u64,
2631 pub downvotes: u64,
2632 pub flags: u64,
2633 pub total_feedback: u64,
2634 pub health_score: f32,
2636}
2637
2638#[derive(Debug, Clone, Serialize, Deserialize)]
2640pub struct FeedbackHealthResponse {
2641 pub agent_id: String,
2642 pub health_score: f32,
2644 pub memory_count: usize,
2645 pub avg_importance: f32,
2646}
2647
2648#[derive(Debug, Clone, Serialize, Deserialize)]
2654pub struct OdeEntity {
2655 pub text: String,
2657 pub label: String,
2659 pub start: usize,
2661 pub end: usize,
2663 pub score: f32,
2665}
2666
2667#[derive(Debug, Clone, Serialize, Deserialize)]
2669pub struct ExtractEntitiesRequest {
2670 pub content: String,
2672 pub agent_id: String,
2674 #[serde(skip_serializing_if = "Option::is_none")]
2676 pub memory_id: Option<String>,
2677 #[serde(skip_serializing_if = "Option::is_none")]
2680 pub entity_types: Option<Vec<String>>,
2681}
2682
2683#[derive(Debug, Clone, Serialize, Deserialize)]
2685pub struct ExtractEntitiesResponse {
2686 pub entities: Vec<OdeEntity>,
2688 pub model: String,
2690 pub processing_time_ms: u64,
2692}
2693
2694#[derive(Debug, Clone, Serialize, Deserialize)]
2700pub struct KgQueryResponse {
2701 pub agent_id: String,
2703 pub node_count: usize,
2705 pub edge_count: usize,
2707 pub edges: Vec<GraphEdge>,
2709}
2710
2711#[derive(Debug, Clone, Serialize, Deserialize)]
2713pub struct KgPathResponse {
2714 pub agent_id: String,
2716 pub from_id: String,
2718 pub to_id: String,
2720 pub hop_count: usize,
2722 pub path: Vec<String>,
2724}
2725
2726#[derive(Debug, Clone, Serialize, Deserialize)]
2728pub struct KgExportResponse {
2729 pub agent_id: String,
2731 pub format: String,
2733 pub node_count: usize,
2735 pub edge_count: usize,
2737 pub edges: Vec<GraphEdge>,
2739}
2740
2741#[derive(Debug, Clone, Serialize, Deserialize)]
2753pub struct MemoryPolicy {
2754 #[serde(skip_serializing_if = "Option::is_none")]
2757 pub working_ttl_seconds: Option<u64>,
2758 #[serde(skip_serializing_if = "Option::is_none")]
2760 pub episodic_ttl_seconds: Option<u64>,
2761 #[serde(skip_serializing_if = "Option::is_none")]
2763 pub semantic_ttl_seconds: Option<u64>,
2764 #[serde(skip_serializing_if = "Option::is_none")]
2766 pub procedural_ttl_seconds: Option<u64>,
2767
2768 #[serde(skip_serializing_if = "Option::is_none")]
2771 pub working_decay: Option<String>,
2772 #[serde(skip_serializing_if = "Option::is_none")]
2774 pub episodic_decay: Option<String>,
2775 #[serde(skip_serializing_if = "Option::is_none")]
2777 pub semantic_decay: Option<String>,
2778 #[serde(skip_serializing_if = "Option::is_none")]
2780 pub procedural_decay: Option<String>,
2781
2782 #[serde(skip_serializing_if = "Option::is_none")]
2786 pub spaced_repetition_factor: Option<f64>,
2787 #[serde(skip_serializing_if = "Option::is_none")]
2789 pub spaced_repetition_base_interval_seconds: Option<u64>,
2790
2791 #[serde(skip_serializing_if = "Option::is_none")]
2796 pub consolidation_enabled: Option<bool>,
2797 #[serde(skip_serializing_if = "Option::is_none")]
2800 pub consolidation_threshold: Option<f32>,
2801 #[serde(skip_serializing_if = "Option::is_none")]
2803 pub consolidation_interval_hours: Option<u32>,
2804 #[serde(skip_serializing_if = "Option::is_none")]
2809 pub consolidated_count: Option<u64>,
2810
2811 #[serde(skip_serializing_if = "Option::is_none")]
2814 pub rate_limit_enabled: Option<bool>,
2815 #[serde(skip_serializing_if = "Option::is_none")]
2817 pub rate_limit_stores_per_minute: Option<u32>,
2818 #[serde(skip_serializing_if = "Option::is_none")]
2820 pub rate_limit_recalls_per_minute: Option<u32>,
2821
2822 #[serde(skip_serializing_if = "Option::is_none")]
2829 pub dedup_on_store: Option<bool>,
2830 #[serde(skip_serializing_if = "Option::is_none")]
2835 pub dedup_threshold: Option<f32>,
2836}
2837
2838impl Default for MemoryPolicy {
2839 fn default() -> Self {
2840 Self {
2841 working_ttl_seconds: Some(14_400),
2842 episodic_ttl_seconds: Some(2_592_000),
2843 semantic_ttl_seconds: Some(31_536_000),
2844 procedural_ttl_seconds: Some(63_072_000),
2845 working_decay: Some("exponential".to_string()),
2846 episodic_decay: Some("power_law".to_string()),
2847 semantic_decay: Some("logarithmic".to_string()),
2848 procedural_decay: Some("flat".to_string()),
2849 spaced_repetition_factor: Some(1.0),
2850 spaced_repetition_base_interval_seconds: Some(86_400),
2851 consolidation_enabled: Some(false),
2852 consolidation_threshold: Some(0.92),
2853 consolidation_interval_hours: Some(24),
2854 consolidated_count: Some(0),
2855 rate_limit_enabled: Some(false),
2856 rate_limit_stores_per_minute: None,
2857 rate_limit_recalls_per_minute: None,
2858 dedup_on_store: Some(false),
2859 dedup_threshold: Some(0.92),
2860 }
2861 }
2862}