Repository navigation
fix: merge all system/developer messages into one leading message (SGLang #377) - #379
ranxianglei wants to merge 2 commits into
Conversation
📦 Built Package ArtifactBranch: Option A — Install from npm PR tag (recommended)npm install -g billion-context@pr-379Each push to this PR publishes a new version under the Option B — Download artifact
tar xzf billion-context-pr379.tgz
npm install -g packageThis comment is automatically updated on each push. |
[bot] Reviewing this PR now. Diff reviewed: |
[bot] Review complete — verified independently on branch Pre-flight (re-run locally)
Code review
One caveat
LGTM from my side — merge is yours to make (I can't merge PRs). |
fix: pin acp-kernel 0.0.86 — count-triggered distillation default-off (#379)
…ranxianglei#379) Bundles kernel ranxianglei#379/ranxianglei#380: tiers.tier2Trigger 5->1000 / tier3Trigger 10->2000 and the ranxianglei#238 usage gate deleted. Count-triggered distillations reclaimed almost nothing while rewriting the wire from the fold anchor onward — the prefix-cache sawtooth root cause of ranxianglei#1249. Growth (>=growthFloor) and token-mass (>=1.5x) paths unchanged and ungated. Adds tests/kernel-tier-defaults.test.ts pinning the contract into bili's suite (kernel defaults 1000/2000; applyCompressSettings never overrides triggers — boolean tiers toggle only flips enabled). Fixes ranxianglei#1249 (with acp-kernel#379)
…ix from ranxianglei#2225) The Soft-target section still described the pre-ranxianglei#379/ranxianglei#380 shape: adaptive step clamp(round(window*5%), 20k, 50k) with a window-dependent growth floor. Current kernel constants (golden-pinned in tests/golden/wire-contract/kernel.json): nudge.growthFloor == nudge.growthCap == 50000, so the step is flat 50k at every window size and the growth gate is max(20k, 0.45*step) ~= 22.5k with the T1 path additionally requiring >= one step of compressible mass. The old text contradicted the new large-window section added alongside ranxianglei#2225.
KDD #8 still stated the pre-#2110 contract (flat 50k pinned at every window size, 'Do NOT re-scale the interval with the context window'), which this PR deliberately reverses for sub-1M windows. Rewrite the entry to the new contract: clamp(5% x window, 20k, 50k), >=1M byte-identical, and keep the surviving #379/#380 settlement (growth-driven, no usage/count proxy gates) plus the escape-hatch wording.
Summary
Fixes #377 — with 2+ active ACP compressed blocks, bili rendered each block's summary as its own
role:"system"message, so the OpenAI wire carried 2+ system messages. SGLang (and vLLM with the Qwen3-family "system-first" chat template) reject that with a hard 400:The earlier #355 fix (
hoistMidSystemMessages) hoisted mid-conversation systems to a contiguous leading prefix but kept them separate — which SGLang still rejects, because its Qwen3 template guard isif message.role == 'system' and not loop.first: raise, i.e. it requires exactly one system message at index 0, not merely a leading prefix.Change
Replace
hoistMidSystemMessageswithmergeSystemMessages(src/util.ts): it collapses all system/developer messages into a single leadingsystemmessage, preserving the relative order of every other message.sysParts(the client's original system + the static compress prompt) is placed first so the stable prefix-cache anchor stays at the head across compress turns; the folded block summaries follow in their original anchor order.src/server.ts(prepareOpenai) andsrc/loop/adapter-openai.ts(buildRequest) now callcoreToOpenai(...)thenmergeSystemMessages(msgs, sysParts); the now-unusedinjectOpenaiSystemimport is dropped from both.Tests
tests/hoist-mid-system.test.ts→tests/merge-system.test.ts: unit tests rewritten for the merge (no-op, single/mid/multiple systems, sysParts-first ordering, the [Bug] ACP: ≥2 compressed blocks render as multiple system messages → SGLang (vLLM-compatible) upstreams return 400 #377 wire shape collapsing to exactly one system, non-string content JSON-stringified).tests/e2e-mid-system.test.ts: the real-proxy e2e now asserts exactly one system/developer message at index 0 in every upstream request (the [Bug] ACP: ≥2 compressed blocks render as multiple system messages → SGLang (vLLM-compatible) upstreams return 400 #377 requirement), in addition to the existing summary-marker checks.Pre-flight
npm run typecheck— cleannpm test— 863 pass, 0 fail (incl. the e2e 多段 compress 夹 user 消息时 T1 摘要 (role:system) 落在对话中部, sglang 报 400 "System message must be at the beginning" #355 real-proxy run)npm run build— success