agent_chain_core/api/
beta.rs1use std::fmt;
10use std::sync::atomic::{AtomicBool, Ordering};
11
12use super::internal::is_caller_internal;
13
14#[derive(Debug, Clone)]
16pub struct AgentChainBetaWarning {
17 message: String,
18}
19
20impl AgentChainBetaWarning {
21 pub fn new(message: impl Into<String>) -> Self {
23 Self {
24 message: message.into(),
25 }
26 }
27
28 pub fn message(&self) -> &str {
30 &self.message
31 }
32}
33
34impl fmt::Display for AgentChainBetaWarning {
35 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36 write!(f, "{}", self.message)
37 }
38}
39
40impl std::error::Error for AgentChainBetaWarning {}
41
42static SUPPRESS_BETA_WARNINGS: AtomicBool = AtomicBool::new(false);
44
45#[derive(Debug, Clone, Default)]
47pub struct BetaParams {
48 pub message: Option<String>,
50 pub name: Option<String>,
52 pub obj_type: Option<String>,
54 pub addendum: Option<String>,
56}
57
58impl BetaParams {
59 pub fn new(name: impl Into<String>) -> Self {
61 Self {
62 name: Some(name.into()),
63 ..Default::default()
64 }
65 }
66
67 pub fn with_message(mut self, message: impl Into<String>) -> Self {
69 self.message = Some(message.into());
70 self
71 }
72
73 pub fn with_obj_type(mut self, obj_type: impl Into<String>) -> Self {
75 self.obj_type = Some(obj_type.into());
76 self
77 }
78
79 pub fn with_addendum(mut self, addendum: impl Into<String>) -> Self {
81 self.addendum = Some(addendum.into());
82 self
83 }
84}
85
86pub fn warn_beta(params: BetaParams, caller_module: &str) {
110 if SUPPRESS_BETA_WARNINGS.load(Ordering::Relaxed) {
112 return;
113 }
114
115 if is_caller_internal(caller_module) {
117 return;
118 }
119
120 let message = if let Some(msg) = params.message {
121 msg
122 } else {
123 let name = params.name.unwrap_or_else(|| "unknown".to_string());
124 let mut msg = if let Some(obj_type) = params.obj_type {
125 format!("The {} `{}`", obj_type, name)
126 } else {
127 format!("`{}`", name)
128 };
129
130 msg.push_str(" is in beta. It is actively being worked on, so the API may change.");
131
132 if let Some(addendum) = params.addendum {
133 msg.push(' ');
134 msg.push_str(&addendum);
135 }
136
137 msg
138 };
139
140 let warning = AgentChainBetaWarning::new(message);
141
142 eprintln!("AgentChainBetaWarning: {}", warning);
145}
146
147pub struct SuppressBetaWarnings {
149 previous_state: bool,
150}
151
152impl SuppressBetaWarnings {
153 pub fn new() -> Self {
155 let previous_state = SUPPRESS_BETA_WARNINGS.swap(true, Ordering::Relaxed);
156 Self { previous_state }
157 }
158}
159
160impl Default for SuppressBetaWarnings {
161 fn default() -> Self {
162 Self::new()
163 }
164}
165
166impl Drop for SuppressBetaWarnings {
167 fn drop(&mut self) {
168 SUPPRESS_BETA_WARNINGS.store(self.previous_state, Ordering::Relaxed);
169 }
170}
171
172pub fn suppress_beta_warnings() -> SuppressBetaWarnings {
186 SuppressBetaWarnings::new()
187}
188
189pub fn surface_beta_warnings() {
193 SUPPRESS_BETA_WARNINGS.store(false, Ordering::Relaxed);
194}
195
196#[macro_export]
216macro_rules! beta {
217 ($name:expr) => {
218 $crate::api::warn_beta($crate::api::BetaParams::new($name), module_path!())
219 };
220 ($name:expr, $($key:ident = $value:expr),+ $(,)?) => {{
221 let mut params = $crate::api::BetaParams::new($name);
222 $(
223 params = $crate::api::beta!(@set params, $key, $value);
224 )+
225 $crate::api::warn_beta(params, module_path!())
226 }};
227 (@set $params:expr, message, $value:expr) => {
228 $params.with_message($value)
229 };
230 (@set $params:expr, obj_type, $value:expr) => {
231 $params.with_obj_type($value)
232 };
233 (@set $params:expr, addendum, $value:expr) => {
234 $params.with_addendum($value)
235 };
236}
237
238#[cfg(test)]
239mod tests {
240 use super::*;
241
242 #[test]
243 fn test_beta_warning_creation() {
244 let warning = AgentChainBetaWarning::new("Test warning");
245 assert_eq!(warning.message(), "Test warning");
246 assert_eq!(format!("{}", warning), "Test warning");
247 }
248
249 #[test]
250 fn test_beta_params_builder() {
251 let params = BetaParams::new("test_function")
252 .with_obj_type("function")
253 .with_addendum("Consider using other_function.");
254
255 assert_eq!(params.name, Some("test_function".to_string()));
256 assert_eq!(params.obj_type, Some("function".to_string()));
257 assert_eq!(
258 params.addendum,
259 Some("Consider using other_function.".to_string())
260 );
261 }
262
263 #[test]
264 fn test_suppress_beta_warnings() {
265 surface_beta_warnings();
267 assert!(!SUPPRESS_BETA_WARNINGS.load(Ordering::Relaxed));
268
269 {
270 let _guard = suppress_beta_warnings();
271 assert!(SUPPRESS_BETA_WARNINGS.load(Ordering::Relaxed));
272 }
273
274 assert!(!SUPPRESS_BETA_WARNINGS.load(Ordering::Relaxed));
275 }
276}