@falai/agent 0.9.2 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (626) hide show
  1. package/README.md +262 -38
  2. package/dist/adapters/MemoryAdapter.d.ts.map +1 -0
  3. package/dist/adapters/MemoryAdapter.js.map +1 -0
  4. package/dist/adapters/MongoAdapter.d.ts.map +1 -0
  5. package/dist/adapters/MongoAdapter.js.map +1 -0
  6. package/dist/adapters/OpenSearchAdapter.d.ts.map +1 -0
  7. package/dist/adapters/OpenSearchAdapter.js.map +1 -0
  8. package/dist/adapters/PostgreSQLAdapter.d.ts.map +1 -0
  9. package/dist/adapters/PostgreSQLAdapter.js.map +1 -0
  10. package/dist/adapters/PrismaAdapter.d.ts.map +1 -0
  11. package/dist/{src/adapters → adapters}/PrismaAdapter.js +3 -2
  12. package/dist/adapters/PrismaAdapter.js.map +1 -0
  13. package/dist/adapters/RedisAdapter.d.ts.map +1 -0
  14. package/dist/{src/adapters → adapters}/RedisAdapter.js +3 -3
  15. package/dist/adapters/RedisAdapter.js.map +1 -0
  16. package/dist/adapters/SQLiteAdapter.d.ts.map +1 -0
  17. package/dist/adapters/SQLiteAdapter.js.map +1 -0
  18. package/dist/adapters/index.d.ts.map +1 -0
  19. package/dist/adapters/index.js.map +1 -0
  20. package/dist/cjs/adapters/MemoryAdapter.js.map +1 -0
  21. package/dist/cjs/adapters/MongoAdapter.js.map +1 -0
  22. package/dist/cjs/adapters/OpenSearchAdapter.js.map +1 -0
  23. package/dist/cjs/adapters/PostgreSQLAdapter.js.map +1 -0
  24. package/dist/{src → cjs}/adapters/PrismaAdapter.d.ts.map +1 -1
  25. package/dist/cjs/{src/adapters → adapters}/PrismaAdapter.js +3 -2
  26. package/dist/cjs/adapters/PrismaAdapter.js.map +1 -0
  27. package/dist/cjs/{src/adapters → adapters}/RedisAdapter.js +2 -2
  28. package/dist/cjs/adapters/RedisAdapter.js.map +1 -0
  29. package/dist/cjs/adapters/SQLiteAdapter.js.map +1 -0
  30. package/dist/cjs/adapters/index.js.map +1 -0
  31. package/dist/cjs/constants/index.js.map +1 -0
  32. package/dist/cjs/{src/core → core}/Agent.d.ts +6 -1
  33. package/dist/cjs/core/Agent.d.ts.map +1 -0
  34. package/dist/cjs/{src/core → core}/Agent.js +42 -2
  35. package/dist/cjs/core/Agent.js.map +1 -0
  36. package/dist/cjs/core/BatchExecutor.d.ts +353 -0
  37. package/dist/cjs/core/BatchExecutor.d.ts.map +1 -0
  38. package/dist/cjs/core/BatchExecutor.js +842 -0
  39. package/dist/cjs/core/BatchExecutor.js.map +1 -0
  40. package/dist/cjs/core/BatchPromptBuilder.d.ts +86 -0
  41. package/dist/cjs/core/BatchPromptBuilder.d.ts.map +1 -0
  42. package/dist/cjs/core/BatchPromptBuilder.js +201 -0
  43. package/dist/cjs/core/BatchPromptBuilder.js.map +1 -0
  44. package/dist/cjs/core/Events.js.map +1 -0
  45. package/dist/cjs/core/PersistenceManager.js.map +1 -0
  46. package/dist/{src → cjs}/core/PromptComposer.d.ts +1 -1
  47. package/dist/cjs/core/PromptComposer.d.ts.map +1 -0
  48. package/dist/cjs/{src/core → core}/PromptComposer.js +44 -7
  49. package/dist/cjs/core/PromptComposer.js.map +1 -0
  50. package/dist/{src → cjs}/core/ResponseEngine.d.ts.map +1 -1
  51. package/dist/cjs/core/ResponseEngine.js +202 -0
  52. package/dist/cjs/core/ResponseEngine.js.map +1 -0
  53. package/dist/{src → cjs}/core/ResponseModal.d.ts +45 -0
  54. package/dist/cjs/core/ResponseModal.d.ts.map +1 -0
  55. package/dist/cjs/{src/core → core}/ResponseModal.js +686 -66
  56. package/dist/cjs/core/ResponseModal.js.map +1 -0
  57. package/dist/{src → cjs}/core/ResponsePipeline.d.ts +2 -2
  58. package/dist/cjs/core/ResponsePipeline.d.ts.map +1 -0
  59. package/dist/cjs/{src/core → core}/ResponsePipeline.js +13 -6
  60. package/dist/cjs/core/ResponsePipeline.js.map +1 -0
  61. package/dist/{src → cjs}/core/Route.d.ts +34 -5
  62. package/dist/cjs/core/Route.d.ts.map +1 -0
  63. package/dist/cjs/{src/core → core}/Route.js +196 -19
  64. package/dist/cjs/core/Route.js.map +1 -0
  65. package/dist/cjs/{src/core → core}/RoutingEngine.d.ts +30 -5
  66. package/dist/cjs/core/RoutingEngine.d.ts.map +1 -0
  67. package/dist/cjs/{src/core → core}/RoutingEngine.js +330 -80
  68. package/dist/cjs/core/RoutingEngine.js.map +1 -0
  69. package/dist/cjs/core/SessionManager.js.map +1 -0
  70. package/dist/{src → cjs}/core/Step.d.ts +31 -10
  71. package/dist/cjs/core/Step.d.ts.map +1 -0
  72. package/dist/cjs/{src/core → core}/Step.js +105 -10
  73. package/dist/cjs/core/Step.js.map +1 -0
  74. package/dist/cjs/core/ToolManager.js.map +1 -0
  75. package/dist/{src → cjs}/index.d.ts +4 -1
  76. package/dist/cjs/index.d.ts.map +1 -0
  77. package/dist/cjs/{src/index.js → index.js} +12 -1
  78. package/dist/cjs/index.js.map +1 -0
  79. package/dist/cjs/{src/providers → providers}/AnthropicProvider.js +18 -18
  80. package/dist/cjs/providers/AnthropicProvider.js.map +1 -0
  81. package/dist/{src → cjs}/providers/GeminiProvider.d.ts.map +1 -1
  82. package/dist/cjs/{src/providers → providers}/GeminiProvider.js +123 -51
  83. package/dist/cjs/providers/GeminiProvider.js.map +1 -0
  84. package/dist/cjs/{src/providers → providers}/OpenAIProvider.js +19 -19
  85. package/dist/cjs/providers/OpenAIProvider.js.map +1 -0
  86. package/dist/cjs/{src/providers → providers}/OpenRouterProvider.js +19 -19
  87. package/dist/cjs/providers/OpenRouterProvider.js.map +1 -0
  88. package/dist/cjs/providers/index.js.map +1 -0
  89. package/dist/cjs/{src/types → types}/agent.d.ts +11 -3
  90. package/dist/cjs/types/agent.d.ts.map +1 -0
  91. package/dist/cjs/types/agent.js.map +1 -0
  92. package/dist/{src → cjs}/types/ai.js.map +1 -1
  93. package/dist/cjs/types/history.js.map +1 -0
  94. package/dist/cjs/{src/types → types}/index.d.ts +2 -1
  95. package/dist/{src → cjs}/types/index.d.ts.map +1 -1
  96. package/dist/cjs/{src/types → types}/index.js +6 -1
  97. package/dist/cjs/types/index.js.map +1 -0
  98. package/dist/cjs/types/persistence.js.map +1 -0
  99. package/dist/cjs/{src/types → types}/route.d.ts +111 -12
  100. package/dist/cjs/types/route.d.ts.map +1 -0
  101. package/dist/cjs/{src/types → types}/route.js.map +1 -1
  102. package/dist/cjs/types/session.js.map +1 -0
  103. package/dist/cjs/types/template.d.ts +88 -0
  104. package/dist/cjs/types/template.d.ts.map +1 -0
  105. package/dist/cjs/types/tool.js.map +1 -0
  106. package/dist/cjs/utils/clone.js.map +1 -0
  107. package/dist/cjs/utils/condition.d.ts +38 -0
  108. package/dist/cjs/utils/condition.d.ts.map +1 -0
  109. package/dist/cjs/utils/condition.js +168 -0
  110. package/dist/cjs/utils/condition.js.map +1 -0
  111. package/dist/cjs/utils/event.js.map +1 -0
  112. package/dist/cjs/utils/history.js.map +1 -0
  113. package/dist/cjs/utils/id.js.map +1 -0
  114. package/dist/cjs/{src/utils → utils}/index.d.ts +3 -1
  115. package/dist/cjs/utils/index.d.ts.map +1 -0
  116. package/dist/cjs/{src/utils → utils}/index.js +12 -1
  117. package/dist/cjs/utils/index.js.map +1 -0
  118. package/dist/cjs/utils/json.d.ts +16 -0
  119. package/dist/cjs/utils/json.d.ts.map +1 -0
  120. package/dist/cjs/utils/json.js +47 -0
  121. package/dist/cjs/utils/json.js.map +1 -0
  122. package/dist/cjs/utils/logger.js.map +1 -0
  123. package/dist/{src → cjs}/utils/retry.d.ts +0 -3
  124. package/dist/cjs/utils/retry.d.ts.map +1 -0
  125. package/dist/cjs/{src/utils → utils}/retry.js +8 -7
  126. package/dist/cjs/utils/retry.js.map +1 -0
  127. package/dist/cjs/utils/session.js.map +1 -0
  128. package/dist/{src → cjs}/utils/template.d.ts +48 -0
  129. package/dist/cjs/utils/template.d.ts.map +1 -0
  130. package/dist/cjs/{src/utils → utils}/template.js +100 -0
  131. package/dist/cjs/utils/template.js.map +1 -0
  132. package/dist/constants/index.d.ts.map +1 -0
  133. package/dist/constants/index.js.map +1 -0
  134. package/dist/{src/core → core}/Agent.d.ts +6 -1
  135. package/dist/core/Agent.d.ts.map +1 -0
  136. package/dist/{src/core → core}/Agent.js +43 -3
  137. package/dist/core/Agent.js.map +1 -0
  138. package/dist/core/BatchExecutor.d.ts +353 -0
  139. package/dist/core/BatchExecutor.d.ts.map +1 -0
  140. package/dist/core/BatchExecutor.js +837 -0
  141. package/dist/core/BatchExecutor.js.map +1 -0
  142. package/dist/core/BatchPromptBuilder.d.ts +86 -0
  143. package/dist/core/BatchPromptBuilder.d.ts.map +1 -0
  144. package/dist/core/BatchPromptBuilder.js +197 -0
  145. package/dist/core/BatchPromptBuilder.js.map +1 -0
  146. package/dist/core/Events.d.ts.map +1 -0
  147. package/dist/core/Events.js.map +1 -0
  148. package/dist/core/PersistenceManager.d.ts.map +1 -0
  149. package/dist/core/PersistenceManager.js.map +1 -0
  150. package/dist/{cjs/src/core → core}/PromptComposer.d.ts +1 -1
  151. package/dist/core/PromptComposer.d.ts.map +1 -0
  152. package/dist/{src/core → core}/PromptComposer.js +45 -8
  153. package/dist/core/PromptComposer.js.map +1 -0
  154. package/dist/core/ResponseEngine.d.ts.map +1 -0
  155. package/dist/core/ResponseEngine.js +198 -0
  156. package/dist/core/ResponseEngine.js.map +1 -0
  157. package/dist/{cjs/src/core → core}/ResponseModal.d.ts +45 -0
  158. package/dist/core/ResponseModal.d.ts.map +1 -0
  159. package/dist/{src/core → core}/ResponseModal.js +686 -66
  160. package/dist/core/ResponseModal.js.map +1 -0
  161. package/dist/{cjs/src/core → core}/ResponsePipeline.d.ts +2 -2
  162. package/dist/core/ResponsePipeline.d.ts.map +1 -0
  163. package/dist/{src/core → core}/ResponsePipeline.js +13 -6
  164. package/dist/core/ResponsePipeline.js.map +1 -0
  165. package/dist/{cjs/src/core → core}/Route.d.ts +34 -5
  166. package/dist/core/Route.d.ts.map +1 -0
  167. package/dist/{src/core → core}/Route.js +195 -18
  168. package/dist/core/Route.js.map +1 -0
  169. package/dist/{src/core → core}/RoutingEngine.d.ts +30 -5
  170. package/dist/core/RoutingEngine.d.ts.map +1 -0
  171. package/dist/{src/core → core}/RoutingEngine.js +310 -60
  172. package/dist/core/RoutingEngine.js.map +1 -0
  173. package/dist/core/SessionManager.d.ts.map +1 -0
  174. package/dist/core/SessionManager.js.map +1 -0
  175. package/dist/{cjs/src/core → core}/Step.d.ts +31 -10
  176. package/dist/core/Step.d.ts.map +1 -0
  177. package/dist/{src/core → core}/Step.js +104 -9
  178. package/dist/core/Step.js.map +1 -0
  179. package/dist/core/ToolManager.d.ts.map +1 -0
  180. package/dist/core/ToolManager.js.map +1 -0
  181. package/dist/{cjs/src/index.d.ts → index.d.ts} +4 -1
  182. package/dist/index.d.ts.map +1 -0
  183. package/dist/{src/index.js → index.js} +3 -0
  184. package/dist/index.js.map +1 -0
  185. package/dist/providers/AnthropicProvider.d.ts.map +1 -0
  186. package/dist/{src/providers → providers}/AnthropicProvider.js +17 -17
  187. package/dist/providers/AnthropicProvider.js.map +1 -0
  188. package/dist/providers/GeminiProvider.d.ts.map +1 -0
  189. package/dist/{src/providers → providers}/GeminiProvider.js +123 -51
  190. package/dist/providers/GeminiProvider.js.map +1 -0
  191. package/dist/providers/OpenAIProvider.d.ts.map +1 -0
  192. package/dist/{src/providers → providers}/OpenAIProvider.js +18 -18
  193. package/dist/providers/OpenAIProvider.js.map +1 -0
  194. package/dist/providers/OpenRouterProvider.d.ts.map +1 -0
  195. package/dist/{src/providers → providers}/OpenRouterProvider.js +18 -18
  196. package/dist/providers/OpenRouterProvider.js.map +1 -0
  197. package/dist/providers/index.d.ts.map +1 -0
  198. package/dist/providers/index.js.map +1 -0
  199. package/dist/{src/types → types}/agent.d.ts +11 -3
  200. package/dist/types/agent.d.ts.map +1 -0
  201. package/dist/types/agent.js.map +1 -0
  202. package/dist/types/ai.d.ts.map +1 -0
  203. package/dist/types/ai.js.map +1 -0
  204. package/dist/types/history.d.ts.map +1 -0
  205. package/dist/types/history.js.map +1 -0
  206. package/dist/{src/types → types}/index.d.ts +2 -1
  207. package/dist/types/index.d.ts.map +1 -0
  208. package/dist/{src/types → types}/index.js +1 -0
  209. package/dist/types/index.js.map +1 -0
  210. package/dist/types/persistence.d.ts.map +1 -0
  211. package/dist/types/persistence.js.map +1 -0
  212. package/dist/{src/types → types}/route.d.ts +111 -12
  213. package/dist/types/route.d.ts.map +1 -0
  214. package/dist/{src/types → types}/route.js.map +1 -1
  215. package/dist/types/routing.d.ts.map +1 -0
  216. package/dist/{cjs/src/types → types}/routing.js.map +1 -1
  217. package/dist/types/schema.d.ts.map +1 -0
  218. package/dist/{cjs/src/types → types}/schema.js.map +1 -1
  219. package/dist/types/session.d.ts.map +1 -0
  220. package/dist/{src/types → types}/session.js.map +1 -1
  221. package/dist/types/template.d.ts +88 -0
  222. package/dist/types/template.d.ts.map +1 -0
  223. package/dist/{cjs/src/types → types}/template.js.map +1 -1
  224. package/dist/types/tool.d.ts.map +1 -0
  225. package/dist/types/tool.js.map +1 -0
  226. package/dist/utils/clone.d.ts.map +1 -0
  227. package/dist/utils/clone.js.map +1 -0
  228. package/dist/utils/condition.d.ts +38 -0
  229. package/dist/utils/condition.d.ts.map +1 -0
  230. package/dist/utils/condition.js +161 -0
  231. package/dist/utils/condition.js.map +1 -0
  232. package/dist/utils/event.d.ts.map +1 -0
  233. package/dist/utils/event.js.map +1 -0
  234. package/dist/utils/history.d.ts.map +1 -0
  235. package/dist/utils/history.js.map +1 -0
  236. package/dist/utils/id.d.ts.map +1 -0
  237. package/dist/utils/id.js.map +1 -0
  238. package/dist/{src/utils → utils}/index.d.ts +3 -1
  239. package/dist/utils/index.d.ts.map +1 -0
  240. package/dist/{src/utils → utils}/index.js +5 -1
  241. package/dist/utils/index.js.map +1 -0
  242. package/dist/utils/json.d.ts +16 -0
  243. package/dist/utils/json.d.ts.map +1 -0
  244. package/dist/utils/json.js +43 -0
  245. package/dist/utils/json.js.map +1 -0
  246. package/dist/utils/logger.d.ts.map +1 -0
  247. package/dist/utils/logger.js.map +1 -0
  248. package/dist/{cjs/src/utils → utils}/retry.d.ts +0 -3
  249. package/dist/utils/retry.d.ts.map +1 -0
  250. package/dist/{src/utils → utils}/retry.js +5 -4
  251. package/dist/utils/retry.js.map +1 -0
  252. package/dist/utils/session.d.ts.map +1 -0
  253. package/dist/utils/session.js.map +1 -0
  254. package/dist/{cjs/src/utils → utils}/template.d.ts +48 -0
  255. package/dist/utils/template.d.ts.map +1 -0
  256. package/dist/{src/utils → utils}/template.js +98 -0
  257. package/dist/utils/template.js.map +1 -0
  258. package/docs/api/README.md +221 -12
  259. package/docs/api/overview.md +202 -3
  260. package/docs/architecture/data-extraction-flow.md +363 -0
  261. package/docs/architecture/multi-step-execution.md +243 -0
  262. package/docs/core/agent/README.md +120 -5
  263. package/docs/core/agent/session-management.md +1 -1
  264. package/docs/core/ai-integration/prompt-composition.md +135 -0
  265. package/docs/core/ai-integration/response-processing.md +146 -0
  266. package/docs/core/conversation-flows/data-collection.md +143 -0
  267. package/docs/core/conversation-flows/routes.md +2 -2
  268. package/docs/core/conversation-flows/step-transitions.md +132 -0
  269. package/docs/core/conversation-flows/steps.md +112 -0
  270. package/docs/core/error-handling.md +193 -0
  271. package/docs/core/routing/intelligent-routing.md +118 -0
  272. package/docs/guides/getting-started/README.md +284 -3
  273. package/docs/guides/migration/README.md +23 -0
  274. package/docs/guides/migration/flexible-routing-conditions.md +375 -0
  275. package/docs/guides/migration/multi-step-execution.md +303 -0
  276. package/examples/advanced-patterns/knowledge-based-agent.ts +101 -24
  277. package/examples/advanced-patterns/persistent-onboarding.ts +40 -5
  278. package/examples/advanced-patterns/route-lifecycle-hooks.ts +82 -12
  279. package/examples/advanced-patterns/streaming-responses.ts +2 -2
  280. package/examples/ai-providers/anthropic-integration.ts +4 -4
  281. package/examples/ai-providers/openai-integration.ts +1 -1
  282. package/examples/condition-patterns/function-only-conditions.ts +365 -0
  283. package/examples/condition-patterns/mixed-array-conditions.ts +477 -0
  284. package/examples/condition-patterns/route-skipif-patterns.ts +468 -0
  285. package/examples/condition-patterns/step-skipif-patterns.ts +0 -0
  286. package/examples/condition-patterns/string-only-conditions.ts +296 -0
  287. package/examples/conversation-flows/completion-transitions.ts +48 -7
  288. package/examples/core-concepts/basic-agent.ts +54 -33
  289. package/examples/core-concepts/schema-driven-extraction.ts +33 -9
  290. package/examples/core-concepts/session-management.ts +51 -16
  291. package/examples/integrations/database-integration.ts +6 -6
  292. package/examples/integrations/healthcare-integration.ts +10 -10
  293. package/examples/integrations/search-integration.ts +8 -8
  294. package/examples/integrations/server-session-management.ts +8 -8
  295. package/examples/persistence/database-persistence.ts +15 -15
  296. package/examples/persistence/memory-sessions.ts +3 -3
  297. package/examples/persistence/redis-persistence.ts +7 -9
  298. package/examples/tools/data-enrichment-tools.ts +4 -4
  299. package/package.json +6 -4
  300. package/src/adapters/PrismaAdapter.ts +3 -2
  301. package/src/adapters/RedisAdapter.ts +3 -3
  302. package/src/core/Agent.ts +54 -2
  303. package/src/core/BatchExecutor.ts +1156 -0
  304. package/src/core/BatchPromptBuilder.ts +275 -0
  305. package/src/core/PromptComposer.ts +53 -16
  306. package/src/core/ResponseEngine.ts +143 -4
  307. package/src/core/ResponseModal.ts +888 -66
  308. package/src/core/ResponsePipeline.ts +17 -9
  309. package/src/core/Route.ts +223 -22
  310. package/src/core/RoutingEngine.ts +426 -83
  311. package/src/core/Step.ts +144 -16
  312. package/src/index.ts +19 -0
  313. package/src/providers/AnthropicProvider.ts +17 -17
  314. package/src/providers/GeminiProvider.ts +129 -60
  315. package/src/providers/OpenAIProvider.ts +18 -18
  316. package/src/providers/OpenRouterProvider.ts +18 -18
  317. package/src/types/agent.ts +11 -3
  318. package/src/types/index.ts +12 -1
  319. package/src/types/route.ts +131 -12
  320. package/src/types/template.ts +70 -2
  321. package/src/utils/condition.ts +190 -0
  322. package/src/utils/index.ts +12 -0
  323. package/src/utils/json.ts +46 -0
  324. package/src/utils/retry.ts +5 -4
  325. package/src/utils/template.ts +109 -0
  326. package/dist/cjs/src/adapters/MemoryAdapter.d.ts.map +0 -1
  327. package/dist/cjs/src/adapters/MemoryAdapter.js.map +0 -1
  328. package/dist/cjs/src/adapters/MongoAdapter.d.ts.map +0 -1
  329. package/dist/cjs/src/adapters/MongoAdapter.js.map +0 -1
  330. package/dist/cjs/src/adapters/OpenSearchAdapter.d.ts.map +0 -1
  331. package/dist/cjs/src/adapters/OpenSearchAdapter.js.map +0 -1
  332. package/dist/cjs/src/adapters/PostgreSQLAdapter.d.ts.map +0 -1
  333. package/dist/cjs/src/adapters/PostgreSQLAdapter.js.map +0 -1
  334. package/dist/cjs/src/adapters/PrismaAdapter.d.ts.map +0 -1
  335. package/dist/cjs/src/adapters/PrismaAdapter.js.map +0 -1
  336. package/dist/cjs/src/adapters/RedisAdapter.d.ts.map +0 -1
  337. package/dist/cjs/src/adapters/RedisAdapter.js.map +0 -1
  338. package/dist/cjs/src/adapters/SQLiteAdapter.d.ts.map +0 -1
  339. package/dist/cjs/src/adapters/SQLiteAdapter.js.map +0 -1
  340. package/dist/cjs/src/adapters/index.d.ts.map +0 -1
  341. package/dist/cjs/src/adapters/index.js.map +0 -1
  342. package/dist/cjs/src/constants/index.d.ts.map +0 -1
  343. package/dist/cjs/src/constants/index.js.map +0 -1
  344. package/dist/cjs/src/core/Agent.d.ts.map +0 -1
  345. package/dist/cjs/src/core/Agent.js.map +0 -1
  346. package/dist/cjs/src/core/Events.d.ts.map +0 -1
  347. package/dist/cjs/src/core/Events.js.map +0 -1
  348. package/dist/cjs/src/core/PersistenceManager.d.ts.map +0 -1
  349. package/dist/cjs/src/core/PersistenceManager.js.map +0 -1
  350. package/dist/cjs/src/core/PromptComposer.d.ts.map +0 -1
  351. package/dist/cjs/src/core/PromptComposer.js.map +0 -1
  352. package/dist/cjs/src/core/ResponseEngine.d.ts.map +0 -1
  353. package/dist/cjs/src/core/ResponseEngine.js +0 -84
  354. package/dist/cjs/src/core/ResponseEngine.js.map +0 -1
  355. package/dist/cjs/src/core/ResponseModal.d.ts.map +0 -1
  356. package/dist/cjs/src/core/ResponseModal.js.map +0 -1
  357. package/dist/cjs/src/core/ResponsePipeline.d.ts.map +0 -1
  358. package/dist/cjs/src/core/ResponsePipeline.js.map +0 -1
  359. package/dist/cjs/src/core/Route.d.ts.map +0 -1
  360. package/dist/cjs/src/core/Route.js.map +0 -1
  361. package/dist/cjs/src/core/RoutingEngine.d.ts.map +0 -1
  362. package/dist/cjs/src/core/RoutingEngine.js.map +0 -1
  363. package/dist/cjs/src/core/SessionManager.d.ts.map +0 -1
  364. package/dist/cjs/src/core/SessionManager.js.map +0 -1
  365. package/dist/cjs/src/core/Step.d.ts.map +0 -1
  366. package/dist/cjs/src/core/Step.js.map +0 -1
  367. package/dist/cjs/src/core/ToolManager.d.ts.map +0 -1
  368. package/dist/cjs/src/core/ToolManager.js.map +0 -1
  369. package/dist/cjs/src/index.d.ts.map +0 -1
  370. package/dist/cjs/src/index.js.map +0 -1
  371. package/dist/cjs/src/providers/AnthropicProvider.d.ts.map +0 -1
  372. package/dist/cjs/src/providers/AnthropicProvider.js.map +0 -1
  373. package/dist/cjs/src/providers/GeminiProvider.d.ts.map +0 -1
  374. package/dist/cjs/src/providers/GeminiProvider.js.map +0 -1
  375. package/dist/cjs/src/providers/OpenAIProvider.d.ts.map +0 -1
  376. package/dist/cjs/src/providers/OpenAIProvider.js.map +0 -1
  377. package/dist/cjs/src/providers/OpenRouterProvider.d.ts.map +0 -1
  378. package/dist/cjs/src/providers/OpenRouterProvider.js.map +0 -1
  379. package/dist/cjs/src/providers/index.d.ts.map +0 -1
  380. package/dist/cjs/src/providers/index.js.map +0 -1
  381. package/dist/cjs/src/types/agent.d.ts.map +0 -1
  382. package/dist/cjs/src/types/agent.js.map +0 -1
  383. package/dist/cjs/src/types/ai.d.ts.map +0 -1
  384. package/dist/cjs/src/types/ai.js.map +0 -1
  385. package/dist/cjs/src/types/history.d.ts.map +0 -1
  386. package/dist/cjs/src/types/history.js.map +0 -1
  387. package/dist/cjs/src/types/index.d.ts.map +0 -1
  388. package/dist/cjs/src/types/index.js.map +0 -1
  389. package/dist/cjs/src/types/persistence.d.ts.map +0 -1
  390. package/dist/cjs/src/types/persistence.js.map +0 -1
  391. package/dist/cjs/src/types/route.d.ts.map +0 -1
  392. package/dist/cjs/src/types/routing.d.ts.map +0 -1
  393. package/dist/cjs/src/types/schema.d.ts.map +0 -1
  394. package/dist/cjs/src/types/session.d.ts.map +0 -1
  395. package/dist/cjs/src/types/session.js.map +0 -1
  396. package/dist/cjs/src/types/template.d.ts +0 -30
  397. package/dist/cjs/src/types/template.d.ts.map +0 -1
  398. package/dist/cjs/src/types/tool.d.ts.map +0 -1
  399. package/dist/cjs/src/types/tool.js.map +0 -1
  400. package/dist/cjs/src/utils/clone.d.ts.map +0 -1
  401. package/dist/cjs/src/utils/clone.js.map +0 -1
  402. package/dist/cjs/src/utils/event.d.ts.map +0 -1
  403. package/dist/cjs/src/utils/event.js.map +0 -1
  404. package/dist/cjs/src/utils/history.d.ts.map +0 -1
  405. package/dist/cjs/src/utils/history.js.map +0 -1
  406. package/dist/cjs/src/utils/id.d.ts.map +0 -1
  407. package/dist/cjs/src/utils/id.js.map +0 -1
  408. package/dist/cjs/src/utils/index.d.ts.map +0 -1
  409. package/dist/cjs/src/utils/index.js.map +0 -1
  410. package/dist/cjs/src/utils/logger.d.ts.map +0 -1
  411. package/dist/cjs/src/utils/logger.js.map +0 -1
  412. package/dist/cjs/src/utils/retry.d.ts.map +0 -1
  413. package/dist/cjs/src/utils/retry.js.map +0 -1
  414. package/dist/cjs/src/utils/session.d.ts.map +0 -1
  415. package/dist/cjs/src/utils/session.js.map +0 -1
  416. package/dist/cjs/src/utils/template.d.ts.map +0 -1
  417. package/dist/cjs/src/utils/template.js.map +0 -1
  418. package/dist/src/adapters/MemoryAdapter.js.map +0 -1
  419. package/dist/src/adapters/MongoAdapter.js.map +0 -1
  420. package/dist/src/adapters/OpenSearchAdapter.js.map +0 -1
  421. package/dist/src/adapters/PostgreSQLAdapter.js.map +0 -1
  422. package/dist/src/adapters/PrismaAdapter.js.map +0 -1
  423. package/dist/src/adapters/RedisAdapter.js.map +0 -1
  424. package/dist/src/adapters/SQLiteAdapter.js.map +0 -1
  425. package/dist/src/adapters/index.js.map +0 -1
  426. package/dist/src/constants/index.js.map +0 -1
  427. package/dist/src/core/Agent.d.ts.map +0 -1
  428. package/dist/src/core/Agent.js.map +0 -1
  429. package/dist/src/core/Events.js.map +0 -1
  430. package/dist/src/core/PersistenceManager.js.map +0 -1
  431. package/dist/src/core/PromptComposer.d.ts.map +0 -1
  432. package/dist/src/core/PromptComposer.js.map +0 -1
  433. package/dist/src/core/ResponseEngine.js +0 -80
  434. package/dist/src/core/ResponseEngine.js.map +0 -1
  435. package/dist/src/core/ResponseModal.d.ts.map +0 -1
  436. package/dist/src/core/ResponseModal.js.map +0 -1
  437. package/dist/src/core/ResponsePipeline.d.ts.map +0 -1
  438. package/dist/src/core/ResponsePipeline.js.map +0 -1
  439. package/dist/src/core/Route.d.ts.map +0 -1
  440. package/dist/src/core/Route.js.map +0 -1
  441. package/dist/src/core/RoutingEngine.d.ts.map +0 -1
  442. package/dist/src/core/RoutingEngine.js.map +0 -1
  443. package/dist/src/core/SessionManager.js.map +0 -1
  444. package/dist/src/core/Step.d.ts.map +0 -1
  445. package/dist/src/core/Step.js.map +0 -1
  446. package/dist/src/core/ToolManager.js.map +0 -1
  447. package/dist/src/index.d.ts.map +0 -1
  448. package/dist/src/index.js.map +0 -1
  449. package/dist/src/providers/AnthropicProvider.js.map +0 -1
  450. package/dist/src/providers/GeminiProvider.js.map +0 -1
  451. package/dist/src/providers/OpenAIProvider.js.map +0 -1
  452. package/dist/src/providers/OpenRouterProvider.js.map +0 -1
  453. package/dist/src/providers/index.js.map +0 -1
  454. package/dist/src/types/agent.d.ts.map +0 -1
  455. package/dist/src/types/agent.js.map +0 -1
  456. package/dist/src/types/history.js.map +0 -1
  457. package/dist/src/types/index.js.map +0 -1
  458. package/dist/src/types/persistence.js.map +0 -1
  459. package/dist/src/types/route.d.ts.map +0 -1
  460. package/dist/src/types/template.d.ts +0 -30
  461. package/dist/src/types/template.d.ts.map +0 -1
  462. package/dist/src/types/tool.js.map +0 -1
  463. package/dist/src/utils/clone.js.map +0 -1
  464. package/dist/src/utils/event.js.map +0 -1
  465. package/dist/src/utils/history.js.map +0 -1
  466. package/dist/src/utils/id.js.map +0 -1
  467. package/dist/src/utils/index.d.ts.map +0 -1
  468. package/dist/src/utils/index.js.map +0 -1
  469. package/dist/src/utils/logger.js.map +0 -1
  470. package/dist/src/utils/retry.d.ts.map +0 -1
  471. package/dist/src/utils/retry.js.map +0 -1
  472. package/dist/src/utils/session.js.map +0 -1
  473. package/dist/src/utils/template.d.ts.map +0 -1
  474. package/dist/src/utils/template.js.map +0 -1
  475. /package/dist/{cjs/src/adapters → adapters}/MemoryAdapter.d.ts +0 -0
  476. /package/dist/{src/adapters → adapters}/MemoryAdapter.js +0 -0
  477. /package/dist/{cjs/src/adapters → adapters}/MongoAdapter.d.ts +0 -0
  478. /package/dist/{src/adapters → adapters}/MongoAdapter.js +0 -0
  479. /package/dist/{cjs/src/adapters → adapters}/OpenSearchAdapter.d.ts +0 -0
  480. /package/dist/{src/adapters → adapters}/OpenSearchAdapter.js +0 -0
  481. /package/dist/{cjs/src/adapters → adapters}/PostgreSQLAdapter.d.ts +0 -0
  482. /package/dist/{src/adapters → adapters}/PostgreSQLAdapter.js +0 -0
  483. /package/dist/{cjs/src/adapters → adapters}/PrismaAdapter.d.ts +0 -0
  484. /package/dist/{cjs/src/adapters → adapters}/RedisAdapter.d.ts +0 -0
  485. /package/dist/{cjs/src/adapters → adapters}/SQLiteAdapter.d.ts +0 -0
  486. /package/dist/{src/adapters → adapters}/SQLiteAdapter.js +0 -0
  487. /package/dist/{cjs/src/adapters → adapters}/index.d.ts +0 -0
  488. /package/dist/{src/adapters → adapters}/index.js +0 -0
  489. /package/dist/{src → cjs}/adapters/MemoryAdapter.d.ts +0 -0
  490. /package/dist/{src → cjs}/adapters/MemoryAdapter.d.ts.map +0 -0
  491. /package/dist/cjs/{src/adapters → adapters}/MemoryAdapter.js +0 -0
  492. /package/dist/{src → cjs}/adapters/MongoAdapter.d.ts +0 -0
  493. /package/dist/{src → cjs}/adapters/MongoAdapter.d.ts.map +0 -0
  494. /package/dist/cjs/{src/adapters → adapters}/MongoAdapter.js +0 -0
  495. /package/dist/{src → cjs}/adapters/OpenSearchAdapter.d.ts +0 -0
  496. /package/dist/{src → cjs}/adapters/OpenSearchAdapter.d.ts.map +0 -0
  497. /package/dist/cjs/{src/adapters → adapters}/OpenSearchAdapter.js +0 -0
  498. /package/dist/{src → cjs}/adapters/PostgreSQLAdapter.d.ts +0 -0
  499. /package/dist/{src → cjs}/adapters/PostgreSQLAdapter.d.ts.map +0 -0
  500. /package/dist/cjs/{src/adapters → adapters}/PostgreSQLAdapter.js +0 -0
  501. /package/dist/{src → cjs}/adapters/PrismaAdapter.d.ts +0 -0
  502. /package/dist/{src → cjs}/adapters/RedisAdapter.d.ts +0 -0
  503. /package/dist/{src → cjs}/adapters/RedisAdapter.d.ts.map +0 -0
  504. /package/dist/{src → cjs}/adapters/SQLiteAdapter.d.ts +0 -0
  505. /package/dist/{src → cjs}/adapters/SQLiteAdapter.d.ts.map +0 -0
  506. /package/dist/cjs/{src/adapters → adapters}/SQLiteAdapter.js +0 -0
  507. /package/dist/{src → cjs}/adapters/index.d.ts +0 -0
  508. /package/dist/{src → cjs}/adapters/index.d.ts.map +0 -0
  509. /package/dist/cjs/{src/adapters → adapters}/index.js +0 -0
  510. /package/dist/cjs/{src/constants → constants}/index.d.ts +0 -0
  511. /package/dist/{src → cjs}/constants/index.d.ts.map +0 -0
  512. /package/dist/cjs/{src/constants → constants}/index.js +0 -0
  513. /package/dist/cjs/{src/core → core}/Events.d.ts +0 -0
  514. /package/dist/{src → cjs}/core/Events.d.ts.map +0 -0
  515. /package/dist/cjs/{src/core → core}/Events.js +0 -0
  516. /package/dist/cjs/{src/core → core}/PersistenceManager.d.ts +0 -0
  517. /package/dist/{src → cjs}/core/PersistenceManager.d.ts.map +0 -0
  518. /package/dist/cjs/{src/core → core}/PersistenceManager.js +0 -0
  519. /package/dist/cjs/{src/core → core}/ResponseEngine.d.ts +0 -0
  520. /package/dist/cjs/{src/core → core}/SessionManager.d.ts +0 -0
  521. /package/dist/{src → cjs}/core/SessionManager.d.ts.map +0 -0
  522. /package/dist/cjs/{src/core → core}/SessionManager.js +0 -0
  523. /package/dist/cjs/{src/core → core}/ToolManager.d.ts +0 -0
  524. /package/dist/{src → cjs}/core/ToolManager.d.ts.map +0 -0
  525. /package/dist/cjs/{src/core → core}/ToolManager.js +0 -0
  526. /package/dist/cjs/{src/providers → providers}/AnthropicProvider.d.ts +0 -0
  527. /package/dist/{src → cjs}/providers/AnthropicProvider.d.ts.map +0 -0
  528. /package/dist/cjs/{src/providers → providers}/GeminiProvider.d.ts +0 -0
  529. /package/dist/cjs/{src/providers → providers}/OpenAIProvider.d.ts +0 -0
  530. /package/dist/{src → cjs}/providers/OpenAIProvider.d.ts.map +0 -0
  531. /package/dist/cjs/{src/providers → providers}/OpenRouterProvider.d.ts +0 -0
  532. /package/dist/{src → cjs}/providers/OpenRouterProvider.d.ts.map +0 -0
  533. /package/dist/cjs/{src/providers → providers}/index.d.ts +0 -0
  534. /package/dist/{src → cjs}/providers/index.d.ts.map +0 -0
  535. /package/dist/cjs/{src/providers → providers}/index.js +0 -0
  536. /package/dist/cjs/{src/types → types}/agent.js +0 -0
  537. /package/dist/cjs/{src/types → types}/ai.d.ts +0 -0
  538. /package/dist/{src → cjs}/types/ai.d.ts.map +0 -0
  539. /package/dist/cjs/{src/types → types}/ai.js +0 -0
  540. /package/dist/cjs/{src/types → types}/history.d.ts +0 -0
  541. /package/dist/{src → cjs}/types/history.d.ts.map +0 -0
  542. /package/dist/cjs/{src/types → types}/history.js +0 -0
  543. /package/dist/cjs/{src/types → types}/persistence.d.ts +0 -0
  544. /package/dist/{src → cjs}/types/persistence.d.ts.map +0 -0
  545. /package/dist/cjs/{src/types → types}/persistence.js +0 -0
  546. /package/dist/cjs/{src/types → types}/route.js +0 -0
  547. /package/dist/cjs/{src/types → types}/routing.d.ts +0 -0
  548. /package/dist/{src → cjs}/types/routing.d.ts.map +0 -0
  549. /package/dist/cjs/{src/types → types}/routing.js +0 -0
  550. /package/dist/{src → cjs}/types/routing.js.map +0 -0
  551. /package/dist/cjs/{src/types → types}/schema.d.ts +0 -0
  552. /package/dist/{src → cjs}/types/schema.d.ts.map +0 -0
  553. /package/dist/cjs/{src/types → types}/schema.js +0 -0
  554. /package/dist/{src → cjs}/types/schema.js.map +0 -0
  555. /package/dist/cjs/{src/types → types}/session.d.ts +0 -0
  556. /package/dist/{src → cjs}/types/session.d.ts.map +0 -0
  557. /package/dist/cjs/{src/types → types}/session.js +0 -0
  558. /package/dist/cjs/{src/types → types}/template.js +0 -0
  559. /package/dist/{src → cjs}/types/template.js.map +0 -0
  560. /package/dist/cjs/{src/types → types}/tool.d.ts +0 -0
  561. /package/dist/{src → cjs}/types/tool.d.ts.map +0 -0
  562. /package/dist/cjs/{src/types → types}/tool.js +0 -0
  563. /package/dist/cjs/{src/utils → utils}/clone.d.ts +0 -0
  564. /package/dist/{src → cjs}/utils/clone.d.ts.map +0 -0
  565. /package/dist/cjs/{src/utils → utils}/clone.js +0 -0
  566. /package/dist/cjs/{src/utils → utils}/event.d.ts +0 -0
  567. /package/dist/{src → cjs}/utils/event.d.ts.map +0 -0
  568. /package/dist/cjs/{src/utils → utils}/event.js +0 -0
  569. /package/dist/cjs/{src/utils → utils}/history.d.ts +0 -0
  570. /package/dist/{src → cjs}/utils/history.d.ts.map +0 -0
  571. /package/dist/cjs/{src/utils → utils}/history.js +0 -0
  572. /package/dist/cjs/{src/utils → utils}/id.d.ts +0 -0
  573. /package/dist/{src → cjs}/utils/id.d.ts.map +0 -0
  574. /package/dist/cjs/{src/utils → utils}/id.js +0 -0
  575. /package/dist/cjs/{src/utils → utils}/logger.d.ts +0 -0
  576. /package/dist/{src → cjs}/utils/logger.d.ts.map +0 -0
  577. /package/dist/cjs/{src/utils → utils}/logger.js +0 -0
  578. /package/dist/cjs/{src/utils → utils}/session.d.ts +0 -0
  579. /package/dist/{src → cjs}/utils/session.d.ts.map +0 -0
  580. /package/dist/cjs/{src/utils → utils}/session.js +0 -0
  581. /package/dist/{src/constants → constants}/index.d.ts +0 -0
  582. /package/dist/{src/constants → constants}/index.js +0 -0
  583. /package/dist/{src/core → core}/Events.d.ts +0 -0
  584. /package/dist/{src/core → core}/Events.js +0 -0
  585. /package/dist/{src/core → core}/PersistenceManager.d.ts +0 -0
  586. /package/dist/{src/core → core}/PersistenceManager.js +0 -0
  587. /package/dist/{src/core → core}/ResponseEngine.d.ts +0 -0
  588. /package/dist/{src/core → core}/SessionManager.d.ts +0 -0
  589. /package/dist/{src/core → core}/SessionManager.js +0 -0
  590. /package/dist/{src/core → core}/ToolManager.d.ts +0 -0
  591. /package/dist/{src/core → core}/ToolManager.js +0 -0
  592. /package/dist/{src/providers → providers}/AnthropicProvider.d.ts +0 -0
  593. /package/dist/{src/providers → providers}/GeminiProvider.d.ts +0 -0
  594. /package/dist/{src/providers → providers}/OpenAIProvider.d.ts +0 -0
  595. /package/dist/{src/providers → providers}/OpenRouterProvider.d.ts +0 -0
  596. /package/dist/{src/providers → providers}/index.d.ts +0 -0
  597. /package/dist/{src/providers → providers}/index.js +0 -0
  598. /package/dist/{src/types → types}/agent.js +0 -0
  599. /package/dist/{src/types → types}/ai.d.ts +0 -0
  600. /package/dist/{src/types → types}/ai.js +0 -0
  601. /package/dist/{src/types → types}/history.d.ts +0 -0
  602. /package/dist/{src/types → types}/history.js +0 -0
  603. /package/dist/{src/types → types}/persistence.d.ts +0 -0
  604. /package/dist/{src/types → types}/persistence.js +0 -0
  605. /package/dist/{src/types → types}/route.js +0 -0
  606. /package/dist/{src/types → types}/routing.d.ts +0 -0
  607. /package/dist/{src/types → types}/routing.js +0 -0
  608. /package/dist/{src/types → types}/schema.d.ts +0 -0
  609. /package/dist/{src/types → types}/schema.js +0 -0
  610. /package/dist/{src/types → types}/session.d.ts +0 -0
  611. /package/dist/{src/types → types}/session.js +0 -0
  612. /package/dist/{src/types → types}/template.js +0 -0
  613. /package/dist/{src/types → types}/tool.d.ts +0 -0
  614. /package/dist/{src/types → types}/tool.js +0 -0
  615. /package/dist/{src/utils → utils}/clone.d.ts +0 -0
  616. /package/dist/{src/utils → utils}/clone.js +0 -0
  617. /package/dist/{src/utils → utils}/event.d.ts +0 -0
  618. /package/dist/{src/utils → utils}/event.js +0 -0
  619. /package/dist/{src/utils → utils}/history.d.ts +0 -0
  620. /package/dist/{src/utils → utils}/history.js +0 -0
  621. /package/dist/{src/utils → utils}/id.d.ts +0 -0
  622. /package/dist/{src/utils → utils}/id.js +0 -0
  623. /package/dist/{src/utils → utils}/logger.d.ts +0 -0
  624. /package/dist/{src/utils → utils}/logger.js +0 -0
  625. /package/dist/{src/utils → utils}/session.d.ts +0 -0
  626. /package/dist/{src/utils → utils}/session.js +0 -0
