kcode-codex-runtime 0.1.0

Safe Codex CLI generation, web search, and model catalog runtime
Documentation
use std::{path::PathBuf, time::Duration};

use crate::DEFAULT_CODEX_EXECUTABLE;

/// Maximum model reasoning effort.
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
pub enum ReasoningEffort {
    /// Disable reasoning when supported.
    None,
    /// Minimal reasoning.
    Minimal,
    /// Low reasoning.
    Low,
    /// Medium reasoning.
    Medium,
    /// High reasoning.
    High,
    /// Extra-high reasoning.
    #[default]
    XHigh,
    /// Maximum reasoning when supported.
    Max,
}

impl ReasoningEffort {
    /// Returns the Codex configuration value.
    pub const fn as_str(self) -> &'static str {
        match self {
            Self::None => "none",
            Self::Minimal => "minimal",
            Self::Low => "low",
            Self::Medium => "medium",
            Self::High => "high",
            Self::XHigh => "xhigh",
            Self::Max => "max",
        }
    }
}

/// Codex web-search context allocation.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum WebSearchContext {
    /// Low-latency, narrow search context.
    Low,
    /// Default search context.
    Medium,
    /// Broad search context.
    High,
}

impl WebSearchContext {
    pub(crate) const fn as_str(self) -> &'static str {
        match self {
            Self::Low => "low",
            Self::Medium => "medium",
            Self::High => "high",
        }
    }
}

/// Research breadth requested from Codex.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum SearchDepth {
    /// Focused research that stops once adequate evidence is available.
    Focused,
    /// Thorough bounded research that resolves material conflicts.
    Thorough,
}

/// Runtime configuration shared by generation and web search.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CodexConfig {
    /// Codex or sandbox-launcher executable.
    pub executable: String,
    /// Directory supplied to Codex as its working directory.
    pub working_directory: PathBuf,
    /// Fixed application instruction supplied for ordinary generation.
    pub base_instruction: String,
    /// Model used for startup prompt-boundary validation.
    pub validation_model: String,
    /// Reasoning setting used for startup prompt-boundary validation.
    pub validation_reasoning_effort: ReasoningEffort,
}

impl CodexConfig {
    /// Constructs a configuration for one validation model.
    pub fn new(validation_model: impl Into<String>) -> Self {
        Self {
            executable: DEFAULT_CODEX_EXECUTABLE.into(),
            working_directory: std::env::temp_dir(),
            base_instruction: String::new(),
            validation_model: validation_model.into(),
            validation_reasoning_effort: ReasoningEffort::XHigh,
        }
    }
}

/// One ordinary Codex generation request.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct GenerationRequest {
    /// Exact model-visible prompt text.
    pub prompt: String,
    /// Codex model identifier.
    pub model: String,
    /// Requested reasoning effort.
    pub reasoning_effort: ReasoningEffort,
    /// Existing Codex thread identifier to resume, when any.
    pub previous_thread_id: Option<String>,
    /// Whether a fresh thread should avoid persistent Codex session storage.
    pub ephemeral: bool,
    /// Maximum wall-clock duration.
    pub timeout: Duration,
}

impl GenerationRequest {
    /// Constructs a fresh generation request.
    pub fn new(prompt: impl Into<String>, model: impl Into<String>) -> Self {
        Self {
            prompt: prompt.into(),
            model: model.into(),
            reasoning_effort: ReasoningEffort::XHigh,
            previous_thread_id: None,
            ephemeral: false,
            timeout: Duration::from_secs(10 * 60),
        }
    }
}

/// Normalized token accounting from one Codex turn.
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct TokenUsage {
    /// Total input tokens reported for the thread.
    pub input_tokens: u64,
    /// Total output tokens reported for the thread.
    pub output_tokens: u64,
    /// Cached input tokens.
    pub cached_input_tokens: u64,
    /// Reasoning output tokens.
    pub reasoning_output_tokens: u64,
    /// Input tokens for only the most recent turn, when reported.
    pub last_input_tokens: Option<u64>,
    /// Output tokens for only the most recent turn, when reported.
    pub last_output_tokens: Option<u64>,
}

/// Successful ordinary Codex generation.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct GenerationResponse {
    /// Codex thread identifier used for continuation.
    pub thread_id: String,
    /// Final non-empty assistant message.
    pub answer: String,
    /// Provider usage, when reported.
    pub usage: Option<TokenUsage>,
}

/// One Codex web-search request.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct WebSearchRequest {
    /// Research question.
    pub question: String,
    /// Codex model identifier.
    pub model: String,
    /// Requested reasoning effort.
    pub reasoning_effort: ReasoningEffort,
    /// Provider web-search context allocation.
    pub context: WebSearchContext,
    /// Desired research breadth.
    pub depth: SearchDepth,
    /// Fixed application-selected wall-clock limit.
    pub timeout: Duration,
}

/// One normalized public HTTP(S) source found in a Codex answer.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct WebSource {
    /// Source title derived from the Markdown link when available.
    pub title: String,
    /// Canonical public HTTP(S) URL.
    pub url: String,
}

/// Successful Codex web research.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct WebSearchResponse {
    /// Evidence-focused answer text.
    pub answer: String,
    /// All deduplicated HTTP(S) sources present in the answer.
    pub sources: Vec<WebSource>,
    /// Provider usage, when reported.
    pub usage: Option<TokenUsage>,
}