Skip to content

Fix Xiaomi MiMo reasoning-only completions#60304

Open
HiddenPuppy wants to merge 2 commits intoopenclaw:mainfrom
HiddenPuppy:codex/issue-60261-xiaomi-reasoning-content-fallback
Open

Fix Xiaomi MiMo reasoning-only completions#60304
HiddenPuppy wants to merge 2 commits intoopenclaw:mainfrom
HiddenPuppy:codex/issue-60261-xiaomi-reasoning-content-fallback

Conversation

@HiddenPuppy
Copy link
Copy Markdown

Summary

  • Problem: Xiaomi MiMo mimo-v2-pro / mimo-v2-omni can return the user-visible final answer in reasoning_content, which OpenClaw currently surfaces as thinking instead of normal assistant text, so the reply can appear blank.
  • Why it matters: affected Xiaomi users can get an empty-looking assistant response even though the model produced an answer.
  • What changed: added a Xiaomi-only stream compatibility wrapper that converts reasoning-only final assistant messages into text for the affected MiMo models, and added regression tests for both the targeted and non-target Xiaomi paths.
  • What did NOT change (scope boundary): this PR does not change the generic OpenAI-compatible parser, non-Xiaomi providers, auth flow, or model selection behavior.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

Root Cause / Regression History (if applicable)

  • Root cause: Xiaomi's OpenAI-compatible chat completions path can place the final answer in reasoning_content. The shared parser maps that to a thinking block, while downstream rendering expects user-visible output in text blocks.
  • Missing detection / guardrail: there was no Xiaomi-specific compatibility layer or regression test for a final assistant message that contains reasoning only and no text.
  • Prior context (git blame, prior PR, issue, or refactor if known): the shared OpenAI-compatible parsing behavior is reasonable for providers that use reasoning_content for actual reasoning output, but Xiaomi MiMo uses it for the final visible answer in this case.
  • Why this regressed now: the issue surfaced once Xiaomi MiMo reasoning models were used through the standard openai-completions path without a provider-specific normalization step.
  • If unknown, what was ruled out: this was not an auth, model-selection, or request-formatting problem; the content was returned by the provider but landed in the wrong content block type for rendering.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
  • Unit test
  • Seam / integration test
  • End-to-end test
  • Existing coverage already sufficient
  • Target test or file: extensions/xiaomi/index.test.ts
  • Scenario the test should lock in: reasoning-only final assistant messages from mimo-v2-pro / mimo-v2-omni are normalized into text, while non-target Xiaomi models remain unchanged.
  • Why this is the smallest reliable guardrail: it exercises the actual Xiaomi provider registration + wrapStreamFn seam without needing live Xiaomi API traffic.
  • Existing test that already covers this (if any): none
  • If no new test is added, why not: N/A

User-visible / Behavior Changes

  • Xiaomi MiMo mimo-v2-pro / mimo-v2-omni replies no longer appear blank when the provider returns the final answer via reasoning_content.
  • Non-target Xiaomi models keep their existing behavior.
  • Non-Xiaomi providers keep their existing behavior.

Diagram (if applicable)

Before:
[Xiaomi MiMo response]
  -> [final answer only in reasoning_content]
  -> [parsed as thinking only]
  -> [no normal assistant text rendered]

After:
[Xiaomi MiMo response]
  -> [Xiaomi-only compatibility wrapper]
  -> [reasoning-only final message normalized to text]
  -> [assistant reply rendered normally]

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 3, 2026

Greptile Summary

This PR adds a Xiaomi-specific stream compatibility wrapper in extensions/xiaomi/stream.ts that promotes reasoning_content (surfaced as thinking blocks) to text blocks for mimo-v2-pro and mimo-v2-omni when the final message contains reasoning output but no visible text. The fix is correctly scoped to those two model IDs via wrapStreamFn, leaving all other Xiaomi models and providers untouched. Remaining notes are both P2: the early break on hasRenderableText creates a subtle asymmetry in the detection loop that could mislead future contributors, and mimo-v2-omni has no dedicated test case (though the shared logic covers it).

Confidence Score: 5/5

Safe to merge — no P0/P1 issues, all remaining findings are minor style suggestions.

The core normalization logic is correct and well-guarded. Both the iterator and result() rewrite paths are exercised by tests. The only open items are a stylistic early-break asymmetry and missing direct coverage of mimo-v2-omni, neither of which affects runtime behavior.

No files require special attention.

