bc-code-intelligence-mcp 1.1.1 → 1.2.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.
- package/README.md +99 -9
- package/dist/cli/bc-code-intel-cli.js +0 -1
- package/dist/cli/bc-code-intel-cli.js.map +1 -1
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +82 -5
- package/dist/index.js.map +1 -1
- package/dist/layers/embedded-layer.d.ts +74 -0
- package/dist/layers/embedded-layer.d.ts.map +1 -1
- package/dist/layers/embedded-layer.js +287 -3
- package/dist/layers/embedded-layer.js.map +1 -1
- package/dist/layers/layer-service.d.ts +6 -0
- package/dist/layers/layer-service.d.ts.map +1 -1
- package/dist/layers/layer-service.js +13 -0
- package/dist/layers/layer-service.js.map +1 -1
- package/dist/services/agent-onboarding-service.d.ts +45 -0
- package/dist/services/agent-onboarding-service.d.ts.map +1 -0
- package/dist/services/agent-onboarding-service.js +372 -0
- package/dist/services/agent-onboarding-service.js.map +1 -0
- package/dist/services/enhanced-prompt-service.d.ts +60 -0
- package/dist/services/enhanced-prompt-service.d.ts.map +1 -0
- package/dist/services/enhanced-prompt-service.js +162 -0
- package/dist/services/enhanced-prompt-service.js.map +1 -0
- package/dist/services/multi-content-layer-service.d.ts +92 -0
- package/dist/services/multi-content-layer-service.d.ts.map +1 -0
- package/dist/services/multi-content-layer-service.js +407 -0
- package/dist/services/multi-content-layer-service.js.map +1 -0
- package/dist/services/roleplay-engine.d.ts +121 -0
- package/dist/services/roleplay-engine.d.ts.map +1 -0
- package/dist/services/roleplay-engine.js +672 -0
- package/dist/services/roleplay-engine.js.map +1 -0
- package/dist/services/session-storage/file-storage.d.ts +30 -0
- package/dist/services/session-storage/file-storage.d.ts.map +1 -0
- package/dist/services/session-storage/file-storage.js +229 -0
- package/dist/services/session-storage/file-storage.js.map +1 -0
- package/dist/services/session-storage/in-memory-storage.d.ts +31 -0
- package/dist/services/session-storage/in-memory-storage.d.ts.map +1 -0
- package/dist/services/session-storage/in-memory-storage.js +142 -0
- package/dist/services/session-storage/in-memory-storage.js.map +1 -0
- package/dist/services/specialist-discovery.d.ts +76 -0
- package/dist/services/specialist-discovery.d.ts.map +1 -0
- package/dist/services/specialist-discovery.js +270 -0
- package/dist/services/specialist-discovery.js.map +1 -0
- package/dist/services/specialist-handoff-service.d.ts +81 -0
- package/dist/services/specialist-handoff-service.d.ts.map +1 -0
- package/dist/services/specialist-handoff-service.js +470 -0
- package/dist/services/specialist-handoff-service.js.map +1 -0
- package/dist/services/specialist-loader.d.ts +101 -0
- package/dist/services/specialist-loader.d.ts.map +1 -0
- package/dist/services/specialist-loader.js +249 -0
- package/dist/services/specialist-loader.js.map +1 -0
- package/dist/services/specialist-session-manager.d.ts +76 -0
- package/dist/services/specialist-session-manager.d.ts.map +1 -0
- package/dist/services/specialist-session-manager.js +255 -0
- package/dist/services/specialist-session-manager.js.map +1 -0
- package/dist/tools/specialist-discovery-tools.d.ts +27 -0
- package/dist/tools/specialist-discovery-tools.d.ts.map +1 -0
- package/dist/tools/specialist-discovery-tools.js +287 -0
- package/dist/tools/specialist-discovery-tools.js.map +1 -0
- package/dist/tools/specialist-tools.d.ts +38 -0
- package/dist/tools/specialist-tools.d.ts.map +1 -0
- package/dist/tools/specialist-tools.js +322 -0
- package/dist/tools/specialist-tools.js.map +1 -0
- package/dist/types/config-types.d.ts +2 -0
- package/dist/types/config-types.d.ts.map +1 -1
- package/dist/types/config-types.js.map +1 -1
- package/dist/types/enhanced-layer-types.d.ts +193 -0
- package/dist/types/enhanced-layer-types.d.ts.map +1 -0
- package/dist/types/enhanced-layer-types.js +9 -0
- package/dist/types/enhanced-layer-types.js.map +1 -0
- package/dist/types/layer-types.d.ts +2 -0
- package/dist/types/layer-types.d.ts.map +1 -1
- package/dist/types/layer-types.js.map +1 -1
- package/dist/types/roleplay-types.d.ts +149 -0
- package/dist/types/roleplay-types.d.ts.map +1 -0
- package/dist/types/roleplay-types.js +8 -0
- package/dist/types/roleplay-types.js.map +1 -0
- package/dist/types/session-types.d.ts +111 -0
- package/dist/types/session-types.d.ts.map +1 -0
- package/dist/types/session-types.js +8 -0
- package/dist/types/session-types.js.map +1 -0
- package/embedded-knowledge/AGENTS.md +119 -10
- package/embedded-knowledge/README.md +20 -3
- package/embedded-knowledge/specialists/alex-architect.md +216 -0
- package/embedded-knowledge/specialists/casey-copilot.md +226 -0
- package/embedded-knowledge/specialists/dean-debug.md +222 -0
- package/embedded-knowledge/specialists/eva-errors.md +235 -0
- package/embedded-knowledge/specialists/jordan-bridge.md +235 -0
- package/embedded-knowledge/specialists/logan-legacy.md +209 -0
- package/embedded-knowledge/specialists/maya-mentor.md +211 -0
- package/embedded-knowledge/specialists/morgan-market.md +226 -0
- package/embedded-knowledge/specialists/quinn-tester.md +235 -0
- package/embedded-knowledge/specialists/roger-reviewer.md +234 -0
- package/embedded-knowledge/specialists/sam-coder.md +181 -0
- package/embedded-knowledge/specialists/seth-security.md +235 -0
- package/embedded-knowledge/specialists/taylor-docs.md +257 -0
- package/embedded-knowledge/specialists/uma-ux.md +235 -0
- package/package.json +3 -3
|
@@ -0,0 +1,672 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BC Specialist Roleplay Engine
|
|
3
|
+
*
|
|
4
|
+
* Brings specialist personas to life through personality-driven responses,
|
|
5
|
+
* consistent character adoption, and context-aware knowledge integration.
|
|
6
|
+
*/
|
|
7
|
+
export class BCSpecialistRoleplayEngine {
|
|
8
|
+
layerService;
|
|
9
|
+
knowledgeService;
|
|
10
|
+
config;
|
|
11
|
+
responseTemplates = new Map();
|
|
12
|
+
knowledgeRetriever;
|
|
13
|
+
constructor(layerService, knowledgeService, config) {
|
|
14
|
+
this.layerService = layerService;
|
|
15
|
+
this.knowledgeService = knowledgeService;
|
|
16
|
+
this.config = {
|
|
17
|
+
personality_strength: 'moderate',
|
|
18
|
+
response_length: 'adaptive',
|
|
19
|
+
knowledge_integration: 'balanced',
|
|
20
|
+
suggest_handoffs: true,
|
|
21
|
+
suggest_collaborations: true,
|
|
22
|
+
learn_user_preferences: true,
|
|
23
|
+
adapt_communication_style: true,
|
|
24
|
+
...config
|
|
25
|
+
};
|
|
26
|
+
this.knowledgeRetriever = new BCKnowledgeRetriever(layerService, knowledgeService);
|
|
27
|
+
this.initializeResponseTemplates();
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Generate a personality-driven response from a specialist
|
|
31
|
+
*/
|
|
32
|
+
async generateResponse(context) {
|
|
33
|
+
const { specialist, userMessage, session } = context;
|
|
34
|
+
// Analyze the specialist's personality
|
|
35
|
+
const personality = this.analyzePersonality(specialist);
|
|
36
|
+
// Find relevant knowledge
|
|
37
|
+
const relevantTopics = await this.knowledgeRetriever.findRelevantTopics(userMessage, specialist.expertise.primary.concat(specialist.expertise.secondary), 5);
|
|
38
|
+
// Generate personality-driven response
|
|
39
|
+
const response = await this.buildPersonalityResponse(specialist, personality, context, relevantTopics);
|
|
40
|
+
// Apply session context updates
|
|
41
|
+
const contextUpdates = this.generateContextUpdates(context, relevantTopics);
|
|
42
|
+
// Check for collaboration opportunities
|
|
43
|
+
const suggestedHandoffs = await this.suggestCollaborations(context, relevantTopics);
|
|
44
|
+
return {
|
|
45
|
+
content: response.content,
|
|
46
|
+
specialist_id: specialist.specialist_id,
|
|
47
|
+
personality_elements: response.personality_elements,
|
|
48
|
+
topics_referenced: relevantTopics.map(t => t.id),
|
|
49
|
+
knowledge_applied: relevantTopics.map(topic => ({
|
|
50
|
+
topic_id: topic.id,
|
|
51
|
+
application_context: this.getApplicationContext(topic, userMessage)
|
|
52
|
+
})),
|
|
53
|
+
suggested_handoffs: suggestedHandoffs,
|
|
54
|
+
context_updates: contextUpdates,
|
|
55
|
+
recommendations_added: response.recommendations,
|
|
56
|
+
response_type: response.response_type,
|
|
57
|
+
confidence_level: response.confidence_level
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Analyze user message to suggest appropriate specialist
|
|
62
|
+
*/
|
|
63
|
+
async suggestSpecialist(userMessage, currentContext) {
|
|
64
|
+
const specialists = await this.layerService.getAllSpecialists();
|
|
65
|
+
const suggestions = [];
|
|
66
|
+
for (const specialist of specialists) {
|
|
67
|
+
const confidence = await this.calculateSpecialistConfidence(userMessage, specialist, currentContext);
|
|
68
|
+
if (confidence > 0.3) { // Threshold for relevant suggestions
|
|
69
|
+
suggestions.push({
|
|
70
|
+
specialist_id: specialist.specialist_id,
|
|
71
|
+
confidence,
|
|
72
|
+
reasoning: this.generateSuggestionReasoning(userMessage, specialist, confidence)
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return suggestions.sort((a, b) => b.confidence - a.confidence).slice(0, 3);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Generate a specialist greeting for session start
|
|
80
|
+
*/
|
|
81
|
+
async generateGreeting(specialist, context) {
|
|
82
|
+
const personality = this.analyzePersonality(specialist);
|
|
83
|
+
const greeting = this.buildGreeting(specialist, personality, context);
|
|
84
|
+
return {
|
|
85
|
+
content: greeting,
|
|
86
|
+
specialist_id: specialist.specialist_id,
|
|
87
|
+
personality_elements: {
|
|
88
|
+
greeting_used: true,
|
|
89
|
+
characteristic_phrases: [specialist.persona.greeting],
|
|
90
|
+
expertise_demonstrated: specialist.expertise.primary.slice(0, 2),
|
|
91
|
+
communication_style_applied: specialist.persona.communication_style
|
|
92
|
+
},
|
|
93
|
+
topics_referenced: [],
|
|
94
|
+
knowledge_applied: [],
|
|
95
|
+
response_type: 'greeting',
|
|
96
|
+
confidence_level: 'high'
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Generate handoff message when transferring between specialists
|
|
101
|
+
*/
|
|
102
|
+
async generateHandoff(fromSpecialist, toSpecialist, context) {
|
|
103
|
+
const fromPersonality = this.analyzePersonality(fromSpecialist);
|
|
104
|
+
const toPersonality = this.analyzePersonality(toSpecialist);
|
|
105
|
+
const farewell = this.buildHandoffFarewell(fromSpecialist, toSpecialist, context);
|
|
106
|
+
const introduction = this.buildHandoffIntroduction(toSpecialist, fromSpecialist, context);
|
|
107
|
+
return {
|
|
108
|
+
farewell: {
|
|
109
|
+
content: farewell,
|
|
110
|
+
specialist_id: fromSpecialist.specialist_id,
|
|
111
|
+
personality_elements: {
|
|
112
|
+
greeting_used: false,
|
|
113
|
+
characteristic_phrases: [],
|
|
114
|
+
expertise_demonstrated: [],
|
|
115
|
+
communication_style_applied: fromSpecialist.persona.communication_style
|
|
116
|
+
},
|
|
117
|
+
topics_referenced: [],
|
|
118
|
+
knowledge_applied: [],
|
|
119
|
+
response_type: 'handoff',
|
|
120
|
+
confidence_level: 'high'
|
|
121
|
+
},
|
|
122
|
+
introduction: {
|
|
123
|
+
content: introduction,
|
|
124
|
+
specialist_id: toSpecialist.specialist_id,
|
|
125
|
+
personality_elements: {
|
|
126
|
+
greeting_used: true,
|
|
127
|
+
characteristic_phrases: [toSpecialist.persona.greeting],
|
|
128
|
+
expertise_demonstrated: toSpecialist.expertise.primary.slice(0, 2),
|
|
129
|
+
communication_style_applied: toSpecialist.persona.communication_style
|
|
130
|
+
},
|
|
131
|
+
topics_referenced: [],
|
|
132
|
+
knowledge_applied: [],
|
|
133
|
+
response_type: 'handoff',
|
|
134
|
+
confidence_level: 'high'
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Update configuration
|
|
140
|
+
*/
|
|
141
|
+
updateConfig(config) {
|
|
142
|
+
this.config = { ...this.config, ...config };
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Get personality analysis for a specialist
|
|
146
|
+
*/
|
|
147
|
+
analyzePersonality(specialist) {
|
|
148
|
+
return {
|
|
149
|
+
communication_style: specialist.persona.communication_style,
|
|
150
|
+
expertise_focus: specialist.expertise.primary,
|
|
151
|
+
problem_approach: this.extractProblemApproach(specialist),
|
|
152
|
+
collaboration_style: this.extractCollaborationStyle(specialist),
|
|
153
|
+
characteristic_phrases: [
|
|
154
|
+
specialist.persona.greeting,
|
|
155
|
+
...this.extractCharacteristicPhrases(specialist)
|
|
156
|
+
]
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Build personality-driven response
|
|
161
|
+
*/
|
|
162
|
+
async buildPersonalityResponse(specialist, personality, context, relevantTopics) {
|
|
163
|
+
const { userMessage, session } = context;
|
|
164
|
+
// Start with specialist greeting if it's a new conversation
|
|
165
|
+
let response = session.messageCount <= 1 ? `${specialist.persona.greeting} ` : '';
|
|
166
|
+
// Apply personality-driven response patterns
|
|
167
|
+
response += await this.generatePersonalityContent(specialist, personality, userMessage, relevantTopics, context);
|
|
168
|
+
// Add recommendations based on knowledge
|
|
169
|
+
const recommendations = this.generateRecommendations(relevantTopics, userMessage);
|
|
170
|
+
// Determine response type and confidence
|
|
171
|
+
const responseType = this.determineResponseType(userMessage, relevantTopics);
|
|
172
|
+
const confidenceLevel = this.calculateConfidenceLevel(specialist, userMessage, relevantTopics);
|
|
173
|
+
return {
|
|
174
|
+
content: response,
|
|
175
|
+
personality_elements: {
|
|
176
|
+
greeting_used: session.messageCount <= 1,
|
|
177
|
+
characteristic_phrases: personality.characteristic_phrases.slice(0, 2),
|
|
178
|
+
expertise_demonstrated: personality.expertise_focus.slice(0, 3),
|
|
179
|
+
communication_style_applied: personality.communication_style
|
|
180
|
+
},
|
|
181
|
+
recommendations,
|
|
182
|
+
response_type: responseType,
|
|
183
|
+
confidence_level: confidenceLevel
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Generate personality-driven content
|
|
188
|
+
*/
|
|
189
|
+
async generatePersonalityContent(specialist, personality, userMessage, relevantTopics, context) {
|
|
190
|
+
// This is where we'd integrate with the actual BC knowledge to generate responses
|
|
191
|
+
// For now, let's create template-based responses that demonstrate personality
|
|
192
|
+
const templates = this.getResponseTemplates(specialist.specialist_id);
|
|
193
|
+
const selectedTemplate = this.selectBestTemplate(templates, userMessage, relevantTopics);
|
|
194
|
+
if (selectedTemplate) {
|
|
195
|
+
return this.fillTemplate(selectedTemplate, specialist, userMessage, relevantTopics, context);
|
|
196
|
+
}
|
|
197
|
+
// Fallback to basic personality-driven response
|
|
198
|
+
return this.generateBasicPersonalityResponse(specialist, userMessage, relevantTopics);
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Generate a basic personality-driven response
|
|
202
|
+
*/
|
|
203
|
+
generateBasicPersonalityResponse(specialist, userMessage, relevantTopics) {
|
|
204
|
+
// Apply specialist's communication style and expertise focus
|
|
205
|
+
const styleApproach = this.getStyleApproach(specialist);
|
|
206
|
+
let response = `${styleApproach} `;
|
|
207
|
+
if (relevantTopics.length > 0) {
|
|
208
|
+
response += `I can see this relates to ${relevantTopics[0].title}. `;
|
|
209
|
+
response += this.generateKnowledgeBasedGuidance(specialist, relevantTopics[0], userMessage);
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
response += `While this might be outside my primary expertise in ${specialist.expertise.primary.join(', ')}, `;
|
|
213
|
+
response += this.generateGeneralGuidance(specialist, userMessage);
|
|
214
|
+
}
|
|
215
|
+
return response;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Generate style-appropriate opening
|
|
219
|
+
*/
|
|
220
|
+
getStyleApproach(specialist) {
|
|
221
|
+
const communication = specialist.persona.communication_style.toLowerCase();
|
|
222
|
+
if (communication.includes('technical')) {
|
|
223
|
+
return "Let's dive into the technical details.";
|
|
224
|
+
}
|
|
225
|
+
else if (communication.includes('business')) {
|
|
226
|
+
return "Let's think about this from a business perspective.";
|
|
227
|
+
}
|
|
228
|
+
else if (communication.includes('practical')) {
|
|
229
|
+
return "Here's a practical approach to your question.";
|
|
230
|
+
}
|
|
231
|
+
else if (communication.includes('teaching')) {
|
|
232
|
+
return "Let me walk you through this step by step.";
|
|
233
|
+
}
|
|
234
|
+
return "I'd be happy to help with this!";
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Generate knowledge-based guidance
|
|
238
|
+
*/
|
|
239
|
+
generateKnowledgeBasedGuidance(specialist, topic, userMessage) {
|
|
240
|
+
// Create specialist-specific framing of the knowledge
|
|
241
|
+
const specialistLens = this.getSpecialistPerspective(specialist, topic);
|
|
242
|
+
// Extract key points from the topic content
|
|
243
|
+
const keyPoints = this.extractKeyGuidancePoints(topic);
|
|
244
|
+
return `${specialistLens} Looking at **${topic.title}**, ${keyPoints}. This ${topic.frontmatter.difficulty === 'advanced' ? 'advanced' : topic.frontmatter.difficulty} pattern applies directly to your situation.`;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Get specialist-specific perspective on a topic
|
|
248
|
+
*/
|
|
249
|
+
getSpecialistPerspective(specialist, topic) {
|
|
250
|
+
const specialistId = specialist.specialist_id;
|
|
251
|
+
if (specialistId.includes('performance') || specialistId.includes('debug')) {
|
|
252
|
+
return `From a performance optimization standpoint,`;
|
|
253
|
+
}
|
|
254
|
+
else if (specialistId.includes('security')) {
|
|
255
|
+
return `From a security perspective,`;
|
|
256
|
+
}
|
|
257
|
+
else if (specialistId.includes('architect')) {
|
|
258
|
+
return `From an architectural design perspective,`;
|
|
259
|
+
}
|
|
260
|
+
else if (specialistId.includes('test')) {
|
|
261
|
+
return `From a testing and quality standpoint,`;
|
|
262
|
+
}
|
|
263
|
+
else if (specialistId.includes('mentor') || specialistId.includes('docs')) {
|
|
264
|
+
return `Let me explain this step by step:`;
|
|
265
|
+
}
|
|
266
|
+
return `Based on my expertise in ${specialist.expertise.primary[0]},`;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Extract key guidance points from topic content
|
|
270
|
+
*/
|
|
271
|
+
extractKeyGuidancePoints(topic) {
|
|
272
|
+
const content = topic.content;
|
|
273
|
+
// Look for key implementation patterns
|
|
274
|
+
if (content.includes('## Implementation') || content.includes('## How to')) {
|
|
275
|
+
return `the key implementation approach focuses on ${this.extractImplementationFocus(content)}`;
|
|
276
|
+
}
|
|
277
|
+
// Look for best practices
|
|
278
|
+
if (content.includes('## Best Practices') || content.includes('### Best Practices')) {
|
|
279
|
+
return `the best practices emphasize ${this.extractBestPractices(content)}`;
|
|
280
|
+
}
|
|
281
|
+
// Look for common pitfalls
|
|
282
|
+
if (content.includes('## Common Pitfalls') || content.includes('### Pitfalls')) {
|
|
283
|
+
return `it's important to avoid ${this.extractPitfalls(content)}`;
|
|
284
|
+
}
|
|
285
|
+
// Default to title-based guidance
|
|
286
|
+
return `this pattern provides essential guidance for ${topic.title.toLowerCase()}`;
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Extract implementation focus from content
|
|
290
|
+
*/
|
|
291
|
+
extractImplementationFocus(content) {
|
|
292
|
+
// Find implementation section and extract first few points
|
|
293
|
+
const lines = content.split('\n');
|
|
294
|
+
const implIndex = lines.findIndex(line => line.includes('## Implementation') || line.includes('## How to'));
|
|
295
|
+
if (implIndex >= 0 && implIndex < lines.length - 1) {
|
|
296
|
+
const nextFewLines = lines.slice(implIndex + 1, implIndex + 4)
|
|
297
|
+
.filter(line => line.trim() && !line.startsWith('#'))
|
|
298
|
+
.join(' ');
|
|
299
|
+
return this.summarizeIntoPhrase(nextFewLines);
|
|
300
|
+
}
|
|
301
|
+
return 'proper implementation patterns';
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Extract best practices from content
|
|
305
|
+
*/
|
|
306
|
+
extractBestPractices(content) {
|
|
307
|
+
const lines = content.split('\n');
|
|
308
|
+
const practicesIndex = lines.findIndex(line => line.includes('Best Practices'));
|
|
309
|
+
if (practicesIndex >= 0 && practicesIndex < lines.length - 1) {
|
|
310
|
+
const nextFewLines = lines.slice(practicesIndex + 1, practicesIndex + 3)
|
|
311
|
+
.filter(line => line.trim() && !line.startsWith('#'))
|
|
312
|
+
.join(' ');
|
|
313
|
+
return this.summarizeIntoPhrase(nextFewLines);
|
|
314
|
+
}
|
|
315
|
+
return 'following established patterns and maintaining code quality';
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Extract pitfalls from content
|
|
319
|
+
*/
|
|
320
|
+
extractPitfalls(content) {
|
|
321
|
+
const lines = content.split('\n');
|
|
322
|
+
const pitfallsIndex = lines.findIndex(line => line.includes('Pitfalls') || line.includes('Common Issues'));
|
|
323
|
+
if (pitfallsIndex >= 0 && pitfallsIndex < lines.length - 1) {
|
|
324
|
+
const nextFewLines = lines.slice(pitfallsIndex + 1, pitfallsIndex + 3)
|
|
325
|
+
.filter(line => line.trim() && !line.startsWith('#'))
|
|
326
|
+
.join(' ');
|
|
327
|
+
return this.summarizeIntoPhrase(nextFewLines);
|
|
328
|
+
}
|
|
329
|
+
return 'common implementation mistakes';
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Summarize content into a concise phrase
|
|
333
|
+
*/
|
|
334
|
+
summarizeIntoPhrase(text) {
|
|
335
|
+
// Clean up the text and create a concise summary
|
|
336
|
+
const cleaned = text
|
|
337
|
+
.replace(/[*#-]/g, '')
|
|
338
|
+
.replace(/\s+/g, ' ')
|
|
339
|
+
.trim();
|
|
340
|
+
// Take first sentence or first 60 characters
|
|
341
|
+
const firstSentence = cleaned.split('.')[0];
|
|
342
|
+
const truncated = firstSentence.length > 60
|
|
343
|
+
? firstSentence.substring(0, 60) + '...'
|
|
344
|
+
: firstSentence;
|
|
345
|
+
return truncated.toLowerCase();
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Generate general guidance when no specific topics match
|
|
349
|
+
*/
|
|
350
|
+
generateGeneralGuidance(specialist, userMessage) {
|
|
351
|
+
return `I'd suggest we start by understanding the specific requirements and then I can point you toward the right specialist or resources that would be most helpful.`;
|
|
352
|
+
}
|
|
353
|
+
// Additional helper methods...
|
|
354
|
+
initializeResponseTemplates() {
|
|
355
|
+
// Initialize with basic templates - these could be loaded from configuration
|
|
356
|
+
this.responseTemplates.set('performance', [
|
|
357
|
+
{
|
|
358
|
+
trigger_keywords: ['slow', 'performance', 'optimize', 'speed'],
|
|
359
|
+
specialist_types: ['dean-debug'],
|
|
360
|
+
template_pattern: "🔧 Dean here! Performance issues are my specialty. {problem_analysis} {solution_approach} {next_steps}",
|
|
361
|
+
personality_emphasis: ['technical', 'systematic', 'thorough'],
|
|
362
|
+
knowledge_domains: ['performance', 'optimization']
|
|
363
|
+
}
|
|
364
|
+
]);
|
|
365
|
+
}
|
|
366
|
+
getResponseTemplates(specialistId) {
|
|
367
|
+
// Return templates relevant to this specialist
|
|
368
|
+
return Array.from(this.responseTemplates.values()).flat()
|
|
369
|
+
.filter(template => template.specialist_types.includes(specialistId));
|
|
370
|
+
}
|
|
371
|
+
selectBestTemplate(templates, userMessage, relevantTopics) {
|
|
372
|
+
// Simple keyword matching for now
|
|
373
|
+
const messageLower = userMessage.toLowerCase();
|
|
374
|
+
for (const template of templates) {
|
|
375
|
+
if (template.trigger_keywords.some(keyword => messageLower.includes(keyword))) {
|
|
376
|
+
return template;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
return null;
|
|
380
|
+
}
|
|
381
|
+
fillTemplate(template, specialist, userMessage, relevantTopics, context) {
|
|
382
|
+
// Basic template filling - would be more sophisticated in practice
|
|
383
|
+
let content = template.template_pattern;
|
|
384
|
+
content = content.replace('{problem_analysis}', 'Let me analyze this issue systematically.');
|
|
385
|
+
content = content.replace('{solution_approach}', 'Here\'s how I\'d approach solving this:');
|
|
386
|
+
content = content.replace('{next_steps}', 'Next steps would be to examine the specific implementation details.');
|
|
387
|
+
return content;
|
|
388
|
+
}
|
|
389
|
+
extractProblemApproach(specialist) {
|
|
390
|
+
// Extract problem-solving approach from specialist definition
|
|
391
|
+
return specialist.persona.communication_style;
|
|
392
|
+
}
|
|
393
|
+
extractCollaborationStyle(specialist) {
|
|
394
|
+
// Extract collaboration preferences
|
|
395
|
+
return specialist.collaboration?.natural_handoffs?.length > 0 ? 'collaborative' : 'independent';
|
|
396
|
+
}
|
|
397
|
+
extractCharacteristicPhrases(specialist) {
|
|
398
|
+
// Extract characteristic phrases from the content
|
|
399
|
+
return []; // Would parse from the specialist's content
|
|
400
|
+
}
|
|
401
|
+
buildGreeting(specialist, personality, context) {
|
|
402
|
+
let greeting = specialist.persona.greeting;
|
|
403
|
+
if (context?.problem) {
|
|
404
|
+
greeting += ` I understand you're working on ${context.problem}. `;
|
|
405
|
+
}
|
|
406
|
+
greeting += ` I'm here to help with ${specialist.expertise.primary.join(', ')}. What specific challenge are you facing?`;
|
|
407
|
+
return greeting;
|
|
408
|
+
}
|
|
409
|
+
buildHandoffFarewell(fromSpecialist, toSpecialist, context) {
|
|
410
|
+
return `I think ${toSpecialist.persona.greeting.replace('!', '')} would be perfect for this! They're our expert in ${toSpecialist.expertise.primary.join(' and ')}. Let me hand you over to them.`;
|
|
411
|
+
}
|
|
412
|
+
buildHandoffIntroduction(toSpecialist, fromSpecialist, context) {
|
|
413
|
+
return `${toSpecialist.persona.greeting} ${fromSpecialist.specialist_id.split('-')[0]} filled me in on what you're working on. I'm excited to help with ${toSpecialist.expertise.primary[0]}! Let's dive in.`;
|
|
414
|
+
}
|
|
415
|
+
async calculateSpecialistConfidence(userMessage, specialist, context) {
|
|
416
|
+
const messageLower = userMessage.toLowerCase();
|
|
417
|
+
let confidence = 0;
|
|
418
|
+
// Check against primary expertise
|
|
419
|
+
for (const expertise of specialist.expertise.primary) {
|
|
420
|
+
if (messageLower.includes(expertise.toLowerCase().replace('-', ' '))) {
|
|
421
|
+
confidence += 0.3;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
// Check against secondary expertise
|
|
425
|
+
for (const expertise of specialist.expertise.secondary) {
|
|
426
|
+
if (messageLower.includes(expertise.toLowerCase().replace('-', ' '))) {
|
|
427
|
+
confidence += 0.2;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
// Check against domains
|
|
431
|
+
for (const domain of specialist.domains) {
|
|
432
|
+
if (messageLower.includes(domain.toLowerCase().replace('-', ' '))) {
|
|
433
|
+
confidence += 0.1;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
return Math.min(confidence, 1.0);
|
|
437
|
+
}
|
|
438
|
+
generateSuggestionReasoning(userMessage, specialist, confidence) {
|
|
439
|
+
return `${specialist.specialist_id} specializes in ${specialist.expertise.primary.join(', ')} which aligns with your question about ${userMessage.substring(0, 50)}...`;
|
|
440
|
+
}
|
|
441
|
+
generateContextUpdates(context, relevantTopics) {
|
|
442
|
+
return {
|
|
443
|
+
// Add discovered topics to context
|
|
444
|
+
// Update problem understanding
|
|
445
|
+
// Track user preferences
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
async suggestCollaborations(context, relevantTopics) {
|
|
449
|
+
const suggestions = [];
|
|
450
|
+
// Check if other specialists might be helpful
|
|
451
|
+
const { specialist } = context;
|
|
452
|
+
if (specialist.collaboration?.natural_handoffs) {
|
|
453
|
+
for (const handoffId of specialist.collaboration.natural_handoffs) {
|
|
454
|
+
suggestions.push({
|
|
455
|
+
specialist_id: handoffId,
|
|
456
|
+
reason: `Natural collaboration partner for ${specialist.expertise.primary[0]}`
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
return suggestions.slice(0, 2); // Limit suggestions
|
|
461
|
+
}
|
|
462
|
+
getApplicationContext(topic, userMessage) {
|
|
463
|
+
const messageWords = userMessage.toLowerCase().split(' ');
|
|
464
|
+
const topicTags = topic.frontmatter.tags || [];
|
|
465
|
+
// Identify context based on user message and topic
|
|
466
|
+
let context = `Applied ${topic.title} to address`;
|
|
467
|
+
if (messageWords.some(word => ['performance', 'slow', 'optimize', 'speed'].includes(word))) {
|
|
468
|
+
context += ` performance concerns in ${this.extractEntityFromMessage(userMessage)}`;
|
|
469
|
+
}
|
|
470
|
+
else if (messageWords.some(word => ['security', 'permission', 'access'].includes(word))) {
|
|
471
|
+
context += ` security requirements for ${this.extractEntityFromMessage(userMessage)}`;
|
|
472
|
+
}
|
|
473
|
+
else if (messageWords.some(word => ['integration', 'api', 'connect'].includes(word))) {
|
|
474
|
+
context += ` integration challenges with ${this.extractEntityFromMessage(userMessage)}`;
|
|
475
|
+
}
|
|
476
|
+
else if (messageWords.some(word => ['test', 'testing', 'validation'].includes(word))) {
|
|
477
|
+
context += ` testing strategy for ${this.extractEntityFromMessage(userMessage)}`;
|
|
478
|
+
}
|
|
479
|
+
else {
|
|
480
|
+
context += ` the development challenge in ${userMessage.substring(0, 50)}...`;
|
|
481
|
+
}
|
|
482
|
+
// Add BC version context if available
|
|
483
|
+
if (topic.frontmatter.bc_versions) {
|
|
484
|
+
context += ` (BC ${topic.frontmatter.bc_versions} compatible)`;
|
|
485
|
+
}
|
|
486
|
+
return context;
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* Extract business entity or object from user message
|
|
490
|
+
*/
|
|
491
|
+
extractEntityFromMessage(message) {
|
|
492
|
+
const commonEntities = [
|
|
493
|
+
'table', 'page', 'report', 'codeunit', 'api', 'service',
|
|
494
|
+
'customer', 'vendor', 'item', 'purchase', 'sales', 'inventory'
|
|
495
|
+
];
|
|
496
|
+
const messageLower = message.toLowerCase();
|
|
497
|
+
for (const entity of commonEntities) {
|
|
498
|
+
if (messageLower.includes(entity)) {
|
|
499
|
+
return entity;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
return 'your BC implementation';
|
|
503
|
+
}
|
|
504
|
+
generateRecommendations(topics, userMessage) {
|
|
505
|
+
const recommendations = [];
|
|
506
|
+
for (const topic of topics.slice(0, 3)) {
|
|
507
|
+
// Create actionable recommendations based on the topic
|
|
508
|
+
if (topic.frontmatter.bc_versions) {
|
|
509
|
+
recommendations.push(`Apply **${topic.title}** patterns (compatible with ${topic.frontmatter.bc_versions})`);
|
|
510
|
+
}
|
|
511
|
+
else {
|
|
512
|
+
recommendations.push(`Consider implementing **${topic.title}** best practices`);
|
|
513
|
+
}
|
|
514
|
+
// Add specific action based on topic type
|
|
515
|
+
if (topic.frontmatter.tags?.includes('performance')) {
|
|
516
|
+
recommendations.push(`Measure performance impact of ${topic.title.toLowerCase()} implementation`);
|
|
517
|
+
}
|
|
518
|
+
else if (topic.frontmatter.tags?.includes('security')) {
|
|
519
|
+
recommendations.push(`Review security implications when applying ${topic.title.toLowerCase()}`);
|
|
520
|
+
}
|
|
521
|
+
else if (topic.frontmatter.tags?.includes('testing')) {
|
|
522
|
+
recommendations.push(`Create test cases to validate ${topic.title.toLowerCase()} implementation`);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
return recommendations.slice(0, 4); // Limit to 4 recommendations
|
|
526
|
+
}
|
|
527
|
+
determineResponseType(userMessage, topics) {
|
|
528
|
+
const messageLower = userMessage.toLowerCase();
|
|
529
|
+
if (messageLower.includes('how') || messageLower.includes('help')) {
|
|
530
|
+
return 'guidance';
|
|
531
|
+
}
|
|
532
|
+
else if (messageLower.includes('fix') || messageLower.includes('solve')) {
|
|
533
|
+
return 'solution';
|
|
534
|
+
}
|
|
535
|
+
else if (messageLower.includes('?')) {
|
|
536
|
+
return 'question';
|
|
537
|
+
}
|
|
538
|
+
return 'guidance';
|
|
539
|
+
}
|
|
540
|
+
calculateConfidenceLevel(specialist, userMessage, topics) {
|
|
541
|
+
if (topics.length >= 2)
|
|
542
|
+
return 'high';
|
|
543
|
+
if (topics.length === 1)
|
|
544
|
+
return 'medium';
|
|
545
|
+
return 'low';
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
/**
|
|
549
|
+
* Knowledge retriever implementation for BC topics
|
|
550
|
+
*/
|
|
551
|
+
class BCKnowledgeRetriever {
|
|
552
|
+
layerService;
|
|
553
|
+
knowledgeService;
|
|
554
|
+
constructor(layerService, knowledgeService) {
|
|
555
|
+
this.layerService = layerService;
|
|
556
|
+
this.knowledgeService = knowledgeService;
|
|
557
|
+
}
|
|
558
|
+
async findRelevantTopics(userMessage, specialistExpertise, limit = 5) {
|
|
559
|
+
try {
|
|
560
|
+
// Convert specialist expertise to broader search terms that match topic content
|
|
561
|
+
const broadSearchTerms = specialistExpertise.map(exp => {
|
|
562
|
+
// Map specific expertise terms to broader, more searchable terms
|
|
563
|
+
const mappings = {
|
|
564
|
+
'performance-analysis': 'performance',
|
|
565
|
+
'error-diagnosis': 'error',
|
|
566
|
+
'system-monitoring': 'monitoring',
|
|
567
|
+
'optimization-implementation': 'optimization',
|
|
568
|
+
'query-optimization': 'query performance',
|
|
569
|
+
'memory-management': 'memory',
|
|
570
|
+
'integration-performance': 'integration',
|
|
571
|
+
'user-experience-optimization': 'user experience'
|
|
572
|
+
};
|
|
573
|
+
return mappings[exp] || exp.replace('-', ' ');
|
|
574
|
+
});
|
|
575
|
+
// Search for topics using the user's message in code_context field
|
|
576
|
+
const searchParams = {
|
|
577
|
+
code_context: `${userMessage} ${broadSearchTerms.join(' ')}`, // Combine user message with expertise terms
|
|
578
|
+
limit,
|
|
579
|
+
bc_version: 'BC22' // Default - could be made configurable
|
|
580
|
+
};
|
|
581
|
+
// Use the existing knowledge service to find relevant topics
|
|
582
|
+
const searchResults = await this.knowledgeService.searchTopics(searchParams);
|
|
583
|
+
// Get full topic details for each search result
|
|
584
|
+
if (searchResults && Array.isArray(searchResults)) {
|
|
585
|
+
const topics = [];
|
|
586
|
+
for (const result of searchResults.slice(0, limit)) {
|
|
587
|
+
const topic = await this.knowledgeService.getTopic(result.id);
|
|
588
|
+
if (topic) {
|
|
589
|
+
topics.push(topic);
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
return topics;
|
|
593
|
+
}
|
|
594
|
+
return [];
|
|
595
|
+
}
|
|
596
|
+
catch (error) {
|
|
597
|
+
console.error('Error finding relevant topics:', error);
|
|
598
|
+
return [];
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
async getRelatedTopics(topicId, limit = 3) {
|
|
602
|
+
try {
|
|
603
|
+
// Get the main topic first
|
|
604
|
+
const mainTopic = await this.knowledgeService.getTopic(topicId);
|
|
605
|
+
if (!mainTopic) {
|
|
606
|
+
return [];
|
|
607
|
+
}
|
|
608
|
+
// Use domain-based search to find related topics
|
|
609
|
+
const searchParams = {
|
|
610
|
+
query: mainTopic.frontmatter.domain,
|
|
611
|
+
search_type: 'fuzzy',
|
|
612
|
+
limit: limit + 1, // Get one extra to exclude the main topic
|
|
613
|
+
bc_version: 'BC22',
|
|
614
|
+
domains: [mainTopic.frontmatter.domain]
|
|
615
|
+
};
|
|
616
|
+
const searchResults = await this.knowledgeService.searchTopics(searchParams);
|
|
617
|
+
const relatedTopics = [];
|
|
618
|
+
for (const result of searchResults) {
|
|
619
|
+
if (result.id !== topicId && relatedTopics.length < limit) {
|
|
620
|
+
const topic = await this.knowledgeService.getTopic(result.id);
|
|
621
|
+
if (topic) {
|
|
622
|
+
relatedTopics.push(topic);
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
return relatedTopics;
|
|
627
|
+
}
|
|
628
|
+
catch (error) {
|
|
629
|
+
console.error('Error getting related topics:', error);
|
|
630
|
+
return [];
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
async searchSolutions(problemDescription, domains, limit = 5) {
|
|
634
|
+
try {
|
|
635
|
+
// Search for solution-oriented topics in the specified domains
|
|
636
|
+
const searchParams = {
|
|
637
|
+
query: `${problemDescription} solution implementation fix pattern`,
|
|
638
|
+
search_type: 'hybrid',
|
|
639
|
+
limit: limit * 2, // Get more results to filter
|
|
640
|
+
bc_version: 'BC22',
|
|
641
|
+
domains
|
|
642
|
+
};
|
|
643
|
+
const searchResults = await this.knowledgeService.searchTopics(searchParams);
|
|
644
|
+
const solutionTopics = [];
|
|
645
|
+
for (const result of searchResults) {
|
|
646
|
+
if (solutionTopics.length >= limit)
|
|
647
|
+
break;
|
|
648
|
+
const topic = await this.knowledgeService.getTopic(result.id);
|
|
649
|
+
if (topic) {
|
|
650
|
+
// Filter for topics that are more solution-oriented
|
|
651
|
+
const content = topic.content.toLowerCase();
|
|
652
|
+
const title = topic.title.toLowerCase();
|
|
653
|
+
if (content.includes('solution') ||
|
|
654
|
+
content.includes('implementation') ||
|
|
655
|
+
content.includes('fix') ||
|
|
656
|
+
content.includes('pattern') ||
|
|
657
|
+
title.includes('pattern') ||
|
|
658
|
+
title.includes('optimization') ||
|
|
659
|
+
title.includes('best practice')) {
|
|
660
|
+
solutionTopics.push(topic);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
return solutionTopics;
|
|
665
|
+
}
|
|
666
|
+
catch (error) {
|
|
667
|
+
console.error('Error searching solutions:', error);
|
|
668
|
+
return [];
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
//# sourceMappingURL=roleplay-engine.js.map
|