cowork-os 0.3.21 → 0.3.25

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 (252) hide show
  1. package/README.md +372 -10
  2. package/connectors/README.md +20 -0
  3. package/connectors/asana-mcp/README.md +24 -0
  4. package/connectors/asana-mcp/dist/index.js +427 -0
  5. package/connectors/asana-mcp/package.json +15 -0
  6. package/connectors/asana-mcp/src/index.ts +553 -0
  7. package/connectors/asana-mcp/tsconfig.json +13 -0
  8. package/connectors/hubspot-mcp/README.md +35 -0
  9. package/connectors/hubspot-mcp/dist/index.js +454 -0
  10. package/connectors/hubspot-mcp/package.json +15 -0
  11. package/connectors/hubspot-mcp/src/index.ts +562 -0
  12. package/connectors/hubspot-mcp/tsconfig.json +13 -0
  13. package/connectors/jira-mcp/README.md +49 -0
  14. package/connectors/jira-mcp/dist/index.js +588 -0
  15. package/connectors/jira-mcp/package.json +15 -0
  16. package/connectors/jira-mcp/src/index.ts +711 -0
  17. package/connectors/jira-mcp/tsconfig.json +13 -0
  18. package/connectors/linear-mcp/README.md +22 -0
  19. package/connectors/linear-mcp/dist/index.js +402 -0
  20. package/connectors/linear-mcp/package.json +15 -0
  21. package/connectors/linear-mcp/src/index.ts +522 -0
  22. package/connectors/linear-mcp/tsconfig.json +13 -0
  23. package/connectors/okta-mcp/README.md +24 -0
  24. package/connectors/okta-mcp/dist/index.js +411 -0
  25. package/connectors/okta-mcp/package.json +15 -0
  26. package/connectors/okta-mcp/src/index.ts +520 -0
  27. package/connectors/okta-mcp/tsconfig.json +13 -0
  28. package/connectors/salesforce-mcp/README.md +47 -0
  29. package/connectors/salesforce-mcp/dist/index.js +584 -0
  30. package/connectors/salesforce-mcp/package.json +15 -0
  31. package/connectors/salesforce-mcp/src/index.ts +722 -0
  32. package/connectors/salesforce-mcp/tsconfig.json +13 -0
  33. package/connectors/servicenow-mcp/README.md +26 -0
  34. package/connectors/servicenow-mcp/dist/index.js +400 -0
  35. package/connectors/servicenow-mcp/package.json +15 -0
  36. package/connectors/servicenow-mcp/src/index.ts +500 -0
  37. package/connectors/servicenow-mcp/tsconfig.json +13 -0
  38. package/connectors/templates/mcp-connector/README.md +31 -0
  39. package/connectors/templates/mcp-connector/package.json +15 -0
  40. package/connectors/templates/mcp-connector/src/index.ts +330 -0
  41. package/connectors/templates/mcp-connector/tsconfig.json +13 -0
  42. package/connectors/zendesk-mcp/README.md +40 -0
  43. package/connectors/zendesk-mcp/dist/index.js +431 -0
  44. package/connectors/zendesk-mcp/package.json +15 -0
  45. package/connectors/zendesk-mcp/src/index.ts +543 -0
  46. package/connectors/zendesk-mcp/tsconfig.json +13 -0
  47. package/dist/electron/electron/agent/custom-skill-loader.js +31 -1
  48. package/dist/electron/electron/agent/daemon.js +189 -13
  49. package/dist/electron/electron/agent/executor.js +895 -78
  50. package/dist/electron/electron/agent/llm/anthropic-compatible-provider.js +177 -0
  51. package/dist/electron/electron/agent/llm/azure-openai-provider.js +328 -0
  52. package/dist/electron/electron/agent/llm/bedrock-provider.js +49 -9
  53. package/dist/electron/electron/agent/llm/github-copilot-provider.js +97 -0
  54. package/dist/electron/electron/agent/llm/groq-provider.js +33 -0
  55. package/dist/electron/electron/agent/llm/index.js +13 -1
  56. package/dist/electron/electron/agent/llm/kimi-provider.js +33 -0
  57. package/dist/electron/electron/agent/llm/openai-compatible-provider.js +116 -0
  58. package/dist/electron/electron/agent/llm/openai-compatible.js +111 -0
  59. package/dist/electron/electron/agent/llm/openai-oauth.js +2 -1
  60. package/dist/electron/electron/agent/llm/openrouter-provider.js +1 -1
  61. package/dist/electron/electron/agent/llm/provider-factory.js +350 -4
  62. package/dist/electron/electron/agent/llm/types.js +66 -1
  63. package/dist/electron/electron/agent/llm/xai-provider.js +33 -0
  64. package/dist/electron/electron/agent/search/provider-factory.js +38 -2
  65. package/dist/electron/electron/agent/tools/box-tools.js +231 -0
  66. package/dist/electron/electron/agent/tools/builtin-settings.js +28 -0
  67. package/dist/electron/electron/agent/tools/dropbox-tools.js +237 -0
  68. package/dist/electron/electron/agent/tools/file-tools.js +66 -3
  69. package/dist/electron/electron/agent/tools/google-drive-tools.js +227 -0
  70. package/dist/electron/electron/agent/tools/grep-tools.js +90 -10
  71. package/dist/electron/electron/agent/tools/image-tools.js +11 -1
  72. package/dist/electron/electron/agent/tools/notion-tools.js +312 -0
  73. package/dist/electron/electron/agent/tools/onedrive-tools.js +217 -0
  74. package/dist/electron/electron/agent/tools/registry.js +548 -10
  75. package/dist/electron/electron/agent/tools/search-tools.js +28 -10
  76. package/dist/electron/electron/agent/tools/sharepoint-tools.js +243 -0
  77. package/dist/electron/electron/agent/tools/shell-tools.js +12 -3
  78. package/dist/electron/electron/agent/tools/x-tools.js +1 -1
  79. package/dist/electron/electron/agents/agent-dispatch.js +63 -0
  80. package/dist/electron/electron/database/repositories.js +19 -5
  81. package/dist/electron/electron/database/schema.js +8 -0
  82. package/dist/electron/electron/gateway/channels/whatsapp.js +55 -0
  83. package/dist/electron/electron/gateway/index.js +75 -1
  84. package/dist/electron/electron/gateway/router.js +209 -154
  85. package/dist/electron/electron/ipc/canvas-handlers.js +5 -0
  86. package/dist/electron/electron/ipc/handlers.js +763 -267
  87. package/dist/electron/electron/main.js +63 -0
  88. package/dist/electron/electron/mcp/oauth/connector-oauth.js +333 -0
  89. package/dist/electron/electron/mcp/registry/MCPRegistryManager.js +503 -154
  90. package/dist/electron/electron/memory/MemoryService.js +2 -1
  91. package/dist/electron/electron/preload.js +78 -1
  92. package/dist/electron/electron/settings/appearance-manager.js +18 -1
  93. package/dist/electron/electron/settings/box-manager.js +54 -0
  94. package/dist/electron/electron/settings/dropbox-manager.js +54 -0
  95. package/dist/electron/electron/settings/google-drive-manager.js +54 -0
  96. package/dist/electron/electron/settings/notion-manager.js +56 -0
  97. package/dist/electron/electron/settings/onedrive-manager.js +54 -0
  98. package/dist/electron/electron/settings/sharepoint-manager.js +54 -0
  99. package/dist/electron/electron/utils/box-api.js +153 -0
  100. package/dist/electron/electron/utils/dropbox-api.js +144 -0
  101. package/dist/electron/electron/utils/env-migration.js +19 -0
  102. package/dist/electron/electron/utils/google-drive-api.js +152 -0
  103. package/dist/electron/electron/utils/notion-api.js +103 -0
  104. package/dist/electron/electron/utils/onedrive-api.js +113 -0
  105. package/dist/electron/electron/utils/sharepoint-api.js +109 -0
  106. package/dist/electron/electron/utils/validation.js +98 -3
  107. package/dist/electron/electron/utils/x-cli.js +1 -1
  108. package/dist/electron/shared/channelMessages.js +284 -3
  109. package/dist/electron/shared/llm-provider-catalog.js +198 -0
  110. package/dist/electron/shared/types.js +90 -1
  111. package/package.json +14 -3
  112. package/resources/skills/nano-banana-pro.json +4 -4
  113. package/resources/skills/openai-image-gen.json +3 -3
  114. package/resources/skills/scripts/gen.py +163 -0
  115. package/resources/skills/scripts/generate_image.py +91 -0
  116. package/src/electron/agent/custom-skill-loader.ts +34 -1
  117. package/src/electron/agent/daemon.ts +210 -14
  118. package/src/electron/agent/executor.ts +1124 -85
  119. package/src/electron/agent/llm/anthropic-compatible-provider.ts +214 -0
  120. package/src/electron/agent/llm/azure-openai-provider.ts +388 -0
  121. package/src/electron/agent/llm/bedrock-provider.ts +62 -9
  122. package/src/electron/agent/llm/github-copilot-provider.ts +117 -0
  123. package/src/electron/agent/llm/groq-provider.ts +39 -0
  124. package/src/electron/agent/llm/index.ts +6 -0
  125. package/src/electron/agent/llm/kimi-provider.ts +39 -0
  126. package/src/electron/agent/llm/openai-compatible-provider.ts +153 -0
  127. package/src/electron/agent/llm/openai-compatible.ts +133 -0
  128. package/src/electron/agent/llm/openai-oauth.ts +2 -1
  129. package/src/electron/agent/llm/openrouter-provider.ts +2 -1
  130. package/src/electron/agent/llm/provider-factory.ts +459 -6
  131. package/src/electron/agent/llm/types.ts +95 -1
  132. package/src/electron/agent/llm/xai-provider.ts +39 -0
  133. package/src/electron/agent/search/provider-factory.ts +43 -2
  134. package/src/electron/agent/tools/box-tools.ts +239 -0
  135. package/src/electron/agent/tools/builtin-settings.ts +36 -0
  136. package/src/electron/agent/tools/dropbox-tools.ts +237 -0
  137. package/src/electron/agent/tools/file-tools.ts +66 -3
  138. package/src/electron/agent/tools/gmail-tools.ts +240 -0
  139. package/src/electron/agent/tools/google-calendar-tools.ts +258 -0
  140. package/src/electron/agent/tools/google-drive-tools.ts +228 -0
  141. package/src/electron/agent/tools/grep-tools.ts +97 -12
  142. package/src/electron/agent/tools/image-tools.ts +11 -1
  143. package/src/electron/agent/tools/notion-tools.ts +330 -0
  144. package/src/electron/agent/tools/onedrive-tools.ts +217 -0
  145. package/src/electron/agent/tools/registry.ts +794 -10
  146. package/src/electron/agent/tools/search-tools.ts +29 -11
  147. package/src/electron/agent/tools/sharepoint-tools.ts +247 -0
  148. package/src/electron/agent/tools/shell-tools.ts +11 -3
  149. package/src/electron/agent/tools/x-tools.ts +1 -1
  150. package/src/electron/agents/agent-dispatch.ts +79 -0
  151. package/src/electron/database/SecureSettingsRepository.ts +7 -1
  152. package/src/electron/database/repositories.ts +58 -6
  153. package/src/electron/database/schema.ts +8 -0
  154. package/src/electron/gateway/channels/discord.ts +4 -0
  155. package/src/electron/gateway/channels/google-chat.ts +3 -0
  156. package/src/electron/gateway/channels/line.ts +3 -0
  157. package/src/electron/gateway/channels/matrix-client.ts +15 -0
  158. package/src/electron/gateway/channels/matrix.ts +31 -0
  159. package/src/electron/gateway/channels/mattermost.ts +3 -0
  160. package/src/electron/gateway/channels/signal.ts +3 -0
  161. package/src/electron/gateway/channels/slack.ts +9 -4
  162. package/src/electron/gateway/channels/teams.ts +4 -0
  163. package/src/electron/gateway/channels/telegram.ts +2 -0
  164. package/src/electron/gateway/channels/twitch.ts +2 -0
  165. package/src/electron/gateway/channels/types.ts +8 -0
  166. package/src/electron/gateway/channels/whatsapp.ts +66 -0
  167. package/src/electron/gateway/index.ts +95 -2
  168. package/src/electron/gateway/router.ts +231 -161
  169. package/src/electron/gateway/security.ts +21 -9
  170. package/src/electron/ipc/canvas-handlers.ts +10 -0
  171. package/src/electron/ipc/handlers.ts +848 -292
  172. package/src/electron/main.ts +35 -0
  173. package/src/electron/mcp/oauth/connector-oauth.ts +448 -0
  174. package/src/electron/mcp/registry/MCPRegistryManager.ts +343 -12
  175. package/src/electron/memory/MemoryService.ts +7 -1
  176. package/src/electron/preload.ts +200 -5
  177. package/src/electron/settings/appearance-manager.ts +20 -2
  178. package/src/electron/settings/box-manager.ts +58 -0
  179. package/src/electron/settings/dropbox-manager.ts +58 -0
  180. package/src/electron/settings/google-workspace-manager.ts +59 -0
  181. package/src/electron/settings/notion-manager.ts +60 -0
  182. package/src/electron/settings/onedrive-manager.ts +58 -0
  183. package/src/electron/settings/sharepoint-manager.ts +58 -0
  184. package/src/electron/utils/box-api.ts +184 -0
  185. package/src/electron/utils/dropbox-api.ts +171 -0
  186. package/src/electron/utils/env-migration.ts +22 -0
  187. package/src/electron/utils/gmail-api.ts +121 -0
  188. package/src/electron/utils/google-calendar-api.ts +115 -0
  189. package/src/electron/utils/google-workspace-api.ts +228 -0
  190. package/src/electron/utils/google-workspace-auth.ts +109 -0
  191. package/src/electron/utils/google-workspace-oauth.ts +232 -0
  192. package/src/electron/utils/notion-api.ts +126 -0
  193. package/src/electron/utils/onedrive-api.ts +137 -0
  194. package/src/electron/utils/sharepoint-api.ts +132 -0
  195. package/src/electron/utils/validation.ts +128 -1
  196. package/src/electron/utils/x-cli.ts +1 -1
  197. package/src/renderer/App.tsx +119 -8
  198. package/src/renderer/components/ActivityFeedItem.tsx +34 -17
  199. package/src/renderer/components/AgentWorkingStatePanel.tsx +7 -5
  200. package/src/renderer/components/AppearanceSettings.tsx +37 -2
  201. package/src/renderer/components/BlueBubblesSettings.tsx +18 -7
  202. package/src/renderer/components/BoxSettings.tsx +203 -0
  203. package/src/renderer/components/BrowserView.tsx +101 -0
  204. package/src/renderer/components/BuiltinToolsSettings.tsx +105 -0
  205. package/src/renderer/components/CanvasPreview.tsx +68 -1
  206. package/src/renderer/components/ConnectorEnvModal.tsx +116 -0
  207. package/src/renderer/components/ConnectorSetupModal.tsx +566 -0
  208. package/src/renderer/components/ConnectorsSettings.tsx +397 -0
  209. package/src/renderer/components/ControlPlaneSettings.tsx +2 -0
  210. package/src/renderer/components/DiscordSettings.tsx +18 -7
  211. package/src/renderer/components/DropboxSettings.tsx +202 -0
  212. package/src/renderer/components/EmailSettings.tsx +18 -7
  213. package/src/renderer/components/FileViewer.tsx +21 -13
  214. package/src/renderer/components/GoogleChatSettings.tsx +17 -7
  215. package/src/renderer/components/GoogleWorkspaceSettings.tsx +332 -0
  216. package/src/renderer/components/ImessageSettings.tsx +22 -11
  217. package/src/renderer/components/LineIcons.tsx +376 -0
  218. package/src/renderer/components/LineSettings.tsx +18 -7
  219. package/src/renderer/components/MCPSettings.tsx +56 -0
  220. package/src/renderer/components/MainContent.tsx +740 -76
  221. package/src/renderer/components/MatrixSettings.tsx +18 -7
  222. package/src/renderer/components/MattermostSettings.tsx +18 -7
  223. package/src/renderer/components/NodesSettings.tsx +58 -99
  224. package/src/renderer/components/NotificationPanel.tsx +25 -11
  225. package/src/renderer/components/NotionSettings.tsx +231 -0
  226. package/src/renderer/components/Onboarding/Onboarding.tsx +13 -1
  227. package/src/renderer/components/OnboardingModal.tsx +70 -1
  228. package/src/renderer/components/OneDriveSettings.tsx +212 -0
  229. package/src/renderer/components/RightPanel.tsx +141 -28
  230. package/src/renderer/components/ScheduledTasksSettings.tsx +10 -62
  231. package/src/renderer/components/SearchSettings.tsx +118 -114
  232. package/src/renderer/components/Settings.tsx +1425 -651
  233. package/src/renderer/components/SharePointSettings.tsx +224 -0
  234. package/src/renderer/components/Sidebar.tsx +94 -19
  235. package/src/renderer/components/SignalSettings.tsx +18 -7
  236. package/src/renderer/components/SkillHubBrowser.tsx +144 -185
  237. package/src/renderer/components/SlackSettings.tsx +18 -7
  238. package/src/renderer/components/TaskQuickActions.tsx +11 -6
  239. package/src/renderer/components/TaskTimeline.tsx +58 -26
  240. package/src/renderer/components/TeamsSettings.tsx +18 -7
  241. package/src/renderer/components/TelegramSettings.tsx +18 -7
  242. package/src/renderer/components/ThemeIcon.tsx +16 -0
  243. package/src/renderer/components/TwitchSettings.tsx +18 -7
  244. package/src/renderer/components/VoiceSettings.tsx +30 -74
  245. package/src/renderer/components/WhatsAppSettings.tsx +48 -37
  246. package/src/renderer/components/WorkingStateHistory.tsx +7 -5
  247. package/src/renderer/components/WorkspaceSelector.tsx +42 -13
  248. package/src/renderer/hooks/useOnboardingFlow.ts +21 -0
  249. package/src/renderer/styles/index.css +2333 -209
  250. package/src/shared/channelMessages.ts +367 -4
  251. package/src/shared/llm-provider-catalog.ts +217 -0
  252. package/src/shared/types.ts +251 -2
@@ -45,10 +45,87 @@ const ollama_provider_1 = require("./ollama-provider");
45
45
  const gemini_provider_1 = require("./gemini-provider");
46
46
  const openrouter_provider_1 = require("./openrouter-provider");
47
47
  const openai_provider_1 = require("./openai-provider");
48
+ const azure_openai_provider_1 = require("./azure-openai-provider");
49
+ const groq_provider_1 = require("./groq-provider");
50
+ const xai_provider_1 = require("./xai-provider");
51
+ const kimi_provider_1 = require("./kimi-provider");
52
+ const anthropic_compatible_provider_1 = require("./anthropic-compatible-provider");
53
+ const openai_compatible_provider_1 = require("./openai-compatible-provider");
54
+ const github_copilot_provider_1 = require("./github-copilot-provider");
48
55
  const SecureSettingsRepository_1 = require("../../database/SecureSettingsRepository");
56
+ const llm_provider_catalog_1 = require("../../../shared/llm-provider-catalog");
49
57
  const LEGACY_SETTINGS_FILE = 'llm-settings.json';
50
58
  const MASKED_VALUE = '***configured***';
51
59
  const ENCRYPTED_PREFIX = 'encrypted:';
60
+ const CUSTOM_PROVIDER_ALIASES = {
61
+ 'kimi-coding': 'kimi-code',
62
+ };
63
+ function resolveCustomProviderId(providerType) {
64
+ return CUSTOM_PROVIDER_ALIASES[providerType] || providerType;
65
+ }
66
+ function getCustomProviderEntry(providerType) {
67
+ return llm_provider_catalog_1.CUSTOM_PROVIDER_MAP.get(resolveCustomProviderId(providerType));
68
+ }
69
+ function getCustomProviderConfig(customProviders, providerType) {
70
+ if (!customProviders)
71
+ return undefined;
72
+ const resolved = resolveCustomProviderId(providerType);
73
+ const resolvedConfig = customProviders[resolved];
74
+ if (resolvedConfig) {
75
+ return resolvedConfig;
76
+ }
77
+ const fallbackConfig = customProviders[providerType];
78
+ if (fallbackConfig && resolved !== providerType) {
79
+ console.log(`[LLMProviderFactory] Custom provider config not found for "${resolved}", falling back to "${providerType}".`);
80
+ }
81
+ return fallbackConfig;
82
+ }
83
+ function isCustomProviderConfigured(entry, config) {
84
+ if (!config)
85
+ return false;
86
+ const hasApiKey = !!config.apiKey?.trim();
87
+ const hasBaseUrl = !!config.baseUrl?.trim() || !!entry.baseUrl;
88
+ const hasUserConfig = hasApiKey || !!config.baseUrl?.trim() || !!config.model?.trim();
89
+ if (!hasUserConfig)
90
+ return false;
91
+ if (entry.apiKeyOptional) {
92
+ return entry.requiresBaseUrl ? hasBaseUrl : hasApiKey || hasBaseUrl;
93
+ }
94
+ return entry.requiresBaseUrl ? hasApiKey && hasBaseUrl : hasApiKey;
95
+ }
96
+ function createCustomProvider(config, entry, resolvedType) {
97
+ if (resolvedType === 'github-copilot') {
98
+ return new github_copilot_provider_1.GitHubCopilotProvider(config);
99
+ }
100
+ const apiKey = config.providerApiKey || '';
101
+ const baseUrl = config.providerBaseUrl || entry.baseUrl || '';
102
+ if (entry.requiresBaseUrl && !baseUrl) {
103
+ throw new Error(`${entry.name} base URL is required. Configure it in Settings.`);
104
+ }
105
+ if (!apiKey && !entry.apiKeyOptional) {
106
+ throw new Error(`${entry.name} API key is required. Configure it in Settings.`);
107
+ }
108
+ const model = config.model || entry.defaultModel;
109
+ if (!model) {
110
+ throw new Error(`${entry.name} model is required. Configure it in Settings.`);
111
+ }
112
+ if (entry.compatibility === 'openai') {
113
+ return new openai_compatible_provider_1.OpenAICompatibleProvider({
114
+ type: resolvedType,
115
+ providerName: entry.name,
116
+ apiKey,
117
+ baseUrl,
118
+ defaultModel: model,
119
+ });
120
+ }
121
+ return new anthropic_compatible_provider_1.AnthropicCompatibleProvider({
122
+ type: resolvedType,
123
+ providerName: entry.name,
124
+ apiKey,
125
+ baseUrl,
126
+ defaultModel: model,
127
+ });
128
+ }
52
129
  // ============ Legacy Encryption Functions (for migration only) ============
