use crate::types::agent::EmbeddingConfig;
use crate::types::common::{LettaId, Metadata, Timestamp};
use bon::Builder;
use serde::{Deserialize, Serialize};
use smart_default::SmartDefault;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, SmartDefault)]
#[serde(rename_all = "snake_case")]
pub enum FileProcessingStatus {
#[default]
Pending,
Parsing,
Embedding,
Completed,
Error,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FileMetadata {
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<LettaId>,
#[serde(skip_serializing_if = "Option::is_none")]
pub organization_id: Option<LettaId>,
pub source_id: LettaId,
#[serde(skip_serializing_if = "Option::is_none")]
pub file_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub file_path: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub file_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub file_size: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub file_creation_date: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub file_last_modified_date: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub processing_status: Option<FileProcessingStatus>,
#[serde(skip_serializing_if = "Option::is_none")]
pub error_message: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub created_at: Option<Timestamp>,
#[serde(skip_serializing_if = "Option::is_none")]
pub updated_at: Option<Timestamp>,
#[serde(skip_serializing_if = "Option::is_none")]
pub is_deleted: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub content: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Source {
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<LettaId>,
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub instructions: Option<String>,
pub embedding_config: EmbeddingConfig,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<Metadata>,
#[serde(skip_serializing_if = "Option::is_none")]
pub created_by_id: Option<LettaId>,
#[serde(skip_serializing_if = "Option::is_none")]
pub last_updated_by_id: Option<LettaId>,
#[serde(skip_serializing_if = "Option::is_none")]
pub created_at: Option<Timestamp>,
#[serde(skip_serializing_if = "Option::is_none")]
pub updated_at: Option<Timestamp>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SourceCounts {
pub count: i32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum FileUploadResponse {
Job(FileUploadJob),
FileMetadata(FileMetadata),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FileUploadJob {
pub id: LettaId,
pub status: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<FileUploadMetadata>,
#[serde(skip_serializing_if = "Option::is_none")]
pub created_at: Option<Timestamp>,
#[serde(skip_serializing_if = "Option::is_none")]
pub updated_at: Option<Timestamp>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FileUploadMetadata {
#[serde(rename = "type")]
pub upload_type: String,
pub filename: String,
pub source_id: LettaId,
}
#[derive(Debug, Clone, Serialize, Deserialize, Builder)]
pub struct CreateSourceRequest {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub embedding: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub embedding_chunk_size: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub embedding_config: Option<EmbeddingConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub instructions: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<Metadata>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct UpdateSourceRequest {
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub instructions: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<Metadata>,
#[serde(skip_serializing_if = "Option::is_none")]
pub embedding_config: Option<EmbeddingConfig>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct ListFilesParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub after: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub include_content: Option<bool>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct GetFileParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub include_content: Option<bool>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct ListPassagesParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub before: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub after: Option<String>,
}
#[cfg(test)]
mod tests {
use super::*;
use crate::types::agent::EmbeddingEndpointType;
use std::collections::HashMap;
use std::str::FromStr;
#[test]
fn test_source_serialization() {
let source = Source {
id: Some(LettaId::from_str("source-550e8400-e29b-41d4-a716-446655440002").unwrap()),
name: "documents".to_string(),
description: Some("Document collection".to_string()),
instructions: Some("Use for general knowledge".to_string()),
embedding_config: EmbeddingConfig {
embedding_endpoint_type: Some(EmbeddingEndpointType::Openai),
embedding_endpoint: None,
embedding_model: Some("text-embedding-ada-002".to_string()),
embedding_dim: Some(1536),
embedding_chunk_size: Some(300),
handle: None,
azure_config: None,
extra: HashMap::new(),
},
metadata: None,
created_by_id: None,
last_updated_by_id: None,
created_at: Some(chrono::Utc::now()),
updated_at: None,
};
let json = serde_json::to_string(&source).unwrap();
let deserialized: Source = serde_json::from_str(&json).unwrap();
assert_eq!(source.name, deserialized.name);
}
#[test]
fn test_file_metadata_serialization() {
let file_metadata = FileMetadata {
id: Some(LettaId::from_str("file-550e8400-e29b-41d4-a716-446655440000").unwrap()),
organization_id: None,
source_id: LettaId::from_str("source-550e8400-e29b-41d4-a716-446655440001").unwrap(),
file_name: Some("test.txt".to_string()),
file_path: Some("/path/to/test.txt".to_string()),
file_type: Some("text/plain".to_string()),
file_size: Some(1024),
file_creation_date: None,
file_last_modified_date: None,
processing_status: Some(FileProcessingStatus::Completed),
error_message: None,
created_at: Some(chrono::Utc::now()),
updated_at: None,
is_deleted: Some(false),
content: None,
};
let json = serde_json::to_string(&file_metadata).unwrap();
let deserialized: FileMetadata = serde_json::from_str(&json).unwrap();
assert_eq!(file_metadata.source_id, deserialized.source_id);
assert_eq!(file_metadata.file_name, deserialized.file_name);
}
}