pi-cache-optimizer 2.5.1 → 2.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/README.md +74 -495
  2. package/README.zh-CN.md +77 -357
  3. package/index.ts +223 -43
  4. package/package.json +2 -2
package/README.zh-CN.md CHANGED
@@ -6,413 +6,133 @@
6
6
 
7
7
  [English README](./README.md)
8
8
 
9
- > **已从 `pi-deepseek-cache-optimizer` 重命名。** 如果你之前安装的是旧名称,请迁移:
10
- >
11
- > ```bash
12
- > pi remove npm:pi-deepseek-cache-optimizer && pi install npm:pi-cache-optimizer
13
- > ```
14
- >
15
- > 持久化的底部计数器以及已有的 `~/.pi/agent/models.json` 都会被保留。
16
-
17
- 开箱即用的 Pi 扩展,用稳定 prompt 前缀提升 provider-side KV Cache / Prompt Cache 命中概率,并以保守的 provider-specific adapter 显示底部缓存统计。包名里虽带 DeepSeek,但从 1.x 开始实际上已同时支持 DeepSeek、OpenAI、Claude、Gemini 的统计 adapter;新名称反映这个事实。
18
-
19
- > 重要:prompt/KV 缓存是 provider 侧、best-effort 行为。本扩展只能通过稳定前缀、在 Pi 支持时请求长保留、提醒明显 compat 缺口、以及展示 provider 暴露的轻量统计来提高命中概率,不能保证每次命中。第三方代理可能隐藏、丢失、重路由或重新解释缓存行为。
20
-
21
- ## 做了什么
22
-
23
- | 功能 | 方式 | 是否需要手动操作 |
24
- |------|------|:---:|
25
- | 🔄 重组 system prompt | `before_agent_start` 钩子 — 稳定前缀在前、动态上下文在后 | ❌ 自动 |
26
- | 🗜️ 压缩 Skills XML | 将 pi 的每 skill 四行 XML 替换为按 skills-root 分组的紧凑单行索引(大小缩减约 93%) | ❌ 自动 |
27
- | 🧹 剥离 session-overview 动态尾字段 | 从 `<session-overview>` 中移除 `RECENT COMMITS`、`Working directory`、`Line count`——这些字段每轮都在变,破坏前缀缓存 | ❌ 自动 |
28
- | 🛡️ 完整性 guard | 检测 prompt 重排是否意外截断了 trellis 结构标记;如发生则回退到原始 prompt 并在 footer 显示 `⚠️ integrity` | ❌ 自动 |
29
- | ⏳ 长缓存保留 | 扩展加载时设置 `PI_CACHE_RETENTION=long`;Pi/provider compat 决定实际发送内容 | ❌ 自动 |
30
- | 🔗 保守 compat 提醒 | DeepSeek session-affinity 提醒,以及 Claude 兼容 endpoint 的明显 cache-control 提醒 | ⚠️ 见下 |
31
- | 📊 Provider-specific 底部统计 | 在 Pi footer/status 中显示受支持 provider family 的只读缓存统计 | ❌ 自动 |
32
-
33
- ## 支持的统计 adapter
34
-
35
- 本版本保留原有 DeepSeek 行为,并增加针对 Pi 或 provider 能安全暴露 usage 的只读统计 adapter。Adapter 选择刻意只使用 model id/name(以及 `message_end` 中 assistant message 的 `model`/`name`);不会用 provider id、API type、base URL、`thinkingFormat` 或 compat flags 来选择统计 adapter。
36
-
37
- | Adapter | 检测方式 | 底部标签 | usage 字段 |
38
- |---|---|---|---|
39
- | DeepSeek | model id/name 包含 `deepseek` | `DS cache` | Pi `usage.cacheRead`/`usage.input`,或可见 raw 字段 `prompt_cache_hit_tokens`、`prompt_cache_miss_tokens`、`prompt_tokens` |
40
- | OpenAI-family | model id/name 包含保守 OpenAI-family token,例如 `gpt-`、`chatgpt`、`o1`、`o3`、`o4` 或 `o5` | `OpenAI cache` | Pi 归一化 usage,或可见 raw 字段 `prompt_tokens_details.cached_tokens` / `input_tokens_details.cached_tokens` 及 prompt/input total |
41
- | Kimi / Moonshot | model id/name 包含 `kimi` | `Kimi cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
42
- | Qwen / Alibaba | model id/name 包含 `qwen` | `Qwen cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
43
- | GLM / Zhipu | model id/name 包含 `glm` | `GLM cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
44
- | MiniMax | model id/name 包含 `minimax` | `MiniMax cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
45
- | Hunyuan / Tencent | model id/name 包含 `hunyuan` | `Hunyuan cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
46
- | Mistral | model id/name 包含 `mistral`、`mixtral` 或 `codestral` | `Mistral cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
47
- | xAI / Grok | model id/name 包含 `grok`,或安全边界内 `xai` 模式 | `Grok cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
48
- | Meta / Llama | model id/name 包含 `llama` | `Llama cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
49
- | NVIDIA Nemotron | model id/name 包含 `nemotron` | `Nemotron cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
50
- | Cohere / Command | model id/name 包含 `cohere` 或 `command-r` | `Cohere cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
51
- | Yi / 零一万物 | model id/name 包含 `yi-`、`01-ai`、`zero-one`,或安全边界内 `yi` 模式 | `Yi cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
52
- | Doubao / ByteDance / Seed | model id/name 包含 `doubao`、`豆包`、`volcengine`、`bytedance`、`byte-dance`,或安全边界内 `seed` 模式 | `Doubao cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
53
- | Baidu ERNIE / 文心一言 | model id/name 包含 `ernie`、`wenxin`、`文心`、`yiyan`、`一言` 或 `baidu` | `ERNIE cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
54
- | Baichuan / 百川 | model id/name 包含 `baichuan` 或 `百川` | `Baichuan cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
55
- | StepFun / 阶跃星辰 | model id/name 包含 `stepfun` 或 `step-` 前缀 | `StepFun cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
56
- | iFlytek Spark / 讯飞星火 | model id/name 包含 `spark`、`xinghuo`、`星火`、`iflytek` 或 `讯飞` | `Spark cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
57
- | InternLM / 书生 | model id/name 包含 `internlm`、`intern-lm` 或 `书生` | `InternLM cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
58
- | Google Gemma | model id/name 包含 `gemma` | `Gemma cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
59
- | Microsoft Phi | model id/name 包含 `phi-` 前缀,或安全边界内 `phi` 模式 | `Phi cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
60
- | AI21 Jamba | model id/name 包含 `jamba` 或 `ai21` | `Jamba cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
61
- | Upstage Solar | model id/name 包含 `solar` 或 `upstage` | `Solar cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
62
- | Perplexity / Sonar | model id/name 包含 `sonar`、`perplexity`,或安全边界内 `pplx` 模式 | `Sonar cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
63
- | Amazon Nova | model id/name 包含 `amazon-nova`,或安全边界内 `nova` 模式 | `Nova cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
64
- | Reka | model id/name 包含 `reka` | `Reka cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
65
- | Falcon / TII | model id/name 包含 `falcon` 或 `tiiuae`(不含裸 `tii`) | `Falcon cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
66
- | Databricks DBRX | model id/name 包含 `dbrx` 或 `databricks` | `DBRX cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
67
- | MosaicML MPT | model id/name 包含 `mosaicml`、`mpt-` 前缀,或安全边界内 `mpt` 模式 | `MPT cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
68
- | StableLM / Stability AI | model id/name 包含 `stablelm`、`stable-lm` 或 `stability-ai` | `StableLM cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
69
- | BAAI / Aquila | model id/name 包含 `aquila` 或 `baai` | `Aquila cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
70
- | LG EXAONE | model id/name 包含 `exaone` | `EXAONE cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
71
- | Naver HyperCLOVA X | model id/name 包含 `hyperclova` 或 `clova-x`(保守检测,不含裸 `clova`/`naver`) | `HyperCLOVA cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
72
- | Aleph Alpha Luminous | model id/name 包含 `luminous`、`aleph-alpha`,或安全边界内 `aleph` 模式 | `Luminous cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
73
- | Nous / Hermes / OpenHermes | model id/name 包含 `nous`、`hermes` 或 `openhermes` | `Hermes cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
74
- | IBM Granite | model id/name 包含 `granite` 或 `ibm-granite` | `Granite cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
75
- | Snowflake Arctic | model id/name 包含 `snowflake-arctic`,或安全边界内 `arctic` 模式 | `Arctic cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
76
- | Huawei Pangu / 盘古 | model id/name 包含 `pangu`、`pan-gu`、`盘古` 或 `huawei-pangu` | `Pangu cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
77
- | SenseTime SenseNova / 商汤 | model id/name 包含 `sensenova`、`sense-nova`、`sensechat` 或 `商汤` | `SenseNova cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
78
- | 360 Zhinao / 智脑 | model id/name 包含 `360gpt`、`360-gpt`、`zhinao` 或 `智脑`(不含裸 `360`) | `Zhinao cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
79
- | OpenBMB MiniCPM | model id/name 包含 `minicpm`、`mini-cpm` 或 `openbmb` | `MiniCPM cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
80
- | XVERSE | model id/name 包含 `xverse` | `XVERSE cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
81
- | OrionStar Orion | model id/name 包含 `orionstar`、`orion-star`,或安全边界内 `orion` 模式 | `Orion cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
82
- | OpenChat | model id/name 包含 `openchat` | `OpenChat cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
83
- | Vicuna | model id/name 包含 `vicuna` | `Vicuna cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
84
- | WizardLM / WizardCoder | model id/name 包含 `wizardlm`、`wizard-lm`、`wizardcoder` 或 `wizard-coder` | `Wizard cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
85
- | Zephyr | model id/name 包含 `zephyr` | `Zephyr cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
86
- | Dolphin | model id/name 包含 `dolphin` | `Dolphin cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
87
- | OpenOrca | model id/name 包含 `openorca` 或 `open-orca` | `OpenOrca cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
88
- | Starling | model id/name 包含 `starling` | `Starling cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
89
- | BLOOM / BigScience | model id/name 包含 `bloom` 或 `bigscience` | `BLOOM cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
90
- | RWKV | model id/name 包含 `rwkv` | `RWKV cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
91
- | Cohere Aya | model id/name 包含 `aya-expanse`,或安全边界内 `aya` 模式(避免 `maya`/`payara`) | `Aya cache` | Pi 归一化 usage,或可见 OpenAI 形状字段 |
92
- | Anthropic / Claude | model id/name 包含 `anthropic` 或 `claude` | `Claude cache` | Pi 归一化 usage,或可见 raw 字段 `cache_read_input_tokens`、`cache_creation_input_tokens`、`input_tokens` |
93
- | Gemini / Vertex | model id/name 包含 `gemini` 或 `vertex` | `Gemini cache` | Pi 归一化 usage,或可见 Gemini/Vertex cached-content token metadata |
94
-
95
- Generic OpenAI-compatible 代理**不会**仅因为使用 OpenAI 形状 API 或 provider id 就被当作 OpenAI-family。如果当前 model id/name 语义不明确,扩展会隐藏底部统计,而不是猜测。
96
-
97
- ## 平台支持
98
-
99
- 本扩展是纯 Node.js 实现 —— 不调用 shell、没有原生绑定、不写死平台相关路径 —— 因此与 Pi 自身保持一致,支持以下系统:
100
-
101
- | 操作系统 | 说明 |
102
- |---|---|
103
- | Linux | 原生支持。 |
104
- | macOS | 原生支持。 |
105
- | Windows | 通过 Pi 在 Windows 下要求的 bash shell 运行(Git Bash、Cygwin、MSYS2 或 WSL)。详见 Pi 的 [Windows setup](https://github.com/earendil-works/pi-coding-agent/blob/main/docs/windows.md)。 |
106
- | Termux / Android | 在 Pi 的 Termux 环境中可用。 |
9
+ 用于提升 Pi 中 provider 侧 KV Cache / Prompt Cache 命中率的扩展:把稳定 prompt 内容前置,给 OpenAI-compatible 请求补保守的 `prompt_cache_key`,提示代理渠道常见缓存路由兼容问题,并在底部显示只读缓存统计。
107
10
 
108
- 状态文件 `~/.pi/agent/` 通过 Node `os.homedir()` 解析,所以在 Windows 上会自动展开为 `C:\Users\<你>\.pi\agent\...`。扩展的 compat 提醒、`/cache-optimizer doctor` `/cache-optimizer compat` 会自动显示适合当前平台的路径(Linux/macOS 上显示 `~/.pi/agent/models.json`,Windows 上显示 `%USERPROFILE%\.pi\agent\models.json`)。本文档中所有 shell 命令均使用 bash 语法,与 Pi 在每个受支持平台下运行的 shell 一致;只要在 Pi 内(或为 Pi 而执行)运行,就**不需要**改写为 PowerShell 或 `cmd.exe` 形式。
11
+ **GitHub About:** Improve Pi prompt/KV cache hit rates with stable prompts, OpenAI-compatible cache keys, proxy compat warnings, and footer cache stats.
109
12
 
110
- ## 安装
13
+ > 本包已从 `pi-deepseek-cache-optimizer` 改名。已有底部统计会自动迁移。本扩展绝不会创建、修改、备份或删除你的 `~/.pi/agent/models.json`。
111
14
 
112
- 请先安装并配置好 Pi,然后安装本扩展:
15
+ ## 目录
113
16
 
114
- ```bash
115
- pi install npm:pi-cache-optimizer
116
- ```
17
+ - [功能](#功能)
18
+ - [安装](#安装)
19
+ - [命令](#命令)
20
+ - [持久 Opt-out](#持久-opt-out)
21
+ - [OpenAI-compatible 代理配置](#openai-compatible-代理配置)
22
+ - [Footer 统计](#footer-统计)
23
+ - [卸载](#卸载)
24
+ - [验证效果](#验证效果)
25
+ - [License](#license)
117
26
 
118
- 安装后 `PI_CACHE_RETENTION=long` **自动生效**,system prompt **自动重组**、skills 自动压缩、session-overview 动态尾字段自动剥离;受支持 model family 的响应完成且暴露 usage 后,底部状态栏会显示缓存统计。
27
+ ## 功能
119
28
 
120
- ## 退出(Opt-out)
29
+ - 将稳定的 system prompt 内容移动到动态上下文之前。
30
+ - 压缩 Pi skill 列表,并移除 session-overview 中的易变字段。
31
+ - 在 Pi / provider compat 支持时请求长缓存保留。
32
+ - 对 `openai-completions` / `openai-responses` 请求,在没有有效 key 时使用 Pi session id 补 `prompt_cache_key`。
33
+ - 对缺少缓存 / session-affinity compat 的第三方 OpenAI-compatible 代理给出一次性提醒。
34
+ - 为支持的模型家族显示按 session 隔离的底部缓存统计。
121
35
 
122
- | 环境变量 | 作用 |
123
- |---------|------|
124
- | `PI_CACHE_OPTIMIZER_NO_PROMPT_REWRITE=1` | 跳过所有 `before_agent_start` prompt 修改(session-overview 字段剥离、skills 压缩、稳定前缀重排);底部统计和 `prompt_cache_key` 兜底仍然生效 |
125
- | `PI_CACHE_OPTIMIZER_NO_SKILL_COMPRESSION=1` | 保留 pi 的 verbose `<available_skills>` XML(退出一行索引模式) |
126
- | `PI_CACHE_OPTIMIZER_OPENAI_CACHE_KEY=0` | 禁用 OpenAI-family `prompt_cache_key` 兜底(默认启用) |
127
- | `PI_CACHE_OPTIMIZER_NO_OPENAI_CACHE_KEY=1` | 禁用 OpenAI-family `prompt_cache_key` 兜底 |
36
+ 缓存是 provider 侧的 best-effort 行为。第三方代理仍可能隐藏缓存 usage、拒绝不支持的参数,或把请求路由到多个上游。
128
37
 
129
- ## 卸载
130
-
131
- 请移除当初安装时使用的同一个 package source。npm 包对应命令:
38
+ ## 安装
132
39
 
133
40
  ```bash
134
- pi remove npm:pi-cache-optimizer
41
+ pi install npm:pi-cache-optimizer
135
42
  ```
136
43
 
137
- 如果你是从本地路径安装的,请移除同一个路径/source,例如:
44
+ 如果之前安装过旧包:
138
45
 
139
46
  ```bash
140
- pi remove /absolute/path/to/pi-deepseek-cache-optimizer
141
- # 或者,如果安装时使用的就是这个相对路径:
142
- pi remove ./relative/path/to/pi-deepseek-cache-optimizer
47
+ pi remove npm:pi-deepseek-cache-optimizer && pi install npm:pi-cache-optimizer
143
48
  ```
144
49
 
145
- 如果当初使用 `pi install -l ...` 安装到项目级 settings,请使用对应的项目级卸载命令,例如 `pi remove -l npm:pi-cache-optimizer`。
50
+ 安装、更新或移除后,在 Pi 中运行 `/reload`,让 extension hooks 刷新。
146
51
 
147
- 移除 package 后,在 Pi 中执行 `/reload` 或重启 Pi,让扩展卸载。底部统计计数器会单独持久化;如果也想删除这个本地状态文件,可以执行:
52
+ ## 命令
148
53
 
149
- ```bash
150
- rm ~/.pi/agent/pi-cache-optimizer-stats.json
151
- # 旧名称(首次运行新版本时会被迁移、可能已被删除;仍在的话可安全删除):
152
- rm -f ~/.pi/agent/deepseek-cache-optimizer-stats.json
153
- ```
54
+ | 命令 | 作用 |
55
+ |---|---|
56
+ | `/cache-optimizer` | UI 支持时打开交互菜单;否则打印帮助和当前状态。 |
57
+ | `/cache-optimizer enable` | 在当前 Pi 进程中开启运行时优化,清零当前 session 统计,并开始新的“开启状态”测量。 |
58
+ | `/cache-optimizer disable` | 在当前 Pi 进程中关闭优化,清零当前 session 统计,并继续以 disabled 对比模式采集 footer 统计。运行 `/reload` 或重启 Pi 后回到启动时行为。 |
59
+ | `/cache-optimizer doctor` | 显示当前模型 / provider / API / base URL / compat 与低命中诊断。 |
60
+ | `/cache-optimizer compat` | 对当前模型显示可复制的 compat 建议(如适用)。 |
61
+ | `/cache-optimizer stats` | 显示当前模型今天的 session-scoped 统计和近期趋势。 |
62
+ | `/cache-optimizer reset` | 只重置当前 session + 当前模型的本地统计;不会修改上游 provider 缓存。 |
154
63
 
64
+ `enable` / `disable` 是当前进程内开关。若要持久关闭某些能力,请使用下面的环境变量。
155
65
 
66
+ ## 持久 Opt-out
156
67
 
157
- ## 添加 OpenAI-compatible 代理渠道
68
+ | 环境变量 | 作用 |
69
+ |---|---|
70
+ | `PI_CACHE_OPTIMIZER_NO_PROMPT_REWRITE=1` | 只关闭 prompt 改写;footer 统计和 cache-key fallback 仍启用。 |
71
+ | `PI_CACHE_OPTIMIZER_NO_SKILL_COMPRESSION=1` | 保留 Pi 原始 verbose skill XML。 |
72
+ | `PI_CACHE_OPTIMIZER_OPENAI_CACHE_KEY=0` | 关闭 OpenAI-compatible `prompt_cache_key` fallback。 |
73
+ | `PI_CACHE_OPTIMIZER_NO_OPENAI_CACHE_KEY=1` | 关闭 OpenAI-compatible `prompt_cache_key` fallback。 |
158
74
 
159
- 当在 `~/.pi/agent/models.json` 中添加第三方 OpenAI-compatible 代理 provider(例如 `otokapi`、`cafecode`、OpenRouter 等)时,缓存优化的 `compat` 标志对模型正常使用不是必需的,但它们能显著提高缓存持久性。
75
+ ## OpenAI-compatible 代理配置
160
76
 
161
- ### 最小 provider 配置模板
77
+ LiteLLM / OneAPI / NewAPI / 类 OpenRouter 渠道等第三方 `openai-completions` 代理,缓存命中率低通常是因为请求被分散到多个后端。安全默认配置是 session affinity:
162
78
 
163
- ```jsonc
79
+ ```json
164
80
  {
165
81
  "providers": {
166
82
  "your-provider-id": {
167
- "api": "openai-completions", // 或 "openai-responses"
168
- "baseUrl": "https://your-proxy.example.com/v1",
169
- "apiKey": "your-api-key",
170
- "models": {
171
- "gpt-5.5": {
172
- "id": "gpt-5.5",
173
- "name": "GPT 5.5",
174
- "contextWindowTokens": 128000,
175
- "maxOutputTokens": 8192,
176
- "thinking": {
177
- // 使用你的代理实际支持的 thinking 级别。
178
- // Pi 通过 thinkingLevelMap 将 --thinking <level> 映射为 token。
179
- // 下面模板保持各级别独立 —— 不要全部映射为 "xhigh"。
180
- // 你的代理可能不支持所有级别;移除不支持的或逐个测试。
181
- "thinkingLevelMap": {
182
- "off": null,
183
- "minimal": "minimal",
184
- "low": "low",
185
- "medium": "medium",
186
- "high": "high",
187
- "xhigh": "xhigh"
188
- }
189
- },
190
- "compat": {
191
- "supportsLongCacheRetention": true,
192
- "sendSessionAffinityHeaders": true
193
- }
194
- }
195
- }
196
- }
197
- }
198
- }
199
- ```
200
-
201
- 关键点:
202
-
203
- - `thinkingLevelMap` 保持不同的 level 独立。如果你的代理不支持某个级别(例如 `minimal`),请移除该条目或设为 `null`。**不要**将所有级别都映射为 `"xhigh"` —— 那会破坏用户对推理努力度的控制。
204
- - `compat` 标志帮助 Pi 请求更长的缓存保留时间,并通过发送 session-affinity headers 实现代理侧缓存本地性。仅在代理支持时才启用。
205
- - 扩展通过模型 `id`/`name` 字符串来检测模型家族,而不是通过 provider id、base URL 或 API 类型。请使用易识别的模型 id(例如 `gpt-5.5`、`kimi-k2.5`),以便正确匹配统计 adapter。
206
-
207
- ## 底部缓存统计
208
-
209
- Pi footer 只显示**当前活跃模型 family** 的统计,例如:
210
-
211
- ```text
212
- DS cache 3/5 · 0.77M/0.80M tok (96%)
213
- OpenAI cache 2/4 · 0.25M/0.70M tok (36%)
214
- Claude cache 1/3 · 0.10M/0.45M tok (22%) · write 0.20M tok
215
- Gemini cache 1/2 · 0.18M/0.50M tok (36%)
216
- ```
217
-
218
- 含义:
219
-
220
- - `3/5`:该 provider family 的 5 次受支持 assistant 响应中,有 3 次出现 cache-read tokens。
221
- - `0.77M/0.80M tok`:累计 cache-read input tokens / 累计 prompt input tokens,单位固定显示为百万(M)。
222
- - 百分比:`cacheRead / total prompt input`。
223
- - `write ... tok` 只会在 Claude cache-write tokens 非零时出现,因为 Anthropic cache write 有独立成本/统计语义。
224
-
225
- 统计规则:
226
-
227
- - 计数器按 provider family 分开保存。DeepSeek、OpenAI、Claude、Gemini 不会合并成一个全局 hit rate。
228
- - 底部只显示当前活跃模型 family 的标签和计数器;不支持或语义不明确的模型会隐藏/清空状态。
229
- - 只统计 Pi/provider 暴露 usage 的 assistant 响应;没有 usage 时不更新计数器。
230
- - Adapter 匹配只使用当前 model id/name 加 assistant message 的 `model`/`name`;选择 adapter 时会忽略宽泛 provider/API/compat metadata。
231
- - 优先使用 Pi 归一化后的 `usage.input`、`usage.cacheRead`、`usage.cacheWrite`。只有当 assistant message 上可见已知 provider raw 字段时,才做保守 fallback 解析。
232
- - Pi 归一化 usage 的 prompt input 总量使用 `input + cacheRead + cacheWrite`。provider raw normalizer 会优先使用各 provider 文档里的 total/input 字段。
233
- - 统计只更新底部状态栏,不创建额外 TUI 组件,也不写诊断文件;因此不会因调试组件频繁重绘导致屏幕闪烁。
234
- - 统计会持久化到本地小 JSON 文件:`~/.pi/agent/pi-cache-optimizer-stats.json`。早期 1.x 版本使用 `~/.pi/agent/deepseek-cache-optimizer-stats.json`;首次运行新版时会从旧路径读一次、复制到新路径、然后 best-effort 删除旧文件。该文件只保存计数器和本地日期,不保存 API key、prompt、消息内容、headers 或模型输出。
235
- - DeepSeek-only 旧版本的 v1 状态文件会自动迁移到 DeepSeek adapter 计数器。
236
-
237
- ## 统计桶隔离(Session-scoped)
238
-
239
- - 统计现在按 Pi session + provider/model 隔离,不再全局聚合。
240
- - 每个 Pi 进程(session)从零开始计数。不同 session 对同一 provider/model 的统计不共享。
241
- - 同一 Pi session 中,同一 provider/model 的统计正常累积。
242
- - Pi 进程重新启动时,新的 session 从头开始统计。
243
- - `/reload` **不会**清空累计的 session-scoped 统计;只清除临时内存状态(recent samples、integrity notification)。
244
- - 跨过本地自然日时,下一次状态更新或受支持 provider 响应时会自动按本地日期清零。
245
- - 持久化统计文件使用不透明的 session hash key(SHA-256 哈希后的 session id)来隔离不同 session 的数据。原始 session id 不会写入文件。
246
-
247
- > **并发写入说明**:统计以原子方式持久化(写 temp 文件再 rename),但多个 Pi 进程同时读写仍然存在 lost-update 窗口(经典的 read-modify-write 竞态)。实现中尽可能保留顺序语义(每次写入只替换当前 session 的数据,其他 session 的数据从前次读取追加),但**不保证**跨进程并发安全。如果同时运行多个 Pi 实例使用不同 provider/model,统计文件偶尔可能覆盖彼此 session 的数据。这只影响磁盘持久化;每个进程的内存统计始终正确。
248
-
249
- ## 诊断命令
250
-
251
- 扩展注册了 Pi 命令 `/cache-optimizer` 用于交互式诊断。
252
-
253
- ```
254
- /cache-optimizer — 交互菜单(无 UI 时显示文字帮助)
255
- /cache-optimizer doctor — 显示 provider、model、API、base URL、compat 状态
256
- 及低命中原因诊断
257
- /cache-optimizer stats — 显示当前模型的 stats 桶和近期趋势
258
- /cache-optimizer compat — 显示 compat 建议和编辑说明
259
- /cache-optimizer reset — 重置当前 Pi session 中当前模型的本地统计
260
- (不影响上游 provider prompt cache)
261
- ```
262
-
263
- 不带参数时,当 Pi UI 支持时(`ctx.ui.select` 可用),`/cache-optimizer` 会显示交互选择菜单(Doctor / Stats / Compat / Reset / Cancel)。在非交互终端中,会回退到文字帮助和当前模型 compat 状态。
264
-
265
- ### `/cache-optimizer reset`
266
-
267
- 仅重置当前 Pi session 中活跃 provider/model 的统计桶。清除今日请求计数(命中/总数)、缓存 token 计数和近期趋势样本。同一 session 中其他 provider/model 的桶不受影响,其他 session 的数据也不受影响。
268
-
269
- ```text
270
- Provider: otokapi
271
- Model: gpt-5.5
272
-
273
- ✅ 已重置 "otokapi/gpt-5.5" 的本地 session 缓存统计。
274
- 上游 provider prompt cache 未被修改。
275
- 新的请求将为这个 Pi session 重新开始统计。
276
- ```
277
-
278
- 如果没有选中的模型,显示警告。如果当前模型不匹配缓存的 adapter(不显示底部统计),则显示友好的无操作提示。
279
-
280
- ## 建议的 compat 配置
281
-
282
- 对直连 DeepSeek 或 DeepSeek-like OpenAI-compatible 代理,建议在对应 provider 或 model 的 `compat` 中配置。
283
-
284
- `compat` 块应该放在 `~/.pi/agent/models.json` 中 provider 对象内部,与 `baseUrl`、`api`、`apiKey`、`models` 同级:
285
-
286
- ```jsonc
287
- {
288
- "providers": {
289
- "deepseek": {
290
83
  "api": "openai-completions",
291
- "baseUrl": "https://api.deepseek.com/v1",
292
- "apiKey": "sk-...",
293
- "models": { /* ... */ },
294
- // 👇 compat 在此位置,而不是在 models 内部
84
+ "baseUrl": "https://example.com/v1",
85
+ "apiKey": "env:YOUR_API_KEY",
295
86
  "compat": {
296
- "thinkingFormat": "deepseek",
297
- "supportsLongCacheRetention": true,
298
87
  "sendSessionAffinityHeaders": true
299
- }
88
+ },
89
+ "models": [
90
+ { "id": "gpt-5.5", "name": "GPT-5.5" }
91
+ ]
300
92
  }
301
93
  }
302
94
  }
303
95
  ```
304
96
 
305
- 如果你的 provider id 不是 `deepseek`(例如公司代理、OpenRouter 风格代理),也可以把同样字段放在该 provider 或具体 DeepSeek 模型的 `compat` 里。扩展识别 DeepSeek-like 模型的依据仍然是 model id / model name 是否包含 `deepseek`;不会根据 provider id、baseUrl `thinkingFormat` 判断。当前推荐的 DeepSeek 验证路径只覆盖官方直连 `deepseek/deepseek-v4-pro`。
97
+ 只有在 endpoint / proxy 明确支持 OpenAI long prompt cache retention 时,才添加 `supportsLongCacheRetention: true`。本扩展不会直接写入 `prompt_cache_retention`;它会请求 `PI_CACHE_RETENTION=long`,当 compat 声明支持 long retention 时,Pi 可能发送 `prompt_cache_retention`。如果某代理返回 `400 Unsupported parameter: prompt_cache_retention`,请为该渠道移除 / 避免 `supportsLongCacheRetention`,如支持可保留 `sendSessionAffinityHeaders`,并用 `/cache-optimizer compat` / `/cache-optimizer doctor` 诊断。当启用 long retention compat 时观察到 400,本扩展会给一次性 warning,并在 doctor 中提示。本扩展只给建议,不会修改 `models.json`。
306
98
 
307
- 扩展会对每个 provider/model **每个会话最多提醒一次**。对于 DeepSeek-like OpenAI-compatible 模型,会在缺少以下配置时提醒:
99
+ ## Footer 统计
308
100
 
309
- - `supportsLongCacheRetention: true`:Pi 可能不会发送 `prompt_cache_retention: "24h"`。
310
- - `sendSessionAffinityHeaders: true`(OpenAI Completions 兼容 API)或 `sendSessionIdHeader: true`(OpenAI Responses 兼容 API):Pi 可能不会发送 session affinity headers(如 `session_id`、`x-client-request-id`、`x-session-affinity`),代理/负载均衡场景下缓存命中可能更差。
101
+ 统计是只读本地计数,保存在 `~/.pi/agent/pi-cache-optimizer-stats.json`,按 Pi session + provider/model 隔离。文件只包含日期和数字计数,不包含 API key、prompt、payload、headers、响应或模型输出。
311
102
 
312
- 对于通过 OpenAI-compatible endpoint 暴露的 Claude/Anthropic 模型,如果模型明显 Claude-like 但缺少 `cacheControlFormat: "anthropic"`,扩展可能提醒。只有在 endpoint 支持 Anthropic-style cache-control markers 时才应启用该 compat flag。
313
-
314
- > 提醒:只有在 endpoint 或代理明确支持时,才建议启用 session-affinity headers 或 cache-control compat。
315
-
316
- ## 原理
317
-
318
- Provider 缓存通常依赖精确或近似精确的前缀匹配。Pi 的 system prompt 包含跨会话稳定的内容(工具定义、技能、规范),也包含每次变化的动态内容(git status、当前任务)。
103
+ 示例 footer:
319
104
 
320
105
  ```text
321
- 优化前: [动态 git status | 任务上下文 | 稳定工具+规范]
322
- ↓ 每次前缀不同 → 缓存复用降低
323
-
324
- 优化后: [稳定工具+规范 | 动态 git status | 任务上下文]
325
- ↓ 稳定前缀不变 → 更容易命中缓存
106
+ OpenAI cache 3/10 (30%) · 0.002M/0.005M tok ⚠️ compat
326
107
  ```
327
108
 
328
- Pi 本身还会根据模型 compat 和 `PI_CACHE_RETENTION` 决定是否发送缓存相关字段,例如 `prompt_cache_retention`、session affinity headers 或 Anthropic-style `cache_control`。本扩展现在默认只做一个保守的 request-body 兜底:对所有使用 OpenAI-compatible Pi API(`openai-completions` / `openai-responses`)的模型,当顶层 `prompt_cache_key` 缺失或为空时,用 Pi session id 补上,并且不会覆盖已有的非空 key。这覆盖 GPT 命名模型、Kimi/Moonshot、Qwen/Alibaba、GLM/Zhipu、MiniMax、Hunyuan 等任何使用 OpenAI 形状 API 的 provider——只有 `kiro-api` 等 custom transport 不被注入。本扩展不伪造缓存命中,只帮助配置、提高稳定前缀概率,并把已暴露的 usage 汇总到底部状态栏。
329
-
330
- ## 提高 cache 命中率
109
+ 支持的 footer label 包括:DS、Claude、OpenAI、Gemini、Kimi、Qwen、GLM、MiniMax、Hunyuan、Mistral、Grok、Llama、Nemotron、Cohere、Yi、Doubao、ERNIE、Baichuan、StepFun、Spark、InternLM、Gemma、Phi、Jamba、Solar、Sonar、Nova、Reka、Falcon、DBRX、MPT、StableLM、Aquila、EXAONE、HyperCLOVA、Luminous、Hermes、Granite、Arctic、Pangu、SenseNova、Zhinao、MiniCPM、XVERSE、Orion、OpenChat、Vicuna、Wizard、Zephyr、Dolphin、OpenOrca、Starling、BLOOM、RWKV、Aya。
331
110
 
332
- 代码里的命中率优化会保持保守和 provider-neutral:把最大的稳定 prompt 前缀放在最前面,让 Pi/provider compat 发送其支持的缓存控制字段,避免把不受支持的 request 字段泄漏给代理。
111
+ Adapter 选择只看模型 id/name(以及 message_end 时 assistant message 的 model/name)。仅使用 OpenAI-shaped API 不会被当作 OpenAI-family,除非模型 id/name 匹配受支持的家族。
333
112
 
334
- 扩展会自动做这些事:
335
-
336
- - 把稳定 prompt 内容移动到动态 task/git/session 上下文之前。除了 tools、skills、custom prompt、append prompt 和 guideline bullets,也会把已知稳定的项目/规范文件(例如 `AGENTS.md`、`CLAUDE.md`、`GEMINI.md`、`CURSOR.md`、`.trellis/spec/...`)保留在更靠前的 cacheable prefix 中。任意大型 context file 不会只因为体积大就被提前,因为它们可能是 task/session-specific 内容。
337
- - 设置 `PI_CACHE_RETENTION=long`,让 Pi 在当前模型/provider compat 支持时请求更长缓存保留。
338
- - 按 provider family 分开 footer 计数,方便你验证当前活跃模型 family 是否真的报告 cache reads。
339
-
340
- 各 provider 注意点:
341
-
342
- - DeepSeek:现有行为仍是参考路径。稳定前缀排序,加上 long-retention / session-affinity compat,最有利于自动 KV prefix 复用。
343
- - OpenAI-family:prompt caching 只会在真实上游支持且 prompt 足够长时自动生效。请尽量把静态 instructions、tools、examples、specs 放在变化的 user/task context 前面。retention 传输默认由 Pi 负责。对 OpenAI-compatible Pi API,本扩展会用 Pi session id 补齐缺失或空白的顶层 `prompt_cache_key`(与 Pi core 官方 OpenAI 行为对齐),并且不会覆盖已有非空的 `prompt_cache_key` / `promptCacheKey`。该兜底现在适用于所有使用 `openai-completions` / `openai-responses` 的模型(不限于 GPT 命名),因此 Kimi、Qwen、GLM、MiniMax、Hunyuan 等 OpenAI-compatible 模型也同样受益。可用 `PI_CACHE_OPTIMIZER_NO_OPENAI_CACHE_KEY=1` 或 `PI_CACHE_OPTIMIZER_OPENAI_CACHE_KEY=0` 禁用该兜底。不支持该字段的 OpenAI-compatible 代理可能拒绝请求;custom API 不会被注入。
344
- - Claude:prompt caching 依赖 Anthropic `cache_control` breakpoints。本扩展不会自行注入 breakpoint;对兼容 endpoint,只在 endpoint 明确支持时配置 Pi compat,例如 `cacheControlFormat: "anthropic"`。
345
- - Gemini/Vertex:implicit caching 受益于重复的大型稳定前缀。本扩展不会创建 explicit `cachedContents` resources,也不会保存 cache resource names。
346
- - Proxies/aggregators:尽量固定上游 routing/provider order。如果同一个 model id/name 可能路由到不同上游,cache hit rate 会不稳定。
347
-
348
- ## Provider-specific 限制
113
+ ## 卸载
349
114
 
350
- 本包现在有 provider-family stats adapter,但仍避免盲目泛化:
115
+ ```bash
116
+ pi remove npm:pi-cache-optimizer
117
+ ```
351
118
 
352
- - DeepSeek cache 是自动的 prefix/KV cache。命中是 best-effort,代理可能隐藏 DeepSeek usage 字段。DeepSeek 的 Anthropic API 兼容层**明确忽略 `cache_control` markers**(对所有 content 类型均忽略)——像 Claude Code 那样用显式缓存断点对 DeepSeek 无效。
353
- - **Kiro / kiro-api**:`pi-provider-kiro` 扩展使用 AWS CodeWhisperer / Q Developer 流式协议(不是 Anthropic Messages / OpenAI Chat Completions / Bedrock Converse)。该协议没有 `cache_control` marker 的注入位置,也不返回 `cache_read_input_tokens`。对 Kiro Claude 模型,底部会显示 **0%**——这是 `pi-provider-kiro` 的限制,不是本扩展的 bug。不要强行用特殊逻辑 bump 这些数字。
354
- - OpenAI-family prompt caching 只有在真实上游支持且 prompt 足够长时才会自动生效。adapter 基于模型名称且刻意保守;不会用 provider/API/base URL metadata 推断官方 OpenAI 支持。
355
- - Claude prompt caching 依赖显式 Anthropic cache-control breakpoints。本版本只报告 Pi/provider 暴露的统计;不会插入 breakpoint,也不会修改请求体。
356
- - Gemini/Vertex 可能暴露 implicit cached-content token count。本版本不会创建、保存、更新或删除 explicit Gemini cached-content resources。
357
- - Proxies/aggregators 可能把同一个 model name 路由到不同上游 provider。由于检测是 id/name-only,请使用无歧义 model name、固定上游 routing,并验证 exposed usage 后再判断缓存行为。
119
+ 然后运行 `/reload` 或重启 Pi。可选:删除本地统计文件:
358
120
 
359
- ## 本版本不包含
121
+ | 平台 | 删除本地统计文件 |
122
+ |---|---|
123
+ | Linux / macOS / WSL | `rm -f ~/.pi/agent/pi-cache-optimizer-stats.json ~/.pi/agent/deepseek-cache-optimizer-stats.json` |
124
+ | Windows PowerShell | `Remove-Item -Force "$env:USERPROFILE\.pi\agent\pi-cache-optimizer-stats.json", "$env:USERPROFILE\.pi\agent\deepseek-cache-optimizer-stats.json" -ErrorAction SilentlyContinue` |
125
+ | Windows 命令提示符 | `del /f /q "%USERPROFILE%\.pi\agent\pi-cache-optimizer-stats.json" "%USERPROFILE%\.pi\agent\deepseek-cache-optimizer-stats.json" 2>nul` |
360
126
 
361
- - 广泛/provider-agnostic 修改请求体,或做 cache-control 注入。唯一默认 request-body 兜底是 OpenAI-family 在 OpenAI-compatible API 上使用 Pi session id `prompt_cache_key`,且已有有效 key 时会跳过。
362
- - 注入 Anthropic `cache_control` markers。
363
- - 向 custom / 非 OpenAI-compatible API 发送 OpenAI `prompt_cache_key`;该兜底只要求 API 是 `openai-completions` / `openai-responses`(`kiro-api` 等 custom transport 不被注入,但模型命名不再要求属于 GPT-family)。
364
- - 在 Pi 自己的 compat 处理之外覆盖 OpenAI `prompt_cache_retention`。
365
- - 创建 Gemini explicit `cachedContents` resources 或持久化 cache resource names。
366
- - 对不暴露可靠 cache usage 的 provider 声称统计支持。
127
+ 清理时不要删除 `models.json`;它保存你的 Pi 模型 / provider 配置,不属于本包。
367
128
 
368
129
  ## 验证效果
369
130
 
370
- ### Pi 中查看
371
-
372
- - 查看当前活跃 family 的底部标签,例如 `DS cache ...`、`OpenAI cache ...`、`Claude cache ...` 或 `Gemini cache ...`。
373
- - 使用 Pi 内置 `/stats` 查看 Pi 归一化后的 `cacheRead` tokens 是否增长。
374
- - 对 DeepSeek,Pi 会把 `usage.input` 归一化为未缓存/miss prompt tokens,把 `usage.cacheRead` 归一化为 `prompt_cache_hit_tokens`,所以 footer 分母使用 `input + cacheRead + cacheWrite` 还原(provider 正常报告 usage 时应对应 DeepSeek `prompt_tokens`)。
375
- - footer 的 hit count 是请求级:每个 assistant response 计入一次总请求,`cacheRead > 0` 计为命中。DeepSeek 后台可能使用不同时间窗口或账号级/provider 侧聚合;对比前请先对齐 reset/window。
376
- - 对 provider raw API,可对比文档中的 usage 字段,例如 DeepSeek `prompt_cache_hit_tokens`、OpenAI `cached_tokens`、Anthropic `cache_read_input_tokens` 或 Gemini/Vertex cached-content token count。
377
-
378
- ### 官方 DeepSeek baseline(推荐)
379
-
380
- 请使用官方直连 `deepseek/deepseek-v4-pro` 做 DeepSeek 基线;暂不建议把代理路径混进同一次验证。请不要把 API key 粘贴到聊天记录或 issue 中。
381
-
382
- 1. 配置官方 key(任选一种方式):
383
-
384
- ```bash
385
- export DEEPSEEK_API_KEY='...'
386
- ```
387
-
388
- 或使用 Pi 的登录/配置方式保存 key。
389
-
390
- 2. 确认模型可见:
391
-
392
- ```bash
393
- pi --list-models deepseek-v4-pro
394
- ```
395
-
396
- 应能看到 `deepseek/deepseek-v4-pro`。
397
-
398
- 3. 运行最小请求:
399
-
400
- ```bash
401
- pi --model deepseek/deepseek-v4-pro --thinking high
402
- ```
403
-
404
- 在 Pi 中连续输入几次相同或高度相似的短 prompt,例如:
405
-
406
- ```text
407
- 请用一句话回答:cache baseline ping
408
- ```
409
-
410
- 4. 对同一或高度相似请求连续运行至少三次,再用底部 `DS cache ...` 和 `/stats` 对比 `cacheRead` / hit rate 是否增长。
411
-
412
- DeepSeek 的缓存前缀以服务端 prefix/cache unit 为粒度。第一次重复但在后缀处发生分歧的请求,可能是在构建公共前缀缓存;第三次以及之后与该公共前缀匹配的请求通常更有参考意义。官方文档提到缓存清理可能是数小时到数天的 best-effort 行为,但这不是“命中保证”;短时间内 miss 也不一定代表 TTL 已经失效,可能只是前缀粒度、路由、请求差异或缓存尚未建立。
413
-
414
- > 注意:baseline 会消耗少量 token;请使用短 prompt,不要粘贴大文件。当前推荐测试命令只使用官方 `deepseek/deepseek-v4-pro`。
131
+ 1. 选择一个 provider 会暴露 cache usage 的模型。
132
+ 2. 在同一个 Pi session 中连续发送几轮相似请求。
133
+ 3. 观察 footer,或运行 `/cache-optimizer stats`。
134
+ 4. 对第三方代理,再运行 `/cache-optimizer doctor`,并在代理侧确认 sticky routing / session affinity。
415
135
 
416
- ## 许可证
136
+ ## License
417
137
 
418
- 本项目基于 [MIT License](./LICENSE) 开源发布。
138
+ MIT