@vezlo/assistant-server 2.7.0 โ†’ 2.8.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 (28) hide show
  1. package/README.md +1 -1
  2. package/dist/src/bootstrap/initializeServices.d.ts +2 -0
  3. package/dist/src/bootstrap/initializeServices.d.ts.map +1 -1
  4. package/dist/src/bootstrap/initializeServices.js +4 -1
  5. package/dist/src/bootstrap/initializeServices.js.map +1 -1
  6. package/dist/src/controllers/ChatController.d.ts +2 -12
  7. package/dist/src/controllers/ChatController.d.ts.map +1 -1
  8. package/dist/src/controllers/ChatController.js +38 -192
  9. package/dist/src/controllers/ChatController.js.map +1 -1
  10. package/dist/src/controllers/KnowledgeController.d.ts +8 -1
  11. package/dist/src/controllers/KnowledgeController.d.ts.map +1 -1
  12. package/dist/src/controllers/KnowledgeController.js +38 -1
  13. package/dist/src/controllers/KnowledgeController.js.map +1 -1
  14. package/dist/src/server.js +44 -1
  15. package/dist/src/server.js.map +1 -1
  16. package/dist/src/services/CitationService.d.ts +14 -0
  17. package/dist/src/services/CitationService.d.ts.map +1 -0
  18. package/dist/src/services/CitationService.js +76 -0
  19. package/dist/src/services/CitationService.js.map +1 -0
  20. package/dist/src/services/ResponseGenerationService.d.ts +65 -0
  21. package/dist/src/services/ResponseGenerationService.d.ts.map +1 -0
  22. package/dist/src/services/ResponseGenerationService.js +165 -0
  23. package/dist/src/services/ResponseGenerationService.js.map +1 -0
  24. package/dist/src/services/ResponseStreamingService.d.ts +33 -0
  25. package/dist/src/services/ResponseStreamingService.d.ts.map +1 -0
  26. package/dist/src/services/ResponseStreamingService.js +114 -0
  27. package/dist/src/services/ResponseStreamingService.js.map +1 -0
  28. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ResponseGenerationService.d.ts","sourceRoot":"","sources":["../../../src/services/ResponseGenerationService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AAC5E,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAGvC,MAAM,WAAW,qBAAqB;IACpC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,OAAO,EAAE,KAAK,CAAC;QACb,aAAa,EAAE,MAAM,CAAC;QACtB,cAAc,EAAE,MAAM,CAAC;QACvB,aAAa,EAAE,MAAM,EAAE,CAAC;KACzB,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,QAAQ,GAAG,WAAW,CAAC;IAC7B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE;QACjB,mBAAmB,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,QAAQ,CAAC;YAAC,OAAO,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QACvF,gBAAgB,CAAC,EAAE,MAAM,CAAC;KAC3B,CAAC;IACF,OAAO,CAAC,EAAE,KAAK,CAAC;QACd,aAAa,EAAE,MAAM,CAAC;QACtB,cAAc,EAAE,MAAM,CAAC;QACvB,aAAa,EAAE,MAAM,EAAE,CAAC;KACzB,CAAC,CAAC;CACJ;AAED,qBAAa,yBAAyB;IACpC,OAAO,CAAC,aAAa,CAAC,CAAgB;IACtC,OAAO,CAAC,SAAS,CAAC,CAAY;IAC9B,OAAO,CAAC,iBAAiB,CAAS;gBAGhC,aAAa,EAAE,aAAa,GAAG,SAAS,EACxC,SAAS,EAAE,SAAS,GAAG,SAAS,EAChC,iBAAiB,EAAE,MAAM;IAO3B;;OAEG;IACG,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,0BAA0B,CAAC;IAkBlG;;;OAGG;IACH,kBAAkB,CAChB,MAAM,EAAE,0BAA0B,EAClC,kBAAkB,EAAE,MAAM,GACzB,MAAM,GAAG,IAAI;IAmBhB;;OAEG;IACG,mBAAmB,CACvB,KAAK,EAAE,MAAM,EACb,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,qBAAqB,CAAC;IAsFjC;;OAEG;IACH,gBAAgB,CACd,QAAQ,EAAE,WAAW,EAAE,EACvB,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,GAC/B;QACD,mBAAmB,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,QAAQ,CAAC;YAAC,OAAO,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QACvF,gBAAgB,CAAC,EAAE,MAAM,CAAC;KAC3B;IAUD;;OAEG;IACH,YAAY,IAAI,SAAS,GAAG,SAAS;IAIrC;;OAEG;IACH,OAAO,CAAC,mBAAmB;CAa5B"}