@@ -6,7 +6,10 @@ import { EventKind, MessageRole } from "../types";
6
6
  import { Step } from "./Step";
7
7
  import { ResponseEngine } from "./ResponseEngine";
8
8
  import { ResponsePipeline } from "./ResponsePipeline";
9
+ import { BatchExecutor } from "./BatchExecutor";
10
+ import { BatchPromptBuilder } from "./BatchPromptBuilder";
9
11
  import { cloneDeep, mergeCollected, enterStep, getLastMessageFromHistory, render, logger, historyToEvents } from "../utils";
12
+ import { createTemplateContext } from "../utils/template";
10
13
  import { END_ROUTE_ID } from "../constants";
11
14
  /**
12
15
  * Error class for response generation failures
@@ -48,6 +51,10 @@ export class ResponseModal {
48
51
  // Initialize response pipeline with agent dependencies
49
52
  this.responsePipeline = new ResponsePipeline(this.agent.getAgentOptions(), () => this.agent.getRoutes(), // Pass a function to get routes dynamically
50
53
  this.agent.getTools(), this.agent.getRoutingEngine(), this.agent.updateContext.bind(this.agent), this.agent.getUpdateDataMethod(), this.agent.updateCollectedData.bind(this.agent), this.getToolManager());
54
+ // Initialize batch executor for multi-step execution
55
+ this.batchExecutor = new BatchExecutor();
56
+ // Initialize batch prompt builder for combined prompts
57
+ this.batchPromptBuilder = new BatchPromptBuilder();
51
58
  }
52
59
  /**
53
60
  * Generate a non-streaming response using unified logic
@@ -268,6 +275,7 @@ export class ResponseModal {
268
275
  throw ResponseGenerationError.fromError(error, 'step_preparation', params, { session, effectiveContext });
269
276
  }
270
277
  // PHASE 2: ROUTING + STEP SELECTION - Determine which route and step to use
278
+ // Also performs pre-extraction and batch determination
271
279
  let routingResult;
272
280
  try {
273
281
  routingResult = await this.handleUnifiedRoutingAndStepSelection({
@@ -288,6 +296,9 @@ export class ResponseModal {
288
296
  selectedStep: routingResult.selectedStep,
289
297
  responseDirectives: routingResult.responseDirectives,
290
298
  isRouteComplete: routingResult.isRouteComplete,
299
+ batchSteps: routingResult.batchSteps,
300
+ batchStoppedReason: routingResult.batchStoppedReason,
301
+ batchStoppedAtStep: routingResult.batchStoppedAtStep,
291
302
  };
292
303
  }
293
304
  catch (error) {
@@ -313,31 +324,156 @@ export class ResponseModal {
313
324
  context: params.context,
314
325
  signal: params.signal,
315
326
  });
327
+ let updatedSession = routingResult.session;
328
+ let isRouteComplete = routingResult.isRouteComplete;
329
+ // PRE-EXTRACTION: If entering a route that collects data, extract data from user message first
330
+ // This allows us to skip steps whose data is already provided
331
+ // Requirement 3.1: Perform Pre_Extraction before determining the Batch
332
+ if (routingResult.selectedRoute && !isRouteComplete) {
333
+ // Always pre-extract when route collects data (not just on new route entry)
334
+ // This ensures batch determination has the most up-to-date data
335
+ if (this.shouldPreExtractData(routingResult.selectedRoute)) {
336
+ logger.debug(`[ResponseModal] Pre-extracting data for route: ${routingResult.selectedRoute.title}`);
337
+ const extractedData = await this.preExtractRouteData({
338
+ route: routingResult.selectedRoute,
339
+ history: params.history,
340
+ context: params.context,
341
+ session: updatedSession,
342
+ signal: params.signal,
343
+ });
344
+ if (extractedData && Object.keys(extractedData).length > 0) {
345
+ logger.debug(`[ResponseModal] Pre-extracted data:`, extractedData);
346
+ // Requirement 3.3: Merge pre-extracted data into session before batch determination
347
+ updatedSession = mergeCollected(updatedSession, extractedData);
348
+ // Also update agent's collected data
349
+ await this.agent.updateCollectedData(extractedData);
350
+ // Re-check route completion after pre-extraction
351
+ const allRequiredFieldsCollected = routingResult.selectedRoute.isComplete(updatedSession.data || {});
352
+ if (allRequiredFieldsCollected) {
353
+ logger.debug(`[ResponseModal] Route ${routingResult.selectedRoute.title} completed after pre-extraction`);
354
+ isRouteComplete = true;
355
+ }
356
+ }
357
+ }
358
+ }
359
+ // BATCH DETERMINATION: Use BatchExecutor to determine which steps can execute together
360
+ // Requirement 3.4: Pre-extraction results affect batch determination
361
+ let batchSteps;
362
+ let batchStoppedReason;
363
+ let batchStoppedAtStep;
364
+ if (routingResult.selectedRoute && !isRouteComplete) {
365
+ // Determine current step position for batch determination
366
+ const currentStep = routingResult.selectedStep ||
367
+ (updatedSession.currentStep ? routingResult.selectedRoute.getStep(updatedSession.currentStep.id) : undefined);
368
+ logger.debug(`[ResponseModal] Determining batch starting from step: ${currentStep?.id || 'initial'}`);
369
+ const batchResult = await this.batchExecutor.determineBatch({
370
+ route: routingResult.selectedRoute,
371
+ currentStep,
372
+ sessionData: updatedSession.data || {},
373
+ context: params.context,
374
+ });
375
+ batchSteps = batchResult.steps;
376
+ batchStoppedReason = batchResult.stoppedReason;
377
+ batchStoppedAtStep = batchResult.stoppedAtStep;
378
+ logger.debug(`[ResponseModal] Batch determined: ${batchSteps.length} steps, stopped reason: ${batchStoppedReason}`);
379
+ }
316
380
  // Determine next step using pipeline method for consistency
317
- const stepResult = this.responsePipeline.determineNextStep({
381
+ const stepResult = await this.responsePipeline.determineNextStep({
318
382
  selectedRoute: routingResult.selectedRoute,
319
383
  selectedStep: routingResult.selectedStep,
320
- session: routingResult.session,
321
- isRouteComplete: routingResult.isRouteComplete,
384
+ session: updatedSession, // Use updated session with pre-extracted data
385
+ isRouteComplete, // Use updated completion status
322
386
  });
323
387
  return {
324
388
  selectedRoute: routingResult.selectedRoute,
325
389
  selectedStep: stepResult.nextStep, // Use the determined next step
326
390
  responseDirectives: routingResult.responseDirectives,
327
391
  session: stepResult.session,
328
- isRouteComplete: routingResult.isRouteComplete,
392
+ isRouteComplete, // Use updated completion status
393
+ batchSteps,
394
+ batchStoppedReason,
395
+ batchStoppedAtStep,
329
396
  };
330
397
  }
331
398
  catch (error) {
332
399
  throw ResponseGenerationError.fromError(error, 'routing_optimization', params);
333
400
  }
334
401
  }
402
+ /**
403
+ * Check if a route should pre-extract data before determining the initial step
404
+ * @private
405
+ */
406
+ shouldPreExtractData(route) {
407
+ // Pre-extract if route has declared required or optional fields
408
+ if (route.requiredFields && route.requiredFields.length > 0) {
409
+ return true;
410
+ }
411
+ if (route.optionalFields && route.optionalFields.length > 0) {
412
+ return true;
413
+ }
414
+ // Pre-extract if any step in the route collects data
415
+ const steps = route.getAllSteps();
416
+ const hasDataCollectionSteps = steps.some(step => step.collect && step.collect.length > 0);
417
+ return hasDataCollectionSteps;
418
+ }
419
+ /**
420
+ * Pre-extract data from user message when entering a route
421
+ * This allows skipping steps whose data is already provided
422
+ * @private
423
+ */
424
+ async preExtractRouteData(params) {
425
+ const { route, history, context, signal } = params;
426
+ // Build a schema for data extraction based on route's fields
427
+ const extractionSchema = this.agent.getSchema();
428
+ if (!extractionSchema) {
429
+ logger.warn(`[ResponseModal] No schema available for pre-extraction`);
430
+ return {};
431
+ }
432
+ // Get last user message
433
+ const lastMessage = getLastMessageFromHistory(history);
434
+ // Build extraction prompt
435
+ const extractionPrompt = [
436
+ `Extract any relevant information from the user's message that matches the following data fields.`,
437
+ `Only extract information that is explicitly stated or clearly implied.`,
438
+ ``,
439
+ `User's message: "${lastMessage}"`,
440
+ ``,
441
+ `Extract data for these fields if present:`,
442
+ ];
443
+ // Add field descriptions
444
+ if (route.requiredFields) {
445
+ extractionPrompt.push(`Required fields: ${route.requiredFields.join(', ')}`);
446
+ }
447
+ if (route.optionalFields) {
448
+ extractionPrompt.push(`Optional fields: ${route.optionalFields.join(', ')}`);
449
+ }
450
+ extractionPrompt.push(``, `Return ONLY the extracted data as JSON. If no data can be extracted, return an empty object {}.`);
451
+ // Call AI to extract data
452
+ const agentOptions = this.agent.getAgentOptions();
453
+ try {
454
+ const result = await agentOptions.provider.generateMessage({
455
+ prompt: extractionPrompt.join('\n'),
456
+ history,
457
+ context,
458
+ signal,
459
+ parameters: {
460
+ jsonSchema: extractionSchema,
461
+ schemaName: 'data_extraction',
462
+ },
463
+ });
464
+ return result.structured || {};
465
+ }
466
+ catch (error) {
467
+ logger.error(`[ResponseModal] Pre-extraction failed:`, error);
468
+ return {};
469
+ }
470
+ }
335
471
  /**
336
472
  * Unified response generation for non-streaming responses
337
473
  * @private
338
474
  */
339
475
  async generateUnifiedResponse(responseContext) {
340
- const { effectiveContext, session: initialSession, history, selectedRoute, selectedStep, responseDirectives, isRouteComplete } = responseContext;
476
+ const { effectiveContext, session: initialSession, history, selectedRoute, selectedStep, responseDirectives, isRouteComplete, batchSteps, batchStoppedReason, } = responseContext;
341
477
  let session = initialSession;
342
478
  // Get last user message (needed for both route and completion handling)
343
479
  // Convert HistoryItem[] to Event[] for internal processing
@@ -345,35 +481,79 @@ export class ResponseModal {
345
481
  const lastMessageText = getLastMessageFromHistory(historyEvents);
346
482
  let message;
347
483
  let toolCalls = undefined;
484
+ let executedSteps;
485
+ let stoppedReason;
348
486
  if (selectedRoute && !isRouteComplete) {
349
- // Handle normal route processing
350
- const result = await this.processRouteResponse({
351
- selectedRoute,
352
- selectedStep,
353
- responseDirectives,
354
- session,
355
- history,
356
- context: effectiveContext,
357
- lastMessageText,
358
- historyEvents,
359
- signal: responseContext.history ? undefined : undefined, // TODO: Fix signal passing
360
- });
361
- message = result.message;
362
- toolCalls = result.toolCalls;
363
- session = result.session;
487
+ // Check if we have batch steps to execute
488
+ if (batchSteps && batchSteps.length > 0) {
489
+ // BATCH EXECUTION: Execute multiple steps in a single LLM call
490
+ logger.debug(`[ResponseModal] Executing batch of ${batchSteps.length} steps`);
491
+ const batchResult = await this.executeBatchResponse({
492
+ selectedRoute,
493
+ batchSteps,
494
+ responseDirectives,
495
+ session,
496
+ history,
497
+ context: effectiveContext,
498
+ historyEvents,
499
+ });
500
+ message = batchResult.message;
501
+ toolCalls = batchResult.toolCalls;
502
+ session = batchResult.session;
503
+ executedSteps = batchResult.executedSteps;
504
+ stoppedReason = batchStoppedReason;
505
+ }
506
+ else {
507
+ // SINGLE STEP EXECUTION: Fall back to single-step processing
508
+ // This happens when batch determination returns empty (first step needs input)
509
+ const result = await this.processRouteResponse({
510
+ selectedRoute,
511
+ selectedStep,
512
+ responseDirectives,
513
+ session,
514
+ history,
515
+ context: effectiveContext,
516
+ lastMessageText,
517
+ historyEvents,
518
+ signal: undefined,
519
+ });
520
+ message = result.message;
521
+ toolCalls = result.toolCalls;
522
+ session = result.session;
523
+ // Track executed step for single-step execution
524
+ if (selectedStep) {
525
+ executedSteps = [{
526
+ id: selectedStep.id,
527
+ routeId: selectedRoute.id,
528
+ }];
529
+ }
530
+ stoppedReason = batchStoppedReason || 'needs_input';
531
+ }
364
532
  }
365
533
  else if (isRouteComplete && selectedRoute) {
366
534
  // Handle route completion
367
- message = await this.handleRouteCompletion({
368
- selectedRoute,
369
- session,
370
- context: effectiveContext,
371
- lastMessageText,
372
- historyEvents,
373
- });
374
- // Set step to END_ROUTE marker
375
- session = enterStep(session, END_ROUTE_ID, "Route completed");
376
- logger.debug(`[ResponseModal] Route ${selectedRoute.title} completed. Entered END_ROUTE step.`);
535
+ logger.debug(`[ResponseModal] Generating completion message for route: ${selectedRoute.title}`);
536
+ try {
537
+ message = await this.handleRouteCompletion({
538
+ selectedRoute,
539
+ session,
540
+ context: effectiveContext,
541
+ lastMessageText,
542
+ historyEvents,
543
+ signal: undefined,
544
+ });
545
+ // Set step to END_ROUTE marker
546
+ session = enterStep(session, END_ROUTE_ID, "Route completed");
547
+ stoppedReason = 'route_complete';
548
+ logger.debug(`[ResponseModal] Route ${selectedRoute.title} completed. Entered END_ROUTE step.`);
549
+ }
550
+ catch (error) {
551
+ logger.error(`[ResponseModal] Error generating completion message:`, error);
552
+ // Fallback to simple completion message
553
+ message = `Thank you! I've recorded all the information for your ${selectedRoute.title.toLowerCase()}.`;
554
+ session = enterStep(session, END_ROUTE_ID, "Route completed");
555
+ stoppedReason = 'route_complete';
556
+ }
377
557
  }
378
558
  else {
379
559
  // Fallback: No routes defined, generate a simple response
@@ -382,37 +562,268 @@ export class ResponseModal {
382
562
  context: effectiveContext,
383
563
  session,
384
564
  });
565
+ // For fallback responses, set empty executedSteps and no stoppedReason
566
+ // since there's no route/step execution happening
567
+ executedSteps = [];
568
+ stoppedReason = undefined;
385
569
  }
570
+ // Ensure response structure completeness (Requirement 8.1, 8.2, 8.3)
571
+ // - executedSteps: array of steps executed (empty array if none)
572
+ // - stoppedReason: why execution stopped (undefined for fallback)
573
+ // - session.currentStep: reflects final step position
386
574
  return {
387
575
  message,
388
576
  session,
389
577
  toolCalls,
390
578
  isRouteComplete,
579
+ executedSteps: executedSteps || [],
580
+ stoppedReason,
581
+ };
582
+ }
583
+ /**
584
+ * Execute a batch of steps with a single LLM call
585
+ *
586
+ * This method:
587
+ * 1. Executes all prepare hooks for steps in the batch (in order)
588
+ * 2. Builds a combined prompt using BatchPromptBuilder
589
+ * 3. Makes a single LLM call
590
+ * 4. Collects data from the response for all steps
591
+ * 5. Executes all finalize hooks for steps in the batch (in order)
592
+ *
593
+ * @private
594
+ * **Validates: Requirements 1.1, 4.4, 5.1, 5.2**
595
+ */
596
+ async executeBatchResponse(params) {
597
+ const { selectedRoute, batchSteps, history, context, historyEvents, signal } = params;
598
+ let session = params.session;
599
+ logger.debug(`[ResponseModal] Starting batch execution for ${batchSteps.length} steps`);
600
+ // Create hook executor function
601
+ const executeHook = async (hook, hookContext, data, step) => {
602
+ // Find the route for this step
603
+ const route = selectedRoute;
604
+ // Convert StepOptions to Step if needed for executePrepareFinalize
605
+ const stepInstance = step?.id ? route.getStep(step.id) : undefined;
606
+ await this.executePrepareFinalize(hook, hookContext, data, route, stepInstance);
607
+ };
608
+ // PHASE 1: Execute all prepare hooks (Requirement 5.1)
609
+ logger.debug(`[ResponseModal] Executing prepare hooks for batch`);
610
+ const prepareResult = await this.batchExecutor.executePrepareHooks({
611
+ steps: batchSteps,
612
+ context,
613
+ data: session.data,
614
+ executeHook,
615
+ });
616
+ if (!prepareResult.success) {
617
+ // Prepare hook failed - return error response
618
+ logger.error(`[ResponseModal] Prepare hook failed:`, prepareResult.error);
619
+ throw new ResponseGenerationError(`Prepare hook failed: ${prepareResult.error?.message}`, {
620
+ phase: 'prepare_hooks',
621
+ context: {
622
+ stepId: prepareResult.error?.stepId,
623
+ executedSteps: prepareResult.executedSteps,
624
+ }
625
+ });
626
+ }
627
+ // PHASE 2: Build combined prompt using BatchPromptBuilder (Requirement 4.4)
628
+ logger.debug(`[ResponseModal] Building batch prompt`);
629
+ const batchPromptResult = await this.batchPromptBuilder.buildBatchPrompt({
630
+ steps: batchSteps,
631
+ route: selectedRoute,
632
+ history: historyEvents,
633
+ context,
634
+ session,
635
+ agentOptions: this.agent.getAgentOptions(),
636
+ });
637
+ logger.debug(`[ResponseModal] Batch prompt built with ${batchPromptResult.stepCount} steps, collecting: ${batchPromptResult.collectFields.join(', ')}`);
638
+ // Build response schema for batch (includes all collect fields)
639
+ const responseSchema = this.buildBatchResponseSchema(batchPromptResult.collectFields);
640
+ // Collect available tools for AI (from all steps in batch)
641
+ const availableTools = this.collectBatchAvailableTools(selectedRoute, batchSteps);
642
+ // PHASE 3: Make single LLM call (Requirement 4.4)
643
+ logger.debug(`[ResponseModal] Making LLM call for batch`);
644
+ const agentOptions = this.agent.getAgentOptions();
645
+ const result = await agentOptions.provider.generateMessage({
646
+ prompt: batchPromptResult.prompt,
647
+ history: historyEvents,
648
+ context,
649
+ tools: availableTools,
650
+ signal,
651
+ parameters: responseSchema ? { jsonSchema: responseSchema, schemaName: "batch_response" } : undefined,
652
+ });
653
+ let message = result.structured?.message || result.message;
654
+ let toolCalls = result.structured?.toolCalls;
655
+ logger.debug(`[ResponseModal] LLM response received for batch`);
656
+ // Execute tools if any
657
+ if (toolCalls && toolCalls.length > 0) {
658
+ const toolResult = await this.executeUnifiedToolLoop({
659
+ toolCalls,
660
+ context,
661
+ session,
662
+ history,
663
+ selectedRoute,
664
+ responsePrompt: batchPromptResult.prompt,
665
+ availableTools,
666
+ responseSchema,
667
+ signal,
668
+ });
669
+ session = toolResult.session;
670
+ toolCalls = toolResult.finalToolCalls;
671
+ if (toolResult.finalMessage) {
672
+ message = toolResult.finalMessage;
673
+ }
674
+ }
675
+ // PHASE 4: Collect data from response for all steps (Requirement 6.1, 6.2, 6.3)
676
+ logger.debug(`[ResponseModal] Collecting batch data`);
677
+ const collectResult = this.batchExecutor.collectBatchData({
678
+ steps: batchSteps,
679
+ llmResponse: result.structured || {},
680
+ session,
681
+ schema: this.agent.getSchema(),
682
+ });
683
+ session = collectResult.session;
684
+ if (collectResult.collectedData && Object.keys(collectResult.collectedData).length > 0) {
685
+ // Update agent's collected data
686
+ await this.agent.updateCollectedData(collectResult.collectedData);
687
+ logger.debug(`[ResponseModal] Batch collected data:`, collectResult.collectedData);
688
+ }
689
+ if (collectResult.validationErrors && collectResult.validationErrors.length > 0) {
690
+ logger.warn(`[ResponseModal] Batch data validation errors:`, collectResult.validationErrors);
691
+ }
692
+ // Update session to final step position
693
+ const lastStep = batchSteps[batchSteps.length - 1];
694
+ if (lastStep?.id) {
695
+ session = enterStep(session, lastStep.id, lastStep.description);
696
+ logger.debug(`[ResponseModal] Updated session to final batch step: ${lastStep.id}`);
697
+ }
698
+ // PHASE 5: Execute all finalize hooks (Requirement 5.2)
699
+ logger.debug(`[ResponseModal] Executing finalize hooks for batch`);
700
+ const finalizeResult = await this.batchExecutor.executeFinalizeHooks({
701
+ steps: batchSteps,
702
+ context,
703
+ data: session.data,
704
+ executeHook,
705
+ });
706
+ if (finalizeResult.errors && finalizeResult.errors.length > 0) {
707
+ // Log finalize errors but don't fail (Requirement 5.5)
708
+ logger.warn(`[ResponseModal] Some finalize hooks failed:`, finalizeResult.errors);
709
+ }
710
+ // Build executed steps list
711
+ const executedSteps = batchSteps
712
+ .filter(step => step.id)
713
+ .map(step => ({
714
+ id: step.id,
715
+ routeId: selectedRoute.id,
716
+ }));
717
+ logger.debug(`[ResponseModal] Batch execution complete. Executed ${executedSteps.length} steps`);
718
+ return {
719
+ message,
720
+ toolCalls,
721
+ session,
722
+ executedSteps,
723
+ };
724
+ }
725
+ /**
726
+ * Build response schema for batch execution
727
+ * @private
728
+ */
729
+ buildBatchResponseSchema(collectFields) {
730
+ const properties = {
731
+ message: {
732
+ type: "string",
733
+ description: "Your response to the user",
734
+ },
735
+ };
736
+ // Add collect fields to schema
737
+ for (const field of collectFields) {
738
+ properties[field] = {
739
+ type: "string",
740
+ description: `Collected value for ${field}`,
741
+ };
742
+ }
743
+ return {
744
+ type: "object",
745
+ properties,
746
+ required: ["message"],
747
+ additionalProperties: true,
391
748
  };
392
749
  }
