@namzu/sdk 49.0.0 → 50.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 (742) hide show
  1. package/CHANGELOG.md +541 -0
  2. package/README.md +137 -125
  3. package/dist/agents/QueryAgent.d.ts.map +1 -1
  4. package/dist/agents/QueryAgent.js +1 -0
  5. package/dist/agents/QueryAgent.js.map +1 -1
  6. package/dist/agents/examples/SupervisorAgent.d.ts.map +1 -1
  7. package/dist/agents/examples/SupervisorAgent.js +1 -0
  8. package/dist/agents/examples/SupervisorAgent.js.map +1 -1
  9. package/dist/agents/runAgent.d.ts +2 -0
  10. package/dist/agents/runAgent.d.ts.map +1 -1
  11. package/dist/agents/runAgent.js +1 -0
  12. package/dist/agents/runAgent.js.map +1 -1
  13. package/dist/authorization/shell-lexer.d.ts.map +1 -1
  14. package/dist/authorization/shell-lexer.js +16 -1
  15. package/dist/authorization/shell-lexer.js.map +1 -1
  16. package/dist/bridge/acp/permission.d.ts +8 -2
  17. package/dist/bridge/acp/permission.d.ts.map +1 -1
  18. package/dist/bridge/acp/permission.js +1 -0
  19. package/dist/bridge/acp/permission.js.map +1 -1
  20. package/dist/bridge/acp/server.d.ts +25 -1
  21. package/dist/bridge/acp/server.d.ts.map +1 -1
  22. package/dist/bridge/acp/server.js +205 -21
  23. package/dist/bridge/acp/server.js.map +1 -1
  24. package/dist/bridge/acp/tasks.d.ts +5 -0
  25. package/dist/bridge/acp/tasks.d.ts.map +1 -0
  26. package/dist/bridge/acp/tasks.js +19 -0
  27. package/dist/bridge/acp/tasks.js.map +1 -0
  28. package/dist/bridge/acp/update.d.ts.map +1 -1
  29. package/dist/bridge/acp/update.js +148 -13
  30. package/dist/bridge/acp/update.js.map +1 -1
  31. package/dist/config/runtime.d.ts +31 -31
  32. package/dist/connector/mcp/adapter.d.ts.map +1 -1
  33. package/dist/connector/mcp/adapter.js +11 -4
  34. package/dist/connector/mcp/adapter.js.map +1 -1
  35. package/dist/connector/mcp/client.d.ts.map +1 -1
  36. package/dist/connector/mcp/client.js +6 -3
  37. package/dist/connector/mcp/client.js.map +1 -1
  38. package/dist/constants/acp/index.d.ts +3 -0
  39. package/dist/constants/acp/index.d.ts.map +1 -1
  40. package/dist/constants/acp/index.js +3 -0
  41. package/dist/constants/acp/index.js.map +1 -1
  42. package/dist/contracts/a2a.d.ts +80 -80
  43. package/dist/contracts/schemas.d.ts +2 -2
  44. package/dist/contracts/session/schemas.d.ts +10 -10
  45. package/dist/manager/agent/lifecycle.d.ts +11 -0
  46. package/dist/manager/agent/lifecycle.d.ts.map +1 -1
  47. package/dist/manager/agent/lifecycle.js +178 -3
  48. package/dist/manager/agent/lifecycle.js.map +1 -1
  49. package/dist/manager/plan/lifecycle.d.ts +7 -8
  50. package/dist/manager/plan/lifecycle.d.ts.map +1 -1
  51. package/dist/manager/plan/lifecycle.js +7 -8
  52. package/dist/manager/plan/lifecycle.js.map +1 -1
  53. package/dist/manager/resident/consumption.d.ts +8 -8
  54. package/dist/manager/resident/learning-cycle.d.ts +2 -2
  55. package/dist/manager/resident/learning-observation.d.ts +12 -12
  56. package/dist/manager/resident/learning.d.ts +82 -82
  57. package/dist/manager/resident/outbox.d.ts +8 -8
  58. package/dist/manager/resident/proposal.d.ts +2 -2
  59. package/dist/manager/resident/store.d.ts +10 -10
  60. package/dist/manager/session/attribution.d.ts +1 -0
  61. package/dist/manager/session/attribution.d.ts.map +1 -1
  62. package/dist/manager/session/attribution.js +9 -1
  63. package/dist/manager/session/attribution.js.map +1 -1
  64. package/dist/manager/session/streamed-message-identity.d.ts +6 -0
  65. package/dist/manager/session/streamed-message-identity.d.ts.map +1 -0
  66. package/dist/manager/session/streamed-message-identity.js +14 -0
  67. package/dist/manager/session/streamed-message-identity.js.map +1 -0
  68. package/dist/manager/session/turn-recorder.d.ts.map +1 -1
  69. package/dist/manager/session/turn-recorder.js +4 -3
  70. package/dist/manager/session/turn-recorder.js.map +1 -1
  71. package/dist/pals/activity/causality.d.ts +23 -0
  72. package/dist/pals/activity/causality.d.ts.map +1 -0
  73. package/dist/pals/activity/causality.js +205 -0
  74. package/dist/pals/activity/causality.js.map +1 -0
  75. package/dist/pals/activity/projection.d.ts +5 -0
  76. package/dist/pals/activity/projection.d.ts.map +1 -0
  77. package/dist/pals/activity/projection.js +79 -0
  78. package/dist/pals/activity/projection.js.map +1 -0
  79. package/dist/pals/activity/source.d.ts +16 -0
  80. package/dist/pals/activity/source.d.ts.map +1 -0
  81. package/dist/pals/activity/source.js +235 -0
  82. package/dist/pals/activity/source.js.map +1 -0
  83. package/dist/pals/activity/subscription-policy.d.ts +38 -0
  84. package/dist/pals/activity/subscription-policy.d.ts.map +1 -0
  85. package/dist/pals/activity/subscription-policy.js +183 -0
  86. package/dist/pals/activity/subscription-policy.js.map +1 -0
  87. package/dist/pals/activity/subscription-schema.d.ts +353 -0
  88. package/dist/pals/activity/subscription-schema.d.ts.map +1 -0
  89. package/dist/pals/activity/subscription-schema.js +24 -0
  90. package/dist/pals/activity/subscription-schema.js.map +1 -0
  91. package/dist/pals/activity/subscription-store.d.ts +25 -0
  92. package/dist/pals/activity/subscription-store.d.ts.map +1 -0
  93. package/dist/pals/activity/subscription-store.js +152 -0
  94. package/dist/pals/activity/subscription-store.js.map +1 -0
  95. package/dist/pals/activity/subscription-types.d.ts +42 -0
  96. package/dist/pals/activity/subscription-types.d.ts.map +1 -0
  97. package/dist/pals/activity/subscription-types.js +2 -0
  98. package/dist/pals/activity/subscription-types.js.map +1 -0
  99. package/dist/pals/activity/subscriptions.d.ts +32 -0
  100. package/dist/pals/activity/subscriptions.d.ts.map +1 -0
  101. package/dist/pals/activity/subscriptions.js +151 -0
  102. package/dist/pals/activity/subscriptions.js.map +1 -0
  103. package/dist/pals/activity/types.d.ts +77 -0
  104. package/dist/pals/activity/types.d.ts.map +1 -0
  105. package/dist/pals/activity/types.js +2 -0
  106. package/dist/pals/activity/types.js.map +1 -0
  107. package/dist/pals/channels/ingress.d.ts +9 -0
  108. package/dist/pals/channels/ingress.d.ts.map +1 -0
  109. package/dist/pals/channels/ingress.js +131 -0
  110. package/dist/pals/channels/ingress.js.map +1 -0
  111. package/dist/pals/channels/routes.d.ts +20 -0
  112. package/dist/pals/channels/routes.d.ts.map +1 -0
  113. package/dist/pals/channels/routes.js +111 -0
  114. package/dist/pals/channels/routes.js.map +1 -0
  115. package/dist/pals/channels/routing.d.ts +37 -0
  116. package/dist/pals/channels/routing.d.ts.map +1 -0
  117. package/dist/pals/channels/routing.js +150 -0
  118. package/dist/pals/channels/routing.js.map +1 -0
  119. package/dist/pals/channels/schema.d.ts +234 -0
  120. package/dist/pals/channels/schema.d.ts.map +1 -0
  121. package/dist/pals/channels/schema.js +94 -0
  122. package/dist/pals/channels/schema.js.map +1 -0
  123. package/dist/pals/channels/types.d.ts +115 -0
  124. package/dist/pals/channels/types.d.ts.map +1 -0
  125. package/dist/pals/channels/types.js +2 -0
  126. package/dist/pals/channels/types.js.map +1 -0
  127. package/dist/pals/communication/broker.d.ts +8 -0
  128. package/dist/pals/communication/broker.d.ts.map +1 -0
  129. package/dist/pals/communication/broker.js +121 -0
  130. package/dist/pals/communication/broker.js.map +1 -0
  131. package/dist/pals/communication/dispatch.d.ts +4 -0
  132. package/dist/pals/communication/dispatch.d.ts.map +1 -0
  133. package/dist/pals/communication/dispatch.js +57 -0
  134. package/dist/pals/communication/dispatch.js.map +1 -0
  135. package/dist/pals/communication/inbound.d.ts +9 -0
  136. package/dist/pals/communication/inbound.d.ts.map +1 -0
  137. package/dist/pals/communication/inbound.js +155 -0
  138. package/dist/pals/communication/inbound.js.map +1 -0
  139. package/dist/pals/communication/ingress-dispatch.d.ts +5 -0
  140. package/dist/pals/communication/ingress-dispatch.d.ts.map +1 -0
  141. package/dist/pals/communication/ingress-dispatch.js +51 -0
  142. package/dist/pals/communication/ingress-dispatch.js.map +1 -0
  143. package/dist/pals/communication/ingress-inbound.d.ts +9 -0
  144. package/dist/pals/communication/ingress-inbound.d.ts.map +1 -0
  145. package/dist/pals/communication/ingress-inbound.js +222 -0
  146. package/dist/pals/communication/ingress-inbound.js.map +1 -0
  147. package/dist/pals/communication/ingress-schema.d.ts +7829 -0
  148. package/dist/pals/communication/ingress-schema.d.ts.map +1 -0
  149. package/dist/pals/communication/ingress-schema.js +479 -0
  150. package/dist/pals/communication/ingress-schema.js.map +1 -0
  151. package/dist/pals/communication/ingress-types.d.ts +187 -0
  152. package/dist/pals/communication/ingress-types.d.ts.map +1 -0
  153. package/dist/pals/communication/ingress-types.js +73 -0
  154. package/dist/pals/communication/ingress-types.js.map +1 -0
  155. package/dist/pals/communication/operator.d.ts +75 -0
  156. package/dist/pals/communication/operator.d.ts.map +1 -0
  157. package/dist/pals/communication/operator.js +217 -0
  158. package/dist/pals/communication/operator.js.map +1 -0
  159. package/dist/pals/communication/policy.d.ts +41 -0
  160. package/dist/pals/communication/policy.d.ts.map +1 -0
  161. package/dist/pals/communication/policy.js +138 -0
  162. package/dist/pals/communication/policy.js.map +1 -0
  163. package/dist/pals/communication/schema.d.ts +2000 -0
  164. package/dist/pals/communication/schema.d.ts.map +1 -0
  165. package/dist/pals/communication/schema.js +170 -0
  166. package/dist/pals/communication/schema.js.map +1 -0
  167. package/dist/pals/communication/store.d.ts +61 -0
  168. package/dist/pals/communication/store.d.ts.map +1 -0
  169. package/dist/pals/communication/store.js +450 -0
  170. package/dist/pals/communication/store.js.map +1 -0
  171. package/dist/pals/communication/tools.d.ts +23 -0
  172. package/dist/pals/communication/tools.d.ts.map +1 -0
  173. package/dist/pals/communication/tools.js +107 -0
  174. package/dist/pals/communication/tools.js.map +1 -0
  175. package/dist/pals/communication/types.d.ts +168 -0
  176. package/dist/pals/communication/types.d.ts.map +1 -0
  177. package/dist/pals/communication/types.js +24 -0
  178. package/dist/pals/communication/types.js.map +1 -0
  179. package/dist/pals/communication/verify.d.ts +22 -0
  180. package/dist/pals/communication/verify.d.ts.map +1 -0
  181. package/dist/pals/communication/verify.js +142 -0
  182. package/dist/pals/communication/verify.js.map +1 -0
  183. package/dist/pals/lifecycle.d.ts +37 -0
  184. package/dist/pals/lifecycle.d.ts.map +1 -0
  185. package/dist/pals/lifecycle.js +22 -0
  186. package/dist/pals/lifecycle.js.map +1 -0
  187. package/dist/pals/prompt.d.ts +30 -0
  188. package/dist/pals/prompt.d.ts.map +1 -0
  189. package/dist/pals/prompt.js +65 -0
  190. package/dist/pals/prompt.js.map +1 -0
  191. package/dist/pals/reference-images.d.ts +44 -0
  192. package/dist/pals/reference-images.d.ts.map +1 -0
  193. package/dist/pals/reference-images.js +248 -0
  194. package/dist/pals/reference-images.js.map +1 -0
  195. package/dist/pals/runtime.d.ts +46 -0
  196. package/dist/pals/runtime.d.ts.map +1 -0
  197. package/dist/pals/runtime.js +624 -0
  198. package/dist/pals/runtime.js.map +1 -0
  199. package/dist/pals/store.d.ts +26 -0
  200. package/dist/pals/store.d.ts.map +1 -0
  201. package/dist/pals/store.js +334 -0
  202. package/dist/pals/store.js.map +1 -0
  203. package/dist/pals/types.d.ts +145 -0
  204. package/dist/pals/types.d.ts.map +1 -0
  205. package/dist/pals/types.js +2 -0
  206. package/dist/pals/types.js.map +1 -0
  207. package/dist/peers/envelope.js +1 -1
  208. package/dist/peers/envelope.js.map +1 -1
  209. package/dist/peers/protocol.d.ts +83 -83
  210. package/dist/peers/record.d.ts +10 -10
  211. package/dist/plugin/shell-hook.d.ts.map +1 -1
  212. package/dist/plugin/shell-hook.js +7 -2
  213. package/dist/plugin/shell-hook.js.map +1 -1
  214. package/dist/process/kill-tree.d.ts.map +1 -1
  215. package/dist/process/kill-tree.js +9 -1
  216. package/dist/process/kill-tree.js.map +1 -1
  217. package/dist/provider/errors.d.ts +19 -0
  218. package/dist/provider/errors.d.ts.map +1 -1
  219. package/dist/provider/errors.js +123 -2
  220. package/dist/provider/errors.js.map +1 -1
  221. package/dist/provider/strict-schema.d.ts +28 -0
  222. package/dist/provider/strict-schema.d.ts.map +1 -1
  223. package/dist/provider/strict-schema.js +86 -0
  224. package/dist/provider/strict-schema.js.map +1 -1
  225. package/dist/public-runtime.d.ts +42 -14
  226. package/dist/public-runtime.d.ts.map +1 -1
  227. package/dist/public-runtime.js +36 -8
  228. package/dist/public-runtime.js.map +1 -1
  229. package/dist/public-tools.d.ts +8 -3
  230. package/dist/public-tools.d.ts.map +1 -1
  231. package/dist/public-tools.js +8 -3
  232. package/dist/public-tools.js.map +1 -1
  233. package/dist/public-types.d.ts +27 -7
  234. package/dist/public-types.d.ts.map +1 -1
  235. package/dist/registry/tool/presentation.d.ts +1 -0
  236. package/dist/registry/tool/presentation.d.ts.map +1 -1
  237. package/dist/registry/tool/presentation.js +9 -7
  238. package/dist/registry/tool/presentation.js.map +1 -1
  239. package/dist/runtime/harness-session/index.d.ts +5 -0
  240. package/dist/runtime/harness-session/index.d.ts.map +1 -0
  241. package/dist/runtime/harness-session/index.js +928 -0
  242. package/dist/runtime/harness-session/index.js.map +1 -0
  243. package/dist/runtime/harness-session/journal.d.ts +37 -0
  244. package/dist/runtime/harness-session/journal.d.ts.map +1 -0
  245. package/dist/runtime/harness-session/journal.js +177 -0
  246. package/dist/runtime/harness-session/journal.js.map +1 -0
  247. package/dist/runtime/harness-session/saved-view.d.ts +8 -0
  248. package/dist/runtime/harness-session/saved-view.d.ts.map +1 -0
  249. package/dist/runtime/harness-session/saved-view.js +112 -0
  250. package/dist/runtime/harness-session/saved-view.js.map +1 -0
  251. package/dist/runtime/jobs/awaited-jobs.d.ts +2 -1
  252. package/dist/runtime/jobs/awaited-jobs.d.ts.map +1 -1
  253. package/dist/runtime/jobs/awaited-jobs.js +2 -1
  254. package/dist/runtime/jobs/awaited-jobs.js.map +1 -1
  255. package/dist/runtime/jobs/registry.d.ts +56 -1
  256. package/dist/runtime/jobs/registry.d.ts.map +1 -1
  257. package/dist/runtime/jobs/registry.js +351 -34
  258. package/dist/runtime/jobs/registry.js.map +1 -1
  259. package/dist/runtime/query/abandon-turn.d.ts +12 -1
  260. package/dist/runtime/query/abandon-turn.d.ts.map +1 -1
  261. package/dist/runtime/query/abandon-turn.js +3 -1
  262. package/dist/runtime/query/abandon-turn.js.map +1 -1
  263. package/dist/runtime/query/checkpoint.d.ts +4 -0
  264. package/dist/runtime/query/checkpoint.d.ts.map +1 -1
  265. package/dist/runtime/query/checkpoint.js +10 -0
  266. package/dist/runtime/query/checkpoint.js.map +1 -1
  267. package/dist/runtime/query/durable-inbound.d.ts +5 -0
  268. package/dist/runtime/query/durable-inbound.d.ts.map +1 -0
  269. package/dist/runtime/query/durable-inbound.js +89 -0
  270. package/dist/runtime/query/durable-inbound.js.map +1 -0
  271. package/dist/runtime/query/events.d.ts +4 -0
  272. package/dist/runtime/query/events.d.ts.map +1 -1
  273. package/dist/runtime/query/events.js +22 -5
  274. package/dist/runtime/query/events.js.map +1 -1
  275. package/dist/runtime/query/executor/tool-call-admission.d.ts +5 -1
  276. package/dist/runtime/query/executor/tool-call-admission.d.ts.map +1 -1
  277. package/dist/runtime/query/executor/tool-call-admission.js +85 -13
  278. package/dist/runtime/query/executor/tool-call-admission.js.map +1 -1
  279. package/dist/runtime/query/executor.d.ts +41 -18
  280. package/dist/runtime/query/executor.d.ts.map +1 -1
  281. package/dist/runtime/query/executor.js +227 -114
  282. package/dist/runtime/query/executor.js.map +1 -1
  283. package/dist/runtime/query/index.d.ts +3 -0
  284. package/dist/runtime/query/index.d.ts.map +1 -1
  285. package/dist/runtime/query/index.js +21 -4
  286. package/dist/runtime/query/index.js.map +1 -1
  287. package/dist/runtime/query/iteration/index.d.ts +18 -6
  288. package/dist/runtime/query/iteration/index.d.ts.map +1 -1
  289. package/dist/runtime/query/iteration/index.js +144 -67
  290. package/dist/runtime/query/iteration/index.js.map +1 -1
  291. package/dist/runtime/query/iteration/outstanding-work.d.ts +9 -5
  292. package/dist/runtime/query/iteration/outstanding-work.d.ts.map +1 -1
  293. package/dist/runtime/query/iteration/outstanding-work.js +61 -6
  294. package/dist/runtime/query/iteration/outstanding-work.js.map +1 -1
  295. package/dist/runtime/query/iteration/phases/context.d.ts +4 -0
  296. package/dist/runtime/query/iteration/phases/context.d.ts.map +1 -1
  297. package/dist/runtime/query/iteration/phases/context.js.map +1 -1
  298. package/dist/runtime/query/iteration/phases/tool-review.d.ts.map +1 -1
  299. package/dist/runtime/query/iteration/phases/tool-review.js +99 -16
  300. package/dist/runtime/query/iteration/phases/tool-review.js.map +1 -1
  301. package/dist/runtime/query/observation-context.d.ts +2 -2
  302. package/dist/runtime/query/observation-context.d.ts.map +1 -1
  303. package/dist/runtime/query/observation-context.js +20 -13
  304. package/dist/runtime/query/observation-context.js.map +1 -1
  305. package/dist/runtime/query/prepare-turn.js +2 -2
  306. package/dist/runtime/query/prepare-turn.js.map +1 -1
  307. package/dist/runtime/query/prompt-cache.d.ts +1 -0
  308. package/dist/runtime/query/prompt-cache.d.ts.map +1 -1
  309. package/dist/runtime/query/prompt-cache.js +2 -0
  310. package/dist/runtime/query/prompt-cache.js.map +1 -1
  311. package/dist/runtime/query/prompt.d.ts +2 -0
  312. package/dist/runtime/query/prompt.d.ts.map +1 -1
  313. package/dist/runtime/query/prompt.js +23 -1
  314. package/dist/runtime/query/prompt.js.map +1 -1
  315. package/dist/runtime/query/repeat-call.d.ts +12 -3
  316. package/dist/runtime/query/repeat-call.d.ts.map +1 -1
  317. package/dist/runtime/query/repeat-call.js +33 -10
  318. package/dist/runtime/query/repeat-call.js.map +1 -1
  319. package/dist/runtime/query/resume-pending.d.ts +5 -6
  320. package/dist/runtime/query/resume-pending.d.ts.map +1 -1
  321. package/dist/runtime/query/resume-pending.js +30 -3
  322. package/dist/runtime/query/resume-pending.js.map +1 -1
  323. package/dist/runtime/query/resume-session.js +1 -1
  324. package/dist/runtime/query/resume-session.js.map +1 -1
  325. package/dist/runtime/query/review-policy.d.ts +8 -1
  326. package/dist/runtime/query/review-policy.d.ts.map +1 -1
  327. package/dist/runtime/query/review-policy.js +6 -0
  328. package/dist/runtime/query/review-policy.js.map +1 -1
  329. package/dist/runtime/query/saved-presentation.d.ts +13 -0
  330. package/dist/runtime/query/saved-presentation.d.ts.map +1 -0
  331. package/dist/runtime/query/saved-presentation.js +63 -0
  332. package/dist/runtime/query/saved-presentation.js.map +1 -0
  333. package/dist/runtime/query/steering.d.ts +6 -9
  334. package/dist/runtime/query/steering.d.ts.map +1 -1
  335. package/dist/runtime/query/steering.js.map +1 -1
  336. package/dist/runtime/query/tool-executions.d.ts +7 -3
  337. package/dist/runtime/query/tool-executions.d.ts.map +1 -1
  338. package/dist/runtime/query/tool-executions.js +89 -9
  339. package/dist/runtime/query/tool-executions.js.map +1 -1
  340. package/dist/runtime/query/tooling.d.ts +3 -1
  341. package/dist/runtime/query/tooling.d.ts.map +1 -1
  342. package/dist/runtime/query/tooling.js +3 -0
  343. package/dist/runtime/query/tooling.js.map +1 -1
  344. package/dist/scheduler/completion-inbox.d.ts +25 -1
  345. package/dist/scheduler/completion-inbox.d.ts.map +1 -1
  346. package/dist/scheduler/completion-inbox.js +102 -8
  347. package/dist/scheduler/completion-inbox.js.map +1 -1
  348. package/dist/scheduler/delegating.d.ts.map +1 -1
  349. package/dist/scheduler/delegating.js +5 -0
  350. package/dist/scheduler/delegating.js.map +1 -1
  351. package/dist/scheduler/local.d.ts.map +1 -1
  352. package/dist/scheduler/local.js +2 -0
  353. package/dist/scheduler/local.js.map +1 -1
  354. package/dist/session/summary/materialize.d.ts +10 -6
  355. package/dist/session/summary/materialize.d.ts.map +1 -1
  356. package/dist/session/summary/materialize.js +41 -8
  357. package/dist/session/summary/materialize.js.map +1 -1
  358. package/dist/store/budget/ledger.d.ts +9 -0
  359. package/dist/store/budget/ledger.d.ts.map +1 -1
  360. package/dist/store/budget/ledger.js +58 -6
  361. package/dist/store/budget/ledger.js.map +1 -1
  362. package/dist/store/evidence/index-page.d.ts +12 -12
  363. package/dist/store/evidence/source-text.d.ts +4 -4
  364. package/dist/store/session/disk.d.ts +9 -4
  365. package/dist/store/session/disk.d.ts.map +1 -1
  366. package/dist/store/session/disk.js +57 -11
  367. package/dist/store/session/disk.js.map +1 -1
  368. package/dist/store/session/memory.d.ts +5 -3
  369. package/dist/store/session/memory.d.ts.map +1 -1
  370. package/dist/store/session/memory.js +24 -7
  371. package/dist/store/session/memory.js.map +1 -1
  372. package/dist/store/session-log/core.d.ts +26 -6
  373. package/dist/store/session-log/core.d.ts.map +1 -1
  374. package/dist/store/session-log/core.js +61 -8
  375. package/dist/store/session-log/core.js.map +1 -1
  376. package/dist/store/session-log/disk.d.ts +2 -2
  377. package/dist/store/session-log/disk.d.ts.map +1 -1
  378. package/dist/store/session-log/disk.js +1 -0
  379. package/dist/store/session-log/disk.js.map +1 -1
  380. package/dist/store/session-log/fold.d.ts +7 -0
  381. package/dist/store/session-log/fold.d.ts.map +1 -1
  382. package/dist/store/session-log/fold.js +21 -0
  383. package/dist/store/session-log/fold.js.map +1 -1
  384. package/dist/store/session-log/index.d.ts +5 -3
  385. package/dist/store/session-log/index.d.ts.map +1 -1
  386. package/dist/store/session-log/index.js +3 -1
  387. package/dist/store/session-log/index.js.map +1 -1
  388. package/dist/store/session-log/memory.d.ts +1 -1
  389. package/dist/store/session-log/memory.d.ts.map +1 -1
  390. package/dist/store/session-log/memory.js +1 -0
  391. package/dist/store/session-log/memory.js.map +1 -1
  392. package/dist/store/session-log/spill.d.ts +10 -3
  393. package/dist/store/session-log/spill.d.ts.map +1 -1
  394. package/dist/store/session-log/spill.js +70 -5
  395. package/dist/store/session-log/spill.js.map +1 -1
  396. package/dist/store/session-log/structured-result.d.ts +21 -0
  397. package/dist/store/session-log/structured-result.d.ts.map +1 -0
  398. package/dist/store/session-log/structured-result.js +67 -0
  399. package/dist/store/session-log/structured-result.js.map +1 -0
  400. package/dist/store/task/disk.d.ts +11 -0
  401. package/dist/store/task/disk.d.ts.map +1 -1
  402. package/dist/store/task/disk.js +41 -2
  403. package/dist/store/task/disk.js.map +1 -1
  404. package/dist/store/task/memory.d.ts.map +1 -1
  405. package/dist/store/task/memory.js +15 -3
  406. package/dist/store/task/memory.js.map +1 -1
  407. package/dist/tools/admit-facts.d.ts +13 -0
  408. package/dist/tools/admit-facts.d.ts.map +1 -0
  409. package/dist/tools/admit-facts.js +142 -0
  410. package/dist/tools/admit-facts.js.map +1 -0
  411. package/dist/tools/builtins/bash.d.ts +4 -1
  412. package/dist/tools/builtins/bash.d.ts.map +1 -1
  413. package/dist/tools/builtins/bash.js +108 -22
  414. package/dist/tools/builtins/bash.js.map +1 -1
  415. package/dist/tools/builtins/browser.d.ts +10 -10
  416. package/dist/tools/builtins/computer-use.d.ts +90 -90
  417. package/dist/tools/builtins/edit.d.ts +17 -0
  418. package/dist/tools/builtins/edit.d.ts.map +1 -1
  419. package/dist/tools/builtins/edit.js +46 -1
  420. package/dist/tools/builtins/edit.js.map +1 -1
  421. package/dist/tools/builtins/file-write-result.d.ts.map +1 -1
  422. package/dist/tools/builtins/file-write-result.js +13 -0
  423. package/dist/tools/builtins/file-write-result.js.map +1 -1
  424. package/dist/tools/builtins/glob.d.ts.map +1 -1
  425. package/dist/tools/builtins/glob.js +12 -0
  426. package/dist/tools/builtins/glob.js.map +1 -1
  427. package/dist/tools/builtins/grep.d.ts.map +1 -1
  428. package/dist/tools/builtins/grep.js +14 -0
  429. package/dist/tools/builtins/grep.js.map +1 -1
  430. package/dist/tools/builtins/index.d.ts +2 -0
  431. package/dist/tools/builtins/index.d.ts.map +1 -1
  432. package/dist/tools/builtins/index.js +1 -0
  433. package/dist/tools/builtins/index.js.map +1 -1
  434. package/dist/tools/builtins/job.d.ts.map +1 -1
  435. package/dist/tools/builtins/job.js +4 -1
  436. package/dist/tools/builtins/job.js.map +1 -1
  437. package/dist/tools/builtins/lsp.d.ts +2 -2
  438. package/dist/tools/builtins/read-file.d.ts.map +1 -1
  439. package/dist/tools/builtins/read-file.js +49 -0
  440. package/dist/tools/builtins/read-file.js.map +1 -1
  441. package/dist/tools/builtins/view-image.d.ts +24 -0
  442. package/dist/tools/builtins/view-image.d.ts.map +1 -0
  443. package/dist/tools/builtins/view-image.js +385 -0
  444. package/dist/tools/builtins/view-image.js.map +1 -0
  445. package/dist/tools/builtins/wait-for-job-bounds.d.ts +2 -0
  446. package/dist/tools/builtins/wait-for-job-bounds.d.ts.map +1 -1
  447. package/dist/tools/builtins/wait-for-job-bounds.js +1 -0
  448. package/dist/tools/builtins/wait-for-job-bounds.js.map +1 -1
  449. package/dist/tools/builtins/wait-for-job.d.ts +2 -0
  450. package/dist/tools/builtins/wait-for-job.d.ts.map +1 -1
  451. package/dist/tools/builtins/wait-for-job.js +104 -6
  452. package/dist/tools/builtins/wait-for-job.js.map +1 -1
  453. package/dist/tools/builtins/write-file.d.ts.map +1 -1
  454. package/dist/tools/builtins/write-file.js +1 -0
  455. package/dist/tools/builtins/write-file.js.map +1 -1
  456. package/dist/tools/command-shell.d.ts +37 -2
  457. package/dist/tools/command-shell.d.ts.map +1 -1
  458. package/dist/tools/command-shell.js +100 -3
  459. package/dist/tools/command-shell.js.map +1 -1
  460. package/dist/tools/coordinator/agent.d.ts +9 -19
  461. package/dist/tools/coordinator/agent.d.ts.map +1 -1
  462. package/dist/tools/coordinator/agent.js.map +1 -1
  463. package/dist/tools/coordinator/index.d.ts.map +1 -1
  464. package/dist/tools/coordinator/index.js +127 -67
  465. package/dist/tools/coordinator/index.js.map +1 -1
  466. package/dist/tools/coordinator/wait-with-idle-bound.d.ts +2 -0
  467. package/dist/tools/coordinator/wait-with-idle-bound.d.ts.map +1 -1
  468. package/dist/tools/coordinator/wait-with-idle-bound.js +1 -1
  469. package/dist/tools/coordinator/wait-with-idle-bound.js.map +1 -1
  470. package/dist/tools/defineTool.d.ts.map +1 -1
  471. package/dist/tools/defineTool.js +4 -0
  472. package/dist/tools/defineTool.js.map +1 -1
  473. package/dist/tools/failure-facts.d.ts +8 -0
  474. package/dist/tools/failure-facts.d.ts.map +1 -0
  475. package/dist/tools/failure-facts.js +24 -0
  476. package/dist/tools/failure-facts.js.map +1 -0
  477. package/dist/tools/host-output.d.ts +24 -0
  478. package/dist/tools/host-output.d.ts.map +1 -0
  479. package/dist/tools/host-output.js +117 -0
  480. package/dist/tools/host-output.js.map +1 -0
  481. package/dist/tools/oem-code-pages.d.ts +8 -0
  482. package/dist/tools/oem-code-pages.d.ts.map +1 -0
  483. package/dist/tools/oem-code-pages.js +23 -0
  484. package/dist/tools/oem-code-pages.js.map +1 -0
  485. package/dist/tools/schedules/schedule-tool.d.ts.map +1 -1
  486. package/dist/tools/schedules/schedule-tool.js +35 -6
  487. package/dist/tools/schedules/schedule-tool.js.map +1 -1
  488. package/dist/tools/schedules/types.d.ts +23 -3
  489. package/dist/tools/schedules/types.d.ts.map +1 -1
  490. package/dist/tools/task/list.d.ts.map +1 -1
  491. package/dist/tools/task/list.js +14 -6
  492. package/dist/tools/task/list.js.map +1 -1
  493. package/dist/tools/task/present.d.ts.map +1 -1
  494. package/dist/tools/task/present.js +26 -6
  495. package/dist/tools/task/present.js.map +1 -1
  496. package/dist/tools/task/update.d.ts.map +1 -1
  497. package/dist/tools/task/update.js +12 -5
  498. package/dist/tools/task/update.js.map +1 -1
  499. package/dist/tools/text-window.d.ts +19 -0
  500. package/dist/tools/text-window.d.ts.map +1 -0
  501. package/dist/tools/text-window.js +83 -0
  502. package/dist/tools/text-window.js.map +1 -0
  503. package/dist/toolsets/manager.d.ts +11 -0
  504. package/dist/toolsets/manager.d.ts.map +1 -1
  505. package/dist/toolsets/manager.js +45 -1
  506. package/dist/toolsets/manager.js.map +1 -1
  507. package/dist/types/acp/index.d.ts +137 -1
  508. package/dist/types/acp/index.d.ts.map +1 -1
  509. package/dist/types/agent/base.d.ts +3 -0
  510. package/dist/types/agent/base.d.ts.map +1 -1
  511. package/dist/types/agent/manager.d.ts +8 -23
  512. package/dist/types/agent/manager.d.ts.map +1 -1
  513. package/dist/types/agent/scheduler.d.ts +10 -1
  514. package/dist/types/agent/scheduler.d.ts.map +1 -1
  515. package/dist/types/agent/task.d.ts +4 -0
  516. package/dist/types/agent/task.d.ts.map +1 -1
  517. package/dist/types/authorization/index.d.ts +30 -30
  518. package/dist/types/connector/mcp.d.ts +7 -0
  519. package/dist/types/connector/mcp.d.ts.map +1 -1
  520. package/dist/types/errors/catalog.d.ts.map +1 -1
  521. package/dist/types/errors/catalog.js +4 -2
  522. package/dist/types/errors/catalog.js.map +1 -1
  523. package/dist/types/harness/schema.d.ts +354 -0
  524. package/dist/types/harness/schema.d.ts.map +1 -0
  525. package/dist/types/harness/schema.js +203 -0
  526. package/dist/types/harness/schema.js.map +1 -0
  527. package/dist/types/harness/session.d.ts +278 -0
  528. package/dist/types/harness/session.d.ts.map +1 -0
  529. package/dist/types/harness/session.js +2 -0
  530. package/dist/types/harness/session.js.map +1 -0
  531. package/dist/types/hitl/index.d.ts +12 -0
  532. package/dist/types/hitl/index.d.ts.map +1 -1
  533. package/dist/types/hitl/index.js.map +1 -1
  534. package/dist/types/job/index.d.ts +47 -0
  535. package/dist/types/job/index.d.ts.map +1 -0
  536. package/dist/types/job/index.js +2 -0
  537. package/dist/types/job/index.js.map +1 -0
  538. package/dist/types/message/inbound-delivery.d.ts +44 -0
  539. package/dist/types/message/inbound-delivery.d.ts.map +1 -0
  540. package/dist/types/message/inbound-delivery.js +14 -0
  541. package/dist/types/message/inbound-delivery.js.map +1 -0
  542. package/dist/types/message/index.d.ts +4 -1
  543. package/dist/types/message/index.d.ts.map +1 -1
  544. package/dist/types/message/index.js +5 -1
  545. package/dist/types/message/index.js.map +1 -1
  546. package/dist/types/plugin/index.d.ts +6 -6
  547. package/dist/types/sandbox/index.d.ts +39 -2
  548. package/dist/types/sandbox/index.d.ts.map +1 -1
  549. package/dist/types/sandbox/index.js.map +1 -1
  550. package/dist/types/session/checkpoint.d.ts +24 -17
  551. package/dist/types/session/checkpoint.d.ts.map +1 -1
  552. package/dist/types/session/checkpoint.js +1 -0
  553. package/dist/types/session/checkpoint.js.map +1 -1
  554. package/dist/types/session/events.d.ts +23 -1
  555. package/dist/types/session/events.d.ts.map +1 -1
  556. package/dist/types/session/events.js.map +1 -1
  557. package/dist/types/session/records.d.ts +1514 -565
  558. package/dist/types/session/records.d.ts.map +1 -1
  559. package/dist/types/session/records.js +89 -1
  560. package/dist/types/session/records.js.map +1 -1
  561. package/dist/types/session/step.d.ts +2 -0
  562. package/dist/types/session/step.d.ts.map +1 -1
  563. package/dist/types/session/step.js.map +1 -1
  564. package/dist/types/session/store.d.ts +19 -10
  565. package/dist/types/session/store.d.ts.map +1 -1
  566. package/dist/types/session/tool-execution.d.ts +6 -0
  567. package/dist/types/session/tool-execution.d.ts.map +1 -1
  568. package/dist/types/structured-output/index.d.ts +12 -2
  569. package/dist/types/structured-output/index.d.ts.map +1 -1
  570. package/dist/types/summary/ref.d.ts +3 -1
  571. package/dist/types/summary/ref.d.ts.map +1 -1
  572. package/dist/types/tool/index.d.ts +32 -4
  573. package/dist/types/tool/index.d.ts.map +1 -1
  574. package/dist/types/tool/index.js.map +1 -1
  575. package/dist/types/tool/presentation.d.ts +106 -0
  576. package/dist/types/tool/presentation.d.ts.map +1 -1
  577. package/dist/utils/json-snapshot.d.ts +6 -2
  578. package/dist/utils/json-snapshot.d.ts.map +1 -1
  579. package/dist/utils/json-snapshot.js +19 -9
  580. package/dist/utils/json-snapshot.js.map +1 -1
  581. package/dist/utils/structured-result-json.d.ts +5 -0
  582. package/dist/utils/structured-result-json.d.ts.map +1 -0
  583. package/dist/utils/structured-result-json.js +10 -0
  584. package/dist/utils/structured-result-json.js.map +1 -0
  585. package/package.json +1 -1
  586. package/src/agents/QueryAgent.ts +1 -0
  587. package/src/agents/examples/SupervisorAgent.ts +1 -0
  588. package/src/agents/runAgent.ts +3 -0
  589. package/src/authorization/shell-lexer.ts +16 -1
  590. package/src/bridge/acp/permission.ts +17 -3
  591. package/src/bridge/acp/server.ts +271 -25
  592. package/src/bridge/acp/tasks.ts +23 -0
  593. package/src/bridge/acp/update.ts +167 -13
  594. package/src/connector/mcp/adapter.ts +16 -4
  595. package/src/connector/mcp/client.ts +6 -2
  596. package/src/constants/acp/index.ts +4 -0
  597. package/src/manager/agent/lifecycle.ts +230 -3
  598. package/src/manager/plan/lifecycle.ts +11 -9
  599. package/src/manager/session/attribution.ts +12 -2
  600. package/src/manager/session/streamed-message-identity.ts +21 -0
  601. package/src/manager/session/turn-recorder.ts +4 -3
  602. package/src/pals/activity/causality.ts +261 -0
  603. package/src/pals/activity/projection.ts +89 -0
  604. package/src/pals/activity/source.ts +240 -0
  605. package/src/pals/activity/subscription-policy.ts +230 -0
  606. package/src/pals/activity/subscription-schema.ts +27 -0
  607. package/src/pals/activity/subscription-store.ts +172 -0
  608. package/src/pals/activity/subscription-types.ts +48 -0
  609. package/src/pals/activity/subscriptions.ts +209 -0
  610. package/src/pals/activity/types.ts +108 -0
  611. package/src/pals/channels/ingress.ts +153 -0
  612. package/src/pals/channels/routes.ts +118 -0
  613. package/src/pals/channels/routing.ts +197 -0
  614. package/src/pals/channels/schema.ts +108 -0
  615. package/src/pals/channels/types.ts +156 -0
  616. package/src/pals/communication/broker.ts +131 -0
  617. package/src/pals/communication/dispatch.ts +66 -0
  618. package/src/pals/communication/inbound.ts +193 -0
  619. package/src/pals/communication/ingress-dispatch.ts +63 -0
  620. package/src/pals/communication/ingress-inbound.ts +269 -0
  621. package/src/pals/communication/ingress-schema.ts +526 -0
  622. package/src/pals/communication/ingress-types.ts +336 -0
  623. package/src/pals/communication/operator.ts +315 -0
  624. package/src/pals/communication/policy.ts +174 -0
  625. package/src/pals/communication/schema.ts +173 -0
  626. package/src/pals/communication/store.ts +577 -0
  627. package/src/pals/communication/tools.ts +139 -0
  628. package/src/pals/communication/types.ts +227 -0
  629. package/src/pals/communication/verify.ts +220 -0
  630. package/src/pals/lifecycle.ts +54 -0
  631. package/src/pals/prompt.ts +101 -0
  632. package/src/pals/reference-images.ts +322 -0
  633. package/src/pals/runtime.ts +670 -0
  634. package/src/pals/store.ts +369 -0
  635. package/src/pals/types.ts +157 -0
  636. package/src/peers/envelope.ts +1 -1
  637. package/src/plugin/shell-hook.ts +8 -2
  638. package/src/process/kill-tree.ts +10 -1
  639. package/src/provider/errors.ts +135 -2
  640. package/src/provider/strict-schema.ts +90 -0
  641. package/src/public-runtime.ts +118 -12
  642. package/src/public-tools.ts +13 -1
  643. package/src/public-types.ts +69 -7
  644. package/src/registry/tool/presentation.ts +9 -4
  645. package/src/runtime/harness-session/index.ts +1125 -0
  646. package/src/runtime/harness-session/journal.ts +209 -0
  647. package/src/runtime/harness-session/saved-view.ts +122 -0
  648. package/src/runtime/jobs/awaited-jobs.ts +2 -1
  649. package/src/runtime/jobs/registry.ts +397 -41
  650. package/src/runtime/query/abandon-turn.ts +18 -2
  651. package/src/runtime/query/checkpoint.ts +11 -0
  652. package/src/runtime/query/durable-inbound.ts +101 -0
  653. package/src/runtime/query/events.ts +22 -5
  654. package/src/runtime/query/executor/tool-call-admission.ts +125 -32
  655. package/src/runtime/query/executor.ts +316 -130
  656. package/src/runtime/query/index.ts +24 -4
  657. package/src/runtime/query/iteration/index.ts +218 -104
  658. package/src/runtime/query/iteration/outstanding-work.ts +55 -7
  659. package/src/runtime/query/iteration/phases/context.ts +4 -0
  660. package/src/runtime/query/iteration/phases/tool-review.ts +118 -21
  661. package/src/runtime/query/observation-context.ts +22 -16
  662. package/src/runtime/query/prepare-turn.ts +2 -2
  663. package/src/runtime/query/prompt-cache.ts +3 -0
  664. package/src/runtime/query/prompt.ts +32 -1
  665. package/src/runtime/query/repeat-call.ts +40 -10
  666. package/src/runtime/query/resume-pending.ts +60 -7
  667. package/src/runtime/query/resume-session.ts +1 -1
  668. package/src/runtime/query/review-policy.ts +23 -2
  669. package/src/runtime/query/saved-presentation.ts +70 -0
  670. package/src/runtime/query/steering.ts +6 -9
  671. package/src/runtime/query/tool-executions.ts +108 -9
  672. package/src/runtime/query/tooling.ts +6 -1
  673. package/src/scheduler/completion-inbox.ts +108 -7
  674. package/src/scheduler/delegating.ts +5 -0
  675. package/src/scheduler/local.ts +2 -0
  676. package/src/session/summary/materialize.ts +51 -9
  677. package/src/store/budget/ledger.ts +60 -5
  678. package/src/store/session/disk.ts +77 -10
  679. package/src/store/session/memory.ts +32 -7
  680. package/src/store/session-log/core.ts +118 -11
  681. package/src/store/session-log/disk.ts +9 -2
  682. package/src/store/session-log/fold.ts +22 -0
  683. package/src/store/session-log/index.ts +5 -0
  684. package/src/store/session-log/memory.ts +2 -1
  685. package/src/store/session-log/spill.ts +89 -6
  686. package/src/store/session-log/structured-result.ts +96 -0
  687. package/src/store/task/disk.ts +46 -2
  688. package/src/store/task/memory.ts +13 -3
  689. package/src/tools/admit-facts.ts +145 -0
  690. package/src/tools/builtins/bash.ts +132 -24
  691. package/src/tools/builtins/edit.ts +54 -1
  692. package/src/tools/builtins/file-write-result.ts +14 -0
  693. package/src/tools/builtins/glob.ts +12 -0
  694. package/src/tools/builtins/grep.ts +14 -0
  695. package/src/tools/builtins/index.ts +2 -0
  696. package/src/tools/builtins/job.ts +4 -1
  697. package/src/tools/builtins/read-file.ts +57 -0
  698. package/src/tools/builtins/view-image.ts +409 -0
  699. package/src/tools/builtins/wait-for-job-bounds.ts +3 -0
  700. package/src/tools/builtins/wait-for-job.ts +141 -32
  701. package/src/tools/builtins/write-file.ts +4 -2
  702. package/src/tools/command-shell.ts +132 -5
  703. package/src/tools/coordinator/agent.ts +9 -19
  704. package/src/tools/coordinator/index.ts +150 -75
  705. package/src/tools/coordinator/wait-with-idle-bound.ts +3 -1
  706. package/src/tools/defineTool.ts +4 -0
  707. package/src/tools/failure-facts.ts +24 -0
  708. package/src/tools/host-output.ts +136 -0
  709. package/src/tools/oem-code-pages.ts +22 -0
  710. package/src/tools/schedules/schedule-tool.ts +38 -5
  711. package/src/tools/schedules/types.ts +23 -3
  712. package/src/tools/task/list.ts +15 -7
  713. package/src/tools/task/present.ts +37 -7
  714. package/src/tools/task/update.ts +12 -5
  715. package/src/tools/text-window.ts +87 -0
  716. package/src/toolsets/manager.ts +58 -1
  717. package/src/types/acp/index.ts +150 -4
  718. package/src/types/agent/base.ts +3 -0
  719. package/src/types/agent/manager.ts +8 -23
  720. package/src/types/agent/scheduler.ts +10 -1
  721. package/src/types/agent/task.ts +4 -0
  722. package/src/types/connector/mcp.ts +7 -0
  723. package/src/types/errors/catalog.ts +4 -2
  724. package/src/types/harness/schema.ts +203 -0
  725. package/src/types/harness/session.ts +306 -0
  726. package/src/types/hitl/index.ts +17 -1
  727. package/src/types/job/index.ts +42 -0
  728. package/src/types/message/inbound-delivery.ts +63 -0
  729. package/src/types/message/index.ts +8 -1
  730. package/src/types/sandbox/index.ts +46 -0
  731. package/src/types/session/checkpoint.ts +4 -1
  732. package/src/types/session/events.ts +23 -1
  733. package/src/types/session/records.ts +114 -2
  734. package/src/types/session/step.ts +2 -0
  735. package/src/types/session/store.ts +23 -9
  736. package/src/types/session/tool-execution.ts +6 -0
  737. package/src/types/structured-output/index.ts +13 -2
  738. package/src/types/summary/ref.ts +3 -1
  739. package/src/types/tool/index.ts +39 -5
  740. package/src/types/tool/presentation.ts +121 -0
  741. package/src/utils/json-snapshot.ts +26 -9
  742. package/src/utils/structured-result-json.ts +10 -0
