Skip to content

fix(providers): align Volcengine Coding Plan with Responses API - #5173

Closed
juzijia wants to merge 1 commit into
lidge-jun:devfrom
juzijia:fix/volcengine-coding-plan-responses-5159
Closed

juzijia wants to merge 1 commit into
lidge-jun:devfrom
juzijia:fix/volcengine-coding-plan-responses-5159

Conversation

@juzijia

@juzijia juzijia commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

Summary

  • switch the built-in Volcengine Ark Coding Plan preset to its documented native Responses endpoint at /api/coding/v3/responses
  • add a provider-scoped replay compatibility flag that drops returned Responses reasoning items for validated Ark Coding Plan tool continuations without enabling orphan tool repair
  • migrate the legacy canonical Chat preset once while preserving custom destinations, explicit per-model Chat overrides, and later operator wire choices
  • fail closed on unsupported service_tier and document the observed Ark continuation behavior

Closes #5159

Verification

  • bun test tests/gui/volcengine-providers.test.ts — 19 pass, 0 fail
  • focused Volcengine startup migration test — pass
  • focused Z.AI reasoning replay regression — pass
  • focused service-tier capability assertion — pass
  • bun run typecheck — pass
  • bun run structure:check — pass
  • bun test tests/test-layout.test.ts tests/test-layout-tooling.test.ts — 18 pass, 0 fail
  • git diff --check — pass

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • Docs or release notes were updated when needed.
  • Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults.

Review readiness checklist

This PR stays in draft until every box below is ticked. Tick all four boxes once the requirements are met:

  • All CI tests are green on my local testing.

  • I pushed my PR to the latest dev commit.

  • I resolved all correct Codex and CodeRabbit findings.

  • My PR is ready for review.

@coderabbitai

coderabbitai Bot commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added the intake: hygiene-blocked Deterministic PR hygiene checks failed label Sep 19, 2026
@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Deterministic hygiene checks failed.

  • unsponsored_surface — This changes an authentication, workflow, release-automation, or dependency surface. MAINTAINERS.md requires security review for these; ask a maintainer to apply maintainer-sponsored once they have reviewed it. Paths: src/server/auth-cors.ts.

@github-actions github-actions Bot added the bug Something isn't working label Sep 19, 2026
@github-actions

github-actions Bot commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

⏳ DRAFT

  • hygiene: unsponsored_surface.

What to do

  • Fix unsponsored_surface — This changes an authentication, workflow, release-automation, or dependency surface. MAINTAINERS.md requires security review for these; ask a maintainer to apply maintainer-sponsored once they have reviewed it. Paths: src/server/auth-cors.ts.
  • Tick all four boxes in the PR description once you're done (currently 0/4).

Review readiness checklist

  • ⬜ All CI tests are green on my local testing.
  • ⬜ I pushed my PR to the latest dev commit.
  • ⬜ I resolved all correct Codex and CodeRabbit findings.
  • ⬜ My PR is ready for review.

0/4 boxes ticked.

This pull request was already a draft. Its draft status will be preserved after every issue above is resolved.
@juzijia Tick the boxes once your local CI is green, your branch is on the latest dev commit, and every correct Codex and CodeRabbit finding is resolved.

@juzijia
juzijia force-pushed the fix/volcengine-coding-plan-responses-5159 branch from dd77038 to 5359da3 Compare September 19, 2026 13:36
@lidge-jun

Copy link
Copy Markdown
Owner

리뷰 · 우선순위 63 / 80

Volcengine 코딩 플랜의 기본 연결을, 채팅 완성에서 공식 문서가 말하는 Responses로 바꿉니다.

기본 주소는 https://ark.cn-beijing.volces.com/api/coding/v3 입니다. 지금까지 연결 방식은 openai-chat 이었습니다. 공식 Codex 설정은 이 주소에서 Responses를 쓰라고 합니다. 채팅 선으로 붙이면 GLM 계열에서 도구 인자 JSON이 깨지는 일이 있었습니다. Responses로 붙이면 그 오류는 안 났습니다. 대신 직전 답의 reasoning 조각을 다음 요청에 그대로 넣으면 Ark가 400 InvalidParameter를 돌려줍니다. 이 PR은 코딩 플랜 프리셋에서만 그 조각을 빼고 보냅니다. 채팅은 모델마다 직접 고르면 그대로 쓸 수 있습니다.

