1use adk_core::{Content, Result};
6
7#[cfg(feature = "guardrails")]
8use adk_core::AdkError;
9
10#[cfg(feature = "guardrails")]
11pub use adk_guardrail::{
12 ContentFilter, ContentFilterConfig, Guardrail, GuardrailExecutor, GuardrailResult,
13 GuardrailSet, PiiRedactor, PiiType, Severity,
14};
15
16#[cfg(feature = "guardrails")]
17pub use adk_guardrail::SchemaValidator;
18
19#[cfg(not(feature = "guardrails"))]
21pub struct GuardrailSet;
22
23#[cfg(not(feature = "guardrails"))]
24impl GuardrailSet {
25 pub fn new() -> Self {
26 Self
27 }
28 pub fn is_empty(&self) -> bool {
29 true
30 }
31}
32
33#[cfg(not(feature = "guardrails"))]
34impl Default for GuardrailSet {
35 fn default() -> Self {
36 Self::new()
37 }
38}
39
40#[cfg(feature = "guardrails")]
41pub(crate) async fn enforce_guardrails(
42 guardrails: &GuardrailSet,
43 content: &Content,
44 phase: &str,
45) -> Result<Content> {
46 let result = GuardrailExecutor::run(guardrails, content)
47 .await
48 .map_err(|err| AdkError::agent(format!("{phase} guardrail failed: {err}")))?;
49
50 if !result.passed {
51 let failures = result
52 .failures
53 .iter()
54 .map(|(name, reason, severity)| format!("{name} ({severity:?}): {reason}"))
55 .collect::<Vec<_>>()
56 .join("; ");
57 return Err(AdkError::agent(format!("{phase} guardrails blocked content: {failures}")));
58 }
59
60 Ok(result.transformed_content.unwrap_or_else(|| content.clone()))
61}
62
63#[cfg(not(feature = "guardrails"))]
64pub(crate) async fn enforce_guardrails(
65 _guardrails: &GuardrailSet,
66 content: &Content,
67 _phase: &str,
68) -> Result<Content> {
69 Ok(content.clone())
70}