gemini_adk_fluent_rs/
policy.rs1use serde::{Deserialize, Serialize};
21
22#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
24#[serde(rename_all = "snake_case", tag = "kind")]
25pub enum Policy {
26 SafetyHandoff {
30 intents: Vec<String>,
32 },
33 Redact {
36 keys: Vec<String>,
38 },
39 Commit {
42 tool: String,
44 #[serde(default, skip_serializing_if = "Option::is_none")]
46 idempotency_key: Option<String>,
47 #[serde(default, skip_serializing_if = "Option::is_none")]
49 compensate_with: Option<String>,
50 },
51}
52
53impl Policy {
54 pub fn safety_handoff<I, S>(intents: I) -> Self
56 where
57 I: IntoIterator<Item = S>,
58 S: Into<String>,
59 {
60 Policy::SafetyHandoff {
61 intents: intents.into_iter().map(Into::into).collect(),
62 }
63 }
64
65 pub fn redact<I, S>(keys: I) -> Self
67 where
68 I: IntoIterator<Item = S>,
69 S: Into<String>,
70 {
71 Policy::Redact {
72 keys: keys.into_iter().map(Into::into).collect(),
73 }
74 }
75
76 pub fn commit(tool: impl Into<String>) -> CommitPolicy {
78 CommitPolicy {
79 tool: tool.into(),
80 idempotency_key: None,
81 compensate_with: None,
82 }
83 }
84
85 pub fn redacted_keys(&self) -> &[String] {
87 match self {
88 Policy::Redact { keys } => keys,
89 _ => &[],
90 }
91 }
92}
93
94#[derive(Debug, Clone)]
96pub struct CommitPolicy {
97 tool: String,
98 idempotency_key: Option<String>,
99 compensate_with: Option<String>,
100}
101
102impl CommitPolicy {
103 pub fn idempotency_key(mut self, template: impl Into<String>) -> Self {
105 self.idempotency_key = Some(template.into());
106 self
107 }
108
109 pub fn compensate_with(mut self, tool: impl Into<String>) -> Self {
111 self.compensate_with = Some(tool.into());
112 self
113 }
114}
115
116impl From<CommitPolicy> for Policy {
117 fn from(c: CommitPolicy) -> Self {
118 Policy::Commit {
119 tool: c.tool,
120 idempotency_key: c.idempotency_key,
121 compensate_with: c.compensate_with,
122 }
123 }
124}
125
126#[cfg(test)]
127mod tests {
128 use super::*;
129
130 #[test]
131 fn commit_builder_into_policy() {
132 let p: Policy = Policy::commit("charge_card")
133 .idempotency_key("{user_id}:{amount}")
134 .compensate_with("refund")
135 .into();
136 assert_eq!(
137 p,
138 Policy::Commit {
139 tool: "charge_card".into(),
140 idempotency_key: Some("{user_id}:{amount}".into()),
141 compensate_with: Some("refund".into()),
142 }
143 );
144 }
145
146 #[test]
147 fn policies_round_trip_through_json() {
148 let policies = vec![
149 Policy::redact(["card_number", "cvv"]),
150 Policy::safety_handoff(["self_harm"]),
151 Policy::commit("book").idempotency_key("{id}").into(),
152 ];
153 let json = serde_json::to_string(&policies).unwrap();
154 let back: Vec<Policy> = serde_json::from_str(&json).unwrap();
155 assert_eq!(policies, back);
156 assert_eq!(back[0].redacted_keys(), &["card_number", "cvv"]);
157 }
158}