Skip to content

fix(runtime): preserve cached prefixes across tool and skill updates - #1325

Closed
zszz3 wants to merge 14 commits into
vastsa:mainfrom
zszz3:codex/fix-toolsearch-system-state-1285
Closed

zszz3 wants to merge 14 commits into
vastsa:mainfrom
zszz3:codex/fix-toolsearch-system-state-1285

Conversation

@zszz3

@zszz3 zszz3 commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

问题与修改

#1285 中,ToolSearch 激活工具和 Skill 更新会改写模型请求前缀。参考 Pi #9548,保留 system/Skill 的发生顺序,并修复各协议的工具声明路径。本轮已移除仅针对官方 Flash 的白名单。

当前 Desktop 请求路径 ToolSearch 后的处理
OpenAI / Codex Responses,已验证支持工具增量 保留 Pi 的 additional_tools 或客户端 tool-search 增量,初始清单不变
Kimi 等已验证支持工具增量的 Chat Completions 保留原生增量
Claude / Anthropic Messages(含原生工具变更能力) 固定完整工具清单;原生变更块仍会增长顶层 schema,不能单靠它保证前缀
普通 Chat Completions、其他 Responses / Codex、Gemini、兼容中转 固定完整工具清单,搜索只改变激活状态
Pi Messages 保留原有 transcript 增量传输;下游服务端缓存不作保证

声明不等于执行权限。 未激活工具在扩展/Host 前被拒绝,激活后仍执行现有模式、审批和 Host 检查。激活记录独立持久化并在重启/压缩后恢复;发给模型前剔除这项 Desktop 私有元数据,防止不支持中途 system 的接口将它折叠到开头、再次破坏缓存。其他指令、工具调用、结果和角色语义保留。

账户、模型、接口或工具 schema 改变会建立新状态并要求重新激活;删除工具立即阻止执行。固定清单采用 128 个工具的保守上限,并检查上下文预算;超限保留按需加载并记录原因,不截断工具,不承诺该场景前缀稳定。固定声明首轮更大,短会话可能更贵。

system/Skill 更新保持时间顺序,由 Pi 按经过绑定验证的接口能力投影。不支持中途指令更新的接口仍可能因真实 system/Skill 变更失去缓存;本轮不会冒用角色或强开能力来掩盖这一限制。未新增 Azure / Vertex / Bedrock / Mistral 原生账户绑定;通过现有兼容接口接入的模型按该协议处理。

验证

候选提交 c7ea6dc92b92 包含目标主线 7f1d7c1ce5f2,采用非破坏性合并,祖先检查通过。

  • 六类 Desktop 可选协议、11 种分支均从 runtime 用户入口执行搜索 A → 调用 A → 搜索 B → 调用 B,捕获真实 Pi 适配器发送前的序列化请求;验证工具清单、初始指令及历史消息前缀。恢复旧声明策略后六条遗漏路径失败、五条已有原生增量路径通过;修复后全部通过。
  • HTTP/SSE 回归额外覆盖官方 Flash、普通 Chat Completions 和兼容中转;权限、恢复、压缩、撤销和模式变化测试保留。
  • Runtime 1,247 项、桌面 3,484 项及其余工作区测试通过;构建、类型检查、lint、文档检查通过。远端 CI 的 JS、Rust,以及独立 Docs、PR-base 四项检查全部通过。此前 CI 发现既有进程取消测试会读到尚未写完的就绪文件;已改为写完后原子改名,保留取消断言,Runtime 全量重跑通过,Claude Code 复核无阻塞。
  • 最终候选上的 system 历史、Flash 固定清单、普通兼容接口固定清单三组 Host + production sidecar + 本地 SSE E2E,共 13 项全部通过;隔离 Electron transcript 回归也通过。
  • Claude Code /pr-review-toolkit:review-pr code tests errors 未发现正确性阻塞项;已移除其指出的未开放 Azure 路径预留判断。

适配器测试在请求发送边界停止,不接触付费服务;证明请求构造和执行流程,不能证明各服务端实际缓存命中率。

官方 Flash 对照实验与代价

以下为此前提交 907594acb860 的实测。本轮跨模型扩展没有重复调用付费服务,不能把这些收益外推到 Claude、Codex 或其他模型。经授权使用现有账户,以合成数据完成 12 个独立会话、60 次请求:短/长上下文各三组按需与固定声明对照,每组均实际完成两次搜索和两次工具调用。所有固定声明会话均保持 tools 与历史前缀稳定。

