| 1 | # Adapter-owned reasoning controls |
| 2 | |
| 3 | Each protocol adapter registers a pure `ReasoningForConfig` resolver alongside |
| 4 | its provider factory. Its returned options are ordered IDs with display names and |
| 5 | optional descriptions. Core does not impose a global effort vocabulary. Resolved |
| 6 | clients expose a detached capability snapshot through `ReasoningProvider`. |
| 7 | |
| 8 | Configuration, the desktop effort menu, CLI completion, the local model catalog, |
| 9 | and request validation use these declarations. Model overrides must be resolved |
| 10 | before querying capabilities. Extension providers own their declared `Efforts` |
| 11 | list; selection and request overrides are validated before sidecar stream I/O. |
| 12 | |
| 13 | Explicit selections must match a declared ID exactly. Unsupported choices return |
| 14 | `UNSUPPORTED_REASONING_EFFORT` before network I/O. Missing capability metadata |
| 15 | returns `UNKNOWN_MODEL_REASONING` for an explicit choice, with recovery through |
| 16 | `auto` or a configured protocol/vocabulary. An empty list alone does not prove |
| 17 | that the model cannot think. Explicit `reasoning_protocol = "none"` declares |
| 18 | unsupported controls. Invalid declarations are also |
| 19 | rejected. No nearest-level mapping is performed. Binary protocols cannot acquire |
| 20 | a depth scale merely by listing depth values in `supported_efforts`. |
| 21 | |
| 22 | `auto` remains the existing UI/CLI spelling for clearing an override; it is not an |
| 23 | adapter option and does not mean adaptive thinking. Request-level overrides use |
| 24 | an empty string to inherit configuration, not the literal `auto`. Existing load |
| 25 | normalization of retired stored `off` and letter case is retained. Existing valid |
| 26 | IDs and TOML field names remain unchanged. Saved DeepSeek `medium` and `xhigh` |
| 27 | values retain their historical `high` wire value when no explicit effort vocabulary |
| 28 | is declared; configuration storage is not rewritten. New explicit selections and |
| 29 | request overrides still reject undeclared aliases. Other unsupported aliases |
| 30 | produce an actionable error. Invalid configured |
| 31 | defaults remain visible for validation instead of falling back to another level. |
| 32 | |
| 33 | | Boundary | Compatibility | |
| 34 | | --- | --- | |
| 35 | | Provider TOML | Existing fields and valid IDs remain readable; no load-time rewrite | |
| 36 | | Desktop `EffortInfo.options` | Optional additive metadata; `levels` remains for older clients | |
| 37 | | New frontend / older backend | Falls back to the older `levels` field | |
| 38 | | Remote model descriptors | Existing `Efforts` declarations remain authoritative | |
| 39 | | Provider-visible history | No prompt, tool schema, or reasoning-history rewrite | |
| 40 | |
| 41 | Default requests retain existing serialization. Explicitly changing an effort can |
| 42 | change provider cache behavior; the contract itself does not add prompt bytes. |
| 43 | The experimental governor checks declared capability before applying its low |
| 44 | request override. This change does not copy Harness's request journal architecture. |
| 45 | |
| 46 | `ResolveReasoningEntry` resolves model overrides, connection overrides, then |
| 47 | current built-in facts. Built-in defaults match the exact effective request URL, |
| 48 | API kind and model ID, including the Token Rhythm `deepseek-flash` alias; |
| 49 | renaming a connection does not change this match. An explicit different reasoning |
| 50 | protocol owns its vocabulary. UI metadata, startup validation and adapter |
| 51 | construction use the same resolved entry. Raw configuration retains only user |
| 52 | declarations, so inherited defaults follow catalog updates. Untagged historical |
| 53 | declarations remain explicit because their provenance cannot be recovered safely. |
| 54 | |
| 55 | Full configuration writes include backward-readable model capability snapshots. |
| 56 | The optional `reasoning_defaults` marker records generated fields and a digest of |
| 57 | the reasoning declaration. Current readers peel only untouched generated fields; |
| 58 | older readers still see the original protocol/list/default fields. A legacy |
| 59 | writer dropping the marker, or changing the declaration without updating its |
| 60 | digest, makes those values explicit. Settings delta saves preserve unrelated and |
| 61 | unknown fields without materializing unchanged inherited values. |
| 62 | |
| 63 | | Field or format | Old data | Current reader | Previous reader/writer | Result | |
| 64 | | --- | --- | --- | --- | --- | |
| 65 | | `reasoning_defaults` | Missing means explicit | Untouched marked fields inherit live defaults | Ignores marker; reads snapshot; marker loss preserves values as explicit | Downgrade remains readable | |
| 66 | | Model capability `reasoning.state` | Optional | `supported`, `unsupported`, or `unknown` | Ignores additive metadata | Older UI continues using its existing fields | |
| 67 | | Remote descriptor `ReasoningUnknown` | Missing means existing declaration semantics | Preserves unknown adapter metadata | Ignores additive flag | Existing `Efforts` remain valid | |
| 68 | | Session model/effort | Existing storage fields | Rebinds as one selection on model changes | Same persisted representation | No session migration | |
| 69 | |
| 70 | Session effort belongs to its provider/model identity. Model changes clear |
| 71 | inherited effort even when both models accept the same ID; same-model explicit |
| 72 | choices remain strict and are never silently clamped. New drafts only inherit |
| 73 | effort from the same model. Boot accepts an optional runtime-only `EffortModel` |
| 74 | origin for inherited overrides. CLI, Desktop, ACP and serve paths preserve this |
| 75 | boundary; `auto` remains available to clear an override with unknown metadata. |
| 76 | |
| 77 | The design is independently implemented for Reasonix, informed by |
| 78 | [DeepSeek Harness's adapter-owned reasoning contract](https://github.com/deepseek-ai/deepseek-harness/blob/d347e703908d0406b7a7ef80e3a0e594d86b2215/.agents/notes/implemented/architecture/2026-07-24-adapter-owned-reasoning-effort-capabilities.md). |
| 79 | No upstream implementation was copied. |
| 80 |