Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .changeset/ai-models-catalog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@tanstack/ai-models': minor
---

New package: a runtime catalog of 1,853 models across 38 providers, generated from models.dev and the OpenRouter and Vercel AI Gateway model lists. `getProviders`, `getModels`, and `getModel` return each model's id, input modalities, context window, output limit, prices, reasoning data, and request quirks (`compat`). A record's `reasoning` has the `ModelReasoning` shape of `@tanstack/ai` (`false`, or `{ levels, budget }`). `supportedReasoningLevels`, `clampReasoningLevel`, and `modelCost` work on a record, and `generatedAt` is the date of the data. Each provider also has its own subpath, for example `@tanstack/ai-models/deepseek`.

`modelCost` prices long context and 1-hour cache writes. A record's `cost.tiers` (from models.dev) holds higher prices above an input size, and a call uses the tier with the highest `inputTokensAbove` below its input. `TokenCounts.cacheWrite1h`, the part of `cacheWrite` with a 1-hour retention, costs 2 times the input price.

The `google-vertex` and `azure-openai-responses` providers have only the models on their own wire, so no Claude models. Use `anthropicVertexText` from `@tanstack/ai-anthropic/vertex` for Claude on Vertex. Embedding, reranking, and transcription models are not in the catalog.
5 changes: 5 additions & 0 deletions docs/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -1634,6 +1634,11 @@
"to": "advanced/extend-adapter-advanced",
"addedAt": "2026-10-21"
},
{
"label": "Model Catalog",
"to": "models/catalog",
"addedAt": "2026-10-14"
},
{
"label": "Typed Pre-Configured Options",
"to": "advanced/typed-options",
Expand Down
125 changes: 125 additions & 0 deletions docs/models/catalog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
---
title: Model Catalog
id: catalog
description: "Look up models, reasoning levels, prices, and context windows at runtime with @tanstack/ai-models."
keywords:
- tanstack ai
- model catalog
- models.dev
- model metadata
- reasoning levels
- model pricing
---

A model picker, a cost display, or a settings menu needs facts about models at runtime: which models a provider has, which reasoning levels a model takes, and what a call costs. `@tanstack/ai-models` is a catalog of that data for more than 1,800 models across 38 providers.

## Install

<!-- ::start:tabs variant="package-manager" mode="install" -->

react: @tanstack/ai-models
vue: @tanstack/ai-models
solid: @tanstack/ai-models
svelte: @tanstack/ai-models
preact: @tanstack/ai-models
angular: @tanstack/ai-models
vanilla: @tanstack/ai-models
octane: @tanstack/ai-models

<!-- ::end:tabs -->

## Look up a model

```typescript
import { getModel, getModels, getProviders } from "@tanstack/ai-models";

const providers = getProviders(); // every provider: id, name, baseUrl, env
const deepseekModels = getModels("deepseek"); // every DeepSeek model
const model = getModel("deepseek", "deepseek-v4-flash");

console.log(model?.contextWindow, model?.maxTokens, model?.input);
```

Each record has the model's `id`, `name`, `input` modalities, `contextWindow`, `maxTokens`, prices, and reasoning data. `getModel` returns `undefined` for a model the catalog does not have.

The `google-vertex` provider has the Gemini models only. For Claude on Vertex, use `anthropicVertexText` from `@tanstack/ai-anthropic/vertex`.

## Show the reasoning levels

`supportedReasoningLevels` gives the levels a model takes. Use it to fill a menu:

```typescript
import { getModel, supportedReasoningLevels } from "@tanstack/ai-models";

const model = getModel("deepseek", "deepseek-v4-flash");
const levels = model ? supportedReasoningLevels(model) : [];
// ["off", "low", "high", "max"]
```

`clampReasoningLevel(model, level)` gives the nearest level the model has, for a level it does not have. Pass the level to [`chat({ reasoning })`](../chat/reasoning).

A record's `reasoning` is `false` for a model that does not reason. Otherwise it has two fields:

- `levels`: the provider value to send for each level the model has.
- `budget`: `true` when the model takes a thinking token budget.

This is the same shape as `ModelReasoning` in `@tanstack/ai`.

## Work out what a call cost

Prices are in USD per million tokens. `modelCost` turns token counts into a cost. `input` is the uncached input:

```typescript
import { getModel, modelCost } from "@tanstack/ai-models";

const model = getModel("openai", "gpt-5.6");
if (model) {
const cost = modelCost(model, { input: 12_000, output: 800 });
console.log(cost.total.toFixed(4));
}
```

`modelCost` also uses two price rules:

- **Long context.** Some models cost more above an input size. The record lists these prices in `cost.tiers`. A call uses the tier with the highest `inputTokensAbove` below its input (uncached, plus cache reads, plus cache writes).
- **1-hour cache writes.** `cacheWrite1h` is the part of `cacheWrite` that has a 1-hour retention. It costs 2 times the input price.

To price each call of a chat, read its usage in middleware:

```typescript
import type { ChatMiddleware } from "@tanstack/ai";
import { getModel, modelCost } from "@tanstack/ai-models";

const model = getModel("anthropic", "claude-sonnet-5-5");

const logCost: ChatMiddleware = {
name: "log-cost",
onUsage(_ctx, usage) {
if (!model) return;
const details = usage.promptTokensDetails;
const cacheRead = details?.cachedTokens ?? 0;
const cacheWrite = details?.cacheWriteTokens ?? 0;
const cost = modelCost(model, {
input: usage.promptTokens - cacheRead - cacheWrite,
output: usage.completionTokens,
cacheRead,
cacheWrite,
});
console.log(cost.total.toFixed(4));
},
};
```

## Load one provider only

The root import has every provider. To load only one, import its subpath:

```typescript
import { models, provider } from "@tanstack/ai-models/deepseek";

console.log(provider.baseUrl, models.length);
```

## Keep it up to date

The catalog comes from [models.dev](https://models.dev) and the OpenRouter and Vercel AI Gateway model lists. `generatedAt` is the date of the last update. A record with `borrowedFrom` took its data from the same model at another provider.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@
"generate:fal-image-fields": "tsx scripts/generate-fal-image-field-map.ts",
"generate:models": "pnpm generate:models:fetch && pnpm regenerate:models && tsx scripts/sync-elevenlabs-models.ts && tsx scripts/sync-provider-models.ts && pnpm format",
"generate:models:elevenlabs": "tsx scripts/sync-elevenlabs-models.ts",
"generate:models:fetch": "tsx scripts/fetch-openrouter-models.ts && tsx scripts/fetch-vercel-gateway-models.ts && tsx scripts/fetch-lovable-gateway-models.ts && node scripts/fetch-llmgateway-models.ts",
"regenerate:models": "tsx scripts/convert-openrouter-models.ts && tsx scripts/convert-vercel-gateway-models.ts && node scripts/convert-llmgateway-models.ts",
"generate:models:fetch": "tsx scripts/fetch-openrouter-models.ts && tsx scripts/fetch-vercel-gateway-models.ts && tsx scripts/fetch-lovable-gateway-models.ts && node scripts/fetch-llmgateway-models.ts && tsx scripts/fetch-models-dev.ts",
"regenerate:models": "tsx scripts/convert-openrouter-models.ts && tsx scripts/convert-vercel-gateway-models.ts && node scripts/convert-llmgateway-models.ts && tsx scripts/generate-ai-models.ts",
"sync-docs-config": "node scripts/sync-docs-config.ts",
"copy:readme": "node scripts/copy-readme.js",
"changeset": "changeset",
Expand Down
21 changes: 21 additions & 0 deletions packages/ai-models/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2025 Tanner Linsley

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
40 changes: 40 additions & 0 deletions packages/ai-models/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<div align="center">
<picture>
<source
media="(prefers-color-scheme: dark)"
srcset="https://tanstack.com/api/readme/ai.png?theme=dark"
/>
<source
media="(prefers-color-scheme: light)"
srcset="https://tanstack.com/api/readme/ai.png"
/>
<img
src="https://tanstack.com/api/readme/ai.png"
alt="TanStack AI"
width="900"
/>
</picture>
</div>

<br />

# @tanstack/ai-models

A model catalog you can read at runtime: each model's context window, price, reasoning levels, input kinds, and wire quirks, for about 1,850 models across 38 providers.

```ts
import { getModel, modelCost, clampReasoningLevel } from '@tanstack/ai-models'

const model = getModel('deepseek', 'deepseek-v4-flash')
if (model) {
model.contextWindow // 1000000
modelCost(model, { input: 12_000, output: 800 }).total // USD
clampReasoningLevel(model, 'medium') // 'high': the nearest level the model has
}
```

- No dependencies, and no Node.js APIs, so it runs on edge runtimes too.
- One subpath per provider (`@tanstack/ai-models/deepseek`), so a build ships only the providers it imports.
- The data comes from [models.dev](https://models.dev) and the OpenRouter and Vercel model lists. `pnpm generate:models` refreshes it.

Read the guide: [Model catalog](https://tanstack.com/ai/latest/docs/models/catalog).
Loading
Loading