场景(各三组累计) 原按需方案未命中输入 token 固定声明未命中输入 token 累计输入费用估算变化
短聊天记录 24,570 28,700 增加 17.8%
较长聊天记录 55,835 38,653 减少 28.1%

较长场景中,原方案每次新增工具后约有 3,900–4,200 个输入 token 未命中;固定方案后续各次约 140–250 个。费用按官方价格分别计算命中/未命中输入,包含首轮;这是实验估算,不是账单核销。

**边界:**固定声明首轮更大,冷请求仍可能零命中,短会话可能更贵。工具目录改变允许一次前缀变化;本轮已覆盖其他模型及兼容中转的工具请求构造;其他服务端的实际命中率、费用收益和超限目录仍不在保证范围。实际命中率由服务端决定,不能只凭接口能力标志推断。

Related to #1285

zszz3 added 4 commits October 3, 2026 02:04
Persist provider-neutral instruction and tool updates before dispatch so
skill refresh, session restoration, and compaction preserve their order.
Keep execution permissions authoritative and gate native updates on the
original model, API, and endpoint binding.

Related to vastsa#1285
Keep Pi's exact transport capabilities independent of models.dev-owned
limits and prices so catalog enrichment cannot silently disable updates.
Normalize compaction checkpoints to the durable journal shape, including
extension-provided text blocks, and cover recovery cleanup boundaries.

Related to vastsa#1285
Register the system transcript decision in the ADR index so the
documentation integrity check no longer aborts the workspace test run.
The reminder now travels in a replaceable transcript section so it can
expire after compaction. Update the old source guard and assert that
Pi folds the actual reminder content into the current system state.
@vastsa

vastsa commented Oct 3, 2026

Copy link
Copy Markdown
Owner

我核对了 #1285:ToolSearch 激活新工具会改变后续请求的工具声明,DeepSeek 的对照请求也显示只增加工具定义就可能使输入缓存失效,问题属实。

暂不合入为该问题的修复:PR 的 Flash 测试明确 supportsMidConvoSystemMessages: true、但 supportsMidConvoToolAdditions: false,因此 ToolSearch 后仍需在请求顶层提交变化后的完整工具清单;这正是 #1285 中导致缓存丢失的路径。PR 说明也承认此处仍未关闭 issue。当前改动改善了 system/skill 更新顺序,但没有根治已报告的工具清单变化。请先补上对该实际路径有效的方案和回归,再作为修复提交评审。感谢你把能力边界和未覆盖场景写得很清楚。

@zszz3

zszz3 commented Oct 3, 2026

Copy link
Copy Markdown
Contributor Author

补充针对 #1285 实际触发路径的方案。认可上述审查:当前实现还没有解决 Flash 在 ToolSearch 后修改顶层 tools 的问题;下面是准备补做的方案,尚未实现或验证,不以现有 CI 通过作为有效性证明。

先针对官方 deepseek-flash Chat Completions,采用固定工具声明快照。 不切换 Messages,也不把“支持中途 system”当成“支持工具增量”。

  1. 首次请求固定声明,搜索后不改 tools。 在当前账户、模型和工具目录下,首次请求就声明本会话可搜索的完整工具 schema,固定顺序、说明和参数;之后 ToolSearch 仍搜索并激活工具,但不再向 Pi 的声明集合增加工具。目标请求形态是:

    搜索前:固定 tools + 既有 messages
    搜索后:同一份 tools + 既有 messages + ToolSearch 调用/结果
    

    需要在 runtime 的工具组装处实现,不能只在发送前强行覆盖 tools,留下声明、执行和恢复状态互相矛盾。

  2. 声明与可执行状态分离。 非核心工具即使已经声明,未经过 ToolSearch 激活也不能执行。执行入口先检查激活状态,再走现有模式、审批和 Host 权限检查;拒绝时不调用实际工具。搜索激活不是权限授权,插件禁用、卸载或撤权后立即阻止执行。工具调用仍使用原工具名和 schema,暂不引入通用 ToolExecute 转发协议。

  3. 恢复时分别恢复快照和激活状态。 保存声明快照及其版本,激活状态继续来自成功的 ToolSearch 记录;特别要修改现在“从历史声明恢复激活”的路径,避免把首次全量声明误当作全部已激活。重启和压缩后,同一目录、模型及接口继续使用同一份声明;不能因重建 runtime 就重新排序或换一份清单。

  4. 明确兼容与失效边界。 先验证官方 Flash 的确切模型/API/地址组合,不直接推广到全部 DeepSeek、Claude、Codex 或中转。其他已验证能在新增工具时保持请求前缀的 Pi 路径继续使用原生增量;Anthropic 等即使支持工具变更消息,也仍需检查顶层声明是否变化。会话中安装新工具、修改 schema、切换模型或接口时,显式建立新快照,允许这一次缓存失效;撤权立即生效,不为缓存保留执行能力。完整目录超过该接口工具数量或上下文限制时,不截断、不谎报支持,保留兼容路径并明确该场景尚未解决。

