@falai/agent 0.9.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (654) hide show
  1. package/README.md +304 -72
  2. package/dist/adapters/MemoryAdapter.d.ts.map +1 -0
  3. package/dist/adapters/MemoryAdapter.js.map +1 -0
  4. package/dist/adapters/MongoAdapter.d.ts.map +1 -0
  5. package/dist/adapters/MongoAdapter.js.map +1 -0
  6. package/dist/adapters/OpenSearchAdapter.d.ts.map +1 -0
  7. package/dist/adapters/OpenSearchAdapter.js.map +1 -0
  8. package/dist/adapters/PostgreSQLAdapter.d.ts.map +1 -0
  9. package/dist/adapters/PostgreSQLAdapter.js.map +1 -0
  10. package/dist/adapters/PrismaAdapter.d.ts.map +1 -0
  11. package/dist/{src/adapters → adapters}/PrismaAdapter.js +3 -2
  12. package/dist/adapters/PrismaAdapter.js.map +1 -0
  13. package/dist/adapters/RedisAdapter.d.ts.map +1 -0
  14. package/dist/{src/adapters → adapters}/RedisAdapter.js +3 -3
  15. package/dist/adapters/RedisAdapter.js.map +1 -0
  16. package/dist/adapters/SQLiteAdapter.d.ts.map +1 -0
  17. package/dist/adapters/SQLiteAdapter.js.map +1 -0
  18. package/dist/adapters/index.d.ts.map +1 -0
  19. package/dist/adapters/index.js.map +1 -0
  20. package/dist/cjs/adapters/MemoryAdapter.js.map +1 -0
  21. package/dist/cjs/adapters/MongoAdapter.js.map +1 -0
  22. package/dist/cjs/adapters/OpenSearchAdapter.js.map +1 -0
  23. package/dist/cjs/adapters/PostgreSQLAdapter.js.map +1 -0
  24. package/dist/{src → cjs}/adapters/PrismaAdapter.d.ts.map +1 -1
  25. package/dist/cjs/{src/adapters → adapters}/PrismaAdapter.js +3 -2
  26. package/dist/cjs/adapters/PrismaAdapter.js.map +1 -0
  27. package/dist/cjs/{src/adapters → adapters}/RedisAdapter.js +2 -2
  28. package/dist/cjs/adapters/RedisAdapter.js.map +1 -0
  29. package/dist/cjs/adapters/SQLiteAdapter.js.map +1 -0
  30. package/dist/cjs/adapters/index.js.map +1 -0
  31. package/dist/cjs/constants/index.js.map +1 -0
  32. package/dist/{src → cjs}/core/Agent.d.ts +25 -6
  33. package/dist/cjs/core/Agent.d.ts.map +1 -0
  34. package/dist/cjs/{src/core → core}/Agent.js +121 -37
  35. package/dist/cjs/core/Agent.js.map +1 -0
  36. package/dist/cjs/core/BatchExecutor.d.ts +353 -0
  37. package/dist/cjs/core/BatchExecutor.d.ts.map +1 -0
  38. package/dist/cjs/core/BatchExecutor.js +842 -0
  39. package/dist/cjs/core/BatchExecutor.js.map +1 -0
  40. package/dist/cjs/core/BatchPromptBuilder.d.ts +86 -0
  41. package/dist/cjs/core/BatchPromptBuilder.d.ts.map +1 -0
  42. package/dist/cjs/core/BatchPromptBuilder.js +201 -0
  43. package/dist/cjs/core/BatchPromptBuilder.js.map +1 -0
  44. package/dist/cjs/core/Events.js.map +1 -0
  45. package/dist/cjs/core/PersistenceManager.js.map +1 -0
  46. package/dist/{src → cjs}/core/PromptComposer.d.ts +1 -1
  47. package/dist/cjs/core/PromptComposer.d.ts.map +1 -0
  48. package/dist/cjs/{src/core → core}/PromptComposer.js +44 -7
  49. package/dist/cjs/core/PromptComposer.js.map +1 -0
  50. package/dist/{src → cjs}/core/ResponseEngine.d.ts.map +1 -1
  51. package/dist/cjs/core/ResponseEngine.js +202 -0
  52. package/dist/cjs/core/ResponseEngine.js.map +1 -0
  53. package/dist/{src → cjs}/core/ResponseModal.d.ts +54 -3
  54. package/dist/cjs/core/ResponseModal.d.ts.map +1 -0
  55. package/dist/cjs/{src/core → core}/ResponseModal.js +807 -121
  56. package/dist/cjs/core/ResponseModal.js.map +1 -0
  57. package/dist/{src → cjs}/core/ResponsePipeline.d.ts +10 -6
  58. package/dist/cjs/core/ResponsePipeline.d.ts.map +1 -0
  59. package/dist/cjs/{src/core → core}/ResponsePipeline.js +60 -25
  60. package/dist/cjs/core/ResponsePipeline.js.map +1 -0
  61. package/dist/{src → cjs}/core/Route.d.ts +46 -10
  62. package/dist/cjs/core/Route.d.ts.map +1 -0
  63. package/dist/cjs/core/Route.js +541 -0
  64. package/dist/cjs/core/Route.js.map +1 -0
  65. package/dist/cjs/{src/core → core}/RoutingEngine.d.ts +35 -5
  66. package/dist/cjs/core/RoutingEngine.d.ts.map +1 -0
  67. package/dist/cjs/{src/core → core}/RoutingEngine.js +360 -98
  68. package/dist/cjs/core/RoutingEngine.js.map +1 -0
  69. package/dist/{src → cjs}/core/SessionManager.d.ts +9 -1
  70. package/dist/cjs/core/SessionManager.d.ts.map +1 -0
  71. package/dist/cjs/{src/core → core}/SessionManager.js +27 -5
  72. package/dist/cjs/core/SessionManager.js.map +1 -0
  73. package/dist/cjs/core/Step.d.ts +170 -0
  74. package/dist/cjs/core/Step.d.ts.map +1 -0
  75. package/dist/cjs/core/Step.js +448 -0
  76. package/dist/cjs/core/Step.js.map +1 -0
  77. package/dist/cjs/core/ToolManager.d.ts +234 -0
  78. package/dist/cjs/core/ToolManager.d.ts.map +1 -0
  79. package/dist/cjs/core/ToolManager.js +1117 -0
  80. package/dist/cjs/core/ToolManager.js.map +1 -0
  81. package/dist/{src → cjs}/index.d.ts +5 -3
  82. package/dist/cjs/index.d.ts.map +1 -0
  83. package/dist/cjs/{src/index.js → index.js} +16 -3
  84. package/dist/cjs/index.js.map +1 -0
  85. package/dist/cjs/{src/providers → providers}/AnthropicProvider.js +18 -18
  86. package/dist/cjs/providers/AnthropicProvider.js.map +1 -0
  87. package/dist/{src → cjs}/providers/GeminiProvider.d.ts.map +1 -1
  88. package/dist/cjs/{src/providers → providers}/GeminiProvider.js +123 -51
  89. package/dist/cjs/providers/GeminiProvider.js.map +1 -0
  90. package/dist/cjs/{src/providers → providers}/OpenAIProvider.js +19 -19
  91. package/dist/cjs/providers/OpenAIProvider.js.map +1 -0
  92. package/dist/cjs/{src/providers → providers}/OpenRouterProvider.js +19 -19
  93. package/dist/cjs/providers/OpenRouterProvider.js.map +1 -0
  94. package/dist/cjs/providers/index.js.map +1 -0
  95. package/dist/cjs/{src/types → types}/agent.d.ts +12 -4
  96. package/dist/cjs/types/agent.d.ts.map +1 -0
  97. package/dist/cjs/types/agent.js.map +1 -0
  98. package/dist/{src → cjs}/types/ai.js.map +1 -1
  99. package/dist/cjs/types/history.js.map +1 -0
  100. package/dist/cjs/{src/types → types}/index.d.ts +5 -3
  101. package/dist/{src → cjs}/types/index.d.ts.map +1 -1
  102. package/dist/cjs/{src/types → types}/index.js +8 -1
  103. package/dist/cjs/types/index.js.map +1 -0
  104. package/dist/cjs/types/persistence.js.map +1 -0
  105. package/dist/cjs/{src/types → types}/route.d.ts +116 -15
  106. package/dist/cjs/types/route.d.ts.map +1 -0
  107. package/dist/cjs/{src/types → types}/route.js.map +1 -1
  108. package/dist/cjs/types/session.js.map +1 -0
  109. package/dist/cjs/types/template.d.ts +88 -0
  110. package/dist/cjs/types/template.d.ts.map +1 -0
  111. package/dist/cjs/types/tool.d.ts +130 -0
  112. package/dist/cjs/types/tool.d.ts.map +1 -0
  113. package/dist/cjs/types/tool.js +19 -0
  114. package/dist/cjs/types/tool.js.map +1 -0
  115. package/dist/cjs/utils/clone.js.map +1 -0
  116. package/dist/cjs/utils/condition.d.ts +38 -0
  117. package/dist/cjs/utils/condition.d.ts.map +1 -0
  118. package/dist/cjs/utils/condition.js +168 -0
  119. package/dist/cjs/utils/condition.js.map +1 -0
  120. package/dist/cjs/utils/event.js.map +1 -0
  121. package/dist/cjs/utils/history.js.map +1 -0
  122. package/dist/cjs/utils/id.js.map +1 -0
  123. package/dist/cjs/{src/utils → utils}/index.d.ts +3 -1
  124. package/dist/cjs/utils/index.d.ts.map +1 -0
  125. package/dist/cjs/{src/utils → utils}/index.js +12 -1
  126. package/dist/cjs/utils/index.js.map +1 -0
  127. package/dist/cjs/utils/json.d.ts +16 -0
  128. package/dist/cjs/utils/json.d.ts.map +1 -0
  129. package/dist/cjs/utils/json.js +47 -0
  130. package/dist/cjs/utils/json.js.map +1 -0
  131. package/dist/cjs/utils/logger.js.map +1 -0
  132. package/dist/{src → cjs}/utils/retry.d.ts +0 -3
  133. package/dist/cjs/utils/retry.d.ts.map +1 -0
  134. package/dist/cjs/{src/utils → utils}/retry.js +8 -7
  135. package/dist/cjs/utils/retry.js.map +1 -0
  136. package/dist/cjs/utils/session.js.map +1 -0
  137. package/dist/{src → cjs}/utils/template.d.ts +48 -0
  138. package/dist/cjs/utils/template.d.ts.map +1 -0
  139. package/dist/cjs/{src/utils → utils}/template.js +100 -0
  140. package/dist/cjs/utils/template.js.map +1 -0
  141. package/dist/constants/index.d.ts.map +1 -0
  142. package/dist/constants/index.js.map +1 -0
  143. package/dist/{cjs/src/core → core}/Agent.d.ts +25 -6
  144. package/dist/core/Agent.d.ts.map +1 -0
  145. package/dist/{src/core → core}/Agent.js +122 -38
  146. package/dist/core/Agent.js.map +1 -0
  147. package/dist/core/BatchExecutor.d.ts +353 -0
  148. package/dist/core/BatchExecutor.d.ts.map +1 -0
  149. package/dist/core/BatchExecutor.js +837 -0
  150. package/dist/core/BatchExecutor.js.map +1 -0
  151. package/dist/core/BatchPromptBuilder.d.ts +86 -0
  152. package/dist/core/BatchPromptBuilder.d.ts.map +1 -0
  153. package/dist/core/BatchPromptBuilder.js +197 -0
  154. package/dist/core/BatchPromptBuilder.js.map +1 -0
  155. package/dist/core/Events.d.ts.map +1 -0
  156. package/dist/core/Events.js.map +1 -0
  157. package/dist/core/PersistenceManager.d.ts.map +1 -0
  158. package/dist/core/PersistenceManager.js.map +1 -0
  159. package/dist/{cjs/src/core → core}/PromptComposer.d.ts +1 -1
  160. package/dist/core/PromptComposer.d.ts.map +1 -0
  161. package/dist/{src/core → core}/PromptComposer.js +45 -8
  162. package/dist/core/PromptComposer.js.map +1 -0
  163. package/dist/core/ResponseEngine.d.ts.map +1 -0
  164. package/dist/core/ResponseEngine.js +198 -0
  165. package/dist/core/ResponseEngine.js.map +1 -0
  166. package/dist/{cjs/src/core → core}/ResponseModal.d.ts +54 -3
  167. package/dist/core/ResponseModal.d.ts.map +1 -0
  168. package/dist/{src/core → core}/ResponseModal.js +807 -121
  169. package/dist/core/ResponseModal.js.map +1 -0
  170. package/dist/{cjs/src/core → core}/ResponsePipeline.d.ts +10 -6
  171. package/dist/core/ResponsePipeline.d.ts.map +1 -0
  172. package/dist/{src/core → core}/ResponsePipeline.js +60 -25
  173. package/dist/core/ResponsePipeline.js.map +1 -0
  174. package/dist/{cjs/src/core → core}/Route.d.ts +46 -10
  175. package/dist/core/Route.d.ts.map +1 -0
  176. package/dist/core/Route.js +537 -0
  177. package/dist/core/Route.js.map +1 -0
  178. package/dist/{src/core → core}/RoutingEngine.d.ts +35 -5
  179. package/dist/core/RoutingEngine.d.ts.map +1 -0
  180. package/dist/{src/core → core}/RoutingEngine.js +343 -81
  181. package/dist/core/RoutingEngine.js.map +1 -0
  182. package/dist/{cjs/src/core → core}/SessionManager.d.ts +9 -1
  183. package/dist/core/SessionManager.d.ts.map +1 -0
  184. package/dist/{src/core → core}/SessionManager.js +27 -5
  185. package/dist/core/SessionManager.js.map +1 -0
  186. package/dist/core/Step.d.ts +170 -0
  187. package/dist/core/Step.d.ts.map +1 -0
  188. package/dist/core/Step.js +444 -0
  189. package/dist/core/Step.js.map +1 -0
  190. package/dist/core/ToolManager.d.ts +234 -0
  191. package/dist/core/ToolManager.d.ts.map +1 -0
  192. package/dist/core/ToolManager.js +1111 -0
  193. package/dist/core/ToolManager.js.map +1 -0
  194. package/dist/{cjs/src/index.d.ts → index.d.ts} +5 -3
  195. package/dist/index.d.ts.map +1 -0
  196. package/dist/{src/index.js → index.js} +4 -1
  197. package/dist/index.js.map +1 -0
  198. package/dist/providers/AnthropicProvider.d.ts.map +1 -0
  199. package/dist/{src/providers → providers}/AnthropicProvider.js +17 -17
  200. package/dist/providers/AnthropicProvider.js.map +1 -0
  201. package/dist/providers/GeminiProvider.d.ts.map +1 -0
  202. package/dist/{src/providers → providers}/GeminiProvider.js +123 -51
  203. package/dist/providers/GeminiProvider.js.map +1 -0
  204. package/dist/providers/OpenAIProvider.d.ts.map +1 -0
  205. package/dist/{src/providers → providers}/OpenAIProvider.js +18 -18
  206. package/dist/providers/OpenAIProvider.js.map +1 -0
  207. package/dist/providers/OpenRouterProvider.d.ts.map +1 -0
  208. package/dist/{src/providers → providers}/OpenRouterProvider.js +18 -18
  209. package/dist/providers/OpenRouterProvider.js.map +1 -0
  210. package/dist/providers/index.d.ts.map +1 -0
  211. package/dist/providers/index.js.map +1 -0
  212. package/dist/{src/types → types}/agent.d.ts +12 -4
  213. package/dist/types/agent.d.ts.map +1 -0
  214. package/dist/types/agent.js.map +1 -0
  215. package/dist/types/ai.d.ts.map +1 -0
  216. package/dist/types/ai.js.map +1 -0
  217. package/dist/types/history.d.ts.map +1 -0
  218. package/dist/types/history.js.map +1 -0
  219. package/dist/{src/types → types}/index.d.ts +5 -3
  220. package/dist/types/index.d.ts.map +1 -0
  221. package/dist/{src/types → types}/index.js +2 -0
  222. package/dist/types/index.js.map +1 -0
  223. package/dist/types/persistence.d.ts.map +1 -0
  224. package/dist/types/persistence.js.map +1 -0
  225. package/dist/{src/types → types}/route.d.ts +116 -15
  226. package/dist/types/route.d.ts.map +1 -0
  227. package/dist/{src/types → types}/route.js.map +1 -1
  228. package/dist/types/routing.d.ts.map +1 -0
  229. package/dist/{cjs/src/types → types}/routing.js.map +1 -1
  230. package/dist/types/schema.d.ts.map +1 -0
  231. package/dist/{cjs/src/types → types}/schema.js.map +1 -1
  232. package/dist/types/session.d.ts.map +1 -0
  233. package/dist/{src/types → types}/session.js.map +1 -1
  234. package/dist/types/template.d.ts +88 -0
  235. package/dist/types/template.d.ts.map +1 -0
  236. package/dist/{cjs/src/types → types}/template.js.map +1 -1
  237. package/dist/types/tool.d.ts +130 -0
  238. package/dist/types/tool.d.ts.map +1 -0
  239. package/dist/types/tool.js +16 -0
  240. package/dist/types/tool.js.map +1 -0
  241. package/dist/utils/clone.d.ts.map +1 -0
  242. package/dist/utils/clone.js.map +1 -0
  243. package/dist/utils/condition.d.ts +38 -0
  244. package/dist/utils/condition.d.ts.map +1 -0
  245. package/dist/utils/condition.js +161 -0
  246. package/dist/utils/condition.js.map +1 -0
  247. package/dist/utils/event.d.ts.map +1 -0
  248. package/dist/utils/event.js.map +1 -0
  249. package/dist/utils/history.d.ts.map +1 -0
  250. package/dist/utils/history.js.map +1 -0
  251. package/dist/utils/id.d.ts.map +1 -0
  252. package/dist/utils/id.js.map +1 -0
  253. package/dist/{src/utils → utils}/index.d.ts +3 -1
  254. package/dist/utils/index.d.ts.map +1 -0
  255. package/dist/{src/utils → utils}/index.js +5 -1
  256. package/dist/utils/index.js.map +1 -0
  257. package/dist/utils/json.d.ts +16 -0
  258. package/dist/utils/json.d.ts.map +1 -0
  259. package/dist/utils/json.js +43 -0
  260. package/dist/utils/json.js.map +1 -0
  261. package/dist/utils/logger.d.ts.map +1 -0
  262. package/dist/utils/logger.js.map +1 -0
  263. package/dist/{cjs/src/utils → utils}/retry.d.ts +0 -3
  264. package/dist/utils/retry.d.ts.map +1 -0
  265. package/dist/{src/utils → utils}/retry.js +5 -4
  266. package/dist/utils/retry.js.map +1 -0
  267. package/dist/utils/session.d.ts.map +1 -0
  268. package/dist/utils/session.js.map +1 -0
  269. package/dist/{cjs/src/utils → utils}/template.d.ts +48 -0
  270. package/dist/utils/template.d.ts.map +1 -0
  271. package/dist/{src/utils → utils}/template.js +98 -0
  272. package/dist/utils/template.js.map +1 -0
  273. package/docs/CONTRIBUTING.md +40 -0
  274. package/docs/README.md +12 -5
  275. package/docs/api/README.md +295 -56
  276. package/docs/api/overview.md +272 -31
  277. package/docs/architecture/data-extraction-flow.md +363 -0
  278. package/docs/architecture/multi-step-execution.md +243 -0
  279. package/docs/core/agent/README.md +120 -5
  280. package/docs/core/agent/session-management.md +153 -6
  281. package/docs/core/ai-integration/prompt-composition.md +135 -0
  282. package/docs/core/ai-integration/response-processing.md +261 -4
  283. package/docs/core/conversation-flows/data-collection.md +143 -0
  284. package/docs/core/conversation-flows/routes.md +132 -2
  285. package/docs/core/conversation-flows/step-transitions.md +132 -0
  286. package/docs/core/conversation-flows/steps.md +112 -0
  287. package/docs/core/error-handling.md +831 -0
  288. package/docs/core/routing/intelligent-routing.md +118 -0
  289. package/docs/core/tools/tool-definition.md +684 -60
  290. package/docs/core/tools/tool-scoping.md +244 -53
  291. package/docs/guides/error-handling-patterns.md +578 -0
  292. package/docs/guides/getting-started/README.md +423 -31
  293. package/docs/guides/migration/README.md +23 -0
  294. package/docs/guides/migration/flexible-routing-conditions.md +375 -0
  295. package/docs/guides/migration/multi-step-execution.md +303 -0
  296. package/examples/advanced-patterns/knowledge-based-agent.ts +107 -30
  297. package/examples/advanced-patterns/persistent-onboarding.ts +70 -48
  298. package/examples/advanced-patterns/route-lifecycle-hooks.ts +82 -12
  299. package/examples/advanced-patterns/streaming-responses.ts +2 -2
  300. package/examples/ai-providers/anthropic-integration.ts +13 -9
  301. package/examples/ai-providers/openai-integration.ts +12 -8
  302. package/examples/condition-patterns/function-only-conditions.ts +365 -0
  303. package/examples/condition-patterns/mixed-array-conditions.ts +477 -0
  304. package/examples/condition-patterns/route-skipif-patterns.ts +468 -0
  305. package/examples/condition-patterns/step-skipif-patterns.ts +0 -0
  306. package/examples/condition-patterns/string-only-conditions.ts +296 -0
  307. package/examples/conversation-flows/completion-transitions.ts +48 -7
  308. package/examples/core-concepts/basic-agent.ts +158 -98
  309. package/examples/core-concepts/schema-driven-extraction.ts +43 -16
  310. package/examples/core-concepts/session-management.ts +117 -29
  311. package/examples/integrations/database-integration.ts +6 -6
  312. package/examples/integrations/healthcare-integration.ts +25 -39
  313. package/examples/integrations/search-integration.ts +8 -8
  314. package/examples/integrations/server-session-management.ts +11 -11
  315. package/examples/persistence/database-persistence.ts +15 -15
  316. package/examples/persistence/memory-sessions.ts +6 -6
  317. package/examples/persistence/redis-persistence.ts +7 -9
  318. package/examples/tools/basic-tools.ts +293 -89
  319. package/examples/tools/data-enrichment-tools.ts +189 -79
  320. package/package.json +6 -4
  321. package/src/adapters/PrismaAdapter.ts +3 -2
  322. package/src/adapters/RedisAdapter.ts +3 -3
  323. package/src/core/Agent.ts +152 -46
  324. package/src/core/BatchExecutor.ts +1156 -0
  325. package/src/core/BatchPromptBuilder.ts +275 -0
  326. package/src/core/PromptComposer.ts +53 -16
  327. package/src/core/ResponseEngine.ts +143 -4
  328. package/src/core/ResponseModal.ts +1035 -137
  329. package/src/core/ResponsePipeline.ts +99 -65
  330. package/src/core/Route.ts +262 -34
  331. package/src/core/RoutingEngine.ts +467 -120
  332. package/src/core/SessionManager.ts +39 -7
  333. package/src/core/Step.ts +338 -32
  334. package/src/core/ToolManager.ts +1394 -0
  335. package/src/index.ts +27 -3
  336. package/src/providers/AnthropicProvider.ts +17 -17
  337. package/src/providers/GeminiProvider.ts +129 -60
  338. package/src/providers/OpenAIProvider.ts +18 -18
  339. package/src/providers/OpenRouterProvider.ts +18 -18
  340. package/src/types/agent.ts +12 -4
  341. package/src/types/index.ts +25 -3
  342. package/src/types/route.ts +136 -15
  343. package/src/types/template.ts +70 -2
  344. package/src/types/tool.ts +116 -25
  345. package/src/utils/condition.ts +190 -0
  346. package/src/utils/index.ts +12 -0
  347. package/src/utils/json.ts +46 -0
  348. package/src/utils/retry.ts +5 -4
  349. package/src/utils/template.ts +109 -0
  350. package/dist/cjs/src/adapters/MemoryAdapter.d.ts.map +0 -1
  351. package/dist/cjs/src/adapters/MemoryAdapter.js.map +0 -1
  352. package/dist/cjs/src/adapters/MongoAdapter.d.ts.map +0 -1
  353. package/dist/cjs/src/adapters/MongoAdapter.js.map +0 -1
  354. package/dist/cjs/src/adapters/OpenSearchAdapter.d.ts.map +0 -1
  355. package/dist/cjs/src/adapters/OpenSearchAdapter.js.map +0 -1
  356. package/dist/cjs/src/adapters/PostgreSQLAdapter.d.ts.map +0 -1
  357. package/dist/cjs/src/adapters/PostgreSQLAdapter.js.map +0 -1
  358. package/dist/cjs/src/adapters/PrismaAdapter.d.ts.map +0 -1
  359. package/dist/cjs/src/adapters/PrismaAdapter.js.map +0 -1
  360. package/dist/cjs/src/adapters/RedisAdapter.d.ts.map +0 -1
  361. package/dist/cjs/src/adapters/RedisAdapter.js.map +0 -1
  362. package/dist/cjs/src/adapters/SQLiteAdapter.d.ts.map +0 -1
  363. package/dist/cjs/src/adapters/SQLiteAdapter.js.map +0 -1
  364. package/dist/cjs/src/adapters/index.d.ts.map +0 -1
  365. package/dist/cjs/src/adapters/index.js.map +0 -1
  366. package/dist/cjs/src/constants/index.d.ts.map +0 -1
  367. package/dist/cjs/src/constants/index.js.map +0 -1
  368. package/dist/cjs/src/core/Agent.d.ts.map +0 -1
  369. package/dist/cjs/src/core/Agent.js.map +0 -1
  370. package/dist/cjs/src/core/Events.d.ts.map +0 -1
  371. package/dist/cjs/src/core/Events.js.map +0 -1
  372. package/dist/cjs/src/core/PersistenceManager.d.ts.map +0 -1
  373. package/dist/cjs/src/core/PersistenceManager.js.map +0 -1
  374. package/dist/cjs/src/core/PromptComposer.d.ts.map +0 -1
  375. package/dist/cjs/src/core/PromptComposer.js.map +0 -1
  376. package/dist/cjs/src/core/ResponseEngine.d.ts.map +0 -1
  377. package/dist/cjs/src/core/ResponseEngine.js +0 -84
  378. package/dist/cjs/src/core/ResponseEngine.js.map +0 -1
  379. package/dist/cjs/src/core/ResponseModal.d.ts.map +0 -1
  380. package/dist/cjs/src/core/ResponseModal.js.map +0 -1
  381. package/dist/cjs/src/core/ResponsePipeline.d.ts.map +0 -1
  382. package/dist/cjs/src/core/ResponsePipeline.js.map +0 -1
  383. package/dist/cjs/src/core/Route.d.ts.map +0 -1
  384. package/dist/cjs/src/core/Route.js +0 -343
  385. package/dist/cjs/src/core/Route.js.map +0 -1
  386. package/dist/cjs/src/core/RoutingEngine.d.ts.map +0 -1
  387. package/dist/cjs/src/core/RoutingEngine.js.map +0 -1
  388. package/dist/cjs/src/core/SessionManager.d.ts.map +0 -1
  389. package/dist/cjs/src/core/SessionManager.js.map +0 -1
  390. package/dist/cjs/src/core/Step.d.ts +0 -96
  391. package/dist/cjs/src/core/Step.d.ts.map +0 -1
  392. package/dist/cjs/src/core/Step.js +0 -206
  393. package/dist/cjs/src/core/Step.js.map +0 -1
  394. package/dist/cjs/src/core/ToolExecutor.d.ts +0 -45
  395. package/dist/cjs/src/core/ToolExecutor.d.ts.map +0 -1
  396. package/dist/cjs/src/core/ToolExecutor.js +0 -84
  397. package/dist/cjs/src/core/ToolExecutor.js.map +0 -1
  398. package/dist/cjs/src/index.d.ts.map +0 -1
  399. package/dist/cjs/src/index.js.map +0 -1
  400. package/dist/cjs/src/providers/AnthropicProvider.d.ts.map +0 -1
  401. package/dist/cjs/src/providers/AnthropicProvider.js.map +0 -1
  402. package/dist/cjs/src/providers/GeminiProvider.d.ts.map +0 -1
  403. package/dist/cjs/src/providers/GeminiProvider.js.map +0 -1
  404. package/dist/cjs/src/providers/OpenAIProvider.d.ts.map +0 -1
  405. package/dist/cjs/src/providers/OpenAIProvider.js.map +0 -1
  406. package/dist/cjs/src/providers/OpenRouterProvider.d.ts.map +0 -1
  407. package/dist/cjs/src/providers/OpenRouterProvider.js.map +0 -1
  408. package/dist/cjs/src/providers/index.d.ts.map +0 -1
  409. package/dist/cjs/src/providers/index.js.map +0 -1
  410. package/dist/cjs/src/types/agent.d.ts.map +0 -1
  411. package/dist/cjs/src/types/agent.js.map +0 -1
  412. package/dist/cjs/src/types/ai.d.ts.map +0 -1
  413. package/dist/cjs/src/types/ai.js.map +0 -1
  414. package/dist/cjs/src/types/history.d.ts.map +0 -1
  415. package/dist/cjs/src/types/history.js.map +0 -1
  416. package/dist/cjs/src/types/index.d.ts.map +0 -1
  417. package/dist/cjs/src/types/index.js.map +0 -1
  418. package/dist/cjs/src/types/persistence.d.ts.map +0 -1
  419. package/dist/cjs/src/types/persistence.js.map +0 -1
  420. package/dist/cjs/src/types/route.d.ts.map +0 -1
  421. package/dist/cjs/src/types/routing.d.ts.map +0 -1
  422. package/dist/cjs/src/types/schema.d.ts.map +0 -1
  423. package/dist/cjs/src/types/session.d.ts.map +0 -1
  424. package/dist/cjs/src/types/session.js.map +0 -1
  425. package/dist/cjs/src/types/template.d.ts +0 -30
  426. package/dist/cjs/src/types/template.d.ts.map +0 -1
  427. package/dist/cjs/src/types/tool.d.ts +0 -60
  428. package/dist/cjs/src/types/tool.d.ts.map +0 -1
  429. package/dist/cjs/src/types/tool.js +0 -6
  430. package/dist/cjs/src/types/tool.js.map +0 -1
  431. package/dist/cjs/src/utils/clone.d.ts.map +0 -1
  432. package/dist/cjs/src/utils/clone.js.map +0 -1
  433. package/dist/cjs/src/utils/event.d.ts.map +0 -1
  434. package/dist/cjs/src/utils/event.js.map +0 -1
  435. package/dist/cjs/src/utils/history.d.ts.map +0 -1
  436. package/dist/cjs/src/utils/history.js.map +0 -1
  437. package/dist/cjs/src/utils/id.d.ts.map +0 -1
  438. package/dist/cjs/src/utils/id.js.map +0 -1
  439. package/dist/cjs/src/utils/index.d.ts.map +0 -1
  440. package/dist/cjs/src/utils/index.js.map +0 -1
  441. package/dist/cjs/src/utils/logger.d.ts.map +0 -1
  442. package/dist/cjs/src/utils/logger.js.map +0 -1
  443. package/dist/cjs/src/utils/retry.d.ts.map +0 -1
  444. package/dist/cjs/src/utils/retry.js.map +0 -1
  445. package/dist/cjs/src/utils/session.d.ts.map +0 -1
  446. package/dist/cjs/src/utils/session.js.map +0 -1
  447. package/dist/cjs/src/utils/template.d.ts.map +0 -1
  448. package/dist/cjs/src/utils/template.js.map +0 -1
  449. package/dist/src/adapters/MemoryAdapter.js.map +0 -1
  450. package/dist/src/adapters/MongoAdapter.js.map +0 -1
  451. package/dist/src/adapters/OpenSearchAdapter.js.map +0 -1
  452. package/dist/src/adapters/PostgreSQLAdapter.js.map +0 -1
  453. package/dist/src/adapters/PrismaAdapter.js.map +0 -1
  454. package/dist/src/adapters/RedisAdapter.js.map +0 -1
  455. package/dist/src/adapters/SQLiteAdapter.js.map +0 -1
  456. package/dist/src/adapters/index.js.map +0 -1
  457. package/dist/src/constants/index.js.map +0 -1
  458. package/dist/src/core/Agent.d.ts.map +0 -1
  459. package/dist/src/core/Agent.js.map +0 -1
  460. package/dist/src/core/Events.js.map +0 -1
  461. package/dist/src/core/PersistenceManager.js.map +0 -1
  462. package/dist/src/core/PromptComposer.d.ts.map +0 -1
  463. package/dist/src/core/PromptComposer.js.map +0 -1
  464. package/dist/src/core/ResponseEngine.js +0 -80
  465. package/dist/src/core/ResponseEngine.js.map +0 -1
  466. package/dist/src/core/ResponseModal.d.ts.map +0 -1
  467. package/dist/src/core/ResponseModal.js.map +0 -1
  468. package/dist/src/core/ResponsePipeline.d.ts.map +0 -1
  469. package/dist/src/core/ResponsePipeline.js.map +0 -1
  470. package/dist/src/core/Route.d.ts.map +0 -1
  471. package/dist/src/core/Route.js +0 -339
  472. package/dist/src/core/Route.js.map +0 -1
  473. package/dist/src/core/RoutingEngine.d.ts.map +0 -1
  474. package/dist/src/core/RoutingEngine.js.map +0 -1
  475. package/dist/src/core/SessionManager.d.ts.map +0 -1
  476. package/dist/src/core/SessionManager.js.map +0 -1
  477. package/dist/src/core/Step.d.ts +0 -96
  478. package/dist/src/core/Step.d.ts.map +0 -1
  479. package/dist/src/core/Step.js +0 -202
  480. package/dist/src/core/Step.js.map +0 -1
  481. package/dist/src/core/ToolExecutor.d.ts +0 -45
  482. package/dist/src/core/ToolExecutor.d.ts.map +0 -1
  483. package/dist/src/core/ToolExecutor.js +0 -80
  484. package/dist/src/core/ToolExecutor.js.map +0 -1
  485. package/dist/src/index.d.ts.map +0 -1
  486. package/dist/src/index.js.map +0 -1
  487. package/dist/src/providers/AnthropicProvider.js.map +0 -1
  488. package/dist/src/providers/GeminiProvider.js.map +0 -1
  489. package/dist/src/providers/OpenAIProvider.js.map +0 -1
  490. package/dist/src/providers/OpenRouterProvider.js.map +0 -1
  491. package/dist/src/providers/index.js.map +0 -1
  492. package/dist/src/types/agent.d.ts.map +0 -1
  493. package/dist/src/types/agent.js.map +0 -1
  494. package/dist/src/types/history.js.map +0 -1
  495. package/dist/src/types/index.js.map +0 -1
  496. package/dist/src/types/persistence.js.map +0 -1
  497. package/dist/src/types/route.d.ts.map +0 -1
  498. package/dist/src/types/template.d.ts +0 -30
  499. package/dist/src/types/template.d.ts.map +0 -1
  500. package/dist/src/types/tool.d.ts +0 -60
  501. package/dist/src/types/tool.d.ts.map +0 -1
  502. package/dist/src/types/tool.js +0 -5
  503. package/dist/src/types/tool.js.map +0 -1
  504. package/dist/src/utils/clone.js.map +0 -1
  505. package/dist/src/utils/event.js.map +0 -1
  506. package/dist/src/utils/history.js.map +0 -1
  507. package/dist/src/utils/id.js.map +0 -1
  508. package/dist/src/utils/index.d.ts.map +0 -1
  509. package/dist/src/utils/index.js.map +0 -1
  510. package/dist/src/utils/logger.js.map +0 -1
  511. package/dist/src/utils/retry.d.ts.map +0 -1
  512. package/dist/src/utils/retry.js.map +0 -1
  513. package/dist/src/utils/session.js.map +0 -1
  514. package/dist/src/utils/template.d.ts.map +0 -1
  515. package/dist/src/utils/template.js.map +0 -1
  516. package/docs/core/tools/tool-execution.md +0 -815
  517. package/src/core/ToolExecutor.ts +0 -126
  518. /package/dist/{cjs/src/adapters → adapters}/MemoryAdapter.d.ts +0 -0
  519. /package/dist/{src/adapters → adapters}/MemoryAdapter.js +0 -0
  520. /package/dist/{cjs/src/adapters → adapters}/MongoAdapter.d.ts +0 -0
  521. /package/dist/{src/adapters → adapters}/MongoAdapter.js +0 -0
  522. /package/dist/{cjs/src/adapters → adapters}/OpenSearchAdapter.d.ts +0 -0
  523. /package/dist/{src/adapters → adapters}/OpenSearchAdapter.js +0 -0
  524. /package/dist/{cjs/src/adapters → adapters}/PostgreSQLAdapter.d.ts +0 -0
  525. /package/dist/{src/adapters → adapters}/PostgreSQLAdapter.js +0 -0
  526. /package/dist/{cjs/src/adapters → adapters}/PrismaAdapter.d.ts +0 -0
  527. /package/dist/{cjs/src/adapters → adapters}/RedisAdapter.d.ts +0 -0
  528. /package/dist/{cjs/src/adapters → adapters}/SQLiteAdapter.d.ts +0 -0
  529. /package/dist/{src/adapters → adapters}/SQLiteAdapter.js +0 -0
  530. /package/dist/{cjs/src/adapters → adapters}/index.d.ts +0 -0
  531. /package/dist/{src/adapters → adapters}/index.js +0 -0
  532. /package/dist/{src → cjs}/adapters/MemoryAdapter.d.ts +0 -0
  533. /package/dist/{src → cjs}/adapters/MemoryAdapter.d.ts.map +0 -0
  534. /package/dist/cjs/{src/adapters → adapters}/MemoryAdapter.js +0 -0
  535. /package/dist/{src → cjs}/adapters/MongoAdapter.d.ts +0 -0
  536. /package/dist/{src → cjs}/adapters/MongoAdapter.d.ts.map +0 -0
  537. /package/dist/cjs/{src/adapters → adapters}/MongoAdapter.js +0 -0
  538. /package/dist/{src → cjs}/adapters/OpenSearchAdapter.d.ts +0 -0
  539. /package/dist/{src → cjs}/adapters/OpenSearchAdapter.d.ts.map +0 -0
  540. /package/dist/cjs/{src/adapters → adapters}/OpenSearchAdapter.js +0 -0
  541. /package/dist/{src → cjs}/adapters/PostgreSQLAdapter.d.ts +0 -0
  542. /package/dist/{src → cjs}/adapters/PostgreSQLAdapter.d.ts.map +0 -0
  543. /package/dist/cjs/{src/adapters → adapters}/PostgreSQLAdapter.js +0 -0
  544. /package/dist/{src → cjs}/adapters/PrismaAdapter.d.ts +0 -0
  545. /package/dist/{src → cjs}/adapters/RedisAdapter.d.ts +0 -0
  546. /package/dist/{src → cjs}/adapters/RedisAdapter.d.ts.map +0 -0
  547. /package/dist/{src → cjs}/adapters/SQLiteAdapter.d.ts +0 -0
  548. /package/dist/{src → cjs}/adapters/SQLiteAdapter.d.ts.map +0 -0
  549. /package/dist/cjs/{src/adapters → adapters}/SQLiteAdapter.js +0 -0
  550. /package/dist/{src → cjs}/adapters/index.d.ts +0 -0
  551. /package/dist/{src → cjs}/adapters/index.d.ts.map +0 -0
  552. /package/dist/cjs/{src/adapters → adapters}/index.js +0 -0
  553. /package/dist/cjs/{src/constants → constants}/index.d.ts +0 -0
  554. /package/dist/{src → cjs}/constants/index.d.ts.map +0 -0
  555. /package/dist/cjs/{src/constants → constants}/index.js +0 -0
  556. /package/dist/cjs/{src/core → core}/Events.d.ts +0 -0
  557. /package/dist/{src → cjs}/core/Events.d.ts.map +0 -0
  558. /package/dist/cjs/{src/core → core}/Events.js +0 -0
  559. /package/dist/cjs/{src/core → core}/PersistenceManager.d.ts +0 -0
  560. /package/dist/{src → cjs}/core/PersistenceManager.d.ts.map +0 -0
  561. /package/dist/cjs/{src/core → core}/PersistenceManager.js +0 -0
  562. /package/dist/cjs/{src/core → core}/ResponseEngine.d.ts +0 -0
  563. /package/dist/cjs/{src/providers → providers}/AnthropicProvider.d.ts +0 -0
  564. /package/dist/{src → cjs}/providers/AnthropicProvider.d.ts.map +0 -0
  565. /package/dist/cjs/{src/providers → providers}/GeminiProvider.d.ts +0 -0
  566. /package/dist/cjs/{src/providers → providers}/OpenAIProvider.d.ts +0 -0
  567. /package/dist/{src → cjs}/providers/OpenAIProvider.d.ts.map +0 -0
  568. /package/dist/cjs/{src/providers → providers}/OpenRouterProvider.d.ts +0 -0
  569. /package/dist/{src → cjs}/providers/OpenRouterProvider.d.ts.map +0 -0
  570. /package/dist/cjs/{src/providers → providers}/index.d.ts +0 -0
  571. /package/dist/{src → cjs}/providers/index.d.ts.map +0 -0
  572. /package/dist/cjs/{src/providers → providers}/index.js +0 -0
  573. /package/dist/cjs/{src/types → types}/agent.js +0 -0
  574. /package/dist/cjs/{src/types → types}/ai.d.ts +0 -0
  575. /package/dist/{src → cjs}/types/ai.d.ts.map +0 -0
  576. /package/dist/cjs/{src/types → types}/ai.js +0 -0
  577. /package/dist/cjs/{src/types → types}/history.d.ts +0 -0
  578. /package/dist/{src → cjs}/types/history.d.ts.map +0 -0
  579. /package/dist/cjs/{src/types → types}/history.js +0 -0
  580. /package/dist/cjs/{src/types → types}/persistence.d.ts +0 -0
  581. /package/dist/{src → cjs}/types/persistence.d.ts.map +0 -0
  582. /package/dist/cjs/{src/types → types}/persistence.js +0 -0
  583. /package/dist/cjs/{src/types → types}/route.js +0 -0
  584. /package/dist/cjs/{src/types → types}/routing.d.ts +0 -0
  585. /package/dist/{src → cjs}/types/routing.d.ts.map +0 -0
  586. /package/dist/cjs/{src/types → types}/routing.js +0 -0
  587. /package/dist/{src → cjs}/types/routing.js.map +0 -0
  588. /package/dist/cjs/{src/types → types}/schema.d.ts +0 -0
  589. /package/dist/{src → cjs}/types/schema.d.ts.map +0 -0
  590. /package/dist/cjs/{src/types → types}/schema.js +0 -0
  591. /package/dist/{src → cjs}/types/schema.js.map +0 -0
  592. /package/dist/cjs/{src/types → types}/session.d.ts +0 -0
  593. /package/dist/{src → cjs}/types/session.d.ts.map +0 -0
  594. /package/dist/cjs/{src/types → types}/session.js +0 -0
  595. /package/dist/cjs/{src/types → types}/template.js +0 -0
  596. /package/dist/{src → cjs}/types/template.js.map +0 -0
  597. /package/dist/cjs/{src/utils → utils}/clone.d.ts +0 -0
  598. /package/dist/{src → cjs}/utils/clone.d.ts.map +0 -0
  599. /package/dist/cjs/{src/utils → utils}/clone.js +0 -0
  600. /package/dist/cjs/{src/utils → utils}/event.d.ts +0 -0
  601. /package/dist/{src → cjs}/utils/event.d.ts.map +0 -0
  602. /package/dist/cjs/{src/utils → utils}/event.js +0 -0
  603. /package/dist/cjs/{src/utils → utils}/history.d.ts +0 -0
  604. /package/dist/{src → cjs}/utils/history.d.ts.map +0 -0
  605. /package/dist/cjs/{src/utils → utils}/history.js +0 -0
  606. /package/dist/cjs/{src/utils → utils}/id.d.ts +0 -0
  607. /package/dist/{src → cjs}/utils/id.d.ts.map +0 -0
  608. /package/dist/cjs/{src/utils → utils}/id.js +0 -0
  609. /package/dist/cjs/{src/utils → utils}/logger.d.ts +0 -0
  610. /package/dist/{src → cjs}/utils/logger.d.ts.map +0 -0
  611. /package/dist/cjs/{src/utils → utils}/logger.js +0 -0
  612. /package/dist/cjs/{src/utils → utils}/session.d.ts +0 -0
  613. /package/dist/{src → cjs}/utils/session.d.ts.map +0 -0
  614. /package/dist/cjs/{src/utils → utils}/session.js +0 -0
  615. /package/dist/{src/constants → constants}/index.d.ts +0 -0
  616. /package/dist/{src/constants → constants}/index.js +0 -0
  617. /package/dist/{src/core → core}/Events.d.ts +0 -0
  618. /package/dist/{src/core → core}/Events.js +0 -0
  619. /package/dist/{src/core → core}/PersistenceManager.d.ts +0 -0
  620. /package/dist/{src/core → core}/PersistenceManager.js +0 -0
  621. /package/dist/{src/core → core}/ResponseEngine.d.ts +0 -0
  622. /package/dist/{src/providers → providers}/AnthropicProvider.d.ts +0 -0
  623. /package/dist/{src/providers → providers}/GeminiProvider.d.ts +0 -0
  624. /package/dist/{src/providers → providers}/OpenAIProvider.d.ts +0 -0
  625. /package/dist/{src/providers → providers}/OpenRouterProvider.d.ts +0 -0
  626. /package/dist/{src/providers → providers}/index.d.ts +0 -0
  627. /package/dist/{src/providers → providers}/index.js +0 -0
  628. /package/dist/{src/types → types}/agent.js +0 -0
  629. /package/dist/{src/types → types}/ai.d.ts +0 -0
  630. /package/dist/{src/types → types}/ai.js +0 -0
  631. /package/dist/{src/types → types}/history.d.ts +0 -0
  632. /package/dist/{src/types → types}/history.js +0 -0
  633. /package/dist/{src/types → types}/persistence.d.ts +0 -0
  634. /package/dist/{src/types → types}/persistence.js +0 -0
  635. /package/dist/{src/types → types}/route.js +0 -0
  636. /package/dist/{src/types → types}/routing.d.ts +0 -0
  637. /package/dist/{src/types → types}/routing.js +0 -0
  638. /package/dist/{src/types → types}/schema.d.ts +0 -0
  639. /package/dist/{src/types → types}/schema.js +0 -0
  640. /package/dist/{src/types → types}/session.d.ts +0 -0
  641. /package/dist/{src/types → types}/session.js +0 -0
  642. /package/dist/{src/types → types}/template.js +0 -0
  643. /package/dist/{src/utils → utils}/clone.d.ts +0 -0
  644. /package/dist/{src/utils → utils}/clone.js +0 -0
  645. /package/dist/{src/utils → utils}/event.d.ts +0 -0
  646. /package/dist/{src/utils → utils}/event.js +0 -0
  647. /package/dist/{src/utils → utils}/history.d.ts +0 -0
  648. /package/dist/{src/utils → utils}/history.js +0 -0
  649. /package/dist/{src/utils → utils}/id.d.ts +0 -0
  650. /package/dist/{src/utils → utils}/id.js +0 -0
  651. /package/dist/{src/utils → utils}/logger.d.ts +0 -0
  652. /package/dist/{src/utils → utils}/logger.js +0 -0
  653. /package/dist/{src/utils → utils}/session.d.ts +0 -0
  654. /package/dist/{src/utils → utils}/session.js +0 -0
