npm package: @jakecelentano/ai-providers
Description: Shared AI provider abstraction for Anthropic and OpenRouter
Author: Jake Celentano
Latest version: 1.1.0

# AI Providers

Unified AI provider abstraction for TypeScript applications. Supports Anthropic Claude and OpenRouter with a consistent interface.

## Installation

```bash
# From GitHub
npm install github:jakecelentano/ai-providers

# Peer dependencies (install what you need)
npm install @anthropic-ai/sdk  # For Anthropic
npm install openai              # For OpenRouter
```

## Quick Start

```typescript
import { AIProviderFactory, MODELS } from 'ai-providers';

// Create provider from environment variables
const provider = AIProviderFactory.createFromEnv('anthropic');

// Generate completion
const response = await provider.generateCompletion(
  'What is the capital of France?',
  'You are a helpful assistant.',
  { maxTokens: 1024 }
);

console.log(response);

// Clean up
await provider.close();
```

## Configuration

### Environment Variables

```bash
# Anthropic
ANTHROPIC_API_KEY=sk-ant-...

# OpenRouter
OPENROUTER_API_KEY=sk-or-...

# Optional defaults
DEFAULT_AI_PROVIDER=anthropic  # or openrouter
DEFAULT_AI_MODEL=claude-sonnet-4-20250514
```

### Explicit Configuration

```typescript
import { AIProviderFactory } from 'ai-providers';

const provider = AIProviderFactory.create({
  providerType: 'anthropic',
  apiKey: 'sk-ant-...',
  model: 'claude-3-5-haiku-20241022',
  baseUrl: 'https://custom-endpoint.com', // Optional
});
```

## Features

### Retry with Backoff

Automatic retry for transient failures:

```typescript
const response = await provider.generateCompletion(prompt, systemPrompt, {
  retry: {
    maxRetries: 3,
    backoff: 'exponential', // or 'linear'
  },
});
```

### Structured Output (Anthropic)

Force JSON schema output using tool use:

```typescript
const response = await provider.generateCompletion(prompt, systemPrompt, {
  schema: {
    type: 'object',
    properties: {
      name: { type: 'string' },
      age: { type: 'number' },
    },
    required: ['name', 'age'],
  },
});

const data = JSON.parse(response);
```

### JSON Mode (OpenRouter)

```typescript
const response = await provider.generateCompletion(prompt, systemPrompt, {
  jsonMode: true,
});
```

### Prompt Caching (Anthropic)

Enable prompt caching for repeated system prompts:

```typescript
const response = await provider.generateCompletion(prompt, systemPrompt, {
  enableCaching: true,
});
```

### Connection Testing

```typescript
const result = await AIProviderFactory.testConnection({
  providerType: 'anthropic',
  apiKey: process.env.ANTHROPIC_API_KEY!,
});

if (result.success) {
  console.log(`Connected: ${result.message}`);
  console.log(`Latency: ${result.details?.latency}ms`);
} else {
  console.error(`Failed: ${result.message}`);
}
```

## Default Models

```typescript
import { MODELS } from 'ai-providers';

// Anthropic
MODELS.anthropic.primary  // claude-sonnet-4-20250514
MODELS.anthropic.fast     // claude-3-5-haiku-20241022

// OpenRouter
MODELS.openrouter.primary // anthropic/claude-sonnet-4-20250514
MODELS.openrouter.fast    // anthropic/claude-3-5-haiku-20241022
```

## OpenRouter Helpers

```typescript
import { OpenRouterHelpers } from 'ai-providers';

// Use cheapest provider for a model
const model = OpenRouterHelpers.useCheapest('anthropic/claude-3-5-sonnet');
// Returns: anthropic/claude-3-5-sonnet:floor

// Use fastest provider
const model = OpenRouterHelpers.useFastest('anthropic/claude-3-5-sonnet');
// Returns: anthropic/claude-3-5-sonnet:nitro
```

## Error Handling

```typescript
import { AIProviderError } from 'ai-providers';

try {
  const response = await provider.generateCompletion(prompt);
} catch (error) {
  if (error instanceof AIProviderError) {
    console.error(`Provider: ${error.provider}`);
    console.error(`Status: ${error.statusCode}`);
    console.error(`Retryable: ${error.retryable}`);
  }
}
```

## API Reference

### AIProvider Interface

```typescript
interface AIProvider {
  readonly providerType: AIProviderType;
  readonly model: AIModel;

  generateCompletion(
    prompt: string,
    systemPrompt?: string,
    options?: GenerationOptions
  ): Promise<string>;

  testConnection(): Promise<ConnectionTestResult>;
  close(): Promise<void>;
}
```

### GenerationOptions

```typescript
interface GenerationOptions {
  maxTokens?: number;
  temperature?: number;
  enableCaching?: boolean;    // Anthropic only
  schema?: unknown;           // Anthropic structured output
  jsonMode?: boolean;         // OpenRouter JSON mode
  retry?: {
    maxRetries?: number;
    backoff?: 'exponential' | 'linear';
  };
  providerOptions?: Record<string, unknown>;
}
```

## License

MIT