minimal-agent 0.10.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (573) hide show
  1. package/README.md +11 -3
  2. package/package.json +52 -5
  3. package/plugins/computer_use/.claude-plugin/plugin.json +6 -0
  4. package/plugins/computer_use/README.md +94 -0
  5. package/plugins/computer_use/app/_template.md +142 -0
  6. package/plugins/computer_use/app/chrome.md +165 -0
  7. package/plugins/computer_use/app/finder.md +76 -0
  8. package/plugins/computer_use/app/macos-system-settings.md +81 -0
  9. package/plugins/computer_use/app/microsoft-excel.md +80 -0
  10. package/plugins/computer_use/app/microsoft-powerpoint.md +80 -0
  11. package/plugins/computer_use/app/microsoft-word.md +79 -0
  12. package/plugins/computer_use/app/wechat.md +413 -0
  13. package/plugins/computer_use/app/weread.md +319 -0
  14. package/plugins/computer_use/commands/computeruse.md +25 -0
  15. package/plugins/computer_use/commands/cu.md +9 -0
  16. package/plugins/computer_use/plugin.js +26 -0
  17. package/plugins/computer_use/plugin.ts +30 -0
  18. package/plugins/computer_use/src/capture.js +90 -0
  19. package/plugins/computer_use/src/capture.ts +104 -0
  20. package/plugins/computer_use/src/commands.js +91 -0
  21. package/plugins/computer_use/src/commands.ts +103 -0
  22. package/plugins/computer_use/src/daemon.js +134 -0
  23. package/plugins/computer_use/src/daemon.ts +161 -0
  24. package/plugins/computer_use/src/manuals.js +135 -0
  25. package/plugins/computer_use/src/manuals.ts +159 -0
  26. package/plugins/computer_use/src/verify.js +168 -0
  27. package/plugins/computer_use/src/verify.ts +219 -0
  28. package/plugins/computer_use/test/commands.test.ts +73 -0
  29. package/plugins/cron-runner/plugin.ts +38 -0
  30. package/plugins/cron-runner/src/commands.ts +373 -0
  31. package/plugins/cron-runner/src/cronTime.ts +155 -0
  32. package/plugins/cron-runner/src/lock.ts +79 -0
  33. package/plugins/cron-runner/src/runs.ts +99 -0
  34. package/plugins/cron-runner/src/scheduleEngine.ts +76 -0
  35. package/plugins/cron-runner/src/scheduler.ts +376 -0
  36. package/plugins/cron-runner/src/schema.ts +139 -0
  37. package/plugins/cron-runner/src/service.ts +193 -0
  38. package/plugins/cron-runner/src/store.ts +333 -0
  39. package/plugins/cron-runner/src/types.ts +141 -0
  40. package/plugins/cron-runner/test/cronTime.test.ts +41 -0
  41. package/plugins/cron-runner/test/plugin-integration.test.ts +47 -0
  42. package/plugins/cron-runner/test/scheduleEngine.test.ts +41 -0
  43. package/plugins/cron-runner/test/service.test.ts +76 -0
  44. package/plugins/cron-runner/test/store-and-scheduler.test.ts +501 -0
  45. package/plugins/workflow-runner/plugin.js +56 -2
  46. package/plugins/workflow-runner/plugin.ts +113 -0
  47. package/plugins/workflow-runner/src/agentCommon.js +43 -4
  48. package/plugins/workflow-runner/src/agentCommon.ts +435 -0
  49. package/plugins/workflow-runner/src/controlFlow/branch.js +40 -0
  50. package/plugins/workflow-runner/src/controlFlow/branch.ts +46 -0
  51. package/plugins/workflow-runner/src/controlFlow/loop.js +211 -0
  52. package/plugins/workflow-runner/src/controlFlow/loop.ts +248 -0
  53. package/plugins/workflow-runner/src/controlFlow/pause.js +129 -0
  54. package/plugins/workflow-runner/src/controlFlow/pause.ts +141 -0
  55. package/plugins/workflow-runner/src/controlFlow/signal.js +21 -0
  56. package/plugins/workflow-runner/src/controlFlow/signal.ts +29 -0
  57. package/plugins/workflow-runner/src/controlFlow/types.js +18 -0
  58. package/plugins/workflow-runner/src/controlFlow/types.ts +63 -0
  59. package/plugins/workflow-runner/src/dslManifest.ts +127 -0
  60. package/plugins/workflow-runner/src/expressions.ts +622 -0
  61. package/plugins/workflow-runner/src/index.js +13 -4
  62. package/plugins/workflow-runner/src/index.ts +338 -0
  63. package/plugins/workflow-runner/src/jsonPayload.ts +84 -0
  64. package/plugins/workflow-runner/src/loader.js +23 -0
  65. package/plugins/workflow-runner/src/loader.ts +721 -0
  66. package/plugins/workflow-runner/src/multimodal.js +2 -1
  67. package/plugins/workflow-runner/src/multimodal.ts +64 -0
  68. package/plugins/workflow-runner/src/recovery.ts +149 -0
  69. package/plugins/workflow-runner/src/runner.js +75 -659
  70. package/plugins/workflow-runner/src/runner.ts +604 -0
  71. package/plugins/workflow-runner/src/stepExecutors/agent.ts +234 -0
  72. package/plugins/workflow-runner/src/stepExecutors/assert.ts +50 -0
  73. package/plugins/workflow-runner/src/stepExecutors/echo.js +31 -0
  74. package/plugins/workflow-runner/src/stepExecutors/echo.ts +38 -0
  75. package/plugins/workflow-runner/src/stepExecutors/llm.ts +133 -0
  76. package/plugins/workflow-runner/src/stepExecutors/set.js +49 -0
  77. package/plugins/workflow-runner/src/stepExecutors/set.ts +56 -0
  78. package/plugins/workflow-runner/src/stepExecutors/skill.js +5 -6
  79. package/plugins/workflow-runner/src/stepExecutors/skill.ts +140 -0
  80. package/plugins/workflow-runner/src/stepExecutors/tool.js +80 -8
  81. package/plugins/workflow-runner/src/stepExecutors/tool.ts +256 -0
  82. package/plugins/workflow-runner/src/stepExecutors/verify.ts +68 -0
  83. package/plugins/workflow-runner/src/stepPipeline.js +277 -0
  84. package/plugins/workflow-runner/src/stepPipeline.ts +366 -0
  85. package/plugins/workflow-runner/src/taskIdentity.ts +405 -0
  86. package/plugins/workflow-runner/src/toolRuntime.js +48 -0
  87. package/plugins/workflow-runner/src/toolRuntime.ts +64 -0
  88. package/plugins/workflow-runner/src/types.js +37 -1
  89. package/plugins/workflow-runner/src/types.ts +602 -0
  90. package/plugins/workflow-runner/src/workflowState.ts +733 -0
  91. package/plugins/workflow-runner/test/agent.test.ts +587 -0
  92. package/plugins/workflow-runner/test/agentLlmError.test.ts +373 -0
  93. package/plugins/workflow-runner/test/bashBlacklist.sweep.test.ts +65 -0
  94. package/plugins/workflow-runner/test/captureMisbind.test.ts +99 -0
  95. package/plugins/workflow-runner/test/cli.e2e.test.ts +147 -0
  96. package/plugins/workflow-runner/test/context-files.test.ts +320 -0
  97. package/plugins/workflow-runner/test/e2e.test.ts +370 -0
  98. package/plugins/workflow-runner/test/engineRobustness.test.ts +226 -0
  99. package/plugins/workflow-runner/test/expressions.test.ts +397 -0
  100. package/plugins/workflow-runner/test/foundation.test.ts +126 -0
  101. package/plugins/workflow-runner/test/graceful.test.ts +139 -0
  102. package/plugins/workflow-runner/test/greedyInputs.load.test.ts +47 -0
  103. package/plugins/workflow-runner/test/hostCapability.test.ts +108 -0
  104. package/plugins/workflow-runner/test/illustrate.load.test.ts +183 -0
  105. package/plugins/workflow-runner/test/jsonPayload.test.ts +83 -0
  106. package/plugins/workflow-runner/test/loader.test.ts +617 -0
  107. package/plugins/workflow-runner/test/maxTurnsRetryDelay.test.ts +33 -0
  108. package/plugins/workflow-runner/test/multimodal.test.ts +342 -0
  109. package/plugins/workflow-runner/test/output-schema.test.ts +213 -0
  110. package/plugins/workflow-runner/test/parseWorkflowArgs.test.ts +87 -0
  111. package/plugins/workflow-runner/test/pluginRunner.isolation.test.ts +269 -0
  112. package/plugins/workflow-runner/test/ppt.load.test.ts +1220 -0
  113. package/plugins/workflow-runner/test/ralphLoop.e2e.test.ts +220 -0
  114. package/plugins/workflow-runner/test/recovery.test.ts +265 -0
  115. package/plugins/workflow-runner/test/runner.test.ts +911 -0
  116. package/plugins/workflow-runner/test/runnerPreflight.test.ts +379 -0
  117. package/plugins/workflow-runner/test/skillTurnDone.test.ts +71 -0
  118. package/plugins/workflow-runner/test/stateLifecycle.test.ts +150 -0
  119. package/plugins/workflow-runner/test/stepPipeline.test.ts +114 -0
  120. package/plugins/workflow-runner/test/taskArbitration.test.ts +338 -0
  121. package/plugins/workflow-runner/test/taskIdentity.test.ts +237 -0
  122. package/plugins/workflow-runner/test/taskLifecycle.test.ts +270 -0
  123. package/plugins/workflow-runner/test/toolArtifactOverwrite.test.ts +221 -0
  124. package/plugins/workflow-runner/test/toolCapabilityBoundary.test.ts +29 -0
  125. package/plugins/workflow-runner/test/toolRuntimeIntegration.test.ts +168 -0
  126. package/plugins/workflow-runner/test/webppt.load.test.ts +250 -0
  127. package/plugins/workflow-runner/test/word.load.test.ts +208 -0
  128. package/plugins/workflow-runner/test/workflows.smoke.test.ts +76 -0
  129. package/plugins/workflow-runner/test/yamlGuardConditions.test.ts +207 -0
  130. package/skills/browser-automation/SKILL.md +9 -19
  131. package/skills/web-crawler/SKILL.md +9 -11
  132. package/src/askBridge.ts +249 -0
  133. package/src/bootstrap/cwdArg.js +10 -3
  134. package/src/bootstrap/cwdArg.ts +31 -0
  135. package/src/bootstrap/workingDir.ts +48 -0
  136. package/src/cli/args.js +70 -7
  137. package/src/cli/args.ts +146 -0
  138. package/src/cli/computerUse.js +185 -0
  139. package/src/cli/computerUse.ts +221 -0
  140. package/src/cli/configMenu.js +274 -202
  141. package/src/cli/configMenu.tsx +521 -0
  142. package/src/cli/memoryAccess.js +45 -0
  143. package/src/cli/memoryAccess.ts +53 -0
  144. package/src/cli/print.js +119 -5
  145. package/src/cli/print.ts +597 -0
  146. package/src/cli/quickModelSetup.js +60 -0
  147. package/src/cli/quickModelSetup.tsx +96 -0
  148. package/src/cli/streamJson.js +80 -4
  149. package/src/cli/streamJson.ts +433 -0
  150. package/src/cli/wizards/advisorWizard.js +1 -0
  151. package/src/cli/wizards/advisorWizard.tsx +195 -0
  152. package/src/cli/wizards/agentRuntimeWizard.js +84 -0
  153. package/src/cli/wizards/agentRuntimeWizard.tsx +134 -0
  154. package/src/cli/wizards/browserWizard.js +55 -0
  155. package/src/cli/wizards/browserWizard.tsx +77 -0
  156. package/src/cli/wizards/contextAdvisorWizard.js +84 -0
  157. package/src/cli/wizards/contextAdvisorWizard.tsx +124 -0
  158. package/src/cli/wizards/fieldForm.js +7 -4
  159. package/src/cli/wizards/fieldForm.tsx +250 -0
  160. package/src/cli/wizards/imageWizard.js +4 -5
  161. package/src/cli/wizards/imageWizard.tsx +96 -0
  162. package/src/cli/wizards/openRouterWizard.tsx +48 -0
  163. package/src/cli/wizards/providerPresets.js +1 -8
  164. package/src/cli/wizards/providerPresets.ts +106 -0
  165. package/src/cli/wizards/providerWizard.js +152 -205
  166. package/src/cli/wizards/providerWizard.tsx +266 -0
  167. package/src/cli/wizards/searchWizard.tsx +47 -0
  168. package/src/cli/wizards/ttsWizard.js +4 -3
  169. package/src/cli/wizards/ttsWizard.tsx +61 -0
  170. package/src/config/configDefaults.js +25 -0
  171. package/src/config/configDefaults.ts +33 -0
  172. package/src/config/configDiagnostics.js +117 -0
  173. package/src/config/configDiagnostics.ts +166 -0
  174. package/src/config/configFile.js +52 -32
  175. package/src/config/configFile.ts +633 -0
  176. package/src/config/configManagement.js +126 -0
  177. package/src/config/configManagement.ts +159 -0
  178. package/src/config/configService.js +66 -11
  179. package/src/config/configService.ts +554 -0
  180. package/src/config/numericLimits.js +61 -0
  181. package/src/config/numericLimits.ts +80 -0
  182. package/src/config.ts +109 -0
  183. package/src/context/agentHome.ts +11 -0
  184. package/src/context/archive.ts +144 -0
  185. package/src/context/budgetPlan.js +54 -0
  186. package/src/context/budgetPlan.ts +88 -0
  187. package/src/context/compact.js +179 -106
  188. package/src/context/compact.ts +584 -0
  189. package/src/context/contextBundle.js +119 -0
  190. package/src/context/contextBundle.ts +176 -0
  191. package/src/context/contextLock.ts +84 -0
  192. package/src/context/microCompactLite.ts +218 -0
  193. package/src/context/persistContext.ts +177 -0
  194. package/src/context/reactiveCompact.js +19 -4
  195. package/src/context/reactiveCompact.ts +240 -0
  196. package/src/context/recentDirs.ts +42 -0
  197. package/src/context/sessionPath.ts +206 -0
  198. package/src/context/sessionRegistry.js +8 -2
  199. package/src/context/sessionRegistry.ts +414 -0
  200. package/src/context/snipCompact.ts +163 -0
  201. package/src/context/tokenCounter.ts +106 -0
  202. package/src/context/workspaceIndex.js +2 -2
  203. package/src/context/workspaceIndex.ts +751 -0
  204. package/src/entry.compiled.tsx +20 -0
  205. package/src/harness/claimValidation.js +9 -0
  206. package/src/harness/claimValidation.ts +22 -0
  207. package/src/harness/evidenceLedger.js +92 -0
  208. package/src/harness/evidenceLedger.ts +96 -0
  209. package/src/harness/stallGuard.js +60 -0
  210. package/src/harness/stallGuard.ts +81 -0
  211. package/src/humanIntervention.js +129 -0
  212. package/src/humanIntervention.ts +216 -0
  213. package/src/infra/verification.ts +295 -0
  214. package/src/irreversible/rules.js +216 -0
  215. package/src/irreversible/rules.ts +261 -0
  216. package/src/llm/client.js +40 -3
  217. package/src/llm/client.ts +621 -0
  218. package/src/llm/promptCache.js +27 -0
  219. package/src/llm/promptCache.ts +41 -0
  220. package/src/llm/providers/anthropicFormat.js +41 -5
  221. package/src/llm/providers/anthropicFormat.ts +290 -0
  222. package/src/llm/providers/openaiFormat.js +186 -8
  223. package/src/llm/providers/openaiFormat.ts +428 -0
  224. package/src/loop.js +614 -63
  225. package/src/loop.ts +1454 -0
  226. package/src/main.js +67 -10
  227. package/src/main.tsx +344 -0
  228. package/src/memory/codec.js +204 -0
  229. package/src/memory/codec.ts +249 -0
  230. package/src/memory/constants.js +34 -0
  231. package/src/memory/constants.ts +50 -0
  232. package/src/memory/episodicMemory.js +684 -0
  233. package/src/memory/episodicMemory.ts +815 -0
  234. package/src/memory/fileStore.js +148 -0
  235. package/src/memory/fileStore.ts +184 -0
  236. package/src/memory/memoryService.js +570 -0
  237. package/src/memory/memoryService.ts +859 -0
  238. package/src/memory/migration.js +128 -0
  239. package/src/memory/migration.ts +160 -0
  240. package/src/memory/repository.js +789 -0
  241. package/src/memory/repository.ts +893 -0
  242. package/src/memory/retrieval.js +108 -0
  243. package/src/memory/retrieval.ts +145 -0
  244. package/src/memory/searchIndex.js +107 -0
  245. package/src/memory/searchIndex.ts +153 -0
  246. package/src/memory/topicView.js +82 -0
  247. package/src/memory/topicView.ts +95 -0
  248. package/src/memory/turnJournal.js +95 -0
  249. package/src/memory/turnJournal.ts +120 -0
  250. package/src/memory/types.js +2 -0
  251. package/src/memory/types.ts +186 -0
  252. package/src/messageQueue.ts +123 -0
  253. package/src/multimodal.js +128 -46
  254. package/src/multimodal.ts +349 -0
  255. package/src/plugin-sdk.js +21 -1
  256. package/src/plugin-sdk.ts +134 -0
  257. package/src/plugins/builtinPluginIds.js +47 -0
  258. package/src/plugins/builtinPluginIds.ts +51 -0
  259. package/src/plugins/builtinRegistry.ts +43 -0
  260. package/src/plugins/commandRouter.js +40 -26
  261. package/src/plugins/commandRouter.ts +261 -0
  262. package/src/plugins/hookEngine.ts +341 -0
  263. package/src/plugins/pluginApi.ts +133 -0
  264. package/src/plugins/pluginLifecycle.ts +34 -0
  265. package/src/plugins/pluginLoader.ts +147 -0
  266. package/src/plugins/pluginManifest.js +127 -0
  267. package/src/plugins/pluginManifest.ts +152 -0
  268. package/src/plugins/pluginRunner.js +47 -2
  269. package/src/plugins/pluginRunner.ts +207 -0
  270. package/src/plugins/transcript.ts +208 -0
  271. package/src/prompts/lint.js +169 -0
  272. package/src/prompts/lint.ts +220 -0
  273. package/src/prompts/pluginList.js +32 -16
  274. package/src/prompts/pluginList.ts +86 -0
  275. package/src/prompts/policyRegistry.js +318 -0
  276. package/src/prompts/policyRegistry.ts +358 -0
  277. package/src/prompts/projectInstructions.js +24 -0
  278. package/src/prompts/projectInstructions.ts +81 -0
  279. package/src/prompts/promptAssembly.js +311 -202
  280. package/src/prompts/promptAssembly.ts +510 -0
  281. package/src/prompts/skillList.js +106 -45
  282. package/src/prompts/skillList.ts +198 -0
  283. package/src/prompts/system.js +31 -6
  284. package/src/prompts/system.ts +81 -0
  285. package/src/runtime/agentRuntimeContext.js +53 -0
  286. package/src/runtime/agentRuntimeContext.ts +112 -0
  287. package/src/session/runAgentTurn.js +71 -12
  288. package/src/session/runAgentTurn.ts +181 -0
  289. package/src/session/runTurn.js +29 -0
  290. package/src/session/runTurn.ts +160 -0
  291. package/src/session/runtimeStore.js +149 -0
  292. package/src/session/runtimeStore.ts +197 -0
  293. package/src/session/sessionState.js +79 -3
  294. package/src/session/sessionState.ts +134 -0
  295. package/src/toolGate.ts +50 -0
  296. package/src/tools/advisor/advisor.js +76 -15
  297. package/src/tools/advisor/advisor.ts +512 -0
  298. package/src/tools/agent/agent.js +245 -29
  299. package/src/tools/agent/agent.ts +837 -0
  300. package/src/tools/agent/agentTaskService.js +60 -0
  301. package/src/tools/agent/agentTaskService.ts +113 -0
  302. package/src/tools/agent/agentTypes.js +20 -8
  303. package/src/tools/agent/agentTypes.ts +94 -0
  304. package/src/tools/agent/coordinator.ts +111 -0
  305. package/src/tools/agent/worktree.ts +296 -0
  306. package/src/tools/ask/ask.js +17 -0
  307. package/src/tools/ask/ask.ts +122 -0
  308. package/src/tools/bash/attachImage.js +223 -0
  309. package/src/tools/bash/attachImage.ts +281 -0
  310. package/src/tools/bash/bash.js +132 -14
  311. package/src/tools/bash/bash.ts +642 -0
  312. package/src/tools/bash/semantics.ts +103 -0
  313. package/src/tools/bash/warnings.js +17 -11
  314. package/src/tools/bash/warnings.ts +117 -0
  315. package/src/tools/capabilities.js +42 -0
  316. package/src/tools/capabilities.ts +69 -0
  317. package/src/tools/computeruse/accessibilityPermission.js +261 -0
  318. package/src/tools/computeruse/accessibilityPermission.ts +294 -0
  319. package/src/tools/computeruse/axSearch.js +96 -0
  320. package/src/tools/computeruse/axSearch.ts +120 -0
  321. package/src/tools/computeruse/axSnap.js +272 -0
  322. package/src/tools/computeruse/axSnap.ts +349 -0
  323. package/src/tools/computeruse/capabilityLabels.js +95 -0
  324. package/src/tools/computeruse/capabilityLabels.ts +115 -0
  325. package/src/tools/computeruse/computerUseService.js +2235 -0
  326. package/src/tools/computeruse/computerUseService.ts +2686 -0
  327. package/src/tools/computeruse/computeruse.js +2742 -0
  328. package/src/tools/computeruse/computeruse.ts +3265 -0
  329. package/src/tools/computeruse/diagnosticTrace.js +154 -0
  330. package/src/tools/computeruse/diagnosticTrace.ts +195 -0
  331. package/src/tools/computeruse/diagnostics.js +369 -0
  332. package/src/tools/computeruse/diagnostics.ts +453 -0
  333. package/src/tools/computeruse/grants.js +53 -0
  334. package/src/tools/computeruse/grants.ts +70 -0
  335. package/src/tools/computeruse/humanBoundary.js +159 -0
  336. package/src/tools/computeruse/humanBoundary.ts +199 -0
  337. package/src/tools/computeruse/intervention.js +77 -0
  338. package/src/tools/computeruse/intervention.ts +110 -0
  339. package/src/tools/computeruse/manualSchema.js +709 -0
  340. package/src/tools/computeruse/manualSchema.ts +916 -0
  341. package/src/tools/computeruse/observationImages.js +705 -0
  342. package/src/tools/computeruse/observationImages.ts +889 -0
  343. package/src/tools/computeruse/protocol.js +60 -0
  344. package/src/tools/computeruse/protocol.ts +515 -0
  345. package/src/tools/computeruse/telemetryLog.js +57 -0
  346. package/src/tools/computeruse/telemetryLog.ts +67 -0
  347. package/src/tools/computeruse/vision/appGuide.js +325 -0
  348. package/src/tools/computeruse/vision/appGuide.ts +482 -0
  349. package/src/tools/computeruse/vision/focus.js +291 -0
  350. package/src/tools/computeruse/vision/focus.ts +382 -0
  351. package/src/tools/computeruse/vision/frames.js +248 -0
  352. package/src/tools/computeruse/vision/frames.ts +329 -0
  353. package/src/tools/computeruse/vision/geometry.js +131 -0
  354. package/src/tools/computeruse/vision/geometry.ts +163 -0
  355. package/src/tools/computeruse/vision/imaging.js +201 -0
  356. package/src/tools/computeruse/vision/imaging.ts +281 -0
  357. package/src/tools/computeruse/vision/png.js +274 -0
  358. package/src/tools/computeruse/vision/png.ts +317 -0
  359. package/src/tools/computeruse/vision/raster.js +320 -0
  360. package/src/tools/computeruse/vision/raster.ts +408 -0
  361. package/src/tools/computeruse/vision/settle.js +131 -0
  362. package/src/tools/computeruse/vision/settle.ts +220 -0
  363. package/src/tools/computeruse/vision/telemetry.js +196 -0
  364. package/src/tools/computeruse/vision/telemetry.ts +241 -0
  365. package/src/tools/computeruse/visionOcr.js +115 -0
  366. package/src/tools/computeruse/visionOcr.ts +128 -0
  367. package/src/tools/computeruse/waitFor.js +237 -0
  368. package/src/tools/computeruse/waitFor.ts +291 -0
  369. package/src/tools/download/download.js +10 -6
  370. package/src/tools/download/download.ts +187 -0
  371. package/src/tools/edit/edit.js +30 -18
  372. package/src/tools/edit/edit.ts +349 -0
  373. package/src/tools/edit/multi-edit.js +25 -14
  374. package/src/tools/edit/multi-edit.ts +223 -0
  375. package/src/tools/effectiveToolSet.js +73 -0
  376. package/src/tools/effectiveToolSet.ts +91 -0
  377. package/src/tools/genimage/genimage.ts +257 -0
  378. package/src/tools/genspeech/genspeech.ts +83 -0
  379. package/src/tools/glob/glob.js +176 -29
  380. package/src/tools/glob/glob.ts +283 -0
  381. package/src/tools/grep/grep.js +61 -19
  382. package/src/tools/grep/grep.ts +239 -0
  383. package/src/tools/grep/rgPath.ts +206 -0
  384. package/src/tools/index.js +99 -5
  385. package/src/tools/index.ts +293 -0
  386. package/src/tools/lsp/config.js +113 -0
  387. package/src/tools/lsp/config.ts +113 -0
  388. package/src/tools/lsp/lsp.js +256 -0
  389. package/src/tools/lsp/lsp.ts +274 -0
  390. package/src/tools/lsp/service.js +303 -0
  391. package/src/tools/lsp/service.ts +296 -0
  392. package/src/tools/memory/memory.js +520 -0
  393. package/src/tools/memory/memory.ts +625 -0
  394. package/src/tools/memory/policy.js +53 -0
  395. package/src/tools/memory/policy.ts +72 -0
  396. package/src/tools/notebook/notebookEdit.js +114 -0
  397. package/src/tools/notebook/notebookEdit.ts +126 -0
  398. package/src/tools/powershell/powershell.js +210 -0
  399. package/src/tools/powershell/powershell.ts +239 -0
  400. package/src/tools/presentresult/presentresult.js +145 -0
  401. package/src/tools/presentresult/presentresult.ts +156 -0
  402. package/src/tools/read/read.js +371 -163
  403. package/src/tools/read/read.ts +558 -0
  404. package/src/tools/shared/diffSummary.js +44 -0
  405. package/src/tools/shared/diffSummary.ts +63 -0
  406. package/src/tools/shared/fileActivity.js +51 -0
  407. package/src/tools/shared/fileActivity.ts +66 -0
  408. package/src/tools/shared/fileMutationBus.js +13 -0
  409. package/src/tools/shared/fileMutationBus.ts +14 -0
  410. package/src/tools/shared/fileState.js +73 -65
  411. package/src/tools/shared/fileState.ts +145 -0
  412. package/src/tools/shared/fileUtils.js +81 -4
  413. package/src/tools/shared/fileUtils.ts +504 -0
  414. package/src/tools/shared/killTree.ts +50 -0
  415. package/src/tools/shared/permanentDeleteGuard.js +26 -0
  416. package/src/tools/shared/permanentDeleteGuard.ts +34 -0
  417. package/src/tools/shared/schemas.ts +20 -0
  418. package/src/tools/shared/toolOutputStore.js +97 -0
  419. package/src/tools/shared/toolOutputStore.ts +110 -0
  420. package/src/tools/skill/skill.js +86 -0
  421. package/src/tools/skill/skill.ts +94 -0
  422. package/src/tools/snip/snip.js +67 -0
  423. package/src/tools/snip/snip.ts +80 -0
  424. package/src/tools/tasks/backgroundTaskService.js +275 -0
  425. package/src/tools/tasks/backgroundTaskService.ts +369 -0
  426. package/src/tools/tasks/processEvidence.js +24 -0
  427. package/src/tools/tasks/processEvidence.ts +34 -0
  428. package/src/tools/tasks/taskManagement.js +163 -0
  429. package/src/tools/tasks/taskManagement.ts +180 -0
  430. package/src/tools/tasks/taskOutput.js +113 -0
  431. package/src/tools/tasks/taskOutput.ts +145 -0
  432. package/src/tools/tasks/taskStop.js +74 -0
  433. package/src/tools/tasks/taskStop.ts +99 -0
  434. package/src/tools/tasks/taskStore.js +46 -0
  435. package/src/tools/tasks/taskStore.ts +77 -0
  436. package/src/tools/terminal/terminalCapture.js +167 -0
  437. package/src/tools/terminal/terminalCapture.ts +179 -0
  438. package/src/tools/trash/trash.js +233 -0
  439. package/src/tools/trash/trash.ts +283 -0
  440. package/src/tools/types.js +1 -1
  441. package/src/tools/types.ts +24 -0
  442. package/src/tools/webbrowser/agentBrowserPath.ts +286 -0
  443. package/src/tools/webbrowser/browser.js +214 -11
  444. package/src/tools/webbrowser/browser.ts +293 -0
  445. package/src/tools/webbrowser/browserControl.js +153 -48
  446. package/src/tools/webbrowser/browserControl.ts +262 -0
  447. package/src/tools/webbrowser/browserDaemon.js +147 -39
  448. package/src/tools/webbrowser/browserDaemon.ts +270 -0
  449. package/src/tools/webbrowser/browserOutcome.js +273 -0
  450. package/src/tools/webbrowser/browserOutcome.ts +306 -0
  451. package/src/tools/webbrowser/browserRunRegistry.js +150 -0
  452. package/src/tools/webbrowser/browserRunRegistry.ts +179 -0
  453. package/src/tools/webbrowser/browserService.js +20 -6
  454. package/src/tools/webbrowser/browserService.ts +56 -0
  455. package/src/tools/webbrowser/browserStream.js +30 -1
  456. package/src/tools/webbrowser/browserStream.ts +216 -0
  457. package/src/tools/webbrowser/browserTabs.js +143 -0
  458. package/src/tools/webbrowser/browserTabs.ts +210 -0
  459. package/src/tools/webbrowser/webbrowser.js +831 -150
  460. package/src/tools/webbrowser/webbrowser.ts +1537 -0
  461. package/src/tools/webfetch/preapproved.ts +274 -0
  462. package/src/tools/webfetch/webfetch.js +24 -23
  463. package/src/tools/webfetch/webfetch.ts +383 -0
  464. package/src/tools/websearch/websearch.js +12 -11
  465. package/src/tools/websearch/websearch.ts +292 -0
  466. package/src/tools/worktree/sessionWorktree.js +128 -0
  467. package/src/tools/worktree/sessionWorktree.ts +158 -0
  468. package/src/tools/write/write.js +27 -44
  469. package/src/tools/write/write.ts +136 -0
  470. package/src/types.ts +960 -0
  471. package/src/ui/App.js +216 -12
  472. package/src/ui/App.tsx +879 -0
  473. package/src/ui/AskQuestion.tsx +300 -0
  474. package/src/ui/InputBox.js +77 -1
  475. package/src/ui/InputBox.tsx +567 -0
  476. package/src/ui/LiveArea.tsx +344 -0
  477. package/src/ui/MessageList.js +27 -6
  478. package/src/ui/MessageList.tsx +559 -0
  479. package/src/ui/ModelPicker.tsx +107 -0
  480. package/src/ui/QueuedMessagesBanner.tsx +51 -0
  481. package/src/ui/Root.js +6 -8
  482. package/src/ui/Root.tsx +100 -0
  483. package/src/ui/SessionPicker.tsx +169 -0
  484. package/src/ui/StatusLine.js +22 -1
  485. package/src/ui/StatusLine.tsx +145 -0
  486. package/src/ui/WorkspacePicker.tsx +84 -0
  487. package/src/ui/advisorCommand.js +54 -0
  488. package/src/ui/advisorCommand.ts +63 -0
  489. package/src/ui/computerCommand.js +19 -0
  490. package/src/ui/computerCommand.ts +35 -0
  491. package/src/ui/figures.ts +45 -0
  492. package/src/ui/hooks/askSlot.ts +112 -0
  493. package/src/ui/hooks/useChat.js +271 -7
  494. package/src/ui/hooks/useChat.ts +1578 -0
  495. package/src/ui/hooks/useInputHistory.ts +235 -0
  496. package/src/ui/hooks/usePasteHandler.ts +220 -0
  497. package/src/ui/hooks/useTerminalSize.ts +41 -0
  498. package/src/ui/hooks/useTextBuffer.ts +108 -0
  499. package/src/ui/hooks/useTokenUsage.ts +44 -0
  500. package/src/ui/liveViewport.ts +189 -0
  501. package/src/ui/markdown.ts +230 -0
  502. package/src/ui/textBuffer.ts +239 -0
  503. package/src/ui/theme.ts +35 -0
  504. package/src/utils/clipboardImage.js +358 -0
  505. package/src/utils/clipboardImage.ts +420 -0
  506. package/src/utils/debugLog.ts +50 -0
  507. package/src/utils/greenRoot.ts +35 -0
  508. package/src/utils/packageRoot.ts +40 -0
  509. package/src/utils/pathContains.js +28 -0
  510. package/src/utils/pathContains.ts +31 -0
  511. package/src/utils/resourcePaths.ts +71 -0
  512. package/src/utils/stripThink.ts +49 -0
  513. package/src/utils/zodToJson.ts +73 -0
  514. package/src/web/browserBridge.js +365 -66
  515. package/src/web/browserBridge.ts +672 -0
  516. package/src/web/protocol.ts +1804 -0
  517. package/vendor/computer-use/arm64-darwin/cu-helperd +0 -0
  518. package/workflows/ppt.yaml +13 -2
  519. package/workflows/wechat-reading-shots.yaml +315 -0
  520. package/workflows/word.yaml +11 -1
  521. package/skills/docx/scripts/office/helpers/__pycache__/__init__.cpython-314.pyc +0 -0
  522. package/skills/docx/scripts/office/helpers/__pycache__/merge_runs.cpython-314.pyc +0 -0
  523. package/skills/docx/scripts/office/helpers/__pycache__/simplify_redlines.cpython-314.pyc +0 -0
  524. package/skills/docx/scripts/office/validators/__pycache__/__init__.cpython-314.pyc +0 -0
  525. package/skills/docx/scripts/office/validators/__pycache__/base.cpython-314.pyc +0 -0
  526. package/skills/docx/scripts/office/validators/__pycache__/docx.cpython-314.pyc +0 -0
  527. package/skills/docx/scripts/office/validators/__pycache__/pptx.cpython-314.pyc +0 -0
  528. package/skills/docx/scripts/office/validators/__pycache__/redlining.cpython-314.pyc +0 -0
  529. package/skills/image-stats/scripts/__pycache__/image_stats.cpython-314.pyc +0 -0
  530. package/skills/image-stats/scripts/__pycache__/image_stats_test.cpython-314.pyc +0 -0
  531. package/skills/ui-design/scripts/__pycache__/assemble_material.cpython-314.pyc +0 -0
  532. package/skills/ui-design/scripts/__pycache__/assemble_material_test.cpython-314.pyc +0 -0
  533. package/skills/ui-design/scripts/__pycache__/chart_sanity_check.cpython-314.pyc +0 -0
  534. package/skills/ui-design/scripts/__pycache__/check_language_policy.cpython-314.pyc +0 -0
  535. package/skills/ui-design/scripts/__pycache__/check_ui_artifact.cpython-314.pyc +0 -0
  536. package/skills/ui-design/scripts/__pycache__/check_ui_artifact_pptx_test.cpython-314.pyc +0 -0
  537. package/skills/ui-design/scripts/__pycache__/deck_pages_check.cpython-314.pyc +0 -0
  538. package/skills/ui-design/scripts/__pycache__/deck_pages_check_test.cpython-314.pyc +0 -0
  539. package/skills/ui-design/scripts/__pycache__/deck_visual_style_check.cpython-314.pyc +0 -0
  540. package/skills/ui-design/scripts/__pycache__/deck_visual_style_check_test.cpython-314.pyc +0 -0
  541. package/skills/ui-design/scripts/__pycache__/design_budget_check.cpython-314.pyc +0 -0
  542. package/skills/ui-design/scripts/__pycache__/design_budget_check_test.cpython-314.pyc +0 -0
  543. package/skills/ui-design/scripts/__pycache__/design_repair_hints.cpython-314.pyc +0 -0
  544. package/skills/ui-design/scripts/__pycache__/design_repair_hints_test.cpython-314.pyc +0 -0
  545. package/skills/ui-design/scripts/__pycache__/design_style_check.cpython-314.pyc +0 -0
  546. package/skills/ui-design/scripts/__pycache__/design_style_check_test.cpython-314.pyc +0 -0
  547. package/skills/ui-design/scripts/__pycache__/draft_coverage_check.cpython-314.pyc +0 -0
  548. package/skills/ui-design/scripts/__pycache__/extract_source_assets.cpython-314.pyc +0 -0
  549. package/skills/ui-design/scripts/__pycache__/extract_source_assets_test.cpython-314.pyc +0 -0
  550. package/skills/ui-design/scripts/__pycache__/generated_image_review_collect.cpython-314.pyc +0 -0
  551. package/skills/ui-design/scripts/__pycache__/generated_image_review_collect_test.cpython-314.pyc +0 -0
  552. package/skills/ui-design/scripts/__pycache__/image_plan_lint.cpython-314.pyc +0 -0
  553. package/skills/ui-design/scripts/__pycache__/image_plan_lint_test.cpython-314.pyc +0 -0
  554. package/skills/ui-design/scripts/__pycache__/image_prompt_rewrite.cpython-314.pyc +0 -0
  555. package/skills/ui-design/scripts/__pycache__/image_prompt_rewrite_test.cpython-314.pyc +0 -0
  556. package/skills/ui-design/scripts/__pycache__/layout_balance.cpython-314.pyc +0 -0
  557. package/skills/ui-design/scripts/__pycache__/layout_balance_test.cpython-314.pyc +0 -0
  558. package/skills/ui-design/scripts/__pycache__/normalize_design_json.cpython-314.pyc +0 -0
  559. package/skills/ui-design/scripts/__pycache__/normalize_design_json_test.cpython-314.pyc +0 -0
  560. package/skills/ui-design/scripts/__pycache__/plan_source_layout.cpython-314.pyc +0 -0
  561. package/skills/ui-design/scripts/__pycache__/plan_source_layout_test.cpython-314.pyc +0 -0
  562. package/skills/ui-design/scripts/__pycache__/resolve_source_hint.cpython-314.pyc +0 -0
  563. package/skills/ui-design/scripts/__pycache__/resolve_source_hint_test.cpython-314.pyc +0 -0
  564. package/skills/ui-design/scripts/__pycache__/resolve_source_input.cpython-314.pyc +0 -0
  565. package/skills/ui-design/scripts/__pycache__/resolve_source_input_test.cpython-314.pyc +0 -0
  566. package/skills/ui-design/scripts/__pycache__/scaffold_ui_artifact.cpython-314.pyc +0 -0
  567. package/skills/ui-design/scripts/__pycache__/source_usage_check.cpython-314.pyc +0 -0
  568. package/skills/ui-design/scripts/__pycache__/source_usage_check_test.cpython-314.pyc +0 -0
  569. package/skills/ui-design/scripts/__pycache__/text_readability_pixel.cpython-314.pyc +0 -0
  570. package/skills/ui-design/scripts/__pycache__/visual_quality_gate.cpython-314.pyc +0 -0
  571. package/skills/ui-design/scripts/__pycache__/visual_quality_gate_test.cpython-314.pyc +0 -0
  572. /package/skills/ai-image/scripts/{generate_test.mjs → generate.selftest.mjs} +0 -0
  573. /package/skills/ai-image/scripts/{generate_from_plan_test.mjs → generate_from_plan.selftest.mjs} +0 -0
@@ -0,0 +1,113 @@
1
+ /**
2
+ * ============================================================
3
+ * plugins/workflow-runner/plugin.ts
4
+ * ------------------------------------------------------------
5
+ * workflow-runner 插件入口。接管 /workflow 与 /workflows 两个命令的执行:
6
+ * 不走声明式 markdown→LLM 通道,而是直接调插件内置的 YAML DAG 执行器。
7
+ *
8
+ * 执行器与全部依赖都住在本插件目录 ./src/,外部 src/ 一行不改。
9
+ * 插件只通过 src/plugin-sdk.ts 取框架运行时(runQuery / chat / executeTool 等)。
10
+ *
11
+ * 契约:default export 一个 PluginApi 对象。框架 pluginLoader 会按 pluginRoot
12
+ * 缓存这次 import,所以 cold start 后 dynamic import 只跑一次。
13
+ * ============================================================
14
+ */
15
+
16
+ import type { PluginApi } from '../../src/plugin-sdk.js';
17
+ import {
18
+ ALL_TOOLS,
19
+ buildTransientPromptBundle,
20
+ createAgentRuntimeContext,
21
+ derivePromptCacheContext,
22
+ filterToolsForRuntime,
23
+ getWorkingDir,
24
+ } from '../../src/plugin-sdk.js';
25
+ import { runWorkflowFromCommand, runWorkflowsList } from './src/index.js';
26
+
27
+ const api: PluginApi = {
28
+ async *runCommand(commandName, args, ctx) {
29
+ if (commandName === 'workflows') {
30
+ yield* runWorkflowsList();
31
+ return;
32
+ }
33
+
34
+ if (commandName === 'workflow') {
35
+ const cwd = getWorkingDir();
36
+ const workflowRuntime = createAgentRuntimeContext({
37
+ ...(ctx.runtimeContext ?? {
38
+ profile: 'main' as const,
39
+ interactiveAsk: false,
40
+ }),
41
+ // The command runs inside the workflow's async-scoped workspace. A
42
+ // parent Desktop/CLI runtime may have been created before that scope.
43
+ cwd,
44
+ surface: 'workflow',
45
+ owner: ctx.runtimeContext?.owner ?? 'untrusted',
46
+ memoryAccess:
47
+ ctx.runtimeContext?.memoryAccess === 'denied'
48
+ ? 'denied'
49
+ : 'read-only',
50
+ });
51
+ const hostToolNames = ctx.allowedTools
52
+ ? new Set(ctx.allowedTools)
53
+ : undefined;
54
+ const hostTools = hostToolNames
55
+ ? ALL_TOOLS.filter((tool) => hostToolNames.has(tool.name))
56
+ : ALL_TOOLS;
57
+ const workflowTools = filterToolsForRuntime(hostTools, workflowRuntime);
58
+ const transientBundle =
59
+ ctx.transientBundle ??
60
+ (await buildTransientPromptBundle({
61
+ cwd,
62
+ tools: workflowTools,
63
+ profile: 'main',
64
+ includeProjectInstructions: true,
65
+ includePlugins: true,
66
+ runtime: {
67
+ surface: 'workflow',
68
+ cwd,
69
+ workspaceId: workflowRuntime.workspaceId,
70
+ interactiveAsk: workflowRuntime.interactiveAsk,
71
+ memoryAccess: workflowRuntime.memoryAccess,
72
+ currentUserInput: args,
73
+ },
74
+ }).catch(() => undefined));
75
+ yield* runWorkflowFromCommand(args, {
76
+ provider: ctx.provider,
77
+ history: ctx.history,
78
+ signal: ctx.signal,
79
+ sessionState: ctx.sessionState,
80
+ cwd,
81
+ tools: workflowTools,
82
+ runtimeContext: workflowRuntime,
83
+ executeTool: ctx.executeTool,
84
+ toolContext: {
85
+ history: ctx.history,
86
+ sessionState: ctx.sessionState,
87
+ provider: ctx.provider,
88
+ toolGate: ctx.host?.toolGate,
89
+ promptCache: ctx.promptCache,
90
+ workspaceId: workflowRuntime.workspaceId,
91
+ sessionId: workflowRuntime.sessionId,
92
+ memoryAccess: workflowRuntime.memoryAccess,
93
+ },
94
+ // 宿主授权上下文原样带上;引擎按各步 `uses:` 切片后才转给工具,不整份下发。
95
+ host: ctx.host,
96
+ transientContext: ctx.transientContext,
97
+ transientBundle,
98
+ promptCache: derivePromptCacheContext(
99
+ ctx.promptCache,
100
+ `workflow:${args.trim() || 'interactive'}`,
101
+ ),
102
+ });
103
+ return;
104
+ }
105
+
106
+ yield {
107
+ type: 'error',
108
+ error: `workflow-runner: 未知命令 /${commandName}`,
109
+ };
110
+ },
111
+ };
112
+
113
+ export default api;
@@ -19,7 +19,8 @@
19
19
  * ③ 检测逻辑增加内容长度启发式(reason > 80 字符视为误报)
20
20
  * ============================================================
21
21
  */
22
- import { runQuery, stripThinkBlocks, } from '../../../src/plugin-sdk.js';
22
+ import { createAgentRuntimeContext, runQuery, stripThinkBlocks, } from '../../../src/plugin-sdk.js';
23
+ import { effectiveWorkflowCwd } from './toolRuntime.js';
23
24
  import { normalizeCapture, } from './types.js';
24
25
  /**
25
26
  * agent 显式放弃的唯一标记;recover 与 agent 节点共用。
@@ -59,7 +60,9 @@ export function effectiveGoalAnchor(ctx) {
59
60
  if (supps.length === 0)
60
61
  return base;
61
62
  const lines = supps.map((s) => `> 📌 用户补充要求:${s}`).join('\n');
62
- return base ? `${base}\n${lines}` : `${lines}\n> ⚠️ 以上补充要求与原始目标同等约束所有操作。`;
63
+ return base
64
+ ? `${base}\n${lines}`
65
+ : `${lines}\n> ⚠️ 以上补充要求与原始目标同等约束所有操作。`;
63
66
  }
64
67
  /** 把 llm_error 细节拼进可重试失败的抛错文案(无细节时退化为原样文案)。 */
65
68
  export function describeLlmFailure(stepId, detail) {
@@ -95,8 +98,23 @@ function createStepHistory(step, ctx) {
95
98
  */
96
99
  export async function* runStepQuery(prompt, step, ctx, opts) {
97
100
  const activeHistory = createStepHistory(step, ctx);
101
+ const availableTools = ctx.tools ?? [];
102
+ const hostToolNames = new Set(availableTools.map((tool) => tool.name));
103
+ const effectiveStepTools = step.allowed_tools === undefined
104
+ ? [...hostToolNames]
105
+ : step.allowed_tools.filter((name) => hostToolNames.has(name));
98
106
  // 记录 runQuery 开始前的 history 长度,用于之后提取本步的 assistant 输出
99
107
  const historyLenBefore = activeHistory.length;
108
+ const runtimeContext = createAgentRuntimeContext({
109
+ ...(ctx.runtimeContext ?? {
110
+ surface: 'workflow',
111
+ profile: 'main',
112
+ interactiveAsk: false,
113
+ }),
114
+ cwd: effectiveWorkflowCwd(ctx),
115
+ owner: ctx.runtimeContext?.owner ?? 'untrusted',
116
+ memoryAccess: ctx.runtimeContext?.memoryAccess ?? 'denied',
117
+ });
100
118
  let aborted = false;
101
119
  let sawLlmError = false;
102
120
  let sawMaxTurns = false;
@@ -107,10 +125,12 @@ export async function* runStepQuery(prompt, step, ctx, opts) {
107
125
  const toolNames = [];
108
126
  for await (const ev of runQuery(prompt, {
109
127
  provider: ctx.provider,
128
+ runtimeContext,
110
129
  history: activeHistory,
111
130
  signal: ctx.signal,
112
131
  maxTurns: opts.maxTurns,
113
- allowedTools: step.allowed_tools,
132
+ allowedTools: effectiveStepTools,
133
+ requiredTools: step.allowed_tools === undefined ? undefined : effectiveStepTools,
114
134
  chat: ctx.chat,
115
135
  executeTool: ctx.executeTool,
116
136
  sessionState: ctx.sessionState,
@@ -118,6 +138,23 @@ export async function* runStepQuery(prompt, step, ctx, opts) {
118
138
  parseInlineImages: opts.parseInlineImages,
119
139
  imageDetail: opts.imageDetail,
120
140
  imageMaxLongSidePixel: opts.imageMaxLongSidePixel,
141
+ transientContext: ctx.transientContext,
142
+ transientBundle: ctx.transientBundle,
143
+ promptCache: ctx.promptCache,
144
+ // ⚠️ 宿主授权上下文必须跟着走 —— 这是与 `stepExecutors/tool.ts` 同一处遗漏的
145
+ // 另一半:tool 步补上了、agent/llm/skill 步没补的话,「让 agent 随机应变操作
146
+ // 电脑」这类步骤照样恒失败,而且症状与 tool 步完全一样、更难定位。
147
+ //
148
+ // 这里**整份下发**而不是像 tool 步那样按 `uses:` 切片,是有意的:agent 步本就是
149
+ // 「把判断权交给模型」的节点,它要用哪个工具由模型临场决定,事先切片等于让
150
+ // yaml 作者预测模型的选择。约束改由 `allowed_tools`(上面那行)承担 —— 那是
151
+ // agent 步既有的、更贴合其语义的收敛手段。
152
+ ...(ctx.host?.computerRun ? { computerRun: ctx.host.computerRun } : {}),
153
+ ...(ctx.host?.computerIntervention
154
+ ? { computerIntervention: ctx.host.computerIntervention }
155
+ : {}),
156
+ ...(ctx.host?.browserRun ? { browserRun: ctx.host.browserRun } : {}),
157
+ ...(ctx.host?.toolGate ? { toolGate: ctx.host.toolGate } : {}),
121
158
  })) {
122
159
  if (ev.type === 'error') {
123
160
  if (ev.code === 'aborted') {
@@ -245,7 +282,9 @@ function isLikelyFalsePositive(reason) {
245
282
  if (reason.length > 80)
246
283
  return true;
247
284
  // 如果 reason 看起来像 markdown 正文(标题/章节),也是误报
248
- if (/^#{1,6}\s/m.test(reason) || /^[-*+]\s/m.test(reason) || /^\d+\.\s/m.test(reason)) {
285
+ if (/^#{1,6}\s/m.test(reason) ||
286
+ /^[-*+]\s/m.test(reason) ||
287
+ /^\d+\.\s/m.test(reason)) {
249
288
  return true;
250
289
  }
251
290
  return false;
@@ -0,0 +1,435 @@
1
+ /**
2
+ * ============================================================
3
+ * plugins/workflow-runner/src/agentCommon.ts —— workflow 内「有界 agent」的共享工具
4
+ * ------------------------------------------------------------
5
+ * 工作流里有两处会临时起一个 agent(runQuery 执行后的验证闸门):
6
+ * - onError:'recover'(recovery.ts)—— 节点失败后救火
7
+ * - agent: 节点(stepExecutors/agent.ts)—— 作者显式声明的开放任务
8
+ * 二者本质同构:受工作流目标/上下文指导、用工具随机应变、产出经验证后回灌 capture。
9
+ * 为避免「同一个脑子写两份提示词、行为漂移」,这里收敛它们的**共享件**:
10
+ * 1. 统一验证闸门(interpretMiniReActResult)—— runQuery 执行完后,判定「真交付」还是
11
+ * 「放弃/不可信」,**永不把没验证过的产出当成功**。这是 Phase 2 验证闸门的提取。
12
+ *
13
+ * ⚠️ GIVEUP 标记设计原则(v0.9.3 修复 LLM 误触发问题):
14
+ * 旧标记 __AGENT_GIVEUP__ 使用 __XXX__ 格式,MiniMax/GPT 等模型容易在输出中
15
+ * 幻觉出类似标记(如 "__AGENT_GIVEUP__: since I did the work..."),导致已完成的工作
16
+ * 被误判为"放弃"而 halt。新标记采用三重防误触发设计:
17
+ * ① 非标准格式(非 __XXX__,LLM 训练数据中几乎不存在)
18
+ * ② 含明确的 "DO-NOT-GENERATE" 警告文本
19
+ * ③ 检测逻辑增加内容长度启发式(reason > 80 字符视为误报)
20
+ * ============================================================
21
+ */
22
+
23
+ import {
24
+ type ImageDetail,
25
+ type ImageInputSpec,
26
+ type LoopEvent,
27
+ type Message,
28
+ createAgentRuntimeContext,
29
+ runQuery,
30
+ stripThinkBlocks,
31
+ } from '../../../src/plugin-sdk.js';
32
+ import { effectiveWorkflowCwd } from './toolRuntime.js';
33
+ import {
34
+ type RunContext,
35
+ type StepDef,
36
+ type StepResult,
37
+ normalizeCapture,
38
+ } from './types.js';
39
+
40
+ /**
41
+ * agent 显式放弃的唯一标记;recover 与 agent 节点共用。
42
+ *
43
+ * 设计约束(纯 ASCII,避免 Unicode 编码匹配问题):
44
+ * - 不使用 __XXX__ 格式(LLM 容易幻觉模仿)
45
+ * - 含 "wf-internal" 前缀 + "do-not-generate" 明确警告
46
+ * - 使用 [bracket] 格式而非 ⟨angle⟩(避免 Unicode 字符在 Bun indexOf 中行为不一致)
47
+ */
48
+ export const GIVEUP_MARKER = '[wf-internal-abort-do-not-generate]';
49
+
50
+ /** 有界 agent 的判定结果:真交付带 value、放弃/不可信带 reason(调用方据此继续或 honest halt)。 */
51
+ export type AgentOutcome =
52
+ | { ok: true; value: StepResult }
53
+ | { ok: false; reason: string };
54
+
55
+ /** 把 step.capture 翻成「下游会把你的结果存成哪些变量」,让 agent 产出对得上形状。
56
+ * 经 normalizeCapture:裸字符串 capture(capture: design_doc)不再被拆成单字符
57
+ * 【d、e、s…】,而是正确显示为【design_doc】。 */
58
+ export function describeCaptureContract(step: StepDef): string {
59
+ const names = Object.values(normalizeCapture(step.capture));
60
+ if (names.length === 0) return '';
61
+ return `\n\n下游契约:工作流会把你的结果保存为变量【${names.join('、')}】供后续步骤引用,请确保你的产出能填好这些变量。`;
62
+ }
63
+
64
+ export function truncate(s: string, n: number): string {
65
+ return s.length > n ? `${s.slice(0, n)}…` : s;
66
+ }
67
+
68
+ // stripThinkBlocks 已上移内核 src/utils/stripThink.ts(Agent 子任务工具同样需要,
69
+ // 内核不能 import 插件)——顶部 import 供本模块使用,此处 re-export 保持插件内
70
+ // 既有 import 路径不变。
71
+ export { stripThinkBlocks };
72
+
73
+ /**
74
+ * 组合「原始目标锚 + 累积的用户补充要求」为本步实际注入的锚定文本。
75
+ * agent / llm / skill / recovery 四个执行器统一经此取锚——补充要求
76
+ * (pause 审批反馈 / goal_supplement 步产出 / 仲裁延续的新指令)与原始目标
77
+ * 同等贯穿每一步,不再只活在被修订的文件或某个变量里。
78
+ * 返回空串 = 无锚(执行器跳过注入,行为同旧 ctx.goalAnchor 为空)。
79
+ */
80
+ export function effectiveGoalAnchor(ctx: RunContext): string {
81
+ const base = ctx.goalAnchor ?? '';
82
+ const supps = (ctx.goalSupplements ?? []).filter((s) => s.trim());
83
+ if (supps.length === 0) return base;
84
+ const lines = supps.map((s) => `> 📌 用户补充要求:${s}`).join('\n');
85
+ return base
86
+ ? `${base}\n${lines}`
87
+ : `${lines}\n> ⚠️ 以上补充要求与原始目标同等约束所有操作。`;
88
+ }
89
+
90
+ /** runStepQuery 的归纳结果:本步产出文本 + 终结性错误旗标(语义判断留给各执行器)。 */
91
+ export interface StepQueryOutcome {
92
+ /** history 反查到的本步最后一条非空 assistant 文本(无则空串) */
93
+ rawText: string;
94
+ /** 本轮 runQuery 是否实际调用过工具。用于区分"空答"和"搜/读了但没落盘"。 */
95
+ sawToolCall: boolean;
96
+ /** 本轮实际调用过的工具名(按首次出现顺序去重)。 */
97
+ toolNames: string[];
98
+ /** 工具成功次数。 */
99
+ toolOkCount: number;
100
+ /** 工具失败次数。 */
101
+ toolFailCount: number;
102
+ /** 用户中断(code:'aborted')—— 不可重试,执行器应按现状返回不抛错 */
103
+ aborted: boolean;
104
+ /** 终结性 LLM 失败(code:'llm_error')—— 可重试,空产出时执行器应抛错触发 in-run retry */
105
+ sawLlmError: boolean;
106
+ /**
107
+ * 撞 maxTurns 被截断(code:'max_turns')—— 模型还在干活时轮数预算耗尽。
108
+ * 截断时刻的产出是半截工作叙述而非可信交付,执行器应抛错触发 in-run retry——
109
+ * 重试在共享 history 上重跑 = 模型看到自己之前的进度**接着干**(续作语义),
110
+ * 每次重试等于再给一份轮数预算。曾被静默当成功:半成品 PPTX 被链路当真交付。
111
+ */
112
+ sawMaxTurns: boolean;
113
+ /**
114
+ * 最后一次 llm_error 事件的具体错误文案(provider 真实报错:超时/限流/5xx…)。
115
+ * 执行器抛错时务必附带——它会经 runner 落进 progress.md(↻/✗ 行)与 halt 文案,
116
+ * 是事后排障的唯一持久证据(TUI 红字刷屏即逝,没有这条就只剩「无产出」四个字)。
117
+ */
118
+ llmErrorDetail: string;
119
+ }
120
+
121
+ /** 把 llm_error 细节拼进可重试失败的抛错文案(无细节时退化为原样文案)。 */
122
+ export function describeLlmFailure(stepId: string, detail: string): string {
123
+ const base = `step ${stepId}: LLM 调用失败且无产出(触发重试)`;
124
+ return detail ? `${base}—— ${truncate(detail, 300)}` : base;
125
+ }
126
+
127
+ function cloneMessage(msg: Message): Message {
128
+ if (msg.role === 'user' && Array.isArray(msg.content)) {
129
+ return { ...msg, content: msg.content.map((part) => ({ ...part })) };
130
+ }
131
+ return { ...msg };
132
+ }
133
+
134
+ function createStepHistory(step: StepDef, ctx: RunContext): Message[] {
135
+ if (step.history_mode !== 'isolated') return ctx.history;
136
+ return ctx.history.filter((msg) => msg.role === 'system').map(cloneMessage);
137
+ }
138
+
139
+ /**
140
+ * agent / llm / skill 三个执行器共享的 runQuery 消费层。
141
+ *
142
+ * 为什么不能各自 `yield*` 直透(曾经的三份拷贝、agent.ts 漏同步酿成误报):
143
+ * runQuery 遇 LLM 超时/网络错是 yield error 后 return(不 throw),直透会让
144
+ * 执行器拿到空 history → 静默返回空文本 → runner 的 in-run retry 不触发
145
+ * (只对抛异常的 step 重试)。这里统一显式消费、侦测终结错误,把
146
+ * 「拿产出 + 记旗标」收敛成一份;**空产出 + sawLlmError 时抛不抛错的语义
147
+ * 差异保留在各执行器**(agent 还要过验证闸门,llm/skill 不过)。
148
+ *
149
+ * 事件透传逐字节等价于重构前:
150
+ * - error / interrupted 照常冒泡(红字照常显示,retry 交给 runner)
151
+ * - 'compact_failed' 非致命,不计为失败
152
+ * - suppressTurnDone(仅 skill 传 true):turn_done 是 runQuery 单次调用的
153
+ * 终结标记,不是 workflow 终结,外泄会让 gateway broker / -p json 误判
154
+ */
155
+ export async function* runStepQuery(
156
+ prompt: string,
157
+ step: StepDef,
158
+ ctx: RunContext,
159
+ opts: {
160
+ maxTurns: number;
161
+ suppressTurnDone?: boolean;
162
+ imageInputs?: ImageInputSpec[];
163
+ parseInlineImages?: boolean;
164
+ imageDetail?: ImageDetail;
165
+ imageMaxLongSidePixel?: number;
166
+ },
167
+ ): AsyncGenerator<LoopEvent, StepQueryOutcome, void> {
168
+ const activeHistory = createStepHistory(step, ctx);
169
+ const availableTools = ctx.tools ?? [];
170
+ const hostToolNames = new Set(availableTools.map((tool) => tool.name));
171
+ const effectiveStepTools =
172
+ step.allowed_tools === undefined
173
+ ? [...hostToolNames]
174
+ : step.allowed_tools.filter((name) => hostToolNames.has(name));
175
+ // 记录 runQuery 开始前的 history 长度,用于之后提取本步的 assistant 输出
176
+ const historyLenBefore = activeHistory.length;
177
+ const runtimeContext = createAgentRuntimeContext({
178
+ ...(ctx.runtimeContext ?? {
179
+ surface: 'workflow' as const,
180
+ profile: 'main' as const,
181
+ interactiveAsk: false,
182
+ }),
183
+ cwd: effectiveWorkflowCwd(ctx),
184
+ owner: ctx.runtimeContext?.owner ?? 'untrusted',
185
+ memoryAccess: ctx.runtimeContext?.memoryAccess ?? 'denied',
186
+ });
187
+
188
+ let aborted = false;
189
+ let sawLlmError = false;
190
+ let sawMaxTurns = false;
191
+ let llmErrorDetail = '';
192
+ let sawToolCall = false;
193
+ let toolOkCount = 0;
194
+ let toolFailCount = 0;
195
+ const toolNames: string[] = [];
196
+ for await (const ev of runQuery(prompt, {
197
+ provider: ctx.provider,
198
+ runtimeContext,
199
+ history: activeHistory,
200
+ signal: ctx.signal,
201
+ maxTurns: opts.maxTurns,
202
+ allowedTools: effectiveStepTools,
203
+ requiredTools:
204
+ step.allowed_tools === undefined ? undefined : effectiveStepTools,
205
+ chat: ctx.chat,
206
+ executeTool: ctx.executeTool,
207
+ sessionState: ctx.sessionState,
208
+ imageInputs: opts.imageInputs,
209
+ parseInlineImages: opts.parseInlineImages,
210
+ imageDetail: opts.imageDetail,
211
+ imageMaxLongSidePixel: opts.imageMaxLongSidePixel,
212
+ transientContext: ctx.transientContext,
213
+ transientBundle: ctx.transientBundle,
214
+ promptCache: ctx.promptCache,
215
+ // ⚠️ 宿主授权上下文必须跟着走 —— 这是与 `stepExecutors/tool.ts` 同一处遗漏的
216
+ // 另一半:tool 步补上了、agent/llm/skill 步没补的话,「让 agent 随机应变操作
217
+ // 电脑」这类步骤照样恒失败,而且症状与 tool 步完全一样、更难定位。
218
+ //
219
+ // 这里**整份下发**而不是像 tool 步那样按 `uses:` 切片,是有意的:agent 步本就是
220
+ // 「把判断权交给模型」的节点,它要用哪个工具由模型临场决定,事先切片等于让
221
+ // yaml 作者预测模型的选择。约束改由 `allowed_tools`(上面那行)承担 —— 那是
222
+ // agent 步既有的、更贴合其语义的收敛手段。
223
+ ...(ctx.host?.computerRun ? { computerRun: ctx.host.computerRun } : {}),
224
+ ...(ctx.host?.computerIntervention
225
+ ? { computerIntervention: ctx.host.computerIntervention }
226
+ : {}),
227
+ ...(ctx.host?.browserRun ? { browserRun: ctx.host.browserRun } : {}),
228
+ ...(ctx.host?.toolGate ? { toolGate: ctx.host.toolGate } : {}),
229
+ })) {
230
+ if (ev.type === 'error') {
231
+ if (ev.code === 'aborted') {
232
+ aborted = true;
233
+ } else if (ev.code === 'llm_error') {
234
+ sawLlmError = true;
235
+ llmErrorDetail = ev.error; // 留住 provider 真实报错,供执行器抛错时附带
236
+ // 🚫 不原样把这条 raw error 事件漏给顶层消费者(2026-07-04 真机事故:-p 模式
237
+ // 收到任意 type:'error' 就 handleEvent→exitCode:1→process.exit(),把整个 -p 进程
238
+ // 杀死在这里——比 runner.ts 的 in-run retry(max_retries/onError:continue)先一步
239
+ // 判定「终结」,等于跳过了整套设计好的重试/降级机制。这条信号已被上面两行转成
240
+ // sawLlmError/llmErrorDetail,稍后由本函数调用方(agent.ts 等)转成规范的可重试
241
+ // Error 抛出,交给 runner.ts 的 catch 块按 max_retries/onError 决定真正要不要终结、
242
+ // 要终结时也是由 runner.ts 在恰当时机重新 yield 一条 warning/error,不需要这条 raw 事件。
243
+ continue;
244
+ } else if (ev.code === 'max_turns') {
245
+ sawMaxTurns = true;
246
+ // 同上:max_turns 截断本是「可续跑」信号(isMaxTurnsCutoff),必须留给 runner.ts
247
+ // 的 in-run retry 先处理,不能原样漏给顶层当成终结。
248
+ continue;
249
+ }
250
+ } else if (
251
+ ev.type === 'warning' &&
252
+ ev.message.includes('finish_reason=length')
253
+ ) {
254
+ sawMaxTurns = true;
255
+ } else if (ev.type === 'tool_start') {
256
+ sawToolCall = true;
257
+ if (!toolNames.includes(ev.toolName)) toolNames.push(ev.toolName);
258
+ } else if (ev.type === 'tool_end') {
259
+ sawToolCall = true;
260
+ if (!toolNames.includes(ev.toolName)) toolNames.push(ev.toolName);
261
+ if (ev.ok) toolOkCount++;
262
+ else toolFailCount++;
263
+ }
264
+ if (opts.suppressTurnDone && ev.type === 'turn_done') continue;
265
+ yield ev;
266
+ }
267
+
268
+ // 从 history 提取本步产生的最后一条非空 assistant 消息。
269
+ // 经 stripThinkBlocks 净化:最后一条若是纯 <think> 块(模型收尾只剩思考),
270
+ // 继续向前回退到真正有内容的消息——capture/补充要求拿到的必须是交付文本。
271
+ let rawText = '';
272
+ for (let i = activeHistory.length - 1; i >= historyLenBefore; i--) {
273
+ const msg = activeHistory[i];
274
+ if (msg.role === 'assistant' && typeof msg.content === 'string') {
275
+ const cleaned = stripThinkBlocks(msg.content);
276
+ if (cleaned) {
277
+ rawText = cleaned;
278
+ break;
279
+ }
280
+ }
281
+ }
282
+
283
+ return {
284
+ rawText,
285
+ sawToolCall,
286
+ toolNames,
287
+ toolOkCount,
288
+ toolFailCount,
289
+ aborted,
290
+ sawLlmError,
291
+ sawMaxTurns,
292
+ llmErrorDetail,
293
+ };
294
+ }
295
+
296
+ /** maxTurns 截断失败文案的稳定标记(producer/detector 同源,防 runner 侧 delay 判定漂移)。 */
297
+ export const MAX_TURNS_CUTOFF_MARKER = '达到最大轮数';
298
+
299
+ /** maxTurns 截断的可重试失败文案(重试 = 在共享 history 上续作,再给一份轮数预算)。 */
300
+ export function describeMaxTurnsCutoff(
301
+ stepId: string,
302
+ maxTurns: number,
303
+ ): string {
304
+ return `step ${stepId}: ${MAX_TURNS_CUTOFF_MARKER} ${maxTurns} 被截断(可续跑)`;
305
+ }
306
+
307
+ /**
308
+ * 该错误是否是 maxTurns 截断(续作语义)。runner 的 in-run retry 用它区分延时:
309
+ * maxTurns 截断默认立即续作,不套用普通 retry_delay_ms;长文档/PPT 类工作流
310
+ * 可显式配置 max_turns_retry_delay_ms 给截断续作增加等待窗口。
311
+ */
312
+ export function isMaxTurnsCutoff(errMsg: string): boolean {
313
+ return errMsg.includes(MAX_TURNS_CUTOFF_MARKER) && errMsg.includes('被截断');
314
+ }
315
+
316
+ /**
317
+ * 解析非 schema 模式下 agent 最终文本里的放弃标记。
318
+ * - 命中 GIVEUP_MARKER → 返回原因字符串(可能为空串)
319
+ * - 未命中 → null(视为给出了真实结果)
320
+ *
321
+ * 注意:旧标记 __AGENT_GIVEUP__ 也兼容检测(向后兼容已存在的 checkpoint/状态数据),
322
+ * 但新代码只使用新标记格式。
323
+ */
324
+ const LEGACY_GIVEUP_MARKER = '__AGENT_GIVEUP__';
325
+
326
+ export function parseGiveup(text: string): string | null {
327
+ // 优先检测新标记
328
+ const newIdx = text.indexOf(GIVEUP_MARKER);
329
+ const legacyIdx = text.indexOf(LEGACY_GIVEUP_MARKER);
330
+
331
+ // 取先出现的那一个
332
+ let idx = -1;
333
+ let markerLen = 0;
334
+ if (newIdx !== -1 && (legacyIdx === -1 || newIdx < legacyIdx)) {
335
+ idx = newIdx;
336
+ markerLen = GIVEUP_MARKER.length;
337
+ } else if (legacyIdx !== -1) {
338
+ idx = legacyIdx;
339
+ markerLen = LEGACY_GIVEUP_MARKER.length;
340
+ }
341
+ if (idx === -1) return null;
342
+
343
+ return text
344
+ .slice(idx + markerLen)
345
+ .replace(/^[::\s\]]+/, '') // 兼容新旧标记后的分隔符(: / : / ])
346
+ .trim();
347
+ }
348
+
349
+ /** 判断一个 giveup reason 是否看起来像"误报"(实际是 LLM 在正常输出中碰巧触发了标记)。
350
+ *
351
+ * 启发式规则:
352
+ * - reason 长度 > 80 字符 → 几乎可以确定是误报(真正的放弃原因通常简短)
353
+ * - reason 包含结构化内容(如 ## 标题、### 章节、列表项等)→ 误报
354
+ */
355
+ function isLikelyFalsePositive(reason: string): boolean {
356
+ if (reason.length > 80) return true;
357
+ // 如果 reason 看起来像 markdown 正文(标题/章节),也是误报
358
+ if (
359
+ /^#{1,6}\s/m.test(reason) ||
360
+ /^[-*+]\s/m.test(reason) ||
361
+ /^\d+\.\s/m.test(reason)
362
+ ) {
363
+ return true;
364
+ }
365
+ return false;
366
+ }
367
+
368
+ /**
369
+ * 验证闸门:把 StepResult 判定为「真交付」或「放弃/不可信」。
370
+ * - schema 模式:extractJsonPayload 已严格解析(解析失败会抛、落不到这里),能拿到结果即 ok;
371
+ * 补 content 别名不覆盖具名字段。
372
+ * - 非 schema 模式:空产出 / 命中 GIVEUP 标记 → ok:false;否则 ok:true,raw 补 text/result/content
373
+ * 三键别名,兼容 capture:{content:x}/{result:x}/{text:x}。
374
+ *
375
+ * v0.9.3 增强:GIVEUP 检测增加误报过滤(isLikelyFalsePositive)。
376
+ * 当标记后的内容看起来像是实质性的工作产出而非简短放弃理由时,
377
+ * 视为 LLM 误触发标记 → 仍然当作成功交付处理。
378
+ */
379
+ export function interpretMiniReActResult(
380
+ result: StepResult,
381
+ hasSchema: boolean,
382
+ ): AgentOutcome {
383
+ if (hasSchema) {
384
+ const raw: Record<string, unknown> = { ...result.raw };
385
+ if (typeof raw.result === 'string' && raw.content === undefined) {
386
+ raw.content = raw.result;
387
+ }
388
+ return { ok: true, value: { raw, preview: result.preview } };
389
+ }
390
+
391
+ const text = typeof result.raw.text === 'string' ? result.raw.text : '';
392
+ const trimmed = text.trim();
393
+ if (trimmed.length === 0) {
394
+ return { ok: false, reason: '没有产出任何结果' };
395
+ }
396
+ const giveup = parseGiveup(trimmed);
397
+ if (giveup !== null) {
398
+ // v0.9.3: 误报过滤 —— 如果 "放弃原因" 太长或太结构化,
399
+ // 说明 LLM 是在正常输出中碰巧触发了标记,不应判为放弃
400
+ if (isLikelyFalsePositive(giveup)) {
401
+ // 降级为成功交付:去掉误触发的标记部分(replaceAll:标记可能被 LLM
402
+ // 误触发多次,replace 只删首个会让残留标记流进 capture 污染下游)
403
+ const cleanText = trimmed
404
+ .replaceAll(GIVEUP_MARKER, '')
405
+ .replaceAll(LEGACY_GIVEUP_MARKER, '')
406
+ .trim();
407
+ const raw: Record<string, unknown> = {
408
+ text: cleanText,
409
+ result: cleanText,
410
+ content: cleanText,
411
+ };
412
+ return {
413
+ ok: true,
414
+ value: {
415
+ raw,
416
+ preview:
417
+ cleanText.length > 200 ? `${cleanText.slice(0, 200)}…` : cleanText,
418
+ },
419
+ };
420
+ }
421
+ return { ok: false, reason: giveup || '显式放弃(未给原因)' };
422
+ }
423
+ const raw: Record<string, unknown> = {
424
+ text: trimmed,
425
+ result: trimmed,
426
+ content: trimmed,
427
+ };
428
+ return {
429
+ ok: true,
430
+ value: {
431
+ raw,
432
+ preview: trimmed.length > 200 ? `${trimmed.slice(0, 200)}…` : trimmed,
433
+ },
434
+ };
435
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * controlFlow/branch.ts —— 条件分支
3
+ *
4
+ * ⚠️ **branch 对 break 透明**:子块返回的 break/continue/halt 都原样上抛给
5
+ * 最近的循环或顶层。分支只决定「走哪一支」,不吞信号 —— 吞掉的话
6
+ * `break target:<loopId>` 就穿不过分支,而那正是它存在的意义。
7
+ */
8
+ import { evalExpr } from '../expressions.js';
9
+ export async function* execBranchStep(step, vars, deps) {
10
+ const { state } = deps;
11
+ let cond = false;
12
+ try {
13
+ cond = Boolean(evalExpr(step.condition ?? 'false', vars));
14
+ }
15
+ catch (e) {
16
+ const errMsg = `branch 条件错误: ${e.message}`;
17
+ await state.appendProgress(`✗ ${step.id}: ${errMsg}`);
18
+ yield { type: 'workflow_step_end', id: step.id, ok: false, error: errMsg };
19
+ yield { type: 'error', error: `Workflow halted at step "${step.id}": ${errMsg}` };
20
+ return { kind: 'halted' };
21
+ }
22
+ const branch = cond ? step.then : step.else;
23
+ if (Array.isArray(branch) && branch.length > 0) {
24
+ // 子块不传 cp:更深嵌套不记 checkpoint(见 CpScope 注释)。
25
+ const r = yield* deps.runBlock(branch, vars);
26
+ if (r === 'halted')
27
+ return { kind: 'halted' };
28
+ if (r !== 'completed')
29
+ return { kind: 'flow', signal: r };
30
+ }
31
+ await state.appendProgress(`✓ ${step.id} (branch=${cond})`);
32
+ await state.writeVars(vars.snapshot());
33
+ yield {
34
+ type: 'workflow_step_end',
35
+ id: step.id,
36
+ ok: true,
37
+ output: `branch=${cond}`,
38
+ };
39
+ return { kind: 'next' };
40
+ }