@qwen-code/qwen-code 0.21.7 → 0.21.8-nightly.20260810.55e20db328
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/README.md +2 -0
- package/bundled/qc-helper/docs/configuration/settings.md +73 -59
- package/bundled/qc-helper/docs/extension/introduction.md +15 -1
- package/bundled/qc-helper/docs/features/channels/dingtalk.md +40 -2
- package/bundled/qc-helper/docs/features/channels/feishu.md +13 -2
- package/bundled/qc-helper/docs/features/channels/github.md +13 -11
- package/bundled/qc-helper/docs/features/channels/gitlab.md +13 -11
- package/bundled/qc-helper/docs/features/channels/overview.md +49 -31
- package/bundled/qc-helper/docs/features/channels/plugins.md +2 -2
- package/bundled/qc-helper/docs/features/channels/qqbot.md +4 -2
- package/bundled/qc-helper/docs/features/channels/telegram.md +4 -2
- package/bundled/qc-helper/docs/features/channels/wecom.md +1 -1
- package/bundled/qc-helper/docs/features/code-review.md +4 -0
- package/bundled/qc-helper/docs/features/commands.md +1 -1
- package/bundled/qc-helper/docs/features/hooks.md +52 -0
- package/bundled/qc-helper/docs/integration-jetbrains.md +1 -0
- package/bundled/qc-helper/docs/qwen-serve-deploy-local.md +1 -1
- package/bundled/qc-helper/docs/qwen-serve.md +10 -5
- package/bundled/qc-helper/docs/reference/keyboard-shortcuts.md +50 -36
- package/bundled/review/SKILL.md +32 -5
- package/chunks/{MaxSizedBox-ANWZBPTS.js → MaxSizedBox-A52T4GEU.js} +29 -25
- package/chunks/{StandaloneSessionPicker-XKS3VU3A.js → StandaloneSessionPicker-4J654SOB.js} +48 -44
- package/chunks/{acp-startup-profiler-ORIQ2CCQ.js → acp-startup-profiler-B5BYAMYQ.js} +2 -2
- package/chunks/{acpAgent-KUAZ3GCZ.js → acpAgent-65AM4AOR.js} +1833 -843
- package/chunks/{agent-T6PTGX5R.js → agent-SVQ7U7NJ.js} +28 -24
- package/chunks/{agent-headless-PR7YCB7S.js → agent-headless-XXGY2SQO.js} +28 -24
- package/chunks/{artifact-tool-U4VOZIK5.js → artifact-tool-N652YE4L.js} +1 -1
- package/chunks/{askUserQuestion-XOBQLPFA.js → askUserQuestion-ONW74PKJ.js} +1 -1
- package/chunks/{bridge-NU6YEEHK.js → bridge-Y32B5S3G.js} +34 -30
- package/chunks/{ca-NYKNH222.js → ca-ZLKAB4K3.js} +6 -0
- package/chunks/{channel-management-service-FSQ7SHYI.js → channel-management-service-PHELKOW2.js} +19 -10
- package/chunks/{channel-settings-store-35VQVUVV.js → channel-settings-store-OW43U6VB.js} +36 -32
- package/chunks/{channel-worker-group-JWQK224X.js → channel-worker-group-MSHT6CWR.js} +7 -7
- package/chunks/{channel-worker-manager-77E3OXRQ.js → channel-worker-manager-XXD3GDSK.js} +7 -7
- package/chunks/{channel-worker-supervisor-62YWUGP2.js → channel-worker-supervisor-IVSDIMI4.js} +4 -4
- package/chunks/{chunk-HYRDKNUY.js → chunk-2545EHZR.js} +1 -1
- package/chunks/{chunk-SPMY6CX6.js → chunk-2ASQDZSJ.js} +3 -3
- package/chunks/{chunk-CJXIIILK.js → chunk-2FRY5CRX.js} +1 -1
- package/chunks/{chunk-CNIID3TV.js → chunk-2UUMVNYT.js} +1 -1
- package/chunks/{chunk-KXSDEOFU.js → chunk-3KJQZEN3.js} +1 -1
- package/chunks/{chunk-22NBYCPD.js → chunk-3P2LV43B.js} +1 -1
- package/chunks/{chunk-Y7E5LNLO.js → chunk-47ZUMGGY.js} +2634 -2114
- package/chunks/{chunk-LA7YLSR6.js → chunk-4EOURKA4.js} +839 -153
- package/chunks/chunk-4JRM2BSM.js +48 -0
- package/chunks/{chunk-BGG4MBYD.js → chunk-4PYCZH2V.js} +4 -187
- package/chunks/{chunk-L4N6TIP7.js → chunk-4TRQPFDP.js} +4 -2
- package/chunks/{chunk-6XJMFJ4D.js → chunk-5WZL724W.js} +177 -120
- package/chunks/{chunk-23RZCH76.js → chunk-5ZTS3OQ3.js} +3 -3
- package/chunks/{chunk-VWOVHOTT.js → chunk-67EWJE77.js} +1 -1
- package/chunks/{chunk-3K7FH2KQ.js → chunk-67N6HB5H.js} +1310 -171
- package/chunks/{chunk-CXE7E23H.js → chunk-6Q5ABMTU.js} +45 -17
- package/chunks/{chunk-NG2R4N5O.js → chunk-6ZRFAKXK.js} +1 -1
- package/chunks/{chunk-RERATVSK.js → chunk-7XX5IBXL.js} +145 -10
- package/chunks/{chunk-S7CV4KO6.js → chunk-AKJQSWV4.js} +4 -4
- package/chunks/{chunk-5KH532V7.js → chunk-AUWN7BAG.js} +1 -1
- package/chunks/{chunk-DBOFL3LQ.js → chunk-BL65MO72.js} +10 -10
- package/chunks/{chunk-AKA24BGO.js → chunk-BT6GQIEJ.js} +1 -1
- package/chunks/{chunk-W7U4ESW2.js → chunk-CG3WBKJK.js} +1 -1
- package/chunks/{chunk-2M5N3DHY.js → chunk-CMOBWHWW.js} +1 -1
- package/chunks/chunk-COBO5EBO.js +135 -0
- package/chunks/chunk-CPG6P4GG.js +82 -0
- package/chunks/{chunk-3NB7TSE2.js → chunk-D2D7J3EW.js} +1 -1
- package/chunks/{chunk-NLREQJFK.js → chunk-DA4HRSBW.js} +15 -0
- package/chunks/{chunk-RNVQB725.js → chunk-DPMJLKUP.js} +2 -2
- package/chunks/{chunk-DIEFUBV6.js → chunk-DX3RGJMS.js} +218 -37
- package/chunks/{chunk-33ACCIIY.js → chunk-DZUO626D.js} +1 -1
- package/chunks/chunk-E2FPSSKP.js +244 -0
- package/chunks/{chunk-72LNFGUY.js → chunk-E2N554HK.js} +3 -3
- package/chunks/{chunk-6EOI4HOK.js → chunk-E2T7FLDU.js} +12 -17
- package/chunks/{chunk-EUQTXRKZ.js → chunk-EISUQQPS.js} +6 -6
- package/chunks/{chunk-H2UQ2M5Z.js → chunk-EUVOKP6Y.js} +96 -22
- package/chunks/{chunk-RMH5OWLD.js → chunk-F3II4BTZ.js} +1 -1
- package/chunks/{chunk-P3LEG54R.js → chunk-F6TUUA2U.js} +3 -3
- package/chunks/chunk-F6WFNA7U.js +22 -0
- package/chunks/{chunk-RZHU3ILK.js → chunk-FAD7OC7V.js} +4 -4
- package/chunks/{chunk-OMKQH5C5.js → chunk-FWWQIFDT.js} +6 -23
- package/chunks/{chunk-TLV2IMHR.js → chunk-FYB4GIDW.js} +3 -3
- package/chunks/{chunk-ZJ3VGYHK.js → chunk-GY24H6IA.js} +40 -22
- package/chunks/{chunk-P2AJ7FTI.js → chunk-H4JC7LZX.js} +1 -1
- package/chunks/{chunk-55LYDVPU.js → chunk-HDYQYYWB.js} +1 -1
- package/chunks/{chunk-PQBHU2IA.js → chunk-HKI3KHAO.js} +11 -11
- package/chunks/{chunk-Y4NGLFGJ.js → chunk-HUWENAHO.js} +1 -1
- package/chunks/{chunk-3ULCB3NE.js → chunk-HV76SFIA.js} +1 -1
- package/chunks/{chunk-CSZEXZBE.js → chunk-HWXGX534.js} +3 -3
- package/chunks/{chunk-E33LOKRA.js → chunk-I5VM3SKY.js} +22 -5
- package/chunks/{chunk-LZC3B5N2.js → chunk-IA7TGCN2.js} +2 -2
- package/chunks/{chunk-RGSBTHSU.js → chunk-KMS57JDD.js} +137 -7
- package/chunks/{chunk-VOARQPTA.js → chunk-KP25NJNM.js} +65 -21
- package/chunks/{chunk-6M26GBKX.js → chunk-L2AFWWJE.js} +42 -3
- package/chunks/{chunk-ZXU5UHMI.js → chunk-LHEC5V6G.js} +2 -2
- package/chunks/{chunk-J26HHFI5.js → chunk-LP2QGNSP.js} +32 -2
- package/chunks/{chunk-R574ATRM.js → chunk-M2PNLYGY.js} +41 -0
- package/chunks/{chunk-MKVZE4ZJ.js → chunk-MFDYOYZZ.js} +3 -2
- package/chunks/{chunk-ALGGS7UH.js → chunk-NPQ5ZKRP.js} +82 -1
- package/chunks/{chunk-YHEEE624.js → chunk-NV3F44FL.js} +7 -3
- package/chunks/{chunk-6GONZVLS.js → chunk-NZMXUSKS.js} +1 -1
- package/chunks/{chunk-HQB2KUAN.js → chunk-O277O7U6.js} +1 -1
- package/chunks/{chunk-Y4EWSQF7.js → chunk-OBP6QWD5.js} +2 -2
- package/chunks/{chunk-CYR3HI5X.js → chunk-OQTXYMKW.js} +2 -2
- package/chunks/{chunk-TYKC75AX.js → chunk-OR6R3IUW.js} +2 -2
- package/chunks/{chunk-TRLYP7OF.js → chunk-OSVH4SMN.js} +16 -141
- package/chunks/{chunk-FPM27XN4.js → chunk-OW2BWT2P.js} +4 -4
- package/chunks/{chunk-TDXGKHDN.js → chunk-P5ULXPK5.js} +2 -2
- package/chunks/{chunk-24ER7UV4.js → chunk-PBRVUF5B.js} +1 -1
- package/chunks/{chunk-LKRMNRSN.js → chunk-PDPFQ2FO.js} +2 -0
- package/chunks/{chunk-2VSTGY6M.js → chunk-PJRW65JO.js} +1 -1
- package/chunks/{chunk-6HVUFDS2.js → chunk-PNVPFARW.js} +22 -13
- package/chunks/{chunk-IC4Z6LX6.js → chunk-PYQADEFD.js} +5 -0
- package/chunks/chunk-R4ZA6GBK.js +208 -0
- package/chunks/{chunk-KR4ZSC7K.js → chunk-RMPLEWF3.js} +3 -3
- package/chunks/{chunk-EORNAQDT.js → chunk-RQ6U2JJQ.js} +1 -1
- package/chunks/{chunk-AE77C5ZU.js → chunk-RYQMJCUO.js} +1 -1
- package/chunks/{chunk-6UWFTUQL.js → chunk-S5CULOHB.js} +75 -31
- package/chunks/{chunk-7UFKAV7Y.js → chunk-S6HYI3MF.js} +2 -2
- package/chunks/chunk-SAH4BD2J.js +92 -0
- package/chunks/chunk-SR7RZ4MS.js +202 -0
- package/chunks/{chunk-QETYKPMG.js → chunk-T2O6NIOY.js} +1 -1
- package/chunks/chunk-TQOF5KBL.js +71 -0
- package/chunks/{chunk-OHJLEW5J.js → chunk-TWFFY5BP.js} +4 -4
- package/chunks/{chunk-SCI7K3GM.js → chunk-TXO5BMR2.js} +19 -10
- package/chunks/{chunk-YJQCUTT2.js → chunk-UAB6J2IE.js} +4 -4
- package/chunks/{chunk-OFI7IGST.js → chunk-UGUKH3SU.js} +10 -10
- package/chunks/{chunk-SHZYHGQH.js → chunk-V2226RFW.js} +1 -1
- package/chunks/{chunk-KKJJB5X6.js → chunk-V47QNK5W.js} +1526 -833
- package/chunks/{chunk-W4B7UBUS.js → chunk-VHXPSL57.js} +6 -6
- package/chunks/{chunk-WUC6ZFXO.js → chunk-VKJ4KTPJ.js} +1 -1
- package/chunks/{chunk-MAJS7AT4.js → chunk-VNNWAZSI.js} +2 -2
- package/chunks/{chunk-BVWVWGLE.js → chunk-WAUGQKUU.js} +4 -64
- package/chunks/{chunk-OH2VKQXH.js → chunk-WH6QMLUW.js} +37 -30
- package/chunks/{chunk-PJOBIWUG.js → chunk-WQYWK4DG.js} +1 -1
- package/chunks/{chunk-LEMXGVEP.js → chunk-YFRFZCIP.js} +3 -3
- package/chunks/{chunk-2U3WZGZG.js → chunk-YGT2AUJ7.js} +103 -135
- package/chunks/{chunk-6XU3PH66.js → chunk-YR7ZQ4RD.js} +22 -69
- package/chunks/{chunk-OA4JVLSA.js → chunk-Z7VOMGDC.js} +22 -1
- package/chunks/{chunk-RUL4S3K3.js → chunk-ZCJBCKL5.js} +175 -60
- package/chunks/{chunk-GSS34377.js → chunk-ZI5IH2HP.js} +2 -2
- package/chunks/{chunk-CB2464BK.js → chunk-ZIKTCMQF.js} +117 -10
- package/chunks/chunk-ZLBIFIMV.js +1099 -0
- package/chunks/{chunk-D3UEZIQH.js → chunk-ZSNBQXMZ.js} +48 -55
- package/chunks/{chunk-FZBZSYKU.js → chunk-ZV7LTLFE.js} +1 -1
- package/chunks/{computer-use-KEAPATUY.js → computer-use-SLN7DV2E.js} +28 -24
- package/chunks/{config-utils-K7SCOWHD.js → config-utils-ULCSRMWD.js} +4 -4
- package/chunks/{contextCommand-ZJA6A5K5.js → contextCommand-EHFYX6FW.js} +30 -26
- package/chunks/{core-runtime-QMJPWHCI.js → core-runtime-FBSP5IIG.js} +33 -29
- package/chunks/{create-sub-session-E4PBYXV5.js → create-sub-session-QIDZUOPU.js} +1 -1
- package/chunks/{create-sub-session-DJE6XICH.js → create-sub-session-WC7YGVSL.js} +29 -25
- package/chunks/{cron-create-GRBWYMIJ.js → cron-create-VONA5JYY.js} +1 -1
- package/chunks/{cron-delete-4CMKBR2M.js → cron-delete-5JXSP2MI.js} +1 -1
- package/chunks/{cron-list-W7K4ASOA.js → cron-list-KE4F2CIR.js} +1 -1
- package/chunks/{daemon-SCTQMM7Z.js → daemon-VSX3FHTY.js} +119 -4
- package/chunks/{daemon-status-provider-FSWDPE2G.js → daemon-status-provider-WW2AD2T7.js} +39 -35
- package/chunks/{daemon-trust-policy-P5L5VFAY.js → daemon-trust-policy-E4MAYWPI.js} +35 -31
- package/chunks/{daemon-trust-policy-monitor-73JYN6ET.js → daemon-trust-policy-monitor-XVIDV6T4.js} +35 -31
- package/chunks/{de-VL76CPLV.js → de-LIW4XVLN.js} +5 -0
- package/chunks/{deferred-core-runtime-BWRCCFTE.js → deferred-core-runtime-5SVUC6UC.js} +28 -24
- package/chunks/{display-image-O2XFPQTC.js → display-image-NQRSIBXM.js} +2 -2
- package/chunks/{dist-HVBMEYWK.js → dist-3NTTUAHT.js} +1 -1
- package/chunks/{dist-7JGAAQSC.js → dist-6BMOAE3Z.js} +2 -2
- package/chunks/{dist-3BMEUGTG.js → dist-B2CGTW6T.js} +1 -1
- package/chunks/{dist-C5U4LJKW.js → dist-EWW3J4HQ.js} +5 -4
- package/chunks/{dist-K4WWQBHS.js → dist-EZE3V3Q7.js} +55 -15
- package/chunks/{dist-DPPHJAVL.js → dist-J47AXBZC.js} +918 -142
- package/chunks/{dist-SFQ34F4M.js → dist-OTUO3AS2.js} +8 -1091
- package/chunks/{dist-KS4O2NKE.js → dist-Z3CS4OVP.js} +14 -8
- package/chunks/{earlyInputCapture-L5ST23A6.js → earlyInputCapture-72FYHYRD.js} +28 -24
- package/chunks/{edit-LHHRFNFK.js → edit-SWVVWHXW.js} +28 -24
- package/chunks/{en-IRJ2WN5T.js → en-SY5GTIGX.js} +6 -0
- package/chunks/{enter-worktree-6NXCRZPF.js → enter-worktree-2HF6WQEO.js} +28 -24
- package/chunks/{enterPlanMode-ZVQT4U7D.js → enterPlanMode-OW6S7L4P.js} +28 -24
- package/chunks/{environment-GJ2HWJOS.js → environment-LRTBTDXH.js} +32 -28
- package/chunks/{errors-6RLH3XXC.js → errors-4CO2DME6.js} +30 -26
- package/chunks/{exit-worktree-I2YLUHHY.js → exit-worktree-GHJEIRGL.js} +28 -24
- package/chunks/{exitPlanMode-7CCWKO7I.js → exitPlanMode-JVP4FNNK.js} +28 -24
- package/chunks/{fast-path-DVFD4HQD.js → fast-path-HCCY7GR2.js} +24 -3
- package/chunks/{fast-path-settings-WQJU2LAT.js → fast-path-settings-MN5QQQET.js} +6 -3
- package/chunks/{fr-GK3HQYVB.js → fr-RQFO7U4P.js} +5 -0
- package/chunks/{gemini-7FWGOYD4.js → gemini-V3YVRKXU.js} +85 -72
- package/chunks/{geminiContentGenerator-V2WVLIXU.js → geminiContentGenerator-LVPMQUWX.js} +1 -1
- package/chunks/{glob-3N6GGI75.js → glob-7HRXHYDR.js} +28 -24
- package/chunks/{goal-tools-APOW6UXL.js → goal-tools-PXWN5VK3.js} +4 -2
- package/chunks/{grep-V43ILZVX.js → grep-BITQUON5.js} +28 -24
- package/chunks/{handleAutoUpdate-A5WFVWIA.js → handleAutoUpdate-DKFY454S.js} +32 -28
- package/chunks/{i18n-PLVQ4FBZ.js → i18n-53BQIQSH.js} +29 -25
- package/chunks/{image-gen-7C6IK6DC.js → image-gen-H62FLDFB.js} +7 -5
- package/chunks/{initializer-CVAIKZYL.js → initializer-Q7NUQRSU.js} +35 -31
- package/chunks/{installationInfo-J6QDHNTK.js → installationInfo-BWFHT7WU.js} +29 -25
- package/chunks/{ja-3FA46IKD.js → ja-KOZKHJHZ.js} +5 -0
- package/chunks/{list-ZZ4OUUWV.js → list-OWQKR6JK.js} +38 -34
- package/chunks/{list-agents-KFFIIS2G.js → list-agents-Z4WABFDZ.js} +1 -1
- package/chunks/{loadedSettingsAdapter-QRYRJSWL.js → loadedSettingsAdapter-HNPKQMFA.js} +35 -31
- package/chunks/{loggingContentGenerator-OJCO75HM.js → loggingContentGenerator-A5I3VQUC.js} +10 -8
- package/chunks/{loop-wakeup-TLMJPMMP.js → loop-wakeup-UZ5RL5Y2.js} +2 -2
- package/chunks/{ls-UVVE2XGE.js → ls-TVHDGIES.js} +1 -1
- package/chunks/{lsp-QMEA2VLB.js → lsp-CVN6OQPI.js} +1 -1
- package/chunks/main-PXAUXNF2.js +8 -0
- package/chunks/{managed-npm-update-PCOSCP2N.js → managed-npm-update-CUUJGUTV.js} +29 -25
- package/chunks/{mcp-M3WKKWKY.js → mcp-GJSC7ZPO.js} +35 -31
- package/chunks/{monitor-GN24FH6C.js → monitor-TZ2II7JM.js} +38 -30
- package/chunks/{nonInteractiveCli-KPTU3VSQ.js → nonInteractiveCli-22RS4EVH.js} +72 -66
- package/chunks/{notebook-edit-4YM65BBO.js → notebook-edit-YZC3YPY2.js} +36 -24
- package/chunks/{openaiContentGenerator-EDQT6GTV.js → openaiContentGenerator-OIGO5XNF.js} +21 -11
- package/chunks/{pidfile-JOIIRN2C.js → pidfile-QJQ65RJ2.js} +28 -24
- package/chunks/{process-registry-2CHQBXH5.js → process-registry-PMJOA5CO.js} +15 -0
- package/chunks/{processUtils-5SV4MX3Q.js → processUtils-V5VSDIKS.js} +2 -2
- package/chunks/{pt-3AOBKPIJ.js → pt-U6AOCTMF.js} +5 -0
- package/chunks/{qwenContentGenerator-ODRJSUGR.js → qwenContentGenerator-HXM25BGB.js} +35 -30
- package/chunks/{qwenOAuth2-NESCMZ47.js → qwenOAuth2-7MTMS2Z5.js} +7 -5
- package/chunks/{read-file-HPSODLPK.js → read-file-PMGXB3ZB.js} +8 -6
- package/chunks/{read-mcp-resource-2TNSJTC3.js → read-mcp-resource-PZ4ZF6YL.js} +1 -1
- package/chunks/{record-artifact-RAON52FC.js → record-artifact-P4HFMS7X.js} +2 -2
- package/chunks/{resumeHistoryUtils-TXCOFFMQ.js → resumeHistoryUtils-YUTPLHUH.js} +33 -29
- package/chunks/{ripGrep-ZKQGTQAO.js → ripGrep-XUS66YIV.js} +28 -24
- package/chunks/{ru-VJRAMC4W.js → ru-CMX4UMYP.js} +5 -0
- package/chunks/{run-qwen-serve-ZPKPKECF.js → run-qwen-serve-4NVSU75L.js} +261 -62
- package/chunks/{runtime-2FLNNM36.js → runtime-QLRVP6HM.js} +40 -36
- package/chunks/{scheduler-365PJHNR.js → scheduler-PBB2NSOP.js} +28 -24
- package/chunks/{sdk-exporters-http-KHAB5JSD.js → sdk-exporters-http-XVTZQRCE.js} +2 -2
- package/chunks/{sdk-impl-KD7FSTC3.js → sdk-impl-7W7AKCS4.js} +7 -3
- package/chunks/{send-message-ZM7MRUGP.js → send-message-CAMSLG2L.js} +4 -3
- package/chunks/{serve-QD2RNLKJ.js → serve-BWKTRX72.js} +37 -31
- package/chunks/{server-XLJVLTYM.js → server-E7CH7WPK.js} +1437 -593
- package/chunks/{session-3VTUHH4Q.js → session-QEKSJ6YU.js} +166 -105
- package/chunks/{settings-KULVPCQC.js → settings-BRAOSJIM.js} +34 -30
- package/chunks/{shell-3SWW22MH.js → shell-OF3CK4AT.js} +28 -24
- package/chunks/{skill-KDHWYS7W.js → skill-HLH2NO2H.js} +9 -7
- package/chunks/{skill-settings-NMY4JEJC.js → skill-settings-DRPU7YI5.js} +34 -30
- package/chunks/{spawnChannel-ZKS4Q5OU.js → spawnChannel-4KO7YTFM.js} +31 -27
- package/chunks/{standalone-update-7CXPGAQ4.js → standalone-update-DJN2R3YW.js} +30 -26
- package/chunks/{startInteractiveUI-2QQLEKM6.js → startInteractiveUI-O3WQQ2WC.js} +384 -173
- package/chunks/{syntheticOutput-ZLCUTKO2.js → syntheticOutput-PEBJQYJV.js} +2 -2
- package/chunks/{task-create-CQP5UEA3.js → task-create-5NWCQSJF.js} +5 -4
- package/chunks/{task-list-XLEZOJXP.js → task-list-53265TRZ.js} +1 -1
- package/chunks/{task-stop-7ZQM5CFF.js → task-stop-FPCOIRYX.js} +1 -1
- package/chunks/{task-update-JA75U2SN.js → task-update-5HN577LS.js} +5 -4
- package/chunks/{team-create-2WTNGAOX.js → team-create-2E4ACBJD.js} +28 -24
- package/chunks/{team-delete-MHY3UZGY.js → team-delete-MMQB4OSC.js} +1 -1
- package/chunks/{team-plan-approval-LZTYLEG4.js → team-plan-approval-LWIDXYOA.js} +28 -24
- package/chunks/{terminal-image-renderer-R5HHAFJN.js → terminal-image-renderer-PJM7663W.js} +30 -26
- package/chunks/{theme-manager-PAUCSJFF.js → theme-manager-FDQTM3RP.js} +28 -24
- package/chunks/{todoWrite-UPVOHYGD.js → todoWrite-JGV6VLOX.js} +1 -1
- package/chunks/{tool-search-2BFCGLI6.js → tool-search-TL5ZXBF4.js} +11 -8
- package/chunks/{total-session-admission-MK4SINFK.js → total-session-admission-LS6EY5KT.js} +37 -32
- package/chunks/{trustedFolders-TJ5S26N7.js → trustedFolders-5RWP5OB7.js} +32 -26
- package/chunks/{types-ML3TRJQ5.js → types-WYCFCEHR.js} +5 -3
- package/chunks/{update-relaunch-N7AYLARF.js → update-relaunch-HWQ4USKY.js} +5 -5
- package/chunks/{updateCheck-QRZ3DVT5.js → updateCheck-EZMBTEIR.js} +31 -27
- package/chunks/{useAutoAcceptIndicator-DBJ7Y5AF.js → useAutoAcceptIndicator-JDMI627A.js} +37 -33
- package/chunks/{validateNonInterActiveAuth-6ZQWUDS3.js → validateNonInterActiveAuth-RRUHC5RO.js} +67 -63
- package/chunks/{version-AJQGQWXC.js → version-XS4UTKUX.js} +1 -1
- package/chunks/{web-fetch-QWJYRXFL.js → web-fetch-2JV7H6OM.js} +14 -10
- package/chunks/{web-search-2AOXJGHU.js → web-search-RCTN2GAM.js} +10 -7
- package/chunks/{workflow-ERH3SJG2.js → workflow-6MKLKQ6R.js} +909 -273
- package/chunks/{workspace-providers-status-HZ474RA4.js → workspace-providers-status-YZ2IJ4DK.js} +38 -34
- package/chunks/{workspace-registration-store-6EUP4JXG.js → workspace-registration-store-IYN72LBS.js} +1 -1
- package/chunks/{workspace-registry-R4APRRNC.js → workspace-registry-7LFBZQLT.js} +37 -32
- package/chunks/{workspace-service-HFIFDMU7.js → workspace-service-2EHSPRJB.js} +45 -39
- package/chunks/{workspace-skills-status-HAHEIHGK.js → workspace-skills-status-5VJ2D5HN.js} +36 -32
- package/chunks/{workspace-trust-reconciler-65GTAGDK.js → workspace-trust-reconciler-X2LZ6XCI.js} +44 -39
- package/chunks/{write-file-B34CDELV.js → write-file-CJK6SCCF.js} +28 -24
- package/chunks/{zh-ARWDLDLR.js → zh-AGL2FVBI.js} +6 -0
- package/chunks/{zh-TW-Y4RGI3P7.js → zh-TW-KI66MHQY.js} +6 -0
- package/chunks/{zoom-image-HPRBZHSS.js → zoom-image-BVW4RFYW.js} +8 -6
- package/cli.js +13 -13
- package/locales/ca.js +10 -0
- package/locales/de.js +9 -0
- package/locales/en.js +10 -0
- package/locales/fr.js +9 -0
- package/locales/ja.js +9 -0
- package/locales/pt.js +9 -0
- package/locales/ru.js +9 -0
- package/locales/zh-TW.js +10 -0
- package/locales/zh.js +10 -0
- package/package.json +3 -3
- package/web-shell/assets/{arc-Ip-FFDJ0.js → arc-DDtoJrAW.js} +1 -1
- package/web-shell/assets/{architectureDiagram-3BPJPVTR-CChqgwIb.js → architectureDiagram-3BPJPVTR-BAInIW4O.js} +1 -1
- package/web-shell/assets/{blockDiagram-GPEHLZMM-BHN-Tfss.js → blockDiagram-GPEHLZMM-ChPDk7fP.js} +1 -1
- package/web-shell/assets/{c4Diagram-AAUBKEIU-BhyjzDjN.js → c4Diagram-AAUBKEIU-Cd9BJuUy.js} +1 -1
- package/web-shell/assets/channel-0OQklTfP.js +1 -0
- package/web-shell/assets/{chunk-2J33WTMH-BB9eyHrx.js → chunk-2J33WTMH-COQkLp56.js} +1 -1
- package/web-shell/assets/{chunk-4BX2VUAB-BeV7ce_J.js → chunk-4BX2VUAB-GUJshQ_l.js} +1 -1
- package/web-shell/assets/{chunk-55IACEB6-DO7kXDiV.js → chunk-55IACEB6-Boaa7c10.js} +1 -1
- package/web-shell/assets/{chunk-727SXJPM-B27MPznD.js → chunk-727SXJPM-CcRXaly2.js} +1 -1
- package/web-shell/assets/{chunk-AQP2D5EJ-DHIjqjD_.js → chunk-AQP2D5EJ-BY0OARHh.js} +1 -1
- package/web-shell/assets/{chunk-FMBD7UC4-DabMqyN2.js → chunk-FMBD7UC4-DLFQfv0S.js} +1 -1
- package/web-shell/assets/{chunk-ND2GUHAM-Dw7Nnnxc.js → chunk-ND2GUHAM-C_S0u-D2.js} +1 -1
- package/web-shell/assets/{chunk-QZHKN3VN-DdaZew1Q.js → chunk-QZHKN3VN-DP9m64hw.js} +1 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-CZ4-apsu.js +1 -0
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-CZ4-apsu.js +1 -0
- package/web-shell/assets/{cose-bilkent-S5V4N54A-CgBpCYH5.js → cose-bilkent-S5V4N54A-CGY6zGE1.js} +1 -1
- package/web-shell/assets/{dagre-BM42HDAG-BB4IU8G0.js → dagre-BM42HDAG-yB7whKNn.js} +1 -1
- package/web-shell/assets/{diagram-2AECGRRQ-BcUTHU37.js → diagram-2AECGRRQ-Bdlc59La.js} +1 -1
- package/web-shell/assets/{diagram-5GNKFQAL-B6Lyihyv.js → diagram-5GNKFQAL-BUClP18L.js} +1 -1
- package/web-shell/assets/{diagram-KO2AKTUF-CRIJOjpG.js → diagram-KO2AKTUF-aZm08kjn.js} +1 -1
- package/web-shell/assets/{diagram-LMA3HP47-DdNiwWWT.js → diagram-LMA3HP47-7DGwEkxC.js} +1 -1
- package/web-shell/assets/{diagram-OG6HWLK6-Dz4b32Do.js → diagram-OG6HWLK6-CAGKayxx.js} +1 -1
- package/web-shell/assets/{erDiagram-TEJ5UH35-D-8NGw77.js → erDiagram-TEJ5UH35-CptoHHQi.js} +1 -1
- package/web-shell/assets/{flowDiagram-I6XJVG4X-Dun26LyM.js → flowDiagram-I6XJVG4X-CNOH0s7Q.js} +1 -1
- package/web-shell/assets/{ganttDiagram-6RSMTGT7-F10Hu1Gc.js → ganttDiagram-6RSMTGT7-CCQuCU3y.js} +1 -1
- package/web-shell/assets/{gitGraphDiagram-PVQCEYII-Bf8Ez6-D.js → gitGraphDiagram-PVQCEYII-B7gv9f4E.js} +1 -1
- package/web-shell/assets/{index-BXqw-nGq.js → index-BoUPVvpf.js} +1 -1
- package/web-shell/assets/index-D1YQXYsB.css +5 -0
- package/web-shell/assets/index-J4N7zCmU.js +1768 -0
- package/web-shell/assets/{infoDiagram-5YYISTIA-DVgTMLvj.js → infoDiagram-5YYISTIA-Bb3KYEbR.js} +1 -1
- package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-uT-KepvK.js → ishikawaDiagram-YF4QCWOH-DWEzbAGi.js} +1 -1
- package/web-shell/assets/{journeyDiagram-JHISSGLW-Vg_XadQf.js → journeyDiagram-JHISSGLW-CmxwEqeb.js} +1 -1
- package/web-shell/assets/{kanban-definition-UN3LZRKU-Dyv1ESBE.js → kanban-definition-UN3LZRKU-Ci0gDD8O.js} +1 -1
- package/web-shell/assets/{linear-BMIepYX3.js → linear-BqxZqGhS.js} +1 -1
- package/web-shell/assets/{mermaid.core-zA8pJ9ag.js → mermaid.core-BDAFffHv.js} +5 -5
- package/web-shell/assets/{mindmap-definition-RKZ34NQL-BCW_BZ_5.js → mindmap-definition-RKZ34NQL-Btvx-xvS.js} +1 -1
- package/web-shell/assets/{pieDiagram-4H26LBE5-DseNEGp2.js → pieDiagram-4H26LBE5-CKAg7yG7.js} +1 -1
- package/web-shell/assets/{quadrantDiagram-W4KKPZXB-6Z7wr1Fi.js → quadrantDiagram-W4KKPZXB-DIt8E1mC.js} +1 -1
- package/web-shell/assets/{requirementDiagram-4Y6WPE33-CVOlCRPf.js → requirementDiagram-4Y6WPE33-BA7mQWQJ.js} +1 -1
- package/web-shell/assets/{sankeyDiagram-5OEKKPKP-CGhgrUJZ.js → sankeyDiagram-5OEKKPKP-D0JppnVU.js} +1 -1
- package/web-shell/assets/{sequenceDiagram-3UESZ5HK-dlqmpLuQ.js → sequenceDiagram-3UESZ5HK-29DIQFjB.js} +1 -1
- package/web-shell/assets/{stateDiagram-AJRCARHV-B9EW10Xb.js → stateDiagram-AJRCARHV-iiXMdK--.js} +1 -1
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-CEGK3l80.js +1 -0
- package/web-shell/assets/{timeline-definition-PNZ67QCA-BBRh0mgZ.js → timeline-definition-PNZ67QCA-CeF7ngSW.js} +1 -1
- package/web-shell/assets/{vennDiagram-CIIHVFJN-B8Gs-REP.js → vennDiagram-CIIHVFJN-Beilq8D6.js} +1 -1
- package/web-shell/assets/{wardley-L42UT6IY-D_y80Ur7.js → wardley-L42UT6IY-DOYjY4zO.js} +1 -1
- package/web-shell/assets/{wardleyDiagram-YWT4CUSO-D-CNfHJ-.js → wardleyDiagram-YWT4CUSO-Dtqp8o18.js} +1 -1
- package/web-shell/assets/{xychartDiagram-2RQKCTM6-DQ5CvELo.js → xychartDiagram-2RQKCTM6-cdAc0Dfv.js} +1 -1
- package/web-shell/index.html +2 -2
- package/chunks/chunk-6PEXNQTX.js +0 -68
- package/chunks/chunk-IUFV6FYU.js +0 -81
- package/chunks/chunk-RXFQM6FQ.js +0 -42
- package/web-shell/assets/channel-Cu8qd6OB.js +0 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-BI3KrXhq.js +0 -1
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-BI3KrXhq.js +0 -1
- package/web-shell/assets/index-QQlUCJGg.css +0 -5
- package/web-shell/assets/index-hcgjV7vS.js +0 -1768
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-CJTZJJ5X.js +0 -1
- package/chunks/{anthropicContentGenerator-DTMVEL5M.js → anthropicContentGenerator-SSFE2753.js} +9 -9
- /package/chunks/{chunk-VXZBKKQR.js → chunk-NTTBXH7U.js} +0 -0
- /package/chunks/{chunk-GRC5HGPI.js → chunk-OIBUG24X.js} +0 -0
|
@@ -5,29 +5,30 @@ import {
|
|
|
5
5
|
FileDiscoveryService,
|
|
6
6
|
GitWorktreeService,
|
|
7
7
|
generateAgentWorktreeSlug,
|
|
8
|
+
isTerminalWorkflowStatus,
|
|
8
9
|
rebuildToolRegistryOnOverride,
|
|
9
10
|
resolveSavedWorkflowScript,
|
|
10
11
|
stripAnsiAndControl,
|
|
11
12
|
toModelVisibleSubagentResult,
|
|
12
13
|
writeWorkflowSnapshot,
|
|
13
14
|
writeWorktreeSessionMarker
|
|
14
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-47ZUMGGY.js";
|
|
15
16
|
import "./chunk-GOFAQQZA.js";
|
|
16
17
|
import "./chunk-5M6IDOMF.js";
|
|
17
18
|
import "./chunk-TWPJO254.js";
|
|
18
19
|
import "./chunk-H6XPXXMH.js";
|
|
19
|
-
import "./chunk-
|
|
20
|
+
import "./chunk-2UUMVNYT.js";
|
|
20
21
|
import "./chunk-MVUQRLOH.js";
|
|
21
22
|
import "./chunk-XCWO3SMQ.js";
|
|
22
23
|
import "./chunk-7MH4J33A.js";
|
|
23
24
|
import {
|
|
24
25
|
parsePositiveIntegerEnv
|
|
25
26
|
} from "./chunk-6PVPNMXU.js";
|
|
26
|
-
import "./chunk-
|
|
27
|
+
import "./chunk-F3II4BTZ.js";
|
|
27
28
|
import "./chunk-IRH27ZC2.js";
|
|
28
29
|
import "./chunk-QHWCP53L.js";
|
|
29
30
|
import "./chunk-GNPNYXJB.js";
|
|
30
|
-
import "./chunk-
|
|
31
|
+
import "./chunk-HUWENAHO.js";
|
|
31
32
|
import "./chunk-O6GEWCJA.js";
|
|
32
33
|
import "./chunk-T26EAKDL.js";
|
|
33
34
|
import "./chunk-ZPJWUGCS.js";
|
|
@@ -36,65 +37,70 @@ import "./chunk-J6SZID63.js";
|
|
|
36
37
|
import "./chunk-KRXPRVGL.js";
|
|
37
38
|
import "./chunk-GM463R2B.js";
|
|
38
39
|
import "./chunk-SEZ556DZ.js";
|
|
39
|
-
import "./chunk-
|
|
40
|
-
import "./chunk-
|
|
40
|
+
import "./chunk-2FRY5CRX.js";
|
|
41
|
+
import "./chunk-67N6HB5H.js";
|
|
42
|
+
import {
|
|
43
|
+
SUBAGENT_PLAN_LIFECYCLE_TOOLS
|
|
44
|
+
} from "./chunk-WAUGQKUU.js";
|
|
45
|
+
import "./chunk-DZUO626D.js";
|
|
46
|
+
import "./chunk-4TRQPFDP.js";
|
|
47
|
+
import "./chunk-SAH4BD2J.js";
|
|
41
48
|
import {
|
|
42
|
-
SUBAGENT_PLAN_LIFECYCLE_TOOLS,
|
|
43
49
|
runWithAgentContext
|
|
44
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-CPG6P4GG.js";
|
|
45
51
|
import "./chunk-S6LOFUVP.js";
|
|
46
|
-
import "./chunk-
|
|
52
|
+
import "./chunk-2J3OJGTL.js";
|
|
53
|
+
import "./chunk-IA7TGCN2.js";
|
|
47
54
|
import "./chunk-K623ENWT.js";
|
|
48
55
|
import "./chunk-AQ37AY7B.js";
|
|
49
56
|
import {
|
|
50
57
|
WorkspaceContext
|
|
51
58
|
} from "./chunk-EQL65XGA.js";
|
|
52
|
-
import "./chunk-
|
|
53
|
-
import "./chunk-22NBYCPD.js";
|
|
59
|
+
import "./chunk-3P2LV43B.js";
|
|
54
60
|
import "./chunk-NAVJD2PQ.js";
|
|
55
|
-
import "./chunk-
|
|
56
|
-
import "./chunk-
|
|
61
|
+
import "./chunk-HV76SFIA.js";
|
|
62
|
+
import "./chunk-4PYCZH2V.js";
|
|
63
|
+
import "./chunk-P3QQPMQA.js";
|
|
64
|
+
import "./chunk-SR7RZ4MS.js";
|
|
65
|
+
import "./chunk-M6HMMKVG.js";
|
|
57
66
|
import "./chunk-DGEIYUC3.js";
|
|
58
67
|
import "./chunk-MPHPFVKK.js";
|
|
59
68
|
import "./chunk-AXMWHKXA.js";
|
|
69
|
+
import "./chunk-GLCZKT5V.js";
|
|
60
70
|
import {
|
|
61
71
|
createAbortController,
|
|
62
72
|
createChildAbortController
|
|
63
73
|
} from "./chunk-DJ2GSRLV.js";
|
|
64
|
-
import "./chunk-33ACCIIY.js";
|
|
65
|
-
import "./chunk-L4N6TIP7.js";
|
|
66
|
-
import "./chunk-2J3OJGTL.js";
|
|
67
|
-
import "./chunk-P3QQPMQA.js";
|
|
68
|
-
import "./chunk-M6HMMKVG.js";
|
|
69
|
-
import "./chunk-GLCZKT5V.js";
|
|
70
74
|
import "./chunk-EI3HZX6C.js";
|
|
71
75
|
import {
|
|
72
76
|
WorkflowRunEvent,
|
|
73
77
|
logWorkflowRun,
|
|
74
78
|
read,
|
|
75
79
|
writeLine
|
|
76
|
-
} from "./chunk-
|
|
80
|
+
} from "./chunk-YGT2AUJ7.js";
|
|
77
81
|
import "./chunk-WOJZWRAZ.js";
|
|
78
82
|
import "./chunk-VGC4I5JJ.js";
|
|
79
83
|
import "./chunk-FVKHVJZQ.js";
|
|
84
|
+
import "./chunk-COBO5EBO.js";
|
|
80
85
|
import {
|
|
81
86
|
SyntheticOutputTool
|
|
82
|
-
} from "./chunk-
|
|
87
|
+
} from "./chunk-6ZRFAKXK.js";
|
|
83
88
|
import {
|
|
84
89
|
BaseDeclarativeTool,
|
|
85
90
|
BaseToolInvocation,
|
|
86
91
|
ToolDisplayNames,
|
|
87
92
|
ToolNames
|
|
88
|
-
} from "./chunk-
|
|
89
|
-
import "./chunk-
|
|
93
|
+
} from "./chunk-PYQADEFD.js";
|
|
94
|
+
import "./chunk-E2T7FLDU.js";
|
|
95
|
+
import "./chunk-F6WFNA7U.js";
|
|
90
96
|
import "./chunk-46UV252V.js";
|
|
91
97
|
import "./chunk-ZBVS26BY.js";
|
|
92
98
|
import "./chunk-KKBPOU75.js";
|
|
93
99
|
import "./chunk-EUNWC2VS.js";
|
|
94
100
|
import "./chunk-FOGU3LJX.js";
|
|
95
|
-
import "./chunk-
|
|
101
|
+
import "./chunk-L2AFWWJE.js";
|
|
96
102
|
import "./chunk-W4RQUHY3.js";
|
|
97
|
-
import "./chunk-
|
|
103
|
+
import "./chunk-PDPFQ2FO.js";
|
|
98
104
|
import {
|
|
99
105
|
createDebugLogger
|
|
100
106
|
} from "./chunk-OIVKILPI.js";
|
|
@@ -114,95 +120,6 @@ import {
|
|
|
114
120
|
// packages/core/src/tools/workflow/workflow.ts
|
|
115
121
|
init_esbuild_shims();
|
|
116
122
|
|
|
117
|
-
// packages/core/src/agents/runtime/workflow-budget.ts
|
|
118
|
-
init_esbuild_shims();
|
|
119
|
-
var debugLogger = createDebugLogger("WORKFLOW_BUDGET");
|
|
120
|
-
var MAX_TOKENS_PER_WORKFLOW_ENV = "QWEN_CODE_MAX_TOKENS_PER_WORKFLOW";
|
|
121
|
-
var HARD_MAX_TOKENS_CEILING = 1e8;
|
|
122
|
-
function resolveMaxTokensPerWorkflow(env = process.env) {
|
|
123
|
-
const raw = env[MAX_TOKENS_PER_WORKFLOW_ENV];
|
|
124
|
-
if (raw === void 0 || raw.trim() === "") {
|
|
125
|
-
return null;
|
|
126
|
-
}
|
|
127
|
-
const parsed = parsePositiveIntegerEnv(raw, 0);
|
|
128
|
-
if (parsed < 1) {
|
|
129
|
-
debugLogger.warn(
|
|
130
|
-
`Invalid ${MAX_TOKENS_PER_WORKFLOW_ENV}=${JSON.stringify(raw)}, treating as unset (no cap)`
|
|
131
|
-
);
|
|
132
|
-
return null;
|
|
133
|
-
}
|
|
134
|
-
if (parsed > HARD_MAX_TOKENS_CEILING) {
|
|
135
|
-
debugLogger.warn(
|
|
136
|
-
`${MAX_TOKENS_PER_WORKFLOW_ENV}=${parsed} exceeds hard ceiling (${HARD_MAX_TOKENS_CEILING}); clamping.`
|
|
137
|
-
);
|
|
138
|
-
return HARD_MAX_TOKENS_CEILING;
|
|
139
|
-
}
|
|
140
|
-
return parsed;
|
|
141
|
-
}
|
|
142
|
-
__name(resolveMaxTokensPerWorkflow, "resolveMaxTokensPerWorkflow");
|
|
143
|
-
var WorkflowBudgetImpl = class _WorkflowBudgetImpl {
|
|
144
|
-
static {
|
|
145
|
-
__name(this, "WorkflowBudgetImpl");
|
|
146
|
-
}
|
|
147
|
-
total;
|
|
148
|
-
_spent;
|
|
149
|
-
constructor(total) {
|
|
150
|
-
this.total = total;
|
|
151
|
-
this._spent = 0;
|
|
152
|
-
}
|
|
153
|
-
spent() {
|
|
154
|
-
return this._spent;
|
|
155
|
-
}
|
|
156
|
-
remaining() {
|
|
157
|
-
if (this.total === null) return Infinity;
|
|
158
|
-
return Math.max(0, this.total - this._spent);
|
|
159
|
-
}
|
|
160
|
-
/**
|
|
161
|
-
* Host-side increment. NOT exposed to the script — the
|
|
162
|
-
* `WorkflowBudget` interface deliberately omits any setter so a
|
|
163
|
-
* malicious workflow cannot inflate / deflate the budget. Only the
|
|
164
|
-
* orchestrator (in `countedDispatch`) calls this after a dispatch
|
|
165
|
-
* resolves with the agent's output token count.
|
|
166
|
-
*
|
|
167
|
-
* Non-positive deltas are silently dropped (some dispatches return
|
|
168
|
-
* `output_tokens: 0` on early failures); negative deltas would be a
|
|
169
|
-
* caller bug and are also dropped rather than silently rewinding
|
|
170
|
-
* the counter.
|
|
171
|
-
*/
|
|
172
|
-
recordSpent(deltaTokens) {
|
|
173
|
-
if (!Number.isFinite(deltaTokens) || deltaTokens <= 0) return;
|
|
174
|
-
this._spent += deltaTokens;
|
|
175
|
-
}
|
|
176
|
-
/**
|
|
177
|
-
* Factory: build a budget from the current environment. Convenience
|
|
178
|
-
* over `new WorkflowBudgetImpl(resolveMaxTokensPerWorkflow(env))`.
|
|
179
|
-
*/
|
|
180
|
-
static fromEnv(env = process.env) {
|
|
181
|
-
return new _WorkflowBudgetImpl(resolveMaxTokensPerWorkflow(env));
|
|
182
|
-
}
|
|
183
|
-
};
|
|
184
|
-
var WorkflowBudgetExceededError = class extends Error {
|
|
185
|
-
static {
|
|
186
|
-
__name(this, "WorkflowBudgetExceededError");
|
|
187
|
-
}
|
|
188
|
-
name = "WorkflowBudgetExceededError";
|
|
189
|
-
runId;
|
|
190
|
-
budgetTotal;
|
|
191
|
-
spent;
|
|
192
|
-
constructor(runId, budgetTotal, spent) {
|
|
193
|
-
super(
|
|
194
|
-
`Workflow ${runId} exceeded the token budget (${spent} / ${budgetTotal} output tokens spent).`
|
|
195
|
-
);
|
|
196
|
-
this.runId = runId;
|
|
197
|
-
this.budgetTotal = budgetTotal;
|
|
198
|
-
this.spent = spent;
|
|
199
|
-
}
|
|
200
|
-
};
|
|
201
|
-
|
|
202
|
-
// packages/core/src/agents/runtime/workflow-runner.ts
|
|
203
|
-
init_esbuild_shims();
|
|
204
|
-
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
205
|
-
|
|
206
123
|
// packages/core/src/agents/runtime/workflow-orchestrator.ts
|
|
207
124
|
init_esbuild_shims();
|
|
208
125
|
import { randomBytes } from "node:crypto";
|
|
@@ -388,7 +305,7 @@ function isRegexContext(source, i) {
|
|
|
388
305
|
return /[{[(,;:=!&|?+\-*/%^~<>]/.test(prev);
|
|
389
306
|
}
|
|
390
307
|
__name(isRegexContext, "isRegexContext");
|
|
391
|
-
var
|
|
308
|
+
var debugLogger = createDebugLogger("WORKFLOW");
|
|
392
309
|
var MAX_LOG_LINES = 1e4;
|
|
393
310
|
var MAX_PHASE_ENTRIES = 1e4;
|
|
394
311
|
var ARGS_MAX_DEPTH = 64;
|
|
@@ -402,6 +319,50 @@ function resolveMaxWallClockMs(opts) {
|
|
|
402
319
|
return DEFAULT_MAX_WALL_CLOCK_MS;
|
|
403
320
|
}
|
|
404
321
|
__name(resolveMaxWallClockMs, "resolveMaxWallClockMs");
|
|
322
|
+
var WallClockWatchdog = class {
|
|
323
|
+
constructor(budgetMs, onFire) {
|
|
324
|
+
this.onFire = onFire;
|
|
325
|
+
this.remainingMs = budgetMs;
|
|
326
|
+
this.arm();
|
|
327
|
+
}
|
|
328
|
+
static {
|
|
329
|
+
__name(this, "WallClockWatchdog");
|
|
330
|
+
}
|
|
331
|
+
timer;
|
|
332
|
+
remainingMs;
|
|
333
|
+
armedAt = 0;
|
|
334
|
+
paused = false;
|
|
335
|
+
stopped = false;
|
|
336
|
+
pause() {
|
|
337
|
+
if (this.stopped || this.paused || this.timer === void 0) return;
|
|
338
|
+
this.paused = true;
|
|
339
|
+
clearTimeout(this.timer);
|
|
340
|
+
this.timer = void 0;
|
|
341
|
+
this.remainingMs = Math.max(
|
|
342
|
+
0,
|
|
343
|
+
this.remainingMs - (performance.now() - this.armedAt)
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
resume() {
|
|
347
|
+
if (this.stopped || !this.paused) return;
|
|
348
|
+
this.paused = false;
|
|
349
|
+
this.arm();
|
|
350
|
+
}
|
|
351
|
+
stop() {
|
|
352
|
+
this.stopped = true;
|
|
353
|
+
if (this.timer !== void 0) clearTimeout(this.timer);
|
|
354
|
+
this.timer = void 0;
|
|
355
|
+
}
|
|
356
|
+
arm() {
|
|
357
|
+
this.armedAt = performance.now();
|
|
358
|
+
this.timer = setTimeout(() => {
|
|
359
|
+
this.stopped = true;
|
|
360
|
+
this.timer = void 0;
|
|
361
|
+
this.onFire();
|
|
362
|
+
}, this.remainingMs);
|
|
363
|
+
this.timer.unref?.();
|
|
364
|
+
}
|
|
365
|
+
};
|
|
405
366
|
function validateArgs(val, depth = 0, seen = /* @__PURE__ */ new WeakSet()) {
|
|
406
367
|
if (depth > ARGS_MAX_DEPTH) {
|
|
407
368
|
throw new Error(
|
|
@@ -447,7 +408,7 @@ function createWorkflowSandbox(opts) {
|
|
|
447
408
|
try {
|
|
448
409
|
opts.emitter?.logAppended?.(line);
|
|
449
410
|
} catch (e) {
|
|
450
|
-
|
|
411
|
+
debugLogger.warn("emitter.logAppended threw:", e);
|
|
451
412
|
}
|
|
452
413
|
} else if (logs.length === MAX_LOG_LINES) {
|
|
453
414
|
logs.push(`[workflow log truncated at ${MAX_LOG_LINES} lines]`);
|
|
@@ -461,7 +422,7 @@ function createWorkflowSandbox(opts) {
|
|
|
461
422
|
try {
|
|
462
423
|
opts.emitter?.phaseStarted?.(t);
|
|
463
424
|
} catch (e) {
|
|
464
|
-
|
|
425
|
+
debugLogger.warn("emitter.phaseStarted threw:", e);
|
|
465
426
|
}
|
|
466
427
|
} else if (phases.length === MAX_PHASE_ENTRIES) {
|
|
467
428
|
phases.push(
|
|
@@ -471,6 +432,17 @@ function createWorkflowSandbox(opts) {
|
|
|
471
432
|
}, "safePhase");
|
|
472
433
|
if (opts.args !== void 0) validateArgs(opts.args);
|
|
473
434
|
const argsJson = opts.args === void 0 ? null : JSON.stringify(opts.args);
|
|
435
|
+
const unconsumedRoots = /* @__PURE__ */ new Map();
|
|
436
|
+
const unconsumedRejections = /* @__PURE__ */ new Map();
|
|
437
|
+
let nextUnconsumedId = 1;
|
|
438
|
+
let unconsumedSettled = false;
|
|
439
|
+
let mirroredEscapeKeys = /* @__PURE__ */ new Set();
|
|
440
|
+
const unconsumedRejectionLine = /* @__PURE__ */ __name((rec) => {
|
|
441
|
+
if (rec.dispatchFailed) {
|
|
442
|
+
return rec.isRoot ? "dispatch failed (result not consumed): " + rec.msg : "dispatch failed (rejection not handled): " + rec.msg;
|
|
443
|
+
}
|
|
444
|
+
return "script handler failed (rejection not handled): " + rec.msg;
|
|
445
|
+
}, "unconsumedRejectionLine");
|
|
474
446
|
const bridge = {
|
|
475
447
|
argsJson,
|
|
476
448
|
pushPhase: safePhase,
|
|
@@ -484,10 +456,56 @@ function createWorkflowSandbox(opts) {
|
|
|
484
456
|
// value" (this warn). Receives only primitive strings/numbers — the bridge
|
|
485
457
|
// contract forbids host objects crossing back to the script.
|
|
486
458
|
logRevivalFailure: /* @__PURE__ */ __name((idx, reason) => {
|
|
487
|
-
|
|
459
|
+
debugLogger.warn(
|
|
488
460
|
`Workflow result revival failed at index ${idx}: ${reason}; slot set to null (non-JSON-serializable thunk return).`
|
|
489
461
|
);
|
|
490
462
|
}, "logRevivalFailure"),
|
|
463
|
+
// --- Unconsumed-rejection mirror bookkeeping ---
|
|
464
|
+
wfRegisterRoot: /* @__PURE__ */ __name(() => {
|
|
465
|
+
const id = nextUnconsumedId++;
|
|
466
|
+
unconsumedRoots.set(id, { rejectionHandled: false, adoptedOut: false });
|
|
467
|
+
return id;
|
|
468
|
+
}, "wfRegisterRoot"),
|
|
469
|
+
wfMarkRejectionHandled: /* @__PURE__ */ __name((rootId) => {
|
|
470
|
+
const root = unconsumedRoots.get(rootId);
|
|
471
|
+
if (root) root.rejectionHandled = true;
|
|
472
|
+
}, "wfMarkRejectionHandled"),
|
|
473
|
+
wfIsRootHandled: /* @__PURE__ */ __name((rootId) => unconsumedRoots.get(rootId)?.rejectionHandled === true, "wfIsRootHandled"),
|
|
474
|
+
wfMarkAdopted: /* @__PURE__ */ __name((rootId) => {
|
|
475
|
+
const root = unconsumedRoots.get(rootId);
|
|
476
|
+
if (root) root.adoptedOut = true;
|
|
477
|
+
}, "wfMarkAdopted"),
|
|
478
|
+
runId: opts.runId ?? "",
|
|
479
|
+
wfReportUnconsumed: /* @__PURE__ */ __name((rootId, isRoot, dispatchFailed, msg) => {
|
|
480
|
+
if (unconsumedSettled) {
|
|
481
|
+
const rec = {
|
|
482
|
+
rootId,
|
|
483
|
+
isRoot,
|
|
484
|
+
dispatchFailed,
|
|
485
|
+
msg
|
|
486
|
+
};
|
|
487
|
+
const rootState = unconsumedRoots.get(rootId);
|
|
488
|
+
if (!rootState?.rejectionHandled && !(dispatchFailed && rootState?.adoptedOut)) {
|
|
489
|
+
safeLog(unconsumedRejectionLine(rec));
|
|
490
|
+
}
|
|
491
|
+
return 0;
|
|
492
|
+
}
|
|
493
|
+
const id = nextUnconsumedId++;
|
|
494
|
+
unconsumedRejections.set(id, { rootId, isRoot, dispatchFailed, msg });
|
|
495
|
+
return id;
|
|
496
|
+
}, "wfReportUnconsumed"),
|
|
497
|
+
wfClearUnconsumed: /* @__PURE__ */ __name((id) => {
|
|
498
|
+
unconsumedRejections.delete(id);
|
|
499
|
+
}, "wfClearUnconsumed"),
|
|
500
|
+
// R10-1: teardown discrimination cannot key on the error name alone.
|
|
501
|
+
// The dominant in-flight cancellation path (controller.abort() →
|
|
502
|
+
// subagent returns terminateMode=CANCELLED → runSingleDispatch throws
|
|
503
|
+
// a PLAIN Error) never produces an 'AbortError', so the mirror would
|
|
504
|
+
// log a spurious dispatch failure for a correctly-cancelled run. Once
|
|
505
|
+
// the run's abort signal has fired, the run is already settling as
|
|
506
|
+
// cancelled / timed-out — every rejection still crossing the boundary
|
|
507
|
+
// is teardown noise regardless of its shape.
|
|
508
|
+
isRunAborted: /* @__PURE__ */ __name(() => opts.abortOnTimeout?.signal.aborted === true, "isRunAborted"),
|
|
491
509
|
// The truthy flags distinguish "injected" from "default stub" inside the
|
|
492
510
|
// init script without leaking the host function itself when not used.
|
|
493
511
|
hasParallel: !!opts.parallel,
|
|
@@ -555,27 +573,318 @@ function createWorkflowSandbox(opts) {
|
|
|
555
573
|
// those wrappers will produce vm-realm results); reject with a
|
|
556
574
|
// freshly-constructed vm-realm Error so e.constructor.constructor
|
|
557
575
|
// stays in the vm realm.
|
|
576
|
+
// Dispatch promises are ObservedPromise instances (a vm-realm
|
|
577
|
+
// Promise subclass). Its then override marks the result consumed
|
|
578
|
+
// and re-attaches the teardown observer to the derived promise, so
|
|
579
|
+
// script-derived chains (agent(...).then(...), await, and the
|
|
580
|
+
// ELEMENTS of static-combinator aggregates \u2014 everything that
|
|
581
|
+
// funnels through then) stay observed at every depth. The
|
|
582
|
+
// AGGREGATES of Promise.all/race/any are built by the native
|
|
583
|
+
// statics and never pass through the observed then, so those
|
|
584
|
+
// statics are wrapped explicitly below (observeAggregate).
|
|
585
|
+
// Without this, a correctly-cancelled run holding a pending derived
|
|
586
|
+
// chain fired a process-level unhandledRejection even though the
|
|
587
|
+
// bare dispatch promise was observed.
|
|
588
|
+
//
|
|
589
|
+
// Unconsumed rejections of an observed node are recorded through
|
|
590
|
+
// the bridge and mirrored into the run log at run settlement (a
|
|
591
|
+
// later consumption clears the record first) \u2014 a dispatch refused
|
|
592
|
+
// at the entry gate (budget / agent cap) or failing mid-run reaches
|
|
593
|
+
// no other surface, so without the mirror the failure leaves no
|
|
594
|
+
// log, alarm, or telemetry.
|
|
595
|
+
function mapDispatchError(hostErr) {
|
|
596
|
+
var msg;
|
|
597
|
+
try {
|
|
598
|
+
msg = (hostErr && hostErr.message != null)
|
|
599
|
+
? String(hostErr.message)
|
|
600
|
+
: String(hostErr);
|
|
601
|
+
} catch (e) {
|
|
602
|
+
msg = '[unserializable rejection value]';
|
|
603
|
+
}
|
|
604
|
+
const vmErr = new Error(msg);
|
|
605
|
+
// Teardown discrimination at the host boundary \u2014 before the error
|
|
606
|
+
// is flattened into a vm-realm Error. Two shapes count as
|
|
607
|
+
// teardown: an error NAMED 'AbortError' (the scheduler's
|
|
608
|
+
// abortError() DOMException), and ANY rejection that crosses
|
|
609
|
+
// after the run's abort signal has fired \u2014 the dominant
|
|
610
|
+
// cancellation path rejects with a plain Error ('did not complete
|
|
611
|
+
// (terminate mode: CANCELLED).'), which a name-only match would
|
|
612
|
+
// mirror as a spurious dispatch failure on a correctly-cancelled
|
|
613
|
+
// run. Matching the name here (rather than the message text)
|
|
614
|
+
// still suppresses teardown noise without swallowing genuine
|
|
615
|
+
// failures whose message merely contains 'aborted' (e.g. a
|
|
616
|
+
// network-layer 'connection aborted by peer').
|
|
617
|
+
var isAbort = false;
|
|
618
|
+
try {
|
|
619
|
+
isAbort = !!(hostErr && hostErr.name === 'AbortError');
|
|
620
|
+
} catch (e) {
|
|
621
|
+
isAbort = false;
|
|
622
|
+
}
|
|
623
|
+
if (isAbort || __b.isRunAborted()) vmErr.__wfAbort = true;
|
|
624
|
+
vmErr.__wfDispatchFailed = true;
|
|
625
|
+
return vmErr;
|
|
626
|
+
}
|
|
627
|
+
function readFlag(value, name) {
|
|
628
|
+
try {
|
|
629
|
+
return !!(value && value[name]);
|
|
630
|
+
} catch (e) {
|
|
631
|
+
return false;
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
function observeDispatch(promise) {
|
|
635
|
+
// Direct native-then call: routing through ObservedPromise.then
|
|
636
|
+
// would mark the promise consumed and recurse the observer. The
|
|
637
|
+
// observer body must be exception-safe on ANY rejection value:
|
|
638
|
+
// a script handler can throw an exotic value (a message getter
|
|
639
|
+
// that throws, a Proxy with throwing traps), and an observer
|
|
640
|
+
// killed mid-body would turn the very rejection it watches into
|
|
641
|
+
// a process-level unhandledRejection \u2014 the exact failure class
|
|
642
|
+
// the observer exists to remove.
|
|
643
|
+
Promise.prototype.then.call(promise, undefined, function (err) {
|
|
644
|
+
if (promise.__wfConsumed) return;
|
|
645
|
+
// R11-30: also suppress on the run-level abort state, not just
|
|
646
|
+
// the rejection's own marker \u2014 a wrapped Promise.any aggregate
|
|
647
|
+
// rejects with a natively built AggregateError that carries
|
|
648
|
+
// neither marker, so teardown rejections of a correctly-
|
|
649
|
+
// cancelled run would still be mirrored when it is unconsumed.
|
|
650
|
+
if (readFlag(err, '__wfAbort') || __b.isRunAborted()) return;
|
|
651
|
+
var dispatchFailed = readFlag(err, '__wfDispatchFailed');
|
|
652
|
+
var errors = null;
|
|
653
|
+
try {
|
|
654
|
+
if (err && Array.isArray(err.errors)) errors = err.errors;
|
|
655
|
+
} catch (e) {
|
|
656
|
+
errors = null;
|
|
657
|
+
}
|
|
658
|
+
if (!dispatchFailed && errors) {
|
|
659
|
+
// R11-4: Promise.any rejects with a fresh vm-realm
|
|
660
|
+
// AggregateError carrying no flags; the element errors are
|
|
661
|
+
// reachable on .errors with their markers preserved. Derive
|
|
662
|
+
// the attribution from the causes instead of blaming the
|
|
663
|
+
// script for a dispatch failure.
|
|
664
|
+
for (var i = 0; i < errors.length; i++) {
|
|
665
|
+
if (readFlag(errors[i], '__wfDispatchFailed')) {
|
|
666
|
+
dispatchFailed = true;
|
|
667
|
+
break;
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
// R11-15: cross-root suppression \u2014 aggregate roots track
|
|
672
|
+
// rejectionHandled independently of their elements' roots, so
|
|
673
|
+
// a forwarded dispatch failure whose originating element root
|
|
674
|
+
// the script already handled must not mirror from the
|
|
675
|
+
// aggregate. The element rootId is stamped in vmAsync;
|
|
676
|
+
// Promise.all/race forward the element's own reason,
|
|
677
|
+
// Promise.any surfaces them on .errors.
|
|
678
|
+
try {
|
|
679
|
+
var sourceIds = [];
|
|
680
|
+
if (err && err.__wfRootId) {
|
|
681
|
+
sourceIds.push(err.__wfRootId);
|
|
682
|
+
} else if (errors) {
|
|
683
|
+
for (var j = 0; j < errors.length; j++) {
|
|
684
|
+
if (errors[j] && errors[j].__wfRootId) {
|
|
685
|
+
sourceIds.push(errors[j].__wfRootId);
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
for (var k = 0; k < sourceIds.length; k++) {
|
|
690
|
+
if (
|
|
691
|
+
sourceIds[k] !== promise.__wfRootId &&
|
|
692
|
+
__b.wfIsRootHandled(sourceIds[k])
|
|
693
|
+
) {
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
} catch (e) {
|
|
698
|
+
// A throwing exotic value must not kill the observer; fall
|
|
699
|
+
// through and mirror conservatively.
|
|
700
|
+
}
|
|
701
|
+
var msg;
|
|
702
|
+
try {
|
|
703
|
+
msg = String(err && err.message != null ? err.message : err);
|
|
704
|
+
} catch (e) {
|
|
705
|
+
msg = '[unserializable rejection value]';
|
|
706
|
+
}
|
|
707
|
+
promise.__wfUnconsumedId = __b.wfReportUnconsumed(
|
|
708
|
+
promise.__wfRootId,
|
|
709
|
+
promise.__wfIsRoot === true,
|
|
710
|
+
dispatchFailed,
|
|
711
|
+
msg,
|
|
712
|
+
);
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
// R11-3: await / Promise.resolve / returning a thenable from a
|
|
716
|
+
// handler adopts an ObservedPromise through this then with the
|
|
717
|
+
// adopting promise's capability (resolve, reject) pair \u2014 native
|
|
718
|
+
// functions, indistinguishable from real handlers by arity. They
|
|
719
|
+
// are detected by the native toString signature. Adoption
|
|
720
|
+
// CONSUMES the result (a delayed adoption clears a recorded
|
|
721
|
+
// verdict exactly like a delayed await) but is NOT a rejection
|
|
722
|
+
// handler: the rejection transfers into the adopting promise \u2014
|
|
723
|
+
// typically an async wrapper's implicit promise, which is a plain
|
|
724
|
+
// vm-realm Promise the mirror cannot observe. Marking adoption as
|
|
725
|
+
// handling would silently disarm the mirror for the forgotten-
|
|
726
|
+
// await failure class; the run-level escape hook in the host
|
|
727
|
+
// surfaces those escapes instead. Bound script functions also
|
|
728
|
+
// stringify as native code; misreading one as adoption only
|
|
729
|
+
// forgoes the rejectionHandled marking, never native semantics.
|
|
730
|
+
function isAdoptionAttach(handler) {
|
|
731
|
+
try {
|
|
732
|
+
return (
|
|
733
|
+
typeof handler === 'function' &&
|
|
734
|
+
Function.prototype.toString
|
|
735
|
+
.call(handler)
|
|
736
|
+
.indexOf('[native code]') !== -1
|
|
737
|
+
);
|
|
738
|
+
} catch (e) {
|
|
739
|
+
return false;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
class ObservedPromise extends Promise {
|
|
743
|
+
then(onFulfilled, onRejected) {
|
|
744
|
+
// R11-26: introspect the handler BEFORE any state mutation.
|
|
745
|
+
// The read is guarded because a script-supplied handler can
|
|
746
|
+
// be exotic (a revoked Proxy wrapping a function, a throwing
|
|
747
|
+
// accessor) \u2014 an unguarded read made .then() throw
|
|
748
|
+
// synchronously, something native then never does, leaving
|
|
749
|
+
// the promise marked consumed with no handler attached.
|
|
750
|
+
var rethrows = false;
|
|
751
|
+
try {
|
|
752
|
+
rethrows = !!(onRejected && onRejected.__wfRethrows);
|
|
753
|
+
} catch (e) {
|
|
754
|
+
rethrows = false;
|
|
755
|
+
}
|
|
756
|
+
this.__wfConsumed = true;
|
|
757
|
+
// An attached rejection handler means the script can surface the
|
|
758
|
+
// root rejection itself; the mirror stays silent for it. The
|
|
759
|
+
// finally override below routes through this then with marked
|
|
760
|
+
// rethrow combinators \u2014 those re-raise the rejection instead of
|
|
761
|
+
// handling it, so they must NOT set the flag (marking them
|
|
762
|
+
// handled would silently drop a fire-and-forget
|
|
763
|
+
// agent(...).finally(...) failure). Adoption attaches count
|
|
764
|
+
// as consumption only, never handling (see isAdoptionAttach):
|
|
765
|
+
// they mark adoptedOut so forwarded sibling entries defer to
|
|
766
|
+
// the adopting chain / escape hook instead of mirroring.
|
|
767
|
+
if (isAdoptionAttach(onRejected)) {
|
|
768
|
+
__b.wfMarkAdopted(this.__wfRootId);
|
|
769
|
+
} else if (typeof onRejected === 'function' && !rethrows) {
|
|
770
|
+
__b.wfMarkRejectionHandled(this.__wfRootId);
|
|
771
|
+
}
|
|
772
|
+
// A delayed consumption clears a verdict recorded at
|
|
773
|
+
// rejection-settlement time, so a late-but-real await is not
|
|
774
|
+
// misreported as unconsumed.
|
|
775
|
+
if (this.__wfUnconsumedId !== undefined) {
|
|
776
|
+
__b.wfClearUnconsumed(this.__wfUnconsumedId);
|
|
777
|
+
this.__wfUnconsumedId = undefined;
|
|
778
|
+
}
|
|
779
|
+
const derived = super.then(onFulfilled, onRejected);
|
|
780
|
+
derived.__wfRootId = this.__wfRootId;
|
|
781
|
+
observeDispatch(derived);
|
|
782
|
+
return derived;
|
|
783
|
+
}
|
|
784
|
+
finally(onFinally) {
|
|
785
|
+
// Native Promise.prototype.finally calls the observed then with
|
|
786
|
+
// two function combinators, indistinguishable there from a real
|
|
787
|
+
// then(f, g) \u2014 which would mark the root rejection handled even
|
|
788
|
+
// though finally rethrows it. Implement finally through the
|
|
789
|
+
// observed then with an explicitly-marked rethrow combinator so
|
|
790
|
+
// the mirror stays armed for finally-only chains.
|
|
791
|
+
if (typeof onFinally !== 'function') {
|
|
792
|
+
return this.then(undefined, undefined);
|
|
793
|
+
}
|
|
794
|
+
const onRethrow = function (err) {
|
|
795
|
+
return Promise.resolve(onFinally()).then(function () {
|
|
796
|
+
throw err;
|
|
797
|
+
});
|
|
798
|
+
};
|
|
799
|
+
onRethrow.__wfRethrows = true;
|
|
800
|
+
return this.then(
|
|
801
|
+
function (value) {
|
|
802
|
+
return Promise.resolve(onFinally()).then(function () {
|
|
803
|
+
return value;
|
|
804
|
+
});
|
|
805
|
+
},
|
|
806
|
+
onRethrow,
|
|
807
|
+
);
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
// --- Static combinators: observe the aggregate promise ---
|
|
811
|
+
// Promise.all/race/any build their aggregate via the native static;
|
|
812
|
+
// it never passes through the observed then, so a fire-and-forget
|
|
813
|
+
// aggregate holding a failed dispatch would escape the run-log
|
|
814
|
+
// mirror. While the run is live the host's adoption-escape hook
|
|
815
|
+
// (R11-3) still catches and mirrors the process-level
|
|
816
|
+
// unhandledRejection \u2014 a round-14 A/B confirmed that hook, not
|
|
817
|
+
// this wrap, is the live-run backstop \u2014 but only with the coarse
|
|
818
|
+
// '(rejection not handled)' wording, and once the run's hook is
|
|
819
|
+
// detached nothing in the sandbox catches the escape. R14-A:
|
|
820
|
+
// wrapping the statics gives each aggregate its own observer, so
|
|
821
|
+
// consumption tracking works through the aggregate's own observed
|
|
822
|
+
// then (await / .catch / .then marks it handled) and the mirror
|
|
823
|
+
// itself classifies the rejection; the elements still funnel
|
|
824
|
+
// through the then override via the native static's internal
|
|
825
|
+
// attach, so they stay marked consumed.
|
|
826
|
+
function observeAggregate(nativeAggregate) {
|
|
827
|
+
const rootId = __b.wfRegisterRoot();
|
|
828
|
+
const observed = new ObservedPromise(function (resolve, reject) {
|
|
829
|
+
Promise.prototype.then.call(nativeAggregate, resolve, reject);
|
|
830
|
+
});
|
|
831
|
+
observed.__wfRootId = rootId;
|
|
832
|
+
observed.__wfIsRoot = true;
|
|
833
|
+
observeDispatch(observed);
|
|
834
|
+
return observed;
|
|
835
|
+
}
|
|
836
|
+
const nativePromiseAll = Promise.all;
|
|
837
|
+
const nativePromiseRace = Promise.race;
|
|
838
|
+
const nativePromiseAny = Promise.any;
|
|
839
|
+
// R11-16: a static called on a script-defined Promise subclass
|
|
840
|
+
// must honor the species contract and return a subclass instance,
|
|
841
|
+
// so non-default receivers bypass observation (their elements
|
|
842
|
+
// still funnel through the observed then, and a fire-and-forget
|
|
843
|
+
// dispatch failure escaping such an aggregate is still caught by
|
|
844
|
+
// the host's adoption-escape hook via its stamped markers).
|
|
845
|
+
Promise.all = function (items) {
|
|
846
|
+
if (this !== Promise) return nativePromiseAll.call(this, items);
|
|
847
|
+
return observeAggregate(nativePromiseAll.call(this, items));
|
|
848
|
+
};
|
|
849
|
+
Promise.race = function (items) {
|
|
850
|
+
if (this !== Promise) return nativePromiseRace.call(this, items);
|
|
851
|
+
return observeAggregate(nativePromiseRace.call(this, items));
|
|
852
|
+
};
|
|
853
|
+
Promise.any = function (items) {
|
|
854
|
+
if (this !== Promise) return nativePromiseAny.call(this, items);
|
|
855
|
+
return observeAggregate(nativePromiseAny.call(this, items));
|
|
856
|
+
};
|
|
558
857
|
function vmAsync(hostFn) {
|
|
559
858
|
return function (...vmArgs) {
|
|
560
|
-
|
|
859
|
+
const rootId = __b.wfRegisterRoot();
|
|
860
|
+
const p = new ObservedPromise(function (resolve, reject) {
|
|
861
|
+
function rejectMapped(hostErr) {
|
|
862
|
+
const vmErr = mapDispatchError(hostErr);
|
|
863
|
+
// Stamp the originating root and run BEFORE the error can
|
|
864
|
+
// be forwarded into aggregate promises: the observer's
|
|
865
|
+
// cross-root suppression (R11-15) reads __wfRootId and
|
|
866
|
+
// the host's adoption-escape hook (R11-3) attributes by
|
|
867
|
+
// __wfRunId.
|
|
868
|
+
try {
|
|
869
|
+
vmErr.__wfRootId = rootId;
|
|
870
|
+
vmErr.__wfRunId = __b.runId;
|
|
871
|
+
} catch (e) {}
|
|
872
|
+
reject(vmErr);
|
|
873
|
+
}
|
|
561
874
|
try {
|
|
562
875
|
const hostPromise = hostFn.apply(null, vmArgs);
|
|
563
876
|
hostPromise.then(
|
|
564
877
|
function (value) { resolve(value); },
|
|
565
|
-
|
|
566
|
-
const msg = (hostErr && hostErr.message != null)
|
|
567
|
-
? String(hostErr.message)
|
|
568
|
-
: String(hostErr);
|
|
569
|
-
reject(new Error(msg));
|
|
570
|
-
}
|
|
878
|
+
rejectMapped
|
|
571
879
|
);
|
|
572
880
|
} catch (hostErr) {
|
|
573
|
-
|
|
574
|
-
? String(hostErr.message)
|
|
575
|
-
: String(hostErr);
|
|
576
|
-
reject(new Error(msg));
|
|
881
|
+
rejectMapped(hostErr);
|
|
577
882
|
}
|
|
578
883
|
});
|
|
884
|
+
p.__wfRootId = rootId;
|
|
885
|
+
p.__wfIsRoot = true;
|
|
886
|
+
observeDispatch(p);
|
|
887
|
+
return p;
|
|
579
888
|
};
|
|
580
889
|
}
|
|
581
890
|
|
|
@@ -873,46 +1182,208 @@ function createWorkflowSandbox(opts) {
|
|
|
873
1182
|
{ filename: "workflow-sandbox-init.js" }
|
|
874
1183
|
);
|
|
875
1184
|
const maxWallClockMs = resolveMaxWallClockMs(opts);
|
|
1185
|
+
const flushUnconsumedRejections = /* @__PURE__ */ __name(async () => {
|
|
1186
|
+
unconsumedSettled = true;
|
|
1187
|
+
if (nextUnconsumedId === 1) return;
|
|
1188
|
+
await new Promise((resolve) => {
|
|
1189
|
+
setImmediate(resolve);
|
|
1190
|
+
});
|
|
1191
|
+
for (const rec of unconsumedRejections.values()) {
|
|
1192
|
+
const rootState = unconsumedRoots.get(rec.rootId);
|
|
1193
|
+
if (rootState?.rejectionHandled) {
|
|
1194
|
+
continue;
|
|
1195
|
+
}
|
|
1196
|
+
if (rec.dispatchFailed && rootState?.adoptedOut) {
|
|
1197
|
+
continue;
|
|
1198
|
+
}
|
|
1199
|
+
const key = rec.rootId + "\0" + rec.msg;
|
|
1200
|
+
if (mirroredEscapeKeys.has(key)) continue;
|
|
1201
|
+
mirroredEscapeKeys.add(key);
|
|
1202
|
+
safeLog(unconsumedRejectionLine(rec));
|
|
1203
|
+
}
|
|
1204
|
+
unconsumedRejections.clear();
|
|
1205
|
+
}, "flushUnconsumedRejections");
|
|
1206
|
+
const hookRunId = opts.runId ?? "";
|
|
1207
|
+
const adoptionEscapeHook = /* @__PURE__ */ __name((reason, _promise) => {
|
|
1208
|
+
try {
|
|
1209
|
+
if (!reason || typeof reason !== "object") return;
|
|
1210
|
+
const marked = reason;
|
|
1211
|
+
if (marked.__wfDispatchFailed !== true) return;
|
|
1212
|
+
if (String(marked.__wfRunId ?? "") !== hookRunId) return;
|
|
1213
|
+
const rootId = typeof marked.__wfRootId === "number" ? marked.__wfRootId : void 0;
|
|
1214
|
+
if (rootId !== void 0 && unconsumedRoots.get(rootId)?.rejectionHandled) {
|
|
1215
|
+
return;
|
|
1216
|
+
}
|
|
1217
|
+
let msg;
|
|
1218
|
+
try {
|
|
1219
|
+
msg = marked.message != null ? String(marked.message) : String(reason);
|
|
1220
|
+
} catch {
|
|
1221
|
+
msg = "[unserializable rejection value]";
|
|
1222
|
+
}
|
|
1223
|
+
const key = String(rootId ?? "") + "\0" + msg;
|
|
1224
|
+
if (mirroredEscapeKeys.has(key)) return;
|
|
1225
|
+
mirroredEscapeKeys.add(key);
|
|
1226
|
+
safeLog("dispatch failed (rejection not handled): " + msg);
|
|
1227
|
+
} catch (e) {
|
|
1228
|
+
debugLogger.warn("adoptionEscapeHook failed:", e);
|
|
1229
|
+
}
|
|
1230
|
+
}, "adoptionEscapeHook");
|
|
876
1231
|
let extractedMeta = null;
|
|
877
1232
|
return {
|
|
878
1233
|
async run(scriptSource) {
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
1234
|
+
unconsumedSettled = false;
|
|
1235
|
+
unconsumedRoots.clear();
|
|
1236
|
+
unconsumedRejections.clear();
|
|
1237
|
+
nextUnconsumedId = 1;
|
|
1238
|
+
mirroredEscapeKeys = /* @__PURE__ */ new Set();
|
|
1239
|
+
let watchdog;
|
|
1240
|
+
let stopWatchingState;
|
|
1241
|
+
let rearmWatchdogOnAbort;
|
|
1242
|
+
process.on("unhandledRejection", adoptionEscapeHook);
|
|
1243
|
+
try {
|
|
1244
|
+
const { stripped, meta } = extractAndStripMeta(scriptSource);
|
|
1245
|
+
extractedMeta = meta;
|
|
1246
|
+
const wrapped = `(async () => {
|
|
882
1247
|
${stripped}
|
|
883
1248
|
})()`;
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
)
|
|
899
|
-
);
|
|
900
|
-
}
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
1249
|
+
const script = new vm.Script(wrapped, {
|
|
1250
|
+
filename: "workflow.js"
|
|
1251
|
+
});
|
|
1252
|
+
const runOpts = {
|
|
1253
|
+
timeout: 3e4
|
|
1254
|
+
};
|
|
1255
|
+
const result = script.runInContext(ctx, runOpts);
|
|
1256
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
1257
|
+
watchdog = new WallClockWatchdog(maxWallClockMs, () => {
|
|
1258
|
+
opts.abortOnTimeout?.abort();
|
|
1259
|
+
reject(
|
|
1260
|
+
new Error(
|
|
1261
|
+
`Workflow execution exceeded ${maxWallClockMs} ms of active time (paused time is not counted). Override via SandboxOptions.maxWallClockMs or QWEN_CODE_MAX_WORKFLOW_SECONDS env var.`
|
|
1262
|
+
)
|
|
1263
|
+
);
|
|
1264
|
+
});
|
|
1265
|
+
});
|
|
1266
|
+
const aborted = /* @__PURE__ */ __name(() => opts.abortOnTimeout?.signal.aborted === true, "aborted");
|
|
1267
|
+
stopWatchingState = opts.scheduler?.onStateChange(({ state }) => {
|
|
1268
|
+
if (state === "paused" && !aborted()) watchdog?.pause();
|
|
1269
|
+
else watchdog?.resume();
|
|
1270
|
+
});
|
|
1271
|
+
if (opts.scheduler?.snapshot().state === "paused" && !aborted()) {
|
|
1272
|
+
watchdog?.pause();
|
|
1273
|
+
}
|
|
1274
|
+
rearmWatchdogOnAbort = /* @__PURE__ */ __name(() => watchdog?.resume(), "rearmWatchdogOnAbort");
|
|
1275
|
+
opts.abortOnTimeout?.signal.addEventListener(
|
|
1276
|
+
"abort",
|
|
1277
|
+
rearmWatchdogOnAbort,
|
|
1278
|
+
{ once: true }
|
|
1279
|
+
);
|
|
904
1280
|
return await Promise.race([result, timeoutPromise]);
|
|
905
1281
|
} finally {
|
|
906
|
-
if (
|
|
1282
|
+
if (rearmWatchdogOnAbort) {
|
|
1283
|
+
opts.abortOnTimeout?.signal.removeEventListener(
|
|
1284
|
+
"abort",
|
|
1285
|
+
rearmWatchdogOnAbort
|
|
1286
|
+
);
|
|
1287
|
+
}
|
|
1288
|
+
stopWatchingState?.();
|
|
1289
|
+
watchdog?.stop();
|
|
1290
|
+
await flushUnconsumedRejections();
|
|
1291
|
+
process.off("unhandledRejection", adoptionEscapeHook);
|
|
907
1292
|
}
|
|
908
1293
|
},
|
|
909
1294
|
getPhases: /* @__PURE__ */ __name(() => [...phases], "getPhases"),
|
|
910
1295
|
getLogs: /* @__PURE__ */ __name(() => [...logs], "getLogs"),
|
|
1296
|
+
appendLog: /* @__PURE__ */ __name((line) => safeLog(line), "appendLog"),
|
|
911
1297
|
getMeta: /* @__PURE__ */ __name(() => extractedMeta, "getMeta")
|
|
912
1298
|
};
|
|
913
1299
|
}
|
|
914
1300
|
__name(createWorkflowSandbox, "createWorkflowSandbox");
|
|
915
1301
|
|
|
1302
|
+
// packages/core/src/agents/runtime/workflow-budget.ts
|
|
1303
|
+
init_esbuild_shims();
|
|
1304
|
+
var debugLogger2 = createDebugLogger("WORKFLOW_BUDGET");
|
|
1305
|
+
var MAX_TOKENS_PER_WORKFLOW_ENV = "QWEN_CODE_MAX_TOKENS_PER_WORKFLOW";
|
|
1306
|
+
var HARD_MAX_TOKENS_CEILING = 1e8;
|
|
1307
|
+
function resolveMaxTokensPerWorkflow(env = process.env) {
|
|
1308
|
+
const raw = env[MAX_TOKENS_PER_WORKFLOW_ENV];
|
|
1309
|
+
if (raw === void 0 || raw.trim() === "") {
|
|
1310
|
+
return null;
|
|
1311
|
+
}
|
|
1312
|
+
const parsed = parsePositiveIntegerEnv(raw, 0);
|
|
1313
|
+
if (parsed < 1) {
|
|
1314
|
+
debugLogger2.warn(
|
|
1315
|
+
`Invalid ${MAX_TOKENS_PER_WORKFLOW_ENV}=${JSON.stringify(raw)}, treating as unset (no cap)`
|
|
1316
|
+
);
|
|
1317
|
+
return null;
|
|
1318
|
+
}
|
|
1319
|
+
if (parsed > HARD_MAX_TOKENS_CEILING) {
|
|
1320
|
+
debugLogger2.warn(
|
|
1321
|
+
`${MAX_TOKENS_PER_WORKFLOW_ENV}=${parsed} exceeds hard ceiling (${HARD_MAX_TOKENS_CEILING}); clamping.`
|
|
1322
|
+
);
|
|
1323
|
+
return HARD_MAX_TOKENS_CEILING;
|
|
1324
|
+
}
|
|
1325
|
+
return parsed;
|
|
1326
|
+
}
|
|
1327
|
+
__name(resolveMaxTokensPerWorkflow, "resolveMaxTokensPerWorkflow");
|
|
1328
|
+
var WorkflowBudgetImpl = class _WorkflowBudgetImpl {
|
|
1329
|
+
static {
|
|
1330
|
+
__name(this, "WorkflowBudgetImpl");
|
|
1331
|
+
}
|
|
1332
|
+
total;
|
|
1333
|
+
_spent;
|
|
1334
|
+
constructor(total) {
|
|
1335
|
+
this.total = total;
|
|
1336
|
+
this._spent = 0;
|
|
1337
|
+
}
|
|
1338
|
+
spent() {
|
|
1339
|
+
return this._spent;
|
|
1340
|
+
}
|
|
1341
|
+
remaining() {
|
|
1342
|
+
if (this.total === null) return Infinity;
|
|
1343
|
+
return Math.max(0, this.total - this._spent);
|
|
1344
|
+
}
|
|
1345
|
+
/**
|
|
1346
|
+
* Host-side increment. NOT exposed to the script — the
|
|
1347
|
+
* `WorkflowBudget` interface deliberately omits any setter so a
|
|
1348
|
+
* malicious workflow cannot inflate / deflate the budget. Only the
|
|
1349
|
+
* orchestrator (in `countedDispatch`) calls this after a dispatch
|
|
1350
|
+
* resolves with the agent's output token count.
|
|
1351
|
+
*
|
|
1352
|
+
* Non-positive deltas are silently dropped (some dispatches return
|
|
1353
|
+
* `output_tokens: 0` on early failures); negative deltas would be a
|
|
1354
|
+
* caller bug and are also dropped rather than silently rewinding
|
|
1355
|
+
* the counter.
|
|
1356
|
+
*/
|
|
1357
|
+
recordSpent(deltaTokens) {
|
|
1358
|
+
if (!Number.isFinite(deltaTokens) || deltaTokens <= 0) return;
|
|
1359
|
+
this._spent += deltaTokens;
|
|
1360
|
+
}
|
|
1361
|
+
/**
|
|
1362
|
+
* Factory: build a budget from the current environment. Convenience
|
|
1363
|
+
* over `new WorkflowBudgetImpl(resolveMaxTokensPerWorkflow(env))`.
|
|
1364
|
+
*/
|
|
1365
|
+
static fromEnv(env = process.env) {
|
|
1366
|
+
return new _WorkflowBudgetImpl(resolveMaxTokensPerWorkflow(env));
|
|
1367
|
+
}
|
|
1368
|
+
};
|
|
1369
|
+
var WorkflowBudgetExceededError = class extends Error {
|
|
1370
|
+
static {
|
|
1371
|
+
__name(this, "WorkflowBudgetExceededError");
|
|
1372
|
+
}
|
|
1373
|
+
name = "WorkflowBudgetExceededError";
|
|
1374
|
+
runId;
|
|
1375
|
+
budgetTotal;
|
|
1376
|
+
spent;
|
|
1377
|
+
constructor(runId, budgetTotal, spent) {
|
|
1378
|
+
super(
|
|
1379
|
+
`Workflow ${runId} exceeded the token budget (${spent} / ${budgetTotal} output tokens spent).`
|
|
1380
|
+
);
|
|
1381
|
+
this.runId = runId;
|
|
1382
|
+
this.budgetTotal = budgetTotal;
|
|
1383
|
+
this.spent = spent;
|
|
1384
|
+
}
|
|
1385
|
+
};
|
|
1386
|
+
|
|
916
1387
|
// packages/core/src/agents/runtime/workflow-stall.ts
|
|
917
1388
|
init_esbuild_shims();
|
|
918
1389
|
var DEFAULT_STALL_MS = 6e4;
|
|
@@ -1144,58 +1615,122 @@ init_esbuild_shims();
|
|
|
1144
1615
|
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.';
|
|
1145
1616
|
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.";
|
|
1146
1617
|
|
|
1147
|
-
// packages/core/src/
|
|
1618
|
+
// packages/core/src/agents/runtime/workflow-dispatch-scheduler.ts
|
|
1148
1619
|
init_esbuild_shims();
|
|
1149
1620
|
function abortError() {
|
|
1150
|
-
return new DOMException("
|
|
1621
|
+
return new DOMException("Workflow dispatch scheduler aborted.", "AbortError");
|
|
1151
1622
|
}
|
|
1152
1623
|
__name(abortError, "abortError");
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
)
|
|
1624
|
+
var WorkflowDispatchScheduler = class {
|
|
1625
|
+
constructor(limit, signal, onStateChange) {
|
|
1626
|
+
this.limit = limit;
|
|
1627
|
+
this.signal = signal;
|
|
1628
|
+
if (!Number.isInteger(limit) || limit < 1) {
|
|
1629
|
+
throw new Error(
|
|
1630
|
+
`Workflow dispatch limit must be a positive integer, got ${String(limit)}.`
|
|
1631
|
+
);
|
|
1632
|
+
}
|
|
1633
|
+
if (onStateChange) this.stateListeners.add(onStateChange);
|
|
1634
|
+
if (signal && !signal.aborted) {
|
|
1635
|
+
signal.addEventListener("abort", () => this.abortPending(), {
|
|
1636
|
+
once: true
|
|
1637
|
+
});
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1640
|
+
static {
|
|
1641
|
+
__name(this, "WorkflowDispatchScheduler");
|
|
1642
|
+
}
|
|
1643
|
+
state = "running";
|
|
1644
|
+
inFlight = 0;
|
|
1645
|
+
queue = [];
|
|
1646
|
+
gateWaiters = [];
|
|
1647
|
+
stateListeners = /* @__PURE__ */ new Set();
|
|
1648
|
+
/**
|
|
1649
|
+
* Subscribe to state transitions. Returns an unsubscribe function.
|
|
1650
|
+
* The constructor callback (when given) is registered as the first
|
|
1651
|
+
* listener; this method lets additional observers — e.g. the sandbox's
|
|
1652
|
+
* pause-aware wall-clock watchdog — hook the same transitions.
|
|
1653
|
+
*/
|
|
1654
|
+
onStateChange(listener) {
|
|
1655
|
+
this.stateListeners.add(listener);
|
|
1656
|
+
return () => {
|
|
1657
|
+
this.stateListeners.delete(listener);
|
|
1658
|
+
};
|
|
1659
|
+
}
|
|
1660
|
+
run(thunk) {
|
|
1661
|
+
return new Promise((resolve, reject) => {
|
|
1662
|
+
if (this.signal?.aborted) {
|
|
1663
|
+
reject(abortError());
|
|
1664
|
+
return;
|
|
1665
|
+
}
|
|
1666
|
+
this.queue.push({
|
|
1667
|
+
thunk,
|
|
1668
|
+
resolve,
|
|
1669
|
+
reject
|
|
1670
|
+
});
|
|
1671
|
+
this.pump();
|
|
1672
|
+
});
|
|
1673
|
+
}
|
|
1674
|
+
pause() {
|
|
1675
|
+
if (this.state !== "running" || this.signal?.aborted) return false;
|
|
1676
|
+
this.setState("pausing");
|
|
1677
|
+
if (this.inFlight === 0) this.setState("paused");
|
|
1678
|
+
return true;
|
|
1679
|
+
}
|
|
1680
|
+
resume() {
|
|
1681
|
+
if (this.state !== "paused" || this.signal?.aborted) return false;
|
|
1682
|
+
this.setState("running");
|
|
1683
|
+
while (this.gateWaiters.length > 0) {
|
|
1684
|
+
this.gateWaiters.shift().resolve();
|
|
1685
|
+
}
|
|
1686
|
+
this.pump();
|
|
1687
|
+
return true;
|
|
1688
|
+
}
|
|
1689
|
+
waitUntilRunning() {
|
|
1690
|
+
if (this.signal?.aborted) return Promise.reject(abortError());
|
|
1691
|
+
if (this.state === "running") return Promise.resolve();
|
|
1692
|
+
return new Promise((resolve, reject) => {
|
|
1693
|
+
this.gateWaiters.push({ resolve, reject });
|
|
1694
|
+
});
|
|
1695
|
+
}
|
|
1696
|
+
snapshot() {
|
|
1697
|
+
return {
|
|
1698
|
+
state: this.state,
|
|
1699
|
+
queued: this.queue.length,
|
|
1700
|
+
inFlight: this.inFlight
|
|
1701
|
+
};
|
|
1158
1702
|
}
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
const job = queue.shift();
|
|
1164
|
-
if (signal?.aborted) {
|
|
1703
|
+
pump() {
|
|
1704
|
+
while (this.state === "running" && this.inFlight < this.limit && this.queue.length > 0) {
|
|
1705
|
+
const job = this.queue.shift();
|
|
1706
|
+
if (this.signal?.aborted) {
|
|
1165
1707
|
job.reject(abortError());
|
|
1166
1708
|
continue;
|
|
1167
1709
|
}
|
|
1168
|
-
|
|
1710
|
+
this.inFlight++;
|
|
1169
1711
|
Promise.resolve().then(job.thunk).then(job.resolve, job.reject).finally(() => {
|
|
1170
|
-
|
|
1171
|
-
|
|
1712
|
+
this.inFlight--;
|
|
1713
|
+
if (this.state === "pausing" && this.inFlight === 0) {
|
|
1714
|
+
this.setState("paused");
|
|
1715
|
+
}
|
|
1716
|
+
this.pump();
|
|
1172
1717
|
});
|
|
1173
1718
|
}
|
|
1174
|
-
}
|
|
1175
|
-
|
|
1176
|
-
if (
|
|
1177
|
-
|
|
1178
|
-
|
|
1719
|
+
}
|
|
1720
|
+
setState(state) {
|
|
1721
|
+
if (this.state === state) return;
|
|
1722
|
+
this.state = state;
|
|
1723
|
+
const snapshot = this.snapshot();
|
|
1724
|
+
for (const listener of [...this.stateListeners]) listener(snapshot);
|
|
1725
|
+
}
|
|
1726
|
+
abortPending() {
|
|
1727
|
+
const error = abortError();
|
|
1728
|
+
while (this.queue.length > 0) this.queue.shift().reject(error);
|
|
1729
|
+
while (this.gateWaiters.length > 0) {
|
|
1730
|
+
this.gateWaiters.shift().reject(error);
|
|
1179
1731
|
}
|
|
1180
|
-
queue.push({
|
|
1181
|
-
thunk,
|
|
1182
|
-
resolve,
|
|
1183
|
-
reject
|
|
1184
|
-
});
|
|
1185
|
-
pump();
|
|
1186
|
-
}), "run");
|
|
1187
|
-
if (signal && !signal.aborted) {
|
|
1188
|
-
signal.addEventListener(
|
|
1189
|
-
"abort",
|
|
1190
|
-
() => {
|
|
1191
|
-
while (queue.length > 0) queue.shift().reject(abortError());
|
|
1192
|
-
},
|
|
1193
|
-
{ once: true }
|
|
1194
|
-
);
|
|
1195
1732
|
}
|
|
1196
|
-
|
|
1197
|
-
}
|
|
1198
|
-
__name(createConcurrencyLimiter, "createConcurrencyLimiter");
|
|
1733
|
+
};
|
|
1199
1734
|
|
|
1200
1735
|
// packages/core/src/agents/runtime/workflow-orchestrator.ts
|
|
1201
1736
|
var DEFAULT_MAX_AGENTS_PER_RUN = 1e3;
|
|
@@ -1208,13 +1743,13 @@ function resolveMaxAgentsPerRun(env = process.env) {
|
|
|
1208
1743
|
}
|
|
1209
1744
|
const parsed = parsePositiveIntegerEnv(raw, 0);
|
|
1210
1745
|
if (parsed < 1) {
|
|
1211
|
-
|
|
1746
|
+
debugLogger.warn(
|
|
1212
1747
|
`Invalid ${MAX_WORKFLOW_AGENTS_ENV}=${JSON.stringify(raw)}, using default (${DEFAULT_MAX_AGENTS_PER_RUN})`
|
|
1213
1748
|
);
|
|
1214
1749
|
return DEFAULT_MAX_AGENTS_PER_RUN;
|
|
1215
1750
|
}
|
|
1216
1751
|
if (parsed > HARD_MAX_AGENTS_PER_RUN_CEILING) {
|
|
1217
|
-
|
|
1752
|
+
debugLogger.warn(
|
|
1218
1753
|
`${MAX_WORKFLOW_AGENTS_ENV}=${parsed} exceeds hard ceiling (${HARD_MAX_AGENTS_PER_RUN_CEILING}); clamping.`
|
|
1219
1754
|
);
|
|
1220
1755
|
return HARD_MAX_AGENTS_PER_RUN_CEILING;
|
|
@@ -1230,14 +1765,14 @@ function resolveConcurrencyLimit(env = process.env) {
|
|
|
1230
1765
|
const parsed = parsePositiveIntegerEnv(raw, 0);
|
|
1231
1766
|
if (parsed >= 1) {
|
|
1232
1767
|
if (parsed > HARD_MAX_CONCURRENCY_CEILING) {
|
|
1233
|
-
|
|
1768
|
+
debugLogger.warn(
|
|
1234
1769
|
`${MAX_WORKFLOW_CONCURRENCY_ENV}=${parsed} exceeds hard ceiling (${HARD_MAX_CONCURRENCY_CEILING}); clamping.`
|
|
1235
1770
|
);
|
|
1236
1771
|
return HARD_MAX_CONCURRENCY_CEILING;
|
|
1237
1772
|
}
|
|
1238
1773
|
return parsed;
|
|
1239
1774
|
}
|
|
1240
|
-
|
|
1775
|
+
debugLogger.warn(
|
|
1241
1776
|
`Invalid ${MAX_WORKFLOW_CONCURRENCY_ENV}=${JSON.stringify(raw)}, using cpu-derived default`
|
|
1242
1777
|
);
|
|
1243
1778
|
}
|
|
@@ -1310,11 +1845,11 @@ function createProductionDispatch(config, signal, onTokens, bridgeApprovalEvents
|
|
|
1310
1845
|
}
|
|
1311
1846
|
__name(createProductionDispatch, "createProductionDispatch");
|
|
1312
1847
|
async function runSingleDispatch(config, prompt, opts, attemptSignal, emitter, onTokens) {
|
|
1313
|
-
const { AgentHeadless, ContextState } = await import("./agent-headless-
|
|
1848
|
+
const { AgentHeadless, ContextState } = await import("./agent-headless-XXGY2SQO.js");
|
|
1314
1849
|
const ctx = new ContextState();
|
|
1315
1850
|
ctx.set("task_prompt", prompt);
|
|
1316
1851
|
const workflowAgentId = `workflow-agent-${randomBytes(8).toString("hex")}`;
|
|
1317
|
-
|
|
1852
|
+
debugLogger.debug(`[workflow] Dispatch ${workflowAgentId}`);
|
|
1318
1853
|
if (opts.agentType === void 0 && opts.model === void 0 && opts.isolation === void 0 && opts.schema === void 0) {
|
|
1319
1854
|
const subagent = await AgentHeadless.create(
|
|
1320
1855
|
opts.label ?? "workflow-agent",
|
|
@@ -1372,7 +1907,7 @@ function reportTokens(subagent, opts, onTokens) {
|
|
|
1372
1907
|
const summary = subagent.getExecutionSummary();
|
|
1373
1908
|
onTokens(summary.outputTokens, opts);
|
|
1374
1909
|
} catch (e) {
|
|
1375
|
-
|
|
1910
|
+
debugLogger.warn("onTokens callback threw:", e);
|
|
1376
1911
|
}
|
|
1377
1912
|
}
|
|
1378
1913
|
__name(reportTokens, "reportTokens");
|
|
@@ -1491,7 +2026,7 @@ ${WORKFLOW_SUBAGENT_SYSTEM_PROMPT_WITH_SCHEMA}` : WORKFLOW_SUBAGENT_SYSTEM_PROMP
|
|
|
1491
2026
|
worktreeIsolation = null;
|
|
1492
2027
|
const preserved = await cleanupWorkflowWorktree(isolation);
|
|
1493
2028
|
if (preserved) {
|
|
1494
|
-
|
|
2029
|
+
debugLogger.info(
|
|
1495
2030
|
`[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.`
|
|
1496
2031
|
);
|
|
1497
2032
|
}
|
|
@@ -1546,7 +2081,7 @@ ${WORKFLOW_SUBAGENT_SYSTEM_PROMPT_WITH_SCHEMA}` : WORKFLOW_SUBAGENT_SYSTEM_PROMP
|
|
|
1546
2081
|
try {
|
|
1547
2082
|
await cleanupWorkflowWorktree(worktreeIsolation);
|
|
1548
2083
|
} catch (error) {
|
|
1549
|
-
|
|
2084
|
+
debugLogger.warn(
|
|
1550
2085
|
`Workflow worktree cleanup in fallback finally failed for ${worktreeIsolation.path}: ${error instanceof Error ? error.message : String(error)}`
|
|
1551
2086
|
);
|
|
1552
2087
|
}
|
|
@@ -1579,7 +2114,7 @@ async function provisionWorkflowWorktree(config) {
|
|
|
1579
2114
|
try {
|
|
1580
2115
|
parentDirty = await wtService.hasWorktreeChanges(projectRoot);
|
|
1581
2116
|
} catch (error) {
|
|
1582
|
-
|
|
2117
|
+
debugLogger.warn(
|
|
1583
2118
|
`[Workflow] hasWorktreeChanges failed at ${projectRoot}: ${error}`
|
|
1584
2119
|
);
|
|
1585
2120
|
parentDirty = true;
|
|
@@ -1594,7 +2129,7 @@ async function provisionWorkflowWorktree(config) {
|
|
|
1594
2129
|
try {
|
|
1595
2130
|
parentBranch = await wtService.getCurrentBranch();
|
|
1596
2131
|
} catch (error) {
|
|
1597
|
-
|
|
2132
|
+
debugLogger.warn(
|
|
1598
2133
|
`[Workflow] getCurrentBranch failed at ${projectRoot}: ${error}`
|
|
1599
2134
|
);
|
|
1600
2135
|
}
|
|
@@ -1612,7 +2147,7 @@ async function provisionWorkflowWorktree(config) {
|
|
|
1612
2147
|
config.getSessionId()
|
|
1613
2148
|
);
|
|
1614
2149
|
} catch (error) {
|
|
1615
|
-
|
|
2150
|
+
debugLogger.warn(
|
|
1616
2151
|
`[Workflow] failed to write session marker at ${created.worktree.path}: ${error}`
|
|
1617
2152
|
);
|
|
1618
2153
|
}
|
|
@@ -1645,20 +2180,20 @@ async function cleanupWorkflowWorktree(isolation) {
|
|
|
1645
2180
|
const wtService = new GitWorktreeService(isolation.repoRoot);
|
|
1646
2181
|
const [hasChanges, hasUnmerged] = await Promise.all([
|
|
1647
2182
|
wtService.hasWorktreeChanges(isolation.path).catch((error) => {
|
|
1648
|
-
|
|
2183
|
+
debugLogger.warn(
|
|
1649
2184
|
`[Workflow] hasWorktreeChanges failed for ${isolation.path}: ${error}`
|
|
1650
2185
|
);
|
|
1651
2186
|
return true;
|
|
1652
2187
|
}),
|
|
1653
2188
|
wtService.hasUnmergedWorktreeCommits(isolation.slug).catch((error) => {
|
|
1654
|
-
|
|
2189
|
+
debugLogger.warn(
|
|
1655
2190
|
`[Workflow] hasUnmergedWorktreeCommits failed for ${isolation.slug}: ${error}`
|
|
1656
2191
|
);
|
|
1657
2192
|
return true;
|
|
1658
2193
|
})
|
|
1659
2194
|
]);
|
|
1660
2195
|
if (hasChanges || hasUnmerged) {
|
|
1661
|
-
|
|
2196
|
+
debugLogger.info(
|
|
1662
2197
|
`[Workflow] Preserving isolation worktree ${isolation.path} (branch ${isolation.branch}, hasChanges=${hasChanges}, hasUnmerged=${hasUnmerged})`
|
|
1663
2198
|
);
|
|
1664
2199
|
return { path: isolation.path, branch: isolation.branch };
|
|
@@ -1668,19 +2203,19 @@ async function cleanupWorkflowWorktree(isolation) {
|
|
|
1668
2203
|
deleteBranch: true
|
|
1669
2204
|
});
|
|
1670
2205
|
if (!result.success) {
|
|
1671
|
-
|
|
2206
|
+
debugLogger.warn(
|
|
1672
2207
|
`[Workflow] Failed to remove ephemeral worktree ${isolation.path}: ${result.error}`
|
|
1673
2208
|
);
|
|
1674
2209
|
return { path: isolation.path, branch: isolation.branch };
|
|
1675
2210
|
}
|
|
1676
2211
|
if (result.branchPreserved) {
|
|
1677
|
-
|
|
2212
|
+
debugLogger.warn(
|
|
1678
2213
|
`[Workflow] Removed worktree directory ${isolation.path} but kept branch ${isolation.branch} (unmerged commits at delete time)`
|
|
1679
2214
|
);
|
|
1680
2215
|
return { branch: isolation.branch };
|
|
1681
2216
|
}
|
|
1682
2217
|
} catch (error) {
|
|
1683
|
-
|
|
2218
|
+
debugLogger.warn(
|
|
1684
2219
|
`[Workflow] Failed to remove ephemeral worktree ${isolation.path}: ${error}`
|
|
1685
2220
|
);
|
|
1686
2221
|
return { path: isolation.path, branch: isolation.branch };
|
|
@@ -1748,7 +2283,15 @@ var WorkflowOrchestrator = class {
|
|
|
1748
2283
|
const runId = req.runId ?? generateRunId();
|
|
1749
2284
|
const maxAgents = resolveMaxAgentsPerRun();
|
|
1750
2285
|
const signal = req.abortOnTimeout?.signal;
|
|
1751
|
-
const
|
|
2286
|
+
const scheduler = req.scheduler ?? new WorkflowDispatchScheduler(resolveConcurrencyLimit(), signal);
|
|
2287
|
+
const rejectThroughPauseGate = /* @__PURE__ */ __name((error) => scheduler.waitUntilRunning().then(
|
|
2288
|
+
() => {
|
|
2289
|
+
throw error;
|
|
2290
|
+
},
|
|
2291
|
+
() => {
|
|
2292
|
+
throw error;
|
|
2293
|
+
}
|
|
2294
|
+
), "rejectThroughPauseGate");
|
|
1752
2295
|
let agentCount = 0;
|
|
1753
2296
|
const emitter = req.emitter;
|
|
1754
2297
|
const budget = req.budget;
|
|
@@ -1768,7 +2311,7 @@ var WorkflowOrchestrator = class {
|
|
|
1768
2311
|
if (cached !== void 0) {
|
|
1769
2312
|
const respawns = replay.started.get(journalKey);
|
|
1770
2313
|
if (respawns && respawns.length > 0) {
|
|
1771
|
-
|
|
2314
|
+
debugLogger.info(
|
|
1772
2315
|
`[Workflow] resume cache hit after ${respawns.length} prior respawn(s) for runId=${runId}.`
|
|
1773
2316
|
);
|
|
1774
2317
|
}
|
|
@@ -1776,33 +2319,36 @@ var WorkflowOrchestrator = class {
|
|
|
1776
2319
|
try {
|
|
1777
2320
|
emitter?.agentDispatched?.(label2);
|
|
1778
2321
|
} catch (e) {
|
|
1779
|
-
|
|
2322
|
+
debugLogger.warn("emitter.agentDispatched threw:", e);
|
|
1780
2323
|
}
|
|
1781
2324
|
try {
|
|
1782
2325
|
emitter?.agentCompleted?.(label2);
|
|
1783
2326
|
} catch (e) {
|
|
1784
|
-
|
|
2327
|
+
debugLogger.warn("emitter.agentCompleted threw:", e);
|
|
1785
2328
|
}
|
|
1786
|
-
return
|
|
2329
|
+
return scheduler.waitUntilRunning().then(
|
|
2330
|
+
() => cached.result,
|
|
2331
|
+
() => cached.result
|
|
2332
|
+
);
|
|
1787
2333
|
}
|
|
1788
2334
|
}
|
|
1789
2335
|
hadMiss = true;
|
|
1790
2336
|
journalEntryId = String(journalAgentId += 1);
|
|
1791
2337
|
journal.append({ type: "started", key: journalKey, agentId: journalEntryId }).catch(
|
|
1792
|
-
(e) =>
|
|
2338
|
+
(e) => debugLogger.warn(`journal started-append failed: ${e}`)
|
|
1793
2339
|
);
|
|
1794
2340
|
}
|
|
1795
2341
|
if (budget && budget.total !== null && budget.remaining() <= 0) {
|
|
1796
|
-
|
|
2342
|
+
debugLogger.warn(
|
|
1797
2343
|
`[Workflow] budget gate refused dispatch at entry: runId=${runId} spent=${budget.spent()} total=${budget.total}`
|
|
1798
2344
|
);
|
|
1799
|
-
return
|
|
2345
|
+
return rejectThroughPauseGate(
|
|
1800
2346
|
new WorkflowBudgetExceededError(runId, budget.total, budget.spent())
|
|
1801
2347
|
);
|
|
1802
2348
|
}
|
|
1803
2349
|
agentCount += 1;
|
|
1804
2350
|
if (agentCount > maxAgents) {
|
|
1805
|
-
return
|
|
2351
|
+
return rejectThroughPauseGate(
|
|
1806
2352
|
new Error(
|
|
1807
2353
|
`Workflow exceeded the maximum of ${maxAgents} agent() calls per run.`
|
|
1808
2354
|
)
|
|
@@ -1812,27 +2358,33 @@ var WorkflowOrchestrator = class {
|
|
|
1812
2358
|
try {
|
|
1813
2359
|
emitter?.agentDispatched?.(label);
|
|
1814
2360
|
} catch (e) {
|
|
1815
|
-
|
|
2361
|
+
debugLogger.warn("emitter.agentDispatched threw:", e);
|
|
1816
2362
|
}
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
);
|
|
2363
|
+
let completionEmitted = false;
|
|
2364
|
+
const emitCompletion = /* @__PURE__ */ __name((error) => {
|
|
2365
|
+
if (completionEmitted) return;
|
|
2366
|
+
completionEmitted = true;
|
|
2367
|
+
const message = error === void 0 ? void 0 : error instanceof Error ? error.message : String(error);
|
|
2368
|
+
try {
|
|
2369
|
+
emitter?.agentCompleted?.(label, message);
|
|
2370
|
+
} catch (e) {
|
|
2371
|
+
debugLogger.warn("emitter.agentCompleted threw:", e);
|
|
1827
2372
|
}
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
2373
|
+
}, "emitCompletion");
|
|
2374
|
+
return scheduler.run(async () => {
|
|
2375
|
+
try {
|
|
2376
|
+
if (budget && budget.total !== null && budget.remaining() <= 0) {
|
|
2377
|
+
debugLogger.warn(
|
|
2378
|
+
`[Workflow] budget gate refused dispatch at slot-acquire: runId=${runId} spent=${budget.spent()} total=${budget.total}`
|
|
2379
|
+
);
|
|
2380
|
+
throw new WorkflowBudgetExceededError(
|
|
2381
|
+
runId,
|
|
2382
|
+
budget.total,
|
|
2383
|
+
budget.spent()
|
|
2384
|
+
);
|
|
1835
2385
|
}
|
|
2386
|
+
const result = await this.dispatch(prompt, opts);
|
|
2387
|
+
emitCompletion();
|
|
1836
2388
|
if (journal && journalKey !== void 0) {
|
|
1837
2389
|
journal.append({
|
|
1838
2390
|
type: "result",
|
|
@@ -1840,63 +2392,92 @@ var WorkflowOrchestrator = class {
|
|
|
1840
2392
|
agentId: journalEntryId ?? "",
|
|
1841
2393
|
result
|
|
1842
2394
|
}).catch(
|
|
1843
|
-
(e) =>
|
|
2395
|
+
(e) => debugLogger.warn(`journal result-append failed: ${e}`)
|
|
1844
2396
|
);
|
|
1845
2397
|
}
|
|
1846
2398
|
if (budget) {
|
|
1847
2399
|
try {
|
|
1848
2400
|
emitter?.budgetUpdated?.(budget.spent(), budget.total);
|
|
1849
2401
|
} catch (e) {
|
|
1850
|
-
|
|
2402
|
+
debugLogger.warn("emitter.budgetUpdated threw:", e);
|
|
1851
2403
|
}
|
|
1852
2404
|
}
|
|
1853
2405
|
return result;
|
|
1854
|
-
}
|
|
1855
|
-
|
|
1856
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
1857
|
-
try {
|
|
1858
|
-
emitter?.agentCompleted?.(label, msg);
|
|
1859
|
-
} catch (e) {
|
|
1860
|
-
debugLogger2.warn("emitter.agentCompleted threw:", e);
|
|
1861
|
-
}
|
|
2406
|
+
} catch (err) {
|
|
2407
|
+
emitCompletion(err);
|
|
1862
2408
|
if (budget) {
|
|
1863
2409
|
try {
|
|
1864
2410
|
emitter?.budgetUpdated?.(budget.spent(), budget.total);
|
|
1865
2411
|
} catch (e) {
|
|
1866
|
-
|
|
2412
|
+
debugLogger.warn("emitter.budgetUpdated threw:", e);
|
|
1867
2413
|
}
|
|
1868
2414
|
}
|
|
1869
2415
|
throw err;
|
|
1870
2416
|
}
|
|
2417
|
+
}).then(
|
|
2418
|
+
// Resolve even if the gate aborts: a successful dispatch must not
|
|
2419
|
+
// turn into a teardown rejection — for a fire-and-forget call the
|
|
2420
|
+
// script never attached a handler, so the rejection would surface
|
|
2421
|
+
// as a spurious process-level unhandledRejection alarm on a
|
|
2422
|
+
// correctly-cancelled run.
|
|
2423
|
+
(result) => scheduler.waitUntilRunning().then(
|
|
2424
|
+
() => result,
|
|
2425
|
+
() => result
|
|
2426
|
+
),
|
|
2427
|
+
(error) => {
|
|
2428
|
+
emitCompletion(error);
|
|
2429
|
+
return scheduler.waitUntilRunning().then(
|
|
2430
|
+
() => {
|
|
2431
|
+
throw error;
|
|
2432
|
+
},
|
|
2433
|
+
() => {
|
|
2434
|
+
throw error;
|
|
2435
|
+
}
|
|
2436
|
+
);
|
|
2437
|
+
}
|
|
1871
2438
|
);
|
|
1872
2439
|
}, "countedDispatch");
|
|
1873
2440
|
const parallelImpl = makeParallelImpl(signal);
|
|
1874
2441
|
const pipelineImpl = makePipelineImpl(signal);
|
|
1875
2442
|
const resolveSavedWorkflow = req.resolveSavedWorkflow;
|
|
2443
|
+
const parentSandboxRef = {
|
|
2444
|
+
current: void 0
|
|
2445
|
+
};
|
|
1876
2446
|
const workflowImpl = resolveSavedWorkflow ? async (nameOrRef, nestedArgs) => {
|
|
1877
2447
|
const resolved = await resolveSavedWorkflow(nameOrRef);
|
|
1878
2448
|
const nestedSandbox = createWorkflowSandbox({
|
|
1879
2449
|
args: nestedArgs,
|
|
2450
|
+
runId,
|
|
1880
2451
|
dispatch: countedDispatch,
|
|
1881
2452
|
parallel: parallelImpl,
|
|
1882
2453
|
pipeline: pipelineImpl,
|
|
1883
2454
|
abortOnTimeout: req.abortOnTimeout,
|
|
1884
2455
|
emitter,
|
|
1885
|
-
budget
|
|
2456
|
+
budget,
|
|
2457
|
+
scheduler
|
|
1886
2458
|
// No `workflow` — single-level nesting limit.
|
|
1887
2459
|
});
|
|
1888
|
-
|
|
2460
|
+
try {
|
|
2461
|
+
return await nestedSandbox.run(resolved.script);
|
|
2462
|
+
} finally {
|
|
2463
|
+
for (const line of nestedSandbox.getLogs()) {
|
|
2464
|
+
parentSandboxRef.current?.appendLog(line);
|
|
2465
|
+
}
|
|
2466
|
+
}
|
|
1889
2467
|
} : void 0;
|
|
1890
2468
|
const sandbox = createWorkflowSandbox({
|
|
1891
2469
|
args: req.args,
|
|
2470
|
+
runId,
|
|
1892
2471
|
dispatch: countedDispatch,
|
|
1893
2472
|
parallel: parallelImpl,
|
|
1894
2473
|
pipeline: pipelineImpl,
|
|
1895
2474
|
workflow: workflowImpl,
|
|
1896
2475
|
abortOnTimeout: req.abortOnTimeout,
|
|
1897
2476
|
emitter,
|
|
1898
|
-
budget
|
|
2477
|
+
budget,
|
|
2478
|
+
scheduler
|
|
1899
2479
|
});
|
|
2480
|
+
parentSandboxRef.current = sandbox;
|
|
1900
2481
|
try {
|
|
1901
2482
|
const result = await sandbox.run(req.script);
|
|
1902
2483
|
return {
|
|
@@ -1929,14 +2510,14 @@ async function settleToNullArray(thunks, signal, kind = "parallel") {
|
|
|
1929
2510
|
if (reason?.name === "WorkflowBudgetExceededError") {
|
|
1930
2511
|
budgetDropped += 1;
|
|
1931
2512
|
} else {
|
|
1932
|
-
|
|
2513
|
+
debugLogger.warn(
|
|
1933
2514
|
`Workflow thunk at index ${i} rejected: ${String(reason?.message ?? r.reason)}`
|
|
1934
2515
|
);
|
|
1935
2516
|
}
|
|
1936
2517
|
return null;
|
|
1937
2518
|
});
|
|
1938
2519
|
if (budgetDropped > 0) {
|
|
1939
|
-
|
|
2520
|
+
debugLogger.warn(
|
|
1940
2521
|
`${kind}: ${budgetDropped} slot${budgetDropped === 1 ? "" : "s"} dropped \u2014 token budget exceeded.`
|
|
1941
2522
|
);
|
|
1942
2523
|
}
|
|
@@ -2010,12 +2591,15 @@ function extractErrorMessage(err) {
|
|
|
2010
2591
|
__name(extractErrorMessage, "extractErrorMessage");
|
|
2011
2592
|
|
|
2012
2593
|
// packages/core/src/agents/runtime/workflow-runner.ts
|
|
2594
|
+
init_esbuild_shims();
|
|
2595
|
+
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
2013
2596
|
var WorkflowRunHandle = class {
|
|
2014
|
-
constructor(runId, budget, registry, controller, start) {
|
|
2597
|
+
constructor(runId, budget, registry, controller, scheduler, start) {
|
|
2015
2598
|
this.runId = runId;
|
|
2016
2599
|
this.budget = budget;
|
|
2017
2600
|
this.registry = registry;
|
|
2018
2601
|
this.controller = controller;
|
|
2602
|
+
this.scheduler = scheduler;
|
|
2019
2603
|
this.completion = Promise.resolve().then(start);
|
|
2020
2604
|
}
|
|
2021
2605
|
static {
|
|
@@ -2025,6 +2609,12 @@ var WorkflowRunHandle = class {
|
|
|
2025
2609
|
abort() {
|
|
2026
2610
|
this.controller.abort();
|
|
2027
2611
|
}
|
|
2612
|
+
pause() {
|
|
2613
|
+
return this.scheduler.pause();
|
|
2614
|
+
}
|
|
2615
|
+
resume() {
|
|
2616
|
+
return this.scheduler.resume();
|
|
2617
|
+
}
|
|
2028
2618
|
};
|
|
2029
2619
|
var WorkflowRunner = class {
|
|
2030
2620
|
static {
|
|
@@ -2103,11 +2693,17 @@ var WorkflowRunner = class {
|
|
|
2103
2693
|
emitUpdate();
|
|
2104
2694
|
}, "budgetUpdated")
|
|
2105
2695
|
};
|
|
2696
|
+
const scheduler = new WorkflowDispatchScheduler(
|
|
2697
|
+
resolveConcurrencyLimit(),
|
|
2698
|
+
controller.signal,
|
|
2699
|
+
({ state }) => registry?.onDispatchStateChange(runId, state)
|
|
2700
|
+
);
|
|
2106
2701
|
const handle = new WorkflowRunHandle(
|
|
2107
2702
|
runId,
|
|
2108
2703
|
budget,
|
|
2109
2704
|
registry,
|
|
2110
2705
|
controller,
|
|
2706
|
+
scheduler,
|
|
2111
2707
|
async () => {
|
|
2112
2708
|
try {
|
|
2113
2709
|
const outcome = await orchestrator.run({
|
|
@@ -2119,7 +2715,8 @@ var WorkflowRunner = class {
|
|
|
2119
2715
|
budget,
|
|
2120
2716
|
resolveSavedWorkflow: /* @__PURE__ */ __name((ref) => resolveSavedWorkflowScript(ref, config), "resolveSavedWorkflow"),
|
|
2121
2717
|
journal,
|
|
2122
|
-
resumeReplay
|
|
2718
|
+
resumeReplay,
|
|
2719
|
+
scheduler
|
|
2123
2720
|
});
|
|
2124
2721
|
if (entry) {
|
|
2125
2722
|
entry.meta = outcome.meta;
|
|
@@ -2128,6 +2725,12 @@ var WorkflowRunner = class {
|
|
|
2128
2725
|
}
|
|
2129
2726
|
}
|
|
2130
2727
|
registry?.setRecentLogs(runId, outcome.logs);
|
|
2728
|
+
if (entry && isTerminalWorkflowStatus(entry.status)) {
|
|
2729
|
+
return {
|
|
2730
|
+
ok: false,
|
|
2731
|
+
message: entry.status === "cancelled" ? "Workflow run cancelled." : entry.error ?? "Workflow run failed."
|
|
2732
|
+
};
|
|
2733
|
+
}
|
|
2131
2734
|
registry?.complete(runId, outcome.result, Date.now());
|
|
2132
2735
|
return { ok: true, outcome };
|
|
2133
2736
|
} catch (error) {
|
|
@@ -2143,20 +2746,18 @@ var WorkflowRunner = class {
|
|
|
2143
2746
|
return { ok: false, message, details };
|
|
2144
2747
|
} finally {
|
|
2145
2748
|
controller.abort();
|
|
2146
|
-
if (entry && entry.status
|
|
2749
|
+
if (entry && isTerminalWorkflowStatus(entry.status)) {
|
|
2750
|
+
const telemetryEvent = new WorkflowRunEvent({
|
|
2751
|
+
status: entry.status,
|
|
2752
|
+
agents_dispatched: entry.agentsDispatched,
|
|
2753
|
+
agents_completed: entry.agentsCompleted,
|
|
2754
|
+
phase_count: entry.phases.length,
|
|
2755
|
+
tokens_spent: entry.tokensSpent,
|
|
2756
|
+
duration_ms: (entry.endTime ?? entry.startTime) - entry.startTime
|
|
2757
|
+
});
|
|
2147
2758
|
await writeWorkflowSnapshot(config, entry);
|
|
2148
2759
|
try {
|
|
2149
|
-
logWorkflowRun(
|
|
2150
|
-
config,
|
|
2151
|
-
new WorkflowRunEvent({
|
|
2152
|
-
status: entry.status,
|
|
2153
|
-
agents_dispatched: entry.agentsDispatched,
|
|
2154
|
-
agents_completed: entry.agentsCompleted,
|
|
2155
|
-
phase_count: entry.phases.length,
|
|
2156
|
-
tokens_spent: entry.tokensSpent,
|
|
2157
|
-
duration_ms: (entry.endTime ?? entry.startTime) - entry.startTime
|
|
2158
|
-
})
|
|
2159
|
-
);
|
|
2760
|
+
logWorkflowRun(config, telemetryEvent);
|
|
2160
2761
|
} catch {
|
|
2161
2762
|
}
|
|
2162
2763
|
}
|
|
@@ -2185,7 +2786,7 @@ var WORKFLOW_PARAM_SCHEMA = {
|
|
|
2185
2786
|
properties: {
|
|
2186
2787
|
script: {
|
|
2187
2788
|
type: "string",
|
|
2188
|
-
description:
|
|
2789
|
+
description: `JavaScript source of the workflow. Wrapped as an async IIFE. May call the injected globals \`phase(title)\`, \`log(msg)\`, \`agent(prompt, opts?)\`, and read \`args\`. agent() opts: \`{ label?, phase?, schema?, model?, agentType?, isolation? }\`. \`schema\` (JSON Schema object): the subagent must deliver its result by calling \`structured_output\` with arguments matching the schema; agent() resolves to the validated object. Two failed attempts produce a terminal error "subagent completed without calling StructuredOutput (after 2 in-conversation nudges)". \`agentType\` (string): resolves against the declarative-agents registry (\`.qwen/agents/<name>.md\`, project then user then built-in). Unresolved names throw "agent({agentType}): agent type 'X' not found". \`model\` (string): per-call model override; routes provider correctly via the subagent runtime view. \`isolation\`: \`'worktree'\` provisions a fresh git worktree under \`<projectRoot>/.qwen/worktrees/agent-<7hex>\`; the worktree is auto-removed if no changes, otherwise the path and branch are returned alongside the result. \`'remote'\` throws "agent({isolation:'remote'}) is not available in this build" (parity with upstream). isolation=worktree refuses to run when the parent working tree has uncommitted changes (the subagent would see a stale HEAD). Workflow subagents always have SendMessage / Monitor / EnterPlanMode / ExitPlanMode in their disallowed-tool floor regardless of agentType. Concurrency: \`parallel([() => agent(...), ...])\` runs thunks through a shared per-run window (default \`max(1, min(16, cpus-2))\` agents in flight; override via \`${MAX_WORKFLOW_CONCURRENCY_ENV}\`) and resolves to a position-aligned array \u2014 a thunk that throws, or resolves to a non-JSON-serializable value, becomes \`null\` at its index (errors-as-data); parallel() itself rejects only on invalid arguments or abort. \`pipeline(items, ...stages)\` runs each item through the stages (staggered, no inter-stage barrier); a stage that throws, returns \`null\`, or returns a non-JSON-serializable value drops that item to \`null\`. Pass THUNKS to parallel, not eager calls: \`parallel([() => agent(...)])\`, not \`parallel([agent(...)])\`. At most ${DEFAULT_MAX_AGENTS_PER_RUN} agent() calls per run (override via \`${MAX_WORKFLOW_AGENTS_ENV}\`). \`Date.now()\` and \`Math.random()\` both throw \u2014 workflow scripts must be deterministic for resume. \`export const meta = {...}\` declarations are stripped before execution.`
|
|
2189
2790
|
},
|
|
2190
2791
|
scriptPath: {
|
|
2191
2792
|
type: "string",
|
|
@@ -2201,7 +2802,7 @@ var WORKFLOW_PARAM_SCHEMA = {
|
|
|
2201
2802
|
run_in_background: {
|
|
2202
2803
|
type: "boolean",
|
|
2203
2804
|
default: false,
|
|
2204
|
-
description: "Optional. When true, start the workflow under the interactive session and return a run handle immediately. The Background Tasks view can observe or stop it, and completion is delivered to the conversation when the run settles. Interactive TUI only. Defaults to false."
|
|
2805
|
+
description: "Optional. When true, start the workflow under the interactive session and return a run handle immediately. The Background Tasks view can observe, cooperatively pause/resume, or stop it, and completion is delivered to the conversation when the run settles. Interactive TUI only. Defaults to false."
|
|
2205
2806
|
}
|
|
2206
2807
|
}
|
|
2207
2808
|
// `script` is required UNLESS `scriptPath` is supplied; this XOR can't be
|
|
@@ -2269,7 +2870,7 @@ Run ID: ${handle.runId}
|
|
|
2269
2870
|
Status: ${status}`
|
|
2270
2871
|
}
|
|
2271
2872
|
],
|
|
2272
|
-
returnDisplay: usageBanner + `Workflow ${handle.runId} started in the background (status: ${status}). Use Background Tasks to observe or stop it.`
|
|
2873
|
+
returnDisplay: usageBanner + `Workflow ${handle.runId} started in the background (status: ${status}). Use Background Tasks to observe, cooperatively pause/resume, or stop it.`
|
|
2273
2874
|
};
|
|
2274
2875
|
}
|
|
2275
2876
|
const settlement = await handle.completion;
|
|
@@ -2414,12 +3015,47 @@ function safeStringifyDisplayPayload(payload) {
|
|
|
2414
3015
|
}
|
|
2415
3016
|
}
|
|
2416
3017
|
__name(safeStringifyDisplayPayload, "safeStringifyDisplayPayload");
|
|
3018
|
+
var WORKFLOW_TOOL_DESCRIPTION = `Execute a workflow script that orchestrates subagents deterministically.
|
|
3019
|
+
|
|
3020
|
+
**What a workflow is for**
|
|
3021
|
+
|
|
3022
|
+
Reach for one to be comprehensive (decompose the work and cover every part in parallel), to be confident (independent perspectives and adversarial checks before an answer is committed to), or to take on scale a single context cannot hold \u2014 migrations, audits, broad sweeps. The script is where that structure is encoded: what fans out, what verifies, what synthesizes. Parallelism on its own is not a reason; work that is already one short sequence of edits belongs in the main loop.
|
|
3023
|
+
|
|
3024
|
+
**Runtime** \u2014 see the \`script\` parameter for the detailed authoring contract.
|
|
3025
|
+
|
|
3026
|
+
\`phase(title)\`, \`log(msg)\`, \`agent(prompt, opts?)\`, \`parallel(thunks)\`, \`pipeline(items, ...stages)\`, \`workflow(nameOrRef, args?)\`, plus the \`args\` and \`budget\` globals. \`workflow()\` runs a saved workflow inline under this run's caps and nests one level only \u2014 a workflow reached through \`workflow()\` cannot call \`workflow()\` itself, and doing so throws. Saved workflows are \`<name>.js\` files under \`<projectRoot>/.qwen/workflows\` (project scope, also surfaced as \`/<name>\` slash commands) or \`~/.qwen/workflows\` (user scope, lower precedence when both define the same name); \`workflow('<name>')\` resolves against those two directories, while \`scriptPath\` takes an absolute path to a script anywhere. Default \`max(1, min(16, cpus-2))\` agents in flight per run (\`${MAX_WORKFLOW_CONCURRENCY_ENV}\`), up to ${DEFAULT_MAX_AGENTS_PER_RUN} agents total (\`${MAX_WORKFLOW_AGENTS_ENV}\`), under a 30-minute wall-clock cap per run (\`QWEN_CODE_MAX_WORKFLOW_SECONDS\`) \u2014 a fan-out near the agent cap will not fit inside the default cap. A per-run output-token cap may also be in effect: read \`budget.total\` (\`null\` = uncapped) before committing to a large fan-out, because once the cap is reached every further \`agent()\` call is refused \u2014 a bare sequential \`await agent()\` sees the rejection, while inside \`parallel()\`/\`pipeline()\` the refused slot becomes \`null\` and the script keeps running on partial results. Per-call \`agent({ schema, agentType, model, isolation: 'worktree' })\` covers structured-output contracts, declarative-agent selection, model override, and git-worktree-isolated subagents. \`resumeFromRunId\` resumes a prior run \u2014 agent() calls whose rolling prefix-hash matches the journal are served from cache for the longest unchanged prefix. Runs appear in the background-tasks view and the \`/workflows\` dialog (live phase tree, token usage, cooperative pause/resume, cancel); \`run_in_background: true\` returns a run handle immediately in the interactive TUI and delivers completion through the conversation. Scripts run in a node:vm sandbox with no filesystem or shell access \u2014 all I/O happens through the spawned agents.
|
|
3027
|
+
|
|
3028
|
+
**Scout first, then orchestrate**
|
|
3029
|
+
|
|
3030
|
+
The strongest pattern is hybrid: discover the work list in the main loop (list the files, scope the diff, read the failing test), then hand that list to a workflow. You do not need to know the shape of the work before the task \u2014 only before the orchestration step. When the work has distinct phases, run several small workflows across turns and read each result before choosing the next, rather than authoring one large script that runs unattended.
|
|
3031
|
+
|
|
3032
|
+
Common single-phase shapes: understand (parallel readers over subsystems, merged into one map), design (independent approaches, judged, then synthesized), review (dimensions, find, verify each finding), research (broad sweep, deep read, synthesis), migrate (discover sites, transform each under \`isolation: 'worktree'\`, verify).
|
|
3033
|
+
|
|
3034
|
+
**Default to \`pipeline()\`**
|
|
3035
|
+
|
|
3036
|
+
\`pipeline()\` runs each item through every stage independently \u2014 item A can be in stage 3 while item B is still in stage 1 \u2014 so wall-clock is the slowest single chain. \`parallel()\` is a barrier: it waits for every thunk before anything moves on, so it costs the slowest item of every stage.
|
|
3037
|
+
|
|
3038
|
+
A barrier is right only when a stage genuinely needs cross-item context: deduplicating or merging across the full result set before expensive downstream work, exiting early when the total count is zero, or a prompt that compares one finding against all the others. It is not justified by needing to flatten, map, or filter between stages (do that inside a pipeline stage), by two stages being conceptually separate, or by the code reading more tidily. Smell test: \`parallel()\` \u2192 a pure transform \u2192 \`parallel()\` is a pipeline someone wrote with an unnecessary barrier. When in doubt, \`pipeline()\`.
|
|
3039
|
+
|
|
3040
|
+
**Verify before believing**
|
|
3041
|
+
|
|
3042
|
+
A subagent's answer is a claim, not a result. For findings that matter, spawn independent verifiers prompted to *refute*, and drop what a majority refutes. When a claim can be wrong in several different ways, give each verifier a distinct lens (correctness, security, performance, does it actually reproduce) \u2014 diversity catches what repetition cannot. For a wide solution space, generate several independent attempts, judge them in parallel, and synthesize from the winner while grafting the best ideas from the rest.
|
|
3043
|
+
|
|
3044
|
+
**Converge deliberately**
|
|
3045
|
+
|
|
3046
|
+
For discovery of unknown size, keep running finders until some number of consecutive rounds turn up nothing new; a fixed round count stops partway into the tail. Deduplicate each round against everything already seen, never against only what survived judging \u2014 otherwise rejected findings reappear every round and the loop never terminates. A closing pass that asks what is still missing (a search angle never run, a claim never verified, a file never read) usually produces the next round of real work.
|
|
3047
|
+
|
|
3048
|
+
**Report honestly**
|
|
3049
|
+
|
|
3050
|
+
Scale the fleet to what was actually asked: a quick check gets a few agents and one verification pass; an explicit request to be thorough or exhaustive earns a larger pool and a multi-vote adversarial round. Whenever a run bounds its own coverage \u2014 top-N, sampling, no retry \u2014 \`log()\` what was dropped. Silent truncation reads as full coverage, which is worse than a smaller honest result.
|
|
3051
|
+
|
|
3052
|
+
These shapes are a starting point, not a menu; compose the harness the task actually needs.`;
|
|
2417
3053
|
var WorkflowTool = class extends BaseDeclarativeTool {
|
|
2418
3054
|
constructor(config, toolOptions = {}) {
|
|
2419
3055
|
super(
|
|
2420
3056
|
ToolNames.WORKFLOW,
|
|
2421
3057
|
ToolDisplayNames.WORKFLOW,
|
|
2422
|
-
|
|
3058
|
+
WORKFLOW_TOOL_DESCRIPTION,
|
|
2423
3059
|
"other" /* Other */,
|
|
2424
3060
|
WORKFLOW_PARAM_SCHEMA,
|
|
2425
3061
|
/* isOutputMarkdown */
|
|
@@ -2464,11 +3100,11 @@ export {
|
|
|
2464
3100
|
};
|
|
2465
3101
|
/**
|
|
2466
3102
|
* @license
|
|
2467
|
-
* Copyright
|
|
3103
|
+
* Copyright 2025 Qwen
|
|
2468
3104
|
* SPDX-License-Identifier: Apache-2.0
|
|
2469
3105
|
*/
|
|
2470
3106
|
/**
|
|
2471
3107
|
* @license
|
|
2472
|
-
* Copyright
|
|
3108
|
+
* Copyright 2026 Qwen Team
|
|
2473
3109
|
* SPDX-License-Identifier: Apache-2.0
|
|
2474
3110
|
*/
|