An effort the model had never heard of

Reported from a live instance, on Bonsai:

  Jinja Exception: Unexpected reasoning effort high. Supported types are
  xhigh (default), medium, and low.

Effort goes out two ways because no single field works, and the second --
chat_template_kwargs -- is not a parameter the server interprets. It is
rendered into the model's own chat template, which does not ignore a value it
does not know: it calls raise_exception, and the request dies before a token.
So a perfectly ordinary option, drawn by this application in its own menu, took
the whole reply with it.

The vocabulary is per model and nobody agrees. gpt-oss takes low/medium/high.
Bonsai takes low/medium/xhigh and refuses high. OpenAI has added minimal, xhigh
and max at different points, and which of them a given model accepts varies
again. One global tuple was going to be wrong for somebody whatever it held.

A model carries its own list now, and the picker, the slash command and the
request builder all read it. A column rather than a key in capabilities_json,
for the reason context_length is one: that dict is rebuilt wholesale from the
submitted checkboxes on every save.

And it corrects itself. A refusal retries the reply once without the effort
rather than losing it -- safe only because the template renders before any
token, so nothing has been emitted, and there is a guard that keeps it that way
-- then narrows the model's list. Bonsai's error states what it does take, so
that is what gets stored.

Note the parser bug, because it is a good one: "high" is a substring of
"xhigh", so reading the advertised list by substring learned `high` from a
sentence explaining that `high` is the problem. Whole words now, with a test
named after it.

/effort reads its levels off the picker instead of a second copy of the list
kept in the browser.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-25 21:20:06 +00:00
co-authored by Claude Opus 5
parent b7bf7d728b
commit 32e2326d41
10 changed files with 382 additions and 21 deletions
+24
View File
@@ -16,6 +16,30 @@ for 1.0.0 have something to be assembled from.
## Unreleased
## 1.2.0
- Fixed: **choosing a reasoning effort could kill the reply outright**, with a
Jinja traceback where the answer should have been. Reasoning effort is sent
two ways, and the second — `chat_template_kwargs` — is rendered into the
model's own chat template, which does not ignore a value it has never heard
of: it raises, and the whole request fails. The catch is that the vocabulary
is **not the same for every model**. gpt-oss takes `low/medium/high`; Bonsai
takes `low/medium/xhigh` and refuses `high`; OpenAI has added `minimal`,
`xhigh` and `max` at various points. This application offered the same three
to everything, so on some models the top setting was one the model would
throw for.
- **A model now has its own list of the efforts it accepts**, on its page under
Models, and the composer's picker and `/effort` offer only those. Tick none
and the familiar three are used, which is right for nearly everything.
- **And it corrects itself.** If an endpoint refuses an effort anyway — a model
swapped underneath a name, a runtime upgraded — that reply is retried once
without it instead of being lost, and the model's list is narrowed so the
menu stops offering something that does not work. Where the endpoint says
what it *does* take, that is what gets stored.
- `/effort` now reads the levels from the picker rather than from a second copy
of the list kept in the browser, so the two can no longer disagree about what
a valid effort is.
## 1.1.2
Two things a phone found that 1.1.0's phone pass had not.