Version 2.43.0 Release: Contextual Project Trace & Overrides

This commit is contained in:
g1nation
2026-05-03 00:59:38 +09:00
parent 1d9c7f203f
commit d2c9f624b8
5 changed files with 84 additions and 4 deletions
+1 -1
View File
@@ -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.42.0",
"version": "2.43.0",
"publisher": "connectailab",
"license": "MIT",
"icon": "assets/icon.png",
+1 -1
View File
@@ -843,7 +843,7 @@ export class AgentExecutor {
}
private isBlockingProjectKnowledgeAnswer(content: string): boolean {
return /(블로킹 질문|어떤 기능 영역|어떤 부분.*먼저|어떤 기능이나 아키텍처|구체적인 방향|방향 설정이 필요|명확히 알려주시면|우선적으로 정리|최종 사용 목적|Question reason)/i.test(content);
return /(블로킹 질문|어떤 기능 영역|어떤 부분.*먼저|어떤 기능이나 아키텍처|구체적인 방향|방향 설정이 필요|명확히 알려주시면|우선적으로 정리|최종 사용 목적|Question reason|별도의 파일 기록.*생성되지|파일 기록이 생성되지|더 깊이 있는 분석.*지정|해당 기능.*지정하여 요청)/i.test(content);
}
private buildProjectKnowledgeFallbackAnswer(localPathContext: string): string {
+30 -2
View File
@@ -70,7 +70,8 @@ export function buildSecondBrainTrace(userQuery: string, brainRoot: string, opti
const files = findBrainFiles(brainRoot)
.filter((file) => includeRaw || !isRawConversationPath(path.relative(brainRoot, file)));
const terms = tokenize(retrievalQuery);
const scored = files.map((file) => scoreFile(file, brainRoot, terms, queryIntent))
const targetProject = inferTargetProject(query);
const scored = files.map((file) => scoreFile(file, brainRoot, terms, queryIntent, targetProject))
.filter((doc) => doc.score >= 0.25)
.sort((a, b) => b.score - a.score)
.slice(0, options.limit || 5);
@@ -370,7 +371,15 @@ function tokenize(value: string): string[] {
.filter((term) => term.length >= 2 && !stopWords.has(term));
}
function scoreFile(file: string, brainRoot: string, terms: string[], intent: SecondBrainQueryIntent): SecondBrainTraceDocument {
function inferTargetProject(query: string): string | undefined {
const pathMatch = query.match(/\/Volumes\/Data\/project\/Antigravity\/([^\s`"'<>/]+)/i);
if (pathMatch?.[1]) return pathMatch[1].toLowerCase();
const namedProject = query.match(/\b(connectai|datacollector|skybound)\b/i);
return namedProject?.[1]?.toLowerCase();
}
function scoreFile(file: string, brainRoot: string, terms: string[], intent: SecondBrainQueryIntent, targetProject?: string): SecondBrainTraceDocument {
const relative = path.relative(brainRoot, file);
const title = path.basename(file, path.extname(file));
const basename = relative.toLowerCase();
@@ -385,6 +394,9 @@ function scoreFile(file: string, brainRoot: string, terms: string[], intent: Sec
const lower = content.toLowerCase();
let score = pathPriority(relative, intent);
if (targetProject) {
score += projectRelevanceScore(relative, lower, targetProject);
}
for (const term of terms) {
if (basename.includes(term)) score += 4;
const matches = lower.split(term).length - 1;
@@ -405,6 +417,22 @@ function scoreFile(file: string, brainRoot: string, terms: string[], intent: Sec
};
}
function projectRelevanceScore(relativePath: string, lowerContent: string, targetProject: string): number {
const normalized = relativePath.toLowerCase();
let score = 0;
if (normalized.includes(targetProject)) score += 12;
const targetMatches = lowerContent.split(targetProject).length - 1;
if (targetMatches > 0) score += Math.min(targetMatches * 4, 20);
const otherProjectMatch = lowerContent.match(/(?:project|프로젝트|repository|repo)\s*[:]?\s*`?\/?volumes\/data\/project\/antigravity\/([a-z0-9_-]+)/i)
|| lowerContent.match(/(?:project|프로젝트)\s*[:]\s*([a-z0-9_-]+)/i);
const otherProject = otherProjectMatch?.[1]?.toLowerCase();
if (otherProject && otherProject !== targetProject) score -= 24;
if (normalized.includes('project_logs') && otherProject && otherProject !== targetProject) score -= 8;
return score;
}
function classifySourceType(relativePath: string, content: string): SecondBrainSourceType {
const normalized = relativePath.toLowerCase();
const lower = content.toLowerCase();
+12
View File
@@ -113,4 +113,16 @@ describe('local project path preflight', () => {
expect(fallback).toContain('ConnectAI Project Knowledge Overview');
expect(fallback).not.toContain('어떤 기능 영역을 가장 먼저');
});
it('treats no-record-created answers as incomplete project knowledge creation', () => {
const context: any = {
globalStorageUri: { fsPath: path.join(root, '.storage') },
workspaceState: stateStore(),
globalState: stateStore()
};
const agent = new AgentExecutor(context) as any;
const answer = 'Record Path Check: 요청하신 지식 생성 작업은 파일 목록 검토를 통해 완료되었으며, 별도의 파일 기록이 생성되지 않았습니다.';
expect(agent.isBlockingProjectKnowledgeAnswer(answer)).toBe(true);
});
});
+40
View File
@@ -215,4 +215,44 @@ describe('Second Brain Trace', () => {
expect(trace.retrievedDocuments[0].path).not.toContain('API Gateway.md');
expect(renderSecondBrainTraceContext(trace)).toContain('Approval likelihood is an inference');
});
it('prioritizes notes for the project named in a local Antigravity path', () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'second-brain-project-target-'));
try {
fs.mkdirSync(path.join(root, 'Project_Logs'), { recursive: true });
fs.writeFileSync(
path.join(root, 'Project_Logs', '2026-04-25-Datacollector_Fix.md'),
[
'# Datacollector Fix',
'',
'Project: Datacollector',
'Repository: `/Volumes/Data/project/Antigravity/Datacollector`',
'project antigravity repository documentation knowledge'
].join('\n'),
'utf8'
);
fs.writeFileSync(
path.join(root, 'Project_Logs', '2026-05-02-ConnectAI_Project_Knowledge.md'),
[
'# ConnectAI Project Knowledge',
'',
'Project: ConnectAI',
'Repository: `/Volumes/Data/project/Antigravity/ConnectAI`',
'ConnectAI project knowledge for local AI assistant, Second Brain Trace, and Project Chronicle.'
].join('\n'),
'utf8'
);
const trace = buildSecondBrainTrace(
'그러면 지금 /Volumes/Data/project/Antigravity/ConnectAI 프로젝트에 대한 지식을 만들어',
root,
{ force: true }
);
expect(trace.retrievedDocuments[0].path).toContain('ConnectAI_Project_Knowledge.md');
expect(trace.retrievedDocuments[0].path).not.toContain('Datacollector');
} finally {
fs.rmSync(root, { recursive: true, force: true });
}
});
});