pug-site-core 3.0.0 → 3.0.1

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.
@@ -1,300 +1,628 @@
1
- import express from 'express';
2
- import fs from 'fs-extra';
1
+ import { ChatOpenAI } from "@langchain/openai";
2
+ import { PromptTemplate } from "@langchain/core/prompts";
3
+ import { StructuredOutputParser } from "@langchain/core/output_parsers";
4
+ import { z } from "zod";
5
+ import { Document } from "@langchain/core/documents";
6
+ import { DirectoryLoader } from "langchain/document_loaders/fs/directory";
7
+ import { TextLoader } from "langchain/document_loaders/fs/text";
8
+ import { RecursiveCharacterTextSplitter } from "langchain/text_splitter";
9
+ import { FileManagementToolkit } from "@langchain/community/agent_toolkits";
10
+ import { VectorStore } from "@langchain/core/vectorstores";
11
+ import { MemoryVectorStore } from "langchain/vectorstores/memory";
12
+ import { OpenAIEmbeddings } from "@langchain/openai";
13
+ import { RunnableSequence } from "@langchain/core/runnables";
14
+ import fs from 'fs/promises';
3
15
  import path from 'path';
4
16
  import { fileURLToPath } from 'url';
5
17
 
6
18
  const __filename = fileURLToPath(import.meta.url);
7
19
  const __dirname = path.dirname(__filename);
8
- const router = express.Router();
9
20
 
10
- // 获取template-debug目录的绝对路径
11
- const templateDebugPath = path.join(process.cwd(), 'template-debug');
21
+ // DeepSeek API 配置
22
+ const llm = new ChatOpenAI({
23
+ model: "deepseek-chat",
24
+ temperature: 0.2, // 降低随机性,提高代码修改的准确性
25
+ openAIApiKey: process.env.DEEPSEEK_API_KEY || "your-api-key-here",
26
+ configuration: {
27
+ baseURL: "https://api.deepseek.com/v1"
28
+ }
29
+ });
12
30
 
13
- // 检查是否设置了OpenAI API密钥
14
- const hasOpenAIKey = !!process.env.OPENAI_API_KEY;
31
+ // 定义结构化输出模式
32
+ const LocationSchema = z.object({
33
+ startLine: z.number().describe("修改开始行号"),
34
+ endLine: z.number().describe("修改结束行号"),
35
+ reason: z.string().describe("选择这个位置的原因"),
36
+ context: z.string().describe("相关的代码上下文")
37
+ });
15
38
 
16
- let model = null;
17
- let agentExecutor = null;
39
+ const AnalysisResultSchema = z.object({
40
+ locations: z.array(LocationSchema).describe("可能的修改位置列表"),
41
+ analysis: z.string().describe("整体分析说明"),
42
+ confidence: z.number().min(0).max(1).describe("分析结果的置信度")
43
+ });
18
44
 
