diff --git a/package-lock.json b/package-lock.json index 3c504bc..925523c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,8 +10,13 @@ "license": "AGPL-3.0", "dependencies": { "@ai-sdk/anthropic": "^3.0.35", + "@ai-sdk/deepseek": "^2.0.17", + "@ai-sdk/google": "^3.0.20", + "@ai-sdk/groq": "^3.0.21", + "@ai-sdk/mistral": "^3.0.18", "@ai-sdk/openai": "^3.0.25", "@ai-sdk/openai-compatible": "^2.0.26", + "@ai-sdk/xai": "^3.0.46", "@chutes-ai/ai-sdk-provider": "^0.1.2", "@openrouter/ai-sdk-provider": "^2.1.1", "@tauri-apps/api": "^2", @@ -33,7 +38,9 @@ "jszip": "^3.10.1", "lucide-svelte": "^0.468.0", "marked": "^17.0.1", - "tailwind-merge": "^3.4.0" + "ollama-ai-provider": "^1.2.0", + "tailwind-merge": "^3.4.0", + "zhipu-ai-provider": "^0.2.2" }, "devDependencies": { "@lucide/svelte": "^0.482.0", @@ -73,6 +80,22 @@ "zod": "^3.25.76 || ^4.1.8" } }, + "node_modules/@ai-sdk/deepseek": { + "version": "2.0.17", + "resolved": "https://registry.npmjs.org/@ai-sdk/deepseek/-/deepseek-2.0.17.tgz", + "integrity": "sha512-rkZiasQ24UyOMiZd8Mb7R+OF3Yt90bRQyfyzIkrb0zKZj7kU2h2z2nu1CO6j0X8poE+SZhEEaHOBFhRcp6hKVg==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "3.0.7", + "@ai-sdk/provider-utils": "4.0.13" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, "node_modules/@ai-sdk/gateway": { "version": "3.0.32", "resolved": "https://registry.npmjs.org/@ai-sdk/gateway/-/gateway-3.0.32.tgz", @@ -90,6 +113,54 @@ "zod": "^3.25.76 || ^4.1.8" } }, + "node_modules/@ai-sdk/google": { + "version": "3.0.20", + "resolved": "https://registry.npmjs.org/@ai-sdk/google/-/google-3.0.20.tgz", + "integrity": "sha512-bVGsulEr6JiipAFlclo9bjL5WaUV0iCSiiekLt+PY6pwmtJeuU2GaD9DoE3OqR8LN2W779mU13IhVEzlTupf8g==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "3.0.7", + "@ai-sdk/provider-utils": "4.0.13" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, + "node_modules/@ai-sdk/groq": { + "version": "3.0.21", + "resolved": "https://registry.npmjs.org/@ai-sdk/groq/-/groq-3.0.21.tgz", + "integrity": "sha512-sYTnGbvUNoDKTUa5BBKDvzSnjgahtEWriohdljtGBd4vgcimqY3XMXAqefOXEiYjON/GBFx6Q/YR3GVcX32Mcg==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "3.0.7", + "@ai-sdk/provider-utils": "4.0.13" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, + "node_modules/@ai-sdk/mistral": { + "version": "3.0.18", + "resolved": "https://registry.npmjs.org/@ai-sdk/mistral/-/mistral-3.0.18.tgz", + "integrity": "sha512-k8nCBBVGOzBigNwBO5kREzsP/e+C3npcL7jt19ZdicIbZ6rvmnSIRI90iENyS9T10vM7sjrXoCpgZSYgJB2pJQ==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "3.0.7", + "@ai-sdk/provider-utils": "4.0.13" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, "node_modules/@ai-sdk/openai": { "version": "3.0.25", "resolved": "https://registry.npmjs.org/@ai-sdk/openai/-/openai-3.0.25.tgz", @@ -151,6 +222,23 @@ "zod": "^3.25.76 || ^4.1.8" } }, + "node_modules/@ai-sdk/xai": { + "version": "3.0.46", + "resolved": "https://registry.npmjs.org/@ai-sdk/xai/-/xai-3.0.46.tgz", + "integrity": "sha512-26qM/jYcFhF5krTM7bQT1CiZcdz22EQmA+r5me1hKYFM/yM20sSUMHnAcUzvzuuG9oQVKF0tziU2IcC0HX5huQ==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/openai-compatible": "2.0.26", + "@ai-sdk/provider": "3.0.7", + "@ai-sdk/provider-utils": "4.0.13" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, "node_modules/@chutes-ai/ai-sdk-provider": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/@chutes-ai/ai-sdk-provider/-/ai-sdk-provider-0.1.2.tgz", @@ -2666,7 +2754,6 @@ "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, "funding": [ { "type": "github", @@ -2688,12 +2775,69 @@ "dev": true, "license": "MIT" }, + "node_modules/ollama-ai-provider": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ollama-ai-provider/-/ollama-ai-provider-1.2.0.tgz", + "integrity": "sha512-jTNFruwe3O/ruJeppI/quoOUxG7NA6blG3ZyQj3lei4+NnJo7bi3eIRWqlVpRlu/mbzbFXeJSBuYQWF6pzGKww==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "^1.0.0", + "@ai-sdk/provider-utils": "^2.0.0", + "partial-json": "0.1.7" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.0.0" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, + "node_modules/ollama-ai-provider/node_modules/@ai-sdk/provider": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-1.1.3.tgz", + "integrity": "sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg==", + "license": "Apache-2.0", + "dependencies": { + "json-schema": "^0.4.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/ollama-ai-provider/node_modules/@ai-sdk/provider-utils": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-2.2.8.tgz", + "integrity": "sha512-fqhG+4sCVv8x7nFzYnFo19ryhAa3w096Kmc3hWxMQfW/TubPOmt3A6tYZhl4mUfQWWQMsuSkLrtjlWuXBVSGQA==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "1.1.3", + "nanoid": "^3.3.8", + "secure-json-parse": "^2.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.23.8" + } + }, "node_modules/pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", "license": "(MIT AND Zlib)" }, + "node_modules/partial-json": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/partial-json/-/partial-json-0.1.7.tgz", + "integrity": "sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA==", + "license": "MIT" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -2864,6 +3008,12 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "license": "MIT" }, + "node_modules/secure-json-parse": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz", + "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==", + "license": "BSD-3-Clause" + }, "node_modules/set-cookie-parser": { "version": "2.7.2", "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", @@ -3280,6 +3430,48 @@ } } }, + "node_modules/zhipu-ai-provider": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/zhipu-ai-provider/-/zhipu-ai-provider-0.2.2.tgz", + "integrity": "sha512-UjX1ho4DI9ICUv/mrpAnzmrRe5/LXrGkS5hF6h4WDY2aup5GketWWopFzWYCqsbArXAM5wbzzdH9QzZusgGiBg==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "^2.0.0", + "@ai-sdk/provider-utils": "^3.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/zhipu-ai-provider/node_modules/@ai-sdk/provider": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-2.0.1.tgz", + "integrity": "sha512-KCUwswvsC5VsW2PWFqF8eJgSCu5Ysj7m1TxiHTVA6g7k360bk0RNQENT8KTMAYEs+8fWPD3Uu4dEmzGHc+jGng==", + "license": "Apache-2.0", + "dependencies": { + "json-schema": "^0.4.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/zhipu-ai-provider/node_modules/@ai-sdk/provider-utils": { + "version": "3.0.20", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-3.0.20.tgz", + "integrity": "sha512-iXHVe0apM2zUEzauqJwqmpC37A5rihrStAih5Ks+JE32iTe4LZ58y17UGBjpQQTCRw9YxMeo2UFLxLpBluyvLQ==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "2.0.1", + "@standard-schema/spec": "^1.0.0", + "eventsource-parser": "^3.0.6" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, "node_modules/zimmerframe": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.4.tgz", @@ -3287,9 +3479,9 @@ "license": "MIT" }, "node_modules/zod": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", - "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "license": "MIT", "peer": true, "funding": { diff --git a/package.json b/package.json index e64ef99..50020d1 100644 --- a/package.json +++ b/package.json @@ -14,8 +14,13 @@ "license": "AGPL-3.0", "dependencies": { "@ai-sdk/anthropic": "^3.0.35", + "@ai-sdk/deepseek": "^2.0.17", + "@ai-sdk/google": "^3.0.20", + "@ai-sdk/groq": "^3.0.21", + "@ai-sdk/mistral": "^3.0.18", "@ai-sdk/openai": "^3.0.25", "@ai-sdk/openai-compatible": "^2.0.26", + "@ai-sdk/xai": "^3.0.46", "@chutes-ai/ai-sdk-provider": "^0.1.2", "@openrouter/ai-sdk-provider": "^2.1.1", "@tauri-apps/api": "^2", @@ -37,7 +42,9 @@ "jszip": "^3.10.1", "lucide-svelte": "^0.468.0", "marked": "^17.0.1", - "tailwind-merge": "^3.4.0" + "ollama-ai-provider": "^1.2.0", + "tailwind-merge": "^3.4.0", + "zhipu-ai-provider": "^0.2.2" }, "devDependencies": { "@lucide/svelte": "^0.482.0", diff --git a/src/lib/components/settings/ProviderTypeSelector.svelte b/src/lib/components/settings/ProviderTypeSelector.svelte index 0c64aad..07b6e2f 100644 --- a/src/lib/components/settings/ProviderTypeSelector.svelte +++ b/src/lib/components/settings/ProviderTypeSelector.svelte @@ -1,5 +1,6 @@ @@ -78,16 +37,10 @@ {#each providers as provider} - +
{provider.label} - {provider.description} + {provider.description}
{/each} diff --git a/src/lib/components/settings/tabs/api-connection.svelte b/src/lib/components/settings/tabs/api-connection.svelte index 2f1dce7..fd161d5 100644 --- a/src/lib/components/settings/tabs/api-connection.svelte +++ b/src/lib/components/settings/tabs/api-connection.svelte @@ -2,6 +2,7 @@ import { settings } from "$lib/stores/settings.svelte"; import type { APIProfile, ProviderType } from "$lib/types"; import { fetchModelsFromProvider } from "$lib/services/ai/sdk/providers"; + import { PROVIDERS, hasDefaultEndpoint } from "$lib/services/ai/sdk/providers/config"; import ProviderTypeSelector from "$lib/components/settings/ProviderTypeSelector.svelte"; import { Plus, @@ -16,7 +17,6 @@ Box, AlertCircle, Star, - Zap, RotateCcw, Search, } from "lucide-svelte"; @@ -63,38 +63,6 @@ let modelFilterInput = $state(""); let showBaseUrlCollapsible = $state(false); - // Provider defaults for base URLs - const providerDefaults: Record = { - openrouter: "https://openrouter.ai/api/v1", - openai: "", - anthropic: "", - google: "", - nanogpt: "https://nano-gpt.com/api/v1", - chutes: "", - pollinations: "", - }; - - // Providers that have a built-in default API endpoint and can fetch models without a custom baseUrl - const providerHasDefaultEndpoint: Record = { - openrouter: true, - openai: false, - anthropic: true, - google: true, - nanogpt: true, - chutes: true, - pollinations: true, - }; - - const providerDisplayNames: Record = { - openrouter: "OpenRouter", - openai: "OpenAI Compatible", - anthropic: "Anthropic", - google: "Google AI", - nanogpt: "NanoGPT", - chutes: "Chutes", - pollinations: "Pollinations", - }; - // Auto-save debounce state let saveTimeout: ReturnType | null = null; @@ -295,21 +263,6 @@ } } - // Quick-fill presets for OpenAI-compatible endpoints - function quickFillOpenai() { - formName = "OpenAI"; - formBaseUrl = "https://api.openai.com/v1"; - } - - function quickFillNvidianim() { - formName = "NVIDIA NIM"; - formBaseUrl = "https://integrate.api.nvidia.com/v1"; - } - - function quickFillSelfHosted(port: string, name: string) { - formName = name; - formBaseUrl = `http://127.0.0.1:${port}/v1`; - } function handleOpenChange(open: boolean, profile: APIProfile) { if (open) { @@ -414,7 +367,7 @@ value={formProviderType} onchange={(v) => { formProviderType = v; - formName = providerDisplayNames[v]; + formName = PROVIDERS[v].name; formBaseUrl = ""; formFetchedModels = []; formCustomModels = []; @@ -426,58 +379,7 @@ }} /> - {#if formProviderType === "openai"} -
-
- - Quick fill: -
-
- - - - - -
-
- {/if} - - {#if formProviderType === "openai"} + {#if formProviderType === "openai-compatible"}
- - {/if} - - {#if formProviderType === "openai"} + {#if formProviderType === "openai-compatible"}