@falai/agent 2.6.1 → 3.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 (611) hide show
  1. package/README.md +2 -2
  2. package/dist/adapters/MemoryAdapter.d.ts +1 -1
  3. package/dist/adapters/MemoryAdapter.d.ts.map +1 -1
  4. package/dist/adapters/MemoryAdapter.js +32 -36
  5. package/dist/adapters/MemoryAdapter.js.map +1 -1
  6. package/dist/adapters/MongoAdapter.d.ts +1 -1
  7. package/dist/adapters/MongoAdapter.d.ts.map +1 -1
  8. package/dist/adapters/MongoAdapter.js +2 -2
  9. package/dist/adapters/MongoAdapter.js.map +1 -1
  10. package/dist/adapters/OpenSearchAdapter.d.ts +1 -1
  11. package/dist/adapters/OpenSearchAdapter.d.ts.map +1 -1
  12. package/dist/adapters/OpenSearchAdapter.js +3 -3
  13. package/dist/adapters/OpenSearchAdapter.js.map +1 -1
  14. package/dist/adapters/PostgreSQLAdapter.d.ts +1 -1
  15. package/dist/adapters/PostgreSQLAdapter.d.ts.map +1 -1
  16. package/dist/adapters/PostgreSQLAdapter.js +18 -13
  17. package/dist/adapters/PostgreSQLAdapter.js.map +1 -1
  18. package/dist/adapters/PrismaAdapter.d.ts +1 -1
  19. package/dist/adapters/PrismaAdapter.d.ts.map +1 -1
  20. package/dist/adapters/PrismaAdapter.js +3 -3
  21. package/dist/adapters/PrismaAdapter.js.map +1 -1
  22. package/dist/adapters/RedisAdapter.d.ts +2 -1
  23. package/dist/adapters/RedisAdapter.d.ts.map +1 -1
  24. package/dist/adapters/RedisAdapter.js +77 -27
  25. package/dist/adapters/RedisAdapter.js.map +1 -1
  26. package/dist/adapters/SQLiteAdapter.d.ts +1 -1
  27. package/dist/adapters/SQLiteAdapter.d.ts.map +1 -1
  28. package/dist/adapters/SQLiteAdapter.js +9 -31
  29. package/dist/adapters/SQLiteAdapter.js.map +1 -1
  30. package/dist/adapters/index.d.ts +13 -13
  31. package/dist/adapters/index.d.ts.map +1 -1
  32. package/dist/adapters/index.js +7 -7
  33. package/dist/adapters/index.js.map +1 -1
  34. package/dist/adapters/sessionRow.d.ts +22 -0
  35. package/dist/adapters/sessionRow.d.ts.map +1 -0
  36. package/dist/adapters/sessionRow.js +48 -0
  37. package/dist/adapters/sessionRow.js.map +1 -0
  38. package/dist/cjs/adapters/MemoryAdapter.d.ts +1 -1
  39. package/dist/cjs/adapters/MemoryAdapter.d.ts.map +1 -1
  40. package/dist/cjs/adapters/MemoryAdapter.js +39 -43
  41. package/dist/cjs/adapters/MemoryAdapter.js.map +1 -1
  42. package/dist/cjs/adapters/MongoAdapter.d.ts +1 -1
  43. package/dist/cjs/adapters/MongoAdapter.d.ts.map +1 -1
  44. package/dist/cjs/adapters/MongoAdapter.js +4 -4
  45. package/dist/cjs/adapters/MongoAdapter.js.map +1 -1
  46. package/dist/cjs/adapters/OpenSearchAdapter.d.ts +1 -1
  47. package/dist/cjs/adapters/OpenSearchAdapter.d.ts.map +1 -1
  48. package/dist/cjs/adapters/OpenSearchAdapter.js +6 -6
  49. package/dist/cjs/adapters/OpenSearchAdapter.js.map +1 -1
  50. package/dist/cjs/adapters/PostgreSQLAdapter.d.ts +1 -1
  51. package/dist/cjs/adapters/PostgreSQLAdapter.d.ts.map +1 -1
  52. package/dist/cjs/adapters/PostgreSQLAdapter.js +20 -15
  53. package/dist/cjs/adapters/PostgreSQLAdapter.js.map +1 -1
  54. package/dist/cjs/adapters/PrismaAdapter.d.ts +1 -1
  55. package/dist/cjs/adapters/PrismaAdapter.d.ts.map +1 -1
  56. package/dist/cjs/adapters/PrismaAdapter.js +7 -7
  57. package/dist/cjs/adapters/PrismaAdapter.js.map +1 -1
  58. package/dist/cjs/adapters/RedisAdapter.d.ts +2 -1
  59. package/dist/cjs/adapters/RedisAdapter.d.ts.map +1 -1
  60. package/dist/cjs/adapters/RedisAdapter.js +81 -31
  61. package/dist/cjs/adapters/RedisAdapter.js.map +1 -1
  62. package/dist/cjs/adapters/SQLiteAdapter.d.ts +1 -1
  63. package/dist/cjs/adapters/SQLiteAdapter.d.ts.map +1 -1
  64. package/dist/cjs/adapters/SQLiteAdapter.js +11 -33
  65. package/dist/cjs/adapters/SQLiteAdapter.js.map +1 -1
  66. package/dist/cjs/adapters/index.d.ts +13 -13
  67. package/dist/cjs/adapters/index.d.ts.map +1 -1
  68. package/dist/cjs/adapters/index.js +14 -14
  69. package/dist/cjs/adapters/index.js.map +1 -1
  70. package/dist/cjs/adapters/sessionRow.d.ts +22 -0
  71. package/dist/cjs/adapters/sessionRow.d.ts.map +1 -0
  72. package/dist/cjs/adapters/sessionRow.js +52 -0
  73. package/dist/cjs/adapters/sessionRow.js.map +1 -0
  74. package/dist/cjs/core/Agent.d.ts +19 -11
  75. package/dist/cjs/core/Agent.d.ts.map +1 -1
  76. package/dist/cjs/core/Agent.js +102 -64
  77. package/dist/cjs/core/Agent.js.map +1 -1
  78. package/dist/cjs/core/AutoChainExecutor.d.ts +12 -22
  79. package/dist/cjs/core/AutoChainExecutor.d.ts.map +1 -1
  80. package/dist/cjs/core/AutoChainExecutor.js +46 -49
  81. package/dist/cjs/core/AutoChainExecutor.js.map +1 -1
  82. package/dist/cjs/core/BranchEvaluator.d.ts +4 -4
  83. package/dist/cjs/core/BranchEvaluator.d.ts.map +1 -1
  84. package/dist/cjs/core/BranchEvaluator.js +6 -6
  85. package/dist/cjs/core/BranchEvaluator.js.map +1 -1
  86. package/dist/cjs/core/CompactionEngine.d.ts +16 -3
  87. package/dist/cjs/core/CompactionEngine.d.ts.map +1 -1
  88. package/dist/cjs/core/CompactionEngine.js +30 -6
  89. package/dist/cjs/core/CompactionEngine.js.map +1 -1
  90. package/dist/cjs/core/DirectiveChainTracker.d.ts +1 -1
  91. package/dist/cjs/core/DirectiveChainTracker.d.ts.map +1 -1
  92. package/dist/cjs/core/DirectiveChainTracker.js +5 -5
  93. package/dist/cjs/core/DirectiveChainTracker.js.map +1 -1
  94. package/dist/cjs/core/Events.d.ts +1 -1
  95. package/dist/cjs/core/Events.d.ts.map +1 -1
  96. package/dist/cjs/core/Events.js +15 -15
  97. package/dist/cjs/core/Events.js.map +1 -1
  98. package/dist/cjs/core/Flow.d.ts +4 -4
  99. package/dist/cjs/core/Flow.d.ts.map +1 -1
  100. package/dist/cjs/core/Flow.js +15 -15
  101. package/dist/cjs/core/Flow.js.map +1 -1
  102. package/dist/cjs/core/FlowRouter.d.ts +4 -4
  103. package/dist/cjs/core/FlowRouter.d.ts.map +1 -1
  104. package/dist/cjs/core/FlowRouter.js +92 -70
  105. package/dist/cjs/core/FlowRouter.js.map +1 -1
  106. package/dist/cjs/core/PersistenceManager.d.ts +1 -1
  107. package/dist/cjs/core/PersistenceManager.d.ts.map +1 -1
  108. package/dist/cjs/core/PersistenceManager.js +10 -10
  109. package/dist/cjs/core/PersistenceManager.js.map +1 -1
  110. package/dist/cjs/core/PromptComposer.d.ts +4 -4
  111. package/dist/cjs/core/PromptComposer.d.ts.map +1 -1
  112. package/dist/cjs/core/PromptComposer.js +13 -13
  113. package/dist/cjs/core/PromptComposer.js.map +1 -1
  114. package/dist/cjs/core/PromptSectionCache.d.ts +2 -2
  115. package/dist/cjs/core/PromptSectionCache.d.ts.map +1 -1
  116. package/dist/cjs/core/ResponseEngine.d.ts +4 -4
  117. package/dist/cjs/core/ResponseEngine.d.ts.map +1 -1
  118. package/dist/cjs/core/ResponseEngine.js +7 -7
  119. package/dist/cjs/core/ResponseEngine.js.map +1 -1
  120. package/dist/cjs/core/ResponseGenerationError.d.ts.map +1 -1
  121. package/dist/cjs/core/ResponseGenerationError.js +3 -5
  122. package/dist/cjs/core/ResponseGenerationError.js.map +1 -1
  123. package/dist/cjs/core/ResponseModal.d.ts +39 -10
  124. package/dist/cjs/core/ResponseModal.d.ts.map +1 -1
  125. package/dist/cjs/core/ResponseModal.js +195 -72
  126. package/dist/cjs/core/ResponseModal.js.map +1 -1
  127. package/dist/cjs/core/ResponsePipeline.d.ts +50 -12
  128. package/dist/cjs/core/ResponsePipeline.d.ts.map +1 -1
  129. package/dist/cjs/core/ResponsePipeline.js +301 -158
  130. package/dist/cjs/core/ResponsePipeline.js.map +1 -1
  131. package/dist/cjs/core/SessionFinalizer.d.ts +4 -4
  132. package/dist/cjs/core/SessionFinalizer.d.ts.map +1 -1
  133. package/dist/cjs/core/SessionFinalizer.js +36 -9
  134. package/dist/cjs/core/SessionFinalizer.js.map +1 -1
  135. package/dist/cjs/core/SessionManager.d.ts +15 -6
  136. package/dist/cjs/core/SessionManager.d.ts.map +1 -1
  137. package/dist/cjs/core/SessionManager.js +49 -22
  138. package/dist/cjs/core/SessionManager.js.map +1 -1
  139. package/dist/cjs/core/SignalCoordinator.d.ts +5 -5
  140. package/dist/cjs/core/SignalCoordinator.d.ts.map +1 -1
  141. package/dist/cjs/core/SignalCoordinator.js +12 -12
  142. package/dist/cjs/core/SignalCoordinator.js.map +1 -1
  143. package/dist/cjs/core/SignalEvaluator.d.ts +4 -4
  144. package/dist/cjs/core/SignalEvaluator.d.ts.map +1 -1
  145. package/dist/cjs/core/SignalEvaluator.js +6 -6
  146. package/dist/cjs/core/SignalEvaluator.js.map +1 -1
  147. package/dist/cjs/core/SignalProcessor.d.ts +6 -6
  148. package/dist/cjs/core/SignalProcessor.d.ts.map +1 -1
  149. package/dist/cjs/core/SignalProcessor.js +17 -89
  150. package/dist/cjs/core/SignalProcessor.js.map +1 -1
  151. package/dist/cjs/core/Step.d.ts +5 -5
  152. package/dist/cjs/core/Step.d.ts.map +1 -1
  153. package/dist/cjs/core/Step.js +65 -17
  154. package/dist/cjs/core/Step.js.map +1 -1
  155. package/dist/cjs/core/StepLifecycle.d.ts +18 -8
  156. package/dist/cjs/core/StepLifecycle.d.ts.map +1 -1
  157. package/dist/cjs/core/StepLifecycle.js +103 -20
  158. package/dist/cjs/core/StepLifecycle.js.map +1 -1
  159. package/dist/cjs/core/StreamingToolExecutor.d.ts +1 -1
  160. package/dist/cjs/core/StreamingToolExecutor.d.ts.map +1 -1
  161. package/dist/cjs/core/StreamingToolExecutor.js +30 -6
  162. package/dist/cjs/core/StreamingToolExecutor.js.map +1 -1
  163. package/dist/cjs/core/ToolLoopExecutor.d.ts +8 -4
  164. package/dist/cjs/core/ToolLoopExecutor.d.ts.map +1 -1
  165. package/dist/cjs/core/ToolLoopExecutor.js +189 -97
  166. package/dist/cjs/core/ToolLoopExecutor.js.map +1 -1
  167. package/dist/cjs/core/ToolManager.d.ts +6 -6
  168. package/dist/cjs/core/ToolManager.d.ts.map +1 -1
  169. package/dist/cjs/core/ToolManager.js +102 -79
  170. package/dist/cjs/core/ToolManager.js.map +1 -1
  171. package/dist/cjs/core/createAgent.d.ts +2 -2
  172. package/dist/cjs/core/createAgent.d.ts.map +1 -1
  173. package/dist/cjs/core/createAgent.js +2 -2
  174. package/dist/cjs/core/createAgent.js.map +1 -1
  175. package/dist/cjs/core/flow-namespace.d.ts +16 -1
  176. package/dist/cjs/core/flow-namespace.d.ts.map +1 -1
  177. package/dist/cjs/core/flow-namespace.js +26 -4
  178. package/dist/cjs/core/flow-namespace.js.map +1 -1
  179. package/dist/cjs/core/toolGates.d.ts +1 -1
  180. package/dist/cjs/core/toolGates.d.ts.map +1 -1
  181. package/dist/cjs/core/toolGates.js +3 -3
  182. package/dist/cjs/core/toolGates.js.map +1 -1
  183. package/dist/cjs/index.d.ts +50 -45
  184. package/dist/cjs/index.d.ts.map +1 -1
  185. package/dist/cjs/index.js +96 -88
  186. package/dist/cjs/index.js.map +1 -1
  187. package/dist/cjs/providers/AnthropicProvider.d.ts +25 -35
  188. package/dist/cjs/providers/AnthropicProvider.d.ts.map +1 -1
  189. package/dist/cjs/providers/AnthropicProvider.js +30 -426
  190. package/dist/cjs/providers/AnthropicProvider.js.map +1 -1
  191. package/dist/cjs/providers/DeepSeekProvider.d.ts +13 -34
  192. package/dist/cjs/providers/DeepSeekProvider.d.ts.map +1 -1
  193. package/dist/cjs/providers/DeepSeekProvider.js +17 -51
  194. package/dist/cjs/providers/DeepSeekProvider.js.map +1 -1
  195. package/dist/cjs/providers/GeminiProvider.d.ts +22 -75
  196. package/dist/cjs/providers/GeminiProvider.d.ts.map +1 -1
  197. package/dist/cjs/providers/GeminiProvider.js +32 -558
  198. package/dist/cjs/providers/GeminiProvider.js.map +1 -1
  199. package/dist/cjs/providers/GenericOpenAICompatibleProvider.d.ts +9 -10
  200. package/dist/cjs/providers/GenericOpenAICompatibleProvider.d.ts.map +1 -1
  201. package/dist/cjs/providers/GenericOpenAICompatibleProvider.js +14 -20
  202. package/dist/cjs/providers/GenericOpenAICompatibleProvider.js.map +1 -1
  203. package/dist/cjs/providers/OpenAICompatibleProvider.d.ts +26 -135
  204. package/dist/cjs/providers/OpenAICompatibleProvider.d.ts.map +1 -1
  205. package/dist/cjs/providers/OpenAICompatibleProvider.js +40 -496
  206. package/dist/cjs/providers/OpenAICompatibleProvider.js.map +1 -1
  207. package/dist/cjs/providers/OpenAIProvider.d.ts +14 -20
  208. package/dist/cjs/providers/OpenAIProvider.d.ts.map +1 -1
  209. package/dist/cjs/providers/OpenAIProvider.js +21 -28
  210. package/dist/cjs/providers/OpenAIProvider.js.map +1 -1
  211. package/dist/cjs/providers/OpenRouterProvider.d.ts +20 -24
  212. package/dist/cjs/providers/OpenRouterProvider.d.ts.map +1 -1
  213. package/dist/cjs/providers/OpenRouterProvider.js +22 -38
  214. package/dist/cjs/providers/OpenRouterProvider.js.map +1 -1
  215. package/dist/cjs/providers/ProviderAdapter.d.ts +94 -0
  216. package/dist/cjs/providers/ProviderAdapter.d.ts.map +1 -0
  217. package/dist/cjs/providers/ProviderAdapter.js +257 -0
  218. package/dist/cjs/providers/ProviderAdapter.js.map +1 -0
  219. package/dist/cjs/providers/index.d.ts +21 -18
  220. package/dist/cjs/providers/index.d.ts.map +1 -1
  221. package/dist/cjs/providers/index.js +23 -21
  222. package/dist/cjs/providers/index.js.map +1 -1
  223. package/dist/cjs/types/agent.d.ts +37 -11
  224. package/dist/cjs/types/agent.d.ts.map +1 -1
  225. package/dist/cjs/types/ai.d.ts +11 -21
  226. package/dist/cjs/types/ai.d.ts.map +1 -1
  227. package/dist/cjs/types/compaction.d.ts +2 -2
  228. package/dist/cjs/types/compaction.d.ts.map +1 -1
  229. package/dist/cjs/types/errors.d.ts +16 -20
  230. package/dist/cjs/types/errors.d.ts.map +1 -1
  231. package/dist/cjs/types/errors.js +17 -18
  232. package/dist/cjs/types/errors.js.map +1 -1
  233. package/dist/cjs/types/flow.d.ts +56 -39
  234. package/dist/cjs/types/flow.d.ts.map +1 -1
  235. package/dist/cjs/types/history.d.ts +1 -1
  236. package/dist/cjs/types/history.d.ts.map +1 -1
  237. package/dist/cjs/types/index.d.ts +17 -17
  238. package/dist/cjs/types/index.d.ts.map +1 -1
  239. package/dist/cjs/types/index.js +14 -14
  240. package/dist/cjs/types/index.js.map +1 -1
  241. package/dist/cjs/types/persistence.d.ts +2 -2
  242. package/dist/cjs/types/persistence.d.ts.map +1 -1
  243. package/dist/cjs/types/session.d.ts +4 -4
  244. package/dist/cjs/types/session.d.ts.map +1 -1
  245. package/dist/cjs/types/signals.d.ts +3 -3
  246. package/dist/cjs/types/signals.d.ts.map +1 -1
  247. package/dist/cjs/types/template.d.ts +2 -2
  248. package/dist/cjs/types/template.d.ts.map +1 -1
  249. package/dist/cjs/types/tool.d.ts +4 -2
  250. package/dist/cjs/types/tool.d.ts.map +1 -1
  251. package/dist/cjs/types/tool.js.map +1 -1
  252. package/dist/cjs/utils/condition.d.ts +1 -1
  253. package/dist/cjs/utils/condition.d.ts.map +1 -1
  254. package/dist/cjs/utils/condition.js +6 -6
  255. package/dist/cjs/utils/condition.js.map +1 -1
  256. package/dist/cjs/utils/event.d.ts +1 -1
  257. package/dist/cjs/utils/event.d.ts.map +1 -1
  258. package/dist/cjs/utils/event.js +2 -2
  259. package/dist/cjs/utils/event.js.map +1 -1
  260. package/dist/cjs/utils/history.d.ts +2 -2
  261. package/dist/cjs/utils/history.d.ts.map +1 -1
  262. package/dist/cjs/utils/history.js +15 -15
  263. package/dist/cjs/utils/history.js.map +1 -1
  264. package/dist/cjs/utils/index.d.ts +11 -13
  265. package/dist/cjs/utils/index.d.ts.map +1 -1
  266. package/dist/cjs/utils/index.js +57 -58
  267. package/dist/cjs/utils/index.js.map +1 -1
  268. package/dist/cjs/utils/serialize.d.ts +17 -0
  269. package/dist/cjs/utils/serialize.d.ts.map +1 -1
  270. package/dist/cjs/utils/serialize.js +33 -0
  271. package/dist/cjs/utils/serialize.js.map +1 -1
  272. package/dist/cjs/utils/session.d.ts +23 -3
  273. package/dist/cjs/utils/session.d.ts.map +1 -1
  274. package/dist/cjs/utils/session.js +40 -8
  275. package/dist/cjs/utils/session.js.map +1 -1
  276. package/dist/cjs/utils/template.d.ts +3 -3
  277. package/dist/cjs/utils/template.d.ts.map +1 -1
  278. package/dist/cjs/utils/template.js +5 -5
  279. package/dist/cjs/utils/template.js.map +1 -1
  280. package/dist/constants/index.d.ts +1 -0
  281. package/dist/constants/index.js +1 -1
  282. package/dist/core/Agent.d.ts +19 -11
  283. package/dist/core/Agent.d.ts.map +1 -1
  284. package/dist/core/Agent.js +53 -15
  285. package/dist/core/Agent.js.map +1 -1
  286. package/dist/core/AutoChainExecutor.d.ts +12 -22
  287. package/dist/core/AutoChainExecutor.d.ts.map +1 -1
  288. package/dist/core/AutoChainExecutor.js +27 -30
  289. package/dist/core/AutoChainExecutor.js.map +1 -1
  290. package/dist/core/BranchEvaluator.d.ts +4 -4
  291. package/dist/core/BranchEvaluator.d.ts.map +1 -1
  292. package/dist/core/BranchEvaluator.js +2 -2
  293. package/dist/core/BranchEvaluator.js.map +1 -1
  294. package/dist/core/CompactionEngine.d.ts +16 -3
  295. package/dist/core/CompactionEngine.d.ts.map +1 -1
  296. package/dist/core/CompactionEngine.js +30 -6
  297. package/dist/core/CompactionEngine.js.map +1 -1
  298. package/dist/core/DirectiveChainTracker.d.ts +1 -1
  299. package/dist/core/DirectiveChainTracker.d.ts.map +1 -1
  300. package/dist/core/DirectiveChainTracker.js +2 -2
  301. package/dist/core/DirectiveChainTracker.js.map +1 -1
  302. package/dist/core/Events.d.ts +1 -1
  303. package/dist/core/Events.d.ts.map +1 -1
  304. package/dist/core/Events.js +1 -1
  305. package/dist/core/Events.js.map +1 -1
  306. package/dist/core/Flow.d.ts +4 -4
  307. package/dist/core/Flow.d.ts.map +1 -1
  308. package/dist/core/Flow.js +3 -3
  309. package/dist/core/Flow.js.map +1 -1
  310. package/dist/core/FlowRouter.d.ts +4 -4
  311. package/dist/core/FlowRouter.d.ts.map +1 -1
  312. package/dist/core/FlowRouter.js +36 -14
  313. package/dist/core/FlowRouter.js.map +1 -1
  314. package/dist/core/PersistenceManager.d.ts +1 -1
  315. package/dist/core/PersistenceManager.d.ts.map +1 -1
  316. package/dist/core/PersistenceManager.js +3 -3
  317. package/dist/core/PersistenceManager.js.map +1 -1
  318. package/dist/core/PromptComposer.d.ts +4 -4
  319. package/dist/core/PromptComposer.d.ts.map +1 -1
  320. package/dist/core/PromptComposer.js +3 -3
  321. package/dist/core/PromptComposer.js.map +1 -1
  322. package/dist/core/PromptSectionCache.d.ts +2 -2
  323. package/dist/core/PromptSectionCache.d.ts.map +1 -1
  324. package/dist/core/ResponseEngine.d.ts +4 -4
  325. package/dist/core/ResponseEngine.d.ts.map +1 -1
  326. package/dist/core/ResponseEngine.js +2 -2
  327. package/dist/core/ResponseEngine.js.map +1 -1
  328. package/dist/core/ResponseGenerationError.d.ts.map +1 -1
  329. package/dist/core/ResponseGenerationError.js +3 -5
  330. package/dist/core/ResponseGenerationError.js.map +1 -1
  331. package/dist/core/ResponseModal.d.ts +39 -10
  332. package/dist/core/ResponseModal.d.ts.map +1 -1
  333. package/dist/core/ResponseModal.js +152 -29
  334. package/dist/core/ResponseModal.js.map +1 -1
  335. package/dist/core/ResponsePipeline.d.ts +50 -12
  336. package/dist/core/ResponsePipeline.d.ts.map +1 -1
  337. package/dist/core/ResponsePipeline.js +232 -89
  338. package/dist/core/ResponsePipeline.js.map +1 -1
  339. package/dist/core/SessionFinalizer.d.ts +4 -4
  340. package/dist/core/SessionFinalizer.d.ts.map +1 -1
  341. package/dist/core/SessionFinalizer.js +32 -5
  342. package/dist/core/SessionFinalizer.js.map +1 -1
  343. package/dist/core/SessionManager.d.ts +15 -6
  344. package/dist/core/SessionManager.d.ts.map +1 -1
  345. package/dist/core/SessionManager.js +46 -19
  346. package/dist/core/SessionManager.js.map +1 -1
  347. package/dist/core/SignalCoordinator.d.ts +5 -5
  348. package/dist/core/SignalCoordinator.d.ts.map +1 -1
  349. package/dist/core/SignalCoordinator.js +2 -2
  350. package/dist/core/SignalCoordinator.js.map +1 -1
  351. package/dist/core/SignalEvaluator.d.ts +4 -4
  352. package/dist/core/SignalEvaluator.d.ts.map +1 -1
  353. package/dist/core/SignalEvaluator.js +2 -2
  354. package/dist/core/SignalEvaluator.js.map +1 -1
  355. package/dist/core/SignalProcessor.d.ts +6 -6
  356. package/dist/core/SignalProcessor.d.ts.map +1 -1
  357. package/dist/core/SignalProcessor.js +7 -79
  358. package/dist/core/SignalProcessor.js.map +1 -1
  359. package/dist/core/Step.d.ts +5 -5
  360. package/dist/core/Step.d.ts.map +1 -1
  361. package/dist/core/Step.js +53 -5
  362. package/dist/core/Step.js.map +1 -1
  363. package/dist/core/StepLifecycle.d.ts +18 -8
  364. package/dist/core/StepLifecycle.d.ts.map +1 -1
  365. package/dist/core/StepLifecycle.js +98 -15
  366. package/dist/core/StepLifecycle.js.map +1 -1
  367. package/dist/core/StreamingToolExecutor.d.ts +1 -1
  368. package/dist/core/StreamingToolExecutor.d.ts.map +1 -1
  369. package/dist/core/StreamingToolExecutor.js +29 -5
  370. package/dist/core/StreamingToolExecutor.js.map +1 -1
  371. package/dist/core/ToolLoopExecutor.d.ts +8 -4
  372. package/dist/core/ToolLoopExecutor.d.ts.map +1 -1
  373. package/dist/core/ToolLoopExecutor.js +157 -65
  374. package/dist/core/ToolLoopExecutor.js.map +1 -1
  375. package/dist/core/ToolManager.d.ts +6 -6
  376. package/dist/core/ToolManager.d.ts.map +1 -1
  377. package/dist/core/ToolManager.js +44 -21
  378. package/dist/core/ToolManager.js.map +1 -1
  379. package/dist/core/createAgent.d.ts +2 -2
  380. package/dist/core/createAgent.d.ts.map +1 -1
  381. package/dist/core/createAgent.js +1 -1
  382. package/dist/core/createAgent.js.map +1 -1
  383. package/dist/core/flow-namespace.d.ts +16 -1
  384. package/dist/core/flow-namespace.d.ts.map +1 -1
  385. package/dist/core/flow-namespace.js +23 -1
  386. package/dist/core/flow-namespace.js.map +1 -1
  387. package/dist/core/toolGates.d.ts +1 -1
  388. package/dist/core/toolGates.d.ts.map +1 -1
  389. package/dist/core/toolGates.js +1 -1
  390. package/dist/core/toolGates.js.map +1 -1
  391. package/dist/index.d.ts +50 -45
  392. package/dist/index.d.ts.map +1 -1
  393. package/dist/index.js +34 -30
  394. package/dist/index.js.map +1 -1
  395. package/dist/providers/AnthropicProvider.d.ts +25 -35
  396. package/dist/providers/AnthropicProvider.d.ts.map +1 -1
  397. package/dist/providers/AnthropicProvider.js +30 -423
  398. package/dist/providers/AnthropicProvider.js.map +1 -1
  399. package/dist/providers/DeepSeekProvider.d.ts +13 -34
  400. package/dist/providers/DeepSeekProvider.d.ts.map +1 -1
  401. package/dist/providers/DeepSeekProvider.js +16 -47
  402. package/dist/providers/DeepSeekProvider.js.map +1 -1
  403. package/dist/providers/GeminiProvider.d.ts +22 -75
  404. package/dist/providers/GeminiProvider.d.ts.map +1 -1
  405. package/dist/providers/GeminiProvider.js +32 -558
  406. package/dist/providers/GeminiProvider.js.map +1 -1
  407. package/dist/providers/GenericOpenAICompatibleProvider.d.ts +9 -10
  408. package/dist/providers/GenericOpenAICompatibleProvider.d.ts.map +1 -1
  409. package/dist/providers/GenericOpenAICompatibleProvider.js +13 -16
  410. package/dist/providers/GenericOpenAICompatibleProvider.js.map +1 -1
  411. package/dist/providers/OpenAICompatibleProvider.d.ts +26 -135
  412. package/dist/providers/OpenAICompatibleProvider.d.ts.map +1 -1
  413. package/dist/providers/OpenAICompatibleProvider.js +39 -495
  414. package/dist/providers/OpenAICompatibleProvider.js.map +1 -1
  415. package/dist/providers/OpenAIProvider.d.ts +14 -20
  416. package/dist/providers/OpenAIProvider.d.ts.map +1 -1
  417. package/dist/providers/OpenAIProvider.js +20 -24
  418. package/dist/providers/OpenAIProvider.js.map +1 -1
  419. package/dist/providers/OpenRouterProvider.d.ts +20 -24
  420. package/dist/providers/OpenRouterProvider.d.ts.map +1 -1
  421. package/dist/providers/OpenRouterProvider.js +21 -34
  422. package/dist/providers/OpenRouterProvider.js.map +1 -1
  423. package/dist/providers/ProviderAdapter.d.ts +94 -0
  424. package/dist/providers/ProviderAdapter.d.ts.map +1 -0
  425. package/dist/providers/ProviderAdapter.js +251 -0
  426. package/dist/providers/ProviderAdapter.js.map +1 -0
  427. package/dist/providers/index.d.ts +21 -18
  428. package/dist/providers/index.d.ts.map +1 -1
  429. package/dist/providers/index.js +13 -10
  430. package/dist/providers/index.js.map +1 -1
  431. package/dist/types/agent.d.ts +37 -11
  432. package/dist/types/agent.d.ts.map +1 -1
  433. package/dist/types/ai.d.ts +11 -21
  434. package/dist/types/ai.d.ts.map +1 -1
  435. package/dist/types/compaction.d.ts +2 -2
  436. package/dist/types/compaction.d.ts.map +1 -1
  437. package/dist/types/errors.d.ts +16 -20
  438. package/dist/types/errors.d.ts.map +1 -1
  439. package/dist/types/errors.js +15 -16
  440. package/dist/types/errors.js.map +1 -1
  441. package/dist/types/flow.d.ts +56 -39
  442. package/dist/types/flow.d.ts.map +1 -1
  443. package/dist/types/history.d.ts +1 -1
  444. package/dist/types/history.d.ts.map +1 -1
  445. package/dist/types/index.d.ts +17 -17
  446. package/dist/types/index.d.ts.map +1 -1
  447. package/dist/types/index.js +4 -4
  448. package/dist/types/index.js.map +1 -1
  449. package/dist/types/persistence.d.ts +2 -2
  450. package/dist/types/persistence.d.ts.map +1 -1
  451. package/dist/types/session.d.ts +4 -4
  452. package/dist/types/session.d.ts.map +1 -1
  453. package/dist/types/signals.d.ts +3 -3
  454. package/dist/types/signals.d.ts.map +1 -1
  455. package/dist/types/template.d.ts +2 -2
  456. package/dist/types/template.d.ts.map +1 -1
  457. package/dist/types/tool.d.ts +4 -2
  458. package/dist/types/tool.d.ts.map +1 -1
  459. package/dist/types/tool.js.map +1 -1
  460. package/dist/utils/condition.d.ts +1 -1
  461. package/dist/utils/condition.d.ts.map +1 -1
  462. package/dist/utils/condition.js +2 -2
  463. package/dist/utils/condition.js.map +1 -1
  464. package/dist/utils/event.d.ts +1 -1
  465. package/dist/utils/event.d.ts.map +1 -1
  466. package/dist/utils/event.js +1 -1
  467. package/dist/utils/event.js.map +1 -1
  468. package/dist/utils/history.d.ts +2 -2
  469. package/dist/utils/history.d.ts.map +1 -1
  470. package/dist/utils/history.js +1 -1
  471. package/dist/utils/history.js.map +1 -1
  472. package/dist/utils/index.d.ts +11 -13
  473. package/dist/utils/index.d.ts.map +1 -1
  474. package/dist/utils/index.js +11 -12
  475. package/dist/utils/index.js.map +1 -1
  476. package/dist/utils/serialize.d.ts +17 -0
  477. package/dist/utils/serialize.d.ts.map +1 -1
  478. package/dist/utils/serialize.js +31 -0
  479. package/dist/utils/serialize.js.map +1 -1
  480. package/dist/utils/session.d.ts +23 -3
  481. package/dist/utils/session.d.ts.map +1 -1
  482. package/dist/utils/session.js +35 -6
  483. package/dist/utils/session.js.map +1 -1
  484. package/dist/utils/template.d.ts +3 -3
  485. package/dist/utils/template.d.ts.map +1 -1
  486. package/dist/utils/template.js +1 -1
  487. package/dist/utils/template.js.map +1 -1
  488. package/docs/concepts/architecture.md +3 -3
  489. package/docs/concepts/directives.md +1 -1
  490. package/docs/guides/error-handling.md +46 -45
  491. package/docs/guides/flow-control.md +8 -1
  492. package/docs/guides/instructions.md +15 -6
  493. package/docs/guides/persistence.md +12 -5
  494. package/docs/guides/streaming.md +10 -0
  495. package/docs/migration/README.md +4 -0
  496. package/docs/migration/v2-3-to-v2-4.md +4 -0
  497. package/docs/migration/v2-6-to-v2-7.md +246 -0
  498. package/docs/reference/adapters.md +15 -1
  499. package/docs/reference/branches.md +2 -0
  500. package/docs/reference/create-agent.md +28 -0
  501. package/docs/reference/directive.md +1 -1
  502. package/docs/reference/errors.md +30 -32
  503. package/docs/reference/providers.md +63 -60
  504. package/docs/reference/step.md +28 -21
  505. package/docs/reference/tool.md +14 -5
  506. package/docs/start/02-first-agent.md +8 -4
  507. package/docs/start/03-collect-data.md +19 -10
  508. package/examples/01-quickstart.ts +2 -2
  509. package/examples/02-data-extraction.ts +1 -1
  510. package/examples/03-tools.ts +1 -1
  511. package/examples/04-instructions.ts +2 -2
  512. package/examples/05-branching.ts +3 -3
  513. package/examples/06-flow-control.ts +3 -3
  514. package/examples/07-streaming.ts +1 -1
  515. package/examples/08-persistence.ts +2 -2
  516. package/examples/09-signals.ts +1 -1
  517. package/examples/tsconfig.json +6 -3
  518. package/package.json +9 -7
  519. package/src/adapters/MemoryAdapter.ts +33 -37
  520. package/src/adapters/MongoAdapter.ts +3 -3
  521. package/src/adapters/OpenSearchAdapter.ts +4 -4
  522. package/src/adapters/PostgreSQLAdapter.ts +26 -21
  523. package/src/adapters/PrismaAdapter.ts +4 -4
  524. package/src/adapters/RedisAdapter.ts +84 -37
  525. package/src/adapters/SQLiteAdapter.ts +13 -34
  526. package/src/adapters/index.ts +13 -13
  527. package/src/adapters/sessionRow.ts +57 -0
  528. package/src/core/Agent.ts +64 -18
  529. package/src/core/AutoChainExecutor.ts +44 -57
  530. package/src/core/BranchEvaluator.ts +5 -5
  531. package/src/core/CompactionEngine.ts +42 -8
  532. package/src/core/DirectiveChainTracker.ts +3 -3
  533. package/src/core/Events.ts +2 -2
  534. package/src/core/Flow.ts +9 -9
  535. package/src/core/FlowRouter.ts +46 -20
  536. package/src/core/PersistenceManager.ts +4 -4
  537. package/src/core/PromptComposer.ts +8 -8
  538. package/src/core/PromptSectionCache.ts +2 -2
  539. package/src/core/ResponseEngine.ts +6 -6
  540. package/src/core/ResponseGenerationError.ts +3 -6
  541. package/src/core/ResponseModal.ts +205 -39
  542. package/src/core/ResponsePipeline.ts +301 -107
  543. package/src/core/SessionFinalizer.ts +40 -10
  544. package/src/core/SessionManager.ts +61 -27
  545. package/src/core/SignalCoordinator.ts +7 -7
  546. package/src/core/SignalEvaluator.ts +6 -6
  547. package/src/core/SignalProcessor.ts +13 -93
  548. package/src/core/Step.ts +87 -10
  549. package/src/core/StepLifecycle.ts +129 -26
  550. package/src/core/StreamingToolExecutor.ts +33 -8
  551. package/src/core/ToolLoopExecutor.ts +206 -80
  552. package/src/core/ToolManager.ts +53 -26
  553. package/src/core/createAgent.ts +2 -2
  554. package/src/core/flow-namespace.ts +31 -2
  555. package/src/core/toolGates.ts +2 -2
  556. package/src/index.ts +59 -45
  557. package/src/providers/AnthropicProvider.ts +44 -595
  558. package/src/providers/DeepSeekProvider.ts +27 -92
  559. package/src/providers/GeminiProvider.ts +41 -752
  560. package/src/providers/GenericOpenAICompatibleProvider.ts +19 -27
  561. package/src/providers/OpenAICompatibleProvider.ts +58 -764
  562. package/src/providers/OpenAIProvider.ts +31 -55
  563. package/src/providers/OpenRouterProvider.ts +40 -70
  564. package/src/providers/ProviderAdapter.ts +368 -0
  565. package/src/providers/index.ts +21 -23
  566. package/src/types/agent.ts +36 -11
  567. package/src/types/ai.ts +11 -21
  568. package/src/types/compaction.ts +2 -2
  569. package/src/types/errors.ts +17 -35
  570. package/src/types/flow.ts +44 -46
  571. package/src/types/history.ts +1 -1
  572. package/src/types/index.ts +18 -17
  573. package/src/types/persistence.ts +2 -2
  574. package/src/types/session.ts +4 -4
  575. package/src/types/signals.ts +3 -3
  576. package/src/types/template.ts +2 -2
  577. package/src/types/tool.ts +4 -2
  578. package/src/utils/condition.ts +3 -3
  579. package/src/utils/event.ts +1 -1
  580. package/src/utils/history.ts +3 -3
  581. package/src/utils/index.ts +14 -15
  582. package/src/utils/serialize.ts +38 -0
  583. package/src/utils/session.ts +46 -9
  584. package/src/utils/template.ts +3 -3
  585. package/dist/cjs/core/DirectiveBus.d.ts +0 -88
  586. package/dist/cjs/core/DirectiveBus.d.ts.map +0 -1
  587. package/dist/cjs/core/DirectiveBus.js +0 -196
  588. package/dist/cjs/core/DirectiveBus.js.map +0 -1
  589. package/dist/cjs/providers/errorClassification.d.ts +0 -61
  590. package/dist/cjs/providers/errorClassification.d.ts.map +0 -1
  591. package/dist/cjs/providers/errorClassification.js +0 -123
  592. package/dist/cjs/providers/errorClassification.js.map +0 -1
  593. package/dist/cjs/utils/retry.d.ts +0 -67
  594. package/dist/cjs/utils/retry.d.ts.map +0 -1
  595. package/dist/cjs/utils/retry.js +0 -201
  596. package/dist/cjs/utils/retry.js.map +0 -1
  597. package/dist/core/DirectiveBus.d.ts +0 -88
  598. package/dist/core/DirectiveBus.d.ts.map +0 -1
  599. package/dist/core/DirectiveBus.js +0 -192
  600. package/dist/core/DirectiveBus.js.map +0 -1
  601. package/dist/providers/errorClassification.d.ts +0 -61
  602. package/dist/providers/errorClassification.d.ts.map +0 -1
  603. package/dist/providers/errorClassification.js +0 -116
  604. package/dist/providers/errorClassification.js.map +0 -1
  605. package/dist/utils/retry.d.ts +0 -67
  606. package/dist/utils/retry.d.ts.map +0 -1
  607. package/dist/utils/retry.js +0 -193
  608. package/dist/utils/retry.js.map +0 -1
  609. package/src/core/DirectiveBus.ts +0 -248
  610. package/src/providers/errorClassification.ts +0 -172
  611. package/src/utils/retry.ts +0 -274
