use crate::events::AppServerRpcTransport; use crate::events::CodexRuntimeMetadata; use crate::events::GuardianReviewEventParams; use codex_app_server_protocol::ClientRequest; use codex_app_server_protocol::ClientResponse; use codex_app_server_protocol::InitializeParams; use codex_app_server_protocol::JSONRPCErrorError; use codex_app_server_protocol::RequestId; use codex_app_server_protocol::ServerNotification; use codex_plugin::PluginTelemetryMetadata; use codex_protocol::config_types::ApprovalsReviewer; use codex_protocol::config_types::ModeKind; use codex_protocol::config_types::Personality; use codex_protocol::config_types::ReasoningSummary; use codex_protocol::config_types::ServiceTier; use codex_protocol::openai_models::ReasoningEffort; use codex_protocol::protocol::AskForApproval; use codex_protocol::protocol::SandboxPolicy; use codex_protocol::protocol::SessionSource; use codex_protocol::protocol::SkillScope; use codex_protocol::protocol::SubAgentSource; use codex_protocol::protocol::TokenUsage; use serde::Serialize; use std::path::PathBuf; #[derive(Clone)] pub struct TrackEventsContext { pub model_slug: String, pub thread_id: String, pub turn_id: String, } pub fn build_track_events_context( model_slug: String, thread_id: String, turn_id: String, ) -> TrackEventsContext { TrackEventsContext { model_slug, thread_id, turn_id, } } #[derive(Clone, Copy, Debug, Serialize)] #[serde(rename_all = "snake_case")] pub enum TurnSubmissionType { Default, Queued, } #[derive(Clone)] pub struct TurnResolvedConfigFact { pub turn_id: String, pub thread_id: String, pub num_input_images: usize, pub submission_type: Option, pub ephemeral: bool, pub session_source: SessionSource, pub model: String, pub model_provider: String, pub sandbox_policy: SandboxPolicy, pub reasoning_effort: Option, pub reasoning_summary: Option, pub service_tier: Option, pub approval_policy: AskForApproval, pub approvals_reviewer: ApprovalsReviewer, pub sandbox_network_access: bool, pub collaboration_mode: ModeKind, pub personality: Option, pub is_first_turn: bool, } #[derive(Clone, Copy, Debug, Serialize)] #[serde(rename_all = "snake_case")] pub enum ThreadInitializationMode { New, Forked, Resumed, } #[derive(Clone)] pub struct TurnTokenUsageFact { pub turn_id: String, pub thread_id: String, pub token_usage: TokenUsage, } #[derive(Clone, Copy, Debug, Serialize)] #[serde(rename_all = "snake_case")] pub enum TurnStatus { Completed, Failed, Interrupted, } #[derive(Clone, Copy, Debug, Serialize)] #[serde(rename_all = "snake_case")] pub enum TurnSteerResult { Accepted, Rejected, } #[derive(Clone, Copy, Debug, Serialize)] #[serde(rename_all = "snake_case")] pub enum TurnSteerRejectionReason { NoActiveTurn, ExpectedTurnMismatch, NonSteerableReview, NonSteerableCompact, EmptyInput, InputTooLarge, } #[derive(Clone)] pub struct CodexTurnSteerEvent { pub expected_turn_id: Option, pub accepted_turn_id: Option, pub num_input_images: usize, pub result: TurnSteerResult, pub rejection_reason: Option, pub created_at: u64, } #[derive(Clone, Copy, Debug)] pub enum AnalyticsJsonRpcError { TurnSteer(TurnSteerRequestError), Input(InputError), } #[derive(Clone, Copy, Debug)] pub enum TurnSteerRequestError { NoActiveTurn, ExpectedTurnMismatch, NonSteerableReview, NonSteerableCompact, } #[derive(Clone, Copy, Debug)] pub enum InputError { Empty, TooLarge, } impl From for TurnSteerRejectionReason { fn from(error: TurnSteerRequestError) -> Self { match error { TurnSteerRequestError::NoActiveTurn => Self::NoActiveTurn, TurnSteerRequestError::ExpectedTurnMismatch => Self::ExpectedTurnMismatch, TurnSteerRequestError::NonSteerableReview => Self::NonSteerableReview, TurnSteerRequestError::NonSteerableCompact => Self::NonSteerableCompact, } } } impl From for TurnSteerRejectionReason { fn from(error: InputError) -> Self { match error { InputError::Empty => Self::EmptyInput, InputError::TooLarge => Self::InputTooLarge, } } } #[derive(Clone, Debug)] pub struct SkillInvocation { pub skill_name: String, pub skill_scope: SkillScope, pub skill_path: PathBuf, pub invocation_type: InvocationType, } #[derive(Clone, Copy, Debug, Serialize)] #[serde(rename_all = "lowercase")] pub enum InvocationType { Explicit, Implicit, } pub struct AppInvocation { pub connector_id: Option, pub app_name: Option, pub invocation_type: Option, } #[derive(Clone)] pub struct SubAgentThreadStartedInput { pub thread_id: String, pub parent_thread_id: Option, pub product_client_id: String, pub client_name: String, pub client_version: String, pub model: String, pub ephemeral: bool, pub subagent_source: SubAgentSource, pub created_at: u64, } #[derive(Clone, Copy, Debug, Serialize)] #[serde(rename_all = "snake_case")] pub enum CompactionTrigger { Manual, Auto, } #[derive(Clone, Copy, Debug, Serialize)] #[serde(rename_all = "snake_case")] pub enum CompactionReason { UserRequested, ContextLimit, ModelDownshift, } #[derive(Clone, Copy, Debug, Serialize)] #[serde(rename_all = "snake_case")] pub enum CompactionImplementation { Responses, ResponsesCompact, } #[derive(Clone, Copy, Debug, Serialize)] #[serde(rename_all = "snake_case")] pub enum CompactionPhase { StandaloneTurn, PreTurn, MidTurn, } #[derive(Clone, Copy, Debug, Serialize)] #[serde(rename_all = "snake_case")] pub enum CompactionStrategy { Memento, PrefixCompaction, } #[derive(Clone, Copy, Debug, Serialize)] #[serde(rename_all = "snake_case")] pub enum CompactionStatus { Completed, Failed, Interrupted, } #[derive(Clone)] pub struct CodexCompactionEvent { pub thread_id: String, pub turn_id: String, pub trigger: CompactionTrigger, pub reason: CompactionReason, pub implementation: CompactionImplementation, pub phase: CompactionPhase, pub strategy: CompactionStrategy, pub status: CompactionStatus, pub error: Option, pub active_context_tokens_before: i64, pub active_context_tokens_after: i64, pub started_at: u64, pub completed_at: u64, pub duration_ms: Option, } #[allow(dead_code)] pub(crate) enum AnalyticsFact { Initialize { connection_id: u64, params: InitializeParams, product_client_id: String, runtime: CodexRuntimeMetadata, rpc_transport: AppServerRpcTransport, }, Request { connection_id: u64, request_id: RequestId, request: Box, }, Response { connection_id: u64, response: Box, }, ErrorResponse { connection_id: u64, request_id: RequestId, error: JSONRPCErrorError, error_type: Option, }, Notification(Box), // Facts that do not naturally exist on the app-server protocol surface, or // would require non-trivial protocol reshaping on this branch. Custom(CustomAnalyticsFact), } pub(crate) enum CustomAnalyticsFact { SubAgentThreadStarted(SubAgentThreadStartedInput), Compaction(Box), GuardianReview(Box), TurnResolvedConfig(Box), TurnTokenUsage(Box), SkillInvoked(SkillInvokedInput), AppMentioned(AppMentionedInput), AppUsed(AppUsedInput), PluginUsed(PluginUsedInput), PluginStateChanged(PluginStateChangedInput), } pub(crate) struct SkillInvokedInput { pub tracking: TrackEventsContext, pub invocations: Vec, } pub(crate) struct AppMentionedInput { pub tracking: TrackEventsContext, pub mentions: Vec, } pub(crate) struct AppUsedInput { pub tracking: TrackEventsContext, pub app: AppInvocation, } pub(crate) struct PluginUsedInput { pub tracking: TrackEventsContext, pub plugin: PluginTelemetryMetadata, } pub(crate) struct PluginStateChangedInput { pub plugin: PluginTelemetryMetadata, pub state: PluginState, } #[derive(Clone, Copy)] pub(crate) enum PluginState { Installed, Uninstalled, Enabled, Disabled, }