19
- // 动态导入langchain模块并初始化
20
- async function initializeAI() {
21
- if (!hasOpenAIKey) {
22
- console.warn('警告: 未设置OPENAI_API_KEY环境变量,AI功能将不可用');
23
- return false;
45
+ const ModificationResultSchema = z.object({
46
+ modifiedCode: z.string().describe("修改后的代码"),
47
+ explanation: z.string().describe("修改说明"),
48
+ changes: z.array(z.object({
49
+ type: z.enum(["added", "modified", "deleted"]).describe("修改类型"),
50
+ description: z.string().describe("具体的改动描述"),
51
+ lineNumbers: z.array(z.number()).describe("涉及的行号")
52
+ })).describe("修改详情列表"),
53
+ riskLevel: z.enum(["low", "medium", "high"]).describe("修改风险等级")
54
+ });
55
+
56
+ /**
57
+ * 使用LangChain优化的代码修改 Agent 类
58
+ */
59
+ class EnhancedCodeModificationAgent {
60
+ constructor(options = {}) {
61
+ this.projectRoot = options.projectRoot || process.cwd();
62
+ this.fileManagementToolkit = new FileManagementToolkit({
63
+ rootDir: this.projectRoot
64
+ });
65
+ this.vectorStore = null;
66
+ this.embeddings = new OpenAIEmbeddings({
67
+ openAIApiKey: process.env.OPENAI_API_KEY
68
+ });
69
+ this.textSplitter = new RecursiveCharacterTextSplitter({
70
+ chunkSize: 1000,
71
+ chunkOverlap: 200,
72
+ });
73
+
74
+ // 设置结构化输出解析器
75
+ this.analysisParser = StructuredOutputParser.fromZodSchema(AnalysisResultSchema);
76
+ this.modificationParser = StructuredOutputParser.fromZodSchema(ModificationResultSchema);
77
+ }
78
+
79
+ /**
80
+ * 初始化项目上下文向量存储
81
+ */
82
+ async initializeProjectContext() {
83
+ try {
84
+ const loader = new DirectoryLoader(this.projectRoot, {
85
+ ".js": (path) => new TextLoader(path),
86
+ ".ts": (path) => new TextLoader(path),
87
+ ".jsx": (path) => new TextLoader(path),
88
+ ".tsx": (path) => new TextLoader(path),
89
+ ".vue": (path) => new TextLoader(path),
90
+ ".py": (path) => new TextLoader(path),
91
+ ".md": (path) => new TextLoader(path),
92
+ });
93
+
94
+ const docs = await loader.load();
95
+ const splitDocs = await this.textSplitter.splitDocuments(docs);
96
+
97
+ this.vectorStore = await MemoryVectorStore.fromDocuments(
98
+ splitDocs,
99
+ this.embeddings
100
+ );
101
+
102
+ console.log(`已加载 ${docs.length} 个文件,分割为 ${splitDocs.length} 个文档块`);
103
+ } catch (error) {
104
+ console.error('初始化项目上下文失败:', error);
105
+ throw error;
24
106
  }
107
+ }
25
108
 
109
+ /**
110
+ * 使用LangChain工具进行文件操作
111
+ */
112
+ async readFileWithLangChain(filePath) {
26
113
  try {
27
- const { ChatOpenAI } = await import('@langchain/openai');
28
- const { AgentExecutor, createOpenAIFunctionsAgent } = await import('langchain/agents');
29
- const { ChatPromptTemplate, MessagesPlaceholder } = await import('@langchain/core/prompts');
30
- const { HumanMessage, AIMessage } = await import('@langchain/core/messages');
31
- const { DynamicTool } = await import('@langchain/core/tools');
32
-
33
- // 初始化OpenAI模型
34
- model = new ChatOpenAI({
35
- modelName: "gpt-3.5-turbo",
36
- temperature: 0.1,
37
- });
114
+ const tools = this.fileManagementToolkit.getTools();
115
+ const readTool = tools.find(tool => tool.name === 'read_file');
116
+
117
+ if (!readTool) {
118
+ throw new Error('Read file tool not found');
119
+ }
38
120
 
39
- // 定义工具函数
40
- const tools = [
41
- new DynamicTool({
42
- name: "read_file",
43
- description: "读取template-debug目录下的文件内容。参数: filepath - 相对于template-debug的文件路径",
44
- func: async (filepath) => {
45
- try {
46
- const fullPath = path.join(templateDebugPath, filepath);
47
-
48
- // 安全检查:确保文件在template-debug目录内
49
- if (!fullPath.startsWith(templateDebugPath)) {
50
- return "错误:只能访问template-debug目录下的文件";
51
- }
52
-
53
- if (!await fs.pathExists(fullPath)) {
54
- return `文件不存在: ${filepath}`;
55
- }
56
-
57
- const content = await fs.readFile(fullPath, 'utf-8');
58
- return `文件内容 (${filepath}):\n${content}`;
59
- } catch (error) {
60
- return `读取文件失败: ${error.message}`;
61
- }
62
- }
63
- }),
64
-
65
- new DynamicTool({
66
- name: "write_file",
67
- description: "写入或修改template-debug目录下的文件。参数格式: filepath|content (用|分隔文件路径和内容)",
68
- func: async (input) => {
69
- try {
70
- const [filepath, ...contentParts] = input.split('|');
71
- const content = contentParts.join('|');
72
-
73
- if (!filepath || content === undefined) {
74
- return "错误:请提供文件路径和内容,格式: filepath|content";
75
- }
76
-
77
- const fullPath = path.join(templateDebugPath, filepath);
78
-
79
- // 安全检查:确保文件在template-debug目录内
80
- if (!fullPath.startsWith(templateDebugPath)) {
81
- return "错误:只能修改template-debug目录下的文件";
82
- }
83
-
84
- // 确保目录存在
85
- await fs.ensureDir(path.dirname(fullPath));
86
-
87
- // 写入文件
88
- await fs.writeFile(fullPath, content, 'utf-8');
89
-
90
- return `文件已成功保存: ${filepath}`;
91
- } catch (error) {
92
- return `写入文件失败: ${error.message}`;
93
- }
94
- }
95
- }),
96
-
97
- new DynamicTool({
98
- name: "list_files",
99
- description: "列出template-debug目录下的文件和文件夹。参数: dirpath - 相对于template-debug的目录路径(可选,默认为根目录)",
100
- func: async (dirpath = '') => {
101
- try {
102
- const fullPath = path.join(templateDebugPath, dirpath);
103
-
104
- // 安全检查
105
- if (!fullPath.startsWith(templateDebugPath)) {
106
- return "错误:只能访问template-debug目录下的内容";
107
- }
108
-
109
- if (!await fs.pathExists(fullPath)) {
110
- return `目录不存在: ${dirpath || '/'}`;
111
- }
112
-
113
- const items = await fs.readdir(fullPath, { withFileTypes: true });
114
- const result = items.map(item => {
115
- const type = item.isDirectory() ? '[目录]' : '[文件]';
116
- return `${type} ${item.name}`;
117
- }).join('\n');
118
-
119
- return `目录内容 (${dirpath || '/'}):\n${result}`;
120
- } catch (error) {
121
- return `列出文件失败: ${error.message}`;
122
- }
123
- }
124
- }),
125
-
126
- new DynamicTool({
127
- name: "delete_file",
128
- description: "删除template-debug目录下的文件。参数: filepath - 相对于template-debug的文件路径",
129
- func: async (filepath) => {
130
- try {
131
- const fullPath = path.join(templateDebugPath, filepath);
132
-
133
- // 安全检查
134
- if (!fullPath.startsWith(templateDebugPath)) {
135
- return "错误:只能删除template-debug目录下的文件";
136
- }
137
-
138
- if (!await fs.pathExists(fullPath)) {
139
- return `文件不存在: ${filepath}`;
140
- }
141
-
142
- await fs.remove(fullPath);
143
- return `文件已删除: ${filepath}`;
144
- } catch (error) {
145
- return `删除文件失败: ${error.message}`;
146
- }
147
- }
148
- })
149
- ];
150
-
151
- // 创建prompt模板
152
- const prompt = ChatPromptTemplate.fromMessages([
153
- ["system", `你是一个专业的代码修改助手。你可以帮助用户修改template-debug目录下的代码文件。
154
-
155
- 你有以下工具可以使用:
156
- 1. read_file - 读取文件内容
157
- 2. write_file - 写入或修改文件内容
158
- 3. list_files - 列出目录内容
159
- 4. delete_file - 删除文件
160
-
161
- 请根据用户的需求,使用这些工具来完成代码修改任务。在修改代码时,请:
162
- - 仔细理解用户的需求
163
- - 先读取相关文件了解现有代码结构
164
- - 进行必要的修改
165
- - 确保代码语法正确
166
- - 提供清晰的修改说明
167
-
168
- 始终用中文回复用户。`],
169
- new MessagesPlaceholder("chat_history"),
170
- ["human", "{input}"],
171
- new MessagesPlaceholder("agent_scratchpad")
172
- ]);
173
-
174
- // 创建agent
175
- const agent = await createOpenAIFunctionsAgent({
176
- llm: model,
177
- tools,
178
- prompt
179
- });
121
+ const result = await readTool.invoke({ file_path: filePath });
122
+ const lines = result.split('\n');
123
+
124
+ return {
125
+ success: true,
126
+ content: result,
127
+ lines,
128
+ metadata: {
129
+ lineCount: lines.length,
130
+ filePath: path.resolve(this.projectRoot, filePath)
131
+ }
132
+ };
133
+ } catch (error) {
134
+ return {
135
+ success: false,
136
+ error: error.message,
137
+ filePath
138
+ };
139
+ }
140
+ }
180
141
 
181
- // 创建agent执行器
182
- agentExecutor = new AgentExecutor({
183
- agent,
184
- tools,
185
- verbose: true,
186
- maxIterations: 10
187
- });
142
+ /**
143
+ * 使用LangChain工具写入文件
144
+ */
145
+ async writeFileWithLangChain(filePath, content) {
146
+ try {
147
+ const tools = this.fileManagementToolkit.getTools();
148
+ const writeTool = tools.find(tool => tool.name === 'write_file');
149
+
150
+ if (!writeTool) {
151
+ throw new Error('Write file tool not found');
152
+ }
188
153
 
189
- console.log('AI代码修改助手初始化成功');
190
- return true;
154
+ await writeTool.invoke({
155
+ file_path: filePath,
156
+ text: content
157
+ });
158
+
159
+ return {
160
+ success: true,
161
+ message: `文件 ${filePath} 写入成功`,
162
+ timestamp: new Date().toISOString()
163
+ };
191
164
  } catch (error) {
192
- console.error('初始化AI失败:', error);
193
- return false;
165
+ return {
166
+ success: false,
167
+ error: error.message,
168
+ filePath
169
+ };
194
170
  }
195
- }
171
+ }
196
172
 
197
- // 存储对话历史
198
- const chatHistories = new Map();
173
+ /**
174
+ * 使用向量搜索获取相关上下文
175
+ */
176
+ async getRelevantContext(description, filePath = null) {
177
+ if (!this.vectorStore) {
178
+ await this.initializeProjectContext();
179
+ }
199
180
 
200
- // API路由
201
- router.post('/chat', async (req, res) => {
202
181
  try {
203
- const { message, sessionId = 'default' } = req.body;
204
-
205
- if (!message) {
206
- return res.status(400).json({ error: '请提供消息内容' });
207
- }
182
+ // 构建搜索查询
183
+ let searchQuery = description;
184
+ if (filePath) {
185
+ searchQuery += ` file:${path.basename(filePath)}`;
186
+ }
208
187
 
209
- // 如果AI未初始化,尝试初始化
210
- if (!agentExecutor) {
211
- const initialized = await initializeAI();
212
- if (!initialized) {
213
- return res.status(500).json({
214
- success: false,
215
- error: 'AI服务不可用,请检查OPENAI_API_KEY环境变量是否设置'
216
- });
217
- }
218
- }
188
+ const relevantDocs = await this.vectorStore.similaritySearch(searchQuery, 5);
189
+
190
+ return {
191
+ success: true,
192
+ contexts: relevantDocs.map(doc => ({
193
+ content: doc.pageContent,
194
+ metadata: doc.metadata,
195
+ relevanceScore: doc.score || 0
196
+ }))
197
+ };
198
+ } catch (error) {
199
+ return {
200
+ success: false,
201
+ error: error.message,
202
+ contexts: []
203
+ };
204
+ }
205
+ }
219
206
 
220
- // 获取或初始化对话历史
221
- if (!chatHistories.has(sessionId)) {
222
- chatHistories.set(sessionId, []);
223
- }
224
- const chatHistory = chatHistories.get(sessionId);
207
+ /**
208
+ * 使用结构化输出分析代码位置
209
+ */
210
+ async analyzeCodeLocationStructured(filePath, description) {
211
+ const fileResult = await this.readFileWithLangChain(filePath);
212
+ if (!fileResult.success) {
213
+ return { success: false, error: fileResult.error };
214
+ }
225
215
 
226
- // 执行agent
227
- const result = await agentExecutor.invoke({
228
- input: message,
229
- chat_history: chatHistory
230
- });
216
+ // 获取相关上下文
217
+ const contextResult = await this.getRelevantContext(description, filePath);
218
+ const relevantContext = contextResult.success ?
219
+ contextResult.contexts.map(ctx => ctx.content).join('\n\n') : '';
231
220
 
232
- // 更新对话历史
233
- chatHistory.push(new HumanMessage(message));
234
- chatHistory.push(new AIMessage(result.output));
221
+ const analysisPrompt = PromptTemplate.fromTemplate(`
222
+ 你是一个专业的代码分析师。请分析以下代码文件,根据用户的描述找到需要修改的具体位置。
235
223
 
236
- // 限制历史记录长度
237
- if (chatHistory.length > 20) {
238
- chatHistory.splice(0, chatHistory.length - 20);
239
- }
224
+ 文件路径: {filePath}
225
+ 文件内容:
226
+ \`\`\`
227
+ {fileContent}
228
+ \`\`\`
240
229
 
241
- res.json({
242
- success: true,
243
- response: result.output,
244
- sessionId
245
- });
230
+ 相关项目上下文:
231
+ {relevantContext}
232
+
233
+ 用户描述: {description}
234
+
235
+ 请仔细分析代码结构和用户需求,返回可能的修改位置。考虑以下因素:
236
+ 1. 代码的逻辑结构和依赖关系
237
+ 2. 函数/类的边界
238
+ 3. 变量作用域
239
+ 4. 最小侵入性原则
240
+
241
+ {format_instructions}
242
+ `);
243
+
244
+ try {
245
+ const chain = RunnableSequence.from([
246
+ analysisPrompt,
247
+ llm,
248
+ this.analysisParser
249
+ ]);
250
+
251
+ const result = await chain.invoke({
252
+ filePath,
253
+ fileContent: fileResult.content,
254
+ relevantContext,
255
+ description,
256
+ format_instructions: this.analysisParser.getFormatInstructions()
257
+ });
246
258
 
259
+ return {
260
+ success: true,
261
+ ...result,
262
+ fileMetadata: fileResult.metadata
263
+ };
247
264
  } catch (error) {
248
- console.error('AI Agent错误:', error);
249
- res.status(500).json({
250
- success: false,
251
- error: '处理请求时发生错误',
252
- details: error.message
265
+ return {
266
+ success: false,
267
+ error: `分析失败: ${error.message}`,
268
+ fallbackLocations: this.fallbackLocationAnalysis(fileResult.lines, description)
269
+ };
270
+ }
271
+ }
272
+
273
+ /**
274
+ * 降级位置分析(当结构化分析失败时)
275
+ */
276
+ fallbackLocationAnalysis(lines, description) {
277
+ const keywords = description.toLowerCase().split(/\s+/);
278
+ const locations = [];
279
+
280
+ lines.forEach((line, index) => {
281
+ const lineContent = line.toLowerCase();
282
+ const matchCount = keywords.filter(keyword => lineContent.includes(keyword)).length;
283
+
284
+ if (matchCount > 0) {
285
+ locations.push({
286
+ startLine: index + 1,
287
+ endLine: index + 1,
288
+ reason: `包含关键词: ${keywords.filter(k => lineContent.includes(k)).join(', ')}`,
289
+ context: line.trim(),
290
+ confidence: matchCount / keywords.length
253
291
  });
292
+ }
293
+ });
294
+
295
+ return locations.sort((a, b) => b.confidence - a.confidence).slice(0, 3);
296
+ }
297
+
298
+ /**
299
+ * 生成结构化代码修改
300
+ */
301
+ async generateCodeModificationStructured(filePath, startLine, endLine, description, context = '') {
302
+ const fileResult = await this.readFileWithLangChain(filePath);
303
+ if (!fileResult.success) {
304
+ return { success: false, error: fileResult.error };
254
305
  }
255
- });
256
306
 
257
- // 获取文件列表
258
- router.get('/files', async (req, res) => {
307
+ const lines = fileResult.lines;
308
+ const beforeContext = lines.slice(Math.max(0, startLine - 6), startLine - 1).join('\n');
309
+ const targetCode = lines.slice(startLine - 1, endLine).join('\n');
310
+ const afterContext = lines.slice(endLine, Math.min(lines.length, endLine + 5)).join('\n');
311
+
312
+ // 获取项目上下文
313
+ const contextResult = await this.getRelevantContext(description, filePath);
314
+ const projectContext = contextResult.success ?
315
+ contextResult.contexts.slice(0, 3).map(ctx => ctx.content).join('\n\n') : '';
316
+
317
+ const modificationPrompt = PromptTemplate.fromTemplate(`
318
+ 你是一个专业的代码修改专家。请根据用户的需求修改指定的代码片段。
319
+
320
+ 文件路径: {filePath}
321
+ 修改范围: 第{startLine}行 到 第{endLine}行
322
+
323
+ 项目上下文信息:
324
+ {projectContext}
325
+
326
+ 附加上下文:
327
+ {context}
328
+
329
+ 修改前的代码上下文:
330
+ \`\`\`
331
+ {beforeContext}
332
+ --- 需要修改的代码开始 ---
333
+ {targetCode}
334
+ --- 需要修改的代码结束 ---
335
+ {afterContext}
336
+ \`\`\`
337
+
338
+ 用户需求: {description}
339
+
340
+ 请遵循以下原则:
341
+ 1. 保持原有的代码风格和缩进
342
+ 2. 确保修改后的代码语法正确
343
+ 3. 考虑代码的完整性和逻辑性
344
+ 4. 最小化对现有功能的影响
345
+ 5. 添加必要的注释说明
346
+
347
+ {format_instructions}
348
+ `);
349
+
350
+ try {
351
+ const chain = RunnableSequence.from([
352
+ modificationPrompt,
353
+ llm,
354
+ this.modificationParser
355
+ ]);
356
+
357
+ const result = await chain.invoke({
358
+ filePath,
359
+ startLine,
360
+ endLine,
361
+ beforeContext,
362
+ targetCode,
363
+ afterContext,
364
+ description,
365
+ context,
366
+ projectContext,
367
+ format_instructions: this.modificationParser.getFormatInstructions()
368
+ });
369
+
370
+ return {
371
+ success: true,
372
+ ...result,
373
+ originalCode: targetCode,
374
+ metadata: fileResult.metadata
375
+ };
376
+ } catch (error) {
377
+ return {
378
+ success: false,
379
+ error: `生成修改失败: ${error.message}`,
380
+ originalCode: targetCode
381
+ };
382
+ }
383
+ }
384
+
385
+ /**
386
+ * 应用代码修改(使用LangChain工具)
387
+ */
388
+ async applyModification(filePath, startLine, endLine, newCode) {
389
+ const fileResult = await this.readFileWithLangChain(filePath);
390
+ if (!fileResult.success) {
391
+ return { success: false, error: fileResult.error };
392
+ }
393
+
394
+ try {
395
+ const lines = fileResult.lines;
396
+ const newLines = [
397
+ ...lines.slice(0, startLine - 1),
398
+ ...newCode.split('\n'),
399
+ ...lines.slice(endLine)
400
+ ];
401
+
402
+ const newContent = newLines.join('\n');
403
+ const writeResult = await this.writeFileWithLangChain(filePath, newContent);
404
+
405
+ if (writeResult.success) {
406
+ return {
407
+ success: true,
408
+ message: `成功修改文件 ${filePath}`,
409
+ changes: {
410
+ linesAdded: newCode.split('\n').length,
411
+ linesRemoved: endLine - startLine + 1,
412
+ originalRange: { startLine, endLine },
413
+ modifiedAt: writeResult.timestamp
414
+ }
415
+ };
416
+ } else {
417
+ return { success: false, error: writeResult.error };
418
+ }
419
+ } catch (error) {
420
+ return {
421
+ success: false,
422
+ error: `应用修改失败: ${error.message}`
423
+ };
424
+ }
425
+ }
426
+
427
+ /**
428
+ * 智能代码修改 - 使用所有LangChain优化
429
+ */
430
+ async smartModifyWithEnhancements(filePath, description, autoApply = false) {
431
+ console.log(`开始智能分析文件: ${filePath}`);
432
+
259
433
  try {
260
- const { path: dirPath = '' } = req.query;
261
- const fullPath = path.join(templateDebugPath, dirPath);
434
+ // 1. 使用结构化输出分析代码位置
435
+ const locationResult = await this.analyzeCodeLocationStructured(filePath, description);
436
+ if (!locationResult.success) {
437
+ return { success: false, error: locationResult.error };
438
+ }
439
+
440
+ console.log(`找到 ${locationResult.locations.length} 个可能的修改位置 (置信度: ${locationResult.confidence})`);
441
+
442
+ const results = [];
443
+
444
+ // 2. 对每个位置生成结构化修改
445
+ for (const location of locationResult.locations) {
446
+ console.log(`正在处理位置: 第${location.startLine}-${location.endLine}行`);
447
+
448
+ const modificationResult = await this.generateCodeModificationStructured(
449
+ filePath,
450
+ location.startLine,
451
+ location.endLine,
452
+ description,
453
+ location.context
454
+ );
262
455
 
263
- if (!fullPath.startsWith(templateDebugPath)) {
264
- return res.status(400).json({ error: '无效的路径' });
456
+ if (modificationResult.success) {
457
+ const result = {
458
+ location,
459
+ modification: modificationResult,
460
+ applied: false,
461
+ riskAssessment: {
462
+ level: modificationResult.riskLevel,
463
+ considerations: this.assessModificationRisk(modificationResult)
464
+ }
465
+ };
466
+
467
+ // 如果启用自动应用且风险等级较低
468
+ if (autoApply && modificationResult.riskLevel === 'low') {
469
+ const applyResult = await this.applyModification(
470
+ filePath,
471
+ location.startLine,
472
+ location.endLine,
473
+ modificationResult.modifiedCode
474
+ );
475
+ result.applied = applyResult.success;
476
+ result.applyResult = applyResult;
477
+ }
478
+
479
+ results.push(result);
265
480
  }
481
+ }
482
+
483
+ return {
484
+ success: true,
485
+ analysis: locationResult.analysis,
486
+ confidence: locationResult.confidence,
487
+ modifications: results,
488
+ projectContextUsed: true
489
+ };
490
+ } catch (error) {
491
+ return {
492
+ success: false,
493
+ error: `智能修改失败: ${error.message}`,
494
+ fallbackAvailable: true
495
+ };
496
+ }
497
+ }
498
+
499
+ /**
500
+ * 评估修改风险
501
+ */
502
+ assessModificationRisk(modificationResult) {
503
+ const considerations = [];
504
+
505
+ // 检查修改复杂度
506
+ const changeCount = modificationResult.changes.length;
507
+ if (changeCount > 5) {
508
+ considerations.push("修改涉及多处变更,建议仔细审查");
509
+ }
510
+
511
+ // 检查是否涉及删除操作
512
+ const hasDeletes = modificationResult.changes.some(change => change.type === 'deleted');
513
+ if (hasDeletes) {
514
+ considerations.push("包含代码删除操作,请确认不会影响现有功能");
515
+ }
516
+
517
+ // 检查修改说明的完整性
518
+ if (!modificationResult.explanation || modificationResult.explanation.length < 20) {
519
+ considerations.push("修改说明较简单,建议获取更详细的解释");
520
+ }
521
+
522
+ return considerations;
523
+ }
524
+
525
+ /**
526
+ * 批量修改多个文件 - 增强版
527
+ */
528
+ async batchModifyEnhanced(modifications, options = {}) {
529
+ const { autoApply = false, maxConcurrency = 3 } = options;
530
+ const results = [];
531
+
532
+ // 使用Promise控制并发数量
533
+ const semaphore = new Array(maxConcurrency).fill(null);
534
+
535
+ const processModification = async (mod) => {
536
+ try {
537
+ let result;
266
538
 
267
- if (!await fs.pathExists(fullPath)) {
268
- return res.status(404).json({ error: '目录不存在' });
539
+ if (mod.startLine && mod.endLine) {
540
+ // 指定位置修改
541
+ const modResult = await this.generateCodeModificationStructured(
542
+ mod.filePath,
543
+ mod.startLine,
544
+ mod.endLine,
545
+ mod.description
546
+ );
547
+
548
+ if (modResult.success && autoApply && modResult.riskLevel === 'low') {
549
+ const applyResult = await this.applyModification(
550
+ mod.filePath,
551
+ mod.startLine,
552
+ mod.endLine,
553
+ modResult.modifiedCode
554
+ );
555
+ result = { ...modResult, applied: applyResult.success, applyResult };
556
+ } else {
557
+ result = { ...modResult, applied: false };
558
+ }
559
+ } else {
560
+ // 智能修改
561
+ result = await this.smartModifyWithEnhancements(
562
+ mod.filePath,
563
+ mod.description,
564
+ autoApply
565
+ );
269
566
  }
270
567
 
271
- const items = await fs.readdir(fullPath, { withFileTypes: true });
272
- const files = items.map(item => ({
273
- name: item.name,
274
- type: item.isDirectory() ? 'directory' : 'file',
275
- path: path.join(dirPath, item.name).replace(/\\/g, '/')
276
- }));
568
+ return {
569
+ filePath: mod.filePath,
570
+ description: mod.description,
571
+ result,
572
+ processedAt: new Date().toISOString()
573
+ };
277
574
 
278
- res.json({ success: true, files });
279
- } catch (error) {
280
- res.status(500).json({ error: '获取文件列表失败', details: error.message });
575
+ } catch (error) {
576
+ return {
577
+ filePath: mod.filePath,
578
+ description: mod.description,
579
+ result: { success: false, error: error.message },
580
+ processedAt: new Date().toISOString()
581
+ };
582
+ }
583
+ };
584
+
585
+ // 并发处理修改请求
586
+ const chunks = [];
587
+ for (let i = 0; i < modifications.length; i += maxConcurrency) {
588
+ chunks.push(modifications.slice(i, i + maxConcurrency));
281
589
  }
282
- });
283
590
 
284
- // 清除对话历史
285
- router.delete('/chat/:sessionId', (req, res) => {
286
- const { sessionId } = req.params;
287
- chatHistories.delete(sessionId);
288
- res.json({ success: true, message: '对话历史已清除' });
289
- });
591
+ for (const chunk of chunks) {
592
+ const promises = chunk.map(processModification);
593
+ const chunkResults = await Promise.all(promises);
594
+ results.push(...chunkResults);
595
+ }
596
+
597
+ return {
598
+ success: true,
599
+ results,
600
+ summary: {
601
+ total: results.length,
602
+ successful: results.filter(r => r.result.success).length,
603
+ applied: results.filter(r => r.result.applied).length,
604
+ failed: results.filter(r => !r.result.success).length
605
+ }
606
+ };
607
+ }
290
608
 
291
- // 健康检查
292
- router.get('/health', (req, res) => {
293
- res.json({
294
- success: true,
295
- aiAvailable: !!agentExecutor,
296
- hasOpenAIKey: hasOpenAIKey
297
- });
298
- });
609
+ /**
610
+ * 清理资源
611
+ */
612
+ async cleanup() {
613
+ if (this.vectorStore) {
614
+ // 清理向量存储资源
615
+ this.vectorStore = null;
616
+ }
617
+ console.log('代码修改Agent资源已清理');
618
+ }
619
+ }
620
+
621
+ // 创建增强的代码修改 Agent 实例
622
+ const enhancedCodeAgent = new EnhancedCodeModificationAgent();
623
+
624
+ // 导出功能
625
+ export { enhancedCodeAgent, EnhancedCodeModificationAgent };
299
626
 
300
- export default router;
627
+ // 默认导出
628
+ export default enhancedCodeAgent;