Codex Handbook
app-server-protocol/src/protocol/v2/item.rs 1501 lines
use super::AdditionalPermissionProfile;use super::ExecPolicyAmendment;use super::McpToolCallError;use super::McpToolCallResult;use super::NetworkApprovalContext;use super::NetworkApprovalProtocol;use super::NetworkPolicyAmendment;use super::RequestPermissionProfile;use super::UserInput;use super::shared::v2_enum_from_core;use crate::protocol::item_builders::convert_patch_changes;use codex_experimental_api_macros::ExperimentalApi;use codex_protocol::approvals::GuardianAssessmentAction as CoreGuardianAssessmentAction;use codex_protocol::approvals::GuardianAssessmentDecisionSource as CoreGuardianAssessmentDecisionSource;use codex_protocol::approvals::GuardianCommandSource as CoreGuardianCommandSource;use codex_protocol::items::AgentMessageContent as CoreAgentMessageContent;use codex_protocol::items::McpToolCallStatus as CoreMcpToolCallStatus;use codex_protocol::items::TurnItem as CoreTurnItem;use codex_protocol::memory_citation::MemoryCitation as CoreMemoryCitation;use codex_protocol::memory_citation::MemoryCitationEntry as CoreMemoryCitationEntry;use codex_protocol::models::MessagePhase;use codex_protocol::models::ResponseItem;use codex_protocol::openai_models::ReasoningEffort;use codex_protocol::parse_command::ParsedCommand as CoreParsedCommand;use codex_protocol::protocol::AgentStatus as CoreAgentStatus;use codex_protocol::protocol::ExecCommandSource as CoreExecCommandSource;use codex_protocol::protocol::ExecCommandStatus as CoreExecCommandStatus;use codex_protocol::protocol::GuardianRiskLevel as CoreGuardianRiskLevel;use codex_protocol::protocol::GuardianUserAuthorization as CoreGuardianUserAuthorization;use codex_protocol::protocol::PatchApplyStatus as CorePatchApplyStatus;use codex_protocol::protocol::ReviewDecision as CoreReviewDecision;use codex_protocol::protocol::SubAgentActivityKind as CoreSubAgentActivityKind;use codex_utils_absolute_path::AbsolutePathBuf;use schemars::JsonSchema;use serde::Deserialize;use serde::Serialize;use serde_json::Value as JsonValue;use serde_with::serde_as;use std::collections::HashMap;use std::io;use std::path::PathBuf;use ts_rs::TS;#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub enum CommandExecutionApprovalDecision {    /// User approved the command.    Accept,    /// User approved the command and future prompts in the same session-scoped    /// approval cache should run without prompting.    AcceptForSession,    /// User approved the command, and wants to apply the proposed execpolicy amendment so future    /// matching commands can run without prompting.    AcceptWithExecpolicyAmendment {        execpolicy_amendment: ExecPolicyAmendment,    },    /// User chose a persistent network policy rule (allow/deny) for this host.    ApplyNetworkPolicyAmendment {        network_policy_amendment: NetworkPolicyAmendment,    },    /// User denied the command. The agent will continue the turn.    Decline,    /// User denied the command. The turn will also be immediately interrupted.    Cancel,}impl From<CoreReviewDecision> for CommandExecutionApprovalDecision {    fn from(value: CoreReviewDecision) -> Self {        match value {            CoreReviewDecision::Approved => Self::Accept,            CoreReviewDecision::ApprovedExecpolicyAmendment {                proposed_execpolicy_amendment,            } => Self::AcceptWithExecpolicyAmendment {                execpolicy_amendment: proposed_execpolicy_amendment.into(),            },            CoreReviewDecision::ApprovedForSession => Self::AcceptForSession,            CoreReviewDecision::NetworkPolicyAmendment {                network_policy_amendment,            } => Self::ApplyNetworkPolicyAmendment {                network_policy_amendment: network_policy_amendment.into(),            },            CoreReviewDecision::Abort => Self::Cancel,            CoreReviewDecision::Denied => Self::Decline,            CoreReviewDecision::TimedOut => Self::Decline,        }    }}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub enum FileChangeApprovalDecision {    /// User approved the file changes.    Accept,    /// User approved the file changes and future changes to the same files should run without prompting.    AcceptForSession,    /// User denied the file changes. The agent will continue the turn.    Decline,    /// User denied the file changes. The turn will also be immediately interrupted.    Cancel,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(tag = "type", rename_all = "camelCase")]#[ts(tag = "type")]#[ts(export_to = "v2/")]pub enum CommandAction {    Read {        command: String,        name: String,        path: AbsolutePathBuf,    },    ListFiles {        command: String,        path: Option<String>,    },    Search {        command: String,        query: Option<String>,        path: Option<String>,    },    Unknown {        command: String,    },}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct MemoryCitation {    pub entries: Vec<MemoryCitationEntry>,    pub thread_ids: Vec<String>,}impl From<CoreMemoryCitation> for MemoryCitation {    fn from(value: CoreMemoryCitation) -> Self {        Self {            entries: value.entries.into_iter().map(Into::into).collect(),            thread_ids: value.rollout_ids,        }    }}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct MemoryCitationEntry {    pub path: String,    pub line_start: u32,    pub line_end: u32,    pub note: String,}impl From<CoreMemoryCitationEntry> for MemoryCitationEntry {    fn from(value: CoreMemoryCitationEntry) -> Self {        Self {            path: value.path,            line_start: value.line_start,            line_end: value.line_end,            note: value.note,        }    }}impl CommandAction {    pub fn into_core(self) -> CoreParsedCommand {        match self {            CommandAction::Read {                command: cmd,                name,                path,            } => CoreParsedCommand::Read {                cmd,                name,                path: path.into_path_buf(),            },            CommandAction::ListFiles { command: cmd, path } => {                CoreParsedCommand::ListFiles { cmd, path }            }            CommandAction::Search {                command: cmd,                query,                path,            } => CoreParsedCommand::Search { cmd, query, path },            CommandAction::Unknown { command: cmd } => CoreParsedCommand::Unknown { cmd },        }    }    pub fn from_core_with_cwd(value: CoreParsedCommand, cwd: &AbsolutePathBuf) -> Self {        match value {            CoreParsedCommand::Read { cmd, name, path } => CommandAction::Read {                command: cmd,                name,                path: cwd.join(path),            },            CoreParsedCommand::ListFiles { cmd, path } => {                CommandAction::ListFiles { command: cmd, path }            }            CoreParsedCommand::Search { cmd, query, path } => CommandAction::Search {                command: cmd,                query,                path,            },            CoreParsedCommand::Unknown { cmd } => CommandAction::Unknown { command: cmd },        }    }}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(tag = "type", rename_all = "camelCase")]#[ts(tag = "type")]#[ts(export_to = "v2/")]pub enum ThreadItem {    #[serde(rename_all = "camelCase")]    #[ts(rename_all = "camelCase")]    UserMessage {        id: String,        client_id: Option<String>,        content: Vec<UserInput>,    },    #[serde(rename_all = "camelCase")]    #[ts(rename_all = "camelCase")]    HookPrompt {        id: String,        fragments: Vec<HookPromptFragment>,    },    #[serde(rename_all = "camelCase")]    #[ts(rename_all = "camelCase")]    AgentMessage {        id: String,        text: String,        #[serde(default)]        phase: Option<MessagePhase>,        #[serde(default)]        memory_citation: Option<MemoryCitation>,    },    #[serde(rename_all = "camelCase")]    #[ts(rename_all = "camelCase")]    /// EXPERIMENTAL - proposed plan item content. The completed plan item is    /// authoritative and may not match the concatenation of `PlanDelta` text.    Plan { id: String, text: String },    #[serde(rename_all = "camelCase")]    #[ts(rename_all = "camelCase")]    Reasoning {        id: String,        #[serde(default)]        summary: Vec<String>,        #[serde(default)]        content: Vec<String>,    },    #[serde(rename_all = "camelCase")]    #[ts(rename_all = "camelCase")]    CommandExecution {        id: String,        /// The command to be executed.        command: String,        /// The command's working directory.        cwd: AbsolutePathBuf,        /// Identifier for the underlying PTY process (when available).        process_id: Option<String>,        #[serde(default)]        source: CommandExecutionSource,        status: CommandExecutionStatus,        /// A best-effort parsing of the command to understand the action(s) it will perform.        /// This returns a list of CommandAction objects because a single shell command may        /// be composed of many commands piped together.        command_actions: Vec<CommandAction>,        /// The command's output, aggregated from stdout and stderr.        aggregated_output: Option<String>,        /// The command's exit code.        exit_code: Option<i32>,        /// The duration of the command execution in milliseconds.        #[ts(type = "number | null")]        duration_ms: Option<i64>,    },    #[serde(rename_all = "camelCase")]    #[ts(rename_all = "camelCase")]    FileChange {        id: String,        changes: Vec<FileUpdateChange>,        status: PatchApplyStatus,    },    #[serde(rename_all = "camelCase")]    #[ts(rename_all = "camelCase")]    McpToolCall {        id: String,        server: String,        tool: String,        status: McpToolCallStatus,        arguments: JsonValue,        #[serde(default, skip_serializing_if = "Option::is_none")]        #[ts(optional)]        mcp_app_resource_uri: Option<String>,        plugin_id: Option<String>,        result: Option<Box<McpToolCallResult>>,        error: Option<McpToolCallError>,        /// The duration of the MCP tool call in milliseconds.        #[ts(type = "number | null")]        duration_ms: Option<i64>,    },    #[serde(rename_all = "camelCase")]    #[ts(rename_all = "camelCase")]    DynamicToolCall {        id: String,        namespace: Option<String>,        tool: String,        arguments: JsonValue,        status: DynamicToolCallStatus,        content_items: Option<Vec<DynamicToolCallOutputContentItem>>,        success: Option<bool>,        /// The duration of the dynamic tool call in milliseconds.        #[ts(type = "number | null")]        duration_ms: Option<i64>,    },    #[serde(rename_all = "camelCase")]    #[ts(rename_all = "camelCase")]    CollabAgentToolCall {        /// Unique identifier for this collab tool call.        id: String,        /// Name of the collab tool that was invoked.        tool: CollabAgentTool,        /// Current status of the collab tool call.        status: CollabAgentToolCallStatus,        /// Thread ID of the agent issuing the collab request.        sender_thread_id: String,        /// Thread ID of the receiving agent, when applicable. In case of spawn operation,        /// this corresponds to the newly spawned agent.        receiver_thread_ids: Vec<String>,        /// Prompt text sent as part of the collab tool call, when available.        prompt: Option<String>,        /// Model requested for the spawned agent, when applicable.        model: Option<String>,        /// Reasoning effort requested for the spawned agent, when applicable.        reasoning_effort: Option<ReasoningEffort>,        /// Last known status of the target agents, when available.        agents_states: HashMap<String, CollabAgentState>,    },    #[serde(rename_all = "camelCase")]    #[ts(rename_all = "camelCase")]    SubAgentActivity {        id: String,        kind: SubAgentActivityKind,        agent_thread_id: String,        agent_path: String,    },    #[serde(rename_all = "camelCase")]    #[ts(rename_all = "camelCase")]    WebSearch {        id: String,        query: String,        action: Option<WebSearchAction>,    },    #[serde(rename_all = "camelCase")]    #[ts(rename_all = "camelCase")]    ImageView { id: String, path: AbsolutePathBuf },    #[serde(rename_all = "camelCase")]    #[ts(rename_all = "camelCase")]    Sleep {        id: String,        #[ts(type = "number")]        duration_ms: u64,    },    #[serde(rename_all = "camelCase")]    #[ts(rename_all = "camelCase")]    ImageGeneration {        id: String,        status: String,        revised_prompt: Option<String>,        result: String,        #[serde(default, skip_serializing_if = "Option::is_none")]        #[ts(optional)]        saved_path: Option<AbsolutePathBuf>,    },    #[serde(rename_all = "camelCase")]    #[ts(rename_all = "camelCase")]    EnteredReviewMode { id: String, review: String },    #[serde(rename_all = "camelCase")]    #[ts(rename_all = "camelCase")]    ExitedReviewMode { id: String, review: String },    #[serde(rename_all = "camelCase")]    #[ts(rename_all = "camelCase")]    ContextCompaction { id: String },}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(rename_all = "camelCase", export_to = "v2/")]pub struct HookPromptFragment {    pub text: String,    pub hook_run_id: String,}impl ThreadItem {    pub fn id(&self) -> &str {        match self {            ThreadItem::UserMessage { id, .. }            | ThreadItem::HookPrompt { id, .. }            | ThreadItem::AgentMessage { id, .. }            | ThreadItem::Plan { id, .. }            | ThreadItem::Reasoning { id, .. }            | ThreadItem::CommandExecution { id, .. }            | ThreadItem::FileChange { id, .. }            | ThreadItem::McpToolCall { id, .. }            | ThreadItem::DynamicToolCall { id, .. }            | ThreadItem::CollabAgentToolCall { id, .. }            | ThreadItem::SubAgentActivity { id, .. }            | ThreadItem::WebSearch { id, .. }            | ThreadItem::ImageView { id, .. }            | ThreadItem::Sleep { id, .. }            | ThreadItem::ImageGeneration { id, .. }            | ThreadItem::EnteredReviewMode { id, .. }            | ThreadItem::ExitedReviewMode { id, .. }            | ThreadItem::ContextCompaction { id, .. } => id,        }    }}#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]/// [UNSTABLE] Lifecycle state for an approval auto-review.pub enum GuardianApprovalReviewStatus {    InProgress,    Approved,    Denied,    TimedOut,    Aborted,}#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]/// [UNSTABLE] Source that produced a terminal approval auto-review decision.pub enum AutoReviewDecisionSource {    Agent,}impl From<CoreGuardianAssessmentDecisionSource> for AutoReviewDecisionSource {    fn from(value: CoreGuardianAssessmentDecisionSource) -> Self {        match value {            CoreGuardianAssessmentDecisionSource::Agent => Self::Agent,        }    }}#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]#[serde(rename_all = "lowercase")]#[ts(export_to = "v2/")]/// [UNSTABLE] Risk level assigned by approval auto-review.pub enum GuardianRiskLevel {    Low,    Medium,    High,    Critical,}impl From<CoreGuardianRiskLevel> for GuardianRiskLevel {    fn from(value: CoreGuardianRiskLevel) -> Self {        match value {            CoreGuardianRiskLevel::Low => Self::Low,            CoreGuardianRiskLevel::Medium => Self::Medium,            CoreGuardianRiskLevel::High => Self::High,            CoreGuardianRiskLevel::Critical => Self::Critical,        }    }}#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]#[serde(rename_all = "lowercase")]#[ts(export_to = "v2/")]/// [UNSTABLE] Authorization level assigned by approval auto-review.pub enum GuardianUserAuthorization {    Unknown,    Low,    Medium,    High,}impl From<CoreGuardianUserAuthorization> for GuardianUserAuthorization {    fn from(value: CoreGuardianUserAuthorization) -> Self {        match value {            CoreGuardianUserAuthorization::Unknown => Self::Unknown,            CoreGuardianUserAuthorization::Low => Self::Low,            CoreGuardianUserAuthorization::Medium => Self::Medium,            CoreGuardianUserAuthorization::High => Self::High,        }    }}/// [UNSTABLE] Temporary approval auto-review payload used by/// `item/autoApprovalReview/*` notifications. This shape is expected to change/// soon.#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct GuardianApprovalReview {    pub status: GuardianApprovalReviewStatus,    pub risk_level: Option<GuardianRiskLevel>,    pub user_authorization: Option<GuardianUserAuthorization>,    pub rationale: Option<String>,}#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub enum GuardianCommandSource {    Shell,    UnifiedExec,}impl From<CoreGuardianCommandSource> for GuardianCommandSource {    fn from(value: CoreGuardianCommandSource) -> Self {        match value {            CoreGuardianCommandSource::Shell => Self::Shell,            CoreGuardianCommandSource::UnifiedExec => Self::UnifiedExec,        }    }}impl From<GuardianCommandSource> for CoreGuardianCommandSource {    fn from(value: GuardianCommandSource) -> Self {        match value {            GuardianCommandSource::Shell => Self::Shell,            GuardianCommandSource::UnifiedExec => Self::UnifiedExec,        }    }}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct GuardianCommandReviewAction {    pub source: GuardianCommandSource,    pub command: String,    pub cwd: AbsolutePathBuf,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct GuardianExecveReviewAction {    pub source: GuardianCommandSource,    pub program: String,    pub argv: Vec<String>,    pub cwd: AbsolutePathBuf,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct GuardianApplyPatchReviewAction {    pub cwd: AbsolutePathBuf,    pub files: Vec<AbsolutePathBuf>,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct GuardianNetworkAccessReviewAction {    pub target: String,    pub host: String,    pub protocol: NetworkApprovalProtocol,    pub port: u16,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct GuardianMcpToolCallReviewAction {    pub server: String,    pub tool_name: String,    pub connector_id: Option<String>,    pub connector_name: Option<String>,    pub tool_title: Option<String>,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct GuardianRequestPermissionsReviewAction {    pub reason: Option<String>,    pub permissions: RequestPermissionProfile,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(tag = "type", rename_all = "camelCase")]#[ts(tag = "type", rename_all = "camelCase")]#[ts(export_to = "v2/")]pub enum GuardianApprovalReviewAction {    #[serde(rename_all = "camelCase")]    #[ts(rename_all = "camelCase")]    Command {        source: GuardianCommandSource,        command: String,        cwd: AbsolutePathBuf,    },    #[serde(rename_all = "camelCase")]    #[ts(rename_all = "camelCase")]    Execve {        source: GuardianCommandSource,        program: String,        argv: Vec<String>,        cwd: AbsolutePathBuf,    },    #[serde(rename_all = "camelCase")]    #[ts(rename_all = "camelCase")]    ApplyPatch {        cwd: AbsolutePathBuf,        files: Vec<AbsolutePathBuf>,    },    #[serde(rename_all = "camelCase")]    #[ts(rename_all = "camelCase")]    NetworkAccess {        target: String,        host: String,        protocol: NetworkApprovalProtocol,        port: u16,    },    #[serde(rename_all = "camelCase")]    #[ts(rename_all = "camelCase")]    McpToolCall {        server: String,        tool_name: String,        connector_id: Option<String>,        connector_name: Option<String>,        tool_title: Option<String>,    },    #[serde(rename_all = "camelCase")]    #[ts(rename_all = "camelCase")]    RequestPermissions {        reason: Option<String>,        permissions: RequestPermissionProfile,    },}impl From<CoreGuardianAssessmentAction> for GuardianApprovalReviewAction {    fn from(value: CoreGuardianAssessmentAction) -> Self {        match value {            CoreGuardianAssessmentAction::Command {                source,                command,                cwd,            } => Self::Command {                source: source.into(),                command,                cwd,            },            CoreGuardianAssessmentAction::Execve {                source,                program,                argv,                cwd,            } => Self::Execve {                source: source.into(),                program,                argv,                cwd,            },            CoreGuardianAssessmentAction::ApplyPatch { cwd, files } => {                Self::ApplyPatch { cwd, files }            }            CoreGuardianAssessmentAction::NetworkAccess {                target,                host,                protocol,                port,            } => Self::NetworkAccess {                target,                host,                protocol: protocol.into(),                port,            },            CoreGuardianAssessmentAction::McpToolCall {                server,                tool_name,                connector_id,                connector_name,                tool_title,            } => Self::McpToolCall {                server,                tool_name,                connector_id,                connector_name,                tool_title,            },            CoreGuardianAssessmentAction::RequestPermissions {                reason,                permissions,            } => Self::RequestPermissions {                reason,                permissions: permissions.into(),            },        }    }}impl TryFrom<GuardianApprovalReviewAction> for CoreGuardianAssessmentAction {    type Error = io::Error;    fn try_from(value: GuardianApprovalReviewAction) -> Result<Self, Self::Error> {        Ok(match value {            GuardianApprovalReviewAction::Command {                source,                command,                cwd,            } => Self::Command {                source: source.into(),                command,                cwd,            },            GuardianApprovalReviewAction::Execve {                source,                program,                argv,                cwd,            } => Self::Execve {                source: source.into(),                program,                argv,                cwd,            },            GuardianApprovalReviewAction::ApplyPatch { cwd, files } => {                Self::ApplyPatch { cwd, files }            }            GuardianApprovalReviewAction::NetworkAccess {                target,                host,                protocol,                port,            } => Self::NetworkAccess {                target,                host,                protocol: protocol.to_core(),                port,            },            GuardianApprovalReviewAction::McpToolCall {                server,                tool_name,                connector_id,                connector_name,                tool_title,            } => Self::McpToolCall {                server,                tool_name,                connector_id,                connector_name,                tool_title,            },            GuardianApprovalReviewAction::RequestPermissions {                reason,                permissions,            } => Self::RequestPermissions {                reason,                permissions: permissions.try_into()?,            },        })    }}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(tag = "type", rename_all = "camelCase")]#[ts(tag = "type", rename_all = "camelCase")]#[ts(export_to = "v2/")]pub enum WebSearchAction {    Search {        query: Option<String>,        queries: Option<Vec<String>>,    },    OpenPage {        url: Option<String>,    },    FindInPage {        url: Option<String>,        pattern: Option<String>,    },    #[serde(other)]    Other,}impl From<codex_protocol::models::WebSearchAction> for WebSearchAction {    fn from(value: codex_protocol::models::WebSearchAction) -> Self {        match value {            codex_protocol::models::WebSearchAction::Search { query, queries } => {                WebSearchAction::Search { query, queries }            }            codex_protocol::models::WebSearchAction::OpenPage { url } => {                WebSearchAction::OpenPage { url }            }            codex_protocol::models::WebSearchAction::FindInPage { url, pattern } => {                WebSearchAction::FindInPage { url, pattern }            }            codex_protocol::models::WebSearchAction::Other => WebSearchAction::Other,        }    }}impl From<CoreTurnItem> for ThreadItem {    fn from(value: CoreTurnItem) -> Self {        match value {            CoreTurnItem::UserMessage(user) => ThreadItem::UserMessage {                id: user.id,                client_id: user.client_id,                content: user.content.into_iter().map(UserInput::from).collect(),            },            CoreTurnItem::HookPrompt(hook_prompt) => ThreadItem::HookPrompt {                id: hook_prompt.id,                fragments: hook_prompt                    .fragments                    .into_iter()                    .map(HookPromptFragment::from)                    .collect(),            },            CoreTurnItem::AgentMessage(agent) => {                let text = agent                    .content                    .into_iter()                    .map(|entry| match entry {                        CoreAgentMessageContent::Text { text } => text,                    })                    .collect::<String>();                ThreadItem::AgentMessage {                    id: agent.id,                    text,                    phase: agent.phase,                    memory_citation: agent.memory_citation.map(Into::into),                }            }            CoreTurnItem::Plan(plan) => ThreadItem::Plan {                id: plan.id,                text: plan.text,            },            CoreTurnItem::Reasoning(reasoning) => ThreadItem::Reasoning {                id: reasoning.id,                summary: reasoning.summary_text,                content: reasoning.raw_content,            },            CoreTurnItem::WebSearch(search) => ThreadItem::WebSearch {                id: search.id,                query: search.query,                action: Some(WebSearchAction::from(search.action)),            },            CoreTurnItem::ImageView(image) => ThreadItem::ImageView {                id: image.id,                path: image.path,            },            CoreTurnItem::Sleep(sleep) => ThreadItem::Sleep {                id: sleep.id,                duration_ms: sleep.duration_ms,            },            CoreTurnItem::ImageGeneration(image) => ThreadItem::ImageGeneration {                id: image.id,                status: image.status,                revised_prompt: image.revised_prompt,                result: image.result,                saved_path: image.saved_path,            },            CoreTurnItem::FileChange(file_change) => ThreadItem::FileChange {                id: file_change.id,                changes: convert_patch_changes(&file_change.changes),                status: file_change                    .status                    .as_ref()                    .map(PatchApplyStatus::from)                    .unwrap_or(PatchApplyStatus::InProgress),            },            CoreTurnItem::McpToolCall(mcp) => {                let duration_ms = mcp                    .duration                    .and_then(|duration| i64::try_from(duration.as_millis()).ok());                ThreadItem::McpToolCall {                    id: mcp.id,                    server: mcp.server,                    tool: mcp.tool,                    status: McpToolCallStatus::from(mcp.status),                    arguments: mcp.arguments,                    mcp_app_resource_uri: mcp.mcp_app_resource_uri,                    plugin_id: mcp.plugin_id,                    result: mcp.result.map(McpToolCallResult::from).map(Box::new),                    error: mcp.error.map(McpToolCallError::from),                    duration_ms,                }            }            CoreTurnItem::ContextCompaction(compaction) => {                ThreadItem::ContextCompaction { id: compaction.id }            }        }    }}impl From<codex_protocol::items::HookPromptFragment> for HookPromptFragment {    fn from(value: codex_protocol::items::HookPromptFragment) -> Self {        Self {            text: value.text,            hook_run_id: value.hook_run_id,        }    }}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub enum CommandExecutionStatus {    InProgress,    Completed,    Failed,    Declined,}impl From<CoreExecCommandStatus> for CommandExecutionStatus {    fn from(value: CoreExecCommandStatus) -> Self {        Self::from(&value)    }}impl From<&CoreExecCommandStatus> for CommandExecutionStatus {    fn from(value: &CoreExecCommandStatus) -> Self {        match value {            CoreExecCommandStatus::Completed => CommandExecutionStatus::Completed,            CoreExecCommandStatus::Failed => CommandExecutionStatus::Failed,            CoreExecCommandStatus::Declined => CommandExecutionStatus::Declined,        }    }}v2_enum_from_core! {    #[derive(Default)]    pub enum CommandExecutionSource from CoreExecCommandSource {        #[default]        Agent,        UserShell,        UnifiedExecStartup,        UnifiedExecInteraction,    }}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub enum CollabAgentTool {    SpawnAgent,    SendInput,    ResumeAgent,    Wait,    CloseAgent,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct FileUpdateChange {    pub path: String,    pub kind: PatchChangeKind,    pub diff: String,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(tag = "type", rename_all = "camelCase")]#[ts(tag = "type")]#[ts(export_to = "v2/")]pub enum PatchChangeKind {    Add,    Delete,    Update { move_path: Option<PathBuf> },}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub enum PatchApplyStatus {    InProgress,    Completed,    Failed,    Declined,}impl From<CorePatchApplyStatus> for PatchApplyStatus {    fn from(value: CorePatchApplyStatus) -> Self {        Self::from(&value)    }}impl From<&CorePatchApplyStatus> for PatchApplyStatus {    fn from(value: &CorePatchApplyStatus) -> Self {        match value {            CorePatchApplyStatus::Completed => PatchApplyStatus::Completed,            CorePatchApplyStatus::Failed => PatchApplyStatus::Failed,            CorePatchApplyStatus::Declined => PatchApplyStatus::Declined,        }    }}impl From<CoreMcpToolCallStatus> for McpToolCallStatus {    fn from(value: CoreMcpToolCallStatus) -> Self {        match value {            CoreMcpToolCallStatus::InProgress => McpToolCallStatus::InProgress,            CoreMcpToolCallStatus::Completed => McpToolCallStatus::Completed,            CoreMcpToolCallStatus::Failed => McpToolCallStatus::Failed,        }    }}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub enum McpToolCallStatus {    InProgress,    Completed,    Failed,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub enum DynamicToolCallStatus {    InProgress,    Completed,    Failed,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub enum CollabAgentToolCallStatus {    InProgress,    Completed,    Failed,}#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub enum SubAgentActivityKind {    Started,    Interacted,    Interrupted,}impl From<CoreSubAgentActivityKind> for SubAgentActivityKind {    fn from(value: CoreSubAgentActivityKind) -> Self {        match value {            CoreSubAgentActivityKind::Started => SubAgentActivityKind::Started,            CoreSubAgentActivityKind::Interacted => SubAgentActivityKind::Interacted,            CoreSubAgentActivityKind::Interrupted => SubAgentActivityKind::Interrupted,        }    }}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub enum CollabAgentStatus {    PendingInit,    Running,    Interrupted,    Completed,    Errored,    Shutdown,    NotFound,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct CollabAgentState {    pub status: CollabAgentStatus,    pub message: Option<String>,}impl From<CoreAgentStatus> for CollabAgentState {    fn from(value: CoreAgentStatus) -> Self {        match value {            CoreAgentStatus::PendingInit => Self {                status: CollabAgentStatus::PendingInit,                message: None,            },            CoreAgentStatus::Running => Self {                status: CollabAgentStatus::Running,                message: None,            },            CoreAgentStatus::Interrupted => Self {                status: CollabAgentStatus::Interrupted,                message: None,            },            CoreAgentStatus::Completed(message) => Self {                status: CollabAgentStatus::Completed,                message,            },            CoreAgentStatus::Errored(message) => Self {                status: CollabAgentStatus::Errored,                message: Some(message),            },            CoreAgentStatus::Shutdown => Self {                status: CollabAgentStatus::Shutdown,                message: None,            },            CoreAgentStatus::NotFound => Self {                status: CollabAgentStatus::NotFound,                message: None,            },        }    }}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct ItemStartedNotification {    pub item: ThreadItem,    pub thread_id: String,    pub turn_id: String,    /// Unix timestamp (in milliseconds) when this item lifecycle started.    #[ts(type = "number")]    pub started_at_ms: i64,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]/// [UNSTABLE] Temporary notification payload for approval auto-review. This/// shape is expected to change soon.pub struct ItemGuardianApprovalReviewStartedNotification {    pub thread_id: String,    pub turn_id: String,    /// Unix timestamp (in milliseconds) when this review started.    #[ts(type = "number")]    pub started_at_ms: i64,    /// Stable identifier for this review.    pub review_id: String,    /// Identifier for the reviewed item or tool call when one exists.    ///    /// In most cases, one review maps to one target item. The exceptions are    /// - execve reviews, where a single command may contain multiple execve    ///   calls to review (only possible when using the shell_zsh_fork feature)    /// - network policy reviews, where there is no target item    ///    /// A network call is triggered by a CommandExecution item, so having a    /// target_item_id set to the CommandExecution item would be misleading    /// because the review is about the network call, not the command execution.    /// Therefore, target_item_id is set to None for network policy reviews.    pub target_item_id: Option<String>,    pub review: GuardianApprovalReview,    pub action: GuardianApprovalReviewAction,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]/// [UNSTABLE] Temporary notification payload for approval auto-review. This/// shape is expected to change soon.pub struct ItemGuardianApprovalReviewCompletedNotification {    pub thread_id: String,    pub turn_id: String,    /// Unix timestamp (in milliseconds) when this review started.    #[ts(type = "number")]    pub started_at_ms: i64,    /// Unix timestamp (in milliseconds) when this review completed.    #[ts(type = "number")]    pub completed_at_ms: i64,    /// Stable identifier for this review.    pub review_id: String,    /// Identifier for the reviewed item or tool call when one exists.    ///    /// In most cases, one review maps to one target item. The exceptions are    /// - execve reviews, where a single command may contain multiple execve    ///   calls to review (only possible when using the shell_zsh_fork feature)    /// - network policy reviews, where there is no target item    ///    /// A network call is triggered by a CommandExecution item, so having a    /// target_item_id set to the CommandExecution item would be misleading    /// because the review is about the network call, not the command execution.    /// Therefore, target_item_id is set to None for network policy reviews.    pub target_item_id: Option<String>,    pub decision_source: AutoReviewDecisionSource,    pub review: GuardianApprovalReview,    pub action: GuardianApprovalReviewAction,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct ItemCompletedNotification {    pub item: ThreadItem,    pub thread_id: String,    pub turn_id: String,    /// Unix timestamp (in milliseconds) when this item lifecycle completed.    #[ts(type = "number")]    pub completed_at_ms: i64,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct RawResponseItemCompletedNotification {    pub thread_id: String,    pub turn_id: String,    pub item: ResponseItem,}// Item-specific progress notifications#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct AgentMessageDeltaNotification {    pub thread_id: String,    pub turn_id: String,    pub item_id: String,    pub delta: String,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]/// EXPERIMENTAL - proposed plan streaming deltas for plan items. Clients should/// not assume concatenated deltas match the completed plan item content.pub struct PlanDeltaNotification {    pub thread_id: String,    pub turn_id: String,    pub item_id: String,    pub delta: String,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct ReasoningSummaryTextDeltaNotification {    pub thread_id: String,    pub turn_id: String,    pub item_id: String,    pub delta: String,    #[ts(type = "number")]    pub summary_index: i64,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct ReasoningSummaryPartAddedNotification {    pub thread_id: String,    pub turn_id: String,    pub item_id: String,    #[ts(type = "number")]    pub summary_index: i64,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct ReasoningTextDeltaNotification {    pub thread_id: String,    pub turn_id: String,    pub item_id: String,    pub delta: String,    #[ts(type = "number")]    pub content_index: i64,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct TerminalInteractionNotification {    pub thread_id: String,    pub turn_id: String,    pub item_id: String,    pub process_id: String,    pub stdin: String,}#[serde_as]#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct CommandExecutionOutputDeltaNotification {    pub thread_id: String,    pub turn_id: String,    pub item_id: String,    pub delta: String,}/// Deprecated legacy notification for `apply_patch` textual output.////// The server no longer emits this notification.#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct FileChangeOutputDeltaNotification {    pub thread_id: String,    pub turn_id: String,    pub item_id: String,    pub delta: String,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct FileChangePatchUpdatedNotification {    pub thread_id: String,    pub turn_id: String,    pub item_id: String,    pub changes: Vec<FileUpdateChange>,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS, ExperimentalApi)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct CommandExecutionRequestApprovalParams {    pub thread_id: String,    pub turn_id: String,    pub item_id: String,    /// Unix timestamp (in milliseconds) when this approval request started.    #[ts(type = "number")]    pub started_at_ms: i64,    /// Unique identifier for this specific approval callback.    ///    /// For regular shell/unified_exec approvals, this is null.    ///    /// For zsh-exec-bridge subcommand approvals, multiple callbacks can belong to    /// one parent `itemId`, so `approvalId` is a distinct opaque callback id    /// (a UUID) used to disambiguate routing.    #[serde(default, skip_serializing_if = "Option::is_none")]    #[ts(optional = nullable)]    pub approval_id: Option<String>,    /// Optional explanatory reason (e.g. request for network access).    #[serde(default, skip_serializing_if = "Option::is_none")]    #[ts(optional = nullable)]    pub reason: Option<String>,    /// Optional context for a managed-network approval prompt.    #[serde(default, skip_serializing_if = "Option::is_none")]    #[ts(optional = nullable)]    pub network_approval_context: Option<NetworkApprovalContext>,    /// The command to be executed.    #[serde(default, skip_serializing_if = "Option::is_none")]    #[ts(optional = nullable)]    pub command: Option<String>,    /// The command's working directory.    #[serde(default, skip_serializing_if = "Option::is_none")]    #[ts(optional = nullable)]    pub cwd: Option<AbsolutePathBuf>,    /// Best-effort parsed command actions for friendly display.    #[serde(default, skip_serializing_if = "Option::is_none")]    #[ts(optional = nullable)]    pub command_actions: Option<Vec<CommandAction>>,    /// Optional additional permissions requested for this command.    #[experimental("item/commandExecution/requestApproval.additionalPermissions")]    #[serde(default, skip_serializing_if = "Option::is_none")]    #[ts(optional = nullable)]    pub additional_permissions: Option<AdditionalPermissionProfile>,    /// Optional proposed execpolicy amendment to allow similar commands without prompting.    #[serde(default, skip_serializing_if = "Option::is_none")]    #[ts(optional = nullable)]    pub proposed_execpolicy_amendment: Option<ExecPolicyAmendment>,    /// Optional proposed network policy amendments (allow/deny host) for future requests.    #[serde(default, skip_serializing_if = "Option::is_none")]    #[ts(optional = nullable)]    pub proposed_network_policy_amendments: Option<Vec<NetworkPolicyAmendment>>,    /// Ordered list of decisions the client may present for this prompt.    #[experimental("item/commandExecution/requestApproval.availableDecisions")]    #[serde(default, skip_serializing_if = "Option::is_none")]    #[ts(optional = nullable)]    pub available_decisions: Option<Vec<CommandExecutionApprovalDecision>>,}impl CommandExecutionRequestApprovalParams {    pub fn strip_experimental_fields(&mut self) {        // TODO: Avoid hardcoding individual experimental fields here.        // We need a generic outbound compatibility design for stripping or        // otherwise handling experimental server->client payloads.        self.additional_permissions = None;    }}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct CommandExecutionRequestApprovalResponse {    pub decision: CommandExecutionApprovalDecision,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct FileChangeRequestApprovalParams {    pub thread_id: String,    pub turn_id: String,    pub item_id: String,    /// Unix timestamp (in milliseconds) when this approval request started.    #[ts(type = "number")]    pub started_at_ms: i64,    /// Optional explanatory reason (e.g. request for extra write access).    #[ts(optional = nullable)]    pub reason: Option<String>,    /// [UNSTABLE] When set, the agent is asking the user to allow writes under this root    /// for the remainder of the session (unclear if this is honored today).    #[ts(optional = nullable)]    pub grant_root: Option<PathBuf>,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[ts(export_to = "v2/")]pub struct FileChangeRequestApprovalResponse {    pub decision: FileChangeApprovalDecision,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct DynamicToolCallParams {    pub thread_id: String,    pub turn_id: String,    pub call_id: String,    pub namespace: Option<String>,    pub tool: String,    pub arguments: JsonValue,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct DynamicToolCallResponse {    pub content_items: Vec<DynamicToolCallOutputContentItem>,    pub success: bool,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(tag = "type", rename_all = "camelCase")]#[ts(tag = "type")]#[ts(export_to = "v2/")]pub enum DynamicToolCallOutputContentItem {    #[serde(rename_all = "camelCase")]    InputText { text: String },    #[serde(rename_all = "camelCase")]    InputImage { image_url: String },}impl From<DynamicToolCallOutputContentItem>    for codex_protocol::dynamic_tools::DynamicToolCallOutputContentItem{    fn from(item: DynamicToolCallOutputContentItem) -> Self {        match item {            DynamicToolCallOutputContentItem::InputText { text } => Self::InputText { text },            DynamicToolCallOutputContentItem::InputImage { image_url } => {                Self::InputImage { image_url }            }        }    }}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]/// EXPERIMENTAL. Defines a single selectable option for request_user_input.pub struct ToolRequestUserInputOption {    pub label: String,    pub description: String,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]/// EXPERIMENTAL. Represents one request_user_input question and its required options.pub struct ToolRequestUserInputQuestion {    pub id: String,    pub header: String,    pub question: String,    #[serde(default)]    pub is_other: bool,    #[serde(default)]    pub is_secret: bool,    pub options: Option<Vec<ToolRequestUserInputOption>>,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]/// EXPERIMENTAL. Params sent with a request_user_input event.pub struct ToolRequestUserInputParams {    pub thread_id: String,    pub turn_id: String,    pub item_id: String,    pub questions: Vec<ToolRequestUserInputQuestion>,    #[serde(default)]    #[ts(type = "number | null")]    pub auto_resolution_ms: Option<u64>,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]/// EXPERIMENTAL. Captures a user's answer to a request_user_input question.pub struct ToolRequestUserInputAnswer {    pub answers: Vec<String>,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]/// EXPERIMENTAL. Response payload mapping question ids to answers.pub struct ToolRequestUserInputResponse {    pub answers: HashMap<String, ToolRequestUserInputAnswer>,}