@falai/agent 0.1.0-alpha2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (499) hide show
  1. package/README.md +797 -0
  2. package/dist/cjs/package.json +1 -0
  3. package/dist/cjs/src/adapters/MemoryAdapter.d.ts +47 -0
  4. package/dist/cjs/src/adapters/MemoryAdapter.d.ts.map +1 -0
  5. package/dist/cjs/src/adapters/MemoryAdapter.js +202 -0
  6. package/dist/cjs/src/adapters/MemoryAdapter.js.map +1 -0
  7. package/dist/cjs/src/adapters/MongoAdapter.d.ts +97 -0
  8. package/dist/cjs/src/adapters/MongoAdapter.d.ts.map +1 -0
  9. package/dist/cjs/src/adapters/MongoAdapter.js +168 -0
  10. package/dist/cjs/src/adapters/MongoAdapter.js.map +1 -0
  11. package/dist/cjs/src/adapters/OpenSearchAdapter.d.ts +169 -0
  12. package/dist/cjs/src/adapters/OpenSearchAdapter.d.ts.map +1 -0
  13. package/dist/cjs/src/adapters/OpenSearchAdapter.js +458 -0
  14. package/dist/cjs/src/adapters/OpenSearchAdapter.js.map +1 -0
  15. package/dist/cjs/src/adapters/PostgreSQLAdapter.d.ts +71 -0
  16. package/dist/cjs/src/adapters/PostgreSQLAdapter.d.ts.map +1 -0
  17. package/dist/cjs/src/adapters/PostgreSQLAdapter.js +260 -0
  18. package/dist/cjs/src/adapters/PostgreSQLAdapter.js.map +1 -0
  19. package/dist/cjs/src/adapters/PrismaAdapter.d.ts +115 -0
  20. package/dist/cjs/src/adapters/PrismaAdapter.d.ts.map +1 -0
  21. package/dist/cjs/src/adapters/PrismaAdapter.js +366 -0
  22. package/dist/cjs/src/adapters/PrismaAdapter.js.map +1 -0
  23. package/dist/cjs/src/adapters/RedisAdapter.d.ts +71 -0
  24. package/dist/cjs/src/adapters/RedisAdapter.d.ts.map +1 -0
  25. package/dist/cjs/src/adapters/RedisAdapter.js +231 -0
  26. package/dist/cjs/src/adapters/RedisAdapter.js.map +1 -0
  27. package/dist/cjs/src/adapters/SQLiteAdapter.d.ts +69 -0
  28. package/dist/cjs/src/adapters/SQLiteAdapter.d.ts.map +1 -0
  29. package/dist/cjs/src/adapters/SQLiteAdapter.js +312 -0
  30. package/dist/cjs/src/adapters/SQLiteAdapter.js.map +1 -0
  31. package/dist/cjs/src/adapters/index.d.ts +17 -0
  32. package/dist/cjs/src/adapters/index.d.ts.map +1 -0
  33. package/dist/cjs/src/adapters/index.js +21 -0
  34. package/dist/cjs/src/adapters/index.js.map +1 -0
  35. package/dist/cjs/src/constants/index.d.ts +10 -0
  36. package/dist/cjs/src/constants/index.d.ts.map +1 -0
  37. package/dist/cjs/src/constants/index.js +13 -0
  38. package/dist/cjs/src/constants/index.js.map +1 -0
  39. package/dist/cjs/src/core/Agent.d.ts +232 -0
  40. package/dist/cjs/src/core/Agent.d.ts.map +1 -0
  41. package/dist/cjs/src/core/Agent.js +741 -0
  42. package/dist/cjs/src/core/Agent.js.map +1 -0
  43. package/dist/cjs/src/core/Events.d.ts +26 -0
  44. package/dist/cjs/src/core/Events.d.ts.map +1 -0
  45. package/dist/cjs/src/core/Events.js +144 -0
  46. package/dist/cjs/src/core/Events.js.map +1 -0
  47. package/dist/cjs/src/core/PersistenceManager.d.ts +98 -0
  48. package/dist/cjs/src/core/PersistenceManager.d.ts.map +1 -0
  49. package/dist/cjs/src/core/PersistenceManager.js +261 -0
  50. package/dist/cjs/src/core/PersistenceManager.js.map +1 -0
  51. package/dist/cjs/src/core/PromptComposer.d.ts +27 -0
  52. package/dist/cjs/src/core/PromptComposer.d.ts.map +1 -0
  53. package/dist/cjs/src/core/PromptComposer.js +194 -0
  54. package/dist/cjs/src/core/PromptComposer.js.map +1 -0
  55. package/dist/cjs/src/core/ResponseEngine.d.ts +32 -0
  56. package/dist/cjs/src/core/ResponseEngine.d.ts.map +1 -0
  57. package/dist/cjs/src/core/ResponseEngine.js +202 -0
  58. package/dist/cjs/src/core/ResponseEngine.js.map +1 -0
  59. package/dist/cjs/src/core/ResponseModal.d.ts +222 -0
  60. package/dist/cjs/src/core/ResponseModal.d.ts.map +1 -0
  61. package/dist/cjs/src/core/ResponseModal.js +1588 -0
  62. package/dist/cjs/src/core/ResponseModal.js.map +1 -0
  63. package/dist/cjs/src/core/ResponsePipeline.d.ts +175 -0
  64. package/dist/cjs/src/core/ResponsePipeline.d.ts.map +1 -0
  65. package/dist/cjs/src/core/ResponsePipeline.js +549 -0
  66. package/dist/cjs/src/core/ResponsePipeline.js.map +1 -0
  67. package/dist/cjs/src/core/Route.d.ts +181 -0
  68. package/dist/cjs/src/core/Route.d.ts.map +1 -0
  69. package/dist/cjs/src/core/Route.js +541 -0
  70. package/dist/cjs/src/core/Route.js.map +1 -0
  71. package/dist/cjs/src/core/RoutingEngine.d.ts +159 -0
  72. package/dist/cjs/src/core/RoutingEngine.d.ts.map +1 -0
  73. package/dist/cjs/src/core/RoutingEngine.js +961 -0
  74. package/dist/cjs/src/core/RoutingEngine.js.map +1 -0
  75. package/dist/cjs/src/core/SessionManager.d.ts +94 -0
  76. package/dist/cjs/src/core/SessionManager.d.ts.map +1 -0
  77. package/dist/cjs/src/core/SessionManager.js +239 -0
  78. package/dist/cjs/src/core/SessionManager.js.map +1 -0
  79. package/dist/cjs/src/core/Step.d.ts +170 -0
  80. package/dist/cjs/src/core/Step.d.ts.map +1 -0
  81. package/dist/cjs/src/core/Step.js +448 -0
  82. package/dist/cjs/src/core/Step.js.map +1 -0
  83. package/dist/cjs/src/core/ToolManager.d.ts +234 -0
  84. package/dist/cjs/src/core/ToolManager.d.ts.map +1 -0
  85. package/dist/cjs/src/core/ToolManager.js +1117 -0
  86. package/dist/cjs/src/core/ToolManager.js.map +1 -0
  87. package/dist/cjs/src/index.d.ts +44 -0
  88. package/dist/cjs/src/index.d.ts.map +1 -0
  89. package/dist/cjs/src/index.js +88 -0
  90. package/dist/cjs/src/index.js.map +1 -0
  91. package/dist/cjs/src/providers/AnthropicProvider.d.ts +43 -0
  92. package/dist/cjs/src/providers/AnthropicProvider.d.ts.map +1 -0
  93. package/dist/cjs/src/providers/AnthropicProvider.js +377 -0
  94. package/dist/cjs/src/providers/AnthropicProvider.js.map +1 -0
  95. package/dist/cjs/src/providers/GeminiProvider.d.ts +58 -0
  96. package/dist/cjs/src/providers/GeminiProvider.d.ts.map +1 -0
  97. package/dist/cjs/src/providers/GeminiProvider.js +489 -0
  98. package/dist/cjs/src/providers/GeminiProvider.js.map +1 -0
  99. package/dist/cjs/src/providers/OpenAIProvider.d.ts +52 -0
  100. package/dist/cjs/src/providers/OpenAIProvider.d.ts.map +1 -0
  101. package/dist/cjs/src/providers/OpenAIProvider.js +395 -0
  102. package/dist/cjs/src/providers/OpenAIProvider.js.map +1 -0
  103. package/dist/cjs/src/providers/OpenRouterProvider.d.ts +56 -0
  104. package/dist/cjs/src/providers/OpenRouterProvider.d.ts.map +1 -0
  105. package/dist/cjs/src/providers/OpenRouterProvider.js +409 -0
  106. package/dist/cjs/src/providers/OpenRouterProvider.js.map +1 -0
  107. package/dist/cjs/src/providers/index.d.ts +13 -0
  108. package/dist/cjs/src/providers/index.d.ts.map +1 -0
  109. package/dist/cjs/src/providers/index.js +16 -0
  110. package/dist/cjs/src/providers/index.js.map +1 -0
  111. package/dist/cjs/src/types/agent.d.ts +181 -0
  112. package/dist/cjs/src/types/agent.d.ts.map +1 -0
  113. package/dist/cjs/src/types/agent.js +21 -0
  114. package/dist/cjs/src/types/agent.js.map +1 -0
  115. package/dist/cjs/src/types/ai.d.ts +143 -0
  116. package/dist/cjs/src/types/ai.d.ts.map +1 -0
  117. package/dist/cjs/src/types/ai.js +6 -0
  118. package/dist/cjs/src/types/ai.js.map +1 -0
  119. package/dist/cjs/src/types/history.d.ts +178 -0
  120. package/dist/cjs/src/types/history.d.ts.map +1 -0
  121. package/dist/cjs/src/types/history.js +33 -0
  122. package/dist/cjs/src/types/history.js.map +1 -0
  123. package/dist/cjs/src/types/index.d.ts +22 -0
  124. package/dist/cjs/src/types/index.d.ts.map +1 -0
  125. package/dist/cjs/src/types/index.js +37 -0
  126. package/dist/cjs/src/types/index.js.map +1 -0
  127. package/dist/cjs/src/types/persistence.d.ts +209 -0
  128. package/dist/cjs/src/types/persistence.d.ts.map +1 -0
  129. package/dist/cjs/src/types/persistence.js +7 -0
  130. package/dist/cjs/src/types/persistence.js.map +1 -0
  131. package/dist/cjs/src/types/route.d.ts +238 -0
  132. package/dist/cjs/src/types/route.d.ts.map +1 -0
  133. package/dist/cjs/src/types/route.js +6 -0
  134. package/dist/cjs/src/types/route.js.map +1 -0
  135. package/dist/cjs/src/types/routing.d.ts +16 -0
  136. package/dist/cjs/src/types/routing.d.ts.map +1 -0
  137. package/dist/cjs/src/types/routing.js +3 -0
  138. package/dist/cjs/src/types/routing.js.map +1 -0
  139. package/dist/cjs/src/types/schema.d.ts +22 -0
  140. package/dist/cjs/src/types/schema.d.ts.map +1 -0
  141. package/dist/cjs/src/types/schema.js +3 -0
  142. package/dist/cjs/src/types/schema.js.map +1 -0
  143. package/dist/cjs/src/types/session.d.ts +65 -0
  144. package/dist/cjs/src/types/session.d.ts.map +1 -0
  145. package/dist/cjs/src/types/session.js +6 -0
  146. package/dist/cjs/src/types/session.js.map +1 -0
  147. package/dist/cjs/src/types/template.d.ts +88 -0
  148. package/dist/cjs/src/types/template.d.ts.map +1 -0
  149. package/dist/cjs/src/types/template.js +3 -0
  150. package/dist/cjs/src/types/template.js.map +1 -0
  151. package/dist/cjs/src/types/tool.d.ts +130 -0
  152. package/dist/cjs/src/types/tool.d.ts.map +1 -0
  153. package/dist/cjs/src/types/tool.js +19 -0
  154. package/dist/cjs/src/types/tool.js.map +1 -0
  155. package/dist/cjs/src/utils/clone.d.ts +8 -0
  156. package/dist/cjs/src/utils/clone.d.ts.map +1 -0
  157. package/dist/cjs/src/utils/clone.js +32 -0
  158. package/dist/cjs/src/utils/clone.js.map +1 -0
  159. package/dist/cjs/src/utils/condition.d.ts +38 -0
  160. package/dist/cjs/src/utils/condition.d.ts.map +1 -0
  161. package/dist/cjs/src/utils/condition.js +168 -0
  162. package/dist/cjs/src/utils/condition.js.map +1 -0
  163. package/dist/cjs/src/utils/event.d.ts +6 -0
  164. package/dist/cjs/src/utils/event.d.ts.map +1 -0
  165. package/dist/cjs/src/utils/event.js +20 -0
  166. package/dist/cjs/src/utils/event.js.map +1 -0
  167. package/dist/cjs/src/utils/history.d.ts +60 -0
  168. package/dist/cjs/src/utils/history.d.ts.map +1 -0
  169. package/dist/cjs/src/utils/history.js +274 -0
  170. package/dist/cjs/src/utils/history.js.map +1 -0
  171. package/dist/cjs/src/utils/id.d.ts +25 -0
  172. package/dist/cjs/src/utils/id.d.ts.map +1 -0
  173. package/dist/cjs/src/utils/id.js +70 -0
  174. package/dist/cjs/src/utils/id.js.map +1 -0
  175. package/dist/cjs/src/utils/index.d.ts +15 -0
  176. package/dist/cjs/src/utils/index.d.ts.map +1 -0
  177. package/dist/cjs/src/utils/index.js +64 -0
  178. package/dist/cjs/src/utils/index.js.map +1 -0
  179. package/dist/cjs/src/utils/json.d.ts +16 -0
  180. package/dist/cjs/src/utils/json.d.ts.map +1 -0
  181. package/dist/cjs/src/utils/json.js +47 -0
  182. package/dist/cjs/src/utils/json.js.map +1 -0
  183. package/dist/cjs/src/utils/logger.d.ts +10 -0
  184. package/dist/cjs/src/utils/logger.d.ts.map +1 -0
  185. package/dist/cjs/src/utils/logger.js +23 -0
  186. package/dist/cjs/src/utils/logger.js.map +1 -0
  187. package/dist/cjs/src/utils/retry.d.ts +10 -0
  188. package/dist/cjs/src/utils/retry.d.ts.map +1 -0
  189. package/dist/cjs/src/utils/retry.js +76 -0
  190. package/dist/cjs/src/utils/retry.js.map +1 -0
  191. package/dist/cjs/src/utils/session.d.ts +51 -0
  192. package/dist/cjs/src/utils/session.d.ts.map +1 -0
  193. package/dist/cjs/src/utils/session.js +170 -0
  194. package/dist/cjs/src/utils/session.js.map +1 -0
  195. package/dist/cjs/src/utils/template.d.ts +155 -0
  196. package/dist/cjs/src/utils/template.d.ts.map +1 -0
  197. package/dist/cjs/src/utils/template.js +383 -0
  198. package/dist/cjs/src/utils/template.js.map +1 -0
  199. package/dist/src/adapters/MemoryAdapter.d.ts +47 -0
  200. package/dist/src/adapters/MemoryAdapter.d.ts.map +1 -0
  201. package/dist/src/adapters/MemoryAdapter.js +198 -0
  202. package/dist/src/adapters/MemoryAdapter.js.map +1 -0
  203. package/dist/src/adapters/MongoAdapter.d.ts +97 -0
  204. package/dist/src/adapters/MongoAdapter.d.ts.map +1 -0
  205. package/dist/src/adapters/MongoAdapter.js +164 -0
  206. package/dist/src/adapters/MongoAdapter.js.map +1 -0
  207. package/dist/src/adapters/OpenSearchAdapter.d.ts +169 -0
  208. package/dist/src/adapters/OpenSearchAdapter.d.ts.map +1 -0
  209. package/dist/src/adapters/OpenSearchAdapter.js +454 -0
  210. package/dist/src/adapters/OpenSearchAdapter.js.map +1 -0
  211. package/dist/src/adapters/PostgreSQLAdapter.d.ts +71 -0
  212. package/dist/src/adapters/PostgreSQLAdapter.d.ts.map +1 -0
  213. package/dist/src/adapters/PostgreSQLAdapter.js +256 -0
  214. package/dist/src/adapters/PostgreSQLAdapter.js.map +1 -0
  215. package/dist/src/adapters/PrismaAdapter.d.ts +115 -0
  216. package/dist/src/adapters/PrismaAdapter.d.ts.map +1 -0
  217. package/dist/src/adapters/PrismaAdapter.js +362 -0
  218. package/dist/src/adapters/PrismaAdapter.js.map +1 -0
  219. package/dist/src/adapters/RedisAdapter.d.ts +71 -0
  220. package/dist/src/adapters/RedisAdapter.d.ts.map +1 -0
  221. package/dist/src/adapters/RedisAdapter.js +227 -0
  222. package/dist/src/adapters/RedisAdapter.js.map +1 -0
  223. package/dist/src/adapters/SQLiteAdapter.d.ts +69 -0
  224. package/dist/src/adapters/SQLiteAdapter.d.ts.map +1 -0
  225. package/dist/src/adapters/SQLiteAdapter.js +308 -0
  226. package/dist/src/adapters/SQLiteAdapter.js.map +1 -0
  227. package/dist/src/adapters/index.d.ts +17 -0
  228. package/dist/src/adapters/index.d.ts.map +1 -0
  229. package/dist/src/adapters/index.js +11 -0
  230. package/dist/src/adapters/index.js.map +1 -0
  231. package/dist/src/constants/index.d.ts +10 -0
  232. package/dist/src/constants/index.d.ts.map +1 -0
  233. package/dist/src/constants/index.js +10 -0
  234. package/dist/src/constants/index.js.map +1 -0
  235. package/dist/src/core/Agent.d.ts +232 -0
  236. package/dist/src/core/Agent.d.ts.map +1 -0
  237. package/dist/src/core/Agent.js +737 -0
  238. package/dist/src/core/Agent.js.map +1 -0
  239. package/dist/src/core/Events.d.ts +26 -0
  240. package/dist/src/core/Events.d.ts.map +1 -0
  241. package/dist/src/core/Events.js +137 -0
  242. package/dist/src/core/Events.js.map +1 -0
  243. package/dist/src/core/PersistenceManager.d.ts +98 -0
  244. package/dist/src/core/PersistenceManager.d.ts.map +1 -0
  245. package/dist/src/core/PersistenceManager.js +257 -0
  246. package/dist/src/core/PersistenceManager.js.map +1 -0
  247. package/dist/src/core/PromptComposer.d.ts +27 -0
  248. package/dist/src/core/PromptComposer.d.ts.map +1 -0
  249. package/dist/src/core/PromptComposer.js +190 -0
  250. package/dist/src/core/PromptComposer.js.map +1 -0
  251. package/dist/src/core/ResponseEngine.d.ts +32 -0
  252. package/dist/src/core/ResponseEngine.d.ts.map +1 -0
  253. package/dist/src/core/ResponseEngine.js +198 -0
  254. package/dist/src/core/ResponseEngine.js.map +1 -0
  255. package/dist/src/core/ResponseModal.d.ts +222 -0
  256. package/dist/src/core/ResponseModal.d.ts.map +1 -0
  257. package/dist/src/core/ResponseModal.js +1583 -0
  258. package/dist/src/core/ResponseModal.js.map +1 -0
  259. package/dist/src/core/ResponsePipeline.d.ts +175 -0
  260. package/dist/src/core/ResponsePipeline.d.ts.map +1 -0
  261. package/dist/src/core/ResponsePipeline.js +545 -0
  262. package/dist/src/core/ResponsePipeline.js.map +1 -0
  263. package/dist/src/core/Route.d.ts +181 -0
  264. package/dist/src/core/Route.d.ts.map +1 -0
  265. package/dist/src/core/Route.js +537 -0
  266. package/dist/src/core/Route.js.map +1 -0
  267. package/dist/src/core/RoutingEngine.d.ts +159 -0
  268. package/dist/src/core/RoutingEngine.d.ts.map +1 -0
  269. package/dist/src/core/RoutingEngine.js +957 -0
  270. package/dist/src/core/RoutingEngine.js.map +1 -0
  271. package/dist/src/core/SessionManager.d.ts +94 -0
  272. package/dist/src/core/SessionManager.d.ts.map +1 -0
  273. package/dist/src/core/SessionManager.js +235 -0
  274. package/dist/src/core/SessionManager.js.map +1 -0
  275. package/dist/src/core/Step.d.ts +170 -0
  276. package/dist/src/core/Step.d.ts.map +1 -0
  277. package/dist/src/core/Step.js +444 -0
  278. package/dist/src/core/Step.js.map +1 -0
  279. package/dist/src/core/ToolManager.d.ts +234 -0
  280. package/dist/src/core/ToolManager.d.ts.map +1 -0
  281. package/dist/src/core/ToolManager.js +1111 -0
  282. package/dist/src/core/ToolManager.js.map +1 -0
  283. package/dist/src/index.d.ts +44 -0
  284. package/dist/src/index.d.ts.map +1 -0
  285. package/dist/src/index.js +37 -0
  286. package/dist/src/index.js.map +1 -0
  287. package/dist/src/providers/AnthropicProvider.d.ts +43 -0
  288. package/dist/src/providers/AnthropicProvider.d.ts.map +1 -0
  289. package/dist/src/providers/AnthropicProvider.js +370 -0
  290. package/dist/src/providers/AnthropicProvider.js.map +1 -0
  291. package/dist/src/providers/GeminiProvider.d.ts +58 -0
  292. package/dist/src/providers/GeminiProvider.d.ts.map +1 -0
  293. package/dist/src/providers/GeminiProvider.js +485 -0
  294. package/dist/src/providers/GeminiProvider.js.map +1 -0
  295. package/dist/src/providers/OpenAIProvider.d.ts +52 -0
  296. package/dist/src/providers/OpenAIProvider.d.ts.map +1 -0
  297. package/dist/src/providers/OpenAIProvider.js +388 -0
  298. package/dist/src/providers/OpenAIProvider.js.map +1 -0
  299. package/dist/src/providers/OpenRouterProvider.d.ts +56 -0
  300. package/dist/src/providers/OpenRouterProvider.d.ts.map +1 -0
  301. package/dist/src/providers/OpenRouterProvider.js +402 -0
  302. package/dist/src/providers/OpenRouterProvider.js.map +1 -0
  303. package/dist/src/providers/index.d.ts +13 -0
  304. package/dist/src/providers/index.d.ts.map +1 -0
  305. package/dist/src/providers/index.js +9 -0
  306. package/dist/src/providers/index.js.map +1 -0
  307. package/dist/src/types/agent.d.ts +181 -0
  308. package/dist/src/types/agent.d.ts.map +1 -0
  309. package/dist/src/types/agent.js +18 -0
  310. package/dist/src/types/agent.js.map +1 -0
  311. package/dist/src/types/ai.d.ts +143 -0
  312. package/dist/src/types/ai.d.ts.map +1 -0
  313. package/dist/src/types/ai.js +5 -0
  314. package/dist/src/types/ai.js.map +1 -0
  315. package/dist/src/types/history.d.ts +178 -0
  316. package/dist/src/types/history.d.ts.map +1 -0
  317. package/dist/src/types/history.js +30 -0
  318. package/dist/src/types/history.js.map +1 -0
  319. package/dist/src/types/index.d.ts +22 -0
  320. package/dist/src/types/index.d.ts.map +1 -0
  321. package/dist/src/types/index.js +12 -0
  322. package/dist/src/types/index.js.map +1 -0
  323. package/dist/src/types/persistence.d.ts +209 -0
  324. package/dist/src/types/persistence.d.ts.map +1 -0
  325. package/dist/src/types/persistence.js +6 -0
  326. package/dist/src/types/persistence.js.map +1 -0
  327. package/dist/src/types/route.d.ts +238 -0
  328. package/dist/src/types/route.d.ts.map +1 -0
  329. package/dist/src/types/route.js +5 -0
  330. package/dist/src/types/route.js.map +1 -0
  331. package/dist/src/types/routing.d.ts +16 -0
  332. package/dist/src/types/routing.d.ts.map +1 -0
  333. package/dist/src/types/routing.js +2 -0
  334. package/dist/src/types/routing.js.map +1 -0
  335. package/dist/src/types/schema.d.ts +22 -0
  336. package/dist/src/types/schema.d.ts.map +1 -0
  337. package/dist/src/types/schema.js +2 -0
  338. package/dist/src/types/schema.js.map +1 -0
  339. package/dist/src/types/session.d.ts +65 -0
  340. package/dist/src/types/session.d.ts.map +1 -0
  341. package/dist/src/types/session.js +5 -0
  342. package/dist/src/types/session.js.map +1 -0
  343. package/dist/src/types/template.d.ts +88 -0
  344. package/dist/src/types/template.d.ts.map +1 -0
  345. package/dist/src/types/template.js +2 -0
  346. package/dist/src/types/template.js.map +1 -0
  347. package/dist/src/types/tool.d.ts +130 -0
  348. package/dist/src/types/tool.d.ts.map +1 -0
  349. package/dist/src/types/tool.js +16 -0
  350. package/dist/src/types/tool.js.map +1 -0
  351. package/dist/src/utils/clone.d.ts +8 -0
  352. package/dist/src/utils/clone.d.ts.map +1 -0
  353. package/dist/src/utils/clone.js +29 -0
  354. package/dist/src/utils/clone.js.map +1 -0
  355. package/dist/src/utils/condition.d.ts +38 -0
  356. package/dist/src/utils/condition.d.ts.map +1 -0
  357. package/dist/src/utils/condition.js +161 -0
  358. package/dist/src/utils/condition.js.map +1 -0
  359. package/dist/src/utils/event.d.ts +6 -0
  360. package/dist/src/utils/event.d.ts.map +1 -0
  361. package/dist/src/utils/event.js +17 -0
  362. package/dist/src/utils/event.js.map +1 -0
  363. package/dist/src/utils/history.d.ts +60 -0
  364. package/dist/src/utils/history.d.ts.map +1 -0
  365. package/dist/src/utils/history.js +263 -0
  366. package/dist/src/utils/history.js.map +1 -0
  367. package/dist/src/utils/id.d.ts +25 -0
  368. package/dist/src/utils/id.d.ts.map +1 -0
  369. package/dist/src/utils/id.js +64 -0
  370. package/dist/src/utils/id.js.map +1 -0
  371. package/dist/src/utils/index.d.ts +15 -0
  372. package/dist/src/utils/index.d.ts.map +1 -0
  373. package/dist/src/utils/index.js +23 -0
  374. package/dist/src/utils/index.js.map +1 -0
  375. package/dist/src/utils/json.d.ts +16 -0
  376. package/dist/src/utils/json.d.ts.map +1 -0
  377. package/dist/src/utils/json.js +43 -0
  378. package/dist/src/utils/json.js.map +1 -0
  379. package/dist/src/utils/logger.d.ts +10 -0
  380. package/dist/src/utils/logger.d.ts.map +1 -0
  381. package/dist/src/utils/logger.js +17 -0
  382. package/dist/src/utils/logger.js.map +1 -0
  383. package/dist/src/utils/retry.d.ts +10 -0
  384. package/dist/src/utils/retry.d.ts.map +1 -0
  385. package/dist/src/utils/retry.js +71 -0
  386. package/dist/src/utils/retry.js.map +1 -0
  387. package/dist/src/utils/session.d.ts +51 -0
  388. package/dist/src/utils/session.d.ts.map +1 -0
  389. package/dist/src/utils/session.js +160 -0
  390. package/dist/src/utils/session.js.map +1 -0
  391. package/dist/src/utils/template.d.ts +155 -0
  392. package/dist/src/utils/template.d.ts.map +1 -0
  393. package/dist/src/utils/template.js +374 -0
  394. package/dist/src/utils/template.js.map +1 -0
  395. package/docs/CONTRIBUTING.md +521 -0
  396. package/docs/README.md +228 -0
  397. package/docs/api/README.md +3258 -0
  398. package/docs/api/overview.md +1134 -0
  399. package/docs/architecture/data-extraction-flow.md +363 -0
  400. package/docs/core/agent/README.md +902 -0
  401. package/docs/core/agent/context-management.md +796 -0
  402. package/docs/core/agent/session-management.md +641 -0
  403. package/docs/core/ai-integration/prompt-composition.md +220 -0
  404. package/docs/core/ai-integration/providers.md +515 -0
  405. package/docs/core/ai-integration/response-processing.md +287 -0
  406. package/docs/core/conversation-flows/data-collection.md +623 -0
  407. package/docs/core/conversation-flows/route-dsl.md +502 -0
  408. package/docs/core/conversation-flows/routes.md +247 -0
  409. package/docs/core/conversation-flows/step-transitions.md +595 -0
  410. package/docs/core/conversation-flows/steps.md +154 -0
  411. package/docs/core/error-handling.md +638 -0
  412. package/docs/core/persistence/adapters.md +255 -0
  413. package/docs/core/persistence/session-storage.md +644 -0
  414. package/docs/core/routing/intelligent-routing.md +466 -0
  415. package/docs/core/tools/tool-definition.md +970 -0
  416. package/docs/core/tools/tool-scoping.md +819 -0
  417. package/docs/guides/advanced-patterns/publishing.md +186 -0
  418. package/docs/guides/error-handling-patterns.md +578 -0
  419. package/docs/guides/getting-started/README.md +696 -0
  420. package/docs/guides/migration/README.md +72 -0
  421. package/docs/guides/migration/flexible-routing-conditions.md +375 -0
  422. package/docs/guides/migration/response-modal-refactor.md +518 -0
  423. package/examples/advanced-patterns/knowledge-based-agent.ts +735 -0
  424. package/examples/advanced-patterns/persistent-onboarding.ts +728 -0
  425. package/examples/advanced-patterns/route-lifecycle-hooks.ts +556 -0
  426. package/examples/advanced-patterns/streaming-responses.ts +578 -0
  427. package/examples/ai-providers/anthropic-integration.ts +388 -0
  428. package/examples/ai-providers/openai-integration.ts +228 -0
  429. package/examples/condition-patterns/function-only-conditions.ts +365 -0
  430. package/examples/condition-patterns/mixed-array-conditions.ts +477 -0
  431. package/examples/condition-patterns/route-skipif-patterns.ts +468 -0
  432. package/examples/condition-patterns/step-skipif-patterns.ts +0 -0
  433. package/examples/condition-patterns/string-only-conditions.ts +296 -0
  434. package/examples/conversation-flows/completion-transitions.ts +318 -0
  435. package/examples/core-concepts/basic-agent.ts +503 -0
  436. package/examples/core-concepts/modern-streaming-api.ts +309 -0
  437. package/examples/core-concepts/schema-driven-extraction.ts +332 -0
  438. package/examples/core-concepts/session-management.ts +494 -0
  439. package/examples/integrations/database-integration.ts +630 -0
  440. package/examples/integrations/healthcare-integration.ts +595 -0
  441. package/examples/integrations/search-integration.ts +530 -0
  442. package/examples/integrations/server-session-management.ts +307 -0
  443. package/examples/persistence/custom-adapter.ts +529 -0
  444. package/examples/persistence/database-persistence.ts +583 -0
  445. package/examples/persistence/memory-sessions.ts +495 -0
  446. package/examples/persistence/prisma-schema.example.prisma +74 -0
  447. package/examples/persistence/redis-persistence.ts +488 -0
  448. package/examples/tools/basic-tools.ts +765 -0
  449. package/examples/tools/data-enrichment-tools.ts +593 -0
  450. package/package.json +125 -0
  451. package/src/adapters/MemoryAdapter.ts +273 -0
  452. package/src/adapters/MongoAdapter.ts +304 -0
  453. package/src/adapters/OpenSearchAdapter.ts +670 -0
  454. package/src/adapters/PostgreSQLAdapter.ts +428 -0
  455. package/src/adapters/PrismaAdapter.ts +553 -0
  456. package/src/adapters/RedisAdapter.ts +377 -0
  457. package/src/adapters/SQLiteAdapter.ts +459 -0
  458. package/src/adapters/index.ts +43 -0
  459. package/src/constants/index.ts +10 -0
  460. package/src/core/Agent.ts +970 -0
  461. package/src/core/Events.ts +164 -0
  462. package/src/core/PersistenceManager.ts +353 -0
  463. package/src/core/PromptComposer.ts +253 -0
  464. package/src/core/ResponseEngine.ts +306 -0
  465. package/src/core/ResponseModal.ts +2050 -0
  466. package/src/core/ResponsePipeline.ts +864 -0
  467. package/src/core/Route.ts +677 -0
  468. package/src/core/RoutingEngine.ts +1396 -0
  469. package/src/core/SessionManager.ts +297 -0
  470. package/src/core/Step.ts +593 -0
  471. package/src/core/ToolManager.ts +1394 -0
  472. package/src/index.ts +155 -0
  473. package/src/providers/AnthropicProvider.ts +560 -0
  474. package/src/providers/GeminiProvider.ts +683 -0
  475. package/src/providers/OpenAIProvider.ts +602 -0
  476. package/src/providers/OpenRouterProvider.ts +613 -0
  477. package/src/providers/index.ts +16 -0
  478. package/src/types/agent.ts +196 -0
  479. package/src/types/ai.ts +158 -0
  480. package/src/types/history.ts +206 -0
  481. package/src/types/index.ts +119 -0
  482. package/src/types/persistence.ts +251 -0
  483. package/src/types/route.ts +272 -0
  484. package/src/types/routing.ts +18 -0
  485. package/src/types/schema.ts +23 -0
  486. package/src/types/session.ts +74 -0
  487. package/src/types/template.ts +104 -0
  488. package/src/types/tool.ts +174 -0
  489. package/src/utils/clone.ts +34 -0
  490. package/src/utils/condition.ts +190 -0
  491. package/src/utils/event.ts +16 -0
  492. package/src/utils/history.ts +306 -0
  493. package/src/utils/id.ts +73 -0
  494. package/src/utils/index.ts +69 -0
  495. package/src/utils/json.ts +46 -0
  496. package/src/utils/logger.ts +19 -0
  497. package/src/utils/retry.ts +97 -0
  498. package/src/utils/session.ts +204 -0
  499. package/src/utils/template.ts +444 -0
