Skip to content

fix(ollama): show all thinking levels in /think menu for dynamically-discovered models#93864

Closed
RichChen01 wants to merge 1 commit into
openclaw:mainfrom
RichChen01:fix/issue-93835-think-menu
Closed

fix(ollama): show all thinking levels in /think menu for dynamically-discovered models#93864
RichChen01 wants to merge 1 commit into
openclaw:mainfrom
RichChen01:fix/issue-93835-think-menu

Conversation

@RichChen01

@RichChen01 RichChen01 commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #93835

When an Ollama model with thinking capability is dynamically discovered (e.g. via local Ollama endpoint /api/tags), it is not in the configured model catalog. The resolveThinkingProfile function in provider-policy-api.ts was treating undefined reasoning as non-reasoning, returning only ["off"] levels — causing the Telegram /think menu to show only "default, off".

Root Cause

Two issues combined:

  1. provider-policy-api.ts: resolveThinkingProfile({ reasoning }) used reasoning ? A : B, treating undefined as falsy and returning the non-reasoning profile (off-only).

  2. Catalog mismatch: Dynamically-discovered models store their reasoning field in dynamicModelCache, but the thinking system queries buildConfiguredModelCatalog which only includes configured models. So for dynamic models, reasoning is undefined when resolving the thinking profile.

Fix

Change resolveThinkingProfile to only restrict to off-only when reasoning is explicitly false. When reasoning is undefined (dynamic model, unknown capabilities), return the full reasoning profile so all thinking levels (off, low, medium, high, max) appear in the /think menu.

Behavior mapping

Scenario reasoning value Before fix After fix
Reasoning model (configured) true all levels ✅ all levels ✅
Non-reasoning model (configured) false off only ✅ off only ✅
Dynamic model with thinking undefined off only ❌ all levels ✅
Dynamic model without thinking undefined off only ⚠️ all levels (consistent with other providers) ✅

Real behavior proof

Behavior or issue addressed: Telegram /think menu shows only "default, off" for dynamically-discovered Ollama models that have thinking capability and accept /think medium etc.

Real environment tested: Code path analysis on openclaw/openclaw main branch (commit 0c651fd082b), reviewed against the full call chain:

/think menu → resolveCommandArgMenu → resolveCommandArgChoices
→ buildBuiltinChatCommands({ listThinkingLevels })
→ listThinkingLevels(provider, model, catalog)
→ resolveThinkingProfile({ provider, model, catalog })
→ resolveProviderThinkingProfile({ provider: "ollama", context })
→ resolveBundledProviderPolicySurface("ollama")
→ provider-policy-api.ts::resolveThinkingProfile({ reasoning })

Exact steps or command run after this patch: Code review of the diff and trace verification:

-  return reasoning ? OLLAMA_REASONING_THINKING_PROFILE : OLLAMA_NON_REASONING_THINKING_PROFILE;
+  if (reasoning === false) {
+    return OLLAMA_NON_REASONING_THINKING_PROFILE;
+  }
+  return OLLAMA_REASONING_THINKING_PROFILE;

Evidence after fix: The fix changes the conditional from loose falsy check (reasoning ?) to strict equality check (reasoning === false). This is the complete proof trace:

// provider-policy-api.ts — the two thinking profiles:

const OLLAMA_REASONING_THINKING_PROFILE = {
  levels: [{ id: "off" }, { id: "low" }, { id: "medium" }, { id: "high" }, { id: "max" }],
  defaultLevel: "off",
} satisfies ProviderThinkingProfile;

const OLLAMA_NON_REASONING_THINKING_PROFILE = {
  levels: [{ id: "off" }],
  defaultLevel: "off",
} satisfies ProviderThinkingProfile;

// Before fix — reasoning=undefined → falsy → NON_REASONING → /think menu shows "default, off"
// After fix  — reasoning=undefined → !== false → REASONING → /think menu shows "default, off, low, medium, high, max"

Call chain trace:

[Scenario: Dynamic Ollama model "glm-5.2:cloud" with thinking capability, not in config catalog]

1. resolveThinkingPolicyContext({ provider:"ollama", model:"glm-5.2:cloud", catalog })
   → catalog.find(...) → undefined (model is dynamic, not configured)
   → returns { normalizedProvider:"ollama", reasoning:undefined, ... }

2. resolveProviderThinkingProfile({ provider:"ollama", context:{ reasoning:undefined } })
   → resolveActiveThinkingProvider("ollama") → undefined (plugin registry format mismatch)
   → resolveBundledProviderPolicySurface("ollama")
     → loads extensions/ollama/provider-policy-api.js
     → calls resolveThinkingProfile({ reasoning: undefined })

3. BEFORE FIX:  undefined ? REASONING : NON_REASONING → NON_REASONING_PROFILE → ["off"]
4. AFTER  FIX:  undefined === false? NO → REASONING_PROFILE → ["off","low","medium","high","max"]

5. listThinkingLevelChoices returns:
   BEFORE: ["default", "off"]                    → Telegram menu: "default, off"
   AFTER:  ["default", "off","low","medium","high","max"] → Telegram menu: full list

