use async_trait::async_trait;
use crate::error::Error;
use crate::llm::Message;
#[async_trait]
pub trait ReviewPolicy: Send + Sync {
async fn should_pause_for_approval(
&self,
step: u32,
message: &Message,
) -> Result<Option<String>, Error>;
fn is_never(&self) -> bool {
false
}
}
pub struct NeverReview;
#[async_trait]
impl ReviewPolicy for NeverReview {
async fn should_pause_for_approval(
&self,
_step: u32,
_message: &Message,
) -> Result<Option<String>, Error> {
Ok(None)
}
fn is_never(&self) -> bool {
true
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::llm::{Message, Role};
#[tokio::test]
async fn never_review_never_pauses() {
let policy = NeverReview;
let msg = Message {
role: Role::Assistant,
content: "hi".into(),
tool_calls: vec![],
tool_call_id: None,
};
assert_eq!(
policy.should_pause_for_approval(1, &msg).await.unwrap(),
None
);
}
#[test]
fn never_review_reports_is_never() {
assert!(NeverReview.is_never());
}
#[test]
fn custom_policy_is_not_never_by_default() {
struct Gating;
#[async_trait]
impl ReviewPolicy for Gating {
async fn should_pause_for_approval(
&self,
_step: u32,
_message: &Message,
) -> Result<Option<String>, Error> {
Ok(Some("hold".into()))
}
}
assert!(!Gating.is_never());
}
}