Skip to main content

anthropic_tools/
lib.rs

1//! # Anthropic Tools
2//!
3//! A Rust library for interacting with the Anthropic API.
4//!
5//! ## Features
6//!
7//! - Messages API with builder pattern
8//! - Tool/Function calling support
9//! - Vision/Multimodal support
10//! - Prompt caching support
11//! - Extended thinking support
12//! - Streaming support (planned)
13//!
14//! ## Configuration
15//!
16//! Set the API key via environment variable or `.env` file:
17//!
18//! ```bash
19//! # Environment variable
20//! export ANTHROPIC_API_KEY="sk-ant-..."
21//!
22//! # Or create .env file in project root
23//! echo 'ANTHROPIC_API_KEY=sk-ant-...' > .env
24//! ```
25//!
26//! Priority: Environment variable > `.env` file > [`Messages::with_api_key()`]
27//!
28//! ## Example
29//!
30//! ```rust,no_run
31//! use anthropic_tools::prelude::*;
32//!
33//! #[tokio::main]
34//! async fn main() -> Result<()> {
35//!     let mut client = Messages::new();
36//!     client
37//!         .model(Model::Sonnet4)  // Type-safe model selection
38//!         .max_tokens(1024)
39//!         .system("You are a helpful assistant.")
40//!         .user("Hello, how are you?");
41//!
42//!     let response = client.post().await?;
43//!     println!("{}", response.get_text());
44//!     Ok(())
45//! }
46//! ```
47
48pub mod common;
49pub mod messages;
50
51/// Commonly used types and traits
52pub mod prelude {
53    // Error types
54    pub use crate::common::errors::{AnthropicToolError, Result};
55
56    // Usage
57    pub use crate::common::usage::Usage;
58
59    // Tool definitions
60    pub use crate::common::tool::{CacheControl, JsonSchema, PropertyDef, Tool};
61
62    // Messages API
63    pub use crate::messages::request::{
64        Messages,
65        body::{Body, Metadata, ThinkingConfig, ToolChoice},
66        content::{ContentBlock, DocumentSource, ImageSource, MediaType},
67        message::{Message, SystemBlock, SystemPrompt},
68        model::Model,
69        role::Role,
70    };
71
72    // Response types
73    pub use crate::messages::response::{Response, StopReason};
74
75    // Streaming types
76    pub use crate::messages::streaming::{Delta, MessageDelta, StreamAccumulator, StreamEvent};
77}
78
79// Re-export main types at crate level
80pub use common::{AnthropicToolError, Result, Tool, Usage};
81pub use messages::request::Messages;
82pub use messages::response::Response;
83
84#[cfg(test)]
85mod tests {
86    use super::prelude::*;
87
88    #[test]
89    fn test_messages_builder() {
90        let mut client = Messages::with_api_key("test_key");
91        client
92            .model(Model::Sonnet4)
93            .max_tokens(1024)
94            .system("You are a helpful assistant.")
95            .user("Hello!");
96
97        let body = client.body();
98        assert_eq!(body.model, Model::Sonnet4);
99        assert_eq!(body.max_tokens, 1024);
100        assert_eq!(body.messages.len(), 1);
101    }
102
103    #[test]
104    fn test_messages_builder_with_string_model() {
105        let mut client = Messages::with_api_key("test_key");
106        client
107            .model("claude-opus-4-20250514") // string still works
108            .max_tokens(2048)
109            .user("Test");
110
111        let body = client.body();
112        assert_eq!(body.model, Model::Opus4);
113    }
114
115    #[test]
116    fn test_tool_builder() {
117        let mut tool = Tool::new("search");
118        tool.description("Search for information")
119            .add_string_property("query", Some("Search query"), true);
120
121        assert_eq!(tool.name, "search");
122        assert!(tool.input_schema.properties.is_some());
123    }
124
125    #[test]
126    fn test_message_creation() {
127        let msg = Message::user("Hello!");
128        assert_eq!(msg.role, Role::User);
129        assert_eq!(msg.content.len(), 1);
130    }
131
132    #[test]
133    fn test_content_block() {
134        let block = ContentBlock::text("Test text");
135        let json = serde_json::to_string(&block).unwrap();
136        assert!(json.contains("\"type\":\"text\""));
137        assert!(json.contains("\"text\":\"Test text\""));
138    }
139}