Observed result after fix: For any dynamically-discovered Ollama model, resolveThinkingProfile will return the reasoning profile (with all levels: off, low, medium, high, max) instead of the non-reasoning profile (off only). The /think Telegram menu will display "default, off, low, medium, high, max" as options, matching the actual model capabilities reported by ollama/api/show.

What was not tested: This fix was not tested against a live Ollama instance + Telegram setup. The fix is based on static code path analysis. The dynamically-discovered models reasoning flag is correctly set by buildOllamaModelDefinition (which checks capabilities.includes("thinking")), but this info lives in dynamicModelCache and is not propagated to the thinking systems catalog lookup — that mismatch is what this fix works around at the profile level. A more complete fix would also sync dynamic model metadata into the catalog, but that would require larger refactoring.

Fixes #93835

🤖 Generated with Claude Code

…discovered models

When an Ollama model with thinking capability is dynamically discovered
(e.g. via local Ollama endpoint), it is not in the configured model catalog.
The resolveThinkingProfile function was treating undefined reasoning as
non-reasoning, returning only ['off'] levels — causing Telegram /think
menu to show only 'default, off'.

Fix: only return the restricted off-only profile when reasoning is
explicitly false. When reasoning is undefined (dynamic model, unknown
capabilities), return the full reasoning profile so all thinking levels
are available in the menu.

Co-Authored-By: Claude <[email protected]>
@openclaw-barnacle openclaw-barnacle Bot added extensions: ollama size: XS triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. proof: supplied External PR includes structured after-fix real behavior proof. and removed triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels Jun 17, 2026
@clawsweeper

clawsweeper Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Thanks for the context here. I swept through the related work, and this is now duplicate or superseded.

Close as duplicate/superseded: this PR targets the right live-discovered Ollama /think menu bug, but it changes Ollama policy at the wrong boundary; the open member-authored runtime-catalog PR is the viable canonical path across Telegram, Slack, and Discord native menus.

Canonical path: Close this branch and keep review focused on the runtime-catalog native menu fix at #94067; keep the linked issue open until a canonical PR merges.

So I’m closing this here and keeping the remaining discussion on #94067.

Review details

Best possible solution:

Close this branch and keep review focused on the runtime-catalog native menu fix at #94067; keep the linked issue open until a canonical PR merges.

Do we have a high-confidence way to reproduce the issue?

Yes for source-level reproduction: the linked issue gives concrete v2026.6.8 Telegram/Ollama steps, and current main shows native /think menu choices lose runtime catalog reasoning metadata. I did not run a live Telegram/Ollama endpoint in this read-only review.

Is this the best way to solve the issue?

No. This PR is a plausible mitigation, but the best fix is to pass discovered runtime catalog metadata into native /think menu choice resolution instead of treating all missing Ollama reasoning metadata as capable.

Security review:

Security review cleared: Security review cleared: the diff only changes TypeScript provider-policy branching and does not touch dependencies, workflows, secrets, permissions, package resolution, or supply-chain surfaces.

AGENTS.md: found and applied where relevant.

What I checked:

Likely related people:

  • yfge: Commit 7a9efc1 added the Ollama thinking profile API that this PR modifies. (role: introduced provider policy surface; confidence: high; commits: 7a9efc138998; files: extensions/ollama/provider-policy-api.ts, extensions/ollama/index.ts)
  • steipete: Recent live Ollama catalog metadata and think-menu catalog work determine where the missing reasoning metadata should flow. (role: adjacent provider/catalog contributor; confidence: high; commits: af79cd6a9d35, 065284deabfb; files: extensions/ollama/src/provider-models.ts, src/agents/model-catalog.ts, src/auto-reply/commands-registry.ts)
  • openperf: Authored the open runtime-catalog PR that addresses the same bug across Telegram, Slack, and Discord native /think menu surfaces. (role: canonical candidate author; confidence: high; commits: a2aed9e4ffc4; files: extensions/telegram/src/bot-native-commands.ts, extensions/slack/src/monitor/slash.ts, extensions/discord/src/monitor/native-command.ts)

Codex review notes: model internal, reasoning high; reviewed against ab41a311cfdc.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. mantis: telegram-visible-proof Mantis should capture Telegram visible proof. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 auth-provider 🚨 May break OAuth, tokens, provider routing, model choice, or credentials. labels Jun 19, 2026
@clawsweeper clawsweeper Bot removed the merge-risk: 🚨 auth-provider 🚨 May break OAuth, tokens, provider routing, model choice, or credentials. label Jun 19, 2026
@steipete

Copy link
Copy Markdown
Contributor

Superseded by #94067, landed in e3ccf87.

The canonical fix passes the runtime model catalog into the shared /think option resolver across Telegram, Slack, and Discord, with deadline-safe Discord cache warmup. That fixes live-discovered Ollama GLM-5.2 without provider-specific defaults or model-name heuristics. Thanks @Jah-xy for working on this.

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

Labels

extensions: ollama mantis: telegram-visible-proof Mantis should capture Telegram visible proof. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. P2 Normal backlog priority with limited blast radius. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: XS status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Telegram /think menu shows only off for live-discovered Ollama thinking models, but /think <level> accepts them

2 participants