Skip to main content

locus_gateway/
http_models.rs

1use axum::Json;
2use axum::http::HeaderValue;
3use chrono::{DateTime, Utc};
4use locus_core_rs::SemanticLink;
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Serialize)]
8#[serde(rename_all = "camelCase")]
9pub(crate) struct ErrorResponse {
10    pub(crate) error: String,
11}
12
13#[derive(Debug, Deserialize)]
14#[serde(rename_all = "camelCase")]
15pub(crate) struct CalibrateSessionHttpRequest {
16    pub(crate) session_id: String,
17    pub(crate) tenant_id: Option<String>,
18    pub(crate) stability: f32,
19    pub(crate) friction: f32,
20    pub(crate) logic: f32,
21    pub(crate) autonomy: f32,
22    pub(crate) trigger: Option<String>,
23}
24
25#[derive(Debug, Deserialize)]
26#[serde(rename_all = "camelCase")]
27pub(crate) struct StoreContextHttpRequest {
28    pub(crate) node: String,
29    pub(crate) session_id: String,
30    pub(crate) tenant_id: Option<String>,
31}
32
33#[derive(Debug, Deserialize)]
34#[serde(rename_all = "camelCase")]
35pub(crate) struct ScoreAvecHttpRequest {
36    pub(crate) text: String,
37    pub(crate) tenant_id: Option<String>,
38}
39
40#[derive(Debug, Deserialize)]
41#[serde(rename_all = "camelCase")]
42pub(crate) struct GetContextHttpRequest {
43    pub(crate) session_id: String,
44    pub(crate) tenant_id: Option<String>,
45    pub(crate) stability: f32,
46    pub(crate) friction: f32,
47    pub(crate) logic: f32,
48    pub(crate) autonomy: f32,
49    pub(crate) limit: Option<usize>,
50    pub(crate) from_utc: Option<DateTime<Utc>>,
51    pub(crate) to_utc: Option<DateTime<Utc>>,
52    pub(crate) tiers: Option<Vec<String>>,
53    pub(crate) query_text: Option<String>,
54    pub(crate) query_embedding: Option<Vec<f32>>,
55    pub(crate) alpha: Option<f32>,
56    pub(crate) beta: Option<f32>,
57    pub(crate) gamma: Option<f32>,
58    pub(crate) semantic_tags: Option<Vec<String>>,
59    pub(crate) tags_contains: Option<Vec<String>>,
60    pub(crate) link_rel: Option<String>,
61    pub(crate) link_target: Option<String>,
62    pub(crate) links_to_ref: Option<String>,
63    pub(crate) tag_prefix: Option<String>,
64    pub(crate) has_semantic_links: Option<bool>,
65}
66
67#[derive(Debug, Deserialize)]
68#[serde(rename_all = "camelCase")]
69pub(crate) struct GetEmbeddingContextHttpRequest {
70    pub(crate) session_id: String,
71    pub(crate) tenant_id: Option<String>,
72    pub(crate) stability: f32,
73    pub(crate) friction: f32,
74    pub(crate) logic: f32,
75    pub(crate) autonomy: f32,
76    pub(crate) limit: Option<usize>,
77    pub(crate) from_utc: Option<DateTime<Utc>>,
78    pub(crate) to_utc: Option<DateTime<Utc>>,
79    pub(crate) tiers: Option<Vec<String>>,
80    pub(crate) rag_query_text: Option<String>,
81    pub(crate) rag_embedding: Option<Vec<f32>>,
82    pub(crate) avec_query_text: Option<String>,
83    pub(crate) avec_embedding: Option<Vec<f32>>,
84    pub(crate) rag_weight: Option<f32>,
85    pub(crate) avec_weight: Option<f32>,
86    pub(crate) alpha: Option<f32>,
87    pub(crate) beta: Option<f32>,
88    pub(crate) tag_weight: Option<f32>,
89    pub(crate) semantic_tags: Option<Vec<String>>,
90    pub(crate) link_rel: Option<String>,
91    pub(crate) link_target: Option<String>,
92}
93
94#[derive(Debug, Deserialize)]
95#[serde(rename_all = "camelCase")]
96pub(crate) struct CreateMonthlyRollupHttpRequest {
97    pub(crate) session_id: String,
98    pub(crate) tenant_id: Option<String>,
99    pub(crate) start_date_utc: DateTime<Utc>,
100    pub(crate) end_date_utc: DateTime<Utc>,
101    pub(crate) source_session_id: Option<String>,
102    pub(crate) parent_node_id: Option<String>,
103    pub(crate) persist: Option<bool>,
104    pub(crate) limit: Option<usize>,
105}
106
107#[derive(Debug, Deserialize)]
108#[serde(rename_all = "camelCase")]
109pub(crate) struct BatchRekeyHttpRequest {
110    pub(crate) node_ids: Vec<String>,
111    pub(crate) target_session_id: String,
112    pub(crate) target_tenant_id: Option<String>,
113    pub(crate) dry_run: Option<bool>,
114    pub(crate) allow_merge: Option<bool>,
115}
116
117#[derive(Debug, Clone, Deserialize)]
118#[serde(rename_all = "camelCase")]
119pub(crate) struct EmbeddingMigrationFilterHttp {
120    pub(crate) session_id: Option<String>,
121    pub(crate) from_utc: Option<DateTime<Utc>>,
122    pub(crate) to_utc: Option<DateTime<Utc>>,
123    pub(crate) tiers: Option<Vec<String>>,
124    pub(crate) has_embedding: Option<bool>,
125    pub(crate) embedding_model: Option<String>,
126    pub(crate) sync_keys: Option<Vec<String>>,
127}
128
129#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
130#[serde(rename_all = "snake_case")]
131pub(crate) enum EmbeddingMigrationModeHttp {
132    MissingOnly,
133    ReindexAll,
134    Tags,
135    Both,
136}
137
138#[derive(Debug, Deserialize)]
139#[serde(rename_all = "camelCase")]
140pub(crate) struct EmbeddingMigrationPreviewHttpRequest {
141    pub(crate) tenant_id: Option<String>,
142    pub(crate) filter: Option<EmbeddingMigrationFilterHttp>,
143    pub(crate) sample_limit: Option<usize>,
144    pub(crate) max_nodes: Option<usize>,
145}
146
147#[derive(Debug, Deserialize)]
148#[serde(rename_all = "camelCase")]
149pub(crate) struct EmbeddingMigrationRunHttpRequest {
150    pub(crate) tenant_id: Option<String>,
151    pub(crate) filter: Option<EmbeddingMigrationFilterHttp>,
152    pub(crate) mode: Option<EmbeddingMigrationModeHttp>,
153    pub(crate) dry_run: Option<bool>,
154    pub(crate) batch_size: Option<usize>,
155    pub(crate) max_nodes: Option<usize>,
156}
157
158#[derive(Debug, Deserialize)]
159#[serde(rename_all = "camelCase")]
160pub(crate) struct ListNodesQuery {
161    pub(crate) limit: Option<usize>,
162    pub(crate) session_id: Option<String>,
163    pub(crate) tenant_id: Option<String>,
164    pub(crate) semantic_tags: Option<Vec<String>>,
165    pub(crate) tags_contains: Option<Vec<String>>,
166    pub(crate) link_rel: Option<String>,
167    pub(crate) link_target: Option<String>,
168    pub(crate) links_to_ref: Option<String>,
169    pub(crate) tag_prefix: Option<String>,
170    pub(crate) has_semantic_links: Option<bool>,
171}
172
173#[derive(Debug, Deserialize)]
174#[serde(rename_all = "camelCase")]
175pub(crate) struct GetMoodsQuery {
176    pub(crate) target_mood: Option<String>,
177    pub(crate) blend: Option<f32>,
178    pub(crate) current_stability: Option<f32>,
179    pub(crate) current_friction: Option<f32>,
180    pub(crate) current_logic: Option<f32>,
181    pub(crate) current_autonomy: Option<f32>,
182}
183
184#[derive(Debug, Deserialize)]
185#[serde(rename_all = "camelCase")]
186pub(crate) struct GraphQuery {
187    pub(crate) limit: Option<usize>,
188    pub(crate) session_id: Option<String>,
189    pub(crate) tenant_id: Option<String>,
190    pub(crate) rel: Option<String>,
191    pub(crate) target_prefix: Option<String>,
192    pub(crate) semantic_tags: Option<Vec<String>>,
193    pub(crate) link_rel: Option<String>,
194    pub(crate) link_target: Option<String>,
195    pub(crate) links_to_ref: Option<String>,
196    pub(crate) tag_prefix: Option<String>,
197    pub(crate) has_semantic_links: Option<bool>,
198}
199
200#[derive(Debug, Deserialize)]
201#[serde(rename_all = "camelCase")]
202pub(crate) struct RenameSessionHttpRequest {
203    pub(crate) source_session_id: String,
204    pub(crate) target_session_id: String,
205    pub(crate) tenant_id: Option<String>,
206    pub(crate) allow_merge: Option<bool>,
207}
208
209#[derive(Debug, Serialize)]
210#[serde(rename_all = "camelCase")]
211pub(crate) struct AvecStateDto {
212    pub(crate) stability: f32,
213    pub(crate) friction: f32,
214    pub(crate) logic: f32,
215    pub(crate) autonomy: f32,
216    pub(crate) psi: f32,
217}
218
219#[derive(Debug, Serialize)]
220#[serde(rename_all = "camelCase")]
221pub(crate) struct SttpNodeDto {
222    pub(crate) raw: String,
223    pub(crate) session_id: String,
224    pub(crate) tier: String,
225    pub(crate) timestamp: DateTime<Utc>,
226    pub(crate) compression_depth: i32,
227    pub(crate) parent_node_id: Option<String>,
228    pub(crate) semantic_tags: Option<Vec<String>>,
229    pub(crate) semantic_links: Option<Vec<SemanticLink>>,
230    pub(crate) user_avec: AvecStateDto,
231    pub(crate) model_avec: AvecStateDto,
232    pub(crate) compression_avec: Option<AvecStateDto>,
233    pub(crate) rho: f32,
234    pub(crate) kappa: f32,
235    pub(crate) psi: f32,
236    pub(crate) sync_key: String,
237    pub(crate) synthetic_id: String,
238}
239
240#[derive(Debug, Serialize)]
241#[serde(rename_all = "camelCase")]
242pub(crate) struct PsiRangeDto {
243    pub(crate) min: f32,
244    pub(crate) max: f32,
245    pub(crate) average: f32,
246}
247
248#[derive(Debug, Serialize)]
249#[serde(rename_all = "camelCase")]
250pub(crate) struct NumericRangeDto {
251    pub(crate) min: f32,
252    pub(crate) max: f32,
253    pub(crate) average: f32,
254}
255
256#[derive(Debug, Serialize)]
257#[serde(rename_all = "camelCase")]
258pub(crate) struct ConfidenceBandSummaryDto {
259    pub(crate) low: usize,
260    pub(crate) medium: usize,
261    pub(crate) high: usize,
262}
263
264#[derive(Debug, Serialize)]
265#[serde(rename_all = "camelCase")]
266pub(crate) struct CalibrationResultDto {
267    pub(crate) previous_avec: AvecStateDto,
268    pub(crate) delta: f32,
269    pub(crate) drift_classification: String,
270    pub(crate) trigger: String,
271    pub(crate) trigger_history: Vec<String>,
272    pub(crate) is_first_calibration: bool,
273}
274
275#[derive(Debug, Serialize)]
276#[serde(rename_all = "camelCase")]
277pub(crate) struct StoreResultDto {
278    pub(crate) node_id: String,
279    pub(crate) psi: f32,
280    pub(crate) valid: bool,
281    pub(crate) validation_error: Option<String>,
282    pub(crate) duplicate_skipped: bool,
283    pub(crate) upsert_status: String,
284}
285
286#[derive(Debug, Serialize)]
287#[serde(rename_all = "camelCase")]
288pub(crate) struct ScoreAvecResultDto {
289    pub(crate) provider: String,
290    pub(crate) model: String,
291    pub(crate) avec: AvecStateDto,
292}
293
294#[derive(Debug, Serialize)]
295#[serde(rename_all = "camelCase")]
296pub(crate) struct RenameSessionResultDto {
297    pub(crate) source_session_id: String,
298    pub(crate) target_session_id: String,
299    pub(crate) moved_nodes: usize,
300    pub(crate) moved_calibrations: usize,
301    pub(crate) scopes_applied: usize,
302}
303
304#[derive(Debug, Serialize)]
305#[serde(rename_all = "camelCase")]
306pub(crate) struct RetrieveResultDto {
307    pub(crate) nodes: Vec<SttpNodeDto>,
308    pub(crate) retrieved: usize,
309    pub(crate) psi_range: PsiRangeDto,
310}
311
312#[derive(Debug, Serialize)]
313#[serde(rename_all = "camelCase")]
314pub(crate) struct ListNodesResultDto {
315    pub(crate) nodes: Vec<SttpNodeDto>,
316    pub(crate) retrieved: usize,
317}
318
319#[derive(Debug, Serialize)]
320#[serde(rename_all = "camelCase")]
321pub(crate) struct MoodPresetDto {
322    pub(crate) name: String,
323    pub(crate) description: String,
324    pub(crate) avec: AvecStateDto,
325}
326
327#[derive(Debug, Serialize)]
328#[serde(rename_all = "camelCase")]
329pub(crate) struct MoodSwapPreviewDto {
330    pub(crate) target_mood: String,
331    pub(crate) blend: f32,
332    pub(crate) current: AvecStateDto,
333    pub(crate) target: AvecStateDto,
334    pub(crate) blended: AvecStateDto,
335}
336
337#[derive(Debug, Serialize)]
338#[serde(rename_all = "camelCase")]
339pub(crate) struct MoodCatalogResultDto {
340    pub(crate) presets: Vec<MoodPresetDto>,
341    pub(crate) apply_guide: String,
342    pub(crate) swap_preview: Option<MoodSwapPreviewDto>,
343}
344
345#[derive(Debug, Serialize)]
346#[serde(rename_all = "camelCase")]
347pub(crate) struct MonthlyRollupResultDto {
348    pub(crate) success: bool,
349    pub(crate) node_id: String,
350    pub(crate) raw_node: String,
351    pub(crate) error: Option<String>,
352    pub(crate) source_nodes: usize,
353    pub(crate) parent_reference: Option<String>,
354    pub(crate) user_average: AvecStateDto,
355    pub(crate) model_average: AvecStateDto,
356    pub(crate) compression_average: AvecStateDto,
357    pub(crate) rho_range: NumericRangeDto,
358    pub(crate) kappa_range: NumericRangeDto,
359    pub(crate) psi_range: NumericRangeDto,
360    pub(crate) rho_bands: ConfidenceBandSummaryDto,
361    pub(crate) kappa_bands: ConfidenceBandSummaryDto,
362}
363
364#[derive(Debug, Serialize)]
365#[serde(rename_all = "camelCase")]
366pub(crate) struct ScopeRekeyResultDto {
367    pub(crate) source_tenant_id: String,
368    pub(crate) source_session_id: String,
369    pub(crate) target_tenant_id: String,
370    pub(crate) target_session_id: String,
371    pub(crate) temporal_nodes: usize,
372    pub(crate) calibrations: usize,
373    pub(crate) target_temporal_nodes: usize,
374    pub(crate) target_calibrations: usize,
375    pub(crate) applied: bool,
376    pub(crate) conflict: bool,
377    pub(crate) message: Option<String>,
378}
379
380#[derive(Debug, Serialize)]
381#[serde(rename_all = "camelCase")]
382pub(crate) struct BatchRekeyResultDto {
383    pub(crate) dry_run: bool,
384    pub(crate) requested_node_ids: usize,
385    pub(crate) resolved_node_ids: usize,
386    pub(crate) missing_node_ids: Vec<String>,
387    pub(crate) scopes: Vec<ScopeRekeyResultDto>,
388    pub(crate) temporal_nodes_updated: usize,
389    pub(crate) calibrations_updated: usize,
390    pub(crate) updated_scopes: usize,
391    pub(crate) conflict_scopes: usize,
392}
393
394#[derive(Debug, Serialize)]
395#[serde(rename_all = "camelCase")]
396pub(crate) struct EmbeddingMigrationSampleDto {
397    pub(crate) sync_key: String,
398    pub(crate) session_id: String,
399    pub(crate) tier: String,
400    pub(crate) has_embedding: bool,
401    pub(crate) embedding_model: Option<String>,
402    pub(crate) embedding_dimensions: Option<usize>,
403    pub(crate) embedded_at: Option<DateTime<Utc>>,
404    pub(crate) updated_at: DateTime<Utc>,
405    pub(crate) context_summary: Option<String>,
406}
407
408#[derive(Debug, Serialize)]
409#[serde(rename_all = "camelCase")]
410pub(crate) struct EmbeddingMigrationPreviewResultDto {
411    pub(crate) total_candidates: usize,
412    pub(crate) sample: Vec<EmbeddingMigrationSampleDto>,
413    pub(crate) provider_available: bool,
414    pub(crate) provider_model: Option<String>,
415}
416
417#[derive(Debug, Serialize)]
418#[serde(rename_all = "camelCase")]
419pub(crate) struct EmbeddingMigrationRunResultDto {
420    pub(crate) scanned: usize,
421    pub(crate) selected: usize,
422    pub(crate) updated: usize,
423    pub(crate) skipped: usize,
424    pub(crate) failed: usize,
425    pub(crate) duplicate: usize,
426    pub(crate) started_at: DateTime<Utc>,
427    pub(crate) completed_at: DateTime<Utc>,
428    pub(crate) provider_model: Option<String>,
429    pub(crate) dry_run: bool,
430    pub(crate) mode: String,
431    pub(crate) failure_reasons: Vec<String>,
432}
433
434#[derive(Debug, Serialize)]
435pub(crate) struct GraphResponse {
436    pub(crate) sessions: Vec<serde_json::Value>,
437    pub(crate) nodes: Vec<serde_json::Value>,
438    pub(crate) edges: Vec<serde_json::Value>,
439    pub(crate) retrieved: usize,
440}
441
442#[derive(Debug, Deserialize)]
443#[serde(rename_all = "camelCase")]
444pub(crate) struct EvictHttpRequest {
445    pub(crate) tenant_id: Option<String>,
446    pub(crate) session_id: String,
447    pub(crate) mode: Option<String>,
448    pub(crate) sync_keys: Option<Vec<String>>,
449    pub(crate) node_ids: Option<Vec<String>>,
450    pub(crate) semantic_tags: Option<Vec<String>>,
451    pub(crate) tags_contains: Option<Vec<String>>,
452    pub(crate) link_rel: Option<String>,
453    pub(crate) link_target: Option<String>,
454    pub(crate) links_to_ref: Option<String>,
455    pub(crate) tag_prefix: Option<String>,
456    pub(crate) has_semantic_links: Option<bool>,
457    pub(crate) purge_session: Option<bool>,
458    pub(crate) dry_run: Option<bool>,
459    pub(crate) force: Option<bool>,
460    pub(crate) max_nodes: Option<usize>,
461    pub(crate) include_calibration: Option<bool>,
462    pub(crate) include_checkpoints: Option<bool>,
463    pub(crate) tiers: Option<Vec<String>>,
464}
465
466#[derive(Debug, Serialize)]
467#[serde(rename_all = "camelCase")]
468pub(crate) struct EvictHttpResultDto {
469    pub(crate) dry_run: bool,
470    pub(crate) deleted: usize,
471    pub(crate) blocked: usize,
472    pub(crate) not_found: usize,
473    pub(crate) skipped: usize,
474    pub(crate) would_delete: Vec<String>,
475    pub(crate) calibrations_deleted: usize,
476    pub(crate) checkpoints_deleted: usize,
477    pub(crate) records: Vec<serde_json::Value>,
478}
479
480pub(crate) type ApiResult<T> = Result<Json<T>, (axum::http::StatusCode, Json<ErrorResponse>)>;
481
482pub(crate) enum CorsAllowedOrigins {
483    Any,
484    Explicit(Vec<HeaderValue>),
485}