@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,16 +1,27 @@
1
1
  import { AsyncLocalStorage } from "node:async_hooks";
2
2
  import { randomUUID } from "node:crypto";
3
- import { ConnectionAuthorizationFailedError, ConnectionAuthorizationRequiredError, isConnectionAuthorizationFailedError, isConnectionAuthorizationRequiredError } from "@assemblyline-agents/core";
3
+ import { ConnectionAuthorizationFailedError, ConnectionAuthorizationRequiredError, isConnectionAuthorizationFailedError, isConnectionAuthorizationRequiredError, resolveSandboxPath, shellQuote } from "@assemblyline-agents/core";
4
4
  import { OAUTH_STANDARD_TOKEN_FIELDS, buildOAuthChallenge, connectionPrincipalFor, connectionPrincipalKey, grantToTokenResult, isTokenExpired, normalizeAuthorization, randomUrlToken, resolveHeadersDefinition, storedGrantExpired, tokenCacheKey } from "./connection-auth-util.js";
5
- import { HttpApiConnectionClient, McpConnectionClient, OpenApiConnectionClient, RelayMcpConnectionClient, readResponseBody } from "./connection-clients.js";
5
+ import { HttpApiConnectionClient, A2AConnectionClient, CredentialConnectionClient, McpConnectionClient, OpenApiConnectionClient, RelayMcpConnectionClient, SdkApiConnectionClient, readResponseBody } from "./connection-clients.js";
6
6
  import { SandboxCliConnectionClient } from "./sandbox-cli-client.js";
7
+ import { audienceAllowsConnectionAccess } from "./audience.js";
7
8
  import { InMemoryConnectionAuthorizationSessionStore, InMemoryConnectionGrantStore } from "./connection-stores.js";
8
- import { connectionToolAccess, isLiveConnection, isRecord, liveDefinitionUrl, parseQualifiedName, scoreMatch, stringValue, timestamp, tokenize } from "./connection-util.js";
9
+ import { connectionToolAccess, connectionToolApproval, isLiveConnection, isRecord, liveDefinitionUrl, parseQualifiedName, scoreMatch, stringValue, timestamp, tokenize } from "./connection-util.js";
9
10
  export * from "./connection-auth-util.js";
10
11
  export * from "./connection-clients.js";
11
12
  export * from "./connection-stores.js";
12
13
  export * from "./connection-util.js";
13
14
  export * from "./computer-relay-protocol.js";
15
+ export class ConnectionConfigurationError extends Error {
16
+ constructor(message) {
17
+ super(message);
18
+ this.name = "ConnectionConfigurationError";
19
+ }
20
+ }
21
+ export function isConnectionConfigurationError(error) {
22
+ return error instanceof ConnectionConfigurationError;
23
+ }
24
+ const MATERIALIZED_CREDENTIAL_ROOT = "/workspace/.assembly-line/credentials/";
14
25
  // Compose the channel-visible response for a run parked on connection
15
26
  // authorization. The generic "authorization required" string is useless to the
16
27
  // human — the challenge URL is the thing they need to click.
