@falai/agent 0.3.0 → 0.3.10

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 (49) hide show
  1. package/README.md +158 -9
  2. package/dist/cjs/core/Agent.d.ts +12 -0
  3. package/dist/cjs/core/Agent.d.ts.map +1 -1
  4. package/dist/cjs/core/Agent.js +37 -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/types/route.d.ts +6 -0
  19. package/dist/cjs/types/route.d.ts.map +1 -1
  20. package/dist/core/Agent.d.ts +12 -0
  21. package/dist/core/Agent.d.ts.map +1 -1
  22. package/dist/core/Agent.js +37 -1
  23. package/dist/core/Agent.js.map +1 -1
  24. package/dist/core/DomainRegistry.d.ts +10 -0
  25. package/dist/core/DomainRegistry.d.ts.map +1 -1
  26. package/dist/core/DomainRegistry.js +25 -0
  27. package/dist/core/DomainRegistry.js.map +1 -1
  28. package/dist/core/PromptBuilder.d.ts +9 -1
  29. package/dist/core/PromptBuilder.d.ts.map +1 -1
  30. package/dist/core/PromptBuilder.js +49 -2
  31. package/dist/core/PromptBuilder.js.map +1 -1
  32. package/dist/core/Route.d.ts +16 -0
  33. package/dist/core/Route.d.ts.map +1 -1
  34. package/dist/core/Route.js +22 -0
  35. package/dist/core/Route.js.map +1 -1
  36. package/dist/types/route.d.ts +6 -0
  37. package/dist/types/route.d.ts.map +1 -1
  38. package/docs/API_REFERENCE.md +99 -2
  39. package/docs/CONSTRUCTOR_OPTIONS.md +178 -37
  40. package/docs/GETTING_STARTED.md +10 -2
  41. package/examples/business-onboarding.ts +707 -0
  42. package/examples/domain-scoping.ts +266 -0
  43. package/examples/rules-prohibitions.ts +258 -0
  44. package/package.json +1 -1
  45. package/src/core/Agent.ts +46 -1
  46. package/src/core/DomainRegistry.ts +30 -0
  47. package/src/core/PromptBuilder.ts +70 -3
  48. package/src/core/Route.ts +28 -0
  49. package/src/types/route.ts +6 -0
