@falai/agent 1.2.8 → 2.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 (499) hide show
  1. package/README.md +40 -886
  2. package/dist/adapters/MemoryAdapter.js +2 -2
  3. package/dist/adapters/MemoryAdapter.js.map +1 -1
  4. package/dist/adapters/MongoAdapter.js +2 -2
  5. package/dist/adapters/MongoAdapter.js.map +1 -1
  6. package/dist/adapters/OpenSearchAdapter.d.ts.map +1 -1
  7. package/dist/adapters/OpenSearchAdapter.js +9 -7
  8. package/dist/adapters/OpenSearchAdapter.js.map +1 -1
  9. package/dist/adapters/PostgreSQLAdapter.d.ts +14 -0
  10. package/dist/adapters/PostgreSQLAdapter.d.ts.map +1 -1
  11. package/dist/adapters/PostgreSQLAdapter.js +25 -9
  12. package/dist/adapters/PostgreSQLAdapter.js.map +1 -1
  13. package/dist/adapters/PrismaAdapter.js +5 -5
  14. package/dist/adapters/PrismaAdapter.js.map +1 -1
  15. package/dist/adapters/RedisAdapter.js +2 -2
  16. package/dist/adapters/RedisAdapter.js.map +1 -1
  17. package/dist/adapters/SQLiteAdapter.d.ts +17 -0
  18. package/dist/adapters/SQLiteAdapter.d.ts.map +1 -1
  19. package/dist/adapters/SQLiteAdapter.js +30 -11
  20. package/dist/adapters/SQLiteAdapter.js.map +1 -1
  21. package/dist/cjs/adapters/MemoryAdapter.js +2 -2
  22. package/dist/cjs/adapters/MemoryAdapter.js.map +1 -1
  23. package/dist/cjs/adapters/MongoAdapter.js +2 -2
  24. package/dist/cjs/adapters/MongoAdapter.js.map +1 -1
  25. package/dist/cjs/adapters/OpenSearchAdapter.d.ts.map +1 -1
  26. package/dist/cjs/adapters/OpenSearchAdapter.js +9 -7
  27. package/dist/cjs/adapters/OpenSearchAdapter.js.map +1 -1
  28. package/dist/cjs/adapters/PostgreSQLAdapter.d.ts +14 -0
  29. package/dist/cjs/adapters/PostgreSQLAdapter.d.ts.map +1 -1
  30. package/dist/cjs/adapters/PostgreSQLAdapter.js +25 -9
  31. package/dist/cjs/adapters/PostgreSQLAdapter.js.map +1 -1
  32. package/dist/cjs/adapters/PrismaAdapter.js +5 -5
  33. package/dist/cjs/adapters/PrismaAdapter.js.map +1 -1
  34. package/dist/cjs/adapters/RedisAdapter.js +2 -2
  35. package/dist/cjs/adapters/RedisAdapter.js.map +1 -1
  36. package/dist/cjs/adapters/SQLiteAdapter.d.ts +17 -0
  37. package/dist/cjs/adapters/SQLiteAdapter.d.ts.map +1 -1
  38. package/dist/cjs/adapters/SQLiteAdapter.js +30 -11
  39. package/dist/cjs/adapters/SQLiteAdapter.js.map +1 -1
  40. package/dist/cjs/constants/index.d.ts +0 -9
  41. package/dist/cjs/constants/index.d.ts.map +1 -1
  42. package/dist/cjs/constants/index.js +2 -11
  43. package/dist/cjs/constants/index.js.map +1 -1
  44. package/dist/cjs/core/Agent.d.ts +119 -153
  45. package/dist/cjs/core/Agent.d.ts.map +1 -1
  46. package/dist/cjs/core/Agent.js +471 -324
  47. package/dist/cjs/core/Agent.js.map +1 -1
  48. package/dist/cjs/core/AutoChainExecutor.d.ts +107 -0
  49. package/dist/cjs/core/AutoChainExecutor.d.ts.map +1 -0
  50. package/dist/cjs/core/AutoChainExecutor.js +297 -0
  51. package/dist/cjs/core/AutoChainExecutor.js.map +1 -0
  52. package/dist/cjs/core/BranchEvaluator.d.ts +54 -0
  53. package/dist/cjs/core/BranchEvaluator.d.ts.map +1 -0
  54. package/dist/cjs/core/BranchEvaluator.js +130 -0
  55. package/dist/cjs/core/BranchEvaluator.js.map +1 -0
  56. package/dist/cjs/core/DirectiveBus.d.ts +88 -0
  57. package/dist/cjs/core/DirectiveBus.d.ts.map +1 -0
  58. package/dist/cjs/core/DirectiveBus.js +196 -0
  59. package/dist/cjs/core/DirectiveBus.js.map +1 -0
  60. package/dist/cjs/core/DirectiveChainTracker.d.ts +49 -0
  61. package/dist/cjs/core/DirectiveChainTracker.d.ts.map +1 -0
  62. package/dist/cjs/core/DirectiveChainTracker.js +121 -0
  63. package/dist/cjs/core/DirectiveChainTracker.js.map +1 -0
  64. package/dist/cjs/core/Flow.d.ts +186 -0
  65. package/dist/cjs/core/Flow.d.ts.map +1 -0
  66. package/dist/cjs/core/Flow.js +550 -0
  67. package/dist/cjs/core/Flow.js.map +1 -0
  68. package/dist/cjs/core/FlowRouter.d.ts +182 -0
  69. package/dist/cjs/core/FlowRouter.d.ts.map +1 -0
  70. package/dist/cjs/core/{RoutingEngine.js → FlowRouter.js} +323 -306
  71. package/dist/cjs/core/FlowRouter.js.map +1 -0
  72. package/dist/cjs/core/PersistenceManager.d.ts +2 -2
  73. package/dist/cjs/core/PersistenceManager.d.ts.map +1 -1
  74. package/dist/cjs/core/PersistenceManager.js +7 -7
  75. package/dist/cjs/core/PersistenceManager.js.map +1 -1
  76. package/dist/cjs/core/PromptComposer.d.ts +21 -8
  77. package/dist/cjs/core/PromptComposer.d.ts.map +1 -1
  78. package/dist/cjs/core/PromptComposer.js +182 -105
  79. package/dist/cjs/core/PromptComposer.js.map +1 -1
  80. package/dist/cjs/core/PromptSectionCache.d.ts +1 -1
  81. package/dist/cjs/core/PromptSectionCache.js +1 -1
  82. package/dist/cjs/core/ResponseEngine.d.ts +18 -8
  83. package/dist/cjs/core/ResponseEngine.d.ts.map +1 -1
  84. package/dist/cjs/core/ResponseEngine.js +38 -36
  85. package/dist/cjs/core/ResponseEngine.js.map +1 -1
  86. package/dist/cjs/core/ResponseModal.d.ts +73 -56
  87. package/dist/cjs/core/ResponseModal.d.ts.map +1 -1
  88. package/dist/cjs/core/ResponseModal.js +1191 -1014
  89. package/dist/cjs/core/ResponseModal.js.map +1 -1
  90. package/dist/cjs/core/ResponsePipeline.d.ts +124 -26
  91. package/dist/cjs/core/ResponsePipeline.d.ts.map +1 -1
  92. package/dist/cjs/core/ResponsePipeline.js +509 -136
  93. package/dist/cjs/core/ResponsePipeline.js.map +1 -1
  94. package/dist/cjs/core/SignalEvaluator.d.ts +86 -0
  95. package/dist/cjs/core/SignalEvaluator.d.ts.map +1 -0
  96. package/dist/cjs/core/SignalEvaluator.js +333 -0
  97. package/dist/cjs/core/SignalEvaluator.js.map +1 -0
  98. package/dist/cjs/core/SignalProcessor.d.ts +152 -0
  99. package/dist/cjs/core/SignalProcessor.d.ts.map +1 -0
  100. package/dist/cjs/core/SignalProcessor.js +562 -0
  101. package/dist/cjs/core/SignalProcessor.js.map +1 -0
  102. package/dist/cjs/core/Step.d.ts +43 -32
  103. package/dist/cjs/core/Step.d.ts.map +1 -1
  104. package/dist/cjs/core/Step.js +221 -126
  105. package/dist/cjs/core/Step.js.map +1 -1
  106. package/dist/cjs/core/StreamingToolExecutor.d.ts +2 -2
  107. package/dist/cjs/core/StreamingToolExecutor.d.ts.map +1 -1
  108. package/dist/cjs/core/StreamingToolExecutor.js.map +1 -1
  109. package/dist/cjs/core/ToolManager.d.ts +44 -13
  110. package/dist/cjs/core/ToolManager.d.ts.map +1 -1
  111. package/dist/cjs/core/ToolManager.js +174 -91
  112. package/dist/cjs/core/ToolManager.js.map +1 -1
  113. package/dist/cjs/core/createAgent.d.ts +35 -0
  114. package/dist/cjs/core/createAgent.d.ts.map +1 -0
  115. package/dist/cjs/core/createAgent.js +39 -0
  116. package/dist/cjs/core/createAgent.js.map +1 -0
  117. package/dist/cjs/core/flow-namespace.d.ts +49 -0
  118. package/dist/cjs/core/flow-namespace.d.ts.map +1 -0
  119. package/dist/cjs/core/flow-namespace.js +171 -0
  120. package/dist/cjs/core/flow-namespace.js.map +1 -0
  121. package/dist/cjs/index.d.ts +11 -14
  122. package/dist/cjs/index.d.ts.map +1 -1
  123. package/dist/cjs/index.js +18 -22
  124. package/dist/cjs/index.js.map +1 -1
  125. package/dist/cjs/types/agent.d.ts +183 -54
  126. package/dist/cjs/types/agent.d.ts.map +1 -1
  127. package/dist/cjs/types/agent.js +0 -6
  128. package/dist/cjs/types/agent.js.map +1 -1
  129. package/dist/cjs/types/ai.d.ts +3 -3
  130. package/dist/cjs/types/ai.d.ts.map +1 -1
  131. package/dist/cjs/types/errors.d.ts +15 -0
  132. package/dist/cjs/types/errors.d.ts.map +1 -0
  133. package/dist/cjs/types/errors.js +22 -0
  134. package/dist/cjs/types/errors.js.map +1 -0
  135. package/dist/cjs/types/flow.d.ts +513 -0
  136. package/dist/cjs/types/flow.d.ts.map +1 -0
  137. package/dist/cjs/types/{route.js → flow.js} +2 -2
  138. package/dist/cjs/types/flow.js.map +1 -0
  139. package/dist/cjs/types/index.d.ts +7 -6
  140. package/dist/cjs/types/index.d.ts.map +1 -1
  141. package/dist/cjs/types/index.js +6 -2
  142. package/dist/cjs/types/index.js.map +1 -1
  143. package/dist/cjs/types/persistence.d.ts +11 -7
  144. package/dist/cjs/types/persistence.d.ts.map +1 -1
  145. package/dist/cjs/types/routing.d.ts +1 -1
  146. package/dist/cjs/types/routing.d.ts.map +1 -1
  147. package/dist/cjs/types/session.d.ts +24 -23
  148. package/dist/cjs/types/session.d.ts.map +1 -1
  149. package/dist/cjs/types/signals.d.ts +248 -0
  150. package/dist/cjs/types/signals.d.ts.map +1 -0
  151. package/dist/cjs/types/signals.js +11 -0
  152. package/dist/cjs/types/signals.js.map +1 -0
  153. package/dist/cjs/types/template.d.ts +2 -8
  154. package/dist/cjs/types/template.d.ts.map +1 -1
  155. package/dist/cjs/types/tool.d.ts +36 -29
  156. package/dist/cjs/types/tool.d.ts.map +1 -1
  157. package/dist/cjs/types/tool.js +1 -1
  158. package/dist/cjs/types/tool.js.map +1 -1
  159. package/dist/cjs/utils/condition.d.ts +7 -1
  160. package/dist/cjs/utils/condition.d.ts.map +1 -1
  161. package/dist/cjs/utils/condition.js.map +1 -1
  162. package/dist/cjs/utils/id.d.ts +13 -5
  163. package/dist/cjs/utils/id.d.ts.map +1 -1
  164. package/dist/cjs/utils/id.js +24 -10
  165. package/dist/cjs/utils/id.js.map +1 -1
  166. package/dist/cjs/utils/index.d.ts +2 -2
  167. package/dist/cjs/utils/index.d.ts.map +1 -1
  168. package/dist/cjs/utils/index.js +7 -3
  169. package/dist/cjs/utils/index.js.map +1 -1
  170. package/dist/cjs/utils/session.d.ts +44 -5
  171. package/dist/cjs/utils/session.d.ts.map +1 -1
  172. package/dist/cjs/utils/session.js +197 -38
  173. package/dist/cjs/utils/session.js.map +1 -1
  174. package/dist/constants/index.d.ts +0 -9
  175. package/dist/constants/index.d.ts.map +1 -1
  176. package/dist/constants/index.js +3 -9
  177. package/dist/constants/index.js.map +1 -1
  178. package/dist/core/Agent.d.ts +119 -153
  179. package/dist/core/Agent.d.ts.map +1 -1
  180. package/dist/core/Agent.js +472 -325
  181. package/dist/core/Agent.js.map +1 -1
  182. package/dist/core/AutoChainExecutor.d.ts +107 -0
  183. package/dist/core/AutoChainExecutor.d.ts.map +1 -0
  184. package/dist/core/AutoChainExecutor.js +293 -0
  185. package/dist/core/AutoChainExecutor.js.map +1 -0
  186. package/dist/core/BranchEvaluator.d.ts +54 -0
  187. package/dist/core/BranchEvaluator.d.ts.map +1 -0
  188. package/dist/core/BranchEvaluator.js +126 -0
  189. package/dist/core/BranchEvaluator.js.map +1 -0
  190. package/dist/core/DirectiveBus.d.ts +88 -0
  191. package/dist/core/DirectiveBus.d.ts.map +1 -0
  192. package/dist/core/DirectiveBus.js +192 -0
  193. package/dist/core/DirectiveBus.js.map +1 -0
  194. package/dist/core/DirectiveChainTracker.d.ts +49 -0
  195. package/dist/core/DirectiveChainTracker.d.ts.map +1 -0
  196. package/dist/core/DirectiveChainTracker.js +117 -0
  197. package/dist/core/DirectiveChainTracker.js.map +1 -0
  198. package/dist/core/Flow.d.ts +186 -0
  199. package/dist/core/Flow.d.ts.map +1 -0
  200. package/dist/core/Flow.js +546 -0
  201. package/dist/core/Flow.js.map +1 -0
  202. package/dist/core/FlowRouter.d.ts +182 -0
  203. package/dist/core/FlowRouter.d.ts.map +1 -0
  204. package/dist/core/{RoutingEngine.js → FlowRouter.js} +322 -305
  205. package/dist/core/FlowRouter.js.map +1 -0
  206. package/dist/core/PersistenceManager.d.ts +2 -2
  207. package/dist/core/PersistenceManager.d.ts.map +1 -1
  208. package/dist/core/PersistenceManager.js +7 -7
  209. package/dist/core/PersistenceManager.js.map +1 -1
  210. package/dist/core/PromptComposer.d.ts +21 -8
  211. package/dist/core/PromptComposer.d.ts.map +1 -1
  212. package/dist/core/PromptComposer.js +183 -106
  213. package/dist/core/PromptComposer.js.map +1 -1
  214. package/dist/core/PromptSectionCache.d.ts +1 -1
  215. package/dist/core/PromptSectionCache.js +1 -1
  216. package/dist/core/ResponseEngine.d.ts +18 -8
  217. package/dist/core/ResponseEngine.d.ts.map +1 -1
  218. package/dist/core/ResponseEngine.js +38 -36
  219. package/dist/core/ResponseEngine.js.map +1 -1
  220. package/dist/core/ResponseModal.d.ts +73 -56
  221. package/dist/core/ResponseModal.d.ts.map +1 -1
  222. package/dist/core/ResponseModal.js +1193 -1016
  223. package/dist/core/ResponseModal.js.map +1 -1
  224. package/dist/core/ResponsePipeline.d.ts +124 -26
  225. package/dist/core/ResponsePipeline.d.ts.map +1 -1
  226. package/dist/core/ResponsePipeline.js +509 -137
  227. package/dist/core/ResponsePipeline.js.map +1 -1
  228. package/dist/core/SignalEvaluator.d.ts +86 -0
  229. package/dist/core/SignalEvaluator.d.ts.map +1 -0
  230. package/dist/core/SignalEvaluator.js +326 -0
  231. package/dist/core/SignalEvaluator.js.map +1 -0
  232. package/dist/core/SignalProcessor.d.ts +152 -0
  233. package/dist/core/SignalProcessor.d.ts.map +1 -0
  234. package/dist/core/SignalProcessor.js +555 -0
  235. package/dist/core/SignalProcessor.js.map +1 -0
  236. package/dist/core/Step.d.ts +43 -32
  237. package/dist/core/Step.d.ts.map +1 -1
  238. package/dist/core/Step.js +220 -126
  239. package/dist/core/Step.js.map +1 -1
  240. package/dist/core/StreamingToolExecutor.d.ts +2 -2
  241. package/dist/core/StreamingToolExecutor.d.ts.map +1 -1
  242. package/dist/core/StreamingToolExecutor.js.map +1 -1
  243. package/dist/core/ToolManager.d.ts +44 -13
  244. package/dist/core/ToolManager.d.ts.map +1 -1
  245. package/dist/core/ToolManager.js +174 -91
  246. package/dist/core/ToolManager.js.map +1 -1
  247. package/dist/core/createAgent.d.ts +35 -0
  248. package/dist/core/createAgent.d.ts.map +1 -0
  249. package/dist/core/createAgent.js +36 -0
  250. package/dist/core/createAgent.js.map +1 -0
  251. package/dist/core/flow-namespace.d.ts +49 -0
  252. package/dist/core/flow-namespace.d.ts.map +1 -0
  253. package/dist/core/flow-namespace.js +168 -0
  254. package/dist/core/flow-namespace.js.map +1 -0
  255. package/dist/index.d.ts +11 -14
  256. package/dist/index.d.ts.map +1 -1
  257. package/dist/index.js +9 -12
  258. package/dist/index.js.map +1 -1
  259. package/dist/types/agent.d.ts +183 -54
  260. package/dist/types/agent.d.ts.map +1 -1
  261. package/dist/types/agent.js +0 -6
  262. package/dist/types/agent.js.map +1 -1
  263. package/dist/types/ai.d.ts +3 -3
  264. package/dist/types/ai.d.ts.map +1 -1
  265. package/dist/types/errors.d.ts +15 -0
  266. package/dist/types/errors.d.ts.map +1 -0
  267. package/dist/types/errors.js +18 -0
  268. package/dist/types/errors.js.map +1 -0
  269. package/dist/types/flow.d.ts +513 -0
  270. package/dist/types/flow.d.ts.map +1 -0
  271. package/dist/types/flow.js +5 -0
  272. package/dist/types/flow.js.map +1 -0
  273. package/dist/types/index.d.ts +7 -6
  274. package/dist/types/index.d.ts.map +1 -1
  275. package/dist/types/index.js +4 -1
  276. package/dist/types/index.js.map +1 -1
  277. package/dist/types/persistence.d.ts +11 -7
  278. package/dist/types/persistence.d.ts.map +1 -1
  279. package/dist/types/routing.d.ts +1 -1
  280. package/dist/types/routing.d.ts.map +1 -1
  281. package/dist/types/session.d.ts +24 -23
  282. package/dist/types/session.d.ts.map +1 -1
  283. package/dist/types/signals.d.ts +248 -0
  284. package/dist/types/signals.d.ts.map +1 -0
  285. package/dist/types/signals.js +10 -0
  286. package/dist/types/signals.js.map +1 -0
  287. package/dist/types/template.d.ts +2 -8
  288. package/dist/types/template.d.ts.map +1 -1
  289. package/dist/types/tool.d.ts +36 -29
  290. package/dist/types/tool.d.ts.map +1 -1
  291. package/dist/types/tool.js +1 -1
  292. package/dist/types/tool.js.map +1 -1
  293. package/dist/utils/condition.d.ts +7 -1
  294. package/dist/utils/condition.d.ts.map +1 -1
  295. package/dist/utils/condition.js.map +1 -1
  296. package/dist/utils/id.d.ts +13 -5
  297. package/dist/utils/id.d.ts.map +1 -1
  298. package/dist/utils/id.js +22 -9
  299. package/dist/utils/id.js.map +1 -1
  300. package/dist/utils/index.d.ts +2 -2
  301. package/dist/utils/index.d.ts.map +1 -1
  302. package/dist/utils/index.js +2 -2
  303. package/dist/utils/index.js.map +1 -1
  304. package/dist/utils/session.d.ts +44 -5
  305. package/dist/utils/session.d.ts.map +1 -1
  306. package/dist/utils/session.js +193 -37
  307. package/dist/utils/session.js.map +1 -1
  308. package/docs/README.md +15 -202
  309. package/docs/concepts/architecture.md +281 -0
  310. package/docs/concepts/directives.md +400 -0
  311. package/docs/concepts/pipeline.md +399 -0
  312. package/docs/guides/branching.md +263 -0
  313. package/docs/guides/compaction.md +163 -0
  314. package/docs/guides/conditions.md +167 -0
  315. package/docs/guides/error-handling.md +176 -0
  316. package/docs/guides/flow-control.md +409 -0
  317. package/docs/guides/instructions.md +210 -0
  318. package/docs/guides/persistence.md +182 -0
  319. package/docs/guides/streaming.md +137 -0
  320. package/docs/migration/README.md +15 -0
  321. package/docs/migration/route-to-flow.md +560 -0
  322. package/docs/migration/v1-to-v2.md +909 -0
  323. package/docs/reference/adapters.md +481 -0
  324. package/docs/reference/branches.md +241 -0
  325. package/docs/reference/create-agent.md +186 -0
  326. package/docs/reference/directive.md +243 -0
  327. package/docs/reference/errors.md +122 -0
  328. package/docs/reference/flow.md +238 -0
  329. package/docs/reference/instruction.md +177 -0
  330. package/docs/reference/pre-directive.md +131 -0
  331. package/docs/reference/providers.md +227 -0
  332. package/docs/reference/signals.md +356 -0
  333. package/docs/reference/step.md +339 -0
  334. package/docs/reference/tool.md +269 -0
  335. package/docs/start/01-install.md +81 -0
  336. package/docs/start/02-first-agent.md +196 -0
  337. package/docs/start/03-collect-data.md +222 -0
  338. package/docs/start/04-add-tools.md +276 -0
  339. package/docs/start/05-go-to-production.md +216 -0
  340. package/examples/01-quickstart.ts +20 -0
  341. package/examples/02-data-extraction.ts +90 -0
  342. package/examples/03-tools.ts +136 -0
  343. package/examples/04-instructions.ts +100 -0
  344. package/examples/05-branching.ts +140 -0
  345. package/examples/06-flow-control.ts +103 -0
  346. package/examples/07-streaming.ts +69 -0
  347. package/examples/08-persistence.ts +98 -0
  348. package/examples/09-signals.ts +144 -0
  349. package/examples/tsconfig.json +30 -0
  350. package/package.json +2 -1
  351. package/src/adapters/MemoryAdapter.ts +3 -3
  352. package/src/adapters/MongoAdapter.ts +3 -3
  353. package/src/adapters/OpenSearchAdapter.ts +10 -8
  354. package/src/adapters/PostgreSQLAdapter.ts +26 -10
  355. package/src/adapters/PrismaAdapter.ts +6 -6
  356. package/src/adapters/RedisAdapter.ts +3 -3
  357. package/src/adapters/SQLiteAdapter.ts +31 -12
  358. package/src/constants/index.ts +2 -10
  359. package/src/core/Agent.ts +585 -374
  360. package/src/core/AutoChainExecutor.ts +440 -0
  361. package/src/core/BranchEvaluator.ts +167 -0
  362. package/src/core/DirectiveBus.ts +248 -0
  363. package/src/core/DirectiveChainTracker.ts +144 -0
  364. package/src/core/Flow.ts +666 -0
  365. package/src/core/{RoutingEngine.ts → FlowRouter.ts} +385 -365
  366. package/src/core/PersistenceManager.ts +8 -8
  367. package/src/core/PromptComposer.ts +209 -140
  368. package/src/core/PromptSectionCache.ts +1 -1
  369. package/src/core/ResponseEngine.ts +61 -46
  370. package/src/core/ResponseModal.ts +1453 -1240
  371. package/src/core/ResponsePipeline.ts +655 -175
  372. package/src/core/SignalEvaluator.ts +420 -0
  373. package/src/core/SignalProcessor.ts +723 -0
  374. package/src/core/Step.ts +279 -176
  375. package/src/core/StreamingToolExecutor.ts +4 -4
  376. package/src/core/ToolManager.ts +200 -97
  377. package/src/core/createAgent.ts +40 -0
  378. package/src/core/flow-namespace.ts +219 -0
  379. package/src/index.ts +42 -36
  380. package/src/types/agent.ts +182 -53
  381. package/src/types/ai.ts +3 -3
  382. package/src/types/errors.ts +18 -0
  383. package/src/types/flow.ts +590 -0
  384. package/src/types/index.ts +43 -16
  385. package/src/types/persistence.ts +12 -8
  386. package/src/types/routing.ts +1 -1
  387. package/src/types/session.ts +26 -23
  388. package/src/types/signals.ts +321 -0
  389. package/src/types/template.ts +3 -11
  390. package/src/types/tool.ts +50 -42
  391. package/src/utils/condition.ts +13 -4
  392. package/src/utils/id.ts +27 -9
  393. package/src/utils/index.ts +6 -2
  394. package/src/utils/session.ts +238 -42
  395. package/dist/cjs/core/BatchExecutor.d.ts +0 -359
  396. package/dist/cjs/core/BatchExecutor.d.ts.map +0 -1
  397. package/dist/cjs/core/BatchExecutor.js +0 -861
  398. package/dist/cjs/core/BatchExecutor.js.map +0 -1
  399. package/dist/cjs/core/BatchPromptBuilder.d.ts +0 -89
  400. package/dist/cjs/core/BatchPromptBuilder.d.ts.map +0 -1
  401. package/dist/cjs/core/BatchPromptBuilder.js +0 -223
  402. package/dist/cjs/core/BatchPromptBuilder.js.map +0 -1
  403. package/dist/cjs/core/Route.d.ts +0 -180
  404. package/dist/cjs/core/Route.d.ts.map +0 -1
  405. package/dist/cjs/core/Route.js +0 -542
  406. package/dist/cjs/core/Route.js.map +0 -1
  407. package/dist/cjs/core/RoutingEngine.d.ts +0 -185
  408. package/dist/cjs/core/RoutingEngine.d.ts.map +0 -1
  409. package/dist/cjs/core/RoutingEngine.js.map +0 -1
  410. package/dist/cjs/types/route.d.ts +0 -336
  411. package/dist/cjs/types/route.d.ts.map +0 -1
  412. package/dist/cjs/types/route.js.map +0 -1
  413. package/dist/core/BatchExecutor.d.ts +0 -359
  414. package/dist/core/BatchExecutor.d.ts.map +0 -1
  415. package/dist/core/BatchExecutor.js +0 -856
  416. package/dist/core/BatchExecutor.js.map +0 -1
  417. package/dist/core/BatchPromptBuilder.d.ts +0 -89
  418. package/dist/core/BatchPromptBuilder.d.ts.map +0 -1
  419. package/dist/core/BatchPromptBuilder.js +0 -219
  420. package/dist/core/BatchPromptBuilder.js.map +0 -1
  421. package/dist/core/Route.d.ts +0 -180
  422. package/dist/core/Route.d.ts.map +0 -1
  423. package/dist/core/Route.js +0 -538
  424. package/dist/core/Route.js.map +0 -1
  425. package/dist/core/RoutingEngine.d.ts +0 -185
  426. package/dist/core/RoutingEngine.d.ts.map +0 -1
  427. package/dist/core/RoutingEngine.js.map +0 -1
  428. package/dist/types/route.d.ts +0 -336
  429. package/dist/types/route.d.ts.map +0 -1
  430. package/dist/types/route.js +0 -5
  431. package/dist/types/route.js.map +0 -1
  432. package/docs/CONTRIBUTING.md +0 -521
  433. package/docs/api/README.md +0 -3299
  434. package/docs/api/overview.md +0 -1410
  435. package/docs/architecture/data-extraction-flow.md +0 -360
  436. package/docs/architecture/multi-step-execution.md +0 -277
  437. package/docs/core/agent/README.md +0 -938
  438. package/docs/core/agent/context-management.md +0 -796
  439. package/docs/core/agent/rules-and-prohibitions.md +0 -113
  440. package/docs/core/agent/session-management.md +0 -693
  441. package/docs/core/ai-integration/prompt-composition.md +0 -355
  442. package/docs/core/ai-integration/providers.md +0 -515
  443. package/docs/core/ai-integration/response-processing.md +0 -433
  444. package/docs/core/conversation-flows/data-collection.md +0 -772
  445. package/docs/core/conversation-flows/route-dsl.md +0 -509
  446. package/docs/core/conversation-flows/routes.md +0 -249
  447. package/docs/core/conversation-flows/step-transitions.md +0 -731
  448. package/docs/core/conversation-flows/steps.md +0 -268
  449. package/docs/core/error-handling.md +0 -830
  450. package/docs/core/persistence/adapters.md +0 -255
  451. package/docs/core/persistence/session-storage.md +0 -656
  452. package/docs/core/routing/intelligent-routing.md +0 -470
  453. package/docs/core/tools/enhanced-tool.md +0 -186
  454. package/docs/core/tools/streaming-execution.md +0 -161
  455. package/docs/core/tools/tool-definition.md +0 -970
  456. package/docs/core/tools/tool-scoping.md +0 -819
  457. package/docs/guides/advanced-patterns/publishing.md +0 -186
  458. package/docs/guides/context-compaction.md +0 -96
  459. package/docs/guides/error-handling-patterns.md +0 -578
  460. package/docs/guides/getting-started/README.md +0 -795
  461. package/docs/guides/migration/README.md +0 -101
  462. package/docs/guides/migration/flexible-routing-conditions.md +0 -375
  463. package/docs/guides/migration/multi-step-execution.md +0 -393
  464. package/docs/guides/migration/response-modal-refactor.md +0 -518
  465. package/docs/guides/prompt-optimization.md +0 -164
  466. package/examples/advanced-patterns/context-compaction.ts +0 -223
  467. package/examples/advanced-patterns/knowledge-based-agent.ts +0 -735
  468. package/examples/advanced-patterns/persistent-onboarding.ts +0 -728
  469. package/examples/advanced-patterns/route-lifecycle-hooks.ts +0 -556
  470. package/examples/advanced-patterns/streaming-responses.ts +0 -656
  471. package/examples/ai-providers/anthropic-integration.ts +0 -388
  472. package/examples/ai-providers/openai-integration.ts +0 -228
  473. package/examples/condition-patterns/function-only-conditions.ts +0 -365
  474. package/examples/condition-patterns/mixed-array-conditions.ts +0 -477
  475. package/examples/condition-patterns/route-skipif-patterns.ts +0 -468
  476. package/examples/condition-patterns/step-skipif-patterns.ts +0 -0
  477. package/examples/condition-patterns/string-only-conditions.ts +0 -296
  478. package/examples/conversation-flows/completion-transitions.ts +0 -318
  479. package/examples/core-concepts/basic-agent.ts +0 -503
  480. package/examples/core-concepts/modern-streaming-api.ts +0 -309
  481. package/examples/core-concepts/schema-driven-extraction.ts +0 -332
  482. package/examples/core-concepts/session-management.ts +0 -494
  483. package/examples/integrations/database-integration.ts +0 -631
  484. package/examples/integrations/healthcare-integration.ts +0 -595
  485. package/examples/integrations/search-integration.ts +0 -530
  486. package/examples/integrations/server-session-management.ts +0 -307
  487. package/examples/persistence/custom-adapter.ts +0 -526
  488. package/examples/persistence/database-persistence.ts +0 -583
  489. package/examples/persistence/memory-sessions.ts +0 -495
  490. package/examples/persistence/prisma-schema.example.prisma +0 -74
  491. package/examples/persistence/redis-persistence.ts +0 -488
  492. package/examples/tools/basic-tools.ts +0 -765
  493. package/examples/tools/data-enrichment-tools.ts +0 -593
  494. package/examples/tools/enhanced-tool-metadata.ts +0 -268
  495. package/examples/tools/streaming-tool-execution.ts +0 -283
  496. package/src/core/BatchExecutor.ts +0 -1187
  497. package/src/core/BatchPromptBuilder.ts +0 -299
  498. package/src/core/Route.ts +0 -678
  499. package/src/types/route.ts +0 -392