@@ -0,0 +1,165 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ResponseGenerationService = void 0;
7
+ const logger_1 = __importDefault(require("../config/logger"));
8
+ class ResponseGenerationService {
9
+ constructor(intentService, aiService, chatHistoryLength) {
10
+ this.intentService = intentService;
11
+ this.aiService = aiService;
12
+ this.chatHistoryLength = chatHistoryLength;
13
+ }
14
+ /**
15
+ * Classify user intent
16
+ */
17
+ async classifyIntent(message, history) {
18
+ if (!this.intentService) {
19
+ return {
20
+ intent: 'knowledge',
21
+ needsGuardrail: false,
22
+ contactEmail: null
23
+ };
24
+ }
25
+ const resolvedHistory = Array.isArray(history) ? history : [];
26
+ logger_1.default.info('๐Ÿงญ Classifying user intent...');
27
+ return this.intentService.classify({
28
+ message,
29
+ conversationHistory: resolvedHistory
30
+ });
31
+ }
32
+ /**
33
+ * Handle intent classification result
34
+ * Returns response content if non-knowledge intent, null if knowledge intent
35
+ */
36
+ handleIntentResult(result, userMessageContent) {
37
+ if (result.needsGuardrail && result.intent !== 'guardrail') {
38
+ logger_1.default.info('๐Ÿ›ก๏ธ Guardrail triggered');
39
+ return `I can help with documentation or implementation guidance, but I can't share credentials or confidential configuration. Please contact your system administrator or support for access.`;
40
+ }
41
+ logger_1.default.info(`๐Ÿงพ Intent result: ${result.intent}${result.needsGuardrail ? ' (guardrail triggered)' : ''}`);
42
+ // For non-knowledge intents, return the response content to be streamed
43
+ if (result.intent !== 'knowledge') {
44
+ const responseContent = result.response || this.getFallbackResponse(result.intent);
45
+ return responseContent;
46
+ }
47
+ // Knowledge intent - proceed to RAG flow (return null to indicate streaming will happen later)
48
+ logger_1.default.info('๐Ÿ“š Intent requires knowledge lookup; proceeding with RAG flow.');
49
+ return null;
50
+ }
51
+ /**
52
+ * Search knowledge base and extract sources
53
+ */
54
+ async searchKnowledgeBase(query, companyId) {
55
+ const sources = [];
56
+ let knowledgeResults = null;
57
+ const aiServiceAny = this.aiService;
58
+ if (!aiServiceAny || !aiServiceAny.knowledgeBaseService) {
59
+ logger_1.default.warn('โš ๏ธ AI service or knowledge base service not available');
60
+ return { knowledgeResults: null, sources: [] };
61
+ }
62
+ try {
63
+ logger_1.default.info(`๐Ÿ” Searching KB: query="${query.substring(0, 50)}...", companyId=${companyId}`);
64
+ const searchResults = await aiServiceAny.knowledgeBaseService.search(query, {
65
+ limit: 5,
66
+ company_id: companyId
67
+ });
68
+ logger_1.default.info(`๐Ÿ“Š Found knowledge base results: ${searchResults.length}`);
69
+ if (searchResults.length > 0) {
70
+ knowledgeResults = '\n\nRelevant information from knowledge base:\n';
71
+ searchResults.forEach((result) => {
72
+ const title = result.title || 'Untitled';
73
+ const content = result.content || '';
74
+ if (content.trim()) {
75
+ knowledgeResults += `- ${title}: ${content}\n`;
76
+ // Extract chunk indices from metadata.chunk_range (e.g., "0-2" -> [0,1,2])
77
+ let chunkIndices = [];
78
+ if (result.metadata?.chunk_range) {
79
+ const [start, end] = result.metadata.chunk_range.split('-').map((n) => parseInt(n, 10));
80
+ if (!isNaN(start) && !isNaN(end)) {
81
+ for (let i = start; i <= end; i++) {
82
+ chunkIndices.push(i);
83
+ }
84
+ }
85
+ }
86
+ // Add to sources array (deduplicate by document_uuid)
87
+ if (!sources.find(s => s.document_uuid === result.id)) {
88
+ sources.push({
89
+ document_uuid: result.id,
90
+ document_title: title,
91
+ chunk_indices: chunkIndices
92
+ });
93
+ }
94
+ else {
95
+ const existing = sources.find(s => s.document_uuid === result.id);
96
+ if (existing) {
97
+ // Merge chunk indices
98
+ chunkIndices.forEach(idx => {
99
+ if (!existing.chunk_indices.includes(idx)) {
100
+ existing.chunk_indices.push(idx);
101
+ }
102
+ });
103
+ }
104
+ }
105
+ }
106
+ });
107
+ // Verify we actually have meaningful content (not just the header)
108
+ const headerLength = '\n\nRelevant information from knowledge base:\n'.length;
109
+ if (knowledgeResults.length > headerLength + 10) {
110
+ logger_1.default.info(`โœ… Knowledge context prepared (${knowledgeResults.length} chars, ${searchResults.length} results)`);
111
+ logger_1.default.info(`๐Ÿ“ Knowledge preview: ${knowledgeResults.substring(0, 200)}...`);
112
+ }
113
+ else {
114
+ logger_1.default.warn(`โš ๏ธ Knowledge results found but content is empty or too short (${knowledgeResults.length} chars), treating as no results`);
115
+ knowledgeResults = '';
116
+ }
117
+ }
118
+ else {
119
+ knowledgeResults = '';
120
+ logger_1.default.info('โš ๏ธ No knowledge base results found; will return appropriate fallback response');
121
+ }
122
+ }
123
+ catch (error) {
124
+ console.error('โŒ Failed to search knowledge base:', error);
125
+ logger_1.default.error('Failed to search knowledge base:', error);
126
+ knowledgeResults = null;
127
+ }
128
+ return { knowledgeResults, sources };
129
+ }
130
+ /**
131
+ * Build chat context for AI generation
132
+ */
133
+ buildChatContext(messages, knowledgeResults) {
134
+ return {
135
+ conversationHistory: messages.map(msg => ({
136
+ role: msg.role,
137
+ content: msg.content
138
+ })),
139
+ knowledgeResults: knowledgeResults ?? undefined
140
+ };
141
+ }
142
+ /**
143
+ * Get AI service for streaming
144
+ */
145
+ getAIService() {
146
+ return this.aiService;
147
+ }
148
+ /**
149
+ * Get fallback response for intent
150
+ */
151
+ getFallbackResponse(intent) {
152
+ const fallbacks = {
153
+ greeting: 'Hello! How can I help you today?',
154
+ acknowledgment: "You're welcome! Let me know if you need anything else.",
155
+ personality: `I'm ${process.env.ASSISTANT_NAME || 'AI Assistant'}, your AI assistant for ${process.env.ORGANIZATION_NAME || 'Your Organization'}.`,
156
+ clarification: "I'm not sure I understood. Could you clarify what you need help with?",
157
+ guardrail: "I can help with documentation or implementation guidance, but I can't share credentials or confidential configuration.",
158
+ human_support_request: "I'd be happy to connect you with our support team. Could you please provide your email address?",
159
+ human_support_email: "Thank you! Our support team will reach out to you shortly."
160
+ };
161
+ return fallbacks[intent] || "I'm here to help. What would you like to know?";
162
+ }
163
+ }
164
+ exports.ResponseGenerationService = ResponseGenerationService;
165
+ //# sourceMappingURL=ResponseGenerationService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ResponseGenerationService.js","sourceRoot":"","sources":["../../../src/services/ResponseGenerationService.ts"],"names":[],"mappings":";;;;;;AAGA,8DAAsC;AAyBtC,MAAa,yBAAyB;IAKpC,YACE,aAAwC,EACxC,SAAgC,EAChC,iBAAyB;QAEzB,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;QACnC,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,iBAAiB,GAAG,iBAAiB,CAAC;IAC7C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,cAAc,CAAC,OAAe,EAAE,OAAsB;QAC1D,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;YACxB,OAAO;gBACL,MAAM,EAAE,WAAW;gBACnB,cAAc,EAAE,KAAK;gBACrB,YAAY,EAAE,IAAI;aACnB,CAAC;QACJ,CAAC;QAED,MAAM,eAAe,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9D,gBAAM,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;QAE7C,OAAO,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC;YACjC,OAAO;YACP,mBAAmB,EAAE,eAAe;SACrC,CAAC,CAAC;IACL,CAAC;IAED;;;OAGG;IACH,kBAAkB,CAChB,MAAkC,EAClC,kBAA0B;QAE1B,IAAI,MAAM,CAAC,cAAc,IAAI,MAAM,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YAC3D,gBAAM,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;YACvC,OAAO,wLAAwL,CAAC;QAClM,CAAC;QAED,gBAAM,CAAC,IAAI,CAAC,qBAAqB,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAE1G,wEAAwE;QACxE,IAAI,MAAM,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YAClC,MAAM,eAAe,GAAG,MAAM,CAAC,QAAQ,IAAI,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACnF,OAAO,eAAe,CAAC;QACzB,CAAC;QAED,+FAA+F;QAC/F,gBAAM,CAAC,IAAI,CAAC,gEAAgE,CAAC,CAAC;QAC9E,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,mBAAmB,CACvB,KAAa,EACb,SAAkB;QAElB,MAAM,OAAO,GAIR,EAAE,CAAC;QACR,IAAI,gBAAgB,GAAkB,IAAI,CAAC;QAE3C,MAAM,YAAY,GAAG,IAAI,CAAC,SAAgB,CAAC;QAC3C,IAAI,CAAC,YAAY,IAAI,CAAC,YAAY,CAAC,oBAAoB,EAAE,CAAC;YACxD,gBAAM,CAAC,IAAI,CAAC,wDAAwD,CAAC,CAAC;YACtE,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;QACjD,CAAC;QAED,IAAI,CAAC;YACH,gBAAM,CAAC,IAAI,CAAC,2BAA2B,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,mBAAmB,SAAS,EAAE,CAAC,CAAC;YAE7F,MAAM,aAAa,GAAG,MAAM,YAAY,CAAC,oBAAoB,CAAC,MAAM,CAAC,KAAK,EAAE;gBAC1E,KAAK,EAAE,CAAC;gBACR,UAAU,EAAE,SAAS;aACtB,CAAC,CAAC;YAEH,gBAAM,CAAC,IAAI,CAAC,oCAAoC,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC;YAExE,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC7B,gBAAgB,GAAG,iDAAiD,CAAC;gBACrE,aAAa,CAAC,OAAO,CAAC,CAAC,MAAW,EAAE,EAAE;oBACpC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,UAAU,CAAC;oBACzC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC;oBACrC,IAAI,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;wBACnB,gBAAgB,IAAI,KAAK,KAAK,KAAK,OAAO,IAAI,CAAC;wBAE/C,2EAA2E;wBAC3E,IAAI,YAAY,GAAa,EAAE,CAAC;wBAChC,IAAI,MAAM,CAAC,QAAQ,EAAE,WAAW,EAAE,CAAC;4BACjC,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;4BAChG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;gCACjC,KAAK,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC,IAAI,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;oCAClC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gCACvB,CAAC;4BACH,CAAC;wBACH,CAAC;wBAED,sDAAsD;wBACtD,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,KAAK,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;4BACtD,OAAO,CAAC,IAAI,CAAC;gCACX,aAAa,EAAE,MAAM,CAAC,EAAE;gCACxB,cAAc,EAAE,KAAK;gCACrB,aAAa,EAAE,YAAY;6BAC5B,CAAC,CAAC;wBACL,CAAC;6BAAM,CAAC;4BACN,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,KAAK,MAAM,CAAC,EAAE,CAAC,CAAC;4BAClE,IAAI,QAAQ,EAAE,CAAC;gCACb,sBAAsB;gCACtB,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;oCACzB,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;wCAC1C,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;oCACnC,CAAC;gCACH,CAAC,CAAC,CAAC;4BACL,CAAC;wBACH,CAAC;oBACH,CAAC;gBACH,CAAC,CAAC,CAAC;gBAEH,mEAAmE;gBACnE,MAAM,YAAY,GAAG,iDAAiD,CAAC,MAAM,CAAC;gBAC9E,IAAI,gBAAgB,CAAC,MAAM,GAAG,YAAY,GAAG,EAAE,EAAE,CAAC;oBAChD,gBAAM,CAAC,IAAI,CAAC,iCAAiC,gBAAgB,CAAC,MAAM,WAAW,aAAa,CAAC,MAAM,WAAW,CAAC,CAAC;oBAChH,gBAAM,CAAC,IAAI,CAAC,yBAAyB,gBAAgB,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;gBAChF,CAAC;qBAAM,CAAC;oBACN,gBAAM,CAAC,IAAI,CAAC,kEAAkE,gBAAgB,CAAC,MAAM,iCAAiC,CAAC,CAAC;oBACxI,gBAAgB,GAAG,EAAE,CAAC;gBACxB,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,gBAAgB,GAAG,EAAE,CAAC;gBACtB,gBAAM,CAAC,IAAI,CAAC,gFAAgF,CAAC,CAAC;YAChG,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,oCAAoC,EAAE,KAAK,CAAC,CAAC;YAC3D,gBAAM,CAAC,KAAK,CAAC,kCAAkC,EAAE,KAAK,CAAC,CAAC;YACxD,gBAAgB,GAAG,IAAI,CAAC;QAC1B,CAAC;QAED,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,CAAC;IACvC,CAAC;IAED;;OAEG;IACH,gBAAgB,CACd,QAAuB,EACvB,gBAAgC;QAKhC,OAAO;YACL,mBAAmB,EAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBACxC,IAAI,EAAE,GAAG,CAAC,IAAuC;gBACjD,OAAO,EAAE,GAAG,CAAC,OAAO;aACrB,CAAC,CAAC;YACH,gBAAgB,EAAE,gBAAgB,IAAI,SAAS;SAChD,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,YAAY;QACV,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED;;OAEG;IACK,mBAAmB,CAAC,MAAc;QACxC,MAAM,SAAS,GAA2B;YACxC,QAAQ,EAAE,kCAAkC;YAC5C,cAAc,EAAE,wDAAwD;YACxE,WAAW,EAAE,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,cAAc,2BAA2B,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,mBAAmB,GAAG;YAClJ,aAAa,EAAE,uEAAuE;YACtF,SAAS,EAAE,wHAAwH;YACnI,qBAAqB,EAAE,iGAAiG;YACxH,mBAAmB,EAAE,4DAA4D;SAClF,CAAC;QAEF,OAAO,SAAS,CAAC,MAAM,CAAC,IAAI,gDAAgD,CAAC;IAC/E,CAAC;CACF;AApMD,8DAoMC"}
@@ -0,0 +1,33 @@
1
+ import { Response } from 'express';
2
+ export declare class ResponseStreamingService {
3
+ /**
4
+ * Stream text content word by word to simulate streaming
5
+ * This ensures consistent SSE format for all responses
6
+ */
7
+ streamTextContent(content: string, res: Response): Promise<void>;
8
+ /**
9
+ * Stream AI response chunks with source handling
10
+ */
11
+ streamAIResponse(stream: AsyncGenerator<{
12
+ chunk: string;
13
+ done: boolean;
14
+ fullContent?: string;
15
+ }, void, unknown>, res: Response, sources?: Array<{
16
+ document_uuid: string;
17
+ document_title: string;
18
+ chunk_indices: number[];
19
+ }>, knowledgeResults?: string | null): Promise<string>;
20
+ /**
21
+ * Send completion event
22
+ */
23
+ sendCompletionEvent(res: Response, messageUuid: string, parentMessageUuid: string | undefined, createdAt: Date): void;
24
+ /**
25
+ * Send error event
26
+ */
27
+ sendErrorEvent(res: Response, error: string, message?: string): void;
28
+ /**
29
+ * Setup SSE headers
30
+ */
31
+ setupSSEHeaders(res: Response): void;
32
+ }
33
+ //# sourceMappingURL=ResponseStreamingService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ResponseStreamingService.d.ts","sourceRoot":"","sources":["../../../src/services/ResponseStreamingService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGnC,qBAAa,wBAAwB;IACnC;;;OAGG;IACG,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IA4BtE;;OAEG;IACG,gBAAgB,CACpB,MAAM,EAAE,cAAc,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,IAAI,EAAE,OAAO,CAAC,EAC7F,GAAG,EAAE,QAAQ,EACb,OAAO,CAAC,EAAE,KAAK,CAAC;QACd,aAAa,EAAE,MAAM,CAAC;QACtB,cAAc,EAAE,MAAM,CAAC;QACvB,aAAa,EAAE,MAAM,EAAE,CAAC;KACzB,CAAC,EACF,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,GAC/B,OAAO,CAAC,MAAM,CAAC;IAiDlB;;OAEG;IACH,mBAAmB,CAAC,GAAG,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,GAAG,SAAS,EAAE,SAAS,EAAE,IAAI,GAAG,IAAI;IAWrH;;OAEG;IACH,cAAc,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI;IASpE;;OAEG;IACH,eAAe,CAAC,GAAG,EAAE,QAAQ,GAAG,IAAI;CAMrC"}
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ResponseStreamingService = void 0;
7
+ const logger_1 = __importDefault(require("../config/logger"));
8
+ class ResponseStreamingService {
9
+ /**
10
+ * Stream text content word by word to simulate streaming
11
+ * This ensures consistent SSE format for all responses
12
+ */
13
+ async streamTextContent(content, res) {
14
+ const words = content.split(' ');
15
+ const chunkSize = 2; // Stream 2 words at a time for smoother experience
16
+ const totalChunks = Math.ceil(words.length / chunkSize);
17
+ for (let i = 0; i < words.length; i += chunkSize) {
18
+ const chunk = words.slice(i, i + chunkSize).join(' ') + (i + chunkSize < words.length ? ' ' : '');
19
+ const chunkIndex = Math.floor(i / chunkSize) + 1;
20
+ const isLastChunk = chunkIndex === totalChunks;
21
+ const chunkData = JSON.stringify({
22
+ type: 'chunk',
23
+ content: chunk,
24
+ done: isLastChunk, // Mark last chunk with done: true
25
+ sources: undefined // Intent responses have no sources
26
+ });
27
+ res.write(`data: ${chunkData}\n\n`);
28
+ // Flush the response to ensure chunks are sent immediately
29
+ if (res.flush) {
30
+ res.flush();
31
+ }
32
+ // Delay for smooth streaming effect (30ms for better visibility)
33
+ await new Promise(resolve => setTimeout(resolve, 30));
34
+ }
35
+ }
36
+ /**
37
+ * Stream AI response chunks with source handling
38
+ */
39
+ async streamAIResponse(stream, res, sources, knowledgeResults) {
40
+ let accumulatedContent = '';
41
+ let chunkCount = 0;
42
+ logger_1.default.info('๐Ÿ”„ Starting OpenAI stream...');
43
+ for await (const { chunk, done, fullContent } of stream) {
44
+ chunkCount++;
45
+ // On last chunk, include sources (only if we actually have useful knowledge results)
46
+ // Don't send sources if LLM couldn't answer or apologized
47
+ const shouldIncludeSources = done && sources && sources.length > 0 && knowledgeResults && knowledgeResults.trim().length > 0;
48
+ const chunkData = JSON.stringify({
49
+ type: 'chunk',
50
+ content: chunk,
51
+ done: done || false,
52
+ sources: shouldIncludeSources ? sources : undefined
53
+ });
54
+ // Log sources on last chunk for debugging
55
+ if (shouldIncludeSources) {
56
+ logger_1.default.info(`๐Ÿ“š Sending sources with last chunk: ${JSON.stringify(sources)}`);
57
+ }
58
+ else if (done && sources && sources.length > 0) {
59
+ logger_1.default.info(`โš ๏ธ Sources available but not sent (no knowledge results used)`);
60
+ }
61
+ res.write(`data: ${chunkData}\n\n`);
62
+ if (res.flush)
63
+ res.flush();
64
+ // Update accumulated content
65
+ if (chunk) {
66
+ accumulatedContent += chunk;
67
+ }
68
+ // Log first and last chunks
69
+ if (chunkCount === 1) {
70
+ logger_1.default.info(`๐Ÿ“ค First chunk sent: "${chunk.substring(0, 30)}..."`);
71
+ }
72
+ if (done && fullContent) {
73
+ accumulatedContent = fullContent;
74
+ logger_1.default.info(`๐Ÿ Stream complete: ${chunkCount} chunks sent, ${fullContent.length} total chars`);
75
+ }
76
+ }
77
+ return accumulatedContent;
78
+ }
79
+ /**
80
+ * Send completion event
81
+ */
82
+ sendCompletionEvent(res, messageUuid, parentMessageUuid, createdAt) {
83
+ const completionData = JSON.stringify({
84
+ type: 'completion',
85
+ uuid: messageUuid,
86
+ parent_message_uuid: parentMessageUuid || '',
87
+ status: 'completed',
88
+ created_at: createdAt.toISOString()
89
+ });
90
+ res.write(`data: ${completionData}\n\n`);
91
+ }
92
+ /**
93
+ * Send error event
94
+ */
95
+ sendErrorEvent(res, error, message) {
96
+ const errorData = JSON.stringify({
97
+ type: 'error',
98
+ error,
99
+ message: message || 'Unknown error'
100
+ });
101
+ res.write(`data: ${errorData}\n\n`);
102
+ }
103
+ /**
104
+ * Setup SSE headers
105
+ */
106
+ setupSSEHeaders(res) {
107
+ res.setHeader('Content-Type', 'text/event-stream');
108
+ res.setHeader('Cache-Control', 'no-cache');
109
+ res.setHeader('Connection', 'keep-alive');
110
+ res.setHeader('X-Accel-Buffering', 'no'); // Disable nginx buffering
111
+ }
112
+ }
113
+ exports.ResponseStreamingService = ResponseStreamingService;
114
+ //# sourceMappingURL=ResponseStreamingService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ResponseStreamingService.js","sourceRoot":"","sources":["../../../src/services/ResponseStreamingService.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vezlo/assistant-server",
3
- "version": "2.7.0",
3
+ "version": "2.8.0",
4
4
  "description": "Production-ready AI Assistant Server with advanced RAG (chunk-based semantic search + adjacent retrieval), conversation management, real-time communication, and human agent handoff",
5
5
  "main": "dist/src/server.js",
6
6
  "types": "dist/src/server.d.ts",