@jacobbd/relay-ai 0.4.7 → 0.4.8
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/{chunk-XQCHSU6L.js → chunk-I3SSHXSP.js} +2 -2
- package/dist/{chunk-XQCHSU6L.js.map → chunk-I3SSHXSP.js.map} +1 -1
- package/dist/cli.js +2 -2
- package/dist/ui/public/app.js +49 -10
- package/dist/ui/public/style.css +35 -1
- package/dist/{ui-command-W2W6P6VJ.js → ui-command-P27KHEJG.js} +5 -3
- package/dist/{ui-command-W2W6P6VJ.js.map → ui-command-P27KHEJG.js.map} +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -171,7 +171,7 @@ import {
|
|
|
171
171
|
validateCustomEndpointUrl,
|
|
172
172
|
writeSecureLogLine,
|
|
173
173
|
zenRegistryStub
|
|
174
|
-
} from "./chunk-
|
|
174
|
+
} from "./chunk-I3SSHXSP.js";
|
|
175
175
|
import {
|
|
176
176
|
filterTemplates,
|
|
177
177
|
init_provider_templates,
|
|
@@ -13461,7 +13461,7 @@ Error: ${parsed.error}
|
|
|
13461
13461
|
console.log("Usage: relay-ai ui [--trace]\n\nOpen the settings UI in your browser.");
|
|
13462
13462
|
return 0;
|
|
13463
13463
|
}
|
|
13464
|
-
const { runUiCommand } = await import("./ui-command-
|
|
13464
|
+
const { runUiCommand } = await import("./ui-command-P27KHEJG.js");
|
|
13465
13465
|
return runUiCommand({ trace: parsed.trace });
|
|
13466
13466
|
}
|
|
13467
13467
|
if (parsed.command === "models") {
|
package/dist/ui/public/app.js
CHANGED
|
@@ -2332,10 +2332,14 @@ function renderServerProviderPicker() {
|
|
|
2332
2332
|
const label = p ? p.name : id;
|
|
2333
2333
|
return `<span class="server-provider-chip">${escapeHtml(label)}<button type="button" onclick="toggleServerProvider('${id}')" aria-label="Remove ${escapeHtml(label)}">×</button></span>`;
|
|
2334
2334
|
}).join('');
|
|
2335
|
+
const allFreeNote = s.form.freeModelsOnly && s.form.exposedProviders.length === 0
|
|
2336
|
+
? '<div class="server-field-hint">No providers selected — exposing free models from every available provider.</div>'
|
|
2337
|
+
: '';
|
|
2335
2338
|
|
|
2336
2339
|
return `
|
|
2337
2340
|
<div class="server-providers-picker">
|
|
2338
2341
|
${chips ? `<div class="server-provider-chips">${chips}</div>` : ''}
|
|
2342
|
+
${allFreeNote}
|
|
2339
2343
|
<div class="search-field">
|
|
2340
2344
|
<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>
|
|
2341
2345
|
<input type="search" class="search-input" placeholder="Search providers to expose…" value="${escapeHtml(s.form.providerSearch)}" oninput="setServerProviderSearch(this.value)">
|
|
@@ -2377,13 +2381,27 @@ function renderServerNetworkOptions() {
|
|
|
2377
2381
|
function renderServerSetup(s) {
|
|
2378
2382
|
const f = s.form;
|
|
2379
2383
|
const specific = f.expose === 'specific';
|
|
2380
|
-
const
|
|
2384
|
+
const hasProviders = f.exposedProviders.length > 0;
|
|
2385
|
+
// Free-only with no providers selected = expose free models from every provider
|
|
2386
|
+
// (backend: exposedProviders null + freeModelsOnly). Otherwise require a selection.
|
|
2387
|
+
const providersOk = f.expose === 'favorites'
|
|
2388
|
+
|| (specific && hasProviders)
|
|
2389
|
+
|| (specific && f.freeModelsOnly);
|
|
2381
2390
|
const passwordOk = f.listenMode !== 'network' || f.passwordMode === 'saved' || f.password.trim().length > 0;
|
|
2382
2391
|
const canStart = providersOk && passwordOk && !s.starting;
|
|
2383
2392
|
|
|
2384
2393
|
let hint = '';
|
|
2385
|
-
if (!providersOk)
|
|
2386
|
-
|
|
2394
|
+
if (!providersOk) {
|
|
2395
|
+
hint = f.freeModelsOnly
|
|
2396
|
+
? 'Select at least one provider, or leave none selected to expose free models from all providers.'
|
|
2397
|
+
: 'Select at least one provider to expose.';
|
|
2398
|
+
} else if (!passwordOk) {
|
|
2399
|
+
hint = 'Enter a server password for network mode.';
|
|
2400
|
+
}
|
|
2401
|
+
|
|
2402
|
+
const freeModelsHint = specific
|
|
2403
|
+
? 'With providers selected, only their free models are exposed. With none selected, free models from every available provider are exposed.'
|
|
2404
|
+
: 'Includes verified $0 models and free developer access.';
|
|
2387
2405
|
|
|
2388
2406
|
return `
|
|
2389
2407
|
<div class="server-setup">
|
|
@@ -2405,6 +2423,7 @@ function renderServerSetup(s) {
|
|
|
2405
2423
|
<input type="checkbox" ${f.freeModelsOnly ? 'checked' : ''} onchange="setServerFreeModelsOnly(this.checked)">
|
|
2406
2424
|
<span>Free models only <span class="server-field-hint">(includes verified $0 models and free developer access)</span></span>
|
|
2407
2425
|
</label>
|
|
2426
|
+
<div class="server-field-hint">${escapeHtml(freeModelsHint)}</div>
|
|
2408
2427
|
</div>
|
|
2409
2428
|
|
|
2410
2429
|
<div class="server-field">
|
|
@@ -2475,8 +2494,8 @@ function renderServerRunning(status) {
|
|
|
2475
2494
|
<tr>
|
|
2476
2495
|
<td>${escapeHtml(m.providerLabel)}</td>
|
|
2477
2496
|
<td>${escapeHtml(m.name)}</td>
|
|
2478
|
-
<td
|
|
2479
|
-
<td
|
|
2497
|
+
<td>${serverIdCell(m.anthropicId)}</td>
|
|
2498
|
+
<td>${serverIdCell(m.openaiId)}</td>
|
|
2480
2499
|
</tr>
|
|
2481
2500
|
`).join('');
|
|
2482
2501
|
|
|
@@ -2531,6 +2550,8 @@ function setServerMask(checked) {
|
|
|
2531
2550
|
|
|
2532
2551
|
function setServerFreeModelsOnly(checked) {
|
|
2533
2552
|
state.server.form.freeModelsOnly = checked;
|
|
2553
|
+
state.server.error = null;
|
|
2554
|
+
renderServerPanel();
|
|
2534
2555
|
}
|
|
2535
2556
|
|
|
2536
2557
|
function setServerListenMode(mode) {
|
|
@@ -2561,7 +2582,10 @@ async function submitServerStart() {
|
|
|
2561
2582
|
const body = {
|
|
2562
2583
|
favoritesOnly: f.expose === 'favorites',
|
|
2563
2584
|
freeModelsOnly: f.freeModelsOnly,
|
|
2564
|
-
|
|
2585
|
+
// Empty specific selection + free-only → null (all providers, free filter applied server-side).
|
|
2586
|
+
exposedProviders: f.expose === 'specific' && f.exposedProviders.length > 0
|
|
2587
|
+
? f.exposedProviders
|
|
2588
|
+
: null,
|
|
2565
2589
|
maskGatewayIds: f.maskGatewayIds,
|
|
2566
2590
|
listenMode: f.listenMode,
|
|
2567
2591
|
passwordMode: f.passwordMode,
|
|
@@ -2599,10 +2623,18 @@ async function stopServerGateway() {
|
|
|
2599
2623
|
}
|
|
2600
2624
|
}
|
|
2601
2625
|
|
|
2602
|
-
|
|
2603
|
-
const
|
|
2604
|
-
if (!
|
|
2605
|
-
|
|
2626
|
+
function serverIdCell(id) {
|
|
2627
|
+
const value = String(id ?? '');
|
|
2628
|
+
if (!value) return '<span class="server-id-empty">—</span>';
|
|
2629
|
+
return `
|
|
2630
|
+
<div class="server-id-cell">
|
|
2631
|
+
<code title="${escapeHtml(value)}">${escapeHtml(value)}</code>
|
|
2632
|
+
<button type="button" class="btn btn-ghost btn-sm server-id-copy" onclick='copyPlainText(${JSON.stringify(value)})'>Copy</button>
|
|
2633
|
+
</div>
|
|
2634
|
+
`;
|
|
2635
|
+
}
|
|
2636
|
+
|
|
2637
|
+
async function copyPlainText(text) {
|
|
2606
2638
|
try {
|
|
2607
2639
|
await navigator.clipboard.writeText(text);
|
|
2608
2640
|
showToast('Copied to clipboard');
|
|
@@ -2611,6 +2643,12 @@ async function copyServerValue(id) {
|
|
|
2611
2643
|
}
|
|
2612
2644
|
}
|
|
2613
2645
|
|
|
2646
|
+
async function copyServerValue(id) {
|
|
2647
|
+
const el = document.getElementById(id);
|
|
2648
|
+
if (!el) return;
|
|
2649
|
+
await copyPlainText(el.dataset.value ?? el.textContent);
|
|
2650
|
+
}
|
|
2651
|
+
|
|
2614
2652
|
function toggleServerApiKeyVisibility() {
|
|
2615
2653
|
const el = document.getElementById('server-api-key-value');
|
|
2616
2654
|
if (!el) return;
|
|
@@ -2630,4 +2668,5 @@ window.setServerSavePassword = setServerSavePassword;
|
|
|
2630
2668
|
window.submitServerStart = submitServerStart;
|
|
2631
2669
|
window.stopServerGateway = stopServerGateway;
|
|
2632
2670
|
window.copyServerValue = copyServerValue;
|
|
2671
|
+
window.copyPlainText = copyPlainText;
|
|
2633
2672
|
window.toggleServerApiKeyVisibility = toggleServerApiKeyVisibility;
|
package/dist/ui/public/style.css
CHANGED
|
@@ -401,6 +401,10 @@ input { font-family: inherit; }
|
|
|
401
401
|
max-width: 680px;
|
|
402
402
|
}
|
|
403
403
|
|
|
404
|
+
#server.section {
|
|
405
|
+
max-width: 920px;
|
|
406
|
+
}
|
|
407
|
+
|
|
404
408
|
.section + .section {
|
|
405
409
|
padding-top: 64px;
|
|
406
410
|
margin-top: 12px;
|
|
@@ -1883,6 +1887,7 @@ input { font-family: inherit; }
|
|
|
1883
1887
|
|
|
1884
1888
|
.server-model-table {
|
|
1885
1889
|
width: 100%;
|
|
1890
|
+
table-layout: fixed;
|
|
1886
1891
|
border-collapse: collapse;
|
|
1887
1892
|
font-size: 14px;
|
|
1888
1893
|
}
|
|
@@ -1899,16 +1904,45 @@ input { font-family: inherit; }
|
|
|
1899
1904
|
border-bottom: 1px solid var(--border);
|
|
1900
1905
|
}
|
|
1901
1906
|
|
|
1907
|
+
.server-model-table th:nth-child(1) { width: 18%; }
|
|
1908
|
+
.server-model-table th:nth-child(2) { width: 22%; }
|
|
1909
|
+
.server-model-table th:nth-child(3),
|
|
1910
|
+
.server-model-table th:nth-child(4) { width: 30%; }
|
|
1911
|
+
|
|
1902
1912
|
.server-model-table td {
|
|
1903
1913
|
padding: 9px 14px;
|
|
1904
1914
|
border-bottom: 1px solid var(--border);
|
|
1905
1915
|
color: var(--text-1);
|
|
1916
|
+
vertical-align: middle;
|
|
1917
|
+
overflow: hidden;
|
|
1906
1918
|
}
|
|
1907
1919
|
|
|
1908
1920
|
.server-model-table tr:last-child td { border-bottom: none; }
|
|
1909
1921
|
|
|
1910
|
-
.server-
|
|
1922
|
+
.server-id-cell {
|
|
1923
|
+
display: flex;
|
|
1924
|
+
align-items: center;
|
|
1925
|
+
gap: 8px;
|
|
1926
|
+
min-width: 0;
|
|
1927
|
+
}
|
|
1928
|
+
|
|
1929
|
+
.server-id-cell code {
|
|
1930
|
+
flex: 1;
|
|
1931
|
+
min-width: 0;
|
|
1932
|
+
overflow: hidden;
|
|
1933
|
+
text-overflow: ellipsis;
|
|
1934
|
+
white-space: nowrap;
|
|
1911
1935
|
font-family: 'SF Mono', 'Fira Code', ui-monospace, monospace;
|
|
1912
1936
|
font-size: 12px;
|
|
1913
1937
|
color: var(--text-2);
|
|
1914
1938
|
}
|
|
1939
|
+
|
|
1940
|
+
.server-id-copy {
|
|
1941
|
+
flex-shrink: 0;
|
|
1942
|
+
padding: 3px 8px;
|
|
1943
|
+
font-size: 12px;
|
|
1944
|
+
}
|
|
1945
|
+
|
|
1946
|
+
.server-id-empty {
|
|
1947
|
+
color: var(--text-3);
|
|
1948
|
+
}
|
|
@@ -66,7 +66,7 @@ import {
|
|
|
66
66
|
supportsClaudeTransparentMode,
|
|
67
67
|
validateCustomEndpointUrl,
|
|
68
68
|
writeSecureLogLine
|
|
69
|
-
} from "./chunk-
|
|
69
|
+
} from "./chunk-I3SSHXSP.js";
|
|
70
70
|
import {
|
|
71
71
|
__toCommonJS,
|
|
72
72
|
init_provider_templates,
|
|
@@ -478,7 +478,9 @@ async function doStartGatewayServer(req) {
|
|
|
478
478
|
}
|
|
479
479
|
setServerFavoritesOnly(req.favoritesOnly);
|
|
480
480
|
setServerFreeModelsOnly(req.freeModelsOnly);
|
|
481
|
-
if (req.
|
|
481
|
+
if (!req.favoritesOnly) {
|
|
482
|
+
setServerExposedProviders(req.exposedProviders ?? []);
|
|
483
|
+
}
|
|
482
484
|
setServerMaskGatewayIds(req.maskGatewayIds);
|
|
483
485
|
setServerListenMode(req.listenMode);
|
|
484
486
|
const host = req.listenMode === "network" ? "0.0.0.0" : "127.0.0.1";
|
|
@@ -1487,4 +1489,4 @@ export {
|
|
|
1487
1489
|
resolveUiShutdownDecision,
|
|
1488
1490
|
runUiCommand
|
|
1489
1491
|
};
|
|
1490
|
-
//# sourceMappingURL=ui-command-
|
|
1492
|
+
//# sourceMappingURL=ui-command-P27KHEJG.js.map
|