Skip to content

Commit 38fdae9

Browse files
committed
fix:优化自动修复机制
1 parent 4f08a1f commit 38fdae9

File tree

4 files changed

+101
-24
lines changed

4 files changed

+101
-24
lines changed

prompt/chat.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
�½�һ���������ť
2+
���Ժ���һ������ҳ
3+
���Ժ�ģ��ֱ�ӽ���ʽ����
4+
���ҿ���������������һ���µ����죨ҳ�����ϽǸ�������ҳ��
5+
�����֧�ֶ��У�����������롣��һ�����Ͱ�ť
6+
ͬʱ֧��ѡ���ļ��IJ������ݣ��Ҽ��˵�ֱ�ӷ���һ��׼��������������׷������Ȼ����Է���
7+
�Ѿ����͵���Ϣ�������±༭
8+
�������apiʧ�ܣ���ʾһ��ʧ�ܵĻظ�����������ط��������

src/cvbManager.ts

Lines changed: 86 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -424,20 +424,20 @@ TCVB 格式规范:
424424
1. 全局替换操作(GLOBAL-REPLACE):
425425
## OPERATION:GLOBAL-REPLACE
426426
## OLD_CONTENT
427-
[markdown代码块:被全局替换的内容]
427+
[markdown代码块:被全局替换的内容, 可以在需要被替换的文本前后包含一些上下文帮助精确替换,但是不要太长]
428428
## NEW_CONTENT
429429
[markdown代码块:新内容]
430430
431-
2. 精确替换操作(EXACT-REPLACE),用于替换全局替换无法精准定位的情况:
431+
2. 精确替换操作(EXACT-REPLACE),用于替换全局替换无法精准定位的情况(如果GLOBAL-REPLACE可以定位到,没有歧义,就优先用GLOBAL-REPLACE):
432432
## OPERATION:EXACT-REPLACE
433+
## BEFORE_ANCHOR
434+
[markdown代码块:OLD_CONTENT之前的几行内容, 用来划定范围上半段锚点,避免有多个类似匹配, 不能和OLD_CONTENT重合。不要太长,可以精确定位到位置即可]
435+
## AFTER_ANCHOR
436+
[markdown代码块:OLD_CONTENT之后的几行内容, 用来划定范围下半段锚点,避免有多个类似匹配, 不能和OLD_CONTENT重合,不要太长,可以精确定位到位置即可]
433437
## OLD_CONTENT
434438
[markdown代码块:被替换内容]
435439
## NEW_CONTENT
436440
[markdown代码块:新内容]
437-
## BEFORE_ANCHOR
438-
[markdown代码块:OLD_CONTENT之前的几行内容, 用来划定范围上半段锚点,避免有多个类似匹配, 不能和OLD_CONTENT重合]
439-
## AFTER_ANCHOR
440-
[markdown代码块:OLD_CONTENT之后的几行内容, 用来划定范围下半段锚点,避免有多个类似匹配, 不能和OLD_CONTENT重合]
441441
442442
3. 创建操作(CREATE):
443443
## OPERATION:CREATE
@@ -501,41 +501,105 @@ export function mergeCvb(baseCvb: Cvb, tcvb: TCVB) : Cvb
501501
}
502502
}
503503
catch (err: any) {
504-
throw new Error(`合并CVB失败: ${err.message}`);
504+
throw new Error(`TCVB格式可能有问题,尝试增量修改CVB时出错: ${err.message}`);
505505
}
506506

507507
return rebuildCvb(baseCvb, mapMergedFiles);
508508
}
509509

