Skip to main content

simple_agent_type/
lib.rs

1//! Core type definitions, async provider traits, and configuration types for
2//! SimpleAgents.
3//!
4//! No HTTP client or networking code — but includes `async-trait` for provider
5//! interfaces and config types that read from the environment
6//! (e.g. [`TelemetryConfig::from_env`]).
7//!
8//! # Architecture
9//!
10//! SimpleAgents follows a trait-based architecture:
11//!
12//! - **Provider**: Async trait for LLM provider implementations
13//!
14//! # Main Types
15//!
16//! - [`Message`]: Role-based conversation messages
17//! - [`CompletionRequest`]: Unified request format
18//! - [`CompletionResponse`]: Unified response format
19//! - [`ApiKey`]: Secure API key handling
20//!
21//! # Example
22//!
23//! ```
24//! use simple_agent_type::prelude::*;
25//!
26//! // Create a request
27//! let request = CompletionRequest::builder()
28//!     .model("gpt-4")
29//!     .message(Message::user("Hello!"))
30//!     .temperature(0.7)
31//!     .build()
32//!     .unwrap();
33//!
34//! // Access request properties
35//! assert_eq!(request.model, "gpt-4");
36//! assert_eq!(request.messages.len(), 1);
37//! ```
38//!
39//! # Features
40//!
41//! - **Type Safety**: Strong types prevent common errors
42//! - **Transparency**: All transformations tracked via [`CoercionFlag`]
43//! - **Security**: API keys never logged ([`ApiKey`])
44//! - **Validation**: Early validation with clear errors
45//! - **Async**: All traits use `async_trait`
46
47#![deny(missing_docs)]
48#![deny(unsafe_code)]
49
50// Core modules
51pub mod coercion;
52pub mod error;
53pub mod message;
54pub mod provider;
55pub mod request;
56pub mod response;
57/// Telemetry and tracing configuration types.
58pub mod telemetry;
59pub mod tool;
60pub mod validation;
61
62// Re-export commonly used types at crate root
63pub use error::{HealingError, ProviderError, Result, SimpleAgentsError, ValidationError};
64pub use telemetry::{ApiFormat, OtelProtocol, TelemetryConfig, TraceContext};
65
66/// Prelude module for convenient imports.
67///
68/// # Example
69/// ```
70/// use simple_agent_type::prelude::*;
71///
72/// let msg = Message::user("Hello!");
73/// let request = CompletionRequest::builder()
74///     .model("gpt-4")
75///     .message(msg)
76///     .build()
77///     .unwrap();
78/// ```
79pub mod prelude {
80    // Messages
81    pub use crate::message::{
82        mime, ContentPart, ImageUrlContent, MediaContent, Message, MessageContent, Role,
83    };
84
85    // Requests and responses
86    pub use crate::request::{CompletionRequest, CompletionRequestBuilder};
87    pub use crate::response::{
88        ChoiceDelta, CompletionChoice, CompletionChunk, CompletionResponse, FinishReason,
89        MessageDelta, Usage,
90    };
91
92    // Errors
93    pub use crate::error::{
94        HealingError, ProviderError, Result, SimpleAgentsError, ValidationError,
95    };
96
97    // Validation
98    pub use crate::validation::ApiKey;
99
100    // Coercion
101    pub use crate::coercion::{CoercionFlag, CoercionResult};
102
103    // Tool calling
104    pub use crate::tool::{
105        ToolCall, ToolCallFunction, ToolChoice, ToolChoiceFunction, ToolChoiceMode, ToolChoiceTool,
106        ToolDefinition, ToolFunction, ToolType,
107    };
108
109    // Traits
110    pub use crate::provider::Provider;
111
112    // Provider types
113    pub use crate::provider::{ProviderRequest, ProviderResponse};
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");
123        let _request = CompletionRequest::builder()
124            .model("test")
125            .message(Message::user("test"))
126            .build()
127            .unwrap();
128    }
129
130    #[test]
131    fn test_error_conversion() {
132        let validation_err = ValidationError::new("test");
133        let _agents_err: SimpleAgentsError = validation_err.into();
134    }
135
136    #[test]
137    fn test_api_key_security() {
138        let key = ApiKey::new("sk-1234567890abcdef1234567890").unwrap();
139        let debug = format!("{:?}", key);
140        assert!(debug.contains("REDACTED"));
141    }
142
143    #[test]
144    fn test_coercion_transparency() {
145        let result = CoercionResult::new(42).with_flag(CoercionFlag::StrippedMarkdown);
146        assert!(result.was_coerced());
147        assert_eq!(result.flags.len(), 1);
148    }
149
150    #[test]
151    fn test_builder_pattern() {
152        let request = CompletionRequest::builder()
153            .model("gpt-4")
154            .message(Message::user("Hello"))
155            .temperature(0.7)
156            .build()
157            .unwrap();
158
159        assert_eq!(request.model, "gpt-4");
160        assert_eq!(request.temperature, Some(0.7));
161    }
162
163    #[test]
164    fn test_response_helper() {
165        let response = CompletionResponse {
166            id: "resp_123".to_string(),
167            model: "gpt-4".to_string(),
168            choices: vec![CompletionChoice {
169                index: 0,
170                message: Message::assistant("Hello!"),
171                finish_reason: FinishReason::Stop,
172                logprobs: None,
173            }],
174            usage: Usage::new(10, 5),
175            created: None,
176            provider: None,
177            healing_metadata: None,
178        };
179
180        assert_eq!(response.content(), Some("Hello!"));
181    }
182
183    #[test]
184    fn test_all_types_send_sync() {
185        fn assert_send_sync<T: Send + Sync>() {}
186
187        // Core types
188        assert_send_sync::<Message>();
189        assert_send_sync::<CompletionRequest>();
190        assert_send_sync::<CompletionResponse>();
191
192        // Coercion types
193        assert_send_sync::<CoercionFlag>();
194        assert_send_sync::<CoercionResult<String>>();
195
196        // Provider types
197        assert_send_sync::<ProviderRequest>();
198        assert_send_sync::<ProviderResponse>();
199    }
200}