이미 설치된 설정은 제공자 이름이 volcengine-coding-plan이고 주소가 공식 주소일 때만, 서버가 켜질 때 한 번 옮깁니다. 키, 모델 목록, 모델별 채팅 선택은 남습니다. 옮긴 뒤 volcengineCodingPlanResponsesDefaultVersion을 1로 적어서, 사용자가 나중에 채팅으로 되돌려도 다음 부팅이 다시 Responses로 덮지 않습니다. 주소가 다른 줄과, 이름을 바꾼 줄은 그대로 둡니다.

service_tier는 이 프리셋에서 지원하지 않는 것으로 표시합니다. 문서에 없는 칸을 보내지 않기 위해서입니다.

PR은 아직 초안이고, 본문 준비 체크는 0/4입니다.

src/server/auth-cors.ts - 비밀번호나 로그인 규칙을 바꾼 것은 아닙니다. 새 칸 두 개를 설정 허용 목록에 넣었습니다. dropResponsesReasoningItems는 사용자가 고를 수 있는 editor, 이전 완료 숫자는 화면이 지우면 안 되는 runtime입니다. Z.AI가 쓰는 구분과 같습니다. 이 파일을 고치면 위생 검사가 unsponsored_surface로 실패합니다. 메인테이너가 보고 maintainer-sponsored를 달기 전에는 초안 상태에 남습니다.

src/adapters/openai-responses/reasoning.ts - 설명은 "다시 넣은 reasoning만 뺀다"인데, 코드는 매 요청 입력에서 typereasoning인 항목을 전부 지웁니다. 도구 이어하기가 아닌 첫 요청도 같고, deepseek-v4-flash도 같습니다. 이슈에서 재현된 400을 막는 범위와는 맞습니다. 레지스트리에 남은 preserveReasoningContentModels는 채팅 선에서 reasoning 글을 유지하는 목록이라, Responses가 기본이 되면 DeepSeek도 생각 내용을 다음 턴에 못 넘깁니다.

메인테이너의 판단이 필요한 지점

이름을 바꾼 옛 채팅 복사본을 자동으로 옮기지 않는 쪽이 맞는지입니다. 테스트는 Z.AI와 같이 "정식 이름만 옮긴다"로 고정해 두었습니다. 그 복사본은 도구 호출이 깨진 채팅 선에 남습니다. 공식 주소인데 responsesPath만 다르게 적어 둔 정식 이름은, 버전 숫자가 아직 없으면 한 번 /responses로 바뀝니다. Agent Plan 주소(/api/plan/v3)에는 같은 빼기를 넣지 않았습니다. 400 재현은 코딩 플랜 주소에서만 적혀 있습니다.

너의 추천

기본 선을 문서의 Responses로 맞추고, Ark가 거절하는 reasoning 재생은 이 제공자에만 끄는 쪽이 맞습니다. 한 번만 이전하기, 커스텀 주소는 두기, Z.AI는 reasoning을 유지하기, 짝 없는 도구 결과는 지우지 않기를 테스트가 잡고 있습니다. 코드 방향은 유지하면 됩니다. 머지 전에 메인테이너가 auth-cors.ts의 두 칸이 editor와 runtime으로 나뉜 것을 확인하고 maintainer-sponsored를 달면 위생 실패는 해소됩니다. 준비 체크 네 칸은 작성자가 채워야 합니다. Agent Plan에서 같은 400이 확인되기 전에는 플래그를 넓히지 않아도 됩니다.

이 댓글은 grok-bot이 작성했습니다

lidge-jun added a commit that referenced this pull request Sep 19, 2026
… registry and routing

Adversarial static review of the branch found the carried #5173 flag reached the
adapter but not three places that must know about it.

