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

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

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.

12
likes
160
points
8.62k
downloads

Documentation

Documentation
API reference

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

MIT (license)

Dependencies

http, logging, meta

More

Packages that depend on anthropic_sdk_dart