A Rust SDK for Hyperware processes to access the Anthropic API, providing seamless integration with Claude models.
- Full support for Anthropic Messages API
- Tool use capabilities for function calling
- Multi-turn conversation support
- Image input support (base64 and URL)
- Automatic retry and error handling
- Non-streaming mode (optimized for Hyperware processes)
- Type-safe request and response structures
Add this to your Cargo.toml
:
[dependencies]
hyperware-anthropic-sdk = { git = "https://github.com/hyperware/hyperware-anthropic-sdk" }
This SDK is designed to be used within Hyperware Hyperapps, which provide the async runtime.
use hyperware_anthropic_sdk::AnthropicClient;
// Within a Hyperapp async context
async fn my_hyperapp_function() -> Result<(), Box<dyn std::error::Error>> {
// Initialize the client with your API key
let client = AnthropicClient::new("your-api-key");
// Send a simple message
let response = client.send_simple_message(
"claude-opus-4-1-20250805",
"What is the capital of France?",
100,
).await?;
println!("Response: {}", response);
Ok(())
}
let client = AnthropicClient::new("api-key")
.with_base_url("https://custom-api.example.com") // Optional
.with_api_version("2023-06-01") // Optional
.with_timeout(120); // Optional (seconds)
// Quick method for simple queries
let response = client.send_simple_message(
"claude-opus-4-1-20250805",
"Your prompt here",
max_tokens,
).await?;
use hyperware_anthropic_sdk::{CreateMessageRequest, Message, Role, Content};
let request = CreateMessageRequest::new(
"claude-opus-4-1-20250805",
vec![
Message {
role: Role::User,
content: Content::Text("Hello!".to_string()),
},
Message {
role: Role::Assistant,
content: Content::Text("Hi there!".to_string()),
},
Message {
role: Role::User,
content: Content::Text("How are you?".to_string()),
},
],
1000,
);
let response = client.send_message(request).await?;
use hyperware_anthropic_sdk::{Tool, ToolChoice};
use serde_json::json;
// Define a tool
let weather_tool = Tool::new(
"get_weather",
"Get current weather for a location",
json!({
"location": {
"type": "string",
"description": "City and state"
}
}),
vec!["location".to_string()],
);
// Create request with tools
let request = CreateMessageRequest::new(model, messages, max_tokens)
.with_tools(vec![weather_tool])
.with_tool_choice(ToolChoice::Auto {
disable_parallel_tool_use: None
});
// Send and handle tool use in response
let response = client.send_message(request).await?;
let request = CreateMessageRequest::new(model, messages, max_tokens)
.with_system("You are a helpful assistant specialized in Rust programming.");
use hyperware_anthropic_sdk::{ContentBlock, ImageSource, ImageSourceData};
let image_block = ContentBlock::Image {
source: ImageSource {
source_type: ImageSourceType::Base64,
data: ImageSourceData::Base64 {
media_type: "image/jpeg".to_string(),
data: base64_encoded_image,
},
},
cache_control: None,
};
let message = Message {
role: Role::User,
content: Content::Blocks(vec![
image_block,
ContentBlock::Text {
text: "What's in this image?".to_string(),
cache_control: None,
},
]),
};
let response = client.send_message(request).await?;
// Access response metadata
println!("Message ID: {}", response.id);
println!("Model: {}", response.model);
println!("Stop reason: {:?}", response.stop_reason);
println!("Tokens used: {} input, {} output",
response.usage.input_tokens,
response.usage.output_tokens
);
// Process content blocks
for block in &response.content {
match block {
ResponseContentBlock::Text { text, .. } => {
println!("Text: {}", text);
}
ResponseContentBlock::ToolUse { id, name, input } => {
println!("Tool {} called with ID {}", name, id);
// Handle tool execution
}
}
}
The SDK provides comprehensive error handling:
use hyperware_anthropic_sdk::AnthropicError;
match client.send_message(request).await {
Ok(response) => {
// Handle success
}
Err(AnthropicError::ApiError { error_type, message }) => {
// Handle API errors
eprintln!("API Error ({}): {}", error_type, message);
}
Err(AnthropicError::RateLimit) => {
// Handle rate limiting
eprintln!("Rate limit exceeded");
}
Err(e) => {
// Handle other errors
eprintln!("Error: {}", e);
}
}
This SDK is designed to work seamlessly with Hyperware processes. The HTTP client functionality is provided by the hyperware_process_lib::http::client
module, which includes:
send_request_await_response
- Async HTTP request functionHttpClientError
- Error types for HTTP operations
The SDK requires a Hyperware Hyperapp runtime for async execution.
The SDK supports all Claude models:
claude-opus-4-1-20250805
- Most capable modelclaude-sonnet-4-20250514
- Balanced performanceclaude-haiku-3-20240307
- Fast and efficient
Set your API key as an environment variable:
export ANTHROPIC_API_KEY="your-api-key-here"
The SDK provides a powerful Conversation
struct for managing ongoing conversations with tool use loops:
use hyperware_anthropic_sdk::{AnthropicClient, Conversation};
async fn chat_example() -> Result<(), Box<dyn std::error::Error>> {
let client = AnthropicClient::new("your-api-key");
let mut conversation = Conversation::new("claude-opus-4-1-20250805", 1000)
.with_system("You are a helpful assistant");
// Add a user message and send
let update = conversation.send_user_message(&client, "Hello! What's 2+2?").await?;
println!("Claude: {}", update.text());
// Continue the conversation
let update = conversation.send_user_message(&client, "Now what's 10 times that?").await?;
println!("Claude: {}", update.text());
Ok(())
}
use hyperware_anthropic_sdk::{AnthropicClient, Conversation, Tool, ToolResult};
use serde_json::json;
async fn tool_loop_example() -> Result<(), Box<dyn std::error::Error>> {
let client = AnthropicClient::new("your-api-key");
// Define tools
let calculator_tool = Tool::new(
"calculator",
"Perform mathematical calculations",
json!({
"expression": {
"type": "string",
"description": "Mathematical expression to evaluate"
}
}),
vec!["expression".to_string()],
);
let mut conversation = Conversation::new("claude-opus-4-1-20250805", 1000)
.with_tools(vec![calculator_tool]);
// Send a message that will trigger tool use
conversation.add_user_message("What's 123 * 456 + 789?");
// Complete the full tool loop
let updates = conversation.complete_tool_loop(&client, |tool_use| async move {
match tool_use.name.as_str() {
"calculator" => {
// Extract the expression from the tool input
let expression = tool_use.input["expression"].as_str().unwrap_or("");
// Simulate calculation (in real code, you'd evaluate safely)
let result = "56877"; // 123 * 456 + 789
Ok(ToolResult::success(tool_use.id, result))
}
_ => Ok(ToolResult::error(tool_use.id, "Unknown tool"))
}
}).await?;
// Get the final response
if let Some(final_update) = updates.last() {
println!("Final answer: {}", final_update.text());
}
Ok(())
}
async fn manual_tool_handling() -> Result<(), Box<dyn std::error::Error>> {
let client = AnthropicClient::new("your-api-key");
let mut conversation = Conversation::new("claude-opus-4-1-20250805", 1000)
.with_tools(vec![weather_tool]);
// Send initial message
let update = conversation.send_user_message(&client, "What's the weather in NYC?").await?;
// Check if tools were requested
if update.has_tool_uses() {
for tool_use in update.tool_uses {
println!("Tool requested: {} with input: {}", tool_use.name, tool_use.input);
// Execute the tool (your implementation)
let weather_data = fetch_weather(&tool_use.input).await?;
// Add the result
conversation.add_tool_result(
tool_use.id,
weather_data,
false, // not an error
)?;
}
// Send the tool results and get final response
let final_update = conversation.send(&client).await?;
println!("Claude's response: {}", final_update.text());
}
Ok(())
}
// Fork a conversation to explore different paths
let alternate_conversation = conversation.fork();
// Access and modify message history
let messages = conversation.messages();
println!("Conversation has {} messages", messages.len());
// Clear and start fresh while keeping settings
conversation.clear();
// Check for pending tool uses
if conversation.has_pending_tool_uses() {
let pending = conversation.pending_tool_uses();
println!("{} tools waiting for responses", pending.len());
}
The SDK is designed for use within Hyperware Hyperapps. All examples assume you're running within a Hyperapp async context.
MIT
Contributions are welcome! Please feel free to submit a Pull Request.