@pheem49/mint 1.17.0 → 1.18.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 (421) hide show
  1. package/Cargo.lock +6 -6
  2. package/Cargo.toml +2 -2
  3. package/README.md +8 -2
  4. package/Release_Note.md +222 -71
  5. package/crates/mint-cli/src/agent/diff_render.rs +66 -44
  6. package/crates/mint-cli/src/agent/live_status.rs +21 -4
  7. package/crates/mint-cli/src/agent/markdown_render.rs +342 -5
  8. package/crates/mint-cli/src/agent.rs +25 -10
  9. package/crates/mint-cli/src/commands/agent.rs +4 -92
  10. package/crates/mint-cli/src/commands/browser.rs +2 -15
  11. package/crates/mint-cli/src/commands/integrations.rs +3 -3
  12. package/crates/mint-cli/src/commands/mod.rs +0 -3
  13. package/crates/mint-cli/src/commands/tailnet_web.rs +1 -0
  14. package/crates/mint-cli/src/interactive/chat_tui/dialog.rs +572 -0
  15. package/crates/mint-cli/src/interactive/chat_tui/mod.rs +1427 -0
  16. package/crates/mint-cli/src/interactive/chat_tui/render.rs +1524 -0
  17. package/crates/mint-cli/src/interactive/chat_tui/selection.rs +401 -0
  18. package/crates/mint-cli/src/interactive/chat_tui/state.rs +1833 -0
  19. package/crates/mint-cli/src/interactive/chat_tui/tests.rs +3414 -0
  20. package/crates/mint-cli/src/interactive/chat_tui/thought.rs +202 -0
  21. package/crates/mint-cli/src/interactive/chat_tui/transcript.rs +728 -0
  22. package/crates/mint-cli/src/interactive/chat_tui/watermark.rs +148 -0
  23. package/crates/mint-cli/src/interactive/command_ui.rs +53 -5
  24. package/crates/mint-cli/src/interactive/composer.rs +186 -0
  25. package/crates/mint-cli/src/interactive/format.rs +78 -3
  26. package/crates/mint-cli/src/interactive/input_box.rs +61 -1
  27. package/crates/mint-cli/src/interactive/resume_picker.rs +367 -25
  28. package/crates/mint-cli/src/interactive/slash_commands.rs +648 -371
  29. package/crates/mint-cli/src/interactive/tool_activity.rs +93 -20
  30. package/crates/mint-cli/src/interactive.rs +37 -0
  31. package/crates/mint-cli/src/main.rs +6 -3
  32. package/crates/mint-cli/src/markdown.rs +2 -37
  33. package/crates/mint-cli/src/onboard.rs +700 -282
  34. package/crates/mint-cli/src/setup.rs +1342 -624
  35. package/crates/mint-cli/src/terminal_theme.rs +159 -35
  36. package/crates/mint-cli/tests/library_intake.rs +1 -0
  37. package/crates/mint-core/src/agent/chat/anthropic.rs +318 -0
  38. package/crates/mint-core/src/agent/chat/custom.rs +149 -0
  39. package/crates/mint-core/src/agent/chat/gemini.rs +518 -0
  40. package/crates/mint-core/src/agent/chat/mod.rs +857 -0
  41. package/crates/mint-core/src/agent/chat/ollama.rs +321 -0
  42. package/crates/mint-core/src/agent/chat/openai.rs +582 -0
  43. package/crates/mint-core/src/agent/chat/streaming.rs +469 -0
  44. package/crates/mint-core/src/agent/chat/tests.rs +1479 -0
  45. package/crates/mint-core/src/agent/memory.rs +56 -2
  46. package/crates/mint-core/src/agent/tasks.rs +2 -2
  47. package/crates/mint-core/src/api_server/routes/chat.rs +24 -2
  48. package/crates/mint-core/src/api_server/routes/gemini_live.rs +14 -1
  49. package/crates/mint-core/src/api_server/routes/html_preview.rs +1 -8
  50. package/crates/mint-core/src/api_server/routes/sessions.rs +21 -0
  51. package/crates/mint-core/src/avatar_bridge.rs +0 -22
  52. package/crates/mint-core/src/browser/cdp.rs +10 -4
  53. package/crates/mint-core/src/browser/headless.rs +582 -0
  54. package/crates/mint-core/src/browser/input.rs +7 -62
  55. package/crates/mint-core/src/browser/interact.rs +0 -14
  56. package/crates/mint-core/src/browser/mod.rs +8 -29
  57. package/crates/mint-core/src/browser/navigate.rs +2 -36
  58. package/crates/mint-core/src/browser/runtime.rs +2 -4
  59. package/crates/mint-core/src/browser/session.rs +50 -466
  60. package/crates/mint-core/src/browser/workflow.rs +142 -32
  61. package/crates/mint-core/src/cron/store.rs +2 -2
  62. package/crates/mint-core/src/integrations/mcp.rs +6 -8
  63. package/crates/mint-core/src/lib.rs +0 -5
  64. package/crates/mint-core/src/media/gemini_live.rs +636 -86
  65. package/crates/mint-core/src/media/library/migration.rs +26 -0
  66. package/crates/mint-core/src/media/library/tests.rs +1 -1
  67. package/crates/mint-core/src/media/library/thumbnails.rs +8 -2
  68. package/crates/mint-core/src/media/pictures.rs +1 -1
  69. package/crates/mint-core/src/media/tool_images.rs +92 -1
  70. package/crates/mint-core/src/mods/manager.rs +101 -35
  71. package/crates/mint-core/src/orchestration/context_render.rs +441 -24
  72. package/crates/mint-core/src/orchestration/decision_parsing.rs +531 -16
  73. package/crates/mint-core/src/orchestration/full_skill_result_tests.rs +12 -0
  74. package/crates/mint-core/src/orchestration/loop_guard.rs +145 -0
  75. package/crates/mint-core/src/orchestration/mcp_outcome_tests.rs +864 -0
  76. package/crates/mint-core/src/orchestration/memory_skill.rs +88 -28
  77. package/crates/mint-core/src/orchestration/mod.rs +320 -4249
  78. package/crates/mint-core/src/orchestration/reliability.rs +67 -27
  79. package/crates/mint-core/src/orchestration/review_regressions.rs +5 -0
  80. package/crates/mint-core/src/orchestration/tests.rs +1665 -0
  81. package/crates/mint-core/src/orchestration/tools/dispatch.rs +967 -0
  82. package/crates/mint-core/src/orchestration/tools/files.rs +1 -0
  83. package/crates/mint-core/src/orchestration/tools/mod.rs +5 -1
  84. package/crates/mint-core/src/orchestration/tools/planning.rs +102 -42
  85. package/crates/mint-core/src/orchestration/tools/shell.rs +129 -58
  86. package/crates/mint-core/src/orchestration/truncation.rs +170 -13
  87. package/crates/mint-core/src/orchestration/types.rs +648 -0
  88. package/crates/mint-core/src/orchestration/verification.rs +0 -3
  89. package/crates/mint-core/src/orchestration/workspace_helpers.rs +24 -6
  90. package/crates/mint-core/src/prompts/agent.rs +52 -76
  91. package/crates/mint-core/src/prompts/tool_catalog.rs +8 -151
  92. package/crates/mint-core/src/search/files.rs +20 -0
  93. package/crates/mint-core/src/slash/mod.rs +228 -265
  94. package/crates/mint-core/src/slash/models.rs +6 -1
  95. package/crates/mint-core/src/system/bg_shell.rs +1 -0
  96. package/crates/mint-core/src/system/config.rs +176 -34
  97. package/crates/mint-mod-runtime/src/lib.rs +37 -23
  98. package/out/web/assets/ArtifactPreviewPanel-Cx6BVOOF.js +2 -0
  99. package/out/web/assets/CalculationCard-D2E74u5q.js +1 -0
  100. package/out/web/assets/CliSessionsView-ZbdtSjvK.css +1 -0
  101. package/out/web/assets/{CliSessionsView-MI8kXMAb.js → CliSessionsView-z5i6qGyb.js} +1 -1
  102. package/out/web/assets/CodeReviewPage-BK2bOScd.css +1 -0
  103. package/out/web/assets/CodeReviewPage-Dp6zHuHu.js +2 -0
  104. package/out/web/assets/{CommandPalette-BD8SlTE5.js → CommandPalette-DaKlzbKs.js} +1 -1
  105. package/out/web/assets/ImageGenCard-BMCJHP9O.js +1 -0
  106. package/out/web/assets/ImageSearchCard-Cld_SOUg.js +1 -0
  107. package/out/web/assets/{ImageStudioPanel-BP7N4rLr.js → ImageStudioPanel-B5N7TjeB.js} +1 -1
  108. package/out/web/assets/LibraryPage-CMB89rJ0.css +1 -0
  109. package/out/web/assets/LibraryPage-DbZEi4W_.js +2 -0
  110. package/out/web/assets/LinkedFoldersView-9B9DIPoZ.js +1 -0
  111. package/out/web/assets/{McpRegistryPicker-CoS83vtc.js → McpRegistryPicker-DnXPlzI7.js} +1 -1
  112. package/out/web/assets/McpServersView-CiNBNUl4.js +1 -0
  113. package/out/web/assets/MermaidCard-BBDNEXbY.js +2 -0
  114. package/out/web/assets/MintDashboard-C_UYPoNV.js +119 -0
  115. package/out/web/assets/MintDashboard-DTd8C_c8.css +1 -0
  116. package/out/web/assets/PlanCard-C2x5pajq.js +1 -0
  117. package/out/web/assets/{PluginsView-jBYmcKh4.js → PluginsView-DoTg9MVa.js} +1 -1
  118. package/out/web/assets/RewindModal-B5oowrR0.js +1 -0
  119. package/out/web/assets/{ScheduledTasksView-5uw9-V9H.js → ScheduledTasksView-BD5DVPkZ.js} +1 -1
  120. package/out/web/assets/{SelectField-DXBQtrUK.js → SelectField-Cy6CghrU.js} +1 -1
  121. package/out/web/assets/SettingsWindow-BYl_oCFh.js +4 -0
  122. package/out/web/assets/SettingsWindow-Ckcgnjt8.css +1 -0
  123. package/out/web/assets/{SkillsView-C-gp9J7m.js → SkillsView-CIeWwq5z.js} +1 -1
  124. package/out/web/assets/StockCard-DxUciKyp.js +1 -0
  125. package/out/web/assets/ToolSurfacePage-qBgs_VHq.css +1 -0
  126. package/out/web/assets/ToolSurfacePage-saVbVrkE.js +38 -0
  127. package/out/web/assets/{UiFeatureCard-6BwxTOCe.js → UiFeatureCard-CdY0hGWy.js} +1 -1
  128. package/out/web/assets/{UiGridCard-DvZcLNxb.js → UiGridCard-BBK3I5hC.js} +1 -1
  129. package/out/web/assets/UiMockupWidget-CpR9EDuc.js +1 -0
  130. package/out/web/assets/{VeoStudioPanel-DOj7_WR3.css → VeoStudioPanel-9kU9YLEN.css} +1 -1
  131. package/out/web/assets/{VeoStudioPanel-DfsOJKv0.js → VeoStudioPanel-Co6-wEWM.js} +2 -2
  132. package/out/web/assets/WeatherCard-Buzi7Vfu.js +1 -0
  133. package/out/web/assets/WorkspacePdfPreview-Bi8Zzyir.js +2 -0
  134. package/out/web/assets/{abnfDiagram-VCTEODGH-BOo3Ckng.js → abnfDiagram-VCTEODGH-CMfR95N2.js} +1 -1
  135. package/out/web/assets/{architecture-7GRP2DOG-ZOwheW3n.js → architecture-7GRP2DOG-DhAM4HyO.js} +1 -1
  136. package/out/web/assets/{architectureDiagram-5GKGNRK7-DC2FDzVd.js → architectureDiagram-5GKGNRK7-Yk3TUJ_F.js} +1 -1
  137. package/out/web/assets/{blockDiagram-I7D4REHJ-BrKFWdAH.js → blockDiagram-I7D4REHJ-X9fBgJik.js} +1 -1
  138. package/out/web/assets/{c4Diagram-7LVT6UL2-BHTHK1Yd.js → c4Diagram-7LVT6UL2-Bk9x7N-8.js} +1 -1
  139. package/out/web/assets/{chunk-4HAMMTFA-BYFkZwNj.js → chunk-4HAMMTFA-Dx5fk1_0.js} +1 -1
  140. package/out/web/assets/{chunk-75Z2AOVW-BSKfSKSA.js → chunk-75Z2AOVW-BszTQoM4.js} +1 -1
  141. package/out/web/assets/{chunk-DU6HZSFF-vIhsiW6n.js → chunk-DU6HZSFF-DK-As3rk.js} +1 -1
  142. package/out/web/assets/{chunk-F27PBJKO-BlYpW9xq.js → chunk-F27PBJKO-LmncZZIS.js} +1 -1
  143. package/out/web/assets/{chunk-GMAD6QVW-BIBz_Ug5.js → chunk-GMAD6QVW-DSQ_sDRJ.js} +1 -1
  144. package/out/web/assets/{chunk-GVQU2GXP-NPSHxeqC.js → chunk-GVQU2GXP-Cno3ulje.js} +1 -1
  145. package/out/web/assets/{chunk-IMKFNOWR-YlJK8_Fp.js → chunk-IMKFNOWR-bIzfY9Jc.js} +1 -1
  146. package/out/web/assets/{chunk-L3NEJ4N5-DMYi4-af.js → chunk-L3NEJ4N5-Dl6eOa0D.js} +1 -1
  147. package/out/web/assets/{chunk-OSK3NFVY-Begd3-jA.js → chunk-OSK3NFVY-BaUGJ-cM.js} +1 -1
  148. package/out/web/assets/{chunk-P2QGCYS3-D1I4xFHN.js → chunk-P2QGCYS3-_066ndhH.js} +1 -1
  149. package/out/web/assets/{chunk-POPQ4Y6H-CafZZzNE.js → chunk-POPQ4Y6H-YT1AKhTv.js} +1 -1
  150. package/out/web/assets/{chunk-PWAF6VOD-Dwh6_Lnt.js → chunk-PWAF6VOD-CrEgDsxh.js} +1 -1
  151. package/out/web/assets/{chunk-SHT3W25Y-B0XrCSEb.js → chunk-SHT3W25Y-_KwaRLOl.js} +1 -1
  152. package/out/web/assets/{chunk-SVP7TREG-CxLsddxC.js → chunk-SVP7TREG-BQ1qb32L.js} +1 -1
  153. package/out/web/assets/{chunk-TICWLB2K-y156QInb.js → chunk-TICWLB2K-BDyehCtg.js} +1 -1
  154. package/out/web/assets/classDiagram-ZZMXUADV-BoSpzRCJ.js +1 -0
  155. package/out/web/assets/classDiagram-v2-VYDZK3BY-BoSpzRCJ.js +1 -0
  156. package/out/web/assets/{config-DqXJXeZM.css → config-2suVFPZg.css} +1 -1
  157. package/out/web/assets/config-CkRCdkxn.js +2 -0
  158. package/out/web/assets/{cynefin-OW5HDTMX-SMVvrLf-.js → cynefin-OW5HDTMX-Dl_31aaN.js} +1 -1
  159. package/out/web/assets/{cynefinDiagram-5FMLGOSQ-rZznN24T.js → cynefinDiagram-5FMLGOSQ-Bpir8jha.js} +1 -1
  160. package/out/web/assets/{dagre-GXQ25YYZ-BOToydFu.js → dagre-GXQ25YYZ-D9xu3nsq.js} +1 -1
  161. package/out/web/assets/{diagram-S7CK7UJ4-TMVaGQEJ.js → diagram-S7CK7UJ4-DeveoEeB.js} +1 -1
  162. package/out/web/assets/{diagram-UQ7AKVKN-C2JK-GP2.js → diagram-UQ7AKVKN-p4xWRESV.js} +1 -1
  163. package/out/web/assets/{diagram-VSXAHHWV-Cw8VSi2K.js → diagram-VSXAHHWV-C7qz9NDF.js} +1 -1
  164. package/out/web/assets/{diagram-VX7I27RA-DXp4fKk9.js → diagram-VX7I27RA-DRiCa3Vd.js} +1 -1
  165. package/out/web/assets/{diagram-Z3DM3KII-CzSicYiW.js → diagram-Z3DM3KII-Bt7zduQX.js} +1 -1
  166. package/out/web/assets/{ebnfDiagram-PWID7BFC-Dqj-zqPu.js → ebnfDiagram-PWID7BFC-DV9WpwdR.js} +1 -1
  167. package/out/web/assets/{erDiagram-RLTQ6QDP-DZwFZAuD.js → erDiagram-RLTQ6QDP-BJ_nwG2m.js} +1 -1
  168. package/out/web/assets/{eventmodeling-NTZA5JFV-C0O-Lvgp.js → eventmodeling-NTZA5JFV-BTBMrfVa.js} +1 -1
  169. package/out/web/assets/flowDiagram-HODETNUW-Cdlq3cJL.js +1 -0
  170. package/out/web/assets/{ganttDiagram-EL5Y4UJY-Da4ULXTl.js → ganttDiagram-EL5Y4UJY-DQLdsXrC.js} +1 -1
  171. package/out/web/assets/{gitGraph-4MIJSDKK-B9wNFZIP.js → gitGraph-4MIJSDKK-CL1OEOQ_.js} +1 -1
  172. package/out/web/assets/{gitGraphDiagram-WWUBYQGX-RjrhB0MP.js → gitGraphDiagram-WWUBYQGX-8cSi42H7.js} +1 -1
  173. package/out/web/assets/index-BocxnrDG.js +168 -0
  174. package/out/web/assets/index-yeh_r55a.css +1 -0
  175. package/out/web/assets/{info-A6RAGUB7-B3dfCpeY.js → info-A6RAGUB7-C1zsX5sc.js} +1 -1
  176. package/out/web/assets/{infoDiagram-27XIBGKW-QVWkLVx7.js → infoDiagram-27XIBGKW-DsRYtIyI.js} +1 -1
  177. package/out/web/assets/{ishikawaDiagram-5VMMS53U-CLFNIRI9.js → ishikawaDiagram-5VMMS53U-B2crwIXj.js} +1 -1
  178. package/out/web/assets/{journeyDiagram-3NMN7TZE-fgOQadYF.js → journeyDiagram-3NMN7TZE-BTH-GyVR.js} +1 -1
  179. package/out/web/assets/{kanban-definition-UXKFOSKX-G3Q_9g9O.js → kanban-definition-UXKFOSKX-BeRfCnuA.js} +1 -1
  180. package/out/web/assets/{mermaid-parser.core-v3Jm7nco.js → mermaid-parser.core-BJwgCBBc.js} +3 -3
  181. package/out/web/assets/{mermaid.core-DTEjLUA1.js → mermaid.core-CsDDodN8.js} +4 -4
  182. package/out/web/assets/{mindmap-definition-YA3MSWOX-C_D42_fF.js → mindmap-definition-YA3MSWOX-B42efOQ1.js} +1 -1
  183. package/out/web/assets/{modelManager-BPLycQrN.js → modelManager-B3ZFMh8v.js} +2 -2
  184. package/out/web/assets/{oauthManager-BUK7ic7q.js → oauthManager-Ch5Du2fF.js} +1 -1
  185. package/out/web/assets/{packet-AYTQ26CC-B-R-SHlF.js → packet-AYTQ26CC-B6xUyE6r.js} +1 -1
  186. package/out/web/assets/{pegDiagram-XKGWAZYB-Da2q_giz.js → pegDiagram-XKGWAZYB-1LabVycL.js} +1 -1
  187. package/out/web/assets/{pie-WAS4IAKB-BC8F0N7-.js → pie-WAS4IAKB-DJwo-nf_.js} +1 -1
  188. package/out/web/assets/{pieDiagram-E7YTZNPT-Iy9REJNC.js → pieDiagram-E7YTZNPT-icmAqzy4.js} +1 -1
  189. package/out/web/assets/{quadrantDiagram-AXDQQJYC-ztsiYw7h.js → quadrantDiagram-AXDQQJYC-CZ-wEx41.js} +1 -1
  190. package/out/web/assets/{radar-RG4KPBEZ-B_1P8Z_z.js → radar-RG4KPBEZ-D7d-Xriw.js} +1 -1
  191. package/out/web/assets/{railroad-74A4TZTK-DuTqczSo.js → railroad-74A4TZTK-viuhdYbs.js} +1 -1
  192. package/out/web/assets/{railroad-abnf-HS5TGJTU-Df29WLmp.js → railroad-abnf-HS5TGJTU-DNXiCNea.js} +1 -1
  193. package/out/web/assets/{railroad-ebnf-LZEXJU2U-ePFMo-qp.js → railroad-ebnf-LZEXJU2U-nkSu1-0C.js} +1 -1
  194. package/out/web/assets/{railroad-peg-WCYAUIDC-DYXLW4_E.js → railroad-peg-WCYAUIDC-BhbMeQzz.js} +1 -1
  195. package/out/web/assets/{railroadDiagram-O6MQD6OU-LStnZf2S.js → railroadDiagram-O6MQD6OU-CLpG1jUX.js} +1 -1
  196. package/out/web/assets/{requirementDiagram-BXWQKSXE-DmzonMH-.js → requirementDiagram-BXWQKSXE-kRDrvWrc.js} +1 -1
  197. package/out/web/assets/{sankeyDiagram-P5KCCOFB-B8vjmUU1.js → sankeyDiagram-P5KCCOFB-DxAwmq4x.js} +1 -1
  198. package/out/web/assets/{sequenceDiagram-WJ2MYXX4-CTnplOAX.js → sequenceDiagram-WJ2MYXX4-aLgY-6Wz.js} +1 -1
  199. package/out/web/assets/{stateDiagram-D77RDMKH-BFrIaLdI.js → stateDiagram-D77RDMKH-D5QWfOhp.js} +1 -1
  200. package/out/web/assets/stateDiagram-v2-MP3YSRHH-D6OiZoAP.js +1 -0
  201. package/out/web/assets/{swimlanes-42K2YHIH-BXGngUNU.js → swimlanes-42K2YHIH-CRs5UyA-.js} +1 -1
  202. package/out/web/assets/swimlanesDiagram-VR7AAH4N-UgEXIsV0.js +8 -0
  203. package/out/web/assets/syntaxHighlight-C-wAGT84.js +3 -0
  204. package/out/web/assets/{timeline-definition-24CTP7MA-CegH7n43.js → timeline-definition-24CTP7MA-Denqd9qb.js} +1 -1
  205. package/out/web/assets/{treeView-Q6P3EWNA-DTpJv2Tw.js → treeView-Q6P3EWNA-0my3Z3s4.js} +1 -1
  206. package/out/web/assets/{treemap-WGGIJYW6-i8M9iJU6.js → treemap-WGGIJYW6-B_EjkLYq.js} +1 -1
  207. package/out/web/assets/{vennDiagram-4TSXK5OY-Dpzo1S8U.js → vennDiagram-4TSXK5OY-DxVg3Ewr.js} +1 -1
  208. package/out/web/assets/{wardley-WFR3VGLG-BrNsgtfw.js → wardley-WFR3VGLG-CGD-Tj4p.js} +1 -1
  209. package/out/web/assets/{wardleyDiagram-VM6X3IG4-lQ92LFE1.js → wardleyDiagram-VM6X3IG4-CmfS39Xm.js} +1 -1
  210. package/out/web/assets/{xychartDiagram-S5SC5T6Z-BaOaEoBd.js → xychartDiagram-S5SC5T6Z-BVM9bKis.js} +1 -1
  211. package/out/web/index-web.html +2 -2
  212. package/out/web/index.html +2 -2
  213. package/package.json +2 -2
  214. package/shared-modules/CODEOWNERS +3 -3
  215. package/shared-modules/SDL2/SDL2_mixer.json +27 -0
  216. package/shared-modules/appstream/README.md +13 -0
  217. package/shared-modules/appstream/appstream-compose.json +111 -0
  218. package/shared-modules/dbus-glib/dbus-glib.json +2 -2
  219. package/shared-modules/libportal/libportal.json +23 -0
  220. package/shared-modules/linux-audio/fluidsynth2-static.json +2 -2
  221. package/shared-modules/linux-audio/fluidsynth2.json +2 -2
  222. package/shared-modules/linux-audio/libinstpatch.json +2 -2
  223. package/shared-modules/linux-audio/liblo-static.json +3 -0
  224. package/shared-modules/luajit/luajit.json +2 -2
  225. package/shared-modules/squashfs-tools/squashfs-tools.json +0 -3
  226. package/slash-commands.json +7 -2
  227. package/src/renderer/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  228. package/src/renderer/shared/agentProgress.ts +51 -3
  229. package/src/renderer/shared/components/Settings/AutomationTab.tsx +2 -56
  230. package/src/renderer/shared/components/Settings/AvatarCropModal.tsx +15 -1
  231. package/src/renderer/shared/components/Settings/GeneralTab.tsx +25 -12
  232. package/src/renderer/shared/components/Settings/ThemeTab.test.tsx +45 -0
  233. package/src/renderer/shared/components/Settings/ThemeTab.tsx +106 -3
  234. package/src/renderer/shared/components/activity/AgentActivityDrawer.tsx +67 -17
  235. package/src/renderer/shared/components/activity/AgentActivityTable.tsx +376 -134
  236. package/src/renderer/shared/components/activity/AskUserActivityCard.test.tsx +122 -0
  237. package/src/renderer/shared/components/activity/AskUserActivityCard.tsx +70 -0
  238. package/src/renderer/shared/components/activity/McpToolResults.tsx +39 -2
  239. package/src/renderer/shared/components/activity/SubagentDagView.tsx +7 -7
  240. package/src/renderer/shared/components/activity/ViewedImages.tsx +41 -2
  241. package/src/renderer/shared/components/app/ChunkErrorBoundary.tsx +3 -3
  242. package/src/renderer/shared/components/app/CommandPalette.tsx +7 -7
  243. package/src/renderer/shared/components/app/DesktopTitlebar.tsx +2 -2
  244. package/src/renderer/shared/components/app/MintDashboard.tsx +27 -17
  245. package/src/renderer/shared/components/app/ModalErrorBoundary.tsx +3 -3
  246. package/src/renderer/shared/components/cards/CalculationCard.tsx +3 -3
  247. package/src/renderer/shared/components/cards/ImageGenCard.tsx +2 -2
  248. package/src/renderer/shared/components/cards/ImageSearchCard.tsx +2 -2
  249. package/src/renderer/shared/components/cards/MermaidCard.tsx +1 -1
  250. package/src/renderer/shared/components/cards/PlanCard.test.tsx +41 -0
  251. package/src/renderer/shared/components/cards/PlanCard.tsx +32 -0
  252. package/src/renderer/shared/components/cards/ReleaseNotesCard.test.tsx +29 -0
  253. package/src/renderer/shared/components/cards/ReleaseNotesCard.tsx +137 -0
  254. package/src/renderer/shared/components/cards/StockCard.tsx +7 -7
  255. package/src/renderer/shared/components/cards/ToolResultCards.tsx +11 -3
  256. package/src/renderer/shared/components/cards/UiMockupWidget.tsx +4 -4
  257. package/src/renderer/shared/components/cards/WeatherCard.tsx +5 -5
  258. package/src/renderer/shared/components/chat/ApprovalCard.test.tsx +11 -0
  259. package/src/renderer/shared/components/chat/ApprovalCard.tsx +21 -2
  260. package/src/renderer/shared/components/chat/ArtifactCards.test.tsx +69 -0
  261. package/src/renderer/shared/components/chat/ArtifactCards.tsx +238 -0
  262. package/src/renderer/shared/components/chat/AttachedDocumentCard.test.tsx +39 -0
  263. package/src/renderer/shared/components/chat/AttachedDocumentCard.tsx +220 -0
  264. package/src/renderer/shared/components/chat/ChatCodeBlock.test.tsx +33 -0
  265. package/src/renderer/shared/components/chat/ChatCodeBlock.tsx +15 -1
  266. package/src/renderer/shared/components/chat/ChatMessageItem.test.tsx +40 -2
  267. package/src/renderer/shared/components/chat/ChatMessageItem.tsx +180 -34
  268. package/src/renderer/shared/components/chat/ChatModeSelector.css +227 -0
  269. package/src/renderer/shared/components/chat/ChatModeSelector.test.tsx +45 -0
  270. package/src/renderer/shared/components/chat/ChatModeSelector.tsx +198 -0
  271. package/src/renderer/shared/components/chat/ChatPanel.test.tsx +22 -0
  272. package/src/renderer/shared/components/chat/ChatPanel.tsx +227 -53
  273. package/src/renderer/shared/components/chat/DiffReviewModal.tsx +6 -6
  274. package/src/renderer/shared/components/chat/GeminiLiveOverlay.test.tsx +142 -1
  275. package/src/renderer/shared/components/chat/GeminiLiveOverlay.tsx +45 -3
  276. package/src/renderer/shared/components/chat/ModelSelectorPopover.tsx +42 -14
  277. package/src/renderer/shared/components/chat/RewindModal.tsx +10 -10
  278. package/src/renderer/shared/components/chat/SlashSuggestions.test.tsx +14 -0
  279. package/src/renderer/shared/components/chat/SourcesBlock.test.tsx +53 -0
  280. package/src/renderer/shared/components/chat/SourcesBlock.tsx +236 -90
  281. package/src/renderer/shared/components/chat/TurnFileChanges.test.tsx +45 -1
  282. package/src/renderer/shared/components/chat/TurnFileChanges.tsx +202 -169
  283. package/src/renderer/shared/components/extensions/CliSessionsView.tsx +5 -4
  284. package/src/renderer/shared/components/extensions/McpRegistryPicker.tsx +3 -3
  285. package/src/renderer/shared/components/studio/LibraryPage.tsx +48 -5
  286. package/src/renderer/shared/components/workspace/ArtifactPreviewPanel.tsx +125 -13
  287. package/src/renderer/shared/components/workspace/CodeReviewPage.test.tsx +50 -0
  288. package/src/renderer/shared/components/workspace/CodeReviewPage.tsx +77 -16
  289. package/src/renderer/shared/components/workspace/GitBranchSelector.tsx +78 -22
  290. package/src/renderer/shared/components/workspace/ToolSurfacePage.test.tsx +13 -0
  291. package/src/renderer/shared/components/workspace/ToolSurfacePage.tsx +48 -28
  292. package/src/renderer/shared/components/workspace/WorkspacePdfPreview.tsx +266 -47
  293. package/src/renderer/shared/components/workspace/WorkspacePreviewActions.test.tsx +18 -6
  294. package/src/renderer/shared/components/workspace/background-terminals.css +11 -11
  295. package/src/renderer/shared/constants/config.ts +1 -5
  296. package/src/renderer/shared/constants/models.test.ts +51 -0
  297. package/src/renderer/shared/constants/models.ts +139 -32
  298. package/src/renderer/shared/conversation/lifecycle.test.ts +91 -3
  299. package/src/renderer/shared/conversation/lifecycle.ts +104 -5
  300. package/src/renderer/shared/conversation/progressiveStream.test.ts +83 -0
  301. package/src/renderer/shared/conversation/progressiveStream.ts +219 -0
  302. package/src/renderer/shared/css/agent-observability.css +133 -0
  303. package/src/renderer/shared/css/chat-ui-cards.css +13 -13
  304. package/src/renderer/shared/css/code-review.css +63 -34
  305. package/src/renderer/shared/css/code-sessions.css +47 -18
  306. package/src/renderer/shared/css/collapsed-paste.css +1 -1
  307. package/src/renderer/shared/css/error-notice.css +1 -1
  308. package/src/renderer/shared/css/file-changes.css +165 -80
  309. package/src/renderer/shared/css/library.css +105 -10
  310. package/src/renderer/shared/css/management-views.css +1 -1
  311. package/src/renderer/shared/css/mcp-results.css +5 -5
  312. package/src/renderer/shared/css/model-selector.css +18 -18
  313. package/src/renderer/shared/css/mods.css +7 -7
  314. package/src/renderer/shared/css/notification-notice.css +2 -2
  315. package/src/renderer/shared/css/queued-messages.css +5 -5
  316. package/src/renderer/shared/css/settings/general.css +18 -13
  317. package/src/renderer/shared/css/settings/profile.css +5 -5
  318. package/src/renderer/shared/css/settings/theme.css +5 -5
  319. package/src/renderer/shared/css/slash-choice.css +2 -2
  320. package/src/renderer/shared/css/slash-suggestions.css +3 -3
  321. package/src/renderer/shared/css/sources-block.css +41 -2
  322. package/src/renderer/shared/css/tools-panel.css +2 -2
  323. package/src/renderer/shared/css/ui-tailwind.css +8 -0
  324. package/src/renderer/shared/css/veo-studio.css +2 -2
  325. package/src/renderer/shared/css/viewed-images.css +7 -7
  326. package/src/renderer/shared/platform.ts +2 -1
  327. package/src/renderer/shared/theme/themeManager.test.ts +17 -0
  328. package/src/renderer/shared/theme/themeManager.ts +21 -4
  329. package/src/renderer/shared/theme/themes.ts +54 -0
  330. package/src/renderer/shared/theme/tokens.css +6 -4
  331. package/src/renderer/shared/types.ts +1 -1
  332. package/src/renderer/shared/utils/agentActivity.test.ts +468 -2
  333. package/src/renderer/shared/utils/agentActivity.ts +602 -35
  334. package/src/renderer/shared/utils/artifactBrowser.test.ts +37 -32
  335. package/src/renderer/shared/utils/artifactBrowser.ts +17 -19
  336. package/src/renderer/shared/utils/attachedDocument.test.ts +73 -0
  337. package/src/renderer/shared/utils/attachedDocument.ts +49 -0
  338. package/src/renderer/shared/utils/fileIcons.test.ts +59 -0
  339. package/src/renderer/shared/utils/fileIcons.ts +149 -16
  340. package/src/renderer/shared/utils/markdown.tsx +72 -19
  341. package/src/renderer/shared/utils/markdown.webImages.test.tsx +16 -0
  342. package/src/renderer/shared/utils/mcpResults.test.tsx +29 -0
  343. package/src/renderer/shared/utils/slashCommandProcessor.ts +4 -1
  344. package/src/renderer/shared/utils/syntaxHighlight.test.tsx +11 -1
  345. package/src/renderer/shared/utils/syntaxHighlight.tsx +51 -3
  346. package/src/renderer/shared/utils/useGeminiLiveVoice.ts +324 -51
  347. package/src/renderer/shared/utils/workspaceDrag.test.ts +153 -0
  348. package/src/renderer/shared/utils/workspaceDrag.ts +142 -0
  349. package/src/renderer/shared/utils/workspaceMedia.ts +10 -2
  350. package/src/renderer/src/App.tsx +14 -8
  351. package/src/renderer/src/agentProgress.ts +1 -0
  352. package/src/renderer/src/components/ScreenPicker.css +1 -1
  353. package/src/renderer/src/components/WorkspacePanel.tsx +6 -5
  354. package/src/renderer/src/css/app-shell.css +4 -4
  355. package/src/renderer/src/css/chat.css +1261 -241
  356. package/src/renderer/src/css/desktop-tools.css +11 -11
  357. package/src/renderer/src/css/sidebar-workspace.css +2 -2
  358. package/src/renderer/src/css/tool-surfaces.css +12 -12
  359. package/src/renderer/src/index.css +38 -20
  360. package/src/renderer/src/tauri.ts +22 -2
  361. package/src/renderer/src-web/App.tsx +14 -0
  362. package/src/renderer/src-web/agentProgress.ts +1 -0
  363. package/src/renderer/src-web/css/app-shell.css +4 -4
  364. package/src/renderer/src-web/css/chat.css +1278 -190
  365. package/src/renderer/src-web/css/mobile.css +29 -13
  366. package/src/renderer/src-web/css/settings/mobile.css +2 -2
  367. package/src/renderer/src-web/css/sidebar-workspace.css +1 -1
  368. package/src/renderer/src-web/index.css +38 -20
  369. package/src/renderer/src-web/tauri.ts +22 -2
  370. package/src/renderer/tests/browserArtifacts.browser.tsx +1 -1
  371. package/src/renderer/tests/library.browser.tsx +3 -0
  372. package/src/renderer/tests/liveVoice.browser.html +1 -0
  373. package/src/renderer/tests/workspaceDrop.browser.tsx +1 -1
  374. package/src-tauri/src/app/lifecycle.rs +1 -14
  375. package/src-tauri/src/background/headless.rs +14 -8
  376. package/src-tauri/src/commands/conversation.rs +38 -0
  377. package/src-tauri/src/native/mod.rs +0 -1
  378. package/src-tauri/src/native/system.rs +4 -47
  379. package/crates/mint-cli/src/interactive/chat_tui.rs +0 -8855
  380. package/crates/mint-core/src/agent/chat.rs +0 -4394
  381. package/crates/mint-core/src/browser/lifecycle.rs +0 -291
  382. package/crates/mint-core/src/browser/logging.rs +0 -20
  383. package/crates/mint-core/src/orchestration/tools/browser.rs +0 -31
  384. package/out/web/assets/ArtifactPreviewPanel-S0dPfYFx.js +0 -2
  385. package/out/web/assets/CalculationCard-CRjP3E1j.js +0 -1
  386. package/out/web/assets/CliSessionsView-C3Br2v5Y.css +0 -1
  387. package/out/web/assets/CodeReviewPage-CUJceQme.css +0 -1
  388. package/out/web/assets/CodeReviewPage-VCUgPla_.js +0 -2
  389. package/out/web/assets/ImageGenCard-BCXxkVJX.js +0 -1
  390. package/out/web/assets/ImageSearchCard-N3yQOr8Z.js +0 -1
  391. package/out/web/assets/LibraryPage-DAxUTAg7.css +0 -1
  392. package/out/web/assets/LibraryPage-WlviRdR8.js +0 -2
  393. package/out/web/assets/LinkedFoldersView-CKRgroWK.js +0 -1
  394. package/out/web/assets/McpServersView-D3wHnuHg.js +0 -1
  395. package/out/web/assets/MermaidCard-NqrHdyJW.js +0 -2
  396. package/out/web/assets/MintDashboard-B2DJsDDO.css +0 -1
  397. package/out/web/assets/MintDashboard-COw_xol7.js +0 -63
  398. package/out/web/assets/RewindModal-DempuDod.js +0 -1
  399. package/out/web/assets/SettingsWindow-2YP3yj7s.js +0 -4
  400. package/out/web/assets/SettingsWindow-Dz8LQVgD.css +0 -1
  401. package/out/web/assets/StockCard-BDMCe7mx.js +0 -1
  402. package/out/web/assets/ToolSurfacePage-B0J_q0Jl.js +0 -38
  403. package/out/web/assets/ToolSurfacePage-CRIQ1owD.css +0 -1
  404. package/out/web/assets/UiMockupWidget-DD73QWg1.js +0 -1
  405. package/out/web/assets/WeatherCard-CPucIfq8.js +0 -1
  406. package/out/web/assets/WorkspacePdfPreview-Dx_lkjNu.js +0 -2
  407. package/out/web/assets/classDiagram-ZZMXUADV-BgJ5WtSp.js +0 -1
  408. package/out/web/assets/classDiagram-v2-VYDZK3BY-BgJ5WtSp.js +0 -1
  409. package/out/web/assets/config-CvIO5hkn.js +0 -2
  410. package/out/web/assets/flowDiagram-HODETNUW-uqCHJond.js +0 -1
  411. package/out/web/assets/index-BmpulIkg.js +0 -168
  412. package/out/web/assets/index-CkvBwhX_.css +0 -1
  413. package/out/web/assets/stateDiagram-v2-MP3YSRHH-uf3kdNW4.js +0 -1
  414. package/out/web/assets/swimlanesDiagram-VR7AAH4N-Y8q5bQce.js +0 -8
  415. package/shared-modules/libsecret/libsecret.json +0 -23
  416. package/shared-modules/libusb/libusb.json +0 -27
  417. package/shared-modules/lzo/lzo.json +0 -27
  418. package/src/renderer/src/components/BrowserShell.tsx +0 -108
  419. package/src/renderer/src/components/BrowserSuggestionsPopup.tsx +0 -91
  420. package/src/renderer/src/components/browser-shell.css +0 -185
  421. package/src-tauri/src/native/browser.rs +0 -252
