@pheem49/mint 1.8.0 → 1.8.2

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 (200) hide show
  1. package/.github/workflows/release.yml +1 -1
  2. package/Cargo.lock +34 -3
  3. package/Cargo.toml +2 -2
  4. package/README.md +20 -6
  5. package/Release_Note.md +129 -0
  6. package/assets/Mint_CLI.png +0 -0
  7. package/bin/mint +0 -0
  8. package/crates/mint-cli/Cargo.toml +1 -0
  9. package/crates/mint-cli/src/agent.rs +242 -54
  10. package/crates/mint-cli/src/main.rs +397 -74
  11. package/crates/mint-core/src/agent_loop.rs +1 -0
  12. package/crates/mint-core/src/api_server.rs +64 -2
  13. package/crates/mint-core/src/browser.rs +456 -0
  14. package/crates/mint-core/src/channels.rs +1 -0
  15. package/crates/mint-core/src/chat.rs +3 -0
  16. package/crates/mint-core/src/config.rs +130 -1
  17. package/crates/mint-core/src/lib.rs +19 -0
  18. package/crates/mint-core/src/orchestration.rs +317 -12
  19. package/crates/mint-core/src/skills.rs +113 -4
  20. package/crates/mint-core/src/tts.rs +3 -1
  21. package/crates/mint-core/src/workflows.rs +1 -22
  22. package/flatpak/com.pheem49.mint.desktop +9 -0
  23. package/flatpak/com.pheem49.mint.metainfo.xml +35 -0
  24. package/flatpak/com.pheem49.mint.yaml +52 -0
  25. package/package.json +1 -1
  26. package/shared-modules/.github/workflows/ci.yml +120 -0
  27. package/shared-modules/.github/workflows/update.yaml +28 -0
  28. package/shared-modules/CODEOWNERS +23 -0
  29. package/shared-modules/README.md +79 -0
  30. package/shared-modules/SDL/README.md +3 -0
  31. package/shared-modules/SDL/SDL-1.2.15.json +51 -0
  32. package/shared-modules/SDL/SDL_Pango-0.1.2-API-adds.patch +118 -0
  33. package/shared-modules/SDL/SDL_image-1.2.12.json +25 -0
  34. package/shared-modules/SDL/SDL_mixer-1.2.12.json +27 -0
  35. package/shared-modules/SDL/SDL_net-1.2.8.json +19 -0
  36. package/shared-modules/SDL/SDL_pango-0.1.2.json +26 -0
  37. package/shared-modules/SDL/SDL_ttf-2.0.11.json +28 -0
  38. package/shared-modules/SDL/libsdl-1.2.15-strict-prototypes.patch +316 -0
  39. package/shared-modules/SDL/sdl-check-for-SDL_VIDEO_X11_BACKINGSTORE.patch +24 -0
  40. package/shared-modules/SDL/sdl-libx11-build.patch +59 -0
  41. package/shared-modules/SDL/sdl-sysloadso-buffer-length.patch +27 -0
  42. package/shared-modules/SDL/sdl12-compat.json +22 -0
  43. package/shared-modules/SDL2/SDL2_image.json +27 -0
  44. package/shared-modules/SDL2/SDL2_ttf.json +29 -0
  45. package/shared-modules/cld2/CMakeLists.txt +157 -0
  46. package/shared-modules/cld2/cld2.json +24 -0
  47. package/shared-modules/clutter/clutter.json +72 -0
  48. package/shared-modules/dbus-glib/dbus-glib.json +29 -0
  49. package/shared-modules/glew/glew.json +36 -0
  50. package/shared-modules/glu/glu-9.json +12 -0
  51. package/shared-modules/gtk2/arc-gtk2-theme-Replace-Inkscape-dependency-with-rsvg-convert.patch +180 -0
  52. package/shared-modules/gtk2/gtk2-common-themes.json +360 -0
  53. package/shared-modules/gtk2/gtk2-fix-crash-in-show-uri.patch +30 -0
  54. package/shared-modules/gtk2/gtk2-gcc14.patch +281 -0
  55. package/shared-modules/gtk2/gtk2-gcc15.patch +250 -0
  56. package/shared-modules/gtk2/gtk2-murrine-c99.patch +34 -0
  57. package/shared-modules/gtk2/gtk2-use-adwaita-theme.patch +80 -0
  58. package/shared-modules/gtk2/gtk2.json +120 -0
  59. package/shared-modules/gtk2/ibus-gcc15.patch +13 -0
  60. package/shared-modules/gtk2/murrine-engine-fix-crash.patch +12 -0
  61. package/shared-modules/gtk2/readme.md +10 -0
  62. package/shared-modules/intltool/intltool-0.51.json +20 -0
  63. package/shared-modules/intltool/intltool-perl5.26-regex-fixes.patch +59 -0
  64. package/shared-modules/lame/0001-Build-xmm_quantize_sub.c-with-msse.patch +34 -0
  65. package/shared-modules/lame/0002-Include-GTK-1-autoconf-directives-in-build-system.patch +222 -0
  66. package/shared-modules/lame/0003-Patch-out-remaining-ansi2knr.patch +70 -0
  67. package/shared-modules/lame/0004-initscr-is-not-used-anywhere-in-lame-sourcetree.patch +41 -0
  68. package/shared-modules/lame/0005-Update-autoconf.patch +81 -0
  69. package/shared-modules/lame/lame-3.99.5.json +32 -0
  70. package/shared-modules/libappindicator/libappindicator-gtk2-12.10.json +140 -0
  71. package/shared-modules/libappindicator/libappindicator-gtk3-12.10.json +140 -0
  72. package/shared-modules/libappindicator/libappindicator-gtk3-introspection-12.10.json +140 -0
  73. package/shared-modules/libappindicator/patches/0001-libappindicator-ftbfs.patch +20 -0
  74. package/shared-modules/libappindicator/patches/0002-libappindicator-no-python.patch +888 -0
  75. package/shared-modules/libappindicator/patches/0003-libappindicator-fix-crash-from-incorrect-signal-emission.patch +74 -0
  76. package/shared-modules/libappindicator/patches/0004-libappindicator-fix-crash-iterating-icon-themes.patch +11 -0
  77. package/shared-modules/libayatana-appindicator/0001-Fix-HAVE_VALGRIND-AM_CONDITIONAL.patch +51 -0
  78. package/shared-modules/libayatana-appindicator/0001-Make-introspection-configurable.patch +44 -0
  79. package/shared-modules/libayatana-appindicator/libayatana-appindicator-gtk3.json +121 -0
  80. package/shared-modules/libcanberra/0001-gtk-Don-t-assume-all-GdkDisplays-are-GdkX11Displays-.patch +123 -0
  81. package/shared-modules/libcanberra/libcanberra.json +44 -0
  82. package/shared-modules/libmad/libmad.json +19 -0
  83. package/shared-modules/libsecret/libsecret.json +23 -0
  84. package/shared-modules/libsoup/libsoup-2.4.json +14 -0
  85. package/shared-modules/libusb/libusb.json +27 -0
  86. package/shared-modules/linux-audio/dssi.json +31 -0
  87. package/shared-modules/linux-audio/fftw3f-static.json +44 -0
  88. package/shared-modules/linux-audio/fftw3f.json +42 -0
  89. package/shared-modules/linux-audio/fluidsynth2-static.json +30 -0
  90. package/shared-modules/linux-audio/fluidsynth2.json +19 -0
  91. package/shared-modules/linux-audio/ladspa.json +26 -0
  92. package/shared-modules/linux-audio/lash.json +35 -0
  93. package/shared-modules/linux-audio/libinstpatch.json +16 -0
  94. package/shared-modules/linux-audio/liblo-static.json +22 -0
  95. package/shared-modules/linux-audio/liblo.json +17 -0
  96. package/shared-modules/linux-audio/lilv-static.json +94 -0
  97. package/shared-modules/linux-audio/lilv.json +82 -0
  98. package/shared-modules/linux-audio/lrdf.json +57 -0
  99. package/shared-modules/linux-audio/lv2.json +21 -0
  100. package/shared-modules/linux-audio/patches/lash/0001-configure-remove-aclocal-m4.patch +29 -0
  101. package/shared-modules/linux-audio/patches/lash/0002-Fix-build-with-recent-gcc.patch +73 -0
  102. package/shared-modules/linux-audio/patches/lash/0003-Fix-linking.patch +136 -0
  103. package/shared-modules/linux-audio/patches/raptor-libxml.patch +31 -0
  104. package/shared-modules/linux-audio/patches/stk-install.sh +54 -0
  105. package/shared-modules/linux-audio/stk.json +28 -0
  106. package/shared-modules/lua5.1/0004-Fix-stack-overflow-in-vararg-functions.patch +21 -0
  107. package/shared-modules/lua5.1/lua-5.1.5-so.patch +43 -0
  108. package/shared-modules/lua5.1/lua-5.1.5.json +42 -0
  109. package/shared-modules/lua5.3/lua-5.3.5.json +41 -0
  110. package/shared-modules/lua5.3/lua.pc.in +8 -0
  111. package/shared-modules/lua5.3/luaconf.patch +47 -0
  112. package/shared-modules/lua5.3/makefile-add-liblua.so-rule.patch +47 -0
  113. package/shared-modules/lua5.4/lua-5.4.json +41 -0
  114. package/shared-modules/lua5.4/lua.pc.in +8 -0
  115. package/shared-modules/lua5.4/luaconf.patch +34 -0
  116. package/shared-modules/lua5.4/makefile-add-liblua.so-rule.patch +42 -0
  117. package/shared-modules/luajit/luajit.json +30 -0
  118. package/shared-modules/lzo/lzo.json +27 -0
  119. package/shared-modules/mac/mac.json +18 -0
  120. package/shared-modules/physfs/physfs.json +26 -0
  121. package/shared-modules/pygame/audiofile-gcc6.patch +21 -0
  122. package/shared-modules/pygame/cython-fixes.patch +34 -0
  123. package/shared-modules/pygame/fluidsynth-no-rawmidi.patch +69 -0
  124. package/shared-modules/pygame/glib.patch +25 -0
  125. package/shared-modules/pygame/pygame1-python2.json +157 -0
  126. package/shared-modules/pygtk/pygtk-c99.patch +15 -0
  127. package/shared-modules/pygtk/pygtk.json +117 -0
  128. package/shared-modules/pygtk/pygtk.patch +39 -0
  129. package/shared-modules/python2.7/python-2.7.json +48 -0
  130. package/shared-modules/smpeg/smpeg-0.4.5.json +50 -0
  131. package/shared-modules/smpeg/smpeg-am-prog-as.patch +12 -0
  132. package/shared-modules/smpeg/smpeg-export-mpegaudio-class.patch +17 -0
  133. package/shared-modules/smpeg/smpeg-gcc6.patch +40 -0
  134. package/shared-modules/smpeg/smpeg-no-gtk.patch +37 -0
  135. package/shared-modules/squashfs-tools/squashfs-tools.json +25 -0
  136. package/shared-modules/update-checker.sh +50 -0
  137. package/shared-modules/vorbisgain/0001-temp_files.patch +75 -0
  138. package/shared-modules/vorbisgain/0002-errno.patch +33 -0
  139. package/shared-modules/vorbisgain/0003-manpage.patch +248 -0
  140. package/shared-modules/vorbisgain/0004-vorbisgain_mtime.patch +183 -0
  141. package/shared-modules/vorbisgain/0005-double_fclose.patch +21 -0
  142. package/shared-modules/vorbisgain/0006-manpage_hyphens.patch +56 -0
  143. package/shared-modules/vorbisgain/0007-recursively_spelling.patch +14 -0
  144. package/shared-modules/vorbisgain/0008-manpage_recursion_mistake.patch +23 -0
  145. package/shared-modules/vorbisgain/0009-hardening.patch +13 -0
  146. package/shared-modules/vorbisgain/0010-fclose.patch +13 -0
  147. package/shared-modules/vorbisgain/README.md +23 -0
  148. package/shared-modules/vorbisgain/vorbisgain_0.37-2.json +29 -0
  149. package/src/renderer/shared/agentProgress.ts +145 -0
  150. package/src/renderer/shared/calculator.ts +52 -0
  151. package/src/renderer/shared/components/AgentActivityDrawer.tsx +72 -0
  152. package/src/renderer/shared/components/AgentActivityTable.tsx +66 -0
  153. package/src/renderer/shared/components/ApprovalCard.tsx +93 -0
  154. package/src/renderer/shared/components/ChatCodeBlock.tsx +75 -0
  155. package/src/renderer/shared/components/ThinkingBlock.tsx +101 -0
  156. package/src/renderer/shared/constants/models.ts +91 -0
  157. package/src/renderer/shared/platform.ts +82 -0
  158. package/src/renderer/shared/types.ts +140 -0
  159. package/src/renderer/shared/utils/agentActivity.ts +187 -0
  160. package/src/renderer/shared/utils/approval.ts +1 -0
  161. package/src/renderer/shared/utils/approval.tsx +64 -0
  162. package/src/renderer/shared/utils/markdown.tsx +347 -0
  163. package/src/renderer/shared/utils/providers.ts +36 -0
  164. package/src/renderer/shared/utils/speech.ts +216 -0
  165. package/src/renderer/shared/utils/ui.ts +147 -0
  166. package/src/renderer/src/agentProgress.ts +11 -39
  167. package/src/renderer/src/calculator.ts +3 -46
  168. package/src/renderer/src/components/ChatPanel.tsx +230 -1202
  169. package/src/renderer/src/components/ImageStudioPanel.tsx +11 -1
  170. package/src/renderer/src/components/MintDashboard.tsx +63 -171
  171. package/src/renderer/src/components/PicturesLibrary.tsx +32 -8
  172. package/src/renderer/src/components/Settings/AgentsTab.tsx +362 -0
  173. package/src/renderer/src/components/Settings/AutomationTab.tsx +0 -22
  174. package/src/renderer/src/components/Settings/PluginsTab.tsx +221 -41
  175. package/src/renderer/src/components/SettingsWindow.tsx +54 -12
  176. package/src/renderer/src/components/WorkspacePanel.tsx +66 -9
  177. package/src/renderer/src/css/image-studio.css +6 -0
  178. package/src/renderer/src/css/styles.css +148 -11
  179. package/src/renderer/src/index.css +12 -1
  180. package/src/renderer/src/tauri.ts +169 -143
  181. package/src/renderer/src-web/agentProgress.ts +11 -39
  182. package/src/renderer/src-web/calculator.ts +3 -46
  183. package/src/renderer/src-web/components/ChatPanel.tsx +223 -1199
  184. package/src/renderer/src-web/components/ImageStudioPanel.tsx +11 -1
  185. package/src/renderer/src-web/components/MintDashboard.tsx +31 -172
  186. package/src/renderer/src-web/components/PicturesLibrary.tsx +23 -29
  187. package/src/renderer/src-web/components/Settings/AgentsTab.tsx +362 -0
  188. package/src/renderer/src-web/components/Settings/AutomationTab.tsx +0 -22
  189. package/src/renderer/src-web/components/Settings/PluginsTab.tsx +221 -41
  190. package/src/renderer/src-web/components/SettingsWindow.tsx +54 -12
  191. package/src/renderer/src-web/css/image-studio.css +6 -0
  192. package/src/renderer/src-web/css/styles.css +184 -12
  193. package/src/renderer/src-web/index.css +12 -1
  194. package/src/renderer/src-web/tauri.ts +204 -104
  195. package/src-tauri/src/browser.rs +1 -141
  196. package/src-tauri/src/headless.rs +3 -2
  197. package/src-tauri/src/lib.rs +254 -59
  198. package/src-tauri/src/webhooks.rs +1 -0
  199. package/src-tauri/src/workflows.rs +57 -4
  200. package/src-tauri/tauri.conf.json +1 -1