代价需要一起评估: 这条方案放弃了“首次只发送少量工具 schema”的节省,换取后续声明稳定。因此不能只看命中率,还要比较首轮和累计输入成本;目录很大时,收益可能不成立。

回归与验收:

  • 从真实 DesktopAgentRuntime 的用户请求入口,经本地 HTTP/SSE 边界抓取最终请求,覆盖“首轮 → ToolSearch 激活 A → 调用 A → 激活 B → 再次调用”。断言每次顶层 tools 内容及顺序一致,历史请求内容保持前缀,新增内容只在后面;旧实现应在首次激活后失败。
  • 覆盖未激活调用被拒绝、审批/Plan 限制、撤权、schema 变化、重启、压缩及旧会话恢复,证明固定声明不会绕过权限或复活工具。
  • 用官方 Flash 做多组独立会话对照:现有按需声明与固定声明采用相同合成上下文、工具目录和调用序列,分别记录冷请求、激活 A、激活 B、普通后续轮次的缓存读入/未命中 token、累计成本和实际执行结果。只有请求稳定、工具可正确使用且实测确有收益,才把这条路径作为 ToolSearch 激活新工具后,缓存命中率大幅下降 #1285 的修复;未验证的模型及目录变更场景不纳入承诺。

下一步先完成这条路径的最小验证,再决定是否保留固定快照方案,并同步 ADR/spec。已有 system/Skill 顺序改动不会替代上述验收。

zszz3 added 2 commits October 3, 2026 14:45
Incorporate the current upstream main without rewriting the shared PR.
Move journal entry types to the Desktop-owned projection introduced by
the Pi 1.0 migration, while preserving chronological transcript state.
Declare the verified Flash catalog once per account and schema epoch so
ToolSearch activation does not invalidate the earlier request prefix.
Persist activation independently and reject inactive tools before Host
execution, preserving existing mode and approval restrictions.

Cover HTTP payloads, recovery, compaction, revoked tools and fallback
limits, with paired live Flash measurements documenting the larger cold
request and the short-conversation cost tradeoff.

refs vastsa#1285
@zszz3 zszz3 changed the title fix(runtime): preserve chronological system and tool updates fix(runtime): preserve cached prefixes across tool and skill updates Oct 3, 2026
@zszz3

zszz3 commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor Author

已按上面的方案补做,提交 907594acb860;并先合入最新主线 0d47d26769ec 的 Pi 1.0.0 更新。

这次补到了 Flash 的实际请求:首次固定声明完整工具目录,ToolSearch 只激活执行,顶层 tools 不再变化。激活状态单独持久化,未激活调用、重启/压缩、删除工具和模式/Host 拒绝都有回归;没有把 system 顺序修复当作工具缓存修复。

用官方 Flash 跑了 12 个独立会话、60 次请求。较长聊天记录的三组对照,固定方案在两次搜索后每次约 140–250 个输入 token 未命中,原方案约 3,900–4,200 个;包含首轮后的累计输入费用估算下降 28.1%。也保留不利结果:短聊天记录的三组对照费用增加 17.8%,因为首轮完整目录更大。

Claude Code review skill 未发现阻塞项;本地 runtime 1,222 项、桌面 3,454 项及其余工作区测试通过,两套进程 E2E 共九项通过。完整说明、兼容边界和费用对照已更新到 PR 正文。新的 GitHub CI 及 Docs / PR base 检查已全部通过;合并候选 a927e8f79e6f 与本地测试提交代码树一致。PR 仍保留 draft,未合并。

zszz3 added 2 commits October 3, 2026 21:49
Preserve the upstream single-bubble recovery lifecycle while removing failed
assistant messages behind chronological system deltas. Cover both message
orders so recovery keeps system state without replaying the failed response.
Include the latest MCP timeout changes in the PR integration candidate so validation and review use the current target branch.
@zszz3

zszz3 commented Oct 3, 2026

Copy link
Copy Markdown
Contributor Author

已修复与最新主线的冲突,推送提交 ace60a310110,基于 f3b229ee0584。GitHub 现已无冲突。

冲突处理同时保留两边行为:主线在上下文溢出后继续使用同一个回复气泡;本 PR 会跨过尾部 system 更新,移除失败的 assistant,保留 system 状态。新增组合回归已先验证旧删除循环失败,再验证修复后通过。

