@amodalai/runtime 0.1.26 → 0.2.1

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 (445) hide show
  1. package/dist/src/__fixtures__/README.md +88 -0
  2. package/dist/src/__fixtures__/e2e.test.js +211 -0
  3. package/dist/src/__fixtures__/e2e.test.js.map +1 -0
  4. package/dist/src/__fixtures__/smoke-agent/amodal.json +11 -0
  5. package/dist/src/__fixtures__/smoke-agent/automations/delivery-callback-test.json +9 -0
  6. package/dist/src/__fixtures__/smoke-agent/automations/test-auto.md +5 -0
  7. package/dist/src/__fixtures__/smoke-agent/connections/mock-api/access.json +11 -0
  8. package/dist/src/__fixtures__/smoke-agent/connections/mock-api/spec.json +4 -0
  9. package/dist/src/__fixtures__/smoke-agent/connections/mock-api/surface.md +9 -0
  10. package/dist/src/__fixtures__/smoke-agent/connections/mock-mcp/access.json +3 -0
  11. package/dist/src/__fixtures__/smoke-agent/connections/mock-mcp/spec.json +8 -0
  12. package/dist/src/__fixtures__/smoke-agent/evals/basic-eval.md +12 -0
  13. package/dist/src/__fixtures__/smoke-agent/knowledge/test-knowledge.md +3 -0
  14. package/dist/src/__fixtures__/smoke-agent/skills/test-skill/SKILL.md +11 -0
  15. package/dist/src/__fixtures__/smoke-agent/stores/test-items.json +11 -0
  16. package/dist/src/__fixtures__/smoke-agent/tools/echo_tool/handler.d.ts +18 -0
  17. package/dist/src/__fixtures__/smoke-agent/tools/echo_tool/handler.js +22 -0
  18. package/dist/src/__fixtures__/smoke-agent/tools/echo_tool/handler.js.map +1 -0
  19. package/dist/src/__fixtures__/smoke-agent/tools/echo_tool/tool.json +17 -0
  20. package/dist/src/__fixtures__/smoke.test.js +1404 -0
  21. package/dist/src/__fixtures__/smoke.test.js.map +1 -0
  22. package/dist/src/__fixtures__/test-env.d.ts +27 -0
  23. package/dist/src/__fixtures__/test-env.js +64 -0
  24. package/dist/src/__fixtures__/test-env.js.map +1 -0
  25. package/dist/src/__fixtures__/test-helpers.d.ts +30 -0
  26. package/dist/src/__fixtures__/test-helpers.js +120 -0
  27. package/dist/src/__fixtures__/test-helpers.js.map +1 -0
  28. package/dist/src/__tests__/test-providers.d.ts +40 -0
  29. package/dist/src/__tests__/test-providers.js +61 -0
  30. package/dist/src/__tests__/test-providers.js.map +1 -0
  31. package/dist/src/agent/agent-types.d.ts +22 -0
  32. package/dist/src/agent/agent-types.js.map +1 -1
  33. package/dist/src/agent/automation-bridge.d.ts +9 -0
  34. package/dist/src/agent/automation-bridge.js +26 -0
  35. package/dist/src/agent/automation-bridge.js.map +1 -1
  36. package/dist/src/agent/automation-bridge.test.js +63 -0
  37. package/dist/src/agent/automation-bridge.test.js.map +1 -1
  38. package/dist/src/agent/local-server.d.ts +1 -8
  39. package/dist/src/agent/local-server.js +398 -163
  40. package/dist/src/agent/local-server.js.map +1 -1
  41. package/dist/src/agent/local-server.test.js +14 -8
  42. package/dist/src/agent/local-server.test.js.map +1 -1
  43. package/dist/src/agent/loop-types.d.ts +254 -0
  44. package/dist/src/agent/loop-types.js +24 -0
  45. package/dist/src/agent/loop-types.js.map +1 -0
  46. package/dist/src/agent/loop.d.ts +31 -0
  47. package/dist/src/agent/loop.js +152 -0
  48. package/dist/src/agent/loop.js.map +1 -0
  49. package/dist/src/agent/loop.test.js +1594 -0
  50. package/dist/src/agent/loop.test.js.map +1 -0
  51. package/dist/src/agent/mcp-config.d.ts +28 -0
  52. package/dist/src/agent/mcp-config.js +57 -0
  53. package/dist/src/agent/mcp-config.js.map +1 -0
  54. package/dist/src/agent/page-builder.js +6 -1
  55. package/dist/src/agent/page-builder.js.map +1 -1
  56. package/dist/src/agent/proactive/delivery-router.d.ts +68 -0
  57. package/dist/src/agent/proactive/delivery-router.js +337 -0
  58. package/dist/src/agent/proactive/delivery-router.js.map +1 -0
  59. package/dist/src/agent/{stores-e2e.test.d.ts → proactive/delivery-router.test.d.ts} +1 -1
  60. package/dist/src/agent/proactive/delivery-router.test.js +455 -0
  61. package/dist/src/agent/proactive/delivery-router.test.js.map +1 -0
  62. package/dist/src/agent/proactive/proactive-runner.d.ts +46 -8
  63. package/dist/src/agent/proactive/proactive-runner.js +67 -37
  64. package/dist/src/agent/proactive/proactive-runner.js.map +1 -1
  65. package/dist/src/agent/proactive/proactive-runner.test.d.ts +1 -1
  66. package/dist/src/agent/proactive/proactive-runner.test.js +73 -87
  67. package/dist/src/agent/proactive/proactive-runner.test.js.map +1 -1
  68. package/dist/src/agent/routes/admin-chat-abort.test.d.ts +6 -0
  69. package/dist/src/agent/routes/admin-chat-abort.test.js +206 -0
  70. package/dist/src/agent/routes/admin-chat-abort.test.js.map +1 -0
  71. package/dist/src/agent/routes/admin-chat.d.ts +15 -3
  72. package/dist/src/agent/routes/admin-chat.js +61 -18
  73. package/dist/src/agent/routes/admin-chat.js.map +1 -1
  74. package/dist/src/agent/routes/automations.js +5 -6
  75. package/dist/src/agent/routes/automations.js.map +1 -1
  76. package/dist/src/agent/routes/evals.d.ts +3 -2
  77. package/dist/src/agent/routes/evals.js +25 -12
  78. package/dist/src/agent/routes/evals.js.map +1 -1
  79. package/dist/src/agent/routes/files.js +7 -9
  80. package/dist/src/agent/routes/files.js.map +1 -1
  81. package/dist/src/agent/routes/inspect.d.ts +6 -2
  82. package/dist/src/agent/routes/inspect.js +31 -17
  83. package/dist/src/agent/routes/inspect.js.map +1 -1
  84. package/dist/src/agent/routes/inspect.test.js +18 -42
  85. package/dist/src/agent/routes/inspect.test.js.map +1 -1
  86. package/dist/src/agent/routes/stores.js +9 -12
  87. package/dist/src/agent/routes/stores.js.map +1 -1
  88. package/dist/src/agent/routes/task.d.ts +15 -3
  89. package/dist/src/agent/routes/task.js +16 -7
  90. package/dist/src/agent/routes/task.js.map +1 -1
  91. package/dist/src/agent/routes/task.test.d.ts +1 -1
  92. package/dist/src/agent/routes/task.test.js +68 -53
  93. package/dist/src/agent/routes/task.test.js.map +1 -1
  94. package/dist/src/agent/routes/webhooks.js +12 -3
  95. package/dist/src/agent/routes/webhooks.js.map +1 -1
  96. package/dist/src/agent/snapshot-server.d.ts +2 -22
  97. package/dist/src/agent/snapshot-server.js +48 -27
  98. package/dist/src/agent/snapshot-server.js.map +1 -1
  99. package/dist/src/agent/states/compacting.d.ts +14 -0
  100. package/dist/src/agent/states/compacting.js +260 -0
  101. package/dist/src/agent/states/compacting.js.map +1 -0
  102. package/dist/src/agent/states/confirming.d.ts +10 -0
  103. package/dist/src/agent/states/confirming.js +79 -0
  104. package/dist/src/agent/states/confirming.js.map +1 -0
  105. package/dist/src/agent/states/dispatching.d.ts +18 -0
  106. package/dist/src/agent/states/dispatching.js +285 -0
  107. package/dist/src/agent/states/dispatching.js.map +1 -0
  108. package/dist/src/agent/states/executing.d.ts +21 -0
  109. package/dist/src/agent/states/executing.js +452 -0
  110. package/dist/src/agent/states/executing.js.map +1 -0
  111. package/dist/src/agent/states/streaming.d.ts +10 -0
  112. package/dist/src/agent/states/streaming.js +169 -0
  113. package/dist/src/agent/states/streaming.js.map +1 -0
  114. package/dist/src/agent/states/thinking.d.ts +13 -0
  115. package/dist/src/agent/states/thinking.js +450 -0
  116. package/dist/src/agent/states/thinking.js.map +1 -0
  117. package/dist/src/agent/token-estimate.d.ts +31 -0
  118. package/dist/src/agent/token-estimate.js +34 -0
  119. package/dist/src/agent/token-estimate.js.map +1 -0
  120. package/dist/src/agent/token-estimate.test.d.ts +6 -0
  121. package/dist/src/agent/token-estimate.test.js +44 -0
  122. package/dist/src/agent/token-estimate.test.js.map +1 -0
  123. package/dist/src/agent/tool-executor-local.js +9 -18
  124. package/dist/src/agent/tool-executor-local.js.map +1 -1
  125. package/dist/src/agent/tool-executor-local.test.js +3 -5
  126. package/dist/src/agent/tool-executor-local.test.js.map +1 -1
  127. package/dist/src/api/create-agent.d.ts +15 -0
  128. package/dist/src/api/create-agent.js +134 -0
  129. package/dist/src/api/create-agent.js.map +1 -0
  130. package/dist/src/api/types.d.ts +66 -0
  131. package/dist/src/api/types.js +7 -0
  132. package/dist/src/api/types.js.map +1 -0
  133. package/dist/src/context/compiler.d.ts +13 -0
  134. package/dist/src/context/compiler.js +358 -0
  135. package/dist/src/context/compiler.js.map +1 -0
  136. package/dist/src/context/compiler.test.d.ts +6 -0
  137. package/dist/src/context/compiler.test.js +532 -0
  138. package/dist/src/context/compiler.test.js.map +1 -0
  139. package/dist/src/context/types.d.ts +110 -0
  140. package/dist/src/context/types.js +7 -0
  141. package/dist/src/context/types.js.map +1 -0
  142. package/dist/src/env-ref.d.ts +13 -0
  143. package/dist/src/env-ref.js +31 -0
  144. package/dist/src/env-ref.js.map +1 -0
  145. package/dist/src/env-ref.test.d.ts +6 -0
  146. package/dist/src/env-ref.test.js +34 -0
  147. package/dist/src/env-ref.test.js.map +1 -0
  148. package/dist/src/errors.d.ts +15 -0
  149. package/dist/src/errors.js +22 -0
  150. package/dist/src/errors.js.map +1 -1
  151. package/dist/src/errors.test.js +2 -2
  152. package/dist/src/errors.test.js.map +1 -1
  153. package/dist/src/events/event-bus.d.ts +54 -0
  154. package/dist/src/events/event-bus.js +84 -0
  155. package/dist/src/events/event-bus.js.map +1 -0
  156. package/dist/src/events/event-bus.test.d.ts +6 -0
  157. package/dist/src/events/event-bus.test.js +112 -0
  158. package/dist/src/events/event-bus.test.js.map +1 -0
  159. package/dist/src/events/events-route.d.ts +36 -0
  160. package/dist/src/events/events-route.js +80 -0
  161. package/dist/src/events/events-route.js.map +1 -0
  162. package/dist/src/events/events-route.test.d.ts +6 -0
  163. package/dist/src/events/events-route.test.js +134 -0
  164. package/dist/src/events/events-route.test.js.map +1 -0
  165. package/dist/src/events/store-event-wrapper.d.ts +19 -0
  166. package/dist/src/events/store-event-wrapper.js +57 -0
  167. package/dist/src/events/store-event-wrapper.js.map +1 -0
  168. package/dist/src/events/store-event-wrapper.test.d.ts +6 -0
  169. package/dist/src/events/store-event-wrapper.test.js +91 -0
  170. package/dist/src/events/store-event-wrapper.test.js.map +1 -0
  171. package/dist/src/index.d.ts +33 -6
  172. package/dist/src/index.js +35 -21
  173. package/dist/src/index.js.map +1 -1
  174. package/dist/src/middleware/auth.d.ts +0 -2
  175. package/dist/src/middleware/auth.js.map +1 -1
  176. package/dist/src/providers/create-provider.d.ts +23 -0
  177. package/dist/src/providers/create-provider.js +185 -0
  178. package/dist/src/providers/create-provider.js.map +1 -0
  179. package/dist/src/providers/create-provider.test.d.ts +6 -0
  180. package/dist/src/providers/create-provider.test.js +95 -0
  181. package/dist/src/providers/create-provider.test.js.map +1 -0
  182. package/dist/src/providers/failover.d.ts +38 -0
  183. package/dist/src/providers/failover.js +147 -0
  184. package/dist/src/providers/failover.js.map +1 -0
  185. package/dist/src/providers/failover.test.d.ts +6 -0
  186. package/dist/src/providers/failover.test.js +169 -0
  187. package/dist/src/providers/failover.test.js.map +1 -0
  188. package/dist/src/providers/search-provider.d.ts +64 -0
  189. package/dist/src/providers/search-provider.js +174 -0
  190. package/dist/src/providers/search-provider.js.map +1 -0
  191. package/dist/src/providers/types.d.ts +118 -0
  192. package/dist/src/providers/types.js +7 -0
  193. package/dist/src/providers/types.js.map +1 -0
  194. package/dist/src/routes/ai-stream.d.ts +28 -10
  195. package/dist/src/routes/ai-stream.js +85 -41
  196. package/dist/src/routes/ai-stream.js.map +1 -1
  197. package/dist/src/routes/chat-new.test.d.ts +6 -0
  198. package/dist/src/routes/chat-new.test.js +107 -0
  199. package/dist/src/routes/chat-new.test.js.map +1 -0
  200. package/dist/src/routes/chat-stream-new.test.d.ts +6 -0
  201. package/dist/src/routes/chat-stream-new.test.js +135 -0
  202. package/dist/src/routes/chat-stream-new.test.js.map +1 -0
  203. package/dist/src/routes/chat-stream.d.ts +20 -4
  204. package/dist/src/routes/chat-stream.js +49 -29
  205. package/dist/src/routes/chat-stream.js.map +1 -1
  206. package/dist/src/routes/chat.d.ts +19 -4
  207. package/dist/src/routes/chat.js +62 -23
  208. package/dist/src/routes/chat.js.map +1 -1
  209. package/dist/src/routes/health.d.ts +3 -2
  210. package/dist/src/routes/health.js.map +1 -1
  211. package/dist/src/routes/route-helpers.d.ts +50 -0
  212. package/dist/src/routes/route-helpers.js +80 -0
  213. package/dist/src/routes/route-helpers.js.map +1 -0
  214. package/dist/src/routes/session-resolver.d.ts +77 -0
  215. package/dist/src/routes/session-resolver.js +109 -0
  216. package/dist/src/routes/session-resolver.js.map +1 -0
  217. package/dist/src/routes/session-resolver.test.d.ts +6 -0
  218. package/dist/src/routes/session-resolver.test.js +207 -0
  219. package/dist/src/routes/session-resolver.test.js.map +1 -0
  220. package/dist/src/routes/webhooks.d.ts +3 -1
  221. package/dist/src/routes/webhooks.js +12 -4
  222. package/dist/src/routes/webhooks.js.map +1 -1
  223. package/dist/src/security/permission-checker.d.ts +80 -0
  224. package/dist/src/security/permission-checker.js +75 -0
  225. package/dist/src/security/permission-checker.js.map +1 -0
  226. package/dist/src/security/permission-checker.test.d.ts +6 -0
  227. package/dist/src/security/permission-checker.test.js +208 -0
  228. package/dist/src/security/permission-checker.test.js.map +1 -0
  229. package/dist/src/server.d.ts +18 -11
  230. package/dist/src/server.js +46 -46
  231. package/dist/src/server.js.map +1 -1
  232. package/dist/src/server.test.d.ts +1 -1
  233. package/dist/src/server.test.js +6 -144
  234. package/dist/src/server.test.js.map +1 -1
  235. package/dist/src/session/drizzle-session-store.d.ts +56 -0
  236. package/dist/src/session/drizzle-session-store.js +203 -0
  237. package/dist/src/session/drizzle-session-store.js.map +1 -0
  238. package/dist/src/session/manager.d.ts +101 -0
  239. package/dist/src/session/manager.js +394 -0
  240. package/dist/src/session/manager.js.map +1 -0
  241. package/dist/src/session/manager.test.d.ts +6 -0
  242. package/dist/src/session/manager.test.js +309 -0
  243. package/dist/src/session/manager.test.js.map +1 -0
  244. package/dist/src/session/pglite-session-store.d.ts +23 -0
  245. package/dist/src/session/pglite-session-store.js +70 -0
  246. package/dist/src/session/pglite-session-store.js.map +1 -0
  247. package/dist/src/session/postgres-session-store.d.ts +44 -0
  248. package/dist/src/session/postgres-session-store.js +138 -0
  249. package/dist/src/session/postgres-session-store.js.map +1 -0
  250. package/dist/src/session/session-builder.d.ts +69 -0
  251. package/dist/src/session/session-builder.js +384 -0
  252. package/dist/src/session/session-builder.js.map +1 -0
  253. package/dist/src/session/session-builder.test.d.ts +6 -0
  254. package/dist/src/session/session-builder.test.js +350 -0
  255. package/dist/src/session/session-builder.test.js.map +1 -0
  256. package/dist/src/session/session-store-selector.d.ts +49 -0
  257. package/dist/src/session/session-store-selector.js +60 -0
  258. package/dist/src/session/session-store-selector.js.map +1 -0
  259. package/dist/src/session/session-store-selector.test.d.ts +6 -0
  260. package/dist/src/session/session-store-selector.test.js +79 -0
  261. package/dist/src/session/session-store-selector.test.js.map +1 -0
  262. package/dist/src/session/store.d.ts +171 -0
  263. package/dist/src/session/store.js +155 -0
  264. package/dist/src/session/store.js.map +1 -0
  265. package/dist/src/session/store.test.d.ts +6 -0
  266. package/dist/src/session/store.test.js +423 -0
  267. package/dist/src/session/store.test.js.map +1 -0
  268. package/dist/src/session/stream-hooks.d.ts +39 -0
  269. package/dist/src/session/stream-hooks.js +7 -0
  270. package/dist/src/session/stream-hooks.js.map +1 -0
  271. package/dist/src/session/tool-context-factory.d.ts +61 -0
  272. package/dist/src/session/tool-context-factory.js +189 -0
  273. package/dist/src/session/tool-context-factory.js.map +1 -0
  274. package/dist/src/session/tool-context-factory.test.d.ts +6 -0
  275. package/dist/src/session/tool-context-factory.test.js +284 -0
  276. package/dist/src/session/tool-context-factory.test.js.map +1 -0
  277. package/dist/src/session/types.d.ts +195 -0
  278. package/dist/src/session/types.js +7 -0
  279. package/dist/src/session/types.js.map +1 -0
  280. package/dist/src/stores/drizzle-store-backend.d.ts +49 -0
  281. package/dist/src/stores/drizzle-store-backend.js +306 -0
  282. package/dist/src/stores/drizzle-store-backend.js.map +1 -0
  283. package/dist/src/stores/drizzle-store-backend.test.d.ts +6 -0
  284. package/dist/src/stores/drizzle-store-backend.test.js +215 -0
  285. package/dist/src/stores/drizzle-store-backend.test.js.map +1 -0
  286. package/dist/src/stores/index.d.ts +4 -0
  287. package/dist/src/stores/index.js +2 -0
  288. package/dist/src/stores/index.js.map +1 -1
  289. package/dist/src/stores/pglite-store-backend.d.ts +16 -19
  290. package/dist/src/stores/pglite-store-backend.js +85 -239
  291. package/dist/src/stores/pglite-store-backend.js.map +1 -1
  292. package/dist/src/stores/postgres-store-backend.d.ts +30 -0
  293. package/dist/src/stores/postgres-store-backend.js +100 -0
  294. package/dist/src/stores/postgres-store-backend.js.map +1 -0
  295. package/dist/src/stores/schema.d.ts +457 -0
  296. package/dist/src/stores/schema.js +59 -0
  297. package/dist/src/stores/schema.js.map +1 -0
  298. package/dist/src/tools/admin-file-tools.d.ts +42 -0
  299. package/dist/src/tools/admin-file-tools.js +714 -0
  300. package/dist/src/tools/admin-file-tools.js.map +1 -0
  301. package/dist/src/tools/admin-file-tools.test.d.ts +6 -0
  302. package/dist/src/tools/admin-file-tools.test.js +521 -0
  303. package/dist/src/tools/admin-file-tools.test.js.map +1 -0
  304. package/dist/src/tools/custom-tool-adapter.d.ts +41 -0
  305. package/dist/src/tools/custom-tool-adapter.js +190 -0
  306. package/dist/src/tools/custom-tool-adapter.js.map +1 -0
  307. package/dist/src/tools/custom-tool-adapter.test.d.ts +6 -0
  308. package/dist/src/tools/custom-tool-adapter.test.js +243 -0
  309. package/dist/src/tools/custom-tool-adapter.test.js.map +1 -0
  310. package/dist/src/tools/dispatch-tool.d.ts +52 -0
  311. package/dist/src/tools/dispatch-tool.js +71 -0
  312. package/dist/src/tools/dispatch-tool.js.map +1 -0
  313. package/dist/src/tools/dispatch-tool.test.d.ts +6 -0
  314. package/dist/src/tools/dispatch-tool.test.js +75 -0
  315. package/dist/src/tools/dispatch-tool.test.js.map +1 -0
  316. package/dist/src/tools/fetch-url-tool.d.ts +23 -0
  317. package/dist/src/tools/fetch-url-tool.js +333 -0
  318. package/dist/src/tools/fetch-url-tool.js.map +1 -0
  319. package/dist/src/tools/fetch-url-tool.test.d.ts +6 -0
  320. package/dist/src/tools/fetch-url-tool.test.js +228 -0
  321. package/dist/src/tools/fetch-url-tool.test.js.map +1 -0
  322. package/dist/src/tools/mcp-tool-adapter.d.ts +18 -0
  323. package/dist/src/tools/mcp-tool-adapter.js +135 -0
  324. package/dist/src/tools/mcp-tool-adapter.js.map +1 -0
  325. package/dist/src/tools/mcp-tool-adapter.test.d.ts +6 -0
  326. package/dist/src/tools/mcp-tool-adapter.test.js +226 -0
  327. package/dist/src/tools/mcp-tool-adapter.test.js.map +1 -0
  328. package/dist/src/tools/registry.d.ts +25 -0
  329. package/dist/src/tools/registry.js +72 -0
  330. package/dist/src/tools/registry.js.map +1 -0
  331. package/dist/src/tools/registry.test.d.ts +6 -0
  332. package/dist/src/tools/registry.test.js +120 -0
  333. package/dist/src/tools/registry.test.js.map +1 -0
  334. package/dist/src/tools/request-tool.d.ts +42 -0
  335. package/dist/src/tools/request-tool.js +190 -0
  336. package/dist/src/tools/request-tool.js.map +1 -0
  337. package/dist/src/tools/request-tool.test.d.ts +6 -0
  338. package/dist/src/tools/request-tool.test.js +253 -0
  339. package/dist/src/tools/request-tool.test.js.map +1 -0
  340. package/dist/src/tools/store-tools.d.ts +29 -0
  341. package/dist/src/tools/store-tools.js +224 -0
  342. package/dist/src/tools/store-tools.js.map +1 -0
  343. package/dist/src/tools/store-tools.test.d.ts +6 -0
  344. package/dist/src/tools/store-tools.test.js +215 -0
  345. package/dist/src/tools/store-tools.test.js.map +1 -0
  346. package/dist/src/tools/types.d.ts +129 -0
  347. package/dist/src/tools/types.js +7 -0
  348. package/dist/src/tools/types.js.map +1 -0
  349. package/dist/src/tools/web-search-tool.d.ts +31 -0
  350. package/dist/src/tools/web-search-tool.js +170 -0
  351. package/dist/src/tools/web-search-tool.js.map +1 -0
  352. package/dist/src/tools/web-search-tool.test.d.ts +6 -0
  353. package/dist/src/tools/web-search-tool.test.js +153 -0
  354. package/dist/src/tools/web-search-tool.test.js.map +1 -0
  355. package/dist/src/tools/web-tools-shared.d.ts +21 -0
  356. package/dist/src/tools/web-tools-shared.js +32 -0
  357. package/dist/src/tools/web-tools-shared.js.map +1 -0
  358. package/dist/src/types.d.ts +40 -12
  359. package/dist/src/types.js +16 -2
  360. package/dist/src/types.js.map +1 -1
  361. package/dist/tsconfig.tsbuildinfo +1 -1
  362. package/package.json +27 -4
  363. package/dist/src/__tests__/sse-contract.test.js +0 -464
  364. package/dist/src/__tests__/sse-contract.test.js.map +0 -1
  365. package/dist/src/__tests__/tools.test.js +0 -583
  366. package/dist/src/__tests__/tools.test.js.map +0 -1
  367. package/dist/src/agent/agent-runner.d.ts +0 -33
  368. package/dist/src/agent/agent-runner.js +0 -1040
  369. package/dist/src/agent/agent-runner.js.map +0 -1
  370. package/dist/src/agent/custom-tools-e2e.test.d.ts +0 -6
  371. package/dist/src/agent/custom-tools-e2e.test.js +0 -566
  372. package/dist/src/agent/custom-tools-e2e.test.js.map +0 -1
  373. package/dist/src/agent/request-helper.d.ts +0 -16
  374. package/dist/src/agent/request-helper.js +0 -96
  375. package/dist/src/agent/request-helper.js.map +0 -1
  376. package/dist/src/agent/session-store.d.ts +0 -62
  377. package/dist/src/agent/session-store.js +0 -151
  378. package/dist/src/agent/session-store.js.map +0 -1
  379. package/dist/src/agent/stores-e2e.test.js +0 -433
  380. package/dist/src/agent/stores-e2e.test.js.map +0 -1
  381. package/dist/src/agent/tool-context-builder.d.ts +0 -11
  382. package/dist/src/agent/tool-context-builder.js +0 -102
  383. package/dist/src/agent/tool-context-builder.js.map +0 -1
  384. package/dist/src/agent/tool-context-builder.test.d.ts +0 -6
  385. package/dist/src/agent/tool-context-builder.test.js +0 -152
  386. package/dist/src/agent/tool-context-builder.test.js.map +0 -1
  387. package/dist/src/agent/write-repo-file.test.js +0 -270
  388. package/dist/src/agent/write-repo-file.test.js.map +0 -1
  389. package/dist/src/cron/heartbeat-runner.d.ts +0 -21
  390. package/dist/src/cron/heartbeat-runner.js +0 -79
  391. package/dist/src/cron/heartbeat-runner.js.map +0 -1
  392. package/dist/src/cron/heartbeat-runner.test.d.ts +0 -6
  393. package/dist/src/cron/heartbeat-runner.test.js +0 -120
  394. package/dist/src/cron/heartbeat-runner.test.js.map +0 -1
  395. package/dist/src/cron/heartbeat-scheduler.d.ts +0 -26
  396. package/dist/src/cron/heartbeat-scheduler.js +0 -55
  397. package/dist/src/cron/heartbeat-scheduler.js.map +0 -1
  398. package/dist/src/cron/heartbeat-scheduler.test.d.ts +0 -6
  399. package/dist/src/cron/heartbeat-scheduler.test.js +0 -61
  400. package/dist/src/cron/heartbeat-scheduler.test.js.map +0 -1
  401. package/dist/src/routes/ai-stream.test.d.ts +0 -6
  402. package/dist/src/routes/ai-stream.test.js +0 -586
  403. package/dist/src/routes/ai-stream.test.js.map +0 -1
  404. package/dist/src/routes/ask-user-response.d.ts +0 -30
  405. package/dist/src/routes/ask-user-response.js +0 -61
  406. package/dist/src/routes/ask-user-response.js.map +0 -1
  407. package/dist/src/routes/ask-user-response.test.d.ts +0 -6
  408. package/dist/src/routes/ask-user-response.test.js +0 -88
  409. package/dist/src/routes/ask-user-response.test.js.map +0 -1
  410. package/dist/src/routes/chat-stream.test.d.ts +0 -6
  411. package/dist/src/routes/chat-stream.test.js +0 -155
  412. package/dist/src/routes/chat-stream.test.js.map +0 -1
  413. package/dist/src/routes/chat.test.d.ts +0 -6
  414. package/dist/src/routes/chat.test.js +0 -99
  415. package/dist/src/routes/chat.test.js.map +0 -1
  416. package/dist/src/routes/widget-actions.d.ts +0 -49
  417. package/dist/src/routes/widget-actions.js +0 -78
  418. package/dist/src/routes/widget-actions.js.map +0 -1
  419. package/dist/src/session/admin-file-tools.d.ts +0 -136
  420. package/dist/src/session/admin-file-tools.js +0 -240
  421. package/dist/src/session/admin-file-tools.js.map +0 -1
  422. package/dist/src/session/custom-tool-adapter.d.ts +0 -74
  423. package/dist/src/session/custom-tool-adapter.js +0 -180
  424. package/dist/src/session/custom-tool-adapter.js.map +0 -1
  425. package/dist/src/session/history-converter.d.ts +0 -21
  426. package/dist/src/session/history-converter.js +0 -59
  427. package/dist/src/session/history-converter.js.map +0 -1
  428. package/dist/src/session/history-converter.test.d.ts +0 -6
  429. package/dist/src/session/history-converter.test.js +0 -130
  430. package/dist/src/session/history-converter.test.js.map +0 -1
  431. package/dist/src/session/session-manager.d.ts +0 -219
  432. package/dist/src/session/session-manager.js +0 -915
  433. package/dist/src/session/session-manager.js.map +0 -1
  434. package/dist/src/session/session-manager.test.d.ts +0 -6
  435. package/dist/src/session/session-manager.test.js +0 -455
  436. package/dist/src/session/session-manager.test.js.map +0 -1
  437. package/dist/src/session/session-runner.d.ts +0 -45
  438. package/dist/src/session/session-runner.js +0 -719
  439. package/dist/src/session/session-runner.js.map +0 -1
  440. package/dist/src/session/session-runner.test.d.ts +0 -6
  441. package/dist/src/session/session-runner.test.js +0 -834
  442. package/dist/src/session/session-runner.test.js.map +0 -1
  443. /package/dist/src/{__tests__/sse-contract.test.d.ts → __fixtures__/e2e.test.d.ts} +0 -0
  444. /package/dist/src/{__tests__/tools.test.d.ts → __fixtures__/smoke.test.d.ts} +0 -0
  445. /package/dist/src/agent/{write-repo-file.test.d.ts → loop.test.d.ts} +0 -0
