Skip to content

fix(ollama): send think=false by default so hybrid-reasoning models actually stop thinking - #2103

Open
II-II-II-II wants to merge 1 commit into
Gitlawb:mainfrom
II-II-II-II:fix/ollama-think-not-sent
Open

II-II-II-II wants to merge 1 commit into
Gitlawb:mainfrom
II-II-II-II:fix/ollama-think-not-sent

Conversation

@II-II-II-II

@II-II-II-II II-II-II-II commented Aug 8, 2026

Copy link
Copy Markdown

I have read CONTRIBUTING.md and AGENTS.md.

What changed and why

buildOllamaChatBody() never set a top-level think field on outgoing Ollama requests. Ollama's hybrid-thinking models (e.g. Qwen3.x) interpret the field's absence as thinking enabled — so every Ollama request ran in thinking mode regardless of --effort, with no way to disable it. The existing client-side thinking filter only hides the trace from display; the model still generates the full reasoning chain either way, so the latency cost was paid whether or not it was visible.

This mirrors the effort-handling already implemented for the Anthropic/Gemini paths just above this function in the same file: no --effort specified → think: false; an explicit effort level is passed through (xhigh/max/ultracode collapse to Ollama's "high", matching its three-tier scale).

Impact

Any user running a hybrid-thinking model through the Ollama provider gets a working, silent-by-default non-thinking mode instead of an unremovable reasoning trace on every request.

Measured on qwen3.6:35b-a3b-coding (Apple Silicon, Ollama):

  • Before: 15-21s per trivial response, full visible reasoning trace every time
  • After: ~1.3s via the raw Ollama API with think=false, ~5s through the full CLI (Node startup + OpenAI↔Ollama format conversion overhead) — no reasoning trace in either case

Checks run

  • bun run typecheck — clean
  • bun run check — 21 pre-existing failures, confirmed present on unmodified main (same count before and after this change, all unrelated model-context-window tests, not touched by this diff)
  • bun run smoke — builds and runs cleanly

Provider path tested

Ollama only — this change is scoped to buildOllamaChatBody() and doesn't touch other providers.

No linked issue — searched open/closed issues and PRs first (including #1442/#1443, a related but different and unmerged proposal for adaptive thinking budgets); didn't find an existing report of this specific bug, so per CONTRIBUTING.md this is submitted as a small, self-explanatory fix.

Summary by CodeRabbit

  • New Features
    • Ollama chat requests now support reasoning effort settings.
    • High-effort modes are mapped appropriately, while unspecified reasoning defaults to disabled.

…ctually stop thinking

buildOllamaChatBody() never set a top-level `think` field on outgoing
requests. Ollama's hybrid-thinking models (e.g. Qwen3.x) interpret the
field's absence as thinking enabled, so every Ollama request ran in
thinking mode regardless of --effort, with no way to disable it. The
existing client-side thinking filter only hides the trace from display —
the model still generates the full reasoning chain either way, so the
latency cost was paid regardless of whether it was visible.

Mirrors the effort-handling already implemented for the Anthropic/Gemini
paths just above this function: no --effort specified maps to
think: false; an explicit effort level is passed through (xhigh/max/
ultracode collapse to Ollama's "high", matching its three-tier scale).

Measured on qwen3.6:35b-a3b-coding (Ollama, Apple Silicon):
- Before: 15-21s per trivial response, full visible reasoning trace
- After: ~1.3s via the raw Ollama API with think=false, ~5s through the
  full CLI (Node startup + OpenAI<->Ollama format conversion overhead)
- No visible reasoning trace in either case after the fix
@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The Ollama request planner now adds a think field to chat request bodies. It maps xhigh, max, and ultracode to high, preserves other effort values, and defaults to false when reasoning effort is absent.

Changes

Ollama thinking control

Layer / File(s) Summary
Map reasoning effort to the Ollama request
src/services/api/openaiShim/requestPlanner.ts
buildOllamaChatBody now derives the think field from request.reasoning.effort and includes it in the generated request body.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: jatmn

🚥 Pre-merge checks | ✅ 7
✅ Passed checks (7 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise, scoped to Ollama, and accurately describes the default think=false behavior in the diff.
Description check ✅ Passed The description explains the change and rationale, impact, testing results, provider scope, and known unrelated failures.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Risk Surface Disclosed ✅ Passed The PR identifies the outgoing Ollama payload and its latency/model impact; the review explicitly flags missing native Ollama assertions as a before-merge blocker.
No Hidden Policy Change ✅ Passed The sole changed hunk adds an explicit, documented think payload field only for native Ollama requests; no routing, trust, permission, telemetry, or unrelated network policy code changed.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/services/api/openaiShim/requestPlanner.ts`:
- Around line 433-444: Update the native Ollama assertions in the request
planner tests to include think: false for absent reasoning effort, then add
focused cases covering preserved effort values and mapping xhigh, max, and
ultracode to high. Anchor the cases to the request-planning test flow exercising
the think value derived from request.reasoning.effort.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 5f4e8926-b041-4bfc-9501-e803f9be0cd0

📥 Commits

Reviewing files that changed from the base of the PR and between 41d2f3b and ad20de6.

📒 Files selected for processing (1)
  • src/services/api/openaiShim/requestPlanner.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript strict mode and ESM imports throughout the source code.

Run bun run typecheck and bun run typecheck:type-tests for TypeScript changes when applicable.

Files:

  • src/services/api/openaiShim/requestPlanner.ts
**/*.{tsx,ts}

📄 CodeRabbit inference engine (AGENTS.md)

Use React and Ink patterns for terminal UI components.

Files:

  • src/services/api/openaiShim/requestPlanner.ts
src/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.ts: Prefer existing service, provider, settings, permission, and UI patterns over introducing new abstractions.
Use chalk for terminal color and execa for child-process execution when those capabilities are needed.

Files:

  • src/services/api/openaiShim/requestPlanner.ts
src/services/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Use existing service and provider integration patterns when implementing API, MCP, OAuth, wiki, voice, or related integrations.

Files:

  • src/services/api/openaiShim/requestPlanner.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Do not add new Python code, Python provider paths, or Python dependencies without explicit maintainer approval.

**/*.{ts,tsx,js,jsx}: Follow the existing code style in touched source files, prefer small readable changes, avoid unrelated reformatting, and keep comments useful and concise.
Preserve existing repository patterns unless intentionally refactoring them, and avoid broad rewrites or unnecessary generated changes.
Review AI-assisted code for correctness, style consistency, unnecessary changes, and adherence to project architecture before submitting it.

Files:

  • src/services/api/openaiShim/requestPlanner.ts
**/*

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Update documentation when setup, commands, or user-facing behavior changes.

Files:

  • src/services/api/openaiShim/requestPlanner.ts

⚙️ CodeRabbit configuration file

**/*: Apply the OpenClaude maintainer review rubric from AGENTS.md. Review the current diff, not stale discussion context. Separate real blockers from suggestions. Do not request changes for vague style churn. Treat approval as merge-ready from CodeRabbit's side, pending required human review and GitHub Checks. If checks are failing or unavailable, say so clearly instead of implying the PR is fully ready.

Files:

  • src/services/api/openaiShim/requestPlanner.ts
{src/services/api/**,src/integrations/**,src/utils/model/**,src/utils/provider*.ts,src/commands/provider/**}

⚙️ CodeRabbit configuration file

{src/services/api/**,src/integrations/**,src/utils/model/**,src/utils/provider*.ts,src/commands/provider/**}: Review provider routing, model selection, env precedence, auth/token handling, OpenAI-compatible shims, retries, proxy behavior, and outbound HTTP behavior with high scrutiny. Block on silent default changes, hidden fallback expansion, credential reuse mistakes, hardcoded provider assumptions, or new network reach that is not intentional and documented.

Files:

  • src/services/api/openaiShim/requestPlanner.ts

Comment on lines +433 to +444
const think: boolean | string = request.reasoning?.effort
? ['xhigh', 'max', 'ultracode'].includes(request.reasoning.effort)
? 'high'
: request.reasoning.effort
: false

return {
model: request.resolvedModel,
messages: normalizeOllamaNativeMessages(body.messages),
stream: params.stream ?? false,
options,
think,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Update the native Ollama test contract before merge.

The exact-body assertion in src/services/api/openaiShim/requestPlanner.test.ts, Lines 307-341, omits think. The no-effort case now returns think: false, so that assertion will fail. Update it and add focused cases for preserved effort values and xhigh, max, and ultracode mapping to 'high'.

As per path instructions, AGENTS.md requires focused tests covering absent effort (false), preserved effort values, and xhigh/max/ultracode mapping to high.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/services/api/openaiShim/requestPlanner.ts` around lines 433 - 444, Update
the native Ollama assertions in the request planner tests to include think:
false for absent reasoning effort, then add focused cases covering preserved
effort values and mapping xhigh, max, and ultracode to high. Anchor the cases to
the request-planning test flow exercising the think value derived from
request.reasoning.effort.

Source: Path instructions

@jatmn jatmn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found issues that need to be addressed before this is ready.

Findings

  • [P1] Restore the native-Ollama planner test and cover the new contract
    src/services/api/openaiShim/requestPlanner.test.ts:330
    The only exact-payload assertion for this path still expects no think key, while this PR now always serializes think: false. bun test src/services/api/openaiShim/requestPlanner.test.ts fails deterministically (11 passing, 1 failing) with that extra key. This is also the unresolved CodeRabbit request: update the default assertion and add focused cases for the preserved levels and the normalized levels before this can be merged.

  • [P1] Wire native Ollama into the effort-control path instead of always disabling it
    src/services/api/openaiShim/requestPlanner.ts:433
    The planner reads request.reasoning?.effort, but getAnthropicClient() only supplies that override when modelSupportsShimReasoningEffort() is true. The Ollama route has no controllable reasoning metadata, so ordinary discovered models (including the Qwen3-style models this PR targets) fail that gate and arrive here with no effort. Consequently /effort high / --effort high still emits think: false rather than enabling or selecting thinking, which contradicts the PR's stated behavior. Add an Ollama-specific controllable capability/serialization route and an end-to-end captured-request test.

  • [P1] Preserve an explicit ?thinking=enabled request
    src/services/api/openaiShim/requestPlanner.ts:433
    resolveProviderRequest() preserves ?thinking=enabled as request.thinking, but this new branch ignores it and falls back to false whenever no effort is present. A native-Ollama user who selects --model 'qwen3?thinking=enabled' is therefore forcibly switched from the requested enabled mode to disabled. Resolve the explicit thinking state before applying the default; the native API accepts boolean think values.

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.

2 participants