@falai/agent 3.4.5 → 4.0.0-alpha.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 (847) hide show
  1. package/README.md +41 -34
  2. package/dist/cjs/core/Agent.d.ts +22 -378
  3. package/dist/cjs/core/Agent.d.ts.map +1 -1
  4. package/dist/cjs/core/Agent.js +104 -1178
  5. package/dist/cjs/core/Agent.js.map +1 -1
  6. package/dist/cjs/core/CompactionEngine.d.ts.map +1 -1
  7. package/dist/cjs/core/CompactionEngine.js +5 -3
  8. package/dist/cjs/core/CompactionEngine.js.map +1 -1
  9. package/dist/cjs/core/FlowSpec.d.ts +136 -0
  10. package/dist/cjs/core/FlowSpec.d.ts.map +1 -0
  11. package/dist/cjs/core/FlowSpec.js +522 -0
  12. package/dist/cjs/core/FlowSpec.js.map +1 -0
  13. package/dist/cjs/core/Migrate.d.ts +38 -0
  14. package/dist/cjs/core/Migrate.d.ts.map +1 -0
  15. package/dist/cjs/core/Migrate.js +270 -0
  16. package/dist/cjs/core/Migrate.js.map +1 -0
  17. package/dist/cjs/core/Prompt.d.ts +54 -0
  18. package/dist/cjs/core/Prompt.d.ts.map +1 -0
  19. package/dist/cjs/core/Prompt.js +143 -0
  20. package/dist/cjs/core/Prompt.js.map +1 -0
  21. package/dist/cjs/core/Runner.d.ts +160 -0
  22. package/dist/cjs/core/Runner.d.ts.map +1 -0
  23. package/dist/cjs/core/Runner.js +1131 -0
  24. package/dist/cjs/core/Runner.js.map +1 -0
  25. package/dist/cjs/core/Speak.d.ts +37 -0
  26. package/dist/cjs/core/Speak.d.ts.map +1 -0
  27. package/dist/cjs/core/Speak.js +364 -0
  28. package/dist/cjs/core/Speak.js.map +1 -0
  29. package/dist/cjs/core/Understand.d.ts +28 -0
  30. package/dist/cjs/core/Understand.d.ts.map +1 -0
  31. package/dist/cjs/core/Understand.js +353 -0
  32. package/dist/cjs/core/Understand.js.map +1 -0
  33. package/dist/cjs/core/contracts.d.ts +122 -0
  34. package/dist/cjs/core/contracts.d.ts.map +1 -0
  35. package/dist/cjs/core/contracts.js +11 -0
  36. package/dist/cjs/core/contracts.js.map +1 -0
  37. package/dist/cjs/core/falai.d.ts +57 -0
  38. package/dist/cjs/core/falai.d.ts.map +1 -0
  39. package/dist/cjs/core/falai.js +43 -0
  40. package/dist/cjs/core/falai.js.map +1 -0
  41. package/dist/cjs/core/predicate.d.ts +9 -0
  42. package/dist/cjs/core/predicate.d.ts.map +1 -0
  43. package/dist/cjs/core/predicate.js +58 -0
  44. package/dist/cjs/core/predicate.js.map +1 -0
  45. package/dist/cjs/index.d.ts +26 -31
  46. package/dist/cjs/index.d.ts.map +1 -1
  47. package/dist/cjs/index.js +46 -68
  48. package/dist/cjs/index.js.map +1 -1
  49. package/dist/cjs/persistence/MemoryStore.d.ts +15 -0
  50. package/dist/cjs/persistence/MemoryStore.d.ts.map +1 -0
  51. package/dist/cjs/persistence/MemoryStore.js +39 -0
  52. package/dist/cjs/persistence/MemoryStore.js.map +1 -0
  53. package/dist/cjs/persistence/MongoStore.d.ts +42 -0
  54. package/dist/cjs/persistence/MongoStore.d.ts.map +1 -0
  55. package/dist/cjs/persistence/MongoStore.js +60 -0
  56. package/dist/cjs/persistence/MongoStore.js.map +1 -0
  57. package/dist/cjs/persistence/OpenSearchStore.d.ts +86 -0
  58. package/dist/cjs/persistence/OpenSearchStore.d.ts.map +1 -0
  59. package/dist/cjs/persistence/OpenSearchStore.js +120 -0
  60. package/dist/cjs/persistence/OpenSearchStore.js.map +1 -0
  61. package/dist/cjs/persistence/PostgresStore.d.ts +41 -0
  62. package/dist/cjs/persistence/PostgresStore.d.ts.map +1 -0
  63. package/dist/cjs/persistence/PostgresStore.js +58 -0
  64. package/dist/cjs/persistence/PostgresStore.js.map +1 -0
  65. package/dist/cjs/persistence/PrismaStore.d.ts +65 -0
  66. package/dist/cjs/persistence/PrismaStore.d.ts.map +1 -0
  67. package/dist/cjs/persistence/PrismaStore.js +95 -0
  68. package/dist/cjs/persistence/PrismaStore.js.map +1 -0
  69. package/dist/cjs/persistence/RedisStore.d.ts +34 -0
  70. package/dist/cjs/persistence/RedisStore.d.ts.map +1 -0
  71. package/dist/cjs/persistence/RedisStore.js +61 -0
  72. package/dist/cjs/persistence/RedisStore.js.map +1 -0
  73. package/dist/cjs/persistence/SQLiteStore.d.ts +45 -0
  74. package/dist/cjs/persistence/SQLiteStore.d.ts.map +1 -0
  75. package/dist/cjs/persistence/SQLiteStore.js +74 -0
  76. package/dist/cjs/persistence/SQLiteStore.js.map +1 -0
  77. package/dist/cjs/persistence/sessionRow.d.ts +14 -0
  78. package/dist/cjs/persistence/sessionRow.d.ts.map +1 -0
  79. package/dist/cjs/persistence/sessionRow.js +50 -0
  80. package/dist/cjs/persistence/sessionRow.js.map +1 -0
  81. package/dist/cjs/providers/DeepSeekProvider.d.ts.map +1 -1
  82. package/dist/cjs/providers/DeepSeekProvider.js +8 -3
  83. package/dist/cjs/providers/DeepSeekProvider.js.map +1 -1
  84. package/dist/cjs/providers/GeminiProvider.d.ts +4 -3
  85. package/dist/cjs/providers/GeminiProvider.d.ts.map +1 -1
  86. package/dist/cjs/providers/GeminiProvider.js +4 -3
  87. package/dist/cjs/providers/GeminiProvider.js.map +1 -1
  88. package/dist/cjs/providers/OpenAICompatibleProvider.d.ts +4 -0
  89. package/dist/cjs/providers/OpenAICompatibleProvider.d.ts.map +1 -1
  90. package/dist/cjs/providers/OpenAICompatibleProvider.js +2 -0
  91. package/dist/cjs/providers/OpenAICompatibleProvider.js.map +1 -1
  92. package/dist/cjs/providers/OpenRouterProvider.d.ts.map +1 -1
  93. package/dist/cjs/providers/OpenRouterProvider.js +2 -4
  94. package/dist/cjs/providers/OpenRouterProvider.js.map +1 -1
  95. package/dist/cjs/providers/ProviderAdapter.d.ts +1 -1
  96. package/dist/cjs/providers/ProviderAdapter.d.ts.map +1 -1
  97. package/dist/cjs/providers/ProviderAdapter.js +33 -10
  98. package/dist/cjs/providers/ProviderAdapter.js.map +1 -1
  99. package/dist/cjs/types/agent.d.ts +153 -383
  100. package/dist/cjs/types/agent.d.ts.map +1 -1
  101. package/dist/cjs/types/agent.js +1 -1
  102. package/dist/cjs/types/ai.d.ts +32 -1
  103. package/dist/cjs/types/ai.d.ts.map +1 -1
  104. package/dist/cjs/types/compaction.d.ts +3 -1
  105. package/dist/cjs/types/compaction.d.ts.map +1 -1
  106. package/dist/cjs/types/errors.d.ts +9 -12
  107. package/dist/cjs/types/errors.d.ts.map +1 -1
  108. package/dist/cjs/types/errors.js +14 -17
  109. package/dist/cjs/types/errors.js.map +1 -1
  110. package/dist/cjs/types/flow.d.ts +265 -513
  111. package/dist/cjs/types/flow.d.ts.map +1 -1
  112. package/dist/cjs/types/flow.js +7 -1
  113. package/dist/cjs/types/flow.js.map +1 -1
  114. package/dist/cjs/types/history.d.ts +7 -18
  115. package/dist/cjs/types/history.d.ts.map +1 -1
  116. package/dist/cjs/types/history.js.map +1 -1
  117. package/dist/cjs/types/index.d.ts +9 -15
  118. package/dist/cjs/types/index.d.ts.map +1 -1
  119. package/dist/cjs/types/index.js +4 -14
  120. package/dist/cjs/types/index.js.map +1 -1
  121. package/dist/cjs/types/session.d.ts +94 -64
  122. package/dist/cjs/types/session.d.ts.map +1 -1
  123. package/dist/cjs/types/session.js +5 -1
  124. package/dist/cjs/types/session.js.map +1 -1
  125. package/dist/cjs/types/tool.d.ts +37 -207
  126. package/dist/cjs/types/tool.d.ts.map +1 -1
  127. package/dist/cjs/types/tool.js +5 -14
  128. package/dist/cjs/types/tool.js.map +1 -1
  129. package/dist/cjs/utils/clock.d.ts +28 -0
  130. package/dist/cjs/utils/clock.d.ts.map +1 -0
  131. package/dist/cjs/utils/clock.js +64 -0
  132. package/dist/cjs/utils/clock.js.map +1 -0
  133. package/dist/cjs/utils/duration.d.ts +11 -0
  134. package/dist/cjs/utils/duration.d.ts.map +1 -0
  135. package/dist/cjs/utils/duration.js +31 -0
  136. package/dist/cjs/utils/duration.js.map +1 -0
  137. package/dist/cjs/utils/history.d.ts +4 -1
  138. package/dist/cjs/utils/history.d.ts.map +1 -1
  139. package/dist/cjs/utils/history.js +2 -2
  140. package/dist/cjs/utils/history.js.map +1 -1
  141. package/dist/cjs/utils/index.d.ts +4 -10
  142. package/dist/cjs/utils/index.d.ts.map +1 -1
  143. package/dist/cjs/utils/index.js +14 -61
  144. package/dist/cjs/utils/index.js.map +1 -1
  145. package/dist/cjs/utils/json.d.ts +2 -0
  146. package/dist/cjs/utils/json.d.ts.map +1 -1
  147. package/dist/cjs/utils/json.js +5 -0
  148. package/dist/cjs/utils/json.js.map +1 -1
  149. package/dist/cjs/utils/outcomes.d.ts +48 -0
  150. package/dist/cjs/utils/outcomes.d.ts.map +1 -0
  151. package/dist/cjs/utils/outcomes.js +51 -0
  152. package/dist/cjs/utils/outcomes.js.map +1 -0
  153. package/dist/cjs/utils/schema.d.ts +50 -0
  154. package/dist/cjs/utils/schema.d.ts.map +1 -0
  155. package/dist/cjs/utils/schema.js +138 -0
  156. package/dist/cjs/utils/schema.js.map +1 -0
  157. package/dist/cjs/utils/streamingMessage.d.ts +3 -2
  158. package/dist/cjs/utils/streamingMessage.d.ts.map +1 -1
  159. package/dist/cjs/utils/streamingMessage.js +38 -4
  160. package/dist/cjs/utils/streamingMessage.js.map +1 -1
  161. package/dist/cjs/utils/template.d.ts +13 -149
  162. package/dist/cjs/utils/template.d.ts.map +1 -1
  163. package/dist/cjs/utils/template.js +31 -363
  164. package/dist/cjs/utils/template.js.map +1 -1
  165. package/dist/cjs/utils/usage.d.ts +19 -0
  166. package/dist/cjs/utils/usage.d.ts.map +1 -0
  167. package/dist/cjs/utils/usage.js +35 -0
  168. package/dist/cjs/utils/usage.js.map +1 -0
  169. package/dist/core/Agent.d.ts +22 -378
  170. package/dist/core/Agent.d.ts.map +1 -1
  171. package/dist/core/Agent.js +107 -1181
  172. package/dist/core/Agent.js.map +1 -1
  173. package/dist/core/CompactionEngine.d.ts.map +1 -1
  174. package/dist/core/CompactionEngine.js +5 -3
  175. package/dist/core/CompactionEngine.js.map +1 -1
  176. package/dist/core/FlowSpec.d.ts +136 -0
  177. package/dist/core/FlowSpec.d.ts.map +1 -0
  178. package/dist/core/FlowSpec.js +516 -0
  179. package/dist/core/FlowSpec.js.map +1 -0
  180. package/dist/core/Migrate.d.ts +38 -0
  181. package/dist/core/Migrate.d.ts.map +1 -0
  182. package/dist/core/Migrate.js +264 -0
  183. package/dist/core/Migrate.js.map +1 -0
  184. package/dist/core/Prompt.d.ts +54 -0
  185. package/dist/core/Prompt.d.ts.map +1 -0
  186. package/dist/core/Prompt.js +133 -0
  187. package/dist/core/Prompt.js.map +1 -0
  188. package/dist/core/Runner.d.ts +160 -0
  189. package/dist/core/Runner.d.ts.map +1 -0
  190. package/dist/core/Runner.js +1127 -0
  191. package/dist/core/Runner.js.map +1 -0
  192. package/dist/core/Speak.d.ts +37 -0
  193. package/dist/core/Speak.d.ts.map +1 -0
  194. package/dist/core/Speak.js +360 -0
  195. package/dist/core/Speak.js.map +1 -0
  196. package/dist/core/Understand.d.ts +28 -0
  197. package/dist/core/Understand.d.ts.map +1 -0
  198. package/dist/core/Understand.js +349 -0
  199. package/dist/core/Understand.js.map +1 -0
  200. package/dist/core/contracts.d.ts +122 -0
  201. package/dist/core/contracts.d.ts.map +1 -0
  202. package/dist/core/contracts.js +10 -0
  203. package/dist/core/contracts.js.map +1 -0
  204. package/dist/core/falai.d.ts +57 -0
  205. package/dist/core/falai.d.ts.map +1 -0
  206. package/dist/core/falai.js +40 -0
  207. package/dist/core/falai.js.map +1 -0
  208. package/dist/core/predicate.d.ts +9 -0
  209. package/dist/core/predicate.d.ts.map +1 -0
  210. package/dist/core/predicate.js +54 -0
  211. package/dist/core/predicate.js.map +1 -0
  212. package/dist/index.d.ts +26 -31
  213. package/dist/index.d.ts.map +1 -1
  214. package/dist/index.js +19 -24
  215. package/dist/index.js.map +1 -1
  216. package/dist/persistence/MemoryStore.d.ts +15 -0
  217. package/dist/persistence/MemoryStore.d.ts.map +1 -0
  218. package/dist/persistence/MemoryStore.js +35 -0
  219. package/dist/persistence/MemoryStore.js.map +1 -0
  220. package/dist/persistence/MongoStore.d.ts +42 -0
  221. package/dist/persistence/MongoStore.d.ts.map +1 -0
  222. package/dist/persistence/MongoStore.js +56 -0
  223. package/dist/persistence/MongoStore.js.map +1 -0
  224. package/dist/persistence/OpenSearchStore.d.ts +86 -0
  225. package/dist/persistence/OpenSearchStore.d.ts.map +1 -0
  226. package/dist/persistence/OpenSearchStore.js +116 -0
  227. package/dist/persistence/OpenSearchStore.js.map +1 -0
  228. package/dist/persistence/PostgresStore.d.ts +41 -0
  229. package/dist/persistence/PostgresStore.d.ts.map +1 -0
  230. package/dist/persistence/PostgresStore.js +54 -0
  231. package/dist/persistence/PostgresStore.js.map +1 -0
  232. package/dist/persistence/PrismaStore.d.ts +65 -0
  233. package/dist/persistence/PrismaStore.d.ts.map +1 -0
  234. package/dist/persistence/PrismaStore.js +91 -0
  235. package/dist/persistence/PrismaStore.js.map +1 -0
  236. package/dist/persistence/RedisStore.d.ts +34 -0
  237. package/dist/persistence/RedisStore.d.ts.map +1 -0
  238. package/dist/persistence/RedisStore.js +57 -0
  239. package/dist/persistence/RedisStore.js.map +1 -0
  240. package/dist/persistence/SQLiteStore.d.ts +45 -0
  241. package/dist/persistence/SQLiteStore.d.ts.map +1 -0
  242. package/dist/persistence/SQLiteStore.js +70 -0
  243. package/dist/persistence/SQLiteStore.js.map +1 -0
  244. package/dist/persistence/sessionRow.d.ts +14 -0
  245. package/dist/persistence/sessionRow.d.ts.map +1 -0
  246. package/dist/persistence/sessionRow.js +45 -0
  247. package/dist/persistence/sessionRow.js.map +1 -0
  248. package/dist/providers/DeepSeekProvider.d.ts.map +1 -1
  249. package/dist/providers/DeepSeekProvider.js +8 -3
  250. package/dist/providers/DeepSeekProvider.js.map +1 -1
  251. package/dist/providers/GeminiProvider.d.ts +4 -3
  252. package/dist/providers/GeminiProvider.d.ts.map +1 -1
  253. package/dist/providers/GeminiProvider.js +4 -3
  254. package/dist/providers/GeminiProvider.js.map +1 -1
  255. package/dist/providers/OpenAICompatibleProvider.d.ts +4 -0
  256. package/dist/providers/OpenAICompatibleProvider.d.ts.map +1 -1
  257. package/dist/providers/OpenAICompatibleProvider.js +2 -0
  258. package/dist/providers/OpenAICompatibleProvider.js.map +1 -1
  259. package/dist/providers/OpenRouterProvider.d.ts.map +1 -1
  260. package/dist/providers/OpenRouterProvider.js +2 -4
  261. package/dist/providers/OpenRouterProvider.js.map +1 -1
  262. package/dist/providers/ProviderAdapter.d.ts +1 -1
  263. package/dist/providers/ProviderAdapter.d.ts.map +1 -1
  264. package/dist/providers/ProviderAdapter.js +34 -11
  265. package/dist/providers/ProviderAdapter.js.map +1 -1
  266. package/dist/types/agent.d.ts +153 -383
  267. package/dist/types/agent.d.ts.map +1 -1
  268. package/dist/types/agent.js +1 -1
  269. package/dist/types/ai.d.ts +32 -1
  270. package/dist/types/ai.d.ts.map +1 -1
  271. package/dist/types/compaction.d.ts +3 -1
  272. package/dist/types/compaction.d.ts.map +1 -1
  273. package/dist/types/errors.d.ts +9 -12
  274. package/dist/types/errors.d.ts.map +1 -1
  275. package/dist/types/errors.js +12 -15
  276. package/dist/types/errors.js.map +1 -1
  277. package/dist/types/flow.d.ts +265 -513
  278. package/dist/types/flow.d.ts.map +1 -1
  279. package/dist/types/flow.js +7 -1
  280. package/dist/types/flow.js.map +1 -1
  281. package/dist/types/history.d.ts +7 -18
  282. package/dist/types/history.d.ts.map +1 -1
  283. package/dist/types/history.js.map +1 -1
  284. package/dist/types/index.d.ts +9 -15
  285. package/dist/types/index.d.ts.map +1 -1
  286. package/dist/types/index.js +2 -7
  287. package/dist/types/index.js.map +1 -1
  288. package/dist/types/session.d.ts +94 -64
  289. package/dist/types/session.d.ts.map +1 -1
  290. package/dist/types/session.js +5 -1
  291. package/dist/types/session.js.map +1 -1
  292. package/dist/types/tool.d.ts +37 -207
  293. package/dist/types/tool.d.ts.map +1 -1
  294. package/dist/types/tool.js +6 -13
  295. package/dist/types/tool.js.map +1 -1
  296. package/dist/utils/clock.d.ts +28 -0
  297. package/dist/utils/clock.d.ts.map +1 -0
  298. package/dist/utils/clock.js +59 -0
  299. package/dist/utils/clock.js.map +1 -0
  300. package/dist/utils/duration.d.ts +11 -0
  301. package/dist/utils/duration.d.ts.map +1 -0
  302. package/dist/utils/duration.js +26 -0
  303. package/dist/utils/duration.js.map +1 -0
  304. package/dist/utils/history.d.ts +4 -1
  305. package/dist/utils/history.d.ts.map +1 -1
  306. package/dist/utils/history.js +2 -2
  307. package/dist/utils/history.js.map +1 -1
  308. package/dist/utils/index.d.ts +4 -10
  309. package/dist/utils/index.d.ts.map +1 -1
  310. package/dist/utils/index.js +4 -21
  311. package/dist/utils/index.js.map +1 -1
  312. package/dist/utils/json.d.ts +2 -0
  313. package/dist/utils/json.d.ts.map +1 -1
  314. package/dist/utils/json.js +4 -0
  315. package/dist/utils/json.js.map +1 -1
  316. package/dist/utils/outcomes.d.ts +48 -0
  317. package/dist/utils/outcomes.d.ts.map +1 -0
  318. package/dist/utils/outcomes.js +48 -0
  319. package/dist/utils/outcomes.js.map +1 -0
  320. package/dist/utils/schema.d.ts +50 -0
  321. package/dist/utils/schema.d.ts.map +1 -0
  322. package/dist/utils/schema.js +129 -0
  323. package/dist/utils/schema.js.map +1 -0
  324. package/dist/utils/streamingMessage.d.ts +3 -2
  325. package/dist/utils/streamingMessage.d.ts.map +1 -1
  326. package/dist/utils/streamingMessage.js +38 -4
  327. package/dist/utils/streamingMessage.js.map +1 -1
  328. package/dist/utils/template.d.ts +13 -149
  329. package/dist/utils/template.d.ts.map +1 -1
  330. package/dist/utils/template.js +28 -355
  331. package/dist/utils/template.js.map +1 -1
  332. package/dist/utils/usage.d.ts +19 -0
  333. package/dist/utils/usage.d.ts.map +1 -0
  334. package/dist/utils/usage.js +31 -0
  335. package/dist/utils/usage.js.map +1 -0
  336. package/docs/README.md +37 -19
  337. package/docs/concepts/architecture.md +117 -239
  338. package/docs/concepts/collection.md +170 -0
  339. package/docs/concepts/pipeline.md +132 -378
  340. package/docs/concepts/runs-and-waits.md +192 -0
  341. package/docs/guides/actions-and-events.md +276 -0
  342. package/docs/guides/branching.md +119 -208
  343. package/docs/guides/compaction.md +63 -158
  344. package/docs/guides/conditions.md +164 -128
  345. package/docs/guides/error-handling.md +168 -164
  346. package/docs/guides/flow-control.md +210 -349
  347. package/docs/guides/flows-from-json.md +224 -0
  348. package/docs/guides/instructions.md +125 -161
  349. package/docs/guides/persistence.md +182 -206
  350. package/docs/guides/streaming.md +50 -114
  351. package/docs/guides/testing.md +284 -0
  352. package/docs/guides/triggers.md +401 -0
  353. package/docs/migration/README.md +8 -15
  354. package/docs/migration/v1-to-v2.md +1 -1
  355. package/docs/migration/v2-3-to-v2-4.md +2 -2
  356. package/docs/migration/v2-6-to-v2-7.md +4 -4
  357. package/docs/migration/v3-to-v4.md +452 -0
  358. package/docs/reference/actions-events-conditions.md +396 -0
  359. package/docs/reference/agent.md +244 -0
  360. package/docs/reference/branches.md +75 -203
  361. package/docs/reference/errors.md +188 -144
  362. package/docs/reference/fields.md +125 -0
  363. package/docs/reference/flow-spec.md +248 -0
  364. package/docs/reference/flow.md +104 -192
  365. package/docs/reference/instruction.md +83 -137
  366. package/docs/reference/outcomes.md +273 -0
  367. package/docs/reference/providers.md +525 -302
  368. package/docs/reference/session.md +210 -0
  369. package/docs/reference/step.md +194 -312
  370. package/docs/reference/stores.md +496 -0
  371. package/docs/reference/tool.md +162 -231
  372. package/docs/reference/trigger.md +180 -0
  373. package/docs/rfc/v4-one-flow.md +477 -0
  374. package/docs/start/01-install.md +59 -44
  375. package/docs/start/02-first-agent.md +97 -147
  376. package/docs/start/03-collect-data.md +78 -183
  377. package/docs/start/04-add-tools.md +159 -227
  378. package/docs/start/05-go-to-production.md +167 -164
  379. package/examples/01-quickstart.ts +26 -16
  380. package/examples/02-fields.ts +75 -0
  381. package/examples/03-tools.ts +79 -119
  382. package/examples/04-instructions.ts +60 -87
  383. package/examples/05-branches.ts +78 -0
  384. package/examples/06-triggers-and-waits.ts +148 -0
  385. package/examples/07-streaming.ts +34 -60
  386. package/examples/08-store-and-migration.ts +97 -0
  387. package/examples/09-flows-from-json.ts +107 -0
  388. package/package.json +9 -6
  389. package/src/core/Agent.ts +116 -1512
  390. package/src/core/CompactionEngine.ts +7 -4
  391. package/src/core/FlowSpec.ts +712 -0
  392. package/src/core/Migrate.ts +256 -0
  393. package/src/core/Prompt.ts +156 -0
  394. package/src/core/Runner.ts +1181 -0
  395. package/src/core/Speak.ts +451 -0
  396. package/src/core/Understand.ts +422 -0
  397. package/src/core/contracts.ts +111 -0
  398. package/src/core/falai.ts +86 -0
  399. package/src/core/predicate.ts +56 -0
  400. package/src/index.ts +119 -147
  401. package/src/persistence/MemoryStore.ts +37 -0
  402. package/src/persistence/MongoStore.ts +89 -0
  403. package/src/persistence/OpenSearchStore.ts +153 -0
  404. package/src/persistence/PostgresStore.ts +89 -0
  405. package/src/persistence/PrismaStore.ts +127 -0
  406. package/src/persistence/RedisStore.ts +90 -0
  407. package/src/persistence/SQLiteStore.ts +103 -0
  408. package/src/persistence/sessionRow.ts +45 -0
  409. package/src/providers/DeepSeekProvider.ts +8 -3
  410. package/src/providers/GeminiProvider.ts +4 -3
  411. package/src/providers/OpenAICompatibleProvider.ts +6 -0
  412. package/src/providers/OpenRouterProvider.ts +2 -4
  413. package/src/providers/ProviderAdapter.ts +36 -8
  414. package/src/types/agent.ts +124 -397
  415. package/src/types/ai.ts +33 -1
  416. package/src/types/compaction.ts +3 -1
  417. package/src/types/errors.ts +13 -16
  418. package/src/types/flow.ts +249 -550
  419. package/src/types/history.ts +7 -20
  420. package/src/types/index.ts +87 -139
  421. package/src/types/session.ts +135 -70
  422. package/src/types/tool.ts +42 -267
  423. package/src/utils/clock.ts +70 -0
  424. package/src/utils/duration.ts +33 -0
  425. package/src/utils/history.ts +3 -2
  426. package/src/utils/index.ts +8 -66
  427. package/src/utils/json.ts +5 -0
  428. package/src/utils/outcomes.ts +56 -0
  429. package/src/utils/schema.ts +145 -0
  430. package/src/utils/streamingMessage.ts +34 -4
  431. package/src/utils/template.ts +32 -423
  432. package/src/utils/usage.ts +37 -0
  433. package/dist/adapters/MemoryAdapter.d.ts +0 -47
  434. package/dist/adapters/MemoryAdapter.d.ts.map +0 -1
  435. package/dist/adapters/MemoryAdapter.js +0 -204
  436. package/dist/adapters/MemoryAdapter.js.map +0 -1
  437. package/dist/adapters/MongoAdapter.d.ts +0 -97
  438. package/dist/adapters/MongoAdapter.d.ts.map +0 -1
  439. package/dist/adapters/MongoAdapter.js +0 -196
  440. package/dist/adapters/MongoAdapter.js.map +0 -1
  441. package/dist/adapters/OpenSearchAdapter.d.ts +0 -169
  442. package/dist/adapters/OpenSearchAdapter.d.ts.map +0 -1
  443. package/dist/adapters/OpenSearchAdapter.js +0 -471
  444. package/dist/adapters/OpenSearchAdapter.js.map +0 -1
  445. package/dist/adapters/PostgreSQLAdapter.d.ts +0 -85
  446. package/dist/adapters/PostgreSQLAdapter.d.ts.map +0 -1
  447. package/dist/adapters/PostgreSQLAdapter.js +0 -308
  448. package/dist/adapters/PostgreSQLAdapter.js.map +0 -1
  449. package/dist/adapters/PrismaAdapter.d.ts +0 -115
  450. package/dist/adapters/PrismaAdapter.d.ts.map +0 -1
  451. package/dist/adapters/PrismaAdapter.js +0 -406
  452. package/dist/adapters/PrismaAdapter.js.map +0 -1
  453. package/dist/adapters/RedisAdapter.d.ts +0 -72
  454. package/dist/adapters/RedisAdapter.d.ts.map +0 -1
  455. package/dist/adapters/RedisAdapter.js +0 -286
  456. package/dist/adapters/RedisAdapter.js.map +0 -1
  457. package/dist/adapters/SQLiteAdapter.d.ts +0 -86
  458. package/dist/adapters/SQLiteAdapter.d.ts.map +0 -1
  459. package/dist/adapters/SQLiteAdapter.js +0 -337
  460. package/dist/adapters/SQLiteAdapter.js.map +0 -1
  461. package/dist/adapters/index.d.ts +0 -17
  462. package/dist/adapters/index.d.ts.map +0 -1
  463. package/dist/adapters/index.js +0 -11
  464. package/dist/adapters/index.js.map +0 -1
  465. package/dist/adapters/sessionRow.d.ts +0 -22
  466. package/dist/adapters/sessionRow.d.ts.map +0 -1
  467. package/dist/adapters/sessionRow.js +0 -48
  468. package/dist/adapters/sessionRow.js.map +0 -1
  469. package/dist/cjs/adapters/MemoryAdapter.d.ts +0 -47
  470. package/dist/cjs/adapters/MemoryAdapter.d.ts.map +0 -1
  471. package/dist/cjs/adapters/MemoryAdapter.js +0 -208
  472. package/dist/cjs/adapters/MemoryAdapter.js.map +0 -1
  473. package/dist/cjs/adapters/MongoAdapter.d.ts +0 -97
  474. package/dist/cjs/adapters/MongoAdapter.d.ts.map +0 -1
  475. package/dist/cjs/adapters/MongoAdapter.js +0 -200
  476. package/dist/cjs/adapters/MongoAdapter.js.map +0 -1
  477. package/dist/cjs/adapters/OpenSearchAdapter.d.ts +0 -169
  478. package/dist/cjs/adapters/OpenSearchAdapter.d.ts.map +0 -1
  479. package/dist/cjs/adapters/OpenSearchAdapter.js +0 -475
  480. package/dist/cjs/adapters/OpenSearchAdapter.js.map +0 -1
  481. package/dist/cjs/adapters/PostgreSQLAdapter.d.ts +0 -85
  482. package/dist/cjs/adapters/PostgreSQLAdapter.d.ts.map +0 -1
  483. package/dist/cjs/adapters/PostgreSQLAdapter.js +0 -312
  484. package/dist/cjs/adapters/PostgreSQLAdapter.js.map +0 -1
  485. package/dist/cjs/adapters/PrismaAdapter.d.ts +0 -115
  486. package/dist/cjs/adapters/PrismaAdapter.d.ts.map +0 -1
  487. package/dist/cjs/adapters/PrismaAdapter.js +0 -410
  488. package/dist/cjs/adapters/PrismaAdapter.js.map +0 -1
  489. package/dist/cjs/adapters/RedisAdapter.d.ts +0 -72
  490. package/dist/cjs/adapters/RedisAdapter.d.ts.map +0 -1
  491. package/dist/cjs/adapters/RedisAdapter.js +0 -290
  492. package/dist/cjs/adapters/RedisAdapter.js.map +0 -1
  493. package/dist/cjs/adapters/SQLiteAdapter.d.ts +0 -86
  494. package/dist/cjs/adapters/SQLiteAdapter.d.ts.map +0 -1
  495. package/dist/cjs/adapters/SQLiteAdapter.js +0 -341
  496. package/dist/cjs/adapters/SQLiteAdapter.js.map +0 -1
  497. package/dist/cjs/adapters/index.d.ts +0 -17
  498. package/dist/cjs/adapters/index.d.ts.map +0 -1
  499. package/dist/cjs/adapters/index.js +0 -21
  500. package/dist/cjs/adapters/index.js.map +0 -1
  501. package/dist/cjs/adapters/sessionRow.d.ts +0 -22
  502. package/dist/cjs/adapters/sessionRow.d.ts.map +0 -1
  503. package/dist/cjs/adapters/sessionRow.js +0 -52
  504. package/dist/cjs/adapters/sessionRow.js.map +0 -1
  505. package/dist/cjs/constants/index.d.ts +0 -1
  506. package/dist/cjs/constants/index.d.ts.map +0 -1
  507. package/dist/cjs/constants/index.js +0 -4
  508. package/dist/cjs/constants/index.js.map +0 -1
  509. package/dist/cjs/core/AutoChainExecutor.d.ts +0 -97
  510. package/dist/cjs/core/AutoChainExecutor.d.ts.map +0 -1
  511. package/dist/cjs/core/AutoChainExecutor.js +0 -288
  512. package/dist/cjs/core/AutoChainExecutor.js.map +0 -1
  513. package/dist/cjs/core/BranchEvaluator.d.ts +0 -55
  514. package/dist/cjs/core/BranchEvaluator.d.ts.map +0 -1
  515. package/dist/cjs/core/BranchEvaluator.js +0 -125
  516. package/dist/cjs/core/BranchEvaluator.js.map +0 -1
  517. package/dist/cjs/core/DirectiveChainTracker.d.ts +0 -49
  518. package/dist/cjs/core/DirectiveChainTracker.d.ts.map +0 -1
  519. package/dist/cjs/core/DirectiveChainTracker.js +0 -121
  520. package/dist/cjs/core/DirectiveChainTracker.js.map +0 -1
  521. package/dist/cjs/core/Events.d.ts +0 -26
  522. package/dist/cjs/core/Events.d.ts.map +0 -1
  523. package/dist/cjs/core/Events.js +0 -144
  524. package/dist/cjs/core/Events.js.map +0 -1
  525. package/dist/cjs/core/Flow.d.ts +0 -183
  526. package/dist/cjs/core/Flow.d.ts.map +0 -1
  527. package/dist/cjs/core/Flow.js +0 -551
  528. package/dist/cjs/core/Flow.js.map +0 -1
  529. package/dist/cjs/core/FlowRouter.d.ts +0 -183
  530. package/dist/cjs/core/FlowRouter.d.ts.map +0 -1
  531. package/dist/cjs/core/FlowRouter.js +0 -1047
  532. package/dist/cjs/core/FlowRouter.js.map +0 -1
  533. package/dist/cjs/core/PersistenceManager.d.ts +0 -114
  534. package/dist/cjs/core/PersistenceManager.d.ts.map +0 -1
  535. package/dist/cjs/core/PersistenceManager.js +0 -336
  536. package/dist/cjs/core/PersistenceManager.js.map +0 -1
  537. package/dist/cjs/core/PromptComposer.d.ts +0 -47
  538. package/dist/cjs/core/PromptComposer.d.ts.map +0 -1
  539. package/dist/cjs/core/PromptComposer.js +0 -397
  540. package/dist/cjs/core/PromptComposer.js.map +0 -1
  541. package/dist/cjs/core/PromptSectionCache.d.ts +0 -48
  542. package/dist/cjs/core/PromptSectionCache.d.ts.map +0 -1
  543. package/dist/cjs/core/PromptSectionCache.js +0 -108
  544. package/dist/cjs/core/PromptSectionCache.js.map +0 -1
  545. package/dist/cjs/core/ResponseEngine.d.ts +0 -43
  546. package/dist/cjs/core/ResponseEngine.d.ts.map +0 -1
  547. package/dist/cjs/core/ResponseEngine.js +0 -235
  548. package/dist/cjs/core/ResponseEngine.js.map +0 -1
  549. package/dist/cjs/core/ResponseGenerationError.d.ts +0 -30
  550. package/dist/cjs/core/ResponseGenerationError.d.ts.map +0 -1
  551. package/dist/cjs/core/ResponseGenerationError.js +0 -35
  552. package/dist/cjs/core/ResponseGenerationError.js.map +0 -1
  553. package/dist/cjs/core/ResponseModal.d.ts +0 -305
  554. package/dist/cjs/core/ResponseModal.d.ts.map +0 -1
  555. package/dist/cjs/core/ResponseModal.js +0 -1414
  556. package/dist/cjs/core/ResponseModal.js.map +0 -1
  557. package/dist/cjs/core/ResponsePipeline.d.ts +0 -220
  558. package/dist/cjs/core/ResponsePipeline.d.ts.map +0 -1
  559. package/dist/cjs/core/ResponsePipeline.js +0 -1040
  560. package/dist/cjs/core/ResponsePipeline.js.map +0 -1
  561. package/dist/cjs/core/SessionFinalizer.d.ts +0 -34
  562. package/dist/cjs/core/SessionFinalizer.d.ts.map +0 -1
  563. package/dist/cjs/core/SessionFinalizer.js +0 -88
  564. package/dist/cjs/core/SessionFinalizer.js.map +0 -1
  565. package/dist/cjs/core/SessionManager.d.ts +0 -112
  566. package/dist/cjs/core/SessionManager.d.ts.map +0 -1
  567. package/dist/cjs/core/SessionManager.js +0 -308
  568. package/dist/cjs/core/SessionManager.js.map +0 -1
  569. package/dist/cjs/core/SignalCoordinator.d.ts +0 -103
  570. package/dist/cjs/core/SignalCoordinator.d.ts.map +0 -1
  571. package/dist/cjs/core/SignalCoordinator.js +0 -207
  572. package/dist/cjs/core/SignalCoordinator.js.map +0 -1
  573. package/dist/cjs/core/SignalEvaluator.d.ts +0 -86
  574. package/dist/cjs/core/SignalEvaluator.d.ts.map +0 -1
  575. package/dist/cjs/core/SignalEvaluator.js +0 -319
  576. package/dist/cjs/core/SignalEvaluator.js.map +0 -1
  577. package/dist/cjs/core/SignalProcessor.d.ts +0 -152
  578. package/dist/cjs/core/SignalProcessor.d.ts.map +0 -1
  579. package/dist/cjs/core/SignalProcessor.js +0 -505
  580. package/dist/cjs/core/SignalProcessor.js.map +0 -1
  581. package/dist/cjs/core/Step.d.ts +0 -184
  582. package/dist/cjs/core/Step.d.ts.map +0 -1
  583. package/dist/cjs/core/Step.js +0 -599
  584. package/dist/cjs/core/Step.js.map +0 -1
  585. package/dist/cjs/core/StepLifecycle.d.ts +0 -43
  586. package/dist/cjs/core/StepLifecycle.d.ts.map +0 -1
  587. package/dist/cjs/core/StepLifecycle.js +0 -180
  588. package/dist/cjs/core/StepLifecycle.js.map +0 -1
  589. package/dist/cjs/core/StreamingToolExecutor.d.ts +0 -142
  590. package/dist/cjs/core/StreamingToolExecutor.d.ts.map +0 -1
  591. package/dist/cjs/core/StreamingToolExecutor.js +0 -490
  592. package/dist/cjs/core/StreamingToolExecutor.js.map +0 -1
  593. package/dist/cjs/core/ToolLoopExecutor.d.ts +0 -133
  594. package/dist/cjs/core/ToolLoopExecutor.d.ts.map +0 -1
  595. package/dist/cjs/core/ToolLoopExecutor.js +0 -568
  596. package/dist/cjs/core/ToolLoopExecutor.js.map +0 -1
  597. package/dist/cjs/core/ToolManager.d.ts +0 -250
  598. package/dist/cjs/core/ToolManager.d.ts.map +0 -1
  599. package/dist/cjs/core/ToolManager.js +0 -1104
  600. package/dist/cjs/core/ToolManager.js.map +0 -1
  601. package/dist/cjs/core/createAgent.d.ts +0 -35
  602. package/dist/cjs/core/createAgent.d.ts.map +0 -1
  603. package/dist/cjs/core/createAgent.js +0 -39
  604. package/dist/cjs/core/createAgent.js.map +0 -1
  605. package/dist/cjs/core/flow-namespace.d.ts +0 -64
  606. package/dist/cjs/core/flow-namespace.d.ts.map +0 -1
  607. package/dist/cjs/core/flow-namespace.js +0 -182
  608. package/dist/cjs/core/flow-namespace.js.map +0 -1
  609. package/dist/cjs/core/toolGates.d.ts +0 -24
  610. package/dist/cjs/core/toolGates.d.ts.map +0 -1
  611. package/dist/cjs/core/toolGates.js +0 -52
  612. package/dist/cjs/core/toolGates.js.map +0 -1
  613. package/dist/cjs/types/persistence.d.ts +0 -254
  614. package/dist/cjs/types/persistence.d.ts.map +0 -1
  615. package/dist/cjs/types/persistence.js +0 -7
  616. package/dist/cjs/types/persistence.js.map +0 -1
  617. package/dist/cjs/types/prompt-cache.d.ts +0 -15
  618. package/dist/cjs/types/prompt-cache.d.ts.map +0 -1
  619. package/dist/cjs/types/prompt-cache.js +0 -6
  620. package/dist/cjs/types/prompt-cache.js.map +0 -1
  621. package/dist/cjs/types/signals.d.ts +0 -263
  622. package/dist/cjs/types/signals.d.ts.map +0 -1
  623. package/dist/cjs/types/signals.js +0 -11
  624. package/dist/cjs/types/signals.js.map +0 -1
  625. package/dist/cjs/types/template.d.ts +0 -84
  626. package/dist/cjs/types/template.d.ts.map +0 -1
  627. package/dist/cjs/types/template.js +0 -3
  628. package/dist/cjs/types/template.js.map +0 -1
  629. package/dist/cjs/utils/condition.d.ts +0 -63
  630. package/dist/cjs/utils/condition.d.ts.map +0 -1
  631. package/dist/cjs/utils/condition.js +0 -239
  632. package/dist/cjs/utils/condition.js.map +0 -1
  633. package/dist/cjs/utils/event.d.ts +0 -6
  634. package/dist/cjs/utils/event.d.ts.map +0 -1
  635. package/dist/cjs/utils/event.js +0 -20
  636. package/dist/cjs/utils/event.js.map +0 -1
  637. package/dist/cjs/utils/id.d.ts +0 -33
  638. package/dist/cjs/utils/id.d.ts.map +0 -1
  639. package/dist/cjs/utils/id.js +0 -84
  640. package/dist/cjs/utils/id.js.map +0 -1
  641. package/dist/cjs/utils/serialize.d.ts +0 -36
  642. package/dist/cjs/utils/serialize.d.ts.map +0 -1
  643. package/dist/cjs/utils/serialize.js +0 -77
  644. package/dist/cjs/utils/serialize.js.map +0 -1
  645. package/dist/cjs/utils/session.d.ts +0 -124
  646. package/dist/cjs/utils/session.d.ts.map +0 -1
  647. package/dist/cjs/utils/session.js +0 -396
  648. package/dist/cjs/utils/session.js.map +0 -1
  649. package/dist/constants/index.d.ts +0 -2
  650. package/dist/constants/index.d.ts.map +0 -1
  651. package/dist/constants/index.js +0 -4
  652. package/dist/constants/index.js.map +0 -1
  653. package/dist/core/AutoChainExecutor.d.ts +0 -97
  654. package/dist/core/AutoChainExecutor.d.ts.map +0 -1
  655. package/dist/core/AutoChainExecutor.js +0 -284
  656. package/dist/core/AutoChainExecutor.js.map +0 -1
  657. package/dist/core/BranchEvaluator.d.ts +0 -55
  658. package/dist/core/BranchEvaluator.d.ts.map +0 -1
  659. package/dist/core/BranchEvaluator.js +0 -121
  660. package/dist/core/BranchEvaluator.js.map +0 -1
  661. package/dist/core/DirectiveChainTracker.d.ts +0 -49
  662. package/dist/core/DirectiveChainTracker.d.ts.map +0 -1
  663. package/dist/core/DirectiveChainTracker.js +0 -117
  664. package/dist/core/DirectiveChainTracker.js.map +0 -1
  665. package/dist/core/Events.d.ts +0 -26
  666. package/dist/core/Events.d.ts.map +0 -1
  667. package/dist/core/Events.js +0 -137
  668. package/dist/core/Events.js.map +0 -1
  669. package/dist/core/Flow.d.ts +0 -183
  670. package/dist/core/Flow.d.ts.map +0 -1
  671. package/dist/core/Flow.js +0 -547
  672. package/dist/core/Flow.js.map +0 -1
  673. package/dist/core/FlowRouter.d.ts +0 -183
  674. package/dist/core/FlowRouter.d.ts.map +0 -1
  675. package/dist/core/FlowRouter.js +0 -1043
  676. package/dist/core/FlowRouter.js.map +0 -1
  677. package/dist/core/PersistenceManager.d.ts +0 -114
  678. package/dist/core/PersistenceManager.d.ts.map +0 -1
  679. package/dist/core/PersistenceManager.js +0 -332
  680. package/dist/core/PersistenceManager.js.map +0 -1
  681. package/dist/core/PromptComposer.d.ts +0 -47
  682. package/dist/core/PromptComposer.d.ts.map +0 -1
  683. package/dist/core/PromptComposer.js +0 -393
  684. package/dist/core/PromptComposer.js.map +0 -1
  685. package/dist/core/PromptSectionCache.d.ts +0 -48
  686. package/dist/core/PromptSectionCache.d.ts.map +0 -1
  687. package/dist/core/PromptSectionCache.js +0 -104
  688. package/dist/core/PromptSectionCache.js.map +0 -1
  689. package/dist/core/ResponseEngine.d.ts +0 -43
  690. package/dist/core/ResponseEngine.d.ts.map +0 -1
  691. package/dist/core/ResponseEngine.js +0 -231
  692. package/dist/core/ResponseEngine.js.map +0 -1
  693. package/dist/core/ResponseGenerationError.d.ts +0 -30
  694. package/dist/core/ResponseGenerationError.d.ts.map +0 -1
  695. package/dist/core/ResponseGenerationError.js +0 -31
  696. package/dist/core/ResponseGenerationError.js.map +0 -1
  697. package/dist/core/ResponseModal.d.ts +0 -305
  698. package/dist/core/ResponseModal.d.ts.map +0 -1
  699. package/dist/core/ResponseModal.js +0 -1410
  700. package/dist/core/ResponseModal.js.map +0 -1
  701. package/dist/core/ResponsePipeline.d.ts +0 -220
  702. package/dist/core/ResponsePipeline.d.ts.map +0 -1
  703. package/dist/core/ResponsePipeline.js +0 -1035
  704. package/dist/core/ResponsePipeline.js.map +0 -1
  705. package/dist/core/SessionFinalizer.d.ts +0 -34
  706. package/dist/core/SessionFinalizer.d.ts.map +0 -1
  707. package/dist/core/SessionFinalizer.js +0 -84
  708. package/dist/core/SessionFinalizer.js.map +0 -1
  709. package/dist/core/SessionManager.d.ts +0 -112
  710. package/dist/core/SessionManager.d.ts.map +0 -1
  711. package/dist/core/SessionManager.js +0 -301
  712. package/dist/core/SessionManager.js.map +0 -1
  713. package/dist/core/SignalCoordinator.d.ts +0 -103
  714. package/dist/core/SignalCoordinator.d.ts.map +0 -1
  715. package/dist/core/SignalCoordinator.js +0 -203
  716. package/dist/core/SignalCoordinator.js.map +0 -1
  717. package/dist/core/SignalEvaluator.d.ts +0 -86
  718. package/dist/core/SignalEvaluator.d.ts.map +0 -1
  719. package/dist/core/SignalEvaluator.js +0 -312
  720. package/dist/core/SignalEvaluator.js.map +0 -1
  721. package/dist/core/SignalProcessor.d.ts +0 -152
  722. package/dist/core/SignalProcessor.d.ts.map +0 -1
  723. package/dist/core/SignalProcessor.js +0 -498
  724. package/dist/core/SignalProcessor.js.map +0 -1
  725. package/dist/core/Step.d.ts +0 -184
  726. package/dist/core/Step.d.ts.map +0 -1
  727. package/dist/core/Step.js +0 -594
  728. package/dist/core/Step.js.map +0 -1
  729. package/dist/core/StepLifecycle.d.ts +0 -43
  730. package/dist/core/StepLifecycle.d.ts.map +0 -1
  731. package/dist/core/StepLifecycle.js +0 -176
  732. package/dist/core/StepLifecycle.js.map +0 -1
  733. package/dist/core/StreamingToolExecutor.d.ts +0 -142
  734. package/dist/core/StreamingToolExecutor.d.ts.map +0 -1
  735. package/dist/core/StreamingToolExecutor.js +0 -483
  736. package/dist/core/StreamingToolExecutor.js.map +0 -1
  737. package/dist/core/ToolLoopExecutor.d.ts +0 -133
  738. package/dist/core/ToolLoopExecutor.d.ts.map +0 -1
  739. package/dist/core/ToolLoopExecutor.js +0 -564
  740. package/dist/core/ToolLoopExecutor.js.map +0 -1
  741. package/dist/core/ToolManager.d.ts +0 -250
  742. package/dist/core/ToolManager.d.ts.map +0 -1
  743. package/dist/core/ToolManager.js +0 -1098
  744. package/dist/core/ToolManager.js.map +0 -1
  745. package/dist/core/createAgent.d.ts +0 -35
  746. package/dist/core/createAgent.d.ts.map +0 -1
  747. package/dist/core/createAgent.js +0 -36
  748. package/dist/core/createAgent.js.map +0 -1
  749. package/dist/core/flow-namespace.d.ts +0 -64
  750. package/dist/core/flow-namespace.d.ts.map +0 -1
  751. package/dist/core/flow-namespace.js +0 -179
  752. package/dist/core/flow-namespace.js.map +0 -1
  753. package/dist/core/toolGates.d.ts +0 -24
  754. package/dist/core/toolGates.d.ts.map +0 -1
  755. package/dist/core/toolGates.js +0 -49
  756. package/dist/core/toolGates.js.map +0 -1
  757. package/dist/types/persistence.d.ts +0 -254
  758. package/dist/types/persistence.d.ts.map +0 -1
  759. package/dist/types/persistence.js +0 -6
  760. package/dist/types/persistence.js.map +0 -1
  761. package/dist/types/prompt-cache.d.ts +0 -15
  762. package/dist/types/prompt-cache.d.ts.map +0 -1
  763. package/dist/types/prompt-cache.js +0 -5
  764. package/dist/types/prompt-cache.js.map +0 -1
  765. package/dist/types/signals.d.ts +0 -263
  766. package/dist/types/signals.d.ts.map +0 -1
  767. package/dist/types/signals.js +0 -10
  768. package/dist/types/signals.js.map +0 -1
  769. package/dist/types/template.d.ts +0 -84
  770. package/dist/types/template.d.ts.map +0 -1
  771. package/dist/types/template.js +0 -2
  772. package/dist/types/template.js.map +0 -1
  773. package/dist/utils/condition.d.ts +0 -63
  774. package/dist/utils/condition.d.ts.map +0 -1
  775. package/dist/utils/condition.js +0 -230
  776. package/dist/utils/condition.js.map +0 -1
  777. package/dist/utils/event.d.ts +0 -6
  778. package/dist/utils/event.d.ts.map +0 -1
  779. package/dist/utils/event.js +0 -17
  780. package/dist/utils/event.js.map +0 -1
  781. package/dist/utils/id.d.ts +0 -33
  782. package/dist/utils/id.d.ts.map +0 -1
  783. package/dist/utils/id.js +0 -77
  784. package/dist/utils/id.js.map +0 -1
  785. package/dist/utils/serialize.d.ts +0 -36
  786. package/dist/utils/serialize.d.ts.map +0 -1
  787. package/dist/utils/serialize.js +0 -72
  788. package/dist/utils/serialize.js.map +0 -1
  789. package/dist/utils/session.d.ts +0 -124
  790. package/dist/utils/session.d.ts.map +0 -1
  791. package/dist/utils/session.js +0 -379
  792. package/dist/utils/session.js.map +0 -1
  793. package/docs/concepts/directives.md +0 -369
  794. package/docs/reference/adapters.md +0 -543
  795. package/docs/reference/create-agent.md +0 -216
  796. package/docs/reference/directive.md +0 -242
  797. package/docs/reference/signals.md +0 -368
  798. package/examples/02-data-extraction.ts +0 -90
  799. package/examples/05-branching.ts +0 -140
  800. package/examples/06-flow-control.ts +0 -103
  801. package/examples/08-persistence.ts +0 -98
  802. package/examples/09-signals.ts +0 -144
  803. package/src/adapters/MemoryAdapter.ts +0 -281
  804. package/src/adapters/MongoAdapter.ts +0 -341
  805. package/src/adapters/OpenSearchAdapter.ts +0 -693
  806. package/src/adapters/PostgreSQLAdapter.ts +0 -487
  807. package/src/adapters/PrismaAdapter.ts +0 -617
  808. package/src/adapters/RedisAdapter.ts +0 -439
  809. package/src/adapters/SQLiteAdapter.ts +0 -496
  810. package/src/adapters/index.ts +0 -43
  811. package/src/adapters/sessionRow.ts +0 -57
  812. package/src/constants/index.ts +0 -2
  813. package/src/core/AutoChainExecutor.ts +0 -397
  814. package/src/core/BranchEvaluator.ts +0 -161
  815. package/src/core/DirectiveChainTracker.ts +0 -144
  816. package/src/core/Events.ts +0 -164
  817. package/src/core/Flow.ts +0 -665
  818. package/src/core/FlowRouter.ts +0 -1540
  819. package/src/core/PersistenceManager.ts +0 -446
  820. package/src/core/PromptComposer.ts +0 -448
  821. package/src/core/PromptSectionCache.ts +0 -125
  822. package/src/core/ResponseEngine.ts +0 -338
  823. package/src/core/ResponseGenerationError.ts +0 -53
  824. package/src/core/ResponseModal.ts +0 -1902
  825. package/src/core/ResponsePipeline.ts +0 -1404
  826. package/src/core/SessionFinalizer.ts +0 -108
  827. package/src/core/SessionManager.ts +0 -372
  828. package/src/core/SignalCoordinator.ts +0 -263
  829. package/src/core/SignalEvaluator.ts +0 -404
  830. package/src/core/SignalProcessor.ts +0 -663
  831. package/src/core/Step.ts +0 -782
  832. package/src/core/StepLifecycle.ts +0 -242
  833. package/src/core/StreamingToolExecutor.ts +0 -609
  834. package/src/core/ToolLoopExecutor.ts +0 -749
  835. package/src/core/ToolManager.ts +0 -1379
  836. package/src/core/createAgent.ts +0 -40
  837. package/src/core/flow-namespace.ts +0 -227
  838. package/src/core/toolGates.ts +0 -72
  839. package/src/types/persistence.ts +0 -303
  840. package/src/types/prompt-cache.ts +0 -17
  841. package/src/types/signals.ts +0 -338
  842. package/src/types/template.ts +0 -98
  843. package/src/utils/condition.ts +0 -296
  844. package/src/utils/event.ts +0 -16
  845. package/src/utils/id.ts +0 -91
  846. package/src/utils/serialize.ts +0 -86
  847. package/src/utils/session.ts +0 -501
