Skip to content

feat: drive reasoning variants from models.dev reasoning_options#31570

Open
rekram1-node wants to merge 1 commit into
devfrom
reasoning-options-support
Open

feat: drive reasoning variants from models.dev reasoning_options#31570
rekram1-node wants to merge 1 commit into
devfrom
reasoning-options-support

Conversation

@rekram1-node

Copy link
Copy Markdown
Collaborator

What

models.dev now curates a reasoning_options field per provider model (431 models live). This PR parses it and uses its effort values to generate reasoning variants instead of the ~500-line hardcoded per-package tables — in both the v1 provider catalog and the v2 catalog plugin.

How

Schema (forward-compatible by design)

  • ModelsDev.ReasoningOption is a discriminated union mirroring models.dev: toggle | effort | budget_tokens. Effort values are open strings (tiers like xhigh were added over time) and budget bounds are optional. api.json is cast, never decoded, so unknown future option types cannot fail parsing; they are filtered at the single mapping boundary into the resolved catalog, so schema-validated surfaces (HTTP/SDK/openapi) only ever see known variants.
  • Config models (ConfigProviderV1.Model) accept the same union; null effort values are stripped when mapping so the resolved capabilities.reasoningOptions contract matches its generated SDK type exactly.

v1 (ProviderTransform.variants)

  • Effort data drives variant generation when present; the wire encoding per SDK package stays in code (ReasoningVariants in core). Models without usable effort data (toggle/budget-only, absent) fall back to the hardcoded tables unchanged.

v2

  • ModelsDevPlugin generates effort variants from reasoning_options alongside experimental.modes (curated modes win id collisions), partitioned through ModelRequest.normalizeAiSdkOptions.
  • The anthropic profile gains the effort semantic, and the native AnthropicMessages protocol now supports adaptive thinking (thinking: {type: "adaptive", display?}), lowers effort to output_config.effort (wire shape verified against @ai-sdk/anthropic), and conditionally sends the anthropic-beta: effort-2025-11-24 header. Without this, anthropic effort variants would be dead on arrival in v2.
  • v1→v2 config migration now keeps anthropic effort aisdk-shaped so it re-partitions into the semantic option — more correct than the old raw output_config.effort lowering, which never sent the required beta header.

Verification

  • Catalog-wide audit against live api.json (old vs new variants for all ~3000 reasoning models): 2975 byte-identical, 0 encoding changes, 38 diffs — every diff is curated data correcting stale hardcoding (e.g. vercel/openai/o1,o3 losing bogus none/minimal/xhigh, deepseek-v4 narrowing to [high,max], grok-4.3/mistral/fireworks gaining missing variants, gemini-3-pro dropping unsupported medium). Anthropic, OpenAI, Azure, Copilot, OpenRouter, and SAP produce byte-identical output from data vs hardcoded.
  • New tests: 13 data-driven variants tests + 3 schema decode tests (opencode), 2 v2 plugin tests (core), 3 anthropic protocol tests (llm).
  • Typechecks clean in core/opencode/llm; full suites green (llm 278, opencode provider 400, core 1036 — the 6 core failures are pre-existing on dev, verified by stashing).
  • SDK + openapi regenerated.

Not in scope

  • ModelV2.Capabilities still carries no reasoning fields — variants are the selection surface in v2 (Ref.variant), so nothing needed it yet.
  • budget_tokens data is parsed and carried but does not yet drive budget-style variants; those still come from the hardcoded fallback (current data matches the hardcoded budgets exactly).

Parse the curated reasoning_options field from models.dev api.json and use
its effort values to generate reasoning variants instead of the hardcoded
per-package tables, in both the v1 provider catalog and the v2 catalog plugin.

- core: ModelsDev.ReasoningOption discriminated union (toggle | effort |
  budget_tokens); effort values stay open strings and unknown option types
  are tolerated since api.json is cast, not decoded
- core: ReasoningVariants shared per-package effort encoder used by v1
  ProviderTransform.variants and the v2 ModelsDevPlugin
- core: v2 catalog generates effort variants from reasoning_options;
  curated experimental modes win id collisions; anthropic profile gains
  the effort semantic
- llm: anthropic protocol supports adaptive thinking, lowers effort to
  output_config.effort, and sends the effort-2025-11-24 beta header
- opencode: resolved Provider.Model carries capabilities.reasoningOptions
  (unknown types and null effort values dropped at the mapping boundary);
  config models accept reasoning_options; models without usable effort
  data fall back to the hardcoded tables unchanged

Catalog-wide audit vs live api.json: 2975 models byte-identical, 38 diffs,
all data correcting stale hardcoded effort lists.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant