catalist-support-agent 1.0.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 (140) hide show
  1. package/dist/admin-portal.d.ts +43 -0
  2. package/dist/admin-portal.d.ts.map +1 -0
  3. package/dist/admin-portal.js +166 -0
  4. package/dist/admin-portal.js.map +1 -0
  5. package/dist/analysis/entities.d.ts +73 -0
  6. package/dist/analysis/entities.d.ts.map +1 -0
  7. package/dist/analysis/entities.js +378 -0
  8. package/dist/analysis/entities.js.map +1 -0
  9. package/dist/analysis/index.d.ts +44 -0
  10. package/dist/analysis/index.d.ts.map +1 -0
  11. package/dist/analysis/index.js +243 -0
  12. package/dist/analysis/index.js.map +1 -0
  13. package/dist/analysis/intent.d.ts +49 -0
  14. package/dist/analysis/intent.d.ts.map +1 -0
  15. package/dist/analysis/intent.js +320 -0
  16. package/dist/analysis/intent.js.map +1 -0
  17. package/dist/analysis/sentiment.d.ts +57 -0
  18. package/dist/analysis/sentiment.d.ts.map +1 -0
  19. package/dist/analysis/sentiment.js +351 -0
  20. package/dist/analysis/sentiment.js.map +1 -0
  21. package/dist/brand/compliance.d.ts +122 -0
  22. package/dist/brand/compliance.d.ts.map +1 -0
  23. package/dist/brand/compliance.js +378 -0
  24. package/dist/brand/compliance.js.map +1 -0
  25. package/dist/brand/forbidden-terms.d.ts +99 -0
  26. package/dist/brand/forbidden-terms.d.ts.map +1 -0
  27. package/dist/brand/forbidden-terms.js +265 -0
  28. package/dist/brand/forbidden-terms.js.map +1 -0
  29. package/dist/brand/index.d.ts +10 -0
  30. package/dist/brand/index.d.ts.map +1 -0
  31. package/dist/brand/index.js +12 -0
  32. package/dist/brand/index.js.map +1 -0
  33. package/dist/config.d.ts +325 -0
  34. package/dist/config.d.ts.map +1 -0
  35. package/dist/config.js +492 -0
  36. package/dist/config.js.map +1 -0
  37. package/dist/delivery/index.d.ts +84 -0
  38. package/dist/delivery/index.d.ts.map +1 -0
  39. package/dist/delivery/index.js +435 -0
  40. package/dist/delivery/index.js.map +1 -0
  41. package/dist/embeddings/cache.d.ts +96 -0
  42. package/dist/embeddings/cache.d.ts.map +1 -0
  43. package/dist/embeddings/cache.js +193 -0
  44. package/dist/embeddings/cache.js.map +1 -0
  45. package/dist/embeddings/index.d.ts +152 -0
  46. package/dist/embeddings/index.d.ts.map +1 -0
  47. package/dist/embeddings/index.js +337 -0
  48. package/dist/embeddings/index.js.map +1 -0
  49. package/dist/embeddings/openai-client.d.ts +67 -0
  50. package/dist/embeddings/openai-client.d.ts.map +1 -0
  51. package/dist/embeddings/openai-client.js +190 -0
  52. package/dist/embeddings/openai-client.js.map +1 -0
  53. package/dist/errors.d.ts +302 -0
  54. package/dist/errors.d.ts.map +1 -0
  55. package/dist/errors.js +508 -0
  56. package/dist/errors.js.map +1 -0
  57. package/dist/escalation/index.d.ts +93 -0
  58. package/dist/escalation/index.d.ts.map +1 -0
  59. package/dist/escalation/index.js +436 -0
  60. package/dist/escalation/index.js.map +1 -0
  61. package/dist/extraction/deduplication.d.ts +97 -0
  62. package/dist/extraction/deduplication.d.ts.map +1 -0
  63. package/dist/extraction/deduplication.js +271 -0
  64. package/dist/extraction/deduplication.js.map +1 -0
  65. package/dist/extraction/gmail-extractor.d.ts +160 -0
  66. package/dist/extraction/gmail-extractor.d.ts.map +1 -0
  67. package/dist/extraction/gmail-extractor.js +396 -0
  68. package/dist/extraction/gmail-extractor.js.map +1 -0
  69. package/dist/extraction/gmail-token-manager.d.ts +36 -0
  70. package/dist/extraction/gmail-token-manager.d.ts.map +1 -0
  71. package/dist/extraction/gmail-token-manager.js +146 -0
  72. package/dist/extraction/gmail-token-manager.js.map +1 -0
  73. package/dist/extraction/index.d.ts +13 -0
  74. package/dist/extraction/index.d.ts.map +1 -0
  75. package/dist/extraction/index.js +20 -0
  76. package/dist/extraction/index.js.map +1 -0
  77. package/dist/extraction/pii-handler.d.ts +100 -0
  78. package/dist/extraction/pii-handler.d.ts.map +1 -0
  79. package/dist/extraction/pii-handler.js +295 -0
  80. package/dist/extraction/pii-handler.js.map +1 -0
  81. package/dist/extraction/pipeline.d.ts +94 -0
  82. package/dist/extraction/pipeline.d.ts.map +1 -0
  83. package/dist/extraction/pipeline.js +380 -0
  84. package/dist/extraction/pipeline.js.map +1 -0
  85. package/dist/extraction/quality-filter.d.ts +99 -0
  86. package/dist/extraction/quality-filter.d.ts.map +1 -0
  87. package/dist/extraction/quality-filter.js +370 -0
  88. package/dist/extraction/quality-filter.js.map +1 -0
  89. package/dist/extraction/rate-limiter.d.ts +90 -0
  90. package/dist/extraction/rate-limiter.d.ts.map +1 -0
  91. package/dist/extraction/rate-limiter.js +242 -0
  92. package/dist/extraction/rate-limiter.js.map +1 -0
  93. package/dist/extraction/state-manager.d.ts +126 -0
  94. package/dist/extraction/state-manager.d.ts.map +1 -0
  95. package/dist/extraction/state-manager.js +344 -0
  96. package/dist/extraction/state-manager.js.map +1 -0
  97. package/dist/generation/index.d.ts +75 -0
  98. package/dist/generation/index.d.ts.map +1 -0
  99. package/dist/generation/index.js +641 -0
  100. package/dist/generation/index.js.map +1 -0
  101. package/dist/index.d.ts +96 -0
  102. package/dist/index.d.ts.map +1 -0
  103. package/dist/index.js +233 -0
  104. package/dist/index.js.map +1 -0
  105. package/dist/intake/index.d.ts +15 -0
  106. package/dist/intake/index.d.ts.map +1 -0
  107. package/dist/intake/index.js +19 -0
  108. package/dist/intake/index.js.map +1 -0
  109. package/dist/intake/normalizer.d.ts +163 -0
  110. package/dist/intake/normalizer.d.ts.map +1 -0
  111. package/dist/intake/normalizer.js +309 -0
  112. package/dist/intake/normalizer.js.map +1 -0
  113. package/dist/intake/postmark.d.ts +72 -0
  114. package/dist/intake/postmark.d.ts.map +1 -0
  115. package/dist/intake/postmark.js +276 -0
  116. package/dist/intake/postmark.js.map +1 -0
  117. package/dist/intake/slack.d.ts +106 -0
  118. package/dist/intake/slack.d.ts.map +1 -0
  119. package/dist/intake/slack.js +378 -0
  120. package/dist/intake/slack.js.map +1 -0
  121. package/dist/intake/twilio.d.ts +86 -0
  122. package/dist/intake/twilio.d.ts.map +1 -0
  123. package/dist/intake/twilio.js +283 -0
  124. package/dist/intake/twilio.js.map +1 -0
  125. package/dist/knowledge/index.d.ts +100 -0
  126. package/dist/knowledge/index.d.ts.map +1 -0
  127. package/dist/knowledge/index.js +516 -0
  128. package/dist/knowledge/index.js.map +1 -0
  129. package/dist/knowledge/invoice-resolver.d.ts +62 -0
  130. package/dist/knowledge/invoice-resolver.d.ts.map +1 -0
  131. package/dist/knowledge/invoice-resolver.js +267 -0
  132. package/dist/knowledge/invoice-resolver.js.map +1 -0
  133. package/dist/types.d.ts +535 -0
  134. package/dist/types.d.ts.map +1 -0
  135. package/dist/types.js +48 -0
  136. package/dist/types.js.map +1 -0
  137. package/ga-service-account.json +13 -0
  138. package/gmail-knowledge-migration.sql +149 -0
  139. package/nul +1 -0
  140. package/package.json +55 -0
