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 {
27 Self
28 }
29 pub fn is_empty(&self) -> bool {
31 true
32 }
33}
34
35#[cfg(not(feature = "guardrails"))]
36impl Default for GuardrailSet {
37 fn default() -> Self {
38 Self::new()
39 }
40}
41
42#[cfg(feature = "guardrails")]
43pub(crate) async fn enforce_guardrails(
44 guardrails: &GuardrailSet,
45 content: &Content,
46 phase: &str,
47) -> Result<Content> {
48 let result = GuardrailExecutor::run(guardrails, content)
49 .await
50 .map_err(|err| AdkError::agent(format!("{phase} guardrail failed: {err}")))?;
51
52 if !result.passed {
53 let failures = result
54 .failures
55 .iter()
56 .map(|(name, reason, severity)| format!("{name} ({severity:?}): {reason}"))
57 .collect::<Vec<_>>()
58 .join("; ");
59 return Err(AdkError::agent(format!("{phase} guardrails blocked content: {failures}")));
60 }
61
62 Ok(result.transformed_content.unwrap_or_else(|| content.clone()))
63}
64
65#[cfg(not(feature = "guardrails"))]
66pub(crate) async fn enforce_guardrails(
67 _guardrails: &GuardrailSet,
68 content: &Content,
69 _phase: &str,
70) -> Result<Content> {
71 Ok(content.clone())
72}
73
74#[cfg(feature = "guardrails")]
75pub use adk_guardrail::{
76 DeniedArgumentPattern, PathAllowList, ToolCallDecision, ToolGuardrail, ToolGuardrailResult,
77 ToolGuardrailSet,
78};
79
80#[cfg(not(feature = "guardrails"))]
82pub struct ToolGuardrailSet;
83
84#[cfg(not(feature = "guardrails"))]
85impl ToolGuardrailSet {
86 pub fn new() -> Self {
88 Self
89 }
90 pub fn is_empty(&self) -> bool {
92 true
93 }
94}
95
96#[cfg(not(feature = "guardrails"))]
97impl Default for ToolGuardrailSet {
98 fn default() -> Self {
99 Self::new()
100 }
101}
102
103pub(crate) enum ToolScreening {
105 Allow(serde_json::Value),
107 #[cfg_attr(not(feature = "guardrails"), allow(dead_code))]
112 Deny(String),
113}
114
115#[cfg(feature = "guardrails")]
117pub(crate) async fn screen_tool_call(
118 guardrails: &ToolGuardrailSet,
119 tool_name: &str,
120 args: &serde_json::Value,
121) -> ToolScreening {
122 if guardrails.is_empty() {
123 return ToolScreening::Allow(args.clone());
124 }
125
126 match guardrails.evaluate(tool_name, args).await {
127 ToolCallDecision::Allow { args } => ToolScreening::Allow(args),
128 ToolCallDecision::Deny { guardrail, reason, severity } => ToolScreening::Deny(format!(
129 "Tool '{tool_name}' blocked by guardrail '{guardrail}' ({severity:?}): {reason}"
130 )),
131 }
132}
133
134#[cfg(not(feature = "guardrails"))]
135pub(crate) async fn screen_tool_call(
136 _guardrails: &ToolGuardrailSet,
137 _tool_name: &str,
138 args: &serde_json::Value,
139) -> ToolScreening {
140 ToolScreening::Allow(args.clone())
141}