@@ -0,0 +1,409 @@
1
+ import { createHash } from 'node:crypto'
2
+ import { open } from 'node:fs/promises'
3
+ import { inflateSync } from 'node:zlib'
4
+ import { z } from 'zod'
5
+ import { admitMcpImageBatch } from '../../connector/mcp/image-admission.js'
6
+ import type { ToolContext, ToolDefinition } from '../../types/tool/index.js'
7
+ import { defineTool } from '../defineTool.js'
8
+ import { resolveWithinAnyReal, toolRoots } from '../paths.js'
9
+ import { STANDARD_SCREENSHOT_LIMITS, fitPng, screenshotTargetSize } from './computer-use-image.js'
10
+
11
+ // 16 MiB becomes less than the runtime's 24 MiB encoded rich-content budget.
12
+ // Admission is per artifact; the runtime still budgets accumulated images.
13
+ const MAX_BYTES = 16 * 1024 * 1024
14
+ const READ_CHUNK_BYTES = 1024 * 1024
15
+ const MAX_EDGE = 16_384
16
+ const MAX_PIXELS = 16_000_000
17
+ const PNG_SIGNATURE = Buffer.from('89504e470d0a1a0a', 'hex')
18
+ const JPEG_FRAME_MARKERS = new Set([
19
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc5, 0xc6, 0xc7, 0xc9, 0xca, 0xcb, 0xcd, 0xce, 0xcf,
20
+ ])
21
+
22
+ const inputSchema = z.object({
23
+ path: z.string().min(1).describe("Path to a saved PNG, JPEG or WebP image in this turn's files"),
24
+ })
25
+
26
+ /** Host admission for a model which cannot receive image tool results. */
27
+ export interface ViewImageToolOptions {
28
+ readonly unavailableReason?: string
29
+ }
30
+
31
+ interface Raster {
32
+ readonly mediaType: 'image/png' | 'image/jpeg' | 'image/webp'
33
+ readonly width: number
34
+ readonly height: number
35
+ }
36
+
37
+ async function readBounded(
38
+ read: (offset: number, length: number) => Promise<Buffer>,
39
+ signal: AbortSignal,
40
+ ): Promise<Buffer> {
41
+ const chunks: Buffer[] = []
42
+ let offset = 0
43
+ for (;;) {
44
+ signal.throwIfAborted()
45
+ const length = Math.min(READ_CHUNK_BYTES, MAX_BYTES + 1 - offset)
46
+ const chunk = await read(offset, length)
47
+ signal.throwIfAborted()
48
+ if (chunk.length > length)
49
+ throw new Error('The file backend returned more bytes than the requested bounded range.')
50
+ offset += chunk.length
51
+ if (offset > MAX_BYTES)
52
+ throw new Error('Image exceeds the 16 MiB inspection limit. Export a smaller image.')
53
+ chunks.push(chunk)
54
+ if (chunk.length < length) return Buffer.concat(chunks, offset)
55
+ }
56
+ }
57
+
58
+ async function readArtifact(
59
+ path: string,
60
+ context: ToolContext,
61
+ ): Promise<{ path: string; bytes: Buffer; sandboxed: boolean }> {
62
+ context.abortSignal.throwIfAborted()
63
+ if (context.sandbox) {
64
+ const bytes = await context.sandbox.readFile(path, {
65
+ offset: 0,
66
+ length: MAX_BYTES + 1,
67
+ signal: context.abortSignal,
68
+ })
69
+ context.abortSignal.throwIfAborted()
70
+ if (bytes.length > MAX_BYTES)
71
+ throw new Error('Image exceeds the 16 MiB inspection limit. Export a smaller image.')
72
+ return { path, bytes, sandboxed: true }
73
+ }
74
+ const resolved = await resolveWithinAnyReal(toolRoots(context), path)
75
+ const file = await open(resolved, 'r')
76
+ try {
77
+ const stat = await file.stat()
78
+ if (!stat.isFile()) throw new Error('Image inspection requires a regular file.')
79
+ if (stat.size > MAX_BYTES)
80
+ throw new Error('Image exceeds the 16 MiB inspection limit. Export a smaller image.')
81
+ const bytes = await readBounded(async (offset, length) => {
82
+ const buffer = Buffer.allocUnsafe(length)
83
+ const { bytesRead } = await file.read(buffer, 0, length, offset)
84
+ return buffer.subarray(0, bytesRead)
85
+ }, context.abortSignal)
86
+ return { path: resolved, bytes, sandboxed: false }
87
+ } finally {
88
+ await file.close()
89
+ }
90
+ }
91
+
92
+ function malformed(): never {
93
+ throw new Error('Image is malformed or truncated. Export a complete static PNG, JPEG or WebP.')
94
+ }
95
+
96
+ function jpegDimensions(bytes: Buffer): Pick<Raster, 'width' | 'height'> {
97
+ let offset = 2
98
+ let inScan = false
99
+ let frame: Pick<Raster, 'width' | 'height'> | undefined
100
+ while (offset < bytes.length) {
101
+ if (inScan && bytes[offset] !== 0xff) {
102
+ offset += 1
103
+ continue
104
+ }
105
+ if (bytes[offset] !== 0xff) malformed()
106
+ while (bytes[offset] === 0xff) offset += 1
107
+ const marker = bytes[offset]
108
+ if (marker === undefined) malformed()
109
+ offset += 1
110
+ if (inScan && (marker === 0 || (marker >= 0xd0 && marker <= 0xd7))) continue
111
+ inScan = false
112
+ if (marker === 0xd9) break
113
+ if (marker === 0xd8 || marker === 0x01 || (marker >= 0xd0 && marker <= 0xd7)) continue
114
+ if (offset + 2 > bytes.length) malformed()
115
+ const length = bytes.readUInt16BE(offset)
116
+ if (length < 2 || offset + length > bytes.length) malformed()
117
+ if (JPEG_FRAME_MARKERS.has(marker)) {
118
+ if (length < 8 || frame) malformed()
119
+ frame = {
120
+ width: bytes.readUInt16BE(offset + 5),
121
+ height: bytes.readUInt16BE(offset + 3),
122
+ }
123
+ }
124
+ offset += length
125
+ if (marker === 0xda) inScan = true
126
+ }
127
+ return frame ?? malformed()
128
+ }
129
+
130
+ function webpDimensions(bytes: Buffer): Pick<Raster, 'width' | 'height'> {
131
+ let offset = 12
132
+ let dimensions: Pick<Raster, 'width' | 'height'> | undefined
133
+ while (offset + 8 <= bytes.length) {
134
+ const type = bytes.toString('ascii', offset, offset + 4)
135
+ const length = bytes.readUInt32LE(offset + 4)
136
+ const start = offset + 8
137
+ if (start + length > bytes.length) malformed()
138
+ let current: Pick<Raster, 'width' | 'height'> | undefined
139
+ if (type === 'ANIM' || type === 'ANMF')
140
+ throw new Error('Animated WebP is unsupported. Export the required frame as a static PNG.')
141
+ if (type === 'VP8X' && length >= 10) {
142
+ current = {
143
+ width: bytes.readUIntLE(start + 4, 3) + 1,
144
+ height: bytes.readUIntLE(start + 7, 3) + 1,
145
+ }
146
+ } else if (type === 'VP8L' && length >= 5 && bytes[start] === 0x2f) {
147
+ const packed = bytes.readUInt32LE(start + 1)
148
+ current = {
149
+ width: (packed & 0x3fff) + 1,
150
+ height: ((packed >>> 14) & 0x3fff) + 1,
151
+ }
152
+ } else if (type === 'VP8 ' && length >= 10) {
153
+ current = {
154
+ width: bytes.readUInt16LE(start + 6) & 0x3fff,
155
+ height: bytes.readUInt16LE(start + 8) & 0x3fff,
156
+ }
157
+ }
158
+ if (current) {
159
+ if (
160
+ dimensions &&
161
+ (dimensions.width !== current.width || dimensions.height !== current.height)
162
+ )
163
+ malformed()
164
+ dimensions = current
165
+ }
166
+ offset = start + length + (length & 1)
167
+ }
168
+ return dimensions ?? malformed()
169
+ }
170
+
171
+ function describeRaster(bytes: Buffer): Raster {
172
+ let raster: Raster
173
+ if (bytes.subarray(0, 8).equals(PNG_SIGNATURE)) {
174
+ if (bytes.length < 33) malformed()
175
+ raster = {
176
+ mediaType: 'image/png',
177
+ width: bytes.readUInt32BE(16),
178
+ height: bytes.readUInt32BE(20),
179
+ }
180
+ } else if (bytes[0] === 0xff && bytes[1] === 0xd8) {
181
+ raster = { mediaType: 'image/jpeg', ...jpegDimensions(bytes) }
182
+ } else if (
183
+ bytes.toString('ascii', 0, 4) === 'RIFF' &&
184
+ bytes.toString('ascii', 8, 12) === 'WEBP'
185
+ ) {
186
+ raster = { mediaType: 'image/webp', ...webpDimensions(bytes) }
187
+ } else {
188
+ throw new Error(
189
+ 'Unsupported image bytes. Export a static PNG, JPEG or WebP; renaming the file does not convert it.',
190
+ )
191
+ }
192
+ if (
193
+ raster.width < 1 ||
194
+ raster.height < 1 ||
195
+ raster.width > MAX_EDGE ||
196
+ raster.height > MAX_EDGE ||
197
+ raster.width * raster.height > MAX_PIXELS
198
+ )
199
+ throw new Error(
200
+ 'Image dimensions exceed the inspection limit (16,384 pixels per edge, 16 million pixels total). Export a smaller image.',
201
+ )
202
+ return raster
203
+ }
204
+
205
+ /** Validate bounded pixel data without inflating ancillary metadata. */
206
+ async function validatedPng(bytes: Buffer, raster: Raster): Promise<Buffer> {
207
+ const depth = bytes[24] ?? 0
208
+ const colour = bytes[25] ?? -1
209
+ const channels = ({ 0: 1, 2: 3, 3: 1, 4: 2, 6: 4 } as Record<number, number>)[colour]
210
+ const allowedDepths = colour === 0 ? [1, 2, 4, 8, 16] : colour === 3 ? [1, 2, 4, 8] : [8, 16]
211
+ if (
212
+ !channels ||
213
+ !allowedDepths.includes(depth) ||
214
+ bytes[26] !== 0 ||
215
+ bytes[27] !== 0 ||
216
+ (bytes[28] !== 0 && bytes[28] !== 1)
217
+ )
218
+ malformed()
219
+ // fast-png's Adam7 reader lays out sub-byte pixels as whole bytes. Do not
220
+ // return a success observation whose unpacked pixels differ from the file.
221
+ if (bytes[28] === 1 && depth < 8)
222
+ throw new Error(
223
+ 'Interlaced PNGs below 8 bits per sample are unsupported by this decoder. Export a non-interlaced or 8-bit PNG and inspect that file.',
224
+ )
225
+ const passes =
226
+ bytes[28] === 1
227
+ ? [
228
+ [0, 0, 8, 8],
229
+ [4, 0, 8, 8],
230
+ [0, 4, 4, 8],
231
+ [2, 0, 4, 4],
232
+ [0, 2, 2, 4],
233
+ [1, 0, 2, 2],
234
+ [0, 1, 1, 2],
235
+ ]
236
+ : [[0, 0, 1, 1]]
237
+ let expected = 0
238
+ for (const [x = 0, y = 0, dx = 1, dy = 1] of passes) {
239
+ const width = Math.max(0, Math.ceil((raster.width - x) / dx))
240
+ const height = Math.max(0, Math.ceil((raster.height - y) / dy))
241
+ if (width > 0 && height > 0)
242
+ expected += (Math.ceil((width * channels * depth) / 8) + 1) * height
243
+ }
244
+ const chunks: Buffer[] = [PNG_SIGNATURE]
245
+ const compressed: Buffer[] = []
246
+ let offset = 8
247
+ while (offset + 12 <= bytes.length) {
248
+ const length = bytes.readUInt32BE(offset)
249
+ const type = bytes.toString('ascii', offset + 4, offset + 8)
250
+ const end = offset + length + 12
251
+ if (end > bytes.length) malformed()
252
+ if (type === 'acTL' || type === 'fcTL' || type === 'fdAT')
253
+ throw new Error('Animated PNG is unsupported. Export the required frame as a static PNG.')
254
+ if (type === 'IDAT') compressed.push(bytes.subarray(offset + 8, end - 4))
255
+ if (['IHDR', 'PLTE', 'tRNS', 'IDAT', 'IEND'].includes(type))
256
+ chunks.push(bytes.subarray(offset, end))
257
+ else if (/^[A-Z]/.test(type)) throw new Error(`Unsupported critical PNG chunk: ${type}.`)
258
+ offset = end
259
+ }
260
+ // fast-png's inflater does not expose a byte ceiling. Check the complete
261
+ // compressed pixel stream with Node's ceiling before handing it the image.
262
+ try {
263
+ const inflated = inflateSync(Buffer.concat(compressed), {
264
+ maxOutputLength: expected,
265
+ })
266
+ if (inflated.length !== expected) malformed()
267
+ } catch {
268
+ malformed()
269
+ }
270
+ const canonical = Buffer.concat(chunks)
271
+ const { decode, encode, convertIndexedToRgb } = await import('fast-png')
272
+ try {
273
+ const decoded = decode(canonical, { checkCrc: true })
274
+ if (decoded.width !== raster.width || decoded.height !== raster.height) malformed()
275
+ // Decode indexed pixels too: a complete PLTE/IDAT container can still
276
+ // refer to a palette entry that does not exist.
277
+ if (decoded.palette) convertIndexedToRgb(decoded)
278
+ else if (decoded.depth < 8 || decoded.transparency) {
279
+ // Screenshot resizing assumes unpacked 8/16-bit samples and explicit
280
+ // alpha. Saved images can use packed greyscale or tRNS colour keys.
281
+ const rgba = new Uint8Array(raster.width * raster.height * 4)
282
+ const packedStride = Math.ceil((raster.width * decoded.depth) / 8)
283
+ const maxSample = 2 ** decoded.depth - 1
284
+ for (let y = 0; y < raster.height; y += 1) {
285
+ for (let x = 0; x < raster.width; x += 1) {
286
+ const i = y * raster.width + x
287
+ const packed = decoded.data[y * packedStride + Math.floor((x * decoded.depth) / 8)] ?? 0
288
+ const grey =
289
+ decoded.depth < 8
290
+ ? (packed >>> (8 - decoded.depth - ((x * decoded.depth) % 8))) & maxSample
291
+ : (decoded.data[i * decoded.channels] ?? 0)
292
+ const r = grey
293
+ const g = decoded.channels >= 3 ? (decoded.data[i * decoded.channels + 1] ?? 0) : grey
294
+ const b = decoded.channels >= 3 ? (decoded.data[i * decoded.channels + 2] ?? 0) : grey
295
+ rgba[i * 4] = Math.round((r * 255) / maxSample)
296
+ rgba[i * 4 + 1] = Math.round((g * 255) / maxSample)
297
+ rgba[i * 4 + 2] = Math.round((b * 255) / maxSample)
298
+ const transparent =
299
+ decoded.transparency &&
300
+ r === decoded.transparency[0] &&
301
+ (decoded.channels === 1 ||
302
+ (g === decoded.transparency[1] && b === decoded.transparency[2]))
303
+ rgba[i * 4 + 3] = transparent ? 0 : 255
304
+ }
305
+ }
306
+ return Buffer.from(
307
+ encode({ width: raster.width, height: raster.height, data: rgba, channels: 4, depth: 8 }),
308
+ )
309
+ }
310
+ } catch {
311
+ malformed()
312
+ }
313
+ return canonical
314
+ }
315
+
316
+ /**
317
+ * Inspect an artifact without granting screen-coordinate authority. An image
318
+ * file can be a reference, render or export; it is never a computer_use frame.
319
+ */
320
+ export function createViewImageTool(
321
+ options: ViewImageToolOptions = {},
322
+ ): ToolDefinition<z.infer<typeof inputSchema>> {
323
+ const unavailableReason = options.unavailableReason
324
+ return defineTool({
325
+ name: 'view_image',
326
+ description: `Visually inspect a saved PNG, JPEG or WebP reference, render or exported image. Reads this turn's files and returns actual image pixels to the model, with source dimensions. PNGs are decoded and fitted; JPEG/WebP containers are checked and must already fit standard vision size. File pixels are not a live desktop screenshot and cannot authorize mouse coordinates.${unavailableReason ? ` Unavailable: ${unavailableReason} Do not retry; tell the user.` : ''}`,
327
+ inputSchema,
328
+ category: 'filesystem',
329
+ pathArgument: 'path',
330
+ permissions: ['file_read'],
331
+ readOnly: true,
332
+ destructive: false,
333
+ concurrencySafe: true,
334
+ presentCall: (input) => ({
335
+ kind: 'generic',
336
+ label: `Inspect ${input.path}`,
337
+ presentation: 'activity',
338
+ activity: 'exploration',
339
+ }),
340
+ async execute(input, context) {
341
+ if (unavailableReason) {
342
+ const message = `view_image unavailable: ${unavailableReason} No image was read or shown. Do not retry; tell the user.`
343
+ return { success: false, output: message, error: message }
344
+ }
345
+ const artifact = await readArtifact(input.path, context)
346
+ const source = describeRaster(artifact.bytes)
347
+ if (
348
+ !admitMcpImageBatch([
349
+ {
350
+ type: 'image',
351
+ mimeType: source.mediaType,
352
+ data: artifact.bytes.toString('base64'),
353
+ },
354
+ ])
355
+ )
356
+ malformed()
357
+ context.abortSignal.throwIfAborted()
358
+ let image = {
359
+ data: artifact.bytes,
360
+ width: source.width,
361
+ height: source.height,
362
+ }
363
+ if (source.mediaType === 'image/png') {
364
+ const png = await validatedPng(artifact.bytes, source)
365
+ image = await fitPng(png, STANDARD_SCREENSHOT_LIMITS)
366
+ } else {
367
+ const target = screenshotTargetSize(source.width, source.height)
368
+ if (target.width !== source.width || target.height !== source.height)
369
+ throw new Error(
370
+ `This ${source.mediaType} image needs resizing. JPEG/WebP decoding and resizing are unavailable here; export a PNG (or a smaller JPEG/WebP) and inspect that file.`,
371
+ )
372
+ }
373
+ context.abortSignal.throwIfAborted()
374
+ const validation = source.mediaType === 'image/png' ? 'decoded' : 'container'
375
+ const output = `Image artifact: ${artifact.path} (${source.width}x${source.height}, ${source.mediaType}); shown at ${image.width}x${image.height}.`
376
+ return {
377
+ success: true,
378
+ output,
379
+ content: [
380
+ {
381
+ type: 'text',
382
+ text: `${output}\n${validation === 'container' ? 'The complete container and dimensions were validated; compressed JPEG/WebP pixels were not decoded by this tool. ' : ''}Inspect these pixels for visual evidence. This saved artifact is not a current computer_use screenshot; capture the application before GUI input.`,
383
+ },
384
+ {
385
+ type: 'image',
386
+ mediaType: source.mediaType,
387
+ data: image.data.toString('base64'),
388
+ },
389
+ ],
390
+ data: {
391
+ path: artifact.path,
392
+ sandboxed: artifact.sandboxed,
393
+ artifact: true,
394
+ mediaType: source.mediaType,
395
+ sourceWidth: source.width,
396
+ sourceHeight: source.height,
397
+ width: image.width,
398
+ height: image.height,
399
+ sourceBytes: artifact.bytes.length,
400
+ sha256: createHash('sha256').update(artifact.bytes).digest('hex'),
401
+ validation,
402
+ },
403
+ }
404
+ },
405
+ })
406
+ }
407
+
408
+ /** An optional artifact inspection tool; hosts must mount it explicitly. */
409
+ export const ViewImageTool = createViewImageTool()
@@ -52,6 +52,8 @@ export type JobWaitOutcome =
52
52
  readonly kind: 'exited'
53
53
  readonly status: string
54
54
  readonly exitCode?: number
55
+ /** Why the command never started, when it could not. */
56
+ readonly error?: string
55
57
  } & JobWaitProgress)
56
58
  | ({
57
59
  readonly kind: 'timeout'
@@ -142,6 +144,7 @@ export async function waitForJobWithBounds(
142
144
  kind: 'exited',
143
145
  status: job.status,
144
146
  ...(job.exitCode === undefined ? {} : { exitCode: job.exitCode }),
147
+ ...(job.error === undefined ? {} : { error: job.error }),
145
148
  output,
146
149
  nextOffset: cursor,
147
150
  droppedBytes,
@@ -33,40 +33,69 @@ const DEFAULT_IDLE_TIMEOUT_MS = readPositiveIntEnv('NAMZU_JOB_WAIT_IDLE_MS', 2 *
33
33
  */
34
34
  const MAX_WAIT_MS = readPositiveIntEnv('NAMZU_JOB_WAIT_MAX_MS', 60 * 60 * 1000)
35
35
 
36
- const inputSchema = z.object({
37
- id: z.string().describe('The job id, as returned by bash with run_in_background.'),
38
- from_offset: z
39
- .number()
40
- .int()
41
- .nonnegative()
42
- .optional()
43
- .describe('Resume after a previous wait: pass its next_offset to receive only new output.'),
44
- timeout_ms: z
45
- .number()
46
- .int()
47
- .positive()
48
- .max(MAX_WAIT_MS)
49
- .optional()
50
- .describe(
51
- `Give up after this long even if the job keeps producing output, in milliseconds. Default: ${DEFAULT_TIMEOUT_MS}, maximum: ${MAX_WAIT_MS}. The job is never stopped by this running out.`,
52
- ),
53
- idle_timeout_ms: z
54
- .number()
55
- .int()
56
- .positive()
57
- .max(MAX_WAIT_MS)
58
- .optional()
59
- .describe(
60
- `Give up if the job produces no new output for this long, in milliseconds. Default: ${DEFAULT_IDLE_TIMEOUT_MS}. Resets on every new byte of output, so a job that is still working is not cut off; only real silence ends the wait early.`,
61
- ),
62
- })
36
+ const inputSchema = z
37
+ .object({
38
+ id: z.string().describe('The job id, as returned by bash with run_in_background.'),
39
+ output_contains: z
40
+ .string()
41
+ .min(1)
42
+ .max(4096)
43
+ .refine(
44
+ (value) =>
45
+ Buffer.byteLength(value) <= 4096 && Buffer.from(value).toString('utf8') === value,
46
+ 'Use a non-empty UTF-8 literal of at most 4096 bytes.',
47
+ )
48
+ .optional()
49
+ .describe(
50
+ 'Wait for this exact literal in output rather than for exit. This observes a marker; it does not prove service health or keep the turn open until the job exits.',
51
+ ),
52
+ output_stream: z
53
+ .enum(['stdout', 'stderr', 'either'])
54
+ .optional()
55
+ .describe(
56
+ 'Pipe to inspect with output_contains. Default either; stdout and stderr are never joined for a match.',
57
+ ),
58
+ from_offset: z
59
+ .number()
60
+ .int()
61
+ .nonnegative()
62
+ .optional()
63
+ .describe('Resume after a previous wait: pass its next_offset to receive only new output.'),
64
+ timeout_ms: z
65
+ .number()
66
+ .int()
67
+ .positive()
68
+ .max(MAX_WAIT_MS)
69
+ .optional()
70
+ .describe(
71
+ `Give up after this long even if the job keeps producing output, in milliseconds. Default: ${DEFAULT_TIMEOUT_MS}, maximum: ${MAX_WAIT_MS}. The job is never stopped by this running out.`,
72
+ ),
73
+ idle_timeout_ms: z
74
+ .number()
75
+ .int()
76
+ .positive()
77
+ .max(MAX_WAIT_MS)
78
+ .optional()
79
+ .describe(
80
+ `Give up if the job produces no new output for this long, in milliseconds. Default: ${DEFAULT_IDLE_TIMEOUT_MS}. Resets on every new byte of output, so a job that is still working is not cut off; only real silence ends the wait early.`,
81
+ ),
82
+ })
83
+ .superRefine((input, ctx) => {
84
+ if (input.output_stream !== undefined && input.output_contains === undefined) {
85
+ ctx.addIssue({
86
+ code: 'custom',
87
+ path: ['output_stream'],
88
+ message: 'output_stream requires output_contains.',
89
+ })
90
+ }
91
+ })
63
92
 
64
93
  type WaitForJobInput = z.infer<typeof inputSchema>
65
94
 
66
95
  export const WaitForJobTool = defineTool({
67
96
  name: 'wait_for_job',
68
97
  description:
69
- 'Block until a background job started by bash with run_in_background ends, and return its bounded output in one call. Use this instead of calling job with action "read" in a loop: it costs one call and no waiting turns. A wait that runs too long or goes quiet returns its output and next_offset without stopping the job; pass that offset as from_offset on the next wait to avoid repeats.',
98
+ 'Wait for an owned background job to exit, or set output_contains to observe an exact output marker while it stays running. Use one wait instead of polling job read. Output markers do not prove service health or completion and never express intent to wait until exit. A bounded wait returns output and next_offset without stopping the job; pass that cursor as from_offset to exclude earlier output.',
70
99
  inputSchema,
71
100
  category: 'shell',
72
101
  permissions: ['shell_execute'],
@@ -88,7 +117,7 @@ export const WaitForJobTool = defineTool({
88
117
  return {
89
118
  kind: 'generic',
90
119
  presentation: 'activity',
91
- label: `Wait for background job · ${input.id ?? '(missing id)'}`,
120
+ label: `${input.output_contains === undefined ? 'Wait for background job' : 'Wait for job output'} · ${input.id ?? '(missing id)'}`,
92
121
  }
93
122
  },
94
123
 
@@ -112,6 +141,83 @@ export const WaitForJobTool = defineTool({
112
141
  }
113
142
  }
114
143
 
144
+ if (input.output_stream !== undefined && input.output_contains === undefined) {
145
+ return { success: false, output: '', error: 'output_stream requires output_contains.' }
146
+ }
147
+ if (input.output_contains !== undefined) {
148
+ if (!jobs.waitForOutput) {
149
+ return {
150
+ success: false,
151
+ output: '',
152
+ error:
153
+ 'This host cannot observe output readiness. It must implement backgroundJobs.waitForOutput; no exit wait was started.',
154
+ }
155
+ }
156
+ try {
157
+ const outcome = await jobs.waitForOutput(input.id, {
158
+ literal: input.output_contains,
159
+ stream: input.output_stream ?? 'either',
160
+ timeoutMs: input.timeout_ms ?? DEFAULT_TIMEOUT_MS,
161
+ idleTimeoutMs: input.idle_timeout_ms ?? DEFAULT_IDLE_TIMEOUT_MS,
162
+ ...(input.from_offset === undefined ? {} : { fromOffset: input.from_offset }),
163
+ signal: context.abortSignal,
164
+ })
165
+ const notices = [
166
+ ...(outcome.droppedBytes > 0
167
+ ? [`[${outcome.droppedBytes} bytes unavailable before the retained output]`]
168
+ : []),
169
+ ...(outcome.unsearchedBytes > 0
170
+ ? [
171
+ `[${outcome.unsearchedBytes} retained bytes could not be searched because the channel history cap discarded them]`,
172
+ ]
173
+ : []),
174
+ ...(outcome.omittedOutputBytes > 0
175
+ ? [`[${outcome.omittedOutputBytes} earlier bytes omitted from this bounded result]`]
176
+ : []),
177
+ ]
178
+ const status =
179
+ outcome.error !== undefined
180
+ ? `failed to start: ${outcome.error}`
181
+ : outcome.exitCode === undefined
182
+ ? outcome.status
183
+ : `${outcome.status} with code ${outcome.exitCode}`
184
+ const reason =
185
+ outcome.kind === 'matched'
186
+ ? `Output marker observed on ${outcome.matchedStream}. This is output evidence, not a health check or completion claim.`
187
+ : outcome.kind === 'exited'
188
+ ? 'Job exited before the marker was observed.'
189
+ : outcome.kind === 'stopped'
190
+ ? 'Job stop was requested before the marker was observed; shutdown may still be completing.'
191
+ : outcome.kind === 'aborted'
192
+ ? 'Output observation was cancelled; this wait did not stop the job.'
193
+ : `Output marker was not observed before the ${outcome.cause} timeout (${outcome.elapsedMs} ms); this wait did not stop the job.`
194
+ return {
195
+ success: outcome.kind !== 'aborted',
196
+ output: `${reason}\n\n${notices.length > 0 ? `${notices.join('\n')}\n` : ''}${outcome.output || '(no new output)'}\n\n[job ${input.id} is ${status}; next_offset ${outcome.nextOffset}]`,
197
+ data: {
198
+ jobId: input.id,
199
+ outcome: outcome.kind,
200
+ status: outcome.status,
201
+ nextOffset: outcome.nextOffset,
202
+ droppedBytes: outcome.droppedBytes,
203
+ unsearchedBytes: outcome.unsearchedBytes,
204
+ omittedOutputBytes: outcome.omittedOutputBytes,
205
+ ...(outcome.kind === 'matched' ? { matchedStream: outcome.matchedStream } : {}),
206
+ ...(outcome.kind === 'timeout' ? { timedOut: outcome.cause } : {}),
207
+ ...(outcome.kind === 'aborted' ? { abandoned: true } : {}),
208
+ ...(outcome.exitCode === undefined ? {} : { exitCode: outcome.exitCode }),
209
+ ...(outcome.error === undefined ? {} : { error: outcome.error }),
210
+ },
211
+ }
212
+ } catch (err) {
213
+ return {
214
+ success: false,
215
+ output: '',
216
+ error: err instanceof Error ? err.message : String(err),
217
+ }
218
+ }
219
+ }
220
+
115
221
  if (!jobs.waitForExit) {
116
222
  return {
117
223
  success: false,
@@ -178,9 +284,11 @@ export const WaitForJobTool = defineTool({
178
284
  }
179
285
 
180
286
  const status =
181
- outcome.exitCode === undefined
182
- ? outcome.status
183
- : `${outcome.status} with code ${outcome.exitCode}`
287
+ outcome.error !== undefined
288
+ ? `failed to start: ${outcome.error}`
289
+ : outcome.exitCode === undefined
290
+ ? outcome.status
291
+ : `${outcome.status} with code ${outcome.exitCode}`
184
292
 
185
293
  return {
186
294
  success: true,
@@ -192,6 +300,7 @@ export const WaitForJobTool = defineTool({
192
300
  droppedBytes: outcome.droppedBytes,
193
301
  omittedOutputBytes: outcome.omittedOutputBytes,
194
302
  ...(outcome.exitCode === undefined ? {} : { exitCode: outcome.exitCode }),
303
+ ...(outcome.error === undefined ? {} : { error: outcome.error }),
195
304
  },
196
305
  }
197
306
  },
@@ -2,6 +2,7 @@ import { mkdir, readFile } from 'node:fs/promises'
2
2
  import { dirname } from 'node:path'
3
3
  import { z } from 'zod'
4
4
  import type { ToolContext, ToolResult } from '../../types/tool/index.js'
5
+ import type { ToolFacts } from '../../types/tool/presentation.js'
5
6
  import { defineTool } from '../defineTool.js'
6
7
  import { resolveWithinAnyReal, toolRoots } from '../paths.js'
7
8
  import { atomicWriteFile } from './atomic-write-file.js'
@@ -196,13 +197,14 @@ export const WriteFileTool = defineTool({
196
197
  function enforceReadBeforeOverwrite(
197
198
  context: ToolContext,
198
199
  key: string,
199
- ): { success: false; output: ''; error: string } | null {
200
+ ): { success: false; output: ''; error: string; facts?: ToolFacts } | null {
200
201
  if (!context.fileReadTracker) return null
201
202
  if (context.fileReadTracker.hasRead(key)) return null
202
203
  return {
203
204
  success: false,
204
205
  output: '',
205
206
  error: `${key} already exists. Use the \`read\` tool on it first in this conversation, then call \`write\` again — or prefer \`edit\` for a targeted change.`,
207
+ facts: { kind: 'failure', reason: 'already_exists', subject: key },
206
208
  }
207
209
  }
208
210
 
@@ -210,7 +212,7 @@ function enforceFreshOverwrite(
210
212
  context: ToolContext,
211
213
  key: string,
212
214
  currentContent: string,
213
- ): { success: false; output: ''; error: string } | null {
215
+ ): { success: false; output: ''; error: string; facts?: ToolFacts } | null {
214
216
  const unread = enforceReadBeforeOverwrite(context, key)
215
217
  if (unread) return unread
216
218