@@ -0,0 +1,957 @@
1
+ import { enterRoute, mergeCollected } from "../utils";
2
+ import { PromptComposer } from "./PromptComposer";
3
+ import { END_ROUTE_ID } from "../constants";
4
+ import { createTemplateContext, getLastMessageFromHistory, logger } from "../utils";
5
+ export class RoutingEngine {
6
+ constructor(options) {
7
+ this.options = options;
8
+ }
9
+ /**
10
+ * Enter a route if not already in it, merging initial data
11
+ * @private
12
+ */
13
+ enterRouteIfNeeded(session, route) {
14
+ if (!session.currentRoute || session.currentRoute.id !== route.id) {
15
+ let updatedSession = enterRoute(session, route.id, route.title);
16
+ if (route.initialData) {
17
+ updatedSession = mergeCollected(updatedSession, route.initialData);
18
+ logger.debug(`[RoutingEngine] Merged initial data for route ${route.title}:`, route.initialData);
19
+ }
20
+ logger.debug(`[RoutingEngine] Entered route: ${route.title}`);
21
+ return updatedSession;
22
+ }
23
+ return session;
24
+ }
25
+ /**
26
+ * Optimized decision for single-route scenarios
27
+ * Skips route scoring and only does step selection
28
+ * @private
29
+ */
30
+ async decideSingleRouteStep(params) {
31
+ const { route, session, history, agentOptions, provider, context, signal } = params;
32
+ const selectedRoute = route;
33
+ // Enter route if not already in it (this may merge initial data)
34
+ const updatedSession = this.enterRouteIfNeeded(session, route);
35
+ // Check if this single route is complete (use updated session data)
36
+ const completedRoutes = route.isComplete(updatedSession.data || {}) ? [route] : [];
37
+ // Get candidate steps using new condition evaluation
38
+ const templateContext = createTemplateContext({
39
+ context,
40
+ session: updatedSession,
41
+ history,
42
+ data: updatedSession.data
43
+ });
44
+ const currentStep = updatedSession.currentStep
45
+ ? route.getStep(updatedSession.currentStep.id)
46
+ : undefined;
47
+ const candidates = await this.getCandidateStepsWithConditions(route, currentStep, templateContext);
48
+ if (candidates.length === 0) {
49
+ logger.warn(`[RoutingEngine] Single-route: No valid steps found`);
50
+ return { selectedRoute, session: updatedSession };
51
+ }
52
+ // If only one candidate, check if it's a completion marker
53
+ if (candidates.length === 1) {
54
+ const candidate = candidates[0];
55
+ if (candidate.isRouteComplete) {
56
+ logger.debug(`[RoutingEngine] Single-route: Route complete - all required fields collected or END_ROUTE reached`);
57
+ // Don't return a selectedStep when route is complete - there's no step to enter
58
+ return {
59
+ selectedRoute,
60
+ selectedStep: undefined,
61
+ session: updatedSession,
62
+ isRouteComplete: true,
63
+ completedRoutes,
64
+ };
65
+ }
66
+ else {
67
+ logger.debug(`[RoutingEngine] Single-route: Only one valid step: ${candidate.step.id}`);
68
+ return {
69
+ selectedRoute,
70
+ selectedStep: candidate.step,
71
+ session: updatedSession,
72
+ isRouteComplete: false,
73
+ completedRoutes,
74
+ };
75
+ }
76
+ }
77
+ // No candidates means route is likely complete or has no valid next steps
78
+ if (candidates.length === 0) {
79
+ const dataComplete = route.isComplete(updatedSession.data || {});
80
+ logger.debug(`[RoutingEngine] Single-route: No valid steps found - ` +
81
+ `(data: ${dataComplete ? 'complete' : 'incomplete'}, marking as ${dataComplete ? 'complete' : 'incomplete'})`);
82
+ return {
83
+ selectedRoute,
84
+ selectedStep: undefined,
85
+ session: updatedSession,
86
+ isRouteComplete: dataComplete,
87
+ completedRoutes,
88
+ };
89
+ }
90
+ // Multiple candidates - use AI to select best step
91
+ const lastUserMessage = getLastMessageFromHistory(history);
92
+ // Collect AI context strings from step conditions
93
+ const stepConditionContext = [];
94
+ for (const candidate of candidates) {
95
+ const whenResult = await candidate.step.evaluateWhen(templateContext);
96
+ stepConditionContext.push(...whenResult.aiContextStrings);
97
+ }
98
+ // Check if any candidate is a completion marker (isRouteComplete = true)
99
+ const hasCompletionOption = candidates.some(c => c.isRouteComplete);
100
+ const stepPrompt = await this.buildStepSelectionPrompt({
101
+ route,
102
+ currentStep,
103
+ candidates,
104
+ data: updatedSession.data || {},
105
+ history,
106
+ lastMessage: lastUserMessage,
107
+ agentOptions,
108
+ context,
109
+ session: updatedSession,
110
+ stepConditionContext,
111
+ includeEndRoute: hasCompletionOption,
112
+ });
113
+ const stepSchema = this.buildStepSelectionSchema(candidates.filter(c => !c.isRouteComplete).map((c) => c.step), hasCompletionOption);
114
+ const stepResult = await provider.generateMessage({
115
+ prompt: stepPrompt,
116
+ history,
117
+ context,
118
+ signal,
119
+ parameters: {
120
+ jsonSchema: stepSchema,
121
+ schemaName: "step_selection",
122
+ },
123
+ });
124
+ const selectedStepId = stepResult.structured?.selectedStepId;
125
+ // Check if AI selected END_ROUTE
126
+ if (selectedStepId === END_ROUTE_ID) {
127
+ logger.debug(`[RoutingEngine] Single-route: AI selected END_ROUTE - completing route`);
128
+ logger.debug(`[RoutingEngine] Single-route: Reasoning: ${stepResult.structured?.reasoning}`);
129
+ return {
130
+ selectedRoute,
131
+ selectedStep: undefined,
132
+ responseDirectives: stepResult.structured?.responseDirectives,
133
+ session: updatedSession,
134
+ isRouteComplete: true,
135
+ completedRoutes,
136
+ };
137
+ }
138
+ const selectedStep = candidates.find((c) => c.step.id === selectedStepId);
139
+ if (selectedStep) {
140
+ logger.debug(`[RoutingEngine] Single-route: AI selected step: ${selectedStep.step.id}`);
141
+ logger.debug(`[RoutingEngine] Single-route: Reasoning: ${stepResult.structured?.reasoning}`);
142
+ }
143
+ else {
144
+ logger.warn(`[RoutingEngine] Single-route: Invalid step ID returned, using first candidate`);
145
+ }
146
+ return {
147
+ selectedRoute,
148
+ selectedStep: selectedStep?.step || candidates[0].step,
149
+ responseDirectives: stepResult.structured?.responseDirectives,
150
+ session: updatedSession,
151
+ completedRoutes,
152
+ };
153
+ }
154
+ /**
155
+ * Recursively traverse step chain to find first non-skipped step or END_ROUTE using new condition evaluation
156
+ * @private
157
+ */
158
+ async findFirstValidStepRecursiveWithConditions(currentStep, templateContext, visited) {
159
+ // Prevent infinite loops
160
+ if (visited.has(currentStep.id)) {
161
+ return { aiContextStrings: [] };
162
+ }
163
+ visited.add(currentStep.id);
164
+ const transitions = currentStep.getTransitions();
165
+ const allAiContextStrings = [];
166
+ for (const transition of transitions) {
167
+ const target = transition;
168
+ // Check for END_ROUTE transition
169
+ if (target && target.id === END_ROUTE_ID) {
170
+ // Found END_ROUTE - route is complete
171
+ return {
172
+ isRouteComplete: true,
173
+ aiContextStrings: allAiContextStrings,
174
+ };
175
+ }
176
+ if (!target)
177
+ continue;
178
+ // Evaluate skipIf condition using new system
179
+ const skipResult = await target.evaluateSkipIf(templateContext);
180
+ allAiContextStrings.push(...skipResult.aiContextStrings);
181
+ // If target should NOT be skipped, we found our step
182
+ if (!skipResult.shouldSkip) {
183
+ logger.debug(`[RoutingEngine] Found valid step after skipping: ${target.id}`);
184
+ return {
185
+ step: target,
186
+ isRouteComplete: false,
187
+ aiContextStrings: allAiContextStrings,
188
+ };
189
+ }
190
+ // Target should be skipped too - recurse deeper
191
+ logger.debug(`[RoutingEngine] Skipping step ${target.id} (skipIf condition met), continuing traversal...`);
192
+ const result = await this.findFirstValidStepRecursiveWithConditions(target, templateContext, visited);
193
+ // Collect AI context from recursive call
194
+ if (result.aiContextStrings) {
195
+ allAiContextStrings.push(...result.aiContextStrings);
196
+ }
197
+ // If we found something (a valid step or END_ROUTE), return it
198
+ if (result.step || result.isRouteComplete) {
199
+ return {
200
+ ...result,
201
+ aiContextStrings: allAiContextStrings,
202
+ };
203
+ }
204
+ }
205
+ // No valid steps or END_ROUTE found in this branch
206
+ return { aiContextStrings: allAiContextStrings };
207
+ }
208
+ /**
209
+ * Identify valid next candidate steps using new condition evaluation system
210
+ * Returns step with isRouteComplete flag if route is complete (all steps skipped + has END_ROUTE transition)
211
+ *
212
+ * NEW: Automatically completes route when all required fields are collected
213
+ */
214
+ async getCandidateStepsWithConditions(route, currentStep, templateContext) {
215
+ const candidates = [];
216
+ const data = templateContext.data || {};
217
+ // Check if all required fields are collected
218
+ const allRequiredFieldsCollected = route.isComplete(data);
219
+ if (!currentStep) {
220
+ // Entering route for the first time
221
+ // If all required fields already collected, route is immediately complete
222
+ if (allRequiredFieldsCollected) {
223
+ logger.debug(`[RoutingEngine] Route ${route.title} complete on entry: all required fields already collected`);
224
+ // Return a completion marker - use initial step with completion flag
225
+ candidates.push({
226
+ step: route.initialStep,
227
+ isRouteComplete: true,
228
+ });
229
+ return candidates;
230
+ }
231
+ const initialStep = route.initialStep;
232
+ const skipResult = await initialStep.evaluateSkipIf(templateContext);
233
+ if (skipResult.shouldSkip) {
234
+ // Initial step should be skipped - recursively traverse to find first non-skipped step or END_ROUTE
235
+ const result = await this.findFirstValidStepRecursiveWithConditions(initialStep, templateContext, new Set());
236
+ if (result.isRouteComplete) {
237
+ // All steps are skipped and we reached END_ROUTE
238
+ logger.debug(`[RoutingEngine] Route complete on entry: all steps skipped, END_ROUTE reached`);
239
+ candidates.push({
240
+ step: initialStep,
241
+ isRouteComplete: true,
242
+ });
243
+ }
244
+ else if (result.step) {
245
+ // Found a non-skipped step
246
+ candidates.push({
247
+ step: result.step,
248
+ isRouteComplete: result.isRouteComplete || false,
249
+ });
250
+ }
251
+ // If no step found and not complete, fall through to return empty candidates
252
+ }
253
+ else {
254
+ candidates.push({
255
+ step: initialStep,
256
+ isRouteComplete: false,
257
+ });
258
+ }
259
+ return candidates;
260
+ }
261
+ // Check if all required fields are now collected (may have been collected during this step)
262
+ if (allRequiredFieldsCollected) {
263
+ // Required fields are complete - check if we should continue for optional fields
264
+ const transitions = currentStep.getTransitions();
265
+ const optionalFieldCandidates = [];
266
+ for (const transition of transitions) {
267
+ const target = transition;
268
+ // Check for END_ROUTE transition
269
+ if (target && target.id === END_ROUTE_ID) {
270
+ continue;
271
+ }
272
+ if (!target)
273
+ continue;
274
+ // Check if this step collects only optional fields
275
+ const collectsOnlyOptional = target.collect && target.collect.length > 0 &&
276
+ target.collect.every(field => route.optionalFields?.includes(field));
277
+ if (collectsOnlyOptional) {
278
+ // This step collects optional fields - it's a candidate
279
+ const skipResult = await target.evaluateSkipIf(templateContext);
280
+ if (!skipResult.shouldSkip) {
281
+ optionalFieldCandidates.push({
282
+ step: target,
283
+ isRouteComplete: false,
284
+ });
285
+ }
286
+ }
287
+ }
288
+ // If we have optional field candidates, include them along with END_ROUTE option
289
+ if (optionalFieldCandidates.length > 0) {
290
+ logger.debug(`[RoutingEngine] Required fields complete, but ${optionalFieldCandidates.length} optional field steps available`);
291
+ // Add optional field steps as candidates
292
+ candidates.push(...optionalFieldCandidates);
293
+ // Also add END_ROUTE as a candidate (AI can choose to skip optional fields)
294
+ candidates.push({
295
+ step: currentStep,
296
+ isRouteComplete: true,
297
+ });
298
+ return candidates;
299
+ }
300
+ // No optional fields to collect - route is complete
301
+ logger.debug(`[RoutingEngine] Route ${route.title} complete: all required fields collected, no optional fields remain`);
302
+ return [
303
+ {
304
+ step: currentStep,
305
+ isRouteComplete: true,
306
+ },
307
+ ];
308
+ }
309
+ // Required fields not yet complete - continue normal step progression
310
+ const transitions = currentStep.getTransitions();
311
+ let hasEndRoute = false;
312
+ for (const transition of transitions) {
313
+ const target = transition;
314
+ // Check for END_ROUTE transition (no target step)
315
+ if (target && target.id === END_ROUTE_ID) {
316
+ hasEndRoute = true;
317
+ continue;
318
+ }
319
+ if (!target)
320
+ continue;
321
+ const skipResult = await target.evaluateSkipIf(templateContext);
322
+ if (skipResult.shouldSkip) {
323
+ logger.debug(`[RoutingEngine] Skipping step ${target.id} (skipIf condition met)`);
324
+ // Recursively traverse to find next valid step or END_ROUTE
325
+ const result = await this.findFirstValidStepRecursiveWithConditions(target, templateContext, new Set([currentStep.id]) // Already visited current step
326
+ );
327
+ if (result.isRouteComplete) {
328
+ hasEndRoute = true;
329
+ }
330
+ else if (result.step) {
331
+ // Found a non-skipped step deeper in the chain
332
+ candidates.push({
333
+ step: result.step,
334
+ isRouteComplete: result.isRouteComplete || false,
335
+ });
336
+ }
337
+ continue;
338
+ }
339
+ candidates.push({
340
+ step: target,
341
+ isRouteComplete: hasEndRoute || false,
342
+ });
343
+ }
344
+ // If no valid candidates found
345
+ if (candidates.length === 0) {
346
+ // If current step has END_ROUTE transition, the route is complete
347
+ if (hasEndRoute) {
348
+ logger.debug(`[RoutingEngine] Route complete: all steps processed, END_ROUTE reached`);
349
+ // Return current step with completion flag
350
+ return [
351
+ {
352
+ step: currentStep,
353
+ isRouteComplete: true,
354
+ },
355
+ ];
356
+ }
357
+ // Otherwise, stay in current step if it's still valid
358
+ const currentSkipResult = await currentStep.evaluateSkipIf(templateContext);
359
+ if (!currentSkipResult.shouldSkip) {
360
+ candidates.push({
361
+ step: currentStep,
362
+ isRouteComplete: hasEndRoute || false,
363
+ });
364
+ }
365
+ }
366
+ return candidates;
367
+ }
368
+ /**
369
+ * Full routing orchestration: builds prompt and schema, calls AI, selects route/step,
370
+ * and updates the session (including initialData merge when entering a new route).
371
+ *
372
+ * OPTIMIZATION: If there's only 1 route, skips route scoring and only does step selection.
373
+ * CROSS-ROUTE COMPLETION: Evaluates all routes for completion based on collected data.
374
+ */
375
+ async decideRouteAndStep(params) {
376
+ const { routes, session, history, agentOptions, provider, context, signal, } = params;
377
+ if (routes.length === 0) {
378
+ return { session };
379
+ }
380
+ // CROSS-ROUTE COMPLETION EVALUATION: Check all routes for completion
381
+ const completedRoutes = this.evaluateRouteCompletions(routes, session.data || {});
382
+ // Log completed routes
383
+ if (completedRoutes.length > 0) {
384
+ logger.debug(`[RoutingEngine] Found ${completedRoutes.length} completed routes: ${completedRoutes.map(r => r.title).join(', ')}`);
385
+ }
386
+ // OPTIMIZATION: Single route - skip route scoring, only do step selection
387
+ if (routes.length === 1) {
388
+ const result = await this.decideSingleRouteStep({
389
+ route: routes[0],
390
+ session,
391
+ history,
392
+ agentOptions,
393
+ provider,
394
+ context,
395
+ signal,
396
+ });
397
+ return {
398
+ ...result,
399
+ completedRoutes,
400
+ };
401
+ }
402
+ const lastUserMessage = getLastMessageFromHistory(history);
403
+ const templateContext = createTemplateContext({
404
+ context,
405
+ session,
406
+ history,
407
+ data: session.data
408
+ });
409
+ // Apply route filtering with new condition evaluation system
410
+ const skipIfResult = await this.filterRoutesBySkipIf(routes, templateContext);
411
+ const whenResult = await this.filterRoutesByWhen(skipIfResult.eligibleRoutes, templateContext);
412
+ // Collect all AI context strings from route conditions
413
+ const routeConditionContext = [...skipIfResult.aiContextStrings, ...whenResult.aiContextStrings];
414
+ // Use filtered routes for further processing
415
+ const eligibleRoutes = whenResult.eligibleRoutes;
416
+ logger.debug(`[RoutingEngine] Route filtering: ${routes.length} total → ${skipIfResult.eligibleRoutes.length} after skipIf → ${eligibleRoutes.length} after when`);
417
+ let activeRouteSteps;
418
+ let activeRoute;
419
+ let isRouteComplete = false;
420
+ let updatedSession = session;
421
+ if (session.currentRoute) {
422
+ activeRoute = eligibleRoutes.find((r) => r.id === session.currentRoute?.id);
423
+ if (activeRoute) {
424
+ const currentStep = session.currentStep
425
+ ? activeRoute.getStep(session.currentStep.id)
426
+ : undefined;
427
+ const activeTemplateContext = createTemplateContext({
428
+ ...templateContext,
429
+ session: updatedSession,
430
+ data: updatedSession.data
431
+ });
432
+ const candidates = await this.getCandidateStepsWithConditions(activeRoute, currentStep, activeTemplateContext);
433
+ // Check if route is complete
434
+ // getCandidateStepsWithConditions now automatically handles completion when required fields are collected
435
+ if (candidates.length === 1 && candidates[0].isRouteComplete) {
436
+ isRouteComplete = true;
437
+ logger.debug(`[RoutingEngine] Route ${activeRoute.title} is complete - all required fields collected or END_ROUTE reached`);
438
+ // Don't include steps in routing if route is complete
439
+ activeRouteSteps = undefined;
440
+ }
441
+ else if (candidates.length === 0) {
442
+ // No candidates - check if data is complete
443
+ const dataComplete = activeRoute.isComplete(updatedSession.data || {});
444
+ isRouteComplete = dataComplete;
445
+ logger.debug(`[RoutingEngine] Route ${activeRoute.title} has no valid steps - ` +
446
+ `marking as ${isRouteComplete ? 'complete' : 'incomplete'}`);
447
+ activeRouteSteps = undefined;
448
+ }
449
+ else {
450
+ // Multiple candidates or single non-complete candidate
451
+ activeRouteSteps = candidates.map((c) => c.step);
452
+ logger.debug(`[RoutingEngine] Found ${activeRouteSteps.length} candidate steps for active route`);
453
+ }
454
+ }
455
+ }
456
+ const routingSchema = this.buildDynamicRoutingSchema(eligibleRoutes, undefined, activeRouteSteps);
457
+ const routingPrompt = await this.buildRoutingPrompt({
458
+ history,
459
+ routes: eligibleRoutes,
460
+ lastMessage: lastUserMessage,
461
+ agentOptions,
462
+ session,
463
+ activeRouteSteps,
464
+ context,
465
+ routeConditionContext, // Pass AI context strings from route conditions
466
+ });
467
+ const routingResult = await provider.generateMessage({
468
+ prompt: routingPrompt,
469
+ history,
470
+ context,
471
+ signal,
472
+ parameters: {
473
+ jsonSchema: routingSchema,
474
+ schemaName: "routing_output",
475
+ },
476
+ });
477
+ let selectedRoute;
478
+ let selectedStep;
479
+ let responseDirectives;
480
+ if (routingResult.structured?.routes) {
481
+ // Use cross-route completion evaluation to select optimal route
482
+ const optimalRoute = this.selectOptimalRoute(eligibleRoutes, updatedSession.data || {}, routingResult.structured.routes);
483
+ // If no optimal route found, check why
484
+ if (!optimalRoute) {
485
+ if (eligibleRoutes.length === 0) {
486
+ // No routes passed filtering
487
+ logger.debug(`[RoutingEngine] No eligible routes available - all routes filtered out`);
488
+ selectedRoute = undefined;
489
+ }
490
+ else {
491
+ // Routes exist but selectOptimalRoute returned undefined
492
+ // This means all routes are 100% complete
493
+ logger.debug(`[RoutingEngine] No optimal route found - all ${eligibleRoutes.length} eligible routes are complete`);
494
+ selectedRoute = undefined;
495
+ }
496
+ }
497
+ else {
498
+ selectedRoute = optimalRoute;
499
+ }
500
+ responseDirectives = routingResult.structured.responseDirectives;
501
+ if (selectedRoute === activeRoute &&
502
+ routingResult.structured.selectedStepId &&
503
+ activeRoute) {
504
+ selectedStep = activeRoute.getStep(routingResult.structured.selectedStepId);
505
+ if (selectedStep) {
506
+ logger.debug(`[RoutingEngine] AI selected step: ${selectedStep.id} in active route`);
507
+ logger.debug(`[RoutingEngine] Step reasoning: ${routingResult.structured.stepReasoning}`);
508
+ }
509
+ }
510
+ if (selectedRoute) {
511
+ logger.debug(`[RoutingEngine] Selected route: ${selectedRoute.title}`);
512
+ updatedSession = this.enterRouteIfNeeded(updatedSession, selectedRoute);
513
+ }
514
+ }
515
+ return {
516
+ selectedRoute,
517
+ selectedStep,
518
+ responseDirectives,
519
+ session: updatedSession,
520
+ isRouteComplete,
521
+ completedRoutes,
522
+ };
523
+ }
524
+ /**
525
+ * Filter routes based on skipIf conditions
526
+ * @param routes - All available routes
527
+ * @param templateContext - Context for condition evaluation
528
+ * @returns Object with eligible routes and collected AI context strings
529
+ */
530
+ async filterRoutesBySkipIf(routes, templateContext) {
531
+ const eligibleRoutes = [];
532
+ const aiContextStrings = [];
533
+ for (const route of routes) {
534
+ const skipResult = await route.evaluateSkipIf(templateContext);
535
+ // Collect AI context strings from skipIf conditions
536
+ aiContextStrings.push(...skipResult.aiContextStrings);
537
+ // If route should not be skipped, it's eligible
538
+ if (!skipResult.programmaticResult) {
539
+ eligibleRoutes.push(route);
540
+ }
541
+ else {
542
+ logger.debug(`[RoutingEngine] Skipping route ${route.title} (skipIf condition met)`);
543
+ }
544
+ }
545
+ return { eligibleRoutes, aiContextStrings };
546
+ }
547
+ /**
548
+ * Filter routes based on when conditions
549
+ * @param routes - Routes that passed skipIf filtering
550
+ * @param templateContext - Context for condition evaluation
551
+ * @returns Object with eligible routes and collected AI context strings
552
+ */
553
+ async filterRoutesByWhen(routes, templateContext) {
554
+ const eligibleRoutes = [];
555
+ const aiContextStrings = [];
556
+ for (const route of routes) {
557
+ const whenResult = await route.evaluateWhen(templateContext);
558
+ // Collect AI context strings from when conditions
559
+ aiContextStrings.push(...whenResult.aiContextStrings);
560
+ // If route has no programmatic conditions or they evaluate to true, it's eligible
561
+ if (!whenResult.hasProgrammaticConditions || whenResult.programmaticResult) {
562
+ eligibleRoutes.push(route);
563
+ }
564
+ else {
565
+ logger.debug(`[RoutingEngine] Route ${route.title} not eligible (when condition not met)`);
566
+ }
567
+ }
568
+ return { eligibleRoutes, aiContextStrings };
569
+ }
570
+ /**
571
+ * Evaluate all routes for completion based on collected data
572
+ * @param routes - All available routes
573
+ * @param data - Currently collected agent-level data
574
+ * @returns Array of routes that are complete
575
+ */
576
+ evaluateRouteCompletions(routes, data) {
577
+ return routes.filter(route => route.isComplete(data));
578
+ }
579
+ /**
580
+ * Get completion status for all routes
581
+ * @param routes - All available routes
582
+ * @param data - Currently collected agent-level data
583
+ * @returns Map of route ID to completion progress (0-1)
584
+ */
585
+ getRouteCompletionStatus(routes, data) {
586
+ const completionStatus = new Map();
587
+ for (const route of routes) {
588
+ const progress = route.getCompletionProgress(data);
589
+ completionStatus.set(route.id, progress);
590
+ }
591
+ return completionStatus;
592
+ }
593
+ /**
594
+ * Find the best route to continue based on completion status and user intent
595
+ * Prioritizes routes that are partially complete but not finished
596
+ * IMPORTANT: Completed routes are excluded to prevent re-entering finished tasks
597
+ * @param routes - All available routes
598
+ * @param data - Currently collected agent-level data
599
+ * @param routeScores - AI-generated route scores from routing decision
600
+ * @returns Route that should be prioritized for continuation
601
+ */
602
+ selectOptimalRoute(routes, data, routeScores) {
603
+ const completionStatus = this.getRouteCompletionStatus(routes, data);
604
+ // Create weighted scores combining AI intent scores with completion progress
605
+ const weightedScores = [];
606
+ for (const route of routes) {
607
+ const aiScore = routeScores[route.id] || 0;
608
+ const completionProgress = completionStatus.get(route.id) || 0;
609
+ // ALWAYS skip fully completed routes to prevent re-entering finished tasks
610
+ // Users should not be forced back into completed routes
611
+ if (completionProgress >= 1.0) {
612
+ logger.debug(`[RoutingEngine] Excluding completed route: ${route.title} (100% complete)`);
613
+ continue;
614
+ }
615
+ // Boost partially complete routes that match user intent
616
+ let weightedScore = aiScore;
617
+ if (completionProgress > 0 && completionProgress < 1.0) {
618
+ // Boost score for partially complete routes
619
+ weightedScore += (completionProgress * 20); // Up to 20 point boost
620
+ }
621
+ weightedScores.push({ route, score: weightedScore });
622
+ }
623
+ // Sort by weighted score and return the best option
624
+ weightedScores.sort((a, b) => b.score - a.score);
625
+ if (weightedScores.length > 0) {
626
+ logger.debug(`[RoutingEngine] Selected optimal route: ${weightedScores[0].route.title} ` +
627
+ `(AI: ${routeScores[weightedScores[0].route.id]}, ` +
628
+ `Completion: ${(completionStatus.get(weightedScores[0].route.id) || 0) * 100}%, ` +
629
+ `Weighted: ${weightedScores[0].score})`);
630
+ return weightedScores[0].route;
631
+ }
632
+ return undefined;
633
+ }
634
+ /**
635
+ * Build prompt for step selection within a single route
636
+ * @private
637
+ */
638
+ async buildStepSelectionPrompt(params) {
639
+ const { route, currentStep, candidates, data, history, lastMessage, agentOptions, context, session, stepConditionContext, includeEndRoute = false, } = params;
640
+ const templateContext = createTemplateContext({ context, session, history });
641
+ const pc = new PromptComposer(templateContext);
642
+ // Add agent metadata
643
+ if (agentOptions) {
644
+ await pc.addAgentMeta(agentOptions);
645
+ }
646
+ // Add route context
647
+ await pc.addInstruction(`Active Route: ${route.title}\nDescription: ${route.description || "N/A"}`);
648
+ // Add current step context
649
+ if (currentStep) {
650
+ await pc.addInstruction(`Current Step: ${currentStep.id}\nDescription: ${currentStep.description || "N/A"}`);
651
+ }
652
+ else {
653
+ await pc.addInstruction("Current Step: None (entering route)");
654
+ }
655
+ // Add collected data context
656
+ if (Object.keys(data).length > 0) {
657
+ await pc.addInstruction(`Collected Data So Far:\n${JSON.stringify(data, null, 2)}`);
658
+ }
659
+ else {
660
+ await pc.addInstruction("Collected Data: None yet");
661
+ }
662
+ // Add conversation history
663
+ await pc.addInteractionHistory(history);
664
+ await pc.addLastMessage(lastMessage);
665
+ // Add candidate steps with condition context
666
+ const stepDescriptions = [];
667
+ for (const candidate of candidates) {
668
+ const idx = candidates.indexOf(candidate);
669
+ const parts = [
670
+ `${idx + 1}. Step ID: ${candidate.step.id}`,
671
+ ` Description: ${candidate.step.description || "N/A"}`,
672
+ ];
673
+ // Add when condition context
674
+ if (candidate.step.when) {
675
+ const whenResult = await candidate.step.evaluateWhen(templateContext);
676
+ if (whenResult.aiContextStrings.length > 0) {
677
+ parts.push(` When conditions: ${whenResult.aiContextStrings.join(", ")}`);
678
+ }
679
+ else if (typeof candidate.step.when === 'string') {
680
+ parts.push(` When this step should be completed: ${candidate.step.when}`);
681
+ }
682
+ }
683
+ if (candidate.step.requires && candidate.step.requires.length > 0) {
684
+ parts.push(` Required Data: ${candidate.step.requires.join(", ")}`);
685
+ }
686
+ if (candidate.step.collect && candidate.step.collect.length > 0) {
687
+ parts.push(` Collects: ${candidate.step.collect.join(", ")}`);
688
+ }
689
+ stepDescriptions.push(parts.join("\n"));
690
+ }
691
+ await pc.addInstruction(`Available Steps to Transition To:\n${stepDescriptions.join("\n\n")}`);
692
+ // Add step condition context if available
693
+ if (stepConditionContext && stepConditionContext.length > 0) {
694
+ await pc.addInstruction([
695
+ "",
696
+ "Additional step context from conditions:",
697
+ ...stepConditionContext.map(ctx => `- ${ctx}`),
698
+ "",
699
+ "Consider this context when selecting the most appropriate step.",
700
+ ].join("\n"));
701
+ }
702
+ // Add decision prompt
703
+ const decisionRules = [
704
+ "Task: Decide which step to transition to based on:",
705
+ "1. The user's current message and intent",
706
+ "2. The conversation history and context",
707
+ "3. The collected data we already have",
708
+ "4. The conditions and requirements of each step",
709
+ "5. The logical flow of the conversation",
710
+ "",
711
+ "Rules:",
712
+ "- If a step has a condition, evaluate whether it's met based on context",
713
+ "- If a step requires data we don't have, consider if we should collect it now",
714
+ "- Choose the step that makes the most sense for moving the conversation forward",
715
+ "- Steps with skipIf conditions that are met have already been filtered out",
716
+ ];
717
+ if (includeEndRoute) {
718
+ decisionRules.push("", `- You can select '${END_ROUTE_ID}' to complete this route if:`, " * All required data has been collected", " * The user's intent suggests they're done with this task", " * No further steps are needed to fulfill the user's request");
719
+ }
720
+ decisionRules.push("", "Return ONLY JSON matching the provided schema.");
721
+ await pc.addInstruction(decisionRules.join("\n"));
722
+ return pc.build();
723
+ }
724
+ /**
725
+ * Build schema for step selection
726
+ * @private
727
+ */
728
+ buildStepSelectionSchema(validSteps, includeEndRoute = false) {
729
+ const stepIds = validSteps.map((s) => s.id);
730
+ // Add END_ROUTE as an option if requested (when required fields are complete)
731
+ if (includeEndRoute) {
732
+ stepIds.push(END_ROUTE_ID);
733
+ }
734
+ return {
735
+ description: "Step transition decision based on conversation context and collected data",
736
+ type: "object",
737
+ properties: {
738
+ reasoning: {
739
+ type: "string",
740
+ nullable: false,
741
+ description: "Brief explanation of why this step was selected",
742
+ },
743
+ selectedStepId: {
744
+ type: "string",
745
+ nullable: false,
746
+ description: includeEndRoute
747
+ ? `The ID of the selected step to transition to, or '${END_ROUTE_ID}' to complete the route`
748
+ : "The ID of the selected step to transition to",
749
+ enum: stepIds,
750
+ },
751
+ responseDirectives: {
752
+ type: "array",
753
+ items: { type: "string" },
754
+ description: "Optional bullet points the response should address (concise)",
755
+ },
756
+ },
757
+ required: ["reasoning", "selectedStepId"],
758
+ additionalProperties: false,
759
+ };
760
+ }
761
+ buildDynamicRoutingSchema(routes, extrasSchema, activeRouteSteps) {
762
+ const routeIds = routes.map((r) => r.id);
763
+ const routeProperties = {};
764
+ for (const id of routeIds) {
765
+ routeProperties[id] = {
766
+ type: "number",
767
+ nullable: false,
768
+ description: `Score for route ${id} based on direct evidence, context and semantic fit (0-100)`,
769
+ minimum: 0,
770
+ maximum: 100,
771
+ };
772
+ }
773
+ const base = {
774
+ description: "Full intent analysis: score ALL available routes (0-100) using evidence and context",
775
+ type: "object",
776
+ properties: {
777
+ context: {
778
+ type: "string",
779
+ nullable: false,
780
+ description: "Brief summary of the user's intent/context",
781
+ },
782
+ routes: {
783
+ type: "object",
784
+ properties: routeProperties,
785
+ required: routeIds,
786
+ nullable: false,
787
+ description: "Mapping of routeId to score (0-100)",
788
+ },
789
+ responseDirectives: {
790
+ type: "array",
791
+ items: { type: "string" },
792
+ description: "Optional bullet points the response should address (concise)",
793
+ },
794
+ },
795
+ required: ["context", "routes"],
796
+ additionalProperties: false,
797
+ };
798
+ // Add step selection fields if there's an active route with steps
799
+ if (activeRouteSteps && activeRouteSteps.length > 0) {
800
+ base.properties = base.properties || {};
801
+ base.properties.selectedStepId = {
802
+ type: "string",
803
+ nullable: false,
804
+ description: "The step ID to transition to within the active route (required if continuing in current route)",
805
+ enum: activeRouteSteps.map((s) => s.id),
806
+ };
807
+ base.properties.stepReasoning = {
808
+ type: "string",
809
+ nullable: false,
810
+ description: "Brief explanation of why this step was selected",
811
+ };
812
+ base.required = [
813
+ ...(base.required || []),
814
+ "selectedStepId",
815
+ "stepReasoning",
816
+ ];
817
+ }
818
+ if (extrasSchema) {
819
+ base.properties = base.properties || {};
820
+ base.properties.extractions = extrasSchema;
821
+ }
822
+ return base;
823
+ }
824
+ async buildRoutingPrompt(params) {
825
+ const { history, routes, lastMessage, agentOptions, session, activeRouteSteps, context, routeConditionContext, } = params;
826
+ const templateContext = createTemplateContext({ context, session, history });
827
+ const pc = new PromptComposer(templateContext);
828
+ if (agentOptions) {
829
+ await pc.addAgentMeta(agentOptions);
830
+ }
831
+ await pc.addInstruction("Task: Intent analysis and route scoring (0-100). Score ALL listed routes.");
832
+ // Add session context if available
833
+ if (session?.currentRoute) {
834
+ const sessionInfo = [
835
+ "Current conversation context:",
836
+ `- Active route: ${session.currentRoute.title} (${session.currentRoute.id})`,
837
+ ];
838
+ if (session.currentStep) {
839
+ sessionInfo.push(`- Current step: ${session.currentStep.id}`);
840
+ if (session.currentStep.description) {
841
+ sessionInfo.push(` "${session.currentStep.description}"`);
842
+ }
843
+ }
844
+ if (session.data && Object.keys(session.data).length > 0) {
845
+ sessionInfo.push(`- Collected data: ${JSON.stringify(session.data)}`);
846
+ }
847
+ sessionInfo.push("Note: User is mid-conversation. They may want to continue current route or switch to a new one based on their intent.");
848
+ await pc.addInstruction(sessionInfo.join("\n"));
849
+ // Add cross-route completion status
850
+ const completionStatus = this.getRouteCompletionStatus(routes, session.data || {});
851
+ const completedRoutes = this.evaluateRouteCompletions(routes, session.data || {});
852
+ if (completionStatus.size > 0) {
853
+ const statusInfo = [
854
+ "",
855
+ "Route completion status based on collected data:",
856
+ ];
857
+ for (const route of routes) {
858
+ const progress = completionStatus.get(route.id) || 0;
859
+ const isComplete = completedRoutes.includes(route);
860
+ const progressPercent = Math.round(progress * 100);
861
+ statusInfo.push(`- ${route.title}: ${progressPercent}% complete${isComplete ? ' ✓ COMPLETE' : ''}`);
862
+ if (!isComplete && route.requiredFields) {
863
+ const missingFields = route.getMissingRequiredFields(session.data || {});
864
+ if (missingFields.length > 0) {
865
+ statusInfo.push(` Missing: ${missingFields.join(', ')}`);
866
+ }
867
+ }
868
+ }
869
+ statusInfo.push("", "Consider route completion status when scoring. Partially complete routes may be good candidates for continuation.");
870
+ await pc.addInstruction(statusInfo.join("\n"));
871
+ }
872
+ // Add available steps for the active route
873
+ if (activeRouteSteps && activeRouteSteps.length > 0) {
874
+ const stepInfo = [
875
+ "",
876
+ "Available steps in active route (choose one to transition to):",
877
+ ];
878
+ const activeStepConditionContext = [];
879
+ for (const step of activeRouteSteps) {
880
+ const idx = activeRouteSteps.indexOf(step);
881
+ stepInfo.push(`${idx + 1}. Step: ${step.id}`);
882
+ if (step.description) {
883
+ stepInfo.push(` Description: ${step.description}`);
884
+ }
885
+ // Collect AI context from step conditions
886
+ if (step.when) {
887
+ const whenResult = await step.evaluateWhen(templateContext);
888
+ if (whenResult.aiContextStrings.length > 0) {
889
+ stepInfo.push(` When conditions: ${whenResult.aiContextStrings.join(", ")}`);
890
+ activeStepConditionContext.push(...whenResult.aiContextStrings);
891
+ }
892
+ else if (typeof step.when === 'string') {
893
+ stepInfo.push(` When this step should be completed: ${step.when}`);
894
+ }
895
+ }
896
+ if (step.requires && step.requires.length > 0) {
897
+ stepInfo.push(` Required data: ${step.requires.join(", ")}`);
898
+ }
899
+ if (step.collect && step.collect.length > 0) {
900
+ stepInfo.push(` Will collect: ${step.collect.join(", ")}`);
901
+ }
902
+ }
903
+ stepInfo.push("");
904
+ stepInfo.push("IMPORTANT: You MUST select a step to transition to. Evaluate which step makes the most sense based on:");
905
+ stepInfo.push("- The conversation flow and what's been collected");
906
+ stepInfo.push("- What data is still needed vs already present");
907
+ stepInfo.push("- The logical next step in the conversation");
908
+ stepInfo.push("- Whether conditions for steps are met");
909
+ await pc.addInstruction(stepInfo.join("\n"));
910
+ // Add active step condition context if available
911
+ if (activeStepConditionContext.length > 0) {
912
+ await pc.addInstruction([
913
+ "",
914
+ "Additional context from step conditions:",
915
+ ...activeStepConditionContext.map(ctx => `- ${ctx}`),
916
+ "",
917
+ "Use this context to inform your step selection decision.",
918
+ ].join("\n"));
919
+ }
920
+ }
921
+ }
922
+ await pc.addInteractionHistory(history);
923
+ await pc.addLastMessage(lastMessage);
924
+ await pc.addRoutingOverview(routes);
925
+ // Add route condition context if available
926
+ if (routeConditionContext && routeConditionContext.length > 0) {
927
+ await pc.addInstruction([
928
+ "",
929
+ "Additional routing context from route conditions:",
930
+ ...routeConditionContext.map(ctx => `- ${ctx}`),
931
+ "",
932
+ "Consider this context when scoring routes for relevance.",
933
+ ].join("\n"));
934
+ }
935
+ await pc.addInstruction([
936
+ "Scoring rules:",
937
+ "- 90-100: explicit keywords + clear intent",
938
+ "- 70-89: strong contextual evidence + relevant keywords",
939
+ "- 50-69: moderate relevance",
940
+ "- 30-49: weak connection or ambiguous",
941
+ "- 0-29: minimal/none",
942
+ "Return ONLY JSON matching the provided schema. Include scores for ALL routes.",
943
+ ].join("\n"));
944
+ return pc.build();
945
+ }
946
+ decideRouteFromScores(output) {
947
+ // Optionally limit candidates and apply switching threshold
948
+ const entries = Object.entries(output.routes).sort((a, b) => b[1] - a[1]);
949
+ const limited = this.options?.maxCandidates
950
+ ? entries.slice(0, this.options.maxCandidates)
951
+ : entries;
952
+ const [topId, topScore] = limited[0] || ["", 0];
953
+ // switchThreshold is enforced by caller when a current route exists
954
+ return { routeId: topId, maxScore: topScore };
955
+ }
956
+ }
957
+ //# sourceMappingURL=RoutingEngine.js.map