@roj-ai/sdk 0.1.1 → 0.1.4

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 (493) hide show
  1. package/dist/bootstrap.js +191 -0
  2. package/dist/bootstrap.js.map +1 -0
  3. package/dist/builtin-events.js +8 -0
  4. package/dist/builtin-events.js.map +1 -0
  5. package/dist/bun-platform/fs.js +39 -0
  6. package/dist/bun-platform/fs.js.map +1 -0
  7. package/dist/bun-platform/index.js +18 -0
  8. package/dist/bun-platform/index.js.map +1 -0
  9. package/dist/bun-platform/process.js +21 -0
  10. package/dist/bun-platform/process.js.map +1 -0
  11. package/dist/config.js +54 -0
  12. package/dist/config.js.map +1 -0
  13. package/dist/config.test.js +155 -0
  14. package/dist/config.test.js.map +1 -0
  15. package/dist/core/agent-loop.integration.test.js +414 -0
  16. package/dist/core/agent-loop.integration.test.js.map +1 -0
  17. package/dist/core/agents/agent-config.test.js +194 -0
  18. package/dist/core/agents/agent-config.test.js.map +1 -0
  19. package/dist/core/agents/agent-roles.js +25 -0
  20. package/dist/core/agents/agent-roles.js.map +1 -0
  21. package/dist/core/agents/agent-shutdown.test.js +180 -0
  22. package/dist/core/agents/agent-shutdown.test.js.map +1 -0
  23. package/dist/core/agents/agent.js +1205 -0
  24. package/dist/core/agents/agent.js.map +1 -0
  25. package/dist/core/agents/agent.test.js +313 -0
  26. package/dist/core/agents/agent.test.js.map +1 -0
  27. package/dist/core/agents/communicator.js +13 -0
  28. package/dist/core/agents/communicator.js.map +1 -0
  29. package/dist/core/agents/config.js +5 -0
  30. package/dist/core/agents/config.js.map +1 -0
  31. package/dist/core/agents/context.js +2 -0
  32. package/dist/core/agents/context.js.map +1 -0
  33. package/dist/core/agents/debounce.js +74 -0
  34. package/dist/core/agents/debounce.js.map +1 -0
  35. package/dist/core/agents/handler-events.test.js +115 -0
  36. package/dist/core/agents/handler-events.test.js.map +1 -0
  37. package/dist/core/agents/index.js +2 -0
  38. package/dist/core/agents/index.js.map +1 -0
  39. package/dist/core/agents/response-sanitizer.js +46 -0
  40. package/dist/core/agents/response-sanitizer.js.map +1 -0
  41. package/dist/core/agents/response-sanitizer.test.js +101 -0
  42. package/dist/core/agents/response-sanitizer.test.js.map +1 -0
  43. package/dist/core/agents/retry.js +105 -0
  44. package/dist/core/agents/retry.js.map +1 -0
  45. package/dist/core/agents/schema.js +39 -0
  46. package/dist/core/agents/schema.js.map +1 -0
  47. package/dist/core/agents/state.js +90 -0
  48. package/dist/core/agents/state.js.map +1 -0
  49. package/dist/core/context/state.js +23 -0
  50. package/dist/core/context/state.js.map +1 -0
  51. package/dist/core/errors.js +38 -0
  52. package/dist/core/errors.js.map +1 -0
  53. package/dist/core/event-sourcing.integration.test.js +154 -0
  54. package/dist/core/event-sourcing.integration.test.js.map +1 -0
  55. package/dist/core/events/base-event-store.js +201 -0
  56. package/dist/core/events/base-event-store.js.map +1 -0
  57. package/dist/core/events/event-store.js +26 -0
  58. package/dist/core/events/event-store.js.map +1 -0
  59. package/dist/core/events/file.js +320 -0
  60. package/dist/core/events/file.js.map +1 -0
  61. package/dist/core/events/file.test.js +284 -0
  62. package/dist/core/events/file.test.js.map +1 -0
  63. package/dist/core/events/index.js +3 -0
  64. package/dist/core/events/index.js.map +1 -0
  65. package/dist/core/events/memory.js +101 -0
  66. package/dist/core/events/memory.js.map +1 -0
  67. package/dist/core/events/memory.test.js +502 -0
  68. package/dist/core/events/memory.test.js.map +1 -0
  69. package/dist/core/events/metadata-utils.js +107 -0
  70. package/dist/core/events/metadata-utils.js.map +1 -0
  71. package/dist/core/events/test-helpers.js +15 -0
  72. package/dist/core/events/test-helpers.js.map +1 -0
  73. package/dist/core/events/types.js +21 -0
  74. package/dist/core/events/types.js.map +1 -0
  75. package/dist/core/file-store/file-store.js +250 -0
  76. package/dist/core/file-store/file-store.js.map +1 -0
  77. package/dist/core/file-store/types.js +7 -0
  78. package/dist/core/file-store/types.js.map +1 -0
  79. package/dist/core/image/image-processor.js +106 -0
  80. package/dist/core/image/image-processor.js.map +1 -0
  81. package/dist/core/image/image-processor.test.js +171 -0
  82. package/dist/core/image/image-processor.test.js.map +1 -0
  83. package/dist/core/image/index.js +4 -0
  84. package/dist/core/image/index.js.map +1 -0
  85. package/dist/core/image/noop-resizer.js +6 -0
  86. package/dist/core/image/noop-resizer.js.map +1 -0
  87. package/dist/core/image/types.js +2 -0
  88. package/dist/core/image/types.js.map +1 -0
  89. package/dist/core/image/vips-resizer.js +100 -0
  90. package/dist/core/image/vips-resizer.js.map +1 -0
  91. package/dist/core/image/vips-resizer.test.js +324 -0
  92. package/dist/core/image/vips-resizer.test.js.map +1 -0
  93. package/dist/core/llm/anthropic.js +396 -0
  94. package/dist/core/llm/anthropic.js.map +1 -0
  95. package/dist/core/llm/anthropic.test.js +434 -0
  96. package/dist/core/llm/anthropic.test.js.map +1 -0
  97. package/dist/core/llm/cache-breakpoints.js +37 -0
  98. package/dist/core/llm/cache-breakpoints.js.map +1 -0
  99. package/dist/core/llm/cache-live.test.js +137 -0
  100. package/dist/core/llm/cache-live.test.js.map +1 -0
  101. package/dist/core/llm/index.js +9 -0
  102. package/dist/core/llm/index.js.map +1 -0
  103. package/dist/core/llm/llm-log-types.js +12 -0
  104. package/dist/core/llm/llm-log-types.js.map +1 -0
  105. package/dist/core/llm/logger.js +241 -0
  106. package/dist/core/llm/logger.js.map +1 -0
  107. package/dist/core/llm/logger.test.js +228 -0
  108. package/dist/core/llm/logger.test.js.map +1 -0
  109. package/dist/core/llm/logging-provider.js +49 -0
  110. package/dist/core/llm/logging-provider.js.map +1 -0
  111. package/dist/core/llm/middleware.js +114 -0
  112. package/dist/core/llm/middleware.js.map +1 -0
  113. package/dist/core/llm/mock.js +186 -0
  114. package/dist/core/llm/mock.js.map +1 -0
  115. package/dist/core/llm/mock.test.js +318 -0
  116. package/dist/core/llm/mock.test.js.map +1 -0
  117. package/dist/core/llm/openrouter-mapping.test.js +125 -0
  118. package/dist/core/llm/openrouter-mapping.test.js.map +1 -0
  119. package/dist/core/llm/openrouter.js +298 -0
  120. package/dist/core/llm/openrouter.js.map +1 -0
  121. package/dist/core/llm/openrouter.test.js +377 -0
  122. package/dist/core/llm/openrouter.test.js.map +1 -0
  123. package/dist/core/llm/provider-integration.test.js +350 -0
  124. package/dist/core/llm/provider-integration.test.js.map +1 -0
  125. package/dist/core/llm/provider.js +18 -0
  126. package/dist/core/llm/provider.js.map +1 -0
  127. package/dist/core/llm/routing-provider.js +52 -0
  128. package/dist/core/llm/routing-provider.js.map +1 -0
  129. package/dist/core/llm/routing-provider.test.js +94 -0
  130. package/dist/core/llm/routing-provider.test.js.map +1 -0
  131. package/dist/core/llm/schema.js +31 -0
  132. package/dist/core/llm/schema.js.map +1 -0
  133. package/dist/core/llm/snapshot-fetch.js +122 -0
  134. package/dist/core/llm/snapshot-fetch.js.map +1 -0
  135. package/dist/core/llm/snapshot-middleware.js +142 -0
  136. package/dist/core/llm/snapshot-middleware.js.map +1 -0
  137. package/dist/core/llm/snapshot-middleware.test.js +144 -0
  138. package/dist/core/llm/snapshot-middleware.test.js.map +1 -0
  139. package/dist/core/llm/state.js +48 -0
  140. package/dist/core/llm/state.js.map +1 -0
  141. package/dist/core/llm/tokens.js +40 -0
  142. package/dist/core/llm/tokens.js.map +1 -0
  143. package/dist/core/multi-agent.integration.test.js +298 -0
  144. package/dist/core/multi-agent.integration.test.js.map +1 -0
  145. package/dist/core/plugin-hooks.integration.test.js +344 -0
  146. package/dist/core/plugin-hooks.integration.test.js.map +1 -0
  147. package/dist/core/plugins/hook-types.js +5 -0
  148. package/dist/core/plugins/hook-types.js.map +1 -0
  149. package/dist/core/plugins/index.js +5 -0
  150. package/dist/core/plugins/index.js.map +1 -0
  151. package/dist/core/plugins/plugin-builder.js +321 -0
  152. package/dist/core/plugins/plugin-builder.js.map +1 -0
  153. package/dist/core/preset/config.js +54 -0
  154. package/dist/core/preset/config.js.map +1 -0
  155. package/dist/core/preset/index.js +6 -0
  156. package/dist/core/preset/index.js.map +1 -0
  157. package/dist/core/preset/preset-builder.js +63 -0
  158. package/dist/core/preset/preset-builder.js.map +1 -0
  159. package/dist/core/session-lifecycle.integration.test.js +159 -0
  160. package/dist/core/session-lifecycle.integration.test.js.map +1 -0
  161. package/dist/core/sessions/apply-event.js +41 -0
  162. package/dist/core/sessions/apply-event.js.map +1 -0
  163. package/dist/core/sessions/context.js +2 -0
  164. package/dist/core/sessions/context.js.map +1 -0
  165. package/dist/core/sessions/fork-utils.js +42 -0
  166. package/dist/core/sessions/fork-utils.js.map +1 -0
  167. package/dist/core/sessions/fork-utils.test.js +129 -0
  168. package/dist/core/sessions/fork-utils.test.js.map +1 -0
  169. package/dist/core/sessions/reducer.js +55 -0
  170. package/dist/core/sessions/reducer.js.map +1 -0
  171. package/dist/core/sessions/schema.js +66 -0
  172. package/dist/core/sessions/schema.js.map +1 -0
  173. package/dist/core/sessions/session-environment.js +2 -0
  174. package/dist/core/sessions/session-environment.js.map +1 -0
  175. package/dist/core/sessions/session-manager.js +650 -0
  176. package/dist/core/sessions/session-manager.js.map +1 -0
  177. package/dist/core/sessions/session-store.js +118 -0
  178. package/dist/core/sessions/session-store.js.map +1 -0
  179. package/dist/core/sessions/session.js +675 -0
  180. package/dist/core/sessions/session.js.map +1 -0
  181. package/dist/core/sessions/session.test.js +1095 -0
  182. package/dist/core/sessions/session.test.js.map +1 -0
  183. package/dist/core/sessions/state.js +377 -0
  184. package/dist/core/sessions/state.js.map +1 -0
  185. package/dist/core/system.js +66 -0
  186. package/dist/core/system.js.map +1 -0
  187. package/dist/core/tools/context.js +2 -0
  188. package/dist/core/tools/context.js.map +1 -0
  189. package/dist/core/tools/definition.js +4 -0
  190. package/dist/core/tools/definition.js.map +1 -0
  191. package/dist/core/tools/executor.js +82 -0
  192. package/dist/core/tools/executor.js.map +1 -0
  193. package/dist/core/tools/executor.test.js +143 -0
  194. package/dist/core/tools/executor.test.js.map +1 -0
  195. package/dist/core/tools/index.js +4 -0
  196. package/dist/core/tools/index.js.map +1 -0
  197. package/dist/core/tools/schema.js +20 -0
  198. package/dist/core/tools/schema.js.map +1 -0
  199. package/dist/core/tools/state.js +29 -0
  200. package/dist/core/tools/state.js.map +1 -0
  201. package/dist/index.js +70 -0
  202. package/dist/index.js.map +1 -0
  203. package/dist/lib/json/index.js +5 -0
  204. package/dist/lib/json/index.js.map +1 -0
  205. package/dist/lib/logger/console.js +147 -0
  206. package/dist/lib/logger/console.js.map +1 -0
  207. package/dist/lib/logger/console.test.js +258 -0
  208. package/dist/lib/logger/console.test.js.map +1 -0
  209. package/dist/lib/logger/file.js +54 -0
  210. package/dist/lib/logger/file.js.map +1 -0
  211. package/dist/lib/logger/index.js +4 -0
  212. package/dist/lib/logger/index.js.map +1 -0
  213. package/dist/lib/logger/logger.js +28 -0
  214. package/dist/lib/logger/logger.js.map +1 -0
  215. package/dist/lib/logger/ring-buffer.js +61 -0
  216. package/dist/lib/logger/ring-buffer.js.map +1 -0
  217. package/dist/lib/logger/tee.js +43 -0
  218. package/dist/lib/logger/tee.js.map +1 -0
  219. package/dist/lib/mime.js +22 -0
  220. package/dist/lib/mime.js.map +1 -0
  221. package/dist/lib/never.js +4 -0
  222. package/dist/lib/never.js.map +1 -0
  223. package/dist/lib/utils/hash.js +35 -0
  224. package/dist/lib/utils/hash.js.map +1 -0
  225. package/dist/lib/utils/result.js +21 -0
  226. package/dist/lib/utils/result.js.map +1 -0
  227. package/dist/platform/fs.js +8 -0
  228. package/dist/platform/fs.js.map +1 -0
  229. package/dist/platform/index.js +9 -0
  230. package/dist/platform/index.js.map +1 -0
  231. package/dist/platform/process.js +8 -0
  232. package/dist/platform/process.js.map +1 -0
  233. package/dist/plugins/agent-status/plugin.js +77 -0
  234. package/dist/plugins/agent-status/plugin.js.map +1 -0
  235. package/dist/plugins/agents/agents.integration.test.js +683 -0
  236. package/dist/plugins/agents/agents.integration.test.js.map +1 -0
  237. package/dist/plugins/agents/index.js +2 -0
  238. package/dist/plugins/agents/index.js.map +1 -0
  239. package/dist/plugins/agents/plugin.js +199 -0
  240. package/dist/plugins/agents/plugin.js.map +1 -0
  241. package/dist/plugins/context-compact/context-compact.integration.test.js +174 -0
  242. package/dist/plugins/context-compact/context-compact.integration.test.js.map +1 -0
  243. package/dist/plugins/context-compact/context-compactor.js +238 -0
  244. package/dist/plugins/context-compact/context-compactor.js.map +1 -0
  245. package/dist/plugins/context-compact/context-compactor.test.js +763 -0
  246. package/dist/plugins/context-compact/context-compactor.test.js.map +1 -0
  247. package/dist/plugins/context-compact/history-offloader.js +42 -0
  248. package/dist/plugins/context-compact/history-offloader.js.map +1 -0
  249. package/dist/plugins/context-compact/history-offloader.test.js +77 -0
  250. package/dist/plugins/context-compact/history-offloader.test.js.map +1 -0
  251. package/dist/plugins/context-compact/index.js +4 -0
  252. package/dist/plugins/context-compact/index.js.map +1 -0
  253. package/dist/plugins/context-compact/plugin.js +37 -0
  254. package/dist/plugins/context-compact/plugin.js.map +1 -0
  255. package/dist/plugins/filesystem/filesystem.integration.test.js +411 -0
  256. package/dist/plugins/filesystem/filesystem.integration.test.js.map +1 -0
  257. package/dist/plugins/filesystem/helpers.js +170 -0
  258. package/dist/plugins/filesystem/helpers.js.map +1 -0
  259. package/dist/plugins/filesystem/index.js +3 -0
  260. package/dist/plugins/filesystem/index.js.map +1 -0
  261. package/dist/plugins/filesystem/listing.js +247 -0
  262. package/dist/plugins/filesystem/listing.js.map +1 -0
  263. package/dist/plugins/filesystem/plugin.js +364 -0
  264. package/dist/plugins/filesystem/plugin.js.map +1 -0
  265. package/dist/plugins/filesystem/schema.js +2 -0
  266. package/dist/plugins/filesystem/schema.js.map +1 -0
  267. package/dist/plugins/git-status/index.js +2 -0
  268. package/dist/plugins/git-status/index.js.map +1 -0
  269. package/dist/plugins/git-status/plugin.js +144 -0
  270. package/dist/plugins/git-status/plugin.js.map +1 -0
  271. package/dist/plugins/limits-guard/config.js +5 -0
  272. package/dist/plugins/limits-guard/config.js.map +1 -0
  273. package/dist/plugins/limits-guard/index.js +3 -0
  274. package/dist/plugins/limits-guard/index.js.map +1 -0
  275. package/dist/plugins/limits-guard/limit-guard.js +125 -0
  276. package/dist/plugins/limits-guard/limit-guard.js.map +1 -0
  277. package/dist/plugins/limits-guard/limit-guard.test.js +121 -0
  278. package/dist/plugins/limits-guard/limit-guard.test.js.map +1 -0
  279. package/dist/plugins/limits-guard/limits-guard.integration.test.js +378 -0
  280. package/dist/plugins/limits-guard/limits-guard.integration.test.js.map +1 -0
  281. package/dist/plugins/limits-guard/plugin.js +240 -0
  282. package/dist/plugins/limits-guard/plugin.js.map +1 -0
  283. package/dist/plugins/llm-debug/index.js +2 -0
  284. package/dist/plugins/llm-debug/index.js.map +1 -0
  285. package/dist/plugins/llm-debug/llm-debug.integration.test.js +157 -0
  286. package/dist/plugins/llm-debug/llm-debug.integration.test.js.map +1 -0
  287. package/dist/plugins/llm-debug/plugin.js +148 -0
  288. package/dist/plugins/llm-debug/plugin.js.map +1 -0
  289. package/dist/plugins/logs/index.js +2 -0
  290. package/dist/plugins/logs/index.js.map +1 -0
  291. package/dist/plugins/logs/plugin.js +38 -0
  292. package/dist/plugins/logs/plugin.js.map +1 -0
  293. package/dist/plugins/mailbox/helpers.js +66 -0
  294. package/dist/plugins/mailbox/helpers.js.map +1 -0
  295. package/dist/plugins/mailbox/index.js +9 -0
  296. package/dist/plugins/mailbox/index.js.map +1 -0
  297. package/dist/plugins/mailbox/mailbox.integration.test.js +605 -0
  298. package/dist/plugins/mailbox/mailbox.integration.test.js.map +1 -0
  299. package/dist/plugins/mailbox/plugin.js +204 -0
  300. package/dist/plugins/mailbox/plugin.js.map +1 -0
  301. package/dist/plugins/mailbox/prompts.js +93 -0
  302. package/dist/plugins/mailbox/prompts.js.map +1 -0
  303. package/dist/plugins/mailbox/query.js +38 -0
  304. package/dist/plugins/mailbox/query.js.map +1 -0
  305. package/dist/plugins/mailbox/schema.js +32 -0
  306. package/dist/plugins/mailbox/schema.js.map +1 -0
  307. package/dist/plugins/mailbox/state.js +41 -0
  308. package/dist/plugins/mailbox/state.js.map +1 -0
  309. package/dist/plugins/resources/index.js +4 -0
  310. package/dist/plugins/resources/index.js.map +1 -0
  311. package/dist/plugins/resources/manifest.js +20 -0
  312. package/dist/plugins/resources/manifest.js.map +1 -0
  313. package/dist/plugins/resources/plugin.js +171 -0
  314. package/dist/plugins/resources/plugin.js.map +1 -0
  315. package/dist/plugins/resources/post-inject.js +32 -0
  316. package/dist/plugins/resources/post-inject.js.map +1 -0
  317. package/dist/plugins/resources/state.js +16 -0
  318. package/dist/plugins/resources/state.js.map +1 -0
  319. package/dist/plugins/result-eviction/index.js +2 -0
  320. package/dist/plugins/result-eviction/index.js.map +1 -0
  321. package/dist/plugins/result-eviction/plugin.js +43 -0
  322. package/dist/plugins/result-eviction/plugin.js.map +1 -0
  323. package/dist/plugins/result-eviction/result-eviction.integration.test.js +217 -0
  324. package/dist/plugins/result-eviction/result-eviction.integration.test.js.map +1 -0
  325. package/dist/plugins/services/plugin.js +453 -0
  326. package/dist/plugins/services/plugin.js.map +1 -0
  327. package/dist/plugins/services/port-pool.js +70 -0
  328. package/dist/plugins/services/port-pool.js.map +1 -0
  329. package/dist/plugins/services/prompt.js +40 -0
  330. package/dist/plugins/services/prompt.js.map +1 -0
  331. package/dist/plugins/services/schema.js +9 -0
  332. package/dist/plugins/services/schema.js.map +1 -0
  333. package/dist/plugins/services/service.js +470 -0
  334. package/dist/plugins/services/service.js.map +1 -0
  335. package/dist/plugins/services/services.integration.test.js +485 -0
  336. package/dist/plugins/services/services.integration.test.js.map +1 -0
  337. package/dist/plugins/session-lifecycle/index.js +2 -0
  338. package/dist/plugins/session-lifecycle/index.js.map +1 -0
  339. package/dist/plugins/session-lifecycle/plugin.js +273 -0
  340. package/dist/plugins/session-lifecycle/plugin.js.map +1 -0
  341. package/dist/plugins/session-lifecycle/session-lifecycle.integration.test.js +498 -0
  342. package/dist/plugins/session-lifecycle/session-lifecycle.integration.test.js.map +1 -0
  343. package/dist/plugins/session-state/plugin.js +159 -0
  344. package/dist/plugins/session-state/plugin.js.map +1 -0
  345. package/dist/plugins/session-stats/index.js +3 -0
  346. package/dist/plugins/session-stats/index.js.map +1 -0
  347. package/dist/plugins/session-stats/plugin.js +81 -0
  348. package/dist/plugins/session-stats/plugin.js.map +1 -0
  349. package/dist/plugins/shell/executor.js +339 -0
  350. package/dist/plugins/shell/executor.js.map +1 -0
  351. package/dist/plugins/shell/index.js +6 -0
  352. package/dist/plugins/shell/index.js.map +1 -0
  353. package/dist/plugins/shell/plugin.js +66 -0
  354. package/dist/plugins/shell/plugin.js.map +1 -0
  355. package/dist/plugins/shell/shell.integration.test.js +234 -0
  356. package/dist/plugins/shell/shell.integration.test.js.map +1 -0
  357. package/dist/plugins/shell/shell.test.js +236 -0
  358. package/dist/plugins/shell/shell.test.js.map +1 -0
  359. package/dist/plugins/skills/discovery.js +205 -0
  360. package/dist/plugins/skills/discovery.js.map +1 -0
  361. package/dist/plugins/skills/discovery.test.js +312 -0
  362. package/dist/plugins/skills/discovery.test.js.map +1 -0
  363. package/dist/plugins/skills/index.js +12 -0
  364. package/dist/plugins/skills/index.js.map +1 -0
  365. package/dist/plugins/skills/plugin.js +293 -0
  366. package/dist/plugins/skills/plugin.js.map +1 -0
  367. package/dist/plugins/skills/prompts.js +70 -0
  368. package/dist/plugins/skills/prompts.js.map +1 -0
  369. package/dist/plugins/skills/schema.js +18 -0
  370. package/dist/plugins/skills/schema.js.map +1 -0
  371. package/dist/plugins/skills/skills.integration.test.js +475 -0
  372. package/dist/plugins/skills/skills.integration.test.js.map +1 -0
  373. package/dist/plugins/snapshotting/index.js +3 -0
  374. package/dist/plugins/snapshotting/index.js.map +1 -0
  375. package/dist/plugins/snapshotting/jj-snapshotter.js +106 -0
  376. package/dist/plugins/snapshotting/jj-snapshotter.js.map +1 -0
  377. package/dist/plugins/snapshotting/plugin.js +28 -0
  378. package/dist/plugins/snapshotting/plugin.js.map +1 -0
  379. package/dist/plugins/snapshotting/snapshotter.js +2 -0
  380. package/dist/plugins/snapshotting/snapshotter.js.map +1 -0
  381. package/dist/plugins/todo/index.js +7 -0
  382. package/dist/plugins/todo/index.js.map +1 -0
  383. package/dist/plugins/todo/plugin.js +319 -0
  384. package/dist/plugins/todo/plugin.js.map +1 -0
  385. package/dist/plugins/todo/prompts.js +54 -0
  386. package/dist/plugins/todo/prompts.js.map +1 -0
  387. package/dist/plugins/todo/schema.js +18 -0
  388. package/dist/plugins/todo/schema.js.map +1 -0
  389. package/dist/plugins/todo/todo.integration.test.js +605 -0
  390. package/dist/plugins/todo/todo.integration.test.js.map +1 -0
  391. package/dist/plugins/uploads/index.js +8 -0
  392. package/dist/plugins/uploads/index.js.map +1 -0
  393. package/dist/plugins/uploads/plugin.js +346 -0
  394. package/dist/plugins/uploads/plugin.js.map +1 -0
  395. package/dist/plugins/uploads/preprocessor.js +44 -0
  396. package/dist/plugins/uploads/preprocessor.js.map +1 -0
  397. package/dist/plugins/uploads/preprocessors/image-classifier.js +127 -0
  398. package/dist/plugins/uploads/preprocessors/image-classifier.js.map +1 -0
  399. package/dist/plugins/uploads/preprocessors/index.js +7 -0
  400. package/dist/plugins/uploads/preprocessors/index.js.map +1 -0
  401. package/dist/plugins/uploads/preprocessors/markitdown-preprocessor.js +204 -0
  402. package/dist/plugins/uploads/preprocessors/markitdown-preprocessor.js.map +1 -0
  403. package/dist/plugins/uploads/preprocessors/zip-preprocessor.js +172 -0
  404. package/dist/plugins/uploads/preprocessors/zip-preprocessor.js.map +1 -0
  405. package/dist/plugins/uploads/schema.js +20 -0
  406. package/dist/plugins/uploads/schema.js.map +1 -0
  407. package/dist/plugins/uploads/state.js +22 -0
  408. package/dist/plugins/uploads/state.js.map +1 -0
  409. package/dist/plugins/uploads/uploads.integration.test.js +496 -0
  410. package/dist/plugins/uploads/uploads.integration.test.js.map +1 -0
  411. package/dist/plugins/user-chat/index.js +5 -0
  412. package/dist/plugins/user-chat/index.js.map +1 -0
  413. package/dist/plugins/user-chat/plugin.js +544 -0
  414. package/dist/plugins/user-chat/plugin.js.map +1 -0
  415. package/dist/plugins/user-chat/prompts.js +29 -0
  416. package/dist/plugins/user-chat/prompts.js.map +1 -0
  417. package/dist/plugins/user-chat/schema.js +46 -0
  418. package/dist/plugins/user-chat/schema.js.map +1 -0
  419. package/dist/plugins/user-chat/user-chat.integration.test.js +668 -0
  420. package/dist/plugins/user-chat/user-chat.integration.test.js.map +1 -0
  421. package/dist/plugins/workers/context.js +143 -0
  422. package/dist/plugins/workers/context.js.map +1 -0
  423. package/dist/plugins/workers/definition.js +30 -0
  424. package/dist/plugins/workers/definition.js.map +1 -0
  425. package/dist/plugins/workers/index.js +7 -0
  426. package/dist/plugins/workers/index.js.map +1 -0
  427. package/dist/plugins/workers/plugin.js +578 -0
  428. package/dist/plugins/workers/plugin.js.map +1 -0
  429. package/dist/plugins/workers/worker.js +18 -0
  430. package/dist/plugins/workers/worker.js.map +1 -0
  431. package/dist/plugins/workers/workers.integration.test.js +629 -0
  432. package/dist/plugins/workers/workers.integration.test.js.map +1 -0
  433. package/dist/prompts/base.js +239 -0
  434. package/dist/prompts/base.js.map +1 -0
  435. package/dist/prompts/builder.js +131 -0
  436. package/dist/prompts/builder.js.map +1 -0
  437. package/dist/prompts/index.js +20 -0
  438. package/dist/prompts/index.js.map +1 -0
  439. package/dist/prompts/macros.js +26 -0
  440. package/dist/prompts/macros.js.map +1 -0
  441. package/dist/prompts/macros.test.js +80 -0
  442. package/dist/prompts/macros.test.js.map +1 -0
  443. package/dist/testing/bootstrap-for-testing.js +28 -0
  444. package/dist/testing/bootstrap-for-testing.js.map +1 -0
  445. package/dist/testing/index.js +7 -0
  446. package/dist/testing/index.js.map +1 -0
  447. package/dist/testing/node-platform.js +65 -0
  448. package/dist/testing/node-platform.js.map +1 -0
  449. package/dist/testing/notification-collector.js +82 -0
  450. package/dist/testing/notification-collector.js.map +1 -0
  451. package/dist/testing/preset-helpers.js +37 -0
  452. package/dist/testing/preset-helpers.js.map +1 -0
  453. package/dist/testing/test-harness.js +226 -0
  454. package/dist/testing/test-harness.js.map +1 -0
  455. package/dist/testing/test-harness.test.js +51 -0
  456. package/dist/testing/test-harness.test.js.map +1 -0
  457. package/dist/testing/wait-helpers.js +64 -0
  458. package/dist/testing/wait-helpers.js.map +1 -0
  459. package/dist/transport/adapter/client-adapter.js +64 -0
  460. package/dist/transport/adapter/client-adapter.js.map +1 -0
  461. package/dist/transport/adapter/index.js +24 -0
  462. package/dist/transport/adapter/index.js.map +1 -0
  463. package/dist/transport/adapter/server-adapter.js +73 -0
  464. package/dist/transport/adapter/server-adapter.js.map +1 -0
  465. package/dist/transport/adapter/types.js +8 -0
  466. package/dist/transport/adapter/types.js.map +1 -0
  467. package/dist/transport/http/app.js +86 -0
  468. package/dist/transport/http/app.js.map +1 -0
  469. package/dist/transport/http/index.js +6 -0
  470. package/dist/transport/http/index.js.map +1 -0
  471. package/dist/transport/http/middleware/bearer-auth.js +33 -0
  472. package/dist/transport/http/middleware/bearer-auth.js.map +1 -0
  473. package/dist/transport/http/middleware/error-handler.js +56 -0
  474. package/dist/transport/http/middleware/error-handler.js.map +1 -0
  475. package/dist/transport/http/routes/files.js +237 -0
  476. package/dist/transport/http/routes/files.js.map +1 -0
  477. package/dist/transport/http/routes/resources.js +77 -0
  478. package/dist/transport/http/routes/resources.js.map +1 -0
  479. package/dist/transport/http/routes/rpc.integration.test.js +189 -0
  480. package/dist/transport/http/routes/rpc.integration.test.js.map +1 -0
  481. package/dist/transport/http/routes/rpc.js +110 -0
  482. package/dist/transport/http/routes/rpc.js.map +1 -0
  483. package/dist/transport/http/routes/rpc.test.js +316 -0
  484. package/dist/transport/http/routes/rpc.test.js.map +1 -0
  485. package/dist/transport/http/routes/upload.js +205 -0
  486. package/dist/transport/http/routes/upload.js.map +1 -0
  487. package/dist/transport/rpc/index.js +7 -0
  488. package/dist/transport/rpc/index.js.map +1 -0
  489. package/dist/transport/rpc/methods.js +8 -0
  490. package/dist/transport/rpc/methods.js.map +1 -0
  491. package/dist/user-config.js +14 -0
  492. package/dist/user-config.js.map +1 -0
  493. package/package.json +47 -57
