@ema.co/mcp-toolkit 1.5.1 → 1.6.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.

Potentially problematic release.


This version of @ema.co/mcp-toolkit might be problematic. Click here for more details.

@@ -0,0 +1,978 @@
1
+ /**
2
+ * Demo Kit Generator
3
+ *
4
+ * Generates comprehensive demo data packages for AI Employees that ensure
5
+ * reliable demos through:
6
+ * - Guaranteed RAG search hits with pre-loaded KB documents
7
+ * - Complete mock datasets tailored to the persona's workflow
8
+ * - Fixed response fallbacks for critical demo questions
9
+ * - Validation queries to verify demo readiness
10
+ */
11
+ // ─────────────────────────────────────────────────────────────────────────────
12
+ // Built-in Scenarios
13
+ // ─────────────────────────────────────────────────────────────────────────────
14
+ export const DEMO_SCENARIOS = {
15
+ "sales-sdr": {
16
+ id: "sales-sdr",
17
+ name: "Sales Development Representative",
18
+ description: "SDR demo for qualifying leads, booking meetings, handling objections",
19
+ persona_types: ["voice", "chat"],
20
+ tags: ["sales", "sdr", "lead-qualification", "booking"],
21
+ intents: [
22
+ {
23
+ name: "company_info",
24
+ description: "Questions about the company/product being sold",
25
+ example_questions: ["What does your company do?", "Tell me about your product"],
26
+ },
27
+ {
28
+ name: "pricing",
29
+ description: "Pricing and package questions",
30
+ example_questions: ["How much does it cost?", "What are your pricing plans?"],
31
+ },
32
+ {
33
+ name: "book_meeting",
34
+ description: "Request to schedule a demo or meeting",
35
+ example_questions: ["Can I schedule a demo?", "I'd like to talk to sales"],
36
+ },
37
+ {
38
+ name: "objection_handling",
39
+ description: "Common sales objections",
40
+ example_questions: ["We're happy with our current solution", "It's too expensive"],
41
+ },
42
+ {
43
+ name: "qualification",
44
+ description: "Qualifying questions about the prospect",
45
+ example_questions: ["What's your current setup?", "How many users do you have?"],
46
+ },
47
+ ],
48
+ entities: [
49
+ {
50
+ type: "company",
51
+ count: 3,
52
+ template: {
53
+ name: "{{company_name}}",
54
+ industry: "{{industry}}",
55
+ size: "{{size}}",
56
+ pain_points: ["{{pain_point_1}}", "{{pain_point_2}}"],
57
+ },
58
+ },
59
+ {
60
+ type: "product",
61
+ count: 2,
62
+ template: {
63
+ name: "{{product_name}}",
64
+ description: "{{description}}",
65
+ pricing: { starter: 99, pro: 299, enterprise: "custom" },
66
+ features: ["{{feature_1}}", "{{feature_2}}", "{{feature_3}}"],
67
+ },
68
+ },
69
+ ],
70
+ qa_pairs: [
71
+ {
72
+ phase: "intro",
73
+ question: "Hi, I saw your website and I'm curious about what you do.",
74
+ answer_template: "Thanks for reaching out! We help companies like yours {{value_prop}}. I'd love to learn more about your needs - what challenges are you currently facing with {{pain_area}}?",
75
+ intent: "company_info",
76
+ },
77
+ {
78
+ phase: "main",
79
+ question: "How much does it cost?",
80
+ answer_template: "Great question! Our pricing starts at $99/month for our Starter plan, which includes {{starter_features}}. Most companies like yours go with our Pro plan at $299/month. Would you like me to walk you through what's included?",
81
+ intent: "pricing",
82
+ },
83
+ {
84
+ phase: "main",
85
+ question: "Can I see a demo?",
86
+ answer_template: "Absolutely! I'd be happy to set that up. Our product specialists can give you a personalized walkthrough. What day works best for you this week - would Tuesday or Thursday afternoon work?",
87
+ intent: "book_meeting",
88
+ },
89
+ {
90
+ phase: "advanced",
91
+ question: "We're already using a competitor product.",
92
+ answer_template: "I hear that a lot, and it's actually why many of our best customers switched to us. What they found was {{differentiator}}. Out of curiosity, what do you wish was better about your current solution?",
93
+ intent: "objection_handling",
94
+ },
95
+ {
96
+ phase: "closing",
97
+ question: "Send me some information.",
98
+ answer_template: "Of course! I'll send over a summary of what we discussed along with a link to schedule that demo whenever you're ready. What email should I send that to?",
99
+ intent: "book_meeting",
100
+ },
101
+ ],
102
+ },
103
+ "support-tier1": {
104
+ id: "support-tier1",
105
+ name: "Tier 1 Support Agent",
106
+ description: "Customer support demo handling tickets, FAQs, and escalations",
107
+ persona_types: ["voice", "chat"],
108
+ tags: ["support", "customer-service", "helpdesk", "tickets"],
109
+ intents: [
110
+ {
111
+ name: "account_lookup",
112
+ description: "Look up customer account information",
113
+ example_questions: ["What's my account status?", "Can you pull up my account?"],
114
+ },
115
+ {
116
+ name: "troubleshooting",
117
+ description: "Technical troubleshooting",
118
+ example_questions: ["It's not working", "I'm getting an error"],
119
+ },
120
+ {
121
+ name: "billing",
122
+ description: "Billing and payment questions",
123
+ example_questions: ["Why was I charged?", "Can I get a refund?"],
124
+ },
125
+ {
126
+ name: "escalation",
127
+ description: "Request for manager or escalation",
128
+ example_questions: ["I want to speak to a manager", "This needs to be escalated"],
129
+ },
130
+ {
131
+ name: "how_to",
132
+ description: "How-to questions",
133
+ example_questions: ["How do I reset my password?", "How do I change my plan?"],
134
+ },
135
+ ],
136
+ entities: [
137
+ {
138
+ type: "customer",
139
+ count: 3,
140
+ template: {
141
+ id: "CUST-{{id}}",
142
+ name: "{{name}}",
143
+ email: "{{email}}",
144
+ plan: "{{plan}}",
145
+ status: "active",
146
+ since: "{{date}}",
147
+ },
148
+ },
149
+ {
150
+ type: "faq",
151
+ count: 5,
152
+ template: {
153
+ question: "{{question}}",
154
+ answer: "{{answer}}",
155
+ category: "{{category}}",
156
+ },
157
+ },
158
+ {
159
+ type: "ticket",
160
+ count: 2,
161
+ template: {
162
+ id: "TKT-{{id}}",
163
+ subject: "{{subject}}",
164
+ status: "{{status}}",
165
+ priority: "{{priority}}",
166
+ },
167
+ },
168
+ ],
169
+ qa_pairs: [
170
+ {
171
+ phase: "intro",
172
+ question: "Hi, I need help with my account.",
173
+ answer_template: "Of course, I'd be happy to help! To pull up your account, could you please provide your email address or account number?",
174
+ intent: "account_lookup",
175
+ },
176
+ {
177
+ phase: "main",
178
+ question: "How do I reset my password?",
179
+ answer_template: "I can help you with that! Here's how to reset your password:\n1. Go to the login page\n2. Click 'Forgot Password'\n3. Enter your email address\n4. Check your inbox for the reset link\n\nThe link expires in 24 hours. Would you like me to send you a reset email right now?",
180
+ intent: "how_to",
181
+ required_entity_type: "faq",
182
+ },
183
+ {
184
+ phase: "main",
185
+ question: "I'm getting an error when I try to login.",
186
+ answer_template: "I'm sorry you're experiencing that! Let me help you troubleshoot. First, could you tell me:\n1. What error message are you seeing?\n2. Are you using the web app or mobile app?\n\nIn the meantime, try clearing your browser cache and cookies, which often resolves login issues.",
187
+ intent: "troubleshooting",
188
+ },
189
+ {
190
+ phase: "advanced",
191
+ question: "I want a refund, this product doesn't work.",
192
+ answer_template: "I understand your frustration, and I'm sorry the product isn't meeting your expectations. Let me look into your account to see what options we have. Before we discuss a refund, would you mind if I tried to resolve the issue you're experiencing? Often we can fix things quickly.",
193
+ intent: "billing",
194
+ },
195
+ {
196
+ phase: "closing",
197
+ question: "Thanks, that's all I needed.",
198
+ answer_template: "You're welcome! I'm glad I could help. Is there anything else I can assist you with today? If you have any other questions later, don't hesitate to reach out. Have a great day!",
199
+ },
200
+ ],
201
+ },
202
+ "hr-assistant": {
203
+ id: "hr-assistant",
204
+ name: "HR Assistant",
205
+ description: "HR demo for policies, benefits, time-off requests",
206
+ persona_types: ["chat", "voice"],
207
+ tags: ["hr", "human-resources", "benefits", "policies"],
208
+ intents: [
209
+ {
210
+ name: "time_off",
211
+ description: "PTO and time-off requests",
212
+ example_questions: ["How do I request time off?", "What's my PTO balance?"],
213
+ },
214
+ {
215
+ name: "benefits",
216
+ description: "Benefits and insurance questions",
217
+ example_questions: ["What benefits do we have?", "How do I add a dependent?"],
218
+ },
219
+ {
220
+ name: "policies",
221
+ description: "Company policy questions",
222
+ example_questions: ["What's the remote work policy?", "What's the dress code?"],
223
+ },
224
+ {
225
+ name: "payroll",
226
+ description: "Payroll and compensation",
227
+ example_questions: ["When is payday?", "How do I update my direct deposit?"],
228
+ },
229
+ {
230
+ name: "onboarding",
231
+ description: "New employee questions",
232
+ example_questions: ["What do I need to complete for onboarding?", "Where do I get my badge?"],
233
+ },
234
+ ],
235
+ entities: [
236
+ {
237
+ type: "policy",
238
+ count: 5,
239
+ template: {
240
+ name: "{{policy_name}}",
241
+ category: "{{category}}",
242
+ summary: "{{summary}}",
243
+ details: "{{details}}",
244
+ last_updated: "{{date}}",
245
+ },
246
+ },
247
+ {
248
+ type: "benefit",
249
+ count: 3,
250
+ template: {
251
+ name: "{{benefit_name}}",
252
+ description: "{{description}}",
253
+ eligibility: "{{eligibility}}",
254
+ enrollment: "{{enrollment_info}}",
255
+ },
256
+ },
257
+ {
258
+ type: "employee",
259
+ count: 2,
260
+ template: {
261
+ id: "EMP-{{id}}",
262
+ name: "{{name}}",
263
+ department: "{{department}}",
264
+ pto_balance: "{{pto_days}} days",
265
+ start_date: "{{date}}",
266
+ },
267
+ },
268
+ ],
269
+ qa_pairs: [
270
+ {
271
+ phase: "intro",
272
+ question: "Hi, I have a question about my benefits.",
273
+ answer_template: "Hi! I'd be happy to help with your benefits questions. We offer comprehensive health, dental, and vision insurance, plus a 401(k) with company match. What specific benefit would you like to know more about?",
274
+ intent: "benefits",
275
+ },
276
+ {
277
+ phase: "main",
278
+ question: "How do I request time off?",
279
+ answer_template: "To request time off:\n1. Log into the HR portal\n2. Click 'Time Off' in the menu\n3. Select your dates and type (PTO, sick, etc.)\n4. Add a note if needed and submit\n\nYour manager will receive an automatic notification. You currently have {{pto_balance}} PTO days available. Would you like me to help you check your balance?",
280
+ intent: "time_off",
281
+ required_entity_type: "employee",
282
+ },
283
+ {
284
+ phase: "main",
285
+ question: "What's the work from home policy?",
286
+ answer_template: "Our hybrid work policy allows employees to work remotely up to 3 days per week, with at least 2 days in the office for collaboration. You'll need to coordinate with your manager on which days. All remote work requires a stable internet connection and appropriate workspace. Is there a specific aspect of the policy you'd like more details on?",
287
+ intent: "policies",
288
+ required_entity_type: "policy",
289
+ },
290
+ {
291
+ phase: "advanced",
292
+ question: "How do I add my spouse to my health insurance?",
293
+ answer_template: "Great question! You can add your spouse during open enrollment (November 1-15) or within 30 days of a qualifying life event like marriage. To add them:\n1. Go to the Benefits portal\n2. Click 'Life Events'\n3. Select 'Marriage' and upload your marriage certificate\n4. Choose the plan that covers your spouse\n\nWould you like me to send you the direct link to get started?",
294
+ intent: "benefits",
295
+ },
296
+ {
297
+ phase: "closing",
298
+ question: "Where can I find all the HR forms?",
299
+ answer_template: "All HR forms are available in the HR portal under 'Resources > Forms'. The most commonly used ones include:\n- Direct deposit change form\n- W-4 updates\n- Benefits enrollment\n- Time off requests\n\nIs there a specific form you're looking for? I can send you a direct link.",
300
+ intent: "policies",
301
+ },
302
+ ],
303
+ },
304
+ };
305
+ // ─────────────────────────────────────────────────────────────────────────────
306
+ // Sample Entity Data
307
+ // ─────────────────────────────────────────────────────────────────────────────
308
+ export const SAMPLE_ENTITIES = {
309
+ company: [
310
+ {
311
+ name: "Acme Corporation",
312
+ industry: "Manufacturing",
313
+ size: "500-1000 employees",
314
+ annual_revenue: "$50M",
315
+ headquarters: "Chicago, IL",
316
+ pain_points: ["Manual processes", "Scaling challenges", "Data silos"],
317
+ current_solution: "Spreadsheets and legacy software",
318
+ },
319
+ {
320
+ name: "TechStart Inc",
321
+ industry: "Technology",
322
+ size: "50-100 employees",
323
+ annual_revenue: "$5M",
324
+ headquarters: "San Francisco, CA",
325
+ pain_points: ["Fast growth", "Hiring challenges", "Process automation"],
326
+ current_solution: "Multiple point solutions",
327
+ },
328
+ {
329
+ name: "Global Retail Co",
330
+ industry: "Retail",
331
+ size: "5000+ employees",
332
+ annual_revenue: "$500M",
333
+ headquarters: "New York, NY",
334
+ pain_points: ["Inventory management", "Customer experience", "Omnichannel"],
335
+ current_solution: "Enterprise legacy system",
336
+ },
337
+ ],
338
+ product: [
339
+ {
340
+ name: "Enterprise Suite Pro",
341
+ sku: "ESP-001",
342
+ description: "All-in-one enterprise solution for growing businesses",
343
+ pricing: {
344
+ starter: { price: 99, features: ["5 users", "Basic support", "Core features"] },
345
+ pro: { price: 299, features: ["25 users", "Priority support", "Advanced features", "API access"] },
346
+ enterprise: { price: "Custom", features: ["Unlimited users", "24/7 support", "Custom integrations", "Dedicated CSM"] },
347
+ },
348
+ differentiators: ["AI-powered automation", "Single platform", "60% faster implementation"],
349
+ },
350
+ {
351
+ name: "Quick Start Bundle",
352
+ sku: "QSB-001",
353
+ description: "Perfect for small teams getting started",
354
+ pricing: {
355
+ monthly: 49,
356
+ annual: 470,
357
+ },
358
+ features: ["3 users", "Email support", "Essential features"],
359
+ },
360
+ ],
361
+ customer: [
362
+ {
363
+ id: "CUST-001",
364
+ name: "John Smith",
365
+ email: "john.smith@example.com",
366
+ plan: "Pro",
367
+ status: "active",
368
+ since: "2023-06-15",
369
+ lifetime_value: "$3,500",
370
+ tickets_opened: 2,
371
+ last_contact: "2024-01-10",
372
+ },
373
+ {
374
+ id: "CUST-002",
375
+ name: "Sarah Johnson",
376
+ email: "sarah.j@company.com",
377
+ plan: "Enterprise",
378
+ status: "active",
379
+ since: "2022-03-01",
380
+ lifetime_value: "$45,000",
381
+ tickets_opened: 5,
382
+ last_contact: "2024-01-15",
383
+ },
384
+ {
385
+ id: "CUST-003",
386
+ name: "Demo User",
387
+ email: "demo@example.com",
388
+ plan: "Starter",
389
+ status: "active",
390
+ since: "2024-01-01",
391
+ lifetime_value: "$297",
392
+ tickets_opened: 0,
393
+ last_contact: "2024-01-20",
394
+ },
395
+ ],
396
+ faq: [
397
+ {
398
+ id: "FAQ-001",
399
+ question: "How do I reset my password?",
400
+ answer: "To reset your password: 1) Go to the login page, 2) Click 'Forgot Password', 3) Enter your email, 4) Check your inbox for the reset link (expires in 24 hours), 5) Click the link and create a new password.",
401
+ category: "Account",
402
+ },
403
+ {
404
+ id: "FAQ-002",
405
+ question: "What payment methods do you accept?",
406
+ answer: "We accept all major credit cards (Visa, MasterCard, American Express), PayPal, and bank transfers for annual Enterprise plans. All payments are processed securely through Stripe.",
407
+ category: "Billing",
408
+ },
409
+ {
410
+ id: "FAQ-003",
411
+ question: "How do I cancel my subscription?",
412
+ answer: "You can cancel anytime from Settings > Subscription > Cancel Plan. Your access continues until the end of your billing period. We also offer a pause option if you need a temporary break.",
413
+ category: "Billing",
414
+ },
415
+ {
416
+ id: "FAQ-004",
417
+ question: "Is my data secure?",
418
+ answer: "Yes! We use bank-level encryption (AES-256), are SOC 2 Type II certified, GDPR compliant, and never share your data with third parties. Your data is backed up daily across multiple secure locations.",
419
+ category: "Security",
420
+ },
421
+ {
422
+ id: "FAQ-005",
423
+ question: "Do you offer a free trial?",
424
+ answer: "Yes! We offer a 14-day free trial with full access to all Pro features. No credit card required to start. You can upgrade, downgrade, or cancel anytime during or after the trial.",
425
+ category: "Pricing",
426
+ },
427
+ ],
428
+ policy: [
429
+ {
430
+ id: "POL-001",
431
+ name: "Remote Work Policy",
432
+ category: "Workplace",
433
+ summary: "Hybrid work with up to 3 remote days per week",
434
+ details: "Employees may work remotely up to 3 days per week with manager approval. Core collaboration hours are 10am-3pm in your local timezone. Equipment and internet stipend available.",
435
+ last_updated: "2024-01-01",
436
+ },
437
+ {
438
+ id: "POL-002",
439
+ name: "PTO Policy",
440
+ category: "Time Off",
441
+ summary: "Unlimited PTO with 2-week notice for extended leave",
442
+ details: "We offer unlimited PTO. For time off over 5 consecutive days, please provide 2 weeks notice. All PTO must be approved by your manager. Company holidays do not count against PTO.",
443
+ last_updated: "2024-01-01",
444
+ },
445
+ {
446
+ id: "POL-003",
447
+ name: "Expense Reimbursement",
448
+ category: "Finance",
449
+ summary: "Submit expenses within 30 days for reimbursement",
450
+ details: "Business expenses must be pre-approved for amounts over $100. Submit receipts via the expense portal within 30 days. Reimbursements are processed bi-weekly.",
451
+ last_updated: "2023-11-15",
452
+ },
453
+ ],
454
+ employee: [
455
+ {
456
+ id: "EMP-001",
457
+ name: "Alex Demo",
458
+ email: "alex.demo@company.com",
459
+ department: "Engineering",
460
+ title: "Software Engineer",
461
+ start_date: "2023-01-15",
462
+ pto_balance: 15,
463
+ manager: "Jane Manager",
464
+ },
465
+ {
466
+ id: "EMP-002",
467
+ name: "Sam Sample",
468
+ email: "sam.sample@company.com",
469
+ department: "Sales",
470
+ title: "Account Executive",
471
+ start_date: "2022-06-01",
472
+ pto_balance: 12,
473
+ manager: "Bob Director",
474
+ },
475
+ ],
476
+ benefit: [
477
+ {
478
+ id: "BEN-001",
479
+ name: "Health Insurance",
480
+ description: "Comprehensive medical, dental, and vision coverage",
481
+ eligibility: "Full-time employees from day 1",
482
+ provider: "Blue Cross Blue Shield",
483
+ employee_cost: "$150/month for individual, $400/month for family",
484
+ company_contribution: "80% of premium",
485
+ },
486
+ {
487
+ id: "BEN-002",
488
+ name: "401(k) Retirement",
489
+ description: "401(k) plan with company match",
490
+ eligibility: "After 90 days of employment",
491
+ match: "100% match up to 4% of salary",
492
+ vesting: "Immediate vesting on all contributions",
493
+ },
494
+ {
495
+ id: "BEN-003",
496
+ name: "Professional Development",
497
+ description: "Annual learning and development budget",
498
+ eligibility: "All full-time employees",
499
+ amount: "$1,500/year",
500
+ covers: "Courses, conferences, certifications, books",
501
+ },
502
+ ],
503
+ };
504
+ // ─────────────────────────────────────────────────────────────────────────────
505
+ // Generator Functions
506
+ // ─────────────────────────────────────────────────────────────────────────────
507
+ /**
508
+ * Analyze a workflow to detect demo requirements
509
+ */
510
+ export function analyzeWorkflowForDemo(workflowDef) {
511
+ const actions = (workflowDef.actions || []);
512
+ const intents = [];
513
+ const entityTypes = new Set();
514
+ let hasSearch = false;
515
+ let hasEmail = false;
516
+ let hasHitl = false;
517
+ let triggerType = "chat";
518
+ for (const action of actions) {
519
+ const actionDef = action.action;
520
+ const name = actionDef?.name?.name || "";
521
+ // Detect trigger type
522
+ if (name.includes("voice_trigger"))
523
+ triggerType = "voice";
524
+ if (name.includes("document_trigger"))
525
+ triggerType = "document";
526
+ // Detect search nodes
527
+ if (name === "search" || name.includes("search"))
528
+ hasSearch = true;
529
+ // Detect email nodes
530
+ if (name === "send_email_agent" || name.includes("email"))
531
+ hasEmail = true;
532
+ // Detect HITL nodes
533
+ if (name === "general_hitl" || name.includes("hitl"))
534
+ hasHitl = true;
535
+ // Extract intents from categorizer
536
+ if (name.includes("categorizer")) {
537
+ const typeArgs = action.typeArguments;
538
+ const enumType = typeArgs?.categories;
539
+ // Try to find enum definition
540
+ const enumTypes = (workflowDef.enumTypes || []);
541
+ for (const et of enumTypes) {
542
+ const options = (et.options || []);
543
+ for (const opt of options) {
544
+ if (opt.name && opt.name !== "Fallback") {
545
+ intents.push(opt.name);
546
+ }
547
+ }
548
+ }
549
+ }
550
+ // Detect entity extraction
551
+ if (name.includes("entity_extraction")) {
552
+ entityTypes.add("customer"); // Common entity type
553
+ }
554
+ }
555
+ // Default entity types based on workflow characteristics
556
+ if (hasSearch) {
557
+ entityTypes.add("faq");
558
+ }
559
+ return {
560
+ intents,
561
+ required_entity_types: Array.from(entityTypes),
562
+ has_search: hasSearch,
563
+ has_email: hasEmail,
564
+ has_hitl: hasHitl,
565
+ trigger_type: triggerType,
566
+ };
567
+ }
568
+ /**
569
+ * Generate a demo document for a specific entity
570
+ */
571
+ export function generateDemoDocument(entityType, entityData, supportedQuestions = []) {
572
+ const id = (entityData.id || entityData.name || "unknown");
573
+ const name = (entityData.name || entityData.question || id);
574
+ let content = "";
575
+ const tags = [entityType];
576
+ switch (entityType) {
577
+ case "customer":
578
+ content = generateCustomerDocument(entityData);
579
+ if (entityData.plan)
580
+ tags.push(String(entityData.plan));
581
+ if (entityData.status)
582
+ tags.push(String(entityData.status));
583
+ break;
584
+ case "product":
585
+ content = generateProductDocument(entityData);
586
+ if (entityData.sku)
587
+ tags.push(String(entityData.sku));
588
+ break;
589
+ case "faq":
590
+ content = generateFaqDocument(entityData);
591
+ if (entityData.category)
592
+ tags.push(String(entityData.category));
593
+ break;
594
+ case "policy":
595
+ content = generatePolicyDocument(entityData);
596
+ if (entityData.category)
597
+ tags.push(String(entityData.category));
598
+ break;
599
+ case "employee":
600
+ content = generateEmployeeDocument(entityData);
601
+ if (entityData.department)
602
+ tags.push(String(entityData.department));
603
+ break;
604
+ case "benefit":
605
+ content = generateBenefitDocument(entityData);
606
+ break;
607
+ case "company":
608
+ content = generateCompanyDocument(entityData);
609
+ if (entityData.industry)
610
+ tags.push(String(entityData.industry));
611
+ break;
612
+ default:
613
+ content = generateGenericDocument(entityType, entityData);
614
+ }
615
+ return {
616
+ filename: `${entityType}-${id.toLowerCase().replace(/[^a-z0-9]/g, "-")}.md`,
617
+ title: name,
618
+ entity_type: entityType,
619
+ content,
620
+ tags,
621
+ supports_questions: supportedQuestions,
622
+ };
623
+ }
624
+ function generateCustomerDocument(data) {
625
+ return `# Customer: ${data.name}
626
+
627
+ ## Metadata
628
+ <!-- ema_entity: customer -->
629
+ <!-- ema_id: ${data.id} -->
630
+ <!-- ema_tags: ${data.plan || "standard"}, ${data.status || "active"} -->
631
+
632
+ ## Account Overview
633
+ | Field | Value |
634
+ |-------|-------|
635
+ | Customer ID | ${data.id} |
636
+ | Name | ${data.name} |
637
+ | Email | ${data.email} |
638
+ | Plan | ${data.plan} |
639
+ | Status | ${data.status} |
640
+ | Customer Since | ${data.since} |
641
+
642
+ ## Account Details
643
+ - **Lifetime Value**: ${data.lifetime_value || "N/A"}
644
+ - **Support Tickets**: ${data.tickets_opened || 0} opened
645
+ - **Last Contact**: ${data.last_contact || "N/A"}
646
+
647
+ ## Notes
648
+ This customer has been with us since ${data.since}. ${data.plan === "Enterprise" ? "Enterprise customer with dedicated support." : ""}
649
+ `;
650
+ }
651
+ function generateProductDocument(data) {
652
+ const pricing = data.pricing;
653
+ let pricingSection = "";
654
+ if (pricing) {
655
+ pricingSection = "## Pricing\n";
656
+ for (const [tier, details] of Object.entries(pricing)) {
657
+ if (typeof details === "object" && details !== null) {
658
+ const d = details;
659
+ pricingSection += `### ${tier.charAt(0).toUpperCase() + tier.slice(1)}\n`;
660
+ pricingSection += `- **Price**: ${d.price || "Custom"}\n`;
661
+ if (d.features) {
662
+ pricingSection += `- **Features**: ${d.features.join(", ")}\n`;
663
+ }
664
+ pricingSection += "\n";
665
+ }
666
+ }
667
+ }
668
+ return `# Product: ${data.name}
669
+
670
+ ## Metadata
671
+ <!-- ema_entity: product -->
672
+ <!-- ema_id: ${data.sku || data.name} -->
673
+
674
+ ## Overview
675
+ | Field | Value |
676
+ |-------|-------|
677
+ | Name | ${data.name} |
678
+ | SKU | ${data.sku || "N/A"} |
679
+
680
+ ## Description
681
+ ${data.description || "No description available."}
682
+
683
+ ${pricingSection}
684
+
685
+ ## Key Differentiators
686
+ ${(data.differentiators || []).map((d) => `- ${d}`).join("\n") || "- See product documentation"}
687
+ `;
688
+ }
689
+ function generateFaqDocument(data) {
690
+ return `# FAQ: ${data.question}
691
+
692
+ ## Metadata
693
+ <!-- ema_entity: faq -->
694
+ <!-- ema_id: ${data.id} -->
695
+ <!-- ema_tags: ${data.category || "general"} -->
696
+
697
+ ## Question
698
+ ${data.question}
699
+
700
+ ## Answer
701
+ ${data.answer}
702
+
703
+ ## Category
704
+ ${data.category || "General"}
705
+ `;
706
+ }
707
+ function generatePolicyDocument(data) {
708
+ return `# Policy: ${data.name}
709
+
710
+ ## Metadata
711
+ <!-- ema_entity: policy -->
712
+ <!-- ema_id: ${data.id} -->
713
+ <!-- ema_tags: ${data.category || "general"}, policy -->
714
+
715
+ ## Summary
716
+ ${data.summary}
717
+
718
+ ## Full Policy
719
+ ${data.details}
720
+
721
+ ## Additional Information
722
+ - **Category**: ${data.category}
723
+ - **Last Updated**: ${data.last_updated}
724
+ `;
725
+ }
726
+ function generateEmployeeDocument(data) {
727
+ return `# Employee: ${data.name}
728
+
729
+ ## Metadata
730
+ <!-- ema_entity: employee -->
731
+ <!-- ema_id: ${data.id} -->
732
+ <!-- ema_tags: ${data.department || "general"} -->
733
+
734
+ ## Profile
735
+ | Field | Value |
736
+ |-------|-------|
737
+ | Employee ID | ${data.id} |
738
+ | Name | ${data.name} |
739
+ | Email | ${data.email} |
740
+ | Department | ${data.department} |
741
+ | Title | ${data.title} |
742
+ | Start Date | ${data.start_date} |
743
+ | Manager | ${data.manager} |
744
+
745
+ ## Time Off
746
+ - **PTO Balance**: ${data.pto_balance} days
747
+ `;
748
+ }
749
+ function generateBenefitDocument(data) {
750
+ return `# Benefit: ${data.name}
751
+
752
+ ## Metadata
753
+ <!-- ema_entity: benefit -->
754
+ <!-- ema_id: ${data.id} -->
755
+ <!-- ema_tags: benefits, hr -->
756
+
757
+ ## Overview
758
+ ${data.description}
759
+
760
+ ## Details
761
+ | Field | Value |
762
+ |-------|-------|
763
+ | Eligibility | ${data.eligibility} |
764
+ ${data.provider ? `| Provider | ${data.provider} |` : ""}
765
+ ${data.employee_cost ? `| Employee Cost | ${data.employee_cost} |` : ""}
766
+ ${data.company_contribution ? `| Company Contribution | ${data.company_contribution} |` : ""}
767
+ ${data.match ? `| Company Match | ${data.match} |` : ""}
768
+ ${data.amount ? `| Amount | ${data.amount} |` : ""}
769
+ `;
770
+ }
771
+ function generateCompanyDocument(data) {
772
+ return `# Company: ${data.name}
773
+
774
+ ## Metadata
775
+ <!-- ema_entity: company -->
776
+ <!-- ema_id: ${data.name} -->
777
+ <!-- ema_tags: ${data.industry || "general"}, prospect -->
778
+
779
+ ## Company Overview
780
+ | Field | Value |
781
+ |-------|-------|
782
+ | Company Name | ${data.name} |
783
+ | Industry | ${data.industry} |
784
+ | Size | ${data.size} |
785
+ | Annual Revenue | ${data.annual_revenue || "N/A"} |
786
+ | Headquarters | ${data.headquarters || "N/A"} |
787
+
788
+ ## Pain Points
789
+ ${(data.pain_points || []).map((p) => `- ${p}`).join("\n") || "- To be discovered"}
790
+
791
+ ## Current Solution
792
+ ${data.current_solution || "Unknown"}
793
+
794
+ ## Notes
795
+ This is a prospective customer in the ${data.industry} industry.
796
+ `;
797
+ }
798
+ function generateGenericDocument(entityType, data) {
799
+ const fields = Object.entries(data)
800
+ .filter(([_, v]) => v !== null && v !== undefined && typeof v !== "object")
801
+ .map(([k, v]) => `| ${k} | ${v} |`)
802
+ .join("\n");
803
+ return `# ${entityType}: ${data.name || data.id || "Unknown"}
804
+
805
+ ## Metadata
806
+ <!-- ema_entity: ${entityType} -->
807
+
808
+ ## Details
809
+ | Field | Value |
810
+ |-------|-------|
811
+ ${fields}
812
+ `;
813
+ }
814
+ /**
815
+ * Generate a complete demo kit for a persona
816
+ */
817
+ export function generateDemoKit(personaId, personaName, workflowDef, scenario, customQA) {
818
+ const analysis = analyzeWorkflowForDemo(workflowDef);
819
+ // Generate KB documents
820
+ const kbDocuments = [];
821
+ const entityTypesNeeded = new Set([
822
+ ...analysis.required_entity_types,
823
+ ...scenario.entities.map((e) => e.type),
824
+ ]);
825
+ for (const entityType of entityTypesNeeded) {
826
+ const samples = SAMPLE_ENTITIES[entityType] || [];
827
+ for (const sample of samples) {
828
+ kbDocuments.push(generateDemoDocument(entityType, sample));
829
+ }
830
+ }
831
+ // Generate demo script from scenario Q&A
832
+ const demoScript = scenario.qa_pairs.map((qa, idx) => ({
833
+ id: `qa-${idx + 1}`,
834
+ question: qa.question,
835
+ expected_answer: qa.answer_template,
836
+ intent: qa.intent,
837
+ required_entities: qa.required_entity_type ? [qa.required_entity_type] : undefined,
838
+ phase: qa.phase,
839
+ presenter_notes: `Triggers ${qa.intent || "general"} intent`,
840
+ }));
841
+ // Add custom Q&A if provided
842
+ if (customQA) {
843
+ for (const [idx, qa] of customQA.entries()) {
844
+ demoScript.push({
845
+ id: `custom-${idx + 1}`,
846
+ question: qa.question,
847
+ expected_answer: qa.answer,
848
+ phase: "main",
849
+ presenter_notes: "Custom Q&A pair",
850
+ });
851
+ }
852
+ }
853
+ // Generate fixed response fallbacks for critical questions
854
+ const fixedResponses = demoScript
855
+ .filter((qa) => qa.phase === "intro" || qa.phase === "closing")
856
+ .map((qa) => ({
857
+ id: `fallback_${qa.id}`,
858
+ displayName: `Demo Fallback: ${qa.id}`,
859
+ template: qa.expected_answer,
860
+ fallback_for: qa.id,
861
+ }));
862
+ // Generate validation queries
863
+ const validationQueries = demoScript.map((qa) => ({
864
+ query: qa.question,
865
+ expect: {
866
+ intent: qa.intent,
867
+ contains: extractKeyPhrases(qa.expected_answer),
868
+ },
869
+ }));
870
+ return {
871
+ persona_id: personaId,
872
+ persona_name: personaName,
873
+ scenario: scenario.id,
874
+ kb_documents: kbDocuments,
875
+ demo_script: demoScript,
876
+ fixed_responses: fixedResponses,
877
+ validation_queries: validationQueries,
878
+ generated_at: new Date().toISOString(),
879
+ version: "1.0.0",
880
+ };
881
+ }
882
+ /**
883
+ * Extract key phrases from an answer for validation
884
+ */
885
+ function extractKeyPhrases(answer) {
886
+ // Extract first 2-3 significant words/phrases
887
+ const words = answer
888
+ .replace(/[^\w\s]/g, "")
889
+ .split(/\s+/)
890
+ .filter((w) => w.length > 4);
891
+ return words.slice(0, 3);
892
+ }
893
+ /**
894
+ * Generate demo script markdown
895
+ */
896
+ export function generateDemoScriptMarkdown(kit) {
897
+ const byPhase = {
898
+ intro: [],
899
+ main: [],
900
+ advanced: [],
901
+ closing: [],
902
+ };
903
+ for (const qa of kit.demo_script) {
904
+ byPhase[qa.phase].push(qa);
905
+ }
906
+ let md = `# Demo Script: ${kit.persona_name}
907
+
908
+ > Generated ${kit.generated_at}
909
+ > Scenario: ${kit.scenario}
910
+
911
+ ## Overview
912
+ - **Total Questions**: ${kit.demo_script.length}
913
+ - **KB Documents**: ${kit.kb_documents.length}
914
+ - **Fallback Responses**: ${kit.fixed_responses.length}
915
+
916
+ ---
917
+
918
+ `;
919
+ for (const [phase, questions] of Object.entries(byPhase)) {
920
+ if (questions.length === 0)
921
+ continue;
922
+ md += `## ${phase.charAt(0).toUpperCase() + phase.slice(1)} Phase\n\n`;
923
+ for (const qa of questions) {
924
+ md += `### Q: "${qa.question}"\n\n`;
925
+ md += `**Expected Answer:**\n${qa.expected_answer}\n\n`;
926
+ if (qa.intent)
927
+ md += `- Intent: \`${qa.intent}\`\n`;
928
+ if (qa.presenter_notes)
929
+ md += `- Notes: ${qa.presenter_notes}\n`;
930
+ md += "\n---\n\n";
931
+ }
932
+ }
933
+ return md;
934
+ }
935
+ /**
936
+ * Validate a demo kit is ready for use
937
+ */
938
+ export function validateDemoKit(kit) {
939
+ const issues = [];
940
+ // Check KB documents
941
+ if (kit.kb_documents.length === 0) {
942
+ issues.push("No KB documents generated - RAG search will return no results");
943
+ }
944
+ // Check demo script
945
+ if (kit.demo_script.length === 0) {
946
+ issues.push("No demo questions defined");
947
+ }
948
+ // Check intro and closing have fallbacks
949
+ const introQuestions = kit.demo_script.filter((q) => q.phase === "intro");
950
+ const introFallbacks = kit.fixed_responses.filter((f) => introQuestions.some((q) => f.fallback_for === q.id));
951
+ if (introQuestions.length > 0 && introFallbacks.length === 0) {
952
+ issues.push("No fallback responses for intro questions - high risk");
953
+ }
954
+ // Check entity coverage
955
+ const neededEntities = new Set();
956
+ for (const qa of kit.demo_script) {
957
+ if (qa.required_entities) {
958
+ for (const e of qa.required_entities) {
959
+ neededEntities.add(e);
960
+ }
961
+ }
962
+ }
963
+ const coveredEntities = new Set(kit.kb_documents.map((d) => d.entity_type));
964
+ for (const needed of neededEntities) {
965
+ if (!coveredEntities.has(needed)) {
966
+ issues.push(`Missing KB documents for entity type: ${needed}`);
967
+ }
968
+ }
969
+ return {
970
+ ready: issues.length === 0,
971
+ issues,
972
+ coverage: {
973
+ total_questions: kit.demo_script.length,
974
+ questions_with_fallback: kit.fixed_responses.length,
975
+ entity_types_covered: coveredEntities.size,
976
+ },
977
+ };
978
+ }