UNPKG

@bernierllc/anthropic-client

Version:

Type-safe Anthropic Claude API client with automatic rate limiting, retry logic, streaming support, and cost tracking

318 lines (234 loc) 9.24 kB
# @bernierllc/anthropic-client Type-safe Anthropic Claude API client with automatic rate limiting, retry logic, streaming support, and cost tracking. ## Installation ```bash npm install @bernierllc/anthropic-client ``` ## Features - **Type-safe API**: Full TypeScript support with strict typing - **Multiple Claude Models**: Support for Claude 3 Opus, Sonnet, Haiku, and Sonnet 3.5 - **Streaming Support**: Real-time streaming responses with chunk callbacks - **Rate Limiting**: Built-in rate limiting to respect API quotas - **Automatic Retries**: Exponential backoff retry logic for failed requests - **Cost Tracking**: Automatic tracking of token usage and costs - **Comprehensive Logging**: Integration with @bernierllc/logger - **Error Handling**: Structured error responses for robust error handling ## Usage ### Basic Completion ```typescript import { AnthropicClient, ClaudeModel } from '@bernierllc/anthropic-client'; const client = new AnthropicClient({ apiKey: process.env.ANTHROPIC_API_KEY! }); const result = await client.complete('Explain quantum computing in simple terms', { model: ClaudeModel.SONNET, maxTokens: 1024, temperature: 0.7 }); if (result.success) { console.log('Response:', result.content); console.log('Tokens used:', result.usage?.totalTokens); console.log('Cost:', `$${result.cost?.totalCost.toFixed(6)}`); } else { console.error('Error:', result.error); } ``` ### Streaming Response ```typescript const result = await client.stream( 'Write a short story about space exploration', (chunk) => { // Process each chunk as it arrives process.stdout.write(chunk); }, { model: ClaudeModel.OPUS, maxTokens: 2000 } ); console.log('\n\nTotal tokens:', result.usage?.totalTokens); console.log('Total cost:', `$${result.cost?.totalCost.toFixed(6)}`); ``` ### Custom Configuration ```typescript const client = new AnthropicClient({ apiKey: process.env.ANTHROPIC_API_KEY!, defaultModel: ClaudeModel.HAIKU, maxRetries: 5, rateLimit: { requestsPerMinute: 100, tokensPerMinute: 50000 }, enableLogging: true }); ``` ### Disable Rate Limiting ```typescript const client = new AnthropicClient({ apiKey: process.env.ANTHROPIC_API_KEY!, rateLimit: null // Disable rate limiting }); ``` ### Usage Tracking ```typescript // Make multiple requests await client.complete('First request'); await client.complete('Second request'); await client.complete('Third request'); // Get aggregated usage statistics const usage = client.getUsage(); console.log('Total requests:', usage.totalRequests); console.log('Total tokens:', usage.totalTokens); console.log('Total cost:', `$${usage.totalCost.toFixed(6)}`); console.log('Requests by model:', usage.requestsByModel); // Reset usage statistics client.resetUsage(); ``` ### Rate Limit Status ```typescript const status = client.getRateLimitStatus(); if (status) { console.log('Requests remaining:', status.requestsRemaining); console.log('Reset time:', status.resetTime); } ``` ## API Reference ### AnthropicClient #### Constructor ```typescript new AnthropicClient(config: AnthropicClientConfig) ``` **Config Options:** - `apiKey` (string, required): Your Anthropic API key - `defaultModel` (ClaudeModel, optional): Default model to use (default: `ClaudeModel.SONNET`) - `maxRetries` (number, optional): Maximum number of retry attempts (default: 3) - `rateLimit` (object | null, optional): Rate limiting configuration or null to disable (default: 50 requests/minute) - `requestsPerMinute` (number): Maximum requests per minute - `tokensPerMinute` (number): Maximum tokens per minute (not enforced by current rate limiter) - `enableLogging` (boolean, optional): Enable detailed logging (default: true) #### Methods ##### complete(prompt: string, options?: CompletionOptions): Promise<CompletionResult> Send a completion request to Claude. **Options:** - `model` (ClaudeModel): Model to use for this request - `maxTokens` (number): Maximum tokens to generate (default: 1024) - `temperature` (number): Sampling temperature (0-1) - `topP` (number): Nucleus sampling parameter - `topK` (number): Top-k sampling parameter - `stopSequences` (string[]): Sequences that stop generation - `systemPrompt` (string): System prompt to use - `metadata` (Record<string, unknown>): Additional metadata **Returns:** `CompletionResult` object with: - `success` (boolean): Whether the request succeeded - `content` (string | undefined): Generated text - `usage` (object | undefined): Token usage information - `cost` (object | undefined): Cost breakdown - `model` (string | undefined): Model used - `stopReason` (string | undefined): Why generation stopped - `error` (string | undefined): Error message if failed ##### stream(prompt: string, onChunk: StreamChunkCallback, options?: CompletionOptions): Promise<CompletionResult> Stream a completion response from Claude. **Parameters:** - `prompt` (string): The prompt to send - `onChunk` (function): Callback function called for each text chunk - `options` (CompletionOptions): Same options as `complete()` **Returns:** `CompletionResult` with the complete response ##### getUsage(): UsageStats Get cumulative usage statistics. **Returns:** - `totalRequests` (number): Total number of requests made - `totalInputTokens` (number): Total input tokens used - `totalOutputTokens` (number): Total output tokens generated - `totalTokens` (number): Total tokens (input + output) - `totalCost` (number): Total cost in USD - `requestsByModel` (Record<string, number>): Request count by model ##### resetUsage(): void Reset all usage statistics to zero. ##### getRateLimitStatus(): RateLimitStatus | null Get current rate limit status. **Returns:** - `requestsRemaining` (number): Requests remaining in current window - `tokensRemaining` (number): Tokens remaining (not implemented) - `resetTime` (Date): When the rate limit window resets Returns `null` if rate limiting is disabled. ## Claude Models The following models are supported: - `ClaudeModel.OPUS` - claude-3-opus-20240229 (most capable, highest cost) - `ClaudeModel.SONNET` - claude-3-sonnet-20240229 (balanced performance and cost) - `ClaudeModel.SONNET_3_5` - claude-3-5-sonnet-20241022 (latest Sonnet version) - `ClaudeModel.HAIKU` - claude-3-haiku-20240307 (fastest, lowest cost) ## Cost Tracking The client automatically tracks costs based on current Anthropic pricing: | Model | Input Cost (per 1M tokens) | Output Cost (per 1M tokens) | |-------|---------------------------|------------------------------| | Opus | $15.00 | $75.00 | | Sonnet | $3.00 | $15.00 | | Sonnet 3.5 | $3.00 | $15.00 | | Haiku | $0.25 | $1.25 | ## Error Handling The client uses structured error responses: ```typescript const result = await client.complete('test prompt'); if (!result.success) { console.error('Request failed:', result.error); // Handle error appropriately } else { // Process successful response console.log(result.content); } ``` ## Integration Status - **Logger**: ✅ Integrated - Uses @bernierllc/logger for structured logging of API calls, errors, and usage tracking - **Docs-Suite**: ✅ Ready - Full TypeDoc documentation with API reference and usage examples - **NeverHub**: 🔄 Optional - Supports graceful degradation. When NeverHub is available via @bernierllc/neverhub-adapter, the client can: - Emit `ai.request.started` and `ai.request.completed` events - Publish token usage and cost metrics - Subscribe to configuration updates - Register as an AI capability provider for service discovery - All core functionality works without NeverHub present ### NeverHub Integration Example ```typescript import { AnthropicClient } from '@bernierllc/anthropic-client'; import { NeverHubAdapter } from '@bernierllc/neverhub-adapter'; const client = new AnthropicClient({ apiKey: process.env.ANTHROPIC_API_KEY! }); // Auto-detect and integrate with NeverHub if available if (await NeverHubAdapter.detect()) { const neverhub = new NeverHubAdapter(); await neverhub.register({ type: 'ai-provider', name: '@bernierllc/anthropic-client', version: '1.0.0', capabilities: [ { type: 'ai', name: 'text-completion', version: '1.0.0' }, { type: 'ai', name: 'streaming', version: '1.0.0' } ] }); // Client emits events automatically when integrated } // Works identically with or without NeverHub const result = await client.complete('Your prompt here'); ``` ## Development ```bash # Install dependencies npm install # Run tests npm test # Run tests with coverage npm run test:coverage # Build npm run build # Lint npm run lint ``` ## License Copyright (c) 2025 Bernier LLC This file is licensed to the client under a limited-use license. The client may use and modify this code *only within the scope of the project it was delivered for*. Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC. ## See Also - [@bernierllc/logger](../logger) - Structured logging - [@bernierllc/retry-policy](../retry-policy) - Retry logic with exponential backoff - [Anthropic API Documentation](https://docs.anthropic.com/) - Official API documentation