fix(#684): reasoning-drop self-disables on strict-echo upstreams; split-turn exit sentinels - #690
Conversation
…it-turn exit sentinels DeepSeek thinking mode documents reasoning_content as mandatory round-trip with tool_calls; #651's drop could strip it from a closed compress turn and the kernel's half-turn bug (fixed in acp-kernel #684 twin) shipped tool_calls without it. Proxy-side closure: - isStrictReasoningEcho(): static deepseek host check + session-learned flag; disables the #651 reasoning-drop (withReasoningDrop gate at all three wire prepares, which now receive upstreamOrigin). - loop UpstreamHttpError handler: first 400 whose body mentions reasoning_content learns session.metadata.strictReasoningEcho=true (self-healing, persisted — same pattern as #552), with ops log. - Exit sentinels on all three wires (warnReasoningPairs / warnAnthropicThinkingPairs / warnResponsesReasoningPairs): log reasoning-pair-violated / thinking-pair-violated when a tool-call message lacks reasoning while siblings carry it — the turn gate makes this unreachable, so a hit means a new regression path. Tests: tests/reasoning-echo.test.ts (static + learned gate, all three sentinels fire/silent). 1320/1320.
📦 Built Package ArtifactBranch: Option A — Install from npm PR tag (recommended)npm install -g billion-context@pr-690Each push to this PR publishes a new version under the Option B — Download artifact
tar xzf billion-context-pr690.tgz
npm install -g packageThis comment is automatically updated on each push. |
[bot] 🏷 PR #690 reviewed. The code is clean, correct, and green — but it is blocked on the kernel dependency and should not be released yet. Details below. Duplicate screening: No duplication. #690 is the proxy-side implementation of #689 (twin of kernel acp-kernel#245 / issue #244). It is distinct from the already-merged #540 (loop re-request drops fresh reasoning) and #667/#651 (compress-reasoning drop) — this PR builds on those rather than overlapping them. Diff cleanliness: ✅ Clean. Single commit Correctness (read the diff): ✅
Independent verification (ran at 🔴 Blocker — kernel dependency not yet satisfied. The PR states it depends on acp-kernel#245 (issue #244) being released first, then the pin bumped here. Current state:
Consequences of cutting a release from this branch today:
Recommendation (one path, not a menu): Hold the merge. Land acp-kernel#245 first (already written there, 644/644 green — just needs its human merge + CI publish), verify it is live on npm, then add a follow-up commit to this branch bumping Minor nits (non-blocking, left as-is):
中文摘要: 代码本身干净、正确、测试全绿(我独立复跑:typecheck 通过、1327 用例 0 失败、新测试 7/7),可以合入;但它依赖的 acp-kernel#245 内核"原子轮次"修复目前仍是未合并未发布状态(最新稳定版 0.0.62 也不含该修复,本 PR 固定的是更旧的 0.0.61),所以现在不能发布——需等内核先发布、在本分支把 acp-kernel 升到含该修复的版本并刷新 lockfile、重跑预检后再合并发布,否则根因未修且三处哨兵会在生产环境误报。 Merge stays human-only per AGENTS.md §4 — I won't merge. |
[bot] 🏷 Re-verified independently against the real published package — every claim checks out. Ready for merge. I didn't take the claim at face value: pulled
The dependency I flagged last round is now satisfied: the atomic-turn gate (#245) that makes the three exit sentinels unreachable is present in the pinned kernel, so a release cut from this branch ships the root-cause fix and the proxy-side closure together. (#247 directional refinement rides along inside 0.0.63 — a kernel-side change covered by its own release process; here it's exercised by the bundled suite passing.) Verdict: code correct, diff clean, dependency satisfied, green across typecheck/test/build. Ready to merge. Per AGENTS.md §4 the merge itself is human-only — I won't merge. 中文摘要: 已独立复验(非照单全收)——从 npm 拉取真实的 acp-kernel@0.0.63 装入干净 worktree 跑完整门禁:0.0.63 确已发布且含 #245( |
Fixes #689 (reported as #684). Depends on the kernel-side atomic-turn fix: acp-kernel#245 (issue acp-kernel#244) — release acp-kernel first, then bump the pinned version here before releasing this.
What this adds
isStrictReasoningEcho(): staticdeepseekhost check + session-learned flag gatewithReasoningDropat all three wire prepares (prepareAnthropic/prepareOpenainow receiveupstreamOrigin).UpstreamHttpErrorhandler setssession.metadata.strictReasoningEcho = trueon first 400 mentioningreasoning_content(persisted, self-healing — billion-context: 400 Bad Request when codex sendsrole: "developer"messages — request a request-body compat transform hook #552 pattern).[reasoning-pair-violated]/[thinking-pair-violated]— with the kernel gate these are unreachable, so a hit = new regression path.drop:falseescape hatch); CHANGELOG entry.Tests
tests/reasoning-echo.test.ts(static + learned gate, all three sentinels fire/silent). 1320/1320 green, typecheck clean.Merge is human-only (AGENTS.md §4).