@amodalai/runtime 0.1.26 → 0.2.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 (347) hide show
  1. package/dist/src/__fixtures__/README.md +84 -0
  2. package/dist/src/__fixtures__/smoke-agent/amodal.json +11 -0
  3. package/dist/src/__fixtures__/smoke-agent/automations/test-auto.md +5 -0
  4. package/dist/src/__fixtures__/smoke-agent/connections/mock-api/access.json +11 -0
  5. package/dist/src/__fixtures__/smoke-agent/connections/mock-api/spec.json +4 -0
  6. package/dist/src/__fixtures__/smoke-agent/connections/mock-api/surface.md +9 -0
  7. package/dist/src/__fixtures__/smoke-agent/connections/mock-mcp/access.json +3 -0
  8. package/dist/src/__fixtures__/smoke-agent/connections/mock-mcp/spec.json +8 -0
  9. package/dist/src/__fixtures__/smoke-agent/evals/basic-eval.md +12 -0
  10. package/dist/src/__fixtures__/smoke-agent/knowledge/test-knowledge.md +3 -0
  11. package/dist/src/__fixtures__/smoke-agent/skills/test-skill/SKILL.md +11 -0
  12. package/dist/src/__fixtures__/smoke-agent/stores/test-items.json +11 -0
  13. package/dist/src/__fixtures__/smoke-agent/tools/echo_tool/handler.d.ts +18 -0
  14. package/dist/src/__fixtures__/smoke-agent/tools/echo_tool/handler.js +22 -0
  15. package/dist/src/__fixtures__/smoke-agent/tools/echo_tool/handler.js.map +1 -0
  16. package/dist/src/__fixtures__/smoke-agent/tools/echo_tool/tool.json +17 -0
  17. package/dist/src/__fixtures__/smoke.test.js +718 -0
  18. package/dist/src/__fixtures__/smoke.test.js.map +1 -0
  19. package/dist/src/__tests__/test-providers.d.ts +40 -0
  20. package/dist/src/__tests__/test-providers.js +61 -0
  21. package/dist/src/__tests__/test-providers.js.map +1 -0
  22. package/dist/src/agent/local-server.d.ts +3 -3
  23. package/dist/src/agent/local-server.js +213 -122
  24. package/dist/src/agent/local-server.js.map +1 -1
  25. package/dist/src/agent/loop-types.d.ts +175 -0
  26. package/dist/src/agent/loop-types.js +20 -0
  27. package/dist/src/agent/loop-types.js.map +1 -0
  28. package/dist/src/agent/loop.d.ts +31 -0
  29. package/dist/src/agent/loop.js +139 -0
  30. package/dist/src/agent/loop.js.map +1 -0
  31. package/dist/src/agent/loop.test.js +1030 -0
  32. package/dist/src/agent/loop.test.js.map +1 -0
  33. package/dist/src/agent/mcp-config.d.ts +28 -0
  34. package/dist/src/agent/mcp-config.js +57 -0
  35. package/dist/src/agent/mcp-config.js.map +1 -0
  36. package/dist/src/agent/page-builder.js +6 -1
  37. package/dist/src/agent/page-builder.js.map +1 -1
  38. package/dist/src/agent/proactive/proactive-runner.d.ts +24 -8
  39. package/dist/src/agent/proactive/proactive-runner.js +30 -32
  40. package/dist/src/agent/proactive/proactive-runner.js.map +1 -1
  41. package/dist/src/agent/proactive/proactive-runner.test.d.ts +1 -1
  42. package/dist/src/agent/proactive/proactive-runner.test.js +75 -87
  43. package/dist/src/agent/proactive/proactive-runner.test.js.map +1 -1
  44. package/dist/src/agent/routes/admin-chat.d.ts +15 -3
  45. package/dist/src/agent/routes/admin-chat.js +63 -18
  46. package/dist/src/agent/routes/admin-chat.js.map +1 -1
  47. package/dist/src/agent/routes/automations.js +5 -6
  48. package/dist/src/agent/routes/automations.js.map +1 -1
  49. package/dist/src/agent/routes/evals.d.ts +3 -2
  50. package/dist/src/agent/routes/evals.js +25 -12
  51. package/dist/src/agent/routes/evals.js.map +1 -1
  52. package/dist/src/agent/routes/files.js +7 -9
  53. package/dist/src/agent/routes/files.js.map +1 -1
  54. package/dist/src/agent/routes/inspect.d.ts +6 -2
  55. package/dist/src/agent/routes/inspect.js +31 -17
  56. package/dist/src/agent/routes/inspect.js.map +1 -1
  57. package/dist/src/agent/routes/inspect.test.js +18 -42
  58. package/dist/src/agent/routes/inspect.test.js.map +1 -1
  59. package/dist/src/agent/routes/stores.js +9 -12
  60. package/dist/src/agent/routes/stores.js.map +1 -1
  61. package/dist/src/agent/routes/task.d.ts +15 -3
  62. package/dist/src/agent/routes/task.js +16 -7
  63. package/dist/src/agent/routes/task.js.map +1 -1
  64. package/dist/src/agent/routes/task.test.d.ts +1 -1
  65. package/dist/src/agent/routes/task.test.js +70 -53
  66. package/dist/src/agent/routes/task.test.js.map +1 -1
  67. package/dist/src/agent/routes/webhooks.js +12 -3
  68. package/dist/src/agent/routes/webhooks.js.map +1 -1
  69. package/dist/src/agent/session-store.d.ts +11 -2
  70. package/dist/src/agent/session-store.js +1 -1
  71. package/dist/src/agent/session-store.js.map +1 -1
  72. package/dist/src/agent/snapshot-server.d.ts +2 -22
  73. package/dist/src/agent/snapshot-server.js +50 -27
  74. package/dist/src/agent/snapshot-server.js.map +1 -1
  75. package/dist/src/agent/states/compacting.d.ts +14 -0
  76. package/dist/src/agent/states/compacting.js +258 -0
  77. package/dist/src/agent/states/compacting.js.map +1 -0
  78. package/dist/src/agent/states/confirming.d.ts +10 -0
  79. package/dist/src/agent/states/confirming.js +76 -0
  80. package/dist/src/agent/states/confirming.js.map +1 -0
  81. package/dist/src/agent/states/dispatching.d.ts +18 -0
  82. package/dist/src/agent/states/dispatching.js +241 -0
  83. package/dist/src/agent/states/dispatching.js.map +1 -0
  84. package/dist/src/agent/states/executing.d.ts +21 -0
  85. package/dist/src/agent/states/executing.js +308 -0
  86. package/dist/src/agent/states/executing.js.map +1 -0
  87. package/dist/src/agent/states/streaming.d.ts +10 -0
  88. package/dist/src/agent/states/streaming.js +155 -0
  89. package/dist/src/agent/states/streaming.js.map +1 -0
  90. package/dist/src/agent/states/thinking.d.ts +13 -0
  91. package/dist/src/agent/states/thinking.js +233 -0
  92. package/dist/src/agent/states/thinking.js.map +1 -0
  93. package/dist/src/agent/token-estimate.d.ts +17 -0
  94. package/dist/src/agent/token-estimate.js +13 -0
  95. package/dist/src/agent/token-estimate.js.map +1 -0
  96. package/dist/src/agent/tool-executor-local.js +9 -18
  97. package/dist/src/agent/tool-executor-local.js.map +1 -1
  98. package/dist/src/agent/tool-executor-local.test.js +3 -5
  99. package/dist/src/agent/tool-executor-local.test.js.map +1 -1
  100. package/dist/src/api/create-agent.d.ts +15 -0
  101. package/dist/src/api/create-agent.js +137 -0
  102. package/dist/src/api/create-agent.js.map +1 -0
  103. package/dist/src/api/types.d.ts +68 -0
  104. package/dist/src/api/types.js +7 -0
  105. package/dist/src/api/types.js.map +1 -0
  106. package/dist/src/context/compiler.d.ts +13 -0
  107. package/dist/src/context/compiler.js +358 -0
  108. package/dist/src/context/compiler.js.map +1 -0
  109. package/dist/src/context/compiler.test.js +532 -0
  110. package/dist/src/context/compiler.test.js.map +1 -0
  111. package/dist/src/context/types.d.ts +110 -0
  112. package/dist/src/context/types.js +7 -0
  113. package/dist/src/context/types.js.map +1 -0
  114. package/dist/src/index.d.ts +33 -6
  115. package/dist/src/index.js +35 -21
  116. package/dist/src/index.js.map +1 -1
  117. package/dist/src/providers/create-provider.d.ts +23 -0
  118. package/dist/src/providers/create-provider.js +185 -0
  119. package/dist/src/providers/create-provider.js.map +1 -0
  120. package/dist/src/{agent/stores-e2e.test.d.ts → providers/create-provider.test.d.ts} +1 -1
  121. package/dist/src/providers/create-provider.test.js +95 -0
  122. package/dist/src/providers/create-provider.test.js.map +1 -0
  123. package/dist/src/providers/failover.d.ts +38 -0
  124. package/dist/src/providers/failover.js +147 -0
  125. package/dist/src/providers/failover.js.map +1 -0
  126. package/dist/src/providers/failover.test.d.ts +6 -0
  127. package/dist/src/providers/failover.test.js +169 -0
  128. package/dist/src/providers/failover.test.js.map +1 -0
  129. package/dist/src/providers/types.d.ts +110 -0
  130. package/dist/src/providers/types.js +7 -0
  131. package/dist/src/providers/types.js.map +1 -0
  132. package/dist/src/routes/ai-stream.d.ts +13 -10
  133. package/dist/src/routes/ai-stream.js +76 -41
  134. package/dist/src/routes/ai-stream.js.map +1 -1
  135. package/dist/src/routes/chat-new.test.d.ts +6 -0
  136. package/dist/src/routes/chat-new.test.js +107 -0
  137. package/dist/src/routes/chat-new.test.js.map +1 -0
  138. package/dist/src/routes/chat-stream-new.test.d.ts +6 -0
  139. package/dist/src/routes/chat-stream-new.test.js +135 -0
  140. package/dist/src/routes/chat-stream-new.test.js.map +1 -0
  141. package/dist/src/routes/chat-stream.d.ts +14 -4
  142. package/dist/src/routes/chat-stream.js +47 -29
  143. package/dist/src/routes/chat-stream.js.map +1 -1
  144. package/dist/src/routes/chat.d.ts +13 -4
  145. package/dist/src/routes/chat.js +60 -23
  146. package/dist/src/routes/chat.js.map +1 -1
  147. package/dist/src/routes/health.d.ts +3 -2
  148. package/dist/src/routes/health.js.map +1 -1
  149. package/dist/src/routes/route-helpers.d.ts +50 -0
  150. package/dist/src/routes/route-helpers.js +80 -0
  151. package/dist/src/routes/route-helpers.js.map +1 -0
  152. package/dist/src/routes/session-resolver.d.ts +72 -0
  153. package/dist/src/routes/session-resolver.js +123 -0
  154. package/dist/src/routes/session-resolver.js.map +1 -0
  155. package/dist/src/routes/session-resolver.test.d.ts +6 -0
  156. package/dist/src/routes/session-resolver.test.js +206 -0
  157. package/dist/src/routes/session-resolver.test.js.map +1 -0
  158. package/dist/src/routes/webhooks.d.ts +3 -1
  159. package/dist/src/routes/webhooks.js +12 -4
  160. package/dist/src/routes/webhooks.js.map +1 -1
  161. package/dist/src/security/permission-checker.d.ts +80 -0
  162. package/dist/src/security/permission-checker.js +75 -0
  163. package/dist/src/security/permission-checker.js.map +1 -0
  164. package/dist/src/security/permission-checker.test.d.ts +6 -0
  165. package/dist/src/security/permission-checker.test.js +208 -0
  166. package/dist/src/security/permission-checker.test.js.map +1 -0
  167. package/dist/src/server.d.ts +12 -11
  168. package/dist/src/server.js +44 -46
  169. package/dist/src/server.js.map +1 -1
  170. package/dist/src/server.test.d.ts +1 -1
  171. package/dist/src/server.test.js +6 -144
  172. package/dist/src/server.test.js.map +1 -1
  173. package/dist/src/session/manager.d.ts +98 -0
  174. package/dist/src/session/manager.js +364 -0
  175. package/dist/src/session/manager.js.map +1 -0
  176. package/dist/src/session/manager.test.d.ts +6 -0
  177. package/dist/src/session/manager.test.js +315 -0
  178. package/dist/src/session/manager.test.js.map +1 -0
  179. package/dist/src/session/session-builder.d.ts +71 -0
  180. package/dist/src/session/session-builder.js +364 -0
  181. package/dist/src/session/session-builder.js.map +1 -0
  182. package/dist/src/session/session-builder.test.d.ts +6 -0
  183. package/dist/src/session/session-builder.test.js +352 -0
  184. package/dist/src/session/session-builder.test.js.map +1 -0
  185. package/dist/src/session/store.d.ts +57 -0
  186. package/dist/src/session/store.js +167 -0
  187. package/dist/src/session/store.js.map +1 -0
  188. package/dist/src/session/store.test.d.ts +6 -0
  189. package/dist/src/session/store.test.js +145 -0
  190. package/dist/src/session/store.test.js.map +1 -0
  191. package/dist/src/session/stream-hooks.d.ts +39 -0
  192. package/dist/src/session/stream-hooks.js +7 -0
  193. package/dist/src/session/stream-hooks.js.map +1 -0
  194. package/dist/src/session/tool-context-factory.d.ts +60 -0
  195. package/dist/src/session/tool-context-factory.js +190 -0
  196. package/dist/src/session/tool-context-factory.js.map +1 -0
  197. package/dist/src/session/tool-context-factory.test.d.ts +6 -0
  198. package/dist/src/session/tool-context-factory.test.js +287 -0
  199. package/dist/src/session/tool-context-factory.test.js.map +1 -0
  200. package/dist/src/session/types.d.ts +188 -0
  201. package/dist/src/session/types.js +7 -0
  202. package/dist/src/session/types.js.map +1 -0
  203. package/dist/src/stores/drizzle-store-backend.d.ts +49 -0
  204. package/dist/src/stores/drizzle-store-backend.js +306 -0
  205. package/dist/src/stores/drizzle-store-backend.js.map +1 -0
  206. package/dist/src/stores/drizzle-store-backend.test.d.ts +6 -0
  207. package/dist/src/stores/drizzle-store-backend.test.js +215 -0
  208. package/dist/src/stores/drizzle-store-backend.test.js.map +1 -0
  209. package/dist/src/stores/index.d.ts +4 -0
  210. package/dist/src/stores/index.js +2 -0
  211. package/dist/src/stores/index.js.map +1 -1
  212. package/dist/src/stores/pglite-store-backend.d.ts +16 -19
  213. package/dist/src/stores/pglite-store-backend.js +85 -239
  214. package/dist/src/stores/pglite-store-backend.js.map +1 -1
  215. package/dist/src/stores/postgres-store-backend.d.ts +30 -0
  216. package/dist/src/stores/postgres-store-backend.js +100 -0
  217. package/dist/src/stores/postgres-store-backend.js.map +1 -0
  218. package/dist/src/stores/schema.d.ts +491 -0
  219. package/dist/src/stores/schema.js +57 -0
  220. package/dist/src/stores/schema.js.map +1 -0
  221. package/dist/src/tools/admin-file-tools.d.ts +13 -0
  222. package/dist/src/tools/admin-file-tools.js +200 -0
  223. package/dist/src/tools/admin-file-tools.js.map +1 -0
  224. package/dist/src/tools/admin-file-tools.test.d.ts +6 -0
  225. package/dist/src/tools/admin-file-tools.test.js +152 -0
  226. package/dist/src/tools/admin-file-tools.test.js.map +1 -0
  227. package/dist/src/tools/custom-tool-adapter.d.ts +41 -0
  228. package/dist/src/tools/custom-tool-adapter.js +190 -0
  229. package/dist/src/tools/custom-tool-adapter.js.map +1 -0
  230. package/dist/src/tools/custom-tool-adapter.test.d.ts +6 -0
  231. package/dist/src/tools/custom-tool-adapter.test.js +244 -0
  232. package/dist/src/tools/custom-tool-adapter.test.js.map +1 -0
  233. package/dist/src/tools/dispatch-tool.d.ts +52 -0
  234. package/dist/src/tools/dispatch-tool.js +71 -0
  235. package/dist/src/tools/dispatch-tool.js.map +1 -0
  236. package/dist/src/tools/dispatch-tool.test.d.ts +6 -0
  237. package/dist/src/tools/dispatch-tool.test.js +75 -0
  238. package/dist/src/tools/dispatch-tool.test.js.map +1 -0
  239. package/dist/src/tools/mcp-tool-adapter.d.ts +18 -0
  240. package/dist/src/tools/mcp-tool-adapter.js +135 -0
  241. package/dist/src/tools/mcp-tool-adapter.js.map +1 -0
  242. package/dist/src/tools/mcp-tool-adapter.test.d.ts +6 -0
  243. package/dist/src/tools/mcp-tool-adapter.test.js +227 -0
  244. package/dist/src/tools/mcp-tool-adapter.test.js.map +1 -0
  245. package/dist/src/tools/registry.d.ts +25 -0
  246. package/dist/src/tools/registry.js +72 -0
  247. package/dist/src/tools/registry.js.map +1 -0
  248. package/dist/src/tools/registry.test.d.ts +6 -0
  249. package/dist/src/tools/registry.test.js +121 -0
  250. package/dist/src/tools/registry.test.js.map +1 -0
  251. package/dist/src/tools/request-tool.d.ts +42 -0
  252. package/dist/src/tools/request-tool.js +190 -0
  253. package/dist/src/tools/request-tool.js.map +1 -0
  254. package/dist/src/tools/request-tool.test.d.ts +6 -0
  255. package/dist/src/tools/request-tool.test.js +254 -0
  256. package/dist/src/tools/request-tool.test.js.map +1 -0
  257. package/dist/src/tools/store-tools.d.ts +29 -0
  258. package/dist/src/tools/store-tools.js +224 -0
  259. package/dist/src/tools/store-tools.js.map +1 -0
  260. package/dist/src/tools/store-tools.test.d.ts +6 -0
  261. package/dist/src/tools/store-tools.test.js +216 -0
  262. package/dist/src/tools/store-tools.test.js.map +1 -0
  263. package/dist/src/tools/types.d.ts +111 -0
  264. package/dist/src/tools/types.js +7 -0
  265. package/dist/src/tools/types.js.map +1 -0
  266. package/dist/src/types.d.ts +20 -12
  267. package/dist/src/types.js +3 -2
  268. package/dist/src/types.js.map +1 -1
  269. package/dist/tsconfig.tsbuildinfo +1 -1
  270. package/package.json +13 -4
  271. package/dist/src/__tests__/sse-contract.test.js +0 -464
  272. package/dist/src/__tests__/sse-contract.test.js.map +0 -1
  273. package/dist/src/__tests__/tools.test.js +0 -583
  274. package/dist/src/__tests__/tools.test.js.map +0 -1
  275. package/dist/src/agent/agent-runner.d.ts +0 -33
  276. package/dist/src/agent/agent-runner.js +0 -1040
  277. package/dist/src/agent/agent-runner.js.map +0 -1
  278. package/dist/src/agent/custom-tools-e2e.test.d.ts +0 -6
  279. package/dist/src/agent/custom-tools-e2e.test.js +0 -566
  280. package/dist/src/agent/custom-tools-e2e.test.js.map +0 -1
  281. package/dist/src/agent/request-helper.d.ts +0 -16
  282. package/dist/src/agent/request-helper.js +0 -96
  283. package/dist/src/agent/request-helper.js.map +0 -1
  284. package/dist/src/agent/stores-e2e.test.js +0 -433
  285. package/dist/src/agent/stores-e2e.test.js.map +0 -1
  286. package/dist/src/agent/tool-context-builder.d.ts +0 -11
  287. package/dist/src/agent/tool-context-builder.js +0 -102
  288. package/dist/src/agent/tool-context-builder.js.map +0 -1
  289. package/dist/src/agent/tool-context-builder.test.d.ts +0 -6
  290. package/dist/src/agent/tool-context-builder.test.js +0 -152
  291. package/dist/src/agent/tool-context-builder.test.js.map +0 -1
  292. package/dist/src/agent/write-repo-file.test.js +0 -270
  293. package/dist/src/agent/write-repo-file.test.js.map +0 -1
  294. package/dist/src/cron/heartbeat-runner.d.ts +0 -21
  295. package/dist/src/cron/heartbeat-runner.js +0 -79
  296. package/dist/src/cron/heartbeat-runner.js.map +0 -1
  297. package/dist/src/cron/heartbeat-runner.test.d.ts +0 -6
  298. package/dist/src/cron/heartbeat-runner.test.js +0 -120
  299. package/dist/src/cron/heartbeat-runner.test.js.map +0 -1
  300. package/dist/src/cron/heartbeat-scheduler.d.ts +0 -26
  301. package/dist/src/cron/heartbeat-scheduler.js +0 -55
  302. package/dist/src/cron/heartbeat-scheduler.js.map +0 -1
  303. package/dist/src/cron/heartbeat-scheduler.test.d.ts +0 -6
  304. package/dist/src/cron/heartbeat-scheduler.test.js +0 -61
  305. package/dist/src/cron/heartbeat-scheduler.test.js.map +0 -1
  306. package/dist/src/routes/ai-stream.test.d.ts +0 -6
  307. package/dist/src/routes/ai-stream.test.js +0 -586
  308. package/dist/src/routes/ai-stream.test.js.map +0 -1
  309. package/dist/src/routes/ask-user-response.d.ts +0 -30
  310. package/dist/src/routes/ask-user-response.js +0 -61
  311. package/dist/src/routes/ask-user-response.js.map +0 -1
  312. package/dist/src/routes/ask-user-response.test.d.ts +0 -6
  313. package/dist/src/routes/ask-user-response.test.js +0 -88
  314. package/dist/src/routes/ask-user-response.test.js.map +0 -1
  315. package/dist/src/routes/chat-stream.test.d.ts +0 -6
  316. package/dist/src/routes/chat-stream.test.js +0 -155
  317. package/dist/src/routes/chat-stream.test.js.map +0 -1
  318. package/dist/src/routes/chat.test.d.ts +0 -6
  319. package/dist/src/routes/chat.test.js +0 -99
  320. package/dist/src/routes/chat.test.js.map +0 -1
  321. package/dist/src/routes/widget-actions.d.ts +0 -49
  322. package/dist/src/routes/widget-actions.js +0 -78
  323. package/dist/src/routes/widget-actions.js.map +0 -1
  324. package/dist/src/session/custom-tool-adapter.d.ts +0 -74
  325. package/dist/src/session/custom-tool-adapter.js +0 -180
  326. package/dist/src/session/custom-tool-adapter.js.map +0 -1
  327. package/dist/src/session/history-converter.d.ts +0 -21
  328. package/dist/src/session/history-converter.js +0 -59
  329. package/dist/src/session/history-converter.js.map +0 -1
  330. package/dist/src/session/history-converter.test.d.ts +0 -6
  331. package/dist/src/session/history-converter.test.js +0 -130
  332. package/dist/src/session/history-converter.test.js.map +0 -1
  333. package/dist/src/session/session-manager.d.ts +0 -219
  334. package/dist/src/session/session-manager.js +0 -915
  335. package/dist/src/session/session-manager.js.map +0 -1
  336. package/dist/src/session/session-manager.test.d.ts +0 -6
  337. package/dist/src/session/session-manager.test.js +0 -455
  338. package/dist/src/session/session-manager.test.js.map +0 -1
  339. package/dist/src/session/session-runner.d.ts +0 -45
  340. package/dist/src/session/session-runner.js +0 -719
  341. package/dist/src/session/session-runner.js.map +0 -1
  342. package/dist/src/session/session-runner.test.d.ts +0 -6
  343. package/dist/src/session/session-runner.test.js +0 -834
  344. package/dist/src/session/session-runner.test.js.map +0 -1
  345. /package/dist/src/{__tests__/sse-contract.test.d.ts → __fixtures__/smoke.test.d.ts} +0 -0
  346. /package/dist/src/{__tests__/tools.test.d.ts → agent/loop.test.d.ts} +0 -0
  347. /package/dist/src/{agent/write-repo-file.test.d.ts → context/compiler.test.d.ts} +0 -0
