Repository navigation
[PR] fix: enforce anthropic-wire-only contract in the incremental-turns path (#3433) - #3440
ranxianglei wants to merge 1 commit into
Conversation
…turns path (#3433) dsh-native's maybeIncrementalNative claimed 'anthropic wire only' but only checked messages-array + model-string, so OpenAI chat-completions bodies (assistant.tool_calls / role:"tool") were converted onto a lane that ingests with anthropicToCore: tool calls silently dropped, role:"tool" mis-mapped into user text, content:null bodies throwing mid-apply. pi/pi-native shared the same gap in the factory hook (pi serves openai/responses/google provider APIs). - wire the existing wireMessagesLookAnthropic into the dsh-native and pi entry points (omp/opencode parity; restores the PLUGIN.md-documented contract) - enforce the same predicate at the lane boundary: 400 for non-anthropic message shapes instead of trusting every host to pre-filter (mirror of the client helper, keep-in-sync marked) - regression tests: dsh OpenAI shape rides full resend (+ anthropic control), pi OpenAI shape not replaced under a live lane (+ anthropic control), lane 400s role:"tool"/tool_calls and still accepts a valid seed afterwards
📦 Built Package ArtifactBranch: Option A — Install this exact build (recommended)npm install -g [email protected]This exact version is immutable and reproducible. The rolling Option B — Download artifact
tar xzf billion-context-pr3440.tgz
npm install -g packageInstall instructions are refreshed on each push. |
(ai: vllm-qwen/qwen3.8-27b) 查重:不重复。 open+closed 的 issue/PR 全搜了 审核方式:diff 全文通读(6 文件 +229/-3,单 commit 八问:
测试有效性:三组测试双向有牙——既断言回归(OpenAI shape 不被替换 / 车道 400 且不落任何状态),也断言 control(anthropic shape 仍转换 / 有效 seed 仍正常落地),去掉守卫或过度拦截都会红;pi 测试用真实 proxy 且强制车道 LIVE(unified storage + rollout=1),确保 probe 通过、由守卫本身裁决,隔离正确。 结论:可合。 代码、diff 整洁度(每行都服务于目的,无空白/锁文件噪音)、测试质量全部过关;CI 在本 head 全绿。无阻塞项。 |
|
(ai: zhipuai-lb/glm-5.3) 已并入 #4590。关单收尾;误判请 reopen。 |
Closes #3433
What this does
The incremental-turns lane (#3248) is end-to-end Anthropic-wire-only: it ingests with
anthropicToCore, re-emits withcoreToAnthropic, and forwards the assembled body to the ORIGINAL request path. But two host entry points claimed "anthropic wire only" without enforcing it:src/agent/dsh-native.ts'smaybeIncrementalNativechecked onlyArray.isArray(messages)+typeof model === "string"— an OpenAI chat-completions body passes both;src/agent/pi.ts'smaybeIncrementalTurn(shared by pi AND pi-native by design) had the same gap, and pi genuinely serves openai/responses/google provider APIs.With the rollout flag on, an OpenAI conversation would be converted onto the lane where:
assistant.tool_callsare silently dropped,role:"tool"messages are mis-mapped into user text blocks (tool_use_id association lost), andcontent:nullbodies throw mid-apply. omp/opencode already guarded withwireMessagesLookAnthropic; this brings dsh/pi to parity and enforces the contract at the trust boundary too.Changes
wireMessagesLookAnthropicinto dsh-native (src/agent/dsh-native.ts) and pi (src/agent/pi.ts). Non-anthropic shapes now stay on full resend — exactly what PLUGIN.md documents.src/incremental-lane.tsrejects non-anthropic message shapes with 400 (laneMessagesLookAnthropic, a keep-in-sync mirror of the client helper — same pattern asREQUEST_PARAM_KEYS/INCREMENTAL_TURN_MARKER_HEADER). No host can corrupt the lane's canonical state anymore; the empty-messages sticky-system-update case stays legal (deliberate divergence from the client predicate, documented in the docstring).tests/dsh-native.test.ts— OpenAI shape (tool_calls + role:"tool") rides full resend untouched, no marker; anthropic control still converts.tests/issue3433-pi-incremental-guard.test.ts(new) — real proxy with the lane LIVE (unified storage + rollout forced on) so the probe passes and the GUARD is what decides: OpenAI shape not replaced; anthropic control converts (seed, sinceSeq 0).tests/incremental-lane.test.ts— lane 400s role:"tool" and tool_calls bodies with a clear error, applies nothing, still accepts a valid seed afterwards.Behavior changes (old → new)
pluginIncrementalTurnsis at percent 0, no traffic reaches this codePOST /__bili/plugin/turn(+ marker-diverted turns) with non-anthropic message shapesmessagesarrayNo config surface changes. No
kernel/changes. No version bump.Verification
npm run typecheckclean (kernel + pi-subagents + bili).tests/dsh-native.test.ts55/55,tests/incremental-lane.test.ts18/18,tests/issue3433-pi-incremental-guard.test.ts1/1, adjacenttests/pi-omp-fork-adopt.test.ts22/22. Full-suite verdict = CI on this head.Out of scope (tracked as a decision request in #3433): making the lane itself format-aware (
detectWireFormatdispatch toopenaiToCore/coreToOpenai+ per-conversation format recording) — the "real fix" that would let OpenAI lanes actually USE incremental turns; a feature/wire change requiring owner sign-off.