@shop-os/modelkit 0.2.3 → 0.2.5

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 CHANGED
@@ -9,6 +9,16 @@ header in the release PR.
9
9
 
10
10
  ## [Unreleased]
11
11
 
12
+ ## [0.2.5] - 2026-09-15
13
+
14
+ ### Changed
15
+ - `Catalog.list()` returns rows in picker order: `display.sortOrder` descending, rows without one after the ordered ones, then `label` ascending (case-insensitive), then `id`. pro-backend orders its query the same way. Before, the order was the insertion order of the primed rows (pro-backend heap order), so an edited row moved to the end of every picker. `compareCatalogOrder` and `sortCatalogRows` are exported from the root and `/catalog` entries for consumers that sort their own lists.
16
+
17
+ ## [0.2.4] - 2026-09-15
18
+
19
+ ### Fixed
20
+ - Catalog prime and fallback log lines carry origin, row count, revision and the error in the message string. pino-style loggers dropped the trailing object argument, so services such as template-service logged no origin.
21
+
12
22
  ## [0.2.3] - 2026-09-15
13
23
 
14
24
  ### Changed
package/dist/catalog.cjs CHANGED
@@ -30,6 +30,7 @@ __export(catalog_entry_exports, {
30
30
  OTHER_MODELS: () => OTHER_MODELS,
31
31
  TEXT_MODELS: () => TEXT_MODELS,
32
32
  VIDEO_MODELS: () => VIDEO_MODELS,
33
+ compareCatalogOrder: () => compareCatalogOrder,
33
34
  isModelKitError: () => isModelKitError,
34
35
  liveCatalog: () => liveCatalog,
35
36
  liveState: () => liveState,
@@ -39,7 +40,8 @@ __export(catalog_entry_exports, {
39
40
  resolveAudioOptions: () => resolveAudioOptions,
40
41
  resolveImageOptions: () => resolveImageOptions,
41
42
  resolveOptions: () => resolveOptions,
42
- resolveVideoOptions: () => resolveVideoOptions
43
+ resolveVideoOptions: () => resolveVideoOptions,
44
+ sortCatalogRows: () => sortCatalogRows
43
45
  });
44
46
  module.exports = __toCommonJS(catalog_entry_exports);
45
47
 
@@ -69,6 +71,22 @@ function isModelKitError(err) {
69
71
  return err instanceof ModelKitError;
70
72
  }
71
73
 
74
+ // src/catalog/order.ts
75
+ function compareCatalogOrder(a, b) {
76
+ const sa = a.display?.sortOrder;
77
+ const sb = b.display?.sortOrder;
78
+ if (sa !== void 0 && sb !== void 0 && sa !== sb) return sb - sa;
79
+ if (sa !== void 0 && sb === void 0) return -1;
80
+ if (sa === void 0 && sb !== void 0) return 1;
81
+ return compareText(a.label.toLowerCase(), b.label.toLowerCase()) || compareText(a.id, b.id);
82
+ }
83
+ function compareText(a, b) {
84
+ return a < b ? -1 : a > b ? 1 : 0;
85
+ }
86
+ function sortCatalogRows(rows) {
87
+ return [...rows].sort(compareCatalogOrder);
88
+ }
89
+
72
90
  // src/catalog/registry.ts
73
91
  var Catalog = class _Catalog {
74
92
  byId = /* @__PURE__ */ new Map();
@@ -125,11 +143,12 @@ var Catalog = class _Catalog {
125
143
  }
126
144
  return model;
127
145
  }
146
+ /** Rows in picker order: `display.sortOrder` descending, then label. See `compareCatalogOrder`. */
128
147
  list(filter = {}) {
129
148
  const lifecycles = filter.lifecycle ?? ["active"];
130
149
  return [...this.byId.values()].filter(
131
150
  (m) => (filter.type ? m.type === filter.type : true) && lifecycles.includes(m.lifecycle)
132
- );
151
+ ).sort(compareCatalogOrder);
133
152
  }
134
153
  /** Merge rows by id. Used for catalogOverride. */
135
154
  withOverrides(rows) {
@@ -306,7 +325,6 @@ var IMAGE_MODELS = [
306
325
  pricingKind: "image_size",
307
326
  display: {
308
327
  provider: "openai",
309
- sortOrder: 20,
310
328
  description: "OpenAI's most capable GPT Image 2.5 tier, built for editing precision; takes text and image input and outputs images in low, medium, high, xhigh, or max quality."
311
329
  }
312
330
  },
@@ -341,7 +359,6 @@ var IMAGE_MODELS = [
341
359
  pricingKind: "image_size",
342
360
  display: {
343
361
  provider: "openai",
344
- sortOrder: 10,
345
362
  description: "OpenAI's fastest GPT Image 2.5 tier for high-quality everyday image generation and editing; takes text and image input and outputs images."
346
363
  }
347
364
  },
@@ -2099,13 +2116,14 @@ function toEnvelope(data) {
2099
2116
  if (data.revision !== void 0) envelope.revision = data.revision;
2100
2117
  return envelope;
2101
2118
  }
2119
+ function describeError(err) {
2120
+ return err instanceof Error ? err.message : String(err);
2121
+ }
2102
2122
  function logPrimed(logger, result) {
2103
- const { origin: loggedOrigin, rowCount: loggedCount, revision: loggedRevision } = result;
2104
- logger.info("[modelkit] catalog primed", {
2105
- origin: loggedOrigin,
2106
- rowCount: loggedCount,
2107
- revision: loggedRevision
2108
- });
2123
+ const revision = result.revision === void 0 ? "" : ` revision=${result.revision}`;
2124
+ logger.info(
2125
+ `[modelkit] catalog primed origin=${result.origin} rowCount=${result.rowCount}${revision}`
2126
+ );
2109
2127
  }
2110
2128
  async function fetchRemote(source, logger) {
2111
2129
  const fetchImpl = source.fetch ?? globalThis.fetch;
@@ -2129,7 +2147,7 @@ async function writeCache(source, logger, rows, rev) {
2129
2147
  try {
2130
2148
  await source.cache.set(JSON.stringify({ rows, revision: rev }));
2131
2149
  } catch (err) {
2132
- logger.warn("[modelkit] catalog cache write failed", err);
2150
+ logger.warn(`[modelkit] catalog cache write failed: ${describeError(err)}`);
2133
2151
  }
2134
2152
  }
2135
2153
  async function prime(source, logger) {
@@ -2150,8 +2168,8 @@ async function prime(source, logger) {
2150
2168
  logPrimed(logger, result);
2151
2169
  return result;
2152
2170
  } catch (err) {
2153
- logger.warn("[modelkit] catalog remote failed, trying cache", err);
2154
- const error = err instanceof Error ? err.message : String(err);
2171
+ logger.warn(`[modelkit] catalog remote failed, trying cache: ${describeError(err)}`);
2172
+ const error = describeError(err);
2155
2173
  try {
2156
2174
  const cached = await source.cache?.get();
2157
2175
  if (!cached) throw new Error("no cached catalog");
@@ -2170,7 +2188,9 @@ async function prime(source, logger) {
2170
2188
  logPrimed(logger, result);
2171
2189
  return result;
2172
2190
  } catch (cacheErr) {
2173
- logger.warn("[modelkit] catalog cache failed, using snapshot", cacheErr);
2191
+ logger.warn(
2192
+ `[modelkit] catalog cache failed, using snapshot: ${describeError(cacheErr)}`
2193
+ );
2174
2194
  liveCatalog.replace([...MODELS]);
2175
2195
  liveState.origin = "snapshot";
2176
2196
  liveState.revision = void 0;
@@ -2193,7 +2213,9 @@ async function refresh(source, logger) {
2193
2213
  liveState.revision = fetched.revision;
2194
2214
  await writeCache(source, logger, fetched.rows, fetched.revision);
2195
2215
  } catch (err) {
2196
- logger.warn("[modelkit] catalog refresh failed, keeping current rows", err);
2216
+ logger.warn(
2217
+ `[modelkit] catalog refresh failed, keeping current rows: ${describeError(err)}`
2218
+ );
2197
2219
  }
2198
2220
  }
2199
2221
  function primeCatalog(source) {