anthropic_sdk_dart 1.0.0
anthropic_sdk_dart: ^1.0.0 copied to clipboard
Dart client for the Anthropic API. Provides type-safe access to Claude models with streaming, tool use, and batch processing support.
Anthropic Dart Client #
Unofficial Dart client for the Anthropic API to build with Claude (Claude Opus 4, Sonnet 4, and more).
Table of Contents
Features #
Messages & Streaming #
- ✅ Message creation (
messages.create) - ✅ Streaming support (
messages.createStream) with SSE - ✅ Request cancellation (via
abortTrigger) - ✅ Token counting (
messages.countTokens) - ✅ Advanced request controls (
outputConfig,inferenceGeo,container,speed)
Tool Use #
- ✅ Custom function/tool calling
- ✅ Tool choice modes (auto, any, tool, none)
- ✅ Tool governance metadata (
allowedCallers,deferLoading,strict,inputExamples,eagerInputStreaming) - ✅ Built-in tools:
- Web search (
WebSearchTool) - Web fetch (
WebFetchTool) - Text editor (
TextEditorTool) - Bash (
BashTool) - Computer use (
ComputerUseTool) - Code execution (
CodeExecutionTool) - Memory (
MemoryTool) - Tool search (
ToolSearchToolBm25,ToolSearchToolRegex)
- Web search (
Extended Thinking #
- ✅ Extended thinking mode (
ThinkingEnabled) - ✅ Adaptive thinking mode (
ThinkingAdaptive) - ✅ Thinking budget control
- ✅ Streaming thinking blocks
Multimodal #
- ✅ Vision (image analysis)
- Base64 images (PNG, JPEG, GIF, WebP)
- URL images
- ✅ Document processing (PDF, text)
- Base64 documents
- URL documents
- ✅ Citations support
Batches #
- ✅ Batch message creation
- ✅ Batch management (list, retrieve, cancel, delete)
- ✅ Batch results streaming (JSONL)
Models #
- ✅ List available models
- ✅ Retrieve model details
Files (Beta) #
- ✅ File upload (from path or bytes)
- ✅ File listing and retrieval
- ✅ File download
- ✅ File deletion
Skills (Beta) #
- ✅ Skill creation and management
- ✅ Skill version control
- ✅ Custom skill uploads (ZIP archives)
Why choose this client? #
- ✅ Type-safe with sealed classes
- ✅ Minimal dependencies (http, logging only)
- ✅ Works on all compilation targets (native, web, WASM)
- ✅ Interceptor-driven architecture
- ✅ Comprehensive error handling
- ✅ Automatic retry with exponential backoff
- ✅ SSE streaming support
Quickstart #
import 'package:anthropic_sdk_dart/anthropic_sdk_dart.dart';
void main() async {
final client = AnthropicClient.fromEnvironment();
final response = await client.messages.create(
MessageCreateRequest(
model: 'claude-sonnet-4-20250514',
maxTokens: 1024,
messages: [
InputMessage.user('What is the capital of France?'),
],
),
);
print(response.text); // Paris is the capital of France.
client.close();
}
Installation #
dependencies:
anthropic_sdk_dart: ^x.y.z
Configuration #
Configuration Options
import 'package:anthropic_sdk_dart/anthropic_sdk_dart.dart';
final client = AnthropicClient(
config: AnthropicConfig(
authProvider: ApiKeyProvider('YOUR_API_KEY'),
baseUrl: 'https://api.anthropic.com', // Default
timeout: Duration(minutes: 5),
retryPolicy: RetryPolicy(
maxRetries: 3,
initialDelay: Duration(seconds: 1),
),
),
);
Custom base URL (for proxies or testing):
final client = AnthropicClient(
config: AnthropicConfig(
baseUrl: 'https://my-proxy.example.com',
authProvider: ApiKeyProvider('YOUR_API_KEY'),
),
);
Usage #
Basic Messages #
Basic Message Example
import 'package:anthropic_sdk_dart/anthropic_sdk_dart.dart';
final client = AnthropicClient.fromEnvironment();
final response = await client.messages.create(
MessageCreateRequest(
model: 'claude-sonnet-4-20250514',
maxTokens: 1024,
messages: [
InputMessage.user('What is the capital of France?'),
],
),
);
print('Response: ${response.text}');
print('Stop reason: ${response.stopReason}');
print('Usage: ${response.usage.inputTokens} in, ${response.usage.outputTokens} out');
client.close();
Multi-turn Conversations #
Multi-turn Conversation Example
final response = await client.messages.create(
MessageCreateRequest(
model: 'claude-sonnet-4-20250514',
maxTokens: 1024,
messages: [
InputMessage.user('My name is Alice.'),
InputMessage.assistant('Nice to meet you, Alice!'),
InputMessage.user('What is my name?'),
],
),
);
print(response.text); // Your name is Alice.
System Prompts #
System Prompt Example
final response = await client.messages.create(
MessageCreateRequest(
model: 'claude-sonnet-4-20250514',
maxTokens: 1024,
system: SystemPrompt.text(
'You are a friendly pirate. Respond in pirate speak.',
),
messages: [
InputMessage.user('Hello, how are you?'),
],
),
);
print(response.text); // Ahoy, matey! I be doin' just fine...
Streaming #
Streaming Example
import 'dart:io';
import 'package:anthropic_sdk_dart/anthropic_sdk_dart.dart';
final stream = client.messages.createStream(
MessageCreateRequest(
model: 'claude-sonnet-4-20250514',
maxTokens: 256,
messages: [
InputMessage.user('Count from 1 to 10 slowly.'),
],
),
);
await for (final event in stream) {
if (event is ContentBlockDeltaEvent) {
final delta = event.delta;
if (delta is TextDelta) {
stdout.write(delta.text);
}
}
}
Streaming with Extensions
Each extension method consumes the stream, so use one per createStream() call:
import 'package:anthropic_sdk_dart/anthropic_sdk_dart.dart';
Stream<MessageStreamEvent> createStream() => client.messages.createStream(
MessageCreateRequest(
model: 'claude-sonnet-4-20250514',
maxTokens: 256,
messages: [InputMessage.user('Count from 1 to 10 slowly.')],
),
);
// Option 1: Collect all text into a single string
final text = await createStream().collectText();
// Option 2: Iterate text deltas as they arrive
await for (final delta in createStream().textDeltas()) {
stdout.write(delta);
}
// Option 3: Accumulate streaming chunks into a complete Message
await for (final accumulator in createStream().accumulate()) {
print('Content so far: ${accumulator.text}');
}
// Option 4: Use MessageStreamAccumulator directly for full control
final accumulator = MessageStreamAccumulator();
await for (final event in createStream()) {
accumulator.add(event);
}
final message = accumulator.toMessage();
print(message.text);
Tool Calling #
Tool Calling Example
import 'dart:convert';
import 'package:anthropic_sdk_dart/anthropic_sdk_dart.dart';
// Define a tool
final weatherTool = Tool(
name: 'get_weather',
description: 'Get the current weather for a location.',
inputSchema: InputSchema(
properties: {
'location': {
'type': 'string',
'description': 'City and state, e.g. "San Francisco, CA"',
},
'unit': {
'type': 'string',
'enum': ['celsius', 'fahrenheit'],
'description': 'Temperature unit',
},
},
required: ['location'],
),
);
// Send message with tool
final response = await client.messages.create(
MessageCreateRequest(
model: 'claude-sonnet-4-20250514',
maxTokens: 1024,
tools: [ToolDefinition.custom(weatherTool)],
messages: [
InputMessage.user('What is the weather in San Francisco?'),
],
),
);
// Check if Claude wants to use a tool
if (response.hasToolUse) {
for (final toolUse in response.toolUseBlocks) {
print('Tool: ${toolUse.name}');
print('Input: ${jsonEncode(toolUse.input)}');
// Execute your tool and send results back...
}
}
Extended Thinking #
Extended Thinking Example
final response = await client.messages.create(
MessageCreateRequest(
model: 'claude-sonnet-4-20250514',
maxTokens: 16000,
thinking: ThinkingEnabled(budgetTokens: 10000),
messages: [
InputMessage.user('Solve this complex math problem step by step...'),
],
),
);
// Access thinking blocks
for (final block in response.content) {
if (block is ThinkingBlock) {
print('Thinking: ${block.thinking}');
} else if (block is TextBlock) {
print('Response: ${block.text}');
}
}
Vision (Image Analysis) #
Vision Example
// Using URL image
final response = await client.messages.create(
MessageCreateRequest(
model: 'claude-sonnet-4-20250514',
maxTokens: 1024,
messages: [
InputMessage.userBlocks([
const TextInputBlock('What do you see in this image?'),
const ImageInputBlock(
UrlImageSource('https://example.com/image.jpg'),
),
]),
],
),
);
// Using base64 image
final base64Image = base64Encode(File('image.png').readAsBytesSync());
final response2 = await client.messages.create(
MessageCreateRequest(
model: 'claude-sonnet-4-20250514',
maxTokens: 1024,
messages: [
InputMessage.userBlocks([
const TextInputBlock('Describe this image.'),
ImageInputBlock(
Base64ImageSource(
mediaType: ImageMediaType.png,
data: base64Image,
),
),
]),
],
),
);
Document Processing #
Document Example
// Using URL document
final response = await client.messages.create(
MessageCreateRequest(
model: 'claude-sonnet-4-20250514',
maxTokens: 1024,
messages: [
InputMessage.userBlocks([
const TextInputBlock('Summarize this PDF document.'),
const DocumentInputBlock(
UrlPdfSource('https://example.com/document.pdf'),
),
]),
],
),
);
// Using base64 PDF
final base64Pdf = base64Encode(File('document.pdf').readAsBytesSync());
final response2 = await client.messages.create(
MessageCreateRequest(
model: 'claude-sonnet-4-20250514',
maxTokens: 1024,
messages: [
InputMessage.userBlocks([
const TextInputBlock('What are the key points in this document?'),
DocumentInputBlock(
Base64PdfSource(base64Pdf),
),
]),
],
),
);
Message Batches #
Batch Example
// Create a batch
final batch = await client.messages.batches.create(
MessageBatchCreateRequest(
requests: [
BatchRequestItem(
customId: 'request-1',
params: MessageCreateRequest(
model: 'claude-sonnet-4-20250514',
maxTokens: 100,
messages: [InputMessage.user('Hello!')],
),
),
BatchRequestItem(
customId: 'request-2',
params: MessageCreateRequest(
model: 'claude-sonnet-4-20250514',
maxTokens: 100,
messages: [InputMessage.user('How are you?')],
),
),
],
),
);
print('Batch ID: ${batch.id}');
print('Status: ${batch.processingStatus}');
// Check batch status
final status = await client.messages.batches.retrieve(batch.id);
print('Progress: ${status.requestCounts.succeeded}/${status.requestCounts.processing}');
// Get results when complete
if (status.processingStatus == ProcessingStatus.ended) {
await for (final result in client.messages.batches.results(batch.id)) {
print('${result.customId}: ${result.result}');
}
}
Token Counting #
Token Counting Example
final response = await client.messages.countTokens(
TokenCountRequest(
model: 'claude-sonnet-4-20250514',
messages: [
InputMessage.user('Hello, Claude!'),
],
),
);
print('Input tokens: ${response.inputTokens}');
Models #
Models Example
// List all models
final models = await client.models.list();
for (final model in models.data) {
print('${model.id}: ${model.displayName}');
}
// Get specific model
final model = await client.models.retrieve('claude-sonnet-4-20250514');
print('Model: ${model.displayName}');
print('Created: ${model.createdAt}');
Error Handling #
Error Handling Example
try {
final response = await client.messages.create(request);
print(response.text);
} on AuthenticationException {
print('Invalid API key - check your credentials');
} on RateLimitException catch (e) {
print('Rate limited - try again later: ${e.message}');
} on ApiException catch (e) {
print('API error ${e.statusCode}: ${e.message}');
} on AnthropicException catch (e) {
print('Anthropic error: ${e.message}');
} catch (e) {
print('Unexpected error: $e');
}
Exception Hierarchy:
AnthropicException- Base exceptionApiException- API errors with status codesAuthenticationException- 401 errorsRateLimitException- 429 errors
ValidationException- Client-side validation errorsTimeoutException- Request timeoutsAbortedException- Request cancellation
Request Cancellation #
Cancellation Example
import 'dart:async';
final abortController = Completer<void>();
// Start request with abort capability
final requestFuture = client.messages.create(
request,
abortTrigger: abortController.future,
);
// Cancel after 5 seconds
Future.delayed(Duration(seconds: 5), () {
abortController.complete();
});
try {
final response = await requestFuture;
print(response.text);
} on AbortedException {
print('Request was cancelled');
}
Extension Methods #
The package provides convenient extension methods for common operations:
Stream Extensions #
Each extension method consumes the stream, so use one per createStream() call:
// Collect all text from a streaming response
final text = await stream.collectText();
// Iterate only text deltas (requires a new stream)
await for (final delta in stream.textDeltas()) {
stdout.write(delta);
}
// Iterate thinking deltas (requires a new stream)
await for (final thinking in stream.thinkingDeltas()) {
print(thinking);
}
// Accumulate streaming chunks into a complete response (requires a new stream)
await for (final accumulator in stream.accumulate()) {
print('Content so far: ${accumulator.text}');
}
// Or use MessageStreamAccumulator directly for full control (requires a new stream)
final accumulator = MessageStreamAccumulator();
await for (final event in stream) {
accumulator.add(event);
}
final message = accumulator.toMessage();
print(message.text);
Message Extensions #
// Access text content
final text = message.text;
// Check for tool use
if (message.hasToolUse) {
for (final toolUse in message.toolUseBlocks) {
print('Tool: ${toolUse.name}');
}
}
// Access thinking content
if (message.hasThinking) {
print(message.thinking);
}
Examples #
See the example/ directory for comprehensive examples:
| Example | Description |
|---|---|
| anthropic_sdk_dart_example.dart | Quick start example |
| messages_example.dart | Basic message creation |
| streaming_example.dart | SSE streaming with accumulator |
| tool_calling_example.dart | Function/tool use |
| vision_example.dart | Image analysis |
| document_example.dart | PDF document processing |
| thinking_example.dart | Extended thinking |
| token_counting_example.dart | Token counting |
| batch_example.dart | Batch processing |
| files_example.dart | Files API (Beta) |
| models_example.dart | Models API |
| error_handling_example.dart | Exception handling |
| abort_example.dart | Request cancellation |
| web_search_example.dart | Web search tool |
| computer_use_example.dart | Computer use (Beta) |
| mcp_example.dart | MCP integration (Beta) |
API Coverage #
This client implements 100% of the Anthropic REST API:
Messages Resource (client.messages) #
- create - Create a message
- createStream - Create a streaming message (SSE)
- countTokens - Count tokens in a message
Message Batches Resource (client.messages.batches) #
- create - Create a message batch
- list - List all batches
- retrieve - Get batch status
- cancel - Cancel a batch
- deleteBatch - Delete a batch
- results - Stream batch results (JSONL)
Models Resource (client.models) #
- list - List available models
- retrieve - Get model details
Files Resource (client.files) - Beta #
- upload - Upload a file from a file path
- uploadBytes - Upload a file from bytes
- list - List uploaded files
- retrieve - Get file metadata
- deleteFile - Delete a file
- download - Download file content
Skills Resource (client.skills) - Beta #
- create - Create a new skill
- list - List skills
- retrieve - Get skill details
- deleteSkill - Delete a skill
- createVersion - Create a new skill version
- listVersions - List skill versions
- retrieveVersion - Get skill version details
- deleteVersion - Delete a skill version
Development #
# Install dependencies
dart pub get
# Run tests
dart test
# Format code
dart format .
# Analyze
dart analyze
License #
anthropic_sdk_dart is licensed under the MIT License.