@falai/agent 0.9.2 → 1.0.1

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 (628) hide show
  1. package/README.md +281 -42
  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/cjs/{src/core → core}/Agent.d.ts +16 -1
  33. package/dist/cjs/core/Agent.d.ts.map +1 -0
  34. package/dist/cjs/{src/core → core}/Agent.js +63 -2
  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 +850 -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 +217 -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 +211 -0
  52. package/dist/cjs/core/ResponseEngine.js.map +1 -0
  53. package/dist/{src → cjs}/core/ResponseModal.d.ts +45 -0
  54. package/dist/cjs/core/ResponseModal.d.ts.map +1 -0
  55. package/dist/cjs/{src/core → core}/ResponseModal.js +752 -74
  56. package/dist/cjs/core/ResponseModal.js.map +1 -0
  57. package/dist/{src → cjs}/core/ResponsePipeline.d.ts +2 -2
  58. package/dist/cjs/core/ResponsePipeline.d.ts.map +1 -0
  59. package/dist/cjs/{src/core → core}/ResponsePipeline.js +13 -6
  60. package/dist/cjs/core/ResponsePipeline.js.map +1 -0
  61. package/dist/{src → cjs}/core/Route.d.ts +34 -5
  62. package/dist/cjs/core/Route.d.ts.map +1 -0
  63. package/dist/cjs/{src/core → core}/Route.js +196 -19
  64. package/dist/cjs/core/Route.js.map +1 -0
  65. package/dist/cjs/{src/core → core}/RoutingEngine.d.ts +30 -5
  66. package/dist/cjs/core/RoutingEngine.d.ts.map +1 -0
  67. package/dist/cjs/{src/core → core}/RoutingEngine.js +330 -80
  68. package/dist/cjs/core/RoutingEngine.js.map +1 -0
  69. package/dist/cjs/core/SessionManager.js.map +1 -0
  70. package/dist/{src → cjs}/core/Step.d.ts +31 -10
  71. package/dist/cjs/core/Step.d.ts.map +1 -0
  72. package/dist/cjs/{src/core → core}/Step.js +105 -10
  73. package/dist/cjs/core/Step.js.map +1 -0
  74. package/dist/cjs/core/ToolManager.js.map +1 -0
  75. package/dist/{src → cjs}/index.d.ts +4 -1
  76. package/dist/cjs/index.d.ts.map +1 -0
  77. package/dist/cjs/{src/index.js → index.js} +12 -1
  78. package/dist/cjs/index.js.map +1 -0
  79. package/dist/cjs/{src/providers → providers}/AnthropicProvider.js +18 -18
  80. package/dist/cjs/providers/AnthropicProvider.js.map +1 -0
  81. package/dist/{src → cjs}/providers/GeminiProvider.d.ts.map +1 -1
  82. package/dist/cjs/{src/providers → providers}/GeminiProvider.js +123 -51
  83. package/dist/cjs/providers/GeminiProvider.js.map +1 -0
  84. package/dist/cjs/{src/providers → providers}/OpenAIProvider.js +19 -19
  85. package/dist/cjs/providers/OpenAIProvider.js.map +1 -0
  86. package/dist/cjs/{src/providers → providers}/OpenRouterProvider.js +19 -19
  87. package/dist/cjs/providers/OpenRouterProvider.js.map +1 -0
  88. package/dist/cjs/providers/index.js.map +1 -0
  89. package/dist/cjs/{src/types → types}/agent.d.ts +15 -3
  90. package/dist/cjs/types/agent.d.ts.map +1 -0
  91. package/dist/cjs/types/agent.js.map +1 -0
  92. package/dist/{src → cjs}/types/ai.js.map +1 -1
  93. package/dist/cjs/types/history.js.map +1 -0
  94. package/dist/cjs/{src/types → types}/index.d.ts +2 -1
  95. package/dist/{src → cjs}/types/index.d.ts.map +1 -1
  96. package/dist/cjs/{src/types → types}/index.js +6 -1
  97. package/dist/cjs/types/index.js.map +1 -0
  98. package/dist/cjs/types/persistence.js.map +1 -0
  99. package/dist/cjs/{src/types → types}/route.d.ts +111 -12
  100. package/dist/cjs/types/route.d.ts.map +1 -0
  101. package/dist/cjs/{src/types → types}/route.js.map +1 -1
  102. package/dist/cjs/types/session.js.map +1 -0
  103. package/dist/cjs/types/template.d.ts +88 -0
  104. package/dist/cjs/types/template.d.ts.map +1 -0
  105. package/dist/cjs/types/tool.js.map +1 -0
  106. package/dist/cjs/utils/clone.js.map +1 -0
  107. package/dist/cjs/utils/condition.d.ts +38 -0
  108. package/dist/cjs/utils/condition.d.ts.map +1 -0
  109. package/dist/cjs/utils/condition.js +168 -0
  110. package/dist/cjs/utils/condition.js.map +1 -0
  111. package/dist/cjs/utils/event.js.map +1 -0
  112. package/dist/cjs/utils/history.js.map +1 -0
  113. package/dist/cjs/utils/id.js.map +1 -0
  114. package/dist/cjs/{src/utils → utils}/index.d.ts +3 -1
  115. package/dist/cjs/utils/index.d.ts.map +1 -0
  116. package/dist/cjs/{src/utils → utils}/index.js +12 -1
  117. package/dist/cjs/utils/index.js.map +1 -0
  118. package/dist/cjs/utils/json.d.ts +16 -0
  119. package/dist/cjs/utils/json.d.ts.map +1 -0
  120. package/dist/cjs/utils/json.js +47 -0
  121. package/dist/cjs/utils/json.js.map +1 -0
  122. package/dist/cjs/utils/logger.js.map +1 -0
  123. package/dist/{src → cjs}/utils/retry.d.ts +0 -3
  124. package/dist/cjs/utils/retry.d.ts.map +1 -0
  125. package/dist/cjs/{src/utils → utils}/retry.js +8 -7
  126. package/dist/cjs/utils/retry.js.map +1 -0
  127. package/dist/cjs/utils/session.js.map +1 -0
  128. package/dist/{src → cjs}/utils/template.d.ts +48 -0
  129. package/dist/cjs/utils/template.d.ts.map +1 -0
  130. package/dist/cjs/{src/utils → utils}/template.js +100 -0
  131. package/dist/cjs/utils/template.js.map +1 -0
  132. package/dist/constants/index.d.ts.map +1 -0
  133. package/dist/constants/index.js.map +1 -0
  134. package/dist/{src/core → core}/Agent.d.ts +16 -1
  135. package/dist/core/Agent.d.ts.map +1 -0
  136. package/dist/{src/core → core}/Agent.js +64 -3
  137. package/dist/core/Agent.js.map +1 -0
  138. package/dist/core/BatchExecutor.d.ts +353 -0
  139. package/dist/core/BatchExecutor.d.ts.map +1 -0
  140. package/dist/core/BatchExecutor.js +845 -0
  141. package/dist/core/BatchExecutor.js.map +1 -0
  142. package/dist/core/BatchPromptBuilder.d.ts +86 -0
  143. package/dist/core/BatchPromptBuilder.d.ts.map +1 -0
  144. package/dist/core/BatchPromptBuilder.js +213 -0
  145. package/dist/core/BatchPromptBuilder.js.map +1 -0
  146. package/dist/core/Events.d.ts.map +1 -0
  147. package/dist/core/Events.js.map +1 -0
  148. package/dist/core/PersistenceManager.d.ts.map +1 -0
  149. package/dist/core/PersistenceManager.js.map +1 -0
  150. package/dist/{cjs/src/core → core}/PromptComposer.d.ts +1 -1
  151. package/dist/core/PromptComposer.d.ts.map +1 -0
  152. package/dist/{src/core → core}/PromptComposer.js +45 -8
  153. package/dist/core/PromptComposer.js.map +1 -0
  154. package/dist/core/ResponseEngine.d.ts.map +1 -0
  155. package/dist/core/ResponseEngine.js +207 -0
  156. package/dist/core/ResponseEngine.js.map +1 -0
  157. package/dist/{cjs/src/core → core}/ResponseModal.d.ts +45 -0
  158. package/dist/core/ResponseModal.d.ts.map +1 -0
  159. package/dist/{src/core → core}/ResponseModal.js +752 -74
  160. package/dist/core/ResponseModal.js.map +1 -0
  161. package/dist/{cjs/src/core → core}/ResponsePipeline.d.ts +2 -2
  162. package/dist/core/ResponsePipeline.d.ts.map +1 -0
  163. package/dist/{src/core → core}/ResponsePipeline.js +13 -6
  164. package/dist/core/ResponsePipeline.js.map +1 -0
  165. package/dist/{cjs/src/core → core}/Route.d.ts +34 -5
  166. package/dist/core/Route.d.ts.map +1 -0
  167. package/dist/{src/core → core}/Route.js +195 -18
  168. package/dist/core/Route.js.map +1 -0
  169. package/dist/{src/core → core}/RoutingEngine.d.ts +30 -5
  170. package/dist/core/RoutingEngine.d.ts.map +1 -0
  171. package/dist/{src/core → core}/RoutingEngine.js +310 -60
  172. package/dist/core/RoutingEngine.js.map +1 -0
  173. package/dist/core/SessionManager.d.ts.map +1 -0
  174. package/dist/core/SessionManager.js.map +1 -0
  175. package/dist/{cjs/src/core → core}/Step.d.ts +31 -10
  176. package/dist/core/Step.d.ts.map +1 -0
  177. package/dist/{src/core → core}/Step.js +104 -9
  178. package/dist/core/Step.js.map +1 -0
  179. package/dist/core/ToolManager.d.ts.map +1 -0
  180. package/dist/core/ToolManager.js.map +1 -0
  181. package/dist/{cjs/src/index.d.ts → index.d.ts} +4 -1
  182. package/dist/index.d.ts.map +1 -0
  183. package/dist/{src/index.js → index.js} +3 -0
  184. package/dist/index.js.map +1 -0
  185. package/dist/providers/AnthropicProvider.d.ts.map +1 -0
  186. package/dist/{src/providers → providers}/AnthropicProvider.js +17 -17
  187. package/dist/providers/AnthropicProvider.js.map +1 -0
  188. package/dist/providers/GeminiProvider.d.ts.map +1 -0
  189. package/dist/{src/providers → providers}/GeminiProvider.js +123 -51
  190. package/dist/providers/GeminiProvider.js.map +1 -0
  191. package/dist/providers/OpenAIProvider.d.ts.map +1 -0
  192. package/dist/{src/providers → providers}/OpenAIProvider.js +18 -18
  193. package/dist/providers/OpenAIProvider.js.map +1 -0
  194. package/dist/providers/OpenRouterProvider.d.ts.map +1 -0
  195. package/dist/{src/providers → providers}/OpenRouterProvider.js +18 -18
  196. package/dist/providers/OpenRouterProvider.js.map +1 -0
  197. package/dist/providers/index.d.ts.map +1 -0
  198. package/dist/providers/index.js.map +1 -0
  199. package/dist/{src/types → types}/agent.d.ts +15 -3
  200. package/dist/types/agent.d.ts.map +1 -0
  201. package/dist/types/agent.js.map +1 -0
  202. package/dist/types/ai.d.ts.map +1 -0
  203. package/dist/types/ai.js.map +1 -0
  204. package/dist/types/history.d.ts.map +1 -0
  205. package/dist/types/history.js.map +1 -0
  206. package/dist/{src/types → types}/index.d.ts +2 -1
  207. package/dist/types/index.d.ts.map +1 -0
  208. package/dist/{src/types → types}/index.js +1 -0
  209. package/dist/types/index.js.map +1 -0
  210. package/dist/types/persistence.d.ts.map +1 -0
  211. package/dist/types/persistence.js.map +1 -0
  212. package/dist/{src/types → types}/route.d.ts +111 -12
  213. package/dist/types/route.d.ts.map +1 -0
  214. package/dist/{src/types → types}/route.js.map +1 -1
  215. package/dist/types/routing.d.ts.map +1 -0
  216. package/dist/{cjs/src/types → types}/routing.js.map +1 -1
  217. package/dist/types/schema.d.ts.map +1 -0
  218. package/dist/{cjs/src/types → types}/schema.js.map +1 -1
  219. package/dist/types/session.d.ts.map +1 -0
  220. package/dist/{src/types → types}/session.js.map +1 -1
  221. package/dist/types/template.d.ts +88 -0
  222. package/dist/types/template.d.ts.map +1 -0
  223. package/dist/{cjs/src/types → types}/template.js.map +1 -1
  224. package/dist/types/tool.d.ts.map +1 -0
  225. package/dist/types/tool.js.map +1 -0
  226. package/dist/utils/clone.d.ts.map +1 -0
  227. package/dist/utils/clone.js.map +1 -0
  228. package/dist/utils/condition.d.ts +38 -0
  229. package/dist/utils/condition.d.ts.map +1 -0
  230. package/dist/utils/condition.js +161 -0
  231. package/dist/utils/condition.js.map +1 -0
  232. package/dist/utils/event.d.ts.map +1 -0
  233. package/dist/utils/event.js.map +1 -0
  234. package/dist/utils/history.d.ts.map +1 -0
  235. package/dist/utils/history.js.map +1 -0
  236. package/dist/utils/id.d.ts.map +1 -0
  237. package/dist/utils/id.js.map +1 -0
  238. package/dist/{src/utils → utils}/index.d.ts +3 -1
  239. package/dist/utils/index.d.ts.map +1 -0
  240. package/dist/{src/utils → utils}/index.js +5 -1
  241. package/dist/utils/index.js.map +1 -0
  242. package/dist/utils/json.d.ts +16 -0
  243. package/dist/utils/json.d.ts.map +1 -0
  244. package/dist/utils/json.js +43 -0
  245. package/dist/utils/json.js.map +1 -0
  246. package/dist/utils/logger.d.ts.map +1 -0
  247. package/dist/utils/logger.js.map +1 -0
  248. package/dist/{cjs/src/utils → utils}/retry.d.ts +0 -3
  249. package/dist/utils/retry.d.ts.map +1 -0
  250. package/dist/{src/utils → utils}/retry.js +5 -4
  251. package/dist/utils/retry.js.map +1 -0
  252. package/dist/utils/session.d.ts.map +1 -0
  253. package/dist/utils/session.js.map +1 -0
  254. package/dist/{cjs/src/utils → utils}/template.d.ts +48 -0
  255. package/dist/utils/template.d.ts.map +1 -0
  256. package/dist/{src/utils → utils}/template.js +98 -0
  257. package/dist/utils/template.js.map +1 -0
  258. package/docs/README.md +1 -0
  259. package/docs/api/README.md +237 -12
  260. package/docs/api/overview.md +206 -3
  261. package/docs/architecture/data-extraction-flow.md +363 -0
  262. package/docs/architecture/multi-step-execution.md +243 -0
  263. package/docs/core/agent/README.md +156 -5
  264. package/docs/core/agent/rules-and-prohibitions.md +113 -0
  265. package/docs/core/agent/session-management.md +1 -1
  266. package/docs/core/ai-integration/prompt-composition.md +135 -0
  267. package/docs/core/ai-integration/response-processing.md +146 -0
  268. package/docs/core/conversation-flows/data-collection.md +143 -0
  269. package/docs/core/conversation-flows/routes.md +2 -2
  270. package/docs/core/conversation-flows/step-transitions.md +132 -0
  271. package/docs/core/conversation-flows/steps.md +112 -0
  272. package/docs/core/error-handling.md +193 -0
  273. package/docs/core/routing/intelligent-routing.md +118 -0
  274. package/docs/guides/getting-started/README.md +284 -3
  275. package/docs/guides/migration/README.md +27 -0
  276. package/docs/guides/migration/flexible-routing-conditions.md +375 -0
  277. package/docs/guides/migration/multi-step-execution.md +373 -0
  278. package/examples/advanced-patterns/knowledge-based-agent.ts +101 -24
  279. package/examples/advanced-patterns/persistent-onboarding.ts +40 -5
  280. package/examples/advanced-patterns/route-lifecycle-hooks.ts +82 -12
  281. package/examples/advanced-patterns/streaming-responses.ts +2 -2
  282. package/examples/ai-providers/anthropic-integration.ts +4 -4
  283. package/examples/ai-providers/openai-integration.ts +1 -1
  284. package/examples/condition-patterns/function-only-conditions.ts +365 -0
  285. package/examples/condition-patterns/mixed-array-conditions.ts +477 -0
  286. package/examples/condition-patterns/route-skipif-patterns.ts +468 -0
  287. package/examples/condition-patterns/step-skipif-patterns.ts +0 -0
  288. package/examples/condition-patterns/string-only-conditions.ts +296 -0
  289. package/examples/conversation-flows/completion-transitions.ts +48 -7
  290. package/examples/core-concepts/basic-agent.ts +54 -33
  291. package/examples/core-concepts/schema-driven-extraction.ts +33 -9
  292. package/examples/core-concepts/session-management.ts +51 -16
  293. package/examples/integrations/database-integration.ts +6 -6
  294. package/examples/integrations/healthcare-integration.ts +10 -10
  295. package/examples/integrations/search-integration.ts +8 -8
  296. package/examples/integrations/server-session-management.ts +8 -8
  297. package/examples/persistence/database-persistence.ts +15 -15
  298. package/examples/persistence/memory-sessions.ts +3 -3
  299. package/examples/persistence/redis-persistence.ts +7 -9
  300. package/examples/tools/data-enrichment-tools.ts +4 -4
  301. package/package.json +6 -4
  302. package/src/adapters/PrismaAdapter.ts +3 -2
  303. package/src/adapters/RedisAdapter.ts +3 -3
  304. package/src/core/Agent.ts +78 -2
  305. package/src/core/BatchExecutor.ts +1166 -0
  306. package/src/core/BatchPromptBuilder.ts +293 -0
  307. package/src/core/PromptComposer.ts +53 -16
  308. package/src/core/ResponseEngine.ts +168 -29
  309. package/src/core/ResponseModal.ts +954 -74
  310. package/src/core/ResponsePipeline.ts +17 -9
  311. package/src/core/Route.ts +223 -22
  312. package/src/core/RoutingEngine.ts +426 -83
  313. package/src/core/Step.ts +144 -16
  314. package/src/index.ts +19 -0
  315. package/src/providers/AnthropicProvider.ts +17 -17
  316. package/src/providers/GeminiProvider.ts +129 -60
  317. package/src/providers/OpenAIProvider.ts +18 -18
  318. package/src/providers/OpenRouterProvider.ts +18 -18
  319. package/src/types/agent.ts +15 -3
  320. package/src/types/index.ts +12 -1
  321. package/src/types/route.ts +131 -12
  322. package/src/types/template.ts +70 -2
  323. package/src/utils/condition.ts +190 -0
  324. package/src/utils/index.ts +12 -0
  325. package/src/utils/json.ts +46 -0
  326. package/src/utils/retry.ts +5 -4
  327. package/src/utils/template.ts +109 -0
  328. package/dist/cjs/src/adapters/MemoryAdapter.d.ts.map +0 -1
  329. package/dist/cjs/src/adapters/MemoryAdapter.js.map +0 -1
  330. package/dist/cjs/src/adapters/MongoAdapter.d.ts.map +0 -1
  331. package/dist/cjs/src/adapters/MongoAdapter.js.map +0 -1
  332. package/dist/cjs/src/adapters/OpenSearchAdapter.d.ts.map +0 -1
  333. package/dist/cjs/src/adapters/OpenSearchAdapter.js.map +0 -1
  334. package/dist/cjs/src/adapters/PostgreSQLAdapter.d.ts.map +0 -1
  335. package/dist/cjs/src/adapters/PostgreSQLAdapter.js.map +0 -1
  336. package/dist/cjs/src/adapters/PrismaAdapter.d.ts.map +0 -1
  337. package/dist/cjs/src/adapters/PrismaAdapter.js.map +0 -1
  338. package/dist/cjs/src/adapters/RedisAdapter.d.ts.map +0 -1
  339. package/dist/cjs/src/adapters/RedisAdapter.js.map +0 -1
  340. package/dist/cjs/src/adapters/SQLiteAdapter.d.ts.map +0 -1
  341. package/dist/cjs/src/adapters/SQLiteAdapter.js.map +0 -1
  342. package/dist/cjs/src/adapters/index.d.ts.map +0 -1
  343. package/dist/cjs/src/adapters/index.js.map +0 -1
  344. package/dist/cjs/src/constants/index.d.ts.map +0 -1
  345. package/dist/cjs/src/constants/index.js.map +0 -1
  346. package/dist/cjs/src/core/Agent.d.ts.map +0 -1
  347. package/dist/cjs/src/core/Agent.js.map +0 -1
  348. package/dist/cjs/src/core/Events.d.ts.map +0 -1
  349. package/dist/cjs/src/core/Events.js.map +0 -1
  350. package/dist/cjs/src/core/PersistenceManager.d.ts.map +0 -1
  351. package/dist/cjs/src/core/PersistenceManager.js.map +0 -1
  352. package/dist/cjs/src/core/PromptComposer.d.ts.map +0 -1
  353. package/dist/cjs/src/core/PromptComposer.js.map +0 -1
  354. package/dist/cjs/src/core/ResponseEngine.d.ts.map +0 -1
  355. package/dist/cjs/src/core/ResponseEngine.js +0 -84
  356. package/dist/cjs/src/core/ResponseEngine.js.map +0 -1
  357. package/dist/cjs/src/core/ResponseModal.d.ts.map +0 -1
  358. package/dist/cjs/src/core/ResponseModal.js.map +0 -1
  359. package/dist/cjs/src/core/ResponsePipeline.d.ts.map +0 -1
  360. package/dist/cjs/src/core/ResponsePipeline.js.map +0 -1
  361. package/dist/cjs/src/core/Route.d.ts.map +0 -1
  362. package/dist/cjs/src/core/Route.js.map +0 -1
  363. package/dist/cjs/src/core/RoutingEngine.d.ts.map +0 -1
  364. package/dist/cjs/src/core/RoutingEngine.js.map +0 -1
  365. package/dist/cjs/src/core/SessionManager.d.ts.map +0 -1
  366. package/dist/cjs/src/core/SessionManager.js.map +0 -1
  367. package/dist/cjs/src/core/Step.d.ts.map +0 -1
  368. package/dist/cjs/src/core/Step.js.map +0 -1
  369. package/dist/cjs/src/core/ToolManager.d.ts.map +0 -1
  370. package/dist/cjs/src/core/ToolManager.js.map +0 -1
  371. package/dist/cjs/src/index.d.ts.map +0 -1
  372. package/dist/cjs/src/index.js.map +0 -1
  373. package/dist/cjs/src/providers/AnthropicProvider.d.ts.map +0 -1
  374. package/dist/cjs/src/providers/AnthropicProvider.js.map +0 -1
  375. package/dist/cjs/src/providers/GeminiProvider.d.ts.map +0 -1
  376. package/dist/cjs/src/providers/GeminiProvider.js.map +0 -1
  377. package/dist/cjs/src/providers/OpenAIProvider.d.ts.map +0 -1
  378. package/dist/cjs/src/providers/OpenAIProvider.js.map +0 -1
  379. package/dist/cjs/src/providers/OpenRouterProvider.d.ts.map +0 -1
  380. package/dist/cjs/src/providers/OpenRouterProvider.js.map +0 -1
  381. package/dist/cjs/src/providers/index.d.ts.map +0 -1
  382. package/dist/cjs/src/providers/index.js.map +0 -1
  383. package/dist/cjs/src/types/agent.d.ts.map +0 -1
  384. package/dist/cjs/src/types/agent.js.map +0 -1
  385. package/dist/cjs/src/types/ai.d.ts.map +0 -1
  386. package/dist/cjs/src/types/ai.js.map +0 -1
  387. package/dist/cjs/src/types/history.d.ts.map +0 -1
  388. package/dist/cjs/src/types/history.js.map +0 -1
  389. package/dist/cjs/src/types/index.d.ts.map +0 -1
  390. package/dist/cjs/src/types/index.js.map +0 -1
  391. package/dist/cjs/src/types/persistence.d.ts.map +0 -1
  392. package/dist/cjs/src/types/persistence.js.map +0 -1
  393. package/dist/cjs/src/types/route.d.ts.map +0 -1
  394. package/dist/cjs/src/types/routing.d.ts.map +0 -1
  395. package/dist/cjs/src/types/schema.d.ts.map +0 -1
  396. package/dist/cjs/src/types/session.d.ts.map +0 -1
  397. package/dist/cjs/src/types/session.js.map +0 -1
  398. package/dist/cjs/src/types/template.d.ts +0 -30
  399. package/dist/cjs/src/types/template.d.ts.map +0 -1
  400. package/dist/cjs/src/types/tool.d.ts.map +0 -1
  401. package/dist/cjs/src/types/tool.js.map +0 -1
  402. package/dist/cjs/src/utils/clone.d.ts.map +0 -1
  403. package/dist/cjs/src/utils/clone.js.map +0 -1
  404. package/dist/cjs/src/utils/event.d.ts.map +0 -1
  405. package/dist/cjs/src/utils/event.js.map +0 -1
  406. package/dist/cjs/src/utils/history.d.ts.map +0 -1
  407. package/dist/cjs/src/utils/history.js.map +0 -1
  408. package/dist/cjs/src/utils/id.d.ts.map +0 -1
  409. package/dist/cjs/src/utils/id.js.map +0 -1
  410. package/dist/cjs/src/utils/index.d.ts.map +0 -1
  411. package/dist/cjs/src/utils/index.js.map +0 -1
  412. package/dist/cjs/src/utils/logger.d.ts.map +0 -1
  413. package/dist/cjs/src/utils/logger.js.map +0 -1
  414. package/dist/cjs/src/utils/retry.d.ts.map +0 -1
  415. package/dist/cjs/src/utils/retry.js.map +0 -1
  416. package/dist/cjs/src/utils/session.d.ts.map +0 -1
  417. package/dist/cjs/src/utils/session.js.map +0 -1
  418. package/dist/cjs/src/utils/template.d.ts.map +0 -1
  419. package/dist/cjs/src/utils/template.js.map +0 -1
  420. package/dist/src/adapters/MemoryAdapter.js.map +0 -1
  421. package/dist/src/adapters/MongoAdapter.js.map +0 -1
  422. package/dist/src/adapters/OpenSearchAdapter.js.map +0 -1
  423. package/dist/src/adapters/PostgreSQLAdapter.js.map +0 -1
  424. package/dist/src/adapters/PrismaAdapter.js.map +0 -1
  425. package/dist/src/adapters/RedisAdapter.js.map +0 -1
  426. package/dist/src/adapters/SQLiteAdapter.js.map +0 -1
  427. package/dist/src/adapters/index.js.map +0 -1
  428. package/dist/src/constants/index.js.map +0 -1
  429. package/dist/src/core/Agent.d.ts.map +0 -1
  430. package/dist/src/core/Agent.js.map +0 -1
  431. package/dist/src/core/Events.js.map +0 -1
  432. package/dist/src/core/PersistenceManager.js.map +0 -1
  433. package/dist/src/core/PromptComposer.d.ts.map +0 -1
  434. package/dist/src/core/PromptComposer.js.map +0 -1
  435. package/dist/src/core/ResponseEngine.js +0 -80
  436. package/dist/src/core/ResponseEngine.js.map +0 -1
  437. package/dist/src/core/ResponseModal.d.ts.map +0 -1
  438. package/dist/src/core/ResponseModal.js.map +0 -1
  439. package/dist/src/core/ResponsePipeline.d.ts.map +0 -1
  440. package/dist/src/core/ResponsePipeline.js.map +0 -1
  441. package/dist/src/core/Route.d.ts.map +0 -1
  442. package/dist/src/core/Route.js.map +0 -1
  443. package/dist/src/core/RoutingEngine.d.ts.map +0 -1
  444. package/dist/src/core/RoutingEngine.js.map +0 -1
  445. package/dist/src/core/SessionManager.js.map +0 -1
  446. package/dist/src/core/Step.d.ts.map +0 -1
  447. package/dist/src/core/Step.js.map +0 -1
  448. package/dist/src/core/ToolManager.js.map +0 -1
  449. package/dist/src/index.d.ts.map +0 -1
  450. package/dist/src/index.js.map +0 -1
  451. package/dist/src/providers/AnthropicProvider.js.map +0 -1
  452. package/dist/src/providers/GeminiProvider.js.map +0 -1
  453. package/dist/src/providers/OpenAIProvider.js.map +0 -1
  454. package/dist/src/providers/OpenRouterProvider.js.map +0 -1
  455. package/dist/src/providers/index.js.map +0 -1
  456. package/dist/src/types/agent.d.ts.map +0 -1
  457. package/dist/src/types/agent.js.map +0 -1
  458. package/dist/src/types/history.js.map +0 -1
  459. package/dist/src/types/index.js.map +0 -1
  460. package/dist/src/types/persistence.js.map +0 -1
  461. package/dist/src/types/route.d.ts.map +0 -1
  462. package/dist/src/types/template.d.ts +0 -30
  463. package/dist/src/types/template.d.ts.map +0 -1
  464. package/dist/src/types/tool.js.map +0 -1
  465. package/dist/src/utils/clone.js.map +0 -1
  466. package/dist/src/utils/event.js.map +0 -1
  467. package/dist/src/utils/history.js.map +0 -1
  468. package/dist/src/utils/id.js.map +0 -1
  469. package/dist/src/utils/index.d.ts.map +0 -1
  470. package/dist/src/utils/index.js.map +0 -1
  471. package/dist/src/utils/logger.js.map +0 -1
  472. package/dist/src/utils/retry.d.ts.map +0 -1
  473. package/dist/src/utils/retry.js.map +0 -1
  474. package/dist/src/utils/session.js.map +0 -1
  475. package/dist/src/utils/template.d.ts.map +0 -1
  476. package/dist/src/utils/template.js.map +0 -1
  477. /package/dist/{cjs/src/adapters → adapters}/MemoryAdapter.d.ts +0 -0
  478. /package/dist/{src/adapters → adapters}/MemoryAdapter.js +0 -0
  479. /package/dist/{cjs/src/adapters → adapters}/MongoAdapter.d.ts +0 -0
  480. /package/dist/{src/adapters → adapters}/MongoAdapter.js +0 -0
  481. /package/dist/{cjs/src/adapters → adapters}/OpenSearchAdapter.d.ts +0 -0
  482. /package/dist/{src/adapters → adapters}/OpenSearchAdapter.js +0 -0
  483. /package/dist/{cjs/src/adapters → adapters}/PostgreSQLAdapter.d.ts +0 -0
  484. /package/dist/{src/adapters → adapters}/PostgreSQLAdapter.js +0 -0
  485. /package/dist/{cjs/src/adapters → adapters}/PrismaAdapter.d.ts +0 -0
  486. /package/dist/{cjs/src/adapters → adapters}/RedisAdapter.d.ts +0 -0
  487. /package/dist/{cjs/src/adapters → adapters}/SQLiteAdapter.d.ts +0 -0
  488. /package/dist/{src/adapters → adapters}/SQLiteAdapter.js +0 -0
  489. /package/dist/{cjs/src/adapters → adapters}/index.d.ts +0 -0
  490. /package/dist/{src/adapters → adapters}/index.js +0 -0
  491. /package/dist/{src → cjs}/adapters/MemoryAdapter.d.ts +0 -0
  492. /package/dist/{src → cjs}/adapters/MemoryAdapter.d.ts.map +0 -0
  493. /package/dist/cjs/{src/adapters → adapters}/MemoryAdapter.js +0 -0
  494. /package/dist/{src → cjs}/adapters/MongoAdapter.d.ts +0 -0
  495. /package/dist/{src → cjs}/adapters/MongoAdapter.d.ts.map +0 -0
  496. /package/dist/cjs/{src/adapters → adapters}/MongoAdapter.js +0 -0
  497. /package/dist/{src → cjs}/adapters/OpenSearchAdapter.d.ts +0 -0
  498. /package/dist/{src → cjs}/adapters/OpenSearchAdapter.d.ts.map +0 -0
  499. /package/dist/cjs/{src/adapters → adapters}/OpenSearchAdapter.js +0 -0
  500. /package/dist/{src → cjs}/adapters/PostgreSQLAdapter.d.ts +0 -0
  501. /package/dist/{src → cjs}/adapters/PostgreSQLAdapter.d.ts.map +0 -0
  502. /package/dist/cjs/{src/adapters → adapters}/PostgreSQLAdapter.js +0 -0
  503. /package/dist/{src → cjs}/adapters/PrismaAdapter.d.ts +0 -0
  504. /package/dist/{src → cjs}/adapters/RedisAdapter.d.ts +0 -0
  505. /package/dist/{src → cjs}/adapters/RedisAdapter.d.ts.map +0 -0
  506. /package/dist/{src → cjs}/adapters/SQLiteAdapter.d.ts +0 -0
  507. /package/dist/{src → cjs}/adapters/SQLiteAdapter.d.ts.map +0 -0
  508. /package/dist/cjs/{src/adapters → adapters}/SQLiteAdapter.js +0 -0
  509. /package/dist/{src → cjs}/adapters/index.d.ts +0 -0
  510. /package/dist/{src → cjs}/adapters/index.d.ts.map +0 -0
  511. /package/dist/cjs/{src/adapters → adapters}/index.js +0 -0
  512. /package/dist/cjs/{src/constants → constants}/index.d.ts +0 -0
  513. /package/dist/{src → cjs}/constants/index.d.ts.map +0 -0
  514. /package/dist/cjs/{src/constants → constants}/index.js +0 -0
  515. /package/dist/cjs/{src/core → core}/Events.d.ts +0 -0
  516. /package/dist/{src → cjs}/core/Events.d.ts.map +0 -0
  517. /package/dist/cjs/{src/core → core}/Events.js +0 -0
  518. /package/dist/cjs/{src/core → core}/PersistenceManager.d.ts +0 -0
  519. /package/dist/{src → cjs}/core/PersistenceManager.d.ts.map +0 -0
  520. /package/dist/cjs/{src/core → core}/PersistenceManager.js +0 -0
  521. /package/dist/cjs/{src/core → core}/ResponseEngine.d.ts +0 -0
  522. /package/dist/cjs/{src/core → core}/SessionManager.d.ts +0 -0
  523. /package/dist/{src → cjs}/core/SessionManager.d.ts.map +0 -0
  524. /package/dist/cjs/{src/core → core}/SessionManager.js +0 -0
  525. /package/dist/cjs/{src/core → core}/ToolManager.d.ts +0 -0
  526. /package/dist/{src → cjs}/core/ToolManager.d.ts.map +0 -0
  527. /package/dist/cjs/{src/core → core}/ToolManager.js +0 -0
  528. /package/dist/cjs/{src/providers → providers}/AnthropicProvider.d.ts +0 -0
  529. /package/dist/{src → cjs}/providers/AnthropicProvider.d.ts.map +0 -0
  530. /package/dist/cjs/{src/providers → providers}/GeminiProvider.d.ts +0 -0
  531. /package/dist/cjs/{src/providers → providers}/OpenAIProvider.d.ts +0 -0
  532. /package/dist/{src → cjs}/providers/OpenAIProvider.d.ts.map +0 -0
  533. /package/dist/cjs/{src/providers → providers}/OpenRouterProvider.d.ts +0 -0
  534. /package/dist/{src → cjs}/providers/OpenRouterProvider.d.ts.map +0 -0
  535. /package/dist/cjs/{src/providers → providers}/index.d.ts +0 -0
  536. /package/dist/{src → cjs}/providers/index.d.ts.map +0 -0
  537. /package/dist/cjs/{src/providers → providers}/index.js +0 -0
  538. /package/dist/cjs/{src/types → types}/agent.js +0 -0
  539. /package/dist/cjs/{src/types → types}/ai.d.ts +0 -0
  540. /package/dist/{src → cjs}/types/ai.d.ts.map +0 -0
  541. /package/dist/cjs/{src/types → types}/ai.js +0 -0
  542. /package/dist/cjs/{src/types → types}/history.d.ts +0 -0
  543. /package/dist/{src → cjs}/types/history.d.ts.map +0 -0
  544. /package/dist/cjs/{src/types → types}/history.js +0 -0
  545. /package/dist/cjs/{src/types → types}/persistence.d.ts +0 -0
  546. /package/dist/{src → cjs}/types/persistence.d.ts.map +0 -0
  547. /package/dist/cjs/{src/types → types}/persistence.js +0 -0
  548. /package/dist/cjs/{src/types → types}/route.js +0 -0
  549. /package/dist/cjs/{src/types → types}/routing.d.ts +0 -0
  550. /package/dist/{src → cjs}/types/routing.d.ts.map +0 -0
  551. /package/dist/cjs/{src/types → types}/routing.js +0 -0
  552. /package/dist/{src → cjs}/types/routing.js.map +0 -0
  553. /package/dist/cjs/{src/types → types}/schema.d.ts +0 -0
  554. /package/dist/{src → cjs}/types/schema.d.ts.map +0 -0
  555. /package/dist/cjs/{src/types → types}/schema.js +0 -0
  556. /package/dist/{src → cjs}/types/schema.js.map +0 -0
  557. /package/dist/cjs/{src/types → types}/session.d.ts +0 -0
  558. /package/dist/{src → cjs}/types/session.d.ts.map +0 -0
  559. /package/dist/cjs/{src/types → types}/session.js +0 -0
  560. /package/dist/cjs/{src/types → types}/template.js +0 -0
  561. /package/dist/{src → cjs}/types/template.js.map +0 -0
  562. /package/dist/cjs/{src/types → types}/tool.d.ts +0 -0
  563. /package/dist/{src → cjs}/types/tool.d.ts.map +0 -0
  564. /package/dist/cjs/{src/types → types}/tool.js +0 -0
  565. /package/dist/cjs/{src/utils → utils}/clone.d.ts +0 -0
  566. /package/dist/{src → cjs}/utils/clone.d.ts.map +0 -0
  567. /package/dist/cjs/{src/utils → utils}/clone.js +0 -0
  568. /package/dist/cjs/{src/utils → utils}/event.d.ts +0 -0
  569. /package/dist/{src → cjs}/utils/event.d.ts.map +0 -0
  570. /package/dist/cjs/{src/utils → utils}/event.js +0 -0
  571. /package/dist/cjs/{src/utils → utils}/history.d.ts +0 -0
  572. /package/dist/{src → cjs}/utils/history.d.ts.map +0 -0
  573. /package/dist/cjs/{src/utils → utils}/history.js +0 -0
  574. /package/dist/cjs/{src/utils → utils}/id.d.ts +0 -0
  575. /package/dist/{src → cjs}/utils/id.d.ts.map +0 -0
  576. /package/dist/cjs/{src/utils → utils}/id.js +0 -0
  577. /package/dist/cjs/{src/utils → utils}/logger.d.ts +0 -0
  578. /package/dist/{src → cjs}/utils/logger.d.ts.map +0 -0
  579. /package/dist/cjs/{src/utils → utils}/logger.js +0 -0
  580. /package/dist/cjs/{src/utils → utils}/session.d.ts +0 -0
  581. /package/dist/{src → cjs}/utils/session.d.ts.map +0 -0
  582. /package/dist/cjs/{src/utils → utils}/session.js +0 -0
  583. /package/dist/{src/constants → constants}/index.d.ts +0 -0
  584. /package/dist/{src/constants → constants}/index.js +0 -0
  585. /package/dist/{src/core → core}/Events.d.ts +0 -0
  586. /package/dist/{src/core → core}/Events.js +0 -0
  587. /package/dist/{src/core → core}/PersistenceManager.d.ts +0 -0
  588. /package/dist/{src/core → core}/PersistenceManager.js +0 -0
  589. /package/dist/{src/core → core}/ResponseEngine.d.ts +0 -0
  590. /package/dist/{src/core → core}/SessionManager.d.ts +0 -0
  591. /package/dist/{src/core → core}/SessionManager.js +0 -0
  592. /package/dist/{src/core → core}/ToolManager.d.ts +0 -0
  593. /package/dist/{src/core → core}/ToolManager.js +0 -0
  594. /package/dist/{src/providers → providers}/AnthropicProvider.d.ts +0 -0
  595. /package/dist/{src/providers → providers}/GeminiProvider.d.ts +0 -0
  596. /package/dist/{src/providers → providers}/OpenAIProvider.d.ts +0 -0
  597. /package/dist/{src/providers → providers}/OpenRouterProvider.d.ts +0 -0
  598. /package/dist/{src/providers → providers}/index.d.ts +0 -0
  599. /package/dist/{src/providers → providers}/index.js +0 -0
  600. /package/dist/{src/types → types}/agent.js +0 -0
  601. /package/dist/{src/types → types}/ai.d.ts +0 -0
  602. /package/dist/{src/types → types}/ai.js +0 -0
  603. /package/dist/{src/types → types}/history.d.ts +0 -0
  604. /package/dist/{src/types → types}/history.js +0 -0
  605. /package/dist/{src/types → types}/persistence.d.ts +0 -0
  606. /package/dist/{src/types → types}/persistence.js +0 -0
  607. /package/dist/{src/types → types}/route.js +0 -0
  608. /package/dist/{src/types → types}/routing.d.ts +0 -0
  609. /package/dist/{src/types → types}/routing.js +0 -0
  610. /package/dist/{src/types → types}/schema.d.ts +0 -0
  611. /package/dist/{src/types → types}/schema.js +0 -0
  612. /package/dist/{src/types → types}/session.d.ts +0 -0
  613. /package/dist/{src/types → types}/session.js +0 -0
  614. /package/dist/{src/types → types}/template.js +0 -0
  615. /package/dist/{src/types → types}/tool.d.ts +0 -0
  616. /package/dist/{src/types → types}/tool.js +0 -0
  617. /package/dist/{src/utils → utils}/clone.d.ts +0 -0
  618. /package/dist/{src/utils → utils}/clone.js +0 -0
  619. /package/dist/{src/utils → utils}/event.d.ts +0 -0
  620. /package/dist/{src/utils → utils}/event.js +0 -0
  621. /package/dist/{src/utils → utils}/history.d.ts +0 -0
  622. /package/dist/{src/utils → utils}/history.js +0 -0
  623. /package/dist/{src/utils → utils}/id.d.ts +0 -0
  624. /package/dist/{src/utils → utils}/id.js +0 -0
  625. /package/dist/{src/utils → utils}/logger.d.ts +0 -0
  626. /package/dist/{src/utils → utils}/logger.js +0 -0
  627. /package/dist/{src/utils → utils}/session.d.ts +0 -0
  628. /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,6 +65,7 @@ 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> {
@@ -125,14 +126,20 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
125
126
  // Check if this single route is complete (use updated session data)
126
127
  const completedRoutes = route.isComplete(updatedSession.data || {}) ? [route] : [];
127
128
 
128
- // 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
+ });
129
136
  const currentStep = updatedSession.currentStep
130
137
  ? route.getStep(updatedSession.currentStep.id)
131
138
  : undefined;
132
- const candidates = this.getCandidateSteps(
139
+ const candidates = await this.getCandidateStepsWithConditions(
133
140
  route,
134
141
  currentStep,
135
- updatedSession.data || {}
142
+ templateContext
136
143
  );
137
144
 
138
145
  if (candidates.length === 0) {
@@ -140,14 +147,13 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
140
147
  return { selectedRoute, session: updatedSession };
141
148
  }
142
149
 
143
- // If only one candidate, no need for AI selection
150
+ // If only one candidate, check if it's a completion marker
144
151
  if (candidates.length === 1) {
145
152
  const candidate = candidates[0];
146
- const isRouteComplete = candidate.isRouteComplete;
147
-
148
- if (isRouteComplete) {
153
+
154
+ if (candidate.isRouteComplete) {
149
155
  logger.debug(
150
- `[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`
151
157
  );
152
158
  // Don't return a selectedStep when route is complete - there's no step to enter
153
159
  return {
@@ -173,18 +179,33 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
173
179
 
174
180
  // No candidates means route is likely complete or has no valid next steps
175
181
  if (candidates.length === 0) {
176
- logger.debug(`[RoutingEngine] Single-route: No valid steps found, route may be complete`);
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
+ );
177
187
  return {
178
188
  selectedRoute,
179
189
  selectedStep: undefined,
180
190
  session: updatedSession,
181
- isRouteComplete: true, // Assume complete if no valid steps
191
+ isRouteComplete: dataComplete,
182
192
  completedRoutes,
183
193
  };
184
194
  }
185
195
 
186
196
  // Multiple candidates - use AI to select best step
187
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
+
188
209
  const stepPrompt = await this.buildStepSelectionPrompt({
189
210
  route,
190
211
  currentStep,
@@ -195,10 +216,13 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
195
216
  agentOptions,
196
217
  context,
197
218
  session: updatedSession,
219
+ stepConditionContext,
220
+ includeEndRoute: hasCompletionOption,
198
221
  });
199
222
 
200
223
  const stepSchema = this.buildStepSelectionSchema(
201
- candidates.map((c) => c.step)
224
+ candidates.filter(c => !c.isRouteComplete).map((c) => c.step),
225
+ hasCompletionOption
202
226
  );
203
227
 
204
228
  const stepResult = await provider.generateMessage<
@@ -220,6 +244,25 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
220
244
  });
221
245
 
222
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
+
223
266
  const selectedStep = candidates.find((c) => c.step.id === selectedStepId);
224
267
 
225
268
  if (selectedStep) {
@@ -245,24 +288,26 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
245
288
  }
246
289
 
247
290
  /**
248
- * 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
249
292
  * @private
250
293
  */
251
- private findFirstValidStepRecursive(
294
+ private async findFirstValidStepRecursiveWithConditions(
252
295
  currentStep: Step<TContext, TData>,
253
- data: Partial<TData>,
296
+ templateContext: TemplateContext<TContext, TData>,
254
297
  visited: Set<string>
255
- ): {
298
+ ): Promise<{
256
299
  step?: Step<TContext, TData>;
257
300
  isRouteComplete?: boolean;
258
- } {
301
+ aiContextStrings?: string[];
302
+ }> {
259
303
  // Prevent infinite loops
260
304
  if (visited.has(currentStep.id)) {
261
- return {};
305
+ return { aiContextStrings: [] };
262
306
  }
263
307
  visited.add(currentStep.id);
264
308
 
265
309
  const transitions = currentStep.getTransitions();
310
+ const allAiContextStrings: string[] = [];
266
311
 
267
312
  for (const transition of transitions) {
268
313
  const target = transition;
@@ -272,19 +317,25 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
272
317
  // Found END_ROUTE - route is complete
273
318
  return {
274
319
  isRouteComplete: true,
320
+ aiContextStrings: allAiContextStrings,
275
321
  };
276
322
  }
277
323
 
278
324
  if (!target) continue;
279
325
 
326
+ // Evaluate skipIf condition using new system
327
+ const skipResult = await target.evaluateSkipIf(templateContext);
328
+ allAiContextStrings.push(...skipResult.aiContextStrings);
329
+
280
330
  // If target should NOT be skipped, we found our step
281
- if (!target.shouldSkip(data)) {
331
+ if (!skipResult.shouldSkip) {
282
332
  logger.debug(
283
333
  `[RoutingEngine] Found valid step after skipping: ${target.id}`
284
334
  );
285
335
  return {
286
336
  step: target,
287
337
  isRouteComplete: false,
338
+ aiContextStrings: allAiContextStrings,
288
339
  };
289
340
  }
290
341
 
@@ -292,36 +343,69 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
292
343
  logger.debug(
293
344
  `[RoutingEngine] Skipping step ${target.id} (skipIf condition met), continuing traversal...`
294
345
  );
295
- 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
+ }
296
352
 
297
353
  // If we found something (a valid step or END_ROUTE), return it
298
354
  if (result.step || result.isRouteComplete) {
299
- return result;
355
+ return {
356
+ ...result,
357
+ aiContextStrings: allAiContextStrings,
358
+ };
300
359
  }
301
360
  }
302
361
 
303
362
  // No valid steps or END_ROUTE found in this branch
304
- return {};
363
+ return { aiContextStrings: allAiContextStrings };
305
364
  }
306
365
 
366
+
367
+
307
368
  /**
308
- * Identify valid next candidate steps based on current step and collected data
369
+ * Identify valid next candidate steps using new condition evaluation system
309
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
310
373
  */
311
- getCandidateSteps(
374
+ async getCandidateStepsWithConditions(
312
375
  route: Route<TContext, TData>,
313
376
  currentStep: Step<TContext, TData> | undefined,
314
- data: Partial<TData>
315
- ): CandidateStep<TContext, TData>[] {
377
+ templateContext: TemplateContext<TContext, TData>
378
+ ): Promise<CandidateStep<TContext, TData>[]> {
316
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);
317
384
 
318
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
+
319
401
  const initialStep = route.initialStep;
320
- if (initialStep.shouldSkip(data)) {
402
+ const skipResult = await initialStep.evaluateSkipIf(templateContext);
403
+
404
+ if (skipResult.shouldSkip) {
321
405
  // Initial step should be skipped - recursively traverse to find first non-skipped step or END_ROUTE
322
- const result = this.findFirstValidStepRecursive(
406
+ const result = await this.findFirstValidStepRecursiveWithConditions(
323
407
  initialStep,
324
- data,
408
+ templateContext,
325
409
  new Set<string>()
326
410
  );
327
411
 
@@ -351,6 +435,68 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
351
435
  return candidates;
352
436
  }
353
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
354
500
  const transitions = currentStep.getTransitions();
355
501
  let hasEndRoute = false;
356
502
 
@@ -365,15 +511,17 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
365
511
 
366
512
  if (!target) continue;
367
513
 
368
- if (target.shouldSkip(data)) {
514
+ const skipResult = await target.evaluateSkipIf(templateContext);
515
+
516
+ if (skipResult.shouldSkip) {
369
517
  logger.debug(
370
518
  `[RoutingEngine] Skipping step ${target.id} (skipIf condition met)`
371
519
  );
372
520
 
373
521
  // Recursively traverse to find next valid step or END_ROUTE
374
- const result = this.findFirstValidStepRecursive(
522
+ const result = await this.findFirstValidStepRecursiveWithConditions(
375
523
  target,
376
- data,
524
+ templateContext,
377
525
  new Set<string>([currentStep.id]) // Already visited current step
378
526
  );
379
527
 
@@ -412,7 +560,8 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
412
560
  }
413
561
 
414
562
  // Otherwise, stay in current step if it's still valid
415
- if (!currentStep.shouldSkip(data)) {
563
+ const currentSkipResult = await currentStep.evaluateSkipIf(templateContext);
564
+ if (!currentSkipResult.shouldSkip) {
416
565
  candidates.push({
417
566
  step: currentStep,
418
567
  isRouteComplete: hasEndRoute || false,
@@ -488,32 +637,67 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
488
637
  }
489
638
 
490
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`);
491
658
 
492
659
  let activeRouteSteps: Step<TContext, TData>[] | undefined;
493
660
  let activeRoute: Route<TContext, TData> | undefined;
494
661
  let isRouteComplete = false;
662
+ let updatedSession = session;
495
663
 
496
664
  if (session.currentRoute) {
497
- activeRoute = routes.find((r) => r.id === session.currentRoute?.id);
665
+ activeRoute = eligibleRoutes.find((r) => r.id === session.currentRoute?.id);
498
666
  if (activeRoute) {
499
667
  const currentStep = session.currentStep
500
668
  ? activeRoute.getStep(session.currentStep.id)
501
669
  : undefined;
502
- const candidates = this.getCandidateSteps(
670
+ const activeTemplateContext = createTemplateContext({
671
+ ...templateContext,
672
+ session: updatedSession,
673
+ data: updatedSession.data
674
+ });
675
+ const candidates = await this.getCandidateStepsWithConditions(
503
676
  activeRoute,
504
677
  currentStep,
505
- session.data || {}
678
+ activeTemplateContext
506
679
  );
507
680
 
508
681
  // Check if route is complete
682
+ // getCandidateStepsWithConditions now automatically handles completion when required fields are collected
509
683
  if (candidates.length === 1 && candidates[0].isRouteComplete) {
510
684
  isRouteComplete = true;
511
685
  logger.debug(
512
- `[RoutingEngine] Route ${activeRoute.title} is complete - all data collected`
686
+ `[RoutingEngine] Route ${activeRoute.title} is complete - all required fields collected or END_ROUTE reached`
513
687
  );
514
688
  // Don't include steps in routing if route is complete
515
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;
516
699
  } else {
700
+ // Multiple candidates or single non-complete candidate
517
701
  activeRouteSteps = candidates.map((c) => c.step);
518
702
  logger.debug(
519
703
  `[RoutingEngine] Found ${activeRouteSteps.length} candidate steps for active route`
@@ -523,19 +707,20 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
523
707
  }
524
708
 
525
709
  const routingSchema = this.buildDynamicRoutingSchema(
526
- routes,
710
+ eligibleRoutes,
527
711
  undefined,
528
712
  activeRouteSteps
529
713
  );
530
714
 
531
715
  const routingPrompt = await this.buildRoutingPrompt({
532
716
  history,
533
- routes,
717
+ routes: eligibleRoutes,
534
718
  lastMessage: lastUserMessage,
535
719
  agentOptions,
536
720
  session,
537
721
  activeRouteSteps,
538
722
  context,
723
+ routeConditionContext, // Pass AI context strings from route conditions
539
724
  });
540
725
 
541
726
  const routingResult = await provider.generateMessage<
@@ -555,25 +740,34 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
555
740
  let selectedRoute: Route<TContext, TData> | undefined;
556
741
  let selectedStep: Step<TContext, TData> | undefined;
557
742
  let responseDirectives: string[] | undefined;
558
- let updatedSession = session;
559
743
 
560
744
  if (routingResult.structured?.routes) {
561
745
  // Use cross-route completion evaluation to select optimal route
562
746
  const optimalRoute = this.selectOptimalRoute(
563
- routes,
747
+ eligibleRoutes,
564
748
  updatedSession.data || {},
565
749
  routingResult.structured.routes
566
750
  );
567
751
 
568
- // Fall back to traditional scoring if no optimal route found
569
- selectedRoute = optimalRoute || (() => {
570
- const decision = this.decideRouteFromScores({
571
- context: routingResult.structured.context,
572
- routes: routingResult.structured.routes,
573
- responseDirectives: routingResult.structured.responseDirectives,
574
- });
575
- return routes.find((r) => r.id === decision.routeId);
576
- })();
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
+ }
577
771
 
578
772
  responseDirectives = routingResult.structured.responseDirectives;
579
773
 
@@ -611,6 +805,72 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
611
805
  };
612
806
  }
613
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
+
614
874
  /**
615
875
  * Evaluate all routes for completion based on collected data
616
876
  * @param routes - All available routes
@@ -641,6 +901,7 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
641
901
  /**
642
902
  * Find the best route to continue based on completion status and user intent
643
903
  * Prioritizes routes that are partially complete but not finished
904
+ * IMPORTANT: Completed routes are excluded to prevent re-entering finished tasks
644
905
  * @param routes - All available routes
645
906
  * @param data - Currently collected agent-level data
646
907
  * @param routeScores - AI-generated route scores from routing decision
@@ -660,8 +921,12 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
660
921
  const aiScore = routeScores[route.id] || 0;
661
922
  const completionProgress = completionStatus.get(route.id) || 0;
662
923
 
663
- // Skip fully completed routes unless they have very high AI scores
664
- 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
+ );
665
930
  continue;
666
931
  }
667
932
 
@@ -696,7 +961,7 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
696
961
  * @private
697
962
  */
698
963
  private async buildStepSelectionPrompt(
699
- params: BuildStepSelectionPromptParams<TContext, TData>
964
+ params: BuildStepSelectionPromptParams<TContext, TData> & { includeEndRoute?: boolean }
700
965
  ): Promise<string> {
701
966
  const {
702
967
  route,
@@ -708,8 +973,10 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
708
973
  agentOptions,
709
974
  context,
710
975
  session,
976
+ stepConditionContext,
977
+ includeEndRoute = false,
711
978
  } = params;
712
- const templateContext = { context, session, history };
979
+ const templateContext = createTemplateContext({ context, session, history });
713
980
  const pc = new PromptComposer<TContext, TData>(templateContext);
714
981
 
715
982
  // Add agent metadata
@@ -745,7 +1012,7 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
745
1012
  await pc.addInteractionHistory(history);
746
1013
  await pc.addLastMessage(lastMessage);
747
1014
 
748
- // Add candidate steps
1015
+ // Add candidate steps with condition context
749
1016
  const stepDescriptions = [];
750
1017
  for (const candidate of candidates) {
751
1018
  const idx = candidates.indexOf(candidate);
@@ -754,9 +1021,14 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
754
1021
  ` Description: ${candidate.step.description || "N/A"}`,
755
1022
  ];
756
1023
 
1024
+ // Add when condition context
757
1025
  if (candidate.step.when) {
758
- const renderedWhen = await render(candidate.step.when, templateContext);
759
- 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
+ }
760
1032
  }
761
1033
 
762
1034
  if (candidate.step.requires && candidate.step.requires.length > 0) {
@@ -774,26 +1046,52 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
774
1046
  `Available Steps to Transition To:\n${stepDescriptions.join("\n\n")}`
775
1047
  );
776
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
+
777
1062
  // Add decision prompt
778
- await pc.addInstruction(
779
- [
780
- "Task: Decide which step to transition to based on:",
781
- "1. The user's current message and intent",
782
- "2. The conversation history and context",
783
- "3. The collected data we already have",
784
- "4. The conditions and requirements of each step",
785
- "5. The logical flow of the conversation",
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(
786
1080
  "",
787
- "Rules:",
788
- "- If a step has a condition, evaluate whether it's met based on context",
789
- "- If a step requires data we don't have, consider if we should collect it now",
790
- "- Choose the step that makes the most sense for moving the conversation forward",
791
- "- Steps with skipIf conditions that are met have already been filtered out",
792
- "",
793
- "Return ONLY JSON matching the provided schema.",
794
- ].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."
795
1091
  );
796
1092
 
1093
+ await pc.addInstruction(decisionRules.join("\n"));
1094
+
797
1095
  return pc.build();
798
1096
  }
799
1097
 
@@ -802,8 +1100,16 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
802
1100
  * @private
803
1101
  */
804
1102
  private buildStepSelectionSchema(
805
- validSteps: Step<TContext, TData>[]
1103
+ validSteps: Step<TContext, TData>[],
1104
+ includeEndRoute: boolean = false
806
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
+
807
1113
  return {
808
1114
  description:
809
1115
  "Step transition decision based on conversation context and collected data",
@@ -817,8 +1123,10 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
817
1123
  selectedStepId: {
818
1124
  type: "string",
819
1125
  nullable: false,
820
- description: "The ID of the selected step to transition to",
821
- 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,
822
1130
  },
823
1131
  responseDirectives: {
824
1132
  type: "array",
@@ -918,8 +1226,9 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
918
1226
  session,
919
1227
  activeRouteSteps,
920
1228
  context,
1229
+ routeConditionContext,
921
1230
  } = params;
922
- const templateContext = { context, session, history };
1231
+ const templateContext = createTemplateContext({ context, session, history });
923
1232
  const pc = new PromptComposer<TContext, TData>(templateContext);
924
1233
  if (agentOptions) {
925
1234
  await pc.addAgentMeta(agentOptions);
@@ -989,18 +1298,26 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
989
1298
  "",
990
1299
  "Available steps in active route (choose one to transition to):",
991
1300
  ];
1301
+ const activeStepConditionContext: string[] = [];
1302
+
992
1303
  for (const step of activeRouteSteps) {
993
1304
  const idx = activeRouteSteps.indexOf(step);
994
1305
  stepInfo.push(`${idx + 1}. Step: ${step.id}`);
995
1306
  if (step.description) {
996
1307
  stepInfo.push(` Description: ${step.description}`);
997
1308
  }
998
- const renderedWhen = await render(step.when, templateContext);
1309
+
1310
+ // Collect AI context from step conditions
999
1311
  if (step.when) {
1000
- stepInfo.push(
1001
- ` When this step should be completed: ${renderedWhen}`
1002
- );
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
+ }
1003
1319
  }
1320
+
1004
1321
  if (step.requires && step.requires.length > 0) {
1005
1322
  stepInfo.push(` Required data: ${step.requires.join(", ")}`);
1006
1323
  }
@@ -1017,12 +1334,38 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
1017
1334
  stepInfo.push("- The logical next step in the conversation");
1018
1335
  stepInfo.push("- Whether conditions for steps are met");
1019
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
+ }
1020
1350
  }
1021
1351
  }
1022
1352
 
1023
1353
  await pc.addInteractionHistory(history);
1024
1354
  await pc.addLastMessage(lastMessage);
1025
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
+ }
1026
1369
  await pc.addInstruction(
1027
1370
  [
1028
1371
  "Scoring rules:",