pi-cache-optimizer 2.8.14 → 2.8.16
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 +14 -0
- package/README.zh-CN.md +14 -0
- package/index.ts +136 -26
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -97,6 +97,20 @@ The interactive `/cache-optimizer` menu includes `Footer mode`, where you can ch
|
|
|
97
97
|
| `PI_CACHE_OPTIMIZER_NO_OPENAI_CACHE_KEY=1` | Disable the OpenAI-compatible `prompt_cache_key` fallback. Preferred explicit opt-out. |
|
|
98
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. |
|
|
99
99
|
|
|
100
|
+
Persistent feature settings are managed under the Pi agent directory by the native command interface. They take precedence over their corresponding environment variables:
|
|
101
|
+
|
|
102
|
+
```text
|
|
103
|
+
/cache-optimizer config prompt-rewrite on|off
|
|
104
|
+
/cache-optimizer config virtual-rewrite on|off
|
|
105
|
+
/cache-optimizer config skill-compression on|off
|
|
106
|
+
/cache-optimizer config openai-cache-key on|off
|
|
107
|
+
/cache-optimizer config tool-order on|off
|
|
108
|
+
/cache-optimizer config footer-mode total|session|process
|
|
109
|
+
/cache-optimizer config reset
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
`config reset` removes persistent feature overrides while preserving the existing footer mode and model-specific prompt-cache-key settings. These commands do not modify shell startup files or `PI_CACHE_RETENTION`; `enable` and `disable` remain current-process runtime switches.
|
|
113
|
+
|
|
100
114
|
## Opt-in deterministic tool ordering
|
|
101
115
|
|
|
102
116
|
`PI_CACHE_OPTIMIZER_TOOL_ORDER=1` enables deterministic ordering for verified tool definitions in Pi's built-in OpenAI Completions, Anthropic, Google, and Bedrock payload shapes. Truthy values are `1`, `true`, `yes`, or `on` (case-insensitive). The feature is off by default, process-local, and suppressed by `/cache-optimizer disable`.
|
package/README.zh-CN.md
CHANGED
|
@@ -97,6 +97,20 @@ Pi 0.79.7 及之后,`pi update` 默认只更新 Pi 本体。若要更新已安
|
|
|
97
97
|
| `PI_CACHE_OPTIMIZER_NO_OPENAI_CACHE_KEY=1` | 关闭 OpenAI-compatible `prompt_cache_key` fallback。推荐使用这个显式 opt-out。 |
|
|
98
98
|
| `PI_CACHE_OPTIMIZER_OPENAI_CACHE_KEY=0` | 通过旧的反向开关关闭同一个 fallback。取值 `0`、`false`、`no`、`off` 时关闭。 |
|
|
99
99
|
|
|
100
|
+
持久化 feature 配置由 Pi agent 目录中的原生命令管理,并且优先于对应环境变量:
|
|
101
|
+
|
|
102
|
+
```text
|
|
103
|
+
/cache-optimizer config prompt-rewrite on|off
|
|
104
|
+
/cache-optimizer config virtual-rewrite on|off
|
|
105
|
+
/cache-optimizer config skill-compression on|off
|
|
106
|
+
/cache-optimizer config openai-cache-key on|off
|
|
107
|
+
/cache-optimizer config tool-order on|off
|
|
108
|
+
/cache-optimizer config footer-mode total|session|process
|
|
109
|
+
/cache-optimizer config reset
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
`config reset` 会移除持久化 feature 覆盖,同时保留现有 footer mode 和按模型配置的 prompt-cache-key 设置。这些命令不会修改 shell 启动文件或 `PI_CACHE_RETENTION`;`enable` 和 `disable` 仍然是当前进程的运行时开关。
|
|
113
|
+
|
|
100
114
|
## Opt-in 确定性工具排序
|
|
101
115
|
|
|
102
116
|
`PI_CACHE_OPTIMIZER_TOOL_ORDER=1` 会对 Pi 内置 OpenAI Completions、Anthropic、Google 与 Bedrock payload 中已验证的工具定义进行确定性排序。Truthy 取值为(不区分大小写)`1`、`true`、`yes` 或 `on`。该能力默认关闭、仅在当前进程生效,并会被 `/cache-optimizer disable` 抑制。
|
package/index.ts
CHANGED
|
@@ -180,6 +180,7 @@ type PersistedCacheOptimizerConfigV1 = {
|
|
|
180
180
|
version: 1;
|
|
181
181
|
footerMode?: FooterStatsMode;
|
|
182
182
|
};
|
|
183
|
+
type PersistedCacheOptimizerFeature = "promptRewrite" | "virtualRewrite" | "skillCompression" | "openAICacheKey" | "toolOrder";
|
|
183
184
|
type PersistedCacheOptimizerConfigV2 = {
|
|
184
185
|
version: 2;
|
|
185
186
|
footerMode?: FooterStatsMode;
|
|
@@ -187,7 +188,13 @@ type PersistedCacheOptimizerConfigV2 = {
|
|
|
187
188
|
omit?: string[];
|
|
188
189
|
};
|
|
189
190
|
};
|
|
190
|
-
type
|
|
191
|
+
type PersistedCacheOptimizerConfigV3 = {
|
|
192
|
+
version: 2 | 3;
|
|
193
|
+
footerMode?: FooterStatsMode;
|
|
194
|
+
promptCacheKey?: { omit?: string[] };
|
|
195
|
+
features?: Partial<Record<PersistedCacheOptimizerFeature, boolean>>;
|
|
196
|
+
};
|
|
197
|
+
type PersistedCacheOptimizerConfig = PersistedCacheOptimizerConfigV1 | PersistedCacheOptimizerConfigV2 | PersistedCacheOptimizerConfigV3;
|
|
191
198
|
type PromptCacheKeyConfigReceipt = {
|
|
192
199
|
version: 2;
|
|
193
200
|
kind: "pi-cache-optimizer-config-receipt";
|
|
@@ -923,7 +930,7 @@ function compressSkillsInSystemPrompt(
|
|
|
923
930
|
prompt: string,
|
|
924
931
|
opts: BuildSystemPromptOptions,
|
|
925
932
|
): string {
|
|
926
|
-
if (
|
|
933
|
+
if (!featureEnabled("skillCompression", NO_SKILL_COMPRESSION_ENV, true)) return prompt;
|
|
927
934
|
if (!opts.skills || opts.skills.length === 0) return prompt;
|
|
928
935
|
|
|
929
936
|
const visible = opts.skills.filter((skill) => !skill.disableModelInvocation);
|
|
@@ -1365,7 +1372,7 @@ function canRewriteNativeVirtualPrompt(
|
|
|
1365
1372
|
model: PiModel | undefined,
|
|
1366
1373
|
ctx?: ContextWithOptionalModelRegistry,
|
|
1367
1374
|
): boolean {
|
|
1368
|
-
if (!isNativeVirtualModel(model) || !
|
|
1375
|
+
if (!isNativeVirtualModel(model) || !featureEnabled("virtualRewrite", VIRTUAL_REWRITE_ENV, false)) return false;
|
|
1369
1376
|
const candidates = resolveNativeVirtualCandidateModels(model, ctx);
|
|
1370
1377
|
return !!candidates?.length && candidates.every((candidate) =>
|
|
1371
1378
|
candidate.api === "openai-completions" || candidate.api === "anthropic-messages",
|
|
@@ -2082,8 +2089,24 @@ function isEnabledEnv(value: string | undefined): boolean {
|
|
|
2082
2089
|
return normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on";
|
|
2083
2090
|
}
|
|
2084
2091
|
|
|
2092
|
+
function featureEnabled(
|
|
2093
|
+
feature: PersistedCacheOptimizerFeature,
|
|
2094
|
+
envName: string,
|
|
2095
|
+
defaultValue: boolean,
|
|
2096
|
+
env: MutableEnv = process.env,
|
|
2097
|
+
config: PersistedCacheOptimizerConfigV3 = persistedCacheOptimizerConfig,
|
|
2098
|
+
): boolean {
|
|
2099
|
+
const configured = config.features?.[feature];
|
|
2100
|
+
if (configured !== undefined) return configured;
|
|
2101
|
+
if (feature === "virtualRewrite") return isEnabledEnv(env[envName]);
|
|
2102
|
+
if (feature === "promptRewrite" || feature === "skillCompression" || feature === "openAICacheKey") {
|
|
2103
|
+
return !isEnabledEnv(env[envName]);
|
|
2104
|
+
}
|
|
2105
|
+
return isEnabledEnv(env[envName]) || defaultValue;
|
|
2106
|
+
}
|
|
2107
|
+
|
|
2085
2108
|
function isToolOrderEnabled(env: MutableEnv = process.env): boolean {
|
|
2086
|
-
return runtimeOptimizerEnabled &&
|
|
2109
|
+
return runtimeOptimizerEnabled && featureEnabled("toolOrder", TOOL_ORDER_ENV, false);
|
|
2087
2110
|
}
|
|
2088
2111
|
|
|
2089
2112
|
function parseFooterStatsMode(value: unknown): FooterStatsMode | undefined {
|
|
@@ -2109,8 +2132,17 @@ const CACHE_OPTIMIZER_COMMANDS = [
|
|
|
2109
2132
|
"fix",
|
|
2110
2133
|
"rollback",
|
|
2111
2134
|
] as const;
|
|
2112
|
-
const CACHE_OPTIMIZER_CONFIG_ARGUMENTS = ["footer-mode"] as const;
|
|
2135
|
+
const CACHE_OPTIMIZER_CONFIG_ARGUMENTS = ["footer-mode", "prompt-rewrite", "virtual-rewrite", "skill-compression", "openai-cache-key", "tool-order", "reset"] as const;
|
|
2136
|
+
const CACHE_OPTIMIZER_FEATURE_COMMANDS = ["prompt-rewrite", "virtual-rewrite", "skill-compression", "openai-cache-key", "tool-order"] as const;
|
|
2137
|
+
const CACHE_OPTIMIZER_FEATURE_VALUES = ["on", "off"] as const;
|
|
2113
2138
|
const CACHE_OPTIMIZER_FOOTER_MODES = ["total", "session", "process"] as const;
|
|
2139
|
+
const FEATURE_COMMAND_MAP: Record<string, PersistedCacheOptimizerFeature> = {
|
|
2140
|
+
"prompt-rewrite": "promptRewrite",
|
|
2141
|
+
"virtual-rewrite": "virtualRewrite",
|
|
2142
|
+
"skill-compression": "skillCompression",
|
|
2143
|
+
"openai-cache-key": "openAICacheKey",
|
|
2144
|
+
"tool-order": "toolOrder",
|
|
2145
|
+
};
|
|
2114
2146
|
const CACHE_OPTIMIZER_STATS_ARGUMENTS = ["all", "contributors"] as const;
|
|
2115
2147
|
const CACHE_OPTIMIZER_FIX_ARGUMENTS = ["prompt-cache-key"] as const;
|
|
2116
2148
|
|
|
@@ -2182,19 +2214,28 @@ function getCacheOptimizerArgumentCompletions(argumentPrefix: string): CommandCo
|
|
|
2182
2214
|
if (parts.length === 3 && parts[1].toLowerCase() === "footer-mode") {
|
|
2183
2215
|
return filterCommandCompletionItems(CACHE_OPTIMIZER_FOOTER_MODES, parts[2], "config footer-mode");
|
|
2184
2216
|
}
|
|
2217
|
+
if (parts.length === 3 && CACHE_OPTIMIZER_FEATURE_COMMANDS.includes(parts[1] as typeof CACHE_OPTIMIZER_FEATURE_COMMANDS[number])) {
|
|
2218
|
+
return filterCommandCompletionItems(CACHE_OPTIMIZER_FEATURE_VALUES, parts[2], `config ${parts[1]}`);
|
|
2219
|
+
}
|
|
2185
2220
|
|
|
2186
2221
|
return null;
|
|
2187
2222
|
}
|
|
2188
2223
|
|
|
2189
2224
|
function parsePersistedCacheOptimizerConfig(value: unknown): PersistedCacheOptimizerConfig | undefined {
|
|
2190
2225
|
const record = asRecord(value);
|
|
2191
|
-
if (!record || (record.version !== 1 && record.version !== 2)) return undefined;
|
|
2192
|
-
const allowedTopLevel = new Set(record.version === 1 ? ["version", "footerMode"] : ["version", "footerMode", "promptCacheKey"]);
|
|
2226
|
+
if (!record || (record.version !== 1 && record.version !== 2 && record.version !== 3)) return undefined;
|
|
2227
|
+
const allowedTopLevel = new Set(record.version === 1 ? ["version", "footerMode"] : record.version === 2 ? ["version", "footerMode", "promptCacheKey"] : ["version", "footerMode", "promptCacheKey", "features"]);
|
|
2193
2228
|
if (Object.keys(record).some((key) => !allowedTopLevel.has(key))) return undefined;
|
|
2194
2229
|
const footerMode = parseFooterStatsMode(record.footerMode);
|
|
2195
2230
|
if (record.footerMode !== undefined && !footerMode) return undefined;
|
|
2196
2231
|
if (record.version === 1) return { version: 1, ...(footerMode ? { footerMode } : {}) };
|
|
2197
2232
|
|
|
2233
|
+
const rawFeatures = record.version === 3 ? record.features : undefined;
|
|
2234
|
+
if (rawFeatures !== undefined && !asRecord(rawFeatures)) return undefined;
|
|
2235
|
+
const featuresRecord = asRecord(rawFeatures);
|
|
2236
|
+
const featureNames = new Set<PersistedCacheOptimizerFeature>(["promptRewrite", "virtualRewrite", "skillCompression", "openAICacheKey", "toolOrder"]);
|
|
2237
|
+
if (featuresRecord && Object.keys(featuresRecord).some((key) => !featureNames.has(key as PersistedCacheOptimizerFeature) || typeof featuresRecord[key] !== "boolean")) return undefined;
|
|
2238
|
+
|
|
2198
2239
|
const rawPromptCacheKey = record.promptCacheKey;
|
|
2199
2240
|
if (rawPromptCacheKey !== undefined && !asRecord(rawPromptCacheKey)) return undefined;
|
|
2200
2241
|
const promptCacheKey = asRecord(rawPromptCacheKey);
|
|
@@ -2204,20 +2245,25 @@ function parsePersistedCacheOptimizerConfig(value: unknown): PersistedCacheOptim
|
|
|
2204
2245
|
const stringOmit = omit as string[] | undefined;
|
|
2205
2246
|
const uniqueOmit = stringOmit ? [...new Set(stringOmit.map((value) => value.trim()))].sort() : undefined;
|
|
2206
2247
|
return {
|
|
2207
|
-
version: 2,
|
|
2248
|
+
version: record.version === 3 ? 3 : 2,
|
|
2208
2249
|
...(footerMode ? { footerMode } : {}),
|
|
2209
2250
|
...(uniqueOmit && uniqueOmit.length > 0 ? { promptCacheKey: { omit: uniqueOmit } } : {}),
|
|
2210
|
-
|
|
2251
|
+
...(featuresRecord ? { features: Object.fromEntries(Object.entries(featuresRecord)) as Partial<Record<PersistedCacheOptimizerFeature, boolean>> } : {}),
|
|
2252
|
+
} as PersistedCacheOptimizerConfigV3;
|
|
2211
2253
|
}
|
|
2212
2254
|
|
|
2213
|
-
function normalizePersistedCacheOptimizerConfig(value: PersistedCacheOptimizerConfig | undefined):
|
|
2255
|
+
function normalizePersistedCacheOptimizerConfig(value: PersistedCacheOptimizerConfig | undefined): PersistedCacheOptimizerConfigV3 {
|
|
2214
2256
|
if (!value) return { version: 2 };
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2257
|
+
const features = value.version === 3 ? value.features : undefined;
|
|
2258
|
+
return {
|
|
2259
|
+
version: features ? 3 : 2,
|
|
2260
|
+
...(value.footerMode ? { footerMode: value.footerMode } : {}),
|
|
2261
|
+
...(value.version !== 1 && value.promptCacheKey ? { promptCacheKey: value.promptCacheKey } : {}),
|
|
2262
|
+
...(features ? { features } : {}),
|
|
2263
|
+
};
|
|
2218
2264
|
}
|
|
2219
2265
|
|
|
2220
|
-
function readPersistedCacheOptimizerConfig(configPath: string = CONFIG_FILE_PATH):
|
|
2266
|
+
function readPersistedCacheOptimizerConfig(configPath: string = CONFIG_FILE_PATH): PersistedCacheOptimizerConfigV3 {
|
|
2221
2267
|
try {
|
|
2222
2268
|
return normalizePersistedCacheOptimizerConfig(parsePersistedCacheOptimizerConfig(JSON.parse(readFileSync(configPath, "utf8"))));
|
|
2223
2269
|
} catch (error) {
|
|
@@ -2231,7 +2277,7 @@ function readPersistedFooterMode(configPath: string = CONFIG_FILE_PATH): FooterS
|
|
|
2231
2277
|
}
|
|
2232
2278
|
|
|
2233
2279
|
async function writePersistedCacheOptimizerConfigUnlocked(
|
|
2234
|
-
config:
|
|
2280
|
+
config: PersistedCacheOptimizerConfig | PersistedCacheOptimizerConfigV3,
|
|
2235
2281
|
configPath: string,
|
|
2236
2282
|
): Promise<void> {
|
|
2237
2283
|
await mkdir(dirname(configPath), { recursive: true });
|
|
@@ -2261,7 +2307,7 @@ async function writePersistedCacheOptimizerConfigUnlocked(
|
|
|
2261
2307
|
}
|
|
2262
2308
|
|
|
2263
2309
|
async function writePersistedCacheOptimizerConfig(
|
|
2264
|
-
config:
|
|
2310
|
+
config: PersistedCacheOptimizerConfig | PersistedCacheOptimizerConfigV3,
|
|
2265
2311
|
configPath: string = CONFIG_FILE_PATH,
|
|
2266
2312
|
): Promise<void> {
|
|
2267
2313
|
await withModelsJsonTransactionLock(() => writePersistedCacheOptimizerConfigUnlocked(config, configPath));
|
|
@@ -2271,14 +2317,14 @@ async function writePersistedFooterModeUnlocked(
|
|
|
2271
2317
|
mode: FooterStatsMode,
|
|
2272
2318
|
configPath: string,
|
|
2273
2319
|
): Promise<void> {
|
|
2274
|
-
let version: 1 | 2 = 1;
|
|
2320
|
+
let version: 1 | 2 | 3 = 1;
|
|
2275
2321
|
let raw: PersistedCacheOptimizerConfig | undefined;
|
|
2276
2322
|
let targetExists = false;
|
|
2277
2323
|
try {
|
|
2278
2324
|
raw = parsePersistedCacheOptimizerConfig(JSON.parse(readFileSync(configPath, "utf8")));
|
|
2279
2325
|
targetExists = true;
|
|
2280
2326
|
if (!raw) throw new Error("invalid footer config schema");
|
|
2281
|
-
version = raw.version === 2 ? 2 : 1;
|
|
2327
|
+
version = raw.version === 3 ? 3 : raw.version === 2 ? 2 : 1;
|
|
2282
2328
|
} catch (error) {
|
|
2283
2329
|
if (getErrorCode(error) !== "ENOENT") throw new Error("invalid footer config schema");
|
|
2284
2330
|
}
|
|
@@ -2301,7 +2347,7 @@ async function writePersistedFooterModeUnlocked(
|
|
|
2301
2347
|
}
|
|
2302
2348
|
return;
|
|
2303
2349
|
}
|
|
2304
|
-
await writePersistedCacheOptimizerConfigUnlocked({ ...current, version:
|
|
2350
|
+
await writePersistedCacheOptimizerConfigUnlocked({ ...current, version: 3, footerMode: mode } as PersistedCacheOptimizerConfigV3, configPath);
|
|
2305
2351
|
}
|
|
2306
2352
|
|
|
2307
2353
|
async function writePersistedFooterMode(
|
|
@@ -2311,6 +2357,17 @@ async function writePersistedFooterMode(
|
|
|
2311
2357
|
await withModelsJsonTransactionLock(() => writePersistedFooterModeUnlocked(mode, configPath));
|
|
2312
2358
|
}
|
|
2313
2359
|
|
|
2360
|
+
async function writePersistedFeature(feature: PersistedCacheOptimizerFeature, enabled: boolean): Promise<void> {
|
|
2361
|
+
const current = readPersistedCacheOptimizerConfig();
|
|
2362
|
+
const next: PersistedCacheOptimizerConfigV3 = {
|
|
2363
|
+
...current,
|
|
2364
|
+
version: 3,
|
|
2365
|
+
features: { ...(current.features ?? {}), [feature]: enabled },
|
|
2366
|
+
};
|
|
2367
|
+
await writePersistedCacheOptimizerConfig(next);
|
|
2368
|
+
setPersistedCacheOptimizerConfig(readPersistedCacheOptimizerConfig());
|
|
2369
|
+
}
|
|
2370
|
+
|
|
2314
2371
|
function configReceiptBackupPath(receipt: PromptCacheKeyConfigReceipt, receiptPath: string = CONFIG_RECEIPT_PATH): string {
|
|
2315
2372
|
return join(dirname(receiptPath), receipt.backupFile);
|
|
2316
2373
|
}
|
|
@@ -2703,7 +2760,7 @@ function isDisabledEnv(value: string | undefined): boolean {
|
|
|
2703
2760
|
|
|
2704
2761
|
function shouldInjectOpenAIPromptCacheKey(): boolean {
|
|
2705
2762
|
if (!runtimeOptimizerEnabled) return false;
|
|
2706
|
-
if (
|
|
2763
|
+
if (!featureEnabled("openAICacheKey", NO_OPENAI_CACHE_KEY_ENV, true)) return false;
|
|
2707
2764
|
if (isDisabledEnv(process.env[OPENAI_CACHE_KEY_ENV])) return false;
|
|
2708
2765
|
return true;
|
|
2709
2766
|
}
|
|
@@ -2725,20 +2782,40 @@ function getOptimizerRuntimeModeLines(): string[] {
|
|
|
2725
2782
|
const state = runtimeOptimizerEnabled ? "enabled" : "disabled";
|
|
2726
2783
|
const lines: string[] = [];
|
|
2727
2784
|
lines.push(`Runtime state: ${state}`);
|
|
2728
|
-
lines.push(`• Prompt rewrite: ${runtimeOptimizerEnabled &&
|
|
2785
|
+
lines.push(`• Prompt rewrite: ${runtimeOptimizerEnabled && featureEnabled("promptRewrite", NO_PROMPT_REWRITE_ENV, true) ? "on" : "off"}`);
|
|
2786
|
+
lines.push(`• Native virtual rewrite: ${featureEnabled("virtualRewrite", VIRTUAL_REWRITE_ENV, false) ? "opt-in" : "off"}`);
|
|
2787
|
+
lines.push(`• Skill compression: ${featureEnabled("skillCompression", NO_SKILL_COMPRESSION_ENV, true) ? "on" : "off"}`);
|
|
2729
2788
|
lines.push(`• Deterministic tool ordering: ${isToolOrderEnabled() ? "on (verified built-in payloads, opt-in)" : "off"}`);
|
|
2730
2789
|
lines.push(`• OpenAI prompt_cache_key fallback: ${shouldInjectOpenAIPromptCacheKey() ? "on" : "off"}`);
|
|
2731
2790
|
lines.push(`• Footer cache stats: on${runtimeOptimizerEnabled ? "" : " (comparison mode)"}`);
|
|
2732
2791
|
lines.push(`• Compat warnings: ${runtimeOptimizerEnabled ? "on" : "off"}`);
|
|
2733
2792
|
lines.push(`• ${PI_CACHE_RETENTION_ENV}: ${process.env[PI_CACHE_RETENTION_ENV] ?? "(unset)"}`);
|
|
2793
|
+
lines.push(`• Persistent feature overrides: ${Object.keys(persistedCacheOptimizerConfig.features ?? {}).length > 0 ? "configured" : "none"}`);
|
|
2734
2794
|
if (!runtimeOptimizerEnabled) {
|
|
2735
2795
|
lines.push("This is a current-process switch. Run /reload or restart Pi to return to startup behavior.");
|
|
2736
|
-
} else if (
|
|
2796
|
+
} else if (!featureEnabled("promptRewrite", NO_PROMPT_REWRITE_ENV, true) || !shouldInjectOpenAIPromptCacheKey()) {
|
|
2737
2797
|
lines.push("Some features are still disabled by environment variables.");
|
|
2738
2798
|
}
|
|
2739
2799
|
return lines;
|
|
2740
2800
|
}
|
|
2741
2801
|
|
|
2802
|
+
function formatPersistentFeatureConfig(): string {
|
|
2803
|
+
const features = persistedCacheOptimizerConfig.features ?? {};
|
|
2804
|
+
const lines = ["Persistent feature configuration:"];
|
|
2805
|
+
const entries: Array<[string, PersistedCacheOptimizerFeature, string, boolean]> = [
|
|
2806
|
+
["Prompt rewrite", "promptRewrite", NO_PROMPT_REWRITE_ENV, true],
|
|
2807
|
+
["Native virtual rewrite", "virtualRewrite", VIRTUAL_REWRITE_ENV, false],
|
|
2808
|
+
["Skill compression", "skillCompression", NO_SKILL_COMPRESSION_ENV, true],
|
|
2809
|
+
["OpenAI cache key", "openAICacheKey", NO_OPENAI_CACHE_KEY_ENV, true],
|
|
2810
|
+
["Tool ordering", "toolOrder", TOOL_ORDER_ENV, false],
|
|
2811
|
+
];
|
|
2812
|
+
for (const [label, feature, envName, defaultValue] of entries) {
|
|
2813
|
+
const source = features[feature] !== undefined ? "config" : process.env[envName] !== undefined ? "env" : "default";
|
|
2814
|
+
lines.push(`• ${label}: ${featureEnabled(feature, envName, defaultValue) ? "on" : "off"} (${source})`);
|
|
2815
|
+
}
|
|
2816
|
+
return lines.join("\n");
|
|
2817
|
+
}
|
|
2818
|
+
|
|
2742
2819
|
function formatOptimizerRuntimeMode(): string {
|
|
2743
2820
|
return getOptimizerRuntimeModeLines().join("\n");
|
|
2744
2821
|
}
|
|
@@ -2820,12 +2897,12 @@ function shouldInjectOpenAIPromptCacheKeyForModel(model: PiModel | undefined): b
|
|
|
2820
2897
|
return isOpenAICompatibleApi(model?.api);
|
|
2821
2898
|
}
|
|
2822
2899
|
|
|
2823
|
-
function isPromptCacheKeyOmittedForModel(model: PiModel | undefined, config:
|
|
2900
|
+
function isPromptCacheKeyOmittedForModel(model: PiModel | undefined, config: PersistedCacheOptimizerConfig | PersistedCacheOptimizerConfigV3 = persistedCacheOptimizerConfig): boolean {
|
|
2824
2901
|
if (!model || !isOpenAICompatibleApi(model.api)) return false;
|
|
2825
|
-
return config.promptCacheKey?.omit?.includes(modelKey(model)) === true;
|
|
2902
|
+
return "promptCacheKey" in config && config.promptCacheKey?.omit?.includes(modelKey(model)) === true;
|
|
2826
2903
|
}
|
|
2827
2904
|
|
|
2828
|
-
function setPersistedCacheOptimizerConfig(config:
|
|
2905
|
+
function setPersistedCacheOptimizerConfig(config: PersistedCacheOptimizerConfig | PersistedCacheOptimizerConfigV3): void {
|
|
2829
2906
|
persistedCacheOptimizerConfig = normalizePersistedCacheOptimizerConfig(config);
|
|
2830
2907
|
persistedFooterStatsMode = persistedCacheOptimizerConfig.footerMode;
|
|
2831
2908
|
}
|
|
@@ -10180,6 +10257,8 @@ export const __internals_for_tests = {
|
|
|
10180
10257
|
SKILL_COMPRESSION_MIN_COUNT,
|
|
10181
10258
|
NO_PROMPT_REWRITE_ENV,
|
|
10182
10259
|
isEnabledEnv,
|
|
10260
|
+
featureEnabled,
|
|
10261
|
+
writePersistedFeature,
|
|
10183
10262
|
// OpenAI-family cache-key helpers
|
|
10184
10263
|
addOpenAIPromptCacheKey,
|
|
10185
10264
|
clampPromptCacheKey,
|
|
@@ -11252,7 +11331,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
11252
11331
|
// prompt mutations below (session-overview churn strip, skill compression,
|
|
11253
11332
|
// and stable-prefix reordering). Footer stats and the OpenAI
|
|
11254
11333
|
// prompt_cache_key fallback remain active.
|
|
11255
|
-
if (
|
|
11334
|
+
if (!featureEnabled("promptRewrite", NO_PROMPT_REWRITE_ENV, true)) return {};
|
|
11256
11335
|
|
|
11257
11336
|
// Step 1: strip per-turn churn from <session-overview>.
|
|
11258
11337
|
// Removing RECENT COMMITS, Working directory status, and
|
|
@@ -11821,10 +11900,39 @@ export default function (pi: ExtensionAPI) {
|
|
|
11821
11900
|
} else if (subcommand === "config") {
|
|
11822
11901
|
const configKey = commandParts[1];
|
|
11823
11902
|
const requestedMode = commandParts[2];
|
|
11903
|
+
const feature = configKey ? FEATURE_COMMAND_MAP[configKey] : undefined;
|
|
11904
|
+
if (feature && (requestedMode === "on" || requestedMode === "off")) {
|
|
11905
|
+
try {
|
|
11906
|
+
await writePersistedFeature(feature, requestedMode === "on");
|
|
11907
|
+
lastStatusText = undefined;
|
|
11908
|
+
await publishStatus(cmdCtx, model);
|
|
11909
|
+
cmdCtx.ui.notify(`✅ ${configKey} set to ${requestedMode}. Persistent config overrides its environment variable.`, "info");
|
|
11910
|
+
} catch (error) {
|
|
11911
|
+
cmdCtx.ui.notify(`❌ Could not update ${configKey}: ${error instanceof Error ? error.message : String(error)}`, "error");
|
|
11912
|
+
}
|
|
11913
|
+
return;
|
|
11914
|
+
}
|
|
11915
|
+
if (configKey === "reset") {
|
|
11916
|
+
try {
|
|
11917
|
+
await writePersistedCacheOptimizerConfig({ version: 2, footerMode: persistedFooterStatsMode, promptCacheKey: persistedCacheOptimizerConfig.promptCacheKey });
|
|
11918
|
+
setPersistedCacheOptimizerConfig(readPersistedCacheOptimizerConfig());
|
|
11919
|
+
cmdCtx.ui.notify("✅ Feature configuration reset. Environment variables now apply again.", "info");
|
|
11920
|
+
} catch (error) {
|
|
11921
|
+
cmdCtx.ui.notify(`❌ Could not reset feature configuration: ${error instanceof Error ? error.message : String(error)}`, "error");
|
|
11922
|
+
}
|
|
11923
|
+
return;
|
|
11924
|
+
}
|
|
11925
|
+
if (!configKey) {
|
|
11926
|
+
cmdCtx.ui.notify(formatPersistentFeatureConfig() + `\n• Footer mode: ${resolveFooterStatsMode(persistedFooterStatsMode).mode}` + "\n\n" +
|
|
11927
|
+
"Usage: /cache-optimizer config <feature> on|off | footer-mode total|session|process | reset", "info");
|
|
11928
|
+
return;
|
|
11929
|
+
}
|
|
11824
11930
|
if (configKey !== "footer-mode" || !requestedMode || !["session", "total", "process"].includes(requestedMode)) {
|
|
11825
11931
|
const resolved = resolveFooterStatsMode(persistedFooterStatsMode);
|
|
11826
11932
|
cmdCtx.ui.notify(
|
|
11827
11933
|
`Usage: /cache-optimizer config footer-mode total|session|process\n` +
|
|
11934
|
+
` /cache-optimizer config prompt-rewrite|virtual-rewrite|skill-compression|openai-cache-key|tool-order on|off\n` +
|
|
11935
|
+
` /cache-optimizer config reset\n` +
|
|
11828
11936
|
`Current footer mode: ${resolved.mode} (${resolved.source})`,
|
|
11829
11937
|
"info",
|
|
11830
11938
|
);
|
|
@@ -12641,7 +12749,9 @@ export default function (pi: ExtensionAPI) {
|
|
|
12641
12749
|
diagnosis.push(" stats all — Show detailed totals for every model across all local sessions");
|
|
12642
12750
|
diagnosis.push(" stats contributors — Show per-session contributors for the active model");
|
|
12643
12751
|
diagnosis.push(" compat — Show compat suggestion with edit location");
|
|
12752
|
+
diagnosis.push(" config prompt-rewrite|virtual-rewrite|skill-compression|openai-cache-key|tool-order on|off — Persist feature settings");
|
|
12644
12753
|
diagnosis.push(" config footer-mode total|session|process — Persist the footer stats mode");
|
|
12754
|
+
diagnosis.push(" config reset — Remove persistent feature overrides");
|
|
12645
12755
|
diagnosis.push(" fix — Auto-fix compat issues (writes models.json or extension config, requires UI)");
|
|
12646
12756
|
diagnosis.push(" fix prompt-cache-key — Explicitly omit prompt_cache_key for the active model");
|
|
12647
12757
|
diagnosis.push(" rollback — Undo the latest confirmed fix (requires UI confirmation)");
|
package/package.json
CHANGED