Repository navigation
fix(volcengine): align Coding Plan preset with native Responses API #5159
Description
Client or integration
Direct HTTP client (validated through OpenCodex's Responses endpoint; the original incompatibility was observed from a Pi/Codex-compatible client path).
Provider or upstream service
Volcengine Ark Coding Plan (volcengine-coding-plan)
OpenCodex version
2.59.0
Endpoint or capability
Volcengine Coding Plan native Responses endpoint and tool-call continuation:
- Upstream base:
https://ark.cn-beijing.volces.com/api/coding/v3 - Expected Responses resource:
/responses - Full upstream URL:
https://ark.cn-beijing.volces.com/api/coding/v3/responses - Capabilities involved: Responses wire selection, streaming tool calls, function-call continuation, reasoning-item replay
Current behaviour
Volcengine's current Coding Plan Codex documentation specifies the Responses wire protocol, but OpenCodex 2.59.0 still presets volcengine-coding-plan to openai-chat.
Current built-in preset:
provider: volcengine-coding-plan
baseUrl: https://ark.cn-beijing.volces.com/api/coding/v3
adapter: openai-chat
On the existing Chat translation path, GLM-5.3 has produced real streamed tool-call failures such as:
upstream_server_error: upstream stream produced malformed tool call arguments
To isolate the wire protocol, I added a separate non-default test provider without modifying the production provider:
adapter: openai-responses
baseUrl: https://ark.cn-beijing.volces.com/api/coding/v3
responsesPath: /responses
Native Responses then succeeded for all three Coding Plan models used in this environment:
deepseek-v4-flash: HTTP 200, exact smoke response,sendCount=1, no recovery.glm-5.3: HTTP 200 function call with valid JSON arguments; continuation HTTP 200; no malformed tool-call error.glm-5.3-flash: HTTP 200 function call and continuation; valid JSON arguments; no malformed tool-call error.
A second compatibility issue was also reproduced on the native Responses path: replaying the full prior reasoning output item together with function_call_output caused Ark to return 400 InvalidParameter. Replaying only the required function_call plus function_call_output succeeded with HTTP 200.
Expected behaviour
The built-in volcengine-coding-plan preset should follow Volcengine's current Codex documentation and use native Responses by default.
Expected provider behaviour:
adapter: openai-responses
baseUrl: https://ark.cn-beijing.volces.com/api/coding/v3
responsesPath: /responses
This must resolve to:
https://ark.cn-beijing.volces.com/api/coding/v3/responses
Tool-call continuations should also apply provider-scoped reasoning replay handling compatible with Ark: do not forward a replayed reasoning item in the form that Ark rejects, while preserving the function_call + function_call_output continuation.
Chat should remain available as an explicit compatibility/per-model fallback where the existing OpenCodex routing model supports it, similar in design intent to the Z.AI Responses migration in #4307.
Minimal redacted request or reproduction
# 1. Current built-in OpenCodex provider (2.59.0)
# volcengine-coding-plan:
# baseUrl=https://ark.cn-beijing.volces.com/api/coding/v3
# adapter=openai-chat
#
# 2. Add a separate TEST-only provider (not default; production provider unchanged):
# adapter=openai-responses
# baseUrl=https://ark.cn-beijing.volces.com/api/coding/v3
# responsesPath=/responses
#
# 3. Minimal Responses smoke request through OpenCodex:
curl -sS http://127.0.0.1:10100/v1/responses \
-H 'Authorization: Bearer <redacted>' \
-H 'Content-Type: application/json' \
-d '{
"model": "volcengine-coding-plan-responses-test/deepseek-v4-flash",
"input": "Reply exactly: RESPONSE-SMOKE-OK"
}'
# Result:
# HTTP 200
# resolved upstream:
# https://ark.cn-beijing.volces.com/api/coding/v3/responses
# output:
# RESPONSE-SMOKE-OK
# 4. GLM-5.3 function-call validation:
# echo({"value":"GLM-RESPONSES-OK"})
# Initial tool call: HTTP 200
# arguments: {"value":"GLM-RESPONSES-OK"}
# continuation without replayed reasoning item: HTTP 200
#
# Replaying the full prior reasoning item + function_call_output:
# HTTP 400 InvalidParameterActual response or error
# Existing Chat translation path, observed on GLM-5.3:
upstream_server_error: upstream stream produced malformed tool call arguments
# Native Responses compatibility test:
# full prior reasoning item + function_call_output
HTTP 400 InvalidParameter
# Same native Responses continuation after omitting the rejected reasoning item:
HTTP 200
completed
# Native Responses smoke/tool-call validation:
deepseek-v4-flash: HTTP 200
glm-5.3: HTTP 200 / HTTP 200 continuation
glm-5.3-flash: HTTP 200 / HTTP 200 continuationUpstream documentation
Volcengine Coding Plan Codex documentation:
https://docs.volcengine.com/docs/ark/coding-plan-personal-ai-codex?lang=zh
The current documented Codex configuration specifies:
base_url = "https://ark.cn-beijing.volces.com/api/coding/v3"
wire_api = "responses"Suggested mapping or implementation notes
The provider preset is now behind the upstream Codex integration documentation.
Suggested direction:
- Make native Responses the default wire for
volcengine-coding-plan. - Set
responsesPath: "/responses". - Keep the existing Chat wire available as an explicit compatibility/per-model fallback where supported.
- Use the Z.AI migration in feat(zai): default to the Responses protocol and keep Chat as a per-model opt-in #4307 as the design reference for Responses-by-default plus fallback, but do not copy its reasoning replay policy blindly: Z.AI accepts preserved plaintext reasoning replay, while Ark Coding Plan rejected the reproduced reasoning-item replay with
400 InvalidParameter. - Apply a provider-scoped Responses replay sanitization rule for Ark rather than a GLM-model-specific hard-coded branch.
- Add focused regression coverage for preset wire selection, resolved URL, tool-call continuation, Ark reasoning replay handling, and explicit Chat override.
I am not claiming the Chat translation path is the sole cause of every previously observed malformed tool-call failure. The compatibility gap is independently established by the upstream wire change, and native Responses was validated locally for the three models above.
Additional context and attachments
Related OpenCodex design reference: #4307 (Z.AI Responses migration).
Local validation safety:
- The production
volcengine-coding-planprovider remained unchanged. - The test provider was additive and was not made default.
- OpenCodex was not restarted.
- No production source/configuration was overwritten.
- No stress test or large-output reproduction was required.
Checks
- I searched existing provider and compatibility issues.
- The request and response were redacted.
- The expected behaviour is based on an upstream specification or a concrete client requirement.
Activity
github-actions commentedon Sep 19, 2026
Issue reopened
The report now contains the information required by the automated check. Thanks for updating it.
fix(providers): point the Volcengine Coding Plan preset at the native…
Provider discovery and model surface: outbound User-Agent, Volcengine…
lidge-jun commentedon Sep 19, 2026
Closed by #5198, squash-merged into
devas98b9b344e1. Carried from #5173 with the author credited.The Volcengine Coding Plan preset now targets the native Responses wire. One part of the submitted change was deliberately dropped, and it is the part worth explaining.
#5173 shipped a startup migration that would rewrite every stored canonical Volcengine Chat row to Responses on the next boot. It copies the shape of the Z.AI wire migration, but inverts what makes that one safe:
zai-responses-migration.tsgates onproviderMatchesRegistryTransport, so it only rewrites rows the router already canonicalizes at request time — its own comment calls that behaviour-preserving by construction. A Volcengine Chat row is not canonicalized, so migrating it changes a wire an operator is actually using, and a version marker added today cannot distinguish the old default from a deliberate pre-upgrade choice to stay on Chat.So the preset default applies to new rows only, and the documentation says how to switch an existing row by hand. Dropping the migration also removed a
src/server/index.tshunk that would have taken that file from 892 to 895 lines against its 893-line ratchet cap once merged withdev.Evidence is exact-head hosted CI at
6861bc3fd087f4...:test 1/4through4/4,gates,structure gateandmacos 1/2all successful. No local suite was run in this lane.