fix: all providers now working

This commit is contained in:
Alastair Grant 2026-01-14 22:25:49 +11:00
parent 72772a2041
commit a3b33f7cf4
2 changed files with 57 additions and 43 deletions

View file

@ -438,7 +438,9 @@ async function callGemini(
const modelEndpoint = model === "gemini-pro" ? "gemini-pro" : model;
const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/${modelEndpoint}:generateContent?key=${apiKey}`;
const requestBody = {
const isModernGemini = model.includes("1.5") || model.includes("gemini-3") || model.includes("gemini-2");
const requestBody: any = {
contents: [
{
parts: [
@ -447,11 +449,15 @@ async function callGemini(
}
],
generationConfig: {
maxOutputTokens: maxTokens,
maxOutputTokens: Math.max(maxTokens, 2048),
temperature: 0.7
}
};
if (isModernGemini) {
requestBody.generationConfig.responseMimeType = "application/json";
}
const response = await requestUrl({
url: apiUrl,
method: "POST",
@ -657,7 +663,30 @@ export async function fetchProviderModels(
});
const data = response.json;
return data.models
.filter((m: any) => m.supportedGenerationMethods.includes("generateContent"))
.filter((m: any) => {
const id = m.name.toLowerCase();
const displayName = (m.displayName || "").toLowerCase();
// 1. Must support content generation
if (!m.supportedGenerationMethods.includes("generateContent")) return false;
// 2. EXCLUDE specialized/incompatible models
const isSpecialized =
id.includes("nano") || displayName.includes("nano") ||
id.includes("robotics") || displayName.includes("robotics") ||
id.includes("computer use") || displayName.includes("computer use") ||
id.includes("deep research") || displayName.includes("deep research") ||
id.includes("aqa") || displayName.includes("aqa") ||
id.includes("experimental") || id.includes("exp") && !id.includes("flash") && !id.includes("pro"); // Keep Pro/Flash exp
if (isSpecialized) return false;
// 3. ONLY keep Gemini and Gemma models
const isTargetFamily = id.includes("gemini") || id.includes("gemma");
if (!isTargetFamily) return false;
return true;
})
.map((m: any) => ({
id: m.name.replace("models/", ""),
name: m.displayName || m.name.replace("models/", "")
@ -670,7 +699,23 @@ export async function fetchProviderModels(
});
const data = response.json;
return data.data
.filter((m: any) => !m.id.includes("embed") && !m.id.includes("moderation"))
.filter((m: any) => {
const id = m.id.toLowerCase();
// 1. MUST exclude known utility/non-chat models
if (id.includes("embed") || id.includes("moderation") || id.includes("vibe-cli")) return false;
// 2. EXCLUDE experimental/developer/internal models
if (id.includes("devstral") || id.includes("magistral") || id.includes("labs-")) return false;
// 3. CLEAN UP dated versions
// Many Mistral models have both a 'latest' and a dated version (e.g. -2411, -2501).
// We favor 'latest' tags and primary model names for a cleaner list.
const isDated = /-\d{4}$/.test(id);
if (isDated && !id.includes("pixtral") && !id.includes("codestral")) return false;
return true;
})
.map((m: any) => ({ id: m.id, name: m.id }));
}
case "ollama": {

View file

@ -6,7 +6,6 @@ import { fetchProviderModels, fetchCommunityModels } from "../services/llm";
export default class SettingsTab extends PluginSettingTab {
plugin: MyPlugin;
fetchedModels: Record<string, Array<{ id: string; name: string }>> = {};
modelFilter: string = "";
static readonly CORE_MODELS: Record<string, Array<{ id: string; name: string }>> = {
openai: [
@ -33,6 +32,8 @@ export default class SettingsTab extends PluginSettingTab {
{ id: "deepseek-coder", name: "DeepSeek Coder" }
],
gemini: [
{ id: "gemini-3-flash-preview", name: "Gemini 3 Flash (Preview)" },
{ id: "gemini-2.0-flash-exp", name: "Gemini 2.0 Flash (Experimental)" },
{ id: "gemini-1.5-pro", name: "Gemini 1.5 Pro" },
{ id: "gemini-1.5-flash", name: "Gemini 1.5 Flash" },
{ id: "gemini-1.5-flash-8b", name: "Gemini 1.5 Flash-8B" },
@ -62,11 +63,12 @@ export default class SettingsTab extends PluginSettingTab {
.addDropdown((dropdown: DropdownComponent) => {
dropdown
.addOption("openai", "OpenAI")
.addOption("anthropic", "Anthropic (Claude)")
.addOption("deepseek", "DeepSeek")
.addOption("gemini", "Google (Gemini)")
.addOption("mistral", "Mistral AI")
.addOption("ollama", "Ollama (Local)")
.setValue(this.plugin.settings.llmProvider === "anthropic" ? "openai" : this.plugin.settings.llmProvider)
.setValue(this.plugin.settings.llmProvider)
.onChange(async (value: LLMProvider) => {
this.plugin.settings.llmProvider = value;
await this.plugin.saveSettings();
@ -79,33 +81,11 @@ export default class SettingsTab extends PluginSettingTab {
const provider = this.plugin.settings.llmProvider;
const apiKey = this.plugin.settings.apiKeys[provider];
// Model Filter
new Setting(containerEl)
.setName("Filter models")
.setDesc("Type to filter the available models list")
.addSearch((search) => {
search
.setPlaceholder("Filter models...")
.setValue(this.modelFilter)
.onChange((value) => {
this.modelFilter = value.toLowerCase();
this.display();
});
})
.addExtraButton((button) => {
button
.setIcon("x-circle")
.setTooltip("Clear filter")
.onClick(() => {
this.modelFilter = "";
this.display();
});
});
// Model selection
const modelSetting = new Setting(containerEl)
.setName(`${provider.charAt(0).toUpperCase() + provider.slice(1)} model`)
.setDesc(`Select which ${provider} model to use`);
.setDesc(`Select which ${provider} model to use. Save your API key and refresh to get latest models. Warning: not all models are compatible with this plugin.`);
modelSetting.addDropdown(async (dropdown: DropdownComponent) => {
const currentModel = this.plugin.settings.models[provider];
@ -122,22 +102,11 @@ export default class SettingsTab extends PluginSettingTab {
modelMap.set(currentModel, currentModel);
}
// Apply filter
let visibleModelsCount = 0;
modelMap.forEach((name, id) => {
if (!this.modelFilter || id.toLowerCase().includes(this.modelFilter) || name.toLowerCase().includes(this.modelFilter)) {
dropdown.addOption(id, name);
visibleModelsCount++;
}
dropdown.addOption(id, name);
});
if (visibleModelsCount === 0 && this.modelFilter) {
dropdown.addOption("", "No models match filter");
dropdown.setDisabled(true);
} else {
dropdown.setDisabled(false);
dropdown.setValue(currentModel);
}
dropdown.setValue(currentModel);
// Auto-fetch in background if we have an API key and haven't fetched yet
if (fetched.length === 0 && apiKey) {
@ -264,7 +233,7 @@ export default class SettingsTab extends PluginSettingTab {
// Model selection
new Setting(containerEl)
.setName("Ollama model")
.setDesc("Enter the name of the Ollama model to use")
.setDesc("Enter the name of the Ollama model to use. Some models may not be compatible with this plugin.")
.addText((text) =>
text
.setPlaceholder("llama3")