fix(mcplocal): learn which models reject sampling params #128

Merged
michal merged 1 commits from deploy/bounded-failures into main 2026-08-25 23:12:08 +00:00
Owner

Follow-up to #127, found by that deploy's own smoke output.

Auto-following to the newest Opus moved the failure rather than removing it. The 404 "model not found" became:

HTTP 400: `temperature` is deprecated for this model.

Anthropic removed temperature/top_p/top_k on the current generation (Opus 5, Sonnet 5, Opus 4.7/4.8, Fable 5), and the adapter sends temperature: 0 unconditionally — so gate prompt-selection was still degrading on every call, just with a different status code.

A hardcoded list of which models accept sampling would rot exactly the way the pinned model ids did — which is what this whole line of work is trying to stop. So the provider learns it: the first 400 naming a sampling parameter drops it and retries, and remembers the model so later calls omit it up front. One wasted call, once.

The match is deliberately narrow — the 400 must actually name temperature/top_p/top_k. An unrelated 400 (missing max_tokens, bad schema) propagates untouched, with a test, because a broad match would silently swallow real request errors and retry them pointlessly.

Verified live: claude-opus-latestclaude-opus-5, first attempt 400 on temperature, retry gets past it. The retry then hit 429 — the personal OAuth token's rate limit, which is the pre-existing credential-tiering issue, not this path.

2,803 tests pass.

🤖 Generated with Claude Code

https://claude.ai/code/session_01GqMidYEGUJG5fxeoTELBu2

Follow-up to #127, found by that deploy's own smoke output. Auto-following to the newest Opus **moved** the failure rather than removing it. The 404 "model not found" became: ``` HTTP 400: `temperature` is deprecated for this model. ``` Anthropic removed `temperature`/`top_p`/`top_k` on the current generation (Opus 5, Sonnet 5, Opus 4.7/4.8, Fable 5), and the adapter sends `temperature: 0` unconditionally — so gate prompt-selection was still degrading on every call, just with a different status code. A hardcoded list of which models accept sampling would rot exactly the way the pinned model ids did — which is what this whole line of work is trying to stop. So the provider **learns** it: the first 400 naming a sampling parameter drops it and retries, and remembers the model so later calls omit it up front. One wasted call, once. The match is deliberately narrow — the 400 must actually name `temperature`/`top_p`/`top_k`. An unrelated 400 (missing `max_tokens`, bad schema) propagates untouched, with a test, because a broad match would silently swallow real request errors and retry them pointlessly. **Verified live:** `claude-opus-latest` → `claude-opus-5`, first attempt 400 on temperature, retry gets past it. The retry then hit **429** — the personal OAuth token's rate limit, which is the pre-existing credential-tiering issue, not this path. 2,803 tests pass. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01GqMidYEGUJG5fxeoTELBu2
michal added 1 commit 2026-08-25 23:12:01 +00:00
fix(mcplocal): learn which models reject sampling params, don't hardcode them
Some checks failed
CI/CD / typecheck (pull_request) Successful in 1m22s
CI/CD / lint (pull_request) Successful in 2m34s
CI/CD / test (pull_request) Successful in 1m28s
CI/CD / build (pull_request) Successful in 2m27s
CI/CD / smoke (pull_request) Failing after 3m6s
CI/CD / publish (pull_request) Has been skipped
bc7eb5a0ad
Auto-following to the newest Opus moved the failure rather than removing it.
The deploy's own smoke output showed it: 404 "model not found" became

  HTTP 400: `temperature` is deprecated for this model.

Anthropic removed temperature/top_p/top_k on the current generation (Opus 5,
Sonnet 5, Opus 4.7/4.8, Fable 5), and the adapter sends temperature: 0
unconditionally. So the gate's prompt-selection was still degrading on every
call -- just with a different status code.

A list of which models accept sampling would rot exactly the way the pinned
model ids did, which is the whole thing this branch is trying to stop. So the
provider learns it instead: the first 400 naming a sampling parameter drops it
and retries, and remembers the model so every later call omits it up front.
One wasted call, once, rather than a hardcoded table to maintain.

The match is deliberately narrow -- a 400 must actually name temperature/top_p/
top_k. An unrelated 400 (missing max_tokens, bad schema) propagates untouched;
there is a test for that, because a broad match here would silently swallow
real request errors and retry them pointlessly.

Verified live: claude-opus-latest -> claude-opus-5, first attempt 400 on
temperature, retry succeeds past it. The retry then hit HTTP 429 -- the
personal OAuth token's rate limit, which is the pre-existing credential-tiering
issue, not this path.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GqMidYEGUJG5fxeoTELBu2
michal merged commit 33d7007af5 into main 2026-08-25 23:12:08 +00:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: michal/mcpctl#128