package/src/core/Agent.ts CHANGED
@@ -5,11 +5,9 @@
5
5
  import type {
6
6
  AgentOptions,
7
7
  Term,
8
- Guideline,
9
- GuidelineMatch,
8
+ Instruction,
10
9
  Tool,
11
- Event,
12
- RouteOptions,
10
+ FlowOptions,
13
11
  SessionState,
14
12
  Template,
15
13
  AgentResponseStreamChunk,
@@ -19,23 +17,28 @@ import type {
19
17
  ValidationResult,
20
18
  AiProvider,
21
19
  CompactionOptions,
20
+ Directive,
22
21
  } from "../types";
23
- import { CompositionMode } from "../types";
22
+ import type { Signal } from "../types/signals";
23
+ import { NotImplementedError } from "../types/errors";
24
+ import { SignalProcessor } from "./SignalProcessor";
25
+ import { SignalEvaluator } from "./SignalEvaluator";
24
26
  import type { StreamOptions, GenerateOptions, RespondParams } from "./ResponseModal";
25
27
  import {
26
28
  mergeCollected,
29
+ enterFlow,
30
+ enterStep,
31
+ completeCurrentFlow,
27
32
  logger,
28
33
  LoggerLevel,
29
- render,
30
- createTemplateContext,
31
- createConditionEvaluator,
34
+ generateSignalId,
32
35
  } from "../utils";
33
36
 
34
- import { Route } from "./Route";
35
- import { Step } from "./Step";
37
+ import { Flow } from "./Flow";
38
+ import { Step, FlowConfigurationError as StepFlowConfigurationError } from "./Step";
36
39
  import { PersistenceManager } from "./PersistenceManager";
37
40
  import { SessionManager } from "./SessionManager";
38
- import { RoutingEngine } from "./RoutingEngine";
41
+ import { FlowRouter } from "./FlowRouter";
39
42
  import { PromptSectionCache } from "./PromptSectionCache";
40
43
 
41
44
  import { ResponseModal } from "./ResponseModal";
@@ -53,12 +56,12 @@ class DataValidationError extends Error {
53
56
  }
54
57
 
55
58
  /**
56
- * Error thrown when route configuration is invalid
59
+ * Error thrown when flow configuration is invalid
57
60
  */
58
- class RouteConfigurationError extends Error {
59
- constructor(public routeTitle: string, public invalidFields: string[], message?: string) {
60
- super(message || `Route configuration error in '${routeTitle}'`);
61
- this.name = "RouteConfigurationError";
61
+ class FlowConfigurationError extends Error {
62
+ constructor(public flowTitle: string, public invalidFields: string[], message?: string) {
63
+ super(message || `Flow configuration error in '${flowTitle}'`);
64
+ this.name = "FlowConfigurationError";
62
65
  }
63
66
  }
64
67
 
@@ -68,14 +71,12 @@ class RouteConfigurationError extends Error {
68
71
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
69
72
  export class Agent<TContext = any, TData = any> {
70
73
  private _terms: Term<TContext, TData>[] = [];
71
- private _guidelines: Guideline<TContext, TData>[] = [];
74
+ private _instructions: Instruction<TContext, TData>[] = [];
72
75
  private _tools: Tool<TContext, TData>[] = [];
73
- private _routes: Route<TContext, TData>[] = [];
74
- private _rules: Template<TContext, TData>[] = [];
75
- private _prohibitions: Template<TContext, TData>[] = [];
76
+ private _flows: Flow<TContext, TData>[] = [];
76
77
  private _context: TContext | undefined;
77
78
  private _persistenceManager: PersistenceManager<TData> | undefined;
78
- private _routingEngine: RoutingEngine<TContext, TData>;
79
+ private _routingEngine: FlowRouter<TContext, TData>;
79
80
  private _responseModal: ResponseModal<TContext, TData>;
80
81
  private _currentSession?: SessionState<TData>;
81
82
  private _knowledgeBase: Record<string, unknown> = {};
@@ -84,6 +85,22 @@ export class Agent<TContext = any, TData = any> {
84
85
  private _compactionOptions?: CompactionOptions;
85
86
  private _promptSectionCache: PromptSectionCache;
86
87
 
88
+ /** Signals: typed event detectors that run around the LLM turn. */
89
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
90
+ private _signals: Signal<TContext, TData, any>[];
91
+
92
+ /**
93
+ * Signal processor instance. Undefined when no signals are configured.
94
+ * Constructed only when `options.signals` is non-empty (Requirement 2.3).
95
+ */
96
+ public signalProcessor: SignalProcessor<TContext, TData> | undefined;
97
+
98
+ /** Maximum consecutive auto-steps allowed in a single turn before throwing. */
99
+ public readonly maxAutoStepsPerTurn: number;
100
+
101
+ /** Maximum chained directives allowed in a single turn before throwing. */
102
+ public readonly maxDirectiveChain: number;
103
+
87
104
  /** Public session manager for easy session management */
88
105
  public session: SessionManager<TData>;
89
106
 
@@ -91,6 +108,98 @@ export class Agent<TContext = any, TData = any> {
91
108
  public tool: ToolManager<TContext, TData>;
92
109
 
93
110
  constructor(private options: AgentOptions<TContext, TData>) {
111
+ this.maxAutoStepsPerTurn = options.maxAutoStepsPerTurn ?? 10;
112
+ this.maxDirectiveChain = options.maxDirectiveChain ?? 10;
113
+
114
+ // Validate routerMode reservation — only 'ai' is supported in v2.0
115
+ if (options.routerMode !== undefined && options.routerMode !== 'ai') {
116
+ throw new NotImplementedError(
117
+ `[NotImplementedError] routerMode "${String(options.routerMode)}" is not implemented: only "ai" is supported in v2.0. ` +
118
+ `Set routerMode to "ai" or omit the option.`
119
+ );
120
+ }
121
+
122
+ // ─── Signal construction-time validation (Requirements 1.4, 1.5, 1.6, 1.9, 2.3) ───
123
+ const rawSignals = options.signals ?? [];
124
+
125
+ // Auto-generate stable ids for entries without `id`
126
+ for (let i = 0; i < rawSignals.length; i++) {
127
+ if (!rawSignals[i].id) {
128
+ rawSignals[i] = {
129
+ ...rawSignals[i],
130
+ id: generateSignalId(rawSignals[i].title, rawSignals[i].description, i),
131
+ };
132
+ }
133
+ }
134
+
135
+ // Validate unique ids (Requirement 1.4)
136
+ const idCounts = new Map<string, number>();
137
+ for (const signal of rawSignals) {
138
+ const id = signal.id!;
139
+ idCounts.set(id, (idCounts.get(id) ?? 0) + 1);
140
+ }
141
+ const duplicateIds = [...idCounts.entries()]
142
+ .filter(([, count]) => count > 1)
143
+ .map(([id]) => id);
144
+ if (duplicateIds.length > 0) {
145
+ throw new StepFlowConfigurationError(
146
+ `[FlowConfigurationError] Duplicate signal ids: ${duplicateIds.join(', ')}. ` +
147
+ `Each signal must have a unique id.`
148
+ );
149
+ }
150
+
151
+ // Validate signalBatchSize (positive integer when set)
152
+ if (options.signalBatchSize !== undefined) {
153
+ if (
154
+ !Number.isInteger(options.signalBatchSize) ||
155
+ options.signalBatchSize <= 0
156
+ ) {
157
+ throw new StepFlowConfigurationError(
158
+ `[FlowConfigurationError] signalBatchSize must be a positive integer, got: ${options.signalBatchSize}.`
159
+ );
160
+ }
161
+ }
162
+
163
+ // Validate each signal's configuration
164
+ for (const signal of rawSignals) {
165
+ // Requirement 1.5: cooldown without cooldownMs → debug warning, treat as 'always'
166
+ if (signal.behavior === 'cooldown' && signal.cooldownMs == null) {
167
+ logger.debug(
168
+ `[Agent] Signal "${signal.id}" has behavior 'cooldown' but no cooldownMs. Treating as 'always'.`
169
+ );
170
+ (signal as { behavior?: string }).behavior = 'always';
171
+ }
172
+
173
+ // Requirement 1.9: validate extract schema is a JSON Schema object
174
+ if (signal.extract !== undefined) {
175
+ if (
176
+ signal.extract === null ||
177
+ typeof signal.extract !== 'object' ||
178
+ Array.isArray(signal.extract)
179
+ ) {
180
+ throw new StepFlowConfigurationError(
181
+ `[FlowConfigurationError] Signal "${signal.id}" has an invalid extract schema. ` +
182
+ `Expected a JSON Schema object, got: ${typeof signal.extract}.`
183
+ );
184
+ }
185
+ }
186
+ }
187
+
188
+ this._signals = rawSignals;
189
+
190
+ // Requirement 2.3: Only instantiate SignalProcessor when signals are present
191
+ if (rawSignals.length > 0) {
192
+ const evaluator = new SignalEvaluator<TContext, TData>(options.provider);
193
+ this.signalProcessor = new SignalProcessor<TContext, TData>(
194
+ rawSignals,
195
+ options.provider,
196
+ evaluator,
197
+ { batchSize: options.signalBatchSize ?? 10 },
198
+ );
199
+ } else {
200
+ this.signalProcessor = undefined;
201
+ }
202
+
94
203
  // Set log level based on debug option
95
204
  if (options.debug) {
96
205
  logger.setLevel(LoggerLevel.DEBUG);
@@ -133,10 +242,10 @@ export class Agent<TContext = any, TData = any> {
133
242
  // Initialize prompt section cache
134
243
  this._promptSectionCache = new PromptSectionCache(options.promptCache);
135
244
 
136
- // Initialize routing engine
137
- this._routingEngine = new RoutingEngine<TContext, TData>({
138
- routeSwitchMargin: options.routeSwitchMargin,
139
- onRouteSwitch: () => this.invalidateRouteSections(),
245
+ // Initialize flow router
246
+ this._routingEngine = new FlowRouter<TContext, TData>({
247
+ flowSwitchMargin: options.flowSwitchMargin,
248
+ onFlowSwitch: () => this.invalidateFlowSections(),
140
249
  promptSectionCache: this._promptSectionCache,
141
250
  });
142
251
 
@@ -184,32 +293,29 @@ export class Agent<TContext = any, TData = any> {
184
293
  });
185
294
  }
186
295
 
187
- if (options.guidelines) {
188
- options.guidelines.forEach((guideline) => {
189
- this.createGuideline(guideline);
296
+ // Initialize instructions (new unified form)
297
+ if (options.instructions) {
298
+ options.instructions.forEach((instruction) => {
299
+ this.createInstruction(instruction);
190
300
  });
191
301
  }
192
302
 
193
303
  if (options.tools) {
194
304
  options.tools.forEach((tool) => {
195
- this.createTool(tool);
305
+ this.addTool(tool);
196
306
  });
197
307
  }
198
308
 
199
- // Initialize agent-level rules and prohibitions
200
- if (options.rules) {
201
- this._rules = [...options.rules];
202
- }
203
- if (options.prohibitions) {
204
- this._prohibitions = [...options.prohibitions];
205
- }
206
-
207
- if (options.routes) {
208
- options.routes.forEach((routeOptions) => {
209
- this.createRoute(routeOptions);
309
+ if (options.flows) {
310
+ options.flows.forEach((flowOptions) => {
311
+ this.createFlow(flowOptions);
210
312
  });
211
313
  }
212
314
 
315
+ // Validate deferred branch `then` string references against the flow registry.
316
+ // This catches strings that don't match a local step id AND don't match any flow id/title.
317
+ this.validateBranchReferences();
318
+
213
319
  // Initialize knowledge base
214
320
  if (options.knowledgeBase) {
215
321
  this._knowledgeBase = { ...options.knowledgeBase };
@@ -280,6 +386,81 @@ export class Agent<TContext = any, TData = any> {
280
386
  logger.debug("[Agent] Schema validation passed");
281
387
  }
282
388
 
389
+ /**
390
+ * Walk every flow's steps and resolve deferred string `then` values in branches
391
+ * against the agent's flow registry. Strings that match neither a local step id
392
+ * nor any flow id/title throw FlowConfigurationError.
393
+ * @private
394
+ */
395
+ private validateBranchReferences(): void {
396
+ for (const flow of this._flows) {
397
+ this.validateFlowBranchReferences(flow);
398
+ }
399
+ }
400
+
401
+ /**
402
+ * Validate branch `then` string references for a single flow against the agent's
403
+ * flow registry. Throws FlowConfigurationError for unresolved references.
404
+ * @private
405
+ */
406
+ private validateFlowBranchReferences(flow: Flow<TContext, TData>): void {
407
+ const steps = flow.getAllSteps();
408
+ const localStepIds = new Set(steps.map(s => s.id));
409
+
410
+ for (const step of steps) {
411
+ if (!step.branches) continue;
412
+
413
+ for (const entry of step.branches) {
414
+ if (typeof entry.then !== 'string') continue;
415
+
416
+ // Already matches a local step id — no deferred resolution needed
417
+ if (localStepIds.has(entry.then)) continue;
418
+
419
+ // Check against the agent's flow registry (id or title)
420
+ const matchesFlow = this._flows.some(
421
+ f => f.id === entry.then || f.title === entry.then
422
+ );
423
+
424
+ if (!matchesFlow) {
425
+ throw new StepFlowConfigurationError(
426
+ `[FlowConfigurationError] Unresolved branch target: "${entry.then}" in ${flow.id}.${step.id} does not match any step in the flow or any flow in the agent. ` +
427
+ `Fix the branch "then" value to reference a valid step id or flow id/title.`
428
+ );
429
+ }
430
+ }
431
+ }
432
+ }
433
+
434
+ /**
435
+ * Validate that every step's `collect` fields in a flow reference valid keys
436
+ * from the agent-level schema. Throws FlowConfigurationError at construction
437
+ * time if any collect field is not a valid schema key.
438
+ *
439
+ * This enforces Requirement 14.5: generic inference is preserved AND every
440
+ * `collect` field reference is a valid key of the inferred TData.
441
+ * @private
442
+ */
443
+ private validateFlowCollectFields(flow: Flow<TContext, TData>): void {
444
+ const schemaKeys = Object.keys(this._schema!.properties!);
445
+ const schemaKeySet = new Set(schemaKeys);
446
+ const steps = flow.getAllSteps();
447
+
448
+ for (const step of steps) {
449
+ if (!step.collect || step.collect.length === 0) continue;
450
+
451
+ const invalidFields = step.collect.filter(
452
+ field => !schemaKeySet.has(String(field))
453
+ );
454
+
455
+ if (invalidFields.length > 0) {
456
+ throw new StepFlowConfigurationError(
457
+ `[FlowConfigurationError] Step "${step.id}" in flow "${flow.title}" references invalid collect fields: ${invalidFields.map(f => String(f)).join(', ')}. ` +
458
+ `Must be valid keys from agent schema. Available fields: ${schemaKeys.join(', ')}.`
459
+ );
460
+ }
461
+ }
462
+ }
463
+
283
464
  /**
284
465
  * Validate data against the agent-level schema
285
466
  */
@@ -358,7 +539,7 @@ export class Agent<TContext = any, TData = any> {
358
539
  const validation = this.validateData(updates);
359
540
  if (!validation.valid) {
360
541
  const errorMessages = validation.errors.map(e => e.message).join(', ');
361
- throw new DataValidationError(validation.errors, `Data validation failed: ${errorMessages}`);
542
+ throw new DataValidationError(validation.errors, `[DataValidationError] Data validation failed: fields [${errorMessages}] did not pass schema validation. Fix the offending values to match the declared schema.`);
362
543
  }
363
544
 
364
545
  // Log warnings if any
@@ -416,17 +597,17 @@ export class Agent<TContext = any, TData = any> {
416
597
  }
417
598
 
418
599
  /**
419
- * Get agent description
600
+ * Get agent persona
420
601
  */
421
- get description(): string | undefined {
422
- return this.options.description;
602
+ get persona(): Template<TContext> | undefined {
603
+ return this.options.persona;
423
604
  }
424
605
 
425
606
  /**
426
- * Set agent description
607
+ * Set agent persona
427
608
  */
428
- set description(value: string | undefined) {
429
- this.options.description = value;
609
+ set persona(value: Template<TContext> | undefined) {
610
+ this.options.persona = value;
430
611
  }
431
612
 
432
613
  /**
@@ -443,34 +624,6 @@ export class Agent<TContext = any, TData = any> {
443
624
  this.options.goal = value;
444
625
  }
445
626
 
446
- /**
447
- * Get agent identity
448
- */
449
- get identity(): Template<TContext> | undefined {
450
- return this.options.identity;
451
- }
452
-
453
- /**
454
- * Set agent identity
455
- */
456
- set identity(value: Template<TContext> | undefined) {
457
- this.options.identity = value;
458
- }
459
-
460
- /**
461
- * Get agent personality
462
- */
463
- get personality(): Template<TContext> | undefined {
464
- return this.options.personality;
465
- }
466
-
467
- /**
468
- * Set agent personality
469
- */
470
- set personality(value: Template<TContext> | undefined) {
471
- this.options.personality = value;
472
- }
473
-
474
627
  /**
475
628
  * Get whether debug mode is enabled
476
629
  */
@@ -501,32 +654,18 @@ export class Agent<TContext = any, TData = any> {
501
654
  }
502
655
 
503
656
  /**
504
- * Get the composition mode
505
- */
506
- get compositionMode(): CompositionMode {
507
- return this.options.compositionMode ?? CompositionMode.FLUID;
508
- }
509
-
510
- /**
511
- * Set the composition mode
512
- */
513
- set compositionMode(value: CompositionMode) {
514
- this.options.compositionMode = value;
515
- }
516
-
517
- /**
518
- * Get the route switch margin
657
+ * Get the flow switch margin
519
658
  * @default 15
520
659
  */
521
- get routeSwitchMargin(): number {
522
- return this.options.routeSwitchMargin ?? 15;
660
+ get flowSwitchMargin(): number {
661
+ return this.options.flowSwitchMargin ?? 15;
523
662
  }
524
663
 
525
664
  /**
526
- * Set the route switch margin
665
+ * Set the flow switch margin
527
666
  */
528
- set routeSwitchMargin(value: number) {
529
- this.options.routeSwitchMargin = value;
667
+ set flowSwitchMargin(value: number) {
668
+ this.options.flowSwitchMargin = value;
530
669
  }
531
670
 
532
671
  /**
@@ -536,21 +675,6 @@ export class Agent<TContext = any, TData = any> {
536
675
  return this._promptSectionCache;
537
676
  }
538
677
 
539
- /**
540
- * Get the maximum steps per batch
541
- * @default 1
542
- */
543
- get maxStepsPerBatch(): number {
544
- return this.options.maxStepsPerBatch ?? 1;
545
- }
546
-
547
- /**
548
- * Set the maximum steps per batch
549
- */
550
- set maxStepsPerBatch(value: number) {
551
- this.options.maxStepsPerBatch = value;
552
- }
553
-
554
678
  /**
555
679
  * Get all terms
556
680
  */
@@ -559,10 +683,10 @@ export class Agent<TContext = any, TData = any> {
559
683
  }
560
684
 
561
685
  /**
562
- * Get all guidelines
686
+ * Get all instructions
563
687
  */
564
- get guidelines(): Guideline<TContext, TData>[] {
565
- return [...this._guidelines];
688
+ get instructions(): Instruction<TContext, TData>[] {
689
+ return [...this._instructions];
566
690
  }
567
691
 
568
692
  /**
@@ -573,38 +697,10 @@ export class Agent<TContext = any, TData = any> {
573
697
  }
574
698
 
575
699
  /**
576
- * Get all routes
700
+ * Get all flows
577
701
  */
578
- get routes(): Route<TContext, TData>[] {
579
- return [...this._routes];
580
- }
581
-
582
- /**
583
- * Get agent-level rules
584
- */
585
- get rules(): Template<TContext, TData>[] {
586
- return [...this._rules];
587
- }
588
-
589
- /**
590
- * Set agent-level rules
591
- */
592
- set rules(value: Template<TContext, TData>[]) {
593
- this._rules = [...value];
594
- }
595
-
596
- /**
597
- * Get agent-level prohibitions
598
- */
599
- get prohibitions(): Template<TContext, TData>[] {
600
- return [...this._prohibitions];
601
- }
602
-
603
- /**
604
- * Set agent-level prohibitions
605
- */
606
- set prohibitions(value: Template<TContext, TData>[]) {
607
- this._prohibitions = [...value];
702
+ get flows(): Flow<TContext, TData>[] {
703
+ return [...this._flows];
608
704
  }
609
705
 
610
706
  /**
@@ -624,6 +720,14 @@ export class Agent<TContext = any, TData = any> {
624
720
  this._schema = value;
625
721
  }
626
722
 
723
+ /**
724
+ * Get the configured signals.
725
+ */
726
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
727
+ get signals(): Signal<TContext, TData, any>[] {
728
+ return this._signals;
729
+ }
730
+
627
731
  /**
628
732
  * Get the agent's knowledge base
629
733
  */
@@ -654,13 +758,15 @@ export class Agent<TContext = any, TData = any> {
654
758
  this._promptSectionCache.invalidateAll();
655
759
  }
656
760
 
657
- // ---------------------------------------------------------------------------
658
- // Deprecated method-based accessors (for backward compatibility)
659
- // ---------------------------------------------------------------------------
761
+ /**
762
+ * Get all flows
763
+ */
764
+ getFlows(): Flow<TContext, TData>[] {
765
+ return this.flows;
766
+ }
660
767
 
661
768
  /**
662
769
  * Get all terms
663
- * @deprecated Use `agent.terms` instead
664
770
  */
665
771
  getTerms(): Term<TContext, TData>[] {
666
772
  return this.terms;
@@ -668,96 +774,26 @@ export class Agent<TContext = any, TData = any> {
668
774
 
669
775
  /**
670
776
  * Get all tools
671
- * @deprecated Use `agent.tools` instead
672
777
  */
673
778
  getTools(): Tool<TContext, TData>[] {
674
779
  return this.tools;
675
780
  }
676
781
 
677
782
  /**
678
- * Get all guidelines
679
- * @deprecated Use `agent.guidelines` instead
680
- */
681
- getGuidelines(): Guideline<TContext, TData>[] {
682
- return this.guidelines;
683
- }
684
-
685
- /**
686
- * Get all routes
687
- * @deprecated Use `agent.routes` instead
688
- */
689
- getRoutes(): Route<TContext, TData>[] {
690
- return this.routes;
691
- }
692
-
693
- /**
694
- * Get agent-level rules
695
- * @deprecated Use `agent.rules` instead
696
- */
697
- getRules(): Template<TContext, TData>[] {
698
- return this.rules;
699
- }
700
-
701
- /**
702
- * Get agent-level prohibitions
703
- * @deprecated Use `agent.prohibitions` instead
704
- */
705
- getProhibitions(): Template<TContext, TData>[] {
706
- return this.prohibitions;
707
- }
708
-
709
- /**
710
- * Get current schema
711
- * @deprecated Use `agent.schema` instead
712
- */
713
- getSchema(): StructuredSchema | undefined {
714
- return this.schema;
715
- }
716
-
717
- /**
718
- * Get the agent's knowledge base
719
- * @deprecated Use `agent.knowledgeBase` instead
783
+ * Get all instructions
720
784
  */
721
- getKnowledgeBase(): Record<string, unknown> {
722
- return this.knowledgeBase;
785
+ getInstructions(): Instruction<TContext, TData>[] {
786
+ return this.instructions;
723
787
  }
724
788
 
725
789
  /**
726
- * Get the current session (if set)
727
- * @deprecated Use `agent.currentSession` instead
790
+ * Invalidate flow-dependent prompt cache sections.
791
+ * Called automatically when the active flow changes.
728
792
  */
729
- getCurrentSession(): SessionState | undefined {
730
- return this.currentSession;
731
- }
732
-
733
- /**
734
- * Set the current session for convenience methods
735
- * @deprecated Use `agent.currentSession = session` instead
736
- * @param session - Session step to use for subsequent calls
737
- */
738
- setCurrentSession(session: SessionState): void {
739
- this.currentSession = session;
740
- this._promptSectionCache.invalidateAll();
741
- }
742
-
743
- /**
744
- * Clear the current session
745
- * @deprecated Use `agent.currentSession = undefined` instead
746
- */
747
- clearCurrentSession(): void {
748
- this._currentSession = undefined;
749
- this._promptSectionCache.invalidateAll();
750
- }
751
-
752
- /**
753
- * Invalidate route-dependent prompt cache sections.
754
- * Called automatically when the active route changes.
755
- */
756
- invalidateRouteSections(): void {
757
- this._promptSectionCache.invalidate('activeRoutes');
758
- this._promptSectionCache.invalidate('routeRules');
759
- this._promptSectionCache.invalidate('routeProhibitions');
760
- this._promptSectionCache.invalidate('routeKnowledgeBase');
793
+ invalidateFlowSections(): void {
794
+ this._promptSectionCache.invalidate('activeFlows');
795
+ this._promptSectionCache.invalidate('flowKnowledgeBase');
796
+ this._promptSectionCache.invalidate('instructionsFlow');
761
797
  }
762
798
 
763
799
  /**
@@ -786,22 +822,22 @@ export class Agent<TContext = any, TData = any> {
786
822
  // ---------------------------------------------------------------------------
787
823
 
788
824
  /**
789
- * Create a new route (journey) using agent-level data type
825
+ * Create a new flow (journey) using agent-level data type
790
826
  */
791
- createRoute(
792
- options: RouteOptions<TContext, TData>
793
- ): Route<TContext, TData> {
827
+ createFlow(
828
+ options: FlowOptions<TContext, TData>
829
+ ): Flow<TContext, TData> {
794
830
  // Validate that requiredFields exist in agent schema
795
831
  if (options.requiredFields && this._schema?.properties) {
796
832
  const invalidRequiredFields = options.requiredFields.filter(
797
833
  field => !(String(field) in this._schema!.properties!)
798
834
  );
799
835
  if (invalidRequiredFields.length > 0) {
800
- throw new RouteConfigurationError(
836
+ throw new FlowConfigurationError(
801
837
  options.title,
802
838
  invalidRequiredFields.map(f => String(f)),
803
- `Invalid required fields in route '${options.title}': ${invalidRequiredFields.join(', ')}. ` +
804
- `Must be valid keys from agent schema. Available fields: ${Object.keys(this._schema.properties).join(', ')}.`
839
+ `[FlowConfigurationError] Invalid required fields in flow "${options.title}": [${invalidRequiredFields.join(', ')}] are not declared in the agent schema. ` +
840
+ `Use valid schema keys. Available fields: ${Object.keys(this._schema.properties).join(', ')}.`
805
841
  );
806
842
  }
807
843
  }
@@ -812,18 +848,24 @@ export class Agent<TContext = any, TData = any> {
812
848
  field => !(String(field) in this._schema!.properties!)
813
849
  );
814
850
  if (invalidOptionalFields.length > 0) {
815
- throw new RouteConfigurationError(
851
+ throw new FlowConfigurationError(
816
852
  options.title,
817
853
  invalidOptionalFields.map(f => String(f)),
818
- `Invalid optional fields in route '${options.title}': ${invalidOptionalFields.join(', ')}. ` +
819
- `Must be valid keys from agent schema. Available fields: ${Object.keys(this._schema.properties).join(', ')}.`
854
+ `[FlowConfigurationError] Invalid optional fields in flow "${options.title}": [${invalidOptionalFields.join(', ')}] are not declared in the agent schema. ` +
855
+ `Use valid schema keys. Available fields: ${Object.keys(this._schema.properties).join(', ')}.`
820
856
  );
821
857
  }
822
858
  }
823
859
 
824
- const route = new Route<TContext, TData>(options, this);
825
- this._routes.push(route);
826
- return route;
860
+ const flow = new Flow<TContext, TData>(options, this);
861
+
862
+ // Validate that step collect fields reference valid schema keys
863
+ if (this._schema?.properties) {
864
+ this.validateFlowCollectFields(flow);
865
+ }
866
+
867
+ this._flows.push(flow);
868
+ return flow;
827
869
  }
828
870
 
829
871
  /**
@@ -835,21 +877,23 @@ export class Agent<TContext = any, TData = any> {
835
877
  }
836
878
 
837
879
  /**
838
- * Create a behavioral guideline
880
+ * Create an instruction (unified behavioral primitive).
839
881
  */
840
- createGuideline(guideline: Guideline<TContext, TData>): this {
841
- const guidelineWithId = {
842
- ...guideline,
843
- id: guideline.id || `guideline_${this._guidelines.length}`,
844
- enabled: guideline.enabled !== false, // Default to true
882
+ createInstruction(instruction: Instruction<TContext, TData>): this {
883
+ const instructionWithId = {
884
+ ...instruction,
885
+ kind: instruction.kind || 'should' as const,
886
+ id: instruction.id || `instruction_${this._instructions.length}`,
887
+ enabled: instruction.enabled !== false, // Default to true
845
888
  };
846
- this._guidelines.push(guidelineWithId);
889
+ this._instructions.push(instructionWithId);
890
+ this._promptSectionCache.invalidate('instructionsGlobal');
847
891
  return this;
848
892
  }
849
893
 
850
894
  /**
851
895
  * Add a tool to the agent using the unified Tool interface
852
- * Creates and adds the tool to agent scope in one operation (BREAKING CHANGE: replaces createTool)
896
+ * Creates and adds the tool to agent scope in one operation
853
897
  */
854
898
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
855
899
  addTool<TResult = any>(
@@ -866,22 +910,6 @@ export class Agent<TContext = any, TData = any> {
866
910
  return this;
867
911
  }
868
912
 
869
- /**
870
- * Register a tool at the agent level (legacy method for backward compatibility)
871
- * @deprecated Use addTool() with Tool interface instead
872
- */
873
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
874
- createTool<TResult = any>(tool: Tool<TContext, TData, TResult>): this {
875
- // Validate tool before adding
876
- if (!tool || !tool.id || !tool.handler) {
877
- throw new Error('Invalid tool: must have id and handler properties');
878
- }
879
-
880
- this._tools.push(tool);
881
- logger.debug(`[Agent] Created tool (legacy): ${tool.id}`);
882
- return this;
883
- }
884
-
885
913
  /**
886
914
  * Register multiple tools at the agent level
887
915
  */
@@ -900,7 +928,7 @@ export class Agent<TContext = any, TData = any> {
900
928
 
901
929
  /**
902
930
  * Update the agent's context
903
- * Triggers both agent-level and route-specific onContextUpdate lifecycle hooks if configured
931
+ * Triggers both agent-level and flow-specific onContextUpdate lifecycle hooks if configured
904
932
  */
905
933
  async updateContext(updates: Partial<TContext>): Promise<void> {
906
934
  const previousContext = this._context;
@@ -911,16 +939,16 @@ export class Agent<TContext = any, TData = any> {
911
939
  ...(updates as Record<string, unknown>),
912
940
  } as TContext;
913
941
 
914
- // Trigger route-specific lifecycle hook if configured and session has current route
915
- if (this._currentSession?.currentRoute) {
916
- const currentRoute = this._routes.find(
917
- (r) => r.id === this._currentSession!.currentRoute?.id
942
+ // Trigger flow-specific lifecycle hook if configured and session has current flow
943
+ if (this._currentSession?.currentFlow) {
944
+ const currentFlow = this._flows.find(
945
+ (r) => r.id === this._currentSession!.currentFlow?.id
918
946
  );
919
947
  if (
920
- currentRoute?.hooks?.onContextUpdate &&
948
+ currentFlow?.hooks?.onContextUpdate &&
921
949
  previousContext !== undefined
922
950
  ) {
923
- await currentRoute.handleContextUpdate(this._context, previousContext);
951
+ await currentFlow.handleContextUpdate(this._context, previousContext);
924
952
  }
925
953
  }
926
954
 
@@ -932,11 +960,12 @@ export class Agent<TContext = any, TData = any> {
932
960
  // Invalidate context-dependent prompt cache sections
933
961
  this._promptSectionCache.invalidate('agentMeta');
934
962
  this._promptSectionCache.invalidate('knowledgeBase');
963
+ this._promptSectionCache.invalidate('instructionsGlobal');
935
964
  }
936
965
 
937
966
  /**
938
967
  * Update collected data in session with lifecycle hook support
939
- * Triggers both agent-level and route-specific onDataUpdate lifecycle hooks if configured
968
+ * Triggers both agent-level and flow-specific onDataUpdate lifecycle hooks if configured
940
969
  * @internal
941
970
  */
942
971
  private async updateData(
@@ -951,13 +980,13 @@ export class Agent<TContext = any, TData = any> {
951
980
  ...dataUpdate,
952
981
  };
953
982
 
954
- // Trigger route-specific lifecycle hook if configured and session has a current route
955
- if (session.currentRoute) {
956
- const currentRoute = this._routes.find(
957
- (r) => r.id === session.currentRoute?.id
983
+ // Trigger flow-specific lifecycle hook if configured and session has a current flow
984
+ if (session.currentFlow) {
985
+ const currentFlow = this._flows.find(
986
+ (r) => r.id === session.currentFlow?.id
958
987
  );
959
- if (currentRoute?.hooks?.onDataUpdate) {
960
- newCollected = await currentRoute.handleDataUpdate(
988
+ if (currentFlow?.hooks?.onDataUpdate) {
989
+ newCollected = await currentFlow.handleDataUpdate(
961
990
  newCollected,
962
991
  previousCollected
963
992
  );
@@ -1017,10 +1046,10 @@ export class Agent<TContext = any, TData = any> {
1017
1046
  }
1018
1047
 
1019
1048
  /**
1020
- * Get routing engine
1049
+ * Get flow router
1021
1050
  * @internal Used by ResponseModal
1022
1051
  */
1023
- getRoutingEngine(): RoutingEngine<TContext, TData> {
1052
+ getFlowRouter(): FlowRouter<TContext, TData> {
1024
1053
  return this._routingEngine;
1025
1054
  }
1026
1055
 
@@ -1032,55 +1061,6 @@ export class Agent<TContext = any, TData = any> {
1032
1061
  return this.updateData.bind(this);
1033
1062
  }
1034
1063
 
1035
- /**
1036
- * Evaluate and match active guidelines based on their conditions
1037
- * Returns guidelines that should be active given the current context
1038
- */
1039
- async evaluateGuidelines(
1040
- context?: TContext,
1041
- session?: SessionState<TData>,
1042
- history?: Event[]
1043
- ): Promise<GuidelineMatch<TContext, TData>[]> {
1044
- const templateContext = { context, session, history, data: session?.data };
1045
- const evaluator = createConditionEvaluator(templateContext);
1046
- const matches: GuidelineMatch<TContext, TData>[] = [];
1047
-
1048
- for (const guideline of this._guidelines) {
1049
- // Skip disabled guidelines
1050
- if (guideline.enabled === false) {
1051
- continue;
1052
- }
1053
-
1054
- if (guideline.condition) {
1055
- const evaluation = await evaluator.evaluateCondition(guideline.condition, 'AND');
1056
-
1057
- // Include guideline if:
1058
- // 1. No programmatic conditions (only strings) - always active
1059
- // 2. Programmatic conditions evaluate to true
1060
- if (!evaluation.hasProgrammaticConditions || evaluation.programmaticResult) {
1061
- const rationale = evaluation.aiContextStrings.length > 0
1062
- ? `Condition met: ${evaluation.aiContextStrings.join(" AND ")}`
1063
- : evaluation.hasProgrammaticConditions
1064
- ? "Programmatic condition evaluated to true"
1065
- : "Always active (no conditions)";
1066
-
1067
- matches.push({
1068
- guideline,
1069
- rationale
1070
- });
1071
- }
1072
- } else {
1073
- // No condition means always active
1074
- matches.push({
1075
- guideline,
1076
- rationale: "Always active (no conditions)"
1077
- });
1078
- }
1079
- }
1080
-
1081
- return matches;
1082
- }
1083
-
1084
1064
  /**
1085
1065
  * Execute a prepare or finalize function/tool
1086
1066
  * @internal Used by ResponseModal
@@ -1093,7 +1073,7 @@ export class Agent<TContext = any, TData = any> {
1093
1073
  | undefined,
1094
1074
  context: TContext,
1095
1075
  data?: Partial<TData>,
1096
- route?: Route<TContext, TData>,
1076
+ flow?: Flow<TContext, TData>,
1097
1077
  step?: Step<TContext, TData>
1098
1078
  ): Promise<void> {
1099
1079
  if (!prepareOrFinalize) return;
@@ -1107,7 +1087,7 @@ export class Agent<TContext = any, TData = any> {
1107
1087
 
1108
1088
  if (typeof prepareOrFinalize === "string") {
1109
1089
  // Tool ID - use ToolManager to find it across all scopes
1110
- tool = this.tool.find(prepareOrFinalize, undefined, step, route);
1090
+ tool = this.tool.find(prepareOrFinalize, undefined, step, flow);
1111
1091
  } else {
1112
1092
  // Tool object - validate it has required properties
1113
1093
  if (prepareOrFinalize.id && typeof prepareOrFinalize.handler === 'function') {
@@ -1160,7 +1140,6 @@ export class Agent<TContext = any, TData = any> {
1160
1140
 
1161
1141
  /**
1162
1142
  * Get collected data from current session or agent-level collected data
1163
- * @param routeId - Optional route ID to get data for (uses current route if not provided)
1164
1143
  * @returns The collected data from the current session or agent-level data
1165
1144
  */
1166
1145
  getData(): Partial<TData> {
@@ -1169,8 +1148,8 @@ export class Agent<TContext = any, TData = any> {
1169
1148
 
1170
1149
  // If we have a current session, use session data
1171
1150
  if (this._currentSession) {
1172
- // With agent-level data, all routes share the same data structure
1173
- // No need for route-specific data access
1151
+ // With agent-level data, all flows share the same data structure
1152
+ // No need for flow-specific data access
1174
1153
  return (this._currentSession.data) || {};
1175
1154
  }
1176
1155
 
@@ -1179,77 +1158,309 @@ export class Agent<TContext = any, TData = any> {
1179
1158
  }
1180
1159
 
1181
1160
  /**
1182
- * Manually transition to a different route
1183
- * Sets a pending transition that will be executed on the next respond() call
1161
+ * Dispatch a directive (or a flow shorthand) into a session.
1162
+ * Sets `pendingDirective` on the session without triggering a `respond()` call.
1163
+ * The directive will be applied at the start of the next turn.
1164
+ *
1165
+ * String form desugars to `{ goTo: target }`.
1166
+ *
1167
+ * @param target - Flow ID/title string (desugars to `{ goTo: target }`) or a full Directive
1168
+ * @param session - Session to update (uses current session if not provided)
1169
+ * @returns Updated session with `pendingDirective` set
1184
1170
  *
1185
- * @param routeIdOrTitle - Route ID or title to transition to
1186
- * @param session - Session step to update (uses current session if not provided)
1187
- * @param condition - Optional AI-evaluated condition for the transition
1188
- * @returns Updated session with pending transition
1171
+ * @throws FlowConfigurationError if the string target doesn't match any flow
1172
+ * @throws FlowConfigurationError if the directive fails validation
1189
1173
  *
1190
1174
  * @example
1191
- * // After route completes
1192
- * if (response.isRouteComplete && response.session) {
1193
- * const updatedSession = agent.nextStepRoute("feedback-collection", response.session);
1194
- * // Next respond() call will automatically transition to feedback route
1195
- * const nextResponse = await agent.respond({ history, session: updatedSession });
1196
- * }
1175
+ * // String shorthand — desugars to { goTo: 'Feedback' }
1176
+ * const updated = await agent.dispatch('Feedback', session);
1177
+ *
1178
+ * @example
1179
+ * // Full directive
1180
+ * const updated = await agent.dispatch({ goTo: 'Billing', reply: 'Transferring you now.' }, session);
1197
1181
  */
1198
- async nextStepRoute(
1199
- routeIdOrTitle: string,
1200
- session?: SessionState<TData>,
1201
- condition?: Template<TContext, TData>,
1202
- history?: Event[]
1182
+ // eslint-disable-next-line @typescript-eslint/require-await
1183
+ async dispatch(
1184
+ target: string | Directive<TContext, TData>,
1185
+ session?: SessionState<TData>
1203
1186
  ): Promise<SessionState<TData>> {
1204
1187
  const targetSession = session || this._currentSession;
1205
1188
 
1206
1189
  if (!targetSession) {
1207
1190
  throw new Error(
1208
- "No session provided and no current session available. Please provide a session to transition."
1191
+ "No session provided and no current session available. Please provide a session to dispatch into."
1209
1192
  );
1210
1193
  }
1211
1194
 
1212
- // Find target route by ID or title
1213
- const targetRoute = this._routes.find(
1214
- (r) => r.id === routeIdOrTitle || r.title === routeIdOrTitle
1215
- );
1195
+ // Desugar string form to { goTo: target }
1196
+ const directive: Directive<TContext, TData> = typeof target === 'string'
1197
+ ? { goTo: target }
1198
+ : target;
1216
1199
 
1217
- if (!targetRoute) {
1218
- throw new Error(
1219
- `Route not found: ${routeIdOrTitle}. Available routes: ${this._routes
1220
- .map((r) => r.title)
1221
- .join(", ")}`
1200
+ // Validate the directive: check for multiple position fields, empty goTo, etc.
1201
+ this.validateDirective(directive);
1202
+
1203
+ // If goTo is a string, validate it references a known flow
1204
+ if (typeof directive.goTo === 'string') {
1205
+ const flowTarget = directive.goTo;
1206
+ const matchesFlow = this._flows.some(
1207
+ f => f.id === flowTarget || f.title === flowTarget
1222
1208
  );
1209
+ if (!matchesFlow) {
1210
+ throw new StepFlowConfigurationError(
1211
+ `[FlowConfigurationError] Unknown flow: "${flowTarget}" does not match any flow id or title. ` +
1212
+ `Available flows: ${this._flows.map(f => f.title).join(', ')}.`
1213
+ );
1214
+ }
1215
+ } else if (directive.goTo && typeof directive.goTo === 'object' && directive.goTo.flow) {
1216
+ const flowTarget = directive.goTo.flow;
1217
+ const matchesFlow = this._flows.some(
1218
+ f => f.id === flowTarget || f.title === flowTarget
1219
+ );
1220
+ if (!matchesFlow) {
1221
+ throw new StepFlowConfigurationError(
1222
+ `[FlowConfigurationError] Unknown flow: "${flowTarget}" does not match any flow id or title. ` +
1223
+ `Available flows: ${this._flows.map(f => f.title).join(', ')}.`
1224
+ );
1225
+ }
1223
1226
  }
1224
- const templateContext = createTemplateContext({
1225
- context: this._context,
1226
- session,
1227
- history,
1228
- data: this._currentSession?.data,
1229
- });
1230
- const renderedCondition = await render(condition, templateContext);
1231
1227
 
1228
+ // Strip PreDirective-only fields before storing
1229
+ const stripped = this.stripPreDirectiveFields(directive);
1230
+
1231
+ // Set pendingDirective on the session without applying it
1232
1232
  const updatedSession: SessionState<TData> = {
1233
1233
  ...targetSession,
1234
- pendingTransition: {
1235
- targetRouteId: targetRoute.id,
1236
- condition: renderedCondition,
1237
- reason: "route_complete",
1234
+ pendingDirective: stripped as Directive<unknown, TData>,
1235
+ metadata: {
1236
+ ...targetSession.metadata,
1237
+ lastUpdatedAt: new Date(),
1238
1238
  },
1239
1239
  };
1240
1240
 
1241
- // Update current session if using it
1241
+ // Update current session in place if no explicit session was passed
1242
1242
  if (!session && this._currentSession) {
1243
1243
  this._currentSession = updatedSession;
1244
1244
  }
1245
1245
 
1246
1246
  logger.debug(
1247
- `[Agent] Set pending transition to route: ${targetRoute.title}`
1247
+ `[Agent] Dispatched directive: pendingDirective set on session ${updatedSession.id}`
1248
1248
  );
1249
1249
 
1250
1250
  return updatedSession;
1251
1251
  }
1252
1252
 
1253
+ /**
1254
+ * Apply a directive synchronously to a session without invoking `respond()`.
1255
+ * Performs in-place application: updates flow/step position, merges state writes.
1256
+ *
1257
+ * This is the synchronous counterpart to `dispatch` — it applies immediately
1258
+ * rather than deferring to the next turn.
1259
+ *
1260
+ * @param directive - The directive to apply
1261
+ * @param session - The session to apply the directive to
1262
+ * @returns The updated session with the directive applied
1263
+ */
1264
+ applyDirective(
1265
+ directive: Directive<TContext, TData>,
1266
+ session: SessionState<TData>
1267
+ ): SessionState<TData> {
1268
+ // Validate the directive
1269
+ this.validateDirective(directive);
1270
+
1271
+ let updatedSession = { ...session };
1272
+ const now = new Date();
1273
+
1274
+ // Apply state writes
1275
+ if (directive.contextUpdate) {
1276
+ // Context updates are applied to the agent, not the session
1277
+ this._context = {
1278
+ ...(this._context as Record<string, unknown>),
1279
+ ...(directive.contextUpdate as Record<string, unknown>),
1280
+ } as TContext;
1281
+ }
1282
+
1283
+ if (directive.dataUpdate) {
1284
+ updatedSession = {
1285
+ ...updatedSession,
1286
+ data: {
1287
+ ...updatedSession.data,
1288
+ ...directive.dataUpdate,
1289
+ },
1290
+ };
1291
+ }
1292
+
1293
+ // Apply position control
1294
+ if (directive.goTo) {
1295
+ const flowTarget = typeof directive.goTo === 'string'
1296
+ ? directive.goTo
1297
+ : directive.goTo.flow;
1298
+
1299
+ if (flowTarget) {
1300
+ const targetFlow = this._flows.find(
1301
+ f => f.id === flowTarget || f.title === flowTarget
1302
+ );
1303
+ if (targetFlow) {
1304
+ // Merge goTo.data if present
1305
+ if (typeof directive.goTo === 'object' && directive.goTo.data) {
1306
+ updatedSession = {
1307
+ ...updatedSession,
1308
+ data: {
1309
+ ...updatedSession.data,
1310
+ ...directive.goTo.data,
1311
+ },
1312
+ };
1313
+ }
1314
+
1315
+ updatedSession = enterFlow(updatedSession, targetFlow.id, targetFlow.title);
1316
+
1317
+ // If a specific step is targeted
1318
+ if (typeof directive.goTo === 'object' && directive.goTo.step) {
1319
+ updatedSession = enterStep(updatedSession, directive.goTo.step);
1320
+ }
1321
+ }
1322
+ }
1323
+ } else if (directive.goToStep) {
1324
+ const stepTarget = typeof directive.goToStep === 'string'
1325
+ ? directive.goToStep
1326
+ : directive.goToStep.step;
1327
+
1328
+ // Merge goToStep.data if present
1329
+ if (typeof directive.goToStep === 'object' && directive.goToStep.data) {
1330
+ updatedSession = {
1331
+ ...updatedSession,
1332
+ data: {
1333
+ ...updatedSession.data,
1334
+ ...directive.goToStep.data,
1335
+ },
1336
+ };
1337
+ }
1338
+
1339
+ updatedSession = enterStep(updatedSession, stepTarget);
1340
+ } else if (directive.complete) {
1341
+ updatedSession = completeCurrentFlow(updatedSession);
1342
+
1343
+ // If complete carries a chained directive, set it as pendingDirective
1344
+ if (typeof directive.complete === 'object' && directive.complete.next) {
1345
+ updatedSession = {
1346
+ ...updatedSession,
1347
+ pendingDirective: directive.complete.next as Directive<unknown, TData>,
1348
+ };
1349
+ }
1350
+ } else if (directive.abort) {
1351
+ const clearSession = typeof directive.abort === 'object'
1352
+ ? directive.abort.clearSession !== false
1353
+ : true;
1354
+
1355
+ if (clearSession) {
1356
+ updatedSession = {
1357
+ ...updatedSession,
1358
+ currentFlow: undefined,
1359
+ currentStep: undefined,
1360
+ data: {} as Partial<TData>,
1361
+ };
1362
+ } else {
1363
+ updatedSession = {
1364
+ ...updatedSession,
1365
+ currentFlow: undefined,
1366
+ currentStep: undefined,
1367
+ };
1368
+ }
1369
+ } else if (directive.reset) {
1370
+ const currentFlowId = updatedSession.currentFlow?.id;
1371
+ const currentFlowTitle = updatedSession.currentFlow?.title;
1372
+
1373
+ if (currentFlowId && currentFlowTitle) {
1374
+ // Clear data if requested
1375
+ if (typeof directive.reset === 'object' && directive.reset.clearData) {
1376
+ const currentFlow = this._flows.find(f => f.id === currentFlowId);
1377
+ if (currentFlow) {
1378
+ const ownedFields = [
1379
+ ...(currentFlow.requiredFields || []),
1380
+ ...(currentFlow.optionalFields || []),
1381
+ ];
1382
+ updatedSession = completeCurrentFlow(updatedSession, { clearOwnedFields: ownedFields });
1383
+ // Re-enter the same flow
1384
+ updatedSession = enterFlow(updatedSession, currentFlowId, currentFlowTitle);
1385
+ }
1386
+ } else {
1387
+ // Re-enter the flow from the beginning (or specified step)
1388
+ updatedSession = enterFlow(updatedSession, currentFlowId, currentFlowTitle);
1389
+ }
1390
+
1391
+ // If a specific step is targeted for reset
1392
+ if (typeof directive.reset === 'object' && directive.reset.step) {
1393
+ updatedSession = enterStep(updatedSession, directive.reset.step);
1394
+ }
1395
+ }
1396
+ }
1397
+
1398
+ // Update metadata
1399
+ updatedSession = {
1400
+ ...updatedSession,
1401
+ metadata: {
1402
+ ...updatedSession.metadata,
1403
+ lastUpdatedAt: now,
1404
+ },
1405
+ };
1406
+
1407
+ return updatedSession;
1408
+ }
1409
+
1410
+ /**
1411
+ * Validate a directive for structural correctness.
1412
+ * Throws FlowConfigurationError for invalid combinations.
1413
+ * @private
1414
+ */
1415
+ private validateDirective(directive: Directive<TContext, TData>): void {
1416
+ // Check for multiple position fields
1417
+ const positionFields = ['goTo', 'goToStep', 'complete', 'abort', 'reset'] as const;
1418
+ const setPositionFields = positionFields.filter(
1419
+ field => directive[field] !== undefined
1420
+ );
1421
+
1422
+ if (setPositionFields.length > 1) {
1423
+ throw new StepFlowConfigurationError(
1424
+ `[FlowConfigurationError] Multiple position fields: a Directive may set at most one position field. ` +
1425
+ `Found: ${setPositionFields.join(', ')}. Remove all but one.`
1426
+ );
1427
+ }
1428
+
1429
+ // Check for empty goTo object
1430
+ if (directive.goTo && typeof directive.goTo === 'object') {
1431
+ const goToObj = directive.goTo;
1432
+ if (!goToObj.flow && !goToObj.step) {
1433
+ throw new StepFlowConfigurationError(
1434
+ `[FlowConfigurationError] Empty goTo: "goTo" requires at least a "flow" field. ` +
1435
+ `Provide { goTo: { flow: '<id>' } } or use the string shorthand { goTo: '<id>' }.`
1436
+ );
1437
+ }
1438
+ }
1439
+ }
1440
+
1441
+ /**
1442
+ * Strip PreDirective-only fields (appendPrompt, injectTools, halt) from a directive.
1443
+ * These fields are transient (one-turn lifetime) and must not be persisted.
1444
+ * @private
1445
+ */
1446
+ private stripPreDirectiveFields(directive: Directive<TContext, TData>): Directive<TContext, TData> {
1447
+ const raw = directive as Record<string, unknown>;
1448
+ if (!raw.appendPrompt && !raw.injectTools && raw.halt === undefined) {
1449
+ return directive;
1450
+ }
1451
+
1452
+ const { appendPrompt, injectTools, halt, ...rest } = raw;
1453
+
1454
+ if (appendPrompt || injectTools || halt !== undefined) {
1455
+ logger.debug(
1456
+ `[Agent] Stripped PreDirective-only fields before storing pendingDirective: ` +
1457
+ `${[appendPrompt && 'appendPrompt', injectTools && 'injectTools', halt !== undefined && 'halt'].filter(Boolean).join(', ')}`
1458
+ );
1459
+ }
1460
+
1461
+ return rest as Directive<TContext, TData>;
1462
+ }
1463
+
1253
1464
  /**
1254
1465
  * Simplified respond method using SessionManager
1255
1466
  * Automatically manages conversation history through the session