@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,1014 @@
1
+ /**
2
+ * @fileoverview delegate_task Tool
3
+ *
4
+ * 基于 agent-core 的 delegate_task 实现
5
+ * 参考: packages/core/src/core/environment/expend/task/task-tool.ts
6
+ *
7
+ * 功能:
8
+ * - 委派子Agent执行任务(同步/后台模式)
9
+ * - 支持多种 subagent 类型
10
+ * - 支持任务关联(task_id)
11
+ * - 发布 EnvEvent 事件
12
+ */
13
+
14
+ import { z } from "zod";
15
+ import type { Tool, ToolContext, ToolResult } from "../../tool/types";
16
+ import type { TaskComponent } from "../task-component";
17
+ import type { SessionComponent } from "../../session/session-component";
18
+ import { createLogger } from "../../log-trace/logger";
19
+ import {
20
+ TaskEventTypes,
21
+ createTaskStartedPayload,
22
+ createTaskProgressPayload,
23
+ createTaskCompletedPayload
24
+ } from "./task-events";
25
+ import { env } from "process";
26
+ import { AgentComponent } from "../../agent";
27
+
28
+ // Hook 机制
29
+ import { globalHookManager } from "../../hook/global-hook-manager";
30
+ import { TaskHookPoints } from "../hooks";
31
+ import type { TaskDelegateContext } from "../hooks/contexts";
32
+ import type { TagService } from "../tag-service";
33
+
34
+ const logger = createLogger("task:delegate");
35
+
36
+ // ============================================================================
37
+ // SubAgent Types (简化版)
38
+ // ============================================================================
39
+
40
+ export interface SubAgentSpec {
41
+ id: string;
42
+ name: string;
43
+ description: string;
44
+ mode: "subagent" | "primary" | "all";
45
+ promptOverride?: string;
46
+ /** 允许的工具列表(白名单) */
47
+ allowedTools?: string[];
48
+ /** 拒绝的工具列表(黑名单) */
49
+ deniedTools?: string[];
50
+ }
51
+
52
+ export const builtInSubAgents: SubAgentSpec[] = [
53
+ {
54
+ id: "general",
55
+ name: "general",
56
+ mode: "subagent",
57
+ description: "General-purpose agent for researching complex questions and executing multi-step tasks.",
58
+ promptOverride: `You are a subagent created by the main agent to handle a specific task.
59
+
60
+ ## Your Role
61
+ - You were created to handle: {task_description}
62
+ - Complete this task. That's your entire purpose.
63
+ - You are NOT the main agent. Don't try to be.
64
+
65
+ ## Task Context Awareness (Required Behavior)
66
+
67
+ **IMPORTANT: Before starting any work, you MUST gather task context to avoid working with outdated or missing information.**
68
+
69
+ 1. **Read task details first**: Use \`task_get\` to read the task's:
70
+ - \`description\`: Detailed description of what needs to be done
71
+ - \`goals_and_expected_deliverables\`: Clear success criteria and expected outputs
72
+ - \`current_status\`: Current work progress
73
+ - \`parent_task_id\`: If exists, this is a sub-task
74
+
75
+ 2. **Read recent operations**: Use \`task_operation_list\` to get the last ~15 operation records
76
+ - These provide history, progress, decisions, and context from previous work
77
+
78
+ 3. **Read parent task context** (if \`parent_task_id\` exists):
79
+ - Use \`task_get\` to read the parent task's description and goals
80
+ - Use \`task_operation_list\` to get parent's recent operations
81
+ - This forms the overall task background and ensures alignment
82
+
83
+ **Why this matters**:
84
+ - The main agent may have made critical decisions recorded in operations
85
+ - Parent task goals provide the broader context for your sub-task
86
+ - Without this context, you risk working on wrong/outdated goals
87
+
88
+ ## Rules
89
+ 1. **Gather context first** - Always read task details and operations before starting
90
+ 2. **Stay focused** - Do your assigned task, nothing else
91
+ 3. **Complete the task** - Your final message will be automatically reported to the main agent
92
+ 4. **Don't initiate** - No heartbeats, no proactive actions, no side quests
93
+ 5. **Be ephemeral** - You may be terminated after task completion. That's fine.
94
+ 6. **No nested delegation** - Do NOT use delegate_task or stop_task tools. Complete the task yourself.
95
+
96
+ ## Execution
97
+ - Use the available tools to complete the task
98
+ - If you need more information, ask the main agent through the result
99
+ - Return a clear summary of what you did and the results`,
100
+ // Prevent nested delegation by denying delegate_task and stop_task
101
+ deniedTools: ["delegate_task", "stop_task"],
102
+ },
103
+ {
104
+ id: "explore",
105
+ name: "explore",
106
+ mode: "subagent",
107
+ description: "Fast agent specialized for exploring codebases, finding files, and searching for patterns.",
108
+ allowedTools: ["glob", "grep", "read", "bash"],
109
+ deniedTools: ["delegate_task", "stop_task"],
110
+ },
111
+ {
112
+ id: "file_agent",
113
+ name: "file_agent",
114
+ mode: "subagent",
115
+ description: "File operation expert, skilled at reading, writing, searching and organizing files.",
116
+ allowedTools: ["file_read", "file_write", "file_glob", "grep", "glob", "read"],
117
+ deniedTools: ["delegate_task", "stop_task"],
118
+ },
119
+ {
120
+ id: "web_search_agent",
121
+ name: "web_search_agent",
122
+ mode: "subagent",
123
+ description: "Web search expert, using Exa search engine to get latest information.",
124
+ allowedTools: ["exa_web_search_exa"],
125
+ deniedTools: ["delegate_task", "stop_task"],
126
+ },
127
+ ];
128
+
129
+ function getSubAgentSpec(id: string): SubAgentSpec | undefined {
130
+ return builtInSubAgents.find((agent) => agent.id === id);
131
+ }
132
+
133
+ function listSubAgents(): SubAgentSpec[] {
134
+ return [...builtInSubAgents];
135
+ }
136
+
137
+ function getSubAgentToolDescription(): string {
138
+ return builtInSubAgents.map((agent) => `- ${agent.id}: ${agent.description}`).join("\n");
139
+ }
140
+
141
+ // ============================================================================
142
+ // SubAgent Registration Helper
143
+ // ============================================================================
144
+
145
+ /**
146
+ * 确保 subAgent 已注册到 AgentComponent
147
+ *
148
+ * @param agentComponent AgentComponent 实例
149
+ * @param subagentType subAgent 类型(用作 agentName)
150
+ * @param basePrompt 基础 system prompt
151
+ * @param subAgent subAgent 配置(可能包含 allowedTools)
152
+ * @param deniedTools 拒绝的工具列表
153
+ * @returns 注册的 agent 实例
154
+ */
155
+ function ensureSubAgentRegistered(
156
+ agentComponent: any,
157
+ subagentType: string,
158
+ basePrompt: string,
159
+ subAgent: SubAgentSpec | undefined,
160
+ deniedTools: string[]
161
+ ): any {
162
+ let agentInstance = agentComponent.getAgent(subagentType);
163
+ if (!agentInstance) {
164
+ const agentConfig: Record<string, unknown> = {
165
+ type: "sub",
166
+ systemPrompt: basePrompt,
167
+ };
168
+
169
+ // 添加 allowedTools(如果有)
170
+ if (subAgent?.allowedTools && subAgent.allowedTools.length > 0) {
171
+ agentConfig.allowedTools = subAgent.allowedTools;
172
+ }
173
+
174
+ // 添加 deniedTools(如果有)
175
+ if (deniedTools.length > 0) {
176
+ agentConfig.deniedTools = deniedTools;
177
+ }
178
+
179
+ agentInstance = agentComponent.registerAgent(subagentType, agentConfig as any);
180
+ logger.debug(`[delegate] Registered subagent: ${subagentType}`);
181
+ }
182
+ return agentInstance;
183
+ }
184
+
185
+ // ============================================================================
186
+ // Tool Parameters Schema
187
+ // ============================================================================
188
+
189
+ export const DelegateToolParameters = z.object({
190
+ description: z.string().describe("A short (3-5 words) description of the task"),
191
+ prompt: z.string().describe("The task for the agent to perform"),
192
+ subagent_type: z
193
+ .string()
194
+ .describe("The type of specialized agent to use for this task")
195
+ .default("general"),
196
+ background: z
197
+ .boolean()
198
+ .describe("Whether to run the task in background. If true, returns immediately and notifies when complete (default: false)")
199
+ .default(false),
200
+ timeout: z
201
+ .number()
202
+ .describe("Task timeout in milliseconds. If set, task will be terminated after timeout (optional)")
203
+ .optional(),
204
+ cleanup: z
205
+ .enum(["delete", "keep"] as const)
206
+ .describe("Whether to delete sub session after completion. 'delete' removes the session, 'keep' retains it (default: keep)")
207
+ .default("keep")
208
+ .optional(),
209
+ task_id: z
210
+ .number()
211
+ .describe("Optional task ID to associate with this delegate task, for tracking in operation records")
212
+ .optional(),
213
+ reason: z
214
+ .string()
215
+ .describe("Brief reason for calling this tool (max 30 chars, e.g., 'Delegate refactor task')")
216
+ .optional(),
217
+ });
218
+
219
+ export type DelegateToolParams = z.infer<typeof DelegateToolParameters>;
220
+
221
+ // ============================================================================
222
+ // Delegate Tool Implementation
223
+ // ============================================================================
224
+
225
+ export interface DelegateToolResult {
226
+ tool: Tool;
227
+ backgroundTaskManager: BackgroundTaskManager;
228
+ }
229
+
230
+ export interface BackgroundTask {
231
+ id: string;
232
+ subSessionId: string;
233
+ parentSessionId: string;
234
+ description: string;
235
+ subagentType: string;
236
+ status: "pending" | "running" | "completed" | "failed" | "timeout" | "stopped";
237
+ createdAt: number;
238
+ startedAt?: number;
239
+ completedAt?: number;
240
+ result?: string;
241
+ error?: string;
242
+ progress?: number;
243
+ progressMessage?: string;
244
+ abortController?: AbortController;
245
+ taskId?: number; // 关联的任务ID
246
+ }
247
+
248
+ export interface CreateBackgroundTaskOptions {
249
+ parentSessionId: string;
250
+ description: string;
251
+ prompt: string;
252
+ subagentType: string;
253
+ timeout?: number;
254
+ cleanup?: "delete" | "keep";
255
+ taskId?: number;
256
+ }
257
+
258
+ const DEFAULT_TIMEOUT = 900000; // 15 minutes
259
+ const PROGRESS_INTERVAL = 120000; // 2 minutes
260
+
261
+ /**
262
+ * Background Task Manager (简化版)
263
+ *
264
+ * 管理后台任务的创建、执行、状态跟踪
265
+ * 支持 EnvEvent 发布
266
+ */
267
+ export class BackgroundTaskManager {
268
+ private tasks: Map<string, BackgroundTask> = new Map();
269
+ private progressTimers: Map<string, NodeJS.Timeout> = new Map();
270
+ private abortControllers: Map<string, AbortController> = new Map();
271
+
272
+ constructor(private env: any) {
273
+ // env 应该具有 pushEnvEvent 和 getComponent 方法
274
+ }
275
+
276
+ /**
277
+ * Get SessionComponent from env
278
+ */
279
+ private getSessionComponent(): any {
280
+ return this.env?.getComponent?.("session");
281
+ }
282
+
283
+ async createTask(options: CreateBackgroundTaskOptions): Promise<{ taskId: string; subSessionId: string }> {
284
+ const { parentSessionId, description, prompt, subagentType, timeout, cleanup, taskId } = options;
285
+
286
+ const taskIdGen = `task_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;
287
+
288
+ // Get SessionComponent
289
+ const sessionComponent = this.getSessionComponent();
290
+ if (!sessionComponent) {
291
+ throw new Error("SessionComponent not found");
292
+ }
293
+
294
+ // Create sub-session
295
+ const parentSession = await sessionComponent.get(parentSessionId);
296
+ if (!parentSession) {
297
+ throw new Error(`Parent session not found: ${parentSessionId}`);
298
+ }
299
+
300
+ const metadata: Record<string, unknown> = {
301
+ subagent_type: subagentType,
302
+ created_by: "subagent",
303
+ task_description: description,
304
+ };
305
+ if (taskId) {
306
+ metadata.task_id = taskId;
307
+ }
308
+
309
+ const subSession = await sessionComponent.create({
310
+ title: `${description} (@${subagentType} subagent)`,
311
+ metadata,
312
+ });
313
+
314
+ if (!subSession) {
315
+ throw new Error("Failed to create sub-session");
316
+ }
317
+
318
+ const abortController = new AbortController();
319
+
320
+ const task: BackgroundTask = {
321
+ id: taskIdGen,
322
+ subSessionId: subSession.id,
323
+ parentSessionId,
324
+ description,
325
+ subagentType,
326
+ status: "pending",
327
+ createdAt: Date.now(),
328
+ abortController,
329
+ taskId,
330
+ };
331
+ this.tasks.set(taskIdGen, task);
332
+ this.abortControllers.set(taskIdGen, abortController);
333
+
334
+ // Publish task.started event
335
+ this.publishEvent(TaskEventTypes.TASK_STARTED, createTaskStartedPayload(task, parentSessionId), parentSessionId);
336
+
337
+ // Start execution asynchronously
338
+ this.executeTask(taskIdGen, prompt, timeout, cleanup, parentSessionId).catch((err) => {
339
+ logger.error(`[BackgroundTaskManager] executeTask unhandled rejection`, {
340
+ taskId: taskIdGen,
341
+ error: err instanceof Error ? err.message : String(err),
342
+ });
343
+ });
344
+
345
+ return { taskId: taskIdGen, subSessionId: subSession.id };
346
+ }
347
+
348
+ private async executeTask(
349
+ taskId: string,
350
+ prompt: string,
351
+ timeout?: number,
352
+ cleanup?: "delete" | "keep",
353
+ parentSessionId?: string
354
+ ): Promise<void> {
355
+ const task = this.tasks.get(taskId);
356
+ if (!task) {
357
+ logger.warn(`[BackgroundTaskManager] executeTask: Task not found`, { taskId });
358
+ return;
359
+ }
360
+
361
+ task.status = "running";
362
+ task.startedAt = Date.now();
363
+
364
+ const timeoutMs = timeout || DEFAULT_TIMEOUT;
365
+ const abortController = this.abortControllers.get(taskId);
366
+
367
+ // Start progress reporter
368
+ this.startProgressReporter(taskId, parentSessionId || task.parentSessionId);
369
+
370
+ try {
371
+ const sessionComponent = this.getSessionComponent();
372
+ const subSession = await sessionComponent.get(task.subSessionId);
373
+ if (!subSession) {
374
+ throw new Error(`Sub session not found: ${task.subSessionId}`);
375
+ }
376
+
377
+ // Execute with timeout and abort support
378
+ const result = await this.executeWithAbort(subSession, prompt, timeoutMs, abortController?.signal);
379
+
380
+ if (abortController?.signal.aborted) {
381
+ logger.info(`[BackgroundTaskManager] Task was aborted`, { taskId });
382
+ return;
383
+ }
384
+
385
+ task.status = "completed";
386
+ task.completedAt = Date.now();
387
+ task.result = result;
388
+
389
+ // Publish task.completed event
390
+ const executionTimeMs = task.completedAt - task.startedAt!;
391
+ this.publishEvent(
392
+ TaskEventTypes.TASK_COMPLETED,
393
+ createTaskCompletedPayload(task, parentSessionId || task.parentSessionId, executionTimeMs),
394
+ parentSessionId || task.parentSessionId
395
+ );
396
+
397
+ logger.info(`[BackgroundTaskManager] Task completed successfully`, {
398
+ taskId,
399
+ executionTimeMs,
400
+ });
401
+ } catch (error) {
402
+ const errorMessage = error instanceof Error ? error.message : String(error);
403
+ const isStoppedError =
404
+ errorMessage.toLowerCase().includes("stopped") ||
405
+ errorMessage.toLowerCase().includes("aborted");
406
+
407
+ if (isStoppedError) {
408
+ task.status = "stopped";
409
+ // Publish task.stopped event
410
+ this.publishEvent(
411
+ TaskEventTypes.TASK_STOPPED,
412
+ createTaskCompletedPayload(task, parentSessionId || task.parentSessionId,
413
+ task.completedAt! - task.startedAt!),
414
+ parentSessionId || task.parentSessionId
415
+ );
416
+ } else if (errorMessage.includes("timeout")) {
417
+ task.status = "timeout";
418
+ // Publish task.timeout event
419
+ this.publishEvent(
420
+ TaskEventTypes.TASK_TIMEOUT,
421
+ createTaskCompletedPayload(task, parentSessionId || task.parentSessionId,
422
+ task.completedAt! - task.startedAt!),
423
+ parentSessionId || task.parentSessionId
424
+ );
425
+ } else {
426
+ task.status = "failed";
427
+ // Publish task.failed event
428
+ this.publishEvent(
429
+ TaskEventTypes.TASK_FAILED,
430
+ createTaskCompletedPayload(task, parentSessionId || task.parentSessionId,
431
+ task.completedAt! - task.startedAt!),
432
+ parentSessionId || task.parentSessionId
433
+ );
434
+ }
435
+ task.error = errorMessage;
436
+ task.completedAt = Date.now();
437
+
438
+ logger.error(`[BackgroundTaskManager] Task execution error`, {
439
+ taskId,
440
+ status: task.status,
441
+ error: errorMessage,
442
+ });
443
+ } finally {
444
+ // Stop progress reporter
445
+ this.stopProgressReporter(taskId);
446
+ }
447
+ }
448
+
449
+ private async executeWithAbort(
450
+ subSession: any,
451
+ prompt: string,
452
+ timeoutMs: number,
453
+ signal?: AbortSignal
454
+ ): Promise<string> {
455
+ return new Promise((resolve, reject) => {
456
+ const timer = setTimeout(() => {
457
+ reject(new Error(`Task execution timeout after ${timeoutMs}ms`));
458
+ }, timeoutMs);
459
+
460
+ signal?.addEventListener("abort", () => {
461
+ clearTimeout(timer);
462
+ reject(new Error("Task execution stopped"));
463
+ });
464
+
465
+ // Build full prompt
466
+ const metadata = subSession.info?.metadata || {};
467
+ const taskId = metadata.task_id as number | undefined;
468
+ const taskDescription = metadata.task_description as string || "";
469
+ const sessionId = subSession.id;
470
+ const subagentType = metadata.subagent_type as string || "general";
471
+
472
+ const subAgent = getSubAgentSpec(subagentType);
473
+ let basePrompt = subAgent?.promptOverride || `You are a subagent. Complete this task: {task_description}`;
474
+
475
+ // Get denied tools from subagent config
476
+ const deniedTools = subAgent?.deniedTools || [];
477
+
478
+ // Only replace valid placeholders
479
+ let fullPrompt = basePrompt.replace(/{task_description}/g, taskDescription || "N/A");
480
+
481
+ // Add session info and execution guidelines
482
+ fullPrompt += `
483
+
484
+ ---
485
+
486
+ # Session Info
487
+ - task_id: ${taskId || "N/A"}
488
+ - session_id: ${sessionId}
489
+
490
+ ---
491
+
492
+ ## 用户指令
493
+ ${prompt}
494
+
495
+ ---
496
+
497
+ ## 执行规范
498
+ - 使用可用工具完成任务
499
+ - 返回清晰的任务执行结果摘要
500
+ - 适时调用 task_operation_create 记录进展`;
501
+
502
+ // Get AgentComponent and ensure subagent is registered
503
+ const agentComponent = this.env?.getComponent?.("agent") as any;
504
+
505
+ if (!agentComponent) {
506
+ clearTimeout(timer);
507
+ reject(new Error("AgentComponent not found"));
508
+ return;
509
+ }
510
+
511
+ // 注册 subagent(使用公共函数)
512
+ ensureSubAgentRegistered(agentComponent, subagentType, basePrompt, subAgent, deniedTools);
513
+
514
+ // Execute using handle_query with agentType specified
515
+ this.env.handle_query?.(fullPrompt, {
516
+ sessionId: sessionId,
517
+ deniedTools: deniedTools.length > 0 ? deniedTools : undefined,
518
+ agentType: subagentType, // handle_query will use this agent
519
+ })
520
+ .then((result: string) => {
521
+ clearTimeout(timer);
522
+ resolve(result);
523
+ })
524
+ .catch((error: Error) => {
525
+ clearTimeout(timer);
526
+ reject(error);
527
+ });
528
+ });
529
+ }
530
+
531
+ /**
532
+ * Start progress reporter for a task
533
+ */
534
+ private startProgressReporter(taskId: string, parentSessionId: string): void {
535
+ const timer = setInterval(() => {
536
+ const task = this.tasks.get(taskId);
537
+ if (!task || task.status !== "running") {
538
+ this.stopProgressReporter(taskId);
539
+ return;
540
+ }
541
+
542
+ // Update progress
543
+ if (task.startedAt) {
544
+ const elapsedMs = Date.now() - task.startedAt;
545
+ task.progress = Math.min(95, Math.floor((elapsedMs / PROGRESS_INTERVAL) * 100));
546
+ }
547
+
548
+ // Publish progress event
549
+ this.publishEvent(
550
+ TaskEventTypes.TASK_PROGRESS,
551
+ createTaskProgressPayload(task, parentSessionId),
552
+ parentSessionId
553
+ );
554
+ }, PROGRESS_INTERVAL);
555
+
556
+ this.progressTimers.set(taskId, timer);
557
+ }
558
+
559
+ /**
560
+ * Stop progress reporter for a task
561
+ */
562
+ private stopProgressReporter(taskId: string): void {
563
+ const timer = this.progressTimers.get(taskId);
564
+ if (timer) {
565
+ clearInterval(timer);
566
+ this.progressTimers.delete(taskId);
567
+ }
568
+ }
569
+
570
+ /**
571
+ * Publish an event to the environment
572
+ */
573
+ private publishEvent<T>(type: string, payload: T, triggerSessionId?: string): void {
574
+ if (this.env?.pushEnvEvent) {
575
+ this.env.pushEnvEvent({
576
+ type,
577
+ metadata: {
578
+ trigger_session_id: triggerSessionId,
579
+ source: "task.delegate",
580
+ },
581
+ payload,
582
+ });
583
+ logger.info(`[BackgroundTaskManager] Event published: ${type}`, { payload });
584
+ }
585
+ }
586
+
587
+ stopTask(taskId: string): { success: boolean; task?: BackgroundTask; message: string } {
588
+ const task = this.tasks.get(taskId);
589
+ if (!task) {
590
+ return { success: false, message: "Task not found" };
591
+ }
592
+
593
+ if (task.status === "completed" || task.status === "failed" || task.status === "stopped" || task.status === "timeout") {
594
+ return {
595
+ success: false,
596
+ task,
597
+ message: `Cannot stop task with status: ${task.status}`,
598
+ };
599
+ }
600
+
601
+ task.status = "stopped";
602
+ task.abortController?.abort();
603
+ task.completedAt = Date.now();
604
+
605
+ // Publish task.stopped event
606
+ this.publishEvent(
607
+ TaskEventTypes.TASK_STOPPED,
608
+ createTaskCompletedPayload(task, task.parentSessionId, task.completedAt - task.startedAt!),
609
+ task.parentSessionId
610
+ );
611
+
612
+ return { success: true, task, message: "Task has been stopped" };
613
+ }
614
+
615
+ getTask(taskId: string): BackgroundTask | undefined {
616
+ return this.tasks.get(taskId);
617
+ }
618
+
619
+ listTasks(): BackgroundTask[] {
620
+ return Array.from(this.tasks.values());
621
+ }
622
+
623
+ /**
624
+ * Dispose and cleanup all resources
625
+ * Call this when shutting down to prevent process from hanging
626
+ */
627
+ dispose(): void {
628
+ // Clear all progress timers
629
+ for (const [taskId, timer] of this.progressTimers) {
630
+ clearInterval(timer);
631
+ logger.debug(`[BackgroundTaskManager] Cleared progress timer for task: ${taskId}`);
632
+ }
633
+ this.progressTimers.clear();
634
+
635
+ // Abort all running tasks
636
+ for (const [taskId, controller] of this.abortControllers) {
637
+ controller.abort();
638
+ logger.debug(`[BackgroundTaskManager] Aborted task: ${taskId}`);
639
+ }
640
+ this.abortControllers.clear();
641
+
642
+ // Clear all tasks
643
+ this.tasks.clear();
644
+
645
+ logger.info(`[BackgroundTaskManager] Disposed`);
646
+ }
647
+ }
648
+
649
+ /**
650
+ * Create delegate_task tool
651
+ */
652
+ export function createDelegateTool(taskComponent: TaskComponent): Tool {
653
+ // Pass taskComponent.env instead of taskComponent, so BackgroundTaskManager
654
+ // can correctly call this.env.getComponent("session")
655
+ const env = (taskComponent as any).env;
656
+ const backgroundTaskManager = new BackgroundTaskManager(env);
657
+
658
+ const tool: Tool = {
659
+ name: "delegate_task",
660
+ description: `Launch a new sub-agent to handle complex, multistep tasks autonomously.
661
+
662
+ Available agent types:
663
+ ${getSubAgentToolDescription()}
664
+
665
+ When using the delegate_task tool, you must specify a subagent_type parameter to select which agent type to use.
666
+
667
+ ## When to use delegate_task:
668
+ - When you need to perform complex, multi-step tasks that require independent execution
669
+ - When you need to explore a codebase thoroughly (use "explore" subagent)
670
+ - When you need to run long-running tasks without blocking the main agent (use background=true)
671
+
672
+ ## Parameters:
673
+ - **description**: A short (3-5 words) description of the task
674
+ - **prompt**: The task for the agent to perform
675
+ - **subagent_type**: The type of specialized agent to use (e.g., "general", "explore")
676
+ - **background**: Whether to run in background (default: false)
677
+ - **timeout**: Task timeout in milliseconds (optional)
678
+ - **task_id**: Optional task ID to associate with this delegate task
679
+
680
+ ## Synchronous vs Background mode:
681
+ **Synchronous mode (default)**: Waits for subagent to complete and returns result directly
682
+ **Background mode (background=true)**: Returns immediately with "accepted" status, runs independently`,
683
+ parameters: DelegateToolParameters,
684
+ execute: async (args: unknown, ctx: ToolContext): Promise<ToolResult> => {
685
+ const startTime = Date.now();
686
+ const params = DelegateToolParameters.parse(args);
687
+ const { description, prompt, subagent_type = "general", background = false, timeout, cleanup, task_id, reason } = params;
688
+
689
+ const parentSessionId = ctx.session_id || "default";
690
+
691
+ logger.info(`[delegate_task] Called: description=${description}, subagent_type=${subagent_type}, background=${background}, task_id=${task_id}`);
692
+
693
+ // Validate subagent_type
694
+ const subAgent = getSubAgentSpec(subagent_type);
695
+ if (!subAgent) {
696
+ return {
697
+ success: false,
698
+ output: "",
699
+ error: `Unknown subagent type: ${subagent_type}`,
700
+ metadata: { execution_time_ms: Date.now() - startTime },
701
+ };
702
+ }
703
+
704
+ // Get TagService from TaskComponent
705
+ const tagService = taskComponent.getTagService();
706
+
707
+ // Build initial prompt - hook will inject similar tasks info
708
+ let promptWithTaskInfo = prompt;
709
+
710
+ // Execute delegate:before Hook (can modify prompt, subagentType, etc.)
711
+ const delegateCtx: TaskDelegateContext = {
712
+ taskId: task_id,
713
+ prompt: promptWithTaskInfo,
714
+ subagentType: subagent_type,
715
+ background,
716
+ timeout,
717
+ cleanup,
718
+ reason,
719
+ tagService,
720
+ };
721
+
722
+ const hookCtx = {
723
+ component: { name: "task", version: "1.0.0" },
724
+ data: delegateCtx,
725
+ metadata: { sessionId: parentSessionId },
726
+ phase: "before" as const,
727
+ hookPoint: TaskHookPoints.DELEGATE_BEFORE,
728
+ };
729
+
730
+ await globalHookManager.execute(TaskHookPoints.DELEGATE_BEFORE, hookCtx, { sessionId: parentSessionId });
731
+
732
+ // Use potentially modified prompt from hook
733
+ promptWithTaskInfo = delegateCtx.prompt;
734
+
735
+ if (background) {
736
+ // Background execution
737
+ return await handleBackgroundTask(
738
+ taskComponent,
739
+ backgroundTaskManager,
740
+ parentSessionId,
741
+ description,
742
+ promptWithTaskInfo,
743
+ delegateCtx.subagentType,
744
+ delegateCtx.timeout,
745
+ delegateCtx.cleanup,
746
+ delegateCtx.taskId
747
+ );
748
+ } else {
749
+ // Synchronous execution
750
+ return await handleSyncTask(
751
+ taskComponent,
752
+ parentSessionId,
753
+ description,
754
+ promptWithTaskInfo,
755
+ delegateCtx.subagentType,
756
+ delegateCtx.timeout,
757
+ delegateCtx.taskId
758
+ );
759
+ }
760
+ },
761
+ };
762
+
763
+ return tool;
764
+ }
765
+
766
+ async function handleSyncTask(
767
+ taskComponent: TaskComponent,
768
+ parentSessionId: string,
769
+ description: string,
770
+ prompt: string,
771
+ subagentType: string,
772
+ timeout?: number,
773
+ taskId?: number
774
+ ): Promise<ToolResult> {
775
+ const startTime = Date.now();
776
+
777
+ try {
778
+ // Get SessionComponent from environment
779
+ const sessionComponent = (taskComponent as any).env?.getComponent?.("session") as SessionComponent | undefined;
780
+ if (!sessionComponent) {
781
+ return {
782
+ success: false,
783
+ output: "",
784
+ error: "SessionComponent not found",
785
+ metadata: { execution_time_ms: Date.now() - startTime },
786
+ };
787
+ }
788
+
789
+ const parentSession = await sessionComponent.get(parentSessionId);
790
+ if (!parentSession) {
791
+ return {
792
+ success: false,
793
+ output: "",
794
+ error: `Parent session not found: ${parentSessionId}`,
795
+ metadata: { execution_time_ms: Date.now() - startTime },
796
+ };
797
+ }
798
+
799
+ // Create sub-session
800
+ const metadata: Record<string, unknown> = {
801
+ subagent_type: subagentType,
802
+ created_by: "subagent",
803
+ task_description: description,
804
+ };
805
+ if (taskId) {
806
+ metadata.task_id = taskId;
807
+ }
808
+
809
+ const subSession = await sessionComponent.create({
810
+ parentID: parentSessionId,
811
+ title: `${description} (@${subagentType} subagent)`,
812
+ metadata,
813
+ });
814
+
815
+ if (!subSession) {
816
+ return {
817
+ success: false,
818
+ output: "",
819
+ error: "Failed to create sub-session",
820
+ metadata: { execution_time_ms: Date.now() - startTime },
821
+ };
822
+ }
823
+
824
+ // Build full prompt
825
+ const subAgent = getSubAgentSpec(subagentType);
826
+ let basePrompt = subAgent?.promptOverride || `You are a subagent. Complete this task: {task_description}`;
827
+
828
+ // Get denied tools from subagent config
829
+ const deniedTools = subAgent?.deniedTools || [];
830
+
831
+ // Only replace valid placeholders
832
+ let fullPrompt = basePrompt.replace(/{task_description}/g, description || "N/A");
833
+
834
+ fullPrompt += `
835
+
836
+ ---
837
+
838
+ # Session Info
839
+ - task_id: ${taskId || "N/A"}
840
+ - session_id: ${subSession.id}
841
+
842
+ ---
843
+
844
+ ## 用户指令
845
+ ${prompt}
846
+
847
+ ---
848
+
849
+ ## 执行规范
850
+ - 使用可用工具完成任务
851
+ - 返回清晰的任务执行结果摘要
852
+ - 适时调用 task_operation_create 记录进展`;
853
+
854
+ const agentComponent = (taskComponent as any).env?.getComponent?.("agent") as any;
855
+
856
+ if (!agentComponent) {
857
+ return {
858
+ success: false,
859
+ output: "",
860
+ error: "AgentComponent not found",
861
+ metadata: { execution_time_ms: Date.now() - startTime },
862
+ };
863
+ }
864
+
865
+ // 注册 subagent(使用公共函数)
866
+ ensureSubAgentRegistered(agentComponent, subagentType, basePrompt, subAgent, deniedTools);
867
+
868
+ // 使用 handle_query 执行,通过 agentType 指定 agent
869
+ const timeoutMs = timeout || DEFAULT_TIMEOUT;
870
+ let result: string;
871
+
872
+ try {
873
+ result = await Promise.race([
874
+ (taskComponent as any).env?.handle_query?.(fullPrompt, {
875
+ sessionId: subSession.id,
876
+ deniedTools: deniedTools.length > 0 ? deniedTools : undefined,
877
+ agentType: subagentType, // 传入 agentType,handle_query 会使用对应的 agent
878
+ }),
879
+ new Promise<string>((_, reject) =>
880
+ setTimeout(() => reject(new Error(`Task execution timeout after ${timeoutMs}ms`)), timeoutMs)
881
+ ),
882
+ ]);
883
+ } catch (error) {
884
+ result = error instanceof Error ? error.message : String(error);
885
+ }
886
+
887
+ // Add result message to session
888
+ await sessionComponent.addMessage(subSession.id, {
889
+ role: "assistant",
890
+ content: result,
891
+ });
892
+
893
+ return {
894
+ success: true,
895
+ output: result + "\n\n" + [
896
+ "<task_metadata>",
897
+ `session_id: ${subSession.id}`,
898
+ `subagent_type: ${subagentType}`,
899
+ "</task_metadata>",
900
+ ].join("\n"),
901
+ metadata: {
902
+ execution_time_ms: Date.now() - startTime,
903
+ sessionId: subSession.id,
904
+ },
905
+ };
906
+ } catch (error) {
907
+ return {
908
+ success: false,
909
+ output: "",
910
+ error: error instanceof Error ? error.message : String(error),
911
+ metadata: { execution_time_ms: Date.now() - startTime },
912
+ };
913
+ }
914
+ }
915
+
916
+ async function handleBackgroundTask(
917
+ taskComponent: TaskComponent,
918
+ backgroundTaskManager: BackgroundTaskManager,
919
+ parentSessionId: string,
920
+ description: string,
921
+ prompt: string,
922
+ subagentType: string,
923
+ timeout?: number,
924
+ cleanup?: "delete" | "keep",
925
+ taskId?: number
926
+ ): Promise<ToolResult> {
927
+ const startTime = Date.now();
928
+
929
+ try {
930
+ // Create or update task
931
+ let associatedTaskId = taskId;
932
+
933
+ if (!associatedTaskId) {
934
+ // Create new task
935
+ const newTask = await taskComponent.createTask({
936
+ title: description,
937
+ description: `Background task delegated to ${subagentType} subagent`,
938
+ priority: "medium",
939
+ goals_and_expected_deliverables: prompt,
940
+ sessionId: parentSessionId,
941
+ });
942
+ associatedTaskId = newTask.id;
943
+
944
+ // Create operation record
945
+ await taskComponent.createOperation({
946
+ taskId: associatedTaskId,
947
+ sessionId: parentSessionId,
948
+ actionType: "create",
949
+ actionTitle: `Delegated to ${subagentType} subagent`,
950
+ actionDescription: `Background task started: ${description}`,
951
+ });
952
+ } else {
953
+ // Update existing task
954
+ await taskComponent.updateTask(associatedTaskId, {
955
+ status: "active",
956
+ current_status: `Running ${subagentType} subagent`,
957
+ });
958
+
959
+ await taskComponent.createOperation({
960
+ taskId: associatedTaskId,
961
+ sessionId: parentSessionId,
962
+ actionType: "progress",
963
+ actionTitle: `Started ${subagentType} subagent`,
964
+ actionDescription: `Background task: ${description}`,
965
+ });
966
+ }
967
+
968
+ // Create background task
969
+ const { taskId: bgTaskId, subSessionId } = await backgroundTaskManager.createTask({
970
+ parentSessionId,
971
+ description,
972
+ prompt,
973
+ subagentType,
974
+ timeout,
975
+ cleanup,
976
+ taskId: associatedTaskId,
977
+ });
978
+
979
+ const output = [
980
+ `✅ Background task accepted`,
981
+ "",
982
+ `📋 Task ID: ${bgTaskId}`,
983
+ `📝 Description: ${description}`,
984
+ `🤖 Sub-agent: ${subagentType}`,
985
+ associatedTaskId ? `📌 Associated Task: #${associatedTaskId}` : "",
986
+ `⏱️ Timeout: ${(timeout || DEFAULT_TIMEOUT) / 1000}s`,
987
+ "",
988
+ `Use stop_task with task_id="${bgTaskId}" to cancel this task.`,
989
+ ].filter(Boolean).join("\n");
990
+
991
+ return {
992
+ success: true,
993
+ output,
994
+ metadata: {
995
+ execution_time_ms: Date.now() - startTime,
996
+ sessionId: subSessionId,
997
+ background: true,
998
+ status: "accepted",
999
+ task_id: associatedTaskId,
1000
+ bgTaskId,
1001
+ },
1002
+ };
1003
+ } catch (error) {
1004
+ return {
1005
+ success: false,
1006
+ output: "",
1007
+ error: error instanceof Error ? error.message : String(error),
1008
+ metadata: { execution_time_ms: Date.now() - startTime },
1009
+ };
1010
+ }
1011
+ }
1012
+
1013
+ // Export for stop_task tool
1014
+ export { handleBackgroundTask, handleSyncTask };