@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.
Files changed (200) 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 +137 -58
  5. package/bin/mint +0 -0
  6. package/crates/mint-cli/src/agent.rs +150 -45
  7. package/crates/mint-cli/src/image.rs +8 -8
  8. package/crates/mint-cli/src/main.rs +929 -412
  9. package/crates/mint-cli/src/onboard.rs +108 -108
  10. package/crates/mint-cli/src/setup.rs +143 -143
  11. package/crates/mint-core/src/agent_loop.rs +1 -0
  12. package/crates/mint-core/src/api_server.rs +108 -52
  13. package/crates/mint-core/src/browser.rs +56 -1
  14. package/crates/mint-core/src/channels.rs +1 -0
  15. package/crates/mint-core/src/chat.rs +126 -8
  16. package/crates/mint-core/src/code_tools.rs +18 -20
  17. package/crates/mint-core/src/config.rs +245 -17
  18. package/crates/mint-core/src/image_gen.rs +5 -5
  19. package/crates/mint-core/src/lib.rs +16 -2
  20. package/crates/mint-core/src/memory.rs +6 -1
  21. package/crates/mint-core/src/orchestration.rs +260 -72
  22. package/crates/mint-core/src/pictures.rs +3 -4
  23. package/crates/mint-core/src/semantic.rs +1 -1
  24. package/crates/mint-core/src/shell.rs +1 -1
  25. package/crates/mint-core/src/skills.rs +46 -19
  26. package/crates/mint-core/src/tts.rs +3 -1
  27. package/flatpak/com.pheem49.mint.desktop +9 -0
  28. package/flatpak/com.pheem49.mint.metainfo.xml +35 -0
  29. package/flatpak/com.pheem49.mint.yaml +52 -0
  30. package/package.json +1 -1
  31. package/shared-modules/.github/workflows/ci.yml +120 -0
  32. package/shared-modules/.github/workflows/update.yaml +28 -0
  33. package/shared-modules/CODEOWNERS +23 -0
  34. package/shared-modules/README.md +79 -0
  35. package/shared-modules/SDL/README.md +3 -0
  36. package/shared-modules/SDL/SDL-1.2.15.json +51 -0
  37. package/shared-modules/SDL/SDL_Pango-0.1.2-API-adds.patch +118 -0
  38. package/shared-modules/SDL/SDL_image-1.2.12.json +25 -0
  39. package/shared-modules/SDL/SDL_mixer-1.2.12.json +27 -0
  40. package/shared-modules/SDL/SDL_net-1.2.8.json +19 -0
  41. package/shared-modules/SDL/SDL_pango-0.1.2.json +26 -0
  42. package/shared-modules/SDL/SDL_ttf-2.0.11.json +28 -0
  43. package/shared-modules/SDL/libsdl-1.2.15-strict-prototypes.patch +316 -0
  44. package/shared-modules/SDL/sdl-check-for-SDL_VIDEO_X11_BACKINGSTORE.patch +24 -0
  45. package/shared-modules/SDL/sdl-libx11-build.patch +59 -0
  46. package/shared-modules/SDL/sdl-sysloadso-buffer-length.patch +27 -0
  47. package/shared-modules/SDL/sdl12-compat.json +22 -0
  48. package/shared-modules/SDL2/SDL2_image.json +27 -0
  49. package/shared-modules/SDL2/SDL2_ttf.json +29 -0
  50. package/shared-modules/cld2/CMakeLists.txt +157 -0
  51. package/shared-modules/cld2/cld2.json +24 -0
  52. package/shared-modules/clutter/clutter.json +72 -0
  53. package/shared-modules/dbus-glib/dbus-glib.json +29 -0
  54. package/shared-modules/glew/glew.json +36 -0
  55. package/shared-modules/glu/glu-9.json +12 -0
  56. package/shared-modules/gtk2/arc-gtk2-theme-Replace-Inkscape-dependency-with-rsvg-convert.patch +180 -0
  57. package/shared-modules/gtk2/gtk2-common-themes.json +360 -0
  58. package/shared-modules/gtk2/gtk2-fix-crash-in-show-uri.patch +30 -0
  59. package/shared-modules/gtk2/gtk2-gcc14.patch +281 -0
  60. package/shared-modules/gtk2/gtk2-gcc15.patch +250 -0
  61. package/shared-modules/gtk2/gtk2-murrine-c99.patch +34 -0
  62. package/shared-modules/gtk2/gtk2-use-adwaita-theme.patch +80 -0
  63. package/shared-modules/gtk2/gtk2.json +120 -0
  64. package/shared-modules/gtk2/ibus-gcc15.patch +13 -0
  65. package/shared-modules/gtk2/murrine-engine-fix-crash.patch +12 -0
  66. package/shared-modules/gtk2/readme.md +10 -0
  67. package/shared-modules/intltool/intltool-0.51.json +20 -0
  68. package/shared-modules/intltool/intltool-perl5.26-regex-fixes.patch +59 -0
  69. package/shared-modules/lame/0001-Build-xmm_quantize_sub.c-with-msse.patch +34 -0
  70. package/shared-modules/lame/0002-Include-GTK-1-autoconf-directives-in-build-system.patch +222 -0
  71. package/shared-modules/lame/0003-Patch-out-remaining-ansi2knr.patch +70 -0
  72. package/shared-modules/lame/0004-initscr-is-not-used-anywhere-in-lame-sourcetree.patch +41 -0
  73. package/shared-modules/lame/0005-Update-autoconf.patch +81 -0
  74. package/shared-modules/lame/lame-3.99.5.json +32 -0
  75. package/shared-modules/libappindicator/libappindicator-gtk2-12.10.json +140 -0
  76. package/shared-modules/libappindicator/libappindicator-gtk3-12.10.json +140 -0
  77. package/shared-modules/libappindicator/libappindicator-gtk3-introspection-12.10.json +140 -0
  78. package/shared-modules/libappindicator/patches/0001-libappindicator-ftbfs.patch +20 -0
  79. package/shared-modules/libappindicator/patches/0002-libappindicator-no-python.patch +888 -0
  80. package/shared-modules/libappindicator/patches/0003-libappindicator-fix-crash-from-incorrect-signal-emission.patch +74 -0
  81. package/shared-modules/libappindicator/patches/0004-libappindicator-fix-crash-iterating-icon-themes.patch +11 -0
  82. package/shared-modules/libayatana-appindicator/0001-Fix-HAVE_VALGRIND-AM_CONDITIONAL.patch +51 -0
  83. package/shared-modules/libayatana-appindicator/0001-Make-introspection-configurable.patch +44 -0
  84. package/shared-modules/libayatana-appindicator/libayatana-appindicator-gtk3.json +121 -0
  85. package/shared-modules/libcanberra/0001-gtk-Don-t-assume-all-GdkDisplays-are-GdkX11Displays-.patch +123 -0
  86. package/shared-modules/libcanberra/libcanberra.json +44 -0
  87. package/shared-modules/libmad/libmad.json +19 -0
  88. package/shared-modules/libsecret/libsecret.json +23 -0
  89. package/shared-modules/libsoup/libsoup-2.4.json +14 -0
  90. package/shared-modules/libusb/libusb.json +27 -0
  91. package/shared-modules/linux-audio/dssi.json +31 -0
  92. package/shared-modules/linux-audio/fftw3f-static.json +44 -0
  93. package/shared-modules/linux-audio/fftw3f.json +42 -0
  94. package/shared-modules/linux-audio/fluidsynth2-static.json +36 -0
  95. package/shared-modules/linux-audio/fluidsynth2.json +25 -0
  96. package/shared-modules/linux-audio/ladspa.json +26 -0
  97. package/shared-modules/linux-audio/lash.json +35 -0
  98. package/shared-modules/linux-audio/libinstpatch.json +16 -0
  99. package/shared-modules/linux-audio/liblo-static.json +22 -0
  100. package/shared-modules/linux-audio/liblo.json +17 -0
  101. package/shared-modules/linux-audio/lilv-static.json +94 -0
  102. package/shared-modules/linux-audio/lilv.json +89 -0
  103. package/shared-modules/linux-audio/lrdf.json +57 -0
  104. package/shared-modules/linux-audio/lv2.json +20 -0
  105. package/shared-modules/linux-audio/patches/lash/0001-configure-remove-aclocal-m4.patch +29 -0
  106. package/shared-modules/linux-audio/patches/lash/0002-Fix-build-with-recent-gcc.patch +73 -0
  107. package/shared-modules/linux-audio/patches/lash/0003-Fix-linking.patch +136 -0
  108. package/shared-modules/linux-audio/patches/raptor-libxml.patch +31 -0
  109. package/shared-modules/linux-audio/patches/stk-install.sh +54 -0
  110. package/shared-modules/linux-audio/stk.json +28 -0
  111. package/shared-modules/lua5.1/0004-Fix-stack-overflow-in-vararg-functions.patch +21 -0
  112. package/shared-modules/lua5.1/lua-5.1.5-so.patch +43 -0
  113. package/shared-modules/lua5.1/lua-5.1.5.json +42 -0
  114. package/shared-modules/lua5.3/lua-5.3.5.json +41 -0
  115. package/shared-modules/lua5.3/lua.pc.in +8 -0
  116. package/shared-modules/lua5.3/luaconf.patch +47 -0
  117. package/shared-modules/lua5.3/makefile-add-liblua.so-rule.patch +47 -0
  118. package/shared-modules/lua5.4/lua-5.4.json +41 -0
  119. package/shared-modules/lua5.4/lua.pc.in +8 -0
  120. package/shared-modules/lua5.4/luaconf.patch +34 -0
  121. package/shared-modules/lua5.4/makefile-add-liblua.so-rule.patch +42 -0
  122. package/shared-modules/luajit/luajit.json +30 -0
  123. package/shared-modules/lzo/lzo.json +27 -0
  124. package/shared-modules/mac/mac.json +18 -0
  125. package/shared-modules/physfs/physfs.json +26 -0
  126. package/shared-modules/pygame/audiofile-gcc6.patch +21 -0
  127. package/shared-modules/pygame/cython-fixes.patch +34 -0
  128. package/shared-modules/pygame/fluidsynth-no-rawmidi.patch +69 -0
  129. package/shared-modules/pygame/glib.patch +25 -0
  130. package/shared-modules/pygame/pygame1-python2.json +157 -0
  131. package/shared-modules/pygtk/pygtk-c99.patch +15 -0
  132. package/shared-modules/pygtk/pygtk.json +117 -0
  133. package/shared-modules/pygtk/pygtk.patch +39 -0
  134. package/shared-modules/python2.7/python-2.7.json +48 -0
  135. package/shared-modules/smpeg/smpeg-0.4.5.json +50 -0
  136. package/shared-modules/smpeg/smpeg-am-prog-as.patch +12 -0
  137. package/shared-modules/smpeg/smpeg-export-mpegaudio-class.patch +17 -0
  138. package/shared-modules/smpeg/smpeg-gcc6.patch +40 -0
  139. package/shared-modules/smpeg/smpeg-no-gtk.patch +37 -0
  140. package/shared-modules/squashfs-tools/squashfs-tools.json +25 -0
  141. package/shared-modules/update-checker.sh +50 -0
  142. package/shared-modules/vorbisgain/0001-temp_files.patch +75 -0
  143. package/shared-modules/vorbisgain/0002-errno.patch +33 -0
  144. package/shared-modules/vorbisgain/0003-manpage.patch +248 -0
  145. package/shared-modules/vorbisgain/0004-vorbisgain_mtime.patch +183 -0
  146. package/shared-modules/vorbisgain/0005-double_fclose.patch +21 -0
  147. package/shared-modules/vorbisgain/0006-manpage_hyphens.patch +56 -0
  148. package/shared-modules/vorbisgain/0007-recursively_spelling.patch +14 -0
  149. package/shared-modules/vorbisgain/0008-manpage_recursion_mistake.patch +23 -0
  150. package/shared-modules/vorbisgain/0009-hardening.patch +13 -0
  151. package/shared-modules/vorbisgain/0010-fclose.patch +13 -0
  152. package/shared-modules/vorbisgain/README.md +23 -0
  153. package/shared-modules/vorbisgain/vorbisgain_0.37-2.json +29 -0
  154. package/src/renderer/shared/agentProgress.ts +145 -0
  155. package/src/renderer/shared/calculator.ts +52 -0
  156. package/src/renderer/shared/components/AgentActivityDrawer.tsx +72 -0
  157. package/src/renderer/shared/components/AgentActivityTable.tsx +85 -0
  158. package/src/renderer/shared/components/ApprovalCard.tsx +93 -0
  159. package/src/renderer/shared/components/ChatCodeBlock.tsx +75 -0
  160. package/src/renderer/shared/components/ThinkingBlock.tsx +101 -0
  161. package/src/renderer/shared/constants/models.ts +91 -0
  162. package/src/renderer/shared/platform.ts +82 -0
  163. package/src/renderer/shared/types.ts +140 -0
  164. package/src/renderer/shared/utils/agentActivity.ts +187 -0
  165. package/src/renderer/shared/utils/approval.ts +1 -0
  166. package/src/renderer/shared/utils/approval.tsx +64 -0
  167. package/src/renderer/shared/utils/fileIcons.ts +135 -0
  168. package/src/renderer/shared/utils/markdown.tsx +347 -0
  169. package/src/renderer/shared/utils/providers.ts +36 -0
  170. package/src/renderer/shared/utils/speech.ts +216 -0
  171. package/src/renderer/shared/utils/ui.ts +147 -0
  172. package/src/renderer/src/agentProgress.ts +11 -39
  173. package/src/renderer/src/calculator.ts +3 -46
  174. package/src/renderer/src/components/ChatPanel.tsx +219 -1308
  175. package/src/renderer/src/components/MintDashboard.tsx +67 -170
  176. package/src/renderer/src/components/PicturesLibrary.tsx +32 -8
  177. package/src/renderer/src/components/Settings/AgentsTab.tsx +381 -0
  178. package/src/renderer/src/components/Settings/AutomationTab.tsx +0 -22
  179. package/src/renderer/src/components/Settings/GeneralTab.tsx +256 -2
  180. package/src/renderer/src/components/SettingsWindow.tsx +120 -3
  181. package/src/renderer/src/components/WorkspacePanel.tsx +7 -125
  182. package/src/renderer/src/css/styles.css +100 -0
  183. package/src/renderer/src/tauri.ts +128 -143
  184. package/src/renderer/src-web/agentProgress.ts +11 -39
  185. package/src/renderer/src-web/calculator.ts +3 -46
  186. package/src/renderer/src-web/components/ChatPanel.tsx +219 -1306
  187. package/src/renderer/src-web/components/MintDashboard.tsx +42 -170
  188. package/src/renderer/src-web/components/PicturesLibrary.tsx +23 -29
  189. package/src/renderer/src-web/components/Settings/AgentsTab.tsx +381 -0
  190. package/src/renderer/src-web/components/Settings/AutomationTab.tsx +0 -22
  191. package/src/renderer/src-web/components/Settings/GeneralTab.tsx +254 -3
  192. package/src/renderer/src-web/components/SettingsWindow.tsx +127 -3
  193. package/src/renderer/src-web/css/styles.css +100 -0
  194. package/src/renderer/src-web/tauri.ts +180 -102
  195. package/src-tauri/src/desktop.rs +18 -16
  196. package/src-tauri/src/discord_rpc.rs +1 -1
  197. package/src-tauri/src/lib.rs +168 -40
  198. package/src-tauri/src/webhooks.rs +1 -0
  199. package/src-tauri/src/workflows.rs +1 -0
  200. package/src-tauri/tauri.conf.json +1 -1
