@pheem49/mint 1.8.1 → 1.9.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/Cargo.lock +3 -3
- package/Cargo.toml +1 -1
- package/README.md +0 -17
- package/Release_Note.md +137 -58
- package/bin/mint +0 -0
- package/crates/mint-cli/src/agent.rs +150 -45
- package/crates/mint-cli/src/image.rs +8 -8
- package/crates/mint-cli/src/main.rs +929 -412
- package/crates/mint-cli/src/onboard.rs +108 -108
- package/crates/mint-cli/src/setup.rs +143 -143
- package/crates/mint-core/src/agent_loop.rs +1 -0
- package/crates/mint-core/src/api_server.rs +108 -52
- package/crates/mint-core/src/browser.rs +56 -1
- package/crates/mint-core/src/channels.rs +1 -0
- package/crates/mint-core/src/chat.rs +126 -8
- package/crates/mint-core/src/code_tools.rs +18 -20
- package/crates/mint-core/src/config.rs +245 -17
- package/crates/mint-core/src/image_gen.rs +5 -5
- package/crates/mint-core/src/lib.rs +16 -2
- package/crates/mint-core/src/memory.rs +6 -1
- package/crates/mint-core/src/orchestration.rs +260 -72
- package/crates/mint-core/src/pictures.rs +3 -4
- package/crates/mint-core/src/semantic.rs +1 -1
- package/crates/mint-core/src/shell.rs +1 -1
- package/crates/mint-core/src/skills.rs +46 -19
- package/crates/mint-core/src/tts.rs +3 -1
- package/flatpak/com.pheem49.mint.desktop +9 -0
- package/flatpak/com.pheem49.mint.metainfo.xml +35 -0
- package/flatpak/com.pheem49.mint.yaml +52 -0
- package/package.json +1 -1
- package/shared-modules/.github/workflows/ci.yml +120 -0
- package/shared-modules/.github/workflows/update.yaml +28 -0
- package/shared-modules/CODEOWNERS +23 -0
- package/shared-modules/README.md +79 -0
- package/shared-modules/SDL/README.md +3 -0
- package/shared-modules/SDL/SDL-1.2.15.json +51 -0
- package/shared-modules/SDL/SDL_Pango-0.1.2-API-adds.patch +118 -0
- package/shared-modules/SDL/SDL_image-1.2.12.json +25 -0
- package/shared-modules/SDL/SDL_mixer-1.2.12.json +27 -0
- package/shared-modules/SDL/SDL_net-1.2.8.json +19 -0
- package/shared-modules/SDL/SDL_pango-0.1.2.json +26 -0
- package/shared-modules/SDL/SDL_ttf-2.0.11.json +28 -0
- package/shared-modules/SDL/libsdl-1.2.15-strict-prototypes.patch +316 -0
- package/shared-modules/SDL/sdl-check-for-SDL_VIDEO_X11_BACKINGSTORE.patch +24 -0
- package/shared-modules/SDL/sdl-libx11-build.patch +59 -0
- package/shared-modules/SDL/sdl-sysloadso-buffer-length.patch +27 -0
- package/shared-modules/SDL/sdl12-compat.json +22 -0
- package/shared-modules/SDL2/SDL2_image.json +27 -0
- package/shared-modules/SDL2/SDL2_ttf.json +29 -0
- package/shared-modules/cld2/CMakeLists.txt +157 -0
- package/shared-modules/cld2/cld2.json +24 -0
- package/shared-modules/clutter/clutter.json +72 -0
- package/shared-modules/dbus-glib/dbus-glib.json +29 -0
- package/shared-modules/glew/glew.json +36 -0
- package/shared-modules/glu/glu-9.json +12 -0
- package/shared-modules/gtk2/arc-gtk2-theme-Replace-Inkscape-dependency-with-rsvg-convert.patch +180 -0
- package/shared-modules/gtk2/gtk2-common-themes.json +360 -0
- package/shared-modules/gtk2/gtk2-fix-crash-in-show-uri.patch +30 -0
- package/shared-modules/gtk2/gtk2-gcc14.patch +281 -0
- package/shared-modules/gtk2/gtk2-gcc15.patch +250 -0
- package/shared-modules/gtk2/gtk2-murrine-c99.patch +34 -0
- package/shared-modules/gtk2/gtk2-use-adwaita-theme.patch +80 -0
- package/shared-modules/gtk2/gtk2.json +120 -0
- package/shared-modules/gtk2/ibus-gcc15.patch +13 -0
- package/shared-modules/gtk2/murrine-engine-fix-crash.patch +12 -0
- package/shared-modules/gtk2/readme.md +10 -0
- package/shared-modules/intltool/intltool-0.51.json +20 -0
- package/shared-modules/intltool/intltool-perl5.26-regex-fixes.patch +59 -0
- package/shared-modules/lame/0001-Build-xmm_quantize_sub.c-with-msse.patch +34 -0
- package/shared-modules/lame/0002-Include-GTK-1-autoconf-directives-in-build-system.patch +222 -0
- package/shared-modules/lame/0003-Patch-out-remaining-ansi2knr.patch +70 -0
- package/shared-modules/lame/0004-initscr-is-not-used-anywhere-in-lame-sourcetree.patch +41 -0
- package/shared-modules/lame/0005-Update-autoconf.patch +81 -0
- package/shared-modules/lame/lame-3.99.5.json +32 -0
- package/shared-modules/libappindicator/libappindicator-gtk2-12.10.json +140 -0
- package/shared-modules/libappindicator/libappindicator-gtk3-12.10.json +140 -0
- package/shared-modules/libappindicator/libappindicator-gtk3-introspection-12.10.json +140 -0
- package/shared-modules/libappindicator/patches/0001-libappindicator-ftbfs.patch +20 -0
- package/shared-modules/libappindicator/patches/0002-libappindicator-no-python.patch +888 -0
- package/shared-modules/libappindicator/patches/0003-libappindicator-fix-crash-from-incorrect-signal-emission.patch +74 -0
- package/shared-modules/libappindicator/patches/0004-libappindicator-fix-crash-iterating-icon-themes.patch +11 -0
- package/shared-modules/libayatana-appindicator/0001-Fix-HAVE_VALGRIND-AM_CONDITIONAL.patch +51 -0
- package/shared-modules/libayatana-appindicator/0001-Make-introspection-configurable.patch +44 -0
- package/shared-modules/libayatana-appindicator/libayatana-appindicator-gtk3.json +121 -0
- package/shared-modules/libcanberra/0001-gtk-Don-t-assume-all-GdkDisplays-are-GdkX11Displays-.patch +123 -0
- package/shared-modules/libcanberra/libcanberra.json +44 -0
- package/shared-modules/libmad/libmad.json +19 -0
- package/shared-modules/libsecret/libsecret.json +23 -0
- package/shared-modules/libsoup/libsoup-2.4.json +14 -0
- package/shared-modules/libusb/libusb.json +27 -0
- package/shared-modules/linux-audio/dssi.json +31 -0
- package/shared-modules/linux-audio/fftw3f-static.json +44 -0
- package/shared-modules/linux-audio/fftw3f.json +42 -0
- package/shared-modules/linux-audio/fluidsynth2-static.json +36 -0
- package/shared-modules/linux-audio/fluidsynth2.json +25 -0
- package/shared-modules/linux-audio/ladspa.json +26 -0
- package/shared-modules/linux-audio/lash.json +35 -0
- package/shared-modules/linux-audio/libinstpatch.json +16 -0
- package/shared-modules/linux-audio/liblo-static.json +22 -0
- package/shared-modules/linux-audio/liblo.json +17 -0
- package/shared-modules/linux-audio/lilv-static.json +94 -0
- package/shared-modules/linux-audio/lilv.json +89 -0
- package/shared-modules/linux-audio/lrdf.json +57 -0
- package/shared-modules/linux-audio/lv2.json +20 -0
- package/shared-modules/linux-audio/patches/lash/0001-configure-remove-aclocal-m4.patch +29 -0
- package/shared-modules/linux-audio/patches/lash/0002-Fix-build-with-recent-gcc.patch +73 -0
- package/shared-modules/linux-audio/patches/lash/0003-Fix-linking.patch +136 -0
- package/shared-modules/linux-audio/patches/raptor-libxml.patch +31 -0
- package/shared-modules/linux-audio/patches/stk-install.sh +54 -0
- package/shared-modules/linux-audio/stk.json +28 -0
- package/shared-modules/lua5.1/0004-Fix-stack-overflow-in-vararg-functions.patch +21 -0
- package/shared-modules/lua5.1/lua-5.1.5-so.patch +43 -0
- package/shared-modules/lua5.1/lua-5.1.5.json +42 -0
- package/shared-modules/lua5.3/lua-5.3.5.json +41 -0
- package/shared-modules/lua5.3/lua.pc.in +8 -0
- package/shared-modules/lua5.3/luaconf.patch +47 -0
- package/shared-modules/lua5.3/makefile-add-liblua.so-rule.patch +47 -0
- package/shared-modules/lua5.4/lua-5.4.json +41 -0
- package/shared-modules/lua5.4/lua.pc.in +8 -0
- package/shared-modules/lua5.4/luaconf.patch +34 -0
- package/shared-modules/lua5.4/makefile-add-liblua.so-rule.patch +42 -0
- package/shared-modules/luajit/luajit.json +30 -0
- package/shared-modules/lzo/lzo.json +27 -0
- package/shared-modules/mac/mac.json +18 -0
- package/shared-modules/physfs/physfs.json +26 -0
- package/shared-modules/pygame/audiofile-gcc6.patch +21 -0
- package/shared-modules/pygame/cython-fixes.patch +34 -0
- package/shared-modules/pygame/fluidsynth-no-rawmidi.patch +69 -0
- package/shared-modules/pygame/glib.patch +25 -0
- package/shared-modules/pygame/pygame1-python2.json +157 -0
- package/shared-modules/pygtk/pygtk-c99.patch +15 -0
- package/shared-modules/pygtk/pygtk.json +117 -0
- package/shared-modules/pygtk/pygtk.patch +39 -0
- package/shared-modules/python2.7/python-2.7.json +48 -0
- package/shared-modules/smpeg/smpeg-0.4.5.json +50 -0
- package/shared-modules/smpeg/smpeg-am-prog-as.patch +12 -0
- package/shared-modules/smpeg/smpeg-export-mpegaudio-class.patch +17 -0
- package/shared-modules/smpeg/smpeg-gcc6.patch +40 -0
- package/shared-modules/smpeg/smpeg-no-gtk.patch +37 -0
- package/shared-modules/squashfs-tools/squashfs-tools.json +25 -0
- package/shared-modules/update-checker.sh +50 -0
- package/shared-modules/vorbisgain/0001-temp_files.patch +75 -0
- package/shared-modules/vorbisgain/0002-errno.patch +33 -0
- package/shared-modules/vorbisgain/0003-manpage.patch +248 -0
- package/shared-modules/vorbisgain/0004-vorbisgain_mtime.patch +183 -0
- package/shared-modules/vorbisgain/0005-double_fclose.patch +21 -0
- package/shared-modules/vorbisgain/0006-manpage_hyphens.patch +56 -0
- package/shared-modules/vorbisgain/0007-recursively_spelling.patch +14 -0
- package/shared-modules/vorbisgain/0008-manpage_recursion_mistake.patch +23 -0
- package/shared-modules/vorbisgain/0009-hardening.patch +13 -0
- package/shared-modules/vorbisgain/0010-fclose.patch +13 -0
- package/shared-modules/vorbisgain/README.md +23 -0
- package/shared-modules/vorbisgain/vorbisgain_0.37-2.json +29 -0
- package/src/renderer/shared/agentProgress.ts +145 -0
- package/src/renderer/shared/calculator.ts +52 -0
- package/src/renderer/shared/components/AgentActivityDrawer.tsx +72 -0
- package/src/renderer/shared/components/AgentActivityTable.tsx +85 -0
- package/src/renderer/shared/components/ApprovalCard.tsx +93 -0
- package/src/renderer/shared/components/ChatCodeBlock.tsx +75 -0
- package/src/renderer/shared/components/ThinkingBlock.tsx +101 -0
- package/src/renderer/shared/constants/models.ts +91 -0
- package/src/renderer/shared/platform.ts +82 -0
- package/src/renderer/shared/types.ts +140 -0
- package/src/renderer/shared/utils/agentActivity.ts +187 -0
- package/src/renderer/shared/utils/approval.ts +1 -0
- package/src/renderer/shared/utils/approval.tsx +64 -0
- package/src/renderer/shared/utils/fileIcons.ts +135 -0
- package/src/renderer/shared/utils/markdown.tsx +347 -0
- package/src/renderer/shared/utils/providers.ts +36 -0
- package/src/renderer/shared/utils/speech.ts +216 -0
- package/src/renderer/shared/utils/ui.ts +147 -0
- package/src/renderer/src/agentProgress.ts +11 -39
- package/src/renderer/src/calculator.ts +3 -46
- package/src/renderer/src/components/ChatPanel.tsx +219 -1308
- package/src/renderer/src/components/MintDashboard.tsx +67 -170
- package/src/renderer/src/components/PicturesLibrary.tsx +32 -8
- package/src/renderer/src/components/Settings/AgentsTab.tsx +381 -0
- package/src/renderer/src/components/Settings/AutomationTab.tsx +0 -22
- package/src/renderer/src/components/Settings/GeneralTab.tsx +256 -2
- package/src/renderer/src/components/SettingsWindow.tsx +120 -3
- package/src/renderer/src/components/WorkspacePanel.tsx +7 -125
- package/src/renderer/src/css/styles.css +100 -0
- package/src/renderer/src/tauri.ts +128 -143
- package/src/renderer/src-web/agentProgress.ts +11 -39
- package/src/renderer/src-web/calculator.ts +3 -46
- package/src/renderer/src-web/components/ChatPanel.tsx +219 -1306
- package/src/renderer/src-web/components/MintDashboard.tsx +42 -170
- package/src/renderer/src-web/components/PicturesLibrary.tsx +23 -29
- package/src/renderer/src-web/components/Settings/AgentsTab.tsx +381 -0
- package/src/renderer/src-web/components/Settings/AutomationTab.tsx +0 -22
- package/src/renderer/src-web/components/Settings/GeneralTab.tsx +254 -3
- package/src/renderer/src-web/components/SettingsWindow.tsx +127 -3
- package/src/renderer/src-web/css/styles.css +100 -0
- package/src/renderer/src-web/tauri.ts +180 -102
- package/src-tauri/src/desktop.rs +18 -16
- package/src-tauri/src/discord_rpc.rs +1 -1
- package/src-tauri/src/lib.rs +168 -40
- package/src-tauri/src/webhooks.rs +1 -0
- package/src-tauri/src/workflows.rs +1 -0
- package/src-tauri/tauri.conf.json +1 -1
|
@@ -7,7 +7,10 @@ import {
|
|
|
7
7
|
DEEPSEEK_MODELS,
|
|
8
8
|
ANTHROPIC_MODELS,
|
|
9
9
|
HF_MODELS,
|
|
10
|
-
LOCAL_MODELS
|
|
10
|
+
LOCAL_MODELS,
|
|
11
|
+
CustomProviderConfig,
|
|
12
|
+
CustomProviderModel,
|
|
13
|
+
CustomProviderHeader,
|
|
11
14
|
} from '../SettingsWindow'
|
|
12
15
|
|
|
13
16
|
interface GeneralTabProps {
|
|
@@ -35,6 +38,7 @@ interface GeneralTabProps {
|
|
|
35
38
|
handleCheckUpdates: () => void
|
|
36
39
|
handleInstallUpdate: () => void
|
|
37
40
|
isDesktopApp?: boolean
|
|
41
|
+
onSaveWithoutClosing?: () => Promise<void>
|
|
38
42
|
}
|
|
39
43
|
|
|
40
44
|
export default function GeneralTab({
|
|
@@ -61,8 +65,18 @@ export default function GeneralTab({
|
|
|
61
65
|
updateMessage,
|
|
62
66
|
handleCheckUpdates,
|
|
63
67
|
handleInstallUpdate,
|
|
64
|
-
isDesktopApp = false
|
|
68
|
+
isDesktopApp = false,
|
|
69
|
+
onSaveWithoutClosing
|
|
65
70
|
}: GeneralTabProps) {
|
|
71
|
+
const [savedProviderId, setSavedProviderId] = React.useState<string | null>(null)
|
|
72
|
+
|
|
73
|
+
const handleSaveProvider = async (providerId: string) => {
|
|
74
|
+
if (onSaveWithoutClosing) {
|
|
75
|
+
await onSaveWithoutClosing()
|
|
76
|
+
setSavedProviderId(providerId)
|
|
77
|
+
setTimeout(() => setSavedProviderId(null), 2000)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
66
80
|
return (
|
|
67
81
|
<div className="tab-pane active">
|
|
68
82
|
<section className="setting-section">
|
|
@@ -86,8 +100,38 @@ export default function GeneralTab({
|
|
|
86
100
|
<option value="ollama">Ollama (Local / Private)</option>
|
|
87
101
|
<option value="huggingface">Hugging Face (Inference API)</option>
|
|
88
102
|
<option value="local_openai">Local (LM Studio / OpenAI Compatible)</option>
|
|
103
|
+
{(config.customProviders ?? []).map(cp => (
|
|
104
|
+
<option key={`custom:${cp.id}`} value={`custom:${cp.id}`}>
|
|
105
|
+
{cp.displayName || cp.id} (Custom)
|
|
106
|
+
</option>
|
|
107
|
+
))}
|
|
89
108
|
</select>
|
|
90
109
|
</div>
|
|
110
|
+
{/* Model selector for custom providers */}
|
|
111
|
+
{config.aiProvider.startsWith('custom:') && (() => {
|
|
112
|
+
const activeId = config.aiProvider.replace(/^custom:/, '')
|
|
113
|
+
const cp = (config.customProviders ?? []).find(p => p.id === activeId)
|
|
114
|
+
if (!cp || cp.models.length === 0) return null
|
|
115
|
+
const currentModel = (config.customModelSelections ?? {})[activeId] ?? cp.models[0]?.modelId ?? ''
|
|
116
|
+
return (
|
|
117
|
+
<div className="setting-row wide">
|
|
118
|
+
<label>Active Model</label>
|
|
119
|
+
<select
|
|
120
|
+
value={currentModel}
|
|
121
|
+
onChange={(e) => updateField('customModelSelections', {
|
|
122
|
+
...(config.customModelSelections ?? {}),
|
|
123
|
+
[activeId]: e.target.value
|
|
124
|
+
})}
|
|
125
|
+
>
|
|
126
|
+
{cp.models.map(m => (
|
|
127
|
+
<option key={m.modelId} value={m.modelId}>
|
|
128
|
+
{m.displayName || m.modelId}
|
|
129
|
+
</option>
|
|
130
|
+
))}
|
|
131
|
+
</select>
|
|
132
|
+
</div>
|
|
133
|
+
)
|
|
134
|
+
})()}
|
|
91
135
|
</div>
|
|
92
136
|
|
|
93
137
|
<div className="provider-cards-container">
|
|
@@ -877,12 +921,219 @@ export default function GeneralTab({
|
|
|
877
921
|
</div>
|
|
878
922
|
</section>
|
|
879
923
|
|
|
924
|
+
{/* ─── Custom Providers ─────────────────────────────────────────────────── */}
|
|
925
|
+
<section className="setting-section">
|
|
926
|
+
<div className="section-heading">
|
|
927
|
+
<div>
|
|
928
|
+
<p className="section-kicker">Custom AI Routing</p>
|
|
929
|
+
<h2 className="section-title">Custom Providers</h2>
|
|
930
|
+
</div>
|
|
931
|
+
<p className="section-description">
|
|
932
|
+
Add any OpenAI-compatible endpoint as a custom provider. Configure its models and optional headers.
|
|
933
|
+
</p>
|
|
934
|
+
</div>
|
|
935
|
+
|
|
936
|
+
<div className="provider-cards-container">
|
|
937
|
+
{(config.customProviders ?? []).map((cp, cpIdx) => {
|
|
938
|
+
const isActive = config.aiProvider === `custom:${cp.id}`
|
|
939
|
+
|
|
940
|
+
const updateCp = (patch: Partial<CustomProviderConfig>) => {
|
|
941
|
+
const updated = (config.customProviders ?? []).map((p, i) =>
|
|
942
|
+
i === cpIdx ? { ...p, ...patch } : p
|
|
943
|
+
)
|
|
944
|
+
updateField('customProviders', updated)
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
const deleteCp = () => {
|
|
948
|
+
const updated = (config.customProviders ?? []).filter((_, i) => i !== cpIdx)
|
|
949
|
+
updateField('customProviders', updated)
|
|
950
|
+
if (config.aiProvider === `custom:${cp.id}`) {
|
|
951
|
+
updateField('aiProvider', 'gemini')
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
const updateModel = (mIdx: number, patch: Partial<CustomProviderModel>) => {
|
|
956
|
+
const updatedModels = cp.models.map((m, i) => i === mIdx ? { ...m, ...patch } : m)
|
|
957
|
+
updateCp({ models: updatedModels })
|
|
958
|
+
}
|
|
959
|
+
const deleteModel = (mIdx: number) => {
|
|
960
|
+
updateCp({ models: cp.models.filter((_, i) => i !== mIdx) })
|
|
961
|
+
}
|
|
962
|
+
const addModel = () => {
|
|
963
|
+
updateCp({ models: [...cp.models, { modelId: '', displayName: '' }] })
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
const updateHeader = (hIdx: number, patch: Partial<CustomProviderHeader>) => {
|
|
967
|
+
const updatedHeaders = cp.headers.map((h, i) => i === hIdx ? { ...h, ...patch } : h)
|
|
968
|
+
updateCp({ headers: updatedHeaders })
|
|
969
|
+
}
|
|
970
|
+
const deleteHeader = (hIdx: number) => {
|
|
971
|
+
updateCp({ headers: cp.headers.filter((_, i) => i !== hIdx) })
|
|
972
|
+
}
|
|
973
|
+
const addHeader = () => {
|
|
974
|
+
updateCp({ headers: [...cp.headers, { name: '', value: '' }] })
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
return (
|
|
978
|
+
<div key={cpIdx} className={`provider-card ${isActive ? 'active-provider' : ''}`}>
|
|
979
|
+
<div className="provider-card-header">
|
|
980
|
+
<div className="provider-card-title">
|
|
981
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
|
|
982
|
+
<circle cx="12" cy="12" r="3" /><path d="M19.07 4.93a10 10 0 0 1 0 14.14M4.93 4.93a10 10 0 0 0 0 14.14" />
|
|
983
|
+
</svg>
|
|
984
|
+
{cp.displayName || cp.id || 'Unnamed Provider'}
|
|
985
|
+
</div>
|
|
986
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
|
|
987
|
+
{isActive && <span className="provider-active-badge">Active</span>}
|
|
988
|
+
<button
|
|
989
|
+
className="btn btn-primary"
|
|
990
|
+
style={{ padding: '3px 8px', fontSize: '12px', background: savedProviderId === cp.id ? '#10b981' : '' }}
|
|
991
|
+
onClick={() => handleSaveProvider(cp.id)}
|
|
992
|
+
title="Save this provider settings"
|
|
993
|
+
>
|
|
994
|
+
{savedProviderId === cp.id ? 'Saved! ✓' : 'Save'}
|
|
995
|
+
</button>
|
|
996
|
+
<button
|
|
997
|
+
className="btn btn-danger"
|
|
998
|
+
style={{ padding: '3px 8px', fontSize: '12px' }}
|
|
999
|
+
onClick={deleteCp}
|
|
1000
|
+
title="Delete this provider"
|
|
1001
|
+
>
|
|
1002
|
+
Delete
|
|
1003
|
+
</button>
|
|
1004
|
+
</div>
|
|
1005
|
+
</div>
|
|
1006
|
+
|
|
1007
|
+
<div className="provider-card-body">
|
|
1008
|
+
<div className="setting-row">
|
|
1009
|
+
<label>Name</label>
|
|
1010
|
+
<input
|
|
1011
|
+
type="text"
|
|
1012
|
+
value={cp.displayName}
|
|
1013
|
+
onChange={(e) => {
|
|
1014
|
+
const name = e.target.value
|
|
1015
|
+
const computedId = name
|
|
1016
|
+
.toLowerCase()
|
|
1017
|
+
.replace(/[^a-z0-9_-]/g, '-')
|
|
1018
|
+
.replace(/-+/g, '-')
|
|
1019
|
+
.replace(/^-|-$/g, '') || `provider-${cpIdx + 1}`
|
|
1020
|
+
updateCp({ displayName: name, id: computedId })
|
|
1021
|
+
}}
|
|
1022
|
+
placeholder="e.g. DeepSeek"
|
|
1023
|
+
/>
|
|
1024
|
+
</div>
|
|
1025
|
+
|
|
1026
|
+
<div className="setting-row">
|
|
1027
|
+
<label>Base URL</label>
|
|
1028
|
+
<input
|
|
1029
|
+
type="text"
|
|
1030
|
+
value={cp.baseUrl}
|
|
1031
|
+
onChange={(e) => updateCp({ baseUrl: e.target.value })}
|
|
1032
|
+
placeholder="https://api.myprovider.com/v1"
|
|
1033
|
+
/>
|
|
1034
|
+
</div>
|
|
1035
|
+
|
|
1036
|
+
<div className="setting-row">
|
|
1037
|
+
<label>API Key</label>
|
|
1038
|
+
<input
|
|
1039
|
+
type="password"
|
|
1040
|
+
value={cp.apiKey}
|
|
1041
|
+
onChange={(e) => updateCp({ apiKey: e.target.value })}
|
|
1042
|
+
placeholder="Optional. Leave empty if you manage auth via headers."
|
|
1043
|
+
/>
|
|
1044
|
+
</div>
|
|
1045
|
+
|
|
1046
|
+
{/* Models */}
|
|
1047
|
+
<div style={{ marginTop: '12px' }}>
|
|
1048
|
+
<label style={{ fontWeight: 600, fontSize: '13px', display: 'block', marginBottom: '8px' }}>Model list</label>
|
|
1049
|
+
{cp.models.map((m, mIdx) => (
|
|
1050
|
+
<div key={mIdx} style={{ display: 'flex', gap: '8px', marginBottom: '6px', alignItems: 'center' }}>
|
|
1051
|
+
<input
|
|
1052
|
+
type="text"
|
|
1053
|
+
value={m.modelId}
|
|
1054
|
+
onChange={(e) => updateModel(mIdx, { modelId: e.target.value, displayName: e.target.value })}
|
|
1055
|
+
placeholder="e.g. llama-3.1-8b"
|
|
1056
|
+
style={{ flex: 1 }}
|
|
1057
|
+
/>
|
|
1058
|
+
<button
|
|
1059
|
+
className="btn btn-danger"
|
|
1060
|
+
style={{ padding: '4px 8px', fontSize: '12px', flexShrink: 0 }}
|
|
1061
|
+
onClick={() => deleteModel(mIdx)}
|
|
1062
|
+
title="Remove model"
|
|
1063
|
+
>🗑</button>
|
|
1064
|
+
</div>
|
|
1065
|
+
))}
|
|
1066
|
+
<button
|
|
1067
|
+
className="btn btn-secondary"
|
|
1068
|
+
style={{ fontSize: '12px', marginTop: '4px' }}
|
|
1069
|
+
onClick={addModel}
|
|
1070
|
+
>
|
|
1071
|
+
+ Add model
|
|
1072
|
+
</button>
|
|
1073
|
+
</div>
|
|
1074
|
+
|
|
1075
|
+
{/* Headers */}
|
|
1076
|
+
<div style={{ marginTop: '12px' }}>
|
|
1077
|
+
<label style={{ fontWeight: 600, fontSize: '13px', display: 'block', marginBottom: '8px' }}>Headers (optional)</label>
|
|
1078
|
+
{cp.headers.map((h, hIdx) => (
|
|
1079
|
+
<div key={hIdx} style={{ display: 'flex', gap: '8px', marginBottom: '6px', alignItems: 'center' }}>
|
|
1080
|
+
<input
|
|
1081
|
+
type="text"
|
|
1082
|
+
value={h.name}
|
|
1083
|
+
onChange={(e) => updateHeader(hIdx, { name: e.target.value })}
|
|
1084
|
+
placeholder="Header-Name"
|
|
1085
|
+
style={{ flex: 1 }}
|
|
1086
|
+
/>
|
|
1087
|
+
<input
|
|
1088
|
+
type="text"
|
|
1089
|
+
value={h.value}
|
|
1090
|
+
onChange={(e) => updateHeader(hIdx, { value: e.target.value })}
|
|
1091
|
+
placeholder="value"
|
|
1092
|
+
style={{ flex: 1 }}
|
|
1093
|
+
/>
|
|
1094
|
+
<button
|
|
1095
|
+
className="btn btn-danger"
|
|
1096
|
+
style={{ padding: '4px 8px', fontSize: '12px', flexShrink: 0 }}
|
|
1097
|
+
onClick={() => deleteHeader(hIdx)}
|
|
1098
|
+
title="Remove header"
|
|
1099
|
+
>🗑</button>
|
|
1100
|
+
</div>
|
|
1101
|
+
))}
|
|
1102
|
+
<button
|
|
1103
|
+
className="btn btn-secondary"
|
|
1104
|
+
style={{ fontSize: '12px', marginTop: '4px' }}
|
|
1105
|
+
onClick={addHeader}
|
|
1106
|
+
>
|
|
1107
|
+
+ Add header
|
|
1108
|
+
</button>
|
|
1109
|
+
</div>
|
|
1110
|
+
</div>
|
|
1111
|
+
</div>
|
|
1112
|
+
)
|
|
1113
|
+
})}
|
|
1114
|
+
</div>
|
|
1115
|
+
|
|
1116
|
+
<div className="setting-actions" style={{ marginTop: '16px' }}>
|
|
1117
|
+
<button
|
|
1118
|
+
className="btn btn-secondary"
|
|
1119
|
+
onClick={() => {
|
|
1120
|
+
const newId = `provider-${(config.customProviders ?? []).length + 1}`
|
|
1121
|
+
updateField('customProviders', [
|
|
1122
|
+
...(config.customProviders ?? []),
|
|
1123
|
+
{ id: newId, displayName: '', baseUrl: '', apiKey: '', models: [], headers: [] }
|
|
1124
|
+
])
|
|
1125
|
+
}}
|
|
1126
|
+
>
|
|
1127
|
+
+ Add custom provider
|
|
1128
|
+
</button>
|
|
1129
|
+
</div>
|
|
1130
|
+
</section>
|
|
1131
|
+
|
|
880
1132
|
{isDesktopApp && (
|
|
881
1133
|
<section className="setting-section">
|
|
882
1134
|
<div className="section-heading">
|
|
883
1135
|
<div>
|
|
884
1136
|
<p className="section-kicker">Desktop updates</p>
|
|
885
|
-
|
|
886
1137
|
<h2 className="section-title">Signed Tauri Channel</h2>
|
|
887
1138
|
</div>
|
|
888
1139
|
<p className="section-description">Check and explicitly install signed Tauri releases from your configured update channel.</p>
|
|
@@ -6,6 +6,28 @@ import AudioTab from './Settings/AudioTab'
|
|
|
6
6
|
import AutomationTab from './Settings/AutomationTab'
|
|
7
7
|
import ThemeTab from './Settings/ThemeTab'
|
|
8
8
|
import PluginsTab from './Settings/PluginsTab'
|
|
9
|
+
import AgentsTab from './Settings/AgentsTab'
|
|
10
|
+
|
|
11
|
+
// ─── Custom Provider Types ────────────────────────────────────────────────────
|
|
12
|
+
|
|
13
|
+
export interface CustomProviderModel {
|
|
14
|
+
modelId: string
|
|
15
|
+
displayName: string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface CustomProviderHeader {
|
|
19
|
+
name: string
|
|
20
|
+
value: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface CustomProviderConfig {
|
|
24
|
+
id: string
|
|
25
|
+
displayName: string
|
|
26
|
+
baseUrl: string
|
|
27
|
+
apiKey: string
|
|
28
|
+
models: CustomProviderModel[]
|
|
29
|
+
headers: CustomProviderHeader[]
|
|
30
|
+
}
|
|
9
31
|
|
|
10
32
|
export const DEFAULT_CONFIG = {
|
|
11
33
|
theme: 'dark',
|
|
@@ -30,7 +52,7 @@ export const DEFAULT_CONFIG = {
|
|
|
30
52
|
proactiveCooldown: 120,
|
|
31
53
|
enableVoiceReply: true,
|
|
32
54
|
enableCustomWorkflows: true,
|
|
33
|
-
enableAgentCollaboration:
|
|
55
|
+
enableAgentCollaboration: false,
|
|
34
56
|
ttsProvider: 'google',
|
|
35
57
|
ttsVolume: 1.0,
|
|
36
58
|
ttsSpeed: 1.0,
|
|
@@ -91,10 +113,44 @@ export const DEFAULT_CONFIG = {
|
|
|
91
113
|
imageGenProvider: 'gemini' as 'gemini' | 'dalle' | 'stability' | 'ideogram' | 'replicate',
|
|
92
114
|
stabilityApiKey: '',
|
|
93
115
|
ideogramApiKey: '',
|
|
94
|
-
replicateApiKey: ''
|
|
116
|
+
replicateApiKey: '',
|
|
117
|
+
// Multi-Agent Configuration
|
|
118
|
+
agents: [
|
|
119
|
+
{
|
|
120
|
+
id: 'planner',
|
|
121
|
+
name: 'Planner',
|
|
122
|
+
provider: 'gemini',
|
|
123
|
+
model: 'gemini-2.5-flash',
|
|
124
|
+
apiKey: '',
|
|
125
|
+
systemInstruction: 'You are the Planner agent. Your task is to analyze the user request, inspect the workspace structure, and design a step-by-step implementation plan. Create or update the implementation_plan.md file to document your proposal.',
|
|
126
|
+
enabled: true
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
id: 'coder',
|
|
130
|
+
name: 'Coder',
|
|
131
|
+
provider: 'gemini',
|
|
132
|
+
model: 'gemini-2.5-flash',
|
|
133
|
+
apiKey: '',
|
|
134
|
+
systemInstruction: 'You are the Coder agent. Your task is to implement the changes specified in the approved implementation plan. Read relevant files, write clean and efficient code, and run terminal commands to build or verify. Stay focused on execution.',
|
|
135
|
+
enabled: true
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
id: 'reviewer',
|
|
139
|
+
name: 'Reviewer',
|
|
140
|
+
provider: 'gemini',
|
|
141
|
+
model: 'gemini-2.5-flash',
|
|
142
|
+
apiKey: '',
|
|
143
|
+
systemInstruction: 'You are the Reviewer agent. Your task is to verify the code modifications made by the Coder. Run the automated tests, check lint errors, and ensure the implementation is correct and complete.',
|
|
144
|
+
enabled: true
|
|
145
|
+
}
|
|
146
|
+
],
|
|
147
|
+
// Custom Providers
|
|
148
|
+
customProviders: [] as CustomProviderConfig[],
|
|
149
|
+
// Per-provider model selection: { [providerId]: selectedModelId }
|
|
150
|
+
customModelSelections: {} as Record<string, string>,
|
|
95
151
|
}
|
|
96
152
|
|
|
97
|
-
type TabType = 'sect-general' | 'sect-audio' | 'sect-automation' | 'sect-theme' | 'sect-plugins' | 'sect-shortcuts' | 'sect-memory'
|
|
153
|
+
type TabType = 'sect-general' | 'sect-audio' | 'sect-automation' | 'sect-theme' | 'sect-plugins' | 'sect-shortcuts' | 'sect-memory' | 'sect-agents'
|
|
98
154
|
|
|
99
155
|
export const GEMINI_MODELS = [
|
|
100
156
|
'gemini-2.5-flash',
|
|
@@ -379,6 +435,54 @@ export default function SettingsWindow() {
|
|
|
379
435
|
}
|
|
380
436
|
}
|
|
381
437
|
|
|
438
|
+
const handleSaveWithoutClosing = async () => {
|
|
439
|
+
const finalConfig = { ...config }
|
|
440
|
+
|
|
441
|
+
if (config.geminiModel === 'custom') {
|
|
442
|
+
finalConfig.geminiModel = customGemini || 'gemini-2.5-flash'
|
|
443
|
+
}
|
|
444
|
+
if (config.openaiModel === 'custom') {
|
|
445
|
+
finalConfig.openaiModel = customOpenAI || 'gpt-4o'
|
|
446
|
+
}
|
|
447
|
+
if (config.openrouterModel === 'custom') {
|
|
448
|
+
finalConfig.openrouterModel = customOpenRouter || 'openai/gpt-4o-mini'
|
|
449
|
+
}
|
|
450
|
+
if (config.deepseekModel === 'custom') {
|
|
451
|
+
finalConfig.deepseekModel = customDeepSeek || 'deepseek-v4-flash'
|
|
452
|
+
}
|
|
453
|
+
if (config.anthropicModel === 'custom') {
|
|
454
|
+
finalConfig.anthropicModel = customAnthropic || 'claude-3-5-sonnet-latest'
|
|
455
|
+
}
|
|
456
|
+
if (config.hfModel === 'custom') {
|
|
457
|
+
finalConfig.hfModel = customHF || 'meta-llama/Meta-Llama-3-8B-Instruct'
|
|
458
|
+
}
|
|
459
|
+
if (config.localModelName === 'custom') {
|
|
460
|
+
finalConfig.localModelName = customLocal || 'local-model'
|
|
461
|
+
}
|
|
462
|
+
if (config.ollamaModel === 'custom') {
|
|
463
|
+
finalConfig.ollamaModel = customOllama || 'llama3:latest'
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
try {
|
|
467
|
+
await setProfileValue('name', userName)
|
|
468
|
+
await setProfileValue('preferences', userPreferences)
|
|
469
|
+
} catch (e) {
|
|
470
|
+
console.error("Failed to save user profile memory:", e)
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
if (window.settingsApi) {
|
|
474
|
+
await window.settingsApi.saveSettings(finalConfig)
|
|
475
|
+
applyThemeStyles(finalConfig)
|
|
476
|
+
} else {
|
|
477
|
+
try {
|
|
478
|
+
await setProfileValue('user-settings', JSON.stringify(finalConfig))
|
|
479
|
+
applyThemeStyles(finalConfig)
|
|
480
|
+
} catch (e) {
|
|
481
|
+
console.error("Failed to save user settings:", e)
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
382
486
|
const handleReset = async () => {
|
|
383
487
|
if (confirm('Reset all settings to default?')) {
|
|
384
488
|
setConfig(DEFAULT_CONFIG)
|
|
@@ -616,6 +720,17 @@ export default function SettingsWindow() {
|
|
|
616
720
|
</span>
|
|
617
721
|
<strong>Plugins</strong>
|
|
618
722
|
</button>
|
|
723
|
+
<button className={`tab-btn ${activeTab === 'sect-agents' ? 'active' : ''}`} onClick={() => setActiveTab('sect-agents')}>
|
|
724
|
+
<span style={{ display: 'inline-flex', alignItems: 'center' }}>
|
|
725
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
|
|
726
|
+
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path>
|
|
727
|
+
<circle cx="9" cy="7" r="4"></circle>
|
|
728
|
+
<path d="M23 21v-2a4 4 0 0 0-3-3.87"></path>
|
|
729
|
+
<path d="M16 3.13a4 4 0 0 1 0 7.75"></path>
|
|
730
|
+
</svg>
|
|
731
|
+
</span>
|
|
732
|
+
<strong>Multi-Agent (Beta)</strong>
|
|
733
|
+
</button>
|
|
619
734
|
</nav>
|
|
620
735
|
|
|
621
736
|
<div className="settings-content">
|
|
@@ -652,6 +767,7 @@ export default function SettingsWindow() {
|
|
|
652
767
|
handleCheckUpdates={handleCheckUpdates}
|
|
653
768
|
handleInstallUpdate={handleInstallUpdate}
|
|
654
769
|
isDesktopApp={isDesktopApp}
|
|
770
|
+
onSaveWithoutClosing={handleSaveWithoutClosing}
|
|
655
771
|
/>
|
|
656
772
|
)}
|
|
657
773
|
|
|
@@ -705,6 +821,14 @@ export default function SettingsWindow() {
|
|
|
705
821
|
handleConnectPlugin={handleConnectPlugin}
|
|
706
822
|
/>
|
|
707
823
|
)}
|
|
824
|
+
|
|
825
|
+
{activeTab === 'sect-agents' && (
|
|
826
|
+
<AgentsTab
|
|
827
|
+
config={config}
|
|
828
|
+
updateField={updateField}
|
|
829
|
+
dynamicOllamaModels={dynamicOllamaModels}
|
|
830
|
+
/>
|
|
831
|
+
)}
|
|
708
832
|
</div>
|
|
709
833
|
</main>
|
|
710
834
|
|
|
@@ -1683,12 +1683,28 @@ h1 {
|
|
|
1683
1683
|
width: 15px;
|
|
1684
1684
|
}
|
|
1685
1685
|
|
|
1686
|
+
.agent-activity-icon[data-has-img="true"]::before,
|
|
1687
|
+
.agent-activity-icon[data-has-img="true"]::after {
|
|
1688
|
+
display: none !important;
|
|
1689
|
+
}
|
|
1690
|
+
|
|
1691
|
+
.agent-activity-icon img {
|
|
1692
|
+
width: 14px;
|
|
1693
|
+
height: 14px;
|
|
1694
|
+
display: block;
|
|
1695
|
+
object-fit: contain;
|
|
1696
|
+
filter: drop-shadow(0 1px 0 rgba(0, 0, 0, 0.12));
|
|
1697
|
+
pointer-events: none;
|
|
1698
|
+
user-select: none;
|
|
1699
|
+
}
|
|
1700
|
+
|
|
1686
1701
|
.agent-activity-icon::before,
|
|
1687
1702
|
.agent-activity-icon::after {
|
|
1688
1703
|
content: "";
|
|
1689
1704
|
position: absolute;
|
|
1690
1705
|
}
|
|
1691
1706
|
|
|
1707
|
+
|
|
1692
1708
|
.agent-activity-item[data-kind="folder"] .agent-activity-icon::before {
|
|
1693
1709
|
background: var(--text-muted);
|
|
1694
1710
|
border-radius: 2px 2px 1px 1px;
|
|
@@ -4167,3 +4183,87 @@ input:checked + .slider:before {
|
|
|
4167
4183
|
-ms-user-select: text !important;
|
|
4168
4184
|
}
|
|
4169
4185
|
|
|
4186
|
+
/* Stop button styling overrides for ChatPanel */
|
|
4187
|
+
#send-btn.stop-btn {
|
|
4188
|
+
background: #ef4444 !important;
|
|
4189
|
+
color: #ffffff !important;
|
|
4190
|
+
box-shadow: 0 8px 18px rgba(239, 68, 68, 0.28) !important;
|
|
4191
|
+
}
|
|
4192
|
+
|
|
4193
|
+
#send-btn.stop-btn:hover {
|
|
4194
|
+
background: #dc2626 !important;
|
|
4195
|
+
}
|
|
4196
|
+
|
|
4197
|
+
/* Breathing voice-active aura glow */
|
|
4198
|
+
@keyframes aura-breathe-form {
|
|
4199
|
+
0% {
|
|
4200
|
+
box-shadow: 0 4px 15px color-mix(in srgb, var(--accent) 22%, transparent);
|
|
4201
|
+
}
|
|
4202
|
+
50% {
|
|
4203
|
+
box-shadow: 0 4px 25px color-mix(in srgb, var(--accent) 42%, transparent);
|
|
4204
|
+
}
|
|
4205
|
+
100% {
|
|
4206
|
+
box-shadow: 0 4px 15px color-mix(in srgb, var(--accent) 22%, transparent);
|
|
4207
|
+
}
|
|
4208
|
+
}
|
|
4209
|
+
|
|
4210
|
+
@keyframes aura-breathe-bar {
|
|
4211
|
+
0% {
|
|
4212
|
+
box-shadow: 0 -4px 15px color-mix(in srgb, var(--accent) 22%, transparent);
|
|
4213
|
+
}
|
|
4214
|
+
50% {
|
|
4215
|
+
box-shadow: 0 -4px 25px color-mix(in srgb, var(--accent) 42%, transparent);
|
|
4216
|
+
}
|
|
4217
|
+
100% {
|
|
4218
|
+
box-shadow: 0 -4px 15px color-mix(in srgb, var(--accent) 22%, transparent);
|
|
4219
|
+
}
|
|
4220
|
+
}
|
|
4221
|
+
|
|
4222
|
+
.input-area.voice-active #chat-form {
|
|
4223
|
+
border-color: var(--accent) !important;
|
|
4224
|
+
animation: aura-breathe-form 2s infinite ease-in-out;
|
|
4225
|
+
transition: border-color 0.3s ease;
|
|
4226
|
+
}
|
|
4227
|
+
|
|
4228
|
+
.input-area.voice-active .voice-mode-bar {
|
|
4229
|
+
border-color: var(--accent) !important;
|
|
4230
|
+
animation: aura-breathe-bar 2s infinite ease-in-out;
|
|
4231
|
+
transition: border-color 0.3s ease;
|
|
4232
|
+
}
|
|
4233
|
+
|
|
4234
|
+
/* Saved Pictures Gallery Load More styles */
|
|
4235
|
+
.pictures-load-more-container {
|
|
4236
|
+
display: flex;
|
|
4237
|
+
justify-content: center;
|
|
4238
|
+
margin-top: 36px;
|
|
4239
|
+
margin-bottom: 24px;
|
|
4240
|
+
}
|
|
4241
|
+
|
|
4242
|
+
.pictures-load-more-btn {
|
|
4243
|
+
height: 40px;
|
|
4244
|
+
padding: 0 24px;
|
|
4245
|
+
border: 1px solid var(--border);
|
|
4246
|
+
border-radius: 10px;
|
|
4247
|
+
background: var(--card-bg, rgba(255, 255, 255, 0.04));
|
|
4248
|
+
color: var(--text-main);
|
|
4249
|
+
font-size: 0.88rem;
|
|
4250
|
+
font-weight: 500;
|
|
4251
|
+
cursor: pointer;
|
|
4252
|
+
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
|
4253
|
+
display: flex;
|
|
4254
|
+
align-items: center;
|
|
4255
|
+
gap: 8px;
|
|
4256
|
+
}
|
|
4257
|
+
|
|
4258
|
+
.pictures-load-more-btn:hover {
|
|
4259
|
+
background: var(--border);
|
|
4260
|
+
border-color: var(--accent);
|
|
4261
|
+
color: var(--accent);
|
|
4262
|
+
box-shadow: 0 0 12px color-mix(in srgb, var(--accent) 20%, transparent);
|
|
4263
|
+
}
|
|
4264
|
+
|
|
4265
|
+
.pictures-load-more-btn:active {
|
|
4266
|
+
transform: scale(0.98);
|
|
4267
|
+
}
|
|
4268
|
+
|
|
4269
|
+
|