minimal-agent 0.12.0 → 0.14.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 (472) hide show
  1. package/README.md +6 -5
  2. package/package.json +62 -5
  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 +204 -185
  16. package/plugins/workflow-runner/src/index.ts +249 -224
  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 +404 -467
  28. package/plugins/workflow-runner/src/runner.ts +491 -535
  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 +172 -152
  54. package/plugins/workflow-runner/src/taskIdentity.ts +233 -200
  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 -105
  58. package/plugins/workflow-runner/src/types.ts +155 -520
  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 +542 -469
  68. package/plugins/workflow-runner/src/workflowState.ts +639 -589
  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/skill-creator/scripts/run_eval.py +3 -2
  92. package/skills/ui-design/SKILL.md +5 -2
  93. package/skills/ui-design/references/layout-composition.md +1 -1
  94. package/skills/workflow-creator/SKILL.md +344 -0
  95. package/skills/workflow-creator/assets/template/workflow.mjs +48 -0
  96. package/skills/workflow-creator/references/api.md +216 -0
  97. package/skills/workflow-creator/references/migration.md +103 -0
  98. package/skills/workflow-creator/references/patterns.md +779 -0
  99. package/skills/workflow-creator/scripts/list-resources.mjs +205 -0
  100. package/skills/workflow-creator/scripts/scaffold.mjs +148 -0
  101. package/skills/workflow-creator/scripts/validate.mjs +275 -0
  102. package/skills/workflow-creator/scripts/workflow-creator.test.mjs +82 -0
  103. package/src/advisor/advisorCoordinator.js +503 -0
  104. package/src/advisor/advisorCoordinator.ts +657 -0
  105. package/src/cli/configMenu.tsx +0 -1
  106. package/src/cli/print.js +44 -6
  107. package/src/cli/print.ts +73 -4
  108. package/src/cli/streamJson.js +5 -6
  109. package/src/cli/streamJson.ts +8 -4
  110. package/src/cli/wizards/advisorWizard.js +4 -2
  111. package/src/cli/wizards/advisorWizard.tsx +8 -2
  112. package/src/cli/wizards/contextAdvisorWizard.js +5 -4
  113. package/src/cli/wizards/contextAdvisorWizard.tsx +7 -6
  114. package/src/collaboration/taskFlow.js +115 -0
  115. package/src/collaboration/taskFlow.ts +169 -0
  116. package/src/config/configDefaults.js +41 -1
  117. package/src/config/configDefaults.ts +43 -1
  118. package/src/config/configDiagnostics.ts +2 -2
  119. package/src/config/configFile.js +40 -9
  120. package/src/config/configFile.ts +60 -11
  121. package/src/config/configService.js +443 -74
  122. package/src/config/configService.ts +723 -142
  123. package/src/config/numericLimits.js +22 -0
  124. package/src/config/numericLimits.ts +24 -0
  125. package/src/config.js +1 -0
  126. package/src/config.ts +3 -2
  127. package/src/context/budgetPlan.js +1 -1
  128. package/src/context/budgetPlan.ts +1 -1
  129. package/src/context/compact.js +7 -2
  130. package/src/context/compact.ts +9 -2
  131. package/src/context/microCompactLite.js +212 -13
  132. package/src/context/microCompactLite.ts +261 -12
  133. package/src/context/sessionRegistry.js +8 -1
  134. package/src/context/sessionRegistry.ts +18 -5
  135. package/src/context/toolResultArchive.js +72 -0
  136. package/src/context/toolResultArchive.ts +95 -0
  137. package/src/goal/errors.js +8 -0
  138. package/src/goal/errors.ts +18 -0
  139. package/src/goal/goalRuntime.js +344 -0
  140. package/src/goal/goalRuntime.ts +466 -0
  141. package/src/goal/goalStore.js +200 -0
  142. package/src/goal/goalStore.ts +219 -0
  143. package/src/goal/index.js +4 -0
  144. package/src/goal/index.ts +4 -0
  145. package/src/goal/statusMapping.js +71 -0
  146. package/src/goal/statusMapping.ts +95 -0
  147. package/src/goal/types.js +7 -0
  148. package/src/goal/types.ts +179 -0
  149. package/src/goal/workflowController.js +306 -0
  150. package/src/goal/workflowController.ts +360 -0
  151. package/src/harness/evidenceLedger.js +2 -0
  152. package/src/harness/evidenceLedger.ts +1 -0
  153. package/src/harness/stallGuard.js +9 -3
  154. package/src/harness/stallGuard.ts +7 -3
  155. package/src/images/imageResolver.js +161 -0
  156. package/src/images/imageResolver.ts +189 -0
  157. package/src/infra/verification.js +56 -20
  158. package/src/infra/verification.ts +87 -20
  159. package/src/llm/client.js +79 -21
  160. package/src/llm/client.ts +182 -35
  161. package/src/llm/gatewayClient.js +201 -0
  162. package/src/llm/gatewayClient.ts +299 -0
  163. package/src/llm/messageProvenance.js +46 -0
  164. package/src/llm/messageProvenance.ts +58 -0
  165. package/src/llm/modelProvider.js +1 -0
  166. package/src/llm/modelProvider.ts +22 -0
  167. package/src/llm/providers/anthropicFormat.js +108 -1
  168. package/src/llm/providers/anthropicFormat.ts +115 -4
  169. package/src/llm/providers/openaiFormat.js +9 -0
  170. package/src/llm/providers/openaiFormat.ts +12 -3
  171. package/src/loop.js +319 -54
  172. package/src/loop.ts +373 -57
  173. package/src/main.js +4 -1
  174. package/src/main.tsx +4 -1
  175. package/src/managedExecution/index.js +2 -0
  176. package/src/managedExecution/index.ts +2 -0
  177. package/src/managedExecution/registry.js +15 -0
  178. package/src/managedExecution/registry.ts +20 -0
  179. package/src/managedExecution/types.js +1 -0
  180. package/src/managedExecution/types.ts +86 -0
  181. package/src/modelRef.js +9 -0
  182. package/src/modelRef.ts +31 -0
  183. package/src/multimodal.js +14 -28
  184. package/src/multimodal.ts +17 -33
  185. package/src/net/lanDiscovery.js +65 -0
  186. package/src/net/lanDiscovery.ts +82 -0
  187. package/src/plugin-sdk.js +28 -3
  188. package/src/plugin-sdk.ts +39 -6
  189. package/src/plugins/pluginApi.ts +16 -1
  190. package/src/plugins/pluginLoader.js +4 -0
  191. package/src/plugins/pluginLoader.ts +6 -0
  192. package/src/plugins/pluginRunner.js +152 -9
  193. package/src/plugins/pluginRunner.ts +186 -8
  194. package/src/plugins/slashFallback.js +113 -0
  195. package/src/plugins/slashFallback.ts +137 -0
  196. package/src/prompts/policyRegistry.js +15 -8
  197. package/src/prompts/policyRegistry.ts +18 -8
  198. package/src/prompts/promptAssembly.js +103 -12
  199. package/src/prompts/promptAssembly.ts +114 -12
  200. package/src/prompts/skillList.js +21 -3
  201. package/src/prompts/skillList.ts +27 -2
  202. package/src/prompts/stableSystemPrompt.js +18 -0
  203. package/src/prompts/stableSystemPrompt.ts +33 -0
  204. package/src/runtime/agentRuntimeContext.js +8 -2
  205. package/src/runtime/agentRuntimeContext.ts +17 -4
  206. package/src/session/runAgentTurn.js +78 -12
  207. package/src/session/runAgentTurn.ts +105 -23
  208. package/src/session/runTurn.js +10 -9
  209. package/src/session/runTurn.ts +17 -8
  210. package/src/session/sessionState.ts +2 -0
  211. package/src/team/auth.js +186 -0
  212. package/src/team/auth.ts +298 -0
  213. package/src/team/cli.js +105 -0
  214. package/src/team/cli.ts +122 -0
  215. package/src/team/onlineToolContract.js +64 -0
  216. package/src/team/onlineToolContract.ts +109 -0
  217. package/src/team/toolPolicy.js +36 -0
  218. package/src/team/toolPolicy.ts +75 -0
  219. package/src/tools/advisor/advisor.js +148 -37
  220. package/src/tools/advisor/advisor.ts +161 -38
  221. package/src/tools/advisor/advisorDecision.js +71 -0
  222. package/src/tools/advisor/advisorDecision.ts +85 -0
  223. package/src/tools/agent/agent.js +18 -5
  224. package/src/tools/agent/agent.ts +21 -7
  225. package/src/tools/agent/agentControl.js +246 -0
  226. package/src/tools/agent/agentControl.ts +284 -0
  227. package/src/tools/agent/agentTaskService.js +40 -1
  228. package/src/tools/agent/agentTaskService.ts +44 -1
  229. package/src/tools/agent/agentTypes.js +14 -2
  230. package/src/tools/agent/agentTypes.ts +15 -2
  231. package/src/tools/applypatch/applyPatch.js +362 -0
  232. package/src/tools/applypatch/applyPatch.ts +428 -0
  233. package/src/tools/bash/bash.js +70 -18
  234. package/src/tools/bash/bash.ts +75 -20
  235. package/src/tools/capabilities.js +10 -5
  236. package/src/tools/capabilities.ts +10 -5
  237. package/src/tools/computeruse/computerIntent.js +32 -0
  238. package/src/tools/computeruse/computerIntent.ts +46 -0
  239. package/src/tools/computeruse/telemetryLog.js +12 -0
  240. package/src/tools/computeruse/telemetryLog.ts +16 -0
  241. package/src/tools/computeruse/vision/telemetry.js +1 -0
  242. package/src/tools/computeruse/vision/telemetry.ts +1 -0
  243. package/src/tools/effectiveToolSet.js +4 -0
  244. package/src/tools/effectiveToolSet.ts +4 -0
  245. package/src/tools/index.js +21 -2
  246. package/src/tools/index.ts +33 -2
  247. package/src/tools/powershell/powershell.js +18 -1
  248. package/src/tools/powershell/powershell.ts +18 -2
  249. package/src/tools/presentresult/presentresult.js +6 -15
  250. package/src/tools/presentresult/presentresult.ts +6 -15
  251. package/src/tools/read/read.js +69 -11
  252. package/src/tools/read/read.ts +70 -11
  253. package/src/tools/shared/fileUtils.js +1 -2
  254. package/src/tools/shared/fileUtils.ts +1 -2
  255. package/src/tools/shared/permanentDeleteGuard.js +34 -3
  256. package/src/tools/shared/permanentDeleteGuard.ts +43 -6
  257. package/src/tools/shared/toolOutputStore.js +23 -1
  258. package/src/tools/shared/toolOutputStore.ts +22 -1
  259. package/src/tools/skill/skill.js +9 -3
  260. package/src/tools/skill/skill.ts +8 -4
  261. package/src/tools/toolPromptGuides.js +117 -0
  262. package/src/tools/toolPromptGuides.ts +137 -0
  263. package/src/tools/webbrowser/agentBrowserPath.js +19 -9
  264. package/src/tools/webbrowser/agentBrowserPath.ts +70 -28
  265. package/src/tools/webbrowser/browser.js +27 -11
  266. package/src/tools/webbrowser/browser.ts +68 -24
  267. package/src/tools/webbrowser/browserAutomation.js +329 -0
  268. package/src/tools/webbrowser/browserAutomation.ts +467 -0
  269. package/src/tools/webbrowser/browserAxState.js +97 -0
  270. package/src/tools/webbrowser/browserAxState.ts +142 -0
  271. package/src/tools/webbrowser/browserBatch.js +1578 -0
  272. package/src/tools/webbrowser/browserBatch.ts +2382 -0
  273. package/src/tools/webbrowser/browserCdp.js +208 -0
  274. package/src/tools/webbrowser/browserCdp.ts +255 -0
  275. package/src/tools/webbrowser/browserConditions.js +24 -0
  276. package/src/tools/webbrowser/browserConditions.ts +45 -0
  277. package/src/tools/webbrowser/browserContent.js +281 -0
  278. package/src/tools/webbrowser/browserContent.ts +438 -0
  279. package/src/tools/webbrowser/browserControl.js +131 -30
  280. package/src/tools/webbrowser/browserControl.ts +210 -50
  281. package/src/tools/webbrowser/browserDaemon.js +22 -14
  282. package/src/tools/webbrowser/browserDaemon.ts +54 -21
  283. package/src/tools/webbrowser/browserFrames.js +47 -0
  284. package/src/tools/webbrowser/browserFrames.ts +54 -0
  285. package/src/tools/webbrowser/browserInteractionResolver.js +17 -0
  286. package/src/tools/webbrowser/browserInteractionResolver.ts +40 -0
  287. package/src/tools/webbrowser/browserLocator.js +140 -0
  288. package/src/tools/webbrowser/browserLocator.ts +194 -0
  289. package/src/tools/webbrowser/browserOutcome.js +10 -17
  290. package/src/tools/webbrowser/browserOutcome.ts +48 -31
  291. package/src/tools/webbrowser/browserRecovery.js +58 -0
  292. package/src/tools/webbrowser/browserRecovery.ts +83 -0
  293. package/src/tools/webbrowser/browserRunRegistry.js +35 -3
  294. package/src/tools/webbrowser/browserRunRegistry.ts +91 -15
  295. package/src/tools/webbrowser/browserService.js +28 -2
  296. package/src/tools/webbrowser/browserService.ts +49 -9
  297. package/src/tools/webbrowser/browserStream.js +132 -33
  298. package/src/tools/webbrowser/browserStream.ts +224 -50
  299. package/src/tools/webbrowser/browserTabs.js +48 -15
  300. package/src/tools/webbrowser/browserTabs.ts +178 -96
  301. package/src/tools/webbrowser/webbrowser.js +683 -144
  302. package/src/tools/webbrowser/webbrowser.ts +979 -236
  303. package/src/tools/webfetch/preapproved.js +0 -2
  304. package/src/tools/webfetch/preapproved.ts +0 -2
  305. package/src/tools/websearch/websearch.js +129 -8
  306. package/src/tools/websearch/websearch.ts +138 -6
  307. package/src/types.ts +450 -42
  308. package/src/ui/App.js +377 -58
  309. package/src/ui/App.tsx +576 -111
  310. package/src/ui/LiveArea.js +14 -8
  311. package/src/ui/LiveArea.tsx +14 -10
  312. package/src/ui/MessageList.js +63 -20
  313. package/src/ui/MessageList.tsx +101 -16
  314. package/src/ui/ModelPicker.js +7 -4
  315. package/src/ui/ModelPicker.tsx +55 -8
  316. package/src/ui/hooks/useChat.js +152 -163
  317. package/src/ui/hooks/useChat.ts +396 -334
  318. package/src/ui/loginCommand.js +56 -0
  319. package/src/ui/loginCommand.ts +63 -0
  320. package/src/ui/toolProgress.js +41 -0
  321. package/src/ui/toolProgress.ts +44 -0
  322. package/src/web/browserBridge.js +20 -2
  323. package/src/web/browserBridge.ts +20 -2
  324. package/src/web/protocol.ts +1897 -194
  325. package/workflows/adaptive-research/workflow.mjs +86 -0
  326. package/workflows/e2e-capabilities/workflow.mjs +102 -0
  327. package/workflows/e2e-llm/workflow.mjs +52 -0
  328. package/workflows/e2e-smoke/workflow.mjs +59 -0
  329. package/workflows/e2e-vision-schema/README.md +48 -0
  330. package/workflows/e2e-vision-schema/workflow.mjs +149 -0
  331. package/workflows/e2e-write-greet/workflow.mjs +37 -0
  332. package/workflows/file-census/README.md +14 -0
  333. package/workflows/file-census/scripts/.gitkeep +2 -0
  334. package/workflows/file-census/workflow.mjs +110 -0
  335. package/workflows/goal/README.md +166 -0
  336. package/workflows/goal/prompts/audit.md +57 -0
  337. package/workflows/goal/prompts/contract.md +56 -0
  338. package/workflows/goal/prompts/iterate.md +37 -0
  339. package/workflows/goal/workflow.mjs +501 -0
  340. package/workflows/illustrate/README.md +90 -0
  341. package/workflows/illustrate/assets/engines.json +20 -0
  342. package/workflows/illustrate/assets/extract-baidu.js +21 -0
  343. package/workflows/illustrate/assets/extract-bing.js +33 -0
  344. package/workflows/illustrate/assets/extract-google.js +31 -0
  345. package/workflows/illustrate/workflow.mjs +301 -0
  346. package/workflows/plan/workflow.mjs +389 -0
  347. package/workflows/question-crops/README.md +35 -0
  348. package/workflows/question-crops/prompts/inventory.md +23 -0
  349. package/workflows/question-crops/scripts/image-ops.mjs +305 -0
  350. package/workflows/question-crops/scripts/image-ops.test.mjs +95 -0
  351. package/workflows/question-crops/workflow.mjs +172 -0
  352. package/workflows/ralph-loop/workflow.mjs +162 -0
  353. package/workflows/research/DESIGN.md +449 -0
  354. package/workflows/research/README.md +74 -0
  355. package/workflows/research/prompts/s0-goal.md +43 -0
  356. package/workflows/research/prompts/s1-early-exit.md +22 -0
  357. package/workflows/research/prompts/s1-map.md +58 -0
  358. package/workflows/research/prompts/s2-options.md +53 -0
  359. package/workflows/research/prompts/s3-deep-dive.md +56 -0
  360. package/workflows/research/prompts/s4-verify.md +74 -0
  361. package/workflows/research/prompts/s5-synthesis.md +81 -0
  362. package/workflows/research/prompts/s5b-fill-gaps.md +32 -0
  363. package/workflows/research/prompts/s6-package.md +32 -0
  364. package/workflows/research/scripts/build-report.mjs +98 -0
  365. package/workflows/research/workflow.mjs +288 -0
  366. package/workflows/wechat-reading-shots/prompts/collect-params.md +16 -0
  367. package/workflows/wechat-reading-shots/prompts/evaluate.md +20 -0
  368. package/workflows/wechat-reading-shots/prompts/open-book.md +28 -0
  369. package/workflows/wechat-reading-shots/prompts/read-page.md +13 -0
  370. package/workflows/wechat-reading-shots/prompts/turn-batch.md +24 -0
  371. package/workflows/wechat-reading-shots/test/control-flow.test.ts +329 -0
  372. package/workflows/wechat-reading-shots/workflow.mjs +266 -0
  373. package/workflows/wrong-question-docx/README.md +55 -0
  374. package/workflows/wrong-question-docx/prompts/figure-qa.md +8 -0
  375. package/workflows/wrong-question-docx/prompts/transcribe.md +25 -0
  376. package/workflows/wrong-question-docx/scripts/workbook.mjs +857 -0
  377. package/workflows/wrong-question-docx/test/control-flow.test.ts +165 -0
  378. package/workflows/wrong-question-docx/test/workbook.test.mjs +303 -0
  379. package/workflows/wrong-question-docx/workflow.mjs +485 -0
  380. package/plugins/workflow-runner/src/agentCommon.js +0 -354
  381. package/plugins/workflow-runner/src/agentCommon.ts +0 -435
  382. package/plugins/workflow-runner/src/controlFlow/branch.js +0 -40
  383. package/plugins/workflow-runner/src/controlFlow/branch.ts +0 -46
  384. package/plugins/workflow-runner/src/controlFlow/loop.js +0 -211
  385. package/plugins/workflow-runner/src/controlFlow/loop.ts +0 -248
  386. package/plugins/workflow-runner/src/controlFlow/pause.js +0 -129
  387. package/plugins/workflow-runner/src/controlFlow/pause.ts +0 -141
  388. package/plugins/workflow-runner/src/controlFlow/signal.js +0 -21
  389. package/plugins/workflow-runner/src/controlFlow/signal.ts +0 -29
  390. package/plugins/workflow-runner/src/controlFlow/types.js +0 -18
  391. package/plugins/workflow-runner/src/controlFlow/types.ts +0 -63
  392. package/plugins/workflow-runner/src/dslManifest.js +0 -72
  393. package/plugins/workflow-runner/src/dslManifest.ts +0 -127
  394. package/plugins/workflow-runner/src/expressions.js +0 -618
  395. package/plugins/workflow-runner/src/expressions.ts +0 -622
  396. package/plugins/workflow-runner/src/loader.js +0 -573
  397. package/plugins/workflow-runner/src/loader.ts +0 -721
  398. package/plugins/workflow-runner/src/multimodal.js +0 -38
  399. package/plugins/workflow-runner/src/multimodal.ts +0 -64
  400. package/plugins/workflow-runner/src/recovery.js +0 -119
  401. package/plugins/workflow-runner/src/recovery.ts +0 -149
  402. package/plugins/workflow-runner/src/stepExecutors/agent.js +0 -173
  403. package/plugins/workflow-runner/src/stepExecutors/agent.ts +0 -234
  404. package/plugins/workflow-runner/src/stepExecutors/assert.js +0 -41
  405. package/plugins/workflow-runner/src/stepExecutors/assert.ts +0 -50
  406. package/plugins/workflow-runner/src/stepExecutors/echo.js +0 -31
  407. package/plugins/workflow-runner/src/stepExecutors/echo.ts +0 -38
  408. package/plugins/workflow-runner/src/stepExecutors/llm.js +0 -99
  409. package/plugins/workflow-runner/src/stepExecutors/llm.ts +0 -133
  410. package/plugins/workflow-runner/src/stepExecutors/set.js +0 -49
  411. package/plugins/workflow-runner/src/stepExecutors/set.ts +0 -56
  412. package/plugins/workflow-runner/src/stepExecutors/skill.js +0 -111
  413. package/plugins/workflow-runner/src/stepExecutors/skill.ts +0 -140
  414. package/plugins/workflow-runner/src/stepExecutors/tool.js +0 -208
  415. package/plugins/workflow-runner/src/stepExecutors/tool.ts +0 -256
  416. package/plugins/workflow-runner/src/stepExecutors/verify.js +0 -58
  417. package/plugins/workflow-runner/src/stepExecutors/verify.ts +0 -68
  418. package/plugins/workflow-runner/src/stepPipeline.js +0 -277
  419. package/plugins/workflow-runner/src/stepPipeline.ts +0 -366
  420. package/plugins/workflow-runner/test/agent.test.ts +0 -587
  421. package/plugins/workflow-runner/test/agentLlmError.test.ts +0 -373
  422. package/plugins/workflow-runner/test/bashBlacklist.sweep.test.ts +0 -65
  423. package/plugins/workflow-runner/test/captureMisbind.test.ts +0 -99
  424. package/plugins/workflow-runner/test/cli.e2e.test.ts +0 -147
  425. package/plugins/workflow-runner/test/context-files.test.ts +0 -320
  426. package/plugins/workflow-runner/test/e2e.test.ts +0 -370
  427. package/plugins/workflow-runner/test/engineRobustness.test.ts +0 -226
  428. package/plugins/workflow-runner/test/expressions.test.ts +0 -397
  429. package/plugins/workflow-runner/test/foundation.test.ts +0 -126
  430. package/plugins/workflow-runner/test/graceful.test.ts +0 -139
  431. package/plugins/workflow-runner/test/greedyInputs.load.test.ts +0 -47
  432. package/plugins/workflow-runner/test/hostCapability.test.ts +0 -108
  433. package/plugins/workflow-runner/test/illustrate.load.test.ts +0 -183
  434. package/plugins/workflow-runner/test/jsonPayload.test.ts +0 -83
  435. package/plugins/workflow-runner/test/loader.test.ts +0 -617
  436. package/plugins/workflow-runner/test/maxTurnsRetryDelay.test.ts +0 -33
  437. package/plugins/workflow-runner/test/multimodal.test.ts +0 -342
  438. package/plugins/workflow-runner/test/output-schema.test.ts +0 -213
  439. package/plugins/workflow-runner/test/parseWorkflowArgs.test.ts +0 -87
  440. package/plugins/workflow-runner/test/pluginRunner.isolation.test.ts +0 -269
  441. package/plugins/workflow-runner/test/ppt.load.test.ts +0 -1220
  442. package/plugins/workflow-runner/test/ralphLoop.e2e.test.ts +0 -220
  443. package/plugins/workflow-runner/test/recovery.test.ts +0 -265
  444. package/plugins/workflow-runner/test/runner.test.ts +0 -911
  445. package/plugins/workflow-runner/test/runnerPreflight.test.ts +0 -379
  446. package/plugins/workflow-runner/test/skillTurnDone.test.ts +0 -71
  447. package/plugins/workflow-runner/test/stateLifecycle.test.ts +0 -150
  448. package/plugins/workflow-runner/test/stepPipeline.test.ts +0 -114
  449. package/plugins/workflow-runner/test/taskArbitration.test.ts +0 -338
  450. package/plugins/workflow-runner/test/taskLifecycle.test.ts +0 -270
  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 -199
  468. package/workflows/schema.json +0 -176
  469. package/workflows/webppt.yaml +0 -496
  470. package/workflows/wechat-reading-shots.yaml +0 -315
  471. package/workflows/word.yaml +0 -720
  472. package/workflows/youtube-shorts.yaml +0 -202
@@ -0,0 +1,54 @@
1
+ export type BrowserFrameInfo = {
2
+ id: string;
3
+ parentId?: string;
4
+ url: string;
5
+ name?: string;
6
+ };
7
+
8
+ /** Fixed, read-only expression for observing nested same-origin frame trees. */
9
+ export const FRAME_INFO_EXPRESSION = `(() => { const walk = (doc, parentId = '', path = '') => Array.from(doc.querySelectorAll('iframe,frame')).flatMap((el, index) => { const id = 'dom-frame-' + (path ? path + '-' : '') + index; const item = { id, ...(parentId ? { parentId } : {}), url: el.src || '', name: el.name || undefined }; try { return [item, ...walk(el.contentDocument, id, id.replace('dom-frame-', ''))]; } catch { return [item]; } }); return walk(document); })()`;
10
+
11
+ /** Normalize the recursive, browser-owned frame tree returned by CDP. */
12
+ export function normalizeFrameTree(value: unknown): BrowserFrameInfo[] {
13
+ const frames: BrowserFrameInfo[] = [];
14
+ const walk = (node: unknown, parentId?: string): void => {
15
+ if (!node || typeof node !== 'object') return;
16
+ const item = node as {
17
+ frame?: { id?: unknown; url?: unknown; name?: unknown };
18
+ childFrames?: unknown[];
19
+ };
20
+ if (typeof item.frame?.id !== 'string' || !item.frame.id) return;
21
+ const id = item.frame.id;
22
+ frames.push({
23
+ id,
24
+ ...(parentId ? { parentId } : {}),
25
+ url: typeof item.frame.url === 'string' ? item.frame.url : '',
26
+ ...(typeof item.frame.name === 'string' && item.frame.name
27
+ ? { name: item.frame.name }
28
+ : {}),
29
+ });
30
+ for (const child of item.childFrames ?? []) walk(child, id);
31
+ };
32
+ walk(value);
33
+ return frames;
34
+ }
35
+
36
+ export function normalizeFrameInfo(value: unknown): BrowserFrameInfo[] {
37
+ if (!Array.isArray(value)) return [];
38
+ return value.flatMap((item) => {
39
+ if (!item || typeof item !== 'object') return [];
40
+ const frame = item as Record<string, unknown>;
41
+ if (typeof frame.id !== 'string' || typeof frame.url !== 'string')
42
+ return [];
43
+ return [
44
+ {
45
+ id: frame.id,
46
+ url: frame.url,
47
+ ...(typeof frame.parentId === 'string'
48
+ ? { parentId: frame.parentId }
49
+ : {}),
50
+ ...(typeof frame.name === 'string' ? { name: frame.name } : {}),
51
+ },
52
+ ];
53
+ });
54
+ }
@@ -0,0 +1,17 @@
1
+ export function resolveInteractionStrategy(target) {
2
+ if (target.locator?.by === 'ax')
3
+ return 'ax';
4
+ if (target.locator?.by === 'role' ||
5
+ target.locator?.by === 'label' ||
6
+ target.locator?.by === 'text' ||
7
+ target.locator?.by === 'placeholder' ||
8
+ target.locator?.by === 'testid')
9
+ return 'role-locator';
10
+ if (target.locator || target.selector)
11
+ return 'playwright-locator';
12
+ if (target.node_id !== undefined)
13
+ return 'dom-cua';
14
+ if (target.x !== undefined && target.y !== undefined)
15
+ return 'visual-coordinate';
16
+ return 'cdp';
17
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Deterministic interaction strategy selection shared by batch results and
3
+ * future adapters. MCP/WebMCP is intentionally absent: this project uses the
4
+ * visible supervised browser and falls back through its strongest local
5
+ * representation.
6
+ */
7
+ export type BrowserInteractionStrategy =
8
+ | 'ax'
9
+ | 'role-locator'
10
+ | 'playwright-locator'
11
+ | 'dom-cua'
12
+ | 'visual-coordinate'
13
+ | 'cdp';
14
+
15
+ export type BrowserInteractionTarget = {
16
+ locator?: { by?: string };
17
+ selector?: string;
18
+ node_id?: number;
19
+ x?: number;
20
+ y?: number;
21
+ };
22
+
23
+ export function resolveInteractionStrategy(
24
+ target: BrowserInteractionTarget,
25
+ ): BrowserInteractionStrategy {
26
+ if (target.locator?.by === 'ax') return 'ax';
27
+ if (
28
+ target.locator?.by === 'role' ||
29
+ target.locator?.by === 'label' ||
30
+ target.locator?.by === 'text' ||
31
+ target.locator?.by === 'placeholder' ||
32
+ target.locator?.by === 'testid'
33
+ )
34
+ return 'role-locator';
35
+ if (target.locator || target.selector) return 'playwright-locator';
36
+ if (target.node_id !== undefined) return 'dom-cua';
37
+ if (target.x !== undefined && target.y !== undefined)
38
+ return 'visual-coordinate';
39
+ return 'cdp';
40
+ }
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Browser locators shared by BrowserBatch and future visible-DOM adapters.
3
+ *
4
+ * This deliberately emits a small, self-contained browser expression instead
5
+ * of retaining DOM node handles. A locator is resolved again for every step,
6
+ * so a navigation or React re-render cannot silently reuse a stale element.
7
+ */
8
+ const quote = (value) => JSON.stringify(value);
9
+ /** Build an expression returning `Element[]` in the selected document. */
10
+ export function buildLocatorExpression(locator, selector, rootExpression = 'document') {
11
+ if (selector) {
12
+ return `Array.from(${rootExpression}.querySelectorAll(${quote(selector)}))`;
13
+ }
14
+ if (!locator)
15
+ throw new Error('step requires selector or locator');
16
+ if (locator.by === 'ax') {
17
+ throw new Error('AX locator must be resolved against the live accessibility tree first');
18
+ }
19
+ const root = locator.within
20
+ ? `${buildLocatorExpression(locator.within, undefined, rootExpression)}.flatMap((scope) => Array.from(scope.querySelectorAll('*')))`
21
+ : `Array.from(${rootExpression}.querySelectorAll('*'))`;
22
+ const value = quote(locator.value);
23
+ const exact = locator.exact === true;
24
+ const compare = (expression, expected = value) => exact
25
+ ? `${expression}.trim()===${expected}`
26
+ : `${expression}.includes(${expected})`;
27
+ let predicate;
28
+ switch (locator.by) {
29
+ case 'css':
30
+ return applyFilters(`Array.from(${rootExpression}.querySelectorAll(${value}))`, locator);
31
+ case 'role': {
32
+ const name = locator.name ? quote(locator.name) : value;
33
+ const nameCompare = locator.name
34
+ ? `(function(name){return ${exact ? `name.trim()===${name}` : `name.includes(${name})`};})(__name)`
35
+ : 'true';
36
+ predicate = `(__role===${value}&&${nameCompare})`;
37
+ break;
38
+ }
39
+ case 'label':
40
+ predicate = `Array.from(__el.labels||[]).some((label)=>${compare("(label.textContent||'')")})`;
41
+ break;
42
+ case 'placeholder':
43
+ predicate = compare(`__el.getAttribute('placeholder')||''`);
44
+ break;
45
+ case 'alt':
46
+ predicate = compare(`__el.getAttribute('alt')||''`);
47
+ break;
48
+ case 'title':
49
+ predicate = compare(`__el.getAttribute('title')||''`);
50
+ break;
51
+ case 'testid':
52
+ predicate = compare(`__el.getAttribute('data-testid')||''`);
53
+ break;
54
+ case 'text':
55
+ predicate = `(!__el.children.length&&${compare("(__el.textContent||'')")})`;
56
+ break;
57
+ }
58
+ const expression = `(() => {
59
+ const __accessibleName = (el) => {
60
+ const labelled = el.getAttribute('aria-label');
61
+ if (labelled) return labelled;
62
+ const ids = (el.getAttribute('aria-labelledby')||'').split(/\\s+/).filter(Boolean);
63
+ if (ids.length) return ids.map((id)=>${rootExpression}.getElementById(id)?.textContent||'').join(' ').trim();
64
+ if (el.labels?.length) return Array.from(el.labels).map((label)=>label.textContent||'').join(' ').trim();
65
+ return (el.innerText||el.textContent||'').trim();
66
+ };
67
+ const __implicitRole = (el) => {
68
+ const explicit = el.getAttribute('role');
69
+ if (explicit) return explicit;
70
+ const tag = el.tagName.toLowerCase();
71
+ if (tag === 'button') return 'button';
72
+ if (tag === 'a' && el.hasAttribute('href')) return 'link';
73
+ if (tag === 'textarea') return 'textbox';
74
+ if (tag === 'select') return 'combobox';
75
+ if (tag === 'input') {
76
+ const type = (el.getAttribute('type')||'text').toLowerCase();
77
+ if (type === 'checkbox') return 'checkbox';
78
+ if (type === 'radio') return 'radio';
79
+ if (type === 'button' || type === 'submit' || type === 'reset') return 'button';
80
+ return 'textbox';
81
+ }
82
+ return '';
83
+ };
84
+ return ${root}.filter((__el) => {
85
+ const __role = __implicitRole(__el);
86
+ const __name = __accessibleName(__el);
87
+ return ${predicate};
88
+ });
89
+ })()`;
90
+ const filtered = applyFilters(expression, locator);
91
+ const framePath = locator.frame ?? locator.framePath ?? locator.frame_path;
92
+ if (!framePath?.length)
93
+ return filtered;
94
+ // Same-origin frame traversal is explicit. Cross-origin frames cannot be
95
+ // inspected through Runtime.evaluate and must be handled by a backend that
96
+ // can attach to the child target; never pretend the parent matched instead.
97
+ let frameRoot = rootExpression;
98
+ for (const frame of framePath) {
99
+ const frameSelector = frame.by === 'css'
100
+ ? quote(frame.value)
101
+ : quote(`iframe[title*="${frame.value.replaceAll('"', '\\"')}"]`);
102
+ frameRoot = `(() => { const frame = ${frameRoot}.querySelector(${frameSelector}); if (!frame || !frame.contentDocument) throw new Error('frameLocator could not resolve a same-origin iframe'); return frame.contentDocument; })()`;
103
+ }
104
+ return buildLocatorExpression({
105
+ ...locator,
106
+ frame: undefined,
107
+ framePath: undefined,
108
+ frame_path: undefined,
109
+ frameId: undefined,
110
+ frame_id: undefined,
111
+ }, selector, frameRoot);
112
+ }
113
+ function applyFilters(expression, locator) {
114
+ const filters = [];
115
+ if (locator.has_text)
116
+ filters.push(`(__el.textContent||'').includes(${quote(locator.has_text)})`);
117
+ return filters.length
118
+ ? `Array.from(${expression}).filter((__el)=>${filters.join('&&')})`
119
+ : expression;
120
+ }
121
+ export function buildTargetExpression(locator, selector) {
122
+ const elements = buildLocatorExpression(locator, selector);
123
+ const strict = locator?.strict !== false;
124
+ const nth = locator?.nth ?? 0;
125
+ return `(() => {
126
+ const __matches = ${elements}.filter((__candidate) => {
127
+ const __style = getComputedStyle(__candidate);
128
+ const __rect = __candidate.getBoundingClientRect();
129
+ return __style.display!=='none' && __style.visibility!=='hidden' && __style.pointerEvents!=='none' && (!!__rect.width || !!__rect.height);
130
+ });
131
+ if (!__matches.length) throw new Error('Locator matched no elements');
132
+ if (__matches.length > 1 && ${strict}) throw new Error('Locator matched '+__matches.length+' elements; use nth or strict:false');
133
+ const __el = __matches[${nth}];
134
+ if (!__el) throw new Error('Locator nth is outside the matched elements');
135
+ const __style = getComputedStyle(__el);
136
+ const __rect = __el.getBoundingClientRect();
137
+ if (__style.display==='none'||__style.visibility==='hidden'||__style.pointerEvents==='none'||(!__rect.width&&!__rect.height)) throw new Error('Locator matched a hidden element');
138
+ return __el;
139
+ })()`;
140
+ }
@@ -0,0 +1,194 @@
1
+ /**
2
+ * Browser locators shared by BrowserBatch and future visible-DOM adapters.
3
+ *
4
+ * This deliberately emits a small, self-contained browser expression instead
5
+ * of retaining DOM node handles. A locator is resolved again for every step,
6
+ * so a navigation or React re-render cannot silently reuse a stale element.
7
+ */
8
+
9
+ export type BrowserLocator = {
10
+ by:
11
+ | 'css'
12
+ | 'ax'
13
+ | 'role'
14
+ | 'text'
15
+ | 'label'
16
+ | 'placeholder'
17
+ | 'alt'
18
+ | 'title'
19
+ | 'testid';
20
+ value: string;
21
+ /** AX node id (or numeric index printed by the latest snapshot). */
22
+ generation?: number;
23
+ name?: string;
24
+ exact?: boolean;
25
+ strict?: boolean;
26
+ nth?: number;
27
+ within?: BrowserLocator;
28
+ has_text?: string;
29
+ frame?: BrowserLocator[];
30
+ framePath?: BrowserLocator[];
31
+ frame_path?: BrowserLocator[];
32
+ /** CDP frame id returned by frameInfo; enables cross-origin frame context. */
33
+ frameId?: string;
34
+ frame_id?: string;
35
+ };
36
+
37
+ const quote = (value: string) => JSON.stringify(value);
38
+
39
+ /** Build an expression returning `Element[]` in the selected document. */
40
+ export function buildLocatorExpression(
41
+ locator: BrowserLocator | undefined,
42
+ selector: string | undefined,
43
+ rootExpression = 'document',
44
+ ): string {
45
+ if (selector) {
46
+ return `Array.from(${rootExpression}.querySelectorAll(${quote(selector)}))`;
47
+ }
48
+ if (!locator) throw new Error('step requires selector or locator');
49
+
50
+ if (locator.by === 'ax') {
51
+ throw new Error(
52
+ 'AX locator must be resolved against the live accessibility tree first',
53
+ );
54
+ }
55
+
56
+ const root = locator.within
57
+ ? `${buildLocatorExpression(locator.within, undefined, rootExpression)}.flatMap((scope) => Array.from(scope.querySelectorAll('*')))`
58
+ : `Array.from(${rootExpression}.querySelectorAll('*'))`;
59
+ const value = quote(locator.value);
60
+ const exact = locator.exact === true;
61
+ const compare = (expression: string, expected = value) =>
62
+ exact
63
+ ? `${expression}.trim()===${expected}`
64
+ : `${expression}.includes(${expected})`;
65
+
66
+ let predicate: string;
67
+ switch (locator.by) {
68
+ case 'css':
69
+ return applyFilters(
70
+ `Array.from(${rootExpression}.querySelectorAll(${value}))`,
71
+ locator,
72
+ );
73
+ case 'role': {
74
+ const name = locator.name ? quote(locator.name) : value;
75
+ const nameCompare = locator.name
76
+ ? `(function(name){return ${exact ? `name.trim()===${name}` : `name.includes(${name})`};})(__name)`
77
+ : 'true';
78
+ predicate = `(__role===${value}&&${nameCompare})`;
79
+ break;
80
+ }
81
+ case 'label':
82
+ predicate = `Array.from(__el.labels||[]).some((label)=>${compare("(label.textContent||'')")})`;
83
+ break;
84
+ case 'placeholder':
85
+ predicate = compare(`__el.getAttribute('placeholder')||''`);
86
+ break;
87
+ case 'alt':
88
+ predicate = compare(`__el.getAttribute('alt')||''`);
89
+ break;
90
+ case 'title':
91
+ predicate = compare(`__el.getAttribute('title')||''`);
92
+ break;
93
+ case 'testid':
94
+ predicate = compare(`__el.getAttribute('data-testid')||''`);
95
+ break;
96
+ case 'text':
97
+ predicate = `(!__el.children.length&&${compare("(__el.textContent||'')")})`;
98
+ break;
99
+ }
100
+
101
+ const expression = `(() => {
102
+ const __accessibleName = (el) => {
103
+ const labelled = el.getAttribute('aria-label');
104
+ if (labelled) return labelled;
105
+ const ids = (el.getAttribute('aria-labelledby')||'').split(/\\s+/).filter(Boolean);
106
+ if (ids.length) return ids.map((id)=>${rootExpression}.getElementById(id)?.textContent||'').join(' ').trim();
107
+ if (el.labels?.length) return Array.from(el.labels).map((label)=>label.textContent||'').join(' ').trim();
108
+ return (el.innerText||el.textContent||'').trim();
109
+ };
110
+ const __implicitRole = (el) => {
111
+ const explicit = el.getAttribute('role');
112
+ if (explicit) return explicit;
113
+ const tag = el.tagName.toLowerCase();
114
+ if (tag === 'button') return 'button';
115
+ if (tag === 'a' && el.hasAttribute('href')) return 'link';
116
+ if (tag === 'textarea') return 'textbox';
117
+ if (tag === 'select') return 'combobox';
118
+ if (tag === 'input') {
119
+ const type = (el.getAttribute('type')||'text').toLowerCase();
120
+ if (type === 'checkbox') return 'checkbox';
121
+ if (type === 'radio') return 'radio';
122
+ if (type === 'button' || type === 'submit' || type === 'reset') return 'button';
123
+ return 'textbox';
124
+ }
125
+ return '';
126
+ };
127
+ return ${root}.filter((__el) => {
128
+ const __role = __implicitRole(__el);
129
+ const __name = __accessibleName(__el);
130
+ return ${predicate};
131
+ });
132
+ })()`;
133
+
134
+ const filtered = applyFilters(expression, locator);
135
+ const framePath = locator.frame ?? locator.framePath ?? locator.frame_path;
136
+ if (!framePath?.length) return filtered;
137
+
138
+ // Same-origin frame traversal is explicit. Cross-origin frames cannot be
139
+ // inspected through Runtime.evaluate and must be handled by a backend that
140
+ // can attach to the child target; never pretend the parent matched instead.
141
+ let frameRoot = rootExpression;
142
+ for (const frame of framePath) {
143
+ const frameSelector =
144
+ frame.by === 'css'
145
+ ? quote(frame.value)
146
+ : quote(`iframe[title*="${frame.value.replaceAll('"', '\\"')}"]`);
147
+ frameRoot = `(() => { const frame = ${frameRoot}.querySelector(${frameSelector}); if (!frame || !frame.contentDocument) throw new Error('frameLocator could not resolve a same-origin iframe'); return frame.contentDocument; })()`;
148
+ }
149
+ return buildLocatorExpression(
150
+ {
151
+ ...locator,
152
+ frame: undefined,
153
+ framePath: undefined,
154
+ frame_path: undefined,
155
+ frameId: undefined,
156
+ frame_id: undefined,
157
+ },
158
+ selector,
159
+ frameRoot,
160
+ );
161
+ }
162
+
163
+ function applyFilters(expression: string, locator: BrowserLocator): string {
164
+ const filters: string[] = [];
165
+ if (locator.has_text)
166
+ filters.push(`(__el.textContent||'').includes(${quote(locator.has_text)})`);
167
+ return filters.length
168
+ ? `Array.from(${expression}).filter((__el)=>${filters.join('&&')})`
169
+ : expression;
170
+ }
171
+
172
+ export function buildTargetExpression(
173
+ locator: BrowserLocator | undefined,
174
+ selector: string | undefined,
175
+ ): string {
176
+ const elements = buildLocatorExpression(locator, selector);
177
+ const strict = locator?.strict !== false;
178
+ const nth = locator?.nth ?? 0;
179
+ return `(() => {
180
+ const __matches = ${elements}.filter((__candidate) => {
181
+ const __style = getComputedStyle(__candidate);
182
+ const __rect = __candidate.getBoundingClientRect();
183
+ return __style.display!=='none' && __style.visibility!=='hidden' && __style.pointerEvents!=='none' && (!!__rect.width || !!__rect.height);
184
+ });
185
+ if (!__matches.length) throw new Error('Locator matched no elements');
186
+ if (__matches.length > 1 && ${strict}) throw new Error('Locator matched '+__matches.length+' elements; use nth or strict:false');
187
+ const __el = __matches[${nth}];
188
+ if (!__el) throw new Error('Locator nth is outside the matched elements');
189
+ const __style = getComputedStyle(__el);
190
+ const __rect = __el.getBoundingClientRect();
191
+ if (__style.display==='none'||__style.visibility==='hidden'||__style.pointerEvents==='none'||(!__rect.width&&!__rect.height)) throw new Error('Locator matched a hidden element');
192
+ return __el;
193
+ })()`;
194
+ }
@@ -85,16 +85,9 @@ export function describeEffect(verdict, action) {
85
85
  case 'changed':
86
86
  return null; // 正常路径不加噪声
87
87
  case 'unchanged':
88
- return (`⚠️ 动作已发出,但页面结构在动作前后**完全没有变化**。\n`
89
- + `这通常意味着三种情况之一:${action} 命中的不是可交互元素、点击被遮挡层拦住了、`
90
- + `或者这个操作本来就不改变页面(比如点了一个纯展示文本)。\n`
91
- + `请对照下面的最新快照确认目标是否正确,不要用同一个选择器直接重试。`
92
- // 豁免了行才提。这不是免责声明,是让模型知道这个结论有多硬:
93
- // 被豁免的位置上,「自己在跳」和「被我改了又在跳」不可区分。
94
- + (verdict.maskedLines > 0
95
- ? `\n(说明:页面上有 ${verdict.maskedLines} 行在持续自行变化(时钟/轮询一类),`
96
- + `已从判定中排除。若你这次操作本该影响的正是这些位置,这个结论可能不准。)`
97
- : ''));
88
+ return `⚠️ 动作已发出,但页面结构在动作前后**完全没有变化**。\n这通常意味着三种情况之一:${action} 命中的不是可交互元素、点击被遮挡层拦住了、或者这个操作本来就不改变页面(比如点了一个纯展示文本)。\n请对照下面的最新快照确认目标是否正确,不要用同一个选择器直接重试。${verdict.maskedLines > 0
89
+ ? `\n(说明:页面上有 ${verdict.maskedLines} 行在持续自行变化(时钟/轮询一类),已从判定中排除。若你这次操作本该影响的正是这些位置,这个结论可能不准。)`
90
+ : ''}`;
98
91
  case 'unknown':
99
92
  return '(未能取得动作前后的页面快照,无法判断这次操作是否生效——请自行核对。)';
100
93
  }
@@ -179,7 +172,7 @@ export function suggestSelectorCandidates(snapshot, selector, limit = 5) {
179
172
  export class BrowserAttemptLedger {
180
173
  counts = new Map();
181
174
  static key(conversationKey, action, selector) {
182
- return `${conversationKey}${action}${selector ?? ''}`;
175
+ return `${conversationKey}\u0000${action}\u0000${selector ?? ''}`;
183
176
  }
184
177
  recordFailure(conversationKey, action, selector) {
185
178
  const key = BrowserAttemptLedger.key(conversationKey, action, selector);
@@ -191,12 +184,12 @@ export class BrowserAttemptLedger {
191
184
  this.counts.delete(BrowserAttemptLedger.key(conversationKey, action, selector));
192
185
  }
193
186
  failures(conversationKey, action, selector) {
194
- return this.counts.get(BrowserAttemptLedger.key(conversationKey, action, selector)) ?? 0;
187
+ return (this.counts.get(BrowserAttemptLedger.key(conversationKey, action, selector)) ?? 0);
195
188
  }
196
189
  /** 会话结束时清账,避免长期驻留。 */
197
190
  forget(conversationKey) {
198
191
  for (const key of [...this.counts.keys()]) {
199
- if (key.startsWith(`${conversationKey}`))
192
+ if (key.startsWith(`${conversationKey}\u0000`))
200
193
  this.counts.delete(key);
201
194
  }
202
195
  }
@@ -228,7 +221,9 @@ export function budgetSnapshot(snapshot, opts = {}) {
228
221
  if (lines.length <= maxLines && snapshot.length <= maxChars)
229
222
  return snapshot;
230
223
  const hasRef = (line) => /@e\d+|\bref=e\d+/.test(line);
231
- const clip = (line) => line.length <= MAX_SNAPSHOT_LINE_CHARS ? line : `${line.slice(0, MAX_SNAPSHOT_LINE_CHARS)}…`;
224
+ const clip = (line) => line.length <= MAX_SNAPSHOT_LINE_CHARS
225
+ ? line
226
+ : `${line.slice(0, MAX_SNAPSHOT_LINE_CHARS)}…`;
232
227
  // 两轮**只挑不排**:先在原序上标记要留的可操作行,再用余量补纯文本行。
233
228
  const keep = new Array(lines.length).fill(false);
234
229
  let kept = 0;
@@ -267,7 +262,5 @@ export function budgetSnapshot(snapshot, opts = {}) {
267
262
  }
268
263
  flushGap();
269
264
  const dropped = lines.length - kept;
270
- return (`${out.join('\n')}\n`
271
- + `… 为控制上下文,共省略 ${dropped} 行(按原顺序保留,优先保住可引用的元素)。`
272
- + '需要完整页面请单独调用 snapshot,或用 getContent 读取正文。');
265
+ return `${out.join('\n')}\n… 为控制上下文,共省略 ${dropped} 行(按原顺序保留,优先保住可引用的元素)。需要完整页面请单独调用 snapshot,或用 getContent 读取正文。`;
273
266
  }
@@ -82,36 +82,35 @@ export function classifyPageEffect(
82
82
  after: string | undefined,
83
83
  noiseAfter?: string,
84
84
  ): BrowserEffectVerdict {
85
- if (before === undefined || after === undefined) return { effect: 'unknown', maskedLines: 0 };
85
+ if (before === undefined || after === undefined)
86
+ return { effect: 'unknown', maskedLines: 0 };
86
87
  const actual = differingLineIndexes(before, after);
87
88
  if (actual === null) return { effect: 'changed', maskedLines: 0 }; // 行数变了 = 结构变了
88
89
  if (actual.size === 0) return { effect: 'unchanged', maskedLines: 0 };
89
- const noisy = noiseAfter !== undefined ? differingLineIndexes(after, noiseAfter) : null;
90
+ const noisy =
91
+ noiseAfter !== undefined ? differingLineIndexes(after, noiseAfter) : null;
90
92
  // 没有可用的噪声基线时不做扣除:宁可把「生效了」判宽,也不能把一次真实变化
91
93
  // 误报成没变——那会让模型放弃一条本来走通了的路。
92
94
  if (noisy === null) return { effect: 'changed', maskedLines: 0 };
93
- for (const index of actual) if (!noisy.has(index)) return { effect: 'changed', maskedLines: 0 };
95
+ for (const index of actual)
96
+ if (!noisy.has(index)) return { effect: 'changed', maskedLines: 0 };
94
97
  return { effect: 'unchanged', maskedLines: actual.size };
95
98
  }
96
99
 
97
100
  /** 给模型的效果说明。措辞要让它知道**下一步该干什么**,不只是知道结果。 */
98
- export function describeEffect(verdict: BrowserEffectVerdict, action: string): string | null {
101
+ export function describeEffect(
102
+ verdict: BrowserEffectVerdict,
103
+ action: string,
104
+ ): string | null {
99
105
  switch (verdict.effect) {
100
106
  case 'changed':
101
107
  return null; // 正常路径不加噪声
102
108
  case 'unchanged':
103
- return (
104
- `⚠️ 动作已发出,但页面结构在动作前后**完全没有变化**。\n`
105
- + `这通常意味着三种情况之一:${action} 命中的不是可交互元素、点击被遮挡层拦住了、`
106
- + `或者这个操作本来就不改变页面(比如点了一个纯展示文本)。\n`
107
- + `请对照下面的最新快照确认目标是否正确,不要用同一个选择器直接重试。`
108
- // 豁免了行才提。这不是免责声明,是让模型知道这个结论有多硬:
109
- // 被豁免的位置上,「自己在跳」和「被我改了又在跳」不可区分。
110
- + (verdict.maskedLines > 0
111
- ? `\n(说明:页面上有 ${verdict.maskedLines} 行在持续自行变化(时钟/轮询一类),`
112
- + `已从判定中排除。若你这次操作本该影响的正是这些位置,这个结论可能不准。)`
113
- : '')
114
- );
109
+ return `⚠️ 动作已发出,但页面结构在动作前后**完全没有变化**。\n这通常意味着三种情况之一:${action} 命中的不是可交互元素、点击被遮挡层拦住了、或者这个操作本来就不改变页面(比如点了一个纯展示文本)。\n请对照下面的最新快照确认目标是否正确,不要用同一个选择器直接重试。${
110
+ verdict.maskedLines > 0
111
+ ? `\n(说明:页面上有 ${verdict.maskedLines} 行在持续自行变化(时钟/轮询一类),已从判定中排除。若你这次操作本该影响的正是这些位置,这个结论可能不准。)`
112
+ : ''
113
+ }`;
115
114
  case 'unknown':
116
115
  return '(未能取得动作前后的页面快照,无法判断这次操作是否生效——请自行核对。)';
117
116
  }
@@ -206,29 +205,47 @@ export function suggestSelectorCandidates(
206
205
  export class BrowserAttemptLedger {
207
206
  private counts = new Map<string, number>();
208
207
 
209
- private static key(conversationKey: string, action: string, selector?: string): string {
210
- return `${conversationKey}${action}${selector ?? ''}`;
208
+ private static key(
209
+ conversationKey: string,
210
+ action: string,
211
+ selector?: string,
212
+ ): string {
213
+ return `${conversationKey}\u0000${action}\u0000${selector ?? ''}`;
211
214
  }
212
215
 
213
- recordFailure(conversationKey: string, action: string, selector?: string): number {
216
+ recordFailure(
217
+ conversationKey: string,
218
+ action: string,
219
+ selector?: string,
220
+ ): number {
214
221
  const key = BrowserAttemptLedger.key(conversationKey, action, selector);
215
222
  const next = (this.counts.get(key) ?? 0) + 1;
216
223
  this.counts.set(key, next);
217
224
  return next;
218
225
  }
219
226
 
220
- recordSuccess(conversationKey: string, action: string, selector?: string): void {
221
- this.counts.delete(BrowserAttemptLedger.key(conversationKey, action, selector));
227
+ recordSuccess(
228
+ conversationKey: string,
229
+ action: string,
230
+ selector?: string,
231
+ ): void {
232
+ this.counts.delete(
233
+ BrowserAttemptLedger.key(conversationKey, action, selector),
234
+ );
222
235
  }
223
236
 
224
237
  failures(conversationKey: string, action: string, selector?: string): number {
225
- return this.counts.get(BrowserAttemptLedger.key(conversationKey, action, selector)) ?? 0;
238
+ return (
239
+ this.counts.get(
240
+ BrowserAttemptLedger.key(conversationKey, action, selector),
241
+ ) ?? 0
242
+ );
226
243
  }
227
244
 
228
245
  /** 会话结束时清账,避免长期驻留。 */
229
246
  forget(conversationKey: string): void {
230
247
  for (const key of [...this.counts.keys()]) {
231
- if (key.startsWith(`${conversationKey}`)) this.counts.delete(key);
248
+ if (key.startsWith(`${conversationKey}\u0000`)) this.counts.delete(key);
232
249
  }
233
250
  }
234
251
  }
@@ -267,7 +284,9 @@ export function budgetSnapshot(
267
284
 
268
285
  const hasRef = (line: string): boolean => /@e\d+|\bref=e\d+/.test(line);
269
286
  const clip = (line: string): string =>
270
- line.length <= MAX_SNAPSHOT_LINE_CHARS ? line : `${line.slice(0, MAX_SNAPSHOT_LINE_CHARS)}…`;
287
+ line.length <= MAX_SNAPSHOT_LINE_CHARS
288
+ ? line
289
+ : `${line.slice(0, MAX_SNAPSHOT_LINE_CHARS)}…`;
271
290
 
272
291
  // 两轮**只挑不排**:先在原序上标记要留的可操作行,再用余量补纯文本行。
273
292
  const keep = new Array<boolean>(lines.length).fill(false);
@@ -292,15 +311,13 @@ export function budgetSnapshot(
292
311
  gap = 0;
293
312
  };
294
313
  for (let i = 0; i < lines.length; i += 1) {
295
- if (keep[i]) { flushGap(); out.push(clip(lines[i])); }
296
- else gap += 1;
314
+ if (keep[i]) {
315
+ flushGap();
316
+ out.push(clip(lines[i]));
317
+ } else gap += 1;
297
318
  }
298
319
  flushGap();
299
320
 
300
321
  const dropped = lines.length - kept;
301
- return (
302
- `${out.join('\n')}\n`
303
- + `… 为控制上下文,共省略 ${dropped} 行(按原顺序保留,优先保住可引用的元素)。`
304
- + '需要完整页面请单独调用 snapshot,或用 getContent 读取正文。'
305
- );
322
+ return `${out.join('\n')}\n… 为控制上下文,共省略 ${dropped} 行(按原顺序保留,优先保住可引用的元素)。需要完整页面请单独调用 snapshot,或用 getContent 读取正文。`;
306
323
  }