//! Data Transfer Objects (DTOs) for the CMS REST API. //! //! These types define the wire format accepted and returned by HTTP handlers. //! They are intentionally independent of the domain entities so the API //! contract can evolve without coupling to the domain model. //! //! ## DTOs //! - `SettingsUpdateRequest` — partial-update body for PUT /settings //! - `SettingsResponse` — response body for GET /settings (API keys redacted) //! - `MemoryCreateRequest` — request body for POST /memories //! - `MemoryResponse` — response body for memory operations //! - `ConversationResponse` — response body for GET /conversation //! //! ## Conventions //! - `From` impls convert domain entities → DTO responses //! - API key values are **redacted** in responses (only key names exposed) //! - Request fields use `Option` to support partial updates use serde::{Deserialize, Serialize}; // --------------------------------------------------------------------------- // Settings // --------------------------------------------------------------------------- /// Request body for updating settings (partial update — only specified fields /// are changed). #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SettingsUpdateRequest { pub internet_mode: Option, pub provider: Option, pub model: Option, pub api_keys: Option>, pub max_tokens: Option>, pub temperature: Option>, pub review_max_lessons_per_run: Option, pub adaptive_review_max_skip: Option, pub verify_command: Option>, pub verify_timeout_ms: Option, pub workflow_max_concurrency: Option, pub review_enabled: Option, pub session_archive_enabled: Option, pub lsp_auto_provision: Option, pub lsp_languages: Option>, pub hive_mind_node_timeout_ms: Option, } /// Response body for settings. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SettingsResponse { pub internet_mode: String, pub provider: String, pub model: String, pub api_keys: Vec, // key names only, values redacted pub max_tokens: Option, pub temperature: Option, pub review_max_lessons_per_run: usize, pub adaptive_review_max_skip: u32, pub verify_command: Option, pub verify_timeout_ms: u64, pub workflow_max_concurrency: usize, pub review_enabled: bool, pub session_archive_enabled: bool, pub lsp_auto_provision: bool, pub lsp_languages: Vec, pub hive_mind_node_timeout_ms: u64, } /// Convert a domain `Settings` entity into its API response representation. /// /// ## Side-effects /// - API key **values are redacted** — only key names are exposed. impl From for SettingsResponse { fn from(s: crate::domain::settings::Settings) -> Self { Self { internet_mode: format!("{:?}", s.internet_mode), provider: s.provider, model: s.model, api_keys: s.api_keys.keys().cloned().collect(), max_tokens: s.max_tokens, temperature: s.temperature, review_max_lessons_per_run: s.review_max_lessons_per_run, adaptive_review_max_skip: s.adaptive_review_max_skip, verify_command: s.verify_command, verify_timeout_ms: s.verify_timeout_ms, workflow_max_concurrency: s.workflow_max_concurrency, review_enabled: s.flags.review_enabled, session_archive_enabled: s.flags.session_archive_enabled, lsp_auto_provision: s.flags.lsp_auto_provision, lsp_languages: s.lsp_languages, hive_mind_node_timeout_ms: s.hive_mind_node_timeout_ms, } } } // --------------------------------------------------------------------------- // Memory // --------------------------------------------------------------------------- /// Request body for creating or updating a memory. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct MemoryCreateRequest { pub name: String, pub description: String, pub content: String, pub kind: Option, pub outcome: Option, pub lifecycle: Option, pub scope: Option, pub before_snippet: Option, pub after_snippet: Option, pub provenances: Option>, } /// Response body for a memory. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct MemoryResponse { pub name: String, pub description: String, pub content: String, pub kind: String, pub created_at: i64, pub updated_at: i64, pub outcome: Option, pub lifecycle: String, pub scope: Option, pub before_snippet: Option, pub after_snippet: Option, pub provenances: Vec, } /// Convert a domain `Memory` entity into its API response representation. impl From for MemoryResponse { fn from(m: crate::domain::memory::Memory) -> Self { Self { name: m.name, description: m.description, content: m.content, kind: m.kind, created_at: m.created_at, updated_at: m.updated_at, outcome: m.outcome, lifecycle: m.lifecycle, scope: m.scope, before_snippet: m.before_snippet, after_snippet: m.after_snippet, provenances: m.provenances, } } } // --------------------------------------------------------------------------- // Conversation // --------------------------------------------------------------------------- /// Response body for a conversation. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ConversationResponse { pub session_id: String, pub message_count: usize, pub model: String, pub system_prompt: String, pub max_tokens: Option, pub temperature: Option, } /// Convert a domain `Conversation` entity into its API response summary. /// /// ## Note /// Only metadata is included (message count, model, system prompt); /// individual messages are not returned in this response. impl From for ConversationResponse { fn from(c: crate::domain::conversation::Conversation) -> Self { let message_count = c.len(); Self { session_id: c.session_id, message_count, model: c.model, system_prompt: c.system_prompt, max_tokens: c.max_tokens, temperature: c.temperature, } } }