510-
function applyExactReplace(strContent: string, op: ExactReplaceOperation): string {
511-
// 构建匹配模式:前锚点 + 中间内容1 + 旧内容 + 中间内容2 + 后锚点
512-
const regPattern = buildPattern(op.m_strBeforeAnchor, op.m_strOldContent, op.m_strAfterAnchor);
513-
// 替换为:前锚点 + 中间内容1 + 新内容 + 中间内容2 + 后锚点
514-
const strReplacement = op.m_strBeforeAnchor + '$1' + op.m_strNewContent + '$2' + op.m_strAfterAnchor;
510+
function diagnoseMatchFailure(strContent: string, op: ExactReplaceOperation): string
511+
{
512+
function findLineNumber(content: string, pattern: RegExp): number[]
513+
{
514+
const lines = content.split("\n");
515+
return lines
516+
.map((line, index) => (pattern.test(line) ? index + 1 : -1))
517+
.filter(index => index !== -1);
518+
}
515519

516-
regPattern.lastIndex = 0; // 重置正则表达式的状态
517-
if (!regPattern.test(strContent)) {
518-
console.log("以下表达式:\n" + regPattern + "\n 无法匹配:\n");
519-
throw new Error(`Exact-replace操作失败:文件 "${op.m_strFilePath}" 中未找到匹配项。请检查前后锚点及旧内容是否正确。## OLD_CONTENT\n${op.m_strOldContent}\n\n## BEFORE_ANCHOR\n${op.m_strBeforeAnchor}\n\n## AFTER_ANCHOR\n${op.m_strAfterAnchor} `);
520-
}
521-
regPattern.lastIndex = 0; // 再次重置以备替换
520+
let errorMessages: string[] = [];
521+
const beforeAnchorPattern = new RegExp(op.m_strBeforeAnchor, "gm");
522+
const afterAnchorPattern = new RegExp(op.m_strAfterAnchor, "gm");
523+
const oldContentPattern = new RegExp(op.m_strOldContent, "gm");
524+
525+
const beforeAnchorLines = findLineNumber(strContent, beforeAnchorPattern);
526+
const afterAnchorLines = findLineNumber(strContent, afterAnchorPattern);
527+
const oldContentLines = findLineNumber(strContent, oldContentPattern);
528+
529+
if (beforeAnchorLines.length === 0)
530+
{
531+
errorMessages.push(`FILE: ${op.m_strFilePath} 未找到 BEFORE_ANCHOR:\n\`\`\`\n${op.m_strBeforeAnchor}\n\`\`\``);
532+
}
533+
534+
if (afterAnchorLines.length === 0)
535+
{
536+
errorMessages.push(`FILE: ${op.m_strFilePath} 未找到 AFTER_ANCHOR:\n\`\`\`\n${op.m_strAfterAnchor}\n\`\`\``);
537+
}
538+
539+
if (oldContentLines.length === 0)
540+
{
541+
errorMessages.push(`FILE: ${op.m_strFilePath} 未找到 OLD_CONTENT:\n\`\`\`\n${op.m_strOldContent}\n\`\`\``);
542+
}
543+
544+
if (errorMessages.length === 0)
545+
{
546+
const minBeforeLine = Math.min(...beforeAnchorLines);
547+
const maxAfterLine = Math.max(...afterAnchorLines);
548+
const minOldLine = Math.min(...oldContentLines);
549+
const maxOldLine = Math.max(...oldContentLines);
550+
551+
if (minOldLine < minBeforeLine || maxOldLine > maxAfterLine)
552+
{
553+
errorMessages.push(
554+
`FILE: ${op.m_strFilePath} OLD_CONTENT 应该在 BEFORE_ANCHOR 和 AFTER_ANCHOR 之间:\nBEFORE_ANCHOR:\n\`\`\`\n${op.m_strBeforeAnchor}\n\`\`\`\nOLD_CONTENT:\n\`\`\`\n${op.m_strOldContent}\n\`\`\`\nAFTER_ANCHOR:\n\`\`\`\n${op.m_strAfterAnchor}\n\`\`\``
555+
);
556+
}
557+
}
558+
559+
return errorMessages.length > 0 ? errorMessages.join("\n") : "";
560+
}
561+
562+
function applyExactReplace(strContent: string, op: ExactReplaceOperation): string
563+
{
564+
const regPattern = buildPattern(op.m_strBeforeAnchor, op.m_strOldContent, op.m_strAfterAnchor);
565+
const strReplacement = op.m_strBeforeAnchor + '$1' + op.m_strNewContent + '$2' + op.m_strAfterAnchor;
566+
567+
regPattern.lastIndex = 0;
568+
if (!regPattern.test(strContent))
569+
{
570+
const diagnosticMessage = diagnoseMatchFailure(strContent, op);
571+
const errorMsg = `## EXACT-REPLACE 失败\n` +
572+
`### FILE: ${op.m_strFilePath}\n` +
573+
`### BEFORE_ANCHOR:\n\`\`\`\n${op.m_strBeforeAnchor}\n\`\`\`\n` +
574+
`### AFTER_ANCHOR:\n\`\`\`\n${op.m_strAfterAnchor}\n\`\`\`\n` +
575+
`### OLD_CONTENT:\n\`\`\`\n${op.m_strOldContent}\n\`\`\`\n` +
576+
`### NEW_CONTENT:\n\`\`\`\n${op.m_strNewContent}\n\`\`\`\n` +
577+
`### 错误:\n${diagnosticMessage}`;
578+
579+
console.log(errorMsg);
580+
throw new Error(errorMsg);
581+
}
522582

523-
return strContent.replace(regPattern, strReplacement);
583+
regPattern.lastIndex = 0;
584+
return strContent.replace(regPattern, strReplacement);
524585
}
525586

526587
function applyGlobalReplace(strContent: string, op: GlobalReplaceOperation) : string
527588
{
528589
if ( op.m_strOldContent === "" )
529590
{
530-
throw new Error(`全局替换为空`);
591+
const errorMsg = `GLOBAL-REPLACE 失败:FILE:"${op.m_strFilePath}" OLD_CONTENT 是空的"`;
592+
console.log(errorMsg);
593+
throw new Error(errorMsg);
531594
}
532595

533596
const regPattern: RegExp = new RegExp(normalizeLineWhitespace(escapeRegExp(op.m_strOldContent)), 'gs');
534597

535598
regPattern.lastIndex = 0;
536599
if (!regPattern.test(strContent)) {
537-
console.log("以下表达式:\n" + regPattern + "\n 无法匹配");
538-
throw new Error(`全局替换失败:文件 "${op.m_strFilePath}" 中未找到旧内容 "${op.m_strOldContent}"。`);
600+
const errorMsg = `GLOBAL-REPLACE 失败:FILE:"${op.m_strFilePath}" 中未找到OLD_CONTENT: "${op.m_strOldContent}"`;
601+
console.log(errorMsg);
602+
throw new Error(errorMsg);
539603
}
540604
regPattern.lastIndex = 0;
541605

src/deepseekApi.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ export async function callDeepSeekFixApi(
203203
let messages_body = lastMessageBody;
204204

205205
messages_body.push(
206-
{ role: 'user', content:`接收的数据格式有错误: ${errorInfo}, 修正后重新完整输出:`}
206+
{ role: 'user', content:`接收的数据格式有错误: ${errorInfo}, 根据错误信息修正错误,其他的地方保持原样。然后重新完整输出:`}
207207
);
208208

209209
let fullResponse = '';
@@ -241,6 +241,11 @@ export async function callDeepSeekFixApi(
241241
}
242242
}
243243

244+
fullResponse = chunkResponse;
245+
246+
messages_body.push({ role: 'assistant', content: fullResponse });
247+
lastMessageBody = messages_body;
248+
244249
return fullResponse;
245250
}
246251

src/extension.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ export async function doUploadCommand(cvbFilePath: string, userPrompt: string, o
7272
vscode.window.showInformationMessage(`API response saved as CVB file: ${newCvbFilePath}`);
7373
}
7474
} catch (err : any){
75-
vscode.window.showInformationMessage(`API response have error, try fix ...`);
75+
vscode.window.showInformationMessage(`API response have error ${err.message}, try fix ...`);
7676
apiResponse = await callDeepSeekFixApi(err.message, outputChannel, true, getCurrentOperationController().signal);
7777
processSuccess = false;
7878
}

0 commit comments

Comments
 (0)