@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.
- package/Cargo.lock +6 -6
- package/Cargo.toml +2 -2
- package/README.md +8 -2
- package/Release_Note.md +222 -71
- package/crates/mint-cli/src/agent/diff_render.rs +66 -44
- package/crates/mint-cli/src/agent/live_status.rs +21 -4
- package/crates/mint-cli/src/agent/markdown_render.rs +342 -5
- package/crates/mint-cli/src/agent.rs +25 -10
- package/crates/mint-cli/src/commands/agent.rs +4 -92
- package/crates/mint-cli/src/commands/browser.rs +2 -15
- package/crates/mint-cli/src/commands/integrations.rs +3 -3
- package/crates/mint-cli/src/commands/mod.rs +0 -3
- package/crates/mint-cli/src/commands/tailnet_web.rs +1 -0
- package/crates/mint-cli/src/interactive/chat_tui/dialog.rs +572 -0
- package/crates/mint-cli/src/interactive/chat_tui/mod.rs +1427 -0
- package/crates/mint-cli/src/interactive/chat_tui/render.rs +1524 -0
- package/crates/mint-cli/src/interactive/chat_tui/selection.rs +401 -0
- package/crates/mint-cli/src/interactive/chat_tui/state.rs +1833 -0
- package/crates/mint-cli/src/interactive/chat_tui/tests.rs +3414 -0
- package/crates/mint-cli/src/interactive/chat_tui/thought.rs +202 -0
- package/crates/mint-cli/src/interactive/chat_tui/transcript.rs +728 -0
- package/crates/mint-cli/src/interactive/chat_tui/watermark.rs +148 -0
- package/crates/mint-cli/src/interactive/command_ui.rs +53 -5
- package/crates/mint-cli/src/interactive/composer.rs +186 -0
- package/crates/mint-cli/src/interactive/format.rs +78 -3
- package/crates/mint-cli/src/interactive/input_box.rs +61 -1
- package/crates/mint-cli/src/interactive/resume_picker.rs +367 -25
- package/crates/mint-cli/src/interactive/slash_commands.rs +648 -371
- package/crates/mint-cli/src/interactive/tool_activity.rs +93 -20
- package/crates/mint-cli/src/interactive.rs +37 -0
- package/crates/mint-cli/src/main.rs +6 -3
- package/crates/mint-cli/src/markdown.rs +2 -37
- package/crates/mint-cli/src/onboard.rs +700 -282
- package/crates/mint-cli/src/setup.rs +1342 -624
- package/crates/mint-cli/src/terminal_theme.rs +159 -35
- package/crates/mint-cli/tests/library_intake.rs +1 -0
- package/crates/mint-core/src/agent/chat/anthropic.rs +318 -0
- package/crates/mint-core/src/agent/chat/custom.rs +149 -0
- package/crates/mint-core/src/agent/chat/gemini.rs +518 -0
- package/crates/mint-core/src/agent/chat/mod.rs +857 -0
- package/crates/mint-core/src/agent/chat/ollama.rs +321 -0
- package/crates/mint-core/src/agent/chat/openai.rs +582 -0
- package/crates/mint-core/src/agent/chat/streaming.rs +469 -0
- package/crates/mint-core/src/agent/chat/tests.rs +1479 -0
- package/crates/mint-core/src/agent/memory.rs +56 -2
- package/crates/mint-core/src/agent/tasks.rs +2 -2
- package/crates/mint-core/src/api_server/routes/chat.rs +24 -2
- package/crates/mint-core/src/api_server/routes/gemini_live.rs +14 -1
- package/crates/mint-core/src/api_server/routes/html_preview.rs +1 -8
- package/crates/mint-core/src/api_server/routes/sessions.rs +21 -0
- package/crates/mint-core/src/avatar_bridge.rs +0 -22
- package/crates/mint-core/src/browser/cdp.rs +10 -4
- package/crates/mint-core/src/browser/headless.rs +582 -0
- package/crates/mint-core/src/browser/input.rs +7 -62
- package/crates/mint-core/src/browser/interact.rs +0 -14
- package/crates/mint-core/src/browser/mod.rs +8 -29
- package/crates/mint-core/src/browser/navigate.rs +2 -36
- package/crates/mint-core/src/browser/runtime.rs +2 -4
- package/crates/mint-core/src/browser/session.rs +50 -466
- package/crates/mint-core/src/browser/workflow.rs +142 -32
- package/crates/mint-core/src/cron/store.rs +2 -2
- package/crates/mint-core/src/integrations/mcp.rs +6 -8
- package/crates/mint-core/src/lib.rs +0 -5
- package/crates/mint-core/src/media/gemini_live.rs +636 -86
- package/crates/mint-core/src/media/library/migration.rs +26 -0
- package/crates/mint-core/src/media/library/tests.rs +1 -1
- package/crates/mint-core/src/media/library/thumbnails.rs +8 -2
- package/crates/mint-core/src/media/pictures.rs +1 -1
- package/crates/mint-core/src/media/tool_images.rs +92 -1
- package/crates/mint-core/src/mods/manager.rs +101 -35
- package/crates/mint-core/src/orchestration/context_render.rs +441 -24
- package/crates/mint-core/src/orchestration/decision_parsing.rs +531 -16
- package/crates/mint-core/src/orchestration/full_skill_result_tests.rs +12 -0
- package/crates/mint-core/src/orchestration/loop_guard.rs +145 -0
- package/crates/mint-core/src/orchestration/mcp_outcome_tests.rs +864 -0
- package/crates/mint-core/src/orchestration/memory_skill.rs +88 -28
- package/crates/mint-core/src/orchestration/mod.rs +320 -4249
- package/crates/mint-core/src/orchestration/reliability.rs +67 -27
- package/crates/mint-core/src/orchestration/review_regressions.rs +5 -0
- package/crates/mint-core/src/orchestration/tests.rs +1665 -0
- package/crates/mint-core/src/orchestration/tools/dispatch.rs +967 -0
- package/crates/mint-core/src/orchestration/tools/files.rs +1 -0
- package/crates/mint-core/src/orchestration/tools/mod.rs +5 -1
- package/crates/mint-core/src/orchestration/tools/planning.rs +102 -42
- package/crates/mint-core/src/orchestration/tools/shell.rs +129 -58
- package/crates/mint-core/src/orchestration/truncation.rs +170 -13
- package/crates/mint-core/src/orchestration/types.rs +648 -0
- package/crates/mint-core/src/orchestration/verification.rs +0 -3
- package/crates/mint-core/src/orchestration/workspace_helpers.rs +24 -6
- package/crates/mint-core/src/prompts/agent.rs +52 -76
- package/crates/mint-core/src/prompts/tool_catalog.rs +8 -151
- package/crates/mint-core/src/search/files.rs +20 -0
- package/crates/mint-core/src/slash/mod.rs +228 -265
- package/crates/mint-core/src/slash/models.rs +6 -1
- package/crates/mint-core/src/system/bg_shell.rs +1 -0
- package/crates/mint-core/src/system/config.rs +176 -34
- package/crates/mint-mod-runtime/src/lib.rs +37 -23
- package/out/web/assets/ArtifactPreviewPanel-Cx6BVOOF.js +2 -0
- package/out/web/assets/CalculationCard-D2E74u5q.js +1 -0
- package/out/web/assets/CliSessionsView-ZbdtSjvK.css +1 -0
- package/out/web/assets/{CliSessionsView-MI8kXMAb.js → CliSessionsView-z5i6qGyb.js} +1 -1
- package/out/web/assets/CodeReviewPage-BK2bOScd.css +1 -0
- package/out/web/assets/CodeReviewPage-Dp6zHuHu.js +2 -0
- package/out/web/assets/{CommandPalette-BD8SlTE5.js → CommandPalette-DaKlzbKs.js} +1 -1
- package/out/web/assets/ImageGenCard-BMCJHP9O.js +1 -0
- package/out/web/assets/ImageSearchCard-Cld_SOUg.js +1 -0
- package/out/web/assets/{ImageStudioPanel-BP7N4rLr.js → ImageStudioPanel-B5N7TjeB.js} +1 -1
- package/out/web/assets/LibraryPage-CMB89rJ0.css +1 -0
- package/out/web/assets/LibraryPage-DbZEi4W_.js +2 -0
- package/out/web/assets/LinkedFoldersView-9B9DIPoZ.js +1 -0
- package/out/web/assets/{McpRegistryPicker-CoS83vtc.js → McpRegistryPicker-DnXPlzI7.js} +1 -1
- package/out/web/assets/McpServersView-CiNBNUl4.js +1 -0
- package/out/web/assets/MermaidCard-BBDNEXbY.js +2 -0
- package/out/web/assets/MintDashboard-C_UYPoNV.js +119 -0
- package/out/web/assets/MintDashboard-DTd8C_c8.css +1 -0
- package/out/web/assets/PlanCard-C2x5pajq.js +1 -0
- package/out/web/assets/{PluginsView-jBYmcKh4.js → PluginsView-DoTg9MVa.js} +1 -1
- package/out/web/assets/RewindModal-B5oowrR0.js +1 -0
- package/out/web/assets/{ScheduledTasksView-5uw9-V9H.js → ScheduledTasksView-BD5DVPkZ.js} +1 -1
- package/out/web/assets/{SelectField-DXBQtrUK.js → SelectField-Cy6CghrU.js} +1 -1
- package/out/web/assets/SettingsWindow-BYl_oCFh.js +4 -0
- package/out/web/assets/SettingsWindow-Ckcgnjt8.css +1 -0
- package/out/web/assets/{SkillsView-C-gp9J7m.js → SkillsView-CIeWwq5z.js} +1 -1
- package/out/web/assets/StockCard-DxUciKyp.js +1 -0
- package/out/web/assets/ToolSurfacePage-qBgs_VHq.css +1 -0
- package/out/web/assets/ToolSurfacePage-saVbVrkE.js +38 -0
- package/out/web/assets/{UiFeatureCard-6BwxTOCe.js → UiFeatureCard-CdY0hGWy.js} +1 -1
- package/out/web/assets/{UiGridCard-DvZcLNxb.js → UiGridCard-BBK3I5hC.js} +1 -1
- package/out/web/assets/UiMockupWidget-CpR9EDuc.js +1 -0
- package/out/web/assets/{VeoStudioPanel-DOj7_WR3.css → VeoStudioPanel-9kU9YLEN.css} +1 -1
- package/out/web/assets/{VeoStudioPanel-DfsOJKv0.js → VeoStudioPanel-Co6-wEWM.js} +2 -2
- package/out/web/assets/WeatherCard-Buzi7Vfu.js +1 -0
- package/out/web/assets/WorkspacePdfPreview-Bi8Zzyir.js +2 -0
- package/out/web/assets/{abnfDiagram-VCTEODGH-BOo3Ckng.js → abnfDiagram-VCTEODGH-CMfR95N2.js} +1 -1
- package/out/web/assets/{architecture-7GRP2DOG-ZOwheW3n.js → architecture-7GRP2DOG-DhAM4HyO.js} +1 -1
- package/out/web/assets/{architectureDiagram-5GKGNRK7-DC2FDzVd.js → architectureDiagram-5GKGNRK7-Yk3TUJ_F.js} +1 -1
- package/out/web/assets/{blockDiagram-I7D4REHJ-BrKFWdAH.js → blockDiagram-I7D4REHJ-X9fBgJik.js} +1 -1
- package/out/web/assets/{c4Diagram-7LVT6UL2-BHTHK1Yd.js → c4Diagram-7LVT6UL2-Bk9x7N-8.js} +1 -1
- package/out/web/assets/{chunk-4HAMMTFA-BYFkZwNj.js → chunk-4HAMMTFA-Dx5fk1_0.js} +1 -1
- package/out/web/assets/{chunk-75Z2AOVW-BSKfSKSA.js → chunk-75Z2AOVW-BszTQoM4.js} +1 -1
- package/out/web/assets/{chunk-DU6HZSFF-vIhsiW6n.js → chunk-DU6HZSFF-DK-As3rk.js} +1 -1
- package/out/web/assets/{chunk-F27PBJKO-BlYpW9xq.js → chunk-F27PBJKO-LmncZZIS.js} +1 -1
- package/out/web/assets/{chunk-GMAD6QVW-BIBz_Ug5.js → chunk-GMAD6QVW-DSQ_sDRJ.js} +1 -1
- package/out/web/assets/{chunk-GVQU2GXP-NPSHxeqC.js → chunk-GVQU2GXP-Cno3ulje.js} +1 -1
- package/out/web/assets/{chunk-IMKFNOWR-YlJK8_Fp.js → chunk-IMKFNOWR-bIzfY9Jc.js} +1 -1
- package/out/web/assets/{chunk-L3NEJ4N5-DMYi4-af.js → chunk-L3NEJ4N5-Dl6eOa0D.js} +1 -1
- package/out/web/assets/{chunk-OSK3NFVY-Begd3-jA.js → chunk-OSK3NFVY-BaUGJ-cM.js} +1 -1
- package/out/web/assets/{chunk-P2QGCYS3-D1I4xFHN.js → chunk-P2QGCYS3-_066ndhH.js} +1 -1
- package/out/web/assets/{chunk-POPQ4Y6H-CafZZzNE.js → chunk-POPQ4Y6H-YT1AKhTv.js} +1 -1
- package/out/web/assets/{chunk-PWAF6VOD-Dwh6_Lnt.js → chunk-PWAF6VOD-CrEgDsxh.js} +1 -1
- package/out/web/assets/{chunk-SHT3W25Y-B0XrCSEb.js → chunk-SHT3W25Y-_KwaRLOl.js} +1 -1
- package/out/web/assets/{chunk-SVP7TREG-CxLsddxC.js → chunk-SVP7TREG-BQ1qb32L.js} +1 -1
- package/out/web/assets/{chunk-TICWLB2K-y156QInb.js → chunk-TICWLB2K-BDyehCtg.js} +1 -1
- package/out/web/assets/classDiagram-ZZMXUADV-BoSpzRCJ.js +1 -0
- package/out/web/assets/classDiagram-v2-VYDZK3BY-BoSpzRCJ.js +1 -0
- package/out/web/assets/{config-DqXJXeZM.css → config-2suVFPZg.css} +1 -1
- package/out/web/assets/config-CkRCdkxn.js +2 -0
- package/out/web/assets/{cynefin-OW5HDTMX-SMVvrLf-.js → cynefin-OW5HDTMX-Dl_31aaN.js} +1 -1
- package/out/web/assets/{cynefinDiagram-5FMLGOSQ-rZznN24T.js → cynefinDiagram-5FMLGOSQ-Bpir8jha.js} +1 -1
- package/out/web/assets/{dagre-GXQ25YYZ-BOToydFu.js → dagre-GXQ25YYZ-D9xu3nsq.js} +1 -1
- package/out/web/assets/{diagram-S7CK7UJ4-TMVaGQEJ.js → diagram-S7CK7UJ4-DeveoEeB.js} +1 -1
- package/out/web/assets/{diagram-UQ7AKVKN-C2JK-GP2.js → diagram-UQ7AKVKN-p4xWRESV.js} +1 -1
- package/out/web/assets/{diagram-VSXAHHWV-Cw8VSi2K.js → diagram-VSXAHHWV-C7qz9NDF.js} +1 -1
- package/out/web/assets/{diagram-VX7I27RA-DXp4fKk9.js → diagram-VX7I27RA-DRiCa3Vd.js} +1 -1
- package/out/web/assets/{diagram-Z3DM3KII-CzSicYiW.js → diagram-Z3DM3KII-Bt7zduQX.js} +1 -1
- package/out/web/assets/{ebnfDiagram-PWID7BFC-Dqj-zqPu.js → ebnfDiagram-PWID7BFC-DV9WpwdR.js} +1 -1
- package/out/web/assets/{erDiagram-RLTQ6QDP-DZwFZAuD.js → erDiagram-RLTQ6QDP-BJ_nwG2m.js} +1 -1
- package/out/web/assets/{eventmodeling-NTZA5JFV-C0O-Lvgp.js → eventmodeling-NTZA5JFV-BTBMrfVa.js} +1 -1
- package/out/web/assets/flowDiagram-HODETNUW-Cdlq3cJL.js +1 -0
- package/out/web/assets/{ganttDiagram-EL5Y4UJY-Da4ULXTl.js → ganttDiagram-EL5Y4UJY-DQLdsXrC.js} +1 -1
- package/out/web/assets/{gitGraph-4MIJSDKK-B9wNFZIP.js → gitGraph-4MIJSDKK-CL1OEOQ_.js} +1 -1
- package/out/web/assets/{gitGraphDiagram-WWUBYQGX-RjrhB0MP.js → gitGraphDiagram-WWUBYQGX-8cSi42H7.js} +1 -1
- package/out/web/assets/index-BocxnrDG.js +168 -0
- package/out/web/assets/index-yeh_r55a.css +1 -0
- package/out/web/assets/{info-A6RAGUB7-B3dfCpeY.js → info-A6RAGUB7-C1zsX5sc.js} +1 -1
- package/out/web/assets/{infoDiagram-27XIBGKW-QVWkLVx7.js → infoDiagram-27XIBGKW-DsRYtIyI.js} +1 -1
- package/out/web/assets/{ishikawaDiagram-5VMMS53U-CLFNIRI9.js → ishikawaDiagram-5VMMS53U-B2crwIXj.js} +1 -1
- package/out/web/assets/{journeyDiagram-3NMN7TZE-fgOQadYF.js → journeyDiagram-3NMN7TZE-BTH-GyVR.js} +1 -1
- package/out/web/assets/{kanban-definition-UXKFOSKX-G3Q_9g9O.js → kanban-definition-UXKFOSKX-BeRfCnuA.js} +1 -1
- package/out/web/assets/{mermaid-parser.core-v3Jm7nco.js → mermaid-parser.core-BJwgCBBc.js} +3 -3
- package/out/web/assets/{mermaid.core-DTEjLUA1.js → mermaid.core-CsDDodN8.js} +4 -4
- package/out/web/assets/{mindmap-definition-YA3MSWOX-C_D42_fF.js → mindmap-definition-YA3MSWOX-B42efOQ1.js} +1 -1
- package/out/web/assets/{modelManager-BPLycQrN.js → modelManager-B3ZFMh8v.js} +2 -2
- package/out/web/assets/{oauthManager-BUK7ic7q.js → oauthManager-Ch5Du2fF.js} +1 -1
- package/out/web/assets/{packet-AYTQ26CC-B-R-SHlF.js → packet-AYTQ26CC-B6xUyE6r.js} +1 -1
- package/out/web/assets/{pegDiagram-XKGWAZYB-Da2q_giz.js → pegDiagram-XKGWAZYB-1LabVycL.js} +1 -1
- package/out/web/assets/{pie-WAS4IAKB-BC8F0N7-.js → pie-WAS4IAKB-DJwo-nf_.js} +1 -1
- package/out/web/assets/{pieDiagram-E7YTZNPT-Iy9REJNC.js → pieDiagram-E7YTZNPT-icmAqzy4.js} +1 -1
- package/out/web/assets/{quadrantDiagram-AXDQQJYC-ztsiYw7h.js → quadrantDiagram-AXDQQJYC-CZ-wEx41.js} +1 -1
- package/out/web/assets/{radar-RG4KPBEZ-B_1P8Z_z.js → radar-RG4KPBEZ-D7d-Xriw.js} +1 -1
- package/out/web/assets/{railroad-74A4TZTK-DuTqczSo.js → railroad-74A4TZTK-viuhdYbs.js} +1 -1
- package/out/web/assets/{railroad-abnf-HS5TGJTU-Df29WLmp.js → railroad-abnf-HS5TGJTU-DNXiCNea.js} +1 -1
- package/out/web/assets/{railroad-ebnf-LZEXJU2U-ePFMo-qp.js → railroad-ebnf-LZEXJU2U-nkSu1-0C.js} +1 -1
- package/out/web/assets/{railroad-peg-WCYAUIDC-DYXLW4_E.js → railroad-peg-WCYAUIDC-BhbMeQzz.js} +1 -1
- package/out/web/assets/{railroadDiagram-O6MQD6OU-LStnZf2S.js → railroadDiagram-O6MQD6OU-CLpG1jUX.js} +1 -1
- package/out/web/assets/{requirementDiagram-BXWQKSXE-DmzonMH-.js → requirementDiagram-BXWQKSXE-kRDrvWrc.js} +1 -1
- package/out/web/assets/{sankeyDiagram-P5KCCOFB-B8vjmUU1.js → sankeyDiagram-P5KCCOFB-DxAwmq4x.js} +1 -1
- package/out/web/assets/{sequenceDiagram-WJ2MYXX4-CTnplOAX.js → sequenceDiagram-WJ2MYXX4-aLgY-6Wz.js} +1 -1
- package/out/web/assets/{stateDiagram-D77RDMKH-BFrIaLdI.js → stateDiagram-D77RDMKH-D5QWfOhp.js} +1 -1
- package/out/web/assets/stateDiagram-v2-MP3YSRHH-D6OiZoAP.js +1 -0
- package/out/web/assets/{swimlanes-42K2YHIH-BXGngUNU.js → swimlanes-42K2YHIH-CRs5UyA-.js} +1 -1
- package/out/web/assets/swimlanesDiagram-VR7AAH4N-UgEXIsV0.js +8 -0
- package/out/web/assets/syntaxHighlight-C-wAGT84.js +3 -0
- package/out/web/assets/{timeline-definition-24CTP7MA-CegH7n43.js → timeline-definition-24CTP7MA-Denqd9qb.js} +1 -1
- package/out/web/assets/{treeView-Q6P3EWNA-DTpJv2Tw.js → treeView-Q6P3EWNA-0my3Z3s4.js} +1 -1
- package/out/web/assets/{treemap-WGGIJYW6-i8M9iJU6.js → treemap-WGGIJYW6-B_EjkLYq.js} +1 -1
- package/out/web/assets/{vennDiagram-4TSXK5OY-Dpzo1S8U.js → vennDiagram-4TSXK5OY-DxVg3Ewr.js} +1 -1
- package/out/web/assets/{wardley-WFR3VGLG-BrNsgtfw.js → wardley-WFR3VGLG-CGD-Tj4p.js} +1 -1
- package/out/web/assets/{wardleyDiagram-VM6X3IG4-lQ92LFE1.js → wardleyDiagram-VM6X3IG4-CmfS39Xm.js} +1 -1
- package/out/web/assets/{xychartDiagram-S5SC5T6Z-BaOaEoBd.js → xychartDiagram-S5SC5T6Z-BVM9bKis.js} +1 -1
- package/out/web/index-web.html +2 -2
- package/out/web/index.html +2 -2
- package/package.json +2 -2
- package/shared-modules/CODEOWNERS +3 -3
- package/shared-modules/SDL2/SDL2_mixer.json +27 -0
- package/shared-modules/appstream/README.md +13 -0
- package/shared-modules/appstream/appstream-compose.json +111 -0
- package/shared-modules/dbus-glib/dbus-glib.json +2 -2
- package/shared-modules/libportal/libportal.json +23 -0
- package/shared-modules/linux-audio/fluidsynth2-static.json +2 -2
- package/shared-modules/linux-audio/fluidsynth2.json +2 -2
- package/shared-modules/linux-audio/libinstpatch.json +2 -2
- package/shared-modules/linux-audio/liblo-static.json +3 -0
- package/shared-modules/luajit/luajit.json +2 -2
- package/shared-modules/squashfs-tools/squashfs-tools.json +0 -3
- package/slash-commands.json +7 -2
- package/src/renderer/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
- package/src/renderer/shared/agentProgress.ts +51 -3
- package/src/renderer/shared/components/Settings/AutomationTab.tsx +2 -56
- package/src/renderer/shared/components/Settings/AvatarCropModal.tsx +15 -1
- package/src/renderer/shared/components/Settings/GeneralTab.tsx +25 -12
- package/src/renderer/shared/components/Settings/ThemeTab.test.tsx +45 -0
- package/src/renderer/shared/components/Settings/ThemeTab.tsx +106 -3
- package/src/renderer/shared/components/activity/AgentActivityDrawer.tsx +67 -17
- package/src/renderer/shared/components/activity/AgentActivityTable.tsx +376 -134
- package/src/renderer/shared/components/activity/AskUserActivityCard.test.tsx +122 -0
- package/src/renderer/shared/components/activity/AskUserActivityCard.tsx +70 -0
- package/src/renderer/shared/components/activity/McpToolResults.tsx +39 -2
- package/src/renderer/shared/components/activity/SubagentDagView.tsx +7 -7
- package/src/renderer/shared/components/activity/ViewedImages.tsx +41 -2
- package/src/renderer/shared/components/app/ChunkErrorBoundary.tsx +3 -3
- package/src/renderer/shared/components/app/CommandPalette.tsx +7 -7
- package/src/renderer/shared/components/app/DesktopTitlebar.tsx +2 -2
- package/src/renderer/shared/components/app/MintDashboard.tsx +27 -17
- package/src/renderer/shared/components/app/ModalErrorBoundary.tsx +3 -3
- package/src/renderer/shared/components/cards/CalculationCard.tsx +3 -3
- package/src/renderer/shared/components/cards/ImageGenCard.tsx +2 -2
- package/src/renderer/shared/components/cards/ImageSearchCard.tsx +2 -2
- package/src/renderer/shared/components/cards/MermaidCard.tsx +1 -1
- package/src/renderer/shared/components/cards/PlanCard.test.tsx +41 -0
- package/src/renderer/shared/components/cards/PlanCard.tsx +32 -0
- package/src/renderer/shared/components/cards/ReleaseNotesCard.test.tsx +29 -0
- package/src/renderer/shared/components/cards/ReleaseNotesCard.tsx +137 -0
- package/src/renderer/shared/components/cards/StockCard.tsx +7 -7
- package/src/renderer/shared/components/cards/ToolResultCards.tsx +11 -3
- package/src/renderer/shared/components/cards/UiMockupWidget.tsx +4 -4
- package/src/renderer/shared/components/cards/WeatherCard.tsx +5 -5
- package/src/renderer/shared/components/chat/ApprovalCard.test.tsx +11 -0
- package/src/renderer/shared/components/chat/ApprovalCard.tsx +21 -2
- package/src/renderer/shared/components/chat/ArtifactCards.test.tsx +69 -0
- package/src/renderer/shared/components/chat/ArtifactCards.tsx +238 -0
- package/src/renderer/shared/components/chat/AttachedDocumentCard.test.tsx +39 -0
- package/src/renderer/shared/components/chat/AttachedDocumentCard.tsx +220 -0
- package/src/renderer/shared/components/chat/ChatCodeBlock.test.tsx +33 -0
- package/src/renderer/shared/components/chat/ChatCodeBlock.tsx +15 -1
- package/src/renderer/shared/components/chat/ChatMessageItem.test.tsx +40 -2
- package/src/renderer/shared/components/chat/ChatMessageItem.tsx +180 -34
- package/src/renderer/shared/components/chat/ChatModeSelector.css +227 -0
- package/src/renderer/shared/components/chat/ChatModeSelector.test.tsx +45 -0
- package/src/renderer/shared/components/chat/ChatModeSelector.tsx +198 -0
- package/src/renderer/shared/components/chat/ChatPanel.test.tsx +22 -0
- package/src/renderer/shared/components/chat/ChatPanel.tsx +227 -53
- package/src/renderer/shared/components/chat/DiffReviewModal.tsx +6 -6
- package/src/renderer/shared/components/chat/GeminiLiveOverlay.test.tsx +142 -1
- package/src/renderer/shared/components/chat/GeminiLiveOverlay.tsx +45 -3
- package/src/renderer/shared/components/chat/ModelSelectorPopover.tsx +42 -14
- package/src/renderer/shared/components/chat/RewindModal.tsx +10 -10
- package/src/renderer/shared/components/chat/SlashSuggestions.test.tsx +14 -0
- package/src/renderer/shared/components/chat/SourcesBlock.test.tsx +53 -0
- package/src/renderer/shared/components/chat/SourcesBlock.tsx +236 -90
- package/src/renderer/shared/components/chat/TurnFileChanges.test.tsx +45 -1
- package/src/renderer/shared/components/chat/TurnFileChanges.tsx +202 -169
- package/src/renderer/shared/components/extensions/CliSessionsView.tsx +5 -4
- package/src/renderer/shared/components/extensions/McpRegistryPicker.tsx +3 -3
- package/src/renderer/shared/components/studio/LibraryPage.tsx +48 -5
- package/src/renderer/shared/components/workspace/ArtifactPreviewPanel.tsx +125 -13
- package/src/renderer/shared/components/workspace/CodeReviewPage.test.tsx +50 -0
- package/src/renderer/shared/components/workspace/CodeReviewPage.tsx +77 -16
- package/src/renderer/shared/components/workspace/GitBranchSelector.tsx +78 -22
- package/src/renderer/shared/components/workspace/ToolSurfacePage.test.tsx +13 -0
- package/src/renderer/shared/components/workspace/ToolSurfacePage.tsx +48 -28
- package/src/renderer/shared/components/workspace/WorkspacePdfPreview.tsx +266 -47
- package/src/renderer/shared/components/workspace/WorkspacePreviewActions.test.tsx +18 -6
- package/src/renderer/shared/components/workspace/background-terminals.css +11 -11
- package/src/renderer/shared/constants/config.ts +1 -5
- package/src/renderer/shared/constants/models.test.ts +51 -0
- package/src/renderer/shared/constants/models.ts +139 -32
- package/src/renderer/shared/conversation/lifecycle.test.ts +91 -3
- package/src/renderer/shared/conversation/lifecycle.ts +104 -5
- package/src/renderer/shared/conversation/progressiveStream.test.ts +83 -0
- package/src/renderer/shared/conversation/progressiveStream.ts +219 -0
- package/src/renderer/shared/css/agent-observability.css +133 -0
- package/src/renderer/shared/css/chat-ui-cards.css +13 -13
- package/src/renderer/shared/css/code-review.css +63 -34
- package/src/renderer/shared/css/code-sessions.css +47 -18
- package/src/renderer/shared/css/collapsed-paste.css +1 -1
- package/src/renderer/shared/css/error-notice.css +1 -1
- package/src/renderer/shared/css/file-changes.css +165 -80
- package/src/renderer/shared/css/library.css +105 -10
- package/src/renderer/shared/css/management-views.css +1 -1
- package/src/renderer/shared/css/mcp-results.css +5 -5
- package/src/renderer/shared/css/model-selector.css +18 -18
- package/src/renderer/shared/css/mods.css +7 -7
- package/src/renderer/shared/css/notification-notice.css +2 -2
- package/src/renderer/shared/css/queued-messages.css +5 -5
- package/src/renderer/shared/css/settings/general.css +18 -13
- package/src/renderer/shared/css/settings/profile.css +5 -5
- package/src/renderer/shared/css/settings/theme.css +5 -5
- package/src/renderer/shared/css/slash-choice.css +2 -2
- package/src/renderer/shared/css/slash-suggestions.css +3 -3
- package/src/renderer/shared/css/sources-block.css +41 -2
- package/src/renderer/shared/css/tools-panel.css +2 -2
- package/src/renderer/shared/css/ui-tailwind.css +8 -0
- package/src/renderer/shared/css/veo-studio.css +2 -2
- package/src/renderer/shared/css/viewed-images.css +7 -7
- package/src/renderer/shared/platform.ts +2 -1
- package/src/renderer/shared/theme/themeManager.test.ts +17 -0
- package/src/renderer/shared/theme/themeManager.ts +21 -4
- package/src/renderer/shared/theme/themes.ts +54 -0
- package/src/renderer/shared/theme/tokens.css +6 -4
- package/src/renderer/shared/types.ts +1 -1
- package/src/renderer/shared/utils/agentActivity.test.ts +468 -2
- package/src/renderer/shared/utils/agentActivity.ts +602 -35
- package/src/renderer/shared/utils/artifactBrowser.test.ts +37 -32
- package/src/renderer/shared/utils/artifactBrowser.ts +17 -19
- package/src/renderer/shared/utils/attachedDocument.test.ts +73 -0
- package/src/renderer/shared/utils/attachedDocument.ts +49 -0
- package/src/renderer/shared/utils/fileIcons.test.ts +59 -0
- package/src/renderer/shared/utils/fileIcons.ts +149 -16
- package/src/renderer/shared/utils/markdown.tsx +72 -19
- package/src/renderer/shared/utils/markdown.webImages.test.tsx +16 -0
- package/src/renderer/shared/utils/mcpResults.test.tsx +29 -0
- package/src/renderer/shared/utils/slashCommandProcessor.ts +4 -1
- package/src/renderer/shared/utils/syntaxHighlight.test.tsx +11 -1
- package/src/renderer/shared/utils/syntaxHighlight.tsx +51 -3
- package/src/renderer/shared/utils/useGeminiLiveVoice.ts +324 -51
- package/src/renderer/shared/utils/workspaceDrag.test.ts +153 -0
- package/src/renderer/shared/utils/workspaceDrag.ts +142 -0
- package/src/renderer/shared/utils/workspaceMedia.ts +10 -2
- package/src/renderer/src/App.tsx +14 -8
- package/src/renderer/src/agentProgress.ts +1 -0
- package/src/renderer/src/components/ScreenPicker.css +1 -1
- package/src/renderer/src/components/WorkspacePanel.tsx +6 -5
- package/src/renderer/src/css/app-shell.css +4 -4
- package/src/renderer/src/css/chat.css +1261 -241
- package/src/renderer/src/css/desktop-tools.css +11 -11
- package/src/renderer/src/css/sidebar-workspace.css +2 -2
- package/src/renderer/src/css/tool-surfaces.css +12 -12
- package/src/renderer/src/index.css +38 -20
- package/src/renderer/src/tauri.ts +22 -2
- package/src/renderer/src-web/App.tsx +14 -0
- package/src/renderer/src-web/agentProgress.ts +1 -0
- package/src/renderer/src-web/css/app-shell.css +4 -4
- package/src/renderer/src-web/css/chat.css +1278 -190
- package/src/renderer/src-web/css/mobile.css +29 -13
- package/src/renderer/src-web/css/settings/mobile.css +2 -2
- package/src/renderer/src-web/css/sidebar-workspace.css +1 -1
- package/src/renderer/src-web/index.css +38 -20
- package/src/renderer/src-web/tauri.ts +22 -2
- package/src/renderer/tests/browserArtifacts.browser.tsx +1 -1
- package/src/renderer/tests/library.browser.tsx +3 -0
- package/src/renderer/tests/liveVoice.browser.html +1 -0
- package/src/renderer/tests/workspaceDrop.browser.tsx +1 -1
- package/src-tauri/src/app/lifecycle.rs +1 -14
- package/src-tauri/src/background/headless.rs +14 -8
- package/src-tauri/src/commands/conversation.rs +38 -0
- package/src-tauri/src/native/mod.rs +0 -1
- package/src-tauri/src/native/system.rs +4 -47
- package/crates/mint-cli/src/interactive/chat_tui.rs +0 -8855
- package/crates/mint-core/src/agent/chat.rs +0 -4394
- package/crates/mint-core/src/browser/lifecycle.rs +0 -291
- package/crates/mint-core/src/browser/logging.rs +0 -20
- package/crates/mint-core/src/orchestration/tools/browser.rs +0 -31
- package/out/web/assets/ArtifactPreviewPanel-S0dPfYFx.js +0 -2
- package/out/web/assets/CalculationCard-CRjP3E1j.js +0 -1
- package/out/web/assets/CliSessionsView-C3Br2v5Y.css +0 -1
- package/out/web/assets/CodeReviewPage-CUJceQme.css +0 -1
- package/out/web/assets/CodeReviewPage-VCUgPla_.js +0 -2
- package/out/web/assets/ImageGenCard-BCXxkVJX.js +0 -1
- package/out/web/assets/ImageSearchCard-N3yQOr8Z.js +0 -1
- package/out/web/assets/LibraryPage-DAxUTAg7.css +0 -1
- package/out/web/assets/LibraryPage-WlviRdR8.js +0 -2
- package/out/web/assets/LinkedFoldersView-CKRgroWK.js +0 -1
- package/out/web/assets/McpServersView-D3wHnuHg.js +0 -1
- package/out/web/assets/MermaidCard-NqrHdyJW.js +0 -2
- package/out/web/assets/MintDashboard-B2DJsDDO.css +0 -1
- package/out/web/assets/MintDashboard-COw_xol7.js +0 -63
- package/out/web/assets/RewindModal-DempuDod.js +0 -1
- package/out/web/assets/SettingsWindow-2YP3yj7s.js +0 -4
- package/out/web/assets/SettingsWindow-Dz8LQVgD.css +0 -1
- package/out/web/assets/StockCard-BDMCe7mx.js +0 -1
- package/out/web/assets/ToolSurfacePage-B0J_q0Jl.js +0 -38
- package/out/web/assets/ToolSurfacePage-CRIQ1owD.css +0 -1
- package/out/web/assets/UiMockupWidget-DD73QWg1.js +0 -1
- package/out/web/assets/WeatherCard-CPucIfq8.js +0 -1
- package/out/web/assets/WorkspacePdfPreview-Dx_lkjNu.js +0 -2
- package/out/web/assets/classDiagram-ZZMXUADV-BgJ5WtSp.js +0 -1
- package/out/web/assets/classDiagram-v2-VYDZK3BY-BgJ5WtSp.js +0 -1
- package/out/web/assets/config-CvIO5hkn.js +0 -2
- package/out/web/assets/flowDiagram-HODETNUW-uqCHJond.js +0 -1
- package/out/web/assets/index-BmpulIkg.js +0 -168
- package/out/web/assets/index-CkvBwhX_.css +0 -1
- package/out/web/assets/stateDiagram-v2-MP3YSRHH-uf3kdNW4.js +0 -1
- package/out/web/assets/swimlanesDiagram-VR7AAH4N-Y8q5bQce.js +0 -8
- package/shared-modules/libsecret/libsecret.json +0 -23
- package/shared-modules/libusb/libusb.json +0 -27
- package/shared-modules/lzo/lzo.json +0 -27
- package/src/renderer/src/components/BrowserShell.tsx +0 -108
- package/src/renderer/src/components/BrowserSuggestionsPopup.tsx +0 -91
- package/src/renderer/src/components/browser-shell.css +0 -185
- 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
|
|
65
|
-
if
|
|
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[
|
|
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
|
-
"
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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,
|
|
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
|
-
|
|
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[
|
|
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
|
-
|
|
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() >
|
|
149
|
-
let end = (
|
|
150
|
-
&messages[
|
|
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
|
|
197
|
-
compacted.
|
|
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() >
|
|
212
|
-
compacted.extend_from_slice(&messages[
|
|
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
|
-
|
|
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)
|
|
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
|
}
|