1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3use serde_json::Value;
4use locus_core_rs::domain::models::{AvecState, PsiRange, SttpNode};
5
6use crate::application::memory_composition::{
7 CompositeInputItem, CompositeNodeFromTextOptions, CompositeNodeFromTextRequest,
8 CompositeNodeFromTextResult, CompositeRole, CompositeRoleAvecOverrides,
9 MemoryDailyRollupRequest, MemoryRecallWithExplainResult, MemoryTransformThenRecallRequest,
10 MemoryTransformThenRecallResult,
11};
12use crate::domain::memory::{
13 FallbackPolicy, MemoryAggregateRequest, MemoryAggregateResult, MemoryExplainRequest,
14 MemoryExplainResult, MemoryFilter,
15 MemoryFindRequest, MemoryFindResult, MemoryGroupBy, MemoryPage, MemoryRecallRequest,
16 MemoryRecallResult, MemorySchemaResult, MemoryScope, MemoryScoring, MemorySort,
17 MemoryTransformOperation,
18 MemoryTransformRequest, MemoryTransformResult, MetricRange, NumericStats, RetrievalPath,
19 StrictnessMode,
20};
21
22#[derive(Debug, Clone, Serialize, Deserialize)]
23#[serde(rename_all = "camelCase")]
24pub struct AvecStateDto {
25 pub stability: f32,
26 pub friction: f32,
27 pub logic: f32,
28 pub autonomy: f32,
29 pub psi: f32,
30}
31
32impl From<AvecStateDto> for AvecState {
33 fn from(value: AvecStateDto) -> Self {
34 Self {
35 stability: value.stability,
36 friction: value.friction,
37 logic: value.logic,
38 autonomy: value.autonomy,
39 }
40 }
41}
42
43impl From<AvecState> for AvecStateDto {
44 fn from(value: AvecState) -> Self {
45 Self {
46 stability: value.stability,
47 friction: value.friction,
48 logic: value.logic,
49 autonomy: value.autonomy,
50 psi: value.psi(),
51 }
52 }
53}
54
55#[derive(Debug, Clone, Serialize, Deserialize)]
56#[serde(rename_all = "camelCase")]
57pub struct PsiRangeDto {
58 pub min: f32,
59 pub max: f32,
60 pub average: f32,
61}
62
63impl From<PsiRange> for PsiRangeDto {
64 fn from(value: PsiRange) -> Self {
65 Self {
66 min: value.min,
67 max: value.max,
68 average: value.average,
69 }
70 }
71}
72
73#[derive(Debug, Clone, Serialize, Deserialize)]
74#[serde(rename_all = "camelCase")]
75pub struct MemoryScopeDto {
76 pub tenant_id: Option<String>,
77 pub session_ids: Option<Vec<String>>,
78 pub tiers: Option<Vec<String>>,
79 pub from_utc: Option<DateTime<Utc>>,
80 pub to_utc: Option<DateTime<Utc>>,
81}
82
83impl From<MemoryScopeDto> for MemoryScope {
84 fn from(value: MemoryScopeDto) -> Self {
85 Self {
86 tenant_id: value.tenant_id,
87 session_ids: value.session_ids,
88 tiers: value.tiers,
89 from_utc: value.from_utc,
90 to_utc: value.to_utc,
91 }
92 }
93}
94
95impl From<MemoryScope> for MemoryScopeDto {
96 fn from(value: MemoryScope) -> Self {
97 Self {
98 tenant_id: value.tenant_id,
99 session_ids: value.session_ids,
100 tiers: value.tiers,
101 from_utc: value.from_utc,
102 to_utc: value.to_utc,
103 }
104 }
105}
106
107#[derive(Debug, Clone, Serialize, Deserialize)]
108#[serde(rename_all = "camelCase")]
109pub struct MemoryFilterDto {
110 pub has_embedding: Option<bool>,
111 pub embedding_model: Option<String>,
112 pub psi: Option<MetricRange>,
113 pub rho: Option<MetricRange>,
114 pub kappa: Option<MetricRange>,
115 pub text_contains: Option<String>,
116}
117
118impl From<MemoryFilterDto> for MemoryFilter {
119 fn from(value: MemoryFilterDto) -> Self {
120 Self {
121 has_embedding: value.has_embedding,
122 embedding_model: value.embedding_model,
123 psi: value.psi,
124 rho: value.rho,
125 kappa: value.kappa,
126 text_contains: value.text_contains,
127 }
128 }
129}
130
131impl From<MemoryFilter> for MemoryFilterDto {
132 fn from(value: MemoryFilter) -> Self {
133 Self {
134 has_embedding: value.has_embedding,
135 embedding_model: value.embedding_model,
136 psi: value.psi,
137 rho: value.rho,
138 kappa: value.kappa,
139 text_contains: value.text_contains,
140 }
141 }
142}
143
144#[derive(Debug, Clone, Serialize, Deserialize)]
145#[serde(rename_all = "camelCase")]
146pub struct MemoryPageDto {
147 pub limit: usize,
148 pub cursor: Option<String>,
149}
150
151impl From<MemoryPageDto> for MemoryPage {
152 fn from(value: MemoryPageDto) -> Self {
153 Self {
154 limit: value.limit,
155 cursor: value.cursor,
156 }
157 }
158}
159
160impl From<MemoryPage> for MemoryPageDto {
161 fn from(value: MemoryPage) -> Self {
162 Self {
163 limit: value.limit,
164 cursor: value.cursor,
165 }
166 }
167}
168
169#[derive(Debug, Clone, Serialize, Deserialize)]
170#[serde(rename_all = "camelCase")]
171pub struct MemoryScoringDto {
172 pub resonance_weight: f32,
173 pub semantic_weight: f32,
174 pub lexical_weight: f32,
175 pub alpha: f32,
176 pub beta: f32,
177 pub fallback_policy: FallbackPolicy,
178 pub strictness: StrictnessMode,
179}
180
181impl From<MemoryScoringDto> for MemoryScoring {
182 fn from(value: MemoryScoringDto) -> Self {
183 Self {
184 resonance_weight: value.resonance_weight,
185 semantic_weight: value.semantic_weight,
186 lexical_weight: value.lexical_weight,
187 alpha: value.alpha,
188 beta: value.beta,
189 fallback_policy: value.fallback_policy,
190 strictness: value.strictness,
191 }
192 }
193}
194
195impl From<MemoryScoring> for MemoryScoringDto {
196 fn from(value: MemoryScoring) -> Self {
197 Self {
198 resonance_weight: value.resonance_weight,
199 semantic_weight: value.semantic_weight,
200 lexical_weight: value.lexical_weight,
201 alpha: value.alpha,
202 beta: value.beta,
203 fallback_policy: value.fallback_policy,
204 strictness: value.strictness,
205 }
206 }
207}
208
209#[derive(Debug, Clone, Serialize, Deserialize)]
210#[serde(rename_all = "camelCase")]
211pub struct MemoryFindRequestDto {
212 pub scope: MemoryScopeDto,
213 pub filter: MemoryFilterDto,
214 pub page: MemoryPageDto,
215 pub sort: MemorySort,
216}
217
218impl From<MemoryFindRequestDto> for MemoryFindRequest {
219 fn from(value: MemoryFindRequestDto) -> Self {
220 Self {
221 scope: value.scope.into(),
222 filter: value.filter.into(),
223 page: value.page.into(),
224 sort: value.sort,
225 }
226 }
227}
228
229#[derive(Debug, Clone, Serialize, Deserialize)]
230#[serde(rename_all = "camelCase")]
231pub struct MemoryRecallRequestDto {
232 pub scope: MemoryScopeDto,
233 pub filter: MemoryFilterDto,
234 pub page: MemoryPageDto,
235 pub scoring: MemoryScoringDto,
236 pub current_avec: Option<AvecStateDto>,
237 pub query_text: Option<String>,
238 pub query_embedding: Option<Vec<f32>>,
239}
240
241impl From<MemoryRecallRequestDto> for MemoryRecallRequest {
242 fn from(value: MemoryRecallRequestDto) -> Self {
243 Self {
244 scope: value.scope.into(),
245 filter: value.filter.into(),
246 page: value.page.into(),
247 scoring: value.scoring.into(),
248 current_avec: value.current_avec.map(Into::into),
249 query_text: value.query_text,
250 query_embedding: value.query_embedding,
251 }
252 }
253}
254
255#[derive(Debug, Clone, Serialize)]
256#[serde(rename_all = "camelCase")]
257pub struct MemoryNodeDto {
258 pub raw: String,
259 pub session_id: String,
260 pub tier: String,
261 pub timestamp: DateTime<Utc>,
262 pub compression_depth: i32,
263 pub parent_node_id: Option<String>,
264 pub sync_key: String,
265 pub context_summary: Option<String>,
266 pub embedding_model: Option<String>,
267 pub embedding_dimensions: Option<usize>,
268 pub embedded_at: Option<DateTime<Utc>>,
269 pub rho: f32,
270 pub kappa: f32,
271 pub psi: f32,
272 pub user_avec: AvecStateDto,
273 pub model_avec: AvecStateDto,
274 pub compression_avec: Option<AvecStateDto>,
275 pub updated_at: DateTime<Utc>,
276}
277
278impl From<SttpNode> for MemoryNodeDto {
279 fn from(value: SttpNode) -> Self {
280 Self {
281 raw: value.raw,
282 session_id: value.session_id,
283 tier: value.tier,
284 timestamp: value.timestamp,
285 compression_depth: value.compression_depth,
286 parent_node_id: value.parent_node_id,
287 sync_key: value.sync_key,
288 context_summary: value.context_summary,
289 embedding_model: value.embedding_model,
290 embedding_dimensions: value.embedding_dimensions,
291 embedded_at: value.embedded_at,
292 rho: value.rho,
293 kappa: value.kappa,
294 psi: value.psi,
295 user_avec: value.user_avec.into(),
296 model_avec: value.model_avec.into(),
297 compression_avec: value.compression_avec.map(Into::into),
298 updated_at: value.updated_at,
299 }
300 }
301}
302
303#[derive(Debug, Clone, Serialize)]
304#[serde(rename_all = "camelCase")]
305pub struct MemoryFindResponseDto {
306 pub nodes: Vec<MemoryNodeDto>,
307 pub retrieved: usize,
308 pub has_more: bool,
309 pub next_cursor: Option<String>,
310}
311
312impl From<MemoryFindResult> for MemoryFindResponseDto {
313 fn from(value: MemoryFindResult) -> Self {
314 Self {
315 nodes: value.nodes.into_iter().map(Into::into).collect(),
316 retrieved: value.retrieved,
317 has_more: value.has_more,
318 next_cursor: value.next_cursor,
319 }
320 }
321}
322
323#[derive(Debug, Clone, Serialize)]
324#[serde(rename_all = "camelCase")]
325pub struct MemoryRecallResponseDto {
326 pub nodes: Vec<MemoryNodeDto>,
327 pub retrieved: usize,
328 pub psi_range: PsiRangeDto,
329 pub retrieval_path: RetrievalPath,
330 pub has_more: bool,
331 pub next_cursor: Option<String>,
332}
333
334impl From<MemoryRecallResult> for MemoryRecallResponseDto {
335 fn from(value: MemoryRecallResult) -> Self {
336 Self {
337 nodes: value.nodes.into_iter().map(Into::into).collect(),
338 retrieved: value.retrieved,
339 psi_range: value.psi_range.into(),
340 retrieval_path: value.retrieval_path,
341 has_more: value.has_more,
342 next_cursor: value.next_cursor,
343 }
344 }
345}
346
347#[derive(Debug, Clone, Serialize, Deserialize)]
348#[serde(rename_all = "camelCase")]
349pub struct NumericStatsDto {
350 pub min: f32,
351 pub max: f32,
352 pub average: f32,
353}
354
355impl From<NumericStats> for NumericStatsDto {
356 fn from(value: NumericStats) -> Self {
357 Self {
358 min: value.min,
359 max: value.max,
360 average: value.average,
361 }
362 }
363}
364
365#[derive(Debug, Clone, Serialize, Deserialize)]
366#[serde(rename_all = "camelCase")]
367pub struct MemoryAggregateRequestDto {
368 pub scope: MemoryScopeDto,
369 pub filter: MemoryFilterDto,
370 pub group_by: MemoryGroupBy,
371 pub max_groups: usize,
372 pub max_nodes: usize,
373}
374
375impl From<MemoryAggregateRequestDto> for MemoryAggregateRequest {
376 fn from(value: MemoryAggregateRequestDto) -> Self {
377 Self {
378 scope: value.scope.into(),
379 filter: value.filter.into(),
380 group_by: value.group_by,
381 max_groups: value.max_groups,
382 max_nodes: value.max_nodes,
383 }
384 }
385}
386
387#[derive(Debug, Clone, Serialize)]
388#[serde(rename_all = "camelCase")]
389pub struct MemoryAggregateGroupDto {
390 pub key: String,
391 pub node_count: usize,
392 pub embedding_coverage: f32,
393 pub avg_user_avec: AvecStateDto,
394 pub avg_model_avec: AvecStateDto,
395 pub avg_compression_avec: Option<AvecStateDto>,
396 pub psi_stats: NumericStatsDto,
397 pub rho_stats: NumericStatsDto,
398 pub kappa_stats: NumericStatsDto,
399}
400
401#[derive(Debug, Clone, Serialize)]
402#[serde(rename_all = "camelCase")]
403pub struct MemoryAggregateResponseDto {
404 pub groups: Vec<MemoryAggregateGroupDto>,
405 pub total_groups: usize,
406 pub scanned_nodes: usize,
407}
408
409impl From<MemoryAggregateResult> for MemoryAggregateResponseDto {
410 fn from(value: MemoryAggregateResult) -> Self {
411 Self {
412 groups: value
413 .groups
414 .into_iter()
415 .map(|group| MemoryAggregateGroupDto {
416 key: group.key,
417 node_count: group.node_count,
418 embedding_coverage: group.embedding_coverage,
419 avg_user_avec: group.avg_user_avec.into(),
420 avg_model_avec: group.avg_model_avec.into(),
421 avg_compression_avec: group.avg_compression_avec.map(Into::into),
422 psi_stats: group.psi_stats.into(),
423 rho_stats: group.rho_stats.into(),
424 kappa_stats: group.kappa_stats.into(),
425 })
426 .collect(),
427 total_groups: value.total_groups,
428 scanned_nodes: value.scanned_nodes,
429 }
430 }
431}
432
433#[derive(Debug, Clone, Serialize, Deserialize)]
434#[serde(rename_all = "camelCase")]
435pub struct MemoryTransformRequestDto {
436 pub scope: MemoryScopeDto,
437 pub filter: MemoryFilterDto,
438 pub operation: MemoryTransformOperation,
439 pub dry_run: bool,
440 pub batch_size: usize,
441 pub max_nodes: usize,
442 pub provider_id: Option<String>,
443 pub model: Option<String>,
444}
445
446impl From<MemoryTransformRequestDto> for MemoryTransformRequest {
447 fn from(value: MemoryTransformRequestDto) -> Self {
448 Self {
449 scope: value.scope.into(),
450 filter: value.filter.into(),
451 operation: value.operation,
452 dry_run: value.dry_run,
453 batch_size: value.batch_size,
454 max_nodes: value.max_nodes,
455 provider_id: value.provider_id,
456 model: value.model,
457 }
458 }
459}
460
461#[derive(Debug, Clone, Serialize)]
462#[serde(rename_all = "camelCase")]
463pub struct MemoryTransformResponseDto {
464 pub scanned: usize,
465 pub selected: usize,
466 pub updated: usize,
467 pub skipped: usize,
468 pub failed: usize,
469 pub duplicate: usize,
470 pub started_at: DateTime<Utc>,
471 pub completed_at: DateTime<Utc>,
472 pub failures: Vec<String>,
473}
474
475impl From<MemoryTransformResult> for MemoryTransformResponseDto {
476 fn from(value: MemoryTransformResult) -> Self {
477 Self {
478 scanned: value.scanned,
479 selected: value.selected,
480 updated: value.updated,
481 skipped: value.skipped,
482 failed: value.failed,
483 duplicate: value.duplicate,
484 started_at: value.started_at,
485 completed_at: value.completed_at,
486 failures: value.failures,
487 }
488 }
489}
490
491#[derive(Debug, Clone, Serialize, Deserialize)]
492#[serde(rename_all = "camelCase")]
493pub struct MemoryDailyRollupRequestDto {
494 pub scope: MemoryScopeDto,
495 pub filter: MemoryFilterDto,
496 pub max_days: usize,
497 pub max_nodes: usize,
498}
499
500impl From<MemoryDailyRollupRequestDto> for MemoryDailyRollupRequest {
501 fn from(value: MemoryDailyRollupRequestDto) -> Self {
502 Self {
503 scope: value.scope.into(),
504 filter: value.filter.into(),
505 max_days: value.max_days,
506 max_nodes: value.max_nodes,
507 }
508 }
509}
510
511#[derive(Debug, Clone, Serialize)]
512#[serde(rename_all = "camelCase")]
513pub struct MemoryRecallWithExplainResponseDto {
514 pub recall: MemoryRecallResponseDto,
515 pub explain: MemoryExplainResponseDto,
516}
517
518impl From<MemoryRecallWithExplainResult> for MemoryRecallWithExplainResponseDto {
519 fn from(value: MemoryRecallWithExplainResult) -> Self {
520 Self {
521 recall: value.recall.into(),
522 explain: value.explain.into(),
523 }
524 }
525}
526
527#[derive(Debug, Clone, Serialize, Deserialize)]
528#[serde(rename_all = "camelCase")]
529pub struct MemoryTransformThenRecallRequestDto {
530 pub transform: MemoryTransformRequestDto,
531 pub recall: MemoryRecallRequestDto,
532}
533
534impl From<MemoryTransformThenRecallRequestDto> for MemoryTransformThenRecallRequest {
535 fn from(value: MemoryTransformThenRecallRequestDto) -> Self {
536 Self {
537 transform: value.transform.into(),
538 recall: value.recall.into(),
539 }
540 }
541}
542
543#[derive(Debug, Clone, Serialize)]
544#[serde(rename_all = "camelCase")]
545pub struct MemoryTransformThenRecallResponseDto {
546 pub transform: MemoryTransformResponseDto,
547 pub recall: MemoryRecallResponseDto,
548}
549
550impl From<MemoryTransformThenRecallResult> for MemoryTransformThenRecallResponseDto {
551 fn from(value: MemoryTransformThenRecallResult) -> Self {
552 Self {
553 transform: value.transform.into(),
554 recall: value.recall.into(),
555 }
556 }
557}
558
559#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
560#[serde(rename_all = "snake_case")]
561pub enum CompositeRoleDto {
562 User,
563 Model,
564 Document,
565 Conversation,
566}
567
568impl From<CompositeRoleDto> for CompositeRole {
569 fn from(value: CompositeRoleDto) -> Self {
570 match value {
571 CompositeRoleDto::User => CompositeRole::User,
572 CompositeRoleDto::Model => CompositeRole::Model,
573 CompositeRoleDto::Document => CompositeRole::Document,
574 CompositeRoleDto::Conversation => CompositeRole::Conversation,
575 }
576 }
577}
578
579impl From<CompositeRole> for CompositeRoleDto {
580 fn from(value: CompositeRole) -> Self {
581 match value {
582 CompositeRole::User => CompositeRoleDto::User,
583 CompositeRole::Model => CompositeRoleDto::Model,
584 CompositeRole::Document => CompositeRoleDto::Document,
585 CompositeRole::Conversation => CompositeRoleDto::Conversation,
586 }
587 }
588}
589
590#[derive(Debug, Clone, Serialize, Deserialize)]
591#[serde(rename_all = "camelCase")]
592pub struct CompositeInputItemDto {
593 pub role: CompositeRoleDto,
594 pub text: String,
595 pub avec_override: Option<AvecStateDto>,
596 #[serde(default)]
597 pub context: Vec<CompositeInputItemDto>,
598}
599
600impl From<CompositeInputItemDto> for CompositeInputItem {
601 fn from(value: CompositeInputItemDto) -> Self {
602 Self {
603 role: value.role.into(),
604 text: value.text,
605 avec_override: value.avec_override.map(Into::into),
606 context: value.context.into_iter().map(Into::into).collect(),
607 }
608 }
609}
610
611impl From<CompositeInputItem> for CompositeInputItemDto {
612 fn from(value: CompositeInputItem) -> Self {
613 Self {
614 role: value.role.into(),
615 text: value.text,
616 avec_override: value.avec_override.map(Into::into),
617 context: value.context.into_iter().map(Into::into).collect(),
618 }
619 }
620}
621
622#[derive(Debug, Clone, Default, Serialize, Deserialize)]
623#[serde(rename_all = "camelCase")]
624pub struct CompositeRoleAvecOverridesDto {
625 pub user: Option<AvecStateDto>,
626 pub model: Option<AvecStateDto>,
627 pub document: Option<AvecStateDto>,
628 pub conversation: Option<AvecStateDto>,
629}
630
631impl From<CompositeRoleAvecOverridesDto> for CompositeRoleAvecOverrides {
632 fn from(value: CompositeRoleAvecOverridesDto) -> Self {
633 Self {
634 user: value.user.map(Into::into),
635 model: value.model.map(Into::into),
636 document: value.document.map(Into::into),
637 conversation: value.conversation.map(Into::into),
638 }
639 }
640}
641
642impl From<CompositeRoleAvecOverrides> for CompositeRoleAvecOverridesDto {
643 fn from(value: CompositeRoleAvecOverrides) -> Self {
644 Self {
645 user: value.user.map(Into::into),
646 model: value.model.map(Into::into),
647 document: value.document.map(Into::into),
648 conversation: value.conversation.map(Into::into),
649 }
650 }
651}
652
653#[derive(Debug, Clone, Serialize, Deserialize)]
654#[serde(rename_all = "camelCase")]
655pub struct CompositeNodeFromTextOptionsDto {
656 pub role_avec: CompositeRoleAvecOverridesDto,
657 pub global_avec: Option<AvecStateDto>,
658 pub allow_llm_avec_fallback: bool,
659 pub max_recursion_depth: usize,
660}
661
662impl From<CompositeNodeFromTextOptionsDto> for CompositeNodeFromTextOptions {
663 fn from(value: CompositeNodeFromTextOptionsDto) -> Self {
664 Self {
665 role_avec: value.role_avec.into(),
666 global_avec: value.global_avec.map(Into::into),
667 allow_llm_avec_fallback: value.allow_llm_avec_fallback,
668 max_recursion_depth: value.max_recursion_depth,
669 }
670 }
671}
672
673impl From<CompositeNodeFromTextOptions> for CompositeNodeFromTextOptionsDto {
674 fn from(value: CompositeNodeFromTextOptions) -> Self {
675 Self {
676 role_avec: value.role_avec.into(),
677 global_avec: value.global_avec.map(Into::into),
678 allow_llm_avec_fallback: value.allow_llm_avec_fallback,
679 max_recursion_depth: value.max_recursion_depth,
680 }
681 }
682}
683
684#[derive(Debug, Clone, Serialize, Deserialize)]
685#[serde(rename_all = "camelCase")]
686pub struct CompositeNodeFromTextRequestDto {
687 pub items: Vec<CompositeInputItemDto>,
688 pub options: CompositeNodeFromTextOptionsDto,
689}
690
691impl From<CompositeNodeFromTextRequestDto> for CompositeNodeFromTextRequest {
692 fn from(value: CompositeNodeFromTextRequestDto) -> Self {
693 Self {
694 items: value.items.into_iter().map(Into::into).collect(),
695 options: value.options.into(),
696 }
697 }
698}
699
700#[derive(Debug, Clone, Serialize)]
701#[serde(rename_all = "camelCase")]
702pub struct CompositeNodeFromTextResponseDto {
703 pub content: Value,
704 pub resolved_avec_count: usize,
705 pub unresolved_avec_count: usize,
706 pub requires_llm_avec: bool,
707}
708
709impl From<CompositeNodeFromTextResult> for CompositeNodeFromTextResponseDto {
710 fn from(value: CompositeNodeFromTextResult) -> Self {
711 Self {
712 content: value.content,
713 resolved_avec_count: value.resolved_avec_count,
714 unresolved_avec_count: value.unresolved_avec_count,
715 requires_llm_avec: value.requires_llm_avec,
716 }
717 }
718}
719
720#[derive(Debug, Clone, Serialize, Deserialize)]
721#[serde(rename_all = "camelCase")]
722pub struct MemoryExplainRequestDto {
723 pub recall: MemoryRecallRequestDto,
724}
725
726impl From<MemoryExplainRequestDto> for MemoryExplainRequest {
727 fn from(value: MemoryExplainRequestDto) -> Self {
728 Self {
729 recall: value.recall.into(),
730 }
731 }
732}
733
734#[derive(Debug, Clone, Serialize)]
735#[serde(rename_all = "camelCase")]
736pub struct MemoryExplainStageDto {
737 pub stage: String,
738 pub count: usize,
739}
740
741#[derive(Debug, Clone, Serialize)]
742#[serde(rename_all = "camelCase")]
743pub struct MemoryExplainResponseDto {
744 pub retrieval_path: RetrievalPath,
745 pub fallback_triggered: bool,
746 pub fallback_reason: Option<String>,
747 pub stages: Vec<MemoryExplainStageDto>,
748 pub scoring: MemoryScoringDto,
749}
750
751impl From<MemoryExplainResult> for MemoryExplainResponseDto {
752 fn from(value: MemoryExplainResult) -> Self {
753 Self {
754 retrieval_path: value.retrieval_path,
755 fallback_triggered: value.fallback_triggered,
756 fallback_reason: value.fallback_reason,
757 stages: value
758 .stages
759 .into_iter()
760 .map(|stage| MemoryExplainStageDto {
761 stage: stage.stage,
762 count: stage.count,
763 })
764 .collect(),
765 scoring: value.scoring.into(),
766 }
767 }
768}
769
770#[derive(Debug, Clone, Serialize)]
771#[serde(rename_all = "camelCase")]
772pub struct MemorySchemaResponseDto {
773 pub schema_version: String,
774 pub sort_fields: Vec<String>,
775 pub filter_fields: Vec<String>,
776 pub group_by_fields: Vec<String>,
777 pub fallback_policies: Vec<String>,
778 pub strictness_modes: Vec<String>,
779 pub transform_operations: Vec<String>,
780}
781
782impl From<MemorySchemaResult> for MemorySchemaResponseDto {
783 fn from(value: MemorySchemaResult) -> Self {
784 Self {
785 schema_version: value.schema_version,
786 sort_fields: value.sort_fields,
787 filter_fields: value.filter_fields,
788 group_by_fields: value.group_by_fields,
789 fallback_policies: value.fallback_policies,
790 strictness_modes: value.strictness_modes,
791 transform_operations: value.transform_operations,
792 }
793 }
794}