@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,523 @@
1
+ /**
2
+ * @fileoverview Session Checkpoint Tests
3
+ *
4
+ * TDD: 先写测试 (RED),再实现代码 (GREEN)
5
+ */
6
+
7
+ import { describe, test, expect, beforeEach, afterEach, vi } from "bun:test";
8
+ import { SessionComponent } from "./session-component";
9
+ import { ConfigComponent } from "../../config/config-component";
10
+ import type { Environment } from "../interface";
11
+ import * as fsSync from "fs";
12
+ import * as path from "path";
13
+ import * as os from "os";
14
+
15
+ // ============================================================================
16
+ // Test Utilities (for test isolation)
17
+ // ============================================================================
18
+
19
+ function createTempDbPath(): string {
20
+ const timestamp = Date.now();
21
+ const random = Math.random().toString(36).substring(2, 8);
22
+ return path.join(os.tmpdir(), `test-sessions-${timestamp}-${random}.db`);
23
+ }
24
+
25
+ async function cleanupTempDb(dbPath: string): Promise<void> {
26
+ try { await fsSync.promises.unlink(dbPath); } catch {}
27
+ try { await fsSync.promises.unlink(`${dbPath}-wal`); } catch {}
28
+ try { await fsSync.promises.unlink(`${dbPath}-shm`); } catch {}
29
+ }
30
+
31
+ describe("SessionComponent Checkpoint", () => {
32
+ let component: SessionComponent;
33
+ let configComponent: ConfigComponent;
34
+ let mockEnv: Environment;
35
+ let tempDbPath: string;
36
+
37
+ beforeEach(() => {
38
+ component = new SessionComponent();
39
+ configComponent = new ConfigComponent();
40
+ tempDbPath = createTempDbPath();
41
+
42
+ mockEnv = {
43
+ name: "test-env",
44
+ version: "1.0.0",
45
+ getComponent: vi.fn((name: string) => {
46
+ if (name === "config") return configComponent;
47
+ return undefined;
48
+ }),
49
+ hasComponent: vi.fn((name: string) => name === "config"),
50
+ logger: vi.fn(),
51
+ trace: vi.fn(),
52
+ } as unknown as Environment;
53
+ });
54
+
55
+ afterEach(async () => {
56
+ // Stop component to release resources
57
+ if (component.getStatus() !== "stopped") {
58
+ try {
59
+ await component.stop();
60
+ } catch {}
61
+ }
62
+ // Clean up temporary database
63
+ await cleanupTempDb(tempDbPath);
64
+ vi.restoreAllMocks();
65
+ });
66
+
67
+ describe("Checkpoint types", () => {
68
+ test("should have version 1.1.0 or higher", async () => {
69
+ await component.init({
70
+ env: mockEnv,
71
+ options: {
72
+ configComponent,
73
+ config: { storage: { type: "sqlite", dbPath: tempDbPath } }
74
+ }
75
+ });
76
+ expect(component.version).toBe("1.1.0");
77
+ });
78
+ });
79
+
80
+ describe("create with checkpoints metadata", () => {
81
+ test("should initialize session with checkpoints metadata", async () => {
82
+ await component.init({
83
+ env: mockEnv,
84
+ options: {
85
+ configComponent,
86
+ config: { storage: { type: "sqlite", dbPath: tempDbPath } }
87
+ }
88
+ });
89
+ const session = await component.create({ title: "Test Session" });
90
+
91
+ expect(session.metadata).toBeDefined();
92
+ expect(session.metadata?.checkpoints).toBeDefined();
93
+ expect(session.metadata?.checkpoints?.checkpoints).toEqual([]);
94
+ expect(session.metadata?.checkpoints?.latestCheckpointId).toBeUndefined();
95
+ });
96
+ });
97
+
98
+ describe("previewCompact", () => {
99
+ test("should preview compact without making changes", async () => {
100
+ await component.init({
101
+ env: mockEnv,
102
+ options: {
103
+ configComponent,
104
+ config: { storage: { type: "sqlite", dbPath: tempDbPath } }
105
+ }
106
+ });
107
+ const session = await component.create({ title: "Test" });
108
+
109
+ // Add some messages
110
+ await component.addMessage(session.id, { role: "user", content: "Hello" });
111
+ await component.addMessage(session.id, { role: "assistant", content: "Hi there" });
112
+ await component.addMessage(session.id, { role: "user", content: "How are you?" });
113
+
114
+ const preview = await component.previewCompact(session.id);
115
+
116
+ expect(preview).toBeDefined();
117
+ expect(preview.messageCountToCompact).toBe(3);
118
+ expect(preview.wouldTrigger).toBe(false); // Less than maxMessages
119
+ });
120
+
121
+ test("should throw error for non-existent session", async () => {
122
+ await component.init({
123
+ env: mockEnv,
124
+ options: {
125
+ configComponent,
126
+ config: { storage: { type: "sqlite", dbPath: tempDbPath } }
127
+ }
128
+ });
129
+
130
+ await expect(component.previewCompact("non-existent")).rejects.toThrow("Session not found");
131
+ });
132
+ });
133
+
134
+ describe("getCheckpoints", () => {
135
+ test("should return empty array for session without checkpoints", async () => {
136
+ await component.init({
137
+ env: mockEnv,
138
+ options: {
139
+ configComponent,
140
+ config: { storage: { type: "sqlite", dbPath: tempDbPath } }
141
+ }
142
+ });
143
+ const session = await component.create({ title: "Test" });
144
+
145
+ const checkpoints = await component.getCheckpoints(session.id);
146
+
147
+ expect(checkpoints).toEqual([]);
148
+ });
149
+
150
+ test("should return checkpoints after compact", async () => {
151
+ await component.init({
152
+ env: mockEnv,
153
+ options: {
154
+ configComponent,
155
+ config: { storage: { type: "sqlite", dbPath: tempDbPath } }
156
+ }
157
+ });
158
+ const session = await component.create({ title: "Test" });
159
+
160
+ // This test will fail because compact needs SummaryAgent
161
+ // We'll implement it after setting up the mock
162
+ });
163
+ });
164
+
165
+ describe("getCheckpoint", () => {
166
+ test("should return undefined for non-existent checkpoint", async () => {
167
+ await component.init({
168
+ env: mockEnv,
169
+ options: {
170
+ configComponent,
171
+ config: { storage: { type: "sqlite", dbPath: tempDbPath } }
172
+ }
173
+ });
174
+ const session = await component.create({ title: "Test" });
175
+
176
+ const checkpoint = await component.getCheckpoint(session.id, "non-existent");
177
+
178
+ expect(checkpoint).toBeUndefined();
179
+ });
180
+ });
181
+
182
+ describe("deleteCheckpoint", () => {
183
+ test("should return false for non-existent checkpoint", async () => {
184
+ await component.init({
185
+ env: mockEnv,
186
+ options: {
187
+ configComponent,
188
+ config: { storage: { type: "sqlite", dbPath: tempDbPath } }
189
+ }
190
+ });
191
+ const session = await component.create({ title: "Test" });
192
+
193
+ const result = await component.deleteCheckpoint(session.id, "non-existent");
194
+
195
+ expect(result).toBe(false);
196
+ });
197
+ });
198
+
199
+ describe("getContext", () => {
200
+ test("should get context from session", async () => {
201
+ await component.init({
202
+ env: mockEnv,
203
+ options: {
204
+ configComponent,
205
+ config: { storage: { type: "sqlite", dbPath: tempDbPath } }
206
+ }
207
+ });
208
+ const session = await component.create({ title: "Test" });
209
+
210
+ const ctx = await component.getContext(session.id);
211
+
212
+ expect(ctx).toBeDefined();
213
+ expect(ctx.session).toBeDefined();
214
+ expect(ctx.messages).toBeDefined();
215
+ expect(Array.isArray(ctx.messages)).toBe(true);
216
+ });
217
+
218
+ test("should throw error for non-existent session", async () => {
219
+ await component.init({
220
+ env: mockEnv,
221
+ options: {
222
+ configComponent,
223
+ config: { storage: { type: "sqlite", dbPath: tempDbPath } }
224
+ }
225
+ });
226
+
227
+ await expect(component.getContext("non-existent")).rejects.toThrow("Session not found");
228
+ });
229
+
230
+ test("should return full history when fullHistory is true", async () => {
231
+ await component.init({
232
+ env: mockEnv,
233
+ options: {
234
+ configComponent,
235
+ config: { storage: { type: "sqlite", dbPath: tempDbPath } }
236
+ }
237
+ });
238
+ const session = await component.create({ title: "Test" });
239
+ await component.addMessage(session.id, { role: "user", content: "Hello" });
240
+
241
+ const ctx = await component.getContext(session.id, { fullHistory: true });
242
+
243
+ expect(ctx.totalMessageCount).toBe(1);
244
+ expect(ctx.messages.length).toBe(1);
245
+ });
246
+
247
+ test("should apply message limit", async () => {
248
+ await component.init({ env: mockEnv, options: { configComponent, config: { storage: { type: "sqlite", dbPath: tempDbPath } } } });
249
+ const session = await component.create({ title: "Test" });
250
+
251
+ for (let i = 0; i < 10; i++) {
252
+ await component.addMessage(session.id, { role: "user", content: `Message ${i}` });
253
+ }
254
+
255
+ const ctx = await component.getContext(session.id, { messageLimit: 5 });
256
+
257
+ expect(ctx.messages.length).toBeLessThanOrEqual(5);
258
+ });
259
+
260
+ test("should get all messages when session has more than 50 messages", async () => {
261
+ // This test verifies the bug fix: getMessages has default limit=50
262
+ // which causes incomplete message retrieval when session has > 50 messages
263
+ await component.init({ env: mockEnv, options: { configComponent, config: { storage: { type: "sqlite", dbPath: tempDbPath } } } });
264
+ const session = await component.create({ title: "Test" });
265
+
266
+ // Add 60 messages (exceeds default limit of 50)
267
+ for (let i = 0; i < 60; i++) {
268
+ await component.addMessage(session.id, { role: "user", content: `Message ${i}` });
269
+ }
270
+
271
+ const ctx = await component.getContext(session.id);
272
+
273
+ // Should return all 60 messages, not just 50
274
+ expect(ctx.messages.length).toBe(60);
275
+ expect(ctx.totalMessageCount).toBe(60);
276
+ expect(ctx.messages[0].content).toBe("Message 0");
277
+ expect(ctx.messages[59].content).toBe("Message 59");
278
+ });
279
+
280
+ test("should get all messages including checkpoints when session has > 50 messages", async () => {
281
+ // Test that getContext returns all messages when session has > 50 messages
282
+ // (optimization with checkpoint is tested separately)
283
+ await component.init({ env: mockEnv, options: { configComponent, config: { storage: { type: "sqlite", dbPath: tempDbPath } } } });
284
+ const session = await component.create({ title: "Test" });
285
+
286
+ // Add 60 messages (exceeds default limit of 50)
287
+ for (let i = 0; i < 60; i++) {
288
+ await component.addMessage(session.id, { role: "user", content: `Message ${i}` });
289
+ }
290
+
291
+ const ctx = await component.getContext(session.id);
292
+
293
+ // Should return all 60 messages
294
+ expect(ctx.messages.length).toBe(60);
295
+ expect(ctx.totalMessageCount).toBe(60);
296
+ });
297
+
298
+ test("should read from checkpoint when checkpoint metadata exists", async () => {
299
+ // Test the optimization: when checkpoint exists in session metadata,
300
+ // getContext should read from checkpoint position, not from 0
301
+ await component.init({ env: mockEnv, options: { configComponent, config: { storage: { type: "sqlite", dbPath: tempDbPath } } } });
302
+ const session = await component.create({ title: "Test" });
303
+
304
+ // Add 10 messages
305
+ for (let i = 0; i < 10; i++) {
306
+ await component.addMessage(session.id, { role: "user", content: `Message ${i}` });
307
+ }
308
+
309
+ // Add a checkpoint message at position 10
310
+ await component.addMessage(session.id, {
311
+ role: "user",
312
+ content: "# Checkpoint",
313
+ metadata: { isCheckpoint: true, checkpointId: "cp_test" }
314
+ });
315
+
316
+ // Add 10 more messages (total 21, with checkpoint at position 10)
317
+ for (let i = 10; i < 20; i++) {
318
+ await component.addMessage(session.id, { role: "user", content: `Message ${i}` });
319
+ }
320
+
321
+ // Without checkpoint metadata in session, should return all 21 messages
322
+ const ctxWithoutMetadata = await component.getContext(session.id);
323
+ expect(ctxWithoutMetadata.messages.length).toBe(21);
324
+
325
+ // With checkpoint metadata in session, should return only 11 messages (from checkpoint)
326
+ // Note: The optimization in getContext reads from checkpoint.messageIndex when available
327
+ });
328
+
329
+ test("should correctly identify checkpoint position from metadata", async () => {
330
+ // Verify that checkpoint messageIndex is correctly tracked
331
+ await component.init({ env: mockEnv, options: { configComponent, config: { storage: { type: "sqlite", dbPath: tempDbPath } } } });
332
+ const session = await component.create({ title: "Test" });
333
+
334
+ // Add messages
335
+ await component.addMessage(session.id, { role: "user", content: "First" });
336
+ await component.addMessage(session.id, { role: "user", content: "Second" });
337
+
338
+ // Get checkpoints - should be empty initially
339
+ const checkpointsBefore = await component.getCheckpoints(session.id);
340
+ expect(checkpointsBefore.length).toBe(0);
341
+
342
+ // Add checkpoint message
343
+ await component.addMessage(session.id, {
344
+ role: "user",
345
+ content: "# Checkpoint",
346
+ metadata: { isCheckpoint: true, checkpointId: "cp_manual" }
347
+ });
348
+
349
+ // Add more messages
350
+ await component.addMessage(session.id, { role: "user", content: "After checkpoint" });
351
+
352
+ // Verify we can get the checkpoint by ID (when it's stored properly)
353
+ const checkpoint = await component.getCheckpoint(session.id, "cp_manual");
354
+ // Note: This will be undefined unless the checkpoint was created via compact()
355
+ // which properly stores it in the checkpoints cache
356
+ });
357
+
358
+ test("should get all messages with fullHistory when session has > 50 messages", async () => {
359
+ // Test that fullHistory returns ALL messages including those before checkpoint
360
+ await component.init({ env: mockEnv, options: { configComponent, config: { storage: { type: "sqlite", dbPath: tempDbPath } } } });
361
+ const session = await component.create({ title: "Test" });
362
+
363
+ // Add 30 messages
364
+ for (let i = 0; i < 30; i++) {
365
+ await component.addMessage(session.id, { role: "user", content: `Message ${i}` });
366
+ }
367
+
368
+ // Add a checkpoint message
369
+ await component.addMessage(session.id, {
370
+ role: "user",
371
+ content: "# Checkpoint",
372
+ metadata: { isCheckpoint: true, checkpointId: "cp_test" }
373
+ });
374
+
375
+ // Add 40 more messages (total 71, with checkpoint)
376
+ for (let i = 30; i < 70; i++) {
377
+ await component.addMessage(session.id, { role: "user", content: `Message ${i}` });
378
+ }
379
+
380
+ const ctx = await component.getContext(session.id, { fullHistory: true });
381
+
382
+ // Should return ALL 71 messages
383
+ expect(ctx.messages.length).toBe(71);
384
+ expect(ctx.totalMessageCount).toBe(71);
385
+ expect(ctx.checkpoints.length).toBe(1);
386
+ });
387
+ });
388
+
389
+ describe("shouldCompact", () => {
390
+ test("should return false when messages below threshold", async () => {
391
+ await component.init({
392
+ env: mockEnv,
393
+ options: {
394
+ configComponent,
395
+ config: {
396
+ maxMessages: 100,
397
+ storage: { type: "sqlite", dbPath: tempDbPath }
398
+ }
399
+ }
400
+ });
401
+ const session = await component.create({ title: "Test" });
402
+ await component.addMessage(session.id, { role: "user", content: "Hi" });
403
+
404
+ const result = await component.shouldCompact(session.id);
405
+
406
+ expect(result).toBe(false);
407
+ });
408
+ });
409
+ });
410
+
411
+ describe("SessionCheckpoint types", () => {
412
+ test("should have required checkpoint properties", () => {
413
+ // Test checkpoint structure
414
+ const checkpoint = {
415
+ id: "cp_test",
416
+ messageIndex: 0,
417
+ title: "Test Checkpoint",
418
+ createdAt: Date.now(),
419
+ type: "compact" as const,
420
+ summary: "Test summary",
421
+ processKeyPoints: ["Point 1", "Point 2"],
422
+ currentState: "Current state",
423
+ nextSteps: ["Next step"],
424
+ messageCountBefore: 10,
425
+ userIntents: [], // New field
426
+ };
427
+
428
+ expect(checkpoint.id).toBe("cp_test");
429
+ expect(checkpoint.type).toBe("compact");
430
+ expect(Array.isArray(checkpoint.processKeyPoints)).toBe(true);
431
+ expect(typeof checkpoint.currentState).toBe("string");
432
+ expect(Array.isArray(checkpoint.userIntents)).toBe(true);
433
+ });
434
+
435
+ test("should support userIntents field in checkpoint", () => {
436
+ // Test that checkpoint supports userIntents
437
+ const checkpoint = {
438
+ id: "cp_test",
439
+ messageIndex: 0,
440
+ title: "Test Checkpoint",
441
+ createdAt: Date.now(),
442
+ type: "compact" as const,
443
+ summary: "Test summary",
444
+ processKeyPoints: [],
445
+ currentState: "Current state",
446
+ nextSteps: [],
447
+ messageCountBefore: 10,
448
+ userIntents: [
449
+ "Fix login bug",
450
+ "Optimize database query",
451
+ "Write unit tests"
452
+ ],
453
+ };
454
+
455
+ expect(checkpoint.userIntents).toBeDefined();
456
+ expect(checkpoint.userIntents.length).toBe(3);
457
+ expect(checkpoint.userIntents[0]).toBe("Fix login bug");
458
+ expect(checkpoint.userIntents).toContain("Optimize database query");
459
+ });
460
+
461
+ test("userIntents should be an array of strings", () => {
462
+ const checkpoint = {
463
+ id: "cp_test",
464
+ messageIndex: 0,
465
+ title: "Test",
466
+ createdAt: Date.now(),
467
+ type: "compact" as const,
468
+ summary: "",
469
+ processKeyPoints: [],
470
+ currentState: "",
471
+ nextSteps: [],
472
+ messageCountBefore: 0,
473
+ userIntents: ["Intent 1", "Intent 2", "Intent 3"],
474
+ };
475
+
476
+ checkpoint.userIntents.forEach(intent => {
477
+ expect(typeof intent).toBe("string");
478
+ });
479
+ });
480
+
481
+ test("userIntents can be empty", () => {
482
+ const checkpoint = {
483
+ id: "cp_test",
484
+ messageIndex: 0,
485
+ title: "Test",
486
+ createdAt: Date.now(),
487
+ type: "compact" as const,
488
+ summary: "",
489
+ processKeyPoints: [],
490
+ currentState: "",
491
+ nextSteps: [],
492
+ messageCountBefore: 0,
493
+ userIntents: [],
494
+ };
495
+
496
+ expect(checkpoint.userIntents).toEqual([]);
497
+ });
498
+
499
+ test("userIntents should have reasonable limit", () => {
500
+ // Intent descriptions should be concise
501
+ const checkpoint = {
502
+ id: "cp_test",
503
+ messageIndex: 0,
504
+ title: "Test",
505
+ createdAt: Date.now(),
506
+ type: "compact" as const,
507
+ summary: "",
508
+ processKeyPoints: [],
509
+ currentState: "",
510
+ nextSteps: [],
511
+ messageCountBefore: 0,
512
+ userIntents: [
513
+ "Fix auth module",
514
+ "Update dependencies"
515
+ ],
516
+ };
517
+
518
+ // Each intent should be a concise string (not too long)
519
+ checkpoint.userIntents.forEach(intent => {
520
+ expect(intent.length).toBeLessThan(200);
521
+ });
522
+ });
523
+ });