Skip to content

[Bug] Xiaomi MiMo token-plan rejects Responses custom tools (400 responses_feature_not_supported) — works fully via openai-chat adapter; add preset/guidance #1158

Closed

Description

@BeniSisaki

Summary

Xiaomi MiMo's paid token-plan endpoint (https://token-plan-cn.xiaomimimo.com/v1) speaks the Responses wire for plain requests, but its gateway rejects type: "custom" tools — which Codex emits for apply_patch and other freeform tools:

HTTP 400
{"error":{"code":"responses_feature_not_supported",
 "message":"tool type 'custom' is not supported by this gateway phase.",
 "type":"unsupported_feature"}}

With the provider configured as adapter: "openai-responses", this makes MiMo unusable as a Codex model for any tool-calling turn (Codex always attaches custom tools). Verified boundary with direct calls:

Request Result
POST /v1/responses (no tools) 200 ✅
POST /v1/responses + tools:[{type:"custom",name:"apply_patch",...}] 400 ❌ (responses_feature_not_supported)
POST /v1/chat/completions 200 ✅ (including reasoning_content)

Verified fix: adapter: "openai-chat"

Switching the provider to the chat adapter makes the full Codex loop work, thanks to the existing freeform bridge (responses/parser.ts wraps custom tools as {input:string} functions; bridge.ts relays calls back as custom_tool_call):

"mimo": {
  "adapter": "openai-chat",
  "baseUrl": "https://token-plan-cn.xiaomimimo.com/v1",
  "apiKey": "${MIMO_API_KEY}",
  "models": ["mimo-v2.5-pro", "mimo-v2.5"]
}

End-to-end through the proxy (POST /v1/responses, model: "mimo/mimo-v2.5"):

  • plain turn → 200, text streamed, response.completed ✅
  • turn with apply_patch custom tool attached → 200, model emits proper response.custom_tool_call_input.delta/done (Codex's freeform handler requires this shape; a plain function_call would fatal-abort) ✅
  • continuation with custom_tool_call + custom_tool_call_output history → 200, coherent follow-up ✅

Suggestions

  1. Add a registry preset for MiMo token-plan (id: "mimo") with adapter: "openai-chat" so users get the working wire by default. (Currently only mimo-free exists; token-plan users hand-roll the provider and naturally pick openai-responses because MiMo documents Responses support.)
  2. Alternatively/additionally: a per-provider flag to force the custom→{input:string} function bridging on the responses wire, for gateways that reject type:"custom".
  3. Document that openai-responses passthrough requires upstream support for Responses custom tools — a 400 from the gateway currently surfaces without guidance.

One friction point hit while fixing: ocx provider edit mimo --adapter openai-chat refused the change because the hostname resolves to a benchmark/fake-IP address (198.18.x.x) behind a VPN with fake-ip DNS — the runtime path works fine through it, only the CLI edit-time validation blocks. Maybe allow an explicit --force/acknowledgement for that case.

Environment: opencodex 2.10.2, Windows 11, MiMo token-plan (paid) account.

Activity

  1. BeniSisaki commented on Aug 6, 2026

    @BeniSisaki
    Author

    Follow-up finding on the same route: MiMo token-plan's chat surface also validates reasoning_effort strictly — Pydantic literal, 'low' | 'medium' | 'high' only. Codex's global default xhigh therefore 400s through the chat adapter too:

    Provider error 400: [{'type': 'literal_error', 'loc': ('body', 'reasoning_effort'),
     'msg': "Input should be 'low', 'medium' or 'high'", 'input': 'xhigh', ...}]
    

    Fixed locally with the provider's existing knobs — suggest baking both into the registry preset:

    "modelReasoningEfforts": {
      "mimo-v2.5-pro": ["low", "medium", "high"],
      "mimo-v2.5": ["low", "medium", "high"]
    },
    "reasoningEffortMap": { "xhigh": "high", "max": "high", "ultra": "high" }

    With that, xhigh/max/medium requests all return 200 through the proxy (verified against mimo/mimo-v2.5 and mimo/mimo-v2.5-pro).

  2. BeniSisaki commented on Aug 6, 2026

    @BeniSisaki
    Author

    Second follow-up from live usage of the mimo route (via the openai-chat adapter): Codex's built-in image tool works through MiMo, because the app exposes it as a client-executed namespaced function tool (image_gen__imagegen) — the namespace flattening passes it to the chat model, and when MiMo emits a valid structured call the app executes it through /v1/images (gpt-image-2 relayed fine, images landed on disk).

    Reliability caveat worth noting for a future preset: MiMo's tool-call discipline is flaky — in a 25-request window we saw 2 turns fail with "upstream stream produced malformed tool call arguments" (bridge.ts fails the turn by design, #765), plus several attempts where the model emitted the call as literal <tool_call>…</tool_call> text instead of a structured call. The client auto-retried and eventually succeeded every time, but it costs turns/tokens. If a lenient repair mode (like the anthropic adapter's MAX_REPAIRABLE_TOOL_ARGUMENT_BYTES path) ever lands for the chat bridge, mimo would benefit; until then a preset doc note ("expect occasional malformed-arg turn failures; client retry handles it") would set expectations.

  3. github-actions commented on Aug 6, 2026

    @github-actions
    Contributor

    Automated translation bookkeeping — detected language: unknown.

  4. Wibias commented on Aug 7, 2026

    @Wibias
    Contributor

    Closing as completed by #1211.

    MiMo token-plan now has a first-class preset using the working openai-chat wire, preserving custom destinations and avoiding the Responses custom-tool incompatibility reported here.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions