@falai/agent 0.3.0 → 0.3.11

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 (114) hide show
  1. package/README.md +257 -24
  2. package/dist/cjs/core/Agent.d.ts +37 -0
  3. package/dist/cjs/core/Agent.d.ts.map +1 -1
  4. package/dist/cjs/core/Agent.js +167 -1
  5. package/dist/cjs/core/Agent.js.map +1 -1
  6. package/dist/cjs/core/DomainRegistry.d.ts +10 -0
  7. package/dist/cjs/core/DomainRegistry.d.ts.map +1 -1
  8. package/dist/cjs/core/DomainRegistry.js +25 -0
  9. package/dist/cjs/core/DomainRegistry.js.map +1 -1
  10. package/dist/cjs/core/PromptBuilder.d.ts +9 -1
  11. package/dist/cjs/core/PromptBuilder.d.ts.map +1 -1
  12. package/dist/cjs/core/PromptBuilder.js +49 -2
  13. package/dist/cjs/core/PromptBuilder.js.map +1 -1
  14. package/dist/cjs/core/Route.d.ts +16 -0
  15. package/dist/cjs/core/Route.d.ts.map +1 -1
  16. package/dist/cjs/core/Route.js +22 -0
  17. package/dist/cjs/core/Route.js.map +1 -1
  18. package/dist/cjs/index.d.ts +2 -0
  19. package/dist/cjs/index.d.ts.map +1 -1
  20. package/dist/cjs/index.js +3 -1
  21. package/dist/cjs/index.js.map +1 -1
  22. package/dist/cjs/providers/AnthropicProvider.d.ts +43 -0
  23. package/dist/cjs/providers/AnthropicProvider.d.ts.map +1 -0
  24. package/dist/cjs/providers/AnthropicProvider.js +328 -0
  25. package/dist/cjs/providers/AnthropicProvider.js.map +1 -0
  26. package/dist/cjs/providers/GeminiProvider.d.ts +4 -1
  27. package/dist/cjs/providers/GeminiProvider.d.ts.map +1 -1
  28. package/dist/cjs/providers/GeminiProvider.js +96 -0
  29. package/dist/cjs/providers/GeminiProvider.js.map +1 -1
  30. package/dist/cjs/providers/OpenAIProvider.d.ts +4 -1
  31. package/dist/cjs/providers/OpenAIProvider.d.ts.map +1 -1
  32. package/dist/cjs/providers/OpenAIProvider.js +115 -0
  33. package/dist/cjs/providers/OpenAIProvider.js.map +1 -1
  34. package/dist/cjs/providers/OpenRouterProvider.d.ts +4 -1
  35. package/dist/cjs/providers/OpenRouterProvider.d.ts.map +1 -1
  36. package/dist/cjs/providers/OpenRouterProvider.js +115 -0
  37. package/dist/cjs/providers/OpenRouterProvider.js.map +1 -1
  38. package/dist/cjs/providers/index.d.ts +13 -0
  39. package/dist/cjs/providers/index.d.ts.map +1 -0
  40. package/dist/cjs/providers/index.js +16 -0
  41. package/dist/cjs/providers/index.js.map +1 -0
  42. package/dist/cjs/types/ai.d.ts +28 -0
  43. package/dist/cjs/types/ai.d.ts.map +1 -1
  44. package/dist/cjs/types/route.d.ts +6 -0
  45. package/dist/cjs/types/route.d.ts.map +1 -1
  46. package/dist/core/Agent.d.ts +37 -0
  47. package/dist/core/Agent.d.ts.map +1 -1
  48. package/dist/core/Agent.js +167 -1
  49. package/dist/core/Agent.js.map +1 -1
  50. package/dist/core/DomainRegistry.d.ts +10 -0
  51. package/dist/core/DomainRegistry.d.ts.map +1 -1
  52. package/dist/core/DomainRegistry.js +25 -0
  53. package/dist/core/DomainRegistry.js.map +1 -1
  54. package/dist/core/PromptBuilder.d.ts +9 -1
  55. package/dist/core/PromptBuilder.d.ts.map +1 -1
  56. package/dist/core/PromptBuilder.js +49 -2
  57. package/dist/core/PromptBuilder.js.map +1 -1
  58. package/dist/core/Route.d.ts +16 -0
  59. package/dist/core/Route.d.ts.map +1 -1
  60. package/dist/core/Route.js +22 -0
  61. package/dist/core/Route.js.map +1 -1
  62. package/dist/index.d.ts +2 -0
  63. package/dist/index.d.ts.map +1 -1
  64. package/dist/index.js +1 -0
  65. package/dist/index.js.map +1 -1
  66. package/dist/providers/AnthropicProvider.d.ts +43 -0
  67. package/dist/providers/AnthropicProvider.d.ts.map +1 -0
  68. package/dist/providers/AnthropicProvider.js +321 -0
  69. package/dist/providers/AnthropicProvider.js.map +1 -0
  70. package/dist/providers/GeminiProvider.d.ts +4 -1
  71. package/dist/providers/GeminiProvider.d.ts.map +1 -1
  72. package/dist/providers/GeminiProvider.js +96 -0
  73. package/dist/providers/GeminiProvider.js.map +1 -1
  74. package/dist/providers/OpenAIProvider.d.ts +4 -1
  75. package/dist/providers/OpenAIProvider.d.ts.map +1 -1
  76. package/dist/providers/OpenAIProvider.js +115 -0
  77. package/dist/providers/OpenAIProvider.js.map +1 -1
  78. package/dist/providers/OpenRouterProvider.d.ts +4 -1
  79. package/dist/providers/OpenRouterProvider.d.ts.map +1 -1
  80. package/dist/providers/OpenRouterProvider.js +115 -0
  81. package/dist/providers/OpenRouterProvider.js.map +1 -1
  82. package/dist/providers/index.d.ts +13 -0
  83. package/dist/providers/index.d.ts.map +1 -0
  84. package/dist/providers/index.js +9 -0
  85. package/dist/providers/index.js.map +1 -0
  86. package/dist/types/ai.d.ts +28 -0
  87. package/dist/types/ai.d.ts.map +1 -1
  88. package/dist/types/route.d.ts +6 -0
  89. package/dist/types/route.d.ts.map +1 -1
  90. package/docs/API_REFERENCE.md +357 -2
  91. package/docs/CONSTRUCTOR_OPTIONS.md +178 -37
  92. package/docs/GETTING_STARTED.md +10 -2
  93. package/docs/PROVIDERS.md +139 -2
  94. package/examples/business-onboarding.ts +708 -0
  95. package/examples/declarative-agent.ts +1 -1
  96. package/examples/domain-scoping.ts +267 -0
  97. package/examples/healthcare-agent.ts +4 -4
  98. package/examples/openai-agent.ts +6 -4
  99. package/examples/rules-prohibitions.ts +258 -0
  100. package/examples/streaming-agent.ts +371 -0
  101. package/examples/travel-agent.ts +7 -4
  102. package/package.json +2 -1
  103. package/src/core/Agent.ts +220 -1
  104. package/src/core/DomainRegistry.ts +30 -0
  105. package/src/core/PromptBuilder.ts +70 -3
  106. package/src/core/Route.ts +28 -0
  107. package/src/index.ts +2 -0
  108. package/src/providers/AnthropicProvider.ts +467 -0
  109. package/src/providers/GeminiProvider.ts +135 -0
  110. package/src/providers/OpenAIProvider.ts +157 -0
  111. package/src/providers/OpenRouterProvider.ts +157 -0
  112. package/src/providers/index.ts +16 -0
  113. package/src/types/ai.ts +32 -0
  114. package/src/types/route.ts +6 -0
