Split canonical ReasoningEffort::Max out of Xhigh (providers P0c-1)

OpenAI (Responses) and Anthropic (Messages) treat xhigh and max as
DISTINCT effort levels in 2026, and the Kimi K3 wire's top tier is max —
the old parse alias (max→Xhigh) conflated them. Canonical Max now exists:
parse/as_str/serde split, Messages mapping sends xhigh and max as their
own tokens (was Xhigh→"max"), and the K3 menu token max carries
canonical Max end to end.

Kimi wire is byte-identical in all four flows (menu pick, restored
legacy xhigh session, --reasoning-effort flag, /effort command) —
adversarially traced and pinned: kimi_compat's string-level xhigh→max
rename covers legacy tokens, max passes through verbatim.

From the review:
- Rollback safety: persisted reasoning_effort (session summaries, chat
  history) deserializes leniently — unknown future tokens degrade to
  None with a warning instead of hiding sessions or failing resume.
- Restore migration: a pre-split xhigh override onto a model whose menu
  offers max but not xhigh (K3) migrates once, healing display/active-row
  drift and re-persisting the live vocabulary.
- /effort max now rejects (with the offered list) on models whose menu
  lacks a max row instead of silently applying xhigh; deliberate, tested.
- The interim Responses-backend Max→xhigh downgrade (async-openai has no
  Max variant through 0.41) warns loudly; real max wiring lands with the
  OpenAI provider cycle via post-serialize body patch.
- Two rusted ignored-e2e wire pins asserted the pre-adapt reasoning_effort
  key (deleted by the body adapter since ea0ce9d); they now pin the real
  thinking.effort=max shape.
This commit is contained in:
2026-07-21 02:36:37 -04:00
parent c5ddaec71e
commit 83e6935189
13 changed files with 276 additions and 37 deletions
+12 -2
View File
@@ -292,8 +292,9 @@ mod tests {
json!({ "type": "enabled", "effort": "high" })
);
// Canonical `xhigh` is spelled `max` on the Kimi wire (the K3
// valid_efforts vocabulary is low/high/max).
// Legacy canonical `xhigh` (pre-Max configs/sessions) is spelled
// `max` on the Kimi wire (the K3 valid_efforts vocabulary is
// low/high/max — there is no `xhigh` there).
let mut body = json!({ "model": "k3", "reasoning_effort": "xhigh" });
adapt_chat_completions_body(&mut body);
assert_eq!(
@@ -301,6 +302,15 @@ mod tests {
json!({ "type": "enabled", "effort": "max" })
);
// Canonical `max` (what the K3 menu token parses to since the
// ReasoningEffort::Max split) passes through unchanged.
let mut body = json!({ "model": "k3", "reasoning_effort": "max" });
adapt_chat_completions_body(&mut body);
assert_eq!(
body["thinking"],
json!({ "type": "enabled", "effort": "max" })
);
// kimi.py:218: "off" (our ReasoningEffort::None) → disabled, and no
// effort key (a disabled+effort combination would be contradictory).
let mut body = json!({ "reasoning_effort": "none" });