nolo-cli 0.148.0-alpha.1 → 0.151.0-alpha.2
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/{_executeModel-NFJAMAGJ.js → _executeModel-XHAFJ2MM.js} +134 -91
- package/accountResolver-7RYB4D2P.js +300 -0
- package/action-SXJD5N5R.js +23 -0
- package/{addContentAction-B2DRF7P6.js → addContentAction-ZV774PHH.js} +20 -14
- package/{addDialogAgentAction-2P2FLTLD.js → addDialogAgentAction-A6SMKAGH.js} +26 -22
- package/{agentDeleteCommand-7IDWF6E3.js → agentDeleteCommand-DPUUS56Z.js} +181 -93
- package/{agentEmailCommands-4KW33JII.js → agentEmailCommands-V4P5EFLP.js} +132 -112
- package/{agentGrantCommands-M3XFO6EN.js → agentGrantCommands-HOJ3JBBQ.js} +3 -3
- package/agentListCommands-TWFLUYIZ.js +802 -0
- package/{agentMachineCommands-CMQR4RQ4.js → agentMachineCommands-MELPAZZI.js} +58 -62
- package/{agentProviderCommands-YK2BIIXZ.js → agentProviderCommands-HL6MBLCL.js} +149 -2
- package/{agentPullCommand-HF4A42D4.js → agentPullCommand-FA43RBRU.js} +7 -7
- package/agentRecordCommands-FSWSSQIO.js +154 -0
- package/agentRunCommand-GDBJVOAT.js +183 -0
- package/{agentRunControl-2SKCR4SB.js → agentRunControl-IFM7IGMG.js} +10 -2
- package/{agentRuntimeLocal-AK2QVJHY.js → agentRuntimeLocal-KKSQJMTE.js} +47 -50
- package/{agentSlice-OZ33K224.js → agentSlice-YO2ZLJMD.js} +23 -16
- package/{appDeleteCommands-N3XEVVYC.js → appDeleteCommands-4PL4KYRN.js} +58 -59
- package/{appDeployCommands-AWFIXYVW.js → appDeployCommands-EEEXCEB6.js} +67 -63
- package/{appDeployStatusCommands-CZRON2FO.js → appDeployStatusCommands-35ZX7T66.js} +56 -56
- package/{appGetCommands-XQIUY4TD.js → appGetCommands-WFCHXJWF.js} +56 -56
- package/{appListCommands-NNG4H36Y.js → appListCommands-XY2U6DPF.js} +57 -59
- package/{authCommand-UBJ4EWYZ.js → authCommand-QYN47CQD.js} +371 -68
- package/{authCommands-H6WKKCRW.js → authCommands-77CHYBGF.js} +12 -9
- package/{builtinSkillRegistry-ZMF6YGNO.js → builtinSkillRegistry-TDQ6JB2E.js} +13 -11
- package/{chromeCommands-2N6MEWRU.js → chromeCommands-OBBNJCLS.js} +314 -13
- package/chromeOpsCommands-3Z34RKSE.js +472 -0
- package/{chunk-ALXHV7NK.js → chunk-2GGXHQIW.js} +43 -4
- package/{localRuntimeAuthority-5W6IJRAD.js → chunk-2IXDJNZI.js} +154 -75
- package/{chunk-IVZJWTDI.js → chunk-36OMEXXR.js} +89 -21
- package/{chunk-H6A6X4EK.js → chunk-3MZAGMYY.js} +16 -0
- package/chunk-3PVYUPXK.js +40 -0
- package/chunk-3SZA4U64.js +1192 -0
- package/{chunk-GNMAFAIS.js → chunk-44WXLHFI.js} +1 -1
- package/{chunk-AGGIDPCZ.js → chunk-4JH2UMJR.js} +6 -0
- package/chunk-4LCOCOR5.js +50 -0
- package/chunk-4YRTZIVN.js +871 -0
- package/chunk-556RW72X.js +14110 -0
- package/{chunk-N7J63Q6C.js → chunk-56GBUMO5.js} +10 -1
- package/{chunk-W7XHHYWM.js → chunk-5BHQICF2.js} +5 -1
- package/{chunk-XUWRURDF.js → chunk-5EBLANFT.js} +1 -1
- package/{chunk-3AH7LNUB.js → chunk-5EMSBTQ6.js} +33 -14
- package/{chunk-YRRASA5Q.js → chunk-5MM7NNO6.js} +113 -52
- package/chunk-5MMAK75Q.js +15 -0
- package/{chunk-M5PVFLD4.js → chunk-64K7WX26.js} +90 -21
- package/{chunk-AKG5W4LG.js → chunk-6CCFTVBP.js} +76 -221
- package/chunk-6MJNEXUU.js +614 -0
- package/{chunk-62IL3KQV.js → chunk-6MXDOUMH.js} +15 -3
- package/{chunk-QOKAKDPE.js → chunk-6Q7UTJKR.js} +6 -94
- package/chunk-6QDYSCPW.js +223 -0
- package/{chunk-HYZIYH2H.js → chunk-74RAWNQN.js} +56 -63
- package/chunk-7DPNBQSV.js +9 -0
- package/chunk-7MOXKPHC.js +119 -0
- package/{chunk-523WHFSL.js → chunk-7XKL25PW.js} +1973 -754
- package/{chunk-IAESIMK7.js → chunk-A4MW3YZL.js} +10 -14
- package/chunk-AGIM7IMJ.js +147 -0
- package/{chunk-7CHC4W22.js → chunk-AIZE5TDM.js} +3 -3
- package/{chunk-P4BX6FFU.js → chunk-AOCM7HPT.js} +214 -51
- package/{chunk-5GVBDNTO.js → chunk-AU7AXHUL.js} +1 -1
- package/{chunk-4H22P2JV.js → chunk-AUIJZACN.js} +2073 -1275
- package/{chunk-CIF4X6ZM.js → chunk-AWVFQMOV.js} +25 -3
- package/{chunk-RYZINGPM.js → chunk-BPMPOFWP.js} +347 -235
- package/{chunk-YUNJN43V.js → chunk-BU2YQBV4.js} +215 -28
- package/{chunk-XPRWFQQK.js → chunk-CBHGZRCE.js} +38 -12
- package/{chunk-Y3PMXGLH.js → chunk-CHCS6XPJ.js} +365 -144
- package/chunk-CHOZJMJS.js +78 -0
- package/{chunk-GBRG75BQ.js → chunk-D2MDMY2M.js} +1 -0
- package/{chunk-3SV7RM24.js → chunk-D2QN6CTI.js} +117 -72
- package/{chunk-5TEEECZM.js → chunk-E2AKSW7L.js} +10 -7
- package/{chunk-RSEEDUMS.js → chunk-EDX5XSJM.js} +2 -2
- package/{chunk-BKWMNZ2X.js → chunk-ES633ZS5.js} +280 -98
- package/{chunk-QDSINZM3.js → chunk-EUGTFFO6.js} +2 -23
- package/{chunk-UNYJU5L6.js → chunk-EYLGAEB4.js} +5 -1
- package/{chunk-CU3QB4HW.js → chunk-EYWJT7A2.js} +12 -12
- package/{chunk-BNGW5ASC.js → chunk-EZVK3N5L.js} +66 -18
- package/{chunk-6FGTMQCL.js → chunk-F32Z66T4.js} +6 -10
- package/chunk-FJMRBOPO.js +11507 -0
- package/{chunk-ZOVKKMF6.js → chunk-FY4SDK2E.js} +1 -1
- package/chunk-G6OOUQWJ.js +417 -0
- package/{chunk-PQWU42UQ.js → chunk-GCKHQECX.js} +6 -6
- package/chunk-GKXCHNTE.js +15 -0
- package/{chunk-T7F46O36.js → chunk-GQN2WLAI.js} +20 -11
- package/{chunk-P6GMCCAT.js → chunk-GQV5KHJU.js} +78 -12
- package/{chunk-B2XUQXQX.js → chunk-HIQ4GF53.js} +191 -68
- package/{chunk-YUWMM4US.js → chunk-HKX3ULQB.js} +34 -22
- package/{chunk-GMZLP5DV.js → chunk-HNUWUO75.js} +30 -19
- package/{chunk-5UTFL4QJ.js → chunk-I2ZMGXXF.js} +10 -5
- package/chunk-I42VC5KR.js +15 -0
- package/{chunk-3BXNTXYI.js → chunk-I4SN4NUQ.js} +1199 -56
- package/chunk-IA7TRNNR.js +11 -0
- package/{chunk-WIWM4FE3.js → chunk-IJERIUXS.js} +55 -748
- package/{chunk-CPUFH46E.js → chunk-ILU2NPWY.js} +10 -10
- package/{chunk-SLLGJZDT.js → chunk-ISQL4V7C.js} +4 -4
- package/chunk-IT3ZZRJE.js +12 -0
- package/{chunk-LPVCRQMM.js → chunk-IZ7OJB6K.js} +20 -16
- package/{chunk-DY7ANLKG.js → chunk-JKMLSTZK.js} +43 -12
- package/{chunk-6TPOEJMQ.js → chunk-JZX2XLKC.js} +64 -23
- package/{chunk-27ONFIEY.js → chunk-K2AER7RX.js} +19 -12
- package/{chunk-O2OWEFII.js → chunk-KFHQQ3NO.js} +1 -1
- package/{chunk-QXGPFY6J.js → chunk-LGN377P3.js} +27 -17
- package/{chunk-L36OWPP3.js → chunk-LIQJTQRN.js} +118 -139
- package/{chunk-FWQEKRTD.js → chunk-LTRUTOHX.js} +36 -31
- package/{chunk-BFU6C242.js → chunk-NMFV26UG.js} +1 -1
- package/{chunk-5J3PYNUP.js → chunk-NYYFIKHI.js} +17 -3
- package/{chunk-6O4IK4V2.js → chunk-OFFL4DCR.js} +1 -1
- package/{chunk-B6SAMB33.js → chunk-OWYYDMGJ.js} +209 -9
- package/{chunk-KQHGZWSV.js → chunk-OXME3PEE.js} +1 -1
- package/{chunk-CTUQJVQM.js → chunk-P5QACQDK.js} +1 -1
- package/{chunk-DIXLJWCD.js → chunk-PCKVQXYV.js} +274 -93
- package/{chunk-4JMDLJAD.js → chunk-PJNFNEJE.js} +114 -37
- package/{chunk-Z4CSIXYP.js → chunk-PLSVXHSA.js} +3 -3
- package/{chunk-BIDGLJQ3.js → chunk-PLXDDGBK.js} +45 -8
- package/chunk-PWTNI4N7.js +47 -0
- package/chunk-QFEW2ULV.js +42 -0
- package/{chunk-RGNEEJ3Y.js → chunk-QLQ573SU.js} +35 -9
- package/chunk-QQ56R7KS.js +88 -0
- package/chunk-QYPE3TS3.js +43 -0
- package/{chunk-4DPP773Q.js → chunk-RSHPU4PD.js} +59 -11
- package/chunk-RVWMAFIT.js +134 -0
- package/{chunk-ESHYE7WU.js → chunk-S73EPYNC.js} +10 -7
- package/{chunk-UQNS32WZ.js → chunk-SCMHQUMK.js} +1 -1
- package/{chunk-T767MPHB.js → chunk-SMENBO3M.js} +354 -120
- package/{chunk-PCVVZ2MH.js → chunk-SSFDFOVT.js} +26 -31
- package/chunk-SW4S4XYB.js +1794 -0
- package/{chunk-HUFPWXFW.js → chunk-T6X3D7NB.js} +572 -430
- package/chunk-TY3TIUJK.js +89 -0
- package/{chunk-X2QRZXZH.js → chunk-TYJ5XFEA.js} +4 -4
- package/{chunk-ALFH24P3.js → chunk-TYYRSFBG.js} +197 -155
- package/{chunk-7KVZ5LDQ.js → chunk-UBUH2TCC.js} +18 -4
- package/chunk-UEILX4EV.js +15 -0
- package/chunk-UHTDNB5Y.js +140 -0
- package/{chunk-YYLHWIW6.js → chunk-UKZX3NHN.js} +1 -1
- package/{chunk-OHOVNO7I.js → chunk-UOKFKFPO.js} +6 -3
- package/{chunk-XISEYOGH.js → chunk-USHQX6VT.js} +5 -5
- package/chunk-UUPR3TD7.js +53 -0
- package/{chunk-HDLLCBRF.js → chunk-VEA7H5FG.js} +2 -2
- package/chunk-VHGD6FHV.js +116 -0
- package/chunk-VIWDGTDA.js +8 -0
- package/{chunk-GOH6RW6F.js → chunk-VJXHL6MH.js} +34 -11
- package/{chunk-4XEYAFLY.js → chunk-VL5KOY2C.js} +623 -94
- package/{chunk-EADNWBAZ.js → chunk-VP3BINY7.js} +13 -0
- package/{chunk-EOARMOVD.js → chunk-W4S6OTSC.js} +6 -3
- package/chunk-WD4XYDYC.js +567 -0
- package/chunk-WJZOQR2J.js +151 -0
- package/{chunk-AUDNYVRC.js → chunk-XETG4RIX.js} +5 -5
- package/{chunk-MX574M24.js → chunk-XI7DGLUK.js} +4 -4
- package/{chunk-3L2WKC3W.js → chunk-XPWGOTBQ.js} +8 -1
- package/chunk-XRUSXPCQ.js +514 -0
- package/{chunk-I4OPU5TK.js → chunk-XS47QOFV.js} +273 -11
- package/{chunk-S5XGT6GB.js → chunk-XZNCX52W.js} +30 -9
- package/{chunk-2JMMBU6V.js → chunk-Y2DXOPSO.js} +1920 -644
- package/{chunk-5OA5HMTL.js → chunk-YLMMECCH.js} +1 -1
- package/{chunk-CFT5HBGW.js → chunk-YVLQXTUB.js} +448 -12
- package/chunk-YVPQATSC.js +709 -0
- package/{chunk-DCFPQW22.js → chunk-Z7OJUX6S.js} +122 -107
- package/chunk-ZEZC7IIM.js +126 -0
- package/{chunk-ALGORS6Y.js → chunk-ZF6526IQ.js} +43 -8
- package/chunk-ZIWPQEFU.js +165 -0
- package/chunk-ZKZ5X2HS.js +7012 -0
- package/chunk-ZRAU6T47.js +56 -0
- package/{cliExecutor-AWYR3T33.js → cliExecutor-BWBF2MTI.js} +4 -3
- package/{clipboardy-BX4NMYHE.js → clipboardy-GCO3GT3I.js} +3 -8
- package/{commandRegistry-YOEQUA7T.js → commandRegistry-XN7C5GHO.js} +183 -107
- package/contentThunks-5L7YQI3S.js +84 -0
- package/{cooldownCommands-ZLEPIB4A.js → cooldownCommands-JFKTYS2D.js} +2 -2
- package/{createAgentAutomationAction-5EJL6ROU.js → createAgentAutomationAction-QOPOLCRK.js} +53 -44
- package/createDialogAction-MZ66VY5Q.js +76 -0
- package/{createPageAction-75ELC64R.js → createPageAction-VQDJIXMY.js} +65 -54
- package/cursorProvider-YGGNMVWX.js +6123 -0
- package/{db-VQSAOWAO.js → db-2QOTXYGH.js} +11 -5
- package/{dbSlice-DQ32LYTJ.js → dbSlice-J37OGIXH.js} +19 -13
- package/{deleteFile-NX6QHCWZ.js → deleteFile-6JWDDRVP.js} +10 -6
- package/dialogCommands-YZLSJB6X.js +113 -0
- package/{dialogSlice-KSXPGJB2.js → dialogSlice-6RODVYCK.js} +53 -39
- package/{docCreateCommands-ZSLGVBZT.js → docCreateCommands-JB2RRMRJ.js} +54 -57
- package/{docDeleteCommands-5N4GVZBG.js → docDeleteCommands-AQENULNM.js} +56 -58
- package/{docReadCommands-YJSAA7AV.js → docReadCommands-DYD25YLQ.js} +53 -56
- package/{docStore-AROBVRCR.js → docStore-ZZA3OPM5.js} +25 -16
- package/{docUpdateCommands-WEMLSW6W.js → docUpdateCommands-3GVS23QL.js} +54 -57
- package/{fetchMessages-67MEFPZR.js → fetchMessages-IIJWQ3HR.js} +5 -4
- package/{getPricing-NMMFT3YI.js → getPricing-FKK3F5EJ.js} +11 -9
- package/{handleSendMessageAction-EGNWHAUB.js → handleSendMessageAction-DVG5U26T.js} +619 -165
- package/index.js +11 -7
- package/{lib-FRRS27KN.js → lib-4YTWAGY7.js} +581 -248
- package/{localDialogRead-EBRS242U.js → localDialogRead-FSOMOPDZ.js} +2 -2
- package/localRuntimeAdapter-HXRHFKRC.js +244 -0
- package/localRuntimeAuthority-JDAD7CB6.js +16 -0
- package/{localRuntimeDb-3LRMNLCM.js → localRuntimeDb-CVC62PM5.js} +1 -1
- package/{machineCommands-ARZYKGGE.js → machineCommands-5KBF4RCC.js} +503 -161
- package/{machineInfo-66ZFUMLE.js → machineInfo-UKPTZO5Y.js} +2 -2
- package/machineWsRunDispatch-4OQDEDOR.js +169 -0
- package/{memberThunks-5ZXPR63F.js → memberThunks-66DH6ABQ.js} +25 -18
- package/{models-ZPU5EDF4.js → models-LAS4B2B5.js} +2 -2
- package/package.json +1 -1
- package/{providerPresetApply-DD6NGWW6.js → providerPresetApply-MY66I6NT.js} +10 -10
- package/{providerRegistry-XDRLMYGJ.js → providerRegistry-QOE2FT57.js} +13 -9
- package/{read-EPTJRAEF.js → read-DC4NUGN6.js} +12 -8
- package/{readDocTool-W4NDXNEX.js → readDocTool-NCJ5NT25.js} +1 -1
- package/{readlineWorkspace-3XOFVARF.js → readlineWorkspace-RIE62QVZ.js} +5022 -921
- package/{removeDialogAgentAction-OSYNZRX7.js → removeDialogAgentAction-E2H3OZU6.js} +29 -28
- package/{runAgentClientLoop-UMF7VZYZ.js → runAgentClientLoop-KLUUXBZS.js} +154 -97
- package/{runtimeDoctorCommands-ID23PNNZ.js → runtimeDoctorCommands-GIOGC5SC.js} +17 -17
- package/secretCommands-ZXZRLR3R.js +700 -0
- package/setDialogExtraReferencesAction-SITRPMYU.js +37 -0
- package/{setPrimaryDialogAgentAction-WZ7KI3YA.js → setPrimaryDialogAgentAction-U7N45TGC.js} +30 -29
- package/{chunk-SONWNI3L.js → settingThunks-Y7SVJOMZ.js} +223 -928
- package/{skillDiscovery-ZBU76COE.js → skillDiscovery-QC35EQY4.js} +2 -2
- package/{slateUtils-RIZES3PV.js → slateUtils-NGV2NMKM.js} +1 -1
- package/{spaceCommands-UJOVU4XI.js → spaceCommands-ZR5BR3GX.js} +59 -59
- package/{streamAgentChatTurn-GYGMYOSM.js → streamAgentChatTurn-MN2SSPGA.js} +309 -165
- package/{switchDialogAgentAction-GMR7WN3P.js → switchDialogAgentAction-OMGBD3N2.js} +26 -22
- package/{tableCommands-G7RV3RU3.js → tableCommands-U3QDY4L6.js} +19 -17
- package/{toolApiClient-CVGWM4PN.js → toolApiClient-7WSJJJBV.js} +6 -5
- package/tools-W2MOLERY.js +124 -0
- package/tuiSummaryLlmCaller-BM3VSTBU.js +130 -0
- package/{updateCommands-4EHDLF5J.js → updateCommands-NQXAGFM7.js} +3 -3
- package/{updateDialogTitleAction-4U5W4AMH.js → updateDialogTitleAction-Z4JX6REN.js} +102 -57
- package/workloadLifecycle-36DXRZKU.js +320 -0
- package/action-GI44T4DR.js +0 -31
- package/agentListCommands-IW3GQVUP.js +0 -427
- package/agentRecordCommands-4YBSYPIY.js +0 -134
- package/agentRunCommand-5MU5X5OT.js +0 -161
- package/browser-image-compression-MFDTD7K6.js +0 -1763
- package/chatQueueReduxAdapter-HVHA2HPM.js +0 -186
- package/chromeOpsCommands-IXRLN57H.js +0 -289
- package/chunk-42Z3EMC4.js +0 -25363
- package/chunk-CQ3WA2NE.js +0 -299
- package/chunk-CYSYR67N.js +0 -93
- package/chunk-IAG4FHOJ.js +0 -34
- package/chunk-JBTJAPUF.js +0 -35
- package/chunk-K2CSUCHJ.js +0 -620
- package/chunk-LTRXGFMS.js +0 -83
- package/chunk-M76ECQRD.js +0 -13658
- package/chunk-MEYIRKDN.js +0 -8967
- package/chunk-OCZKATRC.js +0 -129
- package/chunk-OTGFTBLI.js +0 -13
- package/chunk-PUOC4YRO.js +0 -394
- package/chunk-QU5A4LYX.js +0 -2415
- package/chunk-URMS4XY2.js +0 -10
- package/chunk-UV6VISQJ.js +0 -20
- package/chunk-VJVNU77E.js +0 -83
- package/chunk-WRMKCKZ3.js +0 -13807
- package/chunk-Y5GCAMGP.js +0 -9
- package/chunk-YPREESF4.js +0 -225
- package/contentThunks-AK2F3KNC.js +0 -73
- package/createDialogAction-F5WEWA47.js +0 -66
- package/dialogCommands-G7YBVAMC.js +0 -102
- package/levelLazyShim-GZBKODGI.js +0 -7
- package/machineWsRunDispatch-I7F4L532.js +0 -149
- package/serverStoreFactory-YMXDF4NI.js +0 -20
- package/setDialogExtraReferencesAction-M32UYNCG.js +0 -30
- package/settingSlice-Q6EKL7EQ.js +0 -204
- package/syncMapping-N6RGXGBW.js +0 -437
- package/tools-DU4JXVAV.js +0 -111
- package/tuiSummaryLlmCaller-3YFNHCTW.js +0 -128
- package/{chunk-SV5IJK6K.js → chunk-NBTY7YJF.js} +3 -3
- package/{chunk-2SYTUTLI.js → chunk-YBNHPX4S.js} +3 -3
- package/{offlineMarxistsAgentCommand-HGXZV4XJ.js → offlineMarxistsAgentCommand-2QTHJCHV.js} +4 -4
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
DEVIN_CONNECT_URL,
|
|
3
3
|
parseSseDataLineJson,
|
|
4
4
|
parseSseDataLineObject
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-GQV5KHJU.js";
|
|
6
6
|
import {
|
|
7
7
|
applyChatCompletionDelta,
|
|
8
8
|
applyResponsesToolEvent,
|
|
@@ -11,39 +11,50 @@ import {
|
|
|
11
11
|
flushChatCompletionStream,
|
|
12
12
|
providerHttpFailure,
|
|
13
13
|
throwIfChatCompletionStreamFailed
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-LGN377P3.js";
|
|
15
15
|
import {
|
|
16
16
|
readSseFrames
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-HNUWUO75.js";
|
|
18
|
+
import {
|
|
19
|
+
evaluateFileWritePolicy,
|
|
20
|
+
summarizeToolArguments
|
|
21
|
+
} from "./chunk-CHOZJMJS.js";
|
|
22
|
+
import {
|
|
23
|
+
EXECUTION_BACKEND_KINDS
|
|
24
|
+
} from "./chunk-PWTNI4N7.js";
|
|
18
25
|
import {
|
|
19
26
|
hasImageInRuntimeMessages,
|
|
20
27
|
resolveAgentContextWindow,
|
|
21
28
|
stripImagePartsFromMessages
|
|
22
|
-
} from "./chunk-
|
|
23
|
-
import {
|
|
24
|
-
downgradeUnparsableToolCalls,
|
|
25
|
-
hasParsableObjectArguments,
|
|
26
|
-
repairTruncatedToolArguments,
|
|
27
|
-
sanitizeForOutbound
|
|
28
|
-
} from "./chunk-CQ3WA2NE.js";
|
|
29
|
+
} from "./chunk-UOKFKFPO.js";
|
|
29
30
|
import {
|
|
30
31
|
clipToolText,
|
|
31
32
|
resolveAgentImageInputSupport,
|
|
32
33
|
resolveHistoricalToolContentCap,
|
|
33
34
|
resolveToolOutputProfile
|
|
34
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-GCKHQECX.js";
|
|
35
36
|
import {
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
applyShapingCounts,
|
|
38
|
+
attachProjectionFacts,
|
|
39
|
+
classifyOutboundErrorCategory,
|
|
40
|
+
createOutboundDiagnosticCall,
|
|
41
|
+
createRequestFacts,
|
|
42
|
+
createRequestShapingCounts,
|
|
43
|
+
projectUserPartForModel,
|
|
44
|
+
resolveOutboundDiagnosticSink,
|
|
45
|
+
writeThinkingFacts
|
|
46
|
+
} from "./chunk-G6OOUQWJ.js";
|
|
38
47
|
import {
|
|
39
48
|
createThinkParserState,
|
|
40
49
|
createToolCallAccumulator,
|
|
41
50
|
createToolCallTextParserState,
|
|
42
51
|
extractThinkContent,
|
|
43
52
|
finalizeAccumulatedToolCalls
|
|
44
|
-
} from "./chunk-
|
|
53
|
+
} from "./chunk-56GBUMO5.js";
|
|
45
54
|
import {
|
|
46
55
|
DELETE_SAFETY_RED_LINE,
|
|
56
|
+
PARALLEL_DISPATCH_DEFAULT_RULE,
|
|
57
|
+
PLATFORM_RISK_CONTROL_RULE,
|
|
47
58
|
TOOL_GUIDED_SECTION_ORDER,
|
|
48
59
|
buildIdentityBlock,
|
|
49
60
|
buildRuntimeGuidanceBlocks,
|
|
@@ -51,21 +62,32 @@ import {
|
|
|
51
62
|
detectDispatchIntentFromMessages,
|
|
52
63
|
estimateContextTokens,
|
|
53
64
|
hashStablePrefixContent,
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
resolveToolGuidedSections,
|
|
57
|
-
toBareImageUrlMessages
|
|
58
|
-
} from "./chunk-K2CSUCHJ.js";
|
|
65
|
+
resolveToolGuidedSections
|
|
66
|
+
} from "./chunk-WD4XYDYC.js";
|
|
59
67
|
import {
|
|
68
|
+
classifyUnparsableToolArgs,
|
|
69
|
+
collectStablePromptPrefix,
|
|
60
70
|
convertMessagesToResponsesInput,
|
|
71
|
+
downgradeUnparsableToolCalls,
|
|
61
72
|
extractReasoningFromResponseOutput,
|
|
62
73
|
extractTextFromResponseOutput,
|
|
63
74
|
extractToolCallsFromResponseOutput,
|
|
64
75
|
getUsageRequestOptions,
|
|
76
|
+
hasParsableObjectArguments,
|
|
77
|
+
markDowngradedToolTurnOrigin,
|
|
78
|
+
normalizeChatCompletionsBodyForProvider,
|
|
79
|
+
repairTruncatedToolArguments,
|
|
80
|
+
requiresBareImageUrl,
|
|
81
|
+
resolveReasoningReplayOptions,
|
|
82
|
+
sanitizeForOutbound,
|
|
83
|
+
scanTruncation,
|
|
65
84
|
shouldStripReasoningContentForOutbound,
|
|
85
|
+
stablePromptCacheKey,
|
|
86
|
+
toBareImageUrlMessages,
|
|
66
87
|
toOpenAiCompatibleMessages,
|
|
67
|
-
toResponsesTools
|
|
68
|
-
|
|
88
|
+
toResponsesTools,
|
|
89
|
+
transferDowngradedToolTurnOrigin
|
|
90
|
+
} from "./chunk-3SZA4U64.js";
|
|
69
91
|
import {
|
|
70
92
|
BRIDGE_STREAM_MAX_CHARS,
|
|
71
93
|
DEFAULT_READ_DIALOG_MAX_RESPONSE_CHARS,
|
|
@@ -80,14 +102,12 @@ import {
|
|
|
80
102
|
parseNoloWorkspaceToolArguments,
|
|
81
103
|
readTextStreamUpToChars,
|
|
82
104
|
resolveNoloDialogInput
|
|
83
|
-
} from "./chunk-
|
|
105
|
+
} from "./chunk-QLQ573SU.js";
|
|
84
106
|
import {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
} from "./chunk-27ONFIEY.js";
|
|
107
|
+
buildDialogFallbackTitleFromUserInput
|
|
108
|
+
} from "./chunk-2MBTWINN.js";
|
|
88
109
|
import {
|
|
89
110
|
EMPTY_ASSISTANT_REPAIR_PROMPT,
|
|
90
|
-
getModelContextWindow,
|
|
91
111
|
hasAssistantVisibleOutput,
|
|
92
112
|
normalizeUsage,
|
|
93
113
|
readCacheCreationInputTokens,
|
|
@@ -95,18 +115,20 @@ import {
|
|
|
95
115
|
resolveEmptyAssistantFallbackMessage,
|
|
96
116
|
resolveEmptyAssistantOutcome,
|
|
97
117
|
resolveTruncatedReasoningTailLog
|
|
98
|
-
} from "./chunk-
|
|
118
|
+
} from "./chunk-6CCFTVBP.js";
|
|
99
119
|
import {
|
|
100
120
|
COMPACTION_SUMMARY_SCHEMA_VERSION,
|
|
101
121
|
COMPACTION_SUMMARY_SYSTEM_PROMPT,
|
|
122
|
+
TOOL_RESULT_TRUNCATE_CHARS,
|
|
102
123
|
buildCompactionMetricsFromPlan,
|
|
103
124
|
buildCompactionUserContent,
|
|
104
|
-
|
|
125
|
+
computeSummaryInputTokenCap,
|
|
105
126
|
createProviderCallTimingTracker,
|
|
106
127
|
finalizeProviderCallTiming,
|
|
107
128
|
formatCompactionMetricsLog,
|
|
108
129
|
formatFileOperationsFromMessages,
|
|
109
130
|
formatMessagesForSummaryWithTruncation,
|
|
131
|
+
getModelContextWindow,
|
|
110
132
|
isMeaningfulResponsesOutput,
|
|
111
133
|
observeMeaningfulProviderResponse,
|
|
112
134
|
planCompression,
|
|
@@ -114,40 +136,40 @@ import {
|
|
|
114
136
|
resolveCompressionTriggerRatio,
|
|
115
137
|
truncateToolOutputForContext,
|
|
116
138
|
withProviderCallTimingFields
|
|
117
|
-
} from "./chunk-
|
|
118
|
-
import {
|
|
119
|
-
estimateTokenCount
|
|
120
|
-
} from "./chunk-PSCNXBYA.js";
|
|
121
|
-
import {
|
|
122
|
-
toErrorMessage
|
|
123
|
-
} from "./chunk-HNMXYYJR.js";
|
|
139
|
+
} from "./chunk-BPMPOFWP.js";
|
|
124
140
|
import {
|
|
125
|
-
|
|
126
|
-
} from "./chunk-
|
|
141
|
+
clipCompactText
|
|
142
|
+
} from "./chunk-5MMAK75Q.js";
|
|
127
143
|
import {
|
|
128
|
-
|
|
129
|
-
} from "./chunk-
|
|
144
|
+
asRecordOrEmpty
|
|
145
|
+
} from "./chunk-KX6YBIHG.js";
|
|
130
146
|
import {
|
|
131
|
-
|
|
132
|
-
} from "./chunk-
|
|
147
|
+
isAbortError
|
|
148
|
+
} from "./chunk-7DPNBQSV.js";
|
|
133
149
|
import {
|
|
134
150
|
canonicalizeToolName,
|
|
135
151
|
canonicalizeToolNames
|
|
136
|
-
} from "./chunk-
|
|
137
|
-
import {
|
|
138
|
-
asRecordOrEmpty
|
|
139
|
-
} from "./chunk-KX6YBIHG.js";
|
|
152
|
+
} from "./chunk-5EBLANFT.js";
|
|
140
153
|
import {
|
|
141
|
-
asTrimmedNonEmptyStringArray,
|
|
142
154
|
dialogMessageKey,
|
|
143
155
|
dialogMessageRange
|
|
144
|
-
} from "./chunk-
|
|
156
|
+
} from "./chunk-5EMSBTQ6.js";
|
|
157
|
+
import {
|
|
158
|
+
asTrimmedNonEmptyStringArray
|
|
159
|
+
} from "./chunk-I42VC5KR.js";
|
|
160
|
+
import {
|
|
161
|
+
asOptionalPositiveFiniteNumber
|
|
162
|
+
} from "./chunk-U6VC4MU4.js";
|
|
145
163
|
import {
|
|
146
164
|
asOptionalFiniteNumber
|
|
147
165
|
} from "./chunk-WWC7I6TA.js";
|
|
148
166
|
import {
|
|
149
|
-
|
|
150
|
-
} from "./chunk-
|
|
167
|
+
estimateTokenCount
|
|
168
|
+
} from "./chunk-PSCNXBYA.js";
|
|
169
|
+
import {
|
|
170
|
+
buildProviderAuthHeaders,
|
|
171
|
+
buildProviderExecutionPlan
|
|
172
|
+
} from "./chunk-K2AER7RX.js";
|
|
151
173
|
import {
|
|
152
174
|
isRecord
|
|
153
175
|
} from "./chunk-KUG52IAP.js";
|
|
@@ -155,14 +177,26 @@ import {
|
|
|
155
177
|
asTrimmedString
|
|
156
178
|
} from "./chunk-3EUW3WEO.js";
|
|
157
179
|
import {
|
|
158
|
-
|
|
159
|
-
} from "./chunk-
|
|
180
|
+
toErrorMessage
|
|
181
|
+
} from "./chunk-HNMXYYJR.js";
|
|
160
182
|
import {
|
|
161
183
|
normalizeServerOrigin
|
|
162
184
|
} from "./chunk-CF7PE763.js";
|
|
163
185
|
import {
|
|
164
186
|
asOptionalTrimmedString
|
|
165
187
|
} from "./chunk-G3SUCT4W.js";
|
|
188
|
+
import {
|
|
189
|
+
asTrimmedLowercaseString
|
|
190
|
+
} from "./chunk-QSJ3HFEF.js";
|
|
191
|
+
import {
|
|
192
|
+
resolveNoloStateDir
|
|
193
|
+
} from "./chunk-ZWQUWF6W.js";
|
|
194
|
+
import {
|
|
195
|
+
buildDialogSummaryLayer
|
|
196
|
+
} from "./chunk-VEA7H5FG.js";
|
|
197
|
+
import {
|
|
198
|
+
buildUserResponseLanguageContext
|
|
199
|
+
} from "./chunk-4VJAC32I.js";
|
|
166
200
|
import {
|
|
167
201
|
__export
|
|
168
202
|
} from "./chunk-4VNS5WPM.js";
|
|
@@ -5154,8 +5188,8 @@ var runPromiseExitWith = (context3) => {
|
|
|
5154
5188
|
const runFork3 = runForkWith(context3);
|
|
5155
5189
|
return (effect, options) => {
|
|
5156
5190
|
const fiber3 = runFork3(effect, options);
|
|
5157
|
-
return new Promise((
|
|
5158
|
-
fiber3.addObserver((exit3) =>
|
|
5191
|
+
return new Promise((resolve6) => {
|
|
5192
|
+
fiber3.addObserver((exit3) => resolve6(exit3));
|
|
5159
5193
|
});
|
|
5160
5194
|
};
|
|
5161
5195
|
};
|
|
@@ -12141,8 +12175,8 @@ var toReadableStreamWith = /* @__PURE__ */ dual((args2) => isStream(args2[0]), (
|
|
|
12141
12175
|
});
|
|
12142
12176
|
},
|
|
12143
12177
|
pull() {
|
|
12144
|
-
return new Promise((
|
|
12145
|
-
currentResolve =
|
|
12178
|
+
return new Promise((resolve6) => {
|
|
12179
|
+
currentResolve = resolve6;
|
|
12146
12180
|
latch.openUnsafe();
|
|
12147
12181
|
});
|
|
12148
12182
|
},
|
|
@@ -12546,7 +12580,7 @@ function sanitizeToolCallPairing(messages) {
|
|
|
12546
12580
|
if (isContentBlank(stripped.content)) {
|
|
12547
12581
|
continue;
|
|
12548
12582
|
}
|
|
12549
|
-
output.push(stripped);
|
|
12583
|
+
output.push(markDowngradedToolTurnOrigin(stripped));
|
|
12550
12584
|
continue;
|
|
12551
12585
|
}
|
|
12552
12586
|
const normalizedAssistant = { ...m, tool_calls: matchedToolCalls };
|
|
@@ -12576,11 +12610,11 @@ function resolveSpillDirectory(options) {
|
|
|
12576
12610
|
}
|
|
12577
12611
|
return resolveNoloStateDir("spills");
|
|
12578
12612
|
}
|
|
12579
|
-
function countLines(
|
|
12580
|
-
if (!
|
|
12613
|
+
function countLines(text2) {
|
|
12614
|
+
if (!text2) return 0;
|
|
12581
12615
|
let lines = 1;
|
|
12582
|
-
for (let i = 0; i <
|
|
12583
|
-
if (
|
|
12616
|
+
for (let i = 0; i < text2.length; i++) {
|
|
12617
|
+
if (text2.charCodeAt(i) === 10) {
|
|
12584
12618
|
lines++;
|
|
12585
12619
|
}
|
|
12586
12620
|
}
|
|
@@ -12750,18 +12784,18 @@ var QUICK_PROBE_SUBSTRINGS = [
|
|
|
12750
12784
|
"PASSWD",
|
|
12751
12785
|
"SECRET_KEY"
|
|
12752
12786
|
];
|
|
12753
|
-
function hasPotentialSecrets(
|
|
12754
|
-
if (typeof
|
|
12755
|
-
return QUICK_PROBE_SUBSTRINGS.some((probe) =>
|
|
12787
|
+
function hasPotentialSecrets(text2) {
|
|
12788
|
+
if (typeof text2 !== "string" || text2.length === 0) return false;
|
|
12789
|
+
return QUICK_PROBE_SUBSTRINGS.some((probe) => text2.includes(probe));
|
|
12756
12790
|
}
|
|
12757
|
-
function scrubSecrets(
|
|
12758
|
-
if (typeof
|
|
12759
|
-
return { cleaned:
|
|
12791
|
+
function scrubSecrets(text2) {
|
|
12792
|
+
if (typeof text2 !== "string" || text2.length === 0) {
|
|
12793
|
+
return { cleaned: text2, redactedCount: 0, matchedKinds: [] };
|
|
12760
12794
|
}
|
|
12761
|
-
if (!hasPotentialSecrets(
|
|
12762
|
-
return { cleaned:
|
|
12795
|
+
if (!hasPotentialSecrets(text2)) {
|
|
12796
|
+
return { cleaned: text2, redactedCount: 0, matchedKinds: [] };
|
|
12763
12797
|
}
|
|
12764
|
-
let cleaned =
|
|
12798
|
+
let cleaned = text2;
|
|
12765
12799
|
let redactedCount = 0;
|
|
12766
12800
|
const matchedKinds = [];
|
|
12767
12801
|
for (const pattern of SECRET_PATTERNS) {
|
|
@@ -12820,15 +12854,15 @@ ${JSON.stringify(visible)}`;
|
|
|
12820
12854
|
}
|
|
12821
12855
|
function blocksToOpenAiMessages(blocks) {
|
|
12822
12856
|
const out = [];
|
|
12823
|
-
let
|
|
12857
|
+
let text2 = "";
|
|
12824
12858
|
let reasoning = "";
|
|
12825
12859
|
let pendingToolCalls = [];
|
|
12826
12860
|
let pendingToolResults = [];
|
|
12827
12861
|
const flushSegment = () => {
|
|
12828
|
-
if (
|
|
12862
|
+
if (text2 === "" && pendingToolCalls.length === 0 && reasoning === "") return;
|
|
12829
12863
|
out.push({
|
|
12830
12864
|
role: "assistant",
|
|
12831
|
-
content:
|
|
12865
|
+
content: text2 || null,
|
|
12832
12866
|
...reasoning ? { reasoning_content: reasoning } : {},
|
|
12833
12867
|
...pendingToolCalls.length > 0 ? { tool_calls: pendingToolCalls } : {}
|
|
12834
12868
|
});
|
|
@@ -12847,7 +12881,7 @@ function blocksToOpenAiMessages(blocks) {
|
|
|
12847
12881
|
...res?.metadata ? { tool_result_metadata: res.metadata } : {}
|
|
12848
12882
|
});
|
|
12849
12883
|
}
|
|
12850
|
-
|
|
12884
|
+
text2 = "";
|
|
12851
12885
|
reasoning = "";
|
|
12852
12886
|
pendingToolCalls = [];
|
|
12853
12887
|
pendingToolResults = [];
|
|
@@ -12857,7 +12891,7 @@ function blocksToOpenAiMessages(blocks) {
|
|
|
12857
12891
|
if (pendingToolCalls.length > 0) {
|
|
12858
12892
|
flushSegment();
|
|
12859
12893
|
}
|
|
12860
|
-
|
|
12894
|
+
text2 += block.text;
|
|
12861
12895
|
continue;
|
|
12862
12896
|
}
|
|
12863
12897
|
if (block.type === "thinking") {
|
|
@@ -13045,6 +13079,7 @@ function summarizeHistoricalToolContent(content, toolName, metadata) {
|
|
|
13045
13079
|
label: TOOL_OUTPUT_PROJECTION_LABEL
|
|
13046
13080
|
});
|
|
13047
13081
|
}
|
|
13082
|
+
var toolProjectionMemoMap = /* @__PURE__ */ new WeakMap();
|
|
13048
13083
|
function prepareMessagesForProviderCall(messages) {
|
|
13049
13084
|
const paired = sanitizeToolCallPairing(messages);
|
|
13050
13085
|
let toolMessageCount = 0;
|
|
@@ -13055,27 +13090,39 @@ function prepareMessagesForProviderCall(messages) {
|
|
|
13055
13090
|
const { context_reference: _contextReference, ...providerMessage } = message;
|
|
13056
13091
|
const sanitizedContent = providerMessage.content == null ? "" : typeof providerMessage.content === "string" ? providerMessage.content : providerMessage.content;
|
|
13057
13092
|
if (providerMessage.role !== "tool") {
|
|
13058
|
-
return {
|
|
13093
|
+
return transferDowngradedToolTurnOrigin(message, {
|
|
13059
13094
|
...providerMessage,
|
|
13060
13095
|
content: sanitizedContent
|
|
13061
|
-
};
|
|
13096
|
+
});
|
|
13062
13097
|
}
|
|
13063
13098
|
toolMessageCount += 1;
|
|
13064
|
-
|
|
13065
|
-
|
|
13066
|
-
|
|
13067
|
-
|
|
13068
|
-
|
|
13069
|
-
|
|
13070
|
-
|
|
13071
|
-
|
|
13072
|
-
|
|
13073
|
-
|
|
13099
|
+
let memo = toolProjectionMemoMap.get(message);
|
|
13100
|
+
if (!memo) {
|
|
13101
|
+
const rawChars = contentCharCount(sanitizedContent);
|
|
13102
|
+
const projectedContent = projectToolContentForProvider({
|
|
13103
|
+
content: sanitizedContent,
|
|
13104
|
+
toolName: providerMessage.toolName,
|
|
13105
|
+
metadata: providerMessage.tool_result_metadata,
|
|
13106
|
+
maxChars: resolveToolOutputProfile(providerMessage.toolName).maxChars,
|
|
13107
|
+
label: TOOL_OUTPUT_PROJECTION_LABEL
|
|
13108
|
+
});
|
|
13109
|
+
const projectedChars = contentCharCount(projectedContent);
|
|
13110
|
+
memo = {
|
|
13111
|
+
projectedContent,
|
|
13112
|
+
rawChars,
|
|
13113
|
+
projectedChars,
|
|
13114
|
+
isTruncated: projectedChars < rawChars
|
|
13115
|
+
};
|
|
13116
|
+
toolProjectionMemoMap.set(message, memo);
|
|
13117
|
+
}
|
|
13118
|
+
rawToolContentChars += memo.rawChars;
|
|
13119
|
+
projectedToolContentChars += memo.projectedChars;
|
|
13120
|
+
if (memo.isTruncated) {
|
|
13074
13121
|
truncatedToolResults += 1;
|
|
13075
13122
|
}
|
|
13076
13123
|
return {
|
|
13077
13124
|
...providerMessage,
|
|
13078
|
-
content: projectedContent
|
|
13125
|
+
content: memo.projectedContent
|
|
13079
13126
|
};
|
|
13080
13127
|
});
|
|
13081
13128
|
return {
|
|
@@ -13110,13 +13157,36 @@ function prepareHistoryForNextTurn(history, contextReferenceResolver) {
|
|
|
13110
13157
|
}
|
|
13111
13158
|
function filterImagePartsFromMessages(messages, supportsImages) {
|
|
13112
13159
|
if (supportsImages) return messages;
|
|
13113
|
-
return stripImagePartsFromMessages(messages)
|
|
13160
|
+
return stripImagePartsFromMessages(messages).map(
|
|
13161
|
+
(stripped, index) => transferDowngradedToolTurnOrigin(messages[index], stripped)
|
|
13162
|
+
);
|
|
13163
|
+
}
|
|
13164
|
+
var MODEL_PROJECTED_USER_PART_TYPES = /* @__PURE__ */ new Set(["attachment", "media_job"]);
|
|
13165
|
+
var isModelProjectedUserPart = (part) => typeof part === "object" && part !== null && MODEL_PROJECTED_USER_PART_TYPES.has(
|
|
13166
|
+
part.type
|
|
13167
|
+
);
|
|
13168
|
+
function projectUserMessageForProvider(message) {
|
|
13169
|
+
if (message.role !== "user" || !Array.isArray(message.content)) return message;
|
|
13170
|
+
let projected = false;
|
|
13171
|
+
const nextContent = [];
|
|
13172
|
+
for (const part of message.content) {
|
|
13173
|
+
if (isModelProjectedUserPart(part)) {
|
|
13174
|
+
nextContent.push(...projectUserPartForModel(part));
|
|
13175
|
+
projected = true;
|
|
13176
|
+
} else {
|
|
13177
|
+
nextContent.push(part);
|
|
13178
|
+
}
|
|
13179
|
+
}
|
|
13180
|
+
return projected ? { ...message, content: nextContent } : message;
|
|
13114
13181
|
}
|
|
13115
13182
|
function composeProviderMessages(args2) {
|
|
13116
13183
|
return downgradeUnparsableToolCalls([
|
|
13117
|
-
...args2.prefix,
|
|
13118
|
-
...prepareHistoryForNextTurn(
|
|
13119
|
-
|
|
13184
|
+
...args2.prefix.map(projectUserMessageForProvider),
|
|
13185
|
+
...prepareHistoryForNextTurn(
|
|
13186
|
+
args2.history,
|
|
13187
|
+
args2.contextReferenceResolver
|
|
13188
|
+
).map(projectUserMessageForProvider),
|
|
13189
|
+
...(args2.suffix ?? []).map(projectUserMessageForProvider)
|
|
13120
13190
|
]);
|
|
13121
13191
|
}
|
|
13122
13192
|
function buildMessages(args2) {
|
|
@@ -13147,6 +13217,7 @@ ${args2.input}` : [
|
|
|
13147
13217
|
messages: composed2.messages,
|
|
13148
13218
|
prefixCount: prefix2.length,
|
|
13149
13219
|
poisonDowngraded: composed2.downgraded,
|
|
13220
|
+
poisonStats: composed2.stats,
|
|
13150
13221
|
stableContextChars: stableContent.length,
|
|
13151
13222
|
dynamicContextChars: dynamicContent.length,
|
|
13152
13223
|
...stableContent ? {
|
|
@@ -13168,6 +13239,7 @@ ${args2.input}` : [
|
|
|
13168
13239
|
messages: composed.messages,
|
|
13169
13240
|
prefixCount: prefix.length,
|
|
13170
13241
|
poisonDowngraded: composed.downgraded,
|
|
13242
|
+
poisonStats: composed.stats,
|
|
13171
13243
|
stableContextChars: (args2.prompt?.trim() ?? "").length,
|
|
13172
13244
|
dynamicContextChars: blocks.join("\n\n").length,
|
|
13173
13245
|
...systemContent ? {
|
|
@@ -13177,26 +13249,6 @@ ${args2.input}` : [
|
|
|
13177
13249
|
};
|
|
13178
13250
|
}
|
|
13179
13251
|
|
|
13180
|
-
// packages/agent-runtime/fileWritePolicy.ts
|
|
13181
|
-
function evaluateFileWritePolicy(args2) {
|
|
13182
|
-
if (args2.sessionApproved) return { permissionDecision: "allow" };
|
|
13183
|
-
return {
|
|
13184
|
-
permissionDecision: "ask",
|
|
13185
|
-
permissionRequest: {
|
|
13186
|
-
id: "permission-file-write-session",
|
|
13187
|
-
tool: args2.tool,
|
|
13188
|
-
action: "file_write",
|
|
13189
|
-
title: "\u786E\u8BA4\u5199\u5165\u6587\u4EF6",
|
|
13190
|
-
body: `\u672C\u4F1A\u8BDD\u9996\u6B21\u5199\u5165\u6587\u4EF6\uFF1A${args2.path}\u3002\u6279\u51C6\u540E\u672C\u4F1A\u8BDD\u540E\u7EED\u5199\u5165\u4E0D\u518D\u9010\u6B21\u786E\u8BA4\u3002`,
|
|
13191
|
-
command: args2.path,
|
|
13192
|
-
suggestedRule: {
|
|
13193
|
-
scope: "session",
|
|
13194
|
-
pattern: { capability: "file_write", target: "session" }
|
|
13195
|
-
}
|
|
13196
|
-
}
|
|
13197
|
-
};
|
|
13198
|
-
}
|
|
13199
|
-
|
|
13200
13252
|
// packages/agent-runtime/toolArgsTruncationPolicy.ts
|
|
13201
13253
|
import { createHash as createHash2 } from "node:crypto";
|
|
13202
13254
|
var TRUNCATION_TAIL_DROP_ALLOWED_TOOLS = /* @__PURE__ */ new Set([
|
|
@@ -13205,45 +13257,6 @@ var TRUNCATION_TAIL_DROP_ALLOWED_TOOLS = /* @__PURE__ */ new Set([
|
|
|
13205
13257
|
function isTailDropRepairAllowed(toolName) {
|
|
13206
13258
|
return typeof toolName === "string" && TRUNCATION_TAIL_DROP_ALLOWED_TOOLS.has(toolName);
|
|
13207
13259
|
}
|
|
13208
|
-
function scanTruncation(input) {
|
|
13209
|
-
const stack = [];
|
|
13210
|
-
const commaAtDepth = [];
|
|
13211
|
-
let inString = false;
|
|
13212
|
-
let escaped = false;
|
|
13213
|
-
const closersOf = () => stack.slice().reverse().map((ch) => ch === "{" ? "}" : "]").join("");
|
|
13214
|
-
for (let i = 0; i < input.length; i += 1) {
|
|
13215
|
-
const ch = input[i];
|
|
13216
|
-
if (inString) {
|
|
13217
|
-
if (escaped) escaped = false;
|
|
13218
|
-
else if (ch === "\\") escaped = true;
|
|
13219
|
-
else if (ch === '"') inString = false;
|
|
13220
|
-
continue;
|
|
13221
|
-
}
|
|
13222
|
-
if (ch === '"') {
|
|
13223
|
-
inString = true;
|
|
13224
|
-
} else if (ch === "{" || ch === "[") {
|
|
13225
|
-
stack.push(ch);
|
|
13226
|
-
commaAtDepth[stack.length] = void 0;
|
|
13227
|
-
} else if (ch === "}" || ch === "]") {
|
|
13228
|
-
const open = stack.pop();
|
|
13229
|
-
if (open !== (ch === "}" ? "{" : "[")) {
|
|
13230
|
-
return { inString, malformed: true, tailArrayComma: null };
|
|
13231
|
-
}
|
|
13232
|
-
commaAtDepth[stack.length + 1] = void 0;
|
|
13233
|
-
} else if (ch === "," && stack[stack.length - 1] === "[") {
|
|
13234
|
-
commaAtDepth[stack.length] = { index: i, closers: closersOf() };
|
|
13235
|
-
}
|
|
13236
|
-
}
|
|
13237
|
-
let tailArrayComma = null;
|
|
13238
|
-
for (let d = stack.length; d >= 1; d -= 1) {
|
|
13239
|
-
const c = commaAtDepth[d];
|
|
13240
|
-
if (c && stack[d - 1] === "[") {
|
|
13241
|
-
tailArrayComma = c;
|
|
13242
|
-
break;
|
|
13243
|
-
}
|
|
13244
|
-
}
|
|
13245
|
-
return { inString, malformed: false, tailArrayComma };
|
|
13246
|
-
}
|
|
13247
13260
|
function repairTruncatedToolArgumentsDroppingTail(toolName, raw) {
|
|
13248
13261
|
if (!isTailDropRepairAllowed(toolName)) return null;
|
|
13249
13262
|
if (typeof raw !== "string") return null;
|
|
@@ -13284,50 +13297,6 @@ function buildToolArgsDiagnosticLine(args2) {
|
|
|
13284
13297
|
return parts2.join(" ");
|
|
13285
13298
|
}
|
|
13286
13299
|
|
|
13287
|
-
// packages/agent-runtime/parseToolArguments.ts
|
|
13288
|
-
function parseToolArgumentsJson(raw) {
|
|
13289
|
-
if (!raw?.trim()) return {};
|
|
13290
|
-
try {
|
|
13291
|
-
return asRecordOrEmpty(JSON.parse(raw));
|
|
13292
|
-
} catch {
|
|
13293
|
-
return {};
|
|
13294
|
-
}
|
|
13295
|
-
}
|
|
13296
|
-
|
|
13297
|
-
// packages/agent-runtime/summarizeToolArguments.ts
|
|
13298
|
-
function clip(value, max4 = 240) {
|
|
13299
|
-
return clipCompactText(value, max4);
|
|
13300
|
-
}
|
|
13301
|
-
function summarizeToolArguments(toolName, rawArgs) {
|
|
13302
|
-
const args2 = parseToolArgumentsJson(rawArgs);
|
|
13303
|
-
const pick = (...keys3) => {
|
|
13304
|
-
for (const key of keys3) {
|
|
13305
|
-
const value = asOptionalTrimmedString(args2[key]);
|
|
13306
|
-
if (value) return value;
|
|
13307
|
-
}
|
|
13308
|
-
return "";
|
|
13309
|
-
};
|
|
13310
|
-
const command = pick("command", "cmd", "runCommand", "executeCommand", "bash");
|
|
13311
|
-
if (command) return clip(command);
|
|
13312
|
-
const query = pick("query", "pattern", "search", "q");
|
|
13313
|
-
if (query) return clip(query);
|
|
13314
|
-
const filePath = pick("filePath", "file_path", "path", "filename", "file");
|
|
13315
|
-
if (filePath) return clip(filePath);
|
|
13316
|
-
const keys2 = Object.keys(args2);
|
|
13317
|
-
if (keys2.length === 0) return "";
|
|
13318
|
-
return clip(
|
|
13319
|
-
keys2.slice(0, 6).map((key) => {
|
|
13320
|
-
const value = args2[key];
|
|
13321
|
-
if (typeof value === "string") return `${key}=${clip(value, 80)}`;
|
|
13322
|
-
if (typeof value === "number" || typeof value === "boolean") {
|
|
13323
|
-
return `${key}=${String(value)}`;
|
|
13324
|
-
}
|
|
13325
|
-
if (Array.isArray(value)) return `${key}[${value.length}]`;
|
|
13326
|
-
return `${key}=${value === null ? "null" : typeof value}`;
|
|
13327
|
-
}).join(" ")
|
|
13328
|
-
);
|
|
13329
|
-
}
|
|
13330
|
-
|
|
13331
13300
|
// packages/agent-runtime/progressGuard.ts
|
|
13332
13301
|
var DEFAULT_MAX_CONSECUTIVE_IDENTICAL_ROUNDS = 5;
|
|
13333
13302
|
var DEFAULT_MAX_CONSECUTIVE_STAGNANT_TOOL_ROUNDS = 8;
|
|
@@ -13539,14 +13508,14 @@ function computeDeterministicRef(secret) {
|
|
|
13539
13508
|
const hex = hasher.digest("hex").slice(0, 12);
|
|
13540
13509
|
return `vault-cred-${hex}`;
|
|
13541
13510
|
}
|
|
13542
|
-
async function isolateInboundCredentials(
|
|
13543
|
-
if (typeof
|
|
13544
|
-
return { safeText:
|
|
13511
|
+
async function isolateInboundCredentials(text2, broker) {
|
|
13512
|
+
if (typeof text2 !== "string" || text2.length === 0 || !broker) {
|
|
13513
|
+
return { safeText: text2, isolatedCount: 0, credentials: [] };
|
|
13545
13514
|
}
|
|
13546
|
-
if (!hasPotentialSecrets(
|
|
13547
|
-
return { safeText:
|
|
13515
|
+
if (!hasPotentialSecrets(text2)) {
|
|
13516
|
+
return { safeText: text2, isolatedCount: 0, credentials: [] };
|
|
13548
13517
|
}
|
|
13549
|
-
let safeText =
|
|
13518
|
+
let safeText = text2;
|
|
13550
13519
|
const isolatedCredentials = [];
|
|
13551
13520
|
for (const { kind, regex } of INBOUND_PATTERNS) {
|
|
13552
13521
|
regex.lastIndex = 0;
|
|
@@ -13681,25 +13650,25 @@ var SHELL_STRING_EXECUTION_PATTERNS = [
|
|
|
13681
13650
|
/\bpython[\d.]*\s+(?:-\S+\s+)*-c\b/i,
|
|
13682
13651
|
/\b(?:perl|ruby)\s+(?:-\S+\s+)*-e\b/i
|
|
13683
13652
|
];
|
|
13684
|
-
var stripQuotedSegments = (
|
|
13653
|
+
var stripQuotedSegments = (text2) => {
|
|
13685
13654
|
let out = "";
|
|
13686
13655
|
let i = 0;
|
|
13687
|
-
while (i <
|
|
13688
|
-
const ch =
|
|
13656
|
+
while (i < text2.length) {
|
|
13657
|
+
const ch = text2[i];
|
|
13689
13658
|
if (ch === "\\") {
|
|
13690
|
-
out +=
|
|
13659
|
+
out += text2.slice(i, i + 2);
|
|
13691
13660
|
i += 2;
|
|
13692
13661
|
} else if (ch === "'") {
|
|
13693
|
-
const end3 =
|
|
13694
|
-
if (end3 === -1) return out +
|
|
13662
|
+
const end3 = text2.indexOf("'", i + 1);
|
|
13663
|
+
if (end3 === -1) return out + text2.slice(i);
|
|
13695
13664
|
out += "''";
|
|
13696
13665
|
i = end3 + 1;
|
|
13697
13666
|
} else if (ch === '"') {
|
|
13698
13667
|
let j = i + 1;
|
|
13699
|
-
while (j <
|
|
13700
|
-
j +=
|
|
13668
|
+
while (j < text2.length && text2[j] !== '"') {
|
|
13669
|
+
j += text2[j] === "\\" ? 2 : 1;
|
|
13701
13670
|
}
|
|
13702
|
-
if (j >=
|
|
13671
|
+
if (j >= text2.length) return out + text2.slice(i);
|
|
13703
13672
|
out += '""';
|
|
13704
13673
|
i = j + 1;
|
|
13705
13674
|
} else {
|
|
@@ -13710,7 +13679,7 @@ var stripQuotedSegments = (text) => {
|
|
|
13710
13679
|
return out;
|
|
13711
13680
|
};
|
|
13712
13681
|
var normalizeUserInput = (value) => asTrimmedLowercaseString(value);
|
|
13713
|
-
var containsAny = (
|
|
13682
|
+
var containsAny = (text2, patterns) => patterns.some((pattern) => text2.includes(pattern));
|
|
13714
13683
|
var hasExplicitDestructivePermission = (userInput) => {
|
|
13715
13684
|
const normalized = normalizeUserInput(userInput);
|
|
13716
13685
|
if (!normalized) return false;
|
|
@@ -13914,109 +13883,232 @@ async function evaluateCapabilityPolicy(capability, normalizedInput, ctx) {
|
|
|
13914
13883
|
}
|
|
13915
13884
|
}
|
|
13916
13885
|
|
|
13917
|
-
// packages/agent-runtime/
|
|
13918
|
-
import { existsSync as existsSync3 } from "node:fs";
|
|
13886
|
+
// packages/agent-runtime/capabilities/execShellCapability.ts
|
|
13919
13887
|
import { createHash as createHash3 } from "node:crypto";
|
|
13920
|
-
import { lstat, mkdir, readdir as readdir2, readFile as readFile3, realpath, stat as stat3, writeFile } from "node:fs/promises";
|
|
13921
|
-
import { homedir } from "node:os";
|
|
13922
|
-
import { dirname, isAbsolute as isAbsolute2, relative as relative3, resolve as resolve4, sep } from "node:path";
|
|
13923
|
-
import { spawn as spawnChildProcess3 } from "node:child_process";
|
|
13924
13888
|
|
|
13925
|
-
// packages/
|
|
13926
|
-
|
|
13927
|
-
|
|
13928
|
-
|
|
13929
|
-
|
|
13930
|
-
|
|
13931
|
-
|
|
13932
|
-
|
|
13933
|
-
|
|
13934
|
-
|
|
13935
|
-
|
|
13936
|
-
|
|
13937
|
-
|
|
13938
|
-
|
|
13939
|
-
|
|
13940
|
-
|
|
13889
|
+
// packages/agent-runtime/execShellCompletionWarnings.ts
|
|
13890
|
+
var BG_ESCAPE_WORD_PATTERN = /(?:^|[\s;|(&/\\])(nohup|disown|setsid|start-process)(?=$|[\s;|)&])/i;
|
|
13891
|
+
var SHELL_SPLIT_CHARS = /* @__PURE__ */ new Set([";", "|", "&", "(", ")", "<", ">", "\n", " ", " "]);
|
|
13892
|
+
function maskQuotedAndEscaped(command) {
|
|
13893
|
+
const out = Array.from(command);
|
|
13894
|
+
let quote = null;
|
|
13895
|
+
for (let i = 0; i < out.length; i += 1) {
|
|
13896
|
+
const ch = out[i];
|
|
13897
|
+
if (quote) {
|
|
13898
|
+
out[i] = " ";
|
|
13899
|
+
if (ch === "\\" && quote !== "'") {
|
|
13900
|
+
if (i + 1 < out.length) out[i + 1] = " ";
|
|
13901
|
+
i += 1;
|
|
13902
|
+
} else if (ch === quote) {
|
|
13903
|
+
quote = null;
|
|
13904
|
+
}
|
|
13905
|
+
continue;
|
|
13906
|
+
}
|
|
13907
|
+
if (ch === "\\") {
|
|
13908
|
+
out[i] = " ";
|
|
13909
|
+
if (i + 1 < out.length) out[i + 1] = " ";
|
|
13910
|
+
i += 1;
|
|
13911
|
+
continue;
|
|
13912
|
+
}
|
|
13913
|
+
if (ch === "'" || ch === '"' || ch === "`") {
|
|
13914
|
+
quote = ch;
|
|
13915
|
+
out[i] = " ";
|
|
13916
|
+
continue;
|
|
13917
|
+
}
|
|
13918
|
+
if (ch === "#" && (i === 0 || /[\s;]/.test(out[i - 1] ?? " "))) {
|
|
13919
|
+
while (i < out.length && out[i] !== "\n") {
|
|
13920
|
+
out[i] = " ";
|
|
13921
|
+
i += 1;
|
|
13922
|
+
}
|
|
13941
13923
|
}
|
|
13942
13924
|
}
|
|
13943
|
-
return
|
|
13944
|
-
}
|
|
13945
|
-
function isLineRangeCovered(request3, covered) {
|
|
13946
|
-
if (!isValidRange(request3)) return false;
|
|
13947
|
-
let open = request3.startLine;
|
|
13948
|
-
for (const range3 of mergeLineRanges(covered)) {
|
|
13949
|
-
if (range3.endLine < open) continue;
|
|
13950
|
-
if (range3.startLine > open) return false;
|
|
13951
|
-
open = range3.endLine + 1;
|
|
13952
|
-
if (open > request3.endLine) return true;
|
|
13953
|
-
}
|
|
13954
|
-
return open > request3.endLine;
|
|
13925
|
+
return out.join("");
|
|
13955
13926
|
}
|
|
13956
|
-
|
|
13957
|
-
|
|
13958
|
-
|
|
13959
|
-
|
|
13960
|
-
import { spawn } from "node:child_process";
|
|
13961
|
-
var IS_WINDOWS = process.platform === "win32";
|
|
13962
|
-
function isExecutableFile(candidate) {
|
|
13963
|
-
if (!existsSync2(candidate)) return false;
|
|
13964
|
-
try {
|
|
13965
|
-
return statSync2(candidate).isFile();
|
|
13966
|
-
} catch {
|
|
13967
|
-
return false;
|
|
13927
|
+
function readRedirectTarget(original, start) {
|
|
13928
|
+
let i = start;
|
|
13929
|
+
while (i < original.length && /\s/.test(original[i] ?? "")) {
|
|
13930
|
+
i += 1;
|
|
13968
13931
|
}
|
|
13969
|
-
|
|
13970
|
-
|
|
13971
|
-
|
|
13972
|
-
|
|
13973
|
-
|
|
13974
|
-
|
|
13975
|
-
|
|
13932
|
+
if (i >= original.length) return void 0;
|
|
13933
|
+
let text2 = "";
|
|
13934
|
+
let j = i;
|
|
13935
|
+
while (j < original.length) {
|
|
13936
|
+
const o = original[j];
|
|
13937
|
+
if (o === "'" || o === '"' || o === "`") {
|
|
13938
|
+
const quote = o;
|
|
13939
|
+
j += 1;
|
|
13940
|
+
while (j < original.length && original[j] !== quote) {
|
|
13941
|
+
if (original[j] === "\\" && quote !== "'" && j + 1 < original.length) {
|
|
13942
|
+
text2 += original[j + 1];
|
|
13943
|
+
j += 2;
|
|
13944
|
+
continue;
|
|
13945
|
+
}
|
|
13946
|
+
text2 += original[j];
|
|
13947
|
+
j += 1;
|
|
13948
|
+
}
|
|
13949
|
+
j += 1;
|
|
13950
|
+
continue;
|
|
13976
13951
|
}
|
|
13977
|
-
|
|
13978
|
-
|
|
13979
|
-
|
|
13980
|
-
const sep2 = pathEnv.includes(";") && IS_WINDOWS ? ";" : ":";
|
|
13981
|
-
const pathDirs = pathEnv.split(sep2).filter(Boolean);
|
|
13982
|
-
const fallbackDirs = IS_WINDOWS ? [] : [
|
|
13983
|
-
"/opt/homebrew/bin",
|
|
13984
|
-
"/usr/local/bin",
|
|
13985
|
-
"/usr/bin",
|
|
13986
|
-
"/bin",
|
|
13987
|
-
`${process.env.HOME ?? ""}/.local/bin`
|
|
13988
|
-
].filter(Boolean);
|
|
13989
|
-
for (const dir of [...pathDirs, ...fallbackDirs]) {
|
|
13990
|
-
const candidate = join3(dir, name);
|
|
13991
|
-
if (isExecutableFile(candidate)) return candidate;
|
|
13952
|
+
if (/\s/.test(o) || SHELL_SPLIT_CHARS.has(o)) break;
|
|
13953
|
+
text2 += o;
|
|
13954
|
+
j += 1;
|
|
13992
13955
|
}
|
|
13993
|
-
return
|
|
13956
|
+
if (!text2 || text2 === "$") return void 0;
|
|
13957
|
+
return { text: text2, end: j };
|
|
13994
13958
|
}
|
|
13995
|
-
function
|
|
13996
|
-
|
|
13997
|
-
return {
|
|
13998
|
-
match(path) {
|
|
13999
|
-
return regex.test(path);
|
|
14000
|
-
},
|
|
14001
|
-
scanSync(opts) {
|
|
14002
|
-
const dot = opts.dot ?? false;
|
|
14003
|
-
const results2 = [];
|
|
14004
|
-
walkDir(opts.cwd, "", dot, results2);
|
|
14005
|
-
return results2.filter((rel) => regex.test(rel));
|
|
14006
|
-
}
|
|
14007
|
-
};
|
|
13959
|
+
function isIgnoredRedirectTarget(target) {
|
|
13960
|
+
return target === "/dev/null";
|
|
14008
13961
|
}
|
|
14009
|
-
function
|
|
14010
|
-
|
|
14011
|
-
|
|
14012
|
-
|
|
14013
|
-
|
|
14014
|
-
|
|
14015
|
-
|
|
14016
|
-
|
|
14017
|
-
|
|
14018
|
-
|
|
14019
|
-
|
|
13962
|
+
function detectExecShellSynchronousWarnings(command, shell) {
|
|
13963
|
+
const masked = maskQuotedAndEscaped(command);
|
|
13964
|
+
const isPowerShell = shell?.resolvedShell === "powershell";
|
|
13965
|
+
const redirectTargets = [];
|
|
13966
|
+
let backgrounded = false;
|
|
13967
|
+
let i = 0;
|
|
13968
|
+
while (i < masked.length) {
|
|
13969
|
+
const ch = masked[i];
|
|
13970
|
+
if (ch === "&") {
|
|
13971
|
+
const next = masked[i + 1];
|
|
13972
|
+
if (next === "&") {
|
|
13973
|
+
i += 2;
|
|
13974
|
+
continue;
|
|
13975
|
+
}
|
|
13976
|
+
if (next === ">") {
|
|
13977
|
+
let j = i + 2;
|
|
13978
|
+
if (masked[j] === ">") j += 1;
|
|
13979
|
+
const target = readRedirectTarget(command, j);
|
|
13980
|
+
if (target && !isIgnoredRedirectTarget(target.text)) redirectTargets.push(target.text);
|
|
13981
|
+
i = target ? target.end : j;
|
|
13982
|
+
continue;
|
|
13983
|
+
}
|
|
13984
|
+
const prev = masked[i - 1];
|
|
13985
|
+
if (prev === ">" || prev === "<") {
|
|
13986
|
+
i += 1;
|
|
13987
|
+
continue;
|
|
13988
|
+
}
|
|
13989
|
+
if (isPowerShell) {
|
|
13990
|
+
i += 1;
|
|
13991
|
+
continue;
|
|
13992
|
+
}
|
|
13993
|
+
backgrounded = true;
|
|
13994
|
+
i += 1;
|
|
13995
|
+
continue;
|
|
13996
|
+
}
|
|
13997
|
+
if (ch === ">") {
|
|
13998
|
+
const prev = masked[i - 1];
|
|
13999
|
+
if (prev === ">" || prev === "&" || prev === "<") {
|
|
14000
|
+
i += 1;
|
|
14001
|
+
continue;
|
|
14002
|
+
}
|
|
14003
|
+
let j = i + 1;
|
|
14004
|
+
if (masked[j] === ">") j += 1;
|
|
14005
|
+
if (masked[j] === "&") {
|
|
14006
|
+
const ampTarget = readRedirectTarget(command, j + 1);
|
|
14007
|
+
const isFdDuplication = ampTarget !== void 0 && (/^\d+$/.test(ampTarget.text) || ampTarget.text === "-");
|
|
14008
|
+
if (ampTarget && !isFdDuplication && !isIgnoredRedirectTarget(ampTarget.text)) {
|
|
14009
|
+
redirectTargets.push(ampTarget.text);
|
|
14010
|
+
}
|
|
14011
|
+
i = ampTarget ? ampTarget.end : j + 1;
|
|
14012
|
+
continue;
|
|
14013
|
+
}
|
|
14014
|
+
const target = readRedirectTarget(command, j);
|
|
14015
|
+
if (target && !isIgnoredRedirectTarget(target.text)) redirectTargets.push(target.text);
|
|
14016
|
+
i = target ? target.end : j;
|
|
14017
|
+
continue;
|
|
14018
|
+
}
|
|
14019
|
+
if (ch === "<") {
|
|
14020
|
+
i += masked[i + 1] === "<" || masked[i + 1] === "&" ? 2 : 1;
|
|
14021
|
+
continue;
|
|
14022
|
+
}
|
|
14023
|
+
i += 1;
|
|
14024
|
+
}
|
|
14025
|
+
const wordMatch = BG_ESCAPE_WORD_PATTERN.exec(masked);
|
|
14026
|
+
if (wordMatch) backgrounded = true;
|
|
14027
|
+
const warnings = [];
|
|
14028
|
+
if (redirectTargets.length > 0) {
|
|
14029
|
+
const target = redirectTargets[0];
|
|
14030
|
+
warnings.push({
|
|
14031
|
+
kind: "output-redirect",
|
|
14032
|
+
redirectTarget: target,
|
|
14033
|
+
message: `[wake-safety] This execShell call completed synchronously; its output was redirected to ${target}. That file is NOT delivered by any completion notification \u2014 no tracked background task was created. If you need the result, read that file in this turn.`
|
|
14034
|
+
});
|
|
14035
|
+
}
|
|
14036
|
+
if (backgrounded) {
|
|
14037
|
+
warnings.push({
|
|
14038
|
+
kind: "shell-backgrounding",
|
|
14039
|
+
message: `[wake-safety] Detected shell-internal backgrounding (lone \`&\`, nohup/disown/setsid/Start-Process or similar). Descendant processes are NOT tracked as platform tasks and will not produce completion notifications; text such as \`LAUNCHED\` printed by the command is plain stdout, not a platform receipt.`
|
|
14040
|
+
});
|
|
14041
|
+
}
|
|
14042
|
+
return warnings;
|
|
14043
|
+
}
|
|
14044
|
+
|
|
14045
|
+
// packages/agent-runtime/workspaceShell.ts
|
|
14046
|
+
import { resolve } from "node:path";
|
|
14047
|
+
import { spawn as spawnChildProcess } from "node:child_process";
|
|
14048
|
+
|
|
14049
|
+
// packages/agent-runtime/runtimeCompat.ts
|
|
14050
|
+
import { existsSync as existsSync2, readdirSync as readdirSync2, statSync as statSync2 } from "node:fs";
|
|
14051
|
+
import { join as join3 } from "node:path";
|
|
14052
|
+
import { spawn } from "node:child_process";
|
|
14053
|
+
var IS_WINDOWS = process.platform === "win32";
|
|
14054
|
+
function isExecutableFile(candidate) {
|
|
14055
|
+
if (!existsSync2(candidate)) return false;
|
|
14056
|
+
try {
|
|
14057
|
+
return statSync2(candidate).isFile();
|
|
14058
|
+
} catch {
|
|
14059
|
+
return false;
|
|
14060
|
+
}
|
|
14061
|
+
}
|
|
14062
|
+
function resolveExecutableOnPath(name) {
|
|
14063
|
+
if (IS_WINDOWS && !/\.[a-z]+$/i.test(name)) {
|
|
14064
|
+
const exts = (process.env.PATHEXT || ".EXE;.CMD;.BAT").split(";").filter(Boolean);
|
|
14065
|
+
for (const ext of exts) {
|
|
14066
|
+
const found = resolveExecutableOnPath(name + ext);
|
|
14067
|
+
if (found) return found;
|
|
14068
|
+
}
|
|
14069
|
+
return null;
|
|
14070
|
+
}
|
|
14071
|
+
const pathEnv = process.env.PATH ?? "";
|
|
14072
|
+
const sep2 = pathEnv.includes(";") && IS_WINDOWS ? ";" : ":";
|
|
14073
|
+
const pathDirs = pathEnv.split(sep2).filter(Boolean);
|
|
14074
|
+
const fallbackDirs = IS_WINDOWS ? [] : [
|
|
14075
|
+
"/opt/homebrew/bin",
|
|
14076
|
+
"/usr/local/bin",
|
|
14077
|
+
"/usr/bin",
|
|
14078
|
+
"/bin",
|
|
14079
|
+
`${process.env.HOME ?? ""}/.local/bin`
|
|
14080
|
+
].filter(Boolean);
|
|
14081
|
+
for (const dir of [...pathDirs, ...fallbackDirs]) {
|
|
14082
|
+
const candidate = join3(dir, name);
|
|
14083
|
+
if (isExecutableFile(candidate)) return candidate;
|
|
14084
|
+
}
|
|
14085
|
+
return null;
|
|
14086
|
+
}
|
|
14087
|
+
function createGlob(pattern) {
|
|
14088
|
+
const regex = globToRegExp(pattern);
|
|
14089
|
+
return {
|
|
14090
|
+
match(path) {
|
|
14091
|
+
return regex.test(path);
|
|
14092
|
+
},
|
|
14093
|
+
scanSync(opts) {
|
|
14094
|
+
const dot = opts.dot ?? false;
|
|
14095
|
+
const results2 = [];
|
|
14096
|
+
walkDir(opts.cwd, "", dot, results2);
|
|
14097
|
+
return results2.filter((rel) => regex.test(rel));
|
|
14098
|
+
}
|
|
14099
|
+
};
|
|
14100
|
+
}
|
|
14101
|
+
function walkDir(dir, prefix, dot, out) {
|
|
14102
|
+
let entries;
|
|
14103
|
+
try {
|
|
14104
|
+
entries = readdirSync2(dir, { withFileTypes: true, encoding: "utf8" });
|
|
14105
|
+
} catch {
|
|
14106
|
+
return;
|
|
14107
|
+
}
|
|
14108
|
+
for (const entry of entries) {
|
|
14109
|
+
const name = String(entry.name);
|
|
14110
|
+
if (!dot && name.startsWith(".")) continue;
|
|
14111
|
+
const rel = prefix ? `${prefix}/${name}` : name;
|
|
14020
14112
|
const full = join3(dir, name);
|
|
14021
14113
|
if (entry.isDirectory()) {
|
|
14022
14114
|
walkDir(full, rel, dot, out);
|
|
@@ -14107,9 +14199,9 @@ function spawnToWebStreams(options) {
|
|
|
14107
14199
|
env: options.env,
|
|
14108
14200
|
stdio: ["ignore", "pipe", "pipe"]
|
|
14109
14201
|
});
|
|
14110
|
-
const exited = new Promise((
|
|
14111
|
-
child.on("exit", (code) =>
|
|
14112
|
-
child.on("error", () =>
|
|
14202
|
+
const exited = new Promise((resolve6) => {
|
|
14203
|
+
child.on("exit", (code) => resolve6(code ?? 1));
|
|
14204
|
+
child.on("error", () => resolve6(127));
|
|
14113
14205
|
});
|
|
14114
14206
|
const toWeb = (stream) => {
|
|
14115
14207
|
if (!stream) return null;
|
|
@@ -14128,220 +14220,26 @@ function spawnToWebStreams(options) {
|
|
|
14128
14220
|
};
|
|
14129
14221
|
}
|
|
14130
14222
|
|
|
14131
|
-
// packages/agent-runtime/
|
|
14132
|
-
|
|
14133
|
-
|
|
14134
|
-
|
|
14135
|
-
|
|
14136
|
-
|
|
14137
|
-
|
|
14138
|
-
|
|
14139
|
-
async function readRootGitignorePatterns(workspaceRoot) {
|
|
14140
|
-
const content = await readFile(resolve(workspaceRoot, ".gitignore"), "utf8").catch(() => null);
|
|
14141
|
-
if (content === null) return [];
|
|
14142
|
-
return content.split(/\r?\n/).map((line) => line.trim()).filter((line) => line && !line.startsWith("#") && !line.startsWith("!")).flatMap((line) => {
|
|
14143
|
-
const unanchored = line.replace(/^\//, "");
|
|
14144
|
-
if (unanchored.endsWith("/")) return [`${unanchored}**`];
|
|
14145
|
-
if (unanchored.includes("**")) return [unanchored];
|
|
14146
|
-
return [unanchored, `${unanchored}/**`];
|
|
14147
|
-
});
|
|
14148
|
-
}
|
|
14149
|
-
async function hasRootGitignore(workspaceRoot) {
|
|
14150
|
-
try {
|
|
14151
|
-
await stat(resolve(workspaceRoot, ".gitignore"));
|
|
14152
|
-
return true;
|
|
14153
|
-
} catch {
|
|
14154
|
-
return false;
|
|
14155
|
-
}
|
|
14156
|
-
}
|
|
14157
|
-
|
|
14158
|
-
// packages/agent-runtime/fileTextSearch.ts
|
|
14159
|
-
var normalizePath = (value) => value.replaceAll("\\", "/");
|
|
14160
|
-
var pathFor = (root, file, absolute = false) => absolute ? normalizePath(file) : normalizePath(relative2(root, file) || basename(file));
|
|
14161
|
-
var COMMAND_LIMIT_HEADROOM = 1;
|
|
14162
|
-
async function runCommand(binary, args2, cwd, maxResults) {
|
|
14163
|
-
const recordLimit = maxResults === void 0 ? 0 : Math.max(0, maxResults) + COMMAND_LIMIT_HEADROOM;
|
|
14164
|
-
return await new Promise((done4) => {
|
|
14165
|
-
let stdout = "", stderr = "", recordCount = 0, stopped = false;
|
|
14166
|
-
try {
|
|
14167
|
-
const child = spawnChildProcess(binary, args2, { cwd, stdio: ["ignore", "pipe", "pipe"] });
|
|
14168
|
-
child.stdout.on("data", (chunk) => {
|
|
14169
|
-
stdout += chunk.toString();
|
|
14170
|
-
recordCount = parseMatches(cwd, stdout).length;
|
|
14171
|
-
if (recordLimit > 0 && recordCount >= recordLimit && !stopped) {
|
|
14172
|
-
stopped = true;
|
|
14173
|
-
child.kill();
|
|
14174
|
-
}
|
|
14175
|
-
});
|
|
14176
|
-
child.stderr.on("data", (chunk) => {
|
|
14177
|
-
stderr += chunk.toString();
|
|
14178
|
-
});
|
|
14179
|
-
child.on("error", () => done4({ stdout, stderr, outcome: { kind: "spawn-failed" } }));
|
|
14180
|
-
child.on("close", (exitCode) => done4({ stdout, stderr, outcome: stopped ? { kind: "stopped-by-limit" } : { kind: "completed", exitCode } }));
|
|
14181
|
-
} catch {
|
|
14182
|
-
done4({ stdout, stderr, outcome: { kind: "spawn-failed" } });
|
|
14183
|
-
}
|
|
14184
|
-
});
|
|
14223
|
+
// packages/agent-runtime/processTask.ts
|
|
14224
|
+
var PROCESS_TASK_TERMINAL_STATUSES = [
|
|
14225
|
+
"stopped",
|
|
14226
|
+
"exited",
|
|
14227
|
+
"failed"
|
|
14228
|
+
];
|
|
14229
|
+
function isProcessTaskTerminalStatus(status) {
|
|
14230
|
+
return typeof status === "string" && PROCESS_TASK_TERMINAL_STATUSES.includes(status);
|
|
14185
14231
|
}
|
|
14186
|
-
function
|
|
14187
|
-
|
|
14188
|
-
|
|
14189
|
-
if (o.regex !== true) args2.push(binary === "rg" ? "--fixed-strings" : "-F");
|
|
14190
|
-
else if (binary === "grep") args2.push("-E");
|
|
14191
|
-
if (o.caseSensitive === false) args2.push("-i");
|
|
14192
|
-
if (binary === "rg") {
|
|
14193
|
-
if (o.includeIgnored) args2.push("--no-ignore");
|
|
14194
|
-
for (const x of o.exclude ?? []) args2.push("--glob", `!${x}`);
|
|
14195
|
-
if (o.include) args2.push("--glob", o.include);
|
|
14196
|
-
} else {
|
|
14197
|
-
for (const x of o.exclude ?? []) {
|
|
14198
|
-
const clean = x.replace(/\/\*\*$/, "");
|
|
14199
|
-
if (clean && !clean.includes("/")) args2.push("--exclude-dir", clean);
|
|
14200
|
-
}
|
|
14201
|
-
if (o.include) args2.push("--include", o.include);
|
|
14232
|
+
function reportedTaskStatus(source, exitCode) {
|
|
14233
|
+
if (source === "killed") {
|
|
14234
|
+
return "stopped";
|
|
14202
14235
|
}
|
|
14203
|
-
|
|
14204
|
-
|
|
14205
|
-
}
|
|
14206
|
-
function parseMatches(root, output) {
|
|
14207
|
-
const records = [];
|
|
14208
|
-
const pattern = /(?:^|\n)([^\0\n]+)\0(\d+):(.*?)(?=\n[^\0\n]+\0|$)/gs;
|
|
14209
|
-
for (const match7 of output.matchAll(pattern)) {
|
|
14210
|
-
records.push({ file: resolve2(root, match7[1] ?? ""), line: Number(match7[2]), text: (match7[3] ?? "").replace(/\n$/, "") });
|
|
14236
|
+
if (source === "exited") {
|
|
14237
|
+
return exitCode !== void 0 && exitCode !== 0 ? "failed" : "exited";
|
|
14211
14238
|
}
|
|
14212
|
-
|
|
14213
|
-
|
|
14214
|
-
async function decorate(root, raw, context3, absolute = false) {
|
|
14215
|
-
const cache = /* @__PURE__ */ new Map(), out = [];
|
|
14216
|
-
for (const x of raw) {
|
|
14217
|
-
let lines = cache.get(x.file);
|
|
14218
|
-
if (!lines) {
|
|
14219
|
-
try {
|
|
14220
|
-
lines = (await readFile2(x.file, "utf8")).split(/\r\n|\r|\n/);
|
|
14221
|
-
} catch {
|
|
14222
|
-
continue;
|
|
14223
|
-
}
|
|
14224
|
-
cache.set(x.file, lines);
|
|
14225
|
-
}
|
|
14226
|
-
const i = x.line - 1;
|
|
14227
|
-
out.push({ path: pathFor(root, x.file, absolute), line: x.line, text: lines[i] ?? x.text, before: lines.slice(Math.max(0, i - context3), i), after: lines.slice(i + 1, i + context3 + 1) });
|
|
14239
|
+
if (source === "started" || source === "promoted") {
|
|
14240
|
+
return "running";
|
|
14228
14241
|
}
|
|
14229
|
-
return
|
|
14230
|
-
}
|
|
14231
|
-
function globMatch(pattern, value) {
|
|
14232
|
-
const p = normalizePath(pattern).replace(/^!/, "");
|
|
14233
|
-
let source = "";
|
|
14234
|
-
for (let i = 0; i < p.length; i++) {
|
|
14235
|
-
const c = p[i];
|
|
14236
|
-
if (c === "*" && p[i + 1] === "*") {
|
|
14237
|
-
i++;
|
|
14238
|
-
if (p[i + 1] === "/") {
|
|
14239
|
-
i++;
|
|
14240
|
-
source += "(?:.*/)?";
|
|
14241
|
-
} else source += ".*";
|
|
14242
|
-
} else if (c === "*") source += "[^/]*";
|
|
14243
|
-
else if (c === "?") source += "[^/]";
|
|
14244
|
-
else source += c.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
14245
|
-
}
|
|
14246
|
-
const r = new RegExp(`^${source}$`);
|
|
14247
|
-
return r.test(value) || r.test(basename(value));
|
|
14248
|
-
}
|
|
14249
|
-
var defaultReadTextFile = (filePath) => readFile2(filePath, "utf8").catch(() => "");
|
|
14250
|
-
async function jsSearch(o, targetPath) {
|
|
14251
|
-
const max4 = o.maxResults ?? Number.MAX_SAFE_INTEGER;
|
|
14252
|
-
const excludes = o.exclude ?? [];
|
|
14253
|
-
const readText = o.readTextFile ?? defaultReadTextFile;
|
|
14254
|
-
const files = [];
|
|
14255
|
-
const targetStat = await stat2(targetPath).catch(() => null);
|
|
14256
|
-
if (!targetStat) return { matches: [], totalMatches: 0, truncated: false, engine: "js" };
|
|
14257
|
-
const ignorePatterns = o.includeIgnored ? [] : await readRootGitignorePatterns(o.root);
|
|
14258
|
-
const isIgnored = (rel) => ignorePatterns.some((pattern) => globMatch(pattern, rel));
|
|
14259
|
-
const isSearchableFile = (filePath) => {
|
|
14260
|
-
const rel = pathFor(o.root, filePath);
|
|
14261
|
-
return !excludes.some((pattern) => globMatch(pattern, rel)) && !isIgnored(rel) && (!o.include || globMatch(o.include, rel));
|
|
14262
|
-
};
|
|
14263
|
-
if (targetStat.isFile()) {
|
|
14264
|
-
if (isSearchableFile(targetPath)) files.push(targetPath);
|
|
14265
|
-
} else {
|
|
14266
|
-
const walk = async (dir) => {
|
|
14267
|
-
for (const e of await readdir(dir, { withFileTypes: true })) {
|
|
14268
|
-
const f = resolve2(dir, e.name), rel = pathFor(o.root, f);
|
|
14269
|
-
if (e.isDirectory()) {
|
|
14270
|
-
if (!excludes.some((p) => globMatch(p, rel))) await walk(f);
|
|
14271
|
-
} else if (e.isFile() && !excludes.some((p) => globMatch(p, rel)) && !isIgnored(rel) && (!o.include || globMatch(o.include, rel))) {
|
|
14272
|
-
files.push(f);
|
|
14273
|
-
}
|
|
14274
|
-
}
|
|
14275
|
-
};
|
|
14276
|
-
await walk(targetPath);
|
|
14277
|
-
}
|
|
14278
|
-
const matcher = o.regex ? new RegExp(o.query, o.caseSensitive === false ? "i" : "") : null;
|
|
14279
|
-
const needle = o.caseSensitive === false ? o.query.toLowerCase() : o.query;
|
|
14280
|
-
const out = [], context3 = o.contextLines ?? 0;
|
|
14281
|
-
for (const file of files) {
|
|
14282
|
-
const text = await readText(file);
|
|
14283
|
-
if (!text || text.includes("\0")) continue;
|
|
14284
|
-
const lines = text.split(/\r\n|\r|\n/);
|
|
14285
|
-
for (let i = 0; i < lines.length; i++) {
|
|
14286
|
-
const line = lines[i] ?? "";
|
|
14287
|
-
const hit = matcher ? matcher.test(line) : o.caseSensitive === false ? line.toLowerCase().includes(needle) : line.includes(needle);
|
|
14288
|
-
if (!hit) continue;
|
|
14289
|
-
if (out.length >= max4) return { matches: out, totalMatches: max4, truncated: true, engine: "js" };
|
|
14290
|
-
out.push({ path: pathFor(o.root, file, o.absolutePaths === true), line: i + 1, text: line, before: lines.slice(Math.max(0, i - context3), i), after: lines.slice(i + 1, i + context3 + 1) });
|
|
14291
|
-
}
|
|
14292
|
-
}
|
|
14293
|
-
return { matches: out, totalMatches: out.length, truncated: false, engine: "js" };
|
|
14294
|
-
}
|
|
14295
|
-
var COMMAND_ENGINES = [
|
|
14296
|
-
{ engine: "ripgrep", binaryOption: "resolveRipgrepBinary", binaryName: "rg", argsKey: "rg" },
|
|
14297
|
-
{ engine: "grep", binaryOption: "resolveGrepBinary", binaryName: "grep", argsKey: "grep" }
|
|
14298
|
-
];
|
|
14299
|
-
async function searchFileTextMatches(o) {
|
|
14300
|
-
const targetPath = resolve2(o.root, o.target || ".");
|
|
14301
|
-
const targetStat = await stat2(targetPath).catch(() => null);
|
|
14302
|
-
if (!targetStat) return { matches: [], totalMatches: 0, truncated: false, engine: "js" };
|
|
14303
|
-
if (targetStat.isFile()) return jsSearch(o, targetPath);
|
|
14304
|
-
const run2 = o.runCommand ?? runCommand, max4 = o.maxResults;
|
|
14305
|
-
for (const entry of COMMAND_ENGINES) {
|
|
14306
|
-
const injectedResolver = o[entry.binaryOption];
|
|
14307
|
-
const binary = injectedResolver ? injectedResolver() : resolveExecutableOnPath(entry.binaryName);
|
|
14308
|
-
if (!binary) continue;
|
|
14309
|
-
const result4 = await run2(binary, commandArgs(o, entry.argsKey, o.target || "."), o.root, max4);
|
|
14310
|
-
const raw = parseMatches(o.root, result4.stdout);
|
|
14311
|
-
const hardFailed = result4.outcome.kind === "spawn-failed" || result4.outcome.kind === "completed" && result4.outcome.exitCode !== 0 && result4.outcome.exitCode !== 1;
|
|
14312
|
-
if (hardFailed) continue;
|
|
14313
|
-
const truncated = raw.length > (max4 ?? Number.MAX_SAFE_INTEGER);
|
|
14314
|
-
const matches = await decorate(o.root, raw.slice(0, max4), o.contextLines ?? 0, o.absolutePaths === true);
|
|
14315
|
-
return {
|
|
14316
|
-
matches,
|
|
14317
|
-
totalMatches: truncated ? matches.length : raw.length,
|
|
14318
|
-
truncated,
|
|
14319
|
-
engine: entry.engine
|
|
14320
|
-
};
|
|
14321
|
-
}
|
|
14322
|
-
return jsSearch(o, targetPath);
|
|
14323
|
-
}
|
|
14324
|
-
|
|
14325
|
-
// packages/agent-runtime/processTask.ts
|
|
14326
|
-
var PROCESS_TASK_TERMINAL_STATUSES = [
|
|
14327
|
-
"stopped",
|
|
14328
|
-
"exited",
|
|
14329
|
-
"failed"
|
|
14330
|
-
];
|
|
14331
|
-
function isProcessTaskTerminalStatus(status) {
|
|
14332
|
-
return typeof status === "string" && PROCESS_TASK_TERMINAL_STATUSES.includes(status);
|
|
14333
|
-
}
|
|
14334
|
-
function reportedTaskStatus(source, exitCode) {
|
|
14335
|
-
if (source === "killed") {
|
|
14336
|
-
return "stopped";
|
|
14337
|
-
}
|
|
14338
|
-
if (source === "exited") {
|
|
14339
|
-
return exitCode !== void 0 && exitCode !== 0 ? "failed" : "exited";
|
|
14340
|
-
}
|
|
14341
|
-
if (source === "started" || source === "promoted") {
|
|
14342
|
-
return "running";
|
|
14343
|
-
}
|
|
14344
|
-
return source;
|
|
14242
|
+
return source;
|
|
14345
14243
|
}
|
|
14346
14244
|
var DEFAULT_TASK_EVENT_RETENTION_MS = 5 * 60 * 1e3;
|
|
14347
14245
|
var DEFAULT_MAX_TASK_EVENTS_TASKS = 200;
|
|
@@ -14445,20 +14343,20 @@ var ProcessTaskEventLog = class {
|
|
|
14445
14343
|
};
|
|
14446
14344
|
|
|
14447
14345
|
// packages/agent-runtime/processRegistry.ts
|
|
14448
|
-
function toProcessTaskView(
|
|
14449
|
-
const capsule =
|
|
14346
|
+
function toProcessTaskView(record2) {
|
|
14347
|
+
const capsule = record2.resultCapsule;
|
|
14450
14348
|
return {
|
|
14451
|
-
taskId:
|
|
14452
|
-
pid:
|
|
14453
|
-
pgid:
|
|
14454
|
-
command:
|
|
14455
|
-
label:
|
|
14456
|
-
startedAt:
|
|
14457
|
-
status:
|
|
14458
|
-
...
|
|
14459
|
-
persist:
|
|
14460
|
-
promoted:
|
|
14461
|
-
transient:
|
|
14349
|
+
taskId: record2.taskId,
|
|
14350
|
+
pid: record2.pid,
|
|
14351
|
+
pgid: record2.pgid,
|
|
14352
|
+
command: record2.command,
|
|
14353
|
+
label: record2.label,
|
|
14354
|
+
startedAt: record2.startedAt,
|
|
14355
|
+
status: record2.status,
|
|
14356
|
+
...record2.exitCode !== void 0 ? { exitCode: record2.exitCode } : {},
|
|
14357
|
+
persist: record2.persist,
|
|
14358
|
+
promoted: record2.promoted,
|
|
14359
|
+
transient: record2.transient,
|
|
14462
14360
|
...capsule?.durationMs !== void 0 ? { durationMs: capsule.durationMs } : {},
|
|
14463
14361
|
...capsule?.spill ? { outputRef: capsule.spill.displayPath } : {}
|
|
14464
14362
|
};
|
|
@@ -14509,7 +14407,7 @@ var ProcessRegistry = class {
|
|
|
14509
14407
|
* `started` event. Returns the stored record (with its stable taskId).
|
|
14510
14408
|
*/
|
|
14511
14409
|
add(proc) {
|
|
14512
|
-
const
|
|
14410
|
+
const record2 = {
|
|
14513
14411
|
taskId: proc.taskId ?? mintTaskId(proc.pid),
|
|
14514
14412
|
pid: proc.pid,
|
|
14515
14413
|
pgid: proc.pgid,
|
|
@@ -14522,10 +14420,10 @@ var ProcessRegistry = class {
|
|
|
14522
14420
|
transient: proc.transient ?? false,
|
|
14523
14421
|
owner: proc.owner ?? null
|
|
14524
14422
|
};
|
|
14525
|
-
this.processes.set(proc.pid,
|
|
14526
|
-
this.byTaskId.set(
|
|
14527
|
-
this.eventLog.append({ taskId:
|
|
14528
|
-
return { ...
|
|
14423
|
+
this.processes.set(proc.pid, record2);
|
|
14424
|
+
this.byTaskId.set(record2.taskId, proc.pid);
|
|
14425
|
+
this.eventLog.append({ taskId: record2.taskId, pid: proc.pid, type: "started" });
|
|
14426
|
+
return { ...record2 };
|
|
14529
14427
|
}
|
|
14530
14428
|
list() {
|
|
14531
14429
|
return Array.from(this.processes.values()).map((proc) => ({ ...proc }));
|
|
@@ -14775,28 +14673,7 @@ function buildProcessTaskResultCapsule(args2) {
|
|
|
14775
14673
|
};
|
|
14776
14674
|
}
|
|
14777
14675
|
|
|
14778
|
-
// packages/agent-runtime/processOwnership.ts
|
|
14779
|
-
var asNonEmptyString = (value) => {
|
|
14780
|
-
if (typeof value !== "string") return null;
|
|
14781
|
-
const trimmed = value.trim();
|
|
14782
|
-
return trimmed ? trimmed : null;
|
|
14783
|
-
};
|
|
14784
|
-
function readProcessOwner(runtimeContext) {
|
|
14785
|
-
if (!runtimeContext || typeof runtimeContext !== "object") return null;
|
|
14786
|
-
const dialogId = asNonEmptyString(runtimeContext.dialogId) ?? asNonEmptyString(runtimeContext.parentThreadId);
|
|
14787
|
-
if (!dialogId) return null;
|
|
14788
|
-
const turnId = asNonEmptyString(runtimeContext.turnId);
|
|
14789
|
-
const ownerId = asNonEmptyString(runtimeContext.ownerId);
|
|
14790
|
-
return {
|
|
14791
|
-
dialogId,
|
|
14792
|
-
...turnId ? { turnId } : {},
|
|
14793
|
-
...ownerId ? { ownerId } : {}
|
|
14794
|
-
};
|
|
14795
|
-
}
|
|
14796
|
-
|
|
14797
14676
|
// packages/agent-runtime/workspaceShell.ts
|
|
14798
|
-
import { resolve as resolve3 } from "node:path";
|
|
14799
|
-
import { spawn as spawnChildProcess2 } from "node:child_process";
|
|
14800
14677
|
var EXEC_SHELL_TIMEOUT_ENV = "NOLO_EXEC_SHELL_TIMEOUT_MS";
|
|
14801
14678
|
var EXEC_SHELL_DETACH_ENV = "NOLO_EXEC_SHELL_DETACH_MS";
|
|
14802
14679
|
var DEFAULT_EXEC_SHELL_DETACH_MS = 12e4;
|
|
@@ -14920,8 +14797,12 @@ function wrapPowerShellCommand(command, shellKind = "pwsh") {
|
|
|
14920
14797
|
command
|
|
14921
14798
|
].join("; ");
|
|
14922
14799
|
}
|
|
14800
|
+
var cachedPowerShellExecutable;
|
|
14801
|
+
var cachedBashExecutable;
|
|
14923
14802
|
function findPowerShellExecutable() {
|
|
14924
|
-
|
|
14803
|
+
if (cachedPowerShellExecutable !== void 0) return cachedPowerShellExecutable;
|
|
14804
|
+
cachedPowerShellExecutable = resolveExecutableOnPath("pwsh") || resolveExecutableOnPath("powershell.exe") || resolveExecutableOnPath("powershell");
|
|
14805
|
+
return cachedPowerShellExecutable;
|
|
14925
14806
|
}
|
|
14926
14807
|
function buildPowerShellSpawnArgs(args2) {
|
|
14927
14808
|
return [
|
|
@@ -14935,14 +14816,23 @@ function buildPowerShellSpawnArgs(args2) {
|
|
|
14935
14816
|
wrapPowerShellCommand(args2.command, resolvePowerShellShellKind(args2.executable))
|
|
14936
14817
|
];
|
|
14937
14818
|
}
|
|
14938
|
-
function
|
|
14939
|
-
|
|
14940
|
-
|
|
14941
|
-
|
|
14819
|
+
function resolveShellLoginMode() {
|
|
14820
|
+
if (process.env.NOLO_SHELL_LOGIN_MODE === "login" || process.env.NOLO_LOGIN_SHELL === "1") {
|
|
14821
|
+
return "login";
|
|
14822
|
+
}
|
|
14823
|
+
return "fast";
|
|
14824
|
+
}
|
|
14825
|
+
function buildBashCommand(command, options) {
|
|
14826
|
+
if (cachedBashExecutable === void 0) {
|
|
14827
|
+
cachedBashExecutable = resolveExecutableOnPath("bash") || resolveExecutableOnPath("sh");
|
|
14828
|
+
}
|
|
14829
|
+
if (!cachedBashExecutable) throw new Error("bash/sh is not available on this machine.");
|
|
14830
|
+
const isLogin = options?.login ?? resolveShellLoginMode() === "login";
|
|
14831
|
+
return [cachedBashExecutable, isLogin ? "-lc" : "-c", command];
|
|
14942
14832
|
}
|
|
14943
14833
|
function buildWorkspaceShellPlan(args2) {
|
|
14944
14834
|
if (args2.shell === "bash") {
|
|
14945
|
-
const argv2 = buildBashCommand(args2.command);
|
|
14835
|
+
const argv2 = buildBashCommand(args2.command, { login: args2.login });
|
|
14946
14836
|
return { argv: argv2, resolvedShell: "bash", executable: argv2[0] ?? "bash" };
|
|
14947
14837
|
}
|
|
14948
14838
|
if (args2.shell === "powershell" || process.platform === "win32") {
|
|
@@ -14955,7 +14845,7 @@ function buildWorkspaceShellPlan(args2) {
|
|
|
14955
14845
|
shellKind: resolvePowerShellShellKind(executable)
|
|
14956
14846
|
};
|
|
14957
14847
|
}
|
|
14958
|
-
const argv = buildBashCommand(args2.command);
|
|
14848
|
+
const argv = buildBashCommand(args2.command, { login: args2.login });
|
|
14959
14849
|
return { argv, resolvedShell: "bash", executable: argv[0] ?? "bash" };
|
|
14960
14850
|
}
|
|
14961
14851
|
function buildWorkspaceShellCommand(args2) {
|
|
@@ -15100,13 +14990,13 @@ function readNodeStream(stream, maxBytes = DEFAULT_MAX_STREAM_BUFFER_BYTES) {
|
|
|
15100
14990
|
const finalize2 = (truncated = false) => {
|
|
15101
14991
|
if (settled) return;
|
|
15102
14992
|
settled = true;
|
|
15103
|
-
let
|
|
14993
|
+
let text2 = Buffer.concat(chunks2).toString("utf8");
|
|
15104
14994
|
if (truncated) {
|
|
15105
|
-
|
|
14995
|
+
text2 += `
|
|
15106
14996
|
|
|
15107
14997
|
[stream pipe truncated: output exceeded ${formatLimit} buffer limit]`;
|
|
15108
14998
|
}
|
|
15109
|
-
resolveStream(
|
|
14999
|
+
resolveStream(text2);
|
|
15110
15000
|
};
|
|
15111
15001
|
stream.on("data", (chunk) => {
|
|
15112
15002
|
if (settled) return;
|
|
@@ -15192,8 +15082,8 @@ async function runWorkspaceCommand(args2) {
|
|
|
15192
15082
|
...args2.commandPrefix ?? [],
|
|
15193
15083
|
...args2.command
|
|
15194
15084
|
];
|
|
15195
|
-
const proc =
|
|
15196
|
-
cwd:
|
|
15085
|
+
const proc = spawnChildProcess(command[0] ?? "", command.slice(1), {
|
|
15086
|
+
cwd: resolve(args2.workspaceRoot),
|
|
15197
15087
|
stdio: [
|
|
15198
15088
|
args2.stdin === void 0 ? "ignore" : "pipe",
|
|
15199
15089
|
"pipe",
|
|
@@ -15407,25 +15297,495 @@ Use listProcesses to inspect or stop it.`,
|
|
|
15407
15297
|
` : ""}command timed out after ${timeoutMs ?? "unknown"}ms
|
|
15408
15298
|
` : rawStderr;
|
|
15409
15299
|
return {
|
|
15410
|
-
stdout,
|
|
15411
|
-
stderr,
|
|
15412
|
-
exitCode,
|
|
15413
|
-
timedOut,
|
|
15414
|
-
aborted,
|
|
15415
|
-
content: truncateToolOutput(
|
|
15416
|
-
[
|
|
15417
|
-
stdout.trim() ? `stdout:
|
|
15418
|
-
${stdout.trim()}` : "",
|
|
15419
|
-
stderr.trim() ? `stderr:
|
|
15420
|
-
${stderr.trim()}` : "",
|
|
15421
|
-
`exitCode: ${exitCode}`
|
|
15422
|
-
].filter(Boolean).join("\n\n"),
|
|
15423
|
-
args2.outputLimit,
|
|
15424
|
-
{
|
|
15425
|
-
toolName: "execShell",
|
|
15426
|
-
workspaceRoot: args2.workspaceRoot
|
|
15427
|
-
}
|
|
15428
|
-
)
|
|
15300
|
+
stdout,
|
|
15301
|
+
stderr,
|
|
15302
|
+
exitCode,
|
|
15303
|
+
timedOut,
|
|
15304
|
+
aborted,
|
|
15305
|
+
content: truncateToolOutput(
|
|
15306
|
+
[
|
|
15307
|
+
stdout.trim() ? `stdout:
|
|
15308
|
+
${stdout.trim()}` : "",
|
|
15309
|
+
stderr.trim() ? `stderr:
|
|
15310
|
+
${stderr.trim()}` : "",
|
|
15311
|
+
`exitCode: ${exitCode}`
|
|
15312
|
+
].filter(Boolean).join("\n\n"),
|
|
15313
|
+
args2.outputLimit,
|
|
15314
|
+
{
|
|
15315
|
+
toolName: "execShell",
|
|
15316
|
+
workspaceRoot: args2.workspaceRoot
|
|
15317
|
+
}
|
|
15318
|
+
)
|
|
15319
|
+
};
|
|
15320
|
+
}
|
|
15321
|
+
|
|
15322
|
+
// packages/agent-runtime/capabilities/execShellCapability.ts
|
|
15323
|
+
function buildExecShellToolDefinition(toolName = "execShell") {
|
|
15324
|
+
return {
|
|
15325
|
+
type: "function",
|
|
15326
|
+
function: {
|
|
15327
|
+
name: toolName,
|
|
15328
|
+
description: `Execute a shell command from the workspace root. Prefer one compound command (e.g. 'git status && git diff --stat') to perform complete verification in one step instead of multiple small roundtrips. Do not cd into guessed paths; commands already run from the workspace root. Commands block until exit. Long-running commands (sleep over ${IMMEDIATE_DETACH_SLEEP_THRESHOLD_SECONDS}s, dev servers, watchers) automatically detach to background returning {detached: true, pid, label}; for persistent services, prefer launchProcess. On Windows the resolved shell may be Windows PowerShell 5.1 (metadata.shellKind="powershell5"): it does not support '&&'/'||' or $PSStyle \u2014 join commands with ';' or split into multiple calls. metadata.shellKind="pwsh" means PowerShell 7+ with full syntax. Read resolvedShell/shellKind from any execShell result before writing Windows-specific syntax. LIFECYCLE CONTRACT (misreading this contract silenced a real dialog for 10 hours): (1) A normal command waits synchronously for at most 120 seconds; if it ends inside that window the call IS finished \u2014 a result containing exitCode means the command has already completed, never "still running"; parse it immediately (no later event will remind you). (2) Only a result with metadata.detached === true AND a taskId represents a tracked background task that may trigger completion wake-up (terminal completion turn carrying a bounded result capsule); that handle may be waited on with taskWait and will produce a completion notification (a launchProcess taskId only yields a notice on your next real turn, never a new turn). (3) Text the command itself prints (LAUNCHED, STARTED, BACKGROUND, ...) is plain stdout with zero lifecycle meaning \u2014 never read it as a platform receipt. (4) Shell-level backgrounding (\`&\`, nohup, disown, setsid, self-daemonizing scripts, PowerShell Start-Process) is NOT tracked: those descendants produce no completion notification, and the outer shell finishing tells you nothing about them. Use background: true to turn a finite job into a tracked background task immediately. When a synchronous result's core output was redirected to a file, read that file in the SAME turn ("read it later" means it is lost) \u2014 never end the turn promising a later automatic report without a taskId.`,
|
|
15329
|
+
parameters: {
|
|
15330
|
+
type: "object",
|
|
15331
|
+
properties: {
|
|
15332
|
+
command: {
|
|
15333
|
+
type: "string",
|
|
15334
|
+
description: "Shell command to run (non-empty)."
|
|
15335
|
+
},
|
|
15336
|
+
cmd: {
|
|
15337
|
+
type: "string",
|
|
15338
|
+
description: "Compatibility alias for command."
|
|
15339
|
+
},
|
|
15340
|
+
background: {
|
|
15341
|
+
type: "boolean",
|
|
15342
|
+
description: "Immediately detach this command into a tracked background task (no 120s synchronous wait): returns {detached: true, taskId}, and on completion the platform resumes this conversation with a bounded result capsule (exitCode, duration, stdout/stderr tail). Default false. Use for finite jobs (tests, builds, batch) whose result you need later; NOT for dev servers/watchers \u2014 use launchProcess for those."
|
|
15343
|
+
}
|
|
15344
|
+
}
|
|
15345
|
+
}
|
|
15346
|
+
}
|
|
15347
|
+
};
|
|
15348
|
+
}
|
|
15349
|
+
function normalizeExecShellInput(input) {
|
|
15350
|
+
if (input === null || input === void 0) {
|
|
15351
|
+
throw new Error("execShell requires a non-empty command.");
|
|
15352
|
+
}
|
|
15353
|
+
if (typeof input === "string") {
|
|
15354
|
+
const trimmed = input.trim();
|
|
15355
|
+
if (!trimmed) {
|
|
15356
|
+
throw new Error("execShell requires a non-empty command.");
|
|
15357
|
+
}
|
|
15358
|
+
if (trimmed.startsWith("{") && trimmed.endsWith("}")) {
|
|
15359
|
+
try {
|
|
15360
|
+
const parsed = JSON.parse(trimmed);
|
|
15361
|
+
if (parsed && typeof parsed === "object") {
|
|
15362
|
+
return normalizeExecShellInput(parsed);
|
|
15363
|
+
}
|
|
15364
|
+
} catch {
|
|
15365
|
+
}
|
|
15366
|
+
}
|
|
15367
|
+
return { command: trimmed };
|
|
15368
|
+
}
|
|
15369
|
+
if (typeof input === "object") {
|
|
15370
|
+
const record2 = input;
|
|
15371
|
+
let rawCommand = resolveShellCommandArg(record2);
|
|
15372
|
+
if (typeof rawCommand !== "string" || !rawCommand.trim()) {
|
|
15373
|
+
const fallback = record2.command ?? record2.cmd;
|
|
15374
|
+
if (typeof fallback === "string" && fallback.trim()) {
|
|
15375
|
+
rawCommand = fallback;
|
|
15376
|
+
}
|
|
15377
|
+
}
|
|
15378
|
+
const command = typeof rawCommand === "string" ? rawCommand.trim() : "";
|
|
15379
|
+
if (!command) {
|
|
15380
|
+
throw new Error("execShell requires a non-empty command.");
|
|
15381
|
+
}
|
|
15382
|
+
const activity = extractActivity(record2);
|
|
15383
|
+
const background = record2.background === true || typeof record2.background === "string" && record2.background.trim().toLowerCase() === "true";
|
|
15384
|
+
const login = typeof record2.login === "boolean" ? record2.login : typeof record2.login === "string" ? record2.login.trim().toLowerCase() === "true" : void 0;
|
|
15385
|
+
return {
|
|
15386
|
+
command,
|
|
15387
|
+
...record2.shell !== void 0 ? { shell: record2.shell } : {},
|
|
15388
|
+
...login !== void 0 ? { login } : {},
|
|
15389
|
+
...activity ? { activity } : {},
|
|
15390
|
+
...record2.input !== void 0 ? { input: record2.input } : {},
|
|
15391
|
+
...background ? { background: true } : {}
|
|
15392
|
+
};
|
|
15393
|
+
}
|
|
15394
|
+
throw new Error("execShell requires a non-empty command.");
|
|
15395
|
+
}
|
|
15396
|
+
function execShellExecutionBinding(input, ctx) {
|
|
15397
|
+
return JSON.stringify({
|
|
15398
|
+
input,
|
|
15399
|
+
workspaceRoot: ctx.workspaceRoot || process.cwd(),
|
|
15400
|
+
commandTimeoutMs: ctx.commandTimeoutMs,
|
|
15401
|
+
commandOutputLimit: ctx.commandOutputLimit,
|
|
15402
|
+
commandPrefix: ctx.commandPrefix,
|
|
15403
|
+
restrictToWorkspace: ctx.restrictToWorkspace,
|
|
15404
|
+
detachMs: ctx.detachMs,
|
|
15405
|
+
owner: ctx.owner,
|
|
15406
|
+
confirmed: ctx.confirmed,
|
|
15407
|
+
enableDestructiveShellGuard: ctx.enableDestructiveShellGuard,
|
|
15408
|
+
blockDestructiveWithoutConfirmation: ctx.blockDestructiveWithoutConfirmation,
|
|
15409
|
+
envDigest: createHash3("sha256").update(JSON.stringify(process.env)).digest("hex")
|
|
15410
|
+
});
|
|
15411
|
+
}
|
|
15412
|
+
var execShellCapability = {
|
|
15413
|
+
name: "execShell",
|
|
15414
|
+
getToolDefinition(toolName = "execShell") {
|
|
15415
|
+
return buildExecShellToolDefinition(toolName);
|
|
15416
|
+
},
|
|
15417
|
+
normalizeInput(input) {
|
|
15418
|
+
return normalizeExecShellInput(input);
|
|
15419
|
+
},
|
|
15420
|
+
async invoke(ctx, normalized) {
|
|
15421
|
+
const workspaceRoot = ctx.workspaceRoot || process.cwd();
|
|
15422
|
+
const command = normalized.command;
|
|
15423
|
+
if (ctx.restrictToWorkspace) {
|
|
15424
|
+
const escapeToken = findWorkspaceShellEscapeToken(command);
|
|
15425
|
+
if (escapeToken) {
|
|
15426
|
+
return buildWorkspaceShellEscapeBlockedResult({ command, token: escapeToken });
|
|
15427
|
+
}
|
|
15428
|
+
}
|
|
15429
|
+
const interactiveAuthCommand = extractInteractiveGhAuthCommand(command);
|
|
15430
|
+
if (interactiveAuthCommand) {
|
|
15431
|
+
const blocked = buildInteractiveCommandBlockedResult(interactiveAuthCommand);
|
|
15432
|
+
return {
|
|
15433
|
+
...blocked,
|
|
15434
|
+
metadata: {
|
|
15435
|
+
...blocked.metadata,
|
|
15436
|
+
...normalized.activity ? { activity: normalized.activity } : {}
|
|
15437
|
+
}
|
|
15438
|
+
};
|
|
15439
|
+
}
|
|
15440
|
+
const shellPlan = buildWorkspaceShellPlan({
|
|
15441
|
+
toolName: "execShell",
|
|
15442
|
+
command,
|
|
15443
|
+
shell: normalized.shell,
|
|
15444
|
+
...typeof normalized.login === "boolean" ? { login: normalized.login } : {}
|
|
15445
|
+
});
|
|
15446
|
+
const background = normalized.background === true;
|
|
15447
|
+
const executionArgs = {
|
|
15448
|
+
workspaceRoot,
|
|
15449
|
+
command: shellPlan.argv,
|
|
15450
|
+
timeoutMs: resolveExecShellTimeoutMs(ctx.commandTimeoutMs),
|
|
15451
|
+
outputLimit: ctx.commandOutputLimit,
|
|
15452
|
+
commandPrefix: ctx.commandPrefix,
|
|
15453
|
+
abortSignal: ctx.abortSignal,
|
|
15454
|
+
detachMs: background ? 0 : isImmediateDetachShellCommand({ command }) ? 0 : ctx.detachMs,
|
|
15455
|
+
stdin: typeof normalized.input === "string" ? normalized.input : void 0,
|
|
15456
|
+
// Ownership of the turn that invoked this command: an auto-detached
|
|
15457
|
+
// command keeps its parent dialog so its terminal can resume that
|
|
15458
|
+
// conversation (see processOwnership.ts). Absent ctx.owner = unowned.
|
|
15459
|
+
owner: ctx.owner ?? null
|
|
15460
|
+
};
|
|
15461
|
+
const authority = ctx.execShellApproval;
|
|
15462
|
+
if (authority) {
|
|
15463
|
+
const binding = execShellExecutionBinding(normalized, ctx);
|
|
15464
|
+
const payload = JSON.stringify({ binding, executionArgs });
|
|
15465
|
+
const signal = ctx.abortSignal;
|
|
15466
|
+
const consume = authority.consume;
|
|
15467
|
+
const ticket = await authority.request(payload);
|
|
15468
|
+
if (ctx.execShellApproval !== authority || ctx.abortSignal !== signal || signal?.aborted || execShellExecutionBinding(normalized, ctx) !== binding || JSON.stringify({ binding, executionArgs }) !== payload) {
|
|
15469
|
+
throw new Error("Shell approval final input changed");
|
|
15470
|
+
}
|
|
15471
|
+
if (authority.consume !== consume) throw new Error("Shell approval authority changed");
|
|
15472
|
+
consume.call(authority, ticket, payload);
|
|
15473
|
+
}
|
|
15474
|
+
const result4 = await runWorkspaceCommand(executionArgs);
|
|
15475
|
+
const warnings = result4.detached || result4.spawnFailed ? [] : detectExecShellSynchronousWarnings(command, {
|
|
15476
|
+
resolvedShell: shellPlan.resolvedShell
|
|
15477
|
+
});
|
|
15478
|
+
return {
|
|
15479
|
+
content: warnings.length > 0 ? [result4.content, ...warnings.map((warning) => warning.message)].join("\n\n") : result4.content,
|
|
15480
|
+
metadata: {
|
|
15481
|
+
command,
|
|
15482
|
+
exitCode: result4.exitCode,
|
|
15483
|
+
timedOut: result4.timedOut,
|
|
15484
|
+
resolvedShell: shellPlan.resolvedShell,
|
|
15485
|
+
...shellPlan.shellKind ? { shellKind: shellPlan.shellKind } : {},
|
|
15486
|
+
...result4.aborted ? { aborted: true } : {},
|
|
15487
|
+
...result4.detached ? {
|
|
15488
|
+
detached: true,
|
|
15489
|
+
pid: result4.pid,
|
|
15490
|
+
label: result4.label,
|
|
15491
|
+
// Phase 0: stable taskId from the pre-registered Execution
|
|
15492
|
+
// Envelope (additive; existing detached fields untouched).
|
|
15493
|
+
taskId: result4.taskId,
|
|
15494
|
+
status: "running",
|
|
15495
|
+
// P0 machine-readable execution state: an explicit positive
|
|
15496
|
+
// signal instead of requiring the model to infer "not detached"
|
|
15497
|
+
// from absence. Mirrors the real lifecycle contract.
|
|
15498
|
+
executionState: "detached",
|
|
15499
|
+
trackedBackgroundTask: true,
|
|
15500
|
+
completionNotification: "terminal-resume"
|
|
15501
|
+
} : {
|
|
15502
|
+
// P0 machine-readable execution state: the command already
|
|
15503
|
+
// finished inside the synchronous window; no background task
|
|
15504
|
+
// exists, so no completion notification will ever arrive.
|
|
15505
|
+
executionState: "synchronous-complete",
|
|
15506
|
+
trackedBackgroundTask: false,
|
|
15507
|
+
completionNotification: "none"
|
|
15508
|
+
},
|
|
15509
|
+
...normalized.activity ? { activity: normalized.activity } : {}
|
|
15510
|
+
}
|
|
15511
|
+
};
|
|
15512
|
+
}
|
|
15513
|
+
};
|
|
15514
|
+
|
|
15515
|
+
// packages/agent-runtime/capabilities/capabilitySdk.ts
|
|
15516
|
+
var BUILTIN_CAPABILITIES = [
|
|
15517
|
+
execShellCapability
|
|
15518
|
+
];
|
|
15519
|
+
async function invokeCapability(capabilityOrName, input, ctx = {}) {
|
|
15520
|
+
const capability = typeof capabilityOrName === "string" ? BUILTIN_CAPABILITIES.find((c) => c.name === capabilityOrName) : capabilityOrName;
|
|
15521
|
+
if (!capability) {
|
|
15522
|
+
throw new Error(`Capability "${String(capabilityOrName)}" not found.`);
|
|
15523
|
+
}
|
|
15524
|
+
const normalizedInput = capability.normalizeInput(input);
|
|
15525
|
+
const authority = ctx.execShellApproval;
|
|
15526
|
+
const binding = authority && capability.name === "execShell" ? execShellExecutionBinding(normalizedInput, ctx) : void 0;
|
|
15527
|
+
const signal = ctx.abortSignal;
|
|
15528
|
+
const confirm = ctx.confirmDestructiveAction;
|
|
15529
|
+
await evaluateCapabilityPolicy(capability, normalizedInput, ctx);
|
|
15530
|
+
if (ctx.onInvoke) {
|
|
15531
|
+
await ctx.onInvoke(capability.name, normalizedInput);
|
|
15532
|
+
}
|
|
15533
|
+
if (binding !== void 0 && (ctx.execShellApproval !== authority || ctx.abortSignal !== signal || ctx.confirmDestructiveAction !== confirm || signal?.aborted || execShellExecutionBinding(normalizedInput, ctx) !== binding)) {
|
|
15534
|
+
throw new Error("Shell approval input changed during policy/hook");
|
|
15535
|
+
}
|
|
15536
|
+
return capability.invoke(ctx, normalizedInput);
|
|
15537
|
+
}
|
|
15538
|
+
|
|
15539
|
+
// packages/agent-runtime/localWorkspaceTools.ts
|
|
15540
|
+
import { existsSync as existsSync3 } from "node:fs";
|
|
15541
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
15542
|
+
import { lstat, mkdir, readdir as readdir2, readFile as readFile3, realpath, stat as stat3, writeFile } from "node:fs/promises";
|
|
15543
|
+
import { homedir } from "node:os";
|
|
15544
|
+
import { dirname, isAbsolute as isAbsolute2, relative as relative3, resolve as resolve4, sep } from "node:path";
|
|
15545
|
+
import { spawn as spawnChildProcess3 } from "node:child_process";
|
|
15546
|
+
|
|
15547
|
+
// packages/core/readRangeLedger.ts
|
|
15548
|
+
function filterRetainedLedgerRecords(records, retainedCap) {
|
|
15549
|
+
return records.filter((record2) => record2.chars <= retainedCap);
|
|
15550
|
+
}
|
|
15551
|
+
function isValidRange(range3) {
|
|
15552
|
+
return Number.isInteger(range3.startLine) && Number.isInteger(range3.endLine) && range3.endLine >= range3.startLine;
|
|
15553
|
+
}
|
|
15554
|
+
function mergeLineRanges(ranges) {
|
|
15555
|
+
const sorted = ranges.filter(isValidRange).slice().sort((a, b) => a.startLine - b.startLine);
|
|
15556
|
+
const merged = [];
|
|
15557
|
+
for (const range3 of sorted) {
|
|
15558
|
+
const last = merged[merged.length - 1];
|
|
15559
|
+
if (last && range3.startLine <= last.endLine + 1) {
|
|
15560
|
+
last.endLine = Math.max(last.endLine, range3.endLine);
|
|
15561
|
+
} else {
|
|
15562
|
+
merged.push({ startLine: range3.startLine, endLine: range3.endLine });
|
|
15563
|
+
}
|
|
15564
|
+
}
|
|
15565
|
+
return merged;
|
|
15566
|
+
}
|
|
15567
|
+
function isLineRangeCovered(request3, covered) {
|
|
15568
|
+
if (!isValidRange(request3)) return false;
|
|
15569
|
+
let open = request3.startLine;
|
|
15570
|
+
for (const range3 of mergeLineRanges(covered)) {
|
|
15571
|
+
if (range3.endLine < open) continue;
|
|
15572
|
+
if (range3.startLine > open) return false;
|
|
15573
|
+
open = range3.endLine + 1;
|
|
15574
|
+
if (open > request3.endLine) return true;
|
|
15575
|
+
}
|
|
15576
|
+
return open > request3.endLine;
|
|
15577
|
+
}
|
|
15578
|
+
|
|
15579
|
+
// packages/agent-runtime/fileTextSearch.ts
|
|
15580
|
+
import { readdir, readFile as readFile2, stat as stat2 } from "node:fs/promises";
|
|
15581
|
+
import { basename, relative as relative2, resolve as resolve3 } from "node:path";
|
|
15582
|
+
import { spawn as spawnChildProcess2 } from "node:child_process";
|
|
15583
|
+
|
|
15584
|
+
// packages/agent-runtime/gitignore.ts
|
|
15585
|
+
import { readFile, stat } from "node:fs/promises";
|
|
15586
|
+
import { resolve as resolve2 } from "node:path";
|
|
15587
|
+
async function readRootGitignorePatterns(workspaceRoot) {
|
|
15588
|
+
const content = await readFile(resolve2(workspaceRoot, ".gitignore"), "utf8").catch(() => null);
|
|
15589
|
+
if (content === null) return [];
|
|
15590
|
+
return content.split(/\r?\n/).map((line) => line.trim()).filter((line) => line && !line.startsWith("#") && !line.startsWith("!")).flatMap((line) => {
|
|
15591
|
+
const unanchored = line.replace(/^\//, "");
|
|
15592
|
+
if (unanchored.endsWith("/")) return [`${unanchored}**`];
|
|
15593
|
+
if (unanchored.includes("**")) return [unanchored];
|
|
15594
|
+
return [unanchored, `${unanchored}/**`];
|
|
15595
|
+
});
|
|
15596
|
+
}
|
|
15597
|
+
async function hasRootGitignore(workspaceRoot) {
|
|
15598
|
+
try {
|
|
15599
|
+
await stat(resolve2(workspaceRoot, ".gitignore"));
|
|
15600
|
+
return true;
|
|
15601
|
+
} catch {
|
|
15602
|
+
return false;
|
|
15603
|
+
}
|
|
15604
|
+
}
|
|
15605
|
+
|
|
15606
|
+
// packages/agent-runtime/fileTextSearch.ts
|
|
15607
|
+
var normalizePath = (value) => value.replaceAll("\\", "/");
|
|
15608
|
+
var pathFor = (root, file, absolute = false) => absolute ? normalizePath(file) : normalizePath(relative2(root, file) || basename(file));
|
|
15609
|
+
var COMMAND_LIMIT_HEADROOM = 1;
|
|
15610
|
+
async function runCommand(binary, args2, cwd, maxResults) {
|
|
15611
|
+
const recordLimit = maxResults === void 0 ? 0 : Math.max(0, maxResults) + COMMAND_LIMIT_HEADROOM;
|
|
15612
|
+
return await new Promise((done4) => {
|
|
15613
|
+
let stdout = "", stderr = "", recordCount = 0, stopped = false;
|
|
15614
|
+
try {
|
|
15615
|
+
const child = spawnChildProcess2(binary, args2, { cwd, stdio: ["ignore", "pipe", "pipe"] });
|
|
15616
|
+
child.stdout.on("data", (chunk) => {
|
|
15617
|
+
stdout += chunk.toString();
|
|
15618
|
+
recordCount = parseMatches(cwd, stdout).length;
|
|
15619
|
+
if (recordLimit > 0 && recordCount >= recordLimit && !stopped) {
|
|
15620
|
+
stopped = true;
|
|
15621
|
+
child.kill();
|
|
15622
|
+
}
|
|
15623
|
+
});
|
|
15624
|
+
child.stderr.on("data", (chunk) => {
|
|
15625
|
+
stderr += chunk.toString();
|
|
15626
|
+
});
|
|
15627
|
+
child.on("error", () => done4({ stdout, stderr, outcome: { kind: "spawn-failed" } }));
|
|
15628
|
+
child.on("close", (exitCode) => done4({ stdout, stderr, outcome: stopped ? { kind: "stopped-by-limit" } : { kind: "completed", exitCode } }));
|
|
15629
|
+
} catch {
|
|
15630
|
+
done4({ stdout, stderr, outcome: { kind: "spawn-failed" } });
|
|
15631
|
+
}
|
|
15632
|
+
});
|
|
15633
|
+
}
|
|
15634
|
+
function commandArgs(o, binary, target) {
|
|
15635
|
+
const args2 = binary === "rg" ? ["--line-number", "--no-heading", "--color", "never", "--null"] : ["-RIn", "--binary-files=without-match", "--null"];
|
|
15636
|
+
if (binary === "rg") args2.push("--no-require-git");
|
|
15637
|
+
if (o.regex !== true) args2.push(binary === "rg" ? "--fixed-strings" : "-F");
|
|
15638
|
+
else if (binary === "grep") args2.push("-E");
|
|
15639
|
+
if (o.caseSensitive === false) args2.push("-i");
|
|
15640
|
+
if (binary === "rg") {
|
|
15641
|
+
if (o.includeIgnored) args2.push("--no-ignore");
|
|
15642
|
+
for (const x of o.exclude ?? []) args2.push("--glob", `!${x}`);
|
|
15643
|
+
if (o.include) args2.push("--glob", o.include);
|
|
15644
|
+
} else {
|
|
15645
|
+
for (const x of o.exclude ?? []) {
|
|
15646
|
+
const clean = x.replace(/\/\*\*$/, "");
|
|
15647
|
+
if (clean && !clean.includes("/")) args2.push("--exclude-dir", clean);
|
|
15648
|
+
}
|
|
15649
|
+
if (o.include) args2.push("--include", o.include);
|
|
15650
|
+
}
|
|
15651
|
+
args2.push("--", o.query, target);
|
|
15652
|
+
return args2;
|
|
15653
|
+
}
|
|
15654
|
+
function parseMatches(root, output) {
|
|
15655
|
+
const records = [];
|
|
15656
|
+
const pattern = /(?:^|\n)([^\0\n]+)\0(\d+):(.*?)(?=\n[^\0\n]+\0|$)/gs;
|
|
15657
|
+
for (const match7 of output.matchAll(pattern)) {
|
|
15658
|
+
records.push({ file: resolve3(root, match7[1] ?? ""), line: Number(match7[2]), text: (match7[3] ?? "").replace(/\n$/, "") });
|
|
15659
|
+
}
|
|
15660
|
+
return records;
|
|
15661
|
+
}
|
|
15662
|
+
async function decorate(root, raw, context3, absolute = false) {
|
|
15663
|
+
const cache = /* @__PURE__ */ new Map(), out = [];
|
|
15664
|
+
for (const x of raw) {
|
|
15665
|
+
let lines = cache.get(x.file);
|
|
15666
|
+
if (!lines) {
|
|
15667
|
+
try {
|
|
15668
|
+
lines = (await readFile2(x.file, "utf8")).split(/\r\n|\r|\n/);
|
|
15669
|
+
} catch {
|
|
15670
|
+
continue;
|
|
15671
|
+
}
|
|
15672
|
+
cache.set(x.file, lines);
|
|
15673
|
+
}
|
|
15674
|
+
const i = x.line - 1;
|
|
15675
|
+
out.push({ path: pathFor(root, x.file, absolute), line: x.line, text: lines[i] ?? x.text, before: lines.slice(Math.max(0, i - context3), i), after: lines.slice(i + 1, i + context3 + 1) });
|
|
15676
|
+
}
|
|
15677
|
+
return out;
|
|
15678
|
+
}
|
|
15679
|
+
function globMatch(pattern, value) {
|
|
15680
|
+
const p = normalizePath(pattern).replace(/^!/, "");
|
|
15681
|
+
let source = "";
|
|
15682
|
+
for (let i = 0; i < p.length; i++) {
|
|
15683
|
+
const c = p[i];
|
|
15684
|
+
if (c === "*" && p[i + 1] === "*") {
|
|
15685
|
+
i++;
|
|
15686
|
+
if (p[i + 1] === "/") {
|
|
15687
|
+
i++;
|
|
15688
|
+
source += "(?:.*/)?";
|
|
15689
|
+
} else source += ".*";
|
|
15690
|
+
} else if (c === "*") source += "[^/]*";
|
|
15691
|
+
else if (c === "?") source += "[^/]";
|
|
15692
|
+
else source += c.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
15693
|
+
}
|
|
15694
|
+
const r = new RegExp(`^${source}$`);
|
|
15695
|
+
return r.test(value) || r.test(basename(value));
|
|
15696
|
+
}
|
|
15697
|
+
var defaultReadTextFile = (filePath) => readFile2(filePath, "utf8").catch(() => "");
|
|
15698
|
+
async function jsSearch(o, targetPath) {
|
|
15699
|
+
const max4 = o.maxResults ?? Number.MAX_SAFE_INTEGER;
|
|
15700
|
+
const excludes = o.exclude ?? [];
|
|
15701
|
+
const readText = o.readTextFile ?? defaultReadTextFile;
|
|
15702
|
+
const files = [];
|
|
15703
|
+
const targetStat = await stat2(targetPath).catch(() => null);
|
|
15704
|
+
if (!targetStat) return { matches: [], totalMatches: 0, truncated: false, engine: "js" };
|
|
15705
|
+
const ignorePatterns = o.includeIgnored ? [] : await readRootGitignorePatterns(o.root);
|
|
15706
|
+
const isIgnored = (rel) => ignorePatterns.some((pattern) => globMatch(pattern, rel));
|
|
15707
|
+
const isSearchableFile = (filePath) => {
|
|
15708
|
+
const rel = pathFor(o.root, filePath);
|
|
15709
|
+
return !excludes.some((pattern) => globMatch(pattern, rel)) && !isIgnored(rel) && (!o.include || globMatch(o.include, rel));
|
|
15710
|
+
};
|
|
15711
|
+
if (targetStat.isFile()) {
|
|
15712
|
+
if (isSearchableFile(targetPath)) files.push(targetPath);
|
|
15713
|
+
} else {
|
|
15714
|
+
const walk = async (dir) => {
|
|
15715
|
+
for (const e of await readdir(dir, { withFileTypes: true })) {
|
|
15716
|
+
const f = resolve3(dir, e.name), rel = pathFor(o.root, f);
|
|
15717
|
+
if (e.isDirectory()) {
|
|
15718
|
+
if (!excludes.some((p) => globMatch(p, rel))) await walk(f);
|
|
15719
|
+
} else if (e.isFile() && !excludes.some((p) => globMatch(p, rel)) && !isIgnored(rel) && (!o.include || globMatch(o.include, rel))) {
|
|
15720
|
+
files.push(f);
|
|
15721
|
+
}
|
|
15722
|
+
}
|
|
15723
|
+
};
|
|
15724
|
+
await walk(targetPath);
|
|
15725
|
+
}
|
|
15726
|
+
const matcher = o.regex ? new RegExp(o.query, o.caseSensitive === false ? "i" : "") : null;
|
|
15727
|
+
const needle = o.caseSensitive === false ? o.query.toLowerCase() : o.query;
|
|
15728
|
+
const out = [], context3 = o.contextLines ?? 0;
|
|
15729
|
+
for (const file of files) {
|
|
15730
|
+
const text2 = await readText(file);
|
|
15731
|
+
if (!text2 || text2.includes("\0")) continue;
|
|
15732
|
+
const lines = text2.split(/\r\n|\r|\n/);
|
|
15733
|
+
for (let i = 0; i < lines.length; i++) {
|
|
15734
|
+
const line = lines[i] ?? "";
|
|
15735
|
+
const hit = matcher ? matcher.test(line) : o.caseSensitive === false ? line.toLowerCase().includes(needle) : line.includes(needle);
|
|
15736
|
+
if (!hit) continue;
|
|
15737
|
+
if (out.length >= max4) return { matches: out, totalMatches: max4, truncated: true, engine: "js" };
|
|
15738
|
+
out.push({ path: pathFor(o.root, file, o.absolutePaths === true), line: i + 1, text: line, before: lines.slice(Math.max(0, i - context3), i), after: lines.slice(i + 1, i + context3 + 1) });
|
|
15739
|
+
}
|
|
15740
|
+
}
|
|
15741
|
+
return { matches: out, totalMatches: out.length, truncated: false, engine: "js" };
|
|
15742
|
+
}
|
|
15743
|
+
var COMMAND_ENGINES = [
|
|
15744
|
+
{ engine: "ripgrep", binaryOption: "resolveRipgrepBinary", binaryName: "rg", argsKey: "rg" },
|
|
15745
|
+
{ engine: "grep", binaryOption: "resolveGrepBinary", binaryName: "grep", argsKey: "grep" }
|
|
15746
|
+
];
|
|
15747
|
+
async function searchFileTextMatches(o) {
|
|
15748
|
+
const targetPath = resolve3(o.root, o.target || ".");
|
|
15749
|
+
const targetStat = await stat2(targetPath).catch(() => null);
|
|
15750
|
+
if (!targetStat) return { matches: [], totalMatches: 0, truncated: false, engine: "js" };
|
|
15751
|
+
if (targetStat.isFile()) return jsSearch(o, targetPath);
|
|
15752
|
+
const run2 = o.runCommand ?? runCommand, max4 = o.maxResults;
|
|
15753
|
+
for (const entry of COMMAND_ENGINES) {
|
|
15754
|
+
const injectedResolver = o[entry.binaryOption];
|
|
15755
|
+
const binary = injectedResolver ? injectedResolver() : resolveExecutableOnPath(entry.binaryName);
|
|
15756
|
+
if (!binary) continue;
|
|
15757
|
+
const result4 = await run2(binary, commandArgs(o, entry.argsKey, o.target || "."), o.root, max4);
|
|
15758
|
+
const raw = parseMatches(o.root, result4.stdout);
|
|
15759
|
+
const hardFailed = result4.outcome.kind === "spawn-failed" || result4.outcome.kind === "completed" && result4.outcome.exitCode !== 0 && result4.outcome.exitCode !== 1;
|
|
15760
|
+
if (hardFailed) continue;
|
|
15761
|
+
const truncated = raw.length > (max4 ?? Number.MAX_SAFE_INTEGER);
|
|
15762
|
+
const matches = await decorate(o.root, raw.slice(0, max4), o.contextLines ?? 0, o.absolutePaths === true);
|
|
15763
|
+
return {
|
|
15764
|
+
matches,
|
|
15765
|
+
totalMatches: truncated ? matches.length : raw.length,
|
|
15766
|
+
truncated,
|
|
15767
|
+
engine: entry.engine
|
|
15768
|
+
};
|
|
15769
|
+
}
|
|
15770
|
+
return jsSearch(o, targetPath);
|
|
15771
|
+
}
|
|
15772
|
+
|
|
15773
|
+
// packages/agent-runtime/processOwnership.ts
|
|
15774
|
+
var asNonEmptyString = (value) => {
|
|
15775
|
+
if (typeof value !== "string") return null;
|
|
15776
|
+
const trimmed = value.trim();
|
|
15777
|
+
return trimmed ? trimmed : null;
|
|
15778
|
+
};
|
|
15779
|
+
function readProcessOwner(runtimeContext) {
|
|
15780
|
+
if (!runtimeContext || typeof runtimeContext !== "object") return null;
|
|
15781
|
+
const dialogId = asNonEmptyString(runtimeContext.dialogId) ?? asNonEmptyString(runtimeContext.parentThreadId);
|
|
15782
|
+
if (!dialogId) return null;
|
|
15783
|
+
const turnId = asNonEmptyString(runtimeContext.turnId);
|
|
15784
|
+
const ownerId = asNonEmptyString(runtimeContext.ownerId);
|
|
15785
|
+
return {
|
|
15786
|
+
dialogId,
|
|
15787
|
+
...turnId ? { turnId } : {},
|
|
15788
|
+
...ownerId ? { ownerId } : {}
|
|
15429
15789
|
};
|
|
15430
15790
|
}
|
|
15431
15791
|
|
|
@@ -15434,20 +15794,34 @@ var TASK_WAIT_DEFAULT_TIMEOUT_MS = 5 * 6e4;
|
|
|
15434
15794
|
var TASK_WAIT_MAX_TIMEOUT_MS = 5 * 6e4;
|
|
15435
15795
|
var TASK_WAIT_POLL_INTERVAL_MS = 250;
|
|
15436
15796
|
var TASK_STOP_GRACE_MS = 2e3;
|
|
15797
|
+
function resolveCleanupReport(evidence, previousStatus) {
|
|
15798
|
+
const diagnostic = evidence.diagnostic ? { diagnostic: evidence.diagnostic } : {};
|
|
15799
|
+
if (evidence.confirmedStopped) {
|
|
15800
|
+
return { status: "stopped", pending: false };
|
|
15801
|
+
}
|
|
15802
|
+
if (evidence.alreadyTerminal) {
|
|
15803
|
+
const status = previousStatus ?? "stopped";
|
|
15804
|
+
return { status, pending: status === "stop-unverified", idempotent: true, ...diagnostic };
|
|
15805
|
+
}
|
|
15806
|
+
if (evidence.ttlExpired) {
|
|
15807
|
+
return { status: "expired", pending: false, ...diagnostic };
|
|
15808
|
+
}
|
|
15809
|
+
return { status: "stop-unverified", pending: true, ...diagnostic };
|
|
15810
|
+
}
|
|
15437
15811
|
var TERMINAL_EVENT_TYPES = /* @__PURE__ */ new Set(["exited", "killed"]);
|
|
15438
15812
|
function defaultSleep(ms) {
|
|
15439
|
-
return new Promise((
|
|
15813
|
+
return new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
15440
15814
|
}
|
|
15441
15815
|
function defaultSignalSender(pid, signal) {
|
|
15442
15816
|
process.kill(pid, signal);
|
|
15443
15817
|
}
|
|
15444
|
-
function statusOf(
|
|
15445
|
-
return reportedTaskStatus(
|
|
15818
|
+
function statusOf(record2) {
|
|
15819
|
+
return reportedTaskStatus(record2.status, record2.exitCode);
|
|
15446
15820
|
}
|
|
15447
15821
|
function inspectTask(registry2, taskId) {
|
|
15448
|
-
const
|
|
15822
|
+
const record2 = registry2.getByTaskId(taskId);
|
|
15449
15823
|
const hasEvents = registry2.hasTaskEvents(taskId);
|
|
15450
|
-
return { record, hasEvents, known: hasEvents ||
|
|
15824
|
+
return { record: record2, hasEvents, known: hasEvents || record2 !== void 0 };
|
|
15451
15825
|
}
|
|
15452
15826
|
function notFoundDetail(taskId) {
|
|
15453
15827
|
return `No task ${taskId} is known: it was never started, or both its envelope and its event trail have been dropped. Call tasks to list current handles.`;
|
|
@@ -15489,13 +15863,13 @@ async function runTaskWait(args2) {
|
|
|
15489
15863
|
for (let poll2 = 0; poll2 < maxPolls; poll2 += 1) {
|
|
15490
15864
|
const events = registry2.getTaskEvents(taskId, 0);
|
|
15491
15865
|
if (!registry2.hasTaskEvents(taskId)) {
|
|
15492
|
-
const
|
|
15866
|
+
const record2 = registry2.getByTaskId(taskId);
|
|
15493
15867
|
return {
|
|
15494
15868
|
outcome: "evicted",
|
|
15495
15869
|
taskId,
|
|
15496
15870
|
cursor: 0,
|
|
15497
15871
|
events: [],
|
|
15498
|
-
...
|
|
15872
|
+
...record2 ? { status: statusOf(record2) } : {},
|
|
15499
15873
|
detail: evictedDetail(taskId)
|
|
15500
15874
|
};
|
|
15501
15875
|
}
|
|
@@ -15540,7 +15914,7 @@ function runTaskLogs(args2) {
|
|
|
15540
15914
|
const { registry: registry2, taskId } = args2;
|
|
15541
15915
|
const cursorRaw = typeof args2.cursor === "number" ? args2.cursor : typeof args2.cursor === "string" && args2.cursor.trim() !== "" ? Number(args2.cursor) : Number.NaN;
|
|
15542
15916
|
const cursor = Number.isFinite(cursorRaw) && cursorRaw > 0 ? Math.floor(cursorRaw) : 0;
|
|
15543
|
-
const { record, hasEvents, known } = inspectTask(registry2, taskId);
|
|
15917
|
+
const { record: record2, hasEvents, known } = inspectTask(registry2, taskId);
|
|
15544
15918
|
if (!known) {
|
|
15545
15919
|
return { outcome: "not-found", taskId, detail: notFoundDetail(taskId) };
|
|
15546
15920
|
}
|
|
@@ -15550,14 +15924,14 @@ function runTaskLogs(args2) {
|
|
|
15550
15924
|
taskId,
|
|
15551
15925
|
cursor: 0,
|
|
15552
15926
|
events: [],
|
|
15553
|
-
...
|
|
15927
|
+
...record2 ? { status: statusOf(record2) } : {},
|
|
15554
15928
|
detail: evictedDetail(taskId)
|
|
15555
15929
|
};
|
|
15556
15930
|
}
|
|
15557
15931
|
const events = registry2.getTaskEvents(taskId, cursor);
|
|
15558
15932
|
const allEvents = registry2.getTaskEvents(taskId, 0);
|
|
15559
15933
|
const terminal = lastTerminalEvent(allEvents);
|
|
15560
|
-
const status = terminal ? reportedTaskStatus(terminal.type, terminal.exitCode) :
|
|
15934
|
+
const status = terminal ? reportedTaskStatus(terminal.type, terminal.exitCode) : record2 ? statusOf(record2) : "running";
|
|
15561
15935
|
return {
|
|
15562
15936
|
outcome: "ok",
|
|
15563
15937
|
taskId,
|
|
@@ -15576,410 +15950,106 @@ function formatTaskLogsContent(result4, options) {
|
|
|
15576
15950
|
const spill = spillToolOutput({
|
|
15577
15951
|
content: full,
|
|
15578
15952
|
toolName: "taskLogs",
|
|
15579
|
-
workspaceRoot: options?.workspaceRoot
|
|
15580
|
-
});
|
|
15581
|
-
const omitted = result4.outcome === "ok" ? result4.events.length : 0;
|
|
15582
|
-
const head3 = JSON.stringify({
|
|
15583
|
-
...result4,
|
|
15584
|
-
events: [],
|
|
15585
|
-
eventsOmitted: omitted,
|
|
15586
|
-
logRef: spill.displayPath
|
|
15587
|
-
});
|
|
15588
|
-
return {
|
|
15589
|
-
content: `${head3}${formatToolOverflowMarker({
|
|
15590
|
-
spillRef: spill.displayPath,
|
|
15591
|
-
totalChars: spill.totalChars,
|
|
15592
|
-
totalLines: spill.totalLines,
|
|
15593
|
-
omittedChars: Math.max(0, full.length - head3.length),
|
|
15594
|
-
toolName: "taskLogs"
|
|
15595
|
-
})}`.trimEnd(),
|
|
15596
|
-
logRef: spill.displayPath
|
|
15597
|
-
};
|
|
15598
|
-
} catch {
|
|
15599
|
-
return { content: truncateToolOutput(full, effectiveLimit) };
|
|
15600
|
-
}
|
|
15601
|
-
}
|
|
15602
|
-
function isProcessGroupAlive(pgid, kill = defaultSignalSender) {
|
|
15603
|
-
try {
|
|
15604
|
-
kill(-pgid, 0);
|
|
15605
|
-
return true;
|
|
15606
|
-
} catch (error) {
|
|
15607
|
-
return error.code === "EPERM";
|
|
15608
|
-
}
|
|
15609
|
-
}
|
|
15610
|
-
async function runTaskStop(args2) {
|
|
15611
|
-
const { registry: registry2, taskId } = args2;
|
|
15612
|
-
const sleep3 = args2.sleep ?? defaultSleep;
|
|
15613
|
-
const kill = args2.kill ?? defaultSignalSender;
|
|
15614
|
-
const graceMs = Math.max(0, args2.graceMs ?? TASK_STOP_GRACE_MS);
|
|
15615
|
-
const record = registry2.getByTaskId(taskId);
|
|
15616
|
-
if (!record) {
|
|
15617
|
-
return { outcome: "not-found", taskId, detail: notFoundDetail(taskId) };
|
|
15618
|
-
}
|
|
15619
|
-
const termed = registry2.kill(record.pid, "SIGTERM");
|
|
15620
|
-
if (!termed) {
|
|
15621
|
-
const reason = record.transient ? "transient-foreground" : record.status !== "running" ? "already-terminal" : "kill-refused";
|
|
15622
|
-
const detail = reason === "transient-foreground" ? `${taskId} is a foreground command still inside its grace window, not a background task; its lifecycle belongs to the running execShell call.` : reason === "already-terminal" ? `${taskId} is already ${statusOf(record)}; nothing to stop.` : `Registry refused to stop ${taskId}.`;
|
|
15623
|
-
return {
|
|
15624
|
-
outcome: "not-stoppable",
|
|
15625
|
-
taskId,
|
|
15626
|
-
pid: record.pid,
|
|
15627
|
-
status: statusOf(record),
|
|
15628
|
-
reason,
|
|
15629
|
-
detail
|
|
15630
|
-
};
|
|
15631
|
-
}
|
|
15632
|
-
if (graceMs > 0) await sleep3(graceMs);
|
|
15633
|
-
if (!isProcessGroupAlive(record.pgid, kill)) {
|
|
15634
|
-
return {
|
|
15635
|
-
outcome: "stopped",
|
|
15636
|
-
taskId,
|
|
15637
|
-
pid: record.pid,
|
|
15638
|
-
status: reportedTaskStatus("killed"),
|
|
15639
|
-
signal: "SIGTERM",
|
|
15640
|
-
escalated: false
|
|
15641
|
-
};
|
|
15642
|
-
}
|
|
15643
|
-
try {
|
|
15644
|
-
kill(-record.pgid, "SIGKILL");
|
|
15645
|
-
} catch {
|
|
15646
|
-
}
|
|
15647
|
-
return {
|
|
15648
|
-
outcome: "stopped",
|
|
15649
|
-
taskId,
|
|
15650
|
-
pid: record.pid,
|
|
15651
|
-
status: reportedTaskStatus("killed"),
|
|
15652
|
-
signal: "SIGKILL",
|
|
15653
|
-
escalated: true
|
|
15654
|
-
};
|
|
15655
|
-
}
|
|
15656
|
-
function runTasks(args2) {
|
|
15657
|
-
const tasks = args2.registry.listBackground().map((record) => ({
|
|
15658
|
-
taskId: record.taskId,
|
|
15659
|
-
pid: record.pid,
|
|
15660
|
-
label: record.label,
|
|
15661
|
-
status: statusOf(record),
|
|
15662
|
-
startedAt: record.startedAt,
|
|
15663
|
-
persist: record.persist
|
|
15664
|
-
}));
|
|
15665
|
-
return { tasks, count: tasks.length };
|
|
15666
|
-
}
|
|
15667
|
-
|
|
15668
|
-
// packages/agent-runtime/execShellCompletionWarnings.ts
|
|
15669
|
-
var BG_ESCAPE_WORD_PATTERN = /(?:^|[\s;|(&/\\])(nohup|disown|setsid|start-process)(?=$|[\s;|)&])/i;
|
|
15670
|
-
var SHELL_SPLIT_CHARS = /* @__PURE__ */ new Set([";", "|", "&", "(", ")", "<", ">", "\n", " ", " "]);
|
|
15671
|
-
function maskQuotedAndEscaped(command) {
|
|
15672
|
-
const out = Array.from(command);
|
|
15673
|
-
let quote = null;
|
|
15674
|
-
for (let i = 0; i < out.length; i += 1) {
|
|
15675
|
-
const ch = out[i];
|
|
15676
|
-
if (quote) {
|
|
15677
|
-
out[i] = " ";
|
|
15678
|
-
if (ch === "\\" && quote !== "'") {
|
|
15679
|
-
if (i + 1 < out.length) out[i + 1] = " ";
|
|
15680
|
-
i += 1;
|
|
15681
|
-
} else if (ch === quote) {
|
|
15682
|
-
quote = null;
|
|
15683
|
-
}
|
|
15684
|
-
continue;
|
|
15685
|
-
}
|
|
15686
|
-
if (ch === "\\") {
|
|
15687
|
-
out[i] = " ";
|
|
15688
|
-
if (i + 1 < out.length) out[i + 1] = " ";
|
|
15689
|
-
i += 1;
|
|
15690
|
-
continue;
|
|
15691
|
-
}
|
|
15692
|
-
if (ch === "'" || ch === '"' || ch === "`") {
|
|
15693
|
-
quote = ch;
|
|
15694
|
-
out[i] = " ";
|
|
15695
|
-
continue;
|
|
15696
|
-
}
|
|
15697
|
-
if (ch === "#" && (i === 0 || /[\s;]/.test(out[i - 1] ?? " "))) {
|
|
15698
|
-
while (i < out.length && out[i] !== "\n") {
|
|
15699
|
-
out[i] = " ";
|
|
15700
|
-
i += 1;
|
|
15701
|
-
}
|
|
15702
|
-
}
|
|
15703
|
-
}
|
|
15704
|
-
return out.join("");
|
|
15705
|
-
}
|
|
15706
|
-
function readRedirectTarget(original, start) {
|
|
15707
|
-
let i = start;
|
|
15708
|
-
while (i < original.length && /\s/.test(original[i] ?? "")) {
|
|
15709
|
-
i += 1;
|
|
15710
|
-
}
|
|
15711
|
-
if (i >= original.length) return void 0;
|
|
15712
|
-
let text = "";
|
|
15713
|
-
let j = i;
|
|
15714
|
-
while (j < original.length) {
|
|
15715
|
-
const o = original[j];
|
|
15716
|
-
if (o === "'" || o === '"' || o === "`") {
|
|
15717
|
-
const quote = o;
|
|
15718
|
-
j += 1;
|
|
15719
|
-
while (j < original.length && original[j] !== quote) {
|
|
15720
|
-
if (original[j] === "\\" && quote !== "'" && j + 1 < original.length) {
|
|
15721
|
-
text += original[j + 1];
|
|
15722
|
-
j += 2;
|
|
15723
|
-
continue;
|
|
15724
|
-
}
|
|
15725
|
-
text += original[j];
|
|
15726
|
-
j += 1;
|
|
15727
|
-
}
|
|
15728
|
-
j += 1;
|
|
15729
|
-
continue;
|
|
15730
|
-
}
|
|
15731
|
-
if (/\s/.test(o) || SHELL_SPLIT_CHARS.has(o)) break;
|
|
15732
|
-
text += o;
|
|
15733
|
-
j += 1;
|
|
15734
|
-
}
|
|
15735
|
-
if (!text || text === "$") return void 0;
|
|
15736
|
-
return { text, end: j };
|
|
15737
|
-
}
|
|
15738
|
-
function isIgnoredRedirectTarget(target) {
|
|
15739
|
-
return target === "/dev/null";
|
|
15740
|
-
}
|
|
15741
|
-
function detectExecShellSynchronousWarnings(command, shell) {
|
|
15742
|
-
const masked = maskQuotedAndEscaped(command);
|
|
15743
|
-
const isPowerShell = shell?.resolvedShell === "powershell";
|
|
15744
|
-
const redirectTargets = [];
|
|
15745
|
-
let backgrounded = false;
|
|
15746
|
-
let i = 0;
|
|
15747
|
-
while (i < masked.length) {
|
|
15748
|
-
const ch = masked[i];
|
|
15749
|
-
if (ch === "&") {
|
|
15750
|
-
const next = masked[i + 1];
|
|
15751
|
-
if (next === "&") {
|
|
15752
|
-
i += 2;
|
|
15753
|
-
continue;
|
|
15754
|
-
}
|
|
15755
|
-
if (next === ">") {
|
|
15756
|
-
let j = i + 2;
|
|
15757
|
-
if (masked[j] === ">") j += 1;
|
|
15758
|
-
const target = readRedirectTarget(command, j);
|
|
15759
|
-
if (target && !isIgnoredRedirectTarget(target.text)) redirectTargets.push(target.text);
|
|
15760
|
-
i = target ? target.end : j;
|
|
15761
|
-
continue;
|
|
15762
|
-
}
|
|
15763
|
-
const prev = masked[i - 1];
|
|
15764
|
-
if (prev === ">" || prev === "<") {
|
|
15765
|
-
i += 1;
|
|
15766
|
-
continue;
|
|
15767
|
-
}
|
|
15768
|
-
if (isPowerShell) {
|
|
15769
|
-
i += 1;
|
|
15770
|
-
continue;
|
|
15771
|
-
}
|
|
15772
|
-
backgrounded = true;
|
|
15773
|
-
i += 1;
|
|
15774
|
-
continue;
|
|
15775
|
-
}
|
|
15776
|
-
if (ch === ">") {
|
|
15777
|
-
const prev = masked[i - 1];
|
|
15778
|
-
if (prev === ">" || prev === "&" || prev === "<") {
|
|
15779
|
-
i += 1;
|
|
15780
|
-
continue;
|
|
15781
|
-
}
|
|
15782
|
-
let j = i + 1;
|
|
15783
|
-
if (masked[j] === ">") j += 1;
|
|
15784
|
-
if (masked[j] === "&") {
|
|
15785
|
-
const ampTarget = readRedirectTarget(command, j + 1);
|
|
15786
|
-
const isFdDuplication = ampTarget !== void 0 && (/^\d+$/.test(ampTarget.text) || ampTarget.text === "-");
|
|
15787
|
-
if (ampTarget && !isFdDuplication && !isIgnoredRedirectTarget(ampTarget.text)) {
|
|
15788
|
-
redirectTargets.push(ampTarget.text);
|
|
15789
|
-
}
|
|
15790
|
-
i = ampTarget ? ampTarget.end : j + 1;
|
|
15791
|
-
continue;
|
|
15792
|
-
}
|
|
15793
|
-
const target = readRedirectTarget(command, j);
|
|
15794
|
-
if (target && !isIgnoredRedirectTarget(target.text)) redirectTargets.push(target.text);
|
|
15795
|
-
i = target ? target.end : j;
|
|
15796
|
-
continue;
|
|
15797
|
-
}
|
|
15798
|
-
if (ch === "<") {
|
|
15799
|
-
i += masked[i + 1] === "<" || masked[i + 1] === "&" ? 2 : 1;
|
|
15800
|
-
continue;
|
|
15801
|
-
}
|
|
15802
|
-
i += 1;
|
|
15803
|
-
}
|
|
15804
|
-
const wordMatch = BG_ESCAPE_WORD_PATTERN.exec(masked);
|
|
15805
|
-
if (wordMatch) backgrounded = true;
|
|
15806
|
-
const warnings = [];
|
|
15807
|
-
if (redirectTargets.length > 0) {
|
|
15808
|
-
const target = redirectTargets[0];
|
|
15809
|
-
warnings.push({
|
|
15810
|
-
kind: "output-redirect",
|
|
15811
|
-
redirectTarget: target,
|
|
15812
|
-
message: `[wake-safety] This execShell call completed synchronously; its output was redirected to ${target}. That file is NOT delivered by any completion notification \u2014 no tracked background task was created. If you need the result, read that file in this turn.`
|
|
15813
|
-
});
|
|
15814
|
-
}
|
|
15815
|
-
if (backgrounded) {
|
|
15816
|
-
warnings.push({
|
|
15817
|
-
kind: "shell-backgrounding",
|
|
15818
|
-
message: `[wake-safety] Detected shell-internal backgrounding (lone \`&\`, nohup/disown/setsid/Start-Process or similar). Descendant processes are NOT tracked as platform tasks and will not produce completion notifications; text such as \`LAUNCHED\` printed by the command is plain stdout, not a platform receipt.`
|
|
15953
|
+
workspaceRoot: options?.workspaceRoot
|
|
15954
|
+
});
|
|
15955
|
+
const omitted = result4.outcome === "ok" ? result4.events.length : 0;
|
|
15956
|
+
const head3 = JSON.stringify({
|
|
15957
|
+
...result4,
|
|
15958
|
+
events: [],
|
|
15959
|
+
eventsOmitted: omitted,
|
|
15960
|
+
logRef: spill.displayPath
|
|
15819
15961
|
});
|
|
15962
|
+
return {
|
|
15963
|
+
content: `${head3}${formatToolOverflowMarker({
|
|
15964
|
+
spillRef: spill.displayPath,
|
|
15965
|
+
totalChars: spill.totalChars,
|
|
15966
|
+
totalLines: spill.totalLines,
|
|
15967
|
+
omittedChars: Math.max(0, full.length - head3.length),
|
|
15968
|
+
toolName: "taskLogs"
|
|
15969
|
+
})}`.trimEnd(),
|
|
15970
|
+
logRef: spill.displayPath
|
|
15971
|
+
};
|
|
15972
|
+
} catch {
|
|
15973
|
+
return { content: truncateToolOutput(full, effectiveLimit) };
|
|
15820
15974
|
}
|
|
15821
|
-
return warnings;
|
|
15822
|
-
}
|
|
15823
|
-
|
|
15824
|
-
// packages/agent-runtime/capabilities/execShellCapability.ts
|
|
15825
|
-
function buildExecShellToolDefinition(toolName = "execShell") {
|
|
15826
|
-
return {
|
|
15827
|
-
type: "function",
|
|
15828
|
-
function: {
|
|
15829
|
-
name: toolName,
|
|
15830
|
-
description: `Execute a shell command from the workspace root. Prefer one compound command (e.g. 'git status && git diff --stat') to perform complete verification in one step instead of multiple small roundtrips. Do not cd into guessed paths; commands already run from the workspace root. Commands block until exit. Long-running commands (sleep over ${IMMEDIATE_DETACH_SLEEP_THRESHOLD_SECONDS}s, dev servers, watchers) automatically detach to background returning {detached: true, pid, label}; for persistent services, prefer launchProcess. On Windows the resolved shell may be Windows PowerShell 5.1 (metadata.shellKind="powershell5"): it does not support '&&'/'||' or $PSStyle \u2014 join commands with ';' or split into multiple calls. metadata.shellKind="pwsh" means PowerShell 7+ with full syntax. Read resolvedShell/shellKind from any execShell result before writing Windows-specific syntax. LIFECYCLE CONTRACT (misreading this contract silenced a real dialog for 10 hours): (1) A normal command waits synchronously for at most 120 seconds; if it ends inside that window the call IS finished \u2014 a result containing exitCode means the command has already completed, never "still running". (2) Only a result with metadata.detached === true AND a taskId represents a tracked background task that may trigger completion wake-up (terminal completion turn carrying a bounded result capsule); that handle may be waited on with taskWait and will produce a completion notification. (3) Text the command itself prints (LAUNCHED, STARTED, BACKGROUND, ...) is plain stdout with zero lifecycle meaning \u2014 never read it as a platform receipt. (4) Shell-level backgrounding (\`&\`, nohup, disown, setsid, self-daemonizing scripts, PowerShell Start-Process) is NOT tracked: those descendants produce no completion notification, and the outer shell finishing tells you nothing about them. Use background: true to turn a finite job into a tracked background task immediately. When a synchronous result's core output was redirected to a file, read that file in the SAME turn \u2014 never end the turn promising a later automatic report without a taskId.`,
|
|
15831
|
-
parameters: {
|
|
15832
|
-
type: "object",
|
|
15833
|
-
properties: {
|
|
15834
|
-
command: {
|
|
15835
|
-
type: "string",
|
|
15836
|
-
description: "Shell command to run (non-empty)."
|
|
15837
|
-
},
|
|
15838
|
-
cmd: {
|
|
15839
|
-
type: "string",
|
|
15840
|
-
description: "Compatibility alias for command."
|
|
15841
|
-
},
|
|
15842
|
-
background: {
|
|
15843
|
-
type: "boolean",
|
|
15844
|
-
description: "Immediately detach this command into a tracked background task (no 120s synchronous wait): returns {detached: true, taskId}, and on completion the platform resumes this conversation with a bounded result capsule (exitCode, duration, stdout/stderr tail). Default false. Use for finite jobs (tests, builds, batch) whose result you need later; NOT for dev servers/watchers \u2014 use launchProcess for those."
|
|
15845
|
-
}
|
|
15846
|
-
}
|
|
15847
|
-
}
|
|
15848
|
-
}
|
|
15849
|
-
};
|
|
15850
15975
|
}
|
|
15851
|
-
function
|
|
15852
|
-
|
|
15853
|
-
|
|
15976
|
+
function isProcessGroupAlive(pgid, kill = defaultSignalSender) {
|
|
15977
|
+
try {
|
|
15978
|
+
kill(-pgid, 0);
|
|
15979
|
+
return true;
|
|
15980
|
+
} catch (error) {
|
|
15981
|
+
return error.code === "EPERM";
|
|
15854
15982
|
}
|
|
15855
|
-
|
|
15856
|
-
|
|
15857
|
-
|
|
15858
|
-
|
|
15859
|
-
|
|
15860
|
-
|
|
15861
|
-
|
|
15862
|
-
|
|
15863
|
-
|
|
15864
|
-
|
|
15865
|
-
|
|
15866
|
-
|
|
15867
|
-
}
|
|
15868
|
-
}
|
|
15869
|
-
return { command: trimmed };
|
|
15983
|
+
}
|
|
15984
|
+
async function runTaskStop(args2) {
|
|
15985
|
+
const { registry: registry2, taskId } = args2;
|
|
15986
|
+
const sleep3 = args2.sleep ?? defaultSleep;
|
|
15987
|
+
const kill = args2.kill ?? defaultSignalSender;
|
|
15988
|
+
const graceMs = Math.max(0, args2.graceMs ?? TASK_STOP_GRACE_MS);
|
|
15989
|
+
const record2 = registry2.getByTaskId(taskId);
|
|
15990
|
+
if (!record2) {
|
|
15991
|
+
return {
|
|
15992
|
+
outcome: "not-found",
|
|
15993
|
+
taskId,
|
|
15994
|
+
detail: notFoundDetail(taskId),
|
|
15995
|
+
cleanup: resolveCleanupReport({ confirmedStopped: false, diagnostic: "task-not-found" })
|
|
15996
|
+
};
|
|
15870
15997
|
}
|
|
15871
|
-
|
|
15872
|
-
|
|
15873
|
-
|
|
15874
|
-
|
|
15875
|
-
const fallback = record.command ?? record.cmd;
|
|
15876
|
-
if (typeof fallback === "string" && fallback.trim()) {
|
|
15877
|
-
rawCommand = fallback;
|
|
15878
|
-
}
|
|
15879
|
-
}
|
|
15880
|
-
const command = typeof rawCommand === "string" ? rawCommand.trim() : "";
|
|
15881
|
-
if (!command) {
|
|
15882
|
-
throw new Error("execShell requires a non-empty command.");
|
|
15883
|
-
}
|
|
15884
|
-
const activity = extractActivity(record);
|
|
15885
|
-
const background = record.background === true || typeof record.background === "string" && record.background.trim().toLowerCase() === "true";
|
|
15998
|
+
const termed = registry2.kill(record2.pid, "SIGTERM");
|
|
15999
|
+
if (!termed) {
|
|
16000
|
+
const reason = record2.transient ? "transient-foreground" : record2.status !== "running" ? "already-terminal" : "kill-refused";
|
|
16001
|
+
const detail = reason === "transient-foreground" ? `${taskId} is a foreground command still inside its grace window, not a background task; its lifecycle belongs to the running execShell call.` : reason === "already-terminal" ? `${taskId} is already ${statusOf(record2)}; nothing to stop.` : `Registry refused to stop ${taskId}.`;
|
|
15886
16002
|
return {
|
|
15887
|
-
|
|
15888
|
-
|
|
15889
|
-
|
|
15890
|
-
|
|
15891
|
-
|
|
16003
|
+
outcome: "not-stoppable",
|
|
16004
|
+
taskId,
|
|
16005
|
+
pid: record2.pid,
|
|
16006
|
+
status: statusOf(record2),
|
|
16007
|
+
reason,
|
|
16008
|
+
detail,
|
|
16009
|
+
// 终态 → 幂等路径(原样返回,不覆盖、不重复发事件);其余拒绝理由保留诊断码,
|
|
16010
|
+
// 绝不把「没停成」写成「已停止」(§6.3、§11.4 条款 4)。
|
|
16011
|
+
cleanup: resolveCleanupReport(
|
|
16012
|
+
reason === "already-terminal" ? { confirmedStopped: false, alreadyTerminal: true } : { confirmedStopped: false, diagnostic: reason }
|
|
16013
|
+
)
|
|
15892
16014
|
};
|
|
15893
16015
|
}
|
|
15894
|
-
|
|
15895
|
-
|
|
15896
|
-
var execShellCapability = {
|
|
15897
|
-
name: "execShell",
|
|
15898
|
-
getToolDefinition(toolName = "execShell") {
|
|
15899
|
-
return buildExecShellToolDefinition(toolName);
|
|
15900
|
-
},
|
|
15901
|
-
normalizeInput(input) {
|
|
15902
|
-
return normalizeExecShellInput(input);
|
|
15903
|
-
},
|
|
15904
|
-
async invoke(ctx, normalized) {
|
|
15905
|
-
const workspaceRoot = ctx.workspaceRoot || process.cwd();
|
|
15906
|
-
const command = normalized.command;
|
|
15907
|
-
if (ctx.restrictToWorkspace) {
|
|
15908
|
-
const escapeToken = findWorkspaceShellEscapeToken(command);
|
|
15909
|
-
if (escapeToken) {
|
|
15910
|
-
return buildWorkspaceShellEscapeBlockedResult({ command, token: escapeToken });
|
|
15911
|
-
}
|
|
15912
|
-
}
|
|
15913
|
-
const interactiveAuthCommand = extractInteractiveGhAuthCommand(command);
|
|
15914
|
-
if (interactiveAuthCommand) {
|
|
15915
|
-
const blocked = buildInteractiveCommandBlockedResult(interactiveAuthCommand);
|
|
15916
|
-
return {
|
|
15917
|
-
...blocked,
|
|
15918
|
-
metadata: {
|
|
15919
|
-
...blocked.metadata,
|
|
15920
|
-
...normalized.activity ? { activity: normalized.activity } : {}
|
|
15921
|
-
}
|
|
15922
|
-
};
|
|
15923
|
-
}
|
|
15924
|
-
const shellPlan = buildWorkspaceShellPlan({
|
|
15925
|
-
toolName: "execShell",
|
|
15926
|
-
command,
|
|
15927
|
-
shell: normalized.shell
|
|
15928
|
-
});
|
|
15929
|
-
const background = normalized.background === true;
|
|
15930
|
-
const result4 = await runWorkspaceCommand({
|
|
15931
|
-
workspaceRoot,
|
|
15932
|
-
command: shellPlan.argv,
|
|
15933
|
-
timeoutMs: resolveExecShellTimeoutMs(ctx.commandTimeoutMs),
|
|
15934
|
-
outputLimit: ctx.commandOutputLimit,
|
|
15935
|
-
commandPrefix: ctx.commandPrefix,
|
|
15936
|
-
abortSignal: ctx.abortSignal,
|
|
15937
|
-
detachMs: background ? 0 : isImmediateDetachShellCommand({ command }) ? 0 : ctx.detachMs,
|
|
15938
|
-
stdin: typeof normalized.input === "string" ? normalized.input : void 0,
|
|
15939
|
-
// Ownership of the turn that invoked this command: an auto-detached
|
|
15940
|
-
// command keeps its parent dialog so its terminal can resume that
|
|
15941
|
-
// conversation (see processOwnership.ts). Absent ctx.owner = unowned.
|
|
15942
|
-
owner: ctx.owner ?? null
|
|
15943
|
-
});
|
|
15944
|
-
const warnings = result4.detached || result4.spawnFailed ? [] : detectExecShellSynchronousWarnings(command, {
|
|
15945
|
-
resolvedShell: shellPlan.resolvedShell
|
|
15946
|
-
});
|
|
16016
|
+
if (graceMs > 0) await sleep3(graceMs);
|
|
16017
|
+
if (!isProcessGroupAlive(record2.pgid, kill)) {
|
|
15947
16018
|
return {
|
|
15948
|
-
|
|
15949
|
-
|
|
15950
|
-
|
|
15951
|
-
|
|
15952
|
-
|
|
15953
|
-
|
|
15954
|
-
|
|
15955
|
-
...result4.aborted ? { aborted: true } : {},
|
|
15956
|
-
...result4.detached ? {
|
|
15957
|
-
detached: true,
|
|
15958
|
-
pid: result4.pid,
|
|
15959
|
-
label: result4.label,
|
|
15960
|
-
// Phase 0: stable taskId from the pre-registered Execution
|
|
15961
|
-
// Envelope (additive; existing detached fields untouched).
|
|
15962
|
-
taskId: result4.taskId,
|
|
15963
|
-
status: "running",
|
|
15964
|
-
// P0 machine-readable execution state: an explicit positive
|
|
15965
|
-
// signal instead of requiring the model to infer "not detached"
|
|
15966
|
-
// from absence. Mirrors the real lifecycle contract.
|
|
15967
|
-
executionState: "detached",
|
|
15968
|
-
trackedBackgroundTask: true,
|
|
15969
|
-
completionNotification: "terminal-resume"
|
|
15970
|
-
} : {
|
|
15971
|
-
// P0 machine-readable execution state: the command already
|
|
15972
|
-
// finished inside the synchronous window; no background task
|
|
15973
|
-
// exists, so no completion notification will ever arrive.
|
|
15974
|
-
executionState: "synchronous-complete",
|
|
15975
|
-
trackedBackgroundTask: false,
|
|
15976
|
-
completionNotification: "none"
|
|
15977
|
-
},
|
|
15978
|
-
...normalized.activity ? { activity: normalized.activity } : {}
|
|
15979
|
-
}
|
|
16019
|
+
outcome: "stopped",
|
|
16020
|
+
taskId,
|
|
16021
|
+
pid: record2.pid,
|
|
16022
|
+
status: reportedTaskStatus("killed"),
|
|
16023
|
+
signal: "SIGTERM",
|
|
16024
|
+
escalated: false,
|
|
16025
|
+
cleanup: resolveCleanupReport({ confirmedStopped: true })
|
|
15980
16026
|
};
|
|
15981
16027
|
}
|
|
15982
|
-
|
|
16028
|
+
try {
|
|
16029
|
+
kill(-record2.pgid, "SIGKILL");
|
|
16030
|
+
} catch {
|
|
16031
|
+
}
|
|
16032
|
+
return {
|
|
16033
|
+
outcome: "stopped",
|
|
16034
|
+
taskId,
|
|
16035
|
+
pid: record2.pid,
|
|
16036
|
+
status: reportedTaskStatus("killed"),
|
|
16037
|
+
signal: "SIGKILL",
|
|
16038
|
+
escalated: true,
|
|
16039
|
+
cleanup: resolveCleanupReport({ confirmedStopped: true })
|
|
16040
|
+
};
|
|
16041
|
+
}
|
|
16042
|
+
function runTasks(args2) {
|
|
16043
|
+
const tasks = args2.registry.listBackground().map((record2) => ({
|
|
16044
|
+
taskId: record2.taskId,
|
|
16045
|
+
pid: record2.pid,
|
|
16046
|
+
label: record2.label,
|
|
16047
|
+
status: statusOf(record2),
|
|
16048
|
+
startedAt: record2.startedAt,
|
|
16049
|
+
persist: record2.persist
|
|
16050
|
+
}));
|
|
16051
|
+
return { tasks, count: tasks.length };
|
|
16052
|
+
}
|
|
15983
16053
|
|
|
15984
16054
|
// packages/agent-runtime/localWorkspaceToolDefs.ts
|
|
15985
16055
|
var WORKSPACE_TOOL_NAMES = [
|
|
@@ -16316,23 +16386,6 @@ function filterDeclaredWorkspaceToolNames(args2) {
|
|
|
16316
16386
|
);
|
|
16317
16387
|
}
|
|
16318
16388
|
|
|
16319
|
-
// packages/agent-runtime/capabilities/capabilitySdk.ts
|
|
16320
|
-
var BUILTIN_CAPABILITIES = [
|
|
16321
|
-
execShellCapability
|
|
16322
|
-
];
|
|
16323
|
-
async function invokeCapability(capabilityOrName, input, ctx = {}) {
|
|
16324
|
-
const capability = typeof capabilityOrName === "string" ? BUILTIN_CAPABILITIES.find((c) => c.name === capabilityOrName) : capabilityOrName;
|
|
16325
|
-
if (!capability) {
|
|
16326
|
-
throw new Error(`Capability "${String(capabilityOrName)}" not found.`);
|
|
16327
|
-
}
|
|
16328
|
-
const normalizedInput = capability.normalizeInput(input);
|
|
16329
|
-
await evaluateCapabilityPolicy(capability, normalizedInput, ctx);
|
|
16330
|
-
if (ctx.onInvoke) {
|
|
16331
|
-
await ctx.onInvoke(capability.name, normalizedInput);
|
|
16332
|
-
}
|
|
16333
|
-
return capability.invoke(ctx, normalizedInput);
|
|
16334
|
-
}
|
|
16335
|
-
|
|
16336
16389
|
// packages/agent-runtime/localWorkspaceTools.ts
|
|
16337
16390
|
async function hasRootGitignore2(workspaceRoot) {
|
|
16338
16391
|
return hasRootGitignore(workspaceRoot);
|
|
@@ -16518,20 +16571,20 @@ function collectIntegerArg(args2) {
|
|
|
16518
16571
|
var LINES_ARG_SYNTAX = '"40-120", "120-", "-50", or "50"';
|
|
16519
16572
|
var LINES_RANGE_FORMAT = /^(\d+)?\s*-\s*(\d+)?$/;
|
|
16520
16573
|
function parseLinesArg(value) {
|
|
16521
|
-
const
|
|
16522
|
-
if (!
|
|
16574
|
+
const text2 = asTrimmedString(value);
|
|
16575
|
+
if (!text2) {
|
|
16523
16576
|
return {
|
|
16524
16577
|
warning: `Ignored lines: expected ${LINES_ARG_SYNTAX}, received ${describeRejectedArgValue(value)}.`
|
|
16525
16578
|
};
|
|
16526
16579
|
}
|
|
16527
16580
|
const reject = {
|
|
16528
|
-
warning: `Ignored lines: expected ${LINES_ARG_SYNTAX}, received ${JSON.stringify(
|
|
16581
|
+
warning: `Ignored lines: expected ${LINES_ARG_SYNTAX}, received ${JSON.stringify(text2)}.`
|
|
16529
16582
|
};
|
|
16530
|
-
if (/^\d+$/.test(
|
|
16531
|
-
const count = Number(
|
|
16583
|
+
if (/^\d+$/.test(text2)) {
|
|
16584
|
+
const count = Number(text2);
|
|
16532
16585
|
return count > 0 ? { slice: { maxLines: Math.min(count, 2e3) } } : reject;
|
|
16533
16586
|
}
|
|
16534
|
-
const range3 = LINES_RANGE_FORMAT.exec(
|
|
16587
|
+
const range3 = LINES_RANGE_FORMAT.exec(text2);
|
|
16535
16588
|
if (!range3) return reject;
|
|
16536
16589
|
const [, rawStart, rawEnd] = range3;
|
|
16537
16590
|
if (rawStart === void 0 && rawEnd === void 0) return reject;
|
|
@@ -16545,7 +16598,7 @@ function parseLinesArg(value) {
|
|
|
16545
16598
|
const endLine = Number(rawEnd);
|
|
16546
16599
|
if (endLine < startLine) {
|
|
16547
16600
|
return {
|
|
16548
|
-
warning: `Ignored lines ${JSON.stringify(
|
|
16601
|
+
warning: `Ignored lines ${JSON.stringify(text2)}: the end line must be greater than or equal to the start line.`
|
|
16549
16602
|
};
|
|
16550
16603
|
}
|
|
16551
16604
|
return { slice: { startLine, endLine } };
|
|
@@ -16628,11 +16681,11 @@ function countAndReplaceEolTolerant(args2) {
|
|
|
16628
16681
|
});
|
|
16629
16682
|
return { count, result: result4 };
|
|
16630
16683
|
}
|
|
16631
|
-
function normalizeEolToLf(
|
|
16632
|
-
return
|
|
16684
|
+
function normalizeEolToLf(text2) {
|
|
16685
|
+
return text2.replace(/\r\n/g, "\n");
|
|
16633
16686
|
}
|
|
16634
|
-
function convertEol(
|
|
16635
|
-
const lf = normalizeEolToLf(
|
|
16687
|
+
function convertEol(text2, eol) {
|
|
16688
|
+
const lf = normalizeEolToLf(text2);
|
|
16636
16689
|
return eol === "\r\n" ? lf.replace(/\n/g, "\r\n") : lf;
|
|
16637
16690
|
}
|
|
16638
16691
|
function pluralizeReplacement(count) {
|
|
@@ -16640,8 +16693,8 @@ function pluralizeReplacement(count) {
|
|
|
16640
16693
|
}
|
|
16641
16694
|
var EDIT_SNIPPET_MAX_LINES = 24;
|
|
16642
16695
|
var EDIT_SNIPPET_WIDTH = 160;
|
|
16643
|
-
function clipEditSnippet(
|
|
16644
|
-
const lines =
|
|
16696
|
+
function clipEditSnippet(text2) {
|
|
16697
|
+
const lines = text2.split(/\r?\n/);
|
|
16645
16698
|
if (lines.at(-1) === "") lines.pop();
|
|
16646
16699
|
return lines.slice(0, EDIT_SNIPPET_MAX_LINES).map((line) => line.length > EDIT_SNIPPET_WIDTH ? `${line.slice(0, EDIT_SNIPPET_WIDTH)}\u2026` : line).join("\n");
|
|
16647
16700
|
}
|
|
@@ -16755,8 +16808,8 @@ async function runWorkspacePackageScript(args2) {
|
|
|
16755
16808
|
}
|
|
16756
16809
|
};
|
|
16757
16810
|
}
|
|
16758
|
-
function parseLastJsonObject(
|
|
16759
|
-
const trimmed =
|
|
16811
|
+
function parseLastJsonObject(text2) {
|
|
16812
|
+
const trimmed = text2.trim();
|
|
16760
16813
|
for (let index = trimmed.lastIndexOf("{"); index >= 0; index = trimmed.lastIndexOf("{", index - 1)) {
|
|
16761
16814
|
try {
|
|
16762
16815
|
const parsed = JSON.parse(trimmed.slice(index));
|
|
@@ -16798,9 +16851,12 @@ function expandHomePath(requestedPath) {
|
|
|
16798
16851
|
if (requestedPath.startsWith("~/")) return resolve4(homedir(), requestedPath.slice(2));
|
|
16799
16852
|
return requestedPath;
|
|
16800
16853
|
}
|
|
16854
|
+
function resolveRequestedWorkspacePath(workspaceRoot, requestedPath) {
|
|
16855
|
+
return resolve4(resolve4(workspaceRoot), expandHomePath(requestedPath));
|
|
16856
|
+
}
|
|
16801
16857
|
async function resolveLocalWorkspaceToolPath(args2) {
|
|
16802
16858
|
const workspaceRoot = resolve4(args2.workspaceRoot);
|
|
16803
|
-
const targetPath =
|
|
16859
|
+
const targetPath = resolveRequestedWorkspacePath(workspaceRoot, args2.requestedPath);
|
|
16804
16860
|
const insideWorkspace = isPathInsideWorkspace({ workspaceRoot, targetPath });
|
|
16805
16861
|
const trustedSpillPath = !insideWorkspace && args2.allowRuntimeOwnedSpill === true ? await resolveRuntimeOwnedSpillPath(targetPath) : null;
|
|
16806
16862
|
if (!insideWorkspace && trustedSpillPath === null) {
|
|
@@ -16901,7 +16957,7 @@ async function readFileTool(args2) {
|
|
|
16901
16957
|
const force = parsed.force === true;
|
|
16902
16958
|
const ledger = args2.readLedger;
|
|
16903
16959
|
const requestRange = { startLine: sliced.startLine, endLine: sliced.endLine };
|
|
16904
|
-
const fingerprint =
|
|
16960
|
+
const fingerprint = createHash4("sha1").update(content).digest("hex").slice(0, 20);
|
|
16905
16961
|
let entry = ledger?.get(relativePath);
|
|
16906
16962
|
if (entry && entry.fingerprint !== fingerprint) {
|
|
16907
16963
|
entry = void 0;
|
|
@@ -16976,13 +17032,13 @@ async function writeFileTool(args2) {
|
|
|
16976
17032
|
}
|
|
16977
17033
|
};
|
|
16978
17034
|
}
|
|
16979
|
-
function extractSnippetWords(
|
|
17035
|
+
function extractSnippetWords(text2) {
|
|
16980
17036
|
const tokens = [];
|
|
16981
|
-
const latinWords =
|
|
17037
|
+
const latinWords = text2.match(/[A-Za-z0-9_]{2,}/g);
|
|
16982
17038
|
if (latinWords) {
|
|
16983
17039
|
for (const w of latinWords) tokens.push(w.toLowerCase());
|
|
16984
17040
|
}
|
|
16985
|
-
const cjkChars =
|
|
17041
|
+
const cjkChars = text2.match(new RegExp("\\p{Script=Han}", "gu"));
|
|
16986
17042
|
if (cjkChars) {
|
|
16987
17043
|
for (let i = 0; i < cjkChars.length - 1; i++) {
|
|
16988
17044
|
tokens.push(cjkChars[i] + cjkChars[i + 1]);
|
|
@@ -17886,7 +17942,7 @@ function validateToolArguments(args2) {
|
|
|
17886
17942
|
return { ok: true, args: {} };
|
|
17887
17943
|
}
|
|
17888
17944
|
const raw = typeof rawArguments === "string" ? rawArguments.trim() : "";
|
|
17889
|
-
let
|
|
17945
|
+
let record2 = {};
|
|
17890
17946
|
if (raw !== "") {
|
|
17891
17947
|
let parsed;
|
|
17892
17948
|
try {
|
|
@@ -17897,18 +17953,18 @@ function validateToolArguments(args2) {
|
|
|
17897
17953
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
17898
17954
|
return { ok: true, args: {} };
|
|
17899
17955
|
}
|
|
17900
|
-
|
|
17956
|
+
record2 = parsed;
|
|
17901
17957
|
}
|
|
17902
17958
|
for (const field of requiredFields) {
|
|
17903
|
-
if (
|
|
17904
|
-
if (isAliasSatisfied(
|
|
17959
|
+
if (record2[field] !== void 0) continue;
|
|
17960
|
+
if (isAliasSatisfied(record2, field)) continue;
|
|
17905
17961
|
return {
|
|
17906
17962
|
ok: false,
|
|
17907
17963
|
message: `${toolName} \u53C2\u6570\u6821\u9A8C\u5931\u8D25\uFF1A\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570 "${field}"\u3002\u8BF7\u8865\u4E0A\u540E\u91CD\u65B0\u8C03\u7528 ${toolName}\u3002`
|
|
17908
17964
|
};
|
|
17909
17965
|
}
|
|
17910
17966
|
for (const [field, spec] of Object.entries(properties)) {
|
|
17911
|
-
const value =
|
|
17967
|
+
const value = record2[field];
|
|
17912
17968
|
if (value === void 0 || value === null) continue;
|
|
17913
17969
|
if (!spec || typeof spec !== "object" || Array.isArray(spec)) continue;
|
|
17914
17970
|
const declared = spec.type;
|
|
@@ -17922,7 +17978,7 @@ function validateToolArguments(args2) {
|
|
|
17922
17978
|
};
|
|
17923
17979
|
}
|
|
17924
17980
|
}
|
|
17925
|
-
return { ok: true, args:
|
|
17981
|
+
return { ok: true, args: record2 };
|
|
17926
17982
|
}
|
|
17927
17983
|
function buildToolParametersIndex(tools) {
|
|
17928
17984
|
const index = /* @__PURE__ */ new Map();
|
|
@@ -18062,6 +18118,39 @@ function resolveLocalToolPolicy(args2) {
|
|
|
18062
18118
|
reason: `${toolName} is not enabled for local runtime runs. The agent must declare the tool in its manifest; in restricted mode (NOLO_LOCAL_TOOL_MODE=restricted) non-default tools also require adding to NOLO_LOCAL_ALLOWED_TOOLS (e.g. NOLO_LOCAL_ALLOWED_TOOLS=someCustomTool) and restarting the session so the env var loads.`
|
|
18063
18119
|
};
|
|
18064
18120
|
}
|
|
18121
|
+
async function runExecShellGates(args2) {
|
|
18122
|
+
const opts = {
|
|
18123
|
+
...args2.abortSignal ? { abortSignal: args2.abortSignal } : {},
|
|
18124
|
+
...args2.detachMs !== void 0 ? { detachMs: args2.detachMs } : {},
|
|
18125
|
+
...args2.confirmed !== void 0 ? { confirmed: args2.confirmed } : {},
|
|
18126
|
+
...args2.enableDestructiveShellGuard !== void 0 ? { enableDestructiveShellGuard: args2.enableDestructiveShellGuard } : {},
|
|
18127
|
+
...args2.confirmDestructiveAction ? { confirmDestructiveAction: args2.confirmDestructiveAction } : {},
|
|
18128
|
+
...args2.blockDestructiveWithoutConfirmation !== void 0 ? { blockDestructiveWithoutConfirmation: args2.blockDestructiveWithoutConfirmation } : {}
|
|
18129
|
+
};
|
|
18130
|
+
if (normalizeLocalToolName(args2.toolName) !== "execShell") {
|
|
18131
|
+
return { kind: "pass", opts };
|
|
18132
|
+
}
|
|
18133
|
+
if (args2.execShellApproval) {
|
|
18134
|
+
const result4 = await invokeCapability("execShell", args2.callArguments, {
|
|
18135
|
+
...opts,
|
|
18136
|
+
workspaceRoot: args2.workspaceRoot,
|
|
18137
|
+
commandOutputLimit: args2.commandOutputLimit,
|
|
18138
|
+
execShellApproval: args2.execShellApproval
|
|
18139
|
+
});
|
|
18140
|
+
return { kind: "handled", result: result4 };
|
|
18141
|
+
}
|
|
18142
|
+
let parsedInput = args2.callArguments;
|
|
18143
|
+
if (typeof parsedInput === "string") {
|
|
18144
|
+
try {
|
|
18145
|
+
parsedInput = JSON.parse(parsedInput);
|
|
18146
|
+
} catch {
|
|
18147
|
+
parsedInput = { command: parsedInput };
|
|
18148
|
+
}
|
|
18149
|
+
}
|
|
18150
|
+
await evaluateExecShellDestructiveGuard(parsedInput, opts);
|
|
18151
|
+
opts.confirmed = true;
|
|
18152
|
+
return { kind: "pass", opts };
|
|
18153
|
+
}
|
|
18065
18154
|
async function executeLocalToolWithPolicy(args2) {
|
|
18066
18155
|
if (args2.runToolNames !== void 0 && !args2.runToolNames.map(normalizeLocalToolName).includes(normalizeLocalToolName(args2.call.name))) {
|
|
18067
18156
|
throw new Error(`${args2.call.name} is outside the final run tool surface.`);
|
|
@@ -18078,39 +18167,33 @@ async function executeLocalToolWithPolicy(args2) {
|
|
|
18078
18167
|
}
|
|
18079
18168
|
const parametersSchema = args2.toolParametersIndex?.get(decision.toolName);
|
|
18080
18169
|
if (parametersSchema !== void 0) {
|
|
18081
|
-
const
|
|
18082
|
-
toolName: decision.toolName,
|
|
18083
|
-
rawArguments: args2.call.arguments,
|
|
18084
|
-
parameters: parametersSchema
|
|
18085
|
-
});
|
|
18086
|
-
if (!
|
|
18087
|
-
}
|
|
18088
|
-
const opts = {
|
|
18089
|
-
...args2.abortSignal ? { abortSignal: args2.abortSignal } : {},
|
|
18090
|
-
...args2.detachMs !== void 0 ? { detachMs: args2.detachMs } : {},
|
|
18091
|
-
...args2.confirmed !== void 0 ? { confirmed: args2.confirmed } : {},
|
|
18092
|
-
...args2.enableDestructiveShellGuard !== void 0 ? { enableDestructiveShellGuard: args2.enableDestructiveShellGuard } : {},
|
|
18093
|
-
...args2.confirmDestructiveAction ? { confirmDestructiveAction: args2.confirmDestructiveAction } : {},
|
|
18094
|
-
...args2.blockDestructiveWithoutConfirmation !== void 0 ? { blockDestructiveWithoutConfirmation: args2.blockDestructiveWithoutConfirmation } : {}
|
|
18095
|
-
};
|
|
18096
|
-
if (decision.toolName === "execShell") {
|
|
18097
|
-
let parsedInput = args2.call.arguments;
|
|
18098
|
-
if (typeof parsedInput === "string") {
|
|
18099
|
-
try {
|
|
18100
|
-
parsedInput = JSON.parse(parsedInput);
|
|
18101
|
-
} catch {
|
|
18102
|
-
parsedInput = { command: parsedInput };
|
|
18103
|
-
}
|
|
18104
|
-
}
|
|
18105
|
-
await evaluateExecShellDestructiveGuard(parsedInput, opts);
|
|
18106
|
-
opts.confirmed = true;
|
|
18170
|
+
const gate2 = validateToolArguments({
|
|
18171
|
+
toolName: decision.toolName,
|
|
18172
|
+
rawArguments: args2.call.arguments,
|
|
18173
|
+
parameters: parametersSchema
|
|
18174
|
+
});
|
|
18175
|
+
if (!gate2.ok) throw new Error(gate2.message);
|
|
18107
18176
|
}
|
|
18177
|
+
const gate = await runExecShellGates({
|
|
18178
|
+
toolName: decision.toolName,
|
|
18179
|
+
callArguments: args2.call.arguments,
|
|
18180
|
+
execShellApproval: args2.execShellApproval,
|
|
18181
|
+
workspaceRoot: args2.workspaceRoot,
|
|
18182
|
+
commandOutputLimit: args2.commandOutputLimit,
|
|
18183
|
+
abortSignal: args2.abortSignal,
|
|
18184
|
+
detachMs: args2.detachMs,
|
|
18185
|
+
confirmed: args2.confirmed,
|
|
18186
|
+
enableDestructiveShellGuard: args2.enableDestructiveShellGuard,
|
|
18187
|
+
confirmDestructiveAction: args2.confirmDestructiveAction,
|
|
18188
|
+
blockDestructiveWithoutConfirmation: args2.blockDestructiveWithoutConfirmation
|
|
18189
|
+
});
|
|
18190
|
+
if (gate.kind === "handled") return gate.result;
|
|
18108
18191
|
return executor(
|
|
18109
18192
|
{
|
|
18110
18193
|
...args2.call,
|
|
18111
18194
|
name: decision.toolName
|
|
18112
18195
|
},
|
|
18113
|
-
opts
|
|
18196
|
+
gate.opts
|
|
18114
18197
|
);
|
|
18115
18198
|
}
|
|
18116
18199
|
|
|
@@ -18161,16 +18244,16 @@ function shouldReturnToolExecutionErrors(adapter) {
|
|
|
18161
18244
|
function emitLoopEvent(boundary, event, bridge) {
|
|
18162
18245
|
boundary.emit(bridge ? { event, bridge } : { event });
|
|
18163
18246
|
}
|
|
18164
|
-
function
|
|
18247
|
+
function clip(value, max4 = 240) {
|
|
18165
18248
|
return clipCompactText(value, max4);
|
|
18166
18249
|
}
|
|
18167
18250
|
function projectSafeToolObservationMetadata(metadata) {
|
|
18168
18251
|
if (!metadata || typeof metadata !== "object") return void 0;
|
|
18169
18252
|
const safe = {};
|
|
18170
18253
|
if (typeof metadata.exitCode === "number") safe.exitCode = metadata.exitCode;
|
|
18171
|
-
if (typeof metadata.actionGate === "string") safe.actionGate =
|
|
18172
|
-
if (typeof metadata.command === "string") safe.command =
|
|
18173
|
-
if (typeof metadata.path === "string") safe.path =
|
|
18254
|
+
if (typeof metadata.actionGate === "string") safe.actionGate = clip(metadata.actionGate, 240);
|
|
18255
|
+
if (typeof metadata.command === "string") safe.command = clip(metadata.command, 240);
|
|
18256
|
+
if (typeof metadata.path === "string") safe.path = clip(metadata.path, 240);
|
|
18174
18257
|
if (typeof metadata.truncated === "boolean") safe.truncated = metadata.truncated;
|
|
18175
18258
|
if (typeof metadata.byteCount === "number") safe.byteCount = metadata.byteCount;
|
|
18176
18259
|
if (typeof metadata.lineCount === "number") safe.lineCount = metadata.lineCount;
|
|
@@ -18186,7 +18269,7 @@ function summarizeToolResult(content, metadata) {
|
|
|
18186
18269
|
const lines = trimmed.split(/\r?\n/).length;
|
|
18187
18270
|
parts2.push(`${lines} line${lines === 1 ? "" : "s"}`);
|
|
18188
18271
|
parts2.push(`${trimmed.length} chars`);
|
|
18189
|
-
const tail =
|
|
18272
|
+
const tail = clip(trimmed.slice(-160), 160);
|
|
18190
18273
|
if (tail) parts2.push(`tail="${tail}"`);
|
|
18191
18274
|
} else {
|
|
18192
18275
|
parts2.push("empty");
|
|
@@ -18310,7 +18393,10 @@ async function executeToolCall(args2) {
|
|
|
18310
18393
|
})
|
|
18311
18394
|
);
|
|
18312
18395
|
throw new Error(
|
|
18313
|
-
|
|
18396
|
+
// 只按类别换文案(判定分支、错误类型、可重试性、落库内容、日志级别全部不变):
|
|
18397
|
+
// 两类都只描述**形状**、不判原因——分类只看得出「字符串/括号是否闭合」,
|
|
18398
|
+
// 分不出「上游传输层丢字节」还是「模型自己写错了闭合符」。
|
|
18399
|
+
classifyUnparsableToolArgs(rawPoisonArguments) === "truncated" ? `\u6A21\u578B\u751F\u6210\u7684 tool_call arguments \u4E0D\u662F\u5408\u6CD5 JSON\uFF08\u5F62\u72B6\uFF1A\u7591\u4F3C\u5C3E\u90E8\u4E0D\u5B8C\u6574\u2014\u2014\u5B57\u7B26\u4E32\u6216\u62EC\u53F7\u672A\u95ED\u5408\uFF0C\u7591\u4F3C\u6D41\u5F0F\u4E2D\u65AD\uFF1B\u539F\u59CB\u957F\u5EA6 ${rawPoisonArguments.length}\uFF09\u3002\u8BF7\u91CD\u65B0\u5B8C\u6574\u8C03\u7528 ${toolName}\uFF0C\u786E\u4FDD arguments \u662F\u95ED\u5408\u7684 JSON \u5BF9\u8C61\uFF1B\u82E5\u56E0\u53C2\u6570\u8FC7\u957F\u88AB\u622A\u65AD\uFF0C\u5148\u7CBE\u7B80\u53C2\u6570\uFF08\u4E0D\u8981\u5185\u5D4C diff/\u65E5\u5FD7\u7B49\u5927\u6BB5\u6587\u672C\uFF0C\u6539\u4F20\u8DEF\u5F84\u8BA9\u5BF9\u65B9\u81EA\u884C\u8BFB\u53D6\uFF09\u518D\u91CD\u8BD5\u3002` : `\u6A21\u578B\u751F\u6210\u7684 tool_call arguments \u4E0D\u662F\u5408\u6CD5 JSON\uFF08\u5F62\u72B6\uFF1A\u7ED3\u6784\u5B8C\u6574\u4F46 token \u975E\u6CD5\u2014\u2014\u975E\u95ED\u5408\u95EE\u9898\uFF1B\u539F\u59CB\u957F\u5EA6 ${rawPoisonArguments.length}\uFF09\u3002\u8BF7\u91CD\u65B0\u5B8C\u6574\u8C03\u7528 ${toolName}\uFF0C\u786E\u4FDD\u6BCF\u4E2A\u5B57\u7B26\u4E32\u503C\u90FD\u6309 JSON \u89C4\u5219\u8F6C\u4E49\uFF08\u6362\u884C\u7B49\u63A7\u5236\u5B57\u7B26\u5199\u6210 \\n \u7B49\u8F6C\u4E49\u5E8F\u5217\uFF09\uFF0C\u533A\u95F4/\u7248\u672C\u53F7\u7B49\u975E JSON \u5B57\u9762\u91CF\u5199\u6210\u5B57\u7B26\u4E32\uFF08\u5982 "lines": "300-400"\uFF09\uFF0Carguments \u662F\u95ED\u5408\u7684 JSON \u5BF9\u8C61\u3002`
|
|
18314
18400
|
);
|
|
18315
18401
|
}
|
|
18316
18402
|
}
|
|
@@ -18552,7 +18638,7 @@ function createTurnUsageLedger(args2) {
|
|
|
18552
18638
|
let compactionUsage;
|
|
18553
18639
|
const providerRecords = [];
|
|
18554
18640
|
return {
|
|
18555
|
-
recordProviderCall: ({ usage, model, provider }) => {
|
|
18641
|
+
recordProviderCall: ({ usage, model, provider, telemetry }) => {
|
|
18556
18642
|
turnUsage = mergeTurnUsage(turnUsage, usage);
|
|
18557
18643
|
lastContextUsage = usage;
|
|
18558
18644
|
if (usage && Object.keys(usage).length > 0) {
|
|
@@ -18561,6 +18647,7 @@ function createTurnUsageLedger(args2) {
|
|
|
18561
18647
|
usage,
|
|
18562
18648
|
model: model || args2.model || "unknown",
|
|
18563
18649
|
...provider || args2.provider ? { provider: provider || args2.provider } : {},
|
|
18650
|
+
...telemetry && Object.keys(telemetry).length > 0 ? { telemetry } : {},
|
|
18564
18651
|
...args2.stablePrefixHash ? {
|
|
18565
18652
|
stablePrefixHash: args2.stablePrefixHash,
|
|
18566
18653
|
stablePrefixEstimatedTokens: args2.stablePrefixEstimatedTokens
|
|
@@ -18588,7 +18675,7 @@ function createTurnUsageLedger(args2) {
|
|
|
18588
18675
|
}
|
|
18589
18676
|
|
|
18590
18677
|
// packages/agent-runtime/leafFinalHandoff.ts
|
|
18591
|
-
var LEAF_FINAL_HANDOFF_INSTRUCTIONS = `Leaf subtask final: return only the result, blockers/findings, and minimal evidence the parent needs. Do not narrate your process or restate the task. Keep success minimal (a one-line result is enough); on failure include the blocker, severity when relevant, and an evidence reference (file:line, test command, commit, artifact, or run/dialog). If the task explicitly requires a long-form deliverable (document, translation, dataset, code, or other artifact), provide that deliverable in full and keep only the handoff around it concise. During execution, follow the brief as given: only when new evidence would materially change the goal, risk, irreversibility, or DoD should you surface it as a blocker/finding
|
|
18678
|
+
var LEAF_FINAL_HANDOFF_INSTRUCTIONS = `Leaf subtask final: return only the result, blockers/findings, and minimal evidence the parent needs. Do not narrate your process or restate the task. Keep success minimal (a one-line result is enough); on failure include the blocker, severity when relevant, and an evidence reference (file:line, test command, commit, artifact, or run/dialog). If the task explicitly requires a long-form deliverable (document, translation, dataset, code, or other artifact), provide that deliverable in full and keep only the handoff around it concise. During execution, follow the brief as given: report only results incremental to the brief, new evidence, overturned assumptions, and remaining questions; only when new evidence would materially change the goal, risk, irreversibility, or DoD should you surface it as a blocker/finding \u2014 do not silently expand scope or re-litigate the settled direction. Keep success concise, but include evidence for required DoD items.`;
|
|
18592
18679
|
|
|
18593
18680
|
// packages/agent-runtime/contextBlockScope.ts
|
|
18594
18681
|
var isContextBlockScope = (value) => {
|
|
@@ -18605,7 +18692,7 @@ var normalizeContextBlockScopes = (legacyBlocks = void 0, scopes = void 0) => {
|
|
|
18605
18692
|
};
|
|
18606
18693
|
|
|
18607
18694
|
// packages/agent-runtime/localAutoCompaction.ts
|
|
18608
|
-
import { createHash as
|
|
18695
|
+
import { createHash as createHash5, randomUUID } from "node:crypto";
|
|
18609
18696
|
function toPlanCompressionMessages(history) {
|
|
18610
18697
|
return history.map((message, index) => ({
|
|
18611
18698
|
id: `local-${index}`,
|
|
@@ -18620,7 +18707,7 @@ function hashSummarySourceSlice(history, summarizedBeforeId) {
|
|
|
18620
18707
|
const found = bridged.findIndex((m) => m.id === summarizedBeforeId);
|
|
18621
18708
|
if (found === -1) return void 0;
|
|
18622
18709
|
const slice = bridged.slice(0, found + 1);
|
|
18623
|
-
return
|
|
18710
|
+
return createHash5("sha256").update(JSON.stringify(slice)).digest("hex");
|
|
18624
18711
|
}
|
|
18625
18712
|
function validateStoredSummary(args2) {
|
|
18626
18713
|
const { history, stored } = args2;
|
|
@@ -18671,6 +18758,39 @@ function isColdResume(history, nowMs) {
|
|
|
18671
18758
|
}
|
|
18672
18759
|
return false;
|
|
18673
18760
|
}
|
|
18761
|
+
async function runSummaryFallback(fallback, content, options) {
|
|
18762
|
+
try {
|
|
18763
|
+
const text2 = await fallback(content, options);
|
|
18764
|
+
if (typeof text2 !== "string") return null;
|
|
18765
|
+
const trimmed = text2.trim();
|
|
18766
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
18767
|
+
} catch (error) {
|
|
18768
|
+
console.warn("[localLoop] auto-compaction summary fallback failed", {
|
|
18769
|
+
attemptId: options.attemptId,
|
|
18770
|
+
stage: "fallback"
|
|
18771
|
+
});
|
|
18772
|
+
return null;
|
|
18773
|
+
}
|
|
18774
|
+
}
|
|
18775
|
+
var COMPACTION_RETRY_BACKOFF_MS = 6e4;
|
|
18776
|
+
var COMPACTION_RETRY_BACKOFF_MAX_ENTRIES = 256;
|
|
18777
|
+
var compactionRetryBackoff = /* @__PURE__ */ new Map();
|
|
18778
|
+
function isCompactionBackedOff(dialogId, now) {
|
|
18779
|
+
for (const [key, until2] of compactionRetryBackoff) {
|
|
18780
|
+
if (until2 <= now) compactionRetryBackoff.delete(key);
|
|
18781
|
+
}
|
|
18782
|
+
const until = compactionRetryBackoff.get(dialogId);
|
|
18783
|
+
return until !== void 0 && until > now;
|
|
18784
|
+
}
|
|
18785
|
+
function recordCompactionFailure(dialogId, now) {
|
|
18786
|
+
compactionRetryBackoff.delete(dialogId);
|
|
18787
|
+
while (compactionRetryBackoff.size >= COMPACTION_RETRY_BACKOFF_MAX_ENTRIES) {
|
|
18788
|
+
const oldest = compactionRetryBackoff.keys().next().value;
|
|
18789
|
+
if (oldest === void 0) break;
|
|
18790
|
+
compactionRetryBackoff.delete(oldest);
|
|
18791
|
+
}
|
|
18792
|
+
compactionRetryBackoff.set(dialogId, now + COMPACTION_RETRY_BACKOFF_MS);
|
|
18793
|
+
}
|
|
18674
18794
|
async function maybeAutoCompactLocalHistory(args2) {
|
|
18675
18795
|
const { adapter, dialogId, history } = args2;
|
|
18676
18796
|
const emitPhase = (phase) => {
|
|
@@ -18775,7 +18895,56 @@ async function maybeAutoCompactLocalHistory(args2) {
|
|
|
18775
18895
|
if (!plan.shouldCompress) {
|
|
18776
18896
|
return projectExisting();
|
|
18777
18897
|
}
|
|
18898
|
+
const retryNow = args2.now?.() ?? Date.now();
|
|
18899
|
+
if (isCompactionBackedOff(dialogId, retryNow)) {
|
|
18900
|
+
const projected = projectExisting();
|
|
18901
|
+
const diag = plan.diagnostics;
|
|
18902
|
+
return {
|
|
18903
|
+
...projected,
|
|
18904
|
+
decision: {
|
|
18905
|
+
outcome: "skipped",
|
|
18906
|
+
skipReason: "retry-backoff",
|
|
18907
|
+
...diag ? {
|
|
18908
|
+
estimatedTokens: diag.totalUsed,
|
|
18909
|
+
historyBudget: diag.historyBudget,
|
|
18910
|
+
triggerRatio: diag.triggerRatio,
|
|
18911
|
+
...diag.realUsageRatio !== void 0 ? { realUsageRatio: diag.realUsageRatio } : {}
|
|
18912
|
+
} : {}
|
|
18913
|
+
}
|
|
18914
|
+
};
|
|
18915
|
+
}
|
|
18778
18916
|
emitPhase({ kind: "compaction-start" });
|
|
18917
|
+
const compactionAttemptId = randomUUID();
|
|
18918
|
+
let compactionT0 = Date.now();
|
|
18919
|
+
let compactionInputTokens;
|
|
18920
|
+
let compactionPrevSummaryTokens;
|
|
18921
|
+
let compactionInputSource;
|
|
18922
|
+
let compactionPrevSummarySource;
|
|
18923
|
+
let primaryElapsedMs;
|
|
18924
|
+
let fallbackElapsedMs;
|
|
18925
|
+
let saveElapsedMs;
|
|
18926
|
+
const logCompactionTiming = (outcome, fields) => {
|
|
18927
|
+
if (compactionInputTokens === void 0 && compactionInputSource !== void 0) {
|
|
18928
|
+
compactionInputTokens = estimateTokenCount(compactionInputSource);
|
|
18929
|
+
}
|
|
18930
|
+
if (compactionPrevSummaryTokens === void 0 && compactionPrevSummarySource !== void 0) {
|
|
18931
|
+
compactionPrevSummaryTokens = estimateTokenCount(compactionPrevSummarySource);
|
|
18932
|
+
}
|
|
18933
|
+
console.log(
|
|
18934
|
+
`[compaction-timing] ${JSON.stringify({
|
|
18935
|
+
attemptId: compactionAttemptId,
|
|
18936
|
+
model: fields.model ?? args2.model ?? null,
|
|
18937
|
+
inputTokens: compactionInputTokens ?? null,
|
|
18938
|
+
prevSummaryTokens: compactionPrevSummaryTokens ?? null,
|
|
18939
|
+
outputChars: fields.outputChars ?? null,
|
|
18940
|
+
elapsedMs: Date.now() - compactionT0,
|
|
18941
|
+
primaryElapsedMs: primaryElapsedMs ?? null,
|
|
18942
|
+
fallbackElapsedMs: fallbackElapsedMs ?? null,
|
|
18943
|
+
saveElapsedMs: saveElapsedMs ?? null,
|
|
18944
|
+
outcome
|
|
18945
|
+
})}`
|
|
18946
|
+
);
|
|
18947
|
+
};
|
|
18779
18948
|
try {
|
|
18780
18949
|
if (args2.abortSignal?.aborted) {
|
|
18781
18950
|
throw Object.assign(new Error("auto-compaction aborted"), { compactionReason: "aborted" });
|
|
@@ -18785,7 +18954,11 @@ async function maybeAutoCompactLocalHistory(args2) {
|
|
|
18785
18954
|
throw Object.assign(new Error("auto-compaction aborted"), { compactionReason: "aborted" });
|
|
18786
18955
|
}
|
|
18787
18956
|
const msgsToCompress = plan.msgsToCompress;
|
|
18788
|
-
const messagesText = formatMessagesForSummaryWithTruncation(
|
|
18957
|
+
const messagesText = formatMessagesForSummaryWithTruncation(
|
|
18958
|
+
msgsToCompress,
|
|
18959
|
+
TOOL_RESULT_TRUNCATE_CHARS,
|
|
18960
|
+
computeSummaryInputTokenCap(contextWindow)
|
|
18961
|
+
);
|
|
18789
18962
|
const fileOpsText = formatFileOperationsFromMessages(
|
|
18790
18963
|
msgsToCompress,
|
|
18791
18964
|
canonicalizeToolName
|
|
@@ -18796,58 +18969,102 @@ async function maybeAutoCompactLocalHistory(args2) {
|
|
|
18796
18969
|
fileOpsText
|
|
18797
18970
|
});
|
|
18798
18971
|
emitPhase({ kind: "waiting-provider" });
|
|
18972
|
+
compactionInputSource = messagesText;
|
|
18973
|
+
compactionPrevSummarySource = existingSummary;
|
|
18974
|
+
compactionT0 = Date.now();
|
|
18799
18975
|
const timeoutMs = typeof args2.timeoutMs === "number" && Number.isFinite(args2.timeoutMs) && args2.timeoutMs > 0 ? args2.timeoutMs : void 0;
|
|
18800
18976
|
const requestController = new AbortController();
|
|
18801
18977
|
let timeoutHandle;
|
|
18802
18978
|
let abortListener;
|
|
18979
|
+
if (args2.abortSignal?.aborted) requestController.abort(args2.abortSignal.reason);
|
|
18803
18980
|
const request3 = provider.complete(
|
|
18804
18981
|
[{ role: "system", content: COMPACTION_SUMMARY_SYSTEM_PROMPT }, { role: "user", content: promptContent }],
|
|
18805
|
-
{
|
|
18982
|
+
{
|
|
18983
|
+
signal: requestController.signal,
|
|
18984
|
+
...timeoutMs ? { timeoutMs } : {},
|
|
18985
|
+
// 仅日志用的 attempt id:让 compaction 埋点与 transport 诊断日志 /
|
|
18986
|
+
// 服务端 x-request-id 可对上,用于关联请求级证据。不进 prompt/摘要/持久化。
|
|
18987
|
+
requestId: compactionAttemptId,
|
|
18988
|
+
// Room for factual handoff, exact commands and file operations.
|
|
18989
|
+
max_tokens: 8192,
|
|
18990
|
+
reasoning_effort: "low"
|
|
18991
|
+
}
|
|
18806
18992
|
).then(
|
|
18807
18993
|
(value) => ({ kind: "done", value }),
|
|
18808
18994
|
(error) => ({ kind: "provider-error", error })
|
|
18809
18995
|
);
|
|
18810
18996
|
const guards = [];
|
|
18811
|
-
if (timeoutMs) guards.push(new Promise((
|
|
18997
|
+
if (timeoutMs) guards.push(new Promise((resolve6) => {
|
|
18812
18998
|
timeoutHandle = setTimeout(() => {
|
|
18813
18999
|
requestController.abort();
|
|
18814
|
-
|
|
19000
|
+
resolve6({ kind: "timeout" });
|
|
18815
19001
|
}, timeoutMs);
|
|
18816
19002
|
}));
|
|
18817
|
-
if (args2.abortSignal) guards.push(new Promise((
|
|
19003
|
+
if (args2.abortSignal) guards.push(new Promise((resolve6) => {
|
|
18818
19004
|
abortListener = () => {
|
|
18819
19005
|
requestController.abort(args2.abortSignal?.reason);
|
|
18820
|
-
|
|
19006
|
+
resolve6({ kind: "aborted" });
|
|
18821
19007
|
};
|
|
18822
19008
|
args2.abortSignal?.addEventListener("abort", abortListener, { once: true });
|
|
19009
|
+
if (args2.abortSignal?.aborted) abortListener();
|
|
18823
19010
|
}));
|
|
18824
19011
|
const outcome = guards.length ? await Promise.race([request3, ...guards]) : await request3;
|
|
19012
|
+
primaryElapsedMs = Date.now() - compactionT0;
|
|
18825
19013
|
if (timeoutHandle) clearTimeout(timeoutHandle);
|
|
18826
19014
|
if (abortListener) args2.abortSignal?.removeEventListener("abort", abortListener);
|
|
18827
|
-
|
|
18828
|
-
|
|
18829
|
-
|
|
18830
|
-
|
|
19015
|
+
const result4 = outcome.kind === "done" ? outcome.value : void 0;
|
|
19016
|
+
let newSummary = result4?.finish_reason !== "length" && typeof result4?.content === "string" ? result4.content.trim() : "";
|
|
19017
|
+
const primaryFailure = outcome.kind === "aborted" || args2.abortSignal?.aborted ? "aborted" : newSummary ? null : outcome.kind === "done" ? "provider-error" : outcome.kind;
|
|
19018
|
+
if (primaryFailure === "aborted") {
|
|
19019
|
+
throw Object.assign(new Error("auto-compaction aborted"), {
|
|
19020
|
+
compactionReason: "aborted"
|
|
19021
|
+
});
|
|
18831
19022
|
}
|
|
18832
|
-
const
|
|
18833
|
-
|
|
18834
|
-
|
|
18835
|
-
|
|
18836
|
-
|
|
18837
|
-
|
|
18838
|
-
|
|
18839
|
-
|
|
18840
|
-
|
|
18841
|
-
|
|
18842
|
-
failureMessage: "summary model returned empty content",
|
|
18843
|
-
failureReason,
|
|
18844
|
-
decision: {
|
|
18845
|
-
outcome: "failed",
|
|
18846
|
-
reason: failureReason,
|
|
18847
|
-
detail: "summary model returned empty content"
|
|
19023
|
+
const summaryFallback = args2.summaryFallback;
|
|
19024
|
+
if (primaryFailure && summaryFallback) {
|
|
19025
|
+
const fallbackT0 = Date.now();
|
|
19026
|
+
const fallbackSummary = await runSummaryFallback(
|
|
19027
|
+
summaryFallback,
|
|
19028
|
+
promptContent,
|
|
19029
|
+
{
|
|
19030
|
+
signal: args2.abortSignal,
|
|
19031
|
+
deadlineMs: Date.now() + 3e4,
|
|
19032
|
+
attemptId: compactionAttemptId
|
|
18848
19033
|
}
|
|
18849
|
-
|
|
19034
|
+
);
|
|
19035
|
+
fallbackElapsedMs = Date.now() - fallbackT0;
|
|
19036
|
+
if (args2.abortSignal?.aborted) {
|
|
19037
|
+
throw Object.assign(new Error("auto-compaction aborted"), {
|
|
19038
|
+
compactionReason: "aborted"
|
|
19039
|
+
});
|
|
19040
|
+
}
|
|
19041
|
+
if (fallbackSummary) newSummary = fallbackSummary;
|
|
19042
|
+
}
|
|
19043
|
+
if (!newSummary) {
|
|
19044
|
+
recordCompactionFailure(dialogId, retryNow);
|
|
19045
|
+
if (outcome.kind === "done") {
|
|
19046
|
+
console.warn(
|
|
19047
|
+
"[localLoop] auto-compaction produced empty summary; keeping prior projection"
|
|
19048
|
+
);
|
|
19049
|
+
logCompactionTiming("empty", {});
|
|
19050
|
+
const failureReason = "provider-error";
|
|
19051
|
+
emitPhase({ kind: "compaction-failed", reason: failureReason });
|
|
19052
|
+
return {
|
|
19053
|
+
...projectExisting(),
|
|
19054
|
+
failureMessage: "summary model returned empty content",
|
|
19055
|
+
failureReason,
|
|
19056
|
+
decision: {
|
|
19057
|
+
outcome: "failed",
|
|
19058
|
+
reason: failureReason,
|
|
19059
|
+
detail: "summary model returned empty content"
|
|
19060
|
+
}
|
|
19061
|
+
};
|
|
19062
|
+
}
|
|
19063
|
+
const reason = primaryFailure ?? "provider-error";
|
|
19064
|
+
const detail = outcome.kind === "provider-error" ? outcome.error instanceof Error ? outcome.error.message : String(outcome.error) : `auto-compaction timed out after ${timeoutMs}ms`;
|
|
19065
|
+
throw Object.assign(new Error(detail), { compactionReason: reason });
|
|
18850
19066
|
}
|
|
19067
|
+
const saveT0 = Date.now();
|
|
18851
19068
|
await adapter.saveDialogSummary({
|
|
18852
19069
|
dialogId,
|
|
18853
19070
|
summary: newSummary,
|
|
@@ -18861,15 +19078,20 @@ async function maybeAutoCompactLocalHistory(args2) {
|
|
|
18861
19078
|
})(),
|
|
18862
19079
|
schemaVersion: COMPACTION_SUMMARY_SCHEMA_VERSION
|
|
18863
19080
|
});
|
|
19081
|
+
saveElapsedMs = Date.now() - saveT0;
|
|
18864
19082
|
const metricsReason = invalidSummary ? "invalid_summary" : coldResume ? "cold_resume" : "context_budget";
|
|
18865
19083
|
const metrics = buildCompactionMetricsFromPlan({
|
|
18866
19084
|
reason: metricsReason,
|
|
18867
19085
|
previousSummary: existingSummary,
|
|
18868
19086
|
plan,
|
|
18869
19087
|
newSummary,
|
|
18870
|
-
summaryUsage: result4
|
|
19088
|
+
summaryUsage: result4?.usage
|
|
18871
19089
|
});
|
|
18872
19090
|
console.log(formatCompactionMetricsLog(metrics));
|
|
19091
|
+
logCompactionTiming("success", {
|
|
19092
|
+
model: result4?.model ?? args2.model ?? null,
|
|
19093
|
+
outputChars: newSummary.length
|
|
19094
|
+
});
|
|
18873
19095
|
emitPhase({ kind: "compaction-end" });
|
|
18874
19096
|
return {
|
|
18875
19097
|
history: projectHistoryWithSummary({
|
|
@@ -18882,7 +19104,7 @@ async function maybeAutoCompactLocalHistory(args2) {
|
|
|
18882
19104
|
reason: metricsReason,
|
|
18883
19105
|
beforeTokens: metrics.previousSummaryTokens + metrics.compressedTokens,
|
|
18884
19106
|
afterTokens: metrics.newSummaryTokens + metrics.retainedTokens,
|
|
18885
|
-
...result4
|
|
19107
|
+
...result4?.usage ? { usage: result4.usage } : {},
|
|
18886
19108
|
metrics,
|
|
18887
19109
|
decision: {
|
|
18888
19110
|
outcome: "compressed",
|
|
@@ -18899,6 +19121,8 @@ async function maybeAutoCompactLocalHistory(args2) {
|
|
|
18899
19121
|
console.warn("[localLoop] auto-compaction failed:", error);
|
|
18900
19122
|
const failureMessage = error instanceof Error && error.message ? error.message.slice(0, 200) : String(error).slice(0, 200);
|
|
18901
19123
|
const failureReason = error instanceof Error && "compactionReason" in error ? error.compactionReason : "provider-error";
|
|
19124
|
+
logCompactionTiming(failureReason, {});
|
|
19125
|
+
if (failureReason !== "aborted") recordCompactionFailure(dialogId, retryNow);
|
|
18902
19126
|
emitPhase({ kind: "compaction-failed", reason: failureReason });
|
|
18903
19127
|
return {
|
|
18904
19128
|
...projectExisting(),
|
|
@@ -18985,6 +19209,7 @@ function createTurnCompactionController(args2) {
|
|
|
18985
19209
|
realContextUsagePercent,
|
|
18986
19210
|
abortSignal: args2.abortSignal,
|
|
18987
19211
|
timeoutMs: args2.timeoutMs,
|
|
19212
|
+
summaryFallback: args2.summaryFallback,
|
|
18988
19213
|
onPhase: (phase) => emitPhase(phase, "initial")
|
|
18989
19214
|
});
|
|
18990
19215
|
emitObservation(compacted);
|
|
@@ -19017,6 +19242,7 @@ function createTurnCompactionController(args2) {
|
|
|
19017
19242
|
...ratio !== void 0 ? { realContextUsagePercent: ratio } : {},
|
|
19018
19243
|
abortSignal: args2.abortSignal,
|
|
19019
19244
|
timeoutMs: args2.timeoutMs,
|
|
19245
|
+
summaryFallback: args2.summaryFallback,
|
|
19020
19246
|
onPhase: (phase) => emitPhase(phase, "in-loop")
|
|
19021
19247
|
});
|
|
19022
19248
|
if (compacted.usage) {
|
|
@@ -19029,8 +19255,9 @@ function createTurnCompactionController(args2) {
|
|
|
19029
19255
|
contextReferenceResolver: args2.contextReferenceResolver
|
|
19030
19256
|
});
|
|
19031
19257
|
if (rebuilt.downgraded > 0) {
|
|
19258
|
+
const stats = rebuilt.stats;
|
|
19032
19259
|
console.warn(
|
|
19033
|
-
`[nolo]
|
|
19260
|
+
`[nolo] rewrote ${stats.rewrittenToolCalls} tool calls in ${stats.rewrittenAssistantMessages} assistant messages and ${stats.rewrittenToolMessages} tool-result messages after compaction (bad arguments: truncated=${stats.badArguments.truncated}, malformed=${stats.badArguments.malformed}); persisted history untouched`
|
|
19034
19261
|
);
|
|
19035
19262
|
}
|
|
19036
19263
|
args2.replaceWorkingView(rebuilt.messages);
|
|
@@ -19043,11 +19270,132 @@ function createTurnCompactionController(args2) {
|
|
|
19043
19270
|
return { runInitial, maybeCompactInLoop };
|
|
19044
19271
|
}
|
|
19045
19272
|
|
|
19273
|
+
// packages/agent-runtime/providerCallTelemetry.ts
|
|
19274
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
19275
|
+
var shortHash = (value) => createHash6("sha1").update(value).digest("hex").slice(0, 12);
|
|
19276
|
+
var hashMessage = (message) => {
|
|
19277
|
+
let text2;
|
|
19278
|
+
try {
|
|
19279
|
+
text2 = JSON.stringify(message) ?? "";
|
|
19280
|
+
} catch {
|
|
19281
|
+
text2 = String(message);
|
|
19282
|
+
}
|
|
19283
|
+
return shortHash(text2);
|
|
19284
|
+
};
|
|
19285
|
+
function computeDivergeAt(prev, cur) {
|
|
19286
|
+
const n = Math.min(prev.length, cur.length);
|
|
19287
|
+
for (let i = 0; i < n; i += 1) {
|
|
19288
|
+
if (prev[i] !== cur[i]) return i;
|
|
19289
|
+
}
|
|
19290
|
+
return cur.length >= prev.length ? -1 : n;
|
|
19291
|
+
}
|
|
19292
|
+
var DIVERGE_TRACKER_MAX_DIALOGS = 50;
|
|
19293
|
+
function createDivergeTracker(max4 = DIVERGE_TRACKER_MAX_DIALOGS) {
|
|
19294
|
+
const map8 = /* @__PURE__ */ new Map();
|
|
19295
|
+
return {
|
|
19296
|
+
observe(dialogKey, hashes) {
|
|
19297
|
+
const prev = map8.get(dialogKey);
|
|
19298
|
+
map8.delete(dialogKey);
|
|
19299
|
+
map8.set(dialogKey, hashes);
|
|
19300
|
+
while (map8.size > max4) {
|
|
19301
|
+
const oldest = map8.keys().next().value;
|
|
19302
|
+
if (oldest === void 0) break;
|
|
19303
|
+
map8.delete(oldest);
|
|
19304
|
+
}
|
|
19305
|
+
if (!prev) return { divergeAt: null };
|
|
19306
|
+
return { divergeAt: computeDivergeAt(prev, hashes), prevMsgCount: prev.length };
|
|
19307
|
+
},
|
|
19308
|
+
size: () => map8.size
|
|
19309
|
+
};
|
|
19310
|
+
}
|
|
19311
|
+
var processDivergeTracker = createDivergeTracker();
|
|
19312
|
+
function buildRequestTelemetry(args2) {
|
|
19313
|
+
try {
|
|
19314
|
+
const hashes = args2.messages.map(hashMessage);
|
|
19315
|
+
let toolResultChars = 0;
|
|
19316
|
+
let toolResultCount = 0;
|
|
19317
|
+
let contentChars = 0;
|
|
19318
|
+
for (const m of args2.messages) {
|
|
19319
|
+
const chars = contentCharCount(m.content);
|
|
19320
|
+
contentChars += chars;
|
|
19321
|
+
if (m.role === "tool") {
|
|
19322
|
+
toolResultChars += chars;
|
|
19323
|
+
toolResultCount += 1;
|
|
19324
|
+
}
|
|
19325
|
+
}
|
|
19326
|
+
const diverge = (args2.tracker ?? processDivergeTracker).observe(args2.dialogKey, hashes);
|
|
19327
|
+
return {
|
|
19328
|
+
...args2.toolsHash ? { toolsHash: args2.toolsHash } : {},
|
|
19329
|
+
msgCount: args2.messages.length,
|
|
19330
|
+
contentChars,
|
|
19331
|
+
toolResultChars,
|
|
19332
|
+
toolResultCount,
|
|
19333
|
+
...diverge
|
|
19334
|
+
};
|
|
19335
|
+
} catch {
|
|
19336
|
+
return void 0;
|
|
19337
|
+
}
|
|
19338
|
+
}
|
|
19339
|
+
function hashToolDefinitions(tools) {
|
|
19340
|
+
try {
|
|
19341
|
+
return shortHash(JSON.stringify(tools));
|
|
19342
|
+
} catch {
|
|
19343
|
+
return void 0;
|
|
19344
|
+
}
|
|
19345
|
+
}
|
|
19346
|
+
|
|
19046
19347
|
// packages/agent-runtime/localLoop.ts
|
|
19047
19348
|
var LOCAL_AGENT_CONFIG_MISSING_CODE = "LOCAL_AGENT_CONFIG_MISSING";
|
|
19048
19349
|
var LLM_REQUEST_TIMEOUT = "LLM_REQUEST_TIMEOUT";
|
|
19049
19350
|
var DEFAULT_LLM_REQUEST_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
19050
19351
|
var DEFAULT_COMPACTION_TIMEOUT_MS = 60 * 1e3;
|
|
19352
|
+
var DEFAULT_ROUND_BUDGET_WARNING_THRESHOLD = 25;
|
|
19353
|
+
function buildRoundBudgetWarningPrompt(threshold) {
|
|
19354
|
+
return `[\u7CFB\u7EDF\u63D0\u793A] \u5F53\u524D\u5355\u6B21\u4EFB\u52A1\u7684\u8FDE\u7EED\u5DE5\u5177\u8C03\u7528\u5DF2\u8FBE ${threshold} \u8F6E\u3002\u4E3A\u9632\u6B62\u4E0A\u4E0B\u6587\u590D\u5408\u81A8\u80C0\u4E0E\u6210\u672C\u5931\u63A7\uFF0C\u8BF7\u5728\u672C\u8F6E\u6216\u4E0B\u4E00\u8F6E\u5185\u6536\u655B\u5F53\u524D\u6267\u884C\u7ED3\u679C\uFF0C\u8F93\u51FA\u5DF2\u9A8C\u8BC1\u4E8B\u5B9E\u3001\u9636\u6BB5\u6027\u7ED3\u8BBA\u6216\u5F53\u524D\u5361\u70B9\uFF0C\u5B8C\u6210\u9636\u6BB5\u4EA4\u63A5\u3002`;
|
|
19355
|
+
}
|
|
19356
|
+
var CONCURRENT_READONLY_TOOLS = /* @__PURE__ */ new Set([
|
|
19357
|
+
"readFile",
|
|
19358
|
+
"read_file",
|
|
19359
|
+
"readWorkspaceFile",
|
|
19360
|
+
"globFiles",
|
|
19361
|
+
"readDoc",
|
|
19362
|
+
"readSkillDoc",
|
|
19363
|
+
"listSpaces",
|
|
19364
|
+
"readSpace",
|
|
19365
|
+
"listTables",
|
|
19366
|
+
"queryTableRows",
|
|
19367
|
+
"listDialogs",
|
|
19368
|
+
"readDialog",
|
|
19369
|
+
"queryDialogsBySubjectRef",
|
|
19370
|
+
"listAgents",
|
|
19371
|
+
"readAgent",
|
|
19372
|
+
"cliWhoami",
|
|
19373
|
+
"cliDoctor",
|
|
19374
|
+
"listProcesses",
|
|
19375
|
+
"fetchWebpage",
|
|
19376
|
+
"exa_search"
|
|
19377
|
+
]);
|
|
19378
|
+
function partitionToolCallsIntoBatches(toolCalls) {
|
|
19379
|
+
const batches = [];
|
|
19380
|
+
let currentReadBatch = [];
|
|
19381
|
+
for (let i = 0; i < toolCalls.length; i += 1) {
|
|
19382
|
+
const toolCall = toolCalls[i];
|
|
19383
|
+
const isReadOnly = CONCURRENT_READONLY_TOOLS.has(toolCall.function.name);
|
|
19384
|
+
if (isReadOnly) {
|
|
19385
|
+
currentReadBatch.push({ index: i, toolCall });
|
|
19386
|
+
} else {
|
|
19387
|
+
if (currentReadBatch.length > 0) {
|
|
19388
|
+
batches.push({ isConcurrent: true, calls: currentReadBatch });
|
|
19389
|
+
currentReadBatch = [];
|
|
19390
|
+
}
|
|
19391
|
+
batches.push({ isConcurrent: false, calls: [{ index: i, toolCall }] });
|
|
19392
|
+
}
|
|
19393
|
+
}
|
|
19394
|
+
if (currentReadBatch.length > 0) {
|
|
19395
|
+
batches.push({ isConcurrent: true, calls: currentReadBatch });
|
|
19396
|
+
}
|
|
19397
|
+
return batches;
|
|
19398
|
+
}
|
|
19051
19399
|
function resolveLlmRequestTimeoutMs(input) {
|
|
19052
19400
|
const raw = input.llmRequestTimeoutMs ?? input.timeoutMs;
|
|
19053
19401
|
return typeof raw === "number" && Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_LLM_REQUEST_TIMEOUT_MS;
|
|
@@ -19056,6 +19404,10 @@ function resolveCompactionTimeoutMs(input) {
|
|
|
19056
19404
|
const raw = input.compactionTimeoutMs;
|
|
19057
19405
|
return typeof raw === "number" && Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_COMPACTION_TIMEOUT_MS;
|
|
19058
19406
|
}
|
|
19407
|
+
function readHostCompactionSummaryFallback(adapter) {
|
|
19408
|
+
const value = adapter.compactionSummaryFallback;
|
|
19409
|
+
return typeof value === "function" ? value : void 0;
|
|
19410
|
+
}
|
|
19059
19411
|
async function runCompleteWithTimeout(args2) {
|
|
19060
19412
|
const { provider, messages, options, timeoutMs, round, input, boundary, context: context3, providerName, model } = args2;
|
|
19061
19413
|
emitLoopEvent(boundary, {
|
|
@@ -19137,6 +19489,30 @@ function extractUserInputText(content) {
|
|
|
19137
19489
|
if (!Array.isArray(content)) return "";
|
|
19138
19490
|
return content.flatMap((part) => part?.type === "text" && part.text ? [part.text] : []).join("\n").trim();
|
|
19139
19491
|
}
|
|
19492
|
+
function safeToolNamesHash(names) {
|
|
19493
|
+
try {
|
|
19494
|
+
return names.length ? shortHash([...names].sort().join(",")) : void 0;
|
|
19495
|
+
} catch {
|
|
19496
|
+
return void 0;
|
|
19497
|
+
}
|
|
19498
|
+
}
|
|
19499
|
+
function finalizeCallTelemetry(base, result4, round, startedAt) {
|
|
19500
|
+
try {
|
|
19501
|
+
const endTs = Date.now();
|
|
19502
|
+
const toolCalls = (result4.tool_calls ?? []).map((call) => call?.function?.name ?? call?.name).filter((name) => typeof name === "string");
|
|
19503
|
+
const providerToolsHash = result4.toolsHash;
|
|
19504
|
+
return {
|
|
19505
|
+
...base,
|
|
19506
|
+
...typeof providerToolsHash === "string" ? { toolsHash: providerToolsHash } : {},
|
|
19507
|
+
round,
|
|
19508
|
+
endTs,
|
|
19509
|
+
durationMs: endTs - startedAt,
|
|
19510
|
+
...toolCalls.length ? { toolCalls } : {}
|
|
19511
|
+
};
|
|
19512
|
+
} catch {
|
|
19513
|
+
return void 0;
|
|
19514
|
+
}
|
|
19515
|
+
}
|
|
19140
19516
|
function attachDialogIdToError(error, dialogId) {
|
|
19141
19517
|
if (!dialogId) return;
|
|
19142
19518
|
if (typeof error === "object" && error !== null) {
|
|
@@ -19171,13 +19547,20 @@ async function persistFailedLocalTurn(args2) {
|
|
|
19171
19547
|
...args2.input.spaceId ? { spaceId: args2.input.spaceId } : {},
|
|
19172
19548
|
...args2.input.category ? { category: args2.input.category } : {},
|
|
19173
19549
|
...args2.input.inheritedFromDialogKey ? { inheritedFromDialogKey: args2.input.inheritedFromDialogKey } : {},
|
|
19174
|
-
...args2.input.parentDialogId ? { parentDialogId: args2.input.parentDialogId } : {}
|
|
19550
|
+
...args2.input.parentDialogId ? { parentDialogId: args2.input.parentDialogId } : {},
|
|
19551
|
+
...typeof args2.input.freshDialog === "boolean" ? { freshDialog: args2.input.freshDialog } : {}
|
|
19175
19552
|
});
|
|
19176
19553
|
return saved?.dialogId;
|
|
19177
19554
|
} catch {
|
|
19178
19555
|
return args2.input.continueDialogId;
|
|
19179
19556
|
}
|
|
19180
19557
|
}
|
|
19558
|
+
async function loadAdapterDialogHistory(adapter, dialogId, strictContinueHistory) {
|
|
19559
|
+
if (adapter.loadDialogHistoryWithSource) {
|
|
19560
|
+
return await adapter.loadDialogHistoryWithSource(dialogId, { strictContinueHistory });
|
|
19561
|
+
}
|
|
19562
|
+
return { messages: await adapter.loadDialogHistory(dialogId) };
|
|
19563
|
+
}
|
|
19181
19564
|
async function runLocalAgentTurn(input) {
|
|
19182
19565
|
const legacyCallbacks = {
|
|
19183
19566
|
onLoopEvent: input.onLoopEvent,
|
|
@@ -19261,9 +19644,22 @@ async function runLocalAgentTurn(input) {
|
|
|
19261
19644
|
let sanitizedInput = await sanitizeInbound(input.input);
|
|
19262
19645
|
let sanitizedPersistedInput = input.persistedInput === void 0 ? void 0 : await sanitizeInbound(input.persistedInput);
|
|
19263
19646
|
let history = [];
|
|
19647
|
+
let dialogHistorySource;
|
|
19264
19648
|
try {
|
|
19265
|
-
|
|
19649
|
+
if (input.continueDialogId) {
|
|
19650
|
+
const loaded = await loadAdapterDialogHistory(
|
|
19651
|
+
input.adapter,
|
|
19652
|
+
input.continueDialogId,
|
|
19653
|
+
input.strictContinueHistory
|
|
19654
|
+
);
|
|
19655
|
+
if (input.strictContinueHistory && (loaded.source === "none" || loaded.source === "partial")) {
|
|
19656
|
+
throw new Error(`Strict continuation history unavailable: ${loaded.source}`);
|
|
19657
|
+
}
|
|
19658
|
+
history = loaded.messages;
|
|
19659
|
+
dialogHistorySource = loaded.source;
|
|
19660
|
+
}
|
|
19266
19661
|
} catch (error) {
|
|
19662
|
+
if (input.strictContinueHistory) throw error;
|
|
19267
19663
|
const dialogId = await persistFailedLocalTurn({
|
|
19268
19664
|
adapter: input.adapter,
|
|
19269
19665
|
agentKey: agentConfig.key,
|
|
@@ -19276,6 +19672,15 @@ async function runLocalAgentTurn(input) {
|
|
|
19276
19672
|
throw error;
|
|
19277
19673
|
}
|
|
19278
19674
|
loopTiming.mark("loadDialogHistory", 0);
|
|
19675
|
+
if (input.continueDialogId && history.length === 0 && dialogHistorySource === "none") {
|
|
19676
|
+
console.warn(
|
|
19677
|
+
`[localLoop] dialog history unavailable for ${input.continueDialogId} (source: none); continuing without prior context.`
|
|
19678
|
+
);
|
|
19679
|
+
} else if (input.continueDialogId && dialogHistorySource === "partial") {
|
|
19680
|
+
console.warn(
|
|
19681
|
+
`[localLoop] dialog history incomplete for ${input.continueDialogId} (source: partial); only ${history.length} message(s) available, earlier context may be missing.`
|
|
19682
|
+
);
|
|
19683
|
+
}
|
|
19279
19684
|
const canonicalHistory = history;
|
|
19280
19685
|
const identityBlock = buildIdentityBlock({
|
|
19281
19686
|
agentName: agentConfig.name,
|
|
@@ -19312,6 +19717,11 @@ async function runLocalAgentTurn(input) {
|
|
|
19312
19717
|
// 删除安全红线:系统层最高优先级约束,位于所有块之前(含身份信息块),
|
|
19313
19718
|
// owner 要求常驻「根本提示词」的最顶部(2026-09-26 批量误删事故)。
|
|
19314
19719
|
{ content: DELETE_SAFETY_RED_LINE, cacheScope: "session" },
|
|
19720
|
+
// 并行是默认:系统层固定块,紧随红线(localLoop 无 static 作用域,用 session 占位,
|
|
19721
|
+
// 「最顶」由数组首位保证——与红线同一约定)。
|
|
19722
|
+
{ content: PARALLEL_DISPATCH_DEFAULT_RULE, cacheScope: "session" },
|
|
19723
|
+
// 平台风控纪律:无条件系统层块,沿用 session 占位约定。
|
|
19724
|
+
{ content: PLATFORM_RISK_CONTROL_RULE, cacheScope: "session" },
|
|
19315
19725
|
{ content: identityBlock, cacheScope: "session" },
|
|
19316
19726
|
...guidanceScopes,
|
|
19317
19727
|
...callerScopes
|
|
@@ -19335,6 +19745,11 @@ async function runLocalAgentTurn(input) {
|
|
|
19335
19745
|
compressionTriggerRatio,
|
|
19336
19746
|
abortSignal: input.abortSignal,
|
|
19337
19747
|
timeoutMs: resolveCompactionTimeoutMs(input),
|
|
19748
|
+
// 摘要 fallback:优先显式入参;否则读 host adapter 的会话级注入(CLI 本地
|
|
19749
|
+
// adapter 专有字段,见 localRuntimeAdapter.setCliAutoCompactionSummaryFallback)。
|
|
19750
|
+
// desktop/其他 host 不带该字段 → undefined → 自动压缩行为与注入前完全一致,
|
|
19751
|
+
// 绝不在这里新建第二条摘要通道。
|
|
19752
|
+
summaryFallback: input.compactionSummaryFallback ?? readHostCompactionSummaryFallback(input.adapter),
|
|
19338
19753
|
boundary: observationBoundary,
|
|
19339
19754
|
getContextUsage: () => usageLedger.lastContextUsage(),
|
|
19340
19755
|
getCanonicalCompactionHistory: () => [
|
|
@@ -19368,8 +19783,9 @@ async function runLocalAgentTurn(input) {
|
|
|
19368
19783
|
let messages = builtMessages.messages;
|
|
19369
19784
|
loopTiming.mark("buildMessages", 0);
|
|
19370
19785
|
if (builtMessages.poisonDowngraded > 0) {
|
|
19786
|
+
const stats = builtMessages.poisonStats;
|
|
19371
19787
|
console.warn(
|
|
19372
|
-
`[nolo]
|
|
19788
|
+
`[nolo] rewrote ${stats.rewrittenToolCalls} tool calls in ${stats.rewrittenAssistantMessages} assistant messages and ${stats.rewrittenToolMessages} tool-result messages (bad arguments: truncated=${stats.badArguments.truncated}, malformed=${stats.badArguments.malformed}); persisted history untouched`
|
|
19373
19789
|
);
|
|
19374
19790
|
}
|
|
19375
19791
|
const supportsImages = resolveAgentImageInputSupport({
|
|
@@ -19429,19 +19845,27 @@ async function runLocalAgentTurn(input) {
|
|
|
19429
19845
|
return false;
|
|
19430
19846
|
}
|
|
19431
19847
|
let injected = false;
|
|
19432
|
-
for (const
|
|
19433
|
-
if (typeof
|
|
19434
|
-
const safeText = scrubSecrets(
|
|
19848
|
+
for (const text2 of pending) {
|
|
19849
|
+
if (typeof text2 !== "string" || !text2.trim()) continue;
|
|
19850
|
+
const safeText = scrubSecrets(text2).cleaned;
|
|
19435
19851
|
transcript.push({ role: "user", content: safeText });
|
|
19436
19852
|
injected = true;
|
|
19437
19853
|
}
|
|
19438
19854
|
return injected;
|
|
19439
19855
|
};
|
|
19856
|
+
const newDialogTelemetryKey = `new:${crypto.randomUUID()}`;
|
|
19857
|
+
let roundBudgetWarningInjected = false;
|
|
19858
|
+
const roundWarningThreshold = input.roundBudgetWarningThreshold ?? DEFAULT_ROUND_BUDGET_WARNING_THRESHOLD;
|
|
19440
19859
|
while (true) {
|
|
19441
19860
|
partialContent = "";
|
|
19442
19861
|
throwIfAborted(input);
|
|
19443
19862
|
loopTiming.mark("roundStart", round);
|
|
19444
19863
|
applyPendingInjections();
|
|
19864
|
+
if (roundWarningThreshold > 0 && round >= roundWarningThreshold && !roundBudgetWarningInjected) {
|
|
19865
|
+
const prompt = buildRoundBudgetWarningPrompt(roundWarningThreshold);
|
|
19866
|
+
transcript.push({ role: "user", content: prompt });
|
|
19867
|
+
roundBudgetWarningInjected = true;
|
|
19868
|
+
}
|
|
19445
19869
|
const preparedMessages = prepareMessagesForProviderCall(transcript.working());
|
|
19446
19870
|
const baseRequestMessages = filterImagePartsFromMessages(
|
|
19447
19871
|
preparedMessages.messages,
|
|
@@ -19470,6 +19894,13 @@ async function runLocalAgentTurn(input) {
|
|
|
19470
19894
|
input.onToolEvent || input.onObservationEvent || input.observationBoundary
|
|
19471
19895
|
);
|
|
19472
19896
|
let llmStreamActivity = 0;
|
|
19897
|
+
const callStartedAt = Date.now();
|
|
19898
|
+
const requestTelemetry = buildRequestTelemetry({
|
|
19899
|
+
// 无 dialogId 的新对话用本 turn 唯一键,避免不同新对话共用一个槽误报漂移。
|
|
19900
|
+
dialogKey: input.continueDialogId || newDialogTelemetryKey,
|
|
19901
|
+
messages: requestMessages,
|
|
19902
|
+
toolsHash: safeToolNamesHash(agentTools)
|
|
19903
|
+
});
|
|
19473
19904
|
result4 = await runCompleteWithTimeout({
|
|
19474
19905
|
provider,
|
|
19475
19906
|
messages: requestMessages,
|
|
@@ -19525,7 +19956,8 @@ async function runLocalAgentTurn(input) {
|
|
|
19525
19956
|
usageLedger.recordProviderCall({
|
|
19526
19957
|
usage: result4.usage,
|
|
19527
19958
|
model: result4.model,
|
|
19528
|
-
provider: result4.provider
|
|
19959
|
+
provider: result4.provider,
|
|
19960
|
+
telemetry: finalizeCallTelemetry(requestTelemetry, result4, round, callStartedAt)
|
|
19529
19961
|
});
|
|
19530
19962
|
const assistantGuardVerdict = progressGuard.observeAssistantResponse(result4);
|
|
19531
19963
|
if (assistantGuardVerdict.action === "stall") {
|
|
@@ -19654,8 +20086,9 @@ ${reasoningTailLog}
|
|
|
19654
20086
|
});
|
|
19655
20087
|
const executedToolResults = [];
|
|
19656
20088
|
loopTiming.mark("toolLoopStart", round);
|
|
19657
|
-
|
|
19658
|
-
|
|
20089
|
+
const slotResults = new Array(toolCalls.length);
|
|
20090
|
+
const runSingleTool = async ({ index, toolCall }) => {
|
|
20091
|
+
throwIfAborted(input);
|
|
19659
20092
|
const { toolResult, toolExecMs } = await executeToolCall({
|
|
19660
20093
|
input,
|
|
19661
20094
|
toolCall,
|
|
@@ -19670,6 +20103,17 @@ ${reasoningTailLog}
|
|
|
19670
20103
|
...result4.finish_reason ? { finishReason: result4.finish_reason } : {}
|
|
19671
20104
|
}
|
|
19672
20105
|
});
|
|
20106
|
+
slotResults[index] = {
|
|
20107
|
+
toolName: toolCall.function.name,
|
|
20108
|
+
toolResult,
|
|
20109
|
+
toolExecMs
|
|
20110
|
+
};
|
|
20111
|
+
};
|
|
20112
|
+
const commitSlot = (i) => {
|
|
20113
|
+
const toolCall = toolCalls[i];
|
|
20114
|
+
const slot = slotResults[i];
|
|
20115
|
+
if (!slot) return;
|
|
20116
|
+
const { toolName, toolResult, toolExecMs } = slot;
|
|
19673
20117
|
const observedMetadata = toolExecMs === void 0 ? toolResult.metadata : { ...toolResult.metadata ?? {}, [TOOL_DURATION_METADATA_KEY]: toolExecMs };
|
|
19674
20118
|
executedToolResults.push({
|
|
19675
20119
|
toolName,
|
|
@@ -19688,6 +20132,29 @@ ${reasoningTailLog}
|
|
|
19688
20132
|
toolName,
|
|
19689
20133
|
...observedMetadata ? { tool_result_metadata: observedMetadata } : {}
|
|
19690
20134
|
});
|
|
20135
|
+
};
|
|
20136
|
+
const batches = partitionToolCallsIntoBatches(toolCalls);
|
|
20137
|
+
for (const batch of batches) {
|
|
20138
|
+
throwIfAborted(input);
|
|
20139
|
+
let batchError;
|
|
20140
|
+
try {
|
|
20141
|
+
if (batch.isConcurrent && batch.calls.length > 1) {
|
|
20142
|
+
await Promise.all(batch.calls.map(runSingleTool));
|
|
20143
|
+
} else {
|
|
20144
|
+
for (const call of batch.calls) {
|
|
20145
|
+
await runSingleTool(call);
|
|
20146
|
+
}
|
|
20147
|
+
}
|
|
20148
|
+
} catch (error) {
|
|
20149
|
+
batchError = error;
|
|
20150
|
+
} finally {
|
|
20151
|
+
for (const call of batch.calls) {
|
|
20152
|
+
if (slotResults[call.index]) {
|
|
20153
|
+
commitSlot(call.index);
|
|
20154
|
+
}
|
|
20155
|
+
}
|
|
20156
|
+
}
|
|
20157
|
+
if (batchError) throw batchError;
|
|
19691
20158
|
}
|
|
19692
20159
|
const toolExecutionGuardVerdict = progressGuard.observeToolExecution(
|
|
19693
20160
|
toolCalls,
|
|
@@ -19779,7 +20246,8 @@ ${reasoningTailLog}
|
|
|
19779
20246
|
...input.spaceId ? { spaceId: input.spaceId } : {},
|
|
19780
20247
|
...input.category ? { category: input.category } : {},
|
|
19781
20248
|
...input.inheritedFromDialogKey ? { inheritedFromDialogKey: input.inheritedFromDialogKey } : {},
|
|
19782
|
-
...input.parentDialogId ? { parentDialogId: input.parentDialogId } : {}
|
|
20249
|
+
...input.parentDialogId ? { parentDialogId: input.parentDialogId } : {},
|
|
20250
|
+
...typeof input.freshDialog === "boolean" ? { freshDialog: input.freshDialog } : {}
|
|
19783
20251
|
});
|
|
19784
20252
|
loopTiming.mark("saveTurn", round);
|
|
19785
20253
|
await loopTiming.flush();
|
|
@@ -19794,6 +20262,7 @@ ${reasoningTailLog}
|
|
|
19794
20262
|
dialogId: saved.dialogId,
|
|
19795
20263
|
title: saved.title,
|
|
19796
20264
|
...saved.titlePatchPromise ? { titlePatchPromise: saved.titlePatchPromise } : {},
|
|
20265
|
+
...dialogHistorySource ? { dialogHistorySource } : {},
|
|
19797
20266
|
turnMessages
|
|
19798
20267
|
};
|
|
19799
20268
|
} finally {
|
|
@@ -19845,6 +20314,18 @@ function responsesStreamFailureStatus(failure) {
|
|
|
19845
20314
|
return 502;
|
|
19846
20315
|
}
|
|
19847
20316
|
var codexStreamFailureStatus = responsesStreamFailureStatus;
|
|
20317
|
+
function extractOutputTextFromItem(item) {
|
|
20318
|
+
const parts2 = item.content;
|
|
20319
|
+
if (!Array.isArray(parts2)) return "";
|
|
20320
|
+
return parts2.filter(
|
|
20321
|
+
(part) => !!part && typeof part === "object" && part.type === "output_text" && typeof part.text === "string"
|
|
20322
|
+
).map((part) => String(part.text)).join("");
|
|
20323
|
+
}
|
|
20324
|
+
function hasNumericTokenCount(u) {
|
|
20325
|
+
return ["input_tokens", "output_tokens", "prompt_tokens", "completion_tokens", "total_tokens"].some(
|
|
20326
|
+
(key) => typeof u[key] === "number" && Number.isFinite(u[key])
|
|
20327
|
+
);
|
|
20328
|
+
}
|
|
19848
20329
|
function createResponsesStreamCollector(callbacks) {
|
|
19849
20330
|
let content = "";
|
|
19850
20331
|
let reasoning = "";
|
|
@@ -19852,6 +20333,11 @@ function createResponsesStreamCollector(callbacks) {
|
|
|
19852
20333
|
let usage;
|
|
19853
20334
|
let failure;
|
|
19854
20335
|
let completedResponse;
|
|
20336
|
+
const requireResponseCompleted = callbacks?.requireResponseCompleted === true;
|
|
20337
|
+
const authoritativeCompletedTools = callbacks?.authoritativeCompletedTools === true;
|
|
20338
|
+
const failurePrefix = callbacks?.fallbackPrefix ?? "Responses";
|
|
20339
|
+
let sawTerminalSuccess = false;
|
|
20340
|
+
let sawTerminalEvent = false;
|
|
19855
20341
|
let sawMeaningfulDelta = false;
|
|
19856
20342
|
const observeMeaningfulOnce = () => {
|
|
19857
20343
|
if (sawMeaningfulDelta) return;
|
|
@@ -19859,18 +20345,38 @@ function createResponsesStreamCollector(callbacks) {
|
|
|
19859
20345
|
callbacks?.onMeaningfulDelta?.();
|
|
19860
20346
|
};
|
|
19861
20347
|
const processEvent = (ev) => {
|
|
20348
|
+
callbacks?.onEvent?.(ev);
|
|
19862
20349
|
if (isMeaningfulResponsesOutput(ev)) observeMeaningfulOnce();
|
|
19863
20350
|
const type = String(ev.type ?? "");
|
|
19864
20351
|
if (type === "error") {
|
|
19865
|
-
|
|
20352
|
+
sawTerminalEvent = true;
|
|
20353
|
+
failure = failure ?? toResponsesStreamFailure(ev.error, callbacks?.fallbackPrefix) ?? {
|
|
20354
|
+
code: "response_error",
|
|
20355
|
+
message: `${callbacks?.fallbackPrefix ?? "Responses"} upstream emitted an error event.`
|
|
20356
|
+
};
|
|
19866
20357
|
return;
|
|
19867
20358
|
}
|
|
19868
20359
|
if (type === "response.failed" || type === "response.incomplete") {
|
|
20360
|
+
sawTerminalEvent = true;
|
|
19869
20361
|
const response = ev.response;
|
|
19870
20362
|
failure = failure ?? toResponsesStreamFailure(response?.error, callbacks?.fallbackPrefix) ?? toResponsesStreamFailure(response?.incomplete_details, callbacks?.fallbackPrefix) ?? {
|
|
19871
20363
|
code: type === "response.incomplete" ? "response_incomplete" : "response_failed",
|
|
19872
20364
|
message: `${callbacks?.fallbackPrefix ?? "Responses"} upstream ended with ${type}.`
|
|
19873
20365
|
};
|
|
20366
|
+
{
|
|
20367
|
+
const u = response?.usage;
|
|
20368
|
+
if (u && hasNumericTokenCount(u)) {
|
|
20369
|
+
const prompt = typeof u.input_tokens === "number" ? u.input_tokens : typeof u.prompt_tokens === "number" ? u.prompt_tokens : 0;
|
|
20370
|
+
const completion = typeof u.output_tokens === "number" ? u.output_tokens : typeof u.completion_tokens === "number" ? u.completion_tokens : 0;
|
|
20371
|
+
usage = {
|
|
20372
|
+
prompt_tokens: prompt,
|
|
20373
|
+
completion_tokens: completion,
|
|
20374
|
+
total_tokens: typeof u.total_tokens === "number" ? u.total_tokens : prompt + completion,
|
|
20375
|
+
...u.input_tokens_details && typeof u.input_tokens_details === "object" ? { input_tokens_details: u.input_tokens_details } : {},
|
|
20376
|
+
...u.output_tokens_details && typeof u.output_tokens_details === "object" ? { output_tokens_details: u.output_tokens_details } : {}
|
|
20377
|
+
};
|
|
20378
|
+
}
|
|
20379
|
+
}
|
|
19874
20380
|
return;
|
|
19875
20381
|
}
|
|
19876
20382
|
if (type === "response.output_text.delta" && typeof ev.delta === "string") {
|
|
@@ -19883,16 +20389,38 @@ function createResponsesStreamCollector(callbacks) {
|
|
|
19883
20389
|
callbacks?.onReasoningDelta?.(ev.delta);
|
|
19884
20390
|
return;
|
|
19885
20391
|
}
|
|
19886
|
-
if (type === "response.output_item.added" || type === "response.output_item.done"
|
|
20392
|
+
if (type === "response.output_item.added" || type === "response.output_item.done") {
|
|
20393
|
+
const item = ev.item;
|
|
20394
|
+
if (item?.type === "message" && !content) {
|
|
20395
|
+
const itemText = extractOutputTextFromItem(item);
|
|
20396
|
+
if (itemText) {
|
|
20397
|
+
content = itemText;
|
|
20398
|
+
callbacks?.onTextDelta?.(itemText);
|
|
20399
|
+
}
|
|
20400
|
+
}
|
|
20401
|
+
applyResponsesToolEvent(toolCallsAcc, ev);
|
|
20402
|
+
return;
|
|
20403
|
+
}
|
|
20404
|
+
if (type === "response.function_call_arguments.delta" || type === "response.function_call_arguments.done") {
|
|
19887
20405
|
applyResponsesToolEvent(toolCallsAcc, ev);
|
|
19888
20406
|
return;
|
|
19889
20407
|
}
|
|
19890
20408
|
if (type === "response.completed") {
|
|
20409
|
+
sawTerminalEvent = true;
|
|
19891
20410
|
const response = ev.response;
|
|
20411
|
+
const envelopeStatus = response && typeof response.status === "string" ? response.status : void 0;
|
|
20412
|
+
if (requireResponseCompleted && envelopeStatus !== void 0 && envelopeStatus !== "completed") {
|
|
20413
|
+
failure = failure ?? {
|
|
20414
|
+
code: "response_not_completed",
|
|
20415
|
+
message: `${failurePrefix} emitted response.completed with status "${envelopeStatus}".`
|
|
20416
|
+
};
|
|
20417
|
+
return;
|
|
20418
|
+
}
|
|
20419
|
+
sawTerminalSuccess = true;
|
|
19892
20420
|
if (response) {
|
|
19893
20421
|
completedResponse = response;
|
|
19894
20422
|
const u = response.usage;
|
|
19895
|
-
if (u) {
|
|
20423
|
+
if (u && hasNumericTokenCount(u)) {
|
|
19896
20424
|
const prompt = typeof u.input_tokens === "number" ? u.input_tokens : typeof u.prompt_tokens === "number" ? u.prompt_tokens : 0;
|
|
19897
20425
|
const completion = typeof u.output_tokens === "number" ? u.output_tokens : typeof u.completion_tokens === "number" ? u.completion_tokens : 0;
|
|
19898
20426
|
const total = typeof u.total_tokens === "number" ? u.total_tokens : prompt + completion;
|
|
@@ -19913,29 +20441,58 @@ function createResponsesStreamCollector(callbacks) {
|
|
|
19913
20441
|
let finalToolCalls = finalizeResponsesToolCalls(toolCallsAcc);
|
|
19914
20442
|
if (completedResponse) {
|
|
19915
20443
|
const completedToolCalls = extractToolCallsFromResponseOutput(completedResponse);
|
|
19916
|
-
|
|
19917
|
-
|
|
19918
|
-
|
|
19919
|
-
|
|
19920
|
-
|
|
19921
|
-
|
|
19922
|
-
|
|
19923
|
-
|
|
19924
|
-
|
|
19925
|
-
|
|
20444
|
+
if (authoritativeCompletedTools) {
|
|
20445
|
+
for (const call of completedToolCalls) {
|
|
20446
|
+
const name = call.function?.name;
|
|
20447
|
+
if (typeof name !== "string" || !name.trim()) {
|
|
20448
|
+
failure = failure ?? {
|
|
20449
|
+
code: "tool_name_missing",
|
|
20450
|
+
message: `${failurePrefix} response.completed contained a tool call without a name.`
|
|
20451
|
+
};
|
|
20452
|
+
break;
|
|
20453
|
+
}
|
|
20454
|
+
const args2 = call.function?.arguments;
|
|
20455
|
+
if (typeof args2 === "string" && args2.trim()) {
|
|
20456
|
+
try {
|
|
20457
|
+
JSON.parse(args2);
|
|
20458
|
+
} catch {
|
|
20459
|
+
failure = failure ?? {
|
|
20460
|
+
code: "tool_arguments_malformed",
|
|
20461
|
+
message: `${failurePrefix} response.completed contained malformed tool arguments for "${name}".`
|
|
20462
|
+
};
|
|
20463
|
+
break;
|
|
20464
|
+
}
|
|
20465
|
+
}
|
|
19926
20466
|
}
|
|
19927
|
-
|
|
19928
|
-
|
|
19929
|
-
|
|
19930
|
-
|
|
20467
|
+
finalToolCalls = completedToolCalls;
|
|
20468
|
+
} else {
|
|
20469
|
+
const completedById = new Map(completedToolCalls.map((call) => [call.id, call]));
|
|
20470
|
+
finalToolCalls = finalToolCalls.map((call) => {
|
|
20471
|
+
const completed = completedById.get(call.id);
|
|
20472
|
+
if (!completed) return call;
|
|
20473
|
+
let accumulatedParses = false;
|
|
20474
|
+
let completedParses = false;
|
|
20475
|
+
try {
|
|
20476
|
+
JSON.parse(call.function.arguments);
|
|
20477
|
+
accumulatedParses = true;
|
|
20478
|
+
} catch {
|
|
20479
|
+
}
|
|
20480
|
+
try {
|
|
20481
|
+
JSON.parse(completed.function.arguments);
|
|
20482
|
+
completedParses = true;
|
|
20483
|
+
} catch {
|
|
20484
|
+
return call;
|
|
20485
|
+
}
|
|
20486
|
+
if (completedParses && (!accumulatedParses || completed.function.arguments.startsWith(call.function.arguments))) {
|
|
20487
|
+
return { ...call, function: { ...call.function, arguments: completed.function.arguments } };
|
|
20488
|
+
}
|
|
19931
20489
|
return call;
|
|
19932
|
-
}
|
|
19933
|
-
if (
|
|
19934
|
-
|
|
19935
|
-
|
|
19936
|
-
|
|
19937
|
-
|
|
19938
|
-
if (finalToolCalls.length === 0) finalToolCalls = completedToolCalls;
|
|
20490
|
+
});
|
|
20491
|
+
if (finalToolCalls.length === 0) finalToolCalls = completedToolCalls;
|
|
20492
|
+
}
|
|
20493
|
+
}
|
|
20494
|
+
if (authoritativeCompletedTools && failure) {
|
|
20495
|
+
finalToolCalls = [];
|
|
19939
20496
|
}
|
|
19940
20497
|
if (!content && completedResponse) {
|
|
19941
20498
|
content = extractTextFromResponseOutput(completedResponse);
|
|
@@ -19943,35 +20500,42 @@ function createResponsesStreamCollector(callbacks) {
|
|
|
19943
20500
|
if (!reasoning && completedResponse) {
|
|
19944
20501
|
reasoning = extractReasoningFromResponseOutput(completedResponse);
|
|
19945
20502
|
}
|
|
20503
|
+
const streamComplete = sawTerminalSuccess;
|
|
20504
|
+
const streamTruncated = !sawTerminalEvent;
|
|
19946
20505
|
return {
|
|
19947
20506
|
content,
|
|
19948
20507
|
...reasoning ? { reasoning_content: reasoning } : {},
|
|
19949
20508
|
...finalToolCalls.length > 0 ? { tool_calls: finalToolCalls } : {},
|
|
19950
20509
|
...usage ? { usage } : {},
|
|
19951
|
-
finish_reason: finalToolCalls.length > 0 ? "tool_calls" : "stop",
|
|
19952
|
-
stream_complete: true,
|
|
20510
|
+
...streamComplete ? { finish_reason: finalToolCalls.length > 0 ? "tool_calls" : "stop" } : {},
|
|
20511
|
+
...streamComplete ? { stream_complete: true } : {},
|
|
20512
|
+
...streamTruncated ? { stream_truncated: true } : {},
|
|
20513
|
+
...completedResponse ? { completed_response: completedResponse } : {},
|
|
20514
|
+
...completedResponse && typeof completedResponse.id === "string" ? { response_id: completedResponse.id } : {},
|
|
19953
20515
|
...failure ? { failure } : {}
|
|
19954
20516
|
};
|
|
19955
20517
|
};
|
|
19956
20518
|
return {
|
|
19957
20519
|
processEvent,
|
|
19958
|
-
finalize: finalize2
|
|
19959
|
-
|
|
19960
|
-
|
|
19961
|
-
|
|
19962
|
-
|
|
19963
|
-
|
|
19964
|
-
|
|
19965
|
-
|
|
19966
|
-
|
|
19967
|
-
|
|
19968
|
-
|
|
19969
|
-
|
|
19970
|
-
|
|
19971
|
-
|
|
19972
|
-
|
|
19973
|
-
|
|
19974
|
-
|
|
20520
|
+
finalize: finalize2,
|
|
20521
|
+
/**
|
|
20522
|
+
* legacy 非标准 provider 可能沿用 chat wire 的 `[DONE]` 收尾哨兵。
|
|
20523
|
+
* 原生 Responses(含 CF)的权威终局仍是 response.completed —— 认这个哨兵
|
|
20524
|
+
* 不为 CF 开豁免:CF 被截断时既没有 completed 也没有 [DONE]。
|
|
20525
|
+
*/
|
|
20526
|
+
markLegacyDone: () => {
|
|
20527
|
+
sawTerminalEvent = true;
|
|
20528
|
+
if (requireResponseCompleted) {
|
|
20529
|
+
if (!sawTerminalSuccess) {
|
|
20530
|
+
failure = failure ?? {
|
|
20531
|
+
code: "response_completed_missing",
|
|
20532
|
+
message: `${failurePrefix} upstream ended with a legacy [DONE] sentinel without response.completed.`
|
|
20533
|
+
};
|
|
20534
|
+
}
|
|
20535
|
+
return;
|
|
20536
|
+
}
|
|
20537
|
+
sawTerminalSuccess = true;
|
|
20538
|
+
}
|
|
19975
20539
|
};
|
|
19976
20540
|
}
|
|
19977
20541
|
async function readResponsesSseCompletion(args2) {
|
|
@@ -19979,10 +20543,18 @@ async function readResponsesSseCompletion(args2) {
|
|
|
19979
20543
|
onTextDelta: args2.onTextDelta,
|
|
19980
20544
|
onReasoningDelta: args2.onReasoningDelta,
|
|
19981
20545
|
...args2.onMeaningfulDelta ? { onMeaningfulDelta: args2.onMeaningfulDelta } : {},
|
|
19982
|
-
|
|
20546
|
+
...args2.onEvent ? { onEvent: args2.onEvent } : {},
|
|
20547
|
+
fallbackPrefix: args2.fallbackPrefix ?? "Responses",
|
|
20548
|
+
...args2.requireResponseCompleted === true ? { requireResponseCompleted: true } : {},
|
|
20549
|
+
...args2.authoritativeCompletedTools === true ? { authoritativeCompletedTools: true } : {}
|
|
19983
20550
|
});
|
|
19984
20551
|
for await (const frame of readSseFrames(args2.response)) {
|
|
19985
20552
|
for (const line of frame.split("\n")) {
|
|
20553
|
+
const trimmedLine = line.trim();
|
|
20554
|
+
if (trimmedLine === "[DONE]" || trimmedLine === "data: [DONE]") {
|
|
20555
|
+
collector.markLegacyDone();
|
|
20556
|
+
continue;
|
|
20557
|
+
}
|
|
19986
20558
|
const parsed = parseSseDataLineObject(line);
|
|
19987
20559
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
19988
20560
|
collector.processEvent(parsed);
|
|
@@ -19996,6 +20568,7 @@ async function readResponsesSseCompletion(args2) {
|
|
|
19996
20568
|
err.status = status;
|
|
19997
20569
|
err.code = result4.failure.code;
|
|
19998
20570
|
err.type = result4.failure.type;
|
|
20571
|
+
if (result4.usage) err.usage = result4.usage;
|
|
19999
20572
|
throw err;
|
|
20000
20573
|
}
|
|
20001
20574
|
return result4;
|
|
@@ -20009,6 +20582,25 @@ function resolveOpenAiCompatibleWire(config) {
|
|
|
20009
20582
|
if (config.wire) return config.wire;
|
|
20010
20583
|
return isOpenAiResponsesEndpoint(config.endpoint) ? "responses" : "chat.completions";
|
|
20011
20584
|
}
|
|
20585
|
+
var PROMPT_CACHE_KEY_PROVIDERS = /* @__PURE__ */ new Set([
|
|
20586
|
+
"opendesign",
|
|
20587
|
+
"opencode",
|
|
20588
|
+
"opencode-go",
|
|
20589
|
+
"runinfra",
|
|
20590
|
+
"deepseek",
|
|
20591
|
+
"openai"
|
|
20592
|
+
]);
|
|
20593
|
+
function shouldInjectDirectPromptCacheKey(provider, endpoint) {
|
|
20594
|
+
const p = (provider || "").toLowerCase().trim();
|
|
20595
|
+
if (PROMPT_CACHE_KEY_PROVIDERS.has(p)) return true;
|
|
20596
|
+
if (typeof endpoint === "string") {
|
|
20597
|
+
const ep = endpoint.toLowerCase();
|
|
20598
|
+
if (ep.includes("open-design.ai") || ep.includes("opencode.ai") || ep.includes("deepseek.com")) {
|
|
20599
|
+
return true;
|
|
20600
|
+
}
|
|
20601
|
+
}
|
|
20602
|
+
return false;
|
|
20603
|
+
}
|
|
20012
20604
|
function buildOpenAiCompatibleChatCompletionRequest(args2) {
|
|
20013
20605
|
const isResponses = resolveOpenAiCompatibleWire(args2.providerConfig) === "responses";
|
|
20014
20606
|
const shouldStripReasoning = shouldStripReasoningContentForOutbound(
|
|
@@ -20017,7 +20609,13 @@ function buildOpenAiCompatibleChatCompletionRequest(args2) {
|
|
|
20017
20609
|
);
|
|
20018
20610
|
const sanitizedMessages = sanitizeForOutbound(args2.messages, args2.tools);
|
|
20019
20611
|
const messages = toOpenAiCompatibleMessages(sanitizedMessages, {
|
|
20020
|
-
stripReasoningContent: shouldStripReasoning
|
|
20612
|
+
stripReasoningContent: shouldStripReasoning,
|
|
20613
|
+
...args2.shapingCounts ? { shapingCounts: args2.shapingCounts } : {},
|
|
20614
|
+
...resolveReasoningReplayOptions(
|
|
20615
|
+
args2.providerConfig.provider,
|
|
20616
|
+
args2.providerConfig.model,
|
|
20617
|
+
shouldStripReasoning
|
|
20618
|
+
)
|
|
20021
20619
|
});
|
|
20022
20620
|
const rawBody = {
|
|
20023
20621
|
model: args2.providerConfig.model,
|
|
@@ -20032,7 +20630,20 @@ function buildOpenAiCompatibleChatCompletionRequest(args2) {
|
|
|
20032
20630
|
...!isResponses && args2.stream ? getUsageRequestOptions(args2.providerConfig.usageProvider ?? args2.providerConfig.provider, {
|
|
20033
20631
|
api: "chat-completions",
|
|
20034
20632
|
endpoint: args2.providerConfig.endpoint
|
|
20035
|
-
}) : {}
|
|
20633
|
+
}) : {},
|
|
20634
|
+
...!isResponses && !args2.providerConfig.requestOptions?.prompt_cache_key && shouldInjectDirectPromptCacheKey(args2.providerConfig.provider, args2.providerConfig.endpoint) ? {
|
|
20635
|
+
// 直连通道缓存路由亲和:第三方聚合网关(OpenDesign、OpenCode、RunInfra 等)
|
|
20636
|
+
// 后端是多副本集群,前缀缓存是单节点本地的。键取跨轮稳定的部分(model + system 稳定前缀 + 工具定义),
|
|
20637
|
+
// 确保同任务多轮工具循环始终打到同一后端缓存节点,避免缓存漂移击穿。
|
|
20638
|
+
prompt_cache_key: stablePromptCacheKey(
|
|
20639
|
+
[
|
|
20640
|
+
args2.providerConfig.model,
|
|
20641
|
+
collectStablePromptPrefix(sanitizedMessages),
|
|
20642
|
+
args2.tools ?? []
|
|
20643
|
+
],
|
|
20644
|
+
"nolo-direct"
|
|
20645
|
+
)
|
|
20646
|
+
} : {}
|
|
20036
20647
|
};
|
|
20037
20648
|
const body = isResponses ? buildResponsesRequestBody(rawBody, args2.providerConfig.model) : normalizeChatCompletionsBodyForProvider({
|
|
20038
20649
|
body: rawBody,
|
|
@@ -20040,6 +20651,10 @@ function buildOpenAiCompatibleChatCompletionRequest(args2) {
|
|
|
20040
20651
|
model: args2.providerConfig.model,
|
|
20041
20652
|
endpoint: args2.providerConfig.endpoint
|
|
20042
20653
|
});
|
|
20654
|
+
if (args2.requestFacts) {
|
|
20655
|
+
applyShapingCounts(args2.requestFacts, args2.shapingCounts);
|
|
20656
|
+
writeThinkingFacts(args2.requestFacts, body);
|
|
20657
|
+
}
|
|
20043
20658
|
const endpoint = args2.providerConfig.endpoint;
|
|
20044
20659
|
const headers = {
|
|
20045
20660
|
"Content-Type": "application/json",
|
|
@@ -20128,6 +20743,9 @@ async function readOpenAiCompatibleSseCompletion(args2) {
|
|
|
20128
20743
|
};
|
|
20129
20744
|
for await (const frame of readSseFrames(args2.response)) {
|
|
20130
20745
|
processOpenAiCompatibleSseEvent(frame, state);
|
|
20746
|
+
if (state.sawDone) {
|
|
20747
|
+
break;
|
|
20748
|
+
}
|
|
20131
20749
|
}
|
|
20132
20750
|
flushChatCompletionStream(state);
|
|
20133
20751
|
throwIfChatCompletionStreamFailed(state);
|
|
@@ -20146,14 +20764,32 @@ async function executeOpenAiCompatibleChatCompletion(args2) {
|
|
|
20146
20764
|
const isResponses = resolveOpenAiCompatibleWire(args2.providerConfig) === "responses";
|
|
20147
20765
|
const timingTracker = createProviderCallTimingTracker();
|
|
20148
20766
|
const observeMeaningful = () => observeMeaningfulProviderResponse(timingTracker);
|
|
20767
|
+
const diagnosticSink = resolveOutboundDiagnosticSink(args2.outboundDiagnostics);
|
|
20768
|
+
const diagnosticCall = diagnosticSink ? createOutboundDiagnosticCall({
|
|
20769
|
+
sink: diagnosticSink,
|
|
20770
|
+
seam: "local-runtime",
|
|
20771
|
+
host: args2.outboundDiagnostics?.host ?? "client",
|
|
20772
|
+
wire: isResponses ? "responses" : "chat.completions",
|
|
20773
|
+
provider: args2.providerConfig.provider,
|
|
20774
|
+
model: args2.providerConfig.model,
|
|
20775
|
+
callId: args2.outboundDiagnostics?.callId
|
|
20776
|
+
}) : void 0;
|
|
20777
|
+
let diagnosticAttempt = 0;
|
|
20778
|
+
const terminalIfEnabled = (outcome) => diagnosticCall?.terminal(diagnosticAttempt, outcome);
|
|
20149
20779
|
const send = async (apiKey2) => {
|
|
20780
|
+
diagnosticAttempt += 1;
|
|
20781
|
+
const requestFacts = diagnosticCall ? createRequestFacts() : void 0;
|
|
20782
|
+
if (requestFacts) attachProjectionFacts(requestFacts, args2.projectionStats);
|
|
20150
20783
|
const request3 = buildOpenAiCompatibleChatCompletionRequest({
|
|
20151
20784
|
providerConfig: apiKey2 === args2.providerConfig.apiKey ? args2.providerConfig : { ...args2.providerConfig, apiKey: apiKey2 },
|
|
20152
20785
|
messages: args2.messages,
|
|
20153
20786
|
tools: args2.tools,
|
|
20154
20787
|
stream: args2.stream,
|
|
20155
|
-
sessionId: args2.sessionId
|
|
20788
|
+
sessionId: args2.sessionId,
|
|
20789
|
+
...requestFacts ? { requestFacts } : {},
|
|
20790
|
+
...requestFacts ? { shapingCounts: createRequestShapingCounts() } : {}
|
|
20156
20791
|
});
|
|
20792
|
+
if (requestFacts) diagnosticCall?.dispatch(diagnosticAttempt, requestFacts);
|
|
20157
20793
|
return args2.fetchImpl(request3.url, {
|
|
20158
20794
|
...request3.init,
|
|
20159
20795
|
...args2.signal ? { signal: args2.signal } : {}
|
|
@@ -20163,30 +20799,57 @@ async function executeOpenAiCompatibleChatCompletion(args2) {
|
|
|
20163
20799
|
if (args2.resolveApiKey) {
|
|
20164
20800
|
apiKey = await args2.resolveApiKey({ force: false }) ?? apiKey;
|
|
20165
20801
|
}
|
|
20166
|
-
let res
|
|
20802
|
+
let res;
|
|
20803
|
+
try {
|
|
20804
|
+
res = await send(apiKey);
|
|
20805
|
+
} catch (error) {
|
|
20806
|
+
terminalIfEnabled(isAbortError(error) ? "aborted" : "network-error");
|
|
20807
|
+
throw error;
|
|
20808
|
+
}
|
|
20167
20809
|
if (res.status === 401 && args2.resolveApiKey) {
|
|
20168
20810
|
const refreshed = await args2.resolveApiKey({ force: true });
|
|
20169
20811
|
if (refreshed && refreshed !== apiKey) {
|
|
20812
|
+
diagnosticCall?.httpResult(diagnosticAttempt, {
|
|
20813
|
+
status: res.status,
|
|
20814
|
+
headers: res.headers,
|
|
20815
|
+
errorCategory: "authentication"
|
|
20816
|
+
});
|
|
20817
|
+
terminalIfEnabled("http-error");
|
|
20170
20818
|
await res.body?.cancel().catch(() => {
|
|
20171
20819
|
});
|
|
20172
|
-
|
|
20820
|
+
try {
|
|
20821
|
+
res = await send(refreshed);
|
|
20822
|
+
} catch (error) {
|
|
20823
|
+
terminalIfEnabled(isAbortError(error) ? "aborted" : "network-error");
|
|
20824
|
+
throw error;
|
|
20825
|
+
}
|
|
20173
20826
|
}
|
|
20174
20827
|
}
|
|
20175
20828
|
if (!res.ok) {
|
|
20176
|
-
const
|
|
20177
|
-
let parsed =
|
|
20829
|
+
const raw = await res.text().catch(() => "");
|
|
20830
|
+
let parsed = raw;
|
|
20178
20831
|
try {
|
|
20179
|
-
parsed = JSON.parse(
|
|
20832
|
+
parsed = JSON.parse(raw);
|
|
20180
20833
|
} catch {
|
|
20181
20834
|
}
|
|
20835
|
+
diagnosticCall?.httpResult(diagnosticAttempt, {
|
|
20836
|
+
status: res.status,
|
|
20837
|
+
headers: res.headers,
|
|
20838
|
+
errorCategory: classifyOutboundErrorCategory(res.status, raw)
|
|
20839
|
+
});
|
|
20840
|
+
terminalIfEnabled("http-error");
|
|
20182
20841
|
await args2.onHttpResult?.({ status: res.status, body: parsed });
|
|
20183
20842
|
throw providerHttpFailure({
|
|
20184
20843
|
label: "local provider",
|
|
20185
20844
|
status: res.status,
|
|
20186
|
-
raw
|
|
20845
|
+
raw,
|
|
20187
20846
|
messages: args2.messages
|
|
20188
20847
|
});
|
|
20189
20848
|
}
|
|
20849
|
+
diagnosticCall?.httpResult(diagnosticAttempt, {
|
|
20850
|
+
status: res.status,
|
|
20851
|
+
headers: res.headers
|
|
20852
|
+
});
|
|
20190
20853
|
await args2.onHttpResult?.({ status: res.status });
|
|
20191
20854
|
const contentType = res.headers.get("content-type") ?? "";
|
|
20192
20855
|
const isEventStream = contentType.includes("text/event-stream");
|
|
@@ -20195,65 +20858,73 @@ async function executeOpenAiCompatibleChatCompletion(args2) {
|
|
|
20195
20858
|
result4.usage,
|
|
20196
20859
|
finalizeProviderCallTiming(timingTracker)
|
|
20197
20860
|
);
|
|
20861
|
+
terminalIfEnabled("completed");
|
|
20198
20862
|
return { ...result4, ...usage ? { usage } : {} };
|
|
20199
20863
|
};
|
|
20200
|
-
|
|
20201
|
-
if (
|
|
20202
|
-
|
|
20864
|
+
try {
|
|
20865
|
+
if (isEventStream) {
|
|
20866
|
+
if (isResponses) {
|
|
20867
|
+
const streamed2 = await readResponsesSseCompletion({
|
|
20868
|
+
response: res,
|
|
20869
|
+
...args2.onTextDelta ? { onTextDelta: args2.onTextDelta } : {},
|
|
20870
|
+
...args2.onReasoningDelta ? { onReasoningDelta: args2.onReasoningDelta } : {},
|
|
20871
|
+
onMeaningfulDelta: observeMeaningful
|
|
20872
|
+
});
|
|
20873
|
+
return withTiming({
|
|
20874
|
+
content: streamed2.content,
|
|
20875
|
+
model: args2.providerConfig.model,
|
|
20876
|
+
provider: args2.providerConfig.provider,
|
|
20877
|
+
...streamed2.tool_calls ? { tool_calls: streamed2.tool_calls } : {},
|
|
20878
|
+
...streamed2.reasoning_content ? { reasoning_content: streamed2.reasoning_content } : {},
|
|
20879
|
+
...streamed2.usage ? { usage: streamed2.usage } : {},
|
|
20880
|
+
...streamed2.stream_complete ? { stream_complete: true } : {},
|
|
20881
|
+
...streamed2.finish_reason ? { finish_reason: streamed2.finish_reason } : {},
|
|
20882
|
+
trace: args2.messages
|
|
20883
|
+
});
|
|
20884
|
+
}
|
|
20885
|
+
const streamed = await readOpenAiCompatibleSseCompletion({
|
|
20203
20886
|
response: res,
|
|
20204
20887
|
...args2.onTextDelta ? { onTextDelta: args2.onTextDelta } : {},
|
|
20205
20888
|
...args2.onReasoningDelta ? { onReasoningDelta: args2.onReasoningDelta } : {},
|
|
20206
20889
|
onMeaningfulDelta: observeMeaningful
|
|
20207
20890
|
});
|
|
20208
20891
|
return withTiming({
|
|
20209
|
-
content:
|
|
20892
|
+
content: streamed.content,
|
|
20210
20893
|
model: args2.providerConfig.model,
|
|
20211
20894
|
provider: args2.providerConfig.provider,
|
|
20212
|
-
...
|
|
20213
|
-
...
|
|
20214
|
-
...
|
|
20215
|
-
...
|
|
20216
|
-
...
|
|
20895
|
+
...streamed.tool_calls ? { tool_calls: streamed.tool_calls } : {},
|
|
20896
|
+
...streamed.reasoning_content ? { reasoning_content: streamed.reasoning_content } : {},
|
|
20897
|
+
...streamed.usage ? { usage: streamed.usage } : {},
|
|
20898
|
+
...streamed.stream_complete ? { stream_complete: true } : {},
|
|
20899
|
+
...streamed.finish_reason ? { finish_reason: streamed.finish_reason } : {},
|
|
20217
20900
|
trace: args2.messages
|
|
20218
20901
|
});
|
|
20219
20902
|
}
|
|
20220
|
-
const
|
|
20221
|
-
|
|
20222
|
-
|
|
20223
|
-
|
|
20224
|
-
|
|
20225
|
-
|
|
20226
|
-
|
|
20227
|
-
|
|
20228
|
-
|
|
20229
|
-
|
|
20230
|
-
|
|
20231
|
-
|
|
20232
|
-
|
|
20233
|
-
|
|
20234
|
-
|
|
20235
|
-
trace: args2.messages
|
|
20236
|
-
});
|
|
20237
|
-
}
|
|
20238
|
-
const raw = await res.text().catch(() => "");
|
|
20239
|
-
let data = {};
|
|
20240
|
-
try {
|
|
20241
|
-
data = raw ? JSON.parse(raw) : {};
|
|
20242
|
-
} catch {
|
|
20243
|
-
data = {};
|
|
20244
|
-
}
|
|
20245
|
-
if (isResponses) {
|
|
20246
|
-
return withTiming(parseOpenAiCompatibleResponsesResponse({
|
|
20903
|
+
const raw = await res.text().catch(() => "");
|
|
20904
|
+
let data = {};
|
|
20905
|
+
try {
|
|
20906
|
+
data = raw ? JSON.parse(raw) : {};
|
|
20907
|
+
} catch {
|
|
20908
|
+
data = {};
|
|
20909
|
+
}
|
|
20910
|
+
if (isResponses) {
|
|
20911
|
+
return withTiming(parseOpenAiCompatibleResponsesResponse({
|
|
20912
|
+
providerConfig: args2.providerConfig,
|
|
20913
|
+
data,
|
|
20914
|
+
trace: args2.messages
|
|
20915
|
+
}));
|
|
20916
|
+
}
|
|
20917
|
+
return withTiming(parseOpenAiCompatibleChatCompletionResponse({
|
|
20247
20918
|
providerConfig: args2.providerConfig,
|
|
20248
20919
|
data,
|
|
20249
20920
|
trace: args2.messages
|
|
20250
20921
|
}));
|
|
20922
|
+
} catch (error) {
|
|
20923
|
+
terminalIfEnabled(
|
|
20924
|
+
args2.signal?.aborted || isAbortError(error) ? "aborted" : "stream-error"
|
|
20925
|
+
);
|
|
20926
|
+
throw error;
|
|
20251
20927
|
}
|
|
20252
|
-
return withTiming(parseOpenAiCompatibleChatCompletionResponse({
|
|
20253
|
-
providerConfig: args2.providerConfig,
|
|
20254
|
-
data,
|
|
20255
|
-
trace: args2.messages
|
|
20256
|
-
}));
|
|
20257
20928
|
}
|
|
20258
20929
|
|
|
20259
20930
|
// packages/agent-runtime/openAiCompatibleProviderConfig.ts
|
|
@@ -20405,24 +21076,24 @@ public class NoloCredNative {
|
|
|
20405
21076
|
`.trim();
|
|
20406
21077
|
|
|
20407
21078
|
// packages/agent-runtime/dialogMessageRecord.ts
|
|
20408
|
-
function dialogMessageRecordToAgentRuntimeMessage(
|
|
20409
|
-
if (!
|
|
20410
|
-
if (
|
|
21079
|
+
function dialogMessageRecordToAgentRuntimeMessage(record2) {
|
|
21080
|
+
if (!record2 || typeof record2 !== "object") return null;
|
|
21081
|
+
if (record2.role !== "user" && record2.role !== "assistant" && record2.role !== "tool") return null;
|
|
20411
21082
|
return {
|
|
20412
|
-
role:
|
|
20413
|
-
content:
|
|
20414
|
-
...
|
|
20415
|
-
...typeof
|
|
20416
|
-
...typeof
|
|
20417
|
-
...Array.isArray(
|
|
20418
|
-
...typeof
|
|
21083
|
+
role: record2.role,
|
|
21084
|
+
content: record2.content ?? "",
|
|
21085
|
+
...record2.contextReference !== void 0 ? { context_reference: record2.contextReference } : {},
|
|
21086
|
+
...typeof record2.reasoning_content === "string" ? { reasoning_content: record2.reasoning_content } : {},
|
|
21087
|
+
...typeof record2.toolCallId === "string" ? { tool_call_id: record2.toolCallId } : {},
|
|
21088
|
+
...Array.isArray(record2.tool_calls) ? { tool_calls: record2.tool_calls } : {},
|
|
21089
|
+
...typeof record2.toolName === "string" ? { toolName: record2.toolName } : {},
|
|
20419
21090
|
// 写侧(dialogWritePlan)把 tool_result_metadata 以 `metadata` 字段落库;
|
|
20420
21091
|
// 回读必须还原,否则跨 turn 投影丢失 metadata 后缀,同一 tool 消息的字节
|
|
20421
21092
|
// 在 turn 边界漂移 → provider 前缀缓存断裂(stable projection 契约,
|
|
20422
21093
|
// 见 docs/plans/2026-09-05-tool-output-cache-stability.md)。
|
|
20423
|
-
...
|
|
21094
|
+
...record2.metadata && typeof record2.metadata === "object" ? { tool_result_metadata: record2.metadata } : {},
|
|
20424
21095
|
...(() => {
|
|
20425
|
-
const raw =
|
|
21096
|
+
const raw = record2.createdAt;
|
|
20426
21097
|
const ms = typeof raw === "number" ? raw : typeof raw === "string" ? Date.parse(raw) : NaN;
|
|
20427
21098
|
return Number.isFinite(ms) ? { createdAt: ms } : {};
|
|
20428
21099
|
})()
|
|
@@ -20512,11 +21183,24 @@ function mergeSubjectRefs(...groups) {
|
|
|
20512
21183
|
function buildRuntimeSubjectRefs(runtimeContext) {
|
|
20513
21184
|
return mergeSubjectRefs(runtimeContext?.subjectRefs);
|
|
20514
21185
|
}
|
|
21186
|
+
function withoutSelfLineage(record2, dialogId) {
|
|
21187
|
+
const next = { ...record2 };
|
|
21188
|
+
for (const field of ["parentDialogId", "rootDialogId"]) {
|
|
21189
|
+
if (asOptionalTrimmedString(next[field]) === dialogId) delete next[field];
|
|
21190
|
+
}
|
|
21191
|
+
return next;
|
|
21192
|
+
}
|
|
20515
21193
|
function buildDialogLineageFields(args2) {
|
|
21194
|
+
const selfDialogId = asOptionalTrimmedString(args2.dialogId);
|
|
20516
21195
|
const inheritedFromDialogKey = asOptionalTrimmedString(args2.input.inheritedFromDialogKey);
|
|
20517
|
-
const
|
|
21196
|
+
const rawParentDialogId = asOptionalTrimmedString(args2.input.parentDialogId);
|
|
21197
|
+
const parentDialogId = rawParentDialogId && rawParentDialogId !== selfDialogId ? rawParentDialogId : void 0;
|
|
20518
21198
|
if (!inheritedFromDialogKey && !parentDialogId) return {};
|
|
20519
|
-
const
|
|
21199
|
+
const existingParentDialogId = asOptionalTrimmedString(args2.existingDialog?.parentDialogId);
|
|
21200
|
+
const existingRootDialogId = asOptionalTrimmedString(args2.existingDialog?.rootDialogId);
|
|
21201
|
+
const rootDialogId = [existingRootDialogId, existingParentDialogId, parentDialogId].find(
|
|
21202
|
+
(id) => id && id !== selfDialogId
|
|
21203
|
+
) ?? void 0;
|
|
20520
21204
|
return {
|
|
20521
21205
|
...inheritedFromDialogKey ? { inheritedFromDialogKey } : {},
|
|
20522
21206
|
...parentDialogId ? { parentDialogId } : {},
|
|
@@ -20616,7 +21300,7 @@ function buildAgentRuntimeDialogWritePlan(args2) {
|
|
|
20616
21300
|
args2.existingDialog
|
|
20617
21301
|
);
|
|
20618
21302
|
const dialogRecord = {
|
|
20619
|
-
...asRecordOrEmpty(args2.existingDialog),
|
|
21303
|
+
...withoutSelfLineage(asRecordOrEmpty(args2.existingDialog), dialogId),
|
|
20620
21304
|
id: dialogId,
|
|
20621
21305
|
dbKey: dialogKey,
|
|
20622
21306
|
type: "dialog",
|
|
@@ -20638,7 +21322,8 @@ function buildAgentRuntimeDialogWritePlan(args2) {
|
|
|
20638
21322
|
...subjectRefs ? { subjectRefs } : {},
|
|
20639
21323
|
...buildDialogLineageFields({
|
|
20640
21324
|
input: args2.input,
|
|
20641
|
-
existingDialog: args2.existingDialog
|
|
21325
|
+
existingDialog: args2.existingDialog,
|
|
21326
|
+
dialogId
|
|
20642
21327
|
}),
|
|
20643
21328
|
...typeof args2.input.result.toolCallCount === "number" ? { toolCallCount: args2.input.result.toolCallCount } : {},
|
|
20644
21329
|
localRuntime: {
|
|
@@ -20680,22 +21365,22 @@ function resolveHybridServers(defaultServer, preferredServerOrigin, fallbackServ
|
|
|
20680
21365
|
].filter((value) => value.trim().length > 0);
|
|
20681
21366
|
return [...new Set(raw.map(normalizeServerOrigin))];
|
|
20682
21367
|
}
|
|
20683
|
-
function normalizeHybridRecord(dbKey,
|
|
20684
|
-
if (!
|
|
21368
|
+
function normalizeHybridRecord(dbKey, record2, serverOrigin) {
|
|
21369
|
+
if (!record2 || typeof record2 !== "object") return null;
|
|
20685
21370
|
return {
|
|
20686
|
-
...
|
|
20687
|
-
dbKey: typeof
|
|
21371
|
+
...record2,
|
|
21372
|
+
dbKey: typeof record2.dbKey === "string" && record2.dbKey ? record2.dbKey : dbKey,
|
|
20688
21373
|
...serverOrigin ? { serverOrigin } : {}
|
|
20689
21374
|
};
|
|
20690
21375
|
}
|
|
20691
|
-
function getHybridRecordTimestamp(
|
|
20692
|
-
if (!
|
|
21376
|
+
function getHybridRecordTimestamp(record2) {
|
|
21377
|
+
if (!record2 || typeof record2 !== "object") return 0;
|
|
20693
21378
|
const candidates = [
|
|
20694
|
-
|
|
20695
|
-
|
|
20696
|
-
|
|
20697
|
-
|
|
20698
|
-
|
|
21379
|
+
record2.updatedAt,
|
|
21380
|
+
record2.updated_at,
|
|
21381
|
+
record2.createdAt,
|
|
21382
|
+
record2.created,
|
|
21383
|
+
record2?.meta?.createdAt
|
|
20699
21384
|
];
|
|
20700
21385
|
for (const candidate of candidates) {
|
|
20701
21386
|
const asNumber = asOptionalPositiveFiniteNumber(candidate);
|
|
@@ -20707,10 +21392,10 @@ function getHybridRecordTimestamp(record) {
|
|
|
20707
21392
|
}
|
|
20708
21393
|
return 0;
|
|
20709
21394
|
}
|
|
20710
|
-
function isHybridTombstoneRecord(
|
|
20711
|
-
if (!
|
|
20712
|
-
if (typeof
|
|
20713
|
-
return Boolean(
|
|
21395
|
+
function isHybridTombstoneRecord(record2) {
|
|
21396
|
+
if (!record2 || typeof record2 !== "object") return false;
|
|
21397
|
+
if (typeof record2.deletedAt === "string") return record2.deletedAt.trim().length > 0;
|
|
21398
|
+
return Boolean(record2.deletedAt);
|
|
20714
21399
|
}
|
|
20715
21400
|
function shouldReplaceWithHybridRecord(nextRecord, currentRecord) {
|
|
20716
21401
|
const nextTs = getHybridRecordTimestamp(nextRecord);
|
|
@@ -20794,8 +21479,8 @@ function createHybridRecordStore(deps) {
|
|
|
20794
21479
|
}
|
|
20795
21480
|
return normalizedLocalRecord ?? null;
|
|
20796
21481
|
},
|
|
20797
|
-
write: async (dbKey,
|
|
20798
|
-
const nextRecord = normalizeHybridRecord(dbKey,
|
|
21482
|
+
write: async (dbKey, record2) => {
|
|
21483
|
+
const nextRecord = normalizeHybridRecord(dbKey, record2) ?? { dbKey };
|
|
20799
21484
|
await deps.db.put(dbKey, nextRecord);
|
|
20800
21485
|
return nextRecord;
|
|
20801
21486
|
},
|
|
@@ -20943,10 +21628,10 @@ function buildLoadSkillExecutor(args2) {
|
|
|
20943
21628
|
metadata: { loadSkill: true, resolved: false }
|
|
20944
21629
|
};
|
|
20945
21630
|
}
|
|
20946
|
-
const { resolveSkillByName } = await import("./skillDiscovery-
|
|
21631
|
+
const { resolveSkillByName } = await import("./skillDiscovery-QC35EQY4.js");
|
|
20947
21632
|
const resolved = resolveSkillByName(args2.cwd, name);
|
|
20948
21633
|
if (!resolved) {
|
|
20949
|
-
const { resolveBuiltinSkillByName } = await import("./builtinSkillRegistry-
|
|
21634
|
+
const { resolveBuiltinSkillByName } = await import("./builtinSkillRegistry-TDQ6JB2E.js");
|
|
20950
21635
|
const builtin = resolveBuiltinSkillByName(name);
|
|
20951
21636
|
if (builtin) {
|
|
20952
21637
|
return {
|
|
@@ -20989,7 +21674,7 @@ ${body}`,
|
|
|
20989
21674
|
};
|
|
20990
21675
|
}
|
|
20991
21676
|
async function formatUnknownSkillMessage(cwd, requestedName) {
|
|
20992
|
-
const { discoverSkills } = await import("./skillDiscovery-
|
|
21677
|
+
const { discoverSkills } = await import("./skillDiscovery-QC35EQY4.js");
|
|
20993
21678
|
let available = [];
|
|
20994
21679
|
try {
|
|
20995
21680
|
available = discoverSkills(cwd).map((s) => s.name);
|
|
@@ -21004,8 +21689,27 @@ No skills were discovered in this workspace.`;
|
|
|
21004
21689
|
Available skills: ${available.join(", ")}`;
|
|
21005
21690
|
}
|
|
21006
21691
|
|
|
21692
|
+
// packages/agent-runtime/sessionIdentity.ts
|
|
21693
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
21694
|
+
var SALT = "nolo-session-identity-v1";
|
|
21695
|
+
function isStableSessionIdentityEnabled(env = process.env) {
|
|
21696
|
+
const v = env.NOLO_STABLE_SESSION_IDENTITY?.trim().toLowerCase();
|
|
21697
|
+
return !(v === "0" || v === "false" || v === "off");
|
|
21698
|
+
}
|
|
21699
|
+
function deriveStableUuid(sessionKey, purpose) {
|
|
21700
|
+
const h = createHash7("sha256").update(`${SALT}\0${purpose}\0${sessionKey}`).digest();
|
|
21701
|
+
h[6] = h[6] & 15 | 80;
|
|
21702
|
+
h[8] = h[8] & 63 | 128;
|
|
21703
|
+
const x = h.subarray(0, 16).toString("hex");
|
|
21704
|
+
return `${x.slice(0, 8)}-${x.slice(8, 12)}-${x.slice(12, 16)}-${x.slice(16, 20)}-${x.slice(20, 32)}`;
|
|
21705
|
+
}
|
|
21706
|
+
function resolveSessionKey(args2) {
|
|
21707
|
+
const d = args2.dialogId?.trim();
|
|
21708
|
+
return d ? `dialog:${d}` : void 0;
|
|
21709
|
+
}
|
|
21710
|
+
|
|
21007
21711
|
// packages/agent-runtime/devin/devinProvider.ts
|
|
21008
|
-
import { randomBytes, randomUUID } from "node:crypto";
|
|
21712
|
+
import { randomBytes, randomUUID as randomUUID2 } from "node:crypto";
|
|
21009
21713
|
var CLIENT_NAME = "chisel";
|
|
21010
21714
|
var CLIENT_VERSION = "3000.11.3";
|
|
21011
21715
|
function writeVarint(fieldNum, value) {
|
|
@@ -21064,10 +21768,13 @@ function encodeDevinClientMetadata(token) {
|
|
|
21064
21768
|
writeStringField(31, generateFingerprint())
|
|
21065
21769
|
]);
|
|
21066
21770
|
}
|
|
21067
|
-
function
|
|
21771
|
+
function devinId(id, purpose) {
|
|
21772
|
+
return id?.sessionKey && isStableSessionIdentityEnabled() ? deriveStableUuid(id.sessionKey, purpose) : randomUUID2();
|
|
21773
|
+
}
|
|
21774
|
+
function encodeDevinChatMessage(msg, identity2, index = 0) {
|
|
21068
21775
|
const source = msg.role === "assistant" ? 2 : msg.role === "tool" ? 4 : 1;
|
|
21069
21776
|
return Buffer.concat([
|
|
21070
|
-
writeStringField(1,
|
|
21777
|
+
writeStringField(1, devinId(identity2, `msg:${index}:${msg.role}`)),
|
|
21071
21778
|
writeVarint(2, source),
|
|
21072
21779
|
writeStringField(3, msg.text),
|
|
21073
21780
|
...(msg.toolCalls ?? []).map(
|
|
@@ -21123,19 +21830,20 @@ function buildCompletionConfig(params) {
|
|
|
21123
21830
|
}
|
|
21124
21831
|
function buildGetChatMessageRequest(params) {
|
|
21125
21832
|
const { token, messages, model, tools = [], temperature } = params;
|
|
21833
|
+
const identity2 = { sessionKey: params.sessionKey };
|
|
21126
21834
|
const metadata = encodeDevinClientMetadata(token);
|
|
21127
21835
|
let systemPrompt = "";
|
|
21128
21836
|
const filteredMessages = [];
|
|
21129
21837
|
for (const m of messages) {
|
|
21130
|
-
const
|
|
21838
|
+
const text2 = typeof m.content === "string" ? m.content : Array.isArray(m.content) ? m.content.filter((p) => p?.type === "text").map((p) => p.text).join("\n") : "";
|
|
21131
21839
|
if (m.role === "system") {
|
|
21132
21840
|
systemPrompt = systemPrompt ? `${systemPrompt}
|
|
21133
21841
|
|
|
21134
|
-
${
|
|
21842
|
+
${text2}` : text2;
|
|
21135
21843
|
} else if (m.role === "user" || m.role === "assistant" || m.role === "tool") {
|
|
21136
21844
|
filteredMessages.push({
|
|
21137
21845
|
role: m.role,
|
|
21138
|
-
text,
|
|
21846
|
+
text: text2,
|
|
21139
21847
|
...m.tool_call_id ? { toolCallId: m.tool_call_id } : {},
|
|
21140
21848
|
...m.tool_calls?.length ? { toolCalls: m.tool_calls } : {}
|
|
21141
21849
|
});
|
|
@@ -21152,10 +21860,10 @@ ${item.text}`;
|
|
|
21152
21860
|
coalesced.push({ ...item });
|
|
21153
21861
|
}
|
|
21154
21862
|
}
|
|
21155
|
-
const chatMessageBuffers = coalesced.map((m) => encodeDevinChatMessage(m));
|
|
21863
|
+
const chatMessageBuffers = coalesced.map((m, i) => encodeDevinChatMessage(m, identity2, i));
|
|
21156
21864
|
const completionConfig = buildCompletionConfig({ temperature });
|
|
21157
21865
|
const modelConfig = Buffer.concat([
|
|
21158
|
-
writeStringField(1,
|
|
21866
|
+
writeStringField(1, randomUUID2()),
|
|
21159
21867
|
writeVarint(2, 1),
|
|
21160
21868
|
writeVarint(3, 4)
|
|
21161
21869
|
]);
|
|
@@ -21167,7 +21875,7 @@ ${item.text}`;
|
|
|
21167
21875
|
writeMessageField(8, completionConfig),
|
|
21168
21876
|
...tools.map((tool) => writeMessageField(10, encodeDevinToolDefinition(tool))),
|
|
21169
21877
|
writeMessageField(15, modelConfig),
|
|
21170
|
-
writeStringField(16,
|
|
21878
|
+
writeStringField(16, randomUUID2()),
|
|
21171
21879
|
writeVarint(20, 1),
|
|
21172
21880
|
writeStringField(21, model)
|
|
21173
21881
|
]);
|
|
@@ -21268,12 +21976,12 @@ function readDevinUpstreamFailure(error) {
|
|
|
21268
21976
|
return failure;
|
|
21269
21977
|
}
|
|
21270
21978
|
function parseDevinConnectTrailer(payload) {
|
|
21271
|
-
const
|
|
21272
|
-
if (!
|
|
21979
|
+
const text2 = payload.toString("utf8").trim();
|
|
21980
|
+
if (!text2 || text2 === "{}") return null;
|
|
21273
21981
|
try {
|
|
21274
|
-
const parsed = JSON.parse(
|
|
21982
|
+
const parsed = JSON.parse(text2);
|
|
21275
21983
|
if (!parsed.error) {
|
|
21276
|
-
return new Error(`Devin Connect invalid terminal trailer: ${
|
|
21984
|
+
return new Error(`Devin Connect invalid terminal trailer: ${text2}`);
|
|
21277
21985
|
}
|
|
21278
21986
|
const code = typeof parsed.error.code === "string" ? parsed.error.code : "unknown";
|
|
21279
21987
|
const message = typeof parsed.error.message === "string" ? parsed.error.message : "Unknown error";
|
|
@@ -21283,7 +21991,7 @@ function parseDevinConnectTrailer(payload) {
|
|
|
21283
21991
|
code === "resource_exhausted" ? { status: 429, body: parsed.error } : void 0
|
|
21284
21992
|
);
|
|
21285
21993
|
} catch {
|
|
21286
|
-
return new Error(`Devin Connect invalid terminal trailer: ${
|
|
21994
|
+
return new Error(`Devin Connect invalid terminal trailer: ${text2}`);
|
|
21287
21995
|
}
|
|
21288
21996
|
}
|
|
21289
21997
|
function decodeDevinResponsePayload(payload) {
|
|
@@ -21328,13 +22036,13 @@ function decodeDevinResponsePayload(payload) {
|
|
|
21328
22036
|
const valBytes = payload.subarray(offset, offset + len);
|
|
21329
22037
|
offset += len;
|
|
21330
22038
|
if (fieldNum === 3) {
|
|
21331
|
-
const
|
|
21332
|
-
content +=
|
|
21333
|
-
events.push({ type: "content", text });
|
|
22039
|
+
const text2 = valBytes.toString("utf8");
|
|
22040
|
+
content += text2;
|
|
22041
|
+
events.push({ type: "content", text: text2 });
|
|
21334
22042
|
} else if (fieldNum === 9) {
|
|
21335
|
-
const
|
|
21336
|
-
reasoning +=
|
|
21337
|
-
events.push({ type: "reasoning", text });
|
|
22043
|
+
const text2 = valBytes.toString("utf8");
|
|
22044
|
+
reasoning += text2;
|
|
22045
|
+
events.push({ type: "reasoning", text: text2 });
|
|
21338
22046
|
} else if (fieldNum === 6) {
|
|
21339
22047
|
let nestedOffset = 0;
|
|
21340
22048
|
let id;
|
|
@@ -21362,10 +22070,10 @@ function decodeDevinResponsePayload(payload) {
|
|
|
21362
22070
|
}
|
|
21363
22071
|
const nestedValue = valBytes.subarray(nestedOffset, nestedOffset + nestedLength);
|
|
21364
22072
|
nestedOffset += nestedLength;
|
|
21365
|
-
const
|
|
21366
|
-
if (nestedField === 1) id =
|
|
21367
|
-
else if (nestedField === 2) name =
|
|
21368
|
-
else if (nestedField === 3) argsDelta = (argsDelta ?? "") +
|
|
22073
|
+
const text2 = nestedValue.toString("utf8");
|
|
22074
|
+
if (nestedField === 1) id = text2;
|
|
22075
|
+
else if (nestedField === 2) name = text2;
|
|
22076
|
+
else if (nestedField === 3) argsDelta = (argsDelta ?? "") + text2;
|
|
21369
22077
|
}
|
|
21370
22078
|
if (id !== void 0 && name !== void 0) {
|
|
21371
22079
|
events.push({ type: "tool-call-start", id, name });
|
|
@@ -21382,6 +22090,11 @@ function decodeDevinResponsePayload(payload) {
|
|
|
21382
22090
|
}
|
|
21383
22091
|
return { content, reasoning, finishReason, events, usage };
|
|
21384
22092
|
}
|
|
22093
|
+
function isMeaningfulDevinEvent(event) {
|
|
22094
|
+
if (event.type === "reasoning" || event.type === "content") return event.text.length > 0;
|
|
22095
|
+
if (event.type === "tool-call-start") return !!event.name;
|
|
22096
|
+
return event.argsDelta.length > 0;
|
|
22097
|
+
}
|
|
21385
22098
|
function createDevinProvider(options) {
|
|
21386
22099
|
const { token, model = "swe-2-max", fetchImpl = fetch, tools = [], temperature } = options;
|
|
21387
22100
|
return {
|
|
@@ -21393,9 +22106,11 @@ function createDevinProvider(options) {
|
|
|
21393
22106
|
messages,
|
|
21394
22107
|
model: selectedModel,
|
|
21395
22108
|
tools,
|
|
21396
|
-
temperature
|
|
22109
|
+
temperature,
|
|
22110
|
+
sessionKey: resolveSessionKey({ dialogId: opts?.dialogId })
|
|
21397
22111
|
});
|
|
21398
22112
|
const frame = buildDevinConnectFrame(requestPayload);
|
|
22113
|
+
const timingTracker = createProviderCallTimingTracker();
|
|
21399
22114
|
const response = await fetchImpl(DEVIN_CONNECT_URL, {
|
|
21400
22115
|
method: "POST",
|
|
21401
22116
|
headers: {
|
|
@@ -21418,7 +22133,7 @@ function createDevinProvider(options) {
|
|
|
21418
22133
|
if (!response.body) {
|
|
21419
22134
|
throw new Error("Devin Connect response body is null");
|
|
21420
22135
|
}
|
|
21421
|
-
let
|
|
22136
|
+
let text2 = "";
|
|
21422
22137
|
let reasoning = "";
|
|
21423
22138
|
let finishReason = null;
|
|
21424
22139
|
let frameUsage = null;
|
|
@@ -21449,10 +22164,11 @@ function createDevinProvider(options) {
|
|
|
21449
22164
|
if (delta.usage?.completion !== void 0) {
|
|
21450
22165
|
frameUsage = delta.usage;
|
|
21451
22166
|
}
|
|
21452
|
-
|
|
22167
|
+
text2 += delta.content;
|
|
21453
22168
|
reasoning += delta.reasoning;
|
|
21454
22169
|
if (delta.finishReason) finishReason = delta.finishReason;
|
|
21455
22170
|
for (const event of delta.events) {
|
|
22171
|
+
if (isMeaningfulDevinEvent(event)) observeMeaningfulProviderResponse(timingTracker);
|
|
21456
22172
|
if (event.type === "reasoning") {
|
|
21457
22173
|
opts?.onReasoningDelta?.(event.text);
|
|
21458
22174
|
} else if (event.type === "content") {
|
|
@@ -21498,18 +22214,19 @@ function createDevinProvider(options) {
|
|
|
21498
22214
|
}
|
|
21499
22215
|
};
|
|
21500
22216
|
});
|
|
21501
|
-
if (!
|
|
22217
|
+
if (!text2 && !reasoning && toolCalls.length === 0) {
|
|
21502
22218
|
throw new Error("Devin Connect upstream completed without content or tool calls");
|
|
21503
22219
|
}
|
|
21504
|
-
const
|
|
22220
|
+
const timing = finalizeProviderCallTiming(timingTracker);
|
|
22221
|
+
const usage = frameUsage ? withProviderCallTimingFields({
|
|
21505
22222
|
prompt_tokens: frameUsage.prompt + frameUsage.cacheRead,
|
|
21506
22223
|
completion_tokens: frameUsage.completion ?? 0,
|
|
21507
22224
|
total_tokens: frameUsage.prompt + frameUsage.cacheRead + (frameUsage.completion ?? 0) + frameUsage.cacheWrite,
|
|
21508
22225
|
...frameUsage.cacheRead > 0 ? { prompt_tokens_details: { cached_tokens: frameUsage.cacheRead } } : {},
|
|
21509
22226
|
...frameUsage.cacheWrite > 0 ? { cache_creation_input_tokens: frameUsage.cacheWrite } : {}
|
|
21510
|
-
} : void 0;
|
|
22227
|
+
}, timing) : void 0;
|
|
21511
22228
|
return {
|
|
21512
|
-
content:
|
|
22229
|
+
content: text2,
|
|
21513
22230
|
model: selectedModel,
|
|
21514
22231
|
provider: "devin",
|
|
21515
22232
|
...usage ? { usage } : {},
|
|
@@ -21528,6 +22245,73 @@ function createDevinProvider(options) {
|
|
|
21528
22245
|
};
|
|
21529
22246
|
}
|
|
21530
22247
|
|
|
22248
|
+
// packages/agent-runtime/executionLeaseValidation.ts
|
|
22249
|
+
import { isAbsolute as isAbsolute3, relative as relative4, resolve as resolve5 } from "node:path";
|
|
22250
|
+
function withinRoot(root, child) {
|
|
22251
|
+
if (!isAbsolute3(root) || !isAbsolute3(child)) return false;
|
|
22252
|
+
const canonicalRoot = resolve5(root);
|
|
22253
|
+
const canonicalChild = resolve5(child);
|
|
22254
|
+
const suffix = relative4(canonicalRoot, canonicalChild);
|
|
22255
|
+
return suffix === "" || suffix !== ".." && !suffix.startsWith("../") && !suffix.startsWith("..\\") && !isAbsolute3(suffix);
|
|
22256
|
+
}
|
|
22257
|
+
function subsetOf(allowed, actual) {
|
|
22258
|
+
return actual.every(
|
|
22259
|
+
(root) => isAbsolute3(root) && allowed.some((parent) => withinRoot(parent, root))
|
|
22260
|
+
);
|
|
22261
|
+
}
|
|
22262
|
+
function validateConfiguredRootExecutionLease(ticket, lease) {
|
|
22263
|
+
if (lease.ticketId !== ticket.ticketId || lease.grantId !== ticket.grantId || !lease.leaseId || !lease.backendId) return false;
|
|
22264
|
+
const { filesystem } = ticket;
|
|
22265
|
+
if (filesystem.readScope === "runtime-workspace" || filesystem.readScope === "legacy-unscoped" || filesystem.writeScope === "runtime-workspace") return false;
|
|
22266
|
+
if (filesystem.readScope === "none" && lease.readableRoots.length > 0) return false;
|
|
22267
|
+
if (filesystem.writeScope === "none" && lease.writableRoots.length > 0) return false;
|
|
22268
|
+
if (filesystem.readScope === "configured-roots" && !subsetOf(filesystem.readableRoots, lease.readableRoots)) return false;
|
|
22269
|
+
if (filesystem.writeScope === "configured-roots" && !subsetOf(filesystem.writableRoots, lease.writableRoots)) return false;
|
|
22270
|
+
return true;
|
|
22271
|
+
}
|
|
22272
|
+
|
|
22273
|
+
// packages/agent-runtime/ownerOriginExecution.ts
|
|
22274
|
+
var OWNER_ORIGIN_EXECUTION_VERSION = 1;
|
|
22275
|
+
var TOOL_LOCATION_STATUSES = ["ready", "unavailable", "stopped"];
|
|
22276
|
+
function record(value) {
|
|
22277
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
22278
|
+
}
|
|
22279
|
+
function text(value) {
|
|
22280
|
+
return typeof value === "string" && value.trim().length > 0 && value === value.trim();
|
|
22281
|
+
}
|
|
22282
|
+
function absoluteSnapshotPath(value) {
|
|
22283
|
+
if (!text(value) || value.includes("\0")) return false;
|
|
22284
|
+
const drive = /^[A-Za-z]:[\\/]/.test(value);
|
|
22285
|
+
const unc = value.startsWith("\\\\");
|
|
22286
|
+
if (!(value.startsWith("/") || drive || unc)) return false;
|
|
22287
|
+
if (unc && !/^\\\\[^\\/]+[\\/][^\\/]+(?:[\\/]|$)/.test(value)) return false;
|
|
22288
|
+
const segments = value.split(drive || unc ? /[\\/]/ : /\//);
|
|
22289
|
+
return !segments.some((segment) => segment === "." || segment === "..");
|
|
22290
|
+
}
|
|
22291
|
+
function projectToolExecutionLocation(value) {
|
|
22292
|
+
if (!record(value) || !TOOL_LOCATION_STATUSES.includes(value.status) || !EXECUTION_BACKEND_KINDS.includes(value.hostType) || !text(value.deviceId) || !text(value.deviceName) || !record(value.workspace) || !text(value.workspace.id) || !absoluteSnapshotPath(value.workspace.root) || !absoluteSnapshotPath(value.workspace.cwd)) return { status: "unknown" };
|
|
22293
|
+
return {
|
|
22294
|
+
status: value.status,
|
|
22295
|
+
hostType: value.hostType,
|
|
22296
|
+
deviceId: value.deviceId,
|
|
22297
|
+
deviceName: value.deviceName,
|
|
22298
|
+
workspace: { id: value.workspace.id, root: value.workspace.root, cwd: value.workspace.cwd }
|
|
22299
|
+
};
|
|
22300
|
+
}
|
|
22301
|
+
var OWNER_ROUTE_VERSION_HEADER = "X-Nolo-Owner-Route-Version";
|
|
22302
|
+
var OWNER_ROUTE_REQUEST_ID_HEADER = "X-Nolo-Owner-Route-Request-Id";
|
|
22303
|
+
function verifyOwnerRouteAck(headers, expectedRequestId) {
|
|
22304
|
+
const version = headers.get(OWNER_ROUTE_VERSION_HEADER);
|
|
22305
|
+
const requestId = headers.get(OWNER_ROUTE_REQUEST_ID_HEADER)?.trim();
|
|
22306
|
+
if (version !== String(OWNER_ORIGIN_EXECUTION_VERSION) || !requestId) {
|
|
22307
|
+
return { ok: false, code: "owner_route_unsupported" };
|
|
22308
|
+
}
|
|
22309
|
+
if (expectedRequestId !== void 0 && requestId !== expectedRequestId) {
|
|
22310
|
+
return { ok: false, code: "owner_origin_mismatch" };
|
|
22311
|
+
}
|
|
22312
|
+
return { ok: true, version: OWNER_ORIGIN_EXECUTION_VERSION, requestId };
|
|
22313
|
+
}
|
|
22314
|
+
|
|
21531
22315
|
export {
|
|
21532
22316
|
readCommandActionGatePayload,
|
|
21533
22317
|
readActionGate,
|
|
@@ -21536,29 +22320,36 @@ export {
|
|
|
21536
22320
|
Exit_exports,
|
|
21537
22321
|
Effect_exports,
|
|
21538
22322
|
formatToolOverflowMarker,
|
|
21539
|
-
evaluateFileWritePolicy,
|
|
21540
|
-
summarizeToolArguments,
|
|
21541
22323
|
isDestructiveShellCommand,
|
|
21542
22324
|
evaluateShellCommandPolicy,
|
|
22325
|
+
getProcessRegistry,
|
|
21543
22326
|
filterRetainedLedgerRecords,
|
|
21544
22327
|
isLineRangeCovered,
|
|
21545
|
-
|
|
22328
|
+
WORKSPACE_TOOL_NAMES,
|
|
21546
22329
|
buildLocalWorkspaceToolset,
|
|
21547
22330
|
buildLocalWorkspacePolicyToolNames,
|
|
21548
22331
|
buildLocalWorkspaceOpenAiTools,
|
|
21549
22332
|
PATH_FIELD_ALIASES,
|
|
22333
|
+
NEW_TEXT_FIELD_ALIASES,
|
|
22334
|
+
resolveRequestedWorkspacePath,
|
|
21550
22335
|
internalSearchWorkspace,
|
|
21551
22336
|
internalListWorkspaceEntries,
|
|
21552
22337
|
createLocalWorkspaceToolExecutors,
|
|
21553
22338
|
buildToolParametersIndex,
|
|
21554
22339
|
getAgentRuntimeToolParametersIndex,
|
|
22340
|
+
normalizeLocalToolName,
|
|
22341
|
+
isCommandExecutingTool,
|
|
21555
22342
|
resolveLocalToolPolicy,
|
|
22343
|
+
runExecShellGates,
|
|
21556
22344
|
executeLocalToolWithPolicy,
|
|
21557
22345
|
LOCAL_TURN_ABORTED_CODE,
|
|
22346
|
+
hashToolDefinitions,
|
|
21558
22347
|
LOCAL_AGENT_CONFIG_MISSING_CODE,
|
|
21559
22348
|
runLocalAgentTurn,
|
|
22349
|
+
responsesStreamFailureStatus,
|
|
21560
22350
|
codexStreamFailureStatus,
|
|
21561
|
-
|
|
22351
|
+
createResponsesStreamCollector,
|
|
22352
|
+
readResponsesSseCompletion,
|
|
21562
22353
|
buildOpenAiCompatibleChatCompletionRequest,
|
|
21563
22354
|
parseOpenAiCompatibleChatCompletionResponse,
|
|
21564
22355
|
readOpenAiCompatibleSseCompletion,
|
|
@@ -21574,6 +22365,13 @@ export {
|
|
|
21574
22365
|
buildLocalDialogWritePlan,
|
|
21575
22366
|
buildNoloWorkspaceCliToolExecutors,
|
|
21576
22367
|
buildLoadSkillExecutor,
|
|
22368
|
+
isStableSessionIdentityEnabled,
|
|
22369
|
+
deriveStableUuid,
|
|
22370
|
+
resolveSessionKey,
|
|
21577
22371
|
readDevinUpstreamFailure,
|
|
21578
|
-
createDevinProvider
|
|
22372
|
+
createDevinProvider,
|
|
22373
|
+
validateConfiguredRootExecutionLease,
|
|
22374
|
+
OWNER_ORIGIN_EXECUTION_VERSION,
|
|
22375
|
+
projectToolExecutionLocation,
|
|
22376
|
+
verifyOwnerRouteAck
|
|
21579
22377
|
};
|