#2542·rig

feat: Responses dialect for OpenAI-compatible providers whose vendors ship /responses (MiniMax, Moonshot, Groq, OpenRouter)

Author: BANG404Created Sep 16, 2026Updated Sep 16, 2026

Summary

On main (6389a3bbf01e55693174e936f48135c4706d55ff), only four providers can speak the OpenAI Responses wire format: openai (dialect selectable), xai, chatgpt, and copilot. Every other OpenAI-compatible provider is hard-wired to POST /chat/completions through OpenAICompatibleProvider, with no way to select the dialect — even though several of those vendors now ship a native /responses endpoint.

This is a request to add a Responses dialect for the providers whose vendor API supports it, built on the machinery that already exists in the crate.

Dialect census on main

Responses:

provider evidence
openai providers/openai/client.rs:154 (impl ResponsesProviderExt for OpenAIResponses), providers/openai/responses_api/mod.rs:1243 (RESPONSES_PATH = "/responses")
xai providers/xai/client.rs:84, :86 (RESPONSES_PATH = "/v1/responses")
chatgpt providers/chatgpt/mod.rs:229, :486, :617 (post("/responses"))
copilot providers/copilot/mod.rs:838, :911 (hybrid: /responses + /chat/completions)

OpenAI-compatible, Chat Completions onlyimpl OpenAICompatibleProvider, and completion_path() defaults to /chat/completions (providers/openai/completion/mod.rs:1777):

provider impl
azure providers/azure.rs:412
deepseek providers/deepseek.rs:85
doubleword providers/doubleword/client.rs:66
groq providers/groq.rs:89
huggingface providers/huggingface/client.rs:192
hyperbolic providers/hyperbolic.rs:97
llamacpp providers/llamacpp/client.rs:186
minimax providers/minimax.rs:104
mira providers/mira.rs:76
mistral providers/mistral/client.rs:94
moonshot providers/moonshot.rs:141
openrouter providers/openrouter/completion.rs:1573
perplexity providers/perplexity.rs:63
together providers/together/client.rs:65
venice providers/venice/client.rs:132
xiaomimimo providers/xiaomimimo.rs:84
zai providers/zai.rs:79

Non-OpenAI dialects (out of scope for this request): anthropic (Messages), cohere, gemini, ollama (/api/chat, providers/ollama.rs:865), voyageai (embeddings).

Vendors that already ship /responses

provider endpoint source
MiniMax https://api.minimax.io/v1/responses MiniMax "Create Response" API reference — the OpenAI Responses API-compatible main endpoint, with a web_search server tool declared in tools
Moonshot / Kimi https://api.moonshot.ai/v1/responses Kimi API overview — OpenAI Responses listed as one of the three supported API formats
Groq https://api.groq.com/openai/v1/responses GroqDocs "Responses API" — streaming SSE, tools, MCP
OpenRouter https://openrouter.ai/api/v1/responses OpenRouter Responses API (beta) — drop-in OpenAI Responses across routed models

Vendors that do not currently ship /responses, and would therefore stay on Chat Completions:

  • z.ai / Zhipu — only /chat/completions today; there is an open request on the vendor side (zai-org/GLM-5#39).
  • Together AI/responses is absent from its documented OpenAI-compatibility matrix.

Why it matters

Consumers that want Responses features (reasoning items, hosted tools, prompt-cache routing, store: false replay) currently have to construct the generic openai::Client against these vendors' base URLs. That bypasses the OpenAICompatibleProvider impl — the place where each provider's wire quirks are supposed to live — so every quirk has to be re-handled downstream:

  • MiniMax echoes top_p (object-shaped) and can return "tools": null, which the Responses decoder rejects (#2483), and loses reported usage under serde_json/arbitrary_precision (#2493).
  • MiniMax completes a function_call output item before streaming that item's function_call_arguments.delta, so an output_item.done seen in isolation carries empty arguments.

Routing through a provider-native Responses client would keep those fixups in the provider impl (where #2483/#2493 already live) instead of in every consumer, and would keep provider identity/telemetry (PROVIDER_NAME) correct.

Existing machinery to build on

  • ResponsesProviderExt + GenericResponsesCompletionModel already exist (providers/openai/responses_api/mod.rs:1227) and are implemented by OpenAIResponses, XAi, and ChatGPT. The trait already exposes RESPONSES_PATH, so a vendor whose path differs from /responses is a one-const override.
  • impl_dual_dialect_provider! (providers/internal/anthropic_compatible.rs:85) already establishes the "one provider, two wire dialects" pattern — OpenAI-compatible plus Anthropic-compatible — for MiniMax, Moonshot, ZAi, and XiaomiMimo. A third dialect could follow the same shape, or dialect selection could become a client-level option.
  • Related: #2042 proposes this layer split directly ("Protocol adapter: OpenAI Chat Completions / OpenAI Responses / Anthropic Messages / …").

Caveats

  • OpenRouter's endpoint is beta and stateless: store: true and a non-null previous_response_id are rejected with 400, so a client would have to replay the full transcript there.
  • Groq's Responses surface accepts function tools only (max 128) and store limited to false/null; a dialect switch should not assume full OpenAI feature parity.