@ai-matrx/agents 0.59.187 → 0.59.188

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.
@@ -24,6 +24,7 @@ __export(models_exports, {
24
24
  CONTENT_TYPES: () => CONTENT_TYPES,
25
25
  DEFAULT_CAPABILITIES: () => DEFAULT_CAPABILITIES,
26
26
  EMPTY_MODEL_RECORDS: () => EMPTY_MODEL_RECORDS,
27
+ EXCLUDED_REVIEW_STATES: () => EXCLUDED_REVIEW_STATES,
27
28
  FEATURE_BUCKETS: () => FEATURE_BUCKETS,
28
29
  FEATURE_BUCKET_ORDER: () => FEATURE_BUCKET_ORDER,
29
30
  FEATURE_KEYS: () => FEATURE_KEYS,
@@ -32,6 +33,7 @@ __export(models_exports, {
32
33
  INPUT_MODALITIES: () => INPUT_MODALITIES,
33
34
  INTERACTION_MODES: () => INTERACTION_MODES,
34
35
  MAX_SUCCESSION_HOPS: () => MAX_SUCCESSION_HOPS,
36
+ MODEL_CATALOG_KINDS: () => MODEL_CATALOG_KINDS,
35
37
  MODEL_FAVORITE_ENTITY_TYPE: () => MODEL_FAVORITE_ENTITY_TYPE,
36
38
  OUTPUT_MODALITIES: () => OUTPUT_MODALITIES,
37
39
  SERVICE_LABEL: () => SERVICE_LABEL,
@@ -41,7 +43,9 @@ __export(models_exports, {
41
43
  acceptsTextInstructions: () => acceptsTextInstructions,
42
44
  buildModelClassIndex: () => buildModelClassIndex,
43
45
  buildSuccessionIndex: () => buildSuccessionIndex,
46
+ catalogFingerprint: () => catalogFingerprint,
44
47
  catalogForApp: () => catalogForApp,
48
+ catalogKindOf: () => catalogKindOf,
45
49
  classConfigKey: () => classConfigKey,
46
50
  collapseTiersByClass: () => collapseTiersByClass,
47
51
  costRatingTier: () => costRatingTier,
@@ -69,6 +73,7 @@ __export(models_exports, {
69
73
  isFeatureKey: () => isFeatureKey,
70
74
  isHelperGguf: () => isHelperGguf,
71
75
  isInteractionMode: () => isInteractionMode,
76
+ isListedVariant: () => isListedVariant,
72
77
  isLocalModelCatalog: () => isLocalModelCatalog,
73
78
  isManagedAgentModelCapability: () => isManagedAgentModelCapability,
74
79
  isProjectorName: () => isProjectorName,
@@ -94,7 +99,9 @@ __export(models_exports, {
94
99
  priceTierRating: () => priceTierRating,
95
100
  quantFromName: () => quantFromName,
96
101
  rankVariants: () => rankVariants,
102
+ readCuratedRows: () => readCuratedRows,
97
103
  readGgufHeader: () => readGgufHeader,
104
+ readModelCatalog: () => readModelCatalog,
98
105
  reconcileModelFavoriteIds: () => reconcileModelFavoriteIds,
99
106
  reportModelDiagnostic: () => reportModelDiagnostic,
100
107
  requireCanonicalCapabilities: () => requireCanonicalCapabilities,
@@ -381,13 +388,13 @@ function setModelDiagnosticsSink(sink) {
381
388
  }
382
389
  function reportModelDiagnostic(dedupeKey, entry) {
383
390
  try {
384
- const s2 = state();
385
- if (s2.reported.has(dedupeKey)) return;
386
- s2.reported.add(dedupeKey);
391
+ const s3 = state();
392
+ if (s3.reported.has(dedupeKey)) return;
393
+ s3.reported.add(dedupeKey);
387
394
  console.warn(`[parseCapabilities] ${entry.message}`);
388
- if (s2.sink) s2.sink(entry);
389
- else if (!s2.announced) {
390
- s2.announced = true;
395
+ if (s3.sink) s3.sink(entry);
396
+ else if (!s3.announced) {
397
+ s3.announced = true;
391
398
  console.error(
392
399
  "[@ai-matrx/agents/models] No diagnostics sink is bound \u2014 capability-vocabulary drift reaches the console only. Call setModelDiagnosticsSink(...) with your error store."
393
400
  );
@@ -1014,29 +1021,29 @@ function createModelRecords(config) {
1014
1021
  loadOptions() {
1015
1022
  if (state2.fetchScope === "active" || state2.fetchScope === "all") return Promise.resolve();
1016
1023
  return once("options", async () => {
1017
- update((s2) => ({ ...s2, isLoading: true, error: null }));
1024
+ update((s3) => ({ ...s3, isLoading: true, error: null }));
1018
1025
  try {
1019
1026
  const rows3 = await readOptions();
1020
- update((s2) => {
1021
- const entities = { ...s2.entities };
1027
+ update((s3) => {
1028
+ const entities = { ...s3.entities };
1022
1029
  for (const row of rows3) {
1023
1030
  const existing = entities[row.id];
1024
1031
  if (existing?._fetchType === "full") continue;
1025
1032
  entities[row.id] = { ...emptyRecord(), ...existing, ...row, _fetchType: "options" };
1026
1033
  }
1027
1034
  return withIdLists({
1028
- ...s2,
1035
+ ...s3,
1029
1036
  entities,
1030
1037
  isLoading: false,
1031
1038
  error: null,
1032
- fetchScope: s2.fetchScope !== "all" && s2.fetchScope !== "deprecated" ? "active" : s2.fetchScope,
1039
+ fetchScope: s3.fetchScope !== "all" && s3.fetchScope !== "deprecated" ? "active" : s3.fetchScope,
1033
1040
  lastFetched: Date.now()
1034
1041
  });
1035
1042
  });
1036
1043
  } catch (err) {
1037
1044
  const message = messageOf(err);
1038
1045
  errorSink({ code: "model-records-options-load-failed", message });
1039
- update((s2) => ({ ...s2, isLoading: false, error: message }));
1046
+ update((s3) => ({ ...s3, isLoading: false, error: message }));
1040
1047
  }
1041
1048
  });
1042
1049
  },
@@ -1046,10 +1053,10 @@ function createModelRecords(config) {
1046
1053
  return inFlight.get(`model:${modelId}`) ?? Promise.resolve();
1047
1054
  }
1048
1055
  return once(`model:${modelId}`, async () => {
1049
- update((s2) => {
1050
- const detailErrorById = { ...s2.detailErrorById };
1056
+ update((s3) => {
1057
+ const detailErrorById = { ...s3.detailErrorById };
1051
1058
  delete detailErrorById[modelId];
1052
- return { ...s2, detailStatusById: { ...s2.detailStatusById, [modelId]: "loading" }, detailErrorById };
1059
+ return { ...s3, detailStatusById: { ...s3.detailStatusById, [modelId]: "loading" }, detailErrorById };
1053
1060
  });
1054
1061
  try {
1055
1062
  const relation = await isSignedIn() ? "model_config" : "model_public";
@@ -1066,16 +1073,16 @@ function createModelRecords(config) {
1066
1073
  capabilities: requireCanonicalCapabilities(row.capabilities, { modelId: row.id, modelName: row.name })
1067
1074
  };
1068
1075
  const record = normalizeModel(read);
1069
- update((s2) => {
1070
- const existing = s2.entities[record.id];
1071
- const detailErrorById = { ...s2.detailErrorById };
1076
+ update((s3) => {
1077
+ const existing = s3.entities[record.id];
1078
+ const detailErrorById = { ...s3.detailErrorById };
1072
1079
  delete detailErrorById[modelId];
1073
1080
  return withIdLists({
1074
- ...s2,
1075
- detailStatusById: { ...s2.detailStatusById, [modelId]: "succeeded" },
1081
+ ...s3,
1082
+ detailStatusById: { ...s3.detailStatusById, [modelId]: "succeeded" },
1076
1083
  detailErrorById,
1077
1084
  entities: {
1078
- ...s2.entities,
1085
+ ...s3.entities,
1079
1086
  [record.id]: { ...emptyRecord(), ...existing, ...record, maker: record.maker ?? existing?.maker ?? null, _fetchType: "full" }
1080
1087
  }
1081
1088
  });
@@ -1083,21 +1090,21 @@ function createModelRecords(config) {
1083
1090
  } catch (err) {
1084
1091
  const message = `Model configuration ${modelId}: ${messageOf(err)}`;
1085
1092
  errorSink({ code: "model-records-model-load-failed", message, context: { modelId } });
1086
- update((s2) => ({
1087
- ...s2,
1088
- detailStatusById: { ...s2.detailStatusById, [modelId]: "failed" },
1089
- detailErrorById: { ...s2.detailErrorById, [modelId]: message }
1093
+ update((s3) => ({
1094
+ ...s3,
1095
+ detailStatusById: { ...s3.detailStatusById, [modelId]: "failed" },
1096
+ detailErrorById: { ...s3.detailErrorById, [modelId]: message }
1090
1097
  }));
1091
1098
  }
1092
1099
  });
1093
1100
  },
1094
1101
  retryModel(modelId) {
1095
- update((s2) => {
1096
- const detailStatusById = { ...s2.detailStatusById };
1097
- const detailErrorById = { ...s2.detailErrorById };
1102
+ update((s3) => {
1103
+ const detailStatusById = { ...s3.detailStatusById };
1104
+ const detailErrorById = { ...s3.detailErrorById };
1098
1105
  delete detailStatusById[modelId];
1099
1106
  delete detailErrorById[modelId];
1100
- return { ...s2, detailStatusById, detailErrorById };
1107
+ return { ...s3, detailStatusById, detailErrorById };
1101
1108
  });
1102
1109
  },
1103
1110
  loadClassConfig(modelId, offeringId) {
@@ -1105,37 +1112,37 @@ function createModelRecords(config) {
1105
1112
  const status = state2.classConfigStatusByOffering[key];
1106
1113
  if (status === "loading" || status === "succeeded") return inFlight.get(`class:${key}`) ?? Promise.resolve();
1107
1114
  return once(`class:${key}`, async () => {
1108
- update((s2) => ({ ...s2, classConfigStatusByOffering: { ...s2.classConfigStatusByOffering, [key]: "loading" } }));
1115
+ update((s3) => ({ ...s3, classConfigStatusByOffering: { ...s3.classConfigStatusByOffering, [key]: "loading" } }));
1109
1116
  try {
1110
1117
  const { data, error } = await ai().rpc("resolve_model_config", { p_model_id: modelId, p_offering_id: offeringId });
1111
1118
  if (error) throw error;
1112
1119
  const cfg = data && typeof data === "object" && !Array.isArray(data) ? data : null;
1113
- update((s2) => ({
1114
- ...s2,
1115
- classConfigStatusByOffering: { ...s2.classConfigStatusByOffering, [key]: "succeeded" },
1120
+ update((s3) => ({
1121
+ ...s3,
1122
+ classConfigStatusByOffering: { ...s3.classConfigStatusByOffering, [key]: "succeeded" },
1116
1123
  classConfigByOffering: {
1117
- ...s2.classConfigByOffering,
1124
+ ...s3.classConfigByOffering,
1118
1125
  [key]: { modelId, controls: cfg?.controls ?? null, constraints: cfg?.constraints ?? null }
1119
1126
  }
1120
1127
  }));
1121
1128
  } catch (err) {
1122
1129
  errorSink({ code: "model-records-class-config-failed", message: `Model class configuration ${modelId} / ${offeringId}: ${messageOf(err)}` });
1123
- update((s2) => ({ ...s2, classConfigStatusByOffering: { ...s2.classConfigStatusByOffering, [key]: "failed" } }));
1130
+ update((s3) => ({ ...s3, classConfigStatusByOffering: { ...s3.classConfigStatusByOffering, [key]: "failed" } }));
1124
1131
  }
1125
1132
  });
1126
1133
  },
1127
1134
  loadClasses() {
1128
1135
  if (state2.modelClassStatus === "loading" || state2.modelClassStatus === "succeeded") return inFlight.get("classes") ?? Promise.resolve();
1129
1136
  return once("classes", async () => {
1130
- update((s2) => ({ ...s2, modelClassStatus: "loading" }));
1137
+ update((s3) => ({ ...s3, modelClassStatus: "loading" }));
1131
1138
  try {
1132
1139
  const { data, error } = await ai().from("model_offering").select("model_id, offering_id, served_via, served_via_endpoint_id, priority");
1133
1140
  if (error) throw error;
1134
1141
  const index = buildModelClassIndex(data ?? []);
1135
- update((s2) => ({ ...s2, modelClassStatus: "succeeded", modelClassIndex: index }));
1142
+ update((s3) => ({ ...s3, modelClassStatus: "succeeded", modelClassIndex: index }));
1136
1143
  } catch (err) {
1137
1144
  errorSink({ code: "model-records-classes-failed", message: `Model classes: ${messageOf(err)}` });
1138
- update((s2) => ({ ...s2, modelClassStatus: "failed" }));
1145
+ update((s3) => ({ ...s3, modelClassStatus: "failed" }));
1139
1146
  }
1140
1147
  });
1141
1148
  },
@@ -1150,11 +1157,11 @@ function createModelRecords(config) {
1150
1157
  if (error) throw error;
1151
1158
  const slice = buildModelClassIndex(data ?? []);
1152
1159
  classesReadFor.add(modelId);
1153
- update((s2) => {
1154
- if (s2.modelClassStatus === "succeeded") return s2;
1155
- const base = s2.modelClassIndex ?? { classesByModelId: {}, classOfOffering: {} };
1160
+ update((s3) => {
1161
+ if (s3.modelClassStatus === "succeeded") return s3;
1162
+ const base = s3.modelClassIndex ?? { classesByModelId: {}, classOfOffering: {} };
1156
1163
  return {
1157
- ...s2,
1164
+ ...s3,
1158
1165
  modelClassIndex: {
1159
1166
  classesByModelId: { ...base.classesByModelId, ...slice.classesByModelId },
1160
1167
  classOfOffering: { ...base.classOfOffering, ...slice.classOfOffering }
@@ -1172,20 +1179,20 @@ function createModelRecords(config) {
1172
1179
  return inFlight.get(`identity:${modelId}`) ?? Promise.resolve();
1173
1180
  }
1174
1181
  return once(`identity:${modelId}`, async () => {
1175
- update((s2) => ({ ...s2, identityStatusById: { ...s2.identityStatusById, [modelId]: "loading" } }));
1182
+ update((s3) => ({ ...s3, identityStatusById: { ...s3.identityStatusById, [modelId]: "loading" } }));
1176
1183
  try {
1177
1184
  const { data, error } = await ai().from("model_definition").select("id, name, common_name, is_deprecated").eq("id", modelId).maybeSingle();
1178
1185
  if (error) throw error;
1179
1186
  if (!data) throw new Error(`AI model ${modelId} is not available (ai.model_definition has no such row)`);
1180
1187
  const row = data;
1181
- update((s2) => ({
1182
- ...s2,
1183
- identityById: { ...s2.identityById, [row.id]: row },
1184
- identityStatusById: { ...s2.identityStatusById, [row.id]: "succeeded" }
1188
+ update((s3) => ({
1189
+ ...s3,
1190
+ identityById: { ...s3.identityById, [row.id]: row },
1191
+ identityStatusById: { ...s3.identityStatusById, [row.id]: "succeeded" }
1185
1192
  }));
1186
1193
  } catch (err) {
1187
1194
  errorSink({ code: "model-records-identity-failed", message: messageOf(err), context: { modelId } });
1188
- update((s2) => ({ ...s2, identityStatusById: { ...s2.identityStatusById, [modelId]: "failed" } }));
1195
+ update((s3) => ({ ...s3, identityStatusById: { ...s3.identityStatusById, [modelId]: "failed" } }));
1189
1196
  }
1190
1197
  });
1191
1198
  },
@@ -1194,11 +1201,11 @@ function createModelRecords(config) {
1194
1201
  if (!classesReadFor.has(modelId) && state2.modelClassStatus !== "succeeded") {
1195
1202
  const slice = buildModelClassIndex(offerings.filter((o) => o.model_id === modelId));
1196
1203
  classesReadFor.add(modelId);
1197
- update((s2) => {
1198
- if (s2.modelClassStatus === "succeeded") return s2;
1199
- const base = s2.modelClassIndex ?? { classesByModelId: {}, classOfOffering: {} };
1204
+ update((s3) => {
1205
+ if (s3.modelClassStatus === "succeeded") return s3;
1206
+ const base = s3.modelClassIndex ?? { classesByModelId: {}, classOfOffering: {} };
1200
1207
  return {
1201
- ...s2,
1208
+ ...s3,
1202
1209
  modelClassIndex: {
1203
1210
  classesByModelId: { ...base.classesByModelId, ...slice.classesByModelId },
1204
1211
  classOfOffering: { ...base.classOfOffering, ...slice.classOfOffering }
@@ -1217,16 +1224,16 @@ function createModelRecords(config) {
1217
1224
  controls: row.controls ?? null,
1218
1225
  capabilities: requireCanonicalCapabilities(row.capabilities, { modelId: row.id, modelName: row.name })
1219
1226
  });
1220
- update((s2) => {
1221
- const existing = s2.entities[record.id];
1222
- const detailErrorById = { ...s2.detailErrorById };
1227
+ update((s3) => {
1228
+ const existing = s3.entities[record.id];
1229
+ const detailErrorById = { ...s3.detailErrorById };
1223
1230
  delete detailErrorById[modelId];
1224
1231
  return withIdLists({
1225
- ...s2,
1226
- detailStatusById: { ...s2.detailStatusById, [modelId]: "succeeded" },
1232
+ ...s3,
1233
+ detailStatusById: { ...s3.detailStatusById, [modelId]: "succeeded" },
1227
1234
  detailErrorById,
1228
1235
  entities: {
1229
- ...s2.entities,
1236
+ ...s3.entities,
1230
1237
  [record.id]: { ...emptyRecord(), ...existing, ...record, maker: record.maker ?? existing?.maker ?? null, _fetchType: "full" }
1231
1238
  }
1232
1239
  });
@@ -1236,14 +1243,14 @@ function createModelRecords(config) {
1236
1243
  }
1237
1244
  },
1238
1245
  hydrate({ models, fetchType, fetchScope, lastFetched }) {
1239
- update((s2) => {
1240
- const entities = { ...s2.entities };
1246
+ update((s3) => {
1247
+ const entities = { ...s3.entities };
1241
1248
  for (const raw of models) {
1242
1249
  const existing = entities[raw.id];
1243
1250
  if (existing?._fetchType === "full" && fetchType === "options") continue;
1244
1251
  entities[raw.id] = { ...emptyRecord(), ...normalizeModel({ ...raw, controls: raw.controls ?? null }), _fetchType: fetchType };
1245
1252
  }
1246
- return withIdLists({ ...s2, entities, fetchScope, lastFetched, isLoading: false, error: null });
1253
+ return withIdLists({ ...s3, entities, fetchScope, lastFetched, isLoading: false, error: null });
1247
1254
  });
1248
1255
  }
1249
1256
  };
@@ -1262,28 +1269,28 @@ function memo(fn) {
1262
1269
  var UNSET = /* @__PURE__ */ Symbol("unset");
1263
1270
  var activeKey = null;
1264
1271
  var activeOut = [];
1265
- function selectActiveModels(s2) {
1266
- if (!activeKey || activeKey[0] !== s2.entities || activeKey[1] !== s2.activeIds) {
1267
- activeKey = [s2.entities, s2.activeIds];
1268
- activeOut = s2.activeIds.map((id) => s2.entities[id]).filter((m) => !!m);
1272
+ function selectActiveModels(s3) {
1273
+ if (!activeKey || activeKey[0] !== s3.entities || activeKey[1] !== s3.activeIds) {
1274
+ activeKey = [s3.entities, s3.activeIds];
1275
+ activeOut = s3.activeIds.map((id) => s3.entities[id]).filter((m) => !!m);
1269
1276
  }
1270
1277
  return activeOut;
1271
1278
  }
1272
1279
  var deprecatedKey = null;
1273
1280
  var deprecatedOut = [];
1274
- function selectDeprecatedModels(s2) {
1275
- if (!deprecatedKey || deprecatedKey[0] !== s2.entities || deprecatedKey[1] !== s2.deprecatedIds) {
1276
- deprecatedKey = [s2.entities, s2.deprecatedIds];
1277
- deprecatedOut = s2.deprecatedIds.map((id) => s2.entities[id]).filter((m) => !!m);
1281
+ function selectDeprecatedModels(s3) {
1282
+ if (!deprecatedKey || deprecatedKey[0] !== s3.entities || deprecatedKey[1] !== s3.deprecatedIds) {
1283
+ deprecatedKey = [s3.entities, s3.deprecatedIds];
1284
+ deprecatedOut = s3.deprecatedIds.map((id) => s3.entities[id]).filter((m) => !!m);
1278
1285
  }
1279
1286
  return deprecatedOut;
1280
1287
  }
1281
1288
  var allOf = memo((entities) => Object.values(entities));
1282
- var selectAllModels = (s2) => allOf(s2.entities);
1289
+ var selectAllModels = (s3) => allOf(s3.entities);
1283
1290
  var optionsOf = memo(
1284
1291
  (models) => models.map((m) => ({ value: m.id, label: m.common_name || m.name || m.id, maker: m.maker, costRating: m.cost_rating, speedRating: m.speed_rating }))
1285
1292
  );
1286
- var selectModelOptions = (s2) => optionsOf(selectActiveModels(s2));
1293
+ var selectModelOptions = (s3) => optionsOf(selectActiveModels(s3));
1287
1294
  var allOptionsOf = memo(
1288
1295
  (entities) => Object.values(entities).map((m) => ({
1289
1296
  value: m.id,
@@ -1294,30 +1301,30 @@ var allOptionsOf = memo(
1294
1301
  successorId: m.successor_id ?? null
1295
1302
  }))
1296
1303
  );
1297
- var selectAllModelOptions = (s2) => allOptionsOf(s2.entities);
1298
- var selectModelById = (s2, modelId) => modelId ? s2.entities[modelId] : void 0;
1299
- function selectModelLabelById(s2, modelId) {
1304
+ var selectAllModelOptions = (s3) => allOptionsOf(s3.entities);
1305
+ var selectModelById = (s3, modelId) => modelId ? s3.entities[modelId] : void 0;
1306
+ function selectModelLabelById(s3, modelId) {
1300
1307
  if (!modelId) return void 0;
1301
- const m = s2.entities[modelId];
1302
- const identity = s2.identityById[modelId];
1308
+ const m = s3.entities[modelId];
1309
+ const identity = s3.identityById[modelId];
1303
1310
  return m?.common_name || m?.name || identity?.common_name || identity?.name || void 0;
1304
1311
  }
1305
- var selectModelNameById = (s2, modelId) => modelId ? s2.entities[modelId]?.name : void 0;
1306
- var selectModelClassName = (s2, modelId, offeringId) => modelClassName(s2.modelClassIndex, modelId, offeringId);
1307
- function selectModelLabelWithClass(s2, modelId, offeringId) {
1308
- const label = selectModelLabelById(s2, modelId);
1309
- return label ? withModelClass(label, selectModelClassName(s2, modelId, offeringId)) : void 0;
1310
- }
1311
- var selectModelControls = (s2, modelId) => s2.entities[modelId]?.controls;
1312
- var selectModelFetchType = (s2, modelId) => s2.entities[modelId]?._fetchType;
1313
- var selectModelFullyLoaded = (s2, modelId) => !!modelId && s2.entities[modelId]?._fetchType === "full";
1314
- var selectModelDetailError = (s2, modelId) => modelId && s2.detailErrorById[modelId] || null;
1315
- var selectModelClassConfig = (s2, modelId, offeringId) => modelId && offeringId ? s2.classConfigByOffering[classConfigKey(modelId, offeringId)] : void 0;
1316
- var selectActiveModelsReady = (s2) => (s2.fetchScope === "active" || s2.fetchScope === "all") && s2.activeIds.length > 0;
1317
- var selectDeprecatedModelsReady = (s2) => (s2.fetchScope === "deprecated" || s2.fetchScope === "all") && s2.deprecatedIds.length > 0;
1318
- var selectAllModelsReady = (s2) => s2.fetchScope === "all";
1319
- var selectModelIdentityById = (s2, modelId) => s2.identityById[modelId];
1320
- var selectModelIdentityLookupStatus = (s2, modelId) => s2.identityStatusById[modelId] ?? "idle";
1312
+ var selectModelNameById = (s3, modelId) => modelId ? s3.entities[modelId]?.name : void 0;
1313
+ var selectModelClassName = (s3, modelId, offeringId) => modelClassName(s3.modelClassIndex, modelId, offeringId);
1314
+ function selectModelLabelWithClass(s3, modelId, offeringId) {
1315
+ const label = selectModelLabelById(s3, modelId);
1316
+ return label ? withModelClass(label, selectModelClassName(s3, modelId, offeringId)) : void 0;
1317
+ }
1318
+ var selectModelControls = (s3, modelId) => s3.entities[modelId]?.controls;
1319
+ var selectModelFetchType = (s3, modelId) => s3.entities[modelId]?._fetchType;
1320
+ var selectModelFullyLoaded = (s3, modelId) => !!modelId && s3.entities[modelId]?._fetchType === "full";
1321
+ var selectModelDetailError = (s3, modelId) => modelId && s3.detailErrorById[modelId] || null;
1322
+ var selectModelClassConfig = (s3, modelId, offeringId) => modelId && offeringId ? s3.classConfigByOffering[classConfigKey(modelId, offeringId)] : void 0;
1323
+ var selectActiveModelsReady = (s3) => (s3.fetchScope === "active" || s3.fetchScope === "all") && s3.activeIds.length > 0;
1324
+ var selectDeprecatedModelsReady = (s3) => (s3.fetchScope === "deprecated" || s3.fetchScope === "all") && s3.deprecatedIds.length > 0;
1325
+ var selectAllModelsReady = (s3) => s3.fetchScope === "all";
1326
+ var selectModelIdentityById = (s3, modelId) => s3.identityById[modelId];
1327
+ var selectModelIdentityLookupStatus = (s3, modelId) => s3.identityStatusById[modelId] ?? "idle";
1321
1328
 
1322
1329
  // models/catalog/store.ts
1323
1330
  var IDLE = { status: "idle", models: [], error: null, loadedAt: null };
@@ -1592,9 +1599,9 @@ function createModelCatalog(config) {
1592
1599
  };
1593
1600
  },
1594
1601
  load(variant) {
1595
- const s2 = state2[variant];
1596
- if (s2.status === "idle" || s2.status === "error") return run(variant);
1597
- if (s2.status === "ready" && s2.loadedAt !== null && Date.now() - s2.loadedAt > staleAfterMs) return run(variant);
1602
+ const s3 = state2[variant];
1603
+ if (s3.status === "idle" || s3.status === "error") return run(variant);
1604
+ if (s3.status === "ready" && s3.loadedAt !== null && Date.now() - s3.loadedAt > staleAfterMs) return run(variant);
1598
1605
  return inFlight[variant] ?? Promise.resolve();
1599
1606
  },
1600
1607
  reload: (variant) => run(variant)
@@ -1779,9 +1786,9 @@ function placement(v, runtimes, device) {
1779
1786
  }
1780
1787
  return "not_compatible";
1781
1788
  }
1782
- function formatMemoryBytes(n) {
1783
- const g = n / 2 ** 30;
1784
- if (g < 1) return `${Math.max(1, Math.round(n / 2 ** 20))} MB`;
1789
+ function formatMemoryBytes(n2) {
1790
+ const g = n2 / 2 ** 30;
1791
+ if (g < 1) return `${Math.max(1, Math.round(n2 / 2 ** 20))} MB`;
1785
1792
  return `${g < 10 ? Math.round(g * 10) / 10 : Math.round(g)} GB`;
1786
1793
  }
1787
1794
  function describe(c, decided, runnerUp, device) {
@@ -2073,41 +2080,41 @@ var Cursor = class {
2073
2080
  this.read = read;
2074
2081
  this.size = size;
2075
2082
  }
2076
- async need(n) {
2077
- if (this.pos + n > this.size) throw new GgufError("the file ends inside its header");
2078
- if (this.pos + n > MAX_HEADER) throw new GgufError("its header is larger than any real model's");
2079
- if (this.pos >= this.base && this.pos + n <= this.base + this.buf.length) return;
2080
- const len = Math.min(Math.max(n, CHUNK), this.size - this.pos);
2083
+ async need(n2) {
2084
+ if (this.pos + n2 > this.size) throw new GgufError("the file ends inside its header");
2085
+ if (this.pos + n2 > MAX_HEADER) throw new GgufError("its header is larger than any real model's");
2086
+ if (this.pos >= this.base && this.pos + n2 <= this.base + this.buf.length) return;
2087
+ const len = Math.min(Math.max(n2, CHUNK), this.size - this.pos);
2081
2088
  this.buf = await this.read(this.pos, len);
2082
2089
  this.base = this.pos;
2083
- if (this.buf.length < n) throw new GgufError("the file ends inside its header");
2090
+ if (this.buf.length < n2) throw new GgufError("the file ends inside its header");
2084
2091
  }
2085
- async view(n) {
2086
- await this.need(n);
2087
- const v = new DataView(this.buf.buffer, this.buf.byteOffset + (this.pos - this.base), n);
2088
- this.pos += n;
2092
+ async view(n2) {
2093
+ await this.need(n2);
2094
+ const v = new DataView(this.buf.buffer, this.buf.byteOffset + (this.pos - this.base), n2);
2095
+ this.pos += n2;
2089
2096
  return v;
2090
2097
  }
2091
2098
  async u32() {
2092
2099
  return (await this.view(4)).getUint32(0, true);
2093
2100
  }
2094
2101
  async u64() {
2095
- const n = (await this.view(8)).getBigUint64(0, true);
2096
- if (n > BigInt(Number.MAX_SAFE_INTEGER)) throw new GgufError("a size in its header is out of range");
2097
- return Number(n);
2102
+ const n2 = (await this.view(8)).getBigUint64(0, true);
2103
+ if (n2 > BigInt(Number.MAX_SAFE_INTEGER)) throw new GgufError("a size in its header is out of range");
2104
+ return Number(n2);
2098
2105
  }
2099
2106
  async str() {
2100
2107
  const len = await this.u64();
2101
2108
  if (len > MAX_STRING) throw new GgufError("a text value in its header is out of range");
2102
2109
  await this.need(len);
2103
2110
  const at = this.pos - this.base;
2104
- const s2 = new TextDecoder().decode(this.buf.subarray(at, at + len));
2111
+ const s3 = new TextDecoder().decode(this.buf.subarray(at, at + len));
2105
2112
  this.pos += len;
2106
- return s2;
2113
+ return s3;
2107
2114
  }
2108
- async skip(n) {
2109
- if (this.pos + n > this.size) throw new GgufError("the file ends inside its header");
2110
- this.pos += n;
2115
+ async skip(n2) {
2116
+ if (this.pos + n2 > this.size) throw new GgufError("the file ends inside its header");
2117
+ this.pos += n2;
2111
2118
  }
2112
2119
  async scalar(type) {
2113
2120
  switch (type) {
@@ -2159,11 +2166,11 @@ async function readGgufHeader(read, size) {
2159
2166
  const type = await c.u32();
2160
2167
  if (type === 9) {
2161
2168
  const elem = await c.u32();
2162
- const n = await c.u64();
2163
- if (n > 64 * MAX_COUNT) throw new GgufError("an array in its header is out of range");
2164
- arrays[key] = n;
2165
- if (elem === 8) for (let j = 0; j < n; j++) await c.str();
2166
- else if (SCALAR_BYTES[elem] !== void 0) await c.skip(n * SCALAR_BYTES[elem]);
2169
+ const n2 = await c.u64();
2170
+ if (n2 > 64 * MAX_COUNT) throw new GgufError("an array in its header is out of range");
2171
+ arrays[key] = n2;
2172
+ if (elem === 8) for (let j = 0; j < n2; j++) await c.str();
2173
+ else if (SCALAR_BYTES[elem] !== void 0) await c.skip(n2 * SCALAR_BYTES[elem]);
2167
2174
  else throw new GgufError(`its header has an array of unknown type ${elem}`);
2168
2175
  } else kv[key] = await c.scalar(type);
2169
2176
  }
@@ -2193,20 +2200,20 @@ async function readGgufHeader(read, size) {
2193
2200
  return { version, kv, array_lengths: arrays, tensors, data_offset: dataOffset, data_end: end };
2194
2201
  }
2195
2202
  function ggufFacts(h) {
2196
- const s2 = (k) => typeof h.kv[k] === "string" ? h.kv[k] : null;
2197
- const n = (k) => typeof h.kv[k] === "number" ? h.kv[k] : null;
2198
- const arch = s2("general.architecture");
2199
- const ft = n("general.file_type");
2203
+ const s3 = (k) => typeof h.kv[k] === "string" ? h.kv[k] : null;
2204
+ const n2 = (k) => typeof h.kv[k] === "number" ? h.kv[k] : null;
2205
+ const arch = s3("general.architecture");
2206
+ const ft = n2("general.file_type");
2200
2207
  const params = h.tensors.reduce((t, x) => t + x.dims.reduce((a, b) => a * b, 1), 0);
2201
2208
  return {
2202
2209
  architecture: arch,
2203
- name: s2("general.name"),
2210
+ name: s3("general.name"),
2204
2211
  quant: ft !== null ? FILE_TYPE_QUANT[ft] ?? `FTYPE_${ft}` : null,
2205
- context_length: arch ? n(`${arch}.context_length`) : null,
2212
+ context_length: arch ? n2(`${arch}.context_length`) : null,
2206
2213
  parameter_count: params > 0 ? params : null,
2207
- split_count: n("split.count") ?? 1,
2208
- split_index: n("split.no") ?? 0,
2209
- type: s2("general.type"),
2214
+ split_count: n2("split.count") ?? 1,
2215
+ split_index: n2("split.no") ?? 0,
2216
+ type: s3("general.type"),
2210
2217
  has_tokenizer: typeof h.kv["tokenizer.ggml.model"] === "string"
2211
2218
  };
2212
2219
  }
@@ -2247,16 +2254,16 @@ var isHelperGguf = (name) => HELPER_RE.test(name);
2247
2254
  var isProjectorName = (name) => name.toLowerCase().includes("mmproj");
2248
2255
  var quantFromName = (name) => QUANT_RE.exec(name.split("/").pop() ?? name)?.[1]?.toUpperCase() ?? null;
2249
2256
  function splitSetProblems(names) {
2250
- const shards = names.map(shardName).filter((s2) => s2 !== null);
2257
+ const shards = names.map(shardName).filter((s3) => s3 !== null);
2251
2258
  if (!shards.length) return [];
2252
- const counts = [...new Set(shards.map((s2) => s2.count))];
2259
+ const counts = [...new Set(shards.map((s3) => s3.count))];
2253
2260
  if (counts.length !== 1) return [`its parts disagree on how many parts there are (${counts.sort((a, b) => a - b).join(", ")})`];
2254
- const n = counts[0];
2255
- const have = shards.map((s2) => s2.index);
2256
- const missing = Array.from({ length: n }, (_, i) => i + 1).filter((i) => !have.includes(i));
2261
+ const n2 = counts[0];
2262
+ const have = shards.map((s3) => s3.index);
2263
+ const missing = Array.from({ length: n2 }, (_, i) => i + 1).filter((i) => !have.includes(i));
2257
2264
  const dupes = [...new Set(have.filter((i, k) => have.indexOf(i) !== k))].sort((a, b) => a - b);
2258
2265
  const out = [];
2259
- if (missing.length) out.push(`part${missing.length === 1 ? "" : "s"} ${missing.map((i) => `${i} of ${n}`).join(", ")} ${missing.length === 1 ? "is" : "are"} missing`);
2266
+ if (missing.length) out.push(`part${missing.length === 1 ? "" : "s"} ${missing.map((i) => `${i} of ${n2}`).join(", ")} ${missing.length === 1 ? "is" : "are"} missing`);
2260
2267
  if (dupes.length) out.push(`part${dupes.length === 1 ? "" : "s"} ${dupes.join(", ")} appear${dupes.length === 1 ? "s" : ""} twice`);
2261
2268
  return out;
2262
2269
  }
@@ -2300,8 +2307,8 @@ async function validateModelSet(primary, siblings, env) {
2300
2307
  let parts = [primary];
2301
2308
  if (shard) {
2302
2309
  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)}.` };
2303
- const same = [primary, ...siblings.filter((s2) => s2 !== primary && shardName(s2.name)?.stem === shard.stem)];
2304
- const problems = splitSetProblems(same.map((s2) => s2.name));
2310
+ const same = [primary, ...siblings.filter((s3) => s3 !== primary && shardName(s3.name)?.stem === shard.stem)];
2311
+ const problems = splitSetProblems(same.map((s3) => s3.name));
2305
2312
  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).` };
2306
2313
  parts = same.sort((a, b) => (shardName(a.name)?.index ?? 0) - (shardName(b.name)?.index ?? 0));
2307
2314
  }
@@ -2334,7 +2341,7 @@ async function validateModelSet(primary, siblings, env) {
2334
2341
  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?).` };
2335
2342
  }
2336
2343
  const quant = f.quant ?? quantFromName(primary.name) ?? "unknown";
2337
- const projectorFiles = siblings.filter((s2) => s2 !== primary && extOf(s2.name) === ".gguf" && isProjectorName(s2.name));
2344
+ const projectorFiles = siblings.filter((s3) => s3 !== primary && extOf(s3.name) === ".gguf" && isProjectorName(s3.name));
2338
2345
  const pickedName = pickProjector(quant === "unknown" ? null : quant, projectorFiles.map((p) => p.name));
2339
2346
  let projector = null;
2340
2347
  const picked = projectorFiles.find((p) => p.name === pickedName);
@@ -2399,12 +2406,13 @@ async function rows2(client, table) {
2399
2406
  if (error) throw new Error(`ai.${table}: ${error.message}`);
2400
2407
  return (data ?? []).filter(live);
2401
2408
  }
2409
+ var EXCLUDED_REVIEW_STATES = /* @__PURE__ */ new Set(["rejected", "withdrawn"]);
2410
+ var isListedVariant = (v) => live(v) && !EXCLUDED_REVIEW_STATES.has(s(v.review_state));
2402
2411
  function shapeCuratedModels(input) {
2403
2412
  const providerName = new Map(input.providers.map((p) => [s(p.id), sn(p.name)]));
2404
2413
  const presentationOf = new Map(input.presentations.filter(live).map((p) => [s(p.model_id), p]));
2405
2414
  const variantsOf = /* @__PURE__ */ new Map();
2406
- for (const v of input.variants.filter(live)) {
2407
- if (s(v.review_state) === "dismissed") continue;
2415
+ for (const v of input.variants.filter(isListedVariant)) {
2408
2416
  const meta = v.metadata ?? {};
2409
2417
  const list = variantsOf.get(s(v.model_id)) ?? [];
2410
2418
  list.push({
@@ -2437,15 +2445,230 @@ function shapeCuratedModels(input) {
2437
2445
  };
2438
2446
  });
2439
2447
  }
2440
- async function fetchCuratedModels(client) {
2448
+ async function readCuratedRows(client) {
2441
2449
  const [models, variants, presentations, providers] = await Promise.all([
2442
2450
  rows2(client, "model_definition"),
2443
2451
  rows2(client, "model_variant"),
2444
2452
  rows2(client, "model_presentation"),
2445
2453
  rows2(client, "provider")
2446
2454
  ]);
2447
- return shapeCuratedModels({ models, variants, presentations, providers });
2455
+ return { models, variants, presentations, providers };
2456
+ }
2457
+ async function fetchCuratedModels(client) {
2458
+ return shapeCuratedModels(await readCuratedRows(client));
2448
2459
  }
2449
2460
  function curatedList(models, { offeredOnly }) {
2450
2461
  return orderCatalogModels(offeredOnly ? models.filter((m) => m.offered) : models);
2451
2462
  }
2463
+
2464
+ // models/catalog-reader.ts
2465
+ var import_sha256 = require("@ai-matrx/kit/sha256");
2466
+ var MODEL_CATALOG_KINDS = /* @__PURE__ */ new Set([
2467
+ "llm_model",
2468
+ "whisper_model",
2469
+ "tts_model_file",
2470
+ "image_gen_model",
2471
+ "video_gen_model",
2472
+ "ner_model",
2473
+ "wake_word_model",
2474
+ "lora"
2475
+ ]);
2476
+ function catalogKindOf(m, kindOfEntry) {
2477
+ for (const v of m.variants)
2478
+ for (const id of v.catalog_entry_ids ?? []) {
2479
+ const k = kindOfEntry.get(id);
2480
+ if (k && MODEL_CATALOG_KINDS.has(k)) return k;
2481
+ }
2482
+ const out = m.capabilities.output ?? [];
2483
+ const inp = m.capabilities.input ?? [];
2484
+ if (m.presentation?.shelf === "loras") return "lora";
2485
+ if (out.includes("video")) return "video_gen_model";
2486
+ if (out.includes("image")) return "image_gen_model";
2487
+ if (out.includes("audio")) return "tts_model_file";
2488
+ if (inp.includes("audio")) return "whisper_model";
2489
+ if (m.capabilities.interaction === "extraction") return "ner_model";
2490
+ return "llm_model";
2491
+ }
2492
+ function canonicalJson(value) {
2493
+ if (value === void 0) return "null";
2494
+ if (value === null || typeof value !== "object") return JSON.stringify(value) ?? "null";
2495
+ if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
2496
+ const entries = Object.entries(value).filter(([, v]) => v !== void 0).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
2497
+ return `{${entries.map(([k, v]) => `${JSON.stringify(k)}:${canonicalJson(v)}`).join(",")}}`;
2498
+ }
2499
+ function catalogFingerprint(catalog) {
2500
+ const { catalog_fingerprint: _omit, ...rest } = catalog;
2501
+ return (0, import_sha256.sha256Hex)(canonicalJson(rest));
2502
+ }
2503
+ var s2 = (v) => typeof v === "string" ? v : "";
2504
+ var sn2 = (v) => typeof v === "string" ? v : null;
2505
+ var n = (v) => typeof v === "number" && Number.isFinite(v) ? v : typeof v === "string" && v.trim() !== "" && Number.isFinite(Number(v)) ? Number(v) : null;
2506
+ var live2 = (r) => r.deleted_at == null;
2507
+ var byCodepoint2 = (a, b) => a < b ? -1 : a > b ? 1 : 0;
2508
+ var byId = (rows3) => new Map(rows3.map((r) => [s2(r.id), r]));
2509
+ var strings = (v) => Array.isArray(v) ? v.filter((x) => typeof x === "string") : [];
2510
+ async function readModelCatalog(client, opts = {}) {
2511
+ const db = client;
2512
+ const offeredOnly = opts.offeredOnly ?? true;
2513
+ const ai = db.schema("ai");
2514
+ const all = async (table, filter = (q) => q) => {
2515
+ const { data, error } = await filter(ai.from(table).select("*").is("deleted_at", null));
2516
+ if (error) throw new Error(`ai.${table}: ${error.message}`);
2517
+ return (data ?? []).filter(live2);
2518
+ };
2519
+ const [raw, upstreams, runtimes, builds, compat] = await Promise.all([
2520
+ readCuratedRows(client),
2521
+ all("model_upstream"),
2522
+ all("runtime"),
2523
+ all("runtime_build"),
2524
+ all("runtime_compat")
2525
+ ]);
2526
+ const curated = curatedList(shapeCuratedModels(raw), { offeredOnly });
2527
+ const listed = new Set(curated.map((m) => m.id));
2528
+ const variants = raw.variants.filter((v) => listed.has(s2(v.model_id)) && (offeredOnly ? s2(v.review_state) === "offered" : isListedVariant(v)));
2529
+ const entryIds = [...new Set(curated.flatMap((m) => m.variants.flatMap((v) => v.catalog_entry_ids)))].sort(byCodepoint2);
2530
+ const warnings = [];
2531
+ const [artifacts, entries] = await Promise.all([
2532
+ variants.length ? all("model_artifact", (q) => q.in("variant_id", variants.map((v) => s2(v.id)))) : Promise.resolve([]),
2533
+ entryIds.length ? Promise.resolve(db.schema("public").from("catalog_entries").select("id,kind").in("id", entryIds)).then(({ data, error }) => {
2534
+ if (error) {
2535
+ warnings.push(`public.catalog_entries: ${error.message} (models placed by what they do)`);
2536
+ return [];
2537
+ }
2538
+ return data ?? [];
2539
+ }) : Promise.resolve([])
2540
+ ]);
2541
+ const kindOfEntry = new Map(entries.map((e) => [s2(e.id), s2(e.kind)]));
2542
+ const stamps = [];
2543
+ const stamp = (r) => {
2544
+ if (r && typeof r.updated_at === "string") stamps.push(r.updated_at);
2545
+ };
2546
+ const modelById = byId(raw.models);
2547
+ const providerById = byId(raw.providers);
2548
+ const upstreamById = byId(upstreams);
2549
+ const presentationOf = new Map(raw.presentations.map((p) => [s2(p.model_id), p]));
2550
+ const models = curated.flatMap((c) => {
2551
+ const m = modelById.get(c.id);
2552
+ if (!m) return [];
2553
+ stamp(m);
2554
+ const p = presentationOf.get(c.id);
2555
+ stamp(p);
2556
+ const maker = providerById.get(s2(m.provider_id));
2557
+ return [
2558
+ {
2559
+ id: s2(m.id),
2560
+ name: s2(m.name),
2561
+ desktop_id: sn2(m.metadata?.desktop_id),
2562
+ common_name: sn2(m.common_name),
2563
+ maker: sn2(maker?.name),
2564
+ maker_logo_file_id: sn2(maker?.logo_file_id),
2565
+ description: sn2(m.description),
2566
+ capabilities: m.capabilities ?? {},
2567
+ kind: catalogKindOf(c, kindOfEntry),
2568
+ offered: c.offered,
2569
+ updated_at: c.updated_at,
2570
+ presentation: p ? {
2571
+ summary: sn2(p.summary),
2572
+ symbol: sn2(p.symbol),
2573
+ color: sn2(p.color),
2574
+ shelf: sn2(p.shelf),
2575
+ shelf_title: sn2(p.shelf_title),
2576
+ shelf_subtitle: sn2(p.shelf_subtitle),
2577
+ display_order: n(p.display_order),
2578
+ page: sn2(p.page),
2579
+ params_label: sn2(p.params_label),
2580
+ tags: strings(p.tags),
2581
+ links: Array.isArray(p.links) ? p.links : [],
2582
+ thumbnail_file_id: sn2(p.thumbnail_file_id),
2583
+ hero_file_id: sn2(p.hero_file_id),
2584
+ gallery_file_ids: strings(p.gallery_file_ids).filter((f) => f.length > 0),
2585
+ facts: p.facts && typeof p.facts === "object" && !Array.isArray(p.facts) ? p.facts : {}
2586
+ } : null,
2587
+ variants: variants.filter((v) => s2(v.model_id) === c.id).sort((a, b) => byCodepoint2(s2(a.key), s2(b.key))).map((v) => {
2588
+ stamp(v);
2589
+ const up = upstreamById.get(s2(v.upstream_id));
2590
+ stamp(up);
2591
+ const arts = artifacts.filter((a) => s2(a.variant_id) === s2(v.id)).sort((a, b) => (n(a.shard_index) ?? 0) - (n(b.shard_index) ?? 0) || byCodepoint2(s2(a.path_in_repo), s2(b.path_in_repo)));
2592
+ arts.forEach(stamp);
2593
+ return {
2594
+ id: s2(v.id),
2595
+ key: s2(v.key),
2596
+ catalog_key: `${s2(m.name)}/${s2(v.key)}`,
2597
+ review_state: s2(v.review_state),
2598
+ catalog_entry_ids: strings(v.metadata?.catalog_entry_ids),
2599
+ is_default: v.is_default === true,
2600
+ format: s2(v.format),
2601
+ quant: s2(v.quant),
2602
+ architecture: s2(v.architecture),
2603
+ chat_template_kind: s2(v.chat_template_kind),
2604
+ os_arch: strings(v.os_arch),
2605
+ selection_rank: n(v.selection_rank) ?? Number.MAX_SAFE_INTEGER,
2606
+ // internal-bound: a row with no rank sorts last (the column is NOT NULL; this only orders a malformed row)
2607
+ license: sn2(v.license_id),
2608
+ gated: s2(v.gated),
2609
+ total_bytes: n(v.total_bytes),
2610
+ memory_bytes_min: n(v.memory_bytes_min),
2611
+ memory_bytes_recommended: n(v.memory_bytes_recommended),
2612
+ tested_on_current_runtime: v.tested_on_current_runtime === true,
2613
+ min_app_version: sn2(v.min_app_version),
2614
+ upstream: up ? { kind: s2(up.upstream_kind), repo: sn2(up.repo), revision: sn2(up.revision) } : null,
2615
+ artifacts: arts.map((a) => ({
2616
+ role: s2(a.role),
2617
+ path: s2(a.path_in_repo),
2618
+ url: s2(a.url),
2619
+ size_bytes: n(a.size_bytes) ?? 0,
2620
+ sha256: s2(a.sha256),
2621
+ required_for: strings(a.required_for).sort(),
2622
+ shard_index: n(a.shard_index),
2623
+ shard_count: n(a.shard_count)
2624
+ }))
2625
+ };
2626
+ })
2627
+ }
2628
+ ];
2629
+ });
2630
+ const out = {
2631
+ $schema: "matrx.model-catalog.snapshot/v1",
2632
+ catalog_updated_at: "",
2633
+ models,
2634
+ runtimes: runtimes.sort((a, b) => byCodepoint2(s2(a.key), s2(b.key))).map((rt) => {
2635
+ stamp(rt);
2636
+ return {
2637
+ key: s2(rt.key),
2638
+ name: s2(rt.name),
2639
+ upstream_repo: sn2(rt.upstream_repo),
2640
+ builds: builds.filter((b) => s2(b.runtime_id) === s2(rt.id)).map((b) => {
2641
+ stamp(b);
2642
+ const known = b.metadata?.known_architectures;
2643
+ return {
2644
+ id: s2(b.id),
2645
+ version: s2(b.runtime_version),
2646
+ os: s2(b.os),
2647
+ arch: s2(b.arch),
2648
+ accelerator: s2(b.accelerator),
2649
+ build_kind: s2(b.build_kind),
2650
+ url: sn2(b.url),
2651
+ size_bytes: n(b.size_bytes),
2652
+ sha256: sn2(b.sha256),
2653
+ is_active: b.is_active === true,
2654
+ min_app_version: sn2(b.min_app_version),
2655
+ // The architectures this pinned llama-server build loads (runtime_build.metadata): the own-model judge reads it.
2656
+ known_architectures: Array.isArray(known) ? known.map(String).sort() : null,
2657
+ compat: compat.filter((c) => s2(c.runtime_build_id) === s2(b.id)).map((c) => ({
2658
+ hardware_class: s2(c.hardware_class),
2659
+ format: s2(c.format),
2660
+ quant: s2(c.quant),
2661
+ architecture: s2(c.architecture),
2662
+ chat_template_kind: s2(c.chat_template_kind),
2663
+ status: s2(c.status)
2664
+ }))
2665
+ };
2666
+ })
2667
+ };
2668
+ })
2669
+ };
2670
+ out.catalog_updated_at = stamps.sort().at(-1) ?? "";
2671
+ if (warnings.length) out.warnings = warnings;
2672
+ out.catalog_fingerprint = catalogFingerprint(out);
2673
+ return out;
2674
+ }