1#![deny(missing_docs)]
49#![deny(unsafe_code)]
50
51pub mod cache;
53pub mod coercion;
54pub mod config;
55pub mod error;
56pub mod message;
57pub mod provider;
58pub mod request;
59pub mod response;
60pub mod router;
61pub mod validation;
62
63pub use error::{HealingError, ProviderError, Result, SimpleAgentsError, ValidationError};
65
66pub mod prelude {
80 pub use crate::message::{Message, Role};
82
83 pub use crate::request::{CompletionRequest, CompletionRequestBuilder};
85 pub use crate::response::{
86 ChoiceDelta, CompletionChoice, CompletionChunk, CompletionResponse, FinishReason,
87 MessageDelta, Usage,
88 };
89
90 pub use crate::error::{
92 HealingError, ProviderError, Result, SimpleAgentsError, ValidationError,
93 };
94
95 pub use crate::validation::ApiKey;
97
98 pub use crate::config::{Capabilities, HealingConfig, ProviderConfig, RetryConfig};
100
101 pub use crate::coercion::{CoercionFlag, CoercionResult};
103
104 pub use crate::cache::Cache;
106 pub use crate::provider::Provider;
107 pub use crate::router::RoutingStrategy;
108
109 pub use crate::provider::{ProviderRequest, ProviderResponse};
111
112 pub use crate::router::{ProviderHealth, ProviderMetrics, RoutingMode};
114}
115
116#[cfg(test)]
117mod tests {
118 use super::prelude::*;
119
120 #[test]
121 fn test_prelude_imports() {
122 let _msg = Message::user("test");
124 let _request = CompletionRequest::builder()
125 .model("test")
126 .message(Message::user("test"))
127 .build()
128 .unwrap();
129 }
130
131 #[test]
132 fn test_error_conversion() {
133 let validation_err = ValidationError::new("test");
134 let _agents_err: SimpleAgentsError = validation_err.into();
135 }
136
137 #[test]
138 fn test_api_key_security() {
139 let key = ApiKey::new("sk-1234567890abcdef1234567890").unwrap();
140 let debug = format!("{:?}", key);
141 assert!(debug.contains("REDACTED"));
142 }
143
144 #[test]
145 fn test_coercion_transparency() {
146 let result = CoercionResult::new(42).with_flag(CoercionFlag::StrippedMarkdown);
147 assert!(result.was_coerced());
148 assert_eq!(result.flags.len(), 1);
149 }
150
151 #[test]
152 fn test_builder_pattern() {
153 let request = CompletionRequest::builder()
154 .model("gpt-4")
155 .message(Message::user("Hello"))
156 .temperature(0.7)
157 .build()
158 .unwrap();
159
160 assert_eq!(request.model, "gpt-4");
161 assert_eq!(request.temperature, Some(0.7));
162 }
163
164 #[test]
165 fn test_response_helper() {
166 let response = CompletionResponse {
167 id: "resp_123".to_string(),
168 model: "gpt-4".to_string(),
169 choices: vec![CompletionChoice {
170 index: 0,
171 message: Message::assistant("Hello!"),
172 finish_reason: FinishReason::Stop,
173 logprobs: None,
174 }],
175 usage: Usage::new(10, 5),
176 created: None,
177 provider: None,
178 healing_metadata: None,
179 };
180
181 assert_eq!(response.content(), Some("Hello!"));
182 }
183
184 #[test]
185 fn test_all_types_send_sync() {
186 fn assert_send_sync<T: Send + Sync>() {}
187
188 assert_send_sync::<Message>();
190 assert_send_sync::<CompletionRequest>();
191 assert_send_sync::<CompletionResponse>();
192
193 assert_send_sync::<RetryConfig>();
195 assert_send_sync::<HealingConfig>();
196 assert_send_sync::<Capabilities>();
197
198 assert_send_sync::<CoercionFlag>();
200 assert_send_sync::<CoercionResult<String>>();
201
202 assert_send_sync::<ProviderRequest>();
204 assert_send_sync::<ProviderResponse>();
205 }
206}