Skip to content

fix: omit think parameter for Ollama models without thinking support#67958

Closed
Linux2010 wants to merge 4 commits into
openclaw:mainfrom
Linux2010:fix/issue-67949
Closed

fix: omit think parameter for Ollama models without thinking support#67958
Linux2010 wants to merge 4 commits into
openclaw:mainfrom
Linux2010:fix/issue-67949

Conversation

@Linux2010

Copy link
Copy Markdown
Contributor

Summary

OpenClaw was sending a think parameter to Ollama for all models when thinkingLevel was set, but some smaller models like qwen2.5:0.5b do not support thinking mode, causing a 400 error.

Root Cause

The createConfiguredOllamaCompatStreamWrapper function was unconditionally adding a think parameter when ctx.thinkingLevel was set, but models without thinking capabilities reject this parameter entirely.

Changes

  • Import isReasoningModelHeuristic to detect models that support thinking
  • Check supportsThinking before applying the think wrapper
  • Only send think parameter for reasoning models (r1, reasoning, think patterns)
  • Updated tests for reasoning and non-reasoning models

Fixes #67949

@aisle-research-bot

aisle-research-bot Bot commented Apr 17, 2026

Copy link
Copy Markdown

🔒 Aisle Security Analysis

We found 2 potential security issue(s) in this PR:

# Severity Title
1 🟠 High Untrusted workspace plugin manifests can inject arbitrary env var names into API key resolution (potential secret exfiltration)
2 🟡 Medium Potential chain-of-thought disclosure via Ollama think parameter enabled by heuristic model matching
1. 🟠 Untrusted workspace plugin manifests can inject arbitrary env var names into API key resolution (potential secret exfiltration)
Property Value
Severity High
CWE CWE-200
Location src/secrets/provider-env-vars.ts:45-53

Description

resolveEnvApiKey() uses provider env var candidates sourced from plugin manifests. By default, workspace plugins are treated as eligible sources unless includeUntrustedWorkspacePlugins is explicitly set to false.

This allows an attacker-controlled workspace plugin (e.g., in an untrusted repo) to declare providerAuthEnvVars containing arbitrary environment variable names (AWS/GCP/CI secrets, etc.) for a provider id that the user later selects. The auth resolution path will then read those env vars and treat their values as the provider API key.

Impact:

  • Secret values from the host environment can be read by the CLI
  • Those secrets may then be sent off-host as model-provider credentials when used to authenticate outbound requests (the resolved value becomes the provider "apiKey")

Vulnerable logic:

  • Workspace plugin gating defaults to allowing untrusted workspace plugins
  • No allowlist/validation is applied to providerAuthEnvVars keys (env var names)

Vulnerable code:

if (plugin.origin !== "workspace" || params?.includeUntrustedWorkspacePlugins !== false) {
  return true;
}
return isWorkspacePluginTrustedForProviderEnvVars(plugin, params?.config);

Recommendation

Treat workspace plugin manifests as untrusted by default for env-var candidate harvesting, and/or strictly constrain which env vars can be declared.

Recommended changes:

  1. Change the default to exclude untrusted workspace plugins unless explicitly opted-in.
  2. Add validation/allowlisting for env var names (e.g., must match a provider-specific allowlist or a safe prefix list), and reject/ignore unexpected keys.

Example default-deny fix:

function shouldUsePluginProviderEnvVars(
  plugin: PluginManifestRecord,
  params: ProviderEnvVarLookupParams | undefined,
): boolean {
  if (plugin.origin !== "workspace") return true;// Default: do NOT trust workspace plugins for env var harvesting
  if (params?.includeUntrustedWorkspacePlugins !== true) {
    return isWorkspacePluginTrustedForProviderEnvVars(plugin, params?.config);
  }

  return true;
}

Then ensure all call sites that should consider workspace plugins pass includeUntrustedWorkspacePlugins: true explicitly, and only in trusted contexts.

2. 🟡 Potential chain-of-thought disclosure via Ollama `think` parameter enabled by heuristic model matching
Property Value
Severity Medium
CWE CWE-200
Location extensions/ollama/src/stream.ts:205-217

Description

The Ollama streaming wrapper enables the native Ollama think parameter based on a regex heuristic of the model id and/or model.reasoning === true. When enabled (think=true), Ollama may return separate message.thinking / message.reasoning fields containing chain-of-thought.

