@falai/agent 1.2.8 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (522) hide show
  1. package/README.md +40 -886
  2. package/dist/adapters/MemoryAdapter.js +2 -2
  3. package/dist/adapters/MemoryAdapter.js.map +1 -1
  4. package/dist/adapters/MongoAdapter.js +2 -2
  5. package/dist/adapters/MongoAdapter.js.map +1 -1
  6. package/dist/adapters/OpenSearchAdapter.d.ts.map +1 -1
  7. package/dist/adapters/OpenSearchAdapter.js +9 -7
  8. package/dist/adapters/OpenSearchAdapter.js.map +1 -1
  9. package/dist/adapters/PostgreSQLAdapter.d.ts +14 -0
  10. package/dist/adapters/PostgreSQLAdapter.d.ts.map +1 -1
  11. package/dist/adapters/PostgreSQLAdapter.js +25 -9
  12. package/dist/adapters/PostgreSQLAdapter.js.map +1 -1
  13. package/dist/adapters/PrismaAdapter.js +5 -5
  14. package/dist/adapters/PrismaAdapter.js.map +1 -1
  15. package/dist/adapters/RedisAdapter.js +2 -2
  16. package/dist/adapters/RedisAdapter.js.map +1 -1
  17. package/dist/adapters/SQLiteAdapter.d.ts +17 -0
  18. package/dist/adapters/SQLiteAdapter.d.ts.map +1 -1
  19. package/dist/adapters/SQLiteAdapter.js +30 -11
  20. package/dist/adapters/SQLiteAdapter.js.map +1 -1
  21. package/dist/cjs/adapters/MemoryAdapter.js +2 -2
  22. package/dist/cjs/adapters/MemoryAdapter.js.map +1 -1
  23. package/dist/cjs/adapters/MongoAdapter.js +2 -2
  24. package/dist/cjs/adapters/MongoAdapter.js.map +1 -1
  25. package/dist/cjs/adapters/OpenSearchAdapter.d.ts.map +1 -1
  26. package/dist/cjs/adapters/OpenSearchAdapter.js +9 -7
  27. package/dist/cjs/adapters/OpenSearchAdapter.js.map +1 -1
  28. package/dist/cjs/adapters/PostgreSQLAdapter.d.ts +14 -0
  29. package/dist/cjs/adapters/PostgreSQLAdapter.d.ts.map +1 -1
  30. package/dist/cjs/adapters/PostgreSQLAdapter.js +25 -9
  31. package/dist/cjs/adapters/PostgreSQLAdapter.js.map +1 -1
  32. package/dist/cjs/adapters/PrismaAdapter.js +5 -5
  33. package/dist/cjs/adapters/PrismaAdapter.js.map +1 -1
  34. package/dist/cjs/adapters/RedisAdapter.js +2 -2
  35. package/dist/cjs/adapters/RedisAdapter.js.map +1 -1
  36. package/dist/cjs/adapters/SQLiteAdapter.d.ts +17 -0
  37. package/dist/cjs/adapters/SQLiteAdapter.d.ts.map +1 -1
  38. package/dist/cjs/adapters/SQLiteAdapter.js +30 -11
  39. package/dist/cjs/adapters/SQLiteAdapter.js.map +1 -1
  40. package/dist/cjs/constants/index.d.ts +0 -9
  41. package/dist/cjs/constants/index.d.ts.map +1 -1
  42. package/dist/cjs/constants/index.js +2 -11
  43. package/dist/cjs/constants/index.js.map +1 -1
  44. package/dist/cjs/core/Agent.d.ts +119 -153
  45. package/dist/cjs/core/Agent.d.ts.map +1 -1
  46. package/dist/cjs/core/Agent.js +471 -324
  47. package/dist/cjs/core/Agent.js.map +1 -1
  48. package/dist/cjs/core/AutoChainExecutor.d.ts +107 -0
  49. package/dist/cjs/core/AutoChainExecutor.d.ts.map +1 -0
  50. package/dist/cjs/core/AutoChainExecutor.js +297 -0
  51. package/dist/cjs/core/AutoChainExecutor.js.map +1 -0
  52. package/dist/cjs/core/BranchEvaluator.d.ts +54 -0
  53. package/dist/cjs/core/BranchEvaluator.d.ts.map +1 -0
  54. package/dist/cjs/core/BranchEvaluator.js +130 -0
  55. package/dist/cjs/core/BranchEvaluator.js.map +1 -0
  56. package/dist/cjs/core/DirectiveBus.d.ts +88 -0
  57. package/dist/cjs/core/DirectiveBus.d.ts.map +1 -0
  58. package/dist/cjs/core/DirectiveBus.js +196 -0
  59. package/dist/cjs/core/DirectiveBus.js.map +1 -0
  60. package/dist/cjs/core/DirectiveChainTracker.d.ts +49 -0
  61. package/dist/cjs/core/DirectiveChainTracker.d.ts.map +1 -0
  62. package/dist/cjs/core/DirectiveChainTracker.js +121 -0
  63. package/dist/cjs/core/DirectiveChainTracker.js.map +1 -0
  64. package/dist/cjs/core/Flow.d.ts +186 -0
  65. package/dist/cjs/core/Flow.d.ts.map +1 -0
  66. package/dist/cjs/core/Flow.js +550 -0
  67. package/dist/cjs/core/Flow.js.map +1 -0
  68. package/dist/cjs/core/FlowRouter.d.ts +182 -0
  69. package/dist/cjs/core/FlowRouter.d.ts.map +1 -0
  70. package/dist/cjs/core/{RoutingEngine.js → FlowRouter.js} +323 -306
  71. package/dist/cjs/core/FlowRouter.js.map +1 -0
  72. package/dist/cjs/core/PersistenceManager.d.ts +2 -2
  73. package/dist/cjs/core/PersistenceManager.d.ts.map +1 -1
  74. package/dist/cjs/core/PersistenceManager.js +7 -7
  75. package/dist/cjs/core/PersistenceManager.js.map +1 -1
  76. package/dist/cjs/core/PromptComposer.d.ts +21 -8
  77. package/dist/cjs/core/PromptComposer.d.ts.map +1 -1
  78. package/dist/cjs/core/PromptComposer.js +182 -105
  79. package/dist/cjs/core/PromptComposer.js.map +1 -1
  80. package/dist/cjs/core/PromptSectionCache.d.ts +1 -1
  81. package/dist/cjs/core/PromptSectionCache.js +1 -1
  82. package/dist/cjs/core/ResponseEngine.d.ts +18 -8
  83. package/dist/cjs/core/ResponseEngine.d.ts.map +1 -1
  84. package/dist/cjs/core/ResponseEngine.js +38 -36
  85. package/dist/cjs/core/ResponseEngine.js.map +1 -1
  86. package/dist/cjs/core/ResponseModal.d.ts +73 -56
  87. package/dist/cjs/core/ResponseModal.d.ts.map +1 -1
  88. package/dist/cjs/core/ResponseModal.js +1191 -1014
  89. package/dist/cjs/core/ResponseModal.js.map +1 -1
  90. package/dist/cjs/core/ResponsePipeline.d.ts +124 -26
  91. package/dist/cjs/core/ResponsePipeline.d.ts.map +1 -1
  92. package/dist/cjs/core/ResponsePipeline.js +509 -136
  93. package/dist/cjs/core/ResponsePipeline.js.map +1 -1
  94. package/dist/cjs/core/SignalEvaluator.d.ts +86 -0
  95. package/dist/cjs/core/SignalEvaluator.d.ts.map +1 -0
  96. package/dist/cjs/core/SignalEvaluator.js +333 -0
  97. package/dist/cjs/core/SignalEvaluator.js.map +1 -0
  98. package/dist/cjs/core/SignalProcessor.d.ts +152 -0
  99. package/dist/cjs/core/SignalProcessor.d.ts.map +1 -0
  100. package/dist/cjs/core/SignalProcessor.js +562 -0
  101. package/dist/cjs/core/SignalProcessor.js.map +1 -0
  102. package/dist/cjs/core/Step.d.ts +43 -32
  103. package/dist/cjs/core/Step.d.ts.map +1 -1
  104. package/dist/cjs/core/Step.js +221 -126
  105. package/dist/cjs/core/Step.js.map +1 -1
  106. package/dist/cjs/core/StreamingToolExecutor.d.ts +2 -2
  107. package/dist/cjs/core/StreamingToolExecutor.d.ts.map +1 -1
  108. package/dist/cjs/core/StreamingToolExecutor.js.map +1 -1
  109. package/dist/cjs/core/ToolManager.d.ts +44 -13
  110. package/dist/cjs/core/ToolManager.d.ts.map +1 -1
  111. package/dist/cjs/core/ToolManager.js +174 -91
  112. package/dist/cjs/core/ToolManager.js.map +1 -1
  113. package/dist/cjs/core/createAgent.d.ts +35 -0
  114. package/dist/cjs/core/createAgent.d.ts.map +1 -0
  115. package/dist/cjs/core/createAgent.js +39 -0
  116. package/dist/cjs/core/createAgent.js.map +1 -0
  117. package/dist/cjs/core/flow-namespace.d.ts +49 -0
  118. package/dist/cjs/core/flow-namespace.d.ts.map +1 -0
  119. package/dist/cjs/core/flow-namespace.js +171 -0
  120. package/dist/cjs/core/flow-namespace.js.map +1 -0
  121. package/dist/cjs/index.d.ts +11 -14
  122. package/dist/cjs/index.d.ts.map +1 -1
  123. package/dist/cjs/index.js +18 -22
  124. package/dist/cjs/index.js.map +1 -1
  125. package/dist/cjs/providers/AnthropicProvider.d.ts +1 -1
  126. package/dist/cjs/providers/AnthropicProvider.js +1 -1
  127. package/dist/cjs/providers/GeminiProvider.d.ts +1 -1
  128. package/dist/cjs/providers/GeminiProvider.d.ts.map +1 -1
  129. package/dist/cjs/providers/GeminiProvider.js +1 -1
  130. package/dist/cjs/providers/GeminiProvider.js.map +1 -1
  131. package/dist/cjs/providers/OpenAIProvider.d.ts +1 -1
  132. package/dist/cjs/providers/OpenAIProvider.d.ts.map +1 -1
  133. package/dist/cjs/providers/OpenAIProvider.js +1 -1
  134. package/dist/cjs/providers/OpenAIProvider.js.map +1 -1
  135. package/dist/cjs/types/agent.d.ts +183 -54
  136. package/dist/cjs/types/agent.d.ts.map +1 -1
  137. package/dist/cjs/types/agent.js +0 -6
  138. package/dist/cjs/types/agent.js.map +1 -1
  139. package/dist/cjs/types/ai.d.ts +3 -3
  140. package/dist/cjs/types/ai.d.ts.map +1 -1
  141. package/dist/cjs/types/errors.d.ts +15 -0
  142. package/dist/cjs/types/errors.d.ts.map +1 -0
  143. package/dist/cjs/types/errors.js +22 -0
  144. package/dist/cjs/types/errors.js.map +1 -0
  145. package/dist/cjs/types/flow.d.ts +513 -0
  146. package/dist/cjs/types/flow.d.ts.map +1 -0
  147. package/dist/cjs/types/{route.js → flow.js} +2 -2
  148. package/dist/cjs/types/flow.js.map +1 -0
  149. package/dist/cjs/types/index.d.ts +7 -6
  150. package/dist/cjs/types/index.d.ts.map +1 -1
  151. package/dist/cjs/types/index.js +6 -2
  152. package/dist/cjs/types/index.js.map +1 -1
  153. package/dist/cjs/types/persistence.d.ts +11 -7
  154. package/dist/cjs/types/persistence.d.ts.map +1 -1
  155. package/dist/cjs/types/routing.d.ts +1 -1
  156. package/dist/cjs/types/routing.d.ts.map +1 -1
  157. package/dist/cjs/types/session.d.ts +24 -23
  158. package/dist/cjs/types/session.d.ts.map +1 -1
  159. package/dist/cjs/types/signals.d.ts +248 -0
  160. package/dist/cjs/types/signals.d.ts.map +1 -0
  161. package/dist/cjs/types/signals.js +11 -0
  162. package/dist/cjs/types/signals.js.map +1 -0
  163. package/dist/cjs/types/template.d.ts +2 -8
  164. package/dist/cjs/types/template.d.ts.map +1 -1
  165. package/dist/cjs/types/tool.d.ts +36 -29
  166. package/dist/cjs/types/tool.d.ts.map +1 -1
  167. package/dist/cjs/types/tool.js +1 -1
  168. package/dist/cjs/types/tool.js.map +1 -1
  169. package/dist/cjs/utils/condition.d.ts +7 -1
  170. package/dist/cjs/utils/condition.d.ts.map +1 -1
  171. package/dist/cjs/utils/condition.js.map +1 -1
  172. package/dist/cjs/utils/id.d.ts +13 -5
  173. package/dist/cjs/utils/id.d.ts.map +1 -1
  174. package/dist/cjs/utils/id.js +24 -10
  175. package/dist/cjs/utils/id.js.map +1 -1
  176. package/dist/cjs/utils/index.d.ts +2 -2
  177. package/dist/cjs/utils/index.d.ts.map +1 -1
  178. package/dist/cjs/utils/index.js +7 -3
  179. package/dist/cjs/utils/index.js.map +1 -1
  180. package/dist/cjs/utils/session.d.ts +44 -5
  181. package/dist/cjs/utils/session.d.ts.map +1 -1
  182. package/dist/cjs/utils/session.js +197 -38
  183. package/dist/cjs/utils/session.js.map +1 -1
  184. package/dist/constants/index.d.ts +0 -9
  185. package/dist/constants/index.d.ts.map +1 -1
  186. package/dist/constants/index.js +3 -9
  187. package/dist/constants/index.js.map +1 -1
  188. package/dist/core/Agent.d.ts +119 -153
  189. package/dist/core/Agent.d.ts.map +1 -1
  190. package/dist/core/Agent.js +472 -325
  191. package/dist/core/Agent.js.map +1 -1
  192. package/dist/core/AutoChainExecutor.d.ts +107 -0
  193. package/dist/core/AutoChainExecutor.d.ts.map +1 -0
  194. package/dist/core/AutoChainExecutor.js +293 -0
  195. package/dist/core/AutoChainExecutor.js.map +1 -0
  196. package/dist/core/BranchEvaluator.d.ts +54 -0
  197. package/dist/core/BranchEvaluator.d.ts.map +1 -0
  198. package/dist/core/BranchEvaluator.js +126 -0
  199. package/dist/core/BranchEvaluator.js.map +1 -0
  200. package/dist/core/DirectiveBus.d.ts +88 -0
  201. package/dist/core/DirectiveBus.d.ts.map +1 -0
  202. package/dist/core/DirectiveBus.js +192 -0
  203. package/dist/core/DirectiveBus.js.map +1 -0
  204. package/dist/core/DirectiveChainTracker.d.ts +49 -0
  205. package/dist/core/DirectiveChainTracker.d.ts.map +1 -0
  206. package/dist/core/DirectiveChainTracker.js +117 -0
  207. package/dist/core/DirectiveChainTracker.js.map +1 -0
  208. package/dist/core/Flow.d.ts +186 -0
  209. package/dist/core/Flow.d.ts.map +1 -0
  210. package/dist/core/Flow.js +546 -0
  211. package/dist/core/Flow.js.map +1 -0
  212. package/dist/core/FlowRouter.d.ts +182 -0
  213. package/dist/core/FlowRouter.d.ts.map +1 -0
  214. package/dist/core/{RoutingEngine.js → FlowRouter.js} +322 -305
  215. package/dist/core/FlowRouter.js.map +1 -0
  216. package/dist/core/PersistenceManager.d.ts +2 -2
  217. package/dist/core/PersistenceManager.d.ts.map +1 -1
  218. package/dist/core/PersistenceManager.js +7 -7
  219. package/dist/core/PersistenceManager.js.map +1 -1
  220. package/dist/core/PromptComposer.d.ts +21 -8
  221. package/dist/core/PromptComposer.d.ts.map +1 -1
  222. package/dist/core/PromptComposer.js +183 -106
  223. package/dist/core/PromptComposer.js.map +1 -1
  224. package/dist/core/PromptSectionCache.d.ts +1 -1
  225. package/dist/core/PromptSectionCache.js +1 -1
  226. package/dist/core/ResponseEngine.d.ts +18 -8
  227. package/dist/core/ResponseEngine.d.ts.map +1 -1
  228. package/dist/core/ResponseEngine.js +38 -36
  229. package/dist/core/ResponseEngine.js.map +1 -1
  230. package/dist/core/ResponseModal.d.ts +73 -56
  231. package/dist/core/ResponseModal.d.ts.map +1 -1
  232. package/dist/core/ResponseModal.js +1193 -1016
  233. package/dist/core/ResponseModal.js.map +1 -1
  234. package/dist/core/ResponsePipeline.d.ts +124 -26
  235. package/dist/core/ResponsePipeline.d.ts.map +1 -1
  236. package/dist/core/ResponsePipeline.js +509 -137
  237. package/dist/core/ResponsePipeline.js.map +1 -1
  238. package/dist/core/SignalEvaluator.d.ts +86 -0
  239. package/dist/core/SignalEvaluator.d.ts.map +1 -0
  240. package/dist/core/SignalEvaluator.js +326 -0
  241. package/dist/core/SignalEvaluator.js.map +1 -0
  242. package/dist/core/SignalProcessor.d.ts +152 -0
  243. package/dist/core/SignalProcessor.d.ts.map +1 -0
  244. package/dist/core/SignalProcessor.js +555 -0
  245. package/dist/core/SignalProcessor.js.map +1 -0
  246. package/dist/core/Step.d.ts +43 -32
  247. package/dist/core/Step.d.ts.map +1 -1
  248. package/dist/core/Step.js +220 -126
  249. package/dist/core/Step.js.map +1 -1
  250. package/dist/core/StreamingToolExecutor.d.ts +2 -2
  251. package/dist/core/StreamingToolExecutor.d.ts.map +1 -1
  252. package/dist/core/StreamingToolExecutor.js.map +1 -1
  253. package/dist/core/ToolManager.d.ts +44 -13
  254. package/dist/core/ToolManager.d.ts.map +1 -1
  255. package/dist/core/ToolManager.js +174 -91
  256. package/dist/core/ToolManager.js.map +1 -1
  257. package/dist/core/createAgent.d.ts +35 -0
  258. package/dist/core/createAgent.d.ts.map +1 -0
  259. package/dist/core/createAgent.js +36 -0
  260. package/dist/core/createAgent.js.map +1 -0
  261. package/dist/core/flow-namespace.d.ts +49 -0
  262. package/dist/core/flow-namespace.d.ts.map +1 -0
  263. package/dist/core/flow-namespace.js +168 -0
  264. package/dist/core/flow-namespace.js.map +1 -0
  265. package/dist/index.d.ts +11 -14
  266. package/dist/index.d.ts.map +1 -1
  267. package/dist/index.js +9 -12
  268. package/dist/index.js.map +1 -1
  269. package/dist/providers/AnthropicProvider.d.ts +1 -1
  270. package/dist/providers/AnthropicProvider.js +1 -1
  271. package/dist/providers/GeminiProvider.d.ts +1 -1
  272. package/dist/providers/GeminiProvider.d.ts.map +1 -1
  273. package/dist/providers/GeminiProvider.js +1 -1
  274. package/dist/providers/GeminiProvider.js.map +1 -1
  275. package/dist/providers/OpenAIProvider.d.ts +1 -1
  276. package/dist/providers/OpenAIProvider.d.ts.map +1 -1
  277. package/dist/providers/OpenAIProvider.js +1 -1
  278. package/dist/providers/OpenAIProvider.js.map +1 -1
  279. package/dist/types/agent.d.ts +183 -54
  280. package/dist/types/agent.d.ts.map +1 -1
  281. package/dist/types/agent.js +0 -6
  282. package/dist/types/agent.js.map +1 -1
  283. package/dist/types/ai.d.ts +3 -3
  284. package/dist/types/ai.d.ts.map +1 -1
  285. package/dist/types/errors.d.ts +15 -0
  286. package/dist/types/errors.d.ts.map +1 -0
  287. package/dist/types/errors.js +18 -0
  288. package/dist/types/errors.js.map +1 -0
  289. package/dist/types/flow.d.ts +513 -0
  290. package/dist/types/flow.d.ts.map +1 -0
  291. package/dist/types/flow.js +5 -0
  292. package/dist/types/flow.js.map +1 -0
  293. package/dist/types/index.d.ts +7 -6
  294. package/dist/types/index.d.ts.map +1 -1
  295. package/dist/types/index.js +4 -1
  296. package/dist/types/index.js.map +1 -1
  297. package/dist/types/persistence.d.ts +11 -7
  298. package/dist/types/persistence.d.ts.map +1 -1
  299. package/dist/types/routing.d.ts +1 -1
  300. package/dist/types/routing.d.ts.map +1 -1
  301. package/dist/types/session.d.ts +24 -23
  302. package/dist/types/session.d.ts.map +1 -1
  303. package/dist/types/signals.d.ts +248 -0
  304. package/dist/types/signals.d.ts.map +1 -0
  305. package/dist/types/signals.js +10 -0
  306. package/dist/types/signals.js.map +1 -0
  307. package/dist/types/template.d.ts +2 -8
  308. package/dist/types/template.d.ts.map +1 -1
  309. package/dist/types/tool.d.ts +36 -29
  310. package/dist/types/tool.d.ts.map +1 -1
  311. package/dist/types/tool.js +1 -1
  312. package/dist/types/tool.js.map +1 -1
  313. package/dist/utils/condition.d.ts +7 -1
  314. package/dist/utils/condition.d.ts.map +1 -1
  315. package/dist/utils/condition.js.map +1 -1
  316. package/dist/utils/id.d.ts +13 -5
  317. package/dist/utils/id.d.ts.map +1 -1
  318. package/dist/utils/id.js +22 -9
  319. package/dist/utils/id.js.map +1 -1
  320. package/dist/utils/index.d.ts +2 -2
  321. package/dist/utils/index.d.ts.map +1 -1
  322. package/dist/utils/index.js +2 -2
  323. package/dist/utils/index.js.map +1 -1
  324. package/dist/utils/session.d.ts +44 -5
  325. package/dist/utils/session.d.ts.map +1 -1
  326. package/dist/utils/session.js +193 -37
  327. package/dist/utils/session.js.map +1 -1
  328. package/docs/README.md +22 -200
  329. package/docs/concepts/architecture.md +281 -0
  330. package/docs/concepts/directives.md +400 -0
  331. package/docs/concepts/pipeline.md +399 -0
  332. package/docs/guides/branching.md +263 -0
  333. package/docs/guides/compaction.md +163 -0
  334. package/docs/guides/conditions.md +167 -0
  335. package/docs/guides/error-handling.md +176 -0
  336. package/docs/guides/flow-control.md +409 -0
  337. package/docs/guides/instructions.md +210 -0
  338. package/docs/guides/persistence.md +182 -0
  339. package/docs/guides/streaming.md +137 -0
  340. package/docs/migration/README.md +14 -0
  341. package/docs/migration/route-to-flow.md +561 -0
  342. package/docs/migration/v1-to-v2.md +909 -0
  343. package/docs/reference/adapters.md +481 -0
  344. package/docs/reference/branches.md +241 -0
  345. package/docs/reference/create-agent.md +186 -0
  346. package/docs/reference/directive.md +243 -0
  347. package/docs/reference/errors.md +122 -0
  348. package/docs/reference/flow.md +238 -0
  349. package/docs/reference/instruction.md +177 -0
  350. package/docs/reference/pre-directive.md +131 -0
  351. package/docs/reference/providers.md +227 -0
  352. package/docs/reference/signals.md +356 -0
  353. package/docs/reference/step.md +339 -0
  354. package/docs/reference/tool.md +269 -0
  355. package/docs/start/01-install.md +81 -0
  356. package/docs/start/02-first-agent.md +196 -0
  357. package/docs/start/03-collect-data.md +222 -0
  358. package/docs/start/04-add-tools.md +276 -0
  359. package/docs/start/05-go-to-production.md +216 -0
  360. package/examples/01-quickstart.ts +20 -0
  361. package/examples/02-data-extraction.ts +90 -0
  362. package/examples/03-tools.ts +136 -0
  363. package/examples/04-instructions.ts +100 -0
  364. package/examples/05-branching.ts +140 -0
  365. package/examples/06-flow-control.ts +103 -0
  366. package/examples/07-streaming.ts +69 -0
  367. package/examples/08-persistence.ts +98 -0
  368. package/examples/09-signals.ts +144 -0
  369. package/examples/tsconfig.json +30 -0
  370. package/package.json +2 -1
  371. package/src/adapters/MemoryAdapter.ts +3 -3
  372. package/src/adapters/MongoAdapter.ts +3 -3
  373. package/src/adapters/OpenSearchAdapter.ts +10 -8
  374. package/src/adapters/PostgreSQLAdapter.ts +26 -10
  375. package/src/adapters/PrismaAdapter.ts +6 -6
  376. package/src/adapters/RedisAdapter.ts +3 -3
  377. package/src/adapters/SQLiteAdapter.ts +31 -12
  378. package/src/constants/index.ts +2 -10
  379. package/src/core/Agent.ts +585 -374
  380. package/src/core/AutoChainExecutor.ts +440 -0
  381. package/src/core/BranchEvaluator.ts +167 -0
  382. package/src/core/DirectiveBus.ts +248 -0
  383. package/src/core/DirectiveChainTracker.ts +144 -0
  384. package/src/core/Flow.ts +666 -0
  385. package/src/core/{RoutingEngine.ts → FlowRouter.ts} +385 -365
  386. package/src/core/PersistenceManager.ts +8 -8
  387. package/src/core/PromptComposer.ts +209 -140
  388. package/src/core/PromptSectionCache.ts +1 -1
  389. package/src/core/ResponseEngine.ts +61 -46
  390. package/src/core/ResponseModal.ts +1453 -1240
  391. package/src/core/ResponsePipeline.ts +655 -175
  392. package/src/core/SignalEvaluator.ts +420 -0
  393. package/src/core/SignalProcessor.ts +723 -0
  394. package/src/core/Step.ts +279 -176
  395. package/src/core/StreamingToolExecutor.ts +4 -4
  396. package/src/core/ToolManager.ts +200 -97
  397. package/src/core/createAgent.ts +40 -0
  398. package/src/core/flow-namespace.ts +219 -0
  399. package/src/index.ts +42 -36
  400. package/src/providers/AnthropicProvider.ts +2 -2
  401. package/src/providers/GeminiProvider.ts +2 -2
  402. package/src/providers/OpenAIProvider.ts +2 -2
  403. package/src/types/agent.ts +182 -53
  404. package/src/types/ai.ts +3 -3
  405. package/src/types/errors.ts +18 -0
  406. package/src/types/flow.ts +590 -0
  407. package/src/types/index.ts +43 -16
  408. package/src/types/persistence.ts +12 -8
  409. package/src/types/routing.ts +1 -1
  410. package/src/types/session.ts +26 -23
  411. package/src/types/signals.ts +321 -0
  412. package/src/types/template.ts +3 -11
  413. package/src/types/tool.ts +50 -42
  414. package/src/utils/condition.ts +13 -4
  415. package/src/utils/id.ts +27 -9
  416. package/src/utils/index.ts +6 -2
  417. package/src/utils/session.ts +238 -42
  418. package/dist/cjs/core/BatchExecutor.d.ts +0 -359
  419. package/dist/cjs/core/BatchExecutor.d.ts.map +0 -1
  420. package/dist/cjs/core/BatchExecutor.js +0 -861
  421. package/dist/cjs/core/BatchExecutor.js.map +0 -1
  422. package/dist/cjs/core/BatchPromptBuilder.d.ts +0 -89
  423. package/dist/cjs/core/BatchPromptBuilder.d.ts.map +0 -1
  424. package/dist/cjs/core/BatchPromptBuilder.js +0 -223
  425. package/dist/cjs/core/BatchPromptBuilder.js.map +0 -1
  426. package/dist/cjs/core/Route.d.ts +0 -180
  427. package/dist/cjs/core/Route.d.ts.map +0 -1
  428. package/dist/cjs/core/Route.js +0 -542
  429. package/dist/cjs/core/Route.js.map +0 -1
  430. package/dist/cjs/core/RoutingEngine.d.ts +0 -185
  431. package/dist/cjs/core/RoutingEngine.d.ts.map +0 -1
  432. package/dist/cjs/core/RoutingEngine.js.map +0 -1
  433. package/dist/cjs/types/route.d.ts +0 -336
  434. package/dist/cjs/types/route.d.ts.map +0 -1
  435. package/dist/cjs/types/route.js.map +0 -1
  436. package/dist/core/BatchExecutor.d.ts +0 -359
  437. package/dist/core/BatchExecutor.d.ts.map +0 -1
  438. package/dist/core/BatchExecutor.js +0 -856
  439. package/dist/core/BatchExecutor.js.map +0 -1
  440. package/dist/core/BatchPromptBuilder.d.ts +0 -89
  441. package/dist/core/BatchPromptBuilder.d.ts.map +0 -1
  442. package/dist/core/BatchPromptBuilder.js +0 -219
  443. package/dist/core/BatchPromptBuilder.js.map +0 -1
  444. package/dist/core/Route.d.ts +0 -180
  445. package/dist/core/Route.d.ts.map +0 -1
  446. package/dist/core/Route.js +0 -538
  447. package/dist/core/Route.js.map +0 -1
  448. package/dist/core/RoutingEngine.d.ts +0 -185
  449. package/dist/core/RoutingEngine.d.ts.map +0 -1
  450. package/dist/core/RoutingEngine.js.map +0 -1
  451. package/dist/types/route.d.ts +0 -336
  452. package/dist/types/route.d.ts.map +0 -1
  453. package/dist/types/route.js +0 -5
  454. package/dist/types/route.js.map +0 -1
  455. package/docs/CONTRIBUTING.md +0 -521
  456. package/docs/api/README.md +0 -3299
  457. package/docs/api/overview.md +0 -1410
  458. package/docs/architecture/data-extraction-flow.md +0 -360
  459. package/docs/architecture/multi-step-execution.md +0 -277
  460. package/docs/core/agent/README.md +0 -938
  461. package/docs/core/agent/context-management.md +0 -796
  462. package/docs/core/agent/rules-and-prohibitions.md +0 -113
  463. package/docs/core/agent/session-management.md +0 -693
  464. package/docs/core/ai-integration/prompt-composition.md +0 -355
  465. package/docs/core/ai-integration/providers.md +0 -515
  466. package/docs/core/ai-integration/response-processing.md +0 -433
  467. package/docs/core/conversation-flows/data-collection.md +0 -772
  468. package/docs/core/conversation-flows/route-dsl.md +0 -509
  469. package/docs/core/conversation-flows/routes.md +0 -249
  470. package/docs/core/conversation-flows/step-transitions.md +0 -731
  471. package/docs/core/conversation-flows/steps.md +0 -268
  472. package/docs/core/error-handling.md +0 -830
  473. package/docs/core/persistence/adapters.md +0 -255
  474. package/docs/core/persistence/session-storage.md +0 -656
  475. package/docs/core/routing/intelligent-routing.md +0 -470
  476. package/docs/core/tools/enhanced-tool.md +0 -186
  477. package/docs/core/tools/streaming-execution.md +0 -161
  478. package/docs/core/tools/tool-definition.md +0 -970
  479. package/docs/core/tools/tool-scoping.md +0 -819
  480. package/docs/guides/advanced-patterns/publishing.md +0 -186
  481. package/docs/guides/context-compaction.md +0 -96
  482. package/docs/guides/error-handling-patterns.md +0 -578
  483. package/docs/guides/getting-started/README.md +0 -795
  484. package/docs/guides/migration/README.md +0 -101
  485. package/docs/guides/migration/flexible-routing-conditions.md +0 -375
  486. package/docs/guides/migration/multi-step-execution.md +0 -393
  487. package/docs/guides/migration/response-modal-refactor.md +0 -518
  488. package/docs/guides/prompt-optimization.md +0 -164
  489. package/examples/advanced-patterns/context-compaction.ts +0 -223
  490. package/examples/advanced-patterns/knowledge-based-agent.ts +0 -735
  491. package/examples/advanced-patterns/persistent-onboarding.ts +0 -728
  492. package/examples/advanced-patterns/route-lifecycle-hooks.ts +0 -556
  493. package/examples/advanced-patterns/streaming-responses.ts +0 -656
  494. package/examples/ai-providers/anthropic-integration.ts +0 -388
  495. package/examples/ai-providers/openai-integration.ts +0 -228
  496. package/examples/condition-patterns/function-only-conditions.ts +0 -365
  497. package/examples/condition-patterns/mixed-array-conditions.ts +0 -477
  498. package/examples/condition-patterns/route-skipif-patterns.ts +0 -468
  499. package/examples/condition-patterns/step-skipif-patterns.ts +0 -0
  500. package/examples/condition-patterns/string-only-conditions.ts +0 -296
  501. package/examples/conversation-flows/completion-transitions.ts +0 -318
  502. package/examples/core-concepts/basic-agent.ts +0 -503
  503. package/examples/core-concepts/modern-streaming-api.ts +0 -309
  504. package/examples/core-concepts/schema-driven-extraction.ts +0 -332
  505. package/examples/core-concepts/session-management.ts +0 -494
  506. package/examples/integrations/database-integration.ts +0 -631
  507. package/examples/integrations/healthcare-integration.ts +0 -595
  508. package/examples/integrations/search-integration.ts +0 -530
  509. package/examples/integrations/server-session-management.ts +0 -307
  510. package/examples/persistence/custom-adapter.ts +0 -526
  511. package/examples/persistence/database-persistence.ts +0 -583
  512. package/examples/persistence/memory-sessions.ts +0 -495
  513. package/examples/persistence/prisma-schema.example.prisma +0 -74
  514. package/examples/persistence/redis-persistence.ts +0 -488
  515. package/examples/tools/basic-tools.ts +0 -765
  516. package/examples/tools/data-enrichment-tools.ts +0 -593
  517. package/examples/tools/enhanced-tool-metadata.ts +0 -268
  518. package/examples/tools/streaming-tool-execution.ts +0 -283
  519. package/src/core/BatchExecutor.ts +0 -1187
  520. package/src/core/BatchPromptBuilder.ts +0 -299
  521. package/src/core/Route.ts +0 -678
  522. package/src/types/route.ts +0 -392
