Release: v2.36.9 - Integrate Blog Production Manual & Writing Patterns
This commit is contained in:
+65
-14
@@ -416,9 +416,12 @@ export class AgentExecutor {
|
||||
|
||||
// 5. Execute Actions
|
||||
const rationale = this.parseRationale(aiResponseText);
|
||||
const assistantContent = enforceProjectClaimPolicyInAnswer(
|
||||
this.sanitizeAssistantContent(aiResponseText),
|
||||
secondBrainTrace
|
||||
const assistantContent = this.enforceLocalPathReviewAnswer(
|
||||
enforceProjectClaimPolicyInAnswer(
|
||||
this.sanitizeAssistantContent(aiResponseText),
|
||||
secondBrainTrace
|
||||
),
|
||||
localPathContext
|
||||
);
|
||||
const traceMarkdown = secondBrainTrace
|
||||
? renderSecondBrainTraceMarkdown(secondBrainTrace, !!options.secondBrainTraceDebug)
|
||||
@@ -623,7 +626,8 @@ export class AgentExecutor {
|
||||
const sections: string[] = [
|
||||
'[LOCAL PROJECT PATH PREFLIGHT]',
|
||||
'The user provided a local project path for review or analysis. Use this inspected context before asking for uploads.',
|
||||
'If access failed, explain the concrete failure. If access succeeded, proceed with code review from the scanned files.'
|
||||
'If access failed, explain the concrete failure. If access succeeded, proceed with code review from the scanned files.',
|
||||
'If access succeeded and priority file previews are present, do not say that code was not provided.'
|
||||
];
|
||||
|
||||
for (const candidate of candidates.slice(0, 2)) {
|
||||
@@ -665,14 +669,14 @@ export class AgentExecutor {
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
const tree = this.listProjectTree(absPath, absPath, 0, 2, 80);
|
||||
const priorityFiles = this.findPriorityProjectFiles(absPath).slice(0, 8);
|
||||
const tree = this.listProjectTree(absPath, absPath, 0, 4, 140);
|
||||
const priorityFiles = this.findPriorityProjectFiles(absPath).slice(0, 12);
|
||||
const previews = priorityFiles.map((file) => {
|
||||
try {
|
||||
const content = fs.readFileSync(file, 'utf8');
|
||||
return [
|
||||
`### ${path.relative(absPath, file)}`,
|
||||
summarizeText(content, 1800)
|
||||
summarizeText(content, 2200)
|
||||
].join('\n');
|
||||
} catch (error: any) {
|
||||
return `### ${path.relative(absPath, file)}\nRead failed: ${error.message}`;
|
||||
@@ -697,6 +701,35 @@ export class AgentExecutor {
|
||||
}
|
||||
}
|
||||
|
||||
private enforceLocalPathReviewAnswer(content: string, localPathContext: string): string {
|
||||
if (!localPathContext.includes('Access: succeeded')) {
|
||||
return content;
|
||||
}
|
||||
|
||||
const asksForUpload = /(코드(?:를|가)?\s*업로드|파일(?:을|를)?\s*업로드|소스\s*코드(?:를)?\s*업로드|코드를 제공|파일을 제공|folder path is not enough|upload (?:the )?(?:source )?code|please provide (?:the )?files)/i.test(content);
|
||||
const deniesCodeAccess = /(실제 코드 내용이 없|코드 내용이 없|코드가 없|코드를 볼 수 없|소스 코드를 볼 수 없|기술적인 진단.*수 없습니다)/i.test(content);
|
||||
if (!asksForUpload && !deniesCodeAccess) {
|
||||
return content;
|
||||
}
|
||||
|
||||
const header = [
|
||||
'## 경로 확인 결과',
|
||||
'',
|
||||
'제공된 로컬 프로젝트 경로에는 접근할 수 있고, 코드 파일도 확인되었습니다. 따라서 파일 업로드를 요청하는 대신, 확인된 파일 구조와 코드 프리뷰를 기준으로 리뷰를 진행해야 합니다.',
|
||||
'',
|
||||
'이전 응답의 "코드를 업로드해 주세요" 취지의 문장은 잘못된 안내입니다.'
|
||||
].join('\n');
|
||||
|
||||
return [
|
||||
header,
|
||||
'',
|
||||
content
|
||||
.replace(/.*(?:코드(?:를|가)?\s*업로드|파일(?:을|를)?\s*업로드|소스\s*코드(?:를)?\s*업로드|코드를 제공|파일을 제공).*$/gmi, '')
|
||||
.replace(/.*(?:실제 코드 내용이 없|코드 내용이 없|코드가 없|코드를 볼 수 없|소스 코드를 볼 수 없).*$/gmi, '')
|
||||
.trim()
|
||||
].filter(Boolean).join('\n\n');
|
||||
}
|
||||
|
||||
private listProjectTree(root: string, current: string, depth: number, maxDepth: number, limit: number): string {
|
||||
if (limit <= 0 || depth > maxDepth) {
|
||||
return '';
|
||||
@@ -741,8 +774,8 @@ export class AgentExecutor {
|
||||
'webpack.config.js'
|
||||
]);
|
||||
const results: string[] = [];
|
||||
const visit = (dir: string, depth: number) => {
|
||||
if (depth > 3 || results.length >= 14) return;
|
||||
const visit = (dir: string, depth: number, inSourceArea: boolean) => {
|
||||
if (depth > 6 || results.length >= 24) return;
|
||||
let entries: fs.Dirent[] = [];
|
||||
try {
|
||||
entries = fs.readdirSync(dir, { withFileTypes: true })
|
||||
@@ -754,16 +787,19 @@ export class AgentExecutor {
|
||||
for (const entry of entries) {
|
||||
const fullPath = path.join(dir, entry.name);
|
||||
if (entry.isDirectory()) {
|
||||
if (/^(src|app|pages|components|docs|lib|server|backend|frontend|config)$/i.test(entry.name)) {
|
||||
visit(fullPath, depth + 1);
|
||||
const nextInSourceArea = inSourceArea || /^(src|app|pages|components|docs|lib|server|backend|frontend|config|features|core|hooks|systems|store|model|utils|ui|api)$/i.test(entry.name);
|
||||
if (nextInSourceArea) {
|
||||
visit(fullPath, depth + 1, nextInSourceArea);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
const relative = path.relative(root, fullPath);
|
||||
const isSourceCode = /\.(ts|tsx|js|jsx)$/i.test(entry.name);
|
||||
if (
|
||||
exactNames.has(entry.name)
|
||||
|| /(^|[\\/])(src|app|pages|components|docs|lib|server|backend|frontend)[\\/].+\.(ts|tsx|js|jsx|md|json)$/i.test(relative)
|
||||
|| (inSourceArea && isSourceCode)
|
||||
|| /(^|[\\/])(src|app|pages|components|docs|lib|server|backend|frontend|features|core)[\\/].+\.(ts|tsx|js|jsx|md|json)$/i.test(relative)
|
||||
|| /\.(config|rc)\.(js|ts|json)$/i.test(entry.name)
|
||||
) {
|
||||
results.push(fullPath);
|
||||
@@ -771,8 +807,23 @@ export class AgentExecutor {
|
||||
}
|
||||
};
|
||||
|
||||
visit(root, 0);
|
||||
return Array.from(new Set(results));
|
||||
visit(root, 0, false);
|
||||
return Array.from(new Set(results)).sort((a, b) => {
|
||||
const rank = (file: string) => {
|
||||
const relative = path.relative(root, file);
|
||||
if (path.basename(file) === 'package.json') return 0;
|
||||
if (/readme\.md$/i.test(file)) return 1;
|
||||
if (/^src[\\/]App\.tsx$/i.test(relative)) return 2;
|
||||
if (/^src[\\/]main\.tsx$/i.test(relative)) return 3;
|
||||
if (/^src[\\/]features[\\/]game[\\/]hooks[\\/]useGameEngine\.ts$/i.test(relative)) return 4;
|
||||
if (/^src[\\/]features[\\/]game[\\/]systems[\\/]/i.test(relative)) return 5;
|
||||
if (/^src[\\/]features[\\/]game[\\/]ui[\\/]/i.test(relative)) return 6;
|
||||
if (/^src[\\/]/i.test(relative)) return 7;
|
||||
if (/^docs[\\/]|\.md$/i.test(relative)) return 8;
|
||||
return 9;
|
||||
};
|
||||
return rank(a) - rank(b) || a.localeCompare(b);
|
||||
});
|
||||
}
|
||||
|
||||
private buildMemoryContext(currentPrompt: string): string {
|
||||
|
||||
Reference in New Issue
Block a user