diff --git a/app/api/custom-provider/route.ts b/app/api/custom-provider/route.ts index 5439fb9..05becc5 100644 --- a/app/api/custom-provider/route.ts +++ b/app/api/custom-provider/route.ts @@ -5,6 +5,8 @@ * fast), store the key, persist { baseUrl, models }, re-sync the * provider into piModels(). Discovery lives here because connecting * and discovering are one user action. + * DELETE → disconnect: drop the stored config + the stored key and unregister + * the provider (the mirror image of POST; idempotent). */ import { deleteKey, @@ -56,3 +58,15 @@ export async function POST(request: Request) { syncCustomProvider(next.customProvider); return Response.json({ ok: true, models: next.customProvider?.models ?? [] }); } + +/** Disconnect: forget the endpoint AND its key, then unregister the provider. + * Deleting the section (rather than blanking baseUrl) keeps settings.json the + * same shape as a never-connected install. Idempotent by construction. */ +export async function DELETE() { + const record = readSettingsRecord() ?? { version: 1 }; + const { customProvider: _dropped, ...rest } = record; + const next = writeSettingsRecord(rest); + deleteKey(CUSTOM_PROVIDER.envVar); + syncCustomProvider(next.customProvider); + return Response.json({ ok: true }); +} diff --git a/components/settings/keys-section.tsx b/components/settings/keys-section.tsx index fb8e7f2..8b28ad3 100644 --- a/components/settings/keys-section.tsx +++ b/components/settings/keys-section.tsx @@ -444,6 +444,15 @@ export function KeysSection({ notifySettingsSaved("keys"); } + /** Forget the custom endpoint (config + key server-side), same rhythm as + * deleteKey: fire, re-read, broadcast so the catalog narrows everywhere. */ + async function disconnectCustom(): Promise { + await fetch("/api/custom-provider", { method: "DELETE" }).catch(() => undefined); + setAddingCustom(false); + await reload(); + notifySettingsSaved("keys"); + } + if (loading || statuses === null) { return

Loading keys…

; } @@ -496,6 +505,7 @@ export function KeysSection({ await reload(); notifySettingsSaved("keys"); }} + onDelete={disconnectCustom} onCancel={() => setAddingCustom(false)} /> )} @@ -660,11 +670,13 @@ function CustomEndpointEditor({ keyPresent, onSaved, onCancel, + onDelete, }: { baseUrl0: string; keyPresent: boolean; onSaved: () => void | Promise; onCancel: () => void; + onDelete?: () => void | Promise; }) { const [baseUrl, setBaseUrl] = useState(baseUrl0); const [key, setKey] = useState(""); @@ -742,6 +754,20 @@ function CustomEndpointEditor({ > Cancel + {/* Disconnect rides beside Connect, exactly the stored-key rows' Delete: + quiet text, one click, no confirm — and only once there IS an + endpoint (a fresh add has nothing to delete). */} + {onDelete && baseUrl0.trim() && ( + + )} {needsKey && (