src/providers/registry/model-ids.ts classifies every ProviderRegistryEntry key
through a satisfies Record<keyof ProviderRegistryEntry, ...> clause. Adding
dropResponsesReasoningItems to the interface without classifying it does not
compile, and the parity test rejects an entry carrying an unclassified field.
The flag names no model id, so it is NONE.

The compatibility behavior record described reasoning replay through
preserveResponses alone, so two routes that disagree about whether replayed
reasoning items are dropped produced the same behavior fingerprint and could
share compatibility evidence. Dropping an item changes the continuation body, so
it is now part of reasoning.replayMode. The resolved static policy projection
omitted the field for the same reason and now carries it.

routedProviderConfig returns early for a row whose adapter no longer matches its
registry entry, which is exactly the shape this branch deliberately leaves alone:
a Volcengine Coding Plan config saved on Chat. That row still reaches the
Responses adapter when one model opts in through modelAdapters, and it arrived
without the flag, so the continuation forwarded the reasoning item Ark answers
400 to. The flag belongs to the destination rather than to the provider-wide
wire, so it is filled on that path too, from the destination matcher that already
refuses templated and overridable base URLs. An explicit value still wins.

Also updates the ja, ko, fr, ru and zh-TW provider guides, which still described
Agent Plan as the only native Responses preset and so contradicted the English
and zh-CN source, and softens an overclaiming test comment: the routing case
pins what a user observes, and the absence of a startup migration is the absence
of a module rather than something that case can prove.
lidge-jun added a commit that referenced this pull request Sep 19, 2026
… Responses API

