Files
chenxiao5580-cmd 95cf7bc77c fix(modelis): declare reasoning_options per model from measurements (#3951)
* fix(modelis): declare reasoning_options per model from measurements

Follow-up to #3932. That PR landed with the same six-value effort list on
all nine models; the review bot was right that this is over-broad, and
re-measuring showed it is also incomplete.

Measured one control at a time against the live endpoint:

- effort kept only where the levels measurably change reasoning
  (Claude x3, Gemini x2). Dropped on both DeepSeek and both Qwen models,
  which accept every value and return 200 but do not change behaviour.
- toggle added where both states are caller-reachable. The mechanism
  differs by family: reasoning.enabled for Claude/Gemini/Qwen, and
  reasoning_effort "none" for DeepSeek, which ignores reasoning.enabled.
- budget_tokens added where reasoning_tokens tracks the requested budget
  (Gemini x2, Qwen x2). No min/max, since no boundary was probed.
- claude-fable-5 and gemini-2.5-pro reject disabling with a 400, so
  neither declares a toggle.

Also drops the header comment that claimed all six effort values were
reflected in reasoning_tokens: that holds for five models, not nine.

Costs are unchanged and re-verified against the live pricing endpoint.

* fix(modelis): move wire-path comments to a leading header block

Review finding: every declared control needs its exact request syntax in a
leading top-of-file comment, not an inline one next to the option.

I had put them inline because Modelis has no sync module, so nothing would
strip mid-file comments today. That was the wrong call: the sync rewrites
provider TOMLs by parsing and re-serializing them and keeps only a leading
header, so an inline comment is one sync module away from vanishing with
nobody noticing.

Each file now opens with the wire path for every control it declares.

* fix(modelis): narrow effort values to measured separable levels

Review finding: the six-value lists were the gateway's global accept-set
minus none, not per-model truth.

Re-measured at three task difficulties, asking which ADJACENT levels are
actually distinguishable (sample ranges that do not overlap):

- minimal collapses into low on every Claude model at every difficulty
  -> dropped from all three, as the lab baseline predicted.
- xhigh never rises above high on opus, sonnet or gemini-2.5-flash
  -> dropped there; kept on fable, where it does separate.
- gemini-2.5-flash keeps minimal: 37 vs 107 with zero scatter across
  three repeats.
- claude-fable-5 returns 145 reasoning tokens at reasoning_effort none,
  so it has no off switch at all and declares neither toggle nor none.

Per-file: opus/sonnet/gemini-2.5-pro low|medium|high|max, fable
low|medium|high|xhigh|max, gemini-2.5-flash minimal|low|medium|high|max.

DeepSeek and Qwen still declare no effort list: repeats at one setting
scatter up to 5x and the ordering inverts at medium on both DeepSeek
models. Numbers are in the PR discussion.

* fix(modelis): effort-none authored as effort; restore lab-baseline levels

Review findings:

1. Off via reasoning_effort "none" must be authored as effort with none
   in values, not as toggle. Both DeepSeek files had a toggle declaration
   whose own wire comment named the effort parameter -- self-contradicting.
   They now declare effort = [none, high, max] per the peer set.
   Qwen keeps toggle because there the mechanism really is a separate
   field: reasoning.enabled false -> 0, while reasoning_effort none
   leaves those models reasoning unchanged.

2. Dropping a level because adjacent reasoning_tokens ranges overlapped
   was the wrong test -- a level can differ in latency or quality without
   differing in thinking tokens. Reverted to the lab/peer baseline and
   restored xhigh on claude-opus-4-8.

minimal stays dropped on the Claude models: it is absent from the lab
baseline and returned output identical to low at every difficulty tested.
2026-08-02 10:57:31 -05:00
..