@ai-matrx/agents 0.59.268 → 0.59.269
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/CHANGELOG.md +6 -1
- package/dist/context/react/index.cjs +12 -1
- package/dist/context/react/index.js +12 -1
- package/dist/models/index.cjs +364 -238
- package/dist/models/index.d.cts +140 -14
- package/dist/models/index.d.ts +140 -14
- package/dist/models/index.js +364 -238
- package/dist/models/react/index.d.cts +9 -1
- package/dist/models/react/index.d.ts +9 -1
- package/package.json +2 -2
- package/scripts/check-model-catalog-reads.mjs +11 -6
package/dist/models/index.cjs
CHANGED
|
@@ -23,6 +23,10 @@ __export(models_exports, {
|
|
|
23
23
|
CHAT_DEFAULT_MODEL_KNOB: () => CHAT_DEFAULT_MODEL_KNOB,
|
|
24
24
|
CONTENT_TYPES: () => CONTENT_TYPES,
|
|
25
25
|
DEFAULT_CAPABILITIES: () => DEFAULT_CAPABILITIES,
|
|
26
|
+
DEVICE_FILE_USABLE_STATES: () => DEVICE_FILE_USABLE_STATES,
|
|
27
|
+
DEVICE_OWN_FILE_USABLE_STATES: () => DEVICE_OWN_FILE_USABLE_STATES,
|
|
28
|
+
DEVICE_SERVED_VIA: () => DEVICE_SERVED_VIA,
|
|
29
|
+
DeviceModelUnavailableError: () => DeviceModelUnavailableError,
|
|
26
30
|
EMPTY_MODEL_RECORDS: () => EMPTY_MODEL_RECORDS,
|
|
27
31
|
EXCLUDED_REVIEW_STATES: () => EXCLUDED_REVIEW_STATES,
|
|
28
32
|
FEATURE_BUCKETS: () => FEATURE_BUCKETS,
|
|
@@ -43,6 +47,7 @@ __export(models_exports, {
|
|
|
43
47
|
TOP_TIER_LOCKED_TITLE: () => TOP_TIER_LOCKED_TITLE,
|
|
44
48
|
acceptsTextInstructions: () => acceptsTextInstructions,
|
|
45
49
|
announceModelCatalogChanged: () => announceModelCatalogChanged,
|
|
50
|
+
availableOnDevices: () => availableOnDevices,
|
|
46
51
|
blendedPrice: () => blendedPrice,
|
|
47
52
|
buildModelClassIndex: () => buildModelClassIndex,
|
|
48
53
|
buildSuccessionIndex: () => buildSuccessionIndex,
|
|
@@ -112,6 +117,7 @@ __export(models_exports, {
|
|
|
112
117
|
quantFromName: () => quantFromName,
|
|
113
118
|
rankVariants: () => rankVariants,
|
|
114
119
|
readCuratedRows: () => readCuratedRows,
|
|
120
|
+
readDeviceModelFiles: () => readDeviceModelFiles,
|
|
115
121
|
readGgufHeader: () => readGgufHeader,
|
|
116
122
|
readModelCatalog: () => readModelCatalog,
|
|
117
123
|
readModelIdentities: () => readModelIdentities,
|
|
@@ -119,8 +125,10 @@ __export(models_exports, {
|
|
|
119
125
|
reconcileModelFavoriteIds: () => reconcileModelFavoriteIds,
|
|
120
126
|
reportModelDiagnostic: () => reportModelDiagnostic,
|
|
121
127
|
requireCanonicalCapabilities: () => requireCanonicalCapabilities,
|
|
128
|
+
requiredArtifactIds: () => requiredArtifactIds,
|
|
122
129
|
requiredArtifacts: () => requiredArtifacts,
|
|
123
130
|
resetSuccessionLogForTests: () => resetSuccessionLogForTests,
|
|
131
|
+
resolveDeviceModel: () => resolveDeviceModel,
|
|
124
132
|
resolveLiveModelId: () => resolveLiveModelId,
|
|
125
133
|
resolveModelMapKnob: () => resolveModelMapKnob,
|
|
126
134
|
resolveNewAgentModelId: () => resolveNewAgentModelId,
|
|
@@ -159,6 +167,7 @@ __export(models_exports, {
|
|
|
159
167
|
splitSetProblems: () => splitSetProblems,
|
|
160
168
|
takesInput: () => takesInput,
|
|
161
169
|
toAuditRecord: () => toAuditRecord,
|
|
170
|
+
toDeviceModelFile: () => toDeviceModelFile,
|
|
162
171
|
validateModelSet: () => validateModelSet,
|
|
163
172
|
variantVerdict: () => variantVerdict,
|
|
164
173
|
withModelClass: () => withModelClass
|
|
@@ -414,13 +423,13 @@ function setModelDiagnosticsSink(sink) {
|
|
|
414
423
|
}
|
|
415
424
|
function reportModelDiagnostic(dedupeKey, entry) {
|
|
416
425
|
try {
|
|
417
|
-
const
|
|
418
|
-
if (
|
|
419
|
-
|
|
426
|
+
const s4 = state();
|
|
427
|
+
if (s4.reported.has(dedupeKey)) return;
|
|
428
|
+
s4.reported.add(dedupeKey);
|
|
420
429
|
console.warn(`[parseCapabilities] ${entry.message}`);
|
|
421
|
-
if (
|
|
422
|
-
else if (!
|
|
423
|
-
|
|
430
|
+
if (s4.sink) s4.sink(entry);
|
|
431
|
+
else if (!s4.announced) {
|
|
432
|
+
s4.announced = true;
|
|
424
433
|
console.error(
|
|
425
434
|
"[@ai-matrx/agents/models] No diagnostics sink is bound \u2014 capability-vocabulary drift reaches the console only. Call setModelDiagnosticsSink(...) with your error store."
|
|
426
435
|
);
|
|
@@ -1093,13 +1102,13 @@ function createModelRecords(config) {
|
|
|
1093
1102
|
if (known.fetchScope === "active" || known.fetchScope === "all") {
|
|
1094
1103
|
jobs.push(
|
|
1095
1104
|
readOptions().then(
|
|
1096
|
-
(rows3) => update((
|
|
1097
|
-
const entities = { ...
|
|
1105
|
+
(rows3) => update((s4) => {
|
|
1106
|
+
const entities = { ...s4.entities };
|
|
1098
1107
|
for (const row of rows3) {
|
|
1099
1108
|
const existing = entities[row.id];
|
|
1100
1109
|
entities[row.id] = { ...emptyRecord(), ...existing, ...row, _fetchType: existing?._fetchType === "full" ? "full" : "options" };
|
|
1101
1110
|
}
|
|
1102
|
-
return withIdLists({ ...
|
|
1111
|
+
return withIdLists({ ...s4, entities, lastFetched: Date.now(), error: null });
|
|
1103
1112
|
}),
|
|
1104
1113
|
(err) => fail("model-records-refresh-options-failed", messageOf(err))
|
|
1105
1114
|
)
|
|
@@ -1109,9 +1118,9 @@ function createModelRecords(config) {
|
|
|
1109
1118
|
if (record._fetchType !== "full") continue;
|
|
1110
1119
|
jobs.push(
|
|
1111
1120
|
readFullModel(id).then(
|
|
1112
|
-
(fresh) => update((
|
|
1113
|
-
const existing =
|
|
1114
|
-
return withIdLists({ ...
|
|
1121
|
+
(fresh) => update((s4) => {
|
|
1122
|
+
const existing = s4.entities[fresh.id];
|
|
1123
|
+
return withIdLists({ ...s4, entities: { ...s4.entities, [fresh.id]: { ...emptyRecord(), ...existing, ...fresh, maker: fresh.maker ?? existing?.maker ?? null, _fetchType: "full" } } });
|
|
1115
1124
|
}),
|
|
1116
1125
|
(err) => fail("model-records-refresh-model-failed", `${id}: ${messageOf(err)}`, { modelId: id })
|
|
1117
1126
|
)
|
|
@@ -1122,7 +1131,7 @@ function createModelRecords(config) {
|
|
|
1122
1131
|
Promise.resolve(ai().from("model_definition").select("id, name, common_name, is_deprecated").eq(catalogKeyColumn(id), id).maybeSingle()).then(
|
|
1123
1132
|
({ data, error }) => {
|
|
1124
1133
|
if (error) throw error;
|
|
1125
|
-
if (data) update((
|
|
1134
|
+
if (data) update((s4) => ({ ...s4, identityById: { ...s4.identityById, [id]: data } }));
|
|
1126
1135
|
}
|
|
1127
1136
|
).catch((err) => fail("model-records-refresh-identity-failed", `${id}: ${messageOf(err)}`, { modelId: id }))
|
|
1128
1137
|
);
|
|
@@ -1130,7 +1139,7 @@ function createModelRecords(config) {
|
|
|
1130
1139
|
if (known.modelClassStatus === "succeeded") {
|
|
1131
1140
|
jobs.push(
|
|
1132
1141
|
readOfferings().then(
|
|
1133
|
-
(rows3) => update((
|
|
1142
|
+
(rows3) => update((s4) => ({ ...s4, modelClassIndex: buildModelClassIndex(rows3) })),
|
|
1134
1143
|
(err) => fail("model-records-refresh-classes-failed", messageOf(err))
|
|
1135
1144
|
)
|
|
1136
1145
|
);
|
|
@@ -1138,11 +1147,11 @@ function createModelRecords(config) {
|
|
|
1138
1147
|
for (const id of classesReadFor) {
|
|
1139
1148
|
jobs.push(
|
|
1140
1149
|
readOfferings(id).then(
|
|
1141
|
-
(rows3) => update((
|
|
1142
|
-
if (
|
|
1150
|
+
(rows3) => update((s4) => {
|
|
1151
|
+
if (s4.modelClassStatus === "succeeded") return s4;
|
|
1143
1152
|
const slice = buildModelClassIndex(rows3);
|
|
1144
|
-
const base =
|
|
1145
|
-
return { ...
|
|
1153
|
+
const base = s4.modelClassIndex ?? { classesByModelId: {}, classOfOffering: {} };
|
|
1154
|
+
return { ...s4, modelClassIndex: { classesByModelId: { ...base.classesByModelId, ...slice.classesByModelId }, classOfOffering: { ...base.classOfOffering, ...slice.classOfOffering } } };
|
|
1146
1155
|
}),
|
|
1147
1156
|
(err) => fail("model-records-refresh-classes-failed", `${id}: ${messageOf(err)}`, { modelId: id })
|
|
1148
1157
|
)
|
|
@@ -1156,7 +1165,7 @@ function createModelRecords(config) {
|
|
|
1156
1165
|
({ data, error }) => {
|
|
1157
1166
|
if (error) throw error;
|
|
1158
1167
|
const next = data && typeof data === "object" && !Array.isArray(data) ? data : null;
|
|
1159
|
-
update((
|
|
1168
|
+
update((s4) => ({ ...s4, classConfigByOffering: { ...s4.classConfigByOffering, [key]: { modelId: cfg.modelId, controls: next?.controls ?? null, constraints: next?.constraints ?? null } } }));
|
|
1160
1169
|
}
|
|
1161
1170
|
).catch((err) => fail("model-records-refresh-class-config-failed", `${key}: ${messageOf(err)}`))
|
|
1162
1171
|
);
|
|
@@ -1202,29 +1211,29 @@ function createModelRecords(config) {
|
|
|
1202
1211
|
loadOptions() {
|
|
1203
1212
|
if (state2.fetchScope === "active" || state2.fetchScope === "all") return Promise.resolve();
|
|
1204
1213
|
return once("options", async () => {
|
|
1205
|
-
update((
|
|
1214
|
+
update((s4) => ({ ...s4, isLoading: true, error: null }));
|
|
1206
1215
|
try {
|
|
1207
1216
|
const rows3 = await readOptions();
|
|
1208
|
-
update((
|
|
1209
|
-
const entities = { ...
|
|
1217
|
+
update((s4) => {
|
|
1218
|
+
const entities = { ...s4.entities };
|
|
1210
1219
|
for (const row of rows3) {
|
|
1211
1220
|
const existing = entities[row.id];
|
|
1212
1221
|
if (existing?._fetchType === "full") continue;
|
|
1213
1222
|
entities[row.id] = { ...emptyRecord(), ...existing, ...row, _fetchType: "options" };
|
|
1214
1223
|
}
|
|
1215
1224
|
return withIdLists({
|
|
1216
|
-
...
|
|
1225
|
+
...s4,
|
|
1217
1226
|
entities,
|
|
1218
1227
|
isLoading: false,
|
|
1219
1228
|
error: null,
|
|
1220
|
-
fetchScope:
|
|
1229
|
+
fetchScope: s4.fetchScope !== "all" && s4.fetchScope !== "deprecated" ? "active" : s4.fetchScope,
|
|
1221
1230
|
lastFetched: Date.now()
|
|
1222
1231
|
});
|
|
1223
1232
|
});
|
|
1224
1233
|
} catch (err) {
|
|
1225
1234
|
const message = messageOf(err);
|
|
1226
1235
|
errorSink({ code: "model-records-options-load-failed", message });
|
|
1227
|
-
update((
|
|
1236
|
+
update((s4) => ({ ...s4, isLoading: false, error: message }));
|
|
1228
1237
|
}
|
|
1229
1238
|
});
|
|
1230
1239
|
},
|
|
@@ -1234,23 +1243,23 @@ function createModelRecords(config) {
|
|
|
1234
1243
|
return inFlight.get(`model:${modelId}`) ?? Promise.resolve();
|
|
1235
1244
|
}
|
|
1236
1245
|
return once(`model:${modelId}`, async () => {
|
|
1237
|
-
update((
|
|
1238
|
-
const detailErrorById = { ...
|
|
1246
|
+
update((s4) => {
|
|
1247
|
+
const detailErrorById = { ...s4.detailErrorById };
|
|
1239
1248
|
delete detailErrorById[modelId];
|
|
1240
|
-
return { ...
|
|
1249
|
+
return { ...s4, detailStatusById: { ...s4.detailStatusById, [modelId]: "loading" }, detailErrorById };
|
|
1241
1250
|
});
|
|
1242
1251
|
try {
|
|
1243
1252
|
const record = await readFullModel(modelId);
|
|
1244
|
-
update((
|
|
1245
|
-
const existing =
|
|
1246
|
-
const detailErrorById = { ...
|
|
1253
|
+
update((s4) => {
|
|
1254
|
+
const existing = s4.entities[record.id];
|
|
1255
|
+
const detailErrorById = { ...s4.detailErrorById };
|
|
1247
1256
|
delete detailErrorById[modelId];
|
|
1248
1257
|
return withIdLists({
|
|
1249
|
-
...
|
|
1250
|
-
detailStatusById: { ...
|
|
1258
|
+
...s4,
|
|
1259
|
+
detailStatusById: { ...s4.detailStatusById, [modelId]: "succeeded" },
|
|
1251
1260
|
detailErrorById,
|
|
1252
1261
|
entities: {
|
|
1253
|
-
...
|
|
1262
|
+
...s4.entities,
|
|
1254
1263
|
[record.id]: { ...emptyRecord(), ...existing, ...record, maker: record.maker ?? existing?.maker ?? null, _fetchType: "full" }
|
|
1255
1264
|
}
|
|
1256
1265
|
});
|
|
@@ -1258,21 +1267,21 @@ function createModelRecords(config) {
|
|
|
1258
1267
|
} catch (err) {
|
|
1259
1268
|
const message = `Model configuration ${modelId}: ${messageOf(err)}`;
|
|
1260
1269
|
errorSink({ code: "model-records-model-load-failed", message, context: { modelId } });
|
|
1261
|
-
update((
|
|
1262
|
-
...
|
|
1263
|
-
detailStatusById: { ...
|
|
1264
|
-
detailErrorById: { ...
|
|
1270
|
+
update((s4) => ({
|
|
1271
|
+
...s4,
|
|
1272
|
+
detailStatusById: { ...s4.detailStatusById, [modelId]: "failed" },
|
|
1273
|
+
detailErrorById: { ...s4.detailErrorById, [modelId]: message }
|
|
1265
1274
|
}));
|
|
1266
1275
|
}
|
|
1267
1276
|
});
|
|
1268
1277
|
},
|
|
1269
1278
|
retryModel(modelId) {
|
|
1270
|
-
update((
|
|
1271
|
-
const detailStatusById = { ...
|
|
1272
|
-
const detailErrorById = { ...
|
|
1279
|
+
update((s4) => {
|
|
1280
|
+
const detailStatusById = { ...s4.detailStatusById };
|
|
1281
|
+
const detailErrorById = { ...s4.detailErrorById };
|
|
1273
1282
|
delete detailStatusById[modelId];
|
|
1274
1283
|
delete detailErrorById[modelId];
|
|
1275
|
-
return { ...
|
|
1284
|
+
return { ...s4, detailStatusById, detailErrorById };
|
|
1276
1285
|
});
|
|
1277
1286
|
},
|
|
1278
1287
|
loadClassConfig(modelId, offeringId) {
|
|
@@ -1280,37 +1289,37 @@ function createModelRecords(config) {
|
|
|
1280
1289
|
const status = state2.classConfigStatusByOffering[key];
|
|
1281
1290
|
if (status === "loading" || status === "succeeded") return inFlight.get(`class:${key}`) ?? Promise.resolve();
|
|
1282
1291
|
return once(`class:${key}`, async () => {
|
|
1283
|
-
update((
|
|
1292
|
+
update((s4) => ({ ...s4, classConfigStatusByOffering: { ...s4.classConfigStatusByOffering, [key]: "loading" } }));
|
|
1284
1293
|
try {
|
|
1285
1294
|
const { data, error } = await ai().rpc("resolve_model_config", { p_model_id: modelId, p_offering_id: offeringId });
|
|
1286
1295
|
if (error) throw error;
|
|
1287
1296
|
const cfg = data && typeof data === "object" && !Array.isArray(data) ? data : null;
|
|
1288
|
-
update((
|
|
1289
|
-
...
|
|
1290
|
-
classConfigStatusByOffering: { ...
|
|
1297
|
+
update((s4) => ({
|
|
1298
|
+
...s4,
|
|
1299
|
+
classConfigStatusByOffering: { ...s4.classConfigStatusByOffering, [key]: "succeeded" },
|
|
1291
1300
|
classConfigByOffering: {
|
|
1292
|
-
...
|
|
1301
|
+
...s4.classConfigByOffering,
|
|
1293
1302
|
[key]: { modelId, controls: cfg?.controls ?? null, constraints: cfg?.constraints ?? null }
|
|
1294
1303
|
}
|
|
1295
1304
|
}));
|
|
1296
1305
|
} catch (err) {
|
|
1297
1306
|
errorSink({ code: "model-records-class-config-failed", message: `Model class configuration ${modelId} / ${offeringId}: ${messageOf(err)}` });
|
|
1298
|
-
update((
|
|
1307
|
+
update((s4) => ({ ...s4, classConfigStatusByOffering: { ...s4.classConfigStatusByOffering, [key]: "failed" } }));
|
|
1299
1308
|
}
|
|
1300
1309
|
});
|
|
1301
1310
|
},
|
|
1302
1311
|
loadClasses() {
|
|
1303
1312
|
if (state2.modelClassStatus === "loading" || state2.modelClassStatus === "succeeded") return inFlight.get("classes") ?? Promise.resolve();
|
|
1304
1313
|
return once("classes", async () => {
|
|
1305
|
-
update((
|
|
1314
|
+
update((s4) => ({ ...s4, modelClassStatus: "loading" }));
|
|
1306
1315
|
try {
|
|
1307
1316
|
const { data, error } = await ai().from("model_offering").select("model_id, offering_id, served_via, served_via_endpoint_id, priority");
|
|
1308
1317
|
if (error) throw error;
|
|
1309
1318
|
const index = buildModelClassIndex(data ?? []);
|
|
1310
|
-
update((
|
|
1319
|
+
update((s4) => ({ ...s4, modelClassStatus: "succeeded", modelClassIndex: index }));
|
|
1311
1320
|
} catch (err) {
|
|
1312
1321
|
errorSink({ code: "model-records-classes-failed", message: `Model classes: ${messageOf(err)}` });
|
|
1313
|
-
update((
|
|
1322
|
+
update((s4) => ({ ...s4, modelClassStatus: "failed" }));
|
|
1314
1323
|
}
|
|
1315
1324
|
});
|
|
1316
1325
|
},
|
|
@@ -1325,11 +1334,11 @@ function createModelRecords(config) {
|
|
|
1325
1334
|
if (error) throw error;
|
|
1326
1335
|
const slice = buildModelClassIndex(data ?? []);
|
|
1327
1336
|
classesReadFor.add(modelId);
|
|
1328
|
-
update((
|
|
1329
|
-
if (
|
|
1330
|
-
const base =
|
|
1337
|
+
update((s4) => {
|
|
1338
|
+
if (s4.modelClassStatus === "succeeded") return s4;
|
|
1339
|
+
const base = s4.modelClassIndex ?? { classesByModelId: {}, classOfOffering: {} };
|
|
1331
1340
|
return {
|
|
1332
|
-
...
|
|
1341
|
+
...s4,
|
|
1333
1342
|
modelClassIndex: {
|
|
1334
1343
|
classesByModelId: { ...base.classesByModelId, ...slice.classesByModelId },
|
|
1335
1344
|
classOfOffering: { ...base.classOfOffering, ...slice.classOfOffering }
|
|
@@ -1347,20 +1356,20 @@ function createModelRecords(config) {
|
|
|
1347
1356
|
return inFlight.get(`identity:${modelId}`) ?? Promise.resolve();
|
|
1348
1357
|
}
|
|
1349
1358
|
return once(`identity:${modelId}`, async () => {
|
|
1350
|
-
update((
|
|
1359
|
+
update((s4) => ({ ...s4, identityStatusById: { ...s4.identityStatusById, [modelId]: "loading" } }));
|
|
1351
1360
|
try {
|
|
1352
1361
|
const { data, error } = await ai().from("model_definition").select("id, name, common_name, is_deprecated").eq(catalogKeyColumn(modelId), modelId).maybeSingle();
|
|
1353
1362
|
if (error) throw error;
|
|
1354
1363
|
if (!data) throw new Error(`AI model ${modelId} is not available (ai.model_definition has no such row)`);
|
|
1355
1364
|
const row = data;
|
|
1356
|
-
update((
|
|
1357
|
-
...
|
|
1358
|
-
identityById: { ...
|
|
1359
|
-
identityStatusById: { ...
|
|
1365
|
+
update((s4) => ({
|
|
1366
|
+
...s4,
|
|
1367
|
+
identityById: { ...s4.identityById, [row.id]: row, [modelId]: row },
|
|
1368
|
+
identityStatusById: { ...s4.identityStatusById, [row.id]: "succeeded", [modelId]: "succeeded" }
|
|
1360
1369
|
}));
|
|
1361
1370
|
} catch (err) {
|
|
1362
1371
|
errorSink({ code: "model-records-identity-failed", message: messageOf(err), context: { modelId } });
|
|
1363
|
-
update((
|
|
1372
|
+
update((s4) => ({ ...s4, identityStatusById: { ...s4.identityStatusById, [modelId]: "failed" } }));
|
|
1364
1373
|
}
|
|
1365
1374
|
});
|
|
1366
1375
|
},
|
|
@@ -1379,26 +1388,26 @@ function createModelRecords(config) {
|
|
|
1379
1388
|
}
|
|
1380
1389
|
if (wanted.length > 0) {
|
|
1381
1390
|
const marked = Object.fromEntries(wanted.map((id) => [id, "loading"]));
|
|
1382
|
-
update((
|
|
1391
|
+
update((s4) => ({ ...s4, identityStatusById: { ...s4.identityStatusById, ...marked } }));
|
|
1383
1392
|
const run = (async () => {
|
|
1384
1393
|
try {
|
|
1385
1394
|
const { data, error } = await ai().from("model_definition").select("id, name, common_name, is_deprecated").in("id", wanted);
|
|
1386
1395
|
if (error) throw error;
|
|
1387
1396
|
const rows3 = Array.isArray(data) ? data : [];
|
|
1388
1397
|
const got = new Set(rows3.map((r) => r.id));
|
|
1389
|
-
update((
|
|
1390
|
-
...
|
|
1391
|
-
identityById: { ...
|
|
1398
|
+
update((s4) => ({
|
|
1399
|
+
...s4,
|
|
1400
|
+
identityById: { ...s4.identityById, ...Object.fromEntries(rows3.map((r) => [r.id, r])) },
|
|
1392
1401
|
identityStatusById: {
|
|
1393
|
-
...
|
|
1402
|
+
...s4.identityStatusById,
|
|
1394
1403
|
...Object.fromEntries(wanted.map((id) => [id, got.has(id) ? "succeeded" : "failed"]))
|
|
1395
1404
|
}
|
|
1396
1405
|
}));
|
|
1397
1406
|
} catch (err) {
|
|
1398
1407
|
errorSink({ code: "model-records-identity-failed", message: messageOf(err), context: { modelIds: wanted } });
|
|
1399
|
-
update((
|
|
1400
|
-
...
|
|
1401
|
-
identityStatusById: { ...
|
|
1408
|
+
update((s4) => ({
|
|
1409
|
+
...s4,
|
|
1410
|
+
identityStatusById: { ...s4.identityStatusById, ...Object.fromEntries(wanted.map((id) => [id, "failed"])) }
|
|
1402
1411
|
}));
|
|
1403
1412
|
}
|
|
1404
1413
|
})();
|
|
@@ -1416,11 +1425,11 @@ function createModelRecords(config) {
|
|
|
1416
1425
|
if (!classesReadFor.has(modelId) && state2.modelClassStatus !== "succeeded") {
|
|
1417
1426
|
const slice = buildModelClassIndex(offerings.filter((o) => o.model_id === modelId));
|
|
1418
1427
|
classesReadFor.add(modelId);
|
|
1419
|
-
update((
|
|
1420
|
-
if (
|
|
1421
|
-
const base =
|
|
1428
|
+
update((s4) => {
|
|
1429
|
+
if (s4.modelClassStatus === "succeeded") return s4;
|
|
1430
|
+
const base = s4.modelClassIndex ?? { classesByModelId: {}, classOfOffering: {} };
|
|
1422
1431
|
return {
|
|
1423
|
-
...
|
|
1432
|
+
...s4,
|
|
1424
1433
|
modelClassIndex: {
|
|
1425
1434
|
classesByModelId: { ...base.classesByModelId, ...slice.classesByModelId },
|
|
1426
1435
|
classOfOffering: { ...base.classOfOffering, ...slice.classOfOffering }
|
|
@@ -1439,16 +1448,16 @@ function createModelRecords(config) {
|
|
|
1439
1448
|
controls: row.controls ?? null,
|
|
1440
1449
|
capabilities: requireCanonicalCapabilities(row.capabilities, { modelId: row.id, modelName: row.name })
|
|
1441
1450
|
});
|
|
1442
|
-
update((
|
|
1443
|
-
const existing =
|
|
1444
|
-
const detailErrorById = { ...
|
|
1451
|
+
update((s4) => {
|
|
1452
|
+
const existing = s4.entities[record.id];
|
|
1453
|
+
const detailErrorById = { ...s4.detailErrorById };
|
|
1445
1454
|
delete detailErrorById[modelId];
|
|
1446
1455
|
return withIdLists({
|
|
1447
|
-
...
|
|
1448
|
-
detailStatusById: { ...
|
|
1456
|
+
...s4,
|
|
1457
|
+
detailStatusById: { ...s4.detailStatusById, [modelId]: "succeeded" },
|
|
1449
1458
|
detailErrorById,
|
|
1450
1459
|
entities: {
|
|
1451
|
-
...
|
|
1460
|
+
...s4.entities,
|
|
1452
1461
|
[record.id]: { ...emptyRecord(), ...existing, ...record, maker: record.maker ?? existing?.maker ?? null, _fetchType: "full" }
|
|
1453
1462
|
}
|
|
1454
1463
|
});
|
|
@@ -1458,14 +1467,14 @@ function createModelRecords(config) {
|
|
|
1458
1467
|
}
|
|
1459
1468
|
},
|
|
1460
1469
|
hydrate({ models, fetchType, fetchScope, lastFetched }) {
|
|
1461
|
-
update((
|
|
1462
|
-
const entities = { ...
|
|
1470
|
+
update((s4) => {
|
|
1471
|
+
const entities = { ...s4.entities };
|
|
1463
1472
|
for (const raw of models) {
|
|
1464
1473
|
const existing = entities[raw.id];
|
|
1465
1474
|
if (existing?._fetchType === "full" && fetchType === "options") continue;
|
|
1466
1475
|
entities[raw.id] = { ...emptyRecord(), ...normalizeModel({ ...raw, controls: raw.controls ?? null }), _fetchType: fetchType };
|
|
1467
1476
|
}
|
|
1468
|
-
return withIdLists({ ...
|
|
1477
|
+
return withIdLists({ ...s4, entities, fetchScope, lastFetched, isLoading: false, error: null });
|
|
1469
1478
|
});
|
|
1470
1479
|
}
|
|
1471
1480
|
};
|
|
@@ -1485,28 +1494,28 @@ function memo(fn) {
|
|
|
1485
1494
|
var UNSET = /* @__PURE__ */ Symbol("unset");
|
|
1486
1495
|
var activeKey = null;
|
|
1487
1496
|
var activeOut = [];
|
|
1488
|
-
function selectActiveModels(
|
|
1489
|
-
if (!activeKey || activeKey[0] !==
|
|
1490
|
-
activeKey = [
|
|
1491
|
-
activeOut =
|
|
1497
|
+
function selectActiveModels(s4) {
|
|
1498
|
+
if (!activeKey || activeKey[0] !== s4.entities || activeKey[1] !== s4.activeIds) {
|
|
1499
|
+
activeKey = [s4.entities, s4.activeIds];
|
|
1500
|
+
activeOut = s4.activeIds.map((id) => s4.entities[id]).filter((m) => !!m);
|
|
1492
1501
|
}
|
|
1493
1502
|
return activeOut;
|
|
1494
1503
|
}
|
|
1495
1504
|
var deprecatedKey = null;
|
|
1496
1505
|
var deprecatedOut = [];
|
|
1497
|
-
function selectDeprecatedModels(
|
|
1498
|
-
if (!deprecatedKey || deprecatedKey[0] !==
|
|
1499
|
-
deprecatedKey = [
|
|
1500
|
-
deprecatedOut =
|
|
1506
|
+
function selectDeprecatedModels(s4) {
|
|
1507
|
+
if (!deprecatedKey || deprecatedKey[0] !== s4.entities || deprecatedKey[1] !== s4.deprecatedIds) {
|
|
1508
|
+
deprecatedKey = [s4.entities, s4.deprecatedIds];
|
|
1509
|
+
deprecatedOut = s4.deprecatedIds.map((id) => s4.entities[id]).filter((m) => !!m);
|
|
1501
1510
|
}
|
|
1502
1511
|
return deprecatedOut;
|
|
1503
1512
|
}
|
|
1504
1513
|
var allOf = memo((entities) => Object.values(entities));
|
|
1505
|
-
var selectAllModels = (
|
|
1514
|
+
var selectAllModels = (s4) => allOf(s4.entities);
|
|
1506
1515
|
var optionsOf = memo(
|
|
1507
1516
|
(models) => models.map((m) => ({ value: m.id, label: modelDisplayLabel(m) || m.id, maker: m.maker, costRating: m.cost_rating, speedRating: m.speed_rating }))
|
|
1508
1517
|
);
|
|
1509
|
-
var selectModelOptions = (
|
|
1518
|
+
var selectModelOptions = (s4) => optionsOf(selectActiveModels(s4));
|
|
1510
1519
|
var allOptionsOf = memo(
|
|
1511
1520
|
(entities) => Object.values(entities).map((m) => ({
|
|
1512
1521
|
value: m.id,
|
|
@@ -1517,30 +1526,30 @@ var allOptionsOf = memo(
|
|
|
1517
1526
|
successorId: m.successor_id ?? null
|
|
1518
1527
|
}))
|
|
1519
1528
|
);
|
|
1520
|
-
var selectAllModelOptions = (
|
|
1521
|
-
var selectModelById = (
|
|
1522
|
-
function selectModelLabelById(
|
|
1529
|
+
var selectAllModelOptions = (s4) => allOptionsOf(s4.entities);
|
|
1530
|
+
var selectModelById = (s4, modelId) => modelId ? s4.entities[modelId] : void 0;
|
|
1531
|
+
function selectModelLabelById(s4, modelId) {
|
|
1523
1532
|
if (!modelId) return void 0;
|
|
1524
|
-
const m =
|
|
1525
|
-
const identity =
|
|
1533
|
+
const m = s4.entities[modelId];
|
|
1534
|
+
const identity = s4.identityById[modelId];
|
|
1526
1535
|
return modelDisplayLabel(m) || modelDisplayLabel(identity);
|
|
1527
1536
|
}
|
|
1528
|
-
var selectModelNameById = (
|
|
1529
|
-
var selectModelClassName = (
|
|
1530
|
-
function selectModelLabelWithClass(
|
|
1531
|
-
const label = selectModelLabelById(
|
|
1532
|
-
return label ? withModelClass(label, selectModelClassName(
|
|
1533
|
-
}
|
|
1534
|
-
var selectModelControls = (
|
|
1535
|
-
var selectModelFetchType = (
|
|
1536
|
-
var selectModelFullyLoaded = (
|
|
1537
|
-
var selectModelDetailError = (
|
|
1538
|
-
var selectModelClassConfig = (
|
|
1539
|
-
var selectActiveModelsReady = (
|
|
1540
|
-
var selectDeprecatedModelsReady = (
|
|
1541
|
-
var selectAllModelsReady = (
|
|
1542
|
-
var selectModelIdentityById = (
|
|
1543
|
-
var selectModelIdentityLookupStatus = (
|
|
1537
|
+
var selectModelNameById = (s4, modelId) => modelId ? s4.entities[modelId]?.name : void 0;
|
|
1538
|
+
var selectModelClassName = (s4, modelId, offeringId) => modelClassName(s4.modelClassIndex, modelId, offeringId);
|
|
1539
|
+
function selectModelLabelWithClass(s4, modelId, offeringId) {
|
|
1540
|
+
const label = selectModelLabelById(s4, modelId);
|
|
1541
|
+
return label ? withModelClass(label, selectModelClassName(s4, modelId, offeringId)) : void 0;
|
|
1542
|
+
}
|
|
1543
|
+
var selectModelControls = (s4, modelId) => s4.entities[modelId]?.controls;
|
|
1544
|
+
var selectModelFetchType = (s4, modelId) => s4.entities[modelId]?._fetchType;
|
|
1545
|
+
var selectModelFullyLoaded = (s4, modelId) => !!modelId && s4.entities[modelId]?._fetchType === "full";
|
|
1546
|
+
var selectModelDetailError = (s4, modelId) => modelId && s4.detailErrorById[modelId] || null;
|
|
1547
|
+
var selectModelClassConfig = (s4, modelId, offeringId) => modelId && offeringId ? s4.classConfigByOffering[classConfigKey(modelId, offeringId)] : void 0;
|
|
1548
|
+
var selectActiveModelsReady = (s4) => (s4.fetchScope === "active" || s4.fetchScope === "all") && s4.activeIds.length > 0;
|
|
1549
|
+
var selectDeprecatedModelsReady = (s4) => (s4.fetchScope === "deprecated" || s4.fetchScope === "all") && s4.deprecatedIds.length > 0;
|
|
1550
|
+
var selectAllModelsReady = (s4) => s4.fetchScope === "all";
|
|
1551
|
+
var selectModelIdentityById = (s4, modelId) => s4.identityById[modelId];
|
|
1552
|
+
var selectModelIdentityLookupStatus = (s4, modelId) => s4.identityStatusById[modelId] ?? "idle";
|
|
1544
1553
|
async function readModelIdentities(client, modelIds) {
|
|
1545
1554
|
const ids = [...new Set(modelIds.filter(Boolean))];
|
|
1546
1555
|
if (ids.length === 0) return [];
|
|
@@ -1840,9 +1849,9 @@ function createModelCatalog(config) {
|
|
|
1840
1849
|
};
|
|
1841
1850
|
},
|
|
1842
1851
|
load(variant) {
|
|
1843
|
-
const
|
|
1844
|
-
if (
|
|
1845
|
-
if (
|
|
1852
|
+
const s4 = state2[variant];
|
|
1853
|
+
if (s4.status === "idle" || s4.status === "error") return run(variant);
|
|
1854
|
+
if (s4.status === "ready" && s4.loadedAt !== null && Date.now() - s4.loadedAt > staleAfterMs) return run(variant);
|
|
1846
1855
|
return inFlight[variant] ?? Promise.resolve();
|
|
1847
1856
|
},
|
|
1848
1857
|
reload: (variant) => run(variant)
|
|
@@ -2030,9 +2039,9 @@ function placement(v, runtimes, device) {
|
|
|
2030
2039
|
}
|
|
2031
2040
|
return "not_compatible";
|
|
2032
2041
|
}
|
|
2033
|
-
function formatMemoryBytes(
|
|
2034
|
-
const g =
|
|
2035
|
-
if (g < 1) return `${Math.max(1, Math.round(
|
|
2042
|
+
function formatMemoryBytes(n3) {
|
|
2043
|
+
const g = n3 / 2 ** 30;
|
|
2044
|
+
if (g < 1) return `${Math.max(1, Math.round(n3 / 2 ** 20))} MB`;
|
|
2036
2045
|
return `${g < 10 ? Math.round(g * 10) / 10 : Math.round(g)} GB`;
|
|
2037
2046
|
}
|
|
2038
2047
|
function describe(c, decided, runnerUp, device) {
|
|
@@ -2359,41 +2368,41 @@ var Cursor = class {
|
|
|
2359
2368
|
this.read = read;
|
|
2360
2369
|
this.size = size;
|
|
2361
2370
|
}
|
|
2362
|
-
async need(
|
|
2363
|
-
if (this.pos +
|
|
2364
|
-
if (this.pos +
|
|
2365
|
-
if (this.pos >= this.base && this.pos +
|
|
2366
|
-
const len = Math.min(Math.max(
|
|
2371
|
+
async need(n3) {
|
|
2372
|
+
if (this.pos + n3 > this.size) throw new GgufError("the file ends inside its header");
|
|
2373
|
+
if (this.pos + n3 > MAX_HEADER) throw new GgufError("its header is larger than any real model's");
|
|
2374
|
+
if (this.pos >= this.base && this.pos + n3 <= this.base + this.buf.length) return;
|
|
2375
|
+
const len = Math.min(Math.max(n3, CHUNK), this.size - this.pos);
|
|
2367
2376
|
this.buf = await this.read(this.pos, len);
|
|
2368
2377
|
this.base = this.pos;
|
|
2369
|
-
if (this.buf.length <
|
|
2378
|
+
if (this.buf.length < n3) throw new GgufError("the file ends inside its header");
|
|
2370
2379
|
}
|
|
2371
|
-
async view(
|
|
2372
|
-
await this.need(
|
|
2373
|
-
const v = new DataView(this.buf.buffer, this.buf.byteOffset + (this.pos - this.base),
|
|
2374
|
-
this.pos +=
|
|
2380
|
+
async view(n3) {
|
|
2381
|
+
await this.need(n3);
|
|
2382
|
+
const v = new DataView(this.buf.buffer, this.buf.byteOffset + (this.pos - this.base), n3);
|
|
2383
|
+
this.pos += n3;
|
|
2375
2384
|
return v;
|
|
2376
2385
|
}
|
|
2377
2386
|
async u32() {
|
|
2378
2387
|
return (await this.view(4)).getUint32(0, true);
|
|
2379
2388
|
}
|
|
2380
2389
|
async u64() {
|
|
2381
|
-
const
|
|
2382
|
-
if (
|
|
2383
|
-
return Number(
|
|
2390
|
+
const n3 = (await this.view(8)).getBigUint64(0, true);
|
|
2391
|
+
if (n3 > BigInt(Number.MAX_SAFE_INTEGER)) throw new GgufError("a size in its header is out of range");
|
|
2392
|
+
return Number(n3);
|
|
2384
2393
|
}
|
|
2385
2394
|
async str() {
|
|
2386
2395
|
const len = await this.u64();
|
|
2387
2396
|
if (len > MAX_STRING) throw new GgufError("a text value in its header is out of range");
|
|
2388
2397
|
await this.need(len);
|
|
2389
2398
|
const at = this.pos - this.base;
|
|
2390
|
-
const
|
|
2399
|
+
const s4 = new TextDecoder().decode(this.buf.subarray(at, at + len));
|
|
2391
2400
|
this.pos += len;
|
|
2392
|
-
return
|
|
2401
|
+
return s4;
|
|
2393
2402
|
}
|
|
2394
|
-
async skip(
|
|
2395
|
-
if (this.pos +
|
|
2396
|
-
this.pos +=
|
|
2403
|
+
async skip(n3) {
|
|
2404
|
+
if (this.pos + n3 > this.size) throw new GgufError("the file ends inside its header");
|
|
2405
|
+
this.pos += n3;
|
|
2397
2406
|
}
|
|
2398
2407
|
async scalar(type) {
|
|
2399
2408
|
switch (type) {
|
|
@@ -2445,11 +2454,11 @@ async function readGgufHeader(read, size) {
|
|
|
2445
2454
|
const type = await c.u32();
|
|
2446
2455
|
if (type === 9) {
|
|
2447
2456
|
const elem = await c.u32();
|
|
2448
|
-
const
|
|
2449
|
-
if (
|
|
2450
|
-
arrays[key] =
|
|
2451
|
-
if (elem === 8) for (let j = 0; j <
|
|
2452
|
-
else if (SCALAR_BYTES[elem] !== void 0) await c.skip(
|
|
2457
|
+
const n3 = await c.u64();
|
|
2458
|
+
if (n3 > 64 * MAX_COUNT) throw new GgufError("an array in its header is out of range");
|
|
2459
|
+
arrays[key] = n3;
|
|
2460
|
+
if (elem === 8) for (let j = 0; j < n3; j++) await c.str();
|
|
2461
|
+
else if (SCALAR_BYTES[elem] !== void 0) await c.skip(n3 * SCALAR_BYTES[elem]);
|
|
2453
2462
|
else throw new GgufError(`its header has an array of unknown type ${elem}`);
|
|
2454
2463
|
} else kv[key] = await c.scalar(type);
|
|
2455
2464
|
}
|
|
@@ -2479,20 +2488,20 @@ async function readGgufHeader(read, size) {
|
|
|
2479
2488
|
return { version, kv, array_lengths: arrays, tensors, data_offset: dataOffset, data_end: end };
|
|
2480
2489
|
}
|
|
2481
2490
|
function ggufFacts(h) {
|
|
2482
|
-
const
|
|
2483
|
-
const
|
|
2484
|
-
const arch =
|
|
2485
|
-
const ft =
|
|
2491
|
+
const s4 = (k) => typeof h.kv[k] === "string" ? h.kv[k] : null;
|
|
2492
|
+
const n3 = (k) => typeof h.kv[k] === "number" ? h.kv[k] : null;
|
|
2493
|
+
const arch = s4("general.architecture");
|
|
2494
|
+
const ft = n3("general.file_type");
|
|
2486
2495
|
const params = h.tensors.reduce((t, x) => t + x.dims.reduce((a, b) => a * b, 1), 0);
|
|
2487
2496
|
return {
|
|
2488
2497
|
architecture: arch,
|
|
2489
|
-
name:
|
|
2498
|
+
name: s4("general.name"),
|
|
2490
2499
|
quant: ft !== null ? FILE_TYPE_QUANT[ft] ?? `FTYPE_${ft}` : null,
|
|
2491
|
-
context_length: arch ?
|
|
2500
|
+
context_length: arch ? n3(`${arch}.context_length`) : null,
|
|
2492
2501
|
parameter_count: params > 0 ? params : null,
|
|
2493
|
-
split_count:
|
|
2494
|
-
split_index:
|
|
2495
|
-
type:
|
|
2502
|
+
split_count: n3("split.count") ?? 1,
|
|
2503
|
+
split_index: n3("split.no") ?? 0,
|
|
2504
|
+
type: s4("general.type"),
|
|
2496
2505
|
has_tokenizer: typeof h.kv["tokenizer.ggml.model"] === "string"
|
|
2497
2506
|
};
|
|
2498
2507
|
}
|
|
@@ -2533,16 +2542,16 @@ var isHelperGguf = (name) => HELPER_RE.test(name);
|
|
|
2533
2542
|
var isProjectorName = (name) => name.toLowerCase().includes("mmproj");
|
|
2534
2543
|
var quantFromName = (name) => QUANT_RE.exec(name.split("/").pop() ?? name)?.[1]?.toUpperCase() ?? null;
|
|
2535
2544
|
function splitSetProblems(names) {
|
|
2536
|
-
const shards = names.map(shardName).filter((
|
|
2545
|
+
const shards = names.map(shardName).filter((s4) => s4 !== null);
|
|
2537
2546
|
if (!shards.length) return [];
|
|
2538
|
-
const counts = [...new Set(shards.map((
|
|
2547
|
+
const counts = [...new Set(shards.map((s4) => s4.count))];
|
|
2539
2548
|
if (counts.length !== 1) return [`its parts disagree on how many parts there are (${counts.sort((a, b) => a - b).join(", ")})`];
|
|
2540
|
-
const
|
|
2541
|
-
const have = shards.map((
|
|
2542
|
-
const missing = Array.from({ length:
|
|
2549
|
+
const n3 = counts[0];
|
|
2550
|
+
const have = shards.map((s4) => s4.index);
|
|
2551
|
+
const missing = Array.from({ length: n3 }, (_, i) => i + 1).filter((i) => !have.includes(i));
|
|
2543
2552
|
const dupes = [...new Set(have.filter((i, k) => have.indexOf(i) !== k))].sort((a, b) => a - b);
|
|
2544
2553
|
const out = [];
|
|
2545
|
-
if (missing.length) out.push(`part${missing.length === 1 ? "" : "s"} ${missing.map((i) => `${i} of ${
|
|
2554
|
+
if (missing.length) out.push(`part${missing.length === 1 ? "" : "s"} ${missing.map((i) => `${i} of ${n3}`).join(", ")} ${missing.length === 1 ? "is" : "are"} missing`);
|
|
2546
2555
|
if (dupes.length) out.push(`part${dupes.length === 1 ? "" : "s"} ${dupes.join(", ")} appear${dupes.length === 1 ? "s" : ""} twice`);
|
|
2547
2556
|
return out;
|
|
2548
2557
|
}
|
|
@@ -2579,8 +2588,8 @@ async function validateModelSet(primary, siblings, env) {
|
|
|
2579
2588
|
let parts = [primary];
|
|
2580
2589
|
if (shard) {
|
|
2581
2590
|
if (shard.index !== 1) return { ok: false, reason: `This is part ${shard.index} of ${shard.count} of a split model; add its first part, ${shardFileName(shard.stem, 1, shard.count)}.` };
|
|
2582
|
-
const same = [primary, ...siblings.filter((
|
|
2583
|
-
const problems = splitSetProblems(same.map((
|
|
2591
|
+
const same = [primary, ...siblings.filter((s4) => s4 !== primary && shardName(s4.name)?.stem === shard.stem)];
|
|
2592
|
+
const problems = splitSetProblems(same.map((s4) => s4.name));
|
|
2584
2593
|
if (problems.length) return { ok: false, reason: `It is a model in ${shard.count} parts and ${problems.join("; ")} (every part has to be in the same folder).` };
|
|
2585
2594
|
parts = same.sort((a, b) => (shardName(a.name)?.index ?? 0) - (shardName(b.name)?.index ?? 0));
|
|
2586
2595
|
}
|
|
@@ -2613,7 +2622,7 @@ async function validateModelSet(primary, siblings, env) {
|
|
|
2613
2622
|
if (end !== null && p.size < end) return { ok: false, reason: `${parts.length > 1 ? `Part ${i + 1} of ${parts.length} is incomplete` : "The file is incomplete"}: it is ${formatMemoryBytes(p.size)} and its header says ${formatMemoryBytes(end)} (a download that stopped early?).` };
|
|
2614
2623
|
}
|
|
2615
2624
|
const quant = f.quant ?? quantFromName(primary.name) ?? "unknown";
|
|
2616
|
-
const projectorFiles = siblings.filter((
|
|
2625
|
+
const projectorFiles = siblings.filter((s4) => s4 !== primary && extOf(s4.name) === ".gguf" && isProjectorName(s4.name));
|
|
2617
2626
|
const pickedName = pickProjector(quant === "unknown" ? null : quant, projectorFiles.map((p) => p.name));
|
|
2618
2627
|
let projector = null;
|
|
2619
2628
|
const picked = projectorFiles.find((p) => p.name === pickedName);
|
|
@@ -2735,6 +2744,77 @@ function curatedList(models, { offeredOnly }) {
|
|
|
2735
2744
|
|
|
2736
2745
|
// models/catalog-reader.ts
|
|
2737
2746
|
var import_sha256 = require("@ai-matrx/kit/sha256");
|
|
2747
|
+
|
|
2748
|
+
// models/device-models.ts
|
|
2749
|
+
var DEVICE_SERVED_VIA = "device";
|
|
2750
|
+
var DEVICE_FILE_USABLE_STATES = Object.freeze(["present"]);
|
|
2751
|
+
var DEVICE_OWN_FILE_USABLE_STATES = Object.freeze(["present", "unmatched"]);
|
|
2752
|
+
var s2 = (v) => typeof v === "string" ? v : "";
|
|
2753
|
+
var sn2 = (v) => typeof v === "string" ? v : null;
|
|
2754
|
+
var n = (v) => typeof v === "number" && Number.isFinite(v) ? v : typeof v === "string" && v.trim() !== "" && Number.isFinite(Number(v)) ? Number(v) : null;
|
|
2755
|
+
function toDeviceModelFile(r) {
|
|
2756
|
+
return {
|
|
2757
|
+
id: s2(r.id),
|
|
2758
|
+
app_instance_id: s2(r.app_instance_id),
|
|
2759
|
+
root_id: s2(r.root_id),
|
|
2760
|
+
rel_path: sn2(r.rel_path),
|
|
2761
|
+
size_bytes: n(r.size_bytes),
|
|
2762
|
+
sha256: sn2(r.sha256),
|
|
2763
|
+
artifact_id: sn2(r.artifact_id),
|
|
2764
|
+
state: s2(r.state),
|
|
2765
|
+
organization_id: sn2(r.organization_id)
|
|
2766
|
+
};
|
|
2767
|
+
}
|
|
2768
|
+
async function readDeviceModelFiles(client, opts = {}) {
|
|
2769
|
+
const db = client;
|
|
2770
|
+
let q = db.schema("ai").from("device_model_file").select("*").is("deleted_at", null).in("state", opts.states ?? DEVICE_FILE_USABLE_STATES);
|
|
2771
|
+
if (opts.appInstanceIds) q = q.in("app_instance_id", opts.appInstanceIds);
|
|
2772
|
+
const { data, error } = await q;
|
|
2773
|
+
if (error) throw new Error(`ai.device_model_file: ${error.message}`);
|
|
2774
|
+
return (data ?? []).filter((r) => r.deleted_at == null).map(toDeviceModelFile);
|
|
2775
|
+
}
|
|
2776
|
+
function requiredArtifactIds(v) {
|
|
2777
|
+
const core = v.artifacts.filter((a) => a.required_for.includes("core"));
|
|
2778
|
+
return (core.length ? core : v.artifacts).map((a) => a.id);
|
|
2779
|
+
}
|
|
2780
|
+
function availableOnDevices(variants, files) {
|
|
2781
|
+
const usable = files.filter((f) => f.artifact_id && DEVICE_FILE_USABLE_STATES.includes(f.state));
|
|
2782
|
+
const out = /* @__PURE__ */ new Map();
|
|
2783
|
+
for (const v of variants) {
|
|
2784
|
+
const order = new Map(v.artifacts.map((a, i) => [a.id, i]));
|
|
2785
|
+
const required = requiredArtifactIds(v);
|
|
2786
|
+
const byDevice = /* @__PURE__ */ new Map();
|
|
2787
|
+
for (const f of usable)
|
|
2788
|
+
if (order.has(f.artifact_id)) {
|
|
2789
|
+
const list2 = byDevice.get(f.app_instance_id) ?? [];
|
|
2790
|
+
list2.push(f);
|
|
2791
|
+
byDevice.set(f.app_instance_id, list2);
|
|
2792
|
+
}
|
|
2793
|
+
const list = [];
|
|
2794
|
+
for (const device of [...byDevice.keys()].sort()) {
|
|
2795
|
+
const held = byDevice.get(device);
|
|
2796
|
+
const have = new Set(held.map((f) => f.artifact_id));
|
|
2797
|
+
if (!required.length || !required.every((id) => have.has(id))) continue;
|
|
2798
|
+
list.push({
|
|
2799
|
+
app_instance_id: device,
|
|
2800
|
+
variant_id: v.id,
|
|
2801
|
+
device_model_file_ids: held.slice().sort((a, b) => order.get(a.artifact_id) - order.get(b.artifact_id) || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0)).map((f) => f.id)
|
|
2802
|
+
});
|
|
2803
|
+
}
|
|
2804
|
+
out.set(v.id, list);
|
|
2805
|
+
}
|
|
2806
|
+
return out;
|
|
2807
|
+
}
|
|
2808
|
+
var DeviceModelUnavailableError = class extends Error {
|
|
2809
|
+
code;
|
|
2810
|
+
constructor(code, message) {
|
|
2811
|
+
super(message);
|
|
2812
|
+
this.name = "DeviceModelUnavailableError";
|
|
2813
|
+
this.code = code;
|
|
2814
|
+
}
|
|
2815
|
+
};
|
|
2816
|
+
|
|
2817
|
+
// models/catalog-reader.ts
|
|
2738
2818
|
var MODEL_CATALOG_KINDS = /* @__PURE__ */ new Set([
|
|
2739
2819
|
"llm_model",
|
|
2740
2820
|
"whisper_model",
|
|
@@ -2772,14 +2852,17 @@ function catalogFingerprint(catalog) {
|
|
|
2772
2852
|
const { catalog_fingerprint: _omit, ...rest } = catalog;
|
|
2773
2853
|
return (0, import_sha256.sha256Hex)(canonicalJson(rest));
|
|
2774
2854
|
}
|
|
2775
|
-
var
|
|
2776
|
-
var
|
|
2777
|
-
var
|
|
2855
|
+
var s3 = (v) => typeof v === "string" ? v : "";
|
|
2856
|
+
var sn3 = (v) => typeof v === "string" ? v : null;
|
|
2857
|
+
var n2 = (v) => typeof v === "number" && Number.isFinite(v) ? v : typeof v === "string" && v.trim() !== "" && Number.isFinite(Number(v)) ? Number(v) : null;
|
|
2778
2858
|
var live2 = (r) => r.deleted_at == null;
|
|
2779
2859
|
var byCodepoint2 = (a, b) => a < b ? -1 : a > b ? 1 : 0;
|
|
2780
|
-
var byId = (rows3) => new Map(rows3.map((r) => [
|
|
2860
|
+
var byId = (rows3) => new Map(rows3.map((r) => [s3(r.id), r]));
|
|
2781
2861
|
var strings = (v) => Array.isArray(v) ? v.filter((x) => typeof x === "string") : [];
|
|
2782
2862
|
async function readModelCatalog(client, opts = {}) {
|
|
2863
|
+
return readCatalogWith(client, opts, null);
|
|
2864
|
+
}
|
|
2865
|
+
async function readCatalogWith(client, opts, preread) {
|
|
2783
2866
|
const db = client;
|
|
2784
2867
|
const offeredOnly = opts.offeredOnly ?? true;
|
|
2785
2868
|
const ai = db.schema("ai");
|
|
@@ -2797,20 +2880,29 @@ async function readModelCatalog(client, opts = {}) {
|
|
|
2797
2880
|
]);
|
|
2798
2881
|
const curated = curatedList(shapeCuratedModels(raw), { offeredOnly });
|
|
2799
2882
|
const listed = new Set(curated.map((m) => m.id));
|
|
2800
|
-
const variants = raw.variants.filter((v) => listed.has(
|
|
2883
|
+
const variants = raw.variants.filter((v) => listed.has(s3(v.model_id)) && (offeredOnly ? s3(v.review_state) === "offered" : isListedVariant(v)));
|
|
2801
2884
|
const entryIds = [...new Set(curated.flatMap((m) => m.variants.flatMap((v) => v.catalog_entry_ids)))].sort(byCodepoint2);
|
|
2802
2885
|
const warnings = [];
|
|
2803
|
-
const
|
|
2804
|
-
|
|
2886
|
+
const devices = opts.devices ? opts.devices === true ? {} : opts.devices : null;
|
|
2887
|
+
const [artifacts, entries, deviceFiles] = await Promise.all([
|
|
2888
|
+
variants.length ? all("model_artifact", (q) => q.in("variant_id", variants.map((v) => s3(v.id)))) : Promise.resolve([]),
|
|
2805
2889
|
entryIds.length ? Promise.resolve(db.schema("public").from("catalog_entries").select("id,kind").in("id", entryIds)).then(({ data, error }) => {
|
|
2806
2890
|
if (error) {
|
|
2807
2891
|
warnings.push(`public.catalog_entries: ${error.message} (models placed by what they do)`);
|
|
2808
2892
|
return [];
|
|
2809
2893
|
}
|
|
2810
2894
|
return data ?? [];
|
|
2811
|
-
}) : Promise.resolve([])
|
|
2895
|
+
}) : Promise.resolve([]),
|
|
2896
|
+
devices ? preread ? Promise.resolve(preread) : readDeviceModelFiles(client, devices.appInstanceIds ? { appInstanceIds: devices.appInstanceIds } : {}) : Promise.resolve(null)
|
|
2812
2897
|
]);
|
|
2813
|
-
const
|
|
2898
|
+
const placement2 = deviceFiles ? availableOnDevices(
|
|
2899
|
+
variants.map((v) => ({
|
|
2900
|
+
id: s3(v.id),
|
|
2901
|
+
artifacts: artifacts.filter((a) => s3(a.variant_id) === s3(v.id)).map((a) => ({ id: s3(a.id), required_for: strings(a.required_for) }))
|
|
2902
|
+
})),
|
|
2903
|
+
deviceFiles
|
|
2904
|
+
) : null;
|
|
2905
|
+
const kindOfEntry = new Map(entries.map((e) => [s3(e.id), s3(e.kind)]));
|
|
2814
2906
|
const stamps = [];
|
|
2815
2907
|
const stamp = (r) => {
|
|
2816
2908
|
if (r && typeof r.updated_at === "string") stamps.push(r.updated_at);
|
|
@@ -2818,84 +2910,87 @@ async function readModelCatalog(client, opts = {}) {
|
|
|
2818
2910
|
const modelById = byId(raw.models);
|
|
2819
2911
|
const providerById = byId(raw.providers);
|
|
2820
2912
|
const upstreamById = byId(upstreams);
|
|
2821
|
-
const presentationOf = new Map(raw.presentations.map((p) => [
|
|
2913
|
+
const presentationOf = new Map(raw.presentations.map((p) => [s3(p.model_id), p]));
|
|
2822
2914
|
const models = curated.flatMap((c) => {
|
|
2823
2915
|
const m = modelById.get(c.id);
|
|
2824
2916
|
if (!m) return [];
|
|
2825
2917
|
stamp(m);
|
|
2826
2918
|
const p = presentationOf.get(c.id);
|
|
2827
2919
|
stamp(p);
|
|
2828
|
-
const maker = providerById.get(
|
|
2920
|
+
const maker = providerById.get(s3(m.provider_id));
|
|
2829
2921
|
return [
|
|
2830
2922
|
{
|
|
2831
|
-
id:
|
|
2832
|
-
name:
|
|
2833
|
-
desktop_id:
|
|
2834
|
-
common_name:
|
|
2835
|
-
maker:
|
|
2836
|
-
maker_logo_file_id:
|
|
2837
|
-
description:
|
|
2923
|
+
id: s3(m.id),
|
|
2924
|
+
name: s3(m.name),
|
|
2925
|
+
desktop_id: sn3(m.metadata?.desktop_id),
|
|
2926
|
+
common_name: sn3(m.common_name),
|
|
2927
|
+
maker: sn3(maker?.name),
|
|
2928
|
+
maker_logo_file_id: sn3(maker?.logo_file_id),
|
|
2929
|
+
description: sn3(m.description),
|
|
2838
2930
|
capabilities: m.capabilities ?? {},
|
|
2839
2931
|
kind: catalogKindOf(c, kindOfEntry),
|
|
2840
2932
|
offered: c.offered,
|
|
2841
2933
|
updated_at: c.updated_at,
|
|
2842
2934
|
presentation: p ? {
|
|
2843
|
-
summary:
|
|
2844
|
-
symbol:
|
|
2845
|
-
color:
|
|
2846
|
-
shelf:
|
|
2847
|
-
shelf_title:
|
|
2848
|
-
shelf_subtitle:
|
|
2849
|
-
display_order:
|
|
2850
|
-
page:
|
|
2851
|
-
params_label:
|
|
2935
|
+
summary: sn3(p.summary),
|
|
2936
|
+
symbol: sn3(p.symbol),
|
|
2937
|
+
color: sn3(p.color),
|
|
2938
|
+
shelf: sn3(p.shelf),
|
|
2939
|
+
shelf_title: sn3(p.shelf_title),
|
|
2940
|
+
shelf_subtitle: sn3(p.shelf_subtitle),
|
|
2941
|
+
display_order: n2(p.display_order),
|
|
2942
|
+
page: sn3(p.page),
|
|
2943
|
+
params_label: sn3(p.params_label),
|
|
2852
2944
|
tags: strings(p.tags),
|
|
2853
2945
|
links: Array.isArray(p.links) ? p.links : [],
|
|
2854
|
-
thumbnail_file_id:
|
|
2855
|
-
hero_file_id:
|
|
2946
|
+
thumbnail_file_id: sn3(p.thumbnail_file_id),
|
|
2947
|
+
hero_file_id: sn3(p.hero_file_id),
|
|
2856
2948
|
gallery_file_ids: strings(p.gallery_file_ids).filter((f) => f.length > 0),
|
|
2857
2949
|
facts: p.facts && typeof p.facts === "object" && !Array.isArray(p.facts) ? p.facts : {}
|
|
2858
2950
|
} : null,
|
|
2859
|
-
variants: variants.filter((v) =>
|
|
2951
|
+
variants: variants.filter((v) => s3(v.model_id) === c.id).sort((a, b) => byCodepoint2(s3(a.key), s3(b.key))).map((v) => {
|
|
2860
2952
|
stamp(v);
|
|
2861
|
-
const up = upstreamById.get(
|
|
2953
|
+
const up = upstreamById.get(s3(v.upstream_id));
|
|
2862
2954
|
stamp(up);
|
|
2863
|
-
const arts = artifacts.filter((a) =>
|
|
2955
|
+
const arts = artifacts.filter((a) => s3(a.variant_id) === s3(v.id)).sort((a, b) => (n2(a.shard_index) ?? 0) - (n2(b.shard_index) ?? 0) || byCodepoint2(s3(a.path_in_repo), s3(b.path_in_repo)));
|
|
2864
2956
|
arts.forEach(stamp);
|
|
2865
2957
|
return {
|
|
2866
|
-
id:
|
|
2867
|
-
key:
|
|
2868
|
-
catalog_key: `${
|
|
2869
|
-
review_state:
|
|
2958
|
+
id: s3(v.id),
|
|
2959
|
+
key: s3(v.key),
|
|
2960
|
+
catalog_key: `${s3(m.name)}/${s3(v.key)}`,
|
|
2961
|
+
review_state: s3(v.review_state),
|
|
2870
2962
|
catalog_entry_ids: strings(v.metadata?.catalog_entry_ids),
|
|
2871
2963
|
is_default: v.is_default === true,
|
|
2872
|
-
format:
|
|
2873
|
-
quant:
|
|
2874
|
-
architecture:
|
|
2875
|
-
chat_template_kind:
|
|
2964
|
+
format: s3(v.format),
|
|
2965
|
+
quant: s3(v.quant),
|
|
2966
|
+
architecture: s3(v.architecture),
|
|
2967
|
+
chat_template_kind: s3(v.chat_template_kind),
|
|
2876
2968
|
os_arch: strings(v.os_arch),
|
|
2877
|
-
selection_rank:
|
|
2969
|
+
selection_rank: n2(v.selection_rank) ?? Number.MAX_SAFE_INTEGER,
|
|
2878
2970
|
// internal-bound: a row with no rank sorts last (the column is NOT NULL; this only orders a malformed row)
|
|
2879
|
-
license:
|
|
2880
|
-
gated:
|
|
2881
|
-
total_bytes:
|
|
2882
|
-
memory_bytes_min:
|
|
2883
|
-
memory_bytes_recommended:
|
|
2971
|
+
license: sn3(v.license_id),
|
|
2972
|
+
gated: s3(v.gated),
|
|
2973
|
+
total_bytes: n2(v.total_bytes),
|
|
2974
|
+
memory_bytes_min: n2(v.memory_bytes_min),
|
|
2975
|
+
memory_bytes_recommended: n2(v.memory_bytes_recommended),
|
|
2884
2976
|
tested_on_current_runtime: v.tested_on_current_runtime === true,
|
|
2885
|
-
min_app_version:
|
|
2886
|
-
upstream: up ? { kind:
|
|
2977
|
+
min_app_version: sn3(v.min_app_version),
|
|
2978
|
+
upstream: up ? { kind: s3(up.upstream_kind), repo: sn3(up.repo), revision: sn3(up.revision) } : null,
|
|
2887
2979
|
artifacts: arts.map((a) => ({
|
|
2888
|
-
role:
|
|
2889
|
-
path:
|
|
2890
|
-
url:
|
|
2891
|
-
size_bytes:
|
|
2892
|
-
sha256:
|
|
2980
|
+
role: s3(a.role),
|
|
2981
|
+
path: s3(a.path_in_repo),
|
|
2982
|
+
url: s3(a.url),
|
|
2983
|
+
size_bytes: n2(a.size_bytes) ?? 0,
|
|
2984
|
+
sha256: s3(a.sha256),
|
|
2893
2985
|
required_for: strings(a.required_for).sort(),
|
|
2894
|
-
shard_index:
|
|
2895
|
-
shard_count:
|
|
2986
|
+
shard_index: n2(a.shard_index),
|
|
2987
|
+
shard_count: n2(a.shard_count)
|
|
2896
2988
|
}))
|
|
2897
2989
|
};
|
|
2898
|
-
})
|
|
2990
|
+
}),
|
|
2991
|
+
...placement2 ? {
|
|
2992
|
+
available_on: variants.filter((v) => s3(v.model_id) === c.id).sort((a, b) => byCodepoint2(s3(a.key), s3(b.key))).flatMap((v) => placement2.get(s3(v.id)) ?? [])
|
|
2993
|
+
} : {}
|
|
2899
2994
|
}
|
|
2900
2995
|
];
|
|
2901
2996
|
});
|
|
@@ -2903,36 +2998,36 @@ async function readModelCatalog(client, opts = {}) {
|
|
|
2903
2998
|
$schema: "matrx.model-catalog.snapshot/v1",
|
|
2904
2999
|
catalog_updated_at: "",
|
|
2905
3000
|
models,
|
|
2906
|
-
runtimes: runtimes.sort((a, b) => byCodepoint2(
|
|
3001
|
+
runtimes: runtimes.sort((a, b) => byCodepoint2(s3(a.key), s3(b.key))).map((rt) => {
|
|
2907
3002
|
stamp(rt);
|
|
2908
3003
|
return {
|
|
2909
|
-
key:
|
|
2910
|
-
name:
|
|
2911
|
-
upstream_repo:
|
|
2912
|
-
builds: builds.filter((b) =>
|
|
3004
|
+
key: s3(rt.key),
|
|
3005
|
+
name: s3(rt.name),
|
|
3006
|
+
upstream_repo: sn3(rt.upstream_repo),
|
|
3007
|
+
builds: builds.filter((b) => s3(b.runtime_id) === s3(rt.id)).map((b) => {
|
|
2913
3008
|
stamp(b);
|
|
2914
3009
|
const known = b.metadata?.known_architectures;
|
|
2915
3010
|
return {
|
|
2916
|
-
id:
|
|
2917
|
-
version:
|
|
2918
|
-
os:
|
|
2919
|
-
arch:
|
|
2920
|
-
accelerator:
|
|
2921
|
-
build_kind:
|
|
2922
|
-
url:
|
|
2923
|
-
size_bytes:
|
|
2924
|
-
sha256:
|
|
3011
|
+
id: s3(b.id),
|
|
3012
|
+
version: s3(b.runtime_version),
|
|
3013
|
+
os: s3(b.os),
|
|
3014
|
+
arch: s3(b.arch),
|
|
3015
|
+
accelerator: s3(b.accelerator),
|
|
3016
|
+
build_kind: s3(b.build_kind),
|
|
3017
|
+
url: sn3(b.url),
|
|
3018
|
+
size_bytes: n2(b.size_bytes),
|
|
3019
|
+
sha256: sn3(b.sha256),
|
|
2925
3020
|
is_active: b.is_active === true,
|
|
2926
|
-
min_app_version:
|
|
3021
|
+
min_app_version: sn3(b.min_app_version),
|
|
2927
3022
|
// The architectures this pinned llama-server build loads (runtime_build.metadata): the own-model judge reads it.
|
|
2928
3023
|
known_architectures: Array.isArray(known) ? known.map(String).sort() : null,
|
|
2929
|
-
compat: compat.filter((c) =>
|
|
2930
|
-
hardware_class:
|
|
2931
|
-
format:
|
|
2932
|
-
quant:
|
|
2933
|
-
architecture:
|
|
2934
|
-
chat_template_kind:
|
|
2935
|
-
status:
|
|
3024
|
+
compat: compat.filter((c) => s3(c.runtime_build_id) === s3(b.id)).map((c) => ({
|
|
3025
|
+
hardware_class: s3(c.hardware_class),
|
|
3026
|
+
format: s3(c.format),
|
|
3027
|
+
quant: s3(c.quant),
|
|
3028
|
+
architecture: s3(c.architecture),
|
|
3029
|
+
chat_template_kind: s3(c.chat_template_kind),
|
|
3030
|
+
status: s3(c.status)
|
|
2936
3031
|
}))
|
|
2937
3032
|
};
|
|
2938
3033
|
})
|
|
@@ -2944,6 +3039,37 @@ async function readModelCatalog(client, opts = {}) {
|
|
|
2944
3039
|
out.catalog_fingerprint = catalogFingerprint(out);
|
|
2945
3040
|
return out;
|
|
2946
3041
|
}
|
|
3042
|
+
async function resolveDeviceModel(client, req) {
|
|
3043
|
+
const files = await readDeviceModelFiles(client, {
|
|
3044
|
+
appInstanceIds: [req.app_instance_id],
|
|
3045
|
+
states: [.../* @__PURE__ */ new Set([...DEVICE_FILE_USABLE_STATES, ...DEVICE_OWN_FILE_USABLE_STATES])]
|
|
3046
|
+
});
|
|
3047
|
+
const own = files.find((f) => f.id === req.local_model_id);
|
|
3048
|
+
if (own) {
|
|
3049
|
+
if (own.artifact_id)
|
|
3050
|
+
throw new DeviceModelUnavailableError("not_own_file", `device model file ${own.id} is catalog artifact ${own.artifact_id}; pass its model id, not the file id`);
|
|
3051
|
+
if (!DEVICE_OWN_FILE_USABLE_STATES.includes(own.state))
|
|
3052
|
+
throw new DeviceModelUnavailableError("file_not_usable", `own model file ${own.id} on computer ${req.app_instance_id} is ${own.state}`);
|
|
3053
|
+
return { own: true, file: own };
|
|
3054
|
+
}
|
|
3055
|
+
const usable = files.filter((f) => DEVICE_FILE_USABLE_STATES.includes(f.state));
|
|
3056
|
+
const catalog = await readCatalogWith(client, { offeredOnly: false, devices: { appInstanceIds: [req.app_instance_id] } }, usable);
|
|
3057
|
+
const model = catalog.models.find((m) => m.id === req.local_model_id);
|
|
3058
|
+
if (!model)
|
|
3059
|
+
throw new DeviceModelUnavailableError("unknown_model", `no catalog model or own model file ${req.local_model_id} on computer ${req.app_instance_id}`);
|
|
3060
|
+
const label = model.common_name || model.name;
|
|
3061
|
+
if (req.variant_id && !model.variants.some((v) => v.id === req.variant_id))
|
|
3062
|
+
throw new DeviceModelUnavailableError("unknown_variant", `${label} has no listed variant ${req.variant_id}`);
|
|
3063
|
+
const held = (model.available_on ?? []).filter((a) => a.app_instance_id === req.app_instance_id && (!req.variant_id || a.variant_id === req.variant_id));
|
|
3064
|
+
const variants = held.map((a) => ({ a, v: model.variants.find((v) => v.id === a.variant_id) })).sort((x, y) => Number(y.v.is_default) - Number(x.v.is_default) || x.v.selection_rank - y.v.selection_rank || byCodepoint2(x.v.key, y.v.key));
|
|
3065
|
+
const pick = variants[0];
|
|
3066
|
+
if (!pick) {
|
|
3067
|
+
const which = req.variant_id ? ` (${model.variants.find((v) => v.id === req.variant_id).key})` : "";
|
|
3068
|
+
throw new DeviceModelUnavailableError("not_on_device", `computer ${req.app_instance_id} does not hold every required file of ${label}${which}`);
|
|
3069
|
+
}
|
|
3070
|
+
const byFileId = new Map(usable.map((f) => [f.id, f]));
|
|
3071
|
+
return { own: false, model, variant: pick.v, files: pick.a.device_model_file_ids.map((id) => byFileId.get(id)) };
|
|
3072
|
+
}
|
|
2947
3073
|
|
|
2948
3074
|
// models/fit.ts
|
|
2949
3075
|
var featuresOf = (c) => {
|