From 20c349fcdc8bcac2b23fcbca7dd9ad9826c97f22 Mon Sep 17 00:00:00 2001 From: Aqil Aziz Date: Mon, 25 May 2026 23:27:06 +0700 Subject: [PATCH] fix(ai): contain provider setup errors (#2411) Co-authored-by: Steven Enamakel --- .../components/settings/panels/AIPanel.tsx | 1 - .../panels/__tests__/AIPanel.test.tsx | 21 ++++++++++++++++++- app/src/lib/i18n/chunks/de-5.ts | 6 +++--- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/app/src/components/settings/panels/AIPanel.tsx b/app/src/components/settings/panels/AIPanel.tsx index ac4c0fce0..e60f5326f 100644 --- a/app/src/components/settings/panels/AIPanel.tsx +++ b/app/src/components/settings/panels/AIPanel.tsx @@ -760,7 +760,6 @@ const ProviderKeyDialog = ({ ); }; -// ───────────────────────────────────────────────────────────────────────────── // Background loop controls + usage diagnostics // ───────────────────────────────────────────────────────────────────────────── diff --git a/app/src/components/settings/panels/__tests__/AIPanel.test.tsx b/app/src/components/settings/panels/__tests__/AIPanel.test.tsx index 9065c079a..1116bd7f3 100644 --- a/app/src/components/settings/panels/__tests__/AIPanel.test.tsx +++ b/app/src/components/settings/panels/__tests__/AIPanel.test.tsx @@ -38,7 +38,7 @@ vi.mock('../../../../services/api/aiSettingsApi', () => ({ saveAISettings: vi.fn(), loadLocalProviderSnapshot: vi.fn(), testProviderModel: vi.fn(), - setCloudProviderKey: vi.fn(), + setCloudProviderKey: vi.fn().mockResolvedValue(undefined), clearCloudProviderKey: vi.fn().mockResolvedValue(undefined), serializeProviderRef: vi.fn((r: { kind: string; providerSlug?: string; model?: string }) => r.kind === 'openhuman' @@ -356,6 +356,25 @@ describe('AIPanel', () => { expect(screen.getByLabelText(/API key/i)).toBeInTheDocument(); }); + it('surfaces provider setup errors in an alert with technical details collapsed', async () => { + vi.mocked(loadAISettings).mockResolvedValue({ ...baseSettings, cloudProviders: [] }); + vi.mocked(listProviderModels).mockRejectedValueOnce( + new Error('Could not reach OpenAI: provider returned 401 Unauthorized') + ); + + renderWithProviders(); + + fireEvent.click(await screen.findByRole('switch', { name: /Connect OpenAI/i })); + const dialog = await screen.findByRole('dialog', { name: /Connect OpenAI/i }); + fireEvent.change(within(dialog).getByLabelText(/API key/i), { + target: { value: 'sk-bad-key' }, + }); + fireEvent.click(within(dialog).getByRole('button', { name: /^Save$/i })); + + const alert = await within(dialog).findByRole('alert'); + expect(alert).toHaveTextContent(/rejected the credentials/i); + }); + it('clicking the OpenRouter chip shows both API key entry and the OAuth button', async () => { vi.mocked(loadAISettings).mockResolvedValue({ ...baseSettings, cloudProviders: [] }); diff --git a/app/src/lib/i18n/chunks/de-5.ts b/app/src/lib/i18n/chunks/de-5.ts index 2ce85a837..fa6311941 100644 --- a/app/src/lib/i18n/chunks/de-5.ts +++ b/app/src/lib/i18n/chunks/de-5.ts @@ -222,9 +222,9 @@ const de5: TranslationMap = { 'settings.mascot.characterDesc': 'Charakterbeschreibung', 'settings.mascot.characterHeading': 'Zeichenüberschrift', 'settings.mascot.customGifError': - 'Gib eine HTTPS-.gif-URL, eine Loopback-HTTP-.gif-URL, eine file://-.gif-URL oder einen lokalen .gif-Pfad ein.', - 'settings.mascot.customGifHeading': 'Eigener GIF-Avatar', - 'settings.mascot.customGifLabel': 'URL des eigenen GIF-Avatars', + 'GIF konnte nicht geladen werden. Bitte überprüfe die URL und versuche es erneut.', + 'settings.mascot.customGifHeading': 'Benutzerdefinierter GIF-Avatar', + 'settings.mascot.customGifLabel': 'URL für benutzerdefinierten GIF-Avatar', 'settings.mascot.colorDesc': 'Farbbeschreibung', 'settings.mascot.colorHeading': 'Farbüberschrift', 'settings.mascot.loadingLibrary': 'OpenHuman-Bibliothek wird geladen…',