@falai/agent 0.8.1 → 0.9.0-alpha-2

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 (665) hide show
  1. package/README.md +332 -147
  2. package/dist/{adapters → cjs/src/adapters}/MemoryAdapter.d.ts +4 -4
  3. package/dist/cjs/src/adapters/MemoryAdapter.d.ts.map +1 -0
  4. package/dist/cjs/{adapters → src/adapters}/MemoryAdapter.js +41 -21
  5. package/dist/cjs/src/adapters/MemoryAdapter.js.map +1 -0
  6. package/dist/{adapters → cjs/src/adapters}/MongoAdapter.d.ts +3 -3
  7. package/dist/cjs/src/adapters/MongoAdapter.d.ts.map +1 -0
  8. package/dist/cjs/{adapters → src/adapters}/MongoAdapter.js +2 -1
  9. package/dist/cjs/src/adapters/MongoAdapter.js.map +1 -0
  10. package/dist/cjs/{adapters → src/adapters}/OpenSearchAdapter.d.ts +3 -3
  11. package/dist/cjs/src/adapters/OpenSearchAdapter.d.ts.map +1 -0
  12. package/dist/cjs/{adapters → src/adapters}/OpenSearchAdapter.js +10 -13
  13. package/dist/cjs/src/adapters/OpenSearchAdapter.js.map +1 -0
  14. package/dist/cjs/{adapters → src/adapters}/PostgreSQLAdapter.d.ts +3 -3
  15. package/dist/cjs/src/adapters/PostgreSQLAdapter.d.ts.map +1 -0
  16. package/dist/cjs/{adapters → src/adapters}/PostgreSQLAdapter.js +1 -1
  17. package/dist/cjs/src/adapters/PostgreSQLAdapter.js.map +1 -0
  18. package/dist/cjs/{adapters → src/adapters}/PrismaAdapter.d.ts +3 -3
  19. package/dist/cjs/src/adapters/PrismaAdapter.d.ts.map +1 -0
  20. package/dist/cjs/{adapters → src/adapters}/PrismaAdapter.js +35 -5
  21. package/dist/cjs/src/adapters/PrismaAdapter.js.map +1 -0
  22. package/dist/cjs/{adapters → src/adapters}/RedisAdapter.d.ts +3 -3
  23. package/dist/cjs/src/adapters/RedisAdapter.d.ts.map +1 -0
  24. package/dist/cjs/{adapters → src/adapters}/RedisAdapter.js +3 -2
  25. package/dist/cjs/src/adapters/RedisAdapter.js.map +1 -0
  26. package/dist/{adapters → cjs/src/adapters}/SQLiteAdapter.d.ts +3 -3
  27. package/dist/cjs/src/adapters/SQLiteAdapter.d.ts.map +1 -0
  28. package/dist/cjs/{adapters → src/adapters}/SQLiteAdapter.js +2 -1
  29. package/dist/cjs/src/adapters/SQLiteAdapter.js.map +1 -0
  30. package/dist/cjs/src/adapters/index.d.ts.map +1 -0
  31. package/dist/cjs/src/adapters/index.js.map +1 -0
  32. package/dist/cjs/src/constants/index.d.ts.map +1 -0
  33. package/dist/cjs/src/constants/index.js.map +1 -0
  34. package/dist/cjs/src/core/Agent.d.ts +223 -0
  35. package/dist/cjs/src/core/Agent.d.ts.map +1 -0
  36. package/dist/cjs/src/core/Agent.js +1660 -0
  37. package/dist/cjs/src/core/Agent.js.map +1 -0
  38. package/dist/cjs/src/core/Events.d.ts +26 -0
  39. package/dist/cjs/src/core/Events.d.ts.map +1 -0
  40. package/dist/cjs/src/core/Events.js +144 -0
  41. package/dist/cjs/src/core/Events.js.map +1 -0
  42. package/dist/{core → cjs/src/core}/PersistenceManager.d.ts +21 -19
  43. package/dist/cjs/src/core/PersistenceManager.d.ts.map +1 -0
  44. package/dist/cjs/{core → src/core}/PersistenceManager.js +73 -20
  45. package/dist/cjs/src/core/PersistenceManager.js.map +1 -0
  46. package/dist/cjs/src/core/PromptComposer.d.ts +27 -0
  47. package/dist/cjs/src/core/PromptComposer.d.ts.map +1 -0
  48. package/dist/cjs/src/core/PromptComposer.js +157 -0
  49. package/dist/cjs/src/core/PromptComposer.js.map +1 -0
  50. package/dist/cjs/src/core/ResponseEngine.d.ts +32 -0
  51. package/dist/cjs/src/core/ResponseEngine.d.ts.map +1 -0
  52. package/dist/cjs/src/core/ResponseEngine.js +84 -0
  53. package/dist/cjs/src/core/ResponseEngine.js.map +1 -0
  54. package/dist/cjs/src/core/ResponsePipeline.d.ts +171 -0
  55. package/dist/cjs/src/core/ResponsePipeline.d.ts.map +1 -0
  56. package/dist/cjs/src/core/ResponsePipeline.js +514 -0
  57. package/dist/cjs/src/core/ResponsePipeline.js.map +1 -0
  58. package/dist/cjs/src/core/Route.d.ts +145 -0
  59. package/dist/cjs/src/core/Route.d.ts.map +1 -0
  60. package/dist/cjs/src/core/Route.js +343 -0
  61. package/dist/cjs/src/core/Route.js.map +1 -0
  62. package/dist/cjs/src/core/RoutingEngine.d.ts +129 -0
  63. package/dist/cjs/src/core/RoutingEngine.d.ts.map +1 -0
  64. package/dist/cjs/{core → src/core}/RoutingEngine.js +215 -117
  65. package/dist/cjs/src/core/RoutingEngine.js.map +1 -0
  66. package/dist/cjs/src/core/SessionManager.d.ts +86 -0
  67. package/dist/cjs/src/core/SessionManager.d.ts.map +1 -0
  68. package/dist/cjs/src/core/SessionManager.js +217 -0
  69. package/dist/cjs/src/core/SessionManager.js.map +1 -0
  70. package/dist/cjs/src/core/Step.d.ts +96 -0
  71. package/dist/cjs/src/core/Step.d.ts.map +1 -0
  72. package/dist/cjs/src/core/Step.js +206 -0
  73. package/dist/cjs/src/core/Step.js.map +1 -0
  74. package/dist/cjs/src/core/ToolExecutor.d.ts +45 -0
  75. package/dist/cjs/src/core/ToolExecutor.d.ts.map +1 -0
  76. package/dist/cjs/{core → src/core}/ToolExecutor.js +30 -19
  77. package/dist/cjs/src/core/ToolExecutor.js.map +1 -0
  78. package/dist/{index.d.ts → cjs/src/index.d.ts} +7 -15
  79. package/dist/cjs/src/index.d.ts.map +1 -0
  80. package/dist/cjs/{index.js → src/index.js} +21 -19
  81. package/dist/cjs/src/index.js.map +1 -0
  82. package/dist/cjs/{providers → src/providers}/AnthropicProvider.d.ts +1 -1
  83. package/dist/cjs/src/providers/AnthropicProvider.d.ts.map +1 -0
  84. package/dist/cjs/{providers → src/providers}/AnthropicProvider.js +54 -2
  85. package/dist/cjs/src/providers/AnthropicProvider.js.map +1 -0
  86. package/dist/{providers → cjs/src/providers}/GeminiProvider.d.ts +1 -1
  87. package/dist/cjs/src/providers/GeminiProvider.d.ts.map +1 -0
  88. package/dist/cjs/{providers → src/providers}/GeminiProvider.js +65 -0
  89. package/dist/cjs/src/providers/GeminiProvider.js.map +1 -0
  90. package/dist/cjs/{providers → src/providers}/OpenAIProvider.d.ts +1 -1
  91. package/dist/cjs/src/providers/OpenAIProvider.d.ts.map +1 -0
  92. package/dist/cjs/{providers → src/providers}/OpenAIProvider.js +70 -1
  93. package/dist/cjs/src/providers/OpenAIProvider.js.map +1 -0
  94. package/dist/{providers → cjs/src/providers}/OpenRouterProvider.d.ts +1 -1
  95. package/dist/cjs/src/providers/OpenRouterProvider.d.ts.map +1 -0
  96. package/dist/cjs/{providers → src/providers}/OpenRouterProvider.js +76 -0
  97. package/dist/cjs/src/providers/OpenRouterProvider.js.map +1 -0
  98. package/dist/cjs/src/providers/index.d.ts.map +1 -0
  99. package/dist/cjs/src/providers/index.js.map +1 -0
  100. package/dist/cjs/{types → src/types}/agent.d.ts +80 -41
  101. package/dist/cjs/src/types/agent.d.ts.map +1 -0
  102. package/dist/cjs/src/types/agent.js.map +1 -0
  103. package/dist/cjs/{types → src/types}/ai.d.ts +7 -0
  104. package/dist/cjs/src/types/ai.d.ts.map +1 -0
  105. package/dist/cjs/src/types/ai.js.map +1 -0
  106. package/dist/{types → cjs/src/types}/history.d.ts +76 -18
  107. package/dist/cjs/src/types/history.d.ts.map +1 -0
  108. package/dist/cjs/src/types/history.js +33 -0
  109. package/dist/cjs/src/types/history.js.map +1 -0
  110. package/dist/cjs/src/types/index.d.ts +20 -0
  111. package/dist/cjs/src/types/index.d.ts.map +1 -0
  112. package/dist/cjs/src/types/index.js +30 -0
  113. package/dist/cjs/src/types/index.js.map +1 -0
  114. package/dist/{types → cjs/src/types}/persistence.d.ts +38 -23
  115. package/dist/cjs/src/types/persistence.d.ts.map +1 -0
  116. package/dist/cjs/src/types/persistence.js.map +1 -0
  117. package/dist/cjs/src/types/route.d.ts +235 -0
  118. package/dist/cjs/src/types/route.d.ts.map +1 -0
  119. package/dist/cjs/{types → src/types}/route.js.map +1 -1
  120. package/dist/cjs/src/types/routing.d.ts.map +1 -0
  121. package/dist/{types → cjs/src/types}/routing.js.map +1 -1
  122. package/dist/cjs/src/types/schema.d.ts.map +1 -0
  123. package/dist/{types → cjs/src/types}/schema.js.map +1 -1
  124. package/dist/cjs/src/types/session.d.ts +65 -0
  125. package/dist/cjs/src/types/session.d.ts.map +1 -0
  126. package/dist/cjs/src/types/session.js +6 -0
  127. package/dist/cjs/src/types/session.js.map +1 -0
  128. package/dist/cjs/src/types/template.d.ts +30 -0
  129. package/dist/cjs/src/types/template.d.ts.map +1 -0
  130. package/dist/cjs/src/types/template.js +3 -0
  131. package/dist/cjs/src/types/template.js.map +1 -0
  132. package/dist/{types → cjs/src/types}/tool.d.ts +17 -13
  133. package/dist/cjs/src/types/tool.d.ts.map +1 -0
  134. package/dist/cjs/{types → src/types}/tool.js.map +1 -1
  135. package/dist/cjs/src/utils/clone.d.ts +8 -0
  136. package/dist/cjs/src/utils/clone.d.ts.map +1 -0
  137. package/dist/cjs/src/utils/clone.js +36 -0
  138. package/dist/cjs/src/utils/clone.js.map +1 -0
  139. package/dist/{utils → cjs/src/utils}/event.d.ts +1 -1
  140. package/dist/cjs/src/utils/event.d.ts.map +1 -0
  141. package/dist/cjs/{utils → src/utils}/event.js +2 -2
  142. package/dist/cjs/src/utils/event.js.map +1 -0
  143. package/dist/cjs/src/utils/history.d.ts +31 -0
  144. package/dist/cjs/src/utils/history.d.ts.map +1 -0
  145. package/dist/cjs/src/utils/history.js +128 -0
  146. package/dist/cjs/src/utils/history.js.map +1 -0
  147. package/dist/cjs/src/utils/id.d.ts.map +1 -0
  148. package/dist/cjs/src/utils/id.js.map +1 -0
  149. package/dist/cjs/src/utils/index.d.ts +13 -0
  150. package/dist/cjs/src/utils/index.d.ts.map +1 -0
  151. package/dist/cjs/src/utils/index.js +49 -0
  152. package/dist/cjs/src/utils/index.js.map +1 -0
  153. package/dist/cjs/src/utils/logger.d.ts.map +1 -0
  154. package/dist/cjs/src/utils/logger.js.map +1 -0
  155. package/dist/cjs/src/utils/retry.d.ts.map +1 -0
  156. package/dist/cjs/src/utils/retry.js.map +1 -0
  157. package/dist/cjs/src/utils/session.d.ts +51 -0
  158. package/dist/cjs/src/utils/session.d.ts.map +1 -0
  159. package/dist/cjs/{types → src/utils}/session.js +35 -32
  160. package/dist/cjs/src/utils/session.js.map +1 -0
  161. package/dist/cjs/src/utils/template.d.ts +107 -0
  162. package/dist/cjs/src/utils/template.d.ts.map +1 -0
  163. package/dist/cjs/src/utils/template.js +283 -0
  164. package/dist/cjs/src/utils/template.js.map +1 -0
  165. package/dist/{cjs → src}/adapters/MemoryAdapter.d.ts +4 -4
  166. package/dist/src/adapters/MemoryAdapter.d.ts.map +1 -0
  167. package/dist/{adapters → src/adapters}/MemoryAdapter.js +41 -21
  168. package/dist/src/adapters/MemoryAdapter.js.map +1 -0
  169. package/dist/{cjs → src}/adapters/MongoAdapter.d.ts +3 -3
  170. package/dist/src/adapters/MongoAdapter.d.ts.map +1 -0
  171. package/dist/{adapters → src/adapters}/MongoAdapter.js +2 -1
  172. package/dist/src/adapters/MongoAdapter.js.map +1 -0
  173. package/dist/{adapters → src/adapters}/OpenSearchAdapter.d.ts +3 -3
  174. package/dist/src/adapters/OpenSearchAdapter.d.ts.map +1 -0
  175. package/dist/{adapters → src/adapters}/OpenSearchAdapter.js +10 -13
  176. package/dist/src/adapters/OpenSearchAdapter.js.map +1 -0
  177. package/dist/{adapters → src/adapters}/PostgreSQLAdapter.d.ts +3 -3
  178. package/dist/src/adapters/PostgreSQLAdapter.d.ts.map +1 -0
  179. package/dist/{adapters → src/adapters}/PostgreSQLAdapter.js +1 -1
  180. package/dist/src/adapters/PostgreSQLAdapter.js.map +1 -0
  181. package/dist/{adapters → src/adapters}/PrismaAdapter.d.ts +3 -3
  182. package/dist/src/adapters/PrismaAdapter.d.ts.map +1 -0
  183. package/dist/{adapters → src/adapters}/PrismaAdapter.js +35 -5
  184. package/dist/src/adapters/PrismaAdapter.js.map +1 -0
  185. package/dist/{adapters → src/adapters}/RedisAdapter.d.ts +3 -3
  186. package/dist/src/adapters/RedisAdapter.d.ts.map +1 -0
  187. package/dist/{adapters → src/adapters}/RedisAdapter.js +3 -2
  188. package/dist/src/adapters/RedisAdapter.js.map +1 -0
  189. package/dist/{cjs → src}/adapters/SQLiteAdapter.d.ts +3 -3
  190. package/dist/src/adapters/SQLiteAdapter.d.ts.map +1 -0
  191. package/dist/{adapters → src/adapters}/SQLiteAdapter.js +2 -1
  192. package/dist/src/adapters/SQLiteAdapter.js.map +1 -0
  193. package/dist/src/adapters/index.js.map +1 -0
  194. package/dist/src/constants/index.js.map +1 -0
  195. package/dist/src/core/Agent.d.ts +223 -0
  196. package/dist/src/core/Agent.d.ts.map +1 -0
  197. package/dist/src/core/Agent.js +1656 -0
  198. package/dist/src/core/Agent.js.map +1 -0
  199. package/dist/src/core/Events.d.ts +26 -0
  200. package/dist/src/core/Events.d.ts.map +1 -0
  201. package/dist/src/core/Events.js +137 -0
  202. package/dist/src/core/Events.js.map +1 -0
  203. package/dist/{cjs → src}/core/PersistenceManager.d.ts +21 -19
  204. package/dist/src/core/PersistenceManager.d.ts.map +1 -0
  205. package/dist/{core → src/core}/PersistenceManager.js +71 -18
  206. package/dist/src/core/PersistenceManager.js.map +1 -0
  207. package/dist/src/core/PromptComposer.d.ts +27 -0
  208. package/dist/src/core/PromptComposer.d.ts.map +1 -0
  209. package/dist/src/core/PromptComposer.js +153 -0
  210. package/dist/src/core/PromptComposer.js.map +1 -0
  211. package/dist/src/core/ResponseEngine.d.ts +32 -0
  212. package/dist/src/core/ResponseEngine.d.ts.map +1 -0
  213. package/dist/src/core/ResponseEngine.js +80 -0
  214. package/dist/src/core/ResponseEngine.js.map +1 -0
  215. package/dist/src/core/ResponsePipeline.d.ts +171 -0
  216. package/dist/src/core/ResponsePipeline.d.ts.map +1 -0
  217. package/dist/src/core/ResponsePipeline.js +510 -0
  218. package/dist/src/core/ResponsePipeline.js.map +1 -0
  219. package/dist/src/core/Route.d.ts +145 -0
  220. package/dist/src/core/Route.d.ts.map +1 -0
  221. package/dist/src/core/Route.js +339 -0
  222. package/dist/src/core/Route.js.map +1 -0
  223. package/dist/src/core/RoutingEngine.d.ts +129 -0
  224. package/dist/src/core/RoutingEngine.d.ts.map +1 -0
  225. package/dist/{core → src/core}/RoutingEngine.js +211 -113
  226. package/dist/src/core/RoutingEngine.js.map +1 -0
  227. package/dist/src/core/SessionManager.d.ts +86 -0
  228. package/dist/src/core/SessionManager.d.ts.map +1 -0
  229. package/dist/src/core/SessionManager.js +213 -0
  230. package/dist/src/core/SessionManager.js.map +1 -0
  231. package/dist/src/core/Step.d.ts +96 -0
  232. package/dist/src/core/Step.d.ts.map +1 -0
  233. package/dist/src/core/Step.js +202 -0
  234. package/dist/src/core/Step.js.map +1 -0
  235. package/dist/src/core/ToolExecutor.d.ts +45 -0
  236. package/dist/src/core/ToolExecutor.d.ts.map +1 -0
  237. package/dist/src/core/ToolExecutor.js +80 -0
  238. package/dist/src/core/ToolExecutor.js.map +1 -0
  239. package/dist/{cjs → src}/index.d.ts +7 -15
  240. package/dist/src/index.d.ts.map +1 -0
  241. package/dist/{index.js → src/index.js} +6 -7
  242. package/dist/src/index.js.map +1 -0
  243. package/dist/{providers → src/providers}/AnthropicProvider.d.ts +1 -1
  244. package/dist/src/providers/AnthropicProvider.d.ts.map +1 -0
  245. package/dist/{providers → src/providers}/AnthropicProvider.js +54 -2
  246. package/dist/src/providers/AnthropicProvider.js.map +1 -0
  247. package/dist/{cjs → src}/providers/GeminiProvider.d.ts +1 -1
  248. package/dist/{cjs → src}/providers/GeminiProvider.d.ts.map +1 -1
  249. package/dist/{providers → src/providers}/GeminiProvider.js +65 -0
  250. package/dist/src/providers/GeminiProvider.js.map +1 -0
  251. package/dist/{providers → src/providers}/OpenAIProvider.d.ts +1 -1
  252. package/dist/{cjs → src}/providers/OpenAIProvider.d.ts.map +1 -1
  253. package/dist/{providers → src/providers}/OpenAIProvider.js +70 -1
  254. package/dist/src/providers/OpenAIProvider.js.map +1 -0
  255. package/dist/{cjs → src}/providers/OpenRouterProvider.d.ts +1 -1
  256. package/dist/{cjs → src}/providers/OpenRouterProvider.d.ts.map +1 -1
  257. package/dist/{providers → src/providers}/OpenRouterProvider.js +76 -0
  258. package/dist/src/providers/OpenRouterProvider.js.map +1 -0
  259. package/dist/src/providers/index.js.map +1 -0
  260. package/dist/{types → src/types}/agent.d.ts +80 -41
  261. package/dist/src/types/agent.d.ts.map +1 -0
  262. package/dist/src/types/agent.js.map +1 -0
  263. package/dist/{types → src/types}/ai.d.ts +7 -0
  264. package/dist/src/types/ai.d.ts.map +1 -0
  265. package/dist/{cjs → src}/types/ai.js.map +1 -1
  266. package/dist/{cjs → src}/types/history.d.ts +76 -18
  267. package/dist/src/types/history.d.ts.map +1 -0
  268. package/dist/src/types/history.js +30 -0
  269. package/dist/src/types/history.js.map +1 -0
  270. package/dist/src/types/index.d.ts +20 -0
  271. package/dist/src/types/index.d.ts.map +1 -0
  272. package/dist/src/types/index.js +10 -0
  273. package/dist/src/types/index.js.map +1 -0
  274. package/dist/{cjs → src}/types/persistence.d.ts +38 -23
  275. package/dist/src/types/persistence.d.ts.map +1 -0
  276. package/dist/src/types/persistence.js.map +1 -0
  277. package/dist/src/types/route.d.ts +235 -0
  278. package/dist/src/types/route.d.ts.map +1 -0
  279. package/dist/{types → src/types}/route.js.map +1 -1
  280. package/dist/src/types/session.d.ts +65 -0
  281. package/dist/src/types/session.d.ts.map +1 -0
  282. package/dist/src/types/session.js +5 -0
  283. package/dist/src/types/session.js.map +1 -0
  284. package/dist/src/types/template.d.ts +30 -0
  285. package/dist/src/types/template.d.ts.map +1 -0
  286. package/dist/src/types/template.js +2 -0
  287. package/dist/src/types/template.js.map +1 -0
  288. package/dist/{cjs → src}/types/tool.d.ts +17 -13
  289. package/dist/src/types/tool.d.ts.map +1 -0
  290. package/dist/{types → src/types}/tool.js.map +1 -1
  291. package/dist/src/utils/clone.d.ts +8 -0
  292. package/dist/src/utils/clone.d.ts.map +1 -0
  293. package/dist/src/utils/clone.js +33 -0
  294. package/dist/src/utils/clone.js.map +1 -0
  295. package/dist/{cjs → src}/utils/event.d.ts +1 -1
  296. package/dist/{cjs → src}/utils/event.d.ts.map +1 -1
  297. package/dist/{utils → src/utils}/event.js +1 -1
  298. package/dist/src/utils/event.js.map +1 -0
  299. package/dist/src/utils/history.d.ts +31 -0
  300. package/dist/src/utils/history.d.ts.map +1 -0
  301. package/dist/src/utils/history.js +121 -0
  302. package/dist/src/utils/history.js.map +1 -0
  303. package/dist/src/utils/id.js.map +1 -0
  304. package/dist/src/utils/index.d.ts +13 -0
  305. package/dist/src/utils/index.d.ts.map +1 -0
  306. package/dist/src/utils/index.js +19 -0
  307. package/dist/src/utils/index.js.map +1 -0
  308. package/dist/src/utils/logger.js.map +1 -0
  309. package/dist/src/utils/retry.js.map +1 -0
  310. package/dist/src/utils/session.d.ts +51 -0
  311. package/dist/src/utils/session.d.ts.map +1 -0
  312. package/dist/{types → src/utils}/session.js +33 -32
  313. package/dist/src/utils/session.js.map +1 -0
  314. package/dist/src/utils/template.d.ts +107 -0
  315. package/dist/src/utils/template.d.ts.map +1 -0
  316. package/dist/src/utils/template.js +276 -0
  317. package/dist/src/utils/template.js.map +1 -0
  318. package/docs/README.md +174 -68
  319. package/docs/{API_REFERENCE.md → api/README.md} +925 -255
  320. package/docs/api/overview.md +952 -0
  321. package/docs/core/agent/README.md +787 -0
  322. package/docs/{CONTEXT_MANAGEMENT.md → core/agent/context-management.md} +175 -102
  323. package/docs/{ARCHITECTURE.md → core/agent/session-management.md} +117 -69
  324. package/docs/core/ai-integration/prompt-composition.md +220 -0
  325. package/docs/core/ai-integration/providers.md +515 -0
  326. package/docs/core/ai-integration/response-processing.md +176 -0
  327. package/docs/core/conversation-flows/data-collection.md +623 -0
  328. package/docs/core/conversation-flows/route-dsl.md +502 -0
  329. package/docs/core/conversation-flows/routes.md +117 -0
  330. package/docs/core/conversation-flows/step-transitions.md +595 -0
  331. package/docs/core/conversation-flows/steps.md +154 -0
  332. package/docs/{ADAPTERS.md → core/persistence/adapters.md} +1 -1
  333. package/docs/core/persistence/session-storage.md +644 -0
  334. package/docs/core/routing/intelligent-routing.md +348 -0
  335. package/docs/core/tools/tool-definition.md +346 -0
  336. package/docs/core/tools/tool-execution.md +815 -0
  337. package/docs/core/tools/tool-scoping.md +628 -0
  338. package/docs/guides/getting-started/README.md +406 -0
  339. package/examples/{company-qna-agent.ts → advanced-patterns/knowledge-based-agent.ts} +139 -95
  340. package/examples/{persistent-onboarding.ts → advanced-patterns/persistent-onboarding.ts} +244 -137
  341. package/examples/{rules-prohibitions.ts → advanced-patterns/route-lifecycle-hooks.ts} +130 -84
  342. package/examples/{streaming-agent.ts → advanced-patterns/streaming-responses.ts} +116 -90
  343. package/examples/ai-providers/anthropic-integration.ts +384 -0
  344. package/examples/{openai-agent.ts → ai-providers/openai-integration.ts} +57 -63
  345. package/examples/conversation-flows/completion-transitions.ts +277 -0
  346. package/examples/core-concepts/basic-agent.ts +443 -0
  347. package/examples/core-concepts/schema-driven-extraction.ts +305 -0
  348. package/examples/core-concepts/session-management.ts +406 -0
  349. package/examples/integrations/database-integration.ts +630 -0
  350. package/examples/integrations/healthcare-integration.ts +609 -0
  351. package/examples/{opensearch-persistence.ts → integrations/search-integration.ts} +199 -171
  352. package/examples/integrations/server-session-management.ts +307 -0
  353. package/examples/persistence/custom-adapter.ts +529 -0
  354. package/examples/{prisma-persistence.ts → persistence/database-persistence.ts} +215 -272
  355. package/examples/persistence/memory-sessions.ts +495 -0
  356. package/examples/{prisma-schema.example.prisma → persistence/prisma-schema.example.prisma} +1 -1
  357. package/examples/persistence/redis-persistence.ts +490 -0
  358. package/examples/tools/basic-tools.ts +561 -0
  359. package/examples/{extracted-data-modification.ts → tools/data-enrichment-tools.ts} +128 -117
  360. package/package.json +14 -10
  361. package/src/adapters/MemoryAdapter.ts +74 -46
  362. package/src/adapters/MongoAdapter.ts +33 -24
  363. package/src/adapters/OpenSearchAdapter.ts +41 -37
  364. package/src/adapters/PostgreSQLAdapter.ts +35 -24
  365. package/src/adapters/PrismaAdapter.ts +69 -27
  366. package/src/adapters/RedisAdapter.ts +38 -26
  367. package/src/adapters/SQLiteAdapter.ts +32 -22
  368. package/src/core/Agent.ts +1431 -526
  369. package/src/core/Events.ts +100 -112
  370. package/src/core/PersistenceManager.ts +103 -49
  371. package/src/core/PromptComposer.ts +158 -85
  372. package/src/core/ResponseEngine.ts +128 -46
  373. package/src/core/ResponsePipeline.ts +830 -0
  374. package/src/core/Route.ts +222 -53
  375. package/src/core/RoutingEngine.ts +345 -229
  376. package/src/core/SessionManager.ts +265 -0
  377. package/src/core/Step.ts +157 -67
  378. package/src/core/ToolExecutor.ts +52 -43
  379. package/src/index.ts +31 -37
  380. package/src/providers/AnthropicProvider.ts +71 -5
  381. package/src/providers/GeminiProvider.ts +83 -2
  382. package/src/providers/OpenAIProvider.ts +95 -3
  383. package/src/providers/OpenRouterProvider.ts +102 -2
  384. package/src/types/agent.ts +81 -46
  385. package/src/types/ai.ts +7 -0
  386. package/src/types/history.ts +91 -18
  387. package/src/types/index.ts +45 -7
  388. package/src/types/persistence.ts +45 -28
  389. package/src/types/route.ts +122 -57
  390. package/src/types/session.ts +20 -220
  391. package/src/types/template.ts +36 -0
  392. package/src/types/tool.ts +23 -19
  393. package/src/utils/clone.ts +36 -0
  394. package/src/utils/event.ts +1 -1
  395. package/src/utils/history.ts +143 -0
  396. package/src/utils/index.ts +53 -0
  397. package/src/utils/session.ts +204 -0
  398. package/src/utils/template.ts +335 -0
  399. package/dist/adapters/MemoryAdapter.d.ts.map +0 -1
  400. package/dist/adapters/MemoryAdapter.js.map +0 -1
  401. package/dist/adapters/MongoAdapter.d.ts.map +0 -1
  402. package/dist/adapters/MongoAdapter.js.map +0 -1
  403. package/dist/adapters/OpenSearchAdapter.d.ts.map +0 -1
  404. package/dist/adapters/OpenSearchAdapter.js.map +0 -1
  405. package/dist/adapters/PostgreSQLAdapter.d.ts.map +0 -1
  406. package/dist/adapters/PostgreSQLAdapter.js.map +0 -1
  407. package/dist/adapters/PrismaAdapter.d.ts.map +0 -1
  408. package/dist/adapters/PrismaAdapter.js.map +0 -1
  409. package/dist/adapters/RedisAdapter.d.ts.map +0 -1
  410. package/dist/adapters/RedisAdapter.js.map +0 -1
  411. package/dist/adapters/SQLiteAdapter.d.ts.map +0 -1
  412. package/dist/adapters/SQLiteAdapter.js.map +0 -1
  413. package/dist/adapters/index.d.ts.map +0 -1
  414. package/dist/adapters/index.js.map +0 -1
  415. package/dist/cjs/adapters/MemoryAdapter.d.ts.map +0 -1
  416. package/dist/cjs/adapters/MemoryAdapter.js.map +0 -1
  417. package/dist/cjs/adapters/MongoAdapter.d.ts.map +0 -1
  418. package/dist/cjs/adapters/MongoAdapter.js.map +0 -1
  419. package/dist/cjs/adapters/OpenSearchAdapter.d.ts.map +0 -1
  420. package/dist/cjs/adapters/OpenSearchAdapter.js.map +0 -1
  421. package/dist/cjs/adapters/PostgreSQLAdapter.d.ts.map +0 -1
  422. package/dist/cjs/adapters/PostgreSQLAdapter.js.map +0 -1
  423. package/dist/cjs/adapters/PrismaAdapter.d.ts.map +0 -1
  424. package/dist/cjs/adapters/PrismaAdapter.js.map +0 -1
  425. package/dist/cjs/adapters/RedisAdapter.d.ts.map +0 -1
  426. package/dist/cjs/adapters/RedisAdapter.js.map +0 -1
  427. package/dist/cjs/adapters/SQLiteAdapter.d.ts.map +0 -1
  428. package/dist/cjs/adapters/SQLiteAdapter.js.map +0 -1
  429. package/dist/cjs/adapters/index.js.map +0 -1
  430. package/dist/cjs/constants/index.js.map +0 -1
  431. package/dist/cjs/core/Agent.d.ts +0 -197
  432. package/dist/cjs/core/Agent.d.ts.map +0 -1
  433. package/dist/cjs/core/Agent.js +0 -966
  434. package/dist/cjs/core/Agent.js.map +0 -1
  435. package/dist/cjs/core/DomainRegistry.d.ts +0 -36
  436. package/dist/cjs/core/DomainRegistry.d.ts.map +0 -1
  437. package/dist/cjs/core/DomainRegistry.js +0 -72
  438. package/dist/cjs/core/DomainRegistry.js.map +0 -1
  439. package/dist/cjs/core/Events.d.ts +0 -41
  440. package/dist/cjs/core/Events.d.ts.map +0 -1
  441. package/dist/cjs/core/Events.js +0 -99
  442. package/dist/cjs/core/Events.js.map +0 -1
  443. package/dist/cjs/core/PersistenceManager.d.ts.map +0 -1
  444. package/dist/cjs/core/PersistenceManager.js.map +0 -1
  445. package/dist/cjs/core/PromptComposer.d.ts +0 -24
  446. package/dist/cjs/core/PromptComposer.d.ts.map +0 -1
  447. package/dist/cjs/core/PromptComposer.js +0 -127
  448. package/dist/cjs/core/PromptComposer.js.map +0 -1
  449. package/dist/cjs/core/ResponseEngine.d.ts +0 -14
  450. package/dist/cjs/core/ResponseEngine.d.ts.map +0 -1
  451. package/dist/cjs/core/ResponseEngine.js +0 -56
  452. package/dist/cjs/core/ResponseEngine.js.map +0 -1
  453. package/dist/cjs/core/Route.d.ts +0 -90
  454. package/dist/cjs/core/Route.d.ts.map +0 -1
  455. package/dist/cjs/core/Route.js +0 -203
  456. package/dist/cjs/core/Route.js.map +0 -1
  457. package/dist/cjs/core/RoutingEngine.d.ts +0 -109
  458. package/dist/cjs/core/RoutingEngine.d.ts.map +0 -1
  459. package/dist/cjs/core/RoutingEngine.js.map +0 -1
  460. package/dist/cjs/core/Step.d.ts +0 -72
  461. package/dist/cjs/core/Step.d.ts.map +0 -1
  462. package/dist/cjs/core/Step.js +0 -150
  463. package/dist/cjs/core/Step.js.map +0 -1
  464. package/dist/cjs/core/Tool.d.ts +0 -39
  465. package/dist/cjs/core/Tool.d.ts.map +0 -1
  466. package/dist/cjs/core/Tool.js +0 -34
  467. package/dist/cjs/core/Tool.js.map +0 -1
  468. package/dist/cjs/core/ToolExecutor.d.ts +0 -29
  469. package/dist/cjs/core/ToolExecutor.d.ts.map +0 -1
  470. package/dist/cjs/core/ToolExecutor.js.map +0 -1
  471. package/dist/cjs/core/Transition.d.ts +0 -32
  472. package/dist/cjs/core/Transition.d.ts.map +0 -1
  473. package/dist/cjs/core/Transition.js +0 -89
  474. package/dist/cjs/core/Transition.js.map +0 -1
  475. package/dist/cjs/index.d.ts.map +0 -1
  476. package/dist/cjs/index.js.map +0 -1
  477. package/dist/cjs/providers/AnthropicProvider.d.ts.map +0 -1
  478. package/dist/cjs/providers/AnthropicProvider.js.map +0 -1
  479. package/dist/cjs/providers/GeminiProvider.js.map +0 -1
  480. package/dist/cjs/providers/OpenAIProvider.js.map +0 -1
  481. package/dist/cjs/providers/OpenRouterProvider.js.map +0 -1
  482. package/dist/cjs/providers/index.js.map +0 -1
  483. package/dist/cjs/types/agent.d.ts.map +0 -1
  484. package/dist/cjs/types/agent.js.map +0 -1
  485. package/dist/cjs/types/ai.d.ts.map +0 -1
  486. package/dist/cjs/types/history.d.ts.map +0 -1
  487. package/dist/cjs/types/history.js +0 -37
  488. package/dist/cjs/types/history.js.map +0 -1
  489. package/dist/cjs/types/index.d.ts +0 -12
  490. package/dist/cjs/types/index.d.ts.map +0 -1
  491. package/dist/cjs/types/index.js +0 -12
  492. package/dist/cjs/types/index.js.map +0 -1
  493. package/dist/cjs/types/persistence.d.ts.map +0 -1
  494. package/dist/cjs/types/persistence.js.map +0 -1
  495. package/dist/cjs/types/route.d.ts +0 -175
  496. package/dist/cjs/types/route.d.ts.map +0 -1
  497. package/dist/cjs/types/session.d.ts +0 -104
  498. package/dist/cjs/types/session.d.ts.map +0 -1
  499. package/dist/cjs/types/session.js.map +0 -1
  500. package/dist/cjs/types/tool.d.ts.map +0 -1
  501. package/dist/cjs/utils/event.js.map +0 -1
  502. package/dist/cjs/utils/id.js.map +0 -1
  503. package/dist/cjs/utils/logger.js.map +0 -1
  504. package/dist/cjs/utils/retry.js.map +0 -1
  505. package/dist/constants/index.d.ts.map +0 -1
  506. package/dist/constants/index.js.map +0 -1
  507. package/dist/core/Agent.d.ts +0 -197
  508. package/dist/core/Agent.d.ts.map +0 -1
  509. package/dist/core/Agent.js +0 -962
  510. package/dist/core/Agent.js.map +0 -1
  511. package/dist/core/DomainRegistry.d.ts +0 -36
  512. package/dist/core/DomainRegistry.d.ts.map +0 -1
  513. package/dist/core/DomainRegistry.js +0 -68
  514. package/dist/core/DomainRegistry.js.map +0 -1
  515. package/dist/core/Events.d.ts +0 -41
  516. package/dist/core/Events.d.ts.map +0 -1
  517. package/dist/core/Events.js +0 -94
  518. package/dist/core/Events.js.map +0 -1
  519. package/dist/core/PersistenceManager.d.ts.map +0 -1
  520. package/dist/core/PersistenceManager.js.map +0 -1
  521. package/dist/core/PromptComposer.d.ts +0 -24
  522. package/dist/core/PromptComposer.d.ts.map +0 -1
  523. package/dist/core/PromptComposer.js +0 -123
  524. package/dist/core/PromptComposer.js.map +0 -1
  525. package/dist/core/ResponseEngine.d.ts +0 -14
  526. package/dist/core/ResponseEngine.d.ts.map +0 -1
  527. package/dist/core/ResponseEngine.js +0 -52
  528. package/dist/core/ResponseEngine.js.map +0 -1
  529. package/dist/core/Route.d.ts +0 -90
  530. package/dist/core/Route.d.ts.map +0 -1
  531. package/dist/core/Route.js +0 -199
  532. package/dist/core/Route.js.map +0 -1
  533. package/dist/core/RoutingEngine.d.ts +0 -109
  534. package/dist/core/RoutingEngine.d.ts.map +0 -1
  535. package/dist/core/RoutingEngine.js.map +0 -1
  536. package/dist/core/Step.d.ts +0 -72
  537. package/dist/core/Step.d.ts.map +0 -1
  538. package/dist/core/Step.js +0 -146
  539. package/dist/core/Step.js.map +0 -1
  540. package/dist/core/Tool.d.ts +0 -39
  541. package/dist/core/Tool.d.ts.map +0 -1
  542. package/dist/core/Tool.js +0 -31
  543. package/dist/core/Tool.js.map +0 -1
  544. package/dist/core/ToolExecutor.d.ts +0 -29
  545. package/dist/core/ToolExecutor.d.ts.map +0 -1
  546. package/dist/core/ToolExecutor.js +0 -69
  547. package/dist/core/ToolExecutor.js.map +0 -1
  548. package/dist/core/Transition.d.ts +0 -32
  549. package/dist/core/Transition.d.ts.map +0 -1
  550. package/dist/core/Transition.js +0 -85
  551. package/dist/core/Transition.js.map +0 -1
  552. package/dist/index.d.ts.map +0 -1
  553. package/dist/index.js.map +0 -1
  554. package/dist/providers/AnthropicProvider.d.ts.map +0 -1
  555. package/dist/providers/AnthropicProvider.js.map +0 -1
  556. package/dist/providers/GeminiProvider.d.ts.map +0 -1
  557. package/dist/providers/GeminiProvider.js.map +0 -1
  558. package/dist/providers/OpenAIProvider.d.ts.map +0 -1
  559. package/dist/providers/OpenAIProvider.js.map +0 -1
  560. package/dist/providers/OpenRouterProvider.d.ts.map +0 -1
  561. package/dist/providers/OpenRouterProvider.js.map +0 -1
  562. package/dist/providers/index.d.ts.map +0 -1
  563. package/dist/providers/index.js.map +0 -1
  564. package/dist/types/agent.d.ts.map +0 -1
  565. package/dist/types/agent.js.map +0 -1
  566. package/dist/types/ai.d.ts.map +0 -1
  567. package/dist/types/ai.js.map +0 -1
  568. package/dist/types/history.d.ts.map +0 -1
  569. package/dist/types/history.js +0 -34
  570. package/dist/types/history.js.map +0 -1
  571. package/dist/types/index.d.ts +0 -12
  572. package/dist/types/index.d.ts.map +0 -1
  573. package/dist/types/index.js +0 -6
  574. package/dist/types/index.js.map +0 -1
  575. package/dist/types/persistence.d.ts.map +0 -1
  576. package/dist/types/persistence.js.map +0 -1
  577. package/dist/types/route.d.ts +0 -175
  578. package/dist/types/route.d.ts.map +0 -1
  579. package/dist/types/routing.d.ts.map +0 -1
  580. package/dist/types/schema.d.ts.map +0 -1
  581. package/dist/types/session.d.ts +0 -104
  582. package/dist/types/session.d.ts.map +0 -1
  583. package/dist/types/session.js.map +0 -1
  584. package/dist/types/tool.d.ts.map +0 -1
  585. package/dist/utils/event.d.ts.map +0 -1
  586. package/dist/utils/event.js.map +0 -1
  587. package/dist/utils/id.d.ts.map +0 -1
  588. package/dist/utils/id.js.map +0 -1
  589. package/dist/utils/logger.d.ts.map +0 -1
  590. package/dist/utils/logger.js.map +0 -1
  591. package/dist/utils/retry.d.ts.map +0 -1
  592. package/dist/utils/retry.js.map +0 -1
  593. package/docs/AGENT.md +0 -535
  594. package/docs/DOCS.md +0 -263
  595. package/docs/DOMAINS.md +0 -735
  596. package/docs/EXAMPLES.md +0 -467
  597. package/docs/GETTING_STARTED.md +0 -424
  598. package/docs/PERSISTENCE.md +0 -815
  599. package/docs/PROVIDERS.md +0 -612
  600. package/docs/ROUTES.md +0 -1085
  601. package/docs/STEPS.md +0 -883
  602. package/examples/business-onboarding.ts +0 -791
  603. package/examples/custom-database-persistence.ts +0 -574
  604. package/examples/declarative-agent.ts +0 -401
  605. package/examples/domain-scoping.ts +0 -366
  606. package/examples/healthcare-agent.ts +0 -511
  607. package/examples/redis-persistence.ts +0 -525
  608. package/examples/route-transitions.ts +0 -266
  609. package/examples/travel-agent.ts +0 -584
  610. package/src/core/DomainRegistry.ts +0 -80
  611. package/src/core/Tool.ts +0 -112
  612. package/src/core/Transition.ts +0 -115
  613. /package/dist/{adapters → cjs/src/adapters}/index.d.ts +0 -0
  614. /package/dist/cjs/{adapters → src/adapters}/index.js +0 -0
  615. /package/dist/cjs/{constants → src/constants}/index.d.ts +0 -0
  616. /package/dist/cjs/{constants → src/constants}/index.js +0 -0
  617. /package/dist/cjs/{providers → src/providers}/index.d.ts +0 -0
  618. /package/dist/cjs/{providers → src/providers}/index.js +0 -0
  619. /package/dist/cjs/{types → src/types}/agent.js +0 -0
  620. /package/dist/cjs/{types → src/types}/ai.js +0 -0
  621. /package/dist/cjs/{types → src/types}/persistence.js +0 -0
  622. /package/dist/cjs/{types → src/types}/route.js +0 -0
  623. /package/dist/cjs/{types → src/types}/routing.d.ts +0 -0
  624. /package/dist/cjs/{types → src/types}/routing.js +0 -0
  625. /package/dist/cjs/{types → src/types}/schema.d.ts +0 -0
  626. /package/dist/cjs/{types → src/types}/schema.js +0 -0
  627. /package/dist/cjs/{types → src/types}/tool.js +0 -0
  628. /package/dist/cjs/{utils → src/utils}/id.d.ts +0 -0
  629. /package/dist/cjs/{utils → src/utils}/id.js +0 -0
  630. /package/dist/cjs/{utils → src/utils}/logger.d.ts +0 -0
  631. /package/dist/cjs/{utils → src/utils}/logger.js +0 -0
  632. /package/dist/cjs/{utils → src/utils}/retry.d.ts +0 -0
  633. /package/dist/cjs/{utils → src/utils}/retry.js +0 -0
  634. /package/dist/{cjs → src}/adapters/index.d.ts +0 -0
  635. /package/dist/{cjs → src}/adapters/index.d.ts.map +0 -0
  636. /package/dist/{adapters → src/adapters}/index.js +0 -0
  637. /package/dist/{constants → src/constants}/index.d.ts +0 -0
  638. /package/dist/{cjs → src}/constants/index.d.ts.map +0 -0
  639. /package/dist/{constants → src/constants}/index.js +0 -0
  640. /package/dist/{providers → src/providers}/index.d.ts +0 -0
  641. /package/dist/{cjs → src}/providers/index.d.ts.map +0 -0
  642. /package/dist/{providers → src/providers}/index.js +0 -0
  643. /package/dist/{types → src/types}/agent.js +0 -0
  644. /package/dist/{types → src/types}/ai.js +0 -0
  645. /package/dist/{types → src/types}/persistence.js +0 -0
  646. /package/dist/{types → src/types}/route.js +0 -0
  647. /package/dist/{types → src/types}/routing.d.ts +0 -0
  648. /package/dist/{cjs → src}/types/routing.d.ts.map +0 -0
  649. /package/dist/{types → src/types}/routing.js +0 -0
  650. /package/dist/{cjs → src}/types/routing.js.map +0 -0
  651. /package/dist/{types → src/types}/schema.d.ts +0 -0
  652. /package/dist/{cjs → src}/types/schema.d.ts.map +0 -0
  653. /package/dist/{types → src/types}/schema.js +0 -0
  654. /package/dist/{cjs → src}/types/schema.js.map +0 -0
  655. /package/dist/{types → src/types}/tool.js +0 -0
  656. /package/dist/{utils → src/utils}/id.d.ts +0 -0
  657. /package/dist/{cjs → src}/utils/id.d.ts.map +0 -0
  658. /package/dist/{utils → src/utils}/id.js +0 -0
  659. /package/dist/{utils → src/utils}/logger.d.ts +0 -0
  660. /package/dist/{cjs → src}/utils/logger.d.ts.map +0 -0
  661. /package/dist/{utils → src/utils}/logger.js +0 -0
  662. /package/dist/{utils → src/utils}/retry.d.ts +0 -0
  663. /package/dist/{cjs → src}/utils/retry.d.ts.map +0 -0
  664. /package/dist/{utils → src/utils}/retry.js +0 -0
  665. /package/docs/{PUBLISHING.md → guides/advanced-patterns/publishing.md} +0 -0
