diff --git a/client/src/components/Admin/AddonManager.test.tsx b/client/src/components/Admin/AddonManager.test.tsx index 6f13fcf7d..cfffacead 100644 --- a/client/src/components/Admin/AddonManager.test.tsx +++ b/client/src/components/Admin/AddonManager.test.tsx @@ -560,6 +560,34 @@ describe('AddonManager', () => { }); }); + it('FE-ADMIN-ADDON-029: switching to Anthropic clears a stale base URL before saving', async () => { + const user = userEvent.setup(); + const bodies: unknown[] = []; + server.use( + addonsRoute([llmAddon({ provider: 'local', model: '', baseUrl: 'http://ollama.lan:11434/v1', apiKey: '', multimodal: false })]), + modelsRoute([]), + http.put('/api/admin/addons/llm_parsing', async ({ request }) => { + bodies.push(await request.json()); + return HttpResponse.json({ success: true }); + }), + ); + render(<>); + + await screen.findByText('Installed on the server'); + + await user.click(screen.getByRole('button', { name: /Local · OpenAI-compatible/ })); + await user.click(screen.getByRole('button', { name: 'Anthropic' })); + await user.type(screen.getByPlaceholderText('claude-opus-4-8'), 'claude-haiku-4-5-20251001'); + await user.type(screen.getByPlaceholderText('sk-…'), 'sk-ant-live'); + + await user.click(screen.getByRole('button', { name: 'Save' })); + await screen.findByText('Saved'); + // The stale local base URL must not ride along to Anthropic — it would hijack the endpoint. + expect(bodies[0]).toEqual({ + config: { provider: 'anthropic', model: 'claude-haiku-4-5-20251001', baseUrl: '', apiKey: 'sk-ant-live', multimodal: false }, + }); + }); + it('FE-ADMIN-ADDON-027: an error frame in the pull stream aborts the pull and is reported', async () => { const user = userEvent.setup(); server.use( diff --git a/client/src/components/Admin/AddonManager.tsx b/client/src/components/Admin/AddonManager.tsx index 1c658ee11..99b9c84d8 100644 --- a/client/src/components/Admin/AddonManager.tsx +++ b/client/src/components/Admin/AddonManager.tsx @@ -399,7 +399,7 @@ function LlmParsingConfig({ addon }: { addon: Addon }) { setSaving(true) try { // Send the masked sentinel unchanged so the server keeps the stored key. - await adminApi.updateAddon(addon.id, { config: { provider, model: model.trim(), baseUrl: baseUrl.trim(), apiKey, multimodal: cfg.multimodal === true } }) + await adminApi.updateAddon(addon.id, { config: { provider, model: model.trim(), baseUrl: provider === 'anthropic' ? '' : baseUrl.trim(), apiKey, multimodal: cfg.multimodal === true } }) toast.success('Saved') } catch { toast.error('Failed to save')