@falai/agent 0.6.8 → 0.7.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 (231) hide show
  1. package/README.md +62 -59
  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.js +7 -7
  7. package/dist/adapters/OpenSearchAdapter.js.map +1 -1
  8. package/dist/adapters/PostgreSQLAdapter.js +9 -9
  9. package/dist/adapters/PostgreSQLAdapter.js.map +1 -1
  10. package/dist/adapters/PrismaAdapter.js +3 -3
  11. package/dist/adapters/PrismaAdapter.js.map +1 -1
  12. package/dist/adapters/RedisAdapter.js +2 -2
  13. package/dist/adapters/RedisAdapter.js.map +1 -1
  14. package/dist/adapters/SQLiteAdapter.d.ts +3 -3
  15. package/dist/adapters/SQLiteAdapter.d.ts.map +1 -1
  16. package/dist/adapters/SQLiteAdapter.js +11 -11
  17. package/dist/adapters/SQLiteAdapter.js.map +1 -1
  18. package/dist/adapters/index.d.ts +1 -1
  19. package/dist/adapters/index.d.ts.map +1 -1
  20. package/dist/cjs/adapters/MemoryAdapter.js +2 -2
  21. package/dist/cjs/adapters/MemoryAdapter.js.map +1 -1
  22. package/dist/cjs/adapters/MongoAdapter.js +2 -2
  23. package/dist/cjs/adapters/MongoAdapter.js.map +1 -1
  24. package/dist/cjs/adapters/OpenSearchAdapter.js +7 -7
  25. package/dist/cjs/adapters/OpenSearchAdapter.js.map +1 -1
  26. package/dist/cjs/adapters/PostgreSQLAdapter.js +9 -9
  27. package/dist/cjs/adapters/PostgreSQLAdapter.js.map +1 -1
  28. package/dist/cjs/adapters/PrismaAdapter.js +3 -3
  29. package/dist/cjs/adapters/PrismaAdapter.js.map +1 -1
  30. package/dist/cjs/adapters/RedisAdapter.js +2 -2
  31. package/dist/cjs/adapters/RedisAdapter.js.map +1 -1
  32. package/dist/cjs/adapters/SQLiteAdapter.d.ts +3 -3
  33. package/dist/cjs/adapters/SQLiteAdapter.d.ts.map +1 -1
  34. package/dist/cjs/adapters/SQLiteAdapter.js +11 -11
  35. package/dist/cjs/adapters/SQLiteAdapter.js.map +1 -1
  36. package/dist/cjs/adapters/index.d.ts +1 -1
  37. package/dist/cjs/adapters/index.d.ts.map +1 -1
  38. package/dist/cjs/constants/index.d.ts +4 -4
  39. package/dist/cjs/constants/index.js +5 -5
  40. package/dist/cjs/core/Agent.d.ts +22 -22
  41. package/dist/cjs/core/Agent.d.ts.map +1 -1
  42. package/dist/cjs/core/Agent.js +160 -152
  43. package/dist/cjs/core/Agent.js.map +1 -1
  44. package/dist/cjs/core/Events.d.ts +6 -6
  45. package/dist/cjs/core/Events.d.ts.map +1 -1
  46. package/dist/cjs/core/PersistenceManager.d.ts +13 -13
  47. package/dist/cjs/core/PersistenceManager.d.ts.map +1 -1
  48. package/dist/cjs/core/PersistenceManager.js +24 -24
  49. package/dist/cjs/core/PersistenceManager.js.map +1 -1
  50. package/dist/cjs/core/ResponseEngine.d.ts +3 -8
  51. package/dist/cjs/core/ResponseEngine.d.ts.map +1 -1
  52. package/dist/cjs/core/ResponseEngine.js +8 -8
  53. package/dist/cjs/core/ResponseEngine.js.map +1 -1
  54. package/dist/cjs/core/Route.d.ts +17 -17
  55. package/dist/cjs/core/Route.d.ts.map +1 -1
  56. package/dist/cjs/core/Route.js +33 -33
  57. package/dist/cjs/core/Route.js.map +1 -1
  58. package/dist/cjs/core/RoutingEngine.d.ts +30 -30
  59. package/dist/cjs/core/RoutingEngine.d.ts.map +1 -1
  60. package/dist/cjs/core/RoutingEngine.js +192 -192
  61. package/dist/cjs/core/RoutingEngine.js.map +1 -1
  62. package/dist/cjs/core/Step.d.ts +72 -0
  63. package/dist/cjs/core/Step.d.ts.map +1 -0
  64. package/dist/cjs/core/Step.js +150 -0
  65. package/dist/cjs/core/Step.js.map +1 -0
  66. package/dist/cjs/core/ToolExecutor.d.ts +5 -5
  67. package/dist/cjs/core/ToolExecutor.d.ts.map +1 -1
  68. package/dist/cjs/core/ToolExecutor.js +8 -8
  69. package/dist/cjs/core/ToolExecutor.js.map +1 -1
  70. package/dist/cjs/core/Transition.d.ts +14 -14
  71. package/dist/cjs/core/Transition.d.ts.map +1 -1
  72. package/dist/cjs/core/Transition.js +48 -19
  73. package/dist/cjs/core/Transition.js.map +1 -1
  74. package/dist/cjs/index.d.ts +7 -7
  75. package/dist/cjs/index.d.ts.map +1 -1
  76. package/dist/cjs/index.js +8 -8
  77. package/dist/cjs/index.js.map +1 -1
  78. package/dist/cjs/types/agent.d.ts +8 -8
  79. package/dist/cjs/types/agent.d.ts.map +1 -1
  80. package/dist/cjs/types/ai.d.ts +2 -2
  81. package/dist/cjs/types/ai.d.ts.map +1 -1
  82. package/dist/cjs/types/history.d.ts +3 -3
  83. package/dist/cjs/types/history.d.ts.map +1 -1
  84. package/dist/cjs/types/index.d.ts +1 -1
  85. package/dist/cjs/types/index.d.ts.map +1 -1
  86. package/dist/cjs/types/persistence.d.ts +5 -5
  87. package/dist/cjs/types/persistence.d.ts.map +1 -1
  88. package/dist/cjs/types/route.d.ts +57 -52
  89. package/dist/cjs/types/route.d.ts.map +1 -1
  90. package/dist/cjs/types/session.d.ts +27 -27
  91. package/dist/cjs/types/session.d.ts.map +1 -1
  92. package/dist/cjs/types/session.js +48 -50
  93. package/dist/cjs/types/session.js.map +1 -1
  94. package/dist/cjs/types/tool.d.ts +13 -13
  95. package/dist/cjs/types/tool.d.ts.map +1 -1
  96. package/dist/cjs/utils/id.d.ts +8 -3
  97. package/dist/cjs/utils/id.d.ts.map +1 -1
  98. package/dist/cjs/utils/id.js +16 -7
  99. package/dist/cjs/utils/id.js.map +1 -1
  100. package/dist/constants/index.d.ts +4 -4
  101. package/dist/constants/index.js +4 -4
  102. package/dist/core/Agent.d.ts +22 -22
  103. package/dist/core/Agent.d.ts.map +1 -1
  104. package/dist/core/Agent.js +162 -154
  105. package/dist/core/Agent.js.map +1 -1
  106. package/dist/core/Events.d.ts +6 -6
  107. package/dist/core/Events.d.ts.map +1 -1
  108. package/dist/core/PersistenceManager.d.ts +13 -13
  109. package/dist/core/PersistenceManager.d.ts.map +1 -1
  110. package/dist/core/PersistenceManager.js +25 -25
  111. package/dist/core/PersistenceManager.js.map +1 -1
  112. package/dist/core/ResponseEngine.d.ts +3 -8
  113. package/dist/core/ResponseEngine.d.ts.map +1 -1
  114. package/dist/core/ResponseEngine.js +8 -8
  115. package/dist/core/ResponseEngine.js.map +1 -1
  116. package/dist/core/Route.d.ts +17 -17
  117. package/dist/core/Route.d.ts.map +1 -1
  118. package/dist/core/Route.js +33 -33
  119. package/dist/core/Route.js.map +1 -1
  120. package/dist/core/RoutingEngine.d.ts +30 -30
  121. package/dist/core/RoutingEngine.d.ts.map +1 -1
  122. package/dist/core/RoutingEngine.js +193 -193
  123. package/dist/core/RoutingEngine.js.map +1 -1
  124. package/dist/core/Step.d.ts +72 -0
  125. package/dist/core/Step.d.ts.map +1 -0
  126. package/dist/core/Step.js +146 -0
  127. package/dist/core/Step.js.map +1 -0
  128. package/dist/core/ToolExecutor.d.ts +5 -5
  129. package/dist/core/ToolExecutor.d.ts.map +1 -1
  130. package/dist/core/ToolExecutor.js +8 -8
  131. package/dist/core/ToolExecutor.js.map +1 -1
  132. package/dist/core/Transition.d.ts +14 -14
  133. package/dist/core/Transition.d.ts.map +1 -1
  134. package/dist/core/Transition.js +48 -19
  135. package/dist/core/Transition.js.map +1 -1
  136. package/dist/index.d.ts +7 -7
  137. package/dist/index.d.ts.map +1 -1
  138. package/dist/index.js +4 -4
  139. package/dist/index.js.map +1 -1
  140. package/dist/types/agent.d.ts +8 -8
  141. package/dist/types/agent.d.ts.map +1 -1
  142. package/dist/types/ai.d.ts +2 -2
  143. package/dist/types/ai.d.ts.map +1 -1
  144. package/dist/types/history.d.ts +3 -3
  145. package/dist/types/history.d.ts.map +1 -1
  146. package/dist/types/index.d.ts +1 -1
  147. package/dist/types/index.d.ts.map +1 -1
  148. package/dist/types/persistence.d.ts +5 -5
  149. package/dist/types/persistence.d.ts.map +1 -1
  150. package/dist/types/route.d.ts +57 -52
  151. package/dist/types/route.d.ts.map +1 -1
  152. package/dist/types/session.d.ts +27 -27
  153. package/dist/types/session.d.ts.map +1 -1
  154. package/dist/types/session.js +44 -46
  155. package/dist/types/session.js.map +1 -1
  156. package/dist/types/tool.d.ts +13 -13
  157. package/dist/types/tool.d.ts.map +1 -1
  158. package/dist/utils/id.d.ts +8 -3
  159. package/dist/utils/id.d.ts.map +1 -1
  160. package/dist/utils/id.js +14 -6
  161. package/dist/utils/id.js.map +1 -1
  162. package/docs/ADAPTERS.md +21 -21
  163. package/docs/AGENT.md +57 -55
  164. package/docs/API_REFERENCE.md +218 -220
  165. package/docs/ARCHITECTURE.md +99 -104
  166. package/docs/CONTEXT_MANAGEMENT.md +81 -88
  167. package/docs/DOCS.md +18 -18
  168. package/docs/DOMAINS.md +16 -16
  169. package/docs/EXAMPLES.md +43 -43
  170. package/docs/GETTING_STARTED.md +60 -63
  171. package/docs/PERSISTENCE.md +66 -70
  172. package/docs/PROVIDERS.md +2 -2
  173. package/docs/README.md +6 -6
  174. package/docs/ROUTES.md +218 -220
  175. package/docs/STEPS.md +883 -0
  176. package/examples/business-onboarding.ts +84 -81
  177. package/examples/company-qna-agent.ts +68 -67
  178. package/examples/custom-database-persistence.ts +87 -89
  179. package/examples/declarative-agent.ts +32 -32
  180. package/examples/domain-scoping.ts +18 -18
  181. package/examples/extracted-data-modification.ts +92 -97
  182. package/examples/healthcare-agent.ts +89 -91
  183. package/examples/openai-agent.ts +29 -32
  184. package/examples/opensearch-persistence.ts +43 -45
  185. package/examples/persistent-onboarding.ts +65 -66
  186. package/examples/prisma-persistence.ts +108 -112
  187. package/examples/prisma-schema.example.prisma +3 -3
  188. package/examples/redis-persistence.ts +67 -73
  189. package/examples/route-transitions.ts +71 -47
  190. package/examples/rules-prohibitions.ts +28 -28
  191. package/examples/streaming-agent.ts +24 -24
  192. package/examples/travel-agent.ts +94 -109
  193. package/package.json +1 -1
  194. package/src/adapters/MemoryAdapter.ts +3 -3
  195. package/src/adapters/MongoAdapter.ts +3 -3
  196. package/src/adapters/OpenSearchAdapter.ts +8 -8
  197. package/src/adapters/PostgreSQLAdapter.ts +10 -10
  198. package/src/adapters/PrismaAdapter.ts +4 -4
  199. package/src/adapters/RedisAdapter.ts +3 -3
  200. package/src/adapters/SQLiteAdapter.ts +15 -15
  201. package/src/adapters/index.ts +1 -1
  202. package/src/constants/index.ts +4 -4
  203. package/src/core/Agent.ts +210 -206
  204. package/src/core/Events.ts +12 -12
  205. package/src/core/PersistenceManager.ts +32 -36
  206. package/src/core/ResponseEngine.ts +11 -17
  207. package/src/core/Route.ts +55 -49
  208. package/src/core/RoutingEngine.ts +244 -252
  209. package/src/core/Step.ts +197 -0
  210. package/src/core/ToolExecutor.ts +11 -11
  211. package/src/core/Transition.ts +72 -26
  212. package/src/index.ts +8 -8
  213. package/src/types/agent.ts +8 -8
  214. package/src/types/ai.ts +2 -2
  215. package/src/types/history.ts +3 -3
  216. package/src/types/index.ts +1 -1
  217. package/src/types/persistence.ts +6 -6
  218. package/src/types/route.ts +77 -61
  219. package/src/types/session.ts +75 -78
  220. package/src/types/tool.ts +17 -17
  221. package/src/utils/id.ts +15 -6
  222. package/dist/cjs/core/State.d.ts +0 -72
  223. package/dist/cjs/core/State.d.ts.map +0 -1
  224. package/dist/cjs/core/State.js +0 -148
  225. package/dist/cjs/core/State.js.map +0 -1
  226. package/dist/core/State.d.ts +0 -72
  227. package/dist/core/State.d.ts.map +0 -1
  228. package/dist/core/State.js +0 -144
  229. package/dist/core/State.js.map +0 -1
  230. package/docs/STATES.md +0 -888
  231. package/src/core/State.ts +0 -212