package/Cargo.lock CHANGED
@@ -2095,7 +2095,7 @@ dependencies = [
2095
2095
 
2096
2096
  [[package]]
2097
2097
  name = "mint-cli"
2098
- version = "1.8.1"
2098
+ version = "1.8.2"
2099
2099
  dependencies = [
2100
2100
  "anyhow",
2101
2101
  "base64 0.22.1",
@@ -2114,7 +2114,7 @@ dependencies = [
2114
2114
 
2115
2115
  [[package]]
2116
2116
  name = "mint-core"
2117
- version = "1.8.1"
2117
+ version = "1.8.2"
2118
2118
  dependencies = [
2119
2119
  "base64 0.22.1",
2120
2120
  "chrono",
@@ -2135,7 +2135,7 @@ dependencies = [
2135
2135
 
2136
2136
  [[package]]
2137
2137
  name = "mint-desktop"
2138
- version = "1.8.1"
2138
+ version = "1.8.2"
2139
2139
  dependencies = [
2140
2140
  "base64 0.22.1",
2141
2141
  "dirs",
package/Cargo.toml CHANGED
@@ -7,7 +7,7 @@ members = [
7
7
  resolver = "2"
8
8
 
9
9
  [workspace.package]
10
- version = "1.8.1"
10
+ version = "1.9.0"
11
11
  edition = "2024"
12
12
  license = "AGPL-3.0-only"
13
13
 
package/README.md CHANGED
@@ -113,23 +113,6 @@ Mint is a local-first AI assistant running on your machine, capable of handling
113
113
  - Right-click context menu to delete files/folders with confirmation modals.
114
114
  - Drag-and-drop file mentions in the chat input with automatic spacing and dynamic accent-colored history bubble highlighting.
115
115
 
116
- ## What's New in v1.8.1
117
-
118
- - **File-System Based AI Skills & UI Badges**: Scan and load AI skills from the Global folder (`~/.config/mint/mint-skills/`) and Workspace folders (`.agents/skills/` & `skills/`). Shows source badges (`Workspace` 🟢, `Global` 🔵, `Taught` 🟣) in settings UI and CLI listings (`mint learn --list` and `/learn`) with a clean hidden-content list view.
119
- - **Unified MCP Servers UI & Toggle Controls**: Merged system-discovered servers into a unified list with toggles to enable/disable or install, and red trash can buttons to remove custom servers.
120
- - **Advanced Workspace File Tree & Operations**: Manage files directly from the sidebar UI with file/folder creation buttons, right-click deletion modals, and automatic polling + focus-based syncing.
121
- - **Drag-and-Drop File Mentions**: Drag files from the sidebar to chat input to insert `@filename` with auto-spacing, rendered as outline pills styled with your selected accent color.
122
- - **CLI Agent Interface Polish & Terminal Line Wrapping Fix**: Indented status blocks and confirmation prompts by 2 spaces to align text. Implemented the *Dynamic Breathing Circle System* (`●` ⇄ `○` pulsing during thinking) and fixed terminal duplicate line bugs by counting physical terminal wrapping width and filtering Thai tone marks.
123
- - **AskUser Text Input Modal (Desktop & Web)**: When the agent asks questions, a text input field is rendered inside the approval card so users can write and submit typed answers back to the agent backend.
124
- - **Dynamic Language AI Suggestions**: Auto-translates process suggestions dynamically based on your configured `config.language`.
125
- - **Mobile & Navigation Optimizations**: Mobile-fit Image Studio layout, hamburger menu access, and headers glass-morphism overlay fixes.
126
-
127
- ## What's New in v1.8.0
128
-
129
- - **Integrated Web Search Settings**: Easily toggle between **Brave Search API** and **Google Custom Search API** directly from the General settings tab.
130
- - **Image Generation Providers**: Choose and configure credentials for Stability AI, Ideogram, Replicate, OpenAI DALL-E, and Google NanoBanana (Gemini Images) inside dedicated inline settings cards.
131
- - **Inline Productivity Settings**: Set up Client IDs, secrets, and API keys for native Gmail, Google Calendar, and Notion integrations inline inside the General settings tab.
132
- - **Revamped Plugins Layout**: Moved **Learned AI Skills** (equivalent to `mint learn` in CLI) to the top of the Plugins tab, followed by MCP Servers (External tools), and Built-in Plugins (Spotify and Discord RPC) at the bottom.
133
116
 
134
117
  ## <img src="assets/setup.svg" width="24" height="24" valign="middle" /> Prerequisites
135
118
 
package/Release_Note.md CHANGED
@@ -1,70 +1,109 @@
1
- # Release Notes - Mint Agent v1.8.1
1
+ # Release Notes - Mint Agent v1.9.0
2
2
 
3
- We are excited to release **Mint Agent v1.8.1**! This release introduces powerful local workspace file management features, real-time AI-generated workflow suggestions in the user's active language, mobile layout optimization, and general UI/UX polish.
3
+ We are excited to release **Mint Agent v1.9.0**! This release introduces a configurable Multi-Agent system for sequential collaboration, powerful local workspace file management features, real-time AI-generated workflow suggestions in the user's active language, mobile layout optimization, and general UI/UX polish.
4
4
 
5
5
  ---
6
6
 
7
+ ## 🔌 Custom Provider Support
8
+
9
+ Users can now add any **OpenAI-compatible endpoint** as a fully configurable custom AI provider, giving complete control over which LLM backend Mint uses.
10
+
11
+ ### Backend (`config.rs`, `chat.rs`)
12
+ - **New data model:** Added `CustomProvider`, `CustomProviderModel`, and `CustomProviderHeader` structs to `MintConfig`. Custom providers are persisted to `mint-config.json` under the `customProviders` key.
13
+ - **Provider ID format:** Each custom provider is stored with a user-defined slug ID and is referenced in `ai_provider` as `"custom:<id>"` (e.g. `"custom:myprovider"`).
14
+ - **Chat routing:** `send_chat()` and `stream_chat()` now dispatch `custom:*` providers through `call_custom_provider()` / `stream_custom_provider()`, which use the existing OpenAI-compatible HTTP code path.
15
+ - **Multiple models:** Each provider stores a list of models; the active model is resolved from `customModelSelections` extra config (set by the UI model selector dropdown).
16
+ - **Custom HTTP headers:** All configured headers are applied to every request sent to that provider.
17
+ - **`available_providers()`** now returns `Vec<String>` (up from `Vec<&'static str>`) to accommodate dynamic custom provider IDs.
18
+ - **`resolve_custom_provider()`** helper added to look up a `CustomProvider` by key (strips the `custom:` prefix automatically).
19
+
20
+ ### Frontend (`SettingsWindow.tsx`, `GeneralTab.tsx`, `AgentsTab.tsx`)
21
+ - **Settings → General → Active Provider dropdown** now includes all configured custom providers dynamically.
22
+ - **Model selector:** When a custom provider is selected as the active provider, a second dropdown appears to pick among that provider's configured models.
23
+ - **Custom Providers section:** A new section at the bottom of General settings displays each custom provider as a card. Each card allows inline editing of: Provider ID (slug-validated), Display Name, Base URL, API Key (password), per-model rows (model ID + display name), and per-header rows (name + value). Providers can be added with `+ Add custom provider` and deleted inline.
24
+ - **Agents tab:** Custom providers (with a configured base URL) now appear in the AI Provider dropdown when creating or editing an agent. The model selector shows that provider's configured models.
25
+
26
+ ---
27
+
28
+ ## 🔍 Web Search Source Cards
29
+
30
+ - **Favicon Source Cards:** After a web search, compact clickable source cards now appear above the AI response bubble — each showing the website's favicon, domain name, and a tooltip with the page snippet. Clicking a card opens the source in the browser.
31
+ - **Frontend-only change:** Parsed directly from existing `AgentProgress` `ToolEnd` events — no backend changes required.
32
+ - The AI response also includes a plain-text `Sources:` section listing title and URL for each result used.
33
+
34
+ ---
35
+
36
+
7
37
  ## 🚀 Key Features & Enhancements
8
38
 
9
- ### 📂 1. Native Workspace File Explorer Operations
10
- You can now manage your workspace directory directly from the sidebar without switching to an external editor or using the terminal:
11
- - **New File & New Folder Buttons:** Replaced the legacy "Use Agent" action button with dedicated creation triggers. Inputting a name will immediately create the empty file/folder on disk.
12
- - **Right-Click Deletion:** Right-clicking on any file or directory in the tree view prompts a safety confirmation modal. Upon approval, the item is securely removed from your filesystem.
13
- - **Workspace Auto-Sync:** The file list stays up-to-date automatically using two smart mechanisms:
14
- - **Window Focus Reloading:** Whenever you switch back to the Mint Desktop window (e.g., after editing code in VS Code), it refreshes the file list immediately.
15
- - **Periodic Polling:** Auto-polls the directory structure every 15 seconds.
16
-
17
- ### 💬 2. Drag-and-Drop Mentions with Accent Color Highlight
18
- Referencing files in your conversations is now smoother and visually richer:
19
- - **Trailing Spacing:** Dragging files from the sidebar into the chat input automatically appends spacing (e.g. `@index.html `), allowing you to keep typing immediately.
20
- - **Accent Theme Highlight:** In your chat history, any `@filename` mention is parsed and rendered inside an outline pill container styled dynamically with your selected **Accent Color** theme.
21
-
22
- ### 🌐 3. Dynamic Language AI Suggestions
23
- - Process monitor triggers (such as opening terminal processes) now format real-time queries to your active AI provider.
24
- - Suggestions are dynamically translated and rewritten to match your configured user language (`config.language`), replacing the Thai-only hardcoded templates.
25
- - Features a safe fallback to static trigger defaults if the AI request times out or encounters network errors.
26
-
27
- ### 📱 4. Mobile Layout & Navigation Optimizations (Web View)
28
- - **Image Studio Mobile Fit:** Fixed position clashing media queries resetting Image Studio `.img-studio` offsets to fit smaller screen sizes correctly.
29
- - **Hamburger Menu Visibility:** Rendered the sidebar drawer button (☰) inside the Image Studio header on mobile viewports so users can navigate back.
30
- - **Header Overlaps Resolved:** Added a solid opaque background overlay, glass blur, and borders to the mobile chat header, preventing scrolled messages from clashing with header typography.
31
- - **Mobile Sidebar Drawer Fix:** Prevented the sidebar from collapsing into desktop icon-only configurations on screen widths under 760px, resolving layout drawer compression bugs.
32
-
33
- ### 💅 5. General UX Polish
34
- - **Widescreen Chat Layout:** Expanded the chat conversation box max-width to `1100px` when the assistant avatar model is hidden, optimizing readability on widescreen displays.
35
- - **Global Text Selection:** Unlocked full text selection and copying across the entire application interface (sidebars, panels, buttons, headers) by overriding restricted user-select rules.
36
-
37
- ### 🖥️ 6. CLI Agent Interface Polish & Terminal Line Wrapping Fix
38
- Improved CLI status rendering aesthetics, interactive pacing, and terminal output reliability:
39
- - **Consistent Terminal Padding:** Indented status blocks (Plan, Tasks, Activity, Explored) and confirmation prompt headers by 2 spaces to align with the standard prompt margin and prevent text from sticking to the left edge of the terminal window.
40
- - **Dynamic Breathing Circle System:** Consolidated status symbols into a unified, colored circle layout (`● plan`, `● tasks`, `● activity`, `● explored`) which pulses dynamically between solid and hollow (`●` ⇄ `○`) while the AI is thinking to signify active processing.
41
- - **Wrapping & Thai Combining Characters Fix:** Solved the duplicate/orphaned terminal lines issue caused by text wrapping on narrow screens. It now strips ANSI sequences, filters out Thai combining characters/tone marks that stack vertically, and counts true physical display lines to correctly clear stdout between updates.
42
-
43
- ### 💬 7. AskUser Text Input Modal in Desktop & Web App
44
- Brought parity to the interactive questioning feature between the CLI and GUI versions:
45
- - **Dynamic Input Field:** When the agent runs the `ask_user` tool (asking questions like requesting answers or inputs), a sleek text input textarea is displayed inside the Desktop and Web application's approval card.
46
- - **Answer Submission Backend:** Updated the Tauri backend to handle `ApprovalOutcome::Intercepted(answer)` channels, sending user-typed answers back to the orchestration layer.
47
- - **Activity Log Integration:** Once submitted, the user's typed answer is appended directly to the tool's execution target within the expandable "Working through task" drawer (e.g. `คุณภีมชอบสีอะไรคะ? (Answered: "สีเขียวมิ้นต์")`), maintaining a clear visual history of interactions.
48
-
49
- ### 🐙 8. GitKraken MCP Auto-Detection
50
- Enabled a seamless developer onboarding experience by auto-discovering GitKraken on the host machine:
51
- - **Automatic Discovery:** Scans the user's local PATH during configuration load to check if `gk` (GitKraken CLI) is available on the system.
52
- - **Auto-Config Injection:** If detected, automatically configures and adds the GitKraken MCP server (`gk mcp`) to the user's `mint-config.json` file.
53
- - **Github Release Integration:** Updated the CI/CD `.github/workflows/release.yml` file to parse and use `Release_Note.md` directly for the body description of GitHub Releases.
54
-
55
- ### 🏷️ 9. File-System Based AI Skills & Source Badges
56
- Upgraded the AI skills loading pipeline and settings interface:
57
- - **Dual Workspace Scanning:** Automatically discovers and loads `.md` / `.txt` skills from both `.agents/skills/` and `skills/` folders in the active workspace.
58
- - **Location Color Badges:** Displays tags indicating whether skills come from Workspace (🟢 green), Global (🔵 blue), or Taught database (🟣 purple) in settings UI and CLI list output (`mint learn --list` and `/learn`).
59
- - **Clean List UI:** Hides the lengthy file content preview block under each skill, rendering a much cleaner and concise layout.
60
-
61
- ### 🛠️ 10. Unified MCP Servers & Toggle Management
62
- - **Consolidated List:** Merged all system-discovered tools (Docker, Git, GitHub, Node) into the unified MCP Servers list.
63
- - **Individual Toggle Switches:** Enables/disables or installs MCP servers dynamically with instant toggle state styling.
64
- - **Red Trash Can Buttons:** Added a red trash icon button to easily remove custom/manually configured MCP servers.
39
+ ### 🛑 1. Escape (Esc) Key & Stop Button to Cancel AI Agent / Chat
40
+ You can now cancel or stop an active AI stream or agent loop at any point in the web and desktop applications:
41
+ - **Escape Key Press:** Pressing the `Esc` key while the AI is thinking or executing automatically aborts the active stream.
42
+ - **Red Stop Composer Button:** When the AI is running, the composer "Send" button turns into a red "Stop" square icon button, allowing users to stop the generation instantly.
43
+ - **Thinking Label Hints:** Updated the progress indicator label to explicitly display "Thinking for Xs (Esc to cancel)" so users are aware of the shortcut.
44
+
45
+ ### 🎙️ 2. Microphone Active Breathing Aura Glow
46
+ When the microphone/voice mode is active, the boundaries of the chat composer box and the voice status bar light up with a dynamic, breathing green aura, providing intuitive visual feedback.
47
+
48
+ ### 🤖 3. Configurable Multi-Agent System & Collaboration Pipeline
49
+ Users can now configure and run multiple specialized AI agents (e.g. Planner, Coder, Reviewer) within the desktop and web settings panel, allocating custom models, providers, and instructions to each agent:
50
+ - **Global Toggle Switch:** Added a main "Enable Multi-Agent Collaboration" toggle switch at the top of the new "Multi-Agent (Beta)" settings tab to globally turn on/off the agent routing pipeline.
51
+ - **Provider-Specific Dropdowns:** Replaced the text input for model selection with provider-specific dropdown select lists matching the models available in General settings.
52
+ - **Disable All Button:** Added a "Disable All" button allowing users to disable all configured agents instantly in one click.
53
+ - **Real-Time Agent & Model Indicators:** The live thinking message bubble in the chat panel dynamically displays the active agent's name and model in real-time (e.g. `Planner (gemini-2.5-flash) is thinking...`).
54
+
55
+ ### 🖥️ 4. CLI Suggestions Pagination & Ordering
56
+ Improved the autocomplete experience in the terminal:
57
+ - **Pagination (5 Items Max):** Autocomplete suggestions now display a maximum of 5 commands at a time with a page indicator (e.g., `Suggestions (1/4)`), preventing long list clutter.
58
+ - **Alphabetical Sorting:** Autocomplete suggestions are sorted alphabetically at source.
59
+ - **Simplified Exit Options:** Removed `/quit` from the autocomplete suggestions and help output (while retaining hidden execution support) to clean up the interface.
60
+ - **Real-Time Agent & Model Status:** The CLI live thinking status bar dynamically displays which agent and model is executing.
61
+
62
+ ### 📋 5. Fix Clipboard Permission Popup on Text Paste (Ctrl+V) & Desktop Image Paste Fallback
63
+ - Fixed a bug where pasting text (or pressing `Ctrl + V`) would trigger a browser-level clipboard permission warning popup (asking to "Allow Paste").
64
+ - Removed the redundant global `keydown` Ctrl+V listener and the async `navigator.clipboard.read()` fallback on text paste events. The application now correctly relies on standard, synchronous `event.clipboardData` values during paste events, ensuring seamless pasting of both images and text without prompting the user.
65
+ - **Tauri Native Fallback:** Restored an asynchronous fallback using Tauri's native backend `readClipboardImage` command specifically for the desktop application. This solves the Linux/Windows WebView limitations where WebKitGTK and standard web APIs fail to expose file handles in standard paste events.
66
+ - **Double Paste Throttling:** Implemented a 100ms throttle wrapper around the native clipboard read callback, preventing duplicate image attachments caused by concurrent window-level capture and element-level paste event propagation.
67
+
68
+
69
+
70
+ ### 📦 6. Codebase Refactoring & Shared Utilities
71
+ - **Shared UI & Progress Helpers:** Refactored duplicate helper functions and TypeScript interfaces from the desktop renderer (`src/renderer/src`) and web renderer (`src/renderer/src-web`) into the unified `shared` codebase.
72
+ - **Maintainability:** Standardized helper functions across both application targets to prevent future regressions.
73
+
74
+ ### 🖥️ 7. Horizontal Scrolling for CLI Input Box
75
+ - **Arbitrary Input Length:** Removed the single-line input constraint (previously restricted to `term_width - 4`) in the CLI interactive prompt, allowing users to type or edit long prompt instructions.
76
+ - **Dynamic Sliding Window:** Implemented a horizontal scrolling viewport for the single-line prompt box. It dynamically slices and displays a subset of characters surrounding the cursor position to preserve console alignment and layout integrity.
77
+ - **Interactive Cursor Navigation:** Bounded the arrow keys (`Left` and `Right` navigation) to trigger full box redraws, enabling the visible text window to scroll back and forward dynamically as the cursor moves.
78
+
79
+ ### 🖥️ 8. Browser Automation Visual Indicator (Green Aura)
80
+ - **Visual Feedback:** Injects a breathing green glowing border overlay around the viewport of any browser page under active AI control.
81
+ - **Non-Intrusive Design:** Built with `pointer-events: none` and a high z-index to ensure it sits on top of all page elements without blocking clicks, scrolling, or user interactions.
82
+
83
+ ### 🎙️ 9. Client-Side Speech-to-Text Microphone Consolidation
84
+ - **Consolidated Flow**: Standardized the voice interface to client-side Speech-to-Text (`SpeechRecognition`), enabling compatibility with all AI models (Gemini, OpenAI, Claude, etc.) by transcribing voice to text before sending.
85
+ - **Accurate Speech End Detection**: Configured the Speech-to-Text engine to run in continuous mode (`continuous = true`) so it keeps listening continuously across normal speaking pauses. Added a custom silence timer that triggers sending only after a full 2 seconds of silence, and fixed a loop bug by triggering the timer only after the user starts speaking (preventing the mic from cycling on and off during initial silence).
86
+ - **TTS Language Auto-Detection**: Added automatic Thai character detection in both frontend system voice lookup (now matching language tags case-insensitively) and backend Google Translate TTS generation, resolving the issue where Thai responses were read aloud in English voices.
87
+ - **Codebase Simplification & Hook Refactoring**: Extracted all Speech-to-Text logic, Web Speech APIs, silence timers, and React states into a shared, reusable custom hook `useSpeechToText` in [speech.ts](file:///home/pheem49/vscode/Project/Mint-CLI/src/renderer/shared/utils/speech.ts). This cleaned up ~150 lines of duplicate code in both desktop and web `ChatPanel.tsx` components.
88
+ - **Native App Guidance**: Added a helper prompt to notify users if they attempt to record voice in a browser or WebView that doesn't natively support SpeechRecognition (such as Firefox, Safari, or the Tauri desktop application on Linux/Windows), guiding them to use Google Chrome or Microsoft Edge instead.
89
+
90
+ ### 🖼️ 10. Saved Pictures Gallery Pagination & Caching
91
+ - **24-Picture Pagination**: Refactored the Saved Pictures library component to load exactly 24 images initially, replacing the buggy automatic timer loading with a clean, manual "Load More" button at the bottom of the grid.
92
+ - **Cache-Busting Image URLs**: Appended a dynamic timestamp query parameter (`?_t=...`) to the static API picture fetches and individual image URLs. This prevents the browser from loading stale lists or caching broken images, ensuring that clicking "Refresh" successfully resolves any missing or incomplete pictures.
93
+
94
+ ### 🤖 11. AI Model Self-Awareness Context Injection
95
+ - **Dynamic Context Injection**: Updated the core prompt compilation layer to automatically append an `[Active Environment Context]` block to the system instructions. This supplies the active AI model name and provider to the AI model itself, allowing the AI to successfully know its own model configurations in real-time when queried by the user.
96
+
97
+ ### 🎨 12. Material Icon Theme in Agent Activity Tracker
98
+ - **Visual File & Folder Tracking**: The agent activity tracker (e.g. "Exploring file" progress log) now resolves target filenames/foldernames to display specific Material Icon Theme SVGs (e.g. JavaScript icon for `.js`, Rust icon for `.rs` / Cargo directories). This replaces the generic wireframe outline icons, resulting in a cleaner and more polished UI.
99
+
100
+ ### 🎙️ 13. Stricter Voice Reply Settings Control
101
+ - **Strict Control Switch**: The global "Enable Voice Reply" toggle now acts as a strict master switch. When disabled, Mint will never speak responses out loud under any circumstances (including when using voice conversation/microphone mode).
102
+ - **Voice Mode Loop Resumption**: When "Enable Voice Reply" is disabled but voice conversation mode is active, the microphone automatically resumes listening after the AI response is printed on screen, maintaining the continuous hands-free voice loop.
65
103
 
66
104
  ---
67
105
 
106
+
68
107
  ## 🛠️ Codebase Changes
69
108
 
70
109
  ### Tauri Backend (`src-tauri` & `crates/mint-core`)
@@ -75,6 +114,15 @@ Upgraded the AI skills loading pipeline and settings interface:
75
114
  - Change `submit_tool_approval` signature and `ApprovalsState` pending channel type to support `ApprovalOutcome` in `src-tauri/src/lib.rs`.
76
115
  - Add executable search helper `which` and GitKraken auto-detection hooks to `load_config_from` in `crates/mint-core/src/config.rs`.
77
116
  - Support multiple source directory scanning and deduplication of learned skills in `crates/mint-core/src/skills.rs`.
117
+ - Introduce a global `ACTIVE_AGENTS` thread-safe hash map registry and `cancel_agent` API in `crates/mint-core/src/lib.rs` to track active tokio tasks.
118
+ - Register Tauri command `cancel_chat_message` in `src-tauri/src/lib.rs`.
119
+ - Implement `POST /api/cancel-chat` in `crates/mint-core/src/api_server.rs` to cancel running web agent tasks.
120
+ - Add `enable_agent_collaboration` config parameter (defaulting to `false`) in `crates/mint-core/src/config.rs`.
121
+ - Update `resolve_agent_config` in `crates/mint-core/src/orchestration.rs` to return a tuple containing the active agent name and model, and check `enable_agent_collaboration`.
122
+ - Expand `AgentProgress::Thinking` in `crates/mint-core/src/orchestration.rs` to optionally contain `agent_name` and `model_name`.
123
+ - Inject active AI provider and model name environment context inside `enrich_request` and the initial prompt observation inside `crates/mint-core/src/orchestration.rs` so that the model becomes fully self-aware of its configuration and execution metadata.
124
+ - Inject a green aura viewport border style and DOM overlay (`#mint-browser-aura`) into the active browser page before executing CDP automation actions in `crates/mint-core/src/browser.rs` to visually notify users of active AI control.
125
+
78
126
 
79
127
  ### Desktop/Web Frontend (`src/renderer`)
80
128
  - Integrate creation/deletion actions and focus/polling lifecycle listeners inside `WorkspacePanel.tsx`.
@@ -84,12 +132,43 @@ Upgraded the AI skills loading pipeline and settings interface:
84
132
  - Update `activitiesFrom` and `AgentActivity` structure to parse and append the user's answer into the active `ask_user` tool target block upon `ToolEnd`.
85
133
  - Update `LearnedSkill` TypeScript interface in `src/renderer/src/tauri.ts` to include optional `location`.
86
134
  - Render colored location badges, strip lengthy content text boxes, and unify MCP toggles/delete controls in `src/renderer/src/components/Settings/PluginsTab.tsx` and `src/renderer/src-web/components/Settings/PluginsTab.tsx`.
135
+ - Implement `cancelChatMessage` API helpers in `tauri.ts` for desktop and web.
136
+ - Bind global Window keydown listeners for `Escape` key and dynamic "Stop" buttons in `ChatPanel.tsx` and `MintDashboard.tsx` under desktop and web source directories.
137
+ - Enhance microphone connection/permission alert dialogs in `ChatPanel.tsx` to print the exact Web API error message for easier debugging.
138
+ - Add voice-active class state and breathing keyframe animation effects around the chat input boundaries when microphone mode is active.
139
+ - Refine the voice status bar rendering logic to prevent displaying redundant text (such as "Listening Listening...") and display actual user speech transcripts wrapped inside quotes instead.
140
+ - Create new settings tab `AgentsTab.tsx` in desktop and web source directories supporting CRUD operations, provider-specific model dropdown selects, "Disable All" button, and global collaboration toggle.
141
+ - Register the `Multi-Agent (Beta)` tab in the sidebar of `SettingsWindow.tsx`.
142
+ - Update `ChatPanel.tsx` in desktop and web source directories to render the active agent and model names inside the live thinking status message.
143
+ - Remove duplicate "Enable Multi-Agent Review" checkbox from `AutomationTab.tsx`.
144
+ - Remove redundant `handleWindowKeyDown` Ctrl+V listeners, unused `onReadClipboardImage` prop, and `navigator.clipboard.read()` async fallback routines from `ChatPanel.tsx` and `MintDashboard.tsx` in both desktop and web directories to resolve browser clipboard permission warning popups during text pasting.
145
+ - Refactor duplicated types (`DiffHunk`, `FileChange`), helper functions (`numericSetting`, `errorMessage`, `readImage`, `readDocument`, `createTrimmedImagePreview`, `lightenColor`, `hexToRgb`, `applyThemeStyles`), and progress parsers (`parseFileChangesFromProgress`) from the desktop and web components to a central `src/renderer/shared` repository. Corrected a type checking issue by exporting `AgentProgress` and `InteractionMemory` from `shared/agentProgress.ts`.
146
+ - Consolidate microphone interface to client-side Speech-to-Text (`SpeechRecognition`), extract STT states, silence-detection timers, and event listeners into a reusable React hook `useSpeechToText` in [speech.ts](file:///home/pheem49/vscode/Project/Mint-CLI/src/renderer/shared/utils/speech.ts), and clean up both desktop (`src/renderer/src/components/ChatPanel.tsx`) and web (`src/renderer/src-web/components/ChatPanel.tsx`) `ChatPanel` components.
147
+ - Implement 24-picture pagination, a manual "Load More" button, and API/image fetch cache-busters in `PicturesLibrary.tsx` and `tauri.ts` across desktop and web directories.
148
+ - Refactor file and folder icon mappings from `WorkspacePanel.tsx` into a central, reusable utility `src/renderer/shared/utils/fileIcons.ts`.
149
+ - Update `AgentActivityTable.tsx` to resolve target filenames/foldernames and display their respective Material Icon Theme SVGs instead of default wireframe outlines.
150
+ - Update Desktop and Web CSS stylesheets (`styles.css`) to support rendering and scaling Material Icon SVGs inside the agent activity tracker.
151
+ - Update `ChatPanel.tsx` (Desktop and Web) to strictly check the global `enableVoiceReply` setting. If voice reply is disabled but voice conversation mode is active, the microphone listening loop is automatically scheduled to resume without reading the AI response out loud.
87
152
 
88
153
  ### CLI Agent (`crates/mint-cli`)
89
154
  - Redefine live status print lines (`plan_lines`, `tasks_lines`, `activities_lines`, `explored_lines`) to accept progress tick state and apply the `get_bullet` helper.
90
155
  - Update `render_live_status` in `crates/mint-cli/src/agent.rs` to compute true physical lines of terminal wrapped text, using a new `is_thai_combining` filter.
91
156
  - Modify `confirm` in `crates/mint-cli/src/main.rs` to indent confirmation prompts.
92
157
  - Format `mint learn --list` and `/learn` CLI output into a bullet-point summary showing active skill locations and source paths.
158
+ - Register `/multi-agent` slash command to display configured agents and toggle collaboration status via `/multi-agent on` and `/multi-agent off` in `crates/mint-cli/src/main.rs`.
159
+ - Reorder `AUTOCOMPLETE_COMMANDS` alphabetically and simplify exit suggestions by keeping only `/exit`.
160
+ - Paginate suggestions to display at most 5 items per page with page numbers.
161
+ - Fixed `AgentProgress::Thinking` pattern matching compiler error (E0027) in `crates/mint-cli/src/agent.rs` and render active agent and model names in the live thinking terminal status bar.
162
+ - Implement horizontal scrolling viewport for the CLI prompt input box in `crates/mint-cli/src/main.rs`, slicing the visible text to fit the terminal screen and adjusting the cursor column offset accordingly, allowing arbitrary length instructions.
163
+ - Save `provider_change` system interaction events to the database and render a beautiful styled horizontal divider in the console when switching models via `/models` inside `crates/mint-cli/src/main.rs`.
164
+ - Implement dynamic skill invocation with `$` prefix in the CLI interactive chat.
165
+ - Add realtime autocomplete and pagination dropdown list for local/workspace and global skills under the `$` trigger, resolving and rendering skill descriptions.
166
+ - Add frontmatter YAML parser in `crates/mint-core/src/skills.rs` to fetch skill description values.
167
+ - Support confirmation dialogue to display skill contents and confirm activation before running the Agent, allowing inline or prompted tasks.
168
+ - Register `/skill add <path>` (and `/skill install <path>`) slash commands to automatically copy/install a skill file or folder into the global `~/.config/mint/mint-skills/` directory.
169
+
170
+
171
+
93
172
 
94
173
  ### Github CI/CD Workflows
95
174
  - Modify `Publish GitHub release` step in `.github/workflows/release.yml` to use `body_path: Release_Note.md`.
package/bin/mint CHANGED
Binary file
@@ -184,38 +184,52 @@ pub async fn run_code_agent_with_options(
184
184
  }
185
185
  let progress_live_status = Arc::clone(&live_status);
186
186
  let progress_cb = |progress: AgentProgress| match progress {
187
- AgentProgress::Thinking { elapsed_secs } => {
188
- if !options.fast_mode {
189
- if let Ok(mut status) = progress_live_status.lock() {
190
- status.thinking = Some(format!(
187
+ AgentProgress::Thinking {
188
+ elapsed_secs,
189
+ agent_name,
190
+ model_name,
191
+ } => {
192
+ if !options.fast_mode
193
+ && let Ok(mut status) = progress_live_status.lock()
194
+ {
195
+ let label = if let (Some(a), Some(m)) = (agent_name, model_name) {
196
+ format!(
197
+ "{} ({}) is thinking ({} • Esc to interrupt)",
198
+ a,
199
+ m,
200
+ format_elapsed(Duration::from_secs(elapsed_secs))
201
+ )
202
+ } else {
203
+ format!(
191
204
  "Thinking ({} • Esc to interrupt)",
192
205
  format_elapsed(Duration::from_secs(elapsed_secs))
193
- ));
194
- render_live_status(&mut status);
195
- }
206
+ )
207
+ };
208
+ status.thinking = Some(label);
209
+ render_live_status(&mut status);
196
210
  }
197
211
  }
198
212
  AgentProgress::Thought { thought } => {
199
- if !options.fast_mode {
200
- if let Ok(mut status) = progress_live_status.lock() {
201
- commit_activity_snapshot(&mut status);
202
- print_timeline_note(&thought);
203
- status.thinking = None;
204
- render_live_status(&mut status);
205
- }
213
+ if !options.fast_mode
214
+ && let Ok(mut status) = progress_live_status.lock()
215
+ {
216
+ commit_activity_snapshot(&mut status);
217
+ print_timeline_note(&thought);
218
+ status.thinking = None;
219
+ render_live_status(&mut status);
206
220
  }
207
221
  }
208
222
  AgentProgress::ToolStart { action, input } => {
209
223
  if !options.fast_mode {
210
- if action == "create_plan" || action == "update_plan" {
211
- if let Some(steps) = extract_plan_steps(&input) {
212
- if let Ok(mut status) = progress_live_status.lock() {
213
- status.thinking = None;
214
- status.plan_steps = steps;
215
- render_live_status(&mut status);
216
- }
217
- return;
224
+ if (action == "create_plan" || action == "update_plan")
225
+ && let Some(steps) = extract_plan_steps(&input)
226
+ {
227
+ if let Ok(mut status) = progress_live_status.lock() {
228
+ status.thinking = None;
229
+ status.plan_steps = steps;
230
+ render_live_status(&mut status);
218
231
  }
232
+ return;
219
233
  }
220
234
  if let Some(label) = explored_action_label(&action, &input) {
221
235
  if let Ok(mut status) = progress_live_status.lock() {
@@ -307,12 +321,12 @@ pub async fn run_code_agent_with_options(
307
321
  } => {
308
322
  if !options.fast_mode {
309
323
  if action == "create_plan" || action == "update_plan" {
310
- if let Some(steps) = extract_plan_steps(&input) {
311
- if let Ok(mut status) = progress_live_status.lock() {
312
- status.thinking = None;
313
- status.plan_steps = steps;
314
- render_live_status(&mut status);
315
- }
324
+ if let Some(steps) = extract_plan_steps(&input)
325
+ && let Ok(mut status) = progress_live_status.lock()
326
+ {
327
+ status.thinking = None;
328
+ status.plan_steps = steps;
329
+ render_live_status(&mut status);
316
330
  }
317
331
  } else if command_was_run(&result)
318
332
  && let Some(commands) = ran_command_labels(&action, &input)
@@ -325,21 +339,44 @@ pub async fn run_code_agent_with_options(
325
339
  render_live_status(&mut status);
326
340
  }
327
341
  }
342
+ // Parse web search sources from the result and store them for display
343
+ if action == "web_search"
344
+ && !result.starts_with("Web search error:")
345
+ && result != "No web search results found."
346
+ && let Ok(mut status) = progress_live_status.lock()
347
+ {
348
+ let sources = parse_web_search_sources(&result);
349
+ status.web_sources.extend(sources);
350
+ }
328
351
  }
329
352
  };
330
353
 
331
354
  let chunk_live_status = Arc::clone(&live_status);
332
355
  let on_chunk = |summary: String| {
333
- if !options.fast_mode {
334
- if let Ok(mut status) = chunk_live_status.lock() {
335
- status.thinking = None;
336
- commit_activity_snapshot(&mut status);
337
- clear_live_status(&mut status);
338
- }
356
+ if !options.fast_mode
357
+ && let Ok(mut status) = chunk_live_status.lock()
358
+ {
359
+ status.thinking = None;
360
+ commit_activity_snapshot(&mut status);
361
+ clear_live_status(&mut status);
339
362
  }
340
- let formatted_summary = format_markdown_bold(&summary);
363
+ let formatted_summary = format_markdown_bold(&sanitize_latex(&summary));
341
364
  print!("\n {MINT}Mint:{RESET} ");
342
365
  render_live_summary(&formatted_summary);
366
+
367
+ // Print web search sources if any were collected
368
+ if let Ok(mut status) = chunk_live_status.lock()
369
+ && !status.web_sources.is_empty()
370
+ {
371
+ println!();
372
+ println!(" {DIM}Sources:{RESET}");
373
+ for (i, (title, url)) in status.web_sources.iter().enumerate() {
374
+ println!(" {DIM}{}.{RESET} {BLUE}{}{RESET}", i + 1, title);
375
+ println!(" {DIM}{}{RESET}", url);
376
+ }
377
+ status.web_sources.clear();
378
+ }
379
+
343
380
  println!();
344
381
  };
345
382
 
@@ -349,6 +386,7 @@ pub async fn run_code_agent_with_options(
349
386
  root,
350
387
  image_data_uri,
351
388
  Some(CHAT_CLI_ID),
389
+ None,
352
390
  options.fast_mode,
353
391
  approve_cb,
354
392
  progress_cb,
@@ -365,14 +403,14 @@ pub async fn run_code_agent_with_options(
365
403
  }
366
404
  };
367
405
  agent_done.store(true, Ordering::Relaxed);
368
- if !options.fast_mode {
369
- if let Ok(mut status) = live_status.lock() {
370
- status.thinking = None;
371
- if res.is_err() {
372
- commit_activity_snapshot(&mut status);
373
- }
374
- clear_live_status(&mut status);
406
+ if !options.fast_mode
407
+ && let Ok(mut status) = live_status.lock()
408
+ {
409
+ status.thinking = None;
410
+ if res.is_err() {
411
+ commit_activity_snapshot(&mut status);
375
412
  }
413
+ clear_live_status(&mut status);
376
414
  }
377
415
  let res = res.map_err(|e| anyhow!("{}", e))?;
378
416
 
@@ -396,6 +434,34 @@ fn clear_working_status() {
396
434
  let _ = io::stdout().flush();
397
435
  }
398
436
 
437
+ /// Parse (title, url) pairs from the formatted `web_search` ToolEnd result text.
438
+ /// The format produced by orchestration.rs is:
439
+ /// 1. Title\n URL: https://...\n Snippet\n
440
+ fn parse_web_search_sources(result: &str) -> Vec<(String, String)> {
441
+ let mut sources = Vec::new();
442
+ let mut current_title: Option<String> = None;
443
+ for line in result.lines() {
444
+ let trimmed = line.trim();
445
+ // Match numbered title lines: "1. Title text"
446
+ if let Some(rest) = trimmed.split_once(". ")
447
+ && rest.0.parse::<usize>().is_ok()
448
+ {
449
+ current_title = Some(rest.1.trim().to_owned());
450
+ continue;
451
+ }
452
+ // Match URL lines: "URL: https://..."
453
+ if let Some(url) = trimmed.strip_prefix("URL: ")
454
+ && let Some(title) = current_title.take()
455
+ {
456
+ let url = url.trim().to_owned();
457
+ if !url.is_empty() {
458
+ sources.push((title, url));
459
+ }
460
+ }
461
+ }
462
+ sources
463
+ }
464
+
399
465
  fn format_elapsed(duration: Duration) -> String {
400
466
  let total_seconds = duration.as_secs();
401
467
  let minutes = total_seconds / 60;
@@ -487,6 +553,8 @@ struct LiveStatus {
487
553
  committed_tasks: usize,
488
554
  rendered_lines: usize,
489
555
  spinner_tick: usize,
556
+ /// Sources collected from web_search ToolEnd results (title, url)
557
+ web_sources: Vec<(String, String)>,
490
558
  }
491
559
 
492
560
  #[derive(Debug, Clone)]
@@ -619,7 +687,7 @@ fn render_live_status(status: &mut LiveStatus) {
619
687
  let stripped = strip_ansi_escapes(line);
620
688
  let line_len = stripped.chars().filter(|&c| !is_thai_combining(c)).count();
621
689
  let physical_lines = if width > 0 {
622
- (line_len + width - 1) / width
690
+ line_len.div_ceil(width)
623
691
  } else {
624
692
  1
625
693
  }
@@ -692,7 +760,11 @@ fn clear_live_status(status: &mut LiveStatus) {
692
760
 
693
761
  fn get_bullet(name: &str, is_thinking: bool, tick: usize) -> String {
694
762
  let char_str = if is_thinking {
695
- if (tick / 4) % 2 == 0 { "●" } else { "○" }
763
+ if (tick / 4).is_multiple_of(2) {
764
+ "●"
765
+ } else {
766
+ "○"
767
+ }
696
768
  } else {
697
769
  "●"
698
770
  };
@@ -905,7 +977,7 @@ fn format_markdown_bold(text: &str) -> String {
905
977
  } else {
906
978
  if c == '-' || c == '*' || c == '+' {
907
979
  let after = &line[idx + c.len_utf8()..];
908
- if after.chars().next().map_or(false, |c| c.is_whitespace()) {
980
+ if after.chars().next().is_some_and(|c| c.is_whitespace()) {
909
981
  is_list_item = true;
910
982
  marker_char = c;
911
983
  }
@@ -975,3 +1047,36 @@ fn process_inline_bold(text: &str) -> String {
975
1047
  }
976
1048
  result
977
1049
  }
1050
+
1051
+ /// Replace common LaTeX math symbols with Unicode equivalents.
1052
+ /// Fixes garbled output like "ightarrow$" from models that emit LaTeX notation.
1053
+ fn sanitize_latex(text: &str) -> String {
1054
+ let mut s = text.to_owned();
1055
+ for (pat, uni) in [
1056
+ // arrows
1057
+ ("$\\rightarrow$", "→"),
1058
+ ("$\\leftarrow$", "←"),
1059
+ ("$\\Rightarrow$", "⇒"),
1060
+ ("$\\Leftarrow$", "⇐"),
1061
+ ("$\\leftrightarrow$", "↔"),
1062
+ // comparison
1063
+ ("$\\leq$", "≤"),
1064
+ ("$\\geq$", "≥"),
1065
+ ("$\\neq$", "≠"),
1066
+ ("$\\approx$", "≈"),
1067
+ // math
1068
+ ("$\\times$", "×"),
1069
+ ("$\\div$", "÷"),
1070
+ ("$\\pm$", "±"),
1071
+ ("$\\infty$", "∞"),
1072
+ ("$\\cdot$", "·"),
1073
+ // sets
1074
+ ("$\\in$", "∈"),
1075
+ ("$\\subset$", "⊂"),
1076
+ ("$\\cup$", "∪"),
1077
+ ("$\\cap$", "∩"),
1078
+ ] {
1079
+ s = s.replace(pat, uni);
1080
+ }
1081
+ s
1082
+ }