750
+ /**
751
+ * Collect available tools from all steps in the batch
752
+ * @private
753
+ */
754
+ collectBatchAvailableTools(route, batchSteps) {
755
+ const availableTools = new Map();
756
+ // Add agent-level tools
757
+ this.agent.getTools().forEach((tool) => {
758
+ availableTools.set(tool.id, tool);
759
+ });
760
+ // Add route-level tools
761
+ route.getTools().forEach((tool) => {
762
+ availableTools.set(tool.id, tool);
763
+ });
764
+ // Add step-level tools from all batch steps
765
+ for (const step of batchSteps) {
766
+ if (step.tools) {
767
+ for (const toolRef of step.tools) {
768
+ if (typeof toolRef === "string") {
769
+ // Reference to registered tool - already in availableTools
770
+ }
771
+ else if (typeof toolRef === 'object' && 'id' in toolRef && toolRef.id) {
772
+ // Inline tool definition
773
+ availableTools.set(toolRef.id, toolRef);
774
+ }
775
+ }
776
+ }
777
+ }
778
+ // Convert to the format expected by AI providers
779
+ return Array.from(availableTools.values()).map((tool) => ({
780
+ id: tool.id,
781
+ name: tool.name || tool.id,
782
+ description: tool.description,
783
+ parameters: tool.parameters,
784
+ }));
785
+ }
393
786
  /**
394
787
  * Unified streaming response generation
395
788
  * @private
396
789
  */
