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
@@ -7,7 +7,7 @@
7
7
  * This file is in shared/ so it can be used by both the main process (gateway) and renderer.
8
8
  */
9
9
 
10
- import type { PersonalityId, EmojiUsage, PersonalityQuirks } from './types';
10
+ import type { PersonalityId, PersonaId, EmojiUsage, PersonalityQuirks } from './types';
11
11
 
12
12
  /**
13
13
  * Message keys for channel notifications
@@ -28,10 +28,331 @@ export interface ChannelMessageContext {
28
28
  agentName: string;
29
29
  userName?: string;
30
30
  personality: PersonalityId;
31
+ persona?: PersonaId;
31
32
  emojiUsage: EmojiUsage;
32
33
  quirks: PersonalityQuirks;
33
34
  }
34
35
 
36
+ /**
37
+ * UI copy keys for channel interfaces (commands, onboarding, system messages)
38
+ */
39
+ export type ChannelUiKey =
40
+ | 'welcomeStandard'
41
+ | 'welcomeBack'
42
+ | 'welcomeNoWorkspace'
43
+ | 'welcomeSingleWorkspace'
44
+ | 'welcomeSelectWorkspace'
45
+ | 'workspaceSelected'
46
+ | 'workspaceSelectedExample'
47
+ | 'unauthorized'
48
+ | 'pairingRequired'
49
+ | 'pairingPrompt'
50
+ | 'pairingSuccess'
51
+ | 'pairingFailed'
52
+ | 'unknownCommand'
53
+ | 'statusHeader'
54
+ | 'statusNoWorkspace'
55
+ | 'statusActiveTask'
56
+ | 'workspacesNone'
57
+ | 'workspacesHeader'
58
+ | 'workspacesFooter'
59
+ | 'workspacesSelectPrompt'
60
+ | 'workspaceCurrent'
61
+ | 'workspaceNoneSelected'
62
+ | 'workspaceNotFound'
63
+ | 'workspaceNotFoundShort'
64
+ | 'workspaceSet'
65
+ | 'workspaceAddUsage'
66
+ | 'workspacePathNotDir'
67
+ | 'workspacePathNotFound'
68
+ | 'workspaceAlreadyExists'
69
+ | 'workspaceAdded'
70
+ | 'workspaceRemoveUsage'
71
+ | 'workspaceRemoved'
72
+ | 'taskStartAck'
73
+ | 'taskStartAckSimple'
74
+ | 'taskStartFailed'
75
+ | 'taskContinueFailed'
76
+ | 'agentUnavailable'
77
+ | 'workspaceMissingForTask'
78
+ | 'approvalNone'
79
+ | 'approvalApproved'
80
+ | 'approvalDenied'
81
+ | 'approvalFailed'
82
+ | 'approvalButtonApprove'
83
+ | 'approvalButtonDeny'
84
+ | 'approvalRequiredTitle'
85
+ | 'queueCleared'
86
+ | 'queueStatus'
87
+ | 'cancelled'
88
+ | 'cancelNoActive'
89
+ | 'newTaskReady'
90
+ | 'retryNone'
91
+ | 'retrying'
92
+ | 'historyNone'
93
+ | 'historyHeader'
94
+ | 'skillsNone'
95
+ | 'skillsLoadFailed'
96
+ | 'skillSpecify'
97
+ | 'skillNotFound'
98
+ | 'skillToggle'
99
+ | 'debugStatus'
100
+ | 'shellInvalidOption'
101
+ | 'workspaceNotFoundForShell'
102
+ | 'responseFailed'
103
+ | 'helpCompact'
104
+ | 'helpFull';
105
+
106
+ const CHANNEL_UI_COPY: Record<ChannelUiKey, string> = {
107
+ welcomeStandard: '👋 Welcome to CoWork! Send me a task whenever you are ready.',
108
+ welcomeBack: '👋 Welcome back!\n\nWorkspace: *{workspaceName}*\n\nSend me what you want to do.\n\nType /help for commands.',
109
+ welcomeNoWorkspace: '👋 Welcome to CoWork!\n\nFirst, add a workspace:\n`/addworkspace /path/to/project`\n\nOr add one from the desktop app.',
110
+ welcomeSingleWorkspace: '👋 Welcome to CoWork!\n\n✅ Workspace: *{workspaceName}*\n\nTell me what you want to do.\n\nExamples:\n• "Add dark mode support"\n• "Fix the login bug"\n• "Create a new API endpoint"',
111
+ welcomeSelectWorkspace: '👋 Welcome to CoWork!\n\nSelect a workspace to start:\n\n{workspaceList}\nReply with a number (e.g., `1`)',
112
+ workspaceSelected: '✅ *{workspaceName}* selected!',
113
+ workspaceSelectedExample: 'You can now send tasks.\n\nExample: "Create a new React component called Button"',
114
+ unauthorized: '⚠️ You are not authorized to use this bot. Please contact the administrator.',
115
+ pairingRequired: '🔐 Please enter your pairing code to get started.',
116
+ pairingPrompt: '🔐 Please provide a pairing code.\n\nUsage: `/pair <code>`',
117
+ pairingSuccess: '✅ Pairing successful! You can now use the bot.',
118
+ pairingFailed: '❌ {error}',
119
+ unknownCommand: 'Unknown command: {command}\n\nUse /help to see available commands.',
120
+ statusHeader: 'Online and ready.',
121
+ statusNoWorkspace: '⚠️ No workspace selected. Use /workspaces to see available workspaces.',
122
+ statusActiveTask: '🔄 Active task: {taskTitle} ({status})',
123
+ workspacesNone: '📁 No workspaces configured yet.\n\nAdd a workspace in the CoWork desktop app first, or use:\n`/addworkspace /path/to/your/project`',
124
+ workspacesHeader: '📁 *Available Workspaces*',
125
+ workspacesFooter: 'Reply with the number or name to select.\nExample: `1` or `myproject`',
126
+ workspacesSelectPrompt: 'Tap a workspace to select it:',
127
+ workspaceCurrent: '📁 Current workspace: *{workspaceName}*\n`{workspacePath}`\n\nUse `/workspaces` to see available workspaces.',
128
+ workspaceNoneSelected: 'No workspace selected. Use `/workspaces` to see available workspaces.',
129
+ workspaceNotFound: '❌ Workspace not found: "{selector}"\n\nUse /workspaces to see available workspaces.',
130
+ workspaceNotFoundShort: '❌ Workspace not found.',
131
+ workspaceSet: '✅ Workspace set to: *{workspaceName}*\n`{workspacePath}`\n\nYou can now send messages to create tasks in this workspace.',
132
+ workspaceAddUsage: '📁 *Add Workspace*\n\nUsage: `/addworkspace <path>`\n\nExample:\n`/addworkspace /Users/john/projects/myapp`\n`/addworkspace ~/Documents`',
133
+ workspacePathNotDir: '❌ Path is not a directory: `{workspacePath}`',
134
+ workspacePathNotFound: '❌ Directory not found: `{workspacePath}`',
135
+ workspaceAlreadyExists: '📁 Workspace already exists!\n\n✅ Selected: *{workspaceName}*\n`{workspacePath}`',
136
+ workspaceAdded: '✅ Workspace added and selected!\n\n📁 *{workspaceName}*\n`{workspacePath}`\n\nYou can now send messages to create tasks in this workspace.',
137
+ workspaceRemoveUsage: '❌ Please specify a workspace name to remove.\n\nUsage: `/removeworkspace <name>`',
138
+ workspaceRemoved: '✅ Workspace "{workspaceName}" removed successfully.',
139
+ taskStartAck: '🚀 Task started: "{taskTitle}"\n\nI\'ll update you when it\'s ready or if I need your input.',
140
+ taskStartAckSimple: 'I\'m on it — I\'ll check back soon.',
141
+ taskStartFailed: '❌ Failed to start task: {error}',
142
+ taskContinueFailed: '❌ Failed to send message. Use /newtask to start a new task.',
143
+ agentUnavailable: '❌ Agent not available. Please try again later.',
144
+ workspaceMissingForTask: '❌ Workspace not found. Please select a workspace with /workspace.',
145
+ approvalNone: '❌ No pending approval request.',
146
+ approvalApproved: '✅ Approved. Working on it.',
147
+ approvalDenied: '🛑 Denied. Action cancelled.',
148
+ approvalFailed: '❌ Failed to process approval.',
149
+ approvalButtonApprove: '✅ Approve',
150
+ approvalButtonDeny: '❌ Deny',
151
+ approvalRequiredTitle: 'Approval Required',
152
+ queueCleared: '✅ Queue cleared.\n\n• Running tasks cancelled: {running}\n• Queued tasks removed: {queued}\n\nBrowser sessions and other resources have been cleaned up.',
153
+ queueStatus: '{statusText}',
154
+ cancelled: '🛑 Task cancelled.',
155
+ cancelNoActive: 'No active task to cancel.',
156
+ newTaskReady: '🆕 Ready for a new task.\n\nSend me a message describing what you want to do.',
157
+ retryNone: '❌ No failed task found to retry.\n\nStart a new task by sending a message.',
158
+ retrying: '🔄 Retrying task...\n\nOriginal prompt: "{taskTitle}"',
159
+ historyNone: '📋 No task history found.\n\nStart a new task by sending a message.',
160
+ historyHeader: '📋 *Recent Tasks*\n\n{history}',
161
+ skillsNone: '📚 No skills available.\n\nSkills are stored in:\n`~/Library/Application Support/cowork-os/skills/`',
162
+ skillsLoadFailed: '❌ Failed to load skills.',
163
+ skillSpecify: '❌ Please specify a skill ID.\n\nUsage: `/skill <id>`\n\nUse /skills to see available skills.',
164
+ skillNotFound: '❌ Skill "{skillId}" not found.\n\nUse /skills to see available skills.',
165
+ skillToggle: '{emoji} *{skillName}* is now {statusText}',
166
+ debugStatus: '🐛 Debug mode is now {statusText}',
167
+ shellInvalidOption: '❌ Invalid option. Use `/shell on` or `/shell off`',
168
+ workspaceNotFoundForShell: '❌ Workspace not found.',
169
+ responseFailed: '❌ Failed to process response.',
170
+ helpCompact: `📚 *Commands*
171
+
172
+ *Basics*
173
+ /workspaces - Select workspace
174
+ /status - Current status
175
+ /newtask - Fresh start
176
+
177
+ *Tasks*
178
+ /cancel - Stop task
179
+ /approve or /yes - Approve action
180
+ /deny or /no - Reject action
181
+
182
+ *Settings*
183
+ /shell on|off - Shell access
184
+ /models - Change AI model
185
+
186
+ ━━━━━━━━━━━━━━━
187
+ 💡 Just send your task directly!
188
+ Example: "Add a login form"`,
189
+ helpFull: `📚 *Available Commands*
190
+
191
+ *Core*
192
+ /start - Start the bot
193
+ /help - Show this help message
194
+ /status - Check bot status and workspace
195
+ /version - Show version information
196
+
197
+ *Workspaces*
198
+ /workspaces - List available workspaces
199
+ /workspace <name> - Select a workspace
200
+ /addworkspace <path> - Add a new workspace
201
+ /removeworkspace <name> - Remove a workspace
202
+
203
+ *Tasks*
204
+ /newtask - Start a fresh task/conversation
205
+ /cancel - Cancel current task
206
+ /retry - Retry the last failed task
207
+ /history - Show recent task history
208
+ /approve - Approve pending action (or /yes, /y)
209
+ /deny - Reject pending action (or /no, /n)
210
+ /queue - View/clear task queue
211
+
212
+ *Models*
213
+ /providers - List available AI providers
214
+ /provider <name> - Show or change provider
215
+ /models - List available AI models
216
+ /model <name> - Show or change model
217
+
218
+ *Skills*
219
+ /skills - List available skills
220
+ /skill <name> - Toggle a skill on/off
221
+
222
+ *Settings*
223
+ /settings - View current settings
224
+ /shell - Enable/disable shell commands
225
+ /debug - Toggle debug mode
226
+
227
+ 💬 *Quick Start*
228
+ 1. \`/workspaces\` → \`/workspace <name>\`
229
+ 2. \`/shell on\` (if needed)
230
+ 3. Send your task message
231
+ 4. \`/newtask\` to start fresh`,
232
+ };
233
+
234
+ const PERSONA_CHANNEL_UI_OVERRIDES: Partial<Record<PersonaId, Partial<Record<ChannelUiKey, string>>>> = {
235
+ companion: {
236
+ welcomeStandard: '👋 I\'m here. Send me a task whenever you\'re ready.',
237
+ welcomeBack: '👋 Welcome back.\n\nWorkspace: *{workspaceName}*\n\nTell me what you want to do.\n\nType /help for commands.',
238
+ welcomeNoWorkspace: '👋 I\'m here.\n\nAdd a workspace to begin:\n`/addworkspace /path/to/project`\n\nOr add one from the desktop app.',
239
+ welcomeSingleWorkspace: '👋 We\'re set.\n\n✅ Workspace: *{workspaceName}*\n\nTell me what you want to do.\n\nExamples:\n• "Add dark mode support"\n• "Fix the login bug"\n• "Create a new API endpoint"',
240
+ welcomeSelectWorkspace: '👋 Let\'s pick a workspace:\n\n{workspaceList}\nReply with a number (e.g., `1`)',
241
+ workspaceSelected: '✅ *{workspaceName}* selected.',
242
+ workspaceSelectedExample: 'You can send tasks now.\n\nExample: "Create a new React component called Button"',
243
+ pairingPrompt: '🔐 Share your pairing code so I can connect.\n\nUsage: `/pair <code>`',
244
+ pairingSuccess: '✅ Paired. I\'m ready.',
245
+ pairingFailed: '❌ {error}',
246
+ unknownCommand: 'I didn\'t recognize that command: {command}\n\nUse /help to see options.',
247
+ statusHeader: 'Here and ready.',
248
+ statusNoWorkspace: '⚠️ No workspace selected. Use /workspaces to choose one.',
249
+ workspacesNone: '📁 No workspaces yet.\n\nAdd one in the desktop app, or use:\n`/addworkspace /path/to/your/project`',
250
+ workspacesHeader: '📁 *Workspaces*',
251
+ workspacesFooter: 'Reply with a number or name.\nExample: `1` or `myproject`',
252
+ workspaceCurrent: '📁 Current workspace: *{workspaceName}*\n`{workspacePath}`\n\nUse `/workspaces` to switch.',
253
+ workspaceNoneSelected: 'No workspace selected yet. Use `/workspaces` to pick one.',
254
+ workspaceNotFound: '❌ I couldn\'t find "{selector}".\n\nUse /workspaces to see available workspaces.',
255
+ workspaceNotFoundShort: 'I couldn\'t find that workspace.',
256
+ workspaceSet: '✅ Workspace set: *{workspaceName}*\n`{workspacePath}`\n\nSend a message to start a task.',
257
+ workspaceAddUsage: '📁 *Add Workspace*\n\nUsage: `/addworkspace <path>`\n\nExample:\n`/addworkspace /Users/john/projects/myapp`\n`/addworkspace ~/Documents`',
258
+ workspaceAlreadyExists: '📁 Workspace already exists.\n\n✅ Selected: *{workspaceName}*\n`{workspacePath}`',
259
+ workspaceAdded: '✅ Workspace added and selected.\n\n📁 *{workspaceName}*\n`{workspacePath}`\n\nSend a message to start a task.',
260
+ workspaceRemoveUsage: 'Please specify a workspace name to remove.\n\nUsage: `/removeworkspace <name>`',
261
+ workspaceRemoved: 'Workspace "{workspaceName}" removed.',
262
+ taskStartAck: 'I\'m on it — "{taskTitle}".\n\nI\'ll check back soon or ask if I need input.',
263
+ taskStartAckSimple: 'I\'m on it. I\'ll check back soon.',
264
+ taskContinueFailed: 'I couldn\'t send that. Use /newtask to start fresh.',
265
+ agentUnavailable: 'I\'m not available right now. Try again in a moment.',
266
+ workspaceMissingForTask: 'I can\'t find a workspace. Use /workspace to select one.',
267
+ approvalNone: 'No pending approval right now.',
268
+ approvalApproved: 'Approved. I\'m working on it.',
269
+ approvalDenied: 'Okay. I cancelled that.',
270
+ approvalFailed: 'I couldn\'t process that approval.',
271
+ approvalButtonApprove: 'Approve',
272
+ approvalButtonDeny: 'Deny',
273
+ approvalRequiredTitle: 'Approval required',
274
+ queueCleared: 'Queue cleared.\n\n• Running tasks cancelled: {running}\n• Queued tasks removed: {queued}\n\nYou can start new tasks now.',
275
+ cancelled: 'Task cancelled.',
276
+ cancelNoActive: 'No active task to cancel.',
277
+ newTaskReady: 'Ready for a fresh task.\n\nSend me what you want to do.',
278
+ retryNone: 'No failed task to retry.\n\nSend a new task when you\'re ready.',
279
+ retrying: 'Retrying...\n\nOriginal prompt: "{taskTitle}"',
280
+ historyNone: 'No recent task history yet.',
281
+ historyHeader: 'Recent tasks:\n\n{history}',
282
+ skillsNone: 'No skills available yet.',
283
+ skillsLoadFailed: 'Couldn\'t load skills.',
284
+ skillSpecify: 'Please specify a skill ID.\n\nUsage: `/skill <id>`\n\nUse /skills to see available skills.',
285
+ skillNotFound: 'Skill "{skillId}" not found.\n\nUse /skills to see available skills.',
286
+ skillToggle: '{emoji} *{skillName}* is now {statusText}',
287
+ debugStatus: 'Debug mode is now {statusText}',
288
+ shellInvalidOption: 'Invalid option. Use `/shell on` or `/shell off`',
289
+ workspaceNotFoundForShell: 'I couldn\'t find that workspace.',
290
+ responseFailed: 'I couldn\'t process that response.',
291
+ helpCompact: `📚 *Commands*
292
+
293
+ *Basics*
294
+ /workspaces - Select workspace
295
+ /status - Current status
296
+ /newtask - Fresh start
297
+
298
+ *Tasks*
299
+ /cancel - Stop task
300
+ /approve or /yes - Approve action
301
+ /deny or /no - Reject action
302
+
303
+ *Settings*
304
+ /shell on|off - Shell access
305
+ /models - Change AI model
306
+
307
+ ━━━━━━━━━━━━━━━
308
+ 💡 Just send your task directly.
309
+ Example: "Add a login form"`,
310
+ helpFull: `📚 *Commands*
311
+
312
+ *Core*
313
+ /start - Start
314
+ /help - Help
315
+ /status - Status
316
+ /version - Version
317
+
318
+ *Workspaces*
319
+ /workspaces - List workspaces
320
+ /workspace <name> - Select workspace
321
+ /addworkspace <path> - Add workspace
322
+ /removeworkspace <name> - Remove workspace
323
+
324
+ *Tasks*
325
+ /newtask - New task
326
+ /cancel - Cancel current task
327
+ /retry - Retry last failed task
328
+ /history - Recent tasks
329
+ /approve - Approve (or /yes, /y)
330
+ /deny - Deny (or /no, /n)
331
+ /queue - View/clear queue
332
+
333
+ *Models*
334
+ /providers - List providers
335
+ /provider <name> - Change provider
336
+ /models - List models
337
+ /model <name> - Change model
338
+
339
+ *Skills*
340
+ /skills - List skills
341
+ /skill <name> - Toggle skill
342
+
343
+ *Settings*
344
+ /settings - Current settings
345
+ /shell - Toggle shell access
346
+ /debug - Toggle debug mode
347
+
348
+ 💬 *Quick Start*
349
+ 1. \`/workspaces\` → \`/workspace <name>\`
350
+ 2. \`/shell on\` if needed
351
+ 3. Send your task
352
+ 4. \`/newtask\` to reset`,
353
+ },
354
+ };
355
+
35
356
  /**
36
357
  * Message templates organized by personality type
37
358
  */
