use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashMap;
#[derive(Debug, Serialize, Deserialize)]
pub struct Attachment {
#[serde(skip_serializing_if = "Option::is_none")]
pub file_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub file_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub file_url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub file_size: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub file_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub uploaded_at: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct PageResponse<T> {
#[serde(skip_serializing_if = "Option::is_none")]
pub has_more: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub page_token: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub items: Option<Vec<T>>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct SessionCreateRequest {
pub app_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<HashMap<String, Value>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tool_set: Option<ToolSet>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct SessionUpdateRequest {
pub app_id: String,
pub session_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<HashMap<String, Value>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tool_set: Option<ToolSet>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct SessionGetRequest {
pub app_id: String,
pub session_id: String,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct SessionDeleteRequest {
pub app_id: String,
pub session_id: String,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Session {
#[serde(skip_serializing_if = "Option::is_none")]
pub session_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub app_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub created_at: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<HashMap<String, Value>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tool_set: Option<ToolSet>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ToolSet {
#[serde(skip_serializing_if = "Option::is_none")]
pub tools: Option<Vec<Tool>>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Tool {
#[serde(skip_serializing_if = "Option::is_none")]
pub tool_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub config: Option<Value>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct MessageCreateRequest {
pub app_id: String,
pub session_id: String,
pub content: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub message_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<HashMap<String, Value>>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct MessageGetRequest {
pub app_id: String,
pub session_id: String,
pub message_id: String,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct MessageListRequest {
pub app_id: String,
pub session_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub page_size: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub page_token: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub order: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Message {
#[serde(skip_serializing_if = "Option::is_none")]
pub message_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub session_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub content: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub message_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub role: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub created_at: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<HashMap<String, Value>>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct RunCreateRequest {
pub app_id: String,
pub session_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub instructions: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub model: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub additional_messages: Option<Vec<Message>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tool_set: Option<ToolSet>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct RunGetRequest {
pub app_id: String,
pub session_id: String,
pub run_id: String,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct RunListRequest {
pub app_id: String,
pub session_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub page_size: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub page_token: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub order: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct RunCancelRequest {
pub app_id: String,
pub session_id: String,
pub run_id: String,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Run {
#[serde(skip_serializing_if = "Option::is_none")]
pub run_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub session_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub status: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub created_at: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub started_at: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub completed_at: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub failed_at: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cancelled_at: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub instructions: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub model: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tool_set: Option<ToolSet>,
#[serde(skip_serializing_if = "Option::is_none")]
pub last_error: Option<RunError>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct RunError {
#[serde(skip_serializing_if = "Option::is_none")]
pub code: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub message: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct SkillStartRequest {
pub app_id: String,
pub skill_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub input: Option<HashMap<String, Value>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub session_id: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct SkillGetRequest {
pub app_id: String,
pub skill_id: String,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct SkillListRequest {
pub app_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub page_size: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub page_token: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Skill {
#[serde(skip_serializing_if = "Option::is_none")]
pub skill_id: Option<String>,
#[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 skill_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub status: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub input_config: Option<Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub output_config: Option<Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub created_at: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub updated_at: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct SkillExecution {
#[serde(skip_serializing_if = "Option::is_none")]
pub execution_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub skill_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub status: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub input: Option<HashMap<String, Value>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub output: Option<HashMap<String, Value>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub started_at: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub completed_at: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct DataKnowledgeAskRequest {
pub app_id: String,
pub question: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub knowledge_base_ids: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub chat_history: Option<Vec<ChatMessage>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub retrieval_config: Option<RetrievalConfig>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ChatMessage {
pub role: String,
pub content: String,
}
#[derive(Debug, Serialize, Deserialize, Default)]
pub struct RetrievalConfig {
}
#[derive(Debug, Serialize, Deserialize)]
pub struct DataKnowledgeAnswer {
#[serde(skip_serializing_if = "Option::is_none")]
pub answer: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub references: Option<Vec<KnowledgeReference>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub confidence_score: Option<f64>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct KnowledgeReference {
#[serde(skip_serializing_if = "Option::is_none")]
pub document_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub content: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub relevance_score: Option<f64>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct DataKnowledgeFileUploadRequest {
pub app_id: String,
pub file: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub file_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub file_type: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct DataKnowledgeCreateRequest {
pub app_id: String,
pub title: String,
pub content: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub category_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tags: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<HashMap<String, Value>>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct DataKnowledgeGetRequest {
pub app_id: String,
pub knowledge_id: String,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct DataKnowledgeDeleteRequest {
pub app_id: String,
pub knowledge_id: String,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct DataKnowledgeListRequest {
pub app_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub page_size: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub page_token: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub category_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub keyword: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct DataKnowledgeCategoryListRequest {
pub app_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub page_size: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub page_token: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct DataKnowledge {
#[serde(skip_serializing_if = "Option::is_none")]
pub knowledge_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub content: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub category_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub category_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tags: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub status: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub created_at: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub updated_at: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<HashMap<String, Value>>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct DataKnowledgeCategory {
#[serde(skip_serializing_if = "Option::is_none")]
pub category_id: Option<String>,
#[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 parent_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub weight: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub created_at: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub updated_at: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct FileUploadResult {
#[serde(skip_serializing_if = "Option::is_none")]
pub file_token: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub file_size: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub file_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub uploaded_at: Option<String>,
}
#[cfg(test)]
#[allow(unused_variables, unused_unsafe)]
mod tests {
use super::*;
use serde_json;
#[test]
fn test_page_response_serialization() {
let response = PageResponse {
has_more: Some(true),
page_token: Some("next_token".to_string()),
items: Some(vec!["item1".to_string(), "item2".to_string()]),
};
let json = serde_json::to_string(&response).unwrap();
assert!(json.contains("true"));
assert!(json.contains("next_token"));
assert!(json.contains("item1"));
}
#[test]
fn test_page_response_empty() {
let response: PageResponse<String> = PageResponse {
has_more: Some(false),
page_token: None,
items: Some(vec![]),
};
let json = serde_json::to_string(&response).unwrap();
assert!(json.contains("false"));
assert!(!json.contains("page_token"));
}
#[test]
fn test_session_create_request() {
let mut metadata = HashMap::new();
metadata.insert("user_id".to_string(), serde_json::json!("user123"));
let request = SessionCreateRequest {
app_id: "app456".to_string(),
metadata: Some(metadata),
tool_set: Some(ToolSet {
tools: Some(vec![Tool {
tool_type: Some("function".to_string()),
config: Some(serde_json::json!({
"name": "get_weather",
"description": "Get weather information"
})),
}]),
}),
};
let json = serde_json::to_string(&request).unwrap();
assert!(json.contains("app456"));
assert!(json.contains("user123"));
assert!(json.contains("get_weather"));
}
#[test]
fn test_session_update_request() {
let request = SessionUpdateRequest {
app_id: "app789".to_string(),
session_id: "session123".to_string(),
metadata: Some(HashMap::new()),
tool_set: None,
};
let json = serde_json::to_string(&request).unwrap();
assert!(json.contains("app789"));
assert!(json.contains("session123"));
assert!(!json.contains("tool_set"));
}
#[test]
fn test_session_get_request() {
let request = SessionGetRequest {
app_id: "app001".to_string(),
session_id: "session456".to_string(),
};
let json = serde_json::to_string(&request).unwrap();
assert!(json.contains("app001"));
assert!(json.contains("session456"));
}
#[test]
fn test_session_complete() {
let session = Session {
session_id: Some("sess789".to_string()),
app_id: Some("app123".to_string()),
created_at: Some("2024-01-01T00:00:00Z".to_string()),
metadata: Some({
let mut map = HashMap::new();
map.insert("context".to_string(), serde_json::json!("conversation"));
map
}),
tool_set: Some(ToolSet {
tools: Some(vec![]),
}),
};
let json = serde_json::to_string(&session).unwrap();
assert!(json.contains("sess789"));
assert!(json.contains("app123"));
assert!(json.contains("conversation"));
}
#[test]
fn test_tool_set_with_function() {
let tool_set = ToolSet {
tools: Some(vec![Tool {
tool_type: Some("function".to_string()),
config: Some(serde_json::json!({
"name": "calculate",
"description": "Perform calculations",
"parameters": {
"type": "object",
"properties": {
"expression": {"type": "string"}
}
}
})),
}]),
};
let json = serde_json::to_string(&tool_set).unwrap();
assert!(json.contains("function"));
assert!(json.contains("calculate"));
assert!(json.contains("parameters"));
}
#[test]
fn test_message_create_request() {
let request = MessageCreateRequest {
app_id: "app555".to_string(),
session_id: "session888".to_string(),
content: "Hello, assistant!".to_string(),
message_type: Some("text".to_string()),
metadata: Some({
let mut map = HashMap::new();
map.insert("priority".to_string(), serde_json::json!("high"));
map
}),
};
let json = serde_json::to_string(&request).unwrap();
assert!(json.contains("app555"));
assert!(json.contains("session888"));
assert!(json.contains("Hello, assistant!"));
assert!(json.contains("high"));
assert!(json.contains("text"));
}
#[test]
fn test_message_list_request() {
let request = MessageListRequest {
app_id: "app777".to_string(),
session_id: "session999".to_string(),
page_size: Some(50),
page_token: Some("page_token_123".to_string()),
order: Some("desc".to_string()),
};
let json = serde_json::to_string(&request).unwrap();
assert!(json.contains("app777"));
assert!(json.contains("session999"));
assert!(json.contains("50"));
assert!(json.contains("desc"));
assert!(json.contains("page_token_123"));
}
#[test]
fn test_message_with_assistant_role() {
let message = Message {
message_id: Some("msg456".to_string()),
session_id: Some("session123".to_string()),
role: Some("assistant".to_string()),
content: Some("I can help you with that task.".to_string()),
message_type: Some("text".to_string()),
created_at: Some("2024-01-01T10:00:00Z".to_string()),
metadata: Some({
let mut map = HashMap::new();
map.insert("confidence".to_string(), serde_json::json!(0.95));
map
}),
};
let json = serde_json::to_string(&message).unwrap();
assert!(json.contains("msg456"));
assert!(json.contains("assistant"));
assert!(json.contains("I can help you"));
assert!(json.contains("0.95"));
}
#[test]
fn test_run_create_request() {
let request = RunCreateRequest {
app_id: "app666".to_string(),
session_id: "session444".to_string(),
instructions: Some("Please analyze the uploaded document".to_string()),
model: Some("gpt-4".to_string()),
additional_messages: Some(vec![]),
tool_set: Some(ToolSet {
tools: Some(vec![Tool {
tool_type: Some("code_interpreter".to_string()),
config: None,
}]),
}),
};
let json = serde_json::to_string(&request).unwrap();
assert!(json.contains("app666"));
assert!(json.contains("session444"));
assert!(json.contains("analyze the uploaded"));
assert!(json.contains("code_interpreter"));
}
#[test]
fn test_run_list_request() {
let request = RunListRequest {
app_id: "app888".to_string(),
session_id: "session777".to_string(),
page_size: Some(20),
page_token: Some("run123".to_string()),
order: Some("asc".to_string()),
};
let json = serde_json::to_string(&request).unwrap();
assert!(json.contains("app888"));
assert!(json.contains("session777"));
assert!(json.contains("20"));
assert!(json.contains("asc"));
assert!(json.contains("run123"));
}
#[test]
fn test_run_in_progress() {
let run = Run {
run_id: Some("run789".to_string()),
session_id: Some("session456".to_string()),
status: Some("in_progress".to_string()),
created_at: Some("2024-01-01T14:00:00Z".to_string()),
started_at: Some("2024-01-01T14:00:00Z".to_string()),
completed_at: None,
failed_at: None,
cancelled_at: None,
instructions: Some("Generate a summary report".to_string()),
model: Some("gpt-4".to_string()),
tool_set: Some(ToolSet {
tools: Some(vec![Tool {
tool_type: Some("code_interpreter".to_string()),
config: None,
}]),
}),
last_error: None,
};
let json = serde_json::to_string(&run).unwrap();
assert!(json.contains("run789"));
assert!(json.contains("in_progress"));
assert!(json.contains("Generate a summary"));
assert!(!json.contains("completed_at"));
}
#[test]
fn test_run_failed() {
let run = Run {
run_id: Some("run999".to_string()),
session_id: Some("session111".to_string()),
status: Some("failed".to_string()),
created_at: Some("2024-01-01T15:00:00Z".to_string()),
started_at: Some("2024-01-01T15:00:00Z".to_string()),
completed_at: None,
failed_at: Some("2024-01-01T15:05:00Z".to_string()),
cancelled_at: None,
instructions: Some("Process large dataset".to_string()),
model: Some("gpt-4".to_string()),
tool_set: None,
last_error: Some(RunError {
code: Some("TIMEOUT".to_string()),
message: Some("Processing timeout".to_string()),
}),
};
let json = serde_json::to_string(&run).unwrap();
assert!(json.contains("run999"));
assert!(json.contains("failed"));
assert!(json.contains("TIMEOUT"));
assert!(json.contains("Processing timeout"));
assert!(json.contains("failed_at"));
}
#[test]
fn test_attachment_complete() {
let attachment = Attachment {
file_id: Some("file789".to_string()),
file_name: Some("presentation.pptx".to_string()),
file_url: Some("https://files.example.com/file789".to_string()),
file_size: Some(2048000),
file_type: Some("application/vnd.ms-powerpoint".to_string()),
uploaded_at: Some("2024-01-01T16:30:00Z".to_string()),
};
let json = serde_json::to_string(&attachment).unwrap();
assert!(json.contains("file789"));
assert!(json.contains("presentation.pptx"));
assert!(json.contains("files.example.com"));
assert!(json.contains("2048000"));
assert!(json.contains("vnd.ms-powerpoint"));
}
#[test]
fn test_attachment_minimal() {
let attachment = Attachment {
file_id: Some("file456".to_string()),
file_name: Some("note.txt".to_string()),
file_url: None,
file_size: None,
file_type: Some("text/plain".to_string()),
uploaded_at: None,
};
let json = serde_json::to_string(&attachment).unwrap();
assert!(json.contains("file456"));
assert!(json.contains("note.txt"));
assert!(json.contains("text/plain"));
assert!(!json.contains("file_url"));
assert!(!json.contains("uploaded_at"));
}
}