Skip to content

fix(openrouter): handle reasoning_details in Qwen3 stream parsing#66905

Merged
obviyus merged 4 commits intoopenclaw:mainfrom
bladin:fix/66833-openrouter-qwen3-reasoning-details
Apr 15, 2026
Merged

fix(openrouter): handle reasoning_details in Qwen3 stream parsing#66905
obviyus merged 4 commits intoopenclaw:mainfrom
bladin:fix/66833-openrouter-qwen3-reasoning-details

Conversation

@bladin
Copy link
Copy Markdown
Contributor

@bladin bladin commented Apr 15, 2026

Summary

Fix OpenRouter/Qwen3 models returning empty responses due to unrecognized reasoning_details field.

Problem: When using openrouter/qwen/qwen3-235b-a22b or any Qwen3 model via OpenRouter, every response fails with "incomplete turn detected: payloads=0" and the user sees "⚠️ Agent couldn't generate a response."

Root Cause: The stream parser in src/agents/openai-transport-stream.ts handled reasoning_content, reasoning, and reasoning_text but not reasoning_details — which Qwen3 returns via OpenRouter. The unhandled field caused zero content blocks to be assembled, triggering the incomplete turn path.

Solution: Add handling for reasoning_details array. Extract text from items with type: "reasoning.text" and treat as thinking content, enabling successful turn completion.

Additional defensive fixes:

  • Add ?? "" guards in src/channels/plugins/setup-wizard.ts:458 and src/channels/plugins/setup-wizard-helpers.ts:994 to prevent potential undefined trim errors from clack wrapper edge cases (belt-and-suspenders approach mentioned in issue comments).

Changes

  • openai-transport-stream.ts: Add reasoning_details handling in processOpenAICompletionsStream, extracting reasoning text from array items and creating thinking blocks.
  • openai-transport-stream.test.ts: Add test case verifying correct handling of Qwen3 reasoning_details.
  • setup-wizard.ts & setup-wizard-helpers.ts: Add defensive guards around prompter.text() results.

Test plan

  • New unit test: handles reasoning_details from OpenRouter/Qwen3 in completions stream passes
  • All 53 existing openai-transport-stream.test.ts tests pass
  • Fix verified by community members in original issue thread

AI Code Generation Disclosure

  • 🤖 This PR was created with AI assistance (Claude Codex)
  • The fix implementation and test were generated based on issue description and community diagnosis

Environment

  • OpenClaw version: 2026.4.14 (base)
  • Tested with: Bun test runner, TypeScript type-checking
  • Provider: OpenRouter
  • Model: openrouter/qwen/qwen3-235b-a22b, qwen3-32b

Checklist

@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling size: S labels Apr 15, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 15, 2026

Greptile Summary

This PR fixes empty responses from OpenRouter/Qwen3 models by adding reasoning_details array handling to the completions stream parser, following the same pattern used for reasoning_content/reasoning/reasoning_text. It also adds ?? "" guards in two setup-wizard prompt calls to prevent potential TypeError when the prompter returns null/undefined.

The implementation is targeted and consistent with existing reasoning-field handling. The new test covers the primary multi-chunk scenario and confirms correct assembly of thinking + text content blocks.

Confidence Score: 5/5

Safe to merge — fix is minimal, follows existing patterns, and is covered by a new unit test.

No P0 or P1 issues found. The reasoning_details handling mirrors the established pattern for other reasoning fields. The thinkingSignature: "reasoning_details" value is consistent with how e.g. "reasoning_content" is stored for the same field, and any cross-transport concern (JSON.parse on history replay) is pre-existing and not introduced here. Defensive ?? "" guards are safe.

No files require special attention.

Reviews (1): Last reviewed commit: "fix(openrouter): handle reasoning_detail..." | Re-trigger Greptile

Copy link
Copy Markdown

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

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: 94cda6c34f

ℹ️ 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 src/channels/plugins/setup-wizard.ts Outdated
@@ -455,7 +455,7 @@ export function buildChannelSetupWizardAdapterFromSetupWizard(params: {
});
},
});
const trimmedValue = rawValue.trim();
const trimmedValue = (rawValue ?? "").trim();
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 Preserve required-input failure on undefined text responses

Coalescing rawValue to "" here turns an undefined prompt result into a silent empty value. In the required-field path, that empty value falls through to normalizedValue being falsy and the loop continue branch, so setup can proceed without collecting a required input. This is most visible when the prompt layer returns undefined on cancel/interruption: instead of failing fast, the wizard can now silently skip mandatory configuration.

Useful? React with 👍 / 👎.

Comment on lines 990 to 994
(await params.prompter.text({
message: params.inputPrompt,
validate: (value) => (value?.trim() ? undefined : "Required"),
})
})) ?? ""
).trim();
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 Keep token prompts from downgrading undefined to "keep"

Defaulting prompter.text() to "" causes interrupted/undefined token entry to be treated as an empty token rather than an error. Downstream, empty token values are interpreted as "keep existing token", which is incorrect for first-time setup (no configured token) and can leave the credential unset without any explicit failure or retry. This converts a hard failure into silent misconfiguration.

Useful? React with 👍 / 👎.

@bladin bladin force-pushed the fix/66833-openrouter-qwen3-reasoning-details branch from 94cda6c to 4fb723f Compare April 15, 2026 01:31
Copy link
Copy Markdown

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

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: 4fb723f568

ℹ️ 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 src/agents/openai-transport-stream.ts Outdated
Copy link
Copy Markdown

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

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: bcfac3bfe7

ℹ️ 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 src/agents/openai-transport-stream.ts Outdated
@obviyus obviyus self-assigned this Apr 15, 2026
bladin and others added 2 commits April 15, 2026 08:07
Add support for the reasoning_details field returned by OpenRouter/Qwen3
models. Previously this field was not recognized, causing payloads=0 and
incomplete turn errors.

