@pheem49/mint 1.8.1 → 1.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +3 -3
- package/Cargo.toml +1 -1
- package/README.md +0 -17
- package/Release_Note.md +92 -58
- package/bin/mint +0 -0
- package/crates/mint-cli/src/agent.rs +100 -6
- package/crates/mint-cli/src/main.rs +166 -52
- package/crates/mint-core/src/agent_loop.rs +1 -0
- package/crates/mint-core/src/api_server.rs +55 -2
- package/crates/mint-core/src/browser.rs +55 -0
- package/crates/mint-core/src/channels.rs +1 -0
- package/crates/mint-core/src/chat.rs +3 -0
- package/crates/mint-core/src/config.rs +61 -0
- package/crates/mint-core/src/lib.rs +14 -0
- package/crates/mint-core/src/orchestration.rs +180 -11
- 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 +30 -0
- package/shared-modules/linux-audio/fluidsynth2.json +19 -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 +82 -0
- package/shared-modules/linux-audio/lrdf.json +57 -0
- package/shared-modules/linux-audio/lv2.json +21 -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 +66 -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/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 +194 -1303
- package/src/renderer/src/components/MintDashboard.tsx +23 -169
- package/src/renderer/src/components/PicturesLibrary.tsx +32 -8
- package/src/renderer/src/components/Settings/AgentsTab.tsx +362 -0
- package/src/renderer/src/components/Settings/AutomationTab.tsx +0 -22
- package/src/renderer/src/components/SettingsWindow.tsx +53 -3
- package/src/renderer/src/css/styles.css +84 -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 +194 -1301
- package/src/renderer/src-web/components/MintDashboard.tsx +23 -169
- package/src/renderer/src-web/components/PicturesLibrary.tsx +23 -29
- package/src/renderer/src-web/components/Settings/AgentsTab.tsx +362 -0
- package/src/renderer/src-web/components/Settings/AutomationTab.tsx +0 -22
- package/src/renderer/src-web/components/SettingsWindow.tsx +53 -3
- package/src/renderer/src-web/css/styles.css +84 -0
- package/src/renderer/src-web/tauri.ts +180 -102
- package/src-tauri/src/lib.rs +137 -33
- package/src-tauri/src/webhooks.rs +1 -0
- package/src-tauri/src/workflows.rs +1 -0
- package/src-tauri/tauri.conf.json +1 -1
|
@@ -803,6 +803,7 @@ async fn main() -> Result<()> {
|
|
|
803
803
|
audio_data_uri: None,
|
|
804
804
|
document_attachment: None,
|
|
805
805
|
workspace_path: None,
|
|
806
|
+
agent_id: None,
|
|
806
807
|
},
|
|
807
808
|
)
|
|
808
809
|
.await?;
|
|
@@ -1761,8 +1762,12 @@ async fn handle_slash_command(
|
|
|
1761
1762
|
("/mcp list", "List configured MCP servers"),
|
|
1762
1763
|
("/mcp allow <server> <tool>", "Allow an MCP tool"),
|
|
1763
1764
|
("/stats", "Show session statistics"),
|
|
1764
|
-
("/exit
|
|
1765
|
+
("/exit", "Exit Mint"),
|
|
1765
1766
|
("/code <task>", "Run in code-agent mode"),
|
|
1767
|
+
(
|
|
1768
|
+
"/multi-agent [on|off]",
|
|
1769
|
+
"Show or toggle Multi-Agent Collaboration system",
|
|
1770
|
+
),
|
|
1766
1771
|
];
|
|
1767
1772
|
for (cmd_name, desc) in &commands {
|
|
1768
1773
|
println!(" {MINT}{:<30}{RESET} {DIM}{}{RESET}", cmd_name, desc);
|
|
@@ -1803,13 +1808,77 @@ async fn handle_slash_command(
|
|
|
1803
1808
|
println!();
|
|
1804
1809
|
} else {
|
|
1805
1810
|
session.config.ai_provider = rest.to_owned();
|
|
1811
|
+
match mint_core::save_config(&session.config) {
|
|
1812
|
+
Ok(()) => {
|
|
1813
|
+
let active_model = active_model(&session.config.ai_provider, &session.config);
|
|
1814
|
+
let display_name = format!("Changed model to {} • {}", session.config.ai_provider, active_model);
|
|
1815
|
+
|
|
1816
|
+
// Save system event interaction in memory
|
|
1817
|
+
if let Ok(memory) = MemoryStore::open_default() {
|
|
1818
|
+
let _ = memory.add_interaction_for_chat_with_fallback(
|
|
1819
|
+
CHAT_CLI_ID,
|
|
1820
|
+
&display_name,
|
|
1821
|
+
"",
|
|
1822
|
+
"system",
|
|
1823
|
+
"provider_change",
|
|
1824
|
+
None,
|
|
1825
|
+
);
|
|
1826
|
+
}
|
|
1827
|
+
|
|
1828
|
+
println!(
|
|
1829
|
+
"\n{DIM}───{RESET} {MINT}{}{RESET} {DIM}───{RESET}\n",
|
|
1830
|
+
display_name
|
|
1831
|
+
);
|
|
1832
|
+
}
|
|
1833
|
+
Err(error) => println!("{ERROR}Config error:{RESET} {error}"),
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
Some(SlashResult::Handled)
|
|
1837
|
+
}
|
|
1838
|
+
|
|
1839
|
+
"/multi-agent" => {
|
|
1840
|
+
if rest == "on" || rest == "off" {
|
|
1841
|
+
session.config.enable_agent_collaboration = rest == "on";
|
|
1806
1842
|
match mint_core::save_config(&session.config) {
|
|
1807
1843
|
Ok(()) => println!(
|
|
1808
|
-
"{DIM}
|
|
1809
|
-
session.config.
|
|
1844
|
+
"{DIM}Multi-Agent collaboration set to: {}{RESET}\n",
|
|
1845
|
+
if session.config.enable_agent_collaboration { "Enabled" } else { "Disabled" }
|
|
1810
1846
|
),
|
|
1811
|
-
Err(error) => println!("{ERROR}Config error:{RESET} {error}"),
|
|
1847
|
+
Err(error) => println!("{ERROR}Config error:{RESET} {error}\n"),
|
|
1812
1848
|
}
|
|
1849
|
+
} else if !rest.is_empty() {
|
|
1850
|
+
println!("{WARN}Usage: /multi-agent [on|off]{RESET}\n");
|
|
1851
|
+
} else {
|
|
1852
|
+
println!("\n{BLUE}Multi-Agent System Settings:{RESET}");
|
|
1853
|
+
let collab_status = if session.config.enable_agent_collaboration {
|
|
1854
|
+
format!("{MINT}Enabled (on){RESET}")
|
|
1855
|
+
} else {
|
|
1856
|
+
format!("{DIM}Disabled (off){RESET}")
|
|
1857
|
+
};
|
|
1858
|
+
println!(" Global Collaboration: {collab_status}");
|
|
1859
|
+
println!("\n{BLUE}Configured Agents:{RESET}");
|
|
1860
|
+
if session.config.agents.is_empty() {
|
|
1861
|
+
println!(" No agents configured.");
|
|
1862
|
+
} else {
|
|
1863
|
+
for agent in &session.config.agents {
|
|
1864
|
+
let status_label = if agent.enabled {
|
|
1865
|
+
format!("{MINT}[Enabled]{RESET}")
|
|
1866
|
+
} else {
|
|
1867
|
+
format!("{DIM}[Disabled]{RESET}")
|
|
1868
|
+
};
|
|
1869
|
+
println!(
|
|
1870
|
+
" {:<15} {} Provider: {:<12} Model: {}",
|
|
1871
|
+
agent.name, status_label, agent.provider, agent.model
|
|
1872
|
+
);
|
|
1873
|
+
let truncated_instruction = if agent.system_instruction.len() > 60 {
|
|
1874
|
+
format!("{}...", &agent.system_instruction[..60].replace('\n', " "))
|
|
1875
|
+
} else {
|
|
1876
|
+
agent.system_instruction.replace('\n', " ")
|
|
1877
|
+
};
|
|
1878
|
+
println!(" {DIM}Instruction: {truncated_instruction}{RESET}");
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1881
|
+
println!();
|
|
1813
1882
|
}
|
|
1814
1883
|
Some(SlashResult::Handled)
|
|
1815
1884
|
}
|
|
@@ -2542,6 +2611,7 @@ async fn run_interactive_chat() -> Result<()> {
|
|
|
2542
2611
|
audio_data_uri: None,
|
|
2543
2612
|
document_attachment: None,
|
|
2544
2613
|
workspace_path: None,
|
|
2614
|
+
agent_id: None,
|
|
2545
2615
|
},
|
|
2546
2616
|
|chunk| {
|
|
2547
2617
|
if first_chunk {
|
|
@@ -2635,51 +2705,69 @@ fn print_exit_message(session: &InteractiveSession) {
|
|
|
2635
2705
|
}
|
|
2636
2706
|
|
|
2637
2707
|
const AUTOCOMPLETE_COMMANDS: &[(&str, &str)] = &[
|
|
2638
|
-
("/
|
|
2708
|
+
("/cd", "Change active workspace directory"),
|
|
2709
|
+
("/clear", "Clear conversation history"),
|
|
2710
|
+
("/code", "Run in code-agent mode"),
|
|
2711
|
+
("/exit", "Exit Mint CLI"),
|
|
2639
2712
|
("/fast", "Toggle fast mode (hide thinking traces)"),
|
|
2640
|
-
("/
|
|
2713
|
+
("/help", "Show help menu"),
|
|
2714
|
+
("/image", "Attach image from disk"),
|
|
2641
2715
|
(
|
|
2642
2716
|
"/image-provider",
|
|
2643
2717
|
"List image gen providers or switch default provider",
|
|
2644
2718
|
),
|
|
2645
|
-
("/clear", "Clear conversation history"),
|
|
2646
|
-
("/cd", "Change active workspace directory"),
|
|
2647
|
-
("/image", "Attach image from disk"),
|
|
2648
|
-
("/paste", "Attach image from clipboard"),
|
|
2649
2719
|
("/learn", "Import persistent skill/instruction"),
|
|
2650
|
-
("/plugins", "List or generate plugins/skills"),
|
|
2651
|
-
("/memory", "Manage long-term memory store"),
|
|
2652
2720
|
("/mcp", "List configured MCP servers"),
|
|
2721
|
+
("/memory", "Manage long-term memory store"),
|
|
2722
|
+
("/models", "List AI providers or switch active provider"),
|
|
2723
|
+
("/multi-agent", "Show or toggle Multi-Agent Collaboration system"),
|
|
2724
|
+
("/paste", "Attach image from clipboard"),
|
|
2725
|
+
("/plugins", "List or generate plugins/skills"),
|
|
2653
2726
|
("/stats", "Show session statistics"),
|
|
2654
|
-
("/exit", "Exit Mint CLI"),
|
|
2655
|
-
("/quit", "Exit Mint CLI"),
|
|
2656
|
-
("/code", "Run in code-agent mode"),
|
|
2657
2727
|
];
|
|
2658
2728
|
|
|
2659
2729
|
fn draw_input_box(
|
|
2660
|
-
|
|
2730
|
+
input_chars: &[char],
|
|
2731
|
+
cursor_pos: usize,
|
|
2661
2732
|
placeholder: &str,
|
|
2662
2733
|
model: &str,
|
|
2663
2734
|
path_str: &str,
|
|
2664
2735
|
tab_base_input: Option<&str>,
|
|
2665
2736
|
tab_index: Option<usize>,
|
|
2666
|
-
) -> usize {
|
|
2737
|
+
) -> (usize, usize) {
|
|
2667
2738
|
let (term_width, _) = crossterm::terminal::size().unwrap_or((80, 24));
|
|
2668
2739
|
let width = term_width as usize;
|
|
2669
2740
|
let prefix = "› ";
|
|
2670
2741
|
let input_width = width.saturating_sub(2);
|
|
2671
2742
|
let content_max_len = input_width.saturating_sub(prefix.chars().count());
|
|
2672
2743
|
|
|
2673
|
-
let
|
|
2744
|
+
let mut start_idx = 0;
|
|
2745
|
+
if input_chars.len() > content_max_len {
|
|
2746
|
+
if cursor_pos >= content_max_len {
|
|
2747
|
+
start_idx = (cursor_pos + 5).saturating_sub(content_max_len);
|
|
2748
|
+
if start_idx + content_max_len > input_chars.len() {
|
|
2749
|
+
start_idx = input_chars.len() - content_max_len;
|
|
2750
|
+
}
|
|
2751
|
+
}
|
|
2752
|
+
}
|
|
2753
|
+
|
|
2754
|
+
let slice_chars = if input_chars.len() > content_max_len {
|
|
2755
|
+
&input_chars[start_idx..std::cmp::min(start_idx + content_max_len, input_chars.len())]
|
|
2756
|
+
} else {
|
|
2757
|
+
input_chars
|
|
2758
|
+
};
|
|
2759
|
+
let displayed_input: String = slice_chars.iter().collect();
|
|
2760
|
+
|
|
2761
|
+
let display_str = if displayed_input.is_empty() {
|
|
2674
2762
|
format!("{DIM}{}\x1b[39m", placeholder)
|
|
2675
2763
|
} else {
|
|
2676
|
-
format_placeholders(
|
|
2764
|
+
format_placeholders(&displayed_input)
|
|
2677
2765
|
};
|
|
2678
2766
|
|
|
2679
|
-
let visible_len = if
|
|
2767
|
+
let visible_len = if displayed_input.is_empty() {
|
|
2680
2768
|
placeholder.chars().count()
|
|
2681
2769
|
} else {
|
|
2682
|
-
string_visual_width(
|
|
2770
|
+
string_visual_width(&displayed_input)
|
|
2683
2771
|
};
|
|
2684
2772
|
|
|
2685
2773
|
let pad_len = content_max_len.saturating_sub(visible_len);
|
|
@@ -2707,7 +2795,8 @@ fn draw_input_box(
|
|
|
2707
2795
|
);
|
|
2708
2796
|
|
|
2709
2797
|
// Compute and draw suggestions
|
|
2710
|
-
let
|
|
2798
|
+
let raw_input: String = input_chars.iter().collect();
|
|
2799
|
+
let search_query = tab_base_input.unwrap_or(&raw_input);
|
|
2711
2800
|
let mut match_count = 0;
|
|
2712
2801
|
if search_query.starts_with('/') {
|
|
2713
2802
|
let matches: Vec<_> = AUTOCOMPLETE_COMMANDS
|
|
@@ -2716,11 +2805,18 @@ fn draw_input_box(
|
|
|
2716
2805
|
.collect();
|
|
2717
2806
|
|
|
2718
2807
|
if !matches.is_empty() {
|
|
2719
|
-
|
|
2720
|
-
println!();
|
|
2721
|
-
println!(" {BLUE}Suggestions{RESET}");
|
|
2808
|
+
let total_pages = (matches.len() + 4) / 5;
|
|
2722
2809
|
let highlight_idx = tab_index.map(|idx| idx % matches.len());
|
|
2723
|
-
|
|
2810
|
+
let selected_idx = highlight_idx.unwrap_or(0);
|
|
2811
|
+
let current_page = selected_idx / 5;
|
|
2812
|
+
let start_idx = current_page * 5;
|
|
2813
|
+
let end_idx = std::cmp::min(start_idx + 5, matches.len());
|
|
2814
|
+
match_count = end_idx - start_idx;
|
|
2815
|
+
|
|
2816
|
+
println!();
|
|
2817
|
+
println!(" {BLUE}Suggestions ({}/{}){RESET}", current_page + 1, total_pages);
|
|
2818
|
+
for i in start_idx..end_idx {
|
|
2819
|
+
let (cmd, desc) = matches[i];
|
|
2724
2820
|
if Some(i) == highlight_idx {
|
|
2725
2821
|
println!(" {BLUE}▶ {:<16}{RESET} {DIM}- {}{RESET}", cmd, desc);
|
|
2726
2822
|
} else {
|
|
@@ -2731,11 +2827,29 @@ fn draw_input_box(
|
|
|
2731
2827
|
}
|
|
2732
2828
|
|
|
2733
2829
|
let _ = io::stdout().flush();
|
|
2734
|
-
match_count
|
|
2830
|
+
(match_count, start_idx)
|
|
2735
2831
|
}
|
|
2736
2832
|
|
|
2737
2833
|
fn input_cursor_column(input_chars: &[char], cursor_pos: usize) -> usize {
|
|
2738
|
-
let
|
|
2834
|
+
let (term_width, _) = crossterm::terminal::size().unwrap_or((80, 24));
|
|
2835
|
+
let width = term_width as usize;
|
|
2836
|
+
let prefix = "› ";
|
|
2837
|
+
let input_width = width.saturating_sub(2);
|
|
2838
|
+
let content_max_len = input_width.saturating_sub(prefix.chars().count());
|
|
2839
|
+
|
|
2840
|
+
let mut start_idx = 0;
|
|
2841
|
+
if input_chars.len() > content_max_len {
|
|
2842
|
+
if cursor_pos >= content_max_len {
|
|
2843
|
+
start_idx = (cursor_pos + 5).saturating_sub(content_max_len);
|
|
2844
|
+
if start_idx + content_max_len > input_chars.len() {
|
|
2845
|
+
start_idx = input_chars.len() - content_max_len;
|
|
2846
|
+
}
|
|
2847
|
+
}
|
|
2848
|
+
}
|
|
2849
|
+
|
|
2850
|
+
let cursor_pos_clamped = std::cmp::min(cursor_pos, input_chars.len());
|
|
2851
|
+
let start_idx_clamped = std::cmp::min(start_idx, cursor_pos_clamped);
|
|
2852
|
+
let visual_cursor_pos: usize = input_chars[start_idx_clamped..cursor_pos_clamped]
|
|
2739
2853
|
.iter()
|
|
2740
2854
|
.copied()
|
|
2741
2855
|
.map(char_visual_width)
|
|
@@ -2766,9 +2880,9 @@ fn redraw_input_box(
|
|
|
2766
2880
|
tab_index: Option<usize>,
|
|
2767
2881
|
) {
|
|
2768
2882
|
clear_input_box();
|
|
2769
|
-
let
|
|
2770
|
-
|
|
2771
|
-
|
|
2883
|
+
let (match_count, _) = draw_input_box(
|
|
2884
|
+
input_chars,
|
|
2885
|
+
cursor_pos,
|
|
2772
2886
|
placeholder,
|
|
2773
2887
|
model,
|
|
2774
2888
|
path_str,
|
|
@@ -2799,7 +2913,7 @@ fn read_line_interactive(
|
|
|
2799
2913
|
let mut tab_base_input: Option<String> = None;
|
|
2800
2914
|
let mut tab_index: Option<usize> = None;
|
|
2801
2915
|
|
|
2802
|
-
let match_count = draw_input_box(
|
|
2916
|
+
let (match_count, _) = draw_input_box(&input_chars, cursor_pos, placeholder, model, path_str, None, None);
|
|
2803
2917
|
position_input_cursor(&input_chars, cursor_pos, match_count);
|
|
2804
2918
|
let _ = io::stdout().flush();
|
|
2805
2919
|
|
|
@@ -2918,12 +3032,7 @@ fn read_line_interactive(
|
|
|
2918
3032
|
}
|
|
2919
3033
|
}
|
|
2920
3034
|
KeyCode::Char(c) => {
|
|
2921
|
-
|
|
2922
|
-
let max_width = (term_width as usize).saturating_sub(4);
|
|
2923
|
-
let current_visual_width: usize =
|
|
2924
|
-
input_chars.iter().copied().map(char_visual_width).sum();
|
|
2925
|
-
|
|
2926
|
-
if current_visual_width < max_width {
|
|
3035
|
+
if input_chars.len() < 10000 {
|
|
2927
3036
|
input_chars.insert(cursor_pos, c);
|
|
2928
3037
|
cursor_pos += 1;
|
|
2929
3038
|
|
|
@@ -3092,13 +3201,15 @@ fn read_line_interactive(
|
|
|
3092
3201
|
}
|
|
3093
3202
|
}
|
|
3094
3203
|
disable_raw_mode()?;
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3204
|
+
redraw_input_box(
|
|
3205
|
+
&input_chars,
|
|
3206
|
+
cursor_pos,
|
|
3207
|
+
placeholder,
|
|
3208
|
+
model,
|
|
3209
|
+
path_str,
|
|
3210
|
+
None,
|
|
3211
|
+
None,
|
|
3212
|
+
);
|
|
3102
3213
|
enable_raw_mode()?;
|
|
3103
3214
|
}
|
|
3104
3215
|
KeyCode::Right => {
|
|
@@ -3111,13 +3222,15 @@ fn read_line_interactive(
|
|
|
3111
3222
|
}
|
|
3112
3223
|
}
|
|
3113
3224
|
disable_raw_mode()?;
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3225
|
+
redraw_input_box(
|
|
3226
|
+
&input_chars,
|
|
3227
|
+
cursor_pos,
|
|
3228
|
+
placeholder,
|
|
3229
|
+
model,
|
|
3230
|
+
path_str,
|
|
3231
|
+
None,
|
|
3232
|
+
None,
|
|
3233
|
+
);
|
|
3121
3234
|
enable_raw_mode()?;
|
|
3122
3235
|
}
|
|
3123
3236
|
KeyCode::Enter => {
|
|
@@ -3566,6 +3679,7 @@ async fn run_github_overview(repo: &str, config: &MintConfig) -> Result<()> {
|
|
|
3566
3679
|
audio_data_uri: None,
|
|
3567
3680
|
document_attachment: None,
|
|
3568
3681
|
workspace_path: None,
|
|
3682
|
+
agent_id: None,
|
|
3569
3683
|
},
|
|
3570
3684
|
)
|
|
3571
3685
|
.await?;
|
|
@@ -476,6 +476,7 @@ pub async fn start_api_server(port: u16) -> Result<(), std::io::Error> {
|
|
|
476
476
|
image_data_uri: Option<String>,
|
|
477
477
|
audio_data_uri: Option<String>,
|
|
478
478
|
document_attachment: Option<crate::chat::DocumentAttachment>,
|
|
479
|
+
agent_id: Option<String>,
|
|
479
480
|
}
|
|
480
481
|
|
|
481
482
|
if let Ok(req) = serde_json::from_str::<ApiChatRequest>(body) {
|
|
@@ -488,6 +489,7 @@ pub async fn start_api_server(port: u16) -> Result<(), std::io::Error> {
|
|
|
488
489
|
audio_data_uri: req.audio_data_uri,
|
|
489
490
|
document_attachment: req.document_attachment,
|
|
490
491
|
workspace_path: None,
|
|
492
|
+
agent_id: req.agent_id,
|
|
491
493
|
};
|
|
492
494
|
let mut chat_req =
|
|
493
495
|
chat_req.with_document_context(&config).unwrap_or(chat_req);
|
|
@@ -550,6 +552,24 @@ pub async fn start_api_server(port: u16) -> Result<(), std::io::Error> {
|
|
|
550
552
|
)
|
|
551
553
|
.await;
|
|
552
554
|
}
|
|
555
|
+
("POST", "/api/cancel-chat") => {
|
|
556
|
+
#[derive(Deserialize)]
|
|
557
|
+
#[serde(rename_all = "camelCase")]
|
|
558
|
+
struct CancelRequest {
|
|
559
|
+
chat_id: String,
|
|
560
|
+
}
|
|
561
|
+
if let Ok(req) = serde_json::from_str::<CancelRequest>(body) {
|
|
562
|
+
crate::cancel_agent(&req.chat_id);
|
|
563
|
+
send_json_response(socket, "200 OK", "{\"status\":\"ok\"}").await;
|
|
564
|
+
} else {
|
|
565
|
+
send_json_response(
|
|
566
|
+
socket,
|
|
567
|
+
"400 Bad Request",
|
|
568
|
+
"{\"status\":\"invalid cancel body\"}",
|
|
569
|
+
)
|
|
570
|
+
.await;
|
|
571
|
+
}
|
|
572
|
+
}
|
|
553
573
|
("POST", "/api/chat-stream") => {
|
|
554
574
|
#[derive(Deserialize)]
|
|
555
575
|
#[serde(rename_all = "camelCase")]
|
|
@@ -560,6 +580,7 @@ pub async fn start_api_server(port: u16) -> Result<(), std::io::Error> {
|
|
|
560
580
|
image_data_uri: Option<String>,
|
|
561
581
|
audio_data_uri: Option<String>,
|
|
562
582
|
document_attachment: Option<crate::chat::DocumentAttachment>,
|
|
583
|
+
agent_id: Option<String>,
|
|
563
584
|
}
|
|
564
585
|
|
|
565
586
|
if let Ok(req) = serde_json::from_str::<ApiChatRequest>(body) {
|
|
@@ -572,6 +593,7 @@ pub async fn start_api_server(port: u16) -> Result<(), std::io::Error> {
|
|
|
572
593
|
audio_data_uri: req.audio_data_uri,
|
|
573
594
|
document_attachment: req.document_attachment,
|
|
574
595
|
workspace_path: None,
|
|
596
|
+
agent_id: req.agent_id,
|
|
575
597
|
};
|
|
576
598
|
let mut chat_req =
|
|
577
599
|
chat_req.with_document_context(&config).unwrap_or(chat_req);
|
|
@@ -631,7 +653,8 @@ pub async fn start_api_server(port: u16) -> Result<(), std::io::Error> {
|
|
|
631
653
|
let config_clone = config.clone();
|
|
632
654
|
let chat_req_clone = chat_req.clone();
|
|
633
655
|
let tx_done = tx.clone();
|
|
634
|
-
|
|
656
|
+
let chat_id_str = chat_req.chat_id.clone().unwrap_or_default();
|
|
657
|
+
let join_handle = tokio::spawn(async move {
|
|
635
658
|
let result = orchestrate_chat_stream_with_fallback(
|
|
636
659
|
&config_clone,
|
|
637
660
|
&chat_req_clone,
|
|
@@ -675,6 +698,19 @@ pub async fn start_api_server(port: u16) -> Result<(), std::io::Error> {
|
|
|
675
698
|
}
|
|
676
699
|
}
|
|
677
700
|
});
|
|
701
|
+
|
|
702
|
+
let abort_handle = join_handle.abort_handle();
|
|
703
|
+
if !chat_id_str.is_empty() {
|
|
704
|
+
crate::ACTIVE_AGENTS.lock().unwrap().insert(chat_id_str.clone(), abort_handle);
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
let chat_id_str_cleanup = chat_id_str.clone();
|
|
708
|
+
tokio::spawn(async move {
|
|
709
|
+
let _ = join_handle.await;
|
|
710
|
+
if !chat_id_str_cleanup.is_empty() {
|
|
711
|
+
crate::ACTIVE_AGENTS.lock().unwrap().remove(&chat_id_str_cleanup);
|
|
712
|
+
}
|
|
713
|
+
});
|
|
678
714
|
} else {
|
|
679
715
|
let root = std::env::current_dir().unwrap_or_default();
|
|
680
716
|
let fast_mode = config
|
|
@@ -686,16 +722,19 @@ pub async fn start_api_server(port: u16) -> Result<(), std::io::Error> {
|
|
|
686
722
|
let tx_done = tx.clone();
|
|
687
723
|
let config_clone = config.clone();
|
|
688
724
|
let chat_id = chat_req.chat_id.clone();
|
|
725
|
+
let chat_id_str = chat_id.clone().unwrap_or_default();
|
|
689
726
|
let message = chat_req.message.clone();
|
|
690
727
|
let image_data_uri = chat_req.image_data_uri.clone();
|
|
728
|
+
let agent_id = chat_req.agent_id.clone();
|
|
691
729
|
|
|
692
|
-
tokio::spawn(async move {
|
|
730
|
+
let join_handle = tokio::spawn(async move {
|
|
693
731
|
let result = orchestrate_agent_loop(
|
|
694
732
|
&config_clone,
|
|
695
733
|
&message,
|
|
696
734
|
&root,
|
|
697
735
|
image_data_uri,
|
|
698
736
|
chat_id.as_deref(),
|
|
737
|
+
agent_id.as_deref(),
|
|
699
738
|
fast_mode,
|
|
700
739
|
|_| Ok(ApprovalOutcome::Denied),
|
|
701
740
|
progress_cb,
|
|
@@ -734,6 +773,19 @@ pub async fn start_api_server(port: u16) -> Result<(), std::io::Error> {
|
|
|
734
773
|
}
|
|
735
774
|
}
|
|
736
775
|
});
|
|
776
|
+
|
|
777
|
+
let abort_handle = join_handle.abort_handle();
|
|
778
|
+
if !chat_id_str.is_empty() {
|
|
779
|
+
crate::ACTIVE_AGENTS.lock().unwrap().insert(chat_id_str.clone(), abort_handle);
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
let chat_id_str_cleanup = chat_id_str.clone();
|
|
783
|
+
tokio::spawn(async move {
|
|
784
|
+
let _ = join_handle.await;
|
|
785
|
+
if !chat_id_str_cleanup.is_empty() {
|
|
786
|
+
crate::ACTIVE_AGENTS.lock().unwrap().remove(&chat_id_str_cleanup);
|
|
787
|
+
}
|
|
788
|
+
});
|
|
737
789
|
}
|
|
738
790
|
}
|
|
739
791
|
|
|
@@ -894,6 +946,7 @@ async fn run_web_agent_loop(
|
|
|
894
946
|
&root,
|
|
895
947
|
request.image_data_uri.clone(),
|
|
896
948
|
request.chat_id.as_deref(),
|
|
949
|
+
request.agent_id.as_deref(),
|
|
897
950
|
fast_mode,
|
|
898
951
|
|_| Ok(ApprovalOutcome::Denied),
|
|
899
952
|
|_| {},
|
|
@@ -340,6 +340,61 @@ async fn cdp_call(config: &MintConfig, method: &str, params: Value) -> Result<Va
|
|
|
340
340
|
let (mut socket, _) = connect_async(socket_url)
|
|
341
341
|
.await
|
|
342
342
|
.map_err(|error| format!("unable to connect to Chrome DevTools websocket: {error}"))?;
|
|
343
|
+
let is_aura_script = method == "Runtime.evaluate"
|
|
344
|
+
&& params["expression"]
|
|
345
|
+
.as_str()
|
|
346
|
+
.map(|s| s.contains("mint-browser-aura"))
|
|
347
|
+
.unwrap_or(false);
|
|
348
|
+
|
|
349
|
+
if !is_aura_script {
|
|
350
|
+
let aura_script = r#"
|
|
351
|
+
(() => {
|
|
352
|
+
if (document.getElementById('mint-browser-aura')) return;
|
|
353
|
+
const aura = document.createElement('div');
|
|
354
|
+
aura.id = 'mint-browser-aura';
|
|
355
|
+
|
|
356
|
+
const style = document.createElement('style');
|
|
357
|
+
style.id = 'mint-browser-aura-style';
|
|
358
|
+
style.textContent = `
|
|
359
|
+
@keyframes mint-pulse {
|
|
360
|
+
0% { box-shadow: inset 0 0 15px rgba(16, 185, 129, 0.4); border-color: rgba(16, 185, 129, 0.6); }
|
|
361
|
+
100% { box-shadow: inset 0 0 30px rgba(16, 185, 129, 0.8); border-color: rgba(16, 185, 129, 1); }
|
|
362
|
+
}
|
|
363
|
+
`;
|
|
364
|
+
document.head.appendChild(style);
|
|
365
|
+
|
|
366
|
+
aura.style.cssText = `
|
|
367
|
+
position: fixed;
|
|
368
|
+
top: 0;
|
|
369
|
+
left: 0;
|
|
370
|
+
width: 100vw;
|
|
371
|
+
height: 100vh;
|
|
372
|
+
border: 5px solid rgba(16, 185, 129, 0.6);
|
|
373
|
+
pointer-events: none;
|
|
374
|
+
z-index: 2147483647;
|
|
375
|
+
box-sizing: border-box;
|
|
376
|
+
animation: mint-pulse 1.5s infinite alternate;
|
|
377
|
+
`;
|
|
378
|
+
document.body.appendChild(aura);
|
|
379
|
+
})()
|
|
380
|
+
"#;
|
|
381
|
+
|
|
382
|
+
let _ = socket
|
|
383
|
+
.send(Message::Text(
|
|
384
|
+
json!({
|
|
385
|
+
"id": 999,
|
|
386
|
+
"method": "Runtime.evaluate",
|
|
387
|
+
"params": {
|
|
388
|
+
"expression": aura_script,
|
|
389
|
+
"returnByValue": true
|
|
390
|
+
}
|
|
391
|
+
})
|
|
392
|
+
.to_string()
|
|
393
|
+
.into(),
|
|
394
|
+
))
|
|
395
|
+
.await;
|
|
396
|
+
}
|
|
397
|
+
|
|
343
398
|
socket
|
|
344
399
|
.send(Message::Text(
|
|
345
400
|
json!({ "id": 1, "method": method, "params": params })
|
|
@@ -99,6 +99,8 @@ pub struct ChatRequest {
|
|
|
99
99
|
pub document_attachment: Option<DocumentAttachment>,
|
|
100
100
|
#[serde(default)]
|
|
101
101
|
pub workspace_path: Option<String>,
|
|
102
|
+
#[serde(default)]
|
|
103
|
+
pub agent_id: Option<String>,
|
|
102
104
|
}
|
|
103
105
|
|
|
104
106
|
#[derive(Debug, Clone, Deserialize)]
|
|
@@ -965,6 +967,7 @@ mod tests {
|
|
|
965
967
|
audio_data_uri: None,
|
|
966
968
|
document_attachment: None,
|
|
967
969
|
workspace_path: None,
|
|
970
|
+
agent_id: None,
|
|
968
971
|
})
|
|
969
972
|
.unwrap();
|
|
970
973
|
assert_eq!(parts.len(), 3);
|
|
@@ -79,10 +79,24 @@ 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,
|
|
82
84
|
#[serde(flatten)]
|
|
83
85
|
pub extra: BTreeMap<String, Value>,
|
|
84
86
|
}
|
|
85
87
|
|
|
88
|
+
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
|
|
89
|
+
#[serde(rename_all = "camelCase")]
|
|
90
|
+
pub struct AgentConfig {
|
|
91
|
+
pub id: String,
|
|
92
|
+
pub name: String,
|
|
93
|
+
pub provider: String,
|
|
94
|
+
pub model: String,
|
|
95
|
+
pub api_key: Option<String>,
|
|
96
|
+
pub system_instruction: String,
|
|
97
|
+
pub enabled: bool,
|
|
98
|
+
}
|
|
99
|
+
|
|
86
100
|
impl Default for MintConfig {
|
|
87
101
|
fn default() -> Self {
|
|
88
102
|
let home = dirs::home_dir().unwrap_or_else(|| PathBuf::from("."));
|
|
@@ -142,12 +156,59 @@ impl Default for MintConfig {
|
|
|
142
156
|
],
|
|
143
157
|
blocked_file_names: vec![".env".into(), "id_rsa".into(), "id_ed25519".into()],
|
|
144
158
|
disabled_tools: Vec::new(),
|
|
159
|
+
agents: default_agents(),
|
|
160
|
+
enable_agent_collaboration: false,
|
|
145
161
|
extra: runtime_extra_defaults(),
|
|
146
162
|
}
|
|
147
163
|
}
|
|
148
164
|
}
|
|
149
165
|
|
|
166
|
+
fn default_agents() -> Vec<AgentConfig> {
|
|
167
|
+
vec![
|
|
168
|
+
AgentConfig {
|
|
169
|
+
id: "planner".into(),
|
|
170
|
+
name: "Planner".into(),
|
|
171
|
+
provider: "gemini".into(),
|
|
172
|
+
model: "gemini-2.5-flash".into(),
|
|
173
|
+
api_key: None,
|
|
174
|
+
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(),
|
|
175
|
+
enabled: true,
|
|
176
|
+
},
|
|
177
|
+
AgentConfig {
|
|
178
|
+
id: "coder".into(),
|
|
179
|
+
name: "Coder".into(),
|
|
180
|
+
provider: "gemini".into(),
|
|
181
|
+
model: "gemini-2.5-flash".into(),
|
|
182
|
+
api_key: None,
|
|
183
|
+
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(),
|
|
184
|
+
enabled: true,
|
|
185
|
+
},
|
|
186
|
+
AgentConfig {
|
|
187
|
+
id: "reviewer".into(),
|
|
188
|
+
name: "Reviewer".into(),
|
|
189
|
+
provider: "gemini".into(),
|
|
190
|
+
model: "gemini-2.5-flash".into(),
|
|
191
|
+
api_key: None,
|
|
192
|
+
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(),
|
|
193
|
+
enabled: true,
|
|
194
|
+
},
|
|
195
|
+
]
|
|
196
|
+
}
|
|
197
|
+
|
|
150
198
|
impl MintConfig {
|
|
199
|
+
pub fn active_model(&self) -> &str {
|
|
200
|
+
match self.ai_provider.as_str() {
|
|
201
|
+
"anthropic" => &self.anthropic_model,
|
|
202
|
+
"openai" => &self.openai_model,
|
|
203
|
+
"openrouter" => &self.openrouter_model,
|
|
204
|
+
"deepseek" => &self.deepseek_model,
|
|
205
|
+
"huggingface" => &self.hf_model,
|
|
206
|
+
"local_openai" => &self.local_model_name,
|
|
207
|
+
"ollama" => &self.ollama_model,
|
|
208
|
+
_ => &self.gemini_model,
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
151
212
|
pub fn available_providers(&self) -> Vec<&'static str> {
|
|
152
213
|
let mut providers = Vec::new();
|
|
153
214
|
if has_value(&self.anthropic_api_key) {
|