Ark Coding Plan documents a native Responses endpoint at /api/coding/v3/responses,
but the built-in preset still shipped openai-chat, so Codex clients paid for a
translation hop the gateway does not need (#5159). The preset now carries
adapter openai-responses with responsesPath /responses, declares
supportsServiceTier: false so an unsupported service_tier fails closed instead of
reaching the gateway, and keeps the retired Chat destination as an alias so an
existing row still resolves this entry's metadata.

Validated Ark continuations reject the reasoning item the previous turn returned,
answering 400 InvalidParameter, so the entry sets a new provider-scoped
dropResponsesReasoningItems flag. It removes replayed reasoning items from
continuation input without enabling orphan tool repair. The flag is lossy --
summaries, item ids and encrypted_content go with the item -- so it is documented
as such in the configuration reference and an operator can set it to false.

Carried from #5173 with the startup config migration removed. That migration
would have rewritten every stored canonical Chat row to Responses on the next
boot. It borrowed the shape of the Z.AI wire migration while inverting the
property that makes that one safe: zai-responses-migration.ts gates on
providerMatchesRegistryTransport and therefore only rewrites rows the router
already canonicalizes at request time, which is why its comment can call itself
behavior-preserving by construction. A Volcengine Chat row is not canonicalized
-- volcengine-coding-plan is a preserveCustomDestination key entry, so the
adapter mismatch makes routedProviderConfig return the stored row untouched --
and a version marker introduced now cannot distinguish the old default from a
deliberate pre-upgrade Chat choice. The preset default therefore applies to new
rows only, existing rows keep their wire, and the docs say how to switch by hand.
Dropping that migration also drops the src/server/index.ts hunk, which would have
taken the file from 892 to 895 lines against its 893-line ratchet cap once merged
with dev.

Closes #5159

Co-authored-by: cubebox <58514883+juzijia@users.noreply.github.com>
lidge-jun added a commit that referenced this pull request Sep 19, 2026
… registry and routing

Adversarial static review of the branch found the carried #5173 flag reached the
adapter but not three places that must know about it.

src/providers/registry/model-ids.ts classifies every ProviderRegistryEntry key
through a satisfies Record<keyof ProviderRegistryEntry, ...> clause. Adding
dropResponsesReasoningItems to the interface without classifying it does not
compile, and the parity test rejects an entry carrying an unclassified field.
The flag names no model id, so it is NONE.

The compatibility behavior record described reasoning replay through
preserveResponses alone, so two routes that disagree about whether replayed
reasoning items are dropped produced the same behavior fingerprint and could
share compatibility evidence. Dropping an item changes the continuation body, so
it is now part of reasoning.replayMode. The resolved static policy projection
omitted the field for the same reason and now carries it.

routedProviderConfig returns early for a row whose adapter no longer matches its
registry entry, which is exactly the shape this branch deliberately leaves alone:
a Volcengine Coding Plan config saved on Chat. That row still reaches the
Responses adapter when one model opts in through modelAdapters, and it arrived
without the flag, so the continuation forwarded the reasoning item Ark answers
400 to. The flag belongs to the destination rather than to the provider-wide
wire, so it is filled on that path too, from the destination matcher that already
refuses templated and overridable base URLs. An explicit value still wins.

Also updates the ja, ko, fr, ru and zh-TW provider guides, which still described
Agent Plan as the only native Responses preset and so contradicted the English
and zh-CN source, and softens an overclaiming test comment: the routing case
pins what a user observes, and the absence of a startup migration is the absence
of a module rather than something that case can prove.
lidge-jun added a commit that referenced this pull request Sep 19, 2026
… Responses, Token Plan opt-in, Command Code ladders (#5198)

* fix(transport): fill a default User-Agent on proxy-originated provider outbound

Proxy-originated provider requests -- model discovery, connection tests, the
Ollama show probe, the Antigravity quota probe -- are assembled by the proxy
itself, so there is no client request to inherit a User-Agent from, and the
pinned Node-style transport sends none. WAF-fronted gateways answer a UA-less
request with 403, which surfaces as "provider added but no models" because the
pending initial-model-selection state hides every row (#5104).

The outbound wrapper now fills User-Agent: opencodex when the caller names no
User-Agent of its own. The check is case-insensitive and covers all three
HeadersInit shapes, so registry static headers, provider headers values, and
vendor client fingerprints (Copilot, Kimi CLI, Antigravity) keep their value and
never gain a second User-Agent beside it. Inference traffic never reaches this
wrapper: its only call sites are catalog model discovery, the management
connection test, the Antigravity quota probe, and the Ollama show enrichment.

Carried from #5186 with two corrections. The regression suite now also asserts
the caller-owned-executor branch, which leaves the wrapper without touching the
pinned transport the original tests stubbed -- a fill applied only on the pinned
path would have left that branch UA-less and still 403 behind the same WAF. And
the claim that a caller keeps its header-name spelling is dropped from the
comment, the structure doc, and a test name: the pinned and SOCKS transports
both rebuild the set through new Headers(), which lowercases every name, so the
value is what survives.

Closes #5104

Co-authored-by: mdwsk88 <11055210+mdwsk88@users.noreply.github.com>

* fix(providers): point the Volcengine Coding Plan preset at the native Responses API

Ark Coding Plan documents a native Responses endpoint at /api/coding/v3/responses,
but the built-in preset still shipped openai-chat, so Codex clients paid for a
translation hop the gateway does not need (#5159). The preset now carries
adapter openai-responses with responsesPath /responses, declares
supportsServiceTier: false so an unsupported service_tier fails closed instead of
reaching the gateway, and keeps the retired Chat destination as an alias so an
existing row still resolves this entry's metadata.

Validated Ark continuations reject the reasoning item the previous turn returned,
answering 400 InvalidParameter, so the entry sets a new provider-scoped
dropResponsesReasoningItems flag. It removes replayed reasoning items from
continuation input without enabling orphan tool repair. The flag is lossy --
summaries, item ids and encrypted_content go with the item -- so it is documented
as such in the configuration reference and an operator can set it to false.

Carried from #5173 with the startup config migration removed. That migration
would have rewritten every stored canonical Chat row to Responses on the next
boot. It borrowed the shape of the Z.AI wire migration while inverting the
property that makes that one safe: zai-responses-migration.ts gates on
providerMatchesRegistryTransport and therefore only rewrites rows the router
already canonicalizes at request time, which is why its comment can call itself
behavior-preserving by construction. A Volcengine Chat row is not canonicalized
-- volcengine-coding-plan is a preserveCustomDestination key entry, so the
adapter mismatch makes routedProviderConfig return the stored row untouched --
and a version marker introduced now cannot distinguish the old default from a
deliberate pre-upgrade Chat choice. The preset default therefore applies to new
rows only, existing rows keep their wire, and the docs say how to switch by hand.
Dropping that migration also drops the src/server/index.ts hunk, which would have
taken the file from 892 to 895 lines against its 893-line ratchet cap once merged
with dev.

Closes #5159

Co-authored-by: cubebox <58514883+juzijia@users.noreply.github.com>

* feat(registry): document and lock the Alibaba Token Plan Responses opt-in

Alibaba Token Plan (Beijing) serves its models over an OpenAI-compatible
Responses API on the same /compatible-mode/v1 base and ships an official Codex
integration guide on wire_api = "responses". Three models carry live end-to-end
evidence on that gateway -- qwen3.8-flash, qwen3.7-plus and glm-5.3 -- covering
custom tools, reasoning replay, streaming and multi-turn continuation (#5097).

The issue asked for a validated opt-in or a default flip. This lands the opt-in
and deliberately declines the flip. #5188 proposed pinning those three models
through modelWireDefaults, which would move every existing Codex user of them
onto a different upstream with no config change, and one delta is unresolved:
the entry's preserveReasoningContentModels is read by the CHAT adapter, while
the Responses serializer reads preserveResponsesReasoningContent, which this
entry does not set. Pinned models would therefore replay with blanked reasoning
content -- strictly less state than they carry on the Chat wire today. Z.AI and
DeepSeek set both flags together, and their entry comments say why. Blanking is
the fail-safe direction, so leaving the default alone costs nobody a working
setup; setting the Responses flag on faith could 400 a continuation.

The registry entry records the evidence and the open precondition, the
modelAdapters reference documents the opt-in, and the new suite holds both
halves: the three models resolve to openai-responses once opted in and the
request actually reaches /responses rather than being flipped back by the
handleResponses replay, the wire default stays Chat on every inbound, and a
guard fails if a Responses wire default is ever declared for this entry without
preserveResponsesReasoningContent beside it.

Refs #5097

Co-authored-by: mdwsk88 <11055210+mdwsk88@users.noreply.github.com>

* fix(command-code): let an operator ladder outrank the shipped effort table at the wire

The Command Code adapter resolved its wire effort as
commandCodeReasoningEfforts() ?? configuredReasoningEfforts(), so a model WITH a
row in the shipped table ignored providers.command-code.modelReasoningEfforts
outright while a model WITHOUT one honoured it. The catalog never agreed with
that split: it advertises the picker from configuredReasoningEfforts, so an
operator who widened a pinned row saw the wider ladder offered in Codex and then
watched the adapter strip the rung on the way out, with no error to explain it
(#5096).

An operator row now resolves through the same function the catalog uses, so the
picker and the wire cannot disagree, and sanitization, tier healing and
learned-refusal dropping apply to it. Rows the operator never touched keep the
shipped table, including a value learned by a profile refresh.

The seeded copy is what makes this subtle, and it is why a plain config-first
flip would have been wrong: providerConfigSeed writes the whole shipped table
into every materialized preset, so "the config has a row for this model" proves
nothing about who wrote it. Only a row that DIFFERS from the shipped value counts
as a decision, and the comparison is against the shipped value rather than the
resolved one so that a profile refresh narrowing a ladder is never mistaken for
an operator edit. A regression case asserts that a preset carrying the seeded
table produces byte-identical wire efforts to carrying no config at all.

An operator-authorized rung also stops being silently downgraded. The
effort-rejection path exists for rungs the shipped table guessed wrong, where
replaying without the effort is a repair; when the operator wrote the ladder, the
same replay would answer at the provider default and hide a wrong configuration
behind a successful-looking response, so the upstream rejection is returned
unchanged and no profile fetch is made.

Scope: this closes the structural half of #5096 only. The issue also reports that
seven shipped rows are narrower than the live API accepts and that 38 live models
have no row. Those rows are not adopted here. The table's own provenance rules
require per-row evidence, the measurements are a third party's and cannot be
reproduced without a GOAT-plan key, the ids double as the router's known-ids
decode source via knownModelIdsForProvider so a mis-cased id has routing
consequences, and at least one proposed widening contradicts an alias this file
documents from the model profile (xhigh -> max on deepseek/deepseek-v4-flash).
With this change an operator can apply the measured ladders from config today,
and the reporter offered to open the full 46-model table as its own PR, which is
where that provenance belongs.

Refs #5096

* fix(providers): finish wiring the Volcengine replay-drop flag through registry and routing

Adversarial static review of the branch found the carried #5173 flag reached the
adapter but not three places that must know about it.

src/providers/registry/model-ids.ts classifies every ProviderRegistryEntry key
through a satisfies Record<keyof ProviderRegistryEntry, ...> clause. Adding
dropResponsesReasoningItems to the interface without classifying it does not
compile, and the parity test rejects an entry carrying an unclassified field.
The flag names no model id, so it is NONE.

The compatibility behavior record described reasoning replay through
preserveResponses alone, so two routes that disagree about whether replayed
reasoning items are dropped produced the same behavior fingerprint and could
share compatibility evidence. Dropping an item changes the continuation body, so
it is now part of reasoning.replayMode. The resolved static policy projection
omitted the field for the same reason and now carries it.

routedProviderConfig returns early for a row whose adapter no longer matches its
registry entry, which is exactly the shape this branch deliberately leaves alone:
a Volcengine Coding Plan config saved on Chat. That row still reaches the
Responses adapter when one model opts in through modelAdapters, and it arrived
without the flag, so the continuation forwarded the reasoning item Ark answers
400 to. The flag belongs to the destination rather than to the provider-wide
wire, so it is filled on that path too, from the destination matcher that already
refuses templated and overridable base URLs. An explicit value still wins.

Also updates the ja, ko, fr, ru and zh-TW provider guides, which still described
Agent Plan as the only native Responses preset and so contradicted the English
and zh-CN source, and softens an overclaiming test comment: the routing case
pins what a user observes, and the absence of a startup migration is the absence
of a module rather than something that case can prove.

* fix(command-code): make the operator ladder override an explicit declaration

Adversarial static review rejected the provenance test the previous commit used.
It decided a configured row was an operator decision when that row DIFFERED from
the shipped table. That is not sound: providerConfigSeed copies the whole table
into every materialized preset, and enrichment (derive.ts) and routing
(mergeStringArrayRecord) both keep a persisted row over the current seed. A row
written by an older release therefore keeps its old value, and the moment the
shipped table is corrected that untouched seed starts looking like an operator
edit -- at which point it would outrank the correction AND disable the
effort-rejection repair. The follow-up this issue asks for is exactly a table
correction, so the misfire was not hypothetical.

Provenance is now declared instead of inferred. A provider opts in with
modelReasoningEffortsAuthoritative, which providerConfigSeed never writes, so its
presence can only have come from a human. Without it a configured row changes
nothing at the wire, seeded or stale or hand-written; with it, the ladder
resolves through the same function the catalog uses and a refused rung returns
the upstream error rather than being replayed without the effort.

Also fixes an alias asymmetry the override made reachable. The xhigh branch
aliases to max only when the ladder does not advertise xhigh, but the ultra
branch aliased whenever max existed. An authoritative ladder offering ultra would
have advertised ultra in the picker and quietly sent max -- the same
catalog/wire disagreement this change exists to remove. No shipped row offers
ultra, so the built-in table is unaffected.

The regression cases follow: an authoritative ladder widens, narrows, and sends
ultra as itself; a seeded map and a fully widened stale map both produce
byte-identical wire efforts to carrying no config at all; and an authorized rung
the upstream refuses surfaces the 400 with one generate call and no profile
fetch.

Refs #5096

* fix(compat): record the Command Code ladder authority in behavior identity

Three independent adversarial reviews converged on the same gap: commit 6 added
a flag that changes the wire effort AND suppresses the downgrade retry, but the
compatibility resolver recorded only the configured ladder. Two routes with the
same provider, destination, adapter, model and ladder therefore produced the same
behavior fingerprint while sending different bytes and recovering differently, so
evidence collected under one could admit the other. That is the same defect class
commit 5 fixed for dropResponsesReasoningItems, left unfixed for its sibling.

reasoning.effortsAuthoritative joins the closed behavior key set and is emitted
from the production resolver, and the resolved static policy carries the flag as
an operator-owned value so a policy reader no longer reports the same effective
ladder for two providers that send different efforts.

Also documents both new contracts in structure/providers-and-adapters.md, which
owns this source area: the Coding Plan native Responses default, the lossy
replay drop and why it is filled on the early-return path, why there is no
startup migration, and why the Command Code ladder override is a declared flag
rather than an inference. Softens the dropResponsesReasoningItems reference row,
which promised the upstream sees no previous-turn reasoning state at all — the
flag removes reasoning items from the forwarded input and does not touch
previous_response_id. Corrects a test comment left describing the provenance
inference commit 6 replaced.

* docs: recount the provider preset totals from the registry and pin them

Seventeen pages restate how many built-in presets ship, and sixteen of them had
drifted. The English provider guide said 95 total with 79 key-based; the ja, ko,
fr, ru, tr, zh-CN and zh-TW guides, all eight quickstarts including the English
one, and structure/ops/docs-and-release.md still said 94 and 78. Nothing caught
it, because both numbers read as plausible and no check compared either to the
registry.

The registry says 95. Every authKind declaration in the two entry files that
compose PROVIDER_REGISTRY is a string literal, and they group as 79 key, 12
oauth, 3 local, 1 forward, which is what the English guide already claimed. The
other sixteen places now say the same.

AGENTS.md asks for a count to be derived from the thing it describes rather than
restated, and this is the failure it describes: a preset lands, whoever adds it
updates the English guide, and fifteen translated or secondary copies quietly
keep the old number. A new ci-workflows check derives the total and the
key-based split from PROVIDER_REGISTRY and asserts them against each page, so
the next preset fails every locale at once instead of drifting. Each page is
located by a locale-specific phrase rather than by its number, so rewording a
sentence fails the check and asks to be re-anchored — a sentence nobody can
locate is a sentence nobody is checking.

* docs: keep the structure preset-split line on one line for its own check

The new count check locates each page by a locale-specific phrase and asserts
exactly one line carries it. Rewording the structure ops sentence pushed
"documented split is" across a line break, so the anchor matched nothing and the
check failed in test 2/4 and macos 1/2 — which is the behavior it was written
for: a sentence nobody can locate is a sentence nobody is checking. Reflowed so
the anchor, the total and the key-based split sit on one line again.

---------

Co-authored-by: lidge-jun <lidge-jun@users.noreply.github.com>
Co-authored-by: mdwsk88 <11055210+mdwsk88@users.noreply.github.com>
Co-authored-by: cubebox <58514883+juzijia@users.noreply.github.com>
@lidge-jun

Copy link
Copy Markdown
Owner

The preset change from this PR landed on dev as part of #5198, squash-merged as 98b9b344e1, with a Co-authored-by trailer naming you. It closes #5159.

One part was deliberately not carried, and you deserve the reasoning rather than a silent omission. The startup migration that rewrites stored canonical Volcengine Chat rows to Responses copies the shape of the Z.AI wire migration but inverts what makes that one safe. zai-responses-migration.ts gates on providerMatchesRegistryTransport, 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 actively using, and a version marker added now cannot distinguish the old default from a deliberate pre-upgrade decision to stay on Chat.

So the preset default applies to new rows and the documentation explains the manual switch. If you want the migration, the precondition is a gate that can tell those two cases apart; that is a separate change and worth its own discussion.

Closing because the preset change is on dev. Thank you for the fix.

@lidge-jun lidge-jun closed this Sep 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working intake: hygiene-blocked Deterministic PR hygiene checks failed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants