@assemblyline-agents/runtime 2.0.0 → 3.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 (389) hide show
  1. package/LICENSE +1 -1
  2. package/dist/a2a-client.d.ts +22 -0
  3. package/dist/a2a-client.d.ts.map +1 -0
  4. package/dist/a2a-client.js +211 -0
  5. package/dist/a2a-client.js.map +1 -0
  6. package/dist/agent-hook-context.d.ts +6 -1
  7. package/dist/agent-hook-context.d.ts.map +1 -1
  8. package/dist/agent-hook-context.js +24 -11
  9. package/dist/agent-hook-context.js.map +1 -1
  10. package/dist/agent-hook-evaluation.d.ts +6 -1
  11. package/dist/agent-hook-evaluation.d.ts.map +1 -1
  12. package/dist/agent-hook-evaluation.js +16 -5
  13. package/dist/agent-hook-evaluation.js.map +1 -1
  14. package/dist/agent-hook-run-lifecycle.d.ts +5 -1
  15. package/dist/agent-hook-run-lifecycle.d.ts.map +1 -1
  16. package/dist/agent-hook-run-lifecycle.js +11 -13
  17. package/dist/agent-hook-run-lifecycle.js.map +1 -1
  18. package/dist/agent-surface.d.ts +32 -0
  19. package/dist/agent-surface.d.ts.map +1 -0
  20. package/dist/agent-surface.js +85 -0
  21. package/dist/agent-surface.js.map +1 -0
  22. package/dist/attachments.d.ts +5 -1
  23. package/dist/attachments.d.ts.map +1 -1
  24. package/dist/attachments.js +58 -32
  25. package/dist/attachments.js.map +1 -1
  26. package/dist/audience.d.ts +30 -0
  27. package/dist/audience.d.ts.map +1 -0
  28. package/dist/audience.js +68 -0
  29. package/dist/audience.js.map +1 -0
  30. package/dist/automation-event-match.d.ts +8 -0
  31. package/dist/automation-event-match.d.ts.map +1 -0
  32. package/dist/automation-event-match.js +25 -0
  33. package/dist/automation-event-match.js.map +1 -0
  34. package/dist/background-review-trigger.d.ts.map +1 -1
  35. package/dist/background-review-trigger.js +14 -16
  36. package/dist/background-review-trigger.js.map +1 -1
  37. package/dist/background-review-types.d.ts +9 -2
  38. package/dist/background-review-types.d.ts.map +1 -1
  39. package/dist/background-review-worker.js +2 -2
  40. package/dist/background-review-worker.js.map +1 -1
  41. package/dist/background-review.d.ts.map +1 -1
  42. package/dist/background-review.js +27 -10
  43. package/dist/background-review.js.map +1 -1
  44. package/dist/builtin-tool-executors.d.ts +47 -21
  45. package/dist/builtin-tool-executors.d.ts.map +1 -1
  46. package/dist/builtin-tool-executors.js +293 -121
  47. package/dist/builtin-tool-executors.js.map +1 -1
  48. package/dist/builtin-tools.d.ts +16 -8
  49. package/dist/builtin-tools.d.ts.map +1 -1
  50. package/dist/builtin-tools.js +309 -70
  51. package/dist/builtin-tools.js.map +1 -1
  52. package/dist/capability-catalog.d.ts +3 -2
  53. package/dist/capability-catalog.d.ts.map +1 -1
  54. package/dist/capability-catalog.js +10 -6
  55. package/dist/capability-catalog.js.map +1 -1
  56. package/dist/capability-inspection.d.ts +31 -0
  57. package/dist/capability-inspection.d.ts.map +1 -0
  58. package/dist/capability-inspection.js +58 -0
  59. package/dist/capability-inspection.js.map +1 -0
  60. package/dist/channel-http-util.d.ts.map +1 -1
  61. package/dist/channel-http-util.js +6 -2
  62. package/dist/channel-http-util.js.map +1 -1
  63. package/dist/channel-ingress.d.ts +16 -1
  64. package/dist/channel-ingress.d.ts.map +1 -1
  65. package/dist/channel-ingress.js +117 -7
  66. package/dist/channel-ingress.js.map +1 -1
  67. package/dist/channel.d.ts +58 -2
  68. package/dist/channel.d.ts.map +1 -1
  69. package/dist/checkpoints.d.ts +1 -1
  70. package/dist/checkpoints.d.ts.map +1 -1
  71. package/dist/checkpoints.js +6 -6
  72. package/dist/checkpoints.js.map +1 -1
  73. package/dist/child-process-env.d.ts +7 -0
  74. package/dist/child-process-env.d.ts.map +1 -0
  75. package/dist/child-process-env.js +41 -0
  76. package/dist/child-process-env.js.map +1 -0
  77. package/dist/computer-relay-protocol.d.ts.map +1 -1
  78. package/dist/computer-relay-protocol.js +4 -4
  79. package/dist/computer-relay-protocol.js.map +1 -1
  80. package/dist/concurrency.d.ts +1 -1
  81. package/dist/concurrency.js +1 -1
  82. package/dist/connection-auth-util.d.ts +1 -0
  83. package/dist/connection-auth-util.d.ts.map +1 -1
  84. package/dist/connection-auth-util.js +1 -1
  85. package/dist/connection-auth-util.js.map +1 -1
  86. package/dist/connection-clients.d.ts +11 -3
  87. package/dist/connection-clients.d.ts.map +1 -1
  88. package/dist/connection-clients.js +71 -8
  89. package/dist/connection-clients.js.map +1 -1
  90. package/dist/connection-event-store.d.ts +98 -0
  91. package/dist/connection-event-store.d.ts.map +1 -0
  92. package/dist/connection-event-store.js +162 -0
  93. package/dist/connection-event-store.js.map +1 -0
  94. package/dist/connection-events.d.ts +51 -0
  95. package/dist/connection-events.d.ts.map +1 -0
  96. package/dist/connection-events.js +343 -0
  97. package/dist/connection-events.js.map +1 -0
  98. package/dist/connection-stores.d.ts +3 -0
  99. package/dist/connection-stores.d.ts.map +1 -1
  100. package/dist/connection-stores.js +4 -1
  101. package/dist/connection-stores.js.map +1 -1
  102. package/dist/connection-util.d.ts +3 -2
  103. package/dist/connection-util.d.ts.map +1 -1
  104. package/dist/connection-util.js +18 -1
  105. package/dist/connection-util.js.map +1 -1
  106. package/dist/connections.d.ts +54 -5
  107. package/dist/connections.d.ts.map +1 -1
  108. package/dist/connections.js +342 -53
  109. package/dist/connections.js.map +1 -1
  110. package/dist/context-policy-util.d.ts.map +1 -1
  111. package/dist/context-policy-util.js +1 -3
  112. package/dist/context-policy-util.js.map +1 -1
  113. package/dist/conversation-context.d.ts +6 -2
  114. package/dist/conversation-context.d.ts.map +1 -1
  115. package/dist/conversation-context.js +45 -12
  116. package/dist/conversation-context.js.map +1 -1
  117. package/dist/conversation-transcript.d.ts +8 -5
  118. package/dist/conversation-transcript.d.ts.map +1 -1
  119. package/dist/conversation-transcript.js +24 -5
  120. package/dist/conversation-transcript.js.map +1 -1
  121. package/dist/conversation-turn-coalescing.d.ts +22 -0
  122. package/dist/conversation-turn-coalescing.d.ts.map +1 -0
  123. package/dist/conversation-turn-coalescing.js +121 -0
  124. package/dist/conversation-turn-coalescing.js.map +1 -0
  125. package/dist/conversation-turn-dispatch.d.ts +5 -2
  126. package/dist/conversation-turn-dispatch.d.ts.map +1 -1
  127. package/dist/conversation-turn-dispatch.js +59 -22
  128. package/dist/conversation-turn-dispatch.js.map +1 -1
  129. package/dist/default-outbound-route.d.ts +29 -0
  130. package/dist/default-outbound-route.d.ts.map +1 -0
  131. package/dist/default-outbound-route.js +105 -0
  132. package/dist/default-outbound-route.js.map +1 -0
  133. package/dist/delivery-artifacts.d.ts +2 -0
  134. package/dist/delivery-artifacts.d.ts.map +1 -0
  135. package/dist/delivery-artifacts.js +34 -0
  136. package/dist/delivery-artifacts.js.map +1 -0
  137. package/dist/delivery-files.d.ts +5 -0
  138. package/dist/delivery-files.d.ts.map +1 -0
  139. package/dist/delivery-files.js +33 -0
  140. package/dist/delivery-files.js.map +1 -0
  141. package/dist/delivery-queue.d.ts +21 -1
  142. package/dist/delivery-queue.d.ts.map +1 -1
  143. package/dist/delivery-queue.js +144 -1
  144. package/dist/delivery-queue.js.map +1 -1
  145. package/dist/delivery-send.d.ts +2 -2
  146. package/dist/delivery-send.d.ts.map +1 -1
  147. package/dist/delivery-send.js +256 -100
  148. package/dist/delivery-send.js.map +1 -1
  149. package/dist/durable-files.d.ts +37 -0
  150. package/dist/durable-files.d.ts.map +1 -0
  151. package/dist/durable-files.js +63 -0
  152. package/dist/durable-files.js.map +1 -0
  153. package/dist/harness-loop.d.ts +6 -1
  154. package/dist/harness-loop.d.ts.map +1 -1
  155. package/dist/harness-loop.js +110 -25
  156. package/dist/harness-loop.js.map +1 -1
  157. package/dist/heic-transcode-worker.d.ts +2 -0
  158. package/dist/heic-transcode-worker.d.ts.map +1 -0
  159. package/dist/heic-transcode-worker.js +59 -0
  160. package/dist/heic-transcode-worker.js.map +1 -0
  161. package/dist/heic-transcode.d.ts +18 -0
  162. package/dist/heic-transcode.d.ts.map +1 -0
  163. package/dist/heic-transcode.js +99 -0
  164. package/dist/heic-transcode.js.map +1 -0
  165. package/dist/human-input-routing.d.ts +22 -0
  166. package/dist/human-input-routing.d.ts.map +1 -0
  167. package/dist/human-input-routing.js +26 -0
  168. package/dist/human-input-routing.js.map +1 -0
  169. package/dist/in-memory-conversation-turn-store.d.ts +3 -1
  170. package/dist/in-memory-conversation-turn-store.d.ts.map +1 -1
  171. package/dist/in-memory-conversation-turn-store.js +41 -2
  172. package/dist/in-memory-conversation-turn-store.js.map +1 -1
  173. package/dist/in-memory-run-store.d.ts +8 -0
  174. package/dist/in-memory-run-store.d.ts.map +1 -1
  175. package/dist/in-memory-run-store.js +28 -5
  176. package/dist/in-memory-run-store.js.map +1 -1
  177. package/dist/in-memory-sandbox-session-store.d.ts +2 -1
  178. package/dist/in-memory-sandbox-session-store.d.ts.map +1 -1
  179. package/dist/in-memory-sandbox-session-store.js +65 -1
  180. package/dist/in-memory-sandbox-session-store.js.map +1 -1
  181. package/dist/in-memory-small-stores.d.ts +18 -1
  182. package/dist/in-memory-small-stores.d.ts.map +1 -1
  183. package/dist/in-memory-small-stores.js +107 -1
  184. package/dist/in-memory-small-stores.js.map +1 -1
  185. package/dist/in-memory-workspace-store.d.ts +40 -0
  186. package/dist/in-memory-workspace-store.d.ts.map +1 -0
  187. package/dist/in-memory-workspace-store.js +370 -0
  188. package/dist/in-memory-workspace-store.js.map +1 -0
  189. package/dist/index.d.ts +73 -36
  190. package/dist/index.d.ts.map +1 -1
  191. package/dist/index.js +390 -258
  192. package/dist/index.js.map +1 -1
  193. package/dist/json-util.d.ts +8 -0
  194. package/dist/json-util.d.ts.map +1 -1
  195. package/dist/json-util.js +8 -0
  196. package/dist/json-util.js.map +1 -1
  197. package/dist/local-sandbox.d.ts +3 -2
  198. package/dist/local-sandbox.d.ts.map +1 -1
  199. package/dist/local-sandbox.js +69 -25
  200. package/dist/local-sandbox.js.map +1 -1
  201. package/dist/mcp-client.d.ts.map +1 -1
  202. package/dist/mcp-client.js +3 -2
  203. package/dist/mcp-client.js.map +1 -1
  204. package/dist/media-processor.d.ts +42 -0
  205. package/dist/media-processor.d.ts.map +1 -0
  206. package/dist/media-processor.js +2 -0
  207. package/dist/media-processor.js.map +1 -0
  208. package/dist/model-media.d.ts +13 -1
  209. package/dist/model-media.d.ts.map +1 -1
  210. package/dist/model-media.js +81 -18
  211. package/dist/model-media.js.map +1 -1
  212. package/dist/model-visible-interrupts.d.ts +10 -0
  213. package/dist/model-visible-interrupts.d.ts.map +1 -0
  214. package/dist/model-visible-interrupts.js +41 -0
  215. package/dist/model-visible-interrupts.js.map +1 -0
  216. package/dist/operator-controls.d.ts.map +1 -1
  217. package/dist/operator-controls.js +16 -3
  218. package/dist/operator-controls.js.map +1 -1
  219. package/dist/outbound-http-policy.d.ts +7 -0
  220. package/dist/outbound-http-policy.d.ts.map +1 -0
  221. package/dist/outbound-http-policy.js +155 -0
  222. package/dist/outbound-http-policy.js.map +1 -0
  223. package/dist/public-api.d.ts +21 -0
  224. package/dist/public-api.d.ts.map +1 -0
  225. package/dist/public-api.js +19 -0
  226. package/dist/public-api.js.map +1 -0
  227. package/dist/replay-resume.d.ts +8 -0
  228. package/dist/replay-resume.d.ts.map +1 -1
  229. package/dist/replay-resume.js +141 -11
  230. package/dist/replay-resume.js.map +1 -1
  231. package/dist/resource-projection-util.d.ts +1 -1
  232. package/dist/resource-projection-util.d.ts.map +1 -1
  233. package/dist/resource-projection-util.js +21 -10
  234. package/dist/resource-projection-util.js.map +1 -1
  235. package/dist/resource-projection.d.ts +8 -1
  236. package/dist/resource-projection.d.ts.map +1 -1
  237. package/dist/resource-projection.js +229 -29
  238. package/dist/resource-projection.js.map +1 -1
  239. package/dist/run-heartbeat.d.ts +12 -2
  240. package/dist/run-heartbeat.d.ts.map +1 -1
  241. package/dist/run-heartbeat.js +31 -4
  242. package/dist/run-heartbeat.js.map +1 -1
  243. package/dist/run-outcome.d.ts +9 -5
  244. package/dist/run-outcome.d.ts.map +1 -1
  245. package/dist/run-outcome.js +14 -5
  246. package/dist/run-outcome.js.map +1 -1
  247. package/dist/run-recovery.d.ts +19 -3
  248. package/dist/run-recovery.d.ts.map +1 -1
  249. package/dist/run-recovery.js +205 -34
  250. package/dist/run-recovery.js.map +1 -1
  251. package/dist/run-replay.d.ts +35 -0
  252. package/dist/run-replay.d.ts.map +1 -0
  253. package/dist/run-replay.js +193 -0
  254. package/dist/run-replay.js.map +1 -0
  255. package/dist/run-result.d.ts +4 -0
  256. package/dist/run-result.d.ts.map +1 -0
  257. package/dist/run-result.js +18 -0
  258. package/dist/run-result.js.map +1 -0
  259. package/dist/run-timeline-query.d.ts +38 -0
  260. package/dist/run-timeline-query.d.ts.map +1 -0
  261. package/dist/run-timeline-query.js +99 -0
  262. package/dist/run-timeline-query.js.map +1 -0
  263. package/dist/runs-query.d.ts.map +1 -1
  264. package/dist/runs-query.js +11 -3
  265. package/dist/runs-query.js.map +1 -1
  266. package/dist/runtime-bundle.d.ts.map +1 -1
  267. package/dist/runtime-bundle.js +2 -0
  268. package/dist/runtime-bundle.js.map +1 -1
  269. package/dist/runtime-learning.d.ts +15 -13
  270. package/dist/runtime-learning.d.ts.map +1 -1
  271. package/dist/runtime-learning.js +79 -58
  272. package/dist/runtime-learning.js.map +1 -1
  273. package/dist/runtime-types.d.ts +68 -9
  274. package/dist/runtime-types.d.ts.map +1 -1
  275. package/dist/sandbox-fs.d.ts +8 -5
  276. package/dist/sandbox-fs.d.ts.map +1 -1
  277. package/dist/sandbox-fs.js +30 -31
  278. package/dist/sandbox-fs.js.map +1 -1
  279. package/dist/sandbox-handle.d.ts +25 -0
  280. package/dist/sandbox-handle.d.ts.map +1 -0
  281. package/dist/sandbox-handle.js +120 -0
  282. package/dist/sandbox-handle.js.map +1 -0
  283. package/dist/sandbox-session-identity.d.ts +14 -0
  284. package/dist/sandbox-session-identity.d.ts.map +1 -0
  285. package/dist/sandbox-session-identity.js +33 -0
  286. package/dist/sandbox-session-identity.js.map +1 -0
  287. package/dist/sandbox-session-key.d.ts.map +1 -1
  288. package/dist/sandbox-session-key.js +12 -9
  289. package/dist/sandbox-session-key.js.map +1 -1
  290. package/dist/sandbox-session-lifecycle.d.ts.map +1 -1
  291. package/dist/sandbox-session-lifecycle.js +187 -44
  292. package/dist/sandbox-session-lifecycle.js.map +1 -1
  293. package/dist/sandbox-snapshot-policy.js +3 -3
  294. package/dist/sandbox-snapshot-policy.js.map +1 -1
  295. package/dist/sandbox-state-sync.d.ts +4 -2
  296. package/dist/sandbox-state-sync.d.ts.map +1 -1
  297. package/dist/sandbox-state-sync.js +47 -15
  298. package/dist/sandbox-state-sync.js.map +1 -1
  299. package/dist/sandbox-sync-worker.d.ts +11 -2
  300. package/dist/sandbox-sync-worker.d.ts.map +1 -1
  301. package/dist/sandbox-sync-worker.js +143 -31
  302. package/dist/sandbox-sync-worker.js.map +1 -1
  303. package/dist/schedule-execution.d.ts.map +1 -1
  304. package/dist/schedule-execution.js +127 -23
  305. package/dist/schedule-execution.js.map +1 -1
  306. package/dist/sdk-api-client.d.ts +17 -0
  307. package/dist/sdk-api-client.d.ts.map +1 -0
  308. package/dist/sdk-api-client.js +55 -0
  309. package/dist/sdk-api-client.js.map +1 -0
  310. package/dist/security.js +2 -2
  311. package/dist/security.js.map +1 -1
  312. package/dist/self-improvement.d.ts +5 -1
  313. package/dist/self-improvement.d.ts.map +1 -1
  314. package/dist/self-improvement.js +28 -14
  315. package/dist/self-improvement.js.map +1 -1
  316. package/dist/skill-bundles.d.ts +55 -0
  317. package/dist/skill-bundles.d.ts.map +1 -0
  318. package/dist/skill-bundles.js +134 -0
  319. package/dist/skill-bundles.js.map +1 -0
  320. package/dist/source-loader.js +7 -7
  321. package/dist/source-loader.js.map +1 -1
  322. package/dist/state-store-helpers.d.ts +2 -0
  323. package/dist/state-store-helpers.d.ts.map +1 -1
  324. package/dist/state-store-helpers.js +11 -1
  325. package/dist/state-store-helpers.js.map +1 -1
  326. package/dist/state-stores.d.ts +1 -0
  327. package/dist/state-stores.d.ts.map +1 -1
  328. package/dist/state-stores.js +26 -7
  329. package/dist/state-stores.js.map +1 -1
  330. package/dist/state.d.ts +305 -5
  331. package/dist/state.d.ts.map +1 -1
  332. package/dist/state.js +41 -2
  333. package/dist/state.js.map +1 -1
  334. package/dist/storage.d.ts +47 -2
  335. package/dist/storage.d.ts.map +1 -1
  336. package/dist/storage.js +158 -6
  337. package/dist/storage.js.map +1 -1
  338. package/dist/subagent-execution.d.ts +1 -1
  339. package/dist/subagent-execution.d.ts.map +1 -1
  340. package/dist/subagent-execution.js +10 -12
  341. package/dist/subagent-execution.js.map +1 -1
  342. package/dist/target-instructions.js +1 -1
  343. package/dist/target-instructions.js.map +1 -1
  344. package/dist/tool-apis.d.ts.map +1 -1
  345. package/dist/tool-apis.js +33 -9
  346. package/dist/tool-apis.js.map +1 -1
  347. package/dist/tool-execution.d.ts +22 -12
  348. package/dist/tool-execution.d.ts.map +1 -1
  349. package/dist/tool-execution.js +368 -238
  350. package/dist/tool-execution.js.map +1 -1
  351. package/dist/turn-media.d.ts +29 -0
  352. package/dist/turn-media.d.ts.map +1 -0
  353. package/dist/turn-media.js +233 -0
  354. package/dist/turn-media.js.map +1 -0
  355. package/dist/usage-reconciliation.d.ts +1 -1
  356. package/dist/usage-reconciliation.js +1 -1
  357. package/dist/workspace-id.d.ts +10 -0
  358. package/dist/workspace-id.d.ts.map +1 -0
  359. package/dist/workspace-id.js +55 -0
  360. package/dist/workspace-id.js.map +1 -0
  361. package/dist/workspace-manifest.d.ts +24 -0
  362. package/dist/workspace-manifest.d.ts.map +1 -0
  363. package/dist/workspace-manifest.js +111 -0
  364. package/dist/workspace-manifest.js.map +1 -0
  365. package/dist/workspace-operation-limiter.d.ts +16 -0
  366. package/dist/workspace-operation-limiter.d.ts.map +1 -0
  367. package/dist/workspace-operation-limiter.js +31 -0
  368. package/dist/workspace-operation-limiter.js.map +1 -0
  369. package/dist/workspace-operations.d.ts +145 -0
  370. package/dist/workspace-operations.d.ts.map +1 -0
  371. package/dist/workspace-operations.js +420 -0
  372. package/dist/workspace-operations.js.map +1 -0
  373. package/dist/workspace-runtime.d.ts +110 -0
  374. package/dist/workspace-runtime.d.ts.map +1 -0
  375. package/dist/workspace-runtime.js +240 -0
  376. package/dist/workspace-runtime.js.map +1 -0
  377. package/dist/workspace-search.d.ts +55 -0
  378. package/dist/workspace-search.d.ts.map +1 -0
  379. package/dist/workspace-search.js +262 -0
  380. package/dist/workspace-search.js.map +1 -0
  381. package/dist/workspace-service.d.ts +173 -0
  382. package/dist/workspace-service.d.ts.map +1 -0
  383. package/dist/workspace-service.js +619 -0
  384. package/dist/workspace-service.js.map +1 -0
  385. package/dist/workspace.d.ts +7 -0
  386. package/dist/workspace.d.ts.map +1 -0
  387. package/dist/workspace.js +7 -0
  388. package/dist/workspace.js.map +1 -0
  389. package/package.json +7 -4
@@ -1,13 +1,13 @@
1
- import { boundModelOutput, normalizeApprovalPolicy, sandboxFilesystemContractMetadata } from "@assemblyline-agents/core";
2
- import { ASK_QUESTION_TOOL_NAME, CORE_HARNESS_TOOL_NAMES, isBuiltInToolName, LOAD_SKILL_TOOL_NAME, runtimeToolsForManifest, TOOL_CALL_TOOL_NAME, TOOL_DESCRIBE_TOOL_NAME, TOOL_SEARCH_TOOL_NAME } from "./builtin-tools.js";
3
- import { createConnectionRegistryForRunImpl, deferredLocalTools, executeConnectionSearchTool, executeConnectionTool, executeLoadSkillTool, executeToolDescribeTool, executeToolSearchTool, failRuntimeHandledTool } from "./builtin-tool-executors.js";
4
- import { CONNECTION_SEARCH_TOOL_NAME, parseQualifiedName } from "./connections.js";
1
+ import { boundModelOutput, DELEGATE_TOOL_NAME, normalizeApprovalPolicy, sandboxFilesystemContractMetadata } from "@assemblyline-agents/core";
2
+ import { HISTORY_SEARCH_TOOL_NAME, FILES_MOUNT_TOOL_NAME, FILES_SEARCH_TOOL_NAME, LOAD_SKILL_TOOL_NAME, PAIR_TOOL_NAME, runtimeToolsForSurface, TOOL_SEARCH_TOOL_NAME, WORKSPACE_CHECKPOINT_CREATE_TOOL_NAME, WORKSPACE_CHECKPOINT_LIST_TOOL_NAME, WORKSPACE_CHECKPOINT_RESTORE_TOOL_NAME, WORKSPACE_FORK_TOOL_NAME, WORKSPACE_SEARCH_TOOL_NAME, WORKSPACE_STATUS_TOOL_NAME } from "./builtin-tools.js";
3
+ import { createConnectionRegistryForRunImpl, executeConnectionSearchTool, executeConnectionTool, executeHistorySearchTool, executeLoadSkillTool, executePairTool, executeToolSearchTool, failRuntimeHandledTool, recordRuntimeHandledToolStart } from "./builtin-tool-executors.js";
4
+ import { CONNECTION_SEARCH_TOOL_NAME, isConnectionConfigurationError, parseQualifiedName } from "./connections.js";
5
5
  import { resolvePositiveIntegerEnv } from "./env-config.js";
6
6
  import { harnessPauseOutcome } from "./harness-continuation.js";
7
7
  import { evalRunOptionsForRun } from "./eval-run-options.js";
8
8
  import { isJsonObject, previewString, redactedToolInput, safeJson } from "./json-util.js";
9
+ import { runUsesChannelReplyForHumanInput } from "./human-input-routing.js";
9
10
  import { prepareToolModelOutput } from "./model-media.js";
10
- import { failRun } from "./run-outcome.js";
11
11
  import { sandboxWriteByteLength } from "./resource-projection-util.js";
12
12
  import { stringValue, timestamp, toolRequiresSandbox } from "./runtime-util.js";
13
13
  import { applyCoreToolPolicy, filterVisibleToolSet } from "./security.js";
@@ -16,10 +16,13 @@ export function visibleToolSetImpl(host, defaultToolNames, activeSkills) {
16
16
  void activeSkills;
17
17
  return filterVisibleToolSet(defaultToolNames, host.coreToolPolicy);
18
18
  }
19
- export async function modelToolsImpl(host, activeToolNames, connectionRegistry, discoveredConnectionTools = new Map()) {
19
+ export async function modelToolsImpl(host, run, activeToolNames, connectionRegistry, discoveredConnectionTools = new Map(), options = {}) {
20
20
  const tools = [];
21
- for (const tool of runtimeToolsForManifest(host.manifest)) {
22
- if (!activeToolNames.has(tool.name))
21
+ const surface = host.surfaceForRun(run);
22
+ for (const tool of runtimeToolsForSurface(surface.tools)) {
23
+ const active = activeToolNames.has(tool.name);
24
+ const deferred = options.includeDeferred === true && tool.visibility === "deferred";
25
+ if (!active && !deferred)
23
26
  continue;
24
27
  const policyTool = applyCoreToolPolicy(tool, host.coreToolPolicy);
25
28
  if (!policyTool)
@@ -30,17 +33,21 @@ export async function modelToolsImpl(host, activeToolNames, connectionRegistry,
30
33
  description: definition.description ?? policyTool.description,
31
34
  inputSchema: definition.inputSchema ?? policyTool.inputSchema
32
35
  };
33
- // Statically pause-capable tools must serialize their batch: approval
34
- // gates park the run before executing, ask_question always pauses, and
35
- // the deferred-tool bridge can hit any of those through the tool it
36
- // routes to.
37
- if (policyTool.name === ASK_QUESTION_TOOL_NAME ||
38
- policyTool.name === TOOL_CALL_TOOL_NAME ||
39
- normalizeApprovalPolicy(policyTool.needsApproval).mode === "always") {
36
+ // Approval-gated tools park the run and therefore serialize their batch.
37
+ if (normalizeApprovalPolicy(policyTool.needsApproval).mode === "always") {
40
38
  descriptor.execution = "sequential";
41
39
  }
40
+ if (!active) {
41
+ descriptor.deferLoading = true;
42
+ options.exposedDeferredToolNames?.add(policyTool.name);
43
+ }
42
44
  tools.push(descriptor);
43
45
  }
46
+ // connection_search is not part of the built-in tool catalog, so it cannot
47
+ // be selected by authored setup() (capability validation rejects unknown
48
+ // names) and this branch stays dormant today. tool_search is the model's
49
+ // discovery surface for connection tools, and the core `pair` tool is the
50
+ // discovery-independent binding path.
44
51
  if (connectionRegistry?.hasLiveConnections() && activeToolNames.has(CONNECTION_SEARCH_TOOL_NAME)) {
45
52
  tools.push({
46
53
  name: CONNECTION_SEARCH_TOOL_NAME,
@@ -66,30 +73,74 @@ export async function modelToolsImpl(host, activeToolNames, connectionRegistry,
66
73
  }
67
74
  });
68
75
  }
76
+ if (options.includeDeferred && connectionRegistry?.hasLiveConnections()) {
77
+ const catalog = await connectionRegistry.search({ keywords: "", limit: Number.MAX_SAFE_INTEGER });
78
+ for (const result of catalog) {
79
+ if (!result.qualifiedName || !result.tool || !result.inputSchema)
80
+ continue;
81
+ const metadata = {
82
+ connection: result.connection,
83
+ name: result.tool,
84
+ qualifiedName: result.qualifiedName,
85
+ description: result.description,
86
+ inputSchema: result.inputSchema
87
+ };
88
+ if (result.outputSchema)
89
+ metadata.outputSchema = result.outputSchema;
90
+ discoveredConnectionTools.set(result.qualifiedName, metadata);
91
+ }
92
+ }
69
93
  for (const [qualifiedName, metadata] of discoveredConnectionTools) {
70
- if (!activeToolNames.has(qualifiedName))
94
+ const active = activeToolNames.has(qualifiedName);
95
+ if (!active && !options.includeDeferred)
71
96
  continue;
72
- tools.push({
97
+ const descriptor = {
73
98
  name: qualifiedName,
74
99
  description: metadata.description,
75
100
  inputSchema: metadata.inputSchema,
101
+ external: {
102
+ namespace: metadata.connection,
103
+ name: metadata.name
104
+ },
76
105
  // Connection tools can pause for authorization at any call.
77
106
  execution: "sequential"
78
- });
107
+ };
108
+ if (!active) {
109
+ descriptor.deferLoading = true;
110
+ options.exposedDeferredToolNames?.add(qualifiedName);
111
+ }
112
+ tools.push(descriptor);
79
113
  }
80
- for (const subagent of host.manifest.subagents) {
81
- if (!activeToolNames.has(`delegate_${subagent.name}`))
82
- continue;
114
+ const selectedSubagentNames = new Set(Array.isArray(run.input.agentSubagents)
115
+ ? run.input.agentSubagents.filter((name) => typeof name === "string")
116
+ : []);
117
+ const selectedSubagents = surface.subagents
118
+ .filter((subagent) => selectedSubagentNames.has(subagent.name))
119
+ .sort((left, right) => left.name.localeCompare(right.name));
120
+ if (activeToolNames.has(DELEGATE_TOOL_NAME) && selectedSubagents.length > 0) {
121
+ const directory = selectedSubagents
122
+ .map((subagent) => `${subagent.name}: ${subagent.description}`)
123
+ .join("\n");
83
124
  tools.push({
84
- name: `delegate_${subagent.name}`,
85
- description: subagent.description,
125
+ name: DELEGATE_TOOL_NAME,
126
+ description: `Delegate one self-contained task to an enabled immediate child. The child has no parent transcript, so include needed context and usable file paths; review its result before replying. Available agents:\n${directory}`,
86
127
  inputSchema: {
87
128
  type: "object",
88
129
  properties: {
89
- task: { type: "string" },
90
- expectedOutput: { type: "string" },
91
- constraints: { type: "array", items: { type: "string" } }
130
+ agent: {
131
+ type: "string",
132
+ enum: selectedSubagents.map((subagent) => subagent.name),
133
+ description: "Exact child-agent name from the available-agent directory."
134
+ },
135
+ task: { type: "string", description: "Self-contained objective and required context." },
136
+ expectedOutput: { type: "string", description: "Required result or artifact." },
137
+ constraints: {
138
+ type: "array",
139
+ items: { type: "string" },
140
+ description: "Limits, authority, and confidentiality requirements."
141
+ }
92
142
  },
143
+ required: ["agent", "task"],
93
144
  additionalProperties: true
94
145
  }
95
146
  });
@@ -97,126 +148,142 @@ export async function modelToolsImpl(host, activeToolNames, connectionRegistry,
97
148
  return tools;
98
149
  }
99
150
  export async function harnessExecuteToolImpl(host, call, state) {
100
- const { toolCallId, name, input: params } = call;
101
- if (name === LOAD_SKILL_TOOL_NAME) {
102
- const outcome = await executeLoadSkillTool(host, state.run(), {
103
- sandboxHandle: state.sandboxHandle,
104
- allowedSkills: state.activeSkills
105
- }, params, `tool:${state.run().id}:${name}:${toolCallId}`);
106
- state.setRun(outcome.run);
107
- return harnessResult(outcome.modelOutput, host.env);
108
- }
109
- if (name === TOOL_SEARCH_TOOL_NAME) {
110
- const outcome = await executeToolSearchTool(host, state.run(), {
111
- connectionRegistry: state.connectionRegistry,
112
- discoveredConnectionTools: state.discoveredConnectionTools
113
- }, params, `tool:${state.run().id}:${name}:${toolCallId}`);
114
- state.setRun(outcome.run);
115
- return harnessResult(outcome.modelOutput, host.env);
116
- }
117
- if (name === TOOL_DESCRIBE_TOOL_NAME) {
118
- const outcome = await executeToolDescribeTool(host, state.run(), {
119
- connectionRegistry: state.connectionRegistry,
120
- discoveredConnectionTools: state.discoveredConnectionTools
121
- }, params, `tool:${state.run().id}:${name}:${toolCallId}`);
122
- state.setRun(outcome.run);
123
- return harnessResult(outcome.modelOutput, host.env);
151
+ // Tool calls may already be queued in a provider response when the operator
152
+ // cancels. Re-read the durable run before every tool boundary so no new side
153
+ // effect starts after cancellation became visible to the operator.
154
+ const durableRun = await host.state.getRun(state.run().id);
155
+ if (durableRun?.status === "cancelled" || durableRun?.controlIntent === "cancel") {
156
+ if (durableRun)
157
+ state.setRun(durableRun);
158
+ return harnessResult({ cancelled: true }, host.env);
124
159
  }
125
- if (name === TOOL_CALL_TOOL_NAME) {
126
- const outcome = await executeToolCallBridge(host, state.run(), {
127
- sandboxHandle: state.sandboxHandle,
128
- connectionRegistry: state.connectionRegistry,
129
- discoveredConnectionTools: state.discoveredConnectionTools
130
- }, params, `tool:${state.run().id}:deferred:${toolCallId}`);
160
+ const { toolCallId, name, input: params } = call;
161
+ const boundaryIdempotencyKey = `tool:${state.run().id}:${name}:${toolCallId}`;
162
+ try {
163
+ if (!state.defaultToolNames.has(name) && !state.exposedDeferredToolNames.has(name)) {
164
+ await host.state.appendEvent(state.run().id, "tool.unavailable", {
165
+ toolName: name,
166
+ reason: "not_enabled_for_run"
167
+ });
168
+ throw new Error(`Tool ${name} is not enabled for this run.`);
169
+ }
170
+ if (state.exposedDeferredToolNames.has(name))
171
+ state.defaultToolNames.add(name);
172
+ if (name === LOAD_SKILL_TOOL_NAME) {
173
+ const outcome = await executeLoadSkillTool(host, state.run(), {
174
+ sandboxHandle: state.sandboxHandle,
175
+ allowedSkills: state.activeSkills
176
+ }, params, `tool:${state.run().id}:${name}:${toolCallId}`);
177
+ state.setRun(outcome.run);
178
+ return harnessResult(outcome.modelOutput, host.env);
179
+ }
180
+ if (name === TOOL_SEARCH_TOOL_NAME) {
181
+ const outcome = await executeToolSearchTool(host, state.run(), {
182
+ connectionRegistry: state.connectionRegistry,
183
+ discoveredConnectionTools: state.discoveredConnectionTools,
184
+ activeToolNames: state.defaultToolNames
185
+ }, params, `tool:${state.run().id}:${name}:${toolCallId}`);
186
+ state.setRun(outcome.run);
187
+ return harnessResult(outcome.modelOutput, host.env);
188
+ }
189
+ if (name === DELEGATE_TOOL_NAME) {
190
+ if (!isJsonObject(params))
191
+ throw new Error(`${DELEGATE_TOOL_NAME} requires an object input.`);
192
+ const subagentName = stringValue(params.agent);
193
+ if (!subagentName)
194
+ throw new Error(`${DELEGATE_TOOL_NAME} requires agent.`);
195
+ if (!stringValue(params.task))
196
+ throw new Error(`${DELEGATE_TOOL_NAME} requires a non-empty task.`);
197
+ const task = { ...params };
198
+ delete task.agent;
199
+ const timeline = await host.runSubagent(state.run().id, subagentName, task);
200
+ return harnessResult({
201
+ runId: timeline.run.id,
202
+ status: timeline.run.status,
203
+ events: timeline.events.map((event) => ({ type: event.type, data: event.data })).slice(-8)
204
+ }, host.env);
205
+ }
206
+ if (name === PAIR_TOOL_NAME) {
207
+ const outcome = await executePairTool(host, state.run(), state.connectionRegistry, params, `tool:${state.run().id}:${name}:${toolCallId}`);
208
+ state.setRun(outcome.run);
209
+ return harnessResult(outcome.modelOutput, host.env);
210
+ }
211
+ if (name === CONNECTION_SEARCH_TOOL_NAME) {
212
+ const outcome = await executeConnectionSearchTool(host, state.run(), state.connectionRegistry, params, `tool:${state.run().id}:${name}:${toolCallId}`);
213
+ state.setRun(outcome.run);
214
+ for (const result of outcome.results) {
215
+ if (result.qualifiedName && result.tool && result.inputSchema) {
216
+ const metadata = {
217
+ connection: result.connection,
218
+ name: result.tool,
219
+ qualifiedName: result.qualifiedName,
220
+ description: result.description,
221
+ inputSchema: result.inputSchema
222
+ };
223
+ if (result.outputSchema)
224
+ metadata.outputSchema = result.outputSchema;
225
+ state.discoveredConnectionTools.set(result.qualifiedName, metadata);
226
+ state.defaultToolNames.add(result.qualifiedName);
227
+ }
228
+ }
229
+ return harnessResult(outcome.results, host.env);
230
+ }
231
+ if (parseQualifiedName(name)) {
232
+ const outcome = await executeConnectionTool(host, state.run(), state.connectionRegistry, name, params, false, `tool:${state.run().id}:${name}:${toolCallId}`, "return");
233
+ state.setRun(outcome.run);
234
+ if (outcome.waitingForApproval || outcome.waitingForConnection) {
235
+ const waiting = { run: outcome.run };
236
+ if (outcome.waitingForApproval !== undefined)
237
+ waiting.waitingForApproval = outcome.waitingForApproval;
238
+ if (outcome.waitingForConnection !== undefined)
239
+ waiting.waitingForConnection = outcome.waitingForConnection;
240
+ waiting.toolCallId = toolCallId;
241
+ waiting.toolName = name;
242
+ if (outcome.authorizationSessionId)
243
+ waiting.authorizationSessionId = outcome.authorizationSessionId;
244
+ state.setPause(waiting);
245
+ return harnessPauseOutcome(waiting);
246
+ }
247
+ return harnessResult(outcome.modelOutput ?? {}, host.env);
248
+ }
249
+ const compiledTool = runtimeToolsForSurface(host.surfaceForRun(state.run()).tools).find((candidate) => candidate.name === name);
250
+ if (!compiledTool) {
251
+ await host.state.appendEvent(state.run().id, "tool.unavailable", { toolName: name });
252
+ throw new Error(`Unknown tool: ${name}`);
253
+ }
254
+ const outcome = await executeToolImpl(host, state.run(), compiledTool, params, state.sandboxHandle, false, `tool:${state.run().id}:${compiledTool.name}:${toolCallId}`, call.signal);
131
255
  state.setRun(outcome.run);
132
- if (outcome.waitingForApproval || outcome.waitingForInput || outcome.waitingForConnection) {
256
+ if (outcome.waitingForApproval || outcome.waitingForInput) {
133
257
  const waiting = { run: outcome.run };
134
258
  if (outcome.waitingForApproval !== undefined)
135
259
  waiting.waitingForApproval = outcome.waitingForApproval;
136
260
  if (outcome.waitingForInput !== undefined)
137
261
  waiting.waitingForInput = outcome.waitingForInput;
138
- if (outcome.waitingForConnection !== undefined)
139
- waiting.waitingForConnection = outcome.waitingForConnection;
140
262
  if (outcome.toolCallId)
141
263
  waiting.toolCallId = outcome.toolCallId;
142
264
  if (outcome.toolName)
143
265
  waiting.toolName = outcome.toolName;
144
- if (outcome.authorizationSessionId)
145
- waiting.authorizationSessionId = outcome.authorizationSessionId;
146
- state.setPause(waiting);
147
- return harnessPauseOutcome(waiting);
148
- }
149
- return harnessResult(outcome.modelOutput ?? {}, host.env);
150
- }
151
- if (name.startsWith("delegate_")) {
152
- const subagentName = name.slice("delegate_".length);
153
- const task = isJsonObject(params) ? params : { task: String(params ?? "") };
154
- const timeline = await host.runSubagent(state.run().id, subagentName, task);
155
- return harnessResult({
156
- runId: timeline.run.id,
157
- status: timeline.run.status,
158
- events: timeline.events.map((event) => ({ type: event.type, data: event.data })).slice(-8)
159
- }, host.env);
160
- }
161
- if (name === CONNECTION_SEARCH_TOOL_NAME) {
162
- const outcome = await executeConnectionSearchTool(host, state.run(), state.connectionRegistry, params, `tool:${state.run().id}:${name}:${toolCallId}`);
163
- state.setRun(outcome.run);
164
- for (const result of outcome.results) {
165
- if (result.qualifiedName && result.tool && result.inputSchema) {
166
- const metadata = {
167
- connection: result.connection,
168
- name: result.tool,
169
- qualifiedName: result.qualifiedName,
170
- description: result.description,
171
- inputSchema: result.inputSchema
172
- };
173
- if (result.outputSchema)
174
- metadata.outputSchema = result.outputSchema;
175
- state.discoveredConnectionTools.set(result.qualifiedName, metadata);
176
- state.defaultToolNames.add(result.qualifiedName);
177
- }
178
- }
179
- return harnessResult(outcome.results, host.env);
180
- }
181
- if (parseQualifiedName(name)) {
182
- const outcome = await executeConnectionTool(host, state.run(), state.connectionRegistry, name, params, false, `tool:${state.run().id}:${name}:${toolCallId}`);
183
- state.setRun(outcome.run);
184
- if (outcome.waitingForApproval || outcome.waitingForConnection) {
185
- const waiting = { run: outcome.run };
186
- if (outcome.waitingForApproval !== undefined)
187
- waiting.waitingForApproval = outcome.waitingForApproval;
188
- if (outcome.waitingForConnection !== undefined)
189
- waiting.waitingForConnection = outcome.waitingForConnection;
190
- waiting.toolCallId = toolCallId;
191
- waiting.toolName = name;
192
- if (outcome.authorizationSessionId)
193
- waiting.authorizationSessionId = outcome.authorizationSessionId;
194
266
  state.setPause(waiting);
195
267
  return harnessPauseOutcome(waiting);
196
268
  }
197
269
  return harnessResult(outcome.modelOutput ?? {}, host.env);
198
270
  }
199
- const compiledTool = runtimeToolsForManifest(host.manifest).find((candidate) => candidate.name === name);
200
- if (!compiledTool) {
201
- await host.state.appendEvent(state.run().id, "tool.unavailable", { toolName: name });
202
- return harnessResult({ error: `Unknown tool: ${name}` }, host.env);
203
- }
204
- const outcome = await executeToolImpl(host, state.run(), compiledTool, params, state.sandboxHandle, false, `tool:${state.run().id}:${compiledTool.name}:${toolCallId}`);
205
- state.setRun(outcome.run);
206
- if (outcome.waitingForApproval || outcome.waitingForInput) {
207
- const waiting = { run: outcome.run };
208
- if (outcome.waitingForApproval !== undefined)
209
- waiting.waitingForApproval = outcome.waitingForApproval;
210
- if (outcome.waitingForInput !== undefined)
211
- waiting.waitingForInput = outcome.waitingForInput;
212
- if (outcome.toolCallId)
213
- waiting.toolCallId = outcome.toolCallId;
214
- if (outcome.toolName)
215
- waiting.toolName = outcome.toolName;
216
- state.setPause(waiting);
217
- return harnessPauseOutcome(waiting);
271
+ catch (error) {
272
+ // One shared model-tool boundary catches failures that occur before a
273
+ // specialized executor can normalize them (sandbox acquisition, deferred
274
+ // activation preflight, connection approval resolution, delegation, or
275
+ // future dispatch branches). State persistence failures still escape naturally:
276
+ // if we cannot durably record this failure, the run cannot safely continue.
277
+ const run = state.run();
278
+ const existing = (await host.state.listToolCalls(run.id))
279
+ .filter((candidate) => candidate.idempotencyKey === boundaryIdempotencyKey
280
+ || candidate.idempotencyKey.startsWith(`${boundaryIdempotencyKey}:`))
281
+ .at(-1);
282
+ const toolCall = existing ?? await recordRuntimeHandledToolStart(host, run, name, params, boundaryIdempotencyKey);
283
+ const failure = await failRuntimeHandledTool(host, run, toolCall, toolCall.toolName, error, isConnectionConfigurationError(error) ? { failureKind: "configuration_error" } : undefined);
284
+ state.setRun(failure.run);
285
+ return harnessResult(failure.modelOutput, host.env);
218
286
  }
219
- return harnessResult(outcome.modelOutput ?? {}, host.env);
220
287
  }
221
288
  function harnessResult(output, env) {
222
289
  const prepared = prepareToolModelOutput(output, env);
@@ -224,31 +291,14 @@ function harnessResult(output, env) {
224
291
  return { kind: "result", output: prepared.output };
225
292
  return { kind: "result", output: prepared.output, media: prepared.media };
226
293
  }
227
- async function executeToolCallBridge(host, run, state, input, idempotencyKey, approved = false) {
228
- const raw = isJsonObject(input) ? input : {};
229
- const name = stringValue(raw.name);
230
- const args = isJsonObject(raw.arguments) ? raw.arguments : isJsonObject(raw.input) ? raw.input : {};
231
- if (!name)
232
- throw new Error("tool_call requires name.");
233
- if (CORE_HARNESS_TOOL_NAMES.includes(name)) {
234
- throw new Error(`Core harness tool ${name} is already directly visible; call it directly.`);
235
- }
236
- if (parseQualifiedName(name)) {
237
- return executeConnectionTool(host, run, state.connectionRegistry, name, args, approved, `${idempotencyKey}:${name}`);
238
- }
239
- const compiledTool = deferredLocalTools(host).find((tool) => tool.name === name);
240
- if (!compiledTool)
241
- throw new Error(`Deferred tool not found: ${name}`);
242
- const outcome = await executeToolImpl(host, run, compiledTool, args, state.sandboxHandle, approved, `${idempotencyKey}:${name}`);
243
- return { ...outcome, toolName: compiledTool.name };
244
- }
245
294
  export function selectToolImpl(host, options) {
246
295
  if (options.toolName) {
247
- return runtimeToolsForManifest(host.manifest).find((tool) => tool.name === options.toolName);
296
+ const surface = options.existingRun ? host.surfaceForRun(options.existingRun) : undefined;
297
+ return runtimeToolsForSurface((surface?.tools ?? host.manifest.tools)).find((tool) => tool.name === options.toolName);
248
298
  }
249
299
  return undefined;
250
300
  }
251
- export async function executeToolImpl(host, run, tool, input, sandboxHandle, approved, idempotencyKey = `tool:${run.id}:${tool.name}`) {
301
+ export async function executeToolImpl(host, run, tool, input, sandboxHandle, approved, idempotencyKey = `tool:${run.id}:${tool.name}`, signal) {
252
302
  const policyTool = applyCoreToolPolicy(tool, host.coreToolPolicy);
253
303
  if (!policyTool) {
254
304
  await host.state.appendEvent(run.id, "tool.call_requested", { toolName: tool.name, input: redactedToolInput(input) });
@@ -256,37 +306,30 @@ export async function executeToolImpl(host, run, tool, input, sandboxHandle, app
256
306
  runId: run.id,
257
307
  toolName: tool.name,
258
308
  status: "requested",
259
- input: redactedToolInput(input),
309
+ input: safeJson(input),
260
310
  idempotencyKey
261
311
  });
262
- return failRuntimeHandledTool(host, run, toolCall, tool.name, `Core tool ${tool.name} is disabled by the OpenEve core tool policy.`);
312
+ return failRuntimeHandledTool(host, run, toolCall, tool.name, `Core tool ${tool.name} is disabled by the Assembly Line core tool policy.`);
263
313
  }
264
314
  tool = policyTool;
265
315
  if (tool.name === TOOL_SEARCH_TOOL_NAME) {
266
316
  return executeToolSearchTool(host, run, {
267
317
  connectionRegistry: createConnectionRegistryForRunImpl(host, run, "local"),
268
- discoveredConnectionTools: new Map()
318
+ discoveredConnectionTools: new Map(),
319
+ activeToolNames: new Set()
269
320
  }, input, idempotencyKey);
270
321
  }
271
- if (tool.name === TOOL_DESCRIBE_TOOL_NAME) {
272
- return executeToolDescribeTool(host, run, {
273
- connectionRegistry: createConnectionRegistryForRunImpl(host, run, "local"),
274
- discoveredConnectionTools: new Map()
275
- }, input, idempotencyKey);
276
- }
277
- if (tool.name === TOOL_CALL_TOOL_NAME) {
278
- return executeToolCallBridge(host, run, {
279
- sandboxHandle,
280
- connectionRegistry: createConnectionRegistryForRunImpl(host, run, "local", sandboxHandle),
281
- discoveredConnectionTools: new Map()
282
- }, input, idempotencyKey, approved);
322
+ if (tool.name === HISTORY_SEARCH_TOOL_NAME) {
323
+ return executeHistorySearchTool(host, run, input, idempotencyKey);
283
324
  }
284
325
  await host.state.appendEvent(run.id, "tool.call_requested", { toolName: tool.name, input: redactedToolInput(input) });
285
326
  let toolCall = await host.state.createToolCall({
286
327
  runId: run.id,
287
328
  toolName: tool.name,
288
329
  status: "requested",
289
- input: redactedToolInput(input),
330
+ // Raw, not redacted: approval resume re-executes this persisted input.
331
+ // Redaction happens at outward read boundaries (redactedToolCallRecord).
332
+ input: safeJson(input),
290
333
  idempotencyKey
291
334
  });
292
335
  const approval = normalizeApprovalPolicy(tool.needsApproval);
@@ -303,7 +346,7 @@ export async function executeToolImpl(host, run, tool, input, sandboxHandle, app
303
346
  toolName: tool.name,
304
347
  source: "eval"
305
348
  });
306
- return executeToolWithRecordImpl(host, run, tool, toolCall, input, sandboxHandle, true);
349
+ return executeToolWithRecordImpl(host, run, tool, toolCall, input, sandboxHandle, true, signal);
307
350
  }
308
351
  if (approval.mode === "always" && !approved) {
309
352
  toolCall = await host.state.updateToolCall(toolCall.id, { status: "waiting_for_approval" });
@@ -320,22 +363,34 @@ export async function executeToolImpl(host, run, tool, input, sandboxHandle, app
320
363
  });
321
364
  return { run: waitingRun, waitingForApproval: true, toolCallId: toolCall.id, toolName: tool.name };
322
365
  }
323
- return executeToolWithRecordImpl(host, run, tool, toolCall, input, sandboxHandle, approved);
366
+ return executeToolWithRecordImpl(host, run, tool, toolCall, input, sandboxHandle, approved, signal);
324
367
  }
325
- export async function executeToolWithRecordImpl(host, run, tool, toolCall, input, sandboxHandle, approvedToolCall = false) {
368
+ export async function executeToolWithRecordImpl(host, run, tool, toolCall, input, sandboxHandle, approvedToolCall = false, signal) {
326
369
  await host.state.updateToolCall(toolCall.id, { status: "running" });
327
370
  await host.state.appendEvent(run.id, "tool.execution_started", { toolCallId: toolCall.id, toolName: tool.name });
328
371
  const toolSpanStartedAt = timestamp();
329
- if (toolRequiresSandbox(tool)) {
330
- await sandboxHandle.get();
331
- }
332
- const ctx = createToolContext(host, run, sandboxHandle, approvedToolCall);
333
372
  try {
334
- const definition = await host.loadTool(tool, run);
335
- if (!definition.execute)
373
+ const workspaceTool = WORKSPACE_TOOL_NAMES.has(tool.name);
374
+ const definition = workspaceTool ? undefined : await host.loadTool(tool, run);
375
+ if (!workspaceTool && !definition?.execute)
336
376
  throw new Error(`Tool ${tool.name} does not export execute().`);
337
- const result = await withToolTimeout(Promise.resolve(definition.execute(input, ctx)), definition.timeoutMs ?? host.toolTimeoutMs, tool.name);
338
- const modelOutput = definition.toModelOutput ? await definition.toModelOutput(result) : boundModelOutput(result, host.toolOutputMaxChars);
377
+ const executed = await withToolTimeout(async () => {
378
+ // Acquisition, provider reconnect, filesystem hydration, credential
379
+ // projection, authored execution, and output conversion share one
380
+ // deadline. A sandbox provider can no longer wedge the tool boundary
381
+ // before its timer starts.
382
+ if (toolRequiresSandbox(tool))
383
+ await sandboxHandle.get();
384
+ const ctx = createToolContext(host, run, sandboxHandle, approvedToolCall);
385
+ const result = workspaceTool
386
+ ? await host.executeWorkspaceTool(run, tool.name, input, sandboxHandle)
387
+ : await Promise.resolve(definition.execute(input, ctx));
388
+ const modelOutput = definition?.toModelOutput
389
+ ? await definition.toModelOutput(result)
390
+ : boundModelOutput(result, host.toolOutputMaxChars);
391
+ return { result, modelOutput };
392
+ }, definition?.timeoutMs ?? host.toolTimeoutMs, tool.name, signal);
393
+ const { result, modelOutput } = executed;
339
394
  await host.state.updateToolCall(toolCall.id, {
340
395
  status: "completed",
341
396
  result: safeJson(result),
@@ -368,7 +423,57 @@ export async function executeToolWithRecordImpl(host, run, tool, toolCall, input
368
423
  return { run: await host.state.getRun(run.id) ?? run, modelOutput };
369
424
  }
370
425
  catch (error) {
426
+ if (error instanceof ToolOperationInterruptedError && !sandboxHandle.current()) {
427
+ sandboxHandle.abandonAcquisition();
428
+ }
371
429
  if (error instanceof HumanInputRequired) {
430
+ if (runUsesChannelReplyForHumanInput(run)) {
431
+ const message = "This run accepts human input through its active channel, not by pausing the run.";
432
+ const modelOutput = {
433
+ error: message,
434
+ question: error.question,
435
+ options: safeJson(error.options ?? {}),
436
+ action: "Ask the question as your final response. The user's next channel message will continue the conversation.",
437
+ failure: {
438
+ kind: "channel_reply_required",
439
+ runCanContinue: true
440
+ }
441
+ };
442
+ await host.state.updateToolCall(toolCall.id, {
443
+ status: "failed",
444
+ error: message,
445
+ modelOutput
446
+ });
447
+ await host.state.appendEvent(run.id, "tool.execution_failed", {
448
+ toolCallId: toolCall.id,
449
+ toolName: tool.name,
450
+ error: message,
451
+ failureKind: "channel_reply_required",
452
+ recoverable: true
453
+ });
454
+ await host.state.appendEvent(run.id, "human_input.redirected_to_channel", {
455
+ toolCallId: toolCall.id,
456
+ toolName: tool.name,
457
+ question: error.question,
458
+ options: error.options ?? {}
459
+ });
460
+ await host.emitSpan("ai.toolCall", toolSpanStartedAt, host.runSpanAttributes(run, {
461
+ toolCallId: toolCall.id,
462
+ toolName: tool.name,
463
+ status: "failed",
464
+ error: message,
465
+ ...host.toolContentAttributes(input, modelOutput)
466
+ }), {
467
+ parentSpanId: host.turnSpanId(run.id),
468
+ status: "error"
469
+ });
470
+ await host.emitSpan("assembly-line.tool", toolSpanStartedAt, {
471
+ runId: run.id,
472
+ toolName: tool.name,
473
+ status: "failed"
474
+ });
475
+ return { run: await host.state.getRun(run.id) ?? run, modelOutput };
476
+ }
372
477
  await host.state.updateToolCall(toolCall.id, { status: "waiting_for_approval", error: error.message });
373
478
  const waitingRun = await host.state.updateRun(run.id, { status: "waiting_for_input" });
374
479
  await host.state.appendEvent(run.id, "human_input.requested", {
@@ -392,27 +497,14 @@ export async function executeToolWithRecordImpl(host, run, tool, toolCall, input
392
497
  });
393
498
  return { run: waitingRun, waitingForInput: true, toolCallId: toolCall.id, toolName: tool.name };
394
499
  }
395
- // Core sandbox tools (read/write/edit/delete/list/grep/bash) operate on a
396
- // filesystem: "not found", "empty", and non-zero exit are normal,
397
- // recoverable conditions, not run-ending crashes. Their errors are a
398
- // RESULT for the model to reason over (create the dir, try another path,
399
- // report gracefully) exactly what lets an autonomous agent survive an
400
- // empty /workspace or a first-run state file that doesn't exist yet.
401
- // Authored tools throwing is a stronger signal (the agent's own code
402
- // broke) and remains a run failure, so routine/trigger failure detection
403
- // is unchanged. Terminal conditions (human input, approval, connection
404
- // auth) are explicit cases above and never reach here.
500
+ // Every durably recordable model-invoked tool failure is returned to the
501
+ // model. RecoverableToolError classifies correctable input, but ordinary
502
+ // tool and infrastructure errors are also visible so the model can choose
503
+ // another action or explain the failure. State persistence failures still
504
+ // escape because continuing without a durable record is unsafe.
405
505
  const message = error instanceof Error ? error.message : String(error);
406
- await host.state.updateToolCall(toolCall.id, { status: "failed", error: message });
407
- await host.state.appendEvent(run.id, "tool.execution_failed", { toolCallId: toolCall.id, toolName: tool.name, error: message });
408
- const recoverable = isBuiltInToolName(tool.name);
409
- const nextRun = recoverable
410
- ? await host.state.getRun(run.id) ?? run
411
- : await failRun({ state: host.state }, run.id, {
412
- reason: "tool.execution_failed",
413
- error: message,
414
- data: { toolCallId: toolCall.id, toolName: tool.name }
415
- });
506
+ const failure = await failRuntimeHandledTool(host, run, toolCall, tool.name, error);
507
+ const nextRun = failure.run;
416
508
  await host.emitSpan("ai.toolCall", toolSpanStartedAt, host.runSpanAttributes(nextRun, {
417
509
  toolCallId: toolCall.id,
418
510
  toolName: tool.name,
@@ -428,44 +520,66 @@ export async function executeToolWithRecordImpl(host, run, tool, toolCall, input
428
520
  toolName: tool.name,
429
521
  status: "failed"
430
522
  });
431
- return { run: nextRun, modelOutput: { error: message } };
523
+ return { run: nextRun, modelOutput: failure.modelOutput };
432
524
  }
433
525
  }
526
+ const WORKSPACE_TOOL_NAMES = new Set([
527
+ FILES_SEARCH_TOOL_NAME,
528
+ FILES_MOUNT_TOOL_NAME,
529
+ WORKSPACE_SEARCH_TOOL_NAME,
530
+ WORKSPACE_STATUS_TOOL_NAME,
531
+ WORKSPACE_CHECKPOINT_CREATE_TOOL_NAME,
532
+ WORKSPACE_CHECKPOINT_LIST_TOOL_NAME,
533
+ WORKSPACE_CHECKPOINT_RESTORE_TOOL_NAME,
534
+ WORKSPACE_FORK_TOOL_NAME
535
+ ]);
434
536
  const DEFAULT_SHELL_TIMEOUT_MS = 30_000;
435
537
  const DEFAULT_SHELL_TIMEOUT_MAX_MS = 600_000;
436
- /** Clamp a (possibly model-supplied) shell timeout to [1s, OPENEVE_BASH_TIMEOUT_MAX_MS]; 0/negative/NaN fall to the default. */
538
+ /** Clamp a (possibly model-supplied) shell timeout to [1s, ASSEMBLY_LINE_BASH_TIMEOUT_MAX_MS]; 0/negative/NaN fall to the default. */
437
539
  export function clampShellTimeoutMs(requested, env) {
438
- const max = resolvePositiveIntegerEnv(env.OPENEVE_BASH_TIMEOUT_MAX_MS, DEFAULT_SHELL_TIMEOUT_MAX_MS);
540
+ const max = resolvePositiveIntegerEnv(env.ASSEMBLY_LINE_BASH_TIMEOUT_MAX_MS, DEFAULT_SHELL_TIMEOUT_MAX_MS);
439
541
  if (typeof requested !== "number" || !Number.isFinite(requested) || requested <= 0) {
440
542
  return Math.min(DEFAULT_SHELL_TIMEOUT_MS, max);
441
543
  }
442
544
  return Math.min(Math.max(Math.floor(requested), 1_000), max);
443
545
  }
444
- /**
445
- * Race a tool `execute` against its deadline. The promise is not cancelled —
446
- * the tool call fails (and flows through the recoverable/authored
447
- * classification) but the underlying work is not forcibly stopped.
448
- */
449
- function withToolTimeout(promise, timeoutMs, toolName) {
450
- if (timeoutMs <= 0)
451
- return promise;
546
+ class ToolOperationInterruptedError extends Error {
547
+ }
548
+ /** Bound the complete runtime tool boundary and release its caller on cancel. */
549
+ function withToolTimeout(operation, timeoutMs, toolName, signal) {
550
+ if (signal?.aborted) {
551
+ return Promise.reject(new ToolOperationInterruptedError(`Tool ${toolName} was cancelled.`));
552
+ }
553
+ const pending = Promise.resolve().then(operation);
554
+ if (timeoutMs <= 0 && !signal)
555
+ return pending;
452
556
  return new Promise((resolve, reject) => {
453
- // Ref'd on purpose: while a hung tool is the only pending work, an
454
- // unref'd timer would drain the event loop before the deadline fires.
455
- const timer = setTimeout(() => {
456
- reject(new Error(`Tool ${toolName} timed out after ${timeoutMs}ms.`));
457
- }, timeoutMs);
458
- promise.then((value) => {
459
- clearTimeout(timer);
460
- resolve(value);
557
+ let settled = false;
558
+ const finish = (callback) => {
559
+ if (settled)
560
+ return;
561
+ settled = true;
562
+ if (timer)
563
+ clearTimeout(timer);
564
+ signal?.removeEventListener("abort", onAbort);
565
+ callback();
566
+ };
567
+ const onAbort = () => finish(() => {
568
+ reject(new ToolOperationInterruptedError(`Tool ${toolName} was cancelled.`));
569
+ });
570
+ const timer = timeoutMs > 0 ? setTimeout(() => finish(() => {
571
+ reject(new ToolOperationInterruptedError(`Tool ${toolName} timed out after ${timeoutMs}ms.`));
572
+ }), timeoutMs) : undefined;
573
+ signal?.addEventListener("abort", onAbort, { once: true });
574
+ pending.then((value) => {
575
+ finish(() => resolve(value));
461
576
  }, (error) => {
462
- clearTimeout(timer);
463
- reject(error instanceof Error ? error : new Error(String(error)));
577
+ finish(() => reject(error instanceof Error ? error : new Error(String(error))));
464
578
  });
465
579
  });
466
580
  }
467
581
  export function wrapSandboxImpl(host, runId, session) {
468
- return {
582
+ const wrapped = {
469
583
  ...session,
470
584
  readFile: async (path) => {
471
585
  const contents = await session.readFile(path);
@@ -505,6 +619,14 @@ export function wrapSandboxImpl(host, runId, session) {
505
619
  return result;
506
620
  }
507
621
  };
622
+ if (session.readFileBytes) {
623
+ wrapped.readFileBytes = async (path) => {
624
+ const contents = await session.readFileBytes(path);
625
+ await host.state.appendEvent(runId, "sandbox.file_read", { path, bytes: contents.byteLength });
626
+ return contents;
627
+ };
628
+ }
629
+ return wrapped;
508
630
  }
509
631
  async function ensureSandboxSyncObligation(host, runId, session, reason, metadata = {}) {
510
632
  const run = await host.state.getRun(runId);
@@ -512,6 +634,31 @@ async function ensureSandboxSyncObligation(host, runId, session, reason, metadat
512
634
  throw new Error(`Run not found for sandbox sync obligation: ${runId}`);
513
635
  const sessionKey = host.sandboxSessionKey(run);
514
636
  const existing = await host.state.getSandboxSession(sessionKey);
637
+ const workspaceId = stringValue(existing?.manifest.workspaceId)?.trim();
638
+ const baseVersionId = existing?.manifest.baseVersionId;
639
+ const hasBaseVersionId = baseVersionId === null || typeof baseVersionId === "string";
640
+ if (!workspaceId || !hasBaseVersionId) {
641
+ const missing = [
642
+ ...(!workspaceId ? ["workspaceId"] : []),
643
+ ...(!hasBaseVersionId ? ["baseVersionId"] : [])
644
+ ];
645
+ const error = `Sandbox is not fully hydrated; refusing ${reason} before creating an invalid sync obligation (missing ${missing.join(", ")}).`;
646
+ await host.state.appendEvent(runId, "sandbox.sync_obligation_rejected", {
647
+ sandboxId: session.id,
648
+ sessionKey,
649
+ reason,
650
+ missing,
651
+ metadata
652
+ });
653
+ throw new Error(error);
654
+ }
655
+ const sessionManifest = {
656
+ ...existing?.manifest,
657
+ roots: ["/memory", "/skills", "/workspace"],
658
+ sandboxRoot: session.root,
659
+ ...sandboxFilesystemContractMetadata(session.provider === "local" ? "emulated" : "physical")
660
+ };
661
+ const syncManifest = { ...sessionManifest, sessionRecordKey: sessionKey };
515
662
  const syncJob = await host.state.enqueueSandboxSyncJob({
516
663
  runId,
517
664
  sandboxId: session.id,
@@ -519,13 +666,7 @@ async function ensureSandboxSyncObligation(host, runId, session, reason, metadat
519
666
  idempotencyKey: `sandbox-sync:${runId}:${session.id}`,
520
667
  reason,
521
668
  maxAttempts: host.sandboxSyncMaxAttempts,
522
- manifest: {
523
- ...(existing?.manifest ?? {}),
524
- roots: ["/memory", "/skills", "/workspace"],
525
- sandboxRoot: session.root,
526
- sessionKey,
527
- ...sandboxFilesystemContractMetadata(session.provider === "local" ? "emulated" : "physical")
528
- },
669
+ manifest: syncManifest,
529
670
  metadata
530
671
  });
531
672
  await host.state.updateSandboxSession(sessionKey, {
@@ -535,13 +676,7 @@ async function ensureSandboxSyncObligation(host, runId, session, reason, metadat
535
676
  dirty: true,
536
677
  lastSeenAt: timestamp(),
537
678
  syncJobId: syncJob.id,
538
- manifest: {
539
- ...(existing?.manifest ?? {}),
540
- roots: ["/memory", "/skills", "/workspace"],
541
- sandboxRoot: session.root,
542
- sessionKey,
543
- ...sandboxFilesystemContractMetadata(session.provider === "local" ? "emulated" : "physical")
544
- }
679
+ manifest: sessionManifest
545
680
  }).catch(async () => {
546
681
  await host.state.upsertSandboxSession({
547
682
  sessionKey,
@@ -552,12 +687,7 @@ async function ensureSandboxSyncObligation(host, runId, session, reason, metadat
552
687
  dirty: true,
553
688
  lastSeenAt: timestamp(),
554
689
  syncJobId: syncJob.id,
555
- manifest: {
556
- roots: ["/memory", "/skills", "/workspace"],
557
- sandboxRoot: session.root,
558
- sessionKey,
559
- ...sandboxFilesystemContractMetadata(session.provider === "local" ? "emulated" : "physical")
560
- }
690
+ manifest: sessionManifest
561
691
  });
562
692
  });
563
693
  await host.state.appendEvent(runId, "sandbox.sync_obligation", {