mirror of
https://github.com/openai/codex.git
synced 2026-11-12 21:20:34 +00:00
## Why An explicit denial from a workspace inference hook should stop the request, including retries and compaction model fallback. ## What changed Recognize `inference_hook_denied` provider errors and preserve the provider's message, with a fallback when none is supplied. Expose the distinct `inferenceHookDenied` error through the app-server protocol and generated schemas and SDK types. Treat the denial as non-retryable during turns, compaction, and guardian review. ## Testing Add coverage for terminal denials over HTTP, SSE, and WebSocket, error serialization and persistence in `thread/read`, and compaction failures that preserve token usage and history without retrying or falling back to another model. GitOrigin-RevId: 2ebd480f01e52f4e6bd3db8a0f92d5814d18ccb1
80 lines
2.6 KiB
Rust
80 lines
2.6 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::InferenceHookDenied { .. }
|
|
| CodexErrorDetails::WorkspaceAccessDenied(_)
|
|
| 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"
|
|
);
|
|
}
|