pi-cache-optimizer 2.8.5 → 2.8.6
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/index.ts +90 -18
- package/package.json +1 -1
package/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
2
|
import { chmod, copyFile, lstat, mkdir, readFile, readdir, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
|
|
3
|
-
import { constants as fsConstants, readFileSync, watch } from "node:fs";
|
|
3
|
+
import { constants as fsConstants, readFileSync, statSync, watch } from "node:fs";
|
|
4
4
|
import { homedir } from "node:os";
|
|
5
5
|
import { dirname, join } from "node:path";
|
|
6
6
|
import {
|
|
@@ -1057,9 +1057,10 @@ function isRoutedFallbackModel(model: PiModel | undefined): boolean {
|
|
|
1057
1057
|
function applyConfiguredTransportToModel(model: PiModel, config: unknown): PiModel {
|
|
1058
1058
|
const providers = asRecord(asRecord(config)?.providers);
|
|
1059
1059
|
const provider = asRecord(providers?.[model.provider]);
|
|
1060
|
-
const customModel =
|
|
1061
|
-
|
|
1062
|
-
|
|
1060
|
+
const customModel = findLastExactModelDefinition(
|
|
1061
|
+
Array.isArray(provider?.models) ? provider.models : undefined,
|
|
1062
|
+
model.id,
|
|
1063
|
+
);
|
|
1063
1064
|
const configuredApi = customModel?.api ?? provider?.api;
|
|
1064
1065
|
const configuredBaseUrl = customModel?.baseUrl ?? provider?.baseUrl;
|
|
1065
1066
|
const api = isNonEmptyString(model.api)
|
|
@@ -1172,6 +1173,21 @@ const NESTED_COMPAT_KEYS = [
|
|
|
1172
1173
|
"chatTemplateArgs",
|
|
1173
1174
|
] as const;
|
|
1174
1175
|
|
|
1176
|
+
function findLastExactModelDefinition(
|
|
1177
|
+
models: unknown[] | undefined,
|
|
1178
|
+
modelId: string,
|
|
1179
|
+
): UnknownRecord | undefined {
|
|
1180
|
+
if (!models) return undefined;
|
|
1181
|
+
// Pi's provider composer processes definitions in array order. If a malformed
|
|
1182
|
+
// or hand-edited config repeats an id, the last definition replaces earlier
|
|
1183
|
+
// definitions, so effective resolution must use the same deterministic rule.
|
|
1184
|
+
for (let index = models.length - 1; index >= 0; index--) {
|
|
1185
|
+
const candidate = asRecord(models[index]);
|
|
1186
|
+
if (candidate?.id === modelId) return candidate;
|
|
1187
|
+
}
|
|
1188
|
+
return undefined;
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1175
1191
|
function mergeCacheCompat(...sources: Array<UnknownRecord | undefined>): CacheCompat {
|
|
1176
1192
|
const merged: CacheCompat = {};
|
|
1177
1193
|
for (const source of sources) {
|
|
@@ -1196,9 +1212,10 @@ function getEffectiveCompatSources(model: PiModel, config: unknown): Array<{ sou
|
|
|
1196
1212
|
const providers = asRecord(root?.providers);
|
|
1197
1213
|
const provider = asRecord(providers?.[model.provider]);
|
|
1198
1214
|
const providerCompat = asRecord(provider?.compat);
|
|
1199
|
-
const customModel =
|
|
1200
|
-
? provider.models
|
|
1201
|
-
|
|
1215
|
+
const customModel = findLastExactModelDefinition(
|
|
1216
|
+
Array.isArray(provider?.models) ? provider.models : undefined,
|
|
1217
|
+
model.id,
|
|
1218
|
+
);
|
|
1202
1219
|
const customModelCompat = asRecord(asRecord(customModel)?.compat);
|
|
1203
1220
|
const runtimeCompat = asRecord(model.compat);
|
|
1204
1221
|
const modelOverride = asRecord(asRecord(provider?.modelOverrides)?.[model.id]);
|
|
@@ -1357,6 +1374,10 @@ function isValidCompatRecord(value: unknown): boolean {
|
|
|
1357
1374
|
);
|
|
1358
1375
|
}
|
|
1359
1376
|
|
|
1377
|
+
// Credential-blind fail-closed subset of Pi's models.json validation. This
|
|
1378
|
+
// intentionally covers only fields consumed by compat diagnostics, transport
|
|
1379
|
+
// recovery, and exact route fallback; it is not a replacement for Pi's full
|
|
1380
|
+
// schema and must stay conservative when the file is malformed.
|
|
1360
1381
|
function isValidModelsConfigForEffectiveCompat(value: unknown): boolean {
|
|
1361
1382
|
const root = asRecord(value);
|
|
1362
1383
|
const providers = asRecord(root?.providers);
|
|
@@ -1376,13 +1397,42 @@ function isValidModelsConfigForEffectiveCompat(value: unknown): boolean {
|
|
|
1376
1397
|
return true;
|
|
1377
1398
|
}
|
|
1378
1399
|
|
|
1379
|
-
|
|
1400
|
+
type ModelsConfigCache = {
|
|
1401
|
+
signature: string;
|
|
1402
|
+
value: unknown | undefined;
|
|
1403
|
+
};
|
|
1404
|
+
|
|
1405
|
+
let modelsConfigCache: ModelsConfigCache | undefined;
|
|
1406
|
+
|
|
1407
|
+
function invalidateModelsConfigCache(): void {
|
|
1408
|
+
modelsConfigCache = undefined;
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
function getModelsConfigSignature(): string {
|
|
1380
1412
|
try {
|
|
1381
|
-
const
|
|
1382
|
-
return
|
|
1413
|
+
const info = statSync(MODELS_JSON_PATH);
|
|
1414
|
+
return `${info.dev}:${info.ino}:${info.size}:${info.mtimeMs}:${info.ctimeMs}`;
|
|
1383
1415
|
} catch {
|
|
1384
|
-
return
|
|
1416
|
+
return "missing";
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
function readEffectiveCompatConfig(): unknown | undefined {
|
|
1421
|
+
const signature = getModelsConfigSignature();
|
|
1422
|
+
if (modelsConfigCache?.signature === signature) return modelsConfigCache.value;
|
|
1423
|
+
|
|
1424
|
+
let value: unknown | undefined;
|
|
1425
|
+
if (signature !== "missing") {
|
|
1426
|
+
try {
|
|
1427
|
+
const parsed = parseJsonc(readFileSync(MODELS_JSON_PATH, "utf8"));
|
|
1428
|
+
value = isValidModelsConfigForEffectiveCompat(parsed) ? parsed : undefined;
|
|
1429
|
+
} catch {
|
|
1430
|
+
value = undefined;
|
|
1431
|
+
}
|
|
1385
1432
|
}
|
|
1433
|
+
|
|
1434
|
+
modelsConfigCache = { signature, value };
|
|
1435
|
+
return value;
|
|
1386
1436
|
}
|
|
1387
1437
|
|
|
1388
1438
|
function getCompat(model: PiModel | undefined): CacheCompat {
|
|
@@ -6083,12 +6133,13 @@ function resolveExplicitCompatValue(
|
|
|
6083
6133
|
return { source: "modelOverride", value: overrideCompat[compatKey] };
|
|
6084
6134
|
}
|
|
6085
6135
|
|
|
6086
|
-
|
|
6087
|
-
|
|
6088
|
-
|
|
6089
|
-
|
|
6090
|
-
|
|
6091
|
-
|
|
6136
|
+
const model = findLastExactModelDefinition(
|
|
6137
|
+
Array.isArray(provider.models) ? provider.models : undefined,
|
|
6138
|
+
modelId,
|
|
6139
|
+
);
|
|
6140
|
+
const modelCompat = asRecord(model?.compat);
|
|
6141
|
+
if (modelCompat && Object.prototype.hasOwnProperty.call(modelCompat, compatKey)) {
|
|
6142
|
+
return { source: "model", value: modelCompat[compatKey] };
|
|
6092
6143
|
}
|
|
6093
6144
|
|
|
6094
6145
|
const providerCompat = asRecord(provider.compat);
|
|
@@ -6332,9 +6383,14 @@ function locateModelInJsonc(
|
|
|
6332
6383
|
allModelIds.push(elementId);
|
|
6333
6384
|
}
|
|
6334
6385
|
|
|
6335
|
-
if (elementId === modelId
|
|
6386
|
+
if (elementId === modelId) {
|
|
6387
|
+
// Match Pi's provider composer: later duplicate definitions replace
|
|
6388
|
+
// earlier ones. The effective/fix target is therefore the last exact id.
|
|
6336
6389
|
modelBrace = elementBrace;
|
|
6337
6390
|
modelEndBrace = elementEnd;
|
|
6391
|
+
compatKeyStartClean = -1;
|
|
6392
|
+
compatBrace = -1;
|
|
6393
|
+
compatEndBrace = -1;
|
|
6338
6394
|
|
|
6339
6395
|
const compatKey = findJsonObjectKey(clean, modelBrace, "compat");
|
|
6340
6396
|
if (compatKey && compatKey.keyStart < modelEndBrace) {
|
|
@@ -7606,6 +7662,7 @@ export const __internals_for_tests = {
|
|
|
7606
7662
|
mergeCacheCompat,
|
|
7607
7663
|
resolveEffectiveCompatFromConfig,
|
|
7608
7664
|
getEffectiveCompatValueSource,
|
|
7665
|
+
findLastExactModelDefinition,
|
|
7609
7666
|
isValidModelsConfigForEffectiveCompat,
|
|
7610
7667
|
addEffectiveSessionAffinityHeaders,
|
|
7611
7668
|
getCompat,
|
|
@@ -9081,6 +9138,20 @@ export default function (pi: ExtensionAPI) {
|
|
|
9081
9138
|
return;
|
|
9082
9139
|
}
|
|
9083
9140
|
|
|
9141
|
+
const duplicateTargetDefinitions = location.allModelIds.filter(
|
|
9142
|
+
(configuredModelId) => configuredModelId === suggestion.modelId,
|
|
9143
|
+
).length;
|
|
9144
|
+
if (duplicateTargetDefinitions > 1) {
|
|
9145
|
+
cmdCtx.ui.notify(
|
|
9146
|
+
`❌ ${getModelsJsonDisplayPath()} contains ${duplicateTargetDefinitions} custom model definitions ` +
|
|
9147
|
+
`with the exact id "${suggestion.modelId}" under providers["${suggestion.providerLabel}"].\n` +
|
|
9148
|
+
`Pi uses the last definition, but /cache-optimizer fix refuses an ambiguous duplicate-id edit. ` +
|
|
9149
|
+
`Remove or consolidate the duplicates, then run the command again.`,
|
|
9150
|
+
"error",
|
|
9151
|
+
);
|
|
9152
|
+
return;
|
|
9153
|
+
}
|
|
9154
|
+
|
|
9084
9155
|
// Compose the modified text — observed runtime failures are always
|
|
9085
9156
|
// model-scoped; ordinary compat fixes use the safety-based placement.
|
|
9086
9157
|
const decision = chooseFixPlacement(
|
|
@@ -9179,6 +9250,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
9179
9250
|
return;
|
|
9180
9251
|
}
|
|
9181
9252
|
|
|
9253
|
+
invalidateModelsConfigCache();
|
|
9182
9254
|
cmdCtx.ui.notify(
|
|
9183
9255
|
`✅ Fix applied to ${getModelsJsonDisplayPath()}.\n` +
|
|
9184
9256
|
`Backup saved to: ${backupPath}\n` +
|
package/package.json
CHANGED