@falai/agent 0.4.1 → 0.5.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 (285) hide show
  1. package/README.md +21 -74
  2. package/dist/cjs/core/Agent.d.ts +22 -29
  3. package/dist/cjs/core/Agent.d.ts.map +1 -1
  4. package/dist/cjs/core/Agent.js +464 -291
  5. package/dist/cjs/core/Agent.js.map +1 -1
  6. package/dist/cjs/core/Events.d.ts +10 -1
  7. package/dist/cjs/core/Events.d.ts.map +1 -1
  8. package/dist/cjs/core/Events.js +3 -2
  9. package/dist/cjs/core/Events.js.map +1 -1
  10. package/dist/cjs/core/PersistenceManager.d.ts +19 -0
  11. package/dist/cjs/core/PersistenceManager.d.ts.map +1 -1
  12. package/dist/cjs/core/PersistenceManager.js +57 -0
  13. package/dist/cjs/core/PersistenceManager.js.map +1 -1
  14. package/dist/cjs/core/PromptComposer.d.ts +24 -0
  15. package/dist/cjs/core/PromptComposer.d.ts.map +1 -0
  16. package/dist/cjs/core/PromptComposer.js +127 -0
  17. package/dist/cjs/core/PromptComposer.js.map +1 -0
  18. package/dist/cjs/core/ResponseEngine.d.ts +19 -0
  19. package/dist/cjs/core/ResponseEngine.d.ts.map +1 -0
  20. package/dist/cjs/core/ResponseEngine.js +51 -0
  21. package/dist/cjs/core/ResponseEngine.js.map +1 -0
  22. package/dist/cjs/core/Route.d.ts +18 -12
  23. package/dist/cjs/core/Route.d.ts.map +1 -1
  24. package/dist/cjs/core/Route.js +15 -9
  25. package/dist/cjs/core/Route.js.map +1 -1
  26. package/dist/cjs/core/RoutingEngine.d.ts +38 -0
  27. package/dist/cjs/core/RoutingEngine.d.ts.map +1 -0
  28. package/dist/cjs/core/RoutingEngine.js +110 -0
  29. package/dist/cjs/core/RoutingEngine.js.map +1 -0
  30. package/dist/cjs/core/State.d.ts +15 -4
  31. package/dist/cjs/core/State.d.ts.map +1 -1
  32. package/dist/cjs/core/State.js +21 -2
  33. package/dist/cjs/core/State.js.map +1 -1
  34. package/dist/cjs/core/ToolExecutor.d.ts +29 -0
  35. package/dist/cjs/core/ToolExecutor.d.ts.map +1 -0
  36. package/dist/cjs/core/ToolExecutor.js +73 -0
  37. package/dist/cjs/core/ToolExecutor.js.map +1 -0
  38. package/dist/cjs/core/Transition.d.ts +5 -5
  39. package/dist/cjs/core/Transition.d.ts.map +1 -1
  40. package/dist/cjs/core/Transition.js.map +1 -1
  41. package/dist/cjs/index.d.ts +6 -8
  42. package/dist/cjs/index.d.ts.map +1 -1
  43. package/dist/cjs/index.js +8 -10
  44. package/dist/cjs/index.js.map +1 -1
  45. package/dist/cjs/providers/AnthropicProvider.d.ts.map +1 -1
  46. package/dist/cjs/providers/AnthropicProvider.js +10 -13
  47. package/dist/cjs/providers/AnthropicProvider.js.map +1 -1
  48. package/dist/cjs/providers/GeminiProvider.d.ts.map +1 -1
  49. package/dist/cjs/providers/GeminiProvider.js +12 -8
  50. package/dist/cjs/providers/GeminiProvider.js.map +1 -1
  51. package/dist/cjs/providers/OpenAIProvider.d.ts.map +1 -1
  52. package/dist/cjs/providers/OpenAIProvider.js +10 -53
  53. package/dist/cjs/providers/OpenAIProvider.js.map +1 -1
  54. package/dist/cjs/providers/OpenRouterProvider.d.ts.map +1 -1
  55. package/dist/cjs/providers/OpenRouterProvider.js +10 -53
  56. package/dist/cjs/providers/OpenRouterProvider.js.map +1 -1
  57. package/dist/cjs/types/agent.d.ts +13 -12
  58. package/dist/cjs/types/agent.d.ts.map +1 -1
  59. package/dist/cjs/types/ai.d.ts +8 -2
  60. package/dist/cjs/types/ai.d.ts.map +1 -1
  61. package/dist/cjs/types/history.d.ts +8 -0
  62. package/dist/cjs/types/history.d.ts.map +1 -1
  63. package/dist/cjs/types/index.d.ts +0 -3
  64. package/dist/cjs/types/index.d.ts.map +1 -1
  65. package/dist/cjs/types/index.js +1 -3
  66. package/dist/cjs/types/index.js.map +1 -1
  67. package/dist/cjs/types/route.d.ts +39 -4
  68. package/dist/cjs/types/route.d.ts.map +1 -1
  69. package/dist/cjs/types/routing.d.ts +16 -0
  70. package/dist/cjs/types/routing.d.ts.map +1 -0
  71. package/dist/cjs/types/routing.js +3 -0
  72. package/dist/cjs/types/routing.js.map +1 -0
  73. package/dist/cjs/types/schema.d.ts +22 -0
  74. package/dist/cjs/types/schema.d.ts.map +1 -0
  75. package/dist/cjs/types/schema.js +3 -0
  76. package/dist/cjs/types/schema.js.map +1 -0
  77. package/dist/cjs/types/session.d.ts +72 -0
  78. package/dist/cjs/types/session.d.ts.map +1 -0
  79. package/dist/cjs/types/session.js +140 -0
  80. package/dist/cjs/types/session.js.map +1 -0
  81. package/dist/cjs/types/tool.d.ts +11 -5
  82. package/dist/cjs/types/tool.d.ts.map +1 -1
  83. package/dist/cjs/utils/id.d.ts +0 -5
  84. package/dist/cjs/utils/id.d.ts.map +1 -1
  85. package/dist/cjs/utils/id.js +0 -10
  86. package/dist/cjs/utils/id.js.map +1 -1
  87. package/dist/cjs/utils/schema.d.ts +17 -0
  88. package/dist/cjs/utils/schema.d.ts.map +1 -0
  89. package/dist/cjs/utils/schema.js +32 -0
  90. package/dist/cjs/utils/schema.js.map +1 -0
  91. package/dist/core/Agent.d.ts +22 -29
  92. package/dist/core/Agent.d.ts.map +1 -1
  93. package/dist/core/Agent.js +464 -291
  94. package/dist/core/Agent.js.map +1 -1
  95. package/dist/core/Events.d.ts +10 -1
  96. package/dist/core/Events.d.ts.map +1 -1
  97. package/dist/core/Events.js +3 -2
  98. package/dist/core/Events.js.map +1 -1
  99. package/dist/core/PersistenceManager.d.ts +19 -0
  100. package/dist/core/PersistenceManager.d.ts.map +1 -1
  101. package/dist/core/PersistenceManager.js +57 -0
  102. package/dist/core/PersistenceManager.js.map +1 -1
  103. package/dist/core/PromptComposer.d.ts +24 -0
  104. package/dist/core/PromptComposer.d.ts.map +1 -0
  105. package/dist/core/PromptComposer.js +123 -0
  106. package/dist/core/PromptComposer.js.map +1 -0
  107. package/dist/core/ResponseEngine.d.ts +19 -0
  108. package/dist/core/ResponseEngine.d.ts.map +1 -0
  109. package/dist/core/ResponseEngine.js +47 -0
  110. package/dist/core/ResponseEngine.js.map +1 -0
  111. package/dist/core/Route.d.ts +18 -12
  112. package/dist/core/Route.d.ts.map +1 -1
  113. package/dist/core/Route.js +15 -9
  114. package/dist/core/Route.js.map +1 -1
  115. package/dist/core/RoutingEngine.d.ts +38 -0
  116. package/dist/core/RoutingEngine.d.ts.map +1 -0
  117. package/dist/core/RoutingEngine.js +106 -0
  118. package/dist/core/RoutingEngine.js.map +1 -0
  119. package/dist/core/State.d.ts +15 -4
  120. package/dist/core/State.d.ts.map +1 -1
  121. package/dist/core/State.js +21 -2
  122. package/dist/core/State.js.map +1 -1
  123. package/dist/core/ToolExecutor.d.ts +29 -0
  124. package/dist/core/ToolExecutor.d.ts.map +1 -0
  125. package/dist/core/ToolExecutor.js +69 -0
  126. package/dist/core/ToolExecutor.js.map +1 -0
  127. package/dist/core/Transition.d.ts +5 -5
  128. package/dist/core/Transition.d.ts.map +1 -1
  129. package/dist/core/Transition.js.map +1 -1
  130. package/dist/index.d.ts +6 -8
  131. package/dist/index.d.ts.map +1 -1
  132. package/dist/index.js +3 -5
  133. package/dist/index.js.map +1 -1
  134. package/dist/providers/AnthropicProvider.d.ts.map +1 -1
  135. package/dist/providers/AnthropicProvider.js +10 -13
  136. package/dist/providers/AnthropicProvider.js.map +1 -1
  137. package/dist/providers/GeminiProvider.d.ts.map +1 -1
  138. package/dist/providers/GeminiProvider.js +12 -8
  139. package/dist/providers/GeminiProvider.js.map +1 -1
  140. package/dist/providers/OpenAIProvider.d.ts.map +1 -1
  141. package/dist/providers/OpenAIProvider.js +10 -53
  142. package/dist/providers/OpenAIProvider.js.map +1 -1
  143. package/dist/providers/OpenRouterProvider.d.ts.map +1 -1
  144. package/dist/providers/OpenRouterProvider.js +10 -53
  145. package/dist/providers/OpenRouterProvider.js.map +1 -1
  146. package/dist/types/agent.d.ts +13 -12
  147. package/dist/types/agent.d.ts.map +1 -1
  148. package/dist/types/ai.d.ts +8 -2
  149. package/dist/types/ai.d.ts.map +1 -1
  150. package/dist/types/history.d.ts +8 -0
  151. package/dist/types/history.d.ts.map +1 -1
  152. package/dist/types/index.d.ts +0 -3
  153. package/dist/types/index.d.ts.map +1 -1
  154. package/dist/types/index.js +0 -1
  155. package/dist/types/index.js.map +1 -1
  156. package/dist/types/route.d.ts +39 -4
  157. package/dist/types/route.d.ts.map +1 -1
  158. package/dist/types/routing.d.ts +16 -0
  159. package/dist/types/routing.d.ts.map +1 -0
  160. package/dist/types/routing.js +2 -0
  161. package/dist/types/routing.js.map +1 -0
  162. package/dist/types/schema.d.ts +22 -0
  163. package/dist/types/schema.d.ts.map +1 -0
  164. package/dist/types/schema.js +2 -0
  165. package/dist/types/schema.js.map +1 -0
  166. package/dist/types/session.d.ts +72 -0
  167. package/dist/types/session.d.ts.map +1 -0
  168. package/dist/types/session.js +132 -0
  169. package/dist/types/session.js.map +1 -0
  170. package/dist/types/tool.d.ts +11 -5
  171. package/dist/types/tool.d.ts.map +1 -1
  172. package/dist/utils/id.d.ts +0 -5
  173. package/dist/utils/id.d.ts.map +1 -1
  174. package/dist/utils/id.js +0 -9
  175. package/dist/utils/id.js.map +1 -1
  176. package/dist/utils/schema.d.ts +17 -0
  177. package/dist/utils/schema.d.ts.map +1 -0
  178. package/dist/utils/schema.js +27 -0
  179. package/dist/utils/schema.js.map +1 -0
  180. package/docs/ADAPTERS.md +83 -3
  181. package/docs/API_REFERENCE.md +95 -104
  182. package/docs/ARCHITECTURE.md +284 -286
  183. package/docs/CONSTRUCTOR_OPTIONS.md +192 -135
  184. package/docs/CONTEXT_MANAGEMENT.md +311 -28
  185. package/docs/CONTRIBUTING.md +1 -1
  186. package/docs/DOMAINS.md +61 -0
  187. package/docs/GETTING_STARTED.md +177 -88
  188. package/docs/PERSISTENCE.md +170 -23
  189. package/docs/README.md +7 -10
  190. package/examples/business-onboarding.ts +21 -9
  191. package/examples/company-qna-agent.ts +508 -0
  192. package/examples/declarative-agent.ts +143 -26
  193. package/examples/domain-scoping.ts +31 -10
  194. package/examples/extracted-data-modification.ts +415 -0
  195. package/examples/healthcare-agent.ts +194 -90
  196. package/examples/openai-agent.ts +67 -25
  197. package/examples/opensearch-persistence.ts +455 -151
  198. package/examples/persistent-onboarding.ts +162 -96
  199. package/examples/prisma-persistence.ts +371 -125
  200. package/examples/redis-persistence.ts +393 -23
  201. package/examples/rules-prohibitions.ts +32 -11
  202. package/examples/streaming-agent.ts +61 -13
  203. package/examples/travel-agent.ts +266 -133
  204. package/package.json +1 -1
  205. package/src/core/Agent.ts +674 -356
  206. package/src/core/Events.ts +12 -2
  207. package/src/core/PersistenceManager.ts +83 -0
  208. package/src/core/PromptComposer.ts +143 -0
  209. package/src/core/ResponseEngine.ts +82 -0
  210. package/src/core/Route.ts +32 -17
  211. package/src/core/RoutingEngine.ts +165 -0
  212. package/src/core/State.ts +55 -15
  213. package/src/core/ToolExecutor.ts +117 -0
  214. package/src/core/Transition.ts +5 -5
  215. package/src/index.ts +12 -21
  216. package/src/providers/AnthropicProvider.ts +10 -13
  217. package/src/providers/GeminiProvider.ts +12 -8
  218. package/src/providers/OpenAIProvider.ts +10 -56
  219. package/src/providers/OpenRouterProvider.ts +10 -56
  220. package/src/types/agent.ts +16 -13
  221. package/src/types/ai.ts +6 -2
  222. package/src/types/history.ts +8 -0
  223. package/src/types/index.ts +0 -11
  224. package/src/types/route.ts +41 -5
  225. package/src/types/routing.ts +18 -0
  226. package/src/types/schema.ts +23 -0
  227. package/src/types/session.ts +207 -0
  228. package/src/types/tool.ts +29 -7
  229. package/src/utils/id.ts +0 -10
  230. package/src/utils/schema.ts +32 -0
  231. package/dist/cjs/core/ConditionEvaluator.d.ts +0 -72
  232. package/dist/cjs/core/ConditionEvaluator.d.ts.map +0 -1
  233. package/dist/cjs/core/ConditionEvaluator.js +0 -272
  234. package/dist/cjs/core/ConditionEvaluator.js.map +0 -1
  235. package/dist/cjs/core/Observation.d.ts +0 -24
  236. package/dist/cjs/core/Observation.d.ts.map +0 -1
  237. package/dist/cjs/core/Observation.js +0 -39
  238. package/dist/cjs/core/Observation.js.map +0 -1
  239. package/dist/cjs/core/PreparationEngine.d.ts +0 -116
  240. package/dist/cjs/core/PreparationEngine.d.ts.map +0 -1
  241. package/dist/cjs/core/PreparationEngine.js +0 -353
  242. package/dist/cjs/core/PreparationEngine.js.map +0 -1
  243. package/dist/cjs/core/PromptBuilder.d.ts +0 -136
  244. package/dist/cjs/core/PromptBuilder.d.ts.map +0 -1
  245. package/dist/cjs/core/PromptBuilder.js +0 -421
  246. package/dist/cjs/core/PromptBuilder.js.map +0 -1
  247. package/dist/cjs/types/observation.d.ts +0 -27
  248. package/dist/cjs/types/observation.d.ts.map +0 -1
  249. package/dist/cjs/types/observation.js +0 -6
  250. package/dist/cjs/types/observation.js.map +0 -1
  251. package/dist/cjs/types/prompt.d.ts +0 -46
  252. package/dist/cjs/types/prompt.d.ts.map +0 -1
  253. package/dist/cjs/types/prompt.js +0 -19
  254. package/dist/cjs/types/prompt.js.map +0 -1
  255. package/dist/core/ConditionEvaluator.d.ts +0 -72
  256. package/dist/core/ConditionEvaluator.d.ts.map +0 -1
  257. package/dist/core/ConditionEvaluator.js +0 -268
  258. package/dist/core/ConditionEvaluator.js.map +0 -1
  259. package/dist/core/Observation.d.ts +0 -24
  260. package/dist/core/Observation.d.ts.map +0 -1
  261. package/dist/core/Observation.js +0 -35
  262. package/dist/core/Observation.js.map +0 -1
  263. package/dist/core/PreparationEngine.d.ts +0 -116
  264. package/dist/core/PreparationEngine.d.ts.map +0 -1
  265. package/dist/core/PreparationEngine.js +0 -349
  266. package/dist/core/PreparationEngine.js.map +0 -1
  267. package/dist/core/PromptBuilder.d.ts +0 -136
  268. package/dist/core/PromptBuilder.d.ts.map +0 -1
  269. package/dist/core/PromptBuilder.js +0 -417
  270. package/dist/core/PromptBuilder.js.map +0 -1
  271. package/dist/types/observation.d.ts +0 -27
  272. package/dist/types/observation.d.ts.map +0 -1
  273. package/dist/types/observation.js +0 -5
  274. package/dist/types/observation.js.map +0 -1
  275. package/dist/types/prompt.d.ts +0 -46
  276. package/dist/types/prompt.d.ts.map +0 -1
  277. package/dist/types/prompt.js +0 -16
  278. package/dist/types/prompt.js.map +0 -1
  279. package/docs/STRUCTURE.md +0 -58
  280. package/src/core/ConditionEvaluator.ts +0 -381
  281. package/src/core/Observation.ts +0 -47
  282. package/src/core/PreparationEngine.ts +0 -561
  283. package/src/core/PromptBuilder.ts +0 -617
  284. package/src/types/observation.ts +0 -29
  285. package/src/types/prompt.ts +0 -49
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Persistent multi-turn onboarding agent example
3
- * Demonstrates context lifecycle management for stateful conversations
3
+ * Updated for v2 architecture with session state management and schema-first data extraction
4
4
  */
