@falai/agent 3.4.5 → 4.0.0-alpha.2

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 (856) 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 +11 -6
  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/providers/ZaiProvider.d.ts +6 -4
  100. package/dist/cjs/providers/ZaiProvider.d.ts.map +1 -1
  101. package/dist/cjs/providers/ZaiProvider.js +6 -4
  102. package/dist/cjs/providers/ZaiProvider.js.map +1 -1
  103. package/dist/cjs/types/agent.d.ts +153 -383
  104. package/dist/cjs/types/agent.d.ts.map +1 -1
  105. package/dist/cjs/types/agent.js +1 -1
  106. package/dist/cjs/types/ai.d.ts +32 -1
  107. package/dist/cjs/types/ai.d.ts.map +1 -1
  108. package/dist/cjs/types/compaction.d.ts +3 -1
  109. package/dist/cjs/types/compaction.d.ts.map +1 -1
  110. package/dist/cjs/types/errors.d.ts +9 -12
  111. package/dist/cjs/types/errors.d.ts.map +1 -1
  112. package/dist/cjs/types/errors.js +14 -17
  113. package/dist/cjs/types/errors.js.map +1 -1
  114. package/dist/cjs/types/flow.d.ts +265 -513
  115. package/dist/cjs/types/flow.d.ts.map +1 -1
  116. package/dist/cjs/types/flow.js +7 -1
  117. package/dist/cjs/types/flow.js.map +1 -1
  118. package/dist/cjs/types/history.d.ts +7 -18
  119. package/dist/cjs/types/history.d.ts.map +1 -1
  120. package/dist/cjs/types/history.js.map +1 -1
  121. package/dist/cjs/types/index.d.ts +9 -15
  122. package/dist/cjs/types/index.d.ts.map +1 -1
  123. package/dist/cjs/types/index.js +4 -14
  124. package/dist/cjs/types/index.js.map +1 -1
  125. package/dist/cjs/types/session.d.ts +94 -64
  126. package/dist/cjs/types/session.d.ts.map +1 -1
  127. package/dist/cjs/types/session.js +5 -1
  128. package/dist/cjs/types/session.js.map +1 -1
  129. package/dist/cjs/types/tool.d.ts +37 -207
  130. package/dist/cjs/types/tool.d.ts.map +1 -1
  131. package/dist/cjs/types/tool.js +5 -14
  132. package/dist/cjs/types/tool.js.map +1 -1
  133. package/dist/cjs/utils/clock.d.ts +28 -0
  134. package/dist/cjs/utils/clock.d.ts.map +1 -0
  135. package/dist/cjs/utils/clock.js +64 -0
  136. package/dist/cjs/utils/clock.js.map +1 -0
  137. package/dist/cjs/utils/duration.d.ts +11 -0
  138. package/dist/cjs/utils/duration.d.ts.map +1 -0
  139. package/dist/cjs/utils/duration.js +31 -0
  140. package/dist/cjs/utils/duration.js.map +1 -0
  141. package/dist/cjs/utils/history.d.ts +4 -1
  142. package/dist/cjs/utils/history.d.ts.map +1 -1
  143. package/dist/cjs/utils/history.js +2 -2
  144. package/dist/cjs/utils/history.js.map +1 -1
  145. package/dist/cjs/utils/index.d.ts +4 -10
  146. package/dist/cjs/utils/index.d.ts.map +1 -1
  147. package/dist/cjs/utils/index.js +14 -61
  148. package/dist/cjs/utils/index.js.map +1 -1
  149. package/dist/cjs/utils/json.d.ts +2 -0
  150. package/dist/cjs/utils/json.d.ts.map +1 -1
  151. package/dist/cjs/utils/json.js +5 -0
  152. package/dist/cjs/utils/json.js.map +1 -1
  153. package/dist/cjs/utils/outcomes.d.ts +48 -0
  154. package/dist/cjs/utils/outcomes.d.ts.map +1 -0
  155. package/dist/cjs/utils/outcomes.js +51 -0
  156. package/dist/cjs/utils/outcomes.js.map +1 -0
  157. package/dist/cjs/utils/schema.d.ts +50 -0
  158. package/dist/cjs/utils/schema.d.ts.map +1 -0
  159. package/dist/cjs/utils/schema.js +138 -0
  160. package/dist/cjs/utils/schema.js.map +1 -0
  161. package/dist/cjs/utils/streamingMessage.d.ts +3 -2
  162. package/dist/cjs/utils/streamingMessage.d.ts.map +1 -1
  163. package/dist/cjs/utils/streamingMessage.js +38 -4
  164. package/dist/cjs/utils/streamingMessage.js.map +1 -1
  165. package/dist/cjs/utils/template.d.ts +13 -149
  166. package/dist/cjs/utils/template.d.ts.map +1 -1
  167. package/dist/cjs/utils/template.js +31 -363
  168. package/dist/cjs/utils/template.js.map +1 -1
  169. package/dist/cjs/utils/usage.d.ts +19 -0
  170. package/dist/cjs/utils/usage.d.ts.map +1 -0
  171. package/dist/cjs/utils/usage.js +35 -0
  172. package/dist/cjs/utils/usage.js.map +1 -0
  173. package/dist/core/Agent.d.ts +22 -378
  174. package/dist/core/Agent.d.ts.map +1 -1
  175. package/dist/core/Agent.js +107 -1181
  176. package/dist/core/Agent.js.map +1 -1
  177. package/dist/core/CompactionEngine.d.ts.map +1 -1
  178. package/dist/core/CompactionEngine.js +5 -3
  179. package/dist/core/CompactionEngine.js.map +1 -1
  180. package/dist/core/FlowSpec.d.ts +136 -0
  181. package/dist/core/FlowSpec.d.ts.map +1 -0
  182. package/dist/core/FlowSpec.js +516 -0
  183. package/dist/core/FlowSpec.js.map +1 -0
  184. package/dist/core/Migrate.d.ts +38 -0
  185. package/dist/core/Migrate.d.ts.map +1 -0
  186. package/dist/core/Migrate.js +264 -0
  187. package/dist/core/Migrate.js.map +1 -0
  188. package/dist/core/Prompt.d.ts +54 -0
  189. package/dist/core/Prompt.d.ts.map +1 -0
  190. package/dist/core/Prompt.js +133 -0
  191. package/dist/core/Prompt.js.map +1 -0
  192. package/dist/core/Runner.d.ts +160 -0
  193. package/dist/core/Runner.d.ts.map +1 -0
  194. package/dist/core/Runner.js +1127 -0
  195. package/dist/core/Runner.js.map +1 -0
  196. package/dist/core/Speak.d.ts +37 -0
  197. package/dist/core/Speak.d.ts.map +1 -0
  198. package/dist/core/Speak.js +360 -0
  199. package/dist/core/Speak.js.map +1 -0
  200. package/dist/core/Understand.d.ts +28 -0
  201. package/dist/core/Understand.d.ts.map +1 -0
  202. package/dist/core/Understand.js +349 -0
  203. package/dist/core/Understand.js.map +1 -0
  204. package/dist/core/contracts.d.ts +122 -0
  205. package/dist/core/contracts.d.ts.map +1 -0
  206. package/dist/core/contracts.js +10 -0
  207. package/dist/core/contracts.js.map +1 -0
  208. package/dist/core/falai.d.ts +57 -0
  209. package/dist/core/falai.d.ts.map +1 -0
  210. package/dist/core/falai.js +40 -0
  211. package/dist/core/falai.js.map +1 -0
  212. package/dist/core/predicate.d.ts +9 -0
  213. package/dist/core/predicate.d.ts.map +1 -0
  214. package/dist/core/predicate.js +54 -0
  215. package/dist/core/predicate.js.map +1 -0
  216. package/dist/index.d.ts +26 -31
  217. package/dist/index.d.ts.map +1 -1
  218. package/dist/index.js +19 -24
  219. package/dist/index.js.map +1 -1
  220. package/dist/persistence/MemoryStore.d.ts +15 -0
  221. package/dist/persistence/MemoryStore.d.ts.map +1 -0
  222. package/dist/persistence/MemoryStore.js +35 -0
  223. package/dist/persistence/MemoryStore.js.map +1 -0
  224. package/dist/persistence/MongoStore.d.ts +42 -0
  225. package/dist/persistence/MongoStore.d.ts.map +1 -0
  226. package/dist/persistence/MongoStore.js +56 -0
  227. package/dist/persistence/MongoStore.js.map +1 -0
  228. package/dist/persistence/OpenSearchStore.d.ts +86 -0
  229. package/dist/persistence/OpenSearchStore.d.ts.map +1 -0
  230. package/dist/persistence/OpenSearchStore.js +116 -0
  231. package/dist/persistence/OpenSearchStore.js.map +1 -0
  232. package/dist/persistence/PostgresStore.d.ts +41 -0
  233. package/dist/persistence/PostgresStore.d.ts.map +1 -0
  234. package/dist/persistence/PostgresStore.js +54 -0
  235. package/dist/persistence/PostgresStore.js.map +1 -0
  236. package/dist/persistence/PrismaStore.d.ts +65 -0
  237. package/dist/persistence/PrismaStore.d.ts.map +1 -0
  238. package/dist/persistence/PrismaStore.js +91 -0
  239. package/dist/persistence/PrismaStore.js.map +1 -0
  240. package/dist/persistence/RedisStore.d.ts +34 -0
  241. package/dist/persistence/RedisStore.d.ts.map +1 -0
  242. package/dist/persistence/RedisStore.js +57 -0
  243. package/dist/persistence/RedisStore.js.map +1 -0
  244. package/dist/persistence/SQLiteStore.d.ts +45 -0
  245. package/dist/persistence/SQLiteStore.d.ts.map +1 -0
  246. package/dist/persistence/SQLiteStore.js +70 -0
  247. package/dist/persistence/SQLiteStore.js.map +1 -0
  248. package/dist/persistence/sessionRow.d.ts +14 -0
  249. package/dist/persistence/sessionRow.d.ts.map +1 -0
  250. package/dist/persistence/sessionRow.js +45 -0
  251. package/dist/persistence/sessionRow.js.map +1 -0
  252. package/dist/providers/DeepSeekProvider.d.ts.map +1 -1
  253. package/dist/providers/DeepSeekProvider.js +8 -3
  254. package/dist/providers/DeepSeekProvider.js.map +1 -1
  255. package/dist/providers/GeminiProvider.d.ts +4 -3
  256. package/dist/providers/GeminiProvider.d.ts.map +1 -1
  257. package/dist/providers/GeminiProvider.js +4 -3
  258. package/dist/providers/GeminiProvider.js.map +1 -1
  259. package/dist/providers/OpenAICompatibleProvider.d.ts +4 -0
  260. package/dist/providers/OpenAICompatibleProvider.d.ts.map +1 -1
  261. package/dist/providers/OpenAICompatibleProvider.js +2 -0
  262. package/dist/providers/OpenAICompatibleProvider.js.map +1 -1
  263. package/dist/providers/OpenRouterProvider.d.ts.map +1 -1
  264. package/dist/providers/OpenRouterProvider.js +2 -4
  265. package/dist/providers/OpenRouterProvider.js.map +1 -1
  266. package/dist/providers/ProviderAdapter.d.ts +11 -6
  267. package/dist/providers/ProviderAdapter.d.ts.map +1 -1
  268. package/dist/providers/ProviderAdapter.js +34 -11
  269. package/dist/providers/ProviderAdapter.js.map +1 -1
  270. package/dist/providers/ZaiProvider.d.ts +6 -4
  271. package/dist/providers/ZaiProvider.d.ts.map +1 -1
  272. package/dist/providers/ZaiProvider.js +6 -4
  273. package/dist/providers/ZaiProvider.js.map +1 -1
  274. package/dist/types/agent.d.ts +153 -383
  275. package/dist/types/agent.d.ts.map +1 -1
  276. package/dist/types/agent.js +1 -1
  277. package/dist/types/ai.d.ts +32 -1
  278. package/dist/types/ai.d.ts.map +1 -1
  279. package/dist/types/compaction.d.ts +3 -1
  280. package/dist/types/compaction.d.ts.map +1 -1
  281. package/dist/types/errors.d.ts +9 -12
  282. package/dist/types/errors.d.ts.map +1 -1
  283. package/dist/types/errors.js +12 -15
  284. package/dist/types/errors.js.map +1 -1
  285. package/dist/types/flow.d.ts +265 -513
  286. package/dist/types/flow.d.ts.map +1 -1
  287. package/dist/types/flow.js +7 -1
  288. package/dist/types/flow.js.map +1 -1
  289. package/dist/types/history.d.ts +7 -18
  290. package/dist/types/history.d.ts.map +1 -1
  291. package/dist/types/history.js.map +1 -1
  292. package/dist/types/index.d.ts +9 -15
  293. package/dist/types/index.d.ts.map +1 -1
  294. package/dist/types/index.js +2 -7
  295. package/dist/types/index.js.map +1 -1
  296. package/dist/types/session.d.ts +94 -64
  297. package/dist/types/session.d.ts.map +1 -1
  298. package/dist/types/session.js +5 -1
  299. package/dist/types/session.js.map +1 -1
  300. package/dist/types/tool.d.ts +37 -207
  301. package/dist/types/tool.d.ts.map +1 -1
  302. package/dist/types/tool.js +6 -13
  303. package/dist/types/tool.js.map +1 -1
  304. package/dist/utils/clock.d.ts +28 -0
  305. package/dist/utils/clock.d.ts.map +1 -0
  306. package/dist/utils/clock.js +59 -0
  307. package/dist/utils/clock.js.map +1 -0
  308. package/dist/utils/duration.d.ts +11 -0
  309. package/dist/utils/duration.d.ts.map +1 -0
  310. package/dist/utils/duration.js +26 -0
  311. package/dist/utils/duration.js.map +1 -0
  312. package/dist/utils/history.d.ts +4 -1
  313. package/dist/utils/history.d.ts.map +1 -1
  314. package/dist/utils/history.js +2 -2
  315. package/dist/utils/history.js.map +1 -1
  316. package/dist/utils/index.d.ts +4 -10
  317. package/dist/utils/index.d.ts.map +1 -1
  318. package/dist/utils/index.js +4 -21
  319. package/dist/utils/index.js.map +1 -1
  320. package/dist/utils/json.d.ts +2 -0
  321. package/dist/utils/json.d.ts.map +1 -1
  322. package/dist/utils/json.js +4 -0
  323. package/dist/utils/json.js.map +1 -1
  324. package/dist/utils/outcomes.d.ts +48 -0
  325. package/dist/utils/outcomes.d.ts.map +1 -0
  326. package/dist/utils/outcomes.js +48 -0
  327. package/dist/utils/outcomes.js.map +1 -0
  328. package/dist/utils/schema.d.ts +50 -0
  329. package/dist/utils/schema.d.ts.map +1 -0
  330. package/dist/utils/schema.js +129 -0
  331. package/dist/utils/schema.js.map +1 -0
  332. package/dist/utils/streamingMessage.d.ts +3 -2
  333. package/dist/utils/streamingMessage.d.ts.map +1 -1
  334. package/dist/utils/streamingMessage.js +38 -4
  335. package/dist/utils/streamingMessage.js.map +1 -1
  336. package/dist/utils/template.d.ts +13 -149
  337. package/dist/utils/template.d.ts.map +1 -1
  338. package/dist/utils/template.js +28 -355
  339. package/dist/utils/template.js.map +1 -1
  340. package/dist/utils/usage.d.ts +19 -0
  341. package/dist/utils/usage.d.ts.map +1 -0
  342. package/dist/utils/usage.js +31 -0
  343. package/dist/utils/usage.js.map +1 -0
  344. package/docs/README.md +37 -19
  345. package/docs/concepts/architecture.md +117 -239
  346. package/docs/concepts/collection.md +170 -0
  347. package/docs/concepts/pipeline.md +132 -378
  348. package/docs/concepts/runs-and-waits.md +192 -0
  349. package/docs/guides/actions-and-events.md +276 -0
  350. package/docs/guides/branching.md +119 -208
  351. package/docs/guides/compaction.md +63 -158
  352. package/docs/guides/conditions.md +164 -128
  353. package/docs/guides/error-handling.md +168 -164
  354. package/docs/guides/flow-control.md +210 -349
  355. package/docs/guides/flows-from-json.md +224 -0
  356. package/docs/guides/instructions.md +125 -161
  357. package/docs/guides/persistence.md +182 -206
  358. package/docs/guides/streaming.md +50 -114
  359. package/docs/guides/testing.md +284 -0
  360. package/docs/guides/triggers.md +401 -0
  361. package/docs/migration/README.md +8 -15
  362. package/docs/migration/v1-to-v2.md +1 -1
  363. package/docs/migration/v2-3-to-v2-4.md +2 -2
  364. package/docs/migration/v2-6-to-v2-7.md +4 -4
  365. package/docs/migration/v3-to-v4.md +452 -0
  366. package/docs/reference/actions-events-conditions.md +396 -0
  367. package/docs/reference/agent.md +244 -0
  368. package/docs/reference/branches.md +75 -203
  369. package/docs/reference/errors.md +188 -144
  370. package/docs/reference/fields.md +125 -0
  371. package/docs/reference/flow-spec.md +248 -0
  372. package/docs/reference/flow.md +104 -192
  373. package/docs/reference/instruction.md +83 -137
  374. package/docs/reference/outcomes.md +273 -0
  375. package/docs/reference/providers.md +525 -302
  376. package/docs/reference/session.md +210 -0
  377. package/docs/reference/step.md +194 -312
  378. package/docs/reference/stores.md +496 -0
  379. package/docs/reference/tool.md +162 -231
  380. package/docs/reference/trigger.md +180 -0
  381. package/docs/rfc/v4-one-flow.md +477 -0
  382. package/docs/start/01-install.md +59 -44
  383. package/docs/start/02-first-agent.md +97 -147
  384. package/docs/start/03-collect-data.md +78 -183
  385. package/docs/start/04-add-tools.md +159 -227
  386. package/docs/start/05-go-to-production.md +167 -164
  387. package/examples/01-quickstart.ts +26 -16
  388. package/examples/02-fields.ts +75 -0
  389. package/examples/03-tools.ts +79 -119
  390. package/examples/04-instructions.ts +60 -87
  391. package/examples/05-branches.ts +78 -0
  392. package/examples/06-triggers-and-waits.ts +148 -0
  393. package/examples/07-streaming.ts +34 -60
  394. package/examples/08-store-and-migration.ts +97 -0
  395. package/examples/09-flows-from-json.ts +107 -0
  396. package/package.json +9 -6
  397. package/src/core/Agent.ts +116 -1512
  398. package/src/core/CompactionEngine.ts +7 -4
  399. package/src/core/FlowSpec.ts +712 -0
  400. package/src/core/Migrate.ts +256 -0
  401. package/src/core/Prompt.ts +156 -0
  402. package/src/core/Runner.ts +1181 -0
  403. package/src/core/Speak.ts +451 -0
  404. package/src/core/Understand.ts +422 -0
  405. package/src/core/contracts.ts +111 -0
  406. package/src/core/falai.ts +86 -0
  407. package/src/core/predicate.ts +56 -0
  408. package/src/index.ts +119 -147
  409. package/src/persistence/MemoryStore.ts +37 -0
  410. package/src/persistence/MongoStore.ts +89 -0
  411. package/src/persistence/OpenSearchStore.ts +153 -0
  412. package/src/persistence/PostgresStore.ts +89 -0
  413. package/src/persistence/PrismaStore.ts +127 -0
  414. package/src/persistence/RedisStore.ts +90 -0
  415. package/src/persistence/SQLiteStore.ts +103 -0
  416. package/src/persistence/sessionRow.ts +45 -0
  417. package/src/providers/DeepSeekProvider.ts +8 -3
  418. package/src/providers/GeminiProvider.ts +4 -3
  419. package/src/providers/OpenAICompatibleProvider.ts +6 -0
  420. package/src/providers/OpenRouterProvider.ts +2 -4
  421. package/src/providers/ProviderAdapter.ts +46 -13
  422. package/src/providers/ZaiProvider.ts +6 -4
  423. package/src/types/agent.ts +124 -397
  424. package/src/types/ai.ts +33 -1
  425. package/src/types/compaction.ts +3 -1
  426. package/src/types/errors.ts +13 -16
  427. package/src/types/flow.ts +249 -550
  428. package/src/types/history.ts +7 -20
  429. package/src/types/index.ts +87 -139
  430. package/src/types/session.ts +135 -70
  431. package/src/types/tool.ts +42 -267
  432. package/src/utils/clock.ts +70 -0
  433. package/src/utils/duration.ts +33 -0
  434. package/src/utils/history.ts +3 -2
  435. package/src/utils/index.ts +8 -66
  436. package/src/utils/json.ts +5 -0
  437. package/src/utils/outcomes.ts +56 -0
  438. package/src/utils/schema.ts +145 -0
  439. package/src/utils/streamingMessage.ts +34 -4
  440. package/src/utils/template.ts +32 -423
  441. package/src/utils/usage.ts +37 -0
  442. package/dist/adapters/MemoryAdapter.d.ts +0 -47
  443. package/dist/adapters/MemoryAdapter.d.ts.map +0 -1
  444. package/dist/adapters/MemoryAdapter.js +0 -204
  445. package/dist/adapters/MemoryAdapter.js.map +0 -1
  446. package/dist/adapters/MongoAdapter.d.ts +0 -97
  447. package/dist/adapters/MongoAdapter.d.ts.map +0 -1
  448. package/dist/adapters/MongoAdapter.js +0 -196
  449. package/dist/adapters/MongoAdapter.js.map +0 -1
  450. package/dist/adapters/OpenSearchAdapter.d.ts +0 -169
  451. package/dist/adapters/OpenSearchAdapter.d.ts.map +0 -1
  452. package/dist/adapters/OpenSearchAdapter.js +0 -471
  453. package/dist/adapters/OpenSearchAdapter.js.map +0 -1
  454. package/dist/adapters/PostgreSQLAdapter.d.ts +0 -85
  455. package/dist/adapters/PostgreSQLAdapter.d.ts.map +0 -1
  456. package/dist/adapters/PostgreSQLAdapter.js +0 -308
  457. package/dist/adapters/PostgreSQLAdapter.js.map +0 -1
  458. package/dist/adapters/PrismaAdapter.d.ts +0 -115
  459. package/dist/adapters/PrismaAdapter.d.ts.map +0 -1
  460. package/dist/adapters/PrismaAdapter.js +0 -406
  461. package/dist/adapters/PrismaAdapter.js.map +0 -1
  462. package/dist/adapters/RedisAdapter.d.ts +0 -72
  463. package/dist/adapters/RedisAdapter.d.ts.map +0 -1
  464. package/dist/adapters/RedisAdapter.js +0 -286
  465. package/dist/adapters/RedisAdapter.js.map +0 -1
  466. package/dist/adapters/SQLiteAdapter.d.ts +0 -86
  467. package/dist/adapters/SQLiteAdapter.d.ts.map +0 -1
  468. package/dist/adapters/SQLiteAdapter.js +0 -337
  469. package/dist/adapters/SQLiteAdapter.js.map +0 -1
  470. package/dist/adapters/index.d.ts +0 -17
  471. package/dist/adapters/index.d.ts.map +0 -1
  472. package/dist/adapters/index.js +0 -11
  473. package/dist/adapters/index.js.map +0 -1
  474. package/dist/adapters/sessionRow.d.ts +0 -22
  475. package/dist/adapters/sessionRow.d.ts.map +0 -1
  476. package/dist/adapters/sessionRow.js +0 -48
  477. package/dist/adapters/sessionRow.js.map +0 -1
  478. package/dist/cjs/adapters/MemoryAdapter.d.ts +0 -47
  479. package/dist/cjs/adapters/MemoryAdapter.d.ts.map +0 -1
  480. package/dist/cjs/adapters/MemoryAdapter.js +0 -208
  481. package/dist/cjs/adapters/MemoryAdapter.js.map +0 -1
  482. package/dist/cjs/adapters/MongoAdapter.d.ts +0 -97
  483. package/dist/cjs/adapters/MongoAdapter.d.ts.map +0 -1
  484. package/dist/cjs/adapters/MongoAdapter.js +0 -200
  485. package/dist/cjs/adapters/MongoAdapter.js.map +0 -1
  486. package/dist/cjs/adapters/OpenSearchAdapter.d.ts +0 -169
  487. package/dist/cjs/adapters/OpenSearchAdapter.d.ts.map +0 -1
  488. package/dist/cjs/adapters/OpenSearchAdapter.js +0 -475
  489. package/dist/cjs/adapters/OpenSearchAdapter.js.map +0 -1
  490. package/dist/cjs/adapters/PostgreSQLAdapter.d.ts +0 -85
  491. package/dist/cjs/adapters/PostgreSQLAdapter.d.ts.map +0 -1
  492. package/dist/cjs/adapters/PostgreSQLAdapter.js +0 -312
  493. package/dist/cjs/adapters/PostgreSQLAdapter.js.map +0 -1
  494. package/dist/cjs/adapters/PrismaAdapter.d.ts +0 -115
  495. package/dist/cjs/adapters/PrismaAdapter.d.ts.map +0 -1
  496. package/dist/cjs/adapters/PrismaAdapter.js +0 -410
  497. package/dist/cjs/adapters/PrismaAdapter.js.map +0 -1
  498. package/dist/cjs/adapters/RedisAdapter.d.ts +0 -72
  499. package/dist/cjs/adapters/RedisAdapter.d.ts.map +0 -1
  500. package/dist/cjs/adapters/RedisAdapter.js +0 -290
  501. package/dist/cjs/adapters/RedisAdapter.js.map +0 -1
  502. package/dist/cjs/adapters/SQLiteAdapter.d.ts +0 -86
  503. package/dist/cjs/adapters/SQLiteAdapter.d.ts.map +0 -1
  504. package/dist/cjs/adapters/SQLiteAdapter.js +0 -341
  505. package/dist/cjs/adapters/SQLiteAdapter.js.map +0 -1
  506. package/dist/cjs/adapters/index.d.ts +0 -17
  507. package/dist/cjs/adapters/index.d.ts.map +0 -1
  508. package/dist/cjs/adapters/index.js +0 -21
  509. package/dist/cjs/adapters/index.js.map +0 -1
  510. package/dist/cjs/adapters/sessionRow.d.ts +0 -22
  511. package/dist/cjs/adapters/sessionRow.d.ts.map +0 -1
  512. package/dist/cjs/adapters/sessionRow.js +0 -52
  513. package/dist/cjs/adapters/sessionRow.js.map +0 -1
  514. package/dist/cjs/constants/index.d.ts +0 -1
  515. package/dist/cjs/constants/index.d.ts.map +0 -1
  516. package/dist/cjs/constants/index.js +0 -4
  517. package/dist/cjs/constants/index.js.map +0 -1
  518. package/dist/cjs/core/AutoChainExecutor.d.ts +0 -97
  519. package/dist/cjs/core/AutoChainExecutor.d.ts.map +0 -1
  520. package/dist/cjs/core/AutoChainExecutor.js +0 -288
  521. package/dist/cjs/core/AutoChainExecutor.js.map +0 -1
  522. package/dist/cjs/core/BranchEvaluator.d.ts +0 -55
  523. package/dist/cjs/core/BranchEvaluator.d.ts.map +0 -1
  524. package/dist/cjs/core/BranchEvaluator.js +0 -125
  525. package/dist/cjs/core/BranchEvaluator.js.map +0 -1
  526. package/dist/cjs/core/DirectiveChainTracker.d.ts +0 -49
  527. package/dist/cjs/core/DirectiveChainTracker.d.ts.map +0 -1
  528. package/dist/cjs/core/DirectiveChainTracker.js +0 -121
  529. package/dist/cjs/core/DirectiveChainTracker.js.map +0 -1
  530. package/dist/cjs/core/Events.d.ts +0 -26
  531. package/dist/cjs/core/Events.d.ts.map +0 -1
  532. package/dist/cjs/core/Events.js +0 -144
  533. package/dist/cjs/core/Events.js.map +0 -1
  534. package/dist/cjs/core/Flow.d.ts +0 -183
  535. package/dist/cjs/core/Flow.d.ts.map +0 -1
  536. package/dist/cjs/core/Flow.js +0 -551
  537. package/dist/cjs/core/Flow.js.map +0 -1
  538. package/dist/cjs/core/FlowRouter.d.ts +0 -183
  539. package/dist/cjs/core/FlowRouter.d.ts.map +0 -1
  540. package/dist/cjs/core/FlowRouter.js +0 -1047
  541. package/dist/cjs/core/FlowRouter.js.map +0 -1
  542. package/dist/cjs/core/PersistenceManager.d.ts +0 -114
  543. package/dist/cjs/core/PersistenceManager.d.ts.map +0 -1
  544. package/dist/cjs/core/PersistenceManager.js +0 -336
  545. package/dist/cjs/core/PersistenceManager.js.map +0 -1
  546. package/dist/cjs/core/PromptComposer.d.ts +0 -47
  547. package/dist/cjs/core/PromptComposer.d.ts.map +0 -1
  548. package/dist/cjs/core/PromptComposer.js +0 -397
  549. package/dist/cjs/core/PromptComposer.js.map +0 -1
  550. package/dist/cjs/core/PromptSectionCache.d.ts +0 -48
  551. package/dist/cjs/core/PromptSectionCache.d.ts.map +0 -1
  552. package/dist/cjs/core/PromptSectionCache.js +0 -108
  553. package/dist/cjs/core/PromptSectionCache.js.map +0 -1
  554. package/dist/cjs/core/ResponseEngine.d.ts +0 -43
  555. package/dist/cjs/core/ResponseEngine.d.ts.map +0 -1
  556. package/dist/cjs/core/ResponseEngine.js +0 -235
  557. package/dist/cjs/core/ResponseEngine.js.map +0 -1
  558. package/dist/cjs/core/ResponseGenerationError.d.ts +0 -30
  559. package/dist/cjs/core/ResponseGenerationError.d.ts.map +0 -1
  560. package/dist/cjs/core/ResponseGenerationError.js +0 -35
  561. package/dist/cjs/core/ResponseGenerationError.js.map +0 -1
  562. package/dist/cjs/core/ResponseModal.d.ts +0 -305
  563. package/dist/cjs/core/ResponseModal.d.ts.map +0 -1
  564. package/dist/cjs/core/ResponseModal.js +0 -1414
  565. package/dist/cjs/core/ResponseModal.js.map +0 -1
  566. package/dist/cjs/core/ResponsePipeline.d.ts +0 -220
  567. package/dist/cjs/core/ResponsePipeline.d.ts.map +0 -1
  568. package/dist/cjs/core/ResponsePipeline.js +0 -1040
  569. package/dist/cjs/core/ResponsePipeline.js.map +0 -1
  570. package/dist/cjs/core/SessionFinalizer.d.ts +0 -34
  571. package/dist/cjs/core/SessionFinalizer.d.ts.map +0 -1
  572. package/dist/cjs/core/SessionFinalizer.js +0 -88
  573. package/dist/cjs/core/SessionFinalizer.js.map +0 -1
  574. package/dist/cjs/core/SessionManager.d.ts +0 -112
  575. package/dist/cjs/core/SessionManager.d.ts.map +0 -1
  576. package/dist/cjs/core/SessionManager.js +0 -308
  577. package/dist/cjs/core/SessionManager.js.map +0 -1
  578. package/dist/cjs/core/SignalCoordinator.d.ts +0 -103
  579. package/dist/cjs/core/SignalCoordinator.d.ts.map +0 -1
  580. package/dist/cjs/core/SignalCoordinator.js +0 -207
  581. package/dist/cjs/core/SignalCoordinator.js.map +0 -1
  582. package/dist/cjs/core/SignalEvaluator.d.ts +0 -86
  583. package/dist/cjs/core/SignalEvaluator.d.ts.map +0 -1
  584. package/dist/cjs/core/SignalEvaluator.js +0 -319
  585. package/dist/cjs/core/SignalEvaluator.js.map +0 -1
  586. package/dist/cjs/core/SignalProcessor.d.ts +0 -152
  587. package/dist/cjs/core/SignalProcessor.d.ts.map +0 -1
  588. package/dist/cjs/core/SignalProcessor.js +0 -505
  589. package/dist/cjs/core/SignalProcessor.js.map +0 -1
  590. package/dist/cjs/core/Step.d.ts +0 -184
  591. package/dist/cjs/core/Step.d.ts.map +0 -1
  592. package/dist/cjs/core/Step.js +0 -599
  593. package/dist/cjs/core/Step.js.map +0 -1
  594. package/dist/cjs/core/StepLifecycle.d.ts +0 -43
  595. package/dist/cjs/core/StepLifecycle.d.ts.map +0 -1
  596. package/dist/cjs/core/StepLifecycle.js +0 -180
  597. package/dist/cjs/core/StepLifecycle.js.map +0 -1
  598. package/dist/cjs/core/StreamingToolExecutor.d.ts +0 -142
  599. package/dist/cjs/core/StreamingToolExecutor.d.ts.map +0 -1
  600. package/dist/cjs/core/StreamingToolExecutor.js +0 -490
  601. package/dist/cjs/core/StreamingToolExecutor.js.map +0 -1
  602. package/dist/cjs/core/ToolLoopExecutor.d.ts +0 -133
  603. package/dist/cjs/core/ToolLoopExecutor.d.ts.map +0 -1
  604. package/dist/cjs/core/ToolLoopExecutor.js +0 -568
  605. package/dist/cjs/core/ToolLoopExecutor.js.map +0 -1
  606. package/dist/cjs/core/ToolManager.d.ts +0 -250
  607. package/dist/cjs/core/ToolManager.d.ts.map +0 -1
  608. package/dist/cjs/core/ToolManager.js +0 -1104
  609. package/dist/cjs/core/ToolManager.js.map +0 -1
  610. package/dist/cjs/core/createAgent.d.ts +0 -35
  611. package/dist/cjs/core/createAgent.d.ts.map +0 -1
  612. package/dist/cjs/core/createAgent.js +0 -39
  613. package/dist/cjs/core/createAgent.js.map +0 -1
  614. package/dist/cjs/core/flow-namespace.d.ts +0 -64
  615. package/dist/cjs/core/flow-namespace.d.ts.map +0 -1
  616. package/dist/cjs/core/flow-namespace.js +0 -182
  617. package/dist/cjs/core/flow-namespace.js.map +0 -1
  618. package/dist/cjs/core/toolGates.d.ts +0 -24
  619. package/dist/cjs/core/toolGates.d.ts.map +0 -1
  620. package/dist/cjs/core/toolGates.js +0 -52
  621. package/dist/cjs/core/toolGates.js.map +0 -1
  622. package/dist/cjs/types/persistence.d.ts +0 -254
  623. package/dist/cjs/types/persistence.d.ts.map +0 -1
  624. package/dist/cjs/types/persistence.js +0 -7
  625. package/dist/cjs/types/persistence.js.map +0 -1
  626. package/dist/cjs/types/prompt-cache.d.ts +0 -15
  627. package/dist/cjs/types/prompt-cache.d.ts.map +0 -1
  628. package/dist/cjs/types/prompt-cache.js +0 -6
  629. package/dist/cjs/types/prompt-cache.js.map +0 -1
  630. package/dist/cjs/types/signals.d.ts +0 -263
  631. package/dist/cjs/types/signals.d.ts.map +0 -1
  632. package/dist/cjs/types/signals.js +0 -11
  633. package/dist/cjs/types/signals.js.map +0 -1
  634. package/dist/cjs/types/template.d.ts +0 -84
  635. package/dist/cjs/types/template.d.ts.map +0 -1
  636. package/dist/cjs/types/template.js +0 -3
  637. package/dist/cjs/types/template.js.map +0 -1
  638. package/dist/cjs/utils/condition.d.ts +0 -63
  639. package/dist/cjs/utils/condition.d.ts.map +0 -1
  640. package/dist/cjs/utils/condition.js +0 -239
  641. package/dist/cjs/utils/condition.js.map +0 -1
  642. package/dist/cjs/utils/event.d.ts +0 -6
  643. package/dist/cjs/utils/event.d.ts.map +0 -1
  644. package/dist/cjs/utils/event.js +0 -20
  645. package/dist/cjs/utils/event.js.map +0 -1
  646. package/dist/cjs/utils/id.d.ts +0 -33
  647. package/dist/cjs/utils/id.d.ts.map +0 -1
  648. package/dist/cjs/utils/id.js +0 -84
  649. package/dist/cjs/utils/id.js.map +0 -1
  650. package/dist/cjs/utils/serialize.d.ts +0 -36
  651. package/dist/cjs/utils/serialize.d.ts.map +0 -1
  652. package/dist/cjs/utils/serialize.js +0 -77
  653. package/dist/cjs/utils/serialize.js.map +0 -1
  654. package/dist/cjs/utils/session.d.ts +0 -124
  655. package/dist/cjs/utils/session.d.ts.map +0 -1
  656. package/dist/cjs/utils/session.js +0 -396
  657. package/dist/cjs/utils/session.js.map +0 -1
  658. package/dist/constants/index.d.ts +0 -2
  659. package/dist/constants/index.d.ts.map +0 -1
  660. package/dist/constants/index.js +0 -4
  661. package/dist/constants/index.js.map +0 -1
  662. package/dist/core/AutoChainExecutor.d.ts +0 -97
  663. package/dist/core/AutoChainExecutor.d.ts.map +0 -1
  664. package/dist/core/AutoChainExecutor.js +0 -284
  665. package/dist/core/AutoChainExecutor.js.map +0 -1
  666. package/dist/core/BranchEvaluator.d.ts +0 -55
  667. package/dist/core/BranchEvaluator.d.ts.map +0 -1
  668. package/dist/core/BranchEvaluator.js +0 -121
  669. package/dist/core/BranchEvaluator.js.map +0 -1
  670. package/dist/core/DirectiveChainTracker.d.ts +0 -49
  671. package/dist/core/DirectiveChainTracker.d.ts.map +0 -1
  672. package/dist/core/DirectiveChainTracker.js +0 -117
  673. package/dist/core/DirectiveChainTracker.js.map +0 -1
  674. package/dist/core/Events.d.ts +0 -26
  675. package/dist/core/Events.d.ts.map +0 -1
  676. package/dist/core/Events.js +0 -137
  677. package/dist/core/Events.js.map +0 -1
  678. package/dist/core/Flow.d.ts +0 -183
  679. package/dist/core/Flow.d.ts.map +0 -1
  680. package/dist/core/Flow.js +0 -547
  681. package/dist/core/Flow.js.map +0 -1
  682. package/dist/core/FlowRouter.d.ts +0 -183
  683. package/dist/core/FlowRouter.d.ts.map +0 -1
  684. package/dist/core/FlowRouter.js +0 -1043
  685. package/dist/core/FlowRouter.js.map +0 -1
  686. package/dist/core/PersistenceManager.d.ts +0 -114
  687. package/dist/core/PersistenceManager.d.ts.map +0 -1
  688. package/dist/core/PersistenceManager.js +0 -332
  689. package/dist/core/PersistenceManager.js.map +0 -1
  690. package/dist/core/PromptComposer.d.ts +0 -47
  691. package/dist/core/PromptComposer.d.ts.map +0 -1
  692. package/dist/core/PromptComposer.js +0 -393
  693. package/dist/core/PromptComposer.js.map +0 -1
  694. package/dist/core/PromptSectionCache.d.ts +0 -48
  695. package/dist/core/PromptSectionCache.d.ts.map +0 -1
  696. package/dist/core/PromptSectionCache.js +0 -104
  697. package/dist/core/PromptSectionCache.js.map +0 -1
  698. package/dist/core/ResponseEngine.d.ts +0 -43
  699. package/dist/core/ResponseEngine.d.ts.map +0 -1
  700. package/dist/core/ResponseEngine.js +0 -231
  701. package/dist/core/ResponseEngine.js.map +0 -1
  702. package/dist/core/ResponseGenerationError.d.ts +0 -30
  703. package/dist/core/ResponseGenerationError.d.ts.map +0 -1
  704. package/dist/core/ResponseGenerationError.js +0 -31
  705. package/dist/core/ResponseGenerationError.js.map +0 -1
  706. package/dist/core/ResponseModal.d.ts +0 -305
  707. package/dist/core/ResponseModal.d.ts.map +0 -1
  708. package/dist/core/ResponseModal.js +0 -1410
  709. package/dist/core/ResponseModal.js.map +0 -1
  710. package/dist/core/ResponsePipeline.d.ts +0 -220
  711. package/dist/core/ResponsePipeline.d.ts.map +0 -1
  712. package/dist/core/ResponsePipeline.js +0 -1035
  713. package/dist/core/ResponsePipeline.js.map +0 -1
  714. package/dist/core/SessionFinalizer.d.ts +0 -34
  715. package/dist/core/SessionFinalizer.d.ts.map +0 -1
  716. package/dist/core/SessionFinalizer.js +0 -84
  717. package/dist/core/SessionFinalizer.js.map +0 -1
  718. package/dist/core/SessionManager.d.ts +0 -112
  719. package/dist/core/SessionManager.d.ts.map +0 -1
  720. package/dist/core/SessionManager.js +0 -301
  721. package/dist/core/SessionManager.js.map +0 -1
  722. package/dist/core/SignalCoordinator.d.ts +0 -103
  723. package/dist/core/SignalCoordinator.d.ts.map +0 -1
  724. package/dist/core/SignalCoordinator.js +0 -203
  725. package/dist/core/SignalCoordinator.js.map +0 -1
  726. package/dist/core/SignalEvaluator.d.ts +0 -86
  727. package/dist/core/SignalEvaluator.d.ts.map +0 -1
  728. package/dist/core/SignalEvaluator.js +0 -312
  729. package/dist/core/SignalEvaluator.js.map +0 -1
  730. package/dist/core/SignalProcessor.d.ts +0 -152
  731. package/dist/core/SignalProcessor.d.ts.map +0 -1
  732. package/dist/core/SignalProcessor.js +0 -498
  733. package/dist/core/SignalProcessor.js.map +0 -1
  734. package/dist/core/Step.d.ts +0 -184
  735. package/dist/core/Step.d.ts.map +0 -1
  736. package/dist/core/Step.js +0 -594
  737. package/dist/core/Step.js.map +0 -1
  738. package/dist/core/StepLifecycle.d.ts +0 -43
  739. package/dist/core/StepLifecycle.d.ts.map +0 -1
  740. package/dist/core/StepLifecycle.js +0 -176
  741. package/dist/core/StepLifecycle.js.map +0 -1
  742. package/dist/core/StreamingToolExecutor.d.ts +0 -142
  743. package/dist/core/StreamingToolExecutor.d.ts.map +0 -1
  744. package/dist/core/StreamingToolExecutor.js +0 -483
  745. package/dist/core/StreamingToolExecutor.js.map +0 -1
  746. package/dist/core/ToolLoopExecutor.d.ts +0 -133
  747. package/dist/core/ToolLoopExecutor.d.ts.map +0 -1
  748. package/dist/core/ToolLoopExecutor.js +0 -564
  749. package/dist/core/ToolLoopExecutor.js.map +0 -1
  750. package/dist/core/ToolManager.d.ts +0 -250
  751. package/dist/core/ToolManager.d.ts.map +0 -1
  752. package/dist/core/ToolManager.js +0 -1098
  753. package/dist/core/ToolManager.js.map +0 -1
  754. package/dist/core/createAgent.d.ts +0 -35
  755. package/dist/core/createAgent.d.ts.map +0 -1
  756. package/dist/core/createAgent.js +0 -36
  757. package/dist/core/createAgent.js.map +0 -1
  758. package/dist/core/flow-namespace.d.ts +0 -64
  759. package/dist/core/flow-namespace.d.ts.map +0 -1
  760. package/dist/core/flow-namespace.js +0 -179
  761. package/dist/core/flow-namespace.js.map +0 -1
  762. package/dist/core/toolGates.d.ts +0 -24
  763. package/dist/core/toolGates.d.ts.map +0 -1
  764. package/dist/core/toolGates.js +0 -49
  765. package/dist/core/toolGates.js.map +0 -1
  766. package/dist/types/persistence.d.ts +0 -254
  767. package/dist/types/persistence.d.ts.map +0 -1
  768. package/dist/types/persistence.js +0 -6
  769. package/dist/types/persistence.js.map +0 -1
  770. package/dist/types/prompt-cache.d.ts +0 -15
  771. package/dist/types/prompt-cache.d.ts.map +0 -1
  772. package/dist/types/prompt-cache.js +0 -5
  773. package/dist/types/prompt-cache.js.map +0 -1
  774. package/dist/types/signals.d.ts +0 -263
  775. package/dist/types/signals.d.ts.map +0 -1
  776. package/dist/types/signals.js +0 -10
  777. package/dist/types/signals.js.map +0 -1
  778. package/dist/types/template.d.ts +0 -84
  779. package/dist/types/template.d.ts.map +0 -1
  780. package/dist/types/template.js +0 -2
  781. package/dist/types/template.js.map +0 -1
  782. package/dist/utils/condition.d.ts +0 -63
  783. package/dist/utils/condition.d.ts.map +0 -1
  784. package/dist/utils/condition.js +0 -230
  785. package/dist/utils/condition.js.map +0 -1
  786. package/dist/utils/event.d.ts +0 -6
  787. package/dist/utils/event.d.ts.map +0 -1
  788. package/dist/utils/event.js +0 -17
  789. package/dist/utils/event.js.map +0 -1
  790. package/dist/utils/id.d.ts +0 -33
  791. package/dist/utils/id.d.ts.map +0 -1
  792. package/dist/utils/id.js +0 -77
  793. package/dist/utils/id.js.map +0 -1
  794. package/dist/utils/serialize.d.ts +0 -36
  795. package/dist/utils/serialize.d.ts.map +0 -1
  796. package/dist/utils/serialize.js +0 -72
  797. package/dist/utils/serialize.js.map +0 -1
  798. package/dist/utils/session.d.ts +0 -124
  799. package/dist/utils/session.d.ts.map +0 -1
  800. package/dist/utils/session.js +0 -379
  801. package/dist/utils/session.js.map +0 -1
  802. package/docs/concepts/directives.md +0 -369
  803. package/docs/reference/adapters.md +0 -543
  804. package/docs/reference/create-agent.md +0 -216
  805. package/docs/reference/directive.md +0 -242
  806. package/docs/reference/signals.md +0 -368
  807. package/examples/02-data-extraction.ts +0 -90
  808. package/examples/05-branching.ts +0 -140
  809. package/examples/06-flow-control.ts +0 -103
  810. package/examples/08-persistence.ts +0 -98
  811. package/examples/09-signals.ts +0 -144
  812. package/src/adapters/MemoryAdapter.ts +0 -281
  813. package/src/adapters/MongoAdapter.ts +0 -341
  814. package/src/adapters/OpenSearchAdapter.ts +0 -693
  815. package/src/adapters/PostgreSQLAdapter.ts +0 -487
  816. package/src/adapters/PrismaAdapter.ts +0 -617
  817. package/src/adapters/RedisAdapter.ts +0 -439
  818. package/src/adapters/SQLiteAdapter.ts +0 -496
  819. package/src/adapters/index.ts +0 -43
  820. package/src/adapters/sessionRow.ts +0 -57
  821. package/src/constants/index.ts +0 -2
  822. package/src/core/AutoChainExecutor.ts +0 -397
  823. package/src/core/BranchEvaluator.ts +0 -161
  824. package/src/core/DirectiveChainTracker.ts +0 -144
  825. package/src/core/Events.ts +0 -164
  826. package/src/core/Flow.ts +0 -665
  827. package/src/core/FlowRouter.ts +0 -1540
  828. package/src/core/PersistenceManager.ts +0 -446
  829. package/src/core/PromptComposer.ts +0 -448
  830. package/src/core/PromptSectionCache.ts +0 -125
  831. package/src/core/ResponseEngine.ts +0 -338
  832. package/src/core/ResponseGenerationError.ts +0 -53
  833. package/src/core/ResponseModal.ts +0 -1902
  834. package/src/core/ResponsePipeline.ts +0 -1404
  835. package/src/core/SessionFinalizer.ts +0 -108
  836. package/src/core/SessionManager.ts +0 -372
  837. package/src/core/SignalCoordinator.ts +0 -263
  838. package/src/core/SignalEvaluator.ts +0 -404
  839. package/src/core/SignalProcessor.ts +0 -663
  840. package/src/core/Step.ts +0 -782
  841. package/src/core/StepLifecycle.ts +0 -242
  842. package/src/core/StreamingToolExecutor.ts +0 -609
  843. package/src/core/ToolLoopExecutor.ts +0 -749
  844. package/src/core/ToolManager.ts +0 -1379
  845. package/src/core/createAgent.ts +0 -40
  846. package/src/core/flow-namespace.ts +0 -227
  847. package/src/core/toolGates.ts +0 -72
  848. package/src/types/persistence.ts +0 -303
  849. package/src/types/prompt-cache.ts +0 -17
  850. package/src/types/signals.ts +0 -338
  851. package/src/types/template.ts +0 -98
  852. package/src/utils/condition.ts +0 -296
  853. package/src/utils/event.ts +0 -16
  854. package/src/utils/id.ts +0 -91
  855. package/src/utils/serialize.ts +0 -86
  856. package/src/utils/session.ts +0 -501
@@ -0,0 +1,477 @@
1
+ ---
2
+ title: "@falai/agent v4 — one Flow (design v2)"
3
+ description: "Design record for @falai/agent 4.0: flows, automations and signals become one Flow with triggers, runs, waits and per-field asks. Not part of the docs sidebar."
4
+ type: concept
5
+ order: 99
6
+ sidebar: false
7
+ ---
8
+
9
+ > **Design record, approved 2026-09-20.** This is the reference the 4.0 implementation follows.
10
+ > It came out of a read-only research pass over `@falai/agent` 3.4.5 and its three consumers
11
+ > (prospectar, atendime, ilojista), five independent designs, three judges, one synthesis, four
12
+ > adversarial critiques (90 holes) and a repair pass. Section numbers below are cited from the
13
+ > implementation plan and from commit messages as "design §N".
14
+ >
15
+ > **Decided with Gus:** scope is the framework plus all three products; all seven persistence
16
+ > adapters stay, reshaped to `Store` implementations; the host gate (`silenced`) is one mouth and
17
+ > closes `say`, `prompt` and speaking `do` steps alike; routing, mention detection and extraction
18
+ > share one `understand` call, eval-gated on Gemini and GLM before `4.0.0`.
19
+ >
20
+ > **Assumed defaults:** `maxAsks` 3; `repeat: 'once'` per session for `message` flows; zero LLM
21
+ > calls while a human owns the lead unless `silenced: { understand: true }`; lead-only events run
22
+ > in a `lead:<id>` session with `silenced: 'sem conversa'`; END_FLOW / BOT_DETECTED / SCHEDULING
23
+ > ship as `kind: 'system'` recipes; `criar_fluxo` keeps the host's generation call with
24
+ > `flowSpecSchema`; session = conversation with `anchor: 'lead'`; migrated flows get
25
+ > `onEnd: 'stay'` written explicitly.
26
+ >
27
+ > **Refined during implementation (slices 1–2, 2026-09-20):**
28
+ > - The factory is a two-step chain: `falai<C>()` returns a root whose `.fields(defs)` binds the
29
+ > data type, and `flow` / `action` / `event` / `condition` / `agent` hang off that bound object,
30
+ > so `collect`, `ask`, `clearOnStart` and `ctx.set` are checked against the slugs. `f.agent()`
31
+ > passes the fields itself; `type Data = DataOf<typeof f>` replaces `InferData<typeof fields>`.
32
+ > TypeScript cannot infer one generic while another is written by hand, which is why §3's
33
+ > `const fields = f.fields(...)` then `f.agent({ fields })` shape was dropped.
34
+ > - Action, event and condition names inside a flow are plain strings, checked when the agent is
35
+ > built, the same path a JSON `FlowSpec` takes. The mapped-type unions in §3 (`{ [K in keyof
36
+ > A]: ... }[keyof A]`) would have made every flow generic in four parameters.
37
+ > - `Condition` is `{ check(ctx, arg) }` and `Action` is `{ parameters, run(params, ctx) }`, as
38
+ > method signatures: method bivariance lets a heterogeneous map type without `any`.
39
+ > - `Store.save` returns the saved session, with the bumped version, instead of `void`.
40
+ > - A mention trigger's `extract` is a flat map of parameter definitions (`{ trecho: { type:
41
+ > 'string' } }`), the S7 form, not a JSON schema object: one shape for fields, action
42
+ > parameters and extraction, and `toWireSchema` applies to all three.
43
+ > - Tool handlers take `(args, ctx)`, the order every provider SDK uses.
44
+ > - Prompt scaffolding (section headings, envelope instructions, routing rules) is written in
45
+ > English; the authored content it carries (prompts, `ask` texts, instructions, knowledge) and
46
+ > the outcome `detail` strings the host shows in *Execuções* stay in the product's language.
47
+
48
+ # @falai/agent v4 — one Flow (design v2)
49
+
50
+ ## 1. Mental model
51
+
52
+ A **Flow** is a trigger plus an ordered list of steps. The trigger says when a **run** starts: the lead asks for this (`message`: the AI routes the conversation here), the lead mentions this (`mention`: the AI detects it, the run reacts beside the conversation), something happens in the host (`event` with a payload), the lead goes quiet (`silence`), or nothing — the host starts it (*Início manual*). Each step is one of five things: the AI talks (`prompt` / `collect`), a fixed message goes out (`say`), the host does something (`do`), the run waits (`wait`), or the code forks (`if`). Fields live on the agent schema, each with its own *como perguntar*; they land in any order and a step ends when its fields are known. A **session** (one per conversation) holds many runs; at most one run is asking a question at a time. One method, `agent.turn()`, takes whatever just happened, moves the runs by code, spends at most two LLM calls (understand the lead, phrase the reply) plus one per tool round, and hands back the messages to send, the timers to set and a per-step outcome line. The framework never sends, never sleeps, never saves; the host does those three things after a successful compare-and-swap. Product side: one page (*Fluxos*, sections *Funil* / *Atendimento*), one card (*Quando X → faça Y*), one editor, one assistant tool, one drawer (*Execuções*).
53
+
54
+ Child: "A flow is a list of steps that starts when something happens. The AI does the talking. The code does the rest." Junior: "`agent.turn({ message: 'oi' })` returns the messages to send."
55
+
56
+ ## 2. Primitives: stays, merges, dies
57
+
58
+ | Old | Fate |
59
+ |---|---|
60
+ | Agent | Stays; immutable config, one instance serves every session. `_context`, `_pendingData`, `currentSession` die; PromptSectionCache becomes a per-turn instance (its property tests stay). `context` and `history` arrive per turn. |
61
+ | Flow | THE noun; absorbs Signal and CrmAutomation. Gains `on[]`, `anchor`, `while`, `clearOnStart`, `onEnd`. Loses `when`/`if` (→ triggers), `requiredFields`, `optionalFields`, `reentrant`, `onComplete`, `hooks`. |
62
+ | Step `prompt` / `auto` / `reply` | `prompt` stays (AI talks); `reply` → `say`; `auto` → `do`, `if`, `wait`. |
63
+ | `collect` | Stays as step completion: a talk step ends when its fields are known, skipped without a call when already known. `{ collect: [...] }` alone asks with the schema's `ask`. |
64
+ | `requires`, `skip`, `requiredFields`, `optionalFields` | Die. Order, known-field skipping, `if` steps and `maxAsks` cover every use. |
65
+ | `branches` (`when`/`if` mid-step exits) | Stay as `branches[]` on talk and `wait` steps, judged while the step is asking — `if` free, `when` inside the understand call. There is no standalone `when` step: AI forks only exist where fresh text exists. |
66
+ | `onComplete`, `reentrant` | → `onEnd` (`'end' \| 'stay' \| 'reset'`), `repeat` on the trigger, `clearOnStart`. |
67
+ | prepare / finalize / onEnter / onExit | Die → a `do` step at that position. |
68
+ | Directive, `dispatch`, `pendingDirective`, `flow.merge/validate`, five appliers | Die. Every position change goes through one `advance()`. Tools return `{ value?, data? }`. |
69
+ | Signal | → Flow with a `mention` trigger (§7). |
70
+ | CrmAutomation `trigger` | → `on[]`: `stage_entered`/`meeting_booked`/`tag_added`/`known_contact` → `event`; `stage_stagnant` → `event` + `after`; `signal` → `mention`; `conversation_idle` → `silence`; `manual` → no trigger. |
71
+ | CrmAutomation action / wait / wait_reply / condition | → `do` / `wait` / `wait` + `else` / `if`. |
72
+ | CrmAutomation `conditions`, `hopCount` | → trigger `if` as a JSON condition; `hop` rides on events and `then: { flow }`. |
73
+ | 14 actions | Host `do` actions, except `ai_message` → `prompt`, `send_whatsapp_message` → `say`, `start_automation` → `then: { flow }`. |
74
+ | StepIntegrations / flow integrations / step `media` / `initialData` | → `do` steps / `say` with `media` (`once: true` keeps "once per conversation"); `initialData` removed, no replacement. |
75
+ | `endBehavior` | → `onEnd`; *vai para outro fluxo* → `then: { flow }` on the last step. |
76
+ | `ai_message` + composer | → a `prompt` step reached by a wake. Composer deleted. |
77
+ | `haltReply` | → a `say` first in a mention flow: another run's `say` silences the floor's talk that turn. |
78
+ | behavior once/cooldown (two ledgers) | → one `claims` ledger (§5). |
79
+ | PersistenceAdapter ×7, `restoreSession`, `autoSave` | → `Store { load, save(expectedVersion) }`, `SessionConflictError`, `MemoryStore`, one `PostgresStore` reference. |
80
+ | `respondStream` | → `agent.turnStream()`. |
81
+
82
+ Core modules removed: ResponsePipeline, FlowRouter, ResponseModal, Signal*, AutoChainExecutor, StepLifecycle, DirectiveChainTracker, PersistenceManager, five adapters — about half of `src/core`. One `Runner` with one `advance()` plus `Understand.ts`, `Speak.ts`, `Envelope.ts`, `Migrate.ts`.
83
+
84
+ ## 3. Public TypeScript API
85
+
86
+ ```ts
87
+ import { falai, InferData, StructuredSchema, Instruction, tool } from '@falai/agent';
88
+
89
+ type Duration = `${number}${'s' | 'm' | 'h' | 'd'}`;
90
+ type Repeat = 'once' | 'always' | { cooldown: Duration };
91
+ type Template = string; // {{data.x}} {{context.x}} {{input.x}}
92
+ type Next = string | 'end' | { step: string; clear?: string[] } | { flow: Template; input?: unknown };
93
+ type PredCtx<C, D, P = unknown> = { context: C; data: Partial<D>; input: P; run: Run; silenced?: string; now: Date };
94
+ type ConditionSpec<Cond> = { [K in keyof Cond]?: Arg<Cond[K]> }; // JSON form; built-ins: equals, known, silenced
95
+ type Pred<C, D, Cond, P = unknown> = ((ctx: PredCtx<C, D, P>) => boolean) | ConditionSpec<Cond>;
96
+ type Branch<C, D, Cond> = { then: Next } & ({ when: string } | { if: Pred<C, D, Cond> });
97
+
98
+ type Trigger<C, D, Cond, E> = { repeat?: Repeat } & ( // default: message/mention/silence 'once', event 'always'
99
+ | { message: string[]; if?: Pred<C, D, Cond> } // "o cliente pede isso"; [] = catch-all
100
+ | { mention: string[]; extract?: StructuredSchema; if?: Pred<C, D, Cond> } // "o cliente fala disso"; [] + if = code-only
101
+ | { silence: Duration; if?: Pred<C, D, Cond>; businessHours?: boolean }
102
+ | { [K in keyof E]: { event: K; if?: Pred<C, D, Cond, E[K]>; after?: Duration; businessHours?: boolean } }[keyof E]
103
+ );
104
+
105
+ type Talk<C, D, Cond> = ({ prompt: Template; collect?: (keyof D)[] } | { collect: (keyof D)[]; prompt?: Template }) & {
106
+ ask?: Partial<Record<keyof D, string>>; // per-flow wording; schema `ask` is the default
107
+ maxAsks?: number; branches?: Branch<C, D, Cond>[]; tools?: string[]; instructions?: Instruction<C, D>[];
108
+ };
109
+
110
+ type Step<C, D, Cond, A extends ActionMap, E> = { id: string; label?: string; then?: Next; ui?: Record<string, unknown> } & (
111
+ | Talk<C, D, Cond>
112
+ | { say: Template; media?: { slug: string }; once?: boolean }
113
+ | { [K in keyof A]: { do: K; with: Params<A[K]>; onFail?: Next } }[keyof A]
114
+ | { wait: Duration; businessHours?: boolean; else?: Next; branches?: Branch<C, D, Cond>[] } // then = timed out, else = lead replied
115
+ | { [K in keyof E]: { wait: { event: K; upTo?: Duration }; else?: Next } }[keyof E] // then = event came, else = timed out (upTo default 30d)
116
+ | { if: Pred<C, D, Cond>; else?: Next } // then = true, else = false (default 'end')
117
+ );
118
+
119
+ interface Flow<C, D, Cond, A extends ActionMap, E> {
120
+ id: string; name: string; description?: string;
121
+ on?: Trigger<C, D, Cond, E>[]; // absent or [] = Início manual
122
+ anchor?: string; // 'session' (default) or a host anchor name — "vale por conversa / por lead"
123
+ while?: Pred<C, D, Cond>; // re-checked whenever the run moves; default = trigger `if`
124
+ clearOnStart?: (keyof D)[];
125
+ steps: Step<C, D, Cond, A, E>[]; // ids required, unique, never 'end'
126
+ onEnd?: 'end' | 'stay' | 'reset'; // default 'end'
127
+ instructions?: Instruction<C, D>[]; tools?: string[];
128
+ }
129
+
130
+ type ActionResult = { ok: true; detail?: string; spoke?: true } | { skipped: string } | { failed: string } | { defer: Duration; detail: string };
131
+ interface ActionCtx<C, D> { context: C; data: Partial<D>; input: unknown; run: Run; key: string; dedupeKey: string; silenced?: string; now: Date; set(patch: Partial<D>): void }
132
+ type ToolResult<D> = { value?: unknown; data?: Partial<D> };
133
+ ```
134
+
135
+ One factory carries the only explicit generic an app writes; everything else is inferred from values.
136
+
137
+ ```ts
138
+ interface LeadContext { lead: { id: string; name?: string; tags: string[]; stageId: string; assignee?: string; owner: 'ai' | 'human' }; phone: string }
139
+ const f = falai<LeadContext>(); // falai() with no context; createAgent = falai().agent
140
+
141
+ const fields = f.fields({
142
+ nome: { type: 'string', ask: 'Pergunte o nome de um jeito leve, sem tom de formulário.' },
143
+ empresa: { type: 'string', ask: 'Pergunte de qual empresa a pessoa fala.' },
144
+ tamanho: { type: 'string', enum: ['1-10', '11-50', '51-200', '200+'], ask: 'Pergunte quantas pessoas trabalham lá; ofereça as faixas.' },
145
+ urgencia: { type: 'string', enum: ['agora', '30 dias', 'sem prazo'], ask: 'Pergunte para quando precisam resolver.' },
146
+ orcamento: { type: 'number', ask: 'Pergunte a faixa de investimento, dizendo que é só para orientar.' },
147
+ confirmado:{ type: 'boolean', ask: 'Resuma em uma frase o que anotou e pergunte se está tudo certo.' }, // boolean → extract: 'asked' by default
148
+ });
149
+ type Data = InferData<typeof fields>;
150
+
151
+ const actions = {
152
+ notify: f.action({ parameters: { recipient: { type: 'string' }, message: { type: 'string' } },
153
+ run: async (w, ctx) => { await notifications.send(ctx.context.lead, w.recipient, w.message, { key: ctx.key }); return { ok: true, detail: 'aviso enviado' }; } }),
154
+ add_tags: f.action({ parameters: { tags: { type: 'array', items: { type: 'string' } } },
155
+ run: async (w, ctx) => { await crm.addTags(ctx.context.lead.id, w.tags); return { ok: true }; } }),
156
+ assign_lead: f.action({ parameters: { to: { type: 'string' } },
157
+ run: async (w, ctx) => (await ownership.assign(ctx.context.lead.id, w.to)) ? { ok: true } : { skipped: 'lead já está com uma pessoa' } }),
158
+ send_template: f.action({ parameters: { templateId: { type: 'string' } },
159
+ run: async (w, ctx) => { const r = await meta.sendPaid(ctx.context.phone, w.templateId, { idempotencyKey: ctx.key });
160
+ return r.noCredits ? { defer: '24h', detail: 'sem créditos' } : { ok: true, spoke: true }; } }),
161
+ book: f.action({ parameters: { date: { type: 'string' }, time: { type: 'string' } },
162
+ run: async (w, ctx) => { const ev = await agenda.create(w, { idempotencyKey: ctx.key }); ctx.set({ agenda_event_id: ev.id }); return { ok: true }; } }),
163
+ };
164
+ const events = {
165
+ stage_entered: f.event<{ stageId: string }>(),
166
+ meeting_booked: f.event<{ eventId: string }>(),
167
+ ig_comment: f.event<{ postId: string; text: string }>(),
168
+ reaction: f.event<{ emoji: string }>({ direction: 'inbound' }), // resolves reply waits, stamps lastUserAt
169
+ human_message: f.event<{ text: string }>({ direction: 'outbound' }), // stamps lastAssistantAt, re-arms silence
170
+ };
171
+ const conditions = { // plus built-ins equals / known / silenced
172
+ tagsAny: f.condition((ctx, tags: string[]) => tags.some(t => ctx.context.lead.tags.includes(t))),
173
+ inStage: f.condition((ctx, stageId: string) => ctx.context.lead.stageId === stageId),
174
+ channel: f.condition((ctx, kind: 'assistant' | 'campaign') => ctx.context.channel === kind),
175
+ };
176
+ ```
177
+
178
+ **S1 — Triagem, complete.** The confirmation is a collected boolean; a "no" clears it and re-asks; `avisa` runs only after the lead's ok.
179
+
180
+ ```ts
181
+ const triagem = f.flow({
182
+ id: 'triagem', name: 'Triagem', description: 'Quando alguém chega querendo saber se o produto serve para a empresa dele',
183
+ on: [{ message: ['quer saber como funciona', 'pede um orçamento', 'quer saber se serve para a empresa'] }],
184
+ steps: [
185
+ { id: 'quem', prompt: 'Descubra quem é e de onde fala.', collect: ['nome', 'empresa'] },
186
+ { id: 'porte', collect: ['tamanho', 'urgencia'] },
187
+ { id: 'grana', collect: ['orcamento'], maxAsks: 2 },
188
+ { id: 'confirma', collect: ['confirmado'] },
189
+ { id: 'ok', if: { equals: { confirmado: true } }, else: { step: 'quem', clear: ['confirmado'] } },
190
+ { id: 'avisa', do: 'notify', with: { recipient: 'leadAssignee', message: 'Lead qualificado: {{data.nome}} ({{data.empresa}}), {{data.tamanho}} pessoas, {{data.urgencia}}.' } },
191
+ { id: 'tchau', prompt: 'Agradeça e diga que um vendedor continua daqui.' },
192
+ ],
193
+ });
194
+ ```
195
+
196
+ **S2 — Retomar quem sumiu, complete.** Started by the silence timer the framework arms after it speaks; any reply ends the run; while a human owns the lead the seller gets a reminder instead.
197
+
198
+ ```ts
199
+ const retomar = f.flow({
200
+ id: 'retomar', name: 'Retomar quem sumiu',
201
+ on: [{ silence: '24h', businessHours: true, if: ({ context }) => context.lead.owner === 'ai' }],
202
+ anchor: 'lead',
203
+ steps: [
204
+ { id: 'gate', if: { silenced: true }, then: 'lembra', else: 'p1' },
205
+ { id: 'p1', prompt: 'Retome a conversa de forma leve: relembre o assunto em aberto e pergunte se ainda faz sentido.' },
206
+ { id: 'w1', wait: '2d', else: 'end' },
207
+ { id: 'p2', prompt: 'Última tentativa, curta e sem pressão: fica à disposição quando quiser retomar.' },
208
+ { id: 'w2', wait: '3d', else: 'end' },
209
+ { id: 'n1', do: 'notify', with: { recipient: 'leadAssignee', message: '{{data.nome}} não respondeu a duas retomadas — vale um contato manual.' }, then: 'end' },
210
+ { id: 'lembra', do: 'notify', with: { recipient: 'leadAssignee', message: 'Hora de fazer follow-up com {{data.nome}}.' } },
211
+ ],
212
+ });
213
+
214
+ const agent = f.agent({
215
+ name: 'Ana', provider, fields, actions, events, conditions, tools: [checkAvailability],
216
+ flows: [triagem, retomar],
217
+ idle: { prompt: 'Responda pela empresa; não invente preços.' }, // the one speaker that is not a step; 'silent' mutes it
218
+ clock: () => new Date(), // tests pass fakeClock
219
+ businessHours: (at, ctx) => nextWorkingTime(at, ctx.context.lead), // snaps, never clamps
220
+ });
221
+ ```
222
+
223
+ Entry points and result:
224
+
225
+ ```ts
226
+ type TurnInput<C, D, E> = {
227
+ sessionId: string; session?: Session<D>; // absent = first turn; a wake never creates a session
228
+ context?: C; history?: History; // hosts pass history on EVERY input kind, wakes included
229
+ silenced?: string | { reason: string; understand?: boolean }; // host gate; default zero calls, understand: true opts in
230
+ anchors?: Record<string, { key: string; lastInboundAt?: string }>; // { lead: { key: 'lead:456', lastInboundAt } }
231
+ claims?: { held: Record<string, string>; active: string[] }; // dedupeKey → at; `${flowId}:${anchor}` live in other sessions
232
+ } & (
233
+ | { message: string; id?: string; at?: string } // hosts pass channel id + receipt time; the playground may omit
234
+ | { wake: string }
235
+ | { [K in keyof E]: { event: K; payload: E[K]; key: string; hop?: number } }[keyof E]
236
+ | { start: { flow: string; input?: unknown; key: string; hop?: number } }
237
+ );
238
+
239
+ interface TurnResult<D> {
240
+ session: Session<D>; changed: boolean; // changed: false → save nothing
241
+ messages: Array<{ text: string; kind: 'ai' | 'verbatim'; media?: { slug: string }; afterMs: number; key: string; runId?: string; stepId?: string }>;
242
+ schedule: Array<{ key: string; at: Date; replaces?: string }>; // jobId = key; at fire: turn({ wake: key })
243
+ outcomes: StepOutcome[];
244
+ started: Array<{ runId: string; flowId: string; anchor: string; dedupeKey: string }>;
245
+ ended: Array<Run & { reason: 'end' | 'flow' | 'reset' | 'skipped' | 'failed' | 'replaced' }>;
246
+ skipped: Array<{ flowId: string; anchor: string; triggerKey: string; detail: string }>; // trigger-level, for Execuções
247
+ llmCalls: number;
248
+ }
249
+ declare function turnStream(input: TurnInput): AsyncIterable<{ delta: string } | { done: true; result: TurnResult }>;
250
+
251
+ const r = await agent.turn({ sessionId: 'demo', message: 'oi' }); // README: one call, one obvious result
252
+ console.log(r.messages[0].text);
253
+ ```
254
+
255
+ Stored flows load as `FlowSpec`: the same object as JSON with a **flat step** `{ id, kind: 'prompt' | 'collect' | 'say' | 'do' | 'wait' | 'waitEvent' | 'if', ...props, then?, else? }`, `do` names, condition names and field slugs resolved through the agent's registries. `validateFlow(spec, agent)` throws `FlowConfigurationError` naming the unknown field, action, event, condition or step id, the reserved id `end`, a missing `else` on a backward `if`, and warns on a backward edge without `clear`. `flowSpecSchema(agent)` returns FlowSpec's JSON schema with the workspace's actions (with their parameter schemas), events, conditions and fields enumerated — a closed schema Gemini accepts; it is the response schema of the host's generation call.
256
+
257
+ ## 4. The turn pipeline
258
+
259
+ Eight phases, one order for every input; only 3 and 6 spend LLM calls. `turn()` does no I/O but the provider and the host's action handlers.
260
+
261
+ 1. **Load** (code). Migrate a legacy blob (§10). `wake` with no session → `ignorado: sessão inexistente`, `changed: false`.
262
+ 2. **Ingest** (code).
263
+ - `message` / inbound `event`: `lastUserAt = at ?? clock()`; a keyed `id` already in `session.inputs` → no-op, `changed: false`. Every run parked on a timer `wait` with `else` takes `else` (oldest first); a `wait: { event }` on this event takes `then`.
264
+ - Outbound `event`: stamps `lastAssistantAt`, nothing else.
265
+ - `wake` starting with `silence:`: honored only when its `lastAssistantAtMs` equals `session.lastAssistantAt` and the lead has not written since (`lastUserAt`, and the anchor's `lastInboundAt` for lead-anchored flows, both `< lastAssistantAt`); it then goes through the start order below with `trigger.kind: 'silence'`. Otherwise `ignorado: silêncio quebrado`, `changed: false`. Any other `wake`: the run whose `waiting.key` equals it, else `ignorado: wake antigo`. A timer `wait` with `else` whose lead wrote after `waiting.setAt` takes `else` — the reply beat the job.
266
+ - `event` / `start`: flows with a matching trigger start, in this order: `if` (payload as `input`) → `repeat` via claims (cooldown = interval check on `claims[key].at`) → `hop < 5` else `pulado: limite de encadeamento` → one active run per (flow, anchor) against `session.runs` and `claims.active`: a live run still parked on its own `after` timer is **replaced** (`ended.reason: 'replaced'`, its job self-skips), any other live run → `pulado: já em andamento` → `after` parks the new run.
267
+ - Every run about to move re-checks `while` with fresh context; false → ends `pulado: premissa mudou`. Silence-triggered runs add the premise "no lead message since the run started" → `pulado: lead escreveu nesse meio-tempo`.
268
+ 3. **Understand** (≤1 call, `schemaName: 'understand'`). Only for `message` and inbound events with text; skipped under `silenced` unless `understand: true`, and when nothing is AI-conditioned. Candidates: the floor holder's flow (always, whatever its trigger), `message` flows passing `if` + `repeat`, `mention` flows with non-empty `mention` passing `if` + `repeat`. Envelope, every property required and nullable: `{ flows: { id: 0-100 }, mentions: { id: boolean }, extract: { id: {...} }, branches: { 'runId/stepId/i': boolean }, fields: { every pending field with extract 'anywhere' } }`. Shortcuts: exactly one eligible `message` flow and no floor → it starts, no scoring; zero candidates and zero pending fields → zero calls (S9).
269
+ 4. **Decide** (code). Runs starting this turn apply `clearOnStart` first. Extracted values are checked: unknown keys dropped (`ignorado: campo desconhecido`), strings coerced to number/boolean, enum membership enforced, otherwise `campo descartado: valor fora da lista`; then written to `session.data` (one `known`: not `undefined | null | ''`). Mention runs start in flow order (a trigger `if` with `extract` sees `input` now); `mention: []` code-only detectors start here without the call. The first true branch of the asking step takes its `then`. Routing: if a run took or resumed the floor in Ingest, routing is skipped (scores recorded, not applied). Otherwise the floor (any run `running`/`asking`, not `waiting`) stays unless another flow scores ≥ current + 15 and ≥ 40; no floor → best ≥ 40 starts (a `suspended` run of that flow resumes instead), then a `message: []` catch-all, else the `idle` speaker.
270
+ 5. **Run** (code). If no run is `asking`, the most recently `suspended` returns to `asking`. The Runner advances every run that can move, oldest first, through `advance()`: `do` runs the handler with `key = ${runId}:${stepId}:${visit}` (`run.visits[stepId]` increments on entry; at-least-once, before the save); `failed` writes a `failed` outcome and continues to `then` unless `onFail`; `skipped` continues; `defer` re-parks under a fresh wake key; `spoke: true` makes it the turn's speaker. `say` appends a message (`once` → claim `${flowId}:${stepId}:${sessionId}`). `wait ≤ 10s` carries as `afterMs` to the next message emitted this turn, or schedules a real wake if none follows; longer waits park with `waiting` and a `schedule` entry, snapped by `businessHours`. `if` picks `then`/`else`. A talk step whose fields are all known is skipped (0 calls); otherwise it is queued for phase 6 and the current asker becomes `suspended` (a run started this turn by routing never suspends one that took the floor in Ingest). Flow missing from the agent → `pulado: fluxo desativado ou removido`; step missing → `pulado: passo removido`. Caps: 50 steps per run per turn → `falhou: laço de passos`; hop 5.
271
+ 6. **Speak** (≤1 call + tool rounds, `schemaName: 'speak'`). One talk step speaks. Talk step = `prompt`, `collect`, `say`. Rules: a `say` or `spoke: true` emitted this turn by a run **other than** the floor holder, in reply to a user message, silences the floor's talk (`pulado: outra resposta já saiu`; the run stays `asking`) — a run's own `say` never silences its own talk. Under `silenced` no message-producing step runs and no run advances past one: an `asking` run stays `asking`; a run whose talk step was reached by a wake, event or start ends `silenciado: <reason>` (an earlier `if: { silenced: true }` routes around it); `do` steps still run; zero calls. Prompt = identity + flow + step guideline + this step's pending fields with their `ask` (all of them; the step prompt says how many to ask) + known fields as facts + tools + instructions + history. A wake states *não há mensagem nova do cliente; você fala primeiro*. Envelope `{ message, ...pending fields of this step }`, all required and nullable, shallow-merged last-wins across tool rounds. Provider failure: in phase 3 the turn throws `ProviderError` (nothing ran, nothing saved; the host retries the input); in phase 6 the turn returns with the talk step re-parked under `${runId}:${stepId}:${visit}:retry:${atMs}` (+1m, +5m, +15m), outcome `deferred: IA indisponível`, session saved, phase 5 effects not repeated.
272
+ 7. **Settle** (code, the ONE applier). A collect step stays `asking` until its fields are known, a branch fires, or a field hits `maxAsks` (default 3 → `campo pulado: perguntado 3 vezes`); `asked[field]` increments when the step spoke with the field pending and the next lead message left it unknown — detours count, the ceiling is documented. A prompt without `collect` advances after speaking once. `then`: step (visits++), `{ step, clear }` (clears, then jumps), `'end'` → `onEnd`, `{ flow }` (template resolved against `input`/`context`; this run ends `reason: 'flow'`, the new run has `trigger.kind: 'flow'`, key `${parentRunId}:${stepId}:${visit}`, hop+1, and holds the floor). When no run is `asking`, the most recently suspended resumes. If the assistant spoke last, every `silence` flow passing `if` and `repeat` gets `schedule: { key: silence:${flowId}:${sessionId}:${lastAssistantAtMs}, at, replaces: <previous key> }`.
273
+ 8. **Return**: `session` (version unchanged; the host bumps it), `changed`, `messages` in emission order, `schedule`, `outcomes`, `started`, `ended`, `skipped`, `llmCalls`.
274
+
275
+ Budget: message turn 2 calls + tool rounds (1 with a single flow and no pending fields, 0 when silenced); wake to a talk step 1; wake to `do`/`wait` 0. `llmCalls` on every result makes it a test, not a promise.
276
+
277
+ ## 5. Waiting, timers, events
278
+
279
+ ```ts
280
+ interface Run {
281
+ id: string; // `${flowId}#${triggerKey}` — deterministic, replay mints the same keys
282
+ flowId: string; anchor: string; dedupeKey: string; stepId: string | null;
283
+ status: 'running' | 'asking' | 'waiting' | 'suspended';
284
+ trigger: { kind: 'message' | 'mention' | 'silence' | 'event' | 'start' | 'flow'; key: string; payload?: unknown };
285
+ input?: unknown; hop: number; startedAt: string;
286
+ waiting?: { kind: 'timer' | 'event'; key?: string; until?: string; setAt: string; event?: string };
287
+ asked: Record<string, number>; visits: Record<string, number>;
288
+ outcomes: StepOutcome[];
289
+ }
290
+ interface StepOutcome { runId?: string; flowId?: string; stepId?: string; key?: string;
291
+ kind: 'prompt' | 'collect' | 'say' | 'do' | 'wait' | 'if' | 'idle'; status: 'ok' | 'skipped' | 'failed' | 'waiting' | 'deferred';
292
+ detail?: string; next?: string; until?: string; at: string; llmCalls?: number }
293
+
294
+ interface Store<D> { load(id: string): Promise<Session<D> | null>; save(session: Session<D>, expectedVersion: number): Promise<void> } // 0 = insert-if-absent; throws SessionConflictError
295
+ ```
296
+
297
+ **Invariants** (docs verbatim):
298
+
299
+ - I1. The session blob is the unit of consistency: `load(v) → turn → save(expectedVersion = v)`. A losing turn is discarded and the same input replayed.
300
+ - I2. Messages, schedules, claims and ended runs leave the host's hands only after a successful save. `do` handlers are the exception: they run inside the turn, **at-least-once**, and must be idempotent on `ctx.key` (or `ctx.dedupeKey` for `once`/cooldown flows shared across a lead's sessions). `always` flows cannot be made exactly-once across sessions by the framework.
301
+ - I3. A run wake is honored only by the run whose `waiting.key` equals it; a silence wake only when the blob still shows that silence. Everything else is `ignorado`, `changed: false`. Nothing is ever cancelled; `replaces` is a best-effort hint.
302
+ - I4. Every `do` and message carries `key = ${runId}:${stepId}:${visit}`; run ids come from host keys (message `id`, event/start `key`, wake key, parent run), so a replay of the same input mints the same keys and a revisit mints new ones.
303
+ - I5. A run's claim is written in the same save as its first step; a run never exists without its claim.
304
+
305
+ **Keys.** Trigger key: `message`/`mention` → the input `id` (playground: `at`, replays not idempotent); `silence` → `lastAssistantAtMs`; `event`/`start` → the host key; `flow` → `${parentRunId}:${stepId}:${visit}`. Wake key: `${runId}:${stepId}:${atMs}`. Dedupe key `${flowId}:${anchor}:${nonce}`, nonce `''` for `once` and cooldown (blocked while `now - claims[key].at < cooldown`, else overwritten), the trigger key for `always` (last 50 kept).
306
+
307
+ **Host contract:** (a) one `turn` per session at a time; a wake queues behind a debounced inbound not yet turned. (b) On every input: fresh `context`, `history`, `anchors` (with the lead's `lastInboundAt`), `claims` for non-`always` flows, `silenced` for every "cannot speak now" reason (ownership, Pausa, closed 24h window, quota, `sem conversa`); inbound messages carry the channel `id` and `at`. (c) `changed: false` → nothing. Else one transaction: `store.save`, `started[].dedupeKey` into a unique index, `started`/`ended` into a partial unique index `(flowId, anchor) WHERE live`, `outcomes`/`ended`/`skipped` into the `flowRuns` mirror, `messages[]` and `schedule[]` into the outbox. Conflict or unique violation → discard, replay. (d) Drain the outbox: send honoring `afterMs`, record a refused send against `key` in the mirror (`enviada`/`recusada` beside the framework's `gerada`); enqueue wakes with `jobId = key`, `queue.remove(replaces)` best-effort. (e) At fire: `turn({ wake, silenced })`. (f) Call `turn` for every inbound even while a human owns the lead. (g) `businessHours(at)` snaps, never clamps. (h) Lead-level events go to the lead's latest open conversation; none → session `lead:<id>` with `silenced: 'sem conversa'`. (i) `ProviderError` → retry the input with backoff.
308
+
309
+ ```ts
310
+ const clock = fakeClock('2026-09-20T10:00Z');
311
+ const agent = f.agent({ provider: mockProvider({ understand: [...], speak: [...] }), clock, fields, actions: stubs, flows: [triagem, retomar] });
312
+ let r = await agent.turn({ sessionId: 's1', message: 'oi', id: 'm1' });
313
+ clock.advance('24h');
314
+ r = await agent.turn({ sessionId: 's1', session: r.session, wake: r.schedule[0].key, history });
315
+ assert.equal(r.messages[0].kind, 'ai'); assert.equal(r.llmCalls, 1); assert.equal(r.started[0].flowId, 'retomar');
316
+ ```
317
+
318
+ ## 6. Field collection
319
+
320
+ `pending(step) = step.collect in order, minus known fields, minus fields at maxAsks`, computed by code; the model sees every pending field of the current step with its `ask` (step `ask` overrides the schema's). Fields are authored once: `{ type, enum?, description?, ask, extract?: 'anywhere' | 'asked' }`. `'anywhere'` (default for strings and numbers) is harvested by the understand call from any text; `'asked'` (default for booleans) only by the speak envelope of the step that lists it, so a stray "sim" never opens a code gate. `toWireSchema()` allow-lists JSON-schema keys and strips `ask`/`extract`. In the UI a field row is `{ slug, rótulo, tipo, como perguntar }`; `buildSchema(flows)` merges rows by slug and fails when two flows give one slug two types; suffix-based inference dies.
321
+
322
+ Out of order is the default. A collect step skips when its fields are known and stays `asking` until they are; a `prompt` without `collect` speaks once. Confirmation is a collected boolean behind an `if`; a correction clears it (`{ step, clear }`) and re-asks. `maxAsks` (default 3, loud in Execuções) replaces the `requires` deadlock; `maxAsks: 1` is "ask once, don't insist". `clearOnStart` (applied before this turn's extraction) replaces `reentrant`.
323
+
324
+ ## 7. Signals → triggers
325
+
326
+ | Signal facet | v4 |
327
+ |---|---|
328
+ | `when[]` incl. `!` exclusions | `mention: [...]`, judged in the understand call |
329
+ | `if` | trigger `if`, free; with `extract` set it also sees `input` after the call; `mention: []` + `if` = code-only detector, no call |
330
+ | `extract` | trigger `extract` → `run.input`, `{{input.x}}`, never `data` |
331
+ | `phase: 'pre'` + `halt` + `reply` | first step `say` (or a `do` returning `spoke: true`); another run's say silences the floor that turn |
332
+ | `phase: 'post'` | dies; `do`-only mention flows run beside the reply, same turn |
333
+ | `behavior` once/always/cooldown | `repeat` → claim, one ledger, interval cooldown |
334
+ | `priority` | dies; flow order |
335
+ | `stopOtherSignals` | dies; one speaker per turn |
336
+ | handler side effects | `do` steps |
337
+
338
+ ## 8. Concurrency and anchors
339
+
340
+ Session = conversation. Runs inside a session are concurrent; the floor is single: at most one run is `asking`; a talk step from another run pushes it onto a LIFO stack of `suspended` runs, and whenever nobody is asking the most recently suspended resumes. Order inside a turn: reply-branch resolutions → mention runs → floor talk; `messages[]` in that order.
341
+
342
+ Anchors are host keys per call; a flow names one or defaults to the session. Inside the session the framework dedupes; across a lead's sessions the host passes `claims.held` (nonce rule) and `claims.active` (live `${flowId}:${anchor}` pairs from its mirror) and writes both indexes in the save transaction. A lead-less campaign thread falls back to the session anchor.
343
+
344
+ S10 with versions. R1 (triagem) `asking`; R2 (retomar) `waiting` on W1. W1 fires: load v7 → premise holds → `p1` speaks (1 call) → `w1` parks, `schedule(W2)` → save v7→v8. The lead's text (id m9, at 10:00:02) lands concurrently: load v7 → save fails → replay on v8 → `w1.else` ends R2 (W2 fires stale later) → R1, still the floor, extracts and asks (2 calls) → save v8→v9. Wire: nudge, question. Had the text arrived first (or been debounced, per (a)), the wake finds `lastUserAt > setAt` → `w1.else` → no nudge.
345
+
346
+ ## 9. Flow end
347
+
348
+ A run ends when `then` reaches `'end'` or the last step completes; `onEnd`: `'end'` (default; `ended[]` carries it, session idle), `'stay'` (*repete o último passo*), `'reset'` (first step, data kept). *Vai para outro fluxo* is `then: { flow }` on the last step. The framework never speaks at the boundary. A `message` flow is `repeat: 'once'` per session by default; S8 sets `'always'` + `clearOnStart`.
349
+
350
+ ## 10. Persistence
351
+
352
+ ```ts
353
+ interface Session<D> {
354
+ id: string; v: 4; version: number;
355
+ data: Partial<D>; runs: Run[]; // live runs only
356
+ claims: Record<string, { at: string }>; // once/cooldown: one key per flow; always: last 50
357
+ inputs: string[]; // last 50 keyed input ids
358
+ lastUserAt?: string; lastAssistantAt?: string;
359
+ history?: History; // playground only
360
+ metadata: Record<string, unknown>;
361
+ }
362
+ ```
363
+
364
+ `migrateSession(blob, { flowIdOf })` runs at each app's choke point (`deserializeFalaiSessionState`): no `v` → `data` verbatim; `currentFlow/currentStep` → one run `{ id: '${flowId}#legacy', stepId, status: 'asking', trigger: { kind: 'message', key: 'legacy' }, visits: {} }`; `signals.triggers[key]` and `flowHistory[].completed` → `claims['${flowIdOf(key)}:${sessionId}:']`; `pendingDirective` dropped. `migrateFlows` gives signal-triggered flows `id = trigger.signal` so `flowIdOf` is identity for ilojista's 315 live once-signals — a real ilojista blob is a test fixture. Talk-step ids survive, so 844 + 315 cursors keep position; split-out steps get `${stepId}:media` / `${stepId}:integration`.
365
+
366
+ ## 11. Consumer migration
367
+
368
+ **One stored object.** Table `flows` (replaces `workspace.agent.flows` and `crmAutomationRules`): `id, workspaceId, name, kind ('user' | 'system'), enabled, position, section (derived), stageId?, spec JSONB`. `migrateFlows.ts`: AgentFlow → `on: [{ message: when, if: { channel } }]` from `contexts`; steps → `prompt`+`collect` (media → preceding `say` with `once`, integrations → following `do`, branches → `branches[]` on the step); `onEnd: endBehavior ?? 'stay'` (special flows `'end'`), `redirect` → `then: { flow }`; `{{lead_nome}}`-style variables rewritten to `{{context.lead.name}}` from a table; canvas positions → `ui`. CrmAutomation → `on` per §2, steps 1:1, `conditions` → trigger `if`, `haltReply` → first `say`. `defaultFlows(workspace)` (interesse, pediu_humano, known_contact → Triagem, meeting_booked → rodízio, agenda, bot_detected, conversation_ended) seeds `kind: 'system'` rows where `seedDefaultAutomationRules` runs today. The worker builds `f.agent({ flows: rows.map(r => r.spec) })` once per workspace config version.
369
+
370
+ **One editor.** *Fluxos*: *Título*, *Descrição*, *Quando ativar* (*o cliente pede isso* · *o cliente fala disso* · *acontece algo* · *silêncio do cliente* · *início manual*), *Só se*, *Vale por: conversa / lead*, *Repetição*, *Continuar só enquanto*, *Campos* with *Como perguntar*, *Ao recomeçar, esquecer*, *Ao terminar*, *Regras só deste fluxo*. Canvas *+ Adicionar passo*: *Mensagem & IA* (Enviar mensagem = `say`, IA escreve a próxima mensagem = `prompt`, Perguntar = `collect` with *Insistir até N vezes* and *Ramificação (a IA decide)* edges, Enviar modelo aprovado = `do send_template`), *Esperar* (`wait`, edges *Sem resposta* / *Respondeu*), *CRM* (`do` …, Condição = `if`, edges *Sim* / *Não*), *Equipe & integrações* (`do` …, Iniciar outro fluxo = `then: { flow }` edge). *Execuções* reads `flowRuns`: row upserted from `started[]`, status = last outcome (`Parcial` when a failed/skipped sits beside an ok), `aguardando até` from `until`, *Seguiu "Respondeu"* from `next`, trigger skips from `skipped[]`.
371
+
372
+ **One assistant tool.** `criar_fluxo({ descricao })` runs the host's generation call with `flowSpecSchema(agent)` as response schema, then `validateFlow`, then saves; `ajustar_fluxo`, `ver_fluxos`. `criar_automacao` and siblings die.
373
+
374
+ **Per app (prospectar paths; siblings identical):**
375
+
376
+ | Delete | Move | Rewrite |
377
+ |---|---|---|
378
+ | `apps/worker/src/services/crm-automation.service.ts` (1,548), `automation-message-composer.service.ts`, `conversation-idle-sweep.service.ts`, `integration.service.ts`, `utils/integration-behavior.utils.ts`, `utils/follow-up-time.utils.ts`; `apps/api/src/services/crm-automation.service.ts`, `assistant-tools/automation.tools.ts`, `backfill-scheduling-flow.ts`; `packages/server/.../scheduling-flow.utils.ts`, `signals.builder.ts`, `modules/crm/signal-rule.mapper.ts`; `contracts/.../automation.types.ts`; AgentFlow/Step/StepIntegrations/FlowEndBehavior in `agent-core.types.ts`; `apps/web/src/components/Automation/**` (4,127) | From `flow.utils.ts`: `buildStructuredKnowledgeBase` → `knowledge.utils.ts`, `buildFalaiInstructions` → `instructions.builder.ts`; the rest of the file dies. `schema.utils.ts` → 30-line `buildSchema`. `automationLabels.ts`/`automationRecipes.ts` → `flowLabels.ts`/`flowRecipes.ts`. DEFAULT_SIGNALS → `defaultFlows.ts` | `falai-agent.factory.ts` (one agent per config version, no per-turn rebuild, `buildNativeSignals`/`createStepMediaHook` gone); `ai.service.ts` (`detectFlowEndThisTurn`, `reconcilePersistedSignalState`, `pinCampaignEntryFlows` gone; `runTurn` from §12); `apps/web/src/components/Agent/**` (5,169) merged with the automation canvas into one editor (~9.3k lines of UI touched); api call sites `overview.tool.ts`, `campaign.service.ts` (followUp → `flowId`), `playground.service.ts` (`immediateAutomationActions`, `buildSignalAiEffects` → FlowSpec walkers), `agent-entity.service.ts`, `onboarding-activation.service.ts`, `automation-rule.repository.ts` → `flow.repository.ts`; `StartAutomationDialog`/`SidePanel` graph walkers ported to FlowSpec |
379
+
380
+ New host code (~1k lines): `actions.ts` (11 handlers), `wake.worker.ts`, event publishers, `migrateFlows.ts`, `defaultFlows.ts`, the transactional save. Stays host-side: the gate (→ `silenced`), channels, CRM writes inside actions, BullMQ, history building, the `flowRuns` mirror, the Instagram comment matcher.
381
+
382
+ **Framework side.** Tests: about 50 of 76 files exercise routing, directives, signals, completion, adapters or the `respond()` shape and are deleted or rewritten; ~25 kept (providers, envelope salvage, streaming decoder, tool loop, templates, history, schema, prompt-section-cache); new: `understand`, `runner`, `wakes` (fakeClock + MemoryScheduler), `events`, `session-v4` + legacy fixtures (prospectar and ilojista blobs), one file per scenario. `mockProvider({ understand, speak })` holds FIFO queues per schema name (last entry repeats) and records `.calls`. Docs rewritten in place; `docs/migration/v3-to-v4.md` with a Removed | Replacement table and the blob recipe.
383
+
384
+ ## 12. Scenarios
385
+
386
+ **S1 Triage.** "oi, quero saber como funciona" (id m1) → understand scores `triagem` (1 call) → `quem` asks (1 call). "João, da Acme, somos 30" → nome, empresa, tamanho land → `quem` complete, `porte` asks only urgência. "pra ontem, quanto custa?" → urgência lands; triagem is the floor and scored; `grana` answers price from the KB and asks orçamento. Two evasions → `maxAsks: 2` → `campo pulado`. `confirma` asks; "não, somos 50" → `confirmado: false`, tamanho updated → `ok` false → `clear: ['confirmado']`, `quem`/`porte`/`grana` skip, `confirma` re-asks. "sim" → `avisa` (key `…:avisa:1`) → `tchau` → `'end'`; "obrigado" gets the `idle` reply. 2 calls per turn.
387
+
388
+ **S2 Cadence.** Assistant speaks at T → `schedule(silence:retomar:s1:T)`. Wake: premise holds → run starts (claim now) → `gate` false → `p1` speaks first (1 call) → `w1` parks. Any reply on either channel → `w1.else` → end (the anchor's `lastInboundAt` covers the other channel at the next wake). Timeout → `p2` → `w2` → `n1` (0 calls). Human owns → `gate` true → `lembra` notifies the seller, run ends.
389
+
390
+ **S3 No-show.** `turn({ event: 'stage_entered', payload: { stageId }, key: 'stage:456:T' })` → `if: { inStage: 'nao-compareceu' }, after: '1h'` parks; a re-entry replaces it. Wake → `while` holds → `prompt` + `collect: ['data_preferida', 'horario_preferido']` with agenda tools speaks first (the lead having written at T+20m does not stop it: the premise is the stage), suspends triage, collects → `do book` → host emits `meeting_booked` → *Reunião marcada* notifies. Triage resumes when no-show stops asking.
391
+
392
+ **S4 Pediu humano.** `on: [{ mention: ['quer falar com uma pessoa'], repeat: { cooldown: '1h' } }]`, steps `say 'Já chamo alguém'` → `do assign_lead` → end. The say silences triage's talk that turn; triage stays `asking`. While a human owns, `silenced` turns cost 0 calls. Handback needs no event: the next message finds triage at the same step. A second request an hour later starts a fresh run.
393
+
394
+ **S5 Campaign.** `turn({ start: { flow: 'campanha', input: { campaignId, templateId, flowId }, key } })` → `do send_template` (`spoke: true`, `defer` on no credits) → `wait '1d', else: { flow: '{{input.flowId}}' }` → timeout → `prompt` nudge → `wait '2d', else: { flow: '{{input.flowId}}' }` → end. A reply enters the campaign's own funnel, which holds the floor: routing that turn is skipped. 0 calls until the nudge.
395
+
396
+ **S6 Instagram.** `ig_comment` on the IG session → `say` DM → `wait '1d', else: 'qualifica'` → `prompt` → `then: { flow: 'agendar' }`. `anchor: 'lead'` + `claims.active` stop a second run on WhatsApp.
397
+
398
+ **S7 Rule from chat.** Same FlowSpec, same table, same card; fires inside the understand call, no talk step, runs beside the reply, once per conversation.
399
+
400
+ ```json
401
+ { "id": "concorrente", "name": "Lead falou de concorrente",
402
+ "on": [{ "mention": ["o lead cita ou compara com um concorrente"], "extract": { "trecho": { "type": "string" } }, "repeat": "once" }],
403
+ "steps": [
404
+ { "id": "tag", "kind": "do", "do": "add_tags", "with": { "tags": ["concorrente"] } },
405
+ { "id": "avisa", "kind": "do", "do": "notify", "with": { "recipient": "owner", "message": "{{data.nome}} falou de concorrente: \"{{input.trecho}}\"" } }
406
+ ] }
407
+ ```
408
+
409
+ ```ts
410
+ const criarFluxo = tool({
411
+ id: 'criar_fluxo', description: 'Cria um fluxo a partir do que o dono pediu no chat',
412
+ parameters: { descricao: { type: 'string' } },
413
+ handler: async ({ descricao }, ctx) => {
414
+ const spec = await generateFlowSpec(descricao, flowSpecSchema(agent)); // host generation call, closed schema
415
+ validateFlow(spec, agent); await db.flows.insert(ctx.context.workspaceId, spec);
416
+ return { value: { criado: spec.id } };
417
+ },
418
+ });
419
+ ```
420
+
421
+ **S8 Scheduling.** `on: [{ message: ['quer marcar', 'quer remarcar'], repeat: 'always' }]`, `clearOnStart: ['data_preferida', 'horario_preferido', 'agenda_event_id', 'confirmado']` (applied before "sexta às 15h" lands), collect with agenda tools, `{ collect: ['confirmado'], ask: { confirmado: 'Confirme a data e o horário em uma frase.' } }`, `do book`, last step `then: { flow: 'pos-agendamento' }`.
422
+
423
+ **S9 Config assistant.** Zero flows, zero fields → understand skipped → one speak call with tools. Interview mode: one `message` flow → single-flow shortcut, no scoring; collect steps skip when known.
424
+
425
+ **S10.** §8.
426
+
427
+ **S11 Playground.** `agent.turn({ sessionId, session, message })` without `id`, `MemoryStore`, `schedule` fed to `MemoryScheduler.due(now)` or ignored; actions return `{ ok: true }`; mention flows run as no-ops and show in `started`.
428
+
429
+ **S12 AI speaks first, from a timer, mid-flow.** A `prompt` reached by a wake runs through the same agent, prompt, tools, instructions, `session.data` and the `history` the host passes; the gate arrives as `silenced`.
430
+
431
+ ```ts
432
+ const propostaParada = f.flow({
433
+ id: 'proposta-parada', name: 'Proposta parada',
434
+ on: [{ event: 'stage_entered', if: { inStage: 'proposta-enviada' }, after: '3d', businessHours: true }],
435
+ steps: [
436
+ { id: 'p1', prompt: 'A proposta foi enviada há três dias sem retorno. Pergunte, em uma frase, se ficou alguma dúvida — use o que já sabe sobre {{data.empresa}}.' },
437
+ { id: 'w1', wait: '2d', else: 'end' },
438
+ { id: 'n1', do: 'notify', with: { recipient: 'leadAssignee', message: 'Proposta de {{data.nome}} sem resposta há 5 dias.' } },
439
+ ],
440
+ });
441
+
442
+ wakeQueue.process(async (job: { data: { sessionId: string; key: string } }) => {
443
+ const { sessionId, key } = job.data;
444
+ await runTurn(sessionId, { wake: key });
445
+ });
446
+
447
+ async function runTurn(sessionId: string, input: TurnInputBody) {
448
+ for (let attempt = 0; attempt < 3; attempt++) {
449
+ const [session, context, history] = await Promise.all([store.load(sessionId), loadLeadContext(sessionId), loadHistory(sessionId)]);
450
+ const anchors = { lead: { key: `lead:${context.lead.id}`, lastInboundAt: context.lead.lastInboundAt } };
451
+ const r = await agent.turn({ ...input, sessionId, session, context, history, anchors,
452
+ claims: await ledger.claims(anchors), silenced: await gate.reason(sessionId) });
453
+ if (!r.changed) return;
454
+ try {
455
+ await db.transaction(async (tx) => {
456
+ await store.save(r.session, session?.version ?? 0); // CAS, 0 = insert
457
+ await ledger.write(tx, r.started, r.ended, r.outcomes, r.skipped); // unique(dedupeKey), partial unique(flowId, anchor) WHERE live, Execuções
458
+ await outbox.put(tx, r.messages, r.schedule); // wakes ride in the same transaction
459
+ });
460
+ } catch (e) { if (e instanceof SessionConflictError || isUniqueViolation(e)) continue; throw e; }
461
+ await outbox.drain(sessionId); // send honoring afterMs, enqueue wakes jobId = key
462
+ return;
463
+ }
464
+ }
465
+ ```
466
+
467
+ **S13 TRID script.** `[{ id: 'a', say: 'Oi! Aqui é da TRID.' }, { id: 'p', wait: '3s' }, { id: 'b', say: 'Chegou o iPhone 17, pronta entrega.' }, { id: 'q', prompt: 'Pergunte qual modelo interessa.', collect: ['modelo'] }]` → one turn, `messages: [A, B afterMs 3000, C]`; own says never silence own talk. 2 calls (understand + speak).
468
+
469
+ ## 13. Risks
470
+
471
+ 1. The understand call bundles routing, mentions, branches and extraction; a weak model may score routing worse than today's dedicated call. Run a scenario eval on GLM and Gemini before cutover.
472
+ 2. The speak envelope with pending fields must be probed per provider (Gemini strict, Zai prompt-only); `toWireSchema()` asserts `isStrictSchema` in tests.
473
+ 3. A wake-started talk step suspending a live conversation is new UX; the silence premise and `while` are the guards.
474
+ 4. Dropping five adapters affects npm users beyond the three consumers.
475
+ 5. Three apps migrate blobs, stored flows and ~9k lines of editor UI in lockstep with the worker rewrite; the shared FlowSpec is the chance to share one package.
476
+ 6. Instruction precedence ("cara ou coroa") is untouched.
477
+ 7. `do` is at-least-once before the save; a host handler that ignores `ctx.key` can double-fire on a CAS replay.