@falai/agent 1.2.8 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (499) hide show
  1. package/README.md +40 -886
  2. package/dist/adapters/MemoryAdapter.js +2 -2
  3. package/dist/adapters/MemoryAdapter.js.map +1 -1
  4. package/dist/adapters/MongoAdapter.js +2 -2
  5. package/dist/adapters/MongoAdapter.js.map +1 -1
  6. package/dist/adapters/OpenSearchAdapter.d.ts.map +1 -1
  7. package/dist/adapters/OpenSearchAdapter.js +9 -7
  8. package/dist/adapters/OpenSearchAdapter.js.map +1 -1
  9. package/dist/adapters/PostgreSQLAdapter.d.ts +14 -0
  10. package/dist/adapters/PostgreSQLAdapter.d.ts.map +1 -1
  11. package/dist/adapters/PostgreSQLAdapter.js +25 -9
  12. package/dist/adapters/PostgreSQLAdapter.js.map +1 -1
  13. package/dist/adapters/PrismaAdapter.js +5 -5
  14. package/dist/adapters/PrismaAdapter.js.map +1 -1
  15. package/dist/adapters/RedisAdapter.js +2 -2
  16. package/dist/adapters/RedisAdapter.js.map +1 -1
  17. package/dist/adapters/SQLiteAdapter.d.ts +17 -0
  18. package/dist/adapters/SQLiteAdapter.d.ts.map +1 -1
  19. package/dist/adapters/SQLiteAdapter.js +30 -11
  20. package/dist/adapters/SQLiteAdapter.js.map +1 -1
  21. package/dist/cjs/adapters/MemoryAdapter.js +2 -2
  22. package/dist/cjs/adapters/MemoryAdapter.js.map +1 -1
  23. package/dist/cjs/adapters/MongoAdapter.js +2 -2
  24. package/dist/cjs/adapters/MongoAdapter.js.map +1 -1
  25. package/dist/cjs/adapters/OpenSearchAdapter.d.ts.map +1 -1
  26. package/dist/cjs/adapters/OpenSearchAdapter.js +9 -7
  27. package/dist/cjs/adapters/OpenSearchAdapter.js.map +1 -1
  28. package/dist/cjs/adapters/PostgreSQLAdapter.d.ts +14 -0
  29. package/dist/cjs/adapters/PostgreSQLAdapter.d.ts.map +1 -1
  30. package/dist/cjs/adapters/PostgreSQLAdapter.js +25 -9
  31. package/dist/cjs/adapters/PostgreSQLAdapter.js.map +1 -1
  32. package/dist/cjs/adapters/PrismaAdapter.js +5 -5
  33. package/dist/cjs/adapters/PrismaAdapter.js.map +1 -1
  34. package/dist/cjs/adapters/RedisAdapter.js +2 -2
  35. package/dist/cjs/adapters/RedisAdapter.js.map +1 -1
  36. package/dist/cjs/adapters/SQLiteAdapter.d.ts +17 -0
  37. package/dist/cjs/adapters/SQLiteAdapter.d.ts.map +1 -1
  38. package/dist/cjs/adapters/SQLiteAdapter.js +30 -11
  39. package/dist/cjs/adapters/SQLiteAdapter.js.map +1 -1
  40. package/dist/cjs/constants/index.d.ts +0 -9
  41. package/dist/cjs/constants/index.d.ts.map +1 -1
  42. package/dist/cjs/constants/index.js +2 -11
  43. package/dist/cjs/constants/index.js.map +1 -1
  44. package/dist/cjs/core/Agent.d.ts +119 -153
  45. package/dist/cjs/core/Agent.d.ts.map +1 -1
  46. package/dist/cjs/core/Agent.js +471 -324
  47. package/dist/cjs/core/Agent.js.map +1 -1
  48. package/dist/cjs/core/AutoChainExecutor.d.ts +107 -0
  49. package/dist/cjs/core/AutoChainExecutor.d.ts.map +1 -0
  50. package/dist/cjs/core/AutoChainExecutor.js +297 -0
  51. package/dist/cjs/core/AutoChainExecutor.js.map +1 -0
  52. package/dist/cjs/core/BranchEvaluator.d.ts +54 -0
  53. package/dist/cjs/core/BranchEvaluator.d.ts.map +1 -0
  54. package/dist/cjs/core/BranchEvaluator.js +130 -0
  55. package/dist/cjs/core/BranchEvaluator.js.map +1 -0
  56. package/dist/cjs/core/DirectiveBus.d.ts +88 -0
  57. package/dist/cjs/core/DirectiveBus.d.ts.map +1 -0
  58. package/dist/cjs/core/DirectiveBus.js +196 -0
  59. package/dist/cjs/core/DirectiveBus.js.map +1 -0
  60. package/dist/cjs/core/DirectiveChainTracker.d.ts +49 -0
  61. package/dist/cjs/core/DirectiveChainTracker.d.ts.map +1 -0
  62. package/dist/cjs/core/DirectiveChainTracker.js +121 -0
  63. package/dist/cjs/core/DirectiveChainTracker.js.map +1 -0
  64. package/dist/cjs/core/Flow.d.ts +186 -0
  65. package/dist/cjs/core/Flow.d.ts.map +1 -0
  66. package/dist/cjs/core/Flow.js +550 -0
  67. package/dist/cjs/core/Flow.js.map +1 -0
  68. package/dist/cjs/core/FlowRouter.d.ts +182 -0
  69. package/dist/cjs/core/FlowRouter.d.ts.map +1 -0
  70. package/dist/cjs/core/{RoutingEngine.js → FlowRouter.js} +323 -306
  71. package/dist/cjs/core/FlowRouter.js.map +1 -0
  72. package/dist/cjs/core/PersistenceManager.d.ts +2 -2
  73. package/dist/cjs/core/PersistenceManager.d.ts.map +1 -1
  74. package/dist/cjs/core/PersistenceManager.js +7 -7
  75. package/dist/cjs/core/PersistenceManager.js.map +1 -1
  76. package/dist/cjs/core/PromptComposer.d.ts +21 -8
  77. package/dist/cjs/core/PromptComposer.d.ts.map +1 -1
  78. package/dist/cjs/core/PromptComposer.js +182 -105
  79. package/dist/cjs/core/PromptComposer.js.map +1 -1
  80. package/dist/cjs/core/PromptSectionCache.d.ts +1 -1
  81. package/dist/cjs/core/PromptSectionCache.js +1 -1
  82. package/dist/cjs/core/ResponseEngine.d.ts +18 -8
  83. package/dist/cjs/core/ResponseEngine.d.ts.map +1 -1
  84. package/dist/cjs/core/ResponseEngine.js +38 -36
  85. package/dist/cjs/core/ResponseEngine.js.map +1 -1
  86. package/dist/cjs/core/ResponseModal.d.ts +73 -56
  87. package/dist/cjs/core/ResponseModal.d.ts.map +1 -1
  88. package/dist/cjs/core/ResponseModal.js +1191 -1014
  89. package/dist/cjs/core/ResponseModal.js.map +1 -1
  90. package/dist/cjs/core/ResponsePipeline.d.ts +124 -26
  91. package/dist/cjs/core/ResponsePipeline.d.ts.map +1 -1
  92. package/dist/cjs/core/ResponsePipeline.js +509 -136
  93. package/dist/cjs/core/ResponsePipeline.js.map +1 -1
  94. package/dist/cjs/core/SignalEvaluator.d.ts +86 -0
  95. package/dist/cjs/core/SignalEvaluator.d.ts.map +1 -0
  96. package/dist/cjs/core/SignalEvaluator.js +333 -0
  97. package/dist/cjs/core/SignalEvaluator.js.map +1 -0
  98. package/dist/cjs/core/SignalProcessor.d.ts +152 -0
  99. package/dist/cjs/core/SignalProcessor.d.ts.map +1 -0
  100. package/dist/cjs/core/SignalProcessor.js +562 -0
  101. package/dist/cjs/core/SignalProcessor.js.map +1 -0
  102. package/dist/cjs/core/Step.d.ts +43 -32
  103. package/dist/cjs/core/Step.d.ts.map +1 -1
  104. package/dist/cjs/core/Step.js +221 -126
  105. package/dist/cjs/core/Step.js.map +1 -1
  106. package/dist/cjs/core/StreamingToolExecutor.d.ts +2 -2
  107. package/dist/cjs/core/StreamingToolExecutor.d.ts.map +1 -1
  108. package/dist/cjs/core/StreamingToolExecutor.js.map +1 -1
  109. package/dist/cjs/core/ToolManager.d.ts +44 -13
  110. package/dist/cjs/core/ToolManager.d.ts.map +1 -1
  111. package/dist/cjs/core/ToolManager.js +174 -91
  112. package/dist/cjs/core/ToolManager.js.map +1 -1
  113. package/dist/cjs/core/createAgent.d.ts +35 -0
  114. package/dist/cjs/core/createAgent.d.ts.map +1 -0
  115. package/dist/cjs/core/createAgent.js +39 -0
  116. package/dist/cjs/core/createAgent.js.map +1 -0
  117. package/dist/cjs/core/flow-namespace.d.ts +49 -0
  118. package/dist/cjs/core/flow-namespace.d.ts.map +1 -0
  119. package/dist/cjs/core/flow-namespace.js +171 -0
  120. package/dist/cjs/core/flow-namespace.js.map +1 -0
  121. package/dist/cjs/index.d.ts +11 -14
  122. package/dist/cjs/index.d.ts.map +1 -1
  123. package/dist/cjs/index.js +18 -22
  124. package/dist/cjs/index.js.map +1 -1
  125. package/dist/cjs/types/agent.d.ts +183 -54
  126. package/dist/cjs/types/agent.d.ts.map +1 -1
  127. package/dist/cjs/types/agent.js +0 -6
  128. package/dist/cjs/types/agent.js.map +1 -1
  129. package/dist/cjs/types/ai.d.ts +3 -3
  130. package/dist/cjs/types/ai.d.ts.map +1 -1
  131. package/dist/cjs/types/errors.d.ts +15 -0
  132. package/dist/cjs/types/errors.d.ts.map +1 -0
  133. package/dist/cjs/types/errors.js +22 -0
  134. package/dist/cjs/types/errors.js.map +1 -0
  135. package/dist/cjs/types/flow.d.ts +513 -0
  136. package/dist/cjs/types/flow.d.ts.map +1 -0
  137. package/dist/cjs/types/{route.js → flow.js} +2 -2
  138. package/dist/cjs/types/flow.js.map +1 -0
  139. package/dist/cjs/types/index.d.ts +7 -6
  140. package/dist/cjs/types/index.d.ts.map +1 -1
  141. package/dist/cjs/types/index.js +6 -2
  142. package/dist/cjs/types/index.js.map +1 -1
  143. package/dist/cjs/types/persistence.d.ts +11 -7
  144. package/dist/cjs/types/persistence.d.ts.map +1 -1
  145. package/dist/cjs/types/routing.d.ts +1 -1
  146. package/dist/cjs/types/routing.d.ts.map +1 -1
  147. package/dist/cjs/types/session.d.ts +24 -23
  148. package/dist/cjs/types/session.d.ts.map +1 -1
  149. package/dist/cjs/types/signals.d.ts +248 -0
  150. package/dist/cjs/types/signals.d.ts.map +1 -0
  151. package/dist/cjs/types/signals.js +11 -0
  152. package/dist/cjs/types/signals.js.map +1 -0
  153. package/dist/cjs/types/template.d.ts +2 -8
  154. package/dist/cjs/types/template.d.ts.map +1 -1
  155. package/dist/cjs/types/tool.d.ts +36 -29
  156. package/dist/cjs/types/tool.d.ts.map +1 -1
  157. package/dist/cjs/types/tool.js +1 -1
  158. package/dist/cjs/types/tool.js.map +1 -1
  159. package/dist/cjs/utils/condition.d.ts +7 -1
  160. package/dist/cjs/utils/condition.d.ts.map +1 -1
  161. package/dist/cjs/utils/condition.js.map +1 -1
  162. package/dist/cjs/utils/id.d.ts +13 -5
  163. package/dist/cjs/utils/id.d.ts.map +1 -1
  164. package/dist/cjs/utils/id.js +24 -10
  165. package/dist/cjs/utils/id.js.map +1 -1
  166. package/dist/cjs/utils/index.d.ts +2 -2
  167. package/dist/cjs/utils/index.d.ts.map +1 -1
  168. package/dist/cjs/utils/index.js +7 -3
  169. package/dist/cjs/utils/index.js.map +1 -1
  170. package/dist/cjs/utils/session.d.ts +44 -5
  171. package/dist/cjs/utils/session.d.ts.map +1 -1
  172. package/dist/cjs/utils/session.js +197 -38
  173. package/dist/cjs/utils/session.js.map +1 -1
  174. package/dist/constants/index.d.ts +0 -9
  175. package/dist/constants/index.d.ts.map +1 -1
  176. package/dist/constants/index.js +3 -9
  177. package/dist/constants/index.js.map +1 -1
  178. package/dist/core/Agent.d.ts +119 -153
  179. package/dist/core/Agent.d.ts.map +1 -1
  180. package/dist/core/Agent.js +472 -325
  181. package/dist/core/Agent.js.map +1 -1
  182. package/dist/core/AutoChainExecutor.d.ts +107 -0
  183. package/dist/core/AutoChainExecutor.d.ts.map +1 -0
  184. package/dist/core/AutoChainExecutor.js +293 -0
  185. package/dist/core/AutoChainExecutor.js.map +1 -0
  186. package/dist/core/BranchEvaluator.d.ts +54 -0
  187. package/dist/core/BranchEvaluator.d.ts.map +1 -0
  188. package/dist/core/BranchEvaluator.js +126 -0
  189. package/dist/core/BranchEvaluator.js.map +1 -0
  190. package/dist/core/DirectiveBus.d.ts +88 -0
  191. package/dist/core/DirectiveBus.d.ts.map +1 -0
  192. package/dist/core/DirectiveBus.js +192 -0
  193. package/dist/core/DirectiveBus.js.map +1 -0
  194. package/dist/core/DirectiveChainTracker.d.ts +49 -0
  195. package/dist/core/DirectiveChainTracker.d.ts.map +1 -0
  196. package/dist/core/DirectiveChainTracker.js +117 -0
  197. package/dist/core/DirectiveChainTracker.js.map +1 -0
  198. package/dist/core/Flow.d.ts +186 -0
  199. package/dist/core/Flow.d.ts.map +1 -0
  200. package/dist/core/Flow.js +546 -0
  201. package/dist/core/Flow.js.map +1 -0
  202. package/dist/core/FlowRouter.d.ts +182 -0
  203. package/dist/core/FlowRouter.d.ts.map +1 -0
  204. package/dist/core/{RoutingEngine.js → FlowRouter.js} +322 -305
  205. package/dist/core/FlowRouter.js.map +1 -0
  206. package/dist/core/PersistenceManager.d.ts +2 -2
  207. package/dist/core/PersistenceManager.d.ts.map +1 -1
  208. package/dist/core/PersistenceManager.js +7 -7
  209. package/dist/core/PersistenceManager.js.map +1 -1
  210. package/dist/core/PromptComposer.d.ts +21 -8
  211. package/dist/core/PromptComposer.d.ts.map +1 -1
  212. package/dist/core/PromptComposer.js +183 -106
  213. package/dist/core/PromptComposer.js.map +1 -1
  214. package/dist/core/PromptSectionCache.d.ts +1 -1
  215. package/dist/core/PromptSectionCache.js +1 -1
  216. package/dist/core/ResponseEngine.d.ts +18 -8
  217. package/dist/core/ResponseEngine.d.ts.map +1 -1
  218. package/dist/core/ResponseEngine.js +38 -36
  219. package/dist/core/ResponseEngine.js.map +1 -1
  220. package/dist/core/ResponseModal.d.ts +73 -56
  221. package/dist/core/ResponseModal.d.ts.map +1 -1
  222. package/dist/core/ResponseModal.js +1193 -1016
  223. package/dist/core/ResponseModal.js.map +1 -1
  224. package/dist/core/ResponsePipeline.d.ts +124 -26
  225. package/dist/core/ResponsePipeline.d.ts.map +1 -1
  226. package/dist/core/ResponsePipeline.js +509 -137
  227. package/dist/core/ResponsePipeline.js.map +1 -1
  228. package/dist/core/SignalEvaluator.d.ts +86 -0
  229. package/dist/core/SignalEvaluator.d.ts.map +1 -0
  230. package/dist/core/SignalEvaluator.js +326 -0
  231. package/dist/core/SignalEvaluator.js.map +1 -0
  232. package/dist/core/SignalProcessor.d.ts +152 -0
  233. package/dist/core/SignalProcessor.d.ts.map +1 -0
  234. package/dist/core/SignalProcessor.js +555 -0
  235. package/dist/core/SignalProcessor.js.map +1 -0
  236. package/dist/core/Step.d.ts +43 -32
  237. package/dist/core/Step.d.ts.map +1 -1
  238. package/dist/core/Step.js +220 -126
  239. package/dist/core/Step.js.map +1 -1
  240. package/dist/core/StreamingToolExecutor.d.ts +2 -2
  241. package/dist/core/StreamingToolExecutor.d.ts.map +1 -1
  242. package/dist/core/StreamingToolExecutor.js.map +1 -1
  243. package/dist/core/ToolManager.d.ts +44 -13
  244. package/dist/core/ToolManager.d.ts.map +1 -1
  245. package/dist/core/ToolManager.js +174 -91
  246. package/dist/core/ToolManager.js.map +1 -1
  247. package/dist/core/createAgent.d.ts +35 -0
  248. package/dist/core/createAgent.d.ts.map +1 -0
  249. package/dist/core/createAgent.js +36 -0
  250. package/dist/core/createAgent.js.map +1 -0
  251. package/dist/core/flow-namespace.d.ts +49 -0
  252. package/dist/core/flow-namespace.d.ts.map +1 -0
  253. package/dist/core/flow-namespace.js +168 -0
  254. package/dist/core/flow-namespace.js.map +1 -0
  255. package/dist/index.d.ts +11 -14
  256. package/dist/index.d.ts.map +1 -1
  257. package/dist/index.js +9 -12
  258. package/dist/index.js.map +1 -1
  259. package/dist/types/agent.d.ts +183 -54
  260. package/dist/types/agent.d.ts.map +1 -1
  261. package/dist/types/agent.js +0 -6
  262. package/dist/types/agent.js.map +1 -1
  263. package/dist/types/ai.d.ts +3 -3
  264. package/dist/types/ai.d.ts.map +1 -1
  265. package/dist/types/errors.d.ts +15 -0
  266. package/dist/types/errors.d.ts.map +1 -0
  267. package/dist/types/errors.js +18 -0
  268. package/dist/types/errors.js.map +1 -0
  269. package/dist/types/flow.d.ts +513 -0
  270. package/dist/types/flow.d.ts.map +1 -0
  271. package/dist/types/flow.js +5 -0
  272. package/dist/types/flow.js.map +1 -0
  273. package/dist/types/index.d.ts +7 -6
  274. package/dist/types/index.d.ts.map +1 -1
  275. package/dist/types/index.js +4 -1
  276. package/dist/types/index.js.map +1 -1
  277. package/dist/types/persistence.d.ts +11 -7
  278. package/dist/types/persistence.d.ts.map +1 -1
  279. package/dist/types/routing.d.ts +1 -1
  280. package/dist/types/routing.d.ts.map +1 -1
  281. package/dist/types/session.d.ts +24 -23
  282. package/dist/types/session.d.ts.map +1 -1
  283. package/dist/types/signals.d.ts +248 -0
  284. package/dist/types/signals.d.ts.map +1 -0
  285. package/dist/types/signals.js +10 -0
  286. package/dist/types/signals.js.map +1 -0
  287. package/dist/types/template.d.ts +2 -8
  288. package/dist/types/template.d.ts.map +1 -1
  289. package/dist/types/tool.d.ts +36 -29
  290. package/dist/types/tool.d.ts.map +1 -1
  291. package/dist/types/tool.js +1 -1
  292. package/dist/types/tool.js.map +1 -1
  293. package/dist/utils/condition.d.ts +7 -1
  294. package/dist/utils/condition.d.ts.map +1 -1
  295. package/dist/utils/condition.js.map +1 -1
  296. package/dist/utils/id.d.ts +13 -5
  297. package/dist/utils/id.d.ts.map +1 -1
  298. package/dist/utils/id.js +22 -9
  299. package/dist/utils/id.js.map +1 -1
  300. package/dist/utils/index.d.ts +2 -2
  301. package/dist/utils/index.d.ts.map +1 -1
  302. package/dist/utils/index.js +2 -2
  303. package/dist/utils/index.js.map +1 -1
  304. package/dist/utils/session.d.ts +44 -5
  305. package/dist/utils/session.d.ts.map +1 -1
  306. package/dist/utils/session.js +193 -37
  307. package/dist/utils/session.js.map +1 -1
  308. package/docs/README.md +15 -202
  309. package/docs/concepts/architecture.md +281 -0
  310. package/docs/concepts/directives.md +400 -0
  311. package/docs/concepts/pipeline.md +399 -0
  312. package/docs/guides/branching.md +263 -0
  313. package/docs/guides/compaction.md +163 -0
  314. package/docs/guides/conditions.md +167 -0
  315. package/docs/guides/error-handling.md +176 -0
  316. package/docs/guides/flow-control.md +409 -0
  317. package/docs/guides/instructions.md +210 -0
  318. package/docs/guides/persistence.md +182 -0
  319. package/docs/guides/streaming.md +137 -0
  320. package/docs/migration/README.md +15 -0
  321. package/docs/migration/route-to-flow.md +560 -0
  322. package/docs/migration/v1-to-v2.md +909 -0
  323. package/docs/reference/adapters.md +481 -0
  324. package/docs/reference/branches.md +241 -0
  325. package/docs/reference/create-agent.md +186 -0
  326. package/docs/reference/directive.md +243 -0
  327. package/docs/reference/errors.md +122 -0
  328. package/docs/reference/flow.md +238 -0
  329. package/docs/reference/instruction.md +177 -0
  330. package/docs/reference/pre-directive.md +131 -0
  331. package/docs/reference/providers.md +227 -0
  332. package/docs/reference/signals.md +356 -0
  333. package/docs/reference/step.md +339 -0
  334. package/docs/reference/tool.md +269 -0
  335. package/docs/start/01-install.md +81 -0
  336. package/docs/start/02-first-agent.md +196 -0
  337. package/docs/start/03-collect-data.md +222 -0
  338. package/docs/start/04-add-tools.md +276 -0
  339. package/docs/start/05-go-to-production.md +216 -0
  340. package/examples/01-quickstart.ts +20 -0
  341. package/examples/02-data-extraction.ts +90 -0
  342. package/examples/03-tools.ts +136 -0
  343. package/examples/04-instructions.ts +100 -0
  344. package/examples/05-branching.ts +140 -0
  345. package/examples/06-flow-control.ts +103 -0
  346. package/examples/07-streaming.ts +69 -0
  347. package/examples/08-persistence.ts +98 -0
  348. package/examples/09-signals.ts +144 -0
  349. package/examples/tsconfig.json +30 -0
  350. package/package.json +2 -1
  351. package/src/adapters/MemoryAdapter.ts +3 -3
  352. package/src/adapters/MongoAdapter.ts +3 -3
  353. package/src/adapters/OpenSearchAdapter.ts +10 -8
  354. package/src/adapters/PostgreSQLAdapter.ts +26 -10
  355. package/src/adapters/PrismaAdapter.ts +6 -6
  356. package/src/adapters/RedisAdapter.ts +3 -3
  357. package/src/adapters/SQLiteAdapter.ts +31 -12
  358. package/src/constants/index.ts +2 -10
  359. package/src/core/Agent.ts +585 -374
  360. package/src/core/AutoChainExecutor.ts +440 -0
  361. package/src/core/BranchEvaluator.ts +167 -0
  362. package/src/core/DirectiveBus.ts +248 -0
  363. package/src/core/DirectiveChainTracker.ts +144 -0
  364. package/src/core/Flow.ts +666 -0
  365. package/src/core/{RoutingEngine.ts → FlowRouter.ts} +385 -365
  366. package/src/core/PersistenceManager.ts +8 -8
  367. package/src/core/PromptComposer.ts +209 -140
  368. package/src/core/PromptSectionCache.ts +1 -1
  369. package/src/core/ResponseEngine.ts +61 -46
  370. package/src/core/ResponseModal.ts +1453 -1240
  371. package/src/core/ResponsePipeline.ts +655 -175
  372. package/src/core/SignalEvaluator.ts +420 -0
  373. package/src/core/SignalProcessor.ts +723 -0
  374. package/src/core/Step.ts +279 -176
  375. package/src/core/StreamingToolExecutor.ts +4 -4
  376. package/src/core/ToolManager.ts +200 -97
  377. package/src/core/createAgent.ts +40 -0
  378. package/src/core/flow-namespace.ts +219 -0
  379. package/src/index.ts +42 -36
  380. package/src/types/agent.ts +182 -53
  381. package/src/types/ai.ts +3 -3
  382. package/src/types/errors.ts +18 -0
  383. package/src/types/flow.ts +590 -0
  384. package/src/types/index.ts +43 -16
  385. package/src/types/persistence.ts +12 -8
  386. package/src/types/routing.ts +1 -1
  387. package/src/types/session.ts +26 -23
  388. package/src/types/signals.ts +321 -0
  389. package/src/types/template.ts +3 -11
  390. package/src/types/tool.ts +50 -42
  391. package/src/utils/condition.ts +13 -4
  392. package/src/utils/id.ts +27 -9
  393. package/src/utils/index.ts +6 -2
  394. package/src/utils/session.ts +238 -42
  395. package/dist/cjs/core/BatchExecutor.d.ts +0 -359
  396. package/dist/cjs/core/BatchExecutor.d.ts.map +0 -1
  397. package/dist/cjs/core/BatchExecutor.js +0 -861
  398. package/dist/cjs/core/BatchExecutor.js.map +0 -1
  399. package/dist/cjs/core/BatchPromptBuilder.d.ts +0 -89
  400. package/dist/cjs/core/BatchPromptBuilder.d.ts.map +0 -1
  401. package/dist/cjs/core/BatchPromptBuilder.js +0 -223
  402. package/dist/cjs/core/BatchPromptBuilder.js.map +0 -1
  403. package/dist/cjs/core/Route.d.ts +0 -180
  404. package/dist/cjs/core/Route.d.ts.map +0 -1
  405. package/dist/cjs/core/Route.js +0 -542
  406. package/dist/cjs/core/Route.js.map +0 -1
  407. package/dist/cjs/core/RoutingEngine.d.ts +0 -185
  408. package/dist/cjs/core/RoutingEngine.d.ts.map +0 -1
  409. package/dist/cjs/core/RoutingEngine.js.map +0 -1
  410. package/dist/cjs/types/route.d.ts +0 -336
  411. package/dist/cjs/types/route.d.ts.map +0 -1
  412. package/dist/cjs/types/route.js.map +0 -1
  413. package/dist/core/BatchExecutor.d.ts +0 -359
  414. package/dist/core/BatchExecutor.d.ts.map +0 -1
  415. package/dist/core/BatchExecutor.js +0 -856
  416. package/dist/core/BatchExecutor.js.map +0 -1
  417. package/dist/core/BatchPromptBuilder.d.ts +0 -89
  418. package/dist/core/BatchPromptBuilder.d.ts.map +0 -1
  419. package/dist/core/BatchPromptBuilder.js +0 -219
  420. package/dist/core/BatchPromptBuilder.js.map +0 -1
  421. package/dist/core/Route.d.ts +0 -180
  422. package/dist/core/Route.d.ts.map +0 -1
  423. package/dist/core/Route.js +0 -538
  424. package/dist/core/Route.js.map +0 -1
  425. package/dist/core/RoutingEngine.d.ts +0 -185
  426. package/dist/core/RoutingEngine.d.ts.map +0 -1
  427. package/dist/core/RoutingEngine.js.map +0 -1
  428. package/dist/types/route.d.ts +0 -336
  429. package/dist/types/route.d.ts.map +0 -1
  430. package/dist/types/route.js +0 -5
  431. package/dist/types/route.js.map +0 -1
  432. package/docs/CONTRIBUTING.md +0 -521
  433. package/docs/api/README.md +0 -3299
  434. package/docs/api/overview.md +0 -1410
  435. package/docs/architecture/data-extraction-flow.md +0 -360
  436. package/docs/architecture/multi-step-execution.md +0 -277
  437. package/docs/core/agent/README.md +0 -938
  438. package/docs/core/agent/context-management.md +0 -796
  439. package/docs/core/agent/rules-and-prohibitions.md +0 -113
  440. package/docs/core/agent/session-management.md +0 -693
  441. package/docs/core/ai-integration/prompt-composition.md +0 -355
  442. package/docs/core/ai-integration/providers.md +0 -515
  443. package/docs/core/ai-integration/response-processing.md +0 -433
  444. package/docs/core/conversation-flows/data-collection.md +0 -772
  445. package/docs/core/conversation-flows/route-dsl.md +0 -509
  446. package/docs/core/conversation-flows/routes.md +0 -249
  447. package/docs/core/conversation-flows/step-transitions.md +0 -731
  448. package/docs/core/conversation-flows/steps.md +0 -268
  449. package/docs/core/error-handling.md +0 -830
  450. package/docs/core/persistence/adapters.md +0 -255
  451. package/docs/core/persistence/session-storage.md +0 -656
  452. package/docs/core/routing/intelligent-routing.md +0 -470
  453. package/docs/core/tools/enhanced-tool.md +0 -186
  454. package/docs/core/tools/streaming-execution.md +0 -161
  455. package/docs/core/tools/tool-definition.md +0 -970
  456. package/docs/core/tools/tool-scoping.md +0 -819
  457. package/docs/guides/advanced-patterns/publishing.md +0 -186
  458. package/docs/guides/context-compaction.md +0 -96
  459. package/docs/guides/error-handling-patterns.md +0 -578
  460. package/docs/guides/getting-started/README.md +0 -795
  461. package/docs/guides/migration/README.md +0 -101
  462. package/docs/guides/migration/flexible-routing-conditions.md +0 -375
  463. package/docs/guides/migration/multi-step-execution.md +0 -393
  464. package/docs/guides/migration/response-modal-refactor.md +0 -518
  465. package/docs/guides/prompt-optimization.md +0 -164
  466. package/examples/advanced-patterns/context-compaction.ts +0 -223
  467. package/examples/advanced-patterns/knowledge-based-agent.ts +0 -735
  468. package/examples/advanced-patterns/persistent-onboarding.ts +0 -728
  469. package/examples/advanced-patterns/route-lifecycle-hooks.ts +0 -556
  470. package/examples/advanced-patterns/streaming-responses.ts +0 -656
  471. package/examples/ai-providers/anthropic-integration.ts +0 -388
  472. package/examples/ai-providers/openai-integration.ts +0 -228
  473. package/examples/condition-patterns/function-only-conditions.ts +0 -365
  474. package/examples/condition-patterns/mixed-array-conditions.ts +0 -477
  475. package/examples/condition-patterns/route-skipif-patterns.ts +0 -468
  476. package/examples/condition-patterns/step-skipif-patterns.ts +0 -0
  477. package/examples/condition-patterns/string-only-conditions.ts +0 -296
  478. package/examples/conversation-flows/completion-transitions.ts +0 -318
  479. package/examples/core-concepts/basic-agent.ts +0 -503
  480. package/examples/core-concepts/modern-streaming-api.ts +0 -309
  481. package/examples/core-concepts/schema-driven-extraction.ts +0 -332
  482. package/examples/core-concepts/session-management.ts +0 -494
  483. package/examples/integrations/database-integration.ts +0 -631
  484. package/examples/integrations/healthcare-integration.ts +0 -595
  485. package/examples/integrations/search-integration.ts +0 -530
  486. package/examples/integrations/server-session-management.ts +0 -307
  487. package/examples/persistence/custom-adapter.ts +0 -526
  488. package/examples/persistence/database-persistence.ts +0 -583
  489. package/examples/persistence/memory-sessions.ts +0 -495
  490. package/examples/persistence/prisma-schema.example.prisma +0 -74
  491. package/examples/persistence/redis-persistence.ts +0 -488
  492. package/examples/tools/basic-tools.ts +0 -765
  493. package/examples/tools/data-enrichment-tools.ts +0 -593
  494. package/examples/tools/enhanced-tool-metadata.ts +0 -268
  495. package/examples/tools/streaming-tool-execution.ts +0 -283
  496. package/src/core/BatchExecutor.ts +0 -1187
  497. package/src/core/BatchPromptBuilder.ts +0 -299
  498. package/src/core/Route.ts +0 -678
  499. package/src/types/route.ts +0 -392
@@ -0,0 +1,409 @@
1
+ ---
2
+ title: "Flow control"
3
+ description: "Redirect, complete, abort, or speak verbatim from a tool, hook, or webhook by emitting a directive."
4
+ type: guide
5
+ order: 3
6
+ ---
7
+
8
+ # Flow control
9
+
10
+ > **Where this is introduced:** [Directives](../concepts/directives.md)
11
+
12
+ Most steps run, ask the model, write fields, and move on. Some don't.
13
+ A permission tool finds the caller is not eligible. A booking tool
14
+ finishes its work and wants the flow to end without the LLM phrasing a
15
+ confirmation. A webhook decides the next turn should start in a
16
+ different flow than where the user left off. Every one of these is the
17
+ same primitive: emit a [`Directive`](../reference/directive.md).
18
+
19
+ This guide is a tour of the recipes. Each section is a task and a
20
+ code-block that does it. The shape stays the same across all of them;
21
+ what changes is which fields you set and where the directive comes
22
+ from. The [Directive reference](../reference/directive.md) is the
23
+ canonical contract for every shorthand, object form, and validation
24
+ rule.
25
+
26
+ ## The shape
27
+
28
+ ```typescript
29
+ import type { Directive } from "@falai/agent";
30
+
31
+ const d: Directive = {
32
+ goTo: "Booking", // position (one max)
33
+ reply: "Routing you to booking.", // verbatim utterance
34
+ dataUpdate: { source: "tool" }, // state write
35
+ };
36
+ ```
37
+
38
+ Every field is optional. State writes (`dataUpdate`,
39
+ `contextUpdate`) and `reply` ride alongside any position field.
40
+
41
+ ## Position fields and precedence
42
+
43
+ Position answers "where does the conversation go after this turn?"
44
+
45
+ | Field | Effect |
46
+ |------------|-----------------------------------------------------------------------|
47
+ | `goTo` | Jump to another flow. |
48
+ | `goToStep` | Jump to a step (within this flow, or — in object form — another flow).|
49
+ | `complete` | Mark the current flow done. Run the flow's completion path. |
50
+ | `abort` | End the conversation. Optionally clear the session. |
51
+ | `reset` | Restart the current flow. Optionally clear its declared fields. |
52
+
53
+ The fields are **mutually exclusive** — at most one per directive.
54
+ Setting two throws `FlowConfigurationError`. When more than one
55
+ emitter writes a position field on the same turn, the per-turn merge
56
+ picks one winner by precedence:
57
+
58
+ ```
59
+ abort > complete > goTo / goToStep > reset
60
+ ```
61
+
62
+ `abort` always wins — there's no "somewhere else" after the
63
+ conversation has ended. `complete` beats `goTo` — if a follow-up
64
+ jump belongs after completion, put it in `complete.next`. `goTo` and
65
+ `goToStep` share a tier (last emission wins). `reset` is lowest.
66
+
67
+ State writes and `reply` ride alongside whichever position wins.
68
+
69
+ ## Recipe 1 — Redirect from a tool
70
+
71
+ Tools have two ways to emit a directive: imperative (`ctx.dispatch`)
72
+ mid-handler, or declarative (`ToolResult.directive`) on return. Both
73
+ land on the same per-turn bus and merge identically.
74
+
75
+ ### Imperative — `ctx.dispatch`
76
+
77
+ ```typescript
78
+ import type { Tool } from "@falai/agent";
79
+
80
+ const checkEligibility: Tool<{ userId: string }, BookingData, { ok: boolean }> = {
81
+ id: "check_eligibility",
82
+ description: "Verify the caller is allowed to book this destination.",
83
+ isReadOnly: () => true,
84
+ async handler(ctx) {
85
+ const ok = await isEligible(ctx.context.userId, ctx.data.destination);
86
+ if (!ok) {
87
+ ctx.dispatch({
88
+ goTo: "Denial",
89
+ reply: "Sorry — you're not eligible to book that destination.",
90
+ dataUpdate: { denialReason: "ineligible" },
91
+ });
92
+ return { ok: false };
93
+ }
94
+ return { ok: true };
95
+ },
96
+ };
97
+ ```
98
+
99
+ Multiple `dispatch` calls in one handler are allowed — they
100
+ concatenate alongside emissions from other tools and hooks before the
101
+ merge runs.
102
+
103
+ ### Declarative — `ToolResult.directive`
104
+
105
+ ```typescript
106
+ async handler(ctx) {
107
+ const ok = await isEligible(ctx.context.userId, ctx.data.destination);
108
+ if (!ok) {
109
+ return {
110
+ data: { ok: false },
111
+ directive: {
112
+ goTo: "Denial",
113
+ reply: "Sorry — you're not eligible to book that destination.",
114
+ },
115
+ };
116
+ }
117
+ return { data: { ok: true } };
118
+ }
119
+ ```
120
+
121
+ Reach for **imperative** when the handler still has work after the
122
+ decision. Reach for **declarative** when there's a single return
123
+ point.
124
+
125
+ ## Recipe 2 — Complete with a chained next
126
+
127
+ A booking tool reserved the room. The flow is done, and the next
128
+ thing the agent should do is open a feedback flow. `complete` accepts
129
+ an object form whose `next` field is **another directive** applied
130
+ immediately after the flow's completion path runs:
131
+
132
+ ```typescript
133
+ import type { Tool, Directive } from "@falai/agent";
134
+
135
+ const bookHotel: Tool<unknown, BookingData, { id: string }> = {
136
+ id: "book_hotel",
137
+ description: "Reserve the hotel for the collected fields.",
138
+ async handler(ctx, args) {
139
+ const id = await reserve(args);
140
+ const directive: Directive = {
141
+ complete: {
142
+ reason: "reservation confirmed",
143
+ next: { goTo: "Feedback", reply: "Booked. Mind a quick survey?" },
144
+ },
145
+ dataUpdate: { bookingId: id },
146
+ };
147
+ return { data: { id }, directive };
148
+ },
149
+ };
150
+ ```
151
+
152
+ What runs, in order: the tool's directive lands on the bus, the merge
153
+ picks `complete`, the flow's `hooks.onComplete` runs, then
154
+ `complete.next` is applied — `goTo: "Feedback"` redirects with the
155
+ verbatim reply as that turn's assistant message.
156
+
157
+ `complete.next` is one level deep on purpose — chains do not nest.
158
+ For the simple case, the shorthand `complete: true` is the right
159
+ call:
160
+
161
+ ```typescript
162
+ return { data, directive: { complete: true, dataUpdate: { bookingId: id } } };
163
+ ```
164
+
165
+ ## Recipe 3 — Abort on a permission failure
166
+
167
+ `abort` ends the conversation. Use it when there's no flow to
168
+ redirect *to*:
169
+
170
+ ```typescript
171
+ import type { Tool, Directive } from "@falai/agent";
172
+
173
+ const verifyAccess: Tool = {
174
+ id: "verify_access",
175
+ isReadOnly: () => true,
176
+ async handler(ctx) {
177
+ const allowed = await acl.check(ctx.context.userId);
178
+ if (!allowed) {
179
+ const directive: Directive = {
180
+ abort: { reason: "caller is not on the allow-list", clearSession: true },
181
+ };
182
+ return { data: { allowed: false }, directive };
183
+ }
184
+ return { data: { allowed: true } };
185
+ },
186
+ };
187
+ ```
188
+
189
+ Two things to know:
190
+
191
+ - **`abort` cannot co-exist with `reply`.** Aborted conversations
192
+ don't deliver replies. To say something on the way out, use
193
+ `complete` plus `reply` instead.
194
+ - **`clearSession: true`** purges the session at the next persistence
195
+ write. Without it, the aborted session sticks around for traces.
196
+
197
+ ## Recipe 4 — Reply verbatim from a finalize hook
198
+
199
+ Some utterances should be exact: confirmations, bridges, refusals,
200
+ boilerplate at flow boundaries. `reply: string` skips the LLM and
201
+ emits the literal text — no templating, no model rephrasing.
202
+
203
+ ```typescript
204
+ import type { Directive } from "@falai/agent";
205
+
206
+ const step = {
207
+ id: "confirm_handoff",
208
+ prompt: "Confirm the handoff if the queue is clear.",
209
+ hooks: {
210
+ finalize: ({ data }): Directive | void => {
211
+ if (data.handoffReady) {
212
+ return { reply: "Connecting you with a specialist now." };
213
+ }
214
+ },
215
+ },
216
+ };
217
+ ```
218
+
219
+ The turn ends with `stoppedReason: "reply"` and the literal string as
220
+ `response.message`. State writes and a position field can ride
221
+ alongside:
222
+
223
+ ```typescript
224
+ finalize: ({ data }) => {
225
+ if (data.bookingId) {
226
+ return {
227
+ reply: `Booked. Confirmation: ${data.bookingId}.`,
228
+ dataUpdate: { confirmedAt: new Date().toISOString() },
229
+ complete: true,
230
+ };
231
+ }
232
+ }
233
+ ```
234
+
235
+ That single directive does three things at once. They're orthogonal
236
+ payloads — `reply`, `dataUpdate`, and the position field don't
237
+ compete for the same slot.
238
+
239
+ To skip the LLM **before** it runs (rather than from a finalize hook
240
+ *after*), use a [`PreDirective`](../reference/pre-directive.md) from
241
+ a prepare hook with `halt: true` — see below.
242
+
243
+ ## PreDirective extras (pre-LLM only)
244
+
245
+ Pre-LLM hooks (`flow.hooks.onEnter`, `step.hooks.onEnter`,
246
+ `step.hooks.prepare`) return a [`PreDirective`](../reference/pre-directive.md) —
247
+ the `Directive` variant with three extra fields that only make sense
248
+ before this turn's LLM call.
249
+
250
+ ```typescript
251
+ interface PreDirective extends Directive {
252
+ appendPrompt?: string[];
253
+ injectTools?: Tool[];
254
+ halt?: boolean;
255
+ }
256
+ ```
257
+
258
+ Lifetime is one turn. None of the three fields persist on
259
+ `session.pendingDirective` — they're stripped before the write.
260
+ Returning a PreDirective from a post-LLM hook drops these fields with
261
+ a debug log.
262
+
263
+ ### `appendPrompt` — nudge the system prompt
264
+
265
+ ```typescript
266
+ const flow = {
267
+ title: "Booking",
268
+ hooks: {
269
+ onEnter: (ctx) => {
270
+ if (ctx.context.user.tier === "vip") {
271
+ return { appendPrompt: ["Caller is a VIP — confirm preferences first."] };
272
+ }
273
+ },
274
+ },
275
+ };
276
+ ```
277
+
278
+ Each string is appended to the system prompt for this turn only.
279
+ Multiple emitters' arrays concatenate in emission order; duplicates
280
+ are preserved.
281
+
282
+ ### `injectTools` — one-shot tool surface
283
+
284
+ ```typescript
285
+ const step = {
286
+ id: "verify",
287
+ prompt: "Verify the caller before proceeding.",
288
+ hooks: {
289
+ prepare: async (ctx) => {
290
+ if (!ctx.data.verified) return { injectTools: [lookupAccount] };
291
+ },
292
+ },
293
+ };
294
+ ```
295
+
296
+ Tools listed here are added for this turn only. Multiple emitters'
297
+ arrays concatenate, then dedupe by `Tool.id` (last definition wins).
298
+
299
+ ### `halt` — skip the LLM call
300
+
301
+ ```typescript
302
+ prepare: async (ctx) => {
303
+ if (ctx.data.alreadyVerified) {
304
+ return { halt: true, reply: "Already verified. How can I help?" };
305
+ }
306
+ }
307
+ ```
308
+
309
+ When any pre-phase emitter sets `halt: true`, the LLM call is
310
+ skipped. With `reply`, the turn ends `stoppedReason: "reply"`. Without
311
+ `reply`, the turn ends `stoppedReason: "halt"` and an empty body.
312
+ Multiple emitters merge by logical-OR.
313
+
314
+ ## Recipe 5 — Dispatch from outside a turn
315
+
316
+ Tools and hooks emit directives onto the **per-turn** bus. Sometimes
317
+ the redirect comes from outside any turn — a webhook fires, a
318
+ scheduled job notices an idle session, an external system marks a
319
+ caller upgraded. There's no turn running, so there's no bus.
320
+
321
+ `Agent.dispatch(target, session)` writes a `pendingDirective` onto
322
+ the session without invoking a turn. The directive is consumed at the
323
+ **start of the next** `respond` call — before routing, before
324
+ pre-extraction, before any phase runs.
325
+
326
+ ```typescript
327
+ // Webhook handler: redirect a session from outside a turn.
328
+ import type { Directive } from "@falai/agent";
329
+
330
+ app.post("/webhook/account-upgraded", async (req, res) => {
331
+ const session = await agent.session.getOrCreate(req.body.sessionId);
332
+ await agent.dispatch(
333
+ { goTo: "VipFlow", reply: "You've been upgraded. Let's start fresh." },
334
+ session
335
+ );
336
+ res.sendStatus(204);
337
+ });
338
+ ```
339
+
340
+ Two forms:
341
+
342
+ ```typescript
343
+ // String shorthand — desugars to { goTo: "Feedback" }
344
+ await agent.dispatch("Feedback", session);
345
+
346
+ // Full directive
347
+ await agent.dispatch({ goTo: "Billing", reply: "Transferring you now." }, session);
348
+ ```
349
+
350
+ The call validates the directive (`flow.validate`), confirms any
351
+ `goTo`-named flow exists (throws `FlowConfigurationError` if not),
352
+ strips PreDirective-only fields, writes `pendingDirective` onto the
353
+ session, and persists if an adapter is configured.
354
+
355
+ `pendingDirective` is **single-shot** — consumed exactly once and
356
+ cleared. Calling `dispatch` again before the next turn overwrites the
357
+ previous one (last-wins). To merge with a pending directive instead
358
+ of overwriting, use `flow.merge`:
359
+
360
+ ```typescript
361
+ import { flow } from "@falai/agent";
362
+
363
+ const merged = flow.merge(
364
+ session.pendingDirective ?? {},
365
+ { dataUpdate: { tier: "vip" } }
366
+ );
367
+ await agent.dispatch(merged, session);
368
+ ```
369
+
370
+ ## Picking the right tool
371
+
372
+ Where to emit:
373
+
374
+ | You're in a... | Type | Use |
375
+ |----------------|------|-----|
376
+ | Tool handler, mid-flight | `Directive` | `ctx.dispatch(d)` |
377
+ | Tool handler, on return | `Directive` | `return { data, directive: d }` |
378
+ | `prepare` / `onEnter` hook | `PreDirective` | `return d` |
379
+ | `finalize` / `onComplete` hook | `Directive` | `return d` |
380
+ | Branch `then` target | `Directive` | `then: d` (see [Branching](./branching.md)) |
381
+ | Outside a turn (webhook, job) | `Directive` | `await agent.dispatch(d, session)` |
382
+
383
+ Which position field:
384
+
385
+ - Inside the same flow → `goToStep`.
386
+ - Another flow → `goTo` (or `goToStep` with `flow:` set).
387
+ - Work is done → `complete` (with `complete.next` for follow-ups).
388
+ - No path forward → `abort` (`clearSession: true` if reuse is unsafe).
389
+ - Start the flow over → `reset`.
390
+
391
+ Code or model speaking:
392
+
393
+ - Verbatim → set `reply`.
394
+ - From the model → leave `reply` unset; let the LLM call run.
395
+
396
+ ## See also
397
+
398
+ - [Directive reference](../reference/directive.md) — every field,
399
+ every shorthand, every validation rule.
400
+ - [PreDirective reference](../reference/pre-directive.md) —
401
+ pre-LLM-only fields and merge rules.
402
+ - [Directives concept](../concepts/directives.md) — the mental model
403
+ and the inheritance chain.
404
+ - [Branching](./branching.md) — when the redirect is source-local
405
+ rather than dynamic.
406
+ - [Turn pipeline](../concepts/pipeline.md) — when and where directives
407
+ apply within a turn.
408
+
409
+ **Next:** [Instructions](./instructions.md)
@@ -0,0 +1,210 @@
1
+ ---
2
+ title: "Instructions"
3
+ description: "Shape how the agent talks with must / never / should at agent, flow, and step scope, and read back exactly which ones fired."
4
+ type: guide
5
+ order: 4
6
+ ---
7
+
8
+ # Instructions
9
+
10
+ Use `Instruction` when the agent should always confirm dates, never quote prices it has not looked up, or — only inside the booking flow — try to compare two options before committing. One primitive covers all three. Severity comes from `kind`. Reach comes from where you declare the instruction. The framework reports back which instructions actually rendered on each turn, so the behavior surface is observable, not guessed.
11
+
12
+ This guide assumes a `createAgent` scaffold. If you need one, start from [Your first agent](../start/02-first-agent.md).
13
+
14
+ ## Instruction shape
15
+
16
+ An `Instruction` is a plain object with one required field — `prompt` — and a handful of optional ones. The full contract lives in the [Instruction reference](../reference/instruction.md); the working subset for this guide is:
17
+
18
+ ```typescript
19
+ import type { Instruction } from "@falai/agent";
20
+
21
+ const ins: Instruction = {
22
+ kind: "must", // 'must' | 'never' | 'should' (default 'should')
23
+ when: "User asks about pricing", // optional AI-evaluated activation
24
+ if: (ctx) => ctx.context.tier === "pro", // optional code-evaluated activation
25
+ prompt: "Quote only rates fetched from the live API this turn.",
26
+ };
27
+ ```
28
+
29
+ `prompt` is the behavioral text. `kind` declares severity. `when` and `if` gate the instruction by activation, with `if` running first and `when` only evaluated if `if` passes. Everything else (`id`, `enabled`, `tags`, `metadata`) is bookkeeping you can ignore until you need it.
30
+
31
+ ## The three `kind` values
32
+
33
+ `kind` answers *how strict is this?* Three values, no inheritance, no ordering:
34
+
35
+ | `kind` | Use it for | Example |
36
+ |--------|------------|---------|
37
+ | `must` | Absolute do. The agent is required to follow it whenever rendered. | `"Validate dates are in the future before booking."` |
38
+ | `never` | Absolute don't. The agent is forbidden from doing it. | `"Promise rates you have not looked up."` |
39
+ | `should` | Conditional nudge. Default kind. The agent should try, but it's not a hard line. | `"Offer to compare two options before committing."` |
40
+
41
+ Default is `should`. Reach for `must` or `never` only when the behavior is non-negotiable — they are louder in the prompt and less forgiving in tone. If three flows each need the same `must`, declare it once at the agent scope; if it only matters for one flow, declare it there.
42
+
43
+ ## Agent vs flow vs step scope
44
+
45
+ The same shape attaches at three positions:
46
+
47
+ ```typescript
48
+ createAgent({
49
+ instructions: [/* agent scope — every turn, every flow */],
50
+ flows: [
51
+ {
52
+ title: "Booking",
53
+ instructions: [/* flow scope — only when 'Booking' is active */],
54
+ steps: [
55
+ {
56
+ id: "payment",
57
+ instructions: [/* step scope — only when 'payment' is the current step */],
58
+ },
59
+ ],
60
+ },
61
+ ],
62
+ });
63
+ ```
64
+
65
+ Reach narrows as you nest. Agent-scope instructions render on every turn for every flow. Flow-scope instructions render only while that flow is active. Step-scope instructions render only while that step is current. Conditions on `when` and `if` apply on top — an agent-scope instruction with `when: "User is angry"` still requires that activation to fire, just like a step-scope one.
66
+
67
+ The composer renders the resolved set under a single `## Instructions` heading and tags each line with a scope caption so the model can read both *what* and *where from* in one pass:
68
+
69
+ | Scope | Caption | When it appears |
70
+ |-------|---------|-----------------|
71
+ | Agent | `[Always]` | Every turn. |
72
+ | Flow | `[In: <FlowTitle>]` | While the named flow is active. |
73
+ | Step | `[Step: <stepId>]` | While the named step is current. |
74
+
75
+ ## Rendering format
76
+
77
+ Each active instruction lands in the prompt as a single bullet:
78
+
79
+ ```
80
+ - [<kind>] [<scope>] <prompt>
81
+ ```
82
+
83
+ A composed block looks like this:
84
+
85
+ ```
86
+ ## Instructions
87
+
88
+ - [must] [Always] Validate dates are in the future before booking.
89
+ - [never] [Always] Promise rates you have not looked up.
90
+ - [should] [In: Booking] Offer to compare two options before committing.
91
+ - [must] [Step: payment] If the card is declined, never retry without confirmation.
92
+ ```
93
+
94
+ The format is fixed. The kind prefix is always present (defaulting to `[should]`), the scope caption is always present, and the prompt text follows verbatim. There is nothing to configure — what you write in `prompt` is what the model reads.
95
+
96
+ ## `appliedInstructions` on the response
97
+
98
+ Every `respond()` call returns an `appliedInstructions` array listing exactly which instructions were rendered into that turn's prompt. The set is deterministic — it comes from the prompt composer, not the model — so you can use it for observability, audits, and tests:
99
+
100
+ ```typescript
101
+ const response = await agent.respond("I want to book a room.");
102
+
103
+ for (const a of response.appliedInstructions ?? []) {
104
+ console.log(`${a.scope}${a.scopeRef ? `:${a.scopeRef}` : ""} → ${a.id}`);
105
+ }
106
+ // global → ins_validate_dates
107
+ // global → ins_no_unquoted_prices
108
+ // flow:Booking → ins_offer_two_options
109
+ ```
110
+
111
+ Each `AppliedInstruction` carries the firing instruction's `id`, the originating `scope`, and a `scopeRef` that is the `flowTitle` for flow scope, the `stepId` for step scope, and `undefined` for agent scope. If you want stable ids in the report, set `id` on the instructions you care about — otherwise the framework auto-generates them.
112
+
113
+ The same array lands on the final chunk of `respondStream`:
114
+
115
+ ```typescript
116
+ for await (const chunk of agent.respondStream("I want to book a room.")) {
117
+ if (chunk.done) {
118
+ console.log("rendered:", chunk.appliedInstructions);
119
+ }
120
+ }
121
+ ```
122
+
123
+ `appliedInstructions` is empty on intermediate chunks and populated only when `done: true`.
124
+
125
+ ## Recipe: agent-level absolutes
126
+
127
+ Two house rules every flow must respect:
128
+
129
+ ```typescript
130
+ const agent = createAgent({
131
+ name: "BookingBot",
132
+ provider: new GeminiProvider({ apiKey: process.env.GEMINI_API_KEY! }),
133
+ instructions: [
134
+ { id: "ins_validate_dates", kind: "must", prompt: "Validate dates are in the future before booking." },
135
+ { id: "ins_no_unquoted", kind: "never", prompt: "Promise rates you have not looked up." },
136
+ ],
137
+ flows: [/* ... */],
138
+ });
139
+ ```
140
+
141
+ These render with caption `[Always]` on every turn, regardless of which flow is active.
142
+
143
+ ## Recipe: flow-level conditional
144
+
145
+ A flow-scope nudge that only fires when the user is comparison shopping:
146
+
147
+ ```typescript
148
+ const booking = {
149
+ title: "Booking",
150
+ instructions: [
151
+ {
152
+ id: "ins_offer_two_options",
153
+ kind: "should",
154
+ when: "User is comparing options or asking which is better",
155
+ prompt: "Offer to compare two options side by side before recommending one.",
156
+ },
157
+ ],
158
+ steps: [/* ... */],
159
+ };
160
+ ```
161
+
162
+ While `Booking` is active, the line renders with caption `[In: Booking]` only on turns where the AI condition resolves true. On other turns the entry stays out of the prompt and out of `appliedInstructions`.
163
+
164
+ ## Recipe: step-level reminder
165
+
166
+ A `must` that scopes to a specific step, gated by a code condition:
167
+
168
+ ```typescript
169
+ const paymentStep = {
170
+ id: "payment",
171
+ prompt: "Take payment.",
172
+ instructions: [
173
+ {
174
+ id: "ins_no_retry_on_decline",
175
+ kind: "must",
176
+ if: (ctx) => ctx.data.lastChargeStatus === "declined",
177
+ prompt: "If the card is declined, never retry without explicit user confirmation.",
178
+ },
179
+ ],
180
+ };
181
+ ```
182
+
183
+ Renders with caption `[Step: payment]` only while `payment` is the current step *and* the most recent charge was declined. Move off the step or change `lastChargeStatus`, and it drops out cleanly.
184
+
185
+ ## Recipe: reading `appliedInstructions` in a test
186
+
187
+ Because the set is deterministic, you can assert against it directly:
188
+
189
+ ```typescript
190
+ import { test, expect } from "bun:test";
191
+
192
+ test("payment step renders the no-retry rule when the card was declined", async () => {
193
+ const response = await agent.respond("Try again.", {
194
+ sessionId: "s_1",
195
+ initialContext: {},
196
+ initialData: { lastChargeStatus: "declined" },
197
+ });
198
+
199
+ const ids = response.appliedInstructions?.map(a => a.id) ?? [];
200
+ expect(ids).toContain("ins_no_retry_on_decline");
201
+ });
202
+ ```
203
+
204
+ No fixtures, no LLM mocks — the rendered set is computable from configuration and condition state.
205
+
206
+ ## Where this fits
207
+
208
+ `Instruction` shapes how the agent *talks*. To shape what it *does* — redirect, complete, abort — return a [Directive](../reference/directive.md) from a tool or hook (covered in [Flow control](./flow-control.md)). The two surfaces compose: an instruction nudges the model to confirm dates, a tool's directive completes the flow once the booking is written.
209
+
210
+ **Next:** [Persistence](./persistence.md)