@qwen-code/qwen-code 0.23.5-dev.codemode-responses.20260915.af4da34719 → 0.23.5-preview.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundled/computer-use/SKILL.md +24 -3
- package/bundled/qc-helper/docs/configuration/model-providers.md +43 -0
- package/bundled/qc-helper/docs/configuration/settings.md +10 -9
- package/bundled/qc-helper/docs/extension/agent-plugins.md +1 -0
- package/bundled/qc-helper/docs/extension/introduction.md +49 -0
- package/bundled/qc-helper/docs/features/channels/dingtalk.md +39 -4
- package/bundled/qc-helper/docs/features/channels/overview.md +12 -0
- package/bundled/qc-helper/docs/features/commands.md +57 -52
- package/bundled/qc-helper/docs/features/computer-use.md +1 -1
- package/bundled/qc-helper/docs/features/goals.md +8 -0
- package/bundled/qc-helper/docs/features/hooks.md +16 -0
- package/bundled/qc-helper/docs/qwen-serve.md +3 -1
- package/bundled/workflow-authoring/SKILL.md +48 -22
- package/chunks/{MaxSizedBox-3K65WFGY.js → MaxSizedBox-FCF6M53W.js} +40 -43
- package/chunks/{StandaloneSessionPicker-JKM33JPY.js → StandaloneSessionPicker-V635V72I.js} +60 -63
- package/chunks/{acp-startup-profiler-RUQNTNU5.js → acp-startup-profiler-MOOU37VM.js} +2 -2
- package/chunks/{acp-subagent-executor-KIZBB2CL.js → acp-subagent-executor-TND6W2O5.js} +46 -47
- package/chunks/{acpAgent-SHI4L5EV.js → acpAgent-3DPWZTNC.js} +954 -322
- package/chunks/{agent-AJXNVRX2.js → agent-KIHGINKN.js} +27 -30
- package/chunks/{agent-headless-2JPJKYHK.js → agent-headless-EJ4QOUSM.js} +27 -30
- package/chunks/{anthropicContentGenerator-H5YPXIDE.js → anthropicContentGenerator-4FGOM5LK.js} +46 -64
- package/chunks/{artifact-tool-MFGORTWZ.js → artifact-tool-MUTNH4NI.js} +1 -1
- package/chunks/{askUserQuestion-WS4GUT7C.js → askUserQuestion-AKIRLVB5.js} +1 -1
- package/chunks/bareMode-QWKZPLPX.js +14 -0
- package/chunks/{bridge-KZYSMV4N.js → bridge-MUX5YJZT.js} +46 -49
- package/chunks/{ca-GZ4FDJU2.js → ca-WC3A5B3Q.js} +12 -1
- package/chunks/{channel-management-service-AFVIT4VH.js → channel-management-service-RRILWSXX.js} +4 -4
- package/chunks/{channel-settings-store-IJG52IDV.js → channel-settings-store-7CBIRZER.js} +51 -54
- package/chunks/{channel-worker-group-JR6JOELM.js → channel-worker-group-3DUJFZJR.js} +8 -8
- package/chunks/{channel-worker-manager-AVKJEZFL.js → channel-worker-manager-E5UW2VLA.js} +8 -8
- package/chunks/{channel-worker-supervisor-OOYY7BAQ.js → channel-worker-supervisor-VN33GSEC.js} +5 -5
- package/chunks/{chunk-2YMRRI2C.js → chunk-2C5TR6HN.js} +82 -9
- package/chunks/{chunk-YDFOHRS5.js → chunk-2GP6BQ2J.js} +1 -1
- package/chunks/{chunk-JATZTB7X.js → chunk-347O2YZJ.js} +158 -290
- package/chunks/{chunk-RYREFZFH.js → chunk-36NRLIR6.js} +10 -8
- package/chunks/{chunk-AXZMWAJV.js → chunk-36SDZ2Q4.js} +8 -0
- package/chunks/{chunk-QR4Q425T.js → chunk-3BZI5GDP.js} +1 -1
- package/chunks/{chunk-IP6NRULS.js → chunk-3HTUE6ZR.js} +3 -3
- package/chunks/{chunk-B2VSRPS6.js → chunk-3LLEB5CU.js} +2 -2
- package/chunks/{chunk-L2XNHRDL.js → chunk-3UGMLA4V.js} +10 -8
- package/chunks/{chunk-66N6C4EH.js → chunk-3WILPKTJ.js} +2 -2
- package/chunks/{chunk-SROLVJFY.js → chunk-3WWPEFMX.js} +1 -1
- package/chunks/{chunk-ZKIAGIGH.js → chunk-3XBUCOWS.js} +1 -1
- package/chunks/{chunk-737SVOO7.js → chunk-43Y26NPF.js} +3 -3
- package/chunks/{chunk-INGBUYL6.js → chunk-4FLUQWJ4.js} +1 -1
- package/chunks/{chunk-BTBJEB27.js → chunk-4JFLRHNE.js} +1 -1
- package/chunks/{chunk-MJHLKWGJ.js → chunk-4QPVZA5J.js} +70 -23
- package/chunks/{chunk-XX5HQLCZ.js → chunk-6OTF7TTE.js} +32 -1
- package/chunks/{chunk-4Y2I3CI3.js → chunk-6USYH3EU.js} +99 -6
- package/chunks/{chunk-Q3TFRP5G.js → chunk-7D4CV7JH.js} +102 -9
- package/chunks/{chunk-EWJTAP3Y.js → chunk-7O5PYQ3M.js} +20 -1
- package/chunks/chunk-ADN5KESB.js +28 -0
- package/chunks/chunk-AKRSSKUT.js +229 -0
- package/chunks/{chunk-IOXJX7XE.js → chunk-AQP3H22J.js} +1 -1
- package/chunks/{chunk-YP7QCE7X.js → chunk-AUX2FL5T.js} +24 -7
- package/chunks/{chunk-YGFJ6BRT.js → chunk-AZCTY64Z.js} +1 -1
- package/chunks/{chunk-5CDDYYNI.js → chunk-B5TJK7B3.js} +1 -1
- package/chunks/{chunk-7MKB7L25.js → chunk-B6RMK4ED.js} +4 -4
- package/chunks/{chunk-YH24ZJ65.js → chunk-BHG3H6OZ.js} +1 -1
- package/chunks/{chunk-BRPYJQDD.js → chunk-BHVF3R6B.js} +7 -5
- package/chunks/{chunk-HFJSQ4GL.js → chunk-BTICBRPL.js} +1 -1
- package/chunks/{chunk-KZCK5JUN.js → chunk-C3T6HPNM.js} +1 -1
- package/chunks/{chunk-UB2MATP5.js → chunk-CDDP4ONL.js} +164 -27
- package/chunks/{chunk-OL3TNHFM.js → chunk-CQPM66MG.js} +4 -4
- package/chunks/{chunk-WKVZES7O.js → chunk-CXONOVBN.js} +1 -1
- package/chunks/{chunk-6IHJLXNF.js → chunk-CXY6BICQ.js} +501 -479
- package/chunks/{chunk-I5QPDANL.js → chunk-D3KVGQUV.js} +1 -1
- package/chunks/{chunk-LMJSPC55.js → chunk-D7JMO2GP.js} +3 -7
- package/chunks/{chunk-CXXAZ2LZ.js → chunk-DC4ZNGH4.js} +1 -1
- package/chunks/{chunk-FMLBBXHB.js → chunk-DRAX5YAI.js} +2 -2
- package/chunks/{chunk-DOTF2PF2.js → chunk-DRD6VBNH.js} +1 -1
- package/chunks/chunk-DX6JTDMR.js +105 -0
- package/chunks/{chunk-HJAJ6MR6.js → chunk-E2VSBAFA.js} +53 -11
- package/chunks/{chunk-G7ZYRFHS.js → chunk-EIBECN2J.js} +3 -3
- package/chunks/{chunk-LWWRJRCD.js → chunk-ESBYWATJ.js} +1 -1
- package/chunks/{chunk-2PLQ3CXJ.js → chunk-FASYATAZ.js} +5 -7
- package/chunks/{chunk-3ADU34IF.js → chunk-FBY32737.js} +4 -4
- package/chunks/{chunk-SIDVJZWH.js → chunk-FCPJXKDG.js} +10 -7
- package/chunks/{chunk-5GXJBU7K.js → chunk-FEDFZBGR.js} +3 -3
- package/chunks/{chunk-CALVKIIG.js → chunk-FIJODK52.js} +3 -3
- package/chunks/{chunk-ZTVYMZBD.js → chunk-FX6PZBOV.js} +3 -3
- package/chunks/{chunk-L6DIANLD.js → chunk-G45B3INR.js} +1 -1
- package/chunks/{chunk-TATT2THJ.js → chunk-GI7SLDOI.js} +2 -2
- package/chunks/chunk-GJKP6XOB.js +1092 -0
- package/chunks/{chunk-I6YJZGHS.js → chunk-GSAOVDTH.js} +9 -9
- package/chunks/{chunk-7MIOAF77.js → chunk-H6L4NEAT.js} +1 -1
- package/chunks/{chunk-MJGJF6G6.js → chunk-HNFKYKHH.js} +103 -22
- package/chunks/{chunk-PN6D5LWJ.js → chunk-HX4WXX3H.js} +301 -138
- package/chunks/{chunk-HG46TTAG.js → chunk-HXUI5D4H.js} +1 -1
- package/chunks/{chunk-JF2CFBDK.js → chunk-HYHSMTRA.js} +4 -4
- package/chunks/{chunk-4DZMYFZA.js → chunk-IKBEIDOH.js} +14 -14
- package/chunks/{chunk-QEENIXYB.js → chunk-INN5ORKX.js} +1 -1
- package/chunks/{chunk-GNV2SFO7.js → chunk-IVFTLUZD.js} +26 -1
- package/chunks/{chunk-L2NII7PZ.js → chunk-IXO2OCIP.js} +2 -2
- package/chunks/{chunk-6MAHSVMB.js → chunk-K4XMAIRX.js} +30 -33
- package/chunks/{chunk-AYMSNIYL.js → chunk-KAYC5FBN.js} +5269 -2785
- package/chunks/chunk-KEM7MWS7.js +3541 -0
- package/chunks/{chunk-ADQUK6WA.js → chunk-KVC7HZWK.js} +1 -1
- package/chunks/{chunk-Z35OSDIT.js → chunk-KVQ3QL4K.js} +3 -3
- package/chunks/{chunk-7U5G6JXI.js → chunk-KWYTSSTJ.js} +105 -6
- package/chunks/{chunk-PZRAE65J.js → chunk-L2A5VBDL.js} +3019 -2352
- package/chunks/{chunk-WD6YQI5M.js → chunk-L3SNMEDW.js} +1 -1
- package/chunks/{chunk-BYUAT5OC.js → chunk-L7TJUPNR.js} +19 -3
- package/chunks/{chunk-ABNX6E6K.js → chunk-LFKXIOGC.js} +1 -1
- package/chunks/{chunk-NFQOOITE.js → chunk-LO2UWNO5.js} +2 -2
- package/chunks/{chunk-LWUTZKDU.js → chunk-M22WLKLI.js} +5 -5
- package/chunks/{chunk-54B2LTKP.js → chunk-M23GFJ5B.js} +24 -5
- package/chunks/{chunk-VGY2RGXL.js → chunk-M4U2LTD2.js} +1 -1
- package/chunks/{chunk-ZNI3YJHS.js → chunk-MFDKHGTD.js} +1 -1
- package/chunks/{chunk-R7OO56VZ.js → chunk-MMRGG6R4.js} +1 -1
- package/chunks/{chunk-E6IR653O.js → chunk-MO4XID7S.js} +1 -1
- package/chunks/{chunk-FZQQMVLB.js → chunk-NKTMUPHJ.js} +3 -6
- package/chunks/{chunk-V77DTVCM.js → chunk-NQ272MQG.js} +1 -1
- package/chunks/{chunk-TDFLM7BE.js → chunk-OALXNGUA.js} +6 -6
- package/chunks/{chunk-FBDHP23D.js → chunk-OSG23MR3.js} +1 -1
- package/chunks/{chunk-NJ2OFVUX.js → chunk-P42KMMU6.js} +860 -1
- package/chunks/{chunk-Y33TCKXL.js → chunk-PF7GAP6K.js} +60 -58
- package/chunks/{chunk-MQRLLBMQ.js → chunk-PPJSG2PU.js} +2 -2
- package/chunks/{chunk-EPVEPTI3.js → chunk-PZRXWQUA.js} +753 -18
- package/chunks/{chunk-OLN7QX4P.js → chunk-Q54O3EIA.js} +30 -28
- package/chunks/{chunk-DQH3EVAD.js → chunk-QGEISOJ2.js} +4 -4
- package/chunks/{chunk-3M4O2AY3.js → chunk-QHSOINX6.js} +2 -2
- package/chunks/{chunk-HIQEL7EM.js → chunk-QIPLWW6Q.js} +1 -1
- package/chunks/chunk-QMENOK5T.js +1246 -0
- package/chunks/chunk-QT6Z2IBF.js +347 -0
- package/chunks/{chunk-TBSCTWKF.js → chunk-RN6A53UJ.js} +25 -0
- package/chunks/{chunk-65BKWMMH.js → chunk-RRI764F7.js} +21 -19
- package/chunks/{chunk-YI2YCNSP.js → chunk-SENYKRII.js} +1 -1
- package/chunks/chunk-SFHX5G2S.js +2796 -0
- package/chunks/chunk-SK3RZOPS.js +34 -0
- package/chunks/{chunk-MD6KXINN.js → chunk-SOLRBF7L.js} +13 -9
- package/chunks/{chunk-6BCN3VOY.js → chunk-SSWTA7CH.js} +12 -12
- package/chunks/{chunk-IAS753HG.js → chunk-SYMXYRM5.js} +11 -2
- package/chunks/{chunk-FGROOEKM.js → chunk-TDKUXSJO.js} +34 -6
- package/chunks/{chunk-ZJ7JQUGY.js → chunk-TKF4JINY.js} +1 -1
- package/chunks/{chunk-RVK37FWG.js → chunk-TPY6HW55.js} +4 -4
- package/chunks/{chunk-EDB556X7.js → chunk-TRZ22SG5.js} +1 -1
- package/chunks/{chunk-7LG4MUUD.js → chunk-TXTCM3TC.js} +4 -4
- package/chunks/{chunk-5ODRE7E5.js → chunk-U4AASWUQ.js} +28 -12
- package/chunks/{chunk-WPMRT4AR.js → chunk-UQGRJTDK.js} +2 -2
- package/chunks/{chunk-JBS56C7O.js → chunk-UZSB57EV.js} +6 -8
- package/chunks/{chunk-S4M6BDNE.js → chunk-V4JJAVHQ.js} +2 -2
- package/chunks/chunk-VEXUA6DX.js +1026 -0
- package/chunks/{chunk-ME4JBHSB.js → chunk-VQDWCQOE.js} +2 -0
- package/chunks/{chunk-3XXDCC5C.js → chunk-VU3XMZ5I.js} +23 -4
- package/chunks/{chunk-RD2HAF25.js → chunk-WL36KHUQ.js} +6 -6
- package/chunks/{chunk-WYRSEVBQ.js → chunk-WNQIJTOP.js} +8 -8
- package/chunks/{chunk-GTBXQ5W2.js → chunk-WSJI6ODG.js} +99 -30
- package/chunks/{chunk-VN5G33G7.js → chunk-WZWTY7SG.js} +6 -6
- package/chunks/{chunk-EKMJR7M3.js → chunk-X7AYIXC7.js} +1 -1
- package/chunks/{chunk-IBRQG2MP.js → chunk-XAJZFGD2.js} +11 -11
- package/chunks/{chunk-VRQZESKP.js → chunk-XICCGDWF.js} +2 -2
- package/chunks/{chunk-OZ2KDR2L.js → chunk-Y2KJC55Y.js} +12 -7
- package/chunks/{chunk-2S2WIGCM.js → chunk-Y4NNIGYO.js} +1 -1
- package/chunks/{chunk-J7LBAKDH.js → chunk-YL3UJML3.js} +7 -7
- package/chunks/{chunk-GSS4SZNG.js → chunk-YP2K3WOS.js} +40 -56
- package/chunks/{chunk-ZZUXUBEB.js → chunk-YQQ2U7AS.js} +8 -5
- package/chunks/{chunk-FAWTMDX7.js → chunk-YXHY6BKS.js} +15 -0
- package/chunks/{chunk-VIV2I3R7.js → chunk-YZXSDPOQ.js} +140 -39
- package/chunks/{chunk-KZ63S3HX.js → chunk-ZFHKUQZ4.js} +3 -3
- package/chunks/{chunk-B6KSTADQ.js → chunk-ZMYKNKET.js} +6 -6
- package/chunks/{codex-subagent-executor-6M7TD3MF.js → codex-subagent-executor-AEAIQZDC.js} +48 -49
- package/chunks/{config-utils-TB4QERW7.js → config-utils-KX2YS725.js} +43 -46
- package/chunks/{contextCommand-BFQMDECM.js → contextCommand-RV6Y5LNJ.js} +41 -44
- package/chunks/{core-runtime-Z2QJJMHR.js → core-runtime-ZI4RTOJQ.js} +45 -48
- package/chunks/{create-sub-session-GE4U3D7C.js → create-sub-session-BBWFQARJ.js} +46 -48
- package/chunks/{daemon-NJB4PWZ7.js → daemon-INCM4VBX.js} +3 -1
- package/chunks/{daemon-git-worktree-guard-IPA22S72.js → daemon-git-worktree-guard-KECEMV6A.js} +39 -42
- package/chunks/{daemon-status-provider-2U5WPCCB.js → daemon-status-provider-NULJNAEV.js} +53 -56
- package/chunks/{daemon-trust-policy-GEIGMVDQ.js → daemon-trust-policy-S4KWGPV3.js} +47 -50
- package/chunks/{daemon-trust-policy-monitor-JETBW5FX.js → daemon-trust-policy-monitor-546N5ZVL.js} +47 -50
- package/chunks/{de-VGY3VNBU.js → de-6AVKPTXQ.js} +11 -0
- package/chunks/{deferred-core-runtime-LANRK77C.js → deferred-core-runtime-T23ZT443.js} +39 -42
- package/chunks/{dist-NIOJXMGY.js → dist-4P3ZJYGI.js} +1 -1
- package/chunks/{dist-VDLSBCLM.js → dist-7MGRENQ5.js} +1 -1
- package/chunks/{dist-SE4J6Z4O.js → dist-BNW423XT.js} +326 -77
- package/chunks/{dist-TFGETXFN.js → dist-CESMUYGN.js} +4 -4
- package/chunks/{dist-MPUZZOG5.js → dist-DBBOFWSC.js} +1 -1
- package/chunks/{dist-T6DDPDLQ.js → dist-G5UMXIGF.js} +1 -1
- package/chunks/{dist-PA7WPFVE.js → dist-UXVNLQHG.js} +3 -3
- package/chunks/{dist-GUB7QRYA.js → dist-VA4LREAQ.js} +2 -2
- package/chunks/{dist-2QYIVNS6.js → dist-XDRTR4QP.js} +1 -1
- package/chunks/{edit-QC63PJOZ.js → edit-CMSQB7NP.js} +27 -30
- package/chunks/{en-E5ZO5TZW.js → en-56QLKXS2.js} +23 -1
- package/chunks/{enter-worktree-CAARFWBI.js → enter-worktree-DA6A4XC5.js} +3 -3
- package/chunks/{enterPlanMode-5TMWDRXD.js → enterPlanMode-UDPMNESD.js} +27 -30
- package/chunks/{environment-TNQVM5B3.js → environment-TSQJUTPV.js} +42 -45
- package/chunks/{errors-KWDDLG7P.js → errors-RIVYJS6T.js} +41 -44
- package/chunks/{exit-worktree-JXGGUOBP.js → exit-worktree-4H6Z2VQI.js} +3 -3
- package/chunks/{exitPlanMode-CLEWPZIE.js → exitPlanMode-BYBBFN2T.js} +27 -30
- package/chunks/{fast-path-PMRLQT7J.js → fast-path-F2CYDDZ4.js} +4 -4
- package/chunks/{fast-path-settings-XDYX7X5Z.js → fast-path-settings-N2VGRGDJ.js} +2 -2
- package/chunks/{fr-UAZJJH5N.js → fr-EBUDHJL3.js} +11 -0
- package/chunks/{glob-3AK4KKCE.js → glob-Z2JMJKKN.js} +27 -30
- package/chunks/{goal-tools-FD6OCE6Q.js → goal-tools-HXVVLGCV.js} +27 -30
- package/chunks/{handleAutoUpdate-QUNNMMY6.js → handleAutoUpdate-FZP45KOR.js} +43 -46
- package/chunks/{i18n-DVN326VM.js → i18n-OTB62AKW.js} +40 -43
- package/chunks/{image-gen-5G2TQ3DY.js → image-gen-HIAZCB5T.js} +6 -7
- package/chunks/{initializer-JHEJBPVJ.js → initializer-4JXZEC4B.js} +47 -50
- package/chunks/{installationInfo-DYOI4I5U.js → installationInfo-2IJV5QKC.js} +39 -42
- package/chunks/{ja-2RITCMAJ.js → ja-NCDT4CGV.js} +11 -0
- package/chunks/{list-MW74DDMO.js → list-KQSQ4A5G.js} +50 -53
- package/chunks/{llm-HUDP76IA.js → llm-LSUBOJAR.js} +154 -974
- package/chunks/{llm-content-generator-KYD6ZEM6.js → llm-content-generator-MLIONRXE.js} +17 -12
- package/chunks/{loadedSettingsAdapter-RRAZOPRB.js → loadedSettingsAdapter-TZTTNRHI.js} +47 -50
- package/chunks/{loggingContentGenerator-MHE6Z2OZ.js → loggingContentGenerator-TUPEXFMM.js} +31 -34
- package/chunks/{loop-wakeup-VG6CGBQA.js → loop-wakeup-ZBVRI6VH.js} +1 -1
- package/chunks/{managed-npm-update-3G3O3T3R.js → managed-npm-update-WEA5XMFZ.js} +40 -43
- package/chunks/{mcp-JGLBFJQB.js → mcp-TFDTUPIA.js} +47 -50
- package/chunks/{model-configuration-EGWMLK4P.js → model-configuration-ZCAKKIOF.js} +48 -51
- package/chunks/{modelConfigUtils-H4WFGWQD.js → modelConfigUtils-J3ZPW7ZK.js} +41 -44
- package/chunks/{monitor-62V72TGX.js → monitor-CI7YE7MT.js} +29 -32
- package/chunks/{nonInteractiveCli-GYKHG7RX.js → nonInteractiveCli-GPT3TVOK.js} +96 -98
- package/chunks/{notebook-edit-HOJLHP3F.js → notebook-edit-3WCVRNGL.js} +27 -30
- package/chunks/{openaiContentGenerator-ZAJTUWVO.js → openaiContentGenerator-OGILGUZE.js} +12 -17
- package/chunks/{openaiResponsesContentGenerator-AWRYZLJU.js → openaiResponsesContentGenerator-NXOXUPFM.js} +45 -13
- package/chunks/{pidfile-CS7LHAN5.js → pidfile-GBTBIGHF.js} +39 -42
- package/chunks/{process-registry-X6ZCASEN.js → process-registry-7LAPI3ZB.js} +1 -1
- package/chunks/{processUtils-OWQU3JQM.js → processUtils-O4II3RYH.js} +2 -2
- package/chunks/{prompt-terminal-ledger-76P527XD.js → prompt-terminal-ledger-ILIXZI3E.js} +40 -43
- package/chunks/{pt-5ZF7ZQUV.js → pt-FYYFWYUC.js} +11 -0
- package/chunks/{qwenContentGenerator-QZCQ3UTX.js → qwenContentGenerator-I4LRYADV.js} +33 -36
- package/chunks/{qwenOAuth2-WIEUEFEY.js → qwenOAuth2-3J66TOT5.js} +6 -7
- package/chunks/{read-file-KR5BES2E.js → read-file-G4XKW2CS.js} +5 -9
- package/chunks/{record-artifact-PXMNP7GZ.js → record-artifact-L3CFJOMA.js} +2 -2
- package/chunks/{report-findings-W6GR7SYZ.js → report-findings-LY5HQY4K.js} +3 -3
- package/chunks/{resumeHistoryUtils-36NM5S3D.js → resumeHistoryUtils-YPJU4XFE.js} +44 -47
- package/chunks/{ripGrep-QGFIVODS.js → ripGrep-AAKMALLM.js} +7 -11
- package/chunks/{ru-7BNZFQKG.js → ru-RHEB3RNS.js} +11 -0
- package/chunks/{run-qwen-serve-UFEOUIDD.js → run-qwen-serve-ZVEKGS7Y.js} +177 -98
- package/chunks/{runtime-7LTR2C7Q.js → runtime-SJCRYNPA.js} +52 -55
- package/chunks/safe-mode-KLGUG54M.js +11 -0
- package/chunks/sandbox-UIXL423Z.js +146 -0
- package/chunks/sandboxConfig-CY343YNJ.js +114 -0
- package/chunks/{scheduled-tasks-MV22T3JO.js → scheduled-tasks-5UGBEVNZ.js} +50 -53
- package/chunks/{scheduler-HSNQ53ML.js → scheduler-GCZYLZ2P.js} +41 -44
- package/chunks/{sdk-exporters-http-3R2TRQHE.js → sdk-exporters-http-DR4G663K.js} +1 -1
- package/chunks/{sdk-impl-4WF3VZ2F.js → sdk-impl-SJR26MQF.js} +3 -3
- package/chunks/{send-message-UMJKN27Q.js → send-message-DN76MXDX.js} +6 -6
- package/chunks/{serve-LDD4FEJQ.js → serve-2XXQLVK2.js} +48 -51
- package/chunks/{server-IKTZFW3E.js → server-UHMKPCAZ.js} +408 -211
- package/chunks/{session-T77EXOOI.js → session-ZLUK7E4P.js} +108 -108
- package/chunks/{session-attachments-root-FBASBVAO.js → session-attachments-root-DHQM5IEZ.js} +39 -42
- package/chunks/{session-pr-refresh-2BHKIMIN.js → session-pr-refresh-3OMTQWCZ.js} +48 -51
- package/chunks/{settings-TJNUFBGG.js → settings-P4DHIIUP.js} +50 -53
- package/chunks/{shell-HDI5VPGD.js → shell-IMFUVQQ5.js} +27 -30
- package/chunks/{skill-VTA6FNDX.js → skill-NB5RJGZW.js} +7 -11
- package/chunks/{skill-settings-K4LSGCKA.js → skill-settings-IXG5CTQO.js} +47 -50
- package/chunks/{spawnChannel-YSGSPD5D.js → spawnChannel-Q3YALTCJ.js} +44 -45
- package/chunks/{standalone-update-O5LYCCMB.js → standalone-update-H5OJ7MM7.js} +41 -44
- package/chunks/{start-opentui-ui-CS6HKYCE.js → start-opentui-ui-JKAIWGF7.js} +733 -386
- package/chunks/{startInteractiveUI-IVP5HEDD.js → startInteractiveUI-YRPOT6GH.js} +370 -337
- package/chunks/task-create-75HVPEAH.js +1 -1
- package/chunks/{team-create-DW4KE2PR.js → team-create-2XTBYRJF.js} +31 -34
- package/chunks/{team-plan-approval-33UL4JDG.js → team-plan-approval-CFNWW7ZQ.js} +27 -30
- package/chunks/{terminal-image-renderer-4FK76L22.js → terminal-image-renderer-UDPJPGPQ.js} +39 -42
- package/chunks/{theme-manager-UQ3EKEJ4.js → theme-manager-SK57EKMO.js} +39 -42
- package/chunks/{tool-search-QUOG6M6M.js → tool-search-ZHTJU2MV.js} +5 -9
- package/chunks/{total-session-admission-QRWPWSK5.js → total-session-admission-UUZBDQCG.js} +47 -50
- package/chunks/{tree-sitter-ALGO6NDO.js → tree-sitter-4D7QS7F6.js} +1 -1
- package/chunks/{tree-sitter-bash-H6YH7EBF.js → tree-sitter-bash-VEJGF5XF.js} +1 -1
- package/chunks/{trustedFolders-HESP75BK.js → trustedFolders-4LDBLNTS.js} +40 -43
- package/chunks/{update-relaunch-YROJ7A26.js → update-relaunch-LI7GRP36.js} +5 -5
- package/chunks/{updateCheck-CUKTRHID.js → updateCheck-PKSSORPO.js} +43 -46
- package/chunks/{useAutoAcceptIndicator-BQGSRBHX.js → useAutoAcceptIndicator-I32UEQPI.js} +50 -53
- package/chunks/{validateNonInterActiveAuth-UM5U2ZZI.js → validateNonInterActiveAuth-YFPCYYNL.js} +93 -95
- package/chunks/{version-A6G2KO4K.js → version-4MTL4JVU.js} +1 -1
- package/chunks/{web-fetch-A3RMCVQY.js → web-fetch-O6RG6ISB.js} +9 -13
- package/chunks/{web-search-3XGJ773E.js → web-search-JHAXVEMD.js} +9 -14
- package/chunks/{web-shell-static-T7UGLVE4.js → web-shell-static-FFWCUUZS.js} +8 -4
- package/chunks/{workflow-4TWAFNIB.js → workflow-O7L6VDYU.js} +396 -113
- package/chunks/{workspace-providers-status-GNTJ4OIZ.js → workspace-providers-status-WRX6CJM4.js} +53 -56
- package/chunks/{workspace-registration-store-D3K34O63.js → workspace-registration-store-7G4E7YPY.js} +1 -1
- package/chunks/{workspace-registry-ZE5ZSWNF.js → workspace-registry-SXIMGT4D.js} +47 -50
- package/chunks/{workspace-runtime-coordinator-DEXM2635.js → workspace-runtime-coordinator-7DOEHXYT.js} +47 -50
- package/chunks/{workspace-service-OGYORPWD.js → workspace-service-HDXOZMYC.js} +53 -56
- package/chunks/{workspace-skills-status-4W4H3BGJ.js → workspace-skills-status-VN4L37CA.js} +50 -53
- package/chunks/{workspace-trust-reconciler-BHR7S7UJ.js → workspace-trust-reconciler-XEBW5FUL.js} +57 -60
- package/chunks/{write-file-EP5AEO5E.js → write-file-LKX4ETIO.js} +29 -32
- package/chunks/{zh-V2EYTYJP.js → zh-F76MZTL3.js} +23 -1
- package/chunks/{zh-TW-7PRVUGLW.js → zh-TW-S3YTQ4DS.js} +23 -1
- package/chunks/{zoom-image-DDEGWG3R.js → zoom-image-RDPRTP4B.js} +5 -9
- package/cli.js +19 -15
- package/export-transcript-document.css +1 -1
- package/export-transcript-document.js +151 -150
- package/locales/ca.js +19 -2
- package/locales/de.js +18 -0
- package/locales/en.js +33 -2
- package/locales/fr.js +18 -0
- package/locales/ja.js +18 -0
- package/locales/pt.js +18 -0
- package/locales/ru.js +18 -0
- package/locales/zh-TW.js +33 -2
- package/locales/zh.js +33 -2
- package/package.json +3 -3
- package/web-shell/assets/{abnfDiagram-VCTEODGH-BtpzKw3A.js → abnfDiagram-VCTEODGH-RxykUDmi.js} +1 -1
- package/web-shell/assets/{arc-CQiVKZJP.js → arc-CZpgGCJC.js} +1 -1
- package/web-shell/assets/{architectureDiagram-5GKGNRK7-ekIPBb2d.js → architectureDiagram-5GKGNRK7-BHSMzNDT.js} +1 -1
- package/web-shell/assets/{blockDiagram-NRAW4CY4-BrRWkWri.js → blockDiagram-NRAW4CY4-Bn4mF9SZ.js} +1 -1
- package/web-shell/assets/{c4Diagram-UCG6FXSJ-qYS8CYZ3.js → c4Diagram-UCG6FXSJ-CBM-Bj6t.js} +1 -1
- package/web-shell/assets/channel-DFYs_LlK.js +1 -0
- package/web-shell/assets/{chunk-2Q5K7J3B-ZasyyEZm.js → chunk-2Q5K7J3B-D5Fin58O.js} +1 -1
- package/web-shell/assets/{chunk-5VM5RSS4-C_IzCGeA.js → chunk-5VM5RSS4-CY05weF7.js} +1 -1
- package/web-shell/assets/{chunk-F27PBJKO-C25NZOyD.js → chunk-F27PBJKO-3neZnj5Y.js} +1 -1
- package/web-shell/assets/{chunk-G27WJ6UU-XPOHNSGX.js → chunk-G27WJ6UU-Cd7EU4BE.js} +1 -1
- package/web-shell/assets/{chunk-JWPE2WC7-BQBh0Xni.js → chunk-JWPE2WC7-DwK1mqFw.js} +1 -1
- package/web-shell/assets/{chunk-LCL6LL3I-CoShjpX7.js → chunk-LCL6LL3I-Sl7vY22C.js} +1 -1
- package/web-shell/assets/{chunk-POPQ4Y6H-BwRmCDSz.js → chunk-POPQ4Y6H-BXNzpbVg.js} +1 -1
- package/web-shell/assets/{chunk-SVP7TREG-DSzE5-Mw.js → chunk-SVP7TREG-DjjButcp.js} +1 -1
- package/web-shell/assets/{chunk-XXDRQBXY-BQSQv30h.js → chunk-XXDRQBXY-DNOiCjOJ.js} +1 -1
- package/web-shell/assets/classDiagram-DTDB5LWJ-DnGrKXoM.js +1 -0
- package/web-shell/assets/classDiagram-v2-JRS7N3AN-DnGrKXoM.js +1 -0
- package/web-shell/assets/{cose-bilkent-JH36ORCC-XVUVTHVo.js → cose-bilkent-JH36ORCC-BUnker7a.js} +1 -1
- package/web-shell/assets/{cynefin-OW5HDTMX-CrsKx4lQ.js → cynefin-OW5HDTMX-DcUgdWE5.js} +1 -1
- package/web-shell/assets/{cynefinDiagram-5FMLGOSQ-BPeZEuHw.js → cynefinDiagram-5FMLGOSQ-CvDKsZsL.js} +1 -1
- package/web-shell/assets/{dagre-3AP2YEHR-D31cQ2Qs.js → dagre-3AP2YEHR-jpCmUbr1.js} +1 -1
- package/web-shell/assets/{diagram-S7CK7UJ4-zyiG097Q.js → diagram-S7CK7UJ4-DBe_bKE5.js} +1 -1
- package/web-shell/assets/{diagram-UQ7AKVKN-Br3vtfsy.js → diagram-UQ7AKVKN-oXvPpDgs.js} +1 -1
- package/web-shell/assets/{diagram-VSXAHHWV-Bxkhjx4u.js → diagram-VSXAHHWV-BD7-_SGh.js} +1 -1
- package/web-shell/assets/{diagram-VX7I27RA-BQH8QiDk.js → diagram-VX7I27RA-DOJL0wub.js} +1 -1
- package/web-shell/assets/{diagram-Z3DM3KII-B_aQ1cw0.js → diagram-Z3DM3KII-DRIiodDD.js} +1 -1
- package/web-shell/assets/{ebnfDiagram-PWID7BFC-B9N7BRQE.js → ebnfDiagram-PWID7BFC-Db31Ulmb.js} +1 -1
- package/web-shell/assets/{erDiagram-SSCWMZ5O-Cx6Hb1Re.js → erDiagram-SSCWMZ5O-CVHhwI2_.js} +1 -1
- package/web-shell/assets/{flowDiagram-A5DVABFB-DTuLP7GU.js → flowDiagram-A5DVABFB-DWOFy1FK.js} +1 -1
- package/web-shell/assets/{ganttDiagram-EL5Y4UJY-DYS3d-sL.js → ganttDiagram-EL5Y4UJY-C0sxQtPd.js} +1 -1
- package/web-shell/assets/{gitGraphDiagram-WWUBYQGX-Cp0EGx04.js → gitGraphDiagram-WWUBYQGX-CNituBYC.js} +1 -1
- package/web-shell/assets/index-B15NlwB8.js +2213 -0
- package/web-shell/assets/index-BSrS0tQ6.css +36 -0
- package/web-shell/assets/{index-45-LkPDB.js → index-gm9tLk7h.js} +1 -1
- package/web-shell/assets/{infoDiagram-RXCK75RN-9--kukiT.js → infoDiagram-RXCK75RN-CxhJYtIR.js} +1 -1
- package/web-shell/assets/{ishikawaDiagram-5VMMS53U-CGBdsDLD.js → ishikawaDiagram-5VMMS53U-By2mchUy.js} +1 -1
- package/web-shell/assets/{journeyDiagram-EYS64GPL-DeXhcscd.js → journeyDiagram-EYS64GPL-CVH-OweI.js} +1 -1
- package/web-shell/assets/{kanban-definition-3QL26DDD-CFdvsU3b.js → kanban-definition-3QL26DDD-Cc9dQXLy.js} +1 -1
- package/web-shell/assets/knowledge-Dg9788h4.svg +1 -0
- package/web-shell/assets/{layout-DAnwQ3KB.js → layout-C_60ysHw.js} +1 -1
- package/web-shell/assets/{linear-CTo7v7Nh.js → linear-BvAVfqwu.js} +1 -1
- package/web-shell/assets/{mermaid.core-jggSxF1i.js → mermaid.core-C3CoBKAc.js} +6 -6
- package/web-shell/assets/{mindmap-definition-FBJOCRG2-DzIepvlJ.js → mindmap-definition-FBJOCRG2-Cuu8Q8LM.js} +1 -1
- package/web-shell/assets/{pegDiagram-XKGWAZYB-BFGS9GJv.js → pegDiagram-XKGWAZYB-DmAeyDO2.js} +1 -1
- package/web-shell/assets/{pieDiagram-E7YTZNPT-B2UUcNIT.js → pieDiagram-E7YTZNPT-B7vbB_xv.js} +1 -1
- package/web-shell/assets/{quadrantDiagram-AXDQQJYC-BgM6htrX.js → quadrantDiagram-AXDQQJYC-BqOBkRR7.js} +1 -1
- package/web-shell/assets/{railroadDiagram-O6MQD6OU-Dk9cS7N-.js → railroadDiagram-O6MQD6OU-sI06lZIu.js} +1 -1
- package/web-shell/assets/{requirementDiagram-EFPCY7ZU-C9oRg7xi.js → requirementDiagram-EFPCY7ZU-Bg13d10S.js} +1 -1
- package/web-shell/assets/{sankeyDiagram-P5KCCOFB-B-_c7GzI.js → sankeyDiagram-P5KCCOFB-WFOzZHrR.js} +1 -1
- package/web-shell/assets/{sequenceDiagram-WJ2MYXX4-R0M-347u.js → sequenceDiagram-WJ2MYXX4-CCdRbA4E.js} +1 -1
- package/web-shell/assets/{sizeCapture-X5ZJPWSS-Df0f8UAW.js → sizeCapture-X5ZJPWSS-BH5F3bGg.js} +1 -1
- package/web-shell/assets/{stateDiagram-HBIQ2CUA-CsUEfAA-.js → stateDiagram-HBIQ2CUA-NwS2X3QB.js} +1 -1
- package/web-shell/assets/stateDiagram-v2-4QOOHH4V-1aU2JZXO.js +1 -0
- package/web-shell/assets/{swimlanes-XN3QIQJK-9OGHVSrx.js → swimlanes-XN3QIQJK-Bm38pM28.js} +1 -1
- package/web-shell/assets/swimlanesDiagram-VK2B7HYN-Dp-u6kQG.js +8 -0
- package/web-shell/assets/{timeline-definition-24CTP7MA-DAfGqS2B.js → timeline-definition-24CTP7MA-Do-agLSo.js} +1 -1
- package/web-shell/assets/{vennDiagram-4TSXK5OY-CKATpwHi.js → vennDiagram-4TSXK5OY-aggLfZzl.js} +1 -1
- package/web-shell/assets/{wardleyDiagram-VM6X3IG4-CQHdhTrm.js → wardleyDiagram-VM6X3IG4-D5JR3mXX.js} +1 -1
- package/web-shell/assets/{xychartDiagram-S5SC5T6Z-5k9NLqlY.js → xychartDiagram-S5SC5T6Z-DhtLDuXs.js} +1 -1
- package/web-shell/index.html +2 -2
- package/chunks/chunk-7MIBD3LG.js +0 -137
- package/chunks/chunk-ARDHE6MM.js +0 -235
- package/chunks/chunk-C75BXMPM.js +0 -169
- package/chunks/chunk-ERU3SDXT.js +0 -27
- package/chunks/chunk-FPGTNKCP.js +0 -251
- package/chunks/chunk-JL6APGBX.js +0 -43
- package/chunks/chunk-L5OBTAXN.js +0 -137
- package/chunks/chunk-MZ3W3F44.js +0 -4172
- package/chunks/chunk-OIDF7L67.js +0 -514
- package/chunks/chunk-VSXX6VUI.js +0 -2812
- package/chunks/chunk-ZFYACOVD.js +0 -1416
- package/web-shell/assets/channel-DSQQnOZj.js +0 -1
- package/web-shell/assets/classDiagram-DTDB5LWJ-V94ta08R.js +0 -1
- package/web-shell/assets/classDiagram-v2-JRS7N3AN-V94ta08R.js +0 -1
- package/web-shell/assets/index-H8um-iEl.js +0 -2207
- package/web-shell/assets/index-n6N-2a3v.css +0 -36
- package/web-shell/assets/stateDiagram-v2-4QOOHH4V-CnSuTPJ2.js +0 -1
- package/web-shell/assets/swimlanesDiagram-VK2B7HYN-Bb7TcWQw.js +0 -8
- package/chunks/{chunk-QZW6WRB7.js → chunk-5NUKK2DT.js} +2 -2
- package/chunks/{chunk-JS73NNWF.js → chunk-FUSEMYFX.js} +0 -0
- package/chunks/{chunk-SVWWF5TZ.js → chunk-WVURIAEE.js} +3 -3
- package/chunks/{task-update-RI7QNVDP.js → task-update-3LSYQDRW.js} +4 -4
|
@@ -0,0 +1,2796 @@
|
|
|
1
|
+
// Force strict mode and setup for ESM
|
|
2
|
+
"use strict";
|
|
3
|
+
import {
|
|
4
|
+
AgentEventEmitter,
|
|
5
|
+
MAX_TURN_BUDGET_TOKENS,
|
|
6
|
+
MAX_WORKFLOW_CALL_TRACES,
|
|
7
|
+
attachJsonlTranscriptWriter,
|
|
8
|
+
buildAgentTranscriptAttach,
|
|
9
|
+
createWorkflowSandbox,
|
|
10
|
+
debugLogger,
|
|
11
|
+
deleteInlineWorkflowScript,
|
|
12
|
+
deriveApprovalModeConfig,
|
|
13
|
+
deriveConfig,
|
|
14
|
+
deriveWorktreeConfig,
|
|
15
|
+
installSessionWorkflowRevisionWriteThrough,
|
|
16
|
+
isActiveWorkflowStatus,
|
|
17
|
+
isSymlinkedRoot,
|
|
18
|
+
isTerminalWorkflowStatus,
|
|
19
|
+
isWorkflowRunPersistenceActive,
|
|
20
|
+
isWorkflowSizeWarning,
|
|
21
|
+
isWorkflowSourceRef,
|
|
22
|
+
parseSkillContent,
|
|
23
|
+
readWorkflowSourceRef,
|
|
24
|
+
readWorkflowStepId,
|
|
25
|
+
rebuildToolRegistryOnOverride,
|
|
26
|
+
resolveExternalWorktreeDir,
|
|
27
|
+
toModelVisibleSubagentResult
|
|
28
|
+
} from "./chunk-KAYC5FBN.js";
|
|
29
|
+
import {
|
|
30
|
+
parsePositiveIntegerEnv
|
|
31
|
+
} from "./chunk-6PVPNMXU.js";
|
|
32
|
+
import {
|
|
33
|
+
GitWorktreeService,
|
|
34
|
+
generateAgentWorktreeSlug,
|
|
35
|
+
writeWorktreeSessionMarker
|
|
36
|
+
} from "./chunk-CXONOVBN.js";
|
|
37
|
+
import {
|
|
38
|
+
resolveBundleDir
|
|
39
|
+
} from "./chunk-ACHCT36C.js";
|
|
40
|
+
import {
|
|
41
|
+
SUBAGENT_PLAN_LIFECYCLE_TOOLS
|
|
42
|
+
} from "./chunk-AEWCOE64.js";
|
|
43
|
+
import {
|
|
44
|
+
runWithAgentContext
|
|
45
|
+
} from "./chunk-BW2SMO6L.js";
|
|
46
|
+
import {
|
|
47
|
+
read,
|
|
48
|
+
uiTelemetryService,
|
|
49
|
+
writeLine
|
|
50
|
+
} from "./chunk-CDDP4ONL.js";
|
|
51
|
+
import {
|
|
52
|
+
REASONING_EFFORT_TIERS,
|
|
53
|
+
normalizeReasoningEffort
|
|
54
|
+
} from "./chunk-GJKP6XOB.js";
|
|
55
|
+
import {
|
|
56
|
+
stripAnsiAndControl
|
|
57
|
+
} from "./chunk-6USYH3EU.js";
|
|
58
|
+
import {
|
|
59
|
+
SyntheticOutputTool
|
|
60
|
+
} from "./chunk-SYROIHU7.js";
|
|
61
|
+
import {
|
|
62
|
+
ToolNames,
|
|
63
|
+
resolveBuiltinToolName
|
|
64
|
+
} from "./chunk-RSWBT7AZ.js";
|
|
65
|
+
import {
|
|
66
|
+
createDebugLogger
|
|
67
|
+
} from "./chunk-ZAFYHRVY.js";
|
|
68
|
+
import {
|
|
69
|
+
init_esbuild_shims
|
|
70
|
+
} from "./chunk-5O2XNYP6.js";
|
|
71
|
+
import {
|
|
72
|
+
__name
|
|
73
|
+
} from "./chunk-J2S4EL5Y.js";
|
|
74
|
+
|
|
75
|
+
// packages/core/src/agents/runtime/workflow-budget.ts
|
|
76
|
+
init_esbuild_shims();
|
|
77
|
+
var debugLogger2 = createDebugLogger("WORKFLOW_BUDGET");
|
|
78
|
+
var MAX_TOKENS_PER_WORKFLOW_ENV = "QWEN_CODE_MAX_TOKENS_PER_WORKFLOW";
|
|
79
|
+
var HARD_MAX_TOKENS_CEILING = MAX_TURN_BUDGET_TOKENS;
|
|
80
|
+
function resolveMaxTokensPerWorkflow(env = process.env) {
|
|
81
|
+
const raw = env[MAX_TOKENS_PER_WORKFLOW_ENV];
|
|
82
|
+
if (raw === void 0 || raw.trim() === "") {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
const parsed = parsePositiveIntegerEnv(raw, 0);
|
|
86
|
+
if (parsed < 1) {
|
|
87
|
+
debugLogger2.warn(
|
|
88
|
+
`Invalid ${MAX_TOKENS_PER_WORKFLOW_ENV}=${JSON.stringify(raw)}, treating as unset (no cap)`
|
|
89
|
+
);
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
if (parsed > HARD_MAX_TOKENS_CEILING) {
|
|
93
|
+
debugLogger2.warn(
|
|
94
|
+
`${MAX_TOKENS_PER_WORKFLOW_ENV}=${parsed} exceeds hard ceiling (${HARD_MAX_TOKENS_CEILING}); clamping.`
|
|
95
|
+
);
|
|
96
|
+
return HARD_MAX_TOKENS_CEILING;
|
|
97
|
+
}
|
|
98
|
+
return parsed;
|
|
99
|
+
}
|
|
100
|
+
__name(resolveMaxTokensPerWorkflow, "resolveMaxTokensPerWorkflow");
|
|
101
|
+
var WorkflowBudgetImpl = class _WorkflowBudgetImpl {
|
|
102
|
+
static {
|
|
103
|
+
__name(this, "WorkflowBudgetImpl");
|
|
104
|
+
}
|
|
105
|
+
total;
|
|
106
|
+
source;
|
|
107
|
+
directiveText;
|
|
108
|
+
turnSpent;
|
|
109
|
+
_runSpent;
|
|
110
|
+
constructor(total, options = {}) {
|
|
111
|
+
this.total = total;
|
|
112
|
+
this.source = total === null ? void 0 : options.source ?? "env";
|
|
113
|
+
this.directiveText = this.source === "directive" ? options.directiveText : void 0;
|
|
114
|
+
this.turnSpent = options.turnSpent;
|
|
115
|
+
this._runSpent = 0;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* What the gate and the script measure against `total`: the turn's spend,
|
|
119
|
+
* unless the total is an operator's per-run cap.
|
|
120
|
+
*/
|
|
121
|
+
spent() {
|
|
122
|
+
if (this.source !== "env" && this.turnSpent) return this.turnSpent();
|
|
123
|
+
return this._runSpent;
|
|
124
|
+
}
|
|
125
|
+
/** Output tokens this run's own agents reported. */
|
|
126
|
+
runSpent() {
|
|
127
|
+
return this._runSpent;
|
|
128
|
+
}
|
|
129
|
+
/** The cap on this run alone: only an operator's env cap is per run. */
|
|
130
|
+
runCap() {
|
|
131
|
+
return this.source === "env" ? this.total : null;
|
|
132
|
+
}
|
|
133
|
+
remaining() {
|
|
134
|
+
if (this.total === null) return Infinity;
|
|
135
|
+
return Math.max(0, this.total - this.spent());
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Host-side increment. NOT exposed to the script — the
|
|
139
|
+
* `WorkflowBudget` interface deliberately omits any setter so a
|
|
140
|
+
* malicious workflow cannot inflate / deflate the budget. Only the
|
|
141
|
+
* production dispatch's `onTokens` callback calls this after a dispatch
|
|
142
|
+
* settles with the agent's output token count.
|
|
143
|
+
*
|
|
144
|
+
* Non-positive deltas are silently dropped (some dispatches return
|
|
145
|
+
* `output_tokens: 0` on early failures); negative deltas would be a
|
|
146
|
+
* caller bug and are also dropped rather than silently rewinding
|
|
147
|
+
* the counter.
|
|
148
|
+
*/
|
|
149
|
+
recordSpent(deltaTokens) {
|
|
150
|
+
if (!Number.isFinite(deltaTokens) || deltaTokens <= 0) return;
|
|
151
|
+
this._runSpent += deltaTokens;
|
|
152
|
+
}
|
|
153
|
+
/** A per-run budget from the environment alone, with no turn. */
|
|
154
|
+
static fromEnv(env = process.env) {
|
|
155
|
+
return new _WorkflowBudgetImpl(resolveMaxTokensPerWorkflow(env));
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* The budget for a run launched now: the turn's directive when the current
|
|
159
|
+
* turn set one, else the env cap, else none. The turn is read once — a run
|
|
160
|
+
* that outlives its turn keeps measuring against the turn it started in.
|
|
161
|
+
*/
|
|
162
|
+
static fromConfig(config, env = process.env) {
|
|
163
|
+
const sessionId = config.getSessionId?.();
|
|
164
|
+
const turn = sessionId === void 0 ? null : config.getTurnBudget?.()?.current(sessionId) ?? null;
|
|
165
|
+
const turnSpent = turn ? () => Math.max(
|
|
166
|
+
0,
|
|
167
|
+
uiTelemetryService.getTotalOutputTokens(turn.sessionId) - turn.outputTokensAtTurnStart
|
|
168
|
+
) : void 0;
|
|
169
|
+
if (turn && turn.budget !== null) {
|
|
170
|
+
return new _WorkflowBudgetImpl(turn.budget, {
|
|
171
|
+
source: "directive",
|
|
172
|
+
turnSpent,
|
|
173
|
+
directiveText: turn.directiveText
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
const envCap = resolveMaxTokensPerWorkflow(env);
|
|
177
|
+
if (envCap !== null) {
|
|
178
|
+
return new _WorkflowBudgetImpl(envCap, { source: "env" });
|
|
179
|
+
}
|
|
180
|
+
return new _WorkflowBudgetImpl(null, { turnSpent });
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
var WorkflowBudgetExceededError = class extends Error {
|
|
184
|
+
static {
|
|
185
|
+
__name(this, "WorkflowBudgetExceededError");
|
|
186
|
+
}
|
|
187
|
+
name = "WorkflowBudgetExceededError";
|
|
188
|
+
runId;
|
|
189
|
+
budgetTotal;
|
|
190
|
+
spent;
|
|
191
|
+
constructor(runId, budgetTotal, spent) {
|
|
192
|
+
super(
|
|
193
|
+
`Workflow ${runId}: token budget exceeded (${spent} / ${budgetTotal} output tokens). Stopping further agent() calls.`
|
|
194
|
+
);
|
|
195
|
+
this.runId = runId;
|
|
196
|
+
this.budgetTotal = budgetTotal;
|
|
197
|
+
this.spent = spent;
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
// packages/core/src/agents/runtime/workflow-orchestrator.ts
|
|
202
|
+
init_esbuild_shims();
|
|
203
|
+
import { randomBytes } from "node:crypto";
|
|
204
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
205
|
+
import * as os from "node:os";
|
|
206
|
+
|
|
207
|
+
// packages/core/src/agents/runtime/workflow-agent-failure.ts
|
|
208
|
+
init_esbuild_shims();
|
|
209
|
+
var WorkflowAgentFailedError = class extends Error {
|
|
210
|
+
static {
|
|
211
|
+
__name(this, "WorkflowAgentFailedError");
|
|
212
|
+
}
|
|
213
|
+
name = "WorkflowAgentFailedError";
|
|
214
|
+
kind;
|
|
215
|
+
terminateMode;
|
|
216
|
+
constructor(message, kind, terminateMode) {
|
|
217
|
+
super(message);
|
|
218
|
+
this.kind = kind;
|
|
219
|
+
this.terminateMode = terminateMode;
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
function isWorkflowAgentFailedError(error) {
|
|
223
|
+
return typeof error === "object" && error !== null && error.name === "WorkflowAgentFailedError";
|
|
224
|
+
}
|
|
225
|
+
__name(isWorkflowAgentFailedError, "isWorkflowAgentFailedError");
|
|
226
|
+
var WorkflowAgentCapExceededError = class extends Error {
|
|
227
|
+
static {
|
|
228
|
+
__name(this, "WorkflowAgentCapExceededError");
|
|
229
|
+
}
|
|
230
|
+
name = "WorkflowAgentCapExceededError";
|
|
231
|
+
constructor(maxAgents) {
|
|
232
|
+
super(
|
|
233
|
+
`Workflow exceeded the maximum of ${maxAgents} agent() calls per run. This usually means a loop using budget.remaining() never terminates because no token budget was set \u2014 remaining() returns Infinity when budget.total is null. Add a hard iteration cap to the loop, or pass a token budget.`
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
function isWorkflowRunLevelError(error) {
|
|
238
|
+
if (typeof error !== "object" || error === null) return false;
|
|
239
|
+
const name = error.name;
|
|
240
|
+
return name === "WorkflowBudgetExceededError" || name === "WorkflowAgentCapExceededError";
|
|
241
|
+
}
|
|
242
|
+
__name(isWorkflowRunLevelError, "isWorkflowRunLevelError");
|
|
243
|
+
var WORKFLOW_ABORT_REASON_STALLED = "stalled";
|
|
244
|
+
|
|
245
|
+
// packages/core/src/agents/runtime/workflow-stall.ts
|
|
246
|
+
init_esbuild_shims();
|
|
247
|
+
var DEFAULT_STALL_MS = 18e4;
|
|
248
|
+
var MAX_STALL_ATTEMPTS = 3;
|
|
249
|
+
var MAX_WORKFLOW_STALL_MS_ENV = "QWEN_CODE_WORKFLOW_STALL_SECONDS";
|
|
250
|
+
function resolveStallMs(perCall, env = process.env) {
|
|
251
|
+
if (typeof perCall === "number" && Number.isFinite(perCall)) {
|
|
252
|
+
if (perCall === 0) return 0;
|
|
253
|
+
if (perCall > 0) return perCall;
|
|
254
|
+
}
|
|
255
|
+
const raw = env[MAX_WORKFLOW_STALL_MS_ENV];
|
|
256
|
+
const trimmed = raw?.trim();
|
|
257
|
+
if (trimmed) {
|
|
258
|
+
if (trimmed === "0") return 0;
|
|
259
|
+
const sec = parsePositiveIntegerEnv(trimmed, 0);
|
|
260
|
+
if (sec > 0) return sec * 1e3;
|
|
261
|
+
}
|
|
262
|
+
return DEFAULT_STALL_MS;
|
|
263
|
+
}
|
|
264
|
+
__name(resolveStallMs, "resolveStallMs");
|
|
265
|
+
var debugLogger3 = createDebugLogger("WORKFLOW_STALL");
|
|
266
|
+
function attachStallWatchdog(emitter, controller, stallMs) {
|
|
267
|
+
if (stallMs <= 0) {
|
|
268
|
+
return { stalled: /* @__PURE__ */ __name(() => false, "stalled"), dispose: /* @__PURE__ */ __name(() => {
|
|
269
|
+
}, "dispose") };
|
|
270
|
+
}
|
|
271
|
+
let inFlightTools = 0;
|
|
272
|
+
let fired = false;
|
|
273
|
+
let timer;
|
|
274
|
+
let disposed = false;
|
|
275
|
+
const clear = /* @__PURE__ */ __name(() => {
|
|
276
|
+
if (timer) {
|
|
277
|
+
clearTimeout(timer);
|
|
278
|
+
timer = void 0;
|
|
279
|
+
}
|
|
280
|
+
}, "clear");
|
|
281
|
+
const arm = /* @__PURE__ */ __name(() => {
|
|
282
|
+
clear();
|
|
283
|
+
if (disposed || fired) return;
|
|
284
|
+
if (inFlightTools > 0) return;
|
|
285
|
+
timer = setTimeout(() => {
|
|
286
|
+
if (disposed || fired) return;
|
|
287
|
+
fired = true;
|
|
288
|
+
debugLogger3.warn(
|
|
289
|
+
`[Workflow] agent dispatch stalled \u2014 no progress for ${stallMs}ms; aborting.`
|
|
290
|
+
);
|
|
291
|
+
try {
|
|
292
|
+
controller.abort(WORKFLOW_ABORT_REASON_STALLED);
|
|
293
|
+
} catch (e) {
|
|
294
|
+
debugLogger3.warn("stall watchdog abort threw:", e);
|
|
295
|
+
}
|
|
296
|
+
}, stallMs);
|
|
297
|
+
if (typeof timer.unref === "function") {
|
|
298
|
+
timer.unref();
|
|
299
|
+
}
|
|
300
|
+
}, "arm");
|
|
301
|
+
const onActivity = /* @__PURE__ */ __name(() => arm(), "onActivity");
|
|
302
|
+
const onToolCall = /* @__PURE__ */ __name(() => {
|
|
303
|
+
inFlightTools += 1;
|
|
304
|
+
clear();
|
|
305
|
+
}, "onToolCall");
|
|
306
|
+
const onToolResult = /* @__PURE__ */ __name(() => {
|
|
307
|
+
inFlightTools = Math.max(0, inFlightTools - 1);
|
|
308
|
+
arm();
|
|
309
|
+
}, "onToolResult");
|
|
310
|
+
emitter.on("round_start" /* ROUND_START */, onActivity);
|
|
311
|
+
emitter.on("round_end" /* ROUND_END */, onActivity);
|
|
312
|
+
emitter.on("stream_text" /* STREAM_TEXT */, onActivity);
|
|
313
|
+
emitter.on("usage_metadata" /* USAGE_METADATA */, onActivity);
|
|
314
|
+
emitter.on("tool_call" /* TOOL_CALL */, onToolCall);
|
|
315
|
+
emitter.on("tool_result" /* TOOL_RESULT */, onToolResult);
|
|
316
|
+
return {
|
|
317
|
+
stalled: /* @__PURE__ */ __name(() => fired, "stalled"),
|
|
318
|
+
dispose: /* @__PURE__ */ __name(() => {
|
|
319
|
+
if (disposed) return;
|
|
320
|
+
disposed = true;
|
|
321
|
+
clear();
|
|
322
|
+
emitter.off("round_start" /* ROUND_START */, onActivity);
|
|
323
|
+
emitter.off("round_end" /* ROUND_END */, onActivity);
|
|
324
|
+
emitter.off("stream_text" /* STREAM_TEXT */, onActivity);
|
|
325
|
+
emitter.off("usage_metadata" /* USAGE_METADATA */, onActivity);
|
|
326
|
+
emitter.off("tool_call" /* TOOL_CALL */, onToolCall);
|
|
327
|
+
emitter.off("tool_result" /* TOOL_RESULT */, onToolResult);
|
|
328
|
+
}, "dispose")
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
__name(attachStallWatchdog, "attachStallWatchdog");
|
|
332
|
+
async function runStallResilient(attemptFn, opts) {
|
|
333
|
+
const { stallMs, signal, label } = opts;
|
|
334
|
+
if (stallMs <= 0) {
|
|
335
|
+
const emitter = new AgentEventEmitter();
|
|
336
|
+
return attemptFn(signal ?? new AbortController().signal, emitter);
|
|
337
|
+
}
|
|
338
|
+
let attempt = 0;
|
|
339
|
+
for (; ; ) {
|
|
340
|
+
attempt += 1;
|
|
341
|
+
const controller = new AbortController();
|
|
342
|
+
let onParentAbort;
|
|
343
|
+
if (signal) {
|
|
344
|
+
if (signal.aborted) {
|
|
345
|
+
controller.abort(signal.reason);
|
|
346
|
+
} else {
|
|
347
|
+
onParentAbort = /* @__PURE__ */ __name(() => controller.abort(signal.reason), "onParentAbort");
|
|
348
|
+
signal.addEventListener("abort", onParentAbort);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
const emitter = new AgentEventEmitter();
|
|
352
|
+
const watchdog = attachStallWatchdog(emitter, controller, stallMs);
|
|
353
|
+
try {
|
|
354
|
+
return await attemptFn(controller.signal, emitter);
|
|
355
|
+
} catch (err) {
|
|
356
|
+
if (signal?.aborted) throw err;
|
|
357
|
+
if (watchdog.stalled() && attempt < MAX_STALL_ATTEMPTS) {
|
|
358
|
+
debugLogger3.warn(
|
|
359
|
+
`[Workflow] agent "${label ?? "workflow-agent"}" stalled (attempt ${attempt}/${MAX_STALL_ATTEMPTS}) \u2014 retrying.`
|
|
360
|
+
);
|
|
361
|
+
continue;
|
|
362
|
+
}
|
|
363
|
+
if (watchdog.stalled()) {
|
|
364
|
+
throw new WorkflowAgentFailedError(
|
|
365
|
+
`agent "${label ?? "workflow-agent"}" stalled on all ${MAX_STALL_ATTEMPTS} attempts (no progress for ${stallMs}ms each).`,
|
|
366
|
+
"stalled"
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
throw err;
|
|
370
|
+
} finally {
|
|
371
|
+
watchdog.dispose();
|
|
372
|
+
if (onParentAbort && signal) {
|
|
373
|
+
signal.removeEventListener("abort", onParentAbort);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
__name(runStallResilient, "runStallResilient");
|
|
379
|
+
|
|
380
|
+
// packages/core/src/agents/runtime/workflow-journal.ts
|
|
381
|
+
init_esbuild_shims();
|
|
382
|
+
import { createHash } from "node:crypto";
|
|
383
|
+
import { constants, promises as fs } from "node:fs";
|
|
384
|
+
import path from "node:path";
|
|
385
|
+
var debugLogger4 = createDebugLogger("WORKFLOW_JOURNAL");
|
|
386
|
+
var JOURNAL_KEY_VERSION = "v2";
|
|
387
|
+
var DISPATCH_AFFECTING_AGENT_OPTS = [
|
|
388
|
+
"schema",
|
|
389
|
+
"model",
|
|
390
|
+
"effort",
|
|
391
|
+
"isolation",
|
|
392
|
+
"agentType",
|
|
393
|
+
"workingDir",
|
|
394
|
+
"disallowedTools"
|
|
395
|
+
];
|
|
396
|
+
function canonicalizeAgentOpts(opts) {
|
|
397
|
+
const projected = {};
|
|
398
|
+
for (const k of DISPATCH_AFFECTING_AGENT_OPTS) {
|
|
399
|
+
const v = opts[k];
|
|
400
|
+
if (v === void 0 || typeof v === "function") continue;
|
|
401
|
+
projected[k] = v;
|
|
402
|
+
}
|
|
403
|
+
const sortDeep = /* @__PURE__ */ __name((val) => {
|
|
404
|
+
if (typeof val === "function") return void 0;
|
|
405
|
+
if (Array.isArray(val)) return val.map(sortDeep);
|
|
406
|
+
if (val && typeof val === "object") {
|
|
407
|
+
const out = {};
|
|
408
|
+
for (const key of Object.keys(val).sort()) {
|
|
409
|
+
if (key === "__proto__") continue;
|
|
410
|
+
out[key] = sortDeep(val[key]);
|
|
411
|
+
}
|
|
412
|
+
return out;
|
|
413
|
+
}
|
|
414
|
+
return val;
|
|
415
|
+
}, "sortDeep");
|
|
416
|
+
try {
|
|
417
|
+
return JSON.stringify(sortDeep(projected));
|
|
418
|
+
} catch {
|
|
419
|
+
return "{}";
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
__name(canonicalizeAgentOpts, "canonicalizeAgentOpts");
|
|
423
|
+
function deriveAgentKey(prefixHash, prompt, opts) {
|
|
424
|
+
const hash = createHash("sha256");
|
|
425
|
+
hash.update(prefixHash);
|
|
426
|
+
hash.update("\0");
|
|
427
|
+
hash.update(prompt);
|
|
428
|
+
hash.update("\0");
|
|
429
|
+
hash.update(canonicalizeAgentOpts(opts));
|
|
430
|
+
return `${JOURNAL_KEY_VERSION}:${hash.digest("hex")}`;
|
|
431
|
+
}
|
|
432
|
+
__name(deriveAgentKey, "deriveAgentKey");
|
|
433
|
+
function deriveArgsSeed(args) {
|
|
434
|
+
const hash = createHash("sha256");
|
|
435
|
+
let serialized;
|
|
436
|
+
try {
|
|
437
|
+
serialized = JSON.stringify(args ?? null) ?? "null";
|
|
438
|
+
} catch {
|
|
439
|
+
serialized = "non-serializable-args";
|
|
440
|
+
}
|
|
441
|
+
hash.update(serialized);
|
|
442
|
+
return `${JOURNAL_KEY_VERSION}:${hash.digest("hex")}`;
|
|
443
|
+
}
|
|
444
|
+
__name(deriveArgsSeed, "deriveArgsSeed");
|
|
445
|
+
function buildReplay(entries) {
|
|
446
|
+
let sourceRef;
|
|
447
|
+
let sourceError;
|
|
448
|
+
const results = /* @__PURE__ */ new Map();
|
|
449
|
+
const started = /* @__PURE__ */ new Map();
|
|
450
|
+
const failed = /* @__PURE__ */ new Set();
|
|
451
|
+
for (const e of entries) {
|
|
452
|
+
if (e.type === "result") {
|
|
453
|
+
results.set(e.key, e);
|
|
454
|
+
} else if (e.type === "started") {
|
|
455
|
+
failed.delete(e.key);
|
|
456
|
+
const list = started.get(e.key);
|
|
457
|
+
if (list) list.push(e);
|
|
458
|
+
else started.set(e.key, [e]);
|
|
459
|
+
} else if (e.type === "failed") {
|
|
460
|
+
failed.add(e.key);
|
|
461
|
+
} else if (e.type === "source") {
|
|
462
|
+
try {
|
|
463
|
+
const ref = readWorkflowSourceRef(e.sourceRef);
|
|
464
|
+
if (e.version !== 1 || !ref || sourceRef && (sourceRef.id !== ref.id || sourceRef.revision !== ref.revision)) {
|
|
465
|
+
throw new Error("Conflicting or unsupported workflow source record.");
|
|
466
|
+
}
|
|
467
|
+
sourceRef = ref;
|
|
468
|
+
} catch {
|
|
469
|
+
sourceError = "Workflow journal contains invalid source metadata.";
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
return {
|
|
474
|
+
results,
|
|
475
|
+
started,
|
|
476
|
+
failed,
|
|
477
|
+
...sourceRef ? { sourceRef } : {},
|
|
478
|
+
...sourceError ? { sourceError } : {}
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
__name(buildReplay, "buildReplay");
|
|
482
|
+
var WorkflowJournal = class {
|
|
483
|
+
constructor(journalPath, root = path.dirname(path.dirname(journalPath))) {
|
|
484
|
+
this.root = root;
|
|
485
|
+
this.path = journalPath;
|
|
486
|
+
}
|
|
487
|
+
static {
|
|
488
|
+
__name(this, "WorkflowJournal");
|
|
489
|
+
}
|
|
490
|
+
pending = Promise.resolve();
|
|
491
|
+
path;
|
|
492
|
+
async hasSymlinkedPath() {
|
|
493
|
+
if (await isSymlinkedRoot(this.root) || await isSymlinkedRoot(path.dirname(this.path))) {
|
|
494
|
+
return true;
|
|
495
|
+
}
|
|
496
|
+
return fs.lstat(this.path).then((stat) => stat.isSymbolicLink()).catch(() => false);
|
|
497
|
+
}
|
|
498
|
+
/** Ensure the advertised journal path exists without affecting the run. */
|
|
499
|
+
async ensureExists() {
|
|
500
|
+
try {
|
|
501
|
+
if (await this.hasSymlinkedPath()) return false;
|
|
502
|
+
await fs.mkdir(path.dirname(this.path), { recursive: true });
|
|
503
|
+
if (await this.hasSymlinkedPath()) return false;
|
|
504
|
+
const noFollow = process.platform === "win32" ? 0 : constants.O_NOFOLLOW;
|
|
505
|
+
const file = await fs.open(
|
|
506
|
+
this.path,
|
|
507
|
+
constants.O_APPEND | constants.O_CREAT | constants.O_WRONLY | noFollow,
|
|
508
|
+
384
|
|
509
|
+
);
|
|
510
|
+
try {
|
|
511
|
+
await file.chmod(384);
|
|
512
|
+
} finally {
|
|
513
|
+
await file.close();
|
|
514
|
+
}
|
|
515
|
+
return true;
|
|
516
|
+
} catch (error) {
|
|
517
|
+
debugLogger4.warn(
|
|
518
|
+
`WorkflowJournal.ensureExists failed for ${this.path}: ${error}`
|
|
519
|
+
);
|
|
520
|
+
return false;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
/** Remove a never-registered run's journal file, best-effort. */
|
|
524
|
+
async remove() {
|
|
525
|
+
try {
|
|
526
|
+
if (await this.hasSymlinkedPath()) return;
|
|
527
|
+
await fs.rm(this.path, { force: true });
|
|
528
|
+
await fs.rmdir(path.dirname(this.path)).catch((error) => {
|
|
529
|
+
const code = error.code;
|
|
530
|
+
if (code !== "ENOENT" && code !== "ENOTEMPTY") throw error;
|
|
531
|
+
});
|
|
532
|
+
} catch (error) {
|
|
533
|
+
debugLogger4.warn(
|
|
534
|
+
`WorkflowJournal.remove failed for ${this.path}: ${error}`
|
|
535
|
+
);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
/** Load + parse all entries into replay maps. Empty maps if no file. */
|
|
539
|
+
async load() {
|
|
540
|
+
try {
|
|
541
|
+
const entries = await read(this.path);
|
|
542
|
+
return buildReplay(entries);
|
|
543
|
+
} catch (e) {
|
|
544
|
+
debugLogger4.warn(`WorkflowJournal.load failed for ${this.path}: ${e}`);
|
|
545
|
+
return { results: /* @__PURE__ */ new Map(), started: /* @__PURE__ */ new Map(), failed: /* @__PURE__ */ new Set() };
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
/** Append one entry. Rejects only on I/O error (callers `.catch`). */
|
|
549
|
+
append(entry) {
|
|
550
|
+
const operation = this.pending.then(() => writeLine(this.path, entry));
|
|
551
|
+
this.pending = operation.catch(() => void 0);
|
|
552
|
+
return operation;
|
|
553
|
+
}
|
|
554
|
+
/** Wait until every append issued so far has settled. */
|
|
555
|
+
drain() {
|
|
556
|
+
return this.pending;
|
|
557
|
+
}
|
|
558
|
+
};
|
|
559
|
+
|
|
560
|
+
// packages/core/src/agents/runtime/workflow-prompts.ts
|
|
561
|
+
init_esbuild_shims();
|
|
562
|
+
var WORKFLOW_SUBAGENT_SYSTEM_PROMPT = 'You are a subagent spawned by a workflow orchestration script. Use the tools available to complete the task.\nCRITICAL: Your final text response is returned **verbatim** as a string to the calling script \u2014 it is your return value, not a message to a human.\n- Output the literal result (data, JSON, text). Do NOT output confirmations like "Done." or "Sent."\n- If asked for JSON, return ONLY the raw JSON \u2014 no code fences, no prose, no markdown.\n- Do NOT use SendUserMessage to deliver your answer. Put your answer in your final text response.\n- Be concise. The script will parse your output.';
|
|
563
|
+
var WORKFLOW_SUBAGENT_SYSTEM_PROMPT_WITH_SCHEMA = "You are a subagent spawned by a workflow orchestration script. Use the tools available to complete the task.\nCRITICAL: You MUST deliver your final answer by calling the `structured_output` tool with arguments that conform to its parameter schema. Plain-text final answers are DISCARDED \u2014 only a valid `structured_output` call returns a result to the calling script.\n- Use other tools (Read, Grep, etc.) to gather information first.\n- When ready, call `structured_output` ONCE with the conforming JSON object.\n- If validation fails, the error tells you what to fix. Try again with corrected fields.\n- After two failed attempts, the run terminates \u2014 get the arguments right.\n- Do NOT use SendUserMessage to deliver your answer.\n- Be concise; the script reads only the structured payload, not your prose.";
|
|
564
|
+
|
|
565
|
+
// packages/core/src/agents/runtime/workflow-dispatch-scheduler.ts
|
|
566
|
+
init_esbuild_shims();
|
|
567
|
+
function abortError() {
|
|
568
|
+
return new DOMException("Workflow dispatch scheduler aborted.", "AbortError");
|
|
569
|
+
}
|
|
570
|
+
__name(abortError, "abortError");
|
|
571
|
+
var WorkflowDispatchScheduler = class {
|
|
572
|
+
constructor(limit, signal, onStateChange) {
|
|
573
|
+
this.limit = limit;
|
|
574
|
+
this.signal = signal;
|
|
575
|
+
if (!Number.isInteger(limit) || limit < 1) {
|
|
576
|
+
throw new Error(
|
|
577
|
+
`Workflow dispatch limit must be a positive integer, got ${String(limit)}.`
|
|
578
|
+
);
|
|
579
|
+
}
|
|
580
|
+
if (onStateChange) this.stateListeners.add(onStateChange);
|
|
581
|
+
if (signal && !signal.aborted) {
|
|
582
|
+
signal.addEventListener("abort", () => this.abortPending(), {
|
|
583
|
+
once: true
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
static {
|
|
588
|
+
__name(this, "WorkflowDispatchScheduler");
|
|
589
|
+
}
|
|
590
|
+
state = "running";
|
|
591
|
+
inFlight = 0;
|
|
592
|
+
queue = [];
|
|
593
|
+
gateWaiters = [];
|
|
594
|
+
stateListeners = /* @__PURE__ */ new Set();
|
|
595
|
+
/**
|
|
596
|
+
* Subscribe to state transitions. Returns an unsubscribe function.
|
|
597
|
+
* The constructor callback (when given) is registered as the first
|
|
598
|
+
* listener; this method lets additional observers — e.g. the sandbox's
|
|
599
|
+
* pause-aware wall-clock watchdog — hook the same transitions.
|
|
600
|
+
*/
|
|
601
|
+
onStateChange(listener) {
|
|
602
|
+
this.stateListeners.add(listener);
|
|
603
|
+
return () => {
|
|
604
|
+
this.stateListeners.delete(listener);
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
run(thunk) {
|
|
608
|
+
return new Promise((resolve, reject) => {
|
|
609
|
+
if (this.signal?.aborted) {
|
|
610
|
+
reject(abortError());
|
|
611
|
+
return;
|
|
612
|
+
}
|
|
613
|
+
this.queue.push({
|
|
614
|
+
thunk,
|
|
615
|
+
resolve,
|
|
616
|
+
reject
|
|
617
|
+
});
|
|
618
|
+
this.pump();
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
pause() {
|
|
622
|
+
if (this.state !== "running" || this.signal?.aborted) return false;
|
|
623
|
+
this.setState("pausing");
|
|
624
|
+
if (this.inFlight === 0) this.setState("paused");
|
|
625
|
+
return true;
|
|
626
|
+
}
|
|
627
|
+
resume() {
|
|
628
|
+
if (this.state !== "paused" || this.signal?.aborted) return false;
|
|
629
|
+
this.setState("running");
|
|
630
|
+
while (this.gateWaiters.length > 0) {
|
|
631
|
+
this.gateWaiters.shift().resolve();
|
|
632
|
+
}
|
|
633
|
+
this.pump();
|
|
634
|
+
return true;
|
|
635
|
+
}
|
|
636
|
+
waitUntilRunning() {
|
|
637
|
+
if (this.signal?.aborted) return Promise.reject(abortError());
|
|
638
|
+
if (this.state === "running") return Promise.resolve();
|
|
639
|
+
return new Promise((resolve, reject) => {
|
|
640
|
+
this.gateWaiters.push({ resolve, reject });
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
snapshot() {
|
|
644
|
+
return {
|
|
645
|
+
state: this.state,
|
|
646
|
+
queued: this.queue.length,
|
|
647
|
+
inFlight: this.inFlight
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
pump() {
|
|
651
|
+
while (this.state === "running" && this.inFlight < this.limit && this.queue.length > 0) {
|
|
652
|
+
const job = this.queue.shift();
|
|
653
|
+
if (this.signal?.aborted) {
|
|
654
|
+
job.reject(abortError());
|
|
655
|
+
continue;
|
|
656
|
+
}
|
|
657
|
+
this.inFlight++;
|
|
658
|
+
Promise.resolve().then(job.thunk).then(job.resolve, job.reject).finally(() => {
|
|
659
|
+
this.inFlight--;
|
|
660
|
+
if (this.state === "pausing" && this.inFlight === 0) {
|
|
661
|
+
this.setState("paused");
|
|
662
|
+
}
|
|
663
|
+
this.pump();
|
|
664
|
+
});
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
setState(state) {
|
|
668
|
+
if (this.state === state) return;
|
|
669
|
+
this.state = state;
|
|
670
|
+
const snapshot = this.snapshot();
|
|
671
|
+
for (const listener of [...this.stateListeners]) listener(snapshot);
|
|
672
|
+
}
|
|
673
|
+
abortPending() {
|
|
674
|
+
const error = abortError();
|
|
675
|
+
while (this.queue.length > 0) this.queue.shift().reject(error);
|
|
676
|
+
while (this.gateWaiters.length > 0) {
|
|
677
|
+
this.gateWaiters.shift().reject(error);
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
};
|
|
681
|
+
|
|
682
|
+
// packages/core/src/agents/runtime/workflow-orchestrator.ts
|
|
683
|
+
var DEFAULT_MAX_AGENTS_PER_RUN = 1e3;
|
|
684
|
+
var MAX_WORKFLOW_AGENTS_ENV = "QWEN_CODE_MAX_WORKFLOW_AGENTS";
|
|
685
|
+
var HARD_MAX_AGENTS_PER_RUN_CEILING = 1e4;
|
|
686
|
+
function resolveMaxAgentsPerRun(env = process.env) {
|
|
687
|
+
const raw = env[MAX_WORKFLOW_AGENTS_ENV];
|
|
688
|
+
if (raw === void 0 || raw.trim() === "") {
|
|
689
|
+
return DEFAULT_MAX_AGENTS_PER_RUN;
|
|
690
|
+
}
|
|
691
|
+
const parsed = parsePositiveIntegerEnv(raw, 0);
|
|
692
|
+
if (parsed < 1) {
|
|
693
|
+
debugLogger.warn(
|
|
694
|
+
`Invalid ${MAX_WORKFLOW_AGENTS_ENV}=${JSON.stringify(raw)}, using default (${DEFAULT_MAX_AGENTS_PER_RUN})`
|
|
695
|
+
);
|
|
696
|
+
return DEFAULT_MAX_AGENTS_PER_RUN;
|
|
697
|
+
}
|
|
698
|
+
if (parsed > HARD_MAX_AGENTS_PER_RUN_CEILING) {
|
|
699
|
+
debugLogger.warn(
|
|
700
|
+
`${MAX_WORKFLOW_AGENTS_ENV}=${parsed} exceeds hard ceiling (${HARD_MAX_AGENTS_PER_RUN_CEILING}); clamping.`
|
|
701
|
+
);
|
|
702
|
+
return HARD_MAX_AGENTS_PER_RUN_CEILING;
|
|
703
|
+
}
|
|
704
|
+
return parsed;
|
|
705
|
+
}
|
|
706
|
+
__name(resolveMaxAgentsPerRun, "resolveMaxAgentsPerRun");
|
|
707
|
+
var MAX_WORKFLOW_CONCURRENCY_ENV = "QWEN_CODE_MAX_WORKFLOW_CONCURRENCY";
|
|
708
|
+
var HARD_MAX_CONCURRENCY_CEILING = 64;
|
|
709
|
+
function resolveConcurrencyLimit(env = process.env, availableParallelism2 = os.availableParallelism) {
|
|
710
|
+
const raw = env[MAX_WORKFLOW_CONCURRENCY_ENV];
|
|
711
|
+
if (raw !== void 0 && raw.trim() !== "") {
|
|
712
|
+
const parsed = parsePositiveIntegerEnv(raw, 0);
|
|
713
|
+
if (parsed >= 1) {
|
|
714
|
+
if (parsed > HARD_MAX_CONCURRENCY_CEILING) {
|
|
715
|
+
debugLogger.warn(
|
|
716
|
+
`${MAX_WORKFLOW_CONCURRENCY_ENV}=${parsed} exceeds hard ceiling (${HARD_MAX_CONCURRENCY_CEILING}); clamping.`
|
|
717
|
+
);
|
|
718
|
+
return HARD_MAX_CONCURRENCY_CEILING;
|
|
719
|
+
}
|
|
720
|
+
return parsed;
|
|
721
|
+
}
|
|
722
|
+
debugLogger.warn(
|
|
723
|
+
`Invalid ${MAX_WORKFLOW_CONCURRENCY_ENV}=${JSON.stringify(raw)}, using cpu-derived default`
|
|
724
|
+
);
|
|
725
|
+
}
|
|
726
|
+
return Math.max(2, Math.min(16, availableParallelism2() - 2));
|
|
727
|
+
}
|
|
728
|
+
__name(resolveConcurrencyLimit, "resolveConcurrencyLimit");
|
|
729
|
+
var DEFAULT_WORKFLOW_SUBAGENT_MAX_TURNS = 50;
|
|
730
|
+
var DEFAULT_WORKFLOW_SUBAGENT_MAX_TIME_MINUTES = 10;
|
|
731
|
+
var WORKFLOW_SUBAGENT_MAX_TURNS_ENV = "QWEN_CODE_WORKFLOW_AGENT_MAX_TURNS";
|
|
732
|
+
var WORKFLOW_SUBAGENT_MAX_MINUTES_ENV = "QWEN_CODE_WORKFLOW_AGENT_MAX_MINUTES";
|
|
733
|
+
var HARD_WORKFLOW_SUBAGENT_MAX_TURNS_CEILING = 500;
|
|
734
|
+
var HARD_WORKFLOW_SUBAGENT_MAX_MINUTES_CEILING = 100;
|
|
735
|
+
function resolveSubagentBound(envName, defaultValue, ceiling, env) {
|
|
736
|
+
const raw = env[envName];
|
|
737
|
+
if (raw === void 0 || raw.trim() === "") return defaultValue;
|
|
738
|
+
const parsed = parsePositiveIntegerEnv(raw, 0);
|
|
739
|
+
if (parsed < 1) {
|
|
740
|
+
debugLogger.warn(
|
|
741
|
+
`Invalid ${envName}=${JSON.stringify(raw)}, using default (${defaultValue})`
|
|
742
|
+
);
|
|
743
|
+
return defaultValue;
|
|
744
|
+
}
|
|
745
|
+
if (parsed > ceiling) {
|
|
746
|
+
debugLogger.warn(
|
|
747
|
+
`${envName}=${parsed} exceeds hard ceiling (${ceiling}); clamping.`
|
|
748
|
+
);
|
|
749
|
+
return ceiling;
|
|
750
|
+
}
|
|
751
|
+
return parsed;
|
|
752
|
+
}
|
|
753
|
+
__name(resolveSubagentBound, "resolveSubagentBound");
|
|
754
|
+
function resolveSubagentMaxTurns(env = process.env, defaultValue = DEFAULT_WORKFLOW_SUBAGENT_MAX_TURNS) {
|
|
755
|
+
return resolveSubagentBound(
|
|
756
|
+
WORKFLOW_SUBAGENT_MAX_TURNS_ENV,
|
|
757
|
+
defaultValue,
|
|
758
|
+
HARD_WORKFLOW_SUBAGENT_MAX_TURNS_CEILING,
|
|
759
|
+
env
|
|
760
|
+
);
|
|
761
|
+
}
|
|
762
|
+
__name(resolveSubagentMaxTurns, "resolveSubagentMaxTurns");
|
|
763
|
+
function resolveSubagentMaxTimeMinutes(env = process.env, defaultValue = DEFAULT_WORKFLOW_SUBAGENT_MAX_TIME_MINUTES) {
|
|
764
|
+
return resolveSubagentBound(
|
|
765
|
+
WORKFLOW_SUBAGENT_MAX_MINUTES_ENV,
|
|
766
|
+
defaultValue,
|
|
767
|
+
HARD_WORKFLOW_SUBAGENT_MAX_MINUTES_CEILING,
|
|
768
|
+
env
|
|
769
|
+
);
|
|
770
|
+
}
|
|
771
|
+
__name(resolveSubagentMaxTimeMinutes, "resolveSubagentMaxTimeMinutes");
|
|
772
|
+
var WORKFLOW_SUBAGENT_DISALLOWED_TOOLS = [
|
|
773
|
+
ToolNames.ASK_USER_QUESTION,
|
|
774
|
+
ToolNames.SEND_MESSAGE,
|
|
775
|
+
ToolNames.MONITOR,
|
|
776
|
+
...SUBAGENT_PLAN_LIFECYCLE_TOOLS,
|
|
777
|
+
// AgentTool: workflow subagents must not spawn sub-agents even where
|
|
778
|
+
// maxSubagentDepth would permit nesting — a leaf-spawned agent would run
|
|
779
|
+
// outside the orchestrator's concurrency cap, agent counter, and token
|
|
780
|
+
// budget, and its result would bypass the script's return-value contract.
|
|
781
|
+
// The WorkflowTool itself is already excluded from every subagent; this
|
|
782
|
+
// closes the same loop for plain `agent` calls (review #6189).
|
|
783
|
+
ToolNames.AGENT
|
|
784
|
+
];
|
|
785
|
+
var WorkflowExecutionError = class extends Error {
|
|
786
|
+
constructor(message, phases, logs, meta = null) {
|
|
787
|
+
super(message);
|
|
788
|
+
this.phases = phases;
|
|
789
|
+
this.logs = logs;
|
|
790
|
+
this.meta = meta;
|
|
791
|
+
}
|
|
792
|
+
static {
|
|
793
|
+
__name(this, "WorkflowExecutionError");
|
|
794
|
+
}
|
|
795
|
+
name = "WorkflowExecutionError";
|
|
796
|
+
};
|
|
797
|
+
function runBudgetFigures(budget) {
|
|
798
|
+
return [
|
|
799
|
+
budget.runSpent ? budget.runSpent() : budget.spent(),
|
|
800
|
+
budget.runCap ? budget.runCap() : budget.total
|
|
801
|
+
];
|
|
802
|
+
}
|
|
803
|
+
__name(runBudgetFigures, "runBudgetFigures");
|
|
804
|
+
function generateRunId() {
|
|
805
|
+
return `wf_${randomBytes(8).toString("hex")}`;
|
|
806
|
+
}
|
|
807
|
+
__name(generateRunId, "generateRunId");
|
|
808
|
+
function sanitizeForErrorMessage(value) {
|
|
809
|
+
return stripAnsiAndControl(value);
|
|
810
|
+
}
|
|
811
|
+
__name(sanitizeForErrorMessage, "sanitizeForErrorMessage");
|
|
812
|
+
function createProductionDispatch(config, signal, onTokens, bridgeApprovalEvents, subagentBounds) {
|
|
813
|
+
return async (prompt, opts, dispatchId) => {
|
|
814
|
+
if (typeof prompt !== "string" || prompt.length === 0) {
|
|
815
|
+
throw new Error("agent() requires a non-empty string prompt.");
|
|
816
|
+
}
|
|
817
|
+
const stallMs = resolveStallMs(
|
|
818
|
+
typeof opts.stallMs === "number" ? opts.stallMs : void 0
|
|
819
|
+
);
|
|
820
|
+
const workflowAgentId = `workflow-agent-${randomBytes(8).toString("hex")}`;
|
|
821
|
+
const agentIdentity = await resolveWorkflowAgentIdentity(config, opts);
|
|
822
|
+
if (agentIdentity.resolvedAgentType?.executor !== void 0) {
|
|
823
|
+
throw new Error(
|
|
824
|
+
"Workflow agent() does not support external-executor agents: token budgets, schema output, and workflow tool restrictions cannot be enforced. Use an in-process agent definition instead."
|
|
825
|
+
);
|
|
826
|
+
}
|
|
827
|
+
let attempt = 0;
|
|
828
|
+
return runStallResilient(
|
|
829
|
+
async (attemptSignal, emitter) => {
|
|
830
|
+
attempt += 1;
|
|
831
|
+
const cleanupApprovalBridge = bridgeApprovalEvents?.(
|
|
832
|
+
emitter,
|
|
833
|
+
dispatchId
|
|
834
|
+
);
|
|
835
|
+
const cleanupTranscript = attachDispatchTranscript(
|
|
836
|
+
config,
|
|
837
|
+
workflowAgentId,
|
|
838
|
+
prompt,
|
|
839
|
+
agentIdentity.name,
|
|
840
|
+
emitter,
|
|
841
|
+
attempt
|
|
842
|
+
);
|
|
843
|
+
try {
|
|
844
|
+
return await runSingleDispatch(
|
|
845
|
+
config,
|
|
846
|
+
prompt,
|
|
847
|
+
opts,
|
|
848
|
+
attemptSignal,
|
|
849
|
+
emitter,
|
|
850
|
+
workflowAgentId,
|
|
851
|
+
agentIdentity,
|
|
852
|
+
onTokens,
|
|
853
|
+
subagentBounds
|
|
854
|
+
);
|
|
855
|
+
} finally {
|
|
856
|
+
cleanupTranscript();
|
|
857
|
+
cleanupApprovalBridge?.();
|
|
858
|
+
}
|
|
859
|
+
},
|
|
860
|
+
{
|
|
861
|
+
stallMs,
|
|
862
|
+
signal,
|
|
863
|
+
// The name can carry a model-authored agentType spelling — keep
|
|
864
|
+
// the stall log / abandoned error single-line the same way the
|
|
865
|
+
// "not found" throw site sanitizes it.
|
|
866
|
+
label: sanitizeForErrorMessage(agentIdentity.name)
|
|
867
|
+
}
|
|
868
|
+
);
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
__name(createProductionDispatch, "createProductionDispatch");
|
|
872
|
+
async function resolveWorkflowAgentIdentity(config, opts) {
|
|
873
|
+
if (opts.agentType) {
|
|
874
|
+
const resolved = await config.getSubagentManager().findSubagentByName(opts.agentType);
|
|
875
|
+
if (resolved) {
|
|
876
|
+
return { name: resolved.name, resolvedAgentType: resolved };
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
if (typeof opts.label === "string" && opts.label) {
|
|
880
|
+
return { name: opts.label };
|
|
881
|
+
}
|
|
882
|
+
return { name: opts.agentType || "workflow-agent" };
|
|
883
|
+
}
|
|
884
|
+
__name(resolveWorkflowAgentIdentity, "resolveWorkflowAgentIdentity");
|
|
885
|
+
function attachDispatchTranscript(config, agentId, prompt, agentName, emitter, attempt) {
|
|
886
|
+
const append = attempt > 1;
|
|
887
|
+
try {
|
|
888
|
+
const { jsonlPath, options } = buildAgentTranscriptAttach(config, agentId, {
|
|
889
|
+
agentName,
|
|
890
|
+
// The prompt the SCRIPT dispatched, seeded as the transcript's first
|
|
891
|
+
// user record — the same shape AgentTool writes, so a reader that
|
|
892
|
+
// recovers a launch prompt from a transcript needs no workflow-
|
|
893
|
+
// specific branch. A retry re-uses the first attempt's record rather
|
|
894
|
+
// than seeding a second one.
|
|
895
|
+
initialUserPrompt: append ? void 0 : prompt,
|
|
896
|
+
appendToExisting: append,
|
|
897
|
+
retryAttempt: append ? attempt : void 0
|
|
898
|
+
});
|
|
899
|
+
return attachJsonlTranscriptWriter(emitter, jsonlPath, options).cleanup;
|
|
900
|
+
} catch (error) {
|
|
901
|
+
debugLogger.warn(
|
|
902
|
+
`[Workflow] failed to attach transcript for ${agentId}: ${error}`
|
|
903
|
+
);
|
|
904
|
+
return () => {
|
|
905
|
+
};
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
__name(attachDispatchTranscript, "attachDispatchTranscript");
|
|
909
|
+
function terminalDispatchError(workflowAgentId, mode) {
|
|
910
|
+
const message = `Workflow subagent ${workflowAgentId} did not complete (terminate mode: ${mode}).`;
|
|
911
|
+
switch (mode) {
|
|
912
|
+
case "MAX_TURNS" /* MAX_TURNS */:
|
|
913
|
+
return new WorkflowAgentFailedError(message, "max_turns", mode);
|
|
914
|
+
case "TIMEOUT" /* TIMEOUT */:
|
|
915
|
+
return new WorkflowAgentFailedError(message, "timeout", mode);
|
|
916
|
+
case "ERROR" /* ERROR */:
|
|
917
|
+
return new WorkflowAgentFailedError(message, "error", mode);
|
|
918
|
+
default:
|
|
919
|
+
return new Error(message);
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
__name(terminalDispatchError, "terminalDispatchError");
|
|
923
|
+
async function runSingleDispatch(config, prompt, opts, attemptSignal, emitter, workflowAgentId, agentIdentity, onTokens, subagentBounds) {
|
|
924
|
+
const { AgentHeadless, ContextState } = await import("./agent-headless-EJ4QOUSM.js");
|
|
925
|
+
const ctx = new ContextState();
|
|
926
|
+
ctx.set("task_prompt", prompt);
|
|
927
|
+
debugLogger.debug(`[workflow] Dispatch ${workflowAgentId}`);
|
|
928
|
+
if (DISPATCH_AFFECTING_AGENT_OPTS.every((key) => opts[key] === void 0)) {
|
|
929
|
+
const subagent = await AgentHeadless.create(
|
|
930
|
+
agentIdentity.name,
|
|
931
|
+
config,
|
|
932
|
+
{
|
|
933
|
+
systemPrompt: WORKFLOW_SUBAGENT_SYSTEM_PROMPT
|
|
934
|
+
},
|
|
935
|
+
{},
|
|
936
|
+
// T11 (PR #4732 R1): bound resource ceiling so a single agent() call
|
|
937
|
+
// cannot loop the model indefinitely. Without this, runConfig was {}
|
|
938
|
+
// and the loop guards never tripped — combined with the cancellation
|
|
939
|
+
// bug below, workflows were effectively unkillable.
|
|
940
|
+
subagentBounds ?? {
|
|
941
|
+
max_turns: resolveSubagentMaxTurns(),
|
|
942
|
+
max_time_minutes: resolveSubagentMaxTimeMinutes()
|
|
943
|
+
},
|
|
944
|
+
// T11 (PR #4732 R1): disallow SendMessage / ExitPlanMode to align with
|
|
945
|
+
// upstream Tg8 — closes the back-channel that would let a subagent
|
|
946
|
+
// deliver its answer via user message instead of the script's read.
|
|
947
|
+
{ tools: ["*"], disallowedTools: WORKFLOW_SUBAGENT_DISALLOWED_TOOLS },
|
|
948
|
+
// P-stall: the stall-watchdog emitter observes reasoning-loop events
|
|
949
|
+
// (round/tool/usage) to detect a hang and abort `attemptSignal`.
|
|
950
|
+
emitter,
|
|
951
|
+
void 0,
|
|
952
|
+
void 0,
|
|
953
|
+
prompt,
|
|
954
|
+
workflowAgentId
|
|
955
|
+
);
|
|
956
|
+
try {
|
|
957
|
+
await runWithAgentContext(
|
|
958
|
+
workflowAgentId,
|
|
959
|
+
() => subagent.execute(ctx, attemptSignal)
|
|
960
|
+
);
|
|
961
|
+
} finally {
|
|
962
|
+
reportTokens(subagent, opts, onTokens);
|
|
963
|
+
}
|
|
964
|
+
const mode = subagent.getTerminateMode();
|
|
965
|
+
if (mode !== "GOAL" /* GOAL */) {
|
|
966
|
+
throw terminalDispatchError(workflowAgentId, mode);
|
|
967
|
+
}
|
|
968
|
+
return toModelVisibleSubagentResult(subagent.getFinalText(), mode);
|
|
969
|
+
}
|
|
970
|
+
return runOverridePath(
|
|
971
|
+
config,
|
|
972
|
+
ctx,
|
|
973
|
+
opts,
|
|
974
|
+
attemptSignal,
|
|
975
|
+
workflowAgentId,
|
|
976
|
+
agentIdentity,
|
|
977
|
+
onTokens,
|
|
978
|
+
emitter,
|
|
979
|
+
subagentBounds
|
|
980
|
+
);
|
|
981
|
+
}
|
|
982
|
+
__name(runSingleDispatch, "runSingleDispatch");
|
|
983
|
+
function reportTokens(subagent, opts, onTokens) {
|
|
984
|
+
if (!onTokens) return;
|
|
985
|
+
try {
|
|
986
|
+
const summary = subagent.getExecutionSummary();
|
|
987
|
+
onTokens(summary.outputTokens, opts);
|
|
988
|
+
} catch (e) {
|
|
989
|
+
debugLogger.warn("onTokens callback threw:", e);
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
__name(reportTokens, "reportTokens");
|
|
993
|
+
function resolveDispatchEffort(raw) {
|
|
994
|
+
if (raw === void 0) return void 0;
|
|
995
|
+
const tier = typeof raw === "string" ? normalizeReasoningEffort(raw) : void 0;
|
|
996
|
+
if (tier === void 0) {
|
|
997
|
+
throw new Error(
|
|
998
|
+
`agent({effort}): unknown effort tier ${sanitizeForErrorMessage(
|
|
999
|
+
JSON.stringify(raw) ?? String(raw)
|
|
1000
|
+
)}. Known tiers are: ${REASONING_EFFORT_TIERS.join(", ")}.`
|
|
1001
|
+
);
|
|
1002
|
+
}
|
|
1003
|
+
return tier;
|
|
1004
|
+
}
|
|
1005
|
+
__name(resolveDispatchEffort, "resolveDispatchEffort");
|
|
1006
|
+
function resolveDispatchDenies(raw) {
|
|
1007
|
+
if (raw === void 0) return [];
|
|
1008
|
+
if (!Array.isArray(raw) || raw.some(
|
|
1009
|
+
(name) => typeof name !== "string" || name.length === 0 || name !== name.trim()
|
|
1010
|
+
)) {
|
|
1011
|
+
throw new Error(
|
|
1012
|
+
"agent({disallowedTools}): must be an array of non-empty tool-name strings without surrounding whitespace, e.g. ['run_shell_command', 'write_file']."
|
|
1013
|
+
);
|
|
1014
|
+
}
|
|
1015
|
+
return raw.map((name) => resolveBuiltinToolName(name) ?? name);
|
|
1016
|
+
}
|
|
1017
|
+
__name(resolveDispatchDenies, "resolveDispatchDenies");
|
|
1018
|
+
async function runOverridePath(config, ctx, opts, signal, workflowAgentId, agentIdentity, onTokens, emitter, subagentBounds) {
|
|
1019
|
+
if (opts.isolation === "remote") {
|
|
1020
|
+
throw new Error(
|
|
1021
|
+
"agent({isolation:'remote'}) is not available in this build."
|
|
1022
|
+
);
|
|
1023
|
+
}
|
|
1024
|
+
const effort = resolveDispatchEffort(opts.effort);
|
|
1025
|
+
const requestedDenies = resolveDispatchDenies(opts.disallowedTools);
|
|
1026
|
+
const subagentMgr = config.getSubagentManager();
|
|
1027
|
+
let baseConfig;
|
|
1028
|
+
if (opts.agentType !== void 0) {
|
|
1029
|
+
const resolved = agentIdentity.resolvedAgentType;
|
|
1030
|
+
if (!resolved) {
|
|
1031
|
+
const safeAgentType = sanitizeForErrorMessage(opts.agentType);
|
|
1032
|
+
throw new Error(
|
|
1033
|
+
`agent({agentType}): agent type '${safeAgentType}' not found.`
|
|
1034
|
+
);
|
|
1035
|
+
}
|
|
1036
|
+
baseConfig = resolved;
|
|
1037
|
+
} else {
|
|
1038
|
+
baseConfig = {
|
|
1039
|
+
name: agentIdentity.name,
|
|
1040
|
+
description: "Default workflow subagent (per-call overrides).",
|
|
1041
|
+
systemPrompt: WORKFLOW_SUBAGENT_SYSTEM_PROMPT,
|
|
1042
|
+
level: "session",
|
|
1043
|
+
isBuiltin: false
|
|
1044
|
+
};
|
|
1045
|
+
}
|
|
1046
|
+
let schemaSystemPrompt;
|
|
1047
|
+
if (opts.schema !== void 0) {
|
|
1048
|
+
schemaSystemPrompt = opts.agentType !== void 0 && baseConfig.systemPrompt ? `${baseConfig.systemPrompt}
|
|
1049
|
+
|
|
1050
|
+
${WORKFLOW_SUBAGENT_SYSTEM_PROMPT_WITH_SCHEMA}` : WORKFLOW_SUBAGENT_SYSTEM_PROMPT_WITH_SCHEMA;
|
|
1051
|
+
}
|
|
1052
|
+
let schemaTools;
|
|
1053
|
+
if (opts.schema !== void 0 && baseConfig.tools && baseConfig.tools.length > 0 && !baseConfig.tools.includes("*") && !baseConfig.tools.includes(ToolNames.STRUCTURED_OUTPUT)) {
|
|
1054
|
+
schemaTools = [...baseConfig.tools, ToolNames.STRUCTURED_OUTPUT];
|
|
1055
|
+
}
|
|
1056
|
+
const augmented = {
|
|
1057
|
+
...baseConfig,
|
|
1058
|
+
...opts.model !== void 0 ? { model: opts.model } : {},
|
|
1059
|
+
...schemaSystemPrompt !== void 0 ? { systemPrompt: schemaSystemPrompt } : {},
|
|
1060
|
+
...schemaTools !== void 0 ? { tools: schemaTools } : {},
|
|
1061
|
+
disallowedTools: Array.from(
|
|
1062
|
+
/* @__PURE__ */ new Set([
|
|
1063
|
+
...baseConfig.disallowedTools ?? [],
|
|
1064
|
+
...WORKFLOW_SUBAGENT_DISALLOWED_TOOLS,
|
|
1065
|
+
...requestedDenies
|
|
1066
|
+
])
|
|
1067
|
+
)
|
|
1068
|
+
};
|
|
1069
|
+
if (requestedDenies.length > 0) {
|
|
1070
|
+
const unmatched = await subagentMgr.findUnmatchedToolNames(requestedDenies);
|
|
1071
|
+
if (unmatched.length > 0) {
|
|
1072
|
+
throw new Error(
|
|
1073
|
+
`agent({disallowedTools}): ${sanitizeForErrorMessage(
|
|
1074
|
+
unmatched.map((name) => JSON.stringify(name)).join(", ")
|
|
1075
|
+
)} ${unmatched.length === 1 ? "matches" : "match"} no tool. Use a tool name (run_shell_command, write_file, edit), a display name (Shell, WriteFile, Edit), or an MCP pattern (mcp__<server>, mcp__<server>__*, mcp__<server>__<tool>).`
|
|
1076
|
+
);
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
if (opts.schema !== void 0 && [...baseConfig.disallowedTools ?? [], ...requestedDenies].some(
|
|
1080
|
+
(name) => (resolveBuiltinToolName(name) ?? name) === ToolNames.STRUCTURED_OUTPUT
|
|
1081
|
+
)) {
|
|
1082
|
+
throw new Error(
|
|
1083
|
+
"agent({schema, disallowedTools}): schema mode needs the structured_output tool, but disallowedTools deny it (from this call or from the agent type)."
|
|
1084
|
+
);
|
|
1085
|
+
}
|
|
1086
|
+
let worktreeIsolation = null;
|
|
1087
|
+
let effectiveContext = config;
|
|
1088
|
+
let approvalCleanup;
|
|
1089
|
+
if (opts.isolation !== void 0 && opts.workingDir !== void 0) {
|
|
1090
|
+
throw new Error(
|
|
1091
|
+
"agent({workingDir, isolation}): incompatible options. workingDir pins the agent to a worktree you already own; isolation creates a fresh one and removes it afterwards. Pass one."
|
|
1092
|
+
);
|
|
1093
|
+
}
|
|
1094
|
+
if (opts.isolation === "worktree") {
|
|
1095
|
+
worktreeIsolation = await provisionWorkflowWorktree(config);
|
|
1096
|
+
effectiveContext = deriveWorktreeConfig(config, worktreeIsolation.path, {
|
|
1097
|
+
customIgnoreFiles: config.getFileFilteringOptions().customIgnoreFiles
|
|
1098
|
+
});
|
|
1099
|
+
installSessionWorkflowRevisionWriteThrough(effectiveContext, config);
|
|
1100
|
+
} else if (opts.workingDir !== void 0) {
|
|
1101
|
+
if (typeof opts.workingDir !== "string" || opts.workingDir.trim().length === 0) {
|
|
1102
|
+
throw new Error(
|
|
1103
|
+
"agent({workingDir}): must be a non-empty string naming an existing git worktree of this repository."
|
|
1104
|
+
);
|
|
1105
|
+
}
|
|
1106
|
+
const resolved = await resolveExternalWorktreeDir(
|
|
1107
|
+
config,
|
|
1108
|
+
opts.workingDir,
|
|
1109
|
+
"workingDir"
|
|
1110
|
+
);
|
|
1111
|
+
if ("error" in resolved) {
|
|
1112
|
+
throw new Error(
|
|
1113
|
+
`agent({workingDir: ${sanitizeForErrorMessage(JSON.stringify(opts.workingDir))}}): ${sanitizeForErrorMessage(resolved.error)}`
|
|
1114
|
+
);
|
|
1115
|
+
}
|
|
1116
|
+
effectiveContext = deriveWorktreeConfig(config, resolved.path, {
|
|
1117
|
+
customIgnoreFiles: config.getFileFilteringOptions().customIgnoreFiles
|
|
1118
|
+
});
|
|
1119
|
+
installSessionWorkflowRevisionWriteThrough(effectiveContext, config);
|
|
1120
|
+
}
|
|
1121
|
+
if (effectiveContext !== config) {
|
|
1122
|
+
const approvalHandle = deriveApprovalModeConfig(
|
|
1123
|
+
effectiveContext,
|
|
1124
|
+
config.getApprovalMode()
|
|
1125
|
+
);
|
|
1126
|
+
approvalCleanup = approvalHandle.cleanup;
|
|
1127
|
+
effectiveContext = approvalHandle.config;
|
|
1128
|
+
}
|
|
1129
|
+
let onParentAbort;
|
|
1130
|
+
try {
|
|
1131
|
+
let schemaState = null;
|
|
1132
|
+
if (opts.schema !== void 0) {
|
|
1133
|
+
effectiveContext = await createSchemaConfigOverride(
|
|
1134
|
+
effectiveContext,
|
|
1135
|
+
opts.schema
|
|
1136
|
+
);
|
|
1137
|
+
schemaState = createSchemaModeState();
|
|
1138
|
+
}
|
|
1139
|
+
let dispatchSignal = signal;
|
|
1140
|
+
if (schemaState) {
|
|
1141
|
+
const child = new AbortController();
|
|
1142
|
+
if (signal) {
|
|
1143
|
+
if (signal.aborted) {
|
|
1144
|
+
child.abort(signal.reason);
|
|
1145
|
+
} else {
|
|
1146
|
+
onParentAbort = /* @__PURE__ */ __name(() => child.abort(signal.reason), "onParentAbort");
|
|
1147
|
+
signal.addEventListener("abort", onParentAbort);
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
schemaState.abortController = child;
|
|
1151
|
+
dispatchSignal = child.signal;
|
|
1152
|
+
}
|
|
1153
|
+
const eventEmitter = emitter ?? (schemaState ? new AgentEventEmitter() : void 0);
|
|
1154
|
+
if (schemaState && eventEmitter) {
|
|
1155
|
+
attachSchemaListeners(eventEmitter, schemaState);
|
|
1156
|
+
}
|
|
1157
|
+
const { subagent, dispose } = await subagentMgr.createAgentHeadless(
|
|
1158
|
+
augmented,
|
|
1159
|
+
effectiveContext,
|
|
1160
|
+
{
|
|
1161
|
+
// Workflow always bounds resource ceiling regardless of agentType's
|
|
1162
|
+
// own runConfig / maxTurns — these are workflow-level safety bounds,
|
|
1163
|
+
// not subagent-level preferences. P5 will refine via budget.
|
|
1164
|
+
runConfigOverrides: subagentBounds ?? {
|
|
1165
|
+
max_turns: resolveSubagentMaxTurns(),
|
|
1166
|
+
max_time_minutes: resolveSubagentMaxTimeMinutes()
|
|
1167
|
+
},
|
|
1168
|
+
...effort !== void 0 ? { modelConfigOverrides: { reasoningEffort: effort } } : {},
|
|
1169
|
+
eventEmitter,
|
|
1170
|
+
taskName: String(ctx.get("task_prompt")),
|
|
1171
|
+
subagentId: workflowAgentId
|
|
1172
|
+
}
|
|
1173
|
+
);
|
|
1174
|
+
try {
|
|
1175
|
+
try {
|
|
1176
|
+
await runWithAgentContext(
|
|
1177
|
+
workflowAgentId,
|
|
1178
|
+
() => subagent.execute(ctx, dispatchSignal)
|
|
1179
|
+
);
|
|
1180
|
+
} finally {
|
|
1181
|
+
reportTokens(subagent, opts, onTokens);
|
|
1182
|
+
}
|
|
1183
|
+
if (schemaState) {
|
|
1184
|
+
if (schemaState.result !== null) {
|
|
1185
|
+
if (worktreeIsolation) {
|
|
1186
|
+
const isolation = worktreeIsolation;
|
|
1187
|
+
worktreeIsolation = null;
|
|
1188
|
+
const preserved = await cleanupWorkflowWorktree(isolation);
|
|
1189
|
+
if (preserved) {
|
|
1190
|
+
debugLogger.info(
|
|
1191
|
+
`[Workflow] Schema-mode subagent preserved worktree at ${preserved.path ?? "(directory removed)"} on branch ${preserved.branch}. The structured payload is returned verbatim; recover the work from the preserved path / branch.`
|
|
1192
|
+
);
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
return schemaState.result;
|
|
1196
|
+
}
|
|
1197
|
+
if (signal?.aborted) {
|
|
1198
|
+
throw new DOMException("Workflow aborted.", "AbortError");
|
|
1199
|
+
}
|
|
1200
|
+
const mode2 = subagent.getTerminateMode();
|
|
1201
|
+
if (mode2 !== "GOAL" /* GOAL */ && mode2 !== "CANCELLED" /* CANCELLED */) {
|
|
1202
|
+
throw terminalDispatchError(workflowAgentId, mode2);
|
|
1203
|
+
}
|
|
1204
|
+
if (schemaState.attempts > 2) {
|
|
1205
|
+
throw new WorkflowAgentFailedError(
|
|
1206
|
+
"subagent completed without calling StructuredOutput (after 2 in-conversation nudges).",
|
|
1207
|
+
"no_structured_output"
|
|
1208
|
+
);
|
|
1209
|
+
}
|
|
1210
|
+
throw new WorkflowAgentFailedError(
|
|
1211
|
+
"subagent completed without calling structured_output (no validation attempt \u2014 model produced plain-text content).",
|
|
1212
|
+
"no_structured_output"
|
|
1213
|
+
);
|
|
1214
|
+
}
|
|
1215
|
+
const mode = subagent.getTerminateMode();
|
|
1216
|
+
if (mode !== "GOAL" /* GOAL */) {
|
|
1217
|
+
throw terminalDispatchError(workflowAgentId, mode);
|
|
1218
|
+
}
|
|
1219
|
+
let finalText = toModelVisibleSubagentResult(
|
|
1220
|
+
subagent.getFinalText(),
|
|
1221
|
+
mode
|
|
1222
|
+
);
|
|
1223
|
+
if (worktreeIsolation) {
|
|
1224
|
+
const isolation = worktreeIsolation;
|
|
1225
|
+
worktreeIsolation = null;
|
|
1226
|
+
const preserved = await cleanupWorkflowWorktree(isolation);
|
|
1227
|
+
if (preserved && typeof finalText === "string") {
|
|
1228
|
+
finalText = appendWorktreePreservedSuffix(finalText, preserved);
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
return finalText;
|
|
1232
|
+
} finally {
|
|
1233
|
+
await dispose();
|
|
1234
|
+
}
|
|
1235
|
+
} finally {
|
|
1236
|
+
if (onParentAbort && signal) {
|
|
1237
|
+
signal.removeEventListener("abort", onParentAbort);
|
|
1238
|
+
}
|
|
1239
|
+
approvalCleanup?.();
|
|
1240
|
+
if (worktreeIsolation) {
|
|
1241
|
+
try {
|
|
1242
|
+
await cleanupWorkflowWorktree(worktreeIsolation);
|
|
1243
|
+
} catch (error) {
|
|
1244
|
+
debugLogger.warn(
|
|
1245
|
+
`Workflow worktree cleanup in fallback finally failed for ${worktreeIsolation.path}: ${error instanceof Error ? error.message : String(error)}`
|
|
1246
|
+
);
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
__name(runOverridePath, "runOverridePath");
|
|
1252
|
+
async function provisionWorkflowWorktree(config) {
|
|
1253
|
+
const cwd = config.getTargetDir();
|
|
1254
|
+
if (/\.qwen[\\/]worktrees[\\/]/.test(cwd)) {
|
|
1255
|
+
throw new Error(
|
|
1256
|
+
`agent({isolation:'worktree'}): parent is already inside a worktree (${cwd}). Nested isolation worktrees are not supported \u2014 the subagent's inherited paths would still reference the outer worktree.`
|
|
1257
|
+
);
|
|
1258
|
+
}
|
|
1259
|
+
const probe = new GitWorktreeService(cwd);
|
|
1260
|
+
const gitCheck = await probe.checkGitAvailable();
|
|
1261
|
+
if (!gitCheck.available) {
|
|
1262
|
+
throw new Error(
|
|
1263
|
+
`agent({isolation:'worktree'}): ${gitCheck.error ?? "git is not available"}.`
|
|
1264
|
+
);
|
|
1265
|
+
}
|
|
1266
|
+
if (!await probe.isGitRepository()) {
|
|
1267
|
+
throw new Error(
|
|
1268
|
+
`agent({isolation:'worktree'}): ${cwd} is not a git repository.`
|
|
1269
|
+
);
|
|
1270
|
+
}
|
|
1271
|
+
const projectRoot = await probe.getRepoTopLevel() ?? cwd;
|
|
1272
|
+
const wtService = projectRoot === cwd ? probe : new GitWorktreeService(projectRoot);
|
|
1273
|
+
let parentDirty = false;
|
|
1274
|
+
try {
|
|
1275
|
+
parentDirty = await wtService.hasWorktreeChanges(projectRoot);
|
|
1276
|
+
} catch (error) {
|
|
1277
|
+
debugLogger.warn(
|
|
1278
|
+
`[Workflow] hasWorktreeChanges failed at ${projectRoot}: ${error}`
|
|
1279
|
+
);
|
|
1280
|
+
parentDirty = true;
|
|
1281
|
+
}
|
|
1282
|
+
if (parentDirty) {
|
|
1283
|
+
throw new Error(
|
|
1284
|
+
`agent({isolation:'worktree'}): parent working tree at ${projectRoot} has uncommitted changes that would not propagate into the isolated worktree. The subagent would see the prior HEAD instead of the current state. Commit or stash the changes, then re-run.`
|
|
1285
|
+
);
|
|
1286
|
+
}
|
|
1287
|
+
const slug = generateAgentWorktreeSlug();
|
|
1288
|
+
let parentBranch;
|
|
1289
|
+
try {
|
|
1290
|
+
parentBranch = await wtService.getCurrentBranch();
|
|
1291
|
+
} catch (error) {
|
|
1292
|
+
debugLogger.warn(
|
|
1293
|
+
`[Workflow] getCurrentBranch failed at ${projectRoot}: ${error}`
|
|
1294
|
+
);
|
|
1295
|
+
}
|
|
1296
|
+
const created = await wtService.createUserWorktree(slug, parentBranch, {
|
|
1297
|
+
symlinkDirectories: config.getWorktreeSymlinkDirectories()
|
|
1298
|
+
});
|
|
1299
|
+
if (!created.success || !created.worktree) {
|
|
1300
|
+
throw new Error(
|
|
1301
|
+
`agent({isolation:'worktree'}): failed to create worktree: ${created.error ?? "unknown error"}.`
|
|
1302
|
+
);
|
|
1303
|
+
}
|
|
1304
|
+
try {
|
|
1305
|
+
await writeWorktreeSessionMarker(
|
|
1306
|
+
created.worktree.path,
|
|
1307
|
+
config.getSessionId()
|
|
1308
|
+
);
|
|
1309
|
+
} catch (error) {
|
|
1310
|
+
debugLogger.warn(
|
|
1311
|
+
`[Workflow] failed to write session marker at ${created.worktree.path}: ${error}`
|
|
1312
|
+
);
|
|
1313
|
+
}
|
|
1314
|
+
return {
|
|
1315
|
+
slug,
|
|
1316
|
+
path: created.worktree.path,
|
|
1317
|
+
branch: created.worktree.branch,
|
|
1318
|
+
repoRoot: projectRoot
|
|
1319
|
+
};
|
|
1320
|
+
}
|
|
1321
|
+
__name(provisionWorkflowWorktree, "provisionWorkflowWorktree");
|
|
1322
|
+
async function cleanupWorkflowWorktree(isolation) {
|
|
1323
|
+
const wtService = new GitWorktreeService(isolation.repoRoot);
|
|
1324
|
+
const [hasChanges, hasUnmerged] = await Promise.all([
|
|
1325
|
+
wtService.hasWorktreeChanges(isolation.path).catch((error) => {
|
|
1326
|
+
debugLogger.warn(
|
|
1327
|
+
`[Workflow] hasWorktreeChanges failed for ${isolation.path}: ${error}`
|
|
1328
|
+
);
|
|
1329
|
+
return true;
|
|
1330
|
+
}),
|
|
1331
|
+
wtService.hasUnmergedWorktreeCommits(isolation.slug).catch((error) => {
|
|
1332
|
+
debugLogger.warn(
|
|
1333
|
+
`[Workflow] hasUnmergedWorktreeCommits failed for ${isolation.slug}: ${error}`
|
|
1334
|
+
);
|
|
1335
|
+
return true;
|
|
1336
|
+
})
|
|
1337
|
+
]);
|
|
1338
|
+
if (hasChanges || hasUnmerged) {
|
|
1339
|
+
debugLogger.info(
|
|
1340
|
+
`[Workflow] Preserving isolation worktree ${isolation.path} (branch ${isolation.branch}, hasChanges=${hasChanges}, hasUnmerged=${hasUnmerged})`
|
|
1341
|
+
);
|
|
1342
|
+
return { path: isolation.path, branch: isolation.branch };
|
|
1343
|
+
}
|
|
1344
|
+
try {
|
|
1345
|
+
const result = await wtService.removeUserWorktree(isolation.slug, {
|
|
1346
|
+
deleteBranch: true
|
|
1347
|
+
});
|
|
1348
|
+
if (!result.success) {
|
|
1349
|
+
debugLogger.warn(
|
|
1350
|
+
`[Workflow] Failed to remove ephemeral worktree ${isolation.path}: ${result.error}`
|
|
1351
|
+
);
|
|
1352
|
+
return { path: isolation.path, branch: isolation.branch };
|
|
1353
|
+
}
|
|
1354
|
+
if (result.branchPreserved) {
|
|
1355
|
+
debugLogger.warn(
|
|
1356
|
+
`[Workflow] Removed worktree directory ${isolation.path} but kept branch ${isolation.branch} (unmerged commits at delete time)`
|
|
1357
|
+
);
|
|
1358
|
+
return { branch: isolation.branch };
|
|
1359
|
+
}
|
|
1360
|
+
} catch (error) {
|
|
1361
|
+
debugLogger.warn(
|
|
1362
|
+
`[Workflow] Failed to remove ephemeral worktree ${isolation.path}: ${error}`
|
|
1363
|
+
);
|
|
1364
|
+
return { path: isolation.path, branch: isolation.branch };
|
|
1365
|
+
}
|
|
1366
|
+
return null;
|
|
1367
|
+
}
|
|
1368
|
+
__name(cleanupWorkflowWorktree, "cleanupWorkflowWorktree");
|
|
1369
|
+
function appendWorktreePreservedSuffix(finalText, preserved) {
|
|
1370
|
+
const sep = finalText.endsWith("\n") ? "\n" : "\n\n";
|
|
1371
|
+
if (preserved.path) {
|
|
1372
|
+
return `${finalText}${sep}[worktree preserved: ${preserved.path} (branch ${preserved.branch})]`;
|
|
1373
|
+
}
|
|
1374
|
+
return `${finalText}${sep}[worktree directory removed; branch ${preserved.branch} preserved \u2014 recover with \`git worktree add <path> ${preserved.branch}\`]`;
|
|
1375
|
+
}
|
|
1376
|
+
__name(appendWorktreePreservedSuffix, "appendWorktreePreservedSuffix");
|
|
1377
|
+
function createSchemaModeState() {
|
|
1378
|
+
return {
|
|
1379
|
+
result: null,
|
|
1380
|
+
attempts: 0,
|
|
1381
|
+
pendingArgs: /* @__PURE__ */ new Map(),
|
|
1382
|
+
abortController: new AbortController()
|
|
1383
|
+
};
|
|
1384
|
+
}
|
|
1385
|
+
__name(createSchemaModeState, "createSchemaModeState");
|
|
1386
|
+
function attachSchemaListeners(emitter, state) {
|
|
1387
|
+
const targetTool = ToolNames.STRUCTURED_OUTPUT;
|
|
1388
|
+
emitter.on("tool_call" /* TOOL_CALL */, (evt) => {
|
|
1389
|
+
if (evt.name !== targetTool) return;
|
|
1390
|
+
state.pendingArgs.set(evt.callId, evt.args);
|
|
1391
|
+
});
|
|
1392
|
+
emitter.on("tool_result" /* TOOL_RESULT */, (evt) => {
|
|
1393
|
+
if (evt.name !== targetTool) return;
|
|
1394
|
+
const args = state.pendingArgs.get(evt.callId);
|
|
1395
|
+
state.pendingArgs.delete(evt.callId);
|
|
1396
|
+
if (evt.success) {
|
|
1397
|
+
if (args !== void 0 && state.result === null) {
|
|
1398
|
+
state.result = args;
|
|
1399
|
+
state.abortController.abort();
|
|
1400
|
+
}
|
|
1401
|
+
return;
|
|
1402
|
+
}
|
|
1403
|
+
state.attempts += 1;
|
|
1404
|
+
if (state.attempts > 2 && state.result === null) {
|
|
1405
|
+
state.abortController.abort();
|
|
1406
|
+
}
|
|
1407
|
+
});
|
|
1408
|
+
}
|
|
1409
|
+
__name(attachSchemaListeners, "attachSchemaListeners");
|
|
1410
|
+
async function createSchemaConfigOverride(base, schema) {
|
|
1411
|
+
const override = deriveConfig(base);
|
|
1412
|
+
installSessionWorkflowRevisionWriteThrough(override, base);
|
|
1413
|
+
await rebuildToolRegistryOnOverride(override, base);
|
|
1414
|
+
const registry = override.getToolRegistry();
|
|
1415
|
+
registry.registerTool(new SyntheticOutputTool(schema));
|
|
1416
|
+
return override;
|
|
1417
|
+
}
|
|
1418
|
+
__name(createSchemaConfigOverride, "createSchemaConfigOverride");
|
|
1419
|
+
var WorkflowOrchestrator = class {
|
|
1420
|
+
constructor(dispatch) {
|
|
1421
|
+
this.dispatch = dispatch;
|
|
1422
|
+
}
|
|
1423
|
+
static {
|
|
1424
|
+
__name(this, "WorkflowOrchestrator");
|
|
1425
|
+
}
|
|
1426
|
+
async run(req) {
|
|
1427
|
+
const runId = req.runId ?? generateRunId();
|
|
1428
|
+
const maxAgents = resolveMaxAgentsPerRun();
|
|
1429
|
+
const signal = req.abortOnTimeout?.signal;
|
|
1430
|
+
const scheduler = req.scheduler ?? new WorkflowDispatchScheduler(resolveConcurrencyLimit(), signal);
|
|
1431
|
+
const rejectThroughPauseGate = /* @__PURE__ */ __name((error) => scheduler.waitUntilRunning().then(
|
|
1432
|
+
() => {
|
|
1433
|
+
throw error;
|
|
1434
|
+
},
|
|
1435
|
+
() => {
|
|
1436
|
+
throw error;
|
|
1437
|
+
}
|
|
1438
|
+
), "rejectThroughPauseGate");
|
|
1439
|
+
let agentCount = 0;
|
|
1440
|
+
let dispatchTraceCount = 0;
|
|
1441
|
+
const emitter = req.emitter;
|
|
1442
|
+
const budget = req.budget;
|
|
1443
|
+
const dependencyContext = new AsyncLocalStorage();
|
|
1444
|
+
const issueDispatchTrace = /* @__PURE__ */ __name((prompt, opts, cached = false, workflowCallId) => {
|
|
1445
|
+
const id = `dispatch-${dispatchTraceCount += 1}`;
|
|
1446
|
+
const store = dependencyContext.getStore();
|
|
1447
|
+
const dependsOn = Array.from(new Set(store?.tails ?? []));
|
|
1448
|
+
if (store) store.tails = [id];
|
|
1449
|
+
try {
|
|
1450
|
+
emitter?.dispatchQueued?.({
|
|
1451
|
+
id,
|
|
1452
|
+
...opts.stepId !== void 0 ? { stepId: opts.stepId } : {},
|
|
1453
|
+
...workflowCallId ? { workflowCallId } : {},
|
|
1454
|
+
...typeof opts.label === "string" ? { label: opts.label } : {},
|
|
1455
|
+
prompt,
|
|
1456
|
+
dependsOn,
|
|
1457
|
+
queuedAt: Date.now(),
|
|
1458
|
+
...cached ? { cached: true } : {}
|
|
1459
|
+
});
|
|
1460
|
+
} catch (e) {
|
|
1461
|
+
debugLogger.warn("emitter.dispatchQueued threw:", e);
|
|
1462
|
+
}
|
|
1463
|
+
return id;
|
|
1464
|
+
}, "issueDispatchTrace");
|
|
1465
|
+
const journal = req.journal;
|
|
1466
|
+
const replay = req.resumeReplay;
|
|
1467
|
+
let prefixHash = deriveArgsSeed(req.args);
|
|
1468
|
+
let hadMiss = false;
|
|
1469
|
+
let journalAgentId = 0;
|
|
1470
|
+
const parentSandboxRef = {
|
|
1471
|
+
current: void 0
|
|
1472
|
+
};
|
|
1473
|
+
const countedDispatch = /* @__PURE__ */ __name((prompt, opts, workflowCallId) => {
|
|
1474
|
+
const stepId = readWorkflowStepId(opts.stepId);
|
|
1475
|
+
if (stepId !== void 0) opts = { ...opts, stepId };
|
|
1476
|
+
if (typeof prompt !== "string" || prompt.length === 0) {
|
|
1477
|
+
return rejectThroughPauseGate(
|
|
1478
|
+
new Error("agent() requires a non-empty string prompt.")
|
|
1479
|
+
);
|
|
1480
|
+
}
|
|
1481
|
+
let journalKey;
|
|
1482
|
+
let journalEntryId;
|
|
1483
|
+
let respawnLine;
|
|
1484
|
+
if (journal) {
|
|
1485
|
+
journalKey = deriveAgentKey(prefixHash, prompt, opts);
|
|
1486
|
+
prefixHash = journalKey;
|
|
1487
|
+
if (!hadMiss && replay) {
|
|
1488
|
+
const cached = replay.results.get(journalKey);
|
|
1489
|
+
if (cached !== void 0) {
|
|
1490
|
+
const respawns = replay.started.get(journalKey);
|
|
1491
|
+
if (respawns && respawns.length > 0) {
|
|
1492
|
+
debugLogger.info(
|
|
1493
|
+
`[Workflow] resume cache hit after ${respawns.length} prior respawn(s) for runId=${runId}.`
|
|
1494
|
+
);
|
|
1495
|
+
}
|
|
1496
|
+
const label2 = typeof opts.label === "string" ? opts.label : void 0;
|
|
1497
|
+
const dispatchId2 = issueDispatchTrace(
|
|
1498
|
+
prompt,
|
|
1499
|
+
opts,
|
|
1500
|
+
true,
|
|
1501
|
+
workflowCallId
|
|
1502
|
+
);
|
|
1503
|
+
try {
|
|
1504
|
+
emitter?.agentDispatched?.(label2);
|
|
1505
|
+
} catch (e) {
|
|
1506
|
+
debugLogger.warn("emitter.agentDispatched threw:", e);
|
|
1507
|
+
}
|
|
1508
|
+
try {
|
|
1509
|
+
emitter?.agentCompleted?.(label2);
|
|
1510
|
+
} catch (e) {
|
|
1511
|
+
debugLogger.warn("emitter.agentCompleted threw:", e);
|
|
1512
|
+
}
|
|
1513
|
+
try {
|
|
1514
|
+
emitter?.dispatchSettled?.(dispatchId2, void 0, Date.now());
|
|
1515
|
+
} catch (e) {
|
|
1516
|
+
debugLogger.warn("emitter.dispatchSettled threw:", e);
|
|
1517
|
+
}
|
|
1518
|
+
return scheduler.waitUntilRunning().then(
|
|
1519
|
+
() => cached.result,
|
|
1520
|
+
() => cached.result
|
|
1521
|
+
);
|
|
1522
|
+
}
|
|
1523
|
+
}
|
|
1524
|
+
const priorStarts = replay?.started.get(journalKey);
|
|
1525
|
+
if (priorStarts && priorStarts.length > 0 && !replay?.results.has(journalKey)) {
|
|
1526
|
+
const name = typeof opts.label === "string" ? `"${stripAnsiAndControl(opts.label)}"` : "an agent";
|
|
1527
|
+
respawnLine = replay?.failed.has(journalKey) ? `[resume] re-running ${name}: it failed in the previous run` : `[resume] respawning ${name}: interrupted in a previous run (${priorStarts.length} prior attempt${priorStarts.length === 1 ? "" : "s"})`;
|
|
1528
|
+
}
|
|
1529
|
+
hadMiss = true;
|
|
1530
|
+
}
|
|
1531
|
+
if (budget && budget.total !== null && budget.remaining() <= 0) {
|
|
1532
|
+
debugLogger.warn(
|
|
1533
|
+
`[Workflow] budget gate refused dispatch at entry: runId=${runId} spent=${budget.spent()} total=${budget.total}`
|
|
1534
|
+
);
|
|
1535
|
+
return rejectThroughPauseGate(
|
|
1536
|
+
new WorkflowBudgetExceededError(runId, budget.total, budget.spent())
|
|
1537
|
+
);
|
|
1538
|
+
}
|
|
1539
|
+
if (agentCount >= maxAgents) {
|
|
1540
|
+
return rejectThroughPauseGate(
|
|
1541
|
+
new WorkflowAgentCapExceededError(maxAgents)
|
|
1542
|
+
);
|
|
1543
|
+
}
|
|
1544
|
+
agentCount += 1;
|
|
1545
|
+
if (journal && journalKey !== void 0) {
|
|
1546
|
+
journalEntryId = String(journalAgentId += 1);
|
|
1547
|
+
}
|
|
1548
|
+
const label = typeof opts.label === "string" ? opts.label : void 0;
|
|
1549
|
+
const dispatchId = issueDispatchTrace(
|
|
1550
|
+
prompt,
|
|
1551
|
+
opts,
|
|
1552
|
+
false,
|
|
1553
|
+
workflowCallId
|
|
1554
|
+
);
|
|
1555
|
+
try {
|
|
1556
|
+
emitter?.agentDispatched?.(label);
|
|
1557
|
+
} catch (e) {
|
|
1558
|
+
debugLogger.warn("emitter.agentDispatched threw:", e);
|
|
1559
|
+
}
|
|
1560
|
+
let completionEmitted = false;
|
|
1561
|
+
const emitCompletion = /* @__PURE__ */ __name((error) => {
|
|
1562
|
+
if (completionEmitted) return;
|
|
1563
|
+
completionEmitted = true;
|
|
1564
|
+
const message = error === void 0 ? void 0 : error instanceof Error ? error.message : String(error);
|
|
1565
|
+
try {
|
|
1566
|
+
emitter?.agentCompleted?.(label, message);
|
|
1567
|
+
} catch (e) {
|
|
1568
|
+
debugLogger.warn("emitter.agentCompleted threw:", e);
|
|
1569
|
+
}
|
|
1570
|
+
try {
|
|
1571
|
+
emitter?.dispatchSettled?.(dispatchId, message, Date.now());
|
|
1572
|
+
} catch (e) {
|
|
1573
|
+
debugLogger.warn("emitter.dispatchSettled threw:", e);
|
|
1574
|
+
}
|
|
1575
|
+
}, "emitCompletion");
|
|
1576
|
+
return scheduler.run(async () => {
|
|
1577
|
+
try {
|
|
1578
|
+
try {
|
|
1579
|
+
emitter?.dispatchStarted?.(dispatchId, Date.now());
|
|
1580
|
+
} catch (e) {
|
|
1581
|
+
debugLogger.warn("emitter.dispatchStarted threw:", e);
|
|
1582
|
+
}
|
|
1583
|
+
if (budget && budget.total !== null && budget.remaining() <= 0) {
|
|
1584
|
+
debugLogger.warn(
|
|
1585
|
+
`[Workflow] budget gate refused dispatch at slot-acquire: runId=${runId} spent=${budget.spent()} total=${budget.total}`
|
|
1586
|
+
);
|
|
1587
|
+
throw new WorkflowBudgetExceededError(
|
|
1588
|
+
runId,
|
|
1589
|
+
budget.total,
|
|
1590
|
+
budget.spent()
|
|
1591
|
+
);
|
|
1592
|
+
}
|
|
1593
|
+
if (journal && journalKey !== void 0 && journalEntryId !== void 0) {
|
|
1594
|
+
journal.append({
|
|
1595
|
+
type: "started",
|
|
1596
|
+
key: journalKey,
|
|
1597
|
+
agentId: journalEntryId
|
|
1598
|
+
}).catch(
|
|
1599
|
+
(e) => debugLogger.warn(`journal started-append failed: ${e}`)
|
|
1600
|
+
);
|
|
1601
|
+
}
|
|
1602
|
+
if (respawnLine) {
|
|
1603
|
+
parentSandboxRef.current?.appendLog(respawnLine);
|
|
1604
|
+
try {
|
|
1605
|
+
emitter?.resumeRespawn?.(respawnLine);
|
|
1606
|
+
} catch (e) {
|
|
1607
|
+
debugLogger.warn("emitter.resumeRespawn threw:", e);
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
const result = await this.dispatch(prompt, opts, dispatchId);
|
|
1611
|
+
emitCompletion();
|
|
1612
|
+
if (journal && journalKey !== void 0) {
|
|
1613
|
+
journal.append({
|
|
1614
|
+
type: "result",
|
|
1615
|
+
key: journalKey,
|
|
1616
|
+
agentId: journalEntryId ?? "",
|
|
1617
|
+
result
|
|
1618
|
+
}).catch(
|
|
1619
|
+
(e) => debugLogger.warn(`journal result-append failed: ${e}`)
|
|
1620
|
+
);
|
|
1621
|
+
}
|
|
1622
|
+
if (budget) {
|
|
1623
|
+
try {
|
|
1624
|
+
emitter?.budgetUpdated?.(...runBudgetFigures(budget));
|
|
1625
|
+
} catch (e) {
|
|
1626
|
+
debugLogger.warn("emitter.budgetUpdated threw:", e);
|
|
1627
|
+
}
|
|
1628
|
+
}
|
|
1629
|
+
return result;
|
|
1630
|
+
} catch (err) {
|
|
1631
|
+
emitCompletion(err);
|
|
1632
|
+
if (budget) {
|
|
1633
|
+
try {
|
|
1634
|
+
emitter?.budgetUpdated?.(...runBudgetFigures(budget));
|
|
1635
|
+
} catch (e) {
|
|
1636
|
+
debugLogger.warn("emitter.budgetUpdated threw:", e);
|
|
1637
|
+
}
|
|
1638
|
+
}
|
|
1639
|
+
if (journal && journalKey !== void 0 && !signal?.aborted && !isWorkflowRunLevelError(err)) {
|
|
1640
|
+
journal.append({
|
|
1641
|
+
type: "failed",
|
|
1642
|
+
key: journalKey,
|
|
1643
|
+
agentId: journalEntryId ?? ""
|
|
1644
|
+
}).catch(
|
|
1645
|
+
(e) => debugLogger.warn(`journal failed-append failed: ${e}`)
|
|
1646
|
+
);
|
|
1647
|
+
}
|
|
1648
|
+
if (signal?.aborted || isWorkflowRunLevelError(err)) throw err;
|
|
1649
|
+
if (isWorkflowAgentFailedError(err)) {
|
|
1650
|
+
debugLogger.warn(
|
|
1651
|
+
`[Workflow] agent settled to null (${err.kind}): ${err.message}`
|
|
1652
|
+
);
|
|
1653
|
+
} else {
|
|
1654
|
+
debugLogger.warn(
|
|
1655
|
+
`[Workflow] agent settled to null: ${extractErrorMessage(err)}`
|
|
1656
|
+
);
|
|
1657
|
+
}
|
|
1658
|
+
return null;
|
|
1659
|
+
}
|
|
1660
|
+
}).then(
|
|
1661
|
+
// Resolve even if the gate aborts: a successful dispatch must not
|
|
1662
|
+
// turn into a teardown rejection — for a fire-and-forget call the
|
|
1663
|
+
// script never attached a handler, so the rejection would surface
|
|
1664
|
+
// as a spurious process-level unhandledRejection alarm on a
|
|
1665
|
+
// correctly-cancelled run.
|
|
1666
|
+
(result) => scheduler.waitUntilRunning().then(
|
|
1667
|
+
() => result,
|
|
1668
|
+
() => result
|
|
1669
|
+
),
|
|
1670
|
+
(error) => {
|
|
1671
|
+
emitCompletion(error);
|
|
1672
|
+
return scheduler.waitUntilRunning().then(
|
|
1673
|
+
() => {
|
|
1674
|
+
throw error;
|
|
1675
|
+
},
|
|
1676
|
+
() => {
|
|
1677
|
+
throw error;
|
|
1678
|
+
}
|
|
1679
|
+
);
|
|
1680
|
+
}
|
|
1681
|
+
);
|
|
1682
|
+
}, "countedDispatch");
|
|
1683
|
+
const parallelImpl = makeParallelImpl(signal, dependencyContext);
|
|
1684
|
+
const pipelineImpl = makePipelineImpl(signal, dependencyContext);
|
|
1685
|
+
let workflowCallCount = 0;
|
|
1686
|
+
const recordCall = /* @__PURE__ */ __name((call) => {
|
|
1687
|
+
try {
|
|
1688
|
+
emitter?.workflowCallUpdated?.({ ...call });
|
|
1689
|
+
} catch (error) {
|
|
1690
|
+
debugLogger.warn("emitter.workflowCallUpdated threw:", error);
|
|
1691
|
+
}
|
|
1692
|
+
}, "recordCall");
|
|
1693
|
+
const resolveSavedWorkflow = req.resolveSavedWorkflow;
|
|
1694
|
+
const workflowImpl = resolveSavedWorkflow ? async (nameOrRef, nestedArgs, stepId) => {
|
|
1695
|
+
const call = {
|
|
1696
|
+
id: `workflow-call-${++workflowCallCount}`,
|
|
1697
|
+
...stepId !== void 0 ? { stepId: readWorkflowStepId(stepId) } : {},
|
|
1698
|
+
...typeof nameOrRef === "string" ? { workflowName: nameOrRef } : {},
|
|
1699
|
+
status: "running",
|
|
1700
|
+
startedAt: Date.now()
|
|
1701
|
+
};
|
|
1702
|
+
const recorded = workflowCallCount <= MAX_WORKFLOW_CALL_TRACES;
|
|
1703
|
+
if (recorded) recordCall(call);
|
|
1704
|
+
else if (workflowCallCount === MAX_WORKFLOW_CALL_TRACES + 1) {
|
|
1705
|
+
try {
|
|
1706
|
+
emitter?.workflowCallsTruncated?.();
|
|
1707
|
+
} catch (error) {
|
|
1708
|
+
debugLogger.warn("emitter.workflowCallsTruncated threw:", error);
|
|
1709
|
+
}
|
|
1710
|
+
}
|
|
1711
|
+
let nestedSandbox;
|
|
1712
|
+
try {
|
|
1713
|
+
const resolved = await resolveSavedWorkflow(nameOrRef);
|
|
1714
|
+
if (resolved.name) call.workflowName = resolved.name;
|
|
1715
|
+
nestedSandbox = createWorkflowSandbox({
|
|
1716
|
+
args: nestedArgs,
|
|
1717
|
+
runId,
|
|
1718
|
+
// Each sandbox closes over its own call, including parallel and cached dispatches.
|
|
1719
|
+
dispatch: /* @__PURE__ */ __name((prompt, opts) => countedDispatch(prompt, opts, call.id), "dispatch"),
|
|
1720
|
+
parallel: parallelImpl,
|
|
1721
|
+
pipeline: pipelineImpl,
|
|
1722
|
+
abortOnTimeout: req.abortOnTimeout,
|
|
1723
|
+
emitter,
|
|
1724
|
+
budget,
|
|
1725
|
+
scheduler
|
|
1726
|
+
// No workflow implementation: preserve single-level nesting.
|
|
1727
|
+
});
|
|
1728
|
+
const result = await nestedSandbox.run(resolved.script);
|
|
1729
|
+
call.status = signal?.aborted ? "cancelled" : "completed";
|
|
1730
|
+
return result;
|
|
1731
|
+
} catch (error) {
|
|
1732
|
+
call.status = signal?.aborted ? "cancelled" : "failed";
|
|
1733
|
+
try {
|
|
1734
|
+
const message = typeof error === "string" ? error : error && typeof error === "object" ? Object.getOwnPropertyDescriptor(error, "message")?.value : void 0;
|
|
1735
|
+
if (typeof message === "string") call.error = message;
|
|
1736
|
+
} catch {
|
|
1737
|
+
}
|
|
1738
|
+
throw error;
|
|
1739
|
+
} finally {
|
|
1740
|
+
call.endedAt = Date.now();
|
|
1741
|
+
if (recorded) recordCall(call);
|
|
1742
|
+
for (const line of nestedSandbox?.getLogs() ?? []) {
|
|
1743
|
+
parentSandboxRef.current?.appendLog(line);
|
|
1744
|
+
}
|
|
1745
|
+
}
|
|
1746
|
+
} : void 0;
|
|
1747
|
+
const sandbox = createWorkflowSandbox({
|
|
1748
|
+
args: req.args,
|
|
1749
|
+
maxWallClockMs: req.maxWallClockMs,
|
|
1750
|
+
runId,
|
|
1751
|
+
dispatch: countedDispatch,
|
|
1752
|
+
parallel: parallelImpl,
|
|
1753
|
+
pipeline: pipelineImpl,
|
|
1754
|
+
workflow: workflowImpl,
|
|
1755
|
+
abortOnTimeout: req.abortOnTimeout,
|
|
1756
|
+
emitter,
|
|
1757
|
+
budget,
|
|
1758
|
+
scheduler
|
|
1759
|
+
});
|
|
1760
|
+
parentSandboxRef.current = sandbox;
|
|
1761
|
+
try {
|
|
1762
|
+
const result = await dependencyContext.run(
|
|
1763
|
+
{ tails: [] },
|
|
1764
|
+
() => sandbox.run(req.script)
|
|
1765
|
+
);
|
|
1766
|
+
return {
|
|
1767
|
+
runId,
|
|
1768
|
+
result,
|
|
1769
|
+
phases: sandbox.getPhases(),
|
|
1770
|
+
logs: sandbox.getLogs(),
|
|
1771
|
+
meta: sandbox.getMeta()
|
|
1772
|
+
};
|
|
1773
|
+
} catch (err) {
|
|
1774
|
+
throw new WorkflowExecutionError(
|
|
1775
|
+
extractErrorMessage(err),
|
|
1776
|
+
sandbox.getPhases(),
|
|
1777
|
+
sandbox.getLogs(),
|
|
1778
|
+
sandbox.getMeta()
|
|
1779
|
+
);
|
|
1780
|
+
}
|
|
1781
|
+
}
|
|
1782
|
+
};
|
|
1783
|
+
async function settleToNullArray(thunks, signal) {
|
|
1784
|
+
const settled = await Promise.allSettled(
|
|
1785
|
+
thunks.map((t) => Promise.resolve().then(t))
|
|
1786
|
+
);
|
|
1787
|
+
if (signal?.aborted)
|
|
1788
|
+
throw new DOMException("Workflow run aborted.", "AbortError");
|
|
1789
|
+
const visitedReasons = /* @__PURE__ */ new WeakSet();
|
|
1790
|
+
const findRunFailureReason = /* @__PURE__ */ __name((reason) => {
|
|
1791
|
+
if (reason === null || typeof reason !== "object") return void 0;
|
|
1792
|
+
if (visitedReasons.has(reason)) return void 0;
|
|
1793
|
+
visitedReasons.add(reason);
|
|
1794
|
+
try {
|
|
1795
|
+
if (reason.__wfRunFailure === true) {
|
|
1796
|
+
return reason;
|
|
1797
|
+
}
|
|
1798
|
+
const errors = reason?.errors;
|
|
1799
|
+
if (!Array.isArray(errors)) return void 0;
|
|
1800
|
+
for (const error of errors) {
|
|
1801
|
+
const runFailure = findRunFailureReason(error);
|
|
1802
|
+
if (runFailure !== void 0) return runFailure;
|
|
1803
|
+
}
|
|
1804
|
+
} catch {
|
|
1805
|
+
return void 0;
|
|
1806
|
+
}
|
|
1807
|
+
return void 0;
|
|
1808
|
+
}, "findRunFailureReason");
|
|
1809
|
+
for (const result of settled) {
|
|
1810
|
+
if (result.status !== "rejected") continue;
|
|
1811
|
+
const runFailure = findRunFailureReason(result.reason);
|
|
1812
|
+
if (runFailure !== void 0) throw runFailure;
|
|
1813
|
+
}
|
|
1814
|
+
return settled.map((r, i) => {
|
|
1815
|
+
if (r.status === "fulfilled") return r.value;
|
|
1816
|
+
const reason = r.reason;
|
|
1817
|
+
debugLogger.warn(
|
|
1818
|
+
`Workflow thunk at index ${i} rejected: ${String(reason?.message ?? r.reason)}`
|
|
1819
|
+
);
|
|
1820
|
+
return null;
|
|
1821
|
+
});
|
|
1822
|
+
}
|
|
1823
|
+
__name(settleToNullArray, "settleToNullArray");
|
|
1824
|
+
function makeParallelImpl(signal, dependencyContext) {
|
|
1825
|
+
return (thunks) => {
|
|
1826
|
+
if (!Array.isArray(thunks)) {
|
|
1827
|
+
return Promise.reject(
|
|
1828
|
+
new Error(
|
|
1829
|
+
"parallel() expects an array of thunks (functions returning promises)."
|
|
1830
|
+
)
|
|
1831
|
+
);
|
|
1832
|
+
}
|
|
1833
|
+
for (const t of thunks) {
|
|
1834
|
+
if (typeof t !== "function") {
|
|
1835
|
+
return Promise.reject(
|
|
1836
|
+
new Error(
|
|
1837
|
+
"parallel() expects an array of functions, not values \u2014 wrap each call: parallel([() => agent(...), () => agent(...)])."
|
|
1838
|
+
)
|
|
1839
|
+
);
|
|
1840
|
+
}
|
|
1841
|
+
}
|
|
1842
|
+
const parent = dependencyContext.getStore();
|
|
1843
|
+
const inheritedTails = parent?.tails ?? [];
|
|
1844
|
+
const branches = thunks.map((thunk) => {
|
|
1845
|
+
const store = { tails: [...inheritedTails] };
|
|
1846
|
+
return {
|
|
1847
|
+
store,
|
|
1848
|
+
thunk: /* @__PURE__ */ __name(() => dependencyContext.run(store, thunk), "thunk")
|
|
1849
|
+
};
|
|
1850
|
+
});
|
|
1851
|
+
return settleToNullArray(
|
|
1852
|
+
branches.map(({ thunk }) => thunk),
|
|
1853
|
+
signal
|
|
1854
|
+
).then((result) => {
|
|
1855
|
+
if (parent && branches.length > 0) {
|
|
1856
|
+
parent.tails = mergeFanoutTails(
|
|
1857
|
+
parent.tails,
|
|
1858
|
+
inheritedTails,
|
|
1859
|
+
branches.flatMap(({ store }) => store.tails)
|
|
1860
|
+
);
|
|
1861
|
+
}
|
|
1862
|
+
return result;
|
|
1863
|
+
});
|
|
1864
|
+
};
|
|
1865
|
+
}
|
|
1866
|
+
__name(makeParallelImpl, "makeParallelImpl");
|
|
1867
|
+
function makePipelineImpl(signal, dependencyContext) {
|
|
1868
|
+
return (items, ...stages) => {
|
|
1869
|
+
if (!Array.isArray(items)) {
|
|
1870
|
+
return Promise.reject(
|
|
1871
|
+
new Error(
|
|
1872
|
+
"pipeline() expects an array of items as its first argument."
|
|
1873
|
+
)
|
|
1874
|
+
);
|
|
1875
|
+
}
|
|
1876
|
+
for (const s of stages) {
|
|
1877
|
+
if (typeof s !== "function") {
|
|
1878
|
+
return Promise.reject(
|
|
1879
|
+
new Error(
|
|
1880
|
+
"pipeline() stages must be functions: pipeline(items, item => ..., result => ...)."
|
|
1881
|
+
)
|
|
1882
|
+
);
|
|
1883
|
+
}
|
|
1884
|
+
}
|
|
1885
|
+
const parent = dependencyContext.getStore();
|
|
1886
|
+
const inheritedTails = parent?.tails ?? [];
|
|
1887
|
+
const branches = items.map((item, idx) => {
|
|
1888
|
+
const store = { tails: [...inheritedTails] };
|
|
1889
|
+
return {
|
|
1890
|
+
store,
|
|
1891
|
+
thunk: /* @__PURE__ */ __name(() => dependencyContext.run(
|
|
1892
|
+
store,
|
|
1893
|
+
() => runPipelineChain(item, idx, stages)
|
|
1894
|
+
), "thunk")
|
|
1895
|
+
};
|
|
1896
|
+
});
|
|
1897
|
+
return settleToNullArray(
|
|
1898
|
+
branches.map(({ thunk }) => thunk),
|
|
1899
|
+
signal
|
|
1900
|
+
).then((result) => {
|
|
1901
|
+
if (parent && branches.length > 0) {
|
|
1902
|
+
parent.tails = mergeFanoutTails(
|
|
1903
|
+
parent.tails,
|
|
1904
|
+
inheritedTails,
|
|
1905
|
+
branches.flatMap(({ store }) => store.tails)
|
|
1906
|
+
);
|
|
1907
|
+
}
|
|
1908
|
+
return result;
|
|
1909
|
+
});
|
|
1910
|
+
};
|
|
1911
|
+
}
|
|
1912
|
+
__name(makePipelineImpl, "makePipelineImpl");
|
|
1913
|
+
function mergeFanoutTails(currentParentTails, inheritedTails, branchTails) {
|
|
1914
|
+
const inherited = new Set(inheritedTails);
|
|
1915
|
+
const newBranchTails = branchTails.filter((tail) => !inherited.has(tail));
|
|
1916
|
+
const merged = newBranchTails.length > 0 ? [
|
|
1917
|
+
...newBranchTails,
|
|
1918
|
+
...currentParentTails.filter((tail) => !inherited.has(tail))
|
|
1919
|
+
] : currentParentTails;
|
|
1920
|
+
return Array.from(new Set(merged));
|
|
1921
|
+
}
|
|
1922
|
+
__name(mergeFanoutTails, "mergeFanoutTails");
|
|
1923
|
+
async function runPipelineChain(item, idx, stages) {
|
|
1924
|
+
let prev = item;
|
|
1925
|
+
for (const stage of stages) {
|
|
1926
|
+
if (prev === null) break;
|
|
1927
|
+
prev = await stage(prev, item, idx);
|
|
1928
|
+
}
|
|
1929
|
+
return prev;
|
|
1930
|
+
}
|
|
1931
|
+
__name(runPipelineChain, "runPipelineChain");
|
|
1932
|
+
function extractErrorMessage(err) {
|
|
1933
|
+
if (err && typeof err === "object" && "message" in err) {
|
|
1934
|
+
const m = err.message;
|
|
1935
|
+
if (typeof m === "string") return m;
|
|
1936
|
+
return String(m);
|
|
1937
|
+
}
|
|
1938
|
+
return String(err);
|
|
1939
|
+
}
|
|
1940
|
+
__name(extractErrorMessage, "extractErrorMessage");
|
|
1941
|
+
|
|
1942
|
+
// packages/core/src/agents/workflow-snapshot.ts
|
|
1943
|
+
init_esbuild_shims();
|
|
1944
|
+
import { promises as fs2 } from "node:fs";
|
|
1945
|
+
import path2 from "node:path";
|
|
1946
|
+
var debugLogger5 = createDebugLogger("WORKFLOW_SNAPSHOT");
|
|
1947
|
+
var MAX_RETAINED_SNAPSHOTS = 30;
|
|
1948
|
+
function toSnapshot(task) {
|
|
1949
|
+
if (!isTerminalWorkflowStatus(task.status)) {
|
|
1950
|
+
throw new Error(`Cannot snapshot active workflow ${task.runId}.`);
|
|
1951
|
+
}
|
|
1952
|
+
return {
|
|
1953
|
+
runId: task.runId,
|
|
1954
|
+
...task.sourceRef ? { sourceRef: { ...task.sourceRef } } : {},
|
|
1955
|
+
...task.workflowCalls ? { workflowCalls: task.workflowCalls.map((call) => ({ ...call })) } : {},
|
|
1956
|
+
...task.workflowCallsTruncated ? { workflowCallsTruncated: true } : {},
|
|
1957
|
+
...task.toolUseId ? { toolUseId: task.toolUseId } : {},
|
|
1958
|
+
description: task.description,
|
|
1959
|
+
...task.workflowName ? { workflowName: task.workflowName } : {},
|
|
1960
|
+
sourceRunId: task.sourceRunId,
|
|
1961
|
+
startMode: task.startMode,
|
|
1962
|
+
meta: task.meta,
|
|
1963
|
+
status: task.status,
|
|
1964
|
+
script: task.script ?? "",
|
|
1965
|
+
scriptPath: task.scriptPath,
|
|
1966
|
+
phases: [...task.phases],
|
|
1967
|
+
phaseVisits: task.phaseVisits.map((visit) => ({ ...visit })),
|
|
1968
|
+
dispatches: task.dispatches.map((dispatch) => ({
|
|
1969
|
+
...dispatch,
|
|
1970
|
+
dependsOn: [...dispatch.dependsOn]
|
|
1971
|
+
})),
|
|
1972
|
+
agentsDispatched: task.agentsDispatched,
|
|
1973
|
+
agentsCompleted: task.agentsCompleted,
|
|
1974
|
+
agentsRespawned: task.agentsRespawned ?? 0,
|
|
1975
|
+
...task.sizeWarning ? { sizeWarning: { ...task.sizeWarning } } : {},
|
|
1976
|
+
tokensSpent: task.tokensSpent,
|
|
1977
|
+
tokenBudgetTotal: task.tokenBudgetTotal,
|
|
1978
|
+
perPhaseTokens: Array.from(task.perPhaseTokens.entries()),
|
|
1979
|
+
recentLogs: [...task.recentLogs],
|
|
1980
|
+
events: task.events.map((event) => ({ ...event })),
|
|
1981
|
+
startTime: task.startTime,
|
|
1982
|
+
endTime: task.endTime,
|
|
1983
|
+
result: safeResult(task.result),
|
|
1984
|
+
error: task.error
|
|
1985
|
+
};
|
|
1986
|
+
}
|
|
1987
|
+
__name(toSnapshot, "toSnapshot");
|
|
1988
|
+
function safeResult(result) {
|
|
1989
|
+
if (result === void 0) return void 0;
|
|
1990
|
+
try {
|
|
1991
|
+
JSON.stringify(result);
|
|
1992
|
+
return result;
|
|
1993
|
+
} catch {
|
|
1994
|
+
return `(non-JSON-serializable ${typeof result})`;
|
|
1995
|
+
}
|
|
1996
|
+
}
|
|
1997
|
+
__name(safeResult, "safeResult");
|
|
1998
|
+
async function writeWorkflowSnapshot(config, task) {
|
|
1999
|
+
const storage = config.storage;
|
|
2000
|
+
if (!storage) return false;
|
|
2001
|
+
try {
|
|
2002
|
+
const snapshot = toSnapshot(task);
|
|
2003
|
+
const dir = storage.getWorkflowRunsDir();
|
|
2004
|
+
await fs2.mkdir(dir, { recursive: true });
|
|
2005
|
+
await fs2.writeFile(
|
|
2006
|
+
storage.getWorkflowRunSnapshotPath(task.runId),
|
|
2007
|
+
JSON.stringify(snapshot, null, 2),
|
|
2008
|
+
"utf8"
|
|
2009
|
+
);
|
|
2010
|
+
await pruneSnapshots(config, dir);
|
|
2011
|
+
return true;
|
|
2012
|
+
} catch (e) {
|
|
2013
|
+
debugLogger5.warn(`writeWorkflowSnapshot failed for ${task.runId}: ${e}`);
|
|
2014
|
+
return false;
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
2017
|
+
__name(writeWorkflowSnapshot, "writeWorkflowSnapshot");
|
|
2018
|
+
async function listWorkflowSnapshots(config) {
|
|
2019
|
+
const storage = config.storage;
|
|
2020
|
+
if (!storage) return [];
|
|
2021
|
+
const dir = storage.getWorkflowRunsDir();
|
|
2022
|
+
let files;
|
|
2023
|
+
try {
|
|
2024
|
+
files = (await fs2.readdir(dir)).filter((f) => f.endsWith(".json"));
|
|
2025
|
+
} catch {
|
|
2026
|
+
return [];
|
|
2027
|
+
}
|
|
2028
|
+
const snapshots = [];
|
|
2029
|
+
for (const file of files) {
|
|
2030
|
+
try {
|
|
2031
|
+
const raw = await fs2.readFile(`${dir}/${file}`, "utf8");
|
|
2032
|
+
const parsed = JSON.parse(raw);
|
|
2033
|
+
if (!isWorkflowSnapshot(parsed)) {
|
|
2034
|
+
debugLogger5.warn(`skipping invalid workflow snapshot ${file}`);
|
|
2035
|
+
continue;
|
|
2036
|
+
}
|
|
2037
|
+
snapshots.push(parsed);
|
|
2038
|
+
} catch (e) {
|
|
2039
|
+
debugLogger5.warn(`skipping unparseable snapshot ${file}: ${e}`);
|
|
2040
|
+
}
|
|
2041
|
+
}
|
|
2042
|
+
snapshots.sort((a, b) => (b.startTime ?? 0) - (a.startTime ?? 0));
|
|
2043
|
+
return snapshots;
|
|
2044
|
+
}
|
|
2045
|
+
__name(listWorkflowSnapshots, "listWorkflowSnapshots");
|
|
2046
|
+
async function deleteWorkflowSnapshot(config, runId) {
|
|
2047
|
+
const storage = config.storage;
|
|
2048
|
+
if (!storage || !/^wf_[0-9a-f]+$/.test(runId)) return false;
|
|
2049
|
+
try {
|
|
2050
|
+
await fs2.rm(path2.dirname(storage.getWorkflowRunJournalPath(runId)), {
|
|
2051
|
+
recursive: true,
|
|
2052
|
+
force: true
|
|
2053
|
+
});
|
|
2054
|
+
} catch (error) {
|
|
2055
|
+
debugLogger5.warn(`delete workflow journal failed for ${runId}: ${error}`);
|
|
2056
|
+
return false;
|
|
2057
|
+
}
|
|
2058
|
+
if (!await deleteInlineWorkflowScript(config, runId)) return false;
|
|
2059
|
+
try {
|
|
2060
|
+
await fs2.unlink(storage.getWorkflowRunSnapshotPath(runId));
|
|
2061
|
+
} catch (error) {
|
|
2062
|
+
if (error.code !== "ENOENT") {
|
|
2063
|
+
debugLogger5.warn(`deleteWorkflowSnapshot failed for ${runId}: ${error}`);
|
|
2064
|
+
return false;
|
|
2065
|
+
}
|
|
2066
|
+
}
|
|
2067
|
+
return true;
|
|
2068
|
+
}
|
|
2069
|
+
__name(deleteWorkflowSnapshot, "deleteWorkflowSnapshot");
|
|
2070
|
+
function isRecord(value) {
|
|
2071
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2072
|
+
}
|
|
2073
|
+
__name(isRecord, "isRecord");
|
|
2074
|
+
function isFiniteNumber(value) {
|
|
2075
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
2076
|
+
}
|
|
2077
|
+
__name(isFiniteNumber, "isFiniteNumber");
|
|
2078
|
+
function isOptionalString(value) {
|
|
2079
|
+
return value === void 0 || typeof value === "string";
|
|
2080
|
+
}
|
|
2081
|
+
__name(isOptionalString, "isOptionalString");
|
|
2082
|
+
function isStringArray(value) {
|
|
2083
|
+
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
2084
|
+
}
|
|
2085
|
+
__name(isStringArray, "isStringArray");
|
|
2086
|
+
function isWorkflowMeta(value) {
|
|
2087
|
+
if (value === null) return true;
|
|
2088
|
+
if (!isRecord(value)) return false;
|
|
2089
|
+
if (typeof value["name"] !== "string" || typeof value["description"] !== "string" || !isOptionalString(value["whenToUse"])) {
|
|
2090
|
+
return false;
|
|
2091
|
+
}
|
|
2092
|
+
const phases = value["phases"];
|
|
2093
|
+
return phases === void 0 || Array.isArray(phases) && phases.every(
|
|
2094
|
+
(phase) => isRecord(phase) && typeof phase["title"] === "string" && isOptionalString(phase["detail"]) && isOptionalString(phase["model"])
|
|
2095
|
+
);
|
|
2096
|
+
}
|
|
2097
|
+
__name(isWorkflowMeta, "isWorkflowMeta");
|
|
2098
|
+
function isWorkflowPhaseVisit(value) {
|
|
2099
|
+
return isRecord(value) && typeof value["id"] === "string" && isFiniteNumber(value["index"]) && typeof value["title"] === "string" && isFiniteNumber(value["startedAt"]) && (value["endedAt"] === void 0 || isFiniteNumber(value["endedAt"]));
|
|
2100
|
+
}
|
|
2101
|
+
__name(isWorkflowPhaseVisit, "isWorkflowPhaseVisit");
|
|
2102
|
+
function isWorkflowDispatch(value) {
|
|
2103
|
+
if (!isRecord(value)) return false;
|
|
2104
|
+
const status = value["status"];
|
|
2105
|
+
return typeof value["id"] === "string" && (value["phaseVisitId"] === null || typeof value["phaseVisitId"] === "string") && typeof value["label"] === "string" && typeof value["prompt"] === "string" && isOptionalString(value["subagentId"]) && isOptionalString(value["stepId"]) && isOptionalString(value["workflowCallId"]) && (status === "queued" || status === "running" || status === "completed" || status === "failed" || status === "cancelled" || status === "cached") && isStringArray(value["dependsOn"]) && isFiniteNumber(value["queuedAt"]) && (value["startedAt"] === void 0 || isFiniteNumber(value["startedAt"])) && (value["endedAt"] === void 0 || isFiniteNumber(value["endedAt"])) && isOptionalString(value["error"]);
|
|
2106
|
+
}
|
|
2107
|
+
__name(isWorkflowDispatch, "isWorkflowDispatch");
|
|
2108
|
+
function hasOnlyKeys(value, keys) {
|
|
2109
|
+
const allowed = new Set(keys);
|
|
2110
|
+
return Object.keys(value).every((key) => allowed.has(key));
|
|
2111
|
+
}
|
|
2112
|
+
__name(hasOnlyKeys, "hasOnlyKeys");
|
|
2113
|
+
function isWorkflowEvent(value) {
|
|
2114
|
+
if (!isRecord(value) || typeof value["id"] !== "string" || !isFiniteNumber(value["at"]) || typeof value["type"] !== "string") {
|
|
2115
|
+
return false;
|
|
2116
|
+
}
|
|
2117
|
+
const base = ["id", "type", "at"];
|
|
2118
|
+
switch (value["type"]) {
|
|
2119
|
+
case "phase-started":
|
|
2120
|
+
return hasOnlyKeys(value, [...base, "phaseVisitId", "title"]) && typeof value["phaseVisitId"] === "string" && typeof value["title"] === "string";
|
|
2121
|
+
case "phase-completed":
|
|
2122
|
+
return hasOnlyKeys(value, [...base, "phaseVisitId"]) && typeof value["phaseVisitId"] === "string";
|
|
2123
|
+
case "dispatch-queued":
|
|
2124
|
+
case "dispatch-started":
|
|
2125
|
+
case "dispatch-completed":
|
|
2126
|
+
case "dispatch-cancelled":
|
|
2127
|
+
case "dispatch-cached":
|
|
2128
|
+
return hasOnlyKeys(value, [...base, "dispatchId"]) && typeof value["dispatchId"] === "string";
|
|
2129
|
+
case "dispatch-failed":
|
|
2130
|
+
return hasOnlyKeys(value, [...base, "dispatchId", "error"]) && typeof value["dispatchId"] === "string" && typeof value["error"] === "string";
|
|
2131
|
+
case "log":
|
|
2132
|
+
return hasOnlyKeys(value, [...base, "message"]) && typeof value["message"] === "string";
|
|
2133
|
+
case "approval-requested":
|
|
2134
|
+
case "approval-settled":
|
|
2135
|
+
return hasOnlyKeys(value, [...base, "name", "dispatchId"]) && typeof value["name"] === "string" && isOptionalString(value["dispatchId"]);
|
|
2136
|
+
case "workflow-completed":
|
|
2137
|
+
case "workflow-cancelled":
|
|
2138
|
+
return hasOnlyKeys(value, base);
|
|
2139
|
+
case "workflow-failed":
|
|
2140
|
+
return hasOnlyKeys(value, [...base, "error"]) && typeof value["error"] === "string";
|
|
2141
|
+
default:
|
|
2142
|
+
return false;
|
|
2143
|
+
}
|
|
2144
|
+
}
|
|
2145
|
+
__name(isWorkflowEvent, "isWorkflowEvent");
|
|
2146
|
+
function isWorkflowCall(value) {
|
|
2147
|
+
if (!isRecord(value)) return false;
|
|
2148
|
+
const status = value["status"];
|
|
2149
|
+
return typeof value["id"] === "string" && isOptionalString(value["stepId"]) && isOptionalString(value["workflowName"]) && (status === "running" || status === "completed" || status === "failed" || status === "cancelled") && isFiniteNumber(value["startedAt"]) && (value["endedAt"] === void 0 || isFiniteNumber(value["endedAt"])) && isOptionalString(value["error"]);
|
|
2150
|
+
}
|
|
2151
|
+
__name(isWorkflowCall, "isWorkflowCall");
|
|
2152
|
+
function isWorkflowSnapshot(value) {
|
|
2153
|
+
if (!isRecord(value)) return false;
|
|
2154
|
+
const status = value["status"];
|
|
2155
|
+
const workflowCalls = value["workflowCalls"];
|
|
2156
|
+
const phaseVisits = value["phaseVisits"];
|
|
2157
|
+
const dispatches = value["dispatches"];
|
|
2158
|
+
const events = value["events"];
|
|
2159
|
+
const perPhaseTokens = value["perPhaseTokens"];
|
|
2160
|
+
return (value["sourceRef"] === void 0 || isWorkflowSourceRef(value["sourceRef"])) && (workflowCalls === void 0 || Array.isArray(workflowCalls) && workflowCalls.length <= MAX_WORKFLOW_CALL_TRACES && workflowCalls.every(isWorkflowCall)) && (value["workflowCallsTruncated"] === void 0 || typeof value["workflowCallsTruncated"] === "boolean") && typeof value["runId"] === "string" && value["runId"].length > 0 && isOptionalString(value["toolUseId"]) && isOptionalString(value["description"]) && isOptionalString(value["workflowName"]) && isOptionalString(value["sourceRunId"]) && (value["startMode"] === void 0 || value["startMode"] === "retry" || value["startMode"] === "rerun") && isWorkflowMeta(value["meta"]) && (status === "completed" || status === "failed" || status === "cancelled") && typeof value["script"] === "string" && isOptionalString(value["scriptPath"]) && isStringArray(value["phases"]) && (phaseVisits === void 0 || Array.isArray(phaseVisits) && phaseVisits.every(isWorkflowPhaseVisit)) && (dispatches === void 0 || Array.isArray(dispatches) && dispatches.every(isWorkflowDispatch)) && (events === void 0 || Array.isArray(events) && events.every(isWorkflowEvent)) && isFiniteNumber(value["agentsDispatched"]) && isFiniteNumber(value["agentsCompleted"]) && (value["agentsRespawned"] === void 0 || isFiniteNumber(value["agentsRespawned"])) && (value["sizeWarning"] === void 0 || isWorkflowSizeWarning(value["sizeWarning"])) && isFiniteNumber(value["tokensSpent"]) && (value["tokenBudgetTotal"] === null || isFiniteNumber(value["tokenBudgetTotal"])) && Array.isArray(perPhaseTokens) && perPhaseTokens.every(
|
|
2161
|
+
(entry) => Array.isArray(entry) && entry.length === 2 && (entry[0] === null || typeof entry[0] === "string") && isFiniteNumber(entry[1])
|
|
2162
|
+
) && isStringArray(value["recentLogs"]) && isFiniteNumber(value["startTime"]) && (value["endTime"] === void 0 || isFiniteNumber(value["endTime"])) && isOptionalString(value["error"]);
|
|
2163
|
+
}
|
|
2164
|
+
__name(isWorkflowSnapshot, "isWorkflowSnapshot");
|
|
2165
|
+
async function pruneSnapshots(config, dir) {
|
|
2166
|
+
let files;
|
|
2167
|
+
try {
|
|
2168
|
+
files = (await fs2.readdir(dir)).filter((f) => f.endsWith(".json"));
|
|
2169
|
+
} catch {
|
|
2170
|
+
return;
|
|
2171
|
+
}
|
|
2172
|
+
if (files.length <= MAX_RETAINED_SNAPSHOTS) return;
|
|
2173
|
+
const stats = await Promise.all(
|
|
2174
|
+
files.map(async (f) => {
|
|
2175
|
+
try {
|
|
2176
|
+
const s = await fs2.stat(`${dir}/${f}`);
|
|
2177
|
+
return { f, mtime: s.mtimeMs };
|
|
2178
|
+
} catch {
|
|
2179
|
+
return { f, mtime: 0 };
|
|
2180
|
+
}
|
|
2181
|
+
})
|
|
2182
|
+
);
|
|
2183
|
+
stats.sort((a, b) => a.mtime - b.mtime);
|
|
2184
|
+
const toPrune = stats.slice(0, stats.length - MAX_RETAINED_SNAPSHOTS);
|
|
2185
|
+
const registry = config.getWorkflowRunRegistry?.();
|
|
2186
|
+
const protectedRunIds = /* @__PURE__ */ new Set([
|
|
2187
|
+
...(registry?.list() ?? []).filter((entry) => isActiveWorkflowStatus(entry.status)).map((entry) => entry.runId),
|
|
2188
|
+
...registry?.listStartingRunIds() ?? []
|
|
2189
|
+
]);
|
|
2190
|
+
await Promise.all(
|
|
2191
|
+
toPrune.map((s) => {
|
|
2192
|
+
const runId = s.f.replace(/\.json$/, "");
|
|
2193
|
+
const isRunDir = /^wf_[0-9a-f]+$/.test(runId);
|
|
2194
|
+
const deleteArtifacts = isRunDir && !protectedRunIds.has(runId) && !isWorkflowRunPersistenceActive(config, runId);
|
|
2195
|
+
return Promise.all([
|
|
2196
|
+
fs2.unlink(`${dir}/${s.f}`).catch(
|
|
2197
|
+
(e) => debugLogger5.warn(`prune unlink failed for ${s.f}: ${e}`)
|
|
2198
|
+
),
|
|
2199
|
+
...deleteArtifacts ? [
|
|
2200
|
+
fs2.rm(
|
|
2201
|
+
path2.dirname(config.storage.getWorkflowRunJournalPath(runId)),
|
|
2202
|
+
{ recursive: true, force: true }
|
|
2203
|
+
).catch(
|
|
2204
|
+
(e) => debugLogger5.warn(
|
|
2205
|
+
`prune journal dir failed for ${runId}: ${e}`
|
|
2206
|
+
)
|
|
2207
|
+
),
|
|
2208
|
+
deleteInlineWorkflowScript(config, runId)
|
|
2209
|
+
] : []
|
|
2210
|
+
]);
|
|
2211
|
+
})
|
|
2212
|
+
);
|
|
2213
|
+
}
|
|
2214
|
+
__name(pruneSnapshots, "pruneSnapshots");
|
|
2215
|
+
|
|
2216
|
+
// packages/core/src/agents/runtime/workflow-script-shape.ts
|
|
2217
|
+
init_esbuild_shims();
|
|
2218
|
+
var PROMPT_SUMMARY_CHARS = 60;
|
|
2219
|
+
var LOOP_HEAD_CHARS = 40;
|
|
2220
|
+
var MAX_PROMPTS_PER_ROW = 2;
|
|
2221
|
+
var MAX_VIOLATIONS_LISTED = 5;
|
|
2222
|
+
var PROMPT_READ_LIMIT = 400;
|
|
2223
|
+
var IDENT_START = /[A-Za-z_$]/;
|
|
2224
|
+
var IDENT_PART = /[A-Za-z0-9_$]/;
|
|
2225
|
+
var SPACE = /\s/;
|
|
2226
|
+
function maskNonCode(source) {
|
|
2227
|
+
const n = source.length;
|
|
2228
|
+
const out = source.split("");
|
|
2229
|
+
const blank = /* @__PURE__ */ __name((from, to) => {
|
|
2230
|
+
for (let k = from; k < to && k < n; k++) {
|
|
2231
|
+
if (out[k] !== "\n" && out[k] !== "\r") out[k] = " ";
|
|
2232
|
+
}
|
|
2233
|
+
}, "blank");
|
|
2234
|
+
const templateStack = [];
|
|
2235
|
+
let braceDepth = 0;
|
|
2236
|
+
const scanTemplateText = /* @__PURE__ */ __name((from) => {
|
|
2237
|
+
let j = from;
|
|
2238
|
+
while (j < n) {
|
|
2239
|
+
const ch = source[j];
|
|
2240
|
+
if (ch === "\\") {
|
|
2241
|
+
j += 2;
|
|
2242
|
+
continue;
|
|
2243
|
+
}
|
|
2244
|
+
if (ch === "`") {
|
|
2245
|
+
blank(from, j + 1);
|
|
2246
|
+
return j + 1;
|
|
2247
|
+
}
|
|
2248
|
+
if (ch === "$" && source[j + 1] === "{") {
|
|
2249
|
+
blank(from, j + 2);
|
|
2250
|
+
templateStack.push(braceDepth);
|
|
2251
|
+
braceDepth++;
|
|
2252
|
+
return j + 2;
|
|
2253
|
+
}
|
|
2254
|
+
j++;
|
|
2255
|
+
}
|
|
2256
|
+
blank(from, n);
|
|
2257
|
+
return n;
|
|
2258
|
+
}, "scanTemplateText");
|
|
2259
|
+
let i = 0;
|
|
2260
|
+
while (i < n) {
|
|
2261
|
+
const ch = source[i];
|
|
2262
|
+
const next = source[i + 1];
|
|
2263
|
+
if (ch === "/" && next === "/") {
|
|
2264
|
+
const newline = source.indexOf("\n", i);
|
|
2265
|
+
const end = newline === -1 ? n : newline;
|
|
2266
|
+
blank(i, end);
|
|
2267
|
+
i = end;
|
|
2268
|
+
continue;
|
|
2269
|
+
}
|
|
2270
|
+
if (ch === "/" && next === "*") {
|
|
2271
|
+
const close = source.indexOf("*/", i + 2);
|
|
2272
|
+
const end = close === -1 ? n : close + 2;
|
|
2273
|
+
blank(i, end);
|
|
2274
|
+
i = end;
|
|
2275
|
+
continue;
|
|
2276
|
+
}
|
|
2277
|
+
if (ch === '"' || ch === "'") {
|
|
2278
|
+
let j = i + 1;
|
|
2279
|
+
while (j < n && source[j] !== ch && source[j] !== "\n") {
|
|
2280
|
+
j += source[j] === "\\" ? 2 : 1;
|
|
2281
|
+
}
|
|
2282
|
+
const end = Math.min(n, j + 1);
|
|
2283
|
+
blank(i, end);
|
|
2284
|
+
i = end;
|
|
2285
|
+
continue;
|
|
2286
|
+
}
|
|
2287
|
+
if (ch === "`") {
|
|
2288
|
+
blank(i, i + 1);
|
|
2289
|
+
i = scanTemplateText(i + 1);
|
|
2290
|
+
continue;
|
|
2291
|
+
}
|
|
2292
|
+
if (ch === "{") {
|
|
2293
|
+
braceDepth++;
|
|
2294
|
+
} else if (ch === "}") {
|
|
2295
|
+
if (templateStack.length > 0 && templateStack[templateStack.length - 1] === braceDepth - 1) {
|
|
2296
|
+
templateStack.pop();
|
|
2297
|
+
braceDepth--;
|
|
2298
|
+
blank(i, i + 1);
|
|
2299
|
+
i = scanTemplateText(i + 1);
|
|
2300
|
+
continue;
|
|
2301
|
+
}
|
|
2302
|
+
braceDepth = Math.max(0, braceDepth - 1);
|
|
2303
|
+
}
|
|
2304
|
+
i++;
|
|
2305
|
+
}
|
|
2306
|
+
return out.join("");
|
|
2307
|
+
}
|
|
2308
|
+
__name(maskNonCode, "maskNonCode");
|
|
2309
|
+
function collapse(text, max) {
|
|
2310
|
+
const flat = text.replace(/\s+/g, " ").trim();
|
|
2311
|
+
return flat.length > max ? `${flat.slice(0, max - 1)}\u2026` : flat;
|
|
2312
|
+
}
|
|
2313
|
+
__name(collapse, "collapse");
|
|
2314
|
+
function readPromptSummary(source, from) {
|
|
2315
|
+
let p = from;
|
|
2316
|
+
while (p < source.length && SPACE.test(source[p])) p++;
|
|
2317
|
+
const quote = source[p];
|
|
2318
|
+
if (quote !== '"' && quote !== "'" && quote !== "`") return void 0;
|
|
2319
|
+
let text = "";
|
|
2320
|
+
let j = p + 1;
|
|
2321
|
+
while (j < source.length && text.length < PROMPT_READ_LIMIT) {
|
|
2322
|
+
const ch = source[j];
|
|
2323
|
+
if (ch === "\\") {
|
|
2324
|
+
const escaped = source[j + 1] ?? "";
|
|
2325
|
+
text += escaped === "n" || escaped === "t" || escaped === "r" ? " " : escaped;
|
|
2326
|
+
j += 2;
|
|
2327
|
+
continue;
|
|
2328
|
+
}
|
|
2329
|
+
if (ch === quote) break;
|
|
2330
|
+
if (quote !== "`" && ch === "\n") break;
|
|
2331
|
+
if (quote === "`" && ch === "$" && source[j + 1] === "{") {
|
|
2332
|
+
let depth = 1;
|
|
2333
|
+
j += 2;
|
|
2334
|
+
while (j < source.length && depth > 0) {
|
|
2335
|
+
if (source[j] === "{") depth++;
|
|
2336
|
+
else if (source[j] === "}") depth--;
|
|
2337
|
+
j++;
|
|
2338
|
+
}
|
|
2339
|
+
text += "\u2026";
|
|
2340
|
+
continue;
|
|
2341
|
+
}
|
|
2342
|
+
text += ch;
|
|
2343
|
+
j++;
|
|
2344
|
+
}
|
|
2345
|
+
const summary = collapse(text, PROMPT_SUMMARY_CHARS);
|
|
2346
|
+
return summary.length > 0 ? summary : void 0;
|
|
2347
|
+
}
|
|
2348
|
+
__name(readPromptSummary, "readPromptSummary");
|
|
2349
|
+
function scanWorkflowScriptShape(source) {
|
|
2350
|
+
const code = maskNonCode(source);
|
|
2351
|
+
const n = code.length;
|
|
2352
|
+
const rows = [];
|
|
2353
|
+
const rowByContext = /* @__PURE__ */ new Map();
|
|
2354
|
+
const violations = [];
|
|
2355
|
+
const stack = [];
|
|
2356
|
+
const doBodyCloses = /* @__PURE__ */ new Set();
|
|
2357
|
+
let lastRow;
|
|
2358
|
+
let lastRowWasTopLevel = false;
|
|
2359
|
+
let agentCalls = 0;
|
|
2360
|
+
let depth = 0;
|
|
2361
|
+
let line = 1;
|
|
2362
|
+
let nextId = 0;
|
|
2363
|
+
const skipSpace = /* @__PURE__ */ __name((from) => {
|
|
2364
|
+
let k = from;
|
|
2365
|
+
while (k < n && SPACE.test(code[k])) k++;
|
|
2366
|
+
return k;
|
|
2367
|
+
}, "skipSpace");
|
|
2368
|
+
const readIdent = /* @__PURE__ */ __name((from) => {
|
|
2369
|
+
let k = from;
|
|
2370
|
+
while (k < n && IDENT_PART.test(code[k])) k++;
|
|
2371
|
+
return code.slice(from, k);
|
|
2372
|
+
}, "readIdent");
|
|
2373
|
+
const previousNonSpaceIndex = /* @__PURE__ */ __name((from) => {
|
|
2374
|
+
let k = from - 1;
|
|
2375
|
+
while (k >= 0 && SPACE.test(code[k])) k--;
|
|
2376
|
+
return k;
|
|
2377
|
+
}, "previousNonSpaceIndex");
|
|
2378
|
+
const followsNew = /* @__PURE__ */ __name((start) => {
|
|
2379
|
+
const k = previousNonSpaceIndex(start);
|
|
2380
|
+
return k >= 2 && code.slice(k - 2, k + 1) === "new" && !IDENT_PART.test(code[k - 3] ?? "");
|
|
2381
|
+
}, "followsNew");
|
|
2382
|
+
const matchingClose = /* @__PURE__ */ __name((open) => {
|
|
2383
|
+
let d = 0;
|
|
2384
|
+
for (let k = open; k < n; k++) {
|
|
2385
|
+
const c = code[k];
|
|
2386
|
+
if (c === "(" || c === "[" || c === "{") d++;
|
|
2387
|
+
else if (c === ")" || c === "]" || c === "}") {
|
|
2388
|
+
d--;
|
|
2389
|
+
if (d === 0) return k;
|
|
2390
|
+
}
|
|
2391
|
+
}
|
|
2392
|
+
return -1;
|
|
2393
|
+
}, "matchingClose");
|
|
2394
|
+
const innermost = /* @__PURE__ */ __name((at) => {
|
|
2395
|
+
for (let s = stack.length - 1; s >= 0; s--) {
|
|
2396
|
+
if (at >= stack[s].bodyStart) return stack[s];
|
|
2397
|
+
}
|
|
2398
|
+
return void 0;
|
|
2399
|
+
}, "innermost");
|
|
2400
|
+
const popClosedBlocks = /* @__PURE__ */ __name((closeIndex) => {
|
|
2401
|
+
while (stack.length > 0) {
|
|
2402
|
+
const top = stack[stack.length - 1];
|
|
2403
|
+
const closes = top.statement ? depth < top.openDepth : closeIndex > top.bodyStart && depth <= top.openDepth;
|
|
2404
|
+
if (!closes) break;
|
|
2405
|
+
stack.pop();
|
|
2406
|
+
if (top.isDo) doBodyCloses.add(closeIndex);
|
|
2407
|
+
if (top.kind === "parallel") recordEmptyFanOut(top);
|
|
2408
|
+
}
|
|
2409
|
+
}, "popClosedBlocks");
|
|
2410
|
+
const recordEmptyFanOut = /* @__PURE__ */ __name((closed) => {
|
|
2411
|
+
if (rows.length !== closed.rowsAtOpen) return;
|
|
2412
|
+
if (stack.some((context) => context.kind === "parallel")) return;
|
|
2413
|
+
const row = {
|
|
2414
|
+
kind: "parallel",
|
|
2415
|
+
count: 0,
|
|
2416
|
+
prompts: [],
|
|
2417
|
+
line: closed.line
|
|
2418
|
+
};
|
|
2419
|
+
rows.push(row);
|
|
2420
|
+
lastRow = row;
|
|
2421
|
+
lastRowWasTopLevel = false;
|
|
2422
|
+
}, "recordEmptyFanOut");
|
|
2423
|
+
const popEndedStatements = /* @__PURE__ */ __name(() => {
|
|
2424
|
+
while (stack.length > 0) {
|
|
2425
|
+
const top = stack[stack.length - 1];
|
|
2426
|
+
if (!top.statement || !top.consumed || depth !== top.openDepth) break;
|
|
2427
|
+
stack.pop();
|
|
2428
|
+
}
|
|
2429
|
+
}, "popEndedStatements");
|
|
2430
|
+
const recordAgent = /* @__PURE__ */ __name((start, open) => {
|
|
2431
|
+
agentCalls++;
|
|
2432
|
+
const context = innermost(start);
|
|
2433
|
+
const prompt = readPromptSummary(source, open + 1);
|
|
2434
|
+
let row;
|
|
2435
|
+
if (context) {
|
|
2436
|
+
row = rowByContext.get(context.id);
|
|
2437
|
+
if (!row) {
|
|
2438
|
+
row = {
|
|
2439
|
+
kind: context.kind,
|
|
2440
|
+
count: 0,
|
|
2441
|
+
...context.condition ? { condition: context.condition } : {},
|
|
2442
|
+
prompts: [],
|
|
2443
|
+
line
|
|
2444
|
+
};
|
|
2445
|
+
rowByContext.set(context.id, row);
|
|
2446
|
+
rows.push(row);
|
|
2447
|
+
}
|
|
2448
|
+
} else if (lastRow?.kind === "step" && lastRowWasTopLevel) {
|
|
2449
|
+
row = lastRow;
|
|
2450
|
+
} else {
|
|
2451
|
+
row = { kind: "step", count: 0, prompts: [], line };
|
|
2452
|
+
rows.push(row);
|
|
2453
|
+
}
|
|
2454
|
+
row.count++;
|
|
2455
|
+
if (prompt !== void 0 && row.prompts.length < MAX_PROMPTS_PER_ROW) {
|
|
2456
|
+
row.prompts.push(prompt);
|
|
2457
|
+
}
|
|
2458
|
+
lastRow = row;
|
|
2459
|
+
lastRowWasTopLevel = context === void 0;
|
|
2460
|
+
}, "recordAgent");
|
|
2461
|
+
const recordMemberCall = /* @__PURE__ */ __name((object, end, names) => {
|
|
2462
|
+
const dot = skipSpace(end);
|
|
2463
|
+
if (code[dot] !== ".") return;
|
|
2464
|
+
const nameStart = skipSpace(dot + 1);
|
|
2465
|
+
const name = readIdent(nameStart);
|
|
2466
|
+
if (!names.includes(name)) return;
|
|
2467
|
+
if (code[skipSpace(nameStart + name.length)] !== "(") return;
|
|
2468
|
+
violations.push({
|
|
2469
|
+
call: `${object}.${name}()`,
|
|
2470
|
+
line
|
|
2471
|
+
});
|
|
2472
|
+
}, "recordMemberCall");
|
|
2473
|
+
const handleWord = /* @__PURE__ */ __name((word, start, end) => {
|
|
2474
|
+
switch (word) {
|
|
2475
|
+
case "agent": {
|
|
2476
|
+
const open = skipSpace(end);
|
|
2477
|
+
if (code[open] === "(") recordAgent(start, open);
|
|
2478
|
+
return;
|
|
2479
|
+
}
|
|
2480
|
+
case "parallel":
|
|
2481
|
+
case "pipeline": {
|
|
2482
|
+
const open = skipSpace(end);
|
|
2483
|
+
if (code[open] !== "(") return;
|
|
2484
|
+
stack.push({
|
|
2485
|
+
kind: "parallel",
|
|
2486
|
+
id: nextId++,
|
|
2487
|
+
line,
|
|
2488
|
+
rowsAtOpen: rows.length,
|
|
2489
|
+
openDepth: depth,
|
|
2490
|
+
bodyStart: open,
|
|
2491
|
+
statement: false,
|
|
2492
|
+
consumed: false,
|
|
2493
|
+
isDo: false
|
|
2494
|
+
});
|
|
2495
|
+
return;
|
|
2496
|
+
}
|
|
2497
|
+
case "while":
|
|
2498
|
+
case "for": {
|
|
2499
|
+
if (word === "while" && doBodyCloses.has(previousNonSpaceIndex(start))) {
|
|
2500
|
+
return;
|
|
2501
|
+
}
|
|
2502
|
+
let open = skipSpace(end);
|
|
2503
|
+
if (word === "for" && code.startsWith("await", open) && !IDENT_PART.test(code[open + 5] ?? "")) {
|
|
2504
|
+
open = skipSpace(open + 5);
|
|
2505
|
+
}
|
|
2506
|
+
if (code[open] !== "(") return;
|
|
2507
|
+
const close = matchingClose(open);
|
|
2508
|
+
if (close === -1) return;
|
|
2509
|
+
const body = skipSpace(close + 1);
|
|
2510
|
+
if (body >= n || code[body] === ";") return;
|
|
2511
|
+
stack.push({
|
|
2512
|
+
kind: "loop",
|
|
2513
|
+
id: nextId++,
|
|
2514
|
+
line,
|
|
2515
|
+
rowsAtOpen: rows.length,
|
|
2516
|
+
openDepth: depth,
|
|
2517
|
+
bodyStart: body,
|
|
2518
|
+
statement: code[body] !== "{",
|
|
2519
|
+
condition: `${word} (${collapse(source.slice(open + 1, close), LOOP_HEAD_CHARS)})`,
|
|
2520
|
+
consumed: false,
|
|
2521
|
+
isDo: false
|
|
2522
|
+
});
|
|
2523
|
+
return;
|
|
2524
|
+
}
|
|
2525
|
+
case "do": {
|
|
2526
|
+
const body = skipSpace(end);
|
|
2527
|
+
if (code[body] !== "{") return;
|
|
2528
|
+
stack.push({
|
|
2529
|
+
kind: "loop",
|
|
2530
|
+
id: nextId++,
|
|
2531
|
+
line,
|
|
2532
|
+
rowsAtOpen: rows.length,
|
|
2533
|
+
openDepth: depth,
|
|
2534
|
+
bodyStart: body,
|
|
2535
|
+
statement: false,
|
|
2536
|
+
condition: "do \u2026 while",
|
|
2537
|
+
consumed: false,
|
|
2538
|
+
isDo: true
|
|
2539
|
+
});
|
|
2540
|
+
return;
|
|
2541
|
+
}
|
|
2542
|
+
case "Math":
|
|
2543
|
+
recordMemberCall("Math", end, ["random"]);
|
|
2544
|
+
return;
|
|
2545
|
+
case "Date": {
|
|
2546
|
+
if (code[skipSpace(end)] === "(") {
|
|
2547
|
+
if (!followsNew(start)) violations.push({ call: "Date()", line });
|
|
2548
|
+
return;
|
|
2549
|
+
}
|
|
2550
|
+
recordMemberCall("Date", end, ["now", "parse", "UTC"]);
|
|
2551
|
+
return;
|
|
2552
|
+
}
|
|
2553
|
+
case "new": {
|
|
2554
|
+
const target = skipSpace(end);
|
|
2555
|
+
if (readIdent(target) === "Date" && code[skipSpace(target + 4)] !== ".") {
|
|
2556
|
+
violations.push({ call: "new Date()", line });
|
|
2557
|
+
}
|
|
2558
|
+
return;
|
|
2559
|
+
}
|
|
2560
|
+
default:
|
|
2561
|
+
return;
|
|
2562
|
+
}
|
|
2563
|
+
}, "handleWord");
|
|
2564
|
+
for (let i = 0; i < n; i++) {
|
|
2565
|
+
const ch = code[i];
|
|
2566
|
+
if (ch === "\n") {
|
|
2567
|
+
line++;
|
|
2568
|
+
popEndedStatements();
|
|
2569
|
+
continue;
|
|
2570
|
+
}
|
|
2571
|
+
if (SPACE.test(ch)) continue;
|
|
2572
|
+
const top = stack[stack.length - 1];
|
|
2573
|
+
if (top?.statement && i >= top.bodyStart) top.consumed = true;
|
|
2574
|
+
if (ch === "(" || ch === "[" || ch === "{") {
|
|
2575
|
+
depth++;
|
|
2576
|
+
continue;
|
|
2577
|
+
}
|
|
2578
|
+
if (ch === ")" || ch === "]" || ch === "}") {
|
|
2579
|
+
depth = Math.max(0, depth - 1);
|
|
2580
|
+
popClosedBlocks(i);
|
|
2581
|
+
continue;
|
|
2582
|
+
}
|
|
2583
|
+
if (ch === ";") {
|
|
2584
|
+
popEndedStatements();
|
|
2585
|
+
continue;
|
|
2586
|
+
}
|
|
2587
|
+
if (!IDENT_START.test(ch) || i > 0 && IDENT_PART.test(code[i - 1])) {
|
|
2588
|
+
continue;
|
|
2589
|
+
}
|
|
2590
|
+
const word = readIdent(i);
|
|
2591
|
+
const end = i + word.length;
|
|
2592
|
+
const prev = previousNonSpaceIndex(i);
|
|
2593
|
+
if (prev < 0 || code[prev] !== ".") handleWord(word, i, end);
|
|
2594
|
+
i = end - 1;
|
|
2595
|
+
}
|
|
2596
|
+
return { rows, agentCalls, determinismViolations: violations };
|
|
2597
|
+
}
|
|
2598
|
+
__name(scanWorkflowScriptShape, "scanWorkflowScriptShape");
|
|
2599
|
+
function describeWorkflowDeterminismViolations(violations) {
|
|
2600
|
+
const listed = violations.slice(0, MAX_VIOLATIONS_LISTED).map((v) => `${v.call} on line ${v.line}`);
|
|
2601
|
+
const more = violations.length - listed.length;
|
|
2602
|
+
const where = more > 0 ? `${listed.join(", ")} and ${more} more` : listed.join(", ");
|
|
2603
|
+
return `Workflow scripts must be deterministic so a resume replays the same calls, and this script calls ${where}. None of these is available in a workflow script: pass timestamps or seeds in through \`args\`, or stamp the result after the workflow returns.`;
|
|
2604
|
+
}
|
|
2605
|
+
__name(describeWorkflowDeterminismViolations, "describeWorkflowDeterminismViolations");
|
|
2606
|
+
|
|
2607
|
+
// packages/core/src/skills/workflow-authoring-skill.ts
|
|
2608
|
+
init_esbuild_shims();
|
|
2609
|
+
import { readFileSync } from "node:fs";
|
|
2610
|
+
import * as path3 from "node:path";
|
|
2611
|
+
var debugLogger6 = createDebugLogger("WORKFLOW_AUTHORING_SKILL");
|
|
2612
|
+
var WORKFLOW_AUTHORING_SKILL_NAME = "workflow-authoring";
|
|
2613
|
+
var cachedReference;
|
|
2614
|
+
function referencePath() {
|
|
2615
|
+
return path3.join(
|
|
2616
|
+
resolveBundleDir(import.meta.url),
|
|
2617
|
+
"bundled",
|
|
2618
|
+
WORKFLOW_AUTHORING_SKILL_NAME,
|
|
2619
|
+
"SKILL.md"
|
|
2620
|
+
);
|
|
2621
|
+
}
|
|
2622
|
+
__name(referencePath, "referencePath");
|
|
2623
|
+
function readWorkflowAuthoringReference() {
|
|
2624
|
+
if (cachedReference !== void 0) return cachedReference;
|
|
2625
|
+
try {
|
|
2626
|
+
const filePath = referencePath();
|
|
2627
|
+
const parsed = parseSkillContent(readFileSync(filePath, "utf8"), filePath);
|
|
2628
|
+
cachedReference = { body: parsed.body, baseDir: path3.dirname(filePath) };
|
|
2629
|
+
} catch (error) {
|
|
2630
|
+
debugLogger6.warn(`cannot read the workflow-authoring reference: ${error}`);
|
|
2631
|
+
cachedReference = null;
|
|
2632
|
+
}
|
|
2633
|
+
return cachedReference;
|
|
2634
|
+
}
|
|
2635
|
+
__name(readWorkflowAuthoringReference, "readWorkflowAuthoringReference");
|
|
2636
|
+
function resolveWorkflowAuthoringRoute(config) {
|
|
2637
|
+
try {
|
|
2638
|
+
if (config.getDisabledSkillLevels?.()?.has("bundled")) return "withheld";
|
|
2639
|
+
if (config.isSkillEnabled?.({
|
|
2640
|
+
name: WORKFLOW_AUTHORING_SKILL_NAME,
|
|
2641
|
+
level: "bundled"
|
|
2642
|
+
}) === false) {
|
|
2643
|
+
return "withheld";
|
|
2644
|
+
}
|
|
2645
|
+
if (!config.getSkillManager?.()) return "inline";
|
|
2646
|
+
const registry = config.getToolRegistry?.();
|
|
2647
|
+
const toolNames = registry?.getAllToolNames?.();
|
|
2648
|
+
if (!Array.isArray(toolNames)) return "skill";
|
|
2649
|
+
if (!toolNames.includes(ToolNames.SKILL)) return "inline";
|
|
2650
|
+
if (isToolDeferredBehindToolSearch(config, ToolNames.SKILL)) {
|
|
2651
|
+
return toolNames.includes(ToolNames.TOOL_SEARCH) ? "skill-via-tool-search" : "inline";
|
|
2652
|
+
}
|
|
2653
|
+
return "skill";
|
|
2654
|
+
} catch (error) {
|
|
2655
|
+
debugLogger6.warn(`cannot resolve the workflow-authoring route: ${error}`);
|
|
2656
|
+
return "skill";
|
|
2657
|
+
}
|
|
2658
|
+
}
|
|
2659
|
+
__name(resolveWorkflowAuthoringRoute, "resolveWorkflowAuthoringRoute");
|
|
2660
|
+
function resolveWorkflowAuthoringSurface(config) {
|
|
2661
|
+
const route = resolveWorkflowAuthoringRoute(config);
|
|
2662
|
+
switch (route) {
|
|
2663
|
+
case "skill":
|
|
2664
|
+
return "pointer";
|
|
2665
|
+
case "skill-via-tool-search":
|
|
2666
|
+
return "pointer-via-tool-search";
|
|
2667
|
+
case "withheld":
|
|
2668
|
+
return "withheld";
|
|
2669
|
+
case "inline":
|
|
2670
|
+
return readWorkflowAuthoringReference() ? "inline" : "pointer";
|
|
2671
|
+
default: {
|
|
2672
|
+
const unhandled = route;
|
|
2673
|
+
return unhandled;
|
|
2674
|
+
}
|
|
2675
|
+
}
|
|
2676
|
+
}
|
|
2677
|
+
__name(resolveWorkflowAuthoringSurface, "resolveWorkflowAuthoringSurface");
|
|
2678
|
+
function isToolDeferredBehindToolSearch(config, name) {
|
|
2679
|
+
if (!config.getToolRegistry?.()?.isPermissionDeferred?.(name)) return false;
|
|
2680
|
+
return !config.getVisibleTools?.()?.has(name);
|
|
2681
|
+
}
|
|
2682
|
+
__name(isToolDeferredBehindToolSearch, "isToolDeferredBehindToolSearch");
|
|
2683
|
+
function isToolHiddenBehindToolSearch(config, name) {
|
|
2684
|
+
if (!isToolDeferredBehindToolSearch(config, name)) return false;
|
|
2685
|
+
return !config.getToolRegistry?.()?.isDeferredToolRevealed?.(name);
|
|
2686
|
+
}
|
|
2687
|
+
__name(isToolHiddenBehindToolSearch, "isToolHiddenBehindToolSearch");
|
|
2688
|
+
function toolSearchRevealSentence(toolDisplayName) {
|
|
2689
|
+
return `If the ${toolDisplayName} tool is not in your tool list, reveal it with ToolSearch first.`;
|
|
2690
|
+
}
|
|
2691
|
+
__name(toolSearchRevealSentence, "toolSearchRevealSentence");
|
|
2692
|
+
|
|
2693
|
+
// packages/core/src/agents/runtime/review-workflow.ts
|
|
2694
|
+
init_esbuild_shims();
|
|
2695
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
2696
|
+
import { promises as fs3 } from "node:fs";
|
|
2697
|
+
import path4 from "node:path";
|
|
2698
|
+
var debugLogger7 = createDebugLogger("REVIEW_WORKFLOW");
|
|
2699
|
+
function resolveReviewWorkflowConcurrency(env = process.env) {
|
|
2700
|
+
const configured = parsePositiveIntegerEnv(env[MAX_WORKFLOW_CONCURRENCY_ENV], 0) || parsePositiveIntegerEnv(env["QWEN_CODE_MAX_TOOL_CONCURRENCY"], 10);
|
|
2701
|
+
return resolveConcurrencyLimit({
|
|
2702
|
+
[MAX_WORKFLOW_CONCURRENCY_ENV]: String(configured)
|
|
2703
|
+
});
|
|
2704
|
+
}
|
|
2705
|
+
__name(resolveReviewWorkflowConcurrency, "resolveReviewWorkflowConcurrency");
|
|
2706
|
+
async function resolveReviewWorkflowLimits(scriptPath, generatedDir, scriptContent, env = process.env, nowMs = Date.now()) {
|
|
2707
|
+
let canonicalScript;
|
|
2708
|
+
try {
|
|
2709
|
+
if ((await fs3.lstat(generatedDir)).isSymbolicLink()) return void 0;
|
|
2710
|
+
const generatedRoot = await fs3.realpath(generatedDir);
|
|
2711
|
+
canonicalScript = await fs3.realpath(scriptPath);
|
|
2712
|
+
if (!canonicalScript.startsWith(path4.join(generatedRoot, "review") + path4.sep)) {
|
|
2713
|
+
return void 0;
|
|
2714
|
+
}
|
|
2715
|
+
} catch (error) {
|
|
2716
|
+
if (error.code !== "ENOENT") {
|
|
2717
|
+
debugLogger7.warn(
|
|
2718
|
+
"Cannot classify review workflow; using generic limits:",
|
|
2719
|
+
error
|
|
2720
|
+
);
|
|
2721
|
+
}
|
|
2722
|
+
return void 0;
|
|
2723
|
+
}
|
|
2724
|
+
const digest = /^qwen-review-[a-f0-9]{10}-([a-f0-9]{64})\.js$/.exec(
|
|
2725
|
+
path4.basename(canonicalScript)
|
|
2726
|
+
)?.[1];
|
|
2727
|
+
if (!digest || createHash2("sha256").update(scriptContent).digest("hex") !== digest) {
|
|
2728
|
+
return void 0;
|
|
2729
|
+
}
|
|
2730
|
+
const seconds = Number(env["QWEN_CODE_MAX_WORKFLOW_SECONDS"]);
|
|
2731
|
+
let maxWallClockMs = (Number.isFinite(seconds) && seconds > 0 ? seconds : 6 * 60 * 60) * 1e3;
|
|
2732
|
+
const deadline = Number(env["QWEN_REVIEW_DEADLINE_EPOCH"]);
|
|
2733
|
+
if (Number.isFinite(deadline) && deadline > 0) {
|
|
2734
|
+
const rawFloor = env["QWEN_REVIEW_DEADLINE_COMPOSE_FLOOR_SECONDS"];
|
|
2735
|
+
const floor = Number(rawFloor);
|
|
2736
|
+
const floorSeconds = rawFloor?.trim() && Number.isFinite(floor) && floor >= 0 ? floor : 1200;
|
|
2737
|
+
const remainingMs = deadline * 1e3 - nowMs - floorSeconds * 1e3;
|
|
2738
|
+
if (remainingMs <= 0) {
|
|
2739
|
+
throw new Error(
|
|
2740
|
+
"Review workflow was not launched: the review deadline has reached the compose reserve floor. Recover completed findings and compose now."
|
|
2741
|
+
);
|
|
2742
|
+
}
|
|
2743
|
+
maxWallClockMs = Math.min(maxWallClockMs, remainingMs);
|
|
2744
|
+
}
|
|
2745
|
+
return {
|
|
2746
|
+
subagent: {
|
|
2747
|
+
max_turns: resolveSubagentMaxTurns(env, 500),
|
|
2748
|
+
max_time_minutes: resolveSubagentMaxTimeMinutes(env, 100)
|
|
2749
|
+
},
|
|
2750
|
+
concurrency: resolveReviewWorkflowConcurrency(env),
|
|
2751
|
+
maxWallClockMs
|
|
2752
|
+
};
|
|
2753
|
+
}
|
|
2754
|
+
__name(resolveReviewWorkflowLimits, "resolveReviewWorkflowLimits");
|
|
2755
|
+
|
|
2756
|
+
export {
|
|
2757
|
+
MAX_TOKENS_PER_WORKFLOW_ENV,
|
|
2758
|
+
WorkflowBudgetImpl,
|
|
2759
|
+
WorkflowJournal,
|
|
2760
|
+
WorkflowDispatchScheduler,
|
|
2761
|
+
DEFAULT_MAX_AGENTS_PER_RUN,
|
|
2762
|
+
MAX_WORKFLOW_AGENTS_ENV,
|
|
2763
|
+
MAX_WORKFLOW_CONCURRENCY_ENV,
|
|
2764
|
+
resolveConcurrencyLimit,
|
|
2765
|
+
DEFAULT_WORKFLOW_SUBAGENT_MAX_TURNS,
|
|
2766
|
+
DEFAULT_WORKFLOW_SUBAGENT_MAX_TIME_MINUTES,
|
|
2767
|
+
WORKFLOW_SUBAGENT_MAX_TURNS_ENV,
|
|
2768
|
+
WORKFLOW_SUBAGENT_MAX_MINUTES_ENV,
|
|
2769
|
+
WorkflowExecutionError,
|
|
2770
|
+
createProductionDispatch,
|
|
2771
|
+
WorkflowOrchestrator,
|
|
2772
|
+
MAX_RETAINED_SNAPSHOTS,
|
|
2773
|
+
toSnapshot,
|
|
2774
|
+
writeWorkflowSnapshot,
|
|
2775
|
+
listWorkflowSnapshots,
|
|
2776
|
+
deleteWorkflowSnapshot,
|
|
2777
|
+
scanWorkflowScriptShape,
|
|
2778
|
+
describeWorkflowDeterminismViolations,
|
|
2779
|
+
resolveReviewWorkflowConcurrency,
|
|
2780
|
+
resolveReviewWorkflowLimits,
|
|
2781
|
+
WORKFLOW_AUTHORING_SKILL_NAME,
|
|
2782
|
+
readWorkflowAuthoringReference,
|
|
2783
|
+
resolveWorkflowAuthoringSurface,
|
|
2784
|
+
isToolHiddenBehindToolSearch,
|
|
2785
|
+
toolSearchRevealSentence
|
|
2786
|
+
};
|
|
2787
|
+
/**
|
|
2788
|
+
* @license
|
|
2789
|
+
* Copyright 2026 Qwen Team
|
|
2790
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
2791
|
+
*/
|
|
2792
|
+
/**
|
|
2793
|
+
* @license
|
|
2794
|
+
* Copyright 2025 Qwen
|
|
2795
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
2796
|
+
*/
|