@@ -0,0 +1,362 @@
1
+ import React, { useState } from 'react'
2
+ import {
3
+ DEFAULT_CONFIG,
4
+ GEMINI_MODELS,
5
+ OPENAI_MODELS,
6
+ OPENROUTER_MODELS,
7
+ DEEPSEEK_MODELS,
8
+ ANTHROPIC_MODELS,
9
+ HF_MODELS,
10
+ LOCAL_MODELS
11
+ } from '../SettingsWindow'
12
+
13
+ interface Agent {
14
+ id: string
15
+ name: string
16
+ provider: string
17
+ model: string
18
+ apiKey?: string
19
+ systemInstruction: string
20
+ enabled: boolean
21
+ }
22
+
23
+ interface AgentsTabProps {
24
+ config: typeof DEFAULT_CONFIG & { agents?: Agent[] }
25
+ updateField: (field: any, value: any) => void
26
+ dynamicOllamaModels?: string[]
27
+ }
28
+
29
+ export default function AgentsTab({ config, updateField, dynamicOllamaModels = [] }: AgentsTabProps) {
30
+ const agents = config.agents || []
31
+ const [editingAgent, setEditingAgent] = useState<Agent | null>(null)
32
+ const [name, setName] = useState('')
33
+ const [provider, setProvider] = useState('gemini')
34
+ const [model, setModel] = useState('gemini-2.5-flash')
35
+ const [apiKey, setApiKey] = useState('')
36
+ const [systemInstruction, setSystemInstruction] = useState('')
37
+ const [isEditing, setIsEditing] = useState(false)
38
+
39
+ const handleProviderChange = (newProvider: string) => {
40
+ setProvider(newProvider)
41
+ let defaultModel = ''
42
+ if (newProvider === 'gemini') defaultModel = config.geminiModel || GEMINI_MODELS[0]
43
+ else if (newProvider === 'openai') defaultModel = config.openaiModel || OPENAI_MODELS[0]
44
+ else if (newProvider === 'anthropic') defaultModel = config.anthropicModel || ANTHROPIC_MODELS[0]
45
+ else if (newProvider === 'openrouter') defaultModel = config.openrouterModel || OPENROUTER_MODELS[0]
46
+ else if (newProvider === 'deepseek') defaultModel = config.deepseekModel || DEEPSEEK_MODELS[0]
47
+ else if (newProvider === 'huggingface') defaultModel = config.hfModel || HF_MODELS[0]
48
+ else if (newProvider === 'local_openai') defaultModel = config.localModelName || LOCAL_MODELS[0]
49
+ else if (newProvider === 'ollama') defaultModel = config.ollamaModel || dynamicOllamaModels[0] || 'llama3:latest'
50
+ setModel(defaultModel)
51
+ }
52
+
53
+ const handleEdit = (agent: Agent) => {
54
+ setEditingAgent(agent)
55
+ setName(agent.name)
56
+ setProvider(agent.provider)
57
+ setModel(agent.model)
58
+ setApiKey(agent.apiKey || '')
59
+ setSystemInstruction(agent.systemInstruction)
60
+ setIsEditing(true)
61
+ }
62
+
63
+ const handleSaveAgent = () => {
64
+ if (!name.trim()) {
65
+ alert('Please enter an agent name.')
66
+ return
67
+ }
68
+
69
+ let updatedAgents: Agent[] = []
70
+ if (editingAgent) {
71
+ // Update existing agent
72
+ updatedAgents = agents.map(a =>
73
+ a.id === editingAgent.id
74
+ ? { ...a, name, provider, model, apiKey: apiKey || undefined, systemInstruction }
75
+ : a
76
+ )
77
+ } else {
78
+ // Add new agent
79
+ const newAgent: Agent = {
80
+ id: `agent-${Date.now()}`,
81
+ name,
82
+ provider,
83
+ model,
84
+ apiKey: apiKey || undefined,
85
+ systemInstruction,
86
+ enabled: true
87
+ }
88
+ updatedAgents = [...agents, newAgent]
89
+ }
90
+
91
+ updateField('agents', updatedAgents)
92
+ closeForm()
93
+ }
94
+
95
+ const handleDeleteAgent = (id: string) => {
96
+ if (confirm('Are you sure you want to delete this agent?')) {
97
+ const updatedAgents = agents.filter(a => a.id !== id)
98
+ updateField('agents', updatedAgents)
99
+ }
100
+ }
101
+
102
+ const handleToggleAgent = (id: string, enabled: boolean) => {
103
+ const updatedAgents = agents.map(a =>
104
+ a.id === id ? { ...a, enabled } : a
105
+ )
106
+ updateField('agents', updatedAgents)
107
+ }
108
+
109
+ const handleDisableAll = () => {
110
+ const updatedAgents = agents.map(a => ({ ...a, enabled: false }))
111
+ updateField('agents', updatedAgents)
112
+ }
113
+
114
+ const closeForm = () => {
115
+ setEditingAgent(null)
116
+ setName('')
117
+ setProvider('gemini')
118
+ setModel('gemini-2.5-flash')
119
+ setApiKey('')
120
+ setSystemInstruction('')
121
+ setIsEditing(false)
122
+ }
123
+
124
+ const handleAddClick = () => {
125
+ setEditingAgent(null)
126
+ setName('')
127
+ setProvider('gemini')
128
+ setModel('gemini-2.5-flash')
129
+ setApiKey('')
130
+ setSystemInstruction('')
131
+ setIsEditing(true)
132
+ }
133
+
134
+ // Filter providers that have configured API keys, plus local ones
135
+ const availableProviders = [
136
+ { value: 'gemini', label: 'Google Gemini', hasKey: !!config.apiKey },
137
+ { value: 'openai', label: 'OpenAI', hasKey: !!config.openaiApiKey },
138
+ { value: 'anthropic', label: 'Anthropic Claude', hasKey: !!config.anthropicApiKey },
139
+ { value: 'openrouter', label: 'OpenRouter', hasKey: !!config.openrouterApiKey },
140
+ { value: 'deepseek', label: 'DeepSeek', hasKey: !!config.deepseekApiKey },
141
+ { value: 'ollama', label: 'Ollama (Local)', hasKey: true },
142
+ { value: 'huggingface', label: 'Hugging Face', hasKey: !!config.hfApiKey },
143
+ { value: 'local_openai', label: 'Local (LM Studio / OpenAI Compatible)', hasKey: true },
144
+ ].filter(p => p.hasKey);
145
+
146
+ // Find out what models list corresponds to the selected provider
147
+ let modelList: string[] = []
148
+ let defaultGeneralModel = ''
149
+ if (provider === 'gemini') {
150
+ modelList = GEMINI_MODELS
151
+ defaultGeneralModel = config.geminiModel
152
+ } else if (provider === 'openai') {
153
+ modelList = OPENAI_MODELS
154
+ defaultGeneralModel = config.openaiModel
155
+ } else if (provider === 'openrouter') {
156
+ modelList = OPENROUTER_MODELS
157
+ defaultGeneralModel = config.openrouterModel
158
+ } else if (provider === 'deepseek') {
159
+ modelList = DEEPSEEK_MODELS
160
+ defaultGeneralModel = config.deepseekModel
161
+ } else if (provider === 'anthropic') {
162
+ modelList = ANTHROPIC_MODELS
163
+ defaultGeneralModel = config.anthropicModel
164
+ } else if (provider === 'huggingface') {
165
+ modelList = HF_MODELS
166
+ defaultGeneralModel = config.hfModel
167
+ } else if (provider === 'local_openai') {
168
+ modelList = LOCAL_MODELS
169
+ defaultGeneralModel = config.localModelName
170
+ } else if (provider === 'ollama') {
171
+ modelList = dynamicOllamaModels
172
+ defaultGeneralModel = config.ollamaModel
173
+ }
174
+
175
+ // Sort modelList so defaultGeneralModel is first (at the top)
176
+ const sortedModelList = defaultGeneralModel
177
+ ? [defaultGeneralModel, ...modelList.filter(m => m !== defaultGeneralModel)]
178
+ : modelList;
179
+
180
+ const isCustomModel = !sortedModelList.includes(model)
181
+
182
+ return (
183
+ <div className="tab-pane active animate-fade-in" style={{ display: 'flex', flexDirection: 'column', gap: '24px' }}>
184
+ <section className="setting-section">
185
+ <div className="section-heading" style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
186
+ <div>
187
+ <p className="section-kicker">Multi-Agent System</p>
188
+ <h2 className="section-title">Agent Collaboration Settings</h2>
189
+ <p className="section-description">
190
+ Configure multiple distinct AI agents with specific roles. You can adjust the models, system instructions, and credentials for each agent.
191
+ </p>
192
+ </div>
193
+ {!isEditing && (
194
+ <div style={{ display: 'flex', gap: '10px', height: 'fit-content', flexShrink: 0 }}>
195
+ <button className="btn btn-secondary" onClick={handleDisableAll} style={{ whiteSpace: 'nowrap' }}>
196
+ Disable All
197
+ </button>
198
+ <button className="btn btn-primary" onClick={handleAddClick} style={{ whiteSpace: 'nowrap' }}>
199
+ + Add Custom Agent
200
+ </button>
201
+ </div>
202
+ )}
203
+ </div>
204
+
205
+ <div className="toggle-row" style={{ margin: '16px 0 24px 0' }}>
206
+ <div>
207
+ <label>Enable Multi-Agent Collaboration</label>
208
+ <p className="hint">Allow multiple specialized agents to collaborate sequentially (Planner → Coder → Reviewer).</p>
209
+ </div>
210
+ <label className="settings-toggle-switch">
211
+ <input
212
+ type="checkbox"
213
+ checked={config.enableAgentCollaboration}
214
+ onChange={(e) => updateField('enableAgentCollaboration', e.target.checked)}
215
+ />
216
+ <span className="settings-toggle-slider"></span>
217
+ </label>
218
+ </div>
219
+
220
+ {isEditing ? (
221
+ <div className="form-grid single" style={{ background: 'var(--panel-soft)', padding: '20px', borderRadius: '8px', border: '1px solid var(--panel-raised)', marginTop: '10px' }}>
222
+ <h3 style={{ margin: '0 0 16px 0', fontSize: '18px', color: 'var(--accent)' }}>
223
+ {editingAgent ? `Edit Agent: ${editingAgent.name}` : 'Create New Agent'}
224
+ </h3>
225
+
226
+ <div className="setting-row">
227
+ <label>Agent Name</label>
228
+ <input
229
+ type="text"
230
+ value={name}
231
+ onChange={(e) => setName(e.target.value)}
232
+ placeholder="e.g. Code Reviewer"
233
+ />
234
+ </div>
235
+
236
+ <div className="setting-row">
237
+ <label>AI Provider</label>
238
+ <select value={provider} onChange={(e) => handleProviderChange(e.target.value)}>
239
+ {availableProviders.map(p => (
240
+ <option key={p.value} value={p.value}>{p.label}</option>
241
+ ))}
242
+ </select>
243
+ </div>
244
+
245
+ <div className="setting-row">
246
+ <label>Model Name</label>
247
+ <select
248
+ value={isCustomModel ? 'custom' : model}
249
+ onChange={(e) => {
250
+ const val = e.target.value
251
+ if (val === 'custom') {
252
+ setModel('')
253
+ } else {
254
+ setModel(val)
255
+ }
256
+ }}
257
+ >
258
+ {sortedModelList.map(m => (
259
+ <option key={m} value={m}>{m}</option>
260
+ ))}
261
+ <option value="custom">Custom...</option>
262
+ </select>
263
+ </div>
264
+
265
+ {isCustomModel && (
266
+ <div className="setting-row">
267
+ <label>Custom Model Name</label>
268
+ <input
269
+ type="text"
270
+ value={model}
271
+ onChange={(e) => setModel(e.target.value)}
272
+ placeholder="Enter custom model name..."
273
+ />
274
+ </div>
275
+ )}
276
+
277
+ <div className="setting-row">
278
+ <label>Custom API Key (Optional)</label>
279
+ <input
280
+ type="password"
281
+ value={apiKey}
282
+ onChange={(e) => setApiKey(e.target.value)}
283
+ placeholder="Leave blank to use global provider API key"
284
+ />
285
+ </div>
286
+
287
+ <div className="setting-row">
288
+ <label>System Instructions / Role</label>
289
+ <textarea
290
+ value={systemInstruction}
291
+ onChange={(e) => setSystemInstruction(e.target.value)}
292
+ placeholder="Describe this agent's goal, instructions, and personality..."
293
+ style={{ minHeight: '120px', resize: 'vertical' }}
294
+ />
295
+ </div>
296
+
297
+ <div style={{ display: 'flex', gap: '10px', marginTop: '16px', justifyContent: 'flex-end' }}>
298
+ <button className="btn btn-secondary" onClick={closeForm}>Cancel</button>
299
+ <button className="btn btn-primary" onClick={handleSaveAgent}>Save Agent</button>
300
+ </div>
301
+ </div>
302
+ ) : (
303
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '16px', marginTop: '16px' }}>
304
+ {agents.map((agent) => (
305
+ <div
306
+ key={agent.id}
307
+ style={{
308
+ display: 'flex',
309
+ flexDirection: 'column',
310
+ padding: '16px',
311
+ background: 'var(--panel-bg)',
312
+ border: '1px solid var(--panel-raised)',
313
+ borderRadius: '8px',
314
+ gap: '8px'
315
+ }}
316
+ >
317
+ <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
318
+ <div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
319
+ <strong style={{ fontSize: '18px' }}>{agent.name}</strong>
320
+ <span
321
+ style={{
322
+ fontSize: '11px',
323
+ padding: '2px 6px',
324
+ borderRadius: '4px',
325
+ background: 'var(--panel-raised)',
326
+ color: 'var(--accent)'
327
+ }}
328
+ >
329
+ {agent.provider} ({agent.model})
330
+ </span>
331
+ </div>
332
+ <div style={{ display: 'flex', alignItems: 'center', gap: '14px' }}>
333
+ <label className="settings-toggle-switch">
334
+ <input
335
+ type="checkbox"
336
+ checked={agent.enabled}
337
+ onChange={(e) => handleToggleAgent(agent.id, e.target.checked)}
338
+ />
339
+ <span className="settings-toggle-slider"></span>
340
+ </label>
341
+ <button className="btn btn-secondary" style={{ padding: '4px 8px', fontSize: '12px' }} onClick={() => handleEdit(agent)}>Edit</button>
342
+ {!['planner', 'coder', 'reviewer'].includes(agent.id) && (
343
+ <button className="btn btn-danger" style={{ padding: '4px 8px', fontSize: '12px' }} onClick={() => handleDeleteAgent(agent.id)}>Delete</button>
344
+ )}
345
+ </div>
346
+ </div>
347
+ <p style={{ margin: '4px 0 0 0', fontSize: '14px', color: 'var(--text-soft)', fontStyle: 'italic' }}>
348
+ "{agent.systemInstruction}"
349
+ </p>
350
+ </div>
351
+ ))}
352
+ {agents.length === 0 && (
353
+ <div style={{ textAlign: 'center', padding: '32px', color: 'var(--text-soft)', fontStyle: 'italic' }}>
354
+ No agents configured. Click "+ Add Custom Agent" to get started.
355
+ </div>
356
+ )}
357
+ </div>
358
+ )}
359
+ </section>
360
+ </div>
361
+ )
362
+ }
@@ -168,28 +168,6 @@ export default function AutomationTab({
168
168
  </div>
169
169
  </section>
170
170
 
171
- <section className="setting-section">
172
- <div className="section-heading">
173
- <div>
174
- <p className="section-kicker">Code mode</p>
175
- <h2 className="section-title">Agent Collaboration</h2>
176
- </div>
177
- </div>
178
- <div className="toggle-row">
179
- <div>
180
- <label>Enable Multi-Agent Review</label>
181
- <p className="hint">Allow a secondary model to review code written by the primary model.</p>
182
- </div>
183
- <label className="settings-toggle-switch">
184
- <input
185
- type="checkbox"
186
- checked={config.enableAgentCollaboration}
187
- onChange={(e) => updateField('enableAgentCollaboration', e.target.checked)}
188
- />
189
- <span className="settings-toggle-slider"></span>
190
- </label>
191
- </div>
192
- </section>
193
171
  </div>
194
172
  )
195
173
  }