@@ -5,13 +5,13 @@
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.ResponsePipeline = void 0;
7
7
  exports.hasDirectivePositionField = hasDirectivePositionField;
8
- const utils_1 = require("../utils");
9
- const session_1 = require("../utils/session");
10
- const template_1 = require("../utils/template");
11
- const Step_1 = require("../core/Step");
12
- const BranchEvaluator_1 = require("./BranchEvaluator");
13
- const DirectiveChainTracker_1 = require("./DirectiveChainTracker");
14
- const ResponseGenerationError_1 = require("./ResponseGenerationError");
8
+ const index_js_1 = require("../utils/index.js");
9
+ const session_js_1 = require("../utils/session.js");
10
+ const template_js_1 = require("../utils/template.js");
11
+ const Step_js_1 = require("../core/Step.js");
12
+ const BranchEvaluator_js_1 = require("./BranchEvaluator.js");
13
+ const DirectiveChainTracker_js_1 = require("./DirectiveChainTracker.js");
14
+ const ResponseGenerationError_js_1 = require("./ResponseGenerationError.js");
15
15
  /**
16
16
  * Position fields on a Directive that represent a navigation decision.
17
17
  * When any of these is set, the directive "wins" the turn's position decision
@@ -29,6 +29,23 @@ function hasDirectivePositionField(directive) {
29
29
  return false;
30
30
  return DIRECTIVE_POSITION_FIELDS.some((field) => directive[field] !== undefined);
31
31
  }
32
+ /**
33
+ * Compute the per-key data writes the signal phase applied to a session.
34
+ * The signal phase and routing start from the same input session, so any
35
+ * key whose value differs between the input and the signal output was
36
+ * written by the signal phase alone (handler `updateData` calls).
37
+ */
38
+ function diffSignalDataWrites(before, after) {
39
+ const beforeData = (before ?? {});
40
+ const afterData = (after ?? {});
41
+ const writes = {};
42
+ for (const key of Object.keys(afterData)) {
43
+ if (afterData[key] !== beforeData[key]) {
44
+ writes[key] = afterData[key];
45
+ }
46
+ }
47
+ return writes;
48
+ }
32
49
  /**
33
50
  * Shared response processing logic between respond() and respondStream() methods
34
51
  */
@@ -47,7 +64,7 @@ class ResponsePipeline {
47
64
  */
48
65
  createChainTracker() {
49
66
  const maxChain = this.options.maxDirectiveChain ?? 10;
50
- this._chainTracker = new DirectiveChainTracker_1.DirectiveChainTracker(maxChain);
67
+ this._chainTracker = new DirectiveChainTracker_js_1.DirectiveChainTracker(maxChain);
51
68
  return this._chainTracker;
52
69
  }
53
70
  /**
@@ -78,7 +95,7 @@ class ResponsePipeline {
78
95
  ...contextOverride,
79
96
  };
80
97
  // Initialize or get session (use the live session if available)
81
- const targetSession = session || params.currentSession || (0, utils_1.createSession)();
98
+ const targetSession = session || params.currentSession || (0, index_js_1.createSession)();
82
99
  return {
83
100
  effectiveContext,
84
101
  session: targetSession,
@@ -89,7 +106,7 @@ class ResponsePipeline {
89
106
  * Handle routing and step selection logic
90
107
  */
91
108
  async handleRoutingAndStepSelection(params) {
92
- const { session, history, context, signal } = params;
109
+ const { session, history, context, signal, allowedFlows } = params;
93
110
  // PHASE 2: ROUTING + STEP SELECTION - Determine which flow and step to use (combined)
94
111
  let selectedFlow;
95
112
  let responseDirectives;
@@ -97,12 +114,23 @@ class ResponsePipeline {
97
114
  let isFlowComplete = false;
98
115
  let completedFlows = [];
99
116
  let targetSession = session;
117
+ // Flows exited this turn via pendingDirective redirect/reset
118
+ const endedFlows = [];
119
+ let exitPrevFlowId;
120
+ let exitPrevFlowTitle;
121
+ let exitReason;
100
122
  // Get flows early since we need them for pending directives
101
123
  const flows = this.getFlows();
124
+ // Routing candidates may be narrowed for this turn (entry pins); the
125
+ // pendingDirective applier below still resolves targets against the FULL
126
+ // registry so declared redirects always resolve.
127
+ const routingFlows = allowedFlows && allowedFlows.length > 0
128
+ ? flows.filter((f) => allowedFlows.includes(f.id) || allowedFlows.includes(f.title))
129
+ : flows;
102
130
  // Check for pending directive from previous flow completion or external dispatch
103
131
  if (targetSession.pendingDirective) {
104
132
  const directive = targetSession.pendingDirective;
105
- utils_1.logger.debug(`[ResponsePipeline] Applying pending directive at start of turn`);
133
+ index_js_1.logger.debug(`[ResponsePipeline] Applying pending directive at start of turn`);
106
134
  // Track directive chain depth (Requirement 22.1)
107
135
  const tracker = this.chainTracker;
108
136
  tracker.record(directive, "pending");
@@ -118,23 +146,30 @@ class ResponsePipeline {
118
146
  ...targetSession,
119
147
  pendingDirective: nextDirective,
120
148
  };
149
+ // Capture the flow we're leaving so directive-driven exits surface on
150
+ // the response (endedFlows).
151
+ exitPrevFlowId = targetSession.currentFlow?.id;
152
+ exitPrevFlowTitle = exitPrevFlowId
153
+ ? flows.find((f) => f.id === exitPrevFlowId)?.title
154
+ : undefined;
121
155
  // Apply the directive: resolve position field to a flow/step
122
156
  if (directive.goTo) {
157
+ exitReason = 'goto';
123
158
  const flowTarget = typeof directive.goTo === 'string'
124
159
  ? directive.goTo
125
160
  : directive.goTo.flow;
126
161
  if (flowTarget) {
127
162
  const targetFlow = flows.find((r) => r.id === flowTarget || r.title === flowTarget);
128
163
  if (targetFlow) {
129
- utils_1.logger.debug(`[ResponsePipeline] Pending directive goTo → flow: ${targetFlow.title}`);
130
- targetSession = (0, session_1.enterFlow)(targetSession, targetFlow.id, targetFlow.title);
164
+ index_js_1.logger.debug(`[ResponsePipeline] Pending directive goTo → flow: ${targetFlow.title}`);
165
+ targetSession = (0, session_js_1.enterFlow)(targetSession, targetFlow.id, targetFlow.title);
131
166
  // Merge initial data if available
132
167
  if (targetFlow.initialData) {
133
- targetSession = (0, utils_1.mergeCollected)(targetSession, targetFlow.initialData);
168
+ targetSession = (0, index_js_1.mergeCollected)(targetSession, targetFlow.initialData);
134
169
  }
135
170
  // Merge directive-carried data if present
136
171
  if (typeof directive.goTo === 'object' && directive.goTo.data) {
137
- targetSession = (0, utils_1.mergeCollected)(targetSession, directive.goTo.data);
172
+ targetSession = (0, index_js_1.mergeCollected)(targetSession, directive.goTo.data);
138
173
  }
139
174
  selectedFlow = targetFlow;
140
175
  // If goTo specifies a step, enter it
@@ -142,13 +177,13 @@ class ResponsePipeline {
142
177
  const stepTarget = directive.goTo.step;
143
178
  const targetStep = targetFlow.getStep(stepTarget);
144
179
  if (targetStep) {
145
- targetSession = (0, utils_1.enterStep)(targetSession, targetStep.id, targetStep.description);
180
+ targetSession = (0, index_js_1.enterStep)(targetSession, targetStep.id, targetStep.description);
146
181
  selectedStep = targetStep;
147
182
  }
148
183
  }
149
184
  }
150
185
  else {
151
- utils_1.logger.warn(`[FlowConfigurationError] Pending directive goTo target not found: flow "${flowTarget}" does not exist. Falling back to normal routing. Fix the goTo reference or remove the pending directive.`);
186
+ index_js_1.logger.warn(`[FlowConfigurationError] Pending directive goTo target not found: flow "${flowTarget}" does not exist. Falling back to normal routing. Fix the goTo reference or remove the pending directive.`);
152
187
  }
153
188
  }
154
189
  }
@@ -162,11 +197,11 @@ class ResponsePipeline {
162
197
  if (flowTarget) {
163
198
  const targetFlow = flows.find((r) => r.id === flowTarget || r.title === flowTarget);
164
199
  if (targetFlow) {
165
- targetSession = (0, session_1.enterFlow)(targetSession, targetFlow.id, targetFlow.title);
200
+ targetSession = (0, session_js_1.enterFlow)(targetSession, targetFlow.id, targetFlow.title);
166
201
  selectedFlow = targetFlow;
167
202
  const targetStep = targetFlow.getStep(stepTarget);
168
203
  if (targetStep) {
169
- targetSession = (0, utils_1.enterStep)(targetSession, targetStep.id, targetStep.description);
204
+ targetSession = (0, index_js_1.enterStep)(targetSession, targetStep.id, targetStep.description);
170
205
  selectedStep = targetStep;
171
206
  }
172
207
  }
@@ -178,13 +213,14 @@ class ResponsePipeline {
178
213
  selectedFlow = currentFlow;
179
214
  const targetStep = currentFlow.getStep(stepTarget);
180
215
  if (targetStep) {
181
- targetSession = (0, utils_1.enterStep)(targetSession, targetStep.id, targetStep.description);
216
+ targetSession = (0, index_js_1.enterStep)(targetSession, targetStep.id, targetStep.description);
182
217
  selectedStep = targetStep;
183
218
  }
184
219
  }
185
220
  }
186
221
  }
187
222
  else if (directive.reset) {
223
+ exitReason = 'reset';
188
224
  // Reset current flow
189
225
  if (targetSession.currentFlow) {
190
226
  const currentFlow = flows.find(r => r.id === targetSession.currentFlow?.id);
@@ -196,14 +232,14 @@ class ResponsePipeline {
196
232
  if (resetStep) {
197
233
  const targetStep = currentFlow.getStep(resetStep);
198
234
  if (targetStep) {
199
- targetSession = (0, utils_1.enterStep)(targetSession, targetStep.id, targetStep.description);
235
+ targetSession = (0, index_js_1.enterStep)(targetSession, targetStep.id, targetStep.description);
200
236
  selectedStep = targetStep;
201
237
  }
202
238
  }
203
239
  else {
204
240
  // Reset to initial step
205
241
  const initialStep = currentFlow.initialStep;
206
- targetSession = (0, utils_1.enterStep)(targetSession, initialStep.id, initialStep.description);
242
+ targetSession = (0, index_js_1.enterStep)(targetSession, initialStep.id, initialStep.description);
207
243
  selectedStep = initialStep;
208
244
  }
209
245
  }
@@ -212,14 +248,20 @@ class ResponsePipeline {
212
248
  // For complete/abort, selectedFlow stays undefined → handled downstream
213
249
  // Apply state writes from the directive
214
250
  if (directive.dataUpdate) {
215
- targetSession = (0, utils_1.mergeCollected)(targetSession, directive.dataUpdate);
251
+ targetSession = (0, index_js_1.mergeCollected)(targetSession, directive.dataUpdate);
216
252
  }
217
253
  // Skip FlowRouter.decideFlowAndStep — the directive resolved the position
218
254
  }
219
- // If no pending transition or transition handled, do normal routing
220
- if (flows.length > 0 && !selectedFlow) {
255
+ if (exitReason &&
256
+ exitPrevFlowId &&
257
+ (!selectedFlow || selectedFlow.id !== exitPrevFlowId)) {
258
+ endedFlows.push({ flowId: exitPrevFlowId, title: exitPrevFlowTitle, reason: exitReason });
259
+ }
260
+ // If no pending transition or transition handled, do normal routing.
261
+ // Candidates honor allowedFlows; completion scoring runs over the same set.
262
+ if (routingFlows.length > 0 && !selectedFlow) {
221
263
  const orchestration = await this.flowRouter.decideFlowAndStep({
222
- flows: flows,
264
+ flows: routingFlows,
223
265
  session: targetSession,
224
266
  history,
225
267
  agentOptions: this.options,
@@ -235,7 +277,7 @@ class ResponsePipeline {
235
277
  completedFlows = orchestration.completedFlows || [];
236
278
  // Log if flow is complete
237
279
  if (isFlowComplete) {
238
- utils_1.logger.debug(`[ResponsePipeline] Flow complete: all required data collected or last step reached`);
280
+ index_js_1.logger.debug(`[ResponsePipeline] Flow complete: all required data collected or last step reached`);
239
281
  }
240
282
  }
241
283
  return {
@@ -245,15 +287,36 @@ class ResponsePipeline {
245
287
  session: targetSession,
246
288
  isFlowComplete,
247
289
  completedFlows,
290
+ ...(endedFlows.length > 0 ? { endedFlows } : {}),
248
291
  };
249
292
  }
293
+ /**
294
+ * Combine a routing-derived session with the signal phase's non-position
295
+ * mutations. The routing session is the base — it owns position state AND
296
+ * data merges such as flow initialData and directive-carried writes; the
297
+ * signal phase's mutations (trigger recording under `signals`, handler
298
+ * data writes) are re-applied on top. Both phases start from the same
299
+ * input session, so their mutations cannot silently collide.
300
+ */
301
+ combineRoutingAndSignalSessions(params) {
302
+ const { inputSession, signalSession, routingSession } = params;
303
+ let combined = routingSession;
304
+ if (signalSession.signals !== inputSession.signals) {
305
+ combined = { ...combined, signals: signalSession.signals };
306
+ }
307
+ const signalWrites = diffSignalDataWrites(inputSession.data, signalSession.data);
308
+ if (Object.keys(signalWrites).length > 0) {
309
+ combined = (0, index_js_1.mergeCollected)(combined, signalWrites);
310
+ }
311
+ return combined;
312
+ }
250
313
  /**
251
314
  * Determine next step and update session
252
315
  */
253
316
  async determineNextStep(params) {
254
317
  const { selectedFlow, selectedStep, session, isFlowComplete, context, busDirective } = params;
255
318
  if (!selectedFlow) {
256
- return { nextStep: undefined, session };
319
+ return { nextStep: undefined, session, isFlowComplete };
257
320
  }
258
321
  // ─── GUARD: directive bus winner with a position field preempts branches ───
259
322
  // Resolution precedence (design.md): bus > branches > linear > AI.
@@ -261,8 +324,8 @@ class ResponsePipeline {
261
324
  // complete, abort, reset), that decision wins the turn. Do NOT evaluate
262
325
  // branches or linear/AI selection — the caller applies the bus directive.
263
326
  if (hasDirectivePositionField(busDirective)) {
264
- utils_1.logger.debug(`[ResponsePipeline] Directive bus winner has position field — skipping branch evaluation and linear/AI selection`);
265
- return { nextStep: undefined, session };
327
+ index_js_1.logger.debug(`[ResponsePipeline] Directive bus winner has position field — skipping branch evaluation and linear/AI selection`);
328
+ return { nextStep: undefined, session, isFlowComplete };
266
329
  }
267
330
  // STEP 1 (Algorithm 1): branches win over linear chain AND flow completion.
268
331
  // Evaluate branches before checking isFlowComplete — a branch can redirect
@@ -274,13 +337,20 @@ class ResponsePipeline {
274
337
  if (currentStep?.branches && currentStep.branches.length > 0) {
275
338
  const branchResult = await this.evaluateStepBranches(currentStep, selectedFlow, session, context);
276
339
  if (branchResult) {
277
- return branchResult;
340
+ // A branch that resolved a position overrides the router's completion
341
+ // proposal. Without this, a branch that parks on a step of its own
342
+ // flow (`then: '<stepId>'`, `then: { reset: true }`) keeps
343
+ // isFlowComplete=true, the caller drops the step it just resolved,
344
+ // and the turn ends as a silent completion — no LLM call, empty
345
+ // reply, flow marked completed for the rest of the session.
346
+ const resolvedPosition = Boolean(branchResult.nextStep || branchResult.flowChanged);
347
+ return { ...branchResult, isFlowComplete: resolvedPosition ? false : isFlowComplete };
278
348
  }
279
349
  // undefined → fall through to linear/AI selection or flow completion
280
350
  }
281
351
  }
282
352
  if (isFlowComplete) {
283
- return { nextStep: undefined, session };
353
+ return { nextStep: undefined, session, isFlowComplete: true };
284
354
  }
285
355
  let nextStep;
286
356
  // If we have a selected step from the combined routing decision, use it
@@ -294,15 +364,15 @@ class ResponsePipeline {
294
364
  : undefined;
295
365
  // Get candidate steps based on current position in the flow
296
366
  const candidates = await this.flowRouter.getCandidateStepsWithConditions(selectedFlow, currentStep, // Pass current step instead of undefined to maintain progression
297
- (0, template_1.createTemplateContext)({ data: session.data, session, context }));
367
+ (0, template_js_1.createTemplateContext)({ data: session.data, session, context }));
298
368
  if (candidates.length > 0) {
299
369
  nextStep = candidates[0].step;
300
- utils_1.logger.debug(`[ResponsePipeline] Using first valid step: ${nextStep.id}${currentStep ? ' (progressing from ' + currentStep.id + ')' : ' for new flow'}`);
370
+ index_js_1.logger.debug(`[ResponsePipeline] Using first valid step: ${nextStep.id}${currentStep ? ' (progressing from ' + currentStep.id + ')' : ' for new flow'}`);
301
371
  }
302
372
  else {
303
373
  // Fallback to initial step even if it should be skipped
304
374
  nextStep = selectedFlow.initialStep;
305
- utils_1.logger.warn(`[FlowConfigurationError] No valid steps found in flow "${selectedFlow.title}": all candidates were skipped. Falling back to initial step "${nextStep.id}". Review step skip conditions.`);
375
+ index_js_1.logger.warn(`[FlowConfigurationError] No valid steps found in flow "${selectedFlow.title}": all candidates were skipped. Falling back to initial step "${nextStep.id}". Review step skip conditions.`);
306
376
  }
307
377
  }
308
378
  // Before entering the step, check if requires fields are satisfied
@@ -310,7 +380,7 @@ class ResponsePipeline {
310
380
  const sessionData = session.data || {};
311
381
  const missingRequires = nextStep.requires.filter(field => sessionData[String(field)] === undefined);
312
382
  if (missingRequires.length > 0) {
313
- utils_1.logger.debug(`[ResponsePipeline] Cannot enter step "${nextStep.id}": missing required fields [${missingRequires.join(', ')}]. Staying at current step.`);
383
+ index_js_1.logger.debug(`[ResponsePipeline] Cannot enter step "${nextStep.id}": missing required fields [${missingRequires.join(', ')}]. Staying at current step.`);
314
384
  // Stay at current step - don't enter the next one
315
385
  const currentStepId = session.currentStep?.id;
316
386
  if (currentStepId && selectedFlow) {
@@ -319,13 +389,13 @@ class ResponsePipeline {
319
389
  nextStep = currentStepInstance;
320
390
  }
321
391
  }
322
- return { nextStep, session };
392
+ return { nextStep, session, isFlowComplete: false };
323
393
  }
324
394
  }
325
395
  // Update session with next step
326
- const updatedSession = (0, utils_1.enterStep)(session, nextStep.id, nextStep.description);
327
- utils_1.logger.debug(`[ResponsePipeline] Entered step: ${nextStep.id}`);
328
- return { nextStep, session: updatedSession };
396
+ const updatedSession = (0, index_js_1.enterStep)(session, nextStep.id, nextStep.description);
397
+ index_js_1.logger.debug(`[ResponsePipeline] Entered step: ${nextStep.id}`);
398
+ return { nextStep, session: updatedSession, isFlowComplete: false };
329
399
  }
330
400
  /**
331
401
  * Evaluate branches on a step and resolve the `then` value.
@@ -339,7 +409,7 @@ class ResponsePipeline {
339
409
  * Returns the resolved { nextStep, session, flowChanged? } or undefined if no branch matched.
340
410
  */
341
411
  async evaluateStepBranches(currentStep, selectedFlow, session, context) {
342
- const history = session.history ? (0, utils_1.historyToEvents)(session.history) : [];
412
+ const history = session.history ? (0, index_js_1.historyToEvents)(session.history) : [];
343
413
  // Build the BranchPredicateContext
344
414
  const branchCtx = {
345
415
  data: session.data,
@@ -348,8 +418,8 @@ class ResponsePipeline {
348
418
  history,
349
419
  };
350
420
  // Create the AI condition evaluator
351
- const aiEvaluator = (0, BranchEvaluator_1.createAiConditionEvaluator)(this.options.provider, history, context);
352
- const result = await (0, BranchEvaluator_1.evaluateBranches)(currentStep.branches, branchCtx, aiEvaluator);
421
+ const aiEvaluator = (0, BranchEvaluator_js_1.createAiConditionEvaluator)(this.options.provider, history, context);
422
+ const result = await (0, BranchEvaluator_js_1.evaluateBranches)(currentStep.branches, branchCtx, aiEvaluator);
353
423
  if (result === undefined) {
354
424
  return undefined; // No branch matched → fall through to linear/AI selection
355
425
  }
@@ -362,8 +432,8 @@ class ResponsePipeline {
362
432
  // 1. Look up in current flow's step registry first (local step wins)
363
433
  const localStep = selectedFlow.getStep(result);
364
434
  if (localStep) {
365
- const updatedSession = (0, utils_1.enterStep)(session, localStep.id, localStep.description);
366
- utils_1.logger.debug(`[ResponsePipeline] Branch resolved to local step: ${localStep.id}`);
435
+ const updatedSession = (0, index_js_1.enterStep)(session, localStep.id, localStep.description);
436
+ index_js_1.logger.debug(`[ResponsePipeline] Branch resolved to local step: ${localStep.id}`);
367
437
  return { nextStep: localStep, session: updatedSession };
368
438
  }
369
439
  // 2. Look up in agent's flow registry
@@ -371,12 +441,12 @@ class ResponsePipeline {
371
441
  const targetFlow = flows.find(f => f.id === result || f.title === result);
372
442
  if (targetFlow) {
373
443
  // Treat as applyDirective({ goTo: result }) — enter the target flow
374
- utils_1.logger.debug(`[ResponsePipeline] Branch resolved to flow: ${targetFlow.title}`);
375
- const updatedSession = (0, session_1.enterFlow)(session, targetFlow.id, targetFlow.title);
444
+ index_js_1.logger.debug(`[ResponsePipeline] Branch resolved to flow: ${targetFlow.title}`);
445
+ const updatedSession = (0, session_js_1.enterFlow)(session, targetFlow.id, targetFlow.title);
376
446
  return { nextStep: undefined, session: updatedSession, flowChanged: targetFlow };
377
447
  }
378
448
  // 3. Neither → throw FlowConfigurationError
379
- throw new Step_1.FlowConfigurationError(`[FlowConfigurationError] Unresolved branch target: "${result}" does not match any step in flow "${selectedFlow.id}" or any flow in the agent. ` +
449
+ throw new Step_js_1.FlowConfigurationError(`[FlowConfigurationError] Unresolved branch target: "${result}" does not match any step in flow "${selectedFlow.id}" or any flow in the agent. ` +
380
450
  `Source: ${selectedFlow.id}.${currentStep.id}. Fix the branch "then" value to reference a valid step id or flow id/title.`);
381
451
  }
382
452
  /**
@@ -390,7 +460,7 @@ class ResponsePipeline {
390
460
  let updatedSession = session;
391
461
  // Apply state writes first
392
462
  if (directive.dataUpdate) {
393
- updatedSession = (0, utils_1.mergeCollected)(updatedSession, directive.dataUpdate);
463
+ updatedSession = (0, index_js_1.mergeCollected)(updatedSession, directive.dataUpdate);
394
464
  }
395
465
  // Handle position fields
396
466
  if (directive.goToStep) {
@@ -405,24 +475,24 @@ class ResponsePipeline {
405
475
  const flows = this.getFlows();
406
476
  const targetFlow = flows.find(f => f.id === flowTarget || f.title === flowTarget);
407
477
  if (targetFlow) {
408
- updatedSession = (0, session_1.enterFlow)(updatedSession, targetFlow.id, targetFlow.title);
409
- updatedSession = (0, utils_1.enterStep)(updatedSession, stepTarget);
478
+ updatedSession = (0, session_js_1.enterFlow)(updatedSession, targetFlow.id, targetFlow.title);
479
+ updatedSession = (0, index_js_1.enterStep)(updatedSession, stepTarget);
410
480
  // Try to resolve the target step instance for the caller
411
481
  const targetStepInstance = targetFlow.getStep(stepTarget);
412
- utils_1.logger.debug(`[ResponsePipeline] Branch directive goToStep → ${flowTarget}.${stepTarget}`);
482
+ index_js_1.logger.debug(`[ResponsePipeline] Branch directive goToStep → ${flowTarget}.${stepTarget}`);
413
483
  return { nextStep: targetStepInstance || undefined, session: updatedSession, flowChanged: targetFlow };
414
484
  }
415
- throw new Step_1.FlowConfigurationError(`[FlowConfigurationError] Branch directive goToStep targets unknown flow: "${flowTarget}" does not match any flow id or title. ` +
485
+ throw new Step_js_1.FlowConfigurationError(`[FlowConfigurationError] Branch directive goToStep targets unknown flow: "${flowTarget}" does not match any flow id or title. ` +
416
486
  `Fix the goToStep.flow value or use goTo to target a known flow.`);
417
487
  }
418
488
  // Local step reference
419
489
  const targetStep = selectedFlow.getStep(stepTarget);
420
490
  if (targetStep) {
421
- updatedSession = (0, utils_1.enterStep)(updatedSession, targetStep.id, targetStep.description);
422
- utils_1.logger.debug(`[ResponsePipeline] Branch directive goToStep → ${targetStep.id}`);
491
+ updatedSession = (0, index_js_1.enterStep)(updatedSession, targetStep.id, targetStep.description);
492
+ index_js_1.logger.debug(`[ResponsePipeline] Branch directive goToStep → ${targetStep.id}`);
423
493
  return { nextStep: targetStep, session: updatedSession };
424
494
  }
425
- throw new Step_1.FlowConfigurationError(`[FlowConfigurationError] Branch directive goToStep targets unknown step: "${stepTarget}" does not exist in flow "${selectedFlow.id}". ` +
495
+ throw new Step_js_1.FlowConfigurationError(`[FlowConfigurationError] Branch directive goToStep targets unknown step: "${stepTarget}" does not exist in flow "${selectedFlow.id}". ` +
426
496
  `Fix the goToStep value to reference a valid step id in the current flow.`);
427
497
  }
428
498
  if (directive.goTo) {
@@ -433,24 +503,24 @@ class ResponsePipeline {
433
503
  const flows = this.getFlows();
434
504
  const targetFlow = flows.find(f => f.id === flowTarget || f.title === flowTarget);
435
505
  if (targetFlow) {
436
- updatedSession = (0, session_1.enterFlow)(updatedSession, targetFlow.id, targetFlow.title);
506
+ updatedSession = (0, session_js_1.enterFlow)(updatedSession, targetFlow.id, targetFlow.title);
437
507
  // If goTo is an object with a step field, enter that step too
438
508
  if (typeof directive.goTo === 'object' && directive.goTo.step) {
439
- updatedSession = (0, utils_1.enterStep)(updatedSession, directive.goTo.step);
509
+ updatedSession = (0, index_js_1.enterStep)(updatedSession, directive.goTo.step);
440
510
  }
441
- utils_1.logger.debug(`[ResponsePipeline] Branch directive goTo → ${targetFlow.title}`);
511
+ index_js_1.logger.debug(`[ResponsePipeline] Branch directive goTo → ${targetFlow.title}`);
442
512
  return { nextStep: undefined, session: updatedSession, flowChanged: targetFlow };
443
513
  }
444
- throw new Step_1.FlowConfigurationError(`[FlowConfigurationError] Branch directive goTo targets unknown flow: "${flowTarget}" does not match any flow id or title. ` +
514
+ throw new Step_js_1.FlowConfigurationError(`[FlowConfigurationError] Branch directive goTo targets unknown flow: "${flowTarget}" does not match any flow id or title. ` +
445
515
  `Fix the goTo value to reference a valid flow.`);
446
516
  }
447
517
  }
448
518
  if (directive.complete) {
449
- utils_1.logger.debug(`[ResponsePipeline] Branch directive complete`);
519
+ index_js_1.logger.debug(`[ResponsePipeline] Branch directive complete`);
450
520
  return { nextStep: undefined, session: updatedSession };
451
521
  }
452
522
  if (directive.abort) {
453
- utils_1.logger.debug(`[ResponsePipeline] Branch directive abort`);
523
+ index_js_1.logger.debug(`[ResponsePipeline] Branch directive abort`);
454
524
  return { nextStep: undefined, session: updatedSession };
455
525
  }
456
526
  if (directive.reset) {
@@ -460,14 +530,14 @@ class ResponsePipeline {
460
530
  if (resetStep) {
461
531
  const targetStep = selectedFlow.getStep(resetStep);
462
532
  if (targetStep) {
463
- updatedSession = (0, utils_1.enterStep)(updatedSession, targetStep.id, targetStep.description);
533
+ updatedSession = (0, index_js_1.enterStep)(updatedSession, targetStep.id, targetStep.description);
464
534
  return { nextStep: targetStep, session: updatedSession };
465
535
  }
466
536
  }
467
537
  // Reset to initial step
468
538
  const initialStep = selectedFlow.initialStep;
469
- updatedSession = (0, utils_1.enterStep)(updatedSession, initialStep.id, initialStep.description);
470
- utils_1.logger.debug(`[ResponsePipeline] Branch directive reset → ${initialStep.id}`);
539
+ updatedSession = (0, index_js_1.enterStep)(updatedSession, initialStep.id, initialStep.description);
540
+ index_js_1.logger.debug(`[ResponsePipeline] Branch directive reset → ${initialStep.id}`);
471
541
  return { nextStep: initialStep, session: updatedSession };
472
542
  }
473
543
  // Directive with only non-position fields (e.g., just dataUpdate/contextUpdate/reply)
@@ -485,17 +555,20 @@ class ResponsePipeline {
485
555
  // Create a fresh chain tracker for this turn (Requirement 22.1)
486
556
  this.createChainTracker();
487
557
  // ROUTING SKIP OPTIMIZATION (Requirements 20.1, 20.2, 20.3):
488
- // When the current step has collect fields AND pre-extraction populates at least
489
- // one of those fields, skip FlowRouter.decideFlowAndStep for this turn.
490
- const routingSkipResult = await this.attemptRoutingSkipForCollect(params);
491
- if (routingSkipResult) {
558
+ // When the current step has collect fields AND step-scoped pre-extraction
559
+ // populates at least one of those fields, skip FlowRouter.decideFlowAndStep
560
+ // for this turn. The check's extraction result is reused by the fallthrough
561
+ // paths below so a turn costs at most ONE extraction LLM call.
562
+ const routingSkipCheck = await this.attemptRoutingSkipForCollect(params);
563
+ if (routingSkipCheck.skipResult) {
564
+ const skipResult = routingSkipCheck.skipResult;
492
565
  // Even when routing is skipped, run pre-signal phase if processor is present
493
566
  if (this.signalCoordinator.enabled) {
494
567
  const signalResult = await this.signalCoordinator.runPrePhase(params.session, params.context, params.history);
495
568
  // If signal halts, override the routing skip result
496
569
  if (signalResult.mergedDirective?.halt) {
497
570
  return {
498
- ...routingSkipResult,
571
+ ...skipResult,
499
572
  session: signalResult.updatedSession,
500
573
  signalFirings: signalResult.firings,
501
574
  signalHalted: true,
@@ -506,15 +579,20 @@ class ResponsePipeline {
506
579
  if (hasDirectivePositionField(signalResult.mergedDirective)) {
507
580
  return this.signalCoordinator.applyPositionDirective(signalResult);
508
581
  }
509
- // Non-position directive: propagate for pre-LLM augmentation
582
+ // Non-position directive: keep the skip result (extraction merges,
583
+ // step entry) and re-apply the signal phase's non-position mutations
510
584
  return {
511
- ...routingSkipResult,
512
- session: signalResult.updatedSession,
585
+ ...skipResult,
586
+ session: this.combineRoutingAndSignalSessions({
587
+ inputSession: params.session,
588
+ signalSession: signalResult.updatedSession,
589
+ routingSession: skipResult.session,
590
+ }),
513
591
  signalFirings: signalResult.firings,
514
592
  signalPreDirective: signalResult.mergedDirective || undefined,
515
593
  };
516
594
  }
517
- return routingSkipResult;
595
+ return skipResult;
518
596
  }
519
597
  // ── PARALLEL PRE-SIGNAL PHASE + ROUTING (Algorithm 5) ────────────────
520
598
  // When signalProcessor is present, run pre-signals in parallel with routing.
@@ -528,6 +606,7 @@ class ResponsePipeline {
528
606
  history: params.history,
529
607
  context: params.context,
530
608
  signal: params.signal,
609
+ allowedFlows: params.allowedFlows,
531
610
  }),
532
611
  ]);
533
612
  // ── Requirement 8.2: halt → discard routing, skip LLM ────────────
@@ -548,38 +627,41 @@ class ResponsePipeline {
548
627
  }
549
628
  // ── Requirement 8.4: non-position directive → use routing, propagate augmentation ──
550
629
  // ── Requirement 8.5: no directive → use routing as-is ─────────────
551
- let updatedSession = signalResult.updatedSession;
552
- // Apply data/context updates from signal to the routed session
630
+ // Base = routed session (position state AND router data merges such as
631
+ // flow initialData survive); the signal phase's non-position mutations
632
+ // (trigger state, handler data writes) are re-applied on top.
633
+ let updatedSession = this.combineRoutingAndSignalSessions({
634
+ inputSession: params.session,
635
+ signalSession: signalResult.updatedSession,
636
+ routingSession: routingResult.session,
637
+ });
638
+ // Explicit dataUpdate from the signal's merged directive lands last
553
639
  if (signalResult.mergedDirective?.dataUpdate) {
554
- updatedSession = (0, utils_1.mergeCollected)(updatedSession, signalResult.mergedDirective.dataUpdate);
640
+ updatedSession = (0, index_js_1.mergeCollected)(updatedSession, signalResult.mergedDirective.dataUpdate);
555
641
  }
556
- // Use routing result for flow/step, but carry signal session state
557
- // Merge routing session changes on top of signal session
558
- const routingSession = routingResult.session;
559
- updatedSession = {
560
- ...updatedSession,
561
- currentFlow: routingSession.currentFlow,
562
- currentStep: routingSession.currentStep,
563
- flowHistory: routingSession.flowHistory,
564
- pendingDirective: routingSession.pendingDirective,
565
- };
566
642
  const isFlowComplete = routingResult.isFlowComplete;
567
- // PRE-EXTRACTION: same logic as below — extract data from user message
643
+ // PRE-EXTRACTION: same logic as below — extract data from user message.
644
+ // Reuses the routing-skip check's step-scoped extraction when it already
645
+ // ran this turn (at most ONE extraction LLM call per turn).
568
646
  if (routingResult.selectedFlow && !isFlowComplete) {
569
- if (this.shouldPreExtractData(routingResult.selectedFlow)) {
570
- utils_1.logger.debug(`[ResponsePipeline] Pre-extracting data for flow: ${routingResult.selectedFlow.title}`);
571
- const extractedData = await this.preExtractFlowData({
647
+ let extractedData;
648
+ if (routingSkipCheck.extractionRan) {
649
+ extractedData = routingSkipCheck.extractedData;
650
+ }
651
+ else if (this.shouldPreExtractData(routingResult.selectedFlow)) {
652
+ index_js_1.logger.debug(`[ResponsePipeline] Pre-extracting data for flow: ${routingResult.selectedFlow.title}`);
653
+ extractedData = await this.preExtractFlowData({
572
654
  route: routingResult.selectedFlow,
573
655
  history: params.history,
574
656
  context: params.context,
575
657
  session: updatedSession,
576
658
  signal: params.signal,
577
659
  });
578
- if (extractedData && Object.keys(extractedData).length > 0) {
579
- utils_1.logger.debug(`[ResponsePipeline] Pre-extracted data:`, extractedData);
580
- updatedSession = (0, utils_1.mergeCollected)(updatedSession, extractedData);
581
- await this.updateCollectedData(extractedData);
582
- }
660
+ }
661
+ if (extractedData && Object.keys(extractedData).length > 0) {
662
+ index_js_1.logger.debug(`[ResponsePipeline] Pre-extracted data:`, extractedData);
663
+ updatedSession = (0, index_js_1.mergeCollected)(updatedSession, extractedData);
664
+ await this.updateCollectedData(extractedData);
583
665
  }
584
666
  }
585
667
  // Determine next step
@@ -595,9 +677,10 @@ class ResponsePipeline {
595
677
  selectedStep: stepResult.nextStep,
596
678
  responseDirectives: routingResult.responseDirectives,
597
679
  session: stepResult.session,
598
- isFlowComplete: stepResult.flowChanged ? false : isFlowComplete,
680
+ isFlowComplete: stepResult.isFlowComplete,
599
681
  signalFirings: signalResult.firings,
600
682
  signalPreDirective: signalResult.mergedDirective || undefined,
683
+ endedFlows: routingResult.endedFlows,
601
684
  };
602
685
  }
603
686
  // ── No signal processor: existing behavior (zero overhead) ────────────
@@ -606,30 +689,37 @@ class ResponsePipeline {
606
689
  history: params.history,
607
690
  context: params.context,
608
691
  signal: params.signal,
692
+ allowedFlows: params.allowedFlows,
609
693
  });
610
694
  let updatedSession = routingResult.session;
611
695
  const isFlowComplete = routingResult.isFlowComplete;
612
696
  // PRE-EXTRACTION: If entering a flow that collects data, extract data from user message first
613
- // This allows us to skip steps whose data is already provided
697
+ // This allows us to skip steps whose data is already provided.
698
+ // Reuses the routing-skip check's step-scoped extraction when it already
699
+ // ran this turn — at most ONE extraction LLM call per turn.
614
700
  if (routingResult.selectedFlow && !isFlowComplete) {
615
701
  // Always pre-extract when flow collects data (not just on new flow entry)
616
702
  // This ensures step selection has the most up-to-date data
617
- if (this.shouldPreExtractData(routingResult.selectedFlow)) {
618
- utils_1.logger.debug(`[ResponsePipeline] Pre-extracting data for flow: ${routingResult.selectedFlow.title}`);
619
- const extractedData = await this.preExtractFlowData({
703
+ let extractedData;
704
+ if (routingSkipCheck.extractionRan) {
705
+ extractedData = routingSkipCheck.extractedData;
706
+ }
707
+ else if (this.shouldPreExtractData(routingResult.selectedFlow)) {
708
+ index_js_1.logger.debug(`[ResponsePipeline] Pre-extracting data for flow: ${routingResult.selectedFlow.title}`);
709
+ extractedData = await this.preExtractFlowData({
620
710
  route: routingResult.selectedFlow,
621
711
  history: params.history,
622
712
  context: params.context,
623
713
  session: updatedSession,
624
714
  signal: params.signal,
625
715
  });
626
- if (extractedData && Object.keys(extractedData).length > 0) {
627
- utils_1.logger.debug(`[ResponsePipeline] Pre-extracted data:`, extractedData);
628
- // Merge pre-extracted data into session before step selection
629
- updatedSession = (0, utils_1.mergeCollected)(updatedSession, extractedData);
630
- // Also update agent's collected data
631
- await this.updateCollectedData(extractedData);
632
- }
716
+ }
717
+ if (extractedData && Object.keys(extractedData).length > 0) {
718
+ index_js_1.logger.debug(`[ResponsePipeline] Pre-extracted data:`, extractedData);
719
+ // Merge pre-extracted data into session before step selection
720
+ updatedSession = (0, index_js_1.mergeCollected)(updatedSession, extractedData);
721
+ // Also update agent's collected data
722
+ await this.updateCollectedData(extractedData);
633
723
  }
634
724
  }
635
725
  // Determine next step using pipeline method for consistency
@@ -645,12 +735,14 @@ class ResponsePipeline {
645
735
  selectedStep: stepResult.nextStep, // Use the determined next step
646
736
  responseDirectives: routingResult.responseDirectives,
647
737
  session: stepResult.session,
648
- // If a branch changed the flow, the original isFlowComplete no longer applies
649
- isFlowComplete: stepResult.flowChanged ? false : isFlowComplete,
738
+ // determineNextStep owns the verdict: a branch that resolved a position
739
+ // (new flow, or a step of this one) overrides the router's proposal.
740
+ isFlowComplete: stepResult.isFlowComplete,
741
+ endedFlows: routingResult.endedFlows,
650
742
  };
651
743
  }
652
744
  catch (error) {
653
- throw ResponseGenerationError_1.ResponseGenerationError.fromError(error, 'routing_optimization', params);
745
+ throw ResponseGenerationError_js_1.ResponseGenerationError.fromError(error, 'routing_optimization', params);
654
746
  }
655
747
  }
656
748
  /**
@@ -678,7 +770,7 @@ class ResponsePipeline {
678
770
  const currentStep = isInSameFlow && session.currentStep
679
771
  ? selectedFlow.getStep(session.currentStep.id)
680
772
  : undefined;
681
- utils_1.logger.debug(`[ResponsePipeline] Step determination: flow match=${isInSameFlow}, currentFlow=${session.currentFlow?.id}, selectedFlow=${selectedFlow.id}, currentStep=${currentStep?.id || 'none'}`);
773
+ index_js_1.logger.debug(`[ResponsePipeline] Step determination: flow match=${isInSameFlow}, currentFlow=${session.currentFlow?.id}, selectedFlow=${selectedFlow.id}, currentStep=${currentStep?.id || 'none'}`);
682
774
  // STEP 1 (Algorithm 1): branches win over linear chain
683
775
  if (currentStep?.branches && currentStep.branches.length > 0) {
684
776
  const branchResult = await this.evaluateStepBranches(currentStep, selectedFlow, session, context);
@@ -696,16 +788,16 @@ class ResponsePipeline {
696
788
  if (!nextStep) {
697
789
  // Get candidate steps based on current position in the flow
698
790
  const candidates = await this.flowRouter.getCandidateStepsWithConditions(selectedFlow, currentStep, // Pass current step instead of undefined to maintain progression
699
- (0, template_1.createTemplateContext)({ data: session.data, session, context }));
700
- utils_1.logger.debug(`[ResponsePipeline] Found ${candidates.length} candidate steps${currentStep ? ' from current step ' + currentStep.id : ' (new flow entry)'}`);
791
+ (0, template_js_1.createTemplateContext)({ data: session.data, session, context }));
792
+ index_js_1.logger.debug(`[ResponsePipeline] Found ${candidates.length} candidate steps${currentStep ? ' from current step ' + currentStep.id : ' (new flow entry)'}`);
701
793
  if (candidates.length > 0) {
702
794
  nextStep = candidates[0].step;
703
- utils_1.logger.debug(`[ResponsePipeline] Using first valid step: ${nextStep.id}${currentStep ? ' (progressing from ' + currentStep.id + ')' : ' for new flow'}`);
795
+ index_js_1.logger.debug(`[ResponsePipeline] Using first valid step: ${nextStep.id}${currentStep ? ' (progressing from ' + currentStep.id + ')' : ' for new flow'}`);
704
796
  }
705
797
  else {
706
798
  // Fallback to initial step even if it should be skipped
707
799
  nextStep = selectedFlow.initialStep;
708
- utils_1.logger.warn(`[FlowConfigurationError] No valid steps found: all candidates were skipped in flow. Falling back to initial step "${nextStep.id}". Review step skip conditions.`);
800
+ index_js_1.logger.warn(`[FlowConfigurationError] No valid steps found: all candidates were skipped in flow. Falling back to initial step "${nextStep.id}". Review step skip conditions.`);
709
801
  }
710
802
  }
711
803
  }
@@ -717,7 +809,7 @@ class ResponsePipeline {
717
809
  if (missingRequires.length > 0) {
718
810
  const warning = `[FlowConfigurationError] Cannot advance to step "${nextStep.description || nextStep.id}": ` +
719
811
  `missing required fields [${missingRequires.join(', ')}]. Staying at current step. Ensure preceding steps collect these fields.`;
720
- utils_1.logger.warn(warning);
812
+ index_js_1.logger.warn(warning);
721
813
  console.warn(warning);
722
814
  // Stay at the current step - don't enter the next one
723
815
  const currentStepId = session.currentStep?.id;
@@ -725,82 +817,101 @@ class ResponsePipeline {
725
817
  const currentStepInstance = selectedFlow.getStep(currentStepId);
726
818
  if (currentStepInstance) {
727
819
  nextStep = currentStepInstance;
728
- utils_1.logger.debug(`[ResponsePipeline] Staying at current step: ${nextStep.id} due to missing requires`);
820
+ index_js_1.logger.debug(`[ResponsePipeline] Staying at current step: ${nextStep.id} due to missing requires`);
729
821
  }
730
822
  }
731
823
  }
732
824
  else {
733
- session = (0, utils_1.enterStep)(session, nextStep.id, nextStep.description);
734
- utils_1.logger.debug(`[ResponsePipeline] Entered step: ${nextStep.id}`);
825
+ session = (0, index_js_1.enterStep)(session, nextStep.id, nextStep.description);
826
+ index_js_1.logger.debug(`[ResponsePipeline] Entered step: ${nextStep.id}`);
735
827
  }
736
828
  }
737
829
  else {
738
- session = (0, utils_1.enterStep)(session, nextStep.id, nextStep.description);
739
- utils_1.logger.debug(`[ResponsePipeline] Entered step: ${nextStep.id}`);
830
+ session = (0, index_js_1.enterStep)(session, nextStep.id, nextStep.description);
831
+ index_js_1.logger.debug(`[ResponsePipeline] Entered step: ${nextStep.id}`);
740
832
  }
741
833
  return { nextStep, session, flowTransition: false };
742
834
  }
743
835
  /**
744
- * Routing skip optimization (Requirements 20.1, 20.2, 20.3):
745
- * When the current step declares `collect` fields AND pre-extraction populates
746
- * at least one of those fields from the user's message, skip routing for this turn.
836
+ * Routing skip check (Requirements 20.1, 20.2, 20.3):
837
+ * When the current step declares `collect` fields AND step-scoped extraction
838
+ * populates at least one of those fields from the user's message, the caller
839
+ * skips routing for this turn (`skipResult`).
747
840
  *
748
- * Returns the routing result if the skip applies, or undefined to fall through
749
- * to normal routing.
841
+ * The extraction is scoped to EXACTLY this step's collect fields incidental
842
+ * mentions of other (e.g. other-flow) fields cannot pin the routing decision.
843
+ * It is skipped entirely when every collect field is already populated.
844
+ *
845
+ * Always returns what the check did so the caller can reuse the single
846
+ * extraction result in its normal path instead of extracting twice:
847
+ * - `extractionRan` — whether an extraction LLM call was made this turn.
848
+ * - `extractedData` — that call's result (empty when nothing found / not run).
750
849
  */
751
850
  async attemptRoutingSkipForCollect(params) {
752
851
  const { session } = params;
852
+ const notApplicable = { extractionRan: false, extractedData: {} };
753
853
  // Only applies when we already have a current flow and step
754
854
  if (!session.currentFlow || !session.currentStep) {
755
- return undefined;
855
+ return notApplicable;
756
856
  }
757
857
  // Also skip this optimization if there's a pending directive (it takes priority)
758
858
  if (session.pendingDirective) {
759
- return undefined;
859
+ return notApplicable;
760
860
  }
761
861
  // Look up the actual Flow and Step objects to access `collect`
762
862
  const currentFlow = this.getFlows().find((f) => f.id === session.currentFlow?.id);
763
863
  if (!currentFlow) {
764
- return undefined;
864
+ return notApplicable;
765
865
  }
766
866
  const currentStep = currentFlow.getStep(session.currentStep.id);
767
867
  if (!currentStep || !currentStep.collect || currentStep.collect.length === 0) {
768
- return undefined;
868
+ return notApplicable;
769
869
  }
770
- // We have a step with collect fields. Run pre-extraction to see if the
771
- // user's message populates any of them.
772
870
  const collectFields = currentStep.collect;
871
+ // Every relevant field already set — the skip cannot fire; don't spend
872
+ // an extraction LLM call probing for it.
873
+ const sessionRecord = (session.data ?? {});
874
+ const allPopulated = collectFields.every((field) => {
875
+ const value = sessionRecord[String(field)];
876
+ return value !== undefined && value !== null;
877
+ });
878
+ if (allPopulated) {
879
+ return notApplicable;
880
+ }
773
881
  // Snapshot current data for comparison
774
- const dataBefore = { ...session.data };
775
- // Run pre-extraction against the current flow
882
+ const dataBefore = { ...sessionRecord };
883
+ // Step-scoped pre-extraction: see if the user's message populates any of
884
+ // THIS step's collect fields.
776
885
  const extractedData = await this.preExtractFlowData({
777
886
  route: currentFlow,
778
887
  history: params.history,
779
888
  context: params.context,
780
889
  session,
781
890
  signal: params.signal,
891
+ restrictToFields: collectFields.map(String),
782
892
  });
783
893
  if (!extractedData || Object.keys(extractedData).length === 0) {
784
- return undefined;
894
+ return { extractionRan: true, extractedData: {} };
785
895
  }
786
896
  // Determine which collect fields were newly populated by pre-extraction
897
+ const extractedRecord = extractedData;
787
898
  const populatedCollectFields = [];
788
899
  for (const field of collectFields) {
789
- const key = field;
790
- const hadValue = dataBefore[field] !== undefined && dataBefore[field] !== null;
791
- const hasNewValue = extractedData[field] !== undefined && extractedData[field] !== null;
900
+ const key = String(field);
901
+ const hadValue = dataBefore[key] !== undefined && dataBefore[key] !== null;
902
+ const hasNewValue = extractedRecord[key] !== undefined && extractedRecord[key] !== null;
792
903
  if (hasNewValue && !hadValue) {
793
904
  populatedCollectFields.push(key);
794
905
  }
795
906
  }
796
907
  if (populatedCollectFields.length === 0) {
797
908
  // Pre-extraction didn't populate any declared collect field — no skip
798
- return undefined;
909
+ return { extractionRan: true, extractedData };
799
910
  }
800
911
  // ROUTING SKIP: pre-extraction populated collect fields → retain current flow/step
801
- utils_1.logger.debug(`[ResponsePipeline] Routing skip: pre-extraction populated collect fields [${populatedCollectFields.join(', ')}] for step "${currentStep.id}" — skipping FlowRouter`);
912
+ index_js_1.logger.debug(`[ResponsePipeline] Routing skip: pre-extraction populated collect fields [${populatedCollectFields.join(', ')}] for step "${currentStep.id}" — skipping FlowRouter`);
802
913
  // Merge extracted data into session
803
- const updatedSession = (0, utils_1.mergeCollected)(session, extractedData);
914
+ const updatedSession = (0, index_js_1.mergeCollected)(session, extractedData);
804
915
  await this.updateCollectedData(extractedData);
805
916
  // Determine next step using pipeline method for consistency
806
917
  // Pass the current flow/step as the routing result (retained)
@@ -812,11 +923,15 @@ class ResponsePipeline {
812
923
  context: params.context,
813
924
  });
814
925
  return {
815
- selectedFlow: stepResult.flowChanged || currentFlow,
816
- selectedStep: stepResult.nextStep,
817
- responseDirectives: undefined,
818
- session: stepResult.session,
819
- isFlowComplete: false,
926
+ extractionRan: true,
927
+ extractedData,
928
+ skipResult: {
929
+ selectedFlow: stepResult.flowChanged || currentFlow,
930
+ selectedStep: stepResult.nextStep,
931
+ responseDirectives: undefined,
932
+ session: stepResult.session,
933
+ isFlowComplete: stepResult.isFlowComplete,
934
+ },
820
935
  };
821
936
  }
822
937
  /**
@@ -835,20 +950,43 @@ class ResponsePipeline {
835
950
  const hasDataCollectionSteps = steps.some(step => step.collect && step.collect.length > 0);
836
951
  return hasDataCollectionSteps;
837
952
  }
953
+ /**
954
+ * Build an extraction schema limited to the given subset of agent schema
955
+ * fields. Used by the routing-skip probe so only the current step's collect
956
+ * fields are visible to the extractor.
957
+ */
958
+ buildFieldRestrictedSchema(agentSchema, fields) {
959
+ const properties = {};
960
+ for (const field of fields) {
961
+ const prop = agentSchema.properties?.[field];
962
+ if (prop) {
963
+ properties[field] = prop;
964
+ }
965
+ }
966
+ return {
967
+ type: "object",
968
+ description: `Extraction restricted to these fields: ${fields.join(', ')}`,
969
+ properties,
970
+ additionalProperties: false,
971
+ };
972
+ }
838
973
  /**
839
974
  * Pre-extract data from user message when entering a flow
840
975
  * This allows skipping steps whose data is already provided
841
976
  */
842
977
  async preExtractFlowData(params) {
843
- const { route: flow, history, signal } = params;
978
+ const { route: flow, history, signal, restrictToFields } = params;
844
979
  // Build a schema for data extraction based on flow's fields
845
- const extractionSchema = this.getSchema();
846
- if (!extractionSchema) {
847
- utils_1.logger.warn(`[ResponsePipeline] No schema available for pre-extraction`);
980
+ const agentSchema = this.getSchema();
981
+ if (!agentSchema) {
982
+ index_js_1.logger.warn(`[ResponsePipeline] No schema available for pre-extraction`);
848
983
  return {};
849
984
  }
985
+ const extractionSchema = restrictToFields
986
+ ? this.buildFieldRestrictedSchema(agentSchema, restrictToFields)
987
+ : agentSchema;
850
988
  // Get last user message
851
- const lastMessage = (0, utils_1.getLastMessageFromHistory)(history);
989
+ const lastMessage = (0, index_js_1.getLastMessageFromHistory)(history);
852
990
  // Build extraction prompt
853
991
  const extractionPrompt = [
854
992
  `Extract any relevant information from the user's message that matches the following data fields.`,
@@ -859,15 +997,20 @@ class ResponsePipeline {
859
997
  `Extract data for these fields if present:`,
860
998
  ];
861
999
  // Add field descriptions
862
- if (flow.requiredFields) {
863
- extractionPrompt.push(`Required fields: ${flow.requiredFields.join(', ')}`);
1000
+ if (restrictToFields) {
1001
+ extractionPrompt.push(`Only these fields: ${restrictToFields.join(', ')}`);
864
1002
  }
865
- if (flow.optionalFields) {
866
- extractionPrompt.push(`Optional fields: ${flow.optionalFields.join(', ')}`);
1003
+ else {
1004
+ if (flow.requiredFields) {
1005
+ extractionPrompt.push(`Required fields: ${flow.requiredFields.join(', ')}`);
1006
+ }
1007
+ if (flow.optionalFields) {
1008
+ extractionPrompt.push(`Optional fields: ${flow.optionalFields.join(', ')}`);
1009
+ }
867
1010
  }
868
1011
  extractionPrompt.push(``, `Return ONLY the extracted data as JSON. If no data can be extracted, return an empty object {}.`);
869
1012
  // Convert Event[] to HistoryItem[] for provider call
870
- const historyItems = (0, utils_1.eventsToHistory)(history);
1013
+ const historyItems = (0, index_js_1.eventsToHistory)(history);
871
1014
  // Call AI to extract data
872
1015
  try {
873
1016
  const result = await this.options.provider.generateMessage({
@@ -886,7 +1029,7 @@ class ResponsePipeline {
886
1029
  return result.structured || {};
887
1030
  }
888
1031
  catch (error) {
889
- utils_1.logger.error(`[ResponsePipeline] Pre-extraction failed:`, error);
1032
+ index_js_1.logger.error(`[ResponsePipeline] Pre-extraction failed:`, error);
890
1033
  return {};
891
1034
  }
892
1035
  }