/** * cwd-cache-fixer — 让 fork 到 worktree 的会话复用父会话的 prompt 缓存 * * 背景:pi 的 system prompt 末尾会写入 `Current working directory: `。 * GLM-5.2 等模型的隐式缓存按 prompt 前缀逐 token 匹配。fork 到 git * worktree 后 cwd 变化,导致 system prompt 末尾这行及其后的全部对话历史 * 都缓存未命中(实测命中率 0.4% → 95%,相差约 100 倍计费)。 * * 方案:在 before_agent_start 时,把发送给 LLM 的 system prompt 中的 cwd * 字符串替换回原仓库路径(由 gittree-bootstrap 通过 PI_CACHE_CWD 环境变量 * 注入)。仅影响发送给模型的字符串,bash / 文件工具的真实执行 cwd 不变, * worktree 隔离完全保留。 * * 若未设置 PI_CACHE_CWD,本扩展不注册任何处理逻辑,零开销。 */ import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent"; /** 在 UI 可用时发送通知。hasUI/ui 在 handler 的 ctx 上,不在 pi 上。 */ function safeNotify(ctx: ExtensionContext, msg: string): void { try { if (ctx.hasUI) ctx.ui.notify(msg, "info"); } catch { /* 非交互模式下 UI 不可用,忽略 */ } } export default function (pi: ExtensionAPI): void { const fixedCwd = process.env.PI_CACHE_CWD; if (!fixedCwd) return; // pi 的 system prompt 末尾写入 cwd 的前缀文案。 // 依赖此文案存在;若 pi 升级改了文案,下方会检测到未命中并通知用户。 const CWD_PREFIX = "Current working directory: "; let notified = false; // 已通知过「生效」 let warnedNoMatch = false; // 已警告过「未命中」 pi.on("before_agent_start", (event, ctx) => { const sp = event.systemPrompt; const realCwd = event.systemPromptOptions?.cwd; if (!sp || !realCwd || realCwd === fixedCwd) return; const needle = `${CWD_PREFIX}${realCwd}`; if (!sp.includes(needle)) { // 未找到预期文案,可能是 pi 升级改了 system prompt 中 cwd 行的格式。 // 此时无法做字符串替换,缓存修复静默失效,需提醒用户。 if (!warnedNoMatch) { warnedNoMatch = true; safeNotify( ctx, `[cwd-cache] 未在 system prompt 中找到 "${CWD_PREFIX}${realCwd}",` + `缓存修复未生效,可能是 pi 版本变更了 prompt 格式。`, ); } return; } // 替换所有出现处(system prompt 正文 + project_instructions path 等) const replacement = `${CWD_PREFIX}${fixedCwd}`; const newSp = sp.split(needle).join(replacement); if (!notified) { notified = true; safeNotify( ctx, `[cwd-cache] system cwd 固定为 ${fixedCwd}(实际执行 cwd 仍为 ${realCwd})`, ); } return { systemPrompt: newSp }; }); }