Repository navigation
fix: carry per-conversation id in an ephemeral trailing note, not the static system (#1611) - #1620
ranxianglei wants to merge 3 commits into
Conversation
📦 Built Package ArtifactBranch: Option A — Install this exact build (recommended)npm install -g billion-context@0.0.1562-pr.1620.c6af033This exact version is immutable and reproducible. The rolling Option B — Download artifact
tar xzf billion-context-pr1620.tgz
npm install -g packageInstall instructions are refreshed on each push. |
… static system #1611: withConversationIdNote() embedded the live conversation id in the static system prompt. A fork/resume/session-switch continues under a NEW canonical id while the history stays byte-identical (#1486), so that single system line was the only cross-session divergence and it collapsed the upstream prefix cache to 0% (cached_tokens=0 despite identical history). The system now carries only a byte-stable pointer (CONVERSATION_ID_POINTER_NOTE, constant across every session); the live value travels in an ephemeral trailing user message on each wire lane (conversationIdTrailingNote), mirroring the nudge/imgNote/retrieveNote pattern. Per-lane gates are unchanged from the old id-in-system gate. MCP routing is unaffected: the model still reads the value from context and echoes it as the conversation_id argument (src/mcp.ts routes on the argument). Test updates reflect the intended +1 trailing user message per tool-injecting request: count/shape assertions bumped by one, and the #1548 append-stability check now excludes the convnote tail slot alongside the chain tag (the byte-level cacheable history prefix is unchanged).
… note The #1611 fix appends the per-conversation id as an ephemeral trailing USER message after the client history on every tool-injecting request. The native-lane fake scripts the model off the LAST user message (the directive queue source) and reads lastUserRef from it — so the new tail masked the real prompt: the scripted compress never fired (pi lane) and the filler ref oracle read null (opencode lane). Skip convnote messages in both filters, same transport-metadata treatment as the #1421 chain carrier. Reproduced locally: pi suite 3/4 -> 4/4, opencode (V1) 4/4.
Rebased onto master, which added tests/fold-round2-shape.test.ts (febbc16) after this branch point. That test's divergence model counts the trailing volatile tail as three slots (nudge / chain stamp / new user turn). #1611 appends one more ephemeral tail — the conversation-id note — so steady bodies end [..., prompt, convnote, chain] and the old '-3' boundary classified the first growth pair as a mid-history rewrite ('pair 0->1 diverges at element #3/7'). Bumped to '-4' with the slot list updated; verified all pairs pass incl. both fold round-2s.
b8e0a57 to
3586673
Compare
[bot] 🏷 Review of PR #1620 (fix for #1611) ① Issue triage — valid, root cause correctly targeted. #1611's premise checks out: the live per-conversation id sat in the static system line, so any fork/resume/session-switch (new canonical id, byte-identical history, #1486) diverged at exactly one system line → provider prefix cache missed entirely ( ② Regression ledger (existing behaviors on touched paths):
③ CI red on the original head — root-caused and fixed (2 commits pushed).
Pre-flight on the final head Verdict: direction correct, root cause (not symptom), wire-shape change properly flagged, tests have teeth. Per §7.4 this stays a human-merge (wire/message-shape change affecting both modes). Ready to merge once the triggered CI suite is green. 中文摘要:修复了 #1611「会话 id 写进静态 system 导致 fork/resume 后前缀缓存全 miss」的问题(id 值改为随临时尾部消息下发,system 只留常量指针);我定位并修掉了它引起的两处 CI 红(e2e fake 的"最后一条用户消息"语义被新尾注遮蔽、以及 rebase 后与 master 新增 #1592 折叠形状测试的 3→4 尾槽冲突),已补两个测试修复 commit 并 rebase 到最新 master,本地全套预检通过,等 CI 绿后可合并。 |
What changed
withConversationIdNote()(src/compress-tool.ts) embedded the live per-conversation id in the static system prompt:A fork / resume / session-switch continues under a new canonical id while the message history stays byte-identical (#1486). That one system line was then the only cross-session divergence, so the upstream prompt cache missed entirely (
cached_tokens=0) even though the whole history was identical — nullifying #1486's byte-exact resume inheritance.Fix
src/compress-tool.ts—withConversationIdNote(text)now emits a constant, byte-stable pointer (CONVERSATION_ID_POINTER_NOTE, no id value); newconversationIdTrailingNote(id)returns[Your bili conversation id: <id>].src/server.ts— each of the four client lanes appends that trailing note as an ephemeral user message, under the same gate the old id-in-system used: Anthropicopts.compress.injectTool, OpenAI/GoogleshouldInject, ResponsesshouldInject && !isCompactionTrigger && !ACP_NO_COMPRESS_PROMPT. The compress-loop re-request keeps the constant system pointer (no trailing note — it's proxy-driven; tools execute server-side).This mirrors the existing nudge / imgNote / retrieveNote pattern ("not persisted, never enters the agent's re-sent history, safe for the prefix-cache anchor"). MCP routing is unchanged: the model still reads the value from context and echoes it as the
conversation_idargument (src/mcp.tsroutes on the argument).Behavior change (flagged per AGENTS.md §4)
[Your bili conversation id: <id>. When calling…THIS session.]line sat in the static system. New: the static system carries only the constant pointer ("Your bili conversation id is provided in a short ephemeral message near the end of this conversation…") and the live value appears as a trailing user message[Your bili conversation id: <id>].Both compression modes were reasoned: plugin mode (agent owns compression) and proxy mode (proxy executes compress) both keep the note present under the identical gate, so no mode-specific regression.
Pre-flight
npm run typecheck— cleannpm test— 3123 tests, 0 fail (two consecutive runs)npm run build— successE2E_CHECK=1 tests/e2e/e2e-codex.test.ts) — green (codex-cli 0.147.0 + dist OK). The full token-costing e2e needs a live upstream not reachable from this sandbox; the authoritative e2e runs in CI (ci-e2e.yml) since this touches the request pipeline (src/server.ts).Test updates reflect the intended +1 trailing message: count/shape assertions bumped by one, and the #1548 append-stability check now excludes the convnote tail slot alongside the chain tag (the byte-level cacheable history prefix is unchanged by this fix).
Closes #1611
Refs: #760 (per-call conversation_id), #1486 (byte-exact resume inheritance), #1541/#1542 (chain stamps), #1592 (0% signature quantified).