diff --git a/web-app/package.json b/web-app/package.json index da7849f87..9ead687c2 100644 --- a/web-app/package.json +++ b/web-app/package.json @@ -82,7 +82,7 @@ "remark-math": "6.0.0", "sonner": "2.0.5", "tailwindcss": "4.1.4", - "token.js": "npm:token.js-fork@0.7.27", + "token.js": "npm:token.js-fork@0.7.29", "tw-animate-css": "1.2.8", "ulidx": "2.4.1", "unified": "11.0.5", diff --git a/web-app/src/consts/providers.ts b/web-app/src/consts/providers.ts index 328ba3a9a..d3d806888 100644 --- a/web-app/src/consts/providers.ts +++ b/web-app/src/consts/providers.ts @@ -96,7 +96,7 @@ export const predefinedProviders = [ { active: true, api_key: '', - base_url: 'https://api.anthropic.com', + base_url: 'https://api.anthropic.com/v1', provider: 'anthropic', explore_models_url: 'https://docs.anthropic.com/en/docs/about-claude/models', @@ -127,11 +127,21 @@ export const predefinedProviders = [ }, ], models: [], + custom_header: [ + { + header: 'anthropic-version', + value: '2023-06-01' + }, + { + header: 'anthropic-dangerous-direct-browser-access', + value: 'true' + } + ] }, { active: true, api_key: '', - base_url: 'https://api.cohere.ai/compatibility/v1', + base_url: 'https://api.cohere.ai/v1', explore_models_url: 'https://docs.cohere.com/v2/docs/models', provider: 'cohere', settings: [ diff --git a/web-app/src/hooks/useModelProvider.ts b/web-app/src/hooks/useModelProvider.ts index a0b5a96ce..926cbdd0d 100644 --- a/web-app/src/hooks/useModelProvider.ts +++ b/web-app/src/hooks/useModelProvider.ts @@ -320,9 +320,82 @@ export const useModelProvider = create()( }) } + if (version <= 3 && state?.providers) { + state.providers.forEach((provider) => { + // Migrate Anthropic provider base URL and add custom headers + if (provider.provider === 'anthropic') { + if (provider.base_url === 'https://api.anthropic.com') { + provider.base_url = 'https://api.anthropic.com/v1' + } + + // Update base-url in settings + if (provider.settings) { + const baseUrlSetting = provider.settings.find( + (s) => s.key === 'base-url' + ) + if ( + baseUrlSetting?.controller_props?.value === + 'https://api.anthropic.com' + ) { + baseUrlSetting.controller_props.value = + 'https://api.anthropic.com/v1' + } + if ( + baseUrlSetting?.controller_props?.placeholder === + 'https://api.anthropic.com' + ) { + baseUrlSetting.controller_props.placeholder = + 'https://api.anthropic.com/v1' + } + } + + if (!provider.custom_header) { + provider.custom_header = [ + { + header: 'anthropic-version', + value: '2023-06-01', + }, + { + header: 'anthropic-dangerous-direct-browser-access', + value: 'true', + }, + ] + } + } + + if (provider.provider === 'cohere') { + if (provider.base_url === 'https://api.cohere.ai/compatibility/v1') { + provider.base_url = 'https://api.cohere.ai/v1' + } + + // Update base-url in settings + if (provider.settings) { + const baseUrlSetting = provider.settings.find( + (s) => s.key === 'base-url' + ) + if ( + baseUrlSetting?.controller_props?.value === + 'https://api.cohere.ai/compatibility/v1' + ) { + baseUrlSetting.controller_props.value = + 'https://api.cohere.ai/v1' + } + if ( + baseUrlSetting?.controller_props?.placeholder === + 'https://api.cohere.ai/compatibility/v1' + ) { + baseUrlSetting.controller_props.placeholder = + 'https://api.cohere.ai/v1' + } + } + } + + }) + } + return state }, - version: 3, + version: 4, } ) ) diff --git a/web-app/src/routes/settings/providers/index.tsx b/web-app/src/routes/settings/providers/index.tsx index b22487390..7b9afd905 100644 --- a/web-app/src/routes/settings/providers/index.tsx +++ b/web-app/src/routes/settings/providers/index.tsx @@ -39,7 +39,7 @@ function ModelProviders() { toast.error(t('providerAlreadyExists', { name })) return } - const newProvider = { + const newProvider: ProviderObject = { provider: name, active: true, models: [], diff --git a/web-app/src/services/providers/tauri.ts b/web-app/src/services/providers/tauri.ts index a8ca36fbb..4e08ee751 100644 --- a/web-app/src/services/providers/tauri.ts +++ b/web-app/src/services/providers/tauri.ts @@ -151,6 +151,12 @@ export class TauriProvidersService extends DefaultProvidersService { headers['Authorization'] = `Bearer ${provider.api_key}` } + if (provider.custom_header) { + provider.custom_header.forEach((header) => { + headers[header.header] = header.value + }) + } + // Always use Tauri's fetch to avoid CORS issues const response = await fetchTauri(`${provider.base_url}/models`, { method: 'GET', diff --git a/web-app/src/types/modelProviders.d.ts b/web-app/src/types/modelProviders.d.ts index 93cdd0df2..2225adee0 100644 --- a/web-app/src/types/modelProviders.d.ts +++ b/web-app/src/types/modelProviders.d.ts @@ -48,6 +48,7 @@ type ProviderObject = { settings: ProviderSetting[] models: Model[] persist?: boolean + custom_header?: ProviderCustomHeader[] | null } /** @@ -71,3 +72,8 @@ type ProxyOptions = { verifyHostSSL: boolean noProxy: string } + +type ProviderCustomHeader = { + header: string + value: string +} \ No newline at end of file