@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.
Files changed (184) hide show
  1. package/Cargo.lock +3 -3
  2. package/Cargo.toml +1 -1
  3. package/README.md +0 -17
  4. package/Release_Note.md +92 -58
  5. package/bin/mint +0 -0
  6. package/crates/mint-cli/src/agent.rs +100 -6
  7. package/crates/mint-cli/src/main.rs +166 -52
  8. package/crates/mint-core/src/agent_loop.rs +1 -0
  9. package/crates/mint-core/src/api_server.rs +55 -2
  10. package/crates/mint-core/src/browser.rs +55 -0
  11. package/crates/mint-core/src/channels.rs +1 -0
  12. package/crates/mint-core/src/chat.rs +3 -0
  13. package/crates/mint-core/src/config.rs +61 -0
  14. package/crates/mint-core/src/lib.rs +14 -0
  15. package/crates/mint-core/src/orchestration.rs +180 -11
  16. package/crates/mint-core/src/tts.rs +3 -1
  17. package/flatpak/com.pheem49.mint.desktop +9 -0
  18. package/flatpak/com.pheem49.mint.metainfo.xml +35 -0
  19. package/flatpak/com.pheem49.mint.yaml +52 -0
  20. package/package.json +1 -1
  21. package/shared-modules/.github/workflows/ci.yml +120 -0
  22. package/shared-modules/.github/workflows/update.yaml +28 -0
  23. package/shared-modules/CODEOWNERS +23 -0
  24. package/shared-modules/README.md +79 -0
  25. package/shared-modules/SDL/README.md +3 -0
  26. package/shared-modules/SDL/SDL-1.2.15.json +51 -0
  27. package/shared-modules/SDL/SDL_Pango-0.1.2-API-adds.patch +118 -0
  28. package/shared-modules/SDL/SDL_image-1.2.12.json +25 -0
  29. package/shared-modules/SDL/SDL_mixer-1.2.12.json +27 -0
  30. package/shared-modules/SDL/SDL_net-1.2.8.json +19 -0
  31. package/shared-modules/SDL/SDL_pango-0.1.2.json +26 -0
  32. package/shared-modules/SDL/SDL_ttf-2.0.11.json +28 -0
  33. package/shared-modules/SDL/libsdl-1.2.15-strict-prototypes.patch +316 -0
  34. package/shared-modules/SDL/sdl-check-for-SDL_VIDEO_X11_BACKINGSTORE.patch +24 -0
  35. package/shared-modules/SDL/sdl-libx11-build.patch +59 -0
  36. package/shared-modules/SDL/sdl-sysloadso-buffer-length.patch +27 -0
  37. package/shared-modules/SDL/sdl12-compat.json +22 -0
  38. package/shared-modules/SDL2/SDL2_image.json +27 -0
  39. package/shared-modules/SDL2/SDL2_ttf.json +29 -0
  40. package/shared-modules/cld2/CMakeLists.txt +157 -0
  41. package/shared-modules/cld2/cld2.json +24 -0
  42. package/shared-modules/clutter/clutter.json +72 -0
  43. package/shared-modules/dbus-glib/dbus-glib.json +29 -0
  44. package/shared-modules/glew/glew.json +36 -0
  45. package/shared-modules/glu/glu-9.json +12 -0
  46. package/shared-modules/gtk2/arc-gtk2-theme-Replace-Inkscape-dependency-with-rsvg-convert.patch +180 -0
  47. package/shared-modules/gtk2/gtk2-common-themes.json +360 -0
  48. package/shared-modules/gtk2/gtk2-fix-crash-in-show-uri.patch +30 -0
  49. package/shared-modules/gtk2/gtk2-gcc14.patch +281 -0
  50. package/shared-modules/gtk2/gtk2-gcc15.patch +250 -0
  51. package/shared-modules/gtk2/gtk2-murrine-c99.patch +34 -0
  52. package/shared-modules/gtk2/gtk2-use-adwaita-theme.patch +80 -0
  53. package/shared-modules/gtk2/gtk2.json +120 -0
  54. package/shared-modules/gtk2/ibus-gcc15.patch +13 -0
  55. package/shared-modules/gtk2/murrine-engine-fix-crash.patch +12 -0
  56. package/shared-modules/gtk2/readme.md +10 -0
  57. package/shared-modules/intltool/intltool-0.51.json +20 -0
  58. package/shared-modules/intltool/intltool-perl5.26-regex-fixes.patch +59 -0
  59. package/shared-modules/lame/0001-Build-xmm_quantize_sub.c-with-msse.patch +34 -0
  60. package/shared-modules/lame/0002-Include-GTK-1-autoconf-directives-in-build-system.patch +222 -0
  61. package/shared-modules/lame/0003-Patch-out-remaining-ansi2knr.patch +70 -0
  62. package/shared-modules/lame/0004-initscr-is-not-used-anywhere-in-lame-sourcetree.patch +41 -0
  63. package/shared-modules/lame/0005-Update-autoconf.patch +81 -0
  64. package/shared-modules/lame/lame-3.99.5.json +32 -0
  65. package/shared-modules/libappindicator/libappindicator-gtk2-12.10.json +140 -0
  66. package/shared-modules/libappindicator/libappindicator-gtk3-12.10.json +140 -0
  67. package/shared-modules/libappindicator/libappindicator-gtk3-introspection-12.10.json +140 -0
  68. package/shared-modules/libappindicator/patches/0001-libappindicator-ftbfs.patch +20 -0
  69. package/shared-modules/libappindicator/patches/0002-libappindicator-no-python.patch +888 -0
  70. package/shared-modules/libappindicator/patches/0003-libappindicator-fix-crash-from-incorrect-signal-emission.patch +74 -0
  71. package/shared-modules/libappindicator/patches/0004-libappindicator-fix-crash-iterating-icon-themes.patch +11 -0
  72. package/shared-modules/libayatana-appindicator/0001-Fix-HAVE_VALGRIND-AM_CONDITIONAL.patch +51 -0
  73. package/shared-modules/libayatana-appindicator/0001-Make-introspection-configurable.patch +44 -0
  74. package/shared-modules/libayatana-appindicator/libayatana-appindicator-gtk3.json +121 -0
  75. package/shared-modules/libcanberra/0001-gtk-Don-t-assume-all-GdkDisplays-are-GdkX11Displays-.patch +123 -0
  76. package/shared-modules/libcanberra/libcanberra.json +44 -0
  77. package/shared-modules/libmad/libmad.json +19 -0
  78. package/shared-modules/libsecret/libsecret.json +23 -0
  79. package/shared-modules/libsoup/libsoup-2.4.json +14 -0
  80. package/shared-modules/libusb/libusb.json +27 -0
  81. package/shared-modules/linux-audio/dssi.json +31 -0
  82. package/shared-modules/linux-audio/fftw3f-static.json +44 -0
  83. package/shared-modules/linux-audio/fftw3f.json +42 -0
  84. package/shared-modules/linux-audio/fluidsynth2-static.json +30 -0
  85. package/shared-modules/linux-audio/fluidsynth2.json +19 -0
  86. package/shared-modules/linux-audio/ladspa.json +26 -0
  87. package/shared-modules/linux-audio/lash.json +35 -0
  88. package/shared-modules/linux-audio/libinstpatch.json +16 -0
  89. package/shared-modules/linux-audio/liblo-static.json +22 -0
  90. package/shared-modules/linux-audio/liblo.json +17 -0
  91. package/shared-modules/linux-audio/lilv-static.json +94 -0
  92. package/shared-modules/linux-audio/lilv.json +82 -0
  93. package/shared-modules/linux-audio/lrdf.json +57 -0
  94. package/shared-modules/linux-audio/lv2.json +21 -0
  95. package/shared-modules/linux-audio/patches/lash/0001-configure-remove-aclocal-m4.patch +29 -0
  96. package/shared-modules/linux-audio/patches/lash/0002-Fix-build-with-recent-gcc.patch +73 -0
  97. package/shared-modules/linux-audio/patches/lash/0003-Fix-linking.patch +136 -0
  98. package/shared-modules/linux-audio/patches/raptor-libxml.patch +31 -0
  99. package/shared-modules/linux-audio/patches/stk-install.sh +54 -0
  100. package/shared-modules/linux-audio/stk.json +28 -0
  101. package/shared-modules/lua5.1/0004-Fix-stack-overflow-in-vararg-functions.patch +21 -0
  102. package/shared-modules/lua5.1/lua-5.1.5-so.patch +43 -0
  103. package/shared-modules/lua5.1/lua-5.1.5.json +42 -0
  104. package/shared-modules/lua5.3/lua-5.3.5.json +41 -0
  105. package/shared-modules/lua5.3/lua.pc.in +8 -0
  106. package/shared-modules/lua5.3/luaconf.patch +47 -0
  107. package/shared-modules/lua5.3/makefile-add-liblua.so-rule.patch +47 -0
  108. package/shared-modules/lua5.4/lua-5.4.json +41 -0
  109. package/shared-modules/lua5.4/lua.pc.in +8 -0
  110. package/shared-modules/lua5.4/luaconf.patch +34 -0
  111. package/shared-modules/lua5.4/makefile-add-liblua.so-rule.patch +42 -0
  112. package/shared-modules/luajit/luajit.json +30 -0
  113. package/shared-modules/lzo/lzo.json +27 -0
  114. package/shared-modules/mac/mac.json +18 -0
  115. package/shared-modules/physfs/physfs.json +26 -0
  116. package/shared-modules/pygame/audiofile-gcc6.patch +21 -0
  117. package/shared-modules/pygame/cython-fixes.patch +34 -0
  118. package/shared-modules/pygame/fluidsynth-no-rawmidi.patch +69 -0
  119. package/shared-modules/pygame/glib.patch +25 -0
  120. package/shared-modules/pygame/pygame1-python2.json +157 -0
  121. package/shared-modules/pygtk/pygtk-c99.patch +15 -0
  122. package/shared-modules/pygtk/pygtk.json +117 -0
  123. package/shared-modules/pygtk/pygtk.patch +39 -0
  124. package/shared-modules/python2.7/python-2.7.json +48 -0
  125. package/shared-modules/smpeg/smpeg-0.4.5.json +50 -0
  126. package/shared-modules/smpeg/smpeg-am-prog-as.patch +12 -0
  127. package/shared-modules/smpeg/smpeg-export-mpegaudio-class.patch +17 -0
  128. package/shared-modules/smpeg/smpeg-gcc6.patch +40 -0
  129. package/shared-modules/smpeg/smpeg-no-gtk.patch +37 -0
  130. package/shared-modules/squashfs-tools/squashfs-tools.json +25 -0
  131. package/shared-modules/update-checker.sh +50 -0
  132. package/shared-modules/vorbisgain/0001-temp_files.patch +75 -0
  133. package/shared-modules/vorbisgain/0002-errno.patch +33 -0
  134. package/shared-modules/vorbisgain/0003-manpage.patch +248 -0
  135. package/shared-modules/vorbisgain/0004-vorbisgain_mtime.patch +183 -0
  136. package/shared-modules/vorbisgain/0005-double_fclose.patch +21 -0
  137. package/shared-modules/vorbisgain/0006-manpage_hyphens.patch +56 -0
  138. package/shared-modules/vorbisgain/0007-recursively_spelling.patch +14 -0
  139. package/shared-modules/vorbisgain/0008-manpage_recursion_mistake.patch +23 -0
  140. package/shared-modules/vorbisgain/0009-hardening.patch +13 -0
  141. package/shared-modules/vorbisgain/0010-fclose.patch +13 -0
  142. package/shared-modules/vorbisgain/README.md +23 -0
  143. package/shared-modules/vorbisgain/vorbisgain_0.37-2.json +29 -0
  144. package/src/renderer/shared/agentProgress.ts +145 -0
  145. package/src/renderer/shared/calculator.ts +52 -0
  146. package/src/renderer/shared/components/AgentActivityDrawer.tsx +72 -0
  147. package/src/renderer/shared/components/AgentActivityTable.tsx +66 -0
  148. package/src/renderer/shared/components/ApprovalCard.tsx +93 -0
  149. package/src/renderer/shared/components/ChatCodeBlock.tsx +75 -0
  150. package/src/renderer/shared/components/ThinkingBlock.tsx +101 -0
  151. package/src/renderer/shared/constants/models.ts +91 -0
  152. package/src/renderer/shared/platform.ts +82 -0
  153. package/src/renderer/shared/types.ts +140 -0
  154. package/src/renderer/shared/utils/agentActivity.ts +187 -0
  155. package/src/renderer/shared/utils/approval.ts +1 -0
  156. package/src/renderer/shared/utils/approval.tsx +64 -0
  157. package/src/renderer/shared/utils/markdown.tsx +347 -0
  158. package/src/renderer/shared/utils/providers.ts +36 -0
  159. package/src/renderer/shared/utils/speech.ts +216 -0
  160. package/src/renderer/shared/utils/ui.ts +147 -0
  161. package/src/renderer/src/agentProgress.ts +11 -39
  162. package/src/renderer/src/calculator.ts +3 -46
  163. package/src/renderer/src/components/ChatPanel.tsx +194 -1303
  164. package/src/renderer/src/components/MintDashboard.tsx +23 -169
  165. package/src/renderer/src/components/PicturesLibrary.tsx +32 -8
  166. package/src/renderer/src/components/Settings/AgentsTab.tsx +362 -0
  167. package/src/renderer/src/components/Settings/AutomationTab.tsx +0 -22
  168. package/src/renderer/src/components/SettingsWindow.tsx +53 -3
  169. package/src/renderer/src/css/styles.css +84 -0
  170. package/src/renderer/src/tauri.ts +128 -143
  171. package/src/renderer/src-web/agentProgress.ts +11 -39
  172. package/src/renderer/src-web/calculator.ts +3 -46
  173. package/src/renderer/src-web/components/ChatPanel.tsx +194 -1301
  174. package/src/renderer/src-web/components/MintDashboard.tsx +23 -169
  175. package/src/renderer/src-web/components/PicturesLibrary.tsx +23 -29
  176. package/src/renderer/src-web/components/Settings/AgentsTab.tsx +362 -0
  177. package/src/renderer/src-web/components/Settings/AutomationTab.tsx +0 -22
  178. package/src/renderer/src-web/components/SettingsWindow.tsx +53 -3
  179. package/src/renderer/src-web/css/styles.css +84 -0
  180. package/src/renderer/src-web/tauri.ts +180 -102
  181. package/src-tauri/src/lib.rs +137 -33
  182. package/src-tauri/src/webhooks.rs +1 -0
  183. package/src-tauri/src/workflows.rs +1 -0
  184. package/src-tauri/tauri.conf.json +1 -1
