# Model Registry

URL: https://cogitator.app/docs/core/model-registry

> Dynamic model registry with pricing, capabilities, and multi-provider support.

## Overview

The `@cogitator-ai/models` package provides a dynamic model registry that tracks pricing, context windows, and capabilities for LLM models across all major providers. It fetches data from [LiteLLM](https://github.com/BerriAI/litellm) and includes built-in fallbacks.

```typescript
import { initializeModels, getModel, getPrice, listModels } from '@cogitator-ai/models';

await initializeModels();

const model = getModel('gpt-6.1-sol');
console.log(model?.contextWindow); // 1050000
console.log(model?.capabilities?.supportsVision); // true

const price = getPrice('claude-sonnet-5-5');
console.log(`$${price?.input}/M input, $${price?.output}/M output`);
```

Model ids are matched case-insensitively and `aliases` resolve too (`claude-sonnet-5.5` → `claude-sonnet-5-5`). Lookups return `null` for unknown models.

### Provider-qualified ids

The same model is often sold by several providers at different prices, so the registry keeps one entry per provider. Each entry's `id` is the model's name at that provider, `provider` is the registry's provider id, and `catalogId` is the key LiteLLM lists it under:

```typescript
await initializeModels();

getModel('openrouter/deepseek/deepseek-v4-pro');
// { id: 'deepseek/deepseek-v4-pro', provider: 'openrouter',
//   catalogId: 'openrouter/deepseek/deepseek-v4-pro', pricing: { input: 0.2088, output: 0.4176 }, ... }

getModel('azure_ai/deepseek-v4-pro')?.provider; // 'azure', at Azure's price
getModel('google/gemini-3.8-flash')?.id; // 'gemini-3.8-flash' (also found as gemini/gemini-3.8-flash)
```

A lookup resolves in this order:

1. A provider-qualified id finds that provider's entry. Both Cogitator model strings (`openai/gpt-6.1-sol`, `google/gemini-3.8-flash`, `openrouter/deepseek/deepseek-v4-pro`) and LiteLLM keys (`gemini/...`, `azure_ai/...`) work.
2. When that provider does not list the model, the prefix is dropped and the rest is looked up, so `openai/deepseek/deepseek-v4-pro` (an OpenAI-compatible server) is priced as `deepseek/deepseek-v4-pro`.
3. A bare name (`deepseek-v4-pro`) picks one listing by fixed rules, never by catalogue order: active models before deprecated ones, the vendor's own listing (a built-in model or an unprefixed LiteLLM key) before resellers, then the providers in `BUILTIN_PROVIDERS` order, then the shorter id, then alphabetically.

Pass the full model string your agent runs on to get that provider's price. The built-in models follow the same rules before `initializeModels()` runs.

## Pricing and Cost

Prices are USD per million tokens. `getPrice()` returns only `input` and `output`; `getPricing()` returns the full `ModelPricing`, including prompt-cache prices:

```typescript
import { getPricing, calculateCost } from '@cogitator-ai/models';

getPricing('claude-sonnet-5-5');
// { input: 2, output: 10, inputCached: 0.2, inputCacheWrite: 2.5 }

const cost = calculateCost('claude-sonnet-5-5', {
  inputTokens: 10_000,
  outputTokens: 1_000,
  cachedInputTokens: 8_000, // part of inputTokens read from the cache
  cacheWriteTokens: 0, // part of inputTokens written to the cache
});
// 0.0156 (USD), or null when the model's price is unknown
```

Cache reads and writes are charged at `inputCached` / `inputCacheWrite` where the model has them, and at the input price otherwise. `RunResult.usage.cost` adds up the cost of each model call. When the provider reports what a call cost (OpenRouter does, in `usage.cost`), the runtime takes that price, which also reflects which upstream served the call. Other calls are priced with `calculateCost()` on the shared registry, using the full model string the agent runs on, so a model the registry does not know and whose provider reports nothing costs `0`. Call `initializeModels()` at startup to price more than the built-in models.

## ModelRegistry

The `ModelRegistry` class manages model data with caching and auto-refresh.

```typescript
import { ModelRegistry } from '@cogitator-ai/models';

const registry = new ModelRegistry({
  cache: {
    ttl: 24 * 60 * 60 * 1000,
    storage: 'file',
    filePath: './cache/models.json',
  },
  autoRefresh: true,
  refreshInterval: 24 * 60 * 60 * 1000,
  fallbackToBuiltin: true,
});

await registry.initialize();
```

### Options

| Option              | Default                          | Description                                                                                  |
| ------------------- | -------------------------------- | -------------------------------------------------------------------------------------------- |
| `cache.ttl`         | 24 hours                         | Cache time-to-live in milliseconds                                                           |
| `cache.storage`     | `'memory'`                       | `'memory'` or `'file'`                                                                       |
| `cache.filePath`    | `~/.cogitator/models-cache.json` | File path for file-based cache (in memory where there is no file system, e.g. edge runtimes) |
| `autoRefresh`       | `false`                          | Automatically refresh data in background                                                     |
| `refreshInterval`   | 24 hours                         | Refresh interval in milliseconds                                                             |
| `fallbackToBuiltin` | `true`                           | Use built-in models when fetch fails                                                         |

### Methods

`initialize()` loads a fresh cache if there is one (and refreshes it in the background), otherwise fetches LiteLLM data; on failure it falls back to built-in models (or throws when `fallbackToBuiltin` is `false`). Lookups before `initialize()` load the built-in models.

```typescript
registry.getModel('gpt-6.1-sol');
registry.getPrice('gpt-6.1-sol');
registry.getPricing('gpt-6.1-sol');
registry.listModels({ provider: 'openai', supportsTools: true });
registry.listProviders();
registry.getProvider('anthropic');
registry.getModelCount();
registry.isInitialized();
await registry.refresh();
registry.shutdown();
```

## Filtering

Use `ModelFilter` to query models by provider, capabilities, and cost:

```typescript
import { listModels } from '@cogitator-ai/models';

const visionModels = listModels({ supportsVision: true, excludeDeprecated: true });

const cheapToolModels = listModels({
  supportsTools: true,
  maxPricePerMillion: 1.0,
});

const largeContext = listModels({
  minContextWindow: 200_000,
  provider: 'anthropic',
});
```

### Filter Options

| Filter               | Type      | Description                             |
| -------------------- | --------- | --------------------------------------- |
| `provider`           | `string`  | Filter by provider ID                   |
| `supportsTools`      | `boolean` | Filter by tool/function calling support |
| `supportsVision`     | `boolean` | Filter by vision/image support          |
| `minContextWindow`   | `number`  | Minimum context window size             |
| `maxPricePerMillion` | `number`  | Max average price per million tokens    |
| `excludeDeprecated`  | `boolean` | Exclude deprecated models               |

## Built-in Providers

The registry includes provider entries (`BUILTIN_PROVIDERS`) for 16 providers:

OpenAI (`openai`), Anthropic (`anthropic`), Google (`google`), Ollama (`ollama`), Azure OpenAI (`azure`), AWS Bedrock (`aws`), Mistral AI (`mistral`), Cohere (`cohere`), Groq (`groq`), Together AI (`together`), Fireworks AI (`fireworks`), DeepInfra (`deepinfra`), Perplexity (`perplexity`), Replicate (`replicate`), xAI (`xai`), OpenRouter (`openrouter`).

Built-in model data covers OpenAI, Anthropic and Google; models of the other providers, and additional providers, come from LiteLLM data once it is fetched. `getProvider(id).models` lists the model ids loaded for a provider.

## Built-in Models

Built-in fallbacks cover current model families for major providers, including OpenAI GPT-6 (`gpt-6-astra`, `gpt-6.1-sol`, `gpt-6-luna`) and GPT-5.6/5.5, Anthropic Claude Opus 5.5 / Sonnet 5.5 / Fable 5.1 / Haiku 4.5, and Google Gemini 3.8 Flash / Gemini 3.5 Flash-Lite / Gemini 3.1 Pro Preview.

Retired or retiring models stay in the registry with `deprecated: true` so lookups and pricing keep working for existing configs — among them `o3`, `o3-mini`, `o3-pro`, `o4-mini`, `gpt-4.1-nano`, `gpt-5.4-nano`, `gpt-4`, `gpt-4-turbo`, `claude-sonnet-4`, `claude-opus-4`, `claude-opus-4-1`, the Claude 3.x models, and Gemini 2.5 / 2.0 / 1.5. Use `excludeDeprecated: true` (or filter on `model.deprecated`) to skip them.

```typescript
import {
  BUILTIN_MODELS,
  OPENAI_MODELS,
  ANTHROPIC_MODELS,
  GOOGLE_MODELS,
} from '@cogitator-ai/models';

const activeOpenAI = OPENAI_MODELS.filter((model) => !model.deprecated);
const cheapToolModels = BUILTIN_MODELS.filter(
  (model) =>
    model.capabilities?.supportsTools && (model.pricing.input + model.pricing.output) / 2 <= 5
);
```

## Caching

Models data is cached to avoid repeated network requests:

```typescript
// Memory cache (default)
new ModelRegistry({ cache: { ttl: 3600000, storage: 'memory' } });

// File cache (persists across restarts)
new ModelRegistry({
  cache: { ttl: 86400000, storage: 'file', filePath: './models-cache.json' },
});
```

The cache supports stale-while-revalidate: if a refresh fails, the registry falls back to stale cached data before using built-in models. Fetched data is merged over the built-in entries, so built-in models keep their display names and aliases with fresh prices.

`ModelCache` is exported for direct use (`get()`, `getStale()`, `set(models)`, `clear()`).

## LiteLLM Integration

For advanced use cases, you can fetch and transform LiteLLM data directly:

```typescript
import { fetchLiteLLMData, transformLiteLLMData } from '@cogitator-ai/models';

const rawData = await fetchLiteLLMData();
const models = transformLiteLLMData(rawData);
```

## Zod Schemas

All types have corresponding Zod schemas for runtime validation:

```typescript
import {
  ModelInfoSchema,
  ModelPricingSchema,
  ModelCapabilitiesSchema,
  ProviderInfoSchema,
} from '@cogitator-ai/models';

const result = ModelInfoSchema.safeParse(unknownData);
if (result.success) {
  console.log(result.data.id);
}
```

## Global Functions

Convenience functions use a shared default registry:

```typescript
import {
  initializeModels,
  getModel,
  getPrice,
  listModels,
  getModelRegistry,
  shutdownModels,
} from '@cogitator-ai/models';

await initializeModels();

getModel('gpt-6.1-sol');
getPrice('claude-sonnet-5-5');
listModels({ provider: 'google' });

shutdownModels();
```

These functions auto-initialize with built-in data on first use, so `initializeModels()` is optional but recommended for fetching latest data. The shared registry (`getModelRegistry()`) caches to the file `~/.cogitator/models-cache.json` for 24 hours; `shutdownModels()` stops it and discards it, so the next call creates a new one.
