@qwen-code/qwen-code 0.23.2 → 0.23.3
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 +35 -15
- package/bundled/computer-use/SKILL.md +1 -1
- package/bundled/qc-helper/docs/configuration/model-providers.md +66 -28
- package/bundled/qc-helper/docs/configuration/settings.md +5 -3
- package/bundled/qc-helper/docs/features/_meta.ts +1 -0
- package/bundled/qc-helper/docs/features/channels/dws.md +7 -1
- package/bundled/qc-helper/docs/features/commands.md +57 -9
- package/bundled/qc-helper/docs/features/computer-use.md +1 -1
- package/bundled/qc-helper/docs/features/cross-session-protocol.md +320 -0
- package/bundled/qc-helper/docs/features/goals.md +1 -1
- package/bundled/qc-helper/docs/qwen-serve.md +16 -3
- package/bundled/review/SKILL.md +82 -79
- package/bundled/review/references/posting.md +31 -14
- package/chunks/{MaxSizedBox-4C3BKKKY.js → MaxSizedBox-D4LW7RZZ.js} +58 -51
- package/chunks/{StandaloneSessionPicker-TXVF65YW.js → StandaloneSessionPicker-ALTTRWUP.js} +80 -73
- package/chunks/acp-subagent-executor-LEUN3N7N.js +919 -0
- package/chunks/{acpAgent-H5XBKGB4.js → acpAgent-BBSW7XZG.js} +509 -201
- package/chunks/{agent-T5LEFJIU.js → agent-SQ6OY3QD.js} +42 -36
- package/chunks/{agent-headless-VZKSRH36.js → agent-headless-RI2THRQ7.js} +42 -36
- package/chunks/{anthropicContentGenerator-PRJWWVYJ.js → anthropicContentGenerator-JSKMKS6V.js} +66 -34
- package/chunks/{artifact-tool-G5LHNECG.js → artifact-tool-PMYZCYNH.js} +2 -2
- package/chunks/{askUserQuestion-I5W5S3D6.js → askUserQuestion-4M4YYIB4.js} +2 -2
- package/chunks/{bridge-AOX5IY44.js → bridge-DAFMI72L.js} +62 -55
- package/chunks/{channel-management-service-MWQGHPAS.js → channel-management-service-OWDXVL7R.js} +8 -8
- package/chunks/{channel-settings-store-XZCGDGHW.js → channel-settings-store-4I6JONT7.js} +69 -62
- package/chunks/{channel-worker-group-SQ5FRWOH.js → channel-worker-group-F2ZZMLNS.js} +8 -8
- package/chunks/{channel-worker-manager-TU4ZNWOE.js → channel-worker-manager-2SZLJJSJ.js} +18 -9
- package/chunks/{channel-worker-supervisor-EMITFMCP.js → channel-worker-supervisor-ZFNWMG6D.js} +6 -6
- package/chunks/{chunk-GNY7B3CA.js → chunk-2ALXPGB4.js} +1 -1
- package/chunks/{chunk-LUNC5KCL.js → chunk-2PJRI3EH.js} +7 -7
- package/chunks/{chunk-CLKE4IY3.js → chunk-2SZH22YO.js} +1 -1
- package/chunks/{chunk-RNAJVXUG.js → chunk-2ZN3O5FT.js} +6 -6
- package/chunks/{chunk-HIXUUCGY.js → chunk-36HCNKDS.js} +1 -1
- package/chunks/{chunk-FGHPZGOP.js → chunk-3BTSSIJO.js} +38 -54
- package/chunks/{chunk-VBLAI2HA.js → chunk-3FPYT6QC.js} +0 -31
- package/chunks/{chunk-QB3KS3N3.js → chunk-3I7W2POO.js} +1 -1
- package/chunks/{chunk-QTB4VP4K.js → chunk-3KQBQ6FM.js} +136 -11
- package/chunks/{chunk-JO77FGNZ.js → chunk-3UXUOFO6.js} +19 -7
- package/chunks/{chunk-WDN64MVT.js → chunk-3XLK2QMY.js} +82 -16
- package/chunks/chunk-532WHF4F.js +127 -0
- package/chunks/{chunk-NX7ZTXFF.js → chunk-53GWJOLP.js} +1 -1
- package/chunks/{chunk-QQK4L3UU.js → chunk-5GLDOLNQ.js} +131 -26
- package/chunks/{chunk-WK7P62DV.js → chunk-5KI7ZDTB.js} +6 -6
- package/chunks/{chunk-ERXNTINK.js → chunk-6JACAGYH.js} +1 -1
- package/chunks/{chunk-CMWU6P4D.js → chunk-6W4HBUA2.js} +1 -1
- package/chunks/{chunk-AUTUFD5X.js → chunk-76RGWKLS.js} +1 -1
- package/chunks/{chunk-PDN7FJZV.js → chunk-7APZIRH3.js} +2 -2
- package/chunks/{chunk-WBU2PIZ5.js → chunk-7BXXIQG4.js} +16 -16
- package/chunks/{chunk-APXIW2TF.js → chunk-7ICHPMBQ.js} +4 -4
- package/chunks/{chunk-CWVZBIZJ.js → chunk-7Q2AXRDJ.js} +1 -1
- package/chunks/{chunk-WDVV3LRM.js → chunk-7QYWGTHB.js} +1 -1
- package/chunks/{chunk-RM244SCQ.js → chunk-AC6KDLH3.js} +1 -1
- package/chunks/{chunk-2WC3Y7YY.js → chunk-AEY27Z35.js} +401 -23
- package/chunks/{chunk-XDNFODER.js → chunk-AXTFYDXT.js} +1 -1
- package/chunks/chunk-AYEJOTIU.js +43 -0
- package/chunks/{chunk-ZN5TKAVR.js → chunk-BV6Q5HMY.js} +3 -3
- package/chunks/{chunk-TOOOLHVS.js → chunk-BWAMMKIS.js} +3 -3
- package/chunks/{chunk-IRGDIDGJ.js → chunk-BWQLXU37.js} +26 -19
- package/chunks/{process-registry-OAEG6WGC.js → chunk-BYUAT5OC.js} +1 -0
- package/chunks/{chunk-GOEVQADN.js → chunk-BZM5U74J.js} +287 -169
- package/chunks/chunk-CF5KXZZX.js +150 -0
- package/chunks/{chunk-TGNNLRC3.js → chunk-CJ3DHN5I.js} +1 -0
- package/chunks/{chunk-PFKGV6PO.js → chunk-CUEXOHQH.js} +9 -9
- package/chunks/chunk-CXTPVBFA.js +937 -0
- package/chunks/{chunk-LEAOJ43M.js → chunk-DAWWT2ID.js} +62 -59
- package/chunks/{chunk-CALTQWTZ.js → chunk-DLH7YIX6.js} +2 -2
- package/chunks/chunk-DT75RKNH.js +691 -0
- package/chunks/{chunk-TRWQQBVH.js → chunk-DTNV6UZY.js} +1 -1
- package/chunks/{chunk-3OAXF3UK.js → chunk-DYFOSJHU.js} +3080 -933
- package/chunks/{chunk-GSFV5RQW.js → chunk-E4UEO3XM.js} +3 -2
- package/chunks/{chunk-A7EFXK7P.js → chunk-E7LB57MB.js} +5 -5
- package/chunks/{chunk-KEPC5BOL.js → chunk-EDMXGXAK.js} +9 -9
- package/chunks/chunk-ELRMZTPF.js +374 -0
- package/chunks/chunk-ERU3SDXT.js +27 -0
- package/chunks/{chunk-O2FEO2CB.js → chunk-EUURTIV6.js} +18 -2
- package/chunks/{chunk-QFJZAY7W.js → chunk-EVTNACMT.js} +3 -3
- package/chunks/{chunk-4HOEU2OR.js → chunk-EWJTAP3Y.js} +1 -19
- package/chunks/{chunk-YQGW3M6Z.js → chunk-F42YYSCK.js} +8 -8
- package/chunks/{chunk-7PD7ZMX5.js → chunk-FCQJLMA2.js} +98 -5
- package/chunks/{chunk-4VY3ITHR.js → chunk-FN3JNDRU.js} +3 -3
- package/chunks/{chunk-R457KFV7.js → chunk-GCDXVPFK.js} +3 -3
- package/chunks/{chunk-IR6JKBAP.js → chunk-GOXQL4YH.js} +2 -2
- package/chunks/{chunk-YLOHCA6I.js → chunk-GSILBZLN.js} +2 -2
- package/chunks/{chunk-LNYV4GXX.js → chunk-GSKX53AN.js} +0 -139
- package/chunks/{chunk-4WMGYG3F.js → chunk-HBQ2NXOU.js} +2 -2
- package/chunks/{chunk-F2NYVASI.js → chunk-HBU7EKY4.js} +14 -12
- package/chunks/{chunk-6G4V7SE4.js → chunk-HG46TTAG.js} +1 -1
- package/chunks/{chunk-G5VOXCRX.js → chunk-HGAELO7B.js} +2 -2
- package/chunks/{chunk-FETY36NQ.js → chunk-HGEUHUEV.js} +1 -1
- package/chunks/{chunk-E6TI726I.js → chunk-HUXPEUFL.js} +1 -1
- package/chunks/{chunk-LYT2OU7D.js → chunk-IAEXTMED.js} +1 -1
- package/chunks/{chunk-IW6RQPQB.js → chunk-IJOS26LH.js} +1 -3
- package/chunks/{chunk-ORFIYTI2.js → chunk-IK2MWJP5.js} +1 -1
- package/chunks/{chunk-WXD7INFV.js → chunk-IL5M5NYD.js} +8 -8
- package/chunks/{chunk-KA5HR3G2.js → chunk-IUVIBDKU.js} +2 -2
- package/chunks/{chunk-5DQ4YTIZ.js → chunk-IV7GDNKC.js} +1 -1
- package/chunks/chunk-JL6APGBX.js +43 -0
- package/chunks/{chunk-N6S3NUYJ.js → chunk-JXNIF2O5.js} +1 -1
- package/chunks/{chunk-DAI65CMX.js → chunk-JYKWOREU.js} +1 -1
- package/chunks/chunk-K2OJUPOE.js +78 -0
- package/chunks/{chunk-KFECPHLV.js → chunk-KFZYGSJN.js} +3 -3
- package/chunks/{chunk-BK7D2JR6.js → chunk-KOKPXIAN.js} +3 -3
- package/chunks/{chunk-4I3WFI3U.js → chunk-LDVNJZGH.js} +12 -12
- package/chunks/{chunk-WXFCI3O5.js → chunk-LG5Y4OWO.js} +2 -2
- package/chunks/{chunk-3LPJ776W.js → chunk-LILGKQ4B.js} +10 -7
- package/chunks/{chunk-X7LFJF5D.js → chunk-LK2WUCDQ.js} +36 -84
- package/chunks/{chunk-7LTCFO6T.js → chunk-MF6E7FSA.js} +6 -5
- package/chunks/{chunk-ELD3OBPU.js → chunk-MHAADZOZ.js} +3 -3
- package/chunks/{chunk-4JNHNVAZ.js → chunk-MLQNSPRZ.js} +4 -4
- package/chunks/{chunk-NPKCVSXX.js → chunk-MOS5OAOG.js} +10 -8
- package/chunks/{chunk-IWABUX6T.js → chunk-MSNHNAQZ.js} +6 -6
- package/chunks/{chunk-HJ5UJQQL.js → chunk-N7VWZDWW.js} +1699 -1312
- package/chunks/{chunk-NB3NDQQK.js → chunk-NE624IVP.js} +1 -1
- package/chunks/{chunk-SOA4HKRJ.js → chunk-NFYEQRLG.js} +2 -2
- package/chunks/{chunk-G3ZUMSFS.js → chunk-NHCZJQE4.js} +6 -6
- package/chunks/{chunk-B25JYXZE.js → chunk-NHJKAR6E.js} +4 -4
- package/chunks/{chunk-ZP5XDLSA.js → chunk-NJQTG2G3.js} +12 -12
- package/chunks/{chunk-DARWOZY6.js → chunk-NLNQNBZ2.js} +1 -1
- package/chunks/{chunk-CCBTNJB4.js → chunk-NMCDMLHL.js} +27 -27
- package/chunks/{chunk-AO2VMS72.js → chunk-NMRCXKQ5.js} +3 -3
- package/chunks/{chunk-5BH2AIEY.js → chunk-NOAG7N22.js} +2 -2
- package/chunks/{chunk-VJJXG73H.js → chunk-NRXWJXJ4.js} +15 -0
- package/chunks/chunk-NUQ4GK5I.js +315 -0
- package/chunks/{chunk-J3VZF2AL.js → chunk-NUQVB25K.js} +2 -2
- package/chunks/{chunk-U6REWGVR.js → chunk-OLTN767L.js} +2 -2
- package/chunks/{chunk-R3JIDRUL.js → chunk-OX7IZ2G5.js} +4 -4
- package/chunks/{chunk-QAZ2MGYT.js → chunk-PLLIWEM3.js} +2 -2
- package/chunks/{chunk-KCF2436G.js → chunk-POC3YMHG.js} +4 -4
- package/chunks/{chunk-HZ2HUXX7.js → chunk-Q2LVVIKF.js} +1 -1
- package/chunks/{chunk-7NDZKE2M.js → chunk-Q5BD56BW.js} +3 -3
- package/chunks/{chunk-22GORRNY.js → chunk-QMUYLYT5.js} +1 -1
- package/chunks/{chunk-MV5DTLJV.js → chunk-R4Q2PEFV.js} +1 -1
- package/chunks/{chunk-GOKAOSCN.js → chunk-RLLRJJDR.js} +1 -1
- package/chunks/{chunk-5OZUKLL7.js → chunk-RWVD5RRY.js} +4 -4
- package/chunks/{chunk-ULZECEIP.js → chunk-RZHU3K6M.js} +2 -2
- package/chunks/{chunk-UYDQYDW2.js → chunk-S6Q6Q4P2.js} +1 -1
- package/chunks/{chunk-PQEISIKS.js → chunk-SAH4BD2J.js} +0 -67
- package/chunks/{chunk-LWX4WDFF.js → chunk-SBRX4BDI.js} +43 -15
- package/chunks/{chunk-TODNHE76.js → chunk-SODMFNAR.js} +5 -5
- package/chunks/{chunk-FAJPLSYF.js → chunk-SSGAAWLY.js} +89 -85
- package/chunks/{chunk-46MMBZHI.js → chunk-SYLECP23.js} +4 -4
- package/chunks/{chunk-6RZX2HIH.js → chunk-TBEXLLAO.js} +2 -2
- package/chunks/{chunk-MWIO7MF6.js → chunk-TP6FYVQT.js} +2 -0
- package/chunks/{chunk-HRPFBHW7.js → chunk-TPKQIA7G.js} +1 -0
- package/chunks/{chunk-QHLHE2OT.js → chunk-TWUKBNWM.js} +1 -1
- package/chunks/{chunk-H3Q3RSKZ.js → chunk-U7O65WKL.js} +1 -1
- package/chunks/{chunk-S5QR6CB5.js → chunk-UKMWZ5NS.js} +108 -887
- package/chunks/{chunk-OXR34GCD.js → chunk-UKZ45TJL.js} +1851 -34
- package/chunks/{chunk-CALNF3Z3.js → chunk-V2P3DOQR.js} +1 -1
- package/chunks/{chunk-FV4DM2M4.js → chunk-VG3Q2NC4.js} +7 -7
- package/chunks/{chunk-QTNCGZHQ.js → chunk-VX63RJXE.js} +9 -0
- package/chunks/{chunk-CRZBDVP2.js → chunk-VZUCTJ2P.js} +4 -4
- package/chunks/{chunk-2BMXHB6N.js → chunk-W5FIP7FC.js} +7 -7
- package/chunks/{chunk-7VEYUF3N.js → chunk-W5ZQMAEM.js} +1 -1
- package/chunks/{chunk-XQ4RDO5B.js → chunk-WBCPROWX.js} +1 -1
- package/chunks/{chunk-JYGIJA4W.js → chunk-X6K77VHC.js} +1 -1
- package/chunks/{chunk-7SVM3RP2.js → chunk-X7UJKOHZ.js} +3 -3
- package/chunks/{chunk-WXPPUPHM.js → chunk-XBZTAGB7.js} +1 -1
- package/chunks/{chunk-TRQNRP2H.js → chunk-XGYHNWL3.js} +45 -2
- package/chunks/{chunk-2EKVPSIJ.js → chunk-Y2MYW47X.js} +1 -1
- package/chunks/{chunk-OFVAS4AR.js → chunk-YBUMTY7B.js} +1 -1
- package/chunks/{chunk-67XTVRVB.js → chunk-YQHLFCPU.js} +7 -7
- package/chunks/{chunk-G37O7YO6.js → chunk-Z3GF56ME.js} +2 -2
- package/chunks/{chunk-XBVNNDPK.js → chunk-ZHKTKHMO.js} +8 -1
- package/chunks/{chunk-OWCFKIFQ.js → chunk-ZKYR7QS4.js} +1 -1
- package/chunks/{chunk-YZTGGCEE.js → chunk-ZKZHSB5W.js} +1 -1
- package/chunks/{chunk-565U2ANU.js → chunk-ZTTC7T4X.js} +1 -1
- package/chunks/{chunk-XSOXPG2L.js → chunk-ZU47FBOC.js} +36 -7
- package/chunks/{chunk-7OCIQNKX.js → chunk-ZW2EUO2A.js} +1 -1
- package/chunks/{config-utils-GPLIABL2.js → config-utils-L6KLDYIV.js} +62 -55
- package/chunks/{contextCommand-NCUQUDBY.js → contextCommand-UYEH7NIU.js} +59 -52
- package/chunks/{core-runtime-WKYKWVYU.js → core-runtime-NVHT3Z3V.js} +61 -54
- package/chunks/{create-sub-session-TGIX63YU.js → create-sub-session-TIGCFGCS.js} +2 -2
- package/chunks/{create-sub-session-PPLXB3JJ.js → create-sub-session-YWASE5VH.js} +59 -52
- package/chunks/{cron-create-GTPVMJCF.js → cron-create-AKWX67FO.js} +1 -1
- package/chunks/{cron-delete-ZBK27Z4K.js → cron-delete-XPB6IYZJ.js} +1 -1
- package/chunks/{cron-list-KTFKFDKC.js → cron-list-XBKO4WU5.js} +1 -1
- package/chunks/{daemon-2CKIAO3I.js → daemon-G5TYKZD6.js} +2 -2
- package/chunks/{daemon-git-worktree-guard-73ZWOLKL.js → daemon-git-worktree-guard-FOW4RQSK.js} +60 -53
- package/chunks/{daemon-status-provider-OK7VONJG.js → daemon-status-provider-O5KQZYMP.js} +67 -60
- package/chunks/{daemon-trust-policy-CAUCREG2.js → daemon-trust-policy-3ATXEON7.js} +64 -57
- package/chunks/{daemon-trust-policy-monitor-3Y36OOEQ.js → daemon-trust-policy-monitor-7MCNDNEC.js} +64 -57
- package/chunks/{deferred-core-runtime-Q7WFWYD3.js → deferred-core-runtime-JK5IXL5K.js} +57 -50
- package/chunks/{display-image-CTNHJRZC.js → display-image-NAH3AZ63.js} +3 -3
- package/chunks/{dist-NP7QKLVG.js → dist-AHJYPSJL.js} +3 -3
- package/chunks/{dist-6YDUH3BB.js → dist-AIKC5E5P.js} +2 -2
- package/chunks/{dist-Y5KC3IHW.js → dist-F2DVGTL3.js} +225 -6
- package/chunks/{dist-BNQVF565.js → dist-GWNQVPZT.js} +5 -5
- package/chunks/{dist-F6JLAJLE.js → dist-H6G3K26N.js} +3 -3
- package/chunks/{dist-ZDNJK74R.js → dist-KJGRVIGJ.js} +2 -2
- package/chunks/{dist-F34J4FZX.js → dist-KLZ7XGEQ.js} +2 -2
- package/chunks/{dist-UFTFGI6I.js → dist-ZA52JXAS.js} +2 -2
- package/chunks/{dist-XLV33CLY.js → dist-ZXTZTE54.js} +2 -2
- package/chunks/{edit-YJD6IETK.js → edit-SY35KYIE.js} +45 -39
- package/chunks/{en-YJNRUQG4.js → en-CAJHTIQT.js} +1 -0
- package/chunks/{enter-worktree-YFTKHXHZ.js → enter-worktree-54L5QJ3N.js} +4 -4
- package/chunks/{enterPlanMode-EFPVTWIH.js → enterPlanMode-HXX6KQJR.js} +42 -36
- package/chunks/{environment-HP3AXFTB.js → environment-DKXHG4HB.js} +60 -53
- package/chunks/{errors-22ON46G7.js → errors-ADY7LQJJ.js} +59 -52
- package/chunks/{exit-worktree-NF2XEMES.js → exit-worktree-EORJDKDS.js} +4 -4
- package/chunks/{exitPlanMode-MOQUNCBH.js → exitPlanMode-HSK2CQI6.js} +42 -36
- package/chunks/{fast-path-2X7BPMXX.js → fast-path-U636VWN2.js} +6 -6
- package/chunks/{fast-path-settings-SATXY3PD.js → fast-path-settings-V7MI7EZJ.js} +2 -2
- package/chunks/{glob-Y7ACIB3P.js → glob-GUGGTH5L.js} +45 -39
- package/chunks/{goal-tools-DABMICUC.js → goal-tools-PXYRSQGX.js} +42 -36
- package/chunks/{grep-BLHF2S5D.js → grep-3PKFKLCA.js} +2 -2
- package/chunks/{handleAutoUpdate-MCAMHYDI.js → handleAutoUpdate-5KHS4HIN.js} +60 -53
- package/chunks/{i18n-C3GDCALP.js → i18n-KSGKMUPT.js} +58 -51
- package/chunks/{image-gen-XP4NNIYG.js → image-gen-OCCR2WWU.js} +5 -4
- package/chunks/{initializer-4URDQL2G.js → initializer-YYT5XEZF.js} +64 -57
- package/chunks/{installationInfo-LBOL6SBV.js → installationInfo-UNSBPYW2.js} +57 -50
- package/chunks/{list-JOGBAC2R.js → list-YL6LDQKQ.js} +67 -60
- package/chunks/{list-agents-2CXPGJUE.js → list-agents-QLDXS5OD.js} +17 -7
- package/chunks/{llm-2KPNSAVY.js → llm-XGGLBGPH.js} +126 -119
- package/chunks/{llm-content-generator-GR3FOHLB.js → llm-content-generator-ZHQQT5W7.js} +5 -4
- package/chunks/{loadedSettingsAdapter-DVKROEJD.js → loadedSettingsAdapter-3DXLASK7.js} +64 -57
- package/chunks/{loggingContentGenerator-P4K6K5W4.js → loggingContentGenerator-V72OCCJO.js} +64 -57
- package/chunks/{loop-wakeup-HL6XOWI4.js → loop-wakeup-HHMYIC7Z.js} +2 -2
- package/chunks/{ls-YV7RKLKY.js → ls-N7ABR6HI.js} +4 -4
- package/chunks/{lsp-NO3AMRZT.js → lsp-LTOFWG5P.js} +1 -1
- package/chunks/{managed-npm-update-VWBKHNIN.js → managed-npm-update-HV5LPZH2.js} +57 -50
- package/chunks/{mcp-6YYNSYLK.js → mcp-IYVSIW6O.js} +64 -57
- package/chunks/{monitor-A255TNZR.js → monitor-TLBNM4MV.js} +44 -38
- package/chunks/{nonInteractiveCli-LXGIKQAT.js → nonInteractiveCli-LSJSQ2W4.js} +110 -103
- package/chunks/{notebook-edit-5UYHS2DM.js → notebook-edit-OSPOLZP6.js} +43 -37
- package/chunks/openai-WX26N5OJ.js +47 -0
- package/chunks/{openaiContentGenerator-A6MAMEO5.js → openaiContentGenerator-BE4S5TRD.js} +29 -23
- package/chunks/openaiResponsesContentGenerator-RTCAJ5V5.js +1658 -0
- package/chunks/{pidfile-B7DZC4TP.js → pidfile-H32FEPWA.js} +57 -50
- package/chunks/process-registry-X6ZCASEN.js +10 -0
- package/chunks/{processUtils-BPZ2MCZS.js → processUtils-SSLIPDEA.js} +2 -2
- package/chunks/{prompt-terminal-ledger-FYYTAOXS.js → prompt-terminal-ledger-I5SLL6UF.js} +58 -51
- package/chunks/{qwenContentGenerator-4IOJFD4S.js → qwenContentGenerator-TMQC623Z.js} +55 -47
- package/chunks/{qwenOAuth2-KX6LVYQ3.js → qwenOAuth2-3ZRQHHTC.js} +4 -3
- package/chunks/{read-file-A4H4O3VQ.js → read-file-T2QAIZE2.js} +11 -9
- package/chunks/{read-mcp-resource-D3N75DGF.js → read-mcp-resource-B37WANAQ.js} +1 -1
- package/chunks/{record-artifact-Q5CRGJTP.js → record-artifact-OAXWXZ5D.js} +2 -2
- package/chunks/record-source-D7R7X3GT.js +22 -0
- package/chunks/{report-findings-TJ34R7QK.js → report-findings-AR3VC6EQ.js} +3 -3
- package/chunks/{request-shutdown-LRKMTBAD.js → request-shutdown-IKNWTX5M.js} +5 -5
- package/chunks/{resumeHistoryUtils-YQQ43E4N.js → resumeHistoryUtils-QLKDH5GY.js} +63 -56
- package/chunks/{ripGrep-W32NWFTA.js → ripGrep-YGWL7KCV.js} +15 -13
- package/chunks/{run-qwen-serve-WBSWWIRV.js → run-qwen-serve-26KZDECC.js} +127 -102
- package/chunks/{runtime-VRVBX2E5.js → runtime-BMEIVDDG.js} +70 -63
- package/chunks/{scheduled-tasks-D65KJDA3.js → scheduled-tasks-NCFPP6VQ.js} +64 -57
- package/chunks/{scheduler-M2YPN7Z7.js → scheduler-47TVMUVN.js} +59 -52
- package/chunks/{sdk-exporters-grpc-MXTVSE3C.js → sdk-exporters-grpc-Y2ZUQDUQ.js} +2 -2
- package/chunks/{sdk-exporters-http-7R2ARBPV.js → sdk-exporters-http-VWTF4W6K.js} +3 -3
- package/chunks/{sdk-impl-YOLO7LV4.js → sdk-impl-G6FVTBQZ.js} +9 -9
- package/chunks/{send-message-76BKWKFZ.js → send-message-TWOGWCBG.js} +12 -9
- package/chunks/{serve-BE3H2P6P.js → serve-KL3G6LQQ.js} +64 -57
- package/chunks/{server-FLY5JERG.js → server-LBPYXZ5G.js} +2931 -518
- package/chunks/{session-JVN62R5K.js → session-YG6742LO.js} +118 -111
- package/chunks/{session-attachments-root-7ACGLHXA.js → session-attachments-root-OUBQDYC4.js} +57 -50
- package/chunks/{session-pr-refresh-TQS57SDK.js → session-pr-refresh-EKGMYNAW.js} +64 -57
- package/chunks/{settings-D44YMZFT.js → settings-DDNHJX2L.js} +69 -62
- package/chunks/{shell-3VE6I4V5.js → shell-KUCXWITU.js} +42 -36
- package/chunks/{skill-FHEGRRZU.js → skill-JQLKPNWZ.js} +33 -23
- package/chunks/{skill-settings-VHEJMBFL.js → skill-settings-XERQCUXZ.js} +63 -56
- package/chunks/{spawnChannel-T6MX2ZDN.js → spawnChannel-GQ45QFGB.js} +60 -53
- package/chunks/{standalone-update-QUGHFMCS.js → standalone-update-PRF3ILGZ.js} +59 -52
- package/chunks/{start-opentui-ui-IHIIZ2LE.js → start-opentui-ui-JDSOZE3N.js} +174 -157
- package/chunks/{startInteractiveUI-LR7K2ARZ.js → startInteractiveUI-RRW3JVHN.js} +533 -1119
- package/chunks/{syntheticOutput-D2P5V6RG.js → syntheticOutput-F6F27JMK.js} +2 -2
- package/chunks/{task-create-MWXJFRRM.js → task-create-Y623TBHB.js} +8 -8
- package/chunks/{task-list-EYO3FE57.js → task-list-FCPEEGWL.js} +1 -1
- package/chunks/{task-stop-BFSKRTGV.js → task-stop-QTKZXLPH.js} +1 -1
- package/chunks/{task-update-2JJJRHMT.js → task-update-YLSXF25N.js} +8 -8
- package/chunks/{team-create-GY3VFY47.js → team-create-5DRLOLOE.js} +44 -38
- package/chunks/{team-delete-IQZ6XGFI.js → team-delete-S7TLHZCF.js} +1 -1
- package/chunks/{team-plan-approval-BQPGZOT5.js → team-plan-approval-MWSGAL5T.js} +42 -36
- package/chunks/{terminal-image-renderer-YNYW5CQG.js → terminal-image-renderer-H7PD4FQW.js} +59 -52
- package/chunks/{theme-manager-U6CIK3GM.js → theme-manager-7AV73D6R.js} +57 -50
- package/chunks/{todoWrite-5ERKFWAK.js → todoWrite-5QI2H2FW.js} +4 -4
- package/chunks/{tool-search-XI3QWD5I.js → tool-search-UGYTBLUV.js} +17 -15
- package/chunks/{total-session-admission-3SNSJJ32.js → total-session-admission-JIHSTJ5S.js} +62 -55
- package/chunks/{trustedFolders-OVAQKNV5.js → trustedFolders-5VCBXFOP.js} +58 -51
- package/chunks/{update-relaunch-XV5O74E3.js → update-relaunch-4LF3APCV.js} +5 -5
- package/chunks/{updateCheck-CHUYWD6L.js → updateCheck-4T3WUE5F.js} +59 -52
- package/chunks/{useAutoAcceptIndicator-VKSVIXZC.js → useAutoAcceptIndicator-UMGB64Z6.js} +67 -60
- package/chunks/{validateNonInterActiveAuth-ZNUTD3E5.js → validateNonInterActiveAuth-GFJ72U2C.js} +107 -100
- package/chunks/{version-EK7VAGSI.js → version-EAAZN4T2.js} +1 -1
- package/chunks/{web-fetch-24KZO763.js → web-fetch-VRU3A2NI.js} +13 -11
- package/chunks/{web-search-CRNXKZ2X.js → web-search-NEGYQNDJ.js} +14 -10
- package/chunks/{web-shell-static-BFDESDD4.js → web-shell-static-CCN4JZEE.js} +1 -1
- package/chunks/workflow-UHPFALVZ.js +1224 -0
- package/chunks/{workspace-providers-status-MAM42IZS.js → workspace-providers-status-AEYISSU2.js} +68 -61
- package/chunks/{workspace-registration-store-HKLJEDQX.js → workspace-registration-store-A7RGKW62.js} +3 -1
- package/chunks/{workspace-registry-7RDDOBLN.js → workspace-registry-C2NGE6SD.js} +62 -55
- package/chunks/{workspace-runtime-coordinator-LEPDPXJO.js → workspace-runtime-coordinator-QKMZ24YF.js} +63 -56
- package/chunks/{workspace-service-5IFDCNN3.js → workspace-service-RQTTAGGC.js} +70 -63
- package/chunks/{workspace-skills-status-FJ3HNH4H.js → workspace-skills-status-5HWZU3HX.js} +65 -58
- package/chunks/{workspace-trust-reconciler-PQFHIWLR.js → workspace-trust-reconciler-KFWATZUU.js} +69 -62
- package/chunks/{write-file-ERG67ZFX.js → write-file-DPVB2SBQ.js} +44 -38
- package/chunks/{zh-VBFCRQBL.js → zh-S5V3Z5CR.js} +1 -0
- package/chunks/{zh-TW-N2TBF2F2.js → zh-TW-2K2WRFPY.js} +1 -0
- package/chunks/{zoom-image-WQYEC3SR.js → zoom-image-S7AWLAPC.js} +12 -10
- package/cli.js +13 -13
- package/export-transcript-document.css +1 -0
- package/export-transcript-document.js +164 -165
- package/locales/en.js +1 -0
- package/locales/zh-TW.js +1 -0
- package/locales/zh.js +1 -0
- package/package.json +5 -4
- package/web-shell/assets/{abnfDiagram-VCTEODGH-BRLgQbnT.js → abnfDiagram-VCTEODGH-nU24rpIE.js} +1 -1
- package/web-shell/assets/{arc-qAF9_XsR.js → arc-D1hTu8QI.js} +1 -1
- package/web-shell/assets/{architectureDiagram-5GKGNRK7-BorUttEz.js → architectureDiagram-5GKGNRK7-B_fgkKe7.js} +1 -1
- package/web-shell/assets/{blockDiagram-NRAW4CY4-Bj0qZVxu.js → blockDiagram-NRAW4CY4-C3pddUNg.js} +1 -1
- package/web-shell/assets/{c4Diagram-UCG6FXSJ-BTqJis32.js → c4Diagram-UCG6FXSJ-kEFoC1ei.js} +1 -1
- package/web-shell/assets/channel-Blod4z1X.js +1 -0
- package/web-shell/assets/{chunk-2Q5K7J3B-RrQ5X8m-.js → chunk-2Q5K7J3B-DbT9wS7j.js} +1 -1
- package/web-shell/assets/{chunk-5VM5RSS4-uUjDl8wO.js → chunk-5VM5RSS4-CNbULt6O.js} +1 -1
- package/web-shell/assets/{chunk-F27PBJKO-C3JhpyzI.js → chunk-F27PBJKO-CbQRy4Tb.js} +1 -1
- package/web-shell/assets/{chunk-G27WJ6UU-C8ZNFs7F.js → chunk-G27WJ6UU-CVbXTxYk.js} +1 -1
- package/web-shell/assets/{chunk-JWPE2WC7-DNpXtEOs.js → chunk-JWPE2WC7-D89c_BXy.js} +1 -1
- package/web-shell/assets/{chunk-LCL6LL3I-DagA2ZLw.js → chunk-LCL6LL3I-B7-I_9KB.js} +1 -1
- package/web-shell/assets/{chunk-POPQ4Y6H-R23uH7Xm.js → chunk-POPQ4Y6H-DcLQFzS4.js} +1 -1
- package/web-shell/assets/{chunk-SVP7TREG-Qz9RN_BR.js → chunk-SVP7TREG-DyBb2Axj.js} +1 -1
- package/web-shell/assets/{chunk-XXDRQBXY-jYb1_hni.js → chunk-XXDRQBXY-BIA0eb5B.js} +1 -1
- package/web-shell/assets/classDiagram-DTDB5LWJ-D6hFDMqb.js +1 -0
- package/web-shell/assets/classDiagram-v2-JRS7N3AN-D6hFDMqb.js +1 -0
- package/web-shell/assets/{cose-bilkent-JH36ORCC-Cv2OunpE.js → cose-bilkent-JH36ORCC-Db2FYN85.js} +1 -1
- package/web-shell/assets/{cynefin-OW5HDTMX-LH42KFJx.js → cynefin-OW5HDTMX-i4GwmBVy.js} +1 -1
- package/web-shell/assets/{cynefinDiagram-5FMLGOSQ-Dha4_OoR.js → cynefinDiagram-5FMLGOSQ-LENf_IUy.js} +1 -1
- package/web-shell/assets/{dagre-3AP2YEHR-Br5lnUKD.js → dagre-3AP2YEHR-CF9XVrD9.js} +1 -1
- package/web-shell/assets/{diagram-S7CK7UJ4-dpKq2bBX.js → diagram-S7CK7UJ4-DD5PJfSm.js} +1 -1
- package/web-shell/assets/{diagram-UQ7AKVKN-BAgHWpXr.js → diagram-UQ7AKVKN-CjD_sBMj.js} +1 -1
- package/web-shell/assets/{diagram-VSXAHHWV-GRRzpyE2.js → diagram-VSXAHHWV-U5WwMqyA.js} +1 -1
- package/web-shell/assets/{diagram-VX7I27RA-BNFiaYpG.js → diagram-VX7I27RA-BujpHJJf.js} +1 -1
- package/web-shell/assets/{diagram-Z3DM3KII-BisZzB_h.js → diagram-Z3DM3KII-3ZLtKEXo.js} +1 -1
- package/web-shell/assets/{ebnfDiagram-PWID7BFC-B1xbwycf.js → ebnfDiagram-PWID7BFC-BGpiquRm.js} +1 -1
- package/web-shell/assets/{erDiagram-SSCWMZ5O-CQMzbGE5.js → erDiagram-SSCWMZ5O-D0besu_U.js} +1 -1
- package/web-shell/assets/{flowDiagram-A5DVABFB-CZ_Zondl.js → flowDiagram-A5DVABFB-9DwDuIyr.js} +1 -1
- package/web-shell/assets/{ganttDiagram-EL5Y4UJY-BTh2ShxS.js → ganttDiagram-EL5Y4UJY-CNlsAeNr.js} +1 -1
- package/web-shell/assets/{gitGraphDiagram-WWUBYQGX-oHOB-Uxt.js → gitGraphDiagram-WWUBYQGX-C_pPFiTR.js} +1 -1
- package/web-shell/assets/{index-DWoFMu5x.js → index-BYWs4JWq.js} +1 -1
- package/web-shell/assets/index-D3YS6KuJ.js +2173 -0
- package/web-shell/assets/index-eBxK3rs2.css +36 -0
- package/web-shell/assets/{infoDiagram-RXCK75RN-C0QpudbG.js → infoDiagram-RXCK75RN-Bpai64Ll.js} +1 -1
- package/web-shell/assets/{ishikawaDiagram-5VMMS53U-a6B741uT.js → ishikawaDiagram-5VMMS53U-ktpJFq4r.js} +1 -1
- package/web-shell/assets/{journeyDiagram-EYS64GPL-Dbht9ICp.js → journeyDiagram-EYS64GPL-iz_DKgFX.js} +1 -1
- package/web-shell/assets/{kanban-definition-3QL26DDD-D4OFR8-h.js → kanban-definition-3QL26DDD-m_gG00Yt.js} +1 -1
- package/web-shell/assets/{layout-Dvdh5jRH.js → layout-qEvKgnvU.js} +1 -1
- package/web-shell/assets/{linear-Dvc6KIW2.js → linear-C6lklGdq.js} +1 -1
- package/web-shell/assets/{mermaid.core-CB36RfIb.js → mermaid.core-DSCYB_2P.js} +6 -6
- package/web-shell/assets/{mindmap-definition-FBJOCRG2-Fmqo1CjP.js → mindmap-definition-FBJOCRG2-DRQbT8w-.js} +1 -1
- package/web-shell/assets/{pegDiagram-XKGWAZYB-CCxYBoA4.js → pegDiagram-XKGWAZYB-BhD0q0i6.js} +1 -1
- package/web-shell/assets/{pieDiagram-E7YTZNPT-BVHKQFzt.js → pieDiagram-E7YTZNPT-BvIGQCSd.js} +1 -1
- package/web-shell/assets/{quadrantDiagram-AXDQQJYC-l95IznwR.js → quadrantDiagram-AXDQQJYC-BDQtfpU-.js} +1 -1
- package/web-shell/assets/{railroadDiagram-O6MQD6OU-BlLdRdXp.js → railroadDiagram-O6MQD6OU-E1g2KIFK.js} +1 -1
- package/web-shell/assets/{requirementDiagram-EFPCY7ZU-BkDLBR5w.js → requirementDiagram-EFPCY7ZU-CuerYJOe.js} +1 -1
- package/web-shell/assets/{sankeyDiagram-P5KCCOFB-jAIqRp65.js → sankeyDiagram-P5KCCOFB-CqWyCZGA.js} +1 -1
- package/web-shell/assets/{sequenceDiagram-WJ2MYXX4-f-soZYPr.js → sequenceDiagram-WJ2MYXX4-B-YWb8x4.js} +1 -1
- package/web-shell/assets/{sizeCapture-X5ZJPWSS-BzOuAfB2.js → sizeCapture-X5ZJPWSS-BB7YY4Tl.js} +1 -1
- package/web-shell/assets/{stateDiagram-HBIQ2CUA-BPLSs12r.js → stateDiagram-HBIQ2CUA-C8LDpNHS.js} +1 -1
- package/web-shell/assets/stateDiagram-v2-4QOOHH4V-C4CbdvGa.js +1 -0
- package/web-shell/assets/{swimlanes-XN3QIQJK-D-9E_RIR.js → swimlanes-XN3QIQJK-D94vOoxZ.js} +1 -1
- package/web-shell/assets/swimlanesDiagram-VK2B7HYN--QNSIOC8.js +8 -0
- package/web-shell/assets/{timeline-definition-24CTP7MA-CT56K-gV.js → timeline-definition-24CTP7MA-C9C8uEYm.js} +1 -1
- package/web-shell/assets/{vennDiagram-4TSXK5OY-B-vi4IyO.js → vennDiagram-4TSXK5OY-CYzMHbVW.js} +1 -1
- package/web-shell/assets/{wardleyDiagram-VM6X3IG4-C9O7Ju98.js → wardleyDiagram-VM6X3IG4-G9nhtLES.js} +1 -1
- package/web-shell/assets/{xychartDiagram-S5SC5T6Z-6d8w3jg2.js → xychartDiagram-S5SC5T6Z-ruD2Wjhg.js} +1 -1
- package/web-shell/index.html +29 -5
- package/chunks/chunk-V7RNNPGC.js +0 -44
- package/chunks/workflow-HD5NYMW5.js +0 -2907
- package/web-shell/assets/channel-COIuCrVH.js +0 -1
- package/web-shell/assets/classDiagram-DTDB5LWJ-DoX6OYqu.js +0 -1
- package/web-shell/assets/classDiagram-v2-JRS7N3AN-DoX6OYqu.js +0 -1
- package/web-shell/assets/index-CI1ysIEv.js +0 -2154
- package/web-shell/assets/index-CpxXGH-8.css +0 -36
- package/web-shell/assets/stateDiagram-v2-4QOOHH4V-IRul-LaT.js +0 -1
- package/web-shell/assets/swimlanesDiagram-VK2B7HYN-D6lgKepA.js +0 -8
- /package/chunks/{chunk-JA5CBKRP.js → chunk-7NXSVSFB.js} +0 -0
|
@@ -1,2907 +0,0 @@
|
|
|
1
|
-
// Force strict mode and setup for ESM
|
|
2
|
-
"use strict";
|
|
3
|
-
import {
|
|
4
|
-
compileWorkflowScript,
|
|
5
|
-
createWorkflowSandbox,
|
|
6
|
-
debugLogger,
|
|
7
|
-
deleteInlineWorkflowScript,
|
|
8
|
-
describeWorkflowCompileError,
|
|
9
|
-
extractAndStripMeta,
|
|
10
|
-
isSymlinkedRoot,
|
|
11
|
-
persistInlineWorkflowScript,
|
|
12
|
-
resolveSavedWorkflowScript,
|
|
13
|
-
writeWorkflowSnapshot
|
|
14
|
-
} from "./chunk-OXR34GCD.js";
|
|
15
|
-
import {
|
|
16
|
-
AgentEventEmitter,
|
|
17
|
-
RESUME_ARGS_TOO_LARGE_NOTE,
|
|
18
|
-
attachJsonlTranscriptWriter,
|
|
19
|
-
buildAgentTranscriptAttach,
|
|
20
|
-
buildFailureLines,
|
|
21
|
-
buildResumeCall,
|
|
22
|
-
deriveApprovalModeConfig,
|
|
23
|
-
deriveConfig,
|
|
24
|
-
deriveWorktreeConfig,
|
|
25
|
-
getRuleDisplayName,
|
|
26
|
-
getWorkflowTaskMutationKey,
|
|
27
|
-
hasUninlinableResumeArgs,
|
|
28
|
-
installSessionWorkflowRevisionWriteThrough,
|
|
29
|
-
isTerminalWorkflowStatus,
|
|
30
|
-
markWorkflowRunPersistenceActive,
|
|
31
|
-
rebuildToolRegistryOnOverride,
|
|
32
|
-
resolveExternalWorktreeDir,
|
|
33
|
-
resolveToolName,
|
|
34
|
-
toModelVisibleSubagentResult,
|
|
35
|
-
tryWithWorkflowTaskMutation
|
|
36
|
-
} from "./chunk-HJ5UJQQL.js";
|
|
37
|
-
import "./chunk-GOFAQQZA.js";
|
|
38
|
-
import "./chunk-65I7S4Z3.js";
|
|
39
|
-
import "./chunk-6HUXPLB5.js";
|
|
40
|
-
import "./chunk-TWPJO254.js";
|
|
41
|
-
import "./chunk-CQ35AJ4Z.js";
|
|
42
|
-
import "./chunk-XKBFYTCD.js";
|
|
43
|
-
import "./chunk-LYT2OU7D.js";
|
|
44
|
-
import "./chunk-7CLLH5TI.js";
|
|
45
|
-
import {
|
|
46
|
-
GitWorktreeService,
|
|
47
|
-
generateAgentWorktreeSlug,
|
|
48
|
-
writeWorktreeSessionMarker
|
|
49
|
-
} from "./chunk-HIXUUCGY.js";
|
|
50
|
-
import {
|
|
51
|
-
parsePositiveIntegerEnv
|
|
52
|
-
} from "./chunk-6PVPNMXU.js";
|
|
53
|
-
import "./chunk-565U2ANU.js";
|
|
54
|
-
import "./chunk-GSFV5RQW.js";
|
|
55
|
-
import "./chunk-IRH27ZC2.js";
|
|
56
|
-
import "./chunk-QHWCP53L.js";
|
|
57
|
-
import "./chunk-F53KKZUD.js";
|
|
58
|
-
import "./chunk-TRWQQBVH.js";
|
|
59
|
-
import "./chunk-QJNDUTOL.js";
|
|
60
|
-
import "./chunk-N6S3NUYJ.js";
|
|
61
|
-
import "./chunk-O6GEWCJA.js";
|
|
62
|
-
import "./chunk-CHEIIBT3.js";
|
|
63
|
-
import {
|
|
64
|
-
SUBAGENT_PLAN_LIFECYCLE_TOOLS
|
|
65
|
-
} from "./chunk-QAZ2MGYT.js";
|
|
66
|
-
import "./chunk-QQK4L3UU.js";
|
|
67
|
-
import "./chunk-CH2YDT6X.js";
|
|
68
|
-
import "./chunk-JX6XHPTX.js";
|
|
69
|
-
import "./chunk-CLKE4IY3.js";
|
|
70
|
-
import "./chunk-ZSTCM3MX.js";
|
|
71
|
-
import "./chunk-SOA4HKRJ.js";
|
|
72
|
-
import "./chunk-MLXTMF7H.js";
|
|
73
|
-
import "./chunk-3LPJ776W.js";
|
|
74
|
-
import "./chunk-3CZ2BQV6.js";
|
|
75
|
-
import "./chunk-PQEISIKS.js";
|
|
76
|
-
import "./chunk-S5QR6CB5.js";
|
|
77
|
-
import {
|
|
78
|
-
runWithAgentContext
|
|
79
|
-
} from "./chunk-H3Q3RSKZ.js";
|
|
80
|
-
import "./chunk-S6LOFUVP.js";
|
|
81
|
-
import "./chunk-NAVJD2PQ.js";
|
|
82
|
-
import "./chunk-OFVAS4AR.js";
|
|
83
|
-
import "./chunk-HNLMYDQE.js";
|
|
84
|
-
import "./chunk-QHMLYMMS.js";
|
|
85
|
-
import "./chunk-CFKIH3D3.js";
|
|
86
|
-
import "./chunk-VBLAI2HA.js";
|
|
87
|
-
import {
|
|
88
|
-
createAbortController,
|
|
89
|
-
createChildAbortController
|
|
90
|
-
} from "./chunk-DJ2GSRLV.js";
|
|
91
|
-
import "./chunk-4ALNJDHL.js";
|
|
92
|
-
import "./chunk-NOO4QFXM.js";
|
|
93
|
-
import "./chunk-KFFCDLKV.js";
|
|
94
|
-
import "./chunk-7OCIQNKX.js";
|
|
95
|
-
import {
|
|
96
|
-
WorkflowRunEvent,
|
|
97
|
-
logWorkflowRun,
|
|
98
|
-
read,
|
|
99
|
-
writeLine
|
|
100
|
-
} from "./chunk-F2NYVASI.js";
|
|
101
|
-
import "./chunk-5ETULJLP.js";
|
|
102
|
-
import "./chunk-XBVNNDPK.js";
|
|
103
|
-
import "./chunk-VGC4I5JJ.js";
|
|
104
|
-
import {
|
|
105
|
-
isWithinRoot
|
|
106
|
-
} from "./chunk-J6MB5ZHZ.js";
|
|
107
|
-
import "./chunk-EDIDYZBT.js";
|
|
108
|
-
import "./chunk-HD7O6WLV.js";
|
|
109
|
-
import "./chunk-WZAD4ZNJ.js";
|
|
110
|
-
import "./chunk-FPGTNKCP.js";
|
|
111
|
-
import "./chunk-TIGXX4PA.js";
|
|
112
|
-
import "./chunk-JO77FGNZ.js";
|
|
113
|
-
import "./chunk-XFFRI3WM.js";
|
|
114
|
-
import "./chunk-4HOEU2OR.js";
|
|
115
|
-
import "./chunk-HHJLM3WQ.js";
|
|
116
|
-
import {
|
|
117
|
-
stripAnsiAndControl
|
|
118
|
-
} from "./chunk-7VEYUF3N.js";
|
|
119
|
-
import "./chunk-74TONY4F.js";
|
|
120
|
-
import {
|
|
121
|
-
SyntheticOutputTool
|
|
122
|
-
} from "./chunk-E6TI726I.js";
|
|
123
|
-
import "./chunk-4VY3ITHR.js";
|
|
124
|
-
import "./chunk-O2FEO2CB.js";
|
|
125
|
-
import "./chunk-G6UUOCUT.js";
|
|
126
|
-
import "./chunk-IZ2U57NY.js";
|
|
127
|
-
import {
|
|
128
|
-
BaseDeclarativeTool,
|
|
129
|
-
BaseToolInvocation,
|
|
130
|
-
ToolDisplayNames,
|
|
131
|
-
ToolNames
|
|
132
|
-
} from "./chunk-MWIO7MF6.js";
|
|
133
|
-
import {
|
|
134
|
-
createDebugLogger
|
|
135
|
-
} from "./chunk-ZAFYHRVY.js";
|
|
136
|
-
import "./chunk-75DOP5OR.js";
|
|
137
|
-
import "./chunk-DMTGGOSA.js";
|
|
138
|
-
import "./chunk-YQ3U5MUC.js";
|
|
139
|
-
import "./chunk-MATEIJZF.js";
|
|
140
|
-
import "./chunk-TBWQLLFO.js";
|
|
141
|
-
import {
|
|
142
|
-
init_esbuild_shims
|
|
143
|
-
} from "./chunk-5O2XNYP6.js";
|
|
144
|
-
import {
|
|
145
|
-
__name
|
|
146
|
-
} from "./chunk-J2S4EL5Y.js";
|
|
147
|
-
|
|
148
|
-
// packages/core/src/tools/workflow/workflow.ts
|
|
149
|
-
init_esbuild_shims();
|
|
150
|
-
|
|
151
|
-
// packages/core/src/agents/runtime/workflow-orchestrator.ts
|
|
152
|
-
init_esbuild_shims();
|
|
153
|
-
import { randomBytes } from "node:crypto";
|
|
154
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
155
|
-
import * as os from "node:os";
|
|
156
|
-
|
|
157
|
-
// packages/core/src/agents/runtime/workflow-budget.ts
|
|
158
|
-
init_esbuild_shims();
|
|
159
|
-
var debugLogger2 = createDebugLogger("WORKFLOW_BUDGET");
|
|
160
|
-
var MAX_TOKENS_PER_WORKFLOW_ENV = "QWEN_CODE_MAX_TOKENS_PER_WORKFLOW";
|
|
161
|
-
var HARD_MAX_TOKENS_CEILING = 1e8;
|
|
162
|
-
function resolveMaxTokensPerWorkflow(env = process.env) {
|
|
163
|
-
const raw = env[MAX_TOKENS_PER_WORKFLOW_ENV];
|
|
164
|
-
if (raw === void 0 || raw.trim() === "") {
|
|
165
|
-
return null;
|
|
166
|
-
}
|
|
167
|
-
const parsed = parsePositiveIntegerEnv(raw, 0);
|
|
168
|
-
if (parsed < 1) {
|
|
169
|
-
debugLogger2.warn(
|
|
170
|
-
`Invalid ${MAX_TOKENS_PER_WORKFLOW_ENV}=${JSON.stringify(raw)}, treating as unset (no cap)`
|
|
171
|
-
);
|
|
172
|
-
return null;
|
|
173
|
-
}
|
|
174
|
-
if (parsed > HARD_MAX_TOKENS_CEILING) {
|
|
175
|
-
debugLogger2.warn(
|
|
176
|
-
`${MAX_TOKENS_PER_WORKFLOW_ENV}=${parsed} exceeds hard ceiling (${HARD_MAX_TOKENS_CEILING}); clamping.`
|
|
177
|
-
);
|
|
178
|
-
return HARD_MAX_TOKENS_CEILING;
|
|
179
|
-
}
|
|
180
|
-
return parsed;
|
|
181
|
-
}
|
|
182
|
-
__name(resolveMaxTokensPerWorkflow, "resolveMaxTokensPerWorkflow");
|
|
183
|
-
var WorkflowBudgetImpl = class _WorkflowBudgetImpl {
|
|
184
|
-
static {
|
|
185
|
-
__name(this, "WorkflowBudgetImpl");
|
|
186
|
-
}
|
|
187
|
-
total;
|
|
188
|
-
_spent;
|
|
189
|
-
constructor(total) {
|
|
190
|
-
this.total = total;
|
|
191
|
-
this._spent = 0;
|
|
192
|
-
}
|
|
193
|
-
spent() {
|
|
194
|
-
return this._spent;
|
|
195
|
-
}
|
|
196
|
-
remaining() {
|
|
197
|
-
if (this.total === null) return Infinity;
|
|
198
|
-
return Math.max(0, this.total - this._spent);
|
|
199
|
-
}
|
|
200
|
-
/**
|
|
201
|
-
* Host-side increment. NOT exposed to the script — the
|
|
202
|
-
* `WorkflowBudget` interface deliberately omits any setter so a
|
|
203
|
-
* malicious workflow cannot inflate / deflate the budget. Only the
|
|
204
|
-
* orchestrator (in `countedDispatch`) calls this after a dispatch
|
|
205
|
-
* resolves with the agent's output token count.
|
|
206
|
-
*
|
|
207
|
-
* Non-positive deltas are silently dropped (some dispatches return
|
|
208
|
-
* `output_tokens: 0` on early failures); negative deltas would be a
|
|
209
|
-
* caller bug and are also dropped rather than silently rewinding
|
|
210
|
-
* the counter.
|
|
211
|
-
*/
|
|
212
|
-
recordSpent(deltaTokens) {
|
|
213
|
-
if (!Number.isFinite(deltaTokens) || deltaTokens <= 0) return;
|
|
214
|
-
this._spent += deltaTokens;
|
|
215
|
-
}
|
|
216
|
-
/**
|
|
217
|
-
* Factory: build a budget from the current environment. Convenience
|
|
218
|
-
* over `new WorkflowBudgetImpl(resolveMaxTokensPerWorkflow(env))`.
|
|
219
|
-
*/
|
|
220
|
-
static fromEnv(env = process.env) {
|
|
221
|
-
return new _WorkflowBudgetImpl(resolveMaxTokensPerWorkflow(env));
|
|
222
|
-
}
|
|
223
|
-
};
|
|
224
|
-
var WorkflowBudgetExceededError = class extends Error {
|
|
225
|
-
static {
|
|
226
|
-
__name(this, "WorkflowBudgetExceededError");
|
|
227
|
-
}
|
|
228
|
-
name = "WorkflowBudgetExceededError";
|
|
229
|
-
runId;
|
|
230
|
-
budgetTotal;
|
|
231
|
-
spent;
|
|
232
|
-
constructor(runId, budgetTotal, spent) {
|
|
233
|
-
super(
|
|
234
|
-
`Workflow ${runId} exceeded the token budget (${spent} / ${budgetTotal} output tokens spent).`
|
|
235
|
-
);
|
|
236
|
-
this.runId = runId;
|
|
237
|
-
this.budgetTotal = budgetTotal;
|
|
238
|
-
this.spent = spent;
|
|
239
|
-
}
|
|
240
|
-
};
|
|
241
|
-
|
|
242
|
-
// packages/core/src/agents/runtime/workflow-agent-failure.ts
|
|
243
|
-
init_esbuild_shims();
|
|
244
|
-
var WorkflowAgentFailedError = class extends Error {
|
|
245
|
-
static {
|
|
246
|
-
__name(this, "WorkflowAgentFailedError");
|
|
247
|
-
}
|
|
248
|
-
name = "WorkflowAgentFailedError";
|
|
249
|
-
kind;
|
|
250
|
-
terminateMode;
|
|
251
|
-
constructor(message, kind, terminateMode) {
|
|
252
|
-
super(message);
|
|
253
|
-
this.kind = kind;
|
|
254
|
-
this.terminateMode = terminateMode;
|
|
255
|
-
}
|
|
256
|
-
};
|
|
257
|
-
function isWorkflowAgentFailedError(error) {
|
|
258
|
-
return typeof error === "object" && error !== null && error.name === "WorkflowAgentFailedError";
|
|
259
|
-
}
|
|
260
|
-
__name(isWorkflowAgentFailedError, "isWorkflowAgentFailedError");
|
|
261
|
-
var WorkflowAgentCapExceededError = class extends Error {
|
|
262
|
-
static {
|
|
263
|
-
__name(this, "WorkflowAgentCapExceededError");
|
|
264
|
-
}
|
|
265
|
-
name = "WorkflowAgentCapExceededError";
|
|
266
|
-
constructor(maxAgents) {
|
|
267
|
-
super(
|
|
268
|
-
`Workflow exceeded the maximum of ${maxAgents} agent() calls per run.`
|
|
269
|
-
);
|
|
270
|
-
}
|
|
271
|
-
};
|
|
272
|
-
function isWorkflowRunLevelError(error) {
|
|
273
|
-
if (typeof error !== "object" || error === null) return false;
|
|
274
|
-
const name = error.name;
|
|
275
|
-
return name === "WorkflowBudgetExceededError" || name === "WorkflowAgentCapExceededError";
|
|
276
|
-
}
|
|
277
|
-
__name(isWorkflowRunLevelError, "isWorkflowRunLevelError");
|
|
278
|
-
var WORKFLOW_ABORT_REASON_STALLED = "stalled";
|
|
279
|
-
|
|
280
|
-
// packages/core/src/agents/runtime/workflow-stall.ts
|
|
281
|
-
init_esbuild_shims();
|
|
282
|
-
var DEFAULT_STALL_MS = 18e4;
|
|
283
|
-
var MAX_STALL_ATTEMPTS = 3;
|
|
284
|
-
var MAX_WORKFLOW_STALL_MS_ENV = "QWEN_CODE_WORKFLOW_STALL_SECONDS";
|
|
285
|
-
function resolveStallMs(perCall, env = process.env) {
|
|
286
|
-
if (typeof perCall === "number" && Number.isFinite(perCall)) {
|
|
287
|
-
if (perCall === 0) return 0;
|
|
288
|
-
if (perCall > 0) return perCall;
|
|
289
|
-
}
|
|
290
|
-
const raw = env[MAX_WORKFLOW_STALL_MS_ENV];
|
|
291
|
-
const trimmed = raw?.trim();
|
|
292
|
-
if (trimmed) {
|
|
293
|
-
if (trimmed === "0") return 0;
|
|
294
|
-
const sec = parsePositiveIntegerEnv(trimmed, 0);
|
|
295
|
-
if (sec > 0) return sec * 1e3;
|
|
296
|
-
}
|
|
297
|
-
return DEFAULT_STALL_MS;
|
|
298
|
-
}
|
|
299
|
-
__name(resolveStallMs, "resolveStallMs");
|
|
300
|
-
var debugLogger3 = createDebugLogger("WORKFLOW_STALL");
|
|
301
|
-
function attachStallWatchdog(emitter, controller, stallMs) {
|
|
302
|
-
if (stallMs <= 0) {
|
|
303
|
-
return { stalled: /* @__PURE__ */ __name(() => false, "stalled"), dispose: /* @__PURE__ */ __name(() => {
|
|
304
|
-
}, "dispose") };
|
|
305
|
-
}
|
|
306
|
-
let inFlightTools = 0;
|
|
307
|
-
let fired = false;
|
|
308
|
-
let timer;
|
|
309
|
-
let disposed = false;
|
|
310
|
-
const clear = /* @__PURE__ */ __name(() => {
|
|
311
|
-
if (timer) {
|
|
312
|
-
clearTimeout(timer);
|
|
313
|
-
timer = void 0;
|
|
314
|
-
}
|
|
315
|
-
}, "clear");
|
|
316
|
-
const arm = /* @__PURE__ */ __name(() => {
|
|
317
|
-
clear();
|
|
318
|
-
if (disposed || fired) return;
|
|
319
|
-
if (inFlightTools > 0) return;
|
|
320
|
-
timer = setTimeout(() => {
|
|
321
|
-
if (disposed || fired) return;
|
|
322
|
-
fired = true;
|
|
323
|
-
debugLogger3.warn(
|
|
324
|
-
`[Workflow] agent dispatch stalled \u2014 no progress for ${stallMs}ms; aborting.`
|
|
325
|
-
);
|
|
326
|
-
try {
|
|
327
|
-
controller.abort(WORKFLOW_ABORT_REASON_STALLED);
|
|
328
|
-
} catch (e) {
|
|
329
|
-
debugLogger3.warn("stall watchdog abort threw:", e);
|
|
330
|
-
}
|
|
331
|
-
}, stallMs);
|
|
332
|
-
if (typeof timer.unref === "function") {
|
|
333
|
-
timer.unref();
|
|
334
|
-
}
|
|
335
|
-
}, "arm");
|
|
336
|
-
const onActivity = /* @__PURE__ */ __name(() => arm(), "onActivity");
|
|
337
|
-
const onToolCall = /* @__PURE__ */ __name(() => {
|
|
338
|
-
inFlightTools += 1;
|
|
339
|
-
clear();
|
|
340
|
-
}, "onToolCall");
|
|
341
|
-
const onToolResult = /* @__PURE__ */ __name(() => {
|
|
342
|
-
inFlightTools = Math.max(0, inFlightTools - 1);
|
|
343
|
-
arm();
|
|
344
|
-
}, "onToolResult");
|
|
345
|
-
emitter.on("round_start" /* ROUND_START */, onActivity);
|
|
346
|
-
emitter.on("round_end" /* ROUND_END */, onActivity);
|
|
347
|
-
emitter.on("stream_text" /* STREAM_TEXT */, onActivity);
|
|
348
|
-
emitter.on("usage_metadata" /* USAGE_METADATA */, onActivity);
|
|
349
|
-
emitter.on("tool_call" /* TOOL_CALL */, onToolCall);
|
|
350
|
-
emitter.on("tool_result" /* TOOL_RESULT */, onToolResult);
|
|
351
|
-
return {
|
|
352
|
-
stalled: /* @__PURE__ */ __name(() => fired, "stalled"),
|
|
353
|
-
dispose: /* @__PURE__ */ __name(() => {
|
|
354
|
-
if (disposed) return;
|
|
355
|
-
disposed = true;
|
|
356
|
-
clear();
|
|
357
|
-
emitter.off("round_start" /* ROUND_START */, onActivity);
|
|
358
|
-
emitter.off("round_end" /* ROUND_END */, onActivity);
|
|
359
|
-
emitter.off("stream_text" /* STREAM_TEXT */, onActivity);
|
|
360
|
-
emitter.off("usage_metadata" /* USAGE_METADATA */, onActivity);
|
|
361
|
-
emitter.off("tool_call" /* TOOL_CALL */, onToolCall);
|
|
362
|
-
emitter.off("tool_result" /* TOOL_RESULT */, onToolResult);
|
|
363
|
-
}, "dispose")
|
|
364
|
-
};
|
|
365
|
-
}
|
|
366
|
-
__name(attachStallWatchdog, "attachStallWatchdog");
|
|
367
|
-
async function runStallResilient(attemptFn, opts) {
|
|
368
|
-
const { stallMs, signal, label } = opts;
|
|
369
|
-
if (stallMs <= 0) {
|
|
370
|
-
const emitter = new AgentEventEmitter();
|
|
371
|
-
return attemptFn(signal ?? new AbortController().signal, emitter);
|
|
372
|
-
}
|
|
373
|
-
let attempt = 0;
|
|
374
|
-
for (; ; ) {
|
|
375
|
-
attempt += 1;
|
|
376
|
-
const controller = new AbortController();
|
|
377
|
-
let onParentAbort;
|
|
378
|
-
if (signal) {
|
|
379
|
-
if (signal.aborted) {
|
|
380
|
-
controller.abort(signal.reason);
|
|
381
|
-
} else {
|
|
382
|
-
onParentAbort = /* @__PURE__ */ __name(() => controller.abort(signal.reason), "onParentAbort");
|
|
383
|
-
signal.addEventListener("abort", onParentAbort);
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
const emitter = new AgentEventEmitter();
|
|
387
|
-
const watchdog = attachStallWatchdog(emitter, controller, stallMs);
|
|
388
|
-
try {
|
|
389
|
-
return await attemptFn(controller.signal, emitter);
|
|
390
|
-
} catch (err) {
|
|
391
|
-
if (signal?.aborted) throw err;
|
|
392
|
-
if (watchdog.stalled() && attempt < MAX_STALL_ATTEMPTS) {
|
|
393
|
-
debugLogger3.warn(
|
|
394
|
-
`[Workflow] agent "${label ?? "workflow-agent"}" stalled (attempt ${attempt}/${MAX_STALL_ATTEMPTS}) \u2014 retrying.`
|
|
395
|
-
);
|
|
396
|
-
continue;
|
|
397
|
-
}
|
|
398
|
-
if (watchdog.stalled()) {
|
|
399
|
-
throw new WorkflowAgentFailedError(
|
|
400
|
-
`agent "${label ?? "workflow-agent"}" stalled on all ${MAX_STALL_ATTEMPTS} attempts (no progress for ${stallMs}ms each).`,
|
|
401
|
-
"stalled"
|
|
402
|
-
);
|
|
403
|
-
}
|
|
404
|
-
throw err;
|
|
405
|
-
} finally {
|
|
406
|
-
watchdog.dispose();
|
|
407
|
-
if (onParentAbort && signal) {
|
|
408
|
-
signal.removeEventListener("abort", onParentAbort);
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
__name(runStallResilient, "runStallResilient");
|
|
414
|
-
|
|
415
|
-
// packages/core/src/agents/runtime/workflow-journal.ts
|
|
416
|
-
init_esbuild_shims();
|
|
417
|
-
import { createHash } from "node:crypto";
|
|
418
|
-
import { constants, promises as fs } from "node:fs";
|
|
419
|
-
import path from "node:path";
|
|
420
|
-
var debugLogger4 = createDebugLogger("WORKFLOW_JOURNAL");
|
|
421
|
-
var JOURNAL_KEY_VERSION = "v2";
|
|
422
|
-
function canonicalizeAgentOpts(opts) {
|
|
423
|
-
const projected = {};
|
|
424
|
-
for (const k of [
|
|
425
|
-
"schema",
|
|
426
|
-
"model",
|
|
427
|
-
"isolation",
|
|
428
|
-
"agentType",
|
|
429
|
-
"workingDir"
|
|
430
|
-
]) {
|
|
431
|
-
const v = opts[k];
|
|
432
|
-
if (v === void 0 || typeof v === "function") continue;
|
|
433
|
-
projected[k] = v;
|
|
434
|
-
}
|
|
435
|
-
const sortDeep = /* @__PURE__ */ __name((val) => {
|
|
436
|
-
if (typeof val === "function") return void 0;
|
|
437
|
-
if (Array.isArray(val)) return val.map(sortDeep);
|
|
438
|
-
if (val && typeof val === "object") {
|
|
439
|
-
const out = {};
|
|
440
|
-
for (const key of Object.keys(val).sort()) {
|
|
441
|
-
if (key === "__proto__") continue;
|
|
442
|
-
out[key] = sortDeep(val[key]);
|
|
443
|
-
}
|
|
444
|
-
return out;
|
|
445
|
-
}
|
|
446
|
-
return val;
|
|
447
|
-
}, "sortDeep");
|
|
448
|
-
try {
|
|
449
|
-
return JSON.stringify(sortDeep(projected));
|
|
450
|
-
} catch {
|
|
451
|
-
return "{}";
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
__name(canonicalizeAgentOpts, "canonicalizeAgentOpts");
|
|
455
|
-
function deriveAgentKey(prefixHash, prompt, opts) {
|
|
456
|
-
const hash = createHash("sha256");
|
|
457
|
-
hash.update(prefixHash);
|
|
458
|
-
hash.update("\0");
|
|
459
|
-
hash.update(prompt);
|
|
460
|
-
hash.update("\0");
|
|
461
|
-
hash.update(canonicalizeAgentOpts(opts));
|
|
462
|
-
return `${JOURNAL_KEY_VERSION}:${hash.digest("hex")}`;
|
|
463
|
-
}
|
|
464
|
-
__name(deriveAgentKey, "deriveAgentKey");
|
|
465
|
-
function deriveArgsSeed(args) {
|
|
466
|
-
const hash = createHash("sha256");
|
|
467
|
-
let serialized;
|
|
468
|
-
try {
|
|
469
|
-
serialized = JSON.stringify(args ?? null) ?? "null";
|
|
470
|
-
} catch {
|
|
471
|
-
serialized = "non-serializable-args";
|
|
472
|
-
}
|
|
473
|
-
hash.update(serialized);
|
|
474
|
-
return `${JOURNAL_KEY_VERSION}:${hash.digest("hex")}`;
|
|
475
|
-
}
|
|
476
|
-
__name(deriveArgsSeed, "deriveArgsSeed");
|
|
477
|
-
function buildReplay(entries) {
|
|
478
|
-
const results = /* @__PURE__ */ new Map();
|
|
479
|
-
const started = /* @__PURE__ */ new Map();
|
|
480
|
-
const failed = /* @__PURE__ */ new Set();
|
|
481
|
-
for (const e of entries) {
|
|
482
|
-
if (e.type === "result") {
|
|
483
|
-
results.set(e.key, e);
|
|
484
|
-
} else if (e.type === "started") {
|
|
485
|
-
failed.delete(e.key);
|
|
486
|
-
const list = started.get(e.key);
|
|
487
|
-
if (list) list.push(e);
|
|
488
|
-
else started.set(e.key, [e]);
|
|
489
|
-
} else if (e.type === "failed") {
|
|
490
|
-
failed.add(e.key);
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
return { results, started, failed };
|
|
494
|
-
}
|
|
495
|
-
__name(buildReplay, "buildReplay");
|
|
496
|
-
var WorkflowJournal = class {
|
|
497
|
-
constructor(journalPath, root = path.dirname(path.dirname(journalPath))) {
|
|
498
|
-
this.root = root;
|
|
499
|
-
this.path = journalPath;
|
|
500
|
-
}
|
|
501
|
-
static {
|
|
502
|
-
__name(this, "WorkflowJournal");
|
|
503
|
-
}
|
|
504
|
-
pending = Promise.resolve();
|
|
505
|
-
path;
|
|
506
|
-
async hasSymlinkedPath() {
|
|
507
|
-
if (await isSymlinkedRoot(this.root) || await isSymlinkedRoot(path.dirname(this.path))) {
|
|
508
|
-
return true;
|
|
509
|
-
}
|
|
510
|
-
return fs.lstat(this.path).then((stat) => stat.isSymbolicLink()).catch(() => false);
|
|
511
|
-
}
|
|
512
|
-
/** Ensure the advertised journal path exists without affecting the run. */
|
|
513
|
-
async ensureExists() {
|
|
514
|
-
try {
|
|
515
|
-
if (await this.hasSymlinkedPath()) return false;
|
|
516
|
-
await fs.mkdir(path.dirname(this.path), { recursive: true });
|
|
517
|
-
if (await this.hasSymlinkedPath()) return false;
|
|
518
|
-
const noFollow = process.platform === "win32" ? 0 : constants.O_NOFOLLOW;
|
|
519
|
-
const file = await fs.open(
|
|
520
|
-
this.path,
|
|
521
|
-
constants.O_APPEND | constants.O_CREAT | constants.O_WRONLY | noFollow,
|
|
522
|
-
384
|
|
523
|
-
);
|
|
524
|
-
try {
|
|
525
|
-
await file.chmod(384);
|
|
526
|
-
} finally {
|
|
527
|
-
await file.close();
|
|
528
|
-
}
|
|
529
|
-
return true;
|
|
530
|
-
} catch (error) {
|
|
531
|
-
debugLogger4.warn(
|
|
532
|
-
`WorkflowJournal.ensureExists failed for ${this.path}: ${error}`
|
|
533
|
-
);
|
|
534
|
-
return false;
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
/** Remove a never-registered run's journal file, best-effort. */
|
|
538
|
-
async remove() {
|
|
539
|
-
try {
|
|
540
|
-
if (await this.hasSymlinkedPath()) return;
|
|
541
|
-
await fs.rm(this.path, { force: true });
|
|
542
|
-
await fs.rmdir(path.dirname(this.path)).catch((error) => {
|
|
543
|
-
const code = error.code;
|
|
544
|
-
if (code !== "ENOENT" && code !== "ENOTEMPTY") throw error;
|
|
545
|
-
});
|
|
546
|
-
} catch (error) {
|
|
547
|
-
debugLogger4.warn(
|
|
548
|
-
`WorkflowJournal.remove failed for ${this.path}: ${error}`
|
|
549
|
-
);
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
/** Load + parse all entries into replay maps. Empty maps if no file. */
|
|
553
|
-
async load() {
|
|
554
|
-
try {
|
|
555
|
-
const entries = await read(this.path);
|
|
556
|
-
return buildReplay(entries);
|
|
557
|
-
} catch (e) {
|
|
558
|
-
debugLogger4.warn(`WorkflowJournal.load failed for ${this.path}: ${e}`);
|
|
559
|
-
return { results: /* @__PURE__ */ new Map(), started: /* @__PURE__ */ new Map(), failed: /* @__PURE__ */ new Set() };
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
/** Append one entry. Rejects only on I/O error (callers `.catch`). */
|
|
563
|
-
append(entry) {
|
|
564
|
-
const operation = this.pending.then(() => writeLine(this.path, entry));
|
|
565
|
-
this.pending = operation.catch(() => void 0);
|
|
566
|
-
return operation;
|
|
567
|
-
}
|
|
568
|
-
/** Wait until every append issued so far has settled. */
|
|
569
|
-
drain() {
|
|
570
|
-
return this.pending;
|
|
571
|
-
}
|
|
572
|
-
};
|
|
573
|
-
|
|
574
|
-
// packages/core/src/agents/runtime/workflow-prompts.ts
|
|
575
|
-
init_esbuild_shims();
|
|
576
|
-
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.';
|
|
577
|
-
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.";
|
|
578
|
-
|
|
579
|
-
// packages/core/src/agents/runtime/workflow-dispatch-scheduler.ts
|
|
580
|
-
init_esbuild_shims();
|
|
581
|
-
function abortError() {
|
|
582
|
-
return new DOMException("Workflow dispatch scheduler aborted.", "AbortError");
|
|
583
|
-
}
|
|
584
|
-
__name(abortError, "abortError");
|
|
585
|
-
var WorkflowDispatchScheduler = class {
|
|
586
|
-
constructor(limit, signal, onStateChange) {
|
|
587
|
-
this.limit = limit;
|
|
588
|
-
this.signal = signal;
|
|
589
|
-
if (!Number.isInteger(limit) || limit < 1) {
|
|
590
|
-
throw new Error(
|
|
591
|
-
`Workflow dispatch limit must be a positive integer, got ${String(limit)}.`
|
|
592
|
-
);
|
|
593
|
-
}
|
|
594
|
-
if (onStateChange) this.stateListeners.add(onStateChange);
|
|
595
|
-
if (signal && !signal.aborted) {
|
|
596
|
-
signal.addEventListener("abort", () => this.abortPending(), {
|
|
597
|
-
once: true
|
|
598
|
-
});
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
static {
|
|
602
|
-
__name(this, "WorkflowDispatchScheduler");
|
|
603
|
-
}
|
|
604
|
-
state = "running";
|
|
605
|
-
inFlight = 0;
|
|
606
|
-
queue = [];
|
|
607
|
-
gateWaiters = [];
|
|
608
|
-
stateListeners = /* @__PURE__ */ new Set();
|
|
609
|
-
/**
|
|
610
|
-
* Subscribe to state transitions. Returns an unsubscribe function.
|
|
611
|
-
* The constructor callback (when given) is registered as the first
|
|
612
|
-
* listener; this method lets additional observers — e.g. the sandbox's
|
|
613
|
-
* pause-aware wall-clock watchdog — hook the same transitions.
|
|
614
|
-
*/
|
|
615
|
-
onStateChange(listener) {
|
|
616
|
-
this.stateListeners.add(listener);
|
|
617
|
-
return () => {
|
|
618
|
-
this.stateListeners.delete(listener);
|
|
619
|
-
};
|
|
620
|
-
}
|
|
621
|
-
run(thunk) {
|
|
622
|
-
return new Promise((resolve2, reject) => {
|
|
623
|
-
if (this.signal?.aborted) {
|
|
624
|
-
reject(abortError());
|
|
625
|
-
return;
|
|
626
|
-
}
|
|
627
|
-
this.queue.push({
|
|
628
|
-
thunk,
|
|
629
|
-
resolve: resolve2,
|
|
630
|
-
reject
|
|
631
|
-
});
|
|
632
|
-
this.pump();
|
|
633
|
-
});
|
|
634
|
-
}
|
|
635
|
-
pause() {
|
|
636
|
-
if (this.state !== "running" || this.signal?.aborted) return false;
|
|
637
|
-
this.setState("pausing");
|
|
638
|
-
if (this.inFlight === 0) this.setState("paused");
|
|
639
|
-
return true;
|
|
640
|
-
}
|
|
641
|
-
resume() {
|
|
642
|
-
if (this.state !== "paused" || this.signal?.aborted) return false;
|
|
643
|
-
this.setState("running");
|
|
644
|
-
while (this.gateWaiters.length > 0) {
|
|
645
|
-
this.gateWaiters.shift().resolve();
|
|
646
|
-
}
|
|
647
|
-
this.pump();
|
|
648
|
-
return true;
|
|
649
|
-
}
|
|
650
|
-
waitUntilRunning() {
|
|
651
|
-
if (this.signal?.aborted) return Promise.reject(abortError());
|
|
652
|
-
if (this.state === "running") return Promise.resolve();
|
|
653
|
-
return new Promise((resolve2, reject) => {
|
|
654
|
-
this.gateWaiters.push({ resolve: resolve2, reject });
|
|
655
|
-
});
|
|
656
|
-
}
|
|
657
|
-
snapshot() {
|
|
658
|
-
return {
|
|
659
|
-
state: this.state,
|
|
660
|
-
queued: this.queue.length,
|
|
661
|
-
inFlight: this.inFlight
|
|
662
|
-
};
|
|
663
|
-
}
|
|
664
|
-
pump() {
|
|
665
|
-
while (this.state === "running" && this.inFlight < this.limit && this.queue.length > 0) {
|
|
666
|
-
const job = this.queue.shift();
|
|
667
|
-
if (this.signal?.aborted) {
|
|
668
|
-
job.reject(abortError());
|
|
669
|
-
continue;
|
|
670
|
-
}
|
|
671
|
-
this.inFlight++;
|
|
672
|
-
Promise.resolve().then(job.thunk).then(job.resolve, job.reject).finally(() => {
|
|
673
|
-
this.inFlight--;
|
|
674
|
-
if (this.state === "pausing" && this.inFlight === 0) {
|
|
675
|
-
this.setState("paused");
|
|
676
|
-
}
|
|
677
|
-
this.pump();
|
|
678
|
-
});
|
|
679
|
-
}
|
|
680
|
-
}
|
|
681
|
-
setState(state) {
|
|
682
|
-
if (this.state === state) return;
|
|
683
|
-
this.state = state;
|
|
684
|
-
const snapshot = this.snapshot();
|
|
685
|
-
for (const listener of [...this.stateListeners]) listener(snapshot);
|
|
686
|
-
}
|
|
687
|
-
abortPending() {
|
|
688
|
-
const error = abortError();
|
|
689
|
-
while (this.queue.length > 0) this.queue.shift().reject(error);
|
|
690
|
-
while (this.gateWaiters.length > 0) {
|
|
691
|
-
this.gateWaiters.shift().reject(error);
|
|
692
|
-
}
|
|
693
|
-
}
|
|
694
|
-
};
|
|
695
|
-
|
|
696
|
-
// packages/core/src/agents/runtime/workflow-orchestrator.ts
|
|
697
|
-
var DEFAULT_MAX_AGENTS_PER_RUN = 1e3;
|
|
698
|
-
var MAX_WORKFLOW_AGENTS_ENV = "QWEN_CODE_MAX_WORKFLOW_AGENTS";
|
|
699
|
-
var HARD_MAX_AGENTS_PER_RUN_CEILING = 1e4;
|
|
700
|
-
function resolveMaxAgentsPerRun(env = process.env) {
|
|
701
|
-
const raw = env[MAX_WORKFLOW_AGENTS_ENV];
|
|
702
|
-
if (raw === void 0 || raw.trim() === "") {
|
|
703
|
-
return DEFAULT_MAX_AGENTS_PER_RUN;
|
|
704
|
-
}
|
|
705
|
-
const parsed = parsePositiveIntegerEnv(raw, 0);
|
|
706
|
-
if (parsed < 1) {
|
|
707
|
-
debugLogger.warn(
|
|
708
|
-
`Invalid ${MAX_WORKFLOW_AGENTS_ENV}=${JSON.stringify(raw)}, using default (${DEFAULT_MAX_AGENTS_PER_RUN})`
|
|
709
|
-
);
|
|
710
|
-
return DEFAULT_MAX_AGENTS_PER_RUN;
|
|
711
|
-
}
|
|
712
|
-
if (parsed > HARD_MAX_AGENTS_PER_RUN_CEILING) {
|
|
713
|
-
debugLogger.warn(
|
|
714
|
-
`${MAX_WORKFLOW_AGENTS_ENV}=${parsed} exceeds hard ceiling (${HARD_MAX_AGENTS_PER_RUN_CEILING}); clamping.`
|
|
715
|
-
);
|
|
716
|
-
return HARD_MAX_AGENTS_PER_RUN_CEILING;
|
|
717
|
-
}
|
|
718
|
-
return parsed;
|
|
719
|
-
}
|
|
720
|
-
__name(resolveMaxAgentsPerRun, "resolveMaxAgentsPerRun");
|
|
721
|
-
var MAX_WORKFLOW_CONCURRENCY_ENV = "QWEN_CODE_MAX_WORKFLOW_CONCURRENCY";
|
|
722
|
-
var HARD_MAX_CONCURRENCY_CEILING = 64;
|
|
723
|
-
function resolveConcurrencyLimit(env = process.env, availableParallelism2 = os.availableParallelism) {
|
|
724
|
-
const raw = env[MAX_WORKFLOW_CONCURRENCY_ENV];
|
|
725
|
-
if (raw !== void 0 && raw.trim() !== "") {
|
|
726
|
-
const parsed = parsePositiveIntegerEnv(raw, 0);
|
|
727
|
-
if (parsed >= 1) {
|
|
728
|
-
if (parsed > HARD_MAX_CONCURRENCY_CEILING) {
|
|
729
|
-
debugLogger.warn(
|
|
730
|
-
`${MAX_WORKFLOW_CONCURRENCY_ENV}=${parsed} exceeds hard ceiling (${HARD_MAX_CONCURRENCY_CEILING}); clamping.`
|
|
731
|
-
);
|
|
732
|
-
return HARD_MAX_CONCURRENCY_CEILING;
|
|
733
|
-
}
|
|
734
|
-
return parsed;
|
|
735
|
-
}
|
|
736
|
-
debugLogger.warn(
|
|
737
|
-
`Invalid ${MAX_WORKFLOW_CONCURRENCY_ENV}=${JSON.stringify(raw)}, using cpu-derived default`
|
|
738
|
-
);
|
|
739
|
-
}
|
|
740
|
-
return Math.max(2, Math.min(16, availableParallelism2() - 2));
|
|
741
|
-
}
|
|
742
|
-
__name(resolveConcurrencyLimit, "resolveConcurrencyLimit");
|
|
743
|
-
var DEFAULT_WORKFLOW_SUBAGENT_MAX_TURNS = 50;
|
|
744
|
-
var DEFAULT_WORKFLOW_SUBAGENT_MAX_TIME_MINUTES = 10;
|
|
745
|
-
var WORKFLOW_SUBAGENT_MAX_TURNS_ENV = "QWEN_CODE_WORKFLOW_AGENT_MAX_TURNS";
|
|
746
|
-
var WORKFLOW_SUBAGENT_MAX_MINUTES_ENV = "QWEN_CODE_WORKFLOW_AGENT_MAX_MINUTES";
|
|
747
|
-
var HARD_WORKFLOW_SUBAGENT_MAX_TURNS_CEILING = 500;
|
|
748
|
-
var HARD_WORKFLOW_SUBAGENT_MAX_MINUTES_CEILING = 100;
|
|
749
|
-
function resolveSubagentBound(envName, defaultValue, ceiling, env) {
|
|
750
|
-
const raw = env[envName];
|
|
751
|
-
if (raw === void 0 || raw.trim() === "") return defaultValue;
|
|
752
|
-
const parsed = parsePositiveIntegerEnv(raw, 0);
|
|
753
|
-
if (parsed < 1) {
|
|
754
|
-
debugLogger.warn(
|
|
755
|
-
`Invalid ${envName}=${JSON.stringify(raw)}, using default (${defaultValue})`
|
|
756
|
-
);
|
|
757
|
-
return defaultValue;
|
|
758
|
-
}
|
|
759
|
-
if (parsed > ceiling) {
|
|
760
|
-
debugLogger.warn(
|
|
761
|
-
`${envName}=${parsed} exceeds hard ceiling (${ceiling}); clamping.`
|
|
762
|
-
);
|
|
763
|
-
return ceiling;
|
|
764
|
-
}
|
|
765
|
-
return parsed;
|
|
766
|
-
}
|
|
767
|
-
__name(resolveSubagentBound, "resolveSubagentBound");
|
|
768
|
-
function resolveSubagentMaxTurns(env = process.env) {
|
|
769
|
-
return resolveSubagentBound(
|
|
770
|
-
WORKFLOW_SUBAGENT_MAX_TURNS_ENV,
|
|
771
|
-
DEFAULT_WORKFLOW_SUBAGENT_MAX_TURNS,
|
|
772
|
-
HARD_WORKFLOW_SUBAGENT_MAX_TURNS_CEILING,
|
|
773
|
-
env
|
|
774
|
-
);
|
|
775
|
-
}
|
|
776
|
-
__name(resolveSubagentMaxTurns, "resolveSubagentMaxTurns");
|
|
777
|
-
function resolveSubagentMaxTimeMinutes(env = process.env) {
|
|
778
|
-
return resolveSubagentBound(
|
|
779
|
-
WORKFLOW_SUBAGENT_MAX_MINUTES_ENV,
|
|
780
|
-
DEFAULT_WORKFLOW_SUBAGENT_MAX_TIME_MINUTES,
|
|
781
|
-
HARD_WORKFLOW_SUBAGENT_MAX_MINUTES_CEILING,
|
|
782
|
-
env
|
|
783
|
-
);
|
|
784
|
-
}
|
|
785
|
-
__name(resolveSubagentMaxTimeMinutes, "resolveSubagentMaxTimeMinutes");
|
|
786
|
-
var WORKFLOW_SUBAGENT_DISALLOWED_TOOLS = [
|
|
787
|
-
ToolNames.ASK_USER_QUESTION,
|
|
788
|
-
ToolNames.SEND_MESSAGE,
|
|
789
|
-
ToolNames.MONITOR,
|
|
790
|
-
...SUBAGENT_PLAN_LIFECYCLE_TOOLS,
|
|
791
|
-
// AgentTool: workflow subagents must not spawn sub-agents even where
|
|
792
|
-
// maxSubagentDepth would permit nesting — a leaf-spawned agent would run
|
|
793
|
-
// outside the orchestrator's concurrency cap, agent counter, and token
|
|
794
|
-
// budget, and its result would bypass the script's return-value contract.
|
|
795
|
-
// The WorkflowTool itself is already excluded from every subagent; this
|
|
796
|
-
// closes the same loop for plain `agent` calls (review #6189).
|
|
797
|
-
ToolNames.AGENT
|
|
798
|
-
];
|
|
799
|
-
var WorkflowExecutionError = class extends Error {
|
|
800
|
-
constructor(message, phases, logs, meta = null) {
|
|
801
|
-
super(message);
|
|
802
|
-
this.phases = phases;
|
|
803
|
-
this.logs = logs;
|
|
804
|
-
this.meta = meta;
|
|
805
|
-
}
|
|
806
|
-
static {
|
|
807
|
-
__name(this, "WorkflowExecutionError");
|
|
808
|
-
}
|
|
809
|
-
name = "WorkflowExecutionError";
|
|
810
|
-
};
|
|
811
|
-
function generateRunId() {
|
|
812
|
-
return `wf_${randomBytes(8).toString("hex")}`;
|
|
813
|
-
}
|
|
814
|
-
__name(generateRunId, "generateRunId");
|
|
815
|
-
function sanitizeForErrorMessage(value) {
|
|
816
|
-
return stripAnsiAndControl(value);
|
|
817
|
-
}
|
|
818
|
-
__name(sanitizeForErrorMessage, "sanitizeForErrorMessage");
|
|
819
|
-
function createProductionDispatch(config, signal, onTokens, bridgeApprovalEvents) {
|
|
820
|
-
return async (prompt, opts, dispatchId) => {
|
|
821
|
-
if (typeof prompt !== "string" || prompt.length === 0) {
|
|
822
|
-
throw new Error("agent() requires a non-empty string prompt.");
|
|
823
|
-
}
|
|
824
|
-
const stallMs = resolveStallMs(
|
|
825
|
-
typeof opts.stallMs === "number" ? opts.stallMs : void 0
|
|
826
|
-
);
|
|
827
|
-
const workflowAgentId = `workflow-agent-${randomBytes(8).toString("hex")}`;
|
|
828
|
-
const agentIdentity = await resolveWorkflowAgentIdentity(config, opts);
|
|
829
|
-
let attempt = 0;
|
|
830
|
-
return runStallResilient(
|
|
831
|
-
async (attemptSignal, emitter) => {
|
|
832
|
-
attempt += 1;
|
|
833
|
-
const cleanupApprovalBridge = bridgeApprovalEvents?.(
|
|
834
|
-
emitter,
|
|
835
|
-
dispatchId
|
|
836
|
-
);
|
|
837
|
-
const cleanupTranscript = attachDispatchTranscript(
|
|
838
|
-
config,
|
|
839
|
-
workflowAgentId,
|
|
840
|
-
prompt,
|
|
841
|
-
agentIdentity.name,
|
|
842
|
-
emitter,
|
|
843
|
-
attempt
|
|
844
|
-
);
|
|
845
|
-
try {
|
|
846
|
-
return await runSingleDispatch(
|
|
847
|
-
config,
|
|
848
|
-
prompt,
|
|
849
|
-
opts,
|
|
850
|
-
attemptSignal,
|
|
851
|
-
emitter,
|
|
852
|
-
workflowAgentId,
|
|
853
|
-
agentIdentity,
|
|
854
|
-
onTokens
|
|
855
|
-
);
|
|
856
|
-
} finally {
|
|
857
|
-
cleanupTranscript();
|
|
858
|
-
cleanupApprovalBridge?.();
|
|
859
|
-
}
|
|
860
|
-
},
|
|
861
|
-
{
|
|
862
|
-
stallMs,
|
|
863
|
-
signal,
|
|
864
|
-
// The name can carry a model-authored agentType spelling — keep
|
|
865
|
-
// the stall log / abandoned error single-line the same way the
|
|
866
|
-
// "not found" throw site sanitizes it.
|
|
867
|
-
label: sanitizeForErrorMessage(agentIdentity.name)
|
|
868
|
-
}
|
|
869
|
-
);
|
|
870
|
-
};
|
|
871
|
-
}
|
|
872
|
-
__name(createProductionDispatch, "createProductionDispatch");
|
|
873
|
-
async function resolveWorkflowAgentIdentity(config, opts) {
|
|
874
|
-
if (opts.agentType) {
|
|
875
|
-
const resolved = await config.getSubagentManager().findSubagentByName(opts.agentType);
|
|
876
|
-
if (resolved) {
|
|
877
|
-
return { name: resolved.name, resolvedAgentType: resolved };
|
|
878
|
-
}
|
|
879
|
-
}
|
|
880
|
-
if (typeof opts.label === "string" && opts.label) {
|
|
881
|
-
return { name: opts.label };
|
|
882
|
-
}
|
|
883
|
-
return { name: opts.agentType || "workflow-agent" };
|
|
884
|
-
}
|
|
885
|
-
__name(resolveWorkflowAgentIdentity, "resolveWorkflowAgentIdentity");
|
|
886
|
-
function attachDispatchTranscript(config, agentId, prompt, agentName, emitter, attempt) {
|
|
887
|
-
const append = attempt > 1;
|
|
888
|
-
try {
|
|
889
|
-
const { jsonlPath, options } = buildAgentTranscriptAttach(config, agentId, {
|
|
890
|
-
agentName,
|
|
891
|
-
// The prompt the SCRIPT dispatched, seeded as the transcript's first
|
|
892
|
-
// user record — the same shape AgentTool writes, so a reader that
|
|
893
|
-
// recovers a launch prompt from a transcript needs no workflow-
|
|
894
|
-
// specific branch. A retry re-uses the first attempt's record rather
|
|
895
|
-
// than seeding a second one.
|
|
896
|
-
initialUserPrompt: append ? void 0 : prompt,
|
|
897
|
-
appendToExisting: append,
|
|
898
|
-
retryAttempt: append ? attempt : void 0
|
|
899
|
-
});
|
|
900
|
-
return attachJsonlTranscriptWriter(emitter, jsonlPath, options).cleanup;
|
|
901
|
-
} catch (error) {
|
|
902
|
-
debugLogger.warn(
|
|
903
|
-
`[Workflow] failed to attach transcript for ${agentId}: ${error}`
|
|
904
|
-
);
|
|
905
|
-
return () => {
|
|
906
|
-
};
|
|
907
|
-
}
|
|
908
|
-
}
|
|
909
|
-
__name(attachDispatchTranscript, "attachDispatchTranscript");
|
|
910
|
-
function terminalDispatchError(workflowAgentId, mode) {
|
|
911
|
-
const message = `Workflow subagent ${workflowAgentId} did not complete (terminate mode: ${mode}).`;
|
|
912
|
-
switch (mode) {
|
|
913
|
-
case "MAX_TURNS" /* MAX_TURNS */:
|
|
914
|
-
return new WorkflowAgentFailedError(message, "max_turns", mode);
|
|
915
|
-
case "TIMEOUT" /* TIMEOUT */:
|
|
916
|
-
return new WorkflowAgentFailedError(message, "timeout", mode);
|
|
917
|
-
case "ERROR" /* ERROR */:
|
|
918
|
-
return new WorkflowAgentFailedError(message, "error", mode);
|
|
919
|
-
default:
|
|
920
|
-
return new Error(message);
|
|
921
|
-
}
|
|
922
|
-
}
|
|
923
|
-
__name(terminalDispatchError, "terminalDispatchError");
|
|
924
|
-
async function runSingleDispatch(config, prompt, opts, attemptSignal, emitter, workflowAgentId, agentIdentity, onTokens) {
|
|
925
|
-
const { AgentHeadless, ContextState } = await import("./agent-headless-VZKSRH36.js");
|
|
926
|
-
const ctx = new ContextState();
|
|
927
|
-
ctx.set("task_prompt", prompt);
|
|
928
|
-
debugLogger.debug(`[workflow] Dispatch ${workflowAgentId}`);
|
|
929
|
-
if (opts.agentType === void 0 && opts.model === void 0 && opts.isolation === void 0 && opts.schema === void 0 && opts.workingDir === void 0) {
|
|
930
|
-
const subagent = await AgentHeadless.create(
|
|
931
|
-
agentIdentity.name,
|
|
932
|
-
config,
|
|
933
|
-
{
|
|
934
|
-
systemPrompt: WORKFLOW_SUBAGENT_SYSTEM_PROMPT
|
|
935
|
-
},
|
|
936
|
-
{},
|
|
937
|
-
// T11 (PR #4732 R1): bound resource ceiling so a single agent() call
|
|
938
|
-
// cannot loop the model indefinitely. Without this, runConfig was {}
|
|
939
|
-
// and the loop guards never tripped — combined with the cancellation
|
|
940
|
-
// bug below, workflows were effectively unkillable.
|
|
941
|
-
{
|
|
942
|
-
max_turns: resolveSubagentMaxTurns(),
|
|
943
|
-
max_time_minutes: resolveSubagentMaxTimeMinutes()
|
|
944
|
-
},
|
|
945
|
-
// T11 (PR #4732 R1): disallow SendMessage / ExitPlanMode to align with
|
|
946
|
-
// upstream Tg8 — closes the back-channel that would let a subagent
|
|
947
|
-
// deliver its answer via user message instead of the script's read.
|
|
948
|
-
{ tools: ["*"], disallowedTools: WORKFLOW_SUBAGENT_DISALLOWED_TOOLS },
|
|
949
|
-
// P-stall: the stall-watchdog emitter observes reasoning-loop events
|
|
950
|
-
// (round/tool/usage) to detect a hang and abort `attemptSignal`.
|
|
951
|
-
emitter,
|
|
952
|
-
void 0,
|
|
953
|
-
void 0,
|
|
954
|
-
prompt,
|
|
955
|
-
workflowAgentId
|
|
956
|
-
);
|
|
957
|
-
try {
|
|
958
|
-
await runWithAgentContext(
|
|
959
|
-
workflowAgentId,
|
|
960
|
-
() => subagent.execute(ctx, attemptSignal)
|
|
961
|
-
);
|
|
962
|
-
} finally {
|
|
963
|
-
reportTokens(subagent, opts, onTokens);
|
|
964
|
-
}
|
|
965
|
-
const mode = subagent.getTerminateMode();
|
|
966
|
-
if (mode !== "GOAL" /* GOAL */) {
|
|
967
|
-
throw terminalDispatchError(workflowAgentId, mode);
|
|
968
|
-
}
|
|
969
|
-
return toModelVisibleSubagentResult(subagent.getFinalText(), mode);
|
|
970
|
-
}
|
|
971
|
-
return runOverridePath(
|
|
972
|
-
config,
|
|
973
|
-
ctx,
|
|
974
|
-
opts,
|
|
975
|
-
attemptSignal,
|
|
976
|
-
workflowAgentId,
|
|
977
|
-
agentIdentity,
|
|
978
|
-
onTokens,
|
|
979
|
-
emitter
|
|
980
|
-
);
|
|
981
|
-
}
|
|
982
|
-
__name(runSingleDispatch, "runSingleDispatch");
|
|
983
|
-
function reportTokens(subagent, opts, onTokens) {
|
|
984
|
-
if (!onTokens) return;
|
|
985
|
-
try {
|
|
986
|
-
const summary = subagent.getExecutionSummary();
|
|
987
|
-
onTokens(summary.outputTokens, opts);
|
|
988
|
-
} catch (e) {
|
|
989
|
-
debugLogger.warn("onTokens callback threw:", e);
|
|
990
|
-
}
|
|
991
|
-
}
|
|
992
|
-
__name(reportTokens, "reportTokens");
|
|
993
|
-
async function runOverridePath(config, ctx, opts, signal, workflowAgentId, agentIdentity, onTokens, emitter) {
|
|
994
|
-
if (opts.isolation === "remote") {
|
|
995
|
-
throw new Error(
|
|
996
|
-
"agent({isolation:'remote'}) is not available in this build."
|
|
997
|
-
);
|
|
998
|
-
}
|
|
999
|
-
const subagentMgr = config.getSubagentManager();
|
|
1000
|
-
let baseConfig;
|
|
1001
|
-
if (opts.agentType !== void 0) {
|
|
1002
|
-
const resolved = agentIdentity.resolvedAgentType;
|
|
1003
|
-
if (!resolved) {
|
|
1004
|
-
const safeAgentType = sanitizeForErrorMessage(opts.agentType);
|
|
1005
|
-
throw new Error(
|
|
1006
|
-
`agent({agentType}): agent type '${safeAgentType}' not found.`
|
|
1007
|
-
);
|
|
1008
|
-
}
|
|
1009
|
-
baseConfig = resolved;
|
|
1010
|
-
} else {
|
|
1011
|
-
baseConfig = {
|
|
1012
|
-
name: agentIdentity.name,
|
|
1013
|
-
description: "Default workflow subagent (per-call overrides).",
|
|
1014
|
-
systemPrompt: WORKFLOW_SUBAGENT_SYSTEM_PROMPT,
|
|
1015
|
-
level: "session",
|
|
1016
|
-
isBuiltin: false
|
|
1017
|
-
};
|
|
1018
|
-
}
|
|
1019
|
-
let schemaSystemPrompt;
|
|
1020
|
-
if (opts.schema !== void 0) {
|
|
1021
|
-
schemaSystemPrompt = opts.agentType !== void 0 && baseConfig.systemPrompt ? `${baseConfig.systemPrompt}
|
|
1022
|
-
|
|
1023
|
-
${WORKFLOW_SUBAGENT_SYSTEM_PROMPT_WITH_SCHEMA}` : WORKFLOW_SUBAGENT_SYSTEM_PROMPT_WITH_SCHEMA;
|
|
1024
|
-
}
|
|
1025
|
-
let schemaTools;
|
|
1026
|
-
if (opts.schema !== void 0 && baseConfig.tools && baseConfig.tools.length > 0 && !baseConfig.tools.includes("*") && !baseConfig.tools.includes(ToolNames.STRUCTURED_OUTPUT)) {
|
|
1027
|
-
schemaTools = [...baseConfig.tools, ToolNames.STRUCTURED_OUTPUT];
|
|
1028
|
-
}
|
|
1029
|
-
const augmented = {
|
|
1030
|
-
...baseConfig,
|
|
1031
|
-
...opts.model !== void 0 ? { model: opts.model } : {},
|
|
1032
|
-
...schemaSystemPrompt !== void 0 ? { systemPrompt: schemaSystemPrompt } : {},
|
|
1033
|
-
...schemaTools !== void 0 ? { tools: schemaTools } : {},
|
|
1034
|
-
disallowedTools: Array.from(
|
|
1035
|
-
/* @__PURE__ */ new Set([
|
|
1036
|
-
...baseConfig.disallowedTools ?? [],
|
|
1037
|
-
...WORKFLOW_SUBAGENT_DISALLOWED_TOOLS
|
|
1038
|
-
])
|
|
1039
|
-
)
|
|
1040
|
-
};
|
|
1041
|
-
let worktreeIsolation = null;
|
|
1042
|
-
let effectiveContext = config;
|
|
1043
|
-
let approvalCleanup;
|
|
1044
|
-
if (opts.isolation !== void 0 && opts.workingDir !== void 0) {
|
|
1045
|
-
throw new Error(
|
|
1046
|
-
"agent({workingDir, isolation}): incompatible options. workingDir pins the agent to a worktree you already own; isolation creates a fresh one and removes it afterwards. Pass one."
|
|
1047
|
-
);
|
|
1048
|
-
}
|
|
1049
|
-
if (opts.isolation === "worktree") {
|
|
1050
|
-
worktreeIsolation = await provisionWorkflowWorktree(config);
|
|
1051
|
-
effectiveContext = deriveWorktreeConfig(config, worktreeIsolation.path, {
|
|
1052
|
-
customIgnoreFiles: config.getFileFilteringOptions().customIgnoreFiles
|
|
1053
|
-
});
|
|
1054
|
-
installSessionWorkflowRevisionWriteThrough(effectiveContext, config);
|
|
1055
|
-
} else if (opts.workingDir !== void 0) {
|
|
1056
|
-
if (typeof opts.workingDir !== "string" || opts.workingDir.trim().length === 0) {
|
|
1057
|
-
throw new Error(
|
|
1058
|
-
"agent({workingDir}): must be a non-empty string naming an existing git worktree of this repository."
|
|
1059
|
-
);
|
|
1060
|
-
}
|
|
1061
|
-
const resolved = await resolveExternalWorktreeDir(
|
|
1062
|
-
config,
|
|
1063
|
-
opts.workingDir,
|
|
1064
|
-
"workingDir"
|
|
1065
|
-
);
|
|
1066
|
-
if ("error" in resolved) {
|
|
1067
|
-
throw new Error(
|
|
1068
|
-
`agent({workingDir: ${sanitizeForErrorMessage(JSON.stringify(opts.workingDir))}}): ${sanitizeForErrorMessage(resolved.error)}`
|
|
1069
|
-
);
|
|
1070
|
-
}
|
|
1071
|
-
effectiveContext = deriveWorktreeConfig(config, resolved.path, {
|
|
1072
|
-
customIgnoreFiles: config.getFileFilteringOptions().customIgnoreFiles
|
|
1073
|
-
});
|
|
1074
|
-
installSessionWorkflowRevisionWriteThrough(effectiveContext, config);
|
|
1075
|
-
}
|
|
1076
|
-
if (effectiveContext !== config) {
|
|
1077
|
-
const approvalHandle = deriveApprovalModeConfig(
|
|
1078
|
-
effectiveContext,
|
|
1079
|
-
config.getApprovalMode()
|
|
1080
|
-
);
|
|
1081
|
-
approvalCleanup = approvalHandle.cleanup;
|
|
1082
|
-
effectiveContext = approvalHandle.config;
|
|
1083
|
-
}
|
|
1084
|
-
let onParentAbort;
|
|
1085
|
-
try {
|
|
1086
|
-
let schemaState = null;
|
|
1087
|
-
if (opts.schema !== void 0) {
|
|
1088
|
-
effectiveContext = await createSchemaConfigOverride(
|
|
1089
|
-
effectiveContext,
|
|
1090
|
-
opts.schema
|
|
1091
|
-
);
|
|
1092
|
-
schemaState = createSchemaModeState();
|
|
1093
|
-
}
|
|
1094
|
-
let dispatchSignal = signal;
|
|
1095
|
-
if (schemaState) {
|
|
1096
|
-
const child = new AbortController();
|
|
1097
|
-
if (signal) {
|
|
1098
|
-
if (signal.aborted) {
|
|
1099
|
-
child.abort(signal.reason);
|
|
1100
|
-
} else {
|
|
1101
|
-
onParentAbort = /* @__PURE__ */ __name(() => child.abort(signal.reason), "onParentAbort");
|
|
1102
|
-
signal.addEventListener("abort", onParentAbort);
|
|
1103
|
-
}
|
|
1104
|
-
}
|
|
1105
|
-
schemaState.abortController = child;
|
|
1106
|
-
dispatchSignal = child.signal;
|
|
1107
|
-
}
|
|
1108
|
-
const eventEmitter = emitter ?? (schemaState ? new AgentEventEmitter() : void 0);
|
|
1109
|
-
if (schemaState && eventEmitter) {
|
|
1110
|
-
attachSchemaListeners(eventEmitter, schemaState);
|
|
1111
|
-
}
|
|
1112
|
-
const { subagent, dispose } = await subagentMgr.createAgentHeadless(
|
|
1113
|
-
augmented,
|
|
1114
|
-
effectiveContext,
|
|
1115
|
-
{
|
|
1116
|
-
// Workflow always bounds resource ceiling regardless of agentType's
|
|
1117
|
-
// own runConfig / maxTurns — these are workflow-level safety bounds,
|
|
1118
|
-
// not subagent-level preferences. P5 will refine via budget.
|
|
1119
|
-
runConfigOverrides: {
|
|
1120
|
-
max_turns: resolveSubagentMaxTurns(),
|
|
1121
|
-
max_time_minutes: resolveSubagentMaxTimeMinutes()
|
|
1122
|
-
},
|
|
1123
|
-
eventEmitter,
|
|
1124
|
-
taskName: String(ctx.get("task_prompt")),
|
|
1125
|
-
subagentId: workflowAgentId
|
|
1126
|
-
}
|
|
1127
|
-
);
|
|
1128
|
-
try {
|
|
1129
|
-
try {
|
|
1130
|
-
await runWithAgentContext(
|
|
1131
|
-
workflowAgentId,
|
|
1132
|
-
() => subagent.execute(ctx, dispatchSignal)
|
|
1133
|
-
);
|
|
1134
|
-
} finally {
|
|
1135
|
-
reportTokens(subagent, opts, onTokens);
|
|
1136
|
-
}
|
|
1137
|
-
if (schemaState) {
|
|
1138
|
-
if (schemaState.result !== null) {
|
|
1139
|
-
if (worktreeIsolation) {
|
|
1140
|
-
const isolation = worktreeIsolation;
|
|
1141
|
-
worktreeIsolation = null;
|
|
1142
|
-
const preserved = await cleanupWorkflowWorktree(isolation);
|
|
1143
|
-
if (preserved) {
|
|
1144
|
-
debugLogger.info(
|
|
1145
|
-
`[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.`
|
|
1146
|
-
);
|
|
1147
|
-
}
|
|
1148
|
-
}
|
|
1149
|
-
return schemaState.result;
|
|
1150
|
-
}
|
|
1151
|
-
if (signal?.aborted) {
|
|
1152
|
-
throw new DOMException("Workflow aborted.", "AbortError");
|
|
1153
|
-
}
|
|
1154
|
-
const mode2 = subagent.getTerminateMode();
|
|
1155
|
-
if (mode2 !== "GOAL" /* GOAL */ && mode2 !== "CANCELLED" /* CANCELLED */) {
|
|
1156
|
-
throw terminalDispatchError(workflowAgentId, mode2);
|
|
1157
|
-
}
|
|
1158
|
-
if (schemaState.attempts > 2) {
|
|
1159
|
-
throw new WorkflowAgentFailedError(
|
|
1160
|
-
"subagent completed without calling StructuredOutput (after 2 in-conversation nudges).",
|
|
1161
|
-
"no_structured_output"
|
|
1162
|
-
);
|
|
1163
|
-
}
|
|
1164
|
-
throw new WorkflowAgentFailedError(
|
|
1165
|
-
"subagent completed without calling structured_output (no validation attempt \u2014 model produced plain-text content).",
|
|
1166
|
-
"no_structured_output"
|
|
1167
|
-
);
|
|
1168
|
-
}
|
|
1169
|
-
const mode = subagent.getTerminateMode();
|
|
1170
|
-
if (mode !== "GOAL" /* GOAL */) {
|
|
1171
|
-
throw terminalDispatchError(workflowAgentId, mode);
|
|
1172
|
-
}
|
|
1173
|
-
let finalText = toModelVisibleSubagentResult(
|
|
1174
|
-
subagent.getFinalText(),
|
|
1175
|
-
mode
|
|
1176
|
-
);
|
|
1177
|
-
if (worktreeIsolation) {
|
|
1178
|
-
const isolation = worktreeIsolation;
|
|
1179
|
-
worktreeIsolation = null;
|
|
1180
|
-
const preserved = await cleanupWorkflowWorktree(isolation);
|
|
1181
|
-
if (preserved && typeof finalText === "string") {
|
|
1182
|
-
finalText = appendWorktreePreservedSuffix(finalText, preserved);
|
|
1183
|
-
}
|
|
1184
|
-
}
|
|
1185
|
-
return finalText;
|
|
1186
|
-
} finally {
|
|
1187
|
-
await dispose();
|
|
1188
|
-
}
|
|
1189
|
-
} finally {
|
|
1190
|
-
if (onParentAbort && signal) {
|
|
1191
|
-
signal.removeEventListener("abort", onParentAbort);
|
|
1192
|
-
}
|
|
1193
|
-
approvalCleanup?.();
|
|
1194
|
-
if (worktreeIsolation) {
|
|
1195
|
-
try {
|
|
1196
|
-
await cleanupWorkflowWorktree(worktreeIsolation);
|
|
1197
|
-
} catch (error) {
|
|
1198
|
-
debugLogger.warn(
|
|
1199
|
-
`Workflow worktree cleanup in fallback finally failed for ${worktreeIsolation.path}: ${error instanceof Error ? error.message : String(error)}`
|
|
1200
|
-
);
|
|
1201
|
-
}
|
|
1202
|
-
}
|
|
1203
|
-
}
|
|
1204
|
-
}
|
|
1205
|
-
__name(runOverridePath, "runOverridePath");
|
|
1206
|
-
async function provisionWorkflowWorktree(config) {
|
|
1207
|
-
const cwd = config.getTargetDir();
|
|
1208
|
-
if (/\.qwen[\\/]worktrees[\\/]/.test(cwd)) {
|
|
1209
|
-
throw new Error(
|
|
1210
|
-
`agent({isolation:'worktree'}): parent is already inside a worktree (${cwd}). Nested isolation worktrees are not supported \u2014 the subagent's inherited paths would still reference the outer worktree.`
|
|
1211
|
-
);
|
|
1212
|
-
}
|
|
1213
|
-
const probe = new GitWorktreeService(cwd);
|
|
1214
|
-
const gitCheck = await probe.checkGitAvailable();
|
|
1215
|
-
if (!gitCheck.available) {
|
|
1216
|
-
throw new Error(
|
|
1217
|
-
`agent({isolation:'worktree'}): ${gitCheck.error ?? "git is not available"}.`
|
|
1218
|
-
);
|
|
1219
|
-
}
|
|
1220
|
-
if (!await probe.isGitRepository()) {
|
|
1221
|
-
throw new Error(
|
|
1222
|
-
`agent({isolation:'worktree'}): ${cwd} is not a git repository.`
|
|
1223
|
-
);
|
|
1224
|
-
}
|
|
1225
|
-
const projectRoot = await probe.getRepoTopLevel() ?? cwd;
|
|
1226
|
-
const wtService = projectRoot === cwd ? probe : new GitWorktreeService(projectRoot);
|
|
1227
|
-
let parentDirty = false;
|
|
1228
|
-
try {
|
|
1229
|
-
parentDirty = await wtService.hasWorktreeChanges(projectRoot);
|
|
1230
|
-
} catch (error) {
|
|
1231
|
-
debugLogger.warn(
|
|
1232
|
-
`[Workflow] hasWorktreeChanges failed at ${projectRoot}: ${error}`
|
|
1233
|
-
);
|
|
1234
|
-
parentDirty = true;
|
|
1235
|
-
}
|
|
1236
|
-
if (parentDirty) {
|
|
1237
|
-
throw new Error(
|
|
1238
|
-
`agent({isolation:'worktree'}): parent working tree at ${projectRoot} has uncommitted changes that would not propagate into the isolated worktree. The subagent would see the prior HEAD instead of the current state. Commit or stash the changes, then re-run.`
|
|
1239
|
-
);
|
|
1240
|
-
}
|
|
1241
|
-
const slug = generateAgentWorktreeSlug();
|
|
1242
|
-
let parentBranch;
|
|
1243
|
-
try {
|
|
1244
|
-
parentBranch = await wtService.getCurrentBranch();
|
|
1245
|
-
} catch (error) {
|
|
1246
|
-
debugLogger.warn(
|
|
1247
|
-
`[Workflow] getCurrentBranch failed at ${projectRoot}: ${error}`
|
|
1248
|
-
);
|
|
1249
|
-
}
|
|
1250
|
-
const created = await wtService.createUserWorktree(slug, parentBranch, {
|
|
1251
|
-
symlinkDirectories: config.getWorktreeSymlinkDirectories()
|
|
1252
|
-
});
|
|
1253
|
-
if (!created.success || !created.worktree) {
|
|
1254
|
-
throw new Error(
|
|
1255
|
-
`agent({isolation:'worktree'}): failed to create worktree: ${created.error ?? "unknown error"}.`
|
|
1256
|
-
);
|
|
1257
|
-
}
|
|
1258
|
-
try {
|
|
1259
|
-
await writeWorktreeSessionMarker(
|
|
1260
|
-
created.worktree.path,
|
|
1261
|
-
config.getSessionId()
|
|
1262
|
-
);
|
|
1263
|
-
} catch (error) {
|
|
1264
|
-
debugLogger.warn(
|
|
1265
|
-
`[Workflow] failed to write session marker at ${created.worktree.path}: ${error}`
|
|
1266
|
-
);
|
|
1267
|
-
}
|
|
1268
|
-
return {
|
|
1269
|
-
slug,
|
|
1270
|
-
path: created.worktree.path,
|
|
1271
|
-
branch: created.worktree.branch,
|
|
1272
|
-
repoRoot: projectRoot
|
|
1273
|
-
};
|
|
1274
|
-
}
|
|
1275
|
-
__name(provisionWorkflowWorktree, "provisionWorkflowWorktree");
|
|
1276
|
-
async function cleanupWorkflowWorktree(isolation) {
|
|
1277
|
-
const wtService = new GitWorktreeService(isolation.repoRoot);
|
|
1278
|
-
const [hasChanges, hasUnmerged] = await Promise.all([
|
|
1279
|
-
wtService.hasWorktreeChanges(isolation.path).catch((error) => {
|
|
1280
|
-
debugLogger.warn(
|
|
1281
|
-
`[Workflow] hasWorktreeChanges failed for ${isolation.path}: ${error}`
|
|
1282
|
-
);
|
|
1283
|
-
return true;
|
|
1284
|
-
}),
|
|
1285
|
-
wtService.hasUnmergedWorktreeCommits(isolation.slug).catch((error) => {
|
|
1286
|
-
debugLogger.warn(
|
|
1287
|
-
`[Workflow] hasUnmergedWorktreeCommits failed for ${isolation.slug}: ${error}`
|
|
1288
|
-
);
|
|
1289
|
-
return true;
|
|
1290
|
-
})
|
|
1291
|
-
]);
|
|
1292
|
-
if (hasChanges || hasUnmerged) {
|
|
1293
|
-
debugLogger.info(
|
|
1294
|
-
`[Workflow] Preserving isolation worktree ${isolation.path} (branch ${isolation.branch}, hasChanges=${hasChanges}, hasUnmerged=${hasUnmerged})`
|
|
1295
|
-
);
|
|
1296
|
-
return { path: isolation.path, branch: isolation.branch };
|
|
1297
|
-
}
|
|
1298
|
-
try {
|
|
1299
|
-
const result = await wtService.removeUserWorktree(isolation.slug, {
|
|
1300
|
-
deleteBranch: true
|
|
1301
|
-
});
|
|
1302
|
-
if (!result.success) {
|
|
1303
|
-
debugLogger.warn(
|
|
1304
|
-
`[Workflow] Failed to remove ephemeral worktree ${isolation.path}: ${result.error}`
|
|
1305
|
-
);
|
|
1306
|
-
return { path: isolation.path, branch: isolation.branch };
|
|
1307
|
-
}
|
|
1308
|
-
if (result.branchPreserved) {
|
|
1309
|
-
debugLogger.warn(
|
|
1310
|
-
`[Workflow] Removed worktree directory ${isolation.path} but kept branch ${isolation.branch} (unmerged commits at delete time)`
|
|
1311
|
-
);
|
|
1312
|
-
return { branch: isolation.branch };
|
|
1313
|
-
}
|
|
1314
|
-
} catch (error) {
|
|
1315
|
-
debugLogger.warn(
|
|
1316
|
-
`[Workflow] Failed to remove ephemeral worktree ${isolation.path}: ${error}`
|
|
1317
|
-
);
|
|
1318
|
-
return { path: isolation.path, branch: isolation.branch };
|
|
1319
|
-
}
|
|
1320
|
-
return null;
|
|
1321
|
-
}
|
|
1322
|
-
__name(cleanupWorkflowWorktree, "cleanupWorkflowWorktree");
|
|
1323
|
-
function appendWorktreePreservedSuffix(finalText, preserved) {
|
|
1324
|
-
const sep = finalText.endsWith("\n") ? "\n" : "\n\n";
|
|
1325
|
-
if (preserved.path) {
|
|
1326
|
-
return `${finalText}${sep}[worktree preserved: ${preserved.path} (branch ${preserved.branch})]`;
|
|
1327
|
-
}
|
|
1328
|
-
return `${finalText}${sep}[worktree directory removed; branch ${preserved.branch} preserved \u2014 recover with \`git worktree add <path> ${preserved.branch}\`]`;
|
|
1329
|
-
}
|
|
1330
|
-
__name(appendWorktreePreservedSuffix, "appendWorktreePreservedSuffix");
|
|
1331
|
-
function createSchemaModeState() {
|
|
1332
|
-
return {
|
|
1333
|
-
result: null,
|
|
1334
|
-
attempts: 0,
|
|
1335
|
-
pendingArgs: /* @__PURE__ */ new Map(),
|
|
1336
|
-
abortController: new AbortController()
|
|
1337
|
-
};
|
|
1338
|
-
}
|
|
1339
|
-
__name(createSchemaModeState, "createSchemaModeState");
|
|
1340
|
-
function attachSchemaListeners(emitter, state) {
|
|
1341
|
-
const targetTool = ToolNames.STRUCTURED_OUTPUT;
|
|
1342
|
-
emitter.on("tool_call" /* TOOL_CALL */, (evt) => {
|
|
1343
|
-
if (evt.name !== targetTool) return;
|
|
1344
|
-
state.pendingArgs.set(evt.callId, evt.args);
|
|
1345
|
-
});
|
|
1346
|
-
emitter.on("tool_result" /* TOOL_RESULT */, (evt) => {
|
|
1347
|
-
if (evt.name !== targetTool) return;
|
|
1348
|
-
const args = state.pendingArgs.get(evt.callId);
|
|
1349
|
-
state.pendingArgs.delete(evt.callId);
|
|
1350
|
-
if (evt.success) {
|
|
1351
|
-
if (args !== void 0 && state.result === null) {
|
|
1352
|
-
state.result = args;
|
|
1353
|
-
state.abortController.abort();
|
|
1354
|
-
}
|
|
1355
|
-
return;
|
|
1356
|
-
}
|
|
1357
|
-
state.attempts += 1;
|
|
1358
|
-
if (state.attempts > 2 && state.result === null) {
|
|
1359
|
-
state.abortController.abort();
|
|
1360
|
-
}
|
|
1361
|
-
});
|
|
1362
|
-
}
|
|
1363
|
-
__name(attachSchemaListeners, "attachSchemaListeners");
|
|
1364
|
-
async function createSchemaConfigOverride(base, schema) {
|
|
1365
|
-
const override = deriveConfig(base);
|
|
1366
|
-
installSessionWorkflowRevisionWriteThrough(override, base);
|
|
1367
|
-
await rebuildToolRegistryOnOverride(override, base);
|
|
1368
|
-
const registry = override.getToolRegistry();
|
|
1369
|
-
registry.registerTool(new SyntheticOutputTool(schema));
|
|
1370
|
-
return override;
|
|
1371
|
-
}
|
|
1372
|
-
__name(createSchemaConfigOverride, "createSchemaConfigOverride");
|
|
1373
|
-
var WorkflowOrchestrator = class {
|
|
1374
|
-
constructor(dispatch) {
|
|
1375
|
-
this.dispatch = dispatch;
|
|
1376
|
-
}
|
|
1377
|
-
static {
|
|
1378
|
-
__name(this, "WorkflowOrchestrator");
|
|
1379
|
-
}
|
|
1380
|
-
async run(req) {
|
|
1381
|
-
const runId = req.runId ?? generateRunId();
|
|
1382
|
-
const maxAgents = resolveMaxAgentsPerRun();
|
|
1383
|
-
const signal = req.abortOnTimeout?.signal;
|
|
1384
|
-
const scheduler = req.scheduler ?? new WorkflowDispatchScheduler(resolveConcurrencyLimit(), signal);
|
|
1385
|
-
const rejectThroughPauseGate = /* @__PURE__ */ __name((error) => scheduler.waitUntilRunning().then(
|
|
1386
|
-
() => {
|
|
1387
|
-
throw error;
|
|
1388
|
-
},
|
|
1389
|
-
() => {
|
|
1390
|
-
throw error;
|
|
1391
|
-
}
|
|
1392
|
-
), "rejectThroughPauseGate");
|
|
1393
|
-
let agentCount = 0;
|
|
1394
|
-
let dispatchTraceCount = 0;
|
|
1395
|
-
const emitter = req.emitter;
|
|
1396
|
-
const budget = req.budget;
|
|
1397
|
-
const dependencyContext = new AsyncLocalStorage();
|
|
1398
|
-
const issueDispatchTrace = /* @__PURE__ */ __name((prompt, opts, cached = false) => {
|
|
1399
|
-
const id = `dispatch-${dispatchTraceCount += 1}`;
|
|
1400
|
-
const store = dependencyContext.getStore();
|
|
1401
|
-
const dependsOn = Array.from(new Set(store?.tails ?? []));
|
|
1402
|
-
if (store) store.tails = [id];
|
|
1403
|
-
try {
|
|
1404
|
-
emitter?.dispatchQueued?.({
|
|
1405
|
-
id,
|
|
1406
|
-
...typeof opts.label === "string" ? { label: opts.label } : {},
|
|
1407
|
-
prompt,
|
|
1408
|
-
dependsOn,
|
|
1409
|
-
queuedAt: Date.now(),
|
|
1410
|
-
...cached ? { cached: true } : {}
|
|
1411
|
-
});
|
|
1412
|
-
} catch (e) {
|
|
1413
|
-
debugLogger.warn("emitter.dispatchQueued threw:", e);
|
|
1414
|
-
}
|
|
1415
|
-
return id;
|
|
1416
|
-
}, "issueDispatchTrace");
|
|
1417
|
-
const journal = req.journal;
|
|
1418
|
-
const replay = req.resumeReplay;
|
|
1419
|
-
let prefixHash = deriveArgsSeed(req.args);
|
|
1420
|
-
let hadMiss = false;
|
|
1421
|
-
let journalAgentId = 0;
|
|
1422
|
-
const parentSandboxRef = {
|
|
1423
|
-
current: void 0
|
|
1424
|
-
};
|
|
1425
|
-
const countedDispatch = /* @__PURE__ */ __name((prompt, opts) => {
|
|
1426
|
-
if (typeof prompt !== "string" || prompt.length === 0) {
|
|
1427
|
-
return rejectThroughPauseGate(
|
|
1428
|
-
new Error("agent() requires a non-empty string prompt.")
|
|
1429
|
-
);
|
|
1430
|
-
}
|
|
1431
|
-
let journalKey;
|
|
1432
|
-
let journalEntryId;
|
|
1433
|
-
let respawnLine;
|
|
1434
|
-
if (journal) {
|
|
1435
|
-
journalKey = deriveAgentKey(prefixHash, prompt, opts);
|
|
1436
|
-
prefixHash = journalKey;
|
|
1437
|
-
if (!hadMiss && replay) {
|
|
1438
|
-
const cached = replay.results.get(journalKey);
|
|
1439
|
-
if (cached !== void 0) {
|
|
1440
|
-
const respawns = replay.started.get(journalKey);
|
|
1441
|
-
if (respawns && respawns.length > 0) {
|
|
1442
|
-
debugLogger.info(
|
|
1443
|
-
`[Workflow] resume cache hit after ${respawns.length} prior respawn(s) for runId=${runId}.`
|
|
1444
|
-
);
|
|
1445
|
-
}
|
|
1446
|
-
const label2 = typeof opts.label === "string" ? opts.label : void 0;
|
|
1447
|
-
const dispatchId2 = issueDispatchTrace(prompt, opts, true);
|
|
1448
|
-
try {
|
|
1449
|
-
emitter?.agentDispatched?.(label2);
|
|
1450
|
-
} catch (e) {
|
|
1451
|
-
debugLogger.warn("emitter.agentDispatched threw:", e);
|
|
1452
|
-
}
|
|
1453
|
-
try {
|
|
1454
|
-
emitter?.agentCompleted?.(label2);
|
|
1455
|
-
} catch (e) {
|
|
1456
|
-
debugLogger.warn("emitter.agentCompleted threw:", e);
|
|
1457
|
-
}
|
|
1458
|
-
try {
|
|
1459
|
-
emitter?.dispatchSettled?.(dispatchId2, void 0, Date.now());
|
|
1460
|
-
} catch (e) {
|
|
1461
|
-
debugLogger.warn("emitter.dispatchSettled threw:", e);
|
|
1462
|
-
}
|
|
1463
|
-
return scheduler.waitUntilRunning().then(
|
|
1464
|
-
() => cached.result,
|
|
1465
|
-
() => cached.result
|
|
1466
|
-
);
|
|
1467
|
-
}
|
|
1468
|
-
}
|
|
1469
|
-
const priorStarts = replay?.started.get(journalKey);
|
|
1470
|
-
if (priorStarts && priorStarts.length > 0 && !replay?.results.has(journalKey)) {
|
|
1471
|
-
const name = typeof opts.label === "string" ? `"${stripAnsiAndControl(opts.label)}"` : "an agent";
|
|
1472
|
-
respawnLine = replay?.failed.has(journalKey) ? `[resume] re-running ${name}: it failed in the previous run` : `[resume] respawning ${name}: interrupted in a previous run (${priorStarts.length} prior attempt${priorStarts.length === 1 ? "" : "s"})`;
|
|
1473
|
-
}
|
|
1474
|
-
hadMiss = true;
|
|
1475
|
-
}
|
|
1476
|
-
if (budget && budget.total !== null && budget.remaining() <= 0) {
|
|
1477
|
-
debugLogger.warn(
|
|
1478
|
-
`[Workflow] budget gate refused dispatch at entry: runId=${runId} spent=${budget.spent()} total=${budget.total}`
|
|
1479
|
-
);
|
|
1480
|
-
return rejectThroughPauseGate(
|
|
1481
|
-
new WorkflowBudgetExceededError(runId, budget.total, budget.spent())
|
|
1482
|
-
);
|
|
1483
|
-
}
|
|
1484
|
-
if (agentCount >= maxAgents) {
|
|
1485
|
-
return rejectThroughPauseGate(
|
|
1486
|
-
new WorkflowAgentCapExceededError(maxAgents)
|
|
1487
|
-
);
|
|
1488
|
-
}
|
|
1489
|
-
agentCount += 1;
|
|
1490
|
-
if (journal && journalKey !== void 0) {
|
|
1491
|
-
journalEntryId = String(journalAgentId += 1);
|
|
1492
|
-
}
|
|
1493
|
-
const label = typeof opts.label === "string" ? opts.label : void 0;
|
|
1494
|
-
const dispatchId = issueDispatchTrace(prompt, opts);
|
|
1495
|
-
try {
|
|
1496
|
-
emitter?.agentDispatched?.(label);
|
|
1497
|
-
} catch (e) {
|
|
1498
|
-
debugLogger.warn("emitter.agentDispatched threw:", e);
|
|
1499
|
-
}
|
|
1500
|
-
let completionEmitted = false;
|
|
1501
|
-
const emitCompletion = /* @__PURE__ */ __name((error) => {
|
|
1502
|
-
if (completionEmitted) return;
|
|
1503
|
-
completionEmitted = true;
|
|
1504
|
-
const message = error === void 0 ? void 0 : error instanceof Error ? error.message : String(error);
|
|
1505
|
-
try {
|
|
1506
|
-
emitter?.agentCompleted?.(label, message);
|
|
1507
|
-
} catch (e) {
|
|
1508
|
-
debugLogger.warn("emitter.agentCompleted threw:", e);
|
|
1509
|
-
}
|
|
1510
|
-
try {
|
|
1511
|
-
emitter?.dispatchSettled?.(dispatchId, message, Date.now());
|
|
1512
|
-
} catch (e) {
|
|
1513
|
-
debugLogger.warn("emitter.dispatchSettled threw:", e);
|
|
1514
|
-
}
|
|
1515
|
-
}, "emitCompletion");
|
|
1516
|
-
return scheduler.run(async () => {
|
|
1517
|
-
try {
|
|
1518
|
-
try {
|
|
1519
|
-
emitter?.dispatchStarted?.(dispatchId, Date.now());
|
|
1520
|
-
} catch (e) {
|
|
1521
|
-
debugLogger.warn("emitter.dispatchStarted threw:", e);
|
|
1522
|
-
}
|
|
1523
|
-
if (budget && budget.total !== null && budget.remaining() <= 0) {
|
|
1524
|
-
debugLogger.warn(
|
|
1525
|
-
`[Workflow] budget gate refused dispatch at slot-acquire: runId=${runId} spent=${budget.spent()} total=${budget.total}`
|
|
1526
|
-
);
|
|
1527
|
-
throw new WorkflowBudgetExceededError(
|
|
1528
|
-
runId,
|
|
1529
|
-
budget.total,
|
|
1530
|
-
budget.spent()
|
|
1531
|
-
);
|
|
1532
|
-
}
|
|
1533
|
-
if (journal && journalKey !== void 0 && journalEntryId !== void 0) {
|
|
1534
|
-
journal.append({
|
|
1535
|
-
type: "started",
|
|
1536
|
-
key: journalKey,
|
|
1537
|
-
agentId: journalEntryId
|
|
1538
|
-
}).catch(
|
|
1539
|
-
(e) => debugLogger.warn(`journal started-append failed: ${e}`)
|
|
1540
|
-
);
|
|
1541
|
-
}
|
|
1542
|
-
if (respawnLine) {
|
|
1543
|
-
parentSandboxRef.current?.appendLog(respawnLine);
|
|
1544
|
-
try {
|
|
1545
|
-
emitter?.resumeRespawn?.(respawnLine);
|
|
1546
|
-
} catch (e) {
|
|
1547
|
-
debugLogger.warn("emitter.resumeRespawn threw:", e);
|
|
1548
|
-
}
|
|
1549
|
-
}
|
|
1550
|
-
const result = await this.dispatch(prompt, opts, dispatchId);
|
|
1551
|
-
emitCompletion();
|
|
1552
|
-
if (journal && journalKey !== void 0) {
|
|
1553
|
-
journal.append({
|
|
1554
|
-
type: "result",
|
|
1555
|
-
key: journalKey,
|
|
1556
|
-
agentId: journalEntryId ?? "",
|
|
1557
|
-
result
|
|
1558
|
-
}).catch(
|
|
1559
|
-
(e) => debugLogger.warn(`journal result-append failed: ${e}`)
|
|
1560
|
-
);
|
|
1561
|
-
}
|
|
1562
|
-
if (budget) {
|
|
1563
|
-
try {
|
|
1564
|
-
emitter?.budgetUpdated?.(budget.spent(), budget.total);
|
|
1565
|
-
} catch (e) {
|
|
1566
|
-
debugLogger.warn("emitter.budgetUpdated threw:", e);
|
|
1567
|
-
}
|
|
1568
|
-
}
|
|
1569
|
-
return result;
|
|
1570
|
-
} catch (err) {
|
|
1571
|
-
emitCompletion(err);
|
|
1572
|
-
if (budget) {
|
|
1573
|
-
try {
|
|
1574
|
-
emitter?.budgetUpdated?.(budget.spent(), budget.total);
|
|
1575
|
-
} catch (e) {
|
|
1576
|
-
debugLogger.warn("emitter.budgetUpdated threw:", e);
|
|
1577
|
-
}
|
|
1578
|
-
}
|
|
1579
|
-
if (journal && journalKey !== void 0 && !signal?.aborted && !isWorkflowRunLevelError(err)) {
|
|
1580
|
-
journal.append({
|
|
1581
|
-
type: "failed",
|
|
1582
|
-
key: journalKey,
|
|
1583
|
-
agentId: journalEntryId ?? ""
|
|
1584
|
-
}).catch(
|
|
1585
|
-
(e) => debugLogger.warn(`journal failed-append failed: ${e}`)
|
|
1586
|
-
);
|
|
1587
|
-
}
|
|
1588
|
-
if (signal?.aborted || isWorkflowRunLevelError(err)) throw err;
|
|
1589
|
-
if (isWorkflowAgentFailedError(err)) {
|
|
1590
|
-
debugLogger.warn(
|
|
1591
|
-
`[Workflow] agent settled to null (${err.kind}): ${err.message}`
|
|
1592
|
-
);
|
|
1593
|
-
} else {
|
|
1594
|
-
debugLogger.warn(
|
|
1595
|
-
`[Workflow] agent settled to null: ${extractErrorMessage(err)}`
|
|
1596
|
-
);
|
|
1597
|
-
}
|
|
1598
|
-
return null;
|
|
1599
|
-
}
|
|
1600
|
-
}).then(
|
|
1601
|
-
// Resolve even if the gate aborts: a successful dispatch must not
|
|
1602
|
-
// turn into a teardown rejection — for a fire-and-forget call the
|
|
1603
|
-
// script never attached a handler, so the rejection would surface
|
|
1604
|
-
// as a spurious process-level unhandledRejection alarm on a
|
|
1605
|
-
// correctly-cancelled run.
|
|
1606
|
-
(result) => scheduler.waitUntilRunning().then(
|
|
1607
|
-
() => result,
|
|
1608
|
-
() => result
|
|
1609
|
-
),
|
|
1610
|
-
(error) => {
|
|
1611
|
-
emitCompletion(error);
|
|
1612
|
-
return scheduler.waitUntilRunning().then(
|
|
1613
|
-
() => {
|
|
1614
|
-
throw error;
|
|
1615
|
-
},
|
|
1616
|
-
() => {
|
|
1617
|
-
throw error;
|
|
1618
|
-
}
|
|
1619
|
-
);
|
|
1620
|
-
}
|
|
1621
|
-
);
|
|
1622
|
-
}, "countedDispatch");
|
|
1623
|
-
const parallelImpl = makeParallelImpl(signal, dependencyContext);
|
|
1624
|
-
const pipelineImpl = makePipelineImpl(signal, dependencyContext);
|
|
1625
|
-
const resolveSavedWorkflow = req.resolveSavedWorkflow;
|
|
1626
|
-
const workflowImpl = resolveSavedWorkflow ? async (nameOrRef, nestedArgs) => {
|
|
1627
|
-
const resolved = await resolveSavedWorkflow(nameOrRef);
|
|
1628
|
-
const nestedSandbox = createWorkflowSandbox({
|
|
1629
|
-
args: nestedArgs,
|
|
1630
|
-
runId,
|
|
1631
|
-
dispatch: countedDispatch,
|
|
1632
|
-
parallel: parallelImpl,
|
|
1633
|
-
pipeline: pipelineImpl,
|
|
1634
|
-
abortOnTimeout: req.abortOnTimeout,
|
|
1635
|
-
emitter,
|
|
1636
|
-
budget,
|
|
1637
|
-
scheduler
|
|
1638
|
-
// No `workflow` — single-level nesting limit.
|
|
1639
|
-
});
|
|
1640
|
-
try {
|
|
1641
|
-
return await nestedSandbox.run(resolved.script);
|
|
1642
|
-
} finally {
|
|
1643
|
-
for (const line of nestedSandbox.getLogs()) {
|
|
1644
|
-
parentSandboxRef.current?.appendLog(line);
|
|
1645
|
-
}
|
|
1646
|
-
}
|
|
1647
|
-
} : void 0;
|
|
1648
|
-
const sandbox = createWorkflowSandbox({
|
|
1649
|
-
args: req.args,
|
|
1650
|
-
runId,
|
|
1651
|
-
dispatch: countedDispatch,
|
|
1652
|
-
parallel: parallelImpl,
|
|
1653
|
-
pipeline: pipelineImpl,
|
|
1654
|
-
workflow: workflowImpl,
|
|
1655
|
-
abortOnTimeout: req.abortOnTimeout,
|
|
1656
|
-
emitter,
|
|
1657
|
-
budget,
|
|
1658
|
-
scheduler
|
|
1659
|
-
});
|
|
1660
|
-
parentSandboxRef.current = sandbox;
|
|
1661
|
-
try {
|
|
1662
|
-
const result = await dependencyContext.run(
|
|
1663
|
-
{ tails: [] },
|
|
1664
|
-
() => sandbox.run(req.script)
|
|
1665
|
-
);
|
|
1666
|
-
return {
|
|
1667
|
-
runId,
|
|
1668
|
-
result,
|
|
1669
|
-
phases: sandbox.getPhases(),
|
|
1670
|
-
logs: sandbox.getLogs(),
|
|
1671
|
-
meta: sandbox.getMeta()
|
|
1672
|
-
};
|
|
1673
|
-
} catch (err) {
|
|
1674
|
-
throw new WorkflowExecutionError(
|
|
1675
|
-
extractErrorMessage(err),
|
|
1676
|
-
sandbox.getPhases(),
|
|
1677
|
-
sandbox.getLogs(),
|
|
1678
|
-
sandbox.getMeta()
|
|
1679
|
-
);
|
|
1680
|
-
}
|
|
1681
|
-
}
|
|
1682
|
-
};
|
|
1683
|
-
async function settleToNullArray(thunks, signal) {
|
|
1684
|
-
const settled = await Promise.allSettled(
|
|
1685
|
-
thunks.map((t) => Promise.resolve().then(t))
|
|
1686
|
-
);
|
|
1687
|
-
if (signal?.aborted)
|
|
1688
|
-
throw new DOMException("Workflow run aborted.", "AbortError");
|
|
1689
|
-
const visitedReasons = /* @__PURE__ */ new WeakSet();
|
|
1690
|
-
const findRunFailureReason = /* @__PURE__ */ __name((reason) => {
|
|
1691
|
-
if (reason === null || typeof reason !== "object") return void 0;
|
|
1692
|
-
if (visitedReasons.has(reason)) return void 0;
|
|
1693
|
-
visitedReasons.add(reason);
|
|
1694
|
-
try {
|
|
1695
|
-
if (reason.__wfRunFailure === true) {
|
|
1696
|
-
return reason;
|
|
1697
|
-
}
|
|
1698
|
-
const errors = reason?.errors;
|
|
1699
|
-
if (!Array.isArray(errors)) return void 0;
|
|
1700
|
-
for (const error of errors) {
|
|
1701
|
-
const runFailure = findRunFailureReason(error);
|
|
1702
|
-
if (runFailure !== void 0) return runFailure;
|
|
1703
|
-
}
|
|
1704
|
-
} catch {
|
|
1705
|
-
return void 0;
|
|
1706
|
-
}
|
|
1707
|
-
return void 0;
|
|
1708
|
-
}, "findRunFailureReason");
|
|
1709
|
-
for (const result of settled) {
|
|
1710
|
-
if (result.status !== "rejected") continue;
|
|
1711
|
-
const runFailure = findRunFailureReason(result.reason);
|
|
1712
|
-
if (runFailure !== void 0) throw runFailure;
|
|
1713
|
-
}
|
|
1714
|
-
return settled.map((r, i) => {
|
|
1715
|
-
if (r.status === "fulfilled") return r.value;
|
|
1716
|
-
const reason = r.reason;
|
|
1717
|
-
debugLogger.warn(
|
|
1718
|
-
`Workflow thunk at index ${i} rejected: ${String(reason?.message ?? r.reason)}`
|
|
1719
|
-
);
|
|
1720
|
-
return null;
|
|
1721
|
-
});
|
|
1722
|
-
}
|
|
1723
|
-
__name(settleToNullArray, "settleToNullArray");
|
|
1724
|
-
function makeParallelImpl(signal, dependencyContext) {
|
|
1725
|
-
return (thunks) => {
|
|
1726
|
-
if (!Array.isArray(thunks)) {
|
|
1727
|
-
return Promise.reject(
|
|
1728
|
-
new Error(
|
|
1729
|
-
"parallel() expects an array of thunks (functions returning promises)."
|
|
1730
|
-
)
|
|
1731
|
-
);
|
|
1732
|
-
}
|
|
1733
|
-
for (const t of thunks) {
|
|
1734
|
-
if (typeof t !== "function") {
|
|
1735
|
-
return Promise.reject(
|
|
1736
|
-
new Error(
|
|
1737
|
-
"parallel() expects an array of functions, not values \u2014 wrap each call: parallel([() => agent(...), () => agent(...)])."
|
|
1738
|
-
)
|
|
1739
|
-
);
|
|
1740
|
-
}
|
|
1741
|
-
}
|
|
1742
|
-
const parent = dependencyContext.getStore();
|
|
1743
|
-
const inheritedTails = parent?.tails ?? [];
|
|
1744
|
-
const branches = thunks.map((thunk) => {
|
|
1745
|
-
const store = { tails: [...inheritedTails] };
|
|
1746
|
-
return {
|
|
1747
|
-
store,
|
|
1748
|
-
thunk: /* @__PURE__ */ __name(() => dependencyContext.run(store, thunk), "thunk")
|
|
1749
|
-
};
|
|
1750
|
-
});
|
|
1751
|
-
return settleToNullArray(
|
|
1752
|
-
branches.map(({ thunk }) => thunk),
|
|
1753
|
-
signal
|
|
1754
|
-
).then((result) => {
|
|
1755
|
-
if (parent && branches.length > 0) {
|
|
1756
|
-
parent.tails = mergeFanoutTails(
|
|
1757
|
-
parent.tails,
|
|
1758
|
-
inheritedTails,
|
|
1759
|
-
branches.flatMap(({ store }) => store.tails)
|
|
1760
|
-
);
|
|
1761
|
-
}
|
|
1762
|
-
return result;
|
|
1763
|
-
});
|
|
1764
|
-
};
|
|
1765
|
-
}
|
|
1766
|
-
__name(makeParallelImpl, "makeParallelImpl");
|
|
1767
|
-
function makePipelineImpl(signal, dependencyContext) {
|
|
1768
|
-
return (items, ...stages) => {
|
|
1769
|
-
if (!Array.isArray(items)) {
|
|
1770
|
-
return Promise.reject(
|
|
1771
|
-
new Error(
|
|
1772
|
-
"pipeline() expects an array of items as its first argument."
|
|
1773
|
-
)
|
|
1774
|
-
);
|
|
1775
|
-
}
|
|
1776
|
-
for (const s of stages) {
|
|
1777
|
-
if (typeof s !== "function") {
|
|
1778
|
-
return Promise.reject(
|
|
1779
|
-
new Error(
|
|
1780
|
-
"pipeline() stages must be functions: pipeline(items, item => ..., result => ...)."
|
|
1781
|
-
)
|
|
1782
|
-
);
|
|
1783
|
-
}
|
|
1784
|
-
}
|
|
1785
|
-
const parent = dependencyContext.getStore();
|
|
1786
|
-
const inheritedTails = parent?.tails ?? [];
|
|
1787
|
-
const branches = items.map((item, idx) => {
|
|
1788
|
-
const store = { tails: [...inheritedTails] };
|
|
1789
|
-
return {
|
|
1790
|
-
store,
|
|
1791
|
-
thunk: /* @__PURE__ */ __name(() => dependencyContext.run(
|
|
1792
|
-
store,
|
|
1793
|
-
() => runPipelineChain(item, idx, stages)
|
|
1794
|
-
), "thunk")
|
|
1795
|
-
};
|
|
1796
|
-
});
|
|
1797
|
-
return settleToNullArray(
|
|
1798
|
-
branches.map(({ thunk }) => thunk),
|
|
1799
|
-
signal
|
|
1800
|
-
).then((result) => {
|
|
1801
|
-
if (parent && branches.length > 0) {
|
|
1802
|
-
parent.tails = mergeFanoutTails(
|
|
1803
|
-
parent.tails,
|
|
1804
|
-
inheritedTails,
|
|
1805
|
-
branches.flatMap(({ store }) => store.tails)
|
|
1806
|
-
);
|
|
1807
|
-
}
|
|
1808
|
-
return result;
|
|
1809
|
-
});
|
|
1810
|
-
};
|
|
1811
|
-
}
|
|
1812
|
-
__name(makePipelineImpl, "makePipelineImpl");
|
|
1813
|
-
function mergeFanoutTails(currentParentTails, inheritedTails, branchTails) {
|
|
1814
|
-
const inherited = new Set(inheritedTails);
|
|
1815
|
-
const newBranchTails = branchTails.filter((tail) => !inherited.has(tail));
|
|
1816
|
-
const merged = newBranchTails.length > 0 ? [
|
|
1817
|
-
...newBranchTails,
|
|
1818
|
-
...currentParentTails.filter((tail) => !inherited.has(tail))
|
|
1819
|
-
] : currentParentTails;
|
|
1820
|
-
return Array.from(new Set(merged));
|
|
1821
|
-
}
|
|
1822
|
-
__name(mergeFanoutTails, "mergeFanoutTails");
|
|
1823
|
-
async function runPipelineChain(item, idx, stages) {
|
|
1824
|
-
let prev = item;
|
|
1825
|
-
for (const stage of stages) {
|
|
1826
|
-
if (prev === null) break;
|
|
1827
|
-
prev = await stage(prev, item, idx);
|
|
1828
|
-
}
|
|
1829
|
-
return prev;
|
|
1830
|
-
}
|
|
1831
|
-
__name(runPipelineChain, "runPipelineChain");
|
|
1832
|
-
function extractErrorMessage(err) {
|
|
1833
|
-
if (err && typeof err === "object" && "message" in err) {
|
|
1834
|
-
const m = err.message;
|
|
1835
|
-
if (typeof m === "string") return m;
|
|
1836
|
-
return String(m);
|
|
1837
|
-
}
|
|
1838
|
-
return String(err);
|
|
1839
|
-
}
|
|
1840
|
-
__name(extractErrorMessage, "extractErrorMessage");
|
|
1841
|
-
|
|
1842
|
-
// packages/core/src/agents/runtime/workflow-runner.ts
|
|
1843
|
-
init_esbuild_shims();
|
|
1844
|
-
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
1845
|
-
var WorkflowRunHandle = class {
|
|
1846
|
-
constructor(runId, budget, registry, controller, scheduler, start, locations = {}) {
|
|
1847
|
-
this.runId = runId;
|
|
1848
|
-
this.budget = budget;
|
|
1849
|
-
this.registry = registry;
|
|
1850
|
-
this.controller = controller;
|
|
1851
|
-
this.scheduler = scheduler;
|
|
1852
|
-
this.scriptPath = locations.scriptPath;
|
|
1853
|
-
this.journalPath = locations.journalPath;
|
|
1854
|
-
this.completion = Promise.resolve().then(start);
|
|
1855
|
-
}
|
|
1856
|
-
static {
|
|
1857
|
-
__name(this, "WorkflowRunHandle");
|
|
1858
|
-
}
|
|
1859
|
-
completion;
|
|
1860
|
-
/**
|
|
1861
|
-
* Where this run's script lives on disk: the file a `{scriptPath}` launch
|
|
1862
|
-
* loaded, or the persisted copy of an inline `{script}`. `undefined` when
|
|
1863
|
-
* an inline script could not be persisted (no `storage`, symlinked root,
|
|
1864
|
-
* write failure) — callers report the run without it rather than naming a
|
|
1865
|
-
* path that does not exist.
|
|
1866
|
-
*/
|
|
1867
|
-
scriptPath;
|
|
1868
|
-
/** This run's resume journal, when the config has a `storage` to hold one. */
|
|
1869
|
-
journalPath;
|
|
1870
|
-
abort() {
|
|
1871
|
-
this.controller.abort();
|
|
1872
|
-
}
|
|
1873
|
-
pause() {
|
|
1874
|
-
return this.scheduler.pause();
|
|
1875
|
-
}
|
|
1876
|
-
resume() {
|
|
1877
|
-
return this.scheduler.resume();
|
|
1878
|
-
}
|
|
1879
|
-
};
|
|
1880
|
-
var WorkflowScriptNotLaunchedError = class extends Error {
|
|
1881
|
-
constructor(detail) {
|
|
1882
|
-
super(
|
|
1883
|
-
`Workflow script is invalid and was not launched:
|
|
1884
|
-
${detail}
|
|
1885
|
-
|
|
1886
|
-
Workflow scripts must be plain JavaScript \u2014 the usual causes are TypeScript syntax (type annotations, interfaces, generics) and broken string quoting or escaping. Metadata must use literal values.`
|
|
1887
|
-
);
|
|
1888
|
-
this.detail = detail;
|
|
1889
|
-
this.name = "WorkflowScriptNotLaunchedError";
|
|
1890
|
-
}
|
|
1891
|
-
static {
|
|
1892
|
-
__name(this, "WorkflowScriptNotLaunchedError");
|
|
1893
|
-
}
|
|
1894
|
-
};
|
|
1895
|
-
var WorkflowStartCancelledError = class extends Error {
|
|
1896
|
-
static {
|
|
1897
|
-
__name(this, "WorkflowStartCancelledError");
|
|
1898
|
-
}
|
|
1899
|
-
constructor() {
|
|
1900
|
-
super("Workflow start was cancelled.");
|
|
1901
|
-
this.name = "WorkflowStartCancelledError";
|
|
1902
|
-
}
|
|
1903
|
-
};
|
|
1904
|
-
var WorkflowRunner = class {
|
|
1905
|
-
static {
|
|
1906
|
-
__name(this, "WorkflowRunner");
|
|
1907
|
-
}
|
|
1908
|
-
static async start(options) {
|
|
1909
|
-
if (options.resumeFromRunId) {
|
|
1910
|
-
const attempt = await tryWithWorkflowTaskMutation(
|
|
1911
|
-
getWorkflowTaskMutationKey(options.config, options.resumeFromRunId),
|
|
1912
|
-
() => this.startClaimed(options)
|
|
1913
|
-
);
|
|
1914
|
-
if (!attempt.acquired) {
|
|
1915
|
-
throw new Error(
|
|
1916
|
-
`Workflow run ${options.resumeFromRunId} is already being modified.`
|
|
1917
|
-
);
|
|
1918
|
-
}
|
|
1919
|
-
return attempt.value;
|
|
1920
|
-
}
|
|
1921
|
-
return this.startClaimed(options);
|
|
1922
|
-
}
|
|
1923
|
-
static async startClaimed(options) {
|
|
1924
|
-
const config = options.config;
|
|
1925
|
-
const runInBackground = options.runInBackground === true;
|
|
1926
|
-
const budget = WorkflowBudgetImpl.fromEnv();
|
|
1927
|
-
const runId = options.resumeFromRunId ?? `wf_${randomBytes2(8).toString("hex")}`;
|
|
1928
|
-
const registry = config.getWorkflowRunRegistry?.();
|
|
1929
|
-
let entry;
|
|
1930
|
-
const isCurrentEntry = /* @__PURE__ */ __name(() => registry === void 0 || entry !== void 0 && registry.get(runId) === entry, "isCurrentEntry");
|
|
1931
|
-
const createController = /* @__PURE__ */ __name(() => runInBackground ? createAbortController() : createChildAbortController(options.signal), "createController");
|
|
1932
|
-
const controller = registry ? registry.reserveStart(runId, createController) : createController();
|
|
1933
|
-
const releasePersistenceActivity = markWorkflowRunPersistenceActive(
|
|
1934
|
-
config,
|
|
1935
|
-
runId
|
|
1936
|
-
);
|
|
1937
|
-
const assertStartNotCancelled = /* @__PURE__ */ __name(() => {
|
|
1938
|
-
if (controller.signal.aborted && !options.signal.aborted) {
|
|
1939
|
-
throw new WorkflowStartCancelledError();
|
|
1940
|
-
}
|
|
1941
|
-
if (runInBackground && options.signal.aborted) {
|
|
1942
|
-
throw new WorkflowStartCancelledError();
|
|
1943
|
-
}
|
|
1944
|
-
}, "assertStartNotCancelled");
|
|
1945
|
-
const storage = config.storage;
|
|
1946
|
-
const previousEntry = registry?.get(runId);
|
|
1947
|
-
let journalPath = storage ? storage.getWorkflowRunJournalPath(runId) : void 0;
|
|
1948
|
-
const journal = journalPath ? new WorkflowJournal(journalPath, storage.getWorkflowRunsDir()) : void 0;
|
|
1949
|
-
let script;
|
|
1950
|
-
let scriptPath;
|
|
1951
|
-
let resumeReplay;
|
|
1952
|
-
let persistedInlineScript = false;
|
|
1953
|
-
let callerWasAbortedBeforeStart;
|
|
1954
|
-
let orchestrator;
|
|
1955
|
-
try {
|
|
1956
|
-
const loaded = options.scriptPath && options.script === void 0 ? await resolveSavedWorkflowScript(
|
|
1957
|
-
{ scriptPath: options.scriptPath },
|
|
1958
|
-
config
|
|
1959
|
-
) : void 0;
|
|
1960
|
-
script = loaded?.script ?? options.script ?? "";
|
|
1961
|
-
scriptPath = loaded?.scriptPath ?? options.scriptPath;
|
|
1962
|
-
const workflowName = options.workflowName ?? loaded?.savedWorkflowName ?? registry?.get(runId)?.workflowName;
|
|
1963
|
-
try {
|
|
1964
|
-
compileWorkflowScript(script);
|
|
1965
|
-
} catch (error) {
|
|
1966
|
-
throw new WorkflowScriptNotLaunchedError(
|
|
1967
|
-
describeWorkflowCompileError(
|
|
1968
|
-
error,
|
|
1969
|
-
script.split(/\r\n|[\n\r\u2028\u2029]/).length
|
|
1970
|
-
)
|
|
1971
|
-
);
|
|
1972
|
-
}
|
|
1973
|
-
resumeReplay = options.resumeFromRunId ? await journal?.load() : void 0;
|
|
1974
|
-
assertStartNotCancelled();
|
|
1975
|
-
callerWasAbortedBeforeStart = options.signal.aborted;
|
|
1976
|
-
if (options.script !== void 0 && scriptPath === void 0) {
|
|
1977
|
-
const persisted = await persistInlineWorkflowScript(
|
|
1978
|
-
config,
|
|
1979
|
-
runId,
|
|
1980
|
-
script
|
|
1981
|
-
);
|
|
1982
|
-
scriptPath = persisted ?? void 0;
|
|
1983
|
-
persistedInlineScript = persisted !== null;
|
|
1984
|
-
}
|
|
1985
|
-
if (journal && !await journal.ensureExists()) {
|
|
1986
|
-
journalPath = void 0;
|
|
1987
|
-
}
|
|
1988
|
-
assertStartNotCancelled();
|
|
1989
|
-
const dispatch = options.dispatch ?? createProductionDispatch(
|
|
1990
|
-
config,
|
|
1991
|
-
controller.signal,
|
|
1992
|
-
(outputTokens) => budget.recordSpent(outputTokens),
|
|
1993
|
-
registry ? (emitter2, dispatchId) => isCurrentEntry() ? registry.bridgeApprovalEvents(
|
|
1994
|
-
runId,
|
|
1995
|
-
emitter2,
|
|
1996
|
-
dispatchId,
|
|
1997
|
-
entry
|
|
1998
|
-
) : () => void 0 : void 0
|
|
1999
|
-
);
|
|
2000
|
-
orchestrator = new WorkflowOrchestrator(dispatch);
|
|
2001
|
-
entry = registry?.register(
|
|
2002
|
-
{
|
|
2003
|
-
runId,
|
|
2004
|
-
toolUseId: options.toolUseId,
|
|
2005
|
-
...workflowName ? { workflowName } : {},
|
|
2006
|
-
meta: null,
|
|
2007
|
-
status: "running",
|
|
2008
|
-
startTime: Date.now(),
|
|
2009
|
-
outputFile: "",
|
|
2010
|
-
abortController: controller,
|
|
2011
|
-
tokenBudgetTotal: budget.total,
|
|
2012
|
-
script,
|
|
2013
|
-
scriptPath,
|
|
2014
|
-
...journalPath ? { journalPath } : {},
|
|
2015
|
-
args: options.args,
|
|
2016
|
-
...options.resumeFromRunId ? {
|
|
2017
|
-
sourceRunId: options.resumeFromRunId,
|
|
2018
|
-
startMode: "retry"
|
|
2019
|
-
} : {},
|
|
2020
|
-
isBackgrounded: runInBackground,
|
|
2021
|
-
resumeInBackground: runInBackground && config.isInteractive?.() === true && config.getExperimentalZedIntegration?.() !== true
|
|
2022
|
-
},
|
|
2023
|
-
controller
|
|
2024
|
-
);
|
|
2025
|
-
} catch (error) {
|
|
2026
|
-
registry?.releaseStart(runId, controller);
|
|
2027
|
-
controller.abort();
|
|
2028
|
-
if (persistedInlineScript && options.resumeFromRunId === void 0) {
|
|
2029
|
-
await deleteInlineWorkflowScript(config, runId);
|
|
2030
|
-
}
|
|
2031
|
-
if (persistedInlineScript && options.resumeFromRunId && previousEntry) {
|
|
2032
|
-
await persistInlineWorkflowScript(config, runId, previousEntry.script);
|
|
2033
|
-
}
|
|
2034
|
-
if (options.resumeFromRunId === void 0) {
|
|
2035
|
-
await journal?.remove();
|
|
2036
|
-
}
|
|
2037
|
-
releasePersistenceActivity();
|
|
2038
|
-
throw error;
|
|
2039
|
-
}
|
|
2040
|
-
const emitUpdate = /* @__PURE__ */ __name(() => {
|
|
2041
|
-
if (!entry || !options.onUpdate || !isCurrentEntry()) return;
|
|
2042
|
-
try {
|
|
2043
|
-
options.onUpdate(entry);
|
|
2044
|
-
} catch {
|
|
2045
|
-
}
|
|
2046
|
-
}, "emitUpdate");
|
|
2047
|
-
const emitter = {
|
|
2048
|
-
phaseStarted: /* @__PURE__ */ __name((title) => {
|
|
2049
|
-
if (!isCurrentEntry()) return;
|
|
2050
|
-
registry?.onPhaseStarted(runId, title);
|
|
2051
|
-
emitUpdate();
|
|
2052
|
-
}, "phaseStarted"),
|
|
2053
|
-
agentDispatched: /* @__PURE__ */ __name(() => {
|
|
2054
|
-
if (!isCurrentEntry()) return;
|
|
2055
|
-
registry?.onAgentDispatched(runId);
|
|
2056
|
-
emitUpdate();
|
|
2057
|
-
}, "agentDispatched"),
|
|
2058
|
-
agentCompleted: /* @__PURE__ */ __name(() => {
|
|
2059
|
-
if (!isCurrentEntry()) return;
|
|
2060
|
-
registry?.onAgentCompleted(runId);
|
|
2061
|
-
}, "agentCompleted"),
|
|
2062
|
-
dispatchQueued: /* @__PURE__ */ __name((event) => {
|
|
2063
|
-
if (!isCurrentEntry()) return;
|
|
2064
|
-
registry?.onDispatchQueued(runId, event);
|
|
2065
|
-
emitUpdate();
|
|
2066
|
-
}, "dispatchQueued"),
|
|
2067
|
-
dispatchStarted: /* @__PURE__ */ __name((dispatchId, startedAt) => {
|
|
2068
|
-
if (!isCurrentEntry()) return;
|
|
2069
|
-
registry?.onDispatchStarted(runId, dispatchId, startedAt);
|
|
2070
|
-
emitUpdate();
|
|
2071
|
-
}, "dispatchStarted"),
|
|
2072
|
-
dispatchSettled: /* @__PURE__ */ __name((dispatchId, error, endedAt) => {
|
|
2073
|
-
if (!isCurrentEntry()) return;
|
|
2074
|
-
registry?.onDispatchSettled(
|
|
2075
|
-
runId,
|
|
2076
|
-
dispatchId,
|
|
2077
|
-
error,
|
|
2078
|
-
endedAt,
|
|
2079
|
-
!runInBackground && options.signal.aborted
|
|
2080
|
-
);
|
|
2081
|
-
emitUpdate();
|
|
2082
|
-
}, "dispatchSettled"),
|
|
2083
|
-
// The registry records this without firing a status update, avoiding a
|
|
2084
|
-
// TUI redraw per line while retaining the real replay timestamp.
|
|
2085
|
-
logAppended: /* @__PURE__ */ __name((line) => {
|
|
2086
|
-
if (!isCurrentEntry()) return;
|
|
2087
|
-
registry?.onLogAppended(runId, line);
|
|
2088
|
-
}, "logAppended"),
|
|
2089
|
-
budgetUpdated: /* @__PURE__ */ __name((spent, total) => {
|
|
2090
|
-
if (!isCurrentEntry()) return;
|
|
2091
|
-
registry?.onBudgetUpdated(runId, spent, total);
|
|
2092
|
-
emitUpdate();
|
|
2093
|
-
}, "budgetUpdated"),
|
|
2094
|
-
resumeRespawn: /* @__PURE__ */ __name((line) => {
|
|
2095
|
-
if (!isCurrentEntry()) return;
|
|
2096
|
-
registry?.onResumeRespawn(runId, line);
|
|
2097
|
-
emitUpdate();
|
|
2098
|
-
}, "resumeRespawn")
|
|
2099
|
-
};
|
|
2100
|
-
const scheduler = new WorkflowDispatchScheduler(
|
|
2101
|
-
resolveConcurrencyLimit(),
|
|
2102
|
-
controller.signal,
|
|
2103
|
-
({ state }) => {
|
|
2104
|
-
if (!isCurrentEntry()) return;
|
|
2105
|
-
registry?.onDispatchStateChange(runId, state);
|
|
2106
|
-
}
|
|
2107
|
-
);
|
|
2108
|
-
const handle = new WorkflowRunHandle(
|
|
2109
|
-
runId,
|
|
2110
|
-
budget,
|
|
2111
|
-
registry,
|
|
2112
|
-
controller,
|
|
2113
|
-
scheduler,
|
|
2114
|
-
async () => {
|
|
2115
|
-
try {
|
|
2116
|
-
const outcome = await orchestrator.run({
|
|
2117
|
-
script,
|
|
2118
|
-
args: options.args,
|
|
2119
|
-
abortOnTimeout: controller,
|
|
2120
|
-
runId,
|
|
2121
|
-
emitter,
|
|
2122
|
-
budget,
|
|
2123
|
-
resolveSavedWorkflow: /* @__PURE__ */ __name((ref) => resolveSavedWorkflowScript(ref, config), "resolveSavedWorkflow"),
|
|
2124
|
-
journal,
|
|
2125
|
-
resumeReplay,
|
|
2126
|
-
scheduler
|
|
2127
|
-
});
|
|
2128
|
-
if (entry) {
|
|
2129
|
-
entry.meta = outcome.meta;
|
|
2130
|
-
if (outcome.meta?.name && entry.description === runId) {
|
|
2131
|
-
entry.description = outcome.meta.name;
|
|
2132
|
-
}
|
|
2133
|
-
}
|
|
2134
|
-
registry?.setRecentLogs(runId, outcome.logs);
|
|
2135
|
-
if (entry && isTerminalWorkflowStatus(entry.status)) {
|
|
2136
|
-
return {
|
|
2137
|
-
ok: false,
|
|
2138
|
-
message: entry.status === "cancelled" ? "Workflow run cancelled." : entry.error ?? "Workflow run failed."
|
|
2139
|
-
};
|
|
2140
|
-
}
|
|
2141
|
-
registry?.complete(runId, outcome.result, Date.now());
|
|
2142
|
-
return { ok: true, outcome };
|
|
2143
|
-
} catch (error) {
|
|
2144
|
-
const details = error instanceof WorkflowExecutionError ? error : void 0;
|
|
2145
|
-
const message = extractErrorMessage2(error);
|
|
2146
|
-
if (entry && details?.meta && !entry.meta) entry.meta = details.meta;
|
|
2147
|
-
if (details?.logs) registry?.setRecentLogs(runId, details.logs);
|
|
2148
|
-
if (entry && isTerminalWorkflowStatus(entry.status)) {
|
|
2149
|
-
return {
|
|
2150
|
-
ok: false,
|
|
2151
|
-
message: entry.status === "cancelled" ? "Workflow run cancelled." : entry.error ?? message,
|
|
2152
|
-
details
|
|
2153
|
-
};
|
|
2154
|
-
}
|
|
2155
|
-
if (callerWasAbortedBeforeStart || !runInBackground && options.signal.aborted) {
|
|
2156
|
-
registry?.cancel(runId, Date.now());
|
|
2157
|
-
} else {
|
|
2158
|
-
registry?.fail(runId, message, Date.now());
|
|
2159
|
-
}
|
|
2160
|
-
return { ok: false, message, details };
|
|
2161
|
-
} finally {
|
|
2162
|
-
controller.abort();
|
|
2163
|
-
if (entry && isTerminalWorkflowStatus(entry.status)) {
|
|
2164
|
-
const telemetryEvent = new WorkflowRunEvent({
|
|
2165
|
-
status: entry.status,
|
|
2166
|
-
agents_dispatched: entry.agentsDispatched,
|
|
2167
|
-
agents_completed: entry.agentsCompleted,
|
|
2168
|
-
// Read off the dispatch traces rather than the counters: a
|
|
2169
|
-
// dispatch that failed or replayed from cache still counts as
|
|
2170
|
-
// completed, so without these three a run that lost half its
|
|
2171
|
-
// fan-out and one that lost none report identically.
|
|
2172
|
-
agents_failed: entry.dispatches.reduce(
|
|
2173
|
-
(n, dispatch) => dispatch.status === "failed" ? n + 1 : n,
|
|
2174
|
-
0
|
|
2175
|
-
),
|
|
2176
|
-
agents_cached: entry.dispatches.reduce(
|
|
2177
|
-
(n, dispatch) => dispatch.status === "cached" ? n + 1 : n,
|
|
2178
|
-
0
|
|
2179
|
-
),
|
|
2180
|
-
agents_respawned: entry.agentsRespawned ?? 0,
|
|
2181
|
-
phase_count: entry.phases.length,
|
|
2182
|
-
tokens_spent: entry.tokensSpent,
|
|
2183
|
-
duration_ms: (entry.endTime ?? entry.startTime) - entry.startTime
|
|
2184
|
-
});
|
|
2185
|
-
const snapshotPersisted = await writeWorkflowSnapshot(
|
|
2186
|
-
config,
|
|
2187
|
-
entry
|
|
2188
|
-
);
|
|
2189
|
-
if (snapshotPersisted) {
|
|
2190
|
-
registry?.notifySnapshotPersisted(entry.runId);
|
|
2191
|
-
}
|
|
2192
|
-
await journal?.drain();
|
|
2193
|
-
try {
|
|
2194
|
-
logWorkflowRun(config, telemetryEvent);
|
|
2195
|
-
} catch {
|
|
2196
|
-
}
|
|
2197
|
-
}
|
|
2198
|
-
releasePersistenceActivity();
|
|
2199
|
-
registry?.releaseHandle(runId, handle);
|
|
2200
|
-
}
|
|
2201
|
-
},
|
|
2202
|
-
{
|
|
2203
|
-
...scriptPath ? { scriptPath } : {},
|
|
2204
|
-
...journalPath ? { journalPath } : {}
|
|
2205
|
-
}
|
|
2206
|
-
);
|
|
2207
|
-
registry?.attachHandle(handle);
|
|
2208
|
-
return handle;
|
|
2209
|
-
}
|
|
2210
|
-
};
|
|
2211
|
-
function extractErrorMessage2(error) {
|
|
2212
|
-
if (error && typeof error === "object" && "message" in error) {
|
|
2213
|
-
const message = error.message;
|
|
2214
|
-
if (typeof message === "string") return message;
|
|
2215
|
-
return String(message);
|
|
2216
|
-
}
|
|
2217
|
-
return String(error);
|
|
2218
|
-
}
|
|
2219
|
-
__name(extractErrorMessage2, "extractErrorMessage");
|
|
2220
|
-
|
|
2221
|
-
// packages/core/src/tools/workflow/workflow.ts
|
|
2222
|
-
import { promises as fs2 } from "node:fs";
|
|
2223
|
-
import * as path2 from "node:path";
|
|
2224
|
-
var WORKFLOW_PARAM_SCHEMA = {
|
|
2225
|
-
type: "object",
|
|
2226
|
-
properties: {
|
|
2227
|
-
script: {
|
|
2228
|
-
type: "string",
|
|
2229
|
-
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?, workingDir?, stallMs? }\`. \`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. After two in-conversation nudges without a valid result, it resolves to null and the failure is recorded as "subagent completed without calling StructuredOutput (after 2 in-conversation nudges)"; check for null. \`agentType\` (string): resolves against the declarative-agents registry (\`.qwen/agents/<name>.md\`, project then user then built-in). Unresolved names make the admitted agent() resolve to null and record "agent({agentType}): agent type 'X' not found"; check for null. \`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'\` makes the admitted agent() resolve to null and records "agent({isolation:'remote'}) is not available in this build" (parity with upstream). isolation=worktree also resolves to null and records a refusal when the parent working tree has uncommitted changes (the subagent would see a stale HEAD). \`workingDir\` (string): pin the subagent to an EXISTING git worktree of this repository that the caller owns \u2014 nothing is created and nothing is removed. Use it when the directory the agent must work in already exists and its uncommitted state is the point (a review worktree, a checkout a previous step provisioned) \u2014 exactly the case isolation cannot serve. Mutually exclusive with \`isolation\`. The path must be a linked worktree of this repository registered via \`git worktree add\` (it may live anywhere on disk) \u2014 the main checkout is not eligible. \`stallMs\` (number, ms): a no-progress watchdog, not a wall-clock cap. The dispatch is aborted and retried (up to ${MAX_STALL_ATTEMPTS} attempts total) after this many milliseconds with no observable subagent progress \u2014 including before the first response arrives; the timer is suspended while a tool is in flight, so a legitimately slow tool is not a stall. Default ${DEFAULT_STALL_MS} (override via \`${MAX_WORKFLOW_STALL_MS_ENV}\`, whole seconds); \`0\` disables the watchdog. Wall time per attempt is bounded separately. 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(2, 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 on invalid arguments, abort, or a run-level token/agent-cap refusal. \`pipeline(items, ...stages)\` runs each item through the stages (staggered, no inter-stage barrier); an ordinary stage error, \`null\`, or non-JSON-serializable value drops that item to \`null\`, while a run-level refusal rejects the batch. A bare sequential \`await agent()\` follows the same rule: an agent that fails on its own terms resolves to \`null\` there too, so the fan-out and the sequential form never disagree about what a broken agent means. 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.`
|
|
2230
|
-
},
|
|
2231
|
-
scriptPath: {
|
|
2232
|
-
type: "string",
|
|
2233
|
-
description: "Optional. Absolute path to a workflow `.js` file to load and run instead of inline `script`. Primarily set by the `/<name>` saved-workflow slash command; a tool that generated a script for this run hands you its path the same way. The file must resolve inside a saved-workflow directory (`.qwen/workflows`, `~/.qwen/workflows`) or the generated-scripts root (`$QWEN_CODE_PROJECT_DIR/workflows/generated` \u2014 the per-project runtime dir, not the project tree) \u2014 any other path is refused. Provide exactly ONE of `script` or `scriptPath`. The file is read at execution time, so edits to a saved workflow take effect on the next run. An inline `script` is persisted to `<generated root>/inline/<runId>.js` and that path comes back in the result, so a resume passes the path instead of the source."
|
|
2234
|
-
},
|
|
2235
|
-
args: {
|
|
2236
|
-
description: "Optional structured value bound to the `args` global. Pass actual JSON, not a stringified value."
|
|
2237
|
-
},
|
|
2238
|
-
resumeFromRunId: {
|
|
2239
|
-
type: "string",
|
|
2240
|
-
description: "Optional. Resume a prior workflow run by id (e.g. wf_abc123\u2026). Re-runs the supplied script or returned script path; agent() calls whose rolling prefix-hash (prompt + opts, chained in call order) matches a journaled result are served from cache for the longest unchanged prefix, and the first changed/missing call onward runs live. Pass the `scriptPath` the original run returned and the same `args`. Editing a saved workflow changes future runs too, so copy it for run-specific edits. Replay requires a journal; without one, every agent() call runs live. The journal keys hash each agent() call's prompt and opts, not the script text, so post-processing can change without losing the cache."
|
|
2241
|
-
},
|
|
2242
|
-
run_in_background: {
|
|
2243
|
-
type: "boolean",
|
|
2244
|
-
default: false,
|
|
2245
|
-
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."
|
|
2246
|
-
}
|
|
2247
|
-
}
|
|
2248
|
-
// `script` is required UNLESS `scriptPath` is supplied; this XOR can't be
|
|
2249
|
-
// expressed as a plain `required` list, so it's enforced in
|
|
2250
|
-
// `validateToolParamValues`. Inline authoring (the LLM path) should always
|
|
2251
|
-
// pass `script`; the `scriptPath` property description states the XOR.
|
|
2252
|
-
};
|
|
2253
|
-
var WorkflowToolInvocation = class extends BaseToolInvocation {
|
|
2254
|
-
constructor(config, toolOptions, params, workflowName) {
|
|
2255
|
-
super(params);
|
|
2256
|
-
this.config = config;
|
|
2257
|
-
this.toolOptions = toolOptions;
|
|
2258
|
-
this.workflowName = workflowName;
|
|
2259
|
-
}
|
|
2260
|
-
static {
|
|
2261
|
-
__name(this, "WorkflowToolInvocation");
|
|
2262
|
-
}
|
|
2263
|
-
callId;
|
|
2264
|
-
setCallId(callId) {
|
|
2265
|
-
this.callId = callId;
|
|
2266
|
-
}
|
|
2267
|
-
/**
|
|
2268
|
-
* Cache so the transcript header and the approval dialog cannot disagree,
|
|
2269
|
-
* and so an oversized script is scanned once per invocation rather than
|
|
2270
|
-
* once per surface that asks.
|
|
2271
|
-
*/
|
|
2272
|
-
metaCache;
|
|
2273
|
-
resolveMeta() {
|
|
2274
|
-
if (this.metaCache === void 0) {
|
|
2275
|
-
this.metaCache = this.params.script ? readMetaForConfirmation(this.params.script) : null;
|
|
2276
|
-
}
|
|
2277
|
-
return this.metaCache;
|
|
2278
|
-
}
|
|
2279
|
-
getDescription() {
|
|
2280
|
-
const meta = this.resolveMeta();
|
|
2281
|
-
if (meta) {
|
|
2282
|
-
return `Run workflow: ${sanitizeLine(meta.name)}`;
|
|
2283
|
-
}
|
|
2284
|
-
if (this.params.scriptPath && this.params.script === void 0) {
|
|
2285
|
-
const kind = isGeneratedWorkflowScriptPath(
|
|
2286
|
-
this.config,
|
|
2287
|
-
this.params.scriptPath
|
|
2288
|
-
) ? "generated workflow script" : "saved workflow";
|
|
2289
|
-
return `Run ${kind} (${path2.basename(this.params.scriptPath)})`;
|
|
2290
|
-
}
|
|
2291
|
-
return `Run a workflow script (${this.params.script?.length ?? 0} chars)`;
|
|
2292
|
-
}
|
|
2293
|
-
toolLocations() {
|
|
2294
|
-
return [];
|
|
2295
|
-
}
|
|
2296
|
-
getDefaultPermission() {
|
|
2297
|
-
return Promise.resolve("ask");
|
|
2298
|
-
}
|
|
2299
|
-
/**
|
|
2300
|
-
* Show what is about to run, and scope the grant that approves it.
|
|
2301
|
-
*
|
|
2302
|
-
* Without this override the base class renders `Confirm WorkflowTool` over
|
|
2303
|
-
* `Run a workflow script (4127 chars)` — a character count standing in for
|
|
2304
|
-
* arbitrary model-authored JavaScript that may fan out to
|
|
2305
|
-
* `DEFAULT_MAX_AGENTS_PER_RUN` subagents, provision git worktrees and spend
|
|
2306
|
-
* an uncapped token budget. The asymmetry is visible within one run: the
|
|
2307
|
-
* subagent approvals this workflow bubbles up each get a full dialog.
|
|
2308
|
-
*
|
|
2309
|
-
* Two properties of the grant matter as much as the disclosure:
|
|
2310
|
-
*
|
|
2311
|
-
* - An inline `script` can never be pre-approved. It is fresh
|
|
2312
|
-
* model-authored source every time, so a blanket "always allow" would
|
|
2313
|
-
* transfer consent from the script the user read to every script the
|
|
2314
|
-
* model writes afterwards. `hideAlwaysAllow` removes the option and the
|
|
2315
|
-
* empty `permissionRules` stops `injectPermissionRulesIfMissing` from
|
|
2316
|
-
* supplying the bare-tool-name rule, which `buildPermissionRules`
|
|
2317
|
-
* documents as matching *all* invocations.
|
|
2318
|
-
* - A `scriptPath` names a file on disk that the user chose, so it can be
|
|
2319
|
-
* pre-approved — but scoped to that path. The rule is built with the
|
|
2320
|
-
* same helpers the matcher uses so a tool rename moves both sides.
|
|
2321
|
-
*/
|
|
2322
|
-
async getConfirmationDetails(_abortSignal) {
|
|
2323
|
-
const meta = this.resolveMeta();
|
|
2324
|
-
const isGeneratedScriptPath = this.params.scriptPath !== void 0 && await isGeneratedWorkflowScriptPathCanonical(
|
|
2325
|
-
this.config,
|
|
2326
|
-
this.params.scriptPath
|
|
2327
|
-
);
|
|
2328
|
-
const isGeneratedInlineScriptPath = this.params.scriptPath !== void 0 && await isWorkflowScriptPathWithinCanonicalRoot(
|
|
2329
|
-
this.params.scriptPath,
|
|
2330
|
-
path2.dirname(this.config.storage.getInlineWorkflowScriptPath("wf_0"))
|
|
2331
|
-
);
|
|
2332
|
-
const body = buildConfirmationPrompt(
|
|
2333
|
-
this.params,
|
|
2334
|
-
meta,
|
|
2335
|
-
isGeneratedScriptPath
|
|
2336
|
-
);
|
|
2337
|
-
const banner = resolveUsageBanner(
|
|
2338
|
-
this.config,
|
|
2339
|
-
this.config.getWorkflowRunRegistry?.(),
|
|
2340
|
-
resolveMaxTokensPerWorkflow()
|
|
2341
|
-
);
|
|
2342
|
-
const isInlineScript = this.params.script !== void 0 || isGeneratedInlineScriptPath;
|
|
2343
|
-
const details = {
|
|
2344
|
-
type: "info",
|
|
2345
|
-
title: "Run a dynamic workflow?",
|
|
2346
|
-
prompt: banner ? `${banner}${body}` : body,
|
|
2347
|
-
// The body is a script excerpt and a phase list: rendering it as
|
|
2348
|
-
// Markdown would swallow the very characters the reader needs to see.
|
|
2349
|
-
renderPromptAsPlainText: true,
|
|
2350
|
-
hideAlwaysAllow: isInlineScript,
|
|
2351
|
-
permissionRules: isInlineScript ? [] : [
|
|
2352
|
-
`${getRuleDisplayName(resolveToolName(ToolNames.WORKFLOW))}(scriptPath:${this.params.scriptPath})`
|
|
2353
|
-
],
|
|
2354
|
-
onConfirm: /* @__PURE__ */ __name(async (_outcome, _payload) => {
|
|
2355
|
-
}, "onConfirm")
|
|
2356
|
-
};
|
|
2357
|
-
return details;
|
|
2358
|
-
}
|
|
2359
|
-
async execute(signal, updateOutput, _shellExecutionConfig) {
|
|
2360
|
-
const runInBackground = this.params.run_in_background === true;
|
|
2361
|
-
if (runInBackground && signal.aborted) {
|
|
2362
|
-
return startCancelledResult();
|
|
2363
|
-
}
|
|
2364
|
-
let handle;
|
|
2365
|
-
try {
|
|
2366
|
-
handle = await WorkflowRunner.start({
|
|
2367
|
-
config: this.config,
|
|
2368
|
-
signal,
|
|
2369
|
-
toolUseId: this.callId,
|
|
2370
|
-
...this.workflowName ? { workflowName: this.workflowName } : {},
|
|
2371
|
-
script: this.params.script,
|
|
2372
|
-
scriptPath: this.params.scriptPath,
|
|
2373
|
-
args: this.params.args,
|
|
2374
|
-
resumeFromRunId: this.params.resumeFromRunId,
|
|
2375
|
-
dispatch: this.toolOptions.dispatch,
|
|
2376
|
-
runInBackground,
|
|
2377
|
-
onUpdate: !runInBackground && updateOutput ? (entry) => safeEmitUpdate(updateOutput, entry) : void 0
|
|
2378
|
-
});
|
|
2379
|
-
} catch (error) {
|
|
2380
|
-
if (error instanceof WorkflowStartCancelledError || runInBackground && signal.aborted) {
|
|
2381
|
-
return startCancelledResult();
|
|
2382
|
-
}
|
|
2383
|
-
if (error instanceof WorkflowScriptNotLaunchedError) {
|
|
2384
|
-
return {
|
|
2385
|
-
llmContent: [{ text: error.message }],
|
|
2386
|
-
returnDisplay: error.message,
|
|
2387
|
-
error: {
|
|
2388
|
-
message: error.message,
|
|
2389
|
-
type: "invalid_tool_params" /* INVALID_TOOL_PARAMS */
|
|
2390
|
-
}
|
|
2391
|
-
};
|
|
2392
|
-
}
|
|
2393
|
-
throw error;
|
|
2394
|
-
}
|
|
2395
|
-
if (runInBackground) {
|
|
2396
|
-
const status = handle.registry?.get(handle.runId)?.status ?? "running";
|
|
2397
|
-
const usageBanner = resolveUsageBanner(
|
|
2398
|
-
this.config,
|
|
2399
|
-
handle.registry,
|
|
2400
|
-
handle.budget.total
|
|
2401
|
-
);
|
|
2402
|
-
return {
|
|
2403
|
-
workflowRunId: handle.runId,
|
|
2404
|
-
...handle.scriptPath ? { scriptPath: handle.scriptPath } : {},
|
|
2405
|
-
...handle.journalPath ? { journalPath: handle.journalPath } : {},
|
|
2406
|
-
llmContent: [
|
|
2407
|
-
{
|
|
2408
|
-
text: buildBackgroundStartText(handle, status)
|
|
2409
|
-
}
|
|
2410
|
-
],
|
|
2411
|
-
returnDisplay: usageBanner + `Workflow ${handle.runId} started in the background (status: ${status}). Use Background Tasks to observe, cooperatively pause/resume, or stop it.`
|
|
2412
|
-
};
|
|
2413
|
-
}
|
|
2414
|
-
const settlement = await handle.completion;
|
|
2415
|
-
if (settlement.ok) {
|
|
2416
|
-
const { outcome } = settlement;
|
|
2417
|
-
const usageBanner = resolveUsageBanner(
|
|
2418
|
-
this.config,
|
|
2419
|
-
handle.registry,
|
|
2420
|
-
handle.budget.total
|
|
2421
|
-
);
|
|
2422
|
-
const llmText = safeStringifyResult(outcome.result);
|
|
2423
|
-
const displayJson = safeStringifyDisplayPayload({
|
|
2424
|
-
runId: outcome.runId,
|
|
2425
|
-
...outcome.meta ? { meta: outcome.meta } : {},
|
|
2426
|
-
phases: outcome.phases,
|
|
2427
|
-
logs: outcome.logs,
|
|
2428
|
-
result: outcome.result,
|
|
2429
|
-
// P5: surface the per-run token total in the terminal display so
|
|
2430
|
-
// the user sees actual usage even without opening the dialog.
|
|
2431
|
-
// P5 R1 (#11): align with `buildLivePhaseTreeDisplay` — include
|
|
2432
|
-
// tokens whenever ANY usage is reported OR a cap is set, not
|
|
2433
|
-
// only when spend > 0. A capped-but-zero-spend run still wants
|
|
2434
|
-
// the cap visible so the user sees the gate engaged.
|
|
2435
|
-
...handle.budget.spent() > 0 || handle.budget.total !== null ? {
|
|
2436
|
-
tokens: {
|
|
2437
|
-
spent: handle.budget.spent(),
|
|
2438
|
-
total: handle.budget.total
|
|
2439
|
-
}
|
|
2440
|
-
} : {}
|
|
2441
|
-
});
|
|
2442
|
-
return {
|
|
2443
|
-
...handle.scriptPath ? { scriptPath: handle.scriptPath } : {},
|
|
2444
|
-
...handle.journalPath ? { journalPath: handle.journalPath } : {},
|
|
2445
|
-
// Two parts: the script's return value is left exactly as it was,
|
|
2446
|
-
// and the run handle follows as a separate part. Note what this does
|
|
2447
|
-
// NOT mean — `convertToFunctionResponse` joins the text parts with a
|
|
2448
|
-
// newline, so the model reads `<return value>\n--- workflow run ---…`
|
|
2449
|
-
// as one string. Keeping them apart is still what makes the return
|
|
2450
|
-
// value untouched at the tool boundary, keeps `returnDisplay` clean,
|
|
2451
|
-
// and gives the per-tool head/tail truncator a distinct trailer part.
|
|
2452
|
-
// The scheduler-wide persistence gate may still fold both parts into
|
|
2453
|
-
// one head-only preview when their combined text crosses its limit.
|
|
2454
|
-
llmContent: [
|
|
2455
|
-
{ text: llmText },
|
|
2456
|
-
{ text: buildRunTrailer(this.config, handle, this.params.args) }
|
|
2457
|
-
],
|
|
2458
|
-
returnDisplay: usageBanner + "```json\n" + displayJson + "\n```"
|
|
2459
|
-
};
|
|
2460
|
-
} else {
|
|
2461
|
-
const { message, details } = settlement;
|
|
2462
|
-
const { phases, logs, meta } = details ?? {};
|
|
2463
|
-
const cancelled = handle.registry?.get(handle.runId)?.status === "cancelled";
|
|
2464
|
-
const failureText = cancelled ? "Workflow cancelled." : `Workflow failed: ${clampForDisplay(
|
|
2465
|
-
sanitizeBlock(message),
|
|
2466
|
-
TRAILER_ERROR_CHARS
|
|
2467
|
-
)}`;
|
|
2468
|
-
const trailer = buildRunTrailer(
|
|
2469
|
-
this.config,
|
|
2470
|
-
handle,
|
|
2471
|
-
this.params.args,
|
|
2472
|
-
logs,
|
|
2473
|
-
!cancelled
|
|
2474
|
-
);
|
|
2475
|
-
const display = `${cancelled ? "Workflow cancelled." : `Workflow failed: ${message}`}
|
|
2476
|
-
|
|
2477
|
-
${safeStringifyDisplayPayload(
|
|
2478
|
-
{
|
|
2479
|
-
runId: handle.runId,
|
|
2480
|
-
...meta ? { meta } : {},
|
|
2481
|
-
phases: phases ?? [],
|
|
2482
|
-
logs: logs ?? []
|
|
2483
|
-
}
|
|
2484
|
-
)}`;
|
|
2485
|
-
return {
|
|
2486
|
-
...handle.scriptPath ? { scriptPath: handle.scriptPath } : {},
|
|
2487
|
-
...handle.journalPath ? { journalPath: handle.journalPath } : {},
|
|
2488
|
-
// The failure message alone names what threw but not where to look:
|
|
2489
|
-
// the logs the runtime already mirrored (`dispatch failed (result not
|
|
2490
|
-
// consumed)` and friends) only reached `returnDisplay`, which the
|
|
2491
|
-
// scheduler overwrites with `error.message` — so the model never saw
|
|
2492
|
-
// them. Mirror the two content parts into the error message because
|
|
2493
|
-
// that is the only text the non-timeout scheduler branch delivers.
|
|
2494
|
-
llmContent: [{ text: failureText }, { text: trailer }],
|
|
2495
|
-
returnDisplay: display,
|
|
2496
|
-
// FIX-10 (REUSE-I1): use the standard ToolErrorType.EXECUTION_FAILED
|
|
2497
|
-
// code so error routing / dashboards can classify workflow failures
|
|
2498
|
-
// the same way as other execution-time tool errors.
|
|
2499
|
-
error: {
|
|
2500
|
-
message: `${failureText}
|
|
2501
|
-
${trailer}`,
|
|
2502
|
-
type: "execution_failed" /* EXECUTION_FAILED */
|
|
2503
|
-
}
|
|
2504
|
-
};
|
|
2505
|
-
}
|
|
2506
|
-
}
|
|
2507
|
-
};
|
|
2508
|
-
var TRAILER_LOG_LINES = 20;
|
|
2509
|
-
var TRAILER_LOG_LINE_CHARS = 400;
|
|
2510
|
-
var TRAILER_ERROR_CHARS = 4e3;
|
|
2511
|
-
function buildRunTrailer(config, handle, args, logs, includeResume = true) {
|
|
2512
|
-
const lines = [
|
|
2513
|
-
"--- workflow run ---",
|
|
2514
|
-
`runId: ${sanitizeLine(handle.runId)}`
|
|
2515
|
-
];
|
|
2516
|
-
if (handle.scriptPath) {
|
|
2517
|
-
lines.push(`script: ${sanitizeLine(handle.scriptPath)}`);
|
|
2518
|
-
}
|
|
2519
|
-
if (handle.journalPath) {
|
|
2520
|
-
lines.push(`journal: ${sanitizeLine(handle.journalPath)}`);
|
|
2521
|
-
}
|
|
2522
|
-
const entry = handle.registry?.get(handle.runId);
|
|
2523
|
-
let failedCount = 0;
|
|
2524
|
-
if (entry) {
|
|
2525
|
-
const countByStatus = /* @__PURE__ */ __name((status) => entry.dispatches.reduce(
|
|
2526
|
-
(n, dispatch) => dispatch.status === status ? n + 1 : n,
|
|
2527
|
-
0
|
|
2528
|
-
), "countByStatus");
|
|
2529
|
-
const respawned = entry.agentsRespawned ?? 0;
|
|
2530
|
-
failedCount = countByStatus("failed");
|
|
2531
|
-
lines.push(
|
|
2532
|
-
`agents: ${entry.dispatches.length} dispatched` + (respawned > 0 ? ` (${respawned} re-ran from a prior run)` : "") + ` \xB7 ${countByStatus("completed")} completed \xB7 ${countByStatus("cached")} cached \xB7 ${failedCount} failed \xB7 ${countByStatus("cancelled")} cancelled`
|
|
2533
|
-
);
|
|
2534
|
-
}
|
|
2535
|
-
const spent = handle.budget.spent();
|
|
2536
|
-
lines.push(
|
|
2537
|
-
handle.budget.total === null ? `tokens: ${spent} spent (no cap)` : `tokens: ${spent} / ${handle.budget.total} spent`
|
|
2538
|
-
);
|
|
2539
|
-
const failures = entry ? buildFailureLines(entry) : [];
|
|
2540
|
-
if (failures.length > 0 && entry) {
|
|
2541
|
-
lines.push(
|
|
2542
|
-
`failures (${failedCount}):`,
|
|
2543
|
-
...failures.map(
|
|
2544
|
-
(line) => clampForDisplay(sanitizeLine(line), TRAILER_LOG_LINE_CHARS)
|
|
2545
|
-
)
|
|
2546
|
-
);
|
|
2547
|
-
}
|
|
2548
|
-
const resume = buildResumeCall({
|
|
2549
|
-
runId: handle.runId,
|
|
2550
|
-
scriptPath: handle.scriptPath,
|
|
2551
|
-
args
|
|
2552
|
-
});
|
|
2553
|
-
if (resume && includeResume) {
|
|
2554
|
-
const pathAdvice = entry?.workflowName || !isGeneratedWorkflowScriptPath(config, handle.scriptPath) ? "this reads the saved workflow; copy it before making a run-specific change" : "edit that generated copy first if the script needs to change";
|
|
2555
|
-
const journalAdvice = handle.journalPath ? "the journal replays the longest unchanged prefix of agent() calls, and the first changed call onward runs live" : "no journal was written for this run, so every agent() call runs live";
|
|
2556
|
-
lines.push(`resume: ${resume} \u2014 ${pathAdvice}; ${journalAdvice}.`);
|
|
2557
|
-
if (hasUninlinableResumeArgs({ runId: handle.runId, args })) {
|
|
2558
|
-
lines.push(RESUME_ARGS_TOO_LARGE_NOTE);
|
|
2559
|
-
}
|
|
2560
|
-
}
|
|
2561
|
-
const tail = (logs ?? []).slice(-TRAILER_LOG_LINES);
|
|
2562
|
-
if (tail.length > 0) {
|
|
2563
|
-
lines.push(
|
|
2564
|
-
`logs (last ${tail.length}):`,
|
|
2565
|
-
...tail.map(
|
|
2566
|
-
(line) => clampForDisplay(sanitizeLine(line), TRAILER_LOG_LINE_CHARS)
|
|
2567
|
-
)
|
|
2568
|
-
);
|
|
2569
|
-
}
|
|
2570
|
-
return lines.join("\n");
|
|
2571
|
-
}
|
|
2572
|
-
__name(buildRunTrailer, "buildRunTrailer");
|
|
2573
|
-
function buildBackgroundStartText(handle, status) {
|
|
2574
|
-
const lines = [
|
|
2575
|
-
"Workflow started in background.",
|
|
2576
|
-
`Run ID: ${sanitizeLine(handle.runId)}`,
|
|
2577
|
-
`Status: ${sanitizeLine(status)}`
|
|
2578
|
-
];
|
|
2579
|
-
if (handle.scriptPath) {
|
|
2580
|
-
lines.push(`Script file: ${sanitizeLine(handle.scriptPath)}`);
|
|
2581
|
-
}
|
|
2582
|
-
if (handle.journalPath) {
|
|
2583
|
-
lines.push(`Journal: ${sanitizeLine(handle.journalPath)}`);
|
|
2584
|
-
}
|
|
2585
|
-
lines.push(
|
|
2586
|
-
`You will be notified when it settles. Use /workflows ${sanitizeLine(handle.runId)} for the live phase tree.`
|
|
2587
|
-
);
|
|
2588
|
-
return lines.join("\n");
|
|
2589
|
-
}
|
|
2590
|
-
__name(buildBackgroundStartText, "buildBackgroundStartText");
|
|
2591
|
-
function startCancelledResult() {
|
|
2592
|
-
return {
|
|
2593
|
-
llmContent: "Workflow was cancelled before it could start.",
|
|
2594
|
-
returnDisplay: "Workflow cancelled."
|
|
2595
|
-
};
|
|
2596
|
-
}
|
|
2597
|
-
__name(startCancelledResult, "startCancelledResult");
|
|
2598
|
-
function buildLivePhaseTreeDisplay(entry) {
|
|
2599
|
-
const payload = {
|
|
2600
|
-
runId: entry.runId,
|
|
2601
|
-
...entry.meta ? { meta: entry.meta } : {},
|
|
2602
|
-
status: entry.status,
|
|
2603
|
-
currentPhase: entry.currentPhase,
|
|
2604
|
-
phases: entry.phases,
|
|
2605
|
-
agentsDispatched: entry.agentsDispatched,
|
|
2606
|
-
agentsCompleted: entry.agentsCompleted
|
|
2607
|
-
};
|
|
2608
|
-
if (entry.tokensSpent > 0 || entry.tokenBudgetTotal !== null) {
|
|
2609
|
-
payload["tokens"] = {
|
|
2610
|
-
spent: entry.tokensSpent,
|
|
2611
|
-
total: entry.tokenBudgetTotal
|
|
2612
|
-
};
|
|
2613
|
-
}
|
|
2614
|
-
try {
|
|
2615
|
-
return "```json\n" + JSON.stringify(payload, null, 2) + "\n```";
|
|
2616
|
-
} catch {
|
|
2617
|
-
return `Workflow ${entry.runId} \u2014 ${entry.status} \u2014 ${entry.phases.length} phase(s)`;
|
|
2618
|
-
}
|
|
2619
|
-
}
|
|
2620
|
-
__name(buildLivePhaseTreeDisplay, "buildLivePhaseTreeDisplay");
|
|
2621
|
-
function resolveUsageBanner(config, registry, budgetTotal) {
|
|
2622
|
-
if (!registry) return "";
|
|
2623
|
-
if (config.getSkipWorkflowUsageWarning?.()) return "";
|
|
2624
|
-
if (!registry.shouldShowUsageWarning()) return "";
|
|
2625
|
-
return buildUsageBanner(budgetTotal);
|
|
2626
|
-
}
|
|
2627
|
-
__name(resolveUsageBanner, "resolveUsageBanner");
|
|
2628
|
-
var CONFIRM_SCRIPT_EXCERPT_CHARS = 1200;
|
|
2629
|
-
var CONFIRM_ARGS_CHARS = 300;
|
|
2630
|
-
var CONFIRM_MAX_PHASES = 12;
|
|
2631
|
-
function sanitizeLine(text) {
|
|
2632
|
-
return stripAnsiAndControl(text);
|
|
2633
|
-
}
|
|
2634
|
-
__name(sanitizeLine, "sanitizeLine");
|
|
2635
|
-
function sanitizeBlock(text) {
|
|
2636
|
-
return text.replace(/\t/g, " ").split("\n").map((line) => stripAnsiAndControl(line)).join("\n");
|
|
2637
|
-
}
|
|
2638
|
-
__name(sanitizeBlock, "sanitizeBlock");
|
|
2639
|
-
function clampForDisplay(text, max) {
|
|
2640
|
-
if (text.length <= max) return text;
|
|
2641
|
-
return `${text.slice(0, max)}
|
|
2642
|
-
\u2026 (${text.length - max} more characters)`;
|
|
2643
|
-
}
|
|
2644
|
-
__name(clampForDisplay, "clampForDisplay");
|
|
2645
|
-
function readMetaForConfirmation(script) {
|
|
2646
|
-
try {
|
|
2647
|
-
return extractAndStripMeta(script).meta;
|
|
2648
|
-
} catch {
|
|
2649
|
-
return null;
|
|
2650
|
-
}
|
|
2651
|
-
}
|
|
2652
|
-
__name(readMetaForConfirmation, "readMetaForConfirmation");
|
|
2653
|
-
function isGeneratedWorkflowScriptPath(config, scriptPath) {
|
|
2654
|
-
return isWithinRoot(scriptPath, config.storage.getGeneratedWorkflowsDir());
|
|
2655
|
-
}
|
|
2656
|
-
__name(isGeneratedWorkflowScriptPath, "isGeneratedWorkflowScriptPath");
|
|
2657
|
-
async function isGeneratedWorkflowScriptPathCanonical(config, scriptPath) {
|
|
2658
|
-
return isWorkflowScriptPathWithinCanonicalRoot(
|
|
2659
|
-
scriptPath,
|
|
2660
|
-
config.storage.getGeneratedWorkflowsDir()
|
|
2661
|
-
);
|
|
2662
|
-
}
|
|
2663
|
-
__name(isGeneratedWorkflowScriptPathCanonical, "isGeneratedWorkflowScriptPathCanonical");
|
|
2664
|
-
async function isWorkflowScriptPathWithinCanonicalRoot(scriptPath, root) {
|
|
2665
|
-
if (await isSymlinkedRoot(root)) return false;
|
|
2666
|
-
let realScriptPath;
|
|
2667
|
-
try {
|
|
2668
|
-
realScriptPath = await fs2.realpath(scriptPath);
|
|
2669
|
-
} catch {
|
|
2670
|
-
return isWithinRoot(scriptPath, root);
|
|
2671
|
-
}
|
|
2672
|
-
let realRoot;
|
|
2673
|
-
try {
|
|
2674
|
-
realRoot = await fs2.realpath(root);
|
|
2675
|
-
} catch {
|
|
2676
|
-
realRoot = path2.resolve(root);
|
|
2677
|
-
}
|
|
2678
|
-
return isWithinRoot(realScriptPath, realRoot);
|
|
2679
|
-
}
|
|
2680
|
-
__name(isWorkflowScriptPathWithinCanonicalRoot, "isWorkflowScriptPathWithinCanonicalRoot");
|
|
2681
|
-
function buildConfirmationPrompt(params, meta, isGeneratedScriptPath) {
|
|
2682
|
-
const lines = [];
|
|
2683
|
-
if (meta) {
|
|
2684
|
-
lines.push(`Workflow: ${sanitizeLine(meta.name)}`);
|
|
2685
|
-
lines.push(sanitizeLine(meta.description));
|
|
2686
|
-
} else if (params.scriptPath) {
|
|
2687
|
-
const label = isGeneratedScriptPath ? "Generated workflow script" : "Saved workflow";
|
|
2688
|
-
lines.push(`${label}: ${sanitizeLine(params.scriptPath)}`);
|
|
2689
|
-
} else {
|
|
2690
|
-
lines.push("Workflow: (the script declares no meta block)");
|
|
2691
|
-
}
|
|
2692
|
-
if (meta?.phases?.length) {
|
|
2693
|
-
const shown = meta.phases.slice(0, CONFIRM_MAX_PHASES);
|
|
2694
|
-
lines.push("", `Phases (${meta.phases.length}):`);
|
|
2695
|
-
shown.forEach((phase, i) => {
|
|
2696
|
-
const detail = phase.detail ? ` \u2014 ${sanitizeLine(phase.detail)}` : "";
|
|
2697
|
-
lines.push(` ${i + 1}. ${sanitizeLine(phase.title)}${detail}`);
|
|
2698
|
-
});
|
|
2699
|
-
if (meta.phases.length > shown.length) {
|
|
2700
|
-
lines.push(` \u2026 and ${meta.phases.length - shown.length} more`);
|
|
2701
|
-
}
|
|
2702
|
-
}
|
|
2703
|
-
if (params.scriptPath && meta) {
|
|
2704
|
-
lines.push("", `Loaded from: ${sanitizeLine(params.scriptPath)}`);
|
|
2705
|
-
}
|
|
2706
|
-
if (params.resumeFromRunId) {
|
|
2707
|
-
lines.push("", `Resuming run: ${sanitizeLine(params.resumeFromRunId)}`);
|
|
2708
|
-
}
|
|
2709
|
-
if (params.args !== void 0) {
|
|
2710
|
-
let rendered;
|
|
2711
|
-
try {
|
|
2712
|
-
rendered = JSON.stringify(params.args) ?? String(params.args);
|
|
2713
|
-
} catch {
|
|
2714
|
-
rendered = "(args are not JSON-serializable)";
|
|
2715
|
-
}
|
|
2716
|
-
lines.push(
|
|
2717
|
-
"",
|
|
2718
|
-
`Args: ${clampForDisplay(sanitizeLine(rendered), CONFIRM_ARGS_CHARS)}`
|
|
2719
|
-
);
|
|
2720
|
-
}
|
|
2721
|
-
if (params.script) {
|
|
2722
|
-
lines.push(
|
|
2723
|
-
"",
|
|
2724
|
-
"Script:",
|
|
2725
|
-
clampForDisplay(
|
|
2726
|
-
sanitizeBlock(params.script),
|
|
2727
|
-
CONFIRM_SCRIPT_EXCERPT_CHARS
|
|
2728
|
-
)
|
|
2729
|
-
);
|
|
2730
|
-
}
|
|
2731
|
-
return lines.join("\n");
|
|
2732
|
-
}
|
|
2733
|
-
__name(buildConfirmationPrompt, "buildConfirmationPrompt");
|
|
2734
|
-
function buildUsageBanner(total) {
|
|
2735
|
-
if (total === null) {
|
|
2736
|
-
return `> Workflows have no per-run token cap. Set \`${MAX_TOKENS_PER_WORKFLOW_ENV}=<n>\` (env) for a soft cap. Suppress this notice with \`skipWorkflowUsageWarning: true\` in settings.
|
|
2737
|
-
|
|
2738
|
-
`;
|
|
2739
|
-
}
|
|
2740
|
-
return `> Workflow token cap is ${total} (per \`${MAX_TOKENS_PER_WORKFLOW_ENV}\`). Suppress this notice with \`skipWorkflowUsageWarning: true\` in settings.
|
|
2741
|
-
|
|
2742
|
-
`;
|
|
2743
|
-
}
|
|
2744
|
-
__name(buildUsageBanner, "buildUsageBanner");
|
|
2745
|
-
function safeEmitUpdate(updateOutput, entry) {
|
|
2746
|
-
if (!updateOutput || !entry) return;
|
|
2747
|
-
try {
|
|
2748
|
-
updateOutput(buildLivePhaseTreeDisplay(entry));
|
|
2749
|
-
} catch {
|
|
2750
|
-
}
|
|
2751
|
-
}
|
|
2752
|
-
__name(safeEmitUpdate, "safeEmitUpdate");
|
|
2753
|
-
function safeStringifyResult(result) {
|
|
2754
|
-
if (result === void 0) return "(workflow returned no value)";
|
|
2755
|
-
if (typeof result === "string") return result;
|
|
2756
|
-
try {
|
|
2757
|
-
return JSON.stringify(result, null, 2);
|
|
2758
|
-
} catch {
|
|
2759
|
-
return `(workflow returned a non-JSON-serializable value of type ${typeof result})`;
|
|
2760
|
-
}
|
|
2761
|
-
}
|
|
2762
|
-
__name(safeStringifyResult, "safeStringifyResult");
|
|
2763
|
-
function safeStringifyDisplayPayload(payload) {
|
|
2764
|
-
try {
|
|
2765
|
-
return JSON.stringify(payload, null, 2);
|
|
2766
|
-
} catch {
|
|
2767
|
-
if (payload && typeof payload === "object") {
|
|
2768
|
-
const sanitized = {};
|
|
2769
|
-
for (const [key, value] of Object.entries(payload)) {
|
|
2770
|
-
try {
|
|
2771
|
-
JSON.stringify(value);
|
|
2772
|
-
sanitized[key] = value;
|
|
2773
|
-
} catch {
|
|
2774
|
-
sanitized[key] = `(non-JSON-serializable value of type ${typeof value})`;
|
|
2775
|
-
}
|
|
2776
|
-
}
|
|
2777
|
-
try {
|
|
2778
|
-
return JSON.stringify(sanitized, null, 2);
|
|
2779
|
-
} catch {
|
|
2780
|
-
}
|
|
2781
|
-
}
|
|
2782
|
-
return "(display payload not JSON-serializable)";
|
|
2783
|
-
}
|
|
2784
|
-
}
|
|
2785
|
-
__name(safeStringifyDisplayPayload, "safeStringifyDisplayPayload");
|
|
2786
|
-
var WORKFLOW_TOOL_DESCRIPTION = `Execute a workflow script that orchestrates subagents deterministically.
|
|
2787
|
-
|
|
2788
|
-
**Only on an explicit request**
|
|
2789
|
-
|
|
2790
|
-
Do not call this tool unless the user has asked for multi-agent orchestration. A run can dispatch up to ${DEFAULT_MAX_AGENTS_PER_RUN} subagents and spend tokens accordingly, so that scale has to be requested rather than inferred. It counts as requested when any of these holds:
|
|
2791
|
-
|
|
2792
|
-
- The user's message contains the word \`workflow\`; a system reminder confirms it when it does.
|
|
2793
|
-
- The user asked for orchestration in their own words \u2014 run a workflow, fan out agents, orchestrate this with subagents.
|
|
2794
|
-
- A skill or slash command the user invoked instructs you to use this tool.
|
|
2795
|
-
- The user named a saved workflow to run, reached through \`workflow('<name>')\` or \`scriptPath\`.
|
|
2796
|
-
- The user asked to resume or continue an earlier run, which is \`resumeFromRunId\`.
|
|
2797
|
-
|
|
2798
|
-
Otherwise do not call it, however well the task would parallelize. Do the work in the main loop, or spawn a single subagent for one self-contained piece. When a workflow would genuinely be the better tool, say in one sentence what it would fan out over and roughly how many agents that is, then let the user decide \u2014 and mention that including the word \`workflow\` next time skips the ask.
|
|
2799
|
-
|
|
2800
|
-
**What a workflow is for**
|
|
2801
|
-
|
|
2802
|
-
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.
|
|
2803
|
-
|
|
2804
|
-
**Runtime** \u2014 see the \`script\` parameter for the detailed authoring contract.
|
|
2805
|
-
|
|
2806
|
-
\`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 inside either of them or inside the generated-scripts root (\`$QWEN_CODE_PROJECT_DIR/workflows/generated\` \u2014 the per-project runtime dir, not the project tree \u2014 where a tool emitting a one-run script writes it; never a slash command, never resolvable by name); a path outside those roots is refused. Default \`max(2, 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. Each subagent attempt is separately capped at ${DEFAULT_WORKFLOW_SUBAGENT_MAX_TURNS} turns (\`${WORKFLOW_SUBAGENT_MAX_TURNS_ENV}\`) and ${DEFAULT_WORKFLOW_SUBAGENT_MAX_TIME_MINUTES} minutes (\`${WORKFLOW_SUBAGENT_MAX_MINUTES_ENV}\`) \u2014 raise them for legitimately long work. \`agent()\` resolves to \`null\` when that admitted agent fails on its own \u2014 including turn/time caps, model or setup errors, missing structured output, and exhausted stall retries \u2014 and it does so for a bare \`await agent()\` exactly as it does inside \`parallel()\`/\`pipeline()\`, so check for \`null\` wherever you read a result. Call-shape validation failures \u2014 such as an empty prompt, an unsupported option combination, or an invalid option value \u2014 reject a bare call; inside \`parallel()\`/\`pipeline()\`, the surrounding ordinary thunk or stage rejection becomes a position-aligned \`null\`. Run-level rejections no later call could survive \u2014 the token budget, the ${DEFAULT_MAX_AGENTS_PER_RUN}-agent cap, and cancellation \u2014 throw and end a \`parallel()\`/\`pipeline()\` batch. An admitted agent that fails and settles to \`null\` still counts as dispatched and is named, with its error, in the run's failures list; a \`null\` returned by an ordinary thunk or stage is not an agent dispatch. 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. Per-call \`agent({ schema, agentType, model, isolation: 'worktree', workingDir, stallMs })\` covers structured-output contracts, declarative-agent selection, model override, git-worktree-isolated subagents, pinning an agent to a caller-owned worktree, and the no-progress stall watchdog (\`stallMs: 0\` disables it). \`resumeFromRunId\` resumes a prior run \u2014 agent() calls whose rolling prefix-hash matches the journal are served from cache for the longest unchanged prefix. Every run hands back its runId, the script's path on disk (an inline script is persisted, so a resume edits that file rather than re-sending the source) and its journal path; the journal holds one result line per completed agent, so read it before diagnosing an empty or surprising result. 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.
|
|
2807
|
-
|
|
2808
|
-
**Scout first, then orchestrate**
|
|
2809
|
-
|
|
2810
|
-
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.
|
|
2811
|
-
|
|
2812
|
-
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).
|
|
2813
|
-
|
|
2814
|
-
**Default to \`pipeline()\`**
|
|
2815
|
-
|
|
2816
|
-
\`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.
|
|
2817
|
-
|
|
2818
|
-
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()\`.
|
|
2819
|
-
|
|
2820
|
-
**Verify before believing**
|
|
2821
|
-
|
|
2822
|
-
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.
|
|
2823
|
-
|
|
2824
|
-
**Converge deliberately**
|
|
2825
|
-
|
|
2826
|
-
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.
|
|
2827
|
-
|
|
2828
|
-
**Report honestly**
|
|
2829
|
-
|
|
2830
|
-
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.
|
|
2831
|
-
|
|
2832
|
-
These shapes are a starting point, not a menu; compose the harness the task actually needs.`;
|
|
2833
|
-
var WorkflowTool = class extends BaseDeclarativeTool {
|
|
2834
|
-
constructor(config, toolOptions = {}) {
|
|
2835
|
-
super(
|
|
2836
|
-
ToolNames.WORKFLOW,
|
|
2837
|
-
ToolDisplayNames.WORKFLOW,
|
|
2838
|
-
WORKFLOW_TOOL_DESCRIPTION,
|
|
2839
|
-
"other" /* Other */,
|
|
2840
|
-
WORKFLOW_PARAM_SCHEMA,
|
|
2841
|
-
/* isOutputMarkdown */
|
|
2842
|
-
true,
|
|
2843
|
-
/* canUpdateOutput */
|
|
2844
|
-
true
|
|
2845
|
-
);
|
|
2846
|
-
this.config = config;
|
|
2847
|
-
this.toolOptions = toolOptions;
|
|
2848
|
-
}
|
|
2849
|
-
static {
|
|
2850
|
-
__name(this, "WorkflowTool");
|
|
2851
|
-
}
|
|
2852
|
-
buildSessionOwnedBackground(params, workflowName) {
|
|
2853
|
-
const validationError = this.validateToolParams(params);
|
|
2854
|
-
if (validationError) {
|
|
2855
|
-
throw new Error(validationError);
|
|
2856
|
-
}
|
|
2857
|
-
if (!this.config.getWorkflowRunRegistry().hasCompletionCallback()) {
|
|
2858
|
-
throw new Error(
|
|
2859
|
-
"WorkflowTool: session-owned background runs require an active workflow completion channel."
|
|
2860
|
-
);
|
|
2861
|
-
}
|
|
2862
|
-
return new WorkflowToolInvocation(
|
|
2863
|
-
this.config,
|
|
2864
|
-
this.toolOptions,
|
|
2865
|
-
{ ...params, run_in_background: true },
|
|
2866
|
-
workflowName
|
|
2867
|
-
);
|
|
2868
|
-
}
|
|
2869
|
-
validateToolParamValues(params) {
|
|
2870
|
-
const hasScript = typeof params.script === "string" && params.script.length > 0;
|
|
2871
|
-
const hasPath = typeof params.scriptPath === "string" && params.scriptPath.length > 0;
|
|
2872
|
-
if (!hasScript && !hasPath) {
|
|
2873
|
-
return "WorkflowTool: provide `script` (inline source) or `scriptPath` (a workflow script file).";
|
|
2874
|
-
}
|
|
2875
|
-
if (hasScript && hasPath) {
|
|
2876
|
-
return "WorkflowTool: provide exactly one of `script` or `scriptPath`, not both.";
|
|
2877
|
-
}
|
|
2878
|
-
if (params.resumeFromRunId !== void 0 && !/^wf_[0-9a-f]+$/.test(params.resumeFromRunId)) {
|
|
2879
|
-
return "WorkflowTool: `resumeFromRunId` must match the generated id format `wf_<hex>`.";
|
|
2880
|
-
}
|
|
2881
|
-
if (params.run_in_background === true) {
|
|
2882
|
-
if (!this.config.isInteractive() || this.config.getExperimentalZedIntegration?.() === true) {
|
|
2883
|
-
return "WorkflowTool: `run_in_background` is available only in the interactive TUI.";
|
|
2884
|
-
}
|
|
2885
|
-
if (!this.config.getWorkflowRunRegistry().hasCompletionCallback()) {
|
|
2886
|
-
return "WorkflowTool: `run_in_background` requires an active workflow completion channel.";
|
|
2887
|
-
}
|
|
2888
|
-
}
|
|
2889
|
-
return null;
|
|
2890
|
-
}
|
|
2891
|
-
createInvocation(params) {
|
|
2892
|
-
return new WorkflowToolInvocation(this.config, this.toolOptions, params);
|
|
2893
|
-
}
|
|
2894
|
-
};
|
|
2895
|
-
export {
|
|
2896
|
-
WorkflowTool
|
|
2897
|
-
};
|
|
2898
|
-
/**
|
|
2899
|
-
* @license
|
|
2900
|
-
* Copyright 2026 Qwen Team
|
|
2901
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
2902
|
-
*/
|
|
2903
|
-
/**
|
|
2904
|
-
* @license
|
|
2905
|
-
* Copyright 2025 Qwen
|
|
2906
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
2907
|
-
*/
|