Prompt To Fix All With AI
This is a comment left during a code review.
Path: extensions/xiaomi/stream.ts
Line: 62-65

Comment:
**Early `break` may shadow `hasToolCalls` detection**

The `break` fires as soon as any renderable text block is found, so subsequent `toolCall` blocks are never visited — `hasToolCalls` stays `false` for those iterations. Correctness is preserved because `hasRenderableText = true` already causes the function to bail on line 78, but the loop's three booleans read as symmetric flags when they aren't. If the loop body ever grows (e.g. another bypass condition), this implicit ordering could silently create a bug. Consider removing the `break` or adding a comment explaining that only `hasRenderableText` needs to short-circuit.

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

---

This is a comment left during a code review.
Path: extensions/xiaomi/index.test.ts
Line: 62-104

Comment:
**`mimo-v2-omni` not covered by tests**

The `XIAOMI_REASONING_AS_TEXT_MODEL_IDS` Set lists both `mimo-v2-pro` and `mimo-v2-omni` as target models, but the tests only exercise `mimo-v2-pro`. Adding a parallel case for `mimo-v2-omni` (or parameterizing the existing test) would lock in the full set of affected models against future `XIAOMI_REASONING_AS_TEXT_MODEL_IDS` edits.

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

Reviews (1): Last reviewed commit: "Normalize Xiaomi reasoning-only completi..." | Re-trigger Greptile

Comment on lines +62 to +65
) {
hasRenderableText = true;
break;
}
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 Early break may shadow hasToolCalls detection

The break fires as soon as any renderable text block is found, so subsequent toolCall blocks are never visited — hasToolCalls stays false for those iterations. Correctness is preserved because hasRenderableText = true already causes the function to bail on line 78, but the loop's three booleans read as symmetric flags when they aren't. If the loop body ever grows (e.g. another bypass condition), this implicit ordering could silently create a bug. Consider removing the break or adding a comment explaining that only hasRenderableText needs to short-circuit.

Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/xiaomi/stream.ts
Line: 62-65

Comment:
**Early `break` may shadow `hasToolCalls` detection**

The `break` fires as soon as any renderable text block is found, so subsequent `toolCall` blocks are never visited — `hasToolCalls` stays `false` for those iterations. Correctness is preserved because `hasRenderableText = true` already causes the function to bail on line 78, but the loop's three booleans read as symmetric flags when they aren't. If the loop body ever grows (e.g. another bypass condition), this implicit ordering could silently create a bug. Consider removing the `break` or adding a comment explaining that only `hasRenderableText` needs to short-circuit.

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

Comment thread extensions/xiaomi/index.test.ts Outdated
Comment on lines +62 to +104
it("normalizes reasoning-only final assistant messages into text for MiMo reasoning models", async () => {
const stream = runWrappedXiaomiStream({
modelId: "mimo-v2-pro",
events: [
{
type: "done",
reason: "stop",
message: {
role: "assistant",
content: [{ type: "thinking", thinking: "MiMo final answer" }],
stopReason: "stop",
},
},
],
resultMessage: {
role: "assistant",
content: [{ type: "thinking", thinking: "MiMo final answer" }],
stopReason: "stop",
},
});

const events: unknown[] = [];
for await (const event of stream) {
events.push(event);
}

await expect(stream.result()).resolves.toEqual({
role: "assistant",
content: [{ type: "text", text: "MiMo final answer" }],
stopReason: "stop",
});
expect(events).toEqual([
{
type: "done",
reason: "stop",
message: {
role: "assistant",
content: [{ type: "text", text: "MiMo final answer" }],
stopReason: "stop",
},
},
]);
});
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 mimo-v2-omni not covered by tests

The XIAOMI_REASONING_AS_TEXT_MODEL_IDS Set lists both mimo-v2-pro and mimo-v2-omni as target models, but the tests only exercise mimo-v2-pro. Adding a parallel case for mimo-v2-omni (or parameterizing the existing test) would lock in the full set of affected models against future XIAOMI_REASONING_AS_TEXT_MODEL_IDS edits.

Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/xiaomi/index.test.ts
Line: 62-104

Comment:
**`mimo-v2-omni` not covered by tests**

The `XIAOMI_REASONING_AS_TEXT_MODEL_IDS` Set lists both `mimo-v2-pro` and `mimo-v2-omni` as target models, but the tests only exercise `mimo-v2-pro`. Adding a parallel case for `mimo-v2-omni` (or parameterizing the existing test) would lock in the full set of affected models against future `XIAOMI_REASONING_AS_TEXT_MODEL_IDS` edits.

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

