@jacobbd/relay-ai 0.6.1 → 0.6.2

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/dist/cli.js CHANGED
@@ -167,7 +167,7 @@ import {
167
167
  validateCustomEndpointUrl,
168
168
  writeSecureLogLine,
169
169
  zenRegistryStub
170
- } from "./chunk-P4S42QJK.js";
170
+ } from "./chunk-I3I5LKZI.js";
171
171
  import {
172
172
  filterTemplates,
173
173
  init_provider_templates,
@@ -13599,7 +13599,7 @@ Options:
13599
13599
  --trace Write debug logs under ~/.relay-ai/logs/`);
13600
13600
  return 0;
13601
13601
  }
13602
- const { runUiCommand } = await import("./ui-command-EQJIZRZZ.js");
13602
+ const { runUiCommand } = await import("./ui-command-GNCQS7F7.js");
13603
13603
  return runUiCommand({ trace: parsed.trace, serverMode: parsed.uiServerMode });
13604
13604
  }
13605
13605
  if (parsed.command === "models") {
@@ -41,6 +41,7 @@ const state = {
41
41
  status: null,
42
42
  error: null,
43
43
  starting: false,
44
+ modelSearch: '',
44
45
  form: {
45
46
  seeded: false,
46
47
  expose: 'favorites', // 'favorites' | 'specific'
@@ -2536,15 +2537,6 @@ function renderServerRunning(status) {
2536
2537
  configBits.push(status.maskGatewayIds ? 'Discovery ids masked' : 'Discovery ids raw');
2537
2538
  configBits.push(status.listenMode === 'network' ? 'Network' : 'Local only');
2538
2539
 
2539
- const modelRows = (status.models ?? []).map(m => `
2540
- <tr>
2541
- <td>${escapeHtml(m.providerLabel)}</td>
2542
- <td>${escapeHtml(m.name)}</td>
2543
- <td>${serverIdCell(m.anthropicId)}</td>
2544
- <td>${serverIdCell(m.openaiId)}</td>
2545
- </tr>
2546
- `).join('');
2547
-
2548
2540
  return `
2549
2541
  <div class="server-running">
2550
2542
  <div class="server-status-row">
@@ -2558,16 +2550,63 @@ function renderServerRunning(status) {
2558
2550
  ${urlCards.join('')}
2559
2551
  ${apiKeyCard}
2560
2552
  </div>
2553
+ <div class="server-models-header">
2554
+ <div class="search-field">
2555
+ <svg class="search-icon" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.35-4.35"/></svg>
2556
+ <input type="search" class="search-input" placeholder="Search exposed models…" value="${escapeHtml(state.server.modelSearch)}" oninput="setServerModelSearch(this.value)">
2557
+ </div>
2558
+ <span class="server-models-count" id="server-models-count">${serverModelsCountText()}</span>
2559
+ </div>
2561
2560
  <div class="server-model-table-wrap">
2562
2561
  <table class="server-model-table">
2563
2562
  <thead><tr><th>Provider</th><th>Model</th><th>Anthropic ID</th><th>OpenAI ID</th></tr></thead>
2564
- <tbody>${modelRows || '<tr><td colspan="4" class="fav-empty">No models exposed.</td></tr>'}</tbody>
2563
+ <tbody id="server-model-tbody">${buildServerModelRows()}</tbody>
2565
2564
  </table>
2566
2565
  </div>
2567
2566
  </div>
2568
2567
  `;
2569
2568
  }
2570
2569
 
2570
+ function filteredServerModels() {
2571
+ const models = state.server.status?.models ?? [];
2572
+ const q = state.server.modelSearch.trim().toLowerCase();
2573
+ if (!q) return models;
2574
+ return models.filter(m =>
2575
+ m.providerLabel.toLowerCase().includes(q)
2576
+ || m.name.toLowerCase().includes(q)
2577
+ || m.anthropicId.toLowerCase().includes(q)
2578
+ || m.openaiId.toLowerCase().includes(q)
2579
+ );
2580
+ }
2581
+
2582
+ function buildServerModelRows() {
2583
+ const rows = filteredServerModels().map(m => `
2584
+ <tr>
2585
+ <td>${escapeHtml(m.providerLabel)}</td>
2586
+ <td>${escapeHtml(m.name)}</td>
2587
+ <td>${serverIdCell(m.anthropicId)}</td>
2588
+ <td>${serverIdCell(m.openaiId)}</td>
2589
+ </tr>
2590
+ `).join('');
2591
+ const total = state.server.status?.models?.length ?? 0;
2592
+ if (rows) return rows;
2593
+ return `<tr><td colspan="4" class="fav-empty">${total === 0 ? 'No models exposed.' : 'No models match your search.'}</td></tr>`;
2594
+ }
2595
+
2596
+ function serverModelsCountText() {
2597
+ const total = state.server.status?.models?.length ?? 0;
2598
+ const shown = filteredServerModels().length;
2599
+ return shown === total ? `${total} model${total !== 1 ? 's' : ''}` : `Showing ${shown} of ${total} models`;
2600
+ }
2601
+
2602
+ function setServerModelSearch(value) {
2603
+ state.server.modelSearch = value;
2604
+ const tbody = document.getElementById('server-model-tbody');
2605
+ if (tbody) tbody.innerHTML = buildServerModelRows();
2606
+ const count = document.getElementById('server-models-count');
2607
+ if (count) count.textContent = serverModelsCountText();
2608
+ }
2609
+
2571
2610
  function setServerExpose(mode) {
2572
2611
  state.server.form.expose = mode;
2573
2612
  state.server.error = null;
@@ -2711,6 +2750,7 @@ function toggleServerApiKeyVisibility() {
2711
2750
  window.setServerExpose = setServerExpose;
2712
2751
  window.toggleServerProvider = toggleServerProvider;
2713
2752
  window.setServerProviderSearch = setServerProviderSearch;
2753
+ window.setServerModelSearch = setServerModelSearch;
2714
2754
  window.setServerMask = setServerMask;
2715
2755
  window.setServerFreeModelsOnly = setServerFreeModelsOnly;
2716
2756
  window.setServerListenMode = setServerListenMode;
@@ -2026,6 +2026,21 @@ input { font-family: inherit; }
2026
2026
 
2027
2027
  .url-card-value.masked { letter-spacing: 0.15em; }
2028
2028
 
2029
+ .server-models-header {
2030
+ display: flex;
2031
+ align-items: center;
2032
+ gap: 12px;
2033
+ margin-top: 8px;
2034
+ }
2035
+
2036
+ .server-models-header .search-field { flex: 1; }
2037
+
2038
+ .server-models-count {
2039
+ font-size: 14px;
2040
+ color: var(--text-3);
2041
+ white-space: nowrap;
2042
+ }
2043
+
2029
2044
  .server-model-table-wrap {
2030
2045
  border: 1px solid var(--border);
2031
2046
  border-radius: var(--radius-sm);
@@ -27,6 +27,7 @@ import {
27
27
  getAppPathOverride,
28
28
  getEnvServerPassword,
29
29
  getSavedServerPassword,
30
+ getServerDebugLogPath,
30
31
  getServerExposedProviders,
31
32
  getServerFavoritesOnly,
32
33
  getServerFreeModelsOnly,
@@ -40,6 +41,7 @@ import {
40
41
  loadServerModels,
41
42
  makeTraceLogger,
42
43
  openAiDeviceCodeUrl,
44
+ openAiIdCollisions,
43
45
  pollGithubDeviceCodeToken,
44
46
  pollOpenAiDeviceCodeToken,
45
47
  pollXaiDeviceCodeToken,
@@ -72,7 +74,7 @@ import {
72
74
  supportsClaudeTransparentMode,
73
75
  validateCustomEndpointUrl,
74
76
  writeSecureLogLine
75
- } from "./chunk-P4S42QJK.js";
77
+ } from "./chunk-I3I5LKZI.js";
76
78
  import {
77
79
  __toCommonJS,
78
80
  init_provider_templates,
@@ -379,9 +381,10 @@ function buildModelRows(models, gateway) {
379
381
  if (list) list.push(model);
380
382
  else groups.set(label, [model]);
381
383
  }
384
+ const collisions = openAiIdCollisions(models);
382
385
  const rows = [];
383
386
  for (const [providerLabel, groupModels] of groups) {
384
- for (const row of buildDedupedModelRows(groupModels, gateway)) rows.push({ providerLabel, ...row });
387
+ for (const row of buildDedupedModelRows(groupModels, gateway, collisions)) rows.push({ providerLabel, ...row });
385
388
  }
386
389
  return rows.sort((a, b) => a.providerLabel.localeCompare(b.providerLabel) || a.name.localeCompare(b.name));
387
390
  }
@@ -516,7 +519,8 @@ async function doStartGatewayServer(req, opts) {
516
519
  serverPassword,
517
520
  catalog: createGatewayModelCatalog(models, gateway),
518
521
  backends: BACKENDS,
519
- gateway
522
+ gateway,
523
+ debugLogPath: getServerDebugLogPath()
520
524
  });
521
525
  } catch (err) {
522
526
  const code = err?.code;
@@ -1578,4 +1582,4 @@ export {
1578
1582
  resolveUiShutdownDecision,
1579
1583
  runUiCommand
1580
1584
  };
1581
- //# sourceMappingURL=ui-command-EQJIZRZZ.js.map
1585
+ //# sourceMappingURL=ui-command-GNCQS7F7.js.map