@tombcato/ai-selector-core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/dist/api.d.ts +14 -0
  2. package/dist/api.d.ts.map +1 -0
  3. package/dist/api.js +139 -0
  4. package/dist/api.js.map +1 -0
  5. package/dist/config.d.ts +18 -0
  6. package/dist/config.d.ts.map +1 -0
  7. package/dist/config.js +85 -0
  8. package/dist/config.js.map +1 -0
  9. package/dist/i18n.d.ts +53 -0
  10. package/dist/i18n.d.ts.map +1 -0
  11. package/dist/i18n.js +51 -0
  12. package/dist/i18n.js.map +1 -0
  13. package/dist/icons.d.ts +10 -0
  14. package/dist/icons.d.ts.map +1 -0
  15. package/dist/icons.js +22 -0
  16. package/dist/icons.js.map +1 -0
  17. package/dist/index.d.ts +13 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +19 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/models.d.ts +11 -0
  22. package/dist/models.d.ts.map +1 -0
  23. package/dist/models.js +199 -0
  24. package/dist/models.js.map +1 -0
  25. package/dist/providers.d.ts +42 -0
  26. package/dist/providers.d.ts.map +1 -0
  27. package/dist/providers.js +229 -0
  28. package/dist/providers.js.map +1 -0
  29. package/dist/storage.d.ts +31 -0
  30. package/dist/storage.d.ts.map +1 -0
  31. package/dist/storage.js +65 -0
  32. package/dist/storage.js.map +1 -0
  33. package/dist/strategies.d.ts +54 -0
  34. package/dist/strategies.d.ts.map +1 -0
  35. package/dist/strategies.js +184 -0
  36. package/dist/strategies.js.map +1 -0
  37. package/dist/types.d.ts +122 -0
  38. package/dist/types.d.ts.map +1 -0
  39. package/dist/types.js +6 -0
  40. package/dist/types.js.map +1 -0
  41. package/dist/utils.d.ts +2 -0
  42. package/dist/utils.d.ts.map +1 -0
  43. package/dist/utils.js +4 -0
  44. package/dist/utils.js.map +1 -0
  45. package/package.json +36 -0
  46. package/src/api.ts +154 -0
  47. package/src/config.ts +104 -0
  48. package/src/i18n.ts +54 -0
  49. package/src/index.ts +76 -0
  50. package/src/models.ts +202 -0
  51. package/src/providers.ts +239 -0
  52. package/src/storage.ts +78 -0
  53. package/src/strategies.ts +251 -0
  54. package/src/styles.css +244 -0
  55. package/src/types.ts +151 -0
package/src/config.ts ADDED
@@ -0,0 +1,104 @@
1
+ /**
2
+ * AI Provider Selector - Config Resolution
3
+ * Resolves ProviderConfig into a list of providers and models
4
+ */
5
+
6
+ import type { Provider, Model, ProviderConfig, CustomProviderDefinition } from './types';
7
+ import { PROVIDERS } from './providers';
8
+ import { getStaticModels } from './models';
9
+
10
+ export interface ResolvedConfig {
11
+ providers: Provider[];
12
+ getModels: (providerId: string) => Model[];
13
+ }
14
+
15
+ /**
16
+ * Resolve a ProviderConfig into usable providers and models
17
+ */
18
+ export function resolveProviderConfig(config?: ProviderConfig): ResolvedConfig {
19
+ // Default config: use all built-in providers
20
+ if (!config) {
21
+ return {
22
+ providers: Object.values(PROVIDERS),
23
+ getModels: (providerId: string) => getStaticModels(providerId),
24
+ };
25
+ }
26
+
27
+ const { mode, include, exclude, custom } = config;
28
+ let providers: Provider[] = [];
29
+
30
+ // Handle built-in providers based on mode
31
+ if (mode === 'default') {
32
+ let builtInProviders = Object.values(PROVIDERS);
33
+
34
+ // Apply include filter
35
+ if (include && include.length > 0) {
36
+ builtInProviders = builtInProviders.filter(p => include.includes(p.id));
37
+ }
38
+
39
+ // Apply exclude filter
40
+ if (exclude && exclude.length > 0) {
41
+ builtInProviders = builtInProviders.filter(p => !exclude.includes(p.id));
42
+ }
43
+
44
+ providers = [...builtInProviders];
45
+ }
46
+
47
+ // Handle custom providers
48
+ const customModelsMap: Record<string, Model[]> = {};
49
+
50
+ if (custom) {
51
+ for (const [id, def] of Object.entries(custom)) {
52
+ const customProvider: Provider = {
53
+ id,
54
+ name: def.name,
55
+ baseUrl: def.baseUrl,
56
+ needsApiKey: def.needsApiKey,
57
+ apiFormat: def.apiFormat,
58
+ supportsModelsApi: def.supportsModelsApi ?? false,
59
+ icon: def.icon,
60
+ };
61
+
62
+ // Check if provider already exists (for override)
63
+ const existingIndex = providers.findIndex(p => p.id === id);
64
+
65
+ if (existingIndex >= 0) {
66
+ // Merge/Override existing provider
67
+ // We keep the original icon if custom doesn't provide one
68
+ providers[existingIndex] = {
69
+ ...providers[existingIndex],
70
+ ...customProvider,
71
+ icon: customProvider.icon || providers[existingIndex].icon
72
+ };
73
+ } else {
74
+ // Add new provider
75
+ providers.push(customProvider);
76
+ }
77
+
78
+ // Store custom models if provided
79
+ if (def.models && def.models.length > 0) {
80
+ customModelsMap[id] = def.models;
81
+ }
82
+ }
83
+ }
84
+
85
+ // Create getModels function that checks custom models first
86
+ const getModels = (providerId: string): Model[] => {
87
+ // Check custom models first
88
+ if (customModelsMap[providerId]) {
89
+ return customModelsMap[providerId];
90
+ }
91
+ // Fall back to static models
92
+ return getStaticModels(providerId);
93
+ };
94
+
95
+ return { providers, getModels };
96
+ }
97
+
98
+ /**
99
+ * Get a single provider by ID from config
100
+ */
101
+ export function getProviderFromConfig(providerId: string, config?: ProviderConfig): Provider | null {
102
+ const { providers } = resolveProviderConfig(config);
103
+ return providers.find(p => p.id === providerId) || null;
104
+ }
package/src/i18n.ts ADDED
@@ -0,0 +1,54 @@
1
+ export const I18N = {
2
+ zh: {
3
+ save: '保存配置',
4
+ saved: '保存成功',
5
+ providerLabel: 'Provider',
6
+ modelLabel: 'Model',
7
+ selectProvider: '选择 Provider...',
8
+ customBaseUrl: '自定义 Base URL',
9
+ apiKeyLabel: 'API Key',
10
+ apiKeyPlaceholder: '输入 API Key...',
11
+ testConnection: '测试模型连接',
12
+ testing: '测试中...',
13
+ testSuccess: '连接成功',
14
+ testFailed: '测试连通性失败',
15
+ selectModel: '选择 Model...',
16
+ searchModel: '搜索或自定义模型...',
17
+ useCustom: '使用自定义',
18
+ noModels: '暂无模型数据',
19
+ apiKeyTip: '输入 API Key 后可获取完整模型列表',
20
+ fetchModelsFailed: '拉取模型列表失败,已使用离线模型列表',
21
+ refreshingModels: '列表刷新中...',
22
+ modelListUpdated: '模型列表已刷新',
23
+ preview: '配置预览',
24
+ unselected: '(未选择)',
25
+ },
26
+ en: {
27
+ save: 'Save Config',
28
+ saved: 'Saved',
29
+ providerLabel: 'Provider',
30
+ modelLabel: 'Model',
31
+ selectProvider: 'Select Provider...',
32
+ customBaseUrl: 'Custom Base URL',
33
+ apiKeyLabel: 'API Key',
34
+ apiKeyPlaceholder: 'Enter API Key...',
35
+ testConnection: 'Test Model Connection',
36
+ testing: 'Testing...',
37
+ testSuccess: 'Connection Successful',
38
+ testFailed: 'Connection Failed',
39
+ selectModel: 'Select Model...',
40
+ searchModel: 'Search or custom models...',
41
+ useCustom: 'Use custom',
42
+ noModels: 'No models found',
43
+ apiKeyTip: 'Enter API Key to fetch full model list',
44
+ fetchModelsFailed: 'Failed to fetch model list, using offline models',
45
+ refreshingModels: 'Refreshing models...',
46
+ modelListUpdated: 'Model list updated',
47
+ preview: 'Config Preview',
48
+ unselected: '(Unselected)',
49
+ }
50
+ } as const;
51
+
52
+ export type Language = keyof typeof I18N;
53
+ export type I18NKeys = keyof typeof I18N['zh'];
54
+
package/src/index.ts ADDED
@@ -0,0 +1,76 @@
1
+ /**
2
+ * AI Provider Selector - Core Package
3
+ * Framework-agnostic logic for AI provider configuration
4
+ */
5
+
6
+ // I18N
7
+ export * from './i18n';
8
+
9
+ // Types
10
+ export type {
11
+ Provider,
12
+ Model,
13
+ AIConfig,
14
+
15
+ ApiFormat,
16
+ TestConnectionOptions,
17
+ TestConnectionResult,
18
+ FetchModelsOptions,
19
+ StorageAdapter,
20
+ // New config types
21
+ ProviderConfig,
22
+ CustomProviderDefinition,
23
+ AIConfigFormProps,
24
+ // Fetcher types
25
+ ModelFetcher,
26
+ FetcherParams,
27
+ FetcherActionType,
28
+ } from './types';
29
+
30
+ // Providers
31
+ export {
32
+ PROVIDERS,
33
+ PROVIDER_ID,
34
+ type ProviderId,
35
+ getProvider,
36
+ getAllProviders,
37
+ getProvidersByFormat
38
+ } from './providers';
39
+
40
+ // Models
41
+ export {
42
+ STATIC_MODELS,
43
+ getStaticModels
44
+ } from './models';
45
+
46
+ // API
47
+ export {
48
+ testConnection,
49
+ fetchModels
50
+ } from './api';
51
+
52
+ // Storage
53
+ export {
54
+ localStorageAdapter,
55
+ createConfigStorage
56
+ } from './storage';
57
+
58
+
59
+
60
+ // Config Resolution
61
+ export {
62
+ resolveProviderConfig,
63
+ getProviderFromConfig,
64
+ type ResolvedConfig
65
+ } from './config';
66
+
67
+ // Strategies
68
+ export {
69
+ type ProviderStrategy,
70
+ strategyRegistry,
71
+ getStrategy,
72
+ sendDirectChat,
73
+ testDirectConnection,
74
+ type DirectChatOptions,
75
+ type DirectChatResult,
76
+ } from './strategies';
package/src/models.ts ADDED
@@ -0,0 +1,202 @@
1
+ /**
2
+ * AI Provider Selector - Static Model Definitions
3
+ * Models data when API doesn't support /models endpoint
4
+ */
5
+
6
+ import type { Model } from './types';
7
+ import { PROVIDER_ID } from './providers';
8
+
9
+ export const STATIC_MODELS: Record<string, Model[]> = {
10
+ [PROVIDER_ID.OPENAI]: [
11
+ { id: 'gpt-5.2-pro', name: 'GPT-5.2 Pro' },
12
+ { id: 'gpt-5.2', name: 'GPT-5.2' },
13
+ { id: 'gpt-5', name: 'GPT-5' },
14
+ { id: 'gpt-5-mini', name: 'GPT-5 Mini' },
15
+ { id: 'gpt-5-nano', name: 'GPT-5 Nano' },
16
+ { id: 'gpt-4.1', name: 'GPT-4.1' },
17
+ ],
18
+ [PROVIDER_ID.ANTHROPIC]: [
19
+ { id: 'claude-opus-4.5-20251101', name: 'Claude Opus 4.5' },
20
+ { id: 'claude-opus-4.5-20251101-thinking', name: 'Claude Opus 4.5 Thinking' },
21
+ { id: 'claude-sonnet-4.5-20250929', name: 'Claude Sonnet 4.5' },
22
+ { id: 'claude-sonnet-4.5-20250929-thinking', name: 'Claude Sonnet 4.5 Thinking' },
23
+ { id: 'claude-haiku-4.5-20251001', name: 'Claude Haiku 4.5' },
24
+ { id: 'claude-haiku-4.5-20251001-thinking', name: 'Claude Haiku 4.5 Thinking' },
25
+ { id: 'claude-opus-4.1-20250805', name: 'Claude Opus 4.1' },
26
+ { id: 'claude-opus-4.1-20250805-thinking', name: 'Claude Opus 4.1 Thinking' },
27
+ ],
28
+ [PROVIDER_ID.GEMINI]: [
29
+ { id: 'gemini-3-flash-preview', name: 'Gemini 3 Flash Preview' },
30
+ { id: 'gemini-3-pro-preview', name: 'Gemini 3 Pro Preview' },
31
+ { id: 'gemini-2.5-pro', name: 'Gemini 2.5 Pro' },
32
+ { id: 'gemini-2.5-flash', name: 'Gemini 2.5 Flash' },
33
+ { id: 'gemini-2.5-flash-lite', name: 'Gemini 2.5 Flash-Lite' },
34
+ ],
35
+ [PROVIDER_ID.DEEPSEEK]: [
36
+ { id: 'deepseek-chat', name: 'Deepseek Chat' },
37
+ { id: 'deepseek-reasoner', name: 'Deepseek Reasoner' },
38
+ ],
39
+ [PROVIDER_ID.MISTRAL]: [
40
+ { id: 'mistral-large-latest', name: 'Mistral Large' },
41
+ { id: 'mistral-medium-latest', name: 'Mistral Medium' },
42
+ { id: 'mistral-small-latest', name: 'Mistral Small' },
43
+ { id: 'codestral-latest', name: 'Codestral' },
44
+ { id: 'devstral-latest', name: 'Devstral' },
45
+ { id: 'magistral-medium-latest', name: 'Magistral Medium' },
46
+ { id: 'pixtral-large-latest', name: 'Pixtral Large' },
47
+ { id: 'pixtral-12b-latest', name: 'Pixtral 12B' },
48
+ { id: 'ministral-8b-latest', name: 'Ministral 8B' },
49
+ { id: 'ministral-3b-latest', name: 'Ministral 3B' },
50
+ ],
51
+ [PROVIDER_ID.GROQ]: [
52
+ { id: 'canopylabs/orpheus-v1-english', name: 'Orpheus V1 English' },
53
+ { id: 'canopylabs/orpheus-arabic-saudi', name: 'Orpheus Arabic Saudi' },
54
+ { id: 'moonshotai/kimi-k2-instruct', name: 'Kimi K2 Instruct' },
55
+ { id: 'groq/compound-mini', name: 'Compound Mini' },
56
+ { id: 'llama-3.3-70b-versatile', name: 'Llama 3.3 70B Versatile' },
57
+ { id: 'openai/gpt-oss-120b', name: 'Gpt Oss 120B' },
58
+ { id: 'qwen/qwen3-32b', name: 'Qwen3 32B' },
59
+ { id: 'groq/compound', name: 'Compound' },
60
+ { id: 'meta-llama/llama-4-maverick-17b-128e-instruct', name: 'Llama 4 Maverick 17B 128E Instruct' },
61
+ ],
62
+ [PROVIDER_ID.XAI]: [
63
+ { id: 'grok-4', name: 'Grok 4' },
64
+ { id: 'grok-4-fast', name: 'Grok 4 Fast' },
65
+ { id: 'grok-3-latest', name: 'Grok 3' },
66
+ { id: 'grok-3-fast', name: 'Grok 3 Fast' },
67
+ { id: 'grok-3-mini-latest', name: 'Grok 3 Mini' },
68
+ { id: 'grok-3-mini-fast', name: 'Grok 3 Mini Fast' },
69
+ { id: 'grok-vision-beta', name: 'Grok Vision (Beta)' },
70
+ ],
71
+ [PROVIDER_ID.TOGETHER]: [
72
+ { id: 'Qwen/Qwen2.5-72B-Instruct-Turbo', name: 'Qwen2.5 72B Instruct Turbo' },
73
+ { id: 'Qwen/Qwen3-235B-A22B-Thinking-2507', name: 'Qwen3 235B A22B Thinking 2507' },
74
+ { id: 'deepseek-ai/DeepSeek-R1', name: 'Deepseek R1' },
75
+ { id: 'deepseek-ai/DeepSeek-V3.1', name: 'Deepseek V3.1' },
76
+ { id: 'meta-llama/Llama-3.2-3B-Instruct-Turbo', name: 'Llama 3.2 3B Instruct Turbo' },
77
+ { id: 'meta-llama/Llama-3.3-70B-Instruct-Turbo', name: 'Llama 3.3 70B Instruct Turbo' },
78
+ { id: 'meta-llama/Llama-3.3-70B-Instruct-Turbo-Free', name: 'Llama 3.3 70B Instruct Turbo Free' },
79
+ ],
80
+ [PROVIDER_ID.FIREWORKS]: [
81
+ { id: 'accounts/fireworks/models/llama4-scout-instruct-basic', name: 'Llama4 Scout Instruct Basic' },
82
+ { id: 'accounts/fireworks/models/qwen3-vl-235b-a22b-thinking', name: 'Qwen3 Vl 235B A22B Thinking' },
83
+ { id: 'accounts/fireworks/models/deepseek-v3p2', name: 'Deepseek V3P2' },
84
+ { id: 'accounts/fireworks/models/qwen3-vl-30b-a3b-thinking', name: 'Qwen3 Vl 30B A3B Thinking' },
85
+ { id: 'accounts/fireworks/models/qwen3-8b', name: 'Qwen3 8B' },
86
+ { id: 'accounts/fireworks/models/qwen3-vl-30b-a3b-instruct', name: 'Qwen3 Vl 30B A3B Instruct' },
87
+ { id: 'accounts/fireworks/models/qwen2p5-vl-32b-instruct', name: 'Qwen2P5 Vl 32B Instruct' },
88
+ { id: 'accounts/fireworks/models/llama4-maverick-instruct-basic', name: 'Llama4 Maverick Instruct Basic' },
89
+ { id: 'accounts/fireworks/models/qwen3-235b-a22b-thinking-2507', name: 'Qwen3 235B A22B Thinking 2507' },
90
+ { id: 'accounts/fireworks/models/qwen3-coder-480b-a35b-instruct', name: 'Qwen3 Coder 480B A35B Instruct' },
91
+ ],
92
+ [PROVIDER_ID.DEEPINFRA]: [
93
+ { id: 'meta-llama/Llama-3.2-11B-Vision-Instruct', name: 'Llama 3.2 11B Vision Instruct' },
94
+ { id: 'Qwen/Qwen3-32B', name: 'Qwen3 32B' },
95
+ { id: 'NousResearch/Hermes-3-Llama-3.1-70B', name: 'Hermes 3 Llama 3.1 70B' },
96
+ { id: 'Qwen/Qwen2.5-72B-Instruct', name: 'Qwen2.5 72B Instruct' },
97
+ { id: 'deepseek-ai/DeepSeek-V3-0324', name: 'Deepseek V3 0324' },
98
+ { id: 'Qwen/Qwen3-VL-235B-A22B-Instruct', name: 'Qwen3 Vl 235B A22B Instruct' },
99
+ { id: 'meta-llama/Llama-3.2-3B-Instruct', name: 'Llama 3.2 3B Instruct' },
100
+ { id: 'Qwen/Qwen2.5-VL-32B-Instruct', name: 'Qwen2.5 Vl 32B Instruct' },
101
+ { id: 'meta-llama/Meta-Llama-3.1-8B-Instruct', name: 'Meta Llama 3.1 8B Instruct' },
102
+ { id: 'Qwen/Qwen3-Coder-480B-A35B-Instruct-Turbo', name: 'Qwen3 Coder 480B A35B Instruct Turbo' },
103
+ ],
104
+ [PROVIDER_ID.OPENROUTER]: [
105
+ { id: 'google/gemini-3-flash-preview', name: 'Gemini 3 Flash Preview' },
106
+ { id: 'mistralai/mistral-small-creative', name: 'Mistral Small Creative' },
107
+ { id: 'openai/gpt-5.2-chat', name: 'Gpt 5.2 Chat' },
108
+ { id: 'openai/gpt-5.2-pro', name: 'Gpt 5.2 Pro' },
109
+ { id: 'openai/gpt-5.2', name: 'Gpt 5.2' },
110
+ { id: 'mistralai/devstral-2512', name: 'Devstral 2512' },
111
+ { id: 'openai/gpt-5.1-codex-max', name: 'Gpt 5.1 Codex Max' },
112
+ { id: 'mistralai/ministral-14b-2512', name: 'Ministral 14B 2512' },
113
+ { id: 'mistralai/ministral-8b-2512', name: 'Ministral 8B 2512' },
114
+ { id: 'mistralai/ministral-3b-2512', name: 'Ministral 3B 2512' },
115
+ { id: 'mistralai/mistral-large-2512', name: 'Mistral Large 2512' },
116
+ { id: 'deepseek/deepseek-v3.2-speciale', name: 'Deepseek V3.2 Speciale' },
117
+ ],
118
+ [PROVIDER_ID.PERPLEXITY]: [
119
+ { id: 'codellama-34b-instruct', name: 'Codellama 34B Instruct' },
120
+ { id: 'codellama-70b-instruct', name: 'Codellama 70B Instruct' },
121
+ { id: 'llama-2-70b-chat', name: 'Llama 2 70B Chat' },
122
+ { id: 'llama-3.1-70b-instruct', name: 'Llama 3.1 70B Instruct' },
123
+ { id: 'llama-3.1-8b-instruct', name: 'Llama 3.1 8B Instruct' },
124
+ { id: 'llama-3.1-sonar-huge-128k-online', name: 'Llama 3.1 Sonar Huge 128K Online' },
125
+ { id: 'llama-3.1-sonar-large-128k-chat', name: 'Llama 3.1 Sonar Large 128K Chat' },
126
+ { id: 'llama-3.1-sonar-large-128k-online', name: 'Llama 3.1 Sonar Large 128K Online' },
127
+ { id: 'llama-3.1-sonar-small-128k-chat', name: 'Llama 3.1 Sonar Small 128K Chat' },
128
+ ],
129
+ [PROVIDER_ID.COHERE]: [
130
+ { id: 'command-a-vision-07-2025', name: 'Command A Vision 07 2025' },
131
+ { id: 'command-a-reasoning-08-2025', name: 'Command A Reasoning 08 2025' },
132
+ { id: 'command-r-08-2024', name: 'Command R 08 2024' },
133
+ { id: 'command-r7b-arabic-02-2025', name: 'Command R7B Arabic 02 2025' },
134
+ { id: 'command-r7b-12-2024', name: 'Command R7B 12 2024' },
135
+ ],
136
+ [PROVIDER_ID.MOONSHOT]: [
137
+ { id: 'moonshot-v1-128k', name: 'Moonshot 128K' },
138
+ { id: 'moonshot-v1-32k', name: 'Moonshot 32K' },
139
+ { id: 'moonshot-v1-8k', name: 'Moonshot 8K' },
140
+ { id: 'kimi-k2-0711-chat', name: 'Kimi K2 Chat' },
141
+ { id: 'moonshot-v1-auto', name: 'Moonshot Auto' },
142
+ ],
143
+ [PROVIDER_ID.QWEN]: [
144
+ { id: 'qwen-flash', name: 'Qwen Flash' },
145
+ { id: 'qwen3-vl-plus-2025-12-19', name: 'Qwen3 Vl Plus 2025 12 19' },
146
+ { id: 'qwen3-tts-vd-realtime-2025-12-16', name: 'Qwen3 Tts Vd Realtime 2025 12 16' },
147
+ { id: 'qwen-image-edit-plus-2025-12-15', name: 'Qwen Image Edit Plus 2025 12 15' },
148
+ { id: 'qwen3-omni-flash-2025-12-01', name: 'Qwen3 Omni Flash 2025 12 01' },
149
+ { id: 'qwen3-omni-flash-realtime-2025-12-01', name: 'Qwen3 Omni Flash Realtime 2025 12 01' },
150
+ { id: 'qwen3-livetranslate-flash-2025-12-01', name: 'Qwen3 Livetranslate Flash 2025 12 01' },
151
+ { id: 'qwen3-livetranslate-flash', name: 'Qwen3 Livetranslate Flash' },
152
+ { id: 'qwen-plus-2025-12-01', name: 'Qwen Plus 2025 12 01' },
153
+ { id: 'qwen3-tts-vc-realtime-2025-11-27', name: 'Qwen3 Tts Vc Realtime 2025 11 27' },
154
+ ],
155
+ [PROVIDER_ID.ZHIPU]: [
156
+ { id: 'glm-4.5', name: 'Glm 4.5' },
157
+ { id: 'glm-4.5-air', name: 'Glm 4.5 Air' },
158
+ { id: 'glm-4.6', name: 'Glm 4.6' },
159
+ { id: 'glm-4.7', name: 'Glm 4.7' },
160
+ ],
161
+ [PROVIDER_ID.SILICONFLOW]: [
162
+ { id: 'deepseek-ai/DeepSeek-V3.2', name: 'Deepseek V3.2' },
163
+ { id: 'deepseek-ai/DeepSeek-V3.1-Terminus', name: 'Deepseek V3.1 Terminus' },
164
+ { id: 'deepseek-ai/DeepSeek-R1', name: 'Deepseek R1' },
165
+ { id: 'deepseek-ai/DeepSeek-V3', name: 'Deepseek V3' },
166
+ { id: 'zai-org/GLM-4.6V', name: 'Glm 4.6V' },
167
+ { id: 'zai-org/GLM-4.6', name: 'Glm 4.6' },
168
+ { id: 'Pro/zai-org/GLM-4.7', name: 'Glm 4.7' },
169
+ { id: 'Qwen/Qwen3-VL-32B-Instruct', name: 'Qwen3 Vl 32B Instruct' },
170
+ ],
171
+ [PROVIDER_ID.OLLAMA]: [
172
+ { id: 'llama3.3', name: 'Llama 3.3' },
173
+ { id: 'llama3.2', name: 'Llama 3.2' },
174
+ { id: 'qwq', name: 'QwQ (推理)' },
175
+ { id: 'qwen3:32b', name: 'Qwen3 32B' },
176
+ { id: 'deepseek-r1:32b', name: 'DeepSeek R1 32B' },
177
+ { id: 'deepseek-coder-v2', name: 'DeepSeek Coder V2' },
178
+ { id: 'gemma3:27b', name: 'Gemma 3 27B' },
179
+ { id: 'mistral:7b', name: 'Mistral 7B' },
180
+ { id: 'phi4', name: 'Phi 4' },
181
+ { id: 'codellama', name: 'Code Llama' },
182
+ ],
183
+ [PROVIDER_ID.DOUBAO]: [
184
+ { id: 'doubao-seed-1-8-251215', name: 'Doubao 1.8' },
185
+ { id: "doubao-seed-1-6-251015",name: "Doubao 1.6"},
186
+ { id: 'doubao-seed-1-6-lite-251015', name: 'Doubao 1.6 Lite' },
187
+ { id: 'doubao-seed-1-6-flash-250828', name: 'Doubao 1.6 Flash' },
188
+ { id: 'doubao-seed-1-6-thinking-250615', name: 'Doubao 1.6 Thinking' },
189
+ ],
190
+ [PROVIDER_ID.MINIMAX]: [
191
+ { id: 'MiniMax-M2.1', name: 'MiniMax M2.1' },
192
+ { id: 'MiniMax-M2.1-lightning', name: 'MiniMax M2.1 Lightning' },
193
+ { id: 'MiniMax-M2', name: 'MiniMax M2' },
194
+ ],
195
+ };
196
+
197
+ /**
198
+ * Get static models for a provider
199
+ */
200
+ export function getStaticModels(providerId: string): Model[] {
201
+ return STATIC_MODELS[providerId] || [];
202
+ }
@@ -0,0 +1,239 @@
1
+ /**
2
+ * AI Provider Selector - Provider Definitions
3
+ * All supported AI providers metadata
4
+ */
5
+
6
+ import type { Provider } from './types';
7
+
8
+ const ICON_CDN_BASE = 'https://registry.npmmirror.com/@lobehub/icons-static-svg/1.77.0/files/icons';
9
+
10
+ // Provider IDs
11
+ export const PROVIDER_ID = {
12
+ OPENAI: 'openai',
13
+ ANTHROPIC: 'anthropic',
14
+ GEMINI: 'gemini',
15
+ DEEPSEEK: 'deepseek',
16
+ OPENROUTER: 'openrouter',
17
+ GROQ: 'groq',
18
+ MISTRAL: 'mistral',
19
+ MOONSHOT: 'moonshot',
20
+ QWEN: 'qwen',
21
+ ZHIPU: 'zhipu',
22
+ SILICONFLOW: 'siliconflow',
23
+ XAI: 'xai',
24
+ TOGETHER: 'together',
25
+ FIREWORKS: 'fireworks',
26
+ DEEPINFRA: 'deepinfra',
27
+ PERPLEXITY: 'perplexity',
28
+ COHERE: 'cohere',
29
+ OLLAMA: 'ollama',
30
+ DOUBAO: 'doubao',
31
+ MINIMAX: 'minimax',
32
+ } as const;
33
+
34
+ export type ProviderId = typeof PROVIDER_ID[keyof typeof PROVIDER_ID];
35
+
36
+ export const PROVIDERS: Record<string, Provider> = {
37
+ [PROVIDER_ID.OPENAI]: {
38
+ id: PROVIDER_ID.OPENAI,
39
+ name: 'OpenAI',
40
+ baseUrl: 'https://api.openai.com/v1',
41
+ needsApiKey: true,
42
+ apiFormat: 'openai',
43
+ supportsModelsApi: true,
44
+ icon: `${ICON_CDN_BASE}/openai.svg`,
45
+ },
46
+ [PROVIDER_ID.ANTHROPIC]: {
47
+ id: PROVIDER_ID.ANTHROPIC,
48
+ name: 'Anthropic (Claude)',
49
+ baseUrl: 'https://api.anthropic.com/v1',
50
+ needsApiKey: true,
51
+ apiFormat: 'anthropic',
52
+ supportsModelsApi: false,
53
+ icon: `${ICON_CDN_BASE}/anthropic.svg`,
54
+ },
55
+ [PROVIDER_ID.GEMINI]: {
56
+ id: PROVIDER_ID.GEMINI,
57
+ name: 'Google Gemini',
58
+ baseUrl: 'https://generativelanguage.googleapis.com/v1beta',
59
+ needsApiKey: true,
60
+ apiFormat: 'gemini',
61
+ supportsModelsApi: true,
62
+ icon: `${ICON_CDN_BASE}/gemini.svg`,
63
+ },
64
+ [PROVIDER_ID.OPENROUTER]: {
65
+ id: PROVIDER_ID.OPENROUTER,
66
+ name: 'OpenRouter',
67
+ baseUrl: 'https://openrouter.ai/api/v1',
68
+ needsApiKey: true,
69
+ apiFormat: 'openai',
70
+ supportsModelsApi: true,
71
+ icon: `${ICON_CDN_BASE}/openrouter.svg`,
72
+ },
73
+ [PROVIDER_ID.DEEPSEEK]: {
74
+ id: PROVIDER_ID.DEEPSEEK,
75
+ name: 'DeepSeek',
76
+ baseUrl: 'https://api.deepseek.com',
77
+ needsApiKey: true,
78
+ apiFormat: 'openai',
79
+ supportsModelsApi: true,
80
+ icon: `${ICON_CDN_BASE}/deepseek.svg`,
81
+ },
82
+ [PROVIDER_ID.MOONSHOT]: {
83
+ id: PROVIDER_ID.MOONSHOT,
84
+ name: 'Moonshot (Kimi)',
85
+ baseUrl: 'https://api.moonshot.cn/v1',
86
+ needsApiKey: true,
87
+ apiFormat: 'openai',
88
+ supportsModelsApi: true,
89
+ icon: `${ICON_CDN_BASE}/moonshot.svg`,
90
+ },
91
+ [PROVIDER_ID.QWEN]: {
92
+ id: PROVIDER_ID.QWEN,
93
+ name: '通义千问 (Qwen)',
94
+ baseUrl: 'https://dashscope.aliyuncs.com/compatible-mode/v1',
95
+ needsApiKey: true,
96
+ apiFormat: 'openai',
97
+ supportsModelsApi: true,
98
+ icon: `${ICON_CDN_BASE}/qwen.svg`,
99
+ },
100
+ [PROVIDER_ID.ZHIPU]: {
101
+ id: PROVIDER_ID.ZHIPU,
102
+ name: '智谱 AI (GLM)',
103
+ baseUrl: 'https://open.bigmodel.cn/api/paas/v4',
104
+ needsApiKey: true,
105
+ apiFormat: 'openai',
106
+ supportsModelsApi: true,
107
+ icon: `${ICON_CDN_BASE}/zhipu.svg`,
108
+ },
109
+ [PROVIDER_ID.SILICONFLOW]: {
110
+ id: PROVIDER_ID.SILICONFLOW,
111
+ name: '硅基流动 (siliconflow)',
112
+ baseUrl: 'https://api.siliconflow.cn/v1',
113
+ needsApiKey: true,
114
+ apiFormat: 'openai',
115
+ supportsModelsApi: true,
116
+ icon: `${ICON_CDN_BASE}/siliconcloud.svg`,
117
+ },
118
+
119
+ [PROVIDER_ID.DOUBAO]: {
120
+ id: PROVIDER_ID.DOUBAO,
121
+ name: '火山方舟 (Doubao)',
122
+ baseUrl: 'https://ark.cn-beijing.volces.com/api/v3',
123
+ needsApiKey: true,
124
+ apiFormat: 'openai',
125
+ supportsModelsApi: true,
126
+ icon: `${ICON_CDN_BASE}/doubao.svg`,
127
+ },
128
+ [PROVIDER_ID.MINIMAX]: {
129
+ id: PROVIDER_ID.MINIMAX,
130
+ name: 'MiniMax',
131
+ baseUrl: 'https://api.minimax.io/v1',
132
+ needsApiKey: true,
133
+ apiFormat: 'openai',
134
+ supportsModelsApi: false,
135
+ icon: `${ICON_CDN_BASE}/minimax.svg`,
136
+ },
137
+ [PROVIDER_ID.XAI]: {
138
+ id: PROVIDER_ID.XAI,
139
+ name: 'xAI (Grok)',
140
+ baseUrl: 'https://api.x.ai/v1',
141
+ needsApiKey: true,
142
+ apiFormat: 'openai',
143
+ supportsModelsApi: true,
144
+ icon: `${ICON_CDN_BASE}/grok.svg`,
145
+ },
146
+ [PROVIDER_ID.GROQ]: {
147
+ id: PROVIDER_ID.GROQ,
148
+ name: 'Groq',
149
+ baseUrl: 'https://api.groq.com/openai/v1',
150
+ needsApiKey: true,
151
+ apiFormat: 'openai',
152
+ supportsModelsApi: true,
153
+ icon: `${ICON_CDN_BASE}/groq.svg`,
154
+ },
155
+ [PROVIDER_ID.MISTRAL]: {
156
+ id: PROVIDER_ID.MISTRAL,
157
+ name: 'Mistral AI',
158
+ baseUrl: 'https://api.mistral.ai/v1',
159
+ needsApiKey: true,
160
+ apiFormat: 'openai',
161
+ supportsModelsApi: true,
162
+ icon: `${ICON_CDN_BASE}/mistral.svg`,
163
+ },
164
+ [PROVIDER_ID.TOGETHER]: {
165
+ id: PROVIDER_ID.TOGETHER,
166
+ name: 'Together AI',
167
+ baseUrl: 'https://api.together.xyz/v1',
168
+ needsApiKey: true,
169
+ apiFormat: 'openai',
170
+ supportsModelsApi: true,
171
+ icon: `${ICON_CDN_BASE}/together.svg`,
172
+ },
173
+ [PROVIDER_ID.FIREWORKS]: {
174
+ id: PROVIDER_ID.FIREWORKS,
175
+ name: 'Fireworks AI',
176
+ baseUrl: 'https://api.fireworks.ai/inference/v1',
177
+ needsApiKey: true,
178
+ apiFormat: 'openai',
179
+ supportsModelsApi: true,
180
+ icon: `${ICON_CDN_BASE}/fireworks.svg`,
181
+ },
182
+ [PROVIDER_ID.DEEPINFRA]: {
183
+ id: PROVIDER_ID.DEEPINFRA,
184
+ name: 'DeepInfra',
185
+ baseUrl: 'https://api.deepinfra.com/v1/openai',
186
+ needsApiKey: true,
187
+ apiFormat: 'openai',
188
+ supportsModelsApi: true,
189
+ icon: `${ICON_CDN_BASE}/deepinfra.svg`,
190
+ },
191
+ [PROVIDER_ID.PERPLEXITY]: {
192
+ id: PROVIDER_ID.PERPLEXITY,
193
+ name: 'Perplexity',
194
+ baseUrl: 'https://api.perplexity.ai',
195
+ needsApiKey: true,
196
+ apiFormat: 'openai',
197
+ supportsModelsApi: false,
198
+ icon: `${ICON_CDN_BASE}/perplexity.svg`,
199
+ },
200
+ [PROVIDER_ID.COHERE]: {
201
+ id: PROVIDER_ID.COHERE,
202
+ name: 'Cohere',
203
+ baseUrl: 'https://api.cohere.com/v2',
204
+ needsApiKey: true,
205
+ apiFormat: 'cohere',
206
+ supportsModelsApi: true,
207
+ icon: `${ICON_CDN_BASE}/cohere.svg`,
208
+ },
209
+ [PROVIDER_ID.OLLAMA]: {
210
+ id: PROVIDER_ID.OLLAMA,
211
+ name: 'Ollama (Local)',
212
+ baseUrl: 'http://localhost:11434/v1',
213
+ needsApiKey: false,
214
+ apiFormat: 'openai',
215
+ supportsModelsApi: true,
216
+ icon: `${ICON_CDN_BASE}/ollama.svg`,
217
+ },
218
+ };
219
+
220
+ /**
221
+ * Get a provider by ID
222
+ */
223
+ export function getProvider(id: string): Provider | undefined {
224
+ return PROVIDERS[id];
225
+ }
226
+
227
+ /**
228
+ * Get all providers as an array
229
+ */
230
+ export function getAllProviders(): Provider[] {
231
+ return Object.values(PROVIDERS);
232
+ }
233
+
234
+ /**
235
+ * Get providers by API format
236
+ */
237
+ export function getProvidersByFormat(format: Provider['apiFormat']): Provider[] {
238
+ return getAllProviders().filter(p => p.apiFormat === format);
239
+ }