use super::CodexErrorInfo;use super::ThreadItem;use super::ThreadStatus;use super::TurnStatus;use codex_protocol::protocol::SessionSource as CoreSessionSource;use codex_protocol::protocol::SubAgentSource as CoreSubAgentSource;use codex_protocol::protocol::ThreadSource as CoreThreadSource;use codex_utils_absolute_path::AbsolutePathBuf;use schemars::JsonSchema;use schemars::r#gen::SchemaGenerator;use schemars::schema::Schema;use serde::Deserialize;use serde::Serialize;use std::path::PathBuf;use thiserror::Error;use ts_rs::TS;#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(rename_all = "camelCase", export_to = "v2/")]#[derive(Default)]pub enum SessionSource { Cli, #[serde(rename = "vscode")] #[ts(rename = "vscode")] #[default] VsCode, Exec, AppServer, Custom(String), SubAgent(CoreSubAgentSource), #[serde(other)] Unknown,}impl From<CoreSessionSource> for SessionSource { fn from(value: CoreSessionSource) -> Self { match value { CoreSessionSource::Cli => SessionSource::Cli, CoreSessionSource::VSCode => SessionSource::VsCode, CoreSessionSource::Exec => SessionSource::Exec, CoreSessionSource::Mcp => SessionSource::AppServer, CoreSessionSource::Custom(source) => SessionSource::Custom(source), // We do not want to render those at the app-server level. CoreSessionSource::Internal(_) => SessionSource::Unknown, CoreSessionSource::SubAgent(sub) => SessionSource::SubAgent(sub), CoreSessionSource::Unknown => SessionSource::Unknown, } }}impl From<SessionSource> for CoreSessionSource { fn from(value: SessionSource) -> Self { match value { SessionSource::Cli => CoreSessionSource::Cli, SessionSource::VsCode => CoreSessionSource::VSCode, SessionSource::Exec => CoreSessionSource::Exec, SessionSource::AppServer => CoreSessionSource::Mcp, SessionSource::Custom(source) => CoreSessionSource::Custom(source), SessionSource::SubAgent(sub) => CoreSessionSource::SubAgent(sub), SessionSource::Unknown => CoreSessionSource::Unknown, } }}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, TS)]#[serde(try_from = "String", into = "String")]#[ts(type = "string")]#[ts(export_to = "v2/")]pub enum ThreadSource { User, Subagent, Feature(String), MemoryConsolidation,}impl JsonSchema for ThreadSource { fn schema_name() -> String { "ThreadSource".to_string() } fn json_schema(generator: &mut SchemaGenerator) -> Schema { String::json_schema(generator) }}impl TryFrom<String> for ThreadSource { type Error = String; fn try_from(value: String) -> Result<Self, Self::Error> { value.parse::<CoreThreadSource>().map(Into::into) }}impl From<ThreadSource> for String { fn from(value: ThreadSource) -> Self { CoreThreadSource::from(value).into() }}impl From<CoreThreadSource> for ThreadSource { fn from(value: CoreThreadSource) -> Self { match value { CoreThreadSource::User => ThreadSource::User, CoreThreadSource::Subagent => ThreadSource::Subagent, CoreThreadSource::Feature(feature) => ThreadSource::Feature(feature), CoreThreadSource::MemoryConsolidation => ThreadSource::MemoryConsolidation, } }}impl From<ThreadSource> for CoreThreadSource { fn from(value: ThreadSource) -> Self { match value { ThreadSource::User => CoreThreadSource::User, ThreadSource::Subagent => CoreThreadSource::Subagent, ThreadSource::Feature(feature) => CoreThreadSource::Feature(feature), ThreadSource::MemoryConsolidation => CoreThreadSource::MemoryConsolidation, } }}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct GitInfo { pub sha: Option<String>, pub branch: Option<String>, pub origin_url: Option<String>,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct Thread { pub id: String, /// Session id shared by threads that belong to the same session tree. pub session_id: String, /// Source thread id when this thread was created by forking another thread. pub forked_from_id: Option<String>, /// The ID of the parent thread. This will only be set if this thread is a subagent. pub parent_thread_id: Option<String>, /// Usually the first user message in the thread, if available. pub preview: String, /// Whether the thread is ephemeral and should not be materialized on disk. pub ephemeral: bool, /// Model provider used for this thread (for example, 'openai'). pub model_provider: String, /// Unix timestamp (in seconds) when the thread was created. #[ts(type = "number")] pub created_at: i64, /// Unix timestamp (in seconds) when the thread was last updated. #[ts(type = "number")] pub updated_at: i64, /// Current runtime status for the thread. pub status: ThreadStatus, /// [UNSTABLE] Path to the thread on disk. pub path: Option<PathBuf>, /// Working directory captured for the thread. pub cwd: AbsolutePathBuf, /// Version of the CLI that created the thread. pub cli_version: String, /// Origin of the thread (CLI, VSCode, codex exec, codex app-server, etc.). pub source: SessionSource, /// Optional analytics source classification for this thread. pub thread_source: Option<ThreadSource>, /// Optional random unique nickname assigned to an AgentControl-spawned sub-agent. pub agent_nickname: Option<String>, /// Optional role (agent_role) assigned to an AgentControl-spawned sub-agent. pub agent_role: Option<String>, /// Optional Git metadata captured when the thread was created. pub git_info: Option<GitInfo>, /// Optional user-facing thread title. pub name: Option<String>, /// Only populated on `thread/resume`, `thread/rollback`, `thread/fork`, and `thread/read` /// (when `includeTurns` is true) responses. /// For all other responses and notifications returning a Thread, /// the turns field will be an empty list. pub turns: Vec<Turn>,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct Turn { pub id: String, /// Thread items currently included in this turn payload. pub items: Vec<ThreadItem>, /// Describes how much of `items` has been loaded for this turn. #[serde(default)] pub items_view: TurnItemsView, pub status: TurnStatus, /// Only populated when the Turn's status is failed. pub error: Option<TurnError>, /// Unix timestamp (in seconds) when the turn started. #[ts(type = "number | null")] pub started_at: Option<i64>, /// Unix timestamp (in seconds) when the turn completed. #[ts(type = "number | null")] pub completed_at: Option<i64>, /// Duration between turn start and completion in milliseconds, if known. #[ts(type = "number | null")] pub duration_ms: Option<i64>,}#[derive(Default, Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub enum TurnItemsView { /// `items` was not loaded for this turn. The field is intentionally empty. NotLoaded, /// `items` contains only a display summary for this turn. Summary, /// `items` contains every ThreadItem available from persisted app-server history for this turn. #[default] Full,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS, Error)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]#[error("{message}")]pub struct TurnError { pub message: String, pub codex_error_info: Option<CodexErrorInfo>, #[serde(default)] pub additional_details: Option<String>,}