- Add reasoning_details handling in processOpenAICompletionsStream
- Extract text from reasoning_details array items with type reasoning.text
- Treat as thinking content, similar to other reasoning fields
- Add test case for reasoning_details handling

Fixes openclaw#66833
Copy link
Copy Markdown

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

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: 501561be5f

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/agents/openai-transport-stream.ts Outdated
@obviyus obviyus force-pushed the fix/66833-openrouter-qwen3-reasoning-details branch from 501561b to 35a2bc7 Compare April 15, 2026 02:42
Copy link
Copy Markdown
Contributor

@obviyus obviyus left a comment

Choose a reason for hiding this comment

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

Verified the OpenRouter Qwen3 empty-reply failure path and confirmed the stream parser now handles reasoning_details on the main completions path.

Maintainer follow-up: preserved same-chunk tool calls, kept streamed tool-call argument accumulation intact across repeated reasoning_details deltas, added regression coverage for both cases, and added the unreleased changelog entry.

Local gate: pnpm test src/agents/openai-transport-stream.test.ts (55/55). pnpm check was rerun and only hit the unrelated current-main src/media-understanding/runner.proxy.test.ts:231 tsgo failure.

@obviyus obviyus merged commit e0bf756 into openclaw:main Apr 15, 2026
9 checks passed
@obviyus
Copy link
Copy Markdown
Contributor

obviyus commented Apr 15, 2026

Landed on main.

Thanks @bladin.

kvnkho pushed a commit to kvnkho/openclaw that referenced this pull request Apr 17, 2026
… (thanks @bladin)

* fix(openrouter): handle reasoning_details field in Qwen3 stream parsing

Add support for the reasoning_details field returned by OpenRouter/Qwen3
models. Previously this field was not recognized, causing payloads=0 and
incomplete turn errors.

- Add reasoning_details handling in processOpenAICompletionsStream
- Extract text from reasoning_details array items with type reasoning.text
- Treat as thinking content, similar to other reasoning fields
- Add test case for reasoning_details handling

Fixes openclaw#66833

* fix(openrouter): keep tool calls with reasoning_details

* fix: handle OpenRouter Qwen3 reasoning_details streams (openclaw#66905) (thanks @bladin)

* fix: preserve streamed tool calls with reasoning deltas (openclaw#66905) (thanks @bladin)

---------

Co-authored-by: bladin <[email protected]>
Co-authored-by: Ayaan Zaidi <[email protected]>
zhonghe0615 pushed a commit to zhonghe0615/openclaw that referenced this pull request Apr 27, 2026
… (thanks @bladin)

* fix(openrouter): handle reasoning_details field in Qwen3 stream parsing

Add support for the reasoning_details field returned by OpenRouter/Qwen3
models. Previously this field was not recognized, causing payloads=0 and
incomplete turn errors.

- Add reasoning_details handling in processOpenAICompletionsStream
- Extract text from reasoning_details array items with type reasoning.text
- Treat as thinking content, similar to other reasoning fields
- Add test case for reasoning_details handling

Fixes openclaw#66833

* fix(openrouter): keep tool calls with reasoning_details

* fix: handle OpenRouter Qwen3 reasoning_details streams (openclaw#66905) (thanks @bladin)

* fix: preserve streamed tool calls with reasoning deltas (openclaw#66905) (thanks @bladin)

---------

Co-authored-by: bladin <[email protected]>
Co-authored-by: Ayaan Zaidi <[email protected]>
lovewanwan pushed a commit to lovewanwan/openclaw that referenced this pull request Apr 28, 2026
… (thanks @bladin)

* fix(openrouter): handle reasoning_details field in Qwen3 stream parsing

Add support for the reasoning_details field returned by OpenRouter/Qwen3
models. Previously this field was not recognized, causing payloads=0 and
incomplete turn errors.

- Add reasoning_details handling in processOpenAICompletionsStream
- Extract text from reasoning_details array items with type reasoning.text
- Treat as thinking content, similar to other reasoning fields
- Add test case for reasoning_details handling

Fixes openclaw#66833

* fix(openrouter): keep tool calls with reasoning_details

* fix: handle OpenRouter Qwen3 reasoning_details streams (openclaw#66905) (thanks @bladin)

* fix: preserve streamed tool calls with reasoning deltas (openclaw#66905) (thanks @bladin)

---------

Co-authored-by: bladin <[email protected]>
Co-authored-by: Ayaan Zaidi <[email protected]>
ogt-redknie pushed a commit to ogt-redknie/OPENX that referenced this pull request May 2, 2026
… (thanks @bladin)

* fix(openrouter): handle reasoning_details field in Qwen3 stream parsing

Add support for the reasoning_details field returned by OpenRouter/Qwen3
models. Previously this field was not recognized, causing payloads=0 and
incomplete turn errors.

- Add reasoning_details handling in processOpenAICompletionsStream
- Extract text from reasoning_details array items with type reasoning.text
- Treat as thinking content, similar to other reasoning fields
- Add test case for reasoning_details handling

Fixes openclaw#66833

* fix(openrouter): keep tool calls with reasoning_details

* fix: handle OpenRouter Qwen3 reasoning_details streams (openclaw#66905) (thanks @bladin)

* fix: preserve streamed tool calls with reasoning deltas (openclaw#66905) (thanks @bladin)

---------

Co-authored-by: bladin <[email protected]>
Co-authored-by: Ayaan Zaidi <[email protected]>
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]: OpenRouter/Qwen3 stream parsing fails — reasoning_details field not handled, causes payloads=0

2 participants