5
5
 
6
6
  import {
@@ -10,7 +10,7 @@ import {
10
10
  END_ROUTE,
11
11
  EventSource,
12
12
  createMessageEvent,
13
- type ContextLifecycleHooks,
13
+ createSession,
14
14
  } from "../src/index";
15
15
 
16
16
  // ============================================================================
@@ -63,16 +63,19 @@ const db = {
63
63
  // CONTEXT TYPE
64
64
  // ============================================================================
65
65
 
66
+ // Data extraction types for onboarding
67
+ interface OnboardingData {
68
+ businessName?: string;
69
+ businessDescription?: string;
70
+ industry?: string;
71
+ contactEmail?: string;
72
+ }
73
+
66
74
  interface OnboardingContext {
67
75
  sessionId: string;
68
76
  userId: string;
69
77
  userName?: string;
70
- collectedData: {
71
- businessName?: string;
72
- businessDescription?: string;
73
- industry?: string;
74
- contactEmail?: string;
75
- };
78
+ collectedData: OnboardingData;
76
79
  completedSteps: string[];
77
80
  }
78
81
 
@@ -96,31 +99,26 @@ async function createPersistentOnboardingAgent(sessionId: string) {
96
99
  }
97
100
 
98
101
  // Define lifecycle hooks for automatic persistence
99
- const hooks: ContextLifecycleHooks<OnboardingContext> = {
100
- // Called before respond() - load fresh context from database
101
- beforeRespond: async (currentContext) => {
102
- console.log("🔄 Loading fresh context from database...");
103
- const freshSession = await db.sessions.findById(sessionId);
104
-
105
- if (!freshSession) {
106
- return currentContext; // Fallback to current
107
- }
108
-
109
- return {
110
- sessionId: freshSession.sessionId,
111
- userId: freshSession.userId,
112
- collectedData: freshSession.collectedData,
113
- completedSteps: freshSession.completedSteps,
114
- };
115
- },
116
-
117
- // Called after context updates - persist to database
118
- onContextUpdate: async (newContext) => {
119
- console.log("💾 Persisting context update to database...");
102
+ const hooks = {
103
+ // Called after data extraction - validate and enrich extracted data
104
+ onExtractedUpdate: async (extracted, previousExtracted) => {
105
+ console.log("🔄 Processing extracted data...");
106
+
107
+ // Update completed steps based on what's been extracted
108
+ const completedSteps: string[] = [];
109
+ if (extracted.businessName) completedSteps.push("business_info");
110
+ if (extracted.businessDescription)
111
+ completedSteps.push("business_description");
112
+ if (extracted.industry) completedSteps.push("industry");
113
+ if (extracted.contactEmail) completedSteps.push("contact");
114
+
115
+ // Persist to database
120
116
  await db.sessions.update(sessionId, {
121
- collectedData: newContext.collectedData,
122
- completedSteps: newContext.completedSteps,
117
+ collectedData: extracted,
118
+ completedSteps,
123
119
  });
120
+
121
+ return extracted;
124
122
  },
125
123
  };
126
124
 
@@ -134,11 +132,21 @@ async function createPersistentOnboardingAgent(sessionId: string) {
134
132
  description: "A friendly assistant that helps businesses get started",
135
133
  goal: "Collect business information efficiently while being conversational",
136
134
  ai: provider,
137
- context: {
138
- sessionId: session.sessionId,
139
- userId: session.userId,
140
- collectedData: session.collectedData,
141
- completedSteps: session.completedSteps,
135
+ // Context is loaded fresh from database on each respond() call
136
+ contextProvider: async () => {
137
+ console.log("🔄 Loading fresh context from database...");
138
+ const freshSession = await db.sessions.findById(sessionId);
139
+
140
+ if (!freshSession) {
141
+ throw new Error(`Session ${sessionId} not found`);
142
+ }
143
+
144
+ return {
145
+ sessionId: freshSession.sessionId,
146
+ userId: freshSession.userId,
147
+ collectedData: freshSession.collectedData,
148
+ completedSteps: freshSession.completedSteps,
149
+ };
142
150
  },
143
151
  hooks, // Enable lifecycle hooks for persistence
144
152
  });
@@ -229,44 +237,79 @@ async function createPersistentOnboardingAgent(sessionId: string) {
229
237
  );
230
238
 
231
239
  // ============================================================================
232
- // ONBOARDING ROUTE
240
+ // ONBOARDING ROUTE WITH DATA EXTRACTION
233
241
  // ============================================================================
234
242
 
235
- const onboardingRoute = agent.createRoute({
243
+ const onboardingRoute = agent.createRoute<OnboardingData>({
236
244
  title: "Business Onboarding",
237
245
  description: "Guide user through business information collection",
238
246
  conditions: ["User is onboarding their business"],
247
+ gatherSchema: {
248
+ type: "object",
249
+ properties: {
250
+ businessName: {
251
+ type: "string",
252
+ description: "Name of the business",
253
+ },
254
+ businessDescription: {
255
+ type: "string",
256
+ description: "Brief description of what the business does",
257
+ },
258
+ industry: {
259
+ type: "string",
260
+ description: "Industry the business operates in",
261
+ },
262
+ contactEmail: {
263
+ type: "string",
264
+ description: "Contact email for the business",
265
+ },
266
+ },
267
+ required: ["businessName", "businessDescription"],
268
+ },
239
269
  });
240
270
 
241
- // Step 1: Collect business info
242
- const askBusinessInfo = onboardingRoute.initialState.transitionTo({
271
+ // State 1: Gather business name and description
272
+ const gatherBusinessInfo = onboardingRoute.initialState.transitionTo({
243
273
  chatState: "Ask for business name and a brief description",
274
+ gather: ["businessName", "businessDescription"],
275
+ skipIf: (extracted) =>
276
+ !!extracted.businessName && !!extracted.businessDescription,
244
277
  });
245
278
 
246
- const saveBusinessStep = askBusinessInfo.transitionTo({
279
+ // State 2: Save business info (tool execution)
280
+ const saveBusiness = gatherBusinessInfo.transitionTo({
247
281
  toolState: saveBusinessInfo,
282
+ requiredData: ["businessName", "businessDescription"],
248
283
  });
249
284
 
250
- // Step 2: Collect industry
251
- const askIndustry = saveBusinessStep.transitionTo({
285
+ // State 3: Gather industry
286
+ const gatherIndustry = saveBusiness.transitionTo({
252
287
  chatState: "Ask what industry the business operates in",
288
+ gather: ["industry"],
289
+ skipIf: (extracted) => !!extracted.industry,
253
290
  });
254
291
 
255
- const saveIndustryStep = askIndustry.transitionTo({
292
+ // State 4: Save industry (tool execution)
293
+ const saveIndustryStep = gatherIndustry.transitionTo({
256
294
  toolState: saveIndustry,
295
+ requiredData: ["industry"],
257
296
  });
258
297
 
259
- // Step 3: Collect contact
260
- const askContact = saveIndustryStep.transitionTo({
298
+ // State 5: Gather contact email
299
+ const gatherContact = saveIndustryStep.transitionTo({
261
300
  chatState: "Ask for their contact email",
301
+ gather: ["contactEmail"],
302
+ skipIf: (extracted) => !!extracted.contactEmail,
262
303
  });
263
304
 
264
- const saveContactStep = askContact.transitionTo({
305
+ // State 6: Save contact (tool execution)
306
+ const saveContact = gatherContact.transitionTo({
265
307
  toolState: saveContactEmail,
308
+ requiredData: ["contactEmail"],
266
309
  });
267
310
 
268
- // Step 4: Confirmation
269
- const confirm = saveContactStep.transitionTo({
311
+ // State 7: Confirmation
312
+ const confirm = saveContact.transitionTo({
270
313
  chatState: "Summarize all collected information and ask for confirmation",
271
314
  });
272
315
 
@@ -366,12 +409,17 @@ async function main() {
366
409
  lastUpdated: new Date(),
367
410
  });
368
411
 
412
+ // Create agent with fresh context loading
413
+ const agent = await createPersistentOnboardingAgent(sessionId);
414
+
369
415
  console.log("=== MULTI-TURN CONVERSATION SIMULATION ===\n");
370
416
 
417
+ // Initialize session state for multi-turn conversation
418
+ let session = createSession<OnboardingData>();
419
+
371
420
  // Turn 1: Start onboarding
372
421
  console.log("📱 Turn 1: User starts onboarding");
373
- const agent1 = await createPersistentOnboardingAgent(sessionId);
374
- const response1 = await agent1.respond({
422
+ const response1 = await agent.respond({
375
423
  history: [
376
424
  createMessageEvent(
377
425
  EventSource.CUSTOMER,
@@ -379,42 +427,53 @@ async function main() {
379
427
  "Hi, I want to onboard my business"
380
428
  ),
381
429
  ],
430
+ session,
382
431
  });
383
432
  console.log("🤖 Bot:", response1.message);
384
- console.log("📊 Context after turn 1:", agent1["context"]);
433
+ console.log("📊 Extracted after turn 1:", response1.session?.extracted);
434
+ console.log("📊 Route:", response1.session?.currentRoute?.title);
385
435
  console.log();
386
436
 
437
+ // Update session with progress
438
+ session = response1.session!;
439
+
387
440
  // Turn 2: User provides business info
388
- // NOTE: We create a NEW agent instance - context is loaded from database
389
441
  console.log("📱 Turn 2: User provides business info");
390
- const agent2 = await createPersistentOnboardingAgent(sessionId);
391
- const response2 = await agent2.respond({
392
- history: [
393
- createMessageEvent(
394
- EventSource.CUSTOMER,
395
- "Alice",
396
- "My business is called 'TechFlow' and we build AI-powered workflow automation tools"
397
- ),
398
- ],
399
- });
442
+ const history2 = [
443
+ createMessageEvent(
444
+ EventSource.CUSTOMER,
445
+ "Alice",
446
+ "Hi, I want to onboard my business"
447
+ ),
448
+ createMessageEvent(EventSource.AI_AGENT, "Agent", response1.message),
449
+ createMessageEvent(
450
+ EventSource.CUSTOMER,
451
+ "Alice",
452
+ "My business is called 'TechFlow' and we build AI-powered workflow automation tools"
453
+ ),
454
+ ];
455
+ const response2 = await agent.respond({ history: history2, session });
400
456
  console.log("🤖 Bot:", response2.message);
401
- console.log("📊 Context after turn 2:", agent2["context"]);
457
+ console.log("📊 Extracted after turn 2:", response2.session?.extracted);
402
458
  console.log();
403
459
 
460
+ // Update session again
461
+ session = response2.session!;
462
+
404
463
  // Turn 3: User provides industry
405
464
  console.log("📱 Turn 3: User provides industry");
406
- const agent3 = await createPersistentOnboardingAgent(sessionId);
407
- const response3 = await agent3.respond({
408
- history: [
409
- createMessageEvent(
410
- EventSource.CUSTOMER,
411
- "Alice",
412
- "We're in the SaaS industry"
413
- ),
414
- ],
415
- });
465
+ const history3 = [
466
+ ...history2,
467
+ createMessageEvent(EventSource.AI_AGENT, "Agent", response2.message),
468
+ createMessageEvent(
469
+ EventSource.CUSTOMER,
470
+ "Alice",
471
+ "We're in the SaaS industry"
472
+ ),
473
+ ];
474
+ const response3 = await agent.respond({ history: history3, session });
416
475
  console.log("🤖 Bot:", response3.message);
417
- console.log("📊 Context after turn 3:", agent3["context"]);
476
+ console.log("📊 Extracted after turn 3:", response3.session?.extracted);
418
477
  console.log();
419
478
 
420
479
  // Verify persistence
@@ -427,34 +486,41 @@ async function main() {
427
486
  }
428
487
 
429
488
  // ============================================================================
430
- // KEY PATTERNS DEMONSTRATED
489
+ // KEY PATTERNS DEMONSTRATED (V2 Architecture)
431
490
  // ============================================================================
432
491
 
433
492
  /*
434
- * ✅ PATTERN 1: Lifecycle Hooks (Recommended for most cases)
435
- * - beforeRespond: Load fresh context before each response
436
- * - onContextUpdate: Persist context after updates
437
- * - Works with both static context and updates
493
+ * ✅ PATTERN 1: Session State Management (Core v2 pattern)
494
+ * - createSession<T>(): Initialize typed session state
495
+ * - Pass session to respond() calls
496
+ * - Session tracks extracted data across turns
497
+ * - Always-on routing respects intent changes
498
+ *
499
+ * ✅ PATTERN 2: Schema-First Data Extraction
500
+ * - gatherSchema: Define data contracts upfront
501
+ * - Type-safe extraction throughout conversation
502
+ * - skipIf functions for deterministic state logic
503
+ * - requiredData arrays for prerequisites
438
504
  *
439
- * ✅ PATTERN 2: Context Provider (For always-fresh context)
440
- * - contextProvider: Function that returns fresh context
441
- * - onContextUpdate: Still needed for persistence
442
- * - Best when context is always loaded from external source
505
+ * ✅ PATTERN 3: Context Provider (For external data sources)
506
+ * - contextProvider: Load fresh context from database/API
507
+ * - Runs before each respond() call
508
+ * - Perfect for real-time external data
443
509
  *
444
- * ✅ PATTERN 3: Tool Context Updates (Two options)
445
- * - Option A: Return { data, contextUpdate } in tool result
446
- * - Option B: Call toolContext.updateContext() directly
447
- * - Both trigger onContextUpdate hook automatically
510
+ * ✅ PATTERN 4: Lifecycle Hooks (Data validation & enrichment)
511
+ * - onExtractedUpdate: Process extracted data after extraction
512
+ * - Validate, enrich, and persist extracted data
513
+ * - Return modified extracted data
448
514
  *
449
- * ✅ PATTERN 4: Explicit Updates
450
- * - agent.updateContext() for manual updates
451
- * - Triggers onContextUpdate hook
452
- * - Useful outside of tool execution
515
+ * ✅ PATTERN 5: Tool Integration (Enhanced context access)
516
+ * - Tools access extracted data via context parameter
517
+ * - Can return extractedUpdate to modify extracted data
518
+ * - Perfect for data validation and enrichment
453
519
  *
454
- * ANTI-PATTERN: Caching Agents
455
- * - DON'T cache agent instances across requests
456
- * - DO recreate agents with fresh context
457
- * - Context gets stale if agent is cached
520
+ * PATTERN 6: State Progression (Code-based logic)
521
+ * - skipIf: Deterministic functions instead of fuzzy conditions
522
+ * - requiredData: Prerequisites for state transitions
523
+ * - No more LLM interpretation of state logic
458
524
  */
459
525
 
460
526
  if (import.meta.url === `file://${process.argv[1]}`) {