Skip to content

fix: resolve ollama thinking support per model before sending reasoning_effort - #6053

Merged
atomantic merged 1 commit into
mainfrom
claim/issue-6050
Sep 3, 2026
Merged

fix: resolve ollama thinking support per model before sending reasoning_effort#6053
atomantic merged 1 commit into
mainfrom
claim/issue-6050

Conversation

@atomantic

Copy link
Copy Markdown
Owner

Summary

A local reviewer pinned to ollama[<non-thinking model>]~effort=low sent reasoning_effort on its first request. Ollama translates that field into its own thinking parameter and hard-rejects the whole request with a 400 for a model that does not advertise thinking support.

PR #5960 added a reactive recovery (retry without the field), but the "this model has no thinking" memo lives in a process-local Map — and every reviewer invocation from a claim/PR run is its own short-lived node process. So the cache never survived to the next call, and every review re-uploaded the entire diff twice: once for a request that could never succeed.

Ollama's /api/show reports the capability set per model, and PortOS already reads it (ollamaManager.getModelCapabilities, cached). This resolves it before the request and omits reasoning_effort for a model lacking thinking, so the doomed request is never sent. The 400-retry stays as the fail-safe for a backend with no such probe (LM Studio, MTPLX) and for a probe that cannot answer.

Sentinel handling follows the repo's absent-vs-empty rule: null (probe failed) and [] (daemon answered reporting no capabilities) both mean unknown, not unsupported, so both fall through to the request rather than silently stripping a level a reasoning model does accept.

The probe is skipped entirely when no effort is pinned — nothing to drop, so a capability round-trip buys nothing. That also stops effortUnsupported: true being reported when the caller never asked for a level.

The runLocalCodeReview doc comment now states the omission is decided per model, not per backend, matching the behavior (this was called out in the issue as the contract the implementation had drifted from).

Test plan

  • server/services/codeReview.test.js — 6 new cases pinning the body shape both ways and the fall-through paths:
    • reasoning_effort absent on the first request when /api/show omits thinking (fails on main, passes here — one fetch, not two)
    • reasoning_effort present when /api/show reports thinking
    • [] capabilities treated as unknown → level still sent
    • probe unable to answer → reactive 400-retry still recovers
    • no effort pinned → no probe, no effortUnsupported flag
    • non-ollama backend → not probed, level still sent
  • Full server suite green: 1896 files / 38311 tests passed, 1 file + 14 tests skipped.
  • Verified end-to-end against the live ollama daemon with the exact model that reproduced the bug: previously ok:false with 400 ... does not support thinking; now ok:true with findings and no retry warning, confirming the first request was already correct.

Closes #6050

…ng_effort (#6050)

A reviewer pinned to `ollama[<non-thinking model>]~effort=low` sent
`reasoning_effort` on its first request, which ollama translates into its
`thinking` parameter and hard-rejects with a 400 for a model that does not
advertise thinking support. The existing recovery retried without the field,
but only reactively: the "this model has no thinking" memo lives in a
process-local Map, and every reviewer invocation from a claim or PR run is
its own short-lived `node` process — so each review call re-uploaded the
entire diff twice, once for a request that could never succeed.

Ollama's `/api/show` reports the capability set per model, and PortOS already
reads it (`ollamaManager.getModelCapabilities`, cached). Consult it before the
request and omit `reasoning_effort` for a model that lacks `thinking`, so the
doomed request is never sent. The 400-retry stays as the fail-safe for a
backend with no such probe (LM Studio, MTPLX) and for a probe that cannot
answer.

`null` (probe failed) and `[]` (daemon answered with no capabilities) both mean
*unknown*, not *unsupported* — collapsing them would silently strip a level a
reasoning model does accept, so both fall through to the request. The probe is
also skipped entirely when no effort is pinned, since there is nothing to drop;
that also stops `effortUnsupported` being reported when the caller never asked
for a level. The `runLocalCodeReview` doc comment now says the omission is
decided per model, matching the behavior.

Closes #6050
@atomantic
atomantic merged commit e533f78 into main Sep 3, 2026
7 checks passed
@atomantic
atomantic deleted the claim/issue-6050 branch September 3, 2026 07:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Local reviewer sends reasoning_effort to every ollama model, 400-ing on models without thinking support

1 participant