package/docs/STATES.md DELETED
@@ -1,888 +0,0 @@
1
- # States Guide
2
-
3
- A complete guide to creating and managing states in conversational flows.
4
-
5
- ---
6
-
7
- ## Table of Contents
8
-
9
- - [What is a State?](#what-is-a-state)
10
- - [Creating States](#creating-states)
11
- - [State Configuration](#state-configuration)
12
- - [Transitions](#transitions)
13
- - [Data Gathering](#data-gathering)
14
- - [State Logic](#state-logic)
15
- - [State Types](#state-types)
16
- - [Advanced Patterns](#advanced-patterns)
17
-
18
- ---
19
-
20
- ## What is a State?
21
-
22
- A **State** represents a specific step or moment in a conversation. Each state can:
23
-
24
- - Display a message to the user (chat state)
25
- - Execute a tool (tool state)
26
- - Gather data from the conversation
27
- - Make decisions about what to do next
28
-
29
- ```typescript
30
- // Example: A state that asks for user's name
31
- const askName = route.initialState.transitionTo({
32
- chatState: "What's your name?",
33
- gather: ["firstName", "lastName"],
34
- });
35
- ```
36
-
37
- **Key Concepts:**
38
-
39
- - States form a **state machine** within a route
40
- - Each state has a unique **ID** (auto-generated or custom)
41
- - States can **gather data** from user responses
42
- - States can be **skipped** based on conditions
43
- - States can have **prerequisites** (required data)
44
-
45
- ---
46
-
47
- ## Creating States
48
-
49
- ### Chat States
50
-
51
- Chat states present a message and optionally gather data:
52
-
53
- ```typescript
54
- // Simple chat state
55
- const welcome = route.initialState.transitionTo({
56
- chatState: "Welcome! How can I help you today?",
57
- });
58
-
59
- // Chat state with data gathering
60
- const askDestination = welcome.transitionTo({
61
- chatState: "Where would you like to fly?",
62
- gather: ["destination"],
63
- });
64
-
65
- // Chat state with custom ID
66
- const askDates = askDestination.transitionTo({
67
- id: "ask_travel_dates",
68
- chatState: "When would you like to depart?",
69
- gather: ["departureDate"],
70
- });
71
- ```
72
-
73
- ### Tool States
74
-
75
- Tool states execute functions and can update context or extracted data:
76
-
77
- ```typescript
78
- import { defineTool } from "@falai/agent";
79
-
80
- const searchFlights = defineTool<Context, [], Results>(
81
- "search_flights",
82
- async ({ context, extracted }) => {
83
- const results = await api.search(extracted.destination);
84
- return {
85
- data: results,
86
- contextUpdate: { availableFlights: results },
87
- };
88
- }
89
- );
90
-
91
- // Tool state
92
- const searchState = askDates.transitionTo({
93
- toolState: searchFlights,
94
- requiredData: ["destination", "departureDate"],
95
- });
96
- ```
97
-
98
- ### Direct State References
99
-
100
- Jump to specific states or end the route:
101
-
102
- ```typescript
103
- import { END_STATE } from "@falai/agent";
104
-
105
- // Jump to another state
106
- const confirm = processPayment.transitionTo({
107
- state: previousState.getRef(), // Jump back
108
- });
109
-
110
- // End the route
111
- const complete = confirm.transitionTo({
112
- state: END_STATE,
113
- });
114
- ```
115
-
116
- ---
117
-
118
- ## State Configuration
119
-
120
- ### Configuring Initial State
121
-
122
- Every route has an initial state that can be configured:
123
-
124
- ```typescript
125
- // Option 1: Configure at route creation
126
- const route = agent.createRoute({
127
- title: "Booking",
128
- initialState: {
129
- id: "welcome",
130
- chatState: "Welcome to our booking system!",
131
- gather: ["intention"],
132
- },
133
- });
134
-
135
- // Option 2: Configure after creation
136
- route.initialState.configure({
137
- description: "Welcome! Let's start booking",
138
- gatherFields: ["destination"],
139
- skipIf: (extracted) => !!extracted.destination,
140
- requiredData: [],
141
- });
142
- ```
143
-
144
- ### Configuring Any State
145
-
146
- You can configure any state after creation:
147
-
148
- ```typescript
149
- const askName = route.initialState.transitionTo({
150
- chatState: "What's your name?",
151
- });
152
-
153
- // Later, reconfigure it
154
- askName.configure({
155
- description: "Ask for user's full name",
156
- gatherFields: ["firstName", "lastName"],
157
- skipIf: (extracted) => !!extracted.firstName && !!extracted.lastName,
158
- });
159
-
160
- // Chaining is supported
161
- askName
162
- .configure({ description: "Updated description" })
163
- .configure({ gatherFields: ["fullName"] });
164
- ```
165
-
166
- ### Configuration Options
167
-
168
- ```typescript
169
- state.configure({
170
- // State description
171
- description?: string;
172
-
173
- // Fields to gather from conversation
174
- gatherFields?: string[];
175
-
176
- // Skip this state if condition is met
177
- skipIf?: (extracted: Partial<TExtracted>) => boolean;
178
-
179
- // Prerequisites that must be met before entering
180
- requiredData?: string[];
181
- });
182
- ```
183
-
184
- ---
185
-
186
- ## Transitions
187
-
188
- ### Transition Specification
189
-
190
- Every transition from one state to another uses a `TransitionSpec`:
191
-
192
- ```typescript
193
- interface TransitionSpec<TExtracted = unknown> {
194
- // Custom state ID (optional)
195
- id?: string;
196
-
197
- // Chat state description
198
- chatState?: string;
199
-
200
- // Tool to execute
201
- toolState?: ToolRef;
202
-
203
- // Direct state reference or END_STATE
204
- state?: StateRef | symbol;
205
-
206
- // Fields to gather in this state
207
- gather?: string[];
208
-
209
- // Skip condition (code-based)
210
- skipIf?: (extracted: Partial<TExtracted>) => boolean;
211
-
212
- // Prerequisites
213
- requiredData?: string[];
214
-
215
- // AI-evaluated condition (for state selection)
216
- condition?: string;
217
- }
218
- ```
219
-
220
- ### Transition Chaining
221
-
222
- ```typescript
223
- // Linear flow
224
- route.initialState
225
- .transitionTo({
226
- chatState: "Step 1",
227
- gather: ["field1"],
228
- })
229
- .transitionTo({
230
- chatState: "Step 2",
231
- gather: ["field2"],
232
- })
233
- .transitionTo({
234
- chatState: "Step 3",
235
- gather: ["field3"],
236
- })
237
- .transitionTo({ state: END_STATE });
238
- ```
239
-
240
- ### Branching Transitions
241
-
242
- ```typescript
243
- const askType = route.initialState.transitionTo({
244
- chatState: "Are you booking a flight or hotel?",
245
- gather: ["bookingType"],
246
- });
247
-
248
- // Branch 1: Flight booking
249
- const flightFlow = askType.transitionTo({
250
- chatState: "Let's book your flight",
251
- condition: "User selected flight",
252
- });
253
-
254
- // Branch 2: Hotel booking
255
- const hotelFlow = askType.transitionTo({
256
- chatState: "Let's book your hotel",
257
- condition: "User selected hotel",
258
- });
259
-
260
- // Both branches can converge later
261
- const payment = flightFlow.transitionTo({
262
- chatState: "Let's process payment",
263
- });
264
-
265
- hotelFlow.transitionTo({ state: payment }); // Converge to payment
266
- ```
267
-
268
- ---
269
-
270
- ## Data Gathering
271
-
272
- ### Basic Gathering
273
-
274
- Specify which fields to extract in each state:
275
-
276
- ```typescript
277
- interface UserData {
278
- firstName: string;
279
- lastName: string;
280
- email: string;
281
- phone: string;
282
- }
283
-
284
- const route = agent.createRoute<UserData>({ ... });
285
-
286
- // Gather single field
287
- const askName = route.initialState.transitionTo({
288
- chatState: "What's your first name?",
289
- gather: ["firstName"],
290
- });
291
-
292
- // Gather multiple fields at once
293
- const askContact = askName.transitionTo({
294
- chatState: "Please provide your email and phone number",
295
- gather: ["email", "phone"],
296
- });
297
- ```
298
-
299
- ### Gathering with Schema Validation
300
-
301
- The extraction schema validates gathered data:
302
-
303
- ```typescript
304
- const route = agent.createRoute<UserData>({
305
- title: "User Registration",
306
-
307
- extractionSchema: {
308
- type: "object",
309
- properties: {
310
- firstName: {
311
- type: "string",
312
- minLength: 1,
313
- },
314
- email: {
315
- type: "string",
316
- format: "email", // Validates email format
317
- },
318
- age: {
319
- type: "number",
320
- minimum: 18,
321
- maximum: 120,
322
- },
323
- },
324
- required: ["firstName", "email"],
325
- },
326
- });
327
-
328
- // AI will extract and validate according to schema
329
- const askInfo = route.initialState.transitionTo({
330
- chatState: "Please provide your name, email, and age",
331
- gather: ["firstName", "email", "age"],
332
- });
333
- ```
334
-
335
- ### Conditional Gathering
336
-
337
- Use `skipIf` to avoid re-asking for data:
338
-
339
- ```typescript
340
- const askDestination = route.initialState.transitionTo({
341
- chatState: "Where would you like to go?",
342
- gather: ["destination"],
343
- // Skip if we already have the destination
344
- skipIf: (extracted) => !!extracted.destination,
345
- });
346
-
347
- const askDates = askDestination.transitionTo({
348
- chatState: "When would you like to travel?",
349
- gather: ["departureDate", "returnDate"],
350
- // Skip if we have both dates
351
- skipIf: (extracted) => !!extracted.departureDate && !!extracted.returnDate,
352
- });
353
- ```
354
-
355
- ---
356
-
357
- ## State Logic
358
-
359
- ### Skip Conditions
360
-
361
- Control when states should be bypassed:
362
-
363
- ```typescript
364
- // Skip if data already exists
365
- const askEmail = route.initialState.transitionTo({
366
- chatState: "What's your email?",
367
- gather: ["email"],
368
- skipIf: (extracted) => !!extracted.email,
369
- });
370
-
371
- // Skip based on business logic
372
- const askShipping = askEmail.transitionTo({
373
- chatState: "What's your shipping address?",
374
- gather: ["shippingAddress"],
375
- // Skip if user selected digital product
376
- skipIf: (extracted) => extracted.productType === "digital",
377
- });
378
-
379
- // Skip based on multiple conditions
380
- const askBilling = askShipping.transitionTo({
381
- chatState: "What's your billing address?",
382
- gather: ["billingAddress"],
383
- // Skip if billing same as shipping, or already provided
384
- skipIf: (extracted) =>
385
- extracted.billingSameAsShipping === true || !!extracted.billingAddress,
386
- });
387
- ```
388
-
389
- ### Required Data
390
-
391
- Ensure prerequisites are met before entering a state:
392
-
393
- ```typescript
394
- // Can't search without destination and dates
395
- const searchFlights = askDates.transitionTo({
396
- toolState: searchFlightsTool,
397
- requiredData: ["destination", "departureDate"],
398
- });
399
-
400
- // Can't checkout without all required fields
401
- const processPayment = selectFlight.transitionTo({
402
- toolState: processPaymentTool,
403
- requiredData: [
404
- "destination",
405
- "departureDate",
406
- "selectedFlight",
407
- "paymentMethod",
408
- ],
409
- });
410
-
411
- // Multiple prerequisites
412
- const generateInvoice = processPayment.transitionTo({
413
- chatState: "Here's your invoice",
414
- requiredData: ["paymentConfirmation", "customerEmail", "bookingReference"],
415
- });
416
- ```
417
-
418
- ### State Conditions
419
-
420
- AI-evaluated conditions for state selection:
421
-
422
- ```typescript
423
- const askIssue = route.initialState.transitionTo({
424
- chatState: "What seems to be the problem?",
425
- gather: ["issueDescription"],
426
- });
427
-
428
- // Technical support path
429
- const technicalHelp = askIssue.transitionTo({
430
- chatState: "Let me help with your technical issue",
431
- condition: "Issue is technical in nature",
432
- });
433
-
434
- // Billing support path
435
- const billingHelp = askIssue.transitionTo({
436
- chatState: "Let me help with your billing issue",
437
- condition: "Issue is related to billing or payments",
438
- });
439
-
440
- // General inquiry path
441
- const generalHelp = askIssue.transitionTo({
442
- chatState: "Let me help with your question",
443
- condition: "Issue is a general inquiry",
444
- });
445
- ```
446
-
447
- ---
448
-
449
- ## State Types
450
-
451
- ### 1. Chat States
452
-
453
- Present information and gather data:
454
-
455
- ```typescript
456
- const chat = route.initialState.transitionTo({
457
- chatState: "What would you like to know?",
458
- gather: ["question"],
459
- });
460
- ```
461
-
462
- **When to use:**
463
-
464
- - Ask questions
465
- - Present information
466
- - Gather user input
467
- - Confirm actions
468
-
469
- ### 2. Tool States
470
-
471
- Execute functions:
472
-
473
- ```typescript
474
- const tool = route.initialState.transitionTo({
475
- toolState: myTool,
476
- requiredData: ["param1", "param2"],
477
- });
478
- ```
479
-
480
- **When to use:**
481
-
482
- - Call APIs
483
- - Database operations
484
- - Complex computations
485
- - External integrations
486
- - Data validation/enrichment
487
-
488
- ### 3. Initial State
489
-
490
- Every route's starting point:
491
-
492
- ```typescript
493
- route.initialState.configure({
494
- description: "Welcome message",
495
- gatherFields: ["initialInput"],
496
- });
497
- ```
498
-
499
- **When to configure:**
500
-
501
- - Set up welcome messages
502
- - Gather initial context
503
- - Set expectations
504
- - Pre-populate data
505
-
506
- ### 4. End State (Terminal State)
507
-
508
- Every route ends when it reaches `END_STATE`. You can configure what happens at completion:
509
-
510
- #### Option A: Route-Level Configuration (Recommended)
511
-
512
- ```typescript
513
- import { END_STATE } from "@falai/agent";
514
-
515
- const bookingRoute = agent.createRoute({
516
- title: "Book Flight",
517
-
518
- // Configure end state behavior
519
- endState: {
520
- chatState: "Confirm booking and thank the user!",
521
- toolState: sendConfirmationEmail, // Execute final actions
522
- gather: ["finalConfirmation"], // Gather last data
523
- },
524
- });
525
-
526
- // Later, just transition to END_STATE
527
- finalStep.transitionTo({
528
- state: END_STATE,
529
- });
530
- ```
531
-
532
- #### Option B: Per-Transition Override
533
-
534
- ```typescript
535
- // Override endState for this specific path
536
- finalStep.transitionTo({
537
- chatState: "Special completion message for VIP users!",
538
- state: END_STATE,
539
- });
540
- ```
541
-
542
- #### Option C: Default Behavior
543
-
544
- If you don't configure `endState`, a smart default completion message is generated:
545
-
546
- ```typescript
547
- finalStep.transitionTo({
548
- state: END_STATE,
549
- });
550
- // Uses default: "Summarize what was accomplished and confirm completion..."
551
- ```
552
-
553
- **End State Capabilities:**
554
-
555
- ```typescript
556
- endState: {
557
- // Completion message instruction
558
- chatState?: string;
559
-
560
- // Execute final actions (emails, database updates, etc.)
561
- toolState?: ToolRef;
562
-
563
- // Gather final data before completion
564
- gather?: string[];
565
-
566
- // Require certain data to be present
567
- requiredData?: string[];
568
-
569
- // Custom state ID for debugging
570
- id?: string;
571
- }
572
- ```
573
-
574
- **When to use END_STATE:**
575
-
576
- - ✅ Route completion - all required data collected
577
- - ✅ Success outcomes - action completed successfully
578
- - ✅ Failure outcomes - error handling completed
579
- - ✅ Before transition - handoff to another route via `onComplete`
580
-
581
- **End State with Tools:**
582
-
583
- Execute final actions when route completes:
584
-
585
- ```typescript
586
- import { defineTool, END_STATE } from "@falai/agent";
587
-
588
- const notifyTeam = defineTool("notify_team", async ({ extracted }) => {
589
- await slack.send({
590
- channel: "#bookings",
591
- message: `New booking: ${extracted.hotelName} for ${extracted.guests} guests`,
592
- });
593
- return { data: "Team notified" };
594
- });
595
-
596
- const bookingRoute = agent.createRoute({
597
- endState: {
598
- toolState: notifyTeam, // Runs when route completes
599
- chatState: "Booking complete! Our team has been notified.",
600
- },
601
- });
602
- ```
603
-
604
- **Key Points:**
605
-
606
- - ✅ Configure once at route level (DRY principle)
607
- - ✅ Can be overridden per-transition if needed
608
- - ✅ Supports full state capabilities: `chatState`, `toolState`, `gather`, `requiredData`
609
- - ✅ Automatically generates message if not configured
610
- - ✅ Executes before `onComplete` route transitions
611
-
612
- ---
613
-
614
- ## Advanced Patterns
615
-
616
- ### Pattern 1: State Loops
617
-
618
- ```typescript
619
- const askItems = route.initialState.transitionTo({
620
- chatState: "What items would you like to add to your cart?",
621
- gather: ["newItem"],
622
- });
623
-
624
- const confirmMore = askItems.transitionTo({
625
- chatState: "Would you like to add more items?",
626
- gather: ["addMore"],
627
- });
628
-
629
- // Loop back to askItems if user wants more
630
- confirmMore.transitionTo({
631
- state: askItems,
632
- condition: "User wants to add more items",
633
- });
634
-
635
- // Or continue to checkout
636
- const checkout = confirmMore.transitionTo({
637
- chatState: "Let's proceed to checkout",
638
- condition: "User is done adding items",
639
- });
640
- ```
641
-
642
- ### Pattern 2: Error Handling States
643
-
644
- ```typescript
645
- const processPayment = route.initialState.transitionTo({
646
- toolState: paymentTool,
647
- requiredData: ["amount", "paymentMethod"],
648
- });
649
-
650
- // Success path
651
- const paymentSuccess = processPayment.transitionTo({
652
- chatState: "Payment successful! Here's your receipt",
653
- condition: "Payment was successful",
654
- });
655
-
656
- // Failure path
657
- const paymentFailed = processPayment.transitionTo({
658
- chatState:
659
- "Payment failed. Would you like to try a different payment method?",
660
- gather: ["retryPayment"],
661
- condition: "Payment failed",
662
- });
663
-
664
- // Retry logic
665
- paymentFailed.transitionTo({
666
- state: processPayment,
667
- condition: "User wants to retry",
668
- });
669
- ```
670
-
671
- ### Pattern 3: Progressive Disclosure
672
-
673
- ```typescript
674
- // Start with basic info
675
- const askBasic = route.initialState.transitionTo({
676
- chatState: "Let's start with the basics. What's your name?",
677
- gather: ["name"],
678
- });
679
-
680
- // Reveal more options
681
- const askPreferences = askBasic.transitionTo({
682
- chatState: "Great! Now, would you like to customize your experience?",
683
- gather: ["wantsCustomization"],
684
- });
685
-
686
- // Only ask detailed questions if user wants customization
687
- const askDetailed = askPreferences.transitionTo({
688
- chatState: "Tell me about your preferences...",
689
- gather: ["theme", "notifications", "language"],
690
- skipIf: (extracted) => extracted.wantsCustomization === false,
691
- });
692
-
693
- const finish = askDetailed.transitionTo({
694
- chatState: "All set! Your account is ready",
695
- });
696
-
697
- // Direct path if no customization
698
- askPreferences.transitionTo({
699
- state: finish,
700
- condition: "User doesn't want customization",
701
- });
702
- ```
703
-
704
- ### Pattern 4: State Validation
705
-
706
- ```typescript
707
- const askAge = route.initialState.transitionTo({
708
- chatState: "How old are you?",
709
- gather: ["age"],
710
- });
711
-
712
- const validateAge = askAge.transitionTo({
713
- toolState: validateAgeTool,
714
- requiredData: ["age"],
715
- });
716
-
717
- // Valid age
718
- const proceed = validateAge.transitionTo({
719
- chatState: "Great! Let's continue",
720
- condition: "Age is valid",
721
- });
722
-
723
- // Invalid age - loop back
724
- validateAge.transitionTo({
725
- state: askAge,
726
- condition: "Age is invalid",
727
- });
728
- ```
729
-
730
- ### Pattern 5: Context-Aware States
731
-
732
- ```typescript
733
- const askQuestion = route.initialState.transitionTo({
734
- chatState: "What would you like to know?",
735
- gather: ["question"],
736
- });
737
-
738
- // Different responses based on user type
739
- const premiumResponse = askQuestion.transitionTo({
740
- chatState: "As a premium member, here's detailed information...",
741
- condition: "User has premium account",
742
- });
743
-
744
- const basicResponse = askQuestion.transitionTo({
745
- chatState: "Here's the basic information. Upgrade for more details!",
746
- condition: "User has basic account",
747
- });
748
- ```
749
-
750
- ---
751
-
752
- ## State Properties
753
-
754
- ### Accessing State Properties
755
-
756
- ```typescript
757
- const state = route.getState("ask_name");
758
-
759
- // State identification
760
- console.log(state.id); // "state_ask_name_abc123"
761
- console.log(state.routeId); // "route_onboarding_xyz789"
762
- console.log(state.description); // "Ask for user's name"
763
-
764
- // State configuration
765
- console.log(state.gatherFields); // ["firstName", "lastName"]
766
- console.log(state.requiredData); // ["userId"]
767
-
768
- // State logic
769
- if (state.skipIf) {
770
- const shouldSkip = state.skipIf(extractedData);
771
- console.log("Should skip:", shouldSkip);
772
- }
773
-
774
- // State guidelines
775
- state.addGuideline({
776
- condition: "User provides invalid name",
777
- action: "Ask for valid name format",
778
- });
779
- console.log(state.getGuidelines());
780
-
781
- // Transitions
782
- console.log(state.getTransitions()); // [Transition, Transition, ...]
783
- ```
784
-
785
- ### State Reference
786
-
787
- ```typescript
788
- const stateRef = state.getRef();
789
- console.log(stateRef);
790
- // { id: "state_ask_name_abc123", routeId: "route_onboarding_xyz789" }
791
-
792
- // Use reference in transitions
793
- anotherState.transitionTo({ state: stateRef });
794
- ```
795
-
796
- ---
797
-
798
- ## Best Practices
799
-
800
- ### ✅ Do's
801
-
802
- - **Use descriptive chatState** - Clear prompts for better UX
803
- - **Define gather fields** - Explicit data extraction
804
- - **Use skipIf for efficiency** - Avoid redundant questions
805
- - **Set requiredData** - Prevent premature execution
806
- - **Configure initial state** - Proper route entry point
807
- - **Use tool states for logic** - Separate concerns
808
- - **Add state-specific guidelines** - Context-aware behavior
809
-
810
- ### ❌ Don'ts
811
-
812
- - **Don't hardcode state IDs** - Let framework generate them
813
- - **Don't skip validation** - Always validate with requiredData
814
- - **Don't create circular loops** - Without exit conditions
815
- - **Don't gather unrelated data** - One concept per state
816
- - **Don't use vague conditions** - Be specific
817
- - **Don't forget skipIf** - For pre-populated data
818
- - **Don't mix chat and tool** - One type per state
819
-
820
- ---
821
-
822
- ## Troubleshooting
823
-
824
- ### State Not Being Entered
825
-
826
- ```typescript
827
- // ❌ Problem: Required data missing
828
- const state = prev.transitionTo({
829
- chatState: "Do something",
830
- requiredData: ["field1", "field2"], // Missing field2
831
- });
832
-
833
- // ✅ Solution: Ensure required data is gathered first
834
- const gatherData = prev.transitionTo({
835
- chatState: "Gather data",
836
- gather: ["field1", "field2"],
837
- });
838
-
839
- const state = gatherData.transitionTo({
840
- chatState: "Do something",
841
- requiredData: ["field1", "field2"], // Now available
842
- });
843
- ```
844
-
845
- ### State Always Skipped
846
-
847
- ```typescript
848
- // ❌ Problem: skipIf always returns true
849
- const state = prev.transitionTo({
850
- chatState: "Ask something",
851
- skipIf: (extracted) => true, // Always skips!
852
- });
853
-
854
- // ✅ Solution: Use proper condition
855
- const state = prev.transitionTo({
856
- chatState: "Ask something",
857
- skipIf: (extracted) => !!extracted.field, // Only skip if field exists
858
- });
859
- ```
860
-
861
- ### Data Not Being Gathered
862
-
863
- ```typescript
864
- // ❌ Problem: Forgot to specify gather
865
- const state = prev.transitionTo({
866
- chatState: "What's your name?",
867
- // Missing gather!
868
- });
869
-
870
- // ✅ Solution: Add gather fields
871
- const state = prev.transitionTo({
872
- chatState: "What's your name?",
873
- gather: ["firstName", "lastName"],
874
- });
875
- ```
876
-
877
- ---
878
-
879
- ## See Also
880
-
881
- - [Routes Guide](./ROUTES.md) - Understanding routes
882
- - [API Reference - State](./API_REFERENCE.md#state) - Complete API docs
883
- - [Examples](../examples/) - Real-world implementations
884
- - [Architecture Guide](./ARCHITECTURE.md) - System overview
885
-
886
- ---
887
-
888
- **Made with ❤️ for the community**