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 pub vector_count: u64,
111 #[serde(alias = "dimension")]
113 pub dimensions: Option<u32>,
114 pub index_type: Option<String>,
116}
117
118#[derive(Debug, Clone, Serialize, Deserialize)]
120pub struct ListNamespacesResponse {
121 pub namespaces: Vec<String>,
123}
124
125#[derive(Debug, Clone, Serialize, Deserialize)]
131pub struct Vector {
132 pub id: String,
134 pub values: Vec<f32>,
136 #[serde(skip_serializing_if = "Option::is_none")]
138 pub metadata: Option<HashMap<String, serde_json::Value>>,
139}
140
141impl Vector {
142 pub fn new(id: impl Into<String>, values: Vec<f32>) -> Self {
144 Self {
145 id: id.into(),
146 values,
147 metadata: None,
148 }
149 }
150
151 pub fn with_metadata(
153 id: impl Into<String>,
154 values: Vec<f32>,
155 metadata: HashMap<String, serde_json::Value>,
156 ) -> Self {
157 Self {
158 id: id.into(),
159 values,
160 metadata: Some(metadata),
161 }
162 }
163}
164
165#[derive(Debug, Clone, Serialize, Deserialize)]
167pub struct UpsertRequest {
168 pub vectors: Vec<Vector>,
170}
171
172impl UpsertRequest {
173 pub fn single(vector: Vector) -> Self {
175 Self {
176 vectors: vec![vector],
177 }
178 }
179
180 pub fn batch(vectors: Vec<Vector>) -> Self {
182 Self { vectors }
183 }
184}
185
186#[derive(Debug, Clone, Serialize, Deserialize)]
188pub struct UpsertResponse {
189 pub upserted_count: u64,
191}
192
193#[derive(Debug, Clone, Serialize, Deserialize)]
210pub struct ColumnUpsertRequest {
211 pub ids: Vec<String>,
213 pub vectors: Vec<Vec<f32>>,
215 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
218 pub attributes: HashMap<String, Vec<serde_json::Value>>,
219 #[serde(skip_serializing_if = "Option::is_none")]
221 pub ttl_seconds: Option<u64>,
222 #[serde(skip_serializing_if = "Option::is_none")]
224 pub dimension: Option<usize>,
225}
226
227impl ColumnUpsertRequest {
228 pub fn new(ids: Vec<String>, vectors: Vec<Vec<f32>>) -> Self {
230 Self {
231 ids,
232 vectors,
233 attributes: HashMap::new(),
234 ttl_seconds: None,
235 dimension: None,
236 }
237 }
238
239 pub fn with_attribute(
241 mut self,
242 name: impl Into<String>,
243 values: Vec<serde_json::Value>,
244 ) -> Self {
245 self.attributes.insert(name.into(), values);
246 self
247 }
248
249 pub fn with_ttl(mut self, seconds: u64) -> Self {
251 self.ttl_seconds = Some(seconds);
252 self
253 }
254
255 pub fn with_dimension(mut self, dim: usize) -> Self {
257 self.dimension = Some(dim);
258 self
259 }
260
261 pub fn len(&self) -> usize {
263 self.ids.len()
264 }
265
266 pub fn is_empty(&self) -> bool {
268 self.ids.is_empty()
269 }
270}
271
272#[derive(Debug, Clone, Serialize, Deserialize)]
274pub struct DeleteRequest {
275 pub ids: Vec<String>,
277}
278
279impl DeleteRequest {
280 pub fn single(id: impl Into<String>) -> Self {
282 Self {
283 ids: vec![id.into()],
284 }
285 }
286
287 pub fn batch(ids: Vec<String>) -> Self {
289 Self { ids }
290 }
291}
292
293#[derive(Debug, Clone, Serialize, Deserialize)]
295pub struct DeleteResponse {
296 pub deleted_count: u64,
298}
299
300#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
306#[serde(rename_all = "snake_case")]
307pub enum ReadConsistency {
308 Strong,
310 #[default]
312 Eventual,
313 #[serde(rename = "bounded_staleness")]
315 BoundedStaleness,
316}
317
318#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
320pub struct StalenessConfig {
321 #[serde(default = "default_max_staleness_ms")]
323 pub max_staleness_ms: u64,
324}
325
326fn default_max_staleness_ms() -> u64 {
327 5000 }
329
330impl StalenessConfig {
331 pub fn new(max_staleness_ms: u64) -> Self {
333 Self { max_staleness_ms }
334 }
335}
336
337#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
339#[serde(rename_all = "snake_case")]
340pub enum DistanceMetric {
341 #[default]
343 Cosine,
344 Euclidean,
346 DotProduct,
348}
349
350#[derive(Debug, Clone, Serialize, Deserialize)]
352pub struct QueryRequest {
353 pub vector: Vec<f32>,
355 pub top_k: u32,
357 #[serde(default)]
359 pub distance_metric: DistanceMetric,
360 #[serde(skip_serializing_if = "Option::is_none")]
362 pub filter: Option<serde_json::Value>,
363 #[serde(default = "default_true")]
365 pub include_metadata: bool,
366 #[serde(default)]
368 pub include_vectors: bool,
369 #[serde(default)]
371 pub consistency: ReadConsistency,
372 #[serde(skip_serializing_if = "Option::is_none")]
374 pub staleness_config: Option<StalenessConfig>,
375}
376
377fn default_true() -> bool {
378 true
379}
380
381impl QueryRequest {
382 pub fn new(vector: Vec<f32>, top_k: u32) -> Self {
384 Self {
385 vector,
386 top_k,
387 distance_metric: DistanceMetric::default(),
388 filter: None,
389 include_metadata: true,
390 include_vectors: false,
391 consistency: ReadConsistency::default(),
392 staleness_config: None,
393 }
394 }
395
396 pub fn with_filter(mut self, filter: serde_json::Value) -> Self {
398 self.filter = Some(filter);
399 self
400 }
401
402 pub fn include_metadata(mut self, include: bool) -> Self {
404 self.include_metadata = include;
405 self
406 }
407
408 pub fn include_vectors(mut self, include: bool) -> Self {
410 self.include_vectors = include;
411 self
412 }
413
414 pub fn with_distance_metric(mut self, metric: DistanceMetric) -> Self {
416 self.distance_metric = metric;
417 self
418 }
419
420 pub fn with_consistency(mut self, consistency: ReadConsistency) -> Self {
422 self.consistency = consistency;
423 self
424 }
425
426 pub fn with_bounded_staleness(mut self, max_staleness_ms: u64) -> Self {
428 self.consistency = ReadConsistency::BoundedStaleness;
429 self.staleness_config = Some(StalenessConfig::new(max_staleness_ms));
430 self
431 }
432
433 pub fn with_strong_consistency(mut self) -> Self {
435 self.consistency = ReadConsistency::Strong;
436 self
437 }
438}
439
440#[derive(Debug, Clone, Serialize, Deserialize)]
442pub struct Match {
443 pub id: String,
445 pub score: f32,
447 #[serde(skip_serializing_if = "Option::is_none")]
449 pub metadata: Option<HashMap<String, serde_json::Value>>,
450}
451
452#[derive(Debug, Clone, Serialize, Deserialize)]
454pub struct QueryResponse {
455 pub matches: Vec<Match>,
457}
458
459#[derive(Debug, Clone, Serialize, Deserialize)]
465pub struct Document {
466 pub id: String,
468 pub text: String,
470 #[serde(skip_serializing_if = "Option::is_none")]
472 pub metadata: Option<HashMap<String, serde_json::Value>>,
473}
474
475impl Document {
476 pub fn new(id: impl Into<String>, text: impl Into<String>) -> Self {
478 Self {
479 id: id.into(),
480 text: text.into(),
481 metadata: None,
482 }
483 }
484
485 pub fn with_metadata(
487 id: impl Into<String>,
488 text: impl Into<String>,
489 metadata: HashMap<String, serde_json::Value>,
490 ) -> Self {
491 Self {
492 id: id.into(),
493 text: text.into(),
494 metadata: Some(metadata),
495 }
496 }
497}
498
499#[derive(Debug, Clone, Serialize, Deserialize)]
501pub struct IndexDocumentsRequest {
502 pub documents: Vec<Document>,
504}
505
506#[derive(Debug, Clone, Serialize, Deserialize)]
508pub struct IndexDocumentsResponse {
509 pub indexed_count: u64,
511}
512
513#[derive(Debug, Clone, Serialize, Deserialize)]
515pub struct FullTextSearchRequest {
516 pub query: String,
518 pub top_k: u32,
520 #[serde(skip_serializing_if = "Option::is_none")]
522 pub filter: Option<serde_json::Value>,
523}
524
525impl FullTextSearchRequest {
526 pub fn new(query: impl Into<String>, top_k: u32) -> Self {
528 Self {
529 query: query.into(),
530 top_k,
531 filter: None,
532 }
533 }
534
535 pub fn with_filter(mut self, filter: serde_json::Value) -> Self {
537 self.filter = Some(filter);
538 self
539 }
540}
541
542#[derive(Debug, Clone, Serialize, Deserialize)]
544pub struct FullTextMatch {
545 pub id: String,
547 pub score: f32,
549 #[serde(skip_serializing_if = "Option::is_none")]
551 pub text: Option<String>,
552 #[serde(skip_serializing_if = "Option::is_none")]
554 pub metadata: Option<HashMap<String, serde_json::Value>>,
555}
556
557#[derive(Debug, Clone, Serialize, Deserialize)]
559pub struct FullTextSearchResponse {
560 pub matches: Vec<FullTextMatch>,
562}
563
564#[derive(Debug, Clone, Serialize, Deserialize)]
566pub struct FullTextStats {
567 pub document_count: u64,
569 pub term_count: u64,
571}
572
573#[derive(Debug, Clone, Serialize, Deserialize)]
582pub struct HybridSearchRequest {
583 #[serde(skip_serializing_if = "Option::is_none")]
585 pub vector: Option<Vec<f32>>,
586 pub text: String,
588 pub top_k: u32,
590 #[serde(default = "default_vector_weight")]
592 pub vector_weight: f32,
593 #[serde(skip_serializing_if = "Option::is_none")]
595 pub filter: Option<serde_json::Value>,
596}
597
598fn default_vector_weight() -> f32 {
599 0.5
600}
601
602impl HybridSearchRequest {
603 pub fn new(vector: Vec<f32>, text: impl Into<String>, top_k: u32) -> Self {
605 Self {
606 vector: Some(vector),
607 text: text.into(),
608 top_k,
609 vector_weight: 0.5,
610 filter: None,
611 }
612 }
613
614 pub fn text_only(text: impl Into<String>, top_k: u32) -> Self {
616 Self {
617 vector: None,
618 text: text.into(),
619 top_k,
620 vector_weight: 0.5,
621 filter: None,
622 }
623 }
624
625 pub fn with_vector_weight(mut self, weight: f32) -> Self {
627 self.vector_weight = weight.clamp(0.0, 1.0);
628 self
629 }
630
631 pub fn with_filter(mut self, filter: serde_json::Value) -> Self {
633 self.filter = Some(filter);
634 self
635 }
636}
637
638#[derive(Debug, Clone, Serialize, Deserialize)]
640pub struct HybridSearchResponse {
641 pub matches: Vec<Match>,
643}
644
645#[derive(Debug, Clone, Serialize, Deserialize)]
651pub struct SystemDiagnostics {
652 pub system: SystemInfo,
654 pub resources: ResourceUsage,
656 pub components: ComponentHealth,
658 pub active_jobs: u64,
660}
661
662#[derive(Debug, Clone, Serialize, Deserialize)]
664pub struct SystemInfo {
665 pub version: String,
667 pub rust_version: String,
669 pub uptime_seconds: u64,
671 pub pid: u32,
673}
674
675#[derive(Debug, Clone, Serialize, Deserialize)]
677pub struct ResourceUsage {
678 pub memory_bytes: u64,
680 pub thread_count: u64,
682 pub open_fds: u64,
684 pub cpu_percent: Option<f64>,
686}
687
688#[derive(Debug, Clone, Serialize, Deserialize)]
690pub struct ComponentHealth {
691 pub storage: HealthStatus,
693 pub search_engine: HealthStatus,
695 pub cache: HealthStatus,
697 pub grpc: HealthStatus,
699}
700
701#[derive(Debug, Clone, Serialize, Deserialize)]
703pub struct HealthStatus {
704 pub healthy: bool,
706 pub message: String,
708 pub last_check: u64,
710}
711
712#[derive(Debug, Clone, Serialize, Deserialize)]
714pub struct JobInfo {
715 pub id: String,
717 pub job_type: String,
719 pub status: String,
721 pub created_at: u64,
723 pub started_at: Option<u64>,
725 pub completed_at: Option<u64>,
727 pub progress: u8,
729 pub message: Option<String>,
731}
732
733#[derive(Debug, Clone, Serialize, Deserialize)]
735pub struct CompactionRequest {
736 #[serde(skip_serializing_if = "Option::is_none")]
738 pub namespace: Option<String>,
739 #[serde(default)]
741 pub force: bool,
742}
743
744#[derive(Debug, Clone, Serialize, Deserialize)]
746pub struct CompactionResponse {
747 pub job_id: String,
749 pub message: String,
751}
752
753#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
759#[serde(rename_all = "snake_case")]
760pub enum WarmingPriority {
761 Critical,
763 High,
765 #[default]
767 Normal,
768 Low,
770 Background,
772}
773
774#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
776#[serde(rename_all = "snake_case")]
777pub enum WarmingTargetTier {
778 L1,
780 #[default]
782 L2,
783 Both,
785}
786
787#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
789#[serde(rename_all = "snake_case")]
790pub enum AccessPatternHint {
791 #[default]
793 Random,
794 Sequential,
796 Temporal,
798 Spatial,
800}
801
802#[derive(Debug, Clone, Serialize, Deserialize)]
804pub struct WarmCacheRequest {
805 pub namespace: String,
807 #[serde(skip_serializing_if = "Option::is_none")]
809 pub vector_ids: Option<Vec<String>>,
810 #[serde(default)]
812 pub priority: WarmingPriority,
813 #[serde(default)]
815 pub target_tier: WarmingTargetTier,
816 #[serde(default)]
818 pub background: bool,
819 #[serde(skip_serializing_if = "Option::is_none")]
821 pub ttl_hint_seconds: Option<u64>,
822 #[serde(default)]
824 pub access_pattern: AccessPatternHint,
825 #[serde(skip_serializing_if = "Option::is_none")]
827 pub max_vectors: Option<usize>,
828}
829
830impl WarmCacheRequest {
831 pub fn new(namespace: impl Into<String>) -> Self {
833 Self {
834 namespace: namespace.into(),
835 vector_ids: None,
836 priority: WarmingPriority::default(),
837 target_tier: WarmingTargetTier::default(),
838 background: false,
839 ttl_hint_seconds: None,
840 access_pattern: AccessPatternHint::default(),
841 max_vectors: None,
842 }
843 }
844
845 pub fn with_vector_ids(mut self, ids: Vec<String>) -> Self {
847 self.vector_ids = Some(ids);
848 self
849 }
850
851 pub fn with_priority(mut self, priority: WarmingPriority) -> Self {
853 self.priority = priority;
854 self
855 }
856
857 pub fn with_target_tier(mut self, tier: WarmingTargetTier) -> Self {
859 self.target_tier = tier;
860 self
861 }
862
863 pub fn in_background(mut self) -> Self {
865 self.background = true;
866 self
867 }
868
869 pub fn with_ttl(mut self, seconds: u64) -> Self {
871 self.ttl_hint_seconds = Some(seconds);
872 self
873 }
874
875 pub fn with_access_pattern(mut self, pattern: AccessPatternHint) -> Self {
877 self.access_pattern = pattern;
878 self
879 }
880
881 pub fn with_max_vectors(mut self, max: usize) -> Self {
883 self.max_vectors = Some(max);
884 self
885 }
886}
887
888#[derive(Debug, Clone, Serialize, Deserialize)]
890pub struct WarmCacheResponse {
891 pub success: bool,
893 pub entries_warmed: u64,
895 pub entries_skipped: u64,
897 #[serde(skip_serializing_if = "Option::is_none")]
899 pub job_id: Option<String>,
900 pub message: String,
902 #[serde(skip_serializing_if = "Option::is_none")]
904 pub estimated_completion: Option<String>,
905 pub target_tier: WarmingTargetTier,
907 pub priority: WarmingPriority,
909 #[serde(skip_serializing_if = "Option::is_none")]
911 pub bytes_warmed: Option<u64>,
912}
913
914#[derive(Debug, Clone, Serialize, Deserialize)]
920pub struct ExportRequest {
921 #[serde(default = "default_export_top_k")]
923 pub top_k: usize,
924 #[serde(skip_serializing_if = "Option::is_none")]
926 pub cursor: Option<String>,
927 #[serde(default = "default_true")]
929 pub include_vectors: bool,
930 #[serde(default = "default_true")]
932 pub include_metadata: bool,
933}
934
935fn default_export_top_k() -> usize {
936 1000
937}
938
939impl Default for ExportRequest {
940 fn default() -> Self {
941 Self {
942 top_k: 1000,
943 cursor: None,
944 include_vectors: true,
945 include_metadata: true,
946 }
947 }
948}
949
950impl ExportRequest {
951 pub fn new() -> Self {
953 Self::default()
954 }
955
956 pub fn with_top_k(mut self, top_k: usize) -> Self {
958 self.top_k = top_k;
959 self
960 }
961
962 pub fn with_cursor(mut self, cursor: impl Into<String>) -> Self {
964 self.cursor = Some(cursor.into());
965 self
966 }
967
968 pub fn include_vectors(mut self, include: bool) -> Self {
970 self.include_vectors = include;
971 self
972 }
973
974 pub fn include_metadata(mut self, include: bool) -> Self {
976 self.include_metadata = include;
977 self
978 }
979}
980
981#[derive(Debug, Clone, Serialize, Deserialize)]
983pub struct ExportedVector {
984 pub id: String,
986 #[serde(skip_serializing_if = "Option::is_none")]
988 pub values: Option<Vec<f32>>,
989 #[serde(skip_serializing_if = "Option::is_none")]
991 pub metadata: Option<serde_json::Value>,
992 #[serde(skip_serializing_if = "Option::is_none")]
994 pub ttl_seconds: Option<u64>,
995}
996
997#[derive(Debug, Clone, Serialize, Deserialize)]
999pub struct ExportResponse {
1000 pub vectors: Vec<ExportedVector>,
1002 #[serde(skip_serializing_if = "Option::is_none")]
1004 pub next_cursor: Option<String>,
1005 pub total_count: usize,
1007 pub returned_count: usize,
1009}
1010
1011#[derive(Debug, Clone, Serialize, Deserialize)]
1017pub struct BatchQueryItem {
1018 #[serde(skip_serializing_if = "Option::is_none")]
1020 pub id: Option<String>,
1021 pub vector: Vec<f32>,
1023 #[serde(default = "default_batch_top_k")]
1025 pub top_k: u32,
1026 #[serde(skip_serializing_if = "Option::is_none")]
1028 pub filter: Option<serde_json::Value>,
1029 #[serde(default)]
1031 pub include_metadata: bool,
1032 #[serde(default)]
1034 pub consistency: ReadConsistency,
1035 #[serde(skip_serializing_if = "Option::is_none")]
1037 pub staleness_config: Option<StalenessConfig>,
1038}
1039
1040fn default_batch_top_k() -> u32 {
1041 10
1042}
1043
1044impl BatchQueryItem {
1045 pub fn new(vector: Vec<f32>, top_k: u32) -> Self {
1047 Self {
1048 id: None,
1049 vector,
1050 top_k,
1051 filter: None,
1052 include_metadata: true,
1053 consistency: ReadConsistency::default(),
1054 staleness_config: None,
1055 }
1056 }
1057
1058 pub fn with_id(mut self, id: impl Into<String>) -> Self {
1060 self.id = Some(id.into());
1061 self
1062 }
1063
1064 pub fn with_filter(mut self, filter: serde_json::Value) -> Self {
1066 self.filter = Some(filter);
1067 self
1068 }
1069
1070 pub fn include_metadata(mut self, include: bool) -> Self {
1072 self.include_metadata = include;
1073 self
1074 }
1075
1076 pub fn with_consistency(mut self, consistency: ReadConsistency) -> Self {
1078 self.consistency = consistency;
1079 self
1080 }
1081
1082 pub fn with_bounded_staleness(mut self, max_staleness_ms: u64) -> Self {
1084 self.consistency = ReadConsistency::BoundedStaleness;
1085 self.staleness_config = Some(StalenessConfig::new(max_staleness_ms));
1086 self
1087 }
1088}
1089
1090#[derive(Debug, Clone, Serialize, Deserialize)]
1092pub struct BatchQueryRequest {
1093 pub queries: Vec<BatchQueryItem>,
1095}
1096
1097impl BatchQueryRequest {
1098 pub fn new(queries: Vec<BatchQueryItem>) -> Self {
1100 Self { queries }
1101 }
1102
1103 pub fn single(query: BatchQueryItem) -> Self {
1105 Self {
1106 queries: vec![query],
1107 }
1108 }
1109}
1110
1111#[derive(Debug, Clone, Serialize, Deserialize)]
1113pub struct BatchQueryResult {
1114 #[serde(skip_serializing_if = "Option::is_none")]
1116 pub id: Option<String>,
1117 pub results: Vec<Match>,
1119 pub latency_ms: f64,
1121 #[serde(skip_serializing_if = "Option::is_none")]
1123 pub error: Option<String>,
1124}
1125
1126#[derive(Debug, Clone, Serialize, Deserialize)]
1128pub struct BatchQueryResponse {
1129 pub results: Vec<BatchQueryResult>,
1131 pub total_latency_ms: f64,
1133 pub query_count: usize,
1135}
1136
1137#[derive(Debug, Clone, Serialize, Deserialize)]
1143pub struct MultiVectorSearchRequest {
1144 pub positive_vectors: Vec<Vec<f32>>,
1146 #[serde(skip_serializing_if = "Option::is_none")]
1148 pub positive_weights: Option<Vec<f32>>,
1149 #[serde(skip_serializing_if = "Option::is_none")]
1151 pub negative_vectors: Option<Vec<Vec<f32>>>,
1152 #[serde(skip_serializing_if = "Option::is_none")]
1154 pub negative_weights: Option<Vec<f32>>,
1155 #[serde(default = "default_multi_vector_top_k")]
1157 pub top_k: u32,
1158 #[serde(default)]
1160 pub distance_metric: DistanceMetric,
1161 #[serde(skip_serializing_if = "Option::is_none")]
1163 pub score_threshold: Option<f32>,
1164 #[serde(default)]
1166 pub enable_mmr: bool,
1167 #[serde(default = "default_mmr_lambda")]
1169 pub mmr_lambda: f32,
1170 #[serde(default = "default_true")]
1172 pub include_metadata: bool,
1173 #[serde(default)]
1175 pub include_vectors: bool,
1176 #[serde(skip_serializing_if = "Option::is_none")]
1178 pub filter: Option<serde_json::Value>,
1179 #[serde(default)]
1181 pub consistency: ReadConsistency,
1182 #[serde(skip_serializing_if = "Option::is_none")]
1184 pub staleness_config: Option<StalenessConfig>,
1185}
1186
1187fn default_multi_vector_top_k() -> u32 {
1188 10
1189}
1190
1191fn default_mmr_lambda() -> f32 {
1192 0.5
1193}
1194
1195impl MultiVectorSearchRequest {
1196 pub fn new(positive_vectors: Vec<Vec<f32>>) -> Self {
1198 Self {
1199 positive_vectors,
1200 positive_weights: None,
1201 negative_vectors: None,
1202 negative_weights: None,
1203 top_k: 10,
1204 distance_metric: DistanceMetric::default(),
1205 score_threshold: None,
1206 enable_mmr: false,
1207 mmr_lambda: 0.5,
1208 include_metadata: true,
1209 include_vectors: false,
1210 filter: None,
1211 consistency: ReadConsistency::default(),
1212 staleness_config: None,
1213 }
1214 }
1215
1216 pub fn with_top_k(mut self, top_k: u32) -> Self {
1218 self.top_k = top_k;
1219 self
1220 }
1221
1222 pub fn with_positive_weights(mut self, weights: Vec<f32>) -> Self {
1224 self.positive_weights = Some(weights);
1225 self
1226 }
1227
1228 pub fn with_negative_vectors(mut self, vectors: Vec<Vec<f32>>) -> Self {
1230 self.negative_vectors = Some(vectors);
1231 self
1232 }
1233
1234 pub fn with_negative_weights(mut self, weights: Vec<f32>) -> Self {
1236 self.negative_weights = Some(weights);
1237 self
1238 }
1239
1240 pub fn with_distance_metric(mut self, metric: DistanceMetric) -> Self {
1242 self.distance_metric = metric;
1243 self
1244 }
1245
1246 pub fn with_score_threshold(mut self, threshold: f32) -> Self {
1248 self.score_threshold = Some(threshold);
1249 self
1250 }
1251
1252 pub fn with_mmr(mut self, lambda: f32) -> Self {
1254 self.enable_mmr = true;
1255 self.mmr_lambda = lambda.clamp(0.0, 1.0);
1256 self
1257 }
1258
1259 pub fn include_metadata(mut self, include: bool) -> Self {
1261 self.include_metadata = include;
1262 self
1263 }
1264
1265 pub fn include_vectors(mut self, include: bool) -> Self {
1267 self.include_vectors = include;
1268 self
1269 }
1270
1271 pub fn with_filter(mut self, filter: serde_json::Value) -> Self {
1273 self.filter = Some(filter);
1274 self
1275 }
1276
1277 pub fn with_consistency(mut self, consistency: ReadConsistency) -> Self {
1279 self.consistency = consistency;
1280 self
1281 }
1282}
1283
1284#[derive(Debug, Clone, Serialize, Deserialize)]
1286pub struct MultiVectorSearchResult {
1287 pub id: String,
1289 pub score: f32,
1291 #[serde(skip_serializing_if = "Option::is_none")]
1293 pub mmr_score: Option<f32>,
1294 #[serde(skip_serializing_if = "Option::is_none")]
1296 pub original_rank: Option<usize>,
1297 #[serde(skip_serializing_if = "Option::is_none")]
1299 pub metadata: Option<HashMap<String, serde_json::Value>>,
1300 #[serde(skip_serializing_if = "Option::is_none")]
1302 pub vector: Option<Vec<f32>>,
1303}
1304
1305#[derive(Debug, Clone, Serialize, Deserialize)]
1307pub struct MultiVectorSearchResponse {
1308 pub results: Vec<MultiVectorSearchResult>,
1310 #[serde(skip_serializing_if = "Option::is_none")]
1312 pub computed_query_vector: Option<Vec<f32>>,
1313}
1314
1315#[derive(Debug, Clone, Serialize, Deserialize)]
1321#[serde(untagged)]
1322pub enum AggregateFunction {
1323 Count,
1325 Sum { field: String },
1327 Avg { field: String },
1329 Min { field: String },
1331 Max { field: String },
1333}
1334
1335#[derive(Debug, Clone, Serialize, Deserialize)]
1337pub struct AggregationRequest {
1338 pub aggregate_by: HashMap<String, serde_json::Value>,
1341 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1344 pub group_by: Vec<String>,
1345 #[serde(skip_serializing_if = "Option::is_none")]
1347 pub filter: Option<serde_json::Value>,
1348 #[serde(default = "default_agg_limit")]
1350 pub limit: usize,
1351}
1352
1353fn default_agg_limit() -> usize {
1354 100
1355}
1356
1357impl AggregationRequest {
1358 pub fn new() -> Self {
1360 Self {
1361 aggregate_by: HashMap::new(),
1362 group_by: Vec::new(),
1363 filter: None,
1364 limit: 100,
1365 }
1366 }
1367
1368 pub fn with_count(mut self, name: impl Into<String>) -> Self {
1370 self.aggregate_by
1371 .insert(name.into(), serde_json::json!(["Count"]));
1372 self
1373 }
1374
1375 pub fn with_sum(mut self, name: impl Into<String>, field: impl Into<String>) -> Self {
1377 self.aggregate_by
1378 .insert(name.into(), serde_json::json!(["Sum", field.into()]));
1379 self
1380 }
1381
1382 pub fn with_avg(mut self, name: impl Into<String>, field: impl Into<String>) -> Self {
1384 self.aggregate_by
1385 .insert(name.into(), serde_json::json!(["Avg", field.into()]));
1386 self
1387 }
1388
1389 pub fn with_min(mut self, name: impl Into<String>, field: impl Into<String>) -> Self {
1391 self.aggregate_by
1392 .insert(name.into(), serde_json::json!(["Min", field.into()]));
1393 self
1394 }
1395
1396 pub fn with_max(mut self, name: impl Into<String>, field: impl Into<String>) -> Self {
1398 self.aggregate_by
1399 .insert(name.into(), serde_json::json!(["Max", field.into()]));
1400 self
1401 }
1402
1403 pub fn group_by(mut self, fields: Vec<String>) -> Self {
1405 self.group_by = fields;
1406 self
1407 }
1408
1409 pub fn with_group_by(mut self, field: impl Into<String>) -> Self {
1411 self.group_by.push(field.into());
1412 self
1413 }
1414
1415 pub fn with_filter(mut self, filter: serde_json::Value) -> Self {
1417 self.filter = Some(filter);
1418 self
1419 }
1420
1421 pub fn with_limit(mut self, limit: usize) -> Self {
1423 self.limit = limit;
1424 self
1425 }
1426}
1427
1428impl Default for AggregationRequest {
1429 fn default() -> Self {
1430 Self::new()
1431 }
1432}
1433
1434#[derive(Debug, Clone, Serialize, Deserialize)]
1436pub struct AggregationResponse {
1437 #[serde(skip_serializing_if = "Option::is_none")]
1439 pub aggregations: Option<HashMap<String, serde_json::Value>>,
1440 #[serde(skip_serializing_if = "Option::is_none")]
1442 pub aggregation_groups: Option<Vec<AggregationGroup>>,
1443}
1444
1445#[derive(Debug, Clone, Serialize, Deserialize)]
1447pub struct AggregationGroup {
1448 #[serde(flatten)]
1450 pub group_key: HashMap<String, serde_json::Value>,
1451 #[serde(flatten)]
1453 pub aggregations: HashMap<String, serde_json::Value>,
1454}
1455
1456#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
1462pub enum VectorSearchMethod {
1463 #[default]
1465 ANN,
1466 #[serde(rename = "kNN")]
1468 KNN,
1469}
1470
1471#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
1473#[serde(rename_all = "lowercase")]
1474pub enum SortDirection {
1475 Asc,
1477 #[default]
1479 Desc,
1480}
1481
1482#[derive(Debug, Clone, Serialize, Deserialize)]
1485#[serde(untagged)]
1486pub enum RankBy {
1487 VectorSearch {
1489 field: String,
1490 method: VectorSearchMethod,
1491 query_vector: Vec<f32>,
1492 },
1493 FullTextSearch {
1495 field: String,
1496 method: String, query: String,
1498 },
1499 AttributeOrder {
1501 field: String,
1502 direction: SortDirection,
1503 },
1504 Sum(Vec<RankBy>),
1506 Max(Vec<RankBy>),
1508 Product { weight: f32, ranking: Box<RankBy> },
1510}
1511
1512impl RankBy {
1513 pub fn vector_ann(field: impl Into<String>, query_vector: Vec<f32>) -> Self {
1515 RankBy::VectorSearch {
1516 field: field.into(),
1517 method: VectorSearchMethod::ANN,
1518 query_vector,
1519 }
1520 }
1521
1522 pub fn ann(query_vector: Vec<f32>) -> Self {
1524 Self::vector_ann("vector", query_vector)
1525 }
1526
1527 pub fn vector_knn(field: impl Into<String>, query_vector: Vec<f32>) -> Self {
1529 RankBy::VectorSearch {
1530 field: field.into(),
1531 method: VectorSearchMethod::KNN,
1532 query_vector,
1533 }
1534 }
1535
1536 pub fn knn(query_vector: Vec<f32>) -> Self {
1538 Self::vector_knn("vector", query_vector)
1539 }
1540
1541 pub fn bm25(field: impl Into<String>, query: impl Into<String>) -> Self {
1543 RankBy::FullTextSearch {
1544 field: field.into(),
1545 method: "BM25".to_string(),
1546 query: query.into(),
1547 }
1548 }
1549
1550 pub fn asc(field: impl Into<String>) -> Self {
1552 RankBy::AttributeOrder {
1553 field: field.into(),
1554 direction: SortDirection::Asc,
1555 }
1556 }
1557
1558 pub fn desc(field: impl Into<String>) -> Self {
1560 RankBy::AttributeOrder {
1561 field: field.into(),
1562 direction: SortDirection::Desc,
1563 }
1564 }
1565
1566 pub fn sum(rankings: Vec<RankBy>) -> Self {
1568 RankBy::Sum(rankings)
1569 }
1570
1571 pub fn max(rankings: Vec<RankBy>) -> Self {
1573 RankBy::Max(rankings)
1574 }
1575
1576 pub fn product(weight: f32, ranking: RankBy) -> Self {
1578 RankBy::Product {
1579 weight,
1580 ranking: Box::new(ranking),
1581 }
1582 }
1583}
1584
1585#[derive(Debug, Clone, Serialize, Deserialize)]
1603pub struct UnifiedQueryRequest {
1604 pub rank_by: serde_json::Value,
1606 #[serde(default = "default_unified_top_k")]
1608 pub top_k: usize,
1609 #[serde(skip_serializing_if = "Option::is_none")]
1611 pub filter: Option<serde_json::Value>,
1612 #[serde(default = "default_true")]
1614 pub include_metadata: bool,
1615 #[serde(default)]
1617 pub include_vectors: bool,
1618 #[serde(default)]
1620 pub distance_metric: DistanceMetric,
1621}
1622
1623fn default_unified_top_k() -> usize {
1624 10
1625}
1626
1627impl UnifiedQueryRequest {
1628 pub fn vector_search(query_vector: Vec<f32>, top_k: usize) -> Self {
1630 Self {
1631 rank_by: serde_json::json!(["ANN", query_vector]),
1632 top_k,
1633 filter: None,
1634 include_metadata: true,
1635 include_vectors: false,
1636 distance_metric: DistanceMetric::default(),
1637 }
1638 }
1639
1640 pub fn vector_knn_search(query_vector: Vec<f32>, top_k: usize) -> Self {
1642 Self {
1643 rank_by: serde_json::json!(["kNN", query_vector]),
1644 top_k,
1645 filter: None,
1646 include_metadata: true,
1647 include_vectors: false,
1648 distance_metric: DistanceMetric::default(),
1649 }
1650 }
1651
1652 pub fn fulltext_search(
1654 field: impl Into<String>,
1655 query: impl Into<String>,
1656 top_k: usize,
1657 ) -> Self {
1658 Self {
1659 rank_by: serde_json::json!([field.into(), "BM25", query.into()]),
1660 top_k,
1661 filter: None,
1662 include_metadata: true,
1663 include_vectors: false,
1664 distance_metric: DistanceMetric::default(),
1665 }
1666 }
1667
1668 pub fn attribute_order(
1670 field: impl Into<String>,
1671 direction: SortDirection,
1672 top_k: usize,
1673 ) -> Self {
1674 let dir = match direction {
1675 SortDirection::Asc => "asc",
1676 SortDirection::Desc => "desc",
1677 };
1678 Self {
1679 rank_by: serde_json::json!([field.into(), dir]),
1680 top_k,
1681 filter: None,
1682 include_metadata: true,
1683 include_vectors: false,
1684 distance_metric: DistanceMetric::default(),
1685 }
1686 }
1687
1688 pub fn with_rank_by(rank_by: serde_json::Value, top_k: usize) -> Self {
1690 Self {
1691 rank_by,
1692 top_k,
1693 filter: None,
1694 include_metadata: true,
1695 include_vectors: false,
1696 distance_metric: DistanceMetric::default(),
1697 }
1698 }
1699
1700 pub fn with_filter(mut self, filter: serde_json::Value) -> Self {
1702 self.filter = Some(filter);
1703 self
1704 }
1705
1706 pub fn include_metadata(mut self, include: bool) -> Self {
1708 self.include_metadata = include;
1709 self
1710 }
1711
1712 pub fn include_vectors(mut self, include: bool) -> Self {
1714 self.include_vectors = include;
1715 self
1716 }
1717
1718 pub fn with_distance_metric(mut self, metric: DistanceMetric) -> Self {
1720 self.distance_metric = metric;
1721 self
1722 }
1723
1724 pub fn with_top_k(mut self, top_k: usize) -> Self {
1726 self.top_k = top_k;
1727 self
1728 }
1729}
1730
1731#[derive(Debug, Clone, Serialize, Deserialize)]
1733pub struct UnifiedSearchResult {
1734 pub id: String,
1736 #[serde(rename = "$dist", skip_serializing_if = "Option::is_none")]
1739 pub dist: Option<f32>,
1740 #[serde(skip_serializing_if = "Option::is_none")]
1742 pub metadata: Option<serde_json::Value>,
1743 #[serde(skip_serializing_if = "Option::is_none")]
1745 pub vector: Option<Vec<f32>>,
1746}
1747
1748#[derive(Debug, Clone, Serialize, Deserialize)]
1750pub struct UnifiedQueryResponse {
1751 pub results: Vec<UnifiedSearchResult>,
1753 #[serde(skip_serializing_if = "Option::is_none")]
1755 pub next_cursor: Option<String>,
1756}
1757
1758fn default_explain_top_k() -> usize {
1763 10
1764}
1765
1766#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1768#[serde(rename_all = "snake_case")]
1769#[derive(Default)]
1770pub enum ExplainQueryType {
1771 #[default]
1773 VectorSearch,
1774 FullTextSearch,
1776 HybridSearch,
1778 MultiVector,
1780 BatchQuery,
1782}
1783
1784#[derive(Debug, Clone, Serialize, Deserialize)]
1786pub struct QueryExplainRequest {
1787 #[serde(default)]
1789 pub query_type: ExplainQueryType,
1790 #[serde(skip_serializing_if = "Option::is_none")]
1792 pub vector: Option<Vec<f32>>,
1793 #[serde(default = "default_explain_top_k")]
1795 pub top_k: usize,
1796 #[serde(skip_serializing_if = "Option::is_none")]
1798 pub filter: Option<serde_json::Value>,
1799 #[serde(skip_serializing_if = "Option::is_none")]
1801 pub text_query: Option<String>,
1802 #[serde(default = "default_distance_metric")]
1804 pub distance_metric: String,
1805 #[serde(default)]
1807 pub execute: bool,
1808 #[serde(default)]
1810 pub verbose: bool,
1811}
1812
1813fn default_distance_metric() -> String {
1814 "cosine".to_string()
1815}
1816
1817impl QueryExplainRequest {
1818 pub fn vector_search(vector: Vec<f32>, top_k: usize) -> Self {
1820 Self {
1821 query_type: ExplainQueryType::VectorSearch,
1822 vector: Some(vector),
1823 top_k,
1824 filter: None,
1825 text_query: None,
1826 distance_metric: "cosine".to_string(),
1827 execute: false,
1828 verbose: false,
1829 }
1830 }
1831
1832 pub fn fulltext_search(text_query: impl Into<String>, top_k: usize) -> Self {
1834 Self {
1835 query_type: ExplainQueryType::FullTextSearch,
1836 vector: None,
1837 top_k,
1838 filter: None,
1839 text_query: Some(text_query.into()),
1840 distance_metric: "bm25".to_string(),
1841 execute: false,
1842 verbose: false,
1843 }
1844 }
1845
1846 pub fn hybrid_search(vector: Vec<f32>, text_query: impl Into<String>, top_k: usize) -> Self {
1848 Self {
1849 query_type: ExplainQueryType::HybridSearch,
1850 vector: Some(vector),
1851 top_k,
1852 filter: None,
1853 text_query: Some(text_query.into()),
1854 distance_metric: "hybrid".to_string(),
1855 execute: false,
1856 verbose: false,
1857 }
1858 }
1859
1860 pub fn with_filter(mut self, filter: serde_json::Value) -> Self {
1862 self.filter = Some(filter);
1863 self
1864 }
1865
1866 pub fn with_distance_metric(mut self, metric: impl Into<String>) -> Self {
1868 self.distance_metric = metric.into();
1869 self
1870 }
1871
1872 pub fn with_execution(mut self) -> Self {
1874 self.execute = true;
1875 self
1876 }
1877
1878 pub fn with_verbose(mut self) -> Self {
1880 self.verbose = true;
1881 self
1882 }
1883}
1884
1885#[derive(Debug, Clone, Serialize, Deserialize)]
1887pub struct ExecutionStage {
1888 pub name: String,
1890 pub description: String,
1892 pub order: u32,
1894 pub estimated_input: u64,
1896 pub estimated_output: u64,
1898 pub estimated_cost: f64,
1900 #[serde(default)]
1902 pub details: HashMap<String, serde_json::Value>,
1903}
1904
1905#[derive(Debug, Clone, Serialize, Deserialize)]
1907pub struct CostEstimate {
1908 pub total_cost: f64,
1910 pub estimated_time_ms: u64,
1912 pub estimated_memory_bytes: u64,
1914 pub estimated_io_ops: u64,
1916 #[serde(default)]
1918 pub cost_breakdown: HashMap<String, f64>,
1919 pub confidence: f64,
1921}
1922
1923#[derive(Debug, Clone, Serialize, Deserialize)]
1925pub struct ActualStats {
1926 pub execution_time_ms: u64,
1928 pub results_returned: usize,
1930 pub vectors_scanned: u64,
1932 pub vectors_after_filter: u64,
1934 pub index_lookups: u64,
1936 pub cache_hits: u64,
1938 pub cache_misses: u64,
1940 pub memory_used_bytes: u64,
1942}
1943
1944#[derive(Debug, Clone, Serialize, Deserialize)]
1946pub struct Recommendation {
1947 pub recommendation_type: String,
1949 pub priority: String,
1951 pub description: String,
1953 pub expected_improvement: String,
1955 pub implementation: String,
1957}
1958
1959#[derive(Debug, Clone, Serialize, Deserialize)]
1961pub struct IndexSelection {
1962 pub index_type: String,
1964 pub selection_reason: String,
1966 #[serde(default)]
1968 pub alternatives_considered: Vec<IndexAlternative>,
1969 #[serde(default)]
1971 pub index_config: HashMap<String, serde_json::Value>,
1972 pub index_stats: IndexStatistics,
1974}
1975
1976#[derive(Debug, Clone, Serialize, Deserialize)]
1978pub struct IndexAlternative {
1979 pub index_type: String,
1981 pub rejection_reason: String,
1983 pub estimated_cost: f64,
1985}
1986
1987#[derive(Debug, Clone, Serialize, Deserialize)]
1989pub struct IndexStatistics {
1990 pub vector_count: u64,
1992 pub dimension: usize,
1994 pub memory_bytes: u64,
1996 #[serde(skip_serializing_if = "Option::is_none")]
1998 pub build_time_ms: Option<u64>,
1999 #[serde(skip_serializing_if = "Option::is_none")]
2001 pub last_updated: Option<u64>,
2002}
2003
2004#[derive(Debug, Clone, Serialize, Deserialize)]
2006pub struct QueryParams {
2007 pub top_k: usize,
2009 pub has_filter: bool,
2011 pub filter_complexity: String,
2013 #[serde(skip_serializing_if = "Option::is_none")]
2015 pub vector_dimension: Option<usize>,
2016 pub distance_metric: String,
2018 #[serde(skip_serializing_if = "Option::is_none")]
2020 pub text_query_length: Option<usize>,
2021}
2022
2023#[derive(Debug, Clone, Serialize, Deserialize)]
2025pub struct QueryExplainResponse {
2026 pub query_type: ExplainQueryType,
2028 pub namespace: String,
2030 pub index_selection: IndexSelection,
2032 pub stages: Vec<ExecutionStage>,
2034 pub cost_estimate: CostEstimate,
2036 #[serde(skip_serializing_if = "Option::is_none")]
2038 pub actual_stats: Option<ActualStats>,
2039 #[serde(default)]
2041 pub recommendations: Vec<Recommendation>,
2042 pub summary: String,
2044 pub query_params: QueryParams,
2046}
2047
2048#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
2054#[serde(rename_all = "kebab-case")]
2055pub enum EmbeddingModel {
2056 #[default]
2058 BgeLarge,
2059 Minilm,
2061 BgeSmall,
2063 E5Small,
2065}
2066
2067#[derive(Debug, Clone, Serialize, Deserialize)]
2069pub struct TextDocument {
2070 pub id: String,
2072 pub text: String,
2074 #[serde(skip_serializing_if = "Option::is_none")]
2076 pub metadata: Option<HashMap<String, serde_json::Value>>,
2077 #[serde(skip_serializing_if = "Option::is_none")]
2079 pub ttl_seconds: Option<u64>,
2080}
2081
2082impl TextDocument {
2083 pub fn new(id: impl Into<String>, text: impl Into<String>) -> Self {
2085 Self {
2086 id: id.into(),
2087 text: text.into(),
2088 metadata: None,
2089 ttl_seconds: None,
2090 }
2091 }
2092
2093 pub fn with_metadata(mut self, metadata: HashMap<String, serde_json::Value>) -> Self {
2095 self.metadata = Some(metadata);
2096 self
2097 }
2098
2099 pub fn with_ttl(mut self, ttl_seconds: u64) -> Self {
2101 self.ttl_seconds = Some(ttl_seconds);
2102 self
2103 }
2104}
2105
2106#[derive(Debug, Clone, Serialize, Deserialize)]
2108pub struct UpsertTextRequest {
2109 pub documents: Vec<TextDocument>,
2111 #[serde(skip_serializing_if = "Option::is_none")]
2113 pub model: Option<EmbeddingModel>,
2114}
2115
2116impl UpsertTextRequest {
2117 pub fn new(documents: Vec<TextDocument>) -> Self {
2119 Self {
2120 documents,
2121 model: None,
2122 }
2123 }
2124
2125 pub fn with_model(mut self, model: EmbeddingModel) -> Self {
2127 self.model = Some(model);
2128 self
2129 }
2130}
2131
2132#[derive(Debug, Clone, Serialize, Deserialize)]
2134pub struct TextUpsertResponse {
2135 pub upserted_count: u64,
2137 pub tokens_processed: u64,
2139 pub model: EmbeddingModel,
2141 pub embedding_time_ms: u64,
2143}
2144
2145#[derive(Debug, Clone, Serialize, Deserialize)]
2147pub struct TextSearchResult {
2148 pub id: String,
2150 pub score: f32,
2152 #[serde(skip_serializing_if = "Option::is_none")]
2154 pub text: Option<String>,
2155 #[serde(skip_serializing_if = "Option::is_none")]
2157 pub metadata: Option<HashMap<String, serde_json::Value>>,
2158 #[serde(skip_serializing_if = "Option::is_none")]
2160 pub vector: Option<Vec<f32>>,
2161}
2162
2163#[derive(Debug, Clone, Serialize, Deserialize)]
2165pub struct QueryTextRequest {
2166 pub text: String,
2168 pub top_k: u32,
2170 #[serde(skip_serializing_if = "Option::is_none")]
2172 pub filter: Option<serde_json::Value>,
2173 pub include_text: bool,
2175 pub include_vectors: bool,
2177 #[serde(skip_serializing_if = "Option::is_none")]
2179 pub model: Option<EmbeddingModel>,
2180}
2181
2182impl QueryTextRequest {
2183 pub fn new(text: impl Into<String>, top_k: u32) -> Self {
2185 Self {
2186 text: text.into(),
2187 top_k,
2188 filter: None,
2189 include_text: true,
2190 include_vectors: false,
2191 model: None,
2192 }
2193 }
2194
2195 pub fn with_filter(mut self, filter: serde_json::Value) -> Self {
2197 self.filter = Some(filter);
2198 self
2199 }
2200
2201 pub fn include_text(mut self, include: bool) -> Self {
2203 self.include_text = include;
2204 self
2205 }
2206
2207 pub fn include_vectors(mut self, include: bool) -> Self {
2209 self.include_vectors = include;
2210 self
2211 }
2212
2213 pub fn with_model(mut self, model: EmbeddingModel) -> Self {
2215 self.model = Some(model);
2216 self
2217 }
2218}
2219
2220#[derive(Debug, Clone, Serialize, Deserialize)]
2222pub struct TextQueryResponse {
2223 pub results: Vec<TextSearchResult>,
2225 pub model: EmbeddingModel,
2227 pub embedding_time_ms: u64,
2229 pub search_time_ms: u64,
2231}
2232
2233#[derive(Debug, Clone, Serialize, Deserialize)]
2235pub struct BatchQueryTextRequest {
2236 pub queries: Vec<String>,
2238 pub top_k: u32,
2240 #[serde(skip_serializing_if = "Option::is_none")]
2242 pub filter: Option<serde_json::Value>,
2243 pub include_vectors: bool,
2245 #[serde(skip_serializing_if = "Option::is_none")]
2247 pub model: Option<EmbeddingModel>,
2248}
2249
2250impl BatchQueryTextRequest {
2251 pub fn new(queries: Vec<String>, top_k: u32) -> Self {
2253 Self {
2254 queries,
2255 top_k,
2256 filter: None,
2257 include_vectors: false,
2258 model: None,
2259 }
2260 }
2261}
2262
2263#[derive(Debug, Clone, Serialize, Deserialize)]
2265pub struct BatchQueryTextResponse {
2266 pub results: Vec<Vec<TextSearchResult>>,
2268 pub model: EmbeddingModel,
2270 pub embedding_time_ms: u64,
2272 pub search_time_ms: u64,
2274}
2275
2276#[derive(Debug, Clone, Serialize, Deserialize)]
2282pub struct FetchRequest {
2283 pub ids: Vec<String>,
2285 pub include_values: bool,
2287 pub include_metadata: bool,
2289}
2290
2291impl FetchRequest {
2292 pub fn new(ids: Vec<String>) -> Self {
2294 Self {
2295 ids,
2296 include_values: true,
2297 include_metadata: true,
2298 }
2299 }
2300}
2301
2302#[derive(Debug, Clone, Serialize, Deserialize)]
2304pub struct FetchResponse {
2305 pub vectors: Vec<Vector>,
2307}
2308
2309#[derive(Debug, Clone, Serialize, Deserialize, Default)]
2315pub struct CreateNamespaceRequest {
2316 #[serde(skip_serializing_if = "Option::is_none")]
2318 pub dimensions: Option<u32>,
2319 #[serde(skip_serializing_if = "Option::is_none")]
2321 pub index_type: Option<String>,
2322 #[serde(skip_serializing_if = "Option::is_none")]
2324 pub metadata: Option<HashMap<String, serde_json::Value>>,
2325}
2326
2327impl CreateNamespaceRequest {
2328 pub fn new() -> Self {
2330 Self::default()
2331 }
2332
2333 pub fn with_dimensions(mut self, dimensions: u32) -> Self {
2335 self.dimensions = Some(dimensions);
2336 self
2337 }
2338
2339 pub fn with_index_type(mut self, index_type: impl Into<String>) -> Self {
2341 self.index_type = Some(index_type.into());
2342 self
2343 }
2344}
2345
2346#[derive(Debug, Clone, Serialize, Deserialize)]
2351pub struct ConfigureNamespaceRequest {
2352 pub dimension: usize,
2354 #[serde(skip_serializing_if = "Option::is_none")]
2356 pub distance: Option<DistanceMetric>,
2357}
2358
2359impl ConfigureNamespaceRequest {
2360 pub fn new(dimension: usize) -> Self {
2362 Self {
2363 dimension,
2364 distance: None,
2365 }
2366 }
2367
2368 pub fn with_distance(mut self, distance: DistanceMetric) -> Self {
2370 self.distance = Some(distance);
2371 self
2372 }
2373}
2374
2375#[derive(Debug, Clone, Serialize, Deserialize)]
2377pub struct ConfigureNamespaceResponse {
2378 pub namespace: String,
2380 pub dimension: usize,
2382 pub distance: DistanceMetric,
2384 pub created: bool,
2386}
2387
2388#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
2394#[serde(rename_all = "snake_case")]
2395pub enum EdgeType {
2396 RelatedTo,
2398 SharesEntity,
2400 Precedes,
2402 #[default]
2404 LinkedBy,
2405}
2406
2407#[derive(Debug, Clone, Serialize, Deserialize)]
2409pub struct GraphEdge {
2410 pub id: String,
2412 pub source_id: String,
2414 pub target_id: String,
2416 pub edge_type: EdgeType,
2418 pub weight: f64,
2420 pub created_at: i64,
2422}
2423
2424#[derive(Debug, Clone, Serialize, Deserialize)]
2426pub struct GraphNode {
2427 pub memory_id: String,
2429 pub content_preview: String,
2431 pub importance: f64,
2433 pub depth: u32,
2435}
2436
2437#[derive(Debug, Clone, Serialize, Deserialize)]
2439pub struct MemoryGraph {
2440 pub root_id: String,
2442 pub depth: u32,
2444 pub nodes: Vec<GraphNode>,
2446 pub edges: Vec<GraphEdge>,
2448}
2449
2450#[derive(Debug, Clone, Serialize, Deserialize)]
2452pub struct GraphPath {
2453 pub source_id: String,
2455 pub target_id: String,
2457 pub path: Vec<String>,
2459 pub hops: i32,
2461 pub edges: Vec<GraphEdge>,
2463}
2464
2465#[derive(Debug, Clone, Serialize, Deserialize)]
2467pub struct GraphLinkRequest {
2468 pub target_id: String,
2470 pub edge_type: EdgeType,
2472}
2473
2474#[derive(Debug, Clone, Serialize, Deserialize)]
2476pub struct GraphLinkResponse {
2477 pub edge: GraphEdge,
2479}
2480
2481#[derive(Debug, Clone, Serialize, Deserialize)]
2483pub struct GraphExport {
2484 pub agent_id: String,
2486 pub format: String,
2488 pub data: String,
2490 pub node_count: u64,
2492 pub edge_count: u64,
2494}
2495
2496#[derive(Debug, Clone, Default)]
2498pub struct GraphOptions {
2499 pub depth: Option<u32>,
2501 pub types: Option<Vec<EdgeType>>,
2503}
2504
2505impl GraphOptions {
2506 pub fn new() -> Self {
2508 Self::default()
2509 }
2510
2511 pub fn depth(mut self, depth: u32) -> Self {
2513 self.depth = Some(depth);
2514 self
2515 }
2516
2517 pub fn types(mut self, types: Vec<EdgeType>) -> Self {
2519 self.types = Some(types);
2520 self
2521 }
2522}
2523
2524#[derive(Debug, Clone, Serialize, Deserialize, Default)]
2530pub struct NamespaceNerConfig {
2531 pub extract_entities: bool,
2532 #[serde(skip_serializing_if = "Option::is_none")]
2533 pub entity_types: Option<Vec<String>>,
2534}
2535
2536#[derive(Debug, Clone, Serialize, Deserialize)]
2538pub struct ExtractedEntity {
2539 pub entity_type: String,
2540 pub value: String,
2541 pub score: f64,
2542}
2543
2544#[derive(Debug, Clone, Serialize, Deserialize)]
2546pub struct EntityExtractionResponse {
2547 pub entities: Vec<ExtractedEntity>,
2548}
2549
2550#[derive(Debug, Clone, Serialize, Deserialize)]
2552pub struct MemoryEntitiesResponse {
2553 pub memory_id: String,
2554 pub entities: Vec<ExtractedEntity>,
2555}
2556
2557#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2569#[serde(rename_all = "lowercase")]
2570pub enum FeedbackSignal {
2571 Upvote,
2572 Downvote,
2573 Flag,
2574 Positive,
2575 Negative,
2576}
2577
2578#[derive(Debug, Clone, Serialize, Deserialize)]
2580pub struct FeedbackHistoryEntry {
2581 pub signal: FeedbackSignal,
2582 pub timestamp: u64,
2584 pub old_importance: f32,
2585 pub new_importance: f32,
2586}
2587
2588#[derive(Debug, Clone, Serialize, Deserialize)]
2590pub struct MemoryFeedbackBody {
2591 pub agent_id: String,
2592 pub signal: FeedbackSignal,
2593}
2594
2595#[derive(Debug, Clone, Serialize, Deserialize)]
2597pub struct MemoryImportancePatch {
2598 pub agent_id: String,
2599 pub importance: f32,
2600}
2601
2602#[derive(Debug, Clone, Serialize, Deserialize)]
2604pub struct FeedbackResponse {
2605 pub memory_id: String,
2606 pub new_importance: f32,
2608 pub signal: FeedbackSignal,
2609}
2610
2611#[derive(Debug, Clone, Serialize, Deserialize)]
2613pub struct FeedbackHistoryResponse {
2614 pub memory_id: String,
2615 pub entries: Vec<FeedbackHistoryEntry>,
2617}
2618
2619#[derive(Debug, Clone, Serialize, Deserialize)]
2621pub struct AgentFeedbackSummary {
2622 pub agent_id: String,
2623 pub upvotes: u64,
2624 pub downvotes: u64,
2625 pub flags: u64,
2626 pub total_feedback: u64,
2627 pub health_score: f32,
2629}
2630
2631#[derive(Debug, Clone, Serialize, Deserialize)]
2633pub struct FeedbackHealthResponse {
2634 pub agent_id: String,
2635 pub health_score: f32,
2637 pub memory_count: usize,
2638 pub avg_importance: f32,
2639}
2640
2641#[derive(Debug, Clone, Serialize, Deserialize)]
2647pub struct OdeEntity {
2648 pub text: String,
2650 pub label: String,
2652 pub start: usize,
2654 pub end: usize,
2656 pub score: f32,
2658}
2659
2660#[derive(Debug, Clone, Serialize, Deserialize)]
2662pub struct ExtractEntitiesRequest {
2663 pub content: String,
2665 pub agent_id: String,
2667 #[serde(skip_serializing_if = "Option::is_none")]
2669 pub memory_id: Option<String>,
2670 #[serde(skip_serializing_if = "Option::is_none")]
2673 pub entity_types: Option<Vec<String>>,
2674}
2675
2676#[derive(Debug, Clone, Serialize, Deserialize)]
2678pub struct ExtractEntitiesResponse {
2679 pub entities: Vec<OdeEntity>,
2681 pub model: String,
2683 pub processing_time_ms: u64,
2685}
2686
2687#[derive(Debug, Clone, Serialize, Deserialize)]
2693pub struct KgQueryResponse {
2694 pub agent_id: String,
2696 pub node_count: usize,
2698 pub edge_count: usize,
2700 pub edges: Vec<GraphEdge>,
2702}
2703
2704#[derive(Debug, Clone, Serialize, Deserialize)]
2706pub struct KgPathResponse {
2707 pub agent_id: String,
2709 pub from_id: String,
2711 pub to_id: String,
2713 pub hop_count: usize,
2715 pub path: Vec<String>,
2717}
2718
2719#[derive(Debug, Clone, Serialize, Deserialize)]
2721pub struct KgExportResponse {
2722 pub agent_id: String,
2724 pub format: String,
2726 pub node_count: usize,
2728 pub edge_count: usize,
2730 pub edges: Vec<GraphEdge>,
2732}
2733
2734#[derive(Debug, Clone, Serialize, Deserialize)]
2746pub struct MemoryPolicy {
2747 #[serde(skip_serializing_if = "Option::is_none")]
2750 pub working_ttl_seconds: Option<u64>,
2751 #[serde(skip_serializing_if = "Option::is_none")]
2753 pub episodic_ttl_seconds: Option<u64>,
2754 #[serde(skip_serializing_if = "Option::is_none")]
2756 pub semantic_ttl_seconds: Option<u64>,
2757 #[serde(skip_serializing_if = "Option::is_none")]
2759 pub procedural_ttl_seconds: Option<u64>,
2760
2761 #[serde(skip_serializing_if = "Option::is_none")]
2764 pub working_decay: Option<String>,
2765 #[serde(skip_serializing_if = "Option::is_none")]
2767 pub episodic_decay: Option<String>,
2768 #[serde(skip_serializing_if = "Option::is_none")]
2770 pub semantic_decay: Option<String>,
2771 #[serde(skip_serializing_if = "Option::is_none")]
2773 pub procedural_decay: Option<String>,
2774
2775 #[serde(skip_serializing_if = "Option::is_none")]
2779 pub spaced_repetition_factor: Option<f64>,
2780 #[serde(skip_serializing_if = "Option::is_none")]
2782 pub spaced_repetition_base_interval_seconds: Option<u64>,
2783
2784 #[serde(skip_serializing_if = "Option::is_none")]
2789 pub consolidation_enabled: Option<bool>,
2790 #[serde(skip_serializing_if = "Option::is_none")]
2793 pub consolidation_threshold: Option<f32>,
2794 #[serde(skip_serializing_if = "Option::is_none")]
2796 pub consolidation_interval_hours: Option<u32>,
2797 #[serde(skip_serializing_if = "Option::is_none")]
2802 pub consolidated_count: Option<u64>,
2803
2804 #[serde(skip_serializing_if = "Option::is_none")]
2807 pub rate_limit_enabled: Option<bool>,
2808 #[serde(skip_serializing_if = "Option::is_none")]
2810 pub rate_limit_stores_per_minute: Option<u32>,
2811 #[serde(skip_serializing_if = "Option::is_none")]
2813 pub rate_limit_recalls_per_minute: Option<u32>,
2814
2815 #[serde(skip_serializing_if = "Option::is_none")]
2822 pub dedup_on_store: Option<bool>,
2823 #[serde(skip_serializing_if = "Option::is_none")]
2828 pub dedup_threshold: Option<f32>,
2829}
2830
2831impl Default for MemoryPolicy {
2832 fn default() -> Self {
2833 Self {
2834 working_ttl_seconds: Some(14_400),
2835 episodic_ttl_seconds: Some(2_592_000),
2836 semantic_ttl_seconds: Some(31_536_000),
2837 procedural_ttl_seconds: Some(63_072_000),
2838 working_decay: Some("exponential".to_string()),
2839 episodic_decay: Some("power_law".to_string()),
2840 semantic_decay: Some("logarithmic".to_string()),
2841 procedural_decay: Some("flat".to_string()),
2842 spaced_repetition_factor: Some(1.0),
2843 spaced_repetition_base_interval_seconds: Some(86_400),
2844 consolidation_enabled: Some(false),
2845 consolidation_threshold: Some(0.92),
2846 consolidation_interval_hours: Some(24),
2847 consolidated_count: Some(0),
2848 rate_limit_enabled: Some(false),
2849 rate_limit_stores_per_minute: None,
2850 rate_limit_recalls_per_minute: None,
2851 dedup_on_store: Some(false),
2852 dedup_threshold: Some(0.92),
2853 }
2854 }
2855}