53
130
  // These functions are only used to decrypt settings from legacy JSON files
54
131
  // during migration to the encrypted database. New settings use full-object
@@ -178,6 +255,40 @@ function sanitizeSettings(settings) {
178
255
  refreshToken: decryptedRefreshToken,
179
256
  };
180
257
  }
258
+ if (sanitized.azure) {
259
+ sanitized.azure = {
260
+ ...sanitized.azure,
261
+ apiKey: decryptSecret(sanitized.azure.apiKey),
262
+ };
263
+ }
264
+ if (sanitized.groq) {
265
+ sanitized.groq = {
266
+ ...sanitized.groq,
267
+ apiKey: decryptSecret(sanitized.groq.apiKey),
268
+ };
269
+ }
270
+ if (sanitized.xai) {
271
+ sanitized.xai = {
272
+ ...sanitized.xai,
273
+ apiKey: decryptSecret(sanitized.xai.apiKey),
274
+ };
275
+ }
276
+ if (sanitized.kimi) {
277
+ sanitized.kimi = {
278
+ ...sanitized.kimi,
279
+ apiKey: decryptSecret(sanitized.kimi.apiKey),
280
+ };
281
+ }
282
+ if (sanitized.customProviders) {
283
+ const normalized = {};
284
+ for (const [key, value] of Object.entries(sanitized.customProviders)) {
285
+ normalized[key] = {
286
+ ...value,
287
+ apiKey: decryptSecret(value.apiKey),
288
+ };
289
+ }
290
+ sanitized.customProviders = normalized;
291
+ }
181
292
  return sanitized;
