feat: v2.62.0 - Astra Autonomous Loop (AAL) foundation & enhanced file analysis
This commit is contained in:
+77
-10
@@ -793,7 +793,7 @@ export class AgentExecutor {
|
||||
return '';
|
||||
}
|
||||
|
||||
const candidates = this.extractLocalProjectPaths(prompt);
|
||||
const candidates = this.extractLocalProjectPaths(prompt, rootPath);
|
||||
if (candidates.length === 0) {
|
||||
return '';
|
||||
}
|
||||
@@ -803,6 +803,11 @@ export class AgentExecutor {
|
||||
'[LOCAL PROJECT PATH PREFLIGHT]',
|
||||
`Local project intent: ${intent}`,
|
||||
this.buildLocalProjectIntentGuidance(intent),
|
||||
'[CRITICAL DIRECTIVE] The file contents below have already been read from the local filesystem. You MUST use them directly in your analysis.',
|
||||
'DO NOT ask the user to provide, upload, paste, or share the file contents. They are already included below.',
|
||||
'DO NOT say "파일 내용을 보여주세요", "코드를 공유해 주세요", or "파일을 제공해 주세요". The files have been pre-loaded.',
|
||||
'If access succeeded, proceed IMMEDIATELY with analysis. Do not ask for confirmation like "진행할까요?" or "분석을 시작할까요?". Just do it.',
|
||||
'If multiple files are mentioned, analyze them sequentially in the order the user specified without pausing for confirmation between each.',
|
||||
'The user provided a local project path for review, analysis, documentation, or knowledge creation. 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 succeeded and priority file previews are present, do not say that code was not provided.',
|
||||
@@ -812,7 +817,7 @@ export class AgentExecutor {
|
||||
'If intent is thinking, act as a project thinking partner and give a clear verdict grounded in the inspected files.'
|
||||
];
|
||||
|
||||
for (const candidate of candidates.slice(0, 2)) {
|
||||
for (const candidate of candidates.slice(0, 5)) {
|
||||
sections.push(this.inspectLocalProjectPath(candidate, rootPath));
|
||||
}
|
||||
|
||||
@@ -1004,8 +1009,27 @@ export class AgentExecutor {
|
||||
}
|
||||
|
||||
private shouldPreflightLocalProjectPath(prompt: string): boolean {
|
||||
return /(검토|리뷰|분석|확인|봐줘|고쳐|개선|디버그|지식|문서화|문서|정리|기록|위키|저장|만들|생성|설계|아키텍처|구조|방향|의견|생각|판단|어떤\s*거?\s*같|어때|knowledge|document|documentation|wiki|summari[sz]e|review|analy[sz]e|inspect|debug|fix|improve|architecture|design|structure|opinion|think|judge)/i.test(prompt)
|
||||
&& /\/Volumes\/Data\/project\/Antigravity\/[^\s`"'<>]+/i.test(prompt);
|
||||
const hasActionKeyword = /(검토|리뷰|분석|확인|봐줘|읽어|열어|파일|내용|코드|고쳐|개선|디버그|지식|문서화|문서|정리|기록|위키|저장|만들|생성|설계|아키텍처|구조|방향|의견|생각|판단|어떤\s*거?\s*같|어때|순서대로|보면|knowledge|document|documentation|wiki|summari[sz]e|review|analy[sz]e|inspect|debug|fix|improve|architecture|design|structure|opinion|think|judge|read|open|file|content|code)/i.test(prompt);
|
||||
const hasLocalPath = this.containsLocalFilePath(prompt);
|
||||
return hasActionKeyword && hasLocalPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 프롬프트에 로컬 파일/디렉토리 경로가 포함되어 있는지 감지합니다.
|
||||
* 절대 경로: /Volumes/, /Users/, /home/, ~/
|
||||
* 상대 경로: src/..., lib/..., components/..., tests/... 등 + 파일 확장자
|
||||
*/
|
||||
private containsLocalFilePath(prompt: string): boolean {
|
||||
// 절대 경로
|
||||
if (/(?:\/Volumes\/|\/Users\/|\/home\/|~\/)[^\s`"'<>]+/i.test(prompt)) {
|
||||
return true;
|
||||
}
|
||||
// 상대 경로 패턴: 디렉토리/파일명.확장자 형태 (src/lib/engine.ts, components/App.tsx 등)
|
||||
if (/(?:^|[\s,])(?:src|lib|components|pages|app|tests|test|utils|core|features|hooks|services|config|public|assets|docs|scripts)\//i.test(prompt)
|
||||
&& /\.[a-z]{1,6}(?:[\s,;)\]]|$)/i.test(prompt)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private isProjectKnowledgeCreationRequest(prompt: string): boolean {
|
||||
@@ -1017,7 +1041,7 @@ export class AgentExecutor {
|
||||
}
|
||||
|
||||
private classifyLocalProjectIntent(prompt: string): LocalProjectIntent {
|
||||
if (!/\/Volumes\/Data\/project\/Antigravity\/[^\s`"'<>]+/i.test(prompt)) {
|
||||
if (!this.containsLocalFilePath(prompt)) {
|
||||
return 'general';
|
||||
}
|
||||
|
||||
@@ -1323,9 +1347,46 @@ export class AgentExecutor {
|
||||
.sort((a, b) => fs.statSync(b).mtimeMs - fs.statSync(a).mtimeMs)[0] || null;
|
||||
}
|
||||
|
||||
private extractLocalProjectPaths(prompt: string): string[] {
|
||||
const matches = prompt.match(/\/Volumes\/Data\/project\/Antigravity\/[^\s`"'<>]+/gi) || [];
|
||||
return Array.from(new Set(matches.map((value) => value.replace(/[),.;\]]+$/g, ''))));
|
||||
private extractLocalProjectPaths(prompt: string, rootPath?: string): string[] {
|
||||
const results: string[] = [];
|
||||
|
||||
// 1. 절대 경로 감지: /Volumes/, /Users/, /home/, ~/
|
||||
const absMatches = prompt.match(/(?:\/Volumes\/|\/Users\/|\/home\/|~\/)[^\s`"'<>]+/gi) || [];
|
||||
for (const m of absMatches) {
|
||||
results.push(m.replace(/[),.;\]]+$/g, ''));
|
||||
}
|
||||
|
||||
// 2. 상대 경로 감지: src/lib/engine.ts, components/App.tsx 등
|
||||
const relMatches = prompt.match(/(?:^|[\s,])(?:(?:src|lib|components|pages|app|tests|test|utils|core|features|hooks|services|config|public|assets|docs|scripts)\/[^\s`"'<>]+\.[a-z]{1,6})/gi) || [];
|
||||
for (const m of relMatches) {
|
||||
const cleaned = m.trim().replace(/^,\s*/, '').replace(/[),.;\]]+$/g, '');
|
||||
if (rootPath) {
|
||||
// 상대 경로를 워크스페이스 기준 절대 경로로 변환
|
||||
const absPath = path.resolve(rootPath, cleaned);
|
||||
if (fs.existsSync(absPath)) {
|
||||
results.push(absPath);
|
||||
} else {
|
||||
// 프로젝트 루트 하위 프로젝트들에서도 검색
|
||||
const subProjects = ['ConnectAI', 'Datacollector_MAC', 'Agent', 'skybound'];
|
||||
let found = false;
|
||||
for (const sub of subProjects) {
|
||||
const subPath = path.resolve(rootPath, sub, cleaned);
|
||||
if (fs.existsSync(subPath)) {
|
||||
results.push(subPath);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
results.push(absPath); // fallback: 원래 경로 그대로
|
||||
}
|
||||
}
|
||||
} else {
|
||||
results.push(cleaned);
|
||||
}
|
||||
}
|
||||
|
||||
return Array.from(new Set(results));
|
||||
}
|
||||
|
||||
private inspectLocalProjectPath(targetPath: string, rootPath: string): string {
|
||||
@@ -1342,11 +1403,17 @@ export class AgentExecutor {
|
||||
const stat = fs.statSync(absPath);
|
||||
if (!stat.isDirectory()) {
|
||||
const content = fs.readFileSync(absPath, 'utf8');
|
||||
const fileName = path.basename(absPath);
|
||||
const ext = path.extname(absPath).toLowerCase();
|
||||
// 코드/문서 파일은 더 많은 내용을 제공하여 정밀한 분석이 가능하도록 함
|
||||
const isCodeOrDoc = ['.ts', '.js', '.tsx', '.jsx', '.py', '.java', '.go', '.rs', '.md', '.json', '.yaml', '.yml', '.toml', '.css', '.html', '.sql', '.sh', '.zsh', '.env', '.xml', '.swift', '.kt'].includes(ext);
|
||||
const previewLimit = isCodeOrDoc ? 8000 : 2000;
|
||||
return [
|
||||
`Path: ${targetPath}`,
|
||||
'Access: succeeded',
|
||||
'Type: file',
|
||||
`Preview:\n${summarizeText(content, 1200)}`
|
||||
`Type: file (${fileName})`,
|
||||
`Size: ${content.length} characters`,
|
||||
`Full content (${content.length <= previewLimit ? 'complete' : `first ${previewLimit} chars`}):\n\`\`\`${ext.slice(1)}\n${summarizeText(content, previewLimit)}\n\`\`\``
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user