cowork-os 0.3.21 → 0.3.23
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.
- package/README.md +293 -6
- package/connectors/README.md +20 -0
- package/connectors/asana-mcp/README.md +24 -0
- package/connectors/asana-mcp/dist/index.js +427 -0
- package/connectors/asana-mcp/package.json +15 -0
- package/connectors/asana-mcp/src/index.ts +553 -0
- package/connectors/asana-mcp/tsconfig.json +13 -0
- package/connectors/hubspot-mcp/README.md +35 -0
- package/connectors/hubspot-mcp/dist/index.js +454 -0
- package/connectors/hubspot-mcp/package.json +15 -0
- package/connectors/hubspot-mcp/src/index.ts +562 -0
- package/connectors/hubspot-mcp/tsconfig.json +13 -0
- package/connectors/jira-mcp/README.md +49 -0
- package/connectors/jira-mcp/dist/index.js +588 -0
- package/connectors/jira-mcp/package.json +15 -0
- package/connectors/jira-mcp/src/index.ts +711 -0
- package/connectors/jira-mcp/tsconfig.json +13 -0
- package/connectors/linear-mcp/README.md +22 -0
- package/connectors/linear-mcp/dist/index.js +402 -0
- package/connectors/linear-mcp/package.json +15 -0
- package/connectors/linear-mcp/src/index.ts +522 -0
- package/connectors/linear-mcp/tsconfig.json +13 -0
- package/connectors/okta-mcp/README.md +24 -0
- package/connectors/okta-mcp/dist/index.js +411 -0
- package/connectors/okta-mcp/package.json +15 -0
- package/connectors/okta-mcp/src/index.ts +520 -0
- package/connectors/okta-mcp/tsconfig.json +13 -0
- package/connectors/salesforce-mcp/README.md +47 -0
- package/connectors/salesforce-mcp/dist/index.js +584 -0
- package/connectors/salesforce-mcp/package.json +15 -0
- package/connectors/salesforce-mcp/src/index.ts +722 -0
- package/connectors/salesforce-mcp/tsconfig.json +13 -0
- package/connectors/servicenow-mcp/README.md +26 -0
- package/connectors/servicenow-mcp/dist/index.js +400 -0
- package/connectors/servicenow-mcp/package.json +15 -0
- package/connectors/servicenow-mcp/src/index.ts +500 -0
- package/connectors/servicenow-mcp/tsconfig.json +13 -0
- package/connectors/templates/mcp-connector/README.md +31 -0
- package/connectors/templates/mcp-connector/package.json +15 -0
- package/connectors/templates/mcp-connector/src/index.ts +330 -0
- package/connectors/templates/mcp-connector/tsconfig.json +13 -0
- package/connectors/zendesk-mcp/README.md +40 -0
- package/connectors/zendesk-mcp/dist/index.js +431 -0
- package/connectors/zendesk-mcp/package.json +15 -0
- package/connectors/zendesk-mcp/src/index.ts +543 -0
- package/connectors/zendesk-mcp/tsconfig.json +13 -0
- package/dist/electron/electron/agent/daemon.js +25 -0
- package/dist/electron/electron/agent/executor.js +181 -26
- package/dist/electron/electron/agent/llm/anthropic-compatible-provider.js +177 -0
- package/dist/electron/electron/agent/llm/github-copilot-provider.js +97 -0
- package/dist/electron/electron/agent/llm/groq-provider.js +33 -0
- package/dist/electron/electron/agent/llm/index.js +11 -1
- package/dist/electron/electron/agent/llm/kimi-provider.js +33 -0
- package/dist/electron/electron/agent/llm/openai-compatible-provider.js +116 -0
- package/dist/electron/electron/agent/llm/openai-compatible.js +111 -0
- package/dist/electron/electron/agent/llm/openai-oauth.js +2 -1
- package/dist/electron/electron/agent/llm/openrouter-provider.js +1 -1
- package/dist/electron/electron/agent/llm/provider-factory.js +318 -4
- package/dist/electron/electron/agent/llm/types.js +66 -1
- package/dist/electron/electron/agent/llm/xai-provider.js +33 -0
- package/dist/electron/electron/agent/tools/box-tools.js +231 -0
- package/dist/electron/electron/agent/tools/builtin-settings.js +28 -0
- package/dist/electron/electron/agent/tools/dropbox-tools.js +237 -0
- package/dist/electron/electron/agent/tools/google-drive-tools.js +227 -0
- package/dist/electron/electron/agent/tools/notion-tools.js +312 -0
- package/dist/electron/electron/agent/tools/onedrive-tools.js +217 -0
- package/dist/electron/electron/agent/tools/registry.js +541 -0
- package/dist/electron/electron/agent/tools/sharepoint-tools.js +243 -0
- package/dist/electron/electron/agent/tools/shell-tools.js +12 -3
- package/dist/electron/electron/agent/tools/x-tools.js +1 -1
- package/dist/electron/electron/gateway/index.js +1 -0
- package/dist/electron/electron/gateway/router.js +123 -143
- package/dist/electron/electron/ipc/canvas-handlers.js +5 -0
- package/dist/electron/electron/ipc/handlers.js +627 -158
- package/dist/electron/electron/main.js +63 -0
- package/dist/electron/electron/mcp/oauth/connector-oauth.js +333 -0
- package/dist/electron/electron/mcp/registry/MCPRegistryManager.js +503 -154
- package/dist/electron/electron/memory/MemoryService.js +1 -1
- package/dist/electron/electron/preload.js +74 -1
- package/dist/electron/electron/settings/box-manager.js +54 -0
- package/dist/electron/electron/settings/dropbox-manager.js +54 -0
- package/dist/electron/electron/settings/google-drive-manager.js +54 -0
- package/dist/electron/electron/settings/notion-manager.js +56 -0
- package/dist/electron/electron/settings/onedrive-manager.js +54 -0
- package/dist/electron/electron/settings/sharepoint-manager.js +54 -0
- package/dist/electron/electron/utils/box-api.js +153 -0
- package/dist/electron/electron/utils/dropbox-api.js +144 -0
- package/dist/electron/electron/utils/env-migration.js +19 -0
- package/dist/electron/electron/utils/google-drive-api.js +152 -0
- package/dist/electron/electron/utils/notion-api.js +103 -0
- package/dist/electron/electron/utils/onedrive-api.js +113 -0
- package/dist/electron/electron/utils/sharepoint-api.js +109 -0
- package/dist/electron/electron/utils/validation.js +82 -3
- package/dist/electron/electron/utils/x-cli.js +1 -1
- package/dist/electron/shared/channelMessages.js +284 -3
- package/dist/electron/shared/llm-provider-catalog.js +198 -0
- package/dist/electron/shared/types.js +88 -1
- package/package.json +12 -2
- package/src/electron/agent/executor.ts +205 -28
- package/src/electron/agent/llm/anthropic-compatible-provider.ts +214 -0
- package/src/electron/agent/llm/github-copilot-provider.ts +117 -0
- package/src/electron/agent/llm/groq-provider.ts +39 -0
- package/src/electron/agent/llm/index.ts +5 -0
- package/src/electron/agent/llm/kimi-provider.ts +39 -0
- package/src/electron/agent/llm/openai-compatible-provider.ts +153 -0
- package/src/electron/agent/llm/openai-compatible.ts +133 -0
- package/src/electron/agent/llm/openai-oauth.ts +2 -1
- package/src/electron/agent/llm/openrouter-provider.ts +2 -1
- package/src/electron/agent/llm/provider-factory.ts +414 -6
- package/src/electron/agent/llm/types.ts +90 -1
- package/src/electron/agent/llm/xai-provider.ts +39 -0
- package/src/electron/agent/tools/box-tools.ts +239 -0
- package/src/electron/agent/tools/builtin-settings.ts +34 -0
- package/src/electron/agent/tools/dropbox-tools.ts +237 -0
- package/src/electron/agent/tools/google-drive-tools.ts +228 -0
- package/src/electron/agent/tools/notion-tools.ts +330 -0
- package/src/electron/agent/tools/onedrive-tools.ts +217 -0
- package/src/electron/agent/tools/registry.ts +565 -0
- package/src/electron/agent/tools/sharepoint-tools.ts +247 -0
- package/src/electron/agent/tools/shell-tools.ts +11 -3
- package/src/electron/agent/tools/x-tools.ts +1 -1
- package/src/electron/database/SecureSettingsRepository.ts +7 -1
- package/src/electron/gateway/index.ts +1 -0
- package/src/electron/gateway/router.ts +134 -149
- package/src/electron/ipc/canvas-handlers.ts +10 -0
- package/src/electron/ipc/handlers.ts +673 -153
- package/src/electron/main.ts +35 -0
- package/src/electron/mcp/oauth/connector-oauth.ts +448 -0
- package/src/electron/mcp/registry/MCPRegistryManager.ts +343 -12
- package/src/electron/memory/MemoryService.ts +5 -1
- package/src/electron/preload.ts +167 -4
- package/src/electron/settings/box-manager.ts +58 -0
- package/src/electron/settings/dropbox-manager.ts +58 -0
- package/src/electron/settings/google-drive-manager.ts +58 -0
- package/src/electron/settings/notion-manager.ts +60 -0
- package/src/electron/settings/onedrive-manager.ts +58 -0
- package/src/electron/settings/sharepoint-manager.ts +58 -0
- package/src/electron/utils/box-api.ts +184 -0
- package/src/electron/utils/dropbox-api.ts +171 -0
- package/src/electron/utils/env-migration.ts +22 -0
- package/src/electron/utils/google-drive-api.ts +183 -0
- package/src/electron/utils/notion-api.ts +126 -0
- package/src/electron/utils/onedrive-api.ts +137 -0
- package/src/electron/utils/sharepoint-api.ts +132 -0
- package/src/electron/utils/validation.ts +102 -1
- package/src/electron/utils/x-cli.ts +1 -1
- package/src/renderer/App.tsx +20 -2
- package/src/renderer/components/BoxSettings.tsx +203 -0
- package/src/renderer/components/BrowserView.tsx +101 -0
- package/src/renderer/components/BuiltinToolsSettings.tsx +105 -0
- package/src/renderer/components/CanvasPreview.tsx +68 -1
- package/src/renderer/components/ConnectorEnvModal.tsx +116 -0
- package/src/renderer/components/ConnectorSetupModal.tsx +566 -0
- package/src/renderer/components/ConnectorsSettings.tsx +397 -0
- package/src/renderer/components/DropboxSettings.tsx +202 -0
- package/src/renderer/components/GoogleDriveSettings.tsx +201 -0
- package/src/renderer/components/MCPSettings.tsx +56 -0
- package/src/renderer/components/MainContent.tsx +270 -34
- package/src/renderer/components/NotionSettings.tsx +231 -0
- package/src/renderer/components/Onboarding/Onboarding.tsx +13 -1
- package/src/renderer/components/OnboardingModal.tsx +70 -1
- package/src/renderer/components/OneDriveSettings.tsx +212 -0
- package/src/renderer/components/Settings.tsx +611 -8
- package/src/renderer/components/SharePointSettings.tsx +224 -0
- package/src/renderer/components/Sidebar.tsx +25 -9
- package/src/renderer/hooks/useOnboardingFlow.ts +21 -0
- package/src/renderer/styles/index.css +438 -25
- package/src/shared/channelMessages.ts +367 -4
- package/src/shared/llm-provider-catalog.ts +217 -0
- package/src/shared/types.ts +226 -1
|
@@ -16,11 +16,114 @@ import { OllamaProvider } from './ollama-provider';
|
|
|
16
16
|
import { GeminiProvider } from './gemini-provider';
|
|
17
17
|
import { OpenRouterProvider } from './openrouter-provider';
|
|
18
18
|
import { OpenAIProvider } from './openai-provider';
|
|
19
|
+
import { GroqProvider } from './groq-provider';
|
|
20
|
+
import { XAIProvider } from './xai-provider';
|
|
21
|
+
import { KimiProvider } from './kimi-provider';
|
|
22
|
+
import { AnthropicCompatibleProvider } from './anthropic-compatible-provider';
|
|
23
|
+
import { OpenAICompatibleProvider } from './openai-compatible-provider';
|
|
24
|
+
import { GitHubCopilotProvider } from './github-copilot-provider';
|
|
19
25
|
import { SecureSettingsRepository } from '../../database/SecureSettingsRepository';
|
|
26
|
+
import {
|
|
27
|
+
CUSTOM_PROVIDER_CATALOG,
|
|
28
|
+
CUSTOM_PROVIDER_MAP,
|
|
29
|
+
CUSTOM_PROVIDER_IDS,
|
|
30
|
+
type ProviderCatalogEntry,
|
|
31
|
+
} from '../../../shared/llm-provider-catalog';
|
|
32
|
+
import type { CustomProviderConfig } from '../../../shared/types';
|
|
20
33
|
|
|
21
34
|
const LEGACY_SETTINGS_FILE = 'llm-settings.json';
|
|
22
35
|
const MASKED_VALUE = '***configured***';
|
|
23
36
|
const ENCRYPTED_PREFIX = 'encrypted:';
|
|
37
|
+
const CUSTOM_PROVIDER_ALIASES: Partial<Record<LLMProviderType, LLMProviderType>> = {
|
|
38
|
+
'kimi-coding': 'kimi-code',
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
function resolveCustomProviderId(providerType: LLMProviderType): LLMProviderType {
|
|
42
|
+
return CUSTOM_PROVIDER_ALIASES[providerType] || providerType;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function getCustomProviderEntry(providerType: LLMProviderType): ProviderCatalogEntry | undefined {
|
|
46
|
+
return CUSTOM_PROVIDER_MAP.get(resolveCustomProviderId(providerType));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function getCustomProviderConfig(
|
|
50
|
+
customProviders: Record<string, CustomProviderConfig> | undefined,
|
|
51
|
+
providerType: LLMProviderType
|
|
52
|
+
): CustomProviderConfig | undefined {
|
|
53
|
+
if (!customProviders) return undefined;
|
|
54
|
+
const resolved = resolveCustomProviderId(providerType);
|
|
55
|
+
const resolvedConfig = customProviders[resolved];
|
|
56
|
+
if (resolvedConfig) {
|
|
57
|
+
return resolvedConfig;
|
|
58
|
+
}
|
|
59
|
+
const fallbackConfig = customProviders[providerType];
|
|
60
|
+
if (fallbackConfig && resolved !== providerType) {
|
|
61
|
+
console.log(`[LLMProviderFactory] Custom provider config not found for "${resolved}", falling back to "${providerType}".`);
|
|
62
|
+
}
|
|
63
|
+
return fallbackConfig;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function isCustomProviderConfigured(
|
|
67
|
+
entry: ProviderCatalogEntry,
|
|
68
|
+
config?: CustomProviderConfig
|
|
69
|
+
): boolean {
|
|
70
|
+
if (!config) return false;
|
|
71
|
+
const hasApiKey = !!config.apiKey?.trim();
|
|
72
|
+
const hasBaseUrl = !!config.baseUrl?.trim() || !!entry.baseUrl;
|
|
73
|
+
const hasUserConfig = hasApiKey || !!config.baseUrl?.trim() || !!config.model?.trim();
|
|
74
|
+
|
|
75
|
+
if (!hasUserConfig) return false;
|
|
76
|
+
|
|
77
|
+
if (entry.apiKeyOptional) {
|
|
78
|
+
return entry.requiresBaseUrl ? hasBaseUrl : hasApiKey || hasBaseUrl;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return entry.requiresBaseUrl ? hasApiKey && hasBaseUrl : hasApiKey;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function createCustomProvider(
|
|
85
|
+
config: LLMProviderConfig,
|
|
86
|
+
entry: ProviderCatalogEntry,
|
|
87
|
+
resolvedType: LLMProviderType
|
|
88
|
+
): LLMProvider {
|
|
89
|
+
if (resolvedType === 'github-copilot') {
|
|
90
|
+
return new GitHubCopilotProvider(config);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const apiKey = config.providerApiKey || '';
|
|
94
|
+
const baseUrl = config.providerBaseUrl || entry.baseUrl || '';
|
|
95
|
+
|
|
96
|
+
if (entry.requiresBaseUrl && !baseUrl) {
|
|
97
|
+
throw new Error(`${entry.name} base URL is required. Configure it in Settings.`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (!apiKey && !entry.apiKeyOptional) {
|
|
101
|
+
throw new Error(`${entry.name} API key is required. Configure it in Settings.`);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const model = config.model || entry.defaultModel;
|
|
105
|
+
if (!model) {
|
|
106
|
+
throw new Error(`${entry.name} model is required. Configure it in Settings.`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (entry.compatibility === 'openai') {
|
|
110
|
+
return new OpenAICompatibleProvider({
|
|
111
|
+
type: resolvedType,
|
|
112
|
+
providerName: entry.name,
|
|
113
|
+
apiKey,
|
|
114
|
+
baseUrl,
|
|
115
|
+
defaultModel: model,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return new AnthropicCompatibleProvider({
|
|
120
|
+
type: resolvedType,
|
|
121
|
+
providerName: entry.name,
|
|
122
|
+
apiKey,
|
|
123
|
+
baseUrl,
|
|
124
|
+
defaultModel: model,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
24
127
|
|
|
25
128
|
// ============ Legacy Encryption Functions (for migration only) ============
|
|
26
129
|
// These functions are only used to decrypt settings from legacy JSON files
|
|
@@ -159,6 +262,38 @@ function sanitizeSettings(settings: LLMSettings): LLMSettings {
|
|
|
159
262
|
};
|
|
160
263
|
}
|
|
161
264
|
|
|
265
|
+
if (sanitized.groq) {
|
|
266
|
+
sanitized.groq = {
|
|
267
|
+
...sanitized.groq,
|
|
268
|
+
apiKey: decryptSecret(sanitized.groq.apiKey),
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (sanitized.xai) {
|
|
273
|
+
sanitized.xai = {
|
|
274
|
+
...sanitized.xai,
|
|
275
|
+
apiKey: decryptSecret(sanitized.xai.apiKey),
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (sanitized.kimi) {
|
|
280
|
+
sanitized.kimi = {
|
|
281
|
+
...sanitized.kimi,
|
|
282
|
+
apiKey: decryptSecret(sanitized.kimi.apiKey),
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (sanitized.customProviders) {
|
|
287
|
+
const normalized: Record<string, CustomProviderConfig> = {};
|
|
288
|
+
for (const [key, value] of Object.entries(sanitized.customProviders)) {
|
|
289
|
+
normalized[key] = {
|
|
290
|
+
...value,
|
|
291
|
+
apiKey: decryptSecret(value.apiKey),
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
sanitized.customProviders = normalized;
|
|
295
|
+
}
|
|
296
|
+
|
|
162
297
|
return sanitized;
|
|
163
298
|
}
|
|
164
299
|
|
|
@@ -204,6 +339,7 @@ export interface LLMSettings {
|
|
|
204
339
|
openrouter?: {
|
|
205
340
|
apiKey?: string;
|
|
206
341
|
model?: string;
|
|
342
|
+
baseUrl?: string;
|
|
207
343
|
};
|
|
208
344
|
openai?: {
|
|
209
345
|
apiKey?: string;
|
|
@@ -214,12 +350,31 @@ export interface LLMSettings {
|
|
|
214
350
|
tokenExpiresAt?: number;
|
|
215
351
|
authMethod?: 'api_key' | 'oauth';
|
|
216
352
|
};
|
|
353
|
+
groq?: {
|
|
354
|
+
apiKey?: string;
|
|
355
|
+
model?: string;
|
|
356
|
+
baseUrl?: string;
|
|
357
|
+
};
|
|
358
|
+
xai?: {
|
|
359
|
+
apiKey?: string;
|
|
360
|
+
model?: string;
|
|
361
|
+
baseUrl?: string;
|
|
362
|
+
};
|
|
363
|
+
kimi?: {
|
|
364
|
+
apiKey?: string;
|
|
365
|
+
model?: string;
|
|
366
|
+
baseUrl?: string;
|
|
367
|
+
};
|
|
368
|
+
customProviders?: Record<string, CustomProviderConfig>;
|
|
217
369
|
// Cached models from API (populated when user refreshes)
|
|
218
370
|
cachedGeminiModels?: CachedModelInfo[];
|
|
219
371
|
cachedOpenRouterModels?: CachedModelInfo[];
|
|
220
372
|
cachedOllamaModels?: CachedModelInfo[];
|
|
221
373
|
cachedBedrockModels?: CachedModelInfo[];
|
|
222
374
|
cachedOpenAIModels?: CachedModelInfo[];
|
|
375
|
+
cachedGroqModels?: CachedModelInfo[];
|
|
376
|
+
cachedXaiModels?: CachedModelInfo[];
|
|
377
|
+
cachedKimiModels?: CachedModelInfo[];
|
|
223
378
|
}
|
|
224
379
|
|
|
225
380
|
const DEFAULT_SETTINGS: LLMSettings = {
|
|
@@ -235,6 +390,22 @@ export class LLMProviderFactory {
|
|
|
235
390
|
private static cachedSettings: LLMSettings | null = null;
|
|
236
391
|
private static migrationCompleted = false;
|
|
237
392
|
|
|
393
|
+
private static normalizeCustomProviders(settings: LLMSettings): void {
|
|
394
|
+
if (!settings.customProviders) return;
|
|
395
|
+
|
|
396
|
+
const legacyKey = settings.customProviders['kimi-coding'];
|
|
397
|
+
if (legacyKey && !settings.customProviders['kimi-code']) {
|
|
398
|
+
settings.customProviders['kimi-code'] = legacyKey;
|
|
399
|
+
}
|
|
400
|
+
if (settings.customProviders['kimi-coding']) {
|
|
401
|
+
delete settings.customProviders['kimi-coding'];
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
if (settings.providerType === 'kimi-coding') {
|
|
405
|
+
settings.providerType = 'kimi-code';
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
238
409
|
/**
|
|
239
410
|
* Initialize the factory
|
|
240
411
|
*/
|
|
@@ -330,6 +501,7 @@ export class LLMProviderFactory {
|
|
|
330
501
|
const stored = repository.load<LLMSettings>('llm');
|
|
331
502
|
if (stored) {
|
|
332
503
|
settings = { ...DEFAULT_SETTINGS, ...stored };
|
|
504
|
+
this.normalizeCustomProviders(settings);
|
|
333
505
|
settingsExist = true;
|
|
334
506
|
}
|
|
335
507
|
}
|
|
@@ -369,6 +541,15 @@ export class LLMProviderFactory {
|
|
|
369
541
|
if (settings.openai?.apiKey || settings.openai?.accessToken) {
|
|
370
542
|
return 'openai';
|
|
371
543
|
}
|
|
544
|
+
if (settings.groq?.apiKey) {
|
|
545
|
+
return 'groq';
|
|
546
|
+
}
|
|
547
|
+
if (settings.xai?.apiKey) {
|
|
548
|
+
return 'xai';
|
|
549
|
+
}
|
|
550
|
+
if (settings.kimi?.apiKey) {
|
|
551
|
+
return 'kimi';
|
|
552
|
+
}
|
|
372
553
|
if (settings.bedrock?.accessKeyId || settings.bedrock?.profile) {
|
|
373
554
|
return 'bedrock';
|
|
374
555
|
}
|
|
@@ -376,6 +557,15 @@ export class LLMProviderFactory {
|
|
|
376
557
|
return 'ollama';
|
|
377
558
|
}
|
|
378
559
|
|
|
560
|
+
if (settings.customProviders) {
|
|
561
|
+
for (const entry of CUSTOM_PROVIDER_CATALOG) {
|
|
562
|
+
const config = getCustomProviderConfig(settings.customProviders, entry.id);
|
|
563
|
+
if (isCustomProviderConfigured(entry, config)) {
|
|
564
|
+
return entry.id;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
|
|
379
569
|
// No valid credentials detected - user needs to configure via Settings
|
|
380
570
|
return null;
|
|
381
571
|
}
|
|
@@ -418,10 +608,22 @@ export class LLMProviderFactory {
|
|
|
418
608
|
static createProvider(overrideConfig?: Partial<LLMProviderConfig>): LLMProvider {
|
|
419
609
|
const settings = this.loadSettings();
|
|
420
610
|
const providerType = overrideConfig?.type || settings.providerType;
|
|
611
|
+
const customConfig = getCustomProviderConfig(settings.customProviders, providerType);
|
|
421
612
|
|
|
422
613
|
const config: LLMProviderConfig = {
|
|
423
614
|
type: providerType,
|
|
424
|
-
model: this.getModelId(
|
|
615
|
+
model: this.getModelId(
|
|
616
|
+
settings.modelKey,
|
|
617
|
+
providerType,
|
|
618
|
+
settings.ollama?.model,
|
|
619
|
+
settings.gemini?.model,
|
|
620
|
+
settings.openrouter?.model,
|
|
621
|
+
settings.openai?.model,
|
|
622
|
+
settings.groq?.model,
|
|
623
|
+
settings.xai?.model,
|
|
624
|
+
settings.kimi?.model,
|
|
625
|
+
settings.customProviders
|
|
626
|
+
),
|
|
425
627
|
// Anthropic config - from settings only
|
|
426
628
|
anthropicApiKey: normalizeSecret(overrideConfig?.anthropicApiKey) || settings.anthropic?.apiKey,
|
|
427
629
|
// Bedrock config - from settings only
|
|
@@ -437,11 +639,24 @@ export class LLMProviderFactory {
|
|
|
437
639
|
geminiApiKey: normalizeSecret(overrideConfig?.geminiApiKey) || settings.gemini?.apiKey,
|
|
438
640
|
// OpenRouter config - from settings only
|
|
439
641
|
openrouterApiKey: normalizeSecret(overrideConfig?.openrouterApiKey) || settings.openrouter?.apiKey,
|
|
642
|
+
openrouterBaseUrl: overrideConfig?.openrouterBaseUrl || settings.openrouter?.baseUrl,
|
|
440
643
|
// OpenAI config - from settings only
|
|
441
644
|
openaiApiKey: normalizeSecret(overrideConfig?.openaiApiKey) || settings.openai?.apiKey,
|
|
442
645
|
openaiAccessToken: normalizeSecret(overrideConfig?.openaiAccessToken) || settings.openai?.accessToken,
|
|
443
646
|
openaiRefreshToken: settings.openai?.refreshToken,
|
|
444
647
|
openaiTokenExpiresAt: settings.openai?.tokenExpiresAt,
|
|
648
|
+
// Groq config - from settings only
|
|
649
|
+
groqApiKey: normalizeSecret(overrideConfig?.groqApiKey) || settings.groq?.apiKey,
|
|
650
|
+
groqBaseUrl: overrideConfig?.groqBaseUrl || settings.groq?.baseUrl,
|
|
651
|
+
// xAI config - from settings only
|
|
652
|
+
xaiApiKey: normalizeSecret(overrideConfig?.xaiApiKey) || settings.xai?.apiKey,
|
|
653
|
+
xaiBaseUrl: overrideConfig?.xaiBaseUrl || settings.xai?.baseUrl,
|
|
654
|
+
// Kimi config - from settings only
|
|
655
|
+
kimiApiKey: normalizeSecret(overrideConfig?.kimiApiKey) || settings.kimi?.apiKey,
|
|
656
|
+
kimiBaseUrl: overrideConfig?.kimiBaseUrl || settings.kimi?.baseUrl,
|
|
657
|
+
// Custom provider config
|
|
658
|
+
providerApiKey: normalizeSecret(overrideConfig?.providerApiKey) || customConfig?.apiKey,
|
|
659
|
+
providerBaseUrl: overrideConfig?.providerBaseUrl || customConfig?.baseUrl,
|
|
445
660
|
};
|
|
446
661
|
|
|
447
662
|
return this.createProviderFromConfig(config);
|
|
@@ -451,6 +666,12 @@ export class LLMProviderFactory {
|
|
|
451
666
|
* Create a provider from explicit config
|
|
452
667
|
*/
|
|
453
668
|
static createProviderFromConfig(config: LLMProviderConfig): LLMProvider {
|
|
669
|
+
const customEntry = getCustomProviderEntry(config.type);
|
|
670
|
+
if (customEntry) {
|
|
671
|
+
const resolvedType = resolveCustomProviderId(config.type);
|
|
672
|
+
return createCustomProvider(config, customEntry, resolvedType);
|
|
673
|
+
}
|
|
674
|
+
|
|
454
675
|
switch (config.type) {
|
|
455
676
|
case 'anthropic':
|
|
456
677
|
return new AnthropicProvider(config);
|
|
@@ -464,6 +685,12 @@ export class LLMProviderFactory {
|
|
|
464
685
|
return new OpenRouterProvider(config);
|
|
465
686
|
case 'openai':
|
|
466
687
|
return new OpenAIProvider(config);
|
|
688
|
+
case 'groq':
|
|
689
|
+
return new GroqProvider(config);
|
|
690
|
+
case 'xai':
|
|
691
|
+
return new XAIProvider(config);
|
|
692
|
+
case 'kimi':
|
|
693
|
+
return new KimiProvider(config);
|
|
467
694
|
default:
|
|
468
695
|
throw new Error(`Unknown provider type: ${config.type}`);
|
|
469
696
|
}
|
|
@@ -472,7 +699,24 @@ export class LLMProviderFactory {
|
|
|
472
699
|
/**
|
|
473
700
|
* Get the model ID for a provider
|
|
474
701
|
*/
|
|
475
|
-
static getModelId(
|
|
702
|
+
static getModelId(
|
|
703
|
+
modelKey: ModelKey | string,
|
|
704
|
+
providerType: LLMProviderType,
|
|
705
|
+
ollamaModel?: string,
|
|
706
|
+
geminiModel?: string,
|
|
707
|
+
openrouterModel?: string,
|
|
708
|
+
openaiModel?: string,
|
|
709
|
+
groqModel?: string,
|
|
710
|
+
xaiModel?: string,
|
|
711
|
+
kimiModel?: string,
|
|
712
|
+
customProviders?: Record<string, CustomProviderConfig>
|
|
713
|
+
): string {
|
|
714
|
+
const customEntry = getCustomProviderEntry(providerType);
|
|
715
|
+
if (customEntry) {
|
|
716
|
+
const customConfig = getCustomProviderConfig(customProviders, providerType);
|
|
717
|
+
return customConfig?.model || customEntry.defaultModel;
|
|
718
|
+
}
|
|
719
|
+
|
|
476
720
|
// For Ollama, use the specific Ollama model if provided
|
|
477
721
|
if (providerType === 'ollama') {
|
|
478
722
|
return ollamaModel || 'gpt-oss:20b';
|
|
@@ -493,6 +737,21 @@ export class LLMProviderFactory {
|
|
|
493
737
|
return openaiModel || 'gpt-4o-mini';
|
|
494
738
|
}
|
|
495
739
|
|
|
740
|
+
// For Groq, use the specific model if provided or default
|
|
741
|
+
if (providerType === 'groq') {
|
|
742
|
+
return groqModel || 'llama-3.1-8b-instant';
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
// For xAI, use the specific model if provided or default
|
|
746
|
+
if (providerType === 'xai') {
|
|
747
|
+
return xaiModel || 'grok-4-fast-non-reasoning';
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
// For Kimi, use the specific model if provided or default
|
|
751
|
+
if (providerType === 'kimi') {
|
|
752
|
+
return kimiModel || 'kimi-k2.5';
|
|
753
|
+
}
|
|
754
|
+
|
|
496
755
|
// For other providers, look up in MODELS
|
|
497
756
|
const model = MODELS[modelKey as ModelKey];
|
|
498
757
|
if (!model) {
|
|
@@ -529,7 +788,7 @@ export class LLMProviderFactory {
|
|
|
529
788
|
}> {
|
|
530
789
|
const settings = this.loadSettings();
|
|
531
790
|
|
|
532
|
-
|
|
791
|
+
const builtIns = [
|
|
533
792
|
{
|
|
534
793
|
type: 'anthropic' as LLMProviderType,
|
|
535
794
|
name: 'Anthropic API',
|
|
@@ -550,6 +809,21 @@ export class LLMProviderFactory {
|
|
|
550
809
|
name: 'OpenAI',
|
|
551
810
|
configured: !!(settings.openai?.apiKey || settings.openai?.accessToken),
|
|
552
811
|
},
|
|
812
|
+
{
|
|
813
|
+
type: 'groq' as LLMProviderType,
|
|
814
|
+
name: 'Groq',
|
|
815
|
+
configured: !!settings.groq?.apiKey,
|
|
816
|
+
},
|
|
817
|
+
{
|
|
818
|
+
type: 'xai' as LLMProviderType,
|
|
819
|
+
name: 'xAI (Grok)',
|
|
820
|
+
configured: !!settings.xai?.apiKey,
|
|
821
|
+
},
|
|
822
|
+
{
|
|
823
|
+
type: 'kimi' as LLMProviderType,
|
|
824
|
+
name: 'Kimi',
|
|
825
|
+
configured: !!settings.kimi?.apiKey,
|
|
826
|
+
},
|
|
553
827
|
{
|
|
554
828
|
type: 'bedrock' as LLMProviderType,
|
|
555
829
|
name: 'AWS Bedrock',
|
|
@@ -561,6 +835,17 @@ export class LLMProviderFactory {
|
|
|
561
835
|
configured: !!(settings.ollama?.baseUrl || settings.ollama?.model),
|
|
562
836
|
},
|
|
563
837
|
];
|
|
838
|
+
|
|
839
|
+
const customProviders = CUSTOM_PROVIDER_CATALOG.map((entry: ProviderCatalogEntry) => {
|
|
840
|
+
const config = getCustomProviderConfig(settings.customProviders, entry.id);
|
|
841
|
+
return {
|
|
842
|
+
type: entry.id,
|
|
843
|
+
name: entry.name,
|
|
844
|
+
configured: isCustomProviderConfigured(entry, config),
|
|
845
|
+
};
|
|
846
|
+
});
|
|
847
|
+
|
|
848
|
+
return [...builtIns, ...customProviders];
|
|
564
849
|
}
|
|
565
850
|
|
|
566
851
|
/**
|
|
@@ -755,11 +1040,13 @@ export class LLMProviderFactory {
|
|
|
755
1040
|
/**
|
|
756
1041
|
* Fetch available OpenRouter models from the API
|
|
757
1042
|
*/
|
|
758
|
-
static async getOpenRouterModels(apiKey?: string): Promise<Array<{ id: string; name: string; context_length: number }>> {
|
|
1043
|
+
static async getOpenRouterModels(apiKey?: string, baseUrl?: string): Promise<Array<{ id: string; name: string; context_length: number }>> {
|
|
759
1044
|
const settings = this.loadSettings();
|
|
760
1045
|
// Normalize empty strings to undefined
|
|
761
1046
|
const normalizedApiKey = apiKey?.trim() || undefined;
|
|
762
1047
|
const key = normalizedApiKey || settings.openrouter?.apiKey;
|
|
1048
|
+
const normalizedBaseUrl = baseUrl?.trim() || undefined;
|
|
1049
|
+
const resolvedBaseUrl = normalizedBaseUrl || settings.openrouter?.baseUrl;
|
|
763
1050
|
|
|
764
1051
|
const defaultModels = [
|
|
765
1052
|
{ id: 'anthropic/claude-3.5-sonnet', name: 'Claude 3.5 Sonnet', context_length: 200000 },
|
|
@@ -780,6 +1067,7 @@ export class LLMProviderFactory {
|
|
|
780
1067
|
type: 'openrouter',
|
|
781
1068
|
model: '',
|
|
782
1069
|
openrouterApiKey: key,
|
|
1070
|
+
openrouterBaseUrl: resolvedBaseUrl,
|
|
783
1071
|
});
|
|
784
1072
|
return await provider.getAvailableModels();
|
|
785
1073
|
} catch (error: any) {
|
|
@@ -871,6 +1159,109 @@ export class LLMProviderFactory {
|
|
|
871
1159
|
}
|
|
872
1160
|
}
|
|
873
1161
|
|
|
1162
|
+
/**
|
|
1163
|
+
* Fetch available Groq models from the API
|
|
1164
|
+
*/
|
|
1165
|
+
static async getGroqModels(apiKey?: string, baseUrl?: string): Promise<Array<{ id: string; name: string }>> {
|
|
1166
|
+
const settings = this.loadSettings();
|
|
1167
|
+
const normalizedApiKey = apiKey?.trim() || undefined;
|
|
1168
|
+
const key = normalizedApiKey || settings.groq?.apiKey;
|
|
1169
|
+
const normalizedBaseUrl = baseUrl?.trim() || undefined;
|
|
1170
|
+
const resolvedBaseUrl = normalizedBaseUrl || settings.groq?.baseUrl;
|
|
1171
|
+
|
|
1172
|
+
const defaultModels = [
|
|
1173
|
+
{ id: 'llama-3.1-8b-instant', name: 'Llama 3.1 8B Instant' },
|
|
1174
|
+
{ id: 'llama-3.3-70b-versatile', name: 'Llama 3.3 70B Versatile' },
|
|
1175
|
+
];
|
|
1176
|
+
|
|
1177
|
+
if (!key) {
|
|
1178
|
+
return defaultModels;
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
try {
|
|
1182
|
+
const provider = new GroqProvider({
|
|
1183
|
+
type: 'groq',
|
|
1184
|
+
model: '',
|
|
1185
|
+
groqApiKey: key,
|
|
1186
|
+
groqBaseUrl: resolvedBaseUrl,
|
|
1187
|
+
});
|
|
1188
|
+
return await provider.getAvailableModels();
|
|
1189
|
+
} catch (error: any) {
|
|
1190
|
+
console.error('Failed to fetch Groq models:', error);
|
|
1191
|
+
return defaultModels;
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
/**
|
|
1196
|
+
* Fetch available xAI models from the API
|
|
1197
|
+
*/
|
|
1198
|
+
static async getXAIModels(apiKey?: string, baseUrl?: string): Promise<Array<{ id: string; name: string }>> {
|
|
1199
|
+
const settings = this.loadSettings();
|
|
1200
|
+
const normalizedApiKey = apiKey?.trim() || undefined;
|
|
1201
|
+
const key = normalizedApiKey || settings.xai?.apiKey;
|
|
1202
|
+
const normalizedBaseUrl = baseUrl?.trim() || undefined;
|
|
1203
|
+
const resolvedBaseUrl = normalizedBaseUrl || settings.xai?.baseUrl;
|
|
1204
|
+
|
|
1205
|
+
const defaultModels = [
|
|
1206
|
+
{ id: 'grok-4', name: 'Grok 4' },
|
|
1207
|
+
{ id: 'grok-4-fast-non-reasoning', name: 'Grok 4 Fast (Non-Reasoning)' },
|
|
1208
|
+
{ id: 'grok-4-fast-reasoning', name: 'Grok 4 Fast (Reasoning)' },
|
|
1209
|
+
];
|
|
1210
|
+
|
|
1211
|
+
if (!key) {
|
|
1212
|
+
return defaultModels;
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
try {
|
|
1216
|
+
const provider = new XAIProvider({
|
|
1217
|
+
type: 'xai',
|
|
1218
|
+
model: '',
|
|
1219
|
+
xaiApiKey: key,
|
|
1220
|
+
xaiBaseUrl: resolvedBaseUrl,
|
|
1221
|
+
});
|
|
1222
|
+
return await provider.getAvailableModels();
|
|
1223
|
+
} catch (error: any) {
|
|
1224
|
+
console.error('Failed to fetch xAI models:', error);
|
|
1225
|
+
return defaultModels;
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
/**
|
|
1230
|
+
* Fetch available Kimi models from the API
|
|
1231
|
+
*/
|
|
1232
|
+
static async getKimiModels(apiKey?: string, baseUrl?: string): Promise<Array<{ id: string; name: string }>> {
|
|
1233
|
+
const settings = this.loadSettings();
|
|
1234
|
+
const normalizedApiKey = apiKey?.trim() || undefined;
|
|
1235
|
+
const key = normalizedApiKey || settings.kimi?.apiKey;
|
|
1236
|
+
const normalizedBaseUrl = baseUrl?.trim() || undefined;
|
|
1237
|
+
const resolvedBaseUrl = normalizedBaseUrl || settings.kimi?.baseUrl;
|
|
1238
|
+
|
|
1239
|
+
const defaultModels = [
|
|
1240
|
+
{ id: 'kimi-k2.5', name: 'Kimi K2.5' },
|
|
1241
|
+
{ id: 'kimi-k2-0905-preview', name: 'Kimi K2.5 Preview' },
|
|
1242
|
+
{ id: 'kimi-k2-turbo-preview', name: 'Kimi K2 Turbo (Preview)' },
|
|
1243
|
+
{ id: 'kimi-k2-thinking', name: 'Kimi K2 Thinking' },
|
|
1244
|
+
{ id: 'kimi-k2-thinking-turbo', name: 'Kimi K2 Thinking Turbo' },
|
|
1245
|
+
];
|
|
1246
|
+
|
|
1247
|
+
if (!key) {
|
|
1248
|
+
return defaultModels;
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
try {
|
|
1252
|
+
const provider = new KimiProvider({
|
|
1253
|
+
type: 'kimi',
|
|
1254
|
+
model: '',
|
|
1255
|
+
kimiApiKey: key,
|
|
1256
|
+
kimiBaseUrl: resolvedBaseUrl,
|
|
1257
|
+
});
|
|
1258
|
+
return await provider.getAvailableModels();
|
|
1259
|
+
} catch (error: any) {
|
|
1260
|
+
console.error('Failed to fetch Kimi models:', error);
|
|
1261
|
+
return defaultModels;
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
|
|
874
1265
|
/**
|
|
875
1266
|
* Format OpenAI model ID to display name
|
|
876
1267
|
*/
|
|
@@ -921,7 +1312,7 @@ export class LLMProviderFactory {
|
|
|
921
1312
|
* Save cached models for a provider
|
|
922
1313
|
*/
|
|
923
1314
|
static saveCachedModels(
|
|
924
|
-
providerType: 'gemini' | 'openrouter' | 'ollama' | 'bedrock' | 'openai',
|
|
1315
|
+
providerType: 'gemini' | 'openrouter' | 'ollama' | 'bedrock' | 'openai' | 'groq' | 'xai' | 'kimi',
|
|
925
1316
|
models: CachedModelInfo[]
|
|
926
1317
|
): void {
|
|
927
1318
|
const settings = this.loadSettings();
|
|
@@ -942,6 +1333,15 @@ export class LLMProviderFactory {
|
|
|
942
1333
|
case 'openai':
|
|
943
1334
|
settings.cachedOpenAIModels = models;
|
|
944
1335
|
break;
|
|
1336
|
+
case 'groq':
|
|
1337
|
+
settings.cachedGroqModels = models;
|
|
1338
|
+
break;
|
|
1339
|
+
case 'xai':
|
|
1340
|
+
settings.cachedXaiModels = models;
|
|
1341
|
+
break;
|
|
1342
|
+
case 'kimi':
|
|
1343
|
+
settings.cachedKimiModels = models;
|
|
1344
|
+
break;
|
|
945
1345
|
}
|
|
946
1346
|
|
|
947
1347
|
this.saveSettings(settings);
|
|
@@ -950,7 +1350,9 @@ export class LLMProviderFactory {
|
|
|
950
1350
|
/**
|
|
951
1351
|
* Get cached models for a provider
|
|
952
1352
|
*/
|
|
953
|
-
static getCachedModels(
|
|
1353
|
+
static getCachedModels(
|
|
1354
|
+
providerType: 'gemini' | 'openrouter' | 'ollama' | 'bedrock' | 'openai' | 'groq' | 'xai' | 'kimi'
|
|
1355
|
+
): CachedModelInfo[] | undefined {
|
|
954
1356
|
const settings = this.loadSettings();
|
|
955
1357
|
|
|
956
1358
|
switch (providerType) {
|
|
@@ -964,6 +1366,12 @@ export class LLMProviderFactory {
|
|
|
964
1366
|
return settings.cachedBedrockModels;
|
|
965
1367
|
case 'openai':
|
|
966
1368
|
return settings.cachedOpenAIModels;
|
|
1369
|
+
case 'groq':
|
|
1370
|
+
return settings.cachedGroqModels;
|
|
1371
|
+
case 'xai':
|
|
1372
|
+
return settings.cachedXaiModels;
|
|
1373
|
+
case 'kimi':
|
|
1374
|
+
return settings.cachedKimiModels;
|
|
967
1375
|
default:
|
|
968
1376
|
return undefined;
|
|
969
1377
|
}
|