Skip to content

ollama ≥0.32: high reasoning efforts 500 in GGUF chat template — need a per-effort way to omit reasoning_effort on the wire #2356

Description

@mdwsk88

Area

Providers / reasoning-effort mapping (openai-chat adapter, ollama provider)

What are you trying to accomplish?

Route Codex (global model_reasoning_effort = "ultra", so requests carry effort max) to a local ollama model: hf.co/JonathanColetti/Qwen3.8-27B-Uncensored-GGUF:Q4_K_M (27B Q4_K_M GGUF with an embedded Jinja chat template). The template validates reasoning_effort against exactly xhigh/medium/low and — crucially — its top mode is only selected when the field is absent:

{%- set resolved_reasoning_effort = reasoning_effort|default('xhigh') %}
{%- if resolved_reasoning_effort not in ('xhigh', 'medium', 'low') %}
    {{- raise_exception('Unexpected reasoning effort ' ~ reasoning_effort ~ ...) }}
{%- endif %}

I want a working ladder: low/medium for fast turns, deep thinking (template xhigh) for high/xhigh/max/ultra.

What prevents this today?

1. Default behavior is a hard 500 retry loop. With the stock ollama provider config (adapter: openai-chat, baseUrl: http://localhost:11434/v1) the requested effort is forwarded as-is. ollama returns 500 and Codex retries indefinitely (usage.jsonl):

{"requestedModel":"ollama/qwen3.8-uncensored:27b-q4","requestedEffort":"max","effectiveEffort":"max",
 "reasoningWireValue":"max","status":500,"errorCode":"upstream_server_error",
 "upstreamError":"Provider error 500: ... Jinja Exception: Unexpected reasoning effort max. Supported types are xhigh (default), medium, and low."}

2. ollama ≥0.32 normalizes effort values before template rendering, so even ladder-correct values fail. Empirically verified on ollama 0.32.15 (probing which template instruction the model actually received):

wire value sent to ollama /v1/chat/completions value the template sees result
(field omitted) default xhigh ✅ deep mode
minimal low
low low
medium medium
high high ❌ 500
xhigh, ultra, max max (normalized by ollama) ❌ 500
none thinking disabled

So the template's xhigh mode is unreachable through any wire value — only by omitting reasoning_effort entirely.

3. No existing config can express per-effort omission.

  • modelReasoningEffortMap can only rewrite values; every reachable wire value ≥ high is rejected upstream.
  • noReasoningModels omits the field for all efforts, losing low/medium control.
  • clampToSupportedCodexEffort cannot help either: the failure is on the wire, not in the Codex ladder.

What should OpenCodex do?

Support per-effort omission. Minimal change: treat a sentinel wire value (e.g. "__omit__") in reasoningEffortMap/modelReasoningEffortMap as "drop reasoning_effort from the body". Verified locally against 2.29.0 with this one-line patch in src/adapters/openai-chat.ts:

const rawReasoningEffort = mapReasoningEffort(provider, parsed.modelId, parsed.options.reasoning);
const reasoningEffort = rawReasoningEffort === "__omit__" ? undefined : rawReasoningEffort;

with provider config:

"ollama": {
  "adapter": "openai-chat",
  "baseUrl": "http://localhost:11434/v1",
  "modelReasoningEfforts": {
    "qwen3.8-uncensored:27b-q4": ["low", "medium", "high", "xhigh", "max"]
  },
  "modelReasoningEffortMap": {
    "qwen3.8-uncensored:27b-q4": {
      "low": "low", "medium": "medium",
      "high": "__omit__", "xhigh": "__omit__", "max": "__omit__"
    }
  }
}

Verified end-to-end through the proxy: max → HTTP 200 with the model confirming the template's xhigh instruction; low → HTTP 200 with the low instruction.

Optionally, also document (or registry-default for the ollama provider) that xhigh is never a safe wire value under ollama ≥0.32, since ollama collapses xhigh/ultra/max to max before the template sees it.

Alternatives or workarounds

  • Patching the installed source (what I run today) — upgrade-fragile, same concern raised in Feature: suppress synthetic max per model while retaining ultra #2279.
  • noReasoningModels — works but forces deep mode for every turn and removes effort control.
  • Editing the model's embedded GGUF template is not viable via Modelfile: ollama create parses TEMPLATE as a Go template and rejects this Jinja (template error: function "content" not defined).

Environment

  • opencodex 2.29.0 (@bitkyc08/opencodex on npm), service mode on Windows 11 x64
  • Codex desktop 26.818.41509 (model catalog client 0.146.0)
  • ollama 0.32.15

Related: #1870, #2279 (catalog-layer synthetic rungs). This is the wire-layer counterpart: even with an exact catalog ladder, requests still need per-effort field omission for templates like this one.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions