@qwen-code/qwen-code 0.18.5 → 0.19.1-nightly.20260624.a234860a4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundled/qc-helper/SKILL.md +13 -5
- package/bundled/qc-helper/docs/configuration/_meta.ts +1 -0
- package/bundled/qc-helper/docs/configuration/auth.md +68 -48
- package/bundled/qc-helper/docs/configuration/model-providers.md +217 -195
- package/bundled/qc-helper/docs/configuration/qwen-ignore.md +31 -15
- package/bundled/qc-helper/docs/configuration/settings.md +44 -27
- package/bundled/qc-helper/docs/configuration/themes.md +7 -4
- package/bundled/qc-helper/docs/extension/extension-releasing.md +1 -1
- package/bundled/qc-helper/docs/extension/introduction.md +27 -21
- package/bundled/qc-helper/docs/features/arena.md +3 -3
- package/bundled/qc-helper/docs/features/channels/overview.md +1 -1
- package/bundled/qc-helper/docs/features/channels/plugins.md +1 -1
- package/bundled/qc-helper/docs/features/commands.md +6 -1
- package/bundled/qc-helper/docs/features/headless.md +1 -1
- package/bundled/qc-helper/docs/features/mcp.md +33 -14
- package/bundled/qc-helper/docs/features/sandbox.md +2 -2
- package/bundled/qc-helper/docs/features/tool-use-summaries.md +1 -1
- package/bundled/qc-helper/docs/integration-github-action.md +2 -2
- package/bundled/qc-helper/docs/overview.md +1 -1
- package/bundled/qc-helper/docs/quickstart.md +9 -5
- package/bundled/qc-helper/docs/qwen-serve.md +14 -2
- package/bundled/qc-helper/docs/support/tos-privacy.md +1 -1
- package/chunks/{agent-2TEY55UD.js → agent-6KV474S5.js} +24 -22
- package/chunks/{agent-headless-SCUAXEEE.js → agent-headless-XO7MM6JT.js} +24 -22
- package/chunks/{anthropicContentGenerator-5S4OMMNL.js → anthropicContentGenerator-7352A7I5.js} +12 -11
- package/chunks/artifact-tool-5J4HUZAV.js +675 -0
- package/chunks/{askUserQuestion-WHVYL2S2.js → askUserQuestion-HF7HCWDD.js} +20 -7
- package/chunks/chunk-22IFUCVR.js +291 -0
- package/chunks/{chunk-26ZYKTYZ.js → chunk-2BIF2NVV.js} +2 -2
- package/chunks/{chunk-VKILGMZQ.js → chunk-2QDQTWCI.js} +1 -1
- package/chunks/{chunk-XGU3ETVO.js → chunk-3BR4OIOE.js} +3 -3
- package/chunks/{chunk-LTN3VYMZ.js → chunk-3UALQ56H.js} +1 -1
- package/chunks/{chunk-F5E6IKYN.js → chunk-54J4JDWT.js} +619 -135
- package/chunks/{chunk-KZGQ3G3Q.js → chunk-76BDT2HH.js} +80 -83
- package/chunks/{chunk-VECKCOH6.js → chunk-7QBKO4A6.js} +7118 -5113
- package/chunks/{chunk-MSJ2MXJ6.js → chunk-BGUDAULQ.js} +11 -290
- package/chunks/{chunk-FH4P6RQA.js → chunk-BNXANYLH.js} +1 -1
- package/chunks/{chunk-SIJKWK35.js → chunk-C4JC2FL3.js} +8 -7
- package/chunks/{chunk-WE6TNQJU.js → chunk-C4K3FEQ2.js} +36 -0
- package/chunks/{chunk-G4BUMVEY.js → chunk-CGEGHF2C.js} +2 -217
- package/chunks/chunk-EEEZIVFJ.js +908 -0
- package/chunks/chunk-EJYJYJZ2.js +3703 -0
- package/chunks/{chunk-ATLUHLZE.js → chunk-EW6C27XX.js} +1 -1
- package/chunks/{chunk-42HGOMED.js → chunk-F6XNTYNE.js} +216 -1
- package/chunks/{chunk-C6MI2ASN.js → chunk-GZCJS5WH.js} +2 -2
- package/chunks/{chunk-KGV3F6UF.js → chunk-HGNSRCRB.js} +1 -1
- package/chunks/{chunk-2CNO5W47.js → chunk-HNYTRFAM.js} +171 -5016
- package/chunks/{chunk-CX3SGIPK.js → chunk-KBXLIVWQ.js} +2 -2
- package/chunks/{chunk-GOMVJKBL.js → chunk-L7U2RI5O.js} +59 -57
- package/chunks/{chunk-GBN55AWZ.js → chunk-NKJ6LRCR.js} +2 -2
- package/chunks/{chunk-2O3NAOJG.js → chunk-NWLUISRA.js} +1 -1
- package/chunks/{chunk-ID533GA3.js → chunk-OTBK43JR.js} +1 -1
- package/chunks/{chunk-AE6RQU6F.js → chunk-PRYMDRBV.js} +1 -1
- package/chunks/{chunk-KQIKOTQJ.js → chunk-RYLJU2DY.js} +60 -5
- package/chunks/{chunk-CTHZVIMD.js → chunk-T2VDEFUU.js} +2 -2
- package/chunks/{chunk-C7JA3XCX.js → chunk-TKXRLRTF.js} +5 -5
- package/chunks/{chunk-LF6BKGZT.js → chunk-TXVGVZYR.js} +3 -3
- package/chunks/{chunk-XU7BKR3B.js → chunk-XU5P23GN.js} +3 -3
- package/chunks/{computer-use-OB3C5QG2.js → computer-use-WOKHYISX.js} +24 -22
- package/chunks/contextCommand-JSYQAO3O.js +56 -0
- package/chunks/{cron-create-THNDTYXU.js → cron-create-A5637KCI.js} +12 -9
- package/chunks/{cron-delete-BS5H6TFJ.js → cron-delete-AADOSEOZ.js} +4 -4
- package/chunks/{cron-list-7OBVHT7K.js → cron-list-OFCPTT2Y.js} +4 -4
- package/chunks/{dist-GKRNVFBH.js → dist-ZBX7LPJZ.js} +2 -1
- package/chunks/{edit-GNCLIF67.js → edit-6EN6NO6G.js} +24 -22
- package/chunks/{en-S3OQBISC.js → en-7OGNWWME.js} +48 -0
- package/chunks/{enter-worktree-E7BNZOGT.js → enter-worktree-XJ4S74CL.js} +24 -22
- package/chunks/{enterPlanMode-IA42A5EU.js → enterPlanMode-GQNQIH2V.js} +27 -23
- package/chunks/{exit-worktree-QJ2K74UT.js → exit-worktree-6MKLATVB.js} +24 -22
- package/chunks/{exitPlanMode-UKKHBUYJ.js → exitPlanMode-YACWA5GO.js} +36 -28
- package/chunks/{geminiContentGenerator-ICSDM37U.js → geminiContentGenerator-OLJGOIWO.js} +4 -4
- package/chunks/{glob-IGD7LWYX.js → glob-YHSIN2LG.js} +26 -23
- package/chunks/{grep-IZM3IVND.js → grep-5EMEAJBO.js} +24 -22
- package/chunks/{keychain-token-storage-YHXIWXIB.js → keychain-token-storage-CSYMNRPP.js} +2 -2
- package/chunks/{loop-wakeup-SSBWZ64K.js → loop-wakeup-DGSMT4N6.js} +5 -5
- package/chunks/{ls-YPFUHZRQ.js → ls-UGRZ4ZOM.js} +6 -6
- package/chunks/{lsp-FD6DNVAF.js → lsp-72IJURW3.js} +2 -2
- package/chunks/{monitor-ALJNE3R4.js → monitor-ZGXTGINM.js} +24 -22
- package/chunks/{notebook-edit-7XRZX55T.js → notebook-edit-O7WO3APR.js} +25 -23
- package/chunks/{openaiContentGenerator-FWKITDFJ.js → openaiContentGenerator-N4FCEGU2.js} +12 -15
- package/chunks/{qwenContentGenerator-5RPGQZ63.js → qwenContentGenerator-BOAZ7MMG.js} +26 -24
- package/chunks/{qwenOAuth2-WZ54YZ4J.js → qwenOAuth2-K4AASPCV.js} +5 -4
- package/chunks/{read-file-4WN2DT5N.js → read-file-RB35MI5I.js} +9 -8
- package/chunks/{ripGrep-4ZKT6KBQ.js → ripGrep-CWJOA6JG.js} +24 -22
- package/chunks/{scheduler-O2E65VDK.js → scheduler-XUBHNI2Z.js} +73 -27
- package/chunks/{send-message-FWFTX62Q.js → send-message-URUZ7PLA.js} +24 -4
- package/chunks/{serve-3DM6CRGD.js → serve-P356SCA2.js} +618 -92
- package/chunks/{shell-ARVZK6RF.js → shell-5TRHTPML.js} +24 -22
- package/chunks/{skill-BFUBGA4I.js → skill-RW6N7GHL.js} +11 -10
- package/chunks/{src-5YMCDSII.js → src-SPEHQKTK.js} +140 -67
- package/chunks/{syntheticOutput-JY5NEDTV.js → syntheticOutput-65FRJGWM.js} +3 -3
- package/chunks/{task-create-IGILDV25.js → task-create-IH45HOFT.js} +6 -6
- package/chunks/{task-list-KBEJVAAG.js → task-list-FUB6JWSX.js} +5 -5
- package/chunks/{task-stop-WFTMQ6AC.js → task-stop-P6IOHQM3.js} +2 -2
- package/chunks/{task-update-UIVX7ZEV.js → task-update-RTUT7LJV.js} +6 -6
- package/chunks/{team-create-HRBV5ATK.js → team-create-D6GSPXCO.js} +28 -26
- package/chunks/{team-delete-LPOXDPVB.js → team-delete-RXGYRMHC.js} +5 -5
- package/chunks/{todoWrite-R4RIJKOD.js → todoWrite-O6JK24G6.js} +4 -4
- package/chunks/{tool-search-67HI54YA.js → tool-search-6YIMUUVD.js} +9 -8
- package/chunks/{web-fetch-JU7SS6KE.js → web-fetch-KUMBROUI.js} +4 -4
- package/chunks/{workflow-W4SCLWLU.js → workflow-ML3XFTCN.js} +557 -97
- package/chunks/{write-file-TLNXC2NR.js → write-file-VLT6ODLK.js} +24 -22
- package/chunks/{zh-QXLZV2PX.js → zh-3RMSEO5M.js} +48 -0
- package/chunks/{zh-TW-3OKU7LDA.js → zh-TW-R7WRLTJS.js} +48 -0
- package/cli.js +8559 -5100
- package/locales/en.js +69 -0
- package/locales/zh-TW.js +66 -0
- package/locales/zh.js +66 -0
- package/package.json +3 -2
- package/web-shell/assets/{arc-CRFN10gD.js → arc-DHUeMnnj.js} +1 -1
- package/web-shell/assets/{architectureDiagram-3BPJPVTR-IRlu1CpH.js → architectureDiagram-3BPJPVTR-DlX12yyj.js} +1 -1
- package/web-shell/assets/{blockDiagram-GPEHLZMM-htIZ6iw8.js → blockDiagram-GPEHLZMM-DTFUXMUT.js} +1 -1
- package/web-shell/assets/{c4Diagram-AAUBKEIU-A2GoRq3O.js → c4Diagram-AAUBKEIU-CWdB54fk.js} +1 -1
- package/web-shell/assets/channel-C3WhMjjP.js +1 -0
- package/web-shell/assets/{chunk-2J33WTMH-CdP2AC6u.js → chunk-2J33WTMH-CF5C5jNR.js} +1 -1
- package/web-shell/assets/{chunk-4BX2VUAB-DrA07nW2.js → chunk-4BX2VUAB-Cw7Ydfji.js} +1 -1
- package/web-shell/assets/{chunk-55IACEB6-CFGnVU2f.js → chunk-55IACEB6-CnbI1ZCw.js} +1 -1
- package/web-shell/assets/{chunk-727SXJPM-BTMkq3Tk.js → chunk-727SXJPM-DmSy00Pe.js} +1 -1
- package/web-shell/assets/{chunk-AQP2D5EJ-C9sYg04Z.js → chunk-AQP2D5EJ-DgNgXqBu.js} +1 -1
- package/web-shell/assets/{chunk-FMBD7UC4-Cag-cj6I.js → chunk-FMBD7UC4-tz2IvOXv.js} +1 -1
- package/web-shell/assets/{chunk-ND2GUHAM-CDSTFoR7.js → chunk-ND2GUHAM-DaBLEBPa.js} +1 -1
- package/web-shell/assets/{chunk-QZHKN3VN-CN9Z6oOs.js → chunk-QZHKN3VN-DVCQST3O.js} +1 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-CQ6TXPif.js +1 -0
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-CQ6TXPif.js +1 -0
- package/web-shell/assets/{cose-bilkent-S5V4N54A-DuN9j8Du.js → cose-bilkent-S5V4N54A-CAKTcdCQ.js} +1 -1
- package/web-shell/assets/{dagre-BM42HDAG-ByCWe45f.js → dagre-BM42HDAG-BdkBwlKg.js} +1 -1
- package/web-shell/assets/{diagram-2AECGRRQ-eWyU_pKZ.js → diagram-2AECGRRQ-DYt3G65F.js} +1 -1
- package/web-shell/assets/{diagram-5GNKFQAL-0Bfu3Fq5.js → diagram-5GNKFQAL-BWvROWjY.js} +1 -1
- package/web-shell/assets/{diagram-KO2AKTUF-B6KBKkQP.js → diagram-KO2AKTUF-BvvgwIaQ.js} +1 -1
- package/web-shell/assets/{diagram-LMA3HP47-TToDmeA_.js → diagram-LMA3HP47-E7NLSNKg.js} +1 -1
- package/web-shell/assets/{diagram-OG6HWLK6-CQCkC2Yx.js → diagram-OG6HWLK6-CYmUBgpE.js} +1 -1
- package/web-shell/assets/{erDiagram-TEJ5UH35-Cm9ls1iB.js → erDiagram-TEJ5UH35-BU5gY30h.js} +1 -1
- package/web-shell/assets/{flowDiagram-I6XJVG4X-Dyoz80Pv.js → flowDiagram-I6XJVG4X-V_ZssSZ9.js} +1 -1
- package/web-shell/assets/{ganttDiagram-6RSMTGT7-Cfut9yaU.js → ganttDiagram-6RSMTGT7-QIShlsdI.js} +1 -1
- package/web-shell/assets/{gitGraphDiagram-PVQCEYII-BCuJdlfD.js → gitGraphDiagram-PVQCEYII-DJxdu2YS.js} +1 -1
- package/web-shell/assets/index-BPnhI7gl.css +1 -0
- package/web-shell/assets/index-De4rqTsW.js +706 -0
- package/web-shell/assets/{infoDiagram-5YYISTIA-CXKxF2VL.js → infoDiagram-5YYISTIA-BqjdrFeO.js} +1 -1
- package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-DE7HWSU8.js → ishikawaDiagram-YF4QCWOH-BP_a2YZ2.js} +1 -1
- package/web-shell/assets/{journeyDiagram-JHISSGLW-D__YUfds.js → journeyDiagram-JHISSGLW-BXg-S3Lk.js} +1 -1
- package/web-shell/assets/{kanban-definition-UN3LZRKU-D82R169M.js → kanban-definition-UN3LZRKU-BksAkdEJ.js} +1 -1
- package/web-shell/assets/{linear-DpyMbKqT.js → linear-D2m9-ODE.js} +1 -1
- package/web-shell/assets/{mermaid.core-D1KEFDhn.js → mermaid.core-dTtkZp2F.js} +5 -5
- package/web-shell/assets/{mindmap-definition-RKZ34NQL-BwVUFGFE.js → mindmap-definition-RKZ34NQL-Bft9my8O.js} +1 -1
- package/web-shell/assets/{pieDiagram-4H26LBE5-BO_qoEGx.js → pieDiagram-4H26LBE5-Cw8S-alZ.js} +1 -1
- package/web-shell/assets/{quadrantDiagram-W4KKPZXB-Cx0ZaWPo.js → quadrantDiagram-W4KKPZXB-DaDoTMts.js} +1 -1
- package/web-shell/assets/{requirementDiagram-4Y6WPE33-BJPXejOA.js → requirementDiagram-4Y6WPE33-Cp5kSpwj.js} +1 -1
- package/web-shell/assets/{sankeyDiagram-5OEKKPKP-C1xeIL9i.js → sankeyDiagram-5OEKKPKP-CW8RsJJZ.js} +1 -1
- package/web-shell/assets/{sequenceDiagram-3UESZ5HK-CSYKQUjf.js → sequenceDiagram-3UESZ5HK-DTfpIiJK.js} +1 -1
- package/web-shell/assets/{stateDiagram-AJRCARHV-d9hiHlAW.js → stateDiagram-AJRCARHV-DixFVzEs.js} +1 -1
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-DZgE04s3.js +1 -0
- package/web-shell/assets/{timeline-definition-PNZ67QCA-BhCBkq8k.js → timeline-definition-PNZ67QCA-DYsbXn5l.js} +1 -1
- package/web-shell/assets/{vennDiagram-CIIHVFJN-DPPFWp_y.js → vennDiagram-CIIHVFJN-HUpRpuUp.js} +1 -1
- package/web-shell/assets/{wardley-L42UT6IY-CcOUIgXY.js → wardley-L42UT6IY-cT3nQH_T.js} +1 -1
- package/web-shell/assets/{wardleyDiagram-YWT4CUSO-p7oR5X7r.js → wardleyDiagram-YWT4CUSO-Dmm7J6Qc.js} +1 -1
- package/web-shell/assets/{xychartDiagram-2RQKCTM6-Dfr7-SEy.js → xychartDiagram-2RQKCTM6-CX0L5p9C.js} +1 -1
- package/web-shell/index.html +3 -3
- package/chunks/chunk-77WXWU44.js +0 -26
- package/chunks/contextCommand-3327KUC4.js +0 -54
- package/web-shell/assets/channel-WwImfsc7.js +0 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-CJKQYFeJ.js +0 -1
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-CJKQYFeJ.js +0 -1
- package/web-shell/assets/index-BDZiTAkl.css +0 -1
- package/web-shell/assets/index-DaebdpHq.js +0 -516
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-DgReoybQ.js +0 -1
|
@@ -4,57 +4,68 @@ import {
|
|
|
4
4
|
AgentEventEmitter,
|
|
5
5
|
FileDiscoveryService,
|
|
6
6
|
GitWorktreeService,
|
|
7
|
-
WorkspaceContext,
|
|
8
7
|
generateAgentWorktreeSlug,
|
|
8
|
+
parsePositiveIntegerEnv,
|
|
9
9
|
rebuildToolRegistryOnOverride,
|
|
10
|
+
resolveSavedWorkflowScript,
|
|
10
11
|
stripAnsiAndControl,
|
|
12
|
+
writeWorkflowSnapshot,
|
|
11
13
|
writeWorktreeSessionMarker
|
|
12
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-7QBKO4A6.js";
|
|
13
15
|
import "./chunk-K5PGHDBN.js";
|
|
14
|
-
import "./chunk-
|
|
15
|
-
import "./chunk-
|
|
16
|
-
import "./chunk-
|
|
16
|
+
import "./chunk-TXVGVZYR.js";
|
|
17
|
+
import "./chunk-XU5P23GN.js";
|
|
18
|
+
import "./chunk-2BIF2NVV.js";
|
|
19
|
+
import "./chunk-NWLUISRA.js";
|
|
20
|
+
import "./chunk-3BR4OIOE.js";
|
|
17
21
|
import "./chunk-2MPVVENX.js";
|
|
18
22
|
import "./chunk-ZTQ26VBE.js";
|
|
19
|
-
import "./chunk-
|
|
20
|
-
import "./chunk-LF6BKGZT.js";
|
|
21
|
-
import "./chunk-26ZYKTYZ.js";
|
|
23
|
+
import "./chunk-GZCJS5WH.js";
|
|
22
24
|
import "./chunk-MLZQVCF3.js";
|
|
23
25
|
import "./chunk-LD2XBG6Z.js";
|
|
24
|
-
import "./chunk-
|
|
25
|
-
import "./chunk-
|
|
26
|
-
import
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
import "./chunk-OTBK43JR.js";
|
|
27
|
+
import "./chunk-HGNSRCRB.js";
|
|
28
|
+
import {
|
|
29
|
+
WorkspaceContext
|
|
30
|
+
} from "./chunk-EEEZIVFJ.js";
|
|
31
|
+
import "./chunk-PRYMDRBV.js";
|
|
32
|
+
import {
|
|
33
|
+
WorkflowRunEvent,
|
|
34
|
+
logWorkflowRun,
|
|
35
|
+
read,
|
|
36
|
+
writeLine
|
|
37
|
+
} from "./chunk-HNYTRFAM.js";
|
|
29
38
|
import "./chunk-3PJXIDKI.js";
|
|
30
39
|
import "./chunk-UWCTAVOD.js";
|
|
31
40
|
import "./chunk-OFEVLU4C.js";
|
|
32
41
|
import "./chunk-OMX7CUOE.js";
|
|
33
|
-
import "./chunk-
|
|
34
|
-
import "./chunk-
|
|
42
|
+
import "./chunk-BNXANYLH.js";
|
|
43
|
+
import "./chunk-T2VDEFUU.js";
|
|
35
44
|
import {
|
|
36
45
|
SyntheticOutputTool
|
|
37
|
-
} from "./chunk-
|
|
46
|
+
} from "./chunk-2QDQTWCI.js";
|
|
38
47
|
import {
|
|
39
48
|
BaseDeclarativeTool,
|
|
40
49
|
BaseToolInvocation,
|
|
41
50
|
ToolDisplayNames,
|
|
42
51
|
ToolNames
|
|
43
|
-
} from "./chunk-
|
|
44
|
-
import "./chunk-
|
|
45
|
-
import "./chunk-
|
|
52
|
+
} from "./chunk-L7U2RI5O.js";
|
|
53
|
+
import "./chunk-BGUDAULQ.js";
|
|
54
|
+
import "./chunk-EW6C27XX.js";
|
|
55
|
+
import "./chunk-22IFUCVR.js";
|
|
46
56
|
import {
|
|
47
57
|
createChildAbortController
|
|
48
58
|
} from "./chunk-64WXLC72.js";
|
|
49
|
-
import "./chunk-
|
|
50
|
-
import "./chunk-
|
|
51
|
-
import "./chunk-
|
|
59
|
+
import "./chunk-3UALQ56H.js";
|
|
60
|
+
import "./chunk-F6XNTYNE.js";
|
|
61
|
+
import "./chunk-CGEGHF2C.js";
|
|
62
|
+
import "./chunk-EJYJYJZ2.js";
|
|
52
63
|
import "./chunk-55ZMG67I.js";
|
|
53
64
|
import "./chunk-H6BD2ELD.js";
|
|
54
65
|
import "./chunk-5IFG2VC4.js";
|
|
55
66
|
import {
|
|
56
67
|
createDebugLogger
|
|
57
|
-
} from "./chunk-
|
|
68
|
+
} from "./chunk-C4K3FEQ2.js";
|
|
58
69
|
import "./chunk-ZERZSAZL.js";
|
|
59
70
|
import "./chunk-QN5NZ3UQ.js";
|
|
60
71
|
import "./chunk-BR4QREVK.js";
|
|
@@ -358,9 +369,11 @@ function createWorkflowSandbox(opts) {
|
|
|
358
369
|
// init script without leaking the host function itself when not used.
|
|
359
370
|
hasParallel: !!opts.parallel,
|
|
360
371
|
hasPipeline: !!opts.pipeline,
|
|
372
|
+
hasWorkflow: !!opts.workflow,
|
|
361
373
|
hasBudget: !!opts.budget,
|
|
362
374
|
hostParallel: opts.parallel,
|
|
363
375
|
hostPipeline: opts.pipeline,
|
|
376
|
+
hostWorkflow: opts.workflow,
|
|
364
377
|
budgetTotal: opts.budget ? opts.budget.total : null,
|
|
365
378
|
hostBudgetSpent: opts.budget ? opts.budget.spent.bind(opts.budget) : null,
|
|
366
379
|
hostBudgetRemaining: opts.budget ? opts.budget.remaining.bind(opts.budget) : null
|
|
@@ -466,7 +479,7 @@ function createWorkflowSandbox(opts) {
|
|
|
466
479
|
// FIX-Round1-T13: throw on any opts key not in the allowlist \u2014 catches
|
|
467
480
|
// typos like { scema: ... } that previously slipped through the
|
|
468
481
|
// [key:string]: unknown index signature.
|
|
469
|
-
const KNOWN_AGENT_OPTS = ['label', 'phase', 'schema', 'model', 'isolation', 'agentType'];
|
|
482
|
+
const KNOWN_AGENT_OPTS = ['label', 'phase', 'schema', 'model', 'isolation', 'agentType', 'stallMs'];
|
|
470
483
|
globalThis.agent = vmAsync(function (prompt, agentOpts) {
|
|
471
484
|
agentOpts = agentOpts || {};
|
|
472
485
|
const keys = Object.keys(agentOpts);
|
|
@@ -639,15 +652,64 @@ function createWorkflowSandbox(opts) {
|
|
|
639
652
|
});
|
|
640
653
|
};
|
|
641
654
|
}
|
|
642
|
-
// workflow()
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
655
|
+
// --- workflow (nested, single-level) ---
|
|
656
|
+
// Mirrors agent(): args cross vm\u2192host verbatim (safe direction), the
|
|
657
|
+
// single result is revived back into the vm realm via JSON round-trip
|
|
658
|
+
// (same T1/T8/T14 escape defense as agent / parallel / pipeline). The
|
|
659
|
+
// host impl resolves a saved workflow and runs it sharing this run's
|
|
660
|
+
// agent-count cap + token budget. When __b.hasWorkflow is false, the
|
|
661
|
+
// sandbox is either bare (no resolver wired) OR is itself a nested
|
|
662
|
+
// workflow \u2014 in both cases workflow() must throw, which is how the
|
|
663
|
+
// single-level nesting limit is enforced (a nested sandbox is created
|
|
664
|
+
// without a workflow impl, so its workflow() lands in the else branch).
|
|
665
|
+
if (__b.hasWorkflow) {
|
|
666
|
+
const callWorkflow = vmAsync(function (nameOrRef, wfArgs) {
|
|
667
|
+
// Sanitize args through a JSON round-trip BEFORE crossing so the
|
|
668
|
+
// host only ever sees vm-realm plain objects (same defense as
|
|
669
|
+
// agent()'s safeOpts). nameOrRef may be a string or {scriptPath}.
|
|
670
|
+
var safeRef;
|
|
671
|
+
var safeArgs;
|
|
672
|
+
try {
|
|
673
|
+
safeRef = nameOrRef === undefined
|
|
674
|
+
? undefined
|
|
675
|
+
: JSON.parse(JSON.stringify(nameOrRef));
|
|
676
|
+
safeArgs = wfArgs === undefined
|
|
677
|
+
? undefined
|
|
678
|
+
: JSON.parse(JSON.stringify(wfArgs));
|
|
679
|
+
} catch (e) {
|
|
680
|
+
throw new Error(
|
|
681
|
+
'workflow() received a non-JSON-serializable argument: ' +
|
|
682
|
+
String(e && e.message != null ? e.message : e)
|
|
683
|
+
);
|
|
684
|
+
}
|
|
685
|
+
return __b.hostWorkflow(safeRef, safeArgs).then(function (value) {
|
|
686
|
+
if (value === null || typeof value !== 'object') {
|
|
687
|
+
return value;
|
|
688
|
+
}
|
|
689
|
+
try {
|
|
690
|
+
return JSON.parse(JSON.stringify(value));
|
|
691
|
+
} catch (e) {
|
|
692
|
+
__b.logRevivalFailure(0, String(e && e.message != null ? e.message : e));
|
|
693
|
+
return null;
|
|
694
|
+
}
|
|
695
|
+
});
|
|
649
696
|
});
|
|
650
|
-
|
|
697
|
+
globalThis.workflow = function workflow(nameOrRef, wfArgs) {
|
|
698
|
+
return callWorkflow(nameOrRef, wfArgs);
|
|
699
|
+
};
|
|
700
|
+
} else {
|
|
701
|
+
globalThis.workflow = function workflow() {
|
|
702
|
+
return new Promise(function (_, reject) {
|
|
703
|
+
reject(new Error(
|
|
704
|
+
"workflow() is unavailable here. Either this sandbox was created " +
|
|
705
|
+
"without a saved-workflow resolver, or this script is already " +
|
|
706
|
+
"running as a nested workflow \u2014 workflow() nesting is limited to " +
|
|
707
|
+
"a single level (a workflow cannot call another workflow that " +
|
|
708
|
+
"itself calls workflow())."
|
|
709
|
+
));
|
|
710
|
+
});
|
|
711
|
+
};
|
|
712
|
+
}
|
|
651
713
|
|
|
652
714
|
// --- budget ---
|
|
653
715
|
const safeBudget = Object.create(null);
|
|
@@ -738,8 +800,8 @@ function resolveMaxTokensPerWorkflow(env = process.env) {
|
|
|
738
800
|
if (raw === void 0 || raw.trim() === "") {
|
|
739
801
|
return null;
|
|
740
802
|
}
|
|
741
|
-
const parsed =
|
|
742
|
-
if (
|
|
803
|
+
const parsed = parsePositiveIntegerEnv(raw, 0);
|
|
804
|
+
if (parsed < 1) {
|
|
743
805
|
debugLogger2.warn(
|
|
744
806
|
`Invalid ${MAX_TOKENS_PER_WORKFLOW_ENV}=${JSON.stringify(raw)}, treating as unset (no cap)`
|
|
745
807
|
);
|
|
@@ -813,6 +875,231 @@ var WorkflowBudgetExceededError = class extends Error {
|
|
|
813
875
|
}
|
|
814
876
|
};
|
|
815
877
|
|
|
878
|
+
// packages/core/src/agents/runtime/workflow-stall.ts
|
|
879
|
+
init_esbuild_shims();
|
|
880
|
+
var DEFAULT_STALL_MS = 6e4;
|
|
881
|
+
var MAX_STALL_ATTEMPTS = 3;
|
|
882
|
+
var MAX_WORKFLOW_STALL_MS_ENV = "QWEN_CODE_WORKFLOW_STALL_SECONDS";
|
|
883
|
+
function resolveStallMs(perCall, env = process.env) {
|
|
884
|
+
if (typeof perCall === "number" && Number.isFinite(perCall)) {
|
|
885
|
+
if (perCall === 0) return 0;
|
|
886
|
+
if (perCall > 0) return perCall;
|
|
887
|
+
}
|
|
888
|
+
const raw = env[MAX_WORKFLOW_STALL_MS_ENV];
|
|
889
|
+
if (raw !== void 0 && raw.trim() !== "") {
|
|
890
|
+
const sec = Number(raw);
|
|
891
|
+
if (Number.isFinite(sec) && sec > 0) return sec * 1e3;
|
|
892
|
+
if (sec === 0) return 0;
|
|
893
|
+
}
|
|
894
|
+
return DEFAULT_STALL_MS;
|
|
895
|
+
}
|
|
896
|
+
__name(resolveStallMs, "resolveStallMs");
|
|
897
|
+
var debugLogger3 = createDebugLogger("WORKFLOW_STALL");
|
|
898
|
+
function attachStallWatchdog(emitter, controller, stallMs) {
|
|
899
|
+
if (stallMs <= 0) {
|
|
900
|
+
return { stalled: /* @__PURE__ */ __name(() => false, "stalled"), dispose: /* @__PURE__ */ __name(() => {
|
|
901
|
+
}, "dispose") };
|
|
902
|
+
}
|
|
903
|
+
let inFlightTools = 0;
|
|
904
|
+
let fired = false;
|
|
905
|
+
let timer;
|
|
906
|
+
let disposed = false;
|
|
907
|
+
const clear = /* @__PURE__ */ __name(() => {
|
|
908
|
+
if (timer) {
|
|
909
|
+
clearTimeout(timer);
|
|
910
|
+
timer = void 0;
|
|
911
|
+
}
|
|
912
|
+
}, "clear");
|
|
913
|
+
const arm = /* @__PURE__ */ __name(() => {
|
|
914
|
+
clear();
|
|
915
|
+
if (disposed || fired) return;
|
|
916
|
+
if (inFlightTools > 0) return;
|
|
917
|
+
timer = setTimeout(() => {
|
|
918
|
+
if (disposed || fired) return;
|
|
919
|
+
fired = true;
|
|
920
|
+
debugLogger3.warn(
|
|
921
|
+
`[Workflow] agent dispatch stalled \u2014 no progress for ${stallMs}ms; aborting.`
|
|
922
|
+
);
|
|
923
|
+
try {
|
|
924
|
+
controller.abort("stalled");
|
|
925
|
+
} catch (e) {
|
|
926
|
+
debugLogger3.warn("stall watchdog abort threw:", e);
|
|
927
|
+
}
|
|
928
|
+
}, stallMs);
|
|
929
|
+
if (typeof timer.unref === "function") {
|
|
930
|
+
timer.unref();
|
|
931
|
+
}
|
|
932
|
+
}, "arm");
|
|
933
|
+
const onActivity = /* @__PURE__ */ __name(() => arm(), "onActivity");
|
|
934
|
+
const onToolCall = /* @__PURE__ */ __name(() => {
|
|
935
|
+
inFlightTools += 1;
|
|
936
|
+
clear();
|
|
937
|
+
}, "onToolCall");
|
|
938
|
+
const onToolResult = /* @__PURE__ */ __name(() => {
|
|
939
|
+
inFlightTools = Math.max(0, inFlightTools - 1);
|
|
940
|
+
arm();
|
|
941
|
+
}, "onToolResult");
|
|
942
|
+
emitter.on("round_start" /* ROUND_START */, onActivity);
|
|
943
|
+
emitter.on("round_end" /* ROUND_END */, onActivity);
|
|
944
|
+
emitter.on("stream_text" /* STREAM_TEXT */, onActivity);
|
|
945
|
+
emitter.on("usage_metadata" /* USAGE_METADATA */, onActivity);
|
|
946
|
+
emitter.on("tool_call" /* TOOL_CALL */, onToolCall);
|
|
947
|
+
emitter.on("tool_result" /* TOOL_RESULT */, onToolResult);
|
|
948
|
+
return {
|
|
949
|
+
stalled: /* @__PURE__ */ __name(() => fired, "stalled"),
|
|
950
|
+
dispose: /* @__PURE__ */ __name(() => {
|
|
951
|
+
if (disposed) return;
|
|
952
|
+
disposed = true;
|
|
953
|
+
clear();
|
|
954
|
+
emitter.off("round_start" /* ROUND_START */, onActivity);
|
|
955
|
+
emitter.off("round_end" /* ROUND_END */, onActivity);
|
|
956
|
+
emitter.off("stream_text" /* STREAM_TEXT */, onActivity);
|
|
957
|
+
emitter.off("usage_metadata" /* USAGE_METADATA */, onActivity);
|
|
958
|
+
emitter.off("tool_call" /* TOOL_CALL */, onToolCall);
|
|
959
|
+
emitter.off("tool_result" /* TOOL_RESULT */, onToolResult);
|
|
960
|
+
}, "dispose")
|
|
961
|
+
};
|
|
962
|
+
}
|
|
963
|
+
__name(attachStallWatchdog, "attachStallWatchdog");
|
|
964
|
+
async function runStallResilient(attemptFn, opts) {
|
|
965
|
+
const { stallMs, signal, label } = opts;
|
|
966
|
+
if (stallMs <= 0) {
|
|
967
|
+
const emitter = new AgentEventEmitter();
|
|
968
|
+
return attemptFn(signal ?? new AbortController().signal, emitter);
|
|
969
|
+
}
|
|
970
|
+
let attempt = 0;
|
|
971
|
+
for (; ; ) {
|
|
972
|
+
attempt += 1;
|
|
973
|
+
const controller = new AbortController();
|
|
974
|
+
let onParentAbort;
|
|
975
|
+
if (signal) {
|
|
976
|
+
if (signal.aborted) {
|
|
977
|
+
controller.abort(signal.reason);
|
|
978
|
+
} else {
|
|
979
|
+
onParentAbort = /* @__PURE__ */ __name(() => controller.abort(signal.reason), "onParentAbort");
|
|
980
|
+
signal.addEventListener("abort", onParentAbort);
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
const emitter = new AgentEventEmitter();
|
|
984
|
+
const watchdog = attachStallWatchdog(emitter, controller, stallMs);
|
|
985
|
+
try {
|
|
986
|
+
return await attemptFn(controller.signal, emitter);
|
|
987
|
+
} catch (err) {
|
|
988
|
+
if (signal?.aborted) throw err;
|
|
989
|
+
if (watchdog.stalled() && attempt < MAX_STALL_ATTEMPTS) {
|
|
990
|
+
debugLogger3.warn(
|
|
991
|
+
`[Workflow] agent "${label ?? "workflow-agent"}" stalled (attempt ${attempt}/${MAX_STALL_ATTEMPTS}) \u2014 retrying.`
|
|
992
|
+
);
|
|
993
|
+
continue;
|
|
994
|
+
}
|
|
995
|
+
if (watchdog.stalled()) {
|
|
996
|
+
throw new Error(
|
|
997
|
+
`agent "${label ?? "workflow-agent"}" stalled on all ${MAX_STALL_ATTEMPTS} attempts (no progress for ${stallMs}ms each).`
|
|
998
|
+
);
|
|
999
|
+
}
|
|
1000
|
+
throw err;
|
|
1001
|
+
} finally {
|
|
1002
|
+
watchdog.dispose();
|
|
1003
|
+
if (onParentAbort && signal) {
|
|
1004
|
+
signal.removeEventListener("abort", onParentAbort);
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
__name(runStallResilient, "runStallResilient");
|
|
1010
|
+
|
|
1011
|
+
// packages/core/src/agents/runtime/workflow-journal.ts
|
|
1012
|
+
init_esbuild_shims();
|
|
1013
|
+
import { createHash } from "node:crypto";
|
|
1014
|
+
var debugLogger4 = createDebugLogger("WORKFLOW_JOURNAL");
|
|
1015
|
+
var JOURNAL_KEY_VERSION = "v2";
|
|
1016
|
+
function canonicalizeAgentOpts(opts) {
|
|
1017
|
+
const projected = {};
|
|
1018
|
+
for (const k of ["schema", "model", "isolation", "agentType"]) {
|
|
1019
|
+
const v = opts[k];
|
|
1020
|
+
if (v === void 0 || typeof v === "function") continue;
|
|
1021
|
+
projected[k] = v;
|
|
1022
|
+
}
|
|
1023
|
+
const sortDeep = /* @__PURE__ */ __name((val) => {
|
|
1024
|
+
if (typeof val === "function") return void 0;
|
|
1025
|
+
if (Array.isArray(val)) return val.map(sortDeep);
|
|
1026
|
+
if (val && typeof val === "object") {
|
|
1027
|
+
const out = {};
|
|
1028
|
+
for (const key of Object.keys(val).sort()) {
|
|
1029
|
+
if (key === "__proto__") continue;
|
|
1030
|
+
out[key] = sortDeep(val[key]);
|
|
1031
|
+
}
|
|
1032
|
+
return out;
|
|
1033
|
+
}
|
|
1034
|
+
return val;
|
|
1035
|
+
}, "sortDeep");
|
|
1036
|
+
try {
|
|
1037
|
+
return JSON.stringify(sortDeep(projected));
|
|
1038
|
+
} catch {
|
|
1039
|
+
return "{}";
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
__name(canonicalizeAgentOpts, "canonicalizeAgentOpts");
|
|
1043
|
+
function deriveAgentKey(prefixHash, prompt, opts) {
|
|
1044
|
+
const hash = createHash("sha256");
|
|
1045
|
+
hash.update(prefixHash);
|
|
1046
|
+
hash.update("\0");
|
|
1047
|
+
hash.update(prompt);
|
|
1048
|
+
hash.update("\0");
|
|
1049
|
+
hash.update(canonicalizeAgentOpts(opts));
|
|
1050
|
+
return `${JOURNAL_KEY_VERSION}:${hash.digest("hex")}`;
|
|
1051
|
+
}
|
|
1052
|
+
__name(deriveAgentKey, "deriveAgentKey");
|
|
1053
|
+
function deriveArgsSeed(args) {
|
|
1054
|
+
const hash = createHash("sha256");
|
|
1055
|
+
let serialized;
|
|
1056
|
+
try {
|
|
1057
|
+
serialized = JSON.stringify(args ?? null) ?? "null";
|
|
1058
|
+
} catch {
|
|
1059
|
+
serialized = "non-serializable-args";
|
|
1060
|
+
}
|
|
1061
|
+
hash.update(serialized);
|
|
1062
|
+
return `${JOURNAL_KEY_VERSION}:${hash.digest("hex")}`;
|
|
1063
|
+
}
|
|
1064
|
+
__name(deriveArgsSeed, "deriveArgsSeed");
|
|
1065
|
+
function buildReplay(entries) {
|
|
1066
|
+
const results = /* @__PURE__ */ new Map();
|
|
1067
|
+
const started = /* @__PURE__ */ new Map();
|
|
1068
|
+
for (const e of entries) {
|
|
1069
|
+
if (e.type === "result") {
|
|
1070
|
+
results.set(e.key, e);
|
|
1071
|
+
} else if (e.type === "started") {
|
|
1072
|
+
const list = started.get(e.key);
|
|
1073
|
+
if (list) list.push(e);
|
|
1074
|
+
else started.set(e.key, [e]);
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
return { results, started };
|
|
1078
|
+
}
|
|
1079
|
+
__name(buildReplay, "buildReplay");
|
|
1080
|
+
var WorkflowJournal = class {
|
|
1081
|
+
constructor(path2) {
|
|
1082
|
+
this.path = path2;
|
|
1083
|
+
}
|
|
1084
|
+
static {
|
|
1085
|
+
__name(this, "WorkflowJournal");
|
|
1086
|
+
}
|
|
1087
|
+
/** Load + parse all entries into replay maps. Empty maps if no file. */
|
|
1088
|
+
async load() {
|
|
1089
|
+
try {
|
|
1090
|
+
const entries = await read(this.path);
|
|
1091
|
+
return buildReplay(entries);
|
|
1092
|
+
} catch (e) {
|
|
1093
|
+
debugLogger4.warn(`WorkflowJournal.load failed for ${this.path}: ${e}`);
|
|
1094
|
+
return { results: /* @__PURE__ */ new Map(), started: /* @__PURE__ */ new Map() };
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
/** Append one entry. Rejects only on I/O error (callers `.catch`). */
|
|
1098
|
+
append(entry) {
|
|
1099
|
+
return writeLine(this.path, entry);
|
|
1100
|
+
}
|
|
1101
|
+
};
|
|
1102
|
+
|
|
816
1103
|
// packages/core/src/agents/runtime/workflow-prompts.ts
|
|
817
1104
|
init_esbuild_shims();
|
|
818
1105
|
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.';
|
|
@@ -880,8 +1167,8 @@ function resolveMaxAgentsPerRun(env = process.env) {
|
|
|
880
1167
|
if (raw === void 0 || raw.trim() === "") {
|
|
881
1168
|
return DEFAULT_MAX_AGENTS_PER_RUN;
|
|
882
1169
|
}
|
|
883
|
-
const parsed =
|
|
884
|
-
if (
|
|
1170
|
+
const parsed = parsePositiveIntegerEnv(raw, 0);
|
|
1171
|
+
if (parsed < 1) {
|
|
885
1172
|
debugLogger.warn(
|
|
886
1173
|
`Invalid ${MAX_WORKFLOW_AGENTS_ENV}=${JSON.stringify(raw)}, using default (${DEFAULT_MAX_AGENTS_PER_RUN})`
|
|
887
1174
|
);
|
|
@@ -901,8 +1188,8 @@ var HARD_MAX_CONCURRENCY_CEILING = 64;
|
|
|
901
1188
|
function resolveConcurrencyLimit(env = process.env) {
|
|
902
1189
|
const raw = env[MAX_WORKFLOW_CONCURRENCY_ENV];
|
|
903
1190
|
if (raw !== void 0 && raw.trim() !== "") {
|
|
904
|
-
const parsed =
|
|
905
|
-
if (
|
|
1191
|
+
const parsed = parsePositiveIntegerEnv(raw, 0);
|
|
1192
|
+
if (parsed >= 1) {
|
|
906
1193
|
if (parsed > HARD_MAX_CONCURRENCY_CEILING) {
|
|
907
1194
|
debugLogger.warn(
|
|
908
1195
|
`${MAX_WORKFLOW_CONCURRENCY_ENV}=${parsed} exceeds hard ceiling (${HARD_MAX_CONCURRENCY_CEILING}); clamping.`
|
|
@@ -946,48 +1233,72 @@ function sanitizeForErrorMessage(value) {
|
|
|
946
1233
|
__name(sanitizeForErrorMessage, "sanitizeForErrorMessage");
|
|
947
1234
|
function createProductionDispatch(config, signal, onTokens) {
|
|
948
1235
|
return async (prompt, opts) => {
|
|
949
|
-
const
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
opts.label ?? "workflow-agent",
|
|
1236
|
+
const stallMs = resolveStallMs(
|
|
1237
|
+
typeof opts.stallMs === "number" ? opts.stallMs : void 0
|
|
1238
|
+
);
|
|
1239
|
+
return runStallResilient(
|
|
1240
|
+
(attemptSignal, emitter) => runSingleDispatch(
|
|
955
1241
|
config,
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
max_turns: WORKFLOW_SUBAGENT_MAX_TURNS,
|
|
967
|
-
max_time_minutes: WORKFLOW_SUBAGENT_MAX_TIME_MINUTES
|
|
968
|
-
},
|
|
969
|
-
// T11 (PR #4732 R1): disallow SendMessage / ExitPlanMode to align with
|
|
970
|
-
// upstream Tg8 — closes the back-channel that would let a subagent
|
|
971
|
-
// deliver its answer via user message instead of the script's read.
|
|
972
|
-
{ tools: ["*"], disallowedTools: WORKFLOW_SUBAGENT_DISALLOWED_TOOLS }
|
|
973
|
-
);
|
|
974
|
-
try {
|
|
975
|
-
await subagent.execute(ctx, signal);
|
|
976
|
-
} finally {
|
|
977
|
-
reportTokens(subagent, opts, onTokens);
|
|
978
|
-
}
|
|
979
|
-
const mode = subagent.getTerminateMode();
|
|
980
|
-
if (mode !== "GOAL" /* GOAL */) {
|
|
981
|
-
throw new Error(
|
|
982
|
-
`Workflow subagent did not complete (terminate mode: ${mode}).`
|
|
983
|
-
);
|
|
1242
|
+
prompt,
|
|
1243
|
+
opts,
|
|
1244
|
+
attemptSignal,
|
|
1245
|
+
emitter,
|
|
1246
|
+
onTokens
|
|
1247
|
+
),
|
|
1248
|
+
{
|
|
1249
|
+
stallMs,
|
|
1250
|
+
signal,
|
|
1251
|
+
label: typeof opts.label === "string" ? opts.label : void 0
|
|
984
1252
|
}
|
|
985
|
-
|
|
986
|
-
}
|
|
987
|
-
return runOverridePath(config, ctx, opts, signal, onTokens);
|
|
1253
|
+
);
|
|
988
1254
|
};
|
|
989
1255
|
}
|
|
990
1256
|
__name(createProductionDispatch, "createProductionDispatch");
|
|
1257
|
+
async function runSingleDispatch(config, prompt, opts, attemptSignal, emitter, onTokens) {
|
|
1258
|
+
const { AgentHeadless, ContextState } = await import("./agent-headless-XO7MM6JT.js");
|
|
1259
|
+
const ctx = new ContextState();
|
|
1260
|
+
ctx.set("task_prompt", prompt);
|
|
1261
|
+
if (opts.agentType === void 0 && opts.model === void 0 && opts.isolation === void 0 && opts.schema === void 0) {
|
|
1262
|
+
const subagent = await AgentHeadless.create(
|
|
1263
|
+
opts.label ?? "workflow-agent",
|
|
1264
|
+
config,
|
|
1265
|
+
{
|
|
1266
|
+
systemPrompt: WORKFLOW_SUBAGENT_SYSTEM_PROMPT,
|
|
1267
|
+
initialMessages: []
|
|
1268
|
+
},
|
|
1269
|
+
{},
|
|
1270
|
+
// T11 (PR #4732 R1): bound resource ceiling so a single agent() call
|
|
1271
|
+
// cannot loop the model indefinitely. Without this, runConfig was {}
|
|
1272
|
+
// and the loop guards never tripped — combined with the cancellation
|
|
1273
|
+
// bug below, workflows were effectively unkillable.
|
|
1274
|
+
{
|
|
1275
|
+
max_turns: WORKFLOW_SUBAGENT_MAX_TURNS,
|
|
1276
|
+
max_time_minutes: WORKFLOW_SUBAGENT_MAX_TIME_MINUTES
|
|
1277
|
+
},
|
|
1278
|
+
// T11 (PR #4732 R1): disallow SendMessage / ExitPlanMode to align with
|
|
1279
|
+
// upstream Tg8 — closes the back-channel that would let a subagent
|
|
1280
|
+
// deliver its answer via user message instead of the script's read.
|
|
1281
|
+
{ tools: ["*"], disallowedTools: WORKFLOW_SUBAGENT_DISALLOWED_TOOLS },
|
|
1282
|
+
// P-stall: the stall-watchdog emitter observes reasoning-loop events
|
|
1283
|
+
// (round/tool/usage) to detect a hang and abort `attemptSignal`.
|
|
1284
|
+
emitter
|
|
1285
|
+
);
|
|
1286
|
+
try {
|
|
1287
|
+
await subagent.execute(ctx, attemptSignal);
|
|
1288
|
+
} finally {
|
|
1289
|
+
reportTokens(subagent, opts, onTokens);
|
|
1290
|
+
}
|
|
1291
|
+
const mode = subagent.getTerminateMode();
|
|
1292
|
+
if (mode !== "GOAL" /* GOAL */) {
|
|
1293
|
+
throw new Error(
|
|
1294
|
+
`Workflow subagent did not complete (terminate mode: ${mode}).`
|
|
1295
|
+
);
|
|
1296
|
+
}
|
|
1297
|
+
return subagent.getFinalText();
|
|
1298
|
+
}
|
|
1299
|
+
return runOverridePath(config, ctx, opts, attemptSignal, onTokens, emitter);
|
|
1300
|
+
}
|
|
1301
|
+
__name(runSingleDispatch, "runSingleDispatch");
|
|
991
1302
|
function reportTokens(subagent, opts, onTokens) {
|
|
992
1303
|
if (!onTokens) return;
|
|
993
1304
|
try {
|
|
@@ -998,7 +1309,7 @@ function reportTokens(subagent, opts, onTokens) {
|
|
|
998
1309
|
}
|
|
999
1310
|
}
|
|
1000
1311
|
__name(reportTokens, "reportTokens");
|
|
1001
|
-
async function runOverridePath(config, ctx, opts, signal, onTokens) {
|
|
1312
|
+
async function runOverridePath(config, ctx, opts, signal, onTokens, emitter) {
|
|
1002
1313
|
if (opts.isolation === "remote") {
|
|
1003
1314
|
throw new Error(
|
|
1004
1315
|
"agent({isolation:'remote'}) is not available in this build."
|
|
@@ -1079,7 +1390,10 @@ ${WORKFLOW_SUBAGENT_SYSTEM_PROMPT_WITH_SCHEMA}` : WORKFLOW_SUBAGENT_SYSTEM_PROMP
|
|
|
1079
1390
|
schemaState.abortController = child;
|
|
1080
1391
|
dispatchSignal = child.signal;
|
|
1081
1392
|
}
|
|
1082
|
-
const eventEmitter = schemaState ?
|
|
1393
|
+
const eventEmitter = emitter ?? (schemaState ? new AgentEventEmitter() : void 0);
|
|
1394
|
+
if (schemaState && eventEmitter) {
|
|
1395
|
+
attachSchemaListeners(eventEmitter, schemaState);
|
|
1396
|
+
}
|
|
1083
1397
|
const { subagent, dispose } = await subagentMgr.createAgentHeadless(
|
|
1084
1398
|
augmented,
|
|
1085
1399
|
effectiveContext,
|
|
@@ -1318,8 +1632,7 @@ function createSchemaModeState() {
|
|
|
1318
1632
|
};
|
|
1319
1633
|
}
|
|
1320
1634
|
__name(createSchemaModeState, "createSchemaModeState");
|
|
1321
|
-
function
|
|
1322
|
-
const emitter = new AgentEventEmitter();
|
|
1635
|
+
function attachSchemaListeners(emitter, state) {
|
|
1323
1636
|
const targetTool = ToolNames.STRUCTURED_OUTPUT;
|
|
1324
1637
|
emitter.on("tool_call" /* TOOL_CALL */, (evt) => {
|
|
1325
1638
|
if (evt.name !== targetTool) return;
|
|
@@ -1341,9 +1654,8 @@ function createSchemaEventEmitter(state) {
|
|
|
1341
1654
|
state.abortController.abort();
|
|
1342
1655
|
}
|
|
1343
1656
|
});
|
|
1344
|
-
return emitter;
|
|
1345
1657
|
}
|
|
1346
|
-
__name(
|
|
1658
|
+
__name(attachSchemaListeners, "attachSchemaListeners");
|
|
1347
1659
|
async function createSchemaConfigOverride(base, schema) {
|
|
1348
1660
|
const override = Object.create(base);
|
|
1349
1661
|
await rebuildToolRegistryOnOverride(override, base);
|
|
@@ -1367,7 +1679,46 @@ var WorkflowOrchestrator = class {
|
|
|
1367
1679
|
let agentCount = 0;
|
|
1368
1680
|
const emitter = req.emitter;
|
|
1369
1681
|
const budget = req.budget;
|
|
1682
|
+
const journal = req.journal;
|
|
1683
|
+
const replay = req.resumeReplay;
|
|
1684
|
+
let prefixHash = deriveArgsSeed(req.args);
|
|
1685
|
+
let hadMiss = false;
|
|
1686
|
+
let journalAgentId = 0;
|
|
1370
1687
|
const countedDispatch = /* @__PURE__ */ __name((prompt, opts) => {
|
|
1688
|
+
let journalKey;
|
|
1689
|
+
let journalEntryId;
|
|
1690
|
+
if (journal) {
|
|
1691
|
+
journalKey = deriveAgentKey(prefixHash, prompt, opts);
|
|
1692
|
+
prefixHash = journalKey;
|
|
1693
|
+
if (!hadMiss && replay) {
|
|
1694
|
+
const cached = replay.results.get(journalKey);
|
|
1695
|
+
if (cached !== void 0) {
|
|
1696
|
+
const respawns = replay.started.get(journalKey);
|
|
1697
|
+
if (respawns && respawns.length > 0) {
|
|
1698
|
+
debugLogger.info(
|
|
1699
|
+
`[Workflow] resume cache hit after ${respawns.length} prior respawn(s) for runId=${runId}.`
|
|
1700
|
+
);
|
|
1701
|
+
}
|
|
1702
|
+
const label2 = typeof opts.label === "string" ? opts.label : void 0;
|
|
1703
|
+
try {
|
|
1704
|
+
emitter?.agentDispatched?.(label2);
|
|
1705
|
+
} catch (e) {
|
|
1706
|
+
debugLogger.warn("emitter.agentDispatched threw:", e);
|
|
1707
|
+
}
|
|
1708
|
+
try {
|
|
1709
|
+
emitter?.agentCompleted?.(label2);
|
|
1710
|
+
} catch (e) {
|
|
1711
|
+
debugLogger.warn("emitter.agentCompleted threw:", e);
|
|
1712
|
+
}
|
|
1713
|
+
return Promise.resolve(cached.result);
|
|
1714
|
+
}
|
|
1715
|
+
}
|
|
1716
|
+
hadMiss = true;
|
|
1717
|
+
journalEntryId = String(journalAgentId += 1);
|
|
1718
|
+
journal.append({ type: "started", key: journalKey, agentId: journalEntryId }).catch(
|
|
1719
|
+
(e) => debugLogger.warn(`journal started-append failed: ${e}`)
|
|
1720
|
+
);
|
|
1721
|
+
}
|
|
1371
1722
|
if (budget && budget.total !== null && budget.remaining() <= 0) {
|
|
1372
1723
|
debugLogger.warn(
|
|
1373
1724
|
`[Workflow] budget gate refused dispatch at entry: runId=${runId} spent=${budget.spent()} total=${budget.total}`
|
|
@@ -1409,6 +1760,16 @@ var WorkflowOrchestrator = class {
|
|
|
1409
1760
|
} catch (e) {
|
|
1410
1761
|
debugLogger.warn("emitter.agentCompleted threw:", e);
|
|
1411
1762
|
}
|
|
1763
|
+
if (journal && journalKey !== void 0) {
|
|
1764
|
+
journal.append({
|
|
1765
|
+
type: "result",
|
|
1766
|
+
key: journalKey,
|
|
1767
|
+
agentId: journalEntryId ?? "",
|
|
1768
|
+
result
|
|
1769
|
+
}).catch(
|
|
1770
|
+
(e) => debugLogger.warn(`journal result-append failed: ${e}`)
|
|
1771
|
+
);
|
|
1772
|
+
}
|
|
1412
1773
|
if (budget) {
|
|
1413
1774
|
try {
|
|
1414
1775
|
emitter?.budgetUpdated?.(budget.spent(), budget.total);
|
|
@@ -1438,11 +1799,27 @@ var WorkflowOrchestrator = class {
|
|
|
1438
1799
|
}, "countedDispatch");
|
|
1439
1800
|
const parallelImpl = makeParallelImpl(signal);
|
|
1440
1801
|
const pipelineImpl = makePipelineImpl(signal);
|
|
1802
|
+
const resolveSavedWorkflow = req.resolveSavedWorkflow;
|
|
1803
|
+
const workflowImpl = resolveSavedWorkflow ? async (nameOrRef, nestedArgs) => {
|
|
1804
|
+
const resolved = await resolveSavedWorkflow(nameOrRef);
|
|
1805
|
+
const nestedSandbox = createWorkflowSandbox({
|
|
1806
|
+
args: nestedArgs,
|
|
1807
|
+
dispatch: countedDispatch,
|
|
1808
|
+
parallel: parallelImpl,
|
|
1809
|
+
pipeline: pipelineImpl,
|
|
1810
|
+
abortOnTimeout: req.abortOnTimeout,
|
|
1811
|
+
emitter,
|
|
1812
|
+
budget
|
|
1813
|
+
// No `workflow` — single-level nesting limit.
|
|
1814
|
+
});
|
|
1815
|
+
return nestedSandbox.run(resolved.script);
|
|
1816
|
+
} : void 0;
|
|
1441
1817
|
const sandbox = createWorkflowSandbox({
|
|
1442
1818
|
args: req.args,
|
|
1443
1819
|
dispatch: countedDispatch,
|
|
1444
1820
|
parallel: parallelImpl,
|
|
1445
1821
|
pipeline: pipelineImpl,
|
|
1822
|
+
workflow: workflowImpl,
|
|
1446
1823
|
abortOnTimeout: req.abortOnTimeout,
|
|
1447
1824
|
emitter,
|
|
1448
1825
|
budget
|
|
@@ -1466,19 +1843,31 @@ var WorkflowOrchestrator = class {
|
|
|
1466
1843
|
}
|
|
1467
1844
|
}
|
|
1468
1845
|
};
|
|
1469
|
-
async function settleToNullArray(thunks, signal) {
|
|
1846
|
+
async function settleToNullArray(thunks, signal, kind = "parallel") {
|
|
1470
1847
|
const settled = await Promise.allSettled(
|
|
1471
1848
|
thunks.map((t) => Promise.resolve().then(t))
|
|
1472
1849
|
);
|
|
1473
1850
|
if (signal?.aborted)
|
|
1474
1851
|
throw new DOMException("Workflow run aborted.", "AbortError");
|
|
1475
|
-
|
|
1852
|
+
let budgetDropped = 0;
|
|
1853
|
+
const result = settled.map((r, i) => {
|
|
1476
1854
|
if (r.status === "fulfilled") return r.value;
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1855
|
+
const reason = r.reason;
|
|
1856
|
+
if (reason?.name === "WorkflowBudgetExceededError") {
|
|
1857
|
+
budgetDropped += 1;
|
|
1858
|
+
} else {
|
|
1859
|
+
debugLogger.warn(
|
|
1860
|
+
`Workflow thunk at index ${i} rejected: ${String(reason?.message ?? r.reason)}`
|
|
1861
|
+
);
|
|
1862
|
+
}
|
|
1480
1863
|
return null;
|
|
1481
1864
|
});
|
|
1865
|
+
if (budgetDropped > 0) {
|
|
1866
|
+
debugLogger.warn(
|
|
1867
|
+
`${kind}: ${budgetDropped} slot${budgetDropped === 1 ? "" : "s"} dropped \u2014 token budget exceeded.`
|
|
1868
|
+
);
|
|
1869
|
+
}
|
|
1870
|
+
return result;
|
|
1482
1871
|
}
|
|
1483
1872
|
__name(settleToNullArray, "settleToNullArray");
|
|
1484
1873
|
function makeParallelImpl(signal) {
|
|
@@ -1524,7 +1913,7 @@ function makePipelineImpl(signal) {
|
|
|
1524
1913
|
const chains = items.map(
|
|
1525
1914
|
(item, idx) => () => runPipelineChain(item, idx, stages)
|
|
1526
1915
|
);
|
|
1527
|
-
return settleToNullArray(chains, signal);
|
|
1916
|
+
return settleToNullArray(chains, signal, "pipeline");
|
|
1528
1917
|
};
|
|
1529
1918
|
}
|
|
1530
1919
|
__name(makePipelineImpl, "makePipelineImpl");
|
|
@@ -1549,6 +1938,7 @@ __name(extractErrorMessage, "extractErrorMessage");
|
|
|
1549
1938
|
|
|
1550
1939
|
// packages/core/src/tools/workflow/workflow.ts
|
|
1551
1940
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
1941
|
+
import * as path from "node:path";
|
|
1552
1942
|
var WORKFLOW_PARAM_SCHEMA = {
|
|
1553
1943
|
type: "object",
|
|
1554
1944
|
properties: {
|
|
@@ -1556,11 +1946,22 @@ var WORKFLOW_PARAM_SCHEMA = {
|
|
|
1556
1946
|
type: "string",
|
|
1557
1947
|
description: "JavaScript source of the workflow. Wrapped as an async IIFE. May call the injected globals `phase(title)`, `log(msg)`, `agent(prompt, opts?)`, and read `args`. agent() opts: `{ label?, phase?, schema?, model?, agentType?, isolation? }`. `schema` (JSON Schema object): the subagent must deliver its result by calling `structured_output` with arguments matching the schema; agent() resolves to the validated object. Two failed attempts produce a terminal error \"subagent completed without calling StructuredOutput (after 2 in-conversation nudges)\". `agentType` (string): resolves against the declarative-agents registry (`.qwen/agents/<name>.md`, project then user then built-in). Unresolved names throw \"agent({agentType}): agent type 'X' not found\". `model` (string): per-call model override; routes provider correctly via the subagent runtime view. `isolation`: `'worktree'` provisions a fresh git worktree under `<projectRoot>/.qwen/worktrees/agent-<7hex>`; the worktree is auto-removed if no changes, otherwise the path and branch are returned alongside the result. `'remote'` throws \"agent({isolation:'remote'}) is not available in this build\" (parity with upstream). isolation=worktree refuses to run when the parent working tree has uncommitted changes (the subagent would see a stale HEAD). Workflow subagents always have SendMessage / ExitPlanMode in their disallowed-tool floor regardless of agentType. Concurrency: `parallel([() => agent(...), ...])` runs thunks through a shared per-run window (default `max(1, min(16, cpus-2))` agents in flight; override via `QWEN_CODE_MAX_WORKFLOW_CONCURRENCY`) and resolves to a position-aligned array \u2014 a thunk that throws, or resolves to a non-JSON-serializable value, becomes `null` at its index (errors-as-data); parallel() itself rejects only on invalid arguments or abort. `pipeline(items, ...stages)` runs each item through the stages (staggered, no inter-stage barrier); a stage that throws, returns `null`, or returns a non-JSON-serializable value drops that item to `null`. Pass THUNKS to parallel, not eager calls: `parallel([() => agent(...)])`, not `parallel([agent(...)])`. At most 1000 agent() calls per run (override via `QWEN_CODE_MAX_WORKFLOW_AGENTS`). `Date.now()` and `Math.random()` both throw \u2014 workflow scripts must be deterministic for resume. `export const meta = {...}` declarations are stripped before execution."
|
|
1558
1948
|
},
|
|
1949
|
+
scriptPath: {
|
|
1950
|
+
type: "string",
|
|
1951
|
+
description: "Optional. Absolute path to a saved workflow `.js` file to load and run instead of inline `script`. Primarily set by the `/<name>` saved-workflow slash command. 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."
|
|
1952
|
+
},
|
|
1559
1953
|
args: {
|
|
1560
1954
|
description: "Optional structured value bound to the `args` global. Pass actual JSON, not a stringified value."
|
|
1955
|
+
},
|
|
1956
|
+
resumeFromRunId: {
|
|
1957
|
+
type: "string",
|
|
1958
|
+
description: "Optional. Resume a prior workflow run by id (e.g. wf_abc123\u2026). Re-runs the SAME script; 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 same script and args as the original run for the cache to apply."
|
|
1561
1959
|
}
|
|
1562
|
-
}
|
|
1563
|
-
required
|
|
1960
|
+
}
|
|
1961
|
+
// `script` is required UNLESS `scriptPath` is supplied; this XOR can't be
|
|
1962
|
+
// expressed as a plain `required` list, so it's enforced in
|
|
1963
|
+
// `validateToolParamValues`. Inline authoring (the LLM path) should always
|
|
1964
|
+
// pass `script`; the `scriptPath` property description states the XOR.
|
|
1564
1965
|
};
|
|
1565
1966
|
var WorkflowToolInvocation = class extends BaseToolInvocation {
|
|
1566
1967
|
constructor(config, toolOptions, params) {
|
|
@@ -1572,7 +1973,10 @@ var WorkflowToolInvocation = class extends BaseToolInvocation {
|
|
|
1572
1973
|
__name(this, "WorkflowToolInvocation");
|
|
1573
1974
|
}
|
|
1574
1975
|
getDescription() {
|
|
1575
|
-
|
|
1976
|
+
if (this.params.scriptPath && this.params.script === void 0) {
|
|
1977
|
+
return `Run saved workflow (${path.basename(this.params.scriptPath)})`;
|
|
1978
|
+
}
|
|
1979
|
+
return `Run a workflow script (${this.params.script?.length ?? 0} chars)`;
|
|
1576
1980
|
}
|
|
1577
1981
|
toolLocations() {
|
|
1578
1982
|
return [];
|
|
@@ -1592,7 +1996,26 @@ var WorkflowToolInvocation = class extends BaseToolInvocation {
|
|
|
1592
1996
|
(outputTokens) => budget.recordSpent(outputTokens)
|
|
1593
1997
|
);
|
|
1594
1998
|
const orchestrator = new WorkflowOrchestrator(dispatch);
|
|
1595
|
-
|
|
1999
|
+
let resolvedScript = this.params.script ?? "";
|
|
2000
|
+
let resolvedScriptPath = this.params.scriptPath;
|
|
2001
|
+
if (this.params.scriptPath && this.params.script === void 0) {
|
|
2002
|
+
const loaded = await resolveSavedWorkflowScript(
|
|
2003
|
+
{ scriptPath: this.params.scriptPath },
|
|
2004
|
+
this.config
|
|
2005
|
+
);
|
|
2006
|
+
resolvedScript = loaded.script;
|
|
2007
|
+
resolvedScriptPath = loaded.scriptPath;
|
|
2008
|
+
}
|
|
2009
|
+
const runId = this.params.resumeFromRunId ?? `wf_${randomBytes2(8).toString("hex")}`;
|
|
2010
|
+
let journal;
|
|
2011
|
+
let resumeReplay;
|
|
2012
|
+
const storage = this.config.storage;
|
|
2013
|
+
if (storage) {
|
|
2014
|
+
journal = new WorkflowJournal(storage.getWorkflowRunJournalPath(runId));
|
|
2015
|
+
if (this.params.resumeFromRunId) {
|
|
2016
|
+
resumeReplay = await journal.load();
|
|
2017
|
+
}
|
|
2018
|
+
}
|
|
1596
2019
|
const registry = this.config.getWorkflowRunRegistry?.();
|
|
1597
2020
|
const registryEntry = registry?.register({
|
|
1598
2021
|
runId,
|
|
@@ -1606,7 +2029,13 @@ var WorkflowToolInvocation = class extends BaseToolInvocation {
|
|
|
1606
2029
|
// P5: seed the cap so the dialog can render the `M / N` form
|
|
1607
2030
|
// immediately, before the first `budgetUpdated` fires. Stays
|
|
1608
2031
|
// `null` when no env override.
|
|
1609
|
-
tokenBudgetTotal: budget.total
|
|
2032
|
+
tokenBudgetTotal: budget.total,
|
|
2033
|
+
// P7b: carry the script source so a completed run can be snapshotted
|
|
2034
|
+
// to disk and saved to `.qwen/workflows/<name>.js` from the dialog.
|
|
2035
|
+
// `scriptPath` is set when the run was launched from a saved file (run
|
|
2036
|
+
// provenance for the snapshot).
|
|
2037
|
+
script: resolvedScript,
|
|
2038
|
+
scriptPath: resolvedScriptPath
|
|
1610
2039
|
});
|
|
1611
2040
|
const emitter = {
|
|
1612
2041
|
phaseStarted: /* @__PURE__ */ __name((title) => {
|
|
@@ -1629,12 +2058,18 @@ var WorkflowToolInvocation = class extends BaseToolInvocation {
|
|
|
1629
2058
|
};
|
|
1630
2059
|
try {
|
|
1631
2060
|
const outcome = await orchestrator.run({
|
|
1632
|
-
script:
|
|
2061
|
+
script: resolvedScript,
|
|
1633
2062
|
args: this.params.args,
|
|
1634
2063
|
abortOnTimeout: dispatchController,
|
|
1635
2064
|
runId,
|
|
1636
2065
|
emitter,
|
|
1637
|
-
budget
|
|
2066
|
+
budget,
|
|
2067
|
+
// P-nested: resolve `workflow('<name>')` / `workflow({scriptPath})`
|
|
2068
|
+
// against the saved-workflow scripts in `.qwen/workflows/`.
|
|
2069
|
+
resolveSavedWorkflow: /* @__PURE__ */ __name((ref) => resolveSavedWorkflowScript(ref, this.config), "resolveSavedWorkflow"),
|
|
2070
|
+
// P6: resume journal (always wired) + replay maps (resume only).
|
|
2071
|
+
journal,
|
|
2072
|
+
resumeReplay
|
|
1638
2073
|
});
|
|
1639
2074
|
if (registryEntry) {
|
|
1640
2075
|
registryEntry.meta = outcome.meta;
|
|
@@ -1704,6 +2139,23 @@ ${safeStringifyDisplayPayload({
|
|
|
1704
2139
|
};
|
|
1705
2140
|
} finally {
|
|
1706
2141
|
dispatchController.abort();
|
|
2142
|
+
if (registryEntry && registryEntry.status !== "running") {
|
|
2143
|
+
await writeWorkflowSnapshot(this.config, registryEntry);
|
|
2144
|
+
try {
|
|
2145
|
+
logWorkflowRun(
|
|
2146
|
+
this.config,
|
|
2147
|
+
new WorkflowRunEvent({
|
|
2148
|
+
status: registryEntry.status,
|
|
2149
|
+
agents_dispatched: registryEntry.agentsDispatched,
|
|
2150
|
+
agents_completed: registryEntry.agentsCompleted,
|
|
2151
|
+
phase_count: registryEntry.phases.length,
|
|
2152
|
+
tokens_spent: registryEntry.tokensSpent,
|
|
2153
|
+
duration_ms: (registryEntry.endTime ?? registryEntry.startTime) - registryEntry.startTime
|
|
2154
|
+
})
|
|
2155
|
+
);
|
|
2156
|
+
} catch {
|
|
2157
|
+
}
|
|
2158
|
+
}
|
|
1707
2159
|
}
|
|
1708
2160
|
}
|
|
1709
2161
|
};
|
|
@@ -1803,7 +2255,7 @@ var WorkflowTool = class extends BaseDeclarativeTool {
|
|
|
1803
2255
|
super(
|
|
1804
2256
|
ToolNames.WORKFLOW,
|
|
1805
2257
|
ToolDisplayNames.WORKFLOW,
|
|
1806
|
-
"Execute a workflow script that orchestrates subagents. Supports `phase`, `log`, sequential `agent`, concurrent fan-out via `parallel(thunks)` / `pipeline(items, ...stages)` (default `max(1, min(16, cpus-2))` agents in flight per run, up to 1000 agents total; both env-overridable), per-call `agent({ schema, agentType, model, isolation: 'worktree' })` for structured-output contracts, declarative-agent selection, model override, and git-worktree-isolated subagents.
|
|
2258
|
+
"Execute a workflow script that orchestrates subagents. Supports `phase`, `log`, sequential `agent`, concurrent fan-out via `parallel(thunks)` / `pipeline(items, ...stages)` (default `max(1, min(16, cpus-2))` agents in flight per run, up to 1000 agents total; both env-overridable), per-call `agent({ schema, agentType, model, isolation: 'worktree' })` for structured-output contracts, declarative-agent selection, model override, and git-worktree-isolated subagents. Pass `resumeFromRunId` to resume a prior run \u2014 agent() calls whose rolling prefix-hash matches the journal are served from cache for the longest unchanged prefix. Runs are tracked in the background-tasks view and the `/workflows` dialog (live phase tree, token usage, cancel). Scripts run in a node:vm sandbox without access to the filesystem or shell; all I/O happens through the spawned agents.",
|
|
1807
2259
|
"other" /* Other */,
|
|
1808
2260
|
WORKFLOW_PARAM_SCHEMA,
|
|
1809
2261
|
/* isOutputMarkdown */
|
|
@@ -1818,8 +2270,16 @@ var WorkflowTool = class extends BaseDeclarativeTool {
|
|
|
1818
2270
|
__name(this, "WorkflowTool");
|
|
1819
2271
|
}
|
|
1820
2272
|
validateToolParamValues(params) {
|
|
1821
|
-
|
|
1822
|
-
|
|
2273
|
+
const hasScript = typeof params.script === "string" && params.script.length > 0;
|
|
2274
|
+
const hasPath = typeof params.scriptPath === "string" && params.scriptPath.length > 0;
|
|
2275
|
+
if (!hasScript && !hasPath) {
|
|
2276
|
+
return "WorkflowTool: provide `script` (inline source) or `scriptPath` (a saved workflow file).";
|
|
2277
|
+
}
|
|
2278
|
+
if (hasScript && hasPath) {
|
|
2279
|
+
return "WorkflowTool: provide exactly one of `script` or `scriptPath`, not both.";
|
|
2280
|
+
}
|
|
2281
|
+
if (params.resumeFromRunId !== void 0 && !/^wf_[0-9a-f]+$/.test(params.resumeFromRunId)) {
|
|
2282
|
+
return "WorkflowTool: `resumeFromRunId` must match the generated id format `wf_<hex>`.";
|
|
1823
2283
|
}
|
|
1824
2284
|
return null;
|
|
1825
2285
|
}
|