use async_trait::async_trait;
use std::sync::Arc;
#[derive(Debug, Clone)]
pub enum GuardrailResult {
Pass,
Block { reason: String },
Modify { new_value: String },
}
impl GuardrailResult {
pub fn is_pass(&self) -> bool {
matches!(self, GuardrailResult::Pass)
}
pub fn is_block(&self) -> bool {
matches!(self, GuardrailResult::Block { .. })
}
}
#[async_trait]
pub trait InputGuardrail: Send + Sync {
fn name(&self) -> &str;
async fn validate(&self, input: &str) -> GuardrailResult;
}
#[async_trait]
pub trait OutputGuardrail: Send + Sync {
fn name(&self) -> &str;
async fn validate(&self, output: &str) -> GuardrailResult;
}
pub struct GuardrailsConfig {
pub input_guardrails: Vec<Arc<dyn InputGuardrail>>,
pub output_guardrails: Vec<Arc<dyn OutputGuardrail>>,
pub fail_fast: bool,
}
impl Default for GuardrailsConfig {
fn default() -> Self {
Self {
input_guardrails: Vec::new(),
output_guardrails: Vec::new(),
fail_fast: true,
}
}
}
impl GuardrailsConfig {
pub fn new() -> Self {
Self::default()
}
pub fn with_input(mut self, g: Arc<dyn InputGuardrail>) -> Self {
self.input_guardrails.push(g);
self
}
pub fn with_output(mut self, g: Arc<dyn OutputGuardrail>) -> Self {
self.output_guardrails.push(g);
self
}
pub fn fail_fast(mut self, v: bool) -> Self {
self.fail_fast = v;
self
}
}
#[derive(Debug)]
pub enum GuardrailError {
Blocked(String),
AgentError(String),
}
impl std::fmt::Display for GuardrailError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
GuardrailError::Blocked(msg) => write!(f, "Guardrail 拦截: {}", msg),
GuardrailError::AgentError(msg) => write!(f, "Agent 执行错误: {}", msg),
}
}
}
impl std::error::Error for GuardrailError {}