Files
multica/server/pkg
Bohan Jiang c923ace620 fix(agent): let omp (Oh-My-Pi) agents set a thinking level (MUL-7412) (#8464)
Agents on the built-in omp (Oh-My-Pi) runtime could not set a reasoning effort at
all. omp dispatches to the pi backend but was missing from providerThinkingEnums,
so the server rejected every value, and parseOmpModels discarded omp's per-model
effort catalog, leaving the picker hidden and the daemon's guard nothing to
validate against. `--thinking` is blocked in custom_args by design, so the only
workaround was folding the level into the model string (`devin/swe-2:max`).

What a catalog entry means is taken from can1357/oh-my-pi v18.2.0 rather than
inferred from pi, because two of pi's rules are inverted for omp:

- `models --json` emits `thinking` as an effort array or `null`, never an object.
- omp's Effort vocabulary excludes `off`, yet resolveThinkingLevelForModel returns
  `off` before clamping runs, so it is honoured for every reasoning model.
- `reasoning: true` with `thinking: null` means "reasons, no controllable dial";
  inferring levels there would offer efforts omp then clamps away.

So a reasoning model advertises `off` plus exactly the efforts the catalog listed,
a non-reasoning model gets no picker, and nothing is inferred. `auto` is
deliberately not exposed: omp keeps it as a session-level sentinel that is never
an Effort or ThinkingLevel.

An effort with no pinned model is refused rather than stored, because omp resolves
its own default role model at task time and clamps the level to what that model
supports — so a stored level would save cleanly, read back as set, and then run at
a different level. The refusal holds in all three layers: the inspector hides the
picker, CreateAgent/UpdateAgent return 400 (Update against the state the request
lands on, so clearing the model while an effort is carried over is caught too),
and ValidateThinkingLevelWith rejects before any catalog load, so a discovery
error cannot reach the daemon's fail-open path.

codex shares that execution constraint but stays out of the API-level refusal via
a separate narrower predicate: agents already hold an effort with an empty model,
and 400ing that pair would block unrelated edits to them. omp has no such history.

Closes #8458
2026-09-16 12:14:09 +08:00
..