397
790
  async *generateUnifiedStreamingResponse(responseContext) {
398
- const { effectiveContext, session: initialSession, history, selectedRoute, selectedStep, responseDirectives, isRouteComplete } = responseContext;
791
+ const { effectiveContext, session: initialSession, history, selectedRoute, selectedStep, responseDirectives, isRouteComplete, batchSteps, batchStoppedReason, } = responseContext;
399
792
  const session = initialSession;
400
793
  // Get last user message (needed for both route and completion handling)
401
794
  // Convert HistoryItem[] to Event[] for internal processing
402
795
  const historyEvents = historyToEvents(history);
403
796
  const lastMessageText = getLastMessageFromHistory(historyEvents);
404
797
  if (selectedRoute && !isRouteComplete) {
405
- // Handle normal route processing with streaming
406
- yield* this.processRouteStreamingResponse({
407
- selectedRoute,
408
- selectedStep,
409
- responseDirectives,
410
- session,
411
- history,
412
- context: effectiveContext,
413
- lastMessageText,
414
- historyEvents,
415
- });
798
+ // Check if we have batch steps to execute
799
+ if (batchSteps && batchSteps.length > 0) {
800
+ // BATCH EXECUTION: Execute multiple steps with streaming
801
+ // Note: For streaming, we still use batch execution but stream the response
802
+ logger.debug(`[ResponseModal] Streaming batch execution for ${batchSteps.length} steps`);
803
+ yield* this.streamBatchResponse({
804
+ selectedRoute,
805
+ batchSteps,
806
+ responseDirectives,
807
+ session,
808
+ history,
809
+ context: effectiveContext,
810
+ historyEvents,
811
+ batchStoppedReason,
812
+ });
813
+ }
814
+ else {
815
+ // SINGLE STEP EXECUTION: Fall back to single-step streaming
816
+ yield* this.processRouteStreamingResponse({
817
+ selectedRoute,
818
+ selectedStep,
819
+ responseDirectives,
820
+ session,
821
+ history,
822
+ context: effectiveContext,
823
+ lastMessageText,
824
+ historyEvents,
825
+ });
826
+ }
416
827
  }
417
828
  else if (isRouteComplete && selectedRoute) {
418
829
  // Handle route completion streaming
@@ -433,6 +844,114 @@ export class ResponseModal {
433
844
  });
434
845
  }