@@ -0,0 +1,228 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
7
+ import { createFetchUrlTool, resetRateLimitForTesting } from './fetch-url-tool.js';
8
+ function makeCtx(overrides) {
9
+ return {
10
+ request: vi.fn(),
11
+ store: vi.fn(),
12
+ env: vi.fn(),
13
+ log: vi.fn(),
14
+ user: { roles: [] },
15
+ signal: AbortSignal.timeout(5000),
16
+ sessionId: 'test-session',
17
+ ...overrides,
18
+ };
19
+ }
20
+ function makeProvider(result, opts) {
21
+ const fetchMock = opts?.throws
22
+ ? vi.fn().mockRejectedValue(opts.throws)
23
+ : vi.fn().mockResolvedValue(result);
24
+ return {
25
+ model: 'gemini-2.5-flash',
26
+ search: vi.fn(),
27
+ fetchUrl: fetchMock,
28
+ };
29
+ }
30
+ async function runTool(ctx, params) {
31
+ const tool = createFetchUrlTool();
32
+ const raw = await tool.execute(params, ctx);
33
+ return raw;
34
+ }
35
+ /** Build a simple HTML document with enough content for Readability to accept. */
36
+ function htmlPage(title, body) {
37
+ const filler = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. '.repeat(30);
38
+ return `<!doctype html><html><head><title>${title}</title></head><body><article><h1>${title}</h1><p>${body}</p><p>${filler}</p></article></body></html>`;
39
+ }
40
+ describe('fetch_url tool', () => {
41
+ beforeEach(() => {
42
+ resetRateLimitForTesting();
43
+ });
44
+ afterEach(() => {
45
+ vi.unstubAllGlobals();
46
+ });
47
+ describe('primary path (Gemini urlContext)', () => {
48
+ it('uses the search provider for public URLs and returns content', async () => {
49
+ const provider = makeProvider({ text: '# Example\n\nContent here.', retrievedUrls: ['https://example.com'] });
50
+ const ctx = makeCtx({ searchProvider: provider });
51
+ const result = await runTool(ctx, { url: 'https://example.com' });
52
+ expect(result.status).toBe('ok');
53
+ expect(result.used_fallback).toBe(false);
54
+ expect(result.content).toContain('Example');
55
+ expect(provider.fetchUrl).toHaveBeenCalledTimes(1);
56
+ });
57
+ it('passes the user prompt through to the provider', async () => {
58
+ const provider = makeProvider({ text: 'summary', retrievedUrls: ['https://example.com'] });
59
+ const ctx = makeCtx({ searchProvider: provider });
60
+ await runTool(ctx, { url: 'https://example.com', prompt: 'extract the price' });
61
+ expect(provider.fetchUrl).toHaveBeenCalledWith('https://example.com', expect.objectContaining({ prompt: 'extract the price' }));
62
+ });
63
+ it('falls back to local fetch when Gemini returns empty content', async () => {
64
+ const provider = makeProvider({ text: '', retrievedUrls: [] });
65
+ vi.stubGlobal('fetch', vi.fn().mockResolvedValue(new Response(htmlPage('Page Title', 'Body content here'), {
66
+ status: 200,
67
+ headers: { 'content-type': 'text/html' },
68
+ })));
69
+ const ctx = makeCtx({ searchProvider: provider });
70
+ const result = await runTool(ctx, { url: 'https://example.com' });
71
+ expect(result.status).toBe('ok');
72
+ expect(result.used_fallback).toBe(true);
73
+ expect(result.content).toContain('Page Title');
74
+ });
75
+ it('falls back to local fetch when Gemini throws', async () => {
76
+ const provider = makeProvider({ text: '', retrievedUrls: [] }, { throws: new Error('gemini-down') });
77
+ vi.stubGlobal('fetch', vi.fn().mockResolvedValue(new Response(htmlPage('Fallback', 'Content'), { status: 200 })));
78
+ const ctx = makeCtx({ searchProvider: provider });
79
+ const result = await runTool(ctx, { url: 'https://example.com' });
80
+ expect(result.status).toBe('ok');
81
+ expect(result.used_fallback).toBe(true);
82
+ });
83
+ });
84
+ describe('local fallback path', () => {
85
+ it('uses local fetch when no searchProvider is configured', async () => {
86
+ const fetchMock = vi.fn().mockResolvedValue(new Response(htmlPage('Local Only', 'Content'), { status: 200 }));
87
+ vi.stubGlobal('fetch', fetchMock);
88
+ const ctx = makeCtx(); // no searchProvider
89
+ const result = await runTool(ctx, { url: 'https://example.com' });
90
+ expect(result.status).toBe('ok');
91
+ expect(result.used_fallback).toBe(true);
92
+ expect(result.content).toContain('Local Only');
93
+ expect(fetchMock).toHaveBeenCalledTimes(1);
94
+ });
95
+ it('uses local fetch for private network URLs even when provider is configured', async () => {
96
+ const provider = makeProvider({ text: 'wont be used', retrievedUrls: [] });
97
+ const fetchMock = vi.fn().mockResolvedValue(new Response(htmlPage('Local', 'Content'), { status: 200 }));
98
+ vi.stubGlobal('fetch', fetchMock);
99
+ const ctx = makeCtx({ searchProvider: provider });
100
+ const result = await runTool(ctx, { url: 'http://localhost:8080/health' });
101
+ expect(result.used_fallback).toBe(true);
102
+ expect(provider.fetchUrl).not.toHaveBeenCalled();
103
+ expect(fetchMock).toHaveBeenCalledTimes(1);
104
+ });
105
+ it('classifies 127.0.0.1 as private', async () => {
106
+ const fetchMock = vi.fn().mockImplementation(() => Promise.resolve(new Response(htmlPage('x', 'y'), { status: 200 })));
107
+ vi.stubGlobal('fetch', fetchMock);
108
+ const ctx = makeCtx({ searchProvider: makeProvider({ text: 'x', retrievedUrls: [] }) });
109
+ await runTool(ctx, { url: 'http://127.0.0.1:3000' });
110
+ expect(fetchMock).toHaveBeenCalledTimes(1);
111
+ });
112
+ it('classifies RFC1918 10.x and 192.168.x as private', async () => {
113
+ const fetchMock = vi.fn().mockImplementation(() => Promise.resolve(new Response(htmlPage('x', 'y'), { status: 200 })));
114
+ vi.stubGlobal('fetch', fetchMock);
115
+ const provider = makeProvider({ text: 'x', retrievedUrls: [] });
116
+ const ctx = makeCtx({ searchProvider: provider });
117
+ await runTool(ctx, { url: 'http://10.0.0.5/api' });
118
+ await runTool(ctx, { url: 'http://192.168.1.100/' });
119
+ expect(provider.fetchUrl).not.toHaveBeenCalled();
120
+ expect(fetchMock).toHaveBeenCalledTimes(2);
121
+ });
122
+ it('rejects oversized responses', async () => {
123
+ const huge = 'a'.repeat(2_000_000);
124
+ vi.stubGlobal('fetch', vi.fn().mockResolvedValue(new Response(huge, { status: 200 })));
125
+ const ctx = makeCtx();
126
+ const tool = createFetchUrlTool();
127
+ await expect(tool.execute({ url: 'https://example.com' }, ctx)).rejects.toMatchObject({ name: 'ToolExecutionError' });
128
+ });
129
+ it('throws when the local HTTP call returns non-2xx', async () => {
130
+ vi.stubGlobal('fetch', vi.fn().mockResolvedValue(new Response('not found', { status: 404 })));
131
+ const ctx = makeCtx();
132
+ const tool = createFetchUrlTool();
133
+ await expect(tool.execute({ url: 'https://example.com/missing' }, ctx)).rejects.toMatchObject({ name: 'ToolExecutionError' });
134
+ });
135
+ });
136
+ describe('URL validation', () => {
137
+ it('rejects non-http(s) protocols', async () => {
138
+ const ctx = makeCtx();
139
+ const result = await runTool(ctx, { url: 'ftp://example.com/file' });
140
+ // Zod .url() rejects ftp://? Actually it accepts it — our runtime check fires.
141
+ // If Zod rejected, this test would never reach execute; Zod .url() does NOT require http.
142
+ expect(result.status).toBe('error');
143
+ expect(result.content).toContain('http://');
144
+ });
145
+ });
146
+ describe('rate limiting', () => {
147
+ it('rejects after 10 requests in the window', async () => {
148
+ const fetchMock = vi.fn().mockImplementation(() => Promise.resolve(new Response(htmlPage('x', 'y'), { status: 200 })));
149
+ vi.stubGlobal('fetch', fetchMock);
150
+ const ctx = makeCtx();
151
+ // 10 allowed
152
+ for (let i = 0; i < 10; i++) {
153
+ const r = await runTool(ctx, { url: 'https://ratelimit.test/path' });
154
+ expect(r.status).toBe('ok');
155
+ }
156
+ // 11th hits the limit
157
+ const eleventh = await runTool(ctx, { url: 'https://ratelimit.test/other' });
158
+ expect(eleventh.status).toBe('error');
159
+ expect(eleventh.content).toContain('Rate limited');
160
+ expect(eleventh.content).toContain('ratelimit.test');
161
+ });
162
+ it('limits per-hostname independently', async () => {
163
+ const fetchMock = vi.fn().mockImplementation(() => Promise.resolve(new Response(htmlPage('x', 'y'), { status: 200 })));
164
+ vi.stubGlobal('fetch', fetchMock);
165
+ const ctx = makeCtx();
166
+ for (let i = 0; i < 10; i++) {
167
+ await runTool(ctx, { url: 'https://host-a.example/' });
168
+ }
169
+ const blocked = await runTool(ctx, { url: 'https://host-a.example/more' });
170
+ expect(blocked.status).toBe('error');
171
+ // Different host is still OK
172
+ const ok = await runTool(ctx, { url: 'https://host-b.example/' });
173
+ expect(ok.status).toBe('ok');
174
+ });
175
+ });
176
+ describe('DOM-based fallback extraction (Readability fails)', () => {
177
+ // When Readability returns nothing (pages too sparse/malformed), the
178
+ // tool falls back to walking the parsed DOM with linkedom. Verify
179
+ // script/style content does NOT leak into the output.
180
+ it('strips script and style content from DOM-fallback output', async () => {
181
+ const hostile = `<!doctype html><html><head>
182
+ <script>alert("xss-from-head")</script>
183
+ <style>body { color: red; }</style>
184
+ </head><body>
185
+ <script>alert("xss-from-body")</script>
186
+ <p>visible content</p>
187
+ <style>.x{display:none}</style>
188
+ </body></html>`;
189
+ vi.stubGlobal('fetch', vi.fn().mockResolvedValue(new Response(hostile, { status: 200 })));
190
+ const ctx = makeCtx();
191
+ const result = await runTool(ctx, { url: 'https://example.com' });
192
+ expect(result.status).toBe('ok');
193
+ expect(result.content).toContain('visible content');
194
+ // Script/style content should NOT appear
195
+ expect(result.content).not.toContain('xss-from-head');
196
+ expect(result.content).not.toContain('xss-from-body');
197
+ expect(result.content).not.toContain('display:none');
198
+ expect(result.content).not.toContain('color: red');
199
+ });
200
+ it('handles malformed script closing tags', async () => {
201
+ // </script > with trailing space was the CodeQL-flagged regex miss
202
+ const malformed = `<!doctype html><html><body>
203
+ <script >alert("evil")</script >
204
+ <script type="text/plain">alert("sneaky")</script foo="bar">
205
+ <p>real text</p>
206
+ </body></html>`;
207
+ vi.stubGlobal('fetch', vi.fn().mockResolvedValue(new Response(malformed, { status: 200 })));
208
+ const ctx = makeCtx();
209
+ const result = await runTool(ctx, { url: 'https://example.com' });
210
+ expect(result.status).toBe('ok');
211
+ expect(result.content).not.toContain('alert(');
212
+ expect(result.content).not.toContain('evil');
213
+ expect(result.content).not.toContain('sneaky');
214
+ });
215
+ });
216
+ describe('result truncation', () => {
217
+ it('truncates long provider output', async () => {
218
+ const huge = 'x'.repeat(50_000);
219
+ const provider = makeProvider({ text: huge, retrievedUrls: ['https://example.com'] });
220
+ const ctx = makeCtx({ searchProvider: provider });
221
+ const result = await runTool(ctx, { url: 'https://example.com' });
222
+ expect(result.status).toBe('ok');
223
+ expect(result.content.length).toBeLessThan(9_000);
224
+ expect(result.content).toContain('(truncated)');
225
+ });
226
+ });
227
+ });
228
+ //# sourceMappingURL=fetch-url-tool.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch-url-tool.test.js","sourceRoot":"","sources":["../../../src/tools/fetch-url-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 {};
@@ -0,0 +1,226 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ /**
7
+ * MCP Tool Adapter Tests
8
+ *
9
+ * Tests the conversion of MCP discovered tools to ToolDefinition objects:
10
+ * 1. Tool creation with JSON Schema passthrough
11
+ * 2. Tool execution via McpManager.callTool()
12
+ * 3. Registration on ToolRegistry
13
+ * 4. Error classification (connection, auth, generic)
14
+ */
15
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
16
+ import { createMcpToolDefinition, registerMcpTools } from './mcp-tool-adapter.js';
17
+ import { createToolRegistry } from './registry.js';
18
+ import { ConnectionError } from '../errors.js';
19
+ // ---------------------------------------------------------------------------
20
+ // Helpers
21
+ // ---------------------------------------------------------------------------
22
+ function makeMockLogger() {
23
+ return {
24
+ trace: vi.fn(),
25
+ debug: vi.fn(),
26
+ info: vi.fn(),
27
+ warn: vi.fn(),
28
+ error: vi.fn(),
29
+ fatal: vi.fn(),
30
+ child: vi.fn().mockReturnThis(),
31
+ };
32
+ }
33
+ function makeMockContext(overrides) {
34
+ return {
35
+ request: vi.fn(),
36
+ store: vi.fn(),
37
+ env: vi.fn(),
38
+ log: vi.fn(),
39
+ user: { roles: [] },
40
+ signal: AbortSignal.timeout(10000),
41
+ sessionId: 'test-session',
42
+ ...overrides,
43
+ };
44
+ }
45
+ function makeMockMcpManager(overrides) {
46
+ return {
47
+ getDiscoveredTools: overrides?.getDiscoveredTools ?? (() => []),
48
+ callTool: overrides?.callTool ?? vi.fn().mockResolvedValue({
49
+ content: [{ type: 'text', text: 'mock result' }],
50
+ }),
51
+ isMcpTool: vi.fn(),
52
+ startServers: vi.fn(),
53
+ getServerInfo: vi.fn(),
54
+ shutdown: vi.fn(),
55
+ };
56
+ }
57
+ // ---------------------------------------------------------------------------
58
+ // 1. Tool creation with JSON Schema passthrough
59
+ // ---------------------------------------------------------------------------
60
+ describe('createMcpToolDefinition', () => {
61
+ let logger;
62
+ beforeEach(() => {
63
+ logger = makeMockLogger();
64
+ });
65
+ it('creates a ToolDefinition with correct metadata', () => {
66
+ const tool = {
67
+ name: 'github__search_repos',
68
+ originalName: 'search_repos',
69
+ serverName: 'github',
70
+ description: 'Search GitHub repositories',
71
+ parameters: { type: 'object', properties: { query: { type: 'string' } }, required: ['query'] },
72
+ };
73
+ const mcpManager = makeMockMcpManager();
74
+ const def = createMcpToolDefinition(tool, mcpManager, logger);
75
+ expect(def.description).toBe('Search GitHub repositories');
76
+ expect(def.readOnly).toBe(false);
77
+ expect(def.metadata).toEqual({
78
+ category: 'mcp',
79
+ connection: 'github',
80
+ originalName: 'search_repos',
81
+ });
82
+ // Parameters should be defined (jsonSchema passthrough)
83
+ expect(def.parameters).toBeDefined();
84
+ });
85
+ it('execute calls mcpManager.callTool with correct args', async () => {
86
+ const callTool = vi.fn().mockResolvedValue({
87
+ content: [{ type: 'text', text: '{"repos": [{"name": "amodal"}]}' }],
88
+ });
89
+ const mcpManager = makeMockMcpManager({ callTool });
90
+ const tool = {
91
+ name: 'github__search',
92
+ originalName: 'search',
93
+ serverName: 'github',
94
+ description: 'Search',
95
+ parameters: { type: 'object', properties: { q: { type: 'string' } } },
96
+ };
97
+ const def = createMcpToolDefinition(tool, mcpManager, logger);
98
+ const ctx = makeMockContext();
99
+ const result = await def.execute({ q: 'test' }, ctx);
100
+ expect(callTool).toHaveBeenCalledWith('github__search', { q: 'test' });
101
+ expect(result).toEqual({ output: '{"repos": [{"name": "amodal"}]}' });
102
+ // Verify structured logging
103
+ expect(logger.debug).toHaveBeenCalledWith('mcp_tool_call_start', expect.objectContaining({
104
+ tool: 'github__search',
105
+ server: 'github',
106
+ }));
107
+ expect(logger.info).toHaveBeenCalledWith('mcp_tool_call_complete', expect.objectContaining({
108
+ tool: 'github__search',
109
+ isError: false,
110
+ durationMs: expect.any(Number),
111
+ }));
112
+ });
113
+ it('returns error object when MCP tool signals an error', async () => {
114
+ const mcpManager = makeMockMcpManager({
115
+ callTool: vi.fn().mockResolvedValue({
116
+ content: [{ type: 'text', text: 'Permission denied' }],
117
+ isError: true,
118
+ }),
119
+ });
120
+ const tool = {
121
+ name: 'server__action',
122
+ originalName: 'action',
123
+ serverName: 'server',
124
+ description: 'Do action',
125
+ parameters: { type: 'object' },
126
+ };
127
+ const def = createMcpToolDefinition(tool, mcpManager, logger);
128
+ const result = await def.execute({}, makeMockContext());
129
+ expect(result).toEqual({ error: 'Permission denied' });
130
+ expect(logger.info).toHaveBeenCalledWith('mcp_tool_call_complete', expect.objectContaining({
131
+ isError: true,
132
+ }));
133
+ });
134
+ it('throws ConnectionError on ECONNREFUSED', async () => {
135
+ const mcpManager = makeMockMcpManager({
136
+ callTool: vi.fn().mockRejectedValue(new Error('connect ECONNREFUSED 127.0.0.1:3000')),
137
+ });
138
+ const tool = {
139
+ name: 'broken__tool',
140
+ originalName: 'tool',
141
+ serverName: 'broken',
142
+ description: 'Broken',
143
+ parameters: { type: 'object' },
144
+ };
145
+ const def = createMcpToolDefinition(tool, mcpManager, logger);
146
+ await expect(def.execute({}, makeMockContext())).rejects.toThrow(ConnectionError);
147
+ await expect(def.execute({}, makeMockContext())).rejects.toThrow(/unreachable/);
148
+ expect(logger.error).toHaveBeenCalledWith('mcp_tool_call_failed', expect.objectContaining({
149
+ tool: 'broken__tool',
150
+ }));
151
+ });
152
+ it('throws ConnectionError on auth failure', async () => {
153
+ const mcpManager = makeMockMcpManager({
154
+ callTool: vi.fn().mockRejectedValue(new Error('401 Unauthorized')),
155
+ });
156
+ const tool = {
157
+ name: 'secure__tool',
158
+ originalName: 'tool',
159
+ serverName: 'secure',
160
+ description: 'Secure',
161
+ parameters: { type: 'object' },
162
+ };
163
+ const def = createMcpToolDefinition(tool, mcpManager, logger);
164
+ await expect(def.execute({}, makeMockContext())).rejects.toThrow(ConnectionError);
165
+ await expect(def.execute({}, makeMockContext())).rejects.toThrow(/authentication failed/i);
166
+ });
167
+ it('throws ConnectionError when ctx.signal is already aborted (timeout)', async () => {
168
+ const mcpManager = makeMockMcpManager({
169
+ callTool: vi.fn().mockImplementation(() => new Promise(() => { })), // never resolves
170
+ });
171
+ const tool = {
172
+ name: 'slow__tool',
173
+ originalName: 'tool',
174
+ serverName: 'slow',
175
+ description: 'Slow',
176
+ parameters: { type: 'object' },
177
+ };
178
+ const def = createMcpToolDefinition(tool, mcpManager, logger);
179
+ const abortController = new AbortController();
180
+ abortController.abort();
181
+ const ctx = makeMockContext({ signal: abortController.signal });
182
+ await expect(def.execute({}, ctx)).rejects.toThrow(ConnectionError);
183
+ await expect(def.execute({}, ctx)).rejects.toThrow(/timed out/);
184
+ });
185
+ });
186
+ // ---------------------------------------------------------------------------
187
+ // 3. Registration on ToolRegistry
188
+ // ---------------------------------------------------------------------------
189
+ describe('registerMcpTools', () => {
190
+ it('registers all discovered tools on the registry', () => {
191
+ const logger = makeMockLogger();
192
+ const mcpManager = makeMockMcpManager({
193
+ getDiscoveredTools: () => [
194
+ { name: 'github__search', originalName: 'search', serverName: 'github', description: 'Search repos', parameters: { type: 'object', properties: { q: { type: 'string' } } } },
195
+ { name: 'github__get_repo', originalName: 'get_repo', serverName: 'github', description: 'Get repo', parameters: { type: 'object', properties: { owner: { type: 'string' }, repo: { type: 'string' } } } },
196
+ { name: 'slack__send', originalName: 'send', serverName: 'slack', description: 'Send message', parameters: { type: 'object', properties: { channel: { type: 'string' }, text: { type: 'string' } } } },
197
+ ],
198
+ });
199
+ const registry = createToolRegistry();
200
+ const count = registerMcpTools(registry, mcpManager, logger);
201
+ expect(count).toBe(3);
202
+ expect(registry.names()).toContain('github__search');
203
+ expect(registry.names()).toContain('github__get_repo');
204
+ expect(registry.names()).toContain('slack__send');
205
+ expect(registry.size).toBe(3);
206
+ // Each tool should have correct metadata
207
+ const searchTool = registry.get('github__search');
208
+ expect(searchTool).toBeDefined();
209
+ expect(searchTool.metadata?.category).toBe('mcp');
210
+ expect(searchTool.metadata?.connection).toBe('github');
211
+ // Log event
212
+ expect(logger.info).toHaveBeenCalledWith('mcp_tools_registered', expect.objectContaining({
213
+ count: 3,
214
+ }));
215
+ });
216
+ it('returns 0 and does not log when no tools discovered', () => {
217
+ const logger = makeMockLogger();
218
+ const mcpManager = makeMockMcpManager({ getDiscoveredTools: () => [] });
219
+ const registry = createToolRegistry();
220
+ const count = registerMcpTools(registry, mcpManager, logger);
221
+ expect(count).toBe(0);
222
+ expect(registry.size).toBe(0);
223
+ expect(logger.info).not.toHaveBeenCalledWith('mcp_tools_registered', expect.anything());
224
+ });
225
+ });
226
+ //# sourceMappingURL=mcp-tool-adapter.test.js.map