diff --git a/src/app/(dashboard)/dashboard/providers/[id]/page.tsx b/src/app/(dashboard)/dashboard/providers/[id]/page.tsx
index 4724289e0e..a20e14d2e1 100644
--- a/src/app/(dashboard)/dashboard/providers/[id]/page.tsx
+++ b/src/app/(dashboard)/dashboard/providers/[id]/page.tsx
@@ -1542,6 +1542,29 @@ export default function ProviderDetailPage() {
}
};
+ const [clearingModels, setClearingModels] = useState(false);
+ const handleClearAllModels = async () => {
+ if (clearingModels) return;
+ if (!confirm(t("clearAllModelsConfirm"))) return;
+ setClearingModels(true);
+ try {
+ const res = await fetch(
+ `/api/provider-models?provider=${encodeURIComponent(providerStorageAlias)}&all=true`,
+ { method: "DELETE" }
+ );
+ if (res.ok) {
+ await fetchProviderModelMeta();
+ notify.success(t("clearAllModelsSuccess"));
+ } else {
+ notify.error(t("clearAllModelsFailed"));
+ }
+ } catch {
+ notify.error(t("clearAllModelsFailed"));
+ } finally {
+ setClearingModels(false);
+ }
+ };
+
const customMap = useMemo(() => buildCompatMap(modelMeta.customModels), [modelMeta.customModels]);
const overrideMap = useMemo(
() => buildCompatMap(modelMeta.modelCompatOverrides),
@@ -1650,10 +1673,25 @@ export default function ProviderDetailPage() {
);
+ const clearAllButton = modelMeta.customModels.length > 0 && (
+
+ );
+
if (isCompatible) {
return (
-
{autoSyncToggle}
+
+ {autoSyncToggle}
+ {clearAllButton}
+
{autoSyncToggle}
+ {clearAllButton}
{!canImportModels && (
{t("addConnectionToImport")}
)}
diff --git a/src/app/api/provider-models/route.ts b/src/app/api/provider-models/route.ts
index e919e0bf7d..c230d8fcca 100644
--- a/src/app/api/provider-models/route.ts
+++ b/src/app/api/provider-models/route.ts
@@ -3,6 +3,7 @@ import {
getAllCustomModels,
addCustomModel,
removeCustomModel,
+ replaceCustomModels,
updateCustomModel,
getModelCompatOverrides,
mergeModelCompatOverride,
@@ -242,11 +243,30 @@ export async function DELETE(request) {
const provider = searchParams.get("provider");
const modelId = searchParams.get("model");
- if (!provider || !modelId) {
+ if (!provider) {
return Response.json(
{
error: {
- message: "provider and model query params are required",
+ message: "provider query param is required",
+ type: "validation_error",
+ },
+ },
+ { status: 400 }
+ );
+ }
+
+ // DELETE /api/provider-models?provider=&all=true — clear all models
+ const all = searchParams.get("all");
+ if (all === "true") {
+ await replaceCustomModels(provider, []);
+ return Response.json({ cleared: true });
+ }
+
+ if (!modelId) {
+ return Response.json(
+ {
+ error: {
+ message: "model query param is required (or use all=true)",
type: "validation_error",
},
},
diff --git a/src/i18n/messages/en.json b/src/i18n/messages/en.json
index 02083438af..73cd3287b4 100644
--- a/src/i18n/messages/en.json
+++ b/src/i18n/messages/en.json
@@ -1383,6 +1383,10 @@
"autoSyncEnabled": "Auto-sync enabled — models will refresh periodically",
"autoSyncDisabled": "Auto-sync disabled",
"autoSyncToggleFailed": "Failed to toggle auto-sync",
+ "clearAllModels": "Clear All Models",
+ "clearAllModelsConfirm": "Are you sure you want to remove all models for this provider? This cannot be undone.",
+ "clearAllModelsSuccess": "All models cleared",
+ "clearAllModelsFailed": "Failed to clear models",
"addConnectionToImport": "Add a connection to enable importing.",
"noModelsConfigured": "No models configured",
"connectionCount": "{count} connection(s)",
diff --git a/src/i18n/messages/zh-CN.json b/src/i18n/messages/zh-CN.json
index 01d64dc86c..2072515c01 100644
--- a/src/i18n/messages/zh-CN.json
+++ b/src/i18n/messages/zh-CN.json
@@ -1383,6 +1383,10 @@
"autoSyncEnabled": "已启用自动同步 — 模型列表将定期刷新",
"autoSyncDisabled": "已禁用自动同步",
"autoSyncToggleFailed": "切换自动同步失败",
+ "clearAllModels": "清除所有模型",
+ "clearAllModelsConfirm": "确定要删除此提供商的所有模型吗?此操作不可撤销。",
+ "clearAllModelsSuccess": "已清除所有模型",
+ "clearAllModelsFailed": "清除模型失败",
"addConnectionToImport": "添加连接以启用导入。",
"noModelsConfigured": "尚未配置模型",
"connectionCount": "{count} 连接",