@@ -1,1410 +0,0 @@
1
- /**
2
- * ResponseModal handles all response generation logic for the Agent
3
- * Provides both streaming and non-streaming response generation with unified logic
4
- */
5
- import { ResponseEngine } from "./ResponseEngine.js";
6
- import { ResponsePipeline } from "./ResponsePipeline.js";
7
- import { AutoChainExecutor } from "./AutoChainExecutor.js";
8
- import { StepLifecycle } from "./StepLifecycle.js";
9
- import { SessionFinalizer } from "./SessionFinalizer.js";
10
- import { ToolLoopExecutor } from "./ToolLoopExecutor.js";
11
- import { flow } from "./flow-namespace.js";
12
- import { SignalCoordinator } from "./SignalCoordinator.js";
13
- import { ResponseGenerationError } from "./ResponseGenerationError.js";
14
- import { ProviderError, SessionConflictError } from "../types/errors.js";
15
- import { cloneDeep, mergeCollected, logger, historyToEvents, completeCurrentFlow, render, userMessage, assistantMessage } from "../utils/index.js";
16
- import { createTemplateContext } from "../utils/template.js";
17
- import { StreamingMessageDecoder } from "../utils/streamingMessage.js";
18
- import { extractEmbeddedJSONObject, isJSONShaped, tryParseJSONResponse } from "../utils/json.js";
19
- /**
20
- * ResponseModal class that encapsulates all response generation logic
21
- * Uses unified approach for both streaming and non-streaming responses
22
- */
23
- export class ResponseModal {
24
- constructor(agent, options) {
25
- this.agent = agent;
26
- this.options = options;
27
- // Initialize response engine
28
- this.responseEngine = new ResponseEngine(this.agent.promptSectionCache);
29
- // Signal pre/post phase orchestration
30
- this.signalCoordinator = new SignalCoordinator({
31
- getFlows: () => this.agent.getFlows(),
32
- signalProcessor: this.agent.signalProcessor,
33
- });
34
- // Initialize response pipeline with agent dependencies
35
- this.responsePipeline = new ResponsePipeline(this.agent.getAgentOptions(), () => this.agent.getFlows(), // Pass a function to get flows dynamically
36
- this.agent.getFlowRouter(), this.signalCoordinator, this.agent.updateCollectedData.bind(this.agent), () => this.agent.schema);
37
- // Step prepare/finalize execution, shared by the prepare phase and finalizer
38
- this.stepLifecycle = new StepLifecycle({
39
- getFlows: () => this.agent.getFlows(),
40
- toolManager: this.getToolManager(),
41
- updateContext: this.agent.updateContext.bind(this.agent),
42
- updateData: this.agent.updateCollectedData.bind(this.agent),
43
- });
44
- // Single owner of end-of-turn finalization (compaction + persistence + sync)
45
- this.sessionFinalizer = new SessionFinalizer({
46
- getCompactionOptions: () => this.agent.getCompactionOptions(),
47
- getPersistenceManager: () => this.agent.getPersistenceManager(),
48
- getAgentOptions: () => this.agent.getAgentOptions(),
49
- getCurrentSession: () => this.agent.currentSession,
50
- setCurrentSession: (session) => { this.agent.currentSession = session; },
51
- stepLifecycle: this.stepLifecycle,
52
- enableAutoSave: this.options?.enableAutoSave,
53
- });
54
- // Tool follow-up loop (run tools, ask the LLM again) + streaming batch execution
55
- this.toolLoopExecutor = new ToolLoopExecutor({
56
- toolManager: this.getToolManager(),
57
- getAgentOptions: () => this.agent.getAgentOptions(),
58
- updateContext: this.agent.updateContext.bind(this.agent),
59
- updateCollectedData: this.agent.updateCollectedData.bind(this.agent),
60
- updateSessionData: this.agent.getUpdateDataMethod(),
61
- maxToolLoops: this.options?.maxToolLoops,
62
- });
63
- }
64
- /**
65
- * Generate a non-streaming response using unified logic
66
- */
67
- async respond(params) {
68
- // Snapshot the managed session so a failed turn has no in-memory effect:
69
- // without this, mutations made before the failure leave the live session
70
- // diverged from persisted state
71
- const preTurnSession = this.agent.session.current
72
- ? cloneDeep(this.agent.session.current)
73
- : undefined;
74
- try {
75
- // Use unified response preparation and routing
76
- const responseContext = await this.prepareUnifiedResponseContext(params);
77
- // Generate response using unified logic
78
- const result = await this.generateUnifiedResponse(responseContext);
79
- // Finalize session — the non-streaming turn's single finalize
80
- await this.sessionFinalizer.finalize(result.session, responseContext.effectiveContext);
81
- return result;
82
- }
83
- catch (error) {
84
- if (preTurnSession) {
85
- this.agent.session.syncSession(preTurnSession);
86
- }
87
- // Typed library errors carry their own semantics (ProviderError.code,
88
- // SessionConflictError) — rethrow bare so consumers can branch on
89
- // them instead of string-matching. Everything else wraps with the
90
- // original attached as `cause`.
91
- if (error instanceof ProviderError || error instanceof SessionConflictError) {
92
- throw error;
93
- }
94
- throw new ResponseGenerationError(`[ResponseGenerationError] Response generation failed: ${error instanceof Error ? error.message : String(error)}. ` +
95
- `Check provider configuration and network connectivity.`, { originalError: error, params, phase: 'response_generation' });
96
- }
97
- }
98
- /**
99
- * Generate a streaming response using unified logic
100
- */
101
- async *respondStream(params) {
102
- // Same failed-turn rollback semantics as respond()
103
- const preTurnSession = this.agent.session.current
104
- ? cloneDeep(this.agent.session.current)
105
- : undefined;
106
- try {
107
- // Use unified response preparation and routing
108
- const responseContext = await this.prepareUnifiedResponseContext(params);
109
- // Generate streaming response using unified logic
110
- yield* this.generateUnifiedStreamingResponse(responseContext);
111
- }
112
- catch (error) {
113
- if (preTurnSession) {
114
- this.agent.session.syncSession(preTurnSession);
115
- }
116
- // Stream error to caller
117
- yield {
118
- delta: "",
119
- accumulated: "",
120
- done: true,
121
- session: params.session || await this.agent.session.getOrCreate(),
122
- error: new ResponseGenerationError(`Streaming response failed: ${error instanceof Error ? error.message : String(error)}`, { originalError: error, params, phase: 'streaming' }),
123
- };
124
- }
125
- }
126
- /**
127
- * Modern streaming API - simple interface like chat()
128
- */
129
- async *stream(message, options) {
130
- // Determine which history to use
131
- let history;
132
- if (options?.history) {
133
- // Use provided history for this response only
134
- history = options.history;
135
- }
136
- else {
137
- // Add user message to session history if provided
138
- if (message) {
139
- await this.agent.session.addMessage("user", message);
140
- }
141
- history = this.agent.session.getHistory();
142
- }
143
- // Get or create session — session.data is the single source of truth,
144
- // so no agent-side data merge is needed
145
- const session = await this.agent.session.getOrCreate();
146
- // Stream response using existing respondStream method
147
- let finalMessage = "";
148
- let finalizedSession;
149
- for await (const chunk of this.respondStream({
150
- history,
151
- session,
152
- contextOverride: options?.contextOverride,
153
- signal: options?.signal,
154
- })) {
155
- // Accumulate the final message and capture finalized session
156
- if (chunk.done) {
157
- finalMessage = chunk.accumulated;
158
- finalizedSession = chunk.session;
159
- }
160
- yield chunk;
161
- }
162
- // Sync finalized session to agent.session.current (skip in override-history mode)
163
- // Must happen BEFORE addMessage so the assistant message is added on top of the synced session state
164
- if (!options?.history && finalizedSession) {
165
- this.agent.session.syncSession(finalizedSession);
166
- }
167
- // Add agent response to session history (only if not using override history)
168
- if (!options?.history && finalMessage) {
169
- await this.agent.session.addMessage("assistant", finalMessage);
170
- }
171
- }
172
- /**
173
- * Modern non-streaming API - equivalent to chat() but more explicit
174
- */
175
- async generate(message, options) {
176
- // Determine which history to use
177
- let history;
178
- if (options?.history) {
179
- // Use provided history for this response only
180
- history = options.history;
181
- }
182
- else {
183
- // Add user message to session history if provided
184
- if (message) {
185
- await this.agent.session.addMessage("user", message);
186
- }
187
- history = this.agent.session.getHistory();
188
- }
189
- // Get or create session — session.data is the single source of truth,
190
- // so no agent-side data merge is needed
191
- const session = await this.agent.session.getOrCreate();
192
- // Generate response using existing respond method
193
- const result = await this.respond({
194
- history,
195
- session,
196
- contextOverride: options?.contextOverride,
197
- signal: options?.signal,
198
- });
199
- // Sync finalized session to agent.session.current (skip in override-history mode)
200
- // Must happen BEFORE addMessage so the assistant message is added on top of the synced session state
201
- if (!options?.history && result.session) {
202
- this.agent.session.syncSession(result.session);
203
- }
204
- // Add agent response to session history (only if not using override history)
205
- if (!options?.history) {
206
- await this.agent.session.addMessage("assistant", result.message);
207
- }
208
- // Ensure the result includes the current session
209
- return {
210
- ...result,
211
- session: result.session || this.agent.session.current,
212
- };
213
- }
214
- /**
215
- * Get the response engine instance
216
- * @internal
217
- */
218
- getResponseEngine() {
219
- return this.responseEngine;
220
- }
221
- /**
222
- * Get the response pipeline instance
223
- * @internal
224
- */
225
- getResponsePipeline() {
226
- return this.responsePipeline;
227
- }
228
- /**
229
- * Get the ToolManager instance from the agent.
230
- * @private
231
- */
232
- getToolManager() {
233
- return this.agent.tool;
234
- }
235
- /**
236
- * Recover a structured payload from a schema-mandated response the provider
237
- * could not parse. Raw protocol fragments must never surface as the
238
- * user-visible reply. Three shapes arrive here:
239
- * - a truncated or fence-wrapped envelope → one repair-parse;
240
- * - conversational prose FOLLOWED BY the envelope (the model answered
241
- * twice — the observed WhatsApp leak) → recover the embedded envelope,
242
- * whose "message" field is the complete intended reply;
243
- * - plain prose with nothing recoverable → `undefined`; the caller passes
244
- * it through untouched. (An envelope truncated mid-stream after prose
245
- * also lands here: the prose is user-worthy and the fragment carries
246
- * nothing recoverable.)
247
- * An unrecoverable JSON-SHAPED fragment throws so the turn fails LOUDLY
248
- * and the caller's rollback/retry path engages instead of leaking
249
- * `{"message": "…` to an end user.
250
- */
251
- salvageStructuredOutput(raw, surface) {
252
- const salvaged = tryParseJSONResponse(raw);
253
- if (salvaged && typeof salvaged.message === "string") {
254
- logger.warn(`[ResponseModal] Salvaged malformed structured output from ${surface} via JSON repair parse.`);
255
- return { ...salvaged, message: salvaged.message };
256
- }
257
- const embedded = extractEmbeddedJSONObject(raw);
258
- if (embedded && typeof embedded.message === "string") {
259
- logger.warn(`[ResponseModal] Salvaged structured output embedded after prose from ${surface}.`);
260
- return { ...embedded, message: embedded.message };
261
- }
262
- if (isJSONShaped(raw)) {
263
- throw ResponseGenerationError.fromError(new Error("Model returned a schema-mandated response that could not be parsed as JSON. " +
264
- `The ${surface} was failed instead of delivering raw protocol output to the user.`), 'structured_output_malformed', { responseSchemaName: 'response_output' });
265
- }
266
- return undefined;
267
- }
268
- /**
269
- * Tool-emitted directives (ctx.dispatch / `{directive}` returns): state
270
- * writes apply now; control flow queues for the next turn's
271
- * pendingDirective applier (same deferred semantics as dispatch()).
272
- */
273
- async applyToolEmittedDirectives(session, d) {
274
- if (d.dataUpdate) {
275
- session = mergeCollected(session, d.dataUpdate);
276
- }
277
- if (d.contextUpdate) {
278
- await this.agent.updateContext(d.contextUpdate);
279
- }
280
- const control = { ...d };
281
- delete control.dataUpdate;
282
- delete control.contextUpdate;
283
- if (Object.keys(control).length > 0) {
284
- flow.queuePending(session, control);
285
- }
286
- return session;
287
- }
288
- /**
289
- * Collect scoped instructions from agent, flow, and step into a ScopedInstructions value.
290
- * @private
291
- */
292
- collectScopedInstructions(flow, step) {
293
- return {
294
- global: this.agent.instructions,
295
- flow: flow ? { flowTitle: flow.title, items: flow.instructions } : undefined,
296
- step: step ? { stepId: step.id, items: step.getInstructions() } : undefined,
297
- };
298
- }
299
- // UNIFIED RESPONSE LOGIC - Consolidates common logic between streaming and non-streaming
300
- // ============================================================================
301
- /**
302
- * Unified response preparation - handles context setup, session management, and routing
303
- * This consolidates common logic between streaming and non-streaming responses
304
- * @private
305
- */
306
- async prepareUnifiedResponseContext(params) {
307
- try {
308
- const { history: simpleHistory, contextOverride, signal, message: turnMessage, allowedFlows } = params;
309
- // Validate input parameters
310
- if (!simpleHistory) {
311
- throw new ResponseGenerationError('[ResponseGenerationError] Missing history: history is required for response generation. ' +
312
- 'Pass a valid history array (or pass `message` alongside an existing history base).', { params, phase: 'validation' });
313
- }
314
- // `message` is the user turn: appended to what the model sees this
315
- // turn AND recorded on the returned session's history.
316
- const history = turnMessage
317
- ? [...simpleHistory, userMessage(turnMessage)]
318
- : simpleHistory;
319
- // Convert HistoryItem[] to Event[] for internal processing
320
- const historyEvents = historyToEvents(history);
321
- // Use ResponsePipeline for context and session preparation; context
322
- // and session are passed explicitly — the pipeline holds no state
323
- let responseContext;
324
- try {
325
- responseContext = await this.responsePipeline.prepareResponseContext({
326
- contextOverride,
327
- session: params.session ? cloneDeep(params.session) : undefined,
328
- currentContext: await this.agent.getContext(),
329
- currentSession: this.agent.currentSession,
330
- });
331
- }
332
- catch (error) {
333
- throw ResponseGenerationError.fromError(error, 'pipeline_context_preparation', params);
334
- }
335
- const { effectiveContext, contextAfterHook } = responseContext;
336
- let session = responseContext.session;
337
- // Sync the beforeRespond hook's context result back to the agent
338
- if (contextAfterHook !== undefined) {
339
- try {
340
- await this.agent.updateContext(contextAfterHook);
341
- }
342
- catch (error) {
343
- throw ResponseGenerationError.fromError(error, 'context_update_from_pipeline', params, { contextAfterHook });
344
- }
345
- }
346
- // Apply data staged before any session existed (initialData,
347
- // pre-session updateCollectedData calls). Reading the live session's
348
- // data here would leak state across sessions when an explicit
349
- // session is passed, so only the staging buffer is merged.
350
- const stagedData = this.agent.consumePendingData();
351
- if (Object.keys(stagedData).length > 0) {
352
- try {
353
- session = mergeCollected(session, stagedData);
354
- logger.debug("[ResponseModal] Merged staged agent data into session:", stagedData);
355
- }
356
- catch (error) {
357
- throw ResponseGenerationError.fromError(error, 'data_merging', params, { stagedData });
358
- }
359
- }
360
- // Record the user turn on the session's own history so the returned
361
- // session carries the full exchange (respond owns session.history
362
- // when `message` is used).
363
- if (turnMessage) {
364
- session.history = [...(session.history ?? []), userMessage(turnMessage)];
365
- }
366
- // PHASE 1: PREPARE - Execute prepare function if current step has one
367
- try {
368
- const prepareDirective = await this.stepLifecycle.runPrepare(session, effectiveContext);
369
- // Queue the control-flow directive for THIS turn: routing
370
- // (handleRoutingAndStepSelection) consumes session.pendingDirective
371
- // before deciding flow/step, so a prepare-phase goTo/goToStep/
372
- // reset steers the current turn.
373
- if (prepareDirective) {
374
- flow.queuePending(session, prepareDirective);
375
- }
376
- }
377
- catch (error) {
378
- throw ResponseGenerationError.fromError(error, 'step_preparation', params, { session, effectiveContext });
379
- }
380
- // PHASE 2: ROUTING + STEP SELECTION - Determine which flow and step to use
381
- // Performs pre-extraction and step selection
382
- let routingResult;
383
- try {
384
- routingResult = await this.responsePipeline.routeAndSelectStep({
385
- session,
386
- history: historyEvents,
387
- context: effectiveContext,
388
- signal,
389
- allowedFlows,
390
- });
391
- }
392
- catch (error) {
393
- throw ResponseGenerationError.fromError(error, 'routing_and_step_selection', params, { session, effectiveContext });
394
- }
395
- return {
396
- effectiveContext,
397
- session: routingResult.session,
398
- history,
399
- turnMessage,
400
- selectedFlow: routingResult.selectedFlow,
401
- selectedStep: routingResult.selectedStep,
402
- responseDirectives: routingResult.responseDirectives,
403
- isFlowComplete: routingResult.isFlowComplete,
404
- signal,
405
- signalFirings: routingResult.signalFirings,
406
- signalPreDirective: routingResult.signalPreDirective,
407
- signalHalted: routingResult.signalHalted,
408
- signalHaltReply: routingResult.signalHaltReply,
409
- endedFlows: routingResult.endedFlows,
410
- };
411
- }
412
- catch (error) {
413
- // Re-throw ResponseGenerationError as-is, wrap others
414
- if (ResponseGenerationError.isResponseGenerationError(error)) {
415
- throw error;
416
- }
417
- throw ResponseGenerationError.fromError(error, 'preparation', params);
418
- }
419
- }
420
- /**
421
- * Plan a turn: run signal-halt detection, the auto-chain walk, and flow/step
422
- * selection, collapsing them into a single {@link TurnOutcome}. This is the
423
- * shared decision spine for both the streaming and non-streaming paths — the
424
- * only logic that genuinely differs between them is how each *renders* the
425
- * outcome (await a value vs. yield chunks) and the leaf provider primitive it
426
- * uses. Centralizing the decision here is what keeps the two paths from
427
- * drifting (the class of bug behind the 2.4.x retry/empty fixes).
428
- *
429
- * The returned `session` reflects any auto-chain mutation; `signalFirings`
430
- * is seeded with the pre-signal phase firings and is the live accumulator the
431
- * post-phase tail appends to.
432
- * @private
433
- */
434
- async planTurn(responseContext) {
435
- const { effectiveContext, history, selectedFlow, selectedStep, responseDirectives, isFlowComplete, signal, signalFirings: preSignalFirings, signalPreDirective, signalHalted, signalHaltReply, } = responseContext;
436
- let session = responseContext.session;
437
- // Accumulator for signal firings across both phases (fire order)
438
- const signalFirings = [...(preSignalFirings || [])];
439
- // Convert HistoryItem[] to Event[] for internal processing
440
- const historyEvents = historyToEvents(history);
441
- const base = { effectiveContext, history, historyEvents, signal, signalFirings };
442
- // ── SIGNAL HALT (Requirement 8.2) ─────────────────────────────────────
443
- // Pre-signal phase emitted halt → skip LLM call entirely. The post-signal
444
- // phase still runs (it sees the complete turn context).
445
- if (signalHalted) {
446
- const haltMessage = signalHaltReply || '';
447
- return {
448
- ...base, session,
449
- outcome: { kind: 'halt', message: haltMessage, stoppedReason: haltMessage ? 'reply' : 'halt', runPostPhase: true },
450
- };
451
- }
452
- if (selectedFlow && !isFlowComplete) {
453
- // AUTO-CHAIN: Walk consecutive auto-steps before any LLM work. If the
454
- // current step is auto, the executor advances through it (and any
455
- // subsequent auto-steps) until an interactive step or terminal condition.
456
- let resolvedStep = selectedStep;
457
- const currentStepInstance = session.currentStep
458
- ? selectedFlow.getStep(session.currentStep.id)
459
- : selectedStep;
460
- if (currentStepInstance?.auto) {
461
- const autoChainExecutor = new AutoChainExecutor({
462
- maxAutoStepsPerTurn: this.agent.maxAutoStepsPerTurn,
463
- });
464
- const autoResult = await autoChainExecutor.run({
465
- session,
466
- context: effectiveContext,
467
- flow: selectedFlow,
468
- });
469
- session = autoResult.session;
470
- // Halt: emit the verbatim reply, no LLM call. Unlike signal halt,
471
- // the auto-chain halt is a hard short-circuit that does NOT run the
472
- // post-signal phase (preserved across both paths).
473
- if (autoResult.stoppedReason === 'halt') {
474
- return {
475
- ...base, session,
476
- outcome: { kind: 'halt', message: autoResult.mergedDirective?.reply || '', stoppedReason: 'halt', runPostPhase: false },
477
- };
478
- }
479
- // Flow completion or cross-flow redirect from auto-chain: the chain
480
- // ended without resolving to an interactive step (last_step: no
481
- // successor; completed: explicit complete; goto: cross-flow redirect).
482
- if (autoResult.stoppedReason === 'last_step' || autoResult.stoppedReason === 'completed' || autoResult.stoppedReason === 'goto') {
483
- logger.debug(`[ResponseModal] Auto-chain ended with ${autoResult.stoppedReason}`);
484
- return {
485
- ...base, session,
486
- outcome: { kind: 'flowComplete', selectedFlow, stoppedReason: autoResult.stoppedReason },
487
- };
488
- }
489
- // Normal case: auto-chain resolved to an interactive step.
490
- resolvedStep = autoResult.resolvedStep;
491
- }
492
- return {
493
- ...base, session,
494
- outcome: { kind: 'flowStep', selectedFlow, step: resolvedStep, responseDirectives, signalPreDirective },
495
- };
496
- }
497
- if (isFlowComplete && selectedFlow) {
498
- // Flow completion path: pure state transition, no LLM call. The reason
499
- // is 'last_step' (implicit terminus — no successor or all skipped).
500
- logger.debug(`[ResponseModal] Releasing session to idle for completed flow: ${selectedFlow.title}`);
501
- return {
502
- ...base, session,
503
- outcome: { kind: 'flowComplete', selectedFlow, stoppedReason: 'last_step' },
504
- };
505
- }
506
- // Fallback: no flows defined, generate a simple response.
507
- return { ...base, session, outcome: { kind: 'fallback' } };
508
- }
509
- /**
510
- * The shared post-signal phase tail (Requirement 9.1–9.4). Runs after the
511
- * turn's message is known and before persistence, so post-phase signals see
512
- * the complete turn result (assistant message, collected data, tool results)
513
- * and can override the reply or wire a pendingDirective.
514
- *
515
- * `runPostPhase` is false only for the auto-chain halt short-circuit, which
516
- * deliberately bypasses the post-phase in both paths; that branch still
517
- * surfaces any pre-phase firings via `triggeredSignals`.
518
- * @private
519
- */
520
- async applyTurnPostPhase(params) {
521
- const { session, context, historyEvents, message, signalFirings, runPostPhase } = params;
522
- if (!runPostPhase) {
523
- return {
524
- session, message, replyOverridden: false,
525
- triggeredSignals: signalFirings.length > 0 ? signalFirings : undefined,
526
- };
527
- }
528
- const post = await this.signalCoordinator.applyPostPhase({ session, context, historyEvents, message });
529
- signalFirings.push(...post.firings);
530
- return {
531
- session: post.session,
532
- message: post.message,
533
- replyOverridden: post.replyOverridden ?? false,
534
- triggeredSignals: signalFirings.length > 0 ? signalFirings : undefined,
535
- };
536
- }
537
- /**
538
- * Unified response generation for non-streaming responses.
539
- * Renders the shared {@link planTurn} outcome by awaiting the leaf primitive
540
- * and running the shared post-phase tail; respond() owns the single finalize.
541
- * @private
542
- */
543
- async generateUnifiedResponse(responseContext) {
544
- const plan = await this.planTurn(responseContext);
545
- const { effectiveContext, history, historyEvents, signal, signalFirings } = plan;
546
- let session = plan.session;
547
- let message = '';
548
- let toolCalls = undefined;
549
- let executedSteps = [];
550
- let stoppedReason;
551
- let isFlowComplete = false;
552
- let appliedInstructions;
553
- let runPostPhase = true;
554
- let tokensUsed;
555
- const endedFlows = [...(responseContext.endedFlows ?? [])];
556
- switch (plan.outcome.kind) {
557
- case 'halt': {
558
- message = plan.outcome.message;
559
- stoppedReason = plan.outcome.stoppedReason;
560
- runPostPhase = plan.outcome.runPostPhase;
561
- break;
562
- }
563
- case 'flowComplete': {
564
- session = await this.applyFlowCompletion({
565
- selectedFlow: plan.outcome.selectedFlow,
566
- session,
567
- context: effectiveContext,
568
- history,
569
- });
570
- isFlowComplete = true;
571
- stoppedReason = plan.outcome.stoppedReason;
572
- endedFlows.push({
573
- flowId: plan.outcome.selectedFlow.id,
574
- title: plan.outcome.selectedFlow.title,
575
- reason: plan.outcome.stoppedReason,
576
- });
577
- break;
578
- }
579
- case 'flowStep': {
580
- const result = await this.processFlowResponse({
581
- selectedFlow: plan.outcome.selectedFlow,
582
- selectedStep: plan.outcome.step,
583
- responseDirectives: plan.outcome.responseDirectives,
584
- session,
585
- history,
586
- context: effectiveContext,
587
- historyEvents,
588
- signal,
589
- // Propagate signal pre-directive's appendPrompt for this turn's LLM call (Requirement 8.4)
590
- transientAppendage: plan.outcome.signalPreDirective?.appendPrompt,
591
- // Merge signal pre-directive (halt/reply/injectTools) into the pre-LLM bus
592
- mergedPreDirective: plan.outcome.signalPreDirective,
593
- });
594
- message = result.message;
595
- toolCalls = result.toolCalls;
596
- session = result.session;
597
- appliedInstructions = result.appliedInstructions;
598
- tokensUsed = result.tokensUsed;
599
- if (plan.outcome.step) {
600
- executedSteps = [{ id: plan.outcome.step.id, flowId: plan.outcome.selectedFlow.id }];
601
- }
602
- // Use stoppedReason from processFlowResponse if set (halt/reply),
603
- // otherwise default to 'needs_input' for normal LLM responses.
604
- stoppedReason = result.stoppedReason || 'needs_input';
605
- break;
606
- }
607
- case 'fallback': {
608
- const fallbackResult = await this.generateFallbackResponse({
609
- history,
610
- context: effectiveContext,
611
- session,
612
- signal,
613
- });
614
- message = fallbackResult.message;
615
- appliedInstructions = fallbackResult.appliedInstructions;
616
- break;
617
- }
618
- }
619
- const tail = await this.applyTurnPostPhase({
620
- session, context: effectiveContext, historyEvents, message, signalFirings, runPostPhase,
621
- });
622
- // History ownership: with params.message the returned session carries
623
- // the full exchange — the user turn was recorded pre-routing, the
624
- // assistant tail lands here (post-phase, so overridden replies are the
625
- // ones recorded). Empty tails are skipped.
626
- if (responseContext.turnMessage && tail.message) {
627
- tail.session.history = [...(tail.session.history ?? []), assistantMessage(tail.message)];
628
- }
629
- return {
630
- message: tail.message,
631
- session: tail.session,
632
- toolCalls,
633
- isFlowComplete,
634
- executedSteps,
635
- stoppedReason,
636
- appliedInstructions,
637
- triggeredSignals: tail.triggeredSignals,
638
- ...(tokensUsed !== undefined ? { metadata: { tokensUsed } } : {}),
639
- ...(endedFlows.length > 0 ? { endedFlows } : {}),
640
- };
641
- }
642
- /**
643
- * Process flow response with unified tool execution and data collection
644
- * @private
645
- */
646
- async processFlowResponse(params) {
647
- const { selectedFlow, selectedStep, responseDirectives, history, context, historyEvents, signal, transientAppendage, mergedPreDirective } = params;
648
- let session = params.session;
649
- // Resolve the step to render (branches win over linear chain; requires enforced)
650
- const stepResolution = await this.responsePipeline.resolveRenderStep({
651
- selectedFlow,
652
- selectedStep,
653
- session,
654
- context,
655
- });
656
- if (stepResolution.flowTransition) {
657
- // Flow transition or completion — no local step to render
658
- // Return empty message with updated session; caller handles flow transition
659
- return { message: '', session: stepResolution.session };
660
- }
661
- const nextStep = stepResolution.nextStep;
662
- session = stepResolution.session;
663
- // Build response schema for this flow (with collect fields from step)
664
- const responseSchema = this.responseEngine.responseSchemaForFlow(selectedFlow, nextStep, this.agent.schema);
665
- // ── HALT SHORT-CIRCUIT (Requirement 2.5, 2.6, 2.7) ──────────────────────
666
- // After pre-LLM emissions are merged, if `halt: true` then skip the LLM
667
- // call entirely. The behavior depends on whether `reply` is also set.
668
- if (mergedPreDirective?.halt) {
669
- if (mergedPreDirective.reply) {
670
- // halt + reply: emit the reply as the assistant message
671
- logger.debug(`[ResponseModal] Halt with reply — skipping LLM call for step ${nextStep.id}`);
672
- return { message: mergedPreDirective.reply, session, stoppedReason: 'reply' };
673
- }
674
- else {
675
- // halt without reply: emit empty assistant content
676
- logger.debug(`[ResponseModal] Halt without reply — skipping LLM call for step ${nextStep.id}`);
677
- return { message: '', session, stoppedReason: 'halt' };
678
- }
679
- }
680
- // ── STEP.REPLY SHORT-CIRCUIT (Requirement 25.1–25.7, 17.9) ──────────────
681
- // A step with `reply` set emits a verbatim template response without LLM.
682
- // onEnter and prepare have already fired normally at this point.
683
- // If prepare returned a Directive with `reply`, that overrides
684
- // the step-declared reply (last-emission-wins per Algorithm 4).
685
- if (nextStep.reply != null) {
686
- // Determine the effective reply: prepare-emitted reply wins over step-declared
687
- const effectiveReply = mergedPreDirective?.reply ?? await render(nextStep.reply, createTemplateContext({ data: session.data || {}, context, session }));
688
- logger.debug(`[ResponseModal] Step.reply — skipping LLM call for step ${nextStep.id}`);
689
- return { message: effectiveReply, session, stoppedReason: 'reply' };
690
- }
691
- // Transient appendage: per-turn slot from Directive.appendPrompt.
692
- // Fresh each turn, never cached, never persisted.
693
- // Wrapped in try/finally to ensure cleanup even on abnormal termination.
694
- let turnTransientAppendage = transientAppendage;
695
- try {
696
- // Build response prompt
697
- const { prompt: responsePrompt, appliedInstructions } = await this.responseEngine.buildResponsePrompt({
698
- flow: selectedFlow,
699
- currentStep: nextStep,
700
- rules: [],
701
- prohibitions: [],
702
- directives: responseDirectives,
703
- history: historyEvents,
704
- agentOptions: this.agent.getAgentOptions(),
705
- instructions: this.collectScopedInstructions(selectedFlow, nextStep),
706
- combinedTerms: this.agent.getTerms(),
707
- context,
708
- session,
709
- agentSchema: this.agent.schema,
710
- transientAppendage: turnTransientAppendage,
711
- });
712
- // Collect available tools for AI
713
- const availableTools = this.collectAvailableTools(selectedFlow, nextStep);
714
- // Generate message using AI provider
715
- const agentOptions = this.agent.getAgentOptions();
716
- const result = await agentOptions.provider.generateMessage({
717
- prompt: responsePrompt,
718
- history, // Use HistoryItem[] for AI provider
719
- context,
720
- tools: availableTools,
721
- signal,
722
- parameters: responseSchema ? { jsonSchema: responseSchema, schemaName: "response_output" } : undefined,
723
- });
724
- let structuredData = result.structured;
725
- let message = structuredData?.message || result.message;
726
- const tokensUsed = result.metadata?.tokensUsed;
727
- // A schema was requested but the provider failed to parse the model's
728
- // JSON (truncated output, fence-wrapped fragments). Raw protocol
729
- // fragments must never surface as the user-visible reply: attempt one
730
- // repair-parse, and if that fails fail the turn LOUDLY so the caller's
731
- // rollback/retry path engages instead of leaking `{"message": "…` to
732
- // an end user. Plain prose (not JSON-shaped at all) still passes
733
- // through — it is not a protocol fragment.
734
- if (!structuredData && responseSchema && message) {
735
- const salvaged = this.salvageStructuredOutput(message, "turn");
736
- if (salvaged) {
737
- structuredData = salvaged;
738
- message = salvaged.message;
739
- }
740
- }
741
- const effectiveResult = structuredData ? { ...result, structured: structuredData } : result;
742
- let toolCalls = structuredData?.toolCalls;
743
- // Execute tools with unified loop handling
744
- const toolResult = await this.toolLoopExecutor.runLoop({
745
- toolCalls,
746
- context,
747
- session,
748
- history,
749
- selectedFlow,
750
- responsePrompt,
751
- availableTools,
752
- responseSchema,
753
- signal,
754
- });
755
- session = toolResult.session;
756
- toolCalls = toolResult.finalToolCalls;
757
- let toolStructured = toolResult.structured;
758
- if (toolResult.finalMessage) {
759
- // The tool loop's follow-up calls carry the SAME response schema,
760
- // and their message replaces the one the guard above already
761
- // cleared — so an envelope produced after the tools ran reaches
762
- // the user through a path that guard never sees. (Observed
763
- // 2026-09-11: a catalog lookup answered, then the closing call
764
- // returned `{"message": "…"}` raw to a WhatsApp customer.)
765
- const salvaged = responseSchema
766
- ? this.salvageStructuredOutput(toolResult.finalMessage, "turn")
767
- : undefined;
768
- message = salvaged?.message ?? toolResult.finalMessage;
769
- if (salvaged)
770
- toolStructured = salvaged;
771
- }
772
- // Tool-emitted directives (ctx.dispatch / `{directive}` returns):
773
- // state writes apply now; control flow queues for the next turn's
774
- // pendingDirective applier (same deferred semantics as dispatch()).
775
- if (toolResult.directives) {
776
- session = await this.applyToolEmittedDirectives(session, toolResult.directives);
777
- }
778
- // Collect data from response
779
- // Use follow-up structured data from tool loop when available, fall back to original result
780
- const dataSource = toolStructured
781
- ? { structured: toolStructured }
782
- : effectiveResult;
783
- session = await this.collectDataFromResponse({ result: dataSource, selectedFlow, nextStep, session });
784
- return { message, toolCalls, session, appliedInstructions, tokensUsed };
785
- }
786
- finally {
787
- // Drain the transient appendage at end of turn.
788
- // This ensures Directive.appendPrompt does not leak to subsequent
789
- // turns even when the turn terminates abnormally (error, abort, reject).
790
- turnTransientAppendage = undefined;
791
- }
792
- }
793
- /**
794
- * Unified streaming response generation.
795
- * Renders the shared {@link planTurn} outcome as a chunk stream and runs the
796
- * shared post-phase tail on the final chunk (finalizing exactly once).
797
- * @private
798
- */
799
- async *generateUnifiedStreamingResponse(responseContext) {
800
- const plan = await this.planTurn(responseContext);
801
- const { effectiveContext, history, historyEvents, signal, signalFirings } = plan;
802
- const session = plan.session;
803
- // Build the inner chunk stream for the planned outcome. `runPostPhase` is
804
- // the single post-phase gate (false only for auto-chain halt).
805
- let innerStream;
806
- let runPostPhase = true;
807
- switch (plan.outcome.kind) {
808
- case 'halt': {
809
- runPostPhase = plan.outcome.runPostPhase;
810
- innerStream = this.streamTerminalMessage({
811
- message: plan.outcome.message,
812
- stoppedReason: plan.outcome.stoppedReason,
813
- session,
814
- });
815
- break;
816
- }
817
- case 'flowComplete': {
818
- innerStream = this.streamFlowCompletion({
819
- selectedFlow: plan.outcome.selectedFlow,
820
- session,
821
- context: effectiveContext,
822
- history,
823
- historyEvents,
824
- stoppedReason: plan.outcome.stoppedReason,
825
- });
826
- break;
827
- }
828
- case 'flowStep': {
829
- innerStream = this.processFlowStreamingResponse({
830
- selectedFlow: plan.outcome.selectedFlow,
831
- selectedStep: plan.outcome.step,
832
- responseDirectives: plan.outcome.responseDirectives,
833
- session,
834
- history,
835
- context: effectiveContext,
836
- historyEvents,
837
- signal,
838
- transientAppendage: plan.outcome.signalPreDirective?.appendPrompt,
839
- mergedPreDirective: plan.outcome.signalPreDirective,
840
- });
841
- break;
842
- }
843
- case 'fallback': {
844
- innerStream = this.streamFallbackResponse({
845
- history,
846
- context: effectiveContext,
847
- session,
848
- signal,
849
- });
850
- break;
851
- }
852
- }
853
- // ── Intercept the inner stream on the final chunk ──────────────────────
854
- // Mirrors the non-streaming tail: post-signal phase runs first (when
855
- // applicable), then the session is finalized exactly once, attaching
856
- // triggeredSignals to the final chunk (Requirement 11.2).
857
- for await (const chunk of innerStream) {
858
- if (chunk.done) {
859
- const tail = await this.applyTurnPostPhase({
860
- session: chunk.session || session,
861
- context: effectiveContext,
862
- historyEvents,
863
- message: chunk.accumulated,
864
- signalFirings,
865
- runPostPhase,
866
- });
867
- const accumulated = tail.message;
868
- const delta = tail.replyOverridden ? accumulated : chunk.delta;
869
- // History ownership (parity with the sync tail): with
870
- // params.message the returned session carries the full
871
- // exchange — the user turn was recorded pre-routing, the
872
- // assistant tail lands here, BEFORE finalize persists it.
873
- if (responseContext.turnMessage && tail.message) {
874
- tail.session.history = [...(tail.session.history ?? []), assistantMessage(tail.message)];
875
- }
876
- // Single streaming exit: finalize the post-phase session so
877
- // post-signal mutations (e.g. pendingDirective) are persisted.
878
- await this.sessionFinalizer.finalize(tail.session, effectiveContext);
879
- yield {
880
- ...chunk,
881
- delta,
882
- accumulated,
883
- session: tail.session,
884
- triggeredSignals: tail.triggeredSignals,
885
- };
886
- }
887
- else {
888
- yield chunk;
889
- }
890
- }
891
- }
892
- /**
893
- * Emit a framework-authored message (a halt reply) as a single terminal
894
- * chunk, to flow through the shared post-phase tail like any other inner
895
- * stream. No LLM call, no provider text — so nothing to extract or finalize
896
- * here; the caller's tail owns post-phase + finalize.
897
- * @private
898
- */
899
- // eslint-disable-next-line @typescript-eslint/require-await -- yield-only async generator; must be `async *` to satisfy the AsyncGenerator return type the caller switches on
900
- async *streamTerminalMessage(params) {
901
- yield {
902
- delta: params.message,
903
- accumulated: params.message,
904
- done: true,
905
- session: params.session,
906
- toolCalls: undefined,
907
- isFlowComplete: false,
908
- stoppedReason: params.stoppedReason,
909
- executedSteps: [],
910
- };
911
- }
912
- /**
913
- * Wrap a provider message stream so each chunk's `delta`/`accumulated` carry
914
- * clean message text instead of the raw structured-JSON wrapper. The single
915
- * point where streamed JSON is unwrapped — every streaming response variant
916
- * (flow step, fallback) consumes provider chunks through here, so consumers
917
- * and stored history never see `{"message":...}` fragments. `structured`,
918
- * `done`, and `metadata` pass through untouched.
919
- * @private
920
- */
921
- async *decodeMessageStream(stream) {
922
- const decoder = new StreamingMessageDecoder();
923
- for await (const chunk of stream) {
924
- const clean = decoder.push(chunk.accumulated);
925
- yield { ...chunk, delta: clean.delta, accumulated: clean.message };
926
- }
927
- }
928
- /**
929
- * Process flow streaming response with unified tool execution and data collection
930
- * @private
931
- */
932
- async *processFlowStreamingResponse(params) {
933
- const { selectedFlow, selectedStep, responseDirectives, history, context, historyEvents, signal, transientAppendage, mergedPreDirective } = params;
934
- let session = params.session;
935
- // Resolve the step to render (same logic as non-streaming)
936
- const stepResolution = await this.responsePipeline.resolveRenderStep({
937
- selectedFlow,
938
- selectedStep,
939
- session,
940
- context,
941
- });
942
- if (stepResolution.flowTransition) {
943
- // Flow transition or completion — no step to render
944
- yield {
945
- delta: '',
946
- accumulated: '',
947
- done: true,
948
- session: stepResolution.session,
949
- };
950
- return;
951
- }
952
- const nextStep = stepResolution.nextStep;
953
- session = stepResolution.session;
954
- // Build response schema and prompt (same as non-streaming)
955
- const responseSchema = this.responseEngine.responseSchemaForFlow(selectedFlow, nextStep, this.agent.schema);
956
- // ── HALT SHORT-CIRCUIT (Requirement 2.5, 2.6, 2.7) ──────────────────────
957
- // After pre-LLM emissions are merged, if `halt: true` then skip the LLM
958
- // call entirely. Emit a single done chunk with the appropriate content.
959
- if (mergedPreDirective?.halt) {
960
- const reply = mergedPreDirective.reply || '';
961
- const reason = mergedPreDirective.reply ? 'reply' : 'halt';
962
- logger.debug(`[ResponseModal] Halt (streaming) — skipping LLM call for step ${nextStep.id}, stoppedReason: ${reason}`);
963
- yield {
964
- delta: reply,
965
- accumulated: reply,
966
- done: true,
967
- session,
968
- stoppedReason: reason,
969
- executedSteps: [{ id: nextStep.id, flowId: selectedFlow.id }],
970
- };
971
- return;
972
- }
973
- // ── STEP.REPLY SHORT-CIRCUIT (Requirement 25.1–25.7, 17.9) ──────────────
974
- // A step with `reply` set emits a verbatim template response without LLM.
975
- // onEnter and prepare have already fired normally. If prepare returned
976
- // a Directive with `reply`, that overrides the step-declared reply.
977
- if (nextStep.reply != null) {
978
- const effectiveReply = mergedPreDirective?.reply ?? await render(nextStep.reply, createTemplateContext({ data: session.data || {}, context, session }));
979
- logger.debug(`[ResponseModal] Step.reply (streaming) — skipping LLM call for step ${nextStep.id}`);
980
- yield {
981
- delta: effectiveReply,
982
- accumulated: effectiveReply,
983
- done: true,
984
- session,
985
- stoppedReason: 'reply',
986
- executedSteps: [{ id: nextStep.id, flowId: selectedFlow.id }],
987
- };
988
- return;
989
- }
990
- // Transient appendage: per-turn slot from Directive.appendPrompt.
991
- // Fresh each turn, never cached, never persisted.
992
- // Wrapped in try/finally to ensure cleanup even on abnormal termination.
993
- let turnTransientAppendage = transientAppendage;
994
- try {
995
- const { prompt: responsePrompt, appliedInstructions } = await this.responseEngine.buildResponsePrompt({
996
- flow: selectedFlow,
997
- currentStep: nextStep,
998
- rules: [],
999
- prohibitions: [],
1000
- directives: responseDirectives,
1001
- history: historyEvents,
1002
- agentOptions: this.agent.getAgentOptions(),
1003
- instructions: this.collectScopedInstructions(selectedFlow, nextStep),
1004
- combinedTerms: this.agent.getTerms(),
1005
- context,
1006
- session,
1007
- agentSchema: this.agent.schema,
1008
- transientAppendage: turnTransientAppendage,
1009
- });
1010
- // Collect available tools for AI
1011
- const availableTools = this.collectAvailableTools(selectedFlow, nextStep);
1012
- // Generate message stream using AI provider
1013
- const agentOptions = this.agent.getAgentOptions();
1014
- const stream = agentOptions.provider.generateMessageStream({
1015
- prompt: responsePrompt,
1016
- history, // Use HistoryItem[] for AI provider
1017
- context,
1018
- tools: availableTools,
1019
- signal,
1020
- parameters: { jsonSchema: responseSchema, schemaName: "response_stream_output" },
1021
- });
1022
- // Stream chunks with unified tool handling. decodeMessageStream gives
1023
- // each chunk clean message text in delta/accumulated, so the non-done
1024
- // deltas, the final accumulated, the post-phase message input, and the
1025
- // assistant message stored by stream() are all clean — never the raw
1026
- // JSON wrapper (matching the non-streaming structured.message extraction).
1027
- for await (const chunk of this.decodeMessageStream(stream)) {
1028
- let toolCalls = undefined;
1029
- // Final message/structured may be replaced by a forced post-tool
1030
- // response (see runStreamingBatch / gap: tools-ran-but-no-text).
1031
- let finalDelta = chunk.delta;
1032
- let finalAccumulated = chunk.accumulated;
1033
- let finalStructured = chunk.structured;
1034
- // Extract tool calls from AI response on final chunk
1035
- if (chunk.done && chunk.structured?.toolCalls) {
1036
- toolCalls = chunk.structured.toolCalls;
1037
- // Concurrent execution for the initial batch of tool calls,
1038
- // yielding tool-progress chunks as they arrive. The accumulated
1039
- // preamble is already clean text.
1040
- const batchResult = yield* this.toolLoopExecutor.runStreamingBatch({
1041
- toolCalls,
1042
- context,
1043
- session,
1044
- history,
1045
- selectedFlow,
1046
- step: nextStep,
1047
- accumulated: chunk.accumulated,
1048
- responsePrompt,
1049
- availableTools,
1050
- responseSchema,
1051
- signal,
1052
- });
1053
- session = batchResult.session;
1054
- toolCalls = batchResult.toolCalls;
1055
- // Tool-emitted directives (ctx.dispatch / `{directive}`):
1056
- // state writes apply now; control flow queues for the next
1057
- // turn's pendingDirective applier (same deferred semantics
1058
- // as dispatch()). A verbatim tool reply already replaced the
1059
- // closing message inside runStreamingBatch.
1060
- if (batchResult.directives) {
1061
- session = await this.applyToolEmittedDirectives(session, batchResult.directives);
1062
- }
1063
- // Prefer the post-tool follow-up structured for collection and
1064
- // emission whenever present — independent of whether a closing
1065
- // message was forced — matching the non-streaming path's
1066
- // `toolResult.structured ?? result` selection.
1067
- finalStructured = batchResult.structured ?? finalStructured;
1068
- // Tools ran but the model produced no result-aware text — use
1069
- // the forced closing message (already clean) so we never emit the
1070
- // bare preamble (or an empty message) as the final response. Its
1071
- // delta is the portion not already streamed as the preamble.
1072
- if (batchResult.finalMessage) {
1073
- finalAccumulated = batchResult.finalMessage;
1074
- finalDelta = batchResult.finalMessage.startsWith(chunk.accumulated)
1075
- ? batchResult.finalMessage.slice(chunk.accumulated.length)
1076
- : batchResult.finalMessage;
1077
- }
1078
- }
1079
- // Streaming twin of the non-streaming salvage guard: a schema was
1080
- // requested but no structured payload arrived, and the accumulated
1081
- // text is JSON-shaped (a protocol fragment) — repair-parse it or
1082
- // fail the turn rather than leaking raw output to the user.
1083
- if (chunk.done && !finalStructured && responseSchema && finalAccumulated) {
1084
- const salvaged = this.salvageStructuredOutput(finalAccumulated, "stream");
1085
- if (salvaged) {
1086
- finalDelta = salvaged.message.startsWith(finalAccumulated)
1087
- ? salvaged.message.slice(finalAccumulated.length)
1088
- : salvaged.message;
1089
- finalStructured = salvaged;
1090
- finalAccumulated = salvaged.message;
1091
- }
1092
- }
1093
- // Collect data on the final chunk for any flow step — flow
1094
- // required/optional fields are valid targets even without a step
1095
- // `collect` — preferring the post-tool follow-up structured so a
1096
- // tool-driven turn harvests fields the model produced after tools.
1097
- if (chunk.done && finalStructured) {
1098
- session = await this.collectDataFromResponse({
1099
- result: { structured: finalStructured },
1100
- selectedFlow,
1101
- nextStep,
1102
- session,
1103
- });
1104
- }
1105
- // Response structure completeness (Requirement 8.1, 8.2, 8.3)
1106
- // - executedSteps: single step executed in this response
1107
- // - stoppedReason: 'needs_input' for single-step execution (waiting for user input)
1108
- // - session.currentStep: reflects the executed step
1109
- yield {
1110
- delta: finalDelta,
1111
- accumulated: finalAccumulated,
1112
- done: chunk.done,
1113
- session,
1114
- toolCalls,
1115
- isFlowComplete: false,
1116
- executedSteps: chunk.done ? [{ id: nextStep.id, flowId: selectedFlow.id }] : undefined,
1117
- stoppedReason: chunk.done ? 'needs_input' : undefined,
1118
- metadata: chunk.metadata,
1119
- structured: finalStructured,
1120
- appliedInstructions: chunk.done ? appliedInstructions : undefined,
1121
- };
1122
- }
1123
- }
1124
- finally {
1125
- // Drain the transient appendage at end of turn.
1126
- // This ensures Directive.appendPrompt does not leak to subsequent
1127
- // turns even when the turn terminates abnormally (error, abort, reject).
1128
- turnTransientAppendage = undefined;
1129
- }
1130
- }
1131
- /**
1132
- * Unified data collection from AI response
1133
- * @private
1134
- */
1135
- async collectDataFromResponse(params) {
1136
- try {
1137
- const { result, selectedFlow, nextStep, session } = params;
1138
- let updatedSession = session;
1139
- // Extract collected data from final response (only for flow-based interactions)
1140
- if (selectedFlow && result.structured) {
1141
- try {
1142
- const collectedData = {};
1143
- // AgentStructuredResponse extends Record<string, unknown>, so we can safely access properties
1144
- const structuredData = result.structured;
1145
- // Collect ALL flow fields (required + optional) from structured response
1146
- const allFlowFields = new Set();
1147
- // Add flow required fields
1148
- if (selectedFlow.requiredFields) {
1149
- selectedFlow.requiredFields.forEach(field => allFlowFields.add(String(field)));
1150
- }
1151
- // Add flow optional fields
1152
- if (selectedFlow.optionalFields) {
1153
- selectedFlow.optionalFields.forEach(field => allFlowFields.add(String(field)));
1154
- }
1155
- // Also include current step's collect fields (in case they're not in flow fields)
1156
- if (nextStep?.collect) {
1157
- nextStep.collect.forEach(field => allFlowFields.add(String(field)));
1158
- }
1159
- // Extract all available fields from structured response
1160
- for (const field of allFlowFields) {
1161
- const fieldKey = String(field);
1162
- if (fieldKey in structuredData && structuredData[fieldKey] !== undefined && structuredData[fieldKey] !== null) {
1163
- collectedData[fieldKey] = structuredData[fieldKey];
1164
- }
1165
- }
1166
- // Merge collected data into session using agent-level data validation
1167
- if (Object.keys(collectedData).length > 0) {
1168
- try {
1169
- // Update agent-level collected data with validation
1170
- await this.agent.updateCollectedData(collectedData);
1171
- // Update session with validated data
1172
- const updateDataMethod = this.agent.getUpdateDataMethod();
1173
- updatedSession = await updateDataMethod(updatedSession, collectedData);
1174
- logger.debug(`[ResponseModal] Collected data:`, collectedData);
1175
- }
1176
- catch (error) {
1177
- logger.error(`[ResponseModal] Failed to update collected data:`, error);
1178
- // Continue without updating data rather than failing completely
1179
- }
1180
- }
1181
- }
1182
- catch (error) {
1183
- logger.error(`[ResponseModal] Error during data collection:`, error);
1184
- // Continue without collecting data rather than failing completely
1185
- }
1186
- }
1187
- // Extract any additional data from structured response
1188
- // Since AgentStructuredResponse extends Record<string, unknown>, we can safely check for additional properties
1189
- if (result.structured && "contextUpdate" in result.structured) {
1190
- try {
1191
- const contextUpdate = result.structured.contextUpdate;
1192
- if (contextUpdate) {
1193
- await this.agent.updateContext(contextUpdate);
1194
- }
1195
- }
1196
- catch (error) {
1197
- logger.error(`[ResponseModal] Failed to update context from structured response:`, error);
1198
- // Continue without updating context rather than failing completely
1199
- }
1200
- }
1201
- return updatedSession;
1202
- }
1203
- catch (error) {
1204
- logger.error(`[ResponseModal] Error in collectDataFromResponse:`, error);
1205
- // Return original session if data collection fails completely
1206
- return params.session;
1207
- }
1208
- }
1209
- /**
1210
- * Apply flow completion: release the session to idle state.
1211
- *
1212
- * This is a pure state transition. The framework emits **no message of
1213
- * its own** at the completion boundary — every word delivered to the
1214
- * user comes from a developer-defined step prompt. If the dev wants a
1215
- * closing turn, they add a final interactive step with their own
1216
- * `prompt`; the framework respects that step's natural LLM output.
1217
- *
1218
- * Behavior:
1219
- * - Marks the active `flowHistory` entry as `completed: true` and
1220
- * stamps `exitedAt`.
1221
- * - Evaluates `flow.onComplete` for an explicit follow-up transition.
1222
- * When set, populates `session.pendingDirective` (the next turn's
1223
- * pipeline applies it). When absent, the session is fully idle.
1224
- * - Clears `currentFlow` and `currentStep` to `undefined`.
1225
- * - Clears owned fields when the flow is `reentrant` so subsequent
1226
- * re-selections start from a clean state.
1227
- *
1228
- * Returns the updated session. Callers compose any reply text from
1229
- * their own sources (an upstream LLM turn, a directive's `reply`, or
1230
- * an empty string for silent completion).
1231
- *
1232
- * @private
1233
- */
1234
- async applyFlowCompletion(params) {
1235
- const { selectedFlow, session, context } = params;
1236
- // 1) Evaluate onComplete first — needs the still-active session shape.
1237
- const transitionConfig = await selectedFlow.evaluateOnComplete({ data: session.data }, context);
1238
- // 2) Release to idle. If the flow is reentrant, scrub its owned
1239
- // fields so re-selection on a future turn starts clean. When
1240
- // onComplete fires we still go idle here — the next turn's
1241
- // pipeline applies the pendingDirective before any routing.
1242
- const ownedFields = selectedFlow.reentrant
1243
- ? [
1244
- ...(selectedFlow.requiredFields ?? []),
1245
- ...(selectedFlow.optionalFields ?? []),
1246
- ]
1247
- : undefined;
1248
- let nextSession = completeCurrentFlow(session, {
1249
- clearOwnedFields: ownedFields,
1250
- });
1251
- // 3) Wire pendingDirective when onComplete returned a target.
1252
- if (transitionConfig) {
1253
- const goToTarget = typeof transitionConfig.goTo === 'string'
1254
- ? transitionConfig.goTo
1255
- : transitionConfig.goTo?.flow;
1256
- const targetFlow = goToTarget ? this.agent.getFlows().find((r) => r.id === goToTarget ||
1257
- r.title === goToTarget) : undefined;
1258
- if (targetFlow) {
1259
- nextSession = {
1260
- ...nextSession,
1261
- pendingDirective: {
1262
- goTo: targetFlow.id,
1263
- },
1264
- };
1265
- logger.debug(`[ResponseModal] Flow ${selectedFlow.title} completed with pending directive to: ${targetFlow.title}`);
1266
- }
1267
- else if (goToTarget) {
1268
- logger.warn(`[FlowConfigurationError] onComplete target not found: flow "${selectedFlow.title}" completed but onComplete target "${goToTarget}" does not match any flow. ` +
1269
- `Fix the onComplete value to reference an existing flow id/title, or remove onComplete to release the session to idle.`);
1270
- }
1271
- }
1272
- else {
1273
- logger.debug(`[ResponseModal] Flow ${selectedFlow.title} completed; session released to idle.`);
1274
- }
1275
- return nextSession;
1276
- }
1277
- /**
1278
- * Stream a flow completion as a single terminal chunk.
1279
- *
1280
- * No LLM call is made. The framework no longer authors a farewell — the
1281
- * completion path is a pure state transition. The chunk emits an empty
1282
- * `delta` and a `done: true` flag with the idle session attached so
1283
- * downstream consumers can finalize cleanly.
1284
- *
1285
- * If the developer wants closing copy in a streaming response, they
1286
- * should add a final interactive step whose own LLM turn delivers it.
1287
- *
1288
- * @private
1289
- */
1290
- async *streamFlowCompletion(params) {
1291
- const { selectedFlow, context, history } = params;
1292
- const session = await this.applyFlowCompletion({
1293
- selectedFlow,
1294
- session: params.session,
1295
- context,
1296
- history,
1297
- });
1298
- yield {
1299
- delta: '',
1300
- accumulated: '',
1301
- done: true,
1302
- session,
1303
- toolCalls: undefined,
1304
- isFlowComplete: true,
1305
- executedSteps: [],
1306
- stoppedReason: params.stoppedReason ?? 'completed',
1307
- };
1308
- }
1309
- /**
1310
- * Generate fallback response when no flows are available
1311
- * @private
1312
- */
1313
- async generateFallbackResponse(params) {
1314
- const { history, context, session, signal } = params;
1315
- logger.debug(`[ResponseModal] No flow selected, generating basic response`);
1316
- // Build basic response prompt without flow context
1317
- const { prompt: fallbackPrompt, appliedInstructions } = await this.responseEngine.buildFallbackPrompt({
1318
- agentOptions: this.agent.getAgentOptions(),
1319
- terms: this.agent.getTerms(),
1320
- instructions: this.collectScopedInstructions(),
1321
- context,
1322
- session,
1323
- });
1324
- const agentOptions = this.agent.getAgentOptions();
1325
- const result = await agentOptions.provider.generateMessage({
1326
- prompt: fallbackPrompt,
1327
- history,
1328
- context,
1329
- signal,
1330
- parameters: {
1331
- jsonSchema: {
1332
- type: "object",
1333
- properties: { message: { type: "string" } },
1334
- required: ["message"],
1335
- additionalProperties: false,
1336
- },
1337
- schemaName: "fallback_response",
1338
- },
1339
- });
1340
- return { message: result.structured?.message || result.message, appliedInstructions };
1341
- }
1342
- /**
1343
- * Stream fallback response when no flows are available
1344
- * @private
1345
- */
1346
- async *streamFallbackResponse(params) {
1347
- const { history, context, session, signal } = params;
1348
- const { prompt: fallbackPrompt, appliedInstructions } = await this.responseEngine.buildFallbackPrompt({
1349
- agentOptions: this.agent.getAgentOptions(),
1350
- terms: this.agent.getTerms(),
1351
- instructions: this.collectScopedInstructions(),
1352
- context,
1353
- session,
1354
- });
1355
- const agentOptions = this.agent.getAgentOptions();
1356
- const stream = agentOptions.provider.generateMessageStream({
1357
- prompt: fallbackPrompt,
1358
- history,
1359
- context,
1360
- signal,
1361
- parameters: {
1362
- jsonSchema: {
1363
- type: "object",
1364
- properties: { message: { type: "string" } },
1365
- required: ["message"],
1366
- additionalProperties: false,
1367
- },
1368
- schemaName: "fallback_stream_response",
1369
- },
1370
- });
1371
- // Decode the JSON wrapper to clean message text (same as the flow path).
1372
- for await (const chunk of this.decodeMessageStream(stream)) {
1373
- // Response structure completeness (Requirement 8.1, 8.2, 8.3)
1374
- // - executedSteps: empty for fallback (no flow/step execution)
1375
- // - stoppedReason: undefined for fallback (no flow context)
1376
- // - session.currentStep: unchanged (no step progression)
1377
- yield {
1378
- delta: chunk.delta,
1379
- accumulated: chunk.accumulated,
1380
- done: chunk.done,
1381
- session,
1382
- toolCalls: undefined,
1383
- isFlowComplete: false,
1384
- executedSteps: chunk.done ? [] : undefined,
1385
- stoppedReason: undefined,
1386
- metadata: chunk.metadata,
1387
- structured: chunk.structured,
1388
- appliedInstructions: chunk.done ? appliedInstructions : undefined,
1389
- };
1390
- }
1391
- }
1392
- // ============================================================================
1393
- // UTILITY METHODS - Helper methods for tool management and other utilities
1394
- // ============================================================================
1395
- /**
1396
- * Collect all available tools for the given flow and step context.
1397
- * Delegates to ToolManager for unified tool resolution and deduplication.
1398
- * @private
1399
- */
1400
- collectAvailableTools(flow, step) {
1401
- const availableTools = this.getToolManager().getAvailable(undefined, step, flow);
1402
- return availableTools.map((tool) => ({
1403
- id: tool.id,
1404
- name: tool.id,
1405
- description: tool.description,
1406
- parameters: tool.parameters,
1407
- }));
1408
- }
1409
- }
1410
- //# sourceMappingURL=ResponseModal.js.map