minimal-agent 0.13.0 → 0.15.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 (474) hide show
  1. package/README.md +6 -5
  2. package/package.json +60 -4
  3. package/plugins/computer_use/.claude-plugin/plugin.json +1 -1
  4. package/plugins/cron-runner/src/commands.js +4 -4
  5. package/plugins/cron-runner/src/commands.ts +4 -4
  6. package/plugins/workflow-runner/.claude-plugin/plugin.json +2 -2
  7. package/plugins/workflow-runner/commands/workflow.md +57 -90
  8. package/plugins/workflow-runner/commands/workflows.md +4 -4
  9. package/plugins/workflow-runner/plugin.js +24 -13
  10. package/plugins/workflow-runner/plugin.ts +28 -13
  11. package/plugins/workflow-runner/src/discovery.js +160 -0
  12. package/plugins/workflow-runner/src/discovery.ts +194 -0
  13. package/plugins/workflow-runner/src/goalAnchor.js +53 -0
  14. package/plugins/workflow-runner/src/goalAnchor.ts +59 -0
  15. package/plugins/workflow-runner/src/index.js +197 -206
  16. package/plugins/workflow-runner/src/index.ts +248 -249
  17. package/plugins/workflow-runner/src/inputCoercion.js +40 -0
  18. package/plugins/workflow-runner/src/inputCoercion.ts +43 -0
  19. package/plugins/workflow-runner/src/journal.js +224 -0
  20. package/plugins/workflow-runner/src/journal.ts +274 -0
  21. package/plugins/workflow-runner/src/jsonSchema.js +132 -0
  22. package/plugins/workflow-runner/src/jsonSchema.ts +162 -0
  23. package/plugins/workflow-runner/src/moduleResolution.js +64 -0
  24. package/plugins/workflow-runner/src/moduleResolution.ts +71 -0
  25. package/plugins/workflow-runner/src/resourceInputs.js +220 -0
  26. package/plugins/workflow-runner/src/resourceInputs.ts +300 -0
  27. package/plugins/workflow-runner/src/runner.js +400 -489
  28. package/plugins/workflow-runner/src/runner.ts +488 -560
  29. package/plugins/workflow-runner/src/runtime/config.js +46 -0
  30. package/plugins/workflow-runner/src/runtime/config.ts +69 -0
  31. package/plugins/workflow-runner/src/runtime/context.js +1304 -0
  32. package/plugins/workflow-runner/src/runtime/context.ts +1786 -0
  33. package/plugins/workflow-runner/src/runtime/exec.js +34 -0
  34. package/plugins/workflow-runner/src/runtime/exec.ts +53 -0
  35. package/plugins/workflow-runner/src/runtime/flow.js +8 -0
  36. package/plugins/workflow-runner/src/runtime/flow.ts +12 -0
  37. package/plugins/workflow-runner/src/runtime/fs.js +27 -0
  38. package/plugins/workflow-runner/src/runtime/fs.ts +41 -0
  39. package/plugins/workflow-runner/src/runtime/model.js +6 -0
  40. package/plugins/workflow-runner/src/runtime/model.ts +8 -0
  41. package/plugins/workflow-runner/src/runtime/output.js +7 -0
  42. package/plugins/workflow-runner/src/runtime/output.ts +21 -0
  43. package/plugins/workflow-runner/src/runtime/scheduler.js +141 -0
  44. package/plugins/workflow-runner/src/runtime/scheduler.ts +166 -0
  45. package/plugins/workflow-runner/src/runtime/state.js +16 -0
  46. package/plugins/workflow-runner/src/runtime/state.ts +19 -0
  47. package/plugins/workflow-runner/src/runtime/tools.js +3 -0
  48. package/plugins/workflow-runner/src/runtime/tools.ts +6 -0
  49. package/plugins/workflow-runner/src/sandbox.js +141 -0
  50. package/plugins/workflow-runner/src/sandbox.ts +182 -0
  51. package/plugins/workflow-runner/src/scriptGuard.d.mts +38 -0
  52. package/plugins/workflow-runner/src/scriptGuard.mjs +449 -0
  53. package/plugins/workflow-runner/src/taskIdentity.js +151 -307
  54. package/plugins/workflow-runner/src/taskIdentity.ts +207 -355
  55. package/plugins/workflow-runner/src/toolRuntime.js +29 -8
  56. package/plugins/workflow-runner/src/toolRuntime.ts +36 -11
  57. package/plugins/workflow-runner/src/types.js +7 -211
  58. package/plugins/workflow-runner/src/types.ts +154 -623
  59. package/plugins/workflow-runner/src/util.js +47 -0
  60. package/plugins/workflow-runner/src/util.ts +51 -0
  61. package/plugins/workflow-runner/src/workflowContext.js +20 -0
  62. package/plugins/workflow-runner/src/workflowContext.ts +58 -0
  63. package/plugins/workflow-runner/src/workflowDependencies.js +36 -0
  64. package/plugins/workflow-runner/src/workflowDependencies.ts +59 -0
  65. package/plugins/workflow-runner/src/workflowFingerprint.js +118 -0
  66. package/plugins/workflow-runner/src/workflowFingerprint.ts +122 -0
  67. package/plugins/workflow-runner/src/workflowState.js +474 -802
  68. package/plugins/workflow-runner/src/workflowState.ts +575 -970
  69. package/plugins/workflow-runner/test/api.test.ts +223 -0
  70. package/plugins/workflow-runner/test/apiCapabilities.test.ts +614 -0
  71. package/plugins/workflow-runner/test/apiConcurrencyGate.test.ts +104 -0
  72. package/plugins/workflow-runner/test/apiEcho.test.ts +210 -0
  73. package/plugins/workflow-runner/test/apiReadText.test.ts +178 -0
  74. package/plugins/workflow-runner/test/apiResourceLedger.test.ts +184 -0
  75. package/plugins/workflow-runner/test/childWorkflow.test.ts +304 -0
  76. package/plugins/workflow-runner/test/discovery.test.ts +234 -0
  77. package/plugins/workflow-runner/test/goalAnchor.test.ts +106 -0
  78. package/plugins/workflow-runner/test/goalController.test.ts +317 -0
  79. package/plugins/workflow-runner/test/journalLanes.test.ts +198 -0
  80. package/plugins/workflow-runner/test/listResources.test.ts +106 -0
  81. package/plugins/workflow-runner/test/resourceInputs.test.ts +294 -0
  82. package/plugins/workflow-runner/test/sandbox.test.ts +126 -0
  83. package/plugins/workflow-runner/test/scheduler.test.ts +70 -0
  84. package/plugins/workflow-runner/test/scriptGuard.test.ts +276 -0
  85. package/plugins/workflow-runner/test/skillDocSync.test.ts +78 -0
  86. package/plugins/workflow-runner/test/taskIdentity.test.ts +288 -179
  87. package/plugins/workflow-runner/test/workflowFingerprint.test.ts +106 -0
  88. package/plugins/workflow-runner/test/workflowState.test.ts +429 -0
  89. package/skills/pptx/examples/assets/cover-bg.svg +23 -0
  90. package/skills/pptx/examples/assets/icon-spark.svg +5 -0
  91. package/skills/ui-design/SKILL.md +5 -2
  92. package/skills/ui-design/references/layout-composition.md +1 -1
  93. package/skills/workflow-creator/SKILL.md +344 -0
  94. package/skills/workflow-creator/assets/template/workflow.mjs +48 -0
  95. package/skills/workflow-creator/references/api.md +216 -0
  96. package/skills/workflow-creator/references/migration.md +103 -0
  97. package/skills/workflow-creator/references/patterns.md +779 -0
  98. package/skills/workflow-creator/scripts/list-resources.mjs +205 -0
  99. package/skills/workflow-creator/scripts/scaffold.mjs +148 -0
  100. package/skills/workflow-creator/scripts/validate.mjs +275 -0
  101. package/skills/workflow-creator/scripts/workflow-creator.test.mjs +82 -0
  102. package/src/advisor/advisorCoordinator.js +536 -0
  103. package/src/advisor/advisorCoordinator.ts +693 -0
  104. package/src/cli/configMenu.tsx +0 -1
  105. package/src/cli/print.js +27 -6
  106. package/src/cli/print.ts +48 -4
  107. package/src/cli/quickModelSetup.js +12 -1
  108. package/src/cli/quickModelSetup.tsx +15 -3
  109. package/src/cli/streamJson.js +5 -6
  110. package/src/cli/streamJson.ts +8 -4
  111. package/src/cli/wizards/advisorWizard.js +4 -2
  112. package/src/cli/wizards/advisorWizard.tsx +8 -2
  113. package/src/cli/wizards/contextAdvisorWizard.js +5 -4
  114. package/src/cli/wizards/contextAdvisorWizard.tsx +7 -6
  115. package/src/cli/wizards/providerPresets.js +18 -8
  116. package/src/cli/wizards/providerPresets.ts +18 -8
  117. package/src/collaboration/taskFlow.js +115 -0
  118. package/src/collaboration/taskFlow.ts +169 -0
  119. package/src/config/configDefaults.js +41 -1
  120. package/src/config/configDefaults.ts +43 -1
  121. package/src/config/configDiagnostics.ts +2 -2
  122. package/src/config/configFile.js +40 -9
  123. package/src/config/configFile.ts +60 -11
  124. package/src/config/configService.js +419 -74
  125. package/src/config/configService.ts +703 -145
  126. package/src/config/numericLimits.js +22 -0
  127. package/src/config/numericLimits.ts +24 -0
  128. package/src/config.js +1 -0
  129. package/src/config.ts +3 -2
  130. package/src/context/budgetPlan.js +1 -1
  131. package/src/context/budgetPlan.ts +1 -1
  132. package/src/context/compact.js +7 -2
  133. package/src/context/compact.ts +9 -2
  134. package/src/context/microCompactLite.js +212 -13
  135. package/src/context/microCompactLite.ts +261 -12
  136. package/src/context/sessionRegistry.js +8 -1
  137. package/src/context/sessionRegistry.ts +18 -5
  138. package/src/context/toolResultArchive.js +72 -0
  139. package/src/context/toolResultArchive.ts +95 -0
  140. package/src/goal/errors.js +8 -0
  141. package/src/goal/errors.ts +18 -0
  142. package/src/goal/goalRuntime.js +344 -0
  143. package/src/goal/goalRuntime.ts +466 -0
  144. package/src/goal/goalStore.js +200 -0
  145. package/src/goal/goalStore.ts +219 -0
  146. package/src/goal/index.js +4 -0
  147. package/src/goal/index.ts +4 -0
  148. package/src/goal/statusMapping.js +71 -0
  149. package/src/goal/statusMapping.ts +95 -0
  150. package/src/goal/types.js +7 -0
  151. package/src/goal/types.ts +179 -0
  152. package/src/goal/workflowController.js +306 -0
  153. package/src/goal/workflowController.ts +360 -0
  154. package/src/harness/evidenceLedger.js +2 -0
  155. package/src/harness/evidenceLedger.ts +1 -0
  156. package/src/harness/stallGuard.js +9 -3
  157. package/src/harness/stallGuard.ts +7 -3
  158. package/src/images/imageResolver.js +161 -0
  159. package/src/images/imageResolver.ts +189 -0
  160. package/src/infra/verification.js +34 -5
  161. package/src/infra/verification.ts +39 -4
  162. package/src/llm/client.js +79 -21
  163. package/src/llm/client.ts +182 -35
  164. package/src/llm/gatewayClient.js +201 -0
  165. package/src/llm/gatewayClient.ts +299 -0
  166. package/src/llm/messageProvenance.js +46 -0
  167. package/src/llm/messageProvenance.ts +58 -0
  168. package/src/llm/modelProvider.js +1 -0
  169. package/src/llm/modelProvider.ts +22 -0
  170. package/src/llm/providers/anthropicFormat.js +108 -1
  171. package/src/llm/providers/anthropicFormat.ts +115 -4
  172. package/src/llm/providers/openaiFormat.js +9 -0
  173. package/src/llm/providers/openaiFormat.ts +12 -3
  174. package/src/loop.js +328 -55
  175. package/src/loop.ts +382 -58
  176. package/src/main.js +4 -1
  177. package/src/main.tsx +4 -1
  178. package/src/managedExecution/index.js +2 -0
  179. package/src/managedExecution/index.ts +2 -0
  180. package/src/managedExecution/registry.js +15 -0
  181. package/src/managedExecution/registry.ts +20 -0
  182. package/src/managedExecution/types.js +1 -0
  183. package/src/managedExecution/types.ts +86 -0
  184. package/src/modelRef.js +9 -0
  185. package/src/modelRef.ts +31 -0
  186. package/src/multimodal.js +14 -28
  187. package/src/multimodal.ts +17 -33
  188. package/src/net/lanDiscovery.js +65 -0
  189. package/src/net/lanDiscovery.ts +82 -0
  190. package/src/plugin-sdk.js +28 -3
  191. package/src/plugin-sdk.ts +39 -6
  192. package/src/plugins/pluginApi.ts +16 -1
  193. package/src/plugins/pluginLoader.js +4 -0
  194. package/src/plugins/pluginLoader.ts +6 -0
  195. package/src/plugins/pluginRunner.js +139 -7
  196. package/src/plugins/pluginRunner.ts +173 -9
  197. package/src/plugins/slashFallback.js +113 -0
  198. package/src/plugins/slashFallback.ts +137 -0
  199. package/src/prompts/policyRegistry.js +12 -32
  200. package/src/prompts/policyRegistry.ts +15 -32
  201. package/src/prompts/promptAssembly.js +103 -12
  202. package/src/prompts/promptAssembly.ts +114 -12
  203. package/src/prompts/skillList.js +21 -3
  204. package/src/prompts/skillList.ts +27 -2
  205. package/src/prompts/stableSystemPrompt.js +18 -0
  206. package/src/prompts/stableSystemPrompt.ts +33 -0
  207. package/src/runtime/agentRuntimeContext.js +8 -2
  208. package/src/runtime/agentRuntimeContext.ts +17 -4
  209. package/src/session/runAgentTurn.js +78 -12
  210. package/src/session/runAgentTurn.ts +105 -23
  211. package/src/session/runTurn.js +10 -9
  212. package/src/session/runTurn.ts +17 -8
  213. package/src/session/sessionState.ts +2 -0
  214. package/src/team/auth.js +186 -0
  215. package/src/team/auth.ts +298 -0
  216. package/src/team/cli.js +105 -0
  217. package/src/team/cli.ts +122 -0
  218. package/src/team/onlineToolContract.js +64 -0
  219. package/src/team/onlineToolContract.ts +109 -0
  220. package/src/team/toolPolicy.js +36 -0
  221. package/src/team/toolPolicy.ts +75 -0
  222. package/src/tools/advisor/advisor.js +115 -50
  223. package/src/tools/advisor/advisor.ts +124 -51
  224. package/src/tools/advisor/advisorDecision.js +71 -0
  225. package/src/tools/advisor/advisorDecision.ts +85 -0
  226. package/src/tools/agent/agent.js +18 -5
  227. package/src/tools/agent/agent.ts +21 -7
  228. package/src/tools/agent/agentControl.js +246 -0
  229. package/src/tools/agent/agentControl.ts +284 -0
  230. package/src/tools/agent/agentTaskService.js +40 -1
  231. package/src/tools/agent/agentTaskService.ts +44 -1
  232. package/src/tools/agent/agentTypes.js +14 -2
  233. package/src/tools/agent/agentTypes.ts +15 -2
  234. package/src/tools/applypatch/applyPatch.js +362 -0
  235. package/src/tools/applypatch/applyPatch.ts +428 -0
  236. package/src/tools/bash/bash.js +22 -15
  237. package/src/tools/bash/bash.ts +23 -17
  238. package/src/tools/capabilities.js +10 -5
  239. package/src/tools/capabilities.ts +10 -5
  240. package/src/tools/computeruse/computerIntent.js +32 -0
  241. package/src/tools/computeruse/computerIntent.ts +46 -0
  242. package/src/tools/computeruse/telemetryLog.js +12 -0
  243. package/src/tools/computeruse/telemetryLog.ts +16 -0
  244. package/src/tools/computeruse/vision/telemetry.js +1 -0
  245. package/src/tools/computeruse/vision/telemetry.ts +1 -0
  246. package/src/tools/effectiveToolSet.js +4 -0
  247. package/src/tools/effectiveToolSet.ts +4 -0
  248. package/src/tools/index.js +21 -2
  249. package/src/tools/index.ts +33 -2
  250. package/src/tools/presentresult/presentresult.js +6 -15
  251. package/src/tools/presentresult/presentresult.ts +6 -15
  252. package/src/tools/read/read.js +62 -9
  253. package/src/tools/read/read.ts +63 -9
  254. package/src/tools/shared/fileUtils.js +1 -2
  255. package/src/tools/shared/fileUtils.ts +1 -2
  256. package/src/tools/shared/toolOutputStore.js +23 -1
  257. package/src/tools/shared/toolOutputStore.ts +22 -1
  258. package/src/tools/skill/skill.js +9 -3
  259. package/src/tools/skill/skill.ts +8 -4
  260. package/src/tools/toolPromptGuides.js +125 -0
  261. package/src/tools/toolPromptGuides.ts +146 -0
  262. package/src/tools/webbrowser/agentBrowserPath.js +19 -9
  263. package/src/tools/webbrowser/agentBrowserPath.ts +70 -28
  264. package/src/tools/webbrowser/browser.js +27 -11
  265. package/src/tools/webbrowser/browser.ts +68 -24
  266. package/src/tools/webbrowser/browserAutomation.js +329 -0
  267. package/src/tools/webbrowser/browserAutomation.ts +467 -0
  268. package/src/tools/webbrowser/browserAxState.js +97 -0
  269. package/src/tools/webbrowser/browserAxState.ts +142 -0
  270. package/src/tools/webbrowser/browserBatch.js +1578 -0
  271. package/src/tools/webbrowser/browserBatch.ts +2382 -0
  272. package/src/tools/webbrowser/browserCdp.js +208 -0
  273. package/src/tools/webbrowser/browserCdp.ts +255 -0
  274. package/src/tools/webbrowser/browserConditions.js +24 -0
  275. package/src/tools/webbrowser/browserConditions.ts +45 -0
  276. package/src/tools/webbrowser/browserContent.js +281 -0
  277. package/src/tools/webbrowser/browserContent.ts +438 -0
  278. package/src/tools/webbrowser/browserControl.js +131 -34
  279. package/src/tools/webbrowser/browserControl.ts +210 -56
  280. package/src/tools/webbrowser/browserDaemon.js +22 -14
  281. package/src/tools/webbrowser/browserDaemon.ts +54 -21
  282. package/src/tools/webbrowser/browserFrames.js +47 -0
  283. package/src/tools/webbrowser/browserFrames.ts +54 -0
  284. package/src/tools/webbrowser/browserInteractionResolver.js +17 -0
  285. package/src/tools/webbrowser/browserInteractionResolver.ts +40 -0
  286. package/src/tools/webbrowser/browserLocator.js +140 -0
  287. package/src/tools/webbrowser/browserLocator.ts +194 -0
  288. package/src/tools/webbrowser/browserOutcome.js +10 -17
  289. package/src/tools/webbrowser/browserOutcome.ts +48 -31
  290. package/src/tools/webbrowser/browserRecovery.js +58 -0
  291. package/src/tools/webbrowser/browserRecovery.ts +83 -0
  292. package/src/tools/webbrowser/browserRunRegistry.js +35 -3
  293. package/src/tools/webbrowser/browserRunRegistry.ts +91 -15
  294. package/src/tools/webbrowser/browserService.js +28 -2
  295. package/src/tools/webbrowser/browserService.ts +49 -9
  296. package/src/tools/webbrowser/browserStream.js +132 -33
  297. package/src/tools/webbrowser/browserStream.ts +224 -50
  298. package/src/tools/webbrowser/browserTabs.js +48 -15
  299. package/src/tools/webbrowser/browserTabs.ts +178 -96
  300. package/src/tools/webbrowser/webbrowser.js +679 -144
  301. package/src/tools/webbrowser/webbrowser.ts +975 -236
  302. package/src/tools/webfetch/preapproved.js +0 -2
  303. package/src/tools/webfetch/preapproved.ts +0 -2
  304. package/src/tools/websearch/websearch.js +129 -8
  305. package/src/tools/websearch/websearch.ts +138 -6
  306. package/src/types.ts +459 -40
  307. package/src/ui/App.js +377 -58
  308. package/src/ui/App.tsx +576 -111
  309. package/src/ui/LiveArea.js +14 -8
  310. package/src/ui/LiveArea.tsx +14 -10
  311. package/src/ui/MessageList.js +63 -20
  312. package/src/ui/MessageList.tsx +101 -16
  313. package/src/ui/ModelPicker.js +7 -4
  314. package/src/ui/ModelPicker.tsx +55 -8
  315. package/src/ui/hooks/useChat.js +152 -163
  316. package/src/ui/hooks/useChat.ts +396 -334
  317. package/src/ui/loginCommand.js +56 -0
  318. package/src/ui/loginCommand.ts +63 -0
  319. package/src/ui/toolProgress.js +41 -0
  320. package/src/ui/toolProgress.ts +44 -0
  321. package/src/web/browserBridge.js +20 -2
  322. package/src/web/browserBridge.ts +20 -2
  323. package/src/web/protocol.ts +1897 -194
  324. package/workflows/adaptive-research/workflow.mjs +86 -0
  325. package/workflows/e2e-capabilities/workflow.mjs +102 -0
  326. package/workflows/e2e-llm/workflow.mjs +52 -0
  327. package/workflows/e2e-smoke/workflow.mjs +59 -0
  328. package/workflows/e2e-vision-schema/README.md +48 -0
  329. package/workflows/e2e-vision-schema/workflow.mjs +149 -0
  330. package/workflows/e2e-write-greet/workflow.mjs +37 -0
  331. package/workflows/file-census/README.md +14 -0
  332. package/workflows/file-census/scripts/.gitkeep +2 -0
  333. package/workflows/file-census/workflow.mjs +110 -0
  334. package/workflows/goal/README.md +166 -0
  335. package/workflows/goal/prompts/audit.md +57 -0
  336. package/workflows/goal/prompts/contract.md +56 -0
  337. package/workflows/goal/prompts/iterate.md +37 -0
  338. package/workflows/goal/workflow.mjs +501 -0
  339. package/workflows/illustrate/README.md +90 -0
  340. package/workflows/illustrate/assets/engines.json +20 -0
  341. package/workflows/illustrate/assets/extract-baidu.js +21 -0
  342. package/workflows/illustrate/assets/extract-bing.js +33 -0
  343. package/workflows/illustrate/assets/extract-google.js +31 -0
  344. package/workflows/illustrate/workflow.mjs +301 -0
  345. package/workflows/plan/workflow.mjs +389 -0
  346. package/workflows/question-crops/README.md +35 -0
  347. package/workflows/question-crops/prompts/inventory.md +23 -0
  348. package/workflows/question-crops/scripts/image-ops.mjs +305 -0
  349. package/workflows/question-crops/scripts/image-ops.test.mjs +95 -0
  350. package/workflows/question-crops/workflow.mjs +172 -0
  351. package/workflows/ralph-loop/workflow.mjs +162 -0
  352. package/workflows/research/README.md +74 -0
  353. package/workflows/research/prompts/s0-goal.md +43 -0
  354. package/workflows/research/prompts/s1-early-exit.md +22 -0
  355. package/workflows/research/prompts/s1-map.md +58 -0
  356. package/workflows/research/prompts/s2-options.md +53 -0
  357. package/workflows/research/prompts/s3-deep-dive.md +56 -0
  358. package/workflows/research/prompts/s4-verify.md +74 -0
  359. package/workflows/research/prompts/s5-synthesis.md +81 -0
  360. package/workflows/research/prompts/s5b-fill-gaps.md +32 -0
  361. package/workflows/research/prompts/s6-package.md +32 -0
  362. package/workflows/research/scripts/build-report.mjs +98 -0
  363. package/workflows/research/workflow.mjs +288 -0
  364. package/workflows/wechat-reading-shots/prompts/collect-params.md +16 -0
  365. package/workflows/wechat-reading-shots/prompts/evaluate.md +20 -0
  366. package/workflows/wechat-reading-shots/prompts/open-book.md +28 -0
  367. package/workflows/wechat-reading-shots/prompts/read-page.md +13 -0
  368. package/workflows/wechat-reading-shots/prompts/turn-batch.md +24 -0
  369. package/workflows/wechat-reading-shots/test/control-flow.test.ts +329 -0
  370. package/workflows/wechat-reading-shots/workflow.mjs +266 -0
  371. package/workflows/wrong-question-docx/README.md +55 -0
  372. package/workflows/wrong-question-docx/prompts/figure-qa.md +8 -0
  373. package/workflows/wrong-question-docx/prompts/transcribe.md +25 -0
  374. package/workflows/wrong-question-docx/scripts/workbook.mjs +857 -0
  375. package/workflows/wrong-question-docx/test/control-flow.test.ts +165 -0
  376. package/workflows/wrong-question-docx/test/workbook.test.mjs +303 -0
  377. package/workflows/wrong-question-docx/workflow.mjs +485 -0
  378. package/plugins/workflow-runner/src/agentCommon.js +0 -354
  379. package/plugins/workflow-runner/src/agentCommon.ts +0 -435
  380. package/plugins/workflow-runner/src/controlFlow/branch.js +0 -40
  381. package/plugins/workflow-runner/src/controlFlow/branch.ts +0 -46
  382. package/plugins/workflow-runner/src/controlFlow/loop.js +0 -211
  383. package/plugins/workflow-runner/src/controlFlow/loop.ts +0 -248
  384. package/plugins/workflow-runner/src/controlFlow/pause.js +0 -129
  385. package/plugins/workflow-runner/src/controlFlow/pause.ts +0 -141
  386. package/plugins/workflow-runner/src/controlFlow/signal.js +0 -21
  387. package/plugins/workflow-runner/src/controlFlow/signal.ts +0 -29
  388. package/plugins/workflow-runner/src/controlFlow/types.js +0 -18
  389. package/plugins/workflow-runner/src/controlFlow/types.ts +0 -63
  390. package/plugins/workflow-runner/src/dslManifest.js +0 -72
  391. package/plugins/workflow-runner/src/dslManifest.ts +0 -127
  392. package/plugins/workflow-runner/src/expressions.js +0 -639
  393. package/plugins/workflow-runner/src/expressions.ts +0 -640
  394. package/plugins/workflow-runner/src/loader.js +0 -573
  395. package/plugins/workflow-runner/src/loader.ts +0 -721
  396. package/plugins/workflow-runner/src/multimodal.js +0 -38
  397. package/plugins/workflow-runner/src/multimodal.ts +0 -64
  398. package/plugins/workflow-runner/src/recovery.js +0 -126
  399. package/plugins/workflow-runner/src/recovery.ts +0 -156
  400. package/plugins/workflow-runner/src/stepExecutors/agent.js +0 -173
  401. package/plugins/workflow-runner/src/stepExecutors/agent.ts +0 -234
  402. package/plugins/workflow-runner/src/stepExecutors/assert.js +0 -42
  403. package/plugins/workflow-runner/src/stepExecutors/assert.ts +0 -52
  404. package/plugins/workflow-runner/src/stepExecutors/echo.js +0 -31
  405. package/plugins/workflow-runner/src/stepExecutors/echo.ts +0 -38
  406. package/plugins/workflow-runner/src/stepExecutors/llm.js +0 -99
  407. package/plugins/workflow-runner/src/stepExecutors/llm.ts +0 -133
  408. package/plugins/workflow-runner/src/stepExecutors/set.js +0 -49
  409. package/plugins/workflow-runner/src/stepExecutors/set.ts +0 -56
  410. package/plugins/workflow-runner/src/stepExecutors/skill.js +0 -111
  411. package/plugins/workflow-runner/src/stepExecutors/skill.ts +0 -140
  412. package/plugins/workflow-runner/src/stepExecutors/tool.js +0 -227
  413. package/plugins/workflow-runner/src/stepExecutors/tool.ts +0 -274
  414. package/plugins/workflow-runner/src/stepExecutors/verify.js +0 -61
  415. package/plugins/workflow-runner/src/stepExecutors/verify.ts +0 -72
  416. package/plugins/workflow-runner/src/stepPipeline.js +0 -277
  417. package/plugins/workflow-runner/src/stepPipeline.ts +0 -366
  418. package/plugins/workflow-runner/test/agent.test.ts +0 -587
  419. package/plugins/workflow-runner/test/agentLlmError.test.ts +0 -373
  420. package/plugins/workflow-runner/test/bashBlacklist.sweep.test.ts +0 -65
  421. package/plugins/workflow-runner/test/captureMisbind.test.ts +0 -99
  422. package/plugins/workflow-runner/test/cli.e2e.test.ts +0 -167
  423. package/plugins/workflow-runner/test/context-files.test.ts +0 -320
  424. package/plugins/workflow-runner/test/e2e.test.ts +0 -370
  425. package/plugins/workflow-runner/test/e2eNewLayout.test.ts +0 -314
  426. package/plugins/workflow-runner/test/engineRobustness.test.ts +0 -234
  427. package/plugins/workflow-runner/test/expressions.test.ts +0 -439
  428. package/plugins/workflow-runner/test/foundation.test.ts +0 -126
  429. package/plugins/workflow-runner/test/graceful.test.ts +0 -139
  430. package/plugins/workflow-runner/test/greedyInputs.load.test.ts +0 -47
  431. package/plugins/workflow-runner/test/hostCapability.test.ts +0 -108
  432. package/plugins/workflow-runner/test/illustrate.load.test.ts +0 -183
  433. package/plugins/workflow-runner/test/jsonPayload.test.ts +0 -83
  434. package/plugins/workflow-runner/test/loader.test.ts +0 -617
  435. package/plugins/workflow-runner/test/maxTurnsRetryDelay.test.ts +0 -33
  436. package/plugins/workflow-runner/test/multimodal.test.ts +0 -342
  437. package/plugins/workflow-runner/test/output-schema.test.ts +0 -213
  438. package/plugins/workflow-runner/test/parseWorkflowArgs.test.ts +0 -106
  439. package/plugins/workflow-runner/test/pluginRunner.isolation.test.ts +0 -269
  440. package/plugins/workflow-runner/test/ppt.load.test.ts +0 -1220
  441. package/plugins/workflow-runner/test/ralphLoop.e2e.test.ts +0 -221
  442. package/plugins/workflow-runner/test/recovery.test.ts +0 -265
  443. package/plugins/workflow-runner/test/research.load.test.ts +0 -328
  444. package/plugins/workflow-runner/test/runner.test.ts +0 -911
  445. package/plugins/workflow-runner/test/runnerPreflight.test.ts +0 -436
  446. package/plugins/workflow-runner/test/skillTurnDone.test.ts +0 -71
  447. package/plugins/workflow-runner/test/stateLifecycle.test.ts +0 -198
  448. package/plugins/workflow-runner/test/stepPipeline.test.ts +0 -114
  449. package/plugins/workflow-runner/test/taskArbitration.test.ts +0 -354
  450. package/plugins/workflow-runner/test/taskLifecycle.test.ts +0 -324
  451. package/plugins/workflow-runner/test/toolArtifactOverwrite.test.ts +0 -221
  452. package/plugins/workflow-runner/test/toolCapabilityBoundary.test.ts +0 -29
  453. package/plugins/workflow-runner/test/toolRuntimeIntegration.test.ts +0 -168
  454. package/plugins/workflow-runner/test/webppt.load.test.ts +0 -250
  455. package/plugins/workflow-runner/test/word.load.test.ts +0 -208
  456. package/plugins/workflow-runner/test/workflows.smoke.test.ts +0 -76
  457. package/plugins/workflow-runner/test/yamlGuardConditions.test.ts +0 -207
  458. package/src/advisorState.js +0 -22
  459. package/src/cli/configWizard.js +0 -293
  460. package/src/tools/toolProgressBridge.js +0 -48
  461. package/workflows/adaptive-research.yaml +0 -50
  462. package/workflows/book-review-short.yaml +0 -125
  463. package/workflows/e2e-write-greet.yaml +0 -31
  464. package/workflows/illustrate.yaml +0 -227
  465. package/workflows/plan.yaml +0 -470
  466. package/workflows/ppt.yaml +0 -1670
  467. package/workflows/ralph-loop.yaml +0 -201
  468. package/workflows/research.yaml +0 -873
  469. package/workflows/schema.json +0 -176
  470. package/workflows/webppt.yaml +0 -496
  471. package/workflows/wechat-reading-shots.yaml +0 -315
  472. package/workflows/word.yaml +0 -720
  473. package/workflows/youtube-shorts.yaml +0 -202
  474. /package/workflows/{research.md → research/DESIGN.md} +0 -0
@@ -1,6 +1,13 @@
1
+ import type {
2
+ HumanInterventionCredential,
3
+ HumanInterventionEvent,
4
+ } from '../../humanIntervention.js';
5
+ import {
6
+ BrowserControlCoordinator,
7
+ type BrowserControlState,
8
+ type BrowserHumanReason,
9
+ } from './browserControl.js';
1
10
  import { getStreamPort, waitForStreamPort } from './browserDaemon.js';
2
- import { BrowserControlCoordinator, type BrowserControlState, type BrowserHumanReason } from './browserControl.js';
3
- import type { HumanInterventionCredential, HumanInterventionEvent } from '../../humanIntervention.js';
4
11
 
5
12
  export type BrowserMode = 'browse' | 'assist' | 'auto';
6
13
  export type PickedBrowserElement = {
@@ -12,7 +19,10 @@ export type PickedBrowserElement = {
12
19
  boundingBox?: { x: number; y: number; width: number; height: number };
13
20
  attributes?: Record<string, string>;
14
21
  };
15
- export type MarkedBrowserElement = PickedBrowserElement & { label?: string; color?: string };
22
+ export type MarkedBrowserElement = PickedBrowserElement & {
23
+ label?: string;
24
+ color?: string;
25
+ };
16
26
  export type BrowserStreamEvent = Record<string, unknown> & { type: string };
17
27
 
18
28
  export interface BrowserStream {
@@ -21,6 +31,8 @@ export interface BrowserStream {
21
31
  send(frame: unknown): void;
22
32
  dispose(): void;
23
33
  subscribe(listener: (event: BrowserStreamEvent) => void): () => void;
34
+ /** Publish a local engine event to Desktop observers (downloads/CDP lifecycle). */
35
+ publish(event: BrowserStreamEvent): void;
24
36
  getStatus(): Record<string, unknown>;
25
37
  getPort(): number | null;
26
38
  isConnected(): boolean;
@@ -29,7 +41,9 @@ export interface BrowserStream {
29
41
  getCurrentUrl(): string;
30
42
  setCurrentUrl(url: string): void;
31
43
  pickElement(x: number, y: number): Promise<PickedBrowserElement | null>;
32
- setPicker(picker: (x: number, y: number) => Promise<PickedBrowserElement | null>): void;
44
+ setPicker(
45
+ picker: (x: number, y: number) => Promise<PickedBrowserElement | null>,
46
+ ): void;
33
47
  markElement(element: MarkedBrowserElement): void;
34
48
  clearMarkedElements(): void;
35
49
  /** Remove a single marked element by ref (does not affect other marks). */
@@ -41,7 +55,10 @@ export interface BrowserStream {
41
55
  * 候选只进对话的话,盯着浏览器的人看到的是 AI 忽然停住;推到面板上他可以一眼看出
42
56
  * AI 卡在哪,并点一下把正确的那个喂回去 —— 人的判断比模型再猜一轮便宜得多。
43
57
  */
44
- setAgentCandidates(candidates: Array<{ ref: string; line: string }>, selector?: string): void;
58
+ setAgentCandidates(
59
+ candidates: Array<{ ref: string; line: string }>,
60
+ selector?: string,
61
+ ): void;
45
62
  /**
46
63
  * 发布一次动作**做完之后**的生效结论(只在结论不是「变了」时调用)。
47
64
  *
@@ -55,14 +72,34 @@ export interface BrowserStream {
55
72
  maskedLines?: number;
56
73
  }): void;
57
74
  /** C4:发布 AI 指针语义终点给可见面板(宿主用 CSS 过渡平滑移动 + 渲染点击动效)。 */
58
- setAgentPointer(pointer: { x: number; y: number; visible: boolean; action?: 'move' | 'click' | 'type' | 'hover' | 'scroll' | 'idle'; elementRef?: string }): void;
75
+ setAgentPointer(pointer: {
76
+ x: number;
77
+ y: number;
78
+ visible: boolean;
79
+ action?: 'move' | 'click' | 'type' | 'hover' | 'scroll' | 'idle';
80
+ elementRef?: string;
81
+ }): void;
59
82
  getControlState(): BrowserControlState;
60
83
  /** 订阅控制权状态变化(立即以当前状态回调一次);供工具即时感知「用户接管 / 进入 waiting_human」以掐断在跑动作。 */
61
84
  subscribeControl(listener: (state: BrowserControlState) => void): () => void;
62
- subscribeInterventions(listener: (event: HumanInterventionEvent) => void): () => void;
63
- beginAgentAction(input: { runId: string; conversationKey?: string; action?: string }): void;
85
+ subscribeInterventions(
86
+ listener: (event: HumanInterventionEvent) => void,
87
+ ): () => void;
88
+ beginAgentAction(input: {
89
+ runId: string;
90
+ conversationKey?: string;
91
+ action?: string;
92
+ }): void;
64
93
  finishAgentAction(runId: string): void;
65
- requestHuman(reason: BrowserHumanReason, input?: { runId?: string; conversationKey?: string; ownerId?: string; summary?: string }): string;
94
+ requestHuman(
95
+ reason: BrowserHumanReason,
96
+ input?: {
97
+ runId?: string;
98
+ conversationKey?: string;
99
+ ownerId?: string;
100
+ summary?: string;
101
+ },
102
+ ): string;
66
103
  takeControl(input?: { runId?: string; conversationKey?: string }): void;
67
104
  resumeControl(token?: string): boolean;
68
105
  stopControl(token?: string): boolean;
@@ -78,25 +115,46 @@ class SessionBrowserStream implements BrowserStream {
78
115
  private port: number | null = null;
79
116
  private mode: BrowserMode = 'browse';
80
117
  private currentUrl = 'about:blank';
81
- private status: Record<string, unknown> = { connected: false, screencasting: false };
82
- private picker?: (x: number, y: number) => Promise<PickedBrowserElement | null>;
118
+ private status: Record<string, unknown> = {
119
+ connected: false,
120
+ screencasting: false,
121
+ };
122
+ private reconnectTimer: ReturnType<typeof setTimeout> | null = null;
123
+ private reconnectAttempt = 0;
124
+ private disposed = false;
125
+ private picker?: (
126
+ x: number,
127
+ y: number,
128
+ ) => Promise<PickedBrowserElement | null>;
83
129
  private marked: MarkedBrowserElement[] = [];
84
130
  private control: BrowserControlCoordinator;
85
131
 
86
132
  constructor(private readonly sessionName: string) {
87
- this.control = new BrowserControlCoordinator({ conversationKey: `browser:${sessionName}` });
88
- this.control.subscribe((state) => this.emit({ type: 'control_state', state }));
89
- this.control.subscribeInterventions((event) => this.emit({
90
- type: event.type === 'started' ? 'human_intervention_started' : 'human_intervention_resolved',
91
- event,
92
- }));
133
+ this.control = new BrowserControlCoordinator({
134
+ conversationKey: `browser:${sessionName}`,
135
+ });
136
+ this.control.subscribe((state) =>
137
+ this.emit({ type: 'control_state', state }),
138
+ );
139
+ this.control.subscribeInterventions((event) =>
140
+ this.emit({
141
+ type:
142
+ event.type === 'started'
143
+ ? 'human_intervention_started'
144
+ : 'human_intervention_resolved',
145
+ event,
146
+ }),
147
+ );
93
148
  }
94
149
 
95
150
  async connect(): Promise<void> {
151
+ this.disposed = false;
96
152
  if (this.socket?.readyState === WebSocket.OPEN) return;
97
153
  if (this.connecting) return this.connecting;
98
154
  this.connecting = (async () => {
99
- this.port = (await getStreamPort(this.sessionName)) ?? (await waitForStreamPort(this.sessionName));
155
+ this.port =
156
+ (await getStreamPort(this.sessionName)) ??
157
+ (await waitForStreamPort(this.sessionName));
100
158
  await new Promise<void>((resolve, reject) => {
101
159
  const socket = new WebSocket(`ws://127.0.0.1:${this.port}`);
102
160
  const timer = setTimeout(() => {
@@ -106,6 +164,7 @@ class SessionBrowserStream implements BrowserStream {
106
164
  socket.onopen = () => {
107
165
  clearTimeout(timer);
108
166
  this.socket = socket;
167
+ this.reconnectAttempt = 0;
109
168
  this.status = { ...this.status, connected: true };
110
169
  this.emit({ type: 'status', ...this.status });
111
170
  resolve();
@@ -116,40 +175,86 @@ class SessionBrowserStream implements BrowserStream {
116
175
  };
117
176
  socket.onclose = () => {
118
177
  if (this.socket === socket) this.socket = null;
119
- this.status = { ...this.status, connected: false, screencasting: false };
178
+ this.status = {
179
+ ...this.status,
180
+ connected: false,
181
+ screencasting: false,
182
+ };
120
183
  this.emit({ type: 'status', ...this.status });
184
+ this.scheduleReconnect();
121
185
  };
122
186
  socket.onmessage = (event) => this.onMessage(event.data);
123
187
  });
124
- })().finally(() => { this.connecting = null; });
188
+ })().finally(() => {
189
+ this.connecting = null;
190
+ });
125
191
  return this.connecting;
126
192
  }
127
193
 
128
- disconnect(): void { this.socket?.close(); this.socket = null; }
129
- dispose(): void { this.disconnect(); this.listeners.clear(); }
194
+ disconnect(): void {
195
+ this.disposed = true;
196
+ if (this.reconnectTimer) clearTimeout(this.reconnectTimer);
197
+ this.reconnectTimer = null;
198
+ this.socket?.close();
199
+ this.socket = null;
200
+ }
201
+ dispose(): void {
202
+ this.disconnect();
203
+ this.listeners.clear();
204
+ }
130
205
  send(frame: unknown): void {
131
- if (this.socket?.readyState === WebSocket.OPEN) this.socket.send(JSON.stringify(frame));
206
+ if (this.socket?.readyState === WebSocket.OPEN)
207
+ this.socket.send(JSON.stringify(frame));
132
208
  }
133
209
  subscribe(listener: (event: BrowserStreamEvent) => void): () => void {
134
210
  this.listeners.add(listener);
135
211
  return () => this.listeners.delete(listener);
136
212
  }
137
- getStatus(): Record<string, unknown> { return this.status; }
138
- getPort(): number | null { return this.port; }
139
- isConnected(): boolean { return this.socket?.readyState === WebSocket.OPEN; }
140
- setMode(mode: BrowserMode): void { this.mode = mode; this.emit({ type: 'mode', mode }); }
141
- getMode(): BrowserMode { return this.mode; }
142
- getCurrentUrl(): string { return this.currentUrl; }
143
- setCurrentUrl(url: string): void { this.currentUrl = url; this.emit({ type: 'url', url }); }
144
- setPicker(picker: (x: number, y: number) => Promise<PickedBrowserElement | null>): void { this.picker = picker; }
213
+ publish(event: BrowserStreamEvent): void {
214
+ this.emit(event);
215
+ }
216
+ getStatus(): Record<string, unknown> {
217
+ return this.status;
218
+ }
219
+ getPort(): number | null {
220
+ return this.port;
221
+ }
222
+ isConnected(): boolean {
223
+ return this.socket?.readyState === WebSocket.OPEN;
224
+ }
225
+ setMode(mode: BrowserMode): void {
226
+ this.mode = mode;
227
+ this.emit({ type: 'mode', mode });
228
+ }
229
+ getMode(): BrowserMode {
230
+ return this.mode;
231
+ }
232
+ getCurrentUrl(): string {
233
+ return this.currentUrl;
234
+ }
235
+ setCurrentUrl(url: string): void {
236
+ this.currentUrl = url;
237
+ this.emit({ type: 'url', url });
238
+ }
239
+ setPicker(
240
+ picker: (x: number, y: number) => Promise<PickedBrowserElement | null>,
241
+ ): void {
242
+ this.picker = picker;
243
+ }
145
244
  pickElement(x: number, y: number): Promise<PickedBrowserElement | null> {
146
245
  return this.picker ? this.picker(x, y) : Promise.resolve(null);
147
246
  }
148
247
  markElement(element: MarkedBrowserElement): void {
149
- this.marked = [...this.marked.filter((item) => item.ref !== element.ref), element];
248
+ this.marked = [
249
+ ...this.marked.filter((item) => item.ref !== element.ref),
250
+ element,
251
+ ];
150
252
  this.emit({ type: 'marked_elements', elements: this.marked });
151
253
  }
152
- clearMarkedElements(): void { this.marked = []; this.emit({ type: 'marked_elements', elements: [] }); }
254
+ clearMarkedElements(): void {
255
+ this.marked = [];
256
+ this.emit({ type: 'marked_elements', elements: [] });
257
+ }
153
258
  unmarkElement(ref: string): void {
154
259
  const next = this.marked.filter((item) => item.ref !== ref);
155
260
  if (next.length !== this.marked.length) {
@@ -160,7 +265,10 @@ class SessionBrowserStream implements BrowserStream {
160
265
  setAgentActing(acting: boolean, action?: string, target?: string): void {
161
266
  this.emit({ type: 'agent_acting', acting, action, target });
162
267
  }
163
- setAgentCandidates(candidates: Array<{ ref: string; line: string }>, selector?: string): void {
268
+ setAgentCandidates(
269
+ candidates: Array<{ ref: string; line: string }>,
270
+ selector?: string,
271
+ ): void {
164
272
  this.emit({ type: 'agent_candidates', candidates, selector });
165
273
  }
166
274
  setAgentOutcome(outcome: {
@@ -171,39 +279,102 @@ class SessionBrowserStream implements BrowserStream {
171
279
  }): void {
172
280
  this.emit({ type: 'agent_outcome', ...outcome });
173
281
  }
174
- setAgentPointer(pointer: { x: number; y: number; visible: boolean; action?: 'move' | 'click' | 'type' | 'hover' | 'scroll' | 'idle'; elementRef?: string }): void {
282
+ setAgentPointer(pointer: {
283
+ x: number;
284
+ y: number;
285
+ visible: boolean;
286
+ action?: 'move' | 'click' | 'type' | 'hover' | 'scroll' | 'idle';
287
+ elementRef?: string;
288
+ }): void {
175
289
  // 只发语义终点(目标元素中心 + 动作类型);平滑移动交给面板 CSS 过渡,内核不做逐帧插值(避免 WS 洪泛 + 双层缓动打架)。
176
290
  this.emit({ type: 'agent_pointer', ...pointer });
177
291
  }
178
- getControlState(): BrowserControlState { return this.control.getState(); }
179
- subscribeControl(listener: (state: BrowserControlState) => void): () => void { return this.control.subscribe(listener); }
180
- subscribeInterventions(listener: (event: HumanInterventionEvent) => void): () => void { return this.control.subscribeInterventions(listener); }
181
- beginAgentAction(input: { runId: string; conversationKey?: string; action?: string }): void { this.control.beginAgent(input); }
182
- finishAgentAction(runId: string): void { this.control.finishAgent(runId); }
183
- requestHuman(reason: BrowserHumanReason, input?: { runId?: string; conversationKey?: string; ownerId?: string; summary?: string }): string { return this.control.requestHuman(reason, input); }
184
- takeControl(input?: { runId?: string; conversationKey?: string }): void { this.control.takeInteractive(input); }
185
- resumeControl(token?: string): boolean { return this.control.resume(token); }
186
- stopControl(token?: string): boolean { return this.control.stop(token); }
292
+ getControlState(): BrowserControlState {
293
+ return this.control.getState();
294
+ }
295
+ subscribeControl(listener: (state: BrowserControlState) => void): () => void {
296
+ return this.control.subscribe(listener);
297
+ }
298
+ subscribeInterventions(
299
+ listener: (event: HumanInterventionEvent) => void,
300
+ ): () => void {
301
+ return this.control.subscribeInterventions(listener);
302
+ }
303
+ beginAgentAction(input: {
304
+ runId: string;
305
+ conversationKey?: string;
306
+ action?: string;
307
+ }): void {
308
+ this.control.beginAgent(input);
309
+ }
310
+ finishAgentAction(runId: string): void {
311
+ this.control.finishAgent(runId);
312
+ }
313
+ requestHuman(
314
+ reason: BrowserHumanReason,
315
+ input?: {
316
+ runId?: string;
317
+ conversationKey?: string;
318
+ ownerId?: string;
319
+ summary?: string;
320
+ },
321
+ ): string {
322
+ return this.control.requestHuman(reason, input);
323
+ }
324
+ takeControl(input?: { runId?: string; conversationKey?: string }): void {
325
+ this.control.takeInteractive(input);
326
+ }
327
+ resumeControl(token?: string): boolean {
328
+ return this.control.resume(token);
329
+ }
330
+ stopControl(token?: string): boolean {
331
+ return this.control.stop(token);
332
+ }
187
333
  resumeIntervention(credential: HumanInterventionCredential): boolean {
188
334
  return this.control.resumeIntervention(credential);
189
335
  }
190
336
  cancelIntervention(credential: HumanInterventionCredential): boolean {
191
337
  return this.control.cancelIntervention(credential);
192
338
  }
193
- waitForHuman(signal?: AbortSignal): Promise<'resumed' | 'stopped'> { return this.control.waitForHuman(signal); }
339
+ waitForHuman(signal?: AbortSignal): Promise<'resumed' | 'stopped'> {
340
+ return this.control.waitForHuman(signal);
341
+ }
194
342
 
195
343
  private emit(event: BrowserStreamEvent): void {
196
- for (const listener of this.listeners) listener(event);
344
+ for (const listener of this.listeners) {
345
+ try {
346
+ listener(event);
347
+ } catch {
348
+ // A disconnected/failed UI observer must not break browser control or
349
+ // prevent the remaining observers from receiving the event.
350
+ }
351
+ }
352
+ }
353
+
354
+ private scheduleReconnect(): void {
355
+ if (this.disposed || !this.listeners.size || this.reconnectTimer) return;
356
+ const delay = Math.min(10_000, 250 * 2 ** this.reconnectAttempt++);
357
+ this.reconnectTimer = setTimeout(() => {
358
+ this.reconnectTimer = null;
359
+ void this.connect().catch(() => this.scheduleReconnect());
360
+ }, delay);
197
361
  }
198
362
  private onMessage(data: unknown): void {
199
363
  try {
200
- const text = typeof data === 'string' ? data : Buffer.from(data as ArrayBuffer).toString('utf8');
364
+ const text =
365
+ typeof data === 'string'
366
+ ? data
367
+ : Buffer.from(data as ArrayBuffer).toString('utf8');
201
368
  const event = JSON.parse(text) as BrowserStreamEvent;
202
- if (event.type === 'url' && typeof event.url === 'string') this.currentUrl = event.url;
369
+ if (event.type === 'url' && typeof event.url === 'string')
370
+ this.currentUrl = event.url;
203
371
  if (event.type === 'status') this.status = { ...this.status, ...event };
204
372
  this.emit(event);
205
373
  } catch (error) {
206
- this.emit({ type: 'error', message: error instanceof Error ? error.message : String(error) });
374
+ this.emit({
375
+ type: 'error',
376
+ message: error instanceof Error ? error.message : String(error),
377
+ });
207
378
  }
208
379
  }
209
380
  }
@@ -211,6 +382,9 @@ class SessionBrowserStream implements BrowserStream {
211
382
  const streams = new Map<string, SessionBrowserStream>();
212
383
  export function getBrowserStream(sessionName = 'minimal-agent'): BrowserStream {
213
384
  let stream = streams.get(sessionName);
214
- if (!stream) { stream = new SessionBrowserStream(sessionName); streams.set(sessionName, stream); }
385
+ if (!stream) {
386
+ stream = new SessionBrowserStream(sessionName);
387
+ streams.set(sessionName, stream);
388
+ }
215
389
  return stream;
216
390
  }
@@ -1,5 +1,5 @@
1
- import { browserService } from './browserService.js';
2
1
  import { browserRunRegistry, } from './browserRunRegistry.js';
2
+ import { browserService } from './browserService.js';
3
3
  export function parseTabList(text) {
4
4
  try {
5
5
  const parsed = JSON.parse(text);
@@ -11,13 +11,17 @@ export function parseTabList(text) {
11
11
  : Number.isInteger(tab.index)
12
12
  ? String(tab.index)
13
13
  : '';
14
- return id ? [{
15
- id,
16
- active: Boolean(tab.active),
17
- ...(typeof tab.url === 'string' ? { url: tab.url } : {}),
18
- ...(typeof tab.title === 'string' ? { title: tab.title } : {}),
19
- ...(typeof tab.type === 'string' ? { type: tab.type } : {}),
20
- }] : [];
14
+ return id
15
+ ? [
16
+ {
17
+ id,
18
+ active: Boolean(tab.active),
19
+ ...(typeof tab.url === 'string' ? { url: tab.url } : {}),
20
+ ...(typeof tab.title === 'string' ? { title: tab.title } : {}),
21
+ ...(typeof tab.type === 'string' ? { type: tab.type } : {}),
22
+ },
23
+ ]
24
+ : [];
21
25
  });
22
26
  }
23
27
  catch {
@@ -40,7 +44,9 @@ function parseListedTabs(result) {
40
44
  let reportedCount = 0;
41
45
  try {
42
46
  const parsed = JSON.parse(result.stdout);
43
- reportedCount = Array.isArray(parsed.data?.tabs) ? parsed.data.tabs.length : 0;
47
+ reportedCount = Array.isArray(parsed.data?.tabs)
48
+ ? parsed.data.tabs.length
49
+ : 0;
44
50
  }
45
51
  catch {
46
52
  throw new BrowserTabError('browser_protocol_mismatch', '浏览器标签列表不是有效 JSON');
@@ -108,22 +114,30 @@ export async function ensureConversationTab(input) {
108
114
  tabId = claimed.find((candidate) => tabs.some((tab) => tab.id === candidate));
109
115
  }
110
116
  if (!tabId) {
111
- const hasClaimedTabs = browserRunRegistry.claimedTabs(input.context.conversationKey).length > 0;
117
+ const hasClaimedTabs = browserRunRegistry.claimedTabs(input.context.conversationKey).length >
118
+ 0;
112
119
  const reusableBlank = !hasClaimedTabs
113
- ? tabs.find((tab) => tab.url === 'about:blank' && browserRunRegistry.ownerOf(tab.id) === undefined)
120
+ ? tabs.find((tab) => tab.url === 'about:blank' &&
121
+ browserRunRegistry.ownerOf(tab.id) === undefined)
114
122
  : undefined;
115
123
  if (reusableBlank) {
116
124
  tabId = reusableBlank.id;
117
125
  }
118
126
  else {
119
127
  const beforeIds = new Set(tabs.map((tab) => tab.id));
120
- const created = await run([...input.globals, 'tab', 'new', 'about:blank']);
128
+ const created = await run([
129
+ ...input.globals,
130
+ 'tab',
131
+ 'new',
132
+ 'about:blank',
133
+ ]);
121
134
  if (created.code !== 0) {
122
135
  throw new BrowserTabError('tab_bootstrap_failed', created.stderr || created.stdout || '无法创建会话浏览器标签');
123
136
  }
124
137
  const after = parseListedTabs(await run([...input.globals, 'tab', 'list', '--json']));
125
138
  const added = after.filter((tab) => !beforeIds.has(tab.id));
126
- tabId = (added.find((candidate) => candidate.active) ?? added.at(-1))?.id;
139
+ tabId = (added.find((candidate) => candidate.active) ?? added.at(-1))
140
+ ?.id;
127
141
  if (!tabId) {
128
142
  throw new BrowserTabError('tab_bootstrap_failed', '新标签创建成功,但 Runtime 未返回其标签 ID');
129
143
  }
@@ -139,5 +153,24 @@ export async function ensureConversationTab(input) {
139
153
  return tabId;
140
154
  });
141
155
  }
142
- /** Compatibility alias for callers compiled against the previous helper name. */
143
- export const claimConversationTab = ensureConversationTab;
156
+ export async function claimConversationTabById(input, tabId) {
157
+ return browserService.exclusive({
158
+ sessionName: input.sessionName,
159
+ bin: input.bin,
160
+ runner: input.runner,
161
+ signal: input.signal,
162
+ }, async (run) => {
163
+ const tabs = parseListedTabs(await run([...input.globals, 'tab', 'list', '--json']));
164
+ if (!tabs.some((tab) => tab.id === tabId)) {
165
+ throw new BrowserTabError('tab_not_found', `浏览器标签不存在:${tabId}`);
166
+ }
167
+ try {
168
+ browserRunRegistry.claimTab(input.context, tabId);
169
+ }
170
+ catch (error) {
171
+ throw new BrowserTabError('tab_owned_by_other_conversation', error instanceof Error ? error.message : String(error));
172
+ }
173
+ assertSwitched(await run([...input.globals, 'tab', tabId]));
174
+ return tabId;
175
+ });
176
+ }