Multi-provider abstraction with Anthropic, Google, Mistral, and custom providers

AI Providers

The @codmir/ai provider system abstracts multiple AI services behind a unified interface. Each provider implements the BaseProvider abstract class, exposing complete(), stream(), and createEmbedding().

Installation

import {
  BaseProvider,
  AnthropicProvider,
  createAnthropicProvider,
  createProviders,
  getProvider,
  getBestProvider,
} from "@codmir/ai";

Provider Registry

createProviders(): ProviderRegistry

Creates a registry of all available providers. Each provider is instantiated from environment variables.

import { createProviders, getBestProvider } from "@codmir/ai";

const providers = createProviders();
const best = getBestProvider(providers, "anthropic");

const response = await best.complete(
  [{ role: "user", content: "Hello" }],
  { model: "claude-sonnet-4-20250514" },
);

getProvider(registry, name): BaseProvider

Returns a specific provider from the registry. Throws if not found.

getBestProvider(registry, preference?): BaseProvider

Returns the best available provider, optionally preferring a specific one. Falls back to other available providers if the preferred one is not configured.

AnthropicProvider

The Anthropic provider uses Claude models via the @ai-sdk/anthropic package.

Setup

import { createAnthropicProvider } from "@codmir/ai";

// From environment (reads ANTHROPIC_API_KEY)
const provider = createAnthropicProvider();

// Manual configuration
const provider = createAnthropicProvider({
  apiKey: "sk-ant-...",
  baseUrl: "https://api.anthropic.com",
  defaultModel: "claude-opus-4-20250514",
});

Capabilities

CapabilitySupported
ChatYes
StreamingYes
VisionYes
Function CallingYes
EmbeddingsNo
Code GenerationYes
Long ContextYes (200k tokens)

Default Model

claude-opus-4-20250514

Environment Variables

VariableDescription
ANTHROPIC_API_KEYAnthropic API key

BaseProvider Interface

All providers implement this abstract class. Use it to create custom providers.

import { BaseProvider, BaseProviderOptions } from "@codmir/ai";
import type {
  AIProvider,
  ProviderCapabilities,
  Message,
  ToolDefinition,
  CompletionResponse,
  StreamChunk,
} from "@codmir/ai";

BaseProviderOptions

interface BaseProviderOptions {
  apiKey?: string;
  baseUrl?: string;
  defaultModel?: string;
}

Abstract Methods

complete(messages, options?): Promise<CompletionResponse>

Generate a single completion.

abstract complete(
  messages: Message[],
  options?: {
    model?: string;
    temperature?: number;
    maxTokens?: number;
    tools?: ToolDefinition[];
  },
): Promise<CompletionResponse>;

stream(messages, options?): AsyncIterable<StreamChunk>

Stream a completion response.

abstract stream(
  messages: Message[],
  options?: {
    model?: string;
    temperature?: number;
    maxTokens?: number;
    tools?: ToolDefinition[];
  },
): AsyncIterable<StreamChunk>;

createEmbedding(text, options?): Promise<number[][]>

Create embeddings for text. Throws if the provider does not support embeddings.

abstract createEmbedding(
  text: string | string[],
  options?: { model?: string },
): Promise<number[][]>;

isConfigured(): boolean

Returns whether the provider has the required credentials to operate.

getDefaultModel(): string

Returns the provider's default model identifier.

getStatus(): ProviderStatus

Returns the provider's current status (implemented by BaseProvider, not abstract).

const status = provider.getStatus();
// {
//   provider: "anthropic",
//   available: true,
//   model: "claude-opus-4-20250514",
//   capabilities: { chat: true, streaming: true, vision: true, ... }
// }

Creating a Custom Provider

Extend BaseProvider to add support for a new AI service.

import { BaseProvider, BaseProviderOptions } from "@codmir/ai";
import type {
  AIProvider,
  ProviderCapabilities,
  Message,
  CompletionResponse,
  StreamChunk,
} from "@codmir/ai";

export class MyProvider extends BaseProvider {
  readonly name: AIProvider = "local";
  readonly capabilities: ProviderCapabilities = {
    chat: true,
    streaming: true,
    vision: false,
    functionCalling: false,
    embeddings: true,
    codeGeneration: true,
    longContext: false,
    maxContextLength: 8192,
  };

  constructor(options: BaseProviderOptions = {}) {
    super(options);
    this.apiKey = options.apiKey || process.env.MY_PROVIDER_KEY;
  }

  getDefaultModel(): string {
    return "my-model-v1";
  }

  isConfigured(): boolean {
    return !!this.apiKey;
  }

  async complete(messages: Message[], options?: { model?: string; temperature?: number; maxTokens?: number }): Promise<CompletionResponse> {
    // Implement your API call here
    const response = await fetch("https://my-provider.com/v1/chat", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${this.apiKey}`,
      },
      body: JSON.stringify({
        model: options?.model || this.defaultModel,
        messages,
        temperature: options?.temperature,
        max_tokens: options?.maxTokens,
      }),
    });

    const data = await response.json();

    return {
      content: data.choices[0].message.content,
      role: "assistant",
      usage: {
        promptTokens: data.usage.prompt_tokens,
        completionTokens: data.usage.completion_tokens,
        totalTokens: data.usage.total_tokens,
      },
      provider: this.name,
      model: options?.model || this.defaultModel,
      finishReason: "stop",
    };
  }

  async *stream(messages: Message[], options?: { model?: string }): AsyncIterable<StreamChunk> {
    // Implement streaming
    yield { content: "...", done: false };
    yield { content: "", done: true };
  }

  async createEmbedding(text: string | string[]): Promise<number[][]> {
    // Implement embeddings
    const texts = Array.isArray(text) ? text : [text];
    return texts.map(() => new Array(768).fill(0));
  }
}

Types

ProviderCapabilities

interface ProviderCapabilities {
  chat: boolean;
  streaming: boolean;
  vision: boolean;
  functionCalling: boolean;
  embeddings: boolean;
  codeGeneration: boolean;
  longContext: boolean;
  maxContextLength: number;
}

ProviderStatus

interface ProviderStatus {
  provider: AIProvider;
  available: boolean;
  model: string;
  capabilities: ProviderCapabilities;
}

ProviderConfig

interface ProviderConfig {
  provider: AIProvider;
  apiKey?: string;
  baseUrl?: string;
  model?: string;
  maxTokens?: number;
  temperature?: number;
}