@@ -0,0 +1,683 @@
1
+ import { describe, expect, it } from 'bun:test';
2
+ import z from 'zod/v4';
3
+ import { AgentId } from '../../core/agents/schema.js';
4
+ import { agentEvents } from '../../core/agents/state.js';
5
+ import { MockLLMProvider } from '../../core/llm/mock.js';
6
+ import { ToolCallId } from '../../core/tools/schema.js';
7
+ import { createMultiAgentPreset, createTestPreset, TestHarness } from '../../testing/index.js';
8
+ describe('agents plugin', () => {
9
+ // =========================================================================
10
+ // start_<agent> tool
11
+ // =========================================================================
12
+ describe('start_<agent> tool', () => {
13
+ it('orchestrator calls start_worker → child agent spawned → agent_spawned event', async () => {
14
+ let orchestratorCalls = 0;
15
+ const harness = new TestHarness({
16
+ presets: [createMultiAgentPreset([
17
+ { name: 'worker', system: 'Worker agent.', tools: [], agents: [] },
18
+ ], { orchestratorSystem: 'Orchestrator agent.' })],
19
+ mockHandler: (request) => {
20
+ if (request.systemPrompt.includes('Orchestrator')) {
21
+ orchestratorCalls++;
22
+ if (orchestratorCalls === 1) {
23
+ return {
24
+ content: null,
25
+ toolCalls: [{ id: ToolCallId('tc1'), name: 'start_worker', input: { message: 'Do some work' } }],
26
+ finishReason: 'stop',
27
+ metrics: MockLLMProvider.defaultMetrics(),
28
+ };
29
+ }
30
+ return { content: 'Done', toolCalls: [], finishReason: 'stop', metrics: MockLLMProvider.defaultMetrics() };
31
+ }
32
+ return { content: 'Worker done', toolCalls: [], finishReason: 'stop', metrics: MockLLMProvider.defaultMetrics() };
33
+ },
34
+ });
35
+ const session = await harness.createSession('test');
36
+ await session.sendAndWaitForIdle('Start');
37
+ const events = await session.getEventsByType(agentEvents, 'agent_spawned');
38
+ // orchestrator_1 + worker_1
39
+ const workerSpawned = events.filter(e => e.definitionName === 'worker');
40
+ expect(workerSpawned).toHaveLength(1);
41
+ expect(workerSpawned[0].agentId).toBe(AgentId('worker_1'));
42
+ expect(workerSpawned[0].parentId).toBe(session.getEntryAgentId());
43
+ await harness.shutdown();
44
+ });
45
+ it('spawned agent appears in session.state.agents', async () => {
46
+ let orchestratorCalls = 0;
47
+ const harness = new TestHarness({
48
+ presets: [createMultiAgentPreset([
49
+ { name: 'worker', system: 'Worker agent.', tools: [], agents: [] },
50
+ ], { orchestratorSystem: 'Orchestrator agent.' })],
51
+ mockHandler: (request) => {
52
+ if (request.systemPrompt.includes('Orchestrator')) {
53
+ orchestratorCalls++;
54
+ if (orchestratorCalls === 1) {
55
+ return {
56
+ content: null,
57
+ toolCalls: [{ id: ToolCallId('tc1'), name: 'start_worker', input: { message: 'Do work' } }],
58
+ finishReason: 'stop',
59
+ metrics: MockLLMProvider.defaultMetrics(),
60
+ };
61
+ }
62
+ return { content: 'Done', toolCalls: [], finishReason: 'stop', metrics: MockLLMProvider.defaultMetrics() };
63
+ }
64
+ return { content: 'Worker done', toolCalls: [], finishReason: 'stop', metrics: MockLLMProvider.defaultMetrics() };
65
+ },
66
+ });
67
+ const session = await harness.createSession('test');
68
+ await session.sendAndWaitForIdle('Start');
69
+ expect(session.state.agents.has(AgentId('worker_1'))).toBe(true);
70
+ const workerState = session.state.agents.get(AgentId('worker_1'));
71
+ expect(workerState.definitionName).toBe('worker');
72
+ expect(workerState.parentId).toBe(session.getEntryAgentId());
73
+ await harness.shutdown();
74
+ });
75
+ it('spawned agent receives initial task message via mailbox', async () => {
76
+ let orchestratorCalls = 0;
77
+ let workerSawTask = false;
78
+ const harness = new TestHarness({
79
+ presets: [createMultiAgentPreset([
80
+ { name: 'worker', system: 'Worker agent.', tools: [], agents: [] },
81
+ ], { orchestratorSystem: 'Orchestrator agent.' })],
82
+ mockHandler: (request) => {
83
+ if (request.systemPrompt.includes('Orchestrator')) {
84
+ orchestratorCalls++;
85
+ if (orchestratorCalls === 1) {
86
+ return {
87
+ content: null,
88
+ toolCalls: [{ id: ToolCallId('tc1'), name: 'start_worker', input: { message: 'Process this data please' } }],
89
+ finishReason: 'stop',
90
+ metrics: MockLLMProvider.defaultMetrics(),
91
+ };
92
+ }
93
+ return { content: 'Done', toolCalls: [], finishReason: 'stop', metrics: MockLLMProvider.defaultMetrics() };
94
+ }
95
+ // Worker: check if initial message arrived
96
+ const userMessages = request.messages.filter(m => m.role === 'user');
97
+ const lastUserMsg = userMessages[userMessages.length - 1];
98
+ if (typeof lastUserMsg?.content === 'string' && lastUserMsg.content.includes('Process this data please')) {
99
+ workerSawTask = true;
100
+ }
101
+ return { content: 'Worker done', toolCalls: [], finishReason: 'stop', metrics: MockLLMProvider.defaultMetrics() };
102
+ },
103
+ });
104
+ const session = await harness.createSession('test');
105
+ await session.sendAndWaitForIdle('Start');
106
+ expect(workerSawTask).toBe(true);
107
+ await harness.shutdown();
108
+ });
109
+ it('spawned agent starts processing (scheduled after spawn)', async () => {
110
+ let orchestratorCalls = 0;
111
+ let workerCalls = 0;
112
+ const harness = new TestHarness({
113
+ presets: [createMultiAgentPreset([
114
+ { name: 'worker', system: 'Worker agent.', tools: [], agents: [] },
115
+ ], { orchestratorSystem: 'Orchestrator agent.' })],
116
+ mockHandler: (request) => {
117
+ if (request.systemPrompt.includes('Orchestrator')) {
118
+ orchestratorCalls++;
119
+ if (orchestratorCalls === 1) {
120
+ return {
121
+ content: null,
122
+ toolCalls: [{ id: ToolCallId('tc1'), name: 'start_worker', input: { message: 'Go' } }],
123
+ finishReason: 'stop',
124
+ metrics: MockLLMProvider.defaultMetrics(),
125
+ };
126
+ }
127
+ return { content: 'Done', toolCalls: [], finishReason: 'stop', metrics: MockLLMProvider.defaultMetrics() };
128
+ }
129
+ workerCalls++;
130
+ return { content: 'Worker done', toolCalls: [], finishReason: 'stop', metrics: MockLLMProvider.defaultMetrics() };
131
+ },
132
+ });
133
+ const session = await harness.createSession('test');
134
+ await session.sendAndWaitForIdle('Start');
135
+ expect(workerCalls).toBeGreaterThanOrEqual(1);
136
+ await harness.shutdown();
137
+ });
138
+ it('multiple spawns of same type → unique agent IDs (worker_1, worker_2, ...)', async () => {
139
+ let orchestratorCalls = 0;
140
+ const harness = new TestHarness({
141
+ presets: [createMultiAgentPreset([
142
+ { name: 'worker', system: 'Worker agent.', tools: [], agents: [] },
143
+ ], { orchestratorSystem: 'Orchestrator agent.' })],
144
+ mockHandler: (request) => {
145
+ if (request.systemPrompt.includes('Orchestrator')) {
146
+ orchestratorCalls++;
147
+ if (orchestratorCalls === 1) {
148
+ return {
149
+ content: null,
150
+ toolCalls: [
151
+ { id: ToolCallId('tc1'), name: 'start_worker', input: { message: 'Task 1' } },
152
+ { id: ToolCallId('tc2'), name: 'start_worker', input: { message: 'Task 2' } },
153
+ ],
154
+ finishReason: 'stop',
155
+ metrics: MockLLMProvider.defaultMetrics(),
156
+ };
157
+ }
158
+ return { content: 'Done', toolCalls: [], finishReason: 'stop', metrics: MockLLMProvider.defaultMetrics() };
159
+ }
160
+ return { content: 'Worker done', toolCalls: [], finishReason: 'stop', metrics: MockLLMProvider.defaultMetrics() };
161
+ },
162
+ });
163
+ const session = await harness.createSession('test');
164
+ await session.sendAndWaitForIdle('Start');
165
+ expect(session.state.agents.has(AgentId('worker_1'))).toBe(true);
166
+ expect(session.state.agents.has(AgentId('worker_2'))).toBe(true);
167
+ const events = await session.getEventsByType(agentEvents, 'agent_spawned');
168
+ const workerEvents = events.filter(e => e.definitionName === 'worker');
169
+ expect(workerEvents).toHaveLength(2);
170
+ const agentIds = workerEvents.map(e => e.agentId);
171
+ expect(agentIds).toContain(AgentId('worker_1'));
172
+ expect(agentIds).toContain(AgentId('worker_2'));
173
+ await harness.shutdown();
174
+ });
175
+ });
176
+ // =========================================================================
177
+ // typed input
178
+ // =========================================================================
179
+ describe('typed input', () => {
180
+ it('agent with Zod input schema → start_<agent> tool includes input field', async () => {
181
+ let orchestratorCalls = 0;
182
+ let workerCalls = 0;
183
+ const harness = new TestHarness({
184
+ presets: [createMultiAgentPreset([
185
+ {
186
+ name: 'worker',
187
+ system: 'Worker agent.',
188
+ tools: [],
189
+ agents: [],
190
+ input: z.object({ url: z.string(), depth: z.number() }),
191
+ },
192
+ ], { orchestratorSystem: 'Orchestrator agent.' })],
193
+ mockHandler: (request) => {
194
+ if (request.systemPrompt.includes('Orchestrator')) {
195
+ orchestratorCalls++;
196
+ if (orchestratorCalls === 1) {
197
+ return {
198
+ content: null,
199
+ toolCalls: [{
200
+ id: ToolCallId('tc1'),
201
+ name: 'start_worker',
202
+ input: { message: 'Crawl this', input: { url: 'https://example.com', depth: 3 } },
203
+ }],
204
+ finishReason: 'stop',
205
+ metrics: MockLLMProvider.defaultMetrics(),
206
+ };
207
+ }
208
+ return { content: 'Done', toolCalls: [], finishReason: 'stop', metrics: MockLLMProvider.defaultMetrics() };
209
+ }
210
+ workerCalls++;
211
+ return { content: 'Worker done', toolCalls: [], finishReason: 'stop', metrics: MockLLMProvider.defaultMetrics() };
212
+ },
213
+ });
214
+ const session = await harness.createSession('test');
215
+ await session.sendAndWaitForIdle('Start');
216
+ // Verify the agent was spawned with typed input
217
+ const events = await session.getEventsByType(agentEvents, 'agent_spawned');
218
+ const workerSpawned = events.find(e => e.definitionName === 'worker');
219
+ expect(workerSpawned).toBeDefined();
220
+ expect(workerSpawned.typedInput).toEqual({ url: 'https://example.com', depth: 3 });
221
+ // Verify the worker was called with the typed input as JSON in the message
222
+ expect(workerCalls).toBeGreaterThanOrEqual(1);
223
+ await harness.shutdown();
224
+ });
225
+ it('valid typed input → passed to agent as typedInput in spawn event', async () => {
226
+ let orchestratorCalls = 0;
227
+ const harness = new TestHarness({
228
+ presets: [createMultiAgentPreset([
229
+ {
230
+ name: 'worker',
231
+ system: 'Worker agent.',
232
+ tools: [],
233
+ agents: [],
234
+ input: z.object({ query: z.string() }),
235
+ },
236
+ ], { orchestratorSystem: 'Orchestrator agent.' })],
237
+ mockHandler: (request) => {
238
+ if (request.systemPrompt.includes('Orchestrator')) {
239
+ orchestratorCalls++;
240
+ if (orchestratorCalls === 1) {
241
+ return {
242
+ content: null,
243
+ toolCalls: [{
244
+ id: ToolCallId('tc1'),
245
+ name: 'start_worker',
246
+ input: { message: 'Search', input: { query: 'test query' } },
247
+ }],
248
+ finishReason: 'stop',
249
+ metrics: MockLLMProvider.defaultMetrics(),
250
+ };
251
+ }
252
+ return { content: 'Done', toolCalls: [], finishReason: 'stop', metrics: MockLLMProvider.defaultMetrics() };
253
+ }
254
+ return { content: 'Worker done', toolCalls: [], finishReason: 'stop', metrics: MockLLMProvider.defaultMetrics() };
255
+ },
256
+ });
257
+ const session = await harness.createSession('test');
258
+ await session.sendAndWaitForIdle('Start');
259
+ // typedInput stored in agent state
260
+ const workerState = session.state.agents.get(AgentId('worker_1'));
261
+ expect(workerState).toBeDefined();
262
+ expect(workerState.typedInput).toEqual({ query: 'test query' });
263
+ await harness.shutdown();
264
+ });
265
+ it('invalid typed input → validation error returned', async () => {
266
+ let orchestratorCalls = 0;
267
+ let receivedValidationError = false;
268
+ const harness = new TestHarness({
269
+ presets: [createMultiAgentPreset([
270
+ {
271
+ name: 'worker',
272
+ system: 'Worker agent.',
273
+ tools: [],
274
+ agents: [],
275
+ input: z.object({ url: z.string().url(), depth: z.number() }),
276
+ },
277
+ ], { orchestratorSystem: 'Orchestrator agent.' })],
278
+ mockHandler: (request) => {
279
+ if (request.systemPrompt.includes('Orchestrator')) {
280
+ orchestratorCalls++;
281
+ if (orchestratorCalls === 1) {
282
+ return {
283
+ content: null,
284
+ toolCalls: [{
285
+ id: ToolCallId('tc1'),
286
+ name: 'start_worker',
287
+ input: { message: 'Crawl', input: { url: 'not-a-url', depth: 'not-a-number' } },
288
+ }],
289
+ finishReason: 'stop',
290
+ metrics: MockLLMProvider.defaultMetrics(),
291
+ };
292
+ }
293
+ // Check if tool result contains error
294
+ const toolMessages = request.messages.filter(m => m.role === 'tool');
295
+ if (toolMessages.some(m => typeof m.content === 'string' && m.isError)) {
296
+ receivedValidationError = true;
297
+ }
298
+ return { content: 'Done', toolCalls: [], finishReason: 'stop', metrics: MockLLMProvider.defaultMetrics() };
299
+ }
300
+ return { content: 'Worker done', toolCalls: [], finishReason: 'stop', metrics: MockLLMProvider.defaultMetrics() };
301
+ },
302
+ });
303
+ const session = await harness.createSession('test');
304
+ await session.sendAndWaitForIdle('Start');
305
+ // Worker should NOT have been spawned due to validation error
306
+ expect(session.state.agents.has(AgentId('worker_1'))).toBe(false);
307
+ // Orchestrator received validation error as tool result
308
+ expect(receivedValidationError).toBe(true);
309
+ await harness.shutdown();
310
+ });
311
+ });
312
+ // =========================================================================
313
+ // agents.spawn method
314
+ // =========================================================================
315
+ describe('agents.spawn method', () => {
316
+ it('spawn with valid parent and definition → agent created', async () => {
317
+ const harness = new TestHarness({
318
+ presets: [createMultiAgentPreset([
319
+ { name: 'worker', system: 'Worker agent.', tools: [], agents: [] },
320
+ ], { orchestratorSystem: 'Orchestrator agent.' })],
321
+ llmProvider: MockLLMProvider.withFixedResponse({ content: 'Done', toolCalls: [] }),
322
+ });
323
+ const session = await harness.createSession('test');
324
+ const orchestratorId = session.getEntryAgentId();
325
+ const result = await session.callPluginMethod('agents.spawn', {
326
+ definitionName: 'worker',
327
+ parentId: String(orchestratorId),
328
+ message: 'Hello worker',
329
+ });
330
+ expect(result.ok).toBe(true);
331
+ if (result.ok) {
332
+ expect(result.value).toHaveProperty('agentId');
333
+ }
334
+ await session.waitForIdle();
335
+ expect(session.state.agents.has(AgentId('worker_1'))).toBe(true);
336
+ await harness.shutdown();
337
+ });
338
+ it('spawn with unknown parent → error (agent_not_found)', async () => {
339
+ const harness = new TestHarness({
340
+ presets: [createMultiAgentPreset([
341
+ { name: 'worker', system: 'Worker agent.', tools: [], agents: [] },
342
+ ])],
343
+ llmProvider: MockLLMProvider.withFixedResponse({ content: 'Done', toolCalls: [] }),
344
+ });
345
+ const session = await harness.createSession('test');
346
+ const result = await session.callPluginMethod('agents.spawn', {
347
+ definitionName: 'worker',
348
+ parentId: 'nonexistent_99',
349
+ });
350
+ expect(result.ok).toBe(false);
351
+ if (!result.ok) {
352
+ expect(result.error.type).toBe('agent_not_found');
353
+ }
354
+ await harness.shutdown();
355
+ });
356
+ it('spawn with unknown definition → error (validation_error)', async () => {
357
+ const harness = new TestHarness({
358
+ presets: [createMultiAgentPreset([
359
+ { name: 'worker', system: 'Worker agent.', tools: [], agents: [] },
360
+ ])],
361
+ llmProvider: MockLLMProvider.withFixedResponse({ content: 'Done', toolCalls: [] }),
362
+ });
363
+ const session = await harness.createSession('test');
364
+ const orchestratorId = session.getEntryAgentId();
365
+ const result = await session.callPluginMethod('agents.spawn', {
366
+ definitionName: 'nonexistent_agent',
367
+ parentId: String(orchestratorId),
368
+ });
369
+ expect(result.ok).toBe(false);
370
+ if (!result.ok) {
371
+ expect(result.error.type).toBe('validation_error');
372
+ }
373
+ await harness.shutdown();
374
+ });
375
+ it('spawn with initial message → message sent via mailbox', async () => {
376
+ let workerSawMessage = false;
377
+ const harness = new TestHarness({
378
+ presets: [createMultiAgentPreset([
379
+ { name: 'worker', system: 'Worker agent.', tools: [], agents: [] },
380
+ ], { orchestratorSystem: 'Orchestrator agent.' })],
381
+ mockHandler: (request) => {
382
+ if (request.systemPrompt.includes('Worker')) {
383
+ const userMessages = request.messages.filter(m => m.role === 'user');
384
+ const lastUserMsg = userMessages[userMessages.length - 1];
385
+ if (typeof lastUserMsg?.content === 'string' && lastUserMsg.content.includes('Spawn message')) {
386
+ workerSawMessage = true;
387
+ }
388
+ }
389
+ return { content: 'Done', toolCalls: [], finishReason: 'stop', metrics: MockLLMProvider.defaultMetrics() };
390
+ },
391
+ });
392
+ const session = await harness.createSession('test');
393
+ const orchestratorId = session.getEntryAgentId();
394
+ const result = await session.callPluginMethod('agents.spawn', {
395
+ definitionName: 'worker',
396
+ parentId: String(orchestratorId),
397
+ message: 'Spawn message',
398
+ });
399
+ expect(result.ok).toBe(true);
400
+ await session.waitForIdle();
401
+ expect(workerSawMessage).toBe(true);
402
+ await harness.shutdown();
403
+ });
404
+ });
405
+ // =========================================================================
406
+ // agents.resume method
407
+ // =========================================================================
408
+ describe('agents.resume method', () => {
409
+ it('resume paused agent → agent_resumed event → agent scheduled', async () => {
410
+ let orchestratorCalls = 0;
411
+ let workerCalls = 0;
412
+ const harness = new TestHarness({
413
+ presets: [createMultiAgentPreset([
414
+ { name: 'worker', system: 'Worker agent.', tools: [], agents: [] },
415
+ ], { orchestratorSystem: 'Orchestrator agent.' })],
416
+ mockHandler: (request) => {
417
+ if (request.systemPrompt.includes('Orchestrator')) {
418
+ orchestratorCalls++;
419
+ if (orchestratorCalls === 1) {
420
+ return {
421
+ content: null,
422
+ toolCalls: [{ id: ToolCallId('tc1'), name: 'start_worker', input: { message: 'Work' } }],
423
+ finishReason: 'stop',
424
+ metrics: MockLLMProvider.defaultMetrics(),
425
+ };
426
+ }
427
+ return { content: 'Done', toolCalls: [], finishReason: 'stop', metrics: MockLLMProvider.defaultMetrics() };
428
+ }
429
+ workerCalls++;
430
+ return { content: 'Worker done', toolCalls: [], finishReason: 'stop', metrics: MockLLMProvider.defaultMetrics() };
431
+ },
432
+ });
433
+ const session = await harness.createSession('test');
434
+ await session.sendAndWaitForIdle('Start');
435
+ // Pause the worker
436
+ const pauseResult = await session.callPluginMethod('agents.pause', {
437
+ agentId: 'worker_1',
438
+ });
439
+ expect(pauseResult.ok).toBe(true);
440
+ expect(session.state.agents.get(AgentId('worker_1')).status).toBe('paused');
441
+ const workerCallsBefore = workerCalls;
442
+ // Resume the worker
443
+ const resumeResult = await session.callPluginMethod('agents.resume', {
444
+ agentId: 'worker_1',
445
+ });
446
+ expect(resumeResult.ok).toBe(true);
447
+ await session.waitForIdle();
448
+ // agent_resumed event emitted
449
+ const resumedEvents = await session.getEventsByType(agentEvents, 'agent_resumed');
450
+ expect(resumedEvents.filter(e => e.agentId === AgentId('worker_1'))).toHaveLength(1);
451
+ // Worker status back to pending after processing
452
+ expect(session.state.agents.get(AgentId('worker_1')).status).toBe('pending');
453
+ await harness.shutdown();
454
+ });
455
+ it('resume non-paused agent → error', async () => {
456
+ let orchestratorCalls = 0;
457
+ const harness = new TestHarness({
458
+ presets: [createMultiAgentPreset([
459
+ { name: 'worker', system: 'Worker agent.', tools: [], agents: [] },
460
+ ], { orchestratorSystem: 'Orchestrator agent.' })],
461
+ mockHandler: (request) => {
462
+ if (request.systemPrompt.includes('Orchestrator')) {
463
+ orchestratorCalls++;
464
+ if (orchestratorCalls === 1) {
465
+ return {
466
+ content: null,
467
+ toolCalls: [{ id: ToolCallId('tc1'), name: 'start_worker', input: { message: 'Work' } }],
468
+ finishReason: 'stop',
469
+ metrics: MockLLMProvider.defaultMetrics(),
470
+ };
471
+ }
472
+ return { content: 'Done', toolCalls: [], finishReason: 'stop', metrics: MockLLMProvider.defaultMetrics() };
473
+ }
474
+ return { content: 'Worker done', toolCalls: [], finishReason: 'stop', metrics: MockLLMProvider.defaultMetrics() };
475
+ },
476
+ });
477
+ const session = await harness.createSession('test');
478
+ await session.sendAndWaitForIdle('Start');
479
+ // Worker is idle (pending), not paused
480
+ const result = await session.callPluginMethod('agents.resume', {
481
+ agentId: 'worker_1',
482
+ });
483
+ expect(result.ok).toBe(false);
484
+ if (!result.ok) {
485
+ expect(result.error.type).toBe('validation_error');
486
+ }
487
+ await harness.shutdown();
488
+ });
489
+ it('resume non-existent agent → error', async () => {
490
+ const harness = new TestHarness({
491
+ presets: [createTestPreset()],
492
+ llmProvider: MockLLMProvider.withFixedResponse({ content: 'Done', toolCalls: [] }),
493
+ });
494
+ const session = await harness.createSession('test');
495
+ const result = await session.callPluginMethod('agents.resume', {
496
+ agentId: 'nonexistent_99',
497
+ });
498
+ expect(result.ok).toBe(false);
499
+ if (!result.ok) {
500
+ expect(result.error.type).toBe('agent_not_found');
501
+ }
502
+ await harness.shutdown();
503
+ });
504
+ });
505
+ // =========================================================================
506
+ // agents.pause method
507
+ // =========================================================================
508
+ describe('agents.pause method', () => {
509
+ it('pause active agent → agent_paused event', async () => {
510
+ let orchestratorCalls = 0;
511
+ const harness = new TestHarness({
512
+ presets: [createMultiAgentPreset([
513
+ { name: 'worker', system: 'Worker agent.', tools: [], agents: [] },
514
+ ], { orchestratorSystem: 'Orchestrator agent.' })],
515
+ mockHandler: (request) => {
516
+ if (request.systemPrompt.includes('Orchestrator')) {
517
+ orchestratorCalls++;
518
+ if (orchestratorCalls === 1) {
519
+ return {
520
+ content: null,
521
+ toolCalls: [{ id: ToolCallId('tc1'), name: 'start_worker', input: { message: 'Work' } }],
522
+ finishReason: 'stop',
523
+ metrics: MockLLMProvider.defaultMetrics(),
524
+ };
525
+ }
526
+ return { content: 'Done', toolCalls: [], finishReason: 'stop', metrics: MockLLMProvider.defaultMetrics() };
527
+ }
528
+ return { content: 'Worker done', toolCalls: [], finishReason: 'stop', metrics: MockLLMProvider.defaultMetrics() };
529
+ },
530
+ });
531
+ const session = await harness.createSession('test');
532
+ await session.sendAndWaitForIdle('Start');
533
+ const result = await session.callPluginMethod('agents.pause', {
534
+ agentId: 'worker_1',
535
+ message: 'Pausing for review',
536
+ });
537
+ expect(result.ok).toBe(true);
538
+ // agent_paused event emitted
539
+ const pausedEvents = await session.getEventsByType(agentEvents, 'agent_paused');
540
+ const workerPaused = pausedEvents.filter(e => e.agentId === AgentId('worker_1'));
541
+ expect(workerPaused).toHaveLength(1);
542
+ expect(workerPaused[0].reason).toBe('manual');
543
+ expect(workerPaused[0].message).toBe('Pausing for review');
544
+ // State updated
545
+ expect(session.state.agents.get(AgentId('worker_1')).status).toBe('paused');
546
+ await harness.shutdown();
547
+ });
548
+ it('pause already-paused agent → error', async () => {
549
+ let orchestratorCalls = 0;
550
+ const harness = new TestHarness({
551
+ presets: [createMultiAgentPreset([
552
+ { name: 'worker', system: 'Worker agent.', tools: [], agents: [] },
553
+ ], { orchestratorSystem: 'Orchestrator agent.' })],
554
+ mockHandler: (request) => {
555
+ if (request.systemPrompt.includes('Orchestrator')) {
556
+ orchestratorCalls++;
557
+ if (orchestratorCalls === 1) {
558
+ return {
559
+ content: null,
560
+ toolCalls: [{ id: ToolCallId('tc1'), name: 'start_worker', input: { message: 'Work' } }],
561
+ finishReason: 'stop',
562
+ metrics: MockLLMProvider.defaultMetrics(),
563
+ };
564
+ }
565
+ return { content: 'Done', toolCalls: [], finishReason: 'stop', metrics: MockLLMProvider.defaultMetrics() };
566
+ }
567
+ return { content: 'Worker done', toolCalls: [], finishReason: 'stop', metrics: MockLLMProvider.defaultMetrics() };
568
+ },
569
+ });
570
+ const session = await harness.createSession('test');
571
+ await session.sendAndWaitForIdle('Start');
572
+ // Pause first time
573
+ const first = await session.callPluginMethod('agents.pause', { agentId: 'worker_1' });
574
+ expect(first.ok).toBe(true);
575
+ // Pause again → error
576
+ const second = await session.callPluginMethod('agents.pause', { agentId: 'worker_1' });
577
+ expect(second.ok).toBe(false);
578
+ if (!second.ok) {
579
+ expect(second.error.type).toBe('validation_error');
580
+ }
581
+ await harness.shutdown();
582
+ });
583
+ it('pause non-existent agent → error', async () => {
584
+ const harness = new TestHarness({
585
+ presets: [createTestPreset()],
586
+ llmProvider: MockLLMProvider.withFixedResponse({ content: 'Done', toolCalls: [] }),
587
+ });
588
+ const session = await harness.createSession('test');
589
+ const result = await session.callPluginMethod('agents.pause', {
590
+ agentId: 'nonexistent_99',
591
+ });
592
+ expect(result.ok).toBe(false);
593
+ if (!result.ok) {
594
+ expect(result.error.type).toBe('agent_not_found');
595
+ }
596
+ await harness.shutdown();
597
+ });
598
+ });
599
+ // =========================================================================
600
+ // multi-level
601
+ // =========================================================================
602
+ describe('multi-level', () => {
603
+ it('orchestrator → spawns A → A spawns B → B processes and reports to A', async () => {
604
+ let orchestratorCalls = 0;
605
+ let workerACalls = 0;
606
+ let workerBCalls = 0;
607
+ let workerASawReport = false;
608
+ const harness = new TestHarness({
609
+ presets: [createMultiAgentPreset([
610
+ { name: 'worker_a', system: 'Worker A agent.', tools: [], agents: ['worker_b'] },
611
+ { name: 'worker_b', system: 'Worker B agent.', tools: [], agents: [] },
612
+ ], { orchestratorSystem: 'Orchestrator agent.' })],
613
+ mockHandler: (request) => {
614
+ if (request.systemPrompt.includes('Orchestrator')) {
615
+ orchestratorCalls++;
616
+ if (orchestratorCalls === 1) {
617
+ return {
618
+ content: null,
619
+ toolCalls: [{ id: ToolCallId('tc1'), name: 'start_worker_a', input: { message: 'Delegate' } }],
620
+ finishReason: 'stop',
621
+ metrics: MockLLMProvider.defaultMetrics(),
622
+ };
623
+ }
624
+ return { content: 'Done', toolCalls: [], finishReason: 'stop', metrics: MockLLMProvider.defaultMetrics() };
625
+ }
626
+ if (request.systemPrompt.includes('Worker A')) {
627
+ workerACalls++;
628
+ if (workerACalls === 1) {
629
+ return {
630
+ content: null,
631
+ toolCalls: [{ id: ToolCallId('tc2'), name: 'start_worker_b', input: { message: 'Sub-task' } }],
632
+ finishReason: 'stop',
633
+ metrics: MockLLMProvider.defaultMetrics(),
634
+ };
635
+ }
636
+ // Check if we received B's report
637
+ const lastMsg = request.messages[request.messages.length - 1];
638
+ if (typeof lastMsg?.content === 'string' && lastMsg.content.includes('Report from B')) {
639
+ workerASawReport = true;
640
+ }
641
+ return { content: 'A done', toolCalls: [], finishReason: 'stop', metrics: MockLLMProvider.defaultMetrics() };
642
+ }
643
+ // Worker B
644
+ workerBCalls++;
645
+ if (workerBCalls === 1) {
646
+ return {
647
+ content: null,
648
+ toolCalls: [{ id: ToolCallId('tc3'), name: 'send_message', input: { to: 'parent', message: 'Report from B' } }],
649
+ finishReason: 'stop',
650
+ metrics: MockLLMProvider.defaultMetrics(),
651
+ };
652
+ }
653
+ return { content: 'B done', toolCalls: [], finishReason: 'stop', metrics: MockLLMProvider.defaultMetrics() };
654
+ },
655
+ });
656
+ const session = await harness.createSession('test');
657
+ await session.sendAndWaitForIdle('Start', { timeoutMs: 10000 });
658
+ // All three levels of agents should exist
659
+ expect(session.state.agents.has(AgentId('worker_a_1'))).toBe(true);
660
+ expect(session.state.agents.has(AgentId('worker_b_1'))).toBe(true);
661
+ // Worker A received report from Worker B
662
+ expect(workerASawReport).toBe(true);
663
+ // B's parent is A
664
+ expect(session.state.agents.get(AgentId('worker_b_1')).parentId).toBe(AgentId('worker_a_1'));
665
+ await harness.shutdown();
666
+ });
667
+ it('isEnabled: agents with no spawnable agents → no start_* tools generated', async () => {
668
+ const harness = new TestHarness({
669
+ presets: [createTestPreset({ orchestratorSystem: 'No children orchestrator.' })],
670
+ llmProvider: MockLLMProvider.withFixedResponse({ content: 'Done', toolCalls: [] }),
671
+ });
672
+ const session = await harness.createSession('test');
673
+ await session.sendAndWaitForIdle('Test');
674
+ // No start_* tools in the LLM request
675
+ const lastRequest = harness.llmProvider.getLastRequest();
676
+ expect(lastRequest).toBeDefined();
677
+ const startTools = (lastRequest.tools ?? []).filter(t => t.name.startsWith('start_'));
678
+ expect(startTools).toHaveLength(0);
679
+ await harness.shutdown();
680
+ });
681
+ });
682
+ });
683
+ //# sourceMappingURL=agents.integration.test.js.map