@@ -0,0 +1,708 @@
1
+ /**
2
+ * Business Onboarding Example
3
+ *
4
+ * Real-world example showing:
5
+ * - Complex multi-step onboarding flow
6
+ * - Tools with contextUpdate for automatic state management
7
+ * - Lifecycle hooks for persistence
8
+ * - Branching logic (physical vs online business)
9
+ * - Both step-by-step and chained transition approaches
10
+ * - Agent caching with lifecycle hooks
11
+ */
12
+
13
+ import {
14
+ Agent,
15
+ defineTool,
16
+ END_ROUTE,
17
+ EventSource,
18
+ createMessageEvent,
19
+ OpenAIProvider,
20
+ type ToolContext,
21
+ } from "../src/index";
22
+
23
+ // ==================== Types ====================
24
+
25
+ interface BusinessInfo {
26
+ businessName?: string;
27
+ businessDescription?: string;
28
+ businessSector?: string;
29
+ }
30
+
31
+ interface LocationInfo {
32
+ address?: string;
33
+ city?: string;
34
+ state?: string;
35
+ hasPhysicalStore?: boolean;
36
+ }
37
+
38
+ interface ContactInfo {
39
+ website?: string;
40
+ openingHours?: string;
41
+ }
42
+
43
+ interface PaymentInfo {
44
+ paymentMethods?: string[];
45
+ pixInfo?: {
46
+ pixKey: string;
47
+ pixType: "cpf" | "cnpj" | "email" | "phone" | "random";
48
+ };
49
+ installmentOptions?: string;
50
+ }
51
+
52
+ interface ProductsInfo {
53
+ products?: string[];
54
+ services?: string[];
55
+ targetAudience?: string;
56
+ }
57
+
58
+ interface RouteInfo {
59
+ title: string;
60
+ description: string;
61
+ keywords: string[];
62
+ responseStyle: "formal" | "casual" | "professional" | "friendly";
63
+ actions: string[];
64
+ }
65
+
66
+ interface OnboardingData {
67
+ business?: BusinessInfo;
68
+ location?: LocationInfo;
69
+ contact?: ContactInfo;
70
+ payment?: PaymentInfo;
71
+ productsServices?: ProductsInfo;
72
+ routes: RouteInfo[];
73
+ }
74
+
75
+ interface OnboardingContext {
76
+ userId: string;
77
+ userName: string;
78
+ sessionId: string;
79
+ collectedData: OnboardingData;
80
+ }
81
+
82
+ // ==================== Tools ====================
83
+
84
+ /**
85
+ * Save business information
86
+ */
87
+ const saveBusinessInfo = defineTool<
88
+ OnboardingContext,
89
+ [name: string, description: string, sector: string],
90
+ boolean
91
+ >(
92
+ "save_business_info",
93
+ async (
94
+ toolContext: ToolContext<OnboardingContext>,
95
+ name: string,
96
+ description: string,
97
+ sector: string
98
+ ) => {
99
+ // Return contextUpdate to automatically update context
100
+ return {
101
+ data: true,
102
+ contextUpdate: {
103
+ collectedData: {
104
+ ...toolContext.context.collectedData,
105
+ business: {
106
+ businessName: name,
107
+ businessDescription: description,
108
+ businessSector: sector,
109
+ },
110
+ },
111
+ },
112
+ };
113
+ },
114
+ {
115
+ description:
116
+ "Save basic business information: company name, description, and sector",
117
+ }
118
+ );
119
+
120
+ /**
121
+ * Save products and services information
122
+ */
123
+ const saveProductsServices = defineTool<
124
+ OnboardingContext,
125
+ [products: string[], services: string[], targetAudience: string],
126
+ boolean
127
+ >(
128
+ "save_products_services",
129
+ async (
130
+ toolContext: ToolContext<OnboardingContext>,
131
+ products: string[],
132
+ services: string[],
133
+ targetAudience: string
134
+ ) => {
135
+ return {
136
+ data: true,
137
+ contextUpdate: {
138
+ collectedData: {
139
+ ...toolContext.context.collectedData,
140
+ productsServices: {
141
+ products,
142
+ services,
143
+ targetAudience,
144
+ },
145
+ },
146
+ },
147
+ };
148
+ },
149
+ {
150
+ description: "Save products, services offered, and target audience",
151
+ }
152
+ );
153
+
154
+ /**
155
+ * Save location information
156
+ */
157
+ const saveLocationInfo = defineTool<
158
+ OnboardingContext,
159
+ [address: string, city: string, state: string, hasPhysicalStore: boolean],
160
+ boolean
161
+ >(
162
+ "save_location_info",
163
+ async (
164
+ toolContext: ToolContext<OnboardingContext>,
165
+ address: string,
166
+ city: string,
167
+ state: string,
168
+ hasPhysicalStore: boolean
169
+ ) => {
170
+ return {
171
+ data: true,
172
+ contextUpdate: {
173
+ collectedData: {
174
+ ...toolContext.context.collectedData,
175
+ location: {
176
+ address,
177
+ city,
178
+ state,
179
+ hasPhysicalStore,
180
+ },
181
+ },
182
+ },
183
+ };
184
+ },
185
+ {
186
+ description:
187
+ "Save location information: full address, city, state, and physical store status",
188
+ }
189
+ );
190
+
191
+ /**
192
+ * Save contact information
193
+ */
194
+ const saveContactInfo = defineTool<
195
+ OnboardingContext,
196
+ [website: string, openingHours: string],
197
+ boolean
198
+ >(
199
+ "save_contact_info",
200
+ async (
201
+ toolContext: ToolContext<OnboardingContext>,
202
+ website: string,
203
+ openingHours: string
204
+ ) => {
205
+ return {
206
+ data: true,
207
+ contextUpdate: {
208
+ collectedData: {
209
+ ...toolContext.context.collectedData,
210
+ contact: {
211
+ website,
212
+ openingHours,
213
+ },
214
+ },
215
+ },
216
+ };
217
+ },
218
+ {
219
+ description: "Save contact information: website/URL and business hours",
220
+ }
221
+ );
222
+
223
+ /**
224
+ * Save payment information
225
+ */
226
+ const savePaymentInfo = defineTool<
227
+ OnboardingContext,
228
+ [
229
+ paymentMethods: string[],
230
+ pixKey: string,
231
+ pixType: string,
232
+ installmentOptions: string
233
+ ],
234
+ boolean
235
+ >(
236
+ "save_payment_info",
237
+ async (
238
+ toolContext: ToolContext<OnboardingContext>,
239
+ paymentMethods: string[],
240
+ pixKey: string,
241
+ pixType: string,
242
+ installmentOptions: string
243
+ ) => {
244
+ const pixInfo =
245
+ pixKey && pixType
246
+ ? {
247
+ pixKey,
248
+ pixType: ["cpf", "cnpj", "email", "phone", "random"].includes(
249
+ pixType.toLowerCase()
250
+ )
251
+ ? (pixType.toLowerCase() as
252
+ | "cpf"
253
+ | "cnpj"
254
+ | "email"
255
+ | "phone"
256
+ | "random")
257
+ : ("random" as const),
258
+ }
259
+ : undefined;
260
+
261
+ return {
262
+ data: true,
263
+ contextUpdate: {
264
+ collectedData: {
265
+ ...toolContext.context.collectedData,
266
+ payment: {
267
+ paymentMethods,
268
+ pixInfo,
269
+ installmentOptions,
270
+ },
271
+ },
272
+ },
273
+ };
274
+ },
275
+ {
276
+ description:
277
+ "Save payment information: accepted methods, Pix key with type (cpf/cnpj/email/phone/random), and installment options",
278
+ }
279
+ );
280
+
281
+ /**
282
+ * Add a conversation route
283
+ */
284
+ const addConversationRoute = defineTool<
285
+ OnboardingContext,
286
+ [
287
+ title: string,
288
+ description: string,
289
+ keywords: string[],
290
+ responseStyle: string
291
+ ],
292
+ boolean
293
+ >(
294
+ "add_conversation_route",
295
+ async (
296
+ toolContext: ToolContext<OnboardingContext>,
297
+ title: string,
298
+ description: string,
299
+ keywords: string[],
300
+ responseStyle: string
301
+ ) => {
302
+ const validResponseStyles = [
303
+ "formal",
304
+ "casual",
305
+ "professional",
306
+ "friendly",
307
+ ];
308
+ const normalizedStyle = responseStyle.toLowerCase();
309
+
310
+ const route: RouteInfo = {
311
+ title,
312
+ description,
313
+ keywords,
314
+ responseStyle: validResponseStyles.includes(normalizedStyle)
315
+ ? (normalizedStyle as "formal" | "casual" | "professional" | "friendly")
316
+ : "professional",
317
+ actions: [],
318
+ };
319
+
320
+ const existingRoutes = toolContext.context.collectedData.routes || [];
321
+
322
+ return {
323
+ data: true,
324
+ contextUpdate: {
325
+ collectedData: {
326
+ ...toolContext.context.collectedData,
327
+ routes: [...existingRoutes, route],
328
+ },
329
+ },
330
+ };
331
+ },
332
+ {
333
+ description:
334
+ "Add a new conversation route with title, description, keywords, and response style",
335
+ }
336
+ );
337
+
338
+ /**
339
+ * Get all collected data for review
340
+ */
341
+ const getCollectedData = defineTool<OnboardingContext, [], OnboardingData>(
342
+ "get_collected_data",
343
+ async (toolContext: ToolContext<OnboardingContext>) => {
344
+ return { data: toolContext.context.collectedData };
345
+ },
346
+ {
347
+ description: "Retrieve all collected data for review",
348
+ }
349
+ );
350
+
351
+ // ==================== Agent Creation ====================
352
+
353
+ /**
354
+ * Create a business onboarding agent with lifecycle hooks
355
+ * This demonstrates a real-world pattern with:
356
+ * - beforeRespond: Load fresh context before each response
357
+ * - onContextUpdate: Automatically persist context changes
358
+ */
359
+ async function createBusinessOnboardingAgent(
360
+ userId: string,
361
+ userName: string,
362
+ sessionId: string,
363
+ initialData: OnboardingData = { routes: [] }
364
+ ): Promise<Agent<OnboardingContext>> {
365
+ const provider = new OpenAIProvider({
366
+ apiKey: process.env.OPENAI_API_KEY || "test-key",
367
+ model: "gpt-5",
368
+ backupModels: ["gpt-5-mini"],
369
+ retryConfig: {
370
+ timeout: 60000,
371
+ retries: 3,
372
+ },
373
+ });
374
+
375
+ // Create agent with lifecycle hooks for automatic persistence
376
+ const agent = new Agent<OnboardingContext>({
377
+ name: "Business Onboarding Assistant",
378
+ description:
379
+ "A specialized assistant that helps businesses set up intelligent conversation routes for their customers.",
380
+ goal: "Collect comprehensive business information and create personalized conversation routes",
381
+ ai: provider,
382
+ context: {
383
+ userId,
384
+ userName,
385
+ sessionId,
386
+ collectedData: initialData,
387
+ },
388
+ // Lifecycle hooks enable agent caching!
389
+ hooks: {
390
+ // Load fresh context before each response
391
+ beforeRespond: async (currentContext) => {
392
+ // In a real app, fetch from database here
393
+ console.log(
394
+ `[beforeRespond] Loading fresh context for session ${sessionId}`
395
+ );
396
+ // Return updated context
397
+ return currentContext;
398
+ },
399
+
400
+ // Automatically persist context updates
401
+ onContextUpdate: async (newContext) => {
402
+ // In a real app, save to database here
403
+ console.log(
404
+ `[onContextUpdate] Persisting context for session ${sessionId}`
405
+ );
406
+ console.log(
407
+ "Updated data:",
408
+ JSON.stringify(newContext.collectedData, null, 2)
409
+ );
410
+ },
411
+ },
412
+ });
413
+
414
+ // Create the main onboarding route
415
+ const onboardingRoute = agent.createRoute({
416
+ title: "Business Onboarding",
417
+ description: "Complete onboarding process to configure personalized routes",
418
+ conditions: ["User is starting the onboarding process"],
419
+ });
420
+
421
+ // ==================== Build the Flow ====================
422
+
423
+ // For complex flows with branching, we use step-by-step approach
424
+ // This makes it easier to reference states for branching logic
425
+
426
+ // Step 0: Welcome
427
+ const welcome = onboardingRoute.initialState.transitionTo({
428
+ chatState: `Hello ${userName}! 👋 I'm your setup assistant. I'll help you configure your WhatsApp assistant by collecting practical information about your business. ${
429
+ initialData.business?.businessName
430
+ ? `I see your company is "${initialData.business.businessName}".`
431
+ : ""
432
+ } Let's begin! This will only take a few minutes.`,
433
+ });
434
+
435
+ // Step 1: Business basics - Ask
436
+ const askBusiness = welcome.transitionTo({
437
+ chatState:
438
+ initialData.business?.businessName &&
439
+ initialData.business?.businessDescription &&
440
+ initialData.business?.businessSector
441
+ ? `Please confirm: your company is "${initialData.business.businessName}", operates in "${initialData.business.businessSector}", and "${initialData.business.businessDescription}". Is this correct?`
442
+ : initialData.business?.businessName
443
+ ? `Your company "${initialData.business.businessName}" - what sector do you operate in? And what exactly do you do? (brief description)`
444
+ : "First, the basics: what's your company name, sector, and what do you do? (e.g., 'Store X, retail, we sell women's clothing')",
445
+ });
446
+
447
+ // Step 1: Business basics - Save
448
+ const saveBusiness = askBusiness.transitionTo(
449
+ { toolState: saveBusinessInfo },
450
+ "User provided company name, sector, and description"
451
+ );
452
+
453
+ // Step 2: Products/Services - Ask
454
+ const askProducts = saveBusiness.transitionTo({
455
+ chatState:
456
+ "Perfect! Now tell me: what are the main products or services you offer? And who is your target audience? (e.g., 'We sell women's clothing and accessories for women aged 25-45')",
457
+ });
458
+
459
+ // Step 2: Products/Services - Save
460
+ const saveProducts = askProducts.transitionTo(
461
+ { toolState: saveProductsServices },
462
+ "User listed products/services and target audience"
463
+ );
464
+
465
+ // Step 3: Location - Branch point
466
+ const askLocation = saveProducts.transitionTo({
467
+ chatState:
468
+ "Great! Do you have a physical store or in-person service location? (answer 'yes' or 'no')",
469
+ });
470
+
471
+ // Step 3a: Physical store path
472
+ const askPhysicalLocation = askLocation.transitionTo(
473
+ {
474
+ chatState:
475
+ "I see! Since you have a physical presence, I need the complete address (street, number, city, and state) and business hours. This is important for your assistant to inform customers. (e.g., 'José Silva Street, 123, São Paulo - SP - Mon to Fri: 9am to 6pm')",
476
+ },
477
+ "User has a physical store"
478
+ );
479
+
480
+ const savePhysicalLocation = askPhysicalLocation.transitionTo(
481
+ { toolState: saveLocationInfo },
482
+ "User provided physical address"
483
+ );
484
+
485
+ // Step 3b: Online-only path
486
+ const askOnlineLocation = askLocation.transitionTo(
487
+ {
488
+ chatState:
489
+ "Perfect! Since it's online only, please share your main website or social media where customers can find you? And what are your support hours? (e.g., 'www.example.com - 24/7 support' or 'Instagram @mycompany - Mon to Fri: 9am-6pm')",
490
+ },
491
+ "User does not have a physical store"
492
+ );
493
+
494
+ const saveOnlineLocation = askOnlineLocation.transitionTo(
495
+ { toolState: saveContactInfo },
496
+ "User provided website/social media and support hours"
497
+ );
498
+
499
+ // Step 4: Contact info (convergence point for physical stores)
500
+ const askContact = savePhysicalLocation.transitionTo({
501
+ chatState:
502
+ "Do you also have a website or social media? If yes, which one? (if not, you can skip by saying 'I don't have one')",
503
+ });
504
+
505
+ const saveContact = askContact.transitionTo(
506
+ { toolState: saveContactInfo },
507
+ "User provided website/social media"
508
+ );
509
+
510
+ // Step 5: Payment info (convergence point from both paths)
511
+ const askPayment = saveContact.transitionTo({
512
+ chatState:
513
+ "Now about payment: do you sell products/services that customers pay for? If yes, what payment methods do you accept? If you accept Pix, provide the key and type (CPF, CNPJ, email, phone). Do you offer installments? (e.g., 'Pix CPF: 12345678900, Credit card up to 12x, Bank slip' - or say 'not applicable' if you don't sell)",
514
+ });
515
+
516
+ // Also connect online path to payment
517
+ saveOnlineLocation.transitionTo({ state: askPayment });
518
+
519
+ const savePayment = askPayment.transitionTo(
520
+ { toolState: savePaymentInfo },
521
+ "User provided payment methods or said not applicable"
522
+ );
523
+
524
+ // Step 6: Suggest automatic routes
525
+ const suggestRoutes = savePayment.transitionTo({
526
+ chatState:
527
+ "Perfect! Now I'll create the essential routes. Based on what you told me, I'll automatically create:\n\n1. **Products and Services** - for when they ask what you offer\n2. **Pricing and Quotes** - for questions about prices\n3. **Payment Information** - payment methods and installments\n4. **Location and Contact** - address, website, and hours\n\nThese are the most important routes for any business. I'll create them automatically with the information you provided. Sound good?",
528
+ });
529
+
530
+ const createRoutes = suggestRoutes.transitionTo(
531
+ { toolState: addConversationRoute },
532
+ "User approved automatic route creation"
533
+ );
534
+
535
+ // Step 7: Review collected data
536
+ const reviewData = createRoutes.transitionTo(
537
+ { toolState: getCollectedData },
538
+ "Routes created successfully"
539
+ );
540
+
541
+ // Step 8: Summary and options
542
+ const summary = reviewData.transitionTo({
543
+ chatState:
544
+ "Done! ✅ I've configured everything:\n\n✓ Business information\n✓ Products/services and target audience\n✓ Location and contact\n✓ Payment methods\n✓ Essential conversation routes\n\nYour assistant is ready! It will use this information to automatically respond when customers ask. Do you want to add any custom routes or is everything good?",
545
+ });
546
+
547
+ // Step 9a: Add more routes
548
+ const askCustomRoute = summary.transitionTo(
549
+ {
550
+ chatState:
551
+ "Got it! Tell me about this additional route: what's the title, what kind of questions should it answer, and what keywords do customers use? (e.g., 'Warranty and Exchange - answers about warranty, exchange, and returns - keywords: warranty, exchange, return')",
552
+ },
553
+ "User wants to add more routes"
554
+ );
555
+
556
+ const saveCustomRoute = askCustomRoute.transitionTo(
557
+ { toolState: addConversationRoute },
558
+ "User provided custom route information"
559
+ );
560
+
561
+ // Loop back to summary after adding custom route
562
+ saveCustomRoute.transitionTo({ state: summary });
563
+
564
+ // Step 9b: Final confirmation
565
+ const completion = summary.transitionTo(
566
+ {
567
+ chatState:
568
+ "🎉 Perfect! Setup complete! Your WhatsApp assistant is ready and will use all this information to automatically serve your customers. If you have any questions or need adjustments, just let me know!",
569
+ },
570
+ "User confirmed everything is okay"
571
+ );
572
+
573
+ completion.transitionTo({ state: END_ROUTE });
574
+
575
+ // ==================== Alternative: Chained Approach ====================
576
+ // For simpler linear flows, you can use chaining for conciseness:
577
+
578
+ // Example of a simple feedback collection route
579
+ const feedbackRoute = agent.createRoute({
580
+ title: "Collect Feedback",
581
+ description: "Quick feedback collection from completed onboarding",
582
+ conditions: ["User wants to provide feedback"],
583
+ });
584
+
585
+ // Beautiful fluent chaining for linear flows
586
+ feedbackRoute.initialState
587
+ .transitionTo({
588
+ chatState: "How would you rate your onboarding experience? (1-5 stars)",
589
+ })
590
+ .transitionTo({
591
+ chatState: "What did you like most about the process?",
592
+ })
593
+ .transitionTo({
594
+ chatState: "Is there anything we could improve?",
595
+ })
596
+ .transitionTo({
597
+ chatState: "Thank you for your feedback! It helps us improve. 🙏",
598
+ })
599
+ .transitionTo({ state: END_ROUTE });
600
+
601
+ // ==================== Global Guidelines ====================
602
+
603
+ agent
604
+ .createGuideline({
605
+ condition: "User seems confused or doesn't understand something",
606
+ action:
607
+ "Be patient and provide practical examples of what you need. E.g., 'José Silva Street, 123, São Paulo - SP' for address",
608
+ })
609
+ .createGuideline({
610
+ condition: "User provides incomplete or very vague information",
611
+ action:
612
+ "Politely ask for the missing specific details. E.g., 'You mentioned the address, but what's the city and state?'",
613
+ })
614
+ .createGuideline({
615
+ condition:
616
+ "User wants to skip information saying they don't have it or it doesn't apply",
617
+ action:
618
+ "Be smart: if the information is critical for their business type (e.g., address for physical store, website for e-commerce), explain the importance. If not critical, accept it and move forward saying 'no problem, that's fine'",
619
+ })
620
+ .createGuideline({
621
+ condition: "User has physical store but said online-only or vice versa",
622
+ action:
623
+ "Adjust the flow dynamically: if they have a physical store, prioritize address and hours. If online-only, prioritize website/social media and digital support hours. Don't ask for irrelevant information",
624
+ })
625
+ .createGuideline({
626
+ condition: "User asks why they need to provide certain information",
627
+ action:
628
+ "Explain practically: 'This information will help your assistant automatically answer customers when they ask about this. E.g., when they ask about payment methods, the assistant will inform automatically'",
629
+ })
630
+ .createGuideline({
631
+ condition:
632
+ "User wants to edit or correct something they already provided",
633
+ action:
634
+ "Accept promptly and update the information: 'Of course! I'll update to...'. Use the appropriate tool to save the correction",
635
+ })
636
+ .createGuideline({
637
+ condition: "User asks a question unrelated to onboarding",
638
+ action:
639
+ "Answer briefly and redirect: 'I understand, but let's finish the setup first? We're almost there!'",
640
+ });
641
+
642
+ return agent;
643
+ }
644
+
645
+ // ==================== Example Usage ====================
646
+
647
+ async function main() {
648
+ console.log("=".repeat(60));
649
+ console.log("Business Onboarding Agent - Example");
650
+ console.log("=".repeat(60));
651
+
652
+ // Create agent with sample initial data
653
+ const agent = await createBusinessOnboardingAgent(
654
+ "user_123",
655
+ "Alice",
656
+ "session_456",
657
+ {
658
+ routes: [],
659
+ // Optionally pre-populate some data:
660
+ // business: {
661
+ // businessName: "Alice's Boutique",
662
+ // }
663
+ }
664
+ );
665
+
666
+ console.log("\nAgent:", agent.name);
667
+ console.log("Description:", agent.description);
668
+ console.log("Routes:", agent.getRoutes().length);
669
+ console.log("Guidelines:", agent.getGuidelines().length);
670
+
671
+ // Print route structure
672
+ console.log("\n" + "=".repeat(60));
673
+ const routes = agent.getRoutes();
674
+ for (const route of routes) {
675
+ console.log("\n" + route.describe());
676
+ }
677
+
678
+ // Simulate a conversation
679
+ console.log("\n" + "=".repeat(60));
680
+ console.log("Conversation Simulation");
681
+ console.log("=".repeat(60) + "\n");
682
+
683
+ const history = [
684
+ createMessageEvent(
685
+ EventSource.CUSTOMER,
686
+ "Alice",
687
+ "Hi, I want to set up my assistant"
688
+ ),
689
+ ];
690
+
691
+ // Generate response (requires valid API key)
692
+ try {
693
+ const response = await agent.respond({ history });
694
+ console.log("Agent:", response.message);
695
+ console.log("\nRoute:", response.route?.title);
696
+ console.log("State:", response.state?.description);
697
+ } catch (error: any) {
698
+ console.log("\n(Skipping AI response - requires valid API key)");
699
+ console.log("Error:", error.message);
700
+ }
701
+ }
702
+
703
+ // Run if executed directly
704
+ if (import.meta.url === `file://${process.argv[1]}`) {
705
+ main().catch(console.error);
706
+ }
707
+
708
+ export { createBusinessOnboardingAgent };
@@ -13,10 +13,10 @@
13
13
 
14
14
  import {
15
15
  Agent,
16
- GeminiProvider,
17
16
  defineTool,
18
17
  createMessageEvent,
19
18
  EventSource,
19
+ GeminiProvider,
20
20
  type Term,
21
21
  type Guideline,
22
22
  type Capability,