Skip to main content

Adding a New Provider

Adding an AI provider involves configuring several fields to establish a connection to the AI service.

Step-by-Step Process

1

Open the Provider Form

Click the + button in the Configured Providers section of the plugin settings.
// From settings.ts:176-179
.addButton(button => {
    const addButton = button
        .setIcon('plus')
        .setTooltip(I18n.t('settings.addProvider'))
        .onClick(() => {
            if (this.isFormOpen) return;
            this.openForm(true);
        });
});
2

Select Provider Type

Choose your AI service from the dropdown. The plugin provides pre-configured defaults for each type:
// Provider configurations from ProviderFormModal.ts:26-108
const PROVIDER_CONFIGS: Record<AIProviderType, ProviderConfig> = {
    openai: {
        url: 'https://api.openai.com/v1',
        name: 'OpenAI',
    },
    anthropic: {
        url: 'https://api.anthropic.com',
        name: 'Anthropic',
    },
    ollama: {
        url: 'http://localhost:11434',
        name: 'Ollama',
    },
    gemini: {
        url: 'https://generativelanguage.googleapis.com/v1beta/openai',
        name: 'Google Gemini',
    },
    // ... and 15 more providers
};
When you select a type, the Name and URL fields automatically populate with sensible defaults.
3

Configure Provider Name

The name field is pre-filled based on the provider type, but you can customize it:
  • Must be unique across all providers
  • Cannot be empty or whitespace-only
  • Automatically trimmed when saved
Use descriptive names if you have multiple providers of the same type (e.g., “OpenAI GPT-4”, “OpenAI GPT-3.5”).
4

Set API Endpoint URL

The URL field is auto-filled with the default endpoint for your provider type. You can modify it for:
  • Custom endpoints
  • Self-hosted services
  • Proxy servers
  • Regional endpoints
Local providers (like Ollama, LM Studio) use localhost URLs. Ensure the service is running before testing.
5

Enter API Key

Paste your API key from the provider’s dashboard. The field has special behavior:
// From ProviderFormModal.ts:545-551
text.inputEl.type = 'password';
text.inputEl.addEventListener('focus', () => {
    text.inputEl.type = 'text';
});
text.inputEl.addEventListener('blur', () => {
    text.inputEl.type = 'password';
});
  • Displayed as password (hidden characters)
  • Reveals text when focused
  • Returns to hidden when unfocused
Local providers (Ollama, LM Studio) typically don’t require an API key.
6

Select a Model

The model field behavior depends on the provider type:Providers with automatic model fetching:
  • Desktop: Searchable combobox with fuzzy search
  • Mobile: Standard dropdown
Providers without model fetching (e.g., 302.AI):
  • Simple text input
  • Manually enter the model name
// From ProviderFormModal.ts:260-262
private hasModelFetching(type: AIProviderType): boolean {
    const config = PROVIDER_CONFIGS[type];
    return config.options?.modelsFetching !== false;
}
7

Save Configuration

Click the Save button. The plugin will:
  1. Validate the provider name (non-empty and unique)
  2. Add or update the provider in settings
  3. Persist to disk
  4. Close the form
If validation fails, you’ll see an error notice.

Smart Defaults Behavior

The form intelligently manages field updates when you change the provider type:
// From ProviderFormModal.ts:586-622
private changeProviderType(newType: AIProviderType) {
    const currentDefaultName = this.getDefaultName(this.provider.type);
    const currentDefaultUrl = PROVIDER_CONFIGS[this.provider.type].url;

    // Update provider properties
    this.provider.type = newType;
    this.provider.availableModels = undefined;
    this.provider.model = undefined;

    // Update URL only for new providers or if URL hasn't been manually modified
    if (
        this.isAddingNew &&
        (!this.urlModified || this.provider.url === currentDefaultUrl)
    ) {
        this.provider.url = PROVIDER_CONFIGS[newType].url;
        this.urlModified = false;
    }

    // Update name only for new providers or if name hasn't been manually modified
    if (
        this.isAddingNew &&
        (!this.nameModified || this.provider.name === currentDefaultName)
    ) {
        this.provider.name = this.getDefaultName(newType);
        this.nameModified = false;
    }
}
The plugin tracks whether you’ve manually edited the Name and URL fields. If you haven’t customized them, switching provider types updates them to match the new provider’s defaults. This prevents accidentally using an OpenAI URL with an Anthropic provider, for example.

Editing Existing Providers

You can modify any saved provider configuration:

Opening the Edit Form

Click the gear icon next to the provider you want to edit:
// From settings.ts:217-230
.addExtraButton(button => {
    button
        .setIcon('gear')
        .setTooltip(I18n.t('settings.options'))
        .onClick(() => {
            if (this.isFormOpen) return;
            this.openForm(false, { ...provider });
        });
});

Editing Process

  1. The form opens pre-filled with the current provider configuration
  2. Modify any fields as needed
  3. Click Save to persist changes
  4. Click Cancel to discard changes
When editing, the default smart behavior for name/URL updates is disabled. Only fields you manually change will be updated.

Deleting Providers

Removing a provider requires confirmation to prevent accidental deletion:
// From settings.ts:244-264
.addExtraButton(button => {
    button
        .setIcon('lucide-trash-2')
        .setTooltip(I18n.t('settings.delete'))
        .onClick(async () => {
            new ConfirmationModal(
                this.app,
                I18n.t('settings.deleteConfirmation', {
                    name: provider.name,
                }),
                async () => {
                    await this.deleteProvider(provider);
                }
            ).open();
        });
});

Deletion Steps

1

Click the Trash Icon

Click the red trash icon next to the provider.
2

Confirm Deletion

A confirmation modal appears displaying the provider name. Click to confirm.
3

Provider Removed

The provider is removed from settings and the list refreshes.
// From settings.ts:123-134
async deleteProvider(provider: IAIProvider) {
    const providers = this.plugin.settings.providers || [];
    const index = providers.findIndex(
        (p: IAIProvider) => p.id === provider.id
    );
    if (index !== -1) {
        providers.splice(index, 1);
        this.plugin.settings.providers = providers;
        await this.plugin.saveSettings();
        this.display();
    }
}
Deleting a provider removes it immediately. Other plugins using this provider will no longer have access to it.

Duplicating Providers

Quickly create a copy of an existing provider:
// From settings.ts:136-149
async duplicateProvider(provider: IAIProvider) {
    const newProvider = {
        ...provider,
        id: `id-${Date.now().toString()}`,
        name: `${provider.name} (${I18n.t('settings.duplicate')})`,
    };

    const providers = this.plugin.settings.providers || [];
    providers.push(newProvider);

    this.plugin.settings.providers = providers;
    await this.plugin.saveSettings();
    this.display();
}
Use cases:
  • Testing different models with the same provider
  • Creating production and development configurations
  • Maintaining multiple API keys for the same service
Click the copy icon next to any provider to duplicate it. The duplicate gets a new ID and “(Duplicate)” appended to its name.

Fetching Available Models

For providers that support automatic model discovery, you can fetch the list of available models:
// From ProviderFormModal.ts:124-241
class ModelSuggest extends AbstractInputSuggest<string> {
    getSuggestions(query: string): string[] {
        const trimmedQuery = query.trim();
        
        if (!trimmedQuery) {
            return this.models.slice(0, this.limit);
        }

        if (trimmedQuery.length < this.minQueryLength) {
            const lowerQuery = trimmedQuery.toLowerCase();
            return this.models
                .filter(model => model.toLowerCase().includes(lowerQuery))
                .slice(0, this.limit);
        }

        const fuzzySearch = prepareFuzzySearch(trimmedQuery);
        const matches = candidates
            .map(model => {
                const match = fuzzySearch(model);
                return match ? { model, matches: match.matches, score: match.score } : null;
            })
            .filter(item => Boolean(item))
            .sort((a, b) => b.score - a.score);
        
        return matches.slice(0, this.limit).map(item => item.model);
    }
}
  • Type to search through available models
  • Fuzzy matching highlights matches in suggestions
  • Supports up to 50 results
  • Keyboard navigation with arrow keys

Mobile Experience (Dropdown)

// From ProviderFormModal.ts:336-354
if (Platform.isMobileApp) {
    modelSetting.addDropdown(dropdown => {
        dropdown.selectEl.setAttribute('data-testid', 'model-select');
        dropdown.setDisabled(modelState.isDisabled);
        dropdown.addOption('', modelState.placeholder);

        const optionValues = modelState.currentModel
            ? [modelState.currentModel, ...modelState.models]
            : modelState.models;
        Array.from(new Set(optionValues)).forEach(model => {
            dropdown.addOption(model, model);
        });

        dropdown.setValue(modelState.currentModel);
        dropdown.onChange(value => {
            this.provider.model = value;
        });
    });
}
  • Standard dropdown selector
  • All available models listed
  • Simpler interface for touch devices

Refresh Models Button

Click the refresh icon to fetch the latest available models:
// From ProviderFormModal.ts:434-456
private async refreshModels() {
    try {
        this.isLoadingModels = true;
        this.display();

        const models = await this.plugin.aiProviders.fetchModels(
            this.provider
        );
        this.provider.availableModels = models;

        if (models.length > 0) {
            this.provider.model = models[0] || '';
        }

        new Notice(I18n.t('settings.modelsUpdated'));
    } catch (error) {
        logger.error('Failed to fetch models:', error);
        new Notice(I18n.t('errors.failedToFetchModels'));
    } finally {
        this.isLoadingModels = false;
        this.display();
    }
}
What happens:
  1. Button shows loading spinner
  2. Plugin calls the provider’s API to fetch models
  3. Model list updates with fresh data
  4. First model is auto-selected
  5. Success or error notice appears
