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.
- package/README.md +372 -10
- 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/custom-skill-loader.js +31 -1
- package/dist/electron/electron/agent/daemon.js +189 -13
- package/dist/electron/electron/agent/executor.js +895 -78
- package/dist/electron/electron/agent/llm/anthropic-compatible-provider.js +177 -0
- package/dist/electron/electron/agent/llm/azure-openai-provider.js +328 -0
- package/dist/electron/electron/agent/llm/bedrock-provider.js +49 -9
- 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 +13 -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 +350 -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/search/provider-factory.js +38 -2
- 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/file-tools.js +66 -3
- package/dist/electron/electron/agent/tools/google-drive-tools.js +227 -0
- package/dist/electron/electron/agent/tools/grep-tools.js +90 -10
- package/dist/electron/electron/agent/tools/image-tools.js +11 -1
- 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 +548 -10
- package/dist/electron/electron/agent/tools/search-tools.js +28 -10
- 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/agents/agent-dispatch.js +63 -0
- package/dist/electron/electron/database/repositories.js +19 -5
- package/dist/electron/electron/database/schema.js +8 -0
- package/dist/electron/electron/gateway/channels/whatsapp.js +55 -0
- package/dist/electron/electron/gateway/index.js +75 -1
- package/dist/electron/electron/gateway/router.js +209 -154
- package/dist/electron/electron/ipc/canvas-handlers.js +5 -0
- package/dist/electron/electron/ipc/handlers.js +763 -267
- 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 +2 -1
- package/dist/electron/electron/preload.js +78 -1
- package/dist/electron/electron/settings/appearance-manager.js +18 -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 +98 -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 +90 -1
- package/package.json +14 -3
- package/resources/skills/nano-banana-pro.json +4 -4
- package/resources/skills/openai-image-gen.json +3 -3
- package/resources/skills/scripts/gen.py +163 -0
- package/resources/skills/scripts/generate_image.py +91 -0
- package/src/electron/agent/custom-skill-loader.ts +34 -1
- package/src/electron/agent/daemon.ts +210 -14
- package/src/electron/agent/executor.ts +1124 -85
- package/src/electron/agent/llm/anthropic-compatible-provider.ts +214 -0
- package/src/electron/agent/llm/azure-openai-provider.ts +388 -0
- package/src/electron/agent/llm/bedrock-provider.ts +62 -9
- 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 +6 -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 +459 -6
- package/src/electron/agent/llm/types.ts +95 -1
- package/src/electron/agent/llm/xai-provider.ts +39 -0
- package/src/electron/agent/search/provider-factory.ts +43 -2
- package/src/electron/agent/tools/box-tools.ts +239 -0
- package/src/electron/agent/tools/builtin-settings.ts +36 -0
- package/src/electron/agent/tools/dropbox-tools.ts +237 -0
- package/src/electron/agent/tools/file-tools.ts +66 -3
- package/src/electron/agent/tools/gmail-tools.ts +240 -0
- package/src/electron/agent/tools/google-calendar-tools.ts +258 -0
- package/src/electron/agent/tools/google-drive-tools.ts +228 -0
- package/src/electron/agent/tools/grep-tools.ts +97 -12
- package/src/electron/agent/tools/image-tools.ts +11 -1
- 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 +794 -10
- package/src/electron/agent/tools/search-tools.ts +29 -11
- 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/agents/agent-dispatch.ts +79 -0
- package/src/electron/database/SecureSettingsRepository.ts +7 -1
- package/src/electron/database/repositories.ts +58 -6
- package/src/electron/database/schema.ts +8 -0
- package/src/electron/gateway/channels/discord.ts +4 -0
- package/src/electron/gateway/channels/google-chat.ts +3 -0
- package/src/electron/gateway/channels/line.ts +3 -0
- package/src/electron/gateway/channels/matrix-client.ts +15 -0
- package/src/electron/gateway/channels/matrix.ts +31 -0
- package/src/electron/gateway/channels/mattermost.ts +3 -0
- package/src/electron/gateway/channels/signal.ts +3 -0
- package/src/electron/gateway/channels/slack.ts +9 -4
- package/src/electron/gateway/channels/teams.ts +4 -0
- package/src/electron/gateway/channels/telegram.ts +2 -0
- package/src/electron/gateway/channels/twitch.ts +2 -0
- package/src/electron/gateway/channels/types.ts +8 -0
- package/src/electron/gateway/channels/whatsapp.ts +66 -0
- package/src/electron/gateway/index.ts +95 -2
- package/src/electron/gateway/router.ts +231 -161
- package/src/electron/gateway/security.ts +21 -9
- package/src/electron/ipc/canvas-handlers.ts +10 -0
- package/src/electron/ipc/handlers.ts +848 -292
- 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 +7 -1
- package/src/electron/preload.ts +200 -5
- package/src/electron/settings/appearance-manager.ts +20 -2
- package/src/electron/settings/box-manager.ts +58 -0
- package/src/electron/settings/dropbox-manager.ts +58 -0
- package/src/electron/settings/google-workspace-manager.ts +59 -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/gmail-api.ts +121 -0
- package/src/electron/utils/google-calendar-api.ts +115 -0
- package/src/electron/utils/google-workspace-api.ts +228 -0
- package/src/electron/utils/google-workspace-auth.ts +109 -0
- package/src/electron/utils/google-workspace-oauth.ts +232 -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 +128 -1
- package/src/electron/utils/x-cli.ts +1 -1
- package/src/renderer/App.tsx +119 -8
- package/src/renderer/components/ActivityFeedItem.tsx +34 -17
- package/src/renderer/components/AgentWorkingStatePanel.tsx +7 -5
- package/src/renderer/components/AppearanceSettings.tsx +37 -2
- package/src/renderer/components/BlueBubblesSettings.tsx +18 -7
- 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/ControlPlaneSettings.tsx +2 -0
- package/src/renderer/components/DiscordSettings.tsx +18 -7
- package/src/renderer/components/DropboxSettings.tsx +202 -0
- package/src/renderer/components/EmailSettings.tsx +18 -7
- package/src/renderer/components/FileViewer.tsx +21 -13
- package/src/renderer/components/GoogleChatSettings.tsx +17 -7
- package/src/renderer/components/GoogleWorkspaceSettings.tsx +332 -0
- package/src/renderer/components/ImessageSettings.tsx +22 -11
- package/src/renderer/components/LineIcons.tsx +376 -0
- package/src/renderer/components/LineSettings.tsx +18 -7
- package/src/renderer/components/MCPSettings.tsx +56 -0
- package/src/renderer/components/MainContent.tsx +740 -76
- package/src/renderer/components/MatrixSettings.tsx +18 -7
- package/src/renderer/components/MattermostSettings.tsx +18 -7
- package/src/renderer/components/NodesSettings.tsx +58 -99
- package/src/renderer/components/NotificationPanel.tsx +25 -11
- 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/RightPanel.tsx +141 -28
- package/src/renderer/components/ScheduledTasksSettings.tsx +10 -62
- package/src/renderer/components/SearchSettings.tsx +118 -114
- package/src/renderer/components/Settings.tsx +1425 -651
- package/src/renderer/components/SharePointSettings.tsx +224 -0
- package/src/renderer/components/Sidebar.tsx +94 -19
- package/src/renderer/components/SignalSettings.tsx +18 -7
- package/src/renderer/components/SkillHubBrowser.tsx +144 -185
- package/src/renderer/components/SlackSettings.tsx +18 -7
- package/src/renderer/components/TaskQuickActions.tsx +11 -6
- package/src/renderer/components/TaskTimeline.tsx +58 -26
- package/src/renderer/components/TeamsSettings.tsx +18 -7
- package/src/renderer/components/TelegramSettings.tsx +18 -7
- package/src/renderer/components/ThemeIcon.tsx +16 -0
- package/src/renderer/components/TwitchSettings.tsx +18 -7
- package/src/renderer/components/VoiceSettings.tsx +30 -74
- package/src/renderer/components/WhatsAppSettings.tsx +48 -37
- package/src/renderer/components/WorkingStateHistory.tsx +7 -5
- package/src/renderer/components/WorkspaceSelector.tsx +42 -13
- package/src/renderer/hooks/useOnboardingFlow.ts +21 -0
- package/src/renderer/styles/index.css +2333 -209
- package/src/shared/channelMessages.ts +367 -4
- package/src/shared/llm-provider-catalog.ts +217 -0
- package/src/shared/types.ts +251 -2
|
@@ -44,6 +44,7 @@ const path = __importStar(require("path"));
|
|
|
44
44
|
const fs = __importStar(require("fs/promises"));
|
|
45
45
|
const fsSync = __importStar(require("fs"));
|
|
46
46
|
const mammoth_1 = __importDefault(require("mammoth"));
|
|
47
|
+
const mime_types_1 = __importDefault(require("mime-types"));
|
|
47
48
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
48
49
|
const pdfParseModule = require('pdf-parse');
|
|
49
50
|
// Handle both ESM default export and CommonJS module.exports
|
|
@@ -57,6 +58,7 @@ const TaskLabelRepository_1 = require("../database/TaskLabelRepository");
|
|
|
57
58
|
const WorkingStateRepository_1 = require("../agents/WorkingStateRepository");
|
|
58
59
|
const context_policy_1 = require("../gateway/context-policy");
|
|
59
60
|
const types_1 = require("../../shared/types");
|
|
61
|
+
const llm_provider_catalog_1 = require("../../shared/llm-provider-catalog");
|
|
60
62
|
const os = __importStar(require("os"));
|
|
61
63
|
const llm_1 = require("../agent/llm");
|
|
62
64
|
const search_1 = require("../agent/search");
|
|
@@ -66,6 +68,19 @@ const validation_1 = require("../utils/validation");
|
|
|
66
68
|
const guardrail_manager_1 = require("../guardrails/guardrail-manager");
|
|
67
69
|
const appearance_manager_1 = require("../settings/appearance-manager");
|
|
68
70
|
const personality_manager_1 = require("../settings/personality-manager");
|
|
71
|
+
const notion_manager_1 = require("../settings/notion-manager");
|
|
72
|
+
const notion_api_1 = require("../utils/notion-api");
|
|
73
|
+
const box_manager_1 = require("../settings/box-manager");
|
|
74
|
+
const onedrive_manager_1 = require("../settings/onedrive-manager");
|
|
75
|
+
const google_drive_manager_1 = require("../settings/google-drive-manager");
|
|
76
|
+
const dropbox_manager_1 = require("../settings/dropbox-manager");
|
|
77
|
+
const sharepoint_manager_1 = require("../settings/sharepoint-manager");
|
|
78
|
+
const box_api_1 = require("../utils/box-api");
|
|
79
|
+
const onedrive_api_1 = require("../utils/onedrive-api");
|
|
80
|
+
const google_drive_api_1 = require("../utils/google-drive-api");
|
|
81
|
+
const dropbox_api_1 = require("../utils/dropbox-api");
|
|
82
|
+
const sharepoint_api_1 = require("../utils/sharepoint-api");
|
|
83
|
+
const connector_oauth_1 = require("../mcp/oauth/connector-oauth");
|
|
69
84
|
const normalizeMentionToken = (value) => value.toLowerCase().replace(/[^a-z0-9]/g, '');
|
|
70
85
|
const buildAgentMentionIndex = (roles) => {
|
|
71
86
|
const index = new Map();
|
|
@@ -124,7 +139,8 @@ const scoreAgentForTask = (role, text) => {
|
|
|
124
139
|
}
|
|
125
140
|
return score;
|
|
126
141
|
};
|
|
127
|
-
const
|
|
142
|
+
const MAX_AUTO_AGENTS = 4;
|
|
143
|
+
const selectBestAgentsForTask = (text, roles, maxAgents = MAX_AUTO_AGENTS) => {
|
|
128
144
|
if (roles.length === 0)
|
|
129
145
|
return roles;
|
|
130
146
|
const scored = roles
|
|
@@ -140,24 +156,23 @@ const selectBestAgentsForTask = (text, roles) => {
|
|
|
140
156
|
const threshold = Math.max(1, maxScore - 2);
|
|
141
157
|
const selected = withScore
|
|
142
158
|
.filter((entry) => entry.score >= threshold)
|
|
143
|
-
.slice(0,
|
|
159
|
+
.slice(0, maxAgents)
|
|
144
160
|
.map((entry) => entry.role);
|
|
145
|
-
return selected.length > 0 ? selected : withScore.slice(0,
|
|
161
|
+
return selected.length > 0 ? selected : withScore.slice(0, maxAgents).map((entry) => entry.role);
|
|
146
162
|
}
|
|
147
163
|
const leads = roles
|
|
148
164
|
.filter((role) => role.autonomyLevel === 'lead')
|
|
149
165
|
.sort((a, b) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0));
|
|
150
166
|
if (leads.length > 0) {
|
|
151
|
-
return leads.slice(0,
|
|
167
|
+
return leads.slice(0, maxAgents);
|
|
152
168
|
}
|
|
153
|
-
return roles.slice(0, Math.min(
|
|
169
|
+
return roles.slice(0, Math.min(maxAgents, roles.length));
|
|
154
170
|
};
|
|
155
171
|
const extractMentionedRoles = (text, roles) => {
|
|
156
172
|
const normalizedText = text.toLowerCase();
|
|
157
|
-
const useSmartSelection = /\B@everybody\b/.test(normalizedText)
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
}
|
|
173
|
+
const useSmartSelection = /\B@everybody\b/.test(normalizedText) ||
|
|
174
|
+
/\B@all\b/.test(normalizedText) ||
|
|
175
|
+
/\B@everyone\b/.test(normalizedText);
|
|
161
176
|
const index = buildAgentMentionIndex(roles);
|
|
162
177
|
const matches = new Map();
|
|
163
178
|
const regex = /@([a-zA-Z0-9][a-zA-Z0-9 _-]{0,50})/g;
|
|
@@ -172,11 +187,15 @@ const extractMentionedRoles = (text, roles) => {
|
|
|
172
187
|
}
|
|
173
188
|
if (matches.size > 0) {
|
|
174
189
|
if (useSmartSelection) {
|
|
175
|
-
const selected = selectBestAgentsForTask(text, roles);
|
|
176
190
|
const merged = new Map();
|
|
177
|
-
selected.forEach((role) => merged.set(role.id, role));
|
|
178
191
|
matches.forEach((role) => merged.set(role.id, role));
|
|
179
|
-
|
|
192
|
+
const selected = selectBestAgentsForTask(text, roles, MAX_AUTO_AGENTS);
|
|
193
|
+
selected.forEach((role) => {
|
|
194
|
+
if (merged.size < MAX_AUTO_AGENTS) {
|
|
195
|
+
merged.set(role.id, role);
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
return Array.from(merged.values()).slice(0, MAX_AUTO_AGENTS);
|
|
180
199
|
}
|
|
181
200
|
return Array.from(matches.values());
|
|
182
201
|
}
|
|
@@ -189,64 +208,10 @@ const extractMentionedRoles = (text, roles) => {
|
|
|
189
208
|
}
|
|
190
209
|
});
|
|
191
210
|
if (useSmartSelection) {
|
|
192
|
-
return selectBestAgentsForTask(text, roles);
|
|
211
|
+
return selectBestAgentsForTask(text, roles, MAX_AUTO_AGENTS);
|
|
193
212
|
}
|
|
194
213
|
return Array.from(matches.values());
|
|
195
214
|
};
|
|
196
|
-
const buildSoulSummary = (soul) => {
|
|
197
|
-
if (!soul)
|
|
198
|
-
return null;
|
|
199
|
-
try {
|
|
200
|
-
const parsed = JSON.parse(soul);
|
|
201
|
-
const parts = [];
|
|
202
|
-
if (typeof parsed.name === 'string')
|
|
203
|
-
parts.push(`Name: ${parsed.name}`);
|
|
204
|
-
if (typeof parsed.role === 'string')
|
|
205
|
-
parts.push(`Role: ${parsed.role}`);
|
|
206
|
-
if (typeof parsed.personality === 'string')
|
|
207
|
-
parts.push(`Personality: ${parsed.personality}`);
|
|
208
|
-
if (typeof parsed.communicationStyle === 'string')
|
|
209
|
-
parts.push(`Style: ${parsed.communicationStyle}`);
|
|
210
|
-
if (Array.isArray(parsed.focusAreas))
|
|
211
|
-
parts.push(`Focus: ${parsed.focusAreas.join(', ')}`);
|
|
212
|
-
if (Array.isArray(parsed.strengths))
|
|
213
|
-
parts.push(`Strengths: ${parsed.strengths.join(', ')}`);
|
|
214
|
-
if (parts.length === 0) {
|
|
215
|
-
return null;
|
|
216
|
-
}
|
|
217
|
-
return parts.join('\n');
|
|
218
|
-
}
|
|
219
|
-
catch {
|
|
220
|
-
return soul;
|
|
221
|
-
}
|
|
222
|
-
};
|
|
223
|
-
const buildAgentDispatchPrompt = (role, parentTask) => {
|
|
224
|
-
const lines = [
|
|
225
|
-
`You are ${role.displayName}${role.description ? ` — ${role.description}` : ''}.`,
|
|
226
|
-
];
|
|
227
|
-
if (role.capabilities && role.capabilities.length > 0) {
|
|
228
|
-
lines.push(`Capabilities: ${role.capabilities.join(', ')}`);
|
|
229
|
-
}
|
|
230
|
-
if (role.systemPrompt) {
|
|
231
|
-
lines.push('System guidance:');
|
|
232
|
-
lines.push(role.systemPrompt);
|
|
233
|
-
}
|
|
234
|
-
const soulSummary = buildSoulSummary(role.soul || undefined);
|
|
235
|
-
if (soulSummary) {
|
|
236
|
-
lines.push('Role notes:');
|
|
237
|
-
lines.push(soulSummary);
|
|
238
|
-
}
|
|
239
|
-
lines.push('');
|
|
240
|
-
lines.push(`Parent task: ${parentTask.title}`);
|
|
241
|
-
lines.push('Request:');
|
|
242
|
-
lines.push(parentTask.prompt);
|
|
243
|
-
lines.push('');
|
|
244
|
-
lines.push('Deliverables:');
|
|
245
|
-
lines.push('- Provide a concise summary of your findings.');
|
|
246
|
-
lines.push('- Call out risks or open questions.');
|
|
247
|
-
lines.push('- Recommend next steps.');
|
|
248
|
-
return lines.join('\n');
|
|
249
|
-
};
|
|
250
215
|
const x_manager_1 = require("../settings/x-manager");
|
|
251
216
|
const x_cli_1 = require("../utils/x-cli");
|
|
252
217
|
const custom_skill_loader_1 = require("../agent/custom-skill-loader");
|
|
@@ -263,6 +228,7 @@ const voice_settings_manager_1 = require("../voice/voice-settings-manager");
|
|
|
263
228
|
const VoiceService_1 = require("../voice/VoiceService");
|
|
264
229
|
// Global notification service instance
|
|
265
230
|
let notificationService = null;
|
|
231
|
+
const resolveCustomProviderId = (providerType) => providerType === 'kimi-coding' ? 'kimi-code' : providerType;
|
|
266
232
|
/**
|
|
267
233
|
* Get the notification service instance
|
|
268
234
|
*/
|
|
@@ -286,6 +252,9 @@ rate_limiter_1.rateLimiter.configure(types_1.IPC_CHANNELS.LLM_GET_OLLAMA_MODELS,
|
|
|
286
252
|
rate_limiter_1.rateLimiter.configure(types_1.IPC_CHANNELS.LLM_GET_GEMINI_MODELS, rate_limiter_1.RATE_LIMIT_CONFIGS.standard);
|
|
287
253
|
rate_limiter_1.rateLimiter.configure(types_1.IPC_CHANNELS.LLM_GET_OPENROUTER_MODELS, rate_limiter_1.RATE_LIMIT_CONFIGS.standard);
|
|
288
254
|
rate_limiter_1.rateLimiter.configure(types_1.IPC_CHANNELS.LLM_GET_BEDROCK_MODELS, rate_limiter_1.RATE_LIMIT_CONFIGS.standard);
|
|
255
|
+
rate_limiter_1.rateLimiter.configure(types_1.IPC_CHANNELS.LLM_GET_GROQ_MODELS, rate_limiter_1.RATE_LIMIT_CONFIGS.standard);
|
|
256
|
+
rate_limiter_1.rateLimiter.configure(types_1.IPC_CHANNELS.LLM_GET_XAI_MODELS, rate_limiter_1.RATE_LIMIT_CONFIGS.standard);
|
|
257
|
+
rate_limiter_1.rateLimiter.configure(types_1.IPC_CHANNELS.LLM_GET_KIMI_MODELS, rate_limiter_1.RATE_LIMIT_CONFIGS.standard);
|
|
289
258
|
rate_limiter_1.rateLimiter.configure(types_1.IPC_CHANNELS.SEARCH_SAVE_SETTINGS, rate_limiter_1.RATE_LIMIT_CONFIGS.limited);
|
|
290
259
|
rate_limiter_1.rateLimiter.configure(types_1.IPC_CHANNELS.SEARCH_TEST_PROVIDER, rate_limiter_1.RATE_LIMIT_CONFIGS.expensive);
|
|
291
260
|
rate_limiter_1.rateLimiter.configure(types_1.IPC_CHANNELS.GATEWAY_ADD_CHANNEL, rate_limiter_1.RATE_LIMIT_CONFIGS.limited);
|
|
@@ -543,6 +512,131 @@ async function setupIpcHandlers(dbManager, agentDaemon, gateway) {
|
|
|
543
512
|
return { success: false, error: `Failed to read file: ${error.message}` };
|
|
544
513
|
}
|
|
545
514
|
});
|
|
515
|
+
// File import handler - copy selected files into the workspace for attachment use
|
|
516
|
+
electron_1.ipcMain.handle('file:importToWorkspace', async (_, data) => {
|
|
517
|
+
const validated = (0, validation_1.validateInput)(validation_1.FileImportSchema, data, 'file import');
|
|
518
|
+
const workspace = workspaceRepo.findById(validated.workspaceId);
|
|
519
|
+
if (!workspace) {
|
|
520
|
+
throw new Error(`Workspace not found: ${validated.workspaceId}`);
|
|
521
|
+
}
|
|
522
|
+
if (!workspace.permissions.write) {
|
|
523
|
+
throw new Error('Write permission not granted for workspace');
|
|
524
|
+
}
|
|
525
|
+
const sanitizeFileName = (fileName) => {
|
|
526
|
+
const sanitized = fileName.replace(/[<>:"/\\|?*\x00-\x1F]/g, '_').trim();
|
|
527
|
+
return sanitized.length > 0 ? sanitized : 'file';
|
|
528
|
+
};
|
|
529
|
+
const ensureUniqueName = (dir, baseName, usedNames) => {
|
|
530
|
+
const ext = path.extname(baseName);
|
|
531
|
+
const stem = path.basename(baseName, ext);
|
|
532
|
+
let candidate = baseName;
|
|
533
|
+
let counter = 1;
|
|
534
|
+
while (usedNames.has(candidate) || fsSync.existsSync(path.join(dir, candidate))) {
|
|
535
|
+
candidate = `${stem}-${counter}${ext}`;
|
|
536
|
+
counter += 1;
|
|
537
|
+
}
|
|
538
|
+
usedNames.add(candidate);
|
|
539
|
+
return candidate;
|
|
540
|
+
};
|
|
541
|
+
let uploadRoot = null;
|
|
542
|
+
const usedNames = new Set();
|
|
543
|
+
const ensureUploadRoot = async () => {
|
|
544
|
+
if (uploadRoot)
|
|
545
|
+
return uploadRoot;
|
|
546
|
+
uploadRoot = path.join(workspace.path, '.cowork', 'uploads', `${Date.now()}`);
|
|
547
|
+
await fs.mkdir(uploadRoot, { recursive: true });
|
|
548
|
+
return uploadRoot;
|
|
549
|
+
};
|
|
550
|
+
const results = [];
|
|
551
|
+
for (const filePath of validated.files) {
|
|
552
|
+
const absolutePath = path.isAbsolute(filePath) ? filePath : path.resolve(filePath);
|
|
553
|
+
const stats = await fs.stat(absolutePath);
|
|
554
|
+
if (!stats.isFile()) {
|
|
555
|
+
throw new Error(`Not a file: ${filePath}`);
|
|
556
|
+
}
|
|
557
|
+
const sizeCheck = guardrail_manager_1.GuardrailManager.isFileSizeExceeded(stats.size);
|
|
558
|
+
if (sizeCheck.exceeded) {
|
|
559
|
+
throw new Error(`File "${path.basename(filePath)}" is ${sizeCheck.sizeMB.toFixed(1)}MB and exceeds the ${sizeCheck.limitMB}MB limit.`);
|
|
560
|
+
}
|
|
561
|
+
const mimeType = (mime_types_1.default.lookup(absolutePath) || undefined);
|
|
562
|
+
if (isPathWithinWorkspace(absolutePath, workspace.path)) {
|
|
563
|
+
results.push({
|
|
564
|
+
relativePath: path.relative(workspace.path, absolutePath),
|
|
565
|
+
fileName: path.basename(absolutePath),
|
|
566
|
+
size: stats.size,
|
|
567
|
+
mimeType,
|
|
568
|
+
});
|
|
569
|
+
continue;
|
|
570
|
+
}
|
|
571
|
+
const safeName = sanitizeFileName(path.basename(absolutePath));
|
|
572
|
+
const targetRoot = await ensureUploadRoot();
|
|
573
|
+
const uniqueName = ensureUniqueName(targetRoot, safeName, usedNames);
|
|
574
|
+
const destination = path.join(targetRoot, uniqueName);
|
|
575
|
+
await fs.copyFile(absolutePath, destination);
|
|
576
|
+
results.push({
|
|
577
|
+
relativePath: path.relative(workspace.path, destination),
|
|
578
|
+
fileName: uniqueName,
|
|
579
|
+
size: stats.size,
|
|
580
|
+
mimeType,
|
|
581
|
+
});
|
|
582
|
+
}
|
|
583
|
+
return results;
|
|
584
|
+
});
|
|
585
|
+
// File import handler - save provided file data into the workspace (clipboard / drag data)
|
|
586
|
+
electron_1.ipcMain.handle('file:importDataToWorkspace', async (_, data) => {
|
|
587
|
+
const validated = (0, validation_1.validateInput)(validation_1.FileImportDataSchema, data, 'file import data');
|
|
588
|
+
const workspace = workspaceRepo.findById(validated.workspaceId);
|
|
589
|
+
if (!workspace) {
|
|
590
|
+
throw new Error(`Workspace not found: ${validated.workspaceId}`);
|
|
591
|
+
}
|
|
592
|
+
if (!workspace.permissions.write) {
|
|
593
|
+
throw new Error('Write permission not granted for workspace');
|
|
594
|
+
}
|
|
595
|
+
const sanitizeFileName = (fileName) => {
|
|
596
|
+
const sanitized = fileName.replace(/[<>:"/\\|?*\x00-\x1F]/g, '_').trim();
|
|
597
|
+
return sanitized.length > 0 ? sanitized : 'file';
|
|
598
|
+
};
|
|
599
|
+
const ensureExtension = (fileName, mimeType) => {
|
|
600
|
+
if (path.extname(fileName) || !mimeType)
|
|
601
|
+
return fileName;
|
|
602
|
+
const ext = mime_types_1.default.extension(mimeType);
|
|
603
|
+
return ext ? `${fileName}.${ext}` : fileName;
|
|
604
|
+
};
|
|
605
|
+
const ensureUniqueName = (dir, baseName, usedNames) => {
|
|
606
|
+
const ext = path.extname(baseName);
|
|
607
|
+
const stem = path.basename(baseName, ext);
|
|
608
|
+
let candidate = baseName;
|
|
609
|
+
let counter = 1;
|
|
610
|
+
while (usedNames.has(candidate) || fsSync.existsSync(path.join(dir, candidate))) {
|
|
611
|
+
candidate = `${stem}-${counter}${ext}`;
|
|
612
|
+
counter += 1;
|
|
613
|
+
}
|
|
614
|
+
usedNames.add(candidate);
|
|
615
|
+
return candidate;
|
|
616
|
+
};
|
|
617
|
+
const uploadRoot = path.join(workspace.path, '.cowork', 'uploads', `${Date.now()}`);
|
|
618
|
+
await fs.mkdir(uploadRoot, { recursive: true });
|
|
619
|
+
const usedNames = new Set();
|
|
620
|
+
const results = [];
|
|
621
|
+
for (const file of validated.files) {
|
|
622
|
+
const rawName = ensureExtension(sanitizeFileName(file.name), file.mimeType);
|
|
623
|
+
const uniqueName = ensureUniqueName(uploadRoot, rawName, usedNames);
|
|
624
|
+
const destination = path.join(uploadRoot, uniqueName);
|
|
625
|
+
const buffer = Buffer.from(file.data, 'base64');
|
|
626
|
+
const sizeCheck = guardrail_manager_1.GuardrailManager.isFileSizeExceeded(buffer.length);
|
|
627
|
+
if (sizeCheck.exceeded) {
|
|
628
|
+
throw new Error(`File "${rawName}" is ${sizeCheck.sizeMB.toFixed(1)}MB and exceeds the ${sizeCheck.limitMB}MB limit.`);
|
|
629
|
+
}
|
|
630
|
+
await fs.writeFile(destination, buffer);
|
|
631
|
+
results.push({
|
|
632
|
+
relativePath: path.relative(workspace.path, destination),
|
|
633
|
+
fileName: uniqueName,
|
|
634
|
+
size: buffer.length,
|
|
635
|
+
mimeType: file.mimeType,
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
return results;
|
|
639
|
+
});
|
|
546
640
|
// Workspace handlers
|
|
547
641
|
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.WORKSPACE_CREATE, async (_, data) => {
|
|
548
642
|
const validated = (0, validation_1.validateInput)(validation_1.WorkspaceCreateSchema, data, 'workspace');
|
|
@@ -572,7 +666,16 @@ async function setupIpcHandlers(dbManager, agentDaemon, gateway) {
|
|
|
572
666
|
return getOrCreateTempWorkspace();
|
|
573
667
|
});
|
|
574
668
|
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.WORKSPACE_SELECT, async (_, id) => {
|
|
575
|
-
|
|
669
|
+
const workspace = workspaceRepo.findById(id);
|
|
670
|
+
if (workspace && workspace.id !== types_1.TEMP_WORKSPACE_ID) {
|
|
671
|
+
try {
|
|
672
|
+
workspaceRepo.updateLastUsedAt(workspace.id);
|
|
673
|
+
}
|
|
674
|
+
catch (error) {
|
|
675
|
+
console.warn('Failed to update workspace last used time:', error);
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
return workspace;
|
|
576
679
|
});
|
|
577
680
|
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.WORKSPACE_UPDATE_PERMISSIONS, async (_, id, permissions) => {
|
|
578
681
|
const workspace = workspaceRepo.findById(id);
|
|
@@ -583,6 +686,14 @@ async function setupIpcHandlers(dbManager, agentDaemon, gateway) {
|
|
|
583
686
|
workspaceRepo.updatePermissions(id, updatedPermissions);
|
|
584
687
|
return workspaceRepo.findById(id);
|
|
585
688
|
});
|
|
689
|
+
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.WORKSPACE_TOUCH, async (_, id) => {
|
|
690
|
+
const workspace = workspaceRepo.findById(id);
|
|
691
|
+
if (!workspace) {
|
|
692
|
+
throw new Error(`Workspace not found: ${id}`);
|
|
693
|
+
}
|
|
694
|
+
workspaceRepo.updateLastUsedAt(id);
|
|
695
|
+
return workspaceRepo.findById(id);
|
|
696
|
+
});
|
|
586
697
|
// Task handlers
|
|
587
698
|
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.TASK_CREATE, async (_, data) => {
|
|
588
699
|
checkRateLimit(types_1.IPC_CHANNELS.TASK_CREATE);
|
|
@@ -596,6 +707,37 @@ async function setupIpcHandlers(dbManager, agentDaemon, gateway) {
|
|
|
596
707
|
budgetTokens,
|
|
597
708
|
budgetCost,
|
|
598
709
|
});
|
|
710
|
+
if (workspaceId !== types_1.TEMP_WORKSPACE_ID) {
|
|
711
|
+
try {
|
|
712
|
+
workspaceRepo.updateLastUsedAt(workspaceId);
|
|
713
|
+
}
|
|
714
|
+
catch (error) {
|
|
715
|
+
console.warn('Failed to update workspace last used time:', error);
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
// Capture mentioned agent roles for deferred dispatch (after main plan is created)
|
|
719
|
+
try {
|
|
720
|
+
const activeRoles = agentRoleRepo.findAll(false).filter((role) => role.isActive);
|
|
721
|
+
const mentionedRoles = extractMentionedRoles(`${title}\n${prompt}`, activeRoles);
|
|
722
|
+
const mentionedAgentRoleIds = mentionedRoles.map((role) => role.id);
|
|
723
|
+
if (mentionedAgentRoleIds.length > 0) {
|
|
724
|
+
taskRepo.update(task.id, { mentionedAgentRoleIds });
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
catch (error) {
|
|
728
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
729
|
+
console.error('Failed to record mentioned agents:', error);
|
|
730
|
+
// Notify user of dispatch failure via activity feed
|
|
731
|
+
const errorActivity = activityRepo.create({
|
|
732
|
+
workspaceId: task.workspaceId,
|
|
733
|
+
taskId: task.id,
|
|
734
|
+
actorType: 'system',
|
|
735
|
+
activityType: 'error',
|
|
736
|
+
title: 'Agent mention capture failed',
|
|
737
|
+
description: `Failed to record mentioned agents for deferred dispatch: ${errorMessage}`,
|
|
738
|
+
});
|
|
739
|
+
getMainWindow()?.webContents.send(types_1.IPC_CHANNELS.ACTIVITY_EVENT, { type: 'created', activity: errorActivity });
|
|
740
|
+
}
|
|
599
741
|
// Start task execution in agent daemon
|
|
600
742
|
try {
|
|
601
743
|
await agentDaemon.startTask(task);
|
|
@@ -608,68 +750,6 @@ async function setupIpcHandlers(dbManager, agentDaemon, gateway) {
|
|
|
608
750
|
});
|
|
609
751
|
throw new Error(error.message || 'Failed to start task. Please check your LLM provider settings.');
|
|
610
752
|
}
|
|
611
|
-
// Dispatch to mentioned agents (e.g., "Please review @Vision @Loki")
|
|
612
|
-
try {
|
|
613
|
-
const activeRoles = agentRoleRepo.findAll(false).filter((role) => role.isActive);
|
|
614
|
-
const mentionedRoles = extractMentionedRoles(`${title}\n${prompt}`, activeRoles);
|
|
615
|
-
const dispatchRoles = mentionedRoles.length > 0 ? mentionedRoles : activeRoles;
|
|
616
|
-
if (dispatchRoles.length > 0) {
|
|
617
|
-
taskRepo.update(task.id, {
|
|
618
|
-
mentionedAgentRoleIds: dispatchRoles.map((role) => role.id),
|
|
619
|
-
});
|
|
620
|
-
for (const role of dispatchRoles) {
|
|
621
|
-
const childPrompt = buildAgentDispatchPrompt(role, task);
|
|
622
|
-
const childTask = await agentDaemon.createChildTask({
|
|
623
|
-
title: `@${role.displayName}: ${task.title}`,
|
|
624
|
-
prompt: childPrompt,
|
|
625
|
-
workspaceId: task.workspaceId,
|
|
626
|
-
parentTaskId: task.id,
|
|
627
|
-
agentType: 'sub',
|
|
628
|
-
agentConfig: {
|
|
629
|
-
...(role.modelKey ? { modelKey: role.modelKey } : {}),
|
|
630
|
-
...(role.personalityId ? { personalityId: role.personalityId } : {}),
|
|
631
|
-
retainMemory: false,
|
|
632
|
-
},
|
|
633
|
-
});
|
|
634
|
-
taskRepo.update(childTask.id, {
|
|
635
|
-
assignedAgentRoleId: role.id,
|
|
636
|
-
boardColumn: 'todo',
|
|
637
|
-
});
|
|
638
|
-
const dispatchActivity = activityRepo.create({
|
|
639
|
-
workspaceId: task.workspaceId,
|
|
640
|
-
taskId: task.id,
|
|
641
|
-
agentRoleId: role.id,
|
|
642
|
-
actorType: 'system',
|
|
643
|
-
activityType: 'agent_assigned',
|
|
644
|
-
title: `Dispatched to ${role.displayName}`,
|
|
645
|
-
description: childTask.title,
|
|
646
|
-
});
|
|
647
|
-
getMainWindow()?.webContents.send(types_1.IPC_CHANNELS.ACTIVITY_EVENT, { type: 'created', activity: dispatchActivity });
|
|
648
|
-
const mention = mentionRepo.create({
|
|
649
|
-
workspaceId: task.workspaceId,
|
|
650
|
-
taskId: task.id,
|
|
651
|
-
toAgentRoleId: role.id,
|
|
652
|
-
mentionType: 'request',
|
|
653
|
-
context: `New task: ${task.title}`,
|
|
654
|
-
});
|
|
655
|
-
getMainWindow()?.webContents.send(types_1.IPC_CHANNELS.MENTION_EVENT, { type: 'created', mention });
|
|
656
|
-
const mentionActivity = activityRepo.create({
|
|
657
|
-
workspaceId: task.workspaceId,
|
|
658
|
-
taskId: task.id,
|
|
659
|
-
agentRoleId: role.id,
|
|
660
|
-
actorType: 'user',
|
|
661
|
-
activityType: 'mention',
|
|
662
|
-
title: `@${role.displayName} mentioned`,
|
|
663
|
-
description: mention.context,
|
|
664
|
-
metadata: { mentionId: mention.id, mentionType: mention.mentionType },
|
|
665
|
-
});
|
|
666
|
-
getMainWindow()?.webContents.send(types_1.IPC_CHANNELS.ACTIVITY_EVENT, { type: 'created', activity: mentionActivity });
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
catch (error) {
|
|
671
|
-
console.error('Failed to dispatch to mentioned agents:', error);
|
|
672
|
-
}
|
|
673
753
|
return task;
|
|
674
754
|
});
|
|
675
755
|
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.TASK_GET, async (_, id) => {
|
|
@@ -872,6 +952,26 @@ async function setupIpcHandlers(dbManager, agentDaemon, gateway) {
|
|
|
872
952
|
authMethod: existingSettings.openai.authMethod,
|
|
873
953
|
};
|
|
874
954
|
}
|
|
955
|
+
const normalizeAzureSettings = (incoming, existing) => {
|
|
956
|
+
if (!incoming && !existing)
|
|
957
|
+
return undefined;
|
|
958
|
+
const mergedDeployments = [
|
|
959
|
+
...(incoming?.deployments || []),
|
|
960
|
+
...(existing?.deployments || []),
|
|
961
|
+
]
|
|
962
|
+
.map((entry) => entry.trim())
|
|
963
|
+
.filter(Boolean);
|
|
964
|
+
const deployment = (incoming?.deployment || existing?.deployment || mergedDeployments[0] || '').trim();
|
|
965
|
+
if (deployment && !mergedDeployments.includes(deployment)) {
|
|
966
|
+
mergedDeployments.unshift(deployment);
|
|
967
|
+
}
|
|
968
|
+
return {
|
|
969
|
+
...(existing || {}),
|
|
970
|
+
...(incoming || {}),
|
|
971
|
+
deployment: deployment || undefined,
|
|
972
|
+
deployments: mergedDeployments.length > 0 ? Array.from(new Set(mergedDeployments)) : undefined,
|
|
973
|
+
};
|
|
974
|
+
};
|
|
875
975
|
llm_1.LLMProviderFactory.saveSettings({
|
|
876
976
|
providerType: validated.providerType,
|
|
877
977
|
modelKey: validated.modelKey,
|
|
@@ -881,12 +981,20 @@ async function setupIpcHandlers(dbManager, agentDaemon, gateway) {
|
|
|
881
981
|
gemini: validated.gemini,
|
|
882
982
|
openrouter: validated.openrouter,
|
|
883
983
|
openai: openaiSettings,
|
|
984
|
+
azure: normalizeAzureSettings(validated.azure, existingSettings.azure),
|
|
985
|
+
groq: validated.groq,
|
|
986
|
+
xai: validated.xai,
|
|
987
|
+
kimi: validated.kimi,
|
|
988
|
+
customProviders: validated.customProviders ?? existingSettings.customProviders,
|
|
884
989
|
// Preserve cached models from existing settings
|
|
885
990
|
cachedGeminiModels: existingSettings.cachedGeminiModels,
|
|
886
991
|
cachedOpenRouterModels: existingSettings.cachedOpenRouterModels,
|
|
887
992
|
cachedOllamaModels: existingSettings.cachedOllamaModels,
|
|
888
993
|
cachedBedrockModels: existingSettings.cachedBedrockModels,
|
|
889
994
|
cachedOpenAIModels: existingSettings.cachedOpenAIModels,
|
|
995
|
+
cachedGroqModels: existingSettings.cachedGroqModels,
|
|
996
|
+
cachedXaiModels: existingSettings.cachedXaiModels,
|
|
997
|
+
cachedKimiModels: existingSettings.cachedKimiModels,
|
|
890
998
|
});
|
|
891
999
|
// Clear cache so next task uses new settings
|
|
892
1000
|
llm_1.LLMProviderFactory.clearCache();
|
|
@@ -902,9 +1010,12 @@ async function setupIpcHandlers(dbManager, agentDaemon, gateway) {
|
|
|
902
1010
|
openaiAccessToken = settings.openai?.accessToken;
|
|
903
1011
|
openaiRefreshToken = settings.openai?.refreshToken;
|
|
904
1012
|
}
|
|
1013
|
+
const resolvedProviderType = resolveCustomProviderId(config.providerType);
|
|
1014
|
+
const customProviderConfig = config.customProviders?.[resolvedProviderType] || config.customProviders?.[config.providerType];
|
|
1015
|
+
const azureDeployment = config.azure?.deployment || config.azure?.deployments?.[0];
|
|
905
1016
|
const providerConfig = {
|
|
906
1017
|
type: config.providerType,
|
|
907
|
-
model: llm_1.LLMProviderFactory.getModelId(config.modelKey, config.providerType, config.ollama?.model, config.gemini?.model, config.openrouter?.model, config.openai?.model),
|
|
1018
|
+
model: llm_1.LLMProviderFactory.getModelId(config.modelKey, config.providerType, config.ollama?.model, config.gemini?.model, config.openrouter?.model, config.openai?.model, azureDeployment, config.groq?.model, config.xai?.model, config.kimi?.model, config.customProviders),
|
|
908
1019
|
anthropicApiKey: config.anthropic?.apiKey,
|
|
909
1020
|
awsRegion: config.bedrock?.region,
|
|
910
1021
|
awsAccessKeyId: config.bedrock?.accessKeyId,
|
|
@@ -915,9 +1026,22 @@ async function setupIpcHandlers(dbManager, agentDaemon, gateway) {
|
|
|
915
1026
|
ollamaApiKey: config.ollama?.apiKey,
|
|
916
1027
|
geminiApiKey: config.gemini?.apiKey,
|
|
917
1028
|
openrouterApiKey: config.openrouter?.apiKey,
|
|
1029
|
+
openrouterBaseUrl: config.openrouter?.baseUrl,
|
|
918
1030
|
openaiApiKey: config.openai?.apiKey,
|
|
919
1031
|
openaiAccessToken: openaiAccessToken,
|
|
920
1032
|
openaiRefreshToken: openaiRefreshToken,
|
|
1033
|
+
azureApiKey: config.azure?.apiKey,
|
|
1034
|
+
azureEndpoint: config.azure?.endpoint,
|
|
1035
|
+
azureDeployment: azureDeployment,
|
|
1036
|
+
azureApiVersion: config.azure?.apiVersion,
|
|
1037
|
+
groqApiKey: config.groq?.apiKey,
|
|
1038
|
+
groqBaseUrl: config.groq?.baseUrl,
|
|
1039
|
+
xaiApiKey: config.xai?.apiKey,
|
|
1040
|
+
xaiBaseUrl: config.xai?.baseUrl,
|
|
1041
|
+
kimiApiKey: config.kimi?.apiKey,
|
|
1042
|
+
kimiBaseUrl: config.kimi?.baseUrl,
|
|
1043
|
+
providerApiKey: customProviderConfig?.apiKey,
|
|
1044
|
+
providerBaseUrl: customProviderConfig?.baseUrl,
|
|
921
1045
|
};
|
|
922
1046
|
return llm_1.LLMProviderFactory.testProvider(providerConfig);
|
|
923
1047
|
});
|
|
@@ -936,132 +1060,230 @@ async function setupIpcHandlers(dbManager, agentDaemon, gateway) {
|
|
|
936
1060
|
// Get models based on the current provider type
|
|
937
1061
|
let models = [];
|
|
938
1062
|
let currentModel = settings.modelKey;
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
}
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
models =
|
|
958
|
-
|
|
959
|
-
else {
|
|
960
|
-
// Fall back to static models
|
|
961
|
-
models = Object.values(llm_1.GEMINI_MODELS).map((value) => ({
|
|
962
|
-
key: value.id,
|
|
1063
|
+
const resolvedProviderType = resolveCustomProviderId(settings.providerType);
|
|
1064
|
+
const customEntry = llm_provider_catalog_1.CUSTOM_PROVIDER_MAP.get(resolvedProviderType);
|
|
1065
|
+
if (customEntry) {
|
|
1066
|
+
const customConfig = settings.customProviders?.[resolvedProviderType] || settings.customProviders?.[settings.providerType];
|
|
1067
|
+
currentModel = customConfig?.model || customEntry.defaultModel;
|
|
1068
|
+
models = [
|
|
1069
|
+
{
|
|
1070
|
+
key: currentModel,
|
|
1071
|
+
displayName: currentModel,
|
|
1072
|
+
description: customEntry.description || `${customEntry.name} model`,
|
|
1073
|
+
},
|
|
1074
|
+
];
|
|
1075
|
+
}
|
|
1076
|
+
else {
|
|
1077
|
+
switch (settings.providerType) {
|
|
1078
|
+
case 'anthropic':
|
|
1079
|
+
case 'bedrock':
|
|
1080
|
+
// Use Anthropic/Bedrock models from MODELS
|
|
1081
|
+
models = Object.entries(llm_1.MODELS).map(([key, value]) => ({
|
|
1082
|
+
key,
|
|
963
1083
|
displayName: value.displayName,
|
|
964
|
-
description:
|
|
1084
|
+
description: key.includes('opus') ? 'Most capable for complex work' :
|
|
1085
|
+
key.includes('sonnet') ? 'Balanced performance and speed' :
|
|
1086
|
+
'Fast and efficient',
|
|
965
1087
|
}));
|
|
1088
|
+
break;
|
|
1089
|
+
case 'gemini': {
|
|
1090
|
+
// For Gemini, use the specific model from settings (full model ID)
|
|
1091
|
+
currentModel = settings.gemini?.model || 'gemini-2.0-flash';
|
|
1092
|
+
// Use cached models if available, otherwise fall back to static list
|
|
1093
|
+
const cachedGemini = llm_1.LLMProviderFactory.getCachedModels('gemini');
|
|
1094
|
+
if (cachedGemini && cachedGemini.length > 0) {
|
|
1095
|
+
models = cachedGemini;
|
|
1096
|
+
}
|
|
1097
|
+
else {
|
|
1098
|
+
// Fall back to static models
|
|
1099
|
+
models = Object.values(llm_1.GEMINI_MODELS).map((value) => ({
|
|
1100
|
+
key: value.id,
|
|
1101
|
+
displayName: value.displayName,
|
|
1102
|
+
description: value.description,
|
|
1103
|
+
}));
|
|
1104
|
+
}
|
|
1105
|
+
// Ensure the currently selected model is in the list
|
|
1106
|
+
if (currentModel && !models.some(m => m.key === currentModel)) {
|
|
1107
|
+
models.unshift({
|
|
1108
|
+
key: currentModel,
|
|
1109
|
+
displayName: currentModel,
|
|
1110
|
+
description: 'Selected model',
|
|
1111
|
+
});
|
|
1112
|
+
}
|
|
1113
|
+
break;
|
|
966
1114
|
}
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
1115
|
+
case 'openrouter': {
|
|
1116
|
+
// For OpenRouter, use the specific model from settings (full model ID)
|
|
1117
|
+
currentModel = settings.openrouter?.model || 'anthropic/claude-3.5-sonnet';
|
|
1118
|
+
// Use cached models if available, otherwise fall back to static list
|
|
1119
|
+
const cachedOpenRouter = llm_1.LLMProviderFactory.getCachedModels('openrouter');
|
|
1120
|
+
if (cachedOpenRouter && cachedOpenRouter.length > 0) {
|
|
1121
|
+
models = cachedOpenRouter;
|
|
1122
|
+
}
|
|
1123
|
+
else {
|
|
1124
|
+
// Fall back to static models
|
|
1125
|
+
models = Object.values(llm_1.OPENROUTER_MODELS).map((value) => ({
|
|
1126
|
+
key: value.id,
|
|
1127
|
+
displayName: value.displayName,
|
|
1128
|
+
description: value.description,
|
|
1129
|
+
}));
|
|
1130
|
+
}
|
|
1131
|
+
// Ensure the currently selected model is in the list
|
|
1132
|
+
if (currentModel && !models.some(m => m.key === currentModel)) {
|
|
1133
|
+
models.unshift({
|
|
1134
|
+
key: currentModel,
|
|
1135
|
+
displayName: currentModel,
|
|
1136
|
+
description: 'Selected model',
|
|
1137
|
+
});
|
|
1138
|
+
}
|
|
1139
|
+
break;
|
|
974
1140
|
}
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
1141
|
+
case 'ollama': {
|
|
1142
|
+
// For Ollama, use the specific model from settings
|
|
1143
|
+
currentModel = settings.ollama?.model || 'llama3.2';
|
|
1144
|
+
// Use cached models if available, otherwise fall back to static list
|
|
1145
|
+
const cachedOllama = llm_1.LLMProviderFactory.getCachedModels('ollama');
|
|
1146
|
+
if (cachedOllama && cachedOllama.length > 0) {
|
|
1147
|
+
models = cachedOllama;
|
|
1148
|
+
}
|
|
1149
|
+
else {
|
|
1150
|
+
// Fall back to static models
|
|
1151
|
+
models = Object.entries(llm_1.OLLAMA_MODELS).map(([key, value]) => ({
|
|
1152
|
+
key,
|
|
1153
|
+
displayName: value.displayName,
|
|
1154
|
+
description: `${value.size} parameter model`,
|
|
1155
|
+
}));
|
|
1156
|
+
}
|
|
1157
|
+
// Ensure the currently selected model is in the list
|
|
1158
|
+
if (currentModel && !models.some(m => m.key === currentModel)) {
|
|
1159
|
+
models.unshift({
|
|
1160
|
+
key: currentModel,
|
|
1161
|
+
displayName: currentModel,
|
|
1162
|
+
description: 'Selected model',
|
|
1163
|
+
});
|
|
1164
|
+
}
|
|
1165
|
+
break;
|
|
984
1166
|
}
|
|
985
|
-
|
|
986
|
-
//
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
1167
|
+
case 'openai': {
|
|
1168
|
+
// For OpenAI, use the specific model from settings
|
|
1169
|
+
currentModel = settings.openai?.model || 'gpt-4o-mini';
|
|
1170
|
+
// Use cached models if available, otherwise fall back to static list
|
|
1171
|
+
const cachedOpenAI = llm_1.LLMProviderFactory.getCachedModels('openai');
|
|
1172
|
+
if (cachedOpenAI && cachedOpenAI.length > 0) {
|
|
1173
|
+
models = cachedOpenAI;
|
|
1174
|
+
}
|
|
1175
|
+
else {
|
|
1176
|
+
// Fall back to static models
|
|
1177
|
+
models = [
|
|
1178
|
+
{ key: 'gpt-4o', displayName: 'GPT-4o', description: 'Most capable model for complex tasks' },
|
|
1179
|
+
{ key: 'gpt-4o-mini', displayName: 'GPT-4o Mini', description: 'Fast and affordable for most tasks' },
|
|
1180
|
+
{ key: 'gpt-4-turbo', displayName: 'GPT-4 Turbo', description: 'Previous generation flagship' },
|
|
1181
|
+
{ key: 'gpt-3.5-turbo', displayName: 'GPT-3.5 Turbo', description: 'Fast and cost-effective' },
|
|
1182
|
+
{ key: 'o1', displayName: 'o1', description: 'Advanced reasoning model' },
|
|
1183
|
+
{ key: 'o1-mini', displayName: 'o1 Mini', description: 'Fast reasoning model' },
|
|
1184
|
+
];
|
|
1185
|
+
}
|
|
1186
|
+
// Ensure the currently selected model is in the list
|
|
1187
|
+
if (currentModel && !models.some(m => m.key === currentModel)) {
|
|
1188
|
+
models.unshift({
|
|
1189
|
+
key: currentModel,
|
|
1190
|
+
displayName: currentModel,
|
|
1191
|
+
description: 'Selected model',
|
|
1192
|
+
});
|
|
1193
|
+
}
|
|
1194
|
+
break;
|
|
1195
|
+
}
|
|
1196
|
+
case 'azure': {
|
|
1197
|
+
const deployments = (settings.azure?.deployments || []).filter(Boolean);
|
|
1198
|
+
currentModel = settings.azure?.deployment || deployments[0] || 'deployment-name';
|
|
1199
|
+
models = deployments.map((deployment) => ({
|
|
1200
|
+
key: deployment,
|
|
1201
|
+
displayName: deployment,
|
|
1202
|
+
description: 'Azure OpenAI deployment',
|
|
991
1203
|
}));
|
|
1204
|
+
if (currentModel && !models.some(m => m.key === currentModel)) {
|
|
1205
|
+
models.unshift({
|
|
1206
|
+
key: currentModel,
|
|
1207
|
+
displayName: currentModel,
|
|
1208
|
+
description: 'Selected model',
|
|
1209
|
+
});
|
|
1210
|
+
}
|
|
1211
|
+
break;
|
|
992
1212
|
}
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1213
|
+
case 'groq': {
|
|
1214
|
+
currentModel = settings.groq?.model || 'llama-3.1-8b-instant';
|
|
1215
|
+
const cachedGroq = llm_1.LLMProviderFactory.getCachedModels('groq');
|
|
1216
|
+
if (cachedGroq && cachedGroq.length > 0) {
|
|
1217
|
+
models = cachedGroq;
|
|
1218
|
+
}
|
|
1219
|
+
else {
|
|
1220
|
+
models = Object.values(llm_1.GROQ_MODELS).map((value) => ({
|
|
1221
|
+
key: value.id,
|
|
1222
|
+
displayName: value.displayName,
|
|
1223
|
+
description: value.description,
|
|
1224
|
+
}));
|
|
1225
|
+
}
|
|
1226
|
+
if (currentModel && !models.some(m => m.key === currentModel)) {
|
|
1227
|
+
models.unshift({
|
|
1228
|
+
key: currentModel,
|
|
1229
|
+
displayName: currentModel,
|
|
1230
|
+
description: 'Selected model',
|
|
1231
|
+
});
|
|
1232
|
+
}
|
|
1233
|
+
break;
|
|
1000
1234
|
}
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1235
|
+
case 'xai': {
|
|
1236
|
+
currentModel = settings.xai?.model || 'grok-4-fast-non-reasoning';
|
|
1237
|
+
const cachedXai = llm_1.LLMProviderFactory.getCachedModels('xai');
|
|
1238
|
+
if (cachedXai && cachedXai.length > 0) {
|
|
1239
|
+
models = cachedXai;
|
|
1240
|
+
}
|
|
1241
|
+
else {
|
|
1242
|
+
models = Object.values(llm_1.XAI_MODELS).map((value) => ({
|
|
1243
|
+
key: value.id,
|
|
1244
|
+
displayName: value.displayName,
|
|
1245
|
+
description: value.description,
|
|
1246
|
+
}));
|
|
1247
|
+
}
|
|
1248
|
+
if (currentModel && !models.some(m => m.key === currentModel)) {
|
|
1249
|
+
models.unshift({
|
|
1250
|
+
key: currentModel,
|
|
1251
|
+
displayName: currentModel,
|
|
1252
|
+
description: 'Selected model',
|
|
1253
|
+
});
|
|
1254
|
+
}
|
|
1255
|
+
break;
|
|
1256
|
+
}
|
|
1257
|
+
case 'kimi': {
|
|
1258
|
+
currentModel = settings.kimi?.model || 'kimi-k2.5';
|
|
1259
|
+
const cachedKimi = llm_1.LLMProviderFactory.getCachedModels('kimi');
|
|
1260
|
+
if (cachedKimi && cachedKimi.length > 0) {
|
|
1261
|
+
models = cachedKimi;
|
|
1262
|
+
}
|
|
1263
|
+
else {
|
|
1264
|
+
models = Object.values(llm_1.KIMI_MODELS).map((value) => ({
|
|
1265
|
+
key: value.id,
|
|
1266
|
+
displayName: value.displayName,
|
|
1267
|
+
description: value.description,
|
|
1268
|
+
}));
|
|
1269
|
+
}
|
|
1270
|
+
if (currentModel && !models.some(m => m.key === currentModel)) {
|
|
1271
|
+
models.unshift({
|
|
1272
|
+
key: currentModel,
|
|
1273
|
+
displayName: currentModel,
|
|
1274
|
+
description: 'Selected model',
|
|
1275
|
+
});
|
|
1276
|
+
}
|
|
1277
|
+
break;
|
|
1010
1278
|
}
|
|
1011
|
-
|
|
1012
|
-
//
|
|
1013
|
-
models = Object.entries(llm_1.
|
|
1279
|
+
default:
|
|
1280
|
+
// Fallback to Anthropic models
|
|
1281
|
+
models = Object.entries(llm_1.MODELS).map(([key, value]) => ({
|
|
1014
1282
|
key,
|
|
1015
1283
|
displayName: value.displayName,
|
|
1016
|
-
description:
|
|
1284
|
+
description: 'Claude model',
|
|
1017
1285
|
}));
|
|
1018
|
-
}
|
|
1019
|
-
// Ensure the currently selected model is in the list
|
|
1020
|
-
if (currentModel && !models.some(m => m.key === currentModel)) {
|
|
1021
|
-
models.unshift({
|
|
1022
|
-
key: currentModel,
|
|
1023
|
-
displayName: currentModel,
|
|
1024
|
-
description: 'Selected model',
|
|
1025
|
-
});
|
|
1026
|
-
}
|
|
1027
|
-
break;
|
|
1028
|
-
}
|
|
1029
|
-
case 'openai': {
|
|
1030
|
-
// For OpenAI, use the specific model from settings
|
|
1031
|
-
currentModel = settings.openai?.model || 'gpt-4o-mini';
|
|
1032
|
-
// Use cached models if available, otherwise fall back to static list
|
|
1033
|
-
const cachedOpenAI = llm_1.LLMProviderFactory.getCachedModels('openai');
|
|
1034
|
-
if (cachedOpenAI && cachedOpenAI.length > 0) {
|
|
1035
|
-
models = cachedOpenAI;
|
|
1036
|
-
}
|
|
1037
|
-
else {
|
|
1038
|
-
// Fall back to static models
|
|
1039
|
-
models = [
|
|
1040
|
-
{ key: 'gpt-4o', displayName: 'GPT-4o', description: 'Most capable model for complex tasks' },
|
|
1041
|
-
{ key: 'gpt-4o-mini', displayName: 'GPT-4o Mini', description: 'Fast and affordable for most tasks' },
|
|
1042
|
-
{ key: 'gpt-4-turbo', displayName: 'GPT-4 Turbo', description: 'Previous generation flagship' },
|
|
1043
|
-
{ key: 'gpt-3.5-turbo', displayName: 'GPT-3.5 Turbo', description: 'Fast and cost-effective' },
|
|
1044
|
-
{ key: 'o1', displayName: 'o1', description: 'Advanced reasoning model' },
|
|
1045
|
-
{ key: 'o1-mini', displayName: 'o1 Mini', description: 'Fast reasoning model' },
|
|
1046
|
-
];
|
|
1047
|
-
}
|
|
1048
|
-
// Ensure the currently selected model is in the list
|
|
1049
|
-
if (currentModel && !models.some(m => m.key === currentModel)) {
|
|
1050
|
-
models.unshift({
|
|
1051
|
-
key: currentModel,
|
|
1052
|
-
displayName: currentModel,
|
|
1053
|
-
description: 'Selected model',
|
|
1054
|
-
});
|
|
1055
|
-
}
|
|
1056
|
-
break;
|
|
1057
1286
|
}
|
|
1058
|
-
default:
|
|
1059
|
-
// Fallback to Anthropic models
|
|
1060
|
-
models = Object.entries(llm_1.MODELS).map(([key, value]) => ({
|
|
1061
|
-
key,
|
|
1062
|
-
displayName: value.displayName,
|
|
1063
|
-
description: 'Claude model',
|
|
1064
|
-
}));
|
|
1065
1287
|
}
|
|
1066
1288
|
return {
|
|
1067
1289
|
currentProvider: settings.providerType,
|
|
@@ -1073,26 +1295,61 @@ async function setupIpcHandlers(dbManager, agentDaemon, gateway) {
|
|
|
1073
1295
|
// Set the current model (persists selection across sessions)
|
|
1074
1296
|
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.LLM_SET_MODEL, async (_, modelKey) => {
|
|
1075
1297
|
const settings = llm_1.LLMProviderFactory.loadSettings();
|
|
1298
|
+
const resolvedProviderType = resolveCustomProviderId(settings.providerType);
|
|
1076
1299
|
// Update the model key based on the current provider
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1300
|
+
if (llm_provider_catalog_1.CUSTOM_PROVIDER_IDS.has(resolvedProviderType)) {
|
|
1301
|
+
const existing = settings.customProviders?.[resolvedProviderType] || {};
|
|
1302
|
+
settings.customProviders = {
|
|
1303
|
+
...(settings.customProviders || {}),
|
|
1304
|
+
[resolvedProviderType]: {
|
|
1305
|
+
...existing,
|
|
1306
|
+
model: modelKey,
|
|
1307
|
+
},
|
|
1308
|
+
};
|
|
1309
|
+
}
|
|
1310
|
+
else {
|
|
1311
|
+
switch (settings.providerType) {
|
|
1312
|
+
case 'gemini':
|
|
1313
|
+
settings.gemini = { ...settings.gemini, model: modelKey };
|
|
1314
|
+
break;
|
|
1315
|
+
case 'openrouter':
|
|
1316
|
+
settings.openrouter = { ...settings.openrouter, model: modelKey };
|
|
1317
|
+
break;
|
|
1318
|
+
case 'ollama':
|
|
1319
|
+
settings.ollama = { ...settings.ollama, model: modelKey };
|
|
1320
|
+
break;
|
|
1321
|
+
case 'openai':
|
|
1322
|
+
settings.openai = { ...settings.openai, model: modelKey };
|
|
1323
|
+
break;
|
|
1324
|
+
case 'azure':
|
|
1325
|
+
{
|
|
1326
|
+
const existingDeployments = (settings.azure?.deployments || []).filter(Boolean);
|
|
1327
|
+
const nextDeployments = existingDeployments.includes(modelKey)
|
|
1328
|
+
? existingDeployments
|
|
1329
|
+
: [modelKey, ...existingDeployments];
|
|
1330
|
+
settings.azure = {
|
|
1331
|
+
...settings.azure,
|
|
1332
|
+
deployment: modelKey,
|
|
1333
|
+
deployments: nextDeployments.length > 0 ? nextDeployments : undefined,
|
|
1334
|
+
};
|
|
1335
|
+
}
|
|
1336
|
+
break;
|
|
1337
|
+
case 'groq':
|
|
1338
|
+
settings.groq = { ...settings.groq, model: modelKey };
|
|
1339
|
+
break;
|
|
1340
|
+
case 'xai':
|
|
1341
|
+
settings.xai = { ...settings.xai, model: modelKey };
|
|
1342
|
+
break;
|
|
1343
|
+
case 'kimi':
|
|
1344
|
+
settings.kimi = { ...settings.kimi, model: modelKey };
|
|
1345
|
+
break;
|
|
1346
|
+
case 'anthropic':
|
|
1347
|
+
case 'bedrock':
|
|
1348
|
+
default:
|
|
1349
|
+
// For Anthropic/Bedrock, use the modelKey field
|
|
1350
|
+
settings.modelKey = modelKey;
|
|
1351
|
+
break;
|
|
1352
|
+
}
|
|
1096
1353
|
}
|
|
1097
1354
|
llm_1.LLMProviderFactory.saveSettings(settings);
|
|
1098
1355
|
return { success: true };
|
|
@@ -1123,9 +1380,9 @@ async function setupIpcHandlers(dbManager, agentDaemon, gateway) {
|
|
|
1123
1380
|
llm_1.LLMProviderFactory.saveCachedModels('gemini', cachedModels);
|
|
1124
1381
|
return models;
|
|
1125
1382
|
});
|
|
1126
|
-
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.LLM_GET_OPENROUTER_MODELS, async (_, apiKey) => {
|
|
1383
|
+
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.LLM_GET_OPENROUTER_MODELS, async (_, apiKey, baseUrl) => {
|
|
1127
1384
|
checkRateLimit(types_1.IPC_CHANNELS.LLM_GET_OPENROUTER_MODELS);
|
|
1128
|
-
const models = await llm_1.LLMProviderFactory.getOpenRouterModels(apiKey);
|
|
1385
|
+
const models = await llm_1.LLMProviderFactory.getOpenRouterModels(apiKey, baseUrl);
|
|
1129
1386
|
// Cache the models for use in config status
|
|
1130
1387
|
const cachedModels = models.map(m => ({
|
|
1131
1388
|
key: m.id,
|
|
@@ -1148,6 +1405,39 @@ async function setupIpcHandlers(dbManager, agentDaemon, gateway) {
|
|
|
1148
1405
|
llm_1.LLMProviderFactory.saveCachedModels('openai', cachedModels);
|
|
1149
1406
|
return models;
|
|
1150
1407
|
});
|
|
1408
|
+
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.LLM_GET_GROQ_MODELS, async (_, apiKey, baseUrl) => {
|
|
1409
|
+
checkRateLimit(types_1.IPC_CHANNELS.LLM_GET_GROQ_MODELS);
|
|
1410
|
+
const models = await llm_1.LLMProviderFactory.getGroqModels(apiKey, baseUrl);
|
|
1411
|
+
const cachedModels = models.map(m => ({
|
|
1412
|
+
key: m.id,
|
|
1413
|
+
displayName: m.name,
|
|
1414
|
+
description: 'Groq model',
|
|
1415
|
+
}));
|
|
1416
|
+
llm_1.LLMProviderFactory.saveCachedModels('groq', cachedModels);
|
|
1417
|
+
return models;
|
|
1418
|
+
});
|
|
1419
|
+
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.LLM_GET_XAI_MODELS, async (_, apiKey, baseUrl) => {
|
|
1420
|
+
checkRateLimit(types_1.IPC_CHANNELS.LLM_GET_XAI_MODELS);
|
|
1421
|
+
const models = await llm_1.LLMProviderFactory.getXAIModels(apiKey, baseUrl);
|
|
1422
|
+
const cachedModels = models.map(m => ({
|
|
1423
|
+
key: m.id,
|
|
1424
|
+
displayName: m.name,
|
|
1425
|
+
description: 'xAI model',
|
|
1426
|
+
}));
|
|
1427
|
+
llm_1.LLMProviderFactory.saveCachedModels('xai', cachedModels);
|
|
1428
|
+
return models;
|
|
1429
|
+
});
|
|
1430
|
+
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.LLM_GET_KIMI_MODELS, async (_, apiKey, baseUrl) => {
|
|
1431
|
+
checkRateLimit(types_1.IPC_CHANNELS.LLM_GET_KIMI_MODELS);
|
|
1432
|
+
const models = await llm_1.LLMProviderFactory.getKimiModels(apiKey, baseUrl);
|
|
1433
|
+
const cachedModels = models.map(m => ({
|
|
1434
|
+
key: m.id,
|
|
1435
|
+
displayName: m.name,
|
|
1436
|
+
description: 'Kimi model',
|
|
1437
|
+
}));
|
|
1438
|
+
llm_1.LLMProviderFactory.saveCachedModels('kimi', cachedModels);
|
|
1439
|
+
return models;
|
|
1440
|
+
});
|
|
1151
1441
|
// OpenAI OAuth handlers
|
|
1152
1442
|
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.LLM_OPENAI_OAUTH_START, async () => {
|
|
1153
1443
|
checkRateLimit(types_1.IPC_CHANNELS.LLM_OPENAI_OAUTH_START);
|
|
@@ -1260,6 +1550,204 @@ async function setupIpcHandlers(dbManager, agentDaemon, gateway) {
|
|
|
1260
1550
|
error: result.success ? undefined : result.error,
|
|
1261
1551
|
};
|
|
1262
1552
|
});
|
|
1553
|
+
// Notion Settings handlers
|
|
1554
|
+
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.NOTION_GET_SETTINGS, async () => {
|
|
1555
|
+
return notion_manager_1.NotionSettingsManager.loadSettings();
|
|
1556
|
+
});
|
|
1557
|
+
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.NOTION_SAVE_SETTINGS, async (_, settings) => {
|
|
1558
|
+
checkRateLimit(types_1.IPC_CHANNELS.NOTION_SAVE_SETTINGS);
|
|
1559
|
+
const validated = (0, validation_1.validateInput)(validation_1.NotionSettingsSchema, settings, 'notion settings');
|
|
1560
|
+
notion_manager_1.NotionSettingsManager.saveSettings(validated);
|
|
1561
|
+
notion_manager_1.NotionSettingsManager.clearCache();
|
|
1562
|
+
return { success: true };
|
|
1563
|
+
});
|
|
1564
|
+
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.NOTION_TEST_CONNECTION, async () => {
|
|
1565
|
+
checkRateLimit(types_1.IPC_CHANNELS.NOTION_TEST_CONNECTION);
|
|
1566
|
+
const settings = notion_manager_1.NotionSettingsManager.loadSettings();
|
|
1567
|
+
return (0, notion_api_1.testNotionConnection)(settings);
|
|
1568
|
+
});
|
|
1569
|
+
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.NOTION_GET_STATUS, async () => {
|
|
1570
|
+
checkRateLimit(types_1.IPC_CHANNELS.NOTION_GET_STATUS);
|
|
1571
|
+
const settings = notion_manager_1.NotionSettingsManager.loadSettings();
|
|
1572
|
+
if (!settings.apiKey) {
|
|
1573
|
+
return { configured: false, connected: false };
|
|
1574
|
+
}
|
|
1575
|
+
if (!settings.enabled) {
|
|
1576
|
+
return { configured: true, connected: false };
|
|
1577
|
+
}
|
|
1578
|
+
const result = await (0, notion_api_1.testNotionConnection)(settings);
|
|
1579
|
+
return {
|
|
1580
|
+
configured: true,
|
|
1581
|
+
connected: result.success,
|
|
1582
|
+
name: result.name,
|
|
1583
|
+
error: result.success ? undefined : result.error,
|
|
1584
|
+
};
|
|
1585
|
+
});
|
|
1586
|
+
// Box Settings handlers
|
|
1587
|
+
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.BOX_GET_SETTINGS, async () => {
|
|
1588
|
+
return box_manager_1.BoxSettingsManager.loadSettings();
|
|
1589
|
+
});
|
|
1590
|
+
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.BOX_SAVE_SETTINGS, async (_, settings) => {
|
|
1591
|
+
checkRateLimit(types_1.IPC_CHANNELS.BOX_SAVE_SETTINGS);
|
|
1592
|
+
const validated = (0, validation_1.validateInput)(validation_1.BoxSettingsSchema, settings, 'box settings');
|
|
1593
|
+
box_manager_1.BoxSettingsManager.saveSettings(validated);
|
|
1594
|
+
box_manager_1.BoxSettingsManager.clearCache();
|
|
1595
|
+
return { success: true };
|
|
1596
|
+
});
|
|
1597
|
+
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.BOX_TEST_CONNECTION, async () => {
|
|
1598
|
+
checkRateLimit(types_1.IPC_CHANNELS.BOX_TEST_CONNECTION);
|
|
1599
|
+
const settings = box_manager_1.BoxSettingsManager.loadSettings();
|
|
1600
|
+
return (0, box_api_1.testBoxConnection)(settings);
|
|
1601
|
+
});
|
|
1602
|
+
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.BOX_GET_STATUS, async () => {
|
|
1603
|
+
checkRateLimit(types_1.IPC_CHANNELS.BOX_GET_STATUS);
|
|
1604
|
+
const settings = box_manager_1.BoxSettingsManager.loadSettings();
|
|
1605
|
+
if (!settings.accessToken) {
|
|
1606
|
+
return { configured: false, connected: false };
|
|
1607
|
+
}
|
|
1608
|
+
if (!settings.enabled) {
|
|
1609
|
+
return { configured: true, connected: false };
|
|
1610
|
+
}
|
|
1611
|
+
const result = await (0, box_api_1.testBoxConnection)(settings);
|
|
1612
|
+
return {
|
|
1613
|
+
configured: true,
|
|
1614
|
+
connected: result.success,
|
|
1615
|
+
name: result.name,
|
|
1616
|
+
error: result.success ? undefined : result.error,
|
|
1617
|
+
};
|
|
1618
|
+
});
|
|
1619
|
+
// OneDrive Settings handlers
|
|
1620
|
+
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.ONEDRIVE_GET_SETTINGS, async () => {
|
|
1621
|
+
return onedrive_manager_1.OneDriveSettingsManager.loadSettings();
|
|
1622
|
+
});
|
|
1623
|
+
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.ONEDRIVE_SAVE_SETTINGS, async (_, settings) => {
|
|
1624
|
+
checkRateLimit(types_1.IPC_CHANNELS.ONEDRIVE_SAVE_SETTINGS);
|
|
1625
|
+
const validated = (0, validation_1.validateInput)(validation_1.OneDriveSettingsSchema, settings, 'onedrive settings');
|
|
1626
|
+
onedrive_manager_1.OneDriveSettingsManager.saveSettings(validated);
|
|
1627
|
+
onedrive_manager_1.OneDriveSettingsManager.clearCache();
|
|
1628
|
+
return { success: true };
|
|
1629
|
+
});
|
|
1630
|
+
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.ONEDRIVE_TEST_CONNECTION, async () => {
|
|
1631
|
+
checkRateLimit(types_1.IPC_CHANNELS.ONEDRIVE_TEST_CONNECTION);
|
|
1632
|
+
const settings = onedrive_manager_1.OneDriveSettingsManager.loadSettings();
|
|
1633
|
+
return (0, onedrive_api_1.testOneDriveConnection)(settings);
|
|
1634
|
+
});
|
|
1635
|
+
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.ONEDRIVE_GET_STATUS, async () => {
|
|
1636
|
+
checkRateLimit(types_1.IPC_CHANNELS.ONEDRIVE_GET_STATUS);
|
|
1637
|
+
const settings = onedrive_manager_1.OneDriveSettingsManager.loadSettings();
|
|
1638
|
+
if (!settings.accessToken) {
|
|
1639
|
+
return { configured: false, connected: false };
|
|
1640
|
+
}
|
|
1641
|
+
if (!settings.enabled) {
|
|
1642
|
+
return { configured: true, connected: false };
|
|
1643
|
+
}
|
|
1644
|
+
const result = await (0, onedrive_api_1.testOneDriveConnection)(settings);
|
|
1645
|
+
return {
|
|
1646
|
+
configured: true,
|
|
1647
|
+
connected: result.success,
|
|
1648
|
+
name: result.name,
|
|
1649
|
+
error: result.success ? undefined : result.error,
|
|
1650
|
+
};
|
|
1651
|
+
});
|
|
1652
|
+
// Google Drive Settings handlers
|
|
1653
|
+
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.GOOGLE_DRIVE_GET_SETTINGS, async () => {
|
|
1654
|
+
return google_drive_manager_1.GoogleDriveSettingsManager.loadSettings();
|
|
1655
|
+
});
|
|
1656
|
+
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.GOOGLE_DRIVE_SAVE_SETTINGS, async (_, settings) => {
|
|
1657
|
+
checkRateLimit(types_1.IPC_CHANNELS.GOOGLE_DRIVE_SAVE_SETTINGS);
|
|
1658
|
+
const validated = (0, validation_1.validateInput)(validation_1.GoogleDriveSettingsSchema, settings, 'google drive settings');
|
|
1659
|
+
google_drive_manager_1.GoogleDriveSettingsManager.saveSettings(validated);
|
|
1660
|
+
google_drive_manager_1.GoogleDriveSettingsManager.clearCache();
|
|
1661
|
+
return { success: true };
|
|
1662
|
+
});
|
|
1663
|
+
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.GOOGLE_DRIVE_TEST_CONNECTION, async () => {
|
|
1664
|
+
checkRateLimit(types_1.IPC_CHANNELS.GOOGLE_DRIVE_TEST_CONNECTION);
|
|
1665
|
+
const settings = google_drive_manager_1.GoogleDriveSettingsManager.loadSettings();
|
|
1666
|
+
return (0, google_drive_api_1.testGoogleDriveConnection)(settings);
|
|
1667
|
+
});
|
|
1668
|
+
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.GOOGLE_DRIVE_GET_STATUS, async () => {
|
|
1669
|
+
checkRateLimit(types_1.IPC_CHANNELS.GOOGLE_DRIVE_GET_STATUS);
|
|
1670
|
+
const settings = google_drive_manager_1.GoogleDriveSettingsManager.loadSettings();
|
|
1671
|
+
if (!settings.accessToken) {
|
|
1672
|
+
return { configured: false, connected: false };
|
|
1673
|
+
}
|
|
1674
|
+
if (!settings.enabled) {
|
|
1675
|
+
return { configured: true, connected: false };
|
|
1676
|
+
}
|
|
1677
|
+
const result = await (0, google_drive_api_1.testGoogleDriveConnection)(settings);
|
|
1678
|
+
return {
|
|
1679
|
+
configured: true,
|
|
1680
|
+
connected: result.success,
|
|
1681
|
+
name: result.name,
|
|
1682
|
+
error: result.success ? undefined : result.error,
|
|
1683
|
+
};
|
|
1684
|
+
});
|
|
1685
|
+
// Dropbox Settings handlers
|
|
1686
|
+
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.DROPBOX_GET_SETTINGS, async () => {
|
|
1687
|
+
return dropbox_manager_1.DropboxSettingsManager.loadSettings();
|
|
1688
|
+
});
|
|
1689
|
+
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.DROPBOX_SAVE_SETTINGS, async (_, settings) => {
|
|
1690
|
+
checkRateLimit(types_1.IPC_CHANNELS.DROPBOX_SAVE_SETTINGS);
|
|
1691
|
+
const validated = (0, validation_1.validateInput)(validation_1.DropboxSettingsSchema, settings, 'dropbox settings');
|
|
1692
|
+
dropbox_manager_1.DropboxSettingsManager.saveSettings(validated);
|
|
1693
|
+
dropbox_manager_1.DropboxSettingsManager.clearCache();
|
|
1694
|
+
return { success: true };
|
|
1695
|
+
});
|
|
1696
|
+
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.DROPBOX_TEST_CONNECTION, async () => {
|
|
1697
|
+
checkRateLimit(types_1.IPC_CHANNELS.DROPBOX_TEST_CONNECTION);
|
|
1698
|
+
const settings = dropbox_manager_1.DropboxSettingsManager.loadSettings();
|
|
1699
|
+
return (0, dropbox_api_1.testDropboxConnection)(settings);
|
|
1700
|
+
});
|
|
1701
|
+
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.DROPBOX_GET_STATUS, async () => {
|
|
1702
|
+
checkRateLimit(types_1.IPC_CHANNELS.DROPBOX_GET_STATUS);
|
|
1703
|
+
const settings = dropbox_manager_1.DropboxSettingsManager.loadSettings();
|
|
1704
|
+
if (!settings.accessToken) {
|
|
1705
|
+
return { configured: false, connected: false };
|
|
1706
|
+
}
|
|
1707
|
+
if (!settings.enabled) {
|
|
1708
|
+
return { configured: true, connected: false };
|
|
1709
|
+
}
|
|
1710
|
+
const result = await (0, dropbox_api_1.testDropboxConnection)(settings);
|
|
1711
|
+
return {
|
|
1712
|
+
configured: true,
|
|
1713
|
+
connected: result.success,
|
|
1714
|
+
name: result.name,
|
|
1715
|
+
error: result.success ? undefined : result.error,
|
|
1716
|
+
};
|
|
1717
|
+
});
|
|
1718
|
+
// SharePoint Settings handlers
|
|
1719
|
+
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.SHAREPOINT_GET_SETTINGS, async () => {
|
|
1720
|
+
return sharepoint_manager_1.SharePointSettingsManager.loadSettings();
|
|
1721
|
+
});
|
|
1722
|
+
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.SHAREPOINT_SAVE_SETTINGS, async (_, settings) => {
|
|
1723
|
+
checkRateLimit(types_1.IPC_CHANNELS.SHAREPOINT_SAVE_SETTINGS);
|
|
1724
|
+
const validated = (0, validation_1.validateInput)(validation_1.SharePointSettingsSchema, settings, 'sharepoint settings');
|
|
1725
|
+
sharepoint_manager_1.SharePointSettingsManager.saveSettings(validated);
|
|
1726
|
+
sharepoint_manager_1.SharePointSettingsManager.clearCache();
|
|
1727
|
+
return { success: true };
|
|
1728
|
+
});
|
|
1729
|
+
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.SHAREPOINT_TEST_CONNECTION, async () => {
|
|
1730
|
+
checkRateLimit(types_1.IPC_CHANNELS.SHAREPOINT_TEST_CONNECTION);
|
|
1731
|
+
const settings = sharepoint_manager_1.SharePointSettingsManager.loadSettings();
|
|
1732
|
+
return (0, sharepoint_api_1.testSharePointConnection)(settings);
|
|
1733
|
+
});
|
|
1734
|
+
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.SHAREPOINT_GET_STATUS, async () => {
|
|
1735
|
+
checkRateLimit(types_1.IPC_CHANNELS.SHAREPOINT_GET_STATUS);
|
|
1736
|
+
const settings = sharepoint_manager_1.SharePointSettingsManager.loadSettings();
|
|
1737
|
+
if (!settings.accessToken) {
|
|
1738
|
+
return { configured: false, connected: false };
|
|
1739
|
+
}
|
|
1740
|
+
if (!settings.enabled) {
|
|
1741
|
+
return { configured: true, connected: false };
|
|
1742
|
+
}
|
|
1743
|
+
const result = await (0, sharepoint_api_1.testSharePointConnection)(settings);
|
|
1744
|
+
return {
|
|
1745
|
+
configured: true,
|
|
1746
|
+
connected: result.success,
|
|
1747
|
+
name: result.name,
|
|
1748
|
+
error: result.success ? undefined : result.error,
|
|
1749
|
+
};
|
|
1750
|
+
});
|
|
1263
1751
|
// Gateway / Channel handlers
|
|
1264
1752
|
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.GATEWAY_GET_CHANNELS, async () => {
|
|
1265
1753
|
if (!gateway)
|
|
@@ -1679,7 +2167,8 @@ async function setupIpcHandlers(dbManager, agentDaemon, gateway) {
|
|
|
1679
2167
|
throw new Error('Agent role not found');
|
|
1680
2168
|
}
|
|
1681
2169
|
}
|
|
1682
|
-
|
|
2170
|
+
const taskUpdate = { assignedAgentRoleId: agentRoleId ?? undefined };
|
|
2171
|
+
taskRepo.update(validatedTaskId, taskUpdate);
|
|
1683
2172
|
const task = taskRepo.findById(validatedTaskId);
|
|
1684
2173
|
if (task) {
|
|
1685
2174
|
if (agentRoleId) {
|
|
@@ -2030,6 +2519,7 @@ function setupMCPHandlers() {
|
|
|
2030
2519
|
rate_limiter_1.rateLimiter.configure(types_1.IPC_CHANNELS.MCP_CONNECT_SERVER, rate_limiter_1.RATE_LIMIT_CONFIGS.expensive);
|
|
2031
2520
|
rate_limiter_1.rateLimiter.configure(types_1.IPC_CHANNELS.MCP_TEST_SERVER, rate_limiter_1.RATE_LIMIT_CONFIGS.expensive);
|
|
2032
2521
|
rate_limiter_1.rateLimiter.configure(types_1.IPC_CHANNELS.MCP_REGISTRY_INSTALL, rate_limiter_1.RATE_LIMIT_CONFIGS.expensive);
|
|
2522
|
+
rate_limiter_1.rateLimiter.configure(types_1.IPC_CHANNELS.MCP_CONNECTOR_OAUTH_START, rate_limiter_1.RATE_LIMIT_CONFIGS.expensive);
|
|
2033
2523
|
// Initialize MCP settings manager
|
|
2034
2524
|
settings_1.MCPSettingsManager.initialize();
|
|
2035
2525
|
// Get settings
|
|
@@ -2053,7 +2543,7 @@ function setupMCPHandlers() {
|
|
|
2053
2543
|
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.MCP_ADD_SERVER, async (_, serverConfig) => {
|
|
2054
2544
|
checkRateLimit(types_1.IPC_CHANNELS.MCP_ADD_SERVER);
|
|
2055
2545
|
const validated = (0, validation_1.validateInput)(validation_2.MCPServerConfigSchema, serverConfig, 'MCP server config');
|
|
2056
|
-
const { id, ...configWithoutId } = validated;
|
|
2546
|
+
const { id: _id, ...configWithoutId } = validated;
|
|
2057
2547
|
return settings_1.MCPSettingsManager.addServer(configWithoutId);
|
|
2058
2548
|
});
|
|
2059
2549
|
// Update a server
|
|
@@ -2136,6 +2626,12 @@ function setupMCPHandlers() {
|
|
|
2136
2626
|
const validatedId = (0, validation_1.validateInput)(validation_1.UUIDSchema, serverId, 'server ID');
|
|
2137
2627
|
return MCPRegistryManager_1.MCPRegistryManager.updateServer(validatedId);
|
|
2138
2628
|
});
|
|
2629
|
+
// MCP Connector OAuth (Salesforce/Jira)
|
|
2630
|
+
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.MCP_CONNECTOR_OAUTH_START, async (_, payload) => {
|
|
2631
|
+
checkRateLimit(types_1.IPC_CHANNELS.MCP_CONNECTOR_OAUTH_START);
|
|
2632
|
+
const validated = (0, validation_1.validateInput)(validation_1.MCPConnectorOAuthSchema, payload, 'connector oauth');
|
|
2633
|
+
return (0, connector_oauth_1.startConnectorOAuth)(validated);
|
|
2634
|
+
});
|
|
2139
2635
|
// MCP Host handlers
|
|
2140
2636
|
electron_1.ipcMain.handle(types_1.IPC_CHANNELS.MCP_HOST_START, async () => {
|
|
2141
2637
|
const hostServer = MCPHostServer_1.MCPHostServer.getInstance();
|