Skip to content

OpenCode Go: Xiaomi MiMo rejects list-type tool message content (400 text is not set) #32613

Description

@Cdddo

Description

When using OpenCode Go with Xiaomi MiMo models (e.g. mimo-v2.5), requests that include tool results with image content (e.g. browser screenshots, vision tool output) fail with a 400 error:

Error code: 400 - {"error":{"code":"400","message":"Param Incorrect","param":"`text` is not set","type":""}}

The issue is that Xiaomi MiMo API requires role: "tool" message content to be a string, but OpenAI-compatible clients send it as a list of content parts (e.g. [{"type": "text", "text": "..."}, {"type": "image_url", "image_url": {...}}]) when the tool result includes images.

OpenCode Go exposes an OpenAI-compatible /v1/chat/completions endpoint and routes MiMo requests to Xiaomi. The relay appears to pass through the list-type tool content unchanged, and Xiaomi rejects it.

Steps to Reproduce

  1. Use OpenCode Go with mimo-v2.5 (or any MiMo model)
  2. Send a conversation that includes a tool result with image content (e.g. from a browser/vision tool)
  3. The tool message content is a list with text + image_url parts
  4. Xiaomi returns 400 "text is not set"

Expected Behavior

The relay should either:

  • Convert list-type tool message content to a text string before forwarding to Xiaomi, or
  • Document that MiMo models via OpenCode Go do not support multimodal tool results

Context

This is a known Xiaomi API limitation — their API accepts multimodal user messages but rejects list-type tool message content. Other clients (Hermes Agent, OpenClaw) have hit the same issue (ref: hermes-agent#27344, openclaude#1421).

Clients can work around this by flattening tool-result images to text before sending, but since OpenCode Go positions itself as a unified OpenAI-compatible API, the relay is better positioned to handle this translation — especially since other backends behind the relay (GLM, Kimi) may handle list-type content fine, making this a per-model concern that the relay should abstract away.

Activity

  1. lexlian commented on Jun 19, 2026

    @lexlian

    @Cdddo @fwang , I fixed the issue with PR #32966.

    Root cause: MiMo/GLM-5.2/Xiaomi require tool role messages to have content as a plain string, not ContentPart[] array. The AI SDK sends tool results as [{type: "tool-result", output: {type: "text", value: "..." }}], which these providers reject with 400 errors.

    Fix: Added provider-specific transform that flattens single-part tool results to plain strings for affected providers. Multi-part content is preserved as array (providers that don't support it will error, which signals the limitation clearly.

  2. nagdeepanjan commented on Jul 22, 2026

    @nagdeepanjan

    +1 — still affecting OpenCode Go users

    I'm running OpenCode Go with Xiaomi MiMo v2.5 as my primary model (via Hermes Agent on a Raspberry Pi). This issue causes intermittent 400 errors whenever a tool result includes image content (vision analysis, browser screenshots, etc.), forcing fallback to non-vision models and breaking my entire image verification workflow.

    What I've tried:

    • Routing through OpenRouter instead of OpenCode Go's native relay (works, but adds latency and loses some features)
    • Keeping the fallback chain as a band-aid (all fallback models lack vision, so the system becomes unusable for visual tasks)

    PR #32966 by @lexlian looked like the right fix (flatten single-part tool results to plain strings for affected providers), but it was closed by automated cleanup before being reviewed. The fix was tested and passing all 277 tests.

    Request: Could this be prioritized? The Xiaomi API isn't going to change this behavior — their docs explicitly require string content for tool messages. The relay is the right place to handle this translation.

    Happy to help test if a new PR is opened.

  3. Nandoca95 commented on Jul 26, 2026

    @Nandoca95

    Current reproduction through OpenCode Go / MiMo v2.5

    I am adding current evidence to this existing issue rather than opening a duplicate.

    Effective route

    • Hermes main commit: fe3dd9106a1c9d2327fb3795e55b09742c43bafd
    • Provider: opencode-go
    • Model: mimo-v2.5
    • Base URL: https://opencode.ai/zen/go/v1

    Reproduction

    Using a fresh temporary Hermes home, without changing the permanent configuration:

    opencode-go/mimo-v2.5
    → browser_navigate completed
    → browser_vision completed
    → next request through opencode-go/mimo-v2.5
    → HTTP 400
    

    The returned error was:

    Error from provider (Xiaomi): Param Incorrect
    param: `text` is not set
    

    The request did not switch to Xiaomi as the selected Hermes provider. The effective provider remained OpenCode Go throughout the tested route. Hermes also did not silently switch to another model after the 400.

    The same failure pattern was previously observed in Hermes sessions using opencode-go/mimo-v2.5 directly and after a real fallback to that route.

    Question for OpenCode Go

    Could you confirm how the OpenCode Go relay/adaptor maps the request state associated with browser_vision into the request sent to MiMo v2.5?

    In particular:

    • Is a plain text field required for tool messages on this route?
    • Does the relay normalize list/part-based tool content before forwarding it?
    • Is text is not set expected for this request shape, or should the relay return a more specific compatibility response?

    Scope and limitations

    • This is not a direct Xiaomi-provider test; the effective provider was opencode-go.
    • Xiaomi is mentioned only because it appears as the upstream source in the returned error.
    • The exact wire payload was not captured.
    • I am not asserting that OpenCode Go alone is the root cause; the defect may involve Hermes request construction, relay transformation, or the downstream adapter boundary.
    • The historical introducing change has not been identified.

    Related Hermes reproduction: NousResearch/hermes-agent#49388

  4. FrancoMeneses commented on Sep 22, 2026

    @FrancoMeneses

    Adding current evidence for the third-party OpenAI-compatible client path, plus one gap that the earlier fix does not cover.

    Reproduction as of today:

    • Provider opencode-go, model mimo-v2.5, base URL https://opencode.ai/zen/go/v1
    • Client: Hermes Agent (plain OpenAI-compatible chat completions)
    • A tool result that carries an image is sent as multi-part content on role: "tool":
      [{"type":"text","text":"..."},{"type":"image_url","image_url":{...}}]
    • Xiaomi rejects the request: 400, param: "text" is not set

    The part worth flagging: the transform in #32966 only handles single-part tool results. It flattens a lone text/error part to a string and explicitly leaves multi-part content as an array. Multi-part is exactly the shape this bug is about, so even with that transform merged, a tool result carrying an image would still 400.

    What would actually close it for these providers, either way:

    • hoist media out of the tool result into a normal user message — this is the existing behavior for @ai-sdk/openai-compatible in the CLI (supportsMediaInToolResult returns false for it, so the image is extracted and re-injected as a user message), and it is the same approach PR fix(opencode): hoist Bedrock tool images except Claude, Nova, and Llama 4 #50272 just merged for Bedrock; or
    • for role: "tool" messages specifically, emit plain-string content and move the media part to an adjacent user message.

    Worth noting the asymmetry: the opencode CLI itself does not hit this, because it already hoists media out of tool results for OpenAI-compatible SDKs. It only bites clients that talk to /zen/go/v1/chat/completions directly and treat "OpenAI-compatible" literally. Since Go is advertised as an OpenAI-compatible endpoint, closing that gap on the relay side would fix every third-party client at once instead of each one shipping its own workaround.

    Happy to test a fix or provide a minimal request payload if useful.

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions