guardian: move rejection rationales into turn extension state

This commit is contained in:
Dylan Hurd
2026-06-12 12:10:51 -07:00
parent c7645ca96e
commit ac776a36f1
12 changed files with 102 additions and 35 deletions
+3
View File
@@ -15,6 +15,7 @@ use codex_protocol::protocol::AskForApproval;
mod approval_request;
mod circuit_breaker;
mod rejection_store;
mod truncation;
pub use approval_request::FormattedGuardianAction;
@@ -29,6 +30,8 @@ pub use circuit_breaker::GuardianRejectionCircuitBreaker;
pub use circuit_breaker::GuardianRejectionCircuitBreakerAction;
pub use circuit_breaker::MAX_CONSECUTIVE_GUARDIAN_DENIALS_PER_TURN;
pub use circuit_breaker::MAX_RECENT_AUTO_REVIEW_DENIALS_PER_TURN;
pub use rejection_store::GuardianRejection;
pub use rejection_store::GuardianRejectionStore;
pub use truncation::guardian_truncate_text;
/// Guardian extension dependencies supplied by the host at construction time.
@@ -0,0 +1,37 @@
use std::collections::HashMap;
use codex_protocol::protocol::GuardianAssessmentDecisionSource;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct GuardianRejection {
pub rationale: String,
pub source: GuardianAssessmentDecisionSource,
}
/// Rejection rationales awaiting delivery to callers for one turn.
#[derive(Debug, Default, PartialEq, Eq)]
pub struct GuardianRejectionStore {
rejections: HashMap<String, GuardianRejection>,
}
impl GuardianRejectionStore {
pub fn insert(
&mut self,
review_id: String,
rejection: GuardianRejection,
) -> Option<GuardianRejection> {
self.rejections.insert(review_id, rejection)
}
pub fn remove(&mut self, review_id: &str) -> Option<GuardianRejection> {
self.rejections.remove(review_id)
}
pub fn contains(&self, review_id: &str) -> bool {
self.rejections.contains_key(review_id)
}
}
#[cfg(test)]
#[path = "rejection_store_tests.rs"]
mod tests;
@@ -0,0 +1,30 @@
use std::collections::HashMap;
use codex_protocol::protocol::GuardianAssessmentDecisionSource;
use pretty_assertions::assert_eq;
use super::*;
#[test]
fn stores_rejections_by_review_id_and_removes_them_once() {
let rejection = GuardianRejection {
rationale: "unsafe command".to_string(),
source: GuardianAssessmentDecisionSource::Agent,
};
let mut store = GuardianRejectionStore::default();
assert_eq!(
store.insert("review-1".to_string(), rejection.clone()),
None
);
assert!(store.contains("review-1"));
assert_eq!(
store,
GuardianRejectionStore {
rejections: HashMap::from([("review-1".to_string(), rejection.clone())]),
}
);
assert_eq!(store.remove("review-1"), Some(rejection));
assert_eq!(store.remove("review-1"), None);
assert_eq!(store, GuardianRejectionStore::default());
}