@qwen-code/qwen-code 0.19.9 → 0.19.10-nightly.20260716.506ce0a1a
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/bundled/qc-helper/docs/configuration/settings.md +14 -6
- package/bundled/qc-helper/docs/features/approval-mode.md +2 -2
- package/bundled/qc-helper/docs/features/channels/dingtalk.md +33 -0
- package/bundled/qc-helper/docs/features/channels/overview.md +64 -20
- package/bundled/qc-helper/docs/features/channels/wecom.md +8 -7
- package/bundled/qc-helper/docs/features/code-review.md +88 -44
- package/bundled/qc-helper/docs/features/commands.md +6 -6
- package/bundled/qc-helper/docs/features/hooks.md +29 -0
- package/bundled/qc-helper/docs/features/sandbox.md +2 -0
- package/bundled/qc-helper/docs/features/sub-agents.md +21 -0
- package/bundled/qc-helper/docs/qwen-serve.md +49 -20
- package/bundled/qc-helper/docs/reference/keyboard-shortcuts.md +1 -1
- package/bundled/review/DESIGN.md +219 -33
- package/bundled/review/SKILL.md +429 -382
- package/chunks/{MaxSizedBox-6HYJ3ZPJ.js → MaxSizedBox-WOC3YDWA.js} +31 -32
- package/chunks/{StandaloneSessionPicker-WS4GXYOG.js → StandaloneSessionPicker-H5HZCAFD.js} +49 -48
- package/chunks/{acpAgent-5FWSOZL5.js → acpAgent-55YDJDNM.js} +922 -550
- package/chunks/{agent-HOLHB3RT.js → agent-H6VE5W3L.js} +26 -27
- package/chunks/{agent-headless-SXL6H56A.js → agent-headless-T4XJOCRU.js} +26 -27
- package/chunks/{anthropicContentGenerator-L73TO3DB.js → anthropicContentGenerator-HBRXJSP4.js} +78 -16
- package/chunks/{artifact-tool-U7IRTLIV.js → artifact-tool-MIZLXBLF.js} +2 -2
- package/chunks/{askUserQuestion-2DLUUZZG.js → askUserQuestion-XMJVPNWM.js} +2 -2
- package/chunks/{bridge-BCJQ7BBB.js → bridge-FTB6ZP3R.js} +31 -34
- package/chunks/{ca-UJ6HC4H2.js → ca-CODEN7TD.js} +9 -1
- package/chunks/channel-worker-group-K7QKH6IG.js +13 -0
- package/chunks/channel-worker-manager-CUDPU4CN.js +418 -0
- package/chunks/channel-worker-supervisor-4XTO2ZD3.js +20 -0
- package/chunks/{chunk-LXNEJD34.js → chunk-2FO5GFKZ.js} +1 -1
- package/chunks/{chunk-VA4KQY6V.js → chunk-2JNR4VP2.js} +3 -3
- package/chunks/{chunk-L36P3NBD.js → chunk-2W3OOD4W.js} +2 -0
- package/chunks/{chunk-7R3CZA3Q.js → chunk-2Z5UX4KI.js} +1 -1
- package/chunks/{chunk-CUMMSHH6.js → chunk-3DWIFU7L.js} +1 -1
- package/chunks/chunk-3MX7D6QN.js +516 -0
- package/chunks/{chunk-SJHDYNHF.js → chunk-4BJVSIS3.js} +3 -3
- package/chunks/{chunk-TO6QE22P.js → chunk-5CNYZ7TN.js} +26 -22
- package/chunks/{chunk-N3EMS75V.js → chunk-5DEJ4T6C.js} +1333 -1232
- package/chunks/chunk-5HBA2Z7V.js +28 -0
- package/chunks/{chunk-ZJE7NSL3.js → chunk-5M6IDOMF.js} +34 -97
- package/chunks/{chunk-SCGXUJBT.js → chunk-6LI3L22E.js} +3 -3
- package/chunks/{chunk-K434OPES.js → chunk-6WPJRYLZ.js} +3 -3
- package/chunks/{chunk-YAUFFXDS.js → chunk-7GM2RWCR.js} +12 -11
- package/chunks/{chunk-OQ4DRIOA.js → chunk-7HWE2W74.js} +2 -2
- package/chunks/{chunk-J4TSQ5EQ.js → chunk-7NFB7LBQ.js} +8 -1
- package/chunks/{chunk-MC23XKFE.js → chunk-A2HWMJVO.js} +37 -3
- package/chunks/{chunk-3G7CIHVV.js → chunk-ABNYOMDG.js} +4 -4
- package/chunks/{chunk-3AHXV67U.js → chunk-AGZLXLBY.js} +1 -1
- package/chunks/{chunk-RDJSGHZE.js → chunk-ALGGS7UH.js} +1 -38
- package/chunks/{chunk-Q4YQW46J.js → chunk-AMRZVQUY.js} +43 -40
- package/chunks/{chunk-W3JHSWRP.js → chunk-AN6C2U46.js} +4 -4
- package/chunks/{chunk-GWHYEOV2.js → chunk-ARKANCNX.js} +2 -1
- package/chunks/{chunk-5SFOMFG4.js → chunk-AVEOWVOM.js} +36 -2
- package/chunks/{chunk-34MW4KTI.js → chunk-BA5JGE5F.js} +2 -2
- package/chunks/{chunk-5HOMWMCL.js → chunk-BSJAQUFD.js} +5492 -1336
- package/chunks/{chunk-L6P4KPHR.js → chunk-BWJKL5DB.js} +58 -38
- package/chunks/{chunk-PVZM22CK.js → chunk-C32JFRGV.js} +5 -5
- package/chunks/{chunk-AKIVHSJR.js → chunk-CZIHPO7L.js} +163 -782
- package/chunks/chunk-DL7RCO6V.js +493 -0
- package/chunks/{chunk-KKNMOEZH.js → chunk-E2UVIFI2.js} +185 -398
- package/chunks/{chunk-5VXNZWGF.js → chunk-ENUQSKEY.js} +1 -1
- package/chunks/{chunk-PDZ7MBDG.js → chunk-EWILX3BM.js} +27 -6
- package/chunks/{chunk-BMGVRZN4.js → chunk-EZWX232B.js} +1 -1
- package/chunks/{chunk-4GORAUCN.js → chunk-F333XEAU.js} +1 -1
- package/chunks/{chunk-YLV3XXFB.js → chunk-FBU7WRZI.js} +17 -1
- package/chunks/chunk-FEOZBUMT.js +77 -0
- package/chunks/{chunk-5U27BZ72.js → chunk-FKEGVMPX.js} +269 -83
- package/chunks/chunk-FNX3LGAK.js +34 -0
- package/chunks/{chunk-LK7KUE55.js → chunk-FSA7ERJ2.js} +1 -1
- package/chunks/{chunk-PODM4SZ4.js → chunk-G3BIBPI7.js} +5 -5
- package/chunks/{chunk-A3XKDTSH.js → chunk-GA65O2TB.js} +4 -4
- package/chunks/{chunk-3BTRNWWD.js → chunk-GOXKNSDZ.js} +1 -64
- package/chunks/{channel-worker-supervisor-WSOAAYUO.js → chunk-GXGIM7QP.js} +67 -35
- package/chunks/{chunk-6PESIEKJ.js → chunk-GXUWGPYX.js} +68 -6
- package/chunks/chunk-GYTKQYDB.js +23 -0
- package/chunks/{chunk-GZRTYZ2R.js → chunk-H3XMJV7T.js} +218 -1
- package/chunks/{chunk-WQUQVGTF.js → chunk-HGRXW4HQ.js} +467 -106
- package/chunks/{chunk-YVEDCAUE.js → chunk-HGT6JR3U.js} +19 -0
- package/chunks/{chunk-ECNYL4AA.js → chunk-HUEWOHKV.js} +1 -1
- package/chunks/chunk-IDS7MSUP.js +74 -0
- package/chunks/{chunk-KHUQZZJ6.js → chunk-IHDRJLLR.js} +382 -36
- package/chunks/{chunk-CLFKOZEK.js → chunk-J4SEAF4X.js} +114 -4
- package/chunks/{chunk-B5ORX3FG.js → chunk-JGUT3LWZ.js} +6 -1
- package/chunks/{chunk-P67PFTUT.js → chunk-KEYEYCHZ.js} +4 -4
- package/chunks/{chunk-ORBGV7NJ.js → chunk-KKRTYONM.js} +6 -4
- package/chunks/{chunk-7PU4FYLG.js → chunk-KOXFAG6P.js} +4 -18
- package/chunks/{chunk-EGYZ275M.js → chunk-KWLVWNF5.js} +55 -7
- package/chunks/{chunk-XLA62MYB.js → chunk-KXECVZPD.js} +2 -2
- package/chunks/{chunk-IAVB3HM3.js → chunk-L4Y55KIS.js} +33 -1
- package/chunks/{chunk-4QLQE5WJ.js → chunk-L5U3ELZX.js} +1 -1
- package/chunks/{chunk-4ZVWQHEQ.js → chunk-LQIDP6K5.js} +1 -1
- package/chunks/{chunk-DC5Z3DU6.js → chunk-LXLTBIDP.js} +43 -6
- package/chunks/chunk-LXXMOYPL.js +22 -0
- package/chunks/{chunk-Q6I5QHMH.js → chunk-MFNKBXYH.js} +1 -1
- package/chunks/chunk-MR3PXB6E.js +48 -0
- package/chunks/{chunk-JZETEN3Z.js → chunk-N45S36AH.js} +3 -3
- package/chunks/{chunk-GWLSNBG4.js → chunk-NA3IG6XG.js} +748 -27
- package/chunks/{chunk-D5SKC4YG.js → chunk-O3M25JXE.js} +213 -29
- package/chunks/{chunk-EAXLGSFP.js → chunk-O6XGHDS5.js} +11 -11
- package/chunks/{chunk-WL4L7EZH.js → chunk-OA4JVLSA.js} +27 -1
- package/chunks/{chunk-X4NKFGFJ.js → chunk-OJAMDVF5.js} +0 -15
- package/chunks/{chunk-BZIFY5TF.js → chunk-OKAIGAYW.js} +3 -3
- package/chunks/{chunk-CNEIYWSA.js → chunk-OVIV236K.js} +5 -5
- package/chunks/{chunk-3SJSQXNS.js → chunk-PEJWA3QQ.js} +12 -8
- package/chunks/{chunk-E2IY465S.js → chunk-PWNOAWXB.js} +59 -12
- package/chunks/{chunk-B4G2WOFA.js → chunk-Q5MKHNIR.js} +28 -5
- package/chunks/{chunk-MXL5UP4X.js → chunk-Q6TUALBE.js} +1 -1
- package/chunks/{chunk-QYMQSECS.js → chunk-QAW7PIHT.js} +2 -2
- package/chunks/{chunk-HKMAENAO.js → chunk-QDTGDM2T.js} +14 -9
- package/chunks/{chunk-LUODI7WD.js → chunk-RCEEXIOO.js} +6 -4
- package/chunks/{chunk-W2UIXQDL.js → chunk-RTV5TUYB.js} +12 -4
- package/chunks/chunk-RW7DUKFO.js +91 -0
- package/chunks/{chunk-NVYTCB5Z.js → chunk-SA6QVLWI.js} +17325 -16259
- package/chunks/chunk-SJSI7PXU.js +59 -0
- package/chunks/{chunk-HVY356M2.js → chunk-SMGBWLNU.js} +3 -3
- package/chunks/{chunk-CEA3E3JB.js → chunk-SPJQO2CE.js} +2 -2
- package/chunks/{chunk-CC2ITGCF.js → chunk-STZQCNN3.js} +49 -6
- package/chunks/{chunk-HPDUL5MF.js → chunk-T2ZDAER2.js} +1 -1
- package/chunks/{chunk-XUOOWUZS.js → chunk-T3TQ3ACP.js} +1 -1
- package/chunks/{chunk-4C5BQ2D2.js → chunk-TIKDHS6V.js} +100 -17
- package/chunks/chunk-TV6K2FB4.js +224 -0
- package/chunks/{chunk-5XUCZNSY.js → chunk-TYLOFD2U.js} +1 -1
- package/chunks/{chunk-D2GFWEXB.js → chunk-UCUUH2JV.js} +6 -6
- package/chunks/{chunk-BAPGSC7U.js → chunk-UZP7K33Y.js} +23 -9
- package/chunks/{chunk-77XJ3SWN.js → chunk-VDAR6UO2.js} +8 -6
- package/chunks/{chunk-XYQSMABS.js → chunk-VKLVGA2D.js} +4 -4
- package/chunks/{chunk-JSG7ZSBC.js → chunk-VRR65QYW.js} +251 -3
- package/chunks/{chunk-U2NNEY4R.js → chunk-VT5AWJN4.js} +1 -1
- package/chunks/{chunk-ZLXQN2QS.js → chunk-WIEO4CWB.js} +1 -1
- package/chunks/{chunk-X6TJ3YZV.js → chunk-WKEO3GLZ.js} +160 -60
- package/chunks/{chunk-J3JA76CF.js → chunk-WTNZ6DXB.js} +1 -1
- package/chunks/{chunk-VWPVHAMO.js → chunk-XIWQ5QST.js} +8 -1
- package/chunks/{chunk-TDEXZKMT.js → chunk-Y66VOBRP.js} +2 -2
- package/chunks/{chunk-3VAGG5T5.js → chunk-YYBZUIPL.js} +1015 -100
- package/chunks/{chunk-CCDMCZPP.js → chunk-YZ3SBNP7.js} +1 -1
- package/chunks/{chunk-ATAKVRIF.js → chunk-Z3XA2TNG.js} +7 -7
- package/chunks/{chunk-EMDMPBJ4.js → chunk-Z7SVC7PJ.js} +10 -3
- package/chunks/{chunk-AURZZYMD.js → chunk-ZIVSSTUG.js} +4 -4
- package/chunks/{chunk-UOZWKTQG.js → chunk-ZPAHLFZU.js} +2 -2
- package/chunks/{chunk-34Z3U5RQ.js → chunk-ZQIYGQCG.js} +765 -168
- package/chunks/{computer-use-HM37RX6A.js → computer-use-NADT7ULB.js} +26 -27
- package/chunks/{config-utils-NV2SVGPB.js → config-utils-IQQT3GCI.js} +3 -2
- package/chunks/{contextCommand-OF5SFGH2.js → contextCommand-U7NEJYJ7.js} +28 -29
- package/chunks/{create-sub-session-INX7TXJI.js → create-sub-session-EAB2U5XW.js} +2 -2
- package/chunks/{create-sub-session-KPRT7ECJ.js → create-sub-session-SUN33INC.js} +26 -27
- package/chunks/{cron-create-AMBKGZX6.js → cron-create-GMVKSXZT.js} +4 -4
- package/chunks/{cron-delete-LRU4OJYG.js → cron-delete-VDZKUAVK.js} +4 -4
- package/chunks/{cron-list-WVP2JXER.js → cron-list-UG7C7RAR.js} +4 -4
- package/chunks/{daemon-ARHTSTXP.js → daemon-SJXEKP3H.js} +773 -126
- package/chunks/daemon-status-provider-WIIYLGZJ.js +74 -0
- package/chunks/{de-EBJN3OVN.js → de-NOXPCSYN.js} +9 -1
- package/chunks/{dist-XKU3ABM5.js → dist-4WCQEZIN.js} +4 -51
- package/chunks/{dist-QYCAEZIT.js → dist-DOPL5LSQ.js} +5 -1
- package/chunks/{dist-WKPOYU7O.js → dist-GXJVCOS7.js} +1 -1
- package/chunks/{dist-R7LN5AZE.js → dist-PX2ERZ6I.js} +2 -2
- package/chunks/{dist-PNVLTKTL.js → dist-V2YVLYOW.js} +215 -33
- package/chunks/{dist-VHV4EVHG.js → dist-VYWUKURL.js} +1 -1
- package/chunks/{earlyInputCapture-3VTHRC4C.js → earlyInputCapture-6FRM6UMU.js} +27 -28
- package/chunks/{edit-VNI4NJ73.js → edit-7GOIQTCZ.js} +27 -28
- package/chunks/{en-5A6LA7RK.js → en-JFVULHTB.js} +11 -1
- package/chunks/{enter-worktree-IYYBKPZT.js → enter-worktree-476E6WIK.js} +26 -27
- package/chunks/{enterPlanMode-GMC5FD5A.js → enterPlanMode-IRJM6W3C.js} +42 -28
- package/chunks/{environment-5HSSRMJ7.js → environment-ROMULS2X.js} +30 -30
- package/chunks/{errors-HMFCJJ7P.js → errors-OUIWPUDY.js} +28 -29
- package/chunks/{exit-worktree-6BHCMP5G.js → exit-worktree-PPSFK753.js} +26 -27
- package/chunks/{exitPlanMode-CJW7G74W.js → exitPlanMode-YKQMD4D7.js} +26 -27
- package/chunks/{fast-path-FRDMDVHG.js → fast-path-CNK2HHKH.js} +3 -3
- package/chunks/{fast-path-settings-5QZE64HR.js → fast-path-settings-DAOVFADC.js} +6 -4
- package/chunks/{fr-YXRABLYZ.js → fr-HVFNU42H.js} +9 -1
- package/chunks/{gemini-QYSEGHAX.js → gemini-WQNFT6TR.js} +216 -90
- package/chunks/{geminiContentGenerator-J7YNZDYP.js → geminiContentGenerator-4QJH2JDP.js} +4 -4
- package/chunks/{glob-BRCSGFOT.js → glob-36TVLBWW.js} +28 -28
- package/chunks/{grep-EE2DUOSY.js → grep-QTYLNO2M.js} +26 -27
- package/chunks/{handleAutoUpdate-5NWTLR67.js → handleAutoUpdate-36FQFODK.js} +30 -31
- package/chunks/{i18n-BASPENNQ.js → i18n-JUGYPVSP.js} +27 -28
- package/chunks/initializer-OBBJUS25.js +72 -0
- package/chunks/{installationInfo-W6V4DT7W.js → installationInfo-MCKTPX64.js} +27 -28
- package/chunks/{ja-7VQOANVG.js → ja-PY5AF544.js} +10 -2
- package/chunks/{keychain-token-storage-VKUBNCP4.js → keychain-token-storage-AU22CQI6.js} +2 -2
- package/chunks/list-VW5QY4VJ.js +75 -0
- package/chunks/loadedSettingsAdapter-IELOOXG6.js +69 -0
- package/chunks/{loop-wakeup-WX7BLWWP.js → loop-wakeup-QXWZSCYM.js} +5 -5
- package/chunks/{ls-ZB2BDP6T.js → ls-2OUTG3IZ.js} +4 -4
- package/chunks/{lsp-V5DN4YUJ.js → lsp-4VMNXZW6.js} +2 -2
- package/chunks/mcp-Q3EC37ZS.js +69 -0
- package/chunks/{monitor-X5Z3H4FY.js → monitor-DCZ27AFR.js} +26 -27
- package/chunks/nonInteractiveCli-KXD7PFO4.js +128 -0
- package/chunks/{notebook-edit-TRM2QIJK.js → notebook-edit-YU4XF5LI.js} +27 -28
- package/chunks/{openaiContentGenerator-AAYONPMF.js → openaiContentGenerator-KL5WER2D.js} +13 -13
- package/chunks/{pidfile-D4I4FTVA.js → pidfile-WBOD7EJV.js} +27 -28
- package/chunks/processUtils-AOV4R34M.js +29 -0
- package/chunks/{pt-2C6YCSHL.js → pt-A3PRQXMU.js} +9 -1
- package/chunks/{qwenContentGenerator-K3HZ2H76.js → qwenContentGenerator-YIGBHYE3.js} +28 -29
- package/chunks/{qwenOAuth2-PJQ27GSO.js → qwenOAuth2-LEYOU7RU.js} +5 -5
- package/chunks/{read-file-7SZSIZOL.js → read-file-WVL4Y76X.js} +9 -9
- package/chunks/{read-mcp-resource-SM5DA4RG.js → read-mcp-resource-JUFHCKSC.js} +2 -2
- package/chunks/{record-artifact-4XKZX3UW.js → record-artifact-DWSMBXYY.js} +2 -2
- package/chunks/{ripGrep-YNPFVCZP.js → ripGrep-6GSWJERP.js} +26 -27
- package/chunks/{ru-6BBHVZZV.js → ru-IBCWUTOC.js} +9 -1
- package/chunks/{run-qwen-serve-DMWV5N6L.js → run-qwen-serve-QYUQMEDT.js} +1233 -371
- package/chunks/{runtime-57WWRVHN.js → runtime-K2YZCNB3.js} +42 -38
- package/chunks/{scheduler-YBLGWSIL.js → scheduler-EQCSN7QV.js} +26 -27
- package/chunks/{send-message-F36YD6KQ.js → send-message-JZ752NWD.js} +3 -3
- package/chunks/{serve-R63NK3CV.js → serve-DX5UGZD4.js} +36 -35
- package/chunks/{server-Z22GCAXP.js → server-T6HJH3DR.js} +5869 -1398
- package/chunks/{session-HKAAI7BN.js → session-SNU6ACY6.js} +299 -100
- package/chunks/{settings-3EYN66GK.js → settings-AKHZZNEL.js} +34 -33
- package/chunks/{shell-6YXINTWJ.js → shell-EY74IEZK.js} +28 -27
- package/chunks/{skill-OO57P4X6.js → skill-DPU62O3H.js} +11 -11
- package/chunks/{spawnChannel-JD7G4VU6.js → spawnChannel-RQZRWJ2V.js} +28 -30
- package/chunks/{src-G5UPLZSZ.js → src-7FITDSVC.js} +164 -52
- package/chunks/{standalone-update-OB7F4JPZ.js → standalone-update-XO3RK6DO.js} +28 -29
- package/chunks/{startInteractiveUI-73EGLIIH.js → startInteractiveUI-DVWZRHYQ.js} +728 -382
- package/chunks/{syntheticOutput-34H7LGA7.js → syntheticOutput-LELY6HAI.js} +3 -3
- package/chunks/{task-create-FRGOEIKY.js → task-create-QY3BIMNM.js} +8 -7
- package/chunks/{task-list-OW766BXZ.js → task-list-D2U47WBJ.js} +6 -5
- package/chunks/{task-stop-SIR5SNBN.js → task-stop-N6E5IYLH.js} +2 -2
- package/chunks/{task-update-YRA532MT.js → task-update-HJCQILLB.js} +8 -7
- package/chunks/{team-create-PECAAPXK.js → team-create-FOSRT62K.js} +26 -27
- package/chunks/{team-delete-6OSECUZC.js → team-delete-RCWYDRF4.js} +6 -5
- package/chunks/{team-plan-approval-L6F434RY.js → team-plan-approval-6VUDV27J.js} +26 -27
- package/chunks/{theme-manager-ZG4RY6GU.js → theme-manager-6UT6IO5T.js} +27 -28
- package/chunks/{todoWrite-YDMFEV4G.js → todoWrite-FKCGATPJ.js} +4 -4
- package/chunks/{tool-search-THVIWAPB.js → tool-search-ASSFMMN5.js} +10 -10
- package/chunks/{total-session-admission-JOKNRIIA.js → total-session-admission-YYWUO23H.js} +32 -35
- package/chunks/tree-sitter-YJVE2ZUK.js +2980 -0
- package/chunks/{trustedFolders-EOGT3UVS.js → trustedFolders-4BWV2IBK.js} +29 -29
- package/chunks/types-ML3TRJQ5.js +16 -0
- package/chunks/update-relaunch-74DLGH73.js +87 -0
- package/chunks/{updateCheck-2KYEYVSB.js → updateCheck-CRFCGFO5.js} +31 -30
- package/chunks/{validateNonInterActiveAuth-EN6ZQSR2.js → validateNonInterActiveAuth-BTTEPBGQ.js} +76 -73
- package/chunks/{version-3UEA6ZIR.js → version-Y5JE5Q63.js} +1 -1
- package/chunks/{web-fetch-PAAEQKBW.js → web-fetch-CFCWTCAP.js} +5 -6
- package/chunks/{workflow-QCCCMYP3.js → workflow-6WC7VPQN.js} +27 -28
- package/chunks/workspace-providers-status-RVG2C5ZS.js +72 -0
- package/chunks/workspace-registration-store-SLEU3D3X.js +27 -0
- package/chunks/{workspace-registry-24QFLQYH.js → workspace-registry-QMWGVOTF.js} +32 -35
- package/chunks/workspace-service-G572JSEU.js +84 -0
- package/chunks/workspace-skills-status-VSSMSMNK.js +71 -0
- package/chunks/{write-file-I3MUDRIE.js → write-file-5XVDRORP.js} +27 -28
- package/chunks/{zh-RQE7I22T.js → zh-PAUNIMHQ.js} +12 -2
- package/chunks/{zh-TW-TBPQGHKH.js → zh-TW-GNEUIUFF.js} +12 -2
- package/cli-entry.js +92 -8
- package/cli.js +11 -11
- package/locales/ca.js +16 -0
- package/locales/de.js +16 -0
- package/locales/en.js +19 -0
- package/locales/fr.js +16 -0
- package/locales/ja.js +17 -1
- package/locales/pt.js +16 -0
- package/locales/ru.js +16 -0
- package/locales/zh-TW.js +20 -1
- package/locales/zh.js +20 -1
- package/package.json +3 -3
- package/web-shell/assets/{arc-C15hqnJe.js → arc-vx1tRwnX.js} +1 -1
- package/web-shell/assets/{architectureDiagram-3BPJPVTR-B-At37J_.js → architectureDiagram-3BPJPVTR-DBi6iUA1.js} +1 -1
- package/web-shell/assets/{blockDiagram-GPEHLZMM-B51wjcU7.js → blockDiagram-GPEHLZMM-Ga9JJ4Ak.js} +1 -1
- package/web-shell/assets/{c4Diagram-AAUBKEIU-xBK7BAwN.js → c4Diagram-AAUBKEIU-D8Vi5FYw.js} +1 -1
- package/web-shell/assets/channel-B29zQDTL.js +1 -0
- package/web-shell/assets/{chunk-2J33WTMH-xKmLg7Yr.js → chunk-2J33WTMH-CSV6yQpU.js} +1 -1
- package/web-shell/assets/{chunk-4BX2VUAB-BfkdKZCM.js → chunk-4BX2VUAB-toYlppdI.js} +1 -1
- package/web-shell/assets/{chunk-55IACEB6-DT713sZf.js → chunk-55IACEB6-DbjzuyAr.js} +1 -1
- package/web-shell/assets/{chunk-727SXJPM-CYEeAamv.js → chunk-727SXJPM-IkkSjSkk.js} +1 -1
- package/web-shell/assets/{chunk-AQP2D5EJ-DBN-5CFd.js → chunk-AQP2D5EJ-D5wUL6Zm.js} +1 -1
- package/web-shell/assets/{chunk-FMBD7UC4-CGZKk4PH.js → chunk-FMBD7UC4-C3o2DXG0.js} +1 -1
- package/web-shell/assets/{chunk-ND2GUHAM-qQbC2O-y.js → chunk-ND2GUHAM-CutIi14T.js} +1 -1
- package/web-shell/assets/{chunk-QZHKN3VN-B3zeXwsX.js → chunk-QZHKN3VN-DZ0NRHH-.js} +1 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-BNGI2SvC.js +1 -0
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-BNGI2SvC.js +1 -0
- package/web-shell/assets/{cose-bilkent-S5V4N54A-BKsl1Wvy.js → cose-bilkent-S5V4N54A-B3Dl88UJ.js} +1 -1
- package/web-shell/assets/{dagre-BM42HDAG-CuuuLiBK.js → dagre-BM42HDAG-DfTxfF6-.js} +1 -1
- package/web-shell/assets/{diagram-2AECGRRQ-CG4_eKiV.js → diagram-2AECGRRQ-CJyH98yO.js} +1 -1
- package/web-shell/assets/{diagram-5GNKFQAL-DSFTmZB1.js → diagram-5GNKFQAL-EbOiJNmW.js} +1 -1
- package/web-shell/assets/{diagram-KO2AKTUF-BxwlEHn8.js → diagram-KO2AKTUF-AYNqpqqA.js} +1 -1
- package/web-shell/assets/{diagram-LMA3HP47-BUAg-jMG.js → diagram-LMA3HP47-BY5VPa4H.js} +1 -1
- package/web-shell/assets/{diagram-OG6HWLK6-BFM2jlO5.js → diagram-OG6HWLK6-BhMYAKlk.js} +1 -1
- package/web-shell/assets/{erDiagram-TEJ5UH35-CerbFPa2.js → erDiagram-TEJ5UH35-Bp8S_F9l.js} +1 -1
- package/web-shell/assets/{flowDiagram-I6XJVG4X-BNeZz5Zz.js → flowDiagram-I6XJVG4X-az3TE9PU.js} +1 -1
- package/web-shell/assets/{ganttDiagram-6RSMTGT7-CTOogLaM.js → ganttDiagram-6RSMTGT7-CfkAEpCe.js} +3 -3
- package/web-shell/assets/{gitGraphDiagram-PVQCEYII-yxSFkXPj.js → gitGraphDiagram-PVQCEYII-D1QmjMCy.js} +1 -1
- package/web-shell/assets/index-C8sDwQUv.js +1130 -0
- package/web-shell/assets/index-CaBoc5bb.js +3 -0
- package/web-shell/assets/index-Dpg5Wymg.css +5 -0
- package/web-shell/assets/{infoDiagram-5YYISTIA-DYdAUevm.js → infoDiagram-5YYISTIA-D3ompLrG.js} +1 -1
- package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-CNuijZ90.js → ishikawaDiagram-YF4QCWOH-D3MRWp9I.js} +1 -1
- package/web-shell/assets/{journeyDiagram-JHISSGLW-BTyiuonf.js → journeyDiagram-JHISSGLW-DVkKCa44.js} +1 -1
- package/web-shell/assets/{kanban-definition-UN3LZRKU-DPJo0Uow.js → kanban-definition-UN3LZRKU-BLif81wF.js} +1 -1
- package/web-shell/assets/{linear-C8wKCbIC.js → linear-BDU96EGS.js} +1 -1
- package/web-shell/assets/{mermaid.core-BV5o7nW5.js → mermaid.core-B-CwC26B.js} +5 -5
- package/web-shell/assets/{mindmap-definition-RKZ34NQL-BtLcBmSt.js → mindmap-definition-RKZ34NQL-CS1WOJ4G.js} +1 -1
- package/web-shell/assets/{pieDiagram-4H26LBE5-C22J7A9Q.js → pieDiagram-4H26LBE5-BzgtNXVP.js} +1 -1
- package/web-shell/assets/{quadrantDiagram-W4KKPZXB-DSL10wiL.js → quadrantDiagram-W4KKPZXB-BRfGC8MA.js} +1 -1
- package/web-shell/assets/{requirementDiagram-4Y6WPE33-feqh0UpX.js → requirementDiagram-4Y6WPE33-CPBZkC7g.js} +1 -1
- package/web-shell/assets/{sankeyDiagram-5OEKKPKP-Z4OVaWaZ.js → sankeyDiagram-5OEKKPKP-nqNvinIk.js} +1 -1
- package/web-shell/assets/{sequenceDiagram-3UESZ5HK-DIluIcb1.js → sequenceDiagram-3UESZ5HK-CM_Wdjh3.js} +1 -1
- package/web-shell/assets/{stateDiagram-AJRCARHV-hlhnuoYH.js → stateDiagram-AJRCARHV-L0y-48VE.js} +1 -1
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-BX1DdF8s.js +1 -0
- package/web-shell/assets/{timeline-definition-PNZ67QCA-Dqf_CqgL.js → timeline-definition-PNZ67QCA-B_n5rb3A.js} +1 -1
- package/web-shell/assets/{vennDiagram-CIIHVFJN-DD2QhaTX.js → vennDiagram-CIIHVFJN-C9NmLV5e.js} +1 -1
- package/web-shell/assets/{wardley-L42UT6IY-B2uI85U_.js → wardley-L42UT6IY-CrefK9gt.js} +1 -1
- package/web-shell/assets/{wardleyDiagram-YWT4CUSO-U1aJX71g.js → wardleyDiagram-YWT4CUSO-BUccf-bC.js} +1 -1
- package/web-shell/assets/{xychartDiagram-2RQKCTM6-C0ODHUee.js → xychartDiagram-2RQKCTM6-DM6ef92l.js} +1 -1
- package/web-shell/index.html +2 -2
- package/chunks/chunk-524RQP4Q.js +0 -305
- package/chunks/chunk-CARU2RR2.js +0 -24
- package/chunks/chunk-CU3L64TP.js +0 -93
- package/chunks/chunk-OCPBI7J5.js +0 -18
- package/chunks/chunk-TEGEBB2I.js +0 -122
- package/chunks/chunk-VTU57BWZ.js +0 -30
- package/chunks/daemon-status-provider-B2UTZUJ2.js +0 -76
- package/chunks/initializer-UTQ7FB7G.js +0 -71
- package/chunks/list-DEICDL65.js +0 -74
- package/chunks/loadedSettingsAdapter-NOWEGDYJ.js +0 -68
- package/chunks/mcp-L5JXEEIA.js +0 -68
- package/chunks/nonInteractiveCli-LS2K4X6A.js +0 -124
- package/chunks/types-JNKGKUJT.js +0 -12
- package/chunks/workspace-providers-status-4KMGETOJ.js +0 -71
- package/chunks/workspace-service-RVLBMSMZ.js +0 -80
- package/chunks/workspace-skills-status-DS4ZVFTO.js +0 -70
- package/web-shell/assets/channel-CLiQD50f.js +0 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-D3sYqow5.js +0 -1
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-D3sYqow5.js +0 -1
- package/web-shell/assets/index-D5IWFVk1.css +0 -5
- package/web-shell/assets/index-KFJRDhX7.js +0 -783
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-BhQMwgpl.js +0 -1
|
@@ -12,32 +12,6 @@ import {
|
|
|
12
12
|
__name
|
|
13
13
|
} from "./chunk-J2S4EL5Y.js";
|
|
14
14
|
|
|
15
|
-
// packages/channels/base/dist/paths.js
|
|
16
|
-
init_esbuild_shims();
|
|
17
|
-
import * as path from "node:path";
|
|
18
|
-
import * as os from "node:os";
|
|
19
|
-
function resolvePath(dir) {
|
|
20
|
-
let resolved = dir;
|
|
21
|
-
if (resolved === "~" || resolved.startsWith("~/") || resolved.startsWith("~\\")) {
|
|
22
|
-
const relativeSegments = resolved === "~" ? [] : resolved.slice(2).split(/[/\\]+/).filter(Boolean);
|
|
23
|
-
resolved = path.join(os.homedir(), ...relativeSegments);
|
|
24
|
-
}
|
|
25
|
-
if (!path.isAbsolute(resolved)) {
|
|
26
|
-
resolved = path.resolve(resolved);
|
|
27
|
-
}
|
|
28
|
-
return resolved;
|
|
29
|
-
}
|
|
30
|
-
__name(resolvePath, "resolvePath");
|
|
31
|
-
function getGlobalQwenDir() {
|
|
32
|
-
const envDir = process.env["QWEN_HOME"];
|
|
33
|
-
if (envDir) {
|
|
34
|
-
return resolvePath(envDir);
|
|
35
|
-
}
|
|
36
|
-
const homeDir = os.homedir();
|
|
37
|
-
return homeDir ? path.join(homeDir, ".qwen") : path.join(os.tmpdir(), ".qwen");
|
|
38
|
-
}
|
|
39
|
-
__name(getGlobalQwenDir, "getGlobalQwenDir");
|
|
40
|
-
|
|
41
15
|
// packages/channels/base/dist/sanitize.js
|
|
42
16
|
init_esbuild_shims();
|
|
43
17
|
var PROMPT_UNSAFE_INVISIBLES = new RegExp("[\\u0080-\\u009f\\p{Cf}\\u2028\\u2029]|\\p{Variation_Selector}", "gu");
|
|
@@ -74,6 +48,32 @@ __name(sanitizeLogText, "sanitizeLogText");
|
|
|
74
48
|
// packages/channels/base/dist/index.js
|
|
75
49
|
init_esbuild_shims();
|
|
76
50
|
|
|
51
|
+
// packages/channels/base/dist/paths.js
|
|
52
|
+
init_esbuild_shims();
|
|
53
|
+
import * as path from "node:path";
|
|
54
|
+
import * as os from "node:os";
|
|
55
|
+
function resolvePath(dir) {
|
|
56
|
+
let resolved = dir;
|
|
57
|
+
if (resolved === "~" || resolved.startsWith("~/") || resolved.startsWith("~\\")) {
|
|
58
|
+
const relativeSegments = resolved === "~" ? [] : resolved.slice(2).split(/[/\\]+/).filter(Boolean);
|
|
59
|
+
resolved = path.join(os.homedir(), ...relativeSegments);
|
|
60
|
+
}
|
|
61
|
+
if (!path.isAbsolute(resolved)) {
|
|
62
|
+
resolved = path.resolve(resolved);
|
|
63
|
+
}
|
|
64
|
+
return resolved;
|
|
65
|
+
}
|
|
66
|
+
__name(resolvePath, "resolvePath");
|
|
67
|
+
function getGlobalQwenDir() {
|
|
68
|
+
const envDir = process.env["QWEN_HOME"];
|
|
69
|
+
if (envDir) {
|
|
70
|
+
return resolvePath(envDir);
|
|
71
|
+
}
|
|
72
|
+
const homeDir = os.homedir();
|
|
73
|
+
return homeDir ? path.join(homeDir, ".qwen") : path.join(os.tmpdir(), ".qwen");
|
|
74
|
+
}
|
|
75
|
+
__name(getGlobalQwenDir, "getGlobalQwenDir");
|
|
76
|
+
|
|
77
77
|
// packages/channels/base/dist/AcpBridge.js
|
|
78
78
|
init_esbuild_shims();
|
|
79
79
|
import { spawn } from "node:child_process";
|
|
@@ -361,15 +361,23 @@ var AcpBridge = class extends EventEmitter {
|
|
|
361
361
|
async prompt(sessionId, text, options) {
|
|
362
362
|
const conn = this.ensureConnection();
|
|
363
363
|
const chunks = [];
|
|
364
|
+
let slashCommandOutput = "";
|
|
364
365
|
const onChunk = /* @__PURE__ */ __name((sid, chunk) => {
|
|
365
366
|
if (sid === sessionId)
|
|
366
367
|
chunks.push(chunk);
|
|
367
368
|
}, "onChunk");
|
|
368
|
-
const
|
|
369
|
+
const onSlashCommandOutput = /* @__PURE__ */ __name((sid, chunk) => {
|
|
369
370
|
if (sid === sessionId)
|
|
371
|
+
slashCommandOutput = chunk;
|
|
372
|
+
}, "onSlashCommandOutput");
|
|
373
|
+
const clearChunks = /* @__PURE__ */ __name((sid) => {
|
|
374
|
+
if (sid === sessionId) {
|
|
370
375
|
chunks.length = 0;
|
|
376
|
+
slashCommandOutput = "";
|
|
377
|
+
}
|
|
371
378
|
}, "clearChunks");
|
|
372
379
|
this.on("textChunk", onChunk);
|
|
380
|
+
this.on("slashCommandOutput", onSlashCommandOutput);
|
|
373
381
|
this.on("responseBoundary", clearChunks);
|
|
374
382
|
const prompt = [];
|
|
375
383
|
if (options?.imageBase64 && options.imageMimeType) {
|
|
@@ -387,9 +395,10 @@ var AcpBridge = class extends EventEmitter {
|
|
|
387
395
|
});
|
|
388
396
|
} finally {
|
|
389
397
|
this.off("textChunk", onChunk);
|
|
398
|
+
this.off("slashCommandOutput", onSlashCommandOutput);
|
|
390
399
|
this.off("responseBoundary", clearChunks);
|
|
391
400
|
}
|
|
392
|
-
return chunks.join("");
|
|
401
|
+
return chunks.join("") || slashCommandOutput;
|
|
393
402
|
}
|
|
394
403
|
async cancelSession(sessionId) {
|
|
395
404
|
const conn = this.ensureConnection();
|
|
@@ -432,9 +441,13 @@ var AcpBridge = class extends EventEmitter {
|
|
|
432
441
|
const type = update["sessionUpdate"];
|
|
433
442
|
switch (type) {
|
|
434
443
|
case "agent_message_chunk": {
|
|
444
|
+
const meta = update["_meta"];
|
|
445
|
+
if (typeof meta?.["parentToolCallId"] === "string") {
|
|
446
|
+
break;
|
|
447
|
+
}
|
|
435
448
|
const content = update["content"];
|
|
436
449
|
if (content?.type === "text" && content.text) {
|
|
437
|
-
this.emit("textChunk", sessionId, content.text);
|
|
450
|
+
this.emit(meta?.["source"] === "slash_command" ? "slashCommandOutput" : "textChunk", sessionId, content.text);
|
|
438
451
|
}
|
|
439
452
|
break;
|
|
440
453
|
}
|
|
@@ -707,6 +720,7 @@ var DaemonChannelBridge = class extends EventEmitter2 {
|
|
|
707
720
|
}
|
|
708
721
|
options;
|
|
709
722
|
sessions = /* @__PURE__ */ new Map();
|
|
723
|
+
sessionBindingTokens = /* @__PURE__ */ new Map();
|
|
710
724
|
eventControllers = /* @__PURE__ */ new Map();
|
|
711
725
|
requestToSession = /* @__PURE__ */ new Map();
|
|
712
726
|
respondedRequestToSession = /* @__PURE__ */ new Map();
|
|
@@ -715,6 +729,7 @@ var DaemonChannelBridge = class extends EventEmitter2 {
|
|
|
715
729
|
availableCommandsBySession = /* @__PURE__ */ new Map();
|
|
716
730
|
turnBarriers = /* @__PURE__ */ new Map();
|
|
717
731
|
connected = false;
|
|
732
|
+
lifecycleGeneration = 0;
|
|
718
733
|
latestAvailableCommandsSessionId;
|
|
719
734
|
lastError;
|
|
720
735
|
constructor(options) {
|
|
@@ -750,17 +765,22 @@ var DaemonChannelBridge = class extends EventEmitter2 {
|
|
|
750
765
|
async start() {
|
|
751
766
|
this.connected = true;
|
|
752
767
|
}
|
|
753
|
-
async newSession(cwd, options) {
|
|
768
|
+
async newSession(cwd, options, bindingToken) {
|
|
769
|
+
const lifecycleGeneration = this.lifecycleGeneration;
|
|
754
770
|
const session = await this.options.sessionFactory({
|
|
755
771
|
workspaceCwd: cwd || this.options.cwd,
|
|
756
772
|
modelServiceId: this.options.modelServiceId,
|
|
757
773
|
sessionScope: this.options.sessionScope ?? "thread",
|
|
758
774
|
...options?.approvalMode ? { approvalMode: options.approvalMode } : {}
|
|
759
775
|
});
|
|
760
|
-
this.
|
|
776
|
+
if (lifecycleGeneration !== this.lifecycleGeneration) {
|
|
777
|
+
await this.rejectStaleSession(session);
|
|
778
|
+
}
|
|
779
|
+
this.attachSession(session, bindingToken);
|
|
761
780
|
return session.sessionId;
|
|
762
781
|
}
|
|
763
|
-
async loadSession(sessionId, cwd, options) {
|
|
782
|
+
async loadSession(sessionId, cwd, options, bindingToken) {
|
|
783
|
+
const lifecycleGeneration = this.lifecycleGeneration;
|
|
764
784
|
const session = await this.options.sessionFactory({
|
|
765
785
|
workspaceCwd: cwd || this.options.cwd,
|
|
766
786
|
modelServiceId: this.options.modelServiceId,
|
|
@@ -768,10 +788,16 @@ var DaemonChannelBridge = class extends EventEmitter2 {
|
|
|
768
788
|
sessionScope: this.options.sessionScope ?? "thread",
|
|
769
789
|
...options?.approvalMode ? { approvalMode: options.approvalMode } : {}
|
|
770
790
|
});
|
|
791
|
+
if (lifecycleGeneration !== this.lifecycleGeneration) {
|
|
792
|
+
await this.rejectStaleSession(session);
|
|
793
|
+
}
|
|
771
794
|
if (session.sessionId !== sessionId) {
|
|
795
|
+
void this.releaseSessionClient(session).catch((error) => {
|
|
796
|
+
this.lastError = error;
|
|
797
|
+
});
|
|
772
798
|
throw new Error(`Daemon returned session ${session.sessionId} while loading ${sessionId}`);
|
|
773
799
|
}
|
|
774
|
-
this.attachSession(session);
|
|
800
|
+
this.attachSession(session, bindingToken);
|
|
775
801
|
return session.sessionId;
|
|
776
802
|
}
|
|
777
803
|
async prompt(sessionId, text, options) {
|
|
@@ -788,14 +814,21 @@ var DaemonChannelBridge = class extends EventEmitter2 {
|
|
|
788
814
|
}
|
|
789
815
|
controllers.add(controller);
|
|
790
816
|
const chunks = [];
|
|
817
|
+
let slashCommandOutput = "";
|
|
791
818
|
const onChunk = /* @__PURE__ */ __name((sid, chunk) => {
|
|
792
819
|
if (sid === sessionId) {
|
|
793
820
|
chunks.push(chunk);
|
|
794
821
|
}
|
|
795
822
|
}, "onChunk");
|
|
823
|
+
const onSlashCommandOutput = /* @__PURE__ */ __name((sid, chunk) => {
|
|
824
|
+
if (sid === sessionId) {
|
|
825
|
+
slashCommandOutput = chunk;
|
|
826
|
+
}
|
|
827
|
+
}, "onSlashCommandOutput");
|
|
796
828
|
const clearChunks = /* @__PURE__ */ __name((sid) => {
|
|
797
829
|
if (sid === sessionId) {
|
|
798
830
|
chunks.length = 0;
|
|
831
|
+
slashCommandOutput = "";
|
|
799
832
|
}
|
|
800
833
|
}, "clearChunks");
|
|
801
834
|
const onSessionDied = /* @__PURE__ */ __name((info) => {
|
|
@@ -804,6 +837,7 @@ var DaemonChannelBridge = class extends EventEmitter2 {
|
|
|
804
837
|
}
|
|
805
838
|
}, "onSessionDied");
|
|
806
839
|
this.on("textChunk", onChunk);
|
|
840
|
+
this.on("slashCommandOutput", onSlashCommandOutput);
|
|
807
841
|
this.on("responseBoundary", clearChunks);
|
|
808
842
|
this.on("sessionDied", onSessionDied);
|
|
809
843
|
const turnBarrier = this.createTurnBarrier(sessionId);
|
|
@@ -822,7 +856,7 @@ var DaemonChannelBridge = class extends EventEmitter2 {
|
|
|
822
856
|
turnBarrier,
|
|
823
857
|
new Promise((resolve2) => setTimeout(resolve2, 0))
|
|
824
858
|
]);
|
|
825
|
-
const textResult = chunks.join("");
|
|
859
|
+
const textResult = chunks.join("") || slashCommandOutput;
|
|
826
860
|
this.emit("promptComplete", {
|
|
827
861
|
sessionId,
|
|
828
862
|
text: textResult,
|
|
@@ -832,6 +866,7 @@ var DaemonChannelBridge = class extends EventEmitter2 {
|
|
|
832
866
|
} finally {
|
|
833
867
|
this.clearTurnBarrier(sessionId);
|
|
834
868
|
this.off("textChunk", onChunk);
|
|
869
|
+
this.off("slashCommandOutput", onSlashCommandOutput);
|
|
835
870
|
this.off("responseBoundary", clearChunks);
|
|
836
871
|
this.off("sessionDied", onSessionDied);
|
|
837
872
|
this.activePrompts.delete(sessionId);
|
|
@@ -855,6 +890,25 @@ var DaemonChannelBridge = class extends EventEmitter2 {
|
|
|
855
890
|
this.activePrompts.delete(sessionId);
|
|
856
891
|
await session.cancel();
|
|
857
892
|
}
|
|
893
|
+
async discardSession(sessionId, expectedBindingToken) {
|
|
894
|
+
if (expectedBindingToken !== void 0 && this.sessionBindingTokens.get(sessionId) !== expectedBindingToken) {
|
|
895
|
+
return;
|
|
896
|
+
}
|
|
897
|
+
const session = this.removeSessionBinding(sessionId);
|
|
898
|
+
if (!session)
|
|
899
|
+
return;
|
|
900
|
+
await this.releaseSessionClient(session);
|
|
901
|
+
}
|
|
902
|
+
async releaseSessionClient(session) {
|
|
903
|
+
if (session.detach) {
|
|
904
|
+
try {
|
|
905
|
+
await session.detach();
|
|
906
|
+
return;
|
|
907
|
+
} catch {
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
await session.cancel();
|
|
911
|
+
}
|
|
858
912
|
async setSessionModel(sessionId, modelId) {
|
|
859
913
|
return await this.ensureSession(sessionId).setModel(modelId);
|
|
860
914
|
}
|
|
@@ -885,6 +939,7 @@ var DaemonChannelBridge = class extends EventEmitter2 {
|
|
|
885
939
|
}
|
|
886
940
|
}
|
|
887
941
|
stop() {
|
|
942
|
+
this.lifecycleGeneration++;
|
|
888
943
|
for (const sessionId of Array.from(this.sessions.keys())) {
|
|
889
944
|
const session = this.sessions.get(sessionId);
|
|
890
945
|
if (session) {
|
|
@@ -892,7 +947,7 @@ var DaemonChannelBridge = class extends EventEmitter2 {
|
|
|
892
947
|
this.lastError = error;
|
|
893
948
|
});
|
|
894
949
|
}
|
|
895
|
-
this.dropSession(sessionId, "bridge_stopped");
|
|
950
|
+
this.dropSession(sessionId, "bridge_stopped", false);
|
|
896
951
|
}
|
|
897
952
|
this.latestAvailableCommandsSessionId = void 0;
|
|
898
953
|
this.connected = false;
|
|
@@ -900,15 +955,29 @@ var DaemonChannelBridge = class extends EventEmitter2 {
|
|
|
900
955
|
get isConnected() {
|
|
901
956
|
return this.connected;
|
|
902
957
|
}
|
|
903
|
-
attachSession(session) {
|
|
904
|
-
|
|
905
|
-
|
|
958
|
+
attachSession(session, bindingToken) {
|
|
959
|
+
const replacedSession = this.removeSessionBinding(session.sessionId);
|
|
960
|
+
if (replacedSession) {
|
|
961
|
+
void this.releaseSessionClient(replacedSession).catch((error) => {
|
|
962
|
+
this.lastError = error;
|
|
963
|
+
});
|
|
964
|
+
this.emit("sessionDied", {
|
|
965
|
+
sessionId: session.sessionId,
|
|
966
|
+
reason: "session_replaced"
|
|
967
|
+
});
|
|
906
968
|
}
|
|
907
969
|
this.sessions.set(session.sessionId, session);
|
|
970
|
+
this.sessionBindingTokens.set(session.sessionId, bindingToken);
|
|
908
971
|
const controller = new AbortController();
|
|
909
972
|
this.eventControllers.set(session.sessionId, controller);
|
|
910
973
|
void this.pumpEvents(session, controller.signal);
|
|
911
974
|
}
|
|
975
|
+
async rejectStaleSession(session) {
|
|
976
|
+
void this.releaseSessionClient(session).catch((error) => {
|
|
977
|
+
this.lastError = error;
|
|
978
|
+
});
|
|
979
|
+
throw new Error("Daemon channel bridge stopped during session creation");
|
|
980
|
+
}
|
|
912
981
|
ensureSession(sessionId) {
|
|
913
982
|
const session = this.sessions.get(sessionId);
|
|
914
983
|
if (!session) {
|
|
@@ -944,6 +1013,9 @@ var DaemonChannelBridge = class extends EventEmitter2 {
|
|
|
944
1013
|
handleEvent(session, event) {
|
|
945
1014
|
switch (event.type) {
|
|
946
1015
|
case "session_update":
|
|
1016
|
+
if (isRecord(event.data) && typeof event.data["sessionId"] === "string" && event.data["sessionId"] !== session.sessionId) {
|
|
1017
|
+
break;
|
|
1018
|
+
}
|
|
947
1019
|
this.handleSessionUpdate(session.sessionId, event.data);
|
|
948
1020
|
break;
|
|
949
1021
|
case "permission_request":
|
|
@@ -987,9 +1059,13 @@ var DaemonChannelBridge = class extends EventEmitter2 {
|
|
|
987
1059
|
const type = getString(update["sessionUpdate"]);
|
|
988
1060
|
switch (type) {
|
|
989
1061
|
case "agent_message_chunk": {
|
|
1062
|
+
const meta = isRecord(update["_meta"]) ? update["_meta"] : void 0;
|
|
1063
|
+
if (typeof meta?.["parentToolCallId"] === "string") {
|
|
1064
|
+
break;
|
|
1065
|
+
}
|
|
990
1066
|
const text = getTextContent(update["content"]);
|
|
991
1067
|
if (text) {
|
|
992
|
-
this.emit("textChunk", sessionId, text);
|
|
1068
|
+
this.emit(meta?.["source"] === "slash_command" ? "slashCommandOutput" : "textChunk", sessionId, text);
|
|
993
1069
|
}
|
|
994
1070
|
break;
|
|
995
1071
|
}
|
|
@@ -1004,6 +1080,10 @@ var DaemonChannelBridge = class extends EventEmitter2 {
|
|
|
1004
1080
|
case "tool_call_update": {
|
|
1005
1081
|
const toolCallId = getString(update["toolCallId"]);
|
|
1006
1082
|
const kind = getString(update["kind"]);
|
|
1083
|
+
const meta = isRecord(update["_meta"]) ? update["_meta"] : void 0;
|
|
1084
|
+
if (!kind && toolCallId && getString(update["status"]) === "in_progress" && meta?.["shellProgress"] !== void 0) {
|
|
1085
|
+
break;
|
|
1086
|
+
}
|
|
1007
1087
|
if (!toolCallId || !kind) {
|
|
1008
1088
|
this.emitProtocolError(`Malformed daemon ${type} event`, update);
|
|
1009
1089
|
break;
|
|
@@ -1123,14 +1203,26 @@ var DaemonChannelBridge = class extends EventEmitter2 {
|
|
|
1123
1203
|
handleSessionDied(sessionId, data) {
|
|
1124
1204
|
this.dropSession(sessionId, this.getStringField(data, "reason", "session_died"));
|
|
1125
1205
|
}
|
|
1126
|
-
dropSession(sessionId, reason) {
|
|
1127
|
-
|
|
1206
|
+
dropSession(sessionId, reason, releaseClient = true) {
|
|
1207
|
+
const session = this.removeSessionBinding(sessionId);
|
|
1208
|
+
if (!session)
|
|
1128
1209
|
return;
|
|
1210
|
+
if (releaseClient) {
|
|
1211
|
+
void this.releaseSessionClient(session).catch((error) => {
|
|
1212
|
+
this.lastError = error;
|
|
1213
|
+
});
|
|
1129
1214
|
}
|
|
1215
|
+
this.emit("sessionDied", { sessionId, reason });
|
|
1216
|
+
}
|
|
1217
|
+
removeSessionBinding(sessionId) {
|
|
1218
|
+
const session = this.sessions.get(sessionId);
|
|
1219
|
+
if (!session)
|
|
1220
|
+
return void 0;
|
|
1130
1221
|
this.resolveTurnBarrier(sessionId);
|
|
1131
1222
|
this.eventControllers.get(sessionId)?.abort();
|
|
1132
1223
|
this.eventControllers.delete(sessionId);
|
|
1133
1224
|
this.sessions.delete(sessionId);
|
|
1225
|
+
this.sessionBindingTokens.delete(sessionId);
|
|
1134
1226
|
this.abortActivePrompts(sessionId);
|
|
1135
1227
|
this.activePrompts.delete(sessionId);
|
|
1136
1228
|
this.availableCommandsBySession.delete(sessionId);
|
|
@@ -1147,7 +1239,7 @@ var DaemonChannelBridge = class extends EventEmitter2 {
|
|
|
1147
1239
|
this.respondedRequestToSession.delete(requestId);
|
|
1148
1240
|
}
|
|
1149
1241
|
}
|
|
1150
|
-
|
|
1242
|
+
return session;
|
|
1151
1243
|
}
|
|
1152
1244
|
getStringField(data, field, fallback) {
|
|
1153
1245
|
return isRecord(data) && typeof data[field] === "string" ? data[field] : fallback;
|
|
@@ -1295,7 +1387,7 @@ var BlockStreamer = class {
|
|
|
1295
1387
|
|
|
1296
1388
|
// packages/channels/base/dist/ChannelBase.js
|
|
1297
1389
|
init_esbuild_shims();
|
|
1298
|
-
import { basename, join as
|
|
1390
|
+
import { basename, join as join5 } from "node:path";
|
|
1299
1391
|
|
|
1300
1392
|
// packages/channels/base/dist/GroupGate.js
|
|
1301
1393
|
init_esbuild_shims();
|
|
@@ -1770,7 +1862,8 @@ __name(generateCode, "generateCode");
|
|
|
1770
1862
|
|
|
1771
1863
|
// packages/channels/base/dist/SessionRouter.js
|
|
1772
1864
|
init_esbuild_shims();
|
|
1773
|
-
import { existsSync as existsSync3, readFileSync as readFileSync3,
|
|
1865
|
+
import { chmodSync as chmodSync2, existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync3, renameSync as renameSync2, rmSync, unlinkSync, writeFileSync as writeFileSync3 } from "node:fs";
|
|
1866
|
+
import { dirname as dirname2, join as join4 } from "node:path";
|
|
1774
1867
|
import process2 from "node:process";
|
|
1775
1868
|
var SessionRouter = class {
|
|
1776
1869
|
static {
|
|
@@ -1784,17 +1877,22 @@ var SessionRouter = class {
|
|
|
1784
1877
|
// session ID → cwd
|
|
1785
1878
|
creatingSessions = /* @__PURE__ */ new Map();
|
|
1786
1879
|
sessionLoadWindows = /* @__PURE__ */ new Set();
|
|
1880
|
+
liveSessionIds = /* @__PURE__ */ new Set();
|
|
1881
|
+
routeTokens = /* @__PURE__ */ new Map();
|
|
1882
|
+
lifecycleGeneration = 0;
|
|
1787
1883
|
bridge;
|
|
1788
1884
|
defaultCwd;
|
|
1789
1885
|
defaultScope;
|
|
1790
1886
|
channelScopes = /* @__PURE__ */ new Map();
|
|
1791
1887
|
channelApprovalModes = /* @__PURE__ */ new Map();
|
|
1792
1888
|
persistPath;
|
|
1793
|
-
|
|
1889
|
+
recoveryMode;
|
|
1890
|
+
constructor(bridge, defaultCwd, scope = "user", persistPath, options = {}) {
|
|
1794
1891
|
this.bridge = bridge;
|
|
1795
1892
|
this.defaultCwd = defaultCwd;
|
|
1796
1893
|
this.defaultScope = scope;
|
|
1797
1894
|
this.persistPath = persistPath;
|
|
1895
|
+
this.recoveryMode = options.recoveryMode ?? "eager";
|
|
1798
1896
|
}
|
|
1799
1897
|
/** Replace the bridge instance (used after crash recovery restart). */
|
|
1800
1898
|
setBridge(bridge) {
|
|
@@ -1829,58 +1927,166 @@ var SessionRouter = class {
|
|
|
1829
1927
|
}
|
|
1830
1928
|
async resolve(channelName, senderId, chatId, threadId, cwd, isGroup, options) {
|
|
1831
1929
|
const key = this.routingKey(channelName, senderId, chatId, options?.routingThreadId ?? threadId);
|
|
1832
|
-
|
|
1930
|
+
const input = {
|
|
1931
|
+
channelName,
|
|
1932
|
+
senderId,
|
|
1933
|
+
chatId,
|
|
1934
|
+
threadId,
|
|
1935
|
+
cwd: cwd || this.defaultCwd,
|
|
1936
|
+
isGroup
|
|
1937
|
+
};
|
|
1938
|
+
let failedWaits = 0;
|
|
1833
1939
|
for (; ; ) {
|
|
1834
1940
|
const existing = this.toSession.get(key);
|
|
1835
|
-
if (existing) {
|
|
1941
|
+
if (existing && this.isLive(existing)) {
|
|
1836
1942
|
this.promoteTargetToGroup(existing, isGroup);
|
|
1837
1943
|
return existing;
|
|
1838
1944
|
}
|
|
1839
1945
|
const creating = this.creatingSessions.get(key);
|
|
1840
1946
|
if (creating) {
|
|
1841
1947
|
try {
|
|
1842
|
-
const sessionId = await creating;
|
|
1948
|
+
const sessionId = await creating.promise;
|
|
1949
|
+
try {
|
|
1950
|
+
this.assertOperationResultCurrent(key, sessionId, creating);
|
|
1951
|
+
} catch (error) {
|
|
1952
|
+
this.scheduleDiscardInvalidatedSession(sessionId, creating);
|
|
1953
|
+
throw error;
|
|
1954
|
+
}
|
|
1843
1955
|
this.promoteTargetToGroup(sessionId, isGroup);
|
|
1844
1956
|
return sessionId;
|
|
1845
|
-
} catch (
|
|
1957
|
+
} catch (error) {
|
|
1958
|
+
if (creating.invalidationError) {
|
|
1959
|
+
throw creating.invalidationError;
|
|
1960
|
+
}
|
|
1846
1961
|
if (this.creatingSessions.get(key) === creating) {
|
|
1847
1962
|
this.creatingSessions.delete(key);
|
|
1848
1963
|
}
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1964
|
+
this.releaseRouteToken(key, creating);
|
|
1965
|
+
failedWaits++;
|
|
1966
|
+
if (failedWaits > 3)
|
|
1967
|
+
throw error;
|
|
1853
1968
|
continue;
|
|
1854
1969
|
}
|
|
1855
1970
|
}
|
|
1856
|
-
const
|
|
1857
|
-
|
|
1858
|
-
|
|
1971
|
+
const operation = this.createSessionOperation(key, {
|
|
1972
|
+
channelName: input.channelName,
|
|
1973
|
+
senderId: input.senderId,
|
|
1974
|
+
chatId: input.chatId,
|
|
1975
|
+
threadId: input.threadId,
|
|
1976
|
+
isGroup: input.isGroup
|
|
1977
|
+
}, (currentOperation) => existing ? this.loadOrReplaceSession(key, existing, input, currentOperation) : this.createAndStoreSession(key, input, currentOperation));
|
|
1978
|
+
this.creatingSessions.set(key, operation);
|
|
1979
|
+
try {
|
|
1980
|
+
const sessionId = await operation.promise;
|
|
1859
1981
|
try {
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
this.
|
|
1863
|
-
|
|
1864
|
-
senderId,
|
|
1865
|
-
chatId,
|
|
1866
|
-
threadId,
|
|
1867
|
-
isGroup
|
|
1868
|
-
});
|
|
1869
|
-
this.toCwd.set(sessionId, sessionCwd);
|
|
1870
|
-
this.persist();
|
|
1871
|
-
return sessionId;
|
|
1872
|
-
} finally {
|
|
1873
|
-
this.endSessionLoad(loadWindow);
|
|
1982
|
+
this.assertOperationResultCurrent(key, sessionId, operation);
|
|
1983
|
+
} catch (error) {
|
|
1984
|
+
this.scheduleDiscardInvalidatedSession(sessionId, operation);
|
|
1985
|
+
throw error;
|
|
1874
1986
|
}
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
try {
|
|
1878
|
-
return await created;
|
|
1987
|
+
this.promoteTargetToGroup(sessionId, isGroup);
|
|
1988
|
+
return sessionId;
|
|
1879
1989
|
} finally {
|
|
1880
|
-
if (this.creatingSessions.get(key) ===
|
|
1990
|
+
if (this.creatingSessions.get(key) === operation) {
|
|
1881
1991
|
this.creatingSessions.delete(key);
|
|
1882
1992
|
}
|
|
1993
|
+
this.releaseRouteToken(key, operation);
|
|
1994
|
+
}
|
|
1995
|
+
}
|
|
1996
|
+
}
|
|
1997
|
+
isLive(sessionId) {
|
|
1998
|
+
return this.recoveryMode === "eager" || this.liveSessionIds.has(sessionId);
|
|
1999
|
+
}
|
|
2000
|
+
async createAndStoreSession(key, input, operation) {
|
|
2001
|
+
const loadWindow = this.beginSessionLoad();
|
|
2002
|
+
try {
|
|
2003
|
+
const sessionId = await this.createLiveSession(input.cwd, loadWindow, key, this.sessionOptions(input.channelName), operation);
|
|
2004
|
+
try {
|
|
2005
|
+
this.assertOperationCurrent(operation);
|
|
2006
|
+
} catch (error) {
|
|
2007
|
+
this.scheduleDiscardInvalidatedSession(sessionId, operation);
|
|
2008
|
+
throw error;
|
|
2009
|
+
}
|
|
2010
|
+
this.toSession.set(key, sessionId);
|
|
2011
|
+
this.toTarget.set(sessionId, {
|
|
2012
|
+
channelName: input.channelName,
|
|
2013
|
+
senderId: input.senderId,
|
|
2014
|
+
chatId: input.chatId,
|
|
2015
|
+
threadId: input.threadId,
|
|
2016
|
+
isGroup: input.isGroup
|
|
2017
|
+
});
|
|
2018
|
+
this.toCwd.set(sessionId, input.cwd);
|
|
2019
|
+
this.liveSessionIds.add(sessionId);
|
|
2020
|
+
this.persist();
|
|
2021
|
+
return sessionId;
|
|
2022
|
+
} finally {
|
|
2023
|
+
this.endSessionLoad(loadWindow);
|
|
2024
|
+
}
|
|
2025
|
+
}
|
|
2026
|
+
async loadOrReplaceSession(key, savedSessionId, input, operation) {
|
|
2027
|
+
const savedCwd = this.toCwd.get(savedSessionId) ?? input.cwd;
|
|
2028
|
+
const loadWindow = this.beginSessionLoad();
|
|
2029
|
+
try {
|
|
2030
|
+
try {
|
|
2031
|
+
const loadedSessionId = await this.bridge.loadSession(savedSessionId, savedCwd, this.sessionOptions(input.channelName), operation);
|
|
2032
|
+
try {
|
|
2033
|
+
this.assertOperationCurrent(operation);
|
|
2034
|
+
if (this.toSession.get(key) !== savedSessionId) {
|
|
2035
|
+
this.invalidateOperation(operation);
|
|
2036
|
+
this.assertOperationCurrent(operation);
|
|
2037
|
+
}
|
|
2038
|
+
} catch (error) {
|
|
2039
|
+
this.scheduleDiscardInvalidatedSession(loadedSessionId, operation);
|
|
2040
|
+
throw error;
|
|
2041
|
+
}
|
|
2042
|
+
if (typeof loadedSessionId !== "string" || loadedSessionId.length === 0 || loadWindow.delete(loadedSessionId)) {
|
|
2043
|
+
throw new Error("Invalid or dead restored session ID");
|
|
2044
|
+
}
|
|
2045
|
+
if (loadedSessionId !== savedSessionId) {
|
|
2046
|
+
const target = this.toTarget.get(savedSessionId);
|
|
2047
|
+
this.deleteByKey(key);
|
|
2048
|
+
this.toSession.set(key, loadedSessionId);
|
|
2049
|
+
if (target)
|
|
2050
|
+
this.toTarget.set(loadedSessionId, target);
|
|
2051
|
+
this.toCwd.set(loadedSessionId, savedCwd);
|
|
2052
|
+
this.persist();
|
|
2053
|
+
}
|
|
2054
|
+
this.liveSessionIds.add(loadedSessionId);
|
|
2055
|
+
return loadedSessionId;
|
|
2056
|
+
} catch (loadError) {
|
|
2057
|
+
this.assertOperationCurrent(operation);
|
|
2058
|
+
try {
|
|
2059
|
+
const replacement = await this.createLiveSession(input.cwd, loadWindow, key, this.sessionOptions(input.channelName), operation);
|
|
2060
|
+
try {
|
|
2061
|
+
this.assertOperationCurrent(operation);
|
|
2062
|
+
} catch (error) {
|
|
2063
|
+
this.scheduleDiscardInvalidatedSession(replacement, operation);
|
|
2064
|
+
throw error;
|
|
2065
|
+
}
|
|
2066
|
+
this.deleteByKey(key);
|
|
2067
|
+
this.toSession.set(key, replacement);
|
|
2068
|
+
this.toTarget.set(replacement, {
|
|
2069
|
+
channelName: input.channelName,
|
|
2070
|
+
senderId: input.senderId,
|
|
2071
|
+
chatId: input.chatId,
|
|
2072
|
+
threadId: input.threadId,
|
|
2073
|
+
isGroup: input.isGroup
|
|
2074
|
+
});
|
|
2075
|
+
this.toCwd.set(replacement, input.cwd);
|
|
2076
|
+
this.liveSessionIds.add(replacement);
|
|
2077
|
+
this.persist();
|
|
2078
|
+
process2.stderr.write(`[SessionRouter] Replaced unavailable session ${sanitizeLogText(savedSessionId, 128)} for key ${sanitizeLogText(key, 256)} after load failed: ${sanitizeLogText(loadError instanceof Error ? loadError.message : String(loadError), 512)}
|
|
2079
|
+
`);
|
|
2080
|
+
return replacement;
|
|
2081
|
+
} catch (createError) {
|
|
2082
|
+
this.assertOperationCurrent(operation);
|
|
2083
|
+
process2.stderr.write(`[SessionRouter] Failed to load session ${sanitizeLogText(savedSessionId, 128)} for key ${sanitizeLogText(key, 256)} (${sanitizeLogText(loadError instanceof Error ? loadError.message : String(loadError), 512)}) and failed to create a replacement (${sanitizeLogText(createError instanceof Error ? createError.message : String(createError), 512)})
|
|
2084
|
+
`);
|
|
2085
|
+
throw createError;
|
|
2086
|
+
}
|
|
1883
2087
|
}
|
|
2088
|
+
} finally {
|
|
2089
|
+
this.endSessionLoad(loadWindow);
|
|
1884
2090
|
}
|
|
1885
2091
|
}
|
|
1886
2092
|
getTarget(sessionId) {
|
|
@@ -1912,6 +2118,7 @@ var SessionRouter = class {
|
|
|
1912
2118
|
const scope = this.channelScopes.get(channelName) || this.defaultScope;
|
|
1913
2119
|
if (chatId) {
|
|
1914
2120
|
const key = this.routingKey(channelName, senderId, chatId, threadId);
|
|
2121
|
+
this.invalidateRouteOperation(key);
|
|
1915
2122
|
const sessionId = this.deleteByKey(key);
|
|
1916
2123
|
if (sessionId)
|
|
1917
2124
|
removedIds.push(sessionId);
|
|
@@ -1921,11 +2128,17 @@ var SessionRouter = class {
|
|
|
1921
2128
|
for (const [k, mappedSessionId] of [...this.toSession.entries()]) {
|
|
1922
2129
|
const target = this.toTarget.get(mappedSessionId);
|
|
1923
2130
|
if (target?.channelName === channelName && target.senderId === senderId) {
|
|
2131
|
+
this.invalidateRouteOperation(k);
|
|
1924
2132
|
const sessionId = this.deleteByKey(k);
|
|
1925
2133
|
if (sessionId)
|
|
1926
2134
|
removedIds.push(sessionId);
|
|
1927
2135
|
}
|
|
1928
2136
|
}
|
|
2137
|
+
for (const [key, operation] of [...this.creatingSessions]) {
|
|
2138
|
+
if (operation.target.channelName === channelName && operation.target.senderId === senderId) {
|
|
2139
|
+
this.invalidateRouteOperation(key);
|
|
2140
|
+
}
|
|
2141
|
+
}
|
|
1929
2142
|
}
|
|
1930
2143
|
if (removedIds.length > 0)
|
|
1931
2144
|
this.persist();
|
|
@@ -1936,6 +2149,7 @@ var SessionRouter = class {
|
|
|
1936
2149
|
let removed = false;
|
|
1937
2150
|
for (const [key, mappedSessionId] of [...this.toSession.entries()]) {
|
|
1938
2151
|
if (mappedSessionId === sessionId) {
|
|
2152
|
+
this.invalidateRouteOperation(key);
|
|
1939
2153
|
this.toSession.delete(key);
|
|
1940
2154
|
removed = true;
|
|
1941
2155
|
}
|
|
@@ -1946,6 +2160,7 @@ var SessionRouter = class {
|
|
|
1946
2160
|
if (this.toCwd.delete(sessionId)) {
|
|
1947
2161
|
removed = true;
|
|
1948
2162
|
}
|
|
2163
|
+
this.liveSessionIds.delete(sessionId);
|
|
1949
2164
|
if (!removed && this.sessionLoadWindows.size > 0) {
|
|
1950
2165
|
for (const loadWindow of this.sessionLoadWindows) {
|
|
1951
2166
|
loadWindow.add(sessionId);
|
|
@@ -1956,6 +2171,17 @@ var SessionRouter = class {
|
|
|
1956
2171
|
}
|
|
1957
2172
|
return removed;
|
|
1958
2173
|
}
|
|
2174
|
+
handleSessionDied(sessionId) {
|
|
2175
|
+
if (this.recoveryMode === "eager") {
|
|
2176
|
+
return this.removeSessionId(sessionId);
|
|
2177
|
+
}
|
|
2178
|
+
const known = this.toTarget.has(sessionId);
|
|
2179
|
+
this.liveSessionIds.delete(sessionId);
|
|
2180
|
+
for (const loadWindow of this.sessionLoadWindows) {
|
|
2181
|
+
loadWindow.add(sessionId);
|
|
2182
|
+
}
|
|
2183
|
+
return known;
|
|
2184
|
+
}
|
|
1959
2185
|
deleteByKey(key) {
|
|
1960
2186
|
const sessionId = this.toSession.get(key);
|
|
1961
2187
|
if (!sessionId)
|
|
@@ -1963,6 +2189,7 @@ var SessionRouter = class {
|
|
|
1963
2189
|
this.toSession.delete(key);
|
|
1964
2190
|
this.toTarget.delete(sessionId);
|
|
1965
2191
|
this.toCwd.delete(sessionId);
|
|
2192
|
+
this.liveSessionIds.delete(sessionId);
|
|
1966
2193
|
return sessionId;
|
|
1967
2194
|
}
|
|
1968
2195
|
promoteTargetToGroup(sessionId, isGroup) {
|
|
@@ -1985,45 +2212,69 @@ var SessionRouter = class {
|
|
|
1985
2212
|
}
|
|
1986
2213
|
return entries;
|
|
1987
2214
|
}
|
|
2215
|
+
restoreRoutes() {
|
|
2216
|
+
if (this.recoveryMode !== "lazy") {
|
|
2217
|
+
throw new Error("restoreRoutes requires lazy recovery mode");
|
|
2218
|
+
}
|
|
2219
|
+
const persisted = this.readPersistedEntries();
|
|
2220
|
+
if (!persisted)
|
|
2221
|
+
return { restored: 0, dropped: 0 };
|
|
2222
|
+
this.dispose();
|
|
2223
|
+
let restored = 0;
|
|
2224
|
+
for (const [key, entry] of Object.entries(persisted.entries)) {
|
|
2225
|
+
this.toSession.set(key, entry.sessionId);
|
|
2226
|
+
this.toTarget.set(entry.sessionId, entry.target);
|
|
2227
|
+
this.toCwd.set(entry.sessionId, entry.cwd);
|
|
2228
|
+
restored++;
|
|
2229
|
+
}
|
|
2230
|
+
if (persisted.dropped > 0)
|
|
2231
|
+
this.persist();
|
|
2232
|
+
return { restored, dropped: persisted.dropped };
|
|
2233
|
+
}
|
|
1988
2234
|
/**
|
|
1989
2235
|
* Restore session mappings from a previous bridge.
|
|
1990
2236
|
* Called after bridge restart — attempts loadSession for each saved mapping.
|
|
1991
2237
|
* Failed loads are dropped (new session on next message).
|
|
1992
2238
|
*/
|
|
1993
2239
|
async restoreSessions() {
|
|
1994
|
-
const
|
|
1995
|
-
if (!
|
|
1996
|
-
return { restored: 0, failed: 0 };
|
|
1997
|
-
}
|
|
1998
|
-
let entries;
|
|
1999
|
-
try {
|
|
2000
|
-
entries = JSON.parse(readFileSync3(persistPath, "utf-8"));
|
|
2001
|
-
} catch (err) {
|
|
2002
|
-
const reason = err instanceof Error ? err.message : String(err);
|
|
2003
|
-
process2.stderr.write(`[SessionRouter] Corrupted persist file at ${sanitizeLogText(persistPath, 1024)}: ${sanitizeLogText(reason, 512)}
|
|
2004
|
-
`);
|
|
2240
|
+
const persisted = this.readPersistedEntries();
|
|
2241
|
+
if (!persisted)
|
|
2005
2242
|
return { restored: 0, failed: 0 };
|
|
2006
|
-
|
|
2243
|
+
const entries = persisted.entries;
|
|
2244
|
+
const restoreGeneration = this.lifecycleGeneration;
|
|
2007
2245
|
let restored = 0;
|
|
2008
2246
|
let failed = 0;
|
|
2009
|
-
let changed =
|
|
2247
|
+
let changed = persisted.dropped > 0;
|
|
2010
2248
|
const reservations = /* @__PURE__ */ new Map();
|
|
2249
|
+
for (const key of persisted.droppedKeys) {
|
|
2250
|
+
this.deleteByKey(key);
|
|
2251
|
+
}
|
|
2011
2252
|
for (const key of Object.keys(entries)) {
|
|
2012
2253
|
this.deleteByKey(key);
|
|
2013
2254
|
const reservation = this.createSessionReservation();
|
|
2014
2255
|
reservation.promise.catch(() => void 0);
|
|
2015
|
-
this.
|
|
2016
|
-
|
|
2256
|
+
const operation = this.createSessionOperation(key, entries[key].target, () => reservation.promise);
|
|
2257
|
+
operation.promise.catch(() => void 0);
|
|
2258
|
+
this.creatingSessions.set(key, operation);
|
|
2259
|
+
reservations.set(key, { reservation, operation });
|
|
2017
2260
|
}
|
|
2018
2261
|
const loadWindow = this.beginSessionLoad();
|
|
2019
2262
|
try {
|
|
2020
2263
|
for (const [key, entry] of Object.entries(entries)) {
|
|
2021
|
-
const
|
|
2022
|
-
if (!
|
|
2264
|
+
const reserved = reservations.get(key);
|
|
2265
|
+
if (!reserved)
|
|
2023
2266
|
continue;
|
|
2267
|
+
const { reservation, operation } = reserved;
|
|
2024
2268
|
try {
|
|
2269
|
+
this.assertOperationCurrent(operation);
|
|
2025
2270
|
const options = this.sessionOptions(entry.target.channelName);
|
|
2026
|
-
const sessionId =
|
|
2271
|
+
const sessionId = await this.bridge.loadSession(entry.sessionId, entry.cwd, options, operation);
|
|
2272
|
+
try {
|
|
2273
|
+
this.assertOperationCurrent(operation);
|
|
2274
|
+
} catch (error) {
|
|
2275
|
+
this.scheduleDiscardInvalidatedSession(sessionId, operation);
|
|
2276
|
+
throw error;
|
|
2277
|
+
}
|
|
2027
2278
|
if (typeof sessionId !== "string" || sessionId.length === 0) {
|
|
2028
2279
|
throw new Error("Invalid restored session ID");
|
|
2029
2280
|
}
|
|
@@ -2046,26 +2297,36 @@ var SessionRouter = class {
|
|
|
2046
2297
|
failed++;
|
|
2047
2298
|
changed = true;
|
|
2048
2299
|
} finally {
|
|
2049
|
-
if (this.creatingSessions.get(key) ===
|
|
2300
|
+
if (this.creatingSessions.get(key) === operation) {
|
|
2050
2301
|
this.creatingSessions.delete(key);
|
|
2051
2302
|
}
|
|
2303
|
+
this.releaseRouteToken(key, operation);
|
|
2052
2304
|
}
|
|
2053
2305
|
}
|
|
2054
2306
|
} finally {
|
|
2055
2307
|
this.endSessionLoad(loadWindow);
|
|
2056
2308
|
}
|
|
2057
|
-
if (changed) {
|
|
2309
|
+
if (changed && restoreGeneration === this.lifecycleGeneration) {
|
|
2058
2310
|
this.persist();
|
|
2059
2311
|
}
|
|
2060
2312
|
return { restored, failed };
|
|
2061
2313
|
}
|
|
2062
|
-
|
|
2063
|
-
|
|
2314
|
+
dispose() {
|
|
2315
|
+
this.lifecycleGeneration++;
|
|
2316
|
+
for (const operation of this.creatingSessions.values()) {
|
|
2317
|
+
this.invalidateOperation(operation);
|
|
2318
|
+
}
|
|
2064
2319
|
this.toSession.clear();
|
|
2065
2320
|
this.toTarget.clear();
|
|
2066
2321
|
this.toCwd.clear();
|
|
2067
2322
|
this.creatingSessions.clear();
|
|
2068
2323
|
this.sessionLoadWindows.clear();
|
|
2324
|
+
this.liveSessionIds.clear();
|
|
2325
|
+
this.routeTokens.clear();
|
|
2326
|
+
}
|
|
2327
|
+
/** Clear in-memory state and delete persist file. Used on clean shutdown. */
|
|
2328
|
+
clearAll() {
|
|
2329
|
+
this.dispose();
|
|
2069
2330
|
if (this.persistPath && existsSync3(this.persistPath)) {
|
|
2070
2331
|
try {
|
|
2071
2332
|
unlinkSync(this.persistPath);
|
|
@@ -2073,30 +2334,105 @@ var SessionRouter = class {
|
|
|
2073
2334
|
}
|
|
2074
2335
|
}
|
|
2075
2336
|
}
|
|
2337
|
+
readPersistedEntries() {
|
|
2338
|
+
const persistPath = this.persistPath;
|
|
2339
|
+
if (!persistPath || !existsSync3(persistPath))
|
|
2340
|
+
return void 0;
|
|
2341
|
+
let parsed;
|
|
2342
|
+
try {
|
|
2343
|
+
parsed = JSON.parse(readFileSync3(persistPath, "utf-8"));
|
|
2344
|
+
} catch (error) {
|
|
2345
|
+
const quarantinePath = `${persistPath}.corrupt-${Date.now()}`;
|
|
2346
|
+
try {
|
|
2347
|
+
renameSync2(persistPath, quarantinePath);
|
|
2348
|
+
} catch {
|
|
2349
|
+
}
|
|
2350
|
+
process2.stderr.write(`[SessionRouter] Corrupted persist file at ${sanitizeLogText(persistPath, 1024)}: ${sanitizeLogText(error instanceof Error ? error.message : String(error), 512)}
|
|
2351
|
+
`);
|
|
2352
|
+
return void 0;
|
|
2353
|
+
}
|
|
2354
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
2355
|
+
const quarantinePath = `${persistPath}.corrupt-${Date.now()}`;
|
|
2356
|
+
try {
|
|
2357
|
+
renameSync2(persistPath, quarantinePath);
|
|
2358
|
+
} catch {
|
|
2359
|
+
}
|
|
2360
|
+
process2.stderr.write(`[SessionRouter] Invalid route store at ${sanitizeLogText(persistPath, 1024)}: expected an object
|
|
2361
|
+
`);
|
|
2362
|
+
return void 0;
|
|
2363
|
+
}
|
|
2364
|
+
const entries = {};
|
|
2365
|
+
const droppedKeys = [];
|
|
2366
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
2367
|
+
if (this.isPersistedEntry(value))
|
|
2368
|
+
entries[key] = value;
|
|
2369
|
+
else
|
|
2370
|
+
droppedKeys.push(key);
|
|
2371
|
+
}
|
|
2372
|
+
return { entries, dropped: droppedKeys.length, droppedKeys };
|
|
2373
|
+
}
|
|
2374
|
+
isPersistedEntry(value) {
|
|
2375
|
+
if (typeof value !== "object" || value === null)
|
|
2376
|
+
return false;
|
|
2377
|
+
const entry = value;
|
|
2378
|
+
const target = entry["target"];
|
|
2379
|
+
if (typeof target !== "object" || target === null)
|
|
2380
|
+
return false;
|
|
2381
|
+
const typedTarget = target;
|
|
2382
|
+
return typeof entry["sessionId"] === "string" && entry["sessionId"].length > 0 && typeof entry["cwd"] === "string" && entry["cwd"].length > 0 && typeof typedTarget["channelName"] === "string" && typeof typedTarget["senderId"] === "string" && typeof typedTarget["chatId"] === "string" && (typedTarget["threadId"] === void 0 || typeof typedTarget["threadId"] === "string") && (typedTarget["isGroup"] === void 0 || typeof typedTarget["isGroup"] === "boolean");
|
|
2383
|
+
}
|
|
2076
2384
|
persist() {
|
|
2077
2385
|
if (!this.persistPath)
|
|
2078
2386
|
return;
|
|
2079
2387
|
const data = {};
|
|
2080
2388
|
for (const [key, sessionId] of this.toSession) {
|
|
2081
2389
|
const target = this.toTarget.get(sessionId);
|
|
2082
|
-
if (target)
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
}
|
|
2390
|
+
if (!target)
|
|
2391
|
+
continue;
|
|
2392
|
+
data[key] = {
|
|
2393
|
+
sessionId,
|
|
2394
|
+
target,
|
|
2395
|
+
cwd: this.toCwd.get(sessionId) ?? this.defaultCwd
|
|
2396
|
+
};
|
|
2089
2397
|
}
|
|
2398
|
+
const dir = dirname2(this.persistPath);
|
|
2399
|
+
const tempPath = join4(dir, `${Date.now()}-${process2.pid}-${Math.random().toString(16).slice(2)}.tmp`);
|
|
2090
2400
|
try {
|
|
2091
|
-
|
|
2092
|
-
|
|
2401
|
+
mkdirSync3(dir, { recursive: true, mode: 448 });
|
|
2402
|
+
try {
|
|
2403
|
+
chmodSync2(dir, 448);
|
|
2404
|
+
} catch {
|
|
2405
|
+
}
|
|
2406
|
+
writeFileSync3(tempPath, JSON.stringify(data, null, 2), {
|
|
2407
|
+
encoding: "utf-8",
|
|
2408
|
+
mode: 384
|
|
2409
|
+
});
|
|
2410
|
+
renameSync2(tempPath, this.persistPath);
|
|
2411
|
+
try {
|
|
2412
|
+
chmodSync2(this.persistPath, 384);
|
|
2413
|
+
} catch {
|
|
2414
|
+
}
|
|
2415
|
+
} catch (error) {
|
|
2416
|
+
process2.stderr.write(`[SessionRouter] Failed to persist routes at ${sanitizeLogText(this.persistPath, 1024)}: ${sanitizeLogText(error instanceof Error ? error.message : String(error), 512)}
|
|
2417
|
+
`);
|
|
2418
|
+
} finally {
|
|
2419
|
+
try {
|
|
2420
|
+
rmSync(tempPath, { force: true });
|
|
2421
|
+
} catch {
|
|
2422
|
+
}
|
|
2093
2423
|
}
|
|
2094
2424
|
}
|
|
2095
|
-
async createLiveSession(cwd, loadWindow, routingKey, options) {
|
|
2425
|
+
async createLiveSession(cwd, loadWindow, routingKey, options, operation) {
|
|
2096
2426
|
const maxAttempts = 2;
|
|
2097
2427
|
let lastDeadSessionId;
|
|
2098
2428
|
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
2099
|
-
const sessionId =
|
|
2429
|
+
const sessionId = await this.bridge.newSession(cwd, options, operation);
|
|
2430
|
+
try {
|
|
2431
|
+
this.assertOperationCurrent(operation);
|
|
2432
|
+
} catch (error) {
|
|
2433
|
+
this.scheduleDiscardInvalidatedSession(sessionId, operation);
|
|
2434
|
+
throw error;
|
|
2435
|
+
}
|
|
2100
2436
|
if (typeof sessionId !== "string" || sessionId.length === 0) {
|
|
2101
2437
|
throw new Error("Invalid session ID from bridge");
|
|
2102
2438
|
}
|
|
@@ -2112,6 +2448,65 @@ var SessionRouter = class {
|
|
|
2112
2448
|
this.sessionLoadWindows.add(loadWindow);
|
|
2113
2449
|
return loadWindow;
|
|
2114
2450
|
}
|
|
2451
|
+
createSessionOperation(key, target, run) {
|
|
2452
|
+
let routeToken = this.routeTokens.get(key);
|
|
2453
|
+
if (!routeToken) {
|
|
2454
|
+
routeToken = {};
|
|
2455
|
+
this.routeTokens.set(key, routeToken);
|
|
2456
|
+
}
|
|
2457
|
+
const operation = {
|
|
2458
|
+
promise: Promise.resolve(""),
|
|
2459
|
+
target,
|
|
2460
|
+
lifecycleGeneration: this.lifecycleGeneration,
|
|
2461
|
+
routeToken
|
|
2462
|
+
};
|
|
2463
|
+
operation.promise = Promise.resolve().then(() => run(operation)).catch((error) => {
|
|
2464
|
+
this.assertOperationCurrent(operation);
|
|
2465
|
+
throw error;
|
|
2466
|
+
});
|
|
2467
|
+
return operation;
|
|
2468
|
+
}
|
|
2469
|
+
invalidateRouteOperation(key) {
|
|
2470
|
+
this.routeTokens.delete(key);
|
|
2471
|
+
const operation = this.creatingSessions.get(key);
|
|
2472
|
+
if (!operation)
|
|
2473
|
+
return;
|
|
2474
|
+
this.invalidateOperation(operation);
|
|
2475
|
+
this.creatingSessions.delete(key);
|
|
2476
|
+
}
|
|
2477
|
+
invalidateOperation(operation) {
|
|
2478
|
+
operation.invalidationError ??= new Error("Session route operation was invalidated");
|
|
2479
|
+
}
|
|
2480
|
+
assertOperationCurrent(operation) {
|
|
2481
|
+
if (operation.lifecycleGeneration !== this.lifecycleGeneration) {
|
|
2482
|
+
this.invalidateOperation(operation);
|
|
2483
|
+
}
|
|
2484
|
+
if (operation.invalidationError) {
|
|
2485
|
+
throw operation.invalidationError;
|
|
2486
|
+
}
|
|
2487
|
+
}
|
|
2488
|
+
assertOperationResultCurrent(key, sessionId, operation) {
|
|
2489
|
+
if (operation.routeToken !== this.routeTokens.get(key)) {
|
|
2490
|
+
this.invalidateOperation(operation);
|
|
2491
|
+
}
|
|
2492
|
+
if (this.toSession.get(key) !== sessionId) {
|
|
2493
|
+
this.invalidateOperation(operation);
|
|
2494
|
+
}
|
|
2495
|
+
this.assertOperationCurrent(operation);
|
|
2496
|
+
}
|
|
2497
|
+
releaseRouteToken(key, operation) {
|
|
2498
|
+
if (this.routeTokens.get(key) === operation.routeToken && !this.toSession.has(key) && !this.creatingSessions.has(key)) {
|
|
2499
|
+
this.routeTokens.delete(key);
|
|
2500
|
+
}
|
|
2501
|
+
}
|
|
2502
|
+
scheduleDiscardInvalidatedSession(sessionId, operation) {
|
|
2503
|
+
if ([...this.toSession.values()].includes(sessionId))
|
|
2504
|
+
return;
|
|
2505
|
+
try {
|
|
2506
|
+
void this.bridge.discardSession?.(sessionId, operation).catch(() => void 0);
|
|
2507
|
+
} catch {
|
|
2508
|
+
}
|
|
2509
|
+
}
|
|
2115
2510
|
createSessionReservation() {
|
|
2116
2511
|
let resolveReservation;
|
|
2117
2512
|
let rejectReservation;
|
|
@@ -2488,6 +2883,29 @@ var LIST_PATTERNS = [
|
|
|
2488
2883
|
/^这个聊天你记住了什么[??]?$/u,
|
|
2489
2884
|
/^what do you remember[??]?$/iu
|
|
2490
2885
|
];
|
|
2886
|
+
var LIST_PAGE_PATTERNS = [
|
|
2887
|
+
/^查看第\s*(\d+)\s*页记忆$/u,
|
|
2888
|
+
/^show memory page\s+(\d+)$/iu
|
|
2889
|
+
];
|
|
2890
|
+
var INSPECT_PATTERNS = [
|
|
2891
|
+
/^查看记忆\s+(\S+)$/u,
|
|
2892
|
+
/^show memory\s+(\S+)$/iu
|
|
2893
|
+
];
|
|
2894
|
+
var REMOVE_PATTERNS = [
|
|
2895
|
+
/^忘掉\s+(\S+)$/u,
|
|
2896
|
+
/^删除\s+(\S+)$/u,
|
|
2897
|
+
/^删掉\s+(\S+)$/u,
|
|
2898
|
+
/^forget\s+(\S+)$/iu,
|
|
2899
|
+
/^delete\s+(\S+)$/iu,
|
|
2900
|
+
/^remove\s+(\S+)$/iu
|
|
2901
|
+
];
|
|
2902
|
+
var UPDATE_PATTERNS = [
|
|
2903
|
+
/^把\s+(\S+)\s+改成\s*(.+)$/su,
|
|
2904
|
+
/^更新\s+(\S+)\s+为\s*(.+)$/su,
|
|
2905
|
+
/^update\s+(\S+)\s+to\s+(.+)$/isu,
|
|
2906
|
+
/^change\s+(\S+)\s+to\s+(.+)$/isu
|
|
2907
|
+
];
|
|
2908
|
+
var MEMORY_ID_PATTERN = /^m-[a-f0-9]{12}$/u;
|
|
2491
2909
|
var CLEAR_REQUEST_PATTERNS = [
|
|
2492
2910
|
/^清空记忆$/u,
|
|
2493
2911
|
/^清除记忆$/u,
|
|
@@ -2510,14 +2928,41 @@ function parseChannelMemoryIntent(text) {
|
|
|
2510
2928
|
return { kind: "clear_confirm" };
|
|
2511
2929
|
}
|
|
2512
2930
|
}
|
|
2931
|
+
for (const pattern of REMOVE_PATTERNS) {
|
|
2932
|
+
const match = trimmed.match(pattern);
|
|
2933
|
+
if (match?.[1] && MEMORY_ID_PATTERN.test(match[1])) {
|
|
2934
|
+
return { kind: "remove", id: match[1] };
|
|
2935
|
+
}
|
|
2936
|
+
}
|
|
2937
|
+
for (const pattern of UPDATE_PATTERNS) {
|
|
2938
|
+
const match = trimmed.match(pattern);
|
|
2939
|
+
const id = match?.[1];
|
|
2940
|
+
const updated = match?.[2]?.trim();
|
|
2941
|
+
if (id && updated && MEMORY_ID_PATTERN.test(id)) {
|
|
2942
|
+
return { kind: "update", id, text: updated };
|
|
2943
|
+
}
|
|
2944
|
+
}
|
|
2513
2945
|
for (const pattern of CLEAR_REQUEST_PATTERNS) {
|
|
2514
2946
|
if (pattern.test(trimmed)) {
|
|
2515
2947
|
return { kind: "clear_request" };
|
|
2516
2948
|
}
|
|
2517
2949
|
}
|
|
2950
|
+
for (const pattern of INSPECT_PATTERNS) {
|
|
2951
|
+
const match = trimmed.match(pattern);
|
|
2952
|
+
if (match?.[1] && MEMORY_ID_PATTERN.test(match[1])) {
|
|
2953
|
+
return { kind: "inspect", id: match[1] };
|
|
2954
|
+
}
|
|
2955
|
+
}
|
|
2956
|
+
for (const pattern of LIST_PAGE_PATTERNS) {
|
|
2957
|
+
const match = trimmed.match(pattern);
|
|
2958
|
+
if (match?.[1]) {
|
|
2959
|
+
const page = Number(match[1]);
|
|
2960
|
+
return Number.isSafeInteger(page) && page > 0 ? { kind: "list", page } : null;
|
|
2961
|
+
}
|
|
2962
|
+
}
|
|
2518
2963
|
for (const pattern of LIST_PATTERNS) {
|
|
2519
2964
|
if (pattern.test(trimmed)) {
|
|
2520
|
-
return { kind: "list" };
|
|
2965
|
+
return { kind: "list", page: 1 };
|
|
2521
2966
|
}
|
|
2522
2967
|
}
|
|
2523
2968
|
for (const pattern of REMEMBER_PATTERNS) {
|
|
@@ -2539,8 +2984,10 @@ var GROUP_HISTORY_ENTRY_TEXT_LIMIT = 1e3;
|
|
|
2539
2984
|
var GROUP_HISTORY_ENTRY_METADATA_LIMIT = 256;
|
|
2540
2985
|
var LOOP_CANCEL_GRACE_MS = 5e3;
|
|
2541
2986
|
var CHANNEL_MEMORY_PROMPT_CODE_POINT_LIMIT = 12e3;
|
|
2987
|
+
var CHANNEL_MEMORY_PAGE_SIZE = 20;
|
|
2988
|
+
var CHANNEL_MEMORY_PREVIEW_CODE_POINT_LIMIT = 160;
|
|
2542
2989
|
var CHANNEL_MEMORY_CLASSIFIER_MIN_CONFIDENCE = 0.7;
|
|
2543
|
-
var CHANNEL_MEMORY_CLASSIFIER_TRIGGER_RE = /(
|
|
2990
|
+
var CHANNEL_MEMORY_CLASSIFIER_TRIGGER_RE = /(?:记住|记得|记一下|记忆|忘掉|忘记|清空|清除|删除|删掉|改成|更新|刚才那条|保存|(?:只|仅)(?:看|列出)[\p{Script=Han}\s]{0,12}(?:偏好|习惯)|\b(?:remember|memory|forget|delete|remove|update|change)\b)/iu;
|
|
2544
2991
|
var LOOP_TIMED_OUT_MESSAGE = "loop timed out";
|
|
2545
2992
|
var DEBUG_PAYLOAD_ENV = "QWEN_CHANNEL_DEBUG_PAYLOAD";
|
|
2546
2993
|
var DEBUG_PAYLOAD_LIMIT = 12e3;
|
|
@@ -2750,7 +3197,7 @@ var ChannelBase = class {
|
|
|
2750
3197
|
this.memoryScope = Object.freeze(this.resolveMemoryScope(name, config));
|
|
2751
3198
|
this.channelMemory = options?.channelMemory;
|
|
2752
3199
|
this.memoryIntentClassifier = options?.memoryIntentClassifier;
|
|
2753
|
-
this.groupHistory = new GroupHistoryStore(options?.groupHistoryPath ??
|
|
3200
|
+
this.groupHistory = new GroupHistoryStore(options?.groupHistoryPath ?? join5(getGlobalQwenDir(), "channels", `${encodeURIComponent(name)}-group-history.jsonl`));
|
|
2754
3201
|
this.loopController = options?.loopController;
|
|
2755
3202
|
this.groupGate = new GroupGate(config.groupPolicy, config.groups);
|
|
2756
3203
|
this.dmGate = new DmGate(config.dmPolicy);
|
|
@@ -2862,6 +3309,9 @@ var ChannelBase = class {
|
|
|
2862
3309
|
supportsProactiveTarget(target) {
|
|
2863
3310
|
return target.threadId === void 0;
|
|
2864
3311
|
}
|
|
3312
|
+
supportsProactiveWebhookTarget(target) {
|
|
3313
|
+
return this.supportsProactiveTarget(target);
|
|
3314
|
+
}
|
|
2865
3315
|
async pushProactive(target, text) {
|
|
2866
3316
|
if (target.threadId) {
|
|
2867
3317
|
throw new Error("Channel does not support proactive loop messages for threaded targets.");
|
|
@@ -3147,7 +3597,7 @@ ${sanitizePromptText(job.prompt)}`;
|
|
|
3147
3597
|
throw new Error(`Unknown webhook source "${task.source}".`);
|
|
3148
3598
|
}
|
|
3149
3599
|
const target = resolveChannelWebhookTarget(this.name, this.config.webhooks, task.source, task.targetRef);
|
|
3150
|
-
if (!this.
|
|
3600
|
+
if (!this.supportsProactiveWebhookTarget(target)) {
|
|
3151
3601
|
throw new Error("Channel does not support proactive webhook messages for this chat target.");
|
|
3152
3602
|
}
|
|
3153
3603
|
return target;
|
|
@@ -3444,7 +3894,7 @@ ${sanitizePromptText(job.prompt)}`;
|
|
|
3444
3894
|
onToolCall(_chatId, _event) {
|
|
3445
3895
|
}
|
|
3446
3896
|
onSessionDied(sessionId) {
|
|
3447
|
-
this.router.
|
|
3897
|
+
this.router.handleSessionDied(sessionId);
|
|
3448
3898
|
this.instructedSessions.delete(sessionId);
|
|
3449
3899
|
this.removePendingPermissionsForSession(sessionId);
|
|
3450
3900
|
}
|
|
@@ -3492,13 +3942,16 @@ ${sanitizePromptText(job.prompt)}`;
|
|
|
3492
3942
|
*/
|
|
3493
3943
|
onResponseBoundary(_chatId, _sessionId) {
|
|
3494
3944
|
}
|
|
3945
|
+
async sendResponseMessage(chatId, text, _sessionId) {
|
|
3946
|
+
await this.sendMessage(chatId, text);
|
|
3947
|
+
}
|
|
3495
3948
|
/**
|
|
3496
3949
|
* Called when the agent's full response is ready.
|
|
3497
3950
|
* Override to customize delivery (e.g., finalize an AI card).
|
|
3498
|
-
* Default:
|
|
3951
|
+
* Default: sends the full response text.
|
|
3499
3952
|
*/
|
|
3500
|
-
async onResponseComplete(chatId, fullText,
|
|
3501
|
-
await this.
|
|
3953
|
+
async onResponseComplete(chatId, fullText, sessionId) {
|
|
3954
|
+
await this.sendResponseMessage(chatId, fullText, sessionId);
|
|
3502
3955
|
}
|
|
3503
3956
|
/**
|
|
3504
3957
|
* Register a slash command handler. Subclasses can call this to add
|
|
@@ -3775,30 +4228,6 @@ ${requestList}`);
|
|
|
3775
4228
|
this.registerCommand("approve", (envelope, args) => this.handlePermissionResponseCommand(envelope, args, "approve"));
|
|
3776
4229
|
this.registerCommand("approve-always", (envelope, args) => this.handlePermissionResponseCommand(envelope, args, "approve-always"));
|
|
3777
4230
|
this.registerCommand("deny", (envelope, args) => this.handlePermissionResponseCommand(envelope, args, "deny"));
|
|
3778
|
-
this.registerCommand("remember-channel", async (envelope, args) => {
|
|
3779
|
-
const text = args.trim();
|
|
3780
|
-
if (text === "") {
|
|
3781
|
-
await this.sendMessage(envelope.chatId, "Usage: /remember-channel <text>");
|
|
3782
|
-
return true;
|
|
3783
|
-
}
|
|
3784
|
-
await this.handleChannelMemoryIntent(envelope, {
|
|
3785
|
-
kind: "remember",
|
|
3786
|
-
text
|
|
3787
|
-
});
|
|
3788
|
-
return true;
|
|
3789
|
-
});
|
|
3790
|
-
this.registerCommand("channel-memory", async (envelope) => {
|
|
3791
|
-
await this.handleChannelMemoryIntent(envelope, { kind: "list" });
|
|
3792
|
-
return true;
|
|
3793
|
-
});
|
|
3794
|
-
this.registerCommand("forget-channel", async (envelope, args) => {
|
|
3795
|
-
if (args.toLowerCase() !== "confirm") {
|
|
3796
|
-
await this.sendMessage(envelope.chatId, 'This clears channel memory for this chat. Re-send with "confirm" (e.g. /forget-channel confirm) to proceed.');
|
|
3797
|
-
return true;
|
|
3798
|
-
}
|
|
3799
|
-
await this.handleChannelMemoryIntent(envelope, { kind: "clear_confirm" }, { skipPendingClear: true });
|
|
3800
|
-
return true;
|
|
3801
|
-
});
|
|
3802
4231
|
this.registerCommand("who", async (envelope) => {
|
|
3803
4232
|
if (!this.isAuthorizedForSharedSession(envelope)) {
|
|
3804
4233
|
await this.sendMessage(envelope.chatId, "Only authorized members can view this shared session.");
|
|
@@ -4253,7 +4682,60 @@ ${requestList}`);
|
|
|
4253
4682
|
}
|
|
4254
4683
|
return this.channelMemory;
|
|
4255
4684
|
}
|
|
4256
|
-
|
|
4685
|
+
entriesForChannelMemoryIds(entries, ids) {
|
|
4686
|
+
const selected = new Set(ids);
|
|
4687
|
+
return entries.filter((entry) => selected.has(entry.id));
|
|
4688
|
+
}
|
|
4689
|
+
renderChannelMemoryCandidate(entry) {
|
|
4690
|
+
const preview = truncateCodePoints(sanitizePromptText(entry.text).replace(/[\r\n]+/gu, " ").trim(), CHANNEL_MEMORY_PREVIEW_CODE_POINT_LIMIT);
|
|
4691
|
+
return `${entry.id} ${preview}`;
|
|
4692
|
+
}
|
|
4693
|
+
renderChannelMemoryCandidates(entries) {
|
|
4694
|
+
return entries.map((entry) => this.renderChannelMemoryCandidate(entry));
|
|
4695
|
+
}
|
|
4696
|
+
async handleChannelMemoryIntent(envelope, intent) {
|
|
4697
|
+
if (intent.kind === "no_match") {
|
|
4698
|
+
await this.sendMessage(envelope.chatId, "No matching channel memory entry.");
|
|
4699
|
+
return;
|
|
4700
|
+
}
|
|
4701
|
+
if (intent.kind === "ambiguous") {
|
|
4702
|
+
const channelMemory2 = await this.getChannelMemory(envelope);
|
|
4703
|
+
if (!channelMemory2)
|
|
4704
|
+
return;
|
|
4705
|
+
let entries;
|
|
4706
|
+
try {
|
|
4707
|
+
entries = await channelMemory2.listChannelMemoryEntries(this.channelMemoryTarget(envelope));
|
|
4708
|
+
} catch (error) {
|
|
4709
|
+
this.logChannelMemoryError("read", envelope, this.channelMemoryErrorMessage(error));
|
|
4710
|
+
await this.sendMessage(envelope.chatId, `Failed to read channel memory: ${this.channelMemoryUserErrorMessage()}`);
|
|
4711
|
+
return;
|
|
4712
|
+
}
|
|
4713
|
+
const selected = this.entriesForChannelMemoryIds(entries, intent.ids);
|
|
4714
|
+
await this.sendMessage(envelope.chatId, [
|
|
4715
|
+
"Multiple channel memory entries match:",
|
|
4716
|
+
...this.renderChannelMemoryCandidates(selected)
|
|
4717
|
+
].join("\n"));
|
|
4718
|
+
return;
|
|
4719
|
+
}
|
|
4720
|
+
if (intent.kind === "list_matches") {
|
|
4721
|
+
const channelMemory2 = await this.getChannelMemory(envelope);
|
|
4722
|
+
if (!channelMemory2)
|
|
4723
|
+
return;
|
|
4724
|
+
let entries;
|
|
4725
|
+
try {
|
|
4726
|
+
entries = await channelMemory2.listChannelMemoryEntries(this.channelMemoryTarget(envelope));
|
|
4727
|
+
} catch (error) {
|
|
4728
|
+
this.logChannelMemoryError("read", envelope, this.channelMemoryErrorMessage(error));
|
|
4729
|
+
await this.sendMessage(envelope.chatId, `Failed to read channel memory: ${this.channelMemoryUserErrorMessage()}`);
|
|
4730
|
+
return;
|
|
4731
|
+
}
|
|
4732
|
+
const selected = this.entriesForChannelMemoryIds(entries, intent.ids);
|
|
4733
|
+
await this.sendMessage(envelope.chatId, [
|
|
4734
|
+
"Channel memory (page 1/1):",
|
|
4735
|
+
...this.renderChannelMemoryCandidates(selected)
|
|
4736
|
+
].join("\n"));
|
|
4737
|
+
return;
|
|
4738
|
+
}
|
|
4257
4739
|
if (intent.kind === "clear_request") {
|
|
4258
4740
|
this.setPendingClear(this.clearPendingKey(envelope));
|
|
4259
4741
|
await this.sendMessage(envelope.chatId, 'This clears channel memory for this chat. Say "\u786E\u8BA4\u6E05\u7A7A\u8BB0\u5FC6" or "confirm clear memory" to proceed.');
|
|
@@ -4264,40 +4746,96 @@ ${requestList}`);
|
|
|
4264
4746
|
return;
|
|
4265
4747
|
}
|
|
4266
4748
|
if (intent.kind === "remember") {
|
|
4749
|
+
let result;
|
|
4267
4750
|
try {
|
|
4268
|
-
await channelMemory.
|
|
4751
|
+
result = await channelMemory.addChannelMemoryEntries(this.channelMemoryTarget(envelope), [intent.text], envelope.senderId);
|
|
4269
4752
|
} catch (error) {
|
|
4270
4753
|
const message = this.channelMemoryErrorMessage(error);
|
|
4271
4754
|
this.logChannelMemoryError("save", envelope, message);
|
|
4272
4755
|
await this.sendMessage(envelope.chatId, `Failed to save channel memory: ${this.channelMemoryUserErrorMessage()}`);
|
|
4273
4756
|
return;
|
|
4274
4757
|
}
|
|
4275
|
-
|
|
4276
|
-
|
|
4758
|
+
if (result.changed) {
|
|
4759
|
+
this.invalidateSessionContext(envelope);
|
|
4760
|
+
}
|
|
4761
|
+
if (result.added.length > 0) {
|
|
4762
|
+
const ids = result.added.map((entry) => entry.id);
|
|
4763
|
+
await this.sendMessage(envelope.chatId, ids.length === 1 ? `Channel memory ${ids[0]} saved.` : `Channel memory saved: ${ids.join(", ")}.`);
|
|
4764
|
+
} else if (result.duplicateIds.length > 0) {
|
|
4765
|
+
await this.sendMessage(envelope.chatId, `Channel memory already contains ${result.duplicateIds.join(", ")}.`);
|
|
4766
|
+
} else {
|
|
4767
|
+
await this.sendMessage(envelope.chatId, "Channel memory updated.");
|
|
4768
|
+
}
|
|
4277
4769
|
return;
|
|
4278
4770
|
}
|
|
4279
|
-
if (intent.kind === "list") {
|
|
4280
|
-
let
|
|
4771
|
+
if (intent.kind === "list" || intent.kind === "inspect") {
|
|
4772
|
+
let entries;
|
|
4281
4773
|
try {
|
|
4282
|
-
|
|
4774
|
+
entries = await channelMemory.listChannelMemoryEntries(this.channelMemoryTarget(envelope));
|
|
4283
4775
|
} catch (error) {
|
|
4284
4776
|
const message = this.channelMemoryErrorMessage(error);
|
|
4285
4777
|
this.logChannelMemoryError("read", envelope, message);
|
|
4286
4778
|
await this.sendMessage(envelope.chatId, `Failed to read channel memory: ${this.channelMemoryUserErrorMessage()}`);
|
|
4287
4779
|
return;
|
|
4288
4780
|
}
|
|
4289
|
-
|
|
4781
|
+
if (intent.kind === "inspect") {
|
|
4782
|
+
const entry = entries.find((candidate) => candidate.id === intent.id);
|
|
4783
|
+
await this.sendMessage(envelope.chatId, entry ? `Channel memory ${entry.id}:
|
|
4784
|
+
${sanitizePromptText(entry.text).trim()}` : `No channel memory entry ${intent.id}.`);
|
|
4785
|
+
return;
|
|
4786
|
+
}
|
|
4787
|
+
const totalPages = Math.max(1, Math.ceil(entries.length / CHANNEL_MEMORY_PAGE_SIZE));
|
|
4788
|
+
if (intent.page > totalPages) {
|
|
4789
|
+
await this.sendMessage(envelope.chatId, `Channel memory page ${intent.page} does not exist.`);
|
|
4790
|
+
return;
|
|
4791
|
+
}
|
|
4792
|
+
if (entries.length === 0) {
|
|
4793
|
+
await this.sendMessage(envelope.chatId, "No channel memory saved.");
|
|
4794
|
+
return;
|
|
4795
|
+
}
|
|
4796
|
+
const pageStart = (intent.page - 1) * CHANNEL_MEMORY_PAGE_SIZE;
|
|
4797
|
+
const lines = entries.slice(pageStart, pageStart + CHANNEL_MEMORY_PAGE_SIZE).map((entry) => this.renderChannelMemoryCandidate(entry));
|
|
4798
|
+
await this.sendMessage(envelope.chatId, [`Channel memory (page ${intent.page}/${totalPages}):`, ...lines].join("\n"));
|
|
4290
4799
|
return;
|
|
4291
4800
|
}
|
|
4292
|
-
if (intent.kind === "
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
if (
|
|
4298
|
-
await this.
|
|
4299
|
-
|
|
4801
|
+
if (intent.kind === "update" || intent.kind === "remove" || intent.kind === "natural_update" || intent.kind === "natural_remove") {
|
|
4802
|
+
let changed;
|
|
4803
|
+
const isUpdate = intent.kind === "update" || intent.kind === "natural_update";
|
|
4804
|
+
const id = intent.id;
|
|
4805
|
+
try {
|
|
4806
|
+
if (isUpdate) {
|
|
4807
|
+
({ changed } = await channelMemory.updateChannelMemoryEntry(this.channelMemoryTarget(envelope), intent.kind === "natural_update" ? {
|
|
4808
|
+
id: intent.id,
|
|
4809
|
+
text: intent.text,
|
|
4810
|
+
expectedText: intent.expectedText
|
|
4811
|
+
} : { id: intent.id, text: intent.text }));
|
|
4812
|
+
} else {
|
|
4813
|
+
({ changed } = await channelMemory.removeChannelMemoryEntries(this.channelMemoryTarget(envelope), intent.kind === "natural_remove" ? {
|
|
4814
|
+
ids: [intent.id],
|
|
4815
|
+
expectedTextById: { [intent.id]: intent.expectedText }
|
|
4816
|
+
} : { ids: [intent.id] }));
|
|
4300
4817
|
}
|
|
4818
|
+
} catch (error) {
|
|
4819
|
+
const message = this.channelMemoryErrorMessage(error);
|
|
4820
|
+
this.logChannelMemoryError(isUpdate ? "update" : "remove", envelope, message);
|
|
4821
|
+
await this.sendMessage(envelope.chatId, `Failed to ${isUpdate ? "update" : "remove"} channel memory: ${this.channelMemoryUserErrorMessage()}`);
|
|
4822
|
+
return;
|
|
4823
|
+
}
|
|
4824
|
+
if (!changed) {
|
|
4825
|
+
await this.sendMessage(envelope.chatId, `No channel memory entry ${id}.`);
|
|
4826
|
+
return;
|
|
4827
|
+
}
|
|
4828
|
+
this.invalidateSessionContext(envelope);
|
|
4829
|
+
await this.sendMessage(envelope.chatId, `Channel memory ${id} ${isUpdate ? "updated" : "removed"}.`);
|
|
4830
|
+
return;
|
|
4831
|
+
}
|
|
4832
|
+
if (intent.kind === "clear_confirm") {
|
|
4833
|
+
const pendingKey = this.clearPendingKey(envelope);
|
|
4834
|
+
const expiresAt = this.pendingClears.get(pendingKey);
|
|
4835
|
+
this.pendingClears.delete(pendingKey);
|
|
4836
|
+
if (expiresAt === void 0 || expiresAt < Date.now()) {
|
|
4837
|
+
await this.sendMessage(envelope.chatId, 'No pending clear request. Say "\u6E05\u7A7A\u8BB0\u5FC6" first.');
|
|
4838
|
+
return;
|
|
4301
4839
|
}
|
|
4302
4840
|
let result;
|
|
4303
4841
|
try {
|
|
@@ -4308,7 +4846,9 @@ ${requestList}`);
|
|
|
4308
4846
|
await this.sendMessage(envelope.chatId, `Failed to clear channel memory: ${this.channelMemoryUserErrorMessage()}`);
|
|
4309
4847
|
return;
|
|
4310
4848
|
}
|
|
4311
|
-
|
|
4849
|
+
if (result.changed) {
|
|
4850
|
+
this.invalidateSessionContext(envelope);
|
|
4851
|
+
}
|
|
4312
4852
|
await this.sendMessage(envelope.chatId, result.changed ? "Channel memory cleared." : "No channel memory saved.");
|
|
4313
4853
|
return;
|
|
4314
4854
|
}
|
|
@@ -4331,31 +4871,82 @@ ${requestList}`);
|
|
|
4331
4871
|
}
|
|
4332
4872
|
this.pendingClears.set(key, now + 6e4);
|
|
4333
4873
|
}
|
|
4334
|
-
async classifyChannelMemoryIntent(
|
|
4335
|
-
if (!this.memoryIntentClassifier) {
|
|
4874
|
+
async classifyChannelMemoryIntent(envelope) {
|
|
4875
|
+
if (!this.memoryIntentClassifier || !this.channelMemory) {
|
|
4876
|
+
return null;
|
|
4877
|
+
}
|
|
4878
|
+
let entries;
|
|
4879
|
+
try {
|
|
4880
|
+
entries = await this.channelMemory.listChannelMemoryEntries(this.channelMemoryTarget(envelope));
|
|
4881
|
+
} catch (error) {
|
|
4882
|
+
this.logChannelMemoryError("read", envelope, this.channelMemoryErrorMessage(error));
|
|
4336
4883
|
return null;
|
|
4337
4884
|
}
|
|
4338
4885
|
let classified;
|
|
4339
4886
|
try {
|
|
4340
|
-
classified = await this.memoryIntentClassifier.classifyChannelMemoryIntent(text);
|
|
4887
|
+
classified = await this.memoryIntentClassifier.classifyChannelMemoryIntent(envelope.text, entries);
|
|
4341
4888
|
} catch (error) {
|
|
4342
4889
|
process.stderr.write(`[${this.name}] channel memory intent classifier failed: ${sanitizeLogText(this.channelMemoryErrorMessage(error), 200)}
|
|
4343
4890
|
`);
|
|
4344
4891
|
return null;
|
|
4345
4892
|
}
|
|
4346
|
-
|
|
4893
|
+
const confidence = classified && typeof classified === "object" ? classified.confidence : void 0;
|
|
4894
|
+
if (typeof confidence !== "number" || !Number.isFinite(confidence) || confidence < 0 || confidence > 1 || confidence < CHANNEL_MEMORY_CLASSIFIER_MIN_CONFIDENCE) {
|
|
4347
4895
|
return null;
|
|
4348
4896
|
}
|
|
4349
|
-
|
|
4350
|
-
|
|
4897
|
+
const result = classified;
|
|
4898
|
+
const targetIds = result.targetIds;
|
|
4899
|
+
const entryById = new Map(entries.map((entry2) => [entry2.id, entry2]));
|
|
4900
|
+
const resolvedEntries = targetIds === void 0 ? void 0 : Array.isArray(targetIds) && targetIds.every((id) => typeof id === "string" && entryById.has(id)) && new Set(targetIds).size === targetIds.length ? this.entriesForChannelMemoryIds(entries, targetIds) : null;
|
|
4901
|
+
if (result.intent === "remember") {
|
|
4902
|
+
const memory = typeof result.memory === "string" ? result.memory.trim() : "";
|
|
4351
4903
|
return memory ? { kind: "remember", text: memory } : null;
|
|
4352
4904
|
}
|
|
4353
|
-
if (
|
|
4354
|
-
|
|
4905
|
+
if (result.intent === "list") {
|
|
4906
|
+
if (resolvedEntries === void 0)
|
|
4907
|
+
return { kind: "list", page: 1 };
|
|
4908
|
+
if (resolvedEntries === null)
|
|
4909
|
+
return null;
|
|
4910
|
+
return resolvedEntries.length === 0 ? { kind: "no_match" } : {
|
|
4911
|
+
kind: "list_matches",
|
|
4912
|
+
ids: resolvedEntries.map((entry2) => entry2.id)
|
|
4913
|
+
};
|
|
4355
4914
|
}
|
|
4356
|
-
if (
|
|
4915
|
+
if (result.intent === "clear_all") {
|
|
4357
4916
|
return { kind: "clear_request" };
|
|
4358
4917
|
}
|
|
4918
|
+
if (result.intent !== "inspect" && result.intent !== "update" && result.intent !== "remove") {
|
|
4919
|
+
return null;
|
|
4920
|
+
}
|
|
4921
|
+
if (resolvedEntries === null || resolvedEntries === void 0)
|
|
4922
|
+
return null;
|
|
4923
|
+
if (resolvedEntries.length === 0)
|
|
4924
|
+
return { kind: "no_match" };
|
|
4925
|
+
if (resolvedEntries.length > 1) {
|
|
4926
|
+
return {
|
|
4927
|
+
kind: "ambiguous",
|
|
4928
|
+
ids: resolvedEntries.map((entry2) => entry2.id)
|
|
4929
|
+
};
|
|
4930
|
+
}
|
|
4931
|
+
const entry = resolvedEntries[0];
|
|
4932
|
+
if (result.intent === "inspect")
|
|
4933
|
+
return { kind: "inspect", id: entry.id };
|
|
4934
|
+
if (result.intent === "remove") {
|
|
4935
|
+
return {
|
|
4936
|
+
kind: "natural_remove",
|
|
4937
|
+
id: entry.id,
|
|
4938
|
+
expectedText: entry.text
|
|
4939
|
+
};
|
|
4940
|
+
}
|
|
4941
|
+
const text = typeof result.memory === "string" ? result.memory.trim() : "";
|
|
4942
|
+
if (text) {
|
|
4943
|
+
return {
|
|
4944
|
+
kind: "natural_update",
|
|
4945
|
+
id: entry.id,
|
|
4946
|
+
text,
|
|
4947
|
+
expectedText: entry.text
|
|
4948
|
+
};
|
|
4949
|
+
}
|
|
4359
4950
|
return null;
|
|
4360
4951
|
}
|
|
4361
4952
|
channelMemoryErrorMessage(error) {
|
|
@@ -4687,7 +5278,7 @@ ${promptText}`;
|
|
|
4687
5278
|
}
|
|
4688
5279
|
let memoryIntent = parseChannelMemoryIntent(envelope.text);
|
|
4689
5280
|
if (!memoryIntent && this.shouldClassifyChannelMemoryIntent(envelope.text)) {
|
|
4690
|
-
memoryIntent = await this.classifyChannelMemoryIntent(envelope
|
|
5281
|
+
memoryIntent = await this.classifyChannelMemoryIntent(envelope);
|
|
4691
5282
|
}
|
|
4692
5283
|
if (memoryIntent) {
|
|
4693
5284
|
await this.handleChannelMemoryIntent(envelope, memoryIntent);
|
|
@@ -4909,12 +5500,14 @@ ${promptToSend}`;
|
|
|
4909
5500
|
minChars: this.config.blockStreamingChunk?.minChars ?? 400,
|
|
4910
5501
|
maxChars: this.config.blockStreamingChunk?.maxChars ?? 1e3,
|
|
4911
5502
|
idleMs: this.config.blockStreamingCoalesce?.idleMs ?? 1500,
|
|
4912
|
-
send: /* @__PURE__ */ __name((text) => this.
|
|
5503
|
+
send: /* @__PURE__ */ __name((text) => this.sendResponseMessage(envelope.chatId, text, sessionId), "send")
|
|
4913
5504
|
}) : null;
|
|
4914
5505
|
promptState.stopStreaming = () => streamer?.stop();
|
|
4915
5506
|
const heldChunks = [];
|
|
5507
|
+
let hasStreamedText = false;
|
|
4916
5508
|
const releaseHeldChunks = /* @__PURE__ */ __name(() => {
|
|
4917
5509
|
for (const held of heldChunks.splice(0)) {
|
|
5510
|
+
hasStreamedText = true;
|
|
4918
5511
|
this.emitTaskLifecycle({
|
|
4919
5512
|
...this.lifecycleBase(envelope.chatId, sessionId, envelope.messageId),
|
|
4920
5513
|
type: "text_chunk",
|
|
@@ -4938,6 +5531,7 @@ ${promptToSend}`;
|
|
|
4938
5531
|
return;
|
|
4939
5532
|
}
|
|
4940
5533
|
heldChunks.length = 0;
|
|
5534
|
+
hasStreamedText = false;
|
|
4941
5535
|
this.onResponseBoundary(envelope.chatId, sessionId);
|
|
4942
5536
|
streamer?.stop();
|
|
4943
5537
|
}, "onResponseBoundary");
|
|
@@ -4956,6 +5550,9 @@ ${promptToSend}`;
|
|
|
4956
5550
|
if (!promptState.cancelled && response) {
|
|
4957
5551
|
promptState.deliveryStarted = true;
|
|
4958
5552
|
if (streamer) {
|
|
5553
|
+
if (!hasStreamedText) {
|
|
5554
|
+
streamer.push(response);
|
|
5555
|
+
}
|
|
4959
5556
|
await streamer.flush();
|
|
4960
5557
|
} else {
|
|
4961
5558
|
await this.onResponseComplete(envelope.chatId, response, sessionId);
|