@pheem49/mint 1.3.0 → 1.4.0
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 +28 -24
- package/mint-cli.js +201 -26
- package/package.json +13 -2
- package/src/AI_Brain/Gemini_API.js +299 -46
- package/src/AI_Brain/agent_orchestrator.js +73 -0
- package/src/AI_Brain/autonomous_brain.js +2 -0
- package/src/AI_Brain/memory_store.js +318 -0
- package/src/CLI/chat_router.js +17 -2
- package/src/CLI/chat_ui.js +83 -1
- package/src/CLI/code_agent.js +143 -30
- package/src/CLI/onboarding.js +53 -6
- package/src/CLI/workspace_manager.js +81 -0
- package/src/Plugins/spotify.js +168 -40
- package/src/Plugins/system_monitor.js +72 -0
- package/src/System/config_manager.js +35 -2
- package/src/System/notifications.js +23 -0
- package/src/UI/settings.html +143 -65
- package/src/UI/settings.js +155 -41
- package/tests/agent_orchestrator.test.js +41 -0
- package/tests/config_manager.test.js +141 -0
- package/tests/memory_store.test.js +185 -0
- package/tests/spotify.test.js +201 -0
- package/tests/system_monitor.test.js +37 -0
- package/tests/workspace_manager.test.js +41 -0
package/src/UI/settings.html
CHANGED
|
@@ -38,74 +38,138 @@
|
|
|
38
38
|
<div class="settings-content" id="settings-content">
|
|
39
39
|
|
|
40
40
|
<div class="tab-pane active" id="sect-general">
|
|
41
|
-
<!-- API
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
41
|
+
<!-- API Keys & Hosts -->
|
|
42
|
+
<section class="setting-section">
|
|
43
|
+
<h2 class="section-title">🔑 API Keys & Hosts</h2>
|
|
44
|
+
<div class="setting-row">
|
|
45
|
+
<label for="api-key-input">Gemini API Key</label>
|
|
46
|
+
<div class="input-group">
|
|
47
|
+
<input type="password" id="api-key-input" placeholder="Enter Gemini API Key..." autocomplete="off">
|
|
48
|
+
<button class="toggle-visibility" onclick="const i = document.getElementById('api-key-input'); i.type = i.type === 'password' ? 'text' : 'password';" title="Show/Hide">👁</button>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
<div class="setting-row" style="margin-top: 10px;">
|
|
52
|
+
<label for="openai-api-key-input">OpenAI API Key</label>
|
|
53
|
+
<div class="input-group">
|
|
54
|
+
<input type="password" id="openai-api-key-input" placeholder="Enter OpenAI API Key..." autocomplete="off">
|
|
55
|
+
<button class="toggle-visibility" onclick="const i = document.getElementById('openai-api-key-input'); i.type = i.type === 'password' ? 'text' : 'password';" title="Show/Hide">👁</button>
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
<div class="setting-row" style="margin-top: 10px;">
|
|
59
|
+
<label for="anthropic-api-key-input">Anthropic API Key</label>
|
|
60
|
+
<div class="input-group">
|
|
61
|
+
<input type="password" id="anthropic-api-key-input" placeholder="Enter Anthropic API Key..." autocomplete="off">
|
|
62
|
+
<button class="toggle-visibility" onclick="const i = document.getElementById('anthropic-api-key-input'); i.type = i.type === 'password' ? 'text' : 'password';" title="Show/Hide">👁</button>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
<div class="setting-row" style="margin-top: 10px;">
|
|
66
|
+
<label for="hf-api-key">Hugging Face API Key</label>
|
|
67
|
+
<div class="input-group">
|
|
68
|
+
<input type="password" id="hf-api-key" placeholder="Enter Hugging Face API Key..." autocomplete="off">
|
|
69
|
+
<button class="toggle-visibility" onclick="const i = document.getElementById('hf-api-key'); i.type = i.type === 'password' ? 'text' : 'password';" title="Show/Hide">👁</button>
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
<div class="setting-row" style="margin-top: 10px;">
|
|
73
|
+
<label for="local-api-base-url">LM Studio Base URL</label>
|
|
74
|
+
<input type="text" id="local-api-base-url" placeholder="e.g. http://localhost:1234/v1">
|
|
75
|
+
</div>
|
|
76
|
+
<div class="setting-row" style="margin-top: 10px;">
|
|
77
|
+
<label for="ollama-host-input">Ollama Host</label>
|
|
78
|
+
<input type="text" id="ollama-host-input" placeholder="e.g. http://localhost:11434">
|
|
79
|
+
</div>
|
|
80
|
+
<div class="setting-row" style="display: flex; align-items: center; justify-content: space-between; margin-top: 20px; padding: 12px; background: rgba(139, 92, 246, 0.1); border-radius: 12px; border: 1px solid rgba(139, 92, 246, 0.2);">
|
|
81
|
+
<div style="display: flex; flex-direction: column; gap: 4px;">
|
|
82
|
+
<label for="show-desktop-widget" style="margin-bottom: 0; font-weight: 500;">Show Desktop AI Candidate</label>
|
|
83
|
+
<span class="hint" style="font-size: 0.75rem;">Show the mini AI character on your desktop</span>
|
|
84
|
+
</div>
|
|
85
|
+
<label class="toggle-switch">
|
|
86
|
+
<input type="checkbox" id="show-desktop-widget">
|
|
87
|
+
<span class="toggle-slider"></span>
|
|
88
|
+
</label>
|
|
89
|
+
</div>
|
|
90
|
+
</section>
|
|
80
91
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
<
|
|
85
|
-
|
|
86
|
-
<
|
|
87
|
-
<
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
+
<!-- Models Configuration -->
|
|
93
|
+
<section class="setting-section">
|
|
94
|
+
<h2 class="section-title">🧠 AI Engine & Default Models</h2>
|
|
95
|
+
<div class="setting-row">
|
|
96
|
+
<label for="ai-provider-select">Active Provider</label>
|
|
97
|
+
<div class="input-group">
|
|
98
|
+
<select id="ai-provider-select" style="width: 100%; background: var(--input-bg); border: 1px solid var(--border); border-radius: 10px; padding: 10px 14px; color: var(--text-main); font-family: inherit; font-size: 0.9rem; outline: none; transition: border-color 0.2s; cursor: pointer;">
|
|
99
|
+
<option value="gemini" style="background: var(--bg-color)">Google Gemini (Cloud)</option>
|
|
100
|
+
<option value="anthropic" style="background: var(--bg-color)">Anthropic Claude</option>
|
|
101
|
+
<option value="openai" style="background: var(--bg-color)">OpenAI</option>
|
|
102
|
+
<option value="ollama" style="background: var(--bg-color)">Ollama (Local / Private)</option>
|
|
103
|
+
<option value="huggingface" style="background: var(--bg-color)">Hugging Face (Inference API)</option>
|
|
104
|
+
<option value="local_openai" style="background: var(--bg-color)">Local (LM Studio / OpenAI Compatible)</option>
|
|
105
|
+
</select>
|
|
106
|
+
</div>
|
|
92
107
|
</div>
|
|
93
|
-
</div>
|
|
94
|
-
<div class="setting-row" id="gemini-model-custom-row" style="display: none; margin-top: 10px;">
|
|
95
|
-
<label for="gemini-model-custom">Custom Model</label>
|
|
96
|
-
<input type="text" id="gemini-model-custom" placeholder="e.g. gemini-3.1-flash-lite-preview">
|
|
97
|
-
</div>
|
|
98
|
-
</div>
|
|
99
108
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
+
<div class="setting-row" style="margin-top: 14px;">
|
|
110
|
+
<label for="gemini-model-select">Gemini Model</label>
|
|
111
|
+
<div class="input-group">
|
|
112
|
+
<select id="gemini-model-select" style="width: 100%; background: var(--input-bg); border: 1px solid var(--border); border-radius: 10px; padding: 10px 14px; color: var(--text-main); font-family: inherit; font-size: 0.9rem; outline: none; transition: border-color 0.2s; cursor: pointer;">
|
|
113
|
+
<option value="gemini-2.5-flash" style="background: var(--bg-color)">gemini-2.5-flash</option>
|
|
114
|
+
<option value="gemini-3.1-flash-lite" style="background: var(--bg-color)">gemini-3.1-flash-lite</option>
|
|
115
|
+
<option value="gemini-3.1-flash-lite-preview" style="background: var(--bg-color)">gemini-3.1-flash-lite-preview</option>
|
|
116
|
+
<option value="custom" style="background: var(--bg-color)">Custom...</option>
|
|
117
|
+
</select>
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
<div class="setting-row" id="gemini-model-custom-row" style="display: none; margin-top: 10px;">
|
|
121
|
+
<label for="gemini-model-custom">Custom Gemini Model</label>
|
|
122
|
+
<input type="text" id="gemini-model-custom" placeholder="e.g. gemini-3.1-flash-lite-preview">
|
|
123
|
+
</div>
|
|
124
|
+
|
|
125
|
+
<div class="setting-row" style="margin-top: 14px;">
|
|
126
|
+
<label for="openai-model-select">OpenAI Model</label>
|
|
127
|
+
<div class="input-group">
|
|
128
|
+
<select id="openai-model-select" style="width: 100%; background: var(--input-bg); border: 1px solid var(--border); border-radius: 10px; padding: 10px 14px; color: var(--text-main); font-family: inherit; font-size: 0.9rem; outline: none; transition: border-color 0.2s; cursor: pointer;">
|
|
129
|
+
<option value="gpt-4o" style="background: var(--bg-color)">gpt-4o</option>
|
|
130
|
+
<option value="gpt-4o-mini" style="background: var(--bg-color)">gpt-4o-mini</option>
|
|
131
|
+
<option value="o1-preview" style="background: var(--bg-color)">o1-preview</option>
|
|
132
|
+
<option value="o1-mini" style="background: var(--bg-color)">o1-mini</option>
|
|
133
|
+
<option value="custom" style="background: var(--bg-color)">Custom...</option>
|
|
134
|
+
</select>
|
|
135
|
+
</div>
|
|
136
|
+
</div>
|
|
137
|
+
<div class="setting-row" id="openai-model-custom-row" style="display: none; margin-top: 10px;">
|
|
138
|
+
<label for="openai-model-custom">Custom OpenAI Model</label>
|
|
139
|
+
<input type="text" id="openai-model-custom" placeholder="e.g. gpt-4o">
|
|
140
|
+
</div>
|
|
141
|
+
|
|
142
|
+
<div class="setting-row" style="margin-top: 14px;">
|
|
143
|
+
<label for="anthropic-model-select">Anthropic Model</label>
|
|
144
|
+
<div class="input-group">
|
|
145
|
+
<select id="anthropic-model-select" style="width: 100%; background: var(--input-bg); border: 1px solid var(--border); border-radius: 10px; padding: 10px 14px; color: var(--text-main); font-family: inherit; font-size: 0.9rem; outline: none; transition: border-color 0.2s; cursor: pointer;">
|
|
146
|
+
<option value="claude-3-5-sonnet-latest" style="background: var(--bg-color)">claude-3-5-sonnet-latest</option>
|
|
147
|
+
<option value="claude-3-opus-latest" style="background: var(--bg-color)">claude-3-opus-latest</option>
|
|
148
|
+
<option value="claude-3-5-haiku-latest" style="background: var(--bg-color)">claude-3-5-haiku-latest</option>
|
|
149
|
+
<option value="custom" style="background: var(--bg-color)">Custom...</option>
|
|
150
|
+
</select>
|
|
151
|
+
</div>
|
|
152
|
+
</div>
|
|
153
|
+
<div class="setting-row" id="anthropic-model-custom-row" style="display: none; margin-top: 10px;">
|
|
154
|
+
<label for="anthropic-model-custom">Custom Anthropic Model</label>
|
|
155
|
+
<input type="text" id="anthropic-model-custom" placeholder="e.g. claude-3-5-sonnet-latest">
|
|
156
|
+
</div>
|
|
157
|
+
|
|
158
|
+
<div class="setting-row" style="margin-top: 14px;">
|
|
159
|
+
<label for="hf-model-name">Hugging Face Model</label>
|
|
160
|
+
<input type="text" id="hf-model-name" placeholder="e.g. meta-llama/Meta-Llama-3-8B-Instruct">
|
|
161
|
+
</div>
|
|
162
|
+
|
|
163
|
+
<div class="setting-row" style="margin-top: 14px;">
|
|
164
|
+
<label for="local-model-name">Local (LM Studio) Model</label>
|
|
165
|
+
<input type="text" id="local-model-name" placeholder="e.g. local-model">
|
|
166
|
+
</div>
|
|
167
|
+
|
|
168
|
+
<div class="setting-row" style="margin-top: 14px;">
|
|
169
|
+
<label for="ollama-model-input">Ollama Model</label>
|
|
170
|
+
<input type="text" id="ollama-model-input" placeholder="e.g. llama3:latest">
|
|
171
|
+
</div>
|
|
172
|
+
</section>
|
|
109
173
|
</div>
|
|
110
174
|
<div class="tab-pane" id="sect-audio">
|
|
111
175
|
<!-- Audio & Voice -->
|
|
@@ -212,6 +276,20 @@
|
|
|
212
276
|
<button class="btn-secondary" id="open-workflows-btn">Open workflows.json</button>
|
|
213
277
|
<button class="btn-primary" id="reload-workflows-btn">Reload Rules</button>
|
|
214
278
|
</div>
|
|
279
|
+
</section>
|
|
280
|
+
<!-- Agent Collaboration -->
|
|
281
|
+
<section class="setting-section">
|
|
282
|
+
<h2 class="section-title">🤝 Agent Collaboration</h2>
|
|
283
|
+
<div class="setting-row" style="display: flex; align-items: center; justify-content: space-between;">
|
|
284
|
+
<label for="enable-agent-collaboration" style="margin-bottom: 0;">Enable Multi-Agent Review</label>
|
|
285
|
+
<label class="toggle-switch">
|
|
286
|
+
<input type="checkbox" id="enable-agent-collaboration">
|
|
287
|
+
<span class="toggle-slider"></span>
|
|
288
|
+
</label>
|
|
289
|
+
</div>
|
|
290
|
+
<div class="setting-row" style="margin-top: 10px;">
|
|
291
|
+
<p class="hint">When in Code Mode, allow a secondary AI model to automatically review the code written by the primary model. (Requires multiple API keys. Costs API credits for both models.)</p>
|
|
292
|
+
</div>
|
|
215
293
|
</section>
|
|
216
294
|
</div>
|
|
217
295
|
<div class="tab-pane" id="sect-theme">
|
package/src/UI/settings.js
CHANGED
|
@@ -16,6 +16,7 @@ const DEFAULT_CONFIG = {
|
|
|
16
16
|
ollamaModel: 'llama3:latest',
|
|
17
17
|
enableVoiceReply: true,
|
|
18
18
|
enableCustomWorkflows: true,
|
|
19
|
+
enableAgentCollaboration: true,
|
|
19
20
|
ttsProvider: 'google',
|
|
20
21
|
ttsVolume: 1.0,
|
|
21
22
|
ttsSpeed: 1.0,
|
|
@@ -57,6 +58,18 @@ function applyConfig(config) {
|
|
|
57
58
|
// Apply API key
|
|
58
59
|
document.getElementById('api-key-input').value = config.apiKey || '';
|
|
59
60
|
|
|
61
|
+
const anthropicInput = document.getElementById('anthropic-api-key-input');
|
|
62
|
+
if (anthropicInput) anthropicInput.value = config.anthropicApiKey || '';
|
|
63
|
+
|
|
64
|
+
const openaiInput = document.getElementById('openai-api-key-input');
|
|
65
|
+
if (openaiInput) openaiInput.value = config.openaiApiKey || '';
|
|
66
|
+
|
|
67
|
+
const hfInput = document.getElementById('hf-api-key');
|
|
68
|
+
if (hfInput) hfInput.value = config.hfApiKey || '';
|
|
69
|
+
|
|
70
|
+
const ollamaHostInput = document.getElementById('ollama-host-input');
|
|
71
|
+
if (ollamaHostInput) ollamaHostInput.value = config.ollamaHost || 'http://localhost:11434';
|
|
72
|
+
|
|
60
73
|
// Apply Gemini model
|
|
61
74
|
applyModelSelection(config.geminiModel);
|
|
62
75
|
|
|
@@ -72,6 +85,24 @@ function applyConfig(config) {
|
|
|
72
85
|
ollamaInput.value = config.ollamaModel || 'llama3:latest';
|
|
73
86
|
}
|
|
74
87
|
|
|
88
|
+
applyModelSelectionGeneric('openai-model-select', 'openai-model-custom-row', 'openai-model-custom', config.openaiModel || 'gpt-4o');
|
|
89
|
+
applyModelSelectionGeneric('anthropic-model-select', 'anthropic-model-custom-row', 'anthropic-model-custom', config.anthropicModel || 'claude-3-5-sonnet-latest');
|
|
90
|
+
|
|
91
|
+
const hfModelInput = document.getElementById('hf-model-name');
|
|
92
|
+
if (hfModelInput) {
|
|
93
|
+
hfModelInput.value = config.hfModel || 'meta-llama/Meta-Llama-3-8B-Instruct';
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const localApiBaseUrlInput = document.getElementById('local-api-base-url');
|
|
97
|
+
if (localApiBaseUrlInput) {
|
|
98
|
+
localApiBaseUrlInput.value = config.localApiBaseUrl || 'http://localhost:1234/v1';
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const localModelNameInput = document.getElementById('local-model-name');
|
|
102
|
+
if (localModelNameInput) {
|
|
103
|
+
localModelNameInput.value = config.localModelName || 'local-model';
|
|
104
|
+
}
|
|
105
|
+
|
|
75
106
|
const voiceReplyToggle = document.getElementById('enable-voice-reply');
|
|
76
107
|
if (voiceReplyToggle) {
|
|
77
108
|
voiceReplyToggle.checked = config.enableVoiceReply !== false;
|
|
@@ -103,6 +134,11 @@ function applyConfig(config) {
|
|
|
103
134
|
enableWorkflowsToggle.checked = config.enableCustomWorkflows !== false;
|
|
104
135
|
}
|
|
105
136
|
|
|
137
|
+
const enableAgentCollaborationToggle = document.getElementById('enable-agent-collaboration');
|
|
138
|
+
if (enableAgentCollaborationToggle) {
|
|
139
|
+
enableAgentCollaborationToggle.checked = config.enableAgentCollaboration !== false;
|
|
140
|
+
}
|
|
141
|
+
|
|
106
142
|
// Plugins logic
|
|
107
143
|
updatePluginButton('spotify', config.pluginSpotifyEnabled);
|
|
108
144
|
updatePluginButton('calendar', config.pluginCalendarEnabled);
|
|
@@ -168,9 +204,15 @@ function lightenColor(hex, amount) {
|
|
|
168
204
|
}
|
|
169
205
|
|
|
170
206
|
function applyModelSelection(model) {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
207
|
+
applyModelSelectionGeneric('gemini-model-select', 'gemini-model-custom-row', 'gemini-model-custom', model);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function applyModelSelectionGeneric(selectId, customRowId, customInputId, model) {
|
|
211
|
+
const select = document.getElementById(selectId);
|
|
212
|
+
const customRow = document.getElementById(customRowId);
|
|
213
|
+
const customInput = document.getElementById(customInputId);
|
|
214
|
+
if (!select || !customRow || !customInput) return;
|
|
215
|
+
|
|
174
216
|
const normalized = (model || '').trim();
|
|
175
217
|
const optionValues = Array.from(select.options).map(opt => opt.value);
|
|
176
218
|
|
|
@@ -186,11 +228,16 @@ function applyModelSelection(model) {
|
|
|
186
228
|
}
|
|
187
229
|
|
|
188
230
|
function getSelectedModel() {
|
|
189
|
-
|
|
190
|
-
|
|
231
|
+
return getSelectedModelGeneric('gemini-model-select', 'gemini-model-custom', DEFAULT_CONFIG.geminiModel);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function getSelectedModelGeneric(selectId, customInputId, defaultModel) {
|
|
235
|
+
const select = document.getElementById(selectId);
|
|
236
|
+
const customInput = document.getElementById(customInputId);
|
|
237
|
+
if (!select || !customInput) return defaultModel;
|
|
191
238
|
if (select.value === 'custom') {
|
|
192
239
|
const custom = (customInput.value || '').trim();
|
|
193
|
-
return custom ||
|
|
240
|
+
return custom || defaultModel;
|
|
194
241
|
}
|
|
195
242
|
return select.value;
|
|
196
243
|
}
|
|
@@ -198,21 +245,28 @@ function getSelectedModel() {
|
|
|
198
245
|
// --- Event Listeners ---
|
|
199
246
|
|
|
200
247
|
// Close button
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
248
|
+
// Close button
|
|
249
|
+
const closeBtn = document.getElementById('close-btn');
|
|
250
|
+
if (closeBtn) {
|
|
251
|
+
closeBtn.addEventListener('click', () => {
|
|
252
|
+
window.settingsApi.closeSettings();
|
|
253
|
+
});
|
|
254
|
+
}
|
|
204
255
|
|
|
205
256
|
// Toggle API key visibility
|
|
206
|
-
document.getElementById('toggle-key')
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
257
|
+
const toggleKey = document.getElementById('toggle-key');
|
|
258
|
+
if (toggleKey) {
|
|
259
|
+
toggleKey.addEventListener('click', () => {
|
|
260
|
+
const input = document.getElementById('api-key-input');
|
|
261
|
+
input.type = input.type === 'password' ? 'text' : 'password';
|
|
262
|
+
});
|
|
263
|
+
}
|
|
210
264
|
|
|
211
265
|
async function saveApiKeyOnly() {
|
|
212
266
|
const input = document.getElementById('api-key-input');
|
|
213
267
|
const status = document.getElementById('api-save-status');
|
|
214
268
|
const btn = document.getElementById('save-api-key');
|
|
215
|
-
const apiKey = input.value.trim();
|
|
269
|
+
const apiKey = input ? input.value.trim() : '';
|
|
216
270
|
|
|
217
271
|
try {
|
|
218
272
|
const baseConfig = await window.settingsApi.getSettings();
|
|
@@ -220,26 +274,31 @@ async function saveApiKeyOnly() {
|
|
|
220
274
|
await window.settingsApi.saveSettings(nextConfig);
|
|
221
275
|
currentConfig.apiKey = apiKey;
|
|
222
276
|
|
|
223
|
-
btn.textContent = 'Saved!';
|
|
224
|
-
status.textContent = 'API key saved';
|
|
277
|
+
if (btn) btn.textContent = 'Saved!';
|
|
278
|
+
if (status) status.textContent = 'API key saved';
|
|
225
279
|
setTimeout(() => {
|
|
226
|
-
btn.textContent = 'Save API Key';
|
|
227
|
-
status.textContent = '';
|
|
280
|
+
if (btn) btn.textContent = 'Save API Key';
|
|
281
|
+
if (status) status.textContent = '';
|
|
228
282
|
}, 1500);
|
|
229
283
|
} catch (err) {
|
|
230
284
|
console.error('Failed to save API key:', err);
|
|
231
|
-
status.textContent = 'Save failed';
|
|
232
|
-
setTimeout(() => { status.textContent = ''; }, 1500);
|
|
285
|
+
if (status) status.textContent = 'Save failed';
|
|
286
|
+
setTimeout(() => { if (status) status.textContent = ''; }, 1500);
|
|
233
287
|
}
|
|
234
288
|
}
|
|
235
289
|
|
|
236
|
-
document.getElementById('save-api-key')
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
290
|
+
const saveApiKey = document.getElementById('save-api-key');
|
|
291
|
+
if (saveApiKey) saveApiKey.addEventListener('click', saveApiKeyOnly);
|
|
292
|
+
|
|
293
|
+
const apiKeyInput = document.getElementById('api-key-input');
|
|
294
|
+
if (apiKeyInput) {
|
|
295
|
+
apiKeyInput.addEventListener('keydown', (e) => {
|
|
296
|
+
if (e.key === 'Enter') {
|
|
297
|
+
e.preventDefault();
|
|
298
|
+
saveApiKeyOnly();
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
}
|
|
243
302
|
|
|
244
303
|
// Gemini model select
|
|
245
304
|
document.getElementById('gemini-model-select').addEventListener('change', (e) => {
|
|
@@ -257,23 +316,45 @@ document.getElementById('gemini-model-custom').addEventListener('input', (e) =>
|
|
|
257
316
|
currentConfig.geminiModel = e.target.value.trim();
|
|
258
317
|
});
|
|
259
318
|
|
|
260
|
-
//
|
|
261
|
-
|
|
262
|
-
const
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
geminiOptions.style.display = 'none';
|
|
267
|
-
ollamaOptions.style.display = 'block';
|
|
319
|
+
// OpenAI model select
|
|
320
|
+
document.getElementById('openai-model-select').addEventListener('change', (e) => {
|
|
321
|
+
const customRow = document.getElementById('openai-model-custom-row');
|
|
322
|
+
if (e.target.value === 'custom') {
|
|
323
|
+
customRow.style.display = 'block';
|
|
324
|
+
currentConfig.openaiModel = (document.getElementById('openai-model-custom').value || '').trim();
|
|
268
325
|
} else {
|
|
269
|
-
|
|
270
|
-
|
|
326
|
+
customRow.style.display = 'none';
|
|
327
|
+
currentConfig.openaiModel = e.target.value;
|
|
271
328
|
}
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
document.getElementById('openai-model-custom').addEventListener('input', (e) => {
|
|
332
|
+
currentConfig.openaiModel = e.target.value.trim();
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
// Anthropic model select
|
|
336
|
+
document.getElementById('anthropic-model-select').addEventListener('change', (e) => {
|
|
337
|
+
const customRow = document.getElementById('anthropic-model-custom-row');
|
|
338
|
+
if (e.target.value === 'custom') {
|
|
339
|
+
customRow.style.display = 'block';
|
|
340
|
+
currentConfig.anthropicModel = (document.getElementById('anthropic-model-custom').value || '').trim();
|
|
341
|
+
} else {
|
|
342
|
+
customRow.style.display = 'none';
|
|
343
|
+
currentConfig.anthropicModel = e.target.value;
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
document.getElementById('anthropic-model-custom').addEventListener('input', (e) => {
|
|
348
|
+
currentConfig.anthropicModel = e.target.value.trim();
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
// AI Provider toggle (No-op since all sections stay visible)
|
|
352
|
+
function toggleProviderOptions(provider) {
|
|
353
|
+
// No-op
|
|
272
354
|
}
|
|
273
355
|
|
|
274
356
|
document.getElementById('ai-provider-select').addEventListener('change', (e) => {
|
|
275
357
|
currentConfig.aiProvider = e.target.value;
|
|
276
|
-
toggleProviderOptions(e.target.value);
|
|
277
358
|
});
|
|
278
359
|
|
|
279
360
|
document.getElementById('ollama-model-input').addEventListener('input', (e) => {
|
|
@@ -281,9 +362,12 @@ document.getElementById('ollama-model-input').addEventListener('input', (e) => {
|
|
|
281
362
|
});
|
|
282
363
|
|
|
283
364
|
// AI Studio link
|
|
284
|
-
document.getElementById('ai-studio-link')
|
|
285
|
-
|
|
286
|
-
|
|
365
|
+
const aiStudioLink = document.getElementById('ai-studio-link');
|
|
366
|
+
if (aiStudioLink) {
|
|
367
|
+
aiStudioLink.addEventListener('click', () => {
|
|
368
|
+
window.settingsApi.openExternal('https://aistudio.google.com/');
|
|
369
|
+
});
|
|
370
|
+
}
|
|
287
371
|
|
|
288
372
|
// Theme cards
|
|
289
373
|
document.querySelectorAll('.theme-card').forEach(card => {
|
|
@@ -400,9 +484,34 @@ if (document.getElementById('tts-pitch')) {
|
|
|
400
484
|
// Save
|
|
401
485
|
document.getElementById('save-btn').addEventListener('click', async () => {
|
|
402
486
|
currentConfig.apiKey = document.getElementById('api-key-input').value.trim();
|
|
487
|
+
|
|
488
|
+
const anthropicInput = document.getElementById('anthropic-api-key-input');
|
|
489
|
+
if (anthropicInput) currentConfig.anthropicApiKey = anthropicInput.value.trim();
|
|
490
|
+
|
|
491
|
+
const openaiInput = document.getElementById('openai-api-key-input');
|
|
492
|
+
if (openaiInput) currentConfig.openaiApiKey = openaiInput.value.trim();
|
|
493
|
+
|
|
494
|
+
const hfInput = document.getElementById('hf-api-key');
|
|
495
|
+
if (hfInput) currentConfig.hfApiKey = hfInput.value.trim();
|
|
496
|
+
|
|
497
|
+
const ollamaHostInput = document.getElementById('ollama-host-input');
|
|
498
|
+
if (ollamaHostInput) currentConfig.ollamaHost = ollamaHostInput.value.trim();
|
|
499
|
+
|
|
403
500
|
currentConfig.geminiModel = getSelectedModel();
|
|
404
501
|
currentConfig.aiProvider = document.getElementById('ai-provider-select').value;
|
|
405
502
|
currentConfig.ollamaModel = document.getElementById('ollama-model-input').value.trim();
|
|
503
|
+
|
|
504
|
+
currentConfig.openaiModel = getSelectedModelGeneric('openai-model-select', 'openai-model-custom', DEFAULT_CONFIG.openaiModel || 'gpt-4o');
|
|
505
|
+
currentConfig.anthropicModel = getSelectedModelGeneric('anthropic-model-select', 'anthropic-model-custom', DEFAULT_CONFIG.anthropicModel || 'claude-3-5-sonnet-latest');
|
|
506
|
+
|
|
507
|
+
const hfModelInput = document.getElementById('hf-model-name');
|
|
508
|
+
if (hfModelInput) currentConfig.hfModel = hfModelInput.value.trim();
|
|
509
|
+
|
|
510
|
+
const localApiBaseUrlInput = document.getElementById('local-api-base-url');
|
|
511
|
+
if (localApiBaseUrlInput) currentConfig.localApiBaseUrl = localApiBaseUrlInput.value.trim();
|
|
512
|
+
|
|
513
|
+
const localModelNameInput = document.getElementById('local-model-name');
|
|
514
|
+
if (localModelNameInput) currentConfig.localModelName = localModelNameInput.value.trim();
|
|
406
515
|
|
|
407
516
|
const voiceReplyToggle = document.getElementById('enable-voice-reply');
|
|
408
517
|
if (voiceReplyToggle) {
|
|
@@ -421,6 +530,11 @@ document.getElementById('save-btn').addEventListener('click', async () => {
|
|
|
421
530
|
currentConfig.enableCustomWorkflows = enableWorkflowsToggle.checked;
|
|
422
531
|
}
|
|
423
532
|
|
|
533
|
+
const enableAgentCollaborationToggle = document.getElementById('enable-agent-collaboration');
|
|
534
|
+
if (enableAgentCollaborationToggle) {
|
|
535
|
+
currentConfig.enableAgentCollaboration = enableAgentCollaborationToggle.checked;
|
|
536
|
+
}
|
|
537
|
+
|
|
424
538
|
const showWidgetToggle = document.getElementById('show-desktop-widget');
|
|
425
539
|
if (showWidgetToggle) {
|
|
426
540
|
currentConfig.showDesktopWidget = showWidgetToggle.checked;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests: agent_orchestrator.js
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const orchestrator = require('../src/AI_Brain/agent_orchestrator');
|
|
6
|
+
|
|
7
|
+
describe('Agent Orchestrator', () => {
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
orchestrator.resetAgent();
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
test('starts with general agent', () => {
|
|
13
|
+
const agent = orchestrator.getCurrentAgent();
|
|
14
|
+
expect(agent.name).toBe('Mint Default');
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('can switch to coder agent', () => {
|
|
18
|
+
orchestrator.setAgent('coder');
|
|
19
|
+
const agent = orchestrator.getCurrentAgent();
|
|
20
|
+
expect(agent.name).toBe('Mint Coder');
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test('can switch to researcher agent', () => {
|
|
24
|
+
orchestrator.setAgent('researcher');
|
|
25
|
+
const agent = orchestrator.getCurrentAgent();
|
|
26
|
+
expect(agent.name).toBe('Mint Researcher');
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test('falls back to general for invalid agent', () => {
|
|
30
|
+
orchestrator.setAgent('nonexistent');
|
|
31
|
+
const agent = orchestrator.getCurrentAgent();
|
|
32
|
+
expect(agent.name).toBe('Mint Default');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test('lists available agents', () => {
|
|
36
|
+
const agents = orchestrator.listAgents();
|
|
37
|
+
expect(agents).toContain('general');
|
|
38
|
+
expect(agents).toContain('coder');
|
|
39
|
+
expect(agents).toContain('researcher');
|
|
40
|
+
});
|
|
41
|
+
});
|