@@ -101,6 +422,20 @@ const CHANNEL_MESSAGES: Record<PersonalityId, Record<ChannelMessageKey, string>>
101
422
  },
102
423
  };
103
424
 
425
+ const PERSONA_CHANNEL_MESSAGE_OVERRIDES: Partial<
426
+ Record<PersonaId, Partial<Record<ChannelMessageKey, string>>>
427
+ > = {
428
+ companion: {
429
+ taskComplete: 'All set.',
430
+ taskCompleteWithResult: 'All set.\n\n{result}',
431
+ taskFailed: 'I hit a snag: {error}',
432
+ toolError: 'I ran into an issue with {tool}: {error}',
433
+ followUpProcessed: 'Got it. I\'m on it.',
434
+ followUpFailed: 'I couldn\'t complete that: {error}',
435
+ approvalNeeded: 'I need your OK on this.',
436
+ },
437
+ };
438
+
104
439
  /**
105
440
  * Emoji mappings for message types
106
441
  */
@@ -139,11 +474,14 @@ export function getChannelMessage(
139
474
  ctx: ChannelMessageContext,
140
475
  replacements?: Record<string, string>
141
476
  ): string {
142
- const { personality, emojiUsage, quirks } = ctx;
477
+ const { personality, emojiUsage, quirks, persona } = ctx;
143
478
 
144
479
  // Get base message for personality
145
480
  const messages = CHANNEL_MESSAGES[personality] || CHANNEL_MESSAGES.professional;
146
- let message = messages[key] || CHANNEL_MESSAGES.professional[key] || key;
481
+ const personaOverride = persona
482
+ ? PERSONA_CHANNEL_MESSAGE_OVERRIDES[persona]?.[key]
483
+ : undefined;
484
+ let message = personaOverride || messages[key] || CHANNEL_MESSAGES.professional[key] || key;
147
485
 
148
486
  // Replace placeholders
149
487
  if (replacements) {
@@ -163,6 +501,29 @@ export function getChannelMessage(
163
501
  return message;
164
502
  }
165
503
 
504
+ /**
505
+ * Get channel UI copy with optional persona overrides
506
+ */
507
+ export function getChannelUiCopy(
508
+ key: ChannelUiKey,
509
+ ctx: ChannelMessageContext,
510
+ replacements?: Record<string, string | number>
511
+ ): string {
512
+ const base = CHANNEL_UI_COPY[key] || key;
513
+ const override = ctx.persona
514
+ ? PERSONA_CHANNEL_UI_OVERRIDES[ctx.persona]?.[key]
515
+ : undefined;
516
+ let message = override || base;
517
+
518
+ if (replacements) {
519
+ for (const [placeholder, value] of Object.entries(replacements)) {
520
+ message = message.replace(new RegExp(`\\{${placeholder}\\}`, 'g'), String(value));
521
+ }
522
+ }
523
+
524
+ return message;
525
+ }
526
+
166
527
  /**
167
528
  * Get completion message with optional result and follow-up hint
168
529
  * This is specific to channel messages which may include additional hints
@@ -177,6 +538,7 @@ export function getCompletionMessage(
177
538
 
178
539
  // Add follow-up hint for channels that support it
179
540
  if (includeFollowUpHint && ctx.personality !== 'concise') {
541
+ const companionHint = 'Send another message to continue, or use /newtask for a clean start.';
180
542
  const hints: Record<PersonalityId, string> = {
181
543
  professional: 'Send a follow-up message to continue, or use /newtask to start fresh.',
182
544
  friendly: 'Got more to do? Just send another message!',
@@ -186,7 +548,7 @@ export function getCompletionMessage(
186
548
  casual: 'What\'s next? Just hit me up.',
187
549
  custom: 'Send a follow-up message to continue.',
188
550
  };
189
- const hint = hints[ctx.personality];
551
+ const hint = ctx.persona === 'companion' ? companionHint : hints[ctx.personality];
190
552
  if (hint) {
191
553
  message = `${message}\n\n${hint}`;
192
554
  }
@@ -202,6 +564,7 @@ export const DEFAULT_CHANNEL_CONTEXT: ChannelMessageContext = {
202
564
  agentName: 'CoWork',
203
565
  userName: undefined,
204
566
  personality: 'professional',
567
+ persona: undefined,
205
568
  emojiUsage: 'minimal',
206
569
  quirks: {
207
570
  catchphrase: undefined,
@@ -0,0 +1,217 @@
1
+ import type { LLMProviderType } from './types';
2
+
3
+ export type ProviderCompatibility = 'openai' | 'anthropic';
4
+
5
+ export interface ProviderCatalogEntry {
6
+ id: LLMProviderType;
7
+ name: string;
8
+ compatibility: ProviderCompatibility;
9
+ baseUrl?: string;
10
+ defaultModel: string;
11
+ apiKeyLabel: string;
12
+ apiKeyPlaceholder?: string;
13
+ apiKeyUrl?: string;
14
+ requiresBaseUrl?: boolean;
15
+ apiKeyOptional?: boolean;
16
+ description?: string;
17
+ }
18
+
19
+ export const CUSTOM_PROVIDER_CATALOG: ProviderCatalogEntry[] = [
20
+ {
21
+ id: 'opencode',
22
+ name: 'OpenCode Zen',
23
+ compatibility: 'openai',
24
+ defaultModel: '',
25
+ apiKeyLabel: 'API Key / Token',
26
+ apiKeyPlaceholder: 'Enter token',
27
+ requiresBaseUrl: true,
28
+ description: 'OpenAI-compatible endpoint required.',
29
+ },
30
+ {
31
+ id: 'google-vertex',
32
+ name: 'Google Vertex',
33
+ compatibility: 'openai',
34
+ defaultModel: 'gemini-2.0-flash',
35
+ apiKeyLabel: 'Access Token',
36
+ apiKeyPlaceholder: 'ya29...',
37
+ requiresBaseUrl: true,
38
+ description: 'Requires a compatible gateway endpoint.',
39
+ },
40
+ {
41
+ id: 'google-antigravity',
42
+ name: 'Google Antigravity',
43
+ compatibility: 'openai',
44
+ defaultModel: 'gemini-2.0-flash',
45
+ apiKeyLabel: 'Access Token',
46
+ apiKeyPlaceholder: 'ya29...',
47
+ requiresBaseUrl: true,
48
+ description: 'Requires a compatible gateway endpoint.',
49
+ },
50
+ {
51
+ id: 'google-gemini-cli',
52
+ name: 'Google Gemini CLI',
53
+ compatibility: 'openai',
54
+ defaultModel: 'gemini-2.0-flash',
55
+ apiKeyLabel: 'Access Token',
56
+ apiKeyPlaceholder: 'ya29...',
57
+ requiresBaseUrl: true,
58
+ description: 'Requires a compatible gateway endpoint.',
59
+ },
60
+ {
61
+ id: 'zai',
62
+ name: 'Z.AI',
63
+ compatibility: 'openai',
64
+ defaultModel: 'glm-4.7',
65
+ apiKeyLabel: 'API Key',
66
+ apiKeyPlaceholder: 'zai-...',
67
+ requiresBaseUrl: true,
68
+ description: 'OpenAI-compatible endpoint required.',
69
+ },
70
+ {
71
+ id: 'glm',
72
+ name: 'GLM',
73
+ compatibility: 'openai',
74
+ defaultModel: 'glm-4-plus',
75
+ apiKeyLabel: 'API Key',
76
+ apiKeyPlaceholder: 'glm-...',
77
+ requiresBaseUrl: true,
78
+ description: 'OpenAI-compatible endpoint required.',
79
+ },
80
+ {
81
+ id: 'vercel-ai-gateway',
82
+ name: 'Vercel AI Gateway',
83
+ compatibility: 'anthropic',
84
+ baseUrl: 'https://ai-gateway.vercel.sh/v1',
85
+ defaultModel: 'claude-3-5-sonnet-20241022',
86
+ apiKeyLabel: 'API Key',
87
+ apiKeyPlaceholder: 'vgw_...',
88
+ apiKeyUrl: 'https://vercel.com/docs/ai-gateway',
89
+ },
90
+ {
91
+ id: 'moonshot',
92
+ name: 'Moonshot (Kimi)',
93
+ compatibility: 'openai',
94
+ baseUrl: 'https://api.moonshot.ai/v1',
95
+ defaultModel: 'kimi-k2.5',
96
+ apiKeyLabel: 'API Key',
97
+ apiKeyPlaceholder: 'sk-...',
98
+ },
99
+ {
100
+ id: 'cerebras',
101
+ name: 'Cerebras',
102
+ compatibility: 'openai',
103
+ baseUrl: 'https://api.cerebras.ai/v1',
104
+ defaultModel: 'llama3.1-8b',
105
+ apiKeyLabel: 'API Key',
106
+ apiKeyPlaceholder: 'csk_...',
107
+ apiKeyUrl: 'https://cloud.cerebras.ai/',
108
+ },
109
+ {
110
+ id: 'mistral',
111
+ name: 'Mistral',
112
+ compatibility: 'openai',
113
+ baseUrl: 'https://api.mistral.ai/v1',
114
+ defaultModel: 'mistral-large-latest',
115
+ apiKeyLabel: 'API Key',
116
+ apiKeyPlaceholder: 'mistral-...',
117
+ apiKeyUrl: 'https://console.mistral.ai/',
118
+ },
119
+ {
120
+ id: 'github-copilot',
121
+ name: 'GitHub Copilot',
122
+ compatibility: 'openai',
123
+ defaultModel: 'gpt-4o',
124
+ apiKeyLabel: 'GitHub Token',
125
+ apiKeyPlaceholder: 'ghp_...',
126
+ },
127
+ {
128
+ id: 'qwen-portal',
129
+ name: 'Qwen',
130
+ compatibility: 'anthropic',
131
+ baseUrl: 'https://portal.qwen.ai/v1',
132
+ defaultModel: 'coder-model',
133
+ apiKeyLabel: 'API Key / Token',
134
+ apiKeyPlaceholder: 'qwen-...',
135
+ },
136
+ {
137
+ id: 'minimax',
138
+ name: 'MiniMax',
139
+ compatibility: 'openai',
140
+ baseUrl: 'https://api.minimax.chat/v1',
141
+ defaultModel: 'MiniMax-M2.1',
142
+ apiKeyLabel: 'API Key',
143
+ apiKeyPlaceholder: 'minimax-...',
144
+ },
145
+ {
146
+ id: 'minimax-portal',
147
+ name: 'MiniMax Portal',
148
+ compatibility: 'anthropic',
149
+ baseUrl: 'https://api.minimax.io/anthropic',
150
+ defaultModel: 'MiniMax-M2.1',
151
+ apiKeyLabel: 'API Key / Token',
152
+ apiKeyPlaceholder: 'minimax-...',
153
+ },
154
+ {
155
+ id: 'xiaomi',
156
+ name: 'Xiaomi MiMo',
157
+ compatibility: 'anthropic',
158
+ baseUrl: 'https://api.xiaomimimo.com/anthropic',
159
+ defaultModel: 'mimo-v2-flash',
160
+ apiKeyLabel: 'API Key',
161
+ apiKeyPlaceholder: 'mimo-...',
162
+ },
163
+ {
164
+ id: 'venice',
165
+ name: 'Venice AI',
166
+ compatibility: 'openai',
167
+ baseUrl: 'https://api.venice.ai/api/v1',
168
+ defaultModel: 'llama-3.3-70b',
169
+ apiKeyLabel: 'API Key',
170
+ apiKeyPlaceholder: 'venice-...',
171
+ },
172
+ {
173
+ id: 'synthetic',
174
+ name: 'Synthetic',
175
+ compatibility: 'anthropic',
176
+ baseUrl: 'https://api.synthetic.new/anthropic',
177
+ defaultModel: 'hf:MiniMaxAI/MiniMax-M2.1',
178
+ apiKeyLabel: 'API Key',
179
+ apiKeyPlaceholder: 'syn_...',
180
+ },
181
+ {
182
+ id: 'kimi-code',
183
+ name: 'Kimi Code',
184
+ compatibility: 'openai',
185
+ baseUrl: 'https://api.kimi.com/coding/v1',
186
+ defaultModel: 'kimi-for-coding',
187
+ apiKeyLabel: 'API Key',
188
+ apiKeyPlaceholder: 'sk-...',
189
+ },
190
+ {
191
+ id: 'openai-compatible',
192
+ name: 'OpenAI-Compatible (Custom)',
193
+ compatibility: 'openai',
194
+ baseUrl: 'http://localhost:1234/v1',
195
+ defaultModel: 'gpt-4o-mini',
196
+ apiKeyLabel: 'API Key (Optional)',
197
+ apiKeyPlaceholder: 'sk-...',
198
+ requiresBaseUrl: true,
199
+ apiKeyOptional: true,
200
+ },
201
+ {
202
+ id: 'anthropic-compatible',
203
+ name: 'Anthropic-Compatible (Custom)',
204
+ compatibility: 'anthropic',
205
+ baseUrl: 'http://localhost:4000',
206
+ defaultModel: 'claude-3-5-sonnet-20241022',
207
+ apiKeyLabel: 'API Key',
208
+ apiKeyPlaceholder: 'sk-...',
209
+ requiresBaseUrl: true,
210
+ },
211
+ ];
212
+
213
+ export const CUSTOM_PROVIDER_MAP = new Map(
214
+ CUSTOM_PROVIDER_CATALOG.map((provider) => [provider.id, provider])
215
+ );
216
+
217
+ export const CUSTOM_PROVIDER_IDS = new Set(CUSTOM_PROVIDER_CATALOG.map((provider) => provider.id));