@namzu/sdk 0.6.0 → 1.1.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 (429) hide show
  1. package/CHANGELOG.md +529 -0
  2. package/dist/advisory/executor.d.ts.map +1 -1
  3. package/dist/advisory/executor.js +9 -2
  4. package/dist/advisory/executor.js.map +1 -1
  5. package/dist/advisory/executor.test.d.ts +2 -1
  6. package/dist/advisory/executor.test.d.ts.map +1 -1
  7. package/dist/advisory/executor.test.js +7 -4
  8. package/dist/advisory/executor.test.js.map +1 -1
  9. package/dist/agents/ReactiveAgent.d.ts.map +1 -1
  10. package/dist/agents/ReactiveAgent.js +7 -0
  11. package/dist/agents/ReactiveAgent.js.map +1 -1
  12. package/dist/agents/SupervisorAgent.d.ts +22 -1
  13. package/dist/agents/SupervisorAgent.d.ts.map +1 -1
  14. package/dist/agents/SupervisorAgent.js +54 -14
  15. package/dist/agents/SupervisorAgent.js.map +1 -1
  16. package/dist/agents/__tests__/supervisor-ledger.test.d.ts +2 -0
  17. package/dist/agents/__tests__/supervisor-ledger.test.d.ts.map +1 -0
  18. package/dist/agents/__tests__/supervisor-ledger.test.js +131 -0
  19. package/dist/agents/__tests__/supervisor-ledger.test.js.map +1 -0
  20. package/dist/bridge/sse/mapper.test.js +2 -2
  21. package/dist/config/runtime.d.ts +24 -0
  22. package/dist/config/runtime.d.ts.map +1 -1
  23. package/dist/config/runtime.js +9 -0
  24. package/dist/config/runtime.js.map +1 -1
  25. package/dist/connector/builtins/webhook.test.js +17 -0
  26. package/dist/connector/builtins/webhook.test.js.map +1 -1
  27. package/dist/connector/index.d.ts +1 -0
  28. package/dist/connector/index.d.ts.map +1 -1
  29. package/dist/connector/index.js +1 -0
  30. package/dist/connector/index.js.map +1 -1
  31. package/dist/connector/mcp/client.d.ts.map +1 -1
  32. package/dist/connector/mcp/client.js +4 -0
  33. package/dist/connector/mcp/client.js.map +1 -1
  34. package/dist/connector/mcp/index.d.ts +1 -0
  35. package/dist/connector/mcp/index.d.ts.map +1 -1
  36. package/dist/connector/mcp/index.js +1 -0
  37. package/dist/connector/mcp/index.js.map +1 -1
  38. package/dist/connector/mcp/streamable-http.d.ts +22 -0
  39. package/dist/connector/mcp/streamable-http.d.ts.map +1 -0
  40. package/dist/connector/mcp/streamable-http.js +128 -0
  41. package/dist/connector/mcp/streamable-http.js.map +1 -0
  42. package/dist/connector/mcp/streamable-http.test.d.ts +2 -0
  43. package/dist/connector/mcp/streamable-http.test.d.ts.map +1 -0
  44. package/dist/connector/mcp/streamable-http.test.js +132 -0
  45. package/dist/connector/mcp/streamable-http.test.js.map +1 -0
  46. package/dist/constants/compaction/index.d.ts.map +1 -1
  47. package/dist/constants/compaction/index.js +8 -3
  48. package/dist/constants/compaction/index.js.map +1 -1
  49. package/dist/constants/sandbox/index.d.ts +21 -0
  50. package/dist/constants/sandbox/index.d.ts.map +1 -1
  51. package/dist/constants/sandbox/index.js +30 -0
  52. package/dist/constants/sandbox/index.js.map +1 -1
  53. package/dist/constants/tools/index.d.ts.map +1 -1
  54. package/dist/constants/tools/index.js +33 -2
  55. package/dist/constants/tools/index.js.map +1 -1
  56. package/dist/manager/run/persistence.d.ts.map +1 -1
  57. package/dist/manager/run/persistence.js +35 -5
  58. package/dist/manager/run/persistence.js.map +1 -1
  59. package/dist/persona/assembler.d.ts +1 -0
  60. package/dist/persona/assembler.d.ts.map +1 -1
  61. package/dist/persona/assembler.js +37 -6
  62. package/dist/persona/assembler.js.map +1 -1
  63. package/dist/provider/collect.d.ts.map +1 -1
  64. package/dist/provider/collect.js +4 -1
  65. package/dist/provider/collect.js.map +1 -1
  66. package/dist/provider/collect.test.js +2 -2
  67. package/dist/public-runtime.d.ts +6 -5
  68. package/dist/public-runtime.d.ts.map +1 -1
  69. package/dist/public-runtime.js +6 -5
  70. package/dist/public-runtime.js.map +1 -1
  71. package/dist/public-tools.d.ts +2 -0
  72. package/dist/public-tools.d.ts.map +1 -1
  73. package/dist/public-tools.js +2 -0
  74. package/dist/public-tools.js.map +1 -1
  75. package/dist/public-types.d.ts +3 -0
  76. package/dist/public-types.d.ts.map +1 -1
  77. package/dist/registry/index.d.ts +2 -0
  78. package/dist/registry/index.d.ts.map +1 -1
  79. package/dist/registry/index.js +1 -0
  80. package/dist/registry/index.js.map +1 -1
  81. package/dist/registry/tool/execute.d.ts +27 -0
  82. package/dist/registry/tool/execute.d.ts.map +1 -1
  83. package/dist/registry/tool/execute.js +192 -7
  84. package/dist/registry/tool/execute.js.map +1 -1
  85. package/dist/registry/tool/execute.test.d.ts +9 -4
  86. package/dist/registry/tool/execute.test.d.ts.map +1 -1
  87. package/dist/registry/tool/execute.test.js +178 -7
  88. package/dist/registry/tool/execute.test.js.map +1 -1
  89. package/dist/registry/toolset/catalog.d.ts +42 -0
  90. package/dist/registry/toolset/catalog.d.ts.map +1 -0
  91. package/dist/registry/toolset/catalog.js +217 -0
  92. package/dist/registry/toolset/catalog.js.map +1 -0
  93. package/dist/registry/toolset/catalog.test.d.ts +2 -0
  94. package/dist/registry/toolset/catalog.test.d.ts.map +1 -0
  95. package/dist/registry/toolset/catalog.test.js +147 -0
  96. package/dist/registry/toolset/catalog.test.js.map +1 -0
  97. package/dist/runtime/query/__tests__/deferred-tools.test.d.ts +2 -0
  98. package/dist/runtime/query/__tests__/deferred-tools.test.d.ts.map +1 -0
  99. package/dist/runtime/query/__tests__/deferred-tools.test.js +185 -0
  100. package/dist/runtime/query/__tests__/deferred-tools.test.js.map +1 -0
  101. package/dist/runtime/query/__tests__/executor-concurrency.test.d.ts +2 -0
  102. package/dist/runtime/query/__tests__/executor-concurrency.test.d.ts.map +1 -0
  103. package/dist/runtime/query/__tests__/executor-concurrency.test.js +98 -0
  104. package/dist/runtime/query/__tests__/executor-concurrency.test.js.map +1 -0
  105. package/dist/runtime/query/__tests__/executor-plugin-hooks.test.js +38 -3
  106. package/dist/runtime/query/__tests__/executor-plugin-hooks.test.js.map +1 -1
  107. package/dist/runtime/query/__tests__/long-document-flow.test.d.ts +2 -0
  108. package/dist/runtime/query/__tests__/long-document-flow.test.d.ts.map +1 -0
  109. package/dist/runtime/query/__tests__/long-document-flow.test.js +154 -0
  110. package/dist/runtime/query/__tests__/long-document-flow.test.js.map +1 -0
  111. package/dist/runtime/query/__tests__/prompt.test.js +51 -2
  112. package/dist/runtime/query/__tests__/prompt.test.js.map +1 -1
  113. package/dist/runtime/query/__tests__/stream-recovery.test.d.ts +2 -0
  114. package/dist/runtime/query/__tests__/stream-recovery.test.d.ts.map +1 -0
  115. package/dist/runtime/query/__tests__/stream-recovery.test.js +126 -0
  116. package/dist/runtime/query/__tests__/stream-recovery.test.js.map +1 -0
  117. package/dist/runtime/query/continuation.d.ts +16 -0
  118. package/dist/runtime/query/continuation.d.ts.map +1 -0
  119. package/dist/runtime/query/continuation.js +16 -0
  120. package/dist/runtime/query/continuation.js.map +1 -0
  121. package/dist/runtime/query/executor.d.ts +3 -0
  122. package/dist/runtime/query/executor.d.ts.map +1 -1
  123. package/dist/runtime/query/executor.js +71 -3
  124. package/dist/runtime/query/executor.js.map +1 -1
  125. package/dist/runtime/query/index.d.ts +9 -0
  126. package/dist/runtime/query/index.d.ts.map +1 -1
  127. package/dist/runtime/query/index.js +42 -5
  128. package/dist/runtime/query/index.js.map +1 -1
  129. package/dist/runtime/query/iteration/index.d.ts +24 -0
  130. package/dist/runtime/query/iteration/index.d.ts.map +1 -1
  131. package/dist/runtime/query/iteration/index.js +326 -66
  132. package/dist/runtime/query/iteration/index.js.map +1 -1
  133. package/dist/runtime/query/iteration/phases/checkpoint.d.ts.map +1 -1
  134. package/dist/runtime/query/iteration/phases/checkpoint.js +2 -2
  135. package/dist/runtime/query/iteration/phases/checkpoint.js.map +1 -1
  136. package/dist/runtime/query/iteration/phases/compaction.d.ts +8 -0
  137. package/dist/runtime/query/iteration/phases/compaction.d.ts.map +1 -1
  138. package/dist/runtime/query/iteration/phases/compaction.js +84 -3
  139. package/dist/runtime/query/iteration/phases/compaction.js.map +1 -1
  140. package/dist/runtime/query/iteration/phases/context.d.ts +22 -0
  141. package/dist/runtime/query/iteration/phases/context.d.ts.map +1 -1
  142. package/dist/runtime/query/iteration/phases/context.js +53 -0
  143. package/dist/runtime/query/iteration/phases/context.js.map +1 -1
  144. package/dist/runtime/query/iteration/phases/hitl-abort-race.test.d.ts +2 -0
  145. package/dist/runtime/query/iteration/phases/hitl-abort-race.test.d.ts.map +1 -0
  146. package/dist/runtime/query/iteration/phases/hitl-abort-race.test.js +73 -0
  147. package/dist/runtime/query/iteration/phases/hitl-abort-race.test.js.map +1 -0
  148. package/dist/runtime/query/iteration/phases/hitl-answer-question.test.d.ts +2 -0
  149. package/dist/runtime/query/iteration/phases/hitl-answer-question.test.d.ts.map +1 -0
  150. package/dist/runtime/query/iteration/phases/hitl-answer-question.test.js +120 -0
  151. package/dist/runtime/query/iteration/phases/hitl-answer-question.test.js.map +1 -0
  152. package/dist/runtime/query/iteration/phases/tool-review.d.ts +1 -1
  153. package/dist/runtime/query/iteration/phases/tool-review.d.ts.map +1 -1
  154. package/dist/runtime/query/iteration/phases/tool-review.js +7 -2
  155. package/dist/runtime/query/iteration/phases/tool-review.js.map +1 -1
  156. package/dist/runtime/query/iteration/phases/working-memory-compaction.test.d.ts +19 -0
  157. package/dist/runtime/query/iteration/phases/working-memory-compaction.test.d.ts.map +1 -0
  158. package/dist/runtime/query/iteration/phases/working-memory-compaction.test.js +177 -0
  159. package/dist/runtime/query/iteration/phases/working-memory-compaction.test.js.map +1 -0
  160. package/dist/runtime/query/iteration/phases/working-memory.d.ts +31 -0
  161. package/dist/runtime/query/iteration/phases/working-memory.d.ts.map +1 -0
  162. package/dist/runtime/query/iteration/phases/working-memory.js +81 -0
  163. package/dist/runtime/query/iteration/phases/working-memory.js.map +1 -0
  164. package/dist/runtime/query/prompt.d.ts.map +1 -1
  165. package/dist/runtime/query/prompt.js +21 -1
  166. package/dist/runtime/query/prompt.js.map +1 -1
  167. package/dist/runtime/query/tooling.d.ts +1 -0
  168. package/dist/runtime/query/tooling.d.ts.map +1 -1
  169. package/dist/runtime/query/tooling.js +1 -0
  170. package/dist/runtime/query/tooling.js.map +1 -1
  171. package/dist/sandbox/provider/local.d.ts.map +1 -1
  172. package/dist/sandbox/provider/local.js +32 -1
  173. package/dist/sandbox/provider/local.js.map +1 -1
  174. package/dist/session/workspace/__tests__/shared-run.test.d.ts +2 -0
  175. package/dist/session/workspace/__tests__/shared-run.test.d.ts.map +1 -0
  176. package/dist/session/workspace/__tests__/shared-run.test.js +147 -0
  177. package/dist/session/workspace/__tests__/shared-run.test.js.map +1 -0
  178. package/dist/session/workspace/index.d.ts +2 -0
  179. package/dist/session/workspace/index.d.ts.map +1 -1
  180. package/dist/session/workspace/index.js +1 -0
  181. package/dist/session/workspace/index.js.map +1 -1
  182. package/dist/session/workspace/shared-run.d.ts +81 -0
  183. package/dist/session/workspace/shared-run.d.ts.map +1 -0
  184. package/dist/session/workspace/shared-run.js +252 -0
  185. package/dist/session/workspace/shared-run.js.map +1 -0
  186. package/dist/skills/loader.d.ts.map +1 -1
  187. package/dist/skills/loader.js +36 -6
  188. package/dist/skills/loader.js.map +1 -1
  189. package/dist/skills/loader.test.d.ts +2 -0
  190. package/dist/skills/loader.test.d.ts.map +1 -0
  191. package/dist/skills/loader.test.js +65 -0
  192. package/dist/skills/loader.test.js.map +1 -0
  193. package/dist/streaming/coalesce.test.js +1 -1
  194. package/dist/streaming/coalesce.test.js.map +1 -1
  195. package/dist/tools/builtins/__tests__/edit.test.d.ts +2 -0
  196. package/dist/tools/builtins/__tests__/edit.test.d.ts.map +1 -0
  197. package/dist/tools/builtins/__tests__/edit.test.js +38 -0
  198. package/dist/tools/builtins/__tests__/edit.test.js.map +1 -0
  199. package/dist/tools/builtins/__tests__/payload-budget.test.d.ts +2 -0
  200. package/dist/tools/builtins/__tests__/payload-budget.test.d.ts.map +1 -0
  201. package/dist/tools/builtins/__tests__/payload-budget.test.js +70 -0
  202. package/dist/tools/builtins/__tests__/payload-budget.test.js.map +1 -0
  203. package/dist/tools/builtins/__tests__/read-file.test.d.ts +2 -0
  204. package/dist/tools/builtins/__tests__/read-file.test.d.ts.map +1 -0
  205. package/dist/tools/builtins/__tests__/read-file.test.js +33 -0
  206. package/dist/tools/builtins/__tests__/read-file.test.js.map +1 -0
  207. package/dist/tools/builtins/__tests__/verify-outputs.test.d.ts +2 -0
  208. package/dist/tools/builtins/__tests__/verify-outputs.test.d.ts.map +1 -0
  209. package/dist/tools/builtins/__tests__/verify-outputs.test.js +52 -0
  210. package/dist/tools/builtins/__tests__/verify-outputs.test.js.map +1 -0
  211. package/dist/tools/builtins/__tests__/write-file.test.d.ts +2 -0
  212. package/dist/tools/builtins/__tests__/write-file.test.d.ts.map +1 -0
  213. package/dist/tools/builtins/__tests__/write-file.test.js +74 -0
  214. package/dist/tools/builtins/__tests__/write-file.test.js.map +1 -0
  215. package/dist/tools/builtins/bash.d.ts.map +1 -1
  216. package/dist/tools/builtins/bash.js +40 -7
  217. package/dist/tools/builtins/bash.js.map +1 -1
  218. package/dist/tools/builtins/edit.d.ts +5 -2
  219. package/dist/tools/builtins/edit.d.ts.map +1 -1
  220. package/dist/tools/builtins/edit.js +114 -18
  221. package/dist/tools/builtins/edit.js.map +1 -1
  222. package/dist/tools/builtins/index.d.ts +1 -0
  223. package/dist/tools/builtins/index.d.ts.map +1 -1
  224. package/dist/tools/builtins/index.js +13 -13
  225. package/dist/tools/builtins/index.js.map +1 -1
  226. package/dist/tools/builtins/read-file.d.ts +1 -0
  227. package/dist/tools/builtins/read-file.d.ts.map +1 -1
  228. package/dist/tools/builtins/read-file.js +73 -10
  229. package/dist/tools/builtins/read-file.js.map +1 -1
  230. package/dist/tools/builtins/search-tools.d.ts.map +1 -1
  231. package/dist/tools/builtins/search-tools.js +35 -7
  232. package/dist/tools/builtins/search-tools.js.map +1 -1
  233. package/dist/tools/builtins/verify-outputs.d.ts +5 -0
  234. package/dist/tools/builtins/verify-outputs.d.ts.map +1 -0
  235. package/dist/tools/builtins/verify-outputs.js +103 -0
  236. package/dist/tools/builtins/verify-outputs.js.map +1 -0
  237. package/dist/tools/builtins/write-file.d.ts +3 -2
  238. package/dist/tools/builtins/write-file.d.ts.map +1 -1
  239. package/dist/tools/builtins/write-file.js +72 -12
  240. package/dist/tools/builtins/write-file.js.map +1 -1
  241. package/dist/tools/coordinator/__tests__/agent.test.d.ts +15 -0
  242. package/dist/tools/coordinator/__tests__/agent.test.d.ts.map +1 -0
  243. package/dist/tools/coordinator/__tests__/agent.test.js +142 -0
  244. package/dist/tools/coordinator/__tests__/agent.test.js.map +1 -0
  245. package/dist/tools/coordinator/__tests__/approve-plan.test.d.ts +2 -0
  246. package/dist/tools/coordinator/__tests__/approve-plan.test.d.ts.map +1 -0
  247. package/dist/tools/coordinator/__tests__/approve-plan.test.js +114 -0
  248. package/dist/tools/coordinator/__tests__/approve-plan.test.js.map +1 -0
  249. package/dist/tools/coordinator/__tests__/ask-user-question.test.d.ts +2 -0
  250. package/dist/tools/coordinator/__tests__/ask-user-question.test.d.ts.map +1 -0
  251. package/dist/tools/coordinator/__tests__/ask-user-question.test.js +309 -0
  252. package/dist/tools/coordinator/__tests__/ask-user-question.test.js.map +1 -0
  253. package/dist/tools/coordinator/__tests__/task-list.test.d.ts +13 -0
  254. package/dist/tools/coordinator/__tests__/task-list.test.d.ts.map +1 -0
  255. package/dist/tools/coordinator/__tests__/task-list.test.js +162 -0
  256. package/dist/tools/coordinator/__tests__/task-list.test.js.map +1 -0
  257. package/dist/tools/coordinator/agent.d.ts +34 -0
  258. package/dist/tools/coordinator/agent.d.ts.map +1 -0
  259. package/dist/tools/coordinator/agent.js +107 -0
  260. package/dist/tools/coordinator/agent.js.map +1 -0
  261. package/dist/tools/coordinator/index.d.ts +15 -0
  262. package/dist/tools/coordinator/index.d.ts.map +1 -1
  263. package/dist/tools/coordinator/index.js +305 -35
  264. package/dist/tools/coordinator/index.js.map +1 -1
  265. package/dist/types/agent/base.d.ts +8 -0
  266. package/dist/types/agent/base.d.ts.map +1 -1
  267. package/dist/types/agent/index.d.ts +1 -0
  268. package/dist/types/agent/index.d.ts.map +1 -1
  269. package/dist/types/agent/index.js +1 -0
  270. package/dist/types/agent/index.js.map +1 -1
  271. package/dist/types/agent/reactive.d.ts +38 -0
  272. package/dist/types/agent/reactive.d.ts.map +1 -1
  273. package/dist/types/agent/supervisor.d.ts +32 -0
  274. package/dist/types/agent/supervisor.d.ts.map +1 -1
  275. package/dist/types/agent/working-memory.d.ts +29 -0
  276. package/dist/types/agent/working-memory.d.ts.map +1 -0
  277. package/dist/types/agent/working-memory.js +2 -0
  278. package/dist/types/agent/working-memory.js.map +1 -0
  279. package/dist/types/common/index.d.ts +10 -0
  280. package/dist/types/common/index.d.ts.map +1 -1
  281. package/dist/types/common/index.js +18 -0
  282. package/dist/types/common/index.js.map +1 -1
  283. package/dist/types/common/usage-merge.test.d.ts +2 -0
  284. package/dist/types/common/usage-merge.test.d.ts.map +1 -0
  285. package/dist/types/common/usage-merge.test.js +48 -0
  286. package/dist/types/common/usage-merge.test.js.map +1 -0
  287. package/dist/types/connector/mcp.d.ts +9 -2
  288. package/dist/types/connector/mcp.d.ts.map +1 -1
  289. package/dist/types/hitl/index.d.ts +42 -0
  290. package/dist/types/hitl/index.d.ts.map +1 -1
  291. package/dist/types/hitl/index.js +11 -0
  292. package/dist/types/hitl/index.js.map +1 -1
  293. package/dist/types/message/index.d.ts +22 -1
  294. package/dist/types/message/index.d.ts.map +1 -1
  295. package/dist/types/message/index.js +7 -2
  296. package/dist/types/message/index.js.map +1 -1
  297. package/dist/types/provider/chat.d.ts +11 -9
  298. package/dist/types/provider/chat.d.ts.map +1 -1
  299. package/dist/types/run/events.d.ts +6 -0
  300. package/dist/types/run/events.d.ts.map +1 -1
  301. package/dist/types/run/events.js.map +1 -1
  302. package/dist/types/sandbox/index.d.ts +193 -0
  303. package/dist/types/sandbox/index.d.ts.map +1 -1
  304. package/dist/types/sandbox/index.js.map +1 -1
  305. package/dist/types/skills/index.d.ts +2 -0
  306. package/dist/types/skills/index.d.ts.map +1 -1
  307. package/dist/types/tool/index.d.ts +22 -0
  308. package/dist/types/tool/index.d.ts.map +1 -1
  309. package/dist/types/toolset/index.d.ts +71 -0
  310. package/dist/types/toolset/index.d.ts.map +1 -0
  311. package/dist/types/toolset/index.js +2 -0
  312. package/dist/types/toolset/index.js.map +1 -0
  313. package/dist/types/workspace/index.d.ts +1 -0
  314. package/dist/types/workspace/index.d.ts.map +1 -1
  315. package/dist/types/workspace/shared-run.d.ts +61 -0
  316. package/dist/types/workspace/shared-run.d.ts.map +1 -0
  317. package/dist/types/workspace/shared-run.js +2 -0
  318. package/dist/types/workspace/shared-run.js.map +1 -0
  319. package/dist/verification/index.d.ts +1 -0
  320. package/dist/verification/index.d.ts.map +1 -1
  321. package/dist/verification/index.js +1 -0
  322. package/dist/verification/index.js.map +1 -1
  323. package/dist/verification/presets.d.ts +53 -0
  324. package/dist/verification/presets.d.ts.map +1 -0
  325. package/dist/verification/presets.js +70 -0
  326. package/dist/verification/presets.js.map +1 -0
  327. package/dist/verification/presets.test.d.ts +16 -0
  328. package/dist/verification/presets.test.d.ts.map +1 -0
  329. package/dist/verification/presets.test.js +79 -0
  330. package/dist/verification/presets.test.js.map +1 -0
  331. package/dist/version.d.ts.map +1 -1
  332. package/dist/version.js +25 -4
  333. package/dist/version.js.map +1 -1
  334. package/package.json +3 -2
  335. package/src/advisory/executor.test.ts +7 -4
  336. package/src/advisory/executor.ts +11 -2
  337. package/src/agents/ReactiveAgent.ts +7 -0
  338. package/src/agents/SupervisorAgent.ts +63 -16
  339. package/src/agents/__tests__/supervisor-ledger.test.ts +185 -0
  340. package/src/bridge/sse/mapper.test.ts +2 -2
  341. package/src/config/runtime.ts +9 -0
  342. package/src/connector/builtins/webhook.test.ts +21 -0
  343. package/src/connector/index.ts +1 -0
  344. package/src/connector/mcp/client.ts +4 -0
  345. package/src/connector/mcp/index.ts +1 -0
  346. package/src/connector/mcp/streamable-http.test.ts +169 -0
  347. package/src/connector/mcp/streamable-http.ts +152 -0
  348. package/src/constants/compaction/index.ts +8 -3
  349. package/src/constants/sandbox/index.ts +37 -0
  350. package/src/constants/tools/index.ts +33 -2
  351. package/src/manager/run/persistence.ts +34 -6
  352. package/src/persona/assembler.ts +43 -8
  353. package/src/provider/collect.test.ts +2 -2
  354. package/src/provider/collect.ts +4 -1
  355. package/src/public-runtime.ts +15 -1
  356. package/src/public-tools.ts +2 -0
  357. package/src/public-types.ts +7 -0
  358. package/src/registry/index.ts +7 -0
  359. package/src/registry/tool/execute.test.ts +211 -7
  360. package/src/registry/tool/execute.ts +199 -11
  361. package/src/registry/toolset/catalog.test.ts +165 -0
  362. package/src/registry/toolset/catalog.ts +283 -0
  363. package/src/runtime/query/__tests__/deferred-tools.test.ts +230 -0
  364. package/src/runtime/query/__tests__/executor-concurrency.test.ts +122 -0
  365. package/src/runtime/query/__tests__/executor-plugin-hooks.test.ts +48 -3
  366. package/src/runtime/query/__tests__/long-document-flow.test.ts +180 -0
  367. package/src/runtime/query/__tests__/prompt.test.ts +55 -2
  368. package/src/runtime/query/__tests__/stream-recovery.test.ts +156 -0
  369. package/src/runtime/query/continuation.ts +16 -0
  370. package/src/runtime/query/executor.ts +82 -13
  371. package/src/runtime/query/index.ts +58 -5
  372. package/src/runtime/query/iteration/index.ts +361 -74
  373. package/src/runtime/query/iteration/phases/checkpoint.ts +7 -2
  374. package/src/runtime/query/iteration/phases/compaction.ts +89 -3
  375. package/src/runtime/query/iteration/phases/context.ts +68 -0
  376. package/src/runtime/query/iteration/phases/hitl-abort-race.test.ts +86 -0
  377. package/src/runtime/query/iteration/phases/hitl-answer-question.test.ts +139 -0
  378. package/src/runtime/query/iteration/phases/tool-review.ts +7 -3
  379. package/src/runtime/query/iteration/phases/working-memory-compaction.test.ts +215 -0
  380. package/src/runtime/query/iteration/phases/working-memory.ts +86 -0
  381. package/src/runtime/query/prompt.ts +17 -1
  382. package/src/runtime/query/tooling.ts +2 -0
  383. package/src/sandbox/provider/local.ts +33 -0
  384. package/src/session/workspace/__tests__/shared-run.test.ts +181 -0
  385. package/src/session/workspace/index.ts +6 -0
  386. package/src/session/workspace/shared-run.ts +317 -0
  387. package/src/skills/loader.test.ts +89 -0
  388. package/src/skills/loader.ts +37 -6
  389. package/src/streaming/coalesce.test.ts +4 -4
  390. package/src/tools/builtins/__tests__/edit.test.ts +57 -0
  391. package/src/tools/builtins/__tests__/payload-budget.test.ts +92 -0
  392. package/src/tools/builtins/__tests__/read-file.test.ts +43 -0
  393. package/src/tools/builtins/__tests__/verify-outputs.test.ts +71 -0
  394. package/src/tools/builtins/__tests__/write-file.test.ts +97 -0
  395. package/src/tools/builtins/bash.ts +48 -7
  396. package/src/tools/builtins/edit.ts +162 -27
  397. package/src/tools/builtins/index.ts +13 -13
  398. package/src/tools/builtins/read-file.ts +81 -10
  399. package/src/tools/builtins/search-tools.ts +42 -7
  400. package/src/tools/builtins/verify-outputs.ts +126 -0
  401. package/src/tools/builtins/write-file.ts +83 -14
  402. package/src/tools/coordinator/__tests__/agent.test.ts +172 -0
  403. package/src/tools/coordinator/__tests__/approve-plan.test.ts +139 -0
  404. package/src/tools/coordinator/__tests__/ask-user-question.test.ts +370 -0
  405. package/src/tools/coordinator/__tests__/task-list.test.ts +182 -0
  406. package/src/tools/coordinator/agent.ts +157 -0
  407. package/src/tools/coordinator/index.ts +355 -39
  408. package/src/types/agent/base.ts +8 -0
  409. package/src/types/agent/index.ts +1 -0
  410. package/src/types/agent/reactive.ts +42 -0
  411. package/src/types/agent/supervisor.ts +36 -0
  412. package/src/types/agent/working-memory.ts +29 -0
  413. package/src/types/common/index.ts +19 -0
  414. package/src/types/common/usage-merge.test.ts +53 -0
  415. package/src/types/connector/mcp.ts +14 -2
  416. package/src/types/hitl/index.ts +52 -1
  417. package/src/types/message/index.ts +32 -2
  418. package/src/types/provider/chat.ts +12 -9
  419. package/src/types/run/events.ts +6 -0
  420. package/src/types/sandbox/index.ts +219 -0
  421. package/src/types/skills/index.ts +4 -0
  422. package/src/types/tool/index.ts +24 -0
  423. package/src/types/toolset/index.ts +86 -0
  424. package/src/types/workspace/index.ts +9 -0
  425. package/src/types/workspace/shared-run.ts +65 -0
  426. package/src/verification/index.ts +1 -0
  427. package/src/verification/presets.test.ts +112 -0
  428. package/src/verification/presets.ts +72 -0
  429. package/src/version.ts +26 -4
@@ -4,6 +4,13 @@ export type { ManagedRegistryConfig } from './ManagedRegistry.js'
4
4
 
5
5
  export { ToolRegistry } from './tool/execute.js'
6
6
  export type { ToolExecutionResult } from './tool/execute.js'
7
+ export {
8
+ ToolCatalog,
9
+ createToolCatalogFromRegistry,
10
+ loadingFromAvailability,
11
+ toolDefinitionToCatalogEntry,
12
+ } from './toolset/catalog.js'
13
+ export type { ToolCatalogFromRegistryOptions, ToolCatalogSearchOptions } from './toolset/catalog.js'
7
14
 
8
15
  export { ConnectorRegistry } from './connector/definitions.js'
9
16
  export { ScopedConnectorRegistry } from './connector/scoped.js'
@@ -20,16 +20,21 @@
20
20
  * reports true iff at least one tool is suspended.
21
21
  * - `getAvailability(name)` returns 'active' as a default even for
22
22
  * unknown names (this is non-obvious but is the current behavior).
23
- * - `searchDeferred(q)` is a case-insensitive filter against name OR
24
- * description of every DEFERRED tool.
23
+ * - `searchDeferred(q)` is a RANKED weighted search over DEFERRED tools:
24
+ * per meaningful term (≥3 chars, not a stop token) the score is
25
+ * exact-name 12 / name-substring 8 / description 5 / argument-name 3;
26
+ * results sort score-descending with name ties broken alphabetically.
27
+ * Generic/short tokens (`clawtool`, `tool`, CRUD verbs like `list`,
28
+ * `read`, …) are stopped so they can't over-activate the catalog.
25
29
  * - `assignTiers(mapping)` mutates `tool.tier` on existing tools;
26
30
  * throws via `getOrThrow` on unknown name; throws if the tier id
27
31
  * is not in `tierConfig.tiers`.
28
32
  * - `toTierGuidance` returns null without a guidanceTemplate; calls
29
33
  * the template with every defined tier otherwise.
30
34
  * - `toPromptSection`: returns '' when no active or deferred tools;
31
- * otherwise produces `<available_tools>` + `<deferred_tools>`
32
- * fragments.
35
+ * otherwise produces `<available_tools>` (name-only — descriptions
36
+ * already ride the runtime tools param) + `<deferred_tools>` (name +
37
+ * first-sentence hint ≤100 chars) fragments.
33
38
  * - `toLLMTools`: converts active + suspended tools (filtered by
34
39
  * `toolNames` if provided) into LLM tool schemas via
35
40
  * `zodToJsonSchema`. When `tierConfig.labelInDescription` is true,
@@ -84,6 +89,15 @@ describe('ToolRegistry — register + availability', () => {
84
89
  expect(r.getAvailability('b')).toBe('deferred')
85
90
  })
86
91
 
92
+ it('register overloads: array w/o state defaults active, (id, tool) form, bad id throws', () => {
93
+ const r = new ToolRegistry()
94
+ r.register([makeTool('arr')])
95
+ expect(r.getAvailability('arr')).toBe('active')
96
+ r.register('byid', makeTool('byid'))
97
+ expect(r.get('byid')).toBeDefined()
98
+ expect(() => r.register('oops', 'not-a-tool' as never)).toThrow(/requires a ToolDefinition/)
99
+ })
100
+
87
101
  it('getAvailability returns active for unknown names (current default)', () => {
88
102
  const r = new ToolRegistry()
89
103
  expect(r.getAvailability('never-registered')).toBe('active')
@@ -180,6 +194,79 @@ describe('ToolRegistry — searchDeferred', () => {
180
194
  expect(r.searchDeferred('does').map((t) => t.name)).toEqual(['alpha', 'beta'])
181
195
  expect(r.searchDeferred('gamma')).toEqual([])
182
196
  })
197
+
198
+ it('tokenizes a multi-term query so a batch of tool names each match', () => {
199
+ const r = new ToolRegistry()
200
+ r.register([makeTool('clawtool_A2aCard')], 'deferred')
201
+ r.register([makeTool('clawtool_PeerRegister')], 'deferred')
202
+ r.register([makeTool('clawtool_PeerList')], 'deferred')
203
+ r.register([makeTool('clawtool_Unrelated')], 'deferred')
204
+ // A whole-phrase substring match would find none of these. Equal
205
+ // scores tie-break alphabetically by name (deterministic ranking).
206
+ expect(r.searchDeferred('A2aCard PeerRegister PeerList').map((t) => t.name)).toEqual([
207
+ 'clawtool_A2aCard',
208
+ 'clawtool_PeerList',
209
+ 'clawtool_PeerRegister',
210
+ ])
211
+ expect(r.searchDeferred(' ')).toEqual([])
212
+ })
213
+
214
+ it('ranks exact name above name substring above description-only matches', () => {
215
+ const r = new ToolRegistry()
216
+ r.register([makeTool('release_notes', { description: 'Write deploy notes.' })], 'deferred')
217
+ r.register([makeTool('deploy_preview', { description: 'Stage a preview build.' })], 'deferred')
218
+ r.register([makeTool('deploy', { description: 'Ship the current build.' })], 'deferred')
219
+ expect(r.searchDeferred('deploy').map((t) => t.name)).toEqual([
220
+ 'deploy', // exact name → 12
221
+ 'deploy_preview', // name substring → 8
222
+ 'release_notes', // description only → 5
223
+ ])
224
+ })
225
+
226
+ it('indexes argument names so a parameter term can locate a tool', () => {
227
+ const r = new ToolRegistry()
228
+ r.register(
229
+ [
230
+ makeTool('send_invoice', {
231
+ inputSchema: z.object({ customerEmail: z.string(), amount: z.number() }),
232
+ }),
233
+ ],
234
+ 'deferred',
235
+ )
236
+ r.register([makeTool('send_reminder')], 'deferred')
237
+ expect(r.searchDeferred('customerEmail').map((t) => t.name)).toEqual(['send_invoice'])
238
+ })
239
+
240
+ it('stops generic CRUD verbs so they cannot activate catalog slices', () => {
241
+ const r = new ToolRegistry()
242
+ r.register(
243
+ [makeTool('list_deals', { description: 'List the deals in an account.' })],
244
+ 'deferred',
245
+ )
246
+ r.register([makeTool('list_workflows', { description: 'List workflows.' })], 'deferred')
247
+ r.register([makeTool('read_document', { description: 'Read a document body.' })], 'deferred')
248
+ // Bare CRUD verbs identify nothing.
249
+ expect(r.searchDeferred('list')).toEqual([])
250
+ expect(r.searchDeferred('read')).toEqual([])
251
+ expect(r.searchDeferred('create update delete')).toEqual([])
252
+ // The non-generic remainder carries the query.
253
+ expect(r.searchDeferred('list deals').map((t) => t.name)).toEqual(['list_deals'])
254
+ expect(r.searchDeferred('read document').map((t) => t.name)).toEqual(['read_document'])
255
+ })
256
+
257
+ it('does not over-activate on generic/shared tokens', () => {
258
+ const r = new ToolRegistry()
259
+ r.register([makeTool('clawtool_A2aCard', { description: 'peer card' })], 'deferred')
260
+ r.register([makeTool('clawtool_PeerList', { description: 'list peers' })], 'deferred')
261
+ r.register([makeTool('clawtool_WebSearch', { description: 'search the web' })], 'deferred')
262
+ // The shared "clawtool" prefix token must not drag in every tool.
263
+ expect(r.searchDeferred('clawtool WebSearch').map((t) => t.name)).toEqual([
264
+ 'clawtool_WebSearch',
265
+ ])
266
+ // A bare generic token identifies nothing — must not activate the catalog.
267
+ expect(r.searchDeferred('clawtool')).toEqual([])
268
+ expect(r.searchDeferred('tool')).toEqual([])
269
+ })
183
270
  })
184
271
 
185
272
  describe('ToolRegistry — tier mutation + guidance', () => {
@@ -227,10 +314,49 @@ describe('ToolRegistry — toPromptSection + toLLMTools', () => {
227
314
  r.register(makeTool('a'))
228
315
  r.register([makeTool('b')], 'deferred')
229
316
  const s = r.toPromptSection()
317
+ expect(s).toContain('<tool_runtime_contract>')
318
+ expect(s).toContain('runtime tools parameter')
230
319
  expect(s).toContain('<available_tools>')
231
- expect(s).toContain('- a: a tool')
320
+ // Active entries are NAME-ONLY: the description already rides the
321
+ // runtime tools param every request — repeating it double-bills.
322
+ expect(s).toContain('- a\n')
323
+ expect(s).not.toContain('- a: a tool')
232
324
  expect(s).toContain('<deferred_tools>')
233
- expect(s).toContain('- b')
325
+ expect(s).toContain('Deferred tools are discoverable')
326
+ // Deferred entries carry a one-line hint — their schema is off the
327
+ // wire, so the hint is the model's only capability signal.
328
+ expect(s).toContain('- b: b tool')
329
+ })
330
+
331
+ it('toPromptSection truncates deferred hints to the first sentence, capped at 100 chars', () => {
332
+ const r = new ToolRegistry()
333
+ r.register(
334
+ [
335
+ makeTool('two_sentences', {
336
+ description: 'Reads the document. Second sentence that must not appear.',
337
+ }),
338
+ makeTool('long_sentence', {
339
+ description: `${'x'.repeat(150)} end`,
340
+ }),
341
+ ],
342
+ 'deferred',
343
+ )
344
+ const s = r.toPromptSection()
345
+ expect(s).toContain('- two_sentences: Reads the document.')
346
+ expect(s).not.toContain('Second sentence')
347
+ const longLine = s.split('\n').find((line) => line.startsWith('- long_sentence:'))
348
+ expect(longLine).toBeDefined()
349
+ const hint = (longLine ?? '').replace('- long_sentence: ', '')
350
+ expect(hint.length).toBeLessThanOrEqual(100)
351
+ expect(hint.endsWith('…')).toBe(true)
352
+ })
353
+
354
+ it('toPromptSection references search_tools only when it is active', () => {
355
+ const r = new ToolRegistry()
356
+ r.register(makeTool('search_tools'))
357
+ r.register([makeTool('b')], 'deferred')
358
+ const s = r.toPromptSection()
359
+ expect(s).toContain('Use search_tools to load these before use')
234
360
  })
235
361
 
236
362
  it('toLLMTools: converts active + suspended tools', () => {
@@ -303,7 +429,41 @@ describe('ToolRegistry — execute', () => {
303
429
  )
304
430
  const result = await r.execute('strict', { required: 123 }, makeContext())
305
431
  expect(result.success).toBe(false)
306
- expect(result.error).toMatch(/Invalid input/)
432
+ expect(result.error).toMatch(/Validation failed for "strict"/)
433
+ expect(result.error).toContain('Expected string, received number')
434
+ })
435
+
436
+ it('empty-args validation lists required params with descriptions', async () => {
437
+ const r = new ToolRegistry()
438
+ r.register(
439
+ makeTool('needs', {
440
+ inputSchema: z.object({ q: z.string().describe('the query'), n: z.number() }),
441
+ }),
442
+ )
443
+ const result = await r.execute('needs', {}, makeContext())
444
+ expect(result.success).toBe(false)
445
+ expect(result.error).toMatch(/called with no arguments/)
446
+ expect(result.error).toContain('q: string — the query')
447
+ expect(result.error).toContain('n: number')
448
+ })
449
+
450
+ it('validation hint reports when there are no required params', async () => {
451
+ const r = new ToolRegistry()
452
+ r.register(makeTool('opt', { inputSchema: z.object({ k: z.string().optional() }) }))
453
+ const result = await r.execute('opt', { k: 123 }, makeContext())
454
+ expect(result.success).toBe(false)
455
+ expect(result.error).toContain('No required parameters known.')
456
+ })
457
+
458
+ it('validation hint tolerates a schema it cannot introspect', async () => {
459
+ const r = new ToolRegistry()
460
+ const bogusSchema = {
461
+ safeParse: () => ({ success: false, error: { issues: [{ path: [], message: 'nope' }] } }),
462
+ }
463
+ r.register(makeTool('weird', { inputSchema: bogusSchema as never }))
464
+ const result = await r.execute('weird', { a: 1 }, makeContext())
465
+ expect(result.success).toBe(false)
466
+ expect(result.error).toContain('Could not introspect required parameters.')
307
467
  })
308
468
 
309
469
  it('wraps thrown errors in the execute function', async () => {
@@ -320,6 +480,50 @@ describe('ToolRegistry — execute', () => {
320
480
  expect(result.error).toMatch(/execution failed: boom/)
321
481
  })
322
482
 
483
+ it('wraps a non-Error throw', async () => {
484
+ const r = new ToolRegistry()
485
+ r.register(
486
+ makeTool('throws-string', {
487
+ async execute() {
488
+ throw 'plain string failure'
489
+ },
490
+ }),
491
+ )
492
+ const result = await r.execute('throws-string', {}, makeContext())
493
+ expect(result.success).toBe(false)
494
+ expect(result.error).toMatch(/execution failed/)
495
+ })
496
+
497
+ it('passes through a tool result that is unsuccessful with an error', async () => {
498
+ const r = new ToolRegistry()
499
+ r.register(
500
+ makeTool('soft-fail', {
501
+ async execute() {
502
+ return { success: false, output: '', error: 'soft failure' }
503
+ },
504
+ }),
505
+ )
506
+ const result = await r.execute('soft-fail', {}, makeContext())
507
+ expect(result.success).toBe(false)
508
+ expect(result.error).toBe('soft failure')
509
+ })
510
+
511
+ it('blocks a non-read-only tool in plan mode (no isReadOnly hint)', async () => {
512
+ const r = new ToolRegistry()
513
+ const execute = vi.fn(async () => ({ success: true, output: 'ok' }))
514
+ r.register(makeTool('mutate', { execute }))
515
+ const result = await r.execute(
516
+ 'mutate',
517
+ {},
518
+ makeContext({
519
+ permissionContext: { mode: 'plan', runId: 'run_1', workingDirectory: '/tmp' },
520
+ }),
521
+ )
522
+ expect(result.success).toBe(false)
523
+ expect(result.error).toMatch(/plan mode/)
524
+ expect(execute).not.toHaveBeenCalled()
525
+ })
526
+
323
527
  it('returns the tool result on happy path', async () => {
324
528
  const r = new ToolRegistry()
325
529
  r.register(makeTool('good'))
@@ -16,6 +16,39 @@ import { ManagedRegistry } from '../ManagedRegistry.js'
16
16
 
17
17
  export type { ToolExecutionResult }
18
18
 
19
+ // Tokens too generic to identify a tool by name — ignored when matching a
20
+ // batched `search_tools` query so they can't activate the whole catalog
21
+ // (every bridged tool name shares the `clawtool` prefix, for instance).
22
+ // Generic CRUD verbs are stopped too: a query like "list deals" must rank
23
+ // by "deals", not token-match every `list_*` tool in the deferred catalog.
24
+ const SEARCH_STOP_TOKENS = new Set([
25
+ 'clawtool',
26
+ 'tool',
27
+ 'tools',
28
+ 'mcp',
29
+ 'the',
30
+ 'and',
31
+ 'for',
32
+ 'use',
33
+ 'list',
34
+ 'read',
35
+ 'create',
36
+ 'update',
37
+ 'get',
38
+ 'find',
39
+ 'delete',
40
+ 'search',
41
+ ])
42
+
43
+ // Weighted-scoring weights mirroring ToolCatalog.searchTools (the richer,
44
+ // otherwise-unused catalog scorer): exact name 12, name substring 8,
45
+ // description 5 — extended here with argument-name indexing (3), following
46
+ // Anthropic's tool-search practice of searching argument names too.
47
+ const SEARCH_WEIGHT_NAME_EXACT = 12
48
+ const SEARCH_WEIGHT_NAME_PARTIAL = 8
49
+ const SEARCH_WEIGHT_DESCRIPTION = 5
50
+ const SEARCH_WEIGHT_ARGUMENT = 3
51
+
19
52
  export class ToolRegistry extends ManagedRegistry<ToolDefinition> {
20
53
  private availability: Map<string, ToolAvailability> = new Map()
21
54
  private tierConfig?: ToolTierConfig
@@ -113,11 +146,58 @@ export class ToolRegistry extends ManagedRegistry<ToolDefinition> {
113
146
  return this.availability.get(name) ?? 'active'
114
147
  }
115
148
 
149
+ /**
150
+ * Ranked lexical search over DEFERRED tools, score-descending (ties broken
151
+ * by name) so callers can cap activation at a top-k. Each meaningful query
152
+ * term (≥3 chars, not a stop token) is scored against the tool name
153
+ * (exact/substring), description, and argument names; only tools with a
154
+ * positive score are returned. Description matching is safe here precisely
155
+ * because the result is RANKED — the `search_tools` builtin activates only
156
+ * the top slice, so a shared word can no longer drag in the whole catalog.
157
+ *
158
+ * PARKED (phase 5 of the tool-loading plan): an embedding-backed semantic
159
+ * upgrade was evaluated and deliberately NOT built — at ≤~35 deferred
160
+ * in-house tools with distinct names, weighted lexical scoring sits inside
161
+ * the literature's safe zone, and a weak retriever underperforms no
162
+ * retriever at all. Revisit only when (a) the deferred catalog grows past
163
+ * ~75-100 tools (realistic driver: connector-MCP growth), or (b) telemetry
164
+ * shows a search_tools miss-rate above ~10%. Sticky activation is also
165
+ * deliberate: activating inserts the schema into the tools array at its
166
+ * registry position (a one-time prompt-cache prefix bust); re-defer/TTL
167
+ * would churn that prefix repeatedly and is rejected.
168
+ */
116
169
  searchDeferred(query: string): ToolDefinition[] {
117
- const q = query.toLowerCase()
118
- return this.getByAvailability(['deferred']).filter(
119
- (t) => t.name.toLowerCase().includes(q) || t.description.toLowerCase().includes(q),
120
- )
170
+ const q = query.toLowerCase().trim()
171
+ if (q.length === 0) return []
172
+ const terms = q.split(/\s+/).filter((tok) => tok.length >= 3 && !SEARCH_STOP_TOKENS.has(tok))
173
+ if (terms.length === 0) return []
174
+
175
+ const scored: Array<{ tool: ToolDefinition; score: number }> = []
176
+ for (const tool of this.getByAvailability(['deferred'])) {
177
+ const name = tool.name.toLowerCase()
178
+ const description = tool.description.toLowerCase()
179
+ const argumentNames = listArgumentNames(tool)
180
+ let score = 0
181
+ for (const term of terms) {
182
+ if (name === term) {
183
+ score += SEARCH_WEIGHT_NAME_EXACT
184
+ } else if (name.includes(term)) {
185
+ score += SEARCH_WEIGHT_NAME_PARTIAL
186
+ }
187
+ if (description.includes(term)) {
188
+ score += SEARCH_WEIGHT_DESCRIPTION
189
+ }
190
+ if (argumentNames.some((arg) => arg.includes(term))) {
191
+ score += SEARCH_WEIGHT_ARGUMENT
192
+ }
193
+ }
194
+ if (score > 0) {
195
+ scored.push({ tool, score })
196
+ }
197
+ }
198
+
199
+ scored.sort((a, b) => b.score - a.score || a.tool.name.localeCompare(b.tool.name))
200
+ return scored.map((entry) => entry.tool)
121
201
  }
122
202
 
123
203
  assignTiers(mapping: Record<string, string>): void {
@@ -149,21 +229,38 @@ export class ToolRegistry extends ManagedRegistry<ToolDefinition> {
149
229
  const deferred = this.getByAvailability(['deferred'], toolNames)
150
230
 
151
231
  const parts: string[] = []
232
+ const contractNote = `<tool_runtime_contract>
233
+ Executable tool names, descriptions, and JSON input schemas are attached through the runtime tools parameter. Treat that runtime schema as authoritative; this prompt section is a discoverability summary only.
234
+ </tool_runtime_contract>`
152
235
 
153
236
  if (active.length > 0) {
154
- const entries = active.map((t) => `- ${t.name}: ${t.description}`).join('\n')
237
+ // Name-only: every active tool's full description + JSON schema
238
+ // already rides the runtime tools parameter on each request —
239
+ // repeating descriptions here double-bills the same tokens.
240
+ const entries = active.map((t) => `- ${t.name}`).join('\n')
155
241
  parts.push(`<available_tools>\n${entries}\n</available_tools>`)
156
242
  }
157
243
 
158
244
  if (deferred.length > 0) {
159
- const entries = deferred.map((t) => `- ${t.name}`).join('\n')
160
- parts.push(
161
- `<deferred_tools>\nUse search_tools to load these before use:\n${entries}\n</deferred_tools>`,
162
- )
245
+ // Name + one-line hint: deferred schemas stay off the wire, so the
246
+ // hint is the model's only signal of what a deferred tool does. A
247
+ // bare name list caused a real discovery failure in production
248
+ // (the agent never found read_document behind search_tools).
249
+ const entries = deferred
250
+ .map((t) => {
251
+ const hint = toolDiscoveryHint(t.description)
252
+ return hint.length > 0 ? `- ${t.name}: ${hint}` : `- ${t.name}`
253
+ })
254
+ .join('\n')
255
+ const deferredIntro =
256
+ this.has('search_tools') && this.getAvailability('search_tools') === 'active'
257
+ ? 'Use search_tools to load these before use:'
258
+ : 'Deferred tools are discoverable but not executable until the runtime activates them:'
259
+ parts.push(`<deferred_tools>\n${deferredIntro}\n${entries}\n</deferred_tools>`)
163
260
  }
164
261
 
165
262
  if (parts.length === 0) return ''
166
- return parts.join('\n\n')
263
+ return [contractNote, ...parts].join('\n\n')
167
264
  }
168
265
 
169
266
  toLLMTools(toolNames?: string[]): LLMToolSchema[] {
@@ -254,8 +351,33 @@ export class ToolRegistry extends ManagedRegistry<ToolDefinition> {
254
351
  .map((i) => `${i.path.join('.')}: ${i.message}`)
255
352
  .join('; ')
256
353
 
354
+ // Distinguish "model sent an empty/no-arg call" from
355
+ // "model sent partial args" — the first is most often a
356
+ // streaming hiccup or a definition-test ping (Anthropic
357
+ // occasionally pings tool surfaces with `{}` while the
358
+ // schema is still loading), the second is a genuine
359
+ // programming mistake by the model. The model self-
360
+ // corrects MUCH more reliably when the error tells it
361
+ // (a) which fields are required, (b) their types, and
362
+ // (c) a minimal example call. Without these hints the
363
+ // downstream UI just shows a red "Failed" row and the
364
+ // model rarely retries with the right args.
365
+ const isEmptyInput =
366
+ rawInput === null ||
367
+ rawInput === undefined ||
368
+ (typeof rawInput === 'object' &&
369
+ !Array.isArray(rawInput) &&
370
+ Object.keys(rawInput as Record<string, unknown>).length === 0)
371
+
372
+ const requiredHint = describeRequiredInput(tool.inputSchema)
373
+
374
+ const enrichedMessage = isEmptyInput
375
+ ? `Tool "${toolName}" was called with no arguments. ${requiredHint} Retry the call with the required parameters populated.`
376
+ : `Validation failed for "${toolName}": ${errorMessage}. ${requiredHint}`
377
+
257
378
  this.log.error(`Tool input validation failed: ${toolName}`, {
258
379
  errors: errorMessage,
380
+ empty: isEmptyInput,
259
381
  })
260
382
 
261
383
  span.setAttributes({
@@ -268,7 +390,7 @@ export class ToolRegistry extends ManagedRegistry<ToolDefinition> {
268
390
  return {
269
391
  success: false,
270
392
  output: '',
271
- error: `Invalid input for tool "${toolName}": ${errorMessage}`,
393
+ error: enrichedMessage,
272
394
  }
273
395
  }
274
396
 
@@ -319,3 +441,69 @@ export class ToolRegistry extends ManagedRegistry<ToolDefinition> {
319
441
  return candidates.filter((t) => states.includes(this.getAvailability(t.name)))
320
442
  }
321
443
  }
444
+
445
+ /**
446
+ * One-line discoverability hint for a deferred tool: the first sentence of
447
+ * its description, capped at ~100 chars. Used for the `<deferred_tools>`
448
+ * prompt listing and for `search_tools` near-miss suggestions, where the
449
+ * full description would re-import the token weight deferral avoids.
450
+ */
451
+ export function toolDiscoveryHint(description: string, maxLength = 100): string {
452
+ const normalized = description.trim().replace(/\s+/g, ' ')
453
+ if (normalized.length === 0) return ''
454
+ const sentenceMatch = normalized.match(/^.*?[.!?](?=\s|$)/)
455
+ const sentence = sentenceMatch ? sentenceMatch[0] : normalized
456
+ if (sentence.length <= maxLength) return sentence
457
+ return `${sentence.slice(0, maxLength - 1).trimEnd()}…`
458
+ }
459
+
460
+ /**
461
+ * Lower-cased argument (property) names of a tool's input schema, used by
462
+ * `searchDeferred` ranking. Walks the JSON-Schema rendering (already a
463
+ * registration dependency) instead of Zod internals; opaque schemas simply
464
+ * contribute no argument matches.
465
+ */
466
+ function listArgumentNames(tool: ToolDefinition): string[] {
467
+ try {
468
+ const json = zodToJsonSchema(tool.inputSchema, {
469
+ target: 'jsonSchema7',
470
+ $refStrategy: 'none',
471
+ }) as { properties?: Record<string, unknown> }
472
+ return Object.keys(json.properties ?? {}).map((key) => key.toLowerCase())
473
+ } catch {
474
+ return []
475
+ }
476
+ }
477
+
478
+ /**
479
+ * Build a one-sentence "Required: <field>: <type>, <field>: <type>"
480
+ * hint from a Zod schema, used to enrich tool-input validation
481
+ * errors so the model can self-correct without round-tripping the
482
+ * full JSON schema again. Walks the schema's JSON-Schema rendering
483
+ * (already a dependency for tool registration) so we don't have to
484
+ * branch over Zod's internal type tree.
485
+ *
486
+ * Returns a fallback string for opaque/non-object schemas — the
487
+ * caller still ships the raw Zod issues separately, so the hint
488
+ * here is bonus context, not the only signal.
489
+ */
490
+ function describeRequiredInput(schema: { _def?: unknown }): string {
491
+ try {
492
+ const json = zodToJsonSchema(schema as never) as {
493
+ properties?: Record<string, { type?: string; description?: string }>
494
+ required?: string[]
495
+ }
496
+ const required = json.required ?? []
497
+ if (required.length === 0) return 'No required parameters known.'
498
+ const props = json.properties ?? {}
499
+ const lines = required.map((name) => {
500
+ const def = props[name] ?? {}
501
+ const type = def.type ?? 'value'
502
+ const desc = def.description ? ` — ${def.description}` : ''
503
+ return `${name}: ${type}${desc}`
504
+ })
505
+ return `Required: ${lines.join(', ')}.`
506
+ } catch {
507
+ return 'Could not introspect required parameters.'
508
+ }
509
+ }