@wenathlan/devthink 2.0.12 → 2.0.14

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 (444) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/accounts.ts +2087 -0
  3. package/agent.ts +2331 -0
  4. package/antigravity.ts +2139 -0
  5. package/apifreeze.ts +4146 -0
  6. package/auth.ts +642 -0
  7. package/background.ts +16837 -0
  8. package/bridge.ts +2080 -0
  9. package/build.ts +54 -0
  10. package/bun.ts +26 -0
  11. package/capture.ts +1614 -0
  12. package/checksecrets.ts +72 -0
  13. package/cjs.ts +9 -0
  14. package/cli.ts +3500 -0
  15. package/commands.ts +1101 -0
  16. package/companion.ts +450 -0
  17. package/compatibility.ts +37 -0
  18. package/config.ts +3137 -0
  19. package/constants.ts +943 -0
  20. package/core.ts +1473 -0
  21. package/crossbrowser.ts +1359 -0
  22. package/dashdone.ts +605 -0
  23. package/data.ts +943 -0
  24. package/database.ts +133 -0
  25. package/debug.ts +850 -0
  26. package/deno.ts +27 -0
  27. package/devthink.ts +707 -0
  28. package/dist/accounts.d.ts +409 -0
  29. package/dist/agent.d.ts +837 -0
  30. package/dist/antigravity.d.ts +380 -0
  31. package/dist/apifreeze.d.ts +113 -0
  32. package/dist/auth.d.ts +224 -0
  33. package/{bridge.d.ts → dist/bridge.d.ts} +1 -1
  34. package/dist/capture.d.ts +595 -0
  35. package/dist/cjs.d.ts +6 -0
  36. package/{cli.js → dist/cli.js} +2 -2
  37. package/dist/commands.d.ts +310 -0
  38. package/dist/compatibility.d.ts +17 -0
  39. package/dist/config.d.ts +1853 -0
  40. package/dist/constants.d.ts +637 -0
  41. package/dist/core.d.ts +361 -0
  42. package/dist/data.d.ts +330 -0
  43. package/dist/database.d.ts +24 -0
  44. package/dist/debug.d.ts +270 -0
  45. package/dist/engine.d.ts +74 -0
  46. package/dist/environments.d.ts +244 -0
  47. package/dist/evidence.d.ts +277 -0
  48. package/dist/export.d.ts +311 -0
  49. package/dist/fingerprint.d.ts +594 -0
  50. package/dist/flow.d.ts +300 -0
  51. package/dist/gates.d.ts +103 -0
  52. package/dist/identity.d.ts +51 -0
  53. package/dist/ids.d.ts +7 -0
  54. package/dist/llm.d.ts +652 -0
  55. package/dist/models.d.ts +1807 -0
  56. package/dist/net.d.ts +325 -0
  57. package/dist/neutral.d.ts +41 -0
  58. package/dist/oauth.d.ts +703 -0
  59. package/dist/page.d.ts +1166 -0
  60. package/dist/perf.d.ts +481 -0
  61. package/dist/plan.d.ts +134 -0
  62. package/dist/project.d.ts +395 -0
  63. package/dist/providers.d.ts +37 -0
  64. package/dist/quota.d.ts +453 -0
  65. package/dist/recovery.d.ts +621 -0
  66. package/dist/request.d.ts +1492 -0
  67. package/dist/run.d.ts +779 -0
  68. package/dist/runtime.d.ts +212 -0
  69. package/dist/search.d.ts +375 -0
  70. package/dist/security.d.ts +534 -0
  71. package/dist/serve.d.ts +136 -0
  72. package/dist/session.d.ts +296 -0
  73. package/dist/storage.d.ts +53 -0
  74. package/dist/streaming.d.ts +1119 -0
  75. package/dist/swarm.d.ts +328 -0
  76. package/dist/tools.d.ts +170 -0
  77. package/dist/types.d.ts +8357 -0
  78. package/dist/utils.d.ts +82 -0
  79. package/dist/version.d.ts +7 -0
  80. package/dist/versionregistry.d.ts +406 -0
  81. package/dist/views.d.ts +579 -0
  82. package/dist/workbenchsession.d.ts +69 -0
  83. package/dist/workflow.d.ts +649 -0
  84. package/docs/readme.md +92 -0
  85. package/docs/schemas/antigravity.json +192 -0
  86. package/engine.ts +1524 -0
  87. package/environments.ts +1005 -0
  88. package/evidence.ts +643 -0
  89. package/export.ts +889 -0
  90. package/fingerprint.ts +1458 -0
  91. package/flow.ts +1190 -0
  92. package/gates.ts +307 -0
  93. package/gateway.ts +34 -0
  94. package/hardening.ts +191 -0
  95. package/headless.ts +369 -0
  96. package/http.ts +2110 -0
  97. package/identity.ts +246 -0
  98. package/ids.ts +26 -0
  99. package/index.ts +369 -0
  100. package/llm.ts +2682 -0
  101. package/mcp.ts +1835 -0
  102. package/{memory.js → memory.ts} +3834 -2310
  103. package/models.ts +3805 -0
  104. package/modes.ts +43 -0
  105. package/net.ts +1214 -0
  106. package/neutral.ts +362 -0
  107. package/node.ts +26 -0
  108. package/oauth.ts +2216 -0
  109. package/offscreen.ts +170 -0
  110. package/pack.ts +956 -0
  111. package/package.json +175 -82
  112. package/page.ts +7824 -0
  113. package/pagebridge.ts +1116 -0
  114. package/perf.ts +957 -0
  115. package/plan.ts +672 -0
  116. package/plugin.ts +76 -0
  117. package/{policy.js → policy.ts} +5073 -4679
  118. package/prisma.config.ts +27 -0
  119. package/progress.ts +1308 -0
  120. package/project.ts +1291 -0
  121. package/protocol.ts +4187 -0
  122. package/providers.ts +246 -0
  123. package/quota.ts +1887 -0
  124. package/recovery.ts +2433 -0
  125. package/request.ts +4482 -0
  126. package/run.ts +2135 -0
  127. package/runtime.ts +526 -0
  128. package/search.ts +1760 -0
  129. package/security.ts +1673 -0
  130. package/serve.ts +419 -0
  131. package/server.ts +5538 -0
  132. package/session.ts +1162 -0
  133. package/storage.ts +182 -0
  134. package/streaming.ts +4101 -0
  135. package/swarm.ts +884 -0
  136. package/sync.ts +56 -0
  137. package/tests/agentcert.test.ts +128 -0
  138. package/tests/agentfleet.test.ts +214 -0
  139. package/tests/agentreview.test.ts +241 -0
  140. package/tests/agentstream.test.ts +335 -0
  141. package/tests/agentwork.test.ts +356 -0
  142. package/tests/apifreeze.test.ts +290 -0
  143. package/tests/apimap.test.ts +112 -0
  144. package/tests/approvalgate.test.ts +175 -0
  145. package/tests/artifactmanifest.test.ts +204 -0
  146. package/tests/attentionfeed.test.ts +163 -0
  147. package/tests/backgroundruns.test.ts +100 -0
  148. package/tests/batchscheduling.test.ts +131 -0
  149. package/tests/blackboard.test.ts +238 -0
  150. package/tests/bridge.test.ts +1088 -0
  151. package/tests/browsercoverage.test.ts +134 -0
  152. package/tests/browserpolyfills.test.ts +124 -0
  153. package/tests/build.mjs +1260 -0
  154. package/tests/clientauth.test.ts +223 -0
  155. package/tests/clitools.test.ts +578 -0
  156. package/tests/confirmgates.test.ts +190 -0
  157. package/tests/containerpack.test.ts +143 -0
  158. package/tests/controlflow.test.ts +2120 -0
  159. package/tests/coordination.test.ts +345 -0
  160. package/tests/copyscreen.test.ts +139 -0
  161. package/tests/core.test.ts +417 -0
  162. package/tests/costcert.test.ts +95 -0
  163. package/tests/crossbrowser.test.ts +115 -0
  164. package/tests/cspaudit.test.ts +79 -0
  165. package/tests/dashdone.test.ts +615 -0
  166. package/tests/datagrid.test.ts +137 -0
  167. package/tests/doccheck.test.ts +107 -0
  168. package/tests/dombatch.test.ts +109 -0
  169. package/tests/emulation.test.ts +282 -0
  170. package/tests/environments.test.ts +259 -0
  171. package/tests/evidenceviews.test.ts +88 -0
  172. package/tests/exporttools.test.ts +185 -0
  173. package/tests/firefoxprep.test.ts +134 -0
  174. package/tests/flowlibrary.test.ts +242 -0
  175. package/tests/flowrun.test.ts +303 -0
  176. package/tests/forensics.test.ts +439 -0
  177. package/tests/gateway.test.ts +939 -0
  178. package/tests/headlesslib.test.ts +171 -0
  179. package/tests/httpstream.test.ts +277 -0
  180. package/tests/immutablelog.test.ts +157 -0
  181. package/tests/inboundguard.test.ts +177 -0
  182. package/tests/lazyload.test.ts +72 -0
  183. package/tests/librarymodes.test.ts +623 -0
  184. package/tests/llm.test.ts +696 -0
  185. package/tests/manifest.test.ts +226 -0
  186. package/tests/maskinputs.test.ts +150 -0
  187. package/tests/matrixverify.test.ts +111 -0
  188. package/tests/mavenpack.test.ts +75 -0
  189. package/tests/mcpserver.test.ts +704 -0
  190. package/tests/memory.test.ts +4155 -0
  191. package/tests/memorycare.test.ts +230 -0
  192. package/tests/migrateplan.test.ts +349 -0
  193. package/tests/minimization.test.ts +414 -0
  194. package/tests/modelroute.test.ts +112 -0
  195. package/tests/multiagent.test.ts +440 -0
  196. package/tests/nativebridge.test.ts +807 -0
  197. package/tests/navigation.test.ts +284 -0
  198. package/tests/nugetpack.test.ts +83 -0
  199. package/tests/orchestration.test.ts +449 -0
  200. package/tests/originpolicy.test.ts +405 -0
  201. package/tests/outputcompare.test.ts +97 -0
  202. package/tests/package.test.ts +91 -0
  203. package/tests/pagebridge.test.ts +5909 -0
  204. package/tests/pentest.test.ts +75 -0
  205. package/tests/perfrecords.test.ts +257 -0
  206. package/tests/permdiff.test.ts +85 -0
  207. package/tests/phishguard.test.ts +128 -0
  208. package/tests/pickerviews.test.ts +155 -0
  209. package/tests/pipelines.test.ts +381 -0
  210. package/tests/planlint.test.ts +240 -0
  211. package/tests/planreview.test.ts +383 -0
  212. package/tests/platformtargets.test.ts +56 -0
  213. package/tests/policy.test.ts +8284 -0
  214. package/tests/portability.test.ts +96 -0
  215. package/tests/progress.test.ts +1036 -0
  216. package/tests/promptlibrary.test.ts +116 -0
  217. package/tests/protocol.test.ts +4793 -0
  218. package/tests/publishingpipeline.test.ts +314 -0
  219. package/tests/quickactions.test.ts +164 -0
  220. package/tests/readiness.test.ts +78 -0
  221. package/tests/recipes.test.ts +163 -0
  222. package/tests/redactshots.test.ts +216 -0
  223. package/tests/registernvidiakeys.ts +51 -0
  224. package/tests/relayserve.test.ts +304 -0
  225. package/tests/releasenotes.test.ts +276 -0
  226. package/tests/resilience.test.ts +467 -0
  227. package/tests/resourceaware.test.ts +187 -0
  228. package/tests/runbudget.test.ts +125 -0
  229. package/tests/runhistory.test.ts +299 -0
  230. package/tests/runreplay.test.ts +113 -0
  231. package/tests/runresume.test.ts +184 -0
  232. package/tests/runstate.test.ts +288 -0
  233. package/tests/runtimeadapters.test.ts +251 -0
  234. package/tests/safariskeleton.test.ts +115 -0
  235. package/tests/sandboxframe.test.ts +196 -0
  236. package/tests/sbom.test.ts +105 -0
  237. package/tests/secretvault.test.ts +188 -0
  238. package/tests/selcache.test.ts +111 -0
  239. package/tests/sessioninterface.test.ts +791 -0
  240. package/tests/sessions.test.ts +591 -0
  241. package/tests/siteprefs.test.ts +228 -0
  242. package/tests/snapshotdelta.test.ts +165 -0
  243. package/tests/statusviews.test.ts +237 -0
  244. package/tests/stepmeter.test.ts +200 -0
  245. package/tests/streamparse.test.ts +163 -0
  246. package/tests/stylepruning.test.ts +90 -0
  247. package/tests/surfaces.test.ts +282 -0
  248. package/tests/sweep.test.ts +78 -0
  249. package/tests/syncbridge.test.ts +164 -0
  250. package/tests/taskqueue.test.ts +206 -0
  251. package/tests/toolcalls.test.ts +336 -0
  252. package/tests/toolcatalog.test.ts +201 -0
  253. package/tests/torture-agent.test.ts +706 -0
  254. package/tests/torture-auth.test.ts +461 -0
  255. package/tests/torture-commands.test.ts +895 -0
  256. package/tests/torture-data.test.ts +923 -0
  257. package/tests/torture-environments.test.ts +285 -0
  258. package/tests/torture-export.test.ts +263 -0
  259. package/tests/torture-http.test.ts +1379 -0
  260. package/tests/torture-llm.test.ts +808 -0
  261. package/tests/torture-memory.test.ts +1084 -0
  262. package/tests/torture-plan.test.ts +829 -0
  263. package/tests/torture-run.test.ts +626 -0
  264. package/tests/torture-session.test.ts +928 -0
  265. package/tests/torture-swarm.test.ts +1245 -0
  266. package/tests/torture-tools.test.ts +964 -0
  267. package/tests/torture-workflow.test.ts +2354 -0
  268. package/tests/tourviews.test.ts +52 -0
  269. package/tests/transparency.test.ts +147 -0
  270. package/tests/trigger.test.ts +941 -0
  271. package/tests/v1sunset.test.ts +428 -0
  272. package/tests/virtlist.test.ts +94 -0
  273. package/tests/vision.test.ts +540 -0
  274. package/tests/vsixpack.test.ts +145 -0
  275. package/tests/webapi.test.ts +523 -0
  276. package/tests/workflow.test.ts +1785 -0
  277. package/tests/workfloweditor.test.ts +759 -0
  278. package/tests/xpipack.test.ts +128 -0
  279. package/tools.ts +734 -0
  280. package/types.ts +9908 -0
  281. package/umd.ts +9 -0
  282. package/utils.ts +249 -0
  283. package/version.ts +8 -0
  284. package/versionregistry.ts +1310 -0
  285. package/views.ts +2153 -0
  286. package/vitest.config.ts +12 -0
  287. package/web/App.tsx +78 -0
  288. package/web/README.md +47 -0
  289. package/web/capacitor.config.ts +46 -0
  290. package/web/const.ts +19 -0
  291. package/web/control.shell.tsx +66 -0
  292. package/web/dashboardpage.ts +554 -0
  293. package/web/db.ts +493 -0
  294. package/web/design.html +541 -0
  295. package/web/gatewayview/Gateway.tsx +345 -0
  296. package/web/gatewayview/config.ts +1042 -0
  297. package/web/gatewayview/definition.ts +174 -0
  298. package/web/icons.ts +15 -0
  299. package/{manifest.json → web/manifest.json} +1 -1
  300. package/web/optionspage.ts +691 -0
  301. package/web/popup.ts +1651 -0
  302. package/web/schema.prisma +176 -0
  303. package/web/sidepanel.ts +7941 -0
  304. package/web/sitemanifest.json +13 -0
  305. package/web/terminal-ui.tsx +622 -0
  306. package/web/transparencypage.ts +541 -0
  307. package/web/vite.config.ts +39 -0
  308. package/web/workspace.ts +23 -0
  309. package/workbenchmemory.ts +104 -0
  310. package/workbenchsession.ts +304 -0
  311. package/workflow.ts +4495 -0
  312. package/bridge.d.ts.map +0 -1
  313. package/bridge.js +0 -1877
  314. package/bun.d.ts.map +0 -1
  315. package/bun.js +0 -52329
  316. package/caps/background.json +0 -712
  317. package/caps/cli.json +0 -360
  318. package/caps/library.json +0 -3611
  319. package/caps/mcp.json +0 -126
  320. package/caps/pagebridge.json +0 -377
  321. package/caps/popup.json +0 -51
  322. package/caps/sidepanel.json +0 -522
  323. package/checksums.txt +0 -142
  324. package/cli.d.ts.map +0 -1
  325. package/companion.d.ts.map +0 -1
  326. package/companion.js +0 -389
  327. package/crossbrowser.d.ts.map +0 -1
  328. package/crossbrowser.js +0 -1191
  329. package/dashdone.d.ts.map +0 -1
  330. package/dashdone.js +0 -368
  331. package/deno.d.ts.map +0 -1
  332. package/deno.js +0 -52325
  333. package/devthink.umd.js +0 -52346
  334. package/fixtures/bun.ts +0 -7
  335. package/fixtures/cjs.js +0 -6
  336. package/fixtures/deno.ts +0 -6
  337. package/fixtures/example-org-pagestate.json +0 -22
  338. package/fixtures/importers/automa-workflow.json +0 -18
  339. package/fixtures/importers/selenium-side.json +0 -20
  340. package/fixtures/importers/tabular-plan.csv +0 -7
  341. package/fixtures/importers/uivision-macro.json +0 -10
  342. package/fixtures/importers/v1-plan.json +0 -13
  343. package/fixtures/mcp-client.mjs +0 -14
  344. package/fixtures/pages/checkout.html +0 -192
  345. package/fixtures/pages/dashboard.html +0 -110
  346. package/fixtures/pages/feed.html +0 -113
  347. package/fixtures/pages/product-grid.html +0 -150
  348. package/fixtures/plans/form-inventory-plan.json +0 -11
  349. package/fixtures/plans/release-notes-plan.json +0 -11
  350. package/fixtures/recipes/agentscompete.json +0 -11
  351. package/fixtures/recipes/agentsforms.json +0 -11
  352. package/fixtures/recipes/agentsmonitor.json +0 -11
  353. package/fixtures/recipes/agentsreview.json +0 -29
  354. package/fixtures/recipes/agentswarm.json +0 -11
  355. package/fixtures/recipes/fillcalendar.json +0 -12
  356. package/fixtures/recipes/fillcheckout.json +0 -13
  357. package/fixtures/recipes/filldependentdropdowns.json +0 -12
  358. package/fixtures/recipes/fillfromcsv.json +0 -13
  359. package/fixtures/recipes/fillloginform.json +0 -12
  360. package/fixtures/recipes/fillmultistepwizard.json +0 -13
  361. package/fixtures/recipes/fillregistration.json +0 -12
  362. package/fixtures/recipes/fillsearchfilters.json +0 -12
  363. package/fixtures/recipes/filltypeahead.json +0 -11
  364. package/fixtures/recipes/monitoralerts.json +0 -12
  365. package/fixtures/recipes/monitoravailability.json +0 -11
  366. package/fixtures/recipes/monitornetworkquiet.json +0 -12
  367. package/fixtures/recipes/monitorpagechanges.json +0 -11
  368. package/fixtures/recipes/monitorpricechange.json +0 -11
  369. package/fixtures/recipes/monitorschedule.json +0 -12
  370. package/fixtures/recipes/scrapedynamicprices.json +0 -13
  371. package/fixtures/recipes/scrapeimagegallery.json +0 -12
  372. package/fixtures/recipes/scrapeinfinitefeed.json +0 -13
  373. package/fixtures/recipes/scrapenestedlists.json +0 -12
  374. package/fixtures/recipes/scrapeproductgrid.json +0 -12
  375. package/fixtures/recipes/scrapereviews.json +0 -12
  376. package/fixtures/recipes/scrapesearchresults.json +0 -12
  377. package/fixtures/recipes/scrapetablepagination.json +0 -12
  378. package/fixtures/recipes/testaccessibility.json +0 -34
  379. package/fixtures/recipes/testconsoleerrors.json +0 -12
  380. package/fixtures/recipes/testdeeplinks.json +0 -12
  381. package/fixtures/recipes/testformvalidation.json +0 -13
  382. package/fixtures/recipes/testlayoutshift.json +0 -12
  383. package/fixtures/recipes/testlinkcheck.json +0 -12
  384. package/fixtures/recipes/testloadtiming.json +0 -12
  385. package/fixtures/recipes/testvisualdiff.json +0 -12
  386. package/fixtures/workflows/changelog-digest-workflow.json +0 -13
  387. package/fixtures/workflows/form-survey-workflow.json +0 -13
  388. package/gallery.json +0 -706
  389. package/hardening.d.ts.map +0 -1
  390. package/hardening.js +0 -188
  391. package/headless.d.ts.map +0 -1
  392. package/headless.js +0 -11522
  393. package/http.d.ts.map +0 -1
  394. package/http.js +0 -2165
  395. package/index.cjs +0 -54682
  396. package/index.d.ts.map +0 -1
  397. package/index.js +0 -52310
  398. package/index.neutral.js +0 -46343
  399. package/mcp.d.ts.map +0 -1
  400. package/mcp.js +0 -20515
  401. package/memory.d.ts.map +0 -1
  402. package/nativehost.template.json +0 -10
  403. package/node.cjs +0 -54686
  404. package/node.d.ts.map +0 -1
  405. package/pack.d.ts.map +0 -1
  406. package/pack.js +0 -805
  407. package/policy.d.ts.map +0 -1
  408. package/progress.d.ts.map +0 -1
  409. package/progress.js +0 -645
  410. package/protocol.d.ts.map +0 -1
  411. package/protocol.js +0 -8334
  412. package/schemas/audit.schema.json +0 -226
  413. package/schemas/capability.schema.json +0 -113
  414. package/schemas/envelope.schema.json +0 -162
  415. package/schemas/memory.schema.json +0 -51
  416. package/schemas/observation.schema.json +0 -113
  417. package/schemas/plan.schema.json +0 -208
  418. package/schemas/progress.schema.json +0 -126
  419. package/schemas/proposal.schema.json +0 -68
  420. package/schemas/session.schema.json +0 -82
  421. package/schemas/tool.schema.json +0 -94
  422. package/server.d.ts.map +0 -1
  423. package/server.js +0 -28877
  424. package/umd-example.html +0 -18
  425. package/umd.d.ts.map +0 -1
  426. /package/{bun.d.ts → dist/bun.d.ts} +0 -0
  427. /package/{cli.d.ts → dist/cli.d.ts} +0 -0
  428. /package/{companion.d.ts → dist/companion.d.ts} +0 -0
  429. /package/{crossbrowser.d.ts → dist/crossbrowser.d.ts} +0 -0
  430. /package/{dashdone.d.ts → dist/dashdone.d.ts} +0 -0
  431. /package/{deno.d.ts → dist/deno.d.ts} +0 -0
  432. /package/{hardening.d.ts → dist/hardening.d.ts} +0 -0
  433. /package/{headless.d.ts → dist/headless.d.ts} +0 -0
  434. /package/{http.d.ts → dist/http.d.ts} +0 -0
  435. /package/{index.d.ts → dist/index.d.ts} +0 -0
  436. /package/{mcp.d.ts → dist/mcp.d.ts} +0 -0
  437. /package/{memory.d.ts → dist/memory.d.ts} +0 -0
  438. /package/{node.d.ts → dist/node.d.ts} +0 -0
  439. /package/{pack.d.ts → dist/pack.d.ts} +0 -0
  440. /package/{policy.d.ts → dist/policy.d.ts} +0 -0
  441. /package/{progress.d.ts → dist/progress.d.ts} +0 -0
  442. /package/{protocol.d.ts → dist/protocol.d.ts} +0 -0
  443. /package/{server.d.ts → dist/server.d.ts} +0 -0
  444. /package/{umd.d.ts → dist/umd.d.ts} +0 -0
package/tools.ts ADDED
@@ -0,0 +1,734 @@
1
+ /**
2
+ * The tools module of the 1.1.90 consolidation: every correlated variation of the tool catalog and call runtime logic interned in this one file, so the module family carries one surface without duplicate variations.
3
+ * The correlation is the tools family: toolcatalog holds the catalog of the 1.1.54 agent protocol (the tool namespaces, the json schema layout of every tool def, the read and gated tools of the browser, workflow, memory and system domains, the catalog build, the name resolution and the per namespace listing); toolcalls holds the call runtime of the 1.1.56 agent protocol part three (the per client rate limits, the structured error mapping with its retry hints — exported here as callretryhintof so the session family keeps the canonical retryhintof — the idempotency replay window, the ordered batch calls, the tool dry runs, the tool mocks and the call contexts).
4
+ * No budget, window or mock is ever invented: every rate limit and idempotency window stays the user's choice, and no tool call ever bypasses the dispatch gates.
5
+ */
6
+
7
+ /* ── Merged from toolcatalog.ts ── */
8
+ import type {
9
+ actionkind,
10
+ actionrisk,
11
+ toolcatalog,
12
+ tooldef,
13
+ toolnamespace,
14
+ toolschema,
15
+ toolschemaproperty,
16
+ agentsession,
17
+ agentplan,
18
+ batchoutcome,
19
+ callcontext,
20
+ callratelimit,
21
+ clientrecord,
22
+ idempotencykey,
23
+ idempotencyrecord,
24
+ retryhint,
25
+ structurederror,
26
+ tooldryrun,
27
+ toolmock,
28
+ toolresult,
29
+ } from "./types.js";
30
+
31
+ /**
32
+ * Tool catalog of the 1.1.54 and 1.1.55 agent protocol family, widened by the 1.1.84 mcp server mode.
33
+ * Every mcp tool definition, version and json schema lives in this file: the four tool domains (browser, workflow, memory and system) with their namespace prefixes, the version appended to every tooldef for compatibility checks, the json schema generation that maps every tool input to typed properties with required markers and default values, the plain language descriptions that state the consent class and side effects of every tool and end with the openapi style field layout of their inputs, the consent metadata of the tools with side effects — the review requirement, the policy derived risk class, the approval gate requirement and the session origin scope — and the name resolution that keeps colliding base names apart through their namespace prefix. The 1.1.84 family adds the plan proposal tool with the full step grammar, the review gate tool that waits for the human answer, the observation read tool and the session record tool.
34
+ * The catalog stays pure data: policy validates it against the action kind grammar and the server lists it through the tools/list handshake, while no tool bypasses review — read only tools run under the dryrun risk class and every tool with side effects names the approved plan step it executes.
35
+ */
36
+
37
+ /** The catalog version of the 1.1.84 family; every tooldef appends its own version for compatibility checks, and the bump to 2 adds the plan proposal, review gate, observation and session tools with the openapi style field layout of every description. */
38
+ export const toolcatalogversion = 2;
39
+
40
+ /** The tool namespaces the catalog serves, in the documented order of the panel view. */
41
+ export const toolnamespaces: toolnamespace[] = ["browser", "workflow", "memory", "system"];
42
+
43
+ /** The reviewed action kinds of every namespace so policy can validate that tools stay in their domain. */
44
+ export const domainkinds: Record<toolnamespace, actionkind[]> = {
45
+ browser: [
46
+ "observe",
47
+ "extract",
48
+ "readtext",
49
+ "readtable",
50
+ "readlinks",
51
+ "a11ytree",
52
+ "tablist",
53
+ "windowlist",
54
+ "click",
55
+ "type",
56
+ "presskey",
57
+ "navigate",
58
+ "back",
59
+ "forward",
60
+ "reload",
61
+ "tabcreate",
62
+ "tabactivate",
63
+ "tabclose",
64
+ "windowcreate",
65
+ "windowclose",
66
+ "windowresize",
67
+ ],
68
+ workflow: ["composeworkflow", "runworkflow", "dryrun", "eventrule"],
69
+ memory: ["listruns", "extractvars", "trailaudit"],
70
+ system: ["observe", "readmeta"],
71
+ };
72
+
73
+ /** Builds the json schema of one tool input from its typed property map: required properties are listed and the options object carries the reviewed empty default. */
74
+ export function toolschemaof(properties: Record<string, toolschemaproperty>): toolschema {
75
+ return {
76
+ type: "object",
77
+ properties,
78
+ required: Object.entries(properties)
79
+ .filter(([, property]) => property.required === true)
80
+ .map(([name]) => name),
81
+ };
82
+ }
83
+
84
+ /** Renders the openapi style field layout of one tool input schema: every property lists its name, its json schema type and its required star while a reviewed default renders after an equals sign, so every tool description ends with the same field layout an openapi document carries and a client reads the wire shape from the description alone. */
85
+ export function openapilayout(schema: toolschema): string {
86
+ const fields = Object.entries(schema.properties).map(
87
+ ([name, property]) =>
88
+ `${name}:${property.type}${property.required === true ? "*" : ""}${property.default !== undefined ? `=${typeof property.default === "object" ? JSON.stringify(property.default) : String(property.default)}` : ""}`,
89
+ );
90
+ return `Fields: ${fields.join("; ")}.`;
91
+ }
92
+
93
+ /** Appends the openapi style field layout of its inputs to one tool description so every catalog description follows the same field layout grammar. */
94
+ function withfielddayout(tool: tooldef): tooldef {
95
+ return { ...tool, description: `${tool.description} ${openapilayout(tool.inputschema)}` };
96
+ }
97
+
98
+ /** Builds one read only tool: read tools take their reviewed inputs from the wire and run under the dryrun risk class without extra approval. */
99
+ function readtool(
100
+ name: string,
101
+ kind: actionkind,
102
+ description: string,
103
+ inputs: Record<string, toolschemaproperty> = {},
104
+ ): tooldef {
105
+ return {
106
+ name,
107
+ version: toolcatalogversion,
108
+ description,
109
+ inputschema: toolschemaof({
110
+ target: { type: "string", description: "Reviewed css selector the tool addresses." },
111
+ value: { type: "string", description: "Reviewed literal value the tool carries." },
112
+ options: {
113
+ type: "object",
114
+ description: "Reviewed json options of the wrapped action kind with the empty default.",
115
+ default: {},
116
+ },
117
+ ...inputs,
118
+ }),
119
+ kind,
120
+ risk: "read",
121
+ };
122
+ }
123
+
124
+ /** Builds one tool with side effects: the tool takes only the id of the approved plan step whose reviewed payload it executes, so a client can never widen what the human approved; the consent metadata derives its risk class from the policy grading, marks the approval gate requirement and scopes the tool to the session grants. */
125
+ function gatedtool(name: string, kind: actionkind, risk: actionrisk, description: string, review: string): tooldef {
126
+ return {
127
+ name,
128
+ version: toolcatalogversion,
129
+ description,
130
+ inputschema: toolschemaof({
131
+ stepid: { type: "string", description: "Id of the approved plan step this tool executes.", required: true },
132
+ }),
133
+ kind,
134
+ risk,
135
+ consentmeta: { review, riskclass: risk, approvalrequired: true, originscope: "session" },
136
+ };
137
+ }
138
+
139
+ /** The browser domain of the catalog: the snapshot, interaction, navigation, tab and window tools plus the read only extraction tools. */
140
+ function browserdomain() {
141
+ return {
142
+ namespace: "browser" as const,
143
+ version: toolcatalogversion,
144
+ tools: [
145
+ readtool(
146
+ "browser.snapshot",
147
+ "observe",
148
+ "Captures the semantic snapshot of the active tab: url, title, text preview, forms and interactive elements. Read only with no side effects; runs under the dryrun risk class once the session is approved.",
149
+ ),
150
+ readtool(
151
+ "browser.extract",
152
+ "extract",
153
+ "Extracts the reviewed structured data of the page. Read only with no side effects.",
154
+ ),
155
+ readtool(
156
+ "browser.readtext",
157
+ "readtext",
158
+ "Reads the text of the addressed element. Read only with no side effects.",
159
+ { target: { type: "string", description: "Reviewed css selector of the element to read.", required: true } },
160
+ ),
161
+ readtool(
162
+ "browser.readtable",
163
+ "readtable",
164
+ "Reads the rows of the addressed data table. Read only with no side effects.",
165
+ { target: { type: "string", description: "Reviewed css selector of the table to read.", required: true } },
166
+ ),
167
+ readtool(
168
+ "browser.readlinks",
169
+ "readlinks",
170
+ "Reads the link inventory of the page. Read only with no side effects.",
171
+ ),
172
+ readtool(
173
+ "browser.a11ytree",
174
+ "a11ytree",
175
+ "Reads the accessibility tree of the page. Read only with no side effects.",
176
+ ),
177
+ readtool(
178
+ "browser.observe",
179
+ "observe",
180
+ "Reads the structured observation record of the active tab — the url, the title, the page signals, the detected forms and the interactive elements — exactly as the evidence views render it. Read only with no side effects.",
181
+ ),
182
+ readtool("browser.tablist", "tablist", "Lists the open tabs. Read only with no side effects."),
183
+ readtool("browser.windowlist", "windowlist", "Lists the open windows. Read only with no side effects."),
184
+ gatedtool(
185
+ "browser.click",
186
+ "click",
187
+ "sensitive",
188
+ "Clicks the addressed element. Sensitive: it changes page state, so it executes exactly one approved plan step.",
189
+ "The click runs only as the approved plan step it names; a paired client can never widen the reviewed target or options.",
190
+ ),
191
+ gatedtool(
192
+ "browser.type",
193
+ "type",
194
+ "sensitive",
195
+ "Types the reviewed text into the addressed element. Sensitive: it changes page state, so it executes exactly one approved plan step.",
196
+ "The typing runs only as the approved plan step it names; the reviewed target, text and options stay fixed.",
197
+ ),
198
+ gatedtool(
199
+ "browser.presskey",
200
+ "presskey",
201
+ "sensitive",
202
+ "Presses the reviewed key. Sensitive: it changes page state, so it executes exactly one approved plan step.",
203
+ "The key press runs only as the approved plan step it names.",
204
+ ),
205
+ gatedtool(
206
+ "browser.navigate",
207
+ "navigate",
208
+ "sensitive",
209
+ "Navigates the active tab to the reviewed url. Sensitive: it changes browser state, so it executes exactly one approved plan step.",
210
+ "The navigation runs only as the approved plan step it names and stays inside the session origin grants.",
211
+ ),
212
+ gatedtool(
213
+ "browser.back",
214
+ "back",
215
+ "sensitive",
216
+ "Navigates back in the history of the active tab. Sensitive: it changes browser state, so it executes exactly one approved plan step.",
217
+ "The history navigation runs only as the approved plan step it names.",
218
+ ),
219
+ gatedtool(
220
+ "browser.forward",
221
+ "forward",
222
+ "sensitive",
223
+ "Navigates forward in the history of the active tab. Sensitive: it changes browser state, so it executes exactly one approved plan step.",
224
+ "The history navigation runs only as the approved plan step it names.",
225
+ ),
226
+ gatedtool(
227
+ "browser.reload",
228
+ "reload",
229
+ "sensitive",
230
+ "Reloads the active tab. Sensitive: it changes browser state, so it executes exactly one approved plan step.",
231
+ "The reload runs only as the approved plan step it names.",
232
+ ),
233
+ gatedtool(
234
+ "browser.tabcreate",
235
+ "tabcreate",
236
+ "sensitive",
237
+ "Opens a new tab. Sensitive: it changes browser state, so it executes exactly one approved plan step.",
238
+ "The tab creation runs only as the approved plan step it names.",
239
+ ),
240
+ gatedtool(
241
+ "browser.tabactivate",
242
+ "tabactivate",
243
+ "sensitive",
244
+ "Activates the reviewed tab. Sensitive: it moves focus, so it executes exactly one approved plan step.",
245
+ "The tab activation runs only as the approved plan step it names.",
246
+ ),
247
+ gatedtool(
248
+ "browser.tabclose",
249
+ "tabclose",
250
+ "sensitive",
251
+ "Closes the reviewed tab. Sensitive: it destroys browser state, so it executes exactly one approved plan step.",
252
+ "The tab close runs only as the approved plan step it names.",
253
+ ),
254
+ gatedtool(
255
+ "browser.windowcreate",
256
+ "windowcreate",
257
+ "sensitive",
258
+ "Opens a new window. Sensitive: it changes browser state, so it executes exactly one approved plan step.",
259
+ "The window creation runs only as the approved plan step it names.",
260
+ ),
261
+ gatedtool(
262
+ "browser.windowclose",
263
+ "windowclose",
264
+ "sensitive",
265
+ "Closes the reviewed window. Sensitive: it destroys browser state, so it executes exactly one approved plan step.",
266
+ "The window close runs only as the approved plan step it names.",
267
+ ),
268
+ gatedtool(
269
+ "browser.windowresize",
270
+ "windowresize",
271
+ "sensitive",
272
+ "Resizes the reviewed window. Sensitive: it changes browser state, so it executes exactly one approved plan step.",
273
+ "The window resize runs only as the approved plan step it names.",
274
+ ),
275
+ ],
276
+ };
277
+ }
278
+
279
+ /** The workflow domain of the catalog: the plan proposal tool with the full step grammar, the review gate tool that waits for the human answer, the workflow listing, run, dry run and trigger listing tools. */
280
+ function workflowdomain() {
281
+ return {
282
+ namespace: "workflow" as const,
283
+ version: toolcatalogversion,
284
+ tools: [
285
+ readtool(
286
+ "workflow.list",
287
+ "composeworkflow",
288
+ "Lists the composed workflows with their names, versions, origins and step counts. Read only with no side effects.",
289
+ ),
290
+ readtool(
291
+ "workflow.plan",
292
+ "composeworkflow",
293
+ "Proposes a plan with the full reviewed step grammar — the title, the ordered steps of kind, target, value and reviewed options of the shared step grammar, and the origin the plan runs under — for the human review; the proposal changes no page state. Read only with no side effects.",
294
+ {
295
+ title: { type: "string", description: "Plain language title of the proposed plan.", required: true },
296
+ steps: {
297
+ type: "array",
298
+ description:
299
+ "Reviewed plan steps of the full shared grammar: each entry carries its id, its action kind, its target, its value and its reviewed options object.",
300
+ required: true,
301
+ },
302
+ origin: {
303
+ type: "string",
304
+ description: "Origin the proposed plan runs under; the session grants check it.",
305
+ required: true,
306
+ },
307
+ },
308
+ ),
309
+ readtool(
310
+ "workflow.review",
311
+ "composeworkflow",
312
+ "Submits the proposed plan to the human review gate and waits for the answer: the call returns once the human approves or refuses while the gate refuses by default when the user configured window passes. Read only with no side effects — the run itself still names the approved plan step.",
313
+ { planid: { type: "string", description: "Id of the proposed plan the review gate submits.", required: true } },
314
+ ),
315
+ readtool(
316
+ "workflow.dryrun",
317
+ "dryrun",
318
+ "Runs a composed workflow as a dry run: read steps project their would be outcome and every step with side effects is refused. Read only with no side effects.",
319
+ ),
320
+ gatedtool(
321
+ "workflow.run",
322
+ "runworkflow",
323
+ "sensitive",
324
+ "Runs a composed workflow for real. Sensitive: it executes every step of the workflow, so it executes exactly one approved runworkflow plan step with its explicit run review.",
325
+ "The workflow run needs the explicit run review: the approved runworkflow plan step with its expanded step list shown before the first step executes.",
326
+ ),
327
+ gatedtool(
328
+ "workflow.triggers",
329
+ "eventrule",
330
+ "sensitive",
331
+ "Lists the armed trigger rules with their schedules, cooldowns and fire counters so a client can inspect what launches runs automatically. Sensitive by its trigger family: automatic launchers stay behind the arm review class.",
332
+ "The trigger listing runs behind the approved plan review because trigger rules launch runs automatically.",
333
+ ),
334
+ ],
335
+ };
336
+ }
337
+
338
+ /** The memory domain of the catalog: the read accessors for stored runs, variable scopes and audit summaries. */
339
+ function memorydomain() {
340
+ return {
341
+ namespace: "memory" as const,
342
+ version: toolcatalogversion,
343
+ tools: [
344
+ readtool(
345
+ "memory.list",
346
+ "listruns",
347
+ "Lists the stored workflow run records with their states and step cursors from local memory. Read only with no page access.",
348
+ {
349
+ target: { type: "string", description: "Unused by the memory read; kept for schema uniformity." },
350
+ value: { type: "string", description: "Unused by the memory read; kept for schema uniformity." },
351
+ state: { type: "string", description: "Optional reviewed run state filter of the listing.", default: "" },
352
+ },
353
+ ),
354
+ readtool(
355
+ "memory.variables",
356
+ "extractvars",
357
+ "Reads the stored variable scopes of a run from local memory. Read only with no page access.",
358
+ ),
359
+ readtool(
360
+ "memory.audit",
361
+ "trailaudit",
362
+ "Reads the audit summary of the session trail from local memory. Read only with no page access.",
363
+ ),
364
+ ],
365
+ };
366
+ }
367
+
368
+ /** The system domain of the catalog: status, version, session record and capability reports. */
369
+ function systemdomain() {
370
+ return {
371
+ namespace: "system" as const,
372
+ version: toolcatalogversion,
373
+ tools: [
374
+ readtool(
375
+ "system.status",
376
+ "observe",
377
+ "Reports the mcp server status, the session state and the connected clients. Read only with no side effects.",
378
+ ),
379
+ readtool(
380
+ "system.version",
381
+ "readmeta",
382
+ "Reports the protocol version, the catalog version and the extension version. Read only with no side effects.",
383
+ ),
384
+ readtool(
385
+ "system.session",
386
+ "observe",
387
+ "Reports the live session record of the extension session the client pairs with: the session state, its origin grants and its expiry. Read only with no side effects.",
388
+ ),
389
+ readtool(
390
+ "system.capabilities",
391
+ "observe",
392
+ "Reports the optional browser capabilities the user has granted. Read only with no side effects.",
393
+ ),
394
+ ],
395
+ };
396
+ }
397
+
398
+ /** Builds the full mcp tool catalog of the four domains with the catalog version stamped on every record and the openapi style field layout of its inputs appended to every description. */
399
+ export function buildtoolcatalog(): toolcatalog {
400
+ return {
401
+ version: toolcatalogversion,
402
+ domains: [browserdomain(), workflowdomain(), memorydomain(), systemdomain()].map((domain) => ({
403
+ ...domain,
404
+ tools: domain.tools.map(withfielddayout),
405
+ })),
406
+ };
407
+ }
408
+
409
+ /** Returns every tool of the catalog flattened across the domains. */
410
+ export function alltools(catalog: toolcatalog): tooldef[] {
411
+ return catalog.domains.flatMap((domain) => domain.tools);
412
+ }
413
+
414
+ /** Prefixes one base tool name with its namespace so tool names never collide across domains. */
415
+ export function toolname(namespace: toolnamespace, base: string): string {
416
+ return `${namespace}.${base}`;
417
+ }
418
+
419
+ /** Resolves one tool by its namespaced name; a bare name resolves only when exactly one tool of the catalog carries it, so colliding base names stay unambiguous through their prefix. */
420
+ export function resolvetool(catalog: toolcatalog, name: string): tooldef | undefined {
421
+ if (name.includes(".")) return alltools(catalog).find((tool) => tool.name === name);
422
+ const matches = alltools(catalog).filter((tool) => tool.name.split(".")[1] === name);
423
+ return matches.length === 1 ? matches[0] : undefined;
424
+ }
425
+
426
+ /** Returns the namespace of one tool name; names without a dot carry no namespace. */
427
+ export function namespaceof(name: string): toolnamespace | undefined {
428
+ const head = name.split(".")[0];
429
+ return toolnamespaces.includes(head as toolnamespace) ? (head as toolnamespace) : undefined;
430
+ }
431
+
432
+ /** Groups the tools of the catalog by namespace for the panel view and the tools/list report. */
433
+ export function toolsbynamespace(
434
+ catalog: toolcatalog,
435
+ ): Array<{ namespace: toolnamespace; version: number; tools: tooldef[] }> {
436
+ return catalog.domains.map((domain) => ({
437
+ namespace: domain.namespace,
438
+ version: domain.version,
439
+ tools: domain.tools,
440
+ }));
441
+ }
442
+
443
+ /* ── Merged from toolcalls.ts ── */
444
+ import { tooldispatchgate } from "./policy.js";
445
+ import { randomid } from "./memory.js";
446
+
447
+ /**
448
+ * Tool call runtime of the 1.1.56 agent protocol part three.
449
+ * Every call runtime concern lives in this file: the per client rate limits that count calls inside their window and answer excess with a structured error carrying its retry after, the structured error mapping that turns executor failures into codes with retry hints, the retry hint classification of retryable timeouts, busy windows and consent refusals, the idempotency keys that replay stored results inside their window and expire after it, the ordered batch calls that stop on the first error when the flag requests it, the tool dry runs that evaluate arguments and consent without side effects, the tool mocks that answer declared tools with canned results only in test contexts, and the call contexts that isolate the concurrent calls of concurrent clients while every call lands its audit entry with its idempotency key and outcome.
450
+ * The runtime stays consent-first: a dry run never mutates the page, a mock never touches the browser and a rate limit never invents a budget the user did not configure.
451
+ */
452
+
453
+ /** The default idempotency replay window of five minutes; any user configured window wins and an absent window keeps the replay forever. */
454
+ export const defaultidempotencywindowms = 300_000;
455
+
456
+ /** Counts one client tool call against its per client rate limit: a window past its end resets the counter, a configured budget refuses the call that would exceed it with its retry after window and an absent limit or budget keeps the client unbounded because no silent default ever applies. */
457
+ export function applyratelimit(input: { limits: callratelimit[]; clientid: string; now: number }): {
458
+ allowed: boolean;
459
+ used: number;
460
+ budget?: number;
461
+ retryafter?: number;
462
+ limit?: callratelimit;
463
+ limits: callratelimit[];
464
+ } {
465
+ const existing = input.limits.find((limit) => limit.clientid === input.clientid);
466
+ if (existing === undefined) return { allowed: true, used: 0, limits: input.limits };
467
+ const elapsed = input.now - existing.windowstartedat;
468
+ const limit: callratelimit =
469
+ elapsed >= existing.windowms ? { ...existing, windowstartedat: input.now, used: 0 } : existing;
470
+ if (limit.budget !== undefined && limit.used >= limit.budget) {
471
+ const retryafter = Math.max(0, limit.windowms - (input.now - limit.windowstartedat));
472
+ return {
473
+ allowed: false,
474
+ used: limit.used,
475
+ budget: limit.budget,
476
+ retryafter,
477
+ limits: input.limits.map((candidate) => (candidate.clientid === input.clientid ? limit : candidate)),
478
+ };
479
+ }
480
+ const counted: callratelimit = { ...limit, used: limit.used + 1 };
481
+ return {
482
+ allowed: true,
483
+ used: counted.used,
484
+ ...(counted.budget !== undefined ? { budget: counted.budget } : {}),
485
+ limit: counted,
486
+ limits: input.limits.map((candidate) => (candidate.clientid === input.clientid ? counted : candidate)),
487
+ };
488
+ }
489
+
490
+ /** Builds one structured error with its code, message, retry hint and optional retry after window. */
491
+ export function structurederrorof(input: {
492
+ code: string;
493
+ message: string;
494
+ retryhint: retryhint;
495
+ retryafter?: number;
496
+ }): structurederror {
497
+ return {
498
+ code: input.code,
499
+ message: input.message,
500
+ retryhint: input.retryhint,
501
+ ...(input.retryafter !== undefined ? { retryafter: input.retryafter } : {}),
502
+ };
503
+ }
504
+
505
+ /** Classifies one failure into its retry hint: timeouts stay retryable, busy windows and rate limits wait for their retry after while consent refusals never retry. */
506
+ export function callretryhintof(failure: { code?: string; message?: string }): retryhint {
507
+ const text = `${failure.code ?? ""} ${failure.message ?? ""}`.toLowerCase();
508
+ if (
509
+ text.includes("consent") ||
510
+ text.includes("refus") ||
511
+ text.includes("unpaired") ||
512
+ text.includes("unapproved") ||
513
+ text.includes("grant")
514
+ )
515
+ return "none";
516
+ if (text.includes("rate") || text.includes("busy") || text.includes("queue") || text.includes("window"))
517
+ return "wait";
518
+ if (text.includes("timeout") || text.includes("timed out") || text.includes("internal") || text.includes("network"))
519
+ return "retry";
520
+ return "none";
521
+ }
522
+
523
+ /** Maps one executor failure onto its structured error: the code and message ride the answer while the retry hint classifies the retryable timeouts, busy windows and consent refusals. */
524
+ export function maptoolerror(input: {
525
+ failure: { code?: string; message: string } | Error;
526
+ retryafter?: number;
527
+ }): structurederror {
528
+ const code = input.failure instanceof Error ? "internal" : (input.failure.code ?? "internal");
529
+ const message = input.failure instanceof Error ? input.failure.message : input.failure.message;
530
+ return structurederrorof({
531
+ code,
532
+ message,
533
+ retryhint: callretryhintof({ code, message }),
534
+ ...(input.retryafter !== undefined ? { retryafter: input.retryafter } : {}),
535
+ });
536
+ }
537
+
538
+ /** Checks one idempotency key: a live record of the same client replays its stored result while an expired, foreign or unknown key reports why nothing replayed. */
539
+ export function checkidempotency(input: {
540
+ records: idempotencyrecord[];
541
+ key: idempotencykey;
542
+ clientid: string;
543
+ now: number;
544
+ }): { replay?: toolresult; record?: idempotencyrecord; reason?: string } {
545
+ const match = input.records.find((record) => record.key === input.key && record.clientid === input.clientid);
546
+ if (match !== undefined) {
547
+ if (input.now >= match.expiresat)
548
+ return { reason: "The idempotency record expired past its window and the call runs again." };
549
+ return { replay: match.result, record: match };
550
+ }
551
+ if (input.records.some((record) => record.key === input.key))
552
+ return { reason: "The idempotency key belongs to another client and never replays across clients." };
553
+ return { reason: "The idempotency key names no stored record." };
554
+ }
555
+
556
+ /** Stores one idempotency record for replay: the key, the calling client, the tool and the result with its user configured window; a repeated key of the same client overwrites its record. */
557
+ export function recordidempotency(input: {
558
+ records: idempotencyrecord[];
559
+ key: idempotencykey;
560
+ clientid: string;
561
+ tool: string;
562
+ result: toolresult;
563
+ now: number;
564
+ window?: number;
565
+ }): idempotencyrecord[] {
566
+ const record: idempotencyrecord = {
567
+ key: input.key,
568
+ clientid: input.clientid,
569
+ tool: input.tool,
570
+ result: input.result,
571
+ createdat: input.now,
572
+ expiresat: input.now + (input.window ?? defaultidempotencywindowms),
573
+ };
574
+ return [
575
+ record,
576
+ ...input.records.filter((candidate) => !(candidate.key === input.key && candidate.clientid === input.clientid)),
577
+ ];
578
+ }
579
+
580
+ /** Expires the idempotency records past their window: expired records leave the live set while their keys never replay. */
581
+ export function expireidempotency(records: idempotencyrecord[], now: number): idempotencyrecord[] {
582
+ return records.filter((record) => now < record.expiresat);
583
+ }
584
+
585
+ /** Executes one ordered batch call: every member runs in order through the injected executor, each member lands its own outcome and the batch stops at the first error when the stop on error flag requests it. */
586
+ export async function runbatch(input: {
587
+ calls: Array<{ id: string; name: string; params: Record<string, unknown> }>;
588
+ stoponerror: boolean;
589
+ now: number;
590
+ execute: (
591
+ call: { id: string; name: string; params: Record<string, unknown> },
592
+ index: number,
593
+ ) => Promise<{ ok: boolean; result?: toolresult; error?: structurederror }>;
594
+ }): Promise<{ outcomes: batchoutcome[]; stoppedat?: string }> {
595
+ const outcomes: batchoutcome[] = [];
596
+ for (let index = 0; index < input.calls.length; index += 1) {
597
+ const call = input.calls[index];
598
+ if (call === undefined) continue;
599
+ const outcome = await input.execute(call, index);
600
+ outcomes.push({
601
+ callid: call.id,
602
+ tool: call.name,
603
+ ok: outcome.ok,
604
+ ...(outcome.result !== undefined ? { result: outcome.result } : {}),
605
+ ...(outcome.error !== undefined ? { error: outcome.error } : {}),
606
+ at: input.now + index,
607
+ });
608
+ if (!outcome.ok && input.stoponerror) return { outcomes, stoppedat: call.id };
609
+ }
610
+ return { outcomes };
611
+ }
612
+
613
+ /** Runs one tool dry run: the arguments validate against the tool json schema, the same consent gates that guard execution evaluate the call and the record stays free of page mutations by construction because nothing ever executes. */
614
+ export function dryruntool(input: {
615
+ tool: tooldef;
616
+ params: Record<string, unknown>;
617
+ client: clientrecord;
618
+ session?: agentsession;
619
+ plan?: agentplan;
620
+ origin: string;
621
+ stepid?: string;
622
+ now: number;
623
+ callid?: string;
624
+ }): tooldryrun {
625
+ const findings: string[] = [];
626
+ for (const required of input.tool.inputschema.required) {
627
+ const value = input.params[required];
628
+ if (value === undefined || value === null || (typeof value === "string" && value.trim() === ""))
629
+ findings.push(`The required argument ${required} of ${input.tool.name} stays empty.`);
630
+ }
631
+ for (const [name, property] of Object.entries(input.tool.inputschema.properties)) {
632
+ const value = input.params[name];
633
+ if (value === undefined || value === null) continue;
634
+ const expected = property.type;
635
+ const actual = Array.isArray(value) ? "array" : typeof value;
636
+ if (actual !== expected)
637
+ findings.push(
638
+ `The argument ${name} of ${input.tool.name} carries a ${actual} value where the schema asks a ${expected}.`,
639
+ );
640
+ }
641
+ const stepid =
642
+ input.stepid !== undefined
643
+ ? input.stepid
644
+ : typeof input.params.stepid === "string"
645
+ ? input.params.stepid
646
+ : undefined;
647
+ const gate = tooldispatchgate({
648
+ client: input.client,
649
+ tool: input.tool,
650
+ session: input.session,
651
+ plan: input.plan,
652
+ origin: input.origin,
653
+ ...(stepid !== undefined ? { stepid } : {}),
654
+ now: input.now,
655
+ });
656
+ if (!gate.allowed) findings.push(gate.reason ?? `The consent gates refused the ${input.tool.name} dry run.`);
657
+ return {
658
+ callid: input.callid ?? randomid(),
659
+ tool: input.tool.name,
660
+ argsvalid: findings.length === 0,
661
+ consentok: gate.allowed,
662
+ findings,
663
+ executed: false,
664
+ mutations: [],
665
+ at: input.now,
666
+ };
667
+ }
668
+
669
+ /** Applies one tool mock: a matching mock of a test context answers with its canned result without touching the browser while a mock outside a test context is refused and no mock leaves the call to the real gates. */
670
+ export function applymock(input: { mocks: toolmock[]; tool: string }): { result?: toolresult; reason?: string } {
671
+ const mock = input.mocks.find((candidate) => candidate.tool === input.tool);
672
+ if (mock === undefined) return {};
673
+ if (mock.testcontext !== true)
674
+ return {
675
+ reason: `The ${input.tool} mock stays outside a test context and is refused; mocks never answer real calls.`,
676
+ };
677
+ return { result: mock.result };
678
+ }
679
+
680
+ /** Opens one isolated call context for a concurrent client call: the call id, the client, the tool and the markers of the 1.1.56 family ride the record while the chunk counter starts at zero. */
681
+ export function begincall(input: {
682
+ clientid: string;
683
+ tool: string;
684
+ callid?: string;
685
+ idempotencykey?: idempotencykey;
686
+ dryrun?: boolean;
687
+ batchid?: string;
688
+ now: number;
689
+ }): callcontext {
690
+ return {
691
+ callid: input.callid ?? randomid(),
692
+ clientid: input.clientid,
693
+ tool: input.tool,
694
+ state: "inflight",
695
+ startedat: input.now,
696
+ ...(input.idempotencykey !== undefined && input.idempotencykey.trim() !== ""
697
+ ? { idempotencykey: input.idempotencykey }
698
+ : {}),
699
+ ...(input.dryrun === true ? { dryrun: true } : {}),
700
+ ...(input.batchid !== undefined ? { batchid: input.batchid } : {}),
701
+ chunks: 0,
702
+ };
703
+ }
704
+
705
+ /** Closes one call context with its outcome: the context turns done or failed with its end time while the chunks counter and the partial result of a cancellation survive for the answer. */
706
+ export function endcall(input: {
707
+ contexts: callcontext[];
708
+ callid: string;
709
+ ok: boolean;
710
+ errorcode?: string;
711
+ partial?: toolresult;
712
+ now: number;
713
+ }): { contexts: callcontext[]; context?: callcontext; reason?: string } {
714
+ const match = input.contexts.find((context) => context.callid === input.callid);
715
+ if (match === undefined)
716
+ return { contexts: input.contexts, reason: `The call context ${input.callid} never opened.` };
717
+ if (match.state !== "inflight") return { contexts: input.contexts, context: match };
718
+ const context: callcontext = {
719
+ ...match,
720
+ state: input.ok ? "done" : "failed",
721
+ endedat: input.now,
722
+ ...(input.errorcode !== undefined ? { errorcode: input.errorcode } : {}),
723
+ ...(input.partial !== undefined ? { partial: input.partial } : {}),
724
+ };
725
+ return {
726
+ contexts: input.contexts.map((candidate) => (candidate.callid === input.callid ? context : candidate)),
727
+ context,
728
+ };
729
+ }
730
+
731
+ /** Grades one batch call by its most sensitive member: the batch takes the sensitive grade when any member is sensitive and runs only behind the approval gates. */
732
+ export function batchrisk(calls: Array<{ risk: actionrisk }>): actionrisk {
733
+ return calls.some((call) => call.risk === "sensitive") ? "sensitive" : "read";
734
+ }