anthropic_sdk_dart 1.3.2
anthropic_sdk_dart: ^1.3.2 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
Sponsor #
If these packages are useful to you or your company, please sponsor the project. Development and maintenance are provided to the community for free, but integration tests against real APIs and the tooling required to build and verify releases still have real costs. Your support, at any level, helps keep these packages maintained and free for the Dart & Flutter community.
License #
anthropic_sdk_dart is licensed under the MIT License.