use serde::{Deserialize, Serialize};
pub(super) const PROJECT_NAME_MAX_LENGTH: usize = 256;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "rag", derive(schemars::JsonSchema))]
pub struct IndexRequest {
pub path: String,
#[serde(default)]
pub project: Option<String>,
#[serde(default)]
pub include_patterns: Vec<String>,
#[serde(default)]
pub exclude_patterns: Vec<String>,
#[serde(default = "default_max_file_size")]
pub max_file_size: usize,
}
pub fn default_max_file_size() -> usize {
1_048_576 }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "rag", derive(schemars::JsonSchema))]
#[serde(rename_all = "lowercase")]
pub enum IndexingMode {
Full,
Incremental,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "rag", derive(schemars::JsonSchema))]
pub struct IndexResponse {
pub mode: IndexingMode,
pub files_indexed: usize,
pub chunks_created: usize,
pub embeddings_generated: usize,
pub duration_ms: u64,
#[serde(default)]
pub errors: Vec<String>,
#[serde(default)]
pub files_updated: usize,
#[serde(default)]
pub files_removed: usize,
}
impl IndexRequest {
pub fn validate(&self) -> Result<(), String> {
let path = std::path::Path::new(&self.path);
if !path.exists() {
return Err(format!("Path does not exist: {}", self.path));
}
if !path.is_dir() {
return Err(format!("Path is not a directory: {}", self.path));
}
let _canonical = path
.canonicalize()
.map_err(|e| format!("Failed to canonicalize path: {}", e))?;
const MAX_FILE_SIZE_LIMIT: usize = 100_000_000; if self.max_file_size > MAX_FILE_SIZE_LIMIT {
return Err(format!(
"max_file_size too large: {} bytes (max: {} bytes)",
self.max_file_size, MAX_FILE_SIZE_LIMIT
));
}
if let Some(ref project) = self.project {
if project.is_empty() {
return Err("project name cannot be empty".to_string());
}
if project.len() > PROJECT_NAME_MAX_LENGTH {
return Err(format!(
"project name too long (max {} characters)",
PROJECT_NAME_MAX_LENGTH
));
}
}
Ok(())
}
}