From faff7495b60566dc93d8eb847f65289f5a421a90 Mon Sep 17 00:00:00 2001 From: munimunigamer Date: Sat, 31 Jan 2026 21:42:36 -0600 Subject: [PATCH] using OpenAICompatible --- package-lock.json | 59 ++++++++++++++++++- package.json | 1 + src/lib/services/ai/sdk/agents/factory.ts | 6 +- src/lib/services/ai/sdk/generate.ts | 15 +++-- src/lib/services/ai/sdk/providers/registry.ts | 7 ++- 5 files changed, 77 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index de0bf35..d98d108 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "@ai-sdk/anthropic": "^3.0.29", "@ai-sdk/openai": "^3.0.21", + "@ai-sdk/openai-compatible": "^2.0.25", "@chutes-ai/ai-sdk-provider": "^0.1.2", "@openrouter/ai-sdk-provider": "^2.1.1", "@tauri-apps/api": "^2", @@ -105,6 +106,51 @@ "zod": "^3.25.76 || ^4.1.8" } }, + "node_modules/@ai-sdk/openai-compatible": { + "version": "2.0.25", + "resolved": "https://registry.npmjs.org/@ai-sdk/openai-compatible/-/openai-compatible-2.0.25.tgz", + "integrity": "sha512-8PHEsigICF3wz62slGnAVuepDq+ASHN5MTAVk+qSvINnF1P1712OQ8TthK92eS+oJLabZujMo0jq1umM5y5YMA==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "3.0.6", + "@ai-sdk/provider-utils": "4.0.12" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, + "node_modules/@ai-sdk/openai-compatible/node_modules/@ai-sdk/provider": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-3.0.6.tgz", + "integrity": "sha512-hSfoJtLtpMd7YxKM+iTqlJ0ZB+kJ83WESMiWuWrNVey3X8gg97x0OdAAaeAeclZByCX3UdPOTqhvJdK8qYA3ww==", + "license": "Apache-2.0", + "dependencies": { + "json-schema": "^0.4.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@ai-sdk/openai-compatible/node_modules/@ai-sdk/provider-utils": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-4.0.12.tgz", + "integrity": "sha512-sdC3eUTa5W4r/bISlF3nxmM6zc8mV7Nj3mWI9iUO0cib70h0Zr52Tz5gGzO6HcDirbKVTR2ywmZb61MHU68prA==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "3.0.6", + "@standard-schema/spec": "^1.1.0", + "eventsource-parser": "^3.0.6" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, "node_modules/@ai-sdk/provider": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-3.0.5.tgz", @@ -1082,6 +1128,7 @@ "integrity": "sha512-Vp3zX/qlwerQmHMP6x0Ry1oY7eKKRcOWGc2P59srOp4zcqyn+etJyQpELgOi4+ZSUgteX8Y387NuwruLgGXLUQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@standard-schema/spec": "^1.0.0", "@sveltejs/acorn-typescript": "^1.0.5", @@ -1121,6 +1168,7 @@ "integrity": "sha512-Y1Cs7hhTc+a5E9Va/xwKlAJoariQyHY+5zBgCZg4PFWNYQ1nMN9sjK1zhw1gK69DuqVP++sht/1GZg1aRwmAXQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@sveltejs/vite-plugin-svelte-inspector": "^4.0.1", "debug": "^4.4.1", @@ -1776,6 +1824,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -1788,6 +1837,7 @@ "resolved": "https://registry.npmjs.org/ai/-/ai-6.0.59.tgz", "integrity": "sha512-9SfCvcr4kVk4t8ZzIuyHpuL1hFYKsYMQfBSbBq3dipXPa+MphARvI8wHEjNaRqYl3JOsJbWxEBIMqHL0L92mUA==", "license": "Apache-2.0", + "peer": true, "dependencies": { "@ai-sdk/gateway": "3.0.27", "@ai-sdk/provider": "3.0.5", @@ -1930,6 +1980,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -2685,6 +2736,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -2712,6 +2764,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -2902,6 +2955,7 @@ "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.46.1.tgz", "integrity": "sha512-ynjfCHD3nP2el70kN5Pmg37sSi0EjOm9FgHYQdC4giWG/hzO3AatzXXJJgP305uIhGQxSufJLuYWtkY8uK/8RA==", "license": "MIT", + "peer": true, "dependencies": { "@jridgewell/remapping": "^2.3.4", "@jridgewell/sourcemap-codec": "^1.5.0", @@ -3018,7 +3072,8 @@ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz", "integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/tailwindcss-animate": { "version": "1.0.7", @@ -3094,6 +3149,7 @@ "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -3163,6 +3219,7 @@ "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", diff --git a/package.json b/package.json index d2dfae8..f5c699c 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "dependencies": { "@ai-sdk/anthropic": "^3.0.29", "@ai-sdk/openai": "^3.0.21", + "@ai-sdk/openai-compatible": "^2.0.25", "@chutes-ai/ai-sdk-provider": "^0.1.2", "@openrouter/ai-sdk-provider": "^2.1.1", "@tauri-apps/api": "^2", diff --git a/src/lib/services/ai/sdk/agents/factory.ts b/src/lib/services/ai/sdk/agents/factory.ts index 44dc58b..0e38918 100644 --- a/src/lib/services/ai/sdk/agents/factory.ts +++ b/src/lib/services/ai/sdk/agents/factory.ts @@ -6,6 +6,7 @@ */ import { ToolLoopAgent, type StopCondition, type ToolSet, type StepResult } from 'ai'; +import type { LanguageModelV3 } from '@ai-sdk/provider'; import type { ProviderOptions } from '@ai-sdk/provider-utils'; import { settings } from '$lib/stores/settings.svelte'; import { createProviderFromProfile } from '../providers'; @@ -22,7 +23,7 @@ export interface ResolvedAgentConfig { preset: GenerationPreset; profile: APIProfile; providerType: ProviderType; - model: ReturnType['chat']>; + model: LanguageModelV3; providerOptions: ProviderOptions | undefined; } @@ -42,7 +43,8 @@ export function resolveAgentConfig(presetId: string): ResolvedAgentConfig { } const provider = createProviderFromProfile(profile); - const model = provider.chat(preset.model); + // Call provider directly - all providers support provider(modelId) syntax + const model = provider(preset.model) as LanguageModelV3; const providerOptions = buildProviderOptions(preset, profile.providerType); return { preset, profile, providerType: profile.providerType, model, providerOptions }; diff --git a/src/lib/services/ai/sdk/generate.ts b/src/lib/services/ai/sdk/generate.ts index b87e04a..d35a854 100644 --- a/src/lib/services/ai/sdk/generate.ts +++ b/src/lib/services/ai/sdk/generate.ts @@ -9,11 +9,12 @@ import { generateText, streamText, Output, generateImage as sdkGenerateImage } f import { createOpenAI } from '@ai-sdk/openai'; import { createChutes } from '@chutes-ai/ai-sdk-provider'; import { createPollinations } from 'ai-sdk-pollinations'; +import type { LanguageModelV3 } from '@ai-sdk/provider'; import type { ProviderOptions } from '@ai-sdk/provider-utils'; import type { z } from 'zod'; import { settings } from '$lib/stores/settings.svelte'; import { createProviderFromProfile } from './providers'; -import { PROVIDER_CAPABILITIES, IMAGE_MODEL_DEFAULTS } from './providers/defaults'; +import { PROVIDER_CAPABILITIES } from './providers/defaults'; import type { ProviderType, GenerationPreset, ReasoningEffort, APIProfile } from '$lib/types'; import { createLogger } from '../core/config'; @@ -55,7 +56,7 @@ const PROVIDER_OPTIONS_KEY: Record = { openai: 'openai', anthropic: 'anthropic', google: 'google', - nanogpt: 'openai', // NanoGPT is OpenAI-compatible + nanogpt: 'nanogpt', chutes: 'chutes', pollinations: 'pollinations', }; @@ -141,7 +142,7 @@ interface ResolvedConfig { preset: GenerationPreset; profile: APIProfile; providerType: ProviderType; - model: ReturnType['chat']>; + model: LanguageModelV3; providerOptions: ProviderOptions | undefined; } @@ -159,7 +160,8 @@ function resolveConfig(presetId: string): ResolvedConfig { } const provider = createProviderFromProfile(profile); - const model = provider.chat(preset.model); + // Call provider directly - all providers support provider(modelId) syntax + const model = provider(preset.model) as LanguageModelV3; const providerOptions = buildProviderOptions(preset, profile.providerType); return { preset, profile, providerType: profile.providerType, model, providerOptions }; @@ -172,7 +174,7 @@ function resolveConfig(presetId: string): ResolvedConfig { interface NarrativeConfig { profile: APIProfile; providerType: ProviderType; - model: ReturnType['chat']>; + model: LanguageModelV3; temperature: number; maxTokens: number; providerOptions: ProviderOptions | undefined; @@ -191,7 +193,8 @@ function resolveNarrativeConfig(): NarrativeConfig { const provider = createProviderFromProfile(profile); const modelId = settings.apiSettings.defaultModel; - const model = provider.chat(modelId); + // Call provider directly - all providers support provider(modelId) syntax + const model = provider(modelId) as LanguageModelV3; // Build a minimal preset-like object for provider options const narrativePreset: GenerationPreset = { diff --git a/src/lib/services/ai/sdk/providers/registry.ts b/src/lib/services/ai/sdk/providers/registry.ts index 81ac637..b0cbc71 100644 --- a/src/lib/services/ai/sdk/providers/registry.ts +++ b/src/lib/services/ai/sdk/providers/registry.ts @@ -6,6 +6,7 @@ */ import { createOpenAI } from '@ai-sdk/openai'; +import { createOpenAICompatible } from '@ai-sdk/openai-compatible'; import { createAnthropic } from '@ai-sdk/anthropic'; import { createOpenRouter } from '@openrouter/ai-sdk-provider'; import { createChutes } from '@chutes-ai/ai-sdk-provider'; @@ -49,7 +50,7 @@ const DEFAULT_BASE_URLS: Record = { * ```typescript * const profile = settings.getProfile(profileId); * const provider = createProviderFromProfile(profile); - * const model = provider.chat('gpt-4o'); + * const model = provider('gpt-4o'); // All providers are callable * * const result = await generateText({ model, prompt: '...' }); * ``` @@ -90,9 +91,11 @@ export function createProviderFromProfile(profile: APIProfile) { case 'nanogpt': // NanoGPT is OpenAI-compatible with custom base URL - return createOpenAI({ + return createOpenAICompatible({ + name: 'nanogpt', apiKey: profile.apiKey, baseURL: baseURL ?? NANOGPT_API_URL, + supportsStructuredOutputs: true, fetch, });