fix(custom): support wire = "responses" | "anthropic" for kind="openai-compatible" - #5714
fix(custom): support wire = "responses" | "anthropic" for kind="openai-compatible"#5714whp233 wants to merge 3 commits into
Conversation
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
…nd="openai-compatible" Custom provider was fixed to ChatCompletions, ignoring providers.<name>.wire. Now honors per-config wire in both client::provider_wire_format_for_config and config::provider_capability, keeping Custom::wire_policy default as Chat for compat. Aliases: responses/openai-responses/responses-api -> Responses; anthropic/messages/claude -> AnthropicMessages; default -> Chat. Fixes custom muse-spark-1.2 on opencode.ai/zen/v1 needing Responses. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Thanks @whp233 for taking the time to contribute. This repository is observing a maintainer-managed PR intake gate in dry-run mode, so this pull request is staying open. This note helps maintainers prepare the allowlist before any enforcement is considered. Please read |
…="openai-compatible" (Hmbown#5714)
The contribution gate leaves an unlisted contributor's workflow runs at `action_required`, so their CI never starts and the PR sits looking stalled through no fault of theirs. whp233's #5714 and #5716 had SEVEN workflows each parked that way; I approved those runs by hand, but the allowlist is the actual fix. Added (all five have landed or open work): whp233 open PRs #5714, #5716 — the runs that were parked musichen merged #5689 (DeepSeek configured-view picker) M-Maciej merged #5591 (goal continuation cadence) serephus merged #5669 (nixpkgs update) Pinvou fork owner behind #5686 (Moonshot/Kimi native search) Entries use `all:` to match the existing convention for active contributors. No-Issue: contribution-gate hygiene; no issue tracks it Signed-off-by: CodeWhale Bot <bot@codewhale.net>
Every rule here is something that actually went wrong on the 2026-08-29 night shift, written down so the next agent does not rediscover it. Landing other people's work: - A contributor's branch goes stale because WE land things. #5686 was CONFLICTING purely from Route Contract Phase 1 plus that same contributor's own earlier PRs merging into the same files. A maintainer resolves that. - Conflicts that split mid-function do not resolve by keeping both sides — the markers landed inside two function bodies and the naive resolution failed to compile with 'unclosed delimiter'. Take one side whole, re-insert the other's additions at their anchor. - maintainerCanModify did not grant push access to the fork (403), so the resolved merge went to integration/moonshot-kimi-5686-20260829 instead. That integration-branch path is now the documented default for conflicted work. - whp233's #5714 and #5716 each had SEVEN workflows parked at action_required because the author was not on .github/APPROVED_CONTRIBUTORS. The PRs looked stalled; nobody had looked. Five contributors have since been added. - Credit is mechanical: AUTHOR_MAP and .mailmap are project conventions and GitHub reads neither for the contribution graph. Merging under a gate: - #5698 merged while ACCEPTANCE_MATRIX.md still said FAIL and 37 minutes after a review confirming five findings were unchanged. Five real bugs reached main. A gate is its artifact, and check rollups are not the review thread. Claiming a test passed: - cargo test with a non-matching filter exits 0 having run ZERO tests; that was briefly mistaken for a pass here. - A harness scored 72 PASS of which 12 were never evaluated: 'ok = ok and X or True' parses as '(ok and X) or True'. CLAUDE.md already imports this file, so no second entrypoint was created. No-Issue: process documentation from the night shift Signed-off-by: CodeWhale Bot <bot@codewhale.net>
…rule scripts/check-coauthor-trailers.py rejects bot/tool co-author trailers because those trailers feed the GitHub contribution graph and are for humans. That rule was documented nowhere a contributor would look — CONTRIBUTING.md mentioned Co-authored-by only under harvesting, i.e. how WE credit THEM. The cost is real and current: whp233's #5714 and #5716 both fail Lint solely because their assistant appended 'Co-authored-by: Claude <noreply@anthropic.com>' to 3 and 4 commits respectively. Their code is fine. They had no way to know, and this will catch every contributor who uses an AI assistant — which is most of them now. Adds the rule to the Commit Messages section with the exact rebase command, and restates that co-authoring a person requires their GitHub-linked noreply address or the credit silently does not register. No-Issue: contributor documentation gap found while triaging #5714/#5716 Signed-off-by: CodeWhale Bot <bot@codewhale.net>
|
Closing as superseded by #5716 — verified, not assumed: of #5716's 8 files, the 4 this PR touches ( Full credit to @whp233 for the wire-dialect design — the Both PRs are red on the same checks (Lint, Tests ×3); the fix-forward is running on #5716's lane against current main (it is the superset). Nothing is lost by closing this one — the commits stay, and #5716's merge will carry the work. |
fix(custom): support wire = "responses" | "anthropic" for kind="openai-compatible"
Summary / 摘要
Custom provider (
kind = "openai-compatible") currently only supports Chat Completions wire. 配置wire = "responses"/"anthropic"被忽略,始终走ChatCompletions,导致需要 Responses 或 Anthropic Messages 的模型(如muse-spark-1.2onopencode.ai/zen/v1)无法在 custom provider 下工作。Custom provider (
kind="openai-compatible") only speaks Chat Completions, ignoringwiresetting. Models requiring Responses / Anthropic wire (e.g.muse-spark-1.2viaopencode.ai/zen/v1) cannot be used ascustom.Reproduction / 复现
Minimal
config.toml:Steps:
codewhale --provider myspark(or set as default)codewhale doctor --verbose/v1/chat/completionsinstead of/responsesor/v1/messagesExpected / 期望
wire = "responses"(alsoresponse,openai-responses) →WireFormat::Responses, requests hit/responses(OpenAI Responses API, likeopenai_codex).wire = "anthropic"/"messages"/"anthropic-messages"→WireFormat::AnthropicMessages, requests hit/v1/messages.wireomitted /"openai"/"chat"/"chat_completions"→WireFormat::ChatCompletions(default, backward compatible).Actual / 实际
Always
WireFormat::ChatCompletionsregardless ofwirevalue. 对opencode.ai/zen/v1+muse-spark-1.2这类 Responses-Anthropic hybrid 网关,请求 400/404 或unsupported wire,因为服务端期望 Responses/Anthropic payload 而收到 Chat Completions schema.Root cause / 根因
crates/config/src/provider.rs:1651-1653:Custom::wire_policy()isFixed(ChatCompletions), soWirePolicy::resolve()never consultsproviders.<name>.wire.crates/tui/src/config.rs&crates/tui/src/client.rsresolvewire_formatviaprovider.wire_policy()+provider_wire_format_for_config(), but Custom never reaches theModelAware/wire_config_prefers_anthropicpath.providers.<name>.wireis parsed & stored inlib.rs(ProviderConfigToml::wire) yet never read for Custom.OpencodeZen→ModelAware,OpenaiCodex→Fixed(Responses),Anthropic→Fixed(AnthropicMessages)) demonstrate the wire abstraction already exists; Custom is the outlier.Proposed fix / 修复建议
Branch:
fix/custom-wire-responses(ormainwith following changes)crates/config/src/provider.rs—Custom::wire_policyMake Custom respect
wirefield: eitherModelAwareorFixedwith override viawirestring. Suggested mapping (reuseWirePolicy::resolvekeys):responses→Responsesanthropic/messages/anthropic_messages/anthropic-messages→AnthropicMessageschat/chat_completions/openai/ empty →ChatCompletions(default)crates/tui/src/config.rs—provider_wire_format_for_config/wire_config_prefers_anthropicEnsure
ApiProvider::Custompath readsconfig.wire(like dual-wire vendors do). Normalize aliases (wire,wire_format,api_stylealready aliased inconfig_document.rs).crates/tui/src/client.rs— dispatch & validationNo wire-specific hardcoding for Custom; rely on resolved
wire_formatformatch self.wire_format { ChatCompletions | Responses | AnthropicMessages }→ correct body builder / endpoint. Keepvalidate_route/ limits intact.Backward compat: 无
wire时保持ChatCompletions,不影响现有 custom 用户。Workaround / 临时绕过
Reuse the existing
Responses-fixed built-in provideropenai_codex+ env override (since Custom is blocked):或直接改 env 启动:
原理:
OpenaiCodex::wire_policy = Fixed(Responses)天然走/responses,绕过 Custom 的 Fixed-Chat 限制。For Anthropic wire, useproviders.anthropicsimilarly if gateway supports it.缺点:占用
openai_codex槽位,不能同时配多个 custom Responses 网关;env 覆盖对多路由不友好。Related files / 相关文件
crates/config/src/provider.rs—Customstruct &wire_policy()(root cause)crates/tui/src/config.rs—provider_wire_format_for_config(),wire_config_prefers_anthropic(),ProviderConfigToml::wirehandlingcrates/tui/src/client.rs—provider_default_wire_format(),DeepSeekClient::wire_formatdispatch (ChatCompletions/Responses/AnthropicMessages)crates/config/src/lib.rs—ProviderKind::Custom,ProviderConfigToml,wirefield definitionEnvironment
main@a0341b5a4(pre-fix) / branchfix/custom-wire-responseskind = "openai-compatible"(Custom) →opencode.ai/zen/v1/muse-spark-1.2Fix branch: whp233/CodeWhale#fix/custom-wire-responses (commit 934a69a)
Closes #5713