Skip to main content

serdes_ai/
lib.rs

1//! # SerdesAI - Type-Safe AI Agent Framework for Rust
2//!
3//! SerdesAI is a comprehensive Rust library for building AI agents that interact with
4//! large language models (LLMs). It is a complete port of [pydantic-ai](https://github.com/pydantic/pydantic-ai)
5//! to Rust, providing type-safe, ergonomic APIs for creating intelligent agents.
6//!
7//! ## Quick Start
8//!
9//! ```ignore
10//! use serdes_ai::prelude::*;
11//!
12//! #[tokio::main]
13//! async fn main() -> anyhow::Result<()> {
14//!     let agent = Agent::builder()
15//!         .model("openai:gpt-4o")
16//!         .system_prompt("You are a helpful assistant.")
17//!         .build()?;
18//!
19//!     let result = agent.run("What is the capital of France?", ()).await?;
20//!     println!("{}", result.output());
21//!     Ok(())
22//! }
23//! ```
24//!
25//! ## Key Features
26//!
27//! - **Type-safe agents** with generic dependencies and output types
28//! - **Multiple LLM providers** (OpenAI, Anthropic, Google, Groq, Mistral, Ollama, Bedrock)
29//! - **Tool/function calling** with automatic JSON schema generation
30//! - **Streaming responses** with real-time text updates
31//! - **Structured outputs** with JSON Schema validation
32//! - **MCP protocol support** for Model Context Protocol servers
33//! - **Embeddings** for semantic search and RAG applications
34//! - **Graph-based workflows** for complex multi-step tasks
35//! - **Evaluation framework** for testing and benchmarking agents
36//! - **Retry strategies** with exponential backoff
37//! - **OpenTelemetry integration** for observability
38//!
39//! ## Feature Flags
40//!
41//! | Feature | Description | Default |
42//! |---------|-------------|--------|
43//! | `openai` | OpenAI GPT models | ✅ |
44//! | `anthropic` | Anthropic Claude models | ✅ |
45//! | `gemini` | Google Gemini models | ❌ |
46//! | `groq` | Groq fast inference | ❌ |
47//! | `mistral` | Mistral AI models | ❌ |
48//! | `ollama` | Local Ollama models | ❌ |
49//! | `bedrock` | AWS Bedrock | ❌ |
50//! | `mcp` | MCP protocol support | ❌ |
51//! | `embeddings` | Embedding models | ❌ |
52//! | `graph` | Graph execution engine | ❌ |
53//! | `evals` | Evaluation framework | ❌ |
54//! | `macros` | Proc macros | ✅ |
55//! | `otel` | OpenTelemetry | ❌ |
56//! | `full` | All features | ❌ |
57//!
58//! ## Architecture
59//!
60//! SerdesAI is organized as a workspace of focused crates:
61//!
62//! - [`serdes_ai_core`] - Core types, messages, and errors
63//! - [`serdes_ai_agent`] - Agent implementation and builder
64//! - [`serdes_ai_models`] - Model trait and implementations
65//! - [`serdes_ai_tools`] - Tool system and schema generation
66//! - [`serdes_ai_toolsets`] - Toolset abstractions
67//! - [`serdes_ai_output`] - Output schema validation
68//! - [`serdes_ai_streaming`] - Streaming support
69//! - [`serdes_ai_retries`] - Retry strategies
70//! - [`serdes_ai_mcp`] - MCP protocol (optional)
71//! - [`serdes_ai_embeddings`] - Embeddings (optional)
72//! - [`serdes_ai_graph`] - Graph execution (optional)
73//! - [`serdes_ai_evals`] - Evaluation framework (optional)
74//! - [`serdes_ai_macros`] - Procedural macros
75//!
76//! ## Examples
77//!
78//! ### Simple Chat
79//!
80//! ```ignore
81//! use serdes_ai::prelude::*;
82//!
83//! let agent = Agent::builder()
84//!     .model("openai:gpt-4o")
85//!     .system_prompt("You are helpful.")
86//!     .build()?;
87//!
88//! let result = agent.run("Hello!", ()).await?;
89//! ```
90//!
91//! ### With Tools
92//!
93//! ```ignore
94//! use serdes_ai::prelude::*;
95//!
96//! #[tool(description = "Get weather for a city")]
97//! async fn get_weather(ctx: &RunContext<()>, city: String) -> ToolResult<String> {
98//!     Ok(format!("Weather in {}: 22°C, sunny", city))
99//! }
100//!
101//! let agent = Agent::builder()
102//!     .model("openai:gpt-4o")
103//!     .tool(get_weather)
104//!     .build()?;
105//! ```
106//!
107//! ### Structured Output
108//!
109//! ```ignore
110//! use serdes_ai::prelude::*;
111//! use serde::Deserialize;
112//!
113//! #[derive(Deserialize, OutputSchema)]
114//! struct Person {
115//!     name: String,
116//!     age: u32,
117//! }
118//!
119//! let agent = Agent::builder()
120//!     .model("openai:gpt-4o")
121//!     .output_type::<Person>()
122//!     .build()?;
123//!
124//! let result: Person = agent.run("Extract: John is 30 years old", ()).await?.into_output();
125//! ```
126//!
127//! ### Streaming
128//!
129//! ```ignore
130//! use serdes_ai::prelude::*;
131//! use futures::StreamExt;
132//!
133//! let mut stream = agent.run_stream("Tell me a story", ()).await?;
134//!
135//! while let Some(event) = stream.next().await {
136//!     if let AgentStreamEvent::Text { delta } = event? {
137//!         print!("{}", delta);
138//!     }
139//! }
140//! ```
141
142#![warn(missing_docs)]
143#![warn(rustdoc::missing_crate_level_docs)]
144#![deny(unsafe_code)]
145#![cfg_attr(docsrs, feature(doc_cfg))]
146
147// ============================================================================
148// Direct Model Access
149// ============================================================================
150
151/// Direct model request functions for imperative API access.
152///
153/// Use this module when you want to make simple, direct requests to models
154/// without the full agent infrastructure.
155///
156/// # Example
157///
158/// ```rust,ignore
159/// use serdes_ai::direct::model_request;
160/// use serdes_ai_core::ModelRequest;
161///
162/// let response = model_request(
163///     "openai:gpt-4o",
164///     &[ModelRequest::user("Hello!")],
165///     None,
166///     None,
167/// ).await?;
168/// ```
169pub mod direct;
170
171// ============================================================================
172// Core Crate Re-exports
173// ============================================================================
174
175/// Core types, messages, and error handling.
176pub use serdes_ai_core as core;
177
178/// Agent implementation and builder.
179pub use serdes_ai_agent as agent;
180
181/// Model traits and implementations.
182pub use serdes_ai_models as models;
183
184/// Provider abstractions.
185pub use serdes_ai_providers as providers;
186
187/// Tool system.
188pub use serdes_ai_tools as tools;
189
190/// Toolset abstractions.
191pub use serdes_ai_toolsets as toolsets;
192
193/// Output schema validation.
194pub use serdes_ai_output as output;
195
196/// Streaming support.
197pub use serdes_ai_streaming as streaming;
198
199/// Retry strategies.
200pub use serdes_ai_retries as retries;
201
202// ============================================================================
203// Optional Crate Re-exports
204// ============================================================================
205
206/// Model Context Protocol support.
207#[cfg(feature = "mcp")]
208#[cfg_attr(docsrs, doc(cfg(feature = "mcp")))]
209pub use serdes_ai_mcp as mcp;
210
211/// Embedding models.
212#[cfg(feature = "embeddings")]
213#[cfg_attr(docsrs, doc(cfg(feature = "embeddings")))]
214pub use serdes_ai_embeddings as embeddings;
215
216/// Graph-based execution engine.
217#[cfg(feature = "graph")]
218#[cfg_attr(docsrs, doc(cfg(feature = "graph")))]
219pub use serdes_ai_graph as graph;
220
221/// Evaluation framework.
222#[cfg(feature = "evals")]
223#[cfg_attr(docsrs, doc(cfg(feature = "evals")))]
224pub use serdes_ai_evals as evals;
225
226// ============================================================================
227// Macro Re-exports
228// ============================================================================
229
230/// Derive macro for tools.
231#[cfg(feature = "macros")]
232#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
233pub use serdes_ai_macros::Tool;
234
235/// Derive macro for output schemas.
236#[cfg(feature = "macros")]
237#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
238pub use serdes_ai_macros::OutputSchema;
239
240/// Attribute macro for tool functions.
241#[cfg(feature = "macros")]
242#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
243pub use serdes_ai_macros::tool;
244
245/// Attribute macro for agent definitions.
246#[cfg(feature = "macros")]
247#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
248pub use serdes_ai_macros::agent as agent_macro;
249
250// ============================================================================
251// Core Type Re-exports (Flat)
252// ============================================================================
253
254// Errors
255pub use serdes_ai_core::SerdesAiError;
256
257// Identifiers
258pub use serdes_ai_core::{ConversationId, RunId, ToolCallId};
259
260// Messages
261pub use serdes_ai_core::{
262    BinaryContent,
263    // Builtin tools
264    BuiltinToolCallPart,
265    BuiltinToolReturnContent,
266    BuiltinToolReturnPart,
267    CodeExecutionResult,
268    // File and binary content
269    FilePart,
270    FileSearchResult,
271    FileSearchResults,
272    FinishReason,
273    ModelRequest,
274    ModelRequestPart,
275    ModelResponse,
276    ModelResponsePart,
277    ModelResponsePartDelta,
278    // Streaming events
279    ModelResponseStreamEvent,
280    PartDeltaEvent,
281    PartEndEvent,
282    PartStartEvent,
283    SystemPromptPart,
284    TextPart,
285    ThinkingPart,
286    ToolCallPart,
287    ToolReturnPart,
288    UserContent,
289    WebSearchResult,
290    WebSearchResults,
291};
292
293// Settings
294pub use serdes_ai_core::ModelSettings;
295
296// Usage
297pub use serdes_ai_core::{RequestUsage, RunUsage, UsageLimits};
298
299// Format
300pub use serdes_ai_core::{
301    format_as_xml, format_as_xml_with_options, XmlFormatError, XmlFormatOptions,
302};
303
304// Agent
305pub use serdes_ai_agent::{
306    Agent, AgentBuilder, AgentRun, AgentRunResult, AgentStream, AgentStreamEvent, EndStrategy,
307    ModelConfig, RunContext, RunOptions, StepResult,
308};
309
310// Models
311pub use serdes_ai_models::Model;
312pub use serdes_ai_models::{build_model_extended, build_model_with_config, ExtendedModelConfig};
313
314#[cfg(feature = "openai")]
315#[cfg_attr(docsrs, doc(cfg(feature = "openai")))]
316pub use serdes_ai_models::openai::OpenAIChatModel;
317
318#[cfg(feature = "anthropic")]
319#[cfg_attr(docsrs, doc(cfg(feature = "anthropic")))]
320pub use serdes_ai_models::anthropic::AnthropicModel;
321
322#[cfg(feature = "gemini")]
323#[cfg_attr(docsrs, doc(cfg(feature = "gemini")))]
324pub use serdes_ai_models::GeminiModel;
325
326#[cfg(feature = "groq")]
327#[cfg_attr(docsrs, doc(cfg(feature = "groq")))]
328pub use serdes_ai_models::groq::GroqModel;
329
330#[cfg(feature = "mistral")]
331#[cfg_attr(docsrs, doc(cfg(feature = "mistral")))]
332pub use serdes_ai_models::mistral::MistralModel;
333
334#[cfg(feature = "ollama")]
335#[cfg_attr(docsrs, doc(cfg(feature = "ollama")))]
336pub use serdes_ai_models::ollama::OllamaModel;
337
338#[cfg(feature = "bedrock")]
339#[cfg_attr(docsrs, doc(cfg(feature = "bedrock")))]
340pub use serdes_ai_models::bedrock::BedrockModel;
341
342// Tools
343pub use serdes_ai_tools::{
344    ObjectJsonSchema, SchemaBuilder, Tool, ToolDefinition, ToolRegistry, ToolResult,
345};
346
347// Toolsets
348pub use serdes_ai_toolsets::{
349    AbstractToolset, ApprovalRequiredToolset, BoxedToolset, CombinedToolset, DynamicToolset,
350    ExternalToolset, FilteredToolset, FunctionToolset, PrefixedToolset, PreparedToolset,
351    RenamedToolset, ToolsetInfo, ToolsetTool, WrapperToolset,
352};
353
354// Output
355pub use serdes_ai_output::{
356    OutputSchema, StructuredOutputSchema, TextOutputSchema, ValidationResult,
357};
358
359// Streaming
360pub use serdes_ai_streaming::{ResponseDelta, ResponseStream};
361
362// Retries
363pub use serdes_ai_retries::{
364    ExponentialBackoff, FixedDelay, LinearBackoff, RetryConfig, RetryStrategy,
365};
366
367// Direct model access
368pub use direct::{
369    model_request, model_request_stream, model_request_stream_sync, model_request_sync,
370    DirectError, ModelSpec, StreamedResponseSync,
371};
372
373// ============================================================================
374// Optional Type Re-exports
375// ============================================================================
376
377// MCP
378#[cfg(feature = "mcp")]
379#[cfg_attr(docsrs, doc(cfg(feature = "mcp")))]
380pub use serdes_ai_mcp::{McpClient, McpToolset};
381
382// Embeddings
383#[cfg(feature = "embeddings")]
384#[cfg_attr(docsrs, doc(cfg(feature = "embeddings")))]
385pub use serdes_ai_embeddings::{EmbeddingModel, EmbeddingResult};
386
387// Graph
388#[cfg(feature = "graph")]
389#[cfg_attr(docsrs, doc(cfg(feature = "graph")))]
390pub use serdes_ai_graph::{
391    BaseNode, Edge, End, Graph, GraphError, GraphExecutor, GraphResult, GraphRunContext,
392    GraphRunResult, NodeResult,
393};
394
395// Evals
396#[cfg(feature = "evals")]
397#[cfg_attr(docsrs, doc(cfg(feature = "evals")))]
398pub use serdes_ai_evals::{
399    Case, ContainsScorer, Dataset, EvalCase, EvalRunner, EvalSuite, EvaluationReport,
400    EvaluationResult, Evaluator, ExactMatchScorer,
401};
402
403// ============================================================================
404// Prelude Module
405// ============================================================================
406
407/// Convenient prelude for common imports.
408///
409/// Import everything you need with a single use statement:
410///
411/// ```ignore
412/// use serdes_ai::prelude::*;
413/// ```
414pub mod prelude {
415    // Core types
416    pub use crate::core::{ConversationId, Result, RunId, SerdesAiError, ToolCallId};
417
418    // Messages
419    pub use crate::core::{
420        FinishReason, ModelRequest, ModelResponse, ModelSettings, RequestUsage, RunUsage,
421        UsageLimits, UserContent,
422    };
423
424    // Agent
425    pub use crate::agent::{
426        Agent, AgentBuilder, AgentRun, AgentRunResult, AgentStream, AgentStreamEvent, EndStrategy,
427        ModelConfig, RunContext, RunOptions,
428    };
429
430    // Models
431    pub use crate::models::Model;
432
433    #[cfg(feature = "openai")]
434    pub use crate::models::openai::OpenAIChatModel;
435
436    #[cfg(feature = "anthropic")]
437    pub use crate::models::anthropic::AnthropicModel;
438
439    // Tools
440    pub use crate::tools::{Tool, ToolDefinition, ToolRegistry, ToolResult};
441
442    // Toolsets
443    pub use crate::toolsets::{
444        AbstractToolset, BoxedToolset, CombinedToolset, DynamicToolset, FunctionToolset,
445    };
446
447    // Output
448    pub use crate::output::{
449        OutputSchema, StructuredOutputSchema, TextOutputSchema, ValidationResult,
450    };
451
452    // Streaming
453    pub use crate::streaming::{ResponseDelta, ResponseStream};
454
455    // Retries
456    pub use crate::retries::{ExponentialBackoff, RetryConfig, RetryStrategy};
457
458    // Direct model access
459    pub use crate::direct::{model_request, model_request_stream, DirectError, ModelSpec};
460
461    // Format
462    pub use crate::core::{format_as_xml, XmlFormatOptions};
463
464    // Macros
465    #[cfg(feature = "macros")]
466    pub use crate::{tool, OutputSchema as DeriveOutputSchema, Tool as DeriveTool};
467
468    // MCP
469    #[cfg(feature = "mcp")]
470    pub use crate::mcp::{McpClient, McpToolset};
471
472    // Graph
473    #[cfg(feature = "graph")]
474    pub use crate::graph::{
475        BaseNode, End, Graph, GraphError, GraphExecutor, GraphResult, GraphRunContext,
476        GraphRunResult, NodeResult,
477    };
478
479    // Evals
480    #[cfg(feature = "evals")]
481    pub use crate::evals::{EvalCase, EvalRunner, EvalSuite, Evaluator};
482}
483
484// ============================================================================
485// Version Information
486// ============================================================================
487
488/// Returns the current version of serdes-ai.
489pub fn version() -> &'static str {
490    env!("CARGO_PKG_VERSION")
491}
492
493/// Returns version information as a tuple (major, minor, patch).
494pub fn version_tuple() -> (u32, u32, u32) {
495    let version = version();
496    let parts: Vec<&str> = version.split('.').collect();
497    (
498        parts.first().and_then(|s| s.parse().ok()).unwrap_or(0),
499        parts.get(1).and_then(|s| s.parse().ok()).unwrap_or(0),
500        parts.get(2).and_then(|s| s.parse().ok()).unwrap_or(0),
501    )
502}
503
504#[cfg(test)]
505mod tests {
506    use super::*;
507
508    #[test]
509    fn test_version() {
510        assert_eq!(version(), "0.1.3");
511    }
512
513    #[test]
514    fn test_version_tuple() {
515        let (major, minor, patch) = version_tuple();
516        assert_eq!(major, 0);
517        assert_eq!(minor, 1);
518        assert_eq!(patch, 3);
519    }
520
521    #[test]
522    fn test_prelude_imports() {
523        // Just verify these types exist and are accessible
524        let _: fn() -> &'static str = crate::version;
525    }
526}