Repository navigation
[Provider] alibaba-token-plan: native OpenAI Responses wire is officially supported upstream — request validated opt-in / default flip #5097
Description
Client or integration
Codex App (verified end-to-end through the OpenCodex proxy) / Codex CLI
Provider or upstream service
Alibaba Cloud Model Studio — Token Plan (Beijing) alibaba-token-plan, Token Plan (Intl) alibaba-token-plan-intl
OpenCodex version
2.59.0 (npm @bitkyc08/opencodex); also confirmed on upstream/dev @ 7817cd5 (2026-09-19)
Endpoint or capability
POST {base}/compatible-mode/v1/responses on the Token Plan gateway (https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1) — native OpenAI Responses wire, custom tools, streaming.
Current behaviour
Both Token Plan registry entries pin adapter: "openai-chat" (src/providers/registry/entries-extended.ts:792-795 and the intl sibling at :835), so the proxy translates every inbound Responses request to Chat Completions toward Alibaba. It works — I observed 88-96% prefix-cache hit on real traffic — but:
- Token Plan's built-in "Harness" tools (web search, code interpreter, web extractor, file_search, MCP-in-Responses) are documented by Alibaba as Responses-only and cannot be triggered over the chat wire.
- The chat bridge adds a translation layer for Responses-specific shapes (custom tools, reasoning envelopes) with known edge cases.
Expected behaviour
Alibaba now officially documents an OpenAI-compatible Responses API on the same /compatible-mode/v1 base, and publishes an official Codex integration guide with wire_api = "responses" against the same Token Plan base URL. OpenCodex should offer a first-class Responses wire for the Token Plan entries — opt-in first (registry modelWireDefaults or a documented modelAdapters preset), then a default flip after field validation.
Minimal redacted request or reproduction
Provider config (redacted) that opts one model in today:
"alibaba-token-plan": {
"adapter": "openai-chat",
"baseUrl": "https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1",
"apiKey": "sk-sp-***",
"modelAdapters": { "qwen3.8-flash": "openai-responses" }
}Through the proxy:
curl -N http://127.0.0.1:10100/v1/responses -H 'Content-Type: application/json' -d '{
"model": "alibaba-token-plan/qwen3.8-flash",
"instructions": "You are a coding agent. Use the apply_patch tool to make file changes.",
"input": [{"type":"message","role":"user","content":[{"type":"input_text","text":"Create a file hello.txt containing hello world. Use the apply_patch tool."}]}],
"tools": [{"type":"custom","name":"apply_patch","description":"Apply a unified diff patch. Input is raw patch text."}],
"reasoning": {"effort":"low"},
"stream": true
}'Unauthenticated route-existence probes (no credentials sent):
curl -s -X POST https://dashscope.aliyuncs.com/compatible-mode/v1/responses -d '{}'
# 401 {"code":"InvalidApiKey","message":"No API-key provided."} -> route registered
curl -s -X POST https://dashscope.aliyuncs.com/compatible-mode/v1/resp -d '{}'
# 404 -> near-miss path not registered (same pattern on dashscope-intl)Actual response or error
(End-to-end verification, 2026-09-19, OpenCodex 2.59.0.)
Through the proxy (per-model modelAdapters hot-applied via the management API; provider-wide wire still openai-chat):
- Request above → HTTP 200 in ~1.5 s. The model emitted a proper
custom_tool_callitem with a correct patch; the SSE stream carriedresponse.custom_tool_call_input.delta/.done(exactly the shapes Codex's freeform handler requires, cf. [Bug] Xiaomi MiMo token-plan rejects Responses custom tools (400 responses_feature_not_supported) — works fully via openai-chat adapter; add preset/guidance #1158) plusresponse.completedwith usage. ~/.opencodex/usage.jsonlrecords the attempt withadapter: "openai-responses", status 200.- Usage details carry
"x_billing_type": "response_api"— Alibaba's own marker that the request was served and billed via the Responses path.
Direct upstream (Beijing Token Plan gateway, glm-5.3, same key-auth):
- Full agent loop: tool-call turn (
custom_tool_callwith a correct patch) → 200; continuation turn replayingcustom_tool_call+custom_tool_call_outputininput→ 200, coherent final message, againx_billing_type: "response_api". - Route probes above on both
dashscope.aliyuncs.comanddashscope-intl.aliyuncs.com.
Upstream documentation
- OpenAI-compatible Responses API guide (incl. migration from Chat Completions): https://help.aliyun.com/zh/model-studio/compatibility-with-openai-responses-api
- Official Codex integration (Token Plan personal/team,
wire_api = "responses"): https://help.aliyun.com/zh/model-studio/codex - Base URL overview (Token Plan OpenAI/Anthropic compatible endpoints): https://help.aliyun.com/zh/model-studio/base-url
- Token Plan Harness tools (Responses-only trigger): https://help.aliyun.com/zh/model-studio/token-plan-harness-tool
Suggested mapping or implementation notes
- The Responses-wire model list (qwen3.8/3.7/3.x, deepseek-v4.x, glm-5.3/5.2, kimi-k3) matches
ALIBABA_TOKEN_PLAN_MODELS, so a wire switch needs no new catalog. - There is precedent for mixed-wire registries:
modelWireDefaultsalready pins per-model wires for the GitHub Copilot entry (src/providers/registry/entries-extended.ts:1218), andsrc/config/schema/leaf-validators.tsdocuments DeepSeek routingdeepseek-v4-flashover native Responses for a Responses inbound while the provider-wide wire staysopenai-chat. The same mechanism fits the Token Plan entries. - Correction after deeper live verification: the per-model
modelAdaptersopt-in works today (verified on 2.59.0 with qwen3.8-flash and qwen3.7-plus). The provider-leveladapterfield does NOT switch the wire:routedProviderConfig()(src/router.ts) rebuilds matching registry providers withadapter: registryEntry.adapterat request time, so the registry value silently wins and a savedopenai-responsesis ignored. The request is therefore for a registry-side option (adapter flip ormodelWireDefaults) plus docs for themodelAdapterspath. - Suggested rollout: registry opt-in / documented preset → field validation with Codex App and CLI (custom tools, reasoning replay, streaming, multi-turn continuation — all four verified above) → flip the default.
Additional context and attachments
- [Bug] Xiaomi MiMo token-plan rejects Responses custom tools (400 responses_feature_not_supported) — works fully via openai-chat adapter; add preset/guidance #1158 is the reverse precedent (MiMo token-plan accepted plain Responses calls but rejected
type:"custom"tools withresponses_feature_not_supported). The same validation matrix was run against Alibaba's Token Plan gateway and passed on every axis. - The
alibaba(Coding Plan) entry is deliberately out of scope: Alibaba's own Codex guide still routes Coding Plan overwire_api = "chat"with legacy Codex 0.80.0. - Related history: Stale Alibaba Token Plan catalogs: phantom glm-5.3 rows, wrong qwen3.8-max window, missing callable ids #4787 (Alibaba catalog staleness), [Bug]: Alibaba Token Plan ignores Singapore baseUrl and forces Beijing endpoint at runtime #200 / alibaba-token-plan registry entry silently overrides saved baseUrl -> 401 after provider migration #457 (baseUrl handling).
Checks
- I searched existing provider and compatibility issues.
- The request and response were redacted.
- The expected behaviour is based on an upstream specification (Alibaba Model Studio documentation linked above).
Activity
github-actions commentedon Sep 19, 2026
Issue reopened
The report now contains the information required by the automated check. Thanks for updating it.
mdwsk88 commentedon Sep 19, 2026
Follow-up finding (same day, deeper verification): provider-level
adapteris silently normalized at request time.While testing, I pushed
adapter: "openai-responses"into the running proxy viaPOST /api/providersand confirmed the live row withGET /api/providers— requests still ran overopenai-chat. The cause isroutedProviderConfig()insrc/router.ts: when a provider's transport matches its registry entry, the resolved row is rebuilt withadapter: registryEntry.adapter, so the registry value wins over the configured one on every request.Consequences:
adapterfield cannot opt analibaba-token-planrow into the Responses wire at all today (GUI, CLI, or hand-edited file all get normalized away). Per-modelmodelAdapters— resolved afterroutedProviderConfig()(e.g.src/server/responses/request-prepare.ts:900) — is the only user-side switch. Verified with a second model:qwen3.7-plusviamodelAdapters→openai-responses, HTTP 200, the usage log records the responses wire.modelWireDefaults, or at minimum documentmodelAdaptersas the supported opt-in — the obvious provider-level field is currently a silent no-op for registry providers.I have corrected the affected sentence in the issue body accordingly.
feat(registry): pin live-verified Alibaba Token Plan models to the Re…
feat(registry): document and lock the Alibaba Token Plan Responses op…
Provider discovery and model surface: outbound User-Agent, Volcengine…
Ingwannu commentedon Sep 20, 2026
Tracked by PR #5188. The capability gap is real, including the current registry-authority behavior that prevents a provider-wide configured adapter from overriding the canonical entry while per-model overrides still work.
Do not flip the whole preset merely from route existence. The PR needs the primary-source evidence already supplied plus exact-field validation for both regional endpoints, custom tools, continuation, streaming terminal events, error normalization and credential destination. A staged model-level opt-in is preferable before a preset-wide default. #5188 is currently draft/conflicting, so keep this issue open until it is rebased, reviewed and validated.
fix(providers): bundle lane F1 — Cursor fast continuation, Meta Muse …
lidge-jun commentedon Sep 23, 2026
Fixed on
devby #5673 (squash-merged as 8ffd323, carrying #5188): Alibaba Token Plan (Beijing) now defaultsqwen3.8-flash,qwen3.7-plusandglm-5.3to native Responses for Responses inbound, with reasoning content preserved; Chat and Anthropic inbound stay on Chat, andmodelAdaptersstill overrides either way.