Files
codex/codex-rs/codex-api/src/guardian_assessment.rs
T
jif 9def09afa7 Use serving assessments for adaptive Guardian review (#58075)
## What changed

- Match final serving assessments to their response and output item, then retain them with tool invocations and code cells across waits.
- Use matching assessments instead of asynchronous scoring for adaptive review: low-risk actions can skip synchronous review, while elevated-risk actions require it.
- Revalidate captured authorization and policy before approval. Require fresh review for stale or incomplete authorization, preserve explicit review requirements, and discard assessments when hooks rewrite tool input.
- Keep asynchronous scoring as the fallback when an assessment is missing or does not match.

## Testing

Add integration coverage for direct and nested tool calls, hook rewrites, explicit escalation, interrupted responses, catalog-driven policy, incomplete authorization, and assessment retention across code-cell yields and waits.

GitOrigin-RevId: 4346a227204137f018c03c34b302d6f1e9592c96
2026-10-29 12:54:39 +00:00

37 lines
1.4 KiB
Rust

//! Decodes action-bound Guardian metadata without granting permission to execute.
//! Missing or malformed assessments remain unavailable; consumers must validate the
//! response, completed action, and current authorization before using a low-risk result.
use serde_json::Value;
/// One final serving assessment emitted immediately before the matching output item is done.
/// It is carried outside model-visible response items and is not subsequently revised.
///
/// Consumers must validate the response, completed action, and current authorization
/// before using a low-risk result. This assessment does not grant permission to execute.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct GuardianAssessment {
pub response_id: String,
pub item_id: String,
/// False only permits considering the action for the Guardian fast path.
pub requires_review: bool,
}
pub(crate) fn parse_guardian_assessment(
response_id: Option<&str>,
metadata: Option<&Value>,
) -> Option<GuardianAssessment> {
let response_id = response_id?;
let guardian = metadata?.get("guardian")?;
let item_id = guardian.get("item_id")?.as_str()?;
let requires_review = guardian.get("requires_review")?.as_bool()?;
if response_id.is_empty() || item_id.is_empty() {
return None;
}
Some(GuardianAssessment {
response_id: response_id.to_owned(),
item_id: item_id.to_owned(),
requires_review,
})
}