This commit is contained in:
celia-oai
2025-11-19 23:05:01 -08:00
parent 037e0b5736
commit 918731d918
6 changed files with 81 additions and 1 deletions

1
codex-rs/Cargo.lock generated
View File

@@ -1433,6 +1433,7 @@ dependencies = [
"strum_macros 0.27.2",
"sys-locale",
"tempfile",
"thiserror 2.0.17",
"tracing",
"ts-rs",
"uuid",

View File

@@ -84,9 +84,9 @@ wildmatch = { workspace = true }
[target.'cfg(target_os = "linux")'.dependencies]
keyring = { workspace = true, features = ["linux-native-async-persistent"] }
landlock = { workspace = true }
seccompiler = { workspace = true }
keyring = { workspace = true, features = ["linux-native-async-persistent"] }
[target.'cfg(target_os = "macos")'.dependencies]
core-foundation = "0.9"

View File

@@ -66,6 +66,7 @@ use crate::context_manager::ContextManager;
use crate::environment_context::EnvironmentContext;
use crate::error::CodexErr;
use crate::error::Result as CodexResult;
use crate::error::http_status_code_value;
#[cfg(test)]
use crate::exec::StreamOutput;
use crate::mcp::auth::compute_auth_statuses;
@@ -78,6 +79,7 @@ use crate::protocol::AgentReasoningSectionBreakEvent;
use crate::protocol::ApplyPatchApprovalRequestEvent;
use crate::protocol::AskForApproval;
use crate::protocol::BackgroundEventEvent;
use crate::protocol::CodexErrorCode;
use crate::protocol::DeprecationNoticeEvent;
use crate::protocol::ErrorEvent;
use crate::protocol::Event;
@@ -134,6 +136,7 @@ use codex_protocol::user_input::UserInput;
use codex_utils_readiness::Readiness;
use codex_utils_readiness::ReadinessFlag;
use codex_utils_tokenizer::warm_model_cache;
use reqwest::StatusCode;
/// The high-level interface to the Codex system.
/// It operates as a queue pair where you send submissions and receive events.
@@ -1196,9 +1199,14 @@ impl Session {
&self,
turn_context: &TurnContext,
message: impl Into<String>,
http_status_code: Option<StatusCode>,
) {
let codex_error_code = CodexErrorCode::ResponseStreamError {
http_status_code: http_status_code_value(http_status_code),
};
let event = EventMsg::StreamError(StreamErrorEvent {
message: message.into(),
codex_error_code: Some(codex_error_code),
});
self.send_event(turn_context, event).await;
}

View File

@@ -10,6 +10,8 @@ use chrono::Local;
use chrono::Utc;
use codex_async_utils::CancelErr;
use codex_protocol::ConversationId;
use codex_protocol::protocol::CodexErrorCode;
use codex_protocol::protocol::ErrorEvent;
use codex_protocol::protocol::RateLimitSnapshot;
use reqwest::StatusCode;
use serde_json;
@@ -430,6 +432,50 @@ impl CodexErr {
pub fn downcast_ref<T: std::any::Any>(&self) -> Option<&T> {
(self as &dyn std::any::Any).downcast_ref::<T>()
}
/// Translate core error to client-facing protocol error.
pub fn to_codex_protocol_error(&self) -> CodexErrorCode {
match self {
CodexErr::ContextWindowExceeded => CodexErrorCode::ContextWindowExceeded,
CodexErr::UsageLimitReached(_)
| CodexErr::QuotaExceeded
| CodexErr::UsageNotIncluded => CodexErrorCode::UsageLimitExceeded,
CodexErr::RetryLimit(err) => CodexErrorCode::HttpRetryLimitExceeded {
http_status_code: http_status_code_value(Some(err.status)),
},
CodexErr::ConnectionFailed(err) => CodexErrorCode::HttpConnectionFailed {
http_status_code: http_status_code_value(err.source.status()),
},
CodexErr::ResponseStreamFailed(err) => CodexErrorCode::ResponseSseStreamFailed {
http_status_code: http_status_code_value(err.source.status()),
},
CodexErr::RefreshTokenFailed(_) => CodexErrorCode::Unauthorized,
CodexErr::SessionConfiguredNotFirstEvent
| CodexErr::InternalServerError
| CodexErr::InternalAgentDied => CodexErrorCode::InternalServerError,
CodexErr::UnsupportedOperation(_) | CodexErr::ConversationNotFound(_) => {
CodexErrorCode::BadRequest
}
CodexErr::Sandbox(_) => CodexErrorCode::Sandbox,
_ => CodexErrorCode::Other,
}
}
pub fn to_error_event(&self, message_prefix: Option<String>) -> ErrorEvent {
let error_message = self.to_string();
let message: String = match message_prefix {
Some(prefix) => format!("{prefix}: {error_message}"),
None => error_message,
};
ErrorEvent {
message,
codex_error_code: self.to_codex_protocol_error(),
}
}
}
pub fn http_status_code_value(http_status_code: Option<StatusCode>) -> Option<u16> {
http_status_code.as_ref().map(StatusCode::as_u16)
}
pub fn get_error_message_ui(e: &CodexErr) -> String {

View File

@@ -27,6 +27,7 @@ serde_with = { workspace = true, features = ["macros", "base64"] }
strum = { workspace = true }
strum_macros = { workspace = true }
sys-locale = { workspace = true }
thiserror = { workspace = true }
tracing = { workspace = true }
ts-rs = { workspace = true, features = [
"uuid-impl",

View File

@@ -32,6 +32,7 @@ use serde::Serialize;
use serde_json::Value;
use serde_with::serde_as;
use strum_macros::Display;
use thiserror::Error;
use ts_rs::TS;
pub use crate::approvals::ApplyPatchApprovalRequestEvent;
@@ -562,6 +563,27 @@ pub enum EventMsg {
ReasoningRawContentDelta(ReasoningRawContentDeltaEvent),
}
/// Codex errors that we expose to clients.
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "snake_case")]
#[ts(rename_all = "snake_case")]
pub enum CodexErrorCode {
ContextWindowExceeded,
UsageLimitExceeded,
// Exceeded the retry limit for http requests for retryable HTTP errors.
HttpRetryLimitExceeded { http_status_code: Option<u16> },
HttpConnectionFailed { http_status_code: Option<u16> },
// The SSE stream for the response failed.
ResponseSseStreamFailed { http_status_code: Option<u16> },
InternalServerError,
Unauthorized,
BadRequest,
Sandbox,
// Error emitted by response stream, Usually during retries of a retryable HTTP error.
ResponseStreamError { http_status_code: Option<u16> },
Other,
}
#[derive(Debug, Clone, Deserialize, Serialize, TS, JsonSchema)]
pub struct RawResponseItemEvent {
pub item: ResponseItem,
@@ -686,6 +708,7 @@ pub struct ExitedReviewModeEvent {
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)]
pub struct ErrorEvent {
pub message: String,
pub codex_error_code: Option<CodexErrorCode>,
}
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)]
@@ -1363,6 +1386,7 @@ pub struct UndoCompletedEvent {
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)]
pub struct StreamErrorEvent {
pub message: String,
pub codex_error_code: Option<CodexErrorCode>,
}
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)]