@falai/agent 3.4.4 → 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,149 +1,85 @@
1
1
  ---
2
2
  title: "Streaming"
3
- description: "Stream the assistant's reply token by token, surface tool calls in flight, and cancel mid-turn with an `AbortSignal`."
3
+ description: "turnStream: the reply arrives as text deltas, the full turn result arrives last, and everything else works exactly as in turn()."
4
4
  type: guide
5
- order: 6
5
+ order: 9
6
6
  ---
7
7
 
8
8
  # Streaming
9
9
 
10
- `agent.respond` returns a single `AgentResponse` after the LLM and any tool calls have finished. That works for batch work, but a chat UI feels dead until the first character lands. `agent.respondStream` returns an `AsyncGenerator<AgentResponseStreamChunk>`, yielding the assistant's reply incrementally and finishing with one terminal chunk that carries all the metadata.
10
+ `agent.turnStream()` is `agent.turn()` that yields the reply while the model writes it.
11
11
 
12
- This guide is a recipe: take a non-streaming call site, swap to `respondStream`, render tokens as they arrive, expose a "thinking" indicator while tools run, read instruction and signal telemetry off the final chunk, and wire an `AbortSignal` so the user can stop mid-turn.
12
+ ```ts
13
+ import { falai, GeminiProvider } from "@falai/agent";
13
14
 
14
- ## The shape
15
-
16
- `respondStream` takes the same `RespondParams` as `respond` — `history`, optional `session`, optional `contextOverride`, optional `signal` — and returns an async iterable of chunks.
17
-
18
- ```typescript
19
- const stream = agent.respondStream({
20
- history: [{ role: "user", content: "Book me a hotel in Lisbon." }],
15
+ const f = falai().fields({
16
+ nome: { type: "string", ask: "Pergunte o nome." },
21
17
  });
22
18
 
23
- for await (const chunk of stream) {
24
- process.stdout.write(chunk.delta);
25
- }
26
- ```
27
-
28
- Every chunk has the same shape:
29
-
30
- ```typescript
31
- interface AgentResponseStreamChunk<TData> {
32
- delta: string; // Text added since the previous chunk
33
- accumulated: string; // Full text so far
34
- done: boolean; // True only on the terminal chunk
35
- // ...metadata fields, populated on the final chunk
36
- }
37
- ```
38
-
39
- `delta` is the new token(s); concatenating every `delta` reproduces the final reply unless a post-phase signal replaces the message on the terminal chunk. `accumulated` is the authoritative running total — useful when your renderer needs the full string each tick (e.g., a Markdown view that re-parses on every update). `done` flips to `true` exactly once, on the terminal chunk.
40
-
41
- ## Render incrementally
42
-
43
- The simplest renderer prints every `delta` as it arrives and clears the line on `done`:
19
+ const agent = f.agent({
20
+ name: "Ana",
21
+ provider: new GeminiProvider({ apiKey: process.env.GEMINI_API_KEY ?? "", model: "gemini-2.5-flash" }),
22
+ flows: [
23
+ f.flow({
24
+ id: "boas-vindas",
25
+ name: "Boas-vindas",
26
+ on: [{ message: [] }],
27
+ steps: [{ id: "nome", collect: ["nome"] }],
28
+ }),
29
+ ],
30
+ });
44
31
 
45
- ```typescript
46
- for await (const chunk of agent.respondStream({ history })) {
47
- if (chunk.delta) {
32
+ for await (const chunk of agent.turnStream({ sessionId: "demo", message: "oi, sou o Rui" })) {
33
+ if ("delta" in chunk) {
48
34
  process.stdout.write(chunk.delta);
35
+ continue;
49
36
  }
50
- if (chunk.done) {
51
- process.stdout.write("\n");
52
- }
53
- }
54
- ```
55
-
56
- For a UI, push the latest `accumulated` into your component state. React, Solid, Svelte — they all re-render off whichever value you give them, and `accumulated` is the cheapest to consume because it never requires the renderer to track partial state.
57
-
58
- A common rendering rule of thumb:
59
-
60
- - Plain text view → append `delta`.
61
- - Markdown view that re-parses each frame → bind to `accumulated`.
62
- - Server-Sent Events transport → forward `{ delta, done }` per chunk; let the client reassemble.
63
-
64
- ## Surface tool calls in flight
65
-
66
- Streaming works through tool calls transparently. When the LLM emits a tool call mid-reply, `respondStream` runs the tool, then resumes streaming the post-tool tokens — the consumer never sees the call boundary in the text. What you do get is a quiet gap while the tool executes, which is the right moment to show a "thinking" indicator.
67
-
68
- Detect the gap by watching for empty `delta` chunks after some text has already arrived, or — more robustly — toggle the indicator off as soon as the first non-empty `delta` lands:
69
-
70
- ```typescript
71
- let thinking = true;
72
- let firstToken = true;
73
-
74
- for await (const chunk of agent.respondStream({ history })) {
75
- if (chunk.delta) {
76
- if (firstToken) {
77
- thinking = false;
78
- firstToken = false;
79
- ui.hideSpinner();
80
- }
81
- ui.appendText(chunk.delta);
82
- }
37
+ process.stdout.write("\n");
38
+ console.log(chunk.result.llmCalls, chunk.result.session.data); // 1 { nome: 'Rui' }
83
39
  }
84
40
  ```
85
41
 
86
- If you need finer-grained tool telemetry — which tool fired, with what arguments — read `chunk.toolCalls` on the terminal chunk. It mirrors the same field on the non-streaming `AgentResponse`. For per-tool progress UI, attach observability to the [tool's `handler`](../reference/tool.md) directly; the streaming chunk shape stays clean.
42
+ The stream prints the reply one piece at a time, then the last chunk hands you the same `TurnResult` that `turn()` would have returned.
87
43
 
88
- When a step uses [verbatim `reply`](../reference/step.md) or a `halt` directive, the engine skips the LLM entirely and yields a single chunk with `done: true` and the full text in `accumulated`. The renderer above handles that case without a special branch — there is just no spinner gap.
44
+ ## The chunks
89
45
 
90
- ## The terminal chunk
91
-
92
- The chunk where `done: true` carries every observability field that lives on `AgentResponse`. Three matter for most call sites:
93
-
94
- ```typescript
95
- for await (const chunk of agent.respondStream({ history })) {
96
- // ...render delta...
97
- if (chunk.done) {
98
- console.log("flow complete:", chunk.isFlowComplete);
99
- console.log("instructions rendered:", chunk.appliedInstructions);
100
- console.log("signals fired:", chunk.triggeredSignals);
101
- }
102
- }
46
+ ```ts fragment
47
+ type TurnStreamChunk<D> =
48
+ | { delta: string } // a piece of the reply, in order
49
+ | { done: true; result: TurnResult<D> }; // always last, exactly once
103
50
  ```
104
51
 
105
- - **`appliedInstructions`** — the [instructions](../reference/instruction.md) whose conditions passed and were rendered into this turn's prompt. Deterministic; derived from rendering, not from LLM self-report. Empty on intermediate chunks; populated only when `done: true`.
106
- - **`triggeredSignals`** — the [signals](../reference/signals.md) that fired during this turn (pre- and post-phase), in fire order. Same population rule.
107
- - **`isFlowComplete`** — `true` when this turn finished the flow. Use it to decide whether to clear the conversation, show a summary card, or transition the UI.
52
+ Every `delta` is plain message text. Joined together they add up to the reply. The `done` chunk carries the whole result: `session`, `changed`, `messages[]`, `schedule[]`, `outcomes[]`, `started`, `ended`, `skipped`, `llmCalls`. Read [the agent reference](../reference/agent.md) for the fields.
108
53
 
109
- The terminal chunk also carries `executedSteps`, `stoppedReason`, `metadata` (model, token usage), and the updated `session`. These are the same fields you would read off `AgentResponse` — swapping between APIs does not change observability.
54
+ ## What streams and what does not
110
55
 
111
- ## Cancel mid-stream
56
+ Only the speak call streams: the one call that phrases the reply. Everything else in the turn is code or a call that never streams.
112
57
 
113
- Pass an `AbortSignal` through `respondStream` and abort the controller to cancel. The generator stops yielding, the in-flight LLM call is cancelled at the provider boundary, and any tool execution unwinds cleanly.
58
+ | Source | Arrives as |
59
+ |---|---|
60
+ | the talk step's reply, or the idle speaker's | `delta` chunks, then in `result.messages[]` as one `kind: "ai"` message |
61
+ | a `say` step's text | `result.messages[]` only, `kind: "verbatim"` |
62
+ | the understand call (routing, mentions, extraction) | nothing visible; it finishes before the first delta |
63
+ | actions, waits, `if` steps | `result.outcomes[]`, `result.schedule[]` |
114
64
 
115
- ```typescript
116
- const controller = new AbortController();
65
+ The provider streams a JSON envelope, not bare text: `{"message":"Oi, Rui! Em que posso"…` followed by the collected fields. The framework unwraps it as it arrives (`src/utils/streamingMessage.ts`), so a `delta` never contains a brace, a quote or a field name, and a field the model writes before the message is skipped rather than leaked. A provider that streams plain text passes through as it is.
117
66
 
118
- // User clicks Stop, or a 5s ceiling fires.
119
- const timer = setTimeout(() => controller.abort(), 5000);
67
+ ## Tool calls during a stream
120
68
 
121
- try {
122
- for await (const chunk of agent.respondStream({
123
- history,
124
- signal: controller.signal,
125
- })) {
126
- process.stdout.write(chunk.delta);
127
- }
128
- } finally {
129
- clearTimeout(timer);
130
- }
131
- ```
69
+ A speak call may run in rounds: the model calls tools, the results go back as history, and the model is asked again. This happens inside the stream, before the `done` chunk. Each round streams. If the model writes something beside a tool call ("deixa eu ver"), that preamble reaches the stream, while `result.messages[0].text` holds only the final round's message. A UI that shows deltas as they come should replace what it showed with `result.messages[0].text` when `done` arrives, so both paths end on the same text.
132
70
 
133
- When the signal aborts, the loop exits cleanly — no exception is thrown by the generator itself. If the LLM provider surfaces the cancellation as an error, it lands as a [`ResponseGenerationError`](../reference/errors.md) and you handle it the way you would any other turn-level error.
71
+ Rounds are capped by `maxToolLoops` on the agent, default 5; after the cap the model is asked once more with no tools so a message always comes back. Each round is one model call and counts in `result.llmCalls`.
134
72
 
135
- For a Stop button, store the `controller` reference for the active stream on the UI side and call `controller.abort()` from the click handler. For server-side hard ceilings, wrap `respondStream` with an `AbortController` whose `setTimeout` fires at your SLO budget.
73
+ ## A provider failure mid-stream
136
74
 
137
- If the turn fails — the generator surfaces an error chunk — it has no lasting effect: the in-memory session rolls back to its pre-turn snapshot (the user message added by `stream()` before the turn is retained), and persisted state is whatever the previous turn saved. Retrying is always safe.
75
+ The stream never throws for a speak failure. You get zero or more deltas and then the `done` chunk, whose result carries a `deferred` outcome and a retry wake, exactly as `turn()` would report it.
138
76
 
139
- ## Reliability: retries, backups, and the first-chunk deadline
77
+ A failure mid-stream leaves the person looking at half a reply. Nothing of that half reaches `result.messages[]`, so the deltas you showed are its only trace: clear them when `done` carries a `deferred` outcome, and leave a short line saying the reply is coming. The retry wake fires a minute later, speaks that step again from the start, and its reply arrives as an ordinary message carrying the key the first attempt would have used.
140
78
 
141
- Streaming inherits the same resilience machinery as non-streaming calls — provider `retryConfig` and `backupModels` — with stream-specific rules:
79
+ A failure in the understand call, before any delta, throws from the `for await` like `turn()` does. See [error handling](./error-handling.md).
142
80
 
143
- - **Retry only before the first chunk.** A stream that fails before yielding anything (a connection error, an empty completion, a stalled open) is retried on the same model up to `retryConfig.retries` times. Once a delta has reached your renderer, the stream is committed: any later failure propagates instead of retrying, so a retry can never emit a token your consumer has already seen.
144
- - **First-chunk deadline.** `retryConfig.timeout` doubles as the time-to-first-token budget. If the provider opens a stream but produces no first chunk within it, the attempt counts as failed and the retry and backup machinery takes over. Only the first chunk is bounded — later chunks are unbounded, so a long-but-healthy stream is never cut off.
145
- - **Transparent backup-model switch.** With `backupModels` configured, a model that fails mid-stream — even after deltas were delivered — falls through to the next model, whose chunks flow through unchanged. The switchover happens between chunks; no error reaches the consumer unless every model fails.
81
+ ## The same settle, the same result
146
82
 
147
- These knobs live on the provider constructor, not on `respondStream` — see [Providers](../reference/providers.md) for `retryConfig` and `backupModels`.
83
+ `turnStream` runs the same eight phases as `turn()` and applies the reply the same way. With the same provider output, the two return identical results: the same message keys, the same data written, the same schedule. Stream when you show text to a person as it is written. When the messages leave through a channel you send to yourself, `turn()` is simpler, because it gives you the messages after the save and nothing before it.
148
84
 
149
- **Next:** [Errors](./error-handling.md)
85
+ Save and send are still yours, and still in that order: the `done` chunk's `result.session` is what you save with the version you loaded, and a `SessionConflictError` means you replay the same input; see [persistence](./persistence.md). With a stream the person has already seen the text by then, which is fine in a chat window and is the reason to prefer `turn()` on a channel.
@@ -0,0 +1,284 @@
1
+ ---
2
+ title: "Testing"
3
+ description: "A clock you hold still, a scheduler you fire by hand, a store in memory and a provider you script: everything a turn needs, with no network."
4
+ type: guide
5
+ order: 12
6
+ ---
7
+
8
+ # Testing
9
+
10
+ The core does no I/O beyond the provider and your actions, so a test drives a real `Agent` with four fakes. Start with the clock.
11
+
12
+ ```ts
13
+ import { fakeClock } from "@falai/agent";
14
+
15
+ const clock = fakeClock("2026-09-20T10:00:00.000Z");
16
+ clock.advance("24h");
17
+ console.log(clock.now().toISOString()); // 2026-09-21T10:00:00.000Z
18
+ ```
19
+
20
+ Pass `clock` to the agent and every `now`, every wake time and every key that carries a timestamp comes from it. The core never reads `Date.now()`.
21
+
22
+ ## The four fakes
23
+
24
+ | Fake | From | What it replaces |
25
+ |---|---|---|
26
+ | `fakeClock(iso)` | `@falai/agent` | time: `now()`, `advance("2d" \| ms)`, `set(iso)` |
27
+ | `MemoryScheduler` | `@falai/agent` | your queue: `add(entry)`, `remove(key)`, `size`, `due(now)` returns and removes what is due, earliest first; a new entry with the same key replaces the old one, and `replaces` removes that key |
28
+ | `MemoryStore` | `@falai/agent` | your database, with the same version check |
29
+ | a scripted `AiProvider` | you write it, about 25 lines | the model |
30
+
31
+ The snippets below use `node:assert/strict` so they run under `bun run` or `node` with no framework. The repo's own tests use `bun test` the same way.
32
+
33
+ ## A scripted provider
34
+
35
+ The framework names each call through `parameters.schemaName`: `"understand"` for the call that judges the customer's message, `"speak"` for the call that phrases the reply. A scripted provider keeps one queue per name, shifts the next reply off it, and throws when a queue runs dry, so a turn that spends a call you did not expect fails loudly.
36
+
37
+ ```ts
38
+ import type { AiProvider, GenerateMessageInput, GenerateMessageOutput, GenerateMessageStreamChunk } from "@falai/agent";
39
+
40
+ type Reply = Record<string, unknown>;
41
+
42
+ export interface Scripted extends AiProvider {
43
+ /** Every call's schema name, in order. */
44
+ calls: string[];
45
+ }
46
+
47
+ export function scripted(script: { understand?: Reply[]; speak?: Reply[] }): Scripted {
48
+ const queues: Record<string, Reply[]> = { understand: [...(script.understand ?? [])], speak: [...(script.speak ?? [])] };
49
+ const calls: string[] = [];
50
+
51
+ function next<T>(input: GenerateMessageInput): GenerateMessageOutput<T> {
52
+ const name = input.parameters?.schemaName ?? "(unnamed)";
53
+ calls.push(name);
54
+ const reply = queues[name]?.shift();
55
+ if (!reply) throw new Error(`no scripted "${name}" reply left for call #${calls.length}`);
56
+ const message = typeof reply.message === "string" ? reply.message : JSON.stringify(reply);
57
+ return { message, structured: reply as T };
58
+ }
59
+
60
+ return {
61
+ name: "scripted",
62
+ calls,
63
+ capabilities: { supportsTools: true, supportsNativeJsonSchema: true, supportsStreaming: true, supportsStreamingToolCalls: true, supportsPromptCaching: false },
64
+ generateMessage: <_C, T>(input: GenerateMessageInput) => Promise.resolve().then(() => next<T>(input)),
65
+ // eslint-disable-next-line @typescript-eslint/require-await -- one chunk, nothing to await
66
+ async *generateMessageStream<_C, T>(input: GenerateMessageInput): AsyncGenerator<GenerateMessageStreamChunk<T>> {
67
+ const out = next<T>(input);
68
+ yield { delta: out.message, accumulated: out.message, done: true, structured: out.structured };
69
+ },
70
+ };
71
+ }
72
+ ```
73
+
74
+ The two envelopes you script, as the framework reads them:
75
+
76
+ ```ts fragment
77
+ // understand: every section present, empty when there is nothing to say
78
+ {
79
+ flows: { triagem: 90 }, // flowId → 0–100 fit of the message to the flow
80
+ mentions: { concorrente: true }, // flowId → the customer brought it up
81
+ extract: { concorrente: { trecho: "a Acme cobra metade" } }, // flowId → values for the mention's `extract`
82
+ branches: {}, // "runId/stepId/index" → the `when` holds
83
+ fields: { nome: "Ana" }, // field → the raw value the customer gave
84
+ }
85
+
86
+ // speak: the message, then one property per pending field, null when the customer did not give it
87
+ { message: "Oi Ana! De qual empresa você fala?", empresa: null }
88
+
89
+ // speak, calling a tool first: the next scripted speak reply answers after the tool ran
90
+ { toolCalls: [{ toolName: "orcamento", arguments: { pessoas: 30 } }] }
91
+ ```
92
+
93
+ A `fields` value goes through the same coercion as production: `"sim"` becomes `true` for a boolean, `"1,5"` becomes `1.5` for a number, `"mil"` is dropped with the outcome `code: 'bad-value'`, and an enum value outside the list is dropped with `code: 'not-in-enum'`.
94
+
95
+ ## One test, end to end
96
+
97
+ A triage flow that collects two fields and a silence flow that nudges after 24 hours. The test asserts the call count, the message keys, the wake key, then fires the wake through the scheduler.
98
+
99
+ ```ts
100
+ import assert from "node:assert/strict";
101
+ import { falai, fakeClock, MemoryScheduler, MemoryStore, type AiProvider, type DataOf, type GenerateMessageInput, type GenerateMessageOutput, type GenerateMessageStreamChunk, type TurnKind } from "@falai/agent";
102
+
103
+ // The scripted provider from above, inlined so this file stands alone.
104
+ type Reply = Record<string, unknown>;
105
+ function scripted(script: { understand?: Reply[]; speak?: Reply[] }): AiProvider & { calls: string[] } {
106
+ const queues: Record<string, Reply[]> = { understand: [...(script.understand ?? [])], speak: [...(script.speak ?? [])] };
107
+ const calls: string[] = [];
108
+ function next<T>(input: GenerateMessageInput): GenerateMessageOutput<T> {
109
+ const name = input.parameters?.schemaName ?? "(unnamed)";
110
+ calls.push(name);
111
+ const reply = queues[name]?.shift();
112
+ if (!reply) throw new Error(`no scripted "${name}" reply left for call #${calls.length}`);
113
+ return { message: typeof reply.message === "string" ? reply.message : JSON.stringify(reply), structured: reply as T };
114
+ }
115
+ return {
116
+ name: "scripted",
117
+ calls,
118
+ capabilities: { supportsTools: true, supportsNativeJsonSchema: true, supportsStreaming: true, supportsStreamingToolCalls: true, supportsPromptCaching: false },
119
+ generateMessage: <_C, T>(input: GenerateMessageInput) => Promise.resolve().then(() => next<T>(input)),
120
+ // eslint-disable-next-line @typescript-eslint/require-await -- one chunk, nothing to await
121
+ async *generateMessageStream<_C, T>(input: GenerateMessageInput): AsyncGenerator<GenerateMessageStreamChunk<T>> {
122
+ const out = next<T>(input);
123
+ yield { delta: out.message, accumulated: out.message, done: true, structured: out.structured };
124
+ },
125
+ };
126
+ }
127
+
128
+ const T0 = "2026-09-20T10:00:00.000Z";
129
+ const f = falai().fields({
130
+ nome: { type: "string", ask: "Pergunte o nome de um jeito leve." },
131
+ empresa: { type: "string", ask: "Pergunte de qual empresa a pessoa fala." },
132
+ });
133
+ type Data = DataOf<typeof f>;
134
+
135
+ const triagem = f.flow({
136
+ id: "triagem",
137
+ name: "Triagem",
138
+ on: [{ message: ["quer saber como funciona", "pede um orçamento"] }],
139
+ steps: [
140
+ { id: "quem", prompt: "Descubra quem é e de onde fala.", collect: ["nome", "empresa"] },
141
+ { id: "tchau", prompt: "Agradeça e diga que um vendedor continua daqui." },
142
+ ],
143
+ });
144
+
145
+ const retomar = f.flow({
146
+ id: "retomar",
147
+ name: "Retomar quem sumiu",
148
+ on: [{ silence: "24h" }],
149
+ steps: [
150
+ { id: "p1", prompt: "Retome a conversa de forma leve e pergunte se ainda faz sentido." },
151
+ { id: "w1", wait: "2d", else: "end" },
152
+ { id: "p2", prompt: "Última tentativa, curta e sem pressão." },
153
+ ],
154
+ });
155
+
156
+ const clock = fakeClock(T0);
157
+ const provider = scripted({
158
+ understand: [{ flows: {}, mentions: {}, extract: {}, branches: {}, fields: { nome: "Ana" } }],
159
+ speak: [{ message: "Oi Ana! De qual empresa você fala?", empresa: null }, { message: "Oi Ana, ainda faz sentido conversarmos?" }],
160
+ });
161
+ const agent = f.agent({ name: "Ana", provider, clock, flows: [triagem, retomar] });
162
+ const store = new MemoryStore<Data>();
163
+ const scheduler = new MemoryScheduler();
164
+
165
+ async function runTurn(input: TurnKind & { sessionId: string }) {
166
+ const session = await store.load(input.sessionId);
167
+ const r = await agent.turn({ ...input, session: session ?? undefined, history: [] });
168
+ if (r.changed) {
169
+ await store.save(r.session, session?.version ?? 0);
170
+ for (const entry of r.schedule) scheduler.add(entry);
171
+ }
172
+ return r;
173
+ }
174
+
175
+ // Turn 1: the customer writes. Understand extracts the name (1 call), speak asks for the company (1 call).
176
+ const t1 = await runTurn({ sessionId: "s1", message: "oi, sou a Ana, quero saber como funciona", id: "m1" });
177
+ assert.equal(t1.llmCalls, 2);
178
+ assert.deepEqual(provider.calls, ["understand", "speak"]);
179
+ assert.equal(t1.session.data.nome, "Ana");
180
+ assert.equal(t1.messages[0]?.key, "triagem#m1:quem:1"); // ${runId}:${stepId}:${visit}
181
+ assert.equal(t1.outcomes.find((o) => o.kind === "collect")?.status, "ok");
182
+ // The assistant spoke last: the silence flow armed a wake for 24h from now.
183
+ const silenceKey = `silence:retomar:s1:${Date.parse(T0)}`;
184
+ assert.deepEqual(t1.schedule.map((s) => s.key), [silenceKey]);
185
+ assert.equal(scheduler.size, 1);
186
+
187
+ // 23h later nothing is due; at 24h the wake fires.
188
+ clock.advance("23h");
189
+ assert.equal(scheduler.due(clock.now()).length, 0);
190
+ clock.advance("1h");
191
+ const due = scheduler.due(clock.now());
192
+ assert.deepEqual(due.map((d) => d.key), [silenceKey]);
193
+
194
+ // Turn 2: the wake starts `retomar`, which speaks first (1 call) and parks on w1.
195
+ const t2 = await runTurn({ sessionId: "s1", wake: due[0].key });
196
+ assert.equal(t2.llmCalls, 1);
197
+ assert.deepEqual(t2.started.map((s) => s.flowId), ["retomar"]);
198
+ assert.equal(t2.messages[0]?.key, `retomar#${Date.parse(T0)}:p1:1`);
199
+ assert.deepEqual(t2.outcomes.find((o) => o.stepId === "w1"), {
200
+ runId: `retomar#${Date.parse(T0)}`,
201
+ flowId: "retomar",
202
+ stepId: "w1",
203
+ key: `retomar#${Date.parse(T0)}:w1:1`,
204
+ kind: "wait",
205
+ status: "waiting",
206
+ until: new Date(clock.now().getTime() + 2 * 86_400_000).toISOString(),
207
+ at: clock.now().toISOString(),
208
+ });
209
+ assert.deepEqual(t2.schedule.map((s) => s.key), [`retomar#${Date.parse(T0)}:w1:${clock.now().getTime() + 2 * 86_400_000}`]);
210
+ // Triagem still holds its question: the nudge did not take the floor for good.
211
+ assert.equal(t2.session.runs.find((r) => r.flowId === "triagem")?.status, "asking");
212
+ assert.equal((await store.load("s1"))?.version, 2);
213
+
214
+ console.log("ok");
215
+ ```
216
+
217
+ What each assertion pins down:
218
+
219
+ - `llmCalls` is the budget. A turn that spends more than you scripted throws inside the provider, so an unexpected third call cannot pass silently. `usage` is absent in tests unless your scripted provider reports token counts — real providers do, and the turn adds them up.
220
+ - `messages[].key` is `${runId}:${stepId}:${visit}`, and `runId` is `${flowId}#${triggerKey}`. The trigger key of a message turn is the message `id` you passed; of a silence wake, the `lastAssistantAt` timestamp in milliseconds.
221
+ - `schedule[].key` is what your queue stores as `jobId` and what you pass back as `wake`. The silence key is `silence:${flowId}:${sessionId}:${ms}`; a timer wait's key is `${runId}:${stepId}:${atMs}`.
222
+ - `outcomes[]` is the execution log, one line per step. Assert on `code`, which is stable across versions, not on `message`, the English sentence beside it; see [outcomes](../reference/outcomes.md).
223
+
224
+ ## Replaying the same input
225
+
226
+ The keys are deterministic: the same input on the same session version mints the same run id, the same message keys and the same wake keys. That is what makes a `SessionConflictError` safe to replay and a duplicate webhook harmless. Prove it with two agents that share a clock:
227
+
228
+ ```ts
229
+ import assert from "node:assert/strict";
230
+ import { falai, fakeClock, type AiProvider, type GenerateMessageInput, type GenerateMessageOutput, type GenerateMessageStreamChunk } from "@falai/agent";
231
+
232
+ type Reply = Record<string, unknown>;
233
+ function scripted(speak: Reply[]): AiProvider {
234
+ const queue = [...speak];
235
+ function next<T>(input: GenerateMessageInput): GenerateMessageOutput<T> {
236
+ if (input.parameters?.schemaName !== "speak") throw new Error(`unexpected ${input.parameters?.schemaName ?? "unnamed"} call`);
237
+ const reply = queue.shift();
238
+ if (!reply) throw new Error("no scripted speak reply left");
239
+ return { message: String(reply.message), structured: reply as T };
240
+ }
241
+ return {
242
+ name: "scripted",
243
+ capabilities: { supportsTools: true, supportsNativeJsonSchema: true, supportsStreaming: true, supportsStreamingToolCalls: true, supportsPromptCaching: false },
244
+ generateMessage: <_C, T>(input: GenerateMessageInput) => Promise.resolve().then(() => next<T>(input)),
245
+ // eslint-disable-next-line @typescript-eslint/require-await -- one chunk, nothing to await
246
+ async *generateMessageStream<_C, T>(input: GenerateMessageInput): AsyncGenerator<GenerateMessageStreamChunk<T>> {
247
+ const out = next<T>(input);
248
+ yield { delta: out.message, accumulated: out.message, done: true, structured: out.structured };
249
+ },
250
+ };
251
+ }
252
+
253
+ const f = falai().fields({
254
+ nome: { type: "string", ask: "Pergunte o nome." },
255
+ });
256
+ const flows = [
257
+ f.flow({ id: "boas-vindas", name: "Boas-vindas", on: [{ message: [] }], steps: [{ id: "nome", collect: ["nome"] }] }),
258
+ f.flow({ id: "retomar", name: "Retomar", on: [{ silence: "24h" }], steps: [{ id: "p1", prompt: "Retome a conversa." }] }),
259
+ ];
260
+ const clock = fakeClock("2026-09-20T10:00:00.000Z");
261
+ const reply = { message: "Oi! Como você se chama?", nome: null };
262
+
263
+ const first = await f.agent({ name: "Ana", provider: scripted([reply]), clock, flows }).turn({ sessionId: "s1", message: "oi", id: "m1" });
264
+ const replay = await f.agent({ name: "Ana", provider: scripted([reply]), clock, flows }).turn({ sessionId: "s1", message: "oi", id: "m1" });
265
+
266
+ assert.deepEqual(replay.messages, first.messages); // same key: boas-vindas#m1:nome:1
267
+ assert.deepEqual(replay.schedule, first.schedule); // same wake: silence:retomar:s1:<ms>
268
+ assert.deepEqual(replay.session.runs, first.session.runs);
269
+ assert.equal(first.llmCalls, 1); // a catch-all alone, and nothing to extract before the ask: no understand call
270
+ console.log("ok");
271
+ ```
272
+
273
+ The same holds inside one session: feed the same `{ message, id }` to the session version it was computed on and the result is the same. Feed it again to a version that already recorded that id and the turn is ignored with `changed: false` and the outcome `code: 'duplicate-input'`.
274
+
275
+ ## Other things worth a test
276
+
277
+ - A `silenced` turn: `agent.turn({ …, silenced: "humano no comando" })` spends zero calls, phrases nothing, and still runs `do` steps. Assert `llmCalls === 0` and `messages.length === 0`.
278
+ - A speak failure: leave the `speak` queue empty so the scripted provider throws inside the turn. `agent.turn()` still returns — no try/catch needed. Assert the outcome `{ status: "deferred", code: "provider-unavailable" }` and a `schedule[]` key ending in `:retry:<ms>`. See [error handling](./error-handling.md).
279
+ - A stale wake: fire a key the session no longer waits for and assert `changed === false` and the outcome `code: 'stale-wake'`.
280
+ - Actions: register `f.action` handlers that push `ctx.key` and `ctx.dedupeKey` to an array, and assert the list. The keys are the same on a replay.
281
+ - The prompt: keep every `GenerateMessageInput` your provider receives and assert on `input.prompt` (which instructions reached it) and `input.tools` (which tools were offered). The repo's own scripted provider, `tests/mock-provider.ts`, records them as `calls[].prompt` and `calls[].input`.
282
+ - Streaming: `turnStream` with the same scripted provider yields one `delta` per provider chunk and a final `{ done, result }` equal to what `turn()` returns.
283
+
284
+ See [the pipeline](../concepts/pipeline.md) for what each phase costs, and [runs and waits](../concepts/runs-and-waits.md) for the full key table.