@namzu/sdk 31.1.0 → 33.0.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 (355) hide show
  1. package/CHANGELOG.md +188 -0
  2. package/dist/agents/ReactiveAgent.d.ts.map +1 -1
  3. package/dist/agents/ReactiveAgent.js +4 -0
  4. package/dist/agents/ReactiveAgent.js.map +1 -1
  5. package/dist/agents/SupervisorAgent.d.ts.map +1 -1
  6. package/dist/agents/SupervisorAgent.js +4 -0
  7. package/dist/agents/SupervisorAgent.js.map +1 -1
  8. package/dist/agents/runAgent.d.ts +4 -0
  9. package/dist/agents/runAgent.d.ts.map +1 -1
  10. package/dist/agents/runAgent.js +4 -0
  11. package/dist/agents/runAgent.js.map +1 -1
  12. package/dist/authorization/gate.d.ts +1 -1
  13. package/dist/authorization/gate.js +1 -1
  14. package/dist/connector/index.d.ts +1 -1
  15. package/dist/connector/index.d.ts.map +1 -1
  16. package/dist/connector/index.js +1 -1
  17. package/dist/connector/index.js.map +1 -1
  18. package/dist/connector/mcp/adapter.d.ts.map +1 -1
  19. package/dist/connector/mcp/adapter.js +71 -16
  20. package/dist/connector/mcp/adapter.js.map +1 -1
  21. package/dist/connector/mcp/client.d.ts.map +1 -1
  22. package/dist/connector/mcp/client.js +3 -2
  23. package/dist/connector/mcp/client.js.map +1 -1
  24. package/dist/connector/mcp/http-redirect.d.ts +17 -0
  25. package/dist/connector/mcp/http-redirect.d.ts.map +1 -0
  26. package/dist/connector/mcp/http-redirect.js +31 -0
  27. package/dist/connector/mcp/http-redirect.js.map +1 -0
  28. package/dist/connector/mcp/http-sse.d.ts.map +1 -1
  29. package/dist/connector/mcp/http-sse.js +5 -0
  30. package/dist/connector/mcp/http-sse.js.map +1 -1
  31. package/dist/connector/mcp/image-admission.d.ts +16 -0
  32. package/dist/connector/mcp/image-admission.d.ts.map +1 -0
  33. package/dist/connector/mcp/image-admission.js +288 -0
  34. package/dist/connector/mcp/image-admission.js.map +1 -0
  35. package/dist/connector/mcp/stdio.d.ts +13 -0
  36. package/dist/connector/mcp/stdio.d.ts.map +1 -1
  37. package/dist/connector/mcp/stdio.js +66 -23
  38. package/dist/connector/mcp/stdio.js.map +1 -1
  39. package/dist/connector/mcp/streamable-http.d.ts.map +1 -1
  40. package/dist/connector/mcp/streamable-http.js +3 -0
  41. package/dist/connector/mcp/streamable-http.js.map +1 -1
  42. package/dist/constants/tools/index.js +1 -1
  43. package/dist/constants/tools/index.js.map +1 -1
  44. package/dist/directory/derive-supervisor.d.ts.map +1 -1
  45. package/dist/directory/derive-supervisor.js +5 -0
  46. package/dist/directory/derive-supervisor.js.map +1 -1
  47. package/dist/directory/derive.d.ts.map +1 -1
  48. package/dist/directory/derive.js +5 -0
  49. package/dist/directory/derive.js.map +1 -1
  50. package/dist/directory/load.d.ts.map +1 -1
  51. package/dist/directory/load.js +1 -0
  52. package/dist/directory/load.js.map +1 -1
  53. package/dist/directory/types.d.ts +2 -0
  54. package/dist/directory/types.d.ts.map +1 -1
  55. package/dist/execution/base.d.ts +13 -0
  56. package/dist/execution/base.d.ts.map +1 -1
  57. package/dist/execution/base.js +103 -8
  58. package/dist/execution/base.js.map +1 -1
  59. package/dist/execution/code-runtime/types.d.ts +11 -1
  60. package/dist/execution/code-runtime/types.d.ts.map +1 -1
  61. package/dist/execution/code-runtime/types.js.map +1 -1
  62. package/dist/execution/code-runtime/worker.d.ts.map +1 -1
  63. package/dist/execution/code-runtime/worker.js +67 -9
  64. package/dist/execution/code-runtime/worker.js.map +1 -1
  65. package/dist/execution/errors.d.ts +12 -0
  66. package/dist/execution/errors.d.ts.map +1 -0
  67. package/dist/execution/errors.js +21 -0
  68. package/dist/execution/errors.js.map +1 -0
  69. package/dist/execution/factory.d.ts.map +1 -1
  70. package/dist/execution/factory.js +1 -0
  71. package/dist/execution/factory.js.map +1 -1
  72. package/dist/execution/hybrid.d.ts +5 -0
  73. package/dist/execution/hybrid.d.ts.map +1 -1
  74. package/dist/execution/hybrid.js +36 -16
  75. package/dist/execution/hybrid.js.map +1 -1
  76. package/dist/execution/index.d.ts +1 -0
  77. package/dist/execution/index.d.ts.map +1 -1
  78. package/dist/execution/index.js +1 -0
  79. package/dist/execution/index.js.map +1 -1
  80. package/dist/execution/local.d.ts +13 -0
  81. package/dist/execution/local.d.ts.map +1 -1
  82. package/dist/execution/local.js +145 -19
  83. package/dist/execution/local.js.map +1 -1
  84. package/dist/execution/output.d.ts +27 -0
  85. package/dist/execution/output.d.ts.map +1 -0
  86. package/dist/execution/output.js +105 -0
  87. package/dist/execution/output.js.map +1 -0
  88. package/dist/execution/remote.d.ts +26 -2
  89. package/dist/execution/remote.d.ts.map +1 -1
  90. package/dist/execution/remote.js +86 -15
  91. package/dist/execution/remote.js.map +1 -1
  92. package/dist/manager/agent/lifecycle.d.ts.map +1 -1
  93. package/dist/manager/agent/lifecycle.js +1 -0
  94. package/dist/manager/agent/lifecycle.js.map +1 -1
  95. package/dist/plugin/lifecycle.d.ts.map +1 -1
  96. package/dist/plugin/lifecycle.js +9 -3
  97. package/dist/plugin/lifecycle.js.map +1 -1
  98. package/dist/process/kill-tree.d.ts +11 -13
  99. package/dist/process/kill-tree.d.ts.map +1 -1
  100. package/dist/process/kill-tree.js +11 -13
  101. package/dist/process/kill-tree.js.map +1 -1
  102. package/dist/provider/errors.d.ts +1 -0
  103. package/dist/provider/errors.d.ts.map +1 -1
  104. package/dist/provider/errors.js +39 -1
  105. package/dist/provider/errors.js.map +1 -1
  106. package/dist/provider/fallback.d.ts.map +1 -1
  107. package/dist/provider/fallback.js +31 -0
  108. package/dist/provider/fallback.js.map +1 -1
  109. package/dist/provider/idle-timeout.d.ts.map +1 -1
  110. package/dist/provider/idle-timeout.js +5 -0
  111. package/dist/provider/idle-timeout.js.map +1 -1
  112. package/dist/provider/retry.d.ts.map +1 -1
  113. package/dist/provider/retry.js +5 -0
  114. package/dist/provider/retry.js.map +1 -1
  115. package/dist/public-runtime.d.ts +7 -5
  116. package/dist/public-runtime.d.ts.map +1 -1
  117. package/dist/public-runtime.js +9 -4
  118. package/dist/public-runtime.js.map +1 -1
  119. package/dist/public-types.d.ts +2 -1
  120. package/dist/public-types.d.ts.map +1 -1
  121. package/dist/registry/tool/execute.d.ts +7 -1
  122. package/dist/registry/tool/execute.d.ts.map +1 -1
  123. package/dist/registry/tool/execute.js +201 -54
  124. package/dist/registry/tool/execute.js.map +1 -1
  125. package/dist/run/command-gate.d.ts.map +1 -1
  126. package/dist/run/command-gate.js +11 -0
  127. package/dist/run/command-gate.js.map +1 -1
  128. package/dist/run/reporter.d.ts.map +1 -1
  129. package/dist/run/reporter.js +6 -1
  130. package/dist/run/reporter.js.map +1 -1
  131. package/dist/run/workspace-fingerprint.d.ts +4 -4
  132. package/dist/run/workspace-fingerprint.d.ts.map +1 -1
  133. package/dist/run/workspace-fingerprint.js +6 -4
  134. package/dist/run/workspace-fingerprint.js.map +1 -1
  135. package/dist/runtime/bidi/index.d.ts +1 -1
  136. package/dist/runtime/bidi/index.d.ts.map +1 -1
  137. package/dist/runtime/bidi/index.js +1 -1
  138. package/dist/runtime/bidi/index.js.map +1 -1
  139. package/dist/runtime/bidi/session.d.ts +19 -0
  140. package/dist/runtime/bidi/session.d.ts.map +1 -1
  141. package/dist/runtime/bidi/session.js +150 -26
  142. package/dist/runtime/bidi/session.js.map +1 -1
  143. package/dist/runtime/query/executor.d.ts +43 -1
  144. package/dist/runtime/query/executor.d.ts.map +1 -1
  145. package/dist/runtime/query/executor.js +824 -174
  146. package/dist/runtime/query/executor.js.map +1 -1
  147. package/dist/runtime/query/index.d.ts +5 -0
  148. package/dist/runtime/query/index.d.ts.map +1 -1
  149. package/dist/runtime/query/index.js +47 -4
  150. package/dist/runtime/query/index.js.map +1 -1
  151. package/dist/runtime/query/iteration/index.d.ts +1 -0
  152. package/dist/runtime/query/iteration/index.d.ts.map +1 -1
  153. package/dist/runtime/query/iteration/index.js +34 -14
  154. package/dist/runtime/query/iteration/index.js.map +1 -1
  155. package/dist/runtime/query/iteration/phases/advisory.js +2 -2
  156. package/dist/runtime/query/iteration/phases/advisory.js.map +1 -1
  157. package/dist/runtime/query/iteration/phases/tool-review.d.ts.map +1 -1
  158. package/dist/runtime/query/iteration/phases/tool-review.js +84 -22
  159. package/dist/runtime/query/iteration/phases/tool-review.js.map +1 -1
  160. package/dist/runtime/query/iteration/provider-rejected-image.d.ts +13 -0
  161. package/dist/runtime/query/iteration/provider-rejected-image.d.ts.map +1 -0
  162. package/dist/runtime/query/iteration/provider-rejected-image.js +91 -0
  163. package/dist/runtime/query/iteration/provider-rejected-image.js.map +1 -0
  164. package/dist/runtime/query/iteration/stream-turn.d.ts +4 -1
  165. package/dist/runtime/query/iteration/stream-turn.d.ts.map +1 -1
  166. package/dist/runtime/query/iteration/stream-turn.js +7 -3
  167. package/dist/runtime/query/iteration/stream-turn.js.map +1 -1
  168. package/dist/runtime/query/request-rich-content.d.ts +13 -0
  169. package/dist/runtime/query/request-rich-content.d.ts.map +1 -1
  170. package/dist/runtime/query/request-rich-content.js +173 -17
  171. package/dist/runtime/query/request-rich-content.js.map +1 -1
  172. package/dist/runtime/query/result.d.ts.map +1 -1
  173. package/dist/runtime/query/result.js +1 -0
  174. package/dist/runtime/query/result.js.map +1 -1
  175. package/dist/runtime/query/resume-pending.d.ts +5 -1
  176. package/dist/runtime/query/resume-pending.d.ts.map +1 -1
  177. package/dist/runtime/query/resume-pending.js +66 -1
  178. package/dist/runtime/query/resume-pending.js.map +1 -1
  179. package/dist/runtime/query/tool-output-budget.d.ts.map +1 -1
  180. package/dist/runtime/query/tool-output-budget.js +45 -16
  181. package/dist/runtime/query/tool-output-budget.js.map +1 -1
  182. package/dist/runtime/query/tooling.d.ts +6 -0
  183. package/dist/runtime/query/tooling.d.ts.map +1 -1
  184. package/dist/runtime/query/tooling.js +4 -0
  185. package/dist/runtime/query/tooling.js.map +1 -1
  186. package/dist/sandbox/provider/local.d.ts.map +1 -1
  187. package/dist/sandbox/provider/local.js +193 -41
  188. package/dist/sandbox/provider/local.js.map +1 -1
  189. package/dist/scheduler/delegating.d.ts +2 -1
  190. package/dist/scheduler/delegating.d.ts.map +1 -1
  191. package/dist/scheduler/delegating.js +6 -5
  192. package/dist/scheduler/delegating.js.map +1 -1
  193. package/dist/scheduler/local.d.ts +2 -1
  194. package/dist/scheduler/local.d.ts.map +1 -1
  195. package/dist/scheduler/local.js +2 -2
  196. package/dist/scheduler/local.js.map +1 -1
  197. package/dist/session/workspace/driver.d.ts +12 -4
  198. package/dist/session/workspace/driver.d.ts.map +1 -1
  199. package/dist/session/workspace/git-worktree.d.ts +17 -3
  200. package/dist/session/workspace/git-worktree.d.ts.map +1 -1
  201. package/dist/session/workspace/git-worktree.js +153 -34
  202. package/dist/session/workspace/git-worktree.js.map +1 -1
  203. package/dist/skills/registry.d.ts +15 -0
  204. package/dist/skills/registry.d.ts.map +1 -1
  205. package/dist/skills/registry.js +33 -0
  206. package/dist/skills/registry.js.map +1 -1
  207. package/dist/store/attachment/index.d.ts +24 -2
  208. package/dist/store/attachment/index.d.ts.map +1 -1
  209. package/dist/store/attachment/index.js +52 -5
  210. package/dist/store/attachment/index.js.map +1 -1
  211. package/dist/tools/builtins/computer-use.d.ts.map +1 -1
  212. package/dist/tools/builtins/computer-use.js +39 -2
  213. package/dist/tools/builtins/computer-use.js.map +1 -1
  214. package/dist/tools/builtins/lsp.d.ts +1 -1
  215. package/dist/tools/builtins/run-code.d.ts.map +1 -1
  216. package/dist/tools/builtins/run-code.js +24 -16
  217. package/dist/tools/builtins/run-code.js.map +1 -1
  218. package/dist/tools/builtins/skill.d.ts +2 -1
  219. package/dist/tools/builtins/skill.d.ts.map +1 -1
  220. package/dist/tools/builtins/skill.js +250 -6
  221. package/dist/tools/builtins/skill.js.map +1 -1
  222. package/dist/tools/coordinator/agent.d.ts.map +1 -1
  223. package/dist/tools/coordinator/agent.js +100 -30
  224. package/dist/tools/coordinator/agent.js.map +1 -1
  225. package/dist/types/agent/base.d.ts +4 -0
  226. package/dist/types/agent/base.d.ts.map +1 -1
  227. package/dist/types/agent/factory.d.ts +1 -0
  228. package/dist/types/agent/factory.d.ts.map +1 -1
  229. package/dist/types/agent/manager.d.ts +1 -1
  230. package/dist/types/agent/manager.d.ts.map +1 -1
  231. package/dist/types/agent/scheduler.d.ts +10 -1
  232. package/dist/types/agent/scheduler.d.ts.map +1 -1
  233. package/dist/types/authorization/index.d.ts +12 -12
  234. package/dist/types/bidi/index.d.ts +19 -2
  235. package/dist/types/bidi/index.d.ts.map +1 -1
  236. package/dist/types/computer-use/index.d.ts +18 -0
  237. package/dist/types/computer-use/index.d.ts.map +1 -1
  238. package/dist/types/connector/execution-context.d.ts +3 -1
  239. package/dist/types/connector/execution-context.d.ts.map +1 -1
  240. package/dist/types/execution/index.d.ts +43 -1
  241. package/dist/types/execution/index.d.ts.map +1 -1
  242. package/dist/types/hitl/index.d.ts +11 -0
  243. package/dist/types/hitl/index.d.ts.map +1 -1
  244. package/dist/types/hitl/index.js.map +1 -1
  245. package/dist/types/message/index.d.ts +31 -1
  246. package/dist/types/message/index.d.ts.map +1 -1
  247. package/dist/types/message/index.js +43 -0
  248. package/dist/types/message/index.js.map +1 -1
  249. package/dist/types/plugin/index.d.ts +14 -1
  250. package/dist/types/plugin/index.d.ts.map +1 -1
  251. package/dist/types/plugin/index.js +1 -0
  252. package/dist/types/plugin/index.js.map +1 -1
  253. package/dist/types/provider/error.d.ts +4 -1
  254. package/dist/types/provider/error.d.ts.map +1 -1
  255. package/dist/types/provider/interface.d.ts +14 -0
  256. package/dist/types/provider/interface.d.ts.map +1 -1
  257. package/dist/types/run/events.d.ts +10 -2
  258. package/dist/types/run/events.d.ts.map +1 -1
  259. package/dist/types/run/events.js.map +1 -1
  260. package/dist/types/sandbox/index.d.ts +15 -10
  261. package/dist/types/sandbox/index.d.ts.map +1 -1
  262. package/dist/types/sandbox/index.js.map +1 -1
  263. package/dist/types/tool/index.d.ts +129 -12
  264. package/dist/types/tool/index.d.ts.map +1 -1
  265. package/dist/types/tool/index.js.map +1 -1
  266. package/dist/types/workspace/ref.d.ts +5 -0
  267. package/dist/types/workspace/ref.d.ts.map +1 -1
  268. package/dist/utils/abort.d.ts +8 -0
  269. package/dist/utils/abort.d.ts.map +1 -1
  270. package/dist/utils/abort.js +16 -0
  271. package/dist/utils/abort.js.map +1 -1
  272. package/package.json +4 -4
  273. package/src/agents/ReactiveAgent.ts +4 -0
  274. package/src/agents/SupervisorAgent.ts +4 -0
  275. package/src/agents/runAgent.ts +8 -0
  276. package/src/authorization/gate.ts +1 -1
  277. package/src/connector/index.ts +2 -0
  278. package/src/connector/mcp/adapter.ts +82 -21
  279. package/src/connector/mcp/client.ts +2 -1
  280. package/src/connector/mcp/http-redirect.ts +32 -0
  281. package/src/connector/mcp/http-sse.ts +5 -0
  282. package/src/connector/mcp/image-admission.ts +272 -0
  283. package/src/connector/mcp/stdio.ts +63 -21
  284. package/src/connector/mcp/streamable-http.ts +3 -0
  285. package/src/constants/tools/index.ts +1 -1
  286. package/src/directory/derive-supervisor.ts +5 -0
  287. package/src/directory/derive.ts +5 -0
  288. package/src/directory/load.ts +1 -0
  289. package/src/directory/types.ts +2 -0
  290. package/src/execution/base.ts +124 -7
  291. package/src/execution/code-runtime/types.ts +15 -1
  292. package/src/execution/code-runtime/worker.ts +72 -9
  293. package/src/execution/errors.ts +24 -0
  294. package/src/execution/factory.ts +1 -0
  295. package/src/execution/hybrid.ts +47 -16
  296. package/src/execution/index.ts +1 -0
  297. package/src/execution/local.ts +164 -19
  298. package/src/execution/output.ts +104 -0
  299. package/src/execution/remote.ts +122 -17
  300. package/src/manager/agent/lifecycle.ts +1 -0
  301. package/src/plugin/lifecycle.ts +9 -3
  302. package/src/process/kill-tree.ts +11 -13
  303. package/src/provider/errors.ts +40 -1
  304. package/src/provider/fallback.ts +39 -0
  305. package/src/provider/idle-timeout.ts +8 -0
  306. package/src/provider/retry.ts +8 -0
  307. package/src/public-runtime.ts +23 -2
  308. package/src/public-types.ts +11 -0
  309. package/src/registry/tool/execute.ts +230 -64
  310. package/src/run/command-gate.ts +12 -0
  311. package/src/run/reporter.ts +7 -1
  312. package/src/run/workspace-fingerprint.ts +5 -4
  313. package/src/runtime/bidi/index.ts +1 -1
  314. package/src/runtime/bidi/session.ts +177 -28
  315. package/src/runtime/query/executor.ts +987 -172
  316. package/src/runtime/query/index.ts +59 -6
  317. package/src/runtime/query/iteration/index.ts +69 -29
  318. package/src/runtime/query/iteration/phases/advisory.ts +2 -2
  319. package/src/runtime/query/iteration/phases/tool-review.ts +87 -23
  320. package/src/runtime/query/iteration/provider-rejected-image.ts +106 -0
  321. package/src/runtime/query/iteration/stream-turn.ts +12 -2
  322. package/src/runtime/query/request-rich-content.ts +213 -15
  323. package/src/runtime/query/result.ts +1 -0
  324. package/src/runtime/query/resume-pending.ts +83 -1
  325. package/src/runtime/query/tool-output-budget.ts +52 -17
  326. package/src/runtime/query/tooling.ts +10 -0
  327. package/src/sandbox/provider/local.ts +213 -45
  328. package/src/scheduler/delegating.ts +6 -5
  329. package/src/scheduler/local.ts +3 -2
  330. package/src/session/workspace/driver.ts +12 -4
  331. package/src/session/workspace/git-worktree.ts +173 -34
  332. package/src/skills/registry.ts +47 -0
  333. package/src/store/attachment/index.ts +100 -15
  334. package/src/tools/builtins/computer-use.ts +45 -2
  335. package/src/tools/builtins/run-code.ts +24 -16
  336. package/src/tools/builtins/skill.ts +325 -7
  337. package/src/tools/coordinator/agent.ts +108 -33
  338. package/src/types/agent/base.ts +4 -0
  339. package/src/types/agent/factory.ts +1 -0
  340. package/src/types/agent/manager.ts +1 -1
  341. package/src/types/agent/scheduler.ts +10 -1
  342. package/src/types/bidi/index.ts +19 -2
  343. package/src/types/computer-use/index.ts +19 -0
  344. package/src/types/connector/execution-context.ts +3 -0
  345. package/src/types/execution/index.ts +46 -1
  346. package/src/types/hitl/index.ts +11 -0
  347. package/src/types/message/index.ts +78 -1
  348. package/src/types/plugin/index.ts +15 -0
  349. package/src/types/provider/error.ts +4 -1
  350. package/src/types/provider/interface.ts +18 -0
  351. package/src/types/run/events.ts +18 -4
  352. package/src/types/sandbox/index.ts +15 -10
  353. package/src/types/tool/index.ts +159 -15
  354. package/src/types/workspace/ref.ts +5 -0
  355. package/src/utils/abort.ts +18 -0