182
293
  }
183
294
  const DEFAULT_SETTINGS = {
@@ -188,6 +299,20 @@ const DEFAULT_SETTINGS = {
188
299
  * Factory for creating LLM providers
189
300
  */
190
301
  class LLMProviderFactory {
302
+ static normalizeCustomProviders(settings) {
303
+ if (!settings.customProviders)
304
+ return;
305
+ const legacyKey = settings.customProviders['kimi-coding'];
306
+ if (legacyKey && !settings.customProviders['kimi-code']) {
307
+ settings.customProviders['kimi-code'] = legacyKey;
308
+ }
309
+ if (settings.customProviders['kimi-coding']) {
310
+ delete settings.customProviders['kimi-coding'];
311
+ }
312
+ if (settings.providerType === 'kimi-coding') {
313
+ settings.providerType = 'kimi-code';
314
+ }
315
+ }
191
316
  /**
192
317
  * Initialize the factory
193
318
  */
@@ -270,6 +395,7 @@ class LLMProviderFactory {
270
395
  const stored = repository.load('llm');
271
396
  if (stored) {
272
397
  settings = { ...DEFAULT_SETTINGS, ...stored };
398
+ this.normalizeCustomProviders(settings);
273
399
  settingsExist = true;
274
400
  }
275
401
  }
@@ -307,12 +433,33 @@ class LLMProviderFactory {
307
433
  if (settings.openai?.apiKey || settings.openai?.accessToken) {
308
434
  return 'openai';
309
435
  }
436
+ const azureDeployment = settings.azure?.deployment || settings.azure?.deployments?.[0];
437
+ if (settings.azure?.apiKey && settings.azure?.endpoint && azureDeployment) {
438
+ return 'azure';
439
+ }
440
+ if (settings.groq?.apiKey) {
441
+ return 'groq';
442
+ }
443
+ if (settings.xai?.apiKey) {
444
+ return 'xai';
445
+ }
446
+ if (settings.kimi?.apiKey) {
447
+ return 'kimi';
448
+ }
310
449
  if (settings.bedrock?.accessKeyId || settings.bedrock?.profile) {
311
450
  return 'bedrock';
312
451
  }
313
452
  if (settings.ollama?.baseUrl || settings.ollama?.model) {
314
453
  return 'ollama';
315
454
  }
455
+ if (settings.customProviders) {
456
+ for (const entry of llm_provider_catalog_1.CUSTOM_PROVIDER_CATALOG) {
457
+ const config = getCustomProviderConfig(settings.customProviders, entry.id);
458
+ if (isCustomProviderConfigured(entry, config)) {
459
+ return entry.id;
460
+ }
461
+ }
462
+ }
316
463
  // No valid credentials detected - user needs to configure via Settings
317
464
  return null;
318
465
  }
@@ -350,9 +497,13 @@ class LLMProviderFactory {
350
497
  static createProvider(overrideConfig) {
351
498
  const settings = this.loadSettings();
352
499
  const providerType = overrideConfig?.type || settings.providerType;
500
+ const customConfig = getCustomProviderConfig(settings.customProviders, providerType);
501
+ const azureDeployment = overrideConfig?.azureDeployment
502
+ || settings.azure?.deployment
503
+ || settings.azure?.deployments?.[0];
353
504
  const config = {
354
505
  type: providerType,
355
- model: this.getModelId(settings.modelKey, providerType, settings.ollama?.model, settings.gemini?.model, settings.openrouter?.model, settings.openai?.model),
506
+ model: this.getModelId(settings.modelKey, providerType, settings.ollama?.model, settings.gemini?.model, settings.openrouter?.model, settings.openai?.model, azureDeployment, settings.groq?.model, settings.xai?.model, settings.kimi?.model, settings.customProviders),
356
507
  // Anthropic config - from settings only
357
508
  anthropicApiKey: normalizeSecret(overrideConfig?.anthropicApiKey) || settings.anthropic?.apiKey,
358
509
  // Bedrock config - from settings only
@@ -368,11 +519,29 @@ class LLMProviderFactory {
368
519
  geminiApiKey: normalizeSecret(overrideConfig?.geminiApiKey) || settings.gemini?.apiKey,
369
520
  // OpenRouter config - from settings only
370
521
  openrouterApiKey: normalizeSecret(overrideConfig?.openrouterApiKey) || settings.openrouter?.apiKey,
522
+ openrouterBaseUrl: overrideConfig?.openrouterBaseUrl || settings.openrouter?.baseUrl,
371
523
  // OpenAI config - from settings only
372
524
  openaiApiKey: normalizeSecret(overrideConfig?.openaiApiKey) || settings.openai?.apiKey,
373
525
  openaiAccessToken: normalizeSecret(overrideConfig?.openaiAccessToken) || settings.openai?.accessToken,
374
526
  openaiRefreshToken: settings.openai?.refreshToken,
375
527
  openaiTokenExpiresAt: settings.openai?.tokenExpiresAt,
528
+ // Azure OpenAI config - from settings only
529
+ azureApiKey: normalizeSecret(overrideConfig?.azureApiKey) || settings.azure?.apiKey,
530
+ azureEndpoint: overrideConfig?.azureEndpoint || settings.azure?.endpoint,
531
+ azureDeployment,
532
+ azureApiVersion: overrideConfig?.azureApiVersion || settings.azure?.apiVersion,
533
+ // Groq config - from settings only
534
+ groqApiKey: normalizeSecret(overrideConfig?.groqApiKey) || settings.groq?.apiKey,
535
+ groqBaseUrl: overrideConfig?.groqBaseUrl || settings.groq?.baseUrl,
536
+ // xAI config - from settings only
537
+ xaiApiKey: normalizeSecret(overrideConfig?.xaiApiKey) || settings.xai?.apiKey,
538
+ xaiBaseUrl: overrideConfig?.xaiBaseUrl || settings.xai?.baseUrl,
539
+ // Kimi config - from settings only
540
+ kimiApiKey: normalizeSecret(overrideConfig?.kimiApiKey) || settings.kimi?.apiKey,
541
+ kimiBaseUrl: overrideConfig?.kimiBaseUrl || settings.kimi?.baseUrl,
542
+ // Custom provider config
543
+ providerApiKey: normalizeSecret(overrideConfig?.providerApiKey) || customConfig?.apiKey,
544
+ providerBaseUrl: overrideConfig?.providerBaseUrl || customConfig?.baseUrl,
376
545
  };
377
546
  return this.createProviderFromConfig(config);
378
547
  }
@@ -380,6 +549,11 @@ class LLMProviderFactory {
380
549
  * Create a provider from explicit config
381
550
  */
382
551
  static createProviderFromConfig(config) {
552
+ const customEntry = getCustomProviderEntry(config.type);
553
+ if (customEntry) {
554
+ const resolvedType = resolveCustomProviderId(config.type);
555
+ return createCustomProvider(config, customEntry, resolvedType);
556
+ }
383
557
  switch (config.type) {
384
558
  case 'anthropic':
385
559
  return new anthropic_provider_1.AnthropicProvider(config);
@@ -393,6 +567,14 @@ class LLMProviderFactory {
393
567
  return new openrouter_provider_1.OpenRouterProvider(config);
394
568
  case 'openai':
395
569
  return new openai_provider_1.OpenAIProvider(config);
570
+ case 'azure':
571
+ return new azure_openai_provider_1.AzureOpenAIProvider(config);
572
+ case 'groq':
573
+ return new groq_provider_1.GroqProvider(config);
574
+ case 'xai':
575
+ return new xai_provider_1.XAIProvider(config);
576
+ case 'kimi':
577
+ return new kimi_provider_1.KimiProvider(config);
396
578
  default:
397
579
  throw new Error(`Unknown provider type: ${config.type}`);
398
580
  }
@@ -400,7 +582,12 @@ class LLMProviderFactory {
400
582
  /**
401
583
  * Get the model ID for a provider
402
584
  */
403
- static getModelId(modelKey, providerType, ollamaModel, geminiModel, openrouterModel, openaiModel) {
585
+ static getModelId(modelKey, providerType, ollamaModel, geminiModel, openrouterModel, openaiModel, azureDeployment, groqModel, xaiModel, kimiModel, customProviders) {
586
+ const customEntry = getCustomProviderEntry(providerType);
587
+ if (customEntry) {
588
+ const customConfig = getCustomProviderConfig(customProviders, providerType);
589
+ return customConfig?.model || customEntry.defaultModel;
590
+ }
404
591
  // For Ollama, use the specific Ollama model if provided
405
592
  if (providerType === 'ollama') {
406
593
  return ollamaModel || 'gpt-oss:20b';
@@ -417,6 +604,22 @@ class LLMProviderFactory {
417
604
  if (providerType === 'openai') {
418
605
  return openaiModel || 'gpt-4o-mini';
419
606
  }
607
+ // For Azure OpenAI, use the deployment name
608
+ if (providerType === 'azure') {
609
+ return azureDeployment || '';
610
+ }
611
+ // For Groq, use the specific model if provided or default
612
+ if (providerType === 'groq') {
613
+ return groqModel || 'llama-3.1-8b-instant';
614
+ }
615
+ // For xAI, use the specific model if provided or default
616
+ if (providerType === 'xai') {
617
+ return xaiModel || 'grok-4-fast-non-reasoning';
618
+ }
619
+ // For Kimi, use the specific model if provided or default
620
+ if (providerType === 'kimi') {
621
+ return kimiModel || 'kimi-k2.5';
622
+ }
420
623
  // For other providers, look up in MODELS
421
624
  const model = types_1.MODELS[modelKey];
422
625
  if (!model) {
@@ -445,7 +648,7 @@ class LLMProviderFactory {
445
648
  */
446
649
  static getAvailableProviders() {
447
650
  const settings = this.loadSettings();
448
- return [
651
+ const builtIns = [
449
652
  {
450
653
  type: 'anthropic',
451
654
  name: 'Anthropic API',
@@ -466,6 +669,28 @@ class LLMProviderFactory {
466
669
  name: 'OpenAI',
467
670
  configured: !!(settings.openai?.apiKey || settings.openai?.accessToken),
468
671
  },
672
+ {
673
+ type: 'azure',
674
+ name: 'Azure OpenAI',
675
+ configured: !!(settings.azure?.apiKey
676
+ && settings.azure?.endpoint
677
+ && (settings.azure?.deployment || settings.azure?.deployments?.length)),
678
+ },
679
+ {
680
+ type: 'groq',
681
+ name: 'Groq',
682
+ configured: !!settings.groq?.apiKey,
683
+ },
684
+ {
685
+ type: 'xai',
686
+ name: 'xAI (Grok)',
687
+ configured: !!settings.xai?.apiKey,
688
+ },
689
+ {
690
+ type: 'kimi',
691
+ name: 'Kimi',
692
+ configured: !!settings.kimi?.apiKey,
693
+ },
469
694
  {
470
695
  type: 'bedrock',
471
696
  name: 'AWS Bedrock',
@@ -477,6 +702,15 @@ class LLMProviderFactory {
477
702
  configured: !!(settings.ollama?.baseUrl || settings.ollama?.model),
478
703
  },
479
704
  ];
705
+ const customProviders = llm_provider_catalog_1.CUSTOM_PROVIDER_CATALOG.map((entry) => {
706
+ const config = getCustomProviderConfig(settings.customProviders, entry.id);
707
+ return {
708
+ type: entry.id,
709
+ name: entry.name,
710
+ configured: isCustomProviderConfigured(entry, config),
711
+ };
712
+ });
713
+ return [...builtIns, ...customProviders];
480
714
  }
481
715
  /**
482
716
  * Get current configuration status
@@ -645,11 +879,13 @@ class LLMProviderFactory {
645
879
  /**
646
880
  * Fetch available OpenRouter models from the API
647
881
  */
648
- static async getOpenRouterModels(apiKey) {
882
+ static async getOpenRouterModels(apiKey, baseUrl) {
649
883
  const settings = this.loadSettings();
650
884
  // Normalize empty strings to undefined
651
885
  const normalizedApiKey = apiKey?.trim() || undefined;
652
886
  const key = normalizedApiKey || settings.openrouter?.apiKey;
887
+ const normalizedBaseUrl = baseUrl?.trim() || undefined;
888
+ const resolvedBaseUrl = normalizedBaseUrl || settings.openrouter?.baseUrl;
653
889
  const defaultModels = [
654
890
  { id: 'anthropic/claude-3.5-sonnet', name: 'Claude 3.5 Sonnet', context_length: 200000 },
655
891
  { id: 'anthropic/claude-3-opus', name: 'Claude 3 Opus', context_length: 200000 },
@@ -667,6 +903,7 @@ class LLMProviderFactory {
667
903
  type: 'openrouter',
668
904
  model: '',
669
905
  openrouterApiKey: key,
906
+ openrouterBaseUrl: resolvedBaseUrl,
670
907
  });
671
908
  return await provider.getAvailableModels();
672
909
  }
@@ -758,6 +995,100 @@ class LLMProviderFactory {
758
995
  return defaultModels;
759
996
  }
760
997
  }
998
+ /**
999
+ * Fetch available Groq models from the API
1000
+ */
1001
+ static async getGroqModels(apiKey, baseUrl) {
1002
+ const settings = this.loadSettings();
1003
+ const normalizedApiKey = apiKey?.trim() || undefined;
1004
+ const key = normalizedApiKey || settings.groq?.apiKey;
1005
+ const normalizedBaseUrl = baseUrl?.trim() || undefined;
1006
+ const resolvedBaseUrl = normalizedBaseUrl || settings.groq?.baseUrl;
1007
+ const defaultModels = [
1008
+ { id: 'llama-3.1-8b-instant', name: 'Llama 3.1 8B Instant' },
1009
+ { id: 'llama-3.3-70b-versatile', name: 'Llama 3.3 70B Versatile' },
1010
+ ];
1011
+ if (!key) {
1012
+ return defaultModels;
1013
+ }
1014
+ try {
1015
+ const provider = new groq_provider_1.GroqProvider({
1016
+ type: 'groq',
1017
+ model: '',
1018
+ groqApiKey: key,
1019
+ groqBaseUrl: resolvedBaseUrl,
1020
+ });
1021
+ return await provider.getAvailableModels();
1022
+ }
1023
+ catch (error) {
1024
+ console.error('Failed to fetch Groq models:', error);
1025
+ return defaultModels;
1026
+ }
1027
+ }
1028
+ /**
1029
+ * Fetch available xAI models from the API
1030
+ */
1031
+ static async getXAIModels(apiKey, baseUrl) {
1032
+ const settings = this.loadSettings();
1033
+ const normalizedApiKey = apiKey?.trim() || undefined;
1034
+ const key = normalizedApiKey || settings.xai?.apiKey;
1035
+ const normalizedBaseUrl = baseUrl?.trim() || undefined;
1036
+ const resolvedBaseUrl = normalizedBaseUrl || settings.xai?.baseUrl;
1037
+ const defaultModels = [
1038
+ { id: 'grok-4', name: 'Grok 4' },
1039
+ { id: 'grok-4-fast-non-reasoning', name: 'Grok 4 Fast (Non-Reasoning)' },
1040
+ { id: 'grok-4-fast-reasoning', name: 'Grok 4 Fast (Reasoning)' },
1041
+ ];
1042
+ if (!key) {
1043
+ return defaultModels;
1044
+ }
1045
+ try {
1046
+ const provider = new xai_provider_1.XAIProvider({
1047
+ type: 'xai',
1048
+ model: '',
1049
+ xaiApiKey: key,
1050
+ xaiBaseUrl: resolvedBaseUrl,
1051
+ });
1052
+ return await provider.getAvailableModels();
1053
+ }
1054
+ catch (error) {
1055
+ console.error('Failed to fetch xAI models:', error);
1056
+ return defaultModels;
1057
+ }
1058
+ }
1059
+ /**
1060
+ * Fetch available Kimi models from the API
1061
+ */
1062
+ static async getKimiModels(apiKey, baseUrl) {
1063
+ const settings = this.loadSettings();
1064
+ const normalizedApiKey = apiKey?.trim() || undefined;
1065
+ const key = normalizedApiKey || settings.kimi?.apiKey;
1066
+ const normalizedBaseUrl = baseUrl?.trim() || undefined;
1067
+ const resolvedBaseUrl = normalizedBaseUrl || settings.kimi?.baseUrl;
1068
+ const defaultModels = [
1069
+ { id: 'kimi-k2.5', name: 'Kimi K2.5' },
1070
+ { id: 'kimi-k2-0905-preview', name: 'Kimi K2.5 Preview' },
1071
+ { id: 'kimi-k2-turbo-preview', name: 'Kimi K2 Turbo (Preview)' },
1072
+ { id: 'kimi-k2-thinking', name: 'Kimi K2 Thinking' },
1073
+ { id: 'kimi-k2-thinking-turbo', name: 'Kimi K2 Thinking Turbo' },
1074
+ ];
1075
+ if (!key) {
1076
+ return defaultModels;
1077
+ }
1078
+ try {
1079
+ const provider = new kimi_provider_1.KimiProvider({
1080
+ type: 'kimi',
1081
+ model: '',
1082
+ kimiApiKey: key,
1083
+ kimiBaseUrl: resolvedBaseUrl,
1084
+ });
1085
+ return await provider.getAvailableModels();
1086
+ }
1087
+ catch (error) {
1088
+ console.error('Failed to fetch Kimi models:', error);
1089
+ return defaultModels;
1090
+ }
1091
+ }
761
1092
  /**
762
1093
  * Format OpenAI model ID to display name
763
1094
  */
@@ -851,6 +1182,15 @@ class LLMProviderFactory {
851
1182
  case 'openai':
852
1183
  settings.cachedOpenAIModels = models;
853
1184
  break;
1185
+ case 'groq':
1186
+ settings.cachedGroqModels = models;
1187
+ break;
1188
+ case 'xai':
1189
+ settings.cachedXaiModels = models;
1190
+ break;
1191
+ case 'kimi':
1192
+ settings.cachedKimiModels = models;
1193
+ break;
854
1194
  }
855
1195
  this.saveSettings(settings);
856
1196
  }
@@ -870,6 +1210,12 @@ class LLMProviderFactory {
870
1210
  return settings.cachedBedrockModels;
871
1211
  case 'openai':
872
1212
  return settings.cachedOpenAIModels;
1213
+ case 'groq':
1214
+ return settings.cachedGroqModels;
1215
+ case 'xai':
1216
+ return settings.cachedXaiModels;
1217
+ case 'kimi':
1218
+ return settings.cachedKimiModels;
873
1219
  default:
874
1220
  return undefined;
875
1221
  }
@@ -4,7 +4,7 @@
4
4
  * Allows switching between Anthropic API and AWS Bedrock
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.DEFAULT_MODEL = exports.OLLAMA_MODELS = exports.OPENAI_MODELS = exports.OPENROUTER_MODELS = exports.GEMINI_MODELS = exports.MODELS = void 0;
7
+ exports.DEFAULT_MODEL = exports.OLLAMA_MODELS = exports.KIMI_MODELS = exports.XAI_MODELS = exports.GROQ_MODELS = exports.OPENAI_MODELS = exports.OPENROUTER_MODELS = exports.GEMINI_MODELS = exports.MODELS = void 0;
8
8
  /**
9
9
  * Available AI models with their IDs for each provider
10
10
  * Note: Bedrock uses inference profile IDs (us. prefix) for newer models
@@ -159,6 +159,71 @@ exports.OPENAI_MODELS = {
159
159
  description: 'Fast reasoning model',
160
160
  },
161
161
  };
162
+ /**
163
+ * Popular Groq models
164
+ */
165
+ exports.GROQ_MODELS = {
166
+ 'llama-3.1-8b-instant': {
167
+ id: 'llama-3.1-8b-instant',
168
+ displayName: 'Llama 3.1 8B Instant',
169
+ description: 'Fast, cost-efficient Groq model',
170
+ },
171
+ 'llama-3.3-70b-versatile': {
172
+ id: 'llama-3.3-70b-versatile',
173
+ displayName: 'Llama 3.3 70B Versatile',
174
+ description: 'Higher capability Groq model',
175
+ },
176
+ };
177
+ /**
178
+ * Popular xAI (Grok) models
179
+ */
180
+ exports.XAI_MODELS = {
181
+ 'grok-4': {
182
+ id: 'grok-4',
183
+ displayName: 'Grok 4',
184
+ description: 'Flagship model',
185
+ },
186
+ 'grok-4-fast-non-reasoning': {
187
+ id: 'grok-4-fast-non-reasoning',
188
+ displayName: 'Grok 4 Fast (Non-Reasoning)',
189
+ description: 'Fast responses without explicit reasoning',
190
+ },
191
+ 'grok-4-fast-reasoning': {
192
+ id: 'grok-4-fast-reasoning',
193
+ displayName: 'Grok 4 Fast (Reasoning)',
194
+ description: 'Faster model with reasoning support',
195
+ },
196
+ };
197
+ /**
198
+ * Kimi (Moonshot) models
199
+ */
200
+ exports.KIMI_MODELS = {
201
+ 'kimi-k2.5': {
202
+ id: 'kimi-k2.5',
203
+ displayName: 'Kimi K2.5',
204
+ description: 'Latest Kimi K2.5 model',
205
+ },
206
+ 'kimi-k2-0905-preview': {
207
+ id: 'kimi-k2-0905-preview',
208
+ displayName: 'Kimi K2.5 Preview',
209
+ description: 'Preview K2.5 model',
210
+ },
211
+ 'kimi-k2-turbo-preview': {
212
+ id: 'kimi-k2-turbo-preview',
213
+ displayName: 'Kimi K2 Turbo (Preview)',
214
+ description: 'Faster K2 preview model',
215
+ },
216
+ 'kimi-k2-thinking': {
217
+ id: 'kimi-k2-thinking',
218
+ displayName: 'Kimi K2 Thinking',
219
+ description: 'Reasoning-focused K2 model',
220
+ },
221
+ 'kimi-k2-thinking-turbo': {
222
+ id: 'kimi-k2-thinking-turbo',
223
+ displayName: 'Kimi K2 Thinking Turbo',
224
+ description: 'Faster reasoning K2 model',
225
+ },
226
+ };
162
227
  /**
163
228
  * Popular Ollama models with their details
164
229
  * Users can use any model available on their Ollama server
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.XAIProvider = void 0;
4
+ const openai_compatible_provider_1 = require("./openai-compatible-provider");
5
+ const XAI_BASE_URL = 'https://api.x.ai/v1';
6
+ const DEFAULT_XAI_MODEL = 'grok-4-fast-non-reasoning';
7
+ class XAIProvider {
8
+ constructor(config) {
9
+ this.type = 'xai';
10
+ const apiKey = config.xaiApiKey;
11
+ if (!apiKey) {
12
+ throw new Error('xAI API key is required. Configure it in Settings.');
13
+ }
14
+ const baseUrl = config.xaiBaseUrl || XAI_BASE_URL;
15
+ this.client = new openai_compatible_provider_1.OpenAICompatibleProvider({
16
+ type: 'xai',
17
+ providerName: 'xAI',
18
+ apiKey,
19
+ baseUrl,
20
+ defaultModel: config.model || DEFAULT_XAI_MODEL,
21
+ });
22
+ }
23
+ createMessage(request) {
24
+ return this.client.createMessage(request);
25
+ }
26
+ testConnection() {
27
+ return this.client.testConnection();
28
+ }
29
+ getAvailableModels() {
30
+ return this.client.getAvailableModels();
31
+ }
32
+ }
33
+ exports.XAIProvider = XAIProvider;
@@ -52,6 +52,42 @@ const DEFAULT_SETTINGS = {
52
52
  * Factory for creating Search providers with fallback support
53
53
  */
54
54
  class SearchProviderFactory {
55
+ static async sleep(ms) {
56
+ return new Promise(resolve => setTimeout(resolve, ms));
57
+ }
58
+ static isTransientSearchError(error) {
59
+ const message = String(error?.message || '');
60
+ return (/rate limit/i.test(message) ||
61
+ /429/.test(message) ||
62
+ /too many requests/i.test(message) ||
63
+ /timeout/i.test(message) ||
64
+ /ETIMEDOUT/i.test(message) ||
65
+ /ECONNRESET/i.test(message) ||
66
+ /EAI_AGAIN/i.test(message) ||
67
+ /503/.test(message) ||
68
+ /502/.test(message) ||
69
+ /504/.test(message) ||
70
+ /service unavailable/i.test(message));
71
+ }
72
+ static async searchWithRetry(provider, query, maxAttempts = 3) {
73
+ let lastError;
74
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
75
+ try {
76
+ return await provider.search(query);
77
+ }
78
+ catch (error) {
79
+ lastError = error;
80
+ if (!this.isTransientSearchError(error) || attempt === maxAttempts) {
81
+ throw error;
82
+ }
83
+ // Exponential backoff with jitter: ~1s, ~2s, ~4s
84
+ const baseDelay = 1000 * Math.pow(2, attempt - 1);
85
+ const jitter = Math.random() * 500;
86
+ await this.sleep(baseDelay + jitter);
87
+ }
88
+ }
89
+ throw lastError || new Error('Search failed');
90
+ }
55
91
  /**
56
92
  * Initialize the factory
57
93
  */
@@ -288,7 +324,7 @@ class SearchProviderFactory {
288
324
  try {
289
325
  const primaryConfig = this.getProviderConfig(primaryType);
290
326
  const primaryProvider = this.createProviderFromConfig(primaryConfig);
291
- return await primaryProvider.search(query);
327
+ return await this.searchWithRetry(primaryProvider, query);
292
328
  }
293
329
  catch (primaryError) {
294
330
  console.error(`Primary search provider (${primaryType}) failed:`, primaryError.message);
@@ -303,7 +339,7 @@ class SearchProviderFactory {
303
339
  try {
304
340
  const fallbackConfig = this.getProviderConfig(fallbackType);
305
341
  const fallbackProvider = this.createProviderFromConfig(fallbackConfig);
306
- const response = await fallbackProvider.search(query);
342
+ const response = await this.searchWithRetry(fallbackProvider, query);
307
343
  // Indicate this came from fallback
308
344
  console.log(`Fallback search with ${fallbackType} succeeded`);
309
345
  return response;