Skip to content

Data Sources

Before you can filter or recommend models, you need a catalog. pickai ships fromModelsDev() to fetch 3,700+ models from models.dev, but find() and recommend() accept any Model[], so you can bring your own data too.

Fetches the full catalog from models.dev/api.json and returns Promise<Model[]>. Uses the platform fetch API (Node 18+, Deno, Bun, browsers).

import { fromModelsDev } from "pickai";
const models = await fromModelsDev();

The full catalog includes many resellers and aggregators. When calling find() or recommend(), you can narrow results to known providers using the Provider Constants, and collapse duplicate listings of the same model with perModel().

Reseller metadata is not normalized and can be wrong. The same model can appear at wildly different price points across entries, including bogus $0 listings, which distorts any cost-weighted ranking. Fields like openWeights can also disagree between entries of the same model; use normalizeOpenWeights() before splitting on that field. When price accuracy matters, prefer DIRECT_PROVIDERS or verify against the provider’s pricing page.

If you’ve already fetched the models.dev data (for caching, offline use, or testing), pass it directly:

import { fromModelsDev, type ModelsDevData } from "pickai";
import { readFileSync } from "fs";
// Fetch https://models.dev/api.json yourself and cache however you like
const cached: ModelsDevData = JSON.parse(readFileSync("api.json", "utf-8"));
const models = await fromModelsDev(cached);

If you want to use the models.dev parser without the fetch wrapper, parseModelsDevData() is exported directly:

import { parseModelsDevData } from "pickai";
const data = await fetchFromYourCache();
const models = parseModelsDevData(data);

This returns Model[] synchronously. Useful when you manage fetching and caching yourself.

models.dev provides structured capability fields (reasoning, openWeights, structuredOutput, attachment), knowledge cutoff dates, and model status that other catalog sources don’t expose. These fields are what make metadata-only filtering and scoring meaningful: you can score on knowledge freshness, filter by reasoning capability, and exclude deprecated models out of the box.

That said, metadata can only tell you what a model supports, not how well it performs. For actual quality ranking, add benchmark data as a custom scoring criterion. See the benchmark examples.

find() and recommend() accept any Model[], so you can maintain a curated list, load from a database, combine multiple sources, or test with fixed data.

Each model must conform to the Model interface. These fields are required:

FieldTypeExample
idstring"claude-sonnet-4-5"
namestring"Claude Sonnet 4.5"
providerstring"anthropic"
openRouterIdstring"anthropic/claude-sonnet-4.5"
limit{ context, output }{ context: 200000, output: 16384 }
modalities{ input[], output[] }{ input: ["text", "image"], output: ["text"] }

The remaining fields are optional, but specific pickai features depend on them:

FieldUsed by
costcostEfficiency scoring, maxCostInput/maxCostOutput filters, sortByCost
releaseDaterecency scoring, default sort order in find()
knowledgeknowledgeFreshness scoring, minKnowledge filter
familyperFamily() constraint
reasoningreasoning filter, Purpose.Reasoning
toolCalltoolCall filter, Purpose.Coding
structuredOutputstructuredOutput filter
statusexcludeDeprecated filter

Missing optional fields are handled gracefully. Models without cost, releaseDate, or knowledge are uncovered on the corresponding criteria: they get no score contribution there, and the gap shows up in the result’s coverage. See Missing Data and Coverage.

custom-source.ts
import { recommend, Purpose, type Model } from "pickai";
// Bring your own model data: useful for testing, offline use,
// or when you maintain your own model catalog
const models: Model[] = [
{
id: "claude-sonnet-4-5",
name: "Claude Sonnet 4.5",
provider: "anthropic",
openRouterId: "anthropic/claude-sonnet-4.5",
cost: { input: 3, output: 15 },
limit: { context: 200_000, output: 16_384 },
modalities: { input: ["text", "image"], output: ["text"] },
reasoning: true,
toolCall: true,
structuredOutput: true,
family: "claude-sonnet",
releaseDate: "2025-02-24",
knowledge: "2025-04",
},
{
id: "gpt-4o",
name: "GPT-4o",
provider: "openai",
openRouterId: "openai/gpt-4o",
cost: { input: 2.5, output: 10 },
limit: { context: 128_000, output: 16_384 },
modalities: { input: ["text", "image", "audio"], output: ["text"] },
toolCall: true,
structuredOutput: true,
family: "gpt",
releaseDate: "2024-05-13",
knowledge: "2024-10",
},
];
const results = recommend(models, Purpose.Coding);
for (const m of results) {
console.log(` ${m.score.toFixed(3)} | ${m.name} (${m.provider})`);
}