@@ -0,0 +1,707 @@
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
+ GeminiProvider,
17
+ END_ROUTE,
18
+ EventSource,
19
+ createMessageEvent,
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 GeminiProvider({
366
+ apiKey: process.env.GEMINI_API_KEY || "test-key",
367
+ model: "models/gemini-2.0-flash-exp",
368
+ retryConfig: {
369
+ timeout: 60000,
370
+ retries: 3,
371
+ },
372
+ });
373
+
374
+ // Create agent with lifecycle hooks for automatic persistence
375
+ const agent = new Agent<OnboardingContext>({
376
+ name: "Business Onboarding Assistant",
377
+ description:
378
+ "A specialized assistant that helps businesses set up intelligent conversation routes for their customers.",
379
+ goal: "Collect comprehensive business information and create personalized conversation routes",
380
+ ai: provider,
381
+ context: {
382
+ userId,
383
+ userName,
384
+ sessionId,
385
+ collectedData: initialData,
386
+ },
387
+ // Lifecycle hooks enable agent caching!
388
+ hooks: {
389
+ // Load fresh context before each response
390
+ beforeRespond: async (currentContext) => {
391
+ // In a real app, fetch from database here
392
+ console.log(
393
+ `[beforeRespond] Loading fresh context for session ${sessionId}`
394
+ );
395
+ // Return updated context
396
+ return currentContext;
397
+ },
398
+
399
+ // Automatically persist context updates
400
+ onContextUpdate: async (newContext) => {
401
+ // In a real app, save to database here
402
+ console.log(
403
+ `[onContextUpdate] Persisting context for session ${sessionId}`
404
+ );
405
+ console.log(
406
+ "Updated data:",
407
+ JSON.stringify(newContext.collectedData, null, 2)
408
+ );
409
+ },
410
+ },
411
+ });
412
+
413
+ // Create the main onboarding route
414
+ const onboardingRoute = agent.createRoute({
415
+ title: "Business Onboarding",
416
+ description: "Complete onboarding process to configure personalized routes",
417
+ conditions: ["User is starting the onboarding process"],
418
+ });
419
+
420
+ // ==================== Build the Flow ====================
421
+
422
+ // For complex flows with branching, we use step-by-step approach
423
+ // This makes it easier to reference states for branching logic
424
+
425
+ // Step 0: Welcome
426
+ const welcome = onboardingRoute.initialState.transitionTo({
427
+ chatState: `Hello ${userName}! 👋 I'm your setup assistant. I'll help you configure your WhatsApp assistant by collecting practical information about your business. ${
428
+ initialData.business?.businessName
429
+ ? `I see your company is "${initialData.business.businessName}".`
430
+ : ""
431
+ } Let's begin! This will only take a few minutes.`,
432
+ });
433
+
434
+ // Step 1: Business basics - Ask
435
+ const askBusiness = welcome.transitionTo({
436
+ chatState:
437
+ initialData.business?.businessName &&
438
+ initialData.business?.businessDescription &&
439
+ initialData.business?.businessSector
440
+ ? `Please confirm: your company is "${initialData.business.businessName}", operates in "${initialData.business.businessSector}", and "${initialData.business.businessDescription}". Is this correct?`
441
+ : initialData.business?.businessName
442
+ ? `Your company "${initialData.business.businessName}" - what sector do you operate in? And what exactly do you do? (brief description)`
443
+ : "First, the basics: what's your company name, sector, and what do you do? (e.g., 'Store X, retail, we sell women's clothing')",
444
+ });
445
+
446
+ // Step 1: Business basics - Save
447
+ const saveBusiness = askBusiness.transitionTo(
448
+ { toolState: saveBusinessInfo },
449
+ "User provided company name, sector, and description"
450
+ );
451
+
452
+ // Step 2: Products/Services - Ask
453
+ const askProducts = saveBusiness.transitionTo({
454
+ chatState:
455
+ "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')",
456
+ });
457
+
458
+ // Step 2: Products/Services - Save
459
+ const saveProducts = askProducts.transitionTo(
460
+ { toolState: saveProductsServices },
461
+ "User listed products/services and target audience"
462
+ );
463
+
464
+ // Step 3: Location - Branch point
465
+ const askLocation = saveProducts.transitionTo({
466
+ chatState:
467
+ "Great! Do you have a physical store or in-person service location? (answer 'yes' or 'no')",
468
+ });
469
+
470
+ // Step 3a: Physical store path
471
+ const askPhysicalLocation = askLocation.transitionTo(
472
+ {
473
+ chatState:
474
+ "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')",
475
+ },
476
+ "User has a physical store"
477
+ );
478
+
479
+ const savePhysicalLocation = askPhysicalLocation.transitionTo(
480
+ { toolState: saveLocationInfo },
481
+ "User provided physical address"
482
+ );
483
+
484
+ // Step 3b: Online-only path
485
+ const askOnlineLocation = askLocation.transitionTo(
486
+ {
487
+ chatState:
488
+ "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')",
489
+ },
490
+ "User does not have a physical store"
491
+ );
492
+
493
+ const saveOnlineLocation = askOnlineLocation.transitionTo(
494
+ { toolState: saveContactInfo },
495
+ "User provided website/social media and support hours"
496
+ );
497
+
498
+ // Step 4: Contact info (convergence point for physical stores)
499
+ const askContact = savePhysicalLocation.transitionTo({
500
+ chatState:
501
+ "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')",
502
+ });
503
+
504
+ const saveContact = askContact.transitionTo(
505
+ { toolState: saveContactInfo },
506
+ "User provided website/social media"
507
+ );
508
+
509
+ // Step 5: Payment info (convergence point from both paths)
510
+ const askPayment = saveContact.transitionTo({
511
+ chatState:
512
+ "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)",
513
+ });
514
+
515
+ // Also connect online path to payment
516
+ saveOnlineLocation.transitionTo({ state: askPayment });
517
+
518
+ const savePayment = askPayment.transitionTo(
519
+ { toolState: savePaymentInfo },
520
+ "User provided payment methods or said not applicable"
521
+ );
522
+
523
+ // Step 6: Suggest automatic routes
524
+ const suggestRoutes = savePayment.transitionTo({
525
+ chatState:
526
+ "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?",
527
+ });
528
+
529
+ const createRoutes = suggestRoutes.transitionTo(
530
+ { toolState: addConversationRoute },
531
+ "User approved automatic route creation"
532
+ );
533
+
534
+ // Step 7: Review collected data
535
+ const reviewData = createRoutes.transitionTo(
536
+ { toolState: getCollectedData },
537
+ "Routes created successfully"
538
+ );
539
+
540
+ // Step 8: Summary and options
541
+ const summary = reviewData.transitionTo({
542
+ chatState:
543
+ "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?",
544
+ });
545
+
546
+ // Step 9a: Add more routes
547
+ const askCustomRoute = summary.transitionTo(
548
+ {
549
+ chatState:
550
+ "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')",
551
+ },
552
+ "User wants to add more routes"
553
+ );
554
+
555
+ const saveCustomRoute = askCustomRoute.transitionTo(
556
+ { toolState: addConversationRoute },
557
+ "User provided custom route information"
558
+ );
559
+
560
+ // Loop back to summary after adding custom route
561
+ saveCustomRoute.transitionTo({ state: summary });
562
+
563
+ // Step 9b: Final confirmation
564
+ const completion = summary.transitionTo(
565
+ {
566
+ chatState:
567
+ "🎉 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!",
568
+ },
569
+ "User confirmed everything is okay"
570
+ );
571
+
572
+ completion.transitionTo({ state: END_ROUTE });
573
+
574
+ // ==================== Alternative: Chained Approach ====================
575
+ // For simpler linear flows, you can use chaining for conciseness:
576
+
577
+ // Example of a simple feedback collection route
578
+ const feedbackRoute = agent.createRoute({
579
+ title: "Collect Feedback",
580
+ description: "Quick feedback collection from completed onboarding",
581
+ conditions: ["User wants to provide feedback"],
582
+ });
583
+
584
+ // Beautiful fluent chaining for linear flows
585
+ feedbackRoute.initialState
586
+ .transitionTo({
587
+ chatState: "How would you rate your onboarding experience? (1-5 stars)",
588
+ })
589
+ .transitionTo({
590
+ chatState: "What did you like most about the process?",
591
+ })
592
+ .transitionTo({
593
+ chatState: "Is there anything we could improve?",
594
+ })
595
+ .transitionTo({
596
+ chatState: "Thank you for your feedback! It helps us improve. 🙏",
597
+ })
598
+ .transitionTo({ state: END_ROUTE });
599
+
600
+ // ==================== Global Guidelines ====================
601
+
602
+ agent
603
+ .createGuideline({
604
+ condition: "User seems confused or doesn't understand something",
605
+ action:
606
+ "Be patient and provide practical examples of what you need. E.g., 'José Silva Street, 123, São Paulo - SP' for address",
607
+ })
608
+ .createGuideline({
609
+ condition: "User provides incomplete or very vague information",
610
+ action:
611
+ "Politely ask for the missing specific details. E.g., 'You mentioned the address, but what's the city and state?'",
612
+ })
613
+ .createGuideline({
614
+ condition:
615
+ "User wants to skip information saying they don't have it or it doesn't apply",
616
+ action:
617
+ "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'",
618
+ })
619
+ .createGuideline({
620
+ condition: "User has physical store but said online-only or vice versa",
621
+ action:
622
+ "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",
623
+ })
624
+ .createGuideline({
625
+ condition: "User asks why they need to provide certain information",
626
+ action:
627
+ "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'",
628
+ })
629
+ .createGuideline({
630
+ condition:
631
+ "User wants to edit or correct something they already provided",
632
+ action:
633
+ "Accept promptly and update the information: 'Of course! I'll update to...'. Use the appropriate tool to save the correction",
634
+ })
635
+ .createGuideline({
636
+ condition: "User asks a question unrelated to onboarding",
637
+ action:
638
+ "Answer briefly and redirect: 'I understand, but let's finish the setup first? We're almost there!'",
639
+ });
640
+
641
+ return agent;
642
+ }
643
+
644
+ // ==================== Example Usage ====================
645
+
646
+ async function main() {
647
+ console.log("=".repeat(60));
648
+ console.log("Business Onboarding Agent - Example");
649
+ console.log("=".repeat(60));
650
+
651
+ // Create agent with sample initial data
652
+ const agent = await createBusinessOnboardingAgent(
653
+ "user_123",
654
+ "Alice",
655
+ "session_456",
656
+ {
657
+ routes: [],
658
+ // Optionally pre-populate some data:
659
+ // business: {
660
+ // businessName: "Alice's Boutique",
661
+ // }
662
+ }
663
+ );
664
+
665
+ console.log("\nAgent:", agent.name);
666
+ console.log("Description:", agent.description);
667
+ console.log("Routes:", agent.getRoutes().length);
668
+ console.log("Guidelines:", agent.getGuidelines().length);
669
+
670
+ // Print route structure
671
+ console.log("\n" + "=".repeat(60));
672
+ const routes = agent.getRoutes();
673
+ for (const route of routes) {
674
+ console.log("\n" + route.describe());
675
+ }
676
+
677
+ // Simulate a conversation
678
+ console.log("\n" + "=".repeat(60));
679
+ console.log("Conversation Simulation");
680
+ console.log("=".repeat(60) + "\n");
681
+
682
+ const history = [
683
+ createMessageEvent(
684
+ EventSource.CUSTOMER,
685
+ "Alice",
686
+ "Hi, I want to set up my assistant"
687
+ ),
688
+ ];
689
+
690
+ // Generate response (requires valid API key)
691
+ try {
692
+ const response = await agent.respond({ history });
693
+ console.log("Agent:", response.message);
694
+ console.log("\nRoute:", response.route?.title);
695
+ console.log("State:", response.state?.description);
696
+ } catch (error: any) {
697
+ console.log("\n(Skipping AI response - requires valid API key)");
698
+ console.log("Error:", error.message);
699
+ }
700
+ }
701
+
702
+ // Run if executed directly
703
+ if (import.meta.url === `file://${process.argv[1]}`) {
704
+ main().catch(console.error);
705
+ }
706
+
707
+ export { createBusinessOnboardingAgent };