fix(wizard): prevent duplicate models at API level

Before adding models, fetch existing provider models and skip
names that already exist. Show error toast for manual add duplicates.
This commit is contained in:
langbot-dev
2026-08-12 02:38:28 +08:00
parent 8b0f2f58b1
commit e82918faef
9 changed files with 32 additions and 3 deletions
+24 -3
View File
@@ -1201,11 +1201,24 @@ function WizardModelScan({
}); });
}; };
const getExistingModelNames = async (): Promise<Set<string>> => {
if (!providerUuid) return new Set();
try {
const resp = await httpClient.getProviderLLMModels(providerUuid);
return new Set((resp.models ?? []).map((m: { name: string }) => m.name));
} catch {
return new Set();
}
};
const handleAddSelected = async () => { const handleAddSelected = async () => {
if (!providerUuid || selectedModels.size === 0) return; if (!providerUuid || selectedModels.size === 0) return;
setAdding(true); setAdding(true);
try { try {
const existing = await getExistingModelNames();
let added = 0;
for (const name of selectedModels) { for (const name of selectedModels) {
if (existing.has(name)) continue;
const model = scannedModels.find((m) => m.name === name); const model = scannedModels.find((m) => m.name === name);
await httpClient.createProviderLLMModel({ await httpClient.createProviderLLMModel({
name, name,
@@ -1215,10 +1228,12 @@ function WizardModelScan({
context_length: model?.context_length ?? null, context_length: model?.context_length ?? null,
extra_args: {}, extra_args: {},
} as never); } as never);
existing.add(name);
added++;
}
if (added > 0) {
toast.success(t('wizard.provider.modelsAdded', { count: added }));
} }
toast.success(
t('wizard.provider.modelsAdded', { count: selectedModels.size }),
);
setAddedModelNames((prev) => { setAddedModelNames((prev) => {
const next = new Set(prev); const next = new Set(prev);
for (const name of selectedModels) next.add(name); for (const name of selectedModels) next.add(name);
@@ -1238,6 +1253,12 @@ function WizardModelScan({
if (!providerUuid || !name) return; if (!providerUuid || !name) return;
setManualAdding(true); setManualAdding(true);
try { try {
const existing = await getExistingModelNames();
if (existing.has(name)) {
toast.error(t('wizard.provider.modelAlreadyExists', { name }));
setManualAdding(false);
return;
}
await httpClient.createProviderLLMModel({ await httpClient.createProviderLLMModel({
name, name,
provider_uuid: providerUuid, provider_uuid: providerUuid,
+1
View File
@@ -1874,6 +1874,7 @@ const enUS = {
addManual: 'Add', addManual: 'Add',
saveAndNext: 'Save & Next', saveAndNext: 'Save & Next',
alreadyAdded: 'Added', alreadyAdded: 'Added',
modelAlreadyExists: 'Model "{{name}}" already exists',
}, },
modelSource: { modelSource: {
title: 'Choose Model Source', title: 'Choose Model Source',
+1
View File
@@ -1732,6 +1732,7 @@ const esES = {
addManual: 'Agregar', addManual: 'Agregar',
saveAndNext: 'Guardar y siguiente', saveAndNext: 'Guardar y siguiente',
alreadyAdded: 'Agregado', alreadyAdded: 'Agregado',
modelAlreadyExists: 'El modelo "{{name}}" ya existe',
}, },
modelSource: { modelSource: {
title: 'Elegir fuente del modelo', title: 'Elegir fuente del modelo',
+1
View File
@@ -1793,6 +1793,7 @@ const jaJP = {
addManual: '追加', addManual: '追加',
saveAndNext: '保存して次へ', saveAndNext: '保存して次へ',
alreadyAdded: '追加済み', alreadyAdded: '追加済み',
modelAlreadyExists: 'モデル「{{name}}」は既に存在します',
}, },
modelSource: { modelSource: {
title: 'モデルソースを選択', title: 'モデルソースを選択',
+1
View File
@@ -1702,6 +1702,7 @@ const ruRU = {
addManual: 'Добавить', addManual: 'Добавить',
saveAndNext: 'Сохранить и далее', saveAndNext: 'Сохранить и далее',
alreadyAdded: 'Добавлено', alreadyAdded: 'Добавлено',
modelAlreadyExists: 'Модель "{{name}}" уже существует',
}, },
modelSource: { modelSource: {
title: 'Выберите источник модели', title: 'Выберите источник модели',
+1
View File
@@ -1666,6 +1666,7 @@ const thTH = {
addManual: 'เพิ่ม', addManual: 'เพิ่ม',
saveAndNext: 'บันทึกและถัดไป', saveAndNext: 'บันทึกและถัดไป',
alreadyAdded: 'เพิ่มแล้ว', alreadyAdded: 'เพิ่มแล้ว',
modelAlreadyExists: 'โมเดล "{{name}}" มีอยู่แล้ว',
}, },
modelSource: { modelSource: {
title: 'เลือกแหล่งโมเดล', title: 'เลือกแหล่งโมเดล',
+1
View File
@@ -1692,6 +1692,7 @@ const viVN = {
addManual: 'Thêm', addManual: 'Thêm',
saveAndNext: 'Lưu & Tiếp theo', saveAndNext: 'Lưu & Tiếp theo',
alreadyAdded: 'Đã thêm', alreadyAdded: 'Đã thêm',
modelAlreadyExists: 'Mô hình "{{name}}" đã tồn tại',
}, },
modelSource: { modelSource: {
title: 'Chọn nguồn mô hình', title: 'Chọn nguồn mô hình',
+1
View File
@@ -1790,6 +1790,7 @@ const zhHans = {
addManual: '添加', addManual: '添加',
saveAndNext: '保存并下一步', saveAndNext: '保存并下一步',
alreadyAdded: '已添加', alreadyAdded: '已添加',
modelAlreadyExists: '模型 "{{name}}" 已存在',
}, },
modelSource: { modelSource: {
title: '选择模型来源', title: '选择模型来源',
+1
View File
@@ -1613,6 +1613,7 @@ const zhHant = {
addManual: '新增', addManual: '新增',
saveAndNext: '儲存並下一步', saveAndNext: '儲存並下一步',
alreadyAdded: '已新增', alreadyAdded: '已新增',
modelAlreadyExists: '模型「{{name}}」已存在',
}, },
modelSource: { modelSource: {
title: '選擇模型來源', title: '選擇模型來源',