@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
|
@@ -79,10 +79,65 @@ pub struct MintConfig {
|
|
|
79
79
|
pub blocked_paths: Vec<PathBuf>,
|
|
80
80
|
pub blocked_file_names: Vec<String>,
|
|
81
81
|
pub disabled_tools: Vec<String>,
|
|
82
|
+
pub agents: Vec<AgentConfig>,
|
|
83
|
+
pub enable_agent_collaboration: bool,
|
|
84
|
+
/// User-defined OpenAI-compatible providers.
|
|
85
|
+
pub custom_providers: Vec<CustomProvider>,
|
|
82
86
|
#[serde(flatten)]
|
|
83
87
|
pub extra: BTreeMap<String, Value>,
|
|
84
88
|
}
|
|
85
89
|
|
|
90
|
+
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
|
|
91
|
+
#[serde(rename_all = "camelCase")]
|
|
92
|
+
pub struct AgentConfig {
|
|
93
|
+
pub id: String,
|
|
94
|
+
pub name: String,
|
|
95
|
+
pub provider: String,
|
|
96
|
+
pub model: String,
|
|
97
|
+
pub api_key: Option<String>,
|
|
98
|
+
pub system_instruction: String,
|
|
99
|
+
pub enabled: bool,
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/// A single model entry inside a [`CustomProvider`].
|
|
103
|
+
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
|
|
104
|
+
#[serde(rename_all = "camelCase")]
|
|
105
|
+
pub struct CustomProviderModel {
|
|
106
|
+
/// The model identifier sent to the API, e.g. `"llama-3.1-8b"`.
|
|
107
|
+
pub model_id: String,
|
|
108
|
+
/// Human-readable label shown in the UI, e.g. `"Llama 3.1 8B"`.
|
|
109
|
+
pub display_name: String,
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/// An extra HTTP header to include with every request to a [`CustomProvider`].
|
|
113
|
+
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
|
|
114
|
+
#[serde(rename_all = "camelCase")]
|
|
115
|
+
pub struct CustomProviderHeader {
|
|
116
|
+
pub name: String,
|
|
117
|
+
pub value: String,
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/// A fully user-defined, OpenAI-compatible AI provider.
|
|
121
|
+
///
|
|
122
|
+
/// When this provider is active the `ai_provider` config field is set to
|
|
123
|
+
/// `"custom:<id>"` where `<id>` is [`CustomProvider::id`].
|
|
124
|
+
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
|
|
125
|
+
#[serde(rename_all = "camelCase")]
|
|
126
|
+
pub struct CustomProvider {
|
|
127
|
+
/// Slug identifier (lowercase letters, numbers, hyphens, underscores).
|
|
128
|
+
pub id: String,
|
|
129
|
+
/// Human-readable name shown in the UI.
|
|
130
|
+
pub display_name: String,
|
|
131
|
+
/// Base URL of the OpenAI-compatible endpoint, e.g. `"http://localhost:20128/v1"`.
|
|
132
|
+
pub base_url: String,
|
|
133
|
+
/// API key sent as `Authorization: Bearer <key>`. Empty = no auth header.
|
|
134
|
+
pub api_key: String,
|
|
135
|
+
/// Models offered by this provider.
|
|
136
|
+
pub models: Vec<CustomProviderModel>,
|
|
137
|
+
/// Optional extra HTTP headers sent with every request.
|
|
138
|
+
pub headers: Vec<CustomProviderHeader>,
|
|
139
|
+
}
|
|
140
|
+
|
|
86
141
|
impl Default for MintConfig {
|
|
87
142
|
fn default() -> Self {
|
|
88
143
|
let home = dirs::home_dir().unwrap_or_else(|| PathBuf::from("."));
|
|
@@ -142,36 +197,106 @@ impl Default for MintConfig {
|
|
|
142
197
|
],
|
|
143
198
|
blocked_file_names: vec![".env".into(), "id_rsa".into(), "id_ed25519".into()],
|
|
144
199
|
disabled_tools: Vec::new(),
|
|
200
|
+
agents: default_agents(),
|
|
201
|
+
enable_agent_collaboration: false,
|
|
202
|
+
custom_providers: Vec::new(),
|
|
145
203
|
extra: runtime_extra_defaults(),
|
|
146
204
|
}
|
|
147
205
|
}
|
|
148
206
|
}
|
|
149
207
|
|
|
208
|
+
fn default_agents() -> Vec<AgentConfig> {
|
|
209
|
+
vec![
|
|
210
|
+
AgentConfig {
|
|
211
|
+
id: "planner".into(),
|
|
212
|
+
name: "Planner".into(),
|
|
213
|
+
provider: "gemini".into(),
|
|
214
|
+
model: "gemini-2.5-flash".into(),
|
|
215
|
+
api_key: None,
|
|
216
|
+
system_instruction: "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.".into(),
|
|
217
|
+
enabled: true,
|
|
218
|
+
},
|
|
219
|
+
AgentConfig {
|
|
220
|
+
id: "coder".into(),
|
|
221
|
+
name: "Coder".into(),
|
|
222
|
+
provider: "gemini".into(),
|
|
223
|
+
model: "gemini-2.5-flash".into(),
|
|
224
|
+
api_key: None,
|
|
225
|
+
system_instruction: "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.".into(),
|
|
226
|
+
enabled: true,
|
|
227
|
+
},
|
|
228
|
+
AgentConfig {
|
|
229
|
+
id: "reviewer".into(),
|
|
230
|
+
name: "Reviewer".into(),
|
|
231
|
+
provider: "gemini".into(),
|
|
232
|
+
model: "gemini-2.5-flash".into(),
|
|
233
|
+
api_key: None,
|
|
234
|
+
system_instruction: "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.".into(),
|
|
235
|
+
enabled: true,
|
|
236
|
+
},
|
|
237
|
+
]
|
|
238
|
+
}
|
|
239
|
+
|
|
150
240
|
impl MintConfig {
|
|
151
|
-
pub fn
|
|
241
|
+
pub fn active_model(&self) -> &str {
|
|
242
|
+
match self.ai_provider.as_str() {
|
|
243
|
+
"anthropic" => &self.anthropic_model,
|
|
244
|
+
"openai" => &self.openai_model,
|
|
245
|
+
"openrouter" => &self.openrouter_model,
|
|
246
|
+
"deepseek" => &self.deepseek_model,
|
|
247
|
+
"huggingface" => &self.hf_model,
|
|
248
|
+
"local_openai" => &self.local_model_name,
|
|
249
|
+
"ollama" => &self.ollama_model,
|
|
250
|
+
p if p.starts_with("custom:") => {
|
|
251
|
+
// Return the first model id of the matching custom provider, if any.
|
|
252
|
+
self.resolve_custom_provider(p)
|
|
253
|
+
.and_then(|cp| cp.models.first())
|
|
254
|
+
.map(|m| m.model_id.as_str())
|
|
255
|
+
.unwrap_or("")
|
|
256
|
+
}
|
|
257
|
+
_ => &self.gemini_model,
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/// Returns the `CustomProvider` whose id matches `provider_key`.
|
|
262
|
+
///
|
|
263
|
+
/// `provider_key` must be in `"custom:<id>"` format (the leading `"custom:"`
|
|
264
|
+
/// prefix is stripped before the lookup).
|
|
265
|
+
pub fn resolve_custom_provider(&self, provider_key: &str) -> Option<&CustomProvider> {
|
|
266
|
+
let id = provider_key.strip_prefix("custom:").unwrap_or(provider_key);
|
|
267
|
+
self.custom_providers.iter().find(|cp| cp.id == id)
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
pub fn available_providers(&self) -> Vec<String> {
|
|
152
271
|
let mut providers = Vec::new();
|
|
153
272
|
if has_value(&self.anthropic_api_key) {
|
|
154
|
-
providers.push("anthropic");
|
|
273
|
+
providers.push("anthropic".to_owned());
|
|
155
274
|
}
|
|
156
275
|
if has_value(&self.openai_api_key) {
|
|
157
|
-
providers.push("openai");
|
|
276
|
+
providers.push("openai".to_owned());
|
|
158
277
|
}
|
|
159
278
|
if has_value(&self.openrouter_api_key) {
|
|
160
|
-
providers.push("openrouter");
|
|
279
|
+
providers.push("openrouter".to_owned());
|
|
161
280
|
}
|
|
162
281
|
if has_value(&self.deepseek_api_key) {
|
|
163
|
-
providers.push("deepseek");
|
|
282
|
+
providers.push("deepseek".to_owned());
|
|
164
283
|
}
|
|
165
284
|
if has_value(&self.api_key) {
|
|
166
|
-
providers.push("gemini");
|
|
285
|
+
providers.push("gemini".to_owned());
|
|
167
286
|
}
|
|
168
287
|
if has_value(&self.hf_api_key) {
|
|
169
|
-
providers.push("huggingface");
|
|
288
|
+
providers.push("huggingface".to_owned());
|
|
170
289
|
}
|
|
171
290
|
if has_value(&self.local_api_base_url) {
|
|
172
|
-
providers.push("local_openai");
|
|
291
|
+
providers.push("local_openai".to_owned());
|
|
292
|
+
}
|
|
293
|
+
providers.push("ollama".to_owned());
|
|
294
|
+
// Include all user-defined custom providers that have a base URL configured.
|
|
295
|
+
for cp in &self.custom_providers {
|
|
296
|
+
if !cp.base_url.trim().is_empty() {
|
|
297
|
+
providers.push(format!("custom:{}", cp.id));
|
|
298
|
+
}
|
|
173
299
|
}
|
|
174
|
-
providers.push("ollama");
|
|
175
300
|
providers
|
|
176
301
|
}
|
|
177
302
|
}
|
|
@@ -377,7 +502,10 @@ mod tests {
|
|
|
377
502
|
|
|
378
503
|
#[test]
|
|
379
504
|
fn default_config_always_exposes_ollama() {
|
|
380
|
-
assert_eq!(
|
|
505
|
+
assert_eq!(
|
|
506
|
+
MintConfig::default().available_providers(),
|
|
507
|
+
vec!["ollama".to_owned()]
|
|
508
|
+
);
|
|
381
509
|
}
|
|
382
510
|
|
|
383
511
|
#[test]
|
|
@@ -393,12 +521,12 @@ mod tests {
|
|
|
393
521
|
assert_eq!(
|
|
394
522
|
config.available_providers(),
|
|
395
523
|
vec![
|
|
396
|
-
"openai",
|
|
397
|
-
"openrouter",
|
|
398
|
-
"deepseek",
|
|
399
|
-
"gemini",
|
|
400
|
-
"local_openai",
|
|
401
|
-
"ollama"
|
|
524
|
+
"openai".to_owned(),
|
|
525
|
+
"openrouter".to_owned(),
|
|
526
|
+
"deepseek".to_owned(),
|
|
527
|
+
"gemini".to_owned(),
|
|
528
|
+
"local_openai".to_owned(),
|
|
529
|
+
"ollama".to_owned(),
|
|
402
530
|
]
|
|
403
531
|
);
|
|
404
532
|
}
|
|
@@ -448,8 +576,108 @@ mod tests {
|
|
|
448
576
|
save_config_to(&path, &initial_config).unwrap();
|
|
449
577
|
|
|
450
578
|
let loaded = load_config_from(&path).unwrap();
|
|
451
|
-
assert!(loaded.theme.
|
|
579
|
+
assert!(!loaded.theme.is_empty());
|
|
452
580
|
|
|
453
581
|
let _ = std::fs::remove_file(&path);
|
|
454
582
|
}
|
|
583
|
+
|
|
584
|
+
#[test]
|
|
585
|
+
fn custom_provider_round_trips() {
|
|
586
|
+
let config = MintConfig {
|
|
587
|
+
custom_providers: vec![CustomProvider {
|
|
588
|
+
id: "myprovider".into(),
|
|
589
|
+
display_name: "My Provider".into(),
|
|
590
|
+
base_url: "http://localhost:20128/v1".into(),
|
|
591
|
+
api_key: "sk-abc".into(),
|
|
592
|
+
models: vec![CustomProviderModel {
|
|
593
|
+
model_id: "llama-3.1-8b".into(),
|
|
594
|
+
display_name: "Llama 3.1 8B".into(),
|
|
595
|
+
}],
|
|
596
|
+
headers: vec![CustomProviderHeader {
|
|
597
|
+
name: "X-Custom".into(),
|
|
598
|
+
value: "test".into(),
|
|
599
|
+
}],
|
|
600
|
+
}],
|
|
601
|
+
..MintConfig::default()
|
|
602
|
+
};
|
|
603
|
+
let json = serde_json::to_string(&config).unwrap();
|
|
604
|
+
let restored: MintConfig = serde_json::from_str(&json).unwrap();
|
|
605
|
+
assert_eq!(restored, config);
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
#[test]
|
|
609
|
+
fn custom_provider_appears_in_available_providers() {
|
|
610
|
+
let config = MintConfig {
|
|
611
|
+
custom_providers: vec![CustomProvider {
|
|
612
|
+
id: "myprovider".into(),
|
|
613
|
+
base_url: "http://localhost:20128/v1".into(),
|
|
614
|
+
..CustomProvider::default()
|
|
615
|
+
}],
|
|
616
|
+
..MintConfig::default()
|
|
617
|
+
};
|
|
618
|
+
assert!(
|
|
619
|
+
config
|
|
620
|
+
.available_providers()
|
|
621
|
+
.contains(&"custom:myprovider".to_owned())
|
|
622
|
+
);
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
#[test]
|
|
626
|
+
fn custom_provider_without_base_url_excluded() {
|
|
627
|
+
let config = MintConfig {
|
|
628
|
+
custom_providers: vec![CustomProvider {
|
|
629
|
+
id: "empty".into(),
|
|
630
|
+
base_url: "".into(),
|
|
631
|
+
..CustomProvider::default()
|
|
632
|
+
}],
|
|
633
|
+
..MintConfig::default()
|
|
634
|
+
};
|
|
635
|
+
assert!(
|
|
636
|
+
!config
|
|
637
|
+
.available_providers()
|
|
638
|
+
.contains(&"custom:empty".to_owned())
|
|
639
|
+
);
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
#[test]
|
|
643
|
+
fn active_model_resolves_first_custom_model() {
|
|
644
|
+
let config = MintConfig {
|
|
645
|
+
ai_provider: "custom:myprovider".into(),
|
|
646
|
+
custom_providers: vec![CustomProvider {
|
|
647
|
+
id: "myprovider".into(),
|
|
648
|
+
base_url: "http://localhost:20128/v1".into(),
|
|
649
|
+
models: vec![CustomProviderModel {
|
|
650
|
+
model_id: "llama-3.1-8b".into(),
|
|
651
|
+
display_name: String::new(),
|
|
652
|
+
}],
|
|
653
|
+
..CustomProvider::default()
|
|
654
|
+
}],
|
|
655
|
+
..MintConfig::default()
|
|
656
|
+
};
|
|
657
|
+
assert_eq!(config.active_model(), "llama-3.1-8b");
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
#[test]
|
|
661
|
+
fn resolve_custom_provider_returns_none_for_unknown() {
|
|
662
|
+
let config = MintConfig::default();
|
|
663
|
+
assert!(
|
|
664
|
+
config
|
|
665
|
+
.resolve_custom_provider("custom:nonexistent")
|
|
666
|
+
.is_none()
|
|
667
|
+
);
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
#[test]
|
|
671
|
+
fn resolve_custom_provider_strips_prefix() {
|
|
672
|
+
let config = MintConfig {
|
|
673
|
+
custom_providers: vec![CustomProvider {
|
|
674
|
+
id: "myp".into(),
|
|
675
|
+
..CustomProvider::default()
|
|
676
|
+
}],
|
|
677
|
+
..MintConfig::default()
|
|
678
|
+
};
|
|
679
|
+
assert!(config.resolve_custom_provider("custom:myp").is_some());
|
|
680
|
+
// Also works without prefix
|
|
681
|
+
assert!(config.resolve_custom_provider("myp").is_some());
|
|
682
|
+
}
|
|
455
683
|
}
|
|
@@ -659,11 +659,11 @@ async fn call_replicate(
|
|
|
659
659
|
poll_replicate(client, &api_key, &prediction_url).await?
|
|
660
660
|
};
|
|
661
661
|
|
|
662
|
-
if let Some(err) = prediction.get("error")
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
662
|
+
if let Some(err) = prediction.get("error")
|
|
663
|
+
&& !err.is_null()
|
|
664
|
+
{
|
|
665
|
+
let msg = err.as_str().unwrap_or("unknown Replicate error");
|
|
666
|
+
return Err(ImageGenError::ModelError(msg.to_owned()));
|
|
667
667
|
}
|
|
668
668
|
|
|
669
669
|
// Output is an array of image URLs
|
|
@@ -41,8 +41,8 @@ pub use code_tools::{
|
|
|
41
41
|
propose_code_edits, read_code_file, repository_summary, search_code,
|
|
42
42
|
};
|
|
43
43
|
pub use config::{
|
|
44
|
-
|
|
45
|
-
set_config_value,
|
|
44
|
+
AgentConfig, ConfigError, CustomProvider, CustomProviderHeader, CustomProviderModel,
|
|
45
|
+
MintConfig, config_path, initialize_config, load_config, save_config, set_config_value,
|
|
46
46
|
};
|
|
47
47
|
pub use files::{FileOperationError, PathKind, PathMatch, create_folder, find_paths};
|
|
48
48
|
pub use image_gen::{
|
|
@@ -91,3 +91,17 @@ pub use channels::start_channels;
|
|
|
91
91
|
|
|
92
92
|
pub static HTTP_CLIENT: std::sync::LazyLock<reqwest::Client> =
|
|
93
93
|
std::sync::LazyLock::new(reqwest::Client::new);
|
|
94
|
+
|
|
95
|
+
pub static ACTIVE_AGENTS: std::sync::LazyLock<
|
|
96
|
+
std::sync::Mutex<std::collections::HashMap<String, tokio::task::AbortHandle>>,
|
|
97
|
+
> = std::sync::LazyLock::new(|| std::sync::Mutex::new(std::collections::HashMap::new()));
|
|
98
|
+
|
|
99
|
+
pub fn cancel_agent(chat_id: &str) -> bool {
|
|
100
|
+
let mut agents = ACTIVE_AGENTS.lock().unwrap();
|
|
101
|
+
if let Some(handle) = agents.remove(chat_id) {
|
|
102
|
+
handle.abort();
|
|
103
|
+
true
|
|
104
|
+
} else {
|
|
105
|
+
false
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -58,6 +58,8 @@ pub struct LearnedSkill {
|
|
|
58
58
|
pub source_path: String,
|
|
59
59
|
pub content: String,
|
|
60
60
|
pub created_at: String,
|
|
61
|
+
#[serde(default)]
|
|
62
|
+
pub description: Option<String>,
|
|
61
63
|
}
|
|
62
64
|
|
|
63
65
|
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
|
|
@@ -624,12 +626,15 @@ fn ensure_column(
|
|
|
624
626
|
}
|
|
625
627
|
|
|
626
628
|
fn learned_skill_row(row: &rusqlite::Row<'_>) -> Result<LearnedSkill, rusqlite::Error> {
|
|
629
|
+
let content: String = row.get(3)?;
|
|
630
|
+
let description = crate::skills::parse_skill_description(&content);
|
|
627
631
|
Ok(LearnedSkill {
|
|
628
632
|
id: row.get(0)?,
|
|
629
633
|
name: row.get(1)?,
|
|
630
634
|
source_path: row.get(2)?,
|
|
631
|
-
content
|
|
635
|
+
content,
|
|
632
636
|
created_at: row.get(4)?,
|
|
637
|
+
description,
|
|
633
638
|
})
|
|
634
639
|
}
|
|
635
640
|
|