@clawsweeper
Copy link
Copy Markdown
Contributor

clawsweeper Bot commented May 1, 2026

Codex review: needs changes before merge.

Summary
The PR adds a Xiaomi-only stream wrapper and tests to convert thinking-only final messages for mimo-v2-pro and mimo-v2-omni into text while leaving non-target Xiaomi models unchanged.

Reproducibility: yes. The linked Xiaomi report gives concrete setup steps and delta.reasoning_content samples, and current main still maps that field to thinking while visible rendering reads text blocks.

Next step before merge
This is a narrow provider-plugin bug fix with clear files and validation; automation can repair the test helper usage, add changelog coverage, and preserve the Xiaomi-only scope.

Security
Cleared: The diff only adds Xiaomi provider stream-normalization code and tests, with no dependency, CI, publishing, credential, or script changes.

Review findings

  • [P2] Await the public plugin test helper — extensions/xiaomi/index.test.ts:29
  • [P3] Add the required changelog entry — extensions/xiaomi/index.ts:43
Review details

Best possible solution:

Keep the fix in the Xiaomi plugin boundary: repair or replace the PR on current main, use the public async plugin test helper, add changelog coverage, and avoid changing the generic OpenAI-compatible parser or non-Xiaomi providers.

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

Yes. The linked Xiaomi report gives concrete setup steps and delta.reasoning_content samples, and current main still maps that field to thinking while visible rendering reads text blocks.

Is this the best way to solve the issue?

Mostly yes. A Xiaomi-owned wrapper for the two affected MiMo models is the narrow maintainable direction, but this PR is not mergeable as submitted until the stale test helper usage and changelog gap are fixed.

Full review comments:

  • [P2] Await the public plugin test helper — extensions/xiaomi/index.test.ts:29
    On current main, the old ../../test/helpers/plugins/plugin-registration.js bridge is retired and the supported registerSingleProviderPlugin export from openclaw/plugin-sdk/plugin-test-runtime is async. As written, this test file cannot resolve the import; after switching to the public helper, provider also needs await before provider.wrapStreamFn is used.
    Confidence: 0.95
  • [P3] Add the required changelog entry — extensions/xiaomi/index.ts:43
    This changes user-visible Xiaomi reply behavior for a bug fix, but the PR does not update CHANGELOG.md. Add a single-line ### Fixes entry so the provider fix appears in release notes.
    Confidence: 0.88

Overall correctness: patch is incorrect
Overall confidence: 0.91

Acceptance criteria:

  • pnpm test extensions/xiaomi/index.test.ts
  • pnpm exec oxfmt --check --threads=1 extensions/xiaomi/index.ts extensions/xiaomi/index.test.ts extensions/xiaomi/stream.ts
  • git diff --check
  • pnpm check:changed in Testbox before handoff

What I checked:

Likely related people:

  • DJjjjhao: Authored the merged Xiaomi MiMo V2 Pro/Omni catalog work that put the affected models on the OpenAI-compatible path where reasoning_content is parsed as thinking. (role: introduced behavior; confidence: medium; commits: 69abdd111ab8, 6b672f36cf0b; files: extensions/xiaomi/provider-catalog.ts, docs/providers/xiaomi.md, CHANGELOG.md)
  • shakkernerd: Recently moved Xiaomi model catalog data into the plugin manifest, which is now the current source for the affected model metadata. (role: recent maintainer; confidence: medium; commits: 2d7b16e0dbb5, 00d2c3488932; files: extensions/xiaomi/openclaw.plugin.json)
  • steipete: Has recent merged work around Xiaomi plugin entry points and the provider/plugin SDK surfaces used for provider-owned runtime hooks. (role: adjacent owner; confidence: medium; commits: ec8dbc459558, 956fe72b39e6; files: extensions/xiaomi/index.ts, extensions/xiaomi/openclaw.plugin.json, src/plugin-sdk/provider-entry.ts)

Remaining risk / open question:

  • The exact rebase/conflict shape still needs validation before merge or replacement because the PR branch is stale relative to current main.
  • The repaired branch still needs targeted Xiaomi tests, formatting, and the changed gate; this read-only review did not run artifact-producing validation commands.

Codex review notes: model gpt-5.5, reasoning high; reviewed against cc8a8f1df1cd.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Xiaomi/MiMo models output to reasoning_content instead of content field

1 participant