pi-cache-optimizer 2.8.13 → 2.8.14
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.
- package/README.md +5 -2
- package/README.zh-CN.md +5 -2
- package/index.ts +41 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -92,6 +92,7 @@ The interactive `/cache-optimizer` menu includes `Footer mode`, where you can ch
|
|
|
92
92
|
| Env var | Effect |
|
|
93
93
|
|---|---|
|
|
94
94
|
| `PI_CACHE_OPTIMIZER_NO_PROMPT_REWRITE=1` | Disable prompt mutations only; footer stats and cache-key fallback remain active. |
|
|
95
|
+
| `PI_CACHE_OPTIMIZER_VIRTUAL_REWRITE=1` | Explicitly allow native virtual prompt rewriting only when the routing registry exposes a non-Responses, non-Codex candidate chain. Unknown or incomplete routes remain unchanged. |
|
|
95
96
|
| `PI_CACHE_OPTIMIZER_NO_SKILL_COMPRESSION=1` | Keep Pi's verbose skill XML. |
|
|
96
97
|
| `PI_CACHE_OPTIMIZER_NO_OPENAI_CACHE_KEY=1` | Disable the OpenAI-compatible `prompt_cache_key` fallback. Preferred explicit opt-out. |
|
|
97
98
|
| `PI_CACHE_OPTIMIZER_OPENAI_CACHE_KEY=0` | Disable the same fallback via the legacy inverse switch. Values `0`, `false`, `no`, or `off` disable it. |
|
|
@@ -367,12 +368,14 @@ Pi 0.99 lets extensions register virtual models with `pi.registerVirtualModel()`
|
|
|
367
368
|
- Request hooks read the dispatched model id from the provider payload and match it against physical models with configured credentials. The `prompt_cache_key` fallback, `prompt_cache_retention` safety, Anthropic TTL repair, and per-model `prompt_cache_key` omit rules then apply to that physical model. If several credentialed providers share the id and would be treated differently, the extension does not guess; identity-dependent request changes are skipped.
|
|
368
369
|
- Footer stats and `/cache-optimizer doctor`, `compat`, `stats`, `reset`, and `fix` use the physical model that answered last on the current session branch, matching Pi's own routed-model display and context limits. Doctor and compat name both the virtual selection and that physical model.
|
|
369
370
|
- Before Pi routes the first request, the footer stays empty and diagnostics ask you to send a prompt first.
|
|
370
|
-
- Prompt rewriting is skipped for virtual selections: Pi picks the physical model after the system prompt is built, and a reordered prompt must not reach a safety-filtered Codex route.
|
|
371
|
+
- Prompt rewriting is skipped for virtual selections by default: Pi picks the physical model after the system prompt is built, and a reordered prompt must not reach a safety-filtered Codex route. `PI_CACHE_OPTIMIZER_VIRTUAL_REWRITE=1` is an explicit opt-in only when the routing registry exposes a complete candidate chain and every candidate is a known non-Responses, non-Codex transport; unknown or incomplete routes remain unchanged.
|
|
371
372
|
- The session-affinity header bridge is skipped as well, because Pi builds request headers before the payload exists. Pi still sends the physical model's own configured affinity headers.
|
|
372
373
|
|
|
373
374
|
## For router / virtual-channel extension authors
|
|
374
375
|
|
|
375
|
-
If your Pi extension provides a virtual routing provider (for example `router/auto`, `router/smart`, or a profile/channel that forwards to a real upstream), this extension can show cache stats for the real upstream provider/model instead of the virtual shell. Integration is optional, versioned, and does **not** require importing this package.
|
|
376
|
+
If your Pi extension provides a virtual routing provider (for example [`pi-router`](https://github.com/jiangge/pi-router)'s `router/auto`, `router/smart`, or a profile/channel that forwards to a real upstream), this extension can show cache stats for the real upstream provider/model instead of the virtual shell. Integration is optional, versioned, and does **not** require importing this package.
|
|
377
|
+
|
|
378
|
+
For [`pi-router`](https://github.com/jiangge/pi-router), use a current release that implements `pi.routing.registry.v1`. Direct `router/*` selections continue to use the normal prompt optimizer. When a native Pi 0.99+ virtual model is routed through a registry-aware router, the optional `PI_CACHE_OPTIMIZER_VIRTUAL_REWRITE=1` path inspects the router's candidate chain before rewriting; candidates using OpenAI Responses/Codex APIs, incomplete metadata, and unavailable route information fail closed.
|
|
376
379
|
|
|
377
380
|
### Minimum integration: final assistant message metadata
|
|
378
381
|
|
package/README.zh-CN.md
CHANGED
|
@@ -92,6 +92,7 @@ Pi 0.79.7 及之后,`pi update` 默认只更新 Pi 本体。若要更新已安
|
|
|
92
92
|
| 环境变量 | 作用 |
|
|
93
93
|
|---|---|
|
|
94
94
|
| `PI_CACHE_OPTIMIZER_NO_PROMPT_REWRITE=1` | 只关闭 prompt 改写;footer 统计和 cache-key fallback 仍启用。 |
|
|
95
|
+
| `PI_CACHE_OPTIMIZER_VIRTUAL_REWRITE=1` | 显式允许原生 virtual prompt 改写,但仅当 routing registry 暴露的候选链不包含 Responses/Codex 时生效。路由未知或信息不完整时仍保持原 prompt。 |
|
|
95
96
|
| `PI_CACHE_OPTIMIZER_NO_SKILL_COMPRESSION=1` | 保留 Pi 原始 verbose skill XML。 |
|
|
96
97
|
| `PI_CACHE_OPTIMIZER_NO_OPENAI_CACHE_KEY=1` | 关闭 OpenAI-compatible `prompt_cache_key` fallback。推荐使用这个显式 opt-out。 |
|
|
97
98
|
| `PI_CACHE_OPTIMIZER_OPENAI_CACHE_KEY=0` | 通过旧的反向开关关闭同一个 fallback。取值 `0`、`false`、`no`、`off` 时关闭。 |
|
|
@@ -366,12 +367,14 @@ Pi 0.99 允许扩展通过 `pi.registerVirtualModel()` 注册虚拟模型。选
|
|
|
366
367
|
- 请求 hook 从 provider payload 中读取实际派发的模型 id,并在已配置凭证的物理模型中匹配。`prompt_cache_key` fallback、`prompt_cache_retention` 安全规则、Anthropic TTL 修复以及按模型关闭 `prompt_cache_key` 的规则都按该物理模型生效。如果多个已配置凭证的 provider 共用同一个 id 且处理方式不同,扩展不会猜测,而是跳过依赖模型身份的请求修改。
|
|
367
368
|
- Footer 统计以及 `/cache-optimizer doctor`、`compat`、`stats`、`reset`、`fix` 使用当前会话分支上最近一次应答的物理模型,与 Pi 自身显示的路由模型和 context 上限一致。doctor 与 compat 会同时标出虚拟选择和该物理模型。
|
|
368
369
|
- 在 Pi 路由第一个请求之前,footer 保持为空,诊断会提示先发送一个 prompt。
|
|
369
|
-
-
|
|
370
|
+
- 虚拟选择默认不做 prompt 改写:Pi 在构建 system prompt 之后才决定物理模型,重排后的 prompt 不应被送到有安全过滤的 Codex 路由。只有设置 `PI_CACHE_OPTIMIZER_VIRTUAL_REWRITE=1` 且 routing registry 暴露完整候选链、所有候选都是已知的非 Responses / 非 Codex transport 时,才允许改写;路由未知或信息不完整时仍保持原 prompt。
|
|
370
371
|
- Session-affinity header 桥接同样跳过,因为 Pi 在 payload 生成之前就构造请求 header。Pi 仍会发送物理模型自身配置的 affinity header。
|
|
371
372
|
|
|
372
373
|
## Router / Virtual-channel 扩展作者指南
|
|
373
374
|
|
|
374
|
-
如果你的 Pi 扩展提供虚拟 routing provider(例如 `router/auto`、`router/smart`,或会转发到真实上游的 profile/channel),本扩展可以为真实上游 provider/model 显示缓存统计,而不是把统计记到虚拟外壳上。集成是可选、版本化的,并且**不需要导入本包**。
|
|
375
|
+
如果你的 Pi 扩展提供虚拟 routing provider(例如 [`pi-router`](https://github.com/jiangge/pi-router) 的 `router/auto`、`router/smart`,或会转发到真实上游的 profile/channel),本扩展可以为真实上游 provider/model 显示缓存统计,而不是把统计记到虚拟外壳上。集成是可选、版本化的,并且**不需要导入本包**。
|
|
376
|
+
|
|
377
|
+
对于 [`pi-router`](https://github.com/jiangge/pi-router),请使用实现 `pi.routing.registry.v1` 的较新版本。直接选择 `router/*` 模型时仍使用普通 prompt optimizer;当 Pi 0.99+ 原生 virtual model 通过支持该 registry 的 router 路由时,可选的 `PI_CACHE_OPTIMIZER_VIRTUAL_REWRITE=1` 会先检查 router candidate chain 再决定是否改写。候选包含 OpenAI Responses/Codex API、元数据不完整或路由信息不可用时,会 fail closed。
|
|
375
378
|
|
|
376
379
|
### 最小集成:最终 assistant message metadata
|
|
377
380
|
|
package/index.ts
CHANGED
|
@@ -131,6 +131,7 @@ const NO_OPENAI_CACHE_KEY_ENV = "PI_CACHE_OPTIMIZER_NO_OPENAI_CACHE_KEY";
|
|
|
131
131
|
const OPENAI_PROMPT_CACHE_KEY_MAX_LENGTH = 64;
|
|
132
132
|
const NO_SKILL_COMPRESSION_ENV = "PI_CACHE_OPTIMIZER_NO_SKILL_COMPRESSION";
|
|
133
133
|
const NO_PROMPT_REWRITE_ENV = "PI_CACHE_OPTIMIZER_NO_PROMPT_REWRITE";
|
|
134
|
+
const VIRTUAL_REWRITE_ENV = "PI_CACHE_OPTIMIZER_VIRTUAL_REWRITE";
|
|
134
135
|
const TOOL_ORDER_ENV = "PI_CACHE_OPTIMIZER_TOOL_ORDER";
|
|
135
136
|
const FOOTER_MODE_ENV = "PI_CACHE_OPTIMIZER_FOOTER_MODE";
|
|
136
137
|
type FooterStatsMode = "session" | "total" | "process";
|
|
@@ -1334,6 +1335,43 @@ function resolveActiveRouteSnapshot(
|
|
|
1334
1335
|
}
|
|
1335
1336
|
}
|
|
1336
1337
|
|
|
1338
|
+
function resolveNativeVirtualCandidateModels(
|
|
1339
|
+
model: PiModel | undefined,
|
|
1340
|
+
ctx?: ContextWithOptionalModelRegistry,
|
|
1341
|
+
): PiModel[] | undefined {
|
|
1342
|
+
if (!isNativeVirtualModel(model)) return undefined;
|
|
1343
|
+
const adapter = model ? getRoutingRegistry()?.getRouter(model.provider) : undefined;
|
|
1344
|
+
if (!adapter?.resolveCandidateRoutes) return undefined;
|
|
1345
|
+
|
|
1346
|
+
try {
|
|
1347
|
+
const rawSnapshots = adapter.resolveCandidateRoutes(model.id);
|
|
1348
|
+
if (!Array.isArray(rawSnapshots) || rawSnapshots.length === 0) return undefined;
|
|
1349
|
+
const candidates: PiModel[] = [];
|
|
1350
|
+
for (const rawSnapshot of rawSnapshots) {
|
|
1351
|
+
const snapshot = parseRouteSnapshot(rawSnapshot, model.provider, model.id);
|
|
1352
|
+
if (!snapshot) return undefined;
|
|
1353
|
+
const candidate = findModelInRegistry(ctx?.modelRegistry, snapshot.provider, snapshot.modelId)
|
|
1354
|
+
?? routeSnapshotToPiModel(snapshot, model);
|
|
1355
|
+
if (!isNonEmptyString(candidate.api)) return undefined;
|
|
1356
|
+
candidates.push(candidate);
|
|
1357
|
+
}
|
|
1358
|
+
return candidates;
|
|
1359
|
+
} catch {
|
|
1360
|
+
return undefined;
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
function canRewriteNativeVirtualPrompt(
|
|
1365
|
+
model: PiModel | undefined,
|
|
1366
|
+
ctx?: ContextWithOptionalModelRegistry,
|
|
1367
|
+
): boolean {
|
|
1368
|
+
if (!isNativeVirtualModel(model) || !isEnabledEnv(process.env[VIRTUAL_REWRITE_ENV])) return false;
|
|
1369
|
+
const candidates = resolveNativeVirtualCandidateModels(model, ctx);
|
|
1370
|
+
return !!candidates?.length && candidates.every((candidate) =>
|
|
1371
|
+
candidate.api === "openai-completions" || candidate.api === "anthropic-messages",
|
|
1372
|
+
) && candidates.every((candidate) => !isResponsesPromptRewriteBypassApi(candidate.api));
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1337
1375
|
function routeSnapshotToPiModel(snapshot: PiRouteSnapshot, fallback?: PiModel): PiModel {
|
|
1338
1376
|
const sameIdentity = fallback?.provider === snapshot.provider && fallback?.id === snapshot.modelId;
|
|
1339
1377
|
return {
|
|
@@ -10160,6 +10198,8 @@ export const __internals_for_tests = {
|
|
|
10160
10198
|
normalizeAnthropicCacheControlTtlOrder,
|
|
10161
10199
|
isPiBuiltInLlamaCppModel,
|
|
10162
10200
|
isResponsesPromptRewriteBypassApi,
|
|
10201
|
+
canRewriteNativeVirtualPrompt,
|
|
10202
|
+
VIRTUAL_REWRITE_ENV,
|
|
10163
10203
|
isMistralConversationsApi,
|
|
10164
10204
|
isOpenAIFamilyModel,
|
|
10165
10205
|
isOpenAIFamilyAssistantMessage,
|
|
@@ -11202,7 +11242,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
11202
11242
|
// after this system prompt is built, so the bypass above cannot be decided
|
|
11203
11243
|
// here. A route may reach the safety-filtered Codex backend; keep Pi's
|
|
11204
11244
|
// prompt byte-for-byte instead of reordering it.
|
|
11205
|
-
if (isNativeVirtualModel(_ctx.model)) {
|
|
11245
|
+
if (isNativeVirtualModel(_ctx.model) && !canRewriteNativeVirtualPrompt(_ctx.model, _ctx)) {
|
|
11206
11246
|
return {};
|
|
11207
11247
|
}
|
|
11208
11248
|
|
package/package.json
CHANGED