@@ -5,15 +5,14 @@ import type {
5
5
  RoutingDecision,
6
6
  SessionState,
7
7
  AiProvider,
8
+ TemplateContext,
8
9
  } from "../types";
9
10
  import { enterRoute, mergeCollected } from "../utils";
10
11
  import type { Route } from "./Route";
11
12
  import type { Step } from "./Step";
12
13
  import { PromptComposer } from "./PromptComposer";
13
- import { getLastMessageFromHistory } from "../utils/event";
14
- import { logger } from "../utils/logger";
15
- import { render } from "../utils/template";
16
14
  import { END_ROUTE_ID } from "../constants";
15
+ import { createTemplateContext, getLastMessageFromHistory, logger } from "../utils";
17
16
 
18
17
  export interface CandidateStep<TContext = unknown, TData = unknown> {
19
18
  step: Step<TContext, TData>;
@@ -55,6 +54,7 @@ export interface BuildStepSelectionPromptParams<
55
54
  agentOptions?: AgentOptions<TContext, TData>;
56
55
  context?: TContext;
57
56
  session?: SessionState<TData>;
57
+ stepConditionContext?: string[]; // AI context strings from step conditions
58
58
  }
59
59
 
60
60
  export interface BuildRoutingPromptParams<TContext = unknown, TData = unknown> {
@@ -65,11 +65,35 @@ export interface BuildRoutingPromptParams<TContext = unknown, TData = unknown> {
65
65
  session?: SessionState<TData>;
66
66
  activeRouteSteps?: Step<TContext, TData>[];
67
67
  context?: TContext;
68
+ routeConditionContext?: string[]; // AI context strings from route conditions
68
69
  }
69
70
 
70
71
  export class RoutingEngine<TContext = unknown, TData = unknown> {
71
72
  constructor(private readonly options?: RoutingEngineOptions) { }
72
73
 
74
+ /**
75
+ * Enter a route if not already in it, merging initial data
76
+ * @private
77
+ */
78
+ private enterRouteIfNeeded(
79
+ session: SessionState<TData>,
80
+ route: Route<TContext, TData>
81
+ ): SessionState<TData> {
82
+ if (!session.currentRoute || session.currentRoute.id !== route.id) {
83
+ let updatedSession = enterRoute(session, route.id, route.title);
84
+ if (route.initialData) {
85
+ updatedSession = mergeCollected(updatedSession, route.initialData);
86
+ logger.debug(
87
+ `[RoutingEngine] Merged initial data for route ${route.title}:`,
88
+ route.initialData
89
+ );
90
+ }
91
+ logger.debug(`[RoutingEngine] Entered route: ${route.title}`);
92
+ return updatedSession;
93
+ }
94
+ return session;
95
+ }
96
+
73
97
  /**
74
98
  * Optimized decision for single-route scenarios
75
99
  * Skips route scoring and only does step selection
@@ -94,35 +118,28 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
94
118
  const { route, session, history, agentOptions, provider, context, signal } =
95
119
  params;
96
120
 
97
- let updatedSession = session;
98
121
  const selectedRoute = route;
99
122
 
100
- // Check if this single route is complete
101
- const completedRoutes = route.isComplete(session.data || {}) ? [route] : [];
123
+ // Enter route if not already in it (this may merge initial data)
124
+ const updatedSession = this.enterRouteIfNeeded(session, route);
102
125
 
103
- // Enter route if not already in it
104
- if (!session.currentRoute || session.currentRoute.id !== route.id) {
105
- updatedSession = enterRoute(session, route.id, route.title);
106
- if (route.initialData) {
107
- updatedSession = mergeCollected(updatedSession, route.initialData);
108
- logger.debug(
109
- `[RoutingEngine] Single-route: Merged initial data:`,
110
- route.initialData
111
- );
112
- }
113
- logger.debug(
114
- `[RoutingEngine] Single-route: Entered route: ${route.title}`
115
- );
116
- }
126
+ // Check if this single route is complete (use updated session data)
127
+ const completedRoutes = route.isComplete(updatedSession.data || {}) ? [route] : [];
117
128
 
118
- // Get candidate steps
129
+ // Get candidate steps using new condition evaluation
130
+ const templateContext = createTemplateContext({
131
+ context,
132
+ session: updatedSession,
133
+ history,
134
+ data: updatedSession.data
135
+ });
119
136
  const currentStep = updatedSession.currentStep
120
137
  ? route.getStep(updatedSession.currentStep.id)
121
138
  : undefined;
122
- const candidates = this.getCandidateSteps(
139
+ const candidates = await this.getCandidateStepsWithConditions(
123
140
  route,
124
141
  currentStep,
125
- updatedSession.data || {}
142
+ templateContext
126
143
  );
127
144
 
128
145
  if (candidates.length === 0) {
@@ -130,12 +147,13 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
130
147
  return { selectedRoute, session: updatedSession };
131
148
  }
132
149
 
133
- // If only one candidate, check if route is complete
150
+ // If only one candidate, check if it's a completion marker
134
151
  if (candidates.length === 1) {
135
- const isRouteComplete = candidates[0].isRouteComplete;
136
- if (isRouteComplete) {
152
+ const candidate = candidates[0];
153
+
154
+ if (candidate.isRouteComplete) {
137
155
  logger.debug(
138
- `[RoutingEngine] Single-route: Route complete - all data collected, END_ROUTE reached`
156
+ `[RoutingEngine] Single-route: Route complete - all required fields collected or END_ROUTE reached`
139
157
  );
140
158
  // Don't return a selectedStep when route is complete - there's no step to enter
141
159
  return {
@@ -147,11 +165,11 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
147
165
  };
148
166
  } else {
149
167
  logger.debug(
150
- `[RoutingEngine] Single-route: Only one valid step: ${candidates[0].step.id}`
168
+ `[RoutingEngine] Single-route: Only one valid step: ${candidate.step.id}`
151
169
  );
152
170
  return {
153
171
  selectedRoute,
154
- selectedStep: candidates[0].step,
172
+ selectedStep: candidate.step,
155
173
  session: updatedSession,
156
174
  isRouteComplete: false,
157
175
  completedRoutes,
@@ -159,8 +177,35 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
159
177
  }
160
178
  }
161
179
 
180
+ // No candidates means route is likely complete or has no valid next steps
181
+ if (candidates.length === 0) {
182
+ const dataComplete = route.isComplete(updatedSession.data || {});
183
+ logger.debug(
184
+ `[RoutingEngine] Single-route: No valid steps found - ` +
185
+ `(data: ${dataComplete ? 'complete' : 'incomplete'}, marking as ${dataComplete ? 'complete' : 'incomplete'})`
186
+ );
187
+ return {
188
+ selectedRoute,
189
+ selectedStep: undefined,
190
+ session: updatedSession,
191
+ isRouteComplete: dataComplete,
192
+ completedRoutes,
193
+ };
194
+ }
195
+
162
196
  // Multiple candidates - use AI to select best step
163
197
  const lastUserMessage = getLastMessageFromHistory(history);
198
+
199
+ // Collect AI context strings from step conditions
200
+ const stepConditionContext: string[] = [];
201
+ for (const candidate of candidates) {
202
+ const whenResult = await candidate.step.evaluateWhen(templateContext);
203
+ stepConditionContext.push(...whenResult.aiContextStrings);
204
+ }
205
+
206
+ // Check if any candidate is a completion marker (isRouteComplete = true)
207
+ const hasCompletionOption = candidates.some(c => c.isRouteComplete);
208
+
164
209
  const stepPrompt = await this.buildStepSelectionPrompt({
165
210
  route,
166
211
  currentStep,
@@ -171,10 +216,13 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
171
216
  agentOptions,
172
217
  context,
173
218
  session: updatedSession,
219
+ stepConditionContext,
220
+ includeEndRoute: hasCompletionOption,
174
221
  });
175
222
 
176
223
  const stepSchema = this.buildStepSelectionSchema(
177
- candidates.map((c) => c.step)
224
+ candidates.filter(c => !c.isRouteComplete).map((c) => c.step),
225
+ hasCompletionOption
178
226
  );
179
227
 
180
228
  const stepResult = await provider.generateMessage<
@@ -196,6 +244,25 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
196
244
  });
197
245
 
198
246
  const selectedStepId = stepResult.structured?.selectedStepId;
247
+
248
+ // Check if AI selected END_ROUTE
249
+ if (selectedStepId === END_ROUTE_ID) {
250
+ logger.debug(
251
+ `[RoutingEngine] Single-route: AI selected END_ROUTE - completing route`
252
+ );
253
+ logger.debug(
254
+ `[RoutingEngine] Single-route: Reasoning: ${stepResult.structured?.reasoning}`
255
+ );
256
+ return {
257
+ selectedRoute,
258
+ selectedStep: undefined,
259
+ responseDirectives: stepResult.structured?.responseDirectives,
260
+ session: updatedSession,
261
+ isRouteComplete: true,
262
+ completedRoutes,
263
+ };
264
+ }
265
+
199
266
  const selectedStep = candidates.find((c) => c.step.id === selectedStepId);
200
267
 
201
268
  if (selectedStep) {
@@ -221,24 +288,26 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
221
288
  }
222
289
 
223
290
  /**
224
- * Recursively traverse step chain to find first non-skipped step or END_ROUTE
291
+ * Recursively traverse step chain to find first non-skipped step or END_ROUTE using new condition evaluation
225
292
  * @private
226
293
  */
227
- private findFirstValidStepRecursive(
294
+ private async findFirstValidStepRecursiveWithConditions(
228
295
  currentStep: Step<TContext, TData>,
229
- data: Partial<TData>,
296
+ templateContext: TemplateContext<TContext, TData>,
230
297
  visited: Set<string>
231
- ): {
298
+ ): Promise<{
232
299
  step?: Step<TContext, TData>;
233
300
  isRouteComplete?: boolean;
234
- } {
301
+ aiContextStrings?: string[];
302
+ }> {
235
303
  // Prevent infinite loops
236
304
  if (visited.has(currentStep.id)) {
237
- return {};
305
+ return { aiContextStrings: [] };
238
306
  }
239
307
  visited.add(currentStep.id);
240
308
 
241
309
  const transitions = currentStep.getTransitions();
310
+ const allAiContextStrings: string[] = [];
242
311
 
243
312
  for (const transition of transitions) {
244
313
  const target = transition;
@@ -248,19 +317,25 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
248
317
  // Found END_ROUTE - route is complete
249
318
  return {
250
319
  isRouteComplete: true,
320
+ aiContextStrings: allAiContextStrings,
251
321
  };
252
322
  }
253
323
 
254
324
  if (!target) continue;
255
325
 
326
+ // Evaluate skipIf condition using new system
327
+ const skipResult = await target.evaluateSkipIf(templateContext);
328
+ allAiContextStrings.push(...skipResult.aiContextStrings);
329
+
256
330
  // If target should NOT be skipped, we found our step
257
- if (!target.shouldSkip(data)) {
331
+ if (!skipResult.shouldSkip) {
258
332
  logger.debug(
259
333
  `[RoutingEngine] Found valid step after skipping: ${target.id}`
260
334
  );
261
335
  return {
262
336
  step: target,
263
337
  isRouteComplete: false,
338
+ aiContextStrings: allAiContextStrings,
264
339
  };
265
340
  }
266
341
 
@@ -268,36 +343,69 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
268
343
  logger.debug(
269
344
  `[RoutingEngine] Skipping step ${target.id} (skipIf condition met), continuing traversal...`
270
345
  );
271
- const result = this.findFirstValidStepRecursive(target, data, visited);
346
+ const result = await this.findFirstValidStepRecursiveWithConditions(target, templateContext, visited);
347
+
348
+ // Collect AI context from recursive call
349
+ if (result.aiContextStrings) {
350
+ allAiContextStrings.push(...result.aiContextStrings);
351
+ }
272
352
 
273
353
  // If we found something (a valid step or END_ROUTE), return it
274
354
  if (result.step || result.isRouteComplete) {
275
- return result;
355
+ return {
356
+ ...result,
357
+ aiContextStrings: allAiContextStrings,
358
+ };
276
359
  }
277
360
  }
278
361
 
279
362
  // No valid steps or END_ROUTE found in this branch
280
- return {};
363
+ return { aiContextStrings: allAiContextStrings };
281
364
  }
282
365
 
366
+
367
+
283
368
  /**
284
- * Identify valid next candidate steps based on current step and collected data
369
+ * Identify valid next candidate steps using new condition evaluation system
285
370
  * Returns step with isRouteComplete flag if route is complete (all steps skipped + has END_ROUTE transition)
371
+ *
372
+ * NEW: Automatically completes route when all required fields are collected
286
373
  */
287
- getCandidateSteps(
374
+ async getCandidateStepsWithConditions(
288
375
  route: Route<TContext, TData>,
289
376
  currentStep: Step<TContext, TData> | undefined,
290
- data: Partial<TData>
291
- ): CandidateStep<TContext, TData>[] {
377
+ templateContext: TemplateContext<TContext, TData>
378
+ ): Promise<CandidateStep<TContext, TData>[]> {
292
379
  const candidates: CandidateStep<TContext, TData>[] = [];
380
+ const data = templateContext.data || {};
381
+
382
+ // Check if all required fields are collected
383
+ const allRequiredFieldsCollected = route.isComplete(data);
293
384
 
294
385
  if (!currentStep) {
386
+ // Entering route for the first time
387
+
388
+ // If all required fields already collected, route is immediately complete
389
+ if (allRequiredFieldsCollected) {
390
+ logger.debug(
391
+ `[RoutingEngine] Route ${route.title} complete on entry: all required fields already collected`
392
+ );
393
+ // Return a completion marker - use initial step with completion flag
394
+ candidates.push({
395
+ step: route.initialStep,
396
+ isRouteComplete: true,
397
+ });
398
+ return candidates;
399
+ }
400
+
295
401
  const initialStep = route.initialStep;
296
- if (initialStep.shouldSkip(data)) {
402
+ const skipResult = await initialStep.evaluateSkipIf(templateContext);
403
+
404
+ if (skipResult.shouldSkip) {
297
405
  // Initial step should be skipped - recursively traverse to find first non-skipped step or END_ROUTE
298
- const result = this.findFirstValidStepRecursive(
406
+ const result = await this.findFirstValidStepRecursiveWithConditions(
299
407
  initialStep,
300
- data,
408
+ templateContext,
301
409
  new Set<string>()
302
410
  );
303
411
 
@@ -327,6 +435,68 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
327
435
  return candidates;
328
436
  }
329
437
 
438
+ // Check if all required fields are now collected (may have been collected during this step)
439
+ if (allRequiredFieldsCollected) {
440
+ // Required fields are complete - check if we should continue for optional fields
441
+ const transitions = currentStep.getTransitions();
442
+ const optionalFieldCandidates: CandidateStep<TContext, TData>[] = [];
443
+
444
+ for (const transition of transitions) {
445
+ const target = transition;
446
+
447
+ // Check for END_ROUTE transition
448
+ if (target && target.id === END_ROUTE_ID) {
449
+ continue;
450
+ }
451
+
452
+ if (!target) continue;
453
+
454
+ // Check if this step collects only optional fields
455
+ const collectsOnlyOptional = target.collect && target.collect.length > 0 &&
456
+ target.collect.every(field =>
457
+ route.optionalFields?.includes(field)
458
+ );
459
+
460
+ if (collectsOnlyOptional) {
461
+ // This step collects optional fields - it's a candidate
462
+ const skipResult = await target.evaluateSkipIf(templateContext);
463
+ if (!skipResult.shouldSkip) {
464
+ optionalFieldCandidates.push({
465
+ step: target,
466
+ isRouteComplete: false,
467
+ });
468
+ }
469
+ }
470
+ }
471
+
472
+ // If we have optional field candidates, include them along with END_ROUTE option
473
+ if (optionalFieldCandidates.length > 0) {
474
+ logger.debug(
475
+ `[RoutingEngine] Required fields complete, but ${optionalFieldCandidates.length} optional field steps available`
476
+ );
477
+ // Add optional field steps as candidates
478
+ candidates.push(...optionalFieldCandidates);
479
+ // Also add END_ROUTE as a candidate (AI can choose to skip optional fields)
480
+ candidates.push({
481
+ step: currentStep,
482
+ isRouteComplete: true,
483
+ });
484
+ return candidates;
485
+ }
486
+
487
+ // No optional fields to collect - route is complete
488
+ logger.debug(
489
+ `[RoutingEngine] Route ${route.title} complete: all required fields collected, no optional fields remain`
490
+ );
491
+ return [
492
+ {
493
+ step: currentStep,
494
+ isRouteComplete: true,
495
+ },
496
+ ];
497
+ }
498
+
499
+ // Required fields not yet complete - continue normal step progression
330
500
  const transitions = currentStep.getTransitions();
331
501
  let hasEndRoute = false;
332
502
 
@@ -341,15 +511,17 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
341
511
 
342
512
  if (!target) continue;
343
513
 
344
- if (target.shouldSkip(data)) {
514
+ const skipResult = await target.evaluateSkipIf(templateContext);
515
+
516
+ if (skipResult.shouldSkip) {
345
517
  logger.debug(
346
518
  `[RoutingEngine] Skipping step ${target.id} (skipIf condition met)`
347
519
  );
348
520
 
349
521
  // Recursively traverse to find next valid step or END_ROUTE
350
- const result = this.findFirstValidStepRecursive(
522
+ const result = await this.findFirstValidStepRecursiveWithConditions(
351
523
  target,
352
- data,
524
+ templateContext,
353
525
  new Set<string>([currentStep.id]) // Already visited current step
354
526
  );
355
527
 
@@ -388,7 +560,8 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
388
560
  }
389
561
 
390
562
  // Otherwise, stay in current step if it's still valid
391
- if (!currentStep.shouldSkip(data)) {
563
+ const currentSkipResult = await currentStep.evaluateSkipIf(templateContext);
564
+ if (!currentSkipResult.shouldSkip) {
392
565
  candidates.push({
393
566
  step: currentStep,
394
567
  isRouteComplete: hasEndRoute || false,
@@ -464,32 +637,67 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
464
637
  }
465
638
 
466
639
  const lastUserMessage = getLastMessageFromHistory(history);
640
+ const templateContext = createTemplateContext({
641
+ context,
642
+ session,
643
+ history,
644
+ data: session.data
645
+ });
646
+
647
+ // Apply route filtering with new condition evaluation system
648
+ const skipIfResult = await this.filterRoutesBySkipIf(routes, templateContext);
649
+ const whenResult = await this.filterRoutesByWhen(skipIfResult.eligibleRoutes, templateContext);
650
+
651
+ // Collect all AI context strings from route conditions
652
+ const routeConditionContext = [...skipIfResult.aiContextStrings, ...whenResult.aiContextStrings];
653
+
654
+ // Use filtered routes for further processing
655
+ const eligibleRoutes = whenResult.eligibleRoutes;
656
+
657
+ logger.debug(`[RoutingEngine] Route filtering: ${routes.length} total → ${skipIfResult.eligibleRoutes.length} after skipIf → ${eligibleRoutes.length} after when`);
467
658
 
468
659
  let activeRouteSteps: Step<TContext, TData>[] | undefined;
469
660
  let activeRoute: Route<TContext, TData> | undefined;
470
661
  let isRouteComplete = false;
662
+ let updatedSession = session;
471
663
 
472
664
  if (session.currentRoute) {
473
- activeRoute = routes.find((r) => r.id === session.currentRoute?.id);
665
+ activeRoute = eligibleRoutes.find((r) => r.id === session.currentRoute?.id);
474
666
  if (activeRoute) {
475
667
  const currentStep = session.currentStep
476
668
  ? activeRoute.getStep(session.currentStep.id)
477
669
  : undefined;
478
- const candidates = this.getCandidateSteps(
670
+ const activeTemplateContext = createTemplateContext({
671
+ ...templateContext,
672
+ session: updatedSession,
673
+ data: updatedSession.data
674
+ });
675
+ const candidates = await this.getCandidateStepsWithConditions(
479
676
  activeRoute,
480
677
  currentStep,
481
- session.data || {}
678
+ activeTemplateContext
482
679
  );
483
680
 
484
681
  // Check if route is complete
682
+ // getCandidateStepsWithConditions now automatically handles completion when required fields are collected
485
683
  if (candidates.length === 1 && candidates[0].isRouteComplete) {
486
684
  isRouteComplete = true;
487
685
  logger.debug(
488
- `[RoutingEngine] Route ${activeRoute.title} is complete - all data collected`
686
+ `[RoutingEngine] Route ${activeRoute.title} is complete - all required fields collected or END_ROUTE reached`
489
687
  );
490
688
  // Don't include steps in routing if route is complete
491
689
  activeRouteSteps = undefined;
690
+ } else if (candidates.length === 0) {
691
+ // No candidates - check if data is complete
692
+ const dataComplete = activeRoute.isComplete(updatedSession.data || {});
693
+ isRouteComplete = dataComplete;
694
+ logger.debug(
695
+ `[RoutingEngine] Route ${activeRoute.title} has no valid steps - ` +
696
+ `marking as ${isRouteComplete ? 'complete' : 'incomplete'}`
697
+ );
698
+ activeRouteSteps = undefined;
492
699
  } else {
700
+ // Multiple candidates or single non-complete candidate
493
701
  activeRouteSteps = candidates.map((c) => c.step);
494
702
  logger.debug(
495
703
  `[RoutingEngine] Found ${activeRouteSteps.length} candidate steps for active route`
@@ -499,19 +707,20 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
499
707
  }
500
708
 
501
709
  const routingSchema = this.buildDynamicRoutingSchema(
502
- routes,
710
+ eligibleRoutes,
503
711
  undefined,
504
712
  activeRouteSteps
505
713
  );
506
714
 
507
715
  const routingPrompt = await this.buildRoutingPrompt({
508
716
  history,
509
- routes,
717
+ routes: eligibleRoutes,
510
718
  lastMessage: lastUserMessage,
511
719
  agentOptions,
512
720
  session,
513
721
  activeRouteSteps,
514
722
  context,
723
+ routeConditionContext, // Pass AI context strings from route conditions
515
724
  });
516
725
 
517
726
  const routingResult = await provider.generateMessage<
@@ -531,25 +740,34 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
531
740
  let selectedRoute: Route<TContext, TData> | undefined;
532
741
  let selectedStep: Step<TContext, TData> | undefined;
533
742
  let responseDirectives: string[] | undefined;
534
- let updatedSession = session;
535
743
 
536
744
  if (routingResult.structured?.routes) {
537
745
  // Use cross-route completion evaluation to select optimal route
538
746
  const optimalRoute = this.selectOptimalRoute(
539
- routes,
747
+ eligibleRoutes,
540
748
  updatedSession.data || {},
541
749
  routingResult.structured.routes
542
750
  );
543
751
 
544
- // Fall back to traditional scoring if no optimal route found
545
- selectedRoute = optimalRoute || (() => {
546
- const decision = this.decideRouteFromScores({
547
- context: routingResult.structured.context,
548
- routes: routingResult.structured.routes,
549
- responseDirectives: routingResult.structured.responseDirectives,
550
- });
551
- return routes.find((r) => r.id === decision.routeId);
552
- })();
752
+ // If no optimal route found, check why
753
+ if (!optimalRoute) {
754
+ if (eligibleRoutes.length === 0) {
755
+ // No routes passed filtering
756
+ logger.debug(
757
+ `[RoutingEngine] No eligible routes available - all routes filtered out`
758
+ );
759
+ selectedRoute = undefined;
760
+ } else {
761
+ // Routes exist but selectOptimalRoute returned undefined
762
+ // This means all routes are 100% complete
763
+ logger.debug(
764
+ `[RoutingEngine] No optimal route found - all ${eligibleRoutes.length} eligible routes are complete`
765
+ );
766
+ selectedRoute = undefined;
767
+ }
768
+ } else {
769
+ selectedRoute = optimalRoute;
770
+ }
553
771
 
554
772
  responseDirectives = routingResult.structured.responseDirectives;
555
773
 
@@ -573,27 +791,7 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
573
791
 
574
792
  if (selectedRoute) {
575
793
  logger.debug(`[RoutingEngine] Selected route: ${selectedRoute.title}`);
576
- if (
577
- !session.currentRoute ||
578
- session.currentRoute.id !== selectedRoute.id
579
- ) {
580
- updatedSession = enterRoute(
581
- session,
582
- selectedRoute.id,
583
- selectedRoute.title
584
- );
585
- if (selectedRoute.initialData) {
586
- updatedSession = mergeCollected(
587
- updatedSession,
588
- selectedRoute.initialData
589
- );
590
- logger.debug(
591
- `[RoutingEngine] Merged initial data:`,
592
- selectedRoute.initialData
593
- );
594
- }
595
- logger.debug(`[RoutingEngine] Entered route: ${selectedRoute.title}`);
596
- }
794
+ updatedSession = this.enterRouteIfNeeded(updatedSession, selectedRoute);
597
795
  }
598
796
  }
599
797
 
@@ -607,6 +805,72 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
607
805
  };
608
806
  }
609
807
 
808
+ /**
809
+ * Filter routes based on skipIf conditions
810
+ * @param routes - All available routes
811
+ * @param templateContext - Context for condition evaluation
812
+ * @returns Object with eligible routes and collected AI context strings
813
+ */
814
+ async filterRoutesBySkipIf(
815
+ routes: Route<TContext, TData>[],
816
+ templateContext: TemplateContext<TContext, TData>
817
+ ): Promise<{
818
+ eligibleRoutes: Route<TContext, TData>[];
819
+ aiContextStrings: string[];
820
+ }> {
821
+ const eligibleRoutes: Route<TContext, TData>[] = [];
822
+ const aiContextStrings: string[] = [];
823
+
824
+ for (const route of routes) {
825
+ const skipResult = await route.evaluateSkipIf(templateContext);
826
+
827
+ // Collect AI context strings from skipIf conditions
828
+ aiContextStrings.push(...skipResult.aiContextStrings);
829
+
830
+ // If route should not be skipped, it's eligible
831
+ if (!skipResult.programmaticResult) {
832
+ eligibleRoutes.push(route);
833
+ } else {
834
+ logger.debug(`[RoutingEngine] Skipping route ${route.title} (skipIf condition met)`);
835
+ }
836
+ }
837
+
838
+ return { eligibleRoutes, aiContextStrings };
839
+ }
840
+
841
+ /**
842
+ * Filter routes based on when conditions
843
+ * @param routes - Routes that passed skipIf filtering
844
+ * @param templateContext - Context for condition evaluation
845
+ * @returns Object with eligible routes and collected AI context strings
846
+ */
847
+ async filterRoutesByWhen(
848
+ routes: Route<TContext, TData>[],
849
+ templateContext: TemplateContext<TContext, TData>
850
+ ): Promise<{
851
+ eligibleRoutes: Route<TContext, TData>[];
852
+ aiContextStrings: string[];
853
+ }> {
854
+ const eligibleRoutes: Route<TContext, TData>[] = [];
855
+ const aiContextStrings: string[] = [];
856
+
857
+ for (const route of routes) {
858
+ const whenResult = await route.evaluateWhen(templateContext);
859
+
860
+ // Collect AI context strings from when conditions
861
+ aiContextStrings.push(...whenResult.aiContextStrings);
862
+
863
+ // If route has no programmatic conditions or they evaluate to true, it's eligible
864
+ if (!whenResult.hasProgrammaticConditions || whenResult.programmaticResult) {
865
+ eligibleRoutes.push(route);
866
+ } else {
867
+ logger.debug(`[RoutingEngine] Route ${route.title} not eligible (when condition not met)`);
868
+ }
869
+ }
870
+
871
+ return { eligibleRoutes, aiContextStrings };
872
+ }
873
+
610
874
  /**
611
875
  * Evaluate all routes for completion based on collected data
612
876
  * @param routes - All available routes
@@ -637,6 +901,7 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
637
901
  /**
638
902
  * Find the best route to continue based on completion status and user intent
639
903
  * Prioritizes routes that are partially complete but not finished
904
+ * IMPORTANT: Completed routes are excluded to prevent re-entering finished tasks
640
905
  * @param routes - All available routes
641
906
  * @param data - Currently collected agent-level data
642
907
  * @param routeScores - AI-generated route scores from routing decision
@@ -656,8 +921,12 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
656
921
  const aiScore = routeScores[route.id] || 0;
657
922
  const completionProgress = completionStatus.get(route.id) || 0;
658
923
 
659
- // Skip fully completed routes unless they have very high AI scores
660
- if (completionProgress >= 1.0 && aiScore < 80) {
924
+ // ALWAYS skip fully completed routes to prevent re-entering finished tasks
925
+ // Users should not be forced back into completed routes
926
+ if (completionProgress >= 1.0) {
927
+ logger.debug(
928
+ `[RoutingEngine] Excluding completed route: ${route.title} (100% complete)`
929
+ );
661
930
  continue;
662
931
  }
663
932
 
@@ -692,7 +961,7 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
692
961
  * @private
693
962
  */
694
963
  private async buildStepSelectionPrompt(
695
- params: BuildStepSelectionPromptParams<TContext, TData>
964
+ params: BuildStepSelectionPromptParams<TContext, TData> & { includeEndRoute?: boolean }
696
965
  ): Promise<string> {
697
966
  const {
698
967
  route,
@@ -704,8 +973,10 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
704
973
  agentOptions,
705
974
  context,
706
975
  session,
976
+ stepConditionContext,
977
+ includeEndRoute = false,
707
978
  } = params;
708
- const templateContext = { context, session, history };
979
+ const templateContext = createTemplateContext({ context, session, history });
709
980
  const pc = new PromptComposer<TContext, TData>(templateContext);
710
981
 
711
982
  // Add agent metadata
@@ -741,7 +1012,7 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
741
1012
  await pc.addInteractionHistory(history);
742
1013
  await pc.addLastMessage(lastMessage);
743
1014
 
744
- // Add candidate steps
1015
+ // Add candidate steps with condition context
745
1016
  const stepDescriptions = [];
746
1017
  for (const candidate of candidates) {
747
1018
  const idx = candidates.indexOf(candidate);
@@ -750,9 +1021,14 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
750
1021
  ` Description: ${candidate.step.description || "N/A"}`,
751
1022
  ];
752
1023
 
1024
+ // Add when condition context
753
1025
  if (candidate.step.when) {
754
- const renderedWhen = await render(candidate.step.when, templateContext);
755
- parts.push(` When this step should be completed: ${renderedWhen}`);
1026
+ const whenResult = await candidate.step.evaluateWhen(templateContext);
1027
+ if (whenResult.aiContextStrings.length > 0) {
1028
+ parts.push(` When conditions: ${whenResult.aiContextStrings.join(", ")}`);
1029
+ } else if (typeof candidate.step.when === 'string') {
1030
+ parts.push(` When this step should be completed: ${candidate.step.when}`);
1031
+ }
756
1032
  }
757
1033
 
758
1034
  if (candidate.step.requires && candidate.step.requires.length > 0) {
@@ -770,26 +1046,52 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
770
1046
  `Available Steps to Transition To:\n${stepDescriptions.join("\n\n")}`
771
1047
  );
772
1048
 
1049
+ // Add step condition context if available
1050
+ if (stepConditionContext && stepConditionContext.length > 0) {
1051
+ await pc.addInstruction(
1052
+ [
1053
+ "",
1054
+ "Additional step context from conditions:",
1055
+ ...stepConditionContext.map(ctx => `- ${ctx}`),
1056
+ "",
1057
+ "Consider this context when selecting the most appropriate step.",
1058
+ ].join("\n")
1059
+ );
1060
+ }
1061
+
773
1062
  // Add decision prompt
774
- await pc.addInstruction(
775
- [
776
- "Task: Decide which step to transition to based on:",
777
- "1. The user's current message and intent",
778
- "2. The conversation history and context",
779
- "3. The collected data we already have",
780
- "4. The conditions and requirements of each step",
781
- "5. The logical flow of the conversation",
782
- "",
783
- "Rules:",
784
- "- If a step has a condition, evaluate whether it's met based on context",
785
- "- If a step requires data we don't have, consider if we should collect it now",
786
- "- Choose the step that makes the most sense for moving the conversation forward",
787
- "- Steps with skipIf conditions that are met have already been filtered out",
1063
+ const decisionRules = [
1064
+ "Task: Decide which step to transition to based on:",
1065
+ "1. The user's current message and intent",
1066
+ "2. The conversation history and context",
1067
+ "3. The collected data we already have",
1068
+ "4. The conditions and requirements of each step",
1069
+ "5. The logical flow of the conversation",
1070
+ "",
1071
+ "Rules:",
1072
+ "- If a step has a condition, evaluate whether it's met based on context",
1073
+ "- If a step requires data we don't have, consider if we should collect it now",
1074
+ "- Choose the step that makes the most sense for moving the conversation forward",
1075
+ "- Steps with skipIf conditions that are met have already been filtered out",
1076
+ ];
1077
+
1078
+ if (includeEndRoute) {
1079
+ decisionRules.push(
788
1080
  "",
789
- "Return ONLY JSON matching the provided schema.",
790
- ].join("\n")
1081
+ `- You can select '${END_ROUTE_ID}' to complete this route if:`,
1082
+ " * All required data has been collected",
1083
+ " * The user's intent suggests they're done with this task",
1084
+ " * No further steps are needed to fulfill the user's request"
1085
+ );
1086
+ }
1087
+
1088
+ decisionRules.push(
1089
+ "",
1090
+ "Return ONLY JSON matching the provided schema."
791
1091
  );
792
1092
 
1093
+ await pc.addInstruction(decisionRules.join("\n"));
1094
+
793
1095
  return pc.build();
794
1096
  }
795
1097
 
@@ -798,8 +1100,16 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
798
1100
  * @private
799
1101
  */
800
1102
  private buildStepSelectionSchema(
801
- validSteps: Step<TContext, TData>[]
1103
+ validSteps: Step<TContext, TData>[],
1104
+ includeEndRoute: boolean = false
802
1105
  ): StructuredSchema {
1106
+ const stepIds = validSteps.map((s) => s.id);
1107
+
1108
+ // Add END_ROUTE as an option if requested (when required fields are complete)
1109
+ if (includeEndRoute) {
1110
+ stepIds.push(END_ROUTE_ID);
1111
+ }
1112
+
803
1113
  return {
804
1114
  description:
805
1115
  "Step transition decision based on conversation context and collected data",
@@ -813,8 +1123,10 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
813
1123
  selectedStepId: {
814
1124
  type: "string",
815
1125
  nullable: false,
816
- description: "The ID of the selected step to transition to",
817
- enum: validSteps.map((s) => s.id),
1126
+ description: includeEndRoute
1127
+ ? `The ID of the selected step to transition to, or '${END_ROUTE_ID}' to complete the route`
1128
+ : "The ID of the selected step to transition to",
1129
+ enum: stepIds,
818
1130
  },
819
1131
  responseDirectives: {
820
1132
  type: "array",
@@ -914,8 +1226,9 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
914
1226
  session,
915
1227
  activeRouteSteps,
916
1228
  context,
1229
+ routeConditionContext,
917
1230
  } = params;
918
- const templateContext = { context, session, history };
1231
+ const templateContext = createTemplateContext({ context, session, history });
919
1232
  const pc = new PromptComposer<TContext, TData>(templateContext);
920
1233
  if (agentOptions) {
921
1234
  await pc.addAgentMeta(agentOptions);
@@ -985,18 +1298,26 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
985
1298
  "",
986
1299
  "Available steps in active route (choose one to transition to):",
987
1300
  ];
1301
+ const activeStepConditionContext: string[] = [];
1302
+
988
1303
  for (const step of activeRouteSteps) {
989
1304
  const idx = activeRouteSteps.indexOf(step);
990
1305
  stepInfo.push(`${idx + 1}. Step: ${step.id}`);
991
1306
  if (step.description) {
992
1307
  stepInfo.push(` Description: ${step.description}`);
993
1308
  }
994
- const renderedWhen = await render(step.when, templateContext);
1309
+
1310
+ // Collect AI context from step conditions
995
1311
  if (step.when) {
996
- stepInfo.push(
997
- ` When this step should be completed: ${renderedWhen}`
998
- );
1312
+ const whenResult = await step.evaluateWhen(templateContext);
1313
+ if (whenResult.aiContextStrings.length > 0) {
1314
+ stepInfo.push(` When conditions: ${whenResult.aiContextStrings.join(", ")}`);
1315
+ activeStepConditionContext.push(...whenResult.aiContextStrings);
1316
+ } else if (typeof step.when === 'string') {
1317
+ stepInfo.push(` When this step should be completed: ${step.when}`);
1318
+ }
999
1319
  }
1320
+
1000
1321
  if (step.requires && step.requires.length > 0) {
1001
1322
  stepInfo.push(` Required data: ${step.requires.join(", ")}`);
1002
1323
  }
@@ -1013,12 +1334,38 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
1013
1334
  stepInfo.push("- The logical next step in the conversation");
1014
1335
  stepInfo.push("- Whether conditions for steps are met");
1015
1336
  await pc.addInstruction(stepInfo.join("\n"));
1337
+
1338
+ // Add active step condition context if available
1339
+ if (activeStepConditionContext.length > 0) {
1340
+ await pc.addInstruction(
1341
+ [
1342
+ "",
1343
+ "Additional context from step conditions:",
1344
+ ...activeStepConditionContext.map(ctx => `- ${ctx}`),
1345
+ "",
1346
+ "Use this context to inform your step selection decision.",
1347
+ ].join("\n")
1348
+ );
1349
+ }
1016
1350
  }
1017
1351
  }
1018
1352
 
1019
1353
  await pc.addInteractionHistory(history);
1020
1354
  await pc.addLastMessage(lastMessage);
1021
1355
  await pc.addRoutingOverview(routes);
1356
+
1357
+ // Add route condition context if available
1358
+ if (routeConditionContext && routeConditionContext.length > 0) {
1359
+ await pc.addInstruction(
1360
+ [
1361
+ "",
1362
+ "Additional routing context from route conditions:",
1363
+ ...routeConditionContext.map(ctx => `- ${ctx}`),
1364
+ "",
1365
+ "Consider this context when scoring routes for relevance.",
1366
+ ].join("\n")
1367
+ );
1368
+ }
1022
1369
  await pc.addInstruction(
1023
1370
  [
1024
1371
  "Scoring rules:",