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

Closed

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

  1. lidge-jun commented on Aug 22, 2026

    @lidge-jun
    Owner

    리뷰 · 우선순위 58 / 80

    설명: 이 이슈는 로컬 Ollama 모델에 Codex 추론 강도(high, xhigh, max, ultra)를 보낼 때 업스트림이 500을 내고 Codex가 끝없이 재시도하는 구멍이다. 지금 CURRENT dev HEAD는 ced9a85c5 이다. 이 시간에 착지한 것은 문서뿐이다: #2348 WP4 감사(0 P0/P1, P2 두 개, 전체 스위트 14264 통과), #2349 GO 판정(코드 마지막은 여전히 #2346 Opus Fast 카탈로그). 이 이슈의 openai-chat 추론 와이어와 그 머지들은 파일이 겹치지 않는다. 현재 HEAD에서 레지스트리 src/providers/registry.ts 의 ollama 줄은 adapter openai-chat, baseUrl http://localhost:11434/v1 이고 reasoningEffortMap 이 없다. 요청 라벨을 와이어 값으로 바꾸는 곳은 src/reasoning-effort.ts mapReasoningEffort 한 함수다. ultra 는 먼저 max 로 바뀌고, modelReasoningEffortMap / reasoningEffortMap 에 키가 있으면 그 문자열을 그대로 돌려준다. 맵이 없으면 카탈로그 사다리로 클램프한다. 생략을 뜻하는 센티널은 없다. 어댑터 src/adapters/openai-chat.ts 는 mapReasoningEffort 결과가 undefined 일 때만 reasoning_effort 필드를 빼다. 값이 문자열이면 그대로 붙인다. 그래서 본문이 찍은 표가 코드와 맞다. ollama 0.32 는 와이어의 xhigh/ultra/max 를 템플릿에 주기 전에 max 로 접는다. 이 GGUF Jinja 는 xhigh/medium/low 만 받고, 맨 위 모드(xhigh)는 필드가 없을 때만 켜진다. high 를 보내면 템플릿이 high 를 보고 500. xhigh 를 보내면 ollama 가 max 로 바꿔서 또 500. 지금 설정으로 고칠 길이 없다. 맵은 값만 바꿀 수 있고, 바뀐 값도 결국 high 이상이거나 max 로 접힌다. noReasoningModels 는 모든 강도를 한꺼번에 빼서 low/medium 조절이 사라진다. clampToSupportedCodexEffort 는 Codex 사다리 안의 이야기라 이 500과 무관하다. 본문이 제안한 __omit__ 센티널은 openai-chat 에서 undefined 로 바꾸면 필드가 빠지는 현재 분기와 맞다. 다만 센티널 검사는 mapReasoningEffort 안에 두는 편이 맞다. 같은 맵을 쓰는 다른 어댑터도 같이 빠지게 하기 위해서다. 카탈로그 쪽 짝은 #2279(합성 max 숨기기)와 구현 PR #2280 이다. 그건 픽커에 가짜 max 를 넣을지이고, 이 이슈는 이미 고른 강도를 와이어에서 뺄지다. 한 PR로 묶지 않는다. Cursor #2334 CursorCredentialRouter 는 여전히 src/providers/cursor-pool.ts 모듈+테스트만 있고 어댑터에 연결되지 않았다. #2332 H2 풀은 discovery 전용, 종료 훅은 #2338. Run 은 자기 세션. #2320 overflow 매핑은 dev 에 있고 #2342 size prior 가 provably-small 만 429 로 좁힌다. 카탈로그 팁은 Ox Alpha x-preview-f-free + deepseek-v4-flash-vision-exp. #2346 으로 Cursor Opus Fast 패밀리가 추가됐지만 이 이슈와 무관하다. package.json 은 아직 2.27.0, 태그는 v2.29.0. 프리뷰 배포는 메인테이너 일이지 이 이슈의 일이 아니다. #2188 사이드카+routed vision 은 이미 dev. types.ts/config.ts 스플릿과 이 이슈의 첫 PR이 맵 키를 같이 만지면 리베이스하지 말고 닫고 다시 연다. 로컬 Ollama 가 500 재시도 루프에 빠지는 운영 구멍이라 58.

    src/reasoning-effort.ts mapReasoningEffort - 맵에 키가 있으면 문자열을 그대로 반환한다. 필드를 빼라는 값이 없다
    src/adapters/openai-chat.ts reasoningEffort === undefined 분기 - undefined 일 때만 와이어에서 뺀다. 맵이 max 나 high 를 주면 500이 난다
    src/types/provider.ts reasoningEffortMap / modelReasoningEffortMap - 값 타입이 string 뿐이라 생략을 표현할 자리가 스키마에 없다
    src/providers/registry.ts ollama 줄 - openai-chat 기본값만 있고 강도 맵이 없다. 레지스트리에 xhigh 생략을 기본으로 심지 말 것. 템플릿마다 다르다
    issue #2279 OPEN / PR #2280 - 카탈로그에 합성 max 를 넣을지. 이 이슈는 와이어 생략. 한 장에 묶지 말 것

    메인테이너의 판단이 필요한 지점

    • 센티널을 __omit__ 같은 문자열로 둘지, 빈 문자열/null 을 스키마에 허용할지
    • 변환을 mapReasoningEffort 한곳에서 할지, openai-chat 한줄 패치로 둘지
    • ollama 레지스트리에 기본 맵을 넣을지, 문서와 예시 설정만 둘지. 템플릿마다 최상위 모드가 다르다

    너의 추천
    이 이슈는 연다. 지금 Cursor round-3 / 릴리스 GO 문서 레인(#2349 GO, #2334 미연결 라우터)을 막거나 묶지 않는다. 첫 PR은 mapReasoningEffort 가 생략 센티널을 undefined 로 바꾸게 한다. openai-chat 은 지금처럼 undefined 면 필드를 뺀다. 카탈로그 사다리와 #2279/#2280 은 손대지 않는다. 계산은 맵에 센티널이 있는 강도만 뺀다. noReasoningModels 로 우회하라고 닫지 말 것. ollama 레지스트리 기본값으로 모든 모델의 high 이상을 빼지 말 것. 문서에 0.32 가 xhigh/ultra/max 를 max 로 접는다는 점만 적는다. types.ts/config.ts 스플릿이 맵 필드를 이미 옮긴 뒤에야 충돌이 보이면 리베이스하지 말고 닫고 다시 연다. 지금은 그 정도 아님. 라벨은 그대로 둔다. 프리뷰 배포가 아니다.

    이 댓글은 grok-bot이 작성했습니다

  2. added a commit that references this issue on Aug 22, 2026
    b4c0b94
  3. lidge-jun commented on Aug 22, 2026

    @lidge-jun
    Owner
  4. added a commit that references this issue on Aug 26, 2026
    a2d2ca4
  5. added 2 commits that reference this issue on Sep 17, 2026
    e204f2f
    9b9f8f0
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