agim-cli 1.2.144 → 1.2.147
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/CHANGELOG.md +101 -0
- package/dist/cli-ui/setup-llm.d.ts.map +1 -1
- package/dist/cli-ui/setup-llm.js +3 -1
- package/dist/cli-ui/setup-llm.js.map +1 -1
- package/dist/core/circuit-breaker.d.ts +28 -0
- package/dist/core/circuit-breaker.d.ts.map +1 -1
- package/dist/core/circuit-breaker.js +45 -0
- package/dist/core/circuit-breaker.js.map +1 -1
- package/dist/core/intent.d.ts.map +1 -1
- package/dist/core/intent.js +3 -1
- package/dist/core/intent.js.map +1 -1
- package/dist/core/llm/agent-loop.d.ts +9 -1
- package/dist/core/llm/agent-loop.d.ts.map +1 -1
- package/dist/core/llm/agent-loop.js +80 -1
- package/dist/core/llm/agent-loop.js.map +1 -1
- package/dist/core/llm/anthropic-provider.d.ts.map +1 -1
- package/dist/core/llm/anthropic-provider.js +18 -4
- package/dist/core/llm/anthropic-provider.js.map +1 -1
- package/dist/core/llm/hallucination-detector.d.ts +33 -0
- package/dist/core/llm/hallucination-detector.d.ts.map +1 -0
- package/dist/core/llm/hallucination-detector.js +103 -0
- package/dist/core/llm/hallucination-detector.js.map +1 -0
- package/dist/core/llm/imhub-dispatcher.d.ts.map +1 -1
- package/dist/core/llm/imhub-dispatcher.js +7 -0
- package/dist/core/llm/imhub-dispatcher.js.map +1 -1
- package/dist/core/llm/provider-base.d.ts +9 -0
- package/dist/core/llm/provider-base.d.ts.map +1 -1
- package/dist/core/llm/provider-base.js.map +1 -1
- package/dist/core/memory-distill.d.ts.map +1 -1
- package/dist/core/memory-distill.js +18 -3
- package/dist/core/memory-distill.js.map +1 -1
- package/dist/core/memory.d.ts +14 -0
- package/dist/core/memory.d.ts.map +1 -1
- package/dist/core/memory.js +39 -0
- package/dist/core/memory.js.map +1 -1
- package/dist/core/message-sink.d.ts +6 -0
- package/dist/core/message-sink.d.ts.map +1 -1
- package/dist/core/message-sink.js +18 -3
- package/dist/core/message-sink.js.map +1 -1
- package/dist/core/outbox.d.ts +30 -2
- package/dist/core/outbox.d.ts.map +1 -1
- package/dist/core/outbox.js +102 -10
- package/dist/core/outbox.js.map +1 -1
- package/dist/core/reminders.d.ts.map +1 -1
- package/dist/core/reminders.js +11 -1
- package/dist/core/reminders.js.map +1 -1
- package/dist/core/router.d.ts.map +1 -1
- package/dist/core/router.js +16 -4
- package/dist/core/router.js.map +1 -1
- package/dist/core/schedule.d.ts +18 -0
- package/dist/core/schedule.d.ts.map +1 -1
- package/dist/core/schedule.js +80 -17
- package/dist/core/schedule.js.map +1 -1
- package/dist/core/sensitive-paths.d.ts.map +1 -1
- package/dist/core/sensitive-paths.js +53 -9
- package/dist/core/sensitive-paths.js.map +1 -1
- package/dist/core/types.d.ts +6 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/plugins/agents/native/index.d.ts +47 -8
- package/dist/plugins/agents/native/index.d.ts.map +1 -1
- package/dist/plugins/agents/native/index.js +253 -102
- package/dist/plugins/agents/native/index.js.map +1 -1
- package/dist/plugins/agents/native/tool-registry.d.ts +33 -0
- package/dist/plugins/agents/native/tool-registry.d.ts.map +1 -0
- package/dist/plugins/agents/native/tool-registry.js +82 -0
- package/dist/plugins/agents/native/tool-registry.js.map +1 -0
- package/dist/plugins/messengers/dingtalk/dingtalk-client.d.ts.map +1 -1
- package/dist/plugins/messengers/dingtalk/dingtalk-client.js +11 -11
- package/dist/plugins/messengers/dingtalk/dingtalk-client.js.map +1 -1
- package/dist/plugins/messengers/feishu/feishu-adapter.d.ts.map +1 -1
- package/dist/plugins/messengers/feishu/feishu-adapter.js +9 -5
- package/dist/plugins/messengers/feishu/feishu-adapter.js.map +1 -1
- package/dist/plugins/messengers/wechat/ilink-adapter.d.ts.map +1 -1
- package/dist/plugins/messengers/wechat/ilink-adapter.js +11 -1
- package/dist/plugins/messengers/wechat/ilink-adapter.js.map +1 -1
- package/dist/web/public/assets/{a2a-DczMMkbl.js → a2a-Cll3P4QN.js} +2 -2
- package/dist/web/public/assets/{a2a-DczMMkbl.js.map → a2a-Cll3P4QN.js.map} +1 -1
- package/dist/web/public/assets/{activity-cbLHkzca.js → activity-B7T7YFlD.js} +2 -2
- package/dist/web/public/assets/{activity-cbLHkzca.js.map → activity-B7T7YFlD.js.map} +1 -1
- package/dist/web/public/assets/{admins-C-YsGMj7.js → admins-CN7P018S.js} +2 -2
- package/dist/web/public/assets/{admins-C-YsGMj7.js.map → admins-CN7P018S.js.map} +1 -1
- package/dist/web/public/assets/{agents-BWfov_1-.js → agents-Bqgq7GBF.js} +2 -2
- package/dist/web/public/assets/{agents-BWfov_1-.js.map → agents-Bqgq7GBF.js.map} +1 -1
- package/dist/web/public/assets/{approvals-HSssmXKS.js → approvals-C8IUJQ_A.js} +2 -2
- package/dist/web/public/assets/{approvals-HSssmXKS.js.map → approvals-C8IUJQ_A.js.map} +1 -1
- package/dist/web/public/assets/{arrow-down-BXvC8Al2.js → arrow-down-SLWKqtDc.js} +2 -2
- package/dist/web/public/assets/{arrow-down-BXvC8Al2.js.map → arrow-down-SLWKqtDc.js.map} +1 -1
- package/dist/web/public/assets/{arrow-up-63xELY5Q.js → arrow-up-BOADc9ce.js} +2 -2
- package/dist/web/public/assets/{arrow-up-63xELY5Q.js.map → arrow-up-BOADc9ce.js.map} +1 -1
- package/dist/web/public/assets/{asks-COLEFOvK.js → asks-C-j-DypC.js} +2 -2
- package/dist/web/public/assets/{asks-COLEFOvK.js.map → asks-C-j-DypC.js.map} +1 -1
- package/dist/web/public/assets/{audit-D4ZEiZub.js → audit-DQb-RuXh.js} +2 -2
- package/dist/web/public/assets/{audit-D4ZEiZub.js.map → audit-DQb-RuXh.js.map} +1 -1
- package/dist/web/public/assets/{bell-Cg2Bvv06.js → bell-CV88-ul6.js} +2 -2
- package/dist/web/public/assets/{bell-Cg2Bvv06.js.map → bell-CV88-ul6.js.map} +1 -1
- package/dist/web/public/assets/{bgjobs-CEjCzwtd.js → bgjobs-CDrK0d-W.js} +2 -2
- package/dist/web/public/assets/{bgjobs-CEjCzwtd.js.map → bgjobs-CDrK0d-W.js.map} +1 -1
- package/dist/web/public/assets/{brain-euvl6F6C.js → brain-B7HtSOQU.js} +2 -2
- package/dist/web/public/assets/{brain-euvl6F6C.js.map → brain-B7HtSOQU.js.map} +1 -1
- package/dist/web/public/assets/{briefcase-DPWLbCnA.js → briefcase-mdzuIa__.js} +2 -2
- package/dist/web/public/assets/{briefcase-DPWLbCnA.js.map → briefcase-mdzuIa__.js.map} +1 -1
- package/dist/web/public/assets/{browser-ponyfill-BUutOaRz.js → browser-ponyfill-DBWdeCTC.js} +2 -2
- package/dist/web/public/assets/{browser-ponyfill-BUutOaRz.js.map → browser-ponyfill-DBWdeCTC.js.map} +1 -1
- package/dist/web/public/assets/{chat-Dz9kfaxH.js → chat-CSjtY2rN.js} +3 -3
- package/dist/web/public/assets/{chat-Dz9kfaxH.js.map → chat-CSjtY2rN.js.map} +1 -1
- package/dist/web/public/assets/{chevron-left-BeIh5thq.js → chevron-left-uSfPn636.js} +2 -2
- package/dist/web/public/assets/{chevron-left-BeIh5thq.js.map → chevron-left-uSfPn636.js.map} +1 -1
- package/dist/web/public/assets/{chevron-right-uP_l9MMb.js → chevron-right-CtelqacW.js} +2 -2
- package/dist/web/public/assets/{chevron-right-uP_l9MMb.js.map → chevron-right-CtelqacW.js.map} +1 -1
- package/dist/web/public/assets/{circle-check-CewnjFgv.js → circle-check-8dbL-u7O.js} +2 -2
- package/dist/web/public/assets/{circle-check-CewnjFgv.js.map → circle-check-8dbL-u7O.js.map} +1 -1
- package/dist/web/public/assets/{circle-check-big-C2RTc48c.js → circle-check-big-D8-svk9a.js} +2 -2
- package/dist/web/public/assets/{circle-check-big-C2RTc48c.js.map → circle-check-big-D8-svk9a.js.map} +1 -1
- package/dist/web/public/assets/{circle-x-Ccg1HyV-.js → circle-x-rUxzIz5P.js} +2 -2
- package/dist/web/public/assets/{circle-x-Ccg1HyV-.js.map → circle-x-rUxzIz5P.js.map} +1 -1
- package/dist/web/public/assets/{clock-qxbYSynv.js → clock-CG5dlBGB.js} +2 -2
- package/dist/web/public/assets/{clock-qxbYSynv.js.map → clock-CG5dlBGB.js.map} +1 -1
- package/dist/web/public/assets/{confirm-dialog-DmJq4Td9.js → confirm-dialog-DlUsSur3.js} +2 -2
- package/dist/web/public/assets/{confirm-dialog-DmJq4Td9.js.map → confirm-dialog-DlUsSur3.js.map} +1 -1
- package/dist/web/public/assets/{copy-DxSHRdbc.js → copy-DnC76wFT.js} +2 -2
- package/dist/web/public/assets/{copy-DxSHRdbc.js.map → copy-DnC76wFT.js.map} +1 -1
- package/dist/web/public/assets/{data-table-S7rIjwdO.js → data-table-DswkWUfG.js} +2 -2
- package/dist/web/public/assets/{data-table-S7rIjwdO.js.map → data-table-DswkWUfG.js.map} +1 -1
- package/dist/web/public/assets/dialog-Ceo4YuXy.js +6 -0
- package/dist/web/public/assets/dialog-Ceo4YuXy.js.map +1 -0
- package/dist/web/public/assets/{download-OhsGtnO-.js → download-DF-46tS4.js} +2 -2
- package/dist/web/public/assets/{download-OhsGtnO-.js.map → download-DF-46tS4.js.map} +1 -1
- package/dist/web/public/assets/{email-C1-HxWLF.js → email-CZee26-_.js} +3 -3
- package/dist/web/public/assets/{email-C1-HxWLF.js.map → email-CZee26-_.js.map} +1 -1
- package/dist/web/public/assets/{empty-state-C-qjOHyu.js → empty-state-D9Hi0Atm.js} +2 -2
- package/dist/web/public/assets/{empty-state-C-qjOHyu.js.map → empty-state-D9Hi0Atm.js.map} +1 -1
- package/dist/web/public/assets/{external-link-DRVp9-lb.js → external-link-D64iZa9P.js} +2 -2
- package/dist/web/public/assets/{external-link-DRVp9-lb.js.map → external-link-D64iZa9P.js.map} +1 -1
- package/dist/web/public/assets/{eye-CFhg5BTa.js → eye-sY6WZb7D.js} +2 -2
- package/dist/web/public/assets/{eye-CFhg5BTa.js.map → eye-sY6WZb7D.js.map} +1 -1
- package/dist/web/public/assets/{facts-CGaLWhzi.js → facts-B7bGGwvi.js} +2 -2
- package/dist/web/public/assets/{facts-CGaLWhzi.js.map → facts-B7bGGwvi.js.map} +1 -1
- package/dist/web/public/assets/{goals-C-dJANmn.js → goals-BfQbsvZv.js} +2 -2
- package/dist/web/public/assets/{goals-C-dJANmn.js.map → goals-BfQbsvZv.js.map} +1 -1
- package/dist/web/public/assets/{health-CWcti5h3.js → health-Ba_mY0Ts.js} +2 -2
- package/dist/web/public/assets/{health-CWcti5h3.js.map → health-Ba_mY0Ts.js.map} +1 -1
- package/dist/web/public/assets/{heart-pulse-DmGhKR2W.js → heart-pulse-BjikOVwU.js} +2 -2
- package/dist/web/public/assets/{heart-pulse-DmGhKR2W.js.map → heart-pulse-BjikOVwU.js.map} +1 -1
- package/dist/web/public/assets/{heartbeat-kLoGBNCo.js → heartbeat-BM8LlPes.js} +2 -2
- package/dist/web/public/assets/{heartbeat-kLoGBNCo.js.map → heartbeat-BM8LlPes.js.map} +1 -1
- package/dist/web/public/assets/{hot-BITDoax1.js → hot-BtuLL6n8.js} +2 -2
- package/dist/web/public/assets/{hot-BITDoax1.js.map → hot-BtuLL6n8.js.map} +1 -1
- package/dist/web/public/assets/index-DEWFfW_Z.js +199 -0
- package/dist/web/public/assets/index-DEWFfW_Z.js.map +1 -0
- package/dist/web/public/assets/{installed-Co9WrtQ7.js → installed-Xr8p31ij.js} +2 -2
- package/dist/web/public/assets/{installed-Co9WrtQ7.js.map → installed-Xr8p31ij.js.map} +1 -1
- package/dist/web/public/assets/{jobs-hdHhBEvi.js → jobs-Ddy81Udm.js} +2 -2
- package/dist/web/public/assets/{jobs-hdHhBEvi.js.map → jobs-Ddy81Udm.js.map} +1 -1
- package/dist/web/public/assets/{layout-CQtbOBag.js → layout-BL74fT-L.js} +2 -2
- package/dist/web/public/assets/{layout-CQtbOBag.js.map → layout-BL74fT-L.js.map} +1 -1
- package/dist/web/public/assets/{layout-bDMXIKIR.js → layout-Bn2qUxcK.js} +2 -2
- package/dist/web/public/assets/{layout-bDMXIKIR.js.map → layout-Bn2qUxcK.js.map} +1 -1
- package/dist/web/public/assets/{layout-BMXC1Uh1.js → layout-Bp4SAA8_.js} +2 -2
- package/dist/web/public/assets/{layout-BMXC1Uh1.js.map → layout-Bp4SAA8_.js.map} +1 -1
- package/dist/web/public/assets/{layout-CysVsySh.js → layout-CZ9pGnW8.js} +2 -2
- package/dist/web/public/assets/{layout-CysVsySh.js.map → layout-CZ9pGnW8.js.map} +1 -1
- package/dist/web/public/assets/{layout-CyBGneZ9.js → layout-pasFRkKV.js} +2 -2
- package/dist/web/public/assets/{layout-CyBGneZ9.js.map → layout-pasFRkKV.js.map} +1 -1
- package/dist/web/public/assets/llm-yp7b5xxL.js +7 -0
- package/dist/web/public/assets/llm-yp7b5xxL.js.map +1 -0
- package/dist/web/public/assets/{loader-circle-9VUMGitw.js → loader-circle-Bbw4pEyE.js} +2 -2
- package/dist/web/public/assets/{loader-circle-9VUMGitw.js.map → loader-circle-Bbw4pEyE.js.map} +1 -1
- package/dist/web/public/assets/{map-pin-BXYvvHry.js → map-pin-DIXHUQgM.js} +2 -2
- package/dist/web/public/assets/{map-pin-BXYvvHry.js.map → map-pin-DIXHUQgM.js.map} +1 -1
- package/dist/web/public/assets/{mcp-BgLdlwSn.js → mcp-DyaljIM_.js} +2 -2
- package/dist/web/public/assets/{mcp-BgLdlwSn.js.map → mcp-DyaljIM_.js.map} +1 -1
- package/dist/web/public/assets/memos-Dkoc157i.js +12 -0
- package/dist/web/public/assets/memos-Dkoc157i.js.map +1 -0
- package/dist/web/public/assets/{messengers-7Phqea62.js → messengers-CcyGDeUI.js} +2 -2
- package/dist/web/public/assets/{messengers-7Phqea62.js.map → messengers-CcyGDeUI.js.map} +1 -1
- package/dist/web/public/assets/{mobile-CV5b6D2W.js → mobile-DqzIv4Xb.js} +2 -2
- package/dist/web/public/assets/{mobile-CV5b6D2W.js.map → mobile-DqzIv4Xb.js.map} +1 -1
- package/dist/web/public/assets/{native-agent-QvIa6LjE.js → native-agent-BQ7WaRGK.js} +2 -2
- package/dist/web/public/assets/{native-agent-QvIa6LjE.js.map → native-agent-BQ7WaRGK.js.map} +1 -1
- package/dist/web/public/assets/{network-BXhEjGhE.js → network-B_yUFAqC.js} +2 -2
- package/dist/web/public/assets/{network-BXhEjGhE.js.map → network-B_yUFAqC.js.map} +1 -1
- package/dist/web/public/assets/{outbox-DHQL7TQb.js → outbox-l8aVOZqO.js} +2 -2
- package/dist/web/public/assets/{outbox-DHQL7TQb.js.map → outbox-l8aVOZqO.js.map} +1 -1
- package/dist/web/public/assets/{pagination-VKuPb1Ot.js → pagination-BAKRGKa9.js} +2 -2
- package/dist/web/public/assets/{pagination-VKuPb1Ot.js.map → pagination-BAKRGKa9.js.map} +1 -1
- package/dist/web/public/assets/{persona-CWug2GLR.js → persona-D3VL9Rg1.js} +2 -2
- package/dist/web/public/assets/{persona-CWug2GLR.js.map → persona-D3VL9Rg1.js.map} +1 -1
- package/dist/web/public/assets/{plans-CZoEs5SY.js → plans-BBB5e9my.js} +2 -2
- package/dist/web/public/assets/{plans-CZoEs5SY.js.map → plans-BBB5e9my.js.map} +1 -1
- package/dist/web/public/assets/{play-CfSn5Vdl.js → play-7-Wd369f.js} +2 -2
- package/dist/web/public/assets/{play-CfSn5Vdl.js.map → play-7-Wd369f.js.map} +1 -1
- package/dist/web/public/assets/{plus-Z8l4CiqJ.js → plus-B0sfZy-j.js} +2 -2
- package/dist/web/public/assets/{plus-Z8l4CiqJ.js.map → plus-B0sfZy-j.js.map} +1 -1
- package/dist/web/public/assets/{policy-CutDSEPW.js → policy-BM1WRXH0.js} +2 -2
- package/dist/web/public/assets/{policy-CutDSEPW.js.map → policy-BM1WRXH0.js.map} +1 -1
- package/dist/web/public/assets/{qr-code-DgU5aiM6.js → qr-code-DcKs5fi3.js} +2 -2
- package/dist/web/public/assets/{qr-code-DgU5aiM6.js.map → qr-code-DcKs5fi3.js.map} +1 -1
- package/dist/web/public/assets/{react-Cb2sDjhD.js → react-DlP5eolq.js} +2 -2
- package/dist/web/public/assets/{react-Cb2sDjhD.js.map → react-DlP5eolq.js.map} +1 -1
- package/dist/web/public/assets/{refresh-ccw-D2CWiyU_.js → refresh-ccw-uNKeBeRl.js} +2 -2
- package/dist/web/public/assets/{refresh-ccw-D2CWiyU_.js.map → refresh-ccw-uNKeBeRl.js.map} +1 -1
- package/dist/web/public/assets/{reminders-Cb6Izedg.js → reminders-DHM8K0_O.js} +2 -2
- package/dist/web/public/assets/{reminders-Cb6Izedg.js.map → reminders-DHM8K0_O.js.map} +1 -1
- package/dist/web/public/assets/{save-DB0BDYTs.js → save-qwJa5_SA.js} +2 -2
- package/dist/web/public/assets/{save-DB0BDYTs.js.map → save-qwJa5_SA.js.map} +1 -1
- package/dist/web/public/assets/{schedules-8mSjE14D.js → schedules-Bcd0wbT4.js} +2 -2
- package/dist/web/public/assets/{schedules-8mSjE14D.js.map → schedules-Bcd0wbT4.js.map} +1 -1
- package/dist/web/public/assets/{search-Con69NhG.js → search-BUlzNWrj.js} +2 -2
- package/dist/web/public/assets/{search-Con69NhG.js.map → search-BUlzNWrj.js.map} +1 -1
- package/dist/web/public/assets/{search-B4fHilZ0.js → search-i1tP2maJ.js} +2 -2
- package/dist/web/public/assets/{search-B4fHilZ0.js.map → search-i1tP2maJ.js.map} +1 -1
- package/dist/web/public/assets/{security-BTe3zUg8.js → security-DgJyTT4g.js} +2 -2
- package/dist/web/public/assets/{security-BTe3zUg8.js.map → security-DgJyTT4g.js.map} +1 -1
- package/dist/web/public/assets/{service-C7SqcwfL.js → service-A0Hzear0.js} +2 -2
- package/dist/web/public/assets/{service-C7SqcwfL.js.map → service-A0Hzear0.js.map} +1 -1
- package/dist/web/public/assets/{shield-alert-CKFVsGgI.js → shield-alert-DrnN6fz_.js} +2 -2
- package/dist/web/public/assets/{shield-alert-CKFVsGgI.js.map → shield-alert-DrnN6fz_.js.map} +1 -1
- package/dist/web/public/assets/{status-badge-BSkpyN4D.js → status-badge-Ryzf96Pl.js} +2 -2
- package/dist/web/public/assets/{status-badge-BSkpyN4D.js.map → status-badge-Ryzf96Pl.js.map} +1 -1
- package/dist/web/public/assets/{subtasks-Bel-I1Sk.js → subtasks-Bzh3o3EF.js} +2 -2
- package/dist/web/public/assets/{subtasks-Bel-I1Sk.js.map → subtasks-Bzh3o3EF.js.map} +1 -1
- package/dist/web/public/assets/{table-CPn1MRcy.js → table-BbAOSyc8.js} +2 -2
- package/dist/web/public/assets/{table-CPn1MRcy.js.map → table-BbAOSyc8.js.map} +1 -1
- package/dist/web/public/assets/{topn-Ba3RjcK1.js → topn-DkhYw-Gp.js} +2 -2
- package/dist/web/public/assets/{topn-Ba3RjcK1.js.map → topn-DkhYw-Gp.js.map} +1 -1
- package/dist/web/public/assets/{trash-2-Dfov8aHD.js → trash-2-CA0cLpnU.js} +2 -2
- package/dist/web/public/assets/{trash-2-Dfov8aHD.js.map → trash-2-CA0cLpnU.js.map} +1 -1
- package/dist/web/public/assets/{use-background-tasks-BQrEeUwY.js → use-background-tasks-B64YjlA8.js} +2 -2
- package/dist/web/public/assets/{use-background-tasks-BQrEeUwY.js.map → use-background-tasks-B64YjlA8.js.map} +1 -1
- package/dist/web/public/assets/{use-event-stream-DgGpGKop.js → use-event-stream-I1lMFEfh.js} +2 -2
- package/dist/web/public/assets/{use-event-stream-DgGpGKop.js.map → use-event-stream-I1lMFEfh.js.map} +1 -1
- package/dist/web/public/assets/{use-llm-admin-DYekqogG.js → use-llm-admin-DY2axI4D.js} +2 -2
- package/dist/web/public/assets/{use-llm-admin-DYekqogG.js.map → use-llm-admin-DY2axI4D.js.map} +1 -1
- package/dist/web/public/assets/{use-memory-DbJ4pP2Z.js → use-memory-BYEjVWbU.js} +2 -2
- package/dist/web/public/assets/{use-memory-DbJ4pP2Z.js.map → use-memory-BYEjVWbU.js.map} +1 -1
- package/dist/web/public/assets/{use-observability-C2M6WZ9W.js → use-observability-Coj02yDo.js} +2 -2
- package/dist/web/public/assets/{use-observability-C2M6WZ9W.js.map → use-observability-Coj02yDo.js.map} +1 -1
- package/dist/web/public/assets/{use-settings-DMdaoWsB.js → use-settings-i1MhlkyC.js} +2 -2
- package/dist/web/public/assets/{use-settings-DMdaoWsB.js.map → use-settings-i1MhlkyC.js.map} +1 -1
- package/dist/web/public/assets/{use-workspace-BHG7h3jQ.js → use-workspace-DgEM35PY.js} +2 -2
- package/dist/web/public/assets/{use-workspace-BHG7h3jQ.js.map → use-workspace-DgEM35PY.js.map} +1 -1
- package/dist/web/public/assets/{useQuery-PdiC7-sY.js → useQuery-CY2iazjN.js} +2 -2
- package/dist/web/public/assets/{useQuery-PdiC7-sY.js.map → useQuery-CY2iazjN.js.map} +1 -1
- package/dist/web/public/assets/{vector-DnZM3OXU.js → vector-Ic76u2hY.js} +2 -2
- package/dist/web/public/assets/{vector-DnZM3OXU.js.map → vector-Ic76u2hY.js.map} +1 -1
- package/dist/web/public/assets/{viewer-Dz6k0YKp.js → viewer-BXbUN1Rl.js} +2 -2
- package/dist/web/public/assets/{viewer-Dz6k0YKp.js.map → viewer-BXbUN1Rl.js.map} +1 -1
- package/dist/web/public/assets/{workspace-BnXrWS3j.js → workspace-CUg0JPn6.js} +3 -3
- package/dist/web/public/assets/{workspace-BnXrWS3j.js.map → workspace-CUg0JPn6.js.map} +1 -1
- package/dist/web/public/assets/{workspaces-CSS_UBEi.js → workspaces-C-wb5FQj.js} +2 -2
- package/dist/web/public/assets/{workspaces-CSS_UBEi.js.map → workspaces-C-wb5FQj.js.map} +1 -1
- package/dist/web/public/assets/{x-DG-JKVw_.js → x-D1iSuoqg.js} +2 -2
- package/dist/web/public/assets/{x-DG-JKVw_.js.map → x-D1iSuoqg.js.map} +1 -1
- package/dist/web/public/index.html +2 -2
- package/dist/web/server.d.ts.map +1 -1
- package/dist/web/server.js +6 -0
- package/dist/web/server.js.map +1 -1
- package/package.json +1 -1
- package/dist/web/public/assets/dialog-bAIDaO-6.js +0 -6
- package/dist/web/public/assets/dialog-bAIDaO-6.js.map +0 -1
- package/dist/web/public/assets/index-O0BQoyzo.js +0 -199
- package/dist/web/public/assets/index-O0BQoyzo.js.map +0 -1
- package/dist/web/public/assets/llm-CPIRNQU2.js +0 -7
- package/dist/web/public/assets/llm-CPIRNQU2.js.map +0 -1
- package/dist/web/public/assets/memos-CfneX9DH.js +0 -12
- package/dist/web/public/assets/memos-CfneX9DH.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/plugins/agents/native/index.ts"],"names":[],"mappings":"AAyCA,OAAO,KAAK,EACV,YAAY,EAGb,MAAM,wBAAwB,CAAA;AAG/B,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/plugins/agents/native/index.ts"],"names":[],"mappings":"AAyCA,OAAO,KAAK,EACV,YAAY,EAGb,MAAM,wBAAwB,CAAA;AAG/B,OAAO,EAIL,KAAK,WAAW,EACjB,MAAM,4BAA4B,CAAA;AACnC,OAAO,EAIL,KAAK,wBAAwB,EAC9B,MAAM,2CAA2C,CAAA;AAoDlD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,CAM5C;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,WAAW,EACrB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,SAAS,CAAC,EAAE,MAAM,GACjB,MAAM,CA+NR;AAmDD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAiBpD;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,CAG5C;AA4OD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE;IACJ,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE;QACN,SAAS,EAAE,aAAa,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,OAAO,CAAC;YAAC,OAAO,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;QAC9E,UAAU,EAAE,MAAM,CAAA;KACnB,CAAA;IACD,QAAQ,EAAE,WAAW,CAAA;IACrB,IAAI,EAAE,OAAO,GAAG,UAAU,GAAG,YAAY,GAAG,WAAW,CAAA;IACvD,iDAAiD;IACjD,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;CAClB,GACA,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAAG,IAAI,CAAC,CAwG1D;AAwED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,wBAAwB,CAgE1E;AAWD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAExD;AAoDD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAkCvF;AA2kBD,eAAO,MAAM,kBAAkB,EAAE,YAAuC,CAAA;AAExE;;cAEc;AACd,wBAAgB,mBAAmB,IAAI,MAAM,CAI5C"}
|
|
@@ -40,16 +40,14 @@
|
|
|
40
40
|
// persistence across turns)
|
|
41
41
|
import { logger as rootLogger } from '../../../core/logger.js';
|
|
42
42
|
import { logInvocation } from '../../../core/audit-log.js';
|
|
43
|
-
import { runAgentLoop,
|
|
44
|
-
import { buildBuiltinDispatcher, getBuiltinTools, } from '../../../core/llm/builtin-dispatcher.js';
|
|
43
|
+
import { runAgentLoop, getProvider, } from '../../../core/llm/index.js';
|
|
45
44
|
import { buildPolicyApprovalGate, describePolicy, } from '../../../core/llm/policy-approval-gate.js';
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
import {
|
|
51
|
-
import {
|
|
52
|
-
import { listSkills } from '../../../core/skills/loader.js';
|
|
45
|
+
// Tool assembly (defs + dispatch + per-call concurrency classifier) moved
|
|
46
|
+
// into tool-registry.ts (#86); the per-dispatcher builder imports live there
|
|
47
|
+
// now. MAX_INJECTED_SKILLS is still needed here for the system-prompt skills
|
|
48
|
+
// cap (#85/T3).
|
|
49
|
+
import { assembleNativeTools } from './tool-registry.js';
|
|
50
|
+
import { listSkills, MAX_INJECTED_SKILLS } from '../../../core/skills/loader.js';
|
|
53
51
|
import { describeRegistry as describeMcpRegistry } from '../../../core/llm/mcp-registry.js';
|
|
54
52
|
import { resolveAgentCwd, defaultAgentCwd } from '../../../core/agent-cwd.js';
|
|
55
53
|
import { handlePushOp } from '../../../core/push-rpc.js';
|
|
@@ -61,6 +59,50 @@ import { existsSync as fsExistsSync, statSync as fsStatSync, readFileSync as fsR
|
|
|
61
59
|
import { resolve as pathResolve, sep as pathSep, join as pathJoin } from 'node:path';
|
|
62
60
|
import { sanitizeForInjection, scanForInjectionAttempts } from '../../../core/prompt-injection-guard.js';
|
|
63
61
|
const log = rootLogger.child({ component: 'native-agent' });
|
|
62
|
+
/**
|
|
63
|
+
* v1.2.147 — framework-level tool-call discipline injected into EVERY
|
|
64
|
+
* native turn's system prompt. Sits at the top, before the operator
|
|
65
|
+
* role definition, so it dominates any persona-level rules the user
|
|
66
|
+
* authors. Pure prompt — paired with the runtime hallucination
|
|
67
|
+
* detector (`detectHallucinatedToolCall`) that catches the failure
|
|
68
|
+
* mode if the model ignores the rule.
|
|
69
|
+
*
|
|
70
|
+
* Why this is hard-coded, not optional:
|
|
71
|
+
* - The failure (model narrates a tool call without emitting it) is
|
|
72
|
+
* LLM-side and silent; we cannot fully prevent it. But almost every
|
|
73
|
+
* instance we've seen would have been deterred by an explicit
|
|
74
|
+
* "do not narrate, just emit" rule.
|
|
75
|
+
* - Leaving this to operator AGENTS.md means every fresh install
|
|
76
|
+
* reproduces the same harm before the operator notices.
|
|
77
|
+
* - Escape hatch: IMHUB_NATIVE_TOOL_DISCIPLINE=off (or 0/false/no/
|
|
78
|
+
* disable) lets advanced operators drop the block, e.g. when
|
|
79
|
+
* measuring whether the prompt itself is hurting tool-call recall.
|
|
80
|
+
*/
|
|
81
|
+
const TOOL_CALL_DISCIPLINE_PROMPT = [
|
|
82
|
+
'## 工具调用纪律(agim 框架级硬约束)',
|
|
83
|
+
'',
|
|
84
|
+
'- 禁止用文本"描述/演练"工具调用。例如不可输出 `我现在调用 native_write_file: \\`\\`\\`python ...\\`\\`\\`` —— 想用工具就直接发 `toolCalls`,不要先用纯文本预告。',
|
|
85
|
+
'- 工具调用必须真的发生:如果当轮没真正发出 `toolCalls`,就不要输出"已经写好 / 已经存好 / 已经调了 X"这类口径,更不要承诺"下一步直接写"。',
|
|
86
|
+
'- 不确定是否该调用,用 `native_todo_write` 把意图留为 todo 让用户审,不要假装调用了又没调。',
|
|
87
|
+
'- 用户追问"做了吗 / 写好了吗 / 又没消息了",先回顾本轮 `toolCalls` 历史;没有就直接坦白"没调成",禁止编造"这次直接写""不废话了"等空承诺——空承诺没有任何代价但会摧毁信任。',
|
|
88
|
+
'- write / edit / exec 类副作用工具一次性写完整调用,不要分两步"先承诺再调用"。',
|
|
89
|
+
'',
|
|
90
|
+
'(运行时会有 hallucination 检测器在末轮抓"narrate without emit",触发会用复盘卡替换原回复。)',
|
|
91
|
+
].join('\n');
|
|
92
|
+
/**
|
|
93
|
+
* Read the IMHUB_NATIVE_TOOL_DISCIPLINE kill-switch. Default ON.
|
|
94
|
+
* Recognized OFF values: 'off' / '0' / 'false' / 'no' / 'disable'.
|
|
95
|
+
* Pairs with isHallucinationDetectorOn (hallucination-detector.ts): the
|
|
96
|
+
* detector still fires when discipline is off, by design — discipline
|
|
97
|
+
* removed is a prompting test, not a license to ship lies.
|
|
98
|
+
*/
|
|
99
|
+
export function isToolDisciplineOn() {
|
|
100
|
+
const raw = (process.env.IMHUB_NATIVE_TOOL_DISCIPLINE ?? '').toLowerCase().trim();
|
|
101
|
+
if (raw === 'off' || raw === '0' || raw === 'false' || raw === 'no' || raw === 'disable') {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
64
106
|
/**
|
|
65
107
|
* v1.2.47 — system prompt is rebuilt per IM turn so the model sees:
|
|
66
108
|
* - which LLM backend + role it's actually running on
|
|
@@ -76,9 +118,26 @@ const log = rootLogger.child({ component: 'native-agent' });
|
|
|
76
118
|
* field surfaced here is operator-configured and non-sensitive.
|
|
77
119
|
*/
|
|
78
120
|
export function buildSystemPrompt(provider, role, cwd, threadKey) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
121
|
+
// T3 (context-as-budget): bound the tier-1 skills listing. listSkills()
|
|
122
|
+
// already caps each description at MAX_DESCRIPTION_CHARS; here we also cap
|
|
123
|
+
// the COUNT to MAX_INJECTED_SKILLS (the same ceiling buildSkillsSummary
|
|
124
|
+
// uses) so a large catalog can't blow the per-turn system-prompt budget.
|
|
125
|
+
// Sorted for stable ordering; overflow collapses into a "+N more" hint
|
|
126
|
+
// that points the model at the on-demand read_skill / /skill list path.
|
|
127
|
+
// (Previously this re-rolled an UNCAPPED `name: desc` line per skill.)
|
|
128
|
+
const allSkills = listSkills().slice().sort((a, b) => a.name.localeCompare(b.name));
|
|
129
|
+
const visibleSkills = allSkills.slice(0, MAX_INJECTED_SKILLS);
|
|
130
|
+
const skillsBlock = visibleSkills.length
|
|
131
|
+
? visibleSkills
|
|
132
|
+
.map((s) => {
|
|
133
|
+
const desc = (s.description || '').trim() || '(no description; read body via mcp__imhub__read_skill)';
|
|
134
|
+
const mark = s.available ? '' : ` (unavailable: ${s.unavailableReason ?? 'requires not met'})`;
|
|
135
|
+
return ` - ${s.name}: ${desc}${mark}`;
|
|
136
|
+
})
|
|
137
|
+
.join('\n')
|
|
138
|
+
+ (allSkills.length > visibleSkills.length
|
|
139
|
+
? `\n … and ${allSkills.length - visibleSkills.length} more (use /skill list; read any with mcp__imhub__read_skill)`
|
|
140
|
+
: '')
|
|
82
141
|
: ' (no skill cards loaded; see docs/skills.md to add one)';
|
|
83
142
|
const mcpReg = describeMcpRegistry();
|
|
84
143
|
const externalMcp = mcpReg.servers.length
|
|
@@ -87,6 +146,16 @@ export function buildSystemPrompt(provider, role, cwd, threadKey) {
|
|
|
87
146
|
.join('\n')
|
|
88
147
|
: ' (none configured)';
|
|
89
148
|
const lines = [];
|
|
149
|
+
// v1.2.147 — framework-level tool-call discipline. Prepended BEFORE
|
|
150
|
+
// the operator role so it dominates persona-level rules. Hard-coded
|
|
151
|
+
// (not derived from a file) so every fresh agim install gets it, no
|
|
152
|
+
// per-user setup. Pairs with the runtime hallucination detector.
|
|
153
|
+
if (isToolDisciplineOn()) {
|
|
154
|
+
lines.push('[agim framework rule — tool-call discipline]');
|
|
155
|
+
lines.push(TOOL_CALL_DISCIPLINE_PROMPT);
|
|
156
|
+
lines.push('[/agim framework rule]');
|
|
157
|
+
lines.push('');
|
|
158
|
+
}
|
|
90
159
|
// Operator-supplied role definition. Reads <cwd>/AGENTS.md (seeded by
|
|
91
160
|
// bootstrapAgentWorkspaces) and prepends it as a role block. Lets
|
|
92
161
|
// operators customise the agent's identity, tone, and house rules
|
|
@@ -108,32 +177,37 @@ export function buildSystemPrompt(provider, role, cwd, threadKey) {
|
|
|
108
177
|
if (isPlanModeOn(threadKey)) {
|
|
109
178
|
lines.push(`⚠ Plan mode is ACTIVE`, ` - You MUST produce a read-only plan; native_write_file and native_exec are HARD-BLOCKED.`, ` - Use read tools freely: native_read_file / native_list_dir / native_glob / native_grep / native_web_fetch / native_web_search.`, ` - Exit handshake (v1.2.131): when the plan is ready, call`, ` native_exit_plan_mode({ plan: '<markdown of the steps>' })`, ` The user will see an Approve/Reject card. On approve you regain full write access and proceed immediately. On reject you stay in Plan Mode with the user's feedback in the tool result — revise and call again.`, ` - DO NOT just describe the plan in prose and stop — the user expects the exit handshake. Skip it only if the user explicitly asks for "no exit" / "just brainstorm".`, ``);
|
|
110
179
|
}
|
|
111
|
-
lines.push(`Tools available beyond the four native built-ins (echo / now / sleep / random_uuid):`, ` - agim built-in MCP tools (mcp__imhub__*): read_skill, list_skills, save_memo, search_memos, update_memo, delete_memo, push_message, ask_user, call_agent, long_task, complete_goal`, ` - native filesystem tools: native_read_file, native_write_file, native_list_dir, native_glob, native_grep — constrained to your workspace cwd unless IMHUB_NATIVE_FS_RESTRICT=0`, ` - native web tools: native_web_fetch (r.jina.ai reader by default), native_web_search (duckduckgo → metaso fallback). Private IPs blocked.`, ` - native_exec(command, timeout_ms?, cwd?): run shell commands. Always approval-gated; bwrap sandbox when IMHUB_EXEC_SANDBOX=bwrap.`, ` - External MCP servers configured by the operator:`, externalMcp, ``, `Available skill cards (call mcp__imhub__read_skill('<name>') for the full body):`, skillsBlock, ``, `Guidance:`, ` - Be terse; avoid filler. Prefer tool use over guessing.`, ` - When uncertain, call mcp__imhub__ask_user(question, choices[]) instead of free-form back-and-forth.`, ` - When the user references something they told the bot before, search memos via mcp__imhub__search_memos.`, ``, `Tool selection priority (HARD RULE — v1.2.59):`, ` - For "read this file / list this dir / search this content / fetch this URL", you MUST FIRST try`, ` your own native tools: native_read_file, native_list_dir, native_glob, native_grep,`, ` native_web_fetch (if available). Do NOT delegate these to call_agent.`, ` - call_agent is reserved for tasks that genuinely need a CLI agent's specialised capabilities`, ` (writing/editing source code in a real repo → claude-code; long-running plans → codex; etc).`, ` - You have a per-turn call_agent cap (default 2). Burning it on file reads will leave you`, ` unable to delegate later when you actually need to.`, ``, `When to USE call_agent (v1.2.139 positive framing — pair with the HARD RULE above):`, ` - The task needs sustained source-code editing in a real repo → call_agent('claude-code', …)`, ` or call_agent('codex', …). Don't try to mimic them with native_write_file when the work is`, ` multi-file refactors or feature builds.`, ` - You need a second pair of eyes / cross-checking on your own conclusion → call_agent('codex',`, ` 'audit my findings: …'). Useful before committing or reporting.`, ` - The task is large enough that parallel research helps (e.g. survey 3 independent areas of`, ` a codebase) → fan-out via call_agent('native', …) so each sub-agent's context is fresh.`, ` - Tip: write the sub-agent prompt as a self-contained brief — they don't see this conversation.`, ``, `Web tool routing (HARD RULE — v1.2.64):`, ` - If the user provided a SPECIFIC URL (http://… or https://…) → native_web_fetch.`, ` - If the user wants to FIND / DISCOVER something by keywords ("查找最新 X" / "search for Y" /`, ` "find docs on Z" / "今天 / 最近的 W") → native_web_search FIRST. Don't guess a URL.`, ` - Common pattern: native_web_search(query) → pick a result → native_web_fetch(that.url).`, ` - NEVER call native_web_fetch with a URL you fabricated from the user's keywords.`, ``, `Short-input rule:`, ` - If the user's message is ONLY a slash command alias for an agent name (e.g. "/native", "/llm",`, ` "/na", "/cc", "/oc") and you are already that agent, respond with ONE short line confirming`, ` your identity (e.g. "我是 native,正在听。"). Do NOT call any tool. The slash router handles`, ` actual agent switching; if it didn't switch, the user is already on this agent.`, ``, `Plan tracking (v1.2.124 — native_todo_write):`, ` - When the user gives you a task with ≥ 3 distinct steps, FIRST call native_todo_write({items}) to`, ` write out your plan, then update statuses as you complete each step.`, ` Status values: pending | in_progress | completed. Keep exactly one item in_progress at a time.`, ` - The tool result is a rendered markdown checklist; the user sees your progress.`, ` - Don't call native_todo_write for trivial one-step tasks — overhead.`, ` - Example sequence:`, ` 1) native_todo_write([{c:"Fetch market data",s:"in_progress"}, {c:"Analyse",s:"pending"}, {c:"Reply",s:"pending"}])`, ` 2) … do fetch via native_web_fetch …`, ` 3) native_todo_write([{c:"Fetch market data",s:"completed"}, {c:"Analyse",s:"in_progress"}, {c:"Reply",s:"pending"}])`, ` 4) … analysis …`, ` 5) write final answer to user`, ``, `Closure rule (v1.2.94 — HARD RULE):`, ` - When you finish a tool chain (read_file / web_fetch / native_exec / search_memos / etc.) you`, ` MUST write a short Chinese summary BEFORE stopping. The tool output by itself is not a`, ` user-facing answer — the user can't see the raw JSON / shell stdout. Always close with at`, ` least one sentence stating the finding / conclusion.`, ` - Do NOT end a turn with empty assistant text when you've just called tools. If you genuinely`, ` have nothing to add, say so explicitly ("已查完,未发现 X").`, ``, `Proactive memory rule (v1.2.96 — borrowed from Hermes Agent's "agent-curated memory"):`, ` - Before ending a substantive turn, scan the conversation for facts that should outlive the`, ` current chat. Persist them yourself via mcp__imhub__save_memo — don't wait for the user to`, ` ask you to remember.`, ` - Worth saving (call save_memo for each):`, ` · personal preferences ("我不喝咖啡" / "我用 vim"),`, ` · holdings or portfolio codes ("我持有 600519"),`, ` · recurring people / places ("我家在朝阳" / "爸爸生日 5月8日"),`, ` · stable identifiers (账号 / 邮箱 / API base / 配置路径),`, ` · explicit "记一下" / "remember this" instructions.`, ` - NOT worth saving: one-off questions, transient debugging context, tool outputs that are`, ` already cached elsewhere (memos point AT data, they're not a cache of data).`, ` - Each save_memo call is cheap. Two short memos beat one long one — small atomic facts`, ` search better. Add a 1-line user-facing acknowledgement so the user knows you remembered`, ` (e.g. "已记下 600519 是你的持仓").`, ``, `Long-task SOP (v1.2.93 — for any work you estimate will run > 10 minutes):`, ` - You CANNOT keep a long synchronous turn alive: the IM bridge times out around 30 min, and`, ` most useful work past the 10-min mark loses intermediate state if it crashes mid-flight.`, ` - Instead, use native_exec to invoke the agim bgjob wrapper, which spawns a detached worker`, ` that survives independent of this conversation:`, ` native_exec("/root/.claude/scripts/bgjob start <slug> -- /usr/bin/python3 /path/to/script.py [args]")`, ` Substitute python3 for the runtime you actually need. The wrapper returns a job_id; relay it`, ` to the user verbatim and tell them how to check back: \`bgjob status <id>\` / \`bgjob tail <id> -f\`.`, ` - When the user follows up asking about the job, native_exec calls like \`bgjob status <id>\` or`, ` \`bgjob tail <id> -n 100\` give you the current state + recent log lines.`, ` - The bwrap sandbox (when configured) is bypassed for this specific wrapper path so the`, ` setsid-detached worker actually survives. Any OTHER native_exec command remains sandboxed.`, ` - DO NOT use \`nohup ... &\` or backgrounded shell pipelines for long work — those die with the`, ` parent shell. bgjob is the only correct path on this platform.`, ``, `Python-RPC bridge (v1.2.97 — when a task means MANY similar tool calls):`, ` - When you would otherwise call mcp__imhub__* dozens of times in this chat turn (saving 30`, ` facts, fetching 50 stocks, scoring 100 candidates), DO NOT do it inline — that wastes the`, ` iteration budget and is likely to trip the stuck-loop detector. Write ONE Python script,`, ` run it in bgjob, and let it loop locally while calling back to agim's tool surface via the`, ` local RPC bridge agim sets up automatically for every native_exec child.`, ` - The Python sidecar lives at \`<npm install dir>/bin/agim_rpc.py\` (typically`, ` /usr/local/lib/node_modules/agim-cli/bin/agim_rpc.py — find it with`, ` \`node -e "console.log(require.resolve('agim-cli'))"\`). Import it and instantiate the client:`, ` from agim_rpc import client`, ` rpc = client() # reads env, validates token, no args needed`, ` memos = rpc.search_memos(query="茅台", k=10)`, ` for m in memos.get("rows", []):`, ` ...`, ` rpc.push_message(text="后台跑完了,结果是 X")`, ` - Available tools through the bridge (whitelist): search_memos, save_memo, read_skill,`, ` list_skills, push_message. Everything else (native_exec, fs writes, call_agent, long_task,`, ` ask_user) is NOT exposed — the worker already has a shell + filesystem.`, ` - The token is automatically injected via env (IMHUB_RPC_SOCKET + IMHUB_RPC_TOKEN), bound`, ` to THIS IM thread, valid for 24 h. The worker can only drive this thread; it cannot`, ` push_message into someone else's chat.`, ` - End the worker with rpc.push_message(text="…done…") so the user sees the result come back`, ` asynchronously. Don't expect the user to poll \`bgjob tail\` themselves.`);
|
|
180
|
+
lines.push(`Tools available beyond the four native built-ins (echo / now / sleep / random_uuid):`, ` - agim built-in MCP tools (mcp__imhub__*): read_skill, list_skills, save_memo, search_memos, update_memo, delete_memo, push_message, ask_user, call_agent, long_task, complete_goal`, ` - native filesystem tools: native_read_file, native_write_file, native_list_dir, native_glob, native_grep — constrained to your workspace cwd unless IMHUB_NATIVE_FS_RESTRICT=0`, ` - native web tools: native_web_fetch (r.jina.ai reader by default), native_web_search (duckduckgo → metaso fallback). Private IPs blocked.`, ` - native_exec(command, timeout_ms?, cwd?): run shell commands. Always approval-gated; bwrap sandbox when IMHUB_EXEC_SANDBOX=bwrap.`, ` - External MCP servers configured by the operator:`, externalMcp, ``, `Available skill cards (call mcp__imhub__read_skill('<name>') for the full body):`, skillsBlock, ``, `Guidance:`, ` - Be terse; avoid filler. Prefer tool use over guessing.`, ` - When uncertain, call mcp__imhub__ask_user(question, choices[]) instead of free-form back-and-forth.`, ` - When the user references something they told the bot before, search memos via mcp__imhub__search_memos.`, ``, `Tool selection priority (HARD RULE — v1.2.59):`, ` - For "read this file / list this dir / search this content / fetch this URL", you MUST FIRST try`, ` your own native tools: native_read_file, native_list_dir, native_glob, native_grep,`, ` native_web_fetch (if available). Do NOT delegate these to call_agent.`, ` - call_agent is reserved for tasks that genuinely need a CLI agent's specialised capabilities`, ` (writing/editing source code in a real repo → claude-code; long-running plans → codex; etc).`, ` - You have a per-turn call_agent cap (default 2). Burning it on file reads will leave you`, ` unable to delegate later when you actually need to.`, ``, `When to USE call_agent (v1.2.139 positive framing — pair with the HARD RULE above):`, ` - The task needs sustained source-code editing in a real repo → call_agent('claude-code', …)`, ` or call_agent('codex', …). Don't try to mimic them with native_write_file when the work is`, ` multi-file refactors or feature builds.`, ` - You need a second pair of eyes / cross-checking on your own conclusion → call_agent('codex',`, ` 'audit my findings: …'). Useful before committing or reporting.`, ` - The task is large enough that parallel research helps (e.g. survey 3 independent areas of`, ` a codebase) → fan-out via call_agent('native', …) so each sub-agent's context is fresh.`, ` - Tip: write the sub-agent prompt as a self-contained brief — they don't see this conversation.`, ``, `Verification subagent (T5 — harness pattern, the most reliably useful multi-agent move):`, ` - After you produce a SUBSTANTIVE result (a multi-step conclusion, a refactor, a data`, ` analysis, anything you're about to report or commit), spin up a FRESH subagent whose sole`, ` job is to verify it independently:`, ` call_agent('codex', 'Verify the result below against <source / acceptance criteria>.`, ` Report ONLY discrepancies or risks; if it checks out, say so. <paste result>')`, ` Use 'codex' for code/logic review, 'native' for a fresh-eyes fact/consistency check.`, ` - Give the verifier a SELF-CONTAINED brief: restate the claim AND how to check it, and paste`, ` the artifact. It does NOT see this conversation — "verify my findings" with nothing attached`, ` is useless.`, ` - Synthesize, don't delegate understanding: digest what you learned into a PRECISE spec before`, ` delegating implementation or verification. "Based on your findings, fix it" is an anti-pattern`, ` — you (the coordinator) must state exactly what to do, not hand off the thinking.`, ` - Don't over-verify: skip the verifier for trivial / low-stakes turns (it costs a call_agent hop).`, ``, `Web tool routing (HARD RULE — v1.2.64):`, ` - If the user provided a SPECIFIC URL (http://… or https://…) → native_web_fetch.`, ` - If the user wants to FIND / DISCOVER something by keywords ("查找最新 X" / "search for Y" /`, ` "find docs on Z" / "今天 / 最近的 W") → native_web_search FIRST. Don't guess a URL.`, ` - Common pattern: native_web_search(query) → pick a result → native_web_fetch(that.url).`, ` - NEVER call native_web_fetch with a URL you fabricated from the user's keywords.`, ``, `Short-input rule:`, ` - If the user's message is ONLY a slash command alias for an agent name (e.g. "/native", "/llm",`, ` "/na", "/cc", "/oc") and you are already that agent, respond with ONE short line confirming`, ` your identity (e.g. "我是 native,正在听。"). Do NOT call any tool. The slash router handles`, ` actual agent switching; if it didn't switch, the user is already on this agent.`, ``, `Plan tracking (v1.2.124 — native_todo_write):`, ` - When the user gives you a task with ≥ 3 distinct steps, FIRST call native_todo_write({items}) to`, ` write out your plan, then update statuses as you complete each step.`, ` Status values: pending | in_progress | completed. Keep exactly one item in_progress at a time.`, ` - The tool result is a rendered markdown checklist; the user sees your progress.`, ` - Don't call native_todo_write for trivial one-step tasks — overhead.`, ` - Example sequence:`, ` 1) native_todo_write([{c:"Fetch market data",s:"in_progress"}, {c:"Analyse",s:"pending"}, {c:"Reply",s:"pending"}])`, ` 2) … do fetch via native_web_fetch …`, ` 3) native_todo_write([{c:"Fetch market data",s:"completed"}, {c:"Analyse",s:"in_progress"}, {c:"Reply",s:"pending"}])`, ` 4) … analysis …`, ` 5) write final answer to user`, ``, `Closure rule (v1.2.94 — HARD RULE):`, ` - When you finish a tool chain (read_file / web_fetch / native_exec / search_memos / etc.) you`, ` MUST write a short Chinese summary BEFORE stopping. The tool output by itself is not a`, ` user-facing answer — the user can't see the raw JSON / shell stdout. Always close with at`, ` least one sentence stating the finding / conclusion.`, ` - Do NOT end a turn with empty assistant text when you've just called tools. If you genuinely`, ` have nothing to add, say so explicitly ("已查完,未发现 X").`, ``, `Proactive memory rule (v1.2.96 — borrowed from Hermes Agent's "agent-curated memory"):`, ` - Before ending a substantive turn, scan the conversation for facts that should outlive the`, ` current chat. Persist them yourself via mcp__imhub__save_memo — don't wait for the user to`, ` ask you to remember.`, ` - Worth saving (call save_memo for each):`, ` · personal preferences ("我不喝咖啡" / "我用 vim"),`, ` · holdings or portfolio codes ("我持有 600519"),`, ` · recurring people / places ("我家在朝阳" / "爸爸生日 5月8日"),`, ` · stable identifiers (账号 / 邮箱 / API base / 配置路径),`, ` · explicit "记一下" / "remember this" instructions.`, ` - NOT worth saving: one-off questions, transient debugging context, tool outputs that are`, ` already cached elsewhere (memos point AT data, they're not a cache of data).`, ` - Each save_memo call is cheap. Two short memos beat one long one — small atomic facts`, ` search better. Add a 1-line user-facing acknowledgement so the user knows you remembered`, ` (e.g. "已记下 600519 是你的持仓").`, ``, `Long-task SOP (v1.2.93 — for any work you estimate will run > 10 minutes):`, ` - You CANNOT keep a long synchronous turn alive: the IM bridge times out around 30 min, and`, ` most useful work past the 10-min mark loses intermediate state if it crashes mid-flight.`, ` - Instead, use native_exec to invoke the agim bgjob wrapper, which spawns a detached worker`, ` that survives independent of this conversation:`, ` native_exec("/root/.claude/scripts/bgjob start <slug> -- /usr/bin/python3 /path/to/script.py [args]")`, ` Substitute python3 for the runtime you actually need. The wrapper returns a job_id; relay it`, ` to the user verbatim and tell them how to check back: \`bgjob status <id>\` / \`bgjob tail <id> -f\`.`, ` - When the user follows up asking about the job, native_exec calls like \`bgjob status <id>\` or`, ` \`bgjob tail <id> -n 100\` give you the current state + recent log lines.`, ` - The bwrap sandbox (when configured) is bypassed for this specific wrapper path so the`, ` setsid-detached worker actually survives. Any OTHER native_exec command remains sandboxed.`, ` - DO NOT use \`nohup ... &\` or backgrounded shell pipelines for long work — those die with the`, ` parent shell. bgjob is the only correct path on this platform.`, ``, `Python-RPC bridge (v1.2.97 — when a task means MANY similar tool calls):`, ` - When you would otherwise call mcp__imhub__* dozens of times in this chat turn (saving 30`, ` facts, fetching 50 stocks, scoring 100 candidates), DO NOT do it inline — that wastes the`, ` iteration budget and is likely to trip the stuck-loop detector. Write ONE Python script,`, ` run it in bgjob, and let it loop locally while calling back to agim's tool surface via the`, ` local RPC bridge agim sets up automatically for every native_exec child.`, ` - The Python sidecar lives at \`<npm install dir>/bin/agim_rpc.py\` (typically`, ` /usr/local/lib/node_modules/agim-cli/bin/agim_rpc.py — find it with`, ` \`node -e "console.log(require.resolve('agim-cli'))"\`). Import it and instantiate the client:`, ` from agim_rpc import client`, ` rpc = client() # reads env, validates token, no args needed`, ` memos = rpc.search_memos(query="茅台", k=10)`, ` for m in memos.get("rows", []):`, ` ...`, ` rpc.push_message(text="后台跑完了,结果是 X")`, ` - Available tools through the bridge (whitelist): search_memos, save_memo, read_skill,`, ` list_skills, push_message. Everything else (native_exec, fs writes, call_agent, long_task,`, ` ask_user) is NOT exposed — the worker already has a shell + filesystem.`, ` - The token is automatically injected via env (IMHUB_RPC_SOCKET + IMHUB_RPC_TOKEN), bound`, ` to THIS IM thread, valid for 24 h. The worker can only drive this thread; it cannot`, ` push_message into someone else's chat.`, ` - End the worker with rpc.push_message(text="…done…") so the user sees the result come back`, ` asynchronously. Don't expect the user to poll \`bgjob tail\` themselves.`);
|
|
112
181
|
return lines.join('\n');
|
|
113
182
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
const override = process.env.IMHUB_NATIVE_AGENT_ROLE_FILE;
|
|
124
|
-
const path = override && override.length > 0 ? override : pathJoin(cwd, 'AGENTS.md');
|
|
125
|
-
if (!fsExistsSync(path))
|
|
183
|
+
const _operatorRoleCache = new Map();
|
|
184
|
+
function readRoleFile(path) {
|
|
185
|
+
let st;
|
|
186
|
+
try {
|
|
187
|
+
st = fsStatSync(path);
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
// Missing / unreadable → no role block; drop any stale cache entry.
|
|
191
|
+
_operatorRoleCache.delete(path);
|
|
126
192
|
return '';
|
|
193
|
+
}
|
|
194
|
+
const cached = _operatorRoleCache.get(path);
|
|
195
|
+
if (cached && cached.mtimeMs === st.mtimeMs && cached.size === st.size) {
|
|
196
|
+
return cached.content;
|
|
197
|
+
}
|
|
127
198
|
let raw = '';
|
|
128
199
|
try {
|
|
129
200
|
raw = fsReadFileSync(path, 'utf-8');
|
|
130
201
|
}
|
|
131
202
|
catch {
|
|
203
|
+
_operatorRoleCache.delete(path);
|
|
132
204
|
return '';
|
|
133
205
|
}
|
|
134
206
|
const trimmed = raw.trim();
|
|
135
|
-
if (!trimmed)
|
|
207
|
+
if (!trimmed) {
|
|
208
|
+
_operatorRoleCache.set(path, { mtimeMs: st.mtimeMs, size: st.size, content: '' });
|
|
136
209
|
return '';
|
|
210
|
+
}
|
|
137
211
|
try {
|
|
138
212
|
const scan = scanForInjectionAttempts(trimmed);
|
|
139
213
|
if (scan.suspicious) {
|
|
@@ -145,7 +219,70 @@ export function readOperatorRole(cwd) {
|
|
|
145
219
|
}
|
|
146
220
|
}
|
|
147
221
|
catch { /* scan is best-effort */ }
|
|
148
|
-
|
|
222
|
+
const content = sanitizeForInjection(trimmed, 8000);
|
|
223
|
+
_operatorRoleCache.set(path, { mtimeMs: st.mtimeMs, size: st.size, content });
|
|
224
|
+
return content;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Resolve the operator role definition injected into native's system prompt.
|
|
228
|
+
*
|
|
229
|
+
* T4 (instruction hierarchy, distilled from the agentic-harness Memory
|
|
230
|
+
* pattern's "local overrides win — always"). Instead of a single
|
|
231
|
+
* `<cwd>/AGENTS.md`, discover a layered stack within the native workspace
|
|
232
|
+
* and concatenate in ASCENDING priority so the most-local block appears last
|
|
233
|
+
* and gets the most model attention. LOCAL WINS:
|
|
234
|
+
*
|
|
235
|
+
* 1. project — <cwd>/AGENTS.md (the shared native-workspace role)
|
|
236
|
+
* 2. local — <cwd>/AGENTS.local.md (private override, not version-ctl'd)
|
|
237
|
+
*
|
|
238
|
+
* Both layers live under the native workspace cwd, so the stack is
|
|
239
|
+
* self-contained (no dependency on a global ~/.agim file — native has a
|
|
240
|
+
* single workspace, so "project" already IS the operator-global role; a
|
|
241
|
+
* cross-workspace user layer can be added later if that changes).
|
|
242
|
+
*
|
|
243
|
+
* IMHUB_NATIVE_AGENT_ROLE_FILE still forces a single explicit file (operators
|
|
244
|
+
* who pin one path bypass discovery entirely). Each layer is independently
|
|
245
|
+
* memoized + injection-scanned + capped at 8000 chars by readRoleFile.
|
|
246
|
+
*/
|
|
247
|
+
export function readOperatorRole(cwd) {
|
|
248
|
+
const override = process.env.IMHUB_NATIVE_AGENT_ROLE_FILE;
|
|
249
|
+
if (override && override.length > 0) {
|
|
250
|
+
// An explicit pin is operator-chosen → trusted regardless of the gate.
|
|
251
|
+
return readRoleFile(override);
|
|
252
|
+
}
|
|
253
|
+
// T6 — workspace trust gate. Discovered workspace files are skipped wholesale
|
|
254
|
+
// when the workspace is marked untrusted (see isWorkspaceTrusted).
|
|
255
|
+
if (!isWorkspaceTrusted()) {
|
|
256
|
+
return '';
|
|
257
|
+
}
|
|
258
|
+
const parts = [];
|
|
259
|
+
for (const p of [pathJoin(cwd, 'AGENTS.md'), pathJoin(cwd, 'AGENTS.local.md')]) {
|
|
260
|
+
const c = readRoleFile(p);
|
|
261
|
+
if (c)
|
|
262
|
+
parts.push(c);
|
|
263
|
+
}
|
|
264
|
+
return parts.join('\n\n');
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* T6 — workspace trust gate (distilled from the agentic-harness Lifecycle
|
|
268
|
+
* pattern's "trust is all-or-nothing; an untrusted workspace disables the
|
|
269
|
+
* whole extension surface, not just suspicious parts").
|
|
270
|
+
*
|
|
271
|
+
* agim treats `<cwd>/AGENTS.md` + `AGENTS.local.md` as an operator-authored
|
|
272
|
+
* role definition injected into the system prompt — a privileged surface. In
|
|
273
|
+
* multi-tenant / A2A setups the native cwd can point at a directory whose
|
|
274
|
+
* contents are NOT fully operator-controlled, where an attacker-planted
|
|
275
|
+
* AGENTS.md is a prompt-injection vector. Setting
|
|
276
|
+
* `IMHUB_NATIVE_TRUST_WORKSPACE=off` (or 0/false/no) makes readOperatorRole
|
|
277
|
+
* skip ALL workspace-discovered role files at once. Default is trusted
|
|
278
|
+
* (on) for backward compatibility — operators opt into the stricter posture.
|
|
279
|
+
*
|
|
280
|
+
* An explicit `IMHUB_NATIVE_AGENT_ROLE_FILE` bypasses the gate: the operator
|
|
281
|
+
* pinned that exact file deliberately, so it stays trusted.
|
|
282
|
+
*/
|
|
283
|
+
export function isWorkspaceTrusted() {
|
|
284
|
+
const raw = (process.env.IMHUB_NATIVE_TRUST_WORKSPACE ?? '').toLowerCase().trim();
|
|
285
|
+
return !(raw === 'off' || raw === '0' || raw === 'false' || raw === 'no');
|
|
149
286
|
}
|
|
150
287
|
/** Role priority for picking which LLM backend powers the native chat
|
|
151
288
|
* turn. First found wins. Operators can override the role via
|
|
@@ -328,6 +465,44 @@ function composeOffTrackRecap(result, reason, redirect) {
|
|
|
328
465
|
lines.push(' · 或 /cc / /oc / /cs 切到别的智能体接手');
|
|
329
466
|
return lines.join('\n');
|
|
330
467
|
}
|
|
468
|
+
/**
|
|
469
|
+
* v1.2.147 — recap for the "hallucinated tool-call" failure mode.
|
|
470
|
+
*
|
|
471
|
+
* Trigger: agent-loop detected the model's final text narrates a
|
|
472
|
+
* native_* tool invocation (e.g. "我现在调用 native_write_file:
|
|
473
|
+
* ```python ...```" or "let me invoke native_exec") but the response
|
|
474
|
+
* carried zero real toolCalls. The model promised an action it did not
|
|
475
|
+
* take. Without this branch the lie would get shipped to the user as a
|
|
476
|
+
* normal reply.
|
|
477
|
+
*
|
|
478
|
+
* Distinct from the empty / max-iter / stuck-loop recaps because the
|
|
479
|
+
* fail-mode is model-side rather than budget-side: the model is fine,
|
|
480
|
+
* just not in a tool-calling mood. The recap points the user at a
|
|
481
|
+
* backend swap as the most reliable next step, since prompt tweaking
|
|
482
|
+
* has limited leverage when the model has already drifted out of the
|
|
483
|
+
* function-calling schema. Pure formatting; no LLM call.
|
|
484
|
+
*/
|
|
485
|
+
function composeHallucinatedToolRecap(result, backend) {
|
|
486
|
+
const lines = [];
|
|
487
|
+
lines.push('🧐 模型说要调用工具,但实际上没真的发起调用。');
|
|
488
|
+
lines.push('为了不让你看到空承诺,已经把这次回复挡下。');
|
|
489
|
+
lines.push('');
|
|
490
|
+
lines.push(`当前 native-chat 后端:${backend}`);
|
|
491
|
+
if (result.toolCalls.length > 0) {
|
|
492
|
+
lines.push(`本轮在此之前已真正完成了 ${result.toolCalls.length} 次工具调用,那部分有效。`);
|
|
493
|
+
}
|
|
494
|
+
else {
|
|
495
|
+
lines.push('本轮没有任何真实工具调用产出。');
|
|
496
|
+
}
|
|
497
|
+
lines.push('');
|
|
498
|
+
lines.push('怎么继续:');
|
|
499
|
+
lines.push(' · 直接回「重试」让我重新跑一遍这一步');
|
|
500
|
+
lines.push(' · 或在 /settings/llm 把 native-chat 角色换成工具调用更稳定的后端(Claude / GPT 系列)');
|
|
501
|
+
lines.push(' · 或 /cc / /oc / /cs 切到别的智能体接手这一步');
|
|
502
|
+
lines.push('');
|
|
503
|
+
lines.push('(检测器可用 IMHUB_NATIVE_HALLUCINATION_DETECT=off 关掉)');
|
|
504
|
+
return lines.join('\n');
|
|
505
|
+
}
|
|
331
506
|
/**
|
|
332
507
|
* v1.2.142 — Stage-report retry. Replaces v1.2.94's empty-only auto-
|
|
333
508
|
* summary with a single helper used by all four "unhappy ending"
|
|
@@ -613,31 +788,6 @@ const PLAN_MODE_DENY_TOOLS = [
|
|
|
613
788
|
export function isPlanModeOn(threadKey) {
|
|
614
789
|
return effectivePlanModeOn(threadKey);
|
|
615
790
|
}
|
|
616
|
-
/**
|
|
617
|
-
* v1.2.109 — names of native tools that are safe to dispatch in parallel
|
|
618
|
-
* within a single iteration. Strict opt-in: only tools with no side
|
|
619
|
-
* effects, no shared mutable state, and order-independent semantics.
|
|
620
|
-
* MCP tools beyond explicit read-only ones are NOT listed because they
|
|
621
|
-
* share session state with the agent loop's mcp-client and have caused
|
|
622
|
-
* races in the past (see comment near agent-loop's old serial-only
|
|
623
|
-
* note). Pure/read-only entries:
|
|
624
|
-
* - native_{echo,now,random_uuid}: pure
|
|
625
|
-
* - native_{read_file,list_dir,glob,grep}: read-only fs
|
|
626
|
-
* - native_{web_fetch,web_search}: read-only network (SSRF-checked)
|
|
627
|
-
* - mcp__imhub__{read_skill,list_skills,search_memos}: read-only
|
|
628
|
-
* - mcp__imhub__memory_{list,query}: read-only memory
|
|
629
|
-
* Everything else (native_exec, native_write_file, save/update/delete
|
|
630
|
-
* memo, push_message, ask_user, call_agent, long_task, complete_goal,
|
|
631
|
-
* other MCP) remains serial.
|
|
632
|
-
*/
|
|
633
|
-
const NATIVE_PARALLEL_SAFE_TOOLS = new Set([
|
|
634
|
-
'native_echo', 'native_now', 'native_random_uuid',
|
|
635
|
-
'native_read_file', 'native_list_dir', 'native_glob', 'native_grep',
|
|
636
|
-
'native_web_fetch', 'native_web_search',
|
|
637
|
-
'mcp__imhub__read_skill', 'mcp__imhub__list_skills',
|
|
638
|
-
'mcp__imhub__search_memos',
|
|
639
|
-
'mcp__imhub__memory_list', 'mcp__imhub__memory_query',
|
|
640
|
-
]);
|
|
641
791
|
/**
|
|
642
792
|
* v1.2.60 — bridge native's policy gate to the approval-bus so tools
|
|
643
793
|
* that the gate would otherwise silently deny instead surface an IM
|
|
@@ -903,13 +1053,15 @@ class NativeAgentAdapter {
|
|
|
903
1053
|
// the per-thread workspace subtree. Was previously resolved AFTER
|
|
904
1054
|
// dispatch composition; moved up so fs tools see the right root.
|
|
905
1055
|
const cwd = resolveAgentCwd('native', opts) || defaultAgentCwd('native');
|
|
906
|
-
|
|
1056
|
+
// T2 (single tool registry): assemble the advertised tool list, the
|
|
1057
|
+
// dispatch chain, AND the per-call concurrency classifier from ONE
|
|
1058
|
+
// source-of-truth (see tool-registry.ts). This replaced three
|
|
1059
|
+
// hand-maintained parallel lists (tools[] / combineDispatchers / the
|
|
1060
|
+
// static parallelSafeTools Set) that silently drifted when a tool was
|
|
1061
|
+
// added. The plan-exit dispatcher is always wired (it self-refuses off
|
|
1062
|
+
// plan mode); its tool is advertised only when plan mode is on.
|
|
1063
|
+
const assembled = assembleNativeTools({
|
|
907
1064
|
cwd,
|
|
908
|
-
// v1.2.97 — when this thread has a usable RunContext, hand it
|
|
909
|
-
// to exec-dispatcher so every spawned child inherits a fresh
|
|
910
|
-
// RPC token bound to the thread. Enables the Python-RPC bridge
|
|
911
|
-
// (bgjob worker → agim parent → memo/skill/push). Tokens are
|
|
912
|
-
// per-spawn, expire in 24h, and only authorise THIS thread.
|
|
913
1065
|
rpcCtx: opts.platform && opts.threadId
|
|
914
1066
|
? {
|
|
915
1067
|
platform: opts.platform,
|
|
@@ -918,45 +1070,20 @@ class NativeAgentAdapter {
|
|
|
918
1070
|
userId: opts.userId ?? '',
|
|
919
1071
|
}
|
|
920
1072
|
: undefined,
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
threadId: opts.threadId,
|
|
936
|
-
userId: opts.userId,
|
|
937
|
-
}), buildImhubDispatcher(imhubCtx), buildMcpDispatcher());
|
|
938
|
-
// Compose tool list the same way (built-in → fs → web → exec → todo → imhub → external MCP).
|
|
939
|
-
// Provider tool roster wins on duplicate names via "later
|
|
940
|
-
// definition wins" semantics inside the provider, but our naming
|
|
941
|
-
// is namespaced (`native_*`, `mcp__imhub__*`, `mcp_<server>_*`)
|
|
942
|
-
// so collisions are not expected in practice.
|
|
943
|
-
const tools = [
|
|
944
|
-
...getBuiltinTools(),
|
|
945
|
-
...getFsTools(),
|
|
946
|
-
...getWebTools(),
|
|
947
|
-
...getExecTools(),
|
|
948
|
-
...getTodoTools(),
|
|
949
|
-
...getImhubTools(),
|
|
950
|
-
...getAllMcpTools(),
|
|
951
|
-
];
|
|
952
|
-
// v1.2.131 — when this thread is in Plan Mode, advertise the
|
|
953
|
-
// dedicated exit tool so the model knows the handshake exists. We
|
|
954
|
-
// don't always advertise it: a model in normal mode shouldn't be
|
|
955
|
-
// tempted to call it (the dispatcher would refuse anyway, but
|
|
956
|
-
// keeping the roster honest is cleaner).
|
|
957
|
-
if (planThreadKey && effectivePlanModeOn(planThreadKey)) {
|
|
958
|
-
tools.push(...getPlanExitTools());
|
|
959
|
-
}
|
|
1073
|
+
todoThreadKey: planThreadKey ?? `native:${sessionId}`,
|
|
1074
|
+
planExitCtx: {
|
|
1075
|
+
threadKey: planThreadKey ?? `native:${sessionId}`,
|
|
1076
|
+
runId: sessionId,
|
|
1077
|
+
platform: opts.platform,
|
|
1078
|
+
channelId: opts.channelId,
|
|
1079
|
+
threadId: opts.threadId,
|
|
1080
|
+
userId: opts.userId,
|
|
1081
|
+
},
|
|
1082
|
+
advertisePlanExit: !!(planThreadKey && effectivePlanModeOn(planThreadKey)),
|
|
1083
|
+
imhubCtx,
|
|
1084
|
+
});
|
|
1085
|
+
const tools = assembled.tools;
|
|
1086
|
+
const dispatch = assembled.dispatch;
|
|
960
1087
|
const policy = resolvePolicy(planThreadKey);
|
|
961
1088
|
// v1.2.60 — when the policy would silently deny a tool call,
|
|
962
1089
|
// escalate to the user via an IM approval card instead. Only
|
|
@@ -989,7 +1116,12 @@ class NativeAgentAdapter {
|
|
|
989
1116
|
// Was previously resolved here — that was fine before native had
|
|
990
1117
|
// fs tools, but fs-dispatcher now needs the value at dispatch
|
|
991
1118
|
// build time.
|
|
992
|
-
|
|
1119
|
+
// ADR-0002 — prefer the inbound turn's trace id (plumbed via opts.traceId
|
|
1120
|
+
// from the router) so the native iteration / turn audit rows correlate
|
|
1121
|
+
// back to the originating IM message in SIEM joins. Fall back to a
|
|
1122
|
+
// self-minted id only for entry points that don't carry one (e.g. an A2A
|
|
1123
|
+
// in-process spawn or a direct CLI/smoke invocation).
|
|
1124
|
+
const traceId = opts.traceId || `native-${sessionId}-${Date.now()}`;
|
|
993
1125
|
// Wall-clock cap for the agent loop. agim's IM-layer enforces a 30-
|
|
994
1126
|
// minute hard ceiling per turn (DEFAULT_TIMEOUT_MS in agent-base.ts);
|
|
995
1127
|
// we set the inner loop a hair below so the loop's own abort fires
|
|
@@ -1064,11 +1196,12 @@ class NativeAgentAdapter {
|
|
|
1064
1196
|
traceId,
|
|
1065
1197
|
},
|
|
1066
1198
|
hooks: heartbeats.hooks,
|
|
1067
|
-
// v1.2.109 — declare read-only / pure tools parallel-safe so
|
|
1199
|
+
// v1.2.109 / T2 — declare read-only / pure tools parallel-safe so
|
|
1068
1200
|
// multi-call iterations (e.g. "read these 3 files") run
|
|
1069
|
-
// concurrently.
|
|
1070
|
-
//
|
|
1071
|
-
|
|
1201
|
+
// concurrently. Now a PER-CALL classifier owned by the tool
|
|
1202
|
+
// registry (fail-closed: unknown / throwing → serial), replacing
|
|
1203
|
+
// the static per-name set.
|
|
1204
|
+
parallelSafeClassifier: assembled.isParallelSafe,
|
|
1072
1205
|
// v1.2.112 — stream provider responses so partial assistant
|
|
1073
1206
|
// text survives the IM 30-min hard timeout. Env-gated kill
|
|
1074
1207
|
// switch (`IMHUB_NATIVE_STREAM_PARTIAL=off` + global
|
|
@@ -1222,6 +1355,24 @@ class NativeAgentAdapter {
|
|
|
1222
1355
|
else if (result.finishReason === 'aborted') {
|
|
1223
1356
|
body = '⏹ native agent aborted before completion.';
|
|
1224
1357
|
}
|
|
1358
|
+
else if (result.finishReason === 'hallucinated_tools') {
|
|
1359
|
+
// v1.2.147 — agent-loop detected the model narrated a tool
|
|
1360
|
+
// invocation ("我现在调用 native_write_file: ```python …```")
|
|
1361
|
+
// without actually emitting toolCalls. Surface a recap that
|
|
1362
|
+
// names the failure mode + suggests a backend switch, instead
|
|
1363
|
+
// of shipping the lie as a normal reply.
|
|
1364
|
+
log.warn({
|
|
1365
|
+
event: 'native.turn.hallucinated_tools',
|
|
1366
|
+
sessionId,
|
|
1367
|
+
backend: usedProvider.name,
|
|
1368
|
+
role: usedRole,
|
|
1369
|
+
iterations: result.iterations,
|
|
1370
|
+
toolCallCount: result.toolCalls.length,
|
|
1371
|
+
textLen: (result.text || '').length,
|
|
1372
|
+
elapsedMs: Date.now() - startedAt,
|
|
1373
|
+
}, `native turn ended with hallucinated tool-call narration (no real toolCalls emitted)`);
|
|
1374
|
+
body = composeHallucinatedToolRecap(result, usedProvider.name);
|
|
1375
|
+
}
|
|
1225
1376
|
else if (!body) {
|
|
1226
1377
|
// Normal `stop` finish but the model didn't write anything. Most
|
|
1227
1378
|
// often the model completed a tool chain and forgot to close
|