fix(web): a coding agent on a model's fast version runs at Anthropic as the base model asked for fast speed

Merged
DA
7d ago
+201-27

What broke

Dean's two coding agents on Opus 5.5 · High · Fast (prod, 2026-10-12 22:04:46Z and 22:05:36Z) each failed at their first model call, about 0.4s after starting. Each turn row says failure=model with detail MODEL_CALL_FAILED … model: claude-opus-5-5-fast. His Opus 5.5 High agents without Fast, started a minute later, ran fine. These were the first fast-mode agents ever started in prod, and nothing reached Sentry.

Root cause

The picker's Fast toggle picks AI Gateway's fast slug, anthropic/claude-opus-5.5-fast. Coding agents don't go through AI Gateway, though: they call Anthropic directly, and providerModelOf turned the slug into claude-opus-5-5-fast. Anthropic has no model by that name, so it refused the first call. On Anthropic's own API, fast mode is the base model claude-opus-5-5 sent with speed: "fast" and the fast-mode-2026-02-01 beta header. Fast never worked on this direct-provider path; today's merges (#2222, #2167, #2119, BYOK #2078–2080, #2150) did not cause this.

Fix

  • providerModelOf reads a -fast slug as the base model with fast: true. For Anthropic, the step sends providerOptions.anthropic.speed: "fast", and @ai-sdk/anthropic 4.0.78 adds the fast-mode-2026-02-01 beta header by itself.
  • OpenAI fast versions are no longer offered. Gateway's docs (fast mode, service tiers) never say what an openai/…-fast slug stands for on OpenAI's own API, so instead of guessing (for example the priority tier), the catalog leaves those slugs out. The Fast row in the picker then reads disabled for OpenAI models. A step that still names one is refused with CODER_REFUSAL.NO_FAST_VERSION ("Luke cannot run the fast version of the agent's model at its provider. Choose the model with Fast off.") rather than being sent as the slug.
  • Spend: a fast turn's row and its per-model usage name the agent's catalog id (the -fast slug), so usageOfTurns prices it at the fast entry's catalog prices. For Opus 5.5 that is $8/$40 per MTok, double the base. A new test holds this, and nothing about pricing changes.

Tests

  • coder-host-model.test.ts: runs a step on anthropic/claude-opus-5.5-fast against a fake Anthropic at its fetch. The request it receives names claude-opus-5-5, carries speed: "fast" and the fast-mode-2026-02-01 beta, and keeps effort high; the same step without Fast sends neither. Fails without the fix: the request names claude-opus-5-5-fast. A second test checks that an OpenAI fast slug is refused with the new words; it also fails without the fix.
  • model-catalog.test.ts: a fast slug translates to its base model with fast on; the catalog offers Anthropic's fast version at its own prices and leaves OpenAI's out.
  • coder-host-usage.test.ts: a turn on the fast slug is priced at the fast entry's rates, double the base model's.

The two failed agents

They can't be retried: a failed first turn stays failed. Start new agents on Opus 5.5 · High · Fast once this deploys. Both failed before their first model call returned, so they spent no tokens.

Verification

./scripts/check.sh passes. Nothing in the desktop changed. The picker change comes only from what /api/models now answers, so there is no UI diff to screenshot. CI could not verify the Mac UI, and ./scripts/verify.sh was not run (Linux cloud VM; LUKE-159 is the manual Mac pass). The fix has not been run against the live Anthropic API, because I have no key here; the request shape is checked against Anthropic's fast-mode docs and the SDK's own request building.

🤖 Generated with Claude Code


Open workspace in Conductor


Devin Review