The API key and URL must be configured correctly for model fetching to work.

Testing Provider Connections

The best way to test a provider is by fetching its models:
1

Configure Basic Settings

Ensure Provider Type, URL, and API Key (if required) are set.
2

Click Refresh Models

Click the refresh icon next to the model field.
3

Check Results

  • Success: Model dropdown/combobox populates with available models
  • Failure: Error notice appears with details
private getModelControlState(): ModelControlState {
    const models = this.provider.availableModels || [];
    const hasModels = models.length > 0;
    const isDisabled = this.isLoadingModels || !hasModels;
    const placeholder = this.isLoadingModels
        ? I18n.t('settings.loadingModels')
        : hasModels
          ? I18n.t('settings.modelSearchPlaceholder')
          : I18n.t('settings.noModelsAvailable');
    
    return {
        models,
        currentModel: this.provider.model || '',
        isDisabled,
        placeholder,
    };
}
The model input is disabled while loading or when no models are available.

Debug Logging Option

Enable detailed logging to troubleshoot connection issues:
// From settings.ts:287-298
new Setting(developerSection)
    .setName(I18n.t('settings.debugLogging'))
    .setDesc(I18n.t('settings.debugLoggingDesc'))
    .addToggle(toggle =>
        toggle
            .setValue(this.plugin.settings.debugLogging ?? false)
            .onChange(async value => {
                this.plugin.settings.debugLogging = value;
                logger.setEnabled(value);
                await this.plugin.saveSettings();
            })
    );

Enabling Debug Logging

1

Toggle Developer Settings

In the plugin settings, enable Developer Settings toggle.
2

Enable Debug Logging

Turn on the Debug Logging toggle in the expanded developer section.
3

Check Console

Open Obsidian’s Developer Console (Ctrl/Cmd + Shift + I) and navigate to the Console tab.
4

Perform Actions

Fetch models, execute requests, or perform other operations. Detailed logs will appear in the console.
Debug logging can generate significant console output. Disable it when not actively troubleshooting.

Troubleshooting Common Issues

Provider Name Already Exists

Error: “Provider name already exists: Cause: You’re trying to create or rename a provider with a name that’s already in use. Solution:
// The validation that triggers this from settings.ts:86-92
const existingProvider = providers.find(
    (p: IAIProvider) =>
        p.name.trim() === provider.name.trim() && p.id !== provider.id
);
if (existingProvider) {
    return { isValid: false, error: I18n.t('errors.providerNameExists', { name: provider.name }) };
}
Choose a unique name for your provider.

Failed to Fetch Models

Error: “Failed to fetch models” Common Causes:
  • Verify your API key is correct
  • Check if the key has expired
  • Ensure the key has proper permissions
  • Confirm the URL matches the provider’s documentation
  • Check for typos (https vs http, trailing slashes)
  • For local providers, ensure the service is running
  • Check your internet connection
  • Verify firewall isn’t blocking the request
  • Try disabling VPN if applicable
For Ollama:
# macOS
launchctl setenv OLLAMA_ORIGINS "*"

# Linux (add to service file)
Environment="OLLAMA_ORIGINS=*"

# Windows (PowerShell)
[Environment]::SetEnvironmentVariable("OLLAMA_ORIGINS", "*", "User")
Then restart the Ollama service.

Provider Not Available in Other Plugins

Symptom: Other plugins don’t see your configured provider. Solutions:
  1. Ensure provider is saved - Check that the provider appears in the Configured Providers list
  2. Restart Obsidian - Sometimes plugins need a restart to detect new providers
  3. Check version compatibility - The consuming plugin may require a specific AI Providers version
// Other plugins can check compatibility
aiProviders.checkCompatibility(requiredVersion);

Models Not Loading on Mobile

Symptom: Model dropdown stays empty on mobile devices. Cause: The mobile interface uses a different control than desktop. Solution:
  1. Ensure you’ve clicked the refresh button
  2. Wait for the loading state to complete
  3. Check debug logs for fetch errors
  4. Verify the provider supports model fetching (some don’t)

Text Input Instead of Model Selector

Symptom: You see a text input for the model field instead of a searchable dropdown. Cause: The provider doesn’t support automatic model fetching:
// From ProviderFormModal.ts:58
ai302: {
    url: 'https://api.302.ai/v1',
    name: '302.AI',
    options: { modelsFetching: false },
},
Solution: Manually enter the model name according to the provider’s documentation.

Empty API Key Validation

Note: The plugin doesn’t validate API keys on save. Empty keys are allowed for:
  • Local providers (Ollama, LM Studio)
  • Testing configurations
  • Providers that don’t require authentication
If you see authentication errors when using the provider, ensure you’ve entered a valid API key.

Need More Help?

  • Check the GitHub Issues for known problems
  • Enable debug logging and check console output
  • Review provider-specific documentation for API requirements

Build docs developers (and LLMs) love