archicore 0.1.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 +530 -0
- package/dist/analyzers/dead-code.d.ts +95 -0
- package/dist/analyzers/dead-code.js +327 -0
- package/dist/analyzers/duplication.d.ts +90 -0
- package/dist/analyzers/duplication.js +344 -0
- package/dist/analyzers/security.d.ts +79 -0
- package/dist/analyzers/security.js +484 -0
- package/dist/architecture/index.d.ts +35 -0
- package/dist/architecture/index.js +249 -0
- package/dist/cli/commands/analyzers.d.ts +6 -0
- package/dist/cli/commands/analyzers.js +431 -0
- package/dist/cli/commands/export.d.ts +6 -0
- package/dist/cli/commands/export.js +78 -0
- package/dist/cli/commands/index.d.ts +8 -0
- package/dist/cli/commands/index.js +8 -0
- package/dist/cli/commands/init.d.ts +26 -0
- package/dist/cli/commands/init.js +140 -0
- package/dist/cli/commands/interactive.d.ts +7 -0
- package/dist/cli/commands/interactive.js +522 -0
- package/dist/cli/commands/projects.d.ts +6 -0
- package/dist/cli/commands/projects.js +249 -0
- package/dist/cli/index.d.ts +7 -0
- package/dist/cli/index.js +7 -0
- package/dist/cli/ui/box.d.ts +17 -0
- package/dist/cli/ui/box.js +62 -0
- package/dist/cli/ui/colors.d.ts +49 -0
- package/dist/cli/ui/colors.js +86 -0
- package/dist/cli/ui/index.d.ts +9 -0
- package/dist/cli/ui/index.js +9 -0
- package/dist/cli/ui/prompt.d.ts +34 -0
- package/dist/cli/ui/prompt.js +122 -0
- package/dist/cli/ui/spinner.d.ts +29 -0
- package/dist/cli/ui/spinner.js +80 -0
- package/dist/cli/ui/table.d.ts +33 -0
- package/dist/cli/ui/table.js +84 -0
- package/dist/cli/utils/config.d.ts +23 -0
- package/dist/cli/utils/config.js +73 -0
- package/dist/cli/utils/index.d.ts +6 -0
- package/dist/cli/utils/index.js +6 -0
- package/dist/cli/utils/session.d.ts +27 -0
- package/dist/cli/utils/session.js +117 -0
- package/dist/cli.d.ts +8 -0
- package/dist/cli.js +295 -0
- package/dist/code-index/ast-parser.d.ts +16 -0
- package/dist/code-index/ast-parser.js +330 -0
- package/dist/code-index/dependency-graph.d.ts +16 -0
- package/dist/code-index/dependency-graph.js +161 -0
- package/dist/code-index/index.d.ts +44 -0
- package/dist/code-index/index.js +124 -0
- package/dist/code-index/symbol-extractor.d.ts +13 -0
- package/dist/code-index/symbol-extractor.js +150 -0
- package/dist/export/index.d.ts +92 -0
- package/dist/export/index.js +676 -0
- package/dist/github/github-service.d.ts +146 -0
- package/dist/github/github-service.js +609 -0
- package/dist/impact-engine/index.d.ts +25 -0
- package/dist/impact-engine/index.js +284 -0
- package/dist/index.d.ts +60 -0
- package/dist/index.js +149 -0
- package/dist/metrics/index.d.ts +136 -0
- package/dist/metrics/index.js +525 -0
- package/dist/orchestrator/deepseek-optimizer.d.ts +67 -0
- package/dist/orchestrator/deepseek-optimizer.js +320 -0
- package/dist/orchestrator/index.d.ts +34 -0
- package/dist/orchestrator/index.js +305 -0
- package/dist/pr-guardian/index.d.ts +143 -0
- package/dist/pr-guardian/index.js +553 -0
- package/dist/refactoring/index.d.ts +108 -0
- package/dist/refactoring/index.js +580 -0
- package/dist/rules-engine/index.d.ts +129 -0
- package/dist/rules-engine/index.js +482 -0
- package/dist/semantic-memory/embedding-service.d.ts +24 -0
- package/dist/semantic-memory/embedding-service.js +120 -0
- package/dist/semantic-memory/index.d.ts +45 -0
- package/dist/semantic-memory/index.js +206 -0
- package/dist/semantic-memory/vector-store.d.ts +27 -0
- package/dist/semantic-memory/vector-store.js +166 -0
- package/dist/server/index.d.ts +28 -0
- package/dist/server/index.js +141 -0
- package/dist/server/middleware/api-auth.d.ts +43 -0
- package/dist/server/middleware/api-auth.js +256 -0
- package/dist/server/routes/admin.d.ts +5 -0
- package/dist/server/routes/admin.js +123 -0
- package/dist/server/routes/api.d.ts +7 -0
- package/dist/server/routes/api.js +362 -0
- package/dist/server/routes/auth.d.ts +16 -0
- package/dist/server/routes/auth.js +191 -0
- package/dist/server/routes/developer.d.ts +8 -0
- package/dist/server/routes/developer.js +439 -0
- package/dist/server/routes/github.d.ts +7 -0
- package/dist/server/routes/github.js +495 -0
- package/dist/server/routes/upload.d.ts +7 -0
- package/dist/server/routes/upload.js +196 -0
- package/dist/server/services/api-key-service.d.ts +81 -0
- package/dist/server/services/api-key-service.js +281 -0
- package/dist/server/services/auth-service.d.ts +40 -0
- package/dist/server/services/auth-service.js +315 -0
- package/dist/server/services/project-service.d.ts +123 -0
- package/dist/server/services/project-service.js +533 -0
- package/dist/server/services/token-service.d.ts +107 -0
- package/dist/server/services/token-service.js +416 -0
- package/dist/server/services/upload-service.d.ts +93 -0
- package/dist/server/services/upload-service.js +464 -0
- package/dist/types/api.d.ts +188 -0
- package/dist/types/api.js +86 -0
- package/dist/types/github.d.ts +335 -0
- package/dist/types/github.js +5 -0
- package/dist/types/index.d.ts +265 -0
- package/dist/types/index.js +32 -0
- package/dist/types/user.d.ts +69 -0
- package/dist/types/user.js +42 -0
- package/dist/utils/file-utils.d.ts +20 -0
- package/dist/utils/file-utils.js +163 -0
- package/dist/utils/logger.d.ts +17 -0
- package/dist/utils/logger.js +41 -0
- package/dist/watcher/index.d.ts +125 -0
- package/dist/watcher/index.js +397 -0
- package/package.json +71 -0
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DeepSeek Optimizer
|
|
3
|
+
*
|
|
4
|
+
* Оптимизирует промпты и контекст специально для DeepSeek,
|
|
5
|
+
* чтобы минимизировать ошибки и получать точные ответы.
|
|
6
|
+
*/
|
|
7
|
+
import { Logger } from '../utils/logger.js';
|
|
8
|
+
export class DeepSeekOptimizer {
|
|
9
|
+
config;
|
|
10
|
+
constructor(config) {
|
|
11
|
+
this.config = {
|
|
12
|
+
maxContextLength: 8000, // DeepSeek лучше работает с коротким контекстом
|
|
13
|
+
simplifyPrompts: true,
|
|
14
|
+
useEnglish: true, // DeepSeek лучше понимает английский
|
|
15
|
+
reduceExamples: true,
|
|
16
|
+
structuredOutput: true,
|
|
17
|
+
...config
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Оптимизирует промпт для DeepSeek
|
|
22
|
+
*/
|
|
23
|
+
optimizePrompt(prompt) {
|
|
24
|
+
Logger.debug('Optimizing prompt for DeepSeek...');
|
|
25
|
+
let optimizedSystem = prompt.system;
|
|
26
|
+
let optimizedUser = prompt.user;
|
|
27
|
+
// 1. Упрощаем системный промпт
|
|
28
|
+
if (this.config.simplifyPrompts) {
|
|
29
|
+
optimizedSystem = this.simplifySystemPrompt(prompt.system);
|
|
30
|
+
}
|
|
31
|
+
// 2. Сокращаем контекст
|
|
32
|
+
if (prompt.context) {
|
|
33
|
+
optimizedSystem = this.reduceContext(optimizedSystem, prompt.context);
|
|
34
|
+
}
|
|
35
|
+
// 3. Упрощаем пользовательский запрос
|
|
36
|
+
if (this.config.simplifyPrompts) {
|
|
37
|
+
optimizedUser = this.simplifyUserPrompt(prompt.user);
|
|
38
|
+
}
|
|
39
|
+
// 4. Добавляем требование структурированного вывода
|
|
40
|
+
if (this.config.structuredOutput) {
|
|
41
|
+
optimizedUser = this.addStructuredOutputRequest(optimizedUser);
|
|
42
|
+
}
|
|
43
|
+
// 5. Переводим на английский (если нужно)
|
|
44
|
+
if (this.config.useEnglish) {
|
|
45
|
+
optimizedSystem = this.translateToEnglish(optimizedSystem);
|
|
46
|
+
optimizedUser = this.translateToEnglish(optimizedUser);
|
|
47
|
+
}
|
|
48
|
+
// 6. Обрезаем до максимальной длины
|
|
49
|
+
optimizedSystem = this.truncateText(optimizedSystem, this.config.maxContextLength);
|
|
50
|
+
optimizedUser = this.truncateText(optimizedUser, this.config.maxContextLength);
|
|
51
|
+
Logger.debug(`Prompt optimized: ${prompt.system.length + prompt.user.length} -> ${optimizedSystem.length + optimizedUser.length} chars`);
|
|
52
|
+
return {
|
|
53
|
+
system: optimizedSystem,
|
|
54
|
+
user: optimizedUser,
|
|
55
|
+
context: prompt.context
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Упрощает системный промпт
|
|
60
|
+
*/
|
|
61
|
+
simplifySystemPrompt(prompt) {
|
|
62
|
+
let simplified = prompt;
|
|
63
|
+
// Убираем избыточные формулировки
|
|
64
|
+
simplified = simplified
|
|
65
|
+
.replace(/с глубокими знаниями/g, 'with knowledge')
|
|
66
|
+
.replace(/Вы являетесь/g, 'You are')
|
|
67
|
+
.replace(/должны/g, 'should')
|
|
68
|
+
.replace(/необходимо/g, 'need to');
|
|
69
|
+
// Сокращаем длинные списки правил
|
|
70
|
+
const lines = simplified.split('\n');
|
|
71
|
+
const importantLines = lines.filter(line => {
|
|
72
|
+
// Оставляем только важные строки
|
|
73
|
+
return (line.includes('You are') ||
|
|
74
|
+
line.includes('Your role') ||
|
|
75
|
+
line.includes('Important') ||
|
|
76
|
+
line.includes('Rules') ||
|
|
77
|
+
line.includes('Bounded Context') ||
|
|
78
|
+
line.trim().startsWith('-'));
|
|
79
|
+
});
|
|
80
|
+
return importantLines.join('\n');
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Упрощает пользовательский промпт
|
|
84
|
+
*/
|
|
85
|
+
simplifyUserPrompt(prompt) {
|
|
86
|
+
let simplified = prompt;
|
|
87
|
+
// Убираем эмодзи (DeepSeek может путаться)
|
|
88
|
+
simplified = simplified.replace(/[\u{1F300}-\u{1F9FF}]/gu, '');
|
|
89
|
+
// Убираем markdown форматирование, которое может сбивать
|
|
90
|
+
simplified = simplified
|
|
91
|
+
.replace(/\*\*\*([^*]+)\*\*\*/g, '$1') // *** text ***
|
|
92
|
+
.replace(/\*\*([^*]+)\*\*/g, '$1'); // ** text **
|
|
93
|
+
// Упрощаем структуру
|
|
94
|
+
simplified = simplified
|
|
95
|
+
.replace(/Пожалуйста, предоставьте:/g, 'Provide:')
|
|
96
|
+
.replace(/Пожалуйста/g, 'Please')
|
|
97
|
+
.replace(/Необходимо/g, 'Need');
|
|
98
|
+
return simplified;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Сокращает контекст до самого важного
|
|
102
|
+
*/
|
|
103
|
+
reduceContext(systemPrompt, context) {
|
|
104
|
+
let reduced = systemPrompt;
|
|
105
|
+
// Сокращаем semantic memory до 3 самых релевантных
|
|
106
|
+
if (context.semanticMemory && context.semanticMemory.length > 3) {
|
|
107
|
+
const topResults = context.semanticMemory.slice(0, 3);
|
|
108
|
+
reduced += '\n\n**Relevant Code (top 3):**\n';
|
|
109
|
+
for (const result of topResults) {
|
|
110
|
+
// Берем только путь к файлу и короткий контекст
|
|
111
|
+
const shortContext = result.context.substring(0, 150);
|
|
112
|
+
reduced += `- ${result.chunk.metadata.filePath}: ${shortContext}...\n`;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// Сокращаем информацию об архитектуре
|
|
116
|
+
if (context.architecture?.boundedContexts) {
|
|
117
|
+
reduced += '\n\n**Architecture:**\n';
|
|
118
|
+
for (const bc of context.architecture.boundedContexts.slice(0, 3)) {
|
|
119
|
+
reduced += `- ${bc.name}: ${bc.description}\n`;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return reduced;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Добавляет требование структурированного вывода
|
|
126
|
+
*/
|
|
127
|
+
addStructuredOutputRequest(userPrompt) {
|
|
128
|
+
// Добавляем четкое требование к формату ответа
|
|
129
|
+
return userPrompt + '\n\n**Output Format:**\nProvide a clear, structured response. Use numbered lists. Be specific and concise.';
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Упрощенный перевод ключевых терминов на английский
|
|
133
|
+
*/
|
|
134
|
+
translateToEnglish(text) {
|
|
135
|
+
// Базовый словарь для перевода
|
|
136
|
+
const translations = {
|
|
137
|
+
'Вы': 'You',
|
|
138
|
+
'являетесь': 'are',
|
|
139
|
+
'архитектором': 'architect',
|
|
140
|
+
'системным': 'system',
|
|
141
|
+
'программного обеспечения': 'software',
|
|
142
|
+
'Ваша роль': 'Your role',
|
|
143
|
+
'Понимать': 'Understand',
|
|
144
|
+
'весь код': 'entire codebase',
|
|
145
|
+
'структуру кодовой базы': 'codebase structure',
|
|
146
|
+
'Принимать': 'Make',
|
|
147
|
+
'архитектурные решения': 'architectural decisions',
|
|
148
|
+
'на основе контекста': 'based on context',
|
|
149
|
+
'Определять': 'Identify',
|
|
150
|
+
'риски': 'risks',
|
|
151
|
+
'потенциальные проблемы': 'potential issues',
|
|
152
|
+
'Предлагать': 'Suggest',
|
|
153
|
+
'улучшения': 'improvements',
|
|
154
|
+
'сохраняя': 'maintaining',
|
|
155
|
+
'целостность системы': 'system integrity',
|
|
156
|
+
'Следовать': 'Follow',
|
|
157
|
+
'установленным': 'established',
|
|
158
|
+
'правилам': 'rules',
|
|
159
|
+
'паттернам': 'patterns',
|
|
160
|
+
'Принципы': 'Principles',
|
|
161
|
+
'Минимизировать': 'Minimize',
|
|
162
|
+
'breaking changes': 'breaking changes',
|
|
163
|
+
'Поддерживать': 'Maintain',
|
|
164
|
+
'обратную совместимость': 'backward compatibility',
|
|
165
|
+
'когда возможно': 'when possible',
|
|
166
|
+
'Предпочитать': 'Prefer',
|
|
167
|
+
'инкрементальные улучшения': 'incremental improvements',
|
|
168
|
+
'большим переписываниям': 'big rewrites',
|
|
169
|
+
'Учитывать': 'Consider',
|
|
170
|
+
'производительность': 'performance',
|
|
171
|
+
'безопасность': 'security',
|
|
172
|
+
'поддерживаемость': 'maintainability',
|
|
173
|
+
'Уважать': 'Respect',
|
|
174
|
+
'границы контекстов': 'bounded contexts',
|
|
175
|
+
'доменные границы': 'domain boundaries',
|
|
176
|
+
'Анализировать': 'Analyze',
|
|
177
|
+
'влияние изменений': 'impact of changes',
|
|
178
|
+
'Описание изменения': 'Change Description',
|
|
179
|
+
'Тип': 'Type',
|
|
180
|
+
'Файлы': 'Files',
|
|
181
|
+
'Затронутые компоненты': 'Affected Components',
|
|
182
|
+
'Критические': 'Critical',
|
|
183
|
+
'Высокие': 'High',
|
|
184
|
+
'Средние': 'Medium',
|
|
185
|
+
'Низкие': 'Low',
|
|
186
|
+
'Выявленные риски': 'Identified Risks',
|
|
187
|
+
'Текущие рекомендации': 'Current Recommendations',
|
|
188
|
+
'Предоставьте': 'Provide',
|
|
189
|
+
'Дополнительные риски или проблемы': 'Additional risks or concerns',
|
|
190
|
+
'Конкретные шаги миграции': 'Specific migration steps',
|
|
191
|
+
'при необходимости': 'if needed',
|
|
192
|
+
'Стратегия тестирования': 'Testing strategy',
|
|
193
|
+
'План отката': 'Rollback plan',
|
|
194
|
+
'Долгосрочные архитектурные последствия': 'Long-term architectural implications'
|
|
195
|
+
};
|
|
196
|
+
let translated = text;
|
|
197
|
+
// Если текст в основном на русском, переводим ключевые части
|
|
198
|
+
if (this.isMostlyRussian(text)) {
|
|
199
|
+
for (const [russian, english] of Object.entries(translations)) {
|
|
200
|
+
translated = translated.replace(new RegExp(russian, 'g'), english);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return translated;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Проверяет, в основном ли текст на русском
|
|
207
|
+
*/
|
|
208
|
+
isMostlyRussian(text) {
|
|
209
|
+
const russianChars = text.match(/[а-яА-ЯёЁ]/g);
|
|
210
|
+
const totalChars = text.replace(/\s/g, '').length;
|
|
211
|
+
return russianChars ? (russianChars.length / totalChars) > 0.3 : false;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Обрезает текст до максимальной длины
|
|
215
|
+
*/
|
|
216
|
+
truncateText(text, maxLength) {
|
|
217
|
+
if (text.length <= maxLength) {
|
|
218
|
+
return text;
|
|
219
|
+
}
|
|
220
|
+
// Обрезаем, но стараемся сохранить смысл
|
|
221
|
+
const truncated = text.substring(0, maxLength);
|
|
222
|
+
// Находим последнюю точку или перенос строки
|
|
223
|
+
const lastPeriod = truncated.lastIndexOf('.');
|
|
224
|
+
const lastNewline = truncated.lastIndexOf('\n');
|
|
225
|
+
const cutPoint = Math.max(lastPeriod, lastNewline);
|
|
226
|
+
if (cutPoint > maxLength * 0.8) {
|
|
227
|
+
return truncated.substring(0, cutPoint + 1);
|
|
228
|
+
}
|
|
229
|
+
return truncated + '...';
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Разбивает сложную задачу на простые подзадачи
|
|
233
|
+
*/
|
|
234
|
+
splitComplexTask(task) {
|
|
235
|
+
const subtasks = [];
|
|
236
|
+
// Определяем тип задачи
|
|
237
|
+
if (task.includes('analyze') || task.includes('анализ')) {
|
|
238
|
+
subtasks.push('Step 1: List all affected components');
|
|
239
|
+
subtasks.push('Step 2: Identify direct dependencies');
|
|
240
|
+
subtasks.push('Step 3: Assess risk level for each component');
|
|
241
|
+
subtasks.push('Step 4: Provide recommendations');
|
|
242
|
+
}
|
|
243
|
+
else if (task.includes('refactor') || task.includes('рефакторинг')) {
|
|
244
|
+
subtasks.push('Step 1: Identify code to refactor');
|
|
245
|
+
subtasks.push('Step 2: Propose refactoring approach');
|
|
246
|
+
subtasks.push('Step 3: List potential risks');
|
|
247
|
+
subtasks.push('Step 4: Define testing requirements');
|
|
248
|
+
}
|
|
249
|
+
else if (task.includes('review') || task.includes('ревью')) {
|
|
250
|
+
subtasks.push('Step 1: Check architecture compliance');
|
|
251
|
+
subtasks.push('Step 2: Find potential bugs');
|
|
252
|
+
subtasks.push('Step 3: Identify performance issues');
|
|
253
|
+
subtasks.push('Step 4: Suggest improvements');
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
// Общий подход
|
|
257
|
+
subtasks.push('Step 1: Understand the context');
|
|
258
|
+
subtasks.push('Step 2: Analyze the requirements');
|
|
259
|
+
subtasks.push('Step 3: Provide solution');
|
|
260
|
+
subtasks.push('Step 4: List considerations');
|
|
261
|
+
}
|
|
262
|
+
return subtasks;
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Валидирует и очищает ответ от DeepSeek
|
|
266
|
+
*/
|
|
267
|
+
validateAndCleanResponse(response) {
|
|
268
|
+
let cleaned = response;
|
|
269
|
+
// Убираем возможный мусор в начале/конце
|
|
270
|
+
cleaned = cleaned.trim();
|
|
271
|
+
// Убираем повторяющиеся переносы строк
|
|
272
|
+
cleaned = cleaned.replace(/\n{3,}/g, '\n\n');
|
|
273
|
+
// Убираем незавершенные предложения в конце
|
|
274
|
+
const lastChar = cleaned[cleaned.length - 1];
|
|
275
|
+
if (lastChar !== '.' && lastChar !== '!' && lastChar !== '?' && lastChar !== '\n') {
|
|
276
|
+
const lastCompleteSentence = cleaned.lastIndexOf('.');
|
|
277
|
+
if (lastCompleteSentence > cleaned.length * 0.8) {
|
|
278
|
+
cleaned = cleaned.substring(0, lastCompleteSentence + 1);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return cleaned;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Создает retry-стратегию с упрощением
|
|
285
|
+
*/
|
|
286
|
+
createRetryStrategy(originalPrompt, attemptNumber) {
|
|
287
|
+
Logger.info(`Creating retry strategy, attempt ${attemptNumber}`);
|
|
288
|
+
// С каждой попыткой упрощаем еще больше
|
|
289
|
+
const config = {
|
|
290
|
+
...this.config,
|
|
291
|
+
maxContextLength: this.config.maxContextLength / attemptNumber,
|
|
292
|
+
simplifyPrompts: true,
|
|
293
|
+
useEnglish: true
|
|
294
|
+
};
|
|
295
|
+
const optimizer = new DeepSeekOptimizer(config);
|
|
296
|
+
return optimizer.optimizePrompt(originalPrompt);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Создает оптимизированный промпт для простых задач DeepSeek
|
|
301
|
+
*/
|
|
302
|
+
export function createSimplePrompt(task, context) {
|
|
303
|
+
const systemPrompt = `You are a helpful AI assistant for code analysis.
|
|
304
|
+
|
|
305
|
+
Rules:
|
|
306
|
+
- Be concise and specific
|
|
307
|
+
- Use structured output
|
|
308
|
+
- Focus on facts, not speculation
|
|
309
|
+
- If unsure, say so
|
|
310
|
+
|
|
311
|
+
${context ? `Context:\n${context.substring(0, 500)}` : ''}`;
|
|
312
|
+
const userPrompt = `Task: ${task}
|
|
313
|
+
|
|
314
|
+
Provide a clear, structured response.`;
|
|
315
|
+
return {
|
|
316
|
+
system: systemPrompt,
|
|
317
|
+
user: userPrompt
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
//# sourceMappingURL=deepseek-optimizer.js.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM Orchestrator
|
|
3
|
+
*
|
|
4
|
+
* Оркестрация взаимодействия с LLM:
|
|
5
|
+
* - Управление контекстом
|
|
6
|
+
* - Генерация промптов с архитектурными знаниями
|
|
7
|
+
* - Интеграция с Claude/GPT
|
|
8
|
+
* - Принятие архитектурных решений
|
|
9
|
+
*/
|
|
10
|
+
import { LLMConfig, LLMPrompt, LLMContext, LLMResponse, ChangeImpact } from '../types/index.js';
|
|
11
|
+
export declare class LLMOrchestrator {
|
|
12
|
+
private anthropic?;
|
|
13
|
+
private openai?;
|
|
14
|
+
private config;
|
|
15
|
+
private deepseekOptimizer?;
|
|
16
|
+
private initialized;
|
|
17
|
+
private _isAvailable;
|
|
18
|
+
constructor(config: LLMConfig);
|
|
19
|
+
private ensureInitialized;
|
|
20
|
+
isAvailable(): boolean;
|
|
21
|
+
query(prompt: LLMPrompt, retryCount?: number): Promise<LLMResponse>;
|
|
22
|
+
analyzeImpact(impact: ChangeImpact, context?: LLMContext): Promise<string>;
|
|
23
|
+
suggestRefactoring(code: string, goal: string, context?: LLMContext): Promise<string>;
|
|
24
|
+
answerArchitecturalQuestion(question: string, context: LLMContext): Promise<string>;
|
|
25
|
+
generateDocumentation(codebase: string, context: LLMContext): Promise<string>;
|
|
26
|
+
reviewCode(code: string, changedFiles: string[], context: LLMContext): Promise<string>;
|
|
27
|
+
private queryAnthropic;
|
|
28
|
+
private queryOpenAI;
|
|
29
|
+
private buildImpactAnalysisPrompt;
|
|
30
|
+
private buildRefactoringPrompt;
|
|
31
|
+
private buildArchitecturalPrompt;
|
|
32
|
+
private buildSystemPrompt;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM Orchestrator
|
|
3
|
+
*
|
|
4
|
+
* Оркестрация взаимодействия с LLM:
|
|
5
|
+
* - Управление контекстом
|
|
6
|
+
* - Генерация промптов с архитектурными знаниями
|
|
7
|
+
* - Интеграция с Claude/GPT
|
|
8
|
+
* - Принятие архитектурных решений
|
|
9
|
+
*/
|
|
10
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
11
|
+
import OpenAI from 'openai';
|
|
12
|
+
import { Logger } from '../utils/logger.js';
|
|
13
|
+
import { DeepSeekOptimizer } from './deepseek-optimizer.js';
|
|
14
|
+
export class LLMOrchestrator {
|
|
15
|
+
anthropic;
|
|
16
|
+
openai;
|
|
17
|
+
config;
|
|
18
|
+
deepseekOptimizer;
|
|
19
|
+
initialized = false;
|
|
20
|
+
_isAvailable = false;
|
|
21
|
+
constructor(config) {
|
|
22
|
+
this.config = config;
|
|
23
|
+
// Lazy initialization
|
|
24
|
+
}
|
|
25
|
+
ensureInitialized() {
|
|
26
|
+
if (this.initialized)
|
|
27
|
+
return;
|
|
28
|
+
this.initialized = true;
|
|
29
|
+
try {
|
|
30
|
+
if (this.config.provider === 'anthropic') {
|
|
31
|
+
const apiKey = process.env.ANTHROPIC_API_KEY;
|
|
32
|
+
if (!apiKey) {
|
|
33
|
+
Logger.warn('ANTHROPIC_API_KEY not set - LLM disabled');
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
this.anthropic = new Anthropic({ apiKey });
|
|
37
|
+
this._isAvailable = true;
|
|
38
|
+
}
|
|
39
|
+
else if (this.config.provider === 'deepseek') {
|
|
40
|
+
const apiKey = process.env.DEEPSEEK_API_KEY;
|
|
41
|
+
if (!apiKey) {
|
|
42
|
+
Logger.warn('DEEPSEEK_API_KEY not set - LLM disabled');
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
this.openai = new OpenAI({
|
|
46
|
+
apiKey,
|
|
47
|
+
baseURL: this.config.baseURL || 'https://api.deepseek.com'
|
|
48
|
+
});
|
|
49
|
+
this.deepseekOptimizer = new DeepSeekOptimizer({
|
|
50
|
+
maxContextLength: 8000,
|
|
51
|
+
simplifyPrompts: true,
|
|
52
|
+
useEnglish: true,
|
|
53
|
+
reduceExamples: true,
|
|
54
|
+
structuredOutput: true
|
|
55
|
+
});
|
|
56
|
+
Logger.info('DeepSeek optimizer enabled');
|
|
57
|
+
this._isAvailable = true;
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
const apiKey = process.env.OPENAI_API_KEY;
|
|
61
|
+
if (!apiKey) {
|
|
62
|
+
Logger.warn('OPENAI_API_KEY not set - LLM disabled');
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
this.openai = new OpenAI({ apiKey });
|
|
66
|
+
this._isAvailable = true;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
Logger.warn('LLM init failed: ' + error);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
isAvailable() {
|
|
74
|
+
this.ensureInitialized();
|
|
75
|
+
return this._isAvailable;
|
|
76
|
+
}
|
|
77
|
+
async query(prompt, retryCount = 0) {
|
|
78
|
+
this.ensureInitialized();
|
|
79
|
+
if (!this._isAvailable) {
|
|
80
|
+
return {
|
|
81
|
+
content: 'LLM not available - API key not configured',
|
|
82
|
+
metadata: { tokensUsed: 0, model: this.config.model, timestamp: Date.now() }
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
Logger.progress('Querying LLM...');
|
|
86
|
+
try {
|
|
87
|
+
// Оптимизируем промпт для DeepSeek
|
|
88
|
+
let optimizedPrompt = prompt;
|
|
89
|
+
if (this.config.provider === 'deepseek' && this.deepseekOptimizer) {
|
|
90
|
+
if (retryCount > 0) {
|
|
91
|
+
// При повторных попытках упрощаем еще больше
|
|
92
|
+
optimizedPrompt = this.deepseekOptimizer.createRetryStrategy(prompt, retryCount + 1);
|
|
93
|
+
Logger.info(`Using retry strategy ${retryCount + 1} for DeepSeek`);
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
optimizedPrompt = this.deepseekOptimizer.optimizePrompt(prompt);
|
|
97
|
+
Logger.info('Prompt optimized for DeepSeek');
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// Выполняем запрос
|
|
101
|
+
if (this.config.provider === 'anthropic' && this.anthropic) {
|
|
102
|
+
return await this.queryAnthropic(optimizedPrompt);
|
|
103
|
+
}
|
|
104
|
+
else if ((this.config.provider === 'openai' || this.config.provider === 'deepseek') &&
|
|
105
|
+
this.openai) {
|
|
106
|
+
const response = await this.queryOpenAI(optimizedPrompt);
|
|
107
|
+
// Для DeepSeek валидируем и очищаем ответ
|
|
108
|
+
if (this.config.provider === 'deepseek' && this.deepseekOptimizer) {
|
|
109
|
+
response.content = this.deepseekOptimizer.validateAndCleanResponse(response.content);
|
|
110
|
+
}
|
|
111
|
+
return response;
|
|
112
|
+
}
|
|
113
|
+
throw new Error('No LLM provider configured');
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
// Retry логика для DeepSeek
|
|
117
|
+
if (this.config.provider === 'deepseek' && retryCount < 2) {
|
|
118
|
+
Logger.warn(`DeepSeek query failed, retrying (${retryCount + 1}/2)...`);
|
|
119
|
+
await new Promise(resolve => setTimeout(resolve, 1000 * (retryCount + 1)));
|
|
120
|
+
return this.query(prompt, retryCount + 1);
|
|
121
|
+
}
|
|
122
|
+
Logger.error('LLM query failed', error);
|
|
123
|
+
throw error;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
async analyzeImpact(impact, context) {
|
|
127
|
+
const prompt = this.buildImpactAnalysisPrompt(impact, context);
|
|
128
|
+
const response = await this.query(prompt);
|
|
129
|
+
return response.content;
|
|
130
|
+
}
|
|
131
|
+
async suggestRefactoring(code, goal, context) {
|
|
132
|
+
const prompt = this.buildRefactoringPrompt(code, goal, context);
|
|
133
|
+
const response = await this.query(prompt);
|
|
134
|
+
return response.content;
|
|
135
|
+
}
|
|
136
|
+
async answerArchitecturalQuestion(question, context) {
|
|
137
|
+
const prompt = this.buildArchitecturalPrompt(question, context);
|
|
138
|
+
const response = await this.query(prompt);
|
|
139
|
+
return response.content;
|
|
140
|
+
}
|
|
141
|
+
async generateDocumentation(codebase, context) {
|
|
142
|
+
const prompt = {
|
|
143
|
+
system: this.buildSystemPrompt(context),
|
|
144
|
+
user: `Generate comprehensive documentation for this codebase:\n\n${codebase}\n\nInclude:\n- Architecture overview\n- Key components\n- Data flows\n- Design decisions\n- Usage examples`
|
|
145
|
+
};
|
|
146
|
+
const response = await this.query(prompt);
|
|
147
|
+
return response.content;
|
|
148
|
+
}
|
|
149
|
+
async reviewCode(code, changedFiles, context) {
|
|
150
|
+
const prompt = {
|
|
151
|
+
system: this.buildSystemPrompt(context),
|
|
152
|
+
user: `Review this code change:\n\nChanged files: ${changedFiles.join(', ')}\n\n${code}\n\nProvide:\n- Architecture compliance check\n- Potential bugs\n- Performance issues\n- Security concerns\n- Improvement suggestions`
|
|
153
|
+
};
|
|
154
|
+
const response = await this.query(prompt);
|
|
155
|
+
return response.content;
|
|
156
|
+
}
|
|
157
|
+
async queryAnthropic(prompt) {
|
|
158
|
+
if (!this.anthropic) {
|
|
159
|
+
throw new Error('Anthropic client not initialized');
|
|
160
|
+
}
|
|
161
|
+
const response = await this.anthropic.messages.create({
|
|
162
|
+
model: this.config.model,
|
|
163
|
+
max_tokens: this.config.maxTokens,
|
|
164
|
+
temperature: this.config.temperature,
|
|
165
|
+
system: prompt.system,
|
|
166
|
+
messages: [
|
|
167
|
+
{
|
|
168
|
+
role: 'user',
|
|
169
|
+
content: prompt.user
|
|
170
|
+
}
|
|
171
|
+
]
|
|
172
|
+
});
|
|
173
|
+
const content = response.content[0];
|
|
174
|
+
const text = content.type === 'text' ? content.text : '';
|
|
175
|
+
return {
|
|
176
|
+
content: text,
|
|
177
|
+
metadata: {
|
|
178
|
+
tokensUsed: response.usage.input_tokens + response.usage.output_tokens,
|
|
179
|
+
model: this.config.model,
|
|
180
|
+
timestamp: Date.now()
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
async queryOpenAI(prompt) {
|
|
185
|
+
if (!this.openai) {
|
|
186
|
+
throw new Error('OpenAI client not initialized');
|
|
187
|
+
}
|
|
188
|
+
const response = await this.openai.chat.completions.create({
|
|
189
|
+
model: this.config.model,
|
|
190
|
+
temperature: this.config.temperature,
|
|
191
|
+
max_tokens: this.config.maxTokens,
|
|
192
|
+
messages: [
|
|
193
|
+
{
|
|
194
|
+
role: 'system',
|
|
195
|
+
content: prompt.system
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
role: 'user',
|
|
199
|
+
content: prompt.user
|
|
200
|
+
}
|
|
201
|
+
]
|
|
202
|
+
});
|
|
203
|
+
const message = response.choices[0]?.message;
|
|
204
|
+
return {
|
|
205
|
+
content: message?.content || '',
|
|
206
|
+
metadata: {
|
|
207
|
+
tokensUsed: response.usage?.total_tokens || 0,
|
|
208
|
+
model: this.config.model,
|
|
209
|
+
timestamp: Date.now()
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
buildImpactAnalysisPrompt(impact, context) {
|
|
214
|
+
const systemPrompt = this.buildSystemPrompt(context);
|
|
215
|
+
const userPrompt = `Analyze the impact of this change:
|
|
216
|
+
|
|
217
|
+
**Change Description:** ${impact.change.description}
|
|
218
|
+
**Type:** ${impact.change.type}
|
|
219
|
+
**Files:** ${impact.change.files.join(', ')}
|
|
220
|
+
|
|
221
|
+
**Affected Components:** ${impact.affectedNodes.length}
|
|
222
|
+
- Critical: ${impact.affectedNodes.filter(n => n.impactLevel === 'critical').length}
|
|
223
|
+
- High: ${impact.affectedNodes.filter(n => n.impactLevel === 'high').length}
|
|
224
|
+
- Medium: ${impact.affectedNodes.filter(n => n.impactLevel === 'medium').length}
|
|
225
|
+
|
|
226
|
+
**Risks Identified:** ${impact.risks.length}
|
|
227
|
+
${impact.risks.map(r => `- [${r.severity}] ${r.description}`).join('\n')}
|
|
228
|
+
|
|
229
|
+
**Current Recommendations:**
|
|
230
|
+
${impact.recommendations.map(r => `- [${r.priority}] ${r.description}`).join('\n')}
|
|
231
|
+
|
|
232
|
+
Please provide:
|
|
233
|
+
1. Additional risks or concerns
|
|
234
|
+
2. Specific migration steps if needed
|
|
235
|
+
3. Testing strategy
|
|
236
|
+
4. Rollback plan
|
|
237
|
+
5. Long-term architectural implications`;
|
|
238
|
+
return {
|
|
239
|
+
system: systemPrompt,
|
|
240
|
+
user: userPrompt,
|
|
241
|
+
context
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
buildRefactoringPrompt(code, goal, context) {
|
|
245
|
+
const systemPrompt = this.buildSystemPrompt(context);
|
|
246
|
+
const userPrompt = `Suggest refactoring for this code to achieve: ${goal}
|
|
247
|
+
|
|
248
|
+
Code:
|
|
249
|
+
\`\`\`
|
|
250
|
+
${code}
|
|
251
|
+
\`\`\`
|
|
252
|
+
|
|
253
|
+
Please provide:
|
|
254
|
+
1. Proposed refactoring approach
|
|
255
|
+
2. Step-by-step implementation plan
|
|
256
|
+
3. Potential risks
|
|
257
|
+
4. Testing requirements
|
|
258
|
+
5. Before/after comparison`;
|
|
259
|
+
return {
|
|
260
|
+
system: systemPrompt,
|
|
261
|
+
user: userPrompt,
|
|
262
|
+
context
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
buildArchitecturalPrompt(question, context) {
|
|
266
|
+
return {
|
|
267
|
+
system: this.buildSystemPrompt(context),
|
|
268
|
+
user: question,
|
|
269
|
+
context
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
buildSystemPrompt(context) {
|
|
273
|
+
let prompt = `###CRITICAL INSTRUCTION - LANGUAGE###
|
|
274
|
+
If the user's question contains Cyrillic characters (Russian), you MUST respond ENTIRELY in Russian.
|
|
275
|
+
Если вопрос на русском - отвечай ТОЛЬКО на русском языке. Ни одного слова на английском!
|
|
276
|
+
###END LANGUAGE INSTRUCTION###
|
|
277
|
+
|
|
278
|
+
You are an AI assistant analyzing a specific codebase.
|
|
279
|
+
|
|
280
|
+
ABSOLUTE RULES:
|
|
281
|
+
1. ONLY USE PROVIDED DATA: You may ONLY mention files that appear in "PROJECT FILES" section below.
|
|
282
|
+
2. NO INVENTION: NEVER invent file paths, class names, or code. If not shown - it doesn't exist.
|
|
283
|
+
3. WHEN NO DATA: Say "Нет данных в индексе" (Russian) or "No indexed data" (English).
|
|
284
|
+
4. BE HONEST: If you don't know - say so. Don't guess.`;
|
|
285
|
+
if (context?.architecture?.boundedContexts && context.architecture.boundedContexts.length > 0) {
|
|
286
|
+
prompt += '\n\n**Defined Architecture:**\n';
|
|
287
|
+
for (const bc of context.architecture.boundedContexts) {
|
|
288
|
+
prompt += `- ${bc.name}: ${bc.description}\n`;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
if (context?.semanticMemory && context.semanticMemory.length > 0) {
|
|
292
|
+
prompt += '\n\n###PROJECT FILES (ONLY reference these - nothing else exists)###\n';
|
|
293
|
+
for (const result of context.semanticMemory.slice(0, 10)) {
|
|
294
|
+
prompt += `\nФайл: ${result.chunk.metadata.filePath}\n`;
|
|
295
|
+
prompt += `${result.context}\n`;
|
|
296
|
+
}
|
|
297
|
+
prompt += '\n###END PROJECT FILES###';
|
|
298
|
+
}
|
|
299
|
+
else {
|
|
300
|
+
prompt += '\n\n###PROJECT FILES: EMPTY###\nNo code indexed. Respond: "Проект не проиндексирован. Запустите индексацию."';
|
|
301
|
+
}
|
|
302
|
+
return prompt;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
//# sourceMappingURL=index.js.map
|