@@ -0,0 +1,641 @@
1
+ /**
2
+ * Response Generation Module
3
+ *
4
+ * Generates brand-compliant responses using Claude:
5
+ * - Assembles context from analysis and knowledge
6
+ * - Applies brand voice guidelines
7
+ * - Enforces forbidden terms rules
8
+ * - Formats for target channel
9
+ * - Validates before sending
10
+ */
11
+ import Anthropic from '@anthropic-ai/sdk';
12
+ import { config } from '../config.js';
13
+ import { GenerationError, ResponseQualityError, ForbiddenTermsDetectedError } from '../errors.js';
14
+ import { validateResponseForBrand, applyBrandTerminologyCorrections, getBrandVoiceGuidelines, } from '../brand/index.js';
15
+ import { createResponseId } from '../types.js';
16
+ // =============================================================================
17
+ // System Prompt
18
+ // =============================================================================
19
+ const SYSTEM_PROMPT = `You are a customer support agent for Catalist, an AI-native B2B marketplace platform.
20
+
21
+ ## Your Identity
22
+ - You represent Catalist, a modern B2B marketplace (NOT a wholesale distributor)
23
+ - You are professional, direct, and helpful
24
+ - Keep responses concise - say what needs to be said, nothing more
25
+
26
+ ## CRITICAL: Use Provided Customer Context
27
+
28
+ When customer information is provided in the context (from sender email lookup):
29
+ - DO NOT ask for account details, company name, or email - we already have it
30
+ - Address them by name if available
31
+ - Use this information to personalize your response
32
+
33
+ Only ask for account details if NO customer information appears in the context.
34
+
35
+ ## CRITICAL: Pricing Policy - NO DISCOUNTS
36
+
37
+ Catalist does NOT offer discounts, volume pricing, or special pricing arrangements.
38
+ - Prices are set by our brand partners and are non-negotiable
39
+ - The listed price reflects our best available rate for all quantities
40
+ - Do NOT mention "working on pricing" or imply flexibility
41
+
42
+ Example response to discount requests:
43
+ "Our marketplace prices are set by our brand partners and are non-negotiable. The listed price on our portal reflects our best available rate for all quantities."
44
+
45
+ ## Self-Service: Marketplace Ungating Tool
46
+
47
+ For Amazon/Walmart ungating questions, direct customers to: https://b2b.catalistgroup.co/ungating
48
+
49
+ The workflow is: get approved for the brand through the ungating tool first, then place your order through our portal at https://b2b.catalistgroup.co
50
+
51
+ The tool provides everything you need:
52
+ - Professional invoices from Catalist formatted for Amazon requirements
53
+ - AI guidance with success probability estimates for the specific brand
54
+ - Pre-written case templates to copy into Seller Central
55
+ - Step-by-step submission instructions
56
+ - Resubmission strategies for handling denials
57
+
58
+ Quick note on denials: They're normal (40-60% success on first try, but 85-95% success by the third attempt). You'll submit the documentation yourself through Seller Central - the tool just provides what you need.
59
+
60
+ ## CRITICAL: Brand Terminology Rules
61
+
62
+ NEVER facilitate these requests (escalate to human):
63
+ - Invoice manipulation (editing, modifying, or falsifying invoices)
64
+ - Competitor price matching requests
65
+
66
+ IMPORTANT: Our clients ARE Amazon FBA sellers. The following terms are ALLOWED:
67
+ - Amazon, FBA, FBM, Seller Central, ASIN, Buy Box
68
+ - Walmart, Walmart Marketplace, WFS
69
+ - eBay, or any other marketplace platforms
70
+ - Ungating, brand approval, category approval
71
+ - Reseller, reselling, arbitrage
72
+
73
+ Use correct terminology:
74
+ - "Catalist" (NEVER "Catalist Group" in body text)
75
+ - "B2B marketplace" (not "wholesale distributor")
76
+ - "Brand partners" (not "vendors")
77
+
78
+ ## Brand/Product Sourcing & Catalog Requests
79
+
80
+ When customers ask for brand suggestions, help finding products, or catalog access:
81
+ - Direct them to LOG IN to our marketplace at https://b2b.catalistgroup.co
82
+ - NEVER say "create an account" - assume they already have one (they're emailing us!)
83
+ - Mention they can filter by category, brand, or search for specific products
84
+ - We carry 1200+ brands across categories like home & kitchen, sports and outdoors, hardware, etc.
85
+
86
+ Example response:
87
+ "You can browse our full catalog by logging into the portal at https://b2b.catalistgroup.co where you can filter by category or search for specific products. We carry 1200+ brands across categories like home & kitchen, sports and outdoors, hardware, and more."
88
+
89
+ ## CSV Catalog Downloads - YES WE OFFER THIS
90
+
91
+ IMPORTANT: We DO provide CSV catalog downloads. Customers can:
92
+ 1. Log in to the portal at https://b2b.catalistgroup.co
93
+ 2. Click the "Download CSV" button on the Products page (next to the search bar)
94
+ 3. Export the current filtered product list as a CSV file
95
+
96
+ When customers ask about CSV downloads, catalog exports, spreadsheets, or product data files:
97
+ - Confirm YES, we offer CSV downloads
98
+ - Direct them to log in and use the "Download CSV" button
99
+ - Mention they can apply filters first to export a specific subset of products
100
+
101
+ Example response for CSV/catalog download requests:
102
+ "Yes, you can download our product catalog as a CSV file. Just log in to the portal at https://b2b.catalistgroup.co, apply any filters you want (by brand, category, etc.), and click the 'Download CSV' button next to the search bar. The export will include all products matching your current filters."
103
+
104
+ ## Portal URL
105
+
106
+ Always use: https://b2b.catalistgroup.co
107
+ Never use "portal.catalistgroup.co" - this URL does not exist.
108
+
109
+ ## Email Structure
110
+
111
+ Follow this structure for responses:
112
+
113
+ 1. Brief greeting with customer name
114
+ 2. Direct answer to their question (no preamble)
115
+ 3. If ungating: explain the tool with bullet list, then workflow
116
+ 4. Quick note for secondary info (denial rates, etc.)
117
+ 5. Offer to help with next steps
118
+ 6. Sign off with "Best," and your name
119
+
120
+ Example closing:
121
+ "Let me know if you have any questions about getting started with either the ungating process or placing your order.
122
+
123
+ Best,
124
+ [Name]"
125
+
126
+ ## Email Formatting (IMPORTANT)
127
+
128
+ - Use PLAIN TEXT only - no Markdown formatting
129
+ - Do NOT use asterisks for bold (**text**) or italics (*text*)
130
+ - Do NOT use hashtags for headers (## Header)
131
+ - Use dashes (- item) for bullet lists
132
+ - Indent bullet lists with two spaces for visual clarity
133
+ - Keep URLs on their own line when possible
134
+ - Do NOT include signature block - it's added automatically
135
+
136
+ ## CRITICAL: Write Like a Human, Not an AI
137
+
138
+ Words and phrases to NEVER use:
139
+ - "I hope this helps" / "Let me know if you need anything else" (generic)
140
+ - "Additionally" / "Moreover" / "Furthermore"
141
+ - "Delve" / "Navigate" / "Landscape"
142
+ - "Crucial" / "Pivotal" / "Key" (as adjectives)
143
+ - "Seamless" / "Robust"
144
+ - "Testament to" / "Serves as"
145
+ - "I understand your concern" (just address it)
146
+ - "Great question!" / "Absolutely!" / "Certainly!"
147
+ - "reaching out" (just say "your interest" or "your email")
148
+
149
+ Patterns to avoid:
150
+ - Em dashes for dramatic effect—like this—everywhere
151
+ - Rule of three lists (fast, efficient, and reliable)
152
+ - "It's not just X, it's Y" constructions
153
+ - Starting with "I" repeatedly
154
+ - Excessive hedging ("might potentially be able to")
155
+ - Long explanatory intros before the actual answer
156
+
157
+ Instead:
158
+ - Be direct: answer first, explain second
159
+ - Use simple words: "is" instead of "serves as"
160
+ - Use contractions (we're, you'll, that's)
161
+ - Use "Quick note:" for secondary information
162
+ - Keep sentences short and scannable
163
+ `;
164
+ // =============================================================================
165
+ // Response Generation Service
166
+ // =============================================================================
167
+ export class ResponseGenerationService {
168
+ client = null;
169
+ effectiveConfig;
170
+ constructor(configOverride) {
171
+ this.effectiveConfig = configOverride ?? config;
172
+ }
173
+ getClient() {
174
+ if (!this.client) {
175
+ if (this.effectiveConfig.claude.apiKey) {
176
+ this.client = new Anthropic({
177
+ apiKey: this.effectiveConfig.claude.apiKey,
178
+ });
179
+ }
180
+ else {
181
+ throw new GenerationError('Claude API key not configured', 'llm_call', {
182
+ context: { reason: 'Missing ANTHROPIC_API_KEY' },
183
+ });
184
+ }
185
+ }
186
+ return this.client;
187
+ }
188
+ /**
189
+ * Generate a response for a message
190
+ */
191
+ async generateResponse(message, analysis, knowledge, options = {}) {
192
+ const startTime = Date.now();
193
+ const targetChannel = options.targetChannel ?? message.channel;
194
+ const maxAttempts = options.maxAttempts ?? 3;
195
+ let lastError;
196
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
197
+ try {
198
+ // 1. Build the context prompt
199
+ const contextPrompt = this.buildContextPrompt(message, analysis, knowledge);
200
+ // 2. Generate response with Claude
201
+ const rawResponse = await this.callClaude(contextPrompt, analysis.sentiment.category);
202
+ // 3. Apply terminology corrections
203
+ let processedResponse = applyBrandTerminologyCorrections(rawResponse);
204
+ // 3.5. Humanize response - remove AI writing patterns
205
+ processedResponse = humanizeResponse(processedResponse);
206
+ // 4. Validate brand compliance
207
+ const validationResult = validateResponseForBrand(processedResponse, analysis.sentiment.category);
208
+ if (!validationResult.canBeSent) {
209
+ if (validationResult.complianceCheck.forbiddenTermsResult.hasForbiddenTerms) {
210
+ // This shouldn't happen with proper system prompt, but handle it
211
+ throw new ForbiddenTermsDetectedError(validationResult.complianceCheck.forbiddenTermsResult.detectedTerms, 'generated_response', { messageId: message.id, conversationId: message.conversationId });
212
+ }
213
+ // Try to fix non-critical issues
214
+ if (attempt < maxAttempts) {
215
+ continue;
216
+ }
217
+ throw new ResponseQualityError(validationResult.complianceCheck.score, validationResult.errors, { messageId: message.id, conversationId: message.conversationId });
218
+ }
219
+ // 5. Format for target channel
220
+ const formatting = this.formatForChannel(processedResponse, targetChannel, message.content.subject);
221
+ // 6. Extract citations
222
+ const citations = this.extractCitations(processedResponse, knowledge);
223
+ // 7. Calculate quality score
224
+ const qualityScore = this.calculateQualityScore(processedResponse, validationResult.complianceCheck.score, knowledge);
225
+ const latencyMs = Date.now() - startTime;
226
+ return {
227
+ id: createResponseId(`resp-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`),
228
+ conversationId: analysis.conversationId,
229
+ messageId: message.id,
230
+ content: {
231
+ text: processedResponse,
232
+ html: formatting.email?.htmlBody,
233
+ subject: formatting.email?.subject,
234
+ },
235
+ formatting,
236
+ citations,
237
+ brandCompliance: validationResult.complianceCheck.overallStatus,
238
+ qualityScore,
239
+ generatedAt: new Date().toISOString(),
240
+ metadata: {
241
+ templateUsed: undefined,
242
+ modelUsed: this.effectiveConfig.claude.model,
243
+ tokensUsed: 0, // Would need to track from Claude response
244
+ latencyMs,
245
+ },
246
+ };
247
+ }
248
+ catch (error) {
249
+ lastError = error instanceof Error ? error : new Error(String(error));
250
+ if (error instanceof ForbiddenTermsDetectedError) {
251
+ // Don't retry forbidden terms - this is a critical failure
252
+ throw error;
253
+ }
254
+ // Continue to next attempt
255
+ continue;
256
+ }
257
+ }
258
+ throw new GenerationError(`Response generation failed after ${maxAttempts} attempts: ${lastError?.message}`, 'llm_call', {
259
+ cause: lastError,
260
+ messageId: message.id,
261
+ conversationId: message.conversationId,
262
+ });
263
+ }
264
+ /**
265
+ * Build context prompt for Claude
266
+ */
267
+ buildContextPrompt(message, analysis, knowledge) {
268
+ const sections = [];
269
+ // Customer context
270
+ if (knowledge.customer) {
271
+ sections.push(`## Customer Information
272
+ - Company: ${knowledge.customer.companyName}
273
+ - Contact: ${knowledge.customer.contactName || 'N/A'}
274
+ - Status: ${knowledge.customer.accountStatus}
275
+ ${knowledge.customer.tier ? `- Tier: ${knowledge.customer.tier}` : ''}`);
276
+ }
277
+ // Analysis context
278
+ sections.push(`## Message Analysis
279
+ - Intent: ${analysis.intent.primary}${analysis.intent.secondary ? ` (secondary: ${analysis.intent.secondary})` : ''}
280
+ - Sentiment: ${analysis.sentiment.category} (score: ${analysis.sentiment.score.toFixed(2)})
281
+ - Urgency: ${analysis.sentiment.urgency}`);
282
+ // Order context
283
+ if (knowledge.orders && knowledge.orders.length > 0) {
284
+ const orderList = knowledge.orders
285
+ .slice(0, 3)
286
+ .map((o) => `- Order ${o.orderNumber}: ${o.status} (${o.totalAmount ? `$${o.totalAmount}` : 'N/A'})`)
287
+ .join('\n');
288
+ sections.push(`## Recent Orders\n${orderList}`);
289
+ }
290
+ // Resolved invoice context - prominently displayed so Claude knows not to ask for it
291
+ if (knowledge.resolvedInvoice) {
292
+ const inv = knowledge.resolvedInvoice.invoice;
293
+ const confidence = knowledge.resolvedInvoice.confidence;
294
+ const source = knowledge.resolvedInvoice.source;
295
+ let sourceExplanation = '';
296
+ if (source === 'extracted_number') {
297
+ sourceExplanation = 'Invoice number found in their message.';
298
+ }
299
+ else if (source === 'single_unpaid') {
300
+ sourceExplanation = 'This is their only unpaid invoice.';
301
+ }
302
+ else if (source === 'most_recent') {
303
+ sourceExplanation = 'This is their most recent invoice (no unpaid invoices).';
304
+ }
305
+ const statusDisplay = inv.status === 'issued' ? 'Unpaid' : inv.status === 'paid' ? 'Paid' : inv.status;
306
+ const issuedDate = inv.issuedAt ? new Date(inv.issuedAt).toLocaleDateString() : 'N/A';
307
+ const dueDate = inv.dueAt ? new Date(inv.dueAt).toLocaleDateString() : 'N/A';
308
+ const paidDate = inv.paidAt ? new Date(inv.paidAt).toLocaleDateString() : null;
309
+ sections.push(`## Identified Invoice
310
+ The customer is asking about this invoice (${confidence} confidence - ${sourceExplanation}):
311
+ - Invoice #: ${inv.invoiceNumber || inv.invoiceId}
312
+ - Amount: $${inv.total.toFixed(2)}
313
+ - Status: ${statusDisplay}
314
+ - Issued: ${issuedDate}
315
+ - Due: ${dueDate}${paidDate ? `\n- Paid: ${paidDate}` : ''}
316
+
317
+ IMPORTANT: Do NOT ask the customer for their invoice number - we have already identified it. Include the invoice number and key details in your response so they can confirm we're looking at the right one.`);
318
+ }
319
+ // Product context
320
+ if (knowledge.products && knowledge.products.length > 0) {
321
+ const productList = knowledge.products
322
+ .slice(0, 3)
323
+ .map((p) => `- ${p.name} (${p.sku}): ${p.availability}${p.price ? ` - $${p.price}` : ''}`)
324
+ .join('\n');
325
+ sections.push(`## Relevant Products\n${productList}`);
326
+ }
327
+ // Similar past conversations (few-shot examples)
328
+ if (knowledge.similarConversations && knowledge.similarConversations.length > 0) {
329
+ const examples = knowledge.similarConversations
330
+ .slice(0, 3) // Top 3 most similar
331
+ .map((conv, index) => {
332
+ const exampleParts = [
333
+ `### Example ${index + 1} (similarity: ${(conv.similarity * 100).toFixed(0)}%)`,
334
+ `**Customer Question:** ${conv.summary}`,
335
+ ];
336
+ if (conv.successfulResponse) {
337
+ // Truncate long responses for context window efficiency
338
+ const responsePreview = conv.successfulResponse.length > 300
339
+ ? conv.successfulResponse.substring(0, 300) + '...'
340
+ : conv.successfulResponse;
341
+ exampleParts.push(`**Successful Response:** ${responsePreview}`);
342
+ }
343
+ exampleParts.push(`**Outcome:** ${conv.resolution.replace(/_/g, ' ')}`);
344
+ return exampleParts.join('\n');
345
+ })
346
+ .join('\n\n');
347
+ sections.push(`## Similar Past Conversations (for reference)
348
+ The following are examples of similar questions we've successfully handled. Use these as reference for tone, structure, and approach:
349
+
350
+ ${examples}
351
+
352
+ Note: Adapt these examples to the specific customer's situation rather than copying directly.`);
353
+ }
354
+ // Template suggestions (after similar conversations as they're more specific)
355
+ if (knowledge.templates && knowledge.templates.length > 0) {
356
+ const template = knowledge.templates[0];
357
+ if (template) {
358
+ sections.push(`## Suggested Template
359
+ Consider using elements from this approved template:
360
+ "${template.content.substring(0, 200)}..."`);
361
+ }
362
+ }
363
+ // Original message (always last for clear reference)
364
+ sections.push(`## Customer Message
365
+ ${message.content.subject ? `Subject: ${message.content.subject}\n` : ''}${message.content.text}`);
366
+ return sections.join('\n\n');
367
+ }
368
+ /**
369
+ * Call Claude to generate response
370
+ */
371
+ async callClaude(contextPrompt, sentiment) {
372
+ const client = this.getClient();
373
+ // Add tone guidance based on sentiment
374
+ const voiceGuidelines = getBrandVoiceGuidelines(sentiment);
375
+ const toneInstruction = `\n\nTone for this response: ${voiceGuidelines.tone}`;
376
+ const response = await client.messages.create({
377
+ model: this.effectiveConfig.claude.model,
378
+ max_tokens: this.effectiveConfig.claude.maxTokens,
379
+ system: SYSTEM_PROMPT + toneInstruction,
380
+ messages: [
381
+ {
382
+ role: 'user',
383
+ content: `Based on the following context, write a helpful support response:\n\n${contextPrompt}`,
384
+ },
385
+ ],
386
+ });
387
+ const textContent = response.content.find((c) => c.type === 'text');
388
+ if (!textContent || textContent.type !== 'text') {
389
+ throw new GenerationError('No text response from Claude', 'llm_call');
390
+ }
391
+ return textContent.text;
392
+ }
393
+ /**
394
+ * Format response for target channel
395
+ */
396
+ formatForChannel(text, channel, originalSubject) {
397
+ const formatting = {};
398
+ switch (channel) {
399
+ case 'email':
400
+ formatting.email = {
401
+ subject: originalSubject ? `Re: ${originalSubject}` : 'Catalist Support',
402
+ htmlBody: this.formatAsHtml(text),
403
+ textBody: text,
404
+ };
405
+ break;
406
+ case 'sms':
407
+ // Truncate for SMS, keeping under 160 chars if possible
408
+ const smsText = this.formatForSms(text);
409
+ formatting.sms = {
410
+ body: smsText,
411
+ segments: Math.ceil(smsText.length / 160),
412
+ };
413
+ break;
414
+ case 'slack':
415
+ formatting.slack = {
416
+ blocks: this.formatAsSlackBlocks(text),
417
+ text: text,
418
+ };
419
+ break;
420
+ }
421
+ return formatting;
422
+ }
423
+ /**
424
+ * Format text as HTML for email
425
+ */
426
+ formatAsHtml(text) {
427
+ // Convert markdown-ish formatting to HTML
428
+ let html = text
429
+ .replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>')
430
+ .replace(/\*([^*]+)\*/g, '<em>$1</em>')
431
+ .replace(/^- (.+)$/gm, '<li>$1</li>')
432
+ .replace(/\n\n/g, '</p><p>')
433
+ .replace(/\n/g, '<br>');
434
+ // Wrap in paragraph tags
435
+ html = `<p>${html}</p>`;
436
+ // Wrap list items
437
+ html = html.replace(/(<li>.*<\/li>)+/g, '<ul>$&</ul>');
438
+ return html;
439
+ }
440
+ /**
441
+ * Format text for SMS (truncate and simplify)
442
+ */
443
+ formatForSms(text) {
444
+ // Remove formatting
445
+ let sms = text.replace(/\*\*?/g, '').replace(/^- /gm, '• ');
446
+ // Truncate if too long
447
+ if (sms.length > 320) {
448
+ // 2 SMS segments
449
+ sms = sms.substring(0, 317) + '...';
450
+ }
451
+ return sms;
452
+ }
453
+ /**
454
+ * Format text as Slack blocks
455
+ */
456
+ formatAsSlackBlocks(text) {
457
+ // Convert to Slack mrkdwn format
458
+ const mrkdwn = text.replace(/\*\*([^*]+)\*\*/g, '*$1*');
459
+ return [
460
+ {
461
+ type: 'section',
462
+ text: {
463
+ type: 'mrkdwn',
464
+ text: mrkdwn,
465
+ },
466
+ },
467
+ ];
468
+ }
469
+ /**
470
+ * Extract citations from response
471
+ */
472
+ extractCitations(text, knowledge) {
473
+ const citations = [];
474
+ // Extract order references
475
+ if (knowledge.orders) {
476
+ for (const order of knowledge.orders) {
477
+ if (text.includes(order.orderNumber)) {
478
+ citations.push({
479
+ type: 'order',
480
+ reference: order.orderNumber,
481
+ });
482
+ }
483
+ }
484
+ }
485
+ // Extract product references
486
+ if (knowledge.products) {
487
+ for (const product of knowledge.products) {
488
+ if (text.includes(product.sku) || text.toLowerCase().includes(product.name.toLowerCase())) {
489
+ citations.push({
490
+ type: 'product',
491
+ reference: product.sku,
492
+ context: product.name,
493
+ });
494
+ }
495
+ }
496
+ }
497
+ return citations;
498
+ }
499
+ /**
500
+ * Calculate quality score for response
501
+ */
502
+ calculateQualityScore(text, complianceScore, knowledge) {
503
+ let score = complianceScore / 100; // Start with compliance score
504
+ // Bonus for using available context
505
+ if (knowledge.customer && text.includes(knowledge.customer.companyName)) {
506
+ score += 0.05;
507
+ }
508
+ // Bonus for appropriate length (not too short, not too long)
509
+ const wordCount = text.split(/\s+/).length;
510
+ if (wordCount >= 30 && wordCount <= 200) {
511
+ score += 0.05;
512
+ }
513
+ // Cap at 1.0
514
+ return Math.min(1.0, Math.round(score * 100) / 100);
515
+ }
516
+ }
517
+ // =============================================================================
518
+ // Humanization - Remove AI Writing Patterns
519
+ // =============================================================================
520
+ /**
521
+ * Remove common AI writing patterns to make responses sound more natural
522
+ * Based on Wikipedia's "Signs of AI writing" guide
523
+ */
524
+ export function humanizeResponse(text) {
525
+ let result = text;
526
+ // Remove sycophantic/servile phrases
527
+ const sycophancyPatterns = [
528
+ /^(Great question!|Absolutely!|Certainly!|Of course!)\s*/gi,
529
+ /I hope this helps[.!]?\s*/gi,
530
+ /Let me know if you need anything else[.!]?\s*/gi,
531
+ /Please don't hesitate to reach out[.!]?\s*/gi,
532
+ /I'm happy to help[.!]?\s*/gi,
533
+ /I understand your concern[.!]?\s*/gi,
534
+ /Thank you for your patience[.!]?\s*/gi,
535
+ ];
536
+ for (const pattern of sycophancyPatterns) {
537
+ result = result.replace(pattern, '');
538
+ }
539
+ // Brand name correction
540
+ result = result.replace(/Catalist/g, 'Catalist');
541
+ // Replace AI vocabulary words with simpler alternatives
542
+ const vocabularyReplacements = [
543
+ [/\bAdditionally\b/g, 'Also'],
544
+ [/\bMoreover\b/g, 'Also'],
545
+ [/\bFurthermore\b/g, 'Also'],
546
+ [/\bserves as\b/gi, 'is'],
547
+ [/\bstands as\b/gi, 'is'],
548
+ [/\brepresents a\b/gi, 'is a'],
549
+ [/\bdelve into\b/gi, 'look at'],
550
+ [/\bdelve\b/gi, 'explore'],
551
+ [/\bnavigate\b/gi, 'use'],
552
+ [/\bleverage\b/gi, 'use'],
553
+ [/\butilize\b/gi, 'use'],
554
+ [/\bseamless\b/gi, 'smooth'],
555
+ [/\brobust\b/gi, 'strong'],
556
+ [/\bpivotal\b/gi, 'important'],
557
+ [/\bcrucial\b/gi, 'important'],
558
+ [/\ba testament to\b/gi, 'shows'],
559
+ [/\bunderscore\b/gi, 'show'],
560
+ [/\bhighlight\b/gi, 'show'],
561
+ [/\bensuring\b/gi, 'so'],
562
+ [/\bfostering\b/gi, 'building'],
563
+ [/\benhancing\b/gi, 'improving'],
564
+ ];
565
+ for (const [pattern, replacement] of vocabularyReplacements) {
566
+ result = result.replace(pattern, replacement);
567
+ }
568
+ // Remove filler phrases
569
+ const fillerPatterns = [
570
+ [/In order to\b/gi, 'To'],
571
+ [/Due to the fact that\b/gi, 'Because'],
572
+ [/At this point in time\b/gi, 'Now'],
573
+ [/In the event that\b/gi, 'If'],
574
+ [/It is important to note that\b/gi, ''],
575
+ [/It should be noted that\b/gi, ''],
576
+ [/As you may know,?\s*/gi, ''],
577
+ [/As mentioned earlier,?\s*/gi, ''],
578
+ ];
579
+ for (const [pattern, replacement] of fillerPatterns) {
580
+ result = result.replace(pattern, replacement);
581
+ }
582
+ // Remove excessive em dashes (replace with commas or periods)
583
+ // Keep at most one em dash per paragraph
584
+ const paragraphs = result.split('\n\n');
585
+ result = paragraphs.map(para => {
586
+ const emDashCount = (para.match(/—/g) || []).length;
587
+ if (emDashCount > 1) {
588
+ // Replace all but the first em dash with commas
589
+ let count = 0;
590
+ return para.replace(/—/g, () => {
591
+ count++;
592
+ return count === 1 ? '—' : ',';
593
+ });
594
+ }
595
+ return para;
596
+ }).join('\n\n');
597
+ // Strip Markdown formatting (for plain text emails)
598
+ // Remove bold: **text** or __text__
599
+ result = result.replace(/\*\*([^*]+)\*\*/g, '$1');
600
+ result = result.replace(/__([^_]+)__/g, '$1');
601
+ // Remove italics: *text* or _text_ (but not bullet points)
602
+ result = result.replace(/(?<!\n)\*([^*\n]+)\*(?!\*)/g, '$1');
603
+ // Remove headers: ## Header or ### Header
604
+ result = result.replace(/^#{1,6}\s+/gm, '');
605
+ // Fix double spaces that may result from removals
606
+ result = result.replace(/ +/g, ' ');
607
+ // Fix sentence starts after removals (capitalize)
608
+ result = result.replace(/\.\s+([a-z])/g, (_, letter) => `. ${letter.toUpperCase()}`);
609
+ // Trim whitespace
610
+ result = result.trim();
611
+ return result;
612
+ }
613
+ // =============================================================================
614
+ // Singleton and Utility Functions
615
+ // =============================================================================
616
+ let generationService = null;
617
+ export function getResponseGenerationService(configOverride) {
618
+ // If configOverride is provided, always create a new instance with that config
619
+ if (configOverride) {
620
+ return new ResponseGenerationService(configOverride);
621
+ }
622
+ // Otherwise, use the singleton pattern with global config
623
+ if (!generationService) {
624
+ generationService = new ResponseGenerationService();
625
+ }
626
+ return generationService;
627
+ }
628
+ /**
629
+ * Generate a response for a message
630
+ */
631
+ export async function generateResponse(message, analysis, knowledge, options) {
632
+ return getResponseGenerationService().generateResponse(message, analysis, knowledge, options);
633
+ }
634
+ /**
635
+ * Check if response is ready to send
636
+ */
637
+ export function isResponseReadyToSend(response) {
638
+ return (response.brandCompliance.status === 'compliant' &&
639
+ response.qualityScore >= 0.7);
640
+ }
641
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/generation/index.ts"],"names":[],"mappings":"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"}