Claude Code /pr-review-toolkit:review-pr code tests 复审未发现阻塞项。Runtime 1,233 项、桌面 3,477 项及其余工作区测试通过;构建、类型检查、lint、文档检查通过。最终提交上两套 Host/sidecar/SSE E2E 共九项通过,隔离 Electron transcript E2E 也确认恢复后同一 assistant ID、一个气泡、零错误卡片。

本轮 GitHub CI 的 JS / Rust 及独立 Docs / PR base 检查已全部通过。GitHub 合并候选 288b9a7d7310 与本地已测试提交代码树一致。本轮未重复付费模型实验,PR 正文已标明之前 Flash 数据对应的提交;PR 保持 draft,未合并。

zszz3 added 6 commits October 3, 2026 23:09
Select fixed declarations by transport capabilities instead of a Flash
allowlist, retaining native anchored additions where Pi supports them.
Keep execution activation private to Desktop so folding adapters do not
rewrite their leading instructions after each search.

Exercise all Desktop-selectable adapters through the runtime tool loop,
with compatible-route HTTP and process coverage and independent activation
restoration and permission checks.
Preserve both independently added E2E scenarios while incorporating the latest upstream desktop, Host and dependency security fixes into the candidate.
The unflagged fixture now declares its catalog upfront. Assert persisted activation and stable request schemas instead of expecting a later declaration delta.
Preserve both added E2E sections while bringing the shared PR onto current main. Provider declaration and activation behavior is unchanged by this merge.
CI observed the readiness file between creation and its JSON write. Rename a completed sibling file into place so process cancellation assertions begin only after the PID list is readable.
Include the latest MCP session result bounds before final integration checks. Preserve the independent provider cache fix and readiness regression.
@zszz3

zszz3 commented Oct 3, 2026

Copy link
Copy Markdown
Contributor Author

已把修复扩展到当前 Desktop 的全部六类模型协议,不再限定官方 Flash;最新提交 c7ea6dc92b92,已包含主线 7f1d7c1ce5f2。

按实际传输能力选择:OpenAI/Codex、Kimi 中支持工具增量的路径继续原生增量;Claude、普通 Chat Completions、其他 Responses/Codex、Gemini 和兼容中转固定完整工具清单;Pi Messages 保留 transcript 增量。工具激活记录仍持久化,但发送前剔除这项私有元数据,避免折叠 system 的接口再次改写前缀。执行权限、撤销和恢复检查保持独立。

六类协议的 11 种请求分支通过真实适配器序列化验证。旧策略有六条遗漏路径失败,修复后全部通过;Runtime 1,247 项、桌面 3,484 项、其余工作区测试,以及 13 项 Host/sidecar/SSE E2E 和隔离 Electron transcript 回归通过。Claude Code review skill 未发现正确性阻塞项。

固定清单的首轮成本、128 工具/上下文预算回退,以及不支持中途 system/Skill 更新的接口限制仍明确保留。非 Flash 服务端未做本轮付费实测,不把请求前缀稳定等同于实际缓存命中或费用下降。PR 正文已更新协议表和验证范围。

本轮 CI 的 JS、Rust、Docs 和 PR-base 四项检查全部通过。首次 CI 暴露的既有进程测试就绪文件竞态已用原子改名修正,未更改生产执行逻辑。GitHub 合并候选与本地测试提交的代码树一致。

@vastsa

vastsa commented Oct 3, 2026

Copy link
Copy Markdown
Owner

感谢你连续几轮补齐根因方案、跨协议回归与成本边界。我独立核对确认 #1285 的 ToolSearch 会改变部分协议后续请求的顶层工具清单,导致前缀变化;当前方案将工具声明与激活状态分开,并保留原权限检查,确实覆盖了这个根因。\n\n我把你的贡献提交保留在 successor #1355,集成最新 main 并补做冲突文档合并后合入。最终候选上 Runtime 1,233 项、相关 Desktop 194 项、Host Core 750 项通过;构建、typecheck、lint、Docs、Rust 和基线门禁均通过。Host/Sidecar 固定工具、system transcript、隔离 Electron 的相关 E2E 也通过。早前 DeepSeek Flash 成本数据仍按原提交标注,本轮没有重复调用付费服务,也没有外推到其他服务端。现关闭此 draft,后续以 #1355 的已合入结果为准。

@vastsa

vastsa commented Oct 3, 2026

Copy link
Copy Markdown
Owner

已由合入的 successor PR #1355 取代。

@vastsa vastsa closed this Oct 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants