Skip to main content

simple_agent_type/
lib.rs

1//! Core types and traits for SimpleAgents.
2//!
3//! This crate provides all foundational types, traits, and error definitions
4//! shared across the SimpleAgents project. It is a pure types crate with no
5//! runtime, HTTP, or I/O dependencies.
6//!
7//! # Architecture
8//!
9//! SimpleAgents follows a trait-based architecture:
10//!
11//! - **Provider**: Trait for LLM provider implementations
12//!
13//! # Main Types
14//!
15//! - [`Message`]: Role-based conversation messages
16//! - [`CompletionRequest`]: Unified request format
17//! - [`CompletionResponse`]: Unified response format
18//! - [`ApiKey`]: Secure API key handling
19//!
20//! # Example
21//!
22//! ```
23//! use simple_agent_type::prelude::*;
24//!
25//! // Create a request
26//! let request = CompletionRequest::builder()
27//!     .model("gpt-4")
28//!     .message(Message::user("Hello!"))
29//!     .temperature(0.7)
30//!     .build()
31//!     .unwrap();
32//!
33//! // Access request properties
34//! assert_eq!(request.model, "gpt-4");
35//! assert_eq!(request.messages.len(), 1);
36//! ```
37//!
38//! # Features
39//!
40//! - **Type Safety**: Strong types prevent common errors
41//! - **Transparency**: All transformations tracked via [`CoercionFlag`]
42//! - **Security**: API keys never logged ([`ApiKey`])
43//! - **Validation**: Early validation with clear errors
44//! - **Async**: All traits use `async_trait`
45
46#![deny(missing_docs)]
47#![deny(unsafe_code)]
48
49// Core modules
50pub mod coercion;
51pub mod error;
52pub mod message;
53pub mod provider;
54pub mod request;
55pub mod response;
56/// Telemetry and tracing configuration types.
57pub mod telemetry;
58pub mod tool;
59pub mod validation;
60
61// Re-export commonly used types at crate root
62pub use error::{HealingError, ProviderError, Result, SimpleAgentsError, ValidationError};
63pub use telemetry::{ApiFormat, OtelProtocol, TelemetryConfig, TraceContext};
64
65/// Prelude module for convenient imports.
66///
67/// # Example
68/// ```
69/// use simple_agent_type::prelude::*;
70///
71/// let msg = Message::user("Hello!");
72/// let request = CompletionRequest::builder()
73///     .model("gpt-4")
74///     .message(msg)
75///     .build()
76///     .unwrap();
77/// ```
78pub mod prelude {
79    // Messages
80    pub use crate::message::{
81        mime, ContentPart, ImageUrlContent, MediaContent, Message, MessageContent, Role,
82    };
83
84    // Requests and responses
85    pub use crate::request::{CompletionRequest, CompletionRequestBuilder};
86    pub use crate::response::{
87        ChoiceDelta, CompletionChoice, CompletionChunk, CompletionResponse, FinishReason,
88        MessageDelta, Usage,
89    };
90
91    // Errors
92    pub use crate::error::{
93        HealingError, ProviderError, Result, SimpleAgentsError, ValidationError,
94    };
95
96    // Validation
97    pub use crate::validation::ApiKey;
98
99    // Coercion
100    pub use crate::coercion::{CoercionFlag, CoercionResult};
101
102    // Tool calling
103    pub use crate::tool::{
104        ToolCall, ToolCallFunction, ToolChoice, ToolChoiceFunction, ToolChoiceMode, ToolChoiceTool,
105        ToolDefinition, ToolFunction, ToolType,
106    };
107
108    // Traits
109    pub use crate::provider::Provider;
110
111    // Provider types
112    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        // Core types
187        assert_send_sync::<Message>();
188        assert_send_sync::<CompletionRequest>();
189        assert_send_sync::<CompletionResponse>();
190
191        // Coercion types
192        assert_send_sync::<CoercionFlag>();
193        assert_send_sync::<CoercionResult<String>>();
194
195        // Provider types
196        assert_send_sync::<ProviderRequest>();
197        assert_send_sync::<ProviderResponse>();
198    }
199}