codex-app-server-sdk 0.5.1

Tokio Rust SDK for Codex App Server
Documentation
use serde_json::Value;

use crate::error::ClientError;
use crate::protocol::notifications as n;
use crate::protocol::server_requests as sr;
use crate::protocol::shared::RequestId;

#[derive(Debug, Clone)]
pub enum ServerEvent {
    Notification(ServerNotification),
    ServerRequest(ServerRequestEvent),
    TransportClosed,
}

#[derive(Debug, Clone)]
pub enum ServerNotification {
    Error(n::ErrorNotification),
    ThreadStarted(n::ThreadStartedNotification),
    ThreadArchived(n::ThreadLifecycleNotification),
    ThreadUnarchived(n::ThreadLifecycleNotification),
    ThreadClosed(n::ThreadLifecycleNotification),
    ThreadNameUpdated(n::ThreadNameUpdatedNotification),
    ThreadStatusChanged(n::ThreadStatusChangedNotification),
    ThreadTokenUsageUpdated(n::ThreadTokenUsageUpdatedNotification),
    TurnStarted(n::TurnStartedNotification),
    TurnCompleted(n::TurnCompletedNotification),
    TurnDiffUpdated(n::TurnDiffUpdatedNotification),
    TurnPlanUpdated(n::TurnPlanUpdatedNotification),
    ItemStarted(n::ItemLifecycleNotification),
    ItemCompleted(n::ItemLifecycleNotification),
    RawResponseItemCompleted(n::RawResponseItemCompletedNotification),
    ItemAgentMessageDelta(n::DeltaNotification),
    ItemPlanDelta(n::DeltaNotification),
    ItemCommandExecutionOutputDelta(n::DeltaNotification),
    ItemCommandExecutionTerminalInteraction(n::DeltaNotification),
    ItemFileChangeOutputDelta(n::DeltaNotification),
    ItemMcpToolCallProgress(n::DeltaNotification),
    ItemReasoningSummaryTextDelta(n::DeltaNotification),
    ItemReasoningSummaryPartAdded(n::DeltaNotification),
    ItemReasoningTextDelta(n::DeltaNotification),
    McpServerOauthLoginCompleted(n::McpServerOauthLoginCompletedNotification),
    AccountUpdated(n::AccountUpdatedNotification),
    AccountRateLimitsUpdated(n::AccountRateLimitsUpdatedNotification),
    AppListUpdated(n::AppListUpdatedNotification),
    ContextCompacted(n::DeltaNotification),
    DeprecationNotice(n::DeprecationNoticeNotification),
    ConfigWarning(n::ConfigWarningNotification),
    WindowsWorldWritableWarning(n::WindowsWorldWritableWarningNotification),
    WindowsSandboxSetupCompleted(n::WindowsSandboxSetupCompletedNotification),
    AccountLoginCompleted(n::AccountLoginCompletedNotification),
    AuthStatusChange(n::AuthStatusChangeNotification),
    LoginChatGptComplete(n::LoginChatGptCompleteNotification),
    SessionConfigured(n::SessionConfiguredNotification),
    FuzzyFileSearchSessionUpdated(n::FuzzyFileSearchSessionUpdatedNotification),
    FuzzyFileSearchSessionCompleted(n::FuzzyFileSearchSessionCompletedNotification),
    ServerRequestResolved(n::ServerRequestResolvedNotification),
    Unknown { method: String, params: Value },
}

#[derive(Debug, Clone)]
pub enum ServerRequestEvent {
    ChatgptAuthTokensRefresh {
        id: RequestId,
        params: sr::ChatgptAuthTokensRefreshParams,
    },
    ApplyPatchApproval {
        id: RequestId,
        params: sr::ApplyPatchApprovalParams,
    },
    ExecCommandApproval {
        id: RequestId,
        params: sr::ExecCommandApprovalParams,
    },
    CommandExecutionRequestApproval {
        id: RequestId,
        params: sr::CommandExecutionRequestApprovalParams,
    },
    FileChangeRequestApproval {
        id: RequestId,
        params: sr::FileChangeRequestApprovalParams,
    },
    ToolRequestUserInput {
        id: RequestId,
        params: sr::ToolRequestUserInputParams,
    },
    DynamicToolCall {
        id: RequestId,
        params: sr::DynamicToolCallParams,
    },
    Unknown {
        id: RequestId,
        method: String,
        params: Value,
    },
}

fn decode<T: serde::de::DeserializeOwned>(params: Value) -> Result<T, ClientError> {
    serde_json::from_value(params).map_err(ClientError::Serialization)
}