@@ -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<std::sync::Mutex<std::collections::HashMap<String, tokio::task::AbortHandle>>> =
96
+ std::sync::LazyLock::new(|| std::sync::Mutex::new(std::collections::HashMap::new()));
97
+
98
+ pub fn cancel_agent(chat_id: &str) -> bool {
99
+ let mut agents = ACTIVE_AGENTS.lock().unwrap();
100
+ if let Some(handle) = agents.remove(chat_id) {
101
+ handle.abort();
102
+ true
103
+ } else {
104
+ false
105
+ }
106
+ }
107
+
@@ -93,7 +93,7 @@ pub async fn orchestrate_chat(
93
93
  let mut resolved_request = request.clone();
94
94
  resolved_request.message = resolve_github_links(&request.message, config).await;
95
95
  let memory = MemoryStore::open_default()?;
96
- let enriched = enrich_request(&memory, &resolved_request)?;
96
+ let enriched = enrich_request(config, &memory, &resolved_request)?;
97
97
  let response = send_chat(config, &enriched).await?;
98
98
  memory.add_interaction_for_chat_with_fallback(
99
99
  request_chat_id(request),
@@ -122,7 +122,7 @@ where
122
122
  let mut resolved_request = request.clone();
123
123
  resolved_request.message = resolve_github_links(&request.message, config).await;
124
124
  let memory = MemoryStore::open_default()?;
125
- let enriched = enrich_request(&memory, &resolved_request)?;
125
+ let enriched = enrich_request(config, &memory, &resolved_request)?;
126
126
  let response = stream_chat(config, &enriched, on_chunk).await?;
127
127
  memory.add_interaction_for_chat_with_fallback(
128
128
  request_chat_id(request),
@@ -147,7 +147,7 @@ pub async fn orchestrate_chat_with_fallback(
147
147
  let mut resolved_request = request.clone();
148
148
  resolved_request.message = resolve_github_links(&request.message, config).await;
149
149
  let memory = MemoryStore::open_default()?;
150
- let enriched = enrich_request(&memory, &resolved_request)?;
150
+ let enriched = enrich_request(config, &memory, &resolved_request)?;
151
151
  let (response, fallback) = send_chat_with_fallback(config, &enriched).await?;
152
152
  memory.add_interaction_for_chat_with_fallback(
153
153
  request_chat_id(request),
@@ -176,7 +176,7 @@ where
176
176
  let mut resolved_request = request.clone();
177
177
  resolved_request.message = resolve_github_links(&request.message, config).await;
178
178
  let memory = MemoryStore::open_default()?;
179
- let enriched = enrich_request(&memory, &resolved_request)?;
179
+ let enriched = enrich_request(config, &memory, &resolved_request)?;
180
180
  let (response, fallback) = stream_chat_with_fallback(config, &enriched, on_chunk).await?;
181
181
  memory.add_interaction_for_chat_with_fallback(
182
182
  request_chat_id(request),
@@ -194,7 +194,11 @@ where
194
194
  Ok((response, fallback))
195
195
  }
196
196
 
197
- fn enrich_request(memory: &MemoryStore, request: &ChatRequest) -> Result<ChatRequest, MemoryError> {
197
+ fn enrich_request(
198
+ config: &MintConfig,
199
+ memory: &MemoryStore,
200
+ request: &ChatRequest,
201
+ ) -> Result<ChatRequest, MemoryError> {
198
202
  let mut interactions =
199
203
  memory.recent_interactions_for_chat(request_chat_id(request), CONTEXT_LIMIT)?;
200
204
  interactions.reverse();
@@ -230,6 +234,16 @@ fn enrich_request(memory: &MemoryStore, request: &ChatRequest) -> Result<ChatReq
230
234
  .to_owned();
231
235
  }
232
236
 
237
+ // Inject active AI model/provider context to system instructions
238
+ let active_model_info = format!(
239
+ "\n\n[Active Environment Context]\n\
240
+ You are running on: {}\n\
241
+ Using AI Model: {}\n",
242
+ config.ai_provider,
243
+ config.active_model()
244
+ );
245
+ enriched.system_instruction.push_str(&active_model_info);
246
+
233
247
  if !transcript.is_empty() {
234
248
  enriched.system_instruction = format!(
235
249
  "{}\n\nRecent conversation context:\n{}",
@@ -549,6 +563,10 @@ pub enum ApprovalOutcome {
549
563
  pub enum AgentProgress {
550
564
  Thinking {
551
565
  elapsed_secs: u64,
566
+ #[serde(skip_serializing_if = "Option::is_none")]
567
+ agent_name: Option<String>,
568
+ #[serde(skip_serializing_if = "Option::is_none")]
569
+ model_name: Option<String>,
552
570
  },
553
571
  Thought {
554
572
  thought: String,
@@ -658,12 +676,95 @@ where
658
676
  Ok(Option::<AgentInput>::deserialize(deserializer)?.unwrap_or_default())
659
677
  }
660
678
 
679
+ fn resolve_agent_config(
680
+ config: &MintConfig,
681
+ agent_id: Option<&str>,
682
+ trajectory: &[String],
683
+ ) -> (MintConfig, String, Option<String>, Option<String>) {
684
+ if !config.enable_agent_collaboration {
685
+ return (config.clone(), "".to_string(), None, None);
686
+ }
687
+
688
+ let enabled_agents: Vec<&crate::config::AgentConfig> = config.agents.iter().filter(|a| a.enabled).collect();
689
+ if enabled_agents.is_empty() {
690
+ return (config.clone(), "".to_string(), None, None);
691
+ }
692
+
693
+ let active_agent = if let Some(id) = agent_id {
694
+ enabled_agents.iter().find(|a| a.id == id).copied()
695
+ } else {
696
+ // Multi-Agent Pipeline Collaboration (Planner -> Coder -> Reviewer)
697
+ let plan_created = trajectory.iter().any(|step| step.contains("- Action: create_plan"));
698
+ if !plan_created {
699
+ if let Some(planner) = enabled_agents.iter().find(|a| a.id == "planner") {
700
+ Some(*planner)
701
+ } else {
702
+ enabled_agents.iter().find(|a| a.id == "coder").copied()
703
+ }
704
+ } else {
705
+ // Check if edits have been made to verify
706
+ let edits_made = trajectory.iter().any(|step| {
707
+ step.contains("- Action: write_file") || step.contains("- Action: apply_patch")
708
+ });
709
+ if edits_made {
710
+ if let Some(last_step) = trajectory.last() {
711
+ if last_step.contains("- Action: write_file") || last_step.contains("- Action: apply_patch") {
712
+ if let Some(reviewer) = enabled_agents.iter().find(|a| a.id == "reviewer") {
713
+ Some(*reviewer)
714
+ } else {
715
+ enabled_agents.iter().find(|a| a.id == "coder").copied()
716
+ }
717
+ } else {
718
+ enabled_agents.iter().find(|a| a.id == "coder").copied()
719
+ }
720
+ } else {
721
+ enabled_agents.iter().find(|a| a.id == "coder").copied()
722
+ }
723
+ } else {
724
+ enabled_agents.iter().find(|a| a.id == "coder").copied()
725
+ }
726
+ }
727
+ };
728
+
729
+ let Some(agent) = active_agent else {
730
+ return (config.clone(), "".to_string(), None, None);
731
+ };
732
+
733
+ let mut cfg_clone = config.clone();
734
+ cfg_clone.ai_provider = agent.provider.clone();
735
+ cfg_clone.gemini_model = agent.model.clone();
736
+ cfg_clone.openai_model = agent.model.clone();
737
+ cfg_clone.anthropic_model = agent.model.clone();
738
+ cfg_clone.openrouter_model = agent.model.clone();
739
+ cfg_clone.deepseek_model = agent.model.clone();
740
+ cfg_clone.hf_model = agent.model.clone();
741
+ cfg_clone.local_model_name = agent.model.clone();
742
+ cfg_clone.ollama_model = agent.model.clone();
743
+
744
+ if let Some(key) = &agent.api_key {
745
+ if !key.trim().is_empty() {
746
+ match agent.provider.as_str() {
747
+ "gemini" => cfg_clone.api_key = key.clone(),
748
+ "openai" => cfg_clone.openai_api_key = key.clone(),
749
+ "anthropic" => cfg_clone.anthropic_api_key = key.clone(),
750
+ "openrouter" => cfg_clone.openrouter_api_key = key.clone(),
751
+ "deepseek" => cfg_clone.deepseek_api_key = key.clone(),
752
+ "huggingface" => cfg_clone.hf_api_key = key.clone(),
753
+ _ => {}
754
+ }
755
+ }
756
+ }
757
+
758
+ (cfg_clone, agent.system_instruction.clone(), Some(agent.name.clone()), Some(agent.model.clone()))
759
+ }
760
+
661
761
  pub async fn orchestrate_agent_loop<Approve, Progress, Chunk>(
662
762
  config: &MintConfig,
663
763
  task: &str,
664
764
  root: &Path,
665
765
  image_data_uri: Option<String>,
666
766
  chat_id: Option<&str>,
767
+ agent_id: Option<&str>,
667
768
  fast_mode: bool,
668
769
  mut approve: Approve,
669
770
  mut progress: Progress,
@@ -743,20 +844,39 @@ where
743
844
  let mut trajectory: Vec<String> = Vec::new();
744
845
 
745
846
  for step in 1..=MAX_STEPS {
847
+ let (active_config, agent_instruction, active_agent_name, active_model_name) = resolve_agent_config(config, agent_id, &trajectory);
848
+
746
849
  progress(AgentProgress::Thinking {
747
850
  elapsed_secs: started_at.elapsed().as_secs(),
851
+ agent_name: active_agent_name,
852
+ model_name: active_model_name.clone(),
748
853
  });
749
854
 
855
+ let mut active_system_prompt = system_prompt.clone();
856
+ if let Some(ref model_name) = active_model_name {
857
+ active_system_prompt.push_str(&format!(
858
+ "\n\n[Active Environment Context]\n\
859
+ You are running on: {}\n\
860
+ Using AI Model: {}\n",
861
+ active_config.ai_provider,
862
+ model_name
863
+ ));
864
+ }
865
+ if !agent_instruction.is_empty() {
866
+ active_system_prompt.push_str(&format!("\n\nYour Current Role & System Instructions:\n{}", agent_instruction));
867
+ }
868
+
750
869
  let (response, fallback) = send_chat_with_fallback(
751
- config,
870
+ &active_config,
752
871
  &ChatRequest {
753
872
  message: observation.clone(),
754
- system_instruction: system_prompt.clone(),
873
+ system_instruction: active_system_prompt.clone(),
755
874
  chat_id: Some(chat_id.to_owned()),
756
875
  image_data_uri: pending_image.take(),
757
876
  audio_data_uri: None,
758
877
  document_attachment: None,
759
878
  workspace_path: None,
879
+ agent_id: None,
760
880
  },
761
881
  )
762
882
  .await?;
@@ -771,7 +891,7 @@ where
771
891
  Ok(decision) => decision,
772
892
  Err(_) => {
773
893
  let (repaired, _) = send_chat_with_fallback(
774
- config,
894
+ &active_config,
775
895
  &ChatRequest {
776
896
  message: format!(
777
897
  "Your previous response was not valid Mint agent JSON.\n\
@@ -779,12 +899,13 @@ where
779
899
  Do not use markdown.\n\nPrevious response:\n{}",
780
900
  truncate(&response.text)
781
901
  ),
782
- system_instruction: system_prompt.clone(),
902
+ system_instruction: active_system_prompt.clone(),
783
903
  chat_id: Some(chat_id.to_owned()),
784
904
  image_data_uri: None,
785
905
  audio_data_uri: None,
786
906
  document_attachment: None,
787
907
  workspace_path: None,
908
+ agent_id: None,
788
909
  },
789
910
  )
790
911
  .await?;
@@ -1115,7 +1236,7 @@ where
1115
1236
  .collect::<Vec<_>>()
1116
1237
  .join("\n");
1117
1238
  Ok(format!(
1118
- "{formatted}\n\nNote: Web search succeeded using {provider} Search. In your finish summary, you MUST state that you found this information using the {provider} Search API (e.g. \"มิ้นท์ค้นหาข้อมูลนี้มาจาก {provider} Search นะคะ\")."
1239
+ "{formatted}\n\nNote: Web search succeeded using {provider} Search. In your finish summary, you MUST:\n1. Answer the user's question using the information above.\n2. Mention that you found this information via {provider} Search (e.g. \"I found this information using {provider} Search.\").\nDo NOT list sources manually — the UI will display them automatically."
1119
1240
  ))
1120
1241
  }
1121
1242
  }
@@ -1776,8 +1897,9 @@ fn action_fingerprint(decision: &AgentDecision) -> String {
1776
1897
  }
1777
1898
 
1778
1899
  fn initial_observation(task: &str, root: &Path, skills: &str) -> String {
1900
+ let now = chrono::Local::now().format("%Y-%m-%d %H:%M:%S %Z").to_string();
1779
1901
  let mut observation = format!(
1780
- "Task: {task}\nWorkspace: {}\nLearned skills:\n{}\n",
1902
+ "Current Time: {now}\nTask: {task}\nWorkspace: {}\nLearned skills:\n{}\n",
1781
1903
  root.display(),
1782
1904
  if skills.trim().is_empty() {
1783
1905
  "(none)"
@@ -2127,6 +2249,7 @@ Example response:
2127
2249
  audio_data_uri: None,
2128
2250
  document_attachment: None,
2129
2251
  workspace_path: None,
2252
+ agent_id: None,
2130
2253
  };
2131
2254
 
2132
2255
  // Send the chat request to LLM
@@ -2185,6 +2308,7 @@ mod tests {
2185
2308
  audio_data_uri: None,
2186
2309
  document_attachment: None,
2187
2310
  workspace_path: None,
2311
+ agent_id: None,
2188
2312
  };
2189
2313
  assert_eq!(
2190
2314
  enrich_request(&store, &request).unwrap().system_instruction,
@@ -2290,4 +2414,49 @@ mod tests {
2290
2414
 
2291
2415
  assert_eq!(classification.mode.as_str(), "readOnly");
2292
2416
  }
2417
+
2418
+ #[test]
2419
+ fn test_resolve_agent_config() {
2420
+ let mut config = MintConfig::default();
2421
+ config.agents = vec![
2422
+ AgentConfig {
2423
+ id: "planner".into(),
2424
+ name: "Planner".into(),
2425
+ provider: "openai".into(),
2426
+ model: "gpt-4o".into(),
2427
+ api_key: Some("test-key".into()),
2428
+ system_instruction: "Planner instruction".into(),
2429
+ enabled: true,
2430
+ },
2431
+ AgentConfig {
2432
+ id: "coder".into(),
2433
+ name: "Coder".into(),
2434
+ provider: "gemini".into(),
2435
+ model: "gemini-2.5-flash".into(),
2436
+ api_key: None,
2437
+ system_instruction: "Coder instruction".into(),
2438
+ enabled: true,
2439
+ },
2440
+ ];
2441
+
2442
+ let (cfg, instr, name, model) = resolve_agent_config(&config, Some("planner"), &[]);
2443
+ assert_eq!(cfg.ai_provider, "openai");
2444
+ assert_eq!(cfg.openai_model, "gpt-4o");
2445
+ assert_eq!(cfg.openai_api_key, "test-key");
2446
+ assert_eq!(instr, "Planner instruction");
2447
+ assert_eq!(name, Some("Planner".to_string()));
2448
+ assert_eq!(model, Some("gpt-4o".to_string()));
2449
+
2450
+ let (cfg, instr, name, model) = resolve_agent_config(&config, None, &[]);
2451
+ assert_eq!(cfg.ai_provider, "openai");
2452
+ assert_eq!(instr, "Planner instruction");
2453
+ assert_eq!(name, Some("Planner".to_string()));
2454
+
2455
+ let trajectory = vec!["Step 1:\n- Action: create_plan\n- Observation: all planned".to_string()];
2456
+ let (cfg, instr, name, model) = resolve_agent_config(&config, None, &trajectory);
2457
+ assert_eq!(cfg.ai_provider, "gemini");
2458
+ assert_eq!(instr, "Coder instruction");
2459
+ assert_eq!(name, Some("Coder".to_string()));
2460
+ assert_eq!(model, Some("gemini-2.5-flash".to_string()));
2461
+ }
2293
2462
  }
@@ -10,6 +10,8 @@ pub struct TtsUrl {
10
10
  }
11
11
 
12
12
  pub fn google_tts_urls(text: &str, language: &str) -> Vec<TtsUrl> {
13
+ let has_thai = text.chars().any(|c| ('\u{0e00}'..='\u{0e7f}').contains(&c));
14
+ let tl = if has_thai { "th" } else { language };
13
15
  let chunks = split_text(text, MAX_GOOGLE_TTS_CHARS);
14
16
  let total = chunks.len();
15
17
  chunks
@@ -19,7 +21,7 @@ pub fn google_tts_urls(text: &str, language: &str) -> Vec<TtsUrl> {
19
21
  url: format!(
20
22
  "https://translate.google.com/translate_tts?ie=UTF-8&q={}&tl={}&client=tw-ob&idx={index}&total={total}&textlen={}",
21
23
  encode_component(&chunk),
22
- encode_component(language),
24
+ encode_component(tl),
23
25
  chunk.chars().count()
24
26
  ),
25
27
  short_text: chunk,
@@ -0,0 +1,9 @@
1
+ [Desktop Entry]
2
+ Name=Mint Agent
3
+ Comment=A native Tauri desktop AI assistant with a Rust backend and React UI
4
+ Exec=mint-desktop
5
+ Icon=com.pheem49.mint
6
+ Type=Application
7
+ Terminal=false
8
+ Categories=Utility;Development;
9
+ StartupWMClass=mint-desktop
@@ -0,0 +1,35 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <component type="desktop-application">
3
+ <id>com.pheem49.mint</id>
4
+ <metadata_license>CC0-1.0</metadata_license>
5
+ <project_license>MIT</project_license>
6
+ <name>Mint Agent</name>
7
+ <summary>A native Tauri desktop AI assistant with a Rust backend and React UI</summary>
8
+ <description>
9
+ <p>
10
+ Mint Agent is a native desktop AI assistant built on Tauri. It features a modern, reactive React UI and a powerful Rust backend to assist you with tasks, run local command orchestrations, perform screen captures, and run workflows seamlessly.
11
+ </p>
12
+ <p>
13
+ Features:
14
+ </p>
15
+ <ul>
16
+ <li>High performance and lightweight memory footprint.</li>
17
+ <li>Local Rust agent orchestrator.</li>
18
+ <li>Smart context integration and tool execution.</li>
19
+ <li>Multi-provider AI chat and image generation tools.</li>
20
+ </ul>
21
+ </description>
22
+ <launchable type="desktop-id">com.pheem49.mint.desktop</launchable>
23
+ <screenshots>
24
+ <screenshot type="default">
25
+ <caption>Mint Agent main chat interface and workspaces</caption>
26
+ <image>https://raw.githubusercontent.com/pheem49/Mint-CLI/main/assets/Mint_Desktop.png</image>
27
+ </screenshot>
28
+ </screenshots>
29
+ <url type="homepage">https://github.com/pheem49/Mint-CLI</url>
30
+ <url type="bugtracker">https://github.com/pheem49/Mint-CLI/issues</url>
31
+ <provides>
32
+ <binary>mint-desktop</binary>
33
+ </provides>
34
+ <developer_name>pheem49</developer_name>
35
+ </component>
@@ -0,0 +1,52 @@
1
+ app-id: com.pheem49.mint
2
+ runtime: org.gnome.Platform
3
+ runtime-version: '47'
4
+ sdk: org.gnome.Sdk
5
+ sdk-extensions:
6
+ - org.freedesktop.Sdk.Extension.rust-stable
7
+ command: mint-desktop
8
+ build-options:
9
+ append-path: /usr/lib/sdk/rust-stable/bin
10
+ env:
11
+ PKG_CONFIG_PATH: /app/lib/pkgconfig:/app/lib64/pkgconfig:/usr/lib/pkgconfig:/usr/share/pkgconfig
12
+ LDFLAGS: -L/app/lib -L/app/lib64
13
+ LD_LIBRARY_PATH: /app/lib:/app/lib64
14
+ TAURI_ENV_DEBUG: "false"
15
+ finish-args:
16
+ # Graphic sockets for UI
17
+ - --socket=x11
18
+ - --socket=wayland
19
+ - --device=dri
20
+ - --share=ipc
21
+ # Network permission for AI Agent tasks and APIs
22
+ - --share=network
23
+ # Audio notifications/TTS
24
+ - --socket=pulseaudio
25
+ # Filesystem permissions matching application config scope
26
+ - --filesystem=xdg-config/mint:create
27
+ # D-Bus permissions for Tray Icons (AppIndicator)
28
+ - --talk-name=org.ayatana
29
+ - --talk-name=org.kde.StatusNotifierWatcher
30
+ modules:
31
+ # Reference Flathub's shared module for libayatana-appindicator (requires cloning shared-modules repository)
32
+ - ../shared-modules/libayatana-appindicator/libayatana-appindicator-gtk3.json
33
+ # Note: For strict Flathub compliance, npm and cargo packages should be generated
34
+ # offline using flatpak-node-generator and flatpak-cargo-generator.
35
+ # This manifest represents the build structure using the project source directory.
36
+ - name: mint-desktop
37
+ buildsystem: simple
38
+ build-options:
39
+ build-args:
40
+ - --share=network
41
+ build-commands:
42
+ # Build the Tauri Rust backend binary (Frontend UI must be built on the host first)
43
+ - cargo build --release --bin mint-desktop
44
+ # Install executable, desktop shortcut, metainfo, and app icon
45
+ - install -Dm755 target/release/mint-desktop /app/bin/mint-desktop
46
+ - install -Dm644 flatpak/com.pheem49.mint.desktop /app/share/applications/com.pheem49.mint.desktop
47
+ - install -Dm644 flatpak/com.pheem49.mint.metainfo.xml /app/share/metainfo/com.pheem49.mint.metainfo.xml
48
+ - install -Dm644 assets/icon.png /app/share/icons/hicolor/512x512/apps/com.pheem49.mint.png
49
+ sources:
50
+ - type: git
51
+ url: https://github.com/pheem49/Mint-CLI.git
52
+ branch: main
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pheem49/mint",
3
- "version": "1.8.1",
3
+ "version": "1.8.2",
4
4
  "description": "A native Tauri desktop AI assistant with a Rust backend and React UI.",
5
5
  "scripts": {
6
6
  "dev:web": "vite --config vite.config.web.ts",
@@ -0,0 +1,120 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: master
6
+ pull_request:
7
+ branches: master
8
+ workflow_dispatch:
9
+
10
+ permissions:
11
+ contents: read
12
+
13
+ jobs:
14
+ CI:
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ # 4.2.2
18
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
19
+ with:
20
+ persist-credentials: false
21
+
22
+ - name: Set up dependencies
23
+ run: |
24
+ sudo add-apt-repository ppa:flatpak/stable
25
+ sudo apt-get update
26
+ sudo apt-get install -y flatpak dbus-daemon jq
27
+ flatpak remote-add --user --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
28
+ flatpak install flathub -y org.flatpak.Builder
29
+
30
+ - name: Validate manifests
31
+ run: |
32
+ set -e
33
+ for i in $(find . -type f -name "*.json"); do flatpak run org.flatpak.Builder --show-manifest "$i"; done
34
+ rm -rf .flatpak-builder
35
+
36
+ find . -maxdepth 1 -mindepth 1 -type d ! -path './.github' ! -path './.git' | while read dir; do
37
+ if [ "$(find "$dir" -maxdepth 1 -type f -name '*.json' | wc -l)" -eq 0 ]; then
38
+ echo "Error: $dir has no JSON manifest"
39
+ exit 1
40
+ fi
41
+ done
42
+
43
+ files="$(find . -type f \( -name '*.yml' -o -name '*.yaml' \) ! -path './.github/*' ! -path './.git')"
44
+ if [ -n "$files" ]; then
45
+ echo "Error: YML/YAML file found: $files"
46
+ exit 1
47
+ fi
48
+
49
+ - name: Validate JSON
50
+ run: |
51
+ find . -type f -name '*.json' -exec sh -c 'for f do jq empty "$f" 2>&1 >/dev/null | sed "s|^|$f: |"; done' sh {} \;
52
+
53
+ - name: Build changed manifests against stable Freedesktop SDK
54
+ if: github.event_name == 'pull_request'
55
+ env:
56
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
57
+ GH_REPO: ${{ github.repository }}
58
+ run: |
59
+ set -e
60
+ FILES=$(gh pr view "${{ github.event.number }}" --json files --jq '.files[].path')
61
+
62
+ for f in $FILES; do
63
+ if [[ "$f" == *.json && -f "$f" ]]; then
64
+ echo "Building manifest for $f"
65
+
66
+ RUNTIME_VERSION=$(flatpak remote-ls --columns=ref flathub \
67
+ | grep "runtime/org.freedesktop.Platform/x86_64/" \
68
+ | sed 's|.*/||' \
69
+ | sort -V \
70
+ | tail -n1)
71
+
72
+ cat > org.example.stable.yml <<EOF
73
+ id: org.example.stable
74
+ runtime: org.freedesktop.Platform
75
+ runtime-version: '$RUNTIME_VERSION'
76
+ sdk: org.freedesktop.Sdk
77
+ modules:
78
+ - $f
79
+ EOF
80
+
81
+ cat org.example.stable.yml
82
+ dbus-run-session flatpak run org.flatpak.Builder --verbose --user --force-clean \
83
+ --install-deps-from=flathub builddir org.example.stable.yml
84
+ fi
85
+ done
86
+
87
+ - name: Build changed manifests against oldstable Freedesktop SDK
88
+ if: github.event_name == 'pull_request'
89
+ env:
90
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
91
+ GH_REPO: ${{ github.repository }}
92
+ run: |
93
+ set -e
94
+ FILES=$(gh pr view "${{ github.event.number }}" --json files --jq '.files[].path')
95
+
96
+ for f in $FILES; do
97
+ if [[ "$f" == *.json && -f "$f" ]]; then
98
+ echo "Building manifest for $f"
99
+
100
+ RUNTIME_VERSION=$(flatpak remote-ls --columns=ref flathub \
101
+ | grep "runtime/org.freedesktop.Platform/x86_64/" \
102
+ | sed 's|.*/||' \
103
+ | sort -V \
104
+ | tail -n2|head -1)
105
+
106
+ cat > org.example.oldstable.yml <<EOF
107
+ id: org.example.oldstable
108
+ runtime: org.freedesktop.Platform
109
+ runtime-version: '$RUNTIME_VERSION'
110
+ sdk: org.freedesktop.Sdk
111
+ modules:
112
+ - $f
113
+ EOF
114
+
115
+ cat org.example.oldstable.yml
116
+ dbus-run-session flatpak run org.flatpak.Builder --verbose --user --force-clean \
117
+ --install-deps-from=flathub builddir org.example.oldstable.yml
118
+ fi
119
+ done
120
+
@@ -0,0 +1,28 @@
1
+ name: Check for updates
2
+ on:
3
+ schedule:
4
+ - cron: "0 0 1,21 * *"
5
+ workflow_dispatch:
6
+
7
+ jobs:
8
+ flatpak-external-data-checker:
9
+ runs-on: ubuntu-latest
10
+ strategy:
11
+ matrix:
12
+ branch: [ master ]
13
+ steps:
14
+ # 4.2.2
15
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
16
+ with:
17
+ ref: ${{ matrix.branch }}
18
+
19
+ - uses: docker://ghcr.io/flathub-infra/flatpak-external-data-checker:latest@sha256:9e64f59dc8b92b4e7cf325a3f2ef98a64beaf721b58803801d3bf66269203221
20
+ env:
21
+ GIT_AUTHOR_NAME: flathubbot
22
+ GIT_COMMITTER_NAME: flathubbot
23
+ GIT_AUTHOR_EMAIL: sysadmin@flathub.org
24
+ GIT_COMMITTER_EMAIL: sysadmin@flathub.org
25
+ EMAIL: sysadmin@flathub.org
26
+ GITHUB_TOKEN: ${{ secrets.FLATHUBBOT_TOKEN }}
27
+ with:
28
+ entrypoint: ./update-checker.sh
@@ -0,0 +1,23 @@
1
+ # Fallback on Flathub admins for unowned shared modules
2
+ * @flathub/reviewers
3
+
4
+ update-checker.sh @flathub/reviewers
5
+ .github/ @flathub/reviewers
6
+
7
+ /dbus-glib/ @TingPing
8
+ /clutter/ @A6GibKm
9
+ /gtk2/ @TingPing
10
+ /intltool/ @TingPing
11
+ /libappindicator/ @TingPing
12
+ /libcanberra/ @hadess
13
+ /libusb/ @A6GibKm
14
+ /physfs/ @Mailaender
15
+ /python2.7/ @bilelmoussaoui
16
+ /linux-audio/ @hfiguiere
17
+ /libsoup/ @hfiguiere
18
+ /mac/ @enzo1982
19
+ /luajit/ @ranisalt
20
+ /lzo/ @AKoskovich
21
+ /squashfs-tools/ @AKoskovich
22
+ /libayatana-appindicator/ @AKoskovich
23
+ /SDL2/ @tothxa