models: dedupe endpoints by base_url on create (#266)

POST /api/model-endpoints always inserted a new row, so Settings -> Add
Models -> Scan for Servers re-added any endpoint a user had already
registered manually — once under its model name (from the earlier
manual add) and again under its host:port (auto-generated when scan
posts without a name). The success toast then misreported the result
as "added N new".

Look up an existing endpoint with the same base_url accessible to the
caller (shared or owned by them) before inserting. If found, return it
with `existing: true` so the client can tell the difference between
an actual add and a dedupe hit. Toast now reads, e.g.,
"Found 1 server with 1 model — 1 already added".

Tested: POSTing the same base_url three times (incl. trailing-slash
variation) returns the same id each time; only one row exists.
This commit is contained in:
Sirsyorrz
2026-06-01 15:22:06 +10:00
committed by GitHub
parent 5c142ec34a
commit 09acf955f1
2 changed files with 40 additions and 4 deletions
+12 -4
View File
@@ -952,8 +952,10 @@ function initEndpointForm() {
msg.textContent = 'No model servers found. Make sure vLLM, llama.cpp, SGLang, or Ollama is running. Docker users may need OLLAMA_HOST=0.0.0.0:11434.';
msg.className = 'admin-error';
} else {
// Auto-add each discovered endpoint
// Auto-add each discovered endpoint. Server dedupes on base_url
// and returns `existing: true` for already-registered ones.
let added = 0;
let skipped = 0;
for (const item of items) {
const base = item.url.replace('/chat/completions', '').replace(/\/$/, '');
const fd = new FormData();
@@ -961,12 +963,18 @@ function initEndpointForm() {
fd.append('skip_probe', 'false');
const r = await fetch('/api/model-endpoints', { method: 'POST', body: fd });
if (r.ok) {
added++;
try { const dd = await r.json(); if (dd && dd.id) _recentlyAddedEpId = String(dd.id); } catch (_) {}
try {
const dd = await r.json();
if (dd && dd.existing) { skipped++; }
else { added++; if (dd && dd.id) _recentlyAddedEpId = String(dd.id); }
} catch (_) { added++; }
}
}
const totalModels = items.reduce((n, i) => n + (i.models ? i.models.length : 0), 0);
msg.innerHTML = `Found ${items.length} server${items.length !== 1 ? 's' : ''} with ${totalModels} model${totalModels !== 1 ? 's' : ''}` + (added ? ` — added ${added} new` : ' (already added)');
const parts = [`Found ${items.length} server${items.length !== 1 ? 's' : ''} with ${totalModels} model${totalModels !== 1 ? 's' : ''}`];
if (added) parts.push(`added ${added} new`);
if (skipped) parts.push(`${skipped} already added`);
msg.innerHTML = parts.join(' — ');
msg.className = 'admin-success';
loadEndpoints();
}