Uh oh!
There was an error while loading. Please reload this page.
fix(context-pivot): preflight native compaction history - #320
Conversation
tt-a1i
left a comment
There was a problem hiding this comment.
请求修改,审查提交:6b14f2b0dbeec940cc5673c70305371184f8a005。
这个 PR 想解决 #24 的真实体验问题:总上下文达到 30k,并不意味着存在可丢弃的历史,提前给出解释有价值。不过,当前预检查与 Pi 的实际资格判断不等价:既会误拒绝可压缩的会话,也会在特定旧/自定义摘要边界下误放行。两处复现见行内评论。
处理方向请保持简单:现阶段建议撤回这层基于默认配置的硬性预检查,保留已有的 ctx.compact() 和原生失败的友好提示。不要为此新增 OpenPI 配置读取器、缓存、私有 API 适配或另一套压缩资格算法。拿不到准确的原生资格查询时,让 Pi 做最终判断即可;将来 Pi 提供基于生效配置的公开查询接口,再直接接入。
撤回该层检查会保留“先尝试、再收到无历史提示”的现有限制,也可能使本 PR 不再需要生产代码改动;不必为了保留 PR 而增加替代机制。这不是要求在本 PR 中解决完整上游 eligibility API。
验证:该提交上 bun run check 通过;专项 9/9;完整 Node 测试 1080 通过、1 跳过,Vitest 30/30。额外使用 Node 24 / Pi 0.84.1 源码和内存 Session 对照复现两项问题,未发起真实模型调用。这些是源码/测试证据,不是真实 TUI 验收。
| branch, | ||
| boundaryStart, | ||
| branch.length, | ||
| DEFAULT_COMPACTION_SETTINGS.keepRecentTokens, |
There was a problem hiding this comment.
[P2] 默认保留量不能作为实际压缩资格的硬性否决。
这里固定使用 20k,但 Pi 的 native preparation 使用 SettingsManager 中生效的 keepRecentTokens。已复现:两条 user 消息分别为 12,000 / 20,000 字符,reported context=35,000,实际 keepRecentTokens=4,000;原生 prepareCompaction 有效并会总结第一条消息,本函数却返回 false。agent_start 隐藏 context_pivot,execute 提前拒绝,compactCalls=0。因此原生 onError 无法兜住此假阴性,原本可工作的 pivot 被禁用。
建议收回这个近似结果对工具可见性和执行的硬性拦截,继续交给原生 compact 判断;不需要为此再实现一套配置读取机制。
| : cutPoint.firstKeptEntryIndex; | ||
| const hasHistory = branch | ||
| .slice(boundaryStart, historyEnd) | ||
| .some((entry) => sessionEntryToContextMessages(entry).length > 0); |
There was a problem hiding this comment.
[P2] 已有 compaction 摘要不等于可再次丢弃的普通历史。
sessionEntryToContextMessages(compaction) 会产生上下文消息,但原生 getMessageFromEntryForCompaction 明确排除 compaction 条目;此处及下方 turn-prefix 判断没有排除。已用公开 SessionManager.inMemory() 复现:appendCustomEntry(metadata) → appendCompaction(summary, metadataId, 30000) → appendMessage(user, 100000 字符)。默认配置下本函数返回 true,而 native prepareCompaction 返回 undefined,仍会走到 Nothing to compact。
这是旧/自定义摘要保留边界的情况,不是普通原生摘要主路径。它说明复制这段判定还需要额外维护语义一致性;结合本次简化方向,建议直接撤回近似预检查,而非继续扩展适配层。
tt-a1i
commented
Aug 31, 2026
Review 结论请求修改,基于 这次建议做减法:撤回默认配置驱动的硬性预检查,保留 Pi 原生 |
tt-a1i
commented
Sep 1, 2026
Thanks for simplifying this after review. The current head fully reverts the proposed preflight, so the PR now has an empty diff and there is nothing useful to merge. Closing this PR keeps Issue #24 open for a future Pi-native solution if Pi exposes an authoritative compaction-eligibility API. |
Problem
Issue #24 describes a false-positive context-pivot path: OpenPI's 30k context-usage gate can pass when the session has no discardable conversation history, after which native Pi compaction fails with
Nothing to compact (session too small).Value
The pivot is now fail-closed before starting asynchronous compaction when Pi's public compaction cut-point logic finds no history to summarize. Users get the existing actionable
/sessions/ new Session guidance immediately, instead of a misleading “started” state or an unavailable follow-up tool request.Approach
findCutPoint,sessionEntryToContextMessages, andDEFAULT_COMPACTION_SETTINGSexports.context_pivot; malformed branches and missing kept-entry IDs fail closed./context-pivotcommand path.ctx.compact()and its native error callback unchanged as the race-safe final guard; no second compressor, persistence format, or Session lifecycle is introduced.The installed Pi 0.84.1 package does not actually export
prepareCompactionat runtime, despite the internal type/source references, so this PR deliberately avoids a private deep import. The preflight mirrors the public cut-point boundary and documents that the asynchronous native call remains authoritative if the branch changes between checks.Validation
npx --yes bun@1.3.14 run check— passednpx --yes node@24 --test --experimental-strip-types tests/extensions/context-pivot/index.test.ts— 9/9 passednpx --yes node@24 scripts/run-tests.mjs— 1079 passed, 0 failed, 1 skipped; Vitest 30/30 passedgit diff --check— passedImpact
context_pivotis not exposed when the current branch has no discardable history.