@ai-setting/roy-agent-core 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (378) hide show
  1. package/dist/index.js +99145 -0
  2. package/package.json +114 -0
  3. package/src/config/config-component.test.ts +627 -0
  4. package/src/config/config-component.ts +906 -0
  5. package/src/config/config-parser.test.ts +319 -0
  6. package/src/config/config-parser.ts +203 -0
  7. package/src/config/decentralized-config.test.ts +740 -0
  8. package/src/config/env-key.ts +210 -0
  9. package/src/config/env-source.test.ts +252 -0
  10. package/src/config/env-source.ts +301 -0
  11. package/src/config/file-source.test.ts +357 -0
  12. package/src/config/file-source.ts +421 -0
  13. package/src/config/index.ts +24 -0
  14. package/src/config/protocol-resolver.test.ts +217 -0
  15. package/src/config/protocol-resolver.ts +228 -0
  16. package/src/env/agent/agent-component.abort.test.ts +511 -0
  17. package/src/env/agent/agent-component.record-session.test.ts +349 -0
  18. package/src/env/agent/agent-component.test.ts +1389 -0
  19. package/src/env/agent/agent-component.tool-error.test.ts +327 -0
  20. package/src/env/agent/agent-component.ts +1711 -0
  21. package/src/env/agent/agent-config-registration.test.ts +226 -0
  22. package/src/env/agent/agent-config-registration.ts +46 -0
  23. package/src/env/agent/agent-reminder-plugin.integration.test.ts +243 -0
  24. package/src/env/agent/index.ts +10 -0
  25. package/src/env/agent/summary-agent.parse-hint.test.ts +360 -0
  26. package/src/env/agent/summary-agent.ts +508 -0
  27. package/src/env/agent/types.ts +536 -0
  28. package/src/env/commands/commands-component.test.ts +364 -0
  29. package/src/env/commands/commands-component.ts +604 -0
  30. package/src/env/commands/commands-config-registration.test.ts +198 -0
  31. package/src/env/commands/commands-config-registration.ts +38 -0
  32. package/src/env/commands/index.ts +21 -0
  33. package/src/env/commands/parser.test.ts +203 -0
  34. package/src/env/commands/parser.ts +115 -0
  35. package/src/env/commands/types.ts +184 -0
  36. package/src/env/commands-prompt-integration.test.ts +243 -0
  37. package/src/env/component-env.test.ts +119 -0
  38. package/src/env/component.ts +335 -0
  39. package/src/env/constants.test.ts +72 -0
  40. package/src/env/constants.ts +123 -0
  41. package/src/env/debug/debug-component.test.ts +114 -0
  42. package/src/env/debug/debug-component.ts +547 -0
  43. package/src/env/debug/formatters/index.ts +9 -0
  44. package/src/env/debug/formatters/repl-formatter.test.ts +139 -0
  45. package/src/env/debug/formatters/repl-formatter.ts +358 -0
  46. package/src/env/debug/formatters/trace-formatter.test.ts +119 -0
  47. package/src/env/debug/formatters/trace-formatter.ts +191 -0
  48. package/src/env/debug/formatters/tree-formatter.test.ts +107 -0
  49. package/src/env/debug/formatters/tree-formatter.ts +325 -0
  50. package/src/env/debug/index.ts +38 -0
  51. package/src/env/debug/parser/regex-parser.test.ts +201 -0
  52. package/src/env/debug/parser/regex-parser.ts +196 -0
  53. package/src/env/debug/parser/span-builder.test.ts +241 -0
  54. package/src/env/debug/parser/span-builder.ts +386 -0
  55. package/src/env/debug/reader/log-reader.test.ts +170 -0
  56. package/src/env/debug/reader/log-reader.ts +186 -0
  57. package/src/env/debug/reader/span-db-reader.test.ts +118 -0
  58. package/src/env/debug/reader/span-db-reader.ts +201 -0
  59. package/src/env/debug/types.test.ts +187 -0
  60. package/src/env/debug/types.ts +171 -0
  61. package/src/env/environment-init.test.ts +183 -0
  62. package/src/env/environment-lifecycle.test.ts +516 -0
  63. package/src/env/environment-service.test.ts +332 -0
  64. package/src/env/environment.handle-query.test.ts +96 -0
  65. package/src/env/environment.test.ts +232 -0
  66. package/src/env/environment.ts +708 -0
  67. package/src/env/errors.test.ts +165 -0
  68. package/src/env/errors.ts +157 -0
  69. package/src/env/event-source/event-source-agent-handler.test.ts +193 -0
  70. package/src/env/event-source/event-source-agent-handler.ts +111 -0
  71. package/src/env/event-source/event-source-component.process-cleanup.test.ts +236 -0
  72. package/src/env/event-source/event-source-component.stop.test.ts +346 -0
  73. package/src/env/event-source/event-source-component.test.ts +1207 -0
  74. package/src/env/event-source/event-source-component.ts +1379 -0
  75. package/src/env/event-source/event-source-config-registration.test.ts +242 -0
  76. package/src/env/event-source/event-source-config-registration.ts +37 -0
  77. package/src/env/event-source/event-source-integration.test.ts +320 -0
  78. package/src/env/event-source/event-source-platform.test.ts +630 -0
  79. package/src/env/event-source/types.ts +298 -0
  80. package/src/env/hook/global-hook-manager.ts +162 -0
  81. package/src/env/hook/hook-manager.test.ts +374 -0
  82. package/src/env/hook/hook-manager.ts +309 -0
  83. package/src/env/hook/index.ts +38 -0
  84. package/src/env/hook/types.ts +138 -0
  85. package/src/env/index.ts +144 -0
  86. package/src/env/interface.ts +203 -0
  87. package/src/env/llm/hooks.test.ts +293 -0
  88. package/src/env/llm/hooks.ts +316 -0
  89. package/src/env/llm/index.ts +61 -0
  90. package/src/env/llm/invoke-threshold-check.test.ts +88 -0
  91. package/src/env/llm/invoke-timeout.test.ts +54 -0
  92. package/src/env/llm/invoke.test.ts +71 -0
  93. package/src/env/llm/invoke.ts +1039 -0
  94. package/src/env/llm/llm-config.test.ts +523 -0
  95. package/src/env/llm/llm.test.ts +233 -0
  96. package/src/env/llm/llm.ts +568 -0
  97. package/src/env/llm/provider.test.ts +182 -0
  98. package/src/env/llm/provider.ts +108 -0
  99. package/src/env/llm/transform.test.ts +251 -0
  100. package/src/env/llm/transform.ts +286 -0
  101. package/src/env/llm/types.test.ts +580 -0
  102. package/src/env/llm/types.ts +424 -0
  103. package/src/env/log-trace/decorator-otel.test.ts +182 -0
  104. package/src/env/log-trace/decorator.ts +230 -0
  105. package/src/env/log-trace/index.ts +79 -0
  106. package/src/env/log-trace/log-trace-component.test.ts +242 -0
  107. package/src/env/log-trace/log-trace-component.ts +497 -0
  108. package/src/env/log-trace/log-trace-config-registration.test.ts +348 -0
  109. package/src/env/log-trace/log-trace-config-registration.ts +45 -0
  110. package/src/env/log-trace/logger.test.ts +149 -0
  111. package/src/env/log-trace/logger.ts +522 -0
  112. package/src/env/log-trace/opentelemetry/cli-propagation.test.ts +147 -0
  113. package/src/env/log-trace/opentelemetry/cli-propagation.ts +194 -0
  114. package/src/env/log-trace/opentelemetry/integration.test.ts +668 -0
  115. package/src/env/log-trace/opentelemetry/mod.ts +25 -0
  116. package/src/env/log-trace/opentelemetry/propagation-env.test.ts +181 -0
  117. package/src/env/log-trace/opentelemetry/propagation-env.ts +136 -0
  118. package/src/env/log-trace/opentelemetry/propagation.test.ts +259 -0
  119. package/src/env/log-trace/opentelemetry/propagation.ts +215 -0
  120. package/src/env/log-trace/opentelemetry/tracer-provider-context.test.ts +166 -0
  121. package/src/env/log-trace/opentelemetry/tracer-provider.test.ts +379 -0
  122. package/src/env/log-trace/opentelemetry/tracer-provider.ts +612 -0
  123. package/src/env/log-trace/span-storage.test.ts +145 -0
  124. package/src/env/log-trace/span-storage.ts +230 -0
  125. package/src/env/log-trace/trace-context.test.ts +187 -0
  126. package/src/env/log-trace/trace-context.ts +162 -0
  127. package/src/env/log-trace/types.test.ts +63 -0
  128. package/src/env/log-trace/types.ts +172 -0
  129. package/src/env/mcp/README.md +244 -0
  130. package/src/env/mcp/__integration__/mcp-component.integration.test.ts +373 -0
  131. package/src/env/mcp/config.test.ts +74 -0
  132. package/src/env/mcp/config.ts +116 -0
  133. package/src/env/mcp/index.ts +41 -0
  134. package/src/env/mcp/loader.test.ts +161 -0
  135. package/src/env/mcp/loader.ts +209 -0
  136. package/src/env/mcp/mcp-component.test.ts +111 -0
  137. package/src/env/mcp/mcp-component.ts +358 -0
  138. package/src/env/mcp/mcp-config-registration.test.ts +304 -0
  139. package/src/env/mcp/mcp-config-registration.ts +50 -0
  140. package/src/env/mcp/scanner.test.ts +170 -0
  141. package/src/env/mcp/scanner.ts +246 -0
  142. package/src/env/mcp/tool/adapter.test.ts +520 -0
  143. package/src/env/mcp/tool/adapter.ts +521 -0
  144. package/src/env/mcp/tool/index.ts +5 -0
  145. package/src/env/mcp/types.test.ts +171 -0
  146. package/src/env/mcp/types.ts +79 -0
  147. package/src/env/memory/README.md +177 -0
  148. package/src/env/memory/built-in/index.ts +59 -0
  149. package/src/env/memory/built-in/recall-memory.ts +103 -0
  150. package/src/env/memory/built-in/record-memory.ts +148 -0
  151. package/src/env/memory/index.ts +20 -0
  152. package/src/env/memory/memory-component.test.ts +239 -0
  153. package/src/env/memory/memory-component.ts +503 -0
  154. package/src/env/memory/memory-config-registration.test.ts +67 -0
  155. package/src/env/memory/memory-config-registration.ts +48 -0
  156. package/src/env/memory/memory-config.ts +45 -0
  157. package/src/env/memory/memory-file.test.ts +268 -0
  158. package/src/env/memory/plugin/index.ts +48 -0
  159. package/src/env/memory/plugin/memory-agent.test.ts +249 -0
  160. package/src/env/memory/plugin/memory-agent.ts +365 -0
  161. package/src/env/memory/plugin/memory-manager.ts +198 -0
  162. package/src/env/memory/plugin/memory-plugin-agent.test.ts +145 -0
  163. package/src/env/memory/plugin/memory-plugin.ts +210 -0
  164. package/src/env/memory/plugin/plugin-simplified.test.ts +51 -0
  165. package/src/env/memory/plugin/recall-memory.test.ts +106 -0
  166. package/src/env/memory/plugin/recall-memory.ts +53 -0
  167. package/src/env/memory/plugin/types.ts +101 -0
  168. package/src/env/memory/tools/memory-agent-tools.ts +228 -0
  169. package/src/env/memory/types.ts +85 -0
  170. package/src/env/paths.ts +118 -0
  171. package/src/env/prompt/index.ts +18 -0
  172. package/src/env/prompt/memory-prompts.test.ts +91 -0
  173. package/src/env/prompt/prompt-component.test.ts +491 -0
  174. package/src/env/prompt/prompt-component.ts +619 -0
  175. package/src/env/prompt/prompt-config-registration.test.ts +213 -0
  176. package/src/env/prompt/prompt-config-registration.ts +39 -0
  177. package/src/env/prompt/prompts-index.ts +504 -0
  178. package/src/env/prompt/renderer.ts +67 -0
  179. package/src/env/prompt/types.ts +136 -0
  180. package/src/env/session/hooks.ts +18 -0
  181. package/src/env/session/index.ts +37 -0
  182. package/src/env/session/search-query-parser.test.ts +425 -0
  183. package/src/env/session/search-query-parser.ts +171 -0
  184. package/src/env/session/session-checkpoint.test.ts +523 -0
  185. package/src/env/session/session-component.extract-recent-messages.test.ts +209 -0
  186. package/src/env/session/session-component.test.ts +132 -0
  187. package/src/env/session/session-component.ts +1249 -0
  188. package/src/env/session/session-config-registration.test.ts +138 -0
  189. package/src/env/session/session-config-registration.ts +52 -0
  190. package/src/env/session/session-message-converter.test.ts +763 -0
  191. package/src/env/session/session-message-converter.ts +415 -0
  192. package/src/env/session/session-message-e2e.test.ts +448 -0
  193. package/src/env/session/session-search.test.ts +391 -0
  194. package/src/env/session/session-store.test.ts +362 -0
  195. package/src/env/session/session-store.ts +141 -0
  196. package/src/env/session/storage/index.ts +6 -0
  197. package/src/env/session/storage/memory.ts +502 -0
  198. package/src/env/session/storage/sqlite.ts +794 -0
  199. package/src/env/session/types.ts +742 -0
  200. package/src/env/skill/config.ts +39 -0
  201. package/src/env/skill/index.ts +6 -0
  202. package/src/env/skill/parser.test.ts +116 -0
  203. package/src/env/skill/parser.ts +77 -0
  204. package/src/env/skill/scanner.test.ts +211 -0
  205. package/src/env/skill/scanner.ts +119 -0
  206. package/src/env/skill/skill-component.test.ts +234 -0
  207. package/src/env/skill/skill-component.ts +352 -0
  208. package/src/env/skill/skill-config-registration.test.ts +60 -0
  209. package/src/env/skill/skill-config-registration.ts +43 -0
  210. package/src/env/skill/tool/index.ts +1 -0
  211. package/src/env/skill/tool/skill-tool.test.ts +100 -0
  212. package/src/env/skill/tool/skill-tool.ts +72 -0
  213. package/src/env/skill/types.ts +64 -0
  214. package/src/env/task/delegate/delegate-tool.test.ts +498 -0
  215. package/src/env/task/delegate/delegate-tool.ts +1014 -0
  216. package/src/env/task/delegate/index.ts +18 -0
  217. package/src/env/task/delegate/stop-tool.test.ts +140 -0
  218. package/src/env/task/delegate/stop-tool.ts +119 -0
  219. package/src/env/task/delegate/task-events.test.ts +178 -0
  220. package/src/env/task/delegate/task-events.ts +143 -0
  221. package/src/env/task/hooks/contexts.test.ts +92 -0
  222. package/src/env/task/hooks/contexts.ts +192 -0
  223. package/src/env/task/hooks/index.ts +23 -0
  224. package/src/env/task/hooks/task-hook-points.test.ts +32 -0
  225. package/src/env/task/hooks/task-hook-points.ts +54 -0
  226. package/src/env/task/index.ts +7 -0
  227. package/src/env/task/plugins/index.ts +13 -0
  228. package/src/env/task/plugins/task-plugin.test.ts +74 -0
  229. package/src/env/task/plugins/task-plugin.ts +89 -0
  230. package/src/env/task/plugins/task-tag-plugin.test.ts +377 -0
  231. package/src/env/task/plugins/task-tag-plugin.ts +319 -0
  232. package/src/env/task/plugins/task-workflow-extractor.integration.test.ts +226 -0
  233. package/src/env/task/plugins/workflow-extractor-agent.test.ts +107 -0
  234. package/src/env/task/plugins/workflow-extractor-agent.ts +225 -0
  235. package/src/env/task/storage/index.ts +6 -0
  236. package/src/env/task/storage/sqlite-task-store.test.ts +283 -0
  237. package/src/env/task/storage/sqlite-task-store.ts +903 -0
  238. package/src/env/task/storage/task-search.test.ts +291 -0
  239. package/src/env/task/tag-service.test.ts +198 -0
  240. package/src/env/task/tag-service.ts +264 -0
  241. package/src/env/task/task-component.test.ts +193 -0
  242. package/src/env/task/task-component.ts +658 -0
  243. package/src/env/task/task-config-registration.test.ts +57 -0
  244. package/src/env/task/task-config-registration.ts +37 -0
  245. package/src/env/task/task-types.test.ts +137 -0
  246. package/src/env/task/tools/complete-tool.ts +44 -0
  247. package/src/env/task/tools/create-tool.ts +49 -0
  248. package/src/env/task/tools/delete-tool.ts +43 -0
  249. package/src/env/task/tools/get-tool.ts +59 -0
  250. package/src/env/task/tools/index.ts +10 -0
  251. package/src/env/task/tools/list-tool.ts +40 -0
  252. package/src/env/task/tools/operation/create-tool.ts +48 -0
  253. package/src/env/task/tools/operation/delete-tool.ts +43 -0
  254. package/src/env/task/tools/operation/get-tool.ts +43 -0
  255. package/src/env/task/tools/operation/index.ts +9 -0
  256. package/src/env/task/tools/operation/list-tool.ts +40 -0
  257. package/src/env/task/tools/operation/operation-tools.test.ts +274 -0
  258. package/src/env/task/tools/operation/operation-types.ts +75 -0
  259. package/src/env/task/tools/operation/update-tool.ts +47 -0
  260. package/src/env/task/tools/task-tools.test.ts +203 -0
  261. package/src/env/task/tools/task-types.test.ts +75 -0
  262. package/src/env/task/tools/task-types.ts +68 -0
  263. package/src/env/task/tools/update-tool.ts +70 -0
  264. package/src/env/task/types.ts +160 -0
  265. package/src/env/tool/built-in/bash.ts +201 -0
  266. package/src/env/tool/built-in/echo.ts +29 -0
  267. package/src/env/tool/built-in/edit-file.test.ts +136 -0
  268. package/src/env/tool/built-in/edit-file.ts +92 -0
  269. package/src/env/tool/built-in/glob.test.ts +94 -0
  270. package/src/env/tool/built-in/glob.ts +65 -0
  271. package/src/env/tool/built-in/grep.test.ts +122 -0
  272. package/src/env/tool/built-in/grep.ts +108 -0
  273. package/src/env/tool/built-in/index.ts +44 -0
  274. package/src/env/tool/built-in/read-file.test.ts +84 -0
  275. package/src/env/tool/built-in/read-file.ts +75 -0
  276. package/src/env/tool/built-in/write-file.test.ts +119 -0
  277. package/src/env/tool/built-in/write-file.ts +68 -0
  278. package/src/env/tool/index.ts +24 -0
  279. package/src/env/tool/registry.test.ts +257 -0
  280. package/src/env/tool/registry.ts +167 -0
  281. package/src/env/tool/tool-component.test.ts +559 -0
  282. package/src/env/tool/tool-component.ts +563 -0
  283. package/src/env/tool/tool-config-registration.test.ts +249 -0
  284. package/src/env/tool/tool-config-registration.ts +46 -0
  285. package/src/env/tool/types.ts +267 -0
  286. package/src/env/tool/validator.test.ts +143 -0
  287. package/src/env/tool/validator.ts +44 -0
  288. package/src/env/types.ts +180 -0
  289. package/src/env/workflow/ask-user-tool-registration.test.ts +216 -0
  290. package/src/env/workflow/complex-workflow.integration.test.ts +1900 -0
  291. package/src/env/workflow/decorators/decorator-node.ts +229 -0
  292. package/src/env/workflow/decorators/decorator.test.ts +196 -0
  293. package/src/env/workflow/decorators/edge.ts +82 -0
  294. package/src/env/workflow/decorators/index.ts +31 -0
  295. package/src/env/workflow/decorators/node-as.ts +98 -0
  296. package/src/env/workflow/decorators/workflow.ts +54 -0
  297. package/src/env/workflow/engine/dag-manager.test.ts +570 -0
  298. package/src/env/workflow/engine/dag-manager.ts +594 -0
  299. package/src/env/workflow/engine/engine.ts +1422 -0
  300. package/src/env/workflow/engine/event-bus.test.ts +359 -0
  301. package/src/env/workflow/engine/event-bus.ts +156 -0
  302. package/src/env/workflow/engine/executor-agent-session.test.ts +84 -0
  303. package/src/env/workflow/engine/executor.test.ts +619 -0
  304. package/src/env/workflow/engine/executor.ts +593 -0
  305. package/src/env/workflow/engine/index.ts +24 -0
  306. package/src/env/workflow/engine/node-registry.test.ts +560 -0
  307. package/src/env/workflow/engine/node-registry.ts +289 -0
  308. package/src/env/workflow/engine/resume-removed.test.ts +22 -0
  309. package/src/env/workflow/engine/scheduler.test.ts +715 -0
  310. package/src/env/workflow/engine/scheduler.ts +318 -0
  311. package/src/env/workflow/engine/workflow-engine.test.ts +815 -0
  312. package/src/env/workflow/extractor/workflow-converter.ts +306 -0
  313. package/src/env/workflow/fixtures.ts +380 -0
  314. package/src/env/workflow/index.ts +38 -0
  315. package/src/env/workflow/integration/run-resume-unified.test.ts +186 -0
  316. package/src/env/workflow/integration/service-integration.test.ts +267 -0
  317. package/src/env/workflow/metadata/keys.ts +12 -0
  318. package/src/env/workflow/nodes/agent-component-adapter.test.ts +318 -0
  319. package/src/env/workflow/nodes/agent-component-adapter.ts +448 -0
  320. package/src/env/workflow/nodes/agent-node.test.ts +371 -0
  321. package/src/env/workflow/nodes/agent-node.ts +598 -0
  322. package/src/env/workflow/nodes/ask-user-node.ts +113 -0
  323. package/src/env/workflow/nodes/condition-node.ts +200 -0
  324. package/src/env/workflow/nodes/index.ts +9 -0
  325. package/src/env/workflow/nodes/merge-node.ts +141 -0
  326. package/src/env/workflow/nodes/skill-node.test.ts +253 -0
  327. package/src/env/workflow/nodes/skill-node.ts +393 -0
  328. package/src/env/workflow/nodes/tool-node.test.ts +251 -0
  329. package/src/env/workflow/nodes/tool-node.ts +493 -0
  330. package/src/env/workflow/nodes/workflow-llm-history.test.ts +455 -0
  331. package/src/env/workflow/nodes/workflow-node.test.ts +315 -0
  332. package/src/env/workflow/nodes/workflow-node.ts +311 -0
  333. package/src/env/workflow/service/index.ts +27 -0
  334. package/src/env/workflow/service/registry.test.ts +133 -0
  335. package/src/env/workflow/service/registry.ts +71 -0
  336. package/src/env/workflow/service/workflow-service.test.ts +310 -0
  337. package/src/env/workflow/service/workflow-service.ts +393 -0
  338. package/src/env/workflow/storage/index.ts +28 -0
  339. package/src/env/workflow/storage/mock-repositories.ts +385 -0
  340. package/src/env/workflow/storage/sqlite.test.ts +179 -0
  341. package/src/env/workflow/storage/sqlite.ts +163 -0
  342. package/src/env/workflow/storage/workflow-repo.test.ts +780 -0
  343. package/src/env/workflow/storage/workflow-repo.ts +342 -0
  344. package/src/env/workflow/tools/ask-user-tool.ts +82 -0
  345. package/src/env/workflow/tools/index.ts +26 -0
  346. package/src/env/workflow/tools/run-workflow.test.ts +352 -0
  347. package/src/env/workflow/tools/run-workflow.ts +214 -0
  348. package/src/env/workflow/types/context.ts +18 -0
  349. package/src/env/workflow/types/decorators-types.ts +198 -0
  350. package/src/env/workflow/types/event.test.ts +515 -0
  351. package/src/env/workflow/types/event.ts +193 -0
  352. package/src/env/workflow/types/index.ts +49 -0
  353. package/src/env/workflow/types/run.test.ts +437 -0
  354. package/src/env/workflow/types/run.ts +173 -0
  355. package/src/env/workflow/types/workflow-hil.ts +114 -0
  356. package/src/env/workflow/types/workflow-message.test.ts +138 -0
  357. package/src/env/workflow/types/workflow-message.ts +196 -0
  358. package/src/env/workflow/types/workflow-session.test.ts +95 -0
  359. package/src/env/workflow/types/workflow-session.ts +59 -0
  360. package/src/env/workflow/types/workflow.test.ts +495 -0
  361. package/src/env/workflow/types/workflow.ts +195 -0
  362. package/src/env/workflow/types_compat.ts +51 -0
  363. package/src/env/workflow/utils/create-workflow.ts +47 -0
  364. package/src/env/workflow/utils/execution-state.ts +245 -0
  365. package/src/env/workflow/utils/index.ts +18 -0
  366. package/src/env/workflow/utils/node-registry-helper.ts +58 -0
  367. package/src/env/workflow/utils/recovery-validator.test.ts +460 -0
  368. package/src/env/workflow/utils/recovery-validator.ts +377 -0
  369. package/src/env/workflow/utils/session-parser.test.ts +111 -0
  370. package/src/env/workflow/utils/session-parser.ts +94 -0
  371. package/src/env/workflow/utils/session-recovery.test.ts +334 -0
  372. package/src/env/workflow/utils/session-recovery.ts +188 -0
  373. package/src/env/workflow/utils/template-resolver.test.ts +258 -0
  374. package/src/env/workflow/utils/template-resolver.ts +436 -0
  375. package/src/env/workflow/utils/validation-rules.ts +149 -0
  376. package/src/env/workflow/workflow-component.ts +544 -0
  377. package/src/index.ts +422 -0
  378. package/src/utils/id.ts +21 -0
