[codex] rename rollout budget error to session budget error (#29744)

## Summary

- rename the rollout-budget exhaustion error from
`RolloutBudgetExceeded` to `SessionBudgetExceeded`
- expose the matching app-server v2 wire value as
`sessionBudgetExceeded`
- regenerate JSON/TypeScript schema fixtures and update the app-server
docs and focused tests

This is a naming-only follow-up to #29715 based on [Pavel's review
suggestion](https://github.com/openai/codex/pull/29715#discussion_r3463183480).
Runtime behavior is unchanged.

## Tests

- `just test -p codex-core rollout_budget`
- `just test -p codex-app-server-protocol`
- `just fmt`
- `just write-app-server-schema`
This commit is contained in:
rka-oai authored and GitHub committed 2026-06-23 16:49:13 -07:00
1 parent 77e7ce1374
commit 1ec3def0b5
26 files changed
+32 -32

No files matched your search

+2 -2
View File
@@ -139,7 +139,7 @@ impl TurnCodexErrorFact {
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
pub enum CodexErrKind { pub enum CodexErrKind {
TurnAborted, TurnAborted,
RolloutBudgetExceeded, SessionBudgetExceeded,
Stream, Stream,
ContextWindowExceeded, ContextWindowExceeded,
ThreadNotFound, ThreadNotFound,
@@ -196,7 +196,7 @@ impl From<&CodexErr> for CodexErrKind {
fn from(error: &CodexErr) -> Self { fn from(error: &CodexErr) -> Self {
match error { match error {
CodexErr::TurnAborted => CodexErrKind::TurnAborted, CodexErr::TurnAborted => CodexErrKind::TurnAborted,
CodexErr::RolloutBudgetExceeded => CodexErrKind::RolloutBudgetExceeded, CodexErr::SessionBudgetExceeded => CodexErrKind::SessionBudgetExceeded,
CodexErr::Stream(..) => CodexErrKind::Stream, CodexErr::Stream(..) => CodexErrKind::Stream,
CodexErr::ContextWindowExceeded => CodexErrKind::ContextWindowExceeded, CodexErr::ContextWindowExceeded => CodexErrKind::ContextWindowExceeded,
CodexErr::ThreadNotFound(_) => CodexErrKind::ThreadNotFound, CodexErr::ThreadNotFound(_) => CodexErrKind::ThreadNotFound,
@@ -573,7 +573,7 @@
{ {
"enum": [ "enum": [
"contextWindowExceeded", "contextWindowExceeded",
"rolloutBudgetExceeded", "sessionBudgetExceeded",
"usageLimitExceeded", "usageLimitExceeded",
"serverOverloaded", "serverOverloaded",
"cyberPolicy", "cyberPolicy",
@@ -7070,7 +7070,7 @@
{ {
"enum": [ "enum": [
"contextWindowExceeded", "contextWindowExceeded",
"rolloutBudgetExceeded", "sessionBudgetExceeded",
"usageLimitExceeded", "usageLimitExceeded",
"serverOverloaded", "serverOverloaded",
"cyberPolicy", "cyberPolicy",
@@ -3310,7 +3310,7 @@
{ {
"enum": [ "enum": [
"contextWindowExceeded", "contextWindowExceeded",
"rolloutBudgetExceeded", "sessionBudgetExceeded",
"usageLimitExceeded", "usageLimitExceeded",
"serverOverloaded", "serverOverloaded",
"cyberPolicy", "cyberPolicy",
@@ -7,7 +7,7 @@
{ {
"enum": [ "enum": [
"contextWindowExceeded", "contextWindowExceeded",
"rolloutBudgetExceeded", "sessionBudgetExceeded",
"usageLimitExceeded", "usageLimitExceeded",
"serverOverloaded", "serverOverloaded",
"cyberPolicy", "cyberPolicy",
@@ -30,7 +30,7 @@
{ {
"enum": [ "enum": [
"contextWindowExceeded", "contextWindowExceeded",
"rolloutBudgetExceeded", "sessionBudgetExceeded",
"usageLimitExceeded", "usageLimitExceeded",
"serverOverloaded", "serverOverloaded",
"cyberPolicy", "cyberPolicy",
@@ -111,7 +111,7 @@
{ {
"enum": [ "enum": [
"contextWindowExceeded", "contextWindowExceeded",
"rolloutBudgetExceeded", "sessionBudgetExceeded",
"usageLimitExceeded", "usageLimitExceeded",
"serverOverloaded", "serverOverloaded",
"cyberPolicy", "cyberPolicy",
@@ -33,7 +33,7 @@
{ {
"enum": [ "enum": [
"contextWindowExceeded", "contextWindowExceeded",
"rolloutBudgetExceeded", "sessionBudgetExceeded",
"usageLimitExceeded", "usageLimitExceeded",
"serverOverloaded", "serverOverloaded",
"cyberPolicy", "cyberPolicy",
@@ -33,7 +33,7 @@
{ {
"enum": [ "enum": [
"contextWindowExceeded", "contextWindowExceeded",
"rolloutBudgetExceeded", "sessionBudgetExceeded",
"usageLimitExceeded", "usageLimitExceeded",
"serverOverloaded", "serverOverloaded",
"cyberPolicy", "cyberPolicy",
@@ -33,7 +33,7 @@
{ {
"enum": [ "enum": [
"contextWindowExceeded", "contextWindowExceeded",
"rolloutBudgetExceeded", "sessionBudgetExceeded",
"usageLimitExceeded", "usageLimitExceeded",
"serverOverloaded", "serverOverloaded",
"cyberPolicy", "cyberPolicy",
@@ -111,7 +111,7 @@
{ {
"enum": [ "enum": [
"contextWindowExceeded", "contextWindowExceeded",
"rolloutBudgetExceeded", "sessionBudgetExceeded",
"usageLimitExceeded", "usageLimitExceeded",
"serverOverloaded", "serverOverloaded",
"cyberPolicy", "cyberPolicy",
@@ -33,7 +33,7 @@
{ {
"enum": [ "enum": [
"contextWindowExceeded", "contextWindowExceeded",
"rolloutBudgetExceeded", "sessionBudgetExceeded",
"usageLimitExceeded", "usageLimitExceeded",
"serverOverloaded", "serverOverloaded",
"cyberPolicy", "cyberPolicy",
@@ -111,7 +111,7 @@
{ {
"enum": [ "enum": [
"contextWindowExceeded", "contextWindowExceeded",
"rolloutBudgetExceeded", "sessionBudgetExceeded",
"usageLimitExceeded", "usageLimitExceeded",
"serverOverloaded", "serverOverloaded",
"cyberPolicy", "cyberPolicy",
@@ -33,7 +33,7 @@
{ {
"enum": [ "enum": [
"contextWindowExceeded", "contextWindowExceeded",
"rolloutBudgetExceeded", "sessionBudgetExceeded",
"usageLimitExceeded", "usageLimitExceeded",
"serverOverloaded", "serverOverloaded",
"cyberPolicy", "cyberPolicy",
@@ -33,7 +33,7 @@
{ {
"enum": [ "enum": [
"contextWindowExceeded", "contextWindowExceeded",
"rolloutBudgetExceeded", "sessionBudgetExceeded",
"usageLimitExceeded", "usageLimitExceeded",
"serverOverloaded", "serverOverloaded",
"cyberPolicy", "cyberPolicy",
@@ -30,7 +30,7 @@
{ {
"enum": [ "enum": [
"contextWindowExceeded", "contextWindowExceeded",
"rolloutBudgetExceeded", "sessionBudgetExceeded",
"usageLimitExceeded", "usageLimitExceeded",
"serverOverloaded", "serverOverloaded",
"cyberPolicy", "cyberPolicy",
@@ -30,7 +30,7 @@
{ {
"enum": [ "enum": [
"contextWindowExceeded", "contextWindowExceeded",
"rolloutBudgetExceeded", "sessionBudgetExceeded",
"usageLimitExceeded", "usageLimitExceeded",
"serverOverloaded", "serverOverloaded",
"cyberPolicy", "cyberPolicy",
@@ -30,7 +30,7 @@
{ {
"enum": [ "enum": [
"contextWindowExceeded", "contextWindowExceeded",
"rolloutBudgetExceeded", "sessionBudgetExceeded",
"usageLimitExceeded", "usageLimitExceeded",
"serverOverloaded", "serverOverloaded",
"cyberPolicy", "cyberPolicy",
@@ -9,4 +9,4 @@ import type { NonSteerableTurnKind } from "./NonSteerableTurnKind";
* When an upstream HTTP status is available (for example, from the Responses API or a provider), * When an upstream HTTP status is available (for example, from the Responses API or a provider),
* it is forwarded in `httpStatusCode` on the relevant `codexErrorInfo` variant. * it is forwarded in `httpStatusCode` on the relevant `codexErrorInfo` variant.
*/ */
export type CodexErrorInfo = "contextWindowExceeded" | "rolloutBudgetExceeded" | "usageLimitExceeded" | "serverOverloaded" | "cyberPolicy" | { "httpConnectionFailed": { httpStatusCode: number | null, } } | { "responseStreamConnectionFailed": { httpStatusCode: number | null, } } | "internalServerError" | "unauthorized" | "badRequest" | "threadRollbackFailed" | "sandboxError" | { "responseStreamDisconnected": { httpStatusCode: number | null, } } | { "responseTooManyFailedAttempts": { httpStatusCode: number | null, } } | { "activeTurnNotSteerable": { turnKind: NonSteerableTurnKind, } } | "other"; export type CodexErrorInfo = "contextWindowExceeded" | "sessionBudgetExceeded" | "usageLimitExceeded" | "serverOverloaded" | "cyberPolicy" | { "httpConnectionFailed": { httpStatusCode: number | null, } } | { "responseStreamConnectionFailed": { httpStatusCode: number | null, } } | "internalServerError" | "unauthorized" | "badRequest" | "threadRollbackFailed" | "sandboxError" | { "responseStreamDisconnected": { httpStatusCode: number | null, } } | { "responseTooManyFailedAttempts": { httpStatusCode: number | null, } } | { "activeTurnNotSteerable": { turnKind: NonSteerableTurnKind, } } | "other";
@@ -70,7 +70,7 @@ pub enum NonSteerableTurnKind {
#[ts(export_to = "v2/")] #[ts(export_to = "v2/")]
pub enum CodexErrorInfo { pub enum CodexErrorInfo {
ContextWindowExceeded, ContextWindowExceeded,
RolloutBudgetExceeded, SessionBudgetExceeded,
UsageLimitExceeded, UsageLimitExceeded,
ServerOverloaded, ServerOverloaded,
CyberPolicy, CyberPolicy,
@@ -116,7 +116,7 @@ impl From<CoreCodexErrorInfo> for CodexErrorInfo {
fn from(value: CoreCodexErrorInfo) -> Self { fn from(value: CoreCodexErrorInfo) -> Self {
match value { match value {
CoreCodexErrorInfo::ContextWindowExceeded => CodexErrorInfo::ContextWindowExceeded, CoreCodexErrorInfo::ContextWindowExceeded => CodexErrorInfo::ContextWindowExceeded,
CoreCodexErrorInfo::RolloutBudgetExceeded => CodexErrorInfo::RolloutBudgetExceeded, CoreCodexErrorInfo::SessionBudgetExceeded => CodexErrorInfo::SessionBudgetExceeded,
CoreCodexErrorInfo::UsageLimitExceeded => CodexErrorInfo::UsageLimitExceeded, CoreCodexErrorInfo::UsageLimitExceeded => CodexErrorInfo::UsageLimitExceeded,
CoreCodexErrorInfo::ServerOverloaded => CodexErrorInfo::ServerOverloaded, CoreCodexErrorInfo::ServerOverloaded => CodexErrorInfo::ServerOverloaded,
CoreCodexErrorInfo::CyberPolicy => CodexErrorInfo::CyberPolicy, CoreCodexErrorInfo::CyberPolicy => CodexErrorInfo::CyberPolicy,
+1 -1
View File
@@ -1423,7 +1423,7 @@ There are additional item-specific events:
`codexErrorInfo` maps to the `CodexErrorInfo` enum. Common values: `codexErrorInfo` maps to the `CodexErrorInfo` enum. Common values:
- `ContextWindowExceeded` - `ContextWindowExceeded`
- `RolloutBudgetExceeded` - `SessionBudgetExceeded`
- `UsageLimitExceeded` - `UsageLimitExceeded`
- `HttpConnectionFailed { httpStatusCode? }`: upstream HTTP failures including 4xx/5xx - `HttpConnectionFailed { httpStatusCode? }`: upstream HTTP failures including 4xx/5xx
- `ResponseStreamConnectionFailed { httpStatusCode? }`: failure to connect to the response SSE stream - `ResponseStreamConnectionFailed { httpStatusCode? }`: failure to connect to the response SSE stream
+1 -1
View File
@@ -275,7 +275,7 @@ async fn run_compact_task_inner_impl(
Err(err @ (CodexErr::Interrupted | CodexErr::TurnAborted)) => { Err(err @ (CodexErr::Interrupted | CodexErr::TurnAborted)) => {
return Err(err); return Err(err);
} }
Err(e @ CodexErr::RolloutBudgetExceeded) => { Err(e @ CodexErr::SessionBudgetExceeded) => {
sess.track_turn_codex_error(turn_context.as_ref(), &e); sess.track_turn_codex_error(turn_context.as_ref(), &e);
let event = EventMsg::Error(e.to_error_event(/*message_prefix*/ None)); let event = EventMsg::Error(e.to_error_event(/*message_prefix*/ None));
sess.send_event(&turn_context, event).await; sess.send_event(&turn_context, event).await;
+1 -1
View File
@@ -30,7 +30,7 @@ impl Session {
.rollout_budget() .rollout_budget()
.record_usage(usage) .record_usage(usage)
{ {
return Err(CodexErr::RolloutBudgetExceeded); return Err(CodexErr::SessionBudgetExceeded);
} }
Ok(()) Ok(())
} }
+2 -2
View File
@@ -252,7 +252,7 @@ async fn exhausted_budget_fails_current_and_later_turns() -> Result<()> {
matches!( matches!(
event, event,
EventMsg::Error(error) EventMsg::Error(error)
if error.codex_error_info == Some(CodexErrorInfo::RolloutBudgetExceeded) if error.codex_error_info == Some(CodexErrorInfo::SessionBudgetExceeded)
) )
}) })
.await; .await;
@@ -315,7 +315,7 @@ async fn compaction_budget_exhaustion_fails_without_retry(remote_v2: bool) -> Re
matches!( matches!(
event, event,
EventMsg::Error(error) EventMsg::Error(error)
if error.codex_error_info == Some(CodexErrorInfo::RolloutBudgetExceeded) if error.codex_error_info == Some(CodexErrorInfo::SessionBudgetExceeded)
) )
}) })
.await; .await;
+3 -3
View File
@@ -70,7 +70,7 @@ pub enum CodexErr {
TurnAborted, TurnAborted,
#[error("shared rollout token budget exhausted")] #[error("shared rollout token budget exhausted")]
RolloutBudgetExceeded, SessionBudgetExceeded,
/// Returned by ResponsesClient when the SSE stream disconnects or errors out **after** the HTTP /// Returned by ResponsesClient when the SSE stream disconnects or errors out **after** the HTTP
/// handshake has succeeded but **before** it finished emitting `response.completed`. /// handshake has succeeded but **before** it finished emitting `response.completed`.
@@ -176,7 +176,7 @@ impl CodexErr {
pub fn is_retryable(&self) -> bool { pub fn is_retryable(&self) -> bool {
match self { match self {
CodexErr::TurnAborted CodexErr::TurnAborted
| CodexErr::RolloutBudgetExceeded | CodexErr::SessionBudgetExceeded
| CodexErr::Interrupted | CodexErr::Interrupted
| CodexErr::EnvVar(_) | CodexErr::EnvVar(_)
| CodexErr::Fatal(_) | CodexErr::Fatal(_)
@@ -224,7 +224,7 @@ impl CodexErr {
pub fn to_codex_protocol_error(&self) -> CodexErrorInfo { pub fn to_codex_protocol_error(&self) -> CodexErrorInfo {
match self { match self {
CodexErr::ContextWindowExceeded => CodexErrorInfo::ContextWindowExceeded, CodexErr::ContextWindowExceeded => CodexErrorInfo::ContextWindowExceeded,
CodexErr::RolloutBudgetExceeded => CodexErrorInfo::RolloutBudgetExceeded, CodexErr::SessionBudgetExceeded => CodexErrorInfo::SessionBudgetExceeded,
CodexErr::UsageLimitReached(_) CodexErr::UsageLimitReached(_)
| CodexErr::QuotaExceeded | CodexErr::QuotaExceeded
| CodexErr::UsageNotIncluded => CodexErrorInfo::UsageLimitExceeded, | CodexErr::UsageNotIncluded => CodexErrorInfo::UsageLimitExceeded,
+2 -2
View File
@@ -1690,7 +1690,7 @@ pub enum NonSteerableTurnKind {
#[ts(rename_all = "snake_case")] #[ts(rename_all = "snake_case")]
pub enum CodexErrorInfo { pub enum CodexErrorInfo {
ContextWindowExceeded, ContextWindowExceeded,
RolloutBudgetExceeded, SessionBudgetExceeded,
UsageLimitExceeded, UsageLimitExceeded,
ServerOverloaded, ServerOverloaded,
CyberPolicy, CyberPolicy,
@@ -1728,7 +1728,7 @@ impl CodexErrorInfo {
match self { match self {
Self::ThreadRollbackFailed | Self::ActiveTurnNotSteerable { .. } => false, Self::ThreadRollbackFailed | Self::ActiveTurnNotSteerable { .. } => false,
Self::ContextWindowExceeded Self::ContextWindowExceeded
| Self::RolloutBudgetExceeded | Self::SessionBudgetExceeded
| Self::UsageLimitExceeded | Self::UsageLimitExceeded
| Self::ServerOverloaded | Self::ServerOverloaded
| Self::CyberPolicy | Self::CyberPolicy