435
846
  }
847
+ /**
848
+ * Stream a batch response with multiple steps
849
+ *
850
+ * Similar to executeBatchResponse but streams the LLM response.
851
+ *
852
+ * @private
853
+ */
854
+ async *streamBatchResponse(params) {
855
+ const { selectedRoute, batchSteps, context, historyEvents, batchStoppedReason, signal } = params;
856
+ let session = params.session;
857
+ // Create hook executor function
858
+ const executeHook = async (hook, hookContext, data, step) => {
859
+ const route = selectedRoute;
860
+ const stepInstance = step?.id ? route.getStep(step.id) : undefined;
861
+ await this.executePrepareFinalize(hook, hookContext, data, route, stepInstance);
862
+ };
863
+ // PHASE 1: Execute all prepare hooks
864
+ const prepareResult = await this.batchExecutor.executePrepareHooks({
865
+ steps: batchSteps,
866
+ context,
867
+ data: session.data,
868
+ executeHook,
869
+ });
870
+ if (!prepareResult.success) {
871
+ // Yield error chunk
872
+ yield {
873
+ delta: "",
874
+ accumulated: "",
875
+ done: true,
876
+ session,
877
+ error: new ResponseGenerationError(`Prepare hook failed: ${prepareResult.error?.message}`, { phase: 'prepare_hooks' }),
878
+ };
879
+ return;
880
+ }
881
+ // PHASE 2: Build combined prompt
882
+ const batchPromptResult = await this.batchPromptBuilder.buildBatchPrompt({
883
+ steps: batchSteps,
884
+ route: selectedRoute,
885
+ history: historyEvents,
886
+ context,
887
+ session,
888
+ agentOptions: this.agent.getAgentOptions(),
889
+ });
890
+ const responseSchema = this.buildBatchResponseSchema(batchPromptResult.collectFields);
891
+ const availableTools = this.collectBatchAvailableTools(selectedRoute, batchSteps);
892
+ // PHASE 3: Stream LLM response
893
+ const agentOptions = this.agent.getAgentOptions();
894
+ const stream = agentOptions.provider.generateMessageStream({
895
+ prompt: batchPromptResult.prompt,
896
+ history: historyEvents,
897
+ context,
898
+ tools: availableTools,
899
+ signal,
900
+ parameters: responseSchema ? { jsonSchema: responseSchema, schemaName: "batch_stream_response" } : undefined,
901
+ });
902
+ // Build executed steps list
903
+ const executedSteps = batchSteps
904
+ .filter(step => step.id)
905
+ .map(step => ({
906
+ id: step.id,
907
+ routeId: selectedRoute.id,
908
+ }));
909
+ // Stream chunks
910
+ for await (const chunk of stream) {
911
+ // On final chunk, collect data and execute finalize hooks
912
+ if (chunk.done) {
913
+ // Collect data from response
914
+ if (chunk.structured) {
915
+ const collectResult = this.batchExecutor.collectBatchData({
916
+ steps: batchSteps,
917
+ llmResponse: chunk.structured,
918
+ session,
919
+ schema: this.agent.getSchema(),
920
+ });
921
+ session = collectResult.session;
922
+ if (collectResult.collectedData && Object.keys(collectResult.collectedData).length > 0) {
923
+ await this.agent.updateCollectedData(collectResult.collectedData);
924
+ }
925
+ }
926
+ // Update session to final step position
927
+ const lastStep = batchSteps[batchSteps.length - 1];
928
+ if (lastStep?.id) {
929
+ session = enterStep(session, lastStep.id, lastStep.description);
930
+ }
931
+ // Execute finalize hooks
932
+ await this.batchExecutor.executeFinalizeHooks({
933
+ steps: batchSteps,
934
+ context,
935
+ data: session.data,
936
+ executeHook,
937
+ });
938
+ // Finalize session
939
+ await this.finalizeSession(session, context);
940
+ }
941
+ yield {
942
+ delta: chunk.delta,
943
+ accumulated: chunk.accumulated,
944
+ done: chunk.done,
945
+ session,
946
+ toolCalls: chunk.structured?.toolCalls,
947
+ isRouteComplete: false,
948
+ executedSteps: chunk.done ? executedSteps : undefined,
949
+ stoppedReason: chunk.done ? batchStoppedReason : undefined,
950
+ metadata: chunk.metadata,
951
+ structured: chunk.structured,
952
+ };
953
+ }
954
+ }
436
955
  /**
437
956
  * Execute prepare function for current step if available
438
957
  * @private
@@ -478,12 +997,20 @@ export class ResponseModal {
478
997
  nextStep = selectedStep;
479
998
  }
480
999
  else {
481
- // New route or no step selected - get initial step or first valid step
1000
+ // Determine current step from session if we're already in this route
1001
+ const isInSameRoute = session.currentRoute?.id === selectedRoute.id;
1002
+ const currentStep = isInSameRoute && session.currentStep
1003
+ ? selectedRoute.getStep(session.currentStep.id)
1004
+ : undefined;
1005
+ logger.debug(`[ResponseModal] Step determination: route match=${isInSameRoute}, currentRoute=${session.currentRoute?.id}, selectedRoute=${selectedRoute.id}, currentStep=${currentStep?.id || 'none'}`);
1006
+ // Get candidate steps based on current position in the route
482
1007
  const routingEngine = this.agent.getRoutingEngine();
483
- const candidates = routingEngine.getCandidateSteps(selectedRoute, undefined, session.data || {});
1008
+ const candidates = await routingEngine.getCandidateStepsWithConditions(selectedRoute, currentStep, // Pass current step instead of undefined to maintain progression
1009
+ createTemplateContext({ data: session.data, session, context }));
1010
+ logger.debug(`[ResponseModal] Found ${candidates.length} candidate steps${currentStep ? ' from current step ' + currentStep.id : ' (new route entry)'}`);
484
1011
  if (candidates.length > 0) {
485
1012
  nextStep = candidates[0].step;
486
- logger.debug(`[ResponseModal] Using first valid step: ${nextStep.id} for new route`);
1013
+ logger.debug(`[ResponseModal] Using first valid step: ${nextStep.id}${currentStep ? ' (progressing from ' + currentStep.id + ')' : ' for new route'}`);
487
1014
  }
488
1015
  else {
489
1016
  // Fallback to initial step even if it should be skipped
@@ -526,6 +1053,14 @@ export class ResponseModal {
526
1053
  });
527
1054
  let message = result.structured?.message || result.message;
528
1055
  let toolCalls = result.structured?.toolCalls;
1056
+ // Debug: Log initial AI response
1057
+ logger.debug(`[ResponseModal] Initial AI response:`, {
1058
+ hasMessage: !!message,
1059
+ messageLength: message?.length || 0,
1060
+ hasToolCalls: !!toolCalls,
1061
+ toolCallsCount: toolCalls?.length || 0,
1062
+ toolNames: toolCalls?.map(tc => tc.toolName) || [],
1063
+ });
529
1064
  // Execute tools with unified loop handling
530
1065
  const toolResult = await this.executeUnifiedToolLoop({
531
1066
  toolCalls,
@@ -560,11 +1095,17 @@ export class ResponseModal {
560
1095
  nextStep = selectedStep;
561
1096
  }
562
1097
  else {
1098
+ // Determine current step from session if we're already in this route
1099
+ const currentStep = session.currentRoute?.id === selectedRoute.id && session.currentStep
1100
+ ? selectedRoute.getStep(session.currentStep.id)
1101
+ : undefined;
1102
+ // Get candidate steps based on current position in the route
563
1103
  const routingEngine = this.agent.getRoutingEngine();
564
- const candidates = routingEngine.getCandidateSteps(selectedRoute, undefined, session.data || {});
1104
+ const candidates = await routingEngine.getCandidateStepsWithConditions(selectedRoute, currentStep, // Pass current step instead of undefined to maintain progression
1105
+ createTemplateContext({ data: session.data, session, context }));
565
1106
  if (candidates.length > 0) {
566
1107
  nextStep = candidates[0].step;
567
- logger.debug(`[ResponseModal] Using first valid step: ${nextStep.id} for new route`);
1108
+ logger.debug(`[ResponseModal] Using first valid step: ${nextStep.id}${currentStep ? ' (progressing from ' + currentStep.id + ')' : ' for new route'}`);
568
1109
  }
569
1110
  else {
570
1111
  nextStep = selectedRoute.initialStep;
@@ -637,6 +1178,10 @@ export class ResponseModal {
637
1178
  if (chunk.done) {
638
1179
  await this.finalizeSession(session, context);
639
1180
  }
1181
+ // Response structure completeness (Requirement 8.1, 8.2, 8.3)
1182
+ // - executedSteps: single step executed in this response
1183
+ // - stoppedReason: 'needs_input' for single-step execution (waiting for user input)
1184
+ // - session.currentStep: reflects the executed step
640
1185
  yield {
641
1186
  delta: chunk.delta,
642
1187
  accumulated: chunk.accumulated,
@@ -644,6 +1189,8 @@ export class ResponseModal {
644
1189
  session,
645
1190
  toolCalls,
646
1191
  isRouteComplete: false,
1192
+ executedSteps: chunk.done ? [{ id: nextStep.id, routeId: selectedRoute.id }] : undefined,
1193
+ stoppedReason: chunk.done ? 'needs_input' : undefined,
647
1194
  metadata: chunk.metadata,
648
1195
  structured: chunk.structured,
649
1196
  };
@@ -662,7 +1209,7 @@ export class ResponseModal {
662
1209
  const historyEvents = historyToEvents(history);
663
1210
  // Execute initial dynamic tool calls
664
1211
  if (toolCalls && toolCalls.length > 0) {
665
- logger.debug(`[ResponseModal] Executing ${toolCalls.length} dynamic tool calls`);
1212
+ logger.debug(`[ResponseModal] Executing ${toolCalls.length} dynamic tool calls:`, toolCalls.map(tc => tc.toolName));
666
1213
  for (const toolCall of toolCalls) {
667
1214
  const tool = this.findAvailableTool(toolCall.toolName, selectedRoute);
668
1215
  if (!tool) {
@@ -732,7 +1279,7 @@ export class ResponseModal {
732
1279
  let finalMessage;
733
1280
  while (hasToolCalls && toolLoopCount < MAX_TOOL_LOOPS) {
734
1281
  toolLoopCount++;
735
- logger.debug(`[ResponseModal] Starting tool loop ${toolLoopCount}/${MAX_TOOL_LOOPS}`);
1282
+ logger.debug(`[ResponseModal] Starting tool loop ${toolLoopCount}/${MAX_TOOL_LOOPS} with ${toolCalls?.length || 0} tool calls`);
736
1283
  // Create tool result events with proper Event format structure
737
1284
  const toolResultEvents = [];
738
1285
  for (const toolCall of toolCalls || []) {
@@ -761,12 +1308,19 @@ export class ResponseModal {
761
1308
  // Create updated history with tool results (combine Event arrays)
762
1309
  const updatedHistoryEvents = [...historyEvents, ...toolResultEvents];
763
1310
  // Make follow-up AI call to see if more tools are needed
1311
+ // After first iteration, don't provide tools to force a text response
764
1312
  const agentOptions = this.agent.getAgentOptions();
1313
+ const shouldProvideTools = toolLoopCount === 1;
1314
+ logger.debug(`[ResponseModal] Making follow-up AI call (loop ${toolLoopCount}):`, {
1315
+ providingTools: shouldProvideTools,
1316
+ toolsCount: shouldProvideTools ? availableTools.length : 0,
1317
+ addingTextInstruction: toolLoopCount > 1,
1318
+ });
765
1319
  const followUpResult = await agentOptions.provider.generateMessage({
766
- prompt: responsePrompt,
1320
+ prompt: responsePrompt + (toolLoopCount > 1 ? "\n\nProvide a text response to the user based on the tool results." : ""),
767
1321
  history: updatedHistoryEvents, // Use Event[] for AI provider
768
1322
  context,
769
- tools: availableTools,
1323
+ tools: shouldProvideTools ? availableTools : [], // Only provide tools on first iteration
770
1324
  parameters: responseSchema ? {
771
1325
  jsonSchema: responseSchema,
772
1326
  schemaName: "tool_followup",
@@ -776,6 +1330,13 @@ export class ResponseModal {
776
1330
  // Check if follow-up call has more tool calls
777
1331
  const followUpToolCalls = followUpResult.structured?.toolCalls;
778
1332
  hasToolCalls = followUpToolCalls && followUpToolCalls.length > 0;
1333
+ logger.debug(`[ResponseModal] Follow-up AI response (loop ${toolLoopCount}):`, {
1334
+ hasMessage: !!followUpResult.message,
1335
+ messageLength: followUpResult.message?.length || 0,
1336
+ hasToolCalls,
1337
+ toolCallsCount: followUpToolCalls?.length || 0,
1338
+ toolNames: followUpToolCalls?.map(tc => tc.toolName) || [],
1339
+ });
779
1340
  if (hasToolCalls) {
780
1341
  logger.debug(`[ResponseModal] Follow-up call produced ${followUpToolCalls.length} additional tool calls`);
781
1342
  // Execute the follow-up tool calls
@@ -849,6 +1410,12 @@ export class ResponseModal {
849
1410
  if (toolLoopCount >= MAX_TOOL_LOOPS) {
850
1411
  logger.warn(`[ResponseModal] Tool loop limit reached (${MAX_TOOL_LOOPS}), stopping`);
851
1412
  }
1413
+ logger.debug(`[ResponseModal] Tool loop completed:`, {
1414
+ totalIterations: toolLoopCount,
1415
+ hasFinalMessage: !!finalMessage,
1416
+ finalMessageLength: finalMessage?.length || 0,
1417
+ finalToolCallsCount: toolCalls?.length || 0,
1418
+ });
852
1419
  return {
853
1420
  session,
854
1421
  finalToolCalls: toolCalls,
@@ -870,14 +1437,29 @@ export class ResponseModal {
870
1437
  const { result, selectedRoute, nextStep, session } = params;
871
1438
  let updatedSession = session;
872
1439
  // Extract collected data from final response (only for route-based interactions)
873
- if (selectedRoute && result.structured && nextStep?.collect) {
1440
+ if (selectedRoute && result.structured) {
874
1441
  try {
875
1442
  const collectedData = {};
876
1443
  // AgentStructuredResponse extends Record<string, unknown>, so we can safely access properties
877
1444
  const structuredData = result.structured;
878
- for (const field of nextStep.collect) {
1445
+ // Collect ALL route fields (required + optional) from structured response
1446
+ const allRouteFields = new Set();
1447
+ // Add route required fields
1448
+ if (selectedRoute.requiredFields) {
1449
+ selectedRoute.requiredFields.forEach(field => allRouteFields.add(String(field)));
1450
+ }
1451
+ // Add route optional fields
1452
+ if (selectedRoute.optionalFields) {
1453
+ selectedRoute.optionalFields.forEach(field => allRouteFields.add(String(field)));
1454
+ }
1455
+ // Also include current step's collect fields (in case they're not in route fields)
1456
+ if (nextStep?.collect) {
1457
+ nextStep.collect.forEach(field => allRouteFields.add(String(field)));
1458
+ }
1459
+ // Extract all available fields from structured response
1460
+ for (const field of allRouteFields) {
879
1461
  const fieldKey = String(field);
880
- if (fieldKey in structuredData) {
1462
+ if (fieldKey in structuredData && structuredData[fieldKey] !== undefined && structuredData[fieldKey] !== null) {
881
1463
  collectedData[fieldKey] = structuredData[fieldKey];
882
1464
  }
883
1465
  }
@@ -940,34 +1522,60 @@ export class ResponseModal {
940
1522
  requires: endStepSpec.requires,
941
1523
  prompt: endStepSpec.prompt || "Summarize what was accomplished and confirm completion based on the conversation history and collected data",
942
1524
  });
943
- // Build response schema for completion
944
- const responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, completionStep, this.agent.getSchema());
945
- const templateContext = { context, session, history: historyEvents }; // Use Event[] for template context
946
- // Build completion response prompt
1525
+ // Build response schema for completion (message only, no data collection)
1526
+ const completionSchema = {
1527
+ type: "object",
1528
+ properties: {
1529
+ message: {
1530
+ type: "string",
1531
+ description: "Completion message confirming what was accomplished",
1532
+ },
1533
+ },
1534
+ required: ["message"],
1535
+ additionalProperties: false,
1536
+ };
1537
+ const templateContext = createTemplateContext({ context, session, history: historyEvents });
1538
+ // Build completion response prompt using ResponseEngine
1539
+ // Filter out conditional guidelines - only include always-active ones
1540
+ const alwaysActiveGuidelines = [
1541
+ ...this.agent.getGuidelines().filter(g => !g.condition),
1542
+ ...selectedRoute.getGuidelines().filter(g => !g.condition),
1543
+ ];
1544
+ let completitionPrompt = "Summarize what was accomplished and confirm completion";
1545
+ if (endStepSpec.prompt) {
1546
+ completitionPrompt = await render(endStepSpec.prompt, templateContext);
1547
+ }
947
1548
  const completionPrompt = await this.responseEngine.buildResponsePrompt({
948
1549
  route: selectedRoute,
949
1550
  currentStep: completionStep,
950
1551
  rules: selectedRoute.getRules(),
951
1552
  prohibitions: selectedRoute.getProhibitions(),
952
- directives: undefined, // No directives for completion
953
- history: historyEvents, // Use Event[] for buildResponsePrompt
954
- lastMessage: lastMessageText, // Use string for buildResponsePrompt
1553
+ directives: [
1554
+ `Task completed: ${selectedRoute.title}`,
1555
+ `Collected data: ${JSON.stringify(session.data, null, 2)}`,
1556
+ "Do NOT ask for more information - the task is complete",
1557
+ completitionPrompt,
1558
+ ],
1559
+ history: historyEvents,
1560
+ lastMessage: lastMessageText,
955
1561
  agentOptions: this.agent.getAgentOptions(),
956
- combinedGuidelines: [...this.agent.getGuidelines(), ...selectedRoute.getGuidelines()],
1562
+ combinedGuidelines: alwaysActiveGuidelines, // Only non-conditional guidelines
957
1563
  combinedTerms: this.mergeTerms(this.agent.getTerms(), selectedRoute.getTerms()),
958
1564
  context,
959
1565
  session,
960
- agentSchema: this.agent.getSchema(),
1566
+ agentSchema: undefined, // No data collection schema for completion
961
1567
  });
962
1568
  // Generate completion message using AI provider
963
1569
  const agentOptions = this.agent.getAgentOptions();
1570
+ logger.debug(`[ResponseModal] Calling AI provider for completion message...`);
964
1571
  const completionResult = await agentOptions.provider.generateMessage({
965
1572
  prompt: completionPrompt,
966
- history: historyEvents, // Use Event[] for AI provider
1573
+ history: historyEvents,
967
1574
  context,
968
1575
  signal,
969
- parameters: { jsonSchema: responseSchema, schemaName: "completion_message" },
1576
+ parameters: { jsonSchema: completionSchema, schemaName: "completion_message" },
970
1577
  });
1578
+ logger.debug(`[ResponseModal] AI provider returned completion result`);
971
1579
  const message = completionResult.structured?.message || completionResult.message;
972
1580
  logger.debug(`[ResponseModal] Generated completion message for route: ${selectedRoute.title}`);
973
1581
  // Check for onComplete transition
@@ -1010,7 +1618,7 @@ export class ResponseModal {
1010
1618
  });
1011
1619
  // Build response schema for completion
1012
1620
  const responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, completionStep, this.agent.getSchema());
1013
- const templateContext = { context, session, history: historyEvents }; // Use Event[] for template context
1621
+ const templateContext = createTemplateContext({ context, session, history: historyEvents }); // Use Event[] for template context
1014
1622
  // Build completion response prompt
1015
1623
  const completionPrompt = await this.responseEngine.buildResponsePrompt({
1016
1624
  route: selectedRoute,
@@ -1068,6 +1676,10 @@ export class ResponseModal {
1068
1676
  if (chunk.done) {
1069
1677
  await this.finalizeSession(session, context);
1070
1678
  }
1679
+ // Response structure completeness (Requirement 8.1, 8.2, 8.3)
1680
+ // - executedSteps: empty for route completion (no new steps executed)
1681
+ // - stoppedReason: 'route_complete' for completed routes
1682
+ // - session.currentStep: set to END_ROUTE
1071
1683
  yield {
1072
1684
  delta: chunk.delta,
1073
1685
  accumulated: chunk.accumulated,
@@ -1075,6 +1687,8 @@ export class ResponseModal {
1075
1687
  session,
1076
1688
  toolCalls: undefined,
1077
1689
  isRouteComplete: true,
1690
+ executedSteps: chunk.done ? [] : undefined,
1691
+ stoppedReason: chunk.done ? 'route_complete' : undefined,
1078
1692
  metadata: chunk.metadata,
1079
1693
  structured: chunk.structured,
1080
1694
  };
@@ -1149,6 +1763,10 @@ export class ResponseModal {
1149
1763
  if (chunk.done) {
1150
1764
  await this.finalizeSession(session, context);
1151
1765
  }
1766
+ // Response structure completeness (Requirement 8.1, 8.2, 8.3)
1767
+ // - executedSteps: empty for fallback (no route/step execution)
1768
+ // - stoppedReason: undefined for fallback (no route context)
1769
+ // - session.currentStep: unchanged (no step progression)
1152
1770
  yield {
1153
1771
  delta: chunk.delta,
1154
1772
  accumulated: chunk.accumulated,
@@ -1156,6 +1774,8 @@ export class ResponseModal {
1156
1774
  session,
1157
1775
  toolCalls: undefined,
1158
1776
  isRouteComplete: false,
1777
+ executedSteps: chunk.done ? [] : undefined,
1778
+ stoppedReason: undefined,
1159
1779
  metadata: chunk.metadata,
1160
1780
  structured: chunk.structured,
1161
1781
  };