@@ -0,0 +1,723 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ /**
3
+ * SignalProcessor — Orchestration for signal phase execution.
4
+ *
5
+ * Owns:
6
+ * - `behaviorAllowsExecution`: Behavior gating (Algorithm 2)
7
+ * - `recordTrigger`: Immutable session update for trigger state
8
+ * - `buildSignalContext`: Constructs the handler context (D-Q12 writers)
9
+ * - `runPhase` / `runPreSignalPhase` / `runPostSignalPhase`: Phase orchestration (Algorithm 1)
10
+ *
11
+ * @module SignalProcessor
12
+ */
13
+
14
+ import type { AiProvider } from "../types/ai";
15
+ import type { Event } from "../types/history";
16
+ import { MessageRole as MessageRoleEnum } from "../types/history";
17
+ import type { SessionState } from "../types/session";
18
+ import type { PreDirective, Directive } from "../types/flow";
19
+ import type {
20
+ Signal,
21
+ SignalContext,
22
+ SignalDirective,
23
+ SignalFiring,
24
+ SignalPredicateContext,
25
+ SignalTriggerState,
26
+ } from "../types/signals";
27
+ import type { SignalEvaluator } from "./SignalEvaluator";
28
+ import { logger } from "../utils";
29
+
30
+ // ──────────────────────────────────────────────────────────────────────────────
31
+ // behaviorAllowsExecution — Algorithm 2
32
+ // ──────────────────────────────────────────────────────────────────────────────
33
+
34
+ /**
35
+ * Determines whether a signal's behavior gating allows execution this turn.
36
+ *
37
+ * Algorithm 2 from the design document:
38
+ * - `'always'` (or unset) → always allowed
39
+ * - `'once'` → allowed only if no prior trigger exists
40
+ * - `'cooldown'` → allowed when elapsed time since last trigger >= cooldownMs;
41
+ * when `cooldownMs` is missing, treated as `'always'` (misconfigured)
42
+ * - Missing trigger (first-time) → allowed regardless of behavior
43
+ *
44
+ * Pure function; no I/O.
45
+ *
46
+ * @param signal - The signal definition (with id, behavior, cooldownMs)
47
+ * @param trigger - The existing trigger state from `session.signals.triggers[signal.id]`, or undefined
48
+ * @returns true if the signal is allowed to execute
49
+ *
50
+ * @requirements 5.1, 5.2, 5.3, 5.4
51
+ */
52
+ export function behaviorAllowsExecution<TContext = unknown, TData = unknown>(
53
+ signal: Signal<TContext, TData, any>,
54
+ trigger: SignalTriggerState | undefined,
55
+ ): boolean {
56
+ // No prior trigger → always allowed (first-time execution)
57
+ if (trigger == null) return true;
58
+
59
+ const behavior = signal.behavior ?? 'always';
60
+
61
+ if (behavior === 'always') return true;
62
+ if (behavior === 'once') return false;
63
+
64
+ if (behavior === 'cooldown') {
65
+ // Misconfigured: cooldown without cooldownMs → treat as 'always'
66
+ if (signal.cooldownMs == null) return true;
67
+
68
+ const lastTriggeredTime = trigger.lastTriggeredAt instanceof Date
69
+ ? trigger.lastTriggeredAt.getTime()
70
+ : new Date(trigger.lastTriggeredAt).getTime();
71
+
72
+ const elapsedMs = Date.now() - lastTriggeredTime;
73
+ return elapsedMs >= signal.cooldownMs;
74
+ }
75
+
76
+ // Unknown behavior value → allow (defensive)
77
+ return true;
78
+ }
79
+
80
+ // ──────────────────────────────────────────────────────────────────────────────
81
+ // recordTrigger — Immutable session update
82
+ // ──────────────────────────────────────────────────────────────────────────────
83
+
84
+ /**
85
+ * Records a signal trigger on the session, returning a new session object
86
+ * (immutable update — never mutates input).
87
+ *
88
+ * - On first trigger: sets `firstTriggeredAt` and `lastTriggeredAt` to now,
89
+ * `count = 1`, plus `lastReason` and `lastPhase`.
90
+ * - On subsequent triggers: leaves `firstTriggeredAt` unchanged, increments
91
+ * `count`, updates `lastTriggeredAt`, `lastReason`, `lastPhase`.
92
+ *
93
+ * @param session - Current session state (not mutated)
94
+ * @param signal - The signal that fired
95
+ * @param reason - The match reason (AI rationale, 'code-only', or 'unconditional')
96
+ * @param phase - The phase in which the signal fired
97
+ * @returns A new session with updated `signals.triggers[signal.id]`
98
+ *
99
+ * @requirements 10.1, 10.2
100
+ */
101
+ export function recordTrigger<TData = unknown>(
102
+ session: SessionState<TData>,
103
+ signal: Signal<any, TData, any>,
104
+ reason: string,
105
+ phase: 'pre' | 'post',
106
+ ): SessionState<TData> {
107
+ const signalId = signal.id ?? 'unknown';
108
+ const now = new Date();
109
+
110
+ const existingTriggers = session.signals?.triggers ?? {};
111
+ const existingTrigger = existingTriggers[signalId];
112
+
113
+ let updatedTrigger: SignalTriggerState;
114
+
115
+ if (existingTrigger == null) {
116
+ // First trigger
117
+ updatedTrigger = {
118
+ firstTriggeredAt: now,
119
+ lastTriggeredAt: now,
120
+ count: 1,
121
+ lastReason: reason,
122
+ lastPhase: phase,
123
+ };
124
+ } else {
125
+ // Subsequent trigger — preserve firstTriggeredAt, increment count
126
+ updatedTrigger = {
127
+ firstTriggeredAt: existingTrigger.firstTriggeredAt,
128
+ lastTriggeredAt: now,
129
+ count: existingTrigger.count + 1,
130
+ lastReason: reason,
131
+ lastPhase: phase,
132
+ };
133
+ }
134
+
135
+ return {
136
+ ...session,
137
+ signals: {
138
+ ...session.signals,
139
+ triggers: {
140
+ ...existingTriggers,
141
+ [signalId]: updatedTrigger,
142
+ },
143
+ },
144
+ };
145
+ }
146
+
147
+ // ──────────────────────────────────────────────────────────────────────────────
148
+ // buildSignalContext — Constructs the handler context
149
+ // ──────────────────────────────────────────────────────────────────────────────
150
+
151
+ /**
152
+ * Parameters for building the SignalContext.
153
+ */
154
+ export interface BuildSignalContextParams<TContext = unknown, TData = unknown, TExtract = void> {
155
+ signal: Signal<TContext, TData, TExtract>;
156
+ reason: string;
157
+ extracted: TExtract extends void ? undefined : TExtract;
158
+ phase: 'pre' | 'post';
159
+ session: SessionState<TData>;
160
+ context: TContext;
161
+ history: Event[];
162
+ /** Turn-local directive bus — `dispatch` pushes onto this array. */
163
+ directiveBus: SignalDirective<TContext, TData>[];
164
+ /** Session updater — called when handler invokes `updateContext`. */
165
+ onUpdateSession: (updatedSession: SessionState<TData>) => void;
166
+ }
167
+
168
+ /**
169
+ * Builds the `SignalContext` passed to signal handlers.
170
+ *
171
+ * - `updateContext` and `updateData` replicate the ToolContext D-Q12 writer
172
+ * pattern: shallow-merge partial updates into the session, call the
173
+ * `onUpdateSession` callback so the processor can track mutations.
174
+ * - `dispatch` pushes a `SignalDirective` onto the turn-local bus.
175
+ * - `lastUserMessage` is derived from the last user-role event in history.
176
+ * - `triggeredAt` is set to `new Date()` at construction time.
177
+ * - `matched` is always `true` (literal type).
178
+ *
179
+ * @requirements 6.1, 6.2, 6.3
180
+ */
181
+ export function buildSignalContext<TContext = unknown, TData = unknown, TExtract = void>(
182
+ params: BuildSignalContextParams<TContext, TData, TExtract>,
183
+ ): SignalContext<TContext, TData, TExtract> {
184
+ const {
185
+ signal,
186
+ reason,
187
+ extracted,
188
+ phase,
189
+ session,
190
+ context,
191
+ history,
192
+ directiveBus,
193
+ onUpdateSession,
194
+ } = params;
195
+
196
+ // Derive lastUserMessage from the last user-role event
197
+ const lastUserMessage = deriveLastUserMessage(history);
198
+
199
+ // D-Q12 contract writers — same signature as ToolContext
200
+ const updateContext = (updates: Partial<TContext>): Promise<void> => {
201
+ // Context is agent-level (not on session directly). Push a contextUpdate
202
+ // directive so the pipeline applies the merge after handler returns.
203
+ directiveBus.push({ contextUpdate: updates } as SignalDirective<TContext, TData>);
204
+ return Promise.resolve();
205
+ };
206
+
207
+ const updateData = (updates: Partial<TData>): Promise<void> => {
208
+ const updatedData = { ...session.data, ...updates };
209
+ const updatedSession: SessionState<TData> = {
210
+ ...session,
211
+ data: updatedData,
212
+ };
213
+ onUpdateSession(updatedSession);
214
+ // Also push a dataUpdate directive for the pipeline
215
+ directiveBus.push({ dataUpdate: updates } as SignalDirective<TContext, TData>);
216
+ return Promise.resolve();
217
+ };
218
+
219
+ const dispatch = (directive: SignalDirective<TContext, TData>): void => {
220
+ directiveBus.push(directive);
221
+ };
222
+
223
+ return {
224
+ signal,
225
+ phase,
226
+ matched: true,
227
+ reason,
228
+ extracted,
229
+ session,
230
+ context,
231
+ data: session.data,
232
+ history,
233
+ lastUserMessage,
234
+ triggeredAt: new Date(),
235
+ updateContext,
236
+ updateData,
237
+ dispatch,
238
+ } as SignalContext<TContext, TData, TExtract>;
239
+ }
240
+
241
+ // ──────────────────────────────────────────────────────────────────────────────
242
+ // Internal helpers
243
+ // ──────────────────────────────────────────────────────────────────────────────
244
+
245
+ /**
246
+ * Extracts the last user message from history events.
247
+ * Walks backward to find the most recent user-role message event.
248
+ */
249
+ function deriveLastUserMessage(history: Event[]): string | undefined {
250
+ for (let i = history.length - 1; i >= 0; i--) {
251
+ const event = history[i];
252
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
253
+ if (event.source === MessageRoleEnum.USER && event.kind === 'message') {
254
+ const data = event.data as { message?: string; participant?: { display_name?: string } };
255
+ if (data?.message) {
256
+ return data.message;
257
+ }
258
+ }
259
+ }
260
+ return undefined;
261
+ }
262
+
263
+ // ──────────────────────────────────────────────────────────────────────────────
264
+ // SignalProcessor — Full Algorithm 1 implementation
265
+ // ──────────────────────────────────────────────────────────────────────────────
266
+
267
+ /** Internal matched-signal entry carried through the pipeline. */
268
+ interface MatchedEntry<TContext, TData> {
269
+ signal: Signal<TContext, TData, any>;
270
+ reason: string;
271
+ extracted?: unknown;
272
+ /** Original index in the signals array (declaration order). */
273
+ declarationIndex: number;
274
+ }
275
+
276
+ /**
277
+ * SignalProcessor — Orchestrates signal phase execution.
278
+ *
279
+ * Constructed only when `options.signals` is non-empty (Requirement 2.3).
280
+ * Owns the full Algorithm 1 lifecycle: filtering, gating, evaluation,
281
+ * handler invocation, directive collection, and state persistence.
282
+ */
283
+ export class SignalProcessor<TContext = unknown, TData = unknown> {
284
+ constructor(
285
+ private readonly signals: Signal<TContext, TData, any>[],
286
+ private readonly provider: AiProvider,
287
+ private readonly evaluator: SignalEvaluator<TContext, TData>,
288
+ private readonly options: { batchSize: number },
289
+ ) { }
290
+
291
+ /** @internal Expose internals for testability. */
292
+ get _internals() {
293
+ return { signals: this.signals, provider: this.provider, evaluator: this.evaluator, options: this.options };
294
+ }
295
+
296
+ /**
297
+ * Pre-signal phase. Delegates to `runPhase('pre', ...)`.
298
+ * Return type narrows `mergedDirective` to `PreDirective | undefined`.
299
+ */
300
+ async runPreSignalPhase(params: {
301
+ session: SessionState<TData>;
302
+ history: Event[];
303
+ context: TContext;
304
+ }): Promise<{
305
+ mergedDirective?: PreDirective<TContext, TData>;
306
+ firings: SignalFiring<TContext, TData>[];
307
+ updatedSession: SessionState<TData>;
308
+ }> {
309
+ return await this.runPhase('pre', params);
310
+ }
311
+
312
+ /**
313
+ * Post-signal phase. Delegates to `runPhase('post', ...)`.
314
+ * Return type narrows `mergedDirective` to `Directive | undefined`.
315
+ * Pre-LLM-only fields (`appendPrompt`, `injectTools`, `halt`) are
316
+ * already dropped inside `runPhase` for the post phase.
317
+ */
318
+ async runPostSignalPhase(params: {
319
+ session: SessionState<TData>;
320
+ history: Event[];
321
+ context: TContext;
322
+ }): Promise<{
323
+ mergedDirective?: Directive<TContext, TData>;
324
+ firings: SignalFiring<TContext, TData>[];
325
+ updatedSession: SessionState<TData>;
326
+ }> {
327
+ return await this.runPhase('post', params);
328
+ }
329
+
330
+ // ──────────────────────────────────────────────────────────────────────────
331
+ // Private: Algorithm 1 — Phase orchestration
332
+ // ──────────────────────────────────────────────────────────────────────────
333
+
334
+ private async runPhase(
335
+ phase: 'pre' | 'post',
336
+ params: { session: SessionState<TData>; history: Event[]; context: TContext },
337
+ ): Promise<{
338
+ mergedDirective?: PreDirective<TContext, TData>;
339
+ firings: SignalFiring<TContext, TData>[];
340
+ updatedSession: SessionState<TData>;
341
+ }> {
342
+ const { session, history, context } = params;
343
+
344
+ // ── STEP 0: zero-cost fast path ──────────────────────────────────────
345
+ if (this.signals.length === 0) {
346
+ return { firings: [], updatedSession: session };
347
+ }
348
+
349
+ // ── STEP 1: filter eligible signals for this phase ───────────────────
350
+ const eligible = this.signals.filter(
351
+ (s) => s.enabled !== false && (s.phase === phase || s.phase === 'both'),
352
+ );
353
+ if (eligible.length === 0) {
354
+ return { firings: [], updatedSession: session };
355
+ }
356
+
357
+ logger.debug(`[Signals] Phase "${phase}" eligible signals: [${eligible.map(s => s.id ?? 'unknown').join(', ')}]`);
358
+
359
+ // ── STEP 2: filter by behavior gating ────────────────────────────────
360
+ const gated = eligible.filter((s) =>
361
+ behaviorAllowsExecution(s, session.signals?.triggers?.[s.id ?? 'unknown']),
362
+ );
363
+ if (gated.length === 0) {
364
+ return { firings: [], updatedSession: session };
365
+ }
366
+
367
+ logger.debug(`[Signals] Phase "${phase}" after behavior gating: [${gated.map(s => s.id ?? 'unknown').join(', ')}]`);
368
+
369
+ // ── STEP 3: partition by evaluation mode ─────────────────────────────
370
+ const unconditional: Signal<TContext, TData, any>[] = [];
371
+ const codeOnly: Signal<TContext, TData, any>[] = [];
372
+ const llmConditioned: Signal<TContext, TData, any>[] = [];
373
+
374
+ for (const s of gated) {
375
+ if (s.when != null) {
376
+ llmConditioned.push(s);
377
+ } else if (s.if != null) {
378
+ codeOnly.push(s);
379
+ } else {
380
+ unconditional.push(s);
381
+ }
382
+ }
383
+
384
+ // Build predicate context (shared across code-only and if-gating)
385
+ const predicateCtx: SignalPredicateContext<TContext, TData> = {
386
+ data: session.data,
387
+ context,
388
+ session,
389
+ history,
390
+ };
391
+
392
+ // ── STEP 4: unconditional signals — always match ─────────────────────
393
+ const matched: MatchedEntry<TContext, TData>[] = [];
394
+
395
+ for (const s of unconditional) {
396
+ matched.push({
397
+ signal: s,
398
+ reason: 'unconditional',
399
+ declarationIndex: this.signals.indexOf(s),
400
+ });
401
+ }
402
+
403
+ // ── STEP 5: code-only signals → evaluateIf ──────────────────────────
404
+ for (const s of codeOnly) {
405
+ const passes = await this.evaluator.evaluateIf(s.if!, predicateCtx);
406
+ if (passes) {
407
+ matched.push({
408
+ signal: s,
409
+ reason: 'code-only',
410
+ declarationIndex: this.signals.indexOf(s),
411
+ });
412
+ }
413
+ }
414
+
415
+ // ── STEP 6: LLM-conditioned signals ─────────────────────────────────
416
+ if (llmConditioned.length > 0) {
417
+ // Gate by `if` first to skip token cost
418
+ const ifGated: Signal<TContext, TData, any>[] = [];
419
+ for (const s of llmConditioned) {
420
+ if (s.if == null) {
421
+ ifGated.push(s);
422
+ } else {
423
+ const passes = await this.evaluator.evaluateIf(s.if, predicateCtx);
424
+ if (passes) {
425
+ ifGated.push(s);
426
+ }
427
+ }
428
+ }
429
+
430
+ if (ifGated.length > 0) {
431
+ const classifierStart = performance.now();
432
+ const classifierResults = await this.evaluator.evaluateSignalsBatched({
433
+ signals: ifGated,
434
+ batchSize: this.options.batchSize,
435
+ session,
436
+ history,
437
+ context,
438
+ });
439
+ const classifierDurationMs = performance.now() - classifierStart;
440
+ logger.debug(`[Signals] Phase "${phase}" classifier call duration: ${classifierDurationMs.toFixed(1)}ms for ${ifGated.length} LLM-conditioned signals`);
441
+
442
+ for (const s of ifGated) {
443
+ const id = s.id ?? 'unknown';
444
+ const result = classifierResults[id];
445
+ if (result?.matched) {
446
+ matched.push({
447
+ signal: s,
448
+ reason: result.reason ?? 'matched',
449
+ extracted: result.extracted,
450
+ declarationIndex: this.signals.indexOf(s),
451
+ });
452
+ }
453
+ }
454
+ }
455
+ }
456
+
457
+ // ── STEP 6b: unconditional + extract signals ────────────────────────
458
+ const unconditionalWithExtract = unconditional.filter((s) => s.extract != null);
459
+ if (unconditionalWithExtract.length > 0) {
460
+ const extractResults = await this.evaluator.evaluateSignals({
461
+ signals: unconditionalWithExtract,
462
+ session,
463
+ history,
464
+ context,
465
+ });
466
+
467
+ // Attach extracted data to already-matched unconditional entries
468
+ for (const s of unconditionalWithExtract) {
469
+ const id = s.id ?? 'unknown';
470
+ const entry = matched.find((m) => m.signal === s);
471
+ if (entry) {
472
+ entry.extracted = extractResults[id]?.extracted;
473
+ }
474
+ }
475
+ }
476
+
477
+ // ── STEP 7: sort by priority desc, declaration order tiebreaker ──────
478
+ matched.sort((a, b) => {
479
+ const priorityDiff = (b.signal.priority ?? 0) - (a.signal.priority ?? 0);
480
+ if (priorityDiff !== 0) return priorityDiff;
481
+ return a.declarationIndex - b.declarationIndex;
482
+ });
483
+
484
+ // ── STEP 8: invoke handlers; collect directives; track state ─────────
485
+ const bus: SignalDirective<TContext, TData>[] = [];
486
+ const firings: SignalFiring<TContext, TData>[] = [];
487
+ let updatedSession = session;
488
+
489
+ for (const m of matched) {
490
+ // Turn-local directive bus for this handler (captures dispatch calls)
491
+ const handlerBus: SignalDirective<TContext, TData>[] = [];
492
+
493
+
494
+ const sigCtx = buildSignalContext<TContext, TData, any>({
495
+ signal: m.signal,
496
+ reason: m.reason,
497
+ extracted: m.extracted,
498
+ phase,
499
+ session: updatedSession,
500
+ context,
501
+ history,
502
+ directiveBus: handlerBus,
503
+ onUpdateSession: (s) => { updatedSession = s; },
504
+ });
505
+
506
+ const start = performance.now();
507
+
508
+ try {
509
+
510
+ const handlerResult = await m.signal.handler(sigCtx);
511
+
512
+ // Collect directives from dispatch calls
513
+ for (const d of handlerBus) {
514
+ bus.push(d);
515
+ }
516
+
517
+ let resolvedDirective: SignalDirective<TContext, TData> | undefined;
518
+
519
+ if (handlerResult != null && typeof handlerResult === 'object') {
520
+ resolvedDirective = { ...handlerResult } as SignalDirective<TContext, TData>;
521
+
522
+ // Resolve replyWith → reply
523
+ if (resolvedDirective.replyWith != null) {
524
+ if (typeof resolvedDirective.replyWith === 'function') {
525
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
526
+ resolvedDirective.reply = resolvedDirective.replyWith(sigCtx);
527
+ } else {
528
+ resolvedDirective.reply = resolvedDirective.replyWith;
529
+ }
530
+ delete resolvedDirective.replyWith;
531
+ }
532
+
533
+ bus.push(resolvedDirective);
534
+ }
535
+
536
+ // Update session via recordTrigger
537
+ updatedSession = recordTrigger(updatedSession, m.signal, m.reason, phase);
538
+
539
+ const handlerDurationMs = performance.now() - start;
540
+
541
+ // Debug: per-handler duration and emitted directive fields
542
+ const directiveFields = resolvedDirective
543
+ ? Object.keys(resolvedDirective).filter(k => resolvedDirective[k as keyof typeof resolvedDirective] !== undefined)
544
+ : [];
545
+ logger.debug(
546
+ `[Signals] Phase "${phase}" handler "${m.signal.id ?? 'unknown'}" completed in ${handlerDurationMs.toFixed(1)}ms` +
547
+ (directiveFields.length > 0 ? `, directive fields: [${directiveFields.join(', ')}]` : ', no directive'),
548
+ );
549
+
550
+ // Record firing
551
+ firings.push({
552
+ id: m.signal.id ?? 'unknown',
553
+ phase,
554
+ reason: m.reason,
555
+ extracted: m.extracted,
556
+ directive: resolvedDirective,
557
+ durationMs: handlerDurationMs,
558
+ });
559
+
560
+ // stopOtherSignals → break iteration
561
+ if (resolvedDirective?.stopOtherSignals === true) {
562
+ break;
563
+ }
564
+ } catch (error) {
565
+ const errorMessage = error instanceof Error ? error.message : String(error);
566
+ const handlerDurationMs = performance.now() - start;
567
+
568
+ // Handler errors logged at ERROR regardless of debug flag (Requirement 13.2)
569
+ logger.error(`[Signals] Handler threw for signal "${m.signal.id ?? 'unknown'}": ${errorMessage}`);
570
+
571
+ // Still record trigger even on error (the signal matched)
572
+ updatedSession = recordTrigger(updatedSession, m.signal, m.reason, phase);
573
+
574
+ firings.push({
575
+ id: m.signal.id ?? 'unknown',
576
+ phase,
577
+ reason: m.reason,
578
+ handlerError: errorMessage,
579
+ durationMs: handlerDurationMs,
580
+ });
581
+
582
+ // Continue iteration — handler errors never break the turn
583
+ }
584
+ }
585
+
586
+ // ── STEP 9: merge directives ─────────────────────────────────────────
587
+ let mergedDirective: PreDirective<TContext, TData> | undefined;
588
+
589
+ if (bus.length > 0) {
590
+ mergedDirective = this.mergeDirectives(bus);
591
+
592
+ // For post-phase, drop pre-LLM-only fields with debug warning
593
+ if (phase === 'post') {
594
+ if (mergedDirective.appendPrompt != null) {
595
+ logger.debug('[Signals] Dropping appendPrompt from post-phase signal directive (pre-LLM-only field)');
596
+ delete mergedDirective.appendPrompt;
597
+ }
598
+ if (mergedDirective.injectTools != null) {
599
+ logger.debug('[Signals] Dropping injectTools from post-phase signal directive (pre-LLM-only field)');
600
+ delete mergedDirective.injectTools;
601
+ }
602
+ if (mergedDirective.halt != null) {
603
+ logger.debug('[Signals] Dropping halt from post-phase signal directive (pre-LLM-only field)');
604
+ delete mergedDirective.halt;
605
+ }
606
+ }
607
+
608
+ // Check if merged directive is now empty after stripping
609
+ const hasFields = Object.keys(mergedDirective).length > 0;
610
+ if (!hasFields) {
611
+ mergedDirective = undefined;
612
+ }
613
+ }
614
+
615
+ return { mergedDirective, firings, updatedSession };
616
+ }
617
+
618
+ // ──────────────────────────────────────────────────────────────────────────
619
+ // Directive merging — Algorithm 4 pattern
620
+ // ──────────────────────────────────────────────────────────────────────────
621
+
622
+ /**
623
+ * Merges an array of signal directives into a single directive.
624
+ *
625
+ * Merge strategy (matches Algorithm 4 / AutoChainExecutor pattern):
626
+ * - Position fields (`goTo`, `goToStep`, `complete`, `abort`, `reset`, `halt`): last-write-wins
627
+ * - `reply`: last-write-wins
628
+ * - `appendPrompt`: array-concat
629
+ * - `injectTools`: array-concat
630
+ * - `dataUpdate`: shallow-merge (later values overwrite earlier for same key)
631
+ * - `contextUpdate`: shallow-merge
632
+ * - `stopOtherSignals`: OR (any true → true)
633
+ */
634
+ private mergeDirectives(
635
+ directives: SignalDirective<TContext, TData>[],
636
+ ): PreDirective<TContext, TData> {
637
+ const merged: PreDirective<TContext, TData> = {};
638
+
639
+ for (const d of directives) {
640
+ // Position fields — last-write-wins
641
+ if (d.goTo !== undefined) {
642
+ merged.goTo = d.goTo;
643
+ // Clear other position fields
644
+ delete merged.goToStep;
645
+ delete merged.complete;
646
+ delete merged.abort;
647
+ delete merged.reset;
648
+ }
649
+ if (d.goToStep !== undefined) {
650
+ merged.goToStep = d.goToStep;
651
+ delete merged.goTo;
652
+ delete merged.complete;
653
+ delete merged.abort;
654
+ delete merged.reset;
655
+ }
656
+ if (d.complete !== undefined) {
657
+ merged.complete = d.complete;
658
+ delete merged.goTo;
659
+ delete merged.goToStep;
660
+ delete merged.abort;
661
+ delete merged.reset;
662
+ }
663
+ if (d.abort !== undefined) {
664
+ merged.abort = d.abort;
665
+ delete merged.goTo;
666
+ delete merged.goToStep;
667
+ delete merged.complete;
668
+ delete merged.reset;
669
+ }
670
+ if (d.reset !== undefined) {
671
+ merged.reset = d.reset;
672
+ delete merged.goTo;
673
+ delete merged.goToStep;
674
+ delete merged.complete;
675
+ delete merged.abort;
676
+ }
677
+
678
+ // halt — last-write-wins
679
+ if (d.halt !== undefined) {
680
+ merged.halt = d.halt;
681
+ }
682
+
683
+ // reply — last-write-wins
684
+ if (d.reply !== undefined) {
685
+ merged.reply = d.reply;
686
+ }
687
+
688
+ // appendPrompt — array-concat
689
+ if (d.appendPrompt != null) {
690
+ merged.appendPrompt = [
691
+ ...(merged.appendPrompt ?? []),
692
+ ...d.appendPrompt,
693
+ ];
694
+ }
695
+
696
+ // injectTools — array-concat
697
+ if (d.injectTools != null) {
698
+ merged.injectTools = [
699
+ ...(merged.injectTools ?? []),
700
+ ...d.injectTools,
701
+ ];
702
+ }
703
+
704
+ // dataUpdate — shallow-merge
705
+ if (d.dataUpdate != null) {
706
+ merged.dataUpdate = {
707
+ ...(merged.dataUpdate ?? {}),
708
+ ...d.dataUpdate,
709
+ };
710
+ }
711
+
712
+ // contextUpdate — shallow-merge
713
+ if (d.contextUpdate != null) {
714
+ merged.contextUpdate = {
715
+ ...(merged.contextUpdate ?? {}),
716
+ ...d.contextUpdate,
717
+ };
718
+ }
719
+ }
720
+
721
+ return merged;
722
+ }
723
+ }