kagent-ts 0.1.3 → 0.1.5

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 (349) hide show
  1. package/LICENSE +68 -21
  2. package/README.md +27 -371
  3. package/dist/compression/progressive-compressor.d.ts +66 -0
  4. package/dist/compression/progressive-compressor.d.ts.map +1 -0
  5. package/dist/compression/progressive-compressor.js +367 -0
  6. package/dist/compression/progressive-compressor.js.map +1 -0
  7. package/dist/compression/types.d.ts +1 -5
  8. package/dist/compression/types.d.ts.map +1 -1
  9. package/dist/context/context-manager.d.ts +34 -15
  10. package/dist/context/context-manager.d.ts.map +1 -1
  11. package/dist/context/context-manager.js +78 -28
  12. package/dist/context/context-manager.js.map +1 -1
  13. package/dist/context/types.d.ts +20 -4
  14. package/dist/context/types.d.ts.map +1 -1
  15. package/dist/core/agent.d.ts +407 -35
  16. package/dist/core/agent.d.ts.map +1 -1
  17. package/dist/core/agent.js +685 -70
  18. package/dist/core/agent.js.map +1 -1
  19. package/dist/core/fusion-agent.d.ts +207 -0
  20. package/dist/core/fusion-agent.d.ts.map +1 -0
  21. package/dist/core/fusion-agent.js +769 -0
  22. package/dist/core/fusion-agent.js.map +1 -0
  23. package/dist/core/hooks.d.ts +19 -7
  24. package/dist/core/hooks.d.ts.map +1 -1
  25. package/dist/core/plan-solve-agent.d.ts +1 -15
  26. package/dist/core/plan-solve-agent.d.ts.map +1 -1
  27. package/dist/core/plan-solve-agent.js +144 -117
  28. package/dist/core/plan-solve-agent.js.map +1 -1
  29. package/dist/core/react-agent.d.ts +0 -13
  30. package/dist/core/react-agent.d.ts.map +1 -1
  31. package/dist/core/react-agent.js +128 -101
  32. package/dist/core/react-agent.js.map +1 -1
  33. package/dist/core/response-schema.d.ts +65 -0
  34. package/dist/core/response-schema.d.ts.map +1 -1
  35. package/dist/core/response-schema.js +174 -1
  36. package/dist/core/response-schema.js.map +1 -1
  37. package/dist/core/system-prompts.d.ts +27 -0
  38. package/dist/core/system-prompts.d.ts.map +1 -0
  39. package/dist/core/system-prompts.js +112 -0
  40. package/dist/core/system-prompts.js.map +1 -0
  41. package/dist/eval/benchmark.d.ts +81 -0
  42. package/dist/eval/benchmark.d.ts.map +1 -0
  43. package/dist/eval/benchmark.js +292 -0
  44. package/dist/eval/benchmark.js.map +1 -0
  45. package/dist/eval/eval-runner.d.ts +79 -0
  46. package/dist/eval/eval-runner.d.ts.map +1 -0
  47. package/dist/eval/eval-runner.js +252 -0
  48. package/dist/eval/eval-runner.js.map +1 -0
  49. package/dist/eval/index.d.ts +7 -0
  50. package/dist/eval/index.d.ts.map +1 -0
  51. package/dist/eval/index.js +13 -0
  52. package/dist/eval/index.js.map +1 -0
  53. package/dist/eval/tool-call-evaluator.d.ts +72 -0
  54. package/dist/eval/tool-call-evaluator.d.ts.map +1 -0
  55. package/dist/eval/tool-call-evaluator.js +265 -0
  56. package/dist/eval/tool-call-evaluator.js.map +1 -0
  57. package/dist/eval/types.d.ts +219 -0
  58. package/dist/eval/types.d.ts.map +1 -0
  59. package/dist/eval/types.js +3 -0
  60. package/dist/eval/types.js.map +1 -0
  61. package/dist/index.d.ts +61 -14
  62. package/dist/index.d.ts.map +1 -1
  63. package/dist/index.js +121 -8
  64. package/dist/index.js.map +1 -1
  65. package/dist/llm/anthropic-provider.d.ts +141 -0
  66. package/dist/llm/anthropic-provider.d.ts.map +1 -0
  67. package/dist/llm/anthropic-provider.js +486 -0
  68. package/dist/llm/anthropic-provider.js.map +1 -0
  69. package/dist/llm/errors.d.ts +26 -0
  70. package/dist/llm/errors.d.ts.map +1 -0
  71. package/dist/llm/errors.js +19 -0
  72. package/dist/llm/errors.js.map +1 -0
  73. package/dist/llm/factory.d.ts +73 -0
  74. package/dist/llm/factory.d.ts.map +1 -0
  75. package/dist/llm/factory.js +77 -0
  76. package/dist/llm/factory.js.map +1 -0
  77. package/dist/llm/fallback-provider.d.ts +47 -0
  78. package/dist/llm/fallback-provider.d.ts.map +1 -0
  79. package/dist/llm/fallback-provider.js +91 -0
  80. package/dist/llm/fallback-provider.js.map +1 -0
  81. package/dist/llm/interface.d.ts +54 -11
  82. package/dist/llm/interface.d.ts.map +1 -1
  83. package/dist/llm/interface.js +34 -0
  84. package/dist/llm/interface.js.map +1 -1
  85. package/dist/llm/model-router.d.ts +126 -0
  86. package/dist/llm/model-router.d.ts.map +1 -0
  87. package/dist/llm/model-router.js +178 -0
  88. package/dist/llm/model-router.js.map +1 -0
  89. package/dist/llm/openai-provider.d.ts +8 -32
  90. package/dist/llm/openai-provider.d.ts.map +1 -1
  91. package/dist/llm/openai-provider.js +27 -60
  92. package/dist/llm/openai-provider.js.map +1 -1
  93. package/dist/llm/rate-limiter.d.ts +41 -0
  94. package/dist/llm/rate-limiter.d.ts.map +1 -0
  95. package/dist/llm/rate-limiter.js +93 -0
  96. package/dist/llm/rate-limiter.js.map +1 -0
  97. package/dist/llm/retry.d.ts +26 -0
  98. package/dist/llm/retry.d.ts.map +1 -0
  99. package/dist/llm/retry.js +44 -0
  100. package/dist/llm/retry.js.map +1 -0
  101. package/dist/llm/token-budget.d.ts +97 -0
  102. package/dist/llm/token-budget.d.ts.map +1 -0
  103. package/dist/llm/token-budget.js +115 -0
  104. package/dist/llm/token-budget.js.map +1 -0
  105. package/dist/logging/index.d.ts +2 -0
  106. package/dist/logging/index.d.ts.map +1 -0
  107. package/dist/logging/index.js +7 -0
  108. package/dist/logging/index.js.map +1 -0
  109. package/dist/logging/logger.d.ts +38 -0
  110. package/dist/logging/logger.d.ts.map +1 -0
  111. package/dist/logging/logger.js +34 -0
  112. package/dist/logging/logger.js.map +1 -0
  113. package/dist/mcp/index.d.ts +4 -0
  114. package/dist/mcp/index.d.ts.map +1 -0
  115. package/dist/mcp/index.js +8 -0
  116. package/dist/mcp/index.js.map +1 -0
  117. package/dist/mcp/mcp-client-manager.d.ts +72 -0
  118. package/dist/mcp/mcp-client-manager.d.ts.map +1 -0
  119. package/dist/mcp/mcp-client-manager.js +235 -0
  120. package/dist/mcp/mcp-client-manager.js.map +1 -0
  121. package/dist/mcp/mcp-types.d.ts +58 -0
  122. package/dist/mcp/mcp-types.d.ts.map +1 -0
  123. package/dist/mcp/mcp-types.js +20 -0
  124. package/dist/mcp/mcp-types.js.map +1 -0
  125. package/dist/memory/index.d.ts +3 -0
  126. package/dist/memory/index.d.ts.map +1 -0
  127. package/dist/memory/index.js +6 -0
  128. package/dist/memory/index.js.map +1 -0
  129. package/dist/memory/memory-manager.d.ts +119 -0
  130. package/dist/memory/memory-manager.d.ts.map +1 -0
  131. package/dist/memory/memory-manager.js +334 -0
  132. package/dist/memory/memory-manager.js.map +1 -0
  133. package/dist/messages/types.d.ts +2 -0
  134. package/dist/messages/types.d.ts.map +1 -1
  135. package/dist/orchestrator/index.d.ts +5 -0
  136. package/dist/orchestrator/index.d.ts.map +1 -0
  137. package/dist/orchestrator/index.js +13 -0
  138. package/dist/orchestrator/index.js.map +1 -0
  139. package/dist/orchestrator/json-extractor.d.ts +18 -0
  140. package/dist/orchestrator/json-extractor.d.ts.map +1 -0
  141. package/dist/orchestrator/json-extractor.js +111 -0
  142. package/dist/orchestrator/json-extractor.js.map +1 -0
  143. package/dist/orchestrator/orchestrator-agent.d.ts +152 -0
  144. package/dist/orchestrator/orchestrator-agent.d.ts.map +1 -0
  145. package/dist/orchestrator/orchestrator-agent.js +675 -0
  146. package/dist/orchestrator/orchestrator-agent.js.map +1 -0
  147. package/dist/orchestrator/orchestrator-response.d.ts +40 -0
  148. package/dist/orchestrator/orchestrator-response.d.ts.map +1 -0
  149. package/dist/orchestrator/orchestrator-response.js +275 -0
  150. package/dist/orchestrator/orchestrator-response.js.map +1 -0
  151. package/dist/orchestrator/orchestrator-types.d.ts +116 -0
  152. package/dist/orchestrator/orchestrator-types.d.ts.map +1 -0
  153. package/dist/orchestrator/orchestrator-types.js +3 -0
  154. package/dist/orchestrator/orchestrator-types.js.map +1 -0
  155. package/dist/preferences/preference-manager.d.ts +8 -3
  156. package/dist/preferences/preference-manager.d.ts.map +1 -1
  157. package/dist/preferences/preference-manager.js +17 -4
  158. package/dist/preferences/preference-manager.js.map +1 -1
  159. package/dist/rag/chroma-store.d.ts +52 -0
  160. package/dist/rag/chroma-store.d.ts.map +1 -0
  161. package/dist/rag/chroma-store.js +110 -0
  162. package/dist/rag/chroma-store.js.map +1 -0
  163. package/dist/rag/document-loader.d.ts +21 -0
  164. package/dist/rag/document-loader.d.ts.map +1 -0
  165. package/dist/rag/document-loader.js +129 -0
  166. package/dist/rag/document-loader.js.map +1 -0
  167. package/dist/rag/embedding-provider.d.ts +36 -0
  168. package/dist/rag/embedding-provider.d.ts.map +1 -0
  169. package/dist/rag/embedding-provider.js +74 -0
  170. package/dist/rag/embedding-provider.js.map +1 -0
  171. package/dist/rag/index.d.ts +17 -0
  172. package/dist/rag/index.d.ts.map +1 -0
  173. package/dist/rag/index.js +27 -0
  174. package/dist/rag/index.js.map +1 -0
  175. package/dist/rag/keyword-index.d.ts +53 -0
  176. package/dist/rag/keyword-index.d.ts.map +1 -0
  177. package/dist/rag/keyword-index.js +161 -0
  178. package/dist/rag/keyword-index.js.map +1 -0
  179. package/dist/rag/llm-reranker.d.ts +36 -0
  180. package/dist/rag/llm-reranker.d.ts.map +1 -0
  181. package/dist/rag/llm-reranker.js +95 -0
  182. package/dist/rag/llm-reranker.js.map +1 -0
  183. package/dist/rag/rag-manager.d.ts +54 -0
  184. package/dist/rag/rag-manager.d.ts.map +1 -0
  185. package/dist/rag/rag-manager.js +179 -0
  186. package/dist/rag/rag-manager.js.map +1 -0
  187. package/dist/rag/rag-types.d.ts +143 -0
  188. package/dist/rag/rag-types.d.ts.map +1 -0
  189. package/dist/rag/rag-types.js +9 -0
  190. package/dist/rag/rag-types.js.map +1 -0
  191. package/dist/rag/rrf.d.ts +47 -0
  192. package/dist/rag/rrf.d.ts.map +1 -0
  193. package/dist/rag/rrf.js +70 -0
  194. package/dist/rag/rrf.js.map +1 -0
  195. package/dist/rag/search-knowledge.d.ts +24 -0
  196. package/dist/rag/search-knowledge.d.ts.map +1 -0
  197. package/dist/rag/search-knowledge.js +86 -0
  198. package/dist/rag/search-knowledge.js.map +1 -0
  199. package/dist/rag/text-splitter.d.ts +25 -0
  200. package/dist/rag/text-splitter.d.ts.map +1 -0
  201. package/dist/rag/text-splitter.js +136 -0
  202. package/dist/rag/text-splitter.js.map +1 -0
  203. package/dist/rag/vector-store.d.ts +34 -0
  204. package/dist/rag/vector-store.d.ts.map +1 -0
  205. package/dist/rag/vector-store.js +73 -0
  206. package/dist/rag/vector-store.js.map +1 -0
  207. package/dist/reflection/error-notebook.d.ts +125 -0
  208. package/dist/reflection/error-notebook.d.ts.map +1 -0
  209. package/dist/reflection/error-notebook.js +368 -0
  210. package/dist/reflection/error-notebook.js.map +1 -0
  211. package/dist/reflection/index.d.ts +8 -0
  212. package/dist/reflection/index.d.ts.map +1 -0
  213. package/dist/reflection/index.js +12 -0
  214. package/dist/reflection/index.js.map +1 -0
  215. package/dist/reflection/memory-reflector.d.ts +97 -0
  216. package/dist/reflection/memory-reflector.d.ts.map +1 -0
  217. package/dist/reflection/memory-reflector.js +215 -0
  218. package/dist/reflection/memory-reflector.js.map +1 -0
  219. package/dist/reflection/reflection-agent.d.ts +105 -0
  220. package/dist/reflection/reflection-agent.d.ts.map +1 -0
  221. package/dist/reflection/reflection-agent.js +234 -0
  222. package/dist/reflection/reflection-agent.js.map +1 -0
  223. package/dist/reflection/reflection-hook.d.ts +50 -0
  224. package/dist/reflection/reflection-hook.d.ts.map +1 -0
  225. package/dist/reflection/reflection-hook.js +108 -0
  226. package/dist/reflection/reflection-hook.js.map +1 -0
  227. package/dist/rules/project-rules.d.ts +47 -0
  228. package/dist/rules/project-rules.d.ts.map +1 -0
  229. package/dist/rules/project-rules.js +166 -0
  230. package/dist/rules/project-rules.js.map +1 -0
  231. package/dist/security/boundaries.d.ts +81 -0
  232. package/dist/security/boundaries.d.ts.map +1 -0
  233. package/dist/security/boundaries.js +158 -0
  234. package/dist/security/boundaries.js.map +1 -0
  235. package/dist/security/index.d.ts +2 -0
  236. package/dist/security/index.d.ts.map +1 -0
  237. package/dist/security/index.js +11 -0
  238. package/dist/security/index.js.map +1 -0
  239. package/dist/session/session-types.d.ts +25 -4
  240. package/dist/session/session-types.d.ts.map +1 -1
  241. package/dist/skills/file-skill-loader.d.ts +9 -20
  242. package/dist/skills/file-skill-loader.d.ts.map +1 -1
  243. package/dist/skills/file-skill-loader.js +35 -164
  244. package/dist/skills/file-skill-loader.js.map +1 -1
  245. package/dist/skills/index.d.ts +1 -1
  246. package/dist/skills/index.d.ts.map +1 -1
  247. package/dist/skills/index.js +1 -2
  248. package/dist/skills/index.js.map +1 -1
  249. package/dist/skills/skill-manager.d.ts +22 -29
  250. package/dist/skills/skill-manager.d.ts.map +1 -1
  251. package/dist/skills/skill-manager.js +63 -85
  252. package/dist/skills/skill-manager.js.map +1 -1
  253. package/dist/skills/types.d.ts +4 -16
  254. package/dist/skills/types.d.ts.map +1 -1
  255. package/dist/subagent/index.d.ts +4 -0
  256. package/dist/subagent/index.d.ts.map +1 -0
  257. package/dist/subagent/index.js +8 -0
  258. package/dist/subagent/index.js.map +1 -0
  259. package/dist/subagent/subagent-loader.d.ts +53 -0
  260. package/dist/subagent/subagent-loader.d.ts.map +1 -0
  261. package/dist/subagent/subagent-loader.js +155 -0
  262. package/dist/subagent/subagent-loader.js.map +1 -0
  263. package/dist/subagent/subagent-manager.d.ts +161 -0
  264. package/dist/subagent/subagent-manager.d.ts.map +1 -0
  265. package/dist/subagent/subagent-manager.js +468 -0
  266. package/dist/subagent/subagent-manager.js.map +1 -0
  267. package/dist/subagent/subagent-types.d.ts +77 -0
  268. package/dist/subagent/subagent-types.d.ts.map +1 -0
  269. package/dist/subagent/subagent-types.js +3 -0
  270. package/dist/subagent/subagent-types.js.map +1 -0
  271. package/dist/tools/builtin/bash.d.ts +3 -0
  272. package/dist/tools/builtin/bash.d.ts.map +1 -0
  273. package/dist/tools/builtin/bash.js +87 -0
  274. package/dist/tools/builtin/bash.js.map +1 -0
  275. package/dist/tools/builtin/edit-file.d.ts.map +1 -1
  276. package/dist/tools/builtin/edit-file.js +1 -0
  277. package/dist/tools/builtin/edit-file.js.map +1 -1
  278. package/dist/tools/builtin/index.d.ts +14 -0
  279. package/dist/tools/builtin/index.d.ts.map +1 -1
  280. package/dist/tools/builtin/index.js +45 -1
  281. package/dist/tools/builtin/index.js.map +1 -1
  282. package/dist/tools/builtin/list-errors.d.ts +7 -0
  283. package/dist/tools/builtin/list-errors.d.ts.map +1 -0
  284. package/dist/tools/builtin/list-errors.js +64 -0
  285. package/dist/tools/builtin/list-errors.js.map +1 -0
  286. package/dist/tools/builtin/list-subagents.d.ts +7 -0
  287. package/dist/tools/builtin/list-subagents.d.ts.map +1 -0
  288. package/dist/tools/builtin/list-subagents.js +21 -0
  289. package/dist/tools/builtin/list-subagents.js.map +1 -0
  290. package/dist/tools/builtin/recall.d.ts +11 -0
  291. package/dist/tools/builtin/recall.d.ts.map +1 -0
  292. package/dist/tools/builtin/recall.js +60 -0
  293. package/dist/tools/builtin/recall.js.map +1 -0
  294. package/dist/tools/builtin/remember.d.ts +12 -0
  295. package/dist/tools/builtin/remember.d.ts.map +1 -0
  296. package/dist/tools/builtin/remember.js +72 -0
  297. package/dist/tools/builtin/remember.js.map +1 -0
  298. package/dist/tools/builtin/skill.d.ts +14 -0
  299. package/dist/tools/builtin/skill.d.ts.map +1 -0
  300. package/dist/tools/builtin/skill.js +71 -0
  301. package/dist/tools/builtin/skill.js.map +1 -0
  302. package/dist/tools/builtin/spawn-subagent.d.ts +7 -0
  303. package/dist/tools/builtin/spawn-subagent.d.ts.map +1 -0
  304. package/dist/tools/builtin/spawn-subagent.js +43 -0
  305. package/dist/tools/builtin/spawn-subagent.js.map +1 -0
  306. package/dist/tools/builtin/web-fetch.d.ts +3 -0
  307. package/dist/tools/builtin/web-fetch.d.ts.map +1 -0
  308. package/dist/tools/builtin/web-fetch.js +101 -0
  309. package/dist/tools/builtin/web-fetch.js.map +1 -0
  310. package/dist/tools/builtin/write-file.d.ts.map +1 -1
  311. package/dist/tools/builtin/write-file.js +1 -0
  312. package/dist/tools/builtin/write-file.js.map +1 -1
  313. package/dist/tools/circuit-breaker.d.ts +19 -10
  314. package/dist/tools/circuit-breaker.d.ts.map +1 -1
  315. package/dist/tools/circuit-breaker.js +22 -11
  316. package/dist/tools/circuit-breaker.js.map +1 -1
  317. package/dist/tools/error-tracker.d.ts +28 -44
  318. package/dist/tools/error-tracker.d.ts.map +1 -1
  319. package/dist/tools/error-tracker.js +39 -156
  320. package/dist/tools/error-tracker.js.map +1 -1
  321. package/dist/tools/tool-filter.d.ts +70 -0
  322. package/dist/tools/tool-filter.d.ts.map +1 -0
  323. package/dist/tools/tool-filter.js +92 -0
  324. package/dist/tools/tool-filter.js.map +1 -0
  325. package/dist/tools/tool-output-truncator.d.ts +36 -0
  326. package/dist/tools/tool-output-truncator.d.ts.map +1 -0
  327. package/dist/tools/tool-output-truncator.js +117 -0
  328. package/dist/tools/tool-output-truncator.js.map +1 -0
  329. package/dist/tools/tool-registry.d.ts +25 -9
  330. package/dist/tools/tool-registry.d.ts.map +1 -1
  331. package/dist/tools/tool-registry.js +77 -28
  332. package/dist/tools/tool-registry.js.map +1 -1
  333. package/dist/tools/tool-validator.d.ts +13 -0
  334. package/dist/tools/tool-validator.d.ts.map +1 -0
  335. package/dist/tools/tool-validator.js +116 -0
  336. package/dist/tools/tool-validator.js.map +1 -0
  337. package/dist/tools/types.d.ts +86 -3
  338. package/dist/tools/types.d.ts.map +1 -1
  339. package/dist/tools/types.js +51 -2
  340. package/dist/tools/types.js.map +1 -1
  341. package/dist/trace/trace-logger.d.ts +30 -4
  342. package/dist/trace/trace-logger.d.ts.map +1 -1
  343. package/dist/trace/trace-logger.js +83 -7
  344. package/dist/trace/trace-logger.js.map +1 -1
  345. package/package.json +14 -4
  346. package/dist/compression/sliding-window.d.ts +0 -21
  347. package/dist/compression/sliding-window.d.ts.map +0 -1
  348. package/dist/compression/sliding-window.js +0 -44
  349. package/dist/compression/sliding-window.js.map +0 -1