In this codebase, those thinking deltas are turned into thinking_* stream events and are also assembled into assistant message content as { type: "thinking" }. Downstream components (e.g., embedded subscribe handler) append these events to a raw stream log, which can lead to persistence/exposure of internal reasoning (which may include system prompt or other sensitive context) beyond what a user expects.

Key factors introduced/expanded by this change:

  • isReasoningModelHeuristic() was broadened to match additional model families (e.g., qwen3, qwq).
  • createConfiguredOllamaCompatStreamWrapper() now sets payloadRecord.think = true/false whenever supportsThinking matches and thinkingLevel is set, expanding the set of models that will emit thinking content.

Vulnerable change site:

  • The heuristic-based enablement of think is not gated by an explicit user opt-in for chain-of-thought persistence/exposure; it is enough that a model id matches the regex and thinkingLevel is configured.

Vulnerable code:

const supportsThinking = isReasoningModelHeuristic(ctx.modelId) || ctx.model?.reasoning === true;

if (supportsThinking && ctx.thinkingLevel === "off") {
  streamFn = createOllamaThinkingWrapper(streamFn, false);
} else if (supportsThinking && ctx.thinkingLevel) {
  streamFn = createOllamaThinkingWrapper(streamFn, true);
}

Recommendation

Treat chain-of-thought (“thinking”) as sensitive and do not enable it based on a loose model-id regex.

Recommended fixes (pick one or combine):

  1. Require explicit opt-in (e.g., model.reasoning === true only) and remove/disable the heuristic path:
const supportsThinking = ctx.model?.reasoning === true;
  1. If a heuristic must remain, default to think=false and only set think=true when the user explicitly requests reasoning streaming and agrees to persist/display it.

  2. Ensure thinking content is not logged/persisted by default. For example, omit thinking_* events from raw stream logs unless a secure debug flag is enabled, and/or redact thinking content before storage.

  3. Add a safety filter to prevent accidental exposure: if ctx.thinkingLevel === "off", also ensure any returned message.thinking is discarded before emitting events/messages.


Analyzed PR: #67958 at commit 82ab888

Last updated on: 2026-04-22T13:26:45Z

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 434068aed7

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread extensions/ollama/src/stream.ts Outdated
Comment on lines +208 to +212
const supportsThinking = isReasoningModelHeuristic(ctx.modelId);

if (supportsThinking && ctx.thinkingLevel === "off") {
streamFn = createOllamaThinkingWrapper(streamFn, false);
} else if (ctx.thinkingLevel) {
} else if (supportsThinking && ctx.thinkingLevel) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Gate think injection by capability, not name regex

This new gate uses isReasoningModelHeuristic(ctx.modelId) as the sole signal for thinking support, which excludes thinking-capable Ollama models whose IDs do not match r1|reasoning|think|reason (for example qwen3:*, which the plugin already treats as having "thinking" capability from /api/show). In those cases, thinkingLevel is now silently ignored because neither think=false nor think=true is added, so users lose control over native thinking mode on supported models.

Useful? React with 👍 / 👎.

@greptile-apps

greptile-apps Bot commented Apr 17, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a 400 error that occurred when OpenClaw sent the think parameter to Ollama models that don't support thinking mode (e.g. qwen2.5:0.5b). The fix gates the think parameter behind isReasoningModelHeuristic, which was already used for the catalog reasoning field, making the stream wrapper consistent with the existing model catalog behavior.

  • The regex /r1|reasoning|think|reason/i in isReasoningModelHeuristic does not match qwen3:* or qwq:* model families, which do support the Ollama think parameter. Users with those models and a non-undefined thinkingLevel would silently lose thinking mode after this change. Extending the heuristic to include these families would close that gap.

Confidence Score: 4/5

Safe to merge for the reported bug; the narrow heuristic may silently regress qwen3/qwq thinking-mode users.

The fix correctly solves the 400-error regression for non-thinking models and the tests are well-structured. Score is 4 rather than 5 because the heuristic regex misses qwen3 and qwq Ollama model families that support thinking, which is a silent behavior regression relative to the pre-PR behavior for those users.

extensions/ollama/src/provider-models.ts — isReasoningModelHeuristic regex coverage

Prompt To Fix All With AI
This is a comment left during a code review.
Path: extensions/ollama/src/stream.ts
Line: 208

Comment:
**Heuristic may miss Qwen3 thinking models**

