1#![deny(missing_docs)]
47#![deny(unsafe_code)]
48
49pub mod coercion;
51pub mod error;
52pub mod message;
53pub mod provider;
54pub mod request;
55pub mod response;
56pub mod telemetry;
58pub mod tool;
59pub mod validation;
60
61pub use error::{HealingError, ProviderError, Result, SimpleAgentsError, ValidationError};
63pub use telemetry::{ApiFormat, OtelProtocol, TelemetryConfig, TraceContext};
64
65pub mod prelude {
79 pub use crate::message::{
81 mime, ContentPart, ImageUrlContent, MediaContent, Message, MessageContent, Role,
82 };
83
84 pub use crate::request::{CompletionRequest, CompletionRequestBuilder};
86 pub use crate::response::{
87 ChoiceDelta, CompletionChoice, CompletionChunk, CompletionResponse, FinishReason,
88 MessageDelta, Usage,
89 };
90
91 pub use crate::error::{
93 HealingError, ProviderError, Result, SimpleAgentsError, ValidationError,
94 };
95
96 pub use crate::validation::ApiKey;
98
99 pub use crate::coercion::{CoercionFlag, CoercionResult};
101
102 pub use crate::tool::{
104 ToolCall, ToolCallFunction, ToolChoice, ToolChoiceFunction, ToolChoiceMode, ToolChoiceTool,
105 ToolDefinition, ToolFunction, ToolType,
106 };
107
108 pub use crate::provider::Provider;
110
111 pub use crate::provider::{ProviderRequest, ProviderResponse};
113}
114
115#[cfg(test)]
116mod tests {
117 use super::prelude::*;
118
119 #[test]
120 fn test_prelude_imports() {
121 let _msg = Message::user("test");
122 let _request = CompletionRequest::builder()
123 .model("test")
124 .message(Message::user("test"))
125 .build()
126 .unwrap();
127 }
128
129 #[test]
130 fn test_error_conversion() {
131 let validation_err = ValidationError::new("test");
132 let _agents_err: SimpleAgentsError = validation_err.into();
133 }
134
135 #[test]
136 fn test_api_key_security() {
137 let key = ApiKey::new("sk-1234567890abcdef1234567890").unwrap();
138 let debug = format!("{:?}", key);
139 assert!(debug.contains("REDACTED"));
140 }
141
142 #[test]
143 fn test_coercion_transparency() {
144 let result = CoercionResult::new(42).with_flag(CoercionFlag::StrippedMarkdown);
145 assert!(result.was_coerced());
146 assert_eq!(result.flags.len(), 1);
147 }
148
149 #[test]
150 fn test_builder_pattern() {
151 let request = CompletionRequest::builder()
152 .model("gpt-4")
153 .message(Message::user("Hello"))
154 .temperature(0.7)
155 .build()
156 .unwrap();
157
158 assert_eq!(request.model, "gpt-4");
159 assert_eq!(request.temperature, Some(0.7));
160 }
161
162 #[test]
163 fn test_response_helper() {
164 let response = CompletionResponse {
165 id: "resp_123".to_string(),
166 model: "gpt-4".to_string(),
167 choices: vec![CompletionChoice {
168 index: 0,
169 message: Message::assistant("Hello!"),
170 finish_reason: FinishReason::Stop,
171 logprobs: None,
172 }],
173 usage: Usage::new(10, 5),
174 created: None,
175 provider: None,
176 healing_metadata: None,
177 };
178
179 assert_eq!(response.content(), Some("Hello!"));
180 }
181
182 #[test]
183 fn test_all_types_send_sync() {
184 fn assert_send_sync<T: Send + Sync>() {}
185
186 assert_send_sync::<Message>();
188 assert_send_sync::<CompletionRequest>();
189 assert_send_sync::<CompletionResponse>();
190
191 assert_send_sync::<CoercionFlag>();
193 assert_send_sync::<CoercionResult<String>>();
194
195 assert_send_sync::<ProviderRequest>();
197 assert_send_sync::<ProviderResponse>();
198 }
199}