@@ -0,0 +1,675 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OrchestratorAgent = void 0;
4
+ const agent_1 = require("../core/agent");
5
+ const message_1 = require("../messages/message");
6
+ const types_1 = require("../messages/types");
7
+ const errors_1 = require("../llm/errors");
8
+ const boundaries_1 = require("../security/boundaries");
9
+ const orchestrator_response_1 = require("./orchestrator-response");
10
+ const json_extractor_1 = require("./json-extractor");
11
+ // ─── System Prompt ────────────────────────────────────────────────────────
12
+ const DEFAULT_ORCHESTRATOR_SYSTEM_PROMPT = `You are a helpful AI assistant powered by the Orchestrator paradigm.
13
+ You do NOT execute tasks yourself. Instead, you decompose complex requests into
14
+ sub-tasks, delegate them to specialised sub-agents, synthesise their results,
15
+ and adapt your plan when gaps are found.
16
+
17
+ You have access to tools for discovering and spawning sub-agents.`;
18
+ // ─── OrchestratorAgent ────────────────────────────────────────────────────
19
+ /**
20
+ * Orchestrator Agent that decomposes user requests into a DAG of sub-tasks,
21
+ * dispatches them to sub-agents, synthesises results, and adapts the plan
22
+ * based on what is learned.
23
+ *
24
+ * ## Execution flow:
25
+ * ```
26
+ * User Input
27
+ * ↓
28
+ * [1. Decompose] LLM analyses request → TaskGraph (DAG of sub-agent tasks)
29
+ * ↓
30
+ * ┌─ Loop (up to maxRounds rounds) ─────────────────────────────┐
31
+ * │ │
32
+ * │ [2. Dispatch] Topological execution of ready nodes │
33
+ * │ - Nodes with no pending deps are spawned in parallel │
34
+ * │ - Parent waits for all ready nodes to complete │
35
+ * │ - Results are injected into context │
36
+ * │ │
37
+ * │ [3. Synthesize] LLM reviews all results → isComplete? │
38
+ * │ ├─ YES → return finalAnswer │
39
+ * │ └─ NO → produce gaps list │
40
+ * │ │
41
+ * │ [4. Adapt] LLM turns gaps into new TaskNodes │
42
+ * │ - New nodes appended to task graph │
43
+ * │ - Loop back to Dispatch │
44
+ * │ │
45
+ * └──────────────────────────────────────────────────────────────┘
46
+ * ↓
47
+ * Final Answer
48
+ * ```
49
+ *
50
+ * ## Session persistence
51
+ * When `enableCheckpointing` is set, the agent saves the full task graph
52
+ * state so orchestration can resume after interruption.
53
+ */
54
+ class OrchestratorAgent extends agent_1.Agent {
55
+ // ── Configuration ───────────────────────────────────────────────────
56
+ maxRounds;
57
+ maxParallelNodes;
58
+ maxTotalNodes;
59
+ // ── Runtime state ───────────────────────────────────────────────────
60
+ /** The current task graph. */
61
+ taskGraph = { nodes: [] };
62
+ /** How many dispatch rounds have been completed. */
63
+ completedRounds = 0;
64
+ /** Internal flag: when true, run() skips state reset (used by resume()). */
65
+ _skipStateReset = false;
66
+ constructor(config) {
67
+ const mergedConfig = {
68
+ ...config,
69
+ systemPrompt: config.systemPrompt ?? DEFAULT_ORCHESTRATOR_SYSTEM_PROMPT,
70
+ };
71
+ super(mergedConfig);
72
+ this.maxRounds = config.maxRounds ?? 3;
73
+ this.maxParallelNodes = config.maxParallelNodes ?? 5;
74
+ this.maxTotalNodes = config.maxTotalNodes ?? 20;
75
+ this.rebuildSystemPrompt();
76
+ }
77
+ /**
78
+ * Return the SubAgentManager, throwing a clear error if sub-agents were
79
+ * not configured. The Orchestrator cannot function without sub-agents.
80
+ */
81
+ getSubAgentManager() {
82
+ if (!this.subAgentManager) {
83
+ throw new Error("OrchestratorAgent requires sub-agents to be configured. " +
84
+ "Set `subAgentsDir` in OrchestratorAgentConfig with at least one AGENT.md definition.");
85
+ }
86
+ if (!this.subAgentManager.hasDefinitions()) {
87
+ throw new Error("OrchestratorAgent requires at least one sub-agent definition. " +
88
+ `No definitions found in "${this.subAgentsDir}". Add AGENT.md files to register sub-agents.`);
89
+ }
90
+ return this.subAgentManager;
91
+ }
92
+ // ─── Main Entry Point ───────────────────────────────────────────────
93
+ async run(input) {
94
+ const skipStateReset = this._skipStateReset;
95
+ this._skipStateReset = false;
96
+ // ── Pre-flight ────────────────────────────────────────────────────
97
+ const sizeError = this.validateInputSize(input);
98
+ if (sizeError)
99
+ return sizeError;
100
+ this._abortController = new AbortController();
101
+ await this.init();
102
+ await this.reloadDynamicResources();
103
+ this.recoverOrphanedSubAgentResults();
104
+ // Validate that sub-agents are available — the Orchestrator cannot function without them.
105
+ try {
106
+ this.getSubAgentManager();
107
+ }
108
+ catch (err) {
109
+ const message = err instanceof Error ? err.message : String(err);
110
+ this.logger.error("Orchestrator", message);
111
+ return message;
112
+ }
113
+ const userMessage = message_1.Message.user(input);
114
+ this.contextManager.addMessage(userMessage.toDict());
115
+ if (!skipStateReset) {
116
+ this.taskGraph = { nodes: [] };
117
+ this.completedRounds = 0;
118
+ }
119
+ if (this.checkpointingEnabled) {
120
+ this.saveCheckpoint("active");
121
+ }
122
+ // ── Phase 1: Decompose ─────────────────────────────────────────────
123
+ // On resume (skipStateReset + graph already loaded), skip decomposition.
124
+ if (!skipStateReset || this.taskGraph.nodes.length === 0) {
125
+ const plan = await this.decompose(input);
126
+ this.taskGraph = plan.taskGraph;
127
+ if (this.taskGraph.nodes.length === 0) {
128
+ const fallback = "I was unable to decompose this task into sub-agent actions. " +
129
+ "Please try rephrasing your request with more specific goals.";
130
+ for (const h of this.hooks)
131
+ h.onFinish?.(fallback);
132
+ return fallback;
133
+ }
134
+ this.logger.info("Orchestrator", `Decomposed into ${this.taskGraph.nodes.length} node(s).`);
135
+ for (const n of this.taskGraph.nodes) {
136
+ const depStr = n.dependsOn.length > 0
137
+ ? ` (deps: ${n.dependsOn.join(", ")})`
138
+ : "";
139
+ this.logger.info("Orchestrator", ` [${n.id}] → ${n.subAgentName}${depStr}`);
140
+ }
141
+ }
142
+ else {
143
+ this.logger.info("Orchestrator", `Resuming with ${this.taskGraph.nodes.length} node(s) from session.`);
144
+ }
145
+ if (this.checkpointingEnabled) {
146
+ this.saveCheckpoint("active");
147
+ }
148
+ // ── Phase 2-4: Orchestration Loop ──────────────────────────────────
149
+ for (let round = 0; round < this.maxRounds; round++) {
150
+ if (this.isCancelled) {
151
+ this.saveCheckpoint("cancelled");
152
+ const sid = this.sessionManager?.getSessionId() ?? "unknown";
153
+ const cancelMsg = `Execution cancelled by user. Session "${sid}" preserved — ` +
154
+ `resume with agent.resume("${sid}", "<your prompt>").`;
155
+ for (const h of this.hooks)
156
+ h.onFinish?.(cancelMsg);
157
+ return cancelMsg;
158
+ }
159
+ // Dispatch: execute all ready nodes (topological wave)
160
+ await this.dispatchReadyNodes();
161
+ // Synthesize: review all completed results
162
+ const synthesis = await this.synthesize(input);
163
+ this.completedRounds++;
164
+ if (this.checkpointingEnabled) {
165
+ this.saveCheckpoint("active");
166
+ }
167
+ // Check if complete
168
+ if (synthesis.isComplete && synthesis.finalAnswer) {
169
+ this.logger.info("Orchestrator", "Task complete — returning final answer.");
170
+ if (this.checkpointingEnabled) {
171
+ this.saveCheckpoint("completed");
172
+ }
173
+ for (const h of this.hooks)
174
+ h.onFinish?.(synthesis.finalAnswer);
175
+ return synthesis.finalAnswer;
176
+ }
177
+ // Check if this was the last round
178
+ if (round === this.maxRounds - 1) {
179
+ this.logger.info("Orchestrator", `Max rounds (${this.maxRounds}) reached — forcing synthesis.`);
180
+ const forced = await this.forceSynthesize(input);
181
+ if (this.checkpointingEnabled) {
182
+ this.saveCheckpoint("completed");
183
+ }
184
+ for (const h of this.hooks)
185
+ h.onFinish?.(forced);
186
+ return forced;
187
+ }
188
+ // Check total node limit
189
+ if (this.taskGraph.nodes.length >= this.maxTotalNodes) {
190
+ this.logger.info("Orchestrator", `Max total nodes (${this.maxTotalNodes}) reached — forcing synthesis.`);
191
+ const forced = await this.forceSynthesize(input);
192
+ if (this.checkpointingEnabled) {
193
+ this.saveCheckpoint("completed");
194
+ }
195
+ for (const h of this.hooks)
196
+ h.onFinish?.(forced);
197
+ return forced;
198
+ }
199
+ // Adapt: generate new nodes for gaps
200
+ const gaps = synthesis.gaps ?? [];
201
+ if (gaps.length === 0) {
202
+ // No gaps but not complete — force synthesis
203
+ this.logger.info("Orchestrator", "Synthesis incomplete but no gaps listed — forcing synthesis.");
204
+ const forced = await this.forceSynthesize(input);
205
+ if (this.checkpointingEnabled) {
206
+ this.saveCheckpoint("completed");
207
+ }
208
+ for (const h of this.hooks)
209
+ h.onFinish?.(forced);
210
+ return forced;
211
+ }
212
+ const adaptResult = await this.adapt(gaps);
213
+ if (adaptResult.stuck || adaptResult.newNodes.length === 0) {
214
+ this.logger.info("Orchestrator", "Adapt phase stuck — forcing synthesis.");
215
+ const forced = await this.forceSynthesize(input);
216
+ if (this.checkpointingEnabled) {
217
+ this.saveCheckpoint("completed");
218
+ }
219
+ for (const h of this.hooks)
220
+ h.onFinish?.(forced);
221
+ return forced;
222
+ }
223
+ // Append new nodes to the graph
224
+ this.taskGraph.nodes.push(...adaptResult.newNodes);
225
+ this.logger.info("Orchestrator", `Round ${this.completedRounds + 1}: ${adaptResult.newNodes.length} new node(s) added.`);
226
+ if (this.checkpointingEnabled) {
227
+ this.saveCheckpoint("active");
228
+ }
229
+ }
230
+ // Should not reach here — caught by last-round check above
231
+ const forced = await this.forceSynthesize(input);
232
+ for (const h of this.hooks)
233
+ h.onFinish?.(forced);
234
+ return forced;
235
+ }
236
+ // ─── Phase 1: Decompose ──────────────────────────────────────────────
237
+ /**
238
+ * Ask the LLM to decompose the user's request into a TaskGraph.
239
+ *
240
+ * Sends a dedicated prompt with the list of available sub-agents so the
241
+ * LLM knows what it can delegate to.
242
+ */
243
+ async decompose(input) {
244
+ const availableSubAgents = this.getSubAgentManager().buildSubAgentList();
245
+ const messages = [
246
+ { role: types_1.Role.System, content: (0, orchestrator_response_1.buildDecomposePrompt)(availableSubAgents) },
247
+ { role: types_1.Role.User, content: input },
248
+ ];
249
+ for (const h of this.hooks)
250
+ h.onLLMStart?.(messages, []);
251
+ let response;
252
+ try {
253
+ response = await this.llm.chat(messages, [], this._abortController?.signal);
254
+ }
255
+ catch (err) {
256
+ if (this.isCancelled) {
257
+ this.saveCheckpoint("cancelled");
258
+ const cancelMsg = `Execution cancelled by user. Session "${this.sessionManager?.getSessionId() ?? "unknown"}" preserved.`;
259
+ for (const h of this.hooks)
260
+ h.onFinish?.(cancelMsg);
261
+ return { thought: "Cancelled.", taskGraph: { nodes: [] } };
262
+ }
263
+ if (err instanceof errors_1.LLMNetworkError) {
264
+ for (const h of this.hooks)
265
+ h.onLLMError?.(err);
266
+ const recovered = await this.handleNetworkError(err, 0, "continue creating a decomposition plan");
267
+ // If recovery returned a string, wrap it
268
+ if (typeof recovered === "string") {
269
+ return { thought: recovered, taskGraph: { nodes: [] } };
270
+ }
271
+ }
272
+ throw err;
273
+ }
274
+ for (const h of this.hooks)
275
+ h.onLLMEnd?.(response);
276
+ if (response.usage) {
277
+ this.tokenBudget?.recordUsage(response.usage.prompt_tokens, response.usage.completion_tokens);
278
+ }
279
+ const parsed = (0, orchestrator_response_1.parseDecomposeResponse)(response.content);
280
+ // Validate nodes: ensure every dependsOn references a real node ID
281
+ const nodeIds = new Set(parsed.taskGraph.nodes.map((n) => n.id));
282
+ for (const node of parsed.taskGraph.nodes) {
283
+ for (const dep of node.dependsOn) {
284
+ if (!nodeIds.has(dep)) {
285
+ this.logger.warn("Orchestrator", `Node "${node.id}" depends on unknown node "${dep}" — removing dependency.`);
286
+ }
287
+ }
288
+ // Filter out unknown dependencies
289
+ node.dependsOn = node.dependsOn.filter((d) => nodeIds.has(d));
290
+ }
291
+ if (parsed.thought) {
292
+ this.logger.info("Orchestrator", `Decompose: ${parsed.thought}`);
293
+ for (const h of this.hooks)
294
+ h.onThought?.(parsed.thought);
295
+ }
296
+ return parsed;
297
+ }
298
+ // ─── Phase 2: Dispatch ────────────────────────────────────────────────
299
+ /**
300
+ * Execute all ready nodes in the task graph using topological wave-front
301
+ * dispatch. Nodes with no pending dependencies run in parallel (up to
302
+ * `maxParallelNodes`), then their dependants become ready.
303
+ *
304
+ * This method blocks until all currently ready (and transitively ready)
305
+ * nodes have completed.
306
+ */
307
+ async dispatchReadyNodes() {
308
+ // Keep dispatching waves until no more nodes can make progress
309
+ let progress = true;
310
+ while (progress) {
311
+ progress = false;
312
+ // Find nodes that are ready to run
313
+ const readyNodes = this.getReadyNodes();
314
+ if (readyNodes.length === 0)
315
+ break;
316
+ progress = true;
317
+ // Spawn in parallel, respecting maxParallelNodes
318
+ this.logger.info("Orchestrator", `Dispatching ${readyNodes.length} ready node(s).`);
319
+ for (const node of readyNodes) {
320
+ node.status = "running";
321
+ node.startedAt = Date.now();
322
+ // Resolve template variables in the input
323
+ const resolvedInput = this.resolveInputTemplate(node);
324
+ try {
325
+ const runId = this.getSubAgentManager().spawn(node.subAgentName, resolvedInput);
326
+ this.logger.info("Orchestrator", ` Spawned [${node.id}] → ${node.subAgentName} (${runId})`);
327
+ }
328
+ catch (err) {
329
+ const message = err instanceof Error ? err.message : String(err);
330
+ this.logger.warn("Orchestrator", ` Failed to spawn [${node.id}]: ${message}`);
331
+ node.status = "failed";
332
+ node.result = {
333
+ subAgentId: `error_${node.id}`,
334
+ name: node.subAgentName,
335
+ success: false,
336
+ output: `Failed to spawn: ${message}`,
337
+ durationMs: 0,
338
+ };
339
+ node.durationMs = 0;
340
+ }
341
+ }
342
+ // Poll until all dispatched nodes in this wave complete
343
+ await this.pollUntilNodesComplete(readyNodes);
344
+ // Inject completed results into context
345
+ for (const node of readyNodes) {
346
+ if (node.result) {
347
+ const source = `subagent:${node.subAgentName}:${node.id}`;
348
+ const msg = new message_1.Message(types_1.Role.User, (0, boundaries_1.wrapAndScan)(source, node.result.output), { name: source });
349
+ this.contextManager.addMessage(msg.toDict());
350
+ }
351
+ }
352
+ }
353
+ }
354
+ /**
355
+ * Return nodes whose dependencies are all completed and that haven't
356
+ * been dispatched yet, limited by maxParallelNodes.
357
+ */
358
+ getReadyNodes() {
359
+ const completedIds = new Set(this.taskGraph.nodes
360
+ .filter((n) => n.status === "completed")
361
+ .map((n) => n.id));
362
+ const ready = [];
363
+ for (const node of this.taskGraph.nodes) {
364
+ if (node.status !== "pending")
365
+ continue;
366
+ const allDepsSatisfied = node.dependsOn.every((depId) => {
367
+ // A "failed" node still satisfies the dependency (we don't want to
368
+ // deadlock), but the downstream node will see the error in its input.
369
+ const dep = this.taskGraph.nodes.find((n) => n.id === depId);
370
+ return dep && (dep.status === "completed" || dep.status === "failed");
371
+ });
372
+ if (allDepsSatisfied) {
373
+ ready.push(node);
374
+ if (ready.length >= this.maxParallelNodes)
375
+ break;
376
+ }
377
+ }
378
+ return ready;
379
+ }
380
+ /**
381
+ * Busy-wait until all given nodes have resolved (completed or failed).
382
+ */
383
+ async pollUntilNodesComplete(nodes) {
384
+ const targetIds = new Set(nodes.map((n) => n.id));
385
+ while (true) {
386
+ // Poll the sub-agent manager for any completed results
387
+ const results = await this.getSubAgentManager().pollCompleted();
388
+ // Match results to our task nodes
389
+ for (const result of results) {
390
+ // Find the node by matching the subAgentId pattern
391
+ for (const node of nodes) {
392
+ if (node.status === "running" && !node.result) {
393
+ // Match by sub-agent name + result timing
394
+ if (result.name === node.subAgentName) {
395
+ node.result = result;
396
+ node.status = result.success ? "completed" : "failed";
397
+ node.durationMs = result.durationMs;
398
+ this.logger.info("Orchestrator", ` [${node.id}] ${node.status} (${node.durationMs}ms)`);
399
+ break;
400
+ }
401
+ }
402
+ }
403
+ }
404
+ // Check if all target nodes are done
405
+ const allDone = nodes.every((n) => n.status === "completed" || n.status === "failed");
406
+ if (allDone)
407
+ break;
408
+ // Small delay before next poll
409
+ await new Promise((r) => setTimeout(r, 100));
410
+ }
411
+ }
412
+ /**
413
+ * Resolve `{{node_id.output}}` template references in a node's input.
414
+ */
415
+ resolveInputTemplate(node) {
416
+ return node.input.replace(/\{\{(\w+)\.output\}\}/g, (_match, refId) => {
417
+ const refNode = this.taskGraph.nodes.find((n) => n.id === refId);
418
+ if (refNode?.result) {
419
+ return refNode.result.output;
420
+ }
421
+ if (refNode?.status === "failed") {
422
+ return `[Node "${refId}" failed: ${refNode.result?.output ?? "unknown error"}]`;
423
+ }
424
+ return `[Reference to unavailable node: ${refId}]`;
425
+ });
426
+ }
427
+ // ─── Phase 3: Synthesize ──────────────────────────────────────────────
428
+ /**
429
+ * Ask the LLM to review all completed node results and determine whether
430
+ * the information is sufficient to answer the user.
431
+ */
432
+ async synthesize(userInput) {
433
+ const completedResults = this.formatCompletedResults();
434
+ if (!completedResults) {
435
+ return {
436
+ thought: "No nodes have completed.",
437
+ isComplete: false,
438
+ gaps: ["No sub-agent results available — retry decomposition."],
439
+ };
440
+ }
441
+ const prompt = (0, orchestrator_response_1.buildSynthesizePrompt)(userInput, completedResults);
442
+ const messages = [
443
+ { role: types_1.Role.System, content: prompt },
444
+ ];
445
+ for (const h of this.hooks)
446
+ h.onLLMStart?.(messages, []);
447
+ let response;
448
+ try {
449
+ response = await this.llm.chat(messages, [], this._abortController?.signal);
450
+ }
451
+ catch (err) {
452
+ if (this.isCancelled) {
453
+ return { thought: "Cancelled.", isComplete: false, gaps: [] };
454
+ }
455
+ if (err instanceof errors_1.LLMNetworkError) {
456
+ for (const h of this.hooks)
457
+ h.onLLMError?.(err);
458
+ return {
459
+ thought: `Network error during synthesis: ${err.message}`,
460
+ isComplete: false,
461
+ gaps: ["Synthesis failed due to network error — retry."],
462
+ };
463
+ }
464
+ throw err;
465
+ }
466
+ for (const h of this.hooks)
467
+ h.onLLMEnd?.(response);
468
+ if (response.usage) {
469
+ this.tokenBudget?.recordUsage(response.usage.prompt_tokens, response.usage.completion_tokens);
470
+ }
471
+ const parsed = (0, orchestrator_response_1.parseSynthesizeResponse)(response.content);
472
+ if (parsed.thought) {
473
+ this.logger.info("Orchestrator", `Synthesize: ${parsed.thought}`);
474
+ }
475
+ return parsed;
476
+ }
477
+ /**
478
+ * Build a formatted string of all completed node results for the
479
+ * synthesis LLM prompt.
480
+ */
481
+ formatCompletedResults() {
482
+ const completed = this.taskGraph.nodes.filter((n) => n.status === "completed" || n.status === "failed");
483
+ if (completed.length === 0)
484
+ return "";
485
+ const parts = [];
486
+ for (const node of completed) {
487
+ const header = node.status === "completed"
488
+ ? `=== [${node.id}] ${node.description} (SUCCESS) ===`
489
+ : `=== [${node.id}] ${node.description} (FAILED) ===`;
490
+ const body = node.result?.output ?? "(no output)";
491
+ parts.push(`${header}\n${body}\n`);
492
+ }
493
+ return parts.join("\n\n");
494
+ }
495
+ // ─── Phase 4: Adapt ──────────────────────────────────────────────────
496
+ /**
497
+ * Ask the LLM to generate new task nodes to fill the gaps identified
498
+ * during synthesis.
499
+ */
500
+ async adapt(gaps) {
501
+ const availableSubAgents = this.getSubAgentManager().buildSubAgentList();
502
+ const prompt = (0, orchestrator_response_1.buildAdaptPrompt)(gaps, availableSubAgents);
503
+ const messages = [
504
+ { role: types_1.Role.System, content: prompt },
505
+ ];
506
+ for (const h of this.hooks)
507
+ h.onLLMStart?.(messages, []);
508
+ let response;
509
+ try {
510
+ response = await this.llm.chat(messages, [], this._abortController?.signal);
511
+ }
512
+ catch (err) {
513
+ if (this.isCancelled) {
514
+ return { thought: "Cancelled.", newNodes: [], stuck: true };
515
+ }
516
+ if (err instanceof errors_1.LLMNetworkError) {
517
+ for (const h of this.hooks)
518
+ h.onLLMError?.(err);
519
+ return {
520
+ thought: `Network error during adapt: ${err.message}`,
521
+ newNodes: [],
522
+ stuck: true,
523
+ };
524
+ }
525
+ throw err;
526
+ }
527
+ for (const h of this.hooks)
528
+ h.onLLMEnd?.(response);
529
+ if (response.usage) {
530
+ this.tokenBudget?.recordUsage(response.usage.prompt_tokens, response.usage.completion_tokens);
531
+ }
532
+ const parsed = (0, orchestrator_response_1.parseAdaptResponse)(response.content);
533
+ // Validate new nodes
534
+ const existingIds = new Set(this.taskGraph.nodes.map((n) => n.id));
535
+ for (const node of parsed.newNodes) {
536
+ // Ensure unique IDs
537
+ if (existingIds.has(node.id)) {
538
+ node.id = `${node.id}_r${this.completedRounds}`;
539
+ }
540
+ existingIds.add(node.id);
541
+ // Filter unknown dependencies
542
+ node.dependsOn = node.dependsOn.filter((d) => existingIds.has(d));
543
+ }
544
+ if (parsed.thought) {
545
+ this.logger.info("Orchestrator", `Adapt: ${parsed.thought}`);
546
+ for (const h of this.hooks)
547
+ h.onThought?.(parsed.thought);
548
+ }
549
+ return parsed;
550
+ }
551
+ // ─── Force Synthesis ─────────────────────────────────────────────────
552
+ /**
553
+ * Force a final synthesis when rounds are exhausted or the orchestrator
554
+ * is stuck. Asks the LLM to produce the best answer it can with whatever
555
+ * results are available.
556
+ */
557
+ async forceSynthesize(userInput) {
558
+ const completedResults = this.formatCompletedResults();
559
+ if (!completedResults) {
560
+ return "I was unable to complete the task — no sub-agent results were produced.";
561
+ }
562
+ const prompt = `You are a synthesiser producing a FINAL answer. The orchestrator has
563
+ stopped (either max rounds reached or no more useful work can be devised).
564
+ Using the sub-agent results below, provide the BEST answer you can to the
565
+ user's original request. Be honest about any limitations or incomplete information.
566
+
567
+ === User's Original Request ===
568
+ ${userInput}
569
+
570
+ === Sub-Agent Results ===
571
+ ${completedResults}
572
+
573
+ Respond with ONLY a JSON object:
574
+ {
575
+ "thought": "<your analysis of what was accomplished and what is missing>",
576
+ "answer": "<the best answer you can provide>"
577
+ }
578
+
579
+ Rules:
580
+ - Include "thought" covering both what was learned AND what remains uncertain.
581
+ - The "answer" should be thorough but honest about gaps.
582
+ - The JSON must be valid — no trailing commas, no comments.`;
583
+ const messages = [
584
+ { role: types_1.Role.System, content: prompt },
585
+ ];
586
+ for (const h of this.hooks)
587
+ h.onLLMStart?.(messages, []);
588
+ let response;
589
+ try {
590
+ response = await this.llm.chat(messages, [], this._abortController?.signal);
591
+ }
592
+ catch (err) {
593
+ if (err instanceof errors_1.LLMNetworkError) {
594
+ for (const h of this.hooks)
595
+ h.onLLMError?.(err);
596
+ return `Network error during final synthesis: ${err.message}. ` +
597
+ `Partial results are preserved in the session.`;
598
+ }
599
+ throw err;
600
+ }
601
+ for (const h of this.hooks)
602
+ h.onLLMEnd?.(response);
603
+ if (response.usage) {
604
+ this.tokenBudget?.recordUsage(response.usage.prompt_tokens, response.usage.completion_tokens);
605
+ }
606
+ // Parse with the standard ReAct response format (thought + answer)
607
+ const json = (0, json_extractor_1.extractJSON)(response.content);
608
+ if (json) {
609
+ try {
610
+ const parsed = JSON.parse(json);
611
+ if (typeof parsed === "object" && parsed !== null) {
612
+ const thought = String(parsed.thought ?? "");
613
+ const answer = String(parsed.answer ?? response.content);
614
+ this.logger.info("Orchestrator", `Force synthesize: ${thought}`);
615
+ return answer;
616
+ }
617
+ }
618
+ catch {
619
+ // Fall through
620
+ }
621
+ }
622
+ return response.content;
623
+ }
624
+ // ─── Session Persistence ────────────────────────────────────────────
625
+ /**
626
+ * Agent type identifier for session metadata.
627
+ */
628
+ getAgentType() {
629
+ return "orchestrator";
630
+ }
631
+ /**
632
+ * Include orchestrator state in session checkpoints.
633
+ */
634
+ buildBaseSessionState(status) {
635
+ const base = super.buildBaseSessionState(status);
636
+ return {
637
+ ...base,
638
+ planState: undefined,
639
+ fusionState: undefined,
640
+ orchestratorState: {
641
+ taskGraph: this.taskGraph,
642
+ completedRounds: this.completedRounds,
643
+ },
644
+ };
645
+ }
646
+ /**
647
+ * Restore orchestrator state from a saved session.
648
+ */
649
+ loadAndRestoreSession(sessionId) {
650
+ const state = super.loadAndRestoreSession(sessionId);
651
+ if (state.orchestratorState) {
652
+ const os = state.orchestratorState;
653
+ this.taskGraph = os.taskGraph;
654
+ this.completedRounds = os.completedRounds;
655
+ }
656
+ return state;
657
+ }
658
+ // ─── Resume ─────────────────────────────────────────────────────────
659
+ /**
660
+ * Resume a previously interrupted orchestration session.
661
+ *
662
+ * Restores messages, system prompt, and the full task graph so the
663
+ * orchestrator can continue from where it left off.
664
+ *
665
+ * @param sessionId The session ID to resume.
666
+ * @param input New user input to continue the conversation.
667
+ */
668
+ async resume(sessionId, input) {
669
+ this.loadAndRestoreSession(sessionId);
670
+ this._skipStateReset = true;
671
+ return this.run(input);
672
+ }
673
+ }
674
+ exports.OrchestratorAgent = OrchestratorAgent;
675
+ //# sourceMappingURL=orchestrator-agent.js.map