1use chrono::Utc;
4use nexus_core::{AgentNamespace, Memory, MemoryCategory, MemoryLaneType};
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct CreateMemoryRequest {
14 pub content: String,
15 pub agent_type: String,
16 #[serde(default)]
17 pub category: MemoryCategory,
18 pub memory_lane_type: Option<MemoryLaneType>,
19 #[serde(default)]
20 pub labels: Vec<String>,
21 #[serde(default)]
22 pub metadata: serde_json::Value,
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize)]
27pub struct UpdateMemoryRequest {
28 pub content: Option<String>,
29 pub category: Option<MemoryCategory>,
30 pub memory_lane_type: Option<MemoryLaneType>,
31 pub labels: Option<Vec<String>>,
32 pub metadata: Option<serde_json::Value>,
33 pub is_active: Option<bool>,
34 pub is_archived: Option<bool>,
35}
36
37#[derive(Debug, Clone, Serialize, Deserialize)]
39pub struct MemoryResponse {
40 pub id: i64,
41 pub content: String,
42 pub category: String,
43 pub category_description: Option<String>,
44 pub memory_lane_type: Option<String>,
45 pub labels: Vec<String>,
46 pub metadata: serde_json::Value,
47 pub similarity_score: Option<f32>,
48 pub relevance_score: Option<f32>,
49 pub created_at: String,
50 pub updated_at: Option<String>,
51 pub last_accessed: Option<String>,
52 pub is_active: bool,
53 pub is_archived: bool,
54 pub access_count: i64,
55}
56
57impl From<Memory> for MemoryResponse {
58 fn from(memory: Memory) -> Self {
59 Self {
60 id: memory.id,
61 content: memory.content,
62 category: memory.category.to_string(),
63 category_description: Some(memory.category.description().to_string()),
64 memory_lane_type: memory.memory_lane_type.map(|t| t.to_string()),
65 labels: memory.labels,
66 metadata: memory.metadata,
67 similarity_score: memory.similarity_score,
68 relevance_score: memory.relevance_score,
69 created_at: memory.created_at.to_rfc3339(),
70 updated_at: memory.updated_at.map(|d| d.to_rfc3339()),
71 last_accessed: memory.last_accessed.map(|d| d.to_rfc3339()),
72 is_active: memory.is_active,
73 is_archived: memory.is_archived,
74 access_count: memory.access_count,
75 }
76 }
77}
78
79#[derive(Debug, Clone, Serialize, Deserialize)]
81pub struct MemoryListResponse {
82 pub success: bool,
83 pub total: i64,
84 pub results: Vec<MemoryResponse>,
85 pub query: Option<String>,
86 pub agent_type: String,
87 pub filters: serde_json::Value,
88}
89
90#[derive(Debug, Clone, Serialize, Deserialize)]
92pub struct MemoryCreateResponse {
93 pub success: bool,
94 pub memory_id: Option<i64>,
95 pub agent_type: String,
96 pub category: String,
97 pub error: Option<String>,
98}
99
100#[derive(Debug, Clone, Serialize, Deserialize)]
106pub struct SearchRequest {
107 pub query: String,
108 #[serde(default = "default_agent_type")]
109 pub agent_type: String,
110 #[serde(default = "default_limit")]
111 pub limit: usize,
112 #[serde(default)]
113 pub offset: usize,
114 pub category: Option<MemoryCategory>,
115 pub memory_lane_type: Option<MemoryLaneType>,
116 pub threshold: Option<f32>,
117}
118
119fn default_agent_type() -> String {
120 "general".to_string()
121}
122
123fn default_limit() -> usize {
124 20
125}
126
127impl Default for SearchRequest {
128 fn default() -> Self {
129 Self {
130 query: String::new(),
131 agent_type: default_agent_type(),
132 limit: default_limit(),
133 offset: 0,
134 category: None,
135 memory_lane_type: None,
136 threshold: None,
137 }
138 }
139}
140
141#[derive(Debug, Clone, Serialize, Deserialize)]
143pub struct SearchResponse {
144 pub success: bool,
145 pub results: Vec<MemoryResponse>,
146 pub total: i64,
147 pub query: String,
148 pub agent_type: String,
149 pub filters: serde_json::Value,
150 pub error: Option<String>,
151}
152
153#[derive(Debug, Clone, Serialize, Deserialize)]
159pub struct CreateNamespaceRequest {
160 pub name: String,
161 pub agent_type: String,
162 pub description: Option<String>,
163}
164
165#[derive(Debug, Clone, Serialize, Deserialize)]
167pub struct NamespaceResponse {
168 pub id: i64,
169 pub name: String,
170 pub description: Option<String>,
171 pub agent_type: String,
172 pub created_at: String,
173 pub updated_at: Option<String>,
174}
175
176impl From<AgentNamespace> for NamespaceResponse {
177 fn from(ns: AgentNamespace) -> Self {
178 Self {
179 id: ns.id,
180 name: ns.name,
181 description: ns.description,
182 agent_type: ns.agent_type,
183 created_at: ns.created_at.to_rfc3339(),
184 updated_at: ns.updated_at.map(|d| d.to_rfc3339()),
185 }
186 }
187}
188
189#[derive(Debug, Clone, Serialize, Deserialize)]
191pub struct NamespaceListResponse {
192 pub success: bool,
193 pub namespaces: Vec<NamespaceResponse>,
194 pub total: usize,
195}
196
197#[derive(Debug, Clone, Serialize, Deserialize)]
203pub struct StatsResponse {
204 pub success: bool,
205 pub total_memories: i64,
206 pub active_memories: i64,
207 pub archived_memories: i64,
208 pub categories: serde_json::Value,
209 pub agents: Vec<AgentStats>,
210 pub system_info: Option<SystemInfo>,
211}
212
213#[derive(Debug, Clone, Serialize, Deserialize)]
215pub struct AgentStats {
216 pub agent_type: String,
217 pub namespace_name: String,
218 pub total_memories: i64,
219 pub active_memories: i64,
220 pub archived_memories: i64,
221 pub categories: serde_json::Value,
222 pub oldest_memory: Option<String>,
223 pub newest_memory: Option<String>,
224}
225
226#[derive(Debug, Clone, Serialize, Deserialize)]
228pub struct SystemInfo {
229 pub version: String,
230 pub uptime_seconds: u64,
231 pub active_sessions: usize,
232}
233
234#[derive(Debug, Clone, Serialize, Deserialize)]
240pub struct HealthResponse {
241 pub status: String,
242 pub timestamp: String,
243 pub version: String,
244}
245
246#[derive(Debug, Clone, Serialize, Deserialize)]
248pub struct ErrorResponse {
249 pub success: bool,
250 pub error: String,
251 pub detail: Option<String>,
252}
253
254#[derive(Debug, Clone, Serialize, Deserialize)]
260#[serde(rename_all = "snake_case")]
261pub enum WebSocketMessageType {
262 MemoryStored,
263 MemoryUpdated,
264 MemoryDeleted,
265 SessionStarted,
266 SessionEnded,
267 StatsUpdated,
268 Ping,
269 Pong,
270 CognitiveDrift,
271 DreamCompleted,
272 MorningRecall,
273}
274
275#[derive(Debug, Clone, Serialize, Deserialize)]
277pub struct WebSocketMessage {
278 #[serde(rename = "type")]
279 pub message_type: WebSocketMessageType,
280 pub data: serde_json::Value,
281 pub timestamp: String,
282}
283
284impl WebSocketMessage {
285 pub fn new(message_type: WebSocketMessageType, data: serde_json::Value) -> Self {
286 Self {
287 message_type,
288 data,
289 timestamp: Utc::now().to_rfc3339(),
290 }
291 }
292
293 pub fn memory_stored(memory: &MemoryResponse, agent_type: &str) -> Self {
294 let data = serde_json::json!({
295 "memory": memory,
296 "agent_type": agent_type,
297 });
298 Self::new(WebSocketMessageType::MemoryStored, data)
299 }
300
301 pub fn memory_updated(memory_id: i64) -> Self {
302 let data = serde_json::json!({
303 "memory_id": memory_id,
304 });
305 Self::new(WebSocketMessageType::MemoryUpdated, data)
306 }
307
308 pub fn memory_deleted(memory_id: i64) -> Self {
309 let data = serde_json::json!({
310 "memory_id": memory_id,
311 });
312 Self::new(WebSocketMessageType::MemoryDeleted, data)
313 }
314
315 pub fn ping() -> Self {
316 Self::new(WebSocketMessageType::Ping, serde_json::Value::Null)
317 }
318
319 pub fn pong() -> Self {
320 Self::new(WebSocketMessageType::Pong, serde_json::Value::Null)
321 }
322
323 pub fn cognitive_drift(similarity: f32, agent_type: &str) -> Self {
324 let data = serde_json::json!({
325 "similarity": similarity,
326 "agent_type": agent_type,
327 });
328 Self::new(WebSocketMessageType::CognitiveDrift, data)
329 }
330
331 pub fn dream_completed(agent_type: &str, processed: usize) -> Self {
332 let data = serde_json::json!({
333 "agent_type": agent_type,
334 "processed": processed,
335 });
336 Self::new(WebSocketMessageType::DreamCompleted, data)
337 }
338
339 pub fn morning_recall(namespace: &str, count: usize) -> Self {
340 let data = serde_json::json!({
341 "namespace": namespace,
342 "count": count,
343 });
344 Self::new(WebSocketMessageType::MorningRecall, data)
345 }
346}
347
348#[derive(Debug, Clone, Serialize, Deserialize)]
354pub struct AgentIngestRequest {
355 pub text: String,
356 #[serde(default = "default_source")]
357 pub source: String,
358}
359
360fn default_source() -> String {
361 "api".to_string()
362}
363
364#[derive(Debug, Clone, Serialize, Deserialize)]
366pub struct AgentIngestResponse {
367 pub success: bool,
368 pub memory_id: Option<i64>,
369 pub summary: Option<String>,
370 pub error: Option<String>,
371}
372
373#[derive(Debug, Clone, Serialize, Deserialize)]
375pub struct AgentQueryRequest {
376 pub question: String,
377}
378
379#[derive(Debug, Clone, Serialize, Deserialize)]
381pub struct AgentQueryResponse {
382 pub success: bool,
383 pub question: String,
384 pub answer: Option<String>,
385 pub error: Option<String>,
386}
387
388#[derive(Debug, Clone, Serialize, Deserialize)]
390pub struct AgentConsolidateResponse {
391 pub success: bool,
392 pub memories_processed: usize,
393 pub error: Option<String>,
394}
395
396#[derive(Debug, Clone, Serialize, Deserialize)]
398pub struct AgentStatusResponse {
399 pub enabled: bool,
400 pub namespace: String,
401 pub inbox_dir: String,
402 pub files_processed: u64,
403 pub memories_consolidated: u64,
404 pub queries_answered: u64,
405 pub last_scan: Option<String>,
406 pub last_consolidation: Option<String>,
407 pub errors: Vec<String>,
408 pub uptime_secs: u64,
409}
410
411#[derive(Debug, Clone, Serialize, Deserialize)]
413pub struct AgentBoostRequest {
414 pub memory_id: i64,
415 #[serde(default)]
416 pub pin: bool,
417 pub boost_score: Option<f32>,
418 #[serde(default)]
420 pub root_dir: Option<String>,
421}
422
423#[derive(Debug, Clone, Serialize, Deserialize)]
425pub struct AgentBoostResponse {
426 pub success: bool,
427 pub error: Option<String>,
428}
429
430#[derive(Debug, Clone, Serialize, Deserialize)]
436pub struct JobEntry {
437 pub id: i64,
438 pub job_type: String,
439 pub status: String,
440 pub priority: i64,
441 pub attempts: i64,
442 pub last_error: Option<String>,
443 pub lease_owner: Option<String>,
444 pub lease_expires_at: Option<String>,
445 pub created_at: String,
446 pub updated_at: String,
447}
448
449impl From<nexus_storage::MemoryJobRow> for JobEntry {
450 fn from(row: nexus_storage::MemoryJobRow) -> Self {
451 Self {
452 id: row.id,
453 job_type: row.job_type,
454 status: row.status,
455 priority: row.priority,
456 attempts: row.attempts,
457 last_error: row.last_error,
458 lease_owner: row.lease_owner,
459 lease_expires_at: row.lease_expires_at,
460 created_at: row.created_at,
461 updated_at: row.updated_at,
462 }
463 }
464}
465
466#[derive(Debug, Clone, Serialize, Deserialize)]
468pub struct JobListResponse {
469 pub success: bool,
470 pub namespace: String,
471 pub jobs: Vec<JobEntry>,
472 pub total: i64,
473}
474
475#[derive(Debug, Clone, Serialize, Deserialize)]
477pub struct JobSummaryResponse {
478 pub success: bool,
479 pub namespace: String,
480 pub counts: std::collections::HashMap<String, i64>,
481}
482
483#[derive(Debug, Clone, Serialize, Deserialize)]
485pub struct DigestEntry {
486 pub id: i64,
487 pub session_key: String,
488 pub digest_kind: String,
489 pub memory_id: i64,
490 pub start_memory_id: Option<i64>,
491 pub end_memory_id: Option<i64>,
492 pub token_count: i64,
493 pub created_at: String,
494}
495
496impl From<nexus_storage::SessionDigestRow> for DigestEntry {
497 fn from(row: nexus_storage::SessionDigestRow) -> Self {
498 Self {
499 id: row.id,
500 session_key: row.session_key,
501 digest_kind: row.digest_kind,
502 memory_id: row.memory_id,
503 start_memory_id: row.start_memory_id,
504 end_memory_id: row.end_memory_id,
505 token_count: row.token_count,
506 created_at: row.created_at,
507 }
508 }
509}
510
511#[derive(Debug, Clone, Serialize, Deserialize)]
513pub struct DigestListResponse {
514 pub success: bool,
515 pub namespace: String,
516 pub digests: Vec<DigestEntry>,
517 pub total: i64,
518}
519
520#[derive(Debug, Clone, Serialize, Deserialize)]
522pub struct RuntimeResponse {
523 pub success: bool,
524 pub version: String,
525 pub uptime_seconds: u64,
526 pub db_connected: bool,
527 pub agent_enabled: bool,
528 pub active_sessions: usize,
529}
530
531#[derive(Debug, Clone, Serialize, Deserialize)]
533pub struct ReflectionSampleEntry {
534 pub id: i64,
535 pub content: String,
536 pub created_at: String,
537 pub confidence: Option<f64>,
538}
539
540impl From<Memory> for ReflectionSampleEntry {
541 fn from(memory: Memory) -> Self {
542 let confidence = memory
543 .metadata
544 .get("cognitive")
545 .and_then(|cognitive| cognitive.get("confidence"))
546 .and_then(|value| value.as_f64());
547
548 Self {
549 id: memory.id,
550 content: memory.content,
551 created_at: memory.created_at.to_rfc3339(),
552 confidence,
553 }
554 }
555}
556
557#[derive(Debug, Clone, Serialize, Deserialize)]
559pub struct ReflectionStateResponse {
560 pub success: bool,
561 pub namespace: String,
562 pub contradiction_count: i64,
563 pub derived_count: i64,
564 pub recent_contradictions: Vec<ReflectionSampleEntry>,
565 pub recent_derived: Vec<ReflectionSampleEntry>,
566}
567
568#[derive(Debug, Clone, Serialize, Deserialize)]
570pub struct CognitionOverviewResponse {
571 pub success: bool,
572 pub namespace: String,
573 pub jobs_by_status: std::collections::HashMap<String, i64>,
574 pub digest_count: i64,
575 pub evidence_count: i64,
576 pub stage_metrics: std::collections::HashMap<String, f64>,
577}
578
579#[derive(Debug, Clone, Serialize, Deserialize)]
581pub struct QueryIntrospectionResponse {
582 pub success: bool,
583 pub namespace: String,
584 pub question: String,
585 pub introspection: nexus_agent::QueryIntrospection,
586}
587
588#[derive(Debug, Clone, Serialize, Deserialize)]
594pub struct DreamState {
595 pub completed_reflections: i64,
596 pub completed_digests: i64,
597 pub failed_jobs: i64,
598 pub pending_jobs: i64,
599 pub last_dream_at: Option<String>,
600}
601
602#[derive(Debug, Clone, Serialize, Deserialize)]
604pub struct DigestFreshnessState {
605 pub total_digests: i64,
606 pub sessions_with_cognition: i64,
607 pub latest_digest_age_seconds: Option<i64>,
608 pub latest_digest_at: Option<String>,
609}
610
611#[derive(Debug, Clone, Serialize, Deserialize)]
613pub struct RecallComposition {
614 pub raw: i64,
615 pub explicit: i64,
616 pub derived: i64,
617 pub summary_short: i64,
618 pub summary_long: i64,
619 pub contradiction: i64,
620 pub total: i64,
621}
622
623#[derive(Debug, Clone, Serialize, Deserialize)]
625pub struct AdaptiveDreamState {
626 pub enabled: bool,
627 pub current_interval_secs: u64,
628 pub min_interval_secs: u64,
629 pub max_interval_secs: u64,
630 pub contradiction_count: i64,
631 pub contradiction_density: f64,
632}
633
634#[derive(Debug, Clone, Serialize, Deserialize)]
636pub struct DashboardResponse {
637 pub success: bool,
638 pub namespace: String,
639 pub dream: DreamState,
640 pub digest: DigestFreshnessState,
641 pub recall: RecallComposition,
642 pub adaptive: AdaptiveDreamState,
643}