((cfg.apiKey as string) ?? '');
@@ -30,6 +30,18 @@ export function useLlmParsingConfig(addon: Addon) {
const [pullPct, setPullPct] = useState(0);
const [pullStatus, setPullStatus] = useState('');
+ /**
+ * A different provider never inherits the last one's endpoint: an Ollama address
+ * left in the field would quietly receive the OpenAI or Anthropic key. Back on the
+ * saved provider, its saved address returns. Any provider, Anthropic included, may
+ * keep an address the admin typed for it (#2655); empty means the provider default.
+ */
+ const setProvider = (next: string) => {
+ if (next !== provider) setBaseUrl(next === cfg.provider ? ((cfg.baseUrl as string) ?? '') : '');
+ setProviderState(next);
+ };
+ const baseUrlPlaceholder = LLM_BASE_URL_PLACEHOLDER[provider] ?? LLM_BASE_URL_PLACEHOLDER.openai;
+
const effectiveUrl = baseUrl.trim() || DEFAULT_OLLAMA_URL;
const isInstalled = (id: string) => installed.some((n) => n === id || n.startsWith(id + ':') || n.startsWith(id));
@@ -89,7 +101,7 @@ export function useLlmParsingConfig(addon: Addon) {
config: {
provider,
model: model.trim(),
- baseUrl: provider === 'anthropic' ? '' : baseUrl.trim(),
+ baseUrl: baseUrl.trim(),
apiKey,
vision,
},
@@ -109,6 +121,7 @@ export function useLlmParsingConfig(addon: Addon) {
setModel,
baseUrl,
setBaseUrl,
+ baseUrlPlaceholder,
apiKey,
setApiKey,
vision,
diff --git a/client/src/mobile/screens/admin/MAdminAddonManager.tsx b/client/src/mobile/screens/admin/MAdminAddonManager.tsx
index 4e161f5b5..387441c24 100644
--- a/client/src/mobile/screens/admin/MAdminAddonManager.tsx
+++ b/client/src/mobile/screens/admin/MAdminAddonManager.tsx
@@ -14,6 +14,7 @@ import {
type Addon,
type CollabFeatures,
type ProviderOption,
+ ANTHROPIC_HINT,
COLLAB_SUB_FEATURES,
getAddonLabel,
MASKED,
@@ -255,7 +256,7 @@ function MSubRow({ icon: Icon, providerIcon: ProviderIcon, title, subtitle, enab
function LlmParsingConfig({ addon }: { addon: Addon }) {
const { t } = useTranslation()
const {
- provider, setProvider, model, setModel, baseUrl, setBaseUrl, apiKey, setApiKey, vision, setVision, saving,
+ provider, setProvider, model, setModel, baseUrl, setBaseUrl, baseUrlPlaceholder, apiKey, setApiKey, vision, setVision, saving,
installed, modelsErr, loadingModels, pulling, pullPct, pullStatus, isInstalled, loadModels, pull, save,
} = useLlmParsingConfig(addon)
@@ -302,18 +303,16 @@ function LlmParsingConfig({ addon }: { addon: Addon }) {
})}
- {provider !== 'anthropic' && (
-
- setBaseUrl(e.target.value)}
- onBlur={loadModels}
- placeholder={provider === 'local' ? 'http://localhost:11434/v1' : 'https://api.openai.com/v1'}
- />
-
- )}
+
+ setBaseUrl(e.target.value)}
+ onBlur={loadModels}
+ placeholder={baseUrlPlaceholder}
+ />
+
{provider === 'anthropic' && (
-
- Anthropic reads PDFs (including scans) natively. Local/OpenAI models receive extracted text — scanned PDFs need Anthropic.
-
+ {ANTHROPIC_HINT}
)}
diff --git a/client/tests/unit/mobile/admin/MAdminAddonManager.test.tsx b/client/tests/unit/mobile/admin/MAdminAddonManager.test.tsx
index d586b9ff4..b06d5f98b 100644
--- a/client/tests/unit/mobile/admin/MAdminAddonManager.test.tsx
+++ b/client/tests/unit/mobile/admin/MAdminAddonManager.test.tsx
@@ -574,6 +574,7 @@ describe('MAdminAddonManager', () => {
await user.click(screen.getByRole('button', { name: 'Anthropic' }));
expect(screen.queryByPlaceholderText('https://api.openai.com/v1')).not.toBeInTheDocument();
+ expect(screen.getByPlaceholderText('https://api.anthropic.com')).toHaveValue('');
expect(screen.getByPlaceholderText('claude-opus-4-8')).toBeInTheDocument();
expect(screen.getByText(/Anthropic reads PDFs/)).toBeInTheDocument();
});