@@ -60,30 +60,37 @@ pub(super) fn render_messages_as_text(messages: &[ChatMessage]) -> String {
60
60
  pub(super) async fn compact_native_messages(
61
61
  config: &MintConfig,
62
62
  messages: &[ChatMessage],
63
+ history_prefix_len: usize,
63
64
  ) -> Result<Option<(Vec<ChatMessage>, Option<String>)>, ChatError> {
64
- let step_pairs = messages.len().saturating_sub(1) / 2;
65
- if step_pairs <= COMPACTION_KEEP_RECENT_STEPS || messages.is_empty() {
65
+ let step_start = history_prefix_len + 1;
66
+ if messages.len() <= step_start {
67
+ return Ok(None);
68
+ }
69
+ let step_pairs = (messages.len() - step_start) / 2;
70
+ if step_pairs <= COMPACTION_KEEP_RECENT_STEPS {
66
71
  return Ok(None);
67
72
  }
68
73
  let compact_pairs = step_pairs - COMPACTION_KEEP_RECENT_STEPS;
69
74
  let compact_message_count = compact_pairs * 2;
70
- let compacted_range = &messages[1..1 + compact_message_count];
75
+ let compacted_range = &messages[step_start..step_start + compact_message_count];
71
76
 
72
77
  let transcript = render_messages_as_text(compacted_range);
73
78
  let summary_prompt = format!(
74
- "Summarize the following part of an autonomous coding agent's work log concisely but \
75
- completely. Preserve: exact file paths touched and their resulting state, exact \
76
- commands run and whether they succeeded, key findings from searches/reads, and any \
77
- decisions or open threads still relevant to finishing the task. Omit verbose \
78
- stdout/stderr detail that isn't load-bearing. Write it as dense prose, not a copy of \
79
- the log.\n\n{transcript}"
79
+ "Compress the following execution log of an autonomous coding agent into a high-density, \
80
+ structured milestone summary. Format your summary strictly under these markdown headings:\n\
81
+ ### Milestone Summary (Steps 1-{compact_pairs})\n\
82
+ - **Core Intent & Scope**: The user's original objective and requirements.\n\
83
+ - **Files Modified & Validated**: Exact file paths modified, created, or tested with outcomes.\n\
84
+ - **Key Discoveries & Decisions**: Architectural decisions made, bugs identified, approaches tried and dismissed.\n\
85
+ - **Pending / Next Steps**: Tasks remaining to be completed.\n\n\
86
+ Omit raw stdout/stderr logs and redundant command boilerplate. Focus strictly on facts and state.\n\n{transcript}"
80
87
  );
81
88
 
82
89
  let summary_result = send_chat_with_fallback(
83
90
  config,
84
91
  &ChatRequest {
85
92
  message: summary_prompt,
86
- system_instruction: "You compress agent work logs into dense, factual summaries."
93
+ system_instruction: "You compress agent work logs into dense, structured milestone summaries retaining all critical paths, decisions, and pending tasks."
87
94
  .into(),
88
95
  chat_id: None,
89
96
  image_data_uri: None,
@@ -105,7 +112,12 @@ pub(super) async fn compact_native_messages(
105
112
  match summary_result {
106
113
  Ok((summary_response, fallback_provider)) => {
107
114
  let mut compacted = Vec::with_capacity(messages.len() - compact_message_count + 3);
108
- compacted.push(messages[0].clone());
115
+ if messages.len() > history_prefix_len {
116
+ compacted.extend_from_slice(&messages[..history_prefix_len]);
117
+ compacted.push(messages[history_prefix_len].clone());
118
+ } else {
119
+ compacted.extend_from_slice(messages);
120
+ }
109
121
  compacted.push(ChatMessage {
110
122
  role: ChatRole::Assistant,
111
123
  content: vec![ContentBlock::Text {
@@ -122,15 +134,19 @@ pub(super) async fn compact_native_messages(
122
134
  .into(),
123
135
  }],
124
136
  });
125
- compacted.extend_from_slice(&messages[1 + compact_message_count..]);
137
+ compacted.extend_from_slice(&messages[step_start + compact_message_count..]);
126
138
  Ok(Some((compacted, fallback_provider)))
127
139
  }
128
140
  Err(err) => {
129
141
  // LLM summarization failed (timeout, rate limit 429, provider offline, or context limit).
130
142
  // Rather than returning Err and leaving native_messages uncompacted (which causes the next
131
143
  // agent turn to crash with context window exceeded), fall back to deterministic hard-truncation.
132
- let truncated =
133
- hard_truncate_native_messages(messages, compact_pairs, &err.to_string());
144
+ let truncated = hard_truncate_native_messages(
145
+ messages,
146
+ history_prefix_len,
147
+ compact_pairs,
148
+ &err.to_string(),
149
+ );
134
150
  Ok(Some((
135
151
  truncated,
136
152
  Some(format!("hard-truncate fallback ({err})")),
@@ -141,13 +157,15 @@ pub(super) async fn compact_native_messages(
141
157
 
142
158
  pub(super) fn hard_truncate_native_messages(
143
159
  messages: &[ChatMessage],
160
+ history_prefix_len: usize,
144
161
  compact_pairs: usize,
145
162
  error_reason: &str,
146
163
  ) -> Vec<ChatMessage> {
164
+ let step_start = history_prefix_len + 1;
147
165
  let compact_message_count = compact_pairs * 2;
148
- let compacted_range = if messages.len() > 1 {
149
- let end = (1 + compact_message_count).min(messages.len());
150
- &messages[1..end]
166
+ let compacted_range = if messages.len() > step_start {
167
+ let end = (step_start + compact_message_count).min(messages.len());
168
+ &messages[step_start..end]
151
169
  } else {
152
170
  &[]
153
171
  };
@@ -193,8 +211,11 @@ pub(super) fn hard_truncate_native_messages(
193
211
 
194
212
  let mut compacted =
195
213
  Vec::with_capacity(messages.len().saturating_sub(compact_message_count) + 3);
196
- if !messages.is_empty() {
197
- compacted.push(messages[0].clone());
214
+ if messages.len() > history_prefix_len {
215
+ compacted.extend_from_slice(&messages[..history_prefix_len]);
216
+ compacted.push(messages[history_prefix_len].clone());
217
+ } else {
218
+ compacted.extend_from_slice(messages);
198
219
  }
199
220
  compacted.push(ChatMessage {
200
221
  role: ChatRole::Assistant,
@@ -208,8 +229,8 @@ pub(super) fn hard_truncate_native_messages(
208
229
  text: "Continue the task using the summary above and the recent steps below.".into(),
209
230
  }],
210
231
  });
211
- if messages.len() > 1 + compact_message_count {
212
- compacted.extend_from_slice(&messages[1 + compact_message_count..]);
232
+ if messages.len() > step_start + compact_message_count {
233
+ compacted.extend_from_slice(&messages[step_start + compact_message_count..]);
213
234
  }
214
235
  compacted
215
236
  }
@@ -249,9 +270,32 @@ pub(super) fn initial_observation(task: &str, root: &Path, skills: &str) -> Stri
249
270
  observation
250
271
  }
251
272
 
273
+ /// Compacts an older trajectory step's verbose observation into a single line preview
274
+ /// to prevent `observation` buffer bloat across long-running tasks.
275
+ fn compact_trajectory_step_preview(step_str: &str) -> String {
276
+ if let Some(obs_idx) = step_str.find("\n- Observation:") {
277
+ let prefix = &step_str[..obs_idx + "\n- Observation:".len()];
278
+ let obs_text = step_str[obs_idx + "\n- Observation:".len()..].trim();
279
+ if obs_text.chars().count() > 120 {
280
+ let first_line = obs_text
281
+ .lines()
282
+ .find(|l| !l.trim().is_empty())
283
+ .unwrap_or("");
284
+ let truncated = if first_line.chars().count() > 80 {
285
+ format!("{}...", &first_line[..77])
286
+ } else {
287
+ first_line.to_string()
288
+ };
289
+ return format!("{prefix} {truncated} (details collapsed for earlier step)");
290
+ }
291
+ }
292
+ step_str.to_string()
293
+ }
294
+
252
295
  /// Rebuilds the `observation` string buffer from the current trajectory in-place,
253
296
  /// reusing the underlying allocation across agent-loop steps to avoid repeated
254
297
  /// heap re-allocations and redundant copies.
298
+ /// Preserves full detail for the most recent 5 steps while compacting older observations.
255
299
  pub(super) fn rebuild_observation(
256
300
  task: &str,
257
301
  root: &Path,
@@ -270,11 +314,17 @@ pub(super) fn rebuild_observation(
270
314
  "Task: {task}\nWorkspace: {}\n\nHere is the history of what you have done so far in this agent loop:\n\n",
271
315
  root_display
272
316
  );
317
+ let recent_cutoff = trajectory.len().saturating_sub(5);
273
318
  for (i, step) in trajectory.iter().enumerate() {
274
319
  if i > 0 {
275
320
  target.push_str("\n\n");
276
321
  }
277
- target.push_str(step);
322
+ if i < recent_cutoff {
323
+ let compacted = compact_trajectory_step_preview(step);
324
+ target.push_str(&compacted);
325
+ } else {
326
+ target.push_str(step);
327
+ }
278
328
  }
279
329
  target.push_str(
280
330
  "\n\nProceed to the next step. If you have completed the task, use the 'finish' action.",
@@ -352,6 +402,163 @@ pub(super) fn prune_historic_images_from_native_messages(
352
402
  pruned_count
353
403
  }
354
404
 
405
+ /// Progressively ages older `ContentBlock::ToolResult` entries out of prompt memory
406
+ /// using a Three-Tier Retention Policy (Cursor / Claude Code pattern):
407
+ /// - Hot Zone (most recent `hot_steps` tool turns): Preserves full output verbatim.
408
+ /// - Warm Zone (turns between `hot_steps + 1` and `hot_steps + warm_steps`):
409
+ /// Truncates verbose outputs (> 500 chars) to initial lines + omission note.
410
+ /// - Cold Zone (older than `hot_steps + warm_steps`):
411
+ /// Collapses output into a 1-line tombstone summary.
412
+ ///
413
+ /// Returns the number of tool results compacted.
414
+ pub(super) fn prune_historic_tool_results_from_native_messages(
415
+ messages: &mut [ChatMessage],
416
+ hot_steps: usize,
417
+ warm_steps: usize,
418
+ ) -> usize {
419
+ if messages.is_empty() {
420
+ return 0;
421
+ }
422
+ let mut tool_count = 0;
423
+ let mut compacted_count = 0;
424
+
425
+ for message in messages.iter_mut().rev() {
426
+ if message.role == ChatRole::Tool {
427
+ tool_count += 1;
428
+ if tool_count <= hot_steps {
429
+ // Hot zone: keep full detail
430
+ continue;
431
+ } else if tool_count <= hot_steps + warm_steps {
432
+ // Warm zone: compress if long
433
+ for block in &mut message.content {
434
+ if let ContentBlock::ToolResult { content, .. } = block {
435
+ if content.chars().count() > 500
436
+ && !content.starts_with("[Tool Result:")
437
+ && !content.starts_with("[read_file")
438
+ {
439
+ let lines: Vec<&str> = content.lines().collect();
440
+ if lines.len() > 12 {
441
+ let head = lines[..8].join("\n");
442
+ let omitted = lines.len() - 10;
443
+ let tail = lines[lines.len() - 2..].join("\n");
444
+ *content = format!(
445
+ "{head}\n\n[... {omitted} lines collapsed for earlier turn ...]\n{tail}"
446
+ );
447
+ compacted_count += 1;
448
+ }
449
+ }
450
+ }
451
+ }
452
+ } else {
453
+ // Cold zone: collapse to 1-line tombstone
454
+ for block in &mut message.content {
455
+ if let ContentBlock::ToolResult {
456
+ content, is_error, ..
457
+ } = block
458
+ {
459
+ if !content.starts_with("[Tool Result:")
460
+ && !content.starts_with("[read_file")
461
+ {
462
+ if *is_error {
463
+ let err_line = content
464
+ .lines()
465
+ .find(|l| !l.trim().is_empty())
466
+ .unwrap_or("Failed");
467
+ let trimmed_err = if err_line.len() > 70 {
468
+ format!("{}...", &err_line[..67])
469
+ } else {
470
+ err_line.to_string()
471
+ };
472
+ *content = format!(
473
+ "[Tool Result: Failed ({trimmed_err}) — log collapsed for past step]"
474
+ );
475
+ } else {
476
+ *content =
477
+ "[Tool Result: Succeeded — output collapsed for past step]"
478
+ .to_string();
479
+ }
480
+ compacted_count += 1;
481
+ }
482
+ }
483
+ }
484
+ }
485
+ }
486
+ }
487
+ compacted_count
488
+ }
489
+
490
+ /// When a file edit succeeds in the agent loop, scans earlier `ChatMessage` history
491
+ /// for prior `read_file` tool results targeting any of `modified_paths`.
492
+ /// Collapses their bodies into a concise note indicating their content is superseded.
493
+ /// Prevents the model from reading obsolete code states and saves tokens.
494
+ ///
495
+ /// Returns the number of read_file results superseded.
496
+ pub(super) fn supersede_stale_file_reads(
497
+ messages: &mut [ChatMessage],
498
+ modified_paths: &[String],
499
+ current_step: usize,
500
+ ) -> usize {
501
+ if messages.is_empty() || modified_paths.is_empty() {
502
+ return 0;
503
+ }
504
+
505
+ // Map tool_use_id -> file path for any read_file ToolUse targeting modified_paths
506
+ let mut superseded_call_ids: std::collections::HashMap<String, String> =
507
+ std::collections::HashMap::new();
508
+
509
+ for message in messages.iter() {
510
+ if message.role == ChatRole::Assistant {
511
+ for block in &message.content {
512
+ if let ContentBlock::ToolUse {
513
+ id, name, input, ..
514
+ } = block
515
+ {
516
+ if name == "read_file" {
517
+ if let Some(target_path) = input.get("path").and_then(|p| p.as_str()) {
518
+ if modified_paths.iter().any(|m| {
519
+ m == target_path
520
+ || target_path.ends_with(m.as_str())
521
+ || m.ends_with(target_path)
522
+ }) {
523
+ superseded_call_ids.insert(id.clone(), target_path.to_string());
524
+ }
525
+ }
526
+ }
527
+ }
528
+ }
529
+ }
530
+ }
531
+
532
+ if superseded_call_ids.is_empty() {
533
+ return 0;
534
+ }
535
+
536
+ let mut superseded_count = 0;
537
+ for message in messages.iter_mut() {
538
+ if message.role == ChatRole::Tool {
539
+ for block in &mut message.content {
540
+ if let ContentBlock::ToolResult {
541
+ tool_use_id,
542
+ content,
543
+ ..
544
+ } = block
545
+ {
546
+ if let Some(path) = superseded_call_ids.get(tool_use_id) {
547
+ if !content.starts_with("[read_file") {
548
+ *content = format!(
549
+ "[read_file \"{path}\": Content superseded by file modifications at Step {current_step}]"
550
+ );
551
+ superseded_count += 1;
552
+ }
553
+ }
554
+ }
555
+ }
556
+ }
557
+ }
558
+
559
+ superseded_count
560
+ }
561
+
355
562
  /// Sends a lifecycle around the actual summarizer await; callers retain the
356
563
  /// original messages on failure. Short histories do not enter this UI state.
357
564
  pub(super) async fn report_context_compaction<F>(
@@ -682,7 +889,7 @@ mod compaction_progress_tests {
682
889
  messages.extend(sample_step_pair(i));
683
890
  }
684
891
  // 5 step pairs total (11 messages). Compact 2 pairs (steps 0 and 1), keeping steps 2, 3, 4 (3 pairs = 6 msgs).
685
- let truncated = hard_truncate_native_messages(&messages, 2, "mock provider failure");
892
+ let truncated = hard_truncate_native_messages(&messages, 0, 2, "mock provider failure");
686
893
 
687
894
  assert_eq!(truncated.len(), 1 + 2 + 6);
688
895
  assert_eq!(truncated[0].role, ChatRole::User);
@@ -726,7 +933,9 @@ mod compaction_progress_tests {
726
933
  ai_provider: "non_existent_provider_that_will_fail".into(),
727
934
  ..Default::default()
728
935
  };
729
- let result = compact_native_messages(&config, &messages).await.unwrap();
936
+ let result = compact_native_messages(&config, &messages, 0)
937
+ .await
938
+ .unwrap();
730
939
  assert!(result.is_some());
731
940
  let (compacted, fallback) = result.unwrap();
732
941
  assert_eq!(compacted.len(), 1 + 2 + 6);
@@ -734,4 +943,212 @@ mod compaction_progress_tests {
734
943
  assert_eq!(compacted[2].role, ChatRole::User);
735
944
  assert!(fallback.as_deref().unwrap_or("").contains("hard-truncate"));
736
945
  }
946
+
947
+ #[tokio::test]
948
+ async fn compact_native_messages_preserves_conversation_history_prefix() {
949
+ // Build 2 historical conversation turns (4 messages: User, Assistant, User, Assistant)
950
+ let mut messages = vec![
951
+ ChatMessage::text(ChatRole::User, "ประวัติคุยรอบ 1"),
952
+ ChatMessage::text(ChatRole::Assistant, "ตอบประวัติรอบ 1"),
953
+ ChatMessage::text(ChatRole::User, "ประวัติคุยรอบ 2"),
954
+ ChatMessage::text(ChatRole::Assistant, "ตอบประวัติรอบ 2"),
955
+ ];
956
+ let history_prefix_len = messages.len();
957
+
958
+ // Current agent turn initial observation
959
+ messages.push(ChatMessage::text(ChatRole::User, "งานปัจจุบันรอบ 3"));
960
+
961
+ // Current turn execution steps: 5 step pairs (10 messages)
962
+ for i in 0..5 {
963
+ messages.extend(sample_step_pair(i));
964
+ }
965
+
966
+ let config = MintConfig {
967
+ ai_provider: "non_existent_provider_that_will_fail".into(),
968
+ ..Default::default()
969
+ };
970
+
971
+ let result = compact_native_messages(&config, &messages, history_prefix_len)
972
+ .await
973
+ .unwrap();
974
+ assert!(result.is_some());
975
+ let (compacted, _) = result.unwrap();
976
+
977
+ // Expected structure:
978
+ // [0..4] Historical conversation messages intact
979
+ // [4] Current turn initial task intact
980
+ // [5] Assistant compacted summary of steps 1-2
981
+ // [6] User continuation prompt
982
+ // [7..13] Recent 3 step pairs (6 messages)
983
+ assert_eq!(compacted.len(), 4 + 1 + 2 + 6);
984
+
985
+ // Verify history messages remain identical
986
+ assert_eq!(compacted[0].role, ChatRole::User);
987
+ assert_eq!(
988
+ compacted[0].content,
989
+ vec![ContentBlock::Text {
990
+ text: "ประวัติคุยรอบ 1".into()
991
+ }]
992
+ );
993
+ assert_eq!(compacted[1].role, ChatRole::Assistant);
994
+ assert_eq!(
995
+ compacted[1].content,
996
+ vec![ContentBlock::Text {
997
+ text: "ตอบประวัติรอบ 1".into()
998
+ }]
999
+ );
1000
+ assert_eq!(compacted[2].role, ChatRole::User);
1001
+ assert_eq!(
1002
+ compacted[2].content,
1003
+ vec![ContentBlock::Text {
1004
+ text: "ประวัติคุยรอบ 2".into()
1005
+ }]
1006
+ );
1007
+ assert_eq!(compacted[3].role, ChatRole::Assistant);
1008
+ assert_eq!(
1009
+ compacted[3].content,
1010
+ vec![ContentBlock::Text {
1011
+ text: "ตอบประวัติรอบ 2".into()
1012
+ }]
1013
+ );
1014
+
1015
+ // Verify current turn initial task intact
1016
+ assert_eq!(compacted[4].role, ChatRole::User);
1017
+ assert_eq!(
1018
+ compacted[4].content,
1019
+ vec![ContentBlock::Text {
1020
+ text: "งานปัจจุบันรอบ 3".into()
1021
+ }]
1022
+ );
1023
+
1024
+ // Verify summary block
1025
+ assert_eq!(compacted[5].role, ChatRole::Assistant);
1026
+ match &compacted[5].content[0] {
1027
+ ContentBlock::Text { text } => {
1028
+ assert!(text.contains("Summary of steps 1-2"));
1029
+ assert!(text.contains("file0.rs"));
1030
+ assert!(text.contains("file1.rs"));
1031
+ }
1032
+ _ => panic!("Expected Text block in summary"),
1033
+ }
1034
+
1035
+ // Verify continuation prompt
1036
+ assert_eq!(compacted[6].role, ChatRole::User);
1037
+
1038
+ // Verify recent step pairs preserved
1039
+ assert_eq!(compacted[7].role, ChatRole::Assistant);
1040
+ assert_eq!(compacted[8].role, ChatRole::Tool);
1041
+ }
1042
+
1043
+ #[test]
1044
+ fn test_prune_historic_tool_results_progressive_aging() {
1045
+ let mut messages = vec![ChatMessage::text(ChatRole::User, "initial task")];
1046
+ // Create 15 steps with verbose outputs (> 500 chars)
1047
+ for i in 0..15 {
1048
+ let verbose_log =
1049
+ format!("Line 1 of step {i}: compiler diagnostic message\n").repeat(30);
1050
+ messages.push(ChatMessage {
1051
+ role: ChatRole::Assistant,
1052
+ content: vec![ContentBlock::ToolUse {
1053
+ id: format!("call{i}"),
1054
+ name: "run_shell".into(),
1055
+ input: serde_json::json!({"cmd": "cargo check"}),
1056
+ thought_signature: None,
1057
+ }],
1058
+ });
1059
+ messages.push(ChatMessage {
1060
+ role: ChatRole::Tool,
1061
+ content: vec![ContentBlock::ToolResult {
1062
+ tool_use_id: format!("call{i}"),
1063
+ content: verbose_log,
1064
+ is_error: false,
1065
+ }],
1066
+ });
1067
+ }
1068
+
1069
+ // 3 hot steps, 7 warm steps
1070
+ let compacted = prune_historic_tool_results_from_native_messages(&mut messages, 3, 7);
1071
+ assert!(compacted > 0);
1072
+
1073
+ // Tool messages are at indices 2, 4, 6, ..., 30.
1074
+ // Step 14 is index 30 (hot, tool_count = 1) -> full text
1075
+ // Step 13 is index 28 (hot, tool_count = 2) -> full text
1076
+ // Step 12 is index 26 (hot, tool_count = 3) -> full text
1077
+ let msg_hot = &messages[30];
1078
+ if let ContentBlock::ToolResult { content, .. } = &msg_hot.content[0] {
1079
+ assert!(content.contains("Line 1 of step 14"));
1080
+ assert!(!content.contains("collapsed"));
1081
+ }
1082
+
1083
+ // Step 11 is index 24 (warm, tool_count = 4) -> warm collapsed
1084
+ let msg_warm = &messages[24];
1085
+ if let ContentBlock::ToolResult { content, .. } = &msg_warm.content[0] {
1086
+ assert!(content.contains("lines collapsed for earlier turn"));
1087
+ }
1088
+
1089
+ // Step 0 is index 2 (cold, tool_count = 15) -> tombstone
1090
+ let msg_cold = &messages[2];
1091
+ if let ContentBlock::ToolResult { content, .. } = &msg_cold.content[0] {
1092
+ assert_eq!(
1093
+ content,
1094
+ "[Tool Result: Succeeded — output collapsed for past step]"
1095
+ );
1096
+ }
1097
+ }
1098
+
1099
+ #[test]
1100
+ fn test_supersede_stale_file_reads() {
1101
+ let mut messages = vec![ChatMessage::text(ChatRole::User, "initial task")];
1102
+ // Step 1: read_file "src/main.rs"
1103
+ messages.push(ChatMessage {
1104
+ role: ChatRole::Assistant,
1105
+ content: vec![ContentBlock::ToolUse {
1106
+ id: "call_read_1".into(),
1107
+ name: "read_file".into(),
1108
+ input: serde_json::json!({"path": "src/main.rs"}),
1109
+ thought_signature: None,
1110
+ }],
1111
+ });
1112
+ messages.push(ChatMessage {
1113
+ role: ChatRole::Tool,
1114
+ content: vec![ContentBlock::ToolResult {
1115
+ tool_use_id: "call_read_1".into(),
1116
+ content: "fn main() { println!(\"old code\"); }".into(),
1117
+ is_error: false,
1118
+ }],
1119
+ });
1120
+
1121
+ // Step 2: edit src/main.rs
1122
+ let superseded = supersede_stale_file_reads(&mut messages, &["src/main.rs".to_string()], 2);
1123
+ assert_eq!(superseded, 1);
1124
+
1125
+ if let ContentBlock::ToolResult { content, .. } = &messages[2].content[0] {
1126
+ assert!(content.contains("Content superseded by file modifications at Step 2"));
1127
+ assert!(!content.contains("old code"));
1128
+ }
1129
+ }
1130
+
1131
+ #[test]
1132
+ fn test_rebuild_observation_compacts_older_trajectory_steps() {
1133
+ let root = Path::new("/workspace");
1134
+ let task = "Build project";
1135
+ let mut trajectory = Vec::new();
1136
+ for i in 1..=8 {
1137
+ let obs = format!("Long compiler output line for step {i}\n").repeat(10);
1138
+ trajectory.push(format_trajectory_step(
1139
+ i,
1140
+ "Checking code",
1141
+ "run_shell",
1142
+ &obs,
1143
+ ));
1144
+ }
1145
+
1146
+ let mut buffer = String::new();
1147
+ rebuild_observation(task, root, &trajectory, &mut buffer);
1148
+
1149
+ // Step 1 is older than 5 steps back -> compacted
1150
+ assert!(buffer.contains("details collapsed for earlier step"));
1151
+ // Step 8 is recent -> full observation intact
1152
+ assert!(buffer.contains("Long compiler output line for step 8"));
1153
+ }
737
1154
  }