@@ -0,0 +1,334 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import {
3
+ inferNextNode,
4
+ findLastInterruptMessage,
5
+ findLastCallMessage,
6
+ parseNodeOutputs,
7
+ type ResumePoint,
8
+ } from './session-recovery';
9
+
10
+ // Mock SessionMessage type
11
+ interface MockMessage {
12
+ role: string;
13
+ content: string;
14
+ metadata: Record<string, unknown>;
15
+ }
16
+
17
+ function createMessage(role: string, content: string, metadata: Record<string, unknown>): MockMessage {
18
+ return { role, content, metadata };
19
+ }
20
+
21
+ describe('inferNextNode', () => {
22
+ describe('when no messages', () => {
23
+ it('should return entry node from definition', () => {
24
+ const messages: MockMessage[] = [];
25
+ const definition = {
26
+ entryNode: 'node_A',
27
+ nodes: { node_A: { id: 'node_A' } },
28
+ };
29
+
30
+ const result = inferNextNode(messages as any, definition);
31
+
32
+ expect(result.type).toBe('entry_node');
33
+ expect(result.nodeId).toBe('node_A');
34
+ });
35
+
36
+ it('should handle missing entryNode', () => {
37
+ const messages: MockMessage[] = [];
38
+ const definition = {};
39
+
40
+ const result = inferNextNode(messages as any, definition);
41
+
42
+ expect(result.type).toBe('entry_node');
43
+ expect(result.nodeId).toBeUndefined();
44
+ });
45
+ });
46
+
47
+ describe('when last message is workflow.node.call', () => {
48
+ it('should return resume_node type with nodeId', () => {
49
+ const messages = [
50
+ createMessage('workflow.node.call', '{}', {
51
+ type: 'workflow.node.call',
52
+ workflowNodeId: 'node_A',
53
+ workflowNodeType: 'tool',
54
+ }),
55
+ ];
56
+
57
+ const result = inferNextNode(messages as any, {});
58
+
59
+ expect(result.type).toBe('resume_node');
60
+ expect(result.nodeId).toBe('node_A');
61
+ });
62
+
63
+ it('should include agentSessionId if present', () => {
64
+ const messages = [
65
+ createMessage('workflow.node.call', '{}', {
66
+ type: 'workflow.node.call',
67
+ workflowNodeId: 'agent_1',
68
+ workflowNodeType: 'agent',
69
+ agentSessionId: 'agent_agent_1_123',
70
+ }),
71
+ ];
72
+
73
+ const result = inferNextNode(messages as any, {});
74
+
75
+ expect(result.type).toBe('resume_node');
76
+ expect(result.nodeId).toBe('agent_1');
77
+ expect(result.agentSessionId).toBe('agent_agent_1_123');
78
+ });
79
+ });
80
+
81
+ describe('when last message is workflow.node.interrupt', () => {
82
+ it('should return ask_user type with nodeId', () => {
83
+ const messages = [
84
+ createMessage('workflow.node.interrupt', 'Continue?', {
85
+ type: 'workflow.node.interrupt',
86
+ workflowNodeId: 'ask_user_1',
87
+ workflowNodeType: 'ask_user',
88
+ query: 'Continue?',
89
+ }),
90
+ ];
91
+
92
+ const result = inferNextNode(messages as any, {});
93
+
94
+ expect(result.type).toBe('ask_user');
95
+ expect(result.nodeId).toBe('ask_user_1');
96
+ });
97
+
98
+ it('should include agentSessionId if present', () => {
99
+ const messages = [
100
+ createMessage('workflow.node.interrupt', 'Confirm?', {
101
+ type: 'workflow.node.interrupt',
102
+ workflowNodeId: 'agent_1',
103
+ workflowNodeType: 'agent',
104
+ query: 'Confirm?',
105
+ agentSessionId: 'agent_agent_1_456',
106
+ }),
107
+ ];
108
+
109
+ const result = inferNextNode(messages as any, {});
110
+
111
+ expect(result.type).toBe('ask_user');
112
+ expect(result.nodeId).toBe('agent_1');
113
+ expect(result.agentSessionId).toBe('agent_agent_1_456');
114
+ });
115
+ });
116
+
117
+ describe('when last message is workflow.node.result', () => {
118
+ it('should return next_nodes from DAG edges', () => {
119
+ const messages = [
120
+ createMessage('workflow.node.call', '{}', {
121
+ type: 'workflow.node.call',
122
+ workflowNodeId: 'node_A',
123
+ }),
124
+ createMessage('workflow.node.result', '{"output":"done"}', {
125
+ type: 'workflow.node.result',
126
+ workflowNodeId: 'node_A',
127
+ workflowNodeType: 'tool',
128
+ success: true,
129
+ }),
130
+ ];
131
+
132
+ const definition = {
133
+ edges: [
134
+ { from: 'node_A', to: 'node_B' },
135
+ { from: 'node_A', to: 'node_C' },
136
+ ],
137
+ };
138
+
139
+ const result = inferNextNode(messages as any, definition);
140
+
141
+ expect(result.type).toBe('next_nodes');
142
+ expect(result.nodeIds).toEqual(['node_B', 'node_C']);
143
+ });
144
+
145
+ it('should return empty array if no edges from node', () => {
146
+ const messages = [
147
+ createMessage('workflow.node.result', '{"output":"done"}', {
148
+ type: 'workflow.node.result',
149
+ workflowNodeId: 'node_A',
150
+ success: true,
151
+ }),
152
+ ];
153
+
154
+ const definition = {
155
+ edges: [
156
+ { from: 'node_B', to: 'node_C' },
157
+ ],
158
+ };
159
+
160
+ const result = inferNextNode(messages as any, definition);
161
+
162
+ expect(result.type).toBe('next_nodes');
163
+ expect(result.nodeIds).toEqual([]);
164
+ });
165
+
166
+ it('should return empty array if no edges defined', () => {
167
+ const messages = [
168
+ createMessage('workflow.node.result', '{"output":"done"}', {
169
+ type: 'workflow.node.result',
170
+ workflowNodeId: 'node_A',
171
+ success: true,
172
+ }),
173
+ ];
174
+
175
+ const result = inferNextNode(messages as any, {});
176
+
177
+ expect(result.type).toBe('next_nodes');
178
+ expect(result.nodeIds).toEqual([]);
179
+ });
180
+ });
181
+
182
+ describe('when last message has unknown type', () => {
183
+ it('should find last call message and resume', () => {
184
+ const messages = [
185
+ createMessage('user', 'hello', {}),
186
+ createMessage('workflow.node.call', '{}', {
187
+ type: 'workflow.node.call',
188
+ workflowNodeId: 'node_A',
189
+ }),
190
+ createMessage('system', 'some status', {
191
+ type: 'unknown',
192
+ }),
193
+ ];
194
+
195
+ const result = inferNextNode(messages as any, {});
196
+
197
+ expect(result.type).toBe('resume_node');
198
+ expect(result.nodeId).toBe('node_A');
199
+ });
200
+
201
+ it('should fallback to entry node if no call found', () => {
202
+ const messages = [
203
+ createMessage('user', 'hello', {}),
204
+ ];
205
+
206
+ const definition = { entryNode: 'start' };
207
+
208
+ const result = inferNextNode(messages as any, definition);
209
+
210
+ expect(result.type).toBe('entry_node');
211
+ expect(result.nodeId).toBe('start');
212
+ });
213
+ });
214
+ });
215
+
216
+ describe('findLastInterruptMessage', () => {
217
+ it('should return last interrupt message', () => {
218
+ const messages = [
219
+ createMessage('workflow.node.call', '{}', { type: 'workflow.node.call' }),
220
+ createMessage('workflow.node.result', '{}', { type: 'workflow.node.result' }),
221
+ createMessage('workflow.node.interrupt', 'Continue?', {
222
+ type: 'workflow.node.interrupt',
223
+ workflowNodeId: 'ask_1',
224
+ }),
225
+ ];
226
+
227
+ const result = findLastInterruptMessage(messages as any);
228
+
229
+ expect(result).not.toBeNull();
230
+ expect(result!.metadata.workflowNodeId).toBe('ask_1');
231
+ });
232
+
233
+ it('should return null if no interrupt message', () => {
234
+ const messages = [
235
+ createMessage('workflow.node.call', '{}', { type: 'workflow.node.call' }),
236
+ createMessage('workflow.node.result', '{}', { type: 'workflow.node.result' }),
237
+ ];
238
+
239
+ const result = findLastInterruptMessage(messages as any);
240
+
241
+ expect(result).toBeNull();
242
+ });
243
+
244
+ it('should return null for empty array', () => {
245
+ const result = findLastInterruptMessage([]);
246
+ expect(result).toBeNull();
247
+ });
248
+ });
249
+
250
+ describe('findLastCallMessage', () => {
251
+ it('should return last call message', () => {
252
+ const messages = [
253
+ createMessage('workflow.node.call', '{}', {
254
+ type: 'workflow.node.call',
255
+ workflowNodeId: 'node_A',
256
+ }),
257
+ createMessage('workflow.node.call', '{}', {
258
+ type: 'workflow.node.call',
259
+ workflowNodeId: 'node_B',
260
+ }),
261
+ ];
262
+
263
+ const result = findLastCallMessage(messages as any);
264
+
265
+ expect(result).not.toBeNull();
266
+ expect(result!.metadata.workflowNodeId).toBe('node_B');
267
+ });
268
+
269
+ it('should return null if no call message', () => {
270
+ const messages = [
271
+ createMessage('user', 'hello', {}),
272
+ createMessage('workflow.node.result', '{}', { type: 'workflow.node.result' }),
273
+ ];
274
+
275
+ const result = findLastCallMessage(messages as any);
276
+
277
+ expect(result).toBeNull();
278
+ });
279
+ });
280
+
281
+ describe('parseNodeOutputs', () => {
282
+ it('should parse outputs from call-result pairs', () => {
283
+ const messages = [
284
+ createMessage('workflow.node.call', '{}', {
285
+ type: 'workflow.node.call',
286
+ workflowNodeId: 'node_A',
287
+ }),
288
+ createMessage('workflow.node.result', '{"output":"result_A"}', {
289
+ type: 'workflow.node.result',
290
+ workflowNodeId: 'node_A',
291
+ }),
292
+ createMessage('workflow.node.call', '{}', {
293
+ type: 'workflow.node.call',
294
+ workflowNodeId: 'node_B',
295
+ }),
296
+ createMessage('workflow.node.result', '{"output":"result_B"}', {
297
+ type: 'workflow.node.result',
298
+ workflowNodeId: 'node_B',
299
+ }),
300
+ ];
301
+
302
+ const result = parseNodeOutputs(messages as any);
303
+
304
+ expect(result.get('node_A')).toEqual({ output: 'result_A' });
305
+ expect(result.get('node_B')).toEqual({ output: 'result_B' });
306
+ });
307
+
308
+ it('should handle JSON parse error gracefully', () => {
309
+ const messages = [
310
+ createMessage('workflow.node.call', '{}', {
311
+ type: 'workflow.node.call',
312
+ workflowNodeId: 'node_A',
313
+ }),
314
+ createMessage('workflow.node.result', 'not json', {
315
+ type: 'workflow.node.result',
316
+ workflowNodeId: 'node_A',
317
+ }),
318
+ ];
319
+
320
+ const result = parseNodeOutputs(messages as any);
321
+
322
+ expect(result.get('node_A')).toBe('not json');
323
+ });
324
+
325
+ it('should return empty map for no outputs', () => {
326
+ const messages = [
327
+ createMessage('user', 'hello', {}),
328
+ ];
329
+
330
+ const result = parseNodeOutputs(messages as any);
331
+
332
+ expect(result.size).toBe(0);
333
+ });
334
+ });
@@ -0,0 +1,188 @@
1
+ /**
2
+ * Session Recovery Utilities
3
+ *
4
+ * Utilities for inferring the next execution point from session messages.
5
+ * This is the core of the unified run/resume mechanism.
6
+ */
7
+
8
+ import type { SessionMessage } from '../../session/types';
9
+
10
+ /**
11
+ * Represents a resume point - where to continue execution from
12
+ */
13
+ export interface ResumePoint {
14
+ /** Type of resume point */
15
+ type: 'entry_node' | 'resume_node' | 'ask_user' | 'next_nodes';
16
+ /** Node ID (for single node resume) */
17
+ nodeId?: string;
18
+ /** Node IDs (for multiple next nodes) */
19
+ nodeIds?: string[];
20
+ /** Agent sub-session ID (for agent node resume) */
21
+ agentSessionId?: string;
22
+ /** Input for the node */
23
+ input?: unknown;
24
+ }
25
+
26
+ /**
27
+ * Infer the next node to execute based on session messages
28
+ *
29
+ * Decision logic:
30
+ * - No messages → execute entry node
31
+ * - Last = workflow.node.call → resume this node (incomplete)
32
+ * - Last = workflow.node.interrupt → resume this node (ask_user)
33
+ * - Last = workflow.node.result → execute next nodes from DAG
34
+ * - Unknown → find last call, resume it, or fallback to entry
35
+ */
36
+ export function inferNextNode(
37
+ messages: SessionMessage[],
38
+ definition: {
39
+ entryNode?: string;
40
+ edges?: Array<{ from: string; to: string }>;
41
+ }
42
+ ): ResumePoint {
43
+ if (messages.length === 0) {
44
+ // First run - execute entry node
45
+ return { type: 'entry_node', nodeId: definition.entryNode };
46
+ }
47
+
48
+ const lastMessage = messages[messages.length - 1];
49
+ const metadata = lastMessage.metadata as Record<string, unknown>;
50
+
51
+ switch (metadata?.type) {
52
+ case 'workflow.node.call':
53
+ // Node was interrupted (not completed)
54
+ return {
55
+ type: 'resume_node',
56
+ nodeId: metadata.workflowNodeId as string,
57
+ agentSessionId: metadata.agentSessionId as string | undefined,
58
+ };
59
+
60
+ case 'workflow.node.interrupt':
61
+ // Ask_user or ESC interrupted
62
+ return {
63
+ type: 'ask_user',
64
+ nodeId: metadata.workflowNodeId as string,
65
+ agentSessionId: metadata.agentSessionId as string | undefined,
66
+ };
67
+
68
+ case 'workflow.node.result':
69
+ // Node completed, get next from DAG
70
+ return getNextNodes(metadata.workflowNodeId as string, definition);
71
+
72
+ default:
73
+ // Unknown message type, try to find last call
74
+ const lastCall = findLastCallMessage(messages);
75
+ if (lastCall) {
76
+ const callMetadata = lastCall.metadata as Record<string, unknown>;
77
+ return {
78
+ type: 'resume_node',
79
+ nodeId: callMetadata.workflowNodeId as string,
80
+ agentSessionId: callMetadata.agentSessionId as string | undefined,
81
+ };
82
+ }
83
+ // No call found, fallback to entry
84
+ return { type: 'entry_node', nodeId: definition.entryNode };
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Get next nodes from DAG edges
90
+ */
91
+ function getNextNodes(
92
+ completedNodeId: string,
93
+ definition: { edges?: Array<{ from: string; to: string }> }
94
+ ): ResumePoint {
95
+ if (!definition.edges) {
96
+ return { type: 'next_nodes', nodeIds: [] };
97
+ }
98
+
99
+ const nextNodeIds = definition.edges
100
+ .filter(edge => edge.from === completedNodeId)
101
+ .map(edge => edge.to);
102
+
103
+ return { type: 'next_nodes', nodeIds: nextNodeIds };
104
+ }
105
+
106
+ /**
107
+ * Find the last interrupt message in the session
108
+ */
109
+ export function findLastInterruptMessage(
110
+ messages: SessionMessage[]
111
+ ): SessionMessage | null {
112
+ for (let i = messages.length - 1; i >= 0; i--) {
113
+ const msg = messages[i];
114
+ if ((msg.metadata as Record<string, unknown>)?.type === 'workflow.node.interrupt') {
115
+ return msg;
116
+ }
117
+ }
118
+ return null;
119
+ }
120
+
121
+ /**
122
+ * Find the last call message in the session
123
+ */
124
+ export function findLastCallMessage(
125
+ messages: SessionMessage[]
126
+ ): SessionMessage | null {
127
+ for (let i = messages.length - 1; i >= 0; i--) {
128
+ const msg = messages[i];
129
+ if ((msg.metadata as Record<string, unknown>)?.type === 'workflow.node.call') {
130
+ return msg;
131
+ }
132
+ }
133
+ return null;
134
+ }
135
+
136
+ /**
137
+ * Parse node outputs from session messages
138
+ *
139
+ * Extracts outputs by matching workflow.node.call with workflow.node.result pairs
140
+ */
141
+ export function parseNodeOutputs(
142
+ messages: SessionMessage[]
143
+ ): Map<string, unknown> {
144
+ const outputs = new Map<string, unknown>();
145
+ let lastCallNodeId: string | null = null;
146
+
147
+ for (const msg of messages) {
148
+ const metadata = msg.metadata as Record<string, unknown>;
149
+
150
+ if (metadata?.type === 'workflow.node.call') {
151
+ lastCallNodeId = metadata.workflowNodeId as string;
152
+ } else if (metadata?.type === 'workflow.node.result' && lastCallNodeId) {
153
+ try {
154
+ outputs.set(lastCallNodeId, JSON.parse(msg.content as string));
155
+ } catch {
156
+ outputs.set(lastCallNodeId, msg.content);
157
+ }
158
+ lastCallNodeId = null;
159
+ }
160
+ }
161
+
162
+ return outputs;
163
+ }
164
+
165
+ /**
166
+ * Check if session has pending ask_user interrupt
167
+ */
168
+ export function hasPendingAskUser(messages: SessionMessage[]): boolean {
169
+ if (messages.length === 0) return false;
170
+
171
+ const lastMessage = messages[messages.length - 1];
172
+ const metadata = lastMessage.metadata as Record<string, unknown>;
173
+
174
+ return metadata?.type === 'workflow.node.interrupt';
175
+ }
176
+
177
+ /**
178
+ * Get agent session ID from last interrupt message
179
+ */
180
+ export function getAgentSessionIdFromInterrupt(
181
+ messages: SessionMessage[]
182
+ ): string | null {
183
+ const lastInterrupt = findLastInterruptMessage(messages);
184
+ if (!lastInterrupt) return null;
185
+
186
+ const metadata = lastInterrupt.metadata as Record<string, unknown>;
187
+ return (metadata?.agentSessionId as string) || null;
188
+ }