mirror of
https://github.com/openai/codex.git
synced 2026-11-10 21:00:47 +00:00
## What changed Recognize `content_policy_violation` in HTTP 400 responses and streamed errors as a dedicated, non-retryable error. Preserve the provider's message and available HTTP status, use a fallback message when needed, and report `CodexErrorInfo::InvalidPrompt` to clients. End the response stream immediately on this error and stop compaction from falling back to the current model after a content policy rejection. Add redacted diagnostic output and a dedicated sampler failure reason. ## Testing Extend coverage for HTTP and wrapped WebSocket errors, missing or blank provider messages, terminal stream failures with retry headers, and content policy rejections during local and remote compaction on model downshift. GitOrigin-RevId: 592170ac30c07b0b303a8d5cb15bd35c8f821b55
79 lines
2.5 KiB
Rust
79 lines
2.5 KiB
Rust
use crate::session::turn_context::TurnContext;
|
|
use codex_analytics::CompactionImplementation;
|
|
use codex_analytics::CompactionReason;
|
|
use codex_otel::SessionTelemetry;
|
|
use codex_protocol::error::CodexErr;
|
|
use codex_protocol::error::CodexErrorDetails;
|
|
use tracing::warn;
|
|
|
|
/// Returns whether a failed compaction attempt should use the current model.
|
|
pub(crate) fn should_retry_with_current_model(
|
|
error: &CodexErr,
|
|
previous: &TurnContext,
|
|
current: &TurnContext,
|
|
) -> bool {
|
|
if matches!(
|
|
error.details(),
|
|
CodexErrorDetails::TurnAborted
|
|
| CodexErrorDetails::Interrupted
|
|
| CodexErrorDetails::SessionBudgetExceeded
|
|
| CodexErrorDetails::InvalidWorkspaceSelected(_)
|
|
| CodexErrorDetails::ContentPolicyViolation { .. }
|
|
| CodexErrorDetails::ResponseIncomplete(_)
|
|
) || (previous.model_info().slug == current.model_info().slug
|
|
&& previous.cyber_access_program == current.cyber_access_program)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
current.provider.info().is_openai()
|
|
&& current
|
|
.auth_manager
|
|
.as_deref()
|
|
.and_then(codex_login::AuthManager::auth_cached)
|
|
.is_some_and(|auth| auth.uses_codex_backend() || auth.is_api_key_auth())
|
|
}
|
|
|
|
pub(crate) fn record_model_fallback(
|
|
session_telemetry: &SessionTelemetry,
|
|
previous_model: &str,
|
|
current_model: &str,
|
|
reason: CompactionReason,
|
|
implementation: CompactionImplementation,
|
|
fallback_error: Option<&CodexErr>,
|
|
) {
|
|
let reason_tag = match reason {
|
|
CompactionReason::UserRequested => "user_requested",
|
|
CompactionReason::ContextLimit => "context_limit",
|
|
CompactionReason::ModelDownshift => "model_downshift",
|
|
CompactionReason::CompHashChanged => "comp_hash_changed",
|
|
};
|
|
let implementation_tag = match implementation {
|
|
CompactionImplementation::Responses => "responses",
|
|
CompactionImplementation::ResponsesCompactionV2 => "responses_compaction_v2",
|
|
};
|
|
let outcome = if fallback_error.is_none() {
|
|
"succeeded"
|
|
} else {
|
|
"failed"
|
|
};
|
|
session_telemetry.counter(
|
|
"codex.compaction.model_fallback",
|
|
/*inc*/ 1,
|
|
&[
|
|
("reason", reason_tag),
|
|
("implementation", implementation_tag),
|
|
("outcome", outcome),
|
|
],
|
|
);
|
|
warn!(
|
|
previous_model,
|
|
current_model,
|
|
?reason,
|
|
?implementation,
|
|
outcome,
|
|
?fallback_error,
|
|
"previous-model compaction failed; retried with current model"
|
|
);
|
|
}
|