pi-mono/packages/ai/catalog
David Brailovsky 9ee7586a95 fix(ai): send drop_block for OpenCode Zen and Go Claude models
Enable per-message effort for OpenCode Claude models that support it, which
also sends thinking.block_binding drop_block. OpenCode Go rejected replayed
thinking with a 400 after the tool list or system prompt changed.

closes #10954
2026-11-02 12:37:52 +01:00
..
families feat(ai): refactor provider definitions (#11368) 2026-10-28 11:06:10 +01:00
providers fix(ai): send drop_block for OpenCode Zen and Go Claude models 2026-11-02 12:37:52 +01:00
sources feat(ai): refactor provider definitions (#11368) 2026-10-28 11:06:10 +01:00
build.ts feat(ai): refactor provider definitions (#11368) 2026-10-28 11:06:10 +01:00
define.ts feat(ai): refactor provider definitions (#11368) 2026-10-28 11:06:10 +01:00
generate.ts feat(ai): refactor provider definitions (#11368) 2026-10-28 11:06:10 +01:00
README.md feat(ai): refactor provider definitions (#11368) 2026-10-28 11:06:10 +01:00
reasoning.ts feat(ai): refactor provider definitions (#11368) 2026-10-28 11:06:10 +01:00

Model catalog

node catalog/generate.ts (npm run generate-models) fetches upstream catalogs and writes the built-in model catalog:

  • src/providers/data/<provider>.json: model values, grouped by API (gitignored)
  • src/providers/<provider>.models.ts and src/models.generated.ts: typed wrappers (committed)
  • with --json-output <dir>: the public catalog JSON served by pi.dev

Layout

Path Contents
sources/ Upstream fetchers. models-dev.ts normalizes the models.dev v2 catalog; OpenRouter, Vercel AI Gateway, NVIDIA NIM, and Radius have their own modules. All sources are fetched before anything is built.
providers/<id>.ts One file per built-in provider: where its models come from, its API and base URL, compat defaults, corrections, and models upstream does not list. Register new files in providers/index.ts.
families/ Facts about a model family that hold on every host, such as Claude effort levels or GPT-6 thinking levels. They apply to every provider's models.
define.ts defineProvider() and the helpers provider files use.
build.ts Runs the provider definitions in a fixed order.

Build order

For each provider:

  1. models(ctx) returns its chat models: upstream entries mapped to pi models, data corrections (limits, prices), and authored models. ctx.providerModels(id) returns another provider's models from this step, e.g. Azure derives from OpenAI.
  2. compat defaults for each API are merged under each model's own compat. Then the shared rules run: models.dev effort levels for APIs that send them natively, and the rules in families/.
  3. finalize(model, ctx) applies provider-specific behavior. It runs after the shared rules, so its values win.
  4. Image input limits get the default resize profile, then finalizeAll(models, ctx) runs cross-model logic such as Anthropic's allowed fallback models.

Adding a provider

Most providers are a models.dev provider served on one API:

import { defineProvider, modelsDevModels } from "../define.ts";

export default defineProvider({
	id: "example",
	models: (ctx) =>
		modelsDevModels(ctx, "example", { api: "openai-completions", baseUrl: "https://api.example.com/v1" }),
	compat: { "openai-completions": { supportsStore: false, supportsDeveloperRole: false } },
});

modelsDevModels() keeps tool-capable chat models and maps names, input modalities, costs (including context tiers), and limits. Use its include and map options for provider-specific filtering and fields. Prefer fixing wrong upstream data in models.dev; keep local corrections small and say why they exist.

Checking changes

npm run diff:model-catalog -- [provider ...] from the repository root generates the catalog at HEAD and in the worktree and prints the JSON differences.