@@ -0,0 +1,244 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
7
+ import { createCustomToolDefinition } from './custom-tool-adapter.js';
8
+ // ---------------------------------------------------------------------------
9
+ // Fixtures
10
+ // ---------------------------------------------------------------------------
11
+ function makeTool(overrides) {
12
+ return {
13
+ name: 'test_tool',
14
+ description: 'A test tool',
15
+ parameters: {
16
+ type: 'object',
17
+ properties: {
18
+ query: { type: 'string', description: 'Search query' },
19
+ limit: { type: 'number', description: 'Max results' },
20
+ },
21
+ required: ['query'],
22
+ },
23
+ confirm: true,
24
+ timeout: 30_000,
25
+ env: ['TEST_KEY'],
26
+ handlerPath: '/fake/handler.ts',
27
+ location: '/fake',
28
+ hasPackageJson: false,
29
+ hasSetupScript: false,
30
+ hasRequirementsTxt: false,
31
+ hasDockerfile: false,
32
+ sandboxLanguage: 'node',
33
+ ...overrides,
34
+ };
35
+ }
36
+ function makeExecutor(result = { ok: true }) {
37
+ return {
38
+ execute: vi.fn().mockResolvedValue(result),
39
+ };
40
+ }
41
+ function makeSessionCtx(overrides) {
42
+ return {
43
+ config: {
44
+ getConnections: () => ({
45
+ typefully: {
46
+ base_url: 'https://api.typefully.com',
47
+ _request_config: {
48
+ auth: [{ header: 'Authorization', value_template: 'Bearer tok-123' }],
49
+ default_headers: { 'X-Custom': 'yes' },
50
+ },
51
+ },
52
+ }),
53
+ getStores: () => [{
54
+ name: 'alerts',
55
+ entity: { key: '{alert_id}', schema: { alert_id: { type: 'string' } } },
56
+ }],
57
+ },
58
+ storeBackend: {
59
+ put: vi.fn().mockResolvedValue(undefined),
60
+ },
61
+ appId: 'test-app',
62
+ ...overrides,
63
+ };
64
+ }
65
+ function makeToolContext(overrides) {
66
+ return {
67
+ request: vi.fn(),
68
+ store: vi.fn(),
69
+ env: vi.fn(),
70
+ log: vi.fn(),
71
+ user: { roles: ['admin'] },
72
+ signal: AbortSignal.timeout(30_000),
73
+ sessionId: 'sess-1',
74
+ tenantId: 'tenant-1',
75
+ ...overrides,
76
+ };
77
+ }
78
+ // ---------------------------------------------------------------------------
79
+ // Tests
80
+ // ---------------------------------------------------------------------------
81
+ describe('createCustomToolDefinition', () => {
82
+ describe('schema', () => {
83
+ it('passes JSON Schema through to ToolDefinition parameters', () => {
84
+ const tool = makeTool();
85
+ const def = createCustomToolDefinition(tool, makeExecutor(), makeSessionCtx());
86
+ expect(def.description).toBe('A test tool');
87
+ // The jsonSchema() wrapper preserves the original schema
88
+ expect(def.parameters).toBeDefined();
89
+ });
90
+ it('sets readOnly: true when confirm is false', () => {
91
+ const def = createCustomToolDefinition(makeTool({ confirm: false }), makeExecutor(), makeSessionCtx());
92
+ expect(def.readOnly).toBe(true);
93
+ });
94
+ it('sets readOnly: false when confirm is true', () => {
95
+ const def = createCustomToolDefinition(makeTool({ confirm: true }), makeExecutor(), makeSessionCtx());
96
+ expect(def.readOnly).toBe(false);
97
+ });
98
+ it('sets metadata.category to custom', () => {
99
+ const def = createCustomToolDefinition(makeTool(), makeExecutor(), makeSessionCtx());
100
+ expect(def.metadata?.category).toBe('custom');
101
+ });
102
+ });
103
+ describe('execute', () => {
104
+ it('calls executor with tool, params, and context', async () => {
105
+ const executor = makeExecutor({ result: 42 });
106
+ const def = createCustomToolDefinition(makeTool(), executor, makeSessionCtx());
107
+ const ctx = makeToolContext();
108
+ const result = await def.execute({ query: 'test' }, ctx);
109
+ expect(executor.execute).toHaveBeenCalledOnce();
110
+ expect(result).toEqual({ result: 42 });
111
+ });
112
+ it('wraps executor errors in ToolExecutionError', async () => {
113
+ const executor = {
114
+ execute: vi.fn().mockRejectedValue(new Error('handler crashed')),
115
+ };
116
+ const def = createCustomToolDefinition(makeTool(), executor, makeSessionCtx());
117
+ await expect(def.execute({ query: 'test' }, makeToolContext()))
118
+ .rejects.toThrow('Tool "test_tool" failed: handler crashed');
119
+ });
120
+ it('wraps AbortError as abort-specific message', async () => {
121
+ const abortErr = new Error('aborted');
122
+ abortErr.name = 'AbortError';
123
+ const executor = {
124
+ execute: vi.fn().mockRejectedValue(abortErr),
125
+ };
126
+ const def = createCustomToolDefinition(makeTool(), executor, makeSessionCtx());
127
+ await expect(def.execute({ query: 'test' }, makeToolContext()))
128
+ .rejects.toThrow('Tool "test_tool" was aborted');
129
+ });
130
+ });
131
+ describe('ctx.request()', () => {
132
+ let fetchSpy;
133
+ beforeEach(() => {
134
+ fetchSpy = vi.fn().mockResolvedValue({
135
+ ok: true,
136
+ status: 200,
137
+ text: () => Promise.resolve('{"data": "ok"}'),
138
+ });
139
+ vi.stubGlobal('fetch', fetchSpy);
140
+ });
141
+ it('applies auth headers from connection config', async () => {
142
+ const executor = {
143
+ execute: vi.fn().mockImplementation(async (_tool, _params, ctx) => {
144
+ const result = await ctx.request('typefully', '/social-sets');
145
+ return result;
146
+ }),
147
+ };
148
+ const def = createCustomToolDefinition(makeTool(), executor, makeSessionCtx());
149
+ await def.execute({}, makeToolContext());
150
+ expect(fetchSpy).toHaveBeenCalledOnce();
151
+ const [url, opts] = fetchSpy.mock.calls[0];
152
+ expect(url).toBe('https://api.typefully.com/social-sets');
153
+ expect(opts.headers['Authorization']).toBe('Bearer tok-123');
154
+ expect(opts.headers['X-Custom']).toBe('yes');
155
+ });
156
+ it('throws on unknown connection', async () => {
157
+ const executor = {
158
+ execute: vi.fn().mockImplementation(async (_tool, _params, ctx) => {
159
+ await ctx.request('nonexistent', '/foo');
160
+ }),
161
+ };
162
+ const def = createCustomToolDefinition(makeTool(), executor, makeSessionCtx());
163
+ await expect(def.execute({}, makeToolContext()))
164
+ .rejects.toThrow('Connection "nonexistent" not found');
165
+ });
166
+ it('rejects non-GET when confirm is false', async () => {
167
+ const executor = {
168
+ execute: vi.fn().mockImplementation(async (_tool, _params, ctx) => {
169
+ await ctx
170
+ .request('typefully', '/post', { method: 'POST' });
171
+ }),
172
+ };
173
+ const def = createCustomToolDefinition(makeTool({ confirm: false }), executor, makeSessionCtx());
174
+ await expect(def.execute({}, makeToolContext()))
175
+ .rejects.toThrow('only GET requests are allowed');
176
+ });
177
+ it('throws on non-2xx responses', async () => {
178
+ fetchSpy.mockResolvedValue({
179
+ ok: false,
180
+ status: 401,
181
+ text: () => Promise.resolve('Unauthorized'),
182
+ });
183
+ const executor = {
184
+ execute: vi.fn().mockImplementation(async (_tool, _params, ctx) => {
185
+ await ctx.request('typefully', '/social-sets');
186
+ }),
187
+ };
188
+ const def = createCustomToolDefinition(makeTool(), executor, makeSessionCtx());
189
+ await expect(def.execute({}, makeToolContext()))
190
+ .rejects.toThrow('returned 401');
191
+ });
192
+ });
193
+ describe('ctx.store()', () => {
194
+ it('writes to store backend with resolved key', async () => {
195
+ const sessionCtx = makeSessionCtx();
196
+ const executor = {
197
+ execute: vi.fn().mockImplementation(async (_tool, _params, ctx) => ctx
198
+ .store('alerts', { alert_id: 'a-1', severity: 'high' })),
199
+ };
200
+ const def = createCustomToolDefinition(makeTool(), executor, sessionCtx);
201
+ const result = await def.execute({}, makeToolContext());
202
+ expect(sessionCtx.storeBackend?.put).toHaveBeenCalledWith('test-app', 'alerts', 'a-1', { alert_id: 'a-1', severity: 'high' }, {});
203
+ expect(result).toEqual({ key: 'a-1' });
204
+ });
205
+ it('throws when store backend is not available', async () => {
206
+ const executor = {
207
+ execute: vi.fn().mockImplementation(async (_tool, _params, ctx) => ctx
208
+ .store('alerts', { alert_id: 'a-1' })),
209
+ };
210
+ const def = createCustomToolDefinition(makeTool(), executor, makeSessionCtx({ storeBackend: undefined }));
211
+ await expect(def.execute({}, makeToolContext()))
212
+ .rejects.toThrow('Store backend not available');
213
+ });
214
+ });
215
+ describe('ctx.env()', () => {
216
+ it('returns env var when in allowlist', async () => {
217
+ vi.stubEnv('TEST_KEY', 'secret-value');
218
+ let envResult;
219
+ const executor = {
220
+ execute: vi.fn().mockImplementation(async (_tool, _params, ctx) => {
221
+ envResult = ctx.env('TEST_KEY');
222
+ return { ok: true };
223
+ }),
224
+ };
225
+ const def = createCustomToolDefinition(makeTool(), executor, makeSessionCtx());
226
+ await def.execute({}, makeToolContext());
227
+ expect(envResult).toBe('secret-value');
228
+ vi.unstubAllEnvs();
229
+ });
230
+ it('returns undefined for non-allowlisted env var', async () => {
231
+ let envResult = 'should-be-overwritten';
232
+ const executor = {
233
+ execute: vi.fn().mockImplementation(async (_tool, _params, ctx) => {
234
+ envResult = ctx.env('HOME');
235
+ return { ok: true };
236
+ }),
237
+ };
238
+ const def = createCustomToolDefinition(makeTool(), executor, makeSessionCtx());
239
+ await def.execute({}, makeToolContext());
240
+ expect(envResult).toBeUndefined();
241
+ });
242
+ });
243
+ });
244
+ //# sourceMappingURL=custom-tool-adapter.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"custom-tool-adapter.test.js","sourceRoot":"","sources":["../../../src/tools/custom-tool-adapter.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ /**
7
+ * Dispatch tool.
8
+ *
9
+ * Allows the model to delegate a sub-task to a child agent with a
10
+ * subset of tools. The EXECUTING state handler intercepts this tool
11
+ * by name and transitions to DISPATCHING — the execute() function
12
+ * here is a safety net that should never be reached.
13
+ *
14
+ * Circular dependency avoidance: this file does NOT import from
15
+ * the agent loop. The dispatch tool is just a schema definition.
16
+ * The actual child agent execution lives in states/dispatching.ts.
17
+ */
18
+ import { z } from 'zod';
19
+ import type { ToolDefinition } from './types.js';
20
+ export declare const DISPATCH_TOOL_NAME = "dispatch_task";
21
+ declare const DEFAULT_CHILD_MAX_TURNS = 10;
22
+ declare const DispatchParamsSchema: z.ZodObject<{
23
+ /** Name for the child agent (used in SSE events and logging) */
24
+ agent_name: z.ZodString;
25
+ /** Which tools the child agent can use (must be a subset of available tools) */
26
+ tools: z.ZodArray<z.ZodString, "many">;
27
+ /** The task prompt for the child agent */
28
+ prompt: z.ZodString;
29
+ /** Max turns for the child agent (default: 10) */
30
+ max_turns: z.ZodOptional<z.ZodNumber>;
31
+ }, "strip", z.ZodTypeAny, {
32
+ agent_name: string;
33
+ tools: string[];
34
+ prompt: string;
35
+ max_turns?: number | undefined;
36
+ }, {
37
+ agent_name: string;
38
+ tools: string[];
39
+ prompt: string;
40
+ max_turns?: number | undefined;
41
+ }>;
42
+ export type DispatchParams = z.infer<typeof DispatchParamsSchema>;
43
+ /**
44
+ * Create the dispatch_task tool definition.
45
+ *
46
+ * The tool is intercepted by the EXECUTING state handler before execute()
47
+ * is called. The EXECUTING handler reads the args, strips dispatch_task
48
+ * from the child's tool list (preventing recursion), and transitions to
49
+ * DISPATCHING state.
50
+ */
51
+ export declare function createDispatchTool(): ToolDefinition;
52
+ export { DEFAULT_CHILD_MAX_TURNS };
@@ -0,0 +1,71 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ /**
7
+ * Dispatch tool.
8
+ *
9
+ * Allows the model to delegate a sub-task to a child agent with a
10
+ * subset of tools. The EXECUTING state handler intercepts this tool
11
+ * by name and transitions to DISPATCHING — the execute() function
12
+ * here is a safety net that should never be reached.
13
+ *
14
+ * Circular dependency avoidance: this file does NOT import from
15
+ * the agent loop. The dispatch tool is just a schema definition.
16
+ * The actual child agent execution lives in states/dispatching.ts.
17
+ */
18
+ import { z } from 'zod';
19
+ import { ToolExecutionError } from '../errors.js';
20
+ // ---------------------------------------------------------------------------
21
+ // Constants
22
+ // ---------------------------------------------------------------------------
23
+ export const DISPATCH_TOOL_NAME = 'dispatch_task';
24
+ const DEFAULT_CHILD_MAX_TURNS = 10;
25
+ // ---------------------------------------------------------------------------
26
+ // Schema
27
+ // ---------------------------------------------------------------------------
28
+ const DispatchParamsSchema = z.object({
29
+ /** Name for the child agent (used in SSE events and logging) */
30
+ agent_name: z.string().describe('A short descriptive name for the sub-agent (e.g. "data-fetcher", "entity-profiler")'),
31
+ /** Which tools the child agent can use (must be a subset of available tools) */
32
+ tools: z.array(z.string()).describe('List of tool names the child agent can use'),
33
+ /** The task prompt for the child agent */
34
+ prompt: z.string().describe('The task description for the child agent to complete'),
35
+ /** Max turns for the child agent (default: 10) */
36
+ max_turns: z.number().int().positive().optional().describe('Maximum number of LLM turns the child agent can take'),
37
+ });
38
+ // ---------------------------------------------------------------------------
39
+ // Tool definition
40
+ // ---------------------------------------------------------------------------
41
+ /**
42
+ * Create the dispatch_task tool definition.
43
+ *
44
+ * The tool is intercepted by the EXECUTING state handler before execute()
45
+ * is called. The EXECUTING handler reads the args, strips dispatch_task
46
+ * from the child's tool list (preventing recursion), and transitions to
47
+ * DISPATCHING state.
48
+ */
49
+ export function createDispatchTool() {
50
+ return {
51
+ description: `Delegate a sub-task to a child agent that runs independently with its own tool set. Use this when a task can be broken into parallel or sequential sub-tasks, each requiring specific tools. The child agent completes its task and returns a text summary.
52
+
53
+ The child agent has access only to the tools you specify — choose the minimum set needed. The child cannot dispatch further sub-agents.
54
+
55
+ Use dispatch_task when:
56
+ - A task involves multiple independent data-gathering steps
57
+ - You need to query different connections in parallel
58
+ - A sub-task is self-contained and doesn't need conversation context`,
59
+ parameters: DispatchParamsSchema,
60
+ readOnly: false,
61
+ metadata: { category: 'system' },
62
+ async execute() {
63
+ // The EXECUTING state handler intercepts dispatch_task by name and
64
+ // transitions to DISPATCHING. If execute() is called directly, the
65
+ // interception was bypassed — this is a bug.
66
+ throw new ToolExecutionError('dispatch_task must be intercepted by the EXECUTING state handler — direct execution is not supported', { toolName: DISPATCH_TOOL_NAME, callId: 'unknown', context: {} });
67
+ },
68
+ };
69
+ }
70
+ export { DEFAULT_CHILD_MAX_TURNS };
71
+ //# sourceMappingURL=dispatch-tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatch-tool.js","sourceRoot":"","sources":["../../../src/tools/dispatch-tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;;GAWG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,OAAO,EAAC,kBAAkB,EAAC,MAAM,cAAc,CAAC;AAEhD,8EAA8E;AAC9E,YAAY;AACZ,8EAA8E;AAE9E,MAAM,CAAC,MAAM,kBAAkB,GAAG,eAAe,CAAC;AAElD,MAAM,uBAAuB,GAAG,EAAE,CAAC;AAEnC,8EAA8E;AAC9E,SAAS;AACT,8EAA8E;AAE9E,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,gEAAgE;IAChE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,qFAAqF,CAAC;IACtH,gFAAgF;IAChF,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,4CAA4C,CAAC;IACjF,0CAA0C;IAC1C,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sDAAsD,CAAC;IACnF,kDAAkD;IAClD,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,sDAAsD,CAAC;CACnH,CAAC,CAAC;AAIH,8EAA8E;AAC9E,kBAAkB;AAClB,8EAA8E;AAE9E;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB;IAChC,OAAO;QACL,WAAW,EAAE;;;;;;;qEAOoD;QAEjE,UAAU,EAAE,oBAAoB;QAEhC,QAAQ,EAAE,KAAK;QACf,QAAQ,EAAE,EAAC,QAAQ,EAAE,QAAQ,EAAC;QAE9B,KAAK,CAAC,OAAO;YACX,mEAAmE;YACnE,mEAAmE;YACnE,6CAA6C;YAC7C,MAAM,IAAI,kBAAkB,CAC1B,sGAAsG,EACtG,EAAC,QAAQ,EAAE,kBAAkB,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,EAAC,CAC/D,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC;AAED,OAAO,EAAC,uBAAuB,EAAC,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ export {};
@@ -0,0 +1,75 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ import { describe, it, expect } from 'vitest';
7
+ import { createDispatchTool, DISPATCH_TOOL_NAME, DEFAULT_CHILD_MAX_TURNS } from './dispatch-tool.js';
8
+ import { ToolExecutionError } from '../errors.js';
9
+ describe('dispatch-tool', () => {
10
+ it('has the correct tool name constant', () => {
11
+ expect(DISPATCH_TOOL_NAME).toBe('dispatch_task');
12
+ });
13
+ it('has a sensible default child max turns', () => {
14
+ expect(DEFAULT_CHILD_MAX_TURNS).toBe(10);
15
+ });
16
+ it('creates a tool definition with Zod schema', () => {
17
+ const tool = createDispatchTool();
18
+ expect(tool.description).toContain('child agent');
19
+ expect(tool.readOnly).toBe(false);
20
+ expect(tool.metadata?.category).toBe('system');
21
+ // Zod schema should have safeParse
22
+ expect('safeParse' in tool.parameters).toBe(true);
23
+ });
24
+ it('validates correct parameters', () => {
25
+ const tool = createDispatchTool();
26
+ const schema = tool.parameters;
27
+ if ('safeParse' in schema) {
28
+ const result = schema.safeParse({
29
+ agent_name: 'data-fetcher',
30
+ tools: ['request', 'query_store'],
31
+ prompt: 'Fetch the latest metrics',
32
+ });
33
+ expect(result.success).toBe(true);
34
+ }
35
+ });
36
+ it('validates parameters with optional max_turns', () => {
37
+ const tool = createDispatchTool();
38
+ const schema = tool.parameters;
39
+ if ('safeParse' in schema) {
40
+ const result = schema.safeParse({
41
+ agent_name: 'profiler',
42
+ tools: ['request'],
43
+ prompt: 'Profile the entity',
44
+ max_turns: 5,
45
+ });
46
+ expect(result.success).toBe(true);
47
+ }
48
+ });
49
+ it('rejects missing required fields', () => {
50
+ const tool = createDispatchTool();
51
+ const schema = tool.parameters;
52
+ if ('safeParse' in schema) {
53
+ const result = schema.safeParse({ agent_name: 'test' });
54
+ expect(result.success).toBe(false);
55
+ }
56
+ });
57
+ it('rejects invalid max_turns', () => {
58
+ const tool = createDispatchTool();
59
+ const schema = tool.parameters;
60
+ if ('safeParse' in schema) {
61
+ const result = schema.safeParse({
62
+ agent_name: 'test',
63
+ tools: [],
64
+ prompt: 'do thing',
65
+ max_turns: -1,
66
+ });
67
+ expect(result.success).toBe(false);
68
+ }
69
+ });
70
+ it('execute throws ToolExecutionError (should never be called directly)', async () => {
71
+ const tool = createDispatchTool();
72
+ await expect(tool.execute({}, {})).rejects.toThrow(ToolExecutionError);
73
+ });
74
+ });
75
+ //# sourceMappingURL=dispatch-tool.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatch-tool.test.js","sourceRoot":"","sources":["../../../src/tools/dispatch-tool.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ import type { McpManager, McpDiscoveredTool } from '@amodalai/core';
7
+ import type { ToolDefinition, ToolRegistry } from './types.js';
8
+ import type { Logger } from '@amodalai/core';
9
+ /**
10
+ * Convert a single MCP discovered tool to a ToolDefinition.
11
+ */
12
+ export declare function createMcpToolDefinition(tool: McpDiscoveredTool, mcpManager: McpManager, logger: Logger): ToolDefinition;
13
+ /**
14
+ * Register all discovered MCP tools on a ToolRegistry.
15
+ *
16
+ * Call this after MCP servers have connected and discovered their tools.
17
+ */
18
+ export declare function registerMcpTools(registry: ToolRegistry, mcpManager: McpManager, logger: Logger): number;
@@ -0,0 +1,135 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ /**
7
+ * MCP tool adapter.
8
+ *
9
+ * Converts MCP discovered tools into ToolDefinition objects that can be
10
+ * registered on our ToolRegistry. Each tool's execute function delegates
11
+ * to the McpManager.callTool() method.
12
+ *
13
+ * MCP tools already have JSON Schema parameter definitions from the server.
14
+ * We pass these through to the AI SDK via jsonSchema() — no Zod conversion
15
+ * needed. The AI SDK sends the schema to the LLM as-is, preserving all
16
+ * parameter descriptions, types, and constraints the server defined.
17
+ */
18
+ import { jsonSchema } from 'ai';
19
+ import { ConnectionError } from '../errors.js';
20
+ /** Default timeout for MCP tool calls (60 seconds). */
21
+ const MCP_TOOL_TIMEOUT_MS = 60_000;
22
+ // ---------------------------------------------------------------------------
23
+ // MCP tool → ToolDefinition
24
+ // ---------------------------------------------------------------------------
25
+ /**
26
+ * Convert a single MCP discovered tool to a ToolDefinition.
27
+ */
28
+ export function createMcpToolDefinition(tool, mcpManager, logger) {
29
+ // Pass the MCP server's JSON Schema directly to the AI SDK.
30
+ // No Zod conversion — the schema goes to the LLM as-is, preserving
31
+ // all parameter descriptions, types, and constraints.
32
+ const parametersSchema = jsonSchema(tool.parameters);
33
+ return {
34
+ description: tool.description,
35
+ parameters: parametersSchema,
36
+ readOnly: false, // MCP tools may have side effects — default conservative
37
+ metadata: {
38
+ category: 'mcp',
39
+ connection: tool.serverName,
40
+ originalName: tool.originalName,
41
+ },
42
+ async execute(params, ctx) {
43
+ logger.debug('mcp_tool_call_start', {
44
+ session: ctx.sessionId,
45
+ tool: tool.name,
46
+ server: tool.serverName,
47
+ });
48
+ const startTime = Date.now();
49
+ try {
50
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- params validated by Zod before execute; MCP tools always have object schemas
51
+ const callPromise = mcpManager.callTool(tool.name, (params ?? {}));
52
+ // Race against timeout — McpManager.callTool doesn't accept AbortSignal
53
+ const timeoutSignal = ctx.signal ?? AbortSignal.timeout(MCP_TOOL_TIMEOUT_MS);
54
+ const result = await Promise.race([
55
+ callPromise,
56
+ new Promise((_resolve, reject) => {
57
+ if (timeoutSignal.aborted) {
58
+ reject(new ConnectionError(`MCP tool call "${tool.name}" timed out`, { connection: tool.serverName, action: `callTool(${tool.originalName})` }));
59
+ return;
60
+ }
61
+ timeoutSignal.addEventListener('abort', () => {
62
+ reject(new ConnectionError(`MCP tool call "${tool.name}" timed out`, { connection: tool.serverName, action: `callTool(${tool.originalName})` }));
63
+ }, { once: true });
64
+ }),
65
+ ]);
66
+ const durationMs = Date.now() - startTime;
67
+ logger.info('mcp_tool_call_complete', {
68
+ session: ctx.sessionId,
69
+ tool: tool.name,
70
+ server: tool.serverName,
71
+ durationMs,
72
+ isError: result.isError ?? false,
73
+ });
74
+ if (result.isError) {
75
+ const errorText = result.content
76
+ .filter((c) => c.type === 'text' && c.text)
77
+ .map((c) => c.text)
78
+ .join('\n');
79
+ return { error: errorText || 'MCP tool returned an error' };
80
+ }
81
+ // Format the response content
82
+ const output = result.content
83
+ .map((c) => {
84
+ if (c.type === 'text' && c.text)
85
+ return c.text;
86
+ if (c.type === 'image' && c.data)
87
+ return `[image: ${c.mimeType ?? 'unknown'}]`;
88
+ return `[${c.type}]`;
89
+ })
90
+ .join('\n');
91
+ return { output };
92
+ }
93
+ catch (err) {
94
+ const durationMs = Date.now() - startTime;
95
+ const message = err instanceof Error ? err.message : String(err);
96
+ logger.error('mcp_tool_call_failed', {
97
+ session: ctx.sessionId,
98
+ tool: tool.name,
99
+ server: tool.serverName,
100
+ durationMs,
101
+ error: message,
102
+ });
103
+ // Classify the error for a helpful message
104
+ if (message.includes('ECONNREFUSED') || message.includes('ENOTFOUND') || message.includes('unreachable')) {
105
+ throw new ConnectionError(`MCP server for "${tool.name}" is unreachable: ${message}. The MCP server may have crashed or the URL may be wrong.`, { connection: tool.serverName, action: `callTool(${tool.originalName})`, cause: err });
106
+ }
107
+ if (message.includes('401') || message.includes('403') || message.includes('missing_token') || message.includes('invalid_token')) {
108
+ throw new ConnectionError(`MCP authentication failed for "${tool.name}": ${message}. Check auth headers in amodal.json.`, { connection: tool.serverName, action: `callTool(${tool.originalName})`, cause: err });
109
+ }
110
+ throw new ConnectionError(`MCP tool call failed for "${tool.name}": ${message}`, { connection: tool.serverName, action: `callTool(${tool.originalName})`, cause: err });
111
+ }
112
+ },
113
+ };
114
+ }
115
+ // ---------------------------------------------------------------------------
116
+ // Register all MCP tools
117
+ // ---------------------------------------------------------------------------
118
+ /**
119
+ * Register all discovered MCP tools on a ToolRegistry.
120
+ *
121
+ * Call this after MCP servers have connected and discovered their tools.
122
+ */
123
+ export function registerMcpTools(registry, mcpManager, logger) {
124
+ const tools = mcpManager.getDiscoveredTools();
125
+ let registered = 0;
126
+ for (const tool of tools) {
127
+ registry.register(tool.name, createMcpToolDefinition(tool, mcpManager, logger));
128
+ registered++;
129
+ }
130
+ if (registered > 0) {
131
+ logger.info('mcp_tools_registered', { count: registered, tools: tools.map((t) => t.name) });
132
+ }
133
+ return registered;
134
+ }
135
+ //# sourceMappingURL=mcp-tool-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-tool-adapter.js","sourceRoot":"","sources":["../../../src/tools/mcp-tool-adapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ export {};