@@ -34,23 +45,55 @@ export async function connectionAuthorizationPrompt(store, authorizationSessionI
34
45
  export async function materializeConnectionCredentialsIntoSandbox(run, registry, sandbox, appendEvent) {
35
46
  if (run.input.channel === "subagent" || typeof run.input.parentRunId === "string")
36
47
  return;
37
- const { materialized, pending } = await registry.materializeCredentials();
48
+ const { materialized, pending } = await registry.materializeCredentials({
49
+ id: run.id,
50
+ input: run.input
51
+ });
38
52
  if (materialized.length === 0 && pending.length === 0)
39
53
  return;
40
54
  for (const credential of materialized) {
41
55
  for (const file of credential.files) {
56
+ assertMaterializedCredentialPath(credential.connection, file.path);
42
57
  await sandbox.writeFile(file.path, file.content);
43
- await sandbox.shell(`chmod ${file.mode.toString(8)} '${file.path.replaceAll("'", String.raw `'\''`)}'`);
58
+ const physicalPath = resolveSandboxPath(sandbox.root, file.path);
59
+ await sandbox.shell(`chmod ${file.mode.toString(8)} -- ${shellQuote(physicalPath)}`);
60
+ }
61
+ for (const command of credential.commands ?? []) {
62
+ await sandbox.shell(command);
44
63
  }
45
64
  }
46
65
  await appendEvent("connections.credentials_materialized", {
47
66
  materialized: materialized.map((credential) => ({
48
67
  connection: credential.connection,
49
- files: credential.files.map((file) => file.path)
68
+ files: credential.files.map((file) => file.path),
69
+ ...(credential.audit ? { audit: credential.audit } : {})
50
70
  })),
51
71
  pending
52
72
  });
53
73
  }
74
+ function assertMaterializedCredentialPath(connectionName, path) {
75
+ const normalized = path.replace(/\\/g, "/").replace(/\/+/g, "/");
76
+ if (normalized.split("/").includes("..") || !normalized.startsWith(MATERIALIZED_CREDENTIAL_ROOT)) {
77
+ throw new ConnectionConfigurationError(`Connection ${connectionName} materialize files must be under ${MATERIALIZED_CREDENTIAL_ROOT}`);
78
+ }
79
+ }
80
+ function assertRedactedAuditMetadata(connectionName, audit) {
81
+ const visit = (value, path) => {
82
+ if (Array.isArray(value)) {
83
+ value.forEach((item, index) => visit(item, `${path}[${index}]`));
84
+ return;
85
+ }
86
+ if (!value || typeof value !== "object")
87
+ return;
88
+ for (const [key, item] of Object.entries(value)) {
89
+ if (/(?:token|secret|password|authorization|credential)/iu.test(key)) {
90
+ throw new ConnectionConfigurationError(`Connection ${connectionName} audit metadata contains forbidden secret-like key ${path}.${key}.`);
91
+ }
92
+ visit(item, `${path}.${key}`);
93
+ }
94
+ };
95
+ visit(audit, "audit");
96
+ }
54
97
  export const CONNECTION_PAIR_TOOL_NAME = "pair";
55
98
  // The synthetic host-side pairing tool advertised for connections that define
56
99
  // redeemPairingCode. The input field is named `secret` so tool-call event
@@ -60,7 +103,7 @@ function pairingToolItem(connection) {
60
103
  connection: connection.name,
61
104
  qualifiedName: `${connection.name}__${CONNECTION_PAIR_TOOL_NAME}`,
62
105
  tool: CONNECTION_PAIR_TOOL_NAME,
63
- description: `Pair ${connection.name} by redeeming a one-time pairing packet or claim code. When the user pastes binding/pairing instructions for ${connection.name}, call this with the FULL pasted text as \`secret\`; the host exchanges it and stores the credential durably. Works while the connection is not yet authorized.`,
106
+ description: `Pair ${connection.name} by redeeming a one-time pairing packet or claim code. When the user pastes binding/pairing instructions for ${connection.name}, call this with the FULL pasted text as \`secret\`; the host exchanges it and stores the credential durably. Only call this for a supplied packet; the tool's presence does not mean an existing grant is missing.`,
64
107
  inputSchema: {
65
108
  type: "object",
66
109
  additionalProperties: false,
@@ -112,6 +155,46 @@ export class RuntimeConnectionRegistry {
112
155
  .filter(isLiveConnection)
113
156
  .map((connection) => connection.name);
114
157
  }
158
+ /** Resolve the host-only event adapter without exposing it as a model tool. */
159
+ async eventBindingContext(connectionName) {
160
+ const compiled = this.options.connections.find((connection) => connection.name === connectionName);
161
+ if (!compiled || !isLiveConnection(compiled)) {
162
+ throw new ConnectionConfigurationError(`Connection ${connectionName} is not registered as a live connection.`);
163
+ }
164
+ const definition = (await this.resolveConnection(compiled)).definition;
165
+ if (!definition.events)
166
+ throw new ConnectionConfigurationError(`Connection ${connectionName} does not accept provider events.`);
167
+ const context = this.resolverContext();
168
+ let principal;
169
+ if (definition.events.scope === "connection") {
170
+ principal = { type: "app" };
171
+ }
172
+ else if (definition.auth) {
173
+ const authorization = await normalizeAuthorization(definition.auth, context);
174
+ principal = connectionPrincipalFor(compiled, authorization, context);
175
+ }
176
+ else if (compiled.subject === "user") {
177
+ const sessionPrincipal = context.session.principal;
178
+ if (!sessionPrincipal || sessionPrincipal.type !== "user") {
179
+ throw new ConnectionConfigurationError(`Connection ${connectionName} events require an authenticated user principal.`);
180
+ }
181
+ principal = sessionPrincipal;
182
+ }
183
+ else {
184
+ principal = { type: "app" };
185
+ }
186
+ return {
187
+ compiled,
188
+ events: definition.events,
189
+ principal,
190
+ principalKey: connectionPrincipalKey(principal),
191
+ getToken: async () => {
192
+ if (!definition.auth)
193
+ throw new ConnectionConfigurationError(`Connection ${connectionName} event adapter requested a token without connection auth.`);
194
+ return this.resolveToken(compiled, definition.auth, context, liveDefinitionUrl(definition));
195
+ }
196
+ };
197
+ }
115
198
  async search(input, execution) {
116
199
  return this.authorizationIntent.run("discover", () => this.withExecutionContext(execution, () => this.searchWithContext(input)));
117
200
  }
@@ -122,15 +205,27 @@ export class RuntimeConnectionRegistry {
122
205
  const queryTokens = tokenize(keywords);
123
206
  const scored = [];
124
207
  const failures = [];
208
+ const privateOnly = [];
125
209
  // Pairing tools surface even when the connection cannot authenticate yet —
126
210
  // redeeming a pasted packet is exactly how an unauthorized connection
127
211
  // becomes authorized, so it must not hide behind the failure path.
128
212
  const pairable = [];
129
213
  for (const connection of target) {
130
- if (await this.supportsPairing(connection))
131
- pairable.push(pairingToolItem(connection));
214
+ // A personal connection stays registered in a shared run, but its tool
215
+ // catalog, pairing, and authorization state are private-surface only.
216
+ if (!this.connectionAccessible(connection)) {
217
+ privateOnly.push({
218
+ connection: connection.name,
219
+ description: `${connection.name} is registered. Its personal tools, pairing, and authorization status are available only on a private surface such as a direct message; this does not mean a durable grant is missing.`,
220
+ requiresPrivateAudience: true
221
+ });
222
+ continue;
223
+ }
132
224
  let metadata;
133
225
  try {
226
+ if (await this.supportsPairing(connection)) {
227
+ pairable.push(pairingToolItem(connection));
228
+ }
134
229
  metadata = await this.getClient(connection.name).getToolMetadata();
135
230
  }
136
231
  catch (error) {
@@ -159,23 +254,52 @@ export class RuntimeConnectionRegistry {
159
254
  scored.sort((a, b) => b.score - a.score);
160
255
  const matches = scored.slice(0, limit).map((entry) => entry.item);
161
256
  if (matches.length > 0)
162
- return [...pairable, ...matches, ...failures];
257
+ return [...pairable, ...matches, ...privateOnly, ...failures];
258
+ const privateConnectionNames = new Set(privateOnly.map((item) => item.connection));
163
259
  return [
164
260
  ...pairable,
261
+ ...privateOnly,
165
262
  ...target.map((connection) => ({
166
263
  connection: connection.name,
167
264
  description: connection.description ?? `${connection.name} connection`
168
- })),
265
+ })).filter((item) => !privateConnectionNames.has(item.connection)),
169
266
  ...failures
170
267
  ];
171
268
  }
269
+ // Deliberately does not swallow load errors: a definition module that fails
270
+ // to resolve (for example a deployed artifact missing the connection's
271
+ // package) must surface the real cause instead of silently hiding the
272
+ // pairing tool that would otherwise be the recovery path.
172
273
  async supportsPairing(connection) {
173
- try {
174
- return typeof (await this.resolveConnection(connection)).definition.redeemPairingCode === "function";
175
- }
176
- catch {
177
- return false;
178
- }
274
+ return typeof (await this.resolveConnection(connection)).definition.redeemPairingCode === "function";
275
+ }
276
+ /**
277
+ * Report which live connections can redeem a pairing code right now, and
278
+ * which cannot because their definition failed to resolve (missing package,
279
+ * unset env, platform mismatch). Backs the core `pair` tool: a connection
280
+ * that cannot even load must still be *diagnosable* from the model — the
281
+ * resolve failure is the answer the user needs, not a hidden tool.
282
+ */
283
+ async pairingStatus() {
284
+ return this.authorizationIntent.run("discover", async () => {
285
+ const pairable = [];
286
+ const unavailable = [];
287
+ for (const connection of this.options.connections) {
288
+ if (!this.toolAllowed(connection))
289
+ continue;
290
+ try {
291
+ if (await this.supportsPairing(connection))
292
+ pairable.push(connection.name);
293
+ }
294
+ catch (error) {
295
+ unavailable.push({
296
+ connection: connection.name,
297
+ reason: error instanceof Error ? error.message : String(error)
298
+ });
299
+ }
300
+ }
301
+ return { pairable, unavailable };
302
+ });
179
303
  }
180
304
  /**
181
305
  * Redeem a user-provided one-time pairing code host-side and persist the
@@ -187,6 +311,9 @@ export class RuntimeConnectionRegistry {
187
311
  if (!compiled || !isLiveConnection(compiled)) {
188
312
  throw new Error(`Connection ${connectionName} is not registered as a live connection.`);
189
313
  }
314
+ if (!this.connectionAccessible(compiled)) {
315
+ throw new Error(`Connection ${connectionName} is personal and pairs only on a private surface such as a direct message.`);
316
+ }
190
317
  const definition = (await this.resolveConnection(compiled)).definition;
191
318
  const redeem = definition.redeemPairingCode;
192
319
  if (!redeem)
@@ -213,6 +340,9 @@ export class RuntimeConnectionRegistry {
213
340
  const parsed = parseQualifiedName(qualifiedName);
214
341
  if (!parsed)
215
342
  return undefined;
343
+ const compiled = this.options.connections.find((connection) => connection.name === parsed.connectionName);
344
+ if (!compiled || !this.toolAllowed(compiled))
345
+ return undefined;
216
346
  const metadata = await this.getClient(parsed.connectionName).getToolMetadata();
217
347
  return metadata.find((tool) => tool.name === parsed.toolName);
218
348
  });
@@ -221,11 +351,14 @@ export class RuntimeConnectionRegistry {
221
351
  const parsed = parseQualifiedName(qualifiedName);
222
352
  if (!parsed)
223
353
  throw new Error(`Invalid connection tool name: ${qualifiedName}`);
354
+ const compiled = this.options.connections.find((connection) => connection.name === parsed.connectionName);
355
+ if (!compiled || !this.toolAllowed(compiled)) {
356
+ throw new Error(`Connection tool ${qualifiedName} is unavailable here: personal connections work only on a private surface such as a direct message.`);
357
+ }
224
358
  // "<connection>__pair" is the synthetic host-side pairing tool; it must
225
359
  // run before any client/auth resolution (the whole point is that the
226
360
  // connection is not authorized yet).
227
361
  if (parsed.toolName === CONNECTION_PAIR_TOOL_NAME) {
228
- const compiled = this.options.connections.find((connection) => connection.name === parsed.connectionName);
229
362
  if (compiled && await this.supportsPairing(compiled)) {
230
363
  const secret = isRecord(input) && typeof input.secret === "string" ? input.secret : "";
231
364
  return this.withExecutionContext(execution, () => this.redeemPairingCode(parsed.connectionName, secret));
@@ -237,12 +370,27 @@ export class RuntimeConnectionRegistry {
237
370
  const compiled = this.options.connections.find((connection) => connection.name === connectionName);
238
371
  if (!compiled || !isLiveConnection(compiled))
239
372
  return undefined;
373
+ if (!this.toolAllowed(compiled)) {
374
+ throw new Error(`Connection tool ${connectionName}__${toolName} is unavailable here: personal connections work only on a private surface such as a direct message.`);
375
+ }
376
+ // Pairing is a synthetic host-side bootstrap operation, not a provider
377
+ // tool. It must bypass the provider connection's ordinary read/write
378
+ // classification or discovery will advertise a tool that execution then
379
+ // rejects before the redeemer can run.
380
+ if (toolName === CONNECTION_PAIR_TOOL_NAME) {
381
+ if (!await this.supportsPairing(compiled)) {
382
+ throw new Error(`Connection ${connectionName} does not support pairing codes.`);
383
+ }
384
+ return undefined;
385
+ }
240
386
  const resolved = await this.resolveConnection(compiled);
387
+ if (!("access" in resolved.definition) || !resolved.definition.access)
388
+ return undefined;
241
389
  const access = connectionToolAccess(toolName, resolved.definition.access);
242
390
  if (access === "none")
243
391
  throw new Error(`Tool ${toolName} is not allowed by connection ${connectionName}.`);
244
392
  if (access === "write" && resolved.definition.access.write !== false) {
245
- return resolved.definition.access.write.approval;
393
+ return connectionToolApproval(toolName, resolved.definition.access);
246
394
  }
247
395
  return resolved.definition.approval;
248
396
  }
@@ -252,18 +400,24 @@ export class RuntimeConnectionRegistry {
252
400
  return existing;
253
401
  const compiled = this.options.connections.find((connection) => connection.name === connectionName);
254
402
  if (!compiled || !isLiveConnection(compiled)) {
255
- throw new Error(`Connection ${connectionName} is not registered as a live connection.`);
403
+ throw new ConnectionConfigurationError(`Connection ${connectionName} is not registered as a live connection.`);
256
404
  }
257
405
  const resolved = () => this.resolveConnection(compiled);
258
- const client = compiled.protocol === "cli"
259
- ? new SandboxCliConnectionClient(compiled, resolved, this)
260
- : compiled.protocol === "mcp"
261
- ? compiled.transport === "relay"
262
- ? new RelayMcpConnectionClient(compiled, resolved, this)
263
- : new McpConnectionClient(compiled, resolved, this)
264
- : compiled.protocol === "openapi"
265
- ? new OpenApiConnectionClient(compiled, resolved, this)
266
- : new HttpApiConnectionClient(compiled, resolved, this);
406
+ const client = compiled.protocol === "credential"
407
+ ? new CredentialConnectionClient()
408
+ : compiled.protocol === "cli"
409
+ ? new SandboxCliConnectionClient(compiled, resolved, this)
410
+ : compiled.protocol === "mcp"
411
+ ? compiled.transport === "relay"
412
+ ? new RelayMcpConnectionClient(compiled, resolved, this)
413
+ : new McpConnectionClient(compiled, resolved, this)
414
+ : compiled.protocol === "openapi"
415
+ ? new OpenApiConnectionClient(compiled, resolved, this)
416
+ : compiled.protocol === "sdk"
417
+ ? new SdkApiConnectionClient(compiled, resolved)
418
+ : compiled.protocol === "a2a"
419
+ ? new A2AConnectionClient(compiled, resolved, this)
420
+ : new HttpApiConnectionClient(compiled, resolved, this);
267
421
  this.clients.set(connectionName, client);
268
422
  return client;
269
423
  }
@@ -338,32 +492,38 @@ export class RuntimeConnectionRegistry {
338
492
  * that persists the rotated grant to the grant store BEFORE anything is
339
493
  * rendered — so the sandbox only ever sees the short-lived access token.
340
494
  *
341
- * A connection that cannot resolve (missing grant, pending authorization,
342
- * failed refresh) is reported as pending, never thrown: missing credentials
343
- * are a recoverable connection-required state, not a boot crash.
495
+ * A normal connection that cannot resolve is reported as pending. An
496
+ * required or explicitly requested credential-protocol connection throws
497
+ * instead, so a run can never continue after a missing, revoked, or
498
+ * mismatched sandbox credential.
344
499
  */
345
- async materializeCredentials() {
346
- return this.authorizationIntent.run("discover", () => this.materializeCredentialsWithContext());
500
+ async materializeCredentials(run) {
501
+ return this.authorizationIntent.run("discover", () => this.materializeCredentialsWithContext(run));
347
502
  }
348
- async materializeCredentialsWithContext() {
503
+ async materializeCredentialsWithContext(run) {
349
504
  const materialized = [];
350
505
  const pending = [];
351
506
  const context = this.resolverContext();
352
507
  for (const compiled of this.options.connections) {
353
- if (!isLiveConnection(compiled))
508
+ if (!this.toolAllowed(compiled))
354
509
  continue;
510
+ const failClosed = compiled.protocol === "credential"
511
+ && (compiled.required || sandboxCredentialWasRequested(run, compiled.name));
355
512
  let definition;
356
513
  try {
357
514
  definition = (await this.resolveConnection(compiled)).definition;
358
515
  }
359
516
  catch (error) {
517
+ if (failClosed)
518
+ throw error;
360
519
  pending.push({ connection: compiled.name, reason: error instanceof Error ? error.message : String(error) });
361
520
  continue;
362
521
  }
363
522
  const spec = definition.materialize;
364
- if (!spec || spec.files.length === 0)
523
+ if (!spec || ((spec.files?.length ?? 0) === 0 && !spec.resolve))
365
524
  continue;
366
- const needsToken = spec.files.some((file) => templateUsesToken(file.path) || templateUsesToken(file.content));
525
+ const staticFiles = spec.files ?? [];
526
+ const needsToken = staticFiles.some((file) => templateUsesToken(file.path) || templateUsesToken(file.content));
367
527
  let resolvedToken = { token: "" };
368
528
  if (needsToken) {
369
529
  if (!definition.auth) {
@@ -374,6 +534,64 @@ export class RuntimeConnectionRegistry {
374
534
  resolvedToken = await this.resolveToken(compiled, definition.auth, context, liveDefinitionUrl(definition));
375
535
  }
376
536
  catch (error) {
537
+ if (failClosed)
538
+ throw error;
539
+ if (isConnectionAuthorizationRequiredError(error)) {
540
+ const authorizeUrl = typeof error.challenge?.url === "string" ? error.challenge.url : undefined;
541
+ pending.push({ connection: compiled.name, reason: `authorization_required: ${error.reason}`, ...(authorizeUrl ? { authorizeUrl } : {}) });
542
+ continue;
543
+ }
544
+ const reason = isConnectionAuthorizationFailedError(error)
545
+ ? `${error.reason}: ${error.message}`
546
+ : error instanceof Error
547
+ ? error.message
548
+ : String(error);
549
+ pending.push({ connection: compiled.name, reason });
550
+ continue;
551
+ }
552
+ }
553
+ let files = staticFiles;
554
+ let commands = [];
555
+ let audit;
556
+ if (spec.resolve) {
557
+ if (!run) {
558
+ pending.push({ connection: compiled.name, reason: "run_context_required" });
559
+ continue;
560
+ }
561
+ let lazyToken;
562
+ try {
563
+ const authorization = definition.auth
564
+ ? await normalizeAuthorization(definition.auth, context)
565
+ : undefined;
566
+ const principal = authorization
567
+ ? connectionPrincipalFor(compiled, authorization, context)
568
+ : { type: "app" };
569
+ const resolved = await spec.resolve({
570
+ connectionName: compiled.name,
571
+ agentId: this.options.agentId ?? "",
572
+ run,
573
+ principal,
574
+ session: context.session,
575
+ env: this.options.env,
576
+ fetch: this.options.fetch,
577
+ getToken: async () => {
578
+ if (!definition.auth)
579
+ throw new Error(`Connection ${compiled.name} materialization requested a token without auth.`);
580
+ lazyToken ??= this.resolveToken(compiled, definition.auth, context, liveDefinitionUrl(definition));
581
+ return lazyToken;
582
+ }
583
+ });
584
+ if (!resolved)
585
+ continue;
586
+ files = resolved.files;
587
+ commands = resolved.commands ?? [];
588
+ audit = resolved.audit;
589
+ if (audit)
590
+ assertRedactedAuditMetadata(compiled.name, audit);
591
+ }
592
+ catch (error) {
593
+ if (failClosed)
594
+ throw error;
377
595
  if (isConnectionAuthorizationRequiredError(error)) {
378
596
  const authorizeUrl = typeof error.challenge?.url === "string" ? error.challenge.url : undefined;
379
597
  pending.push({ connection: compiled.name, reason: `authorization_required: ${error.reason}`, ...(authorizeUrl ? { authorizeUrl } : {}) });
@@ -400,14 +618,18 @@ export class RuntimeConnectionRegistry {
400
618
  try {
401
619
  materialized.push({
402
620
  connection: compiled.name,
403
- files: spec.files.map((file) => ({
621
+ files: files.map((file) => ({
404
622
  path: renderCredentialTemplate(file.path, values, compiled.name),
405
623
  content: renderCredentialTemplate(file.content, values, compiled.name),
406
624
  mode: file.mode ?? 0o600
407
- }))
625
+ })),
626
+ ...(commands.length > 0 ? { commands } : {}),
627
+ ...(audit ? { audit } : {})
408
628
  });
409
629
  }
410
630
  catch (error) {
631
+ if (failClosed)
632
+ throw error;
411
633
  pending.push({ connection: compiled.name, reason: error instanceof Error ? error.message : String(error) });
412
634
  }
413
635
  }
@@ -435,6 +657,11 @@ export class RuntimeConnectionRegistry {
435
657
  const session = await this.authorizationSessionStore.getSessionByState(state);
436
658
  if (!session)
437
659
  throw new ConnectionAuthorizationFailedError("unknown", { reason: "unknown_state", retryable: false });
660
+ // Provider callbacks are routinely retried. Once the grant was saved and
661
+ // the session completed, return the durable result without attempting to
662
+ // exchange the one-time authorization code again.
663
+ if (session.status === "completed")
664
+ return session;
438
665
  if (session.expiresAt <= Date.now()) {
439
666
  await this.authorizationSessionStore.updateSession(session.id, { status: "expired" });
440
667
  throw new ConnectionAuthorizationFailedError(session.connectionName, { reason: "authorization_expired", retryable: true });
@@ -455,7 +682,11 @@ export class RuntimeConnectionRegistry {
455
682
  if (!resolved.definition.auth) {
456
683
  throw new ConnectionAuthorizationFailedError(session.connectionName, { reason: "auth_not_configured", retryable: false });
457
684
  }
458
- const authorization = await normalizeAuthorization(resolved.definition.auth, { env: this.options.env, session: session.session });
685
+ const authorization = await normalizeAuthorization(resolved.definition.auth, {
686
+ env: this.options.env,
687
+ fetch: this.options.fetch,
688
+ session: session.session
689
+ });
459
690
  const connectionContext = { url: compiled.url ?? "" };
460
691
  let token;
461
692
  if (authorization.kind === "oauth" && authorization.oauth) {
@@ -544,6 +775,15 @@ export class RuntimeConnectionRegistry {
544
775
  throw new Error(`OpenAPI connection ${compiled.name} must export description.`);
545
776
  return { compiled, definition: raw };
546
777
  }
778
+ if (compiled.protocol === "a2a") {
779
+ if (typeof raw.agentCardUrl !== "string")
780
+ throw new Error(`A2A connection ${compiled.name} must export agentCardUrl.`);
781
+ if (typeof raw.description !== "string")
782
+ throw new Error(`A2A connection ${compiled.name} must export description.`);
783
+ if (!raw.access || typeof raw.access !== "object")
784
+ throw new Error(`A2A connection ${compiled.name} must export access.`);
785
+ return { compiled, definition: raw };
786
+ }
547
787
  if (compiled.protocol === "http") {
548
788
  if (typeof raw.baseUrl !== "string")
549
789
  throw new Error(`HTTP API connection ${compiled.name} must export baseUrl.`);
@@ -553,6 +793,18 @@ export class RuntimeConnectionRegistry {
553
793
  throw new Error(`HTTP API connection ${compiled.name} must export operations.`);
554
794
  return { compiled, definition: raw };
555
795
  }
796
+ if (compiled.protocol === "sdk") {
797
+ if (compiled.source.path.startsWith("dynamic://")) {
798
+ throw new Error(`Dynamic SDK API connection ${compiled.name} is not allowed.`);
799
+ }
800
+ if (typeof raw.description !== "string" || !Array.isArray(raw.operations) || typeof raw.execute !== "function") {
801
+ throw new Error(`SDK API connection ${compiled.name} must export description, operations, and execute.`);
802
+ }
803
+ if (!raw.access || typeof raw.access !== "object") {
804
+ throw new Error(`SDK API connection ${compiled.name} must export access.`);
805
+ }
806
+ return { compiled, definition: raw };
807
+ }
556
808
  if (compiled.protocol === "cli") {
557
809
  if (compiled.source.path.startsWith("dynamic://")) {
558
810
  throw new Error(`Dynamic CLI connection ${compiled.name} is not allowed.`);
@@ -565,6 +817,12 @@ export class RuntimeConnectionRegistry {
565
817
  }
566
818
  return { compiled, definition: raw };
567
819
  }
820
+ if (compiled.protocol === "credential") {
821
+ if (typeof raw.description !== "string" || !raw.auth || !raw.materialize || typeof raw.materialize !== "object") {
822
+ throw new Error(`Credential connection ${compiled.name} must export description, auth, and materialize.`);
823
+ }
824
+ return { compiled, definition: raw };
825
+ }
568
826
  throw new Error(`Connection ${compiled.name} is declaration-only.`);
569
827
  }
570
828
  targetConnections(name) {
@@ -574,6 +832,18 @@ export class RuntimeConnectionRegistry {
574
832
  return !name || connection.name === name;
575
833
  });
576
834
  }
835
+ /**
836
+ * The single audience rule: personal (user-subject) connections exist only
837
+ * on private surfaces. Everything else — discovery, execution, pairing,
838
+ * and credential materialization — derives from this one predicate.
839
+ */
840
+ connectionAccessible(connection) {
841
+ const audience = this.options.audience ?? { private: true };
842
+ return audienceAllowsConnectionAccess(audience, connection.subject);
843
+ }
844
+ toolAllowed(connection) {
845
+ return isLiveConnection(connection) && this.connectionAccessible(connection);
846
+ }
577
847
  connectionFailure(connection, error) {
578
848
  if (isConnectionAuthorizationRequiredError(error)) {
579
849
  return {
@@ -605,14 +875,14 @@ export class RuntimeConnectionRegistry {
605
875
  if (cached && !isTokenExpired(cached.token))
606
876
  return cached.token;
607
877
  const connectionContext = { url: resolvedUrl ?? connection.url ?? "" };
608
- if (authorization.kind === "oauth") {
878
+ if (authorization.kind === "oauth" || authorization.kind === "interactive") {
609
879
  const stored = await this.grantStore.getGrant(connection.name, principalKey);
610
880
  if (stored && !storedGrantExpired(stored)) {
611
881
  const token = grantToTokenResult(stored);
612
882
  this.tokenCache.set(cacheKey, { token, authorization, principal, connection: connectionContext });
613
883
  return token;
614
884
  }
615
- if (stored?.refreshToken && authorization.oauth) {
885
+ if (stored?.refreshToken && authorization.kind === "oauth" && authorization.oauth) {
616
886
  const refreshed = await this.refreshOAuthGrant(authorization.oauth, connection.name, principal, principalKey, stored.refreshToken);
617
887
  // saveGrantFromToken preserved the credential bag on the grant; mirror
618
888
  // that on the returned token so template rendering sees it too.
@@ -621,7 +891,9 @@ export class RuntimeConnectionRegistry {
621
891
  this.tokenCache.set(cacheKey, { token: refreshed, authorization, principal, connection: connectionContext });
622
892
  return refreshed;
623
893
  }
624
- throw await this.createAuthorizationRequiredError(connection, authorization, principal, principalKey, context, connectionContext);
894
+ if (authorization.kind === "oauth") {
895
+ throw await this.createAuthorizationRequiredError(connection, authorization, principal, principalKey, context, connectionContext);
896
+ }
625
897
  }
626
898
  try {
627
899
  const token = await authorization.getToken({ principal, connection: connectionContext });
@@ -643,6 +915,7 @@ export class RuntimeConnectionRegistry {
643
915
  resolverContext() {
644
916
  return {
645
917
  env: this.options.env,
918
+ fetch: this.options.fetch,
646
919
  session: this.options.session
647
920
  };
648
921
  }
@@ -719,7 +992,7 @@ export class RuntimeConnectionRegistry {
719
992
  challenge = buildOAuthChallenge(authorization.oauth, oauthChallengeOptions);
720
993
  }
721
994
  else if (authorization.startAuthorization) {
722
- const started = await authorization.startAuthorization({ principal, connection: connectionContext, callbackUrl });
995
+ const started = await authorization.startAuthorization({ principal, connection: connectionContext, callbackUrl, state });
723
996
  challenge = started.challenge;
724
997
  resume = started.resume;
725
998
  if (!challenge.url && cause?.challenge?.url)
@@ -769,7 +1042,7 @@ export class RuntimeConnectionRegistry {
769
1042
  return new ConnectionAuthorizationRequiredError(connection.name, errorOptions);
770
1043
  }
771
1044
  callbackUrl() {
772
- const base = (this.options.callbackBaseUrl ?? this.options.env.OPENEVE_PUBLIC_URL ?? "http://localhost").replace(/\/+$/u, "");
1045
+ const base = (this.options.callbackBaseUrl ?? this.options.env.ASSEMBLY_LINE_PUBLIC_URL ?? "http://localhost").replace(/\/+$/u, "");
773
1046
  return `${base}/assembly-line/connections/callback`;
774
1047
  }
775
1048
  async exchangeOAuthAuthorizationCode(oauth, session, callback) {
@@ -796,9 +1069,21 @@ export class RuntimeConnectionRegistry {
796
1069
  }
797
1070
  async requestOAuthToken(oauth, fields) {
798
1071
  const body = new URLSearchParams();
799
- body.set("client_id", oauth.clientId);
800
- if (oauth.clientSecret)
801
- body.set("client_secret", oauth.clientSecret);
1072
+ const headers = {
1073
+ accept: "application/json",
1074
+ "content-type": "application/x-www-form-urlencoded"
1075
+ };
1076
+ if (oauth.tokenEndpointAuthMethod === "client_secret_basic") {
1077
+ if (!oauth.clientSecret) {
1078
+ throw new ConnectionAuthorizationFailedError("oauth", { reason: "missing_client_secret" });
1079
+ }
1080
+ headers.authorization = `Basic ${Buffer.from(`${oauth.clientId}:${oauth.clientSecret}`).toString("base64")}`;
1081
+ }
1082
+ else {
1083
+ body.set("client_id", oauth.clientId);
1084
+ if (oauth.clientSecret)
1085
+ body.set("client_secret", oauth.clientSecret);
1086
+ }
802
1087
  for (const [key, value] of Object.entries(oauth.tokenParams ?? {}))
803
1088
  body.set(key, value);
804
1089
  for (const [key, value] of Object.entries(fields)) {
@@ -807,10 +1092,7 @@ export class RuntimeConnectionRegistry {
807
1092
  }
808
1093
  const response = await this.request(oauth.tokenUrl, {
809
1094
  method: "POST",
810
- headers: {
811
- accept: "application/json",
812
- "content-type": "application/x-www-form-urlencoded"
813
- },
1095
+ headers,
814
1096
  body
815
1097
  });
816
1098
  const payload = await readResponseBody(response);
@@ -879,4 +1161,11 @@ export class RuntimeConnectionRegistry {
879
1161
  await this.grantStore.saveGrant(grant);
880
1162
  }
881
1163
  }
1164
+ function sandboxCredentialWasRequested(run, connectionName) {
1165
+ const requests = run?.input.sandboxCredentials;
1166
+ return Boolean(requests
1167
+ && typeof requests === "object"
1168
+ && !Array.isArray(requests)
1169
+ && Object.prototype.hasOwnProperty.call(requests, connectionName));
1170
+ }
882
1171
  //# sourceMappingURL=connections.js.map