Skip to main content

kcode_codex_runtime/
error.rs

1use std::{error::Error as StdError, fmt};
2
3/// The result type returned by Codex operations.
4pub type Result<T> = std::result::Result<T, Error>;
5
6/// Stable failure classification for application adapters.
7#[derive(Clone, Copy, Debug, Eq, PartialEq)]
8pub enum ErrorKind {
9    /// The caller supplied an invalid request or configuration.
10    InvalidInput,
11    /// Codex or its sandbox launcher could not be started or completed.
12    Unavailable,
13    /// Codex authentication is missing or invalid.
14    Authentication,
15    /// The provider rejected the operation due to a usage or rate limit.
16    RateLimited,
17    /// The selected model is temporarily at capacity.
18    Capacity,
19    /// The operation exceeded its configured deadline.
20    Timeout,
21    /// The model input exceeded its supported limit.
22    InputTooLarge,
23    /// Codex completed without a usable assistant message.
24    EmptyOutput,
25    /// Codex returned output that did not satisfy its runtime protocol.
26    Protocol,
27}
28
29/// A sanitized Codex configuration, process, provider, or protocol failure.
30#[derive(Debug)]
31pub struct Error {
32    kind: ErrorKind,
33    message: String,
34}
35
36impl Error {
37    pub(crate) fn new(kind: ErrorKind, message: impl Into<String>) -> Self {
38        Self {
39            kind,
40            message: message.into(),
41        }
42    }
43
44    /// Returns the stable failure classification.
45    pub const fn kind(&self) -> ErrorKind {
46        self.kind
47    }
48
49    /// Returns the sanitized failure detail.
50    pub fn message(&self) -> &str {
51        &self.message
52    }
53}
54
55impl fmt::Display for Error {
56    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
57        formatter.write_str(&self.message)
58    }
59}
60
61impl StdError for Error {}
62
63pub(crate) fn runtime(error: impl fmt::Display) -> Error {
64    Error::new(
65        ErrorKind::Unavailable,
66        clean_message(&error.to_string(), 500),
67    )
68}
69
70pub(crate) fn clean_message(value: &str, limit: usize) -> String {
71    let clean = value
72        .chars()
73        .map(|character| {
74            if character.is_control() {
75                ' '
76            } else {
77                character
78            }
79        })
80        .take(limit)
81        .collect::<String>()
82        .split_whitespace()
83        .collect::<Vec<_>>()
84        .join(" ");
85    if clean.is_empty() {
86        "Codex operation failed".into()
87    } else {
88        clean
89    }
90}