@@ -0,0 +1,1656 @@
1
+ /**
2
+ * Core Agent implementation
3
+ */
4
+ import { EventKind, MessageRole } from "../types/history";
5
+ import { enterRoute, enterStep, mergeCollected, logger, LoggerLevel, render, getLastMessageFromHistory, normalizeHistory, cloneDeep, } from "../utils";
6
+ import { Route } from "./Route";
7
+ import { Step } from "./Step";
8
+ import { PersistenceManager } from "./PersistenceManager";
9
+ import { SessionManager } from "./SessionManager";
10
+ import { RoutingEngine } from "./RoutingEngine";
11
+ import { ResponseEngine } from "./ResponseEngine";
12
+ import { ToolExecutor } from "./ToolExecutor";
13
+ import { ResponsePipeline } from "./ResponsePipeline";
14
+ import { END_ROUTE_ID } from "../constants";
15
+ /**
16
+ * Error thrown when data validation fails
17
+ */
18
+ class DataValidationError extends Error {
19
+ constructor(errors, message) {
20
+ super(message || "Data validation failed");
21
+ this.errors = errors;
22
+ this.name = "DataValidationError";
23
+ }
24
+ }
25
+ /**
26
+ * Error thrown when route configuration is invalid
27
+ */
28
+ class RouteConfigurationError extends Error {
29
+ constructor(routeTitle, invalidFields, message) {
30
+ super(message || `Route configuration error in '${routeTitle}'`);
31
+ this.routeTitle = routeTitle;
32
+ this.invalidFields = invalidFields;
33
+ this.name = "RouteConfigurationError";
34
+ }
35
+ }
36
+ /**
37
+ * Main Agent class with generic context and data support
38
+ */
39
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
40
+ export class Agent {
41
+ constructor(options) {
42
+ this.options = options;
43
+ this.terms = [];
44
+ this.guidelines = [];
45
+ this.tools = [];
46
+ this.routes = [];
47
+ this.knowledgeBase = {};
48
+ this.collectedData = {};
49
+ // Set log level based on debug option
50
+ if (options.debug) {
51
+ logger.setLevel(LoggerLevel.DEBUG);
52
+ }
53
+ // Validate context configuration
54
+ if (options.context !== undefined && options.contextProvider) {
55
+ throw new Error("Cannot provide both 'context' and 'contextProvider'. Choose one.");
56
+ }
57
+ // Initialize and validate agent-level schema if provided
58
+ if (options.schema) {
59
+ this.schema = options.schema;
60
+ this.validateSchema(this.schema);
61
+ logger.debug("[Agent] Agent-level schema initialized and validated");
62
+ }
63
+ // Initialize context if provided
64
+ this.context = options.context;
65
+ // Initialize collected data with initial data if provided
66
+ if (options.initialData) {
67
+ if (this.schema) {
68
+ const validation = this.validateData(options.initialData);
69
+ if (!validation.valid) {
70
+ throw new Error(`Initial data validation failed: ${validation.errors.map(e => e.message).join(', ')}`);
71
+ }
72
+ }
73
+ this.collectedData = { ...options.initialData };
74
+ logger.debug("[Agent] Initial data set:", this.collectedData);
75
+ }
76
+ // Initialize current session if provided
77
+ this.currentSession = options.session;
78
+ // Initialize routing and response engines
79
+ this.routingEngine = new RoutingEngine({
80
+ maxCandidates: 5,
81
+ allowRouteSwitch: true,
82
+ switchThreshold: 70,
83
+ });
84
+ this.responseEngine = new ResponseEngine();
85
+ this.responsePipeline = new ResponsePipeline(options, this.routes, this.tools, this.routingEngine, this.updateContext.bind(this), this.updateData.bind(this), this.updateCollectedData.bind(this));
86
+ // Initialize persistence if configured
87
+ if (options.persistence) {
88
+ try {
89
+ // Validate persistence configuration
90
+ if (!options.persistence.adapter) {
91
+ throw new Error("Persistence adapter is required when persistence is configured");
92
+ }
93
+ if (!options.persistence.adapter.sessionRepository) {
94
+ throw new Error("Persistence adapter must provide a sessionRepository");
95
+ }
96
+ if (!options.persistence.adapter.messageRepository) {
97
+ throw new Error("Persistence adapter must provide a messageRepository");
98
+ }
99
+ this.persistenceManager = new PersistenceManager(options.persistence);
100
+ // Initialize the adapter if it has an initialize method
101
+ if (options.persistence.adapter.initialize) {
102
+ options.persistence.adapter.initialize().catch((error) => {
103
+ logger.error("[Agent] Persistence adapter initialization failed:", error instanceof Error ? error.message : String(error));
104
+ });
105
+ }
106
+ }
107
+ catch (error) {
108
+ const errorMessage = error instanceof Error ? error.message : String(error);
109
+ logger.error("[Agent] Failed to initialize persistence:", errorMessage);
110
+ throw new Error(`Failed to initialize persistence: ${errorMessage}`);
111
+ }
112
+ }
113
+ // Initialize from options - use create methods for consistency
114
+ if (options.terms) {
115
+ options.terms.forEach((term) => {
116
+ this.createTerm(term);
117
+ });
118
+ }
119
+ if (options.guidelines) {
120
+ options.guidelines.forEach((guideline) => {
121
+ this.createGuideline(guideline);
122
+ });
123
+ }
124
+ if (options.tools) {
125
+ options.tools.forEach((tool) => {
126
+ this.createTool(tool);
127
+ });
128
+ }
129
+ if (options.routes) {
130
+ options.routes.forEach((routeOptions) => {
131
+ this.createRoute(routeOptions);
132
+ });
133
+ }
134
+ // Initialize knowledge base
135
+ if (options.knowledgeBase) {
136
+ this.knowledgeBase = { ...options.knowledgeBase };
137
+ }
138
+ // Initialize session manager
139
+ this.session = new SessionManager(this.persistenceManager);
140
+ // Store sessionId for later use in getOrCreate calls
141
+ if (options.sessionId) {
142
+ // The session will be loaded on first getOrCreate call
143
+ this.session.getOrCreate(options.sessionId).catch((err) => {
144
+ logger.error("Failed to start session", err);
145
+ });
146
+ }
147
+ }
148
+ /**
149
+ * Validate the agent-level schema structure
150
+ * @private
151
+ */
152
+ validateSchema(schema) {
153
+ if (!schema || typeof schema !== 'object') {
154
+ throw new Error("Agent schema must be a valid JSON Schema object. " +
155
+ "Provide a schema with 'type': 'object' and 'properties' to define the data structure.");
156
+ }
157
+ if (schema.type !== 'object') {
158
+ throw new Error(`Agent schema must be of type 'object', but received '${String(schema.type)}'. ` +
159
+ "Agent-level schemas must define object structures for data collection.");
160
+ }
161
+ if (!schema.properties || typeof schema.properties !== 'object') {
162
+ throw new Error("Agent schema must have a 'properties' field defining the data fields. " +
163
+ "Example: { type: 'object', properties: { name: { type: 'string' }, email: { type: 'string' } } }");
164
+ }
165
+ logger.debug("[Agent] Schema validation passed");
166
+ }
167
+ /**
168
+ * Validate data against the agent-level schema
169
+ */
170
+ validateData(data) {
171
+ if (!this.schema) {
172
+ // No schema defined, consider all data valid
173
+ return { valid: true, errors: [], warnings: [] };
174
+ }
175
+ const errors = [];
176
+ const warnings = [];
177
+ // Basic validation - check if provided fields exist in schema
178
+ if (this.schema.properties) {
179
+ for (const [key, value] of Object.entries(data)) {
180
+ if (!(key in this.schema.properties)) {
181
+ errors.push({
182
+ field: key,
183
+ value,
184
+ message: `Field '${key}' is not defined in agent schema`,
185
+ schemaPath: `properties.${key}`
186
+ });
187
+ }
188
+ }
189
+ }
190
+ // Check required fields if specified
191
+ if (this.schema.required && Array.isArray(this.schema.required)) {
192
+ for (const requiredField of this.schema.required) {
193
+ if (!(requiredField in data) || data[requiredField] === undefined) {
194
+ warnings.push({
195
+ field: requiredField,
196
+ value: undefined,
197
+ message: `Required field '${requiredField}' is missing`,
198
+ schemaPath: `required`
199
+ });
200
+ }
201
+ }
202
+ }
203
+ return {
204
+ valid: errors.length === 0,
205
+ errors,
206
+ warnings
207
+ };
208
+ }
209
+ /**
210
+ * Check if a field is valid according to the agent schema
211
+ * @param field - The field key to validate
212
+ * @returns true if field exists in schema or no schema is defined, false otherwise
213
+ */
214
+ isValidSchemaField(field) {
215
+ if (!this.schema || !this.schema.properties) {
216
+ // No schema defined, consider all fields valid
217
+ return true;
218
+ }
219
+ return field in this.schema.properties;
220
+ }
221
+ /**
222
+ * Get the current collected data
223
+ */
224
+ getCollectedData() {
225
+ return { ...this.collectedData };
226
+ }
227
+ /**
228
+ * Update collected data with validation
229
+ */
230
+ async updateCollectedData(updates) {
231
+ // Validate the updates
232
+ const validation = this.validateData(updates);
233
+ if (!validation.valid) {
234
+ const errorMessages = validation.errors.map(e => e.message).join(', ');
235
+ throw new DataValidationError(validation.errors, `Data validation failed: ${errorMessages}`);
236
+ }
237
+ // Log warnings if any
238
+ if (validation.warnings.length > 0) {
239
+ const warningMessages = validation.warnings.map(w => w.message).join(', ');
240
+ logger.warn(`[Agent] Data validation warnings: ${warningMessages}`);
241
+ }
242
+ // Merge updates with current data
243
+ const previousData = { ...this.collectedData };
244
+ this.collectedData = {
245
+ ...this.collectedData,
246
+ ...updates
247
+ };
248
+ // Trigger agent-level lifecycle hook if configured
249
+ if (this.options.hooks?.onDataUpdate) {
250
+ this.collectedData = await this.options.hooks.onDataUpdate(this.collectedData, previousData);
251
+ }
252
+ // Update current session if it exists to keep it in sync
253
+ if (this.currentSession) {
254
+ this.currentSession = mergeCollected(this.currentSession, this.collectedData);
255
+ }
256
+ logger.debug("[Agent] Collected data updated:", updates);
257
+ }
258
+ /**
259
+ * Get agent name
260
+ */
261
+ get name() {
262
+ return this.options.name;
263
+ }
264
+ /**
265
+ * Get agent description
266
+ */
267
+ get description() {
268
+ return this.options.description;
269
+ }
270
+ /**
271
+ * Get agent goal
272
+ */
273
+ get goal() {
274
+ return this.options.goal;
275
+ }
276
+ /**
277
+ * Get agent identity
278
+ */
279
+ get identity() {
280
+ return this.options.identity;
281
+ }
282
+ /**
283
+ * Create a new route (journey) using agent-level data type
284
+ */
285
+ createRoute(options) {
286
+ // Validate that requiredFields exist in agent schema
287
+ if (options.requiredFields && this.schema?.properties) {
288
+ const invalidRequiredFields = options.requiredFields.filter(field => !(String(field) in this.schema.properties));
289
+ if (invalidRequiredFields.length > 0) {
290
+ throw new RouteConfigurationError(options.title, invalidRequiredFields.map(f => String(f)), `Invalid required fields in route '${options.title}': ${invalidRequiredFields.join(', ')}. ` +
291
+ `Must be valid keys from agent schema. Available fields: ${Object.keys(this.schema.properties).join(', ')}.`);
292
+ }
293
+ }
294
+ // Validate that optionalFields exist in agent schema
295
+ if (options.optionalFields && this.schema?.properties) {
296
+ const invalidOptionalFields = options.optionalFields.filter(field => !(String(field) in this.schema.properties));
297
+ if (invalidOptionalFields.length > 0) {
298
+ throw new RouteConfigurationError(options.title, invalidOptionalFields.map(f => String(f)), `Invalid optional fields in route '${options.title}': ${invalidOptionalFields.join(', ')}. ` +
299
+ `Must be valid keys from agent schema. Available fields: ${Object.keys(this.schema.properties).join(', ')}.`);
300
+ }
301
+ }
302
+ const route = new Route(options);
303
+ this.routes.push(route);
304
+ return route;
305
+ }
306
+ /**
307
+ * Create a domain term for the glossary
308
+ */
309
+ createTerm(term) {
310
+ this.terms.push(term);
311
+ return this;
312
+ }
313
+ /**
314
+ * Create a behavioral guideline
315
+ */
316
+ createGuideline(guideline) {
317
+ const guidelineWithId = {
318
+ ...guideline,
319
+ id: guideline.id || `guideline_${this.guidelines.length}`,
320
+ enabled: guideline.enabled !== false, // Default to true
321
+ };
322
+ this.guidelines.push(guidelineWithId);
323
+ return this;
324
+ }
325
+ /**
326
+ * Register a tool at the agent level
327
+ */
328
+ createTool(tool) {
329
+ this.tools.push(tool);
330
+ return this;
331
+ }
332
+ /**
333
+ * Register multiple tools at the agent level
334
+ */
335
+ registerTools(tools) {
336
+ tools.forEach((tool) => this.createTool(tool));
337
+ return this;
338
+ }
339
+ /**
340
+ * Update the agent's context
341
+ * Triggers both agent-level and route-specific onContextUpdate lifecycle hooks if configured
342
+ */
343
+ async updateContext(updates) {
344
+ const previousContext = this.context;
345
+ // Merge updates with current context
346
+ this.context = {
347
+ ...this.context,
348
+ ...updates,
349
+ };
350
+ // Trigger route-specific lifecycle hook if configured and session has current route
351
+ if (this.currentSession?.currentRoute) {
352
+ const currentRoute = this.routes.find((r) => r.id === this.currentSession.currentRoute?.id);
353
+ if (currentRoute?.hooks?.onContextUpdate &&
354
+ previousContext !== undefined) {
355
+ await currentRoute.handleContextUpdate(this.context, previousContext);
356
+ }
357
+ }
358
+ // Trigger agent-level lifecycle hook if configured
359
+ if (this.options.hooks?.onContextUpdate && previousContext !== undefined) {
360
+ await this.options.hooks.onContextUpdate(this.context, previousContext);
361
+ }
362
+ }
363
+ /**
364
+ * Update collected data in session with lifecycle hook support
365
+ * Triggers both agent-level and route-specific onDataUpdate lifecycle hooks if configured
366
+ * @internal
367
+ */
368
+ async updateData(session, dataUpdate) {
369
+ const previousCollected = { ...session.data };
370
+ // Merge new collected data
371
+ let newCollected = {
372
+ ...session.data,
373
+ ...dataUpdate,
374
+ };
375
+ // Trigger route-specific lifecycle hook if configured and session has a current route
376
+ if (session.currentRoute) {
377
+ const currentRoute = this.routes.find((r) => r.id === session.currentRoute?.id);
378
+ if (currentRoute?.hooks?.onDataUpdate) {
379
+ newCollected = await currentRoute.handleDataUpdate(newCollected, previousCollected);
380
+ }
381
+ }
382
+ // Trigger agent-level lifecycle hook if configured
383
+ if (this.options.hooks?.onDataUpdate) {
384
+ newCollected = (await this.options.hooks.onDataUpdate(newCollected, previousCollected));
385
+ }
386
+ // Update agent's collected data to stay in sync
387
+ this.collectedData = { ...newCollected };
388
+ // Return updated session
389
+ return mergeCollected(session, newCollected);
390
+ }
391
+ /**
392
+ * Get current context (fetches from provider if configured)
393
+ */
394
+ async getContext() {
395
+ // If context provider is configured, use it to fetch fresh context
396
+ if (this.options.contextProvider) {
397
+ return await this.options.contextProvider();
398
+ }
399
+ // Otherwise return the stored context
400
+ return this.context;
401
+ }
402
+ /**
403
+ * Get current schema
404
+ */
405
+ getSchema() {
406
+ return this.schema;
407
+ }
408
+ /**
409
+ * Generate a response based on history and context as a stream
410
+ */
411
+ async *respondStream(params) {
412
+ const { history: simpleHistory, signal } = params;
413
+ const history = normalizeHistory(simpleHistory);
414
+ // Prepare context and session using the response pipeline
415
+ this.responsePipeline.setContext(this.context);
416
+ this.responsePipeline.setCurrentSession(this.currentSession);
417
+ let session;
418
+ const responseContext = await this.responsePipeline.prepareResponseContext({
419
+ contextOverride: params.contextOverride,
420
+ session: params.session ? cloneDeep(params.session) : undefined,
421
+ });
422
+ const { effectiveContext } = responseContext;
423
+ session = responseContext.session;
424
+ // Merge agent's collected data into session (agent data takes precedence)
425
+ if (Object.keys(this.collectedData).length > 0) {
426
+ session = mergeCollected(session, this.collectedData);
427
+ logger.debug("[Agent] Merged agent collected data into session:", this.collectedData);
428
+ }
429
+ // Update our stored context if it was modified by beforeRespond hook
430
+ this.context = this.responsePipeline.getStoredContext();
431
+ // PHASE 1: PREPARE - Execute prepare function if current step has one
432
+ if (session.currentRoute && session.currentStep) {
433
+ const currentRoute = this.routes.find((r) => r.id === session.currentRoute?.id);
434
+ if (currentRoute) {
435
+ const currentStep = currentRoute.getStep(session.currentStep.id);
436
+ if (currentStep?.prepare) {
437
+ logger.debug(`[Agent] Executing prepare for step: ${currentStep.id}`);
438
+ await this.executePrepareFinalize(currentStep.prepare, effectiveContext, session.data, currentRoute, currentStep);
439
+ }
440
+ }
441
+ }
442
+ // PHASE 2: ROUTING + STEP SELECTION - Use response pipeline
443
+ const routingResult = await this.responsePipeline.handleRoutingAndStepSelection({
444
+ session,
445
+ history,
446
+ context: effectiveContext,
447
+ signal,
448
+ });
449
+ const selectedRoute = routingResult.selectedRoute;
450
+ const selectedStep = routingResult.selectedStep;
451
+ const responseDirectives = routingResult.responseDirectives;
452
+ const isRouteComplete = routingResult.isRouteComplete;
453
+ session = routingResult.session;
454
+ // PHASE 3: DETERMINE NEXT STEP - Use pipeline method
455
+ const stepResult = this.responsePipeline.determineNextStep({
456
+ selectedRoute,
457
+ selectedStep,
458
+ session,
459
+ isRouteComplete,
460
+ });
461
+ const nextStep = stepResult.nextStep;
462
+ session = stepResult.session;
463
+ if (selectedRoute && !isRouteComplete) {
464
+ // PHASE 4: RESPONSE GENERATION - Stream message using selected route and step
465
+ // Get last user message
466
+ const lastUserMessage = getLastMessageFromHistory(history);
467
+ // Build response schema for this route (with collect fields from step)
468
+ const responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, nextStep, this.schema);
469
+ // Check if selected route and next step are defined
470
+ if (!selectedRoute || !nextStep) {
471
+ logger.error("[Agent] Selected route or next step is not defined", {
472
+ selectedRoute,
473
+ nextStep,
474
+ });
475
+ throw new Error("Selected route or next step is not defined");
476
+ }
477
+ // Build response prompt
478
+ const responsePrompt = await this.responseEngine.buildResponsePrompt({
479
+ route: selectedRoute,
480
+ currentStep: nextStep,
481
+ rules: selectedRoute.getRules(),
482
+ prohibitions: selectedRoute.getProhibitions(),
483
+ directives: responseDirectives,
484
+ history,
485
+ lastMessage: lastUserMessage,
486
+ agentOptions: this.options,
487
+ // Combine agent and route properties according to the specified logic
488
+ combinedGuidelines: [
489
+ ...this.getGuidelines(),
490
+ ...selectedRoute.getGuidelines(),
491
+ ],
492
+ combinedTerms: this.mergeTerms(this.getTerms(), selectedRoute.getTerms()),
493
+ context: effectiveContext,
494
+ session,
495
+ agentSchema: this.schema,
496
+ });
497
+ // Collect available tools for AI
498
+ const availableTools = this.collectAvailableTools(selectedRoute, nextStep);
499
+ // Generate message stream using AI provider
500
+ const stream = this.options.provider.generateMessageStream({
501
+ prompt: responsePrompt,
502
+ history,
503
+ context: effectiveContext,
504
+ tools: availableTools,
505
+ signal,
506
+ parameters: {
507
+ jsonSchema: responseSchema,
508
+ schemaName: "response_stream_output",
509
+ },
510
+ });
511
+ // Stream chunks to caller
512
+ for await (const chunk of stream) {
513
+ let toolCalls = undefined;
514
+ // Extract tool calls from AI response on final chunk
515
+ if (chunk.done && chunk.structured?.toolCalls) {
516
+ toolCalls = chunk.structured.toolCalls;
517
+ // Execute dynamic tool calls
518
+ if (toolCalls.length > 0) {
519
+ logger.debug(`[Agent] Executing ${toolCalls.length} dynamic tool calls`);
520
+ for (const toolCall of toolCalls) {
521
+ const tool = this.findAvailableTool(toolCall.toolName, selectedRoute);
522
+ if (!tool) {
523
+ logger.warn(`[Agent] Tool not found: ${toolCall.toolName}`);
524
+ continue;
525
+ }
526
+ const toolExecutor = new ToolExecutor();
527
+ const result = await toolExecutor.executeTool({
528
+ tool: tool,
529
+ context: effectiveContext,
530
+ updateContext: this.updateContext.bind(this),
531
+ updateData: this.updateCollectedData.bind(this),
532
+ history,
533
+ data: session.data,
534
+ toolArguments: toolCall.arguments,
535
+ });
536
+ // Update context with tool results
537
+ if (result.contextUpdate) {
538
+ await this.updateContext(result.contextUpdate);
539
+ }
540
+ // Update collected data with tool results
541
+ if (result.dataUpdate) {
542
+ session = await this.updateData(session, result.dataUpdate);
543
+ logger.debug(`[Agent] Tool updated collected data:`, result.dataUpdate);
544
+ }
545
+ logger.debug(`[Agent] Executed dynamic tool: ${result.toolName} (success: ${result.success})`);
546
+ }
547
+ }
548
+ }
549
+ // TOOL LOOP: Allow AI to make follow-up tool calls after initial tool execution (streaming)
550
+ const MAX_TOOL_LOOPS = 5;
551
+ let toolLoopCount = 0;
552
+ let hasToolCalls = toolCalls && toolCalls.length > 0;
553
+ while (hasToolCalls && toolLoopCount < MAX_TOOL_LOOPS) {
554
+ toolLoopCount++;
555
+ logger.debug(`[Agent] Starting streaming tool loop ${toolLoopCount}/${MAX_TOOL_LOOPS}`);
556
+ // Add tool execution results to history so AI knows what happened
557
+ const toolResultsEvents = [];
558
+ for (const toolCall of toolCalls || []) {
559
+ const tool = this.findAvailableTool(toolCall.toolName, selectedRoute);
560
+ if (tool) {
561
+ toolResultsEvents.push({
562
+ kind: EventKind.TOOL,
563
+ source: MessageRole.AGENT,
564
+ timestamp: new Date().toISOString(),
565
+ data: {
566
+ tool_calls: [
567
+ {
568
+ tool_id: toolCall.toolName,
569
+ arguments: toolCall.arguments,
570
+ result: {
571
+ data: "Tool executed successfully",
572
+ },
573
+ },
574
+ ],
575
+ },
576
+ });
577
+ }
578
+ }
579
+ // Create updated history with tool results
580
+ const updatedHistory = [...history, ...toolResultsEvents];
581
+ // Make follow-up streaming AI call to see if more tools are needed
582
+ const followUpStream = this.options.provider.generateMessageStream({
583
+ prompt: responsePrompt,
584
+ history: updatedHistory,
585
+ context: effectiveContext,
586
+ tools: availableTools,
587
+ parameters: {
588
+ jsonSchema: responseSchema,
589
+ schemaName: "tool_followup",
590
+ },
591
+ signal,
592
+ });
593
+ let followUpToolCalls;
594
+ for await (const followUpChunk of followUpStream) {
595
+ // Extract tool calls from follow-up stream
596
+ if (followUpChunk.done && followUpChunk.structured?.toolCalls) {
597
+ followUpToolCalls = followUpChunk.structured.toolCalls;
598
+ }
599
+ }
600
+ hasToolCalls = followUpToolCalls && followUpToolCalls.length > 0;
601
+ if (hasToolCalls) {
602
+ logger.debug(`[Agent] Follow-up streaming call produced ${followUpToolCalls.length} additional tool calls`);
603
+ // Execute the follow-up tool calls
604
+ for (const toolCall of followUpToolCalls) {
605
+ const tool = this.findAvailableTool(toolCall.toolName, selectedRoute);
606
+ if (!tool) {
607
+ logger.warn(`[Agent] Tool not found in streaming follow-up: ${toolCall.toolName}`);
608
+ continue;
609
+ }
610
+ const toolExecutor = new ToolExecutor();
611
+ const result = await toolExecutor.executeTool({
612
+ tool: tool,
613
+ context: effectiveContext,
614
+ updateContext: this.updateContext.bind(this),
615
+ updateData: this.updateCollectedData.bind(this),
616
+ history: updatedHistory,
617
+ data: session.data,
618
+ toolArguments: toolCall.arguments,
619
+ });
620
+ // Update context with follow-up tool results
621
+ if (result.contextUpdate) {
622
+ await this.updateContext(result.contextUpdate);
623
+ }
624
+ if (result.dataUpdate) {
625
+ session = await this.updateData(session, result.dataUpdate);
626
+ logger.debug(`[Agent] Streaming follow-up tool updated collected data:`, result.dataUpdate);
627
+ }
628
+ logger.debug(`[Agent] Executed streaming follow-up tool: ${result.toolName} (success: ${result.success})`);
629
+ }
630
+ // Update toolCalls for next iteration
631
+ toolCalls = followUpToolCalls;
632
+ }
633
+ else {
634
+ logger.debug(`[Agent] Streaming tool loop completed after ${toolLoopCount} iterations`);
635
+ // Update toolCalls for final response
636
+ toolCalls = followUpToolCalls || [];
637
+ break;
638
+ }
639
+ }
640
+ if (toolLoopCount >= MAX_TOOL_LOOPS) {
641
+ logger.warn(`[Agent] Streaming tool loop limit reached (${MAX_TOOL_LOOPS}), stopping`);
642
+ }
643
+ // Extract collected data on final chunk
644
+ if (chunk.done && chunk.structured && nextStep.collect) {
645
+ const collectedData = {};
646
+ // The structured response includes both base fields and collected extraction fields
647
+ const structuredData = chunk.structured;
648
+ for (const field of nextStep.collect) {
649
+ const fieldKey = String(field);
650
+ if (fieldKey in structuredData) {
651
+ collectedData[fieldKey] = structuredData[fieldKey];
652
+ }
653
+ }
654
+ // Merge collected data into session using agent-level data validation
655
+ if (Object.keys(collectedData).length > 0) {
656
+ // Update agent-level collected data with validation
657
+ await this.updateCollectedData(collectedData);
658
+ // Update session with validated data
659
+ session = await this.updateData(session, collectedData);
660
+ logger.debug(`[Agent] Collected data:`, collectedData);
661
+ }
662
+ }
663
+ // Extract any additional data from structured response on final chunk
664
+ if (chunk.done &&
665
+ chunk.structured &&
666
+ typeof chunk.structured === "object" &&
667
+ "contextUpdate" in chunk.structured) {
668
+ await this.updateContext(chunk.structured
669
+ .contextUpdate);
670
+ }
671
+ // Auto-save session step on final chunk
672
+ if (chunk.done &&
673
+ this.persistenceManager &&
674
+ session.id &&
675
+ this.options.persistence?.autoSave !== false) {
676
+ await this.persistenceManager.saveSessionState(session.id, session);
677
+ logger.debug(`[Agent] Auto-saved session step to persistence: ${session.id}`);
678
+ }
679
+ // Execute finalize function on final chunk
680
+ if (chunk.done && session.currentRoute && session.currentStep) {
681
+ const currentRoute = this.routes.find((r) => r.id === session.currentRoute?.id);
682
+ if (currentRoute) {
683
+ const currentStep = currentRoute.getStep(session.currentStep.id);
684
+ if (currentStep?.finalize) {
685
+ logger.debug(`[Agent] Executing finalize for step: ${currentStep.id}`);
686
+ await this.executePrepareFinalize(currentStep.finalize, effectiveContext, session.data, currentRoute, currentStep);
687
+ }
688
+ }
689
+ }
690
+ // Update current session if we have one
691
+ if (chunk.done && this.currentSession) {
692
+ this.currentSession = session;
693
+ }
694
+ yield {
695
+ delta: chunk.delta,
696
+ accumulated: chunk.accumulated,
697
+ done: chunk.done,
698
+ session, // Return updated session
699
+ toolCalls,
700
+ isRouteComplete,
701
+ metadata: chunk.metadata,
702
+ structured: chunk.structured,
703
+ };
704
+ }
705
+ }
706
+ else if (isRouteComplete && selectedRoute) {
707
+ // Route is complete - generate completion message then check for onComplete transition
708
+ const lastUserMessage = getLastMessageFromHistory(history);
709
+ // Get endStep spec from route
710
+ const endStepSpec = selectedRoute.endStepSpec;
711
+ // Create a temporary step for completion message generation using endStep configuration
712
+ const completionStep = new Step(selectedRoute.id, {
713
+ description: endStepSpec.description,
714
+ id: endStepSpec.id || END_ROUTE_ID,
715
+ collect: endStepSpec.collect,
716
+ requires: endStepSpec.requires,
717
+ prompt: endStepSpec.prompt ||
718
+ "Summarize what was accomplished and confirm completion based on the conversation history and collected data",
719
+ });
720
+ // Build response schema for completion
721
+ const responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, completionStep, this.schema);
722
+ const templateContext = {
723
+ context: effectiveContext,
724
+ session,
725
+ history,
726
+ };
727
+ // Build completion response prompt
728
+ const completionPrompt = await this.responseEngine.buildResponsePrompt({
729
+ route: selectedRoute,
730
+ currentStep: completionStep,
731
+ rules: selectedRoute.getRules(),
732
+ prohibitions: selectedRoute.getProhibitions(),
733
+ directives: undefined, // No directives for completion
734
+ history,
735
+ lastMessage: lastUserMessage,
736
+ agentOptions: this.options,
737
+ // Combine agent and route properties according to the specified logic
738
+ combinedGuidelines: [
739
+ ...this.getGuidelines(),
740
+ ...selectedRoute.getGuidelines(),
741
+ ],
742
+ combinedTerms: this.mergeTerms(this.getTerms(), selectedRoute.getTerms()),
743
+ context: effectiveContext,
744
+ session,
745
+ agentSchema: this.schema,
746
+ });
747
+ // Stream completion message using AI provider
748
+ const stream = this.options.provider.generateMessageStream({
749
+ prompt: completionPrompt,
750
+ history,
751
+ context: effectiveContext,
752
+ signal,
753
+ parameters: {
754
+ jsonSchema: responseSchema,
755
+ schemaName: "completion_message_stream",
756
+ },
757
+ });
758
+ logger.debug(`[Agent] Streaming completion message for route: ${selectedRoute.title}`);
759
+ // Check for onComplete transition
760
+ const transitionConfig = await selectedRoute.evaluateOnComplete({ data: session.data }, effectiveContext);
761
+ if (transitionConfig) {
762
+ // Find target route by ID or title
763
+ const targetRoute = this.routes.find((r) => r.id === transitionConfig.nextStep ||
764
+ r.title === transitionConfig.nextStep);
765
+ if (targetRoute) {
766
+ const renderedCondition = await render(transitionConfig.condition, templateContext);
767
+ // Set pending transition in session
768
+ session = {
769
+ ...session,
770
+ pendingTransition: {
771
+ targetRouteId: targetRoute.id,
772
+ condition: renderedCondition,
773
+ reason: "route_complete",
774
+ },
775
+ };
776
+ logger.debug(`[Agent] Route ${selectedRoute.title} completed with pending transition to: ${targetRoute.title}`);
777
+ }
778
+ else {
779
+ logger.warn(`[Agent] Route ${selectedRoute.title} completed but target route not found: ${transitionConfig.nextStep}`);
780
+ }
781
+ }
782
+ // Set step to END_ROUTE marker
783
+ session = enterStep(session, END_ROUTE_ID, "Route completed");
784
+ logger.debug(`[Agent] Route ${selectedRoute.title} completed. Entered END_ROUTE step.`);
785
+ // Stream completion chunks
786
+ for await (const chunk of stream) {
787
+ // Update current session if we have one
788
+ if (chunk.done && this.currentSession) {
789
+ this.currentSession = session;
790
+ }
791
+ yield {
792
+ delta: chunk.delta,
793
+ accumulated: chunk.accumulated,
794
+ done: chunk.done,
795
+ session,
796
+ toolCalls: undefined,
797
+ isRouteComplete: true,
798
+ metadata: chunk.metadata,
799
+ structured: chunk.structured,
800
+ };
801
+ }
802
+ }
803
+ else {
804
+ // Fallback: No routes defined, stream a simple response
805
+ const fallbackPrompt = await this.responseEngine.buildFallbackPrompt({
806
+ history,
807
+ agentOptions: this.options,
808
+ terms: this.terms,
809
+ guidelines: this.guidelines,
810
+ context: effectiveContext,
811
+ session,
812
+ });
813
+ const stream = this.options.provider.generateMessageStream({
814
+ prompt: fallbackPrompt,
815
+ history,
816
+ context: effectiveContext,
817
+ signal,
818
+ parameters: {
819
+ jsonSchema: {
820
+ type: "object",
821
+ properties: {
822
+ message: { type: "string" },
823
+ },
824
+ required: ["message"],
825
+ additionalProperties: false,
826
+ },
827
+ schemaName: "fallback_stream_response",
828
+ },
829
+ });
830
+ for await (const chunk of stream) {
831
+ // Update current session if we have one
832
+ if (chunk.done && this.currentSession) {
833
+ this.currentSession = session;
834
+ }
835
+ yield {
836
+ delta: chunk.delta,
837
+ accumulated: chunk.accumulated,
838
+ done: chunk.done,
839
+ session, // Return updated session
840
+ toolCalls: undefined,
841
+ isRouteComplete: false,
842
+ metadata: chunk.metadata,
843
+ structured: chunk.structured,
844
+ };
845
+ }
846
+ }
847
+ }
848
+ /**
849
+ * Generate a response based on history and context
850
+ */
851
+ async respond(params) {
852
+ const { history: simpleHistory, contextOverride, signal } = params;
853
+ const history = normalizeHistory(simpleHistory);
854
+ // Get current context (may fetch from provider)
855
+ let currentContext = await this.getContext();
856
+ // Call beforeRespond hook if configured
857
+ if (this.options.hooks?.beforeRespond && currentContext !== undefined) {
858
+ currentContext = await this.options.hooks.beforeRespond(currentContext);
859
+ // Update stored context with the result from beforeRespond
860
+ this.context = currentContext;
861
+ }
862
+ // Merge context with override
863
+ const effectiveContext = {
864
+ ...currentContext,
865
+ ...contextOverride,
866
+ };
867
+ // Initialize or get session (use current session if available)
868
+ let session = cloneDeep(params.session) ||
869
+ cloneDeep(this.currentSession) ||
870
+ (await this.session.getOrCreate());
871
+ // Merge agent's collected data into session (agent data takes precedence)
872
+ if (Object.keys(this.collectedData).length > 0) {
873
+ session = mergeCollected(session, this.collectedData);
874
+ logger.debug("[Agent] Merged agent collected data into session:", this.collectedData);
875
+ }
876
+ // PHASE 1: PREPARE - Execute prepare function if current step has one
877
+ if (session.currentRoute && session.currentStep) {
878
+ const currentRoute = this.routes.find((r) => r.id === session.currentRoute?.id);
879
+ if (currentRoute) {
880
+ const currentStep = currentRoute.getStep(session.currentStep.id);
881
+ if (currentStep?.prepare) {
882
+ logger.debug(`[Agent] Executing prepare for step: ${currentStep.id}`);
883
+ await this.executePrepareFinalize(currentStep.prepare, effectiveContext, session.data, currentRoute, currentStep);
884
+ }
885
+ }
886
+ }
887
+ // PHASE 2: ROUTING + STEP SELECTION - Determine which route and step to use (combined)
888
+ let selectedRoute;
889
+ let responseDirectives;
890
+ let selectedStep;
891
+ let isRouteComplete = false;
892
+ // Check for pending transition from previous route completion
893
+ if (session.pendingTransition) {
894
+ const targetRoute = this.routes.find((r) => r.id === session.pendingTransition?.targetRouteId);
895
+ if (targetRoute) {
896
+ logger.debug(`[Agent] Auto-transitioning from pending transition to route: ${targetRoute.title}`);
897
+ // Clear pending transition and enter new route
898
+ session = {
899
+ ...session,
900
+ pendingTransition: undefined,
901
+ };
902
+ session = enterRoute(session, targetRoute.id, targetRoute.title);
903
+ // Merge initial data if available
904
+ if (targetRoute.initialData) {
905
+ session = mergeCollected(session, targetRoute.initialData);
906
+ }
907
+ selectedRoute = targetRoute;
908
+ }
909
+ else {
910
+ logger.warn(`[Agent] Pending transition target route not found: ${session.pendingTransition.targetRouteId}`);
911
+ // Clear invalid transition
912
+ session = {
913
+ ...session,
914
+ pendingTransition: undefined,
915
+ };
916
+ }
917
+ }
918
+ // If no pending transition or transition handled, do normal routing
919
+ if (this.routes.length > 0 && !selectedRoute) {
920
+ const orchestration = await this.routingEngine.decideRouteAndStep({
921
+ routes: this.routes,
922
+ session,
923
+ history,
924
+ agentOptions: this.options,
925
+ provider: this.options.provider,
926
+ context: effectiveContext,
927
+ signal,
928
+ });
929
+ selectedRoute = orchestration.selectedRoute;
930
+ selectedStep = orchestration.selectedStep;
931
+ responseDirectives = orchestration.responseDirectives;
932
+ session = orchestration.session;
933
+ isRouteComplete = orchestration.isRouteComplete || false;
934
+ // Log if route is complete
935
+ if (isRouteComplete) {
936
+ logger.debug(`[Agent] Route complete: all required data collected, END_ROUTE reached`);
937
+ }
938
+ }
939
+ // PHASE 3: DETERMINE NEXT STEP - Use step from combined decision or get initial step
940
+ let message;
941
+ let toolCalls = undefined;
942
+ let responsePrompt;
943
+ let availableTools = [];
944
+ let responseSchema;
945
+ let nextStep;
946
+ // Get last user message (needed for both route and completion handling)
947
+ const lastUserMessage = getLastMessageFromHistory(history);
948
+ if (selectedRoute && !isRouteComplete) {
949
+ // If we have a selected step from the combined routing decision, use it
950
+ if (selectedStep) {
951
+ nextStep = selectedStep;
952
+ }
953
+ else {
954
+ // New route or no step selected - get initial step or first valid step
955
+ const candidates = this.routingEngine.getCandidateSteps(selectedRoute, undefined, session.data || {});
956
+ if (candidates.length > 0) {
957
+ nextStep = candidates[0].step;
958
+ logger.debug(`[Agent] Using first valid step: ${nextStep.id} for new route`);
959
+ }
960
+ else {
961
+ // Fallback to initial step even if it should be skipped
962
+ nextStep = selectedRoute.initialStep;
963
+ logger.warn(`[Agent] No valid steps found, using initial step: ${nextStep.id}`);
964
+ }
965
+ }
966
+ // Update session with next step
967
+ session = enterStep(session, nextStep.id, nextStep.description);
968
+ logger.debug(`[Agent] Entered step: ${nextStep.id}`);
969
+ // PHASE 4: RESPONSE GENERATION - Generate message using selected route and step
970
+ // Get last user message
971
+ const lastUserMessage = getLastMessageFromHistory(history);
972
+ // Build response schema for this route (with collect fields from step)
973
+ responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, nextStep, this.schema);
974
+ // Build response prompt
975
+ responsePrompt = await this.responseEngine.buildResponsePrompt({
976
+ route: selectedRoute,
977
+ currentStep: nextStep,
978
+ rules: selectedRoute.getRules(),
979
+ prohibitions: selectedRoute.getProhibitions(),
980
+ directives: responseDirectives,
981
+ history,
982
+ lastMessage: lastUserMessage,
983
+ agentOptions: this.options,
984
+ // Combine agent and route properties according to the specified logic
985
+ combinedGuidelines: [
986
+ ...this.getGuidelines(),
987
+ ...selectedRoute.getGuidelines(),
988
+ ],
989
+ combinedTerms: this.mergeTerms(this.getTerms(), selectedRoute.getTerms()),
990
+ context: effectiveContext,
991
+ session,
992
+ agentSchema: this.schema,
993
+ });
994
+ // Collect available tools for AI
995
+ availableTools = this.collectAvailableTools(selectedRoute, nextStep);
996
+ }
997
+ else {
998
+ // No route selected - generate basic response without route context
999
+ logger.debug(`[Agent] No route selected, generating basic response`);
1000
+ // Build basic response prompt without route context
1001
+ responsePrompt = await this.responseEngine.buildFallbackPrompt({
1002
+ history,
1003
+ agentOptions: this.options,
1004
+ terms: this.getTerms(),
1005
+ guidelines: this.getGuidelines(),
1006
+ context: effectiveContext,
1007
+ session,
1008
+ });
1009
+ // Use agent-level tools only
1010
+ availableTools = this.collectAvailableTools();
1011
+ responseSchema = undefined;
1012
+ }
1013
+ // Generate message using AI provider (common for both route and no-route cases)
1014
+ const result = await this.options.provider.generateMessage({
1015
+ prompt: responsePrompt,
1016
+ history,
1017
+ context: effectiveContext,
1018
+ tools: availableTools,
1019
+ signal,
1020
+ parameters: responseSchema
1021
+ ? {
1022
+ jsonSchema: responseSchema,
1023
+ schemaName: "response_output",
1024
+ }
1025
+ : undefined,
1026
+ });
1027
+ message = result.structured?.message || result.message;
1028
+ // Process dynamic tool calls from AI response (common for both route and no-route cases)
1029
+ if (result.structured?.toolCalls) {
1030
+ toolCalls = result.structured.toolCalls;
1031
+ // Execute dynamic tool calls
1032
+ if (toolCalls.length > 0) {
1033
+ logger.debug(`[Agent] Executing ${toolCalls.length} dynamic tool calls`);
1034
+ for (const toolCall of toolCalls) {
1035
+ const tool = this.findAvailableTool(toolCall.toolName, selectedRoute);
1036
+ if (!tool) {
1037
+ logger.warn(`[Agent] Tool not found: ${toolCall.toolName}`);
1038
+ continue;
1039
+ }
1040
+ const toolExecutor = new ToolExecutor();
1041
+ const toolResult = await toolExecutor.executeTool({
1042
+ tool: tool,
1043
+ context: effectiveContext,
1044
+ updateContext: this.updateContext.bind(this),
1045
+ updateData: this.updateCollectedData.bind(this),
1046
+ history,
1047
+ data: session.data,
1048
+ toolArguments: toolCall.arguments,
1049
+ });
1050
+ // Update context with tool results
1051
+ if (toolResult.contextUpdate) {
1052
+ await this.updateContext(toolResult.contextUpdate);
1053
+ }
1054
+ // Update collected data with tool results
1055
+ if (toolResult.dataUpdate) {
1056
+ session = await this.updateData(session, toolResult.dataUpdate);
1057
+ logger.debug(`[Agent] Tool updated collected data:`, toolResult.dataUpdate);
1058
+ }
1059
+ logger.debug(`[Agent] Executed dynamic tool: ${toolResult.toolName} (success: ${toolResult.success})`);
1060
+ }
1061
+ }
1062
+ }
1063
+ // TOOL LOOP: Allow AI to make follow-up tool calls after initial tool execution
1064
+ const MAX_TOOL_LOOPS = 5;
1065
+ let toolLoopCount = 0;
1066
+ let hasToolCalls = toolCalls && toolCalls.length > 0;
1067
+ while (hasToolCalls && toolLoopCount < MAX_TOOL_LOOPS) {
1068
+ toolLoopCount++;
1069
+ logger.debug(`[Agent] Starting tool loop ${toolLoopCount}/${MAX_TOOL_LOOPS}`);
1070
+ // Add tool execution results to history so AI knows what happened
1071
+ const toolResultsEvents = [];
1072
+ for (const toolCall of toolCalls || []) {
1073
+ const tool = this.findAvailableTool(toolCall.toolName, selectedRoute);
1074
+ if (tool) {
1075
+ toolResultsEvents.push({
1076
+ kind: EventKind.TOOL,
1077
+ source: MessageRole.AGENT,
1078
+ timestamp: new Date().toISOString(),
1079
+ data: {
1080
+ tool_calls: [
1081
+ {
1082
+ tool_id: toolCall.toolName,
1083
+ arguments: toolCall.arguments,
1084
+ result: {
1085
+ data: "Tool executed successfully",
1086
+ },
1087
+ },
1088
+ ],
1089
+ },
1090
+ });
1091
+ }
1092
+ }
1093
+ // Create updated history with tool results
1094
+ const updatedHistory = [...history, ...toolResultsEvents];
1095
+ // Make follow-up AI call to see if more tools are needed
1096
+ const followUpResult = await this.options.provider.generateMessage({
1097
+ prompt: responsePrompt,
1098
+ history: updatedHistory,
1099
+ context: effectiveContext,
1100
+ tools: availableTools,
1101
+ parameters: {
1102
+ jsonSchema: responseSchema,
1103
+ schemaName: "tool_followup",
1104
+ },
1105
+ signal,
1106
+ });
1107
+ // Check if follow-up call has more tool calls
1108
+ const followUpToolCalls = followUpResult.structured?.toolCalls;
1109
+ hasToolCalls = followUpToolCalls && followUpToolCalls.length > 0;
1110
+ if (hasToolCalls) {
1111
+ logger.debug(`[Agent] Follow-up call produced ${followUpToolCalls.length} additional tool calls`);
1112
+ // Execute the follow-up tool calls
1113
+ for (const toolCall of followUpToolCalls) {
1114
+ const tool = this.findAvailableTool(toolCall.toolName, selectedRoute);
1115
+ if (!tool) {
1116
+ logger.warn(`[Agent] Tool not found in follow-up: ${toolCall.toolName}`);
1117
+ continue;
1118
+ }
1119
+ const toolExecutor = new ToolExecutor();
1120
+ const toolResult = await toolExecutor.executeTool({
1121
+ tool: tool,
1122
+ context: effectiveContext,
1123
+ updateContext: this.updateContext.bind(this),
1124
+ updateData: this.updateCollectedData.bind(this),
1125
+ history: updatedHistory,
1126
+ data: session.data,
1127
+ toolArguments: toolCall.arguments,
1128
+ });
1129
+ // Update context with follow-up tool results
1130
+ if (toolResult.contextUpdate) {
1131
+ await this.updateContext(toolResult.contextUpdate);
1132
+ }
1133
+ if (toolResult.dataUpdate) {
1134
+ session = await this.updateData(session, toolResult.dataUpdate);
1135
+ logger.debug(`[Agent] Follow-up tool updated collected data:`, toolResult.dataUpdate);
1136
+ }
1137
+ logger.debug(`[Agent] Executed follow-up tool: ${toolResult.toolName} (success: ${toolResult.success})`);
1138
+ }
1139
+ // Update toolCalls for next iteration or final response
1140
+ toolCalls = followUpToolCalls;
1141
+ }
1142
+ else {
1143
+ logger.debug(`[Agent] Tool loop completed after ${toolLoopCount} iterations`);
1144
+ // Update final message and toolCalls from follow-up result if no more tools
1145
+ message = followUpResult.structured?.message || followUpResult.message;
1146
+ toolCalls = followUpToolCalls || [];
1147
+ break;
1148
+ }
1149
+ }
1150
+ if (toolLoopCount >= MAX_TOOL_LOOPS) {
1151
+ logger.warn(`[Agent] Tool loop limit reached (${MAX_TOOL_LOOPS}), stopping`);
1152
+ }
1153
+ // Extract collected data from final response (only for route-based interactions)
1154
+ if (selectedRoute && result.structured && nextStep?.collect) {
1155
+ const collectedData = {};
1156
+ // The structured response includes both base fields and collected extraction fields
1157
+ const structuredData = result.structured;
1158
+ for (const field of nextStep.collect) {
1159
+ const fieldKey = String(field);
1160
+ if (fieldKey in structuredData) {
1161
+ collectedData[fieldKey] = structuredData[fieldKey];
1162
+ }
1163
+ }
1164
+ // Merge collected data into session using agent-level data validation
1165
+ if (Object.keys(collectedData).length > 0) {
1166
+ // Update agent-level collected data with validation
1167
+ await this.updateCollectedData(collectedData);
1168
+ // Update session with validated data
1169
+ session = await this.updateData(session, collectedData);
1170
+ logger.debug(`[Agent] Collected data:`, collectedData);
1171
+ }
1172
+ }
1173
+ // Extract any additional data from structured response
1174
+ if (result.structured &&
1175
+ typeof result.structured === "object" &&
1176
+ "contextUpdate" in result.structured) {
1177
+ await this.updateContext(result.structured
1178
+ .contextUpdate);
1179
+ }
1180
+ // Handle route completion if route is complete
1181
+ if (isRouteComplete) {
1182
+ // Route is complete - generate completion message then check for onComplete transition
1183
+ // Get endStep spec from route
1184
+ const endStepSpec = selectedRoute.endStepSpec;
1185
+ // Create a temporary step for completion message generation using endStep configuration
1186
+ const completionStep = new Step(selectedRoute.id, {
1187
+ description: endStepSpec.description,
1188
+ id: endStepSpec.id || END_ROUTE_ID,
1189
+ collect: endStepSpec.collect,
1190
+ requires: endStepSpec.requires,
1191
+ prompt: endStepSpec.prompt ||
1192
+ "Summarize what was accomplished and confirm completion based on the conversation history and collected data",
1193
+ });
1194
+ if (!selectedRoute) {
1195
+ throw new Error("Selected route is not defined");
1196
+ }
1197
+ // Build response schema for completion
1198
+ const responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, completionStep, this.schema);
1199
+ const templateContext = {
1200
+ context: effectiveContext,
1201
+ session,
1202
+ history,
1203
+ };
1204
+ // Build completion response prompt
1205
+ const completionPrompt = await this.responseEngine.buildResponsePrompt({
1206
+ route: selectedRoute,
1207
+ currentStep: completionStep,
1208
+ rules: selectedRoute.getRules(),
1209
+ prohibitions: selectedRoute.getProhibitions(),
1210
+ directives: undefined, // No directives for completion
1211
+ history,
1212
+ lastMessage: lastUserMessage,
1213
+ agentOptions: this.options,
1214
+ // Combine agent and route properties according to the specified logic
1215
+ combinedGuidelines: [
1216
+ ...this.getGuidelines(),
1217
+ ...selectedRoute.getGuidelines(),
1218
+ ],
1219
+ combinedTerms: this.mergeTerms(this.getTerms(), selectedRoute.getTerms()),
1220
+ context: effectiveContext,
1221
+ session,
1222
+ agentSchema: this.schema,
1223
+ });
1224
+ // Generate completion message using AI provider
1225
+ const completionResult = await this.options.provider.generateMessage({
1226
+ prompt: completionPrompt,
1227
+ history,
1228
+ context: effectiveContext,
1229
+ signal,
1230
+ parameters: {
1231
+ jsonSchema: responseSchema,
1232
+ schemaName: "completion_message",
1233
+ },
1234
+ });
1235
+ message =
1236
+ completionResult.structured?.message || completionResult.message;
1237
+ logger.debug(`[Agent] Generated completion message for route: ${selectedRoute.title}`);
1238
+ // Check for onComplete transition
1239
+ const transitionConfig = await selectedRoute.evaluateOnComplete({ data: session.data }, effectiveContext);
1240
+ if (transitionConfig) {
1241
+ // Find target route by ID or title
1242
+ const targetRoute = this.routes.find((r) => r.id === transitionConfig.nextStep ||
1243
+ r.title === transitionConfig.nextStep);
1244
+ if (targetRoute) {
1245
+ const renderedCondition = await render(transitionConfig.condition, templateContext);
1246
+ // Set pending transition in session
1247
+ session = {
1248
+ ...session,
1249
+ pendingTransition: {
1250
+ targetRouteId: targetRoute.id,
1251
+ condition: renderedCondition,
1252
+ reason: "route_complete",
1253
+ },
1254
+ };
1255
+ logger.debug(`[Agent] Route ${selectedRoute.title} completed with pending transition to: ${targetRoute.title}`);
1256
+ }
1257
+ else {
1258
+ logger.warn(`[Agent] Route ${selectedRoute.title} completed but target route not found: ${transitionConfig.nextStep}`);
1259
+ }
1260
+ }
1261
+ // Set step to END_ROUTE marker
1262
+ session = enterStep(session, END_ROUTE_ID, "Route completed");
1263
+ logger.debug(`[Agent] Route ${selectedRoute.title} completed. Entered END_ROUTE step.`);
1264
+ }
1265
+ else {
1266
+ // Fallback: No routes defined, generate a simple response
1267
+ const fallbackPrompt = await this.responseEngine.buildFallbackPrompt({
1268
+ history,
1269
+ agentOptions: this.options,
1270
+ terms: this.terms,
1271
+ guidelines: this.guidelines,
1272
+ context: effectiveContext,
1273
+ session,
1274
+ });
1275
+ const result = await this.options.provider.generateMessage({
1276
+ prompt: fallbackPrompt,
1277
+ history,
1278
+ context: effectiveContext,
1279
+ signal,
1280
+ parameters: {
1281
+ jsonSchema: {
1282
+ type: "object",
1283
+ properties: {
1284
+ message: { type: "string" },
1285
+ },
1286
+ required: ["message"],
1287
+ additionalProperties: false,
1288
+ },
1289
+ schemaName: "fallback_response",
1290
+ },
1291
+ });
1292
+ message = result.structured?.message || result.message;
1293
+ }
1294
+ // Auto-save session step to persistence if configured
1295
+ if (this.persistenceManager &&
1296
+ session.id &&
1297
+ this.options.persistence?.autoSave !== false) {
1298
+ await this.persistenceManager.saveSessionState(session.id, session);
1299
+ logger.debug(`[Agent] Auto-saved session step to persistence: ${session.id}`);
1300
+ }
1301
+ // Execute finalize function
1302
+ if (session.currentRoute && session.currentStep) {
1303
+ const currentRoute = this.routes.find((r) => r.id === session.currentRoute?.id);
1304
+ if (currentRoute) {
1305
+ const currentStep = currentRoute.getStep(session.currentStep.id);
1306
+ if (currentStep?.finalize) {
1307
+ logger.debug(`[Agent] Executing finalize for step: ${currentStep.id}`);
1308
+ await this.executePrepareFinalize(currentStep.finalize, effectiveContext, session.data, currentRoute, currentStep);
1309
+ }
1310
+ }
1311
+ }
1312
+ // Update current session if we have one
1313
+ if (this.currentSession) {
1314
+ this.currentSession = session;
1315
+ }
1316
+ return {
1317
+ message,
1318
+ session, // Return updated session with route/step info
1319
+ toolCalls,
1320
+ isRouteComplete, // Indicates if the route has reached END_ROUTE with all data collected
1321
+ };
1322
+ }
1323
+ /**
1324
+ * Get all routes
1325
+ */
1326
+ getRoutes() {
1327
+ return [...this.routes];
1328
+ }
1329
+ /**
1330
+ * Get all terms
1331
+ */
1332
+ getTerms() {
1333
+ return [...this.terms];
1334
+ }
1335
+ /**
1336
+ * Get all tools
1337
+ */
1338
+ getTools() {
1339
+ return [...this.tools];
1340
+ }
1341
+ /**
1342
+ * Find an available tool by name for the given route
1343
+ * Route-level tools take precedence over agent-level tools
1344
+ * @private
1345
+ */
1346
+ findAvailableTool(toolName, route) {
1347
+ // Check route-level tools first (if route provided)
1348
+ if (route) {
1349
+ const routeTool = route
1350
+ .getTools()
1351
+ .find((tool) => tool.id === toolName || tool.name === toolName);
1352
+ if (routeTool)
1353
+ return routeTool;
1354
+ }
1355
+ // Fall back to agent-level tools
1356
+ return this.tools.find((tool) => tool.id === toolName || tool.name === toolName);
1357
+ }
1358
+ /**
1359
+ * Collect all available tools for the given route and step context
1360
+ * @private
1361
+ */
1362
+ collectAvailableTools(route, step) {
1363
+ const availableTools = new Map();
1364
+ // Add agent-level tools
1365
+ this.tools.forEach((tool) => {
1366
+ availableTools.set(tool.id, tool);
1367
+ });
1368
+ // Add route-level tools (these take precedence)
1369
+ if (route) {
1370
+ route.getTools().forEach((tool) => {
1371
+ availableTools.set(tool.id, tool);
1372
+ });
1373
+ }
1374
+ // Filter by step-level allowed tools if specified
1375
+ if (step?.tools) {
1376
+ const allowedToolIds = new Set();
1377
+ const stepTools = [];
1378
+ for (const toolRef of step.tools) {
1379
+ if (typeof toolRef === "string") {
1380
+ // Reference to registered tool
1381
+ allowedToolIds.add(toolRef);
1382
+ }
1383
+ else {
1384
+ // Inline tool definition
1385
+ if (toolRef.id) {
1386
+ allowedToolIds.add(toolRef.id);
1387
+ stepTools.push(toolRef);
1388
+ }
1389
+ }
1390
+ }
1391
+ // If step specifies tools, only include those
1392
+ if (allowedToolIds.size > 0) {
1393
+ const filteredTools = new Map();
1394
+ for (const toolId of allowedToolIds) {
1395
+ const tool = availableTools.get(toolId);
1396
+ if (tool) {
1397
+ filteredTools.set(toolId, tool);
1398
+ }
1399
+ }
1400
+ // Add inline tools
1401
+ stepTools.forEach((tool) => {
1402
+ if (tool.id) {
1403
+ filteredTools.set(tool.id, tool);
1404
+ }
1405
+ });
1406
+ availableTools.clear();
1407
+ filteredTools.forEach((tool, id) => availableTools.set(id, tool));
1408
+ }
1409
+ }
1410
+ // Convert to the format expected by AI providers
1411
+ return Array.from(availableTools.values()).map((tool) => ({
1412
+ id: tool.id,
1413
+ name: tool.name || tool.id,
1414
+ description: tool.description,
1415
+ parameters: tool.parameters,
1416
+ }));
1417
+ }
1418
+ /**
1419
+ * Execute a prepare or finalize function/tool
1420
+ * @private
1421
+ */
1422
+ async executePrepareFinalize(prepareOrFinalize, context, data, route, step) {
1423
+ if (!prepareOrFinalize)
1424
+ return;
1425
+ if (typeof prepareOrFinalize === "function") {
1426
+ // It's a function - call it directly
1427
+ await prepareOrFinalize(context, data);
1428
+ }
1429
+ else {
1430
+ // It's a tool reference - find and execute the tool
1431
+ let tool;
1432
+ if (typeof prepareOrFinalize === "string") {
1433
+ // Tool ID - find it in available tools
1434
+ const availableTools = new Map();
1435
+ // Add agent-level tools
1436
+ this.tools.forEach((t) => {
1437
+ availableTools.set(t.id, t);
1438
+ });
1439
+ // Add route-level tools
1440
+ if (route) {
1441
+ route.getTools().forEach((t) => {
1442
+ availableTools.set(t.id, t);
1443
+ });
1444
+ }
1445
+ // Add step-level tools
1446
+ if (step?.tools) {
1447
+ for (const toolRef of step.tools) {
1448
+ if (typeof toolRef === "string") {
1449
+ // Keep as is
1450
+ }
1451
+ else if (toolRef.id) {
1452
+ availableTools.set(toolRef.id, toolRef);
1453
+ }
1454
+ }
1455
+ }
1456
+ tool = availableTools.get(prepareOrFinalize);
1457
+ }
1458
+ else {
1459
+ // Tool object - use directly
1460
+ tool = prepareOrFinalize;
1461
+ }
1462
+ if (tool) {
1463
+ const toolExecutor = new ToolExecutor();
1464
+ const result = await toolExecutor.executeTool({
1465
+ tool,
1466
+ context,
1467
+ updateContext: this.updateContext.bind(this),
1468
+ updateData: this.updateCollectedData.bind(this),
1469
+ history: [], // Empty history for prepare/finalize
1470
+ data,
1471
+ });
1472
+ if (!result.success) {
1473
+ logger.error(`[Agent] Tool execution failed in prepare/finalize: ${result.error}`);
1474
+ throw new Error(`Tool execution failed: ${result.error}`);
1475
+ }
1476
+ }
1477
+ else {
1478
+ logger.warn(`[Agent] Tool not found for prepare/finalize: ${typeof prepareOrFinalize === "string"
1479
+ ? prepareOrFinalize
1480
+ : "inline tool"}`);
1481
+ }
1482
+ }
1483
+ }
1484
+ /**
1485
+ * Get all guidelines
1486
+ */
1487
+ getGuidelines() {
1488
+ return [...this.guidelines];
1489
+ }
1490
+ /**
1491
+ * Get the agent's knowledge base
1492
+ */
1493
+ getKnowledgeBase() {
1494
+ return { ...this.knowledgeBase };
1495
+ }
1496
+ /**
1497
+ * Merge terms with route-specific taking precedence on conflicts
1498
+ * @private
1499
+ */
1500
+ mergeTerms(agentTerms, routeTerms) {
1501
+ const merged = new Map();
1502
+ // Add agent terms first
1503
+ agentTerms.forEach((term) => {
1504
+ const name = typeof term.name === "string" ? term.name : term.name.toString();
1505
+ merged.set(name, term);
1506
+ });
1507
+ // Add route terms (these take precedence)
1508
+ routeTerms.forEach((term) => {
1509
+ const name = typeof term.name === "string" ? term.name : term.name.toString();
1510
+ merged.set(name, term);
1511
+ });
1512
+ return Array.from(merged.values());
1513
+ }
1514
+ /**
1515
+ * Get the persistence manager (if configured)
1516
+ */
1517
+ getPersistenceManager() {
1518
+ return this.persistenceManager;
1519
+ }
1520
+ /**
1521
+ * Check if persistence is enabled
1522
+ */
1523
+ hasPersistence() {
1524
+ return this.persistenceManager !== undefined;
1525
+ }
1526
+ /**
1527
+ * Set the current session for convenience methods
1528
+ * @param session - Session step to use for subsequent calls
1529
+ */
1530
+ setCurrentSession(session) {
1531
+ this.currentSession = session;
1532
+ }
1533
+ /**
1534
+ * Get the current session (if set)
1535
+ */
1536
+ getCurrentSession() {
1537
+ return this.currentSession;
1538
+ }
1539
+ /**
1540
+ * Clear the current session
1541
+ */
1542
+ clearCurrentSession() {
1543
+ this.currentSession = undefined;
1544
+ }
1545
+ /**
1546
+ * Get collected data from current session or agent-level collected data
1547
+ * @param routeId - Optional route ID to get data for (uses current route if not provided)
1548
+ * @returns The collected data from the current session or agent-level data
1549
+ */
1550
+ getData() {
1551
+ // If we have a current session, use session data
1552
+ if (this.currentSession) {
1553
+ // With agent-level data, all routes share the same data structure
1554
+ // No need for route-specific data access
1555
+ return (this.currentSession.data) || {};
1556
+ }
1557
+ // Otherwise, return agent-level collected data
1558
+ return this.getCollectedData();
1559
+ }
1560
+ /**
1561
+ * Manually transition to a different route
1562
+ * Sets a pending transition that will be executed on the next respond() call
1563
+ *
1564
+ * @param routeIdOrTitle - Route ID or title to transition to
1565
+ * @param session - Session step to update (uses current session if not provided)
1566
+ * @param condition - Optional AI-evaluated condition for the transition
1567
+ * @returns Updated session with pending transition
1568
+ *
1569
+ * @example
1570
+ * // After route completes
1571
+ * if (response.isRouteComplete && response.session) {
1572
+ * const updatedSession = agent.nextStepRoute("feedback-collection", response.session);
1573
+ * // Next respond() call will automatically transition to feedback route
1574
+ * const nextResponse = await agent.respond({ history, session: updatedSession });
1575
+ * }
1576
+ */
1577
+ async nextStepRoute(routeIdOrTitle, session, condition, history) {
1578
+ const targetSession = session || this.currentSession;
1579
+ if (!targetSession) {
1580
+ throw new Error("No session provided and no current session available. Please provide a session to transition.");
1581
+ }
1582
+ // Find target route by ID or title
1583
+ const targetRoute = this.routes.find((r) => r.id === routeIdOrTitle || r.title === routeIdOrTitle);
1584
+ if (!targetRoute) {
1585
+ throw new Error(`Route not found: ${routeIdOrTitle}. Available routes: ${this.routes
1586
+ .map((r) => r.title)
1587
+ .join(", ")}`);
1588
+ }
1589
+ const templateContext = {
1590
+ context: this.context,
1591
+ session,
1592
+ history,
1593
+ data: this.currentSession?.data,
1594
+ };
1595
+ const renderedCondition = await render(condition, templateContext);
1596
+ const updatedSession = {
1597
+ ...targetSession,
1598
+ pendingTransition: {
1599
+ targetRouteId: targetRoute.id,
1600
+ condition: renderedCondition,
1601
+ reason: "route_complete",
1602
+ },
1603
+ };
1604
+ // Update current session if using it
1605
+ if (!session && this.currentSession) {
1606
+ this.currentSession = updatedSession;
1607
+ }
1608
+ logger.debug(`[Agent] Set pending transition to route: ${targetRoute.title}`);
1609
+ return updatedSession;
1610
+ }
1611
+ /**
1612
+ * Simplified respond method using SessionManager
1613
+ * Automatically manages conversation history through the session
1614
+ */
1615
+ async chat(message, options) {
1616
+ // Determine which history to use
1617
+ let history;
1618
+ if (options?.history) {
1619
+ // Use provided history for this response only
1620
+ history = options.history;
1621
+ }
1622
+ else {
1623
+ // Add user message to session history if provided
1624
+ if (message) {
1625
+ await this.session.addMessage("user", message);
1626
+ }
1627
+ history = this.session.getHistory();
1628
+ }
1629
+ // Get or create session
1630
+ let session = await this.session.getOrCreate();
1631
+ // Merge agent's collected data into session (agent data takes precedence)
1632
+ if (Object.keys(this.collectedData).length > 0) {
1633
+ session = mergeCollected(session, this.collectedData);
1634
+ // Update the session manager with the merged data
1635
+ await this.session.setData(this.collectedData);
1636
+ logger.debug("[Agent] Merged agent collected data into chat session:", this.collectedData);
1637
+ }
1638
+ // Use existing respond method with session-managed history
1639
+ const result = await this.respond({
1640
+ history,
1641
+ session,
1642
+ contextOverride: options?.contextOverride,
1643
+ signal: options?.signal,
1644
+ });
1645
+ // Add agent response to session history (only if not using override history)
1646
+ if (!options?.history) {
1647
+ await this.session.addMessage("assistant", result.message);
1648
+ }
1649
+ // Ensure the result includes the current session
1650
+ return {
1651
+ ...result,
1652
+ session: result.session || this.session.current,
1653
+ };
1654
+ }
1655
+ }
1656
+ //# sourceMappingURL=Agent.js.map