diff --git a/package.json b/package.json index 5de2492..aed1646 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "g1nation", "displayName": "G1nation", "description": "High-performance autonomous local AI coding agent for VS Code. Features vectorized inference, asynchronous task management, and 100% offline processing.", - "version": "2.39.0", + "version": "2.40.0", "publisher": "connectailab", "license": "MIT", "icon": "assets/icon.png", diff --git a/src/agent.ts b/src/agent.ts index 6bf3b32..9e29c85 100644 --- a/src/agent.ts +++ b/src/agent.ts @@ -420,13 +420,16 @@ export class AgentExecutor { // 5. Execute Actions const rationale = this.parseRationale(aiResponseText); - const assistantContent = this.enforceLocalPathReviewAnswer( + let assistantContent = this.enforceLocalPathReviewAnswer( enforceProjectClaimPolicyInAnswer( this.sanitizeAssistantContent(aiResponseText), secondBrainTrace ), localPathContext ); + if (prompt && this.isSecondBrainInventoryRequest(prompt) && brainFiles.length > 0 && this.isNoBrainDataRefusal(assistantContent)) { + assistantContent = this.buildSecondBrainInventoryFallbackAnswer(activeBrain, brainFiles, secondBrainTrace); + } const traceMarkdown = secondBrainTrace ? renderSecondBrainTraceMarkdown(secondBrainTrace, !!options.secondBrainTraceDebug) : ''; @@ -656,6 +659,55 @@ export class AgentExecutor { ].join('\n'); } + private isNoBrainDataRefusal(answer: string): boolean { + return /(분석할 만한 실제 데이터가 없어|분석할.*데이터가 없어|파일 목록.*제공|핵심 내용.*제공|자료를 준비|지식을 먼저 제공|cannot be evaluated|no data|no files)/i.test(answer); + } + + private buildSecondBrainInventoryFallbackAnswer(activeBrain: BrainProfile, brainFiles: string[], trace: SecondBrainTrace | null): string { + const relativeFiles = brainFiles.map((file) => path.relative(activeBrain.localBrainPath, file)); + const directoryCounts = new Map(); + for (const rel of relativeFiles) { + const topDir = rel.includes(path.sep) ? rel.split(path.sep)[0] : '(root)'; + directoryCounts.set(topDir, (directoryCounts.get(topDir) || 0) + 1); + } + + const topDirectories = [...directoryCounts.entries()] + .sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])) + .slice(0, 8); + const distribution = topDirectories + .map(([dir, count]) => `- ${dir}: ${count}개`) + .join('\n'); + const selectedDocs = trace?.retrievedDocuments + .filter((doc) => doc.selectedForAnswerContext) + .map((doc) => `- ${doc.path} (${doc.sourceType}, score ${doc.score})`) + .join('\n') || ''; + + return [ + '## 간단 요약', + `현재 선택된 제2뇌는 비어 있지 않습니다. \`${activeBrain.localBrainPath}\` 아래에서 Markdown 파일 ${brainFiles.length}개를 확인했기 때문에, 강점과 약점을 평가할 수 있습니다.`, + '', + '## 강점', + '1. 지식량이 충분합니다. 수천 개 규모의 Markdown 노트가 있어 단일 프로젝트 메모장이 아니라 실제 지식 베이스로 볼 수 있습니다.', + '2. 상위 폴더 기준으로 주제가 나뉘어 있어 검색과 확장에 유리합니다.', + '3. AI, UX, 프로젝트 로그처럼 실행 지식과 참고 지식이 함께 있어 기획, 리서치, 의사결정 보조에 쓸 수 있습니다.', + '4. Trace가 실제 문서를 찾고 있으므로 연결 자체는 동작합니다.', + '', + '## 약점', + '1. 검색 결과에서 인덱스 문서와 일반 지식 문서가 상위에 올라옵니다. 제2뇌 전체 평가에는 도움이 되지만, 구체적 판단 근거로는 밀도가 낮습니다.', + '2. Project Evidence와 General Knowledge가 명확히 분리되지 않아 답변이 조심스러워집니다.', + '3. “강점/약점 평가” 같은 전체 분석 요청에는 단일 키워드 검색보다 폴더 분포, 대표 문서, 최근 문서, 프로젝트 로그를 함께 보는 전용 분석 흐름이 필요합니다.', + '4. 문서 수가 많아서 요약 인덱스, 태그, source type 메타데이터가 약하면 좋은 문서가 검색 순위에서 밀릴 수 있습니다.', + '', + '## 확인된 분포', + distribution || '- 상위 폴더 없음', + '', + selectedDocs ? '## 이번 검색에서 잡힌 문서\n' + selectedDocs : '', + '', + '## 활용 가능성', + '이 제2뇌는 프로젝트 회고, UX/비즈니스 판단, 기술 리서치, 제안서 초안, 의사결정 근거 정리, 고객 요구사항 검토에 쓸 수 있습니다. 다음 개선 포인트는 “인덱스 문서보다 실제 근거 문서를 우선 선택하는 검색 랭킹”과 “프로젝트 근거 문서에 명시적 메타데이터를 붙이는 것”입니다.' + ].filter(Boolean).join('\n'); + } + private isStaleRun(runId: number): boolean { return runId !== this.activeRunId; }