Repository navigation
fix(route): honor a custom table's wire on runtime routes - #7020
Merged
Hmbown merged 2 commits intoOct 18, 2026
Merged
Conversation
A named `[providers.<name>]` table with `wire = "responses"` (or
`"anthropic"`) minted a Chat Completions candidate: `RouteRequest` had no
wire channel, so `candidate.protocol()` came from Custom's
backward-compatible static policy, and every per-turn client built by
`CodewhaleClient::from_candidate` bound Chat regardless of the table's
dialect. The ambient spawn-time client (`provider_wire_format_for_config`)
and the capability reporter *did* honor the override, so a host that
resolves routes per turn silently POSTed `{base}/chat/completions` while
its config said Responses — and a cross-model rebind rebuilt the client
around the static protocol, downgrading the transport mid-session.
`RouteRequest` gains a `wire_override` honored only for
`ProviderKind::Custom` (built-ins keep their descriptor policy; a Chat
override cannot demote a fixed-Responses builtin either). The resolver
binds the Custom gate once so the protocol stamp cannot desync from it.
The tui route layer populates the override from the resolved identity's
scoped config — the same table `provider_wire_format_for_config` reads —
and the /provider picker's browsing receipts thread the row's own dialect,
so receipts, readiness, preflight, and the per-turn client all see one
protocol. The app-server `/v1/chat/completions` pass-through threads the
same override so a Responses-bound table fails closed at its Chat-only
guard instead of silently receiving a chat body. The client-internal model
re-resolution pins the transport's own wire for Custom clients, so an
engine-internal model switch cannot downgrade it; same-table per-request
switches that bypass rebind still fail closed at the protocol-mismatch
guard.
The per-config dialect parse moves into the config crate next to the field
it reads (`wire_dialect_override` plus the two alias predicates), replacing
the byte-identical private copies in the client, capability reader, and
dual-wire resolver so one alias list cannot drift. A misspelled dialect
keeps degrading to the static Chat policy, now with a warning naming the
table.
Pinned by resolver-level tests (override mints the wire, builtins ignore
it, unknown dialects degrade), the route-layer test asserting a
`wire = "responses"` table mints a Responses runtime route, and the shared
parse's alias/case/chat-arm tests.
Signed-off-by: asto <asto18089@126.com>
1 of 2 tasks
Collaborator
|
🤖 This reply is from Claude Opus 5.5, an AI agent working on behalf of the Codewhale maintainers. It is posted through @Hmbown's account, but Hunter did not write it. Merged in 53e4e5a. Thank you @asto18089. Giving — Written by Claude Opus 5.5 (AI agent) on behalf of the maintainers. |
Hmbown
pushed a commit
that referenced
this pull request
Oct 18, 2026
Adds [Unreleased] entries for #7014, #7015, #7017, #7018, #7019 and #7020, crediting @asto18089 (and @zhuowp for the fork ports). Each merged without a changelog line. The entry for #7020 names its behavior change: the app-server's legacy [providers.custom] table now refuses a non-Chat wire with provider_wire_format_unsupported instead of forwarding a Chat body. Refs #7014 Refs #7015 Refs #7017 Refs #7018 Refs #7019 Refs #7020 Refs #6997 Verified: sync-changelog --check up to date; web check-facts OK; check-contributor-credit "Every contributor in the window is credited on all three surfaces". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NBKbhx19BRbZtvWK8rVKjz
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
A named
[providers.<name>]table withwire = "responses"(or"anthropic") minted a Chat Completions candidate:RouteRequesthad no wire channel, socandidate.protocol()came from Custom's backward-compatible static policy, and every per-turn client built byCodewhaleClient::from_candidatebound Chat regardless of the table's dialect. The ambient spawn-time client (provider_wire_format_for_config) and the capability reporter did honor the override — so a host that resolves routes per turn silently POSTed{base}/chat/completionswhile its config said Responses, and a cross-model rebind rebuilt the client around the static protocol, downgrading the transport mid-session.RouteRequestgainswire_override, honored only forProviderKind::Custom(built-ins keep their descriptor policy; a Chat override cannot demote a fixed-Responses builtin either). The resolver binds the Custom gate once so the protocol stamp cannot desync from it.provider_wire_format_for_configreads — so receipts, preflight, readiness, and the per-turn client all see one protocol. The app-server/v1/chat/completionspass-through threads the same override, so a Responses-bound table fails closed at its Chat-only guard instead of silently receiving a chat body.wire_dialect_overrideplus the two alias predicates), replacing the byte-identical private copies in the client and capability readers so one alias list cannot drift. A misspelled dialect keeps degrading to the static Chat policy, now with a warning naming the table.Tests
chatdialects keep the static policy.wire = "responses"custom table mints a Responses runtime route; a typo'd dialect degrades to Chat.cargo test -p codewhale-config --locked177 passed; app-server suite 15 passed; targeted tui filters green; clippy-D warningsclean (config, app-server, tui lib).Ported from the Pinvou/CodeWhale fork (#79), rescoped: the fork's encrypted-reasoning capture widening already landed upstream (all Responses routes that send
includecapture now).Refs #6997