@@ -57,6 +57,7 @@ const PROVIDER_ERROR_KINDS: readonly ProviderErrorKind[] = [
57
57
  export class ProviderRequestError extends Error {
58
58
  public readonly kind: ProviderErrorKind
59
59
  public readonly providerId: string
60
+ public readonly providerCode?: string
60
61
  public readonly status?: number
61
62
  public readonly retryAfterMs?: number
62
63
  /**
@@ -81,6 +82,8 @@ export class ProviderRequestError extends Error {
81
82
  this.name = 'ProviderRequestError'
82
83
  this.kind = init.kind
83
84
  this.providerId = init.providerId
85
+ const exactProviderCode = safeProviderCode(init.providerCode)
86
+ if (exactProviderCode !== undefined) this.providerCode = exactProviderCode
84
87
  if (init.status !== undefined) this.status = init.status
85
88
  if (init.retryAfterMs !== undefined) this.retryAfterMs = init.retryAfterMs
86
89
  if (init.detail !== undefined) this.detail = init.detail
@@ -90,6 +93,32 @@ export class ProviderRequestError extends Error {
90
93
  /** Longest detail worth carrying. A provider's complaint is a sentence. */
91
94
  const DETAIL_MAX = 400
92
95
 
96
+ /** Provider codes are identifiers, not another channel for an arbitrary response body. */
97
+ const PROVIDER_CODE = /^[A-Za-z][A-Za-z0-9._-]{0,79}$/
98
+
99
+ function safeProviderCode(value: unknown): string | undefined {
100
+ if (typeof value !== 'string' || !PROVIDER_CODE.test(value)) return undefined
101
+ return redactSecrets(value) === value ? value : undefined
102
+ }
103
+
104
+ function providerCode(value: unknown): string | undefined {
105
+ let decoded = value
106
+ if (typeof decoded === 'string') {
107
+ try {
108
+ decoded = JSON.parse(decoded)
109
+ } catch {
110
+ return undefined
111
+ }
112
+ }
113
+ if (typeof decoded !== 'object' || decoded === null) return undefined
114
+ const record = decoded as Record<string, unknown>
115
+ const nested =
116
+ typeof record.error === 'object' && record.error !== null
117
+ ? (record.error as Record<string, unknown>).code
118
+ : undefined
119
+ return safeProviderCode(record.code ?? nested)
120
+ }
121
+
93
122
  /**
94
123
  * Credential shapes to scrub before a provider's words are kept.
95
124
  *
@@ -161,11 +190,15 @@ function pickMessage(value: unknown): string | undefined {
161
190
 
162
191
  /** Is this a classified provider failure, whichever SDK copy threw it? */
163
192
  export function isProviderRequestError(err: unknown): err is ProviderRequestError {
193
+ const exactProviderCode = (err as { providerCode?: unknown } | null)?.providerCode
164
194
  return (
165
195
  err instanceof Error &&
166
196
  err.name === 'ProviderRequestError' &&
167
197
  typeof (err as { providerId?: unknown }).providerId === 'string' &&
168
- PROVIDER_ERROR_KINDS.includes((err as { kind?: ProviderErrorKind }).kind as ProviderErrorKind)
198
+ PROVIDER_ERROR_KINDS.includes(
199
+ (err as { kind?: ProviderErrorKind }).kind as ProviderErrorKind,
200
+ ) &&
201
+ (exactProviderCode === undefined || safeProviderCode(exactProviderCode) === exactProviderCode)
169
202
  )
170
203
  }
171
204
 
@@ -393,6 +426,7 @@ export function providerVendorError(input: {
393
426
  }): ProviderRequestError {
394
427
  const { error } = input
395
428
  const status = vendorErrorStatus(error)
429
+ const exactProviderCode = providerCode(error)
396
430
  const name = error instanceof Error ? error.name : ''
397
431
  const message = error instanceof Error ? error.message : ''
398
432
 
@@ -411,6 +445,8 @@ export function providerVendorError(input: {
411
445
  kind = 'server'
412
446
  } else if (status !== undefined) {
413
447
  kind = classifyProviderHttpStatus(status, message)
448
+ } else if (exactProviderCode === 'invalid_image') {
449
+ kind = 'bad_request'
414
450
  } else if (bodySaysContextOverflow(message)) {
415
451
  kind = 'context_overflow'
416
452
  } else {
@@ -428,6 +464,7 @@ export function providerVendorError(input: {
428
464
  return new ProviderRequestError({
429
465
  kind,
430
466
  providerId: input.providerId,
467
+ ...(exactProviderCode !== undefined ? { providerCode: exactProviderCode } : {}),
431
468
  ...(status !== undefined ? { status } : {}),
432
469
  ...(retryAfterMs !== undefined ? { retryAfterMs } : {}),
433
470
  ...(detail !== undefined ? { detail } : {}),
@@ -450,9 +487,11 @@ export function providerHttpError(input: {
450
487
  const kind = classifyProviderHttpStatus(input.status, input.body)
451
488
  const retryAfterMs = parseRetryAfterMs(input.retryAfter, input.now ?? Date.now())
452
489
  const detail = vendorDetail(input.body)
490
+ const exactProviderCode = providerCode(input.body)
453
491
  return new ProviderRequestError({
454
492
  kind,
455
493
  providerId: input.providerId,
494
+ ...(exactProviderCode !== undefined ? { providerCode: exactProviderCode } : {}),
456
495
  status: input.status,
457
496
  ...(retryAfterMs !== undefined ? { retryAfterMs } : {}),
458
497
  ...(detail !== undefined ? { detail } : {}),
@@ -230,6 +230,40 @@ function memberReasoningEffortLevels(
230
230
  return member.provider.effortLevelsFor?.(model, thinking)
231
231
  }
232
232
 
233
+ /** Read one member's model-owned default using its routed model id. */
234
+ function memberReasoningEffortDefault(
235
+ member: ProviderChainMember,
236
+ requestModel: string,
237
+ thinking?: ThinkingConfig,
238
+ ): ReasoningEffort | undefined {
239
+ return member.provider.reasoningEffortDefaultFor?.(member.model ?? requestModel, thinking)
240
+ }
241
+
242
+ /**
243
+ * A fallback request has one unambiguous default only when every route agrees.
244
+ *
245
+ * Omitting effort lets whichever member serves the request choose its own
246
+ * default. Publishing the head's answer as the chain's answer can therefore
247
+ * make the same shortcut move in opposite directions after fallback. The
248
+ * agreed value must also survive the chain-wide exact menu.
249
+ */
250
+ function commonReasoningEffortDefault(
251
+ members: readonly ProviderChainMember[],
252
+ requestModel: string,
253
+ thinking?: ThinkingConfig,
254
+ ): ReasoningEffort | undefined {
255
+ const common = commonReasoningEffortLevels(members, requestModel, thinking)
256
+ if (common === undefined) return undefined
257
+ let agreed: ReasoningEffort | undefined
258
+ for (const member of members) {
259
+ const value = memberReasoningEffortDefault(member, requestModel, thinking)
260
+ if (value === undefined) return undefined
261
+ if (agreed !== undefined && value !== agreed) return undefined
262
+ agreed = value
263
+ }
264
+ return agreed !== undefined && common.includes(agreed) ? agreed : undefined
265
+ }
266
+
233
267
  /**
234
268
  * The levels one request may carry safely through every member it can reach.
235
269
  *
@@ -463,6 +497,11 @@ export function withProviderFallback(
463
497
  // answer when any member cannot enumerate its selected model.
464
498
  reasoningEffortLevelsFor: (model: string, thinking?: ThinkingConfig) =>
465
499
  commonReasoningEffortLevels(members, model, thinking),
500
+ // Present on the chain wrapper for the same reason the menu method is:
501
+ // `undefined` is the honest answer when a member cannot answer, defaults
502
+ // disagree, or the value is absent from the common exact menu.
503
+ reasoningEffortDefaultFor: (model: string, thinking?: ThinkingConfig) =>
504
+ commonReasoningEffortDefault(members, model, thinking),
466
505
  // Compatibility projection only. Existing consumers of the deprecated
467
506
  // member keep the head-only answer they had; new consumers use the
468
507
  // canonical chain-aware member above.
@@ -220,6 +220,14 @@ export function withStreamIdleTimeout(
220
220
  ) => provider.reasoningEffortLevelsFor?.(model, thinking),
221
221
  }
222
222
  : {}),
223
+ ...(provider.reasoningEffortDefaultFor
224
+ ? {
225
+ reasoningEffortDefaultFor: (
226
+ model: string,
227
+ thinking?: Parameters<NonNullable<LLMProvider['reasoningEffortDefaultFor']>>[1],
228
+ ) => provider.reasoningEffortDefaultFor?.(model, thinking),
229
+ }
230
+ : {}),
223
231
  ...(provider.effortLevelsFor
224
232
  ? {
225
233
  effortLevelsFor: (
@@ -275,6 +275,14 @@ export function withProviderRetry(
275
275
  ) => provider.reasoningEffortLevelsFor?.(model, thinking),
276
276
  }
277
277
  : {}),
278
+ ...(provider.reasoningEffortDefaultFor
279
+ ? {
280
+ reasoningEffortDefaultFor: (
281
+ model: string,
282
+ thinking?: Parameters<NonNullable<LLMProvider['reasoningEffortDefaultFor']>>[1],
283
+ ) => provider.reasoningEffortDefaultFor?.(model, thinking),
284
+ }
285
+ : {}),
278
286
  // Forwarded for the same reason `healthCheck` is, and both were
279
287
  // missing until something consumed them. A member this wrapper drops
280
288
  // does not fail — it reads as "this driver cannot answer", which is a
@@ -12,6 +12,12 @@
12
12
 
13
13
  export { VERSION } from './version.js'
14
14
 
15
+ // The opt-in model-authored-code backend. `RunCodeToolOptions.runtime` has
16
+ // always accepted this contract; exporting the implementation and its refusal
17
+ // class makes that signature nameable from the package root.
18
+ export { HostCallDeniedError } from './execution/code-runtime/types.js'
19
+ export { WorkerCodeRuntime } from './execution/code-runtime/worker.js'
20
+
15
21
  export {
16
22
  CompactionConfigSchema,
17
23
  PluginRuntimeConfigSchema,
@@ -287,7 +293,11 @@ export {
287
293
  formatSteeringNote,
288
294
  } from './runtime/query/steering.js'
289
295
  export type { SteeringChannel } from './runtime/query/steering.js'
290
- export { createMockBidiProvider, startBidiRun } from './runtime/bidi/index.js'
296
+ export {
297
+ BidiSessionCloseTimeoutError,
298
+ createMockBidiProvider,
299
+ startBidiRun,
300
+ } from './runtime/bidi/index.js'
291
301
  export { PromptCache } from './runtime/query/prompt-cache.js'
292
302
  export {
293
303
  CheckpointManager,
@@ -666,6 +676,7 @@ export {
666
676
  export {
667
677
  BaseConnector,
668
678
  BaseExecutionContext,
679
+ CommandCancellationUnsupportedError,
669
680
  ConnectorManager,
670
681
  ConnectorRegistry,
671
682
  EnvironmentConnectorManager,
@@ -689,6 +700,7 @@ export {
689
700
  mcpToolResultToToolResult,
690
701
  mcpToolToToolDefinition,
691
702
  RemoteExecutionContext,
703
+ RemoteExecutionBusyError,
692
704
  ScopedConnectorRegistry,
693
705
  // The only transport in the tree that can RUN an `MCPServer`. It reached
694
706
  // `connector/mcp/index.ts` and stopped there, so the server was public
@@ -995,6 +1007,7 @@ export { assertMemoryStatus } from './types/memory/index.js'
995
1007
  export {
996
1008
  createAssistantMessage,
997
1009
  createProjectInstructionMessage,
1010
+ createRuntimeContextMessage,
998
1011
  createSystemMessage,
999
1012
  createToolMessage,
1000
1013
  hasNonTextBlocks,
@@ -1002,7 +1015,10 @@ export {
1002
1015
  toolResultToText,
1003
1016
  createUserMessage,
1004
1017
  isProjectInstructionMessageSource,
1018
+ isRuntimeContextMessageSource,
1019
+ isModelContentOmission,
1005
1020
  MAX_PROJECT_INSTRUCTION_SOURCE_FILES,
1021
+ RUNTIME_CONTEXT_MESSAGE_KINDS,
1006
1022
  } from './types/message/index.js'
1007
1023
  export { isTerminalPlanStatus } from './types/plan/index.js'
1008
1024
  export {
@@ -1198,8 +1214,10 @@ export {
1198
1214
  // Inline base64 lands in the transcript, in every checkpoint, and on the
1199
1215
  // wire once per turn; a reference does not.
1200
1216
  export {
1217
+ DEFAULT_ATTACHMENT_RESOLVE_TIMEOUT_MS,
1201
1218
  AttachmentMediaTypeMismatchError,
1202
1219
  AttachmentNotFoundError,
1220
+ AttachmentResolutionTimeoutError,
1203
1221
  NoAttachmentStoreError,
1204
1222
  isStoredAttachment,
1205
1223
  resolveAttachment,
@@ -1254,7 +1272,10 @@ export type {
1254
1272
  CompactionVerificationOptions,
1255
1273
  UsageSink,
1256
1274
  } from './compaction/verifier.js'
1257
- export type { PluginDiscoveryOptions, PluginEnablementCapabilities } from './plugin/loader.js'
1275
+ export type {
1276
+ PluginDiscoveryOptions,
1277
+ PluginEnablementCapabilities,
1278
+ } from './plugin/loader.js'
1258
1279
  export type { ProbeContextInput } from './probe/context.js'
1259
1280
  export type {
1260
1281
  GoalCommandScope,
@@ -19,6 +19,16 @@ export type * from './types/common/index.js'
19
19
  export type { CoalesceOptions } from './streaming/coalesce.js'
20
20
  export type * from './types/bidi/index.js'
21
21
  export type * from './types/tool/index.js'
22
+ export type {
23
+ CodeRunOutcome,
24
+ CodeRunResult,
25
+ CodeRuntime,
26
+ HostCallContext,
27
+ HostCallHandler,
28
+ HostCallRequest,
29
+ HostCallResult,
30
+ RunCodeOptions,
31
+ } from './execution/code-runtime/types.js'
22
32
  // The directory convention: what a loaded `agent/` directory is, and what the
23
33
  // loader reports about the files it could not use.
24
34
  export type * from './directory/types.js'
@@ -336,6 +346,7 @@ export type {
336
346
 
337
347
  export type {
338
348
  AttachmentOperationOptions,
349
+ AttachmentResolutionOptions,
339
350
  AttachmentStore,
340
351
  StoredAttachment,
341
352
  StoredBytes,
@@ -7,10 +7,12 @@ import { isTrustedReadOnly } from '../../tools/trusted-read-only.js'
7
7
  import type { ToolResultGuardrailSpec } from '../../types/guardrail/index.js'
8
8
  import type {
9
9
  LLMToolSchema,
10
+ PreparedToolExecution,
10
11
  ToolAvailability,
11
12
  ToolContext,
12
13
  ToolDefinition,
13
14
  ToolExecutionResult,
15
+ ToolPreparationResult,
14
16
  ToolRegistryConfig,
15
17
  ToolTierConfig,
16
18
  } from '../../types/tool/index.js'
@@ -87,6 +89,82 @@ export function assertToolName(name: string): void {
87
89
  )
88
90
  }
89
91
 
92
+ function clonePreparedInput(value: unknown, freeze: boolean, path = '$'): unknown {
93
+ const active = new WeakSet<object>()
94
+ const copies = new WeakMap<object, object>()
95
+
96
+ const clone = (candidate: unknown, at: string): unknown => {
97
+ if (candidate === null || typeof candidate === 'string' || typeof candidate === 'boolean') {
98
+ return candidate
99
+ }
100
+ if (typeof candidate === 'number') {
101
+ if (!Number.isFinite(candidate) || Object.is(candidate, -0)) {
102
+ throw new TypeError(`${at} must be a finite JSON number`)
103
+ }
104
+ return candidate
105
+ }
106
+ if (typeof candidate !== 'object') {
107
+ throw new TypeError(`${at} must be a JSON value, not ${typeof candidate}`)
108
+ }
109
+ if (active.has(candidate)) throw new TypeError(`${at} contains a cycle`)
110
+ const existing = copies.get(candidate)
111
+ if (existing) return existing
112
+
113
+ active.add(candidate)
114
+ try {
115
+ if (Array.isArray(candidate)) {
116
+ const extra = Reflect.ownKeys(candidate).filter(
117
+ (key) => key !== 'length' && (typeof key !== 'string' || !/^(0|[1-9]\d*)$/.test(key)),
118
+ )
119
+ if (extra.length > 0) throw new TypeError(`${at} has non-JSON array properties`)
120
+ const result: unknown[] = new Array(candidate.length)
121
+ copies.set(candidate, result)
122
+ for (let index = 0; index < candidate.length; index++) {
123
+ const descriptor = Object.getOwnPropertyDescriptor(candidate, String(index))
124
+ if (!descriptor) throw new TypeError(`${at}[${index}] is a sparse array hole`)
125
+ if (!descriptor.enumerable || !('value' in descriptor)) {
126
+ throw new TypeError(`${at}[${index}] must be an enumerable data property`)
127
+ }
128
+ result[index] = clone(descriptor.value, `${at}[${index}]`)
129
+ }
130
+ if (freeze) Object.freeze(result)
131
+ return result
132
+ }
133
+
134
+ const prototype = Object.getPrototypeOf(candidate)
135
+ if (prototype !== Object.prototype && prototype !== null) {
136
+ throw new TypeError(`${at} must be a plain JSON object`)
137
+ }
138
+ // JSON does not preserve prototypes. Canonicalize both admitted plain
139
+ // shapes to an ordinary object so a disk checkpoint round-trip compares
140
+ // equal to a fresh preparation of the same semantic value. Properties
141
+ // are still defined explicitly, so a literal "__proto__" key remains
142
+ // data rather than changing this object's prototype.
143
+ const result: Record<string, unknown> = {}
144
+ copies.set(candidate, result)
145
+ for (const key of Reflect.ownKeys(candidate)) {
146
+ if (typeof key !== 'string') throw new TypeError(`${at} has a symbol property`)
147
+ const descriptor = Object.getOwnPropertyDescriptor(candidate, key)
148
+ if (!descriptor?.enumerable || !('value' in descriptor)) {
149
+ throw new TypeError(`${at}.${key} must be an enumerable data property`)
150
+ }
151
+ Object.defineProperty(result, key, {
152
+ value: clone(descriptor.value, `${at}.${key}`),
153
+ enumerable: true,
154
+ writable: !freeze,
155
+ configurable: !freeze,
156
+ })
157
+ }
158
+ if (freeze) Object.freeze(result)
159
+ return result
160
+ } finally {
161
+ active.delete(candidate)
162
+ }
163
+ }
164
+
165
+ return clone(value, path)
166
+ }
167
+
90
168
  /**
91
169
  * Two sources contributed the same tool name and neither may take it.
92
170
  *
@@ -136,9 +214,17 @@ export class ToolRegistry extends ManagedRegistry<ToolDefinition> {
136
214
  private availability: Map<string, ToolAvailability> = new Map()
137
215
  private tierConfig?: ToolTierConfig
138
216
  private resultGuardrails?: readonly ToolResultGuardrailSpec[]
217
+ private readonly preparations = new WeakMap<
218
+ PreparedToolExecution,
219
+ { readonly tool: ToolDefinition; readonly input: unknown }
220
+ >()
139
221
 
140
222
  constructor(config?: ToolRegistryConfig) {
141
- super({ componentName: 'ToolRegistry', idField: 'name', logger: config?.logger })
223
+ super({
224
+ componentName: 'ToolRegistry',
225
+ idField: 'name',
226
+ logger: config?.logger,
227
+ })
142
228
  this.tierConfig = config?.tierConfig
143
229
  this.resultGuardrails = config?.resultGuardrails
144
230
  }
@@ -401,10 +487,106 @@ Executable tool names, descriptions, and JSON input schemas are attached through
401
487
  return this.getByAvailability(['active'], toolNames)
402
488
  }
403
489
 
490
+ prepareExecution(toolName: string, rawInput: unknown): ToolPreparationResult {
491
+ const tool = this.getOrThrow(toolName)
492
+ const parseResult = tool.inputSchema.safeParse(rawInput)
493
+ if (!parseResult.success) {
494
+ return {
495
+ success: false,
496
+ result: this.validationFailure(tool, rawInput, parseResult.error),
497
+ }
498
+ }
499
+
500
+ let retainedInput: unknown
501
+ let reviewInput: unknown
502
+ try {
503
+ retainedInput = clonePreparedInput(parseResult.data, false)
504
+ reviewInput = clonePreparedInput(retainedInput, true)
505
+ } catch (err) {
506
+ const message = `Tool "${toolName}" produced an input that cannot be safely prepared for review and execution: ${toErrorMessage(err)}`
507
+ this.log.error('Prepared tool input could not be detached for review and execution', {
508
+ 'namzu.tool.name': toolName,
509
+ 'exception.message': toErrorMessage(err),
510
+ })
511
+ return {
512
+ success: false,
513
+ result: { success: false, output: '', error: message },
514
+ }
515
+ }
516
+
517
+ const prepared = Object.freeze({ toolName, input: reviewInput })
518
+ this.preparations.set(prepared, { tool, input: retainedInput })
519
+ return { success: true, prepared }
520
+ }
521
+
522
+ async executePrepared(
523
+ prepared: PreparedToolExecution,
524
+ context: ToolContext,
525
+ ): Promise<ToolExecutionResult> {
526
+ const retained = this.preparations.get(prepared)
527
+ if (!retained) {
528
+ return {
529
+ success: false,
530
+ output: '',
531
+ error: `Tool "${prepared.toolName}" preparation is not owned by this registry or is no longer valid.`,
532
+ }
533
+ }
534
+ if (this.get(prepared.toolName) !== retained.tool) {
535
+ return {
536
+ success: false,
537
+ output: '',
538
+ error: `Tool "${prepared.toolName}" changed after its input was reviewed; prepare the call again.`,
539
+ }
540
+ }
541
+ return this.executeRetained(prepared.toolName, retained.tool, retained.input, context)
542
+ }
543
+
404
544
  async execute(
405
545
  toolName: string,
406
546
  rawInput: unknown,
407
547
  context: ToolContext,
548
+ ): Promise<ToolExecutionResult> {
549
+ let preparation: ToolPreparationResult
550
+ try {
551
+ preparation = this.prepareExecution(toolName, rawInput)
552
+ } catch (err) {
553
+ return this.rejectPreparationWithClosedSpan(toolName, context, err)
554
+ }
555
+ if (!preparation.success) return preparation.result
556
+ return this.executePrepared(preparation.prepared, context)
557
+ }
558
+
559
+ private rejectPreparationWithClosedSpan(
560
+ toolName: string,
561
+ context: ToolContext,
562
+ err: unknown,
563
+ ): Promise<never> {
564
+ const tracer = getTracer()
565
+ const parentCtx = context.parentSpan
566
+ ? trace.setSpan(otelContext.active(), context.parentSpan)
567
+ : otelContext.active()
568
+ return tracer.startActiveSpan(toolSpanName(toolName), {}, parentCtx, async (span) => {
569
+ try {
570
+ span.setAttributes({
571
+ [GENAI.TOOL_NAME]: toolName,
572
+ [GENAI.TOOL_TYPE]: 'function',
573
+ ...(context.toolUseId !== undefined ? { [GENAI.TOOL_CALL_ID]: context.toolUseId } : {}),
574
+ [NAMZU.TOOL_SUCCESS]: false,
575
+ [NAMZU.TOOL_ERROR]: toErrorMessage(err),
576
+ })
577
+ span.setStatus({ code: SpanStatusCode.ERROR, message: toErrorMessage(err) })
578
+ throw err
579
+ } finally {
580
+ span.end()
581
+ }
582
+ })
583
+ }
584
+
585
+ private async executeRetained(
586
+ toolName: string,
587
+ tool: ToolDefinition,
588
+ finalInput: unknown,
589
+ context: ToolContext,
408
590
  ): Promise<ToolExecutionResult> {
409
591
  const tracer = getTracer()
410
592
 
@@ -437,8 +619,6 @@ Executable tool names, descriptions, and JSON input schemas are attached through
437
619
  ...(context.toolUseId !== undefined ? { [GENAI.TOOL_CALL_ID]: context.toolUseId } : {}),
438
620
  })
439
621
 
440
- const tool = this.getOrThrow(toolName)
441
-
442
622
  const availability = this.getAvailability(toolName)
443
623
  if (availability !== 'active') {
444
624
  const msg = `Tool "${toolName}" is ${availability} and cannot be executed`
@@ -492,7 +672,7 @@ Executable tool names, descriptions, and JSON input schemas are attached through
492
672
 
493
673
  const mode = context.permissionContext?.mode ?? 'auto'
494
674
  if (mode === 'plan') {
495
- const isReadOnly = isTrustedReadOnly(tool, rawInput)
675
+ const isReadOnly = isTrustedReadOnly(tool, finalInput)
496
676
  if (!isReadOnly) {
497
677
  const msg = `plan mode: non-read-only tool "${toolName}" blocked`
498
678
  span.setAttributes({
@@ -510,63 +690,6 @@ Executable tool names, descriptions, and JSON input schemas are attached through
510
690
  }
511
691
  }
512
692
 
513
- const parseResult = tool.inputSchema.safeParse(rawInput)
514
- if (!parseResult.success) {
515
- const errorMessage = parseResult.error.issues
516
- .map((i) => `${i.path.join('.')}: ${i.message}`)
517
- .join('; ')
518
-
519
- // Distinguish "model sent an empty/no-arg call" from
520
- // "model sent partial args" — the first is most often a
521
- // streaming hiccup or a definition-test ping (a provider
522
- // occasionally pings tool surfaces with `{}` while the
523
- // schema is still loading), the second is a genuine
524
- // programming mistake by the model. The model self-
525
- // corrects MUCH more reliably when the error tells it
526
- // (a) which fields are required, (b) their types, and
527
- // (c) a minimal example call. Without these hints the
528
- // downstream UI just shows a red "Failed" row and the
529
- // model rarely retries with the right args.
530
- const isEmptyInput =
531
- rawInput === null ||
532
- rawInput === undefined ||
533
- (typeof rawInput === 'object' &&
534
- !Array.isArray(rawInput) &&
535
- Object.keys(rawInput as Record<string, unknown>).length === 0)
536
-
537
- const requiredHint = describeRequiredInput(tool.inputSchema)
538
- // A conditional schema's required shape cannot be reconstructed
539
- // from JSON Schema's top-level `required`, so the author gets to
540
- // say what a valid retry looks like.
541
- const recoveryHint = tool.validationErrorHint?.trim()
542
- ? ` ${tool.validationErrorHint.trim()}`
543
- : ''
544
-
545
- const enrichedMessage = isEmptyInput
546
- ? `Tool "${toolName}" was called with no arguments. ${requiredHint}${recoveryHint} Retry the call with the required parameters populated.`
547
- : `Validation failed for "${toolName}": ${errorMessage}. ${requiredHint}${recoveryHint}`
548
-
549
- this.log.error('Tool input validation failed', {
550
- 'namzu.tool.name': toolName,
551
- 'namzu.registry.errors': errorMessage,
552
- 'namzu.registry.empty': isEmptyInput,
553
- })
554
-
555
- span.setAttributes({
556
- [NAMZU.TOOL_SUCCESS]: false,
557
- [NAMZU.TOOL_ERROR]: `Validation: ${errorMessage}`,
558
- })
559
- span.setStatus({ code: SpanStatusCode.ERROR, message: errorMessage })
560
-
561
- return {
562
- success: false,
563
- output: '',
564
- error: enrichedMessage,
565
- }
566
- }
567
-
568
- const finalInput = parseResult.data
569
-
570
693
  try {
571
694
  this.log.debug('Executing tool', { 'namzu.tool.name': toolName })
572
695
  const startedAt = Date.now()
@@ -604,7 +727,10 @@ Executable tool names, descriptions, and JSON input schemas are attached through
604
727
  )
605
728
  if (!result.success && result.error) {
606
729
  span.setAttribute(NAMZU.TOOL_ERROR, result.error)
607
- span.setStatus({ code: SpanStatusCode.ERROR, message: result.error })
730
+ span.setStatus({
731
+ code: SpanStatusCode.ERROR,
732
+ message: result.error,
733
+ })
608
734
  } else {
609
735
  span.setStatus({ code: SpanStatusCode.OK })
610
736
  }
@@ -622,7 +748,10 @@ Executable tool names, descriptions, and JSON input schemas are attached through
622
748
  [NAMZU.TOOL_SUCCESS]: false,
623
749
  [NAMZU.TOOL_ERROR]: err.message,
624
750
  })
625
- span.setStatus({ code: SpanStatusCode.ERROR, message: err.message })
751
+ span.setStatus({
752
+ code: SpanStatusCode.ERROR,
753
+ message: err.message,
754
+ })
626
755
  throw err
627
756
  }
628
757
  const errorMessage = toErrorMessage(err)
@@ -635,7 +764,10 @@ Executable tool names, descriptions, and JSON input schemas are attached through
635
764
  [NAMZU.TOOL_SUCCESS]: false,
636
765
  [NAMZU.TOOL_ERROR]: errorMessage,
637
766
  })
638
- span.setStatus({ code: SpanStatusCode.ERROR, message: errorMessage })
767
+ span.setStatus({
768
+ code: SpanStatusCode.ERROR,
769
+ message: errorMessage,
770
+ })
639
771
  span.recordException(err instanceof Error ? err : new Error(errorMessage))
640
772
 
641
773
  return {
@@ -655,6 +787,40 @@ Executable tool names, descriptions, and JSON input schemas are attached through
655
787
  })
656
788
  }
657
789
 
790
+ private validationFailure(
791
+ tool: ToolDefinition,
792
+ rawInput: unknown,
793
+ error: {
794
+ readonly issues: readonly {
795
+ readonly path: readonly PropertyKey[]
796
+ readonly message: string
797
+ }[]
798
+ },
799
+ ): ToolExecutionResult {
800
+ const errorMessage = error.issues
801
+ .map((issue) => `${issue.path.join('.')}: ${issue.message}`)
802
+ .join('; ')
803
+ const isEmptyInput =
804
+ rawInput === null ||
805
+ rawInput === undefined ||
806
+ (typeof rawInput === 'object' &&
807
+ !Array.isArray(rawInput) &&
808
+ Object.keys(rawInput as Record<string, unknown>).length === 0)
809
+ const requiredHint = describeRequiredInput(tool.inputSchema)
810
+ const recoveryHint = tool.validationErrorHint?.trim()
811
+ ? ` ${tool.validationErrorHint.trim()}`
812
+ : ''
813
+ const enrichedMessage = isEmptyInput
814
+ ? `Tool "${tool.name}" was called with no arguments. ${requiredHint}${recoveryHint} Retry the call with the required parameters populated.`
815
+ : `Validation failed for "${tool.name}": ${errorMessage}. ${requiredHint}${recoveryHint}`
816
+ this.log.error('Tool input validation failed', {
817
+ 'namzu.tool.name': tool.name,
818
+ 'namzu.registry.errors': errorMessage,
819
+ 'namzu.registry.empty': isEmptyInput,
820
+ })
821
+ return { success: false, output: '', error: enrichedMessage }
822
+ }
823
+
658
824
  private getByAvailability(states: ToolAvailability[], filter?: string[]): ToolDefinition[] {
659
825
  const candidates = filter ? filter.map((n) => this.getOrThrow(n)) : this.getAll()
660
826
  return candidates.filter((t) => states.includes(this.getAvailability(t.name)))