@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
@@ -1,15 +1,14 @@
1
1
  import { MessageRole } from "../types";
2
- import { enterRoute, mergeCollected } from "../utils";
2
+ import { enterFlow, mergeCollected, isFlowCompletedThisSession } from "../utils";
3
3
  import { PromptComposer } from "./PromptComposer";
4
- import { END_ROUTE_ID } from "../constants";
5
4
  import { createTemplateContext, getLastMessageFromHistory, logger, eventsToHistory } from "../utils";
6
- export class RoutingEngine {
5
+ export class FlowRouter {
7
6
  constructor(options) {
8
7
  this.options = options;
9
8
  }
10
9
  /**
11
10
  * Check whether the history contains any user messages.
12
- * Used to detect "session resume" scenarios where a route/step was
11
+ * Used to detect "session resume" scenarios where a flow/step was
13
12
  * pre-set programmatically and the conversation starts with only
14
13
  * system messages (or no messages at all).
15
14
  * @private
@@ -19,46 +18,46 @@ export class RoutingEngine {
19
18
  }
20
19
  /**
21
20
  * Handle the "session resume" fast-path: when a session already has a
22
- * pre-set currentRoute (and optionally currentStep) and the conversation
21
+ * pre-set currentFlow (and optionally currentStep) and the conversation
23
22
  * history contains no user messages, honor the pre-set position instead
24
- * of running AI route/step selection.
23
+ * of running AI flow/step selection.
25
24
  *
26
25
  * Returns `undefined` when the fast-path does not apply.
27
26
  * @private
28
27
  */
29
28
  async handleSessionResume(params) {
30
- const { routes, session, history, context } = params;
29
+ const { flows, session, history, context } = params;
31
30
  // Fast-path only applies when:
32
- // 1. Session already has a currentRoute set
31
+ // 1. Session already has a currentFlow set
33
32
  // 2. There are no user messages in the history (system-only or empty)
34
- if (!session.currentRoute || this.hasUserMessages(history)) {
33
+ if (!session.currentFlow || this.hasUserMessages(history)) {
35
34
  return undefined;
36
35
  }
37
- // Find the pre-set route among available routes
38
- const presetRoute = routes.find((r) => r.id === session.currentRoute.id);
39
- if (!presetRoute) {
40
- logger.warn(`[RoutingEngine] Session resume: pre-set route '${session.currentRoute.id}' not found among available routes, falling back to normal routing`);
36
+ // Find the pre-set flow among available flows
37
+ const presetFlow = flows.find((r) => r.id === session.currentFlow.id);
38
+ if (!presetFlow) {
39
+ logger.warn(`[FlowConfigurationError] Pre-set flow not found: session references flow "${session.currentFlow.id}" which does not exist among available flows. Falling back to normal routing. Remove the stale session reference or register the missing flow.`);
41
40
  return undefined;
42
41
  }
43
- logger.debug(`[RoutingEngine] Session resume: honoring pre-set route '${presetRoute.title}' (no user messages in history)`);
44
- // Enter route if needed (merges initialData, no-op if already entered)
45
- const updatedSession = this.enterRouteIfNeeded(session, presetRoute);
46
- // Evaluate cross-route completions
47
- const completedRoutes = this.evaluateRouteCompletions(routes, updatedSession.data || {});
42
+ logger.debug(`[FlowRouter] Session resume: honoring pre-set flow '${presetFlow.title}' (no user messages in history)`);
43
+ // Enter flow if needed (merges initialData, no-op if already entered)
44
+ const updatedSession = this.enterFlowIfNeeded(session, presetFlow);
45
+ // Evaluate cross-flow completions
46
+ const completedFlows = this.evaluateFlowCompletions(flows, updatedSession.data || {});
48
47
  // If a currentStep is also pre-set, honor it — stay on that step
49
48
  if (session.currentStep) {
50
- const presetStep = presetRoute.getStep(session.currentStep.id);
49
+ const presetStep = presetFlow.getStep(session.currentStep.id);
51
50
  if (presetStep) {
52
- logger.debug(`[RoutingEngine] Session resume: honoring pre-set step '${presetStep.id}'`);
51
+ logger.debug(`[FlowRouter] Session resume: honoring pre-set step '${presetStep.id}'`);
53
52
  return {
54
- selectedRoute: presetRoute,
53
+ selectedFlow: presetFlow,
55
54
  selectedStep: presetStep,
56
55
  session: updatedSession,
57
- isRouteComplete: false,
58
- completedRoutes,
56
+ isFlowComplete: false,
57
+ completedFlows,
59
58
  };
60
59
  }
61
- logger.warn(`[RoutingEngine] Session resume: pre-set step '${session.currentStep.id}' not found in route '${presetRoute.title}', resolving from initial step`);
60
+ logger.warn(`[FlowConfigurationError] Pre-set step not found: session references step "${session.currentStep.id}" which does not exist in flow "${presetFlow.title}". Resolving from initial step. Remove the stale step reference or register the missing step.`);
62
61
  }
63
62
  // No currentStep pre-set (or it wasn't found) — resolve from initialStep
64
63
  // using the standard candidate logic (handles skipIf, etc.)
@@ -68,67 +67,97 @@ export class RoutingEngine {
68
67
  history,
69
68
  data: updatedSession.data,
70
69
  });
71
- const candidates = await this.getCandidateStepsWithConditions(presetRoute, undefined, // No current step — start from beginning
70
+ const candidates = await this.getCandidateStepsWithConditions(presetFlow, undefined, // No current step — start from beginning
72
71
  templateContext);
73
72
  if (candidates.length === 0) {
74
- logger.warn(`[RoutingEngine] Session resume: no valid steps found for route '${presetRoute.title}'`);
73
+ logger.warn(`[FlowConfigurationError] No valid steps found: all steps in flow "${presetFlow.title}" are skipped by their conditions. Check skip/when conditions on the flow's steps.`);
75
74
  return {
76
- selectedRoute: presetRoute,
75
+ selectedFlow: presetFlow,
77
76
  selectedStep: undefined,
78
77
  session: updatedSession,
79
- isRouteComplete: false,
80
- completedRoutes,
78
+ isFlowComplete: false,
79
+ completedFlows,
81
80
  };
82
81
  }
83
82
  const candidate = candidates[0];
84
- if (candidate.isRouteComplete) {
85
- logger.debug(`[RoutingEngine] Session resume: route '${presetRoute.title}' is already complete`);
83
+ if (candidate.isFlowComplete) {
84
+ logger.debug(`[FlowRouter] Session resume: flow '${presetFlow.title}' is already complete`);
86
85
  return {
87
- selectedRoute: presetRoute,
86
+ selectedFlow: presetFlow,
88
87
  selectedStep: undefined,
89
88
  session: updatedSession,
90
- isRouteComplete: true,
91
- completedRoutes,
89
+ isFlowComplete: true,
90
+ completedFlows,
92
91
  };
93
92
  }
94
- logger.debug(`[RoutingEngine] Session resume: resolved initial step '${candidate.step.id}'`);
93
+ logger.debug(`[FlowRouter] Session resume: resolved initial step '${candidate.step.id}'`);
95
94
  return {
96
- selectedRoute: presetRoute,
95
+ selectedFlow: presetFlow,
97
96
  selectedStep: candidate.step,
98
97
  session: updatedSession,
99
- isRouteComplete: false,
100
- completedRoutes,
98
+ isFlowComplete: false,
99
+ completedFlows,
101
100
  };
102
101
  }
103
102
  /**
104
- * Enter a route if not already in it, merging initial data
103
+ * Enter a flow if not already in it, merging initial data.
104
+ *
105
+ * When the flow is `reentrant` and was previously completed in this
106
+ * session, clears every field declared in the flow's `requiredFields`
107
+ * and `optionalFields` before entering — so the flow starts fresh from
108
+ * its initial step instead of being instantly marked complete by stale
109
+ * data. Fields not owned by this flow are preserved.
110
+ *
105
111
  * @private
106
112
  */
107
- enterRouteIfNeeded(session, route) {
108
- if (!session.currentRoute || session.currentRoute.id !== route.id) {
109
- let updatedSession = enterRoute(session, route.id, route.title);
113
+ enterFlowIfNeeded(session, route) {
114
+ if (!session.currentFlow || session.currentFlow.id !== route.id) {
115
+ let workingSession = session;
116
+ // Re-entry into a `reentrant` flow that previously completed:
117
+ // clear owned fields so completion logic doesn't short-circuit on
118
+ // stale data from the prior run.
119
+ const previouslyCompleted = isFlowCompletedThisSession(session, route.id);
120
+ if (previouslyCompleted && route.reentrant) {
121
+ const ownedFields = [
122
+ ...(route.requiredFields ?? []),
123
+ ...(route.optionalFields ?? []),
124
+ ];
125
+ if (ownedFields.length > 0) {
126
+ const owned = new Set(ownedFields);
127
+ const filtered = {};
128
+ for (const key of Object.keys(session.data ?? {})) {
129
+ if (!owned.has(key)) {
130
+ filtered[key] =
131
+ session.data[key];
132
+ }
133
+ }
134
+ workingSession = { ...session, data: filtered };
135
+ logger.debug(`[FlowRouter] Re-entering reentrant flow ${route.title}: cleared ${ownedFields.length} owned field(s)`);
136
+ }
137
+ }
138
+ let updatedSession = enterFlow(workingSession, route.id, route.title);
110
139
  if (route.initialData) {
111
140
  updatedSession = mergeCollected(updatedSession, route.initialData);
112
- logger.debug(`[RoutingEngine] Merged initial data for route ${route.title}:`, route.initialData);
141
+ logger.debug(`[FlowRouter] Merged initial data for flow ${route.title}:`, route.initialData);
113
142
  }
114
- logger.debug(`[RoutingEngine] Entered route: ${route.title}`);
115
- this.options?.onRouteSwitch?.();
143
+ logger.debug(`[FlowRouter] Entered flow: ${route.title}`);
144
+ this.options?.onFlowSwitch?.();
116
145
  return updatedSession;
117
146
  }
118
147
  return session;
119
148
  }
120
149
  /**
121
- * Optimized decision for single-route scenarios
122
- * Skips route scoring and only does step selection
150
+ * Optimized decision for single-flow scenarios
151
+ * Skips flow scoring and only does step selection
123
152
  * @private
124
153
  */
125
- async decideSingleRouteStep(params) {
154
+ async decideSingleFlowStep(params) {
126
155
  const { route, session, history, agentOptions, provider, context, signal } = params;
127
- const selectedRoute = route;
128
- // Enter route if not already in it (this may merge initial data)
129
- const updatedSession = this.enterRouteIfNeeded(session, route);
130
- // Check if this single route is complete (use updated session data)
131
- const completedRoutes = route.isComplete(updatedSession.data || {}) ? [route] : [];
156
+ const selectedFlow = route;
157
+ // Enter flow if not already in it (this may merge initial data)
158
+ const updatedSession = this.enterFlowIfNeeded(session, route);
159
+ // Check if this single flow is complete (use updated session data)
160
+ const completedFlows = route.isComplete(updatedSession.data || {}) ? [route] : [];
132
161
  // Get candidate steps using new condition evaluation
133
162
  const templateContext = createTemplateContext({
134
163
  context,
@@ -141,44 +170,43 @@ export class RoutingEngine {
141
170
  : undefined;
142
171
  const candidates = await this.getCandidateStepsWithConditions(route, currentStep, templateContext);
143
172
  if (candidates.length === 0) {
144
- logger.warn(`[RoutingEngine] Single-route: No valid steps found`);
145
- return { selectedRoute, session: updatedSession };
173
+ logger.warn(`[FlowConfigurationError] No valid steps found: all candidates in the single-flow agent are skipped. Check step skip/when conditions.`);
174
+ return { selectedFlow, session: updatedSession };
146
175
  }
147
176
  // If only one candidate, check if it's a completion marker
148
177
  if (candidates.length === 1) {
149
178
  const candidate = candidates[0];
150
- if (candidate.isRouteComplete) {
151
- logger.debug(`[RoutingEngine] Single-route: Route complete - all required fields collected or END_ROUTE reached`);
152
- // Don't return a selectedStep when route is complete - there's no step to enter
179
+ if (candidate.isFlowComplete) {
180
+ logger.debug(`[FlowRouter] Single-flow: Flow complete - all required fields collected or last step reached`);
181
+ // Don't return a selectedStep when flow is complete - there's no step to enter
153
182
  return {
154
- selectedRoute,
183
+ selectedFlow,
155
184
  selectedStep: undefined,
156
185
  session: updatedSession,
157
- isRouteComplete: true,
158
- completedRoutes,
186
+ isFlowComplete: true,
187
+ completedFlows,
159
188
  };
160
189
  }
161
190
  else {
162
- logger.debug(`[RoutingEngine] Single-route: Only one valid step: ${candidate.step.id}`);
191
+ logger.debug(`[FlowRouter] Single-flow: Only one valid step: ${candidate.step.id}`);
163
192
  return {
164
- selectedRoute,
193
+ selectedFlow,
165
194
  selectedStep: candidate.step,
166
195
  session: updatedSession,
167
- isRouteComplete: false,
168
- completedRoutes,
196
+ isFlowComplete: false,
197
+ completedFlows,
169
198
  };
170
199
  }
171
200
  }
172
- // No candidates means route has no valid next steps (edge case)
173
- // Don't mark as complete based on data alone — only END_ROUTE completes a route
201
+ // No candidates means flow has no valid next steps (edge case)
174
202
  if (candidates.length === 0) {
175
- logger.debug(`[RoutingEngine] Single-route: No valid candidate steps found`);
203
+ logger.debug(`[FlowRouter] Single-flow: No valid candidate steps found`);
176
204
  return {
177
- selectedRoute,
205
+ selectedFlow,
178
206
  selectedStep: undefined,
179
207
  session: updatedSession,
180
- isRouteComplete: false,
181
- completedRoutes,
208
+ isFlowComplete: false,
209
+ completedFlows,
182
210
  };
183
211
  }
184
212
  // Multiple candidates - use AI to select best step
@@ -189,10 +217,10 @@ export class RoutingEngine {
189
217
  const whenResult = await candidate.step.evaluateWhen(templateContext);
190
218
  stepConditionContext.push(...whenResult.aiContextStrings);
191
219
  }
192
- // Check if any candidate is a completion marker (isRouteComplete = true)
193
- const hasCompletionOption = candidates.some(c => c.isRouteComplete);
220
+ // Check if any candidate is a completion marker (isFlowComplete = true)
221
+ const hasCompletionOption = candidates.some(c => c.isFlowComplete);
194
222
  const stepPrompt = await this.buildStepSelectionPrompt({
195
- route,
223
+ flow: route,
196
224
  currentStep,
197
225
  candidates,
198
226
  data: updatedSession.data || {},
@@ -202,9 +230,9 @@ export class RoutingEngine {
202
230
  context,
203
231
  session: updatedSession,
204
232
  stepConditionContext,
205
- includeEndRoute: hasCompletionOption,
233
+ includeCompletion: hasCompletionOption,
206
234
  });
207
- const stepSchema = this.buildStepSelectionSchema(candidates.filter(c => !c.isRouteComplete).map((c) => c.step), hasCompletionOption);
235
+ const stepSchema = this.buildStepSelectionSchema(candidates.filter(c => !c.isFlowComplete).map((c) => c.step), hasCompletionOption);
208
236
  const stepResult = await provider.generateMessage({
209
237
  prompt: stepPrompt,
210
238
  history: eventsToHistory(history),
@@ -216,37 +244,37 @@ export class RoutingEngine {
216
244
  },
217
245
  });
218
246
  const selectedStepId = stepResult.structured?.selectedStepId;
219
- // Check if AI selected END_ROUTE
220
- if (selectedStepId === END_ROUTE_ID) {
221
- logger.debug(`[RoutingEngine] Single-route: AI selected END_ROUTE - completing route`);
222
- logger.debug(`[RoutingEngine] Single-route: Reasoning: ${stepResult.structured?.reasoning}`);
247
+ // Check if AI selected flow completion
248
+ if (selectedStepId === '__COMPLETE__') {
249
+ logger.debug(`[FlowRouter] Single-flow: AI selected flow completion`);
250
+ logger.debug(`[FlowRouter] Single-flow: Reasoning: ${stepResult.structured?.reasoning}`);
223
251
  return {
224
- selectedRoute,
252
+ selectedFlow,
225
253
  selectedStep: undefined,
226
254
  responseDirectives: stepResult.structured?.responseDirectives,
227
255
  session: updatedSession,
228
- isRouteComplete: true,
229
- completedRoutes,
256
+ isFlowComplete: true,
257
+ completedFlows,
230
258
  };
231
259
  }
232
260
  const selectedStep = candidates.find((c) => c.step.id === selectedStepId);
233
261
  if (selectedStep) {
234
- logger.debug(`[RoutingEngine] Single-route: AI selected step: ${selectedStep.step.id}`);
235
- logger.debug(`[RoutingEngine] Single-route: Reasoning: ${stepResult.structured?.reasoning}`);
262
+ logger.debug(`[FlowRouter] Single-flow: AI selected step: ${selectedStep.step.id}`);
263
+ logger.debug(`[FlowRouter] Single-flow: Reasoning: ${stepResult.structured?.reasoning}`);
236
264
  }
237
265
  else {
238
- logger.warn(`[RoutingEngine] Single-route: Invalid step ID returned, using first candidate`);
266
+ logger.warn(`[FlowConfigurationError] Invalid step ID returned: AI router returned a step ID that does not match any candidate. Falling back to first candidate. Check flow step ids and router configuration.`);
239
267
  }
240
268
  return {
241
- selectedRoute,
269
+ selectedFlow,
242
270
  selectedStep: selectedStep?.step || candidates[0].step,
243
271
  responseDirectives: stepResult.structured?.responseDirectives,
244
272
  session: updatedSession,
245
- completedRoutes,
273
+ completedFlows,
246
274
  };
247
275
  }
248
276
  /**
249
- * Recursively traverse step chain to find first non-skipped step or END_ROUTE using new condition evaluation
277
+ * Recursively traverse step chain to find first non-skipped step using new condition evaluation
250
278
  * @private
251
279
  */
252
280
  async findFirstValidStepRecursiveWithConditions(currentStep, templateContext, visited) {
@@ -257,76 +285,78 @@ export class RoutingEngine {
257
285
  visited.add(currentStep.id);
258
286
  const transitions = currentStep.getTransitions();
259
287
  const allAiContextStrings = [];
288
+ // No transitions means implicit terminus — flow is complete
289
+ if (transitions.length === 0) {
290
+ return {
291
+ isFlowComplete: true,
292
+ aiContextStrings: allAiContextStrings,
293
+ };
294
+ }
260
295
  for (const transition of transitions) {
261
296
  const target = transition;
262
- // Check for END_ROUTE transition
263
- if (target && target.id === END_ROUTE_ID) {
264
- // Found END_ROUTE - route is complete
265
- return {
266
- isRouteComplete: true,
267
- aiContextStrings: allAiContextStrings,
268
- };
269
- }
270
297
  if (!target)
271
298
  continue;
272
- // Evaluate skipIf condition using new system
273
- const skipResult = await target.evaluateSkipIf(templateContext);
299
+ // Evaluate skip condition (code-only, if-shape)
300
+ const skipResult = await target.evaluateSkip(templateContext);
274
301
  allAiContextStrings.push(...skipResult.aiContextStrings);
275
302
  // If target should NOT be skipped, we found our step
276
303
  if (!skipResult.shouldSkip) {
277
- logger.debug(`[RoutingEngine] Found valid step after skipping: ${target.id}`);
304
+ logger.debug(`[FlowRouter] Found valid step after skipping: ${target.id}`);
278
305
  return {
279
306
  step: target,
280
- isRouteComplete: false,
307
+ isFlowComplete: false,
281
308
  aiContextStrings: allAiContextStrings,
282
309
  };
283
310
  }
284
311
  // Target should be skipped too - recurse deeper
285
- logger.debug(`[RoutingEngine] Skipping step ${target.id} (skipIf condition met), continuing traversal...`);
312
+ logger.debug(`[FlowRouter] Skipping step ${target.id} (skipIf condition met), continuing traversal...`);
286
313
  const result = await this.findFirstValidStepRecursiveWithConditions(target, templateContext, visited);
287
314
  // Collect AI context from recursive call
288
315
  if (result.aiContextStrings) {
289
316
  allAiContextStrings.push(...result.aiContextStrings);
290
317
  }
291
- // If we found something (a valid step or END_ROUTE), return it
292
- if (result.step || result.isRouteComplete) {
318
+ // If we found something (a valid step or flow complete), return it
319
+ if (result.step || result.isFlowComplete) {
293
320
  return {
294
321
  ...result,
295
322
  aiContextStrings: allAiContextStrings,
296
323
  };
297
324
  }
298
325
  }
299
- // No valid steps or END_ROUTE found in this branch
300
- return { aiContextStrings: allAiContextStrings };
326
+ // No valid steps found in this branch — all skipped with no further transitions
327
+ return {
328
+ isFlowComplete: true,
329
+ aiContextStrings: allAiContextStrings,
330
+ };
301
331
  }
302
332
  /**
303
333
  * Identify valid next candidate steps using new condition evaluation system
304
- * Returns step with isRouteComplete flag if route is complete (all steps skipped + has END_ROUTE transition)
334
+ * Returns step with isFlowComplete flag if flow is complete (all steps skipped or no transitions remain)
305
335
  *
306
- * NEW: Automatically completes route when all required fields are collected
336
+ * Flow completion is implicit: when the last step has no transitions, the flow is done.
307
337
  */
308
338
  async getCandidateStepsWithConditions(route, currentStep, templateContext) {
309
339
  const candidates = [];
310
340
  if (!currentStep) {
311
- // Entering route for the first time — always start the step flow
341
+ // Entering flow for the first time — always start the step flow
312
342
  const initialStep = route.initialStep;
313
- const skipResult = await initialStep.evaluateSkipIf(templateContext);
343
+ const skipResult = await initialStep.evaluateSkip(templateContext);
314
344
  if (skipResult.shouldSkip) {
315
- // Initial step should be skipped - recursively traverse to find first non-skipped step or END_ROUTE
345
+ // Initial step should be skipped - recursively traverse to find first non-skipped step
316
346
  const result = await this.findFirstValidStepRecursiveWithConditions(initialStep, templateContext, new Set());
317
- if (result.isRouteComplete) {
318
- // All steps are skipped and we reached END_ROUTE
319
- logger.debug(`[RoutingEngine] Route complete on entry: all steps skipped, END_ROUTE reached`);
347
+ if (result.isFlowComplete) {
348
+ // All steps are skipped and no transitions remain
349
+ logger.debug(`[FlowRouter] Flow complete on entry: all steps skipped, no transitions remain`);
320
350
  candidates.push({
321
351
  step: initialStep,
322
- isRouteComplete: true,
352
+ isFlowComplete: true,
323
353
  });
324
354
  }
325
355
  else if (result.step) {
326
356
  // Found a non-skipped step
327
357
  candidates.push({
328
358
  step: result.step,
329
- isRouteComplete: result.isRouteComplete || false,
359
+ isFlowComplete: result.isFlowComplete || false,
330
360
  });
331
361
  }
332
362
  // If no step found and not complete, fall through to return empty candidates
@@ -334,87 +364,84 @@ export class RoutingEngine {
334
364
  else {
335
365
  candidates.push({
336
366
  step: initialStep,
337
- isRouteComplete: false,
367
+ isFlowComplete: false,
338
368
  });
339
369
  }
340
370
  return candidates;
341
371
  }
342
- // Continue normal step progression — routes complete via END_ROUTE, not via data collection
372
+ // Continue normal step progression — flows complete when last step has no transitions (implicit terminus)
343
373
  const transitions = currentStep.getTransitions();
344
- let hasEndRoute = false;
374
+ // No transitions means this is the last step — flow is complete
375
+ if (transitions.length === 0) {
376
+ logger.debug(`[FlowRouter] Flow complete: current step has no transitions (implicit terminus)`);
377
+ return [
378
+ {
379
+ step: currentStep,
380
+ isFlowComplete: true,
381
+ },
382
+ ];
383
+ }
345
384
  for (const transition of transitions) {
346
385
  const target = transition;
347
- // Check for END_ROUTE transition (no target step)
348
- if (target && target.id === END_ROUTE_ID) {
349
- hasEndRoute = true;
350
- continue;
351
- }
352
386
  if (!target)
353
387
  continue;
354
- const skipResult = await target.evaluateSkipIf(templateContext);
388
+ const skipResult = await target.evaluateSkip(templateContext);
355
389
  if (skipResult.shouldSkip) {
356
- logger.debug(`[RoutingEngine] Skipping step ${target.id} (skipIf condition met)`);
357
- // Recursively traverse to find next valid step or END_ROUTE
390
+ logger.debug(`[FlowRouter] Skipping step ${target.id} (skip condition met)`);
391
+ // Recursively traverse to find next valid step
358
392
  const result = await this.findFirstValidStepRecursiveWithConditions(target, templateContext, new Set([currentStep.id]) // Already visited current step
359
393
  );
360
- if (result.isRouteComplete) {
361
- hasEndRoute = true;
394
+ if (result.isFlowComplete) {
395
+ // All forward paths lead to terminus
396
+ candidates.push({
397
+ step: currentStep,
398
+ isFlowComplete: true,
399
+ });
362
400
  }
363
401
  else if (result.step) {
364
402
  // Found a non-skipped step deeper in the chain
365
403
  candidates.push({
366
404
  step: result.step,
367
- isRouteComplete: result.isRouteComplete || false,
405
+ isFlowComplete: false,
368
406
  });
369
407
  }
370
408
  continue;
371
409
  }
372
410
  candidates.push({
373
411
  step: target,
374
- isRouteComplete: hasEndRoute || false,
412
+ isFlowComplete: false,
375
413
  });
376
414
  }
377
- // If no valid candidates found
415
+ // If no valid candidates found after evaluating all transitions
378
416
  if (candidates.length === 0) {
379
- // If current step has END_ROUTE transition, the route is complete
380
- if (hasEndRoute) {
381
- logger.debug(`[RoutingEngine] Route complete: all steps processed, END_ROUTE reached`);
382
- // Return current step with completion flag
383
- return [
384
- {
385
- step: currentStep,
386
- isRouteComplete: true,
387
- },
388
- ];
389
- }
390
- // Otherwise, stay in current step if it's still valid
391
- const currentSkipResult = await currentStep.evaluateSkipIf(templateContext);
392
- if (!currentSkipResult.shouldSkip) {
393
- candidates.push({
417
+ // All transitions were skipped flow is complete
418
+ logger.debug(`[FlowRouter] Flow complete: all transitions skipped`);
419
+ return [
420
+ {
394
421
  step: currentStep,
395
- isRouteComplete: hasEndRoute || false,
396
- });
397
- }
422
+ isFlowComplete: true,
423
+ },
424
+ ];
398
425
  }
399
426
  return candidates;
400
427
  }
401
428
  /**
402
429
  * Full routing orchestration: builds prompt and schema, calls AI, selects route/step,
403
- * and updates the session (including initialData merge when entering a new route).
430
+ * and updates the session (including initialData merge when entering a new flow).
404
431
  *
405
432
  * OPTIMIZATION: If there's only 1 route, skips route scoring and only does step selection.
406
- * CROSS-ROUTE COMPLETION: Evaluates all routes for completion based on collected data.
433
+ * CROSS-FLOW COMPLETION: Evaluates all flows for completion based on collected data.
407
434
  */
408
- async decideRouteAndStep(params) {
409
- const { routes, session, history, agentOptions, provider, context, signal, } = params;
410
- if (routes.length === 0) {
435
+ async decideFlowAndStep(params) {
436
+ const { flows, session, history, agentOptions, provider, context, signal, } = params;
437
+ if (flows.length === 0) {
411
438
  return { session };
412
439
  }
413
- // SESSION RESUME: If the session has a pre-set route and there are no user
440
+ // SESSION RESUME: If the session has a pre-set flow and there are no user
414
441
  // messages in the history, honor the pre-set position without AI routing.
415
442
  // This supports programmatic session setup and persistence-based resume.
416
443
  const resumeResult = await this.handleSessionResume({
417
- routes,
444
+ flows,
418
445
  session,
419
446
  history,
420
447
  context,
@@ -422,16 +449,24 @@ export class RoutingEngine {
422
449
  if (resumeResult) {
423
450
  return resumeResult;
424
451
  }
425
- // CROSS-ROUTE COMPLETION EVALUATION: Check all routes for completion
426
- const completedRoutes = this.evaluateRouteCompletions(routes, session.data || {});
427
- // Log completed routes
428
- if (completedRoutes.length > 0) {
429
- logger.debug(`[RoutingEngine] Found ${completedRoutes.length} completed routes: ${completedRoutes.map(r => r.title).join(', ')}`);
430
- }
431
- // OPTIMIZATION: Single route - skip route scoring, only do step selection
432
- if (routes.length === 1) {
433
- const result = await this.decideSingleRouteStep({
434
- route: routes[0],
452
+ // Exclude flows that completed earlier in this session unless explicitly
453
+ // re-entrant. A completed flow surrenders the conversation back to
454
+ // routing it cannot be re-selected without `flow.reentrant: true`.
455
+ const reEntryFiltered = flows.filter((f) => !isFlowCompletedThisSession(session, f.id) || f.reentrant === true);
456
+ const excludedFlows = flows.length - reEntryFiltered.length;
457
+ if (excludedFlows > 0) {
458
+ logger.debug(`[FlowRouter] Excluded ${excludedFlows} completed (non-reentrant) flow(s) from routing candidates`);
459
+ }
460
+ // CROSS-FLOW COMPLETION EVALUATION: Check all eligible flows for completion
461
+ const completedFlows = this.evaluateFlowCompletions(reEntryFiltered, session.data || {});
462
+ // Log completed flows
463
+ if (completedFlows.length > 0) {
464
+ logger.debug(`[FlowRouter] Found ${completedFlows.length} completed routes: ${completedFlows.map(r => r.title).join(', ')}`);
465
+ }
466
+ // OPTIMIZATION: Single flow - skip flow scoring, only do step selection
467
+ if (reEntryFiltered.length === 1) {
468
+ const result = await this.decideSingleFlowStep({
469
+ route: reEntryFiltered[0],
435
470
  session,
436
471
  history,
437
472
  agentOptions,
@@ -441,9 +476,15 @@ export class RoutingEngine {
441
476
  });
442
477
  return {
443
478
  ...result,
444
- completedRoutes,
479
+ completedFlows,
445
480
  };
446
481
  }
482
+ // No eligible flows after re-entry filtering — caller falls back to the
483
+ // generic non-flow response path.
484
+ if (reEntryFiltered.length === 0) {
485
+ logger.debug(`[FlowRouter] All flows completed and none are reentrant — releasing session to fallback`);
486
+ return { session, completedFlows };
487
+ }
447
488
  const lastUserMessage = getLastMessageFromHistory(history);
448
489
  const templateContext = createTemplateContext({
449
490
  context,
@@ -451,56 +492,55 @@ export class RoutingEngine {
451
492
  history,
452
493
  data: session.data
453
494
  });
454
- // Apply route filtering with new condition evaluation system
455
- const skipIfResult = await this.filterRoutesBySkipIf(routes, templateContext);
456
- const whenResult = await this.filterRoutesByWhen(skipIfResult.eligibleRoutes, templateContext);
457
- // Use filtered routes for further processing
495
+ // Apply flow filtering with new condition evaluation system
496
+ const whenResult = await this.filterFlowsByWhen(reEntryFiltered, templateContext);
497
+ // Use filtered flows for further processing
458
498
  const eligibleRoutes = whenResult.eligibleRoutes;
459
- logger.debug(`[RoutingEngine] Route filtering: ${routes.length} total → ${skipIfResult.eligibleRoutes.length} after skipIf → ${eligibleRoutes.length} after when`);
460
- let activeRouteSteps;
461
- let activeRoute;
462
- let isRouteComplete = false;
499
+ logger.debug(`[FlowRouter] Flow filtering: ${flows.length} total → ${reEntryFiltered.length} after re-entry filter → ${eligibleRoutes.length} after when`);
500
+ let activeFlowSteps;
501
+ let activeFlow;
502
+ let isFlowComplete = false;
463
503
  let updatedSession = session;
464
- if (session.currentRoute) {
465
- activeRoute = eligibleRoutes.find((r) => r.id === session.currentRoute?.id);
466
- if (activeRoute) {
504
+ if (session.currentFlow) {
505
+ activeFlow = eligibleRoutes.find((r) => r.id === session.currentFlow?.id);
506
+ if (activeFlow) {
467
507
  const currentStep = session.currentStep
468
- ? activeRoute.getStep(session.currentStep.id)
508
+ ? activeFlow.getStep(session.currentStep.id)
469
509
  : undefined;
470
510
  const activeTemplateContext = createTemplateContext({
471
511
  ...templateContext,
472
512
  session: updatedSession,
473
513
  data: updatedSession.data
474
514
  });
475
- const candidates = await this.getCandidateStepsWithConditions(activeRoute, currentStep, activeTemplateContext);
476
- // Check if route is complete
515
+ const candidates = await this.getCandidateStepsWithConditions(activeFlow, currentStep, activeTemplateContext);
516
+ // Check if flow is complete
477
517
  // getCandidateStepsWithConditions now automatically handles completion when required fields are collected
478
- if (candidates.length === 1 && candidates[0].isRouteComplete) {
479
- isRouteComplete = true;
480
- logger.debug(`[RoutingEngine] Route ${activeRoute.title} is complete - all required fields collected or END_ROUTE reached`);
518
+ if (candidates.length === 1 && candidates[0].isFlowComplete) {
519
+ isFlowComplete = true;
520
+ logger.debug(`[FlowRouter] Flow ${activeFlow.title} is complete - all required fields collected or last step reached`);
481
521
  // Don't include steps in routing if route is complete
482
- activeRouteSteps = undefined;
522
+ activeFlowSteps = undefined;
483
523
  }
484
524
  else if (candidates.length === 0) {
485
- // No candidates available — don't end route based on data alone
486
- logger.debug(`[RoutingEngine] Route ${activeRoute.title} has no valid candidate steps`);
487
- activeRouteSteps = undefined;
525
+ // No candidates available — don't end flow based on data alone
526
+ logger.debug(`[FlowRouter] Flow ${activeFlow.title} has no valid candidate steps`);
527
+ activeFlowSteps = undefined;
488
528
  }
489
529
  else {
490
530
  // Multiple candidates or single non-complete candidate
491
- activeRouteSteps = candidates.map((c) => c.step);
492
- logger.debug(`[RoutingEngine] Found ${activeRouteSteps.length} candidate steps for active route`);
531
+ activeFlowSteps = candidates.map((c) => c.step);
532
+ logger.debug(`[FlowRouter] Found ${activeFlowSteps.length} candidate steps for active route`);
493
533
  }
494
534
  }
495
535
  }
496
- const routingSchema = this.buildDynamicRoutingSchema(eligibleRoutes, undefined, activeRouteSteps);
536
+ const routingSchema = this.buildDynamicFlowSchema(eligibleRoutes, undefined, activeFlowSteps);
497
537
  const routingPrompt = await this.buildRoutingPrompt({
498
538
  history,
499
- routes: eligibleRoutes,
539
+ flows: eligibleRoutes,
500
540
  lastMessage: lastUserMessage,
501
541
  agentOptions,
502
542
  session,
503
- activeRouteSteps,
543
+ activeFlowSteps,
504
544
  context,
505
545
  });
506
546
  const routingResult = await provider.generateMessage({
@@ -513,115 +553,92 @@ export class RoutingEngine {
513
553
  schemaName: "routing_output",
514
554
  },
515
555
  });
516
- let selectedRoute;
556
+ let selectedFlow;
517
557
  let selectedStep;
518
558
  let responseDirectives;
519
- if (routingResult.structured?.routes) {
520
- // Use cross-route completion evaluation to select optimal route
521
- const optimalRoute = this.selectOptimalRoute(eligibleRoutes, updatedSession.data || {}, routingResult.structured.routes, updatedSession.currentRoute?.id);
522
- // If no optimal route found, check why
559
+ if (routingResult.structured?.flows) {
560
+ // Use cross-flow completion evaluation to select optimal flow
561
+ const optimalRoute = this.selectOptimalFlow(eligibleRoutes, updatedSession.data || {}, routingResult.structured.flows, updatedSession.currentFlow?.id);
562
+ // If no optimal flow found, check why
523
563
  if (!optimalRoute) {
524
564
  if (eligibleRoutes.length === 0) {
525
- // No routes passed filtering
526
- logger.debug(`[RoutingEngine] No eligible routes available - all routes filtered out`);
527
- selectedRoute = undefined;
565
+ // No flows passed filtering
566
+ logger.debug(`[FlowRouter] No eligible flows available - all flows filtered out`);
567
+ selectedFlow = undefined;
528
568
  }
529
569
  else {
530
- // Routes exist but selectOptimalRoute returned undefined
531
- // This means all routes are 100% complete
532
- logger.debug(`[RoutingEngine] No optimal route found - all ${eligibleRoutes.length} eligible routes are complete`);
533
- selectedRoute = undefined;
570
+ // Routes exist but selectOptimalFlow returned undefined
571
+ // This means all flows are 100% complete
572
+ logger.debug(`[FlowRouter] No optimal route found - all ${eligibleRoutes.length} eligible routes are complete`);
573
+ selectedFlow = undefined;
534
574
  }
535
575
  }
536
576
  else {
537
- selectedRoute = optimalRoute;
577
+ selectedFlow = optimalRoute;
538
578
  }
539
579
  responseDirectives = routingResult.structured.responseDirectives;
540
- if (selectedRoute === activeRoute &&
580
+ if (selectedFlow === activeFlow &&
541
581
  routingResult.structured.selectedStepId &&
542
- activeRoute) {
543
- selectedStep = activeRoute.getStep(routingResult.structured.selectedStepId);
582
+ activeFlow) {
583
+ selectedStep = activeFlow.getStep(routingResult.structured.selectedStepId);
544
584
  if (selectedStep) {
545
- logger.debug(`[RoutingEngine] AI selected step: ${selectedStep.id} in active route`);
546
- logger.debug(`[RoutingEngine] Step reasoning: ${routingResult.structured.stepReasoning}`);
585
+ logger.debug(`[FlowRouter] AI selected step: ${selectedStep.id} in active route`);
586
+ logger.debug(`[FlowRouter] Step reasoning: ${routingResult.structured.stepReasoning}`);
547
587
  }
548
588
  }
549
- if (selectedRoute) {
550
- logger.debug(`[RoutingEngine] Selected route: ${selectedRoute.title}`);
551
- updatedSession = this.enterRouteIfNeeded(updatedSession, selectedRoute);
589
+ if (selectedFlow) {
590
+ logger.debug(`[FlowRouter] Selected route: ${selectedFlow.title}`);
591
+ updatedSession = this.enterFlowIfNeeded(updatedSession, selectedFlow);
552
592
  }
553
593
  }
554
594
  return {
555
- selectedRoute,
595
+ selectedFlow,
556
596
  selectedStep,
557
597
  responseDirectives,
558
598
  session: updatedSession,
559
- isRouteComplete,
560
- completedRoutes,
599
+ isFlowComplete,
600
+ completedFlows,
561
601
  };
562
602
  }
563
603
  /**
564
- * Filter routes based on skipIf conditions
565
- * @param routes - All available routes
566
- * @param templateContext - Context for condition evaluation
567
- * @returns Object with eligible routes and collected AI context strings
568
- */
569
- async filterRoutesBySkipIf(routes, templateContext) {
570
- const eligibleRoutes = [];
571
- const aiContextStrings = [];
572
- for (const route of routes) {
573
- const skipResult = await route.evaluateSkipIf(templateContext);
574
- // Collect AI context strings from skipIf conditions
575
- aiContextStrings.push(...skipResult.aiContextStrings);
576
- // If route should not be skipped, it's eligible
577
- if (!skipResult.programmaticResult) {
578
- eligibleRoutes.push(route);
579
- }
580
- else {
581
- logger.debug(`[RoutingEngine] Skipping route ${route.title} (skipIf condition met)`);
582
- }
583
- }
584
- return { eligibleRoutes, aiContextStrings };
585
- }
586
- /**
587
- * Filter routes based on when conditions
588
- * @param routes - Routes that passed skipIf filtering
604
+ * Filter flows based on when conditions
605
+ * @param routes - Flows that passed skipIf filtering
589
606
  * @param templateContext - Context for condition evaluation
590
- * @returns Object with eligible routes and collected AI context strings
607
+ * @returns Object with eligible flows and collected AI context strings
591
608
  */
592
- async filterRoutesByWhen(routes, templateContext) {
609
+ async filterFlowsByWhen(routes, templateContext) {
593
610
  const eligibleRoutes = [];
594
611
  const aiContextStrings = [];
595
612
  for (const route of routes) {
596
613
  const whenResult = await route.evaluateWhen(templateContext);
597
614
  // Collect AI context strings from when conditions
598
615
  aiContextStrings.push(...whenResult.aiContextStrings);
599
- // If route has no programmatic conditions or they evaluate to true, it's eligible
616
+ // If flow has no programmatic conditions or they evaluate to true, it's eligible
600
617
  if (!whenResult.hasProgrammaticConditions || whenResult.programmaticResult) {
601
618
  eligibleRoutes.push(route);
602
619
  }
603
620
  else {
604
- logger.debug(`[RoutingEngine] Route ${route.title} not eligible (when condition not met)`);
621
+ logger.debug(`[FlowRouter] Flow ${route.title} not eligible (when condition not met)`);
605
622
  }
606
623
  }
607
624
  return { eligibleRoutes, aiContextStrings };
608
625
  }
609
626
  /**
610
- * Evaluate all routes for completion based on collected data
611
- * @param routes - All available routes
627
+ * Evaluate all flows for completion based on collected data
628
+ * @param routes - All available flows
612
629
  * @param data - Currently collected agent-level data
613
- * @returns Array of routes that are complete
630
+ * @returns Array of flows that are complete
614
631
  */
615
- evaluateRouteCompletions(routes, data) {
632
+ evaluateFlowCompletions(routes, data) {
616
633
  return routes.filter(route => route.isComplete(data));
617
634
  }
618
635
  /**
619
- * Get completion status for all routes
620
- * @param routes - All available routes
636
+ * Get completion status for all flows
637
+ * @param routes - All available flows
621
638
  * @param data - Currently collected agent-level data
622
- * @returns Map of route ID to completion progress (0-1)
639
+ * @returns Map of flow ID to completion progress (0-1)
623
640
  */
624
- getRouteCompletionStatus(routes, data) {
641
+ getFlowCompletionStatus(routes, data) {
625
642
  const completionStatus = new Map();
626
643
  for (const route of routes) {
627
644
  const progress = route.getCompletionProgress(data);
@@ -630,28 +647,28 @@ export class RoutingEngine {
630
647
  return completionStatus;
631
648
  }
632
649
  /**
633
- * Find the best route to continue based on completion status and user intent
634
- * Prioritizes routes that are partially complete but not finished
635
- * IMPORTANT: Completed routes are excluded to prevent re-entering finished tasks
636
- * @param routes - All available routes
650
+ * Find the best flow to continue based on completion status and user intent
651
+ * Prioritizes flows that are partially complete but not finished
652
+ * IMPORTANT: Completed flows are excluded to prevent re-entering finished tasks
653
+ * @param routes - All available flows
637
654
  * @param data - Currently collected agent-level data
638
655
  * @param routeScores - AI-generated route scores from routing decision
639
- * @returns Route that should be prioritized for continuation
656
+ * @returns Flow that should be prioritized for continuation
640
657
  */
641
- selectOptimalRoute(routes, data, routeScores, currentRouteId) {
642
- const completionStatus = this.getRouteCompletionStatus(routes, data);
643
- const switchMargin = this.options?.routeSwitchMargin ?? 15;
658
+ selectOptimalFlow(routes, data, routeScores, currentRouteId) {
659
+ const completionStatus = this.getFlowCompletionStatus(routes, data);
660
+ const switchMargin = this.options?.flowSwitchMargin ?? 15;
644
661
  // Create weighted scores combining AI intent scores with completion progress
645
662
  const weightedScores = [];
646
663
  for (const route of routes) {
647
664
  const aiScore = routeScores[route.id] || 0;
648
665
  const completionProgress = completionStatus.get(route.id) || 0;
649
- // ALWAYS skip fully completed routes to prevent re-entering finished tasks
666
+ // ALWAYS skip fully completed flows to prevent re-entering finished tasks
650
667
  if (completionProgress >= 1.0) {
651
- logger.debug(`[RoutingEngine] Excluding completed route: ${route.title} (100% complete)`);
668
+ logger.debug(`[FlowRouter] Excluding completed flow: ${route.title} (100% complete)`);
652
669
  continue;
653
670
  }
654
- // Boost partially complete routes that match user intent
671
+ // Boost partially complete flows that match user intent
655
672
  let weightedScore = aiScore;
656
673
  if (completionProgress > 0 && completionProgress < 1.0) {
657
674
  weightedScore += (completionProgress * 20); // Up to 20 point boost
@@ -664,48 +681,48 @@ export class RoutingEngine {
664
681
  return undefined;
665
682
  }
666
683
  // Apply sticky routing: if there's a current route, only switch if the
667
- // best alternative exceeds the current route's score by the configured margin
684
+ // best alternative exceeds the current flow's score by the configured margin
668
685
  if (currentRouteId) {
669
686
  const currentEntry = weightedScores.find(e => e.route.id === currentRouteId);
670
687
  const bestEntry = weightedScores[0];
671
688
  if (currentEntry && bestEntry.route.id !== currentRouteId) {
672
689
  if (bestEntry.score < currentEntry.score + switchMargin) {
673
- logger.debug(`[RoutingEngine] Staying on current route: ${currentEntry.route.title} ` +
690
+ logger.debug(`[FlowRouter] Staying on current flow: ${currentEntry.route.title} ` +
674
691
  `(current: ${currentEntry.score}, best alternative: ${bestEntry.score}, ` +
675
692
  `margin required: ${switchMargin})`);
676
693
  return currentEntry.route;
677
694
  }
678
- logger.debug(`[RoutingEngine] Switching route: ${currentEntry.route.title} → ${bestEntry.route.title} ` +
695
+ logger.debug(`[FlowRouter] Switching flow: ${currentEntry.route.title} → ${bestEntry.route.title} ` +
679
696
  `(current: ${currentEntry.score}, alternative: ${bestEntry.score}, ` +
680
697
  `margin: ${switchMargin})`);
681
698
  }
682
699
  }
683
- logger.debug(`[RoutingEngine] Selected optimal route: ${weightedScores[0].route.title} ` +
700
+ logger.debug(`[FlowRouter] Selected optimal route: ${weightedScores[0].route.title} ` +
684
701
  `(AI: ${routeScores[weightedScores[0].route.id]}, ` +
685
702
  `Completion: ${(completionStatus.get(weightedScores[0].route.id) || 0) * 100}%, ` +
686
703
  `Weighted: ${weightedScores[0].score})`);
687
704
  return weightedScores[0].route;
688
705
  }
689
706
  /**
690
- * Build prompt for step selection within a single route
707
+ * Build prompt for step selection within a single flow
691
708
  * @private
692
709
  */
693
710
  async buildStepSelectionPrompt(params) {
694
- const { route, currentStep, candidates, data, history, lastMessage, agentOptions, context, session, stepConditionContext, includeEndRoute = false, } = params;
711
+ const { flow: route, currentStep, candidates, data, history, lastMessage, agentOptions, context, session, stepConditionContext, includeCompletion = false, } = params;
695
712
  const templateContext = createTemplateContext({ context, session, history });
696
713
  const pc = new PromptComposer(templateContext, this.options?.promptSectionCache);
697
714
  // Add agent metadata
698
715
  if (agentOptions) {
699
716
  await pc.addAgentMeta(agentOptions);
700
717
  }
701
- // Add route context
702
- await pc.addInstruction(`Active Route: ${route.title}\nDescription: ${route.description || "N/A"}`);
718
+ // Add flow context
719
+ await pc.addInstruction(`Active Flow: ${route.title}\nDescription: ${route.description || "N/A"}`);
703
720
  // Add current step context
704
721
  if (currentStep) {
705
722
  await pc.addInstruction(`Current Step: ${currentStep.id}\nDescription: ${currentStep.description || "N/A"}`);
706
723
  }
707
724
  else {
708
- await pc.addInstruction("Current Step: None (entering route)");
725
+ await pc.addInstruction("Current Step: None (entering flow)");
709
726
  }
710
727
  // Add collected data context
711
728
  if (Object.keys(data).length > 0) {
@@ -769,8 +786,8 @@ export class RoutingEngine {
769
786
  "- Choose the step that makes the most sense for moving the conversation forward",
770
787
  "- Steps with skipIf conditions that are met have already been filtered out",
771
788
  ];
772
- if (includeEndRoute) {
773
- decisionRules.push("", `- You can select '${END_ROUTE_ID}' to complete this route if:`, " * All required data has been collected", " * The user's intent suggests they're done with this task", " * No further steps are needed to fulfill the user's request");
789
+ if (includeCompletion) {
790
+ decisionRules.push("", `- You can select '__COMPLETE__' to complete this flow if:`, " * All required data has been collected", " * The user's intent suggests they're done with this task", " * No further steps are needed to fulfill the user's request");
774
791
  }
775
792
  decisionRules.push("", "Return ONLY JSON matching the provided schema.");
776
793
  await pc.addInstruction(decisionRules.join("\n"));
@@ -780,11 +797,11 @@ export class RoutingEngine {
780
797
  * Build schema for step selection
781
798
  * @private
782
799
  */
783
- buildStepSelectionSchema(validSteps, includeEndRoute = false) {
800
+ buildStepSelectionSchema(validSteps, includeCompletion = false) {
784
801
  const stepIds = validSteps.map((s) => s.id);
785
- // Add END_ROUTE as an option if requested (when required fields are complete)
786
- if (includeEndRoute) {
787
- stepIds.push(END_ROUTE_ID);
802
+ // Add completion option if requested (when required fields are complete)
803
+ if (includeCompletion) {
804
+ stepIds.push('__COMPLETE__');
788
805
  }
789
806
  return {
790
807
  description: "Step transition decision based on conversation context and collected data",
@@ -798,8 +815,8 @@ export class RoutingEngine {
798
815
  selectedStepId: {
799
816
  type: "string",
800
817
  nullable: false,
801
- description: includeEndRoute
802
- ? `The ID of the selected step to transition to, or '${END_ROUTE_ID}' to complete the route`
818
+ description: includeCompletion
819
+ ? "The ID of the selected step to transition to, or '__COMPLETE__' to complete the flow"
803
820
  : "The ID of the selected step to transition to",
804
821
  enum: stepIds,
805
822
  },
@@ -813,20 +830,20 @@ export class RoutingEngine {
813
830
  additionalProperties: false,
814
831
  };
815
832
  }
816
- buildDynamicRoutingSchema(routes, extrasSchema, activeRouteSteps) {
833
+ buildDynamicFlowSchema(routes, extrasSchema, activeFlowSteps) {
817
834
  const routeIds = routes.map((r) => r.id);
818
835
  const routeProperties = {};
819
836
  for (const id of routeIds) {
820
837
  routeProperties[id] = {
821
838
  type: "number",
822
839
  nullable: false,
823
- description: `Score for route ${id} based on direct evidence, context and semantic fit (0-100)`,
840
+ description: `Score for flow ${id} based on direct evidence, context and semantic fit (0-100)`,
824
841
  minimum: 0,
825
842
  maximum: 100,
826
843
  };
827
844
  }
828
845
  const base = {
829
- description: "Full intent analysis: score ALL available routes (0-100) using evidence and context",
846
+ description: "Full intent analysis: score ALL available flows (0-100) using evidence and context",
830
847
  type: "object",
831
848
  properties: {
832
849
  context: {
@@ -834,12 +851,12 @@ export class RoutingEngine {
834
851
  nullable: false,
835
852
  description: "Brief summary of the user's intent/context",
836
853
  },
837
- routes: {
854
+ flows: {
838
855
  type: "object",
839
856
  properties: routeProperties,
840
857
  required: routeIds,
841
858
  nullable: false,
842
- description: "Mapping of routeId to score (0-100)",
859
+ description: "Mapping of flowId to score (0-100)",
843
860
  },
844
861
  responseDirectives: {
845
862
  type: "array",
@@ -847,17 +864,17 @@ export class RoutingEngine {
847
864
  description: "Optional bullet points the response should address (concise)",
848
865
  },
849
866
  },
850
- required: ["context", "routes"],
867
+ required: ["context", "flows"],
851
868
  additionalProperties: false,
852
869
  };
853
- // Add step selection fields if there's an active route with steps
854
- if (activeRouteSteps && activeRouteSteps.length > 0) {
870
+ // Add step selection fields if there's an active flow with steps
871
+ if (activeFlowSteps && activeFlowSteps.length > 0) {
855
872
  base.properties = base.properties || {};
856
873
  base.properties.selectedStepId = {
857
874
  type: "string",
858
875
  nullable: false,
859
- description: "The step ID to transition to within the active route (required if continuing in current route)",
860
- enum: activeRouteSteps.map((s) => s.id),
876
+ description: "The step ID to transition to within the active flow (required if continuing in current flow)",
877
+ enum: activeFlowSteps.map((s) => s.id),
861
878
  };
862
879
  base.properties.stepReasoning = {
863
880
  type: "string",
@@ -877,7 +894,7 @@ export class RoutingEngine {
877
894
  return base;
878
895
  }
879
896
  async buildRoutingPrompt(params) {
880
- const { history, routes, lastMessage, agentOptions, session, activeRouteSteps, context, } = params;
897
+ const { history, flows: routes, lastMessage, agentOptions, session, activeFlowSteps, context, } = params;
881
898
  const templateContext = createTemplateContext({ context, session, history });
882
899
  const pc = new PromptComposer(templateContext, this.options?.promptSectionCache);
883
900
  if (agentOptions) {
@@ -885,10 +902,10 @@ export class RoutingEngine {
885
902
  }
886
903
  await pc.addInstruction("Task: Intent analysis and route scoring (0-100). Score ALL listed routes.");
887
904
  // Add session context if available
888
- if (session?.currentRoute) {
905
+ if (session?.currentFlow) {
889
906
  const sessionInfo = [
890
907
  "Current conversation context:",
891
- `- Active route: ${session.currentRoute.title} (${session.currentRoute.id})`,
908
+ `- Active route: ${session.currentFlow.title} (${session.currentFlow.id})`,
892
909
  ];
893
910
  if (session.currentStep) {
894
911
  sessionInfo.push(`- Current step: ${session.currentStep.id}`);
@@ -902,16 +919,16 @@ export class RoutingEngine {
902
919
  sessionInfo.push("Note: User is mid-conversation. They may want to continue current route or switch to a new one based on their intent.");
903
920
  await pc.addInstruction(sessionInfo.join("\n"));
904
921
  // Add cross-route completion status
905
- const completionStatus = this.getRouteCompletionStatus(routes, session.data || {});
906
- const completedRoutes = this.evaluateRouteCompletions(routes, session.data || {});
922
+ const completionStatus = this.getFlowCompletionStatus(routes, session.data || {});
923
+ const completedFlows = this.evaluateFlowCompletions(routes, session.data || {});
907
924
  if (completionStatus.size > 0) {
908
925
  const statusInfo = [
909
926
  "",
910
- "Route completion status based on collected data:",
927
+ "Flow completion status based on collected data:",
911
928
  ];
912
929
  for (const route of routes) {
913
930
  const progress = completionStatus.get(route.id) || 0;
914
- const isComplete = completedRoutes.includes(route);
931
+ const isComplete = completedFlows.includes(route);
915
932
  const progressPercent = Math.round(progress * 100);
916
933
  statusInfo.push(`- ${route.title}: ${progressPercent}% complete${isComplete ? ' ✓ COMPLETE' : ''}`);
917
934
  if (!isComplete && route.requiredFields) {
@@ -925,14 +942,14 @@ export class RoutingEngine {
925
942
  await pc.addInstruction(statusInfo.join("\n"));
926
943
  }
927
944
  // Add available steps for the active route
928
- if (activeRouteSteps && activeRouteSteps.length > 0) {
945
+ if (activeFlowSteps && activeFlowSteps.length > 0) {
929
946
  const stepInfo = [
930
947
  "",
931
948
  "Available steps in active route (choose one to transition to):",
932
949
  ];
933
950
  const activeStepConditionContext = [];
934
- for (const step of activeRouteSteps) {
935
- const idx = activeRouteSteps.indexOf(step);
951
+ for (const step of activeFlowSteps) {
952
+ const idx = activeFlowSteps.indexOf(step);
936
953
  stepInfo.push(`${idx + 1}. Step: ${step.id}`);
937
954
  if (step.description) {
938
955
  stepInfo.push(` Description: ${step.description}`);
@@ -976,7 +993,7 @@ export class RoutingEngine {
976
993
  }
977
994
  await pc.addInteractionHistory(history);
978
995
  await pc.addLastMessage(lastMessage);
979
- await pc.addRoutingOverview(routes);
996
+ await pc.addFlowOverview(routes);
980
997
  await pc.addInstruction([
981
998
  "Scoring rules:",
982
999
  "- 90-100: explicit keywords + clear intent",
@@ -989,4 +1006,4 @@ export class RoutingEngine {
989
1006
  return pc.build();
990
1007
  }
991
1008
  }
992
- //# sourceMappingURL=RoutingEngine.js.map
1009
+ //# sourceMappingURL=FlowRouter.js.map