anthropic_sdk_dart 1.1.0 copy "anthropic_sdk_dart: ^1.1.0" to clipboard
anthropic_sdk_dart: ^1.1.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 #

tests anthropic_sdk_dart Discord MIT

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)

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 exception
    • ApiException - API errors with status codes
      • AuthenticationException - 401 errors
      • RateLimitException - 429 errors
    • ValidationException - Client-side validation errors
    • TimeoutException - Request timeouts
    • AbortedException - 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.

12
likes
0
points
10.2k
downloads

Documentation

Documentation

Publisher

verified publisherdavidmiguel.com

Weekly Downloads

Dart client for the Anthropic API. Provides type-safe access to Claude models with streaming, tool use, and batch processing support.

Homepage
Repository (GitHub)
View/report issues

Topics

#nlp #gen-ai #llms #anthropic

Funding

Consider supporting this project:

github.com

License

unknown (license)

Dependencies

http, logging, meta

More

Packages that depend on anthropic_sdk_dart