use serde::{Deserialize, Serialize};
use chrono::{DateTime, Utc};
#[derive(Debug, Serialize)]
pub struct ApiResponse<T> {
pub success: bool,
pub data: Option<T>,
pub error: Option<String>,
pub timestamp: DateTime<Utc>,
}
impl<T> ApiResponse<T> {
pub fn success(data: T) -> Self {
Self {
success: true,
data: Some(data),
error: None,
timestamp: Utc::now(),
}
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct FileEntryResponse {
pub uri: String,
pub name: String,
pub is_directory: bool,
pub size: u64,
pub modified: DateTime<Utc>,
#[serde(skip_serializing_if = "Option::is_none")]
pub abstract_text: Option<String>,
}
impl From<cortex_mem_core::FileEntry> for FileEntryResponse {
fn from(entry: cortex_mem_core::FileEntry) -> Self {
Self {
uri: entry.uri,
name: entry.name,
is_directory: entry.is_directory,
size: entry.size,
modified: entry.modified,
abstract_text: None,
}
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct SessionResponse {
pub thread_id: String,
pub status: String,
pub message_count: usize,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
#[derive(Debug, Deserialize)]
pub struct CloseAndWaitRequest {
#[serde(default = "default_close_wait_timeout_secs")]
pub timeout_secs: u64,
#[serde(default = "default_close_wait_poll_interval_ms")]
pub poll_interval_ms: u64,
}
fn default_close_wait_timeout_secs() -> u64 {
120
}
fn default_close_wait_poll_interval_ms() -> u64 {
500
}
#[derive(Debug, Serialize)]
pub struct CloseAndWaitResponse {
pub thread_id: String,
pub status: String,
pub user_id: String,
pub agent_id: String,
pub waited_ms: u64,
pub user_index_exists: bool,
pub user_memory_count: usize,
pub session_summary_exists: bool,
pub session_summary_memory_count: usize,
pub vector_sync_confirmed: bool,
pub timeline_abstract_exists: bool,
pub timeline_overview_exists: bool,
}
#[derive(Debug, Deserialize)]
pub struct AddMessageRequest {
pub role: String,
pub content: String,
#[serde(default)]
#[allow(dead_code)]
pub metadata: Option<serde_json::Value>,
}
#[derive(Debug, Deserialize)]
pub struct SearchRequest {
pub query: String,
pub thread: Option<String>,
pub limit: Option<usize>,
pub min_score: Option<f32>,
#[serde(default = "default_return_layers")]
pub return_layers: Vec<String>,
}
fn default_return_layers() -> Vec<String> {
vec!["L0".to_string()]
}
#[derive(Debug, Serialize)]
pub struct SearchResultResponse {
pub uri: String,
pub score: f32,
pub snippet: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub overview: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub content: Option<String>,
pub source: String,
pub layers: Vec<String>,
}
#[derive(Debug, Deserialize)]
pub struct LsRequest {
#[serde(default = "default_uri")]
pub uri: String,
#[serde(default)]
pub recursive: bool,
#[serde(default)]
pub include_abstracts: bool,
#[serde(default)]
pub include_layers: bool,
}
fn default_uri() -> String {
"cortex://session".to_string()
}
#[derive(Debug, Serialize)]
pub struct LsResponse {
pub uri: String,
pub total: usize,
pub entries: Vec<FileEntryResponse>,
}
#[derive(Debug, Deserialize)]
pub struct ExploreRequest {
pub query: String,
#[serde(default = "default_explore_start")]
pub start_uri: String,
#[serde(default = "default_return_layers")]
pub return_layers: Vec<String>,
}
fn default_explore_start() -> String {
"cortex://session".to_string()
}
#[derive(Debug, Serialize)]
pub struct ExploreResponse {
pub query: String,
pub exploration_path: Vec<ExplorationPathItem>,
pub matches: Vec<SearchResultResponse>,
pub total_explored: usize,
pub total_matches: usize,
}
#[derive(Debug, Serialize)]
pub struct ExplorationPathItem {
pub uri: String,
pub relevance_score: f32,
pub abstract_text: Option<String>,
}