pub fn parse_notification(
    method: String,
    params: Value,
) -> Result<ServerNotification, ClientError> {
    let event = match method.as_str() {
        "error" => ServerNotification::Error(decode(params)?),
        "thread/started" => ServerNotification::ThreadStarted(decode(params)?),
        "thread/archived" => ServerNotification::ThreadArchived(decode(params)?),
        "thread/unarchived" => ServerNotification::ThreadUnarchived(decode(params)?),
        "thread/closed" => ServerNotification::ThreadClosed(decode(params)?),
        "thread/name/updated" => ServerNotification::ThreadNameUpdated(decode(params)?),
        "thread/status/changed" => ServerNotification::ThreadStatusChanged(decode(params)?),
        "thread/tokenUsage/updated" => ServerNotification::ThreadTokenUsageUpdated(decode(params)?),
        "turn/started" => ServerNotification::TurnStarted(decode(params)?),
        "turn/completed" => ServerNotification::TurnCompleted(decode(params)?),
        "turn/diff/updated" => ServerNotification::TurnDiffUpdated(decode(params)?),
        "turn/plan/updated" => ServerNotification::TurnPlanUpdated(decode(params)?),
        "item/started" => ServerNotification::ItemStarted(decode(params)?),
        "item/completed" => ServerNotification::ItemCompleted(decode(params)?),
        "rawResponseItem/completed" => {
            ServerNotification::RawResponseItemCompleted(decode(params)?)
        }
        "item/agentMessage/delta" => ServerNotification::ItemAgentMessageDelta(decode(params)?),
        "item/plan/delta" => ServerNotification::ItemPlanDelta(decode(params)?),
        "item/commandExecution/outputDelta" => {
            ServerNotification::ItemCommandExecutionOutputDelta(decode(params)?)
        }
        "item/commandExecution/terminalInteraction" => {
            ServerNotification::ItemCommandExecutionTerminalInteraction(decode(params)?)
        }
        "item/fileChange/outputDelta" => {
            ServerNotification::ItemFileChangeOutputDelta(decode(params)?)
        }
        "item/mcpToolCall/progress" => ServerNotification::ItemMcpToolCallProgress(decode(params)?),
        "item/reasoning/summaryTextDelta" => {
            ServerNotification::ItemReasoningSummaryTextDelta(decode(params)?)
        }
        "item/reasoning/summaryPartAdded" => {
            ServerNotification::ItemReasoningSummaryPartAdded(decode(params)?)
        }
        "item/reasoning/textDelta" => ServerNotification::ItemReasoningTextDelta(decode(params)?),
        "mcpServer/oauthLogin/completed" => {
            ServerNotification::McpServerOauthLoginCompleted(decode(params)?)
        }
        "account/updated" => ServerNotification::AccountUpdated(decode(params)?),
        "account/rateLimits/updated" => {
            ServerNotification::AccountRateLimitsUpdated(decode(params)?)
        }
        "app/list/updated" => ServerNotification::AppListUpdated(decode(params)?),
        "thread/compacted" => ServerNotification::ContextCompacted(decode(params)?),
        "deprecationNotice" => ServerNotification::DeprecationNotice(decode(params)?),
        "configWarning" => ServerNotification::ConfigWarning(decode(params)?),
        "windows/worldWritableWarning" => {
            ServerNotification::WindowsWorldWritableWarning(decode(params)?)
        }
        "windowsSandbox/setupCompleted" => {
            ServerNotification::WindowsSandboxSetupCompleted(decode(params)?)
        }
        "account/login/completed" => ServerNotification::AccountLoginCompleted(decode(params)?),
        "authStatusChange" => ServerNotification::AuthStatusChange(decode(params)?),
        "loginChatGptComplete" => ServerNotification::LoginChatGptComplete(decode(params)?),
        "sessionConfigured" => ServerNotification::SessionConfigured(decode(params)?),
        "fuzzyFileSearch/sessionUpdated" => {
            ServerNotification::FuzzyFileSearchSessionUpdated(decode(params)?)
        }
        "fuzzyFileSearch/sessionCompleted" => {
            ServerNotification::FuzzyFileSearchSessionCompleted(decode(params)?)
        }
        "serverRequest/resolved" => ServerNotification::ServerRequestResolved(decode(params)?),
        _ => ServerNotification::Unknown { method, params },
    };
    Ok(event)
}

pub fn parse_server_request(
    id: RequestId,
    method: String,
    params: Value,
) -> Result<ServerRequestEvent, ClientError> {
    let req = match method.as_str() {
        "account/chatgptAuthTokens/refresh" => ServerRequestEvent::ChatgptAuthTokensRefresh {
            id,
            params: decode(params)?,
        },
        "applyPatchApproval" => ServerRequestEvent::ApplyPatchApproval {
            id,
            params: decode(params)?,
        },
        "execCommandApproval" => ServerRequestEvent::ExecCommandApproval {
            id,
            params: decode(params)?,
        },
        "item/commandExecution/requestApproval" => {
            ServerRequestEvent::CommandExecutionRequestApproval {
                id,
                params: decode(params)?,
            }
        }
        "item/fileChange/requestApproval" => ServerRequestEvent::FileChangeRequestApproval {
            id,
            params: decode(params)?,
        },
        "item/tool/requestUserInput" => ServerRequestEvent::ToolRequestUserInput {
            id,
            params: decode(params)?,
        },
        "item/tool/call" => ServerRequestEvent::DynamicToolCall {
            id,
            params: decode(params)?,
        },
        _ => ServerRequestEvent::Unknown { id, method, params },
    };
    Ok(req)
}