The regex `/r1|reasoning|think|reason/i` will return `false` for `qwen3:8b`, `qwen3:32b`, and `qwq:32b`, all of which support the `think` parameter in Ollama. Before this PR, those models would have received the `think` parameter because the guard didn't exist; after this PR they won't, silently disabling thinking for users with those models set to a non-`undefined` `thinkingLevel`.

The same heuristic already governs the catalog `reasoning` field (in `buildOllamaModelDefinition`), so this inconsistency pre-dates the PR — but adding `qwen3` (and possibly `qwq`) to the pattern here would avoid the regression. Consider updating `isReasoningModelHeuristic` itself to include `qwen3|qwq` so the catalog and stream wrapper stay aligned.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "fix: omit think parameter for Ollama mod..." | Re-trigger Greptile

Comment thread extensions/ollama/src/stream.ts Outdated
// Only apply the think parameter for models that are known to support thinking.
// Models like qwen2.5:0.5b don't support the think parameter at all and will
// return a 400 error if the parameter is sent (even with think=false).
const supportsThinking = isReasoningModelHeuristic(ctx.modelId);

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.

P2 Heuristic may miss Qwen3 thinking models

The regex /r1|reasoning|think|reason/i will return false for qwen3:8b, qwen3:32b, and qwq:32b, all of which support the think parameter in Ollama. Before this PR, those models would have received the think parameter because the guard didn't exist; after this PR they won't, silently disabling thinking for users with those models set to a non-undefined thinkingLevel.

The same heuristic already governs the catalog reasoning field (in buildOllamaModelDefinition), so this inconsistency pre-dates the PR — but adding qwen3 (and possibly qwq) to the pattern here would avoid the regression. Consider updating isReasoningModelHeuristic itself to include qwen3|qwq so the catalog and stream wrapper stay aligned.

Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/ollama/src/stream.ts
Line: 208

Comment:
**Heuristic may miss Qwen3 thinking models**

The regex `/r1|reasoning|think|reason/i` will return `false` for `qwen3:8b`, `qwen3:32b`, and `qwq:32b`, all of which support the `think` parameter in Ollama. Before this PR, those models would have received the `think` parameter because the guard didn't exist; after this PR they won't, silently disabling thinking for users with those models set to a non-`undefined` `thinkingLevel`.

The same heuristic already governs the catalog `reasoning` field (in `buildOllamaModelDefinition`), so this inconsistency pre-dates the PR — but adding `qwen3` (and possibly `qwq`) to the pattern here would avoid the regression. Consider updating `isReasoningModelHeuristic` itself to include `qwen3|qwq` so the catalog and stream wrapper stay aligned.

How can I resolve this? If you propose a fix, please make it concise.

Linux2010 pushed a commit to Linux2010/openclaw that referenced this pull request Apr 17, 2026
Addresses review feedback from Codex/Greptile/Aisle on PR openclaw#67958
@Linux2010 Linux2010 requested a review from a team as a code owner April 17, 2026 08:02
@openclaw-barnacle openclaw-barnacle Bot added the agents Agent runtime and tooling label Apr 17, 2026
@Linux2010

Copy link
Copy Markdown
Contributor Author

Updated isReasoningModelHeuristic regex to include qwen3|qwq patterns, addressing the feedback from Codex P1, Greptile P2, and Aisle Medium. This ensures all known thinking-capable Ollama model families receive proper think parameter handling.

Changes:

  • Regex updated from /r1|reasoning|think|reason/i to /r1|reasoning|think|reason|qwen3|qwq/i

Commit: 0fa01fa

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0fa01fa849

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread extensions/ollama/src/stream.ts Outdated
Comment on lines +208 to +212
const supportsThinking = isReasoningModelHeuristic(ctx.modelId);

if (supportsThinking && ctx.thinkingLevel === "off") {
streamFn = createOllamaThinkingWrapper(streamFn, false);
} else if (ctx.thinkingLevel) {
} else if (supportsThinking && ctx.thinkingLevel) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Gate think injection by capability instead of name heuristic

createConfiguredOllamaCompatStreamWrapper now ignores thinkingLevel unless ctx.modelId matches a regex, so thinking-capable models with non-matching IDs silently lose think control. Fresh evidence in this commit: Ollama discovery already captures capabilities from /api/show (including "thinking") for models like glm-5.1:cloud, but this gate only checks isReasoningModelHeuristic(ctx.modelId), which does not match that ID. In those cases thinkingLevel is dropped and neither think=true nor think=false is sent.

Useful? React with 👍 / 👎.

Developer and others added 4 commits April 22, 2026 13:24
…y resolution

The PROVIDER_ENV_API_KEY_CANDIDATES export was calling
resolveProviderEnvApiKeyCandidates() at module load time,
which triggered loadPluginManifestRegistry() before bundled
plugins were fully available. This caused OpenRouter and other
bundled provider auth env vars to be missing from the candidate
map at startup.

Fixes openclaw#67989: OpenRouter provider not routing requests to models

The fix delegates to the existing lazy PROVIDER_AUTH_ENV_VAR_CANDIDATES
proxy from provider-env-vars.ts, which defers manifest registry
loading until first property access. This ensures bundled plugin
metadata (including providerAuthEnvVars from manifests like
OpenRouter's) is available when needed.

Tests added to verify:
- openrouter env var resolution works
- lazy loading behavior is preserved
Addresses review feedback from Codex/Greptile/Aisle on PR openclaw#67958
Codex P2: isReasoningModelHeuristic alone misses models with
explicit reasoning:true config. Also check ctx.model.reasoning.

Refs: openclaw#67958
@clawsweeper

clawsweeper Bot commented Apr 26, 2026

Copy link
Copy Markdown
Contributor

Closing this as implemented after Codex automated review.

PR #67958 is obsolete for its linked Ollama bug. Current main and v2026.4.24 already address the reported qwen2.5 failure path by defaulting embedded runs to thinking off and forwarding native Ollama thinking control as top-level think:false for off and think:true only for explicit non-off thinking. The PR's heuristic-gated omit approach is not the best current path, and the branch also contains unrelated env-var changes.

Best possible solution:

Close this PR as implemented/obsolete for #67949. Keep the shipped v2026.4.24 native Ollama top-level think mapping, and handle any future capability-aware thinking validation in a fresh narrow PR against the Ollama provider metadata/profile path without unrelated env-var changes.

What I checked:

  • default-thinking-off: Embedded runs initialize initialThinkLevel as params.thinkLevel ?? "off", so plain infer/web runs no longer implicitly enable native Ollama thinking for small local models. (src/agents/pi-embedded-runner/run.ts:504, d54d2d6b9b8a)
  • native-ollama-think-mapping: The current Ollama stream wrapper applies top-level think:false only for native Ollama transport with thinkingLevel === "off", and top-level think:true for native Ollama transport with any explicit non-off thinking level. (extensions/ollama/src/stream.ts:199, d54d2d6b9b8a)
  • ollama-provider-registration: The bundled Ollama provider registers createConfiguredOllamaCompatStreamWrapper as its wrapStreamFn, so the native thinking-control mapping is on the live Ollama provider request path. (extensions/ollama/index.ts:169, d54d2d6b9b8a)
  • regression-tests: Regression tests assert native Ollama payloads contain top-level think:false for off and think:true for enabled thinking, with no nested options.think. (extensions/ollama/src/stream-runtime.test.ts:100, d54d2d6b9b8a)
  • docs-and-release-evidence: The Ollama provider docs describe the shipped native /api/chat behavior, and tag v2026.4.24 contains the same stream wrapper, tests, and docs. The appcast/changelog release note also records the Ollama top-level think forwarding fix. Public docs: docs/providers/ollama.md. (docs/providers/ollama.md:464, cbcfdf62c729)
  • pr-discussion-and-branch-scope: The provided PR discussion shows reviewers flagged the branch's heuristic gate for missing thinking-capable qwen3/qwq/GLM-style models; the author broadened the regex, but the PR still carries unrelated src/agents/model-auth-env-vars.* work for [Bug]: OpenRouter provider not routing requests to models #67989, making it unsuitable as the narrow Ollama fix now that main has shipped a different solution. (82ab8883d56f)

So I’m closing this as already implemented rather than keeping a duplicate issue open.

Codex Review notes: model gpt-5.5, reasoning high; reviewed against d54d2d6b9b8a; fix evidence: release v2026.4.24, commit cbcfdf62c729.

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

Labels

agents Agent runtime and tooling size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: OpenClaw infer/web UI fails with ollama/qwen2.5:0.5b, but direct Ollama /api/chat works

1 participant