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}
271
272#[derive(Debug, Clone, Serialize, Deserialize)]
274pub struct WebSocketMessage {
275 #[serde(rename = "type")]
276 pub message_type: WebSocketMessageType,
277 pub data: serde_json::Value,
278 pub timestamp: String,
279}
280
281impl WebSocketMessage {
282 pub fn new(message_type: WebSocketMessageType, data: serde_json::Value) -> Self {
283 Self {
284 message_type,
285 data,
286 timestamp: Utc::now().to_rfc3339(),
287 }
288 }
289
290 pub fn memory_stored(memory: &MemoryResponse, agent_type: &str) -> Self {
291 let data = serde_json::json!({
292 "memory": memory,
293 "agent_type": agent_type,
294 });
295 Self::new(WebSocketMessageType::MemoryStored, data)
296 }
297
298 pub fn memory_updated(memory_id: i64) -> Self {
299 let data = serde_json::json!({
300 "memory_id": memory_id,
301 });
302 Self::new(WebSocketMessageType::MemoryUpdated, data)
303 }
304
305 pub fn memory_deleted(memory_id: i64) -> Self {
306 let data = serde_json::json!({
307 "memory_id": memory_id,
308 });
309 Self::new(WebSocketMessageType::MemoryDeleted, data)
310 }
311
312 pub fn ping() -> Self {
313 Self::new(WebSocketMessageType::Ping, serde_json::Value::Null)
314 }
315
316 pub fn pong() -> Self {
317 Self::new(WebSocketMessageType::Pong, serde_json::Value::Null)
318 }
319}
320
321#[derive(Debug, Clone, Serialize, Deserialize)]
327pub struct AgentIngestRequest {
328 pub text: String,
329 #[serde(default = "default_source")]
330 pub source: String,
331}
332
333fn default_source() -> String {
334 "api".to_string()
335}
336
337#[derive(Debug, Clone, Serialize, Deserialize)]
339pub struct AgentIngestResponse {
340 pub success: bool,
341 pub memory_id: Option<i64>,
342 pub summary: Option<String>,
343 pub error: Option<String>,
344}
345
346#[derive(Debug, Clone, Serialize, Deserialize)]
348pub struct AgentQueryRequest {
349 pub question: String,
350}
351
352#[derive(Debug, Clone, Serialize, Deserialize)]
354pub struct AgentQueryResponse {
355 pub success: bool,
356 pub question: String,
357 pub answer: Option<String>,
358 pub error: Option<String>,
359}
360
361#[derive(Debug, Clone, Serialize, Deserialize)]
363pub struct AgentConsolidateResponse {
364 pub success: bool,
365 pub memories_processed: usize,
366 pub error: Option<String>,
367}
368
369#[derive(Debug, Clone, Serialize, Deserialize)]
371pub struct AgentStatusResponse {
372 pub enabled: bool,
373 pub namespace: String,
374 pub inbox_dir: String,
375 pub files_processed: u64,
376 pub memories_consolidated: u64,
377 pub queries_answered: u64,
378 pub last_scan: Option<String>,
379 pub last_consolidation: Option<String>,
380 pub errors: Vec<String>,
381 pub uptime_secs: u64,
382}
383
384#[derive(Debug, Clone, Serialize, Deserialize)]
390pub struct JobEntry {
391 pub id: i64,
392 pub job_type: String,
393 pub status: String,
394 pub priority: i64,
395 pub attempts: i64,
396 pub last_error: Option<String>,
397 pub lease_owner: Option<String>,
398 pub lease_expires_at: Option<String>,
399 pub created_at: String,
400 pub updated_at: String,
401}
402
403impl From<nexus_storage::MemoryJobRow> for JobEntry {
404 fn from(row: nexus_storage::MemoryJobRow) -> Self {
405 Self {
406 id: row.id,
407 job_type: row.job_type,
408 status: row.status,
409 priority: row.priority,
410 attempts: row.attempts,
411 last_error: row.last_error,
412 lease_owner: row.lease_owner,
413 lease_expires_at: row.lease_expires_at,
414 created_at: row.created_at,
415 updated_at: row.updated_at,
416 }
417 }
418}
419
420#[derive(Debug, Clone, Serialize, Deserialize)]
422pub struct JobListResponse {
423 pub success: bool,
424 pub namespace: String,
425 pub jobs: Vec<JobEntry>,
426 pub total: i64,
427}
428
429#[derive(Debug, Clone, Serialize, Deserialize)]
431pub struct JobSummaryResponse {
432 pub success: bool,
433 pub namespace: String,
434 pub counts: std::collections::HashMap<String, i64>,
435}
436
437#[derive(Debug, Clone, Serialize, Deserialize)]
439pub struct DigestEntry {
440 pub id: i64,
441 pub session_key: String,
442 pub digest_kind: String,
443 pub memory_id: i64,
444 pub start_memory_id: Option<i64>,
445 pub end_memory_id: Option<i64>,
446 pub token_count: i64,
447 pub created_at: String,
448}
449
450impl From<nexus_storage::SessionDigestRow> for DigestEntry {
451 fn from(row: nexus_storage::SessionDigestRow) -> Self {
452 Self {
453 id: row.id,
454 session_key: row.session_key,
455 digest_kind: row.digest_kind,
456 memory_id: row.memory_id,
457 start_memory_id: row.start_memory_id,
458 end_memory_id: row.end_memory_id,
459 token_count: row.token_count,
460 created_at: row.created_at,
461 }
462 }
463}
464
465#[derive(Debug, Clone, Serialize, Deserialize)]
467pub struct DigestListResponse {
468 pub success: bool,
469 pub namespace: String,
470 pub digests: Vec<DigestEntry>,
471 pub total: i64,
472}
473
474#[derive(Debug, Clone, Serialize, Deserialize)]
476pub struct RuntimeResponse {
477 pub success: bool,
478 pub version: String,
479 pub uptime_seconds: u64,
480 pub db_connected: bool,
481 pub agent_enabled: bool,
482 pub active_sessions: usize,
483}
484
485#[derive(Debug, Clone, Serialize, Deserialize)]
487pub struct ReflectionSampleEntry {
488 pub id: i64,
489 pub content: String,
490 pub created_at: String,
491 pub confidence: Option<f64>,
492}
493
494impl From<Memory> for ReflectionSampleEntry {
495 fn from(memory: Memory) -> Self {
496 let confidence = memory
497 .metadata
498 .get("cognitive")
499 .and_then(|cognitive| cognitive.get("confidence"))
500 .and_then(|value| value.as_f64());
501
502 Self {
503 id: memory.id,
504 content: memory.content,
505 created_at: memory.created_at.to_rfc3339(),
506 confidence,
507 }
508 }
509}
510
511#[derive(Debug, Clone, Serialize, Deserialize)]
513pub struct ReflectionStateResponse {
514 pub success: bool,
515 pub namespace: String,
516 pub contradiction_count: i64,
517 pub derived_count: i64,
518 pub recent_contradictions: Vec<ReflectionSampleEntry>,
519 pub recent_derived: Vec<ReflectionSampleEntry>,
520}
521
522#[derive(Debug, Clone, Serialize, Deserialize)]
524pub struct CognitionOverviewResponse {
525 pub success: bool,
526 pub namespace: String,
527 pub jobs_by_status: std::collections::HashMap<String, i64>,
528 pub digest_count: i64,
529 pub evidence_count: i64,
530 pub stage_metrics: std::collections::HashMap<String, f64>,
531}
532
533#[derive(Debug, Clone, Serialize, Deserialize)]
535pub struct QueryIntrospectionResponse {
536 pub success: bool,
537 pub namespace: String,
538 pub question: String,
539 pub introspection: nexus_agent::QueryIntrospection,
540}
541
542#[derive(Debug, Clone, Serialize, Deserialize)]
548pub struct DreamState {
549 pub completed_reflections: i64,
550 pub completed_digests: i64,
551 pub failed_jobs: i64,
552 pub pending_jobs: i64,
553 pub last_dream_at: Option<String>,
554}
555
556#[derive(Debug, Clone, Serialize, Deserialize)]
558pub struct DigestFreshnessState {
559 pub total_digests: i64,
560 pub sessions_with_cognition: i64,
561 pub latest_digest_age_seconds: Option<i64>,
562 pub latest_digest_at: Option<String>,
563}
564
565#[derive(Debug, Clone, Serialize, Deserialize)]
567pub struct RecallComposition {
568 pub raw: i64,
569 pub explicit: i64,
570 pub derived: i64,
571 pub summary_short: i64,
572 pub summary_long: i64,
573 pub contradiction: i64,
574 pub total: i64,
575}
576
577#[derive(Debug, Clone, Serialize, Deserialize)]
579pub struct AdaptiveDreamState {
580 pub enabled: bool,
581 pub current_interval_secs: u64,
582 pub min_interval_secs: u64,
583 pub max_interval_secs: u64,
584 pub contradiction_count: i64,
585 pub contradiction_density: f64,
586}
587
588#[derive(Debug, Clone, Serialize, Deserialize)]
590pub struct DashboardResponse {
591 pub success: bool,
592 pub namespace: String,
593 pub dream: DreamState,
594 pub digest: DigestFreshnessState,
595 pub recall: RecallComposition,
596 pub adaptive: AdaptiveDreamState,
597}