Version 2.39.0 Release: Second Brain Inventory and empty response fix

This commit is contained in:
g1nation
2026-05-03 00:30:44 +09:00
parent d875ba7bc3
commit 33d73bdd1d
2 changed files with 49 additions and 6 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.38.0",
"version": "2.39.0",
"publisher": "connectailab",
"license": "MIT",
"icon": "assets/icon.png",
+48 -5
View File
@@ -264,6 +264,9 @@ export class AgentExecutor {
activeBrain.description ? `Description: ${activeBrain.description}` : '',
brainPreview ? `Available file examples:\n${brainPreview}` : 'Files: none found'
].filter(Boolean).join('\n');
const brainInventoryCtx = prompt && this.isSecondBrainInventoryRequest(prompt)
? `\n\n${this.buildSecondBrainInventoryContext(activeBrain, brainFiles)}`
: '';
const editor = vscode.window.activeTextEditor;
if (editor && editor.document.uri.scheme === 'file') {
const text = editor.document.getText();
@@ -332,7 +335,7 @@ export class AgentExecutor {
: '';
const memoryCtx = this.buildMemoryContext(prompt || '', activeBrain);
const fullSystemPrompt = `${agentSkillCtx}\n\n${systemPrompt}${internetCtx}${memoryCtx}${designerCtx}${secondBrainTraceCtx}\n\n[CONTEXT]\n${brainContext}\n${contextBlock}${negativeCtx}`;
const fullSystemPrompt = `${agentSkillCtx}\n\n${systemPrompt}${internetCtx}${memoryCtx}${designerCtx}${secondBrainTraceCtx}\n\n[CONTEXT]\n${brainContext}${brainInventoryCtx}\n${contextBlock}${negativeCtx}`;
const messagesForRequest: ChatMessage[] = [
{ role: 'system', content: fullSystemPrompt, internal: true },
...reqMessages
@@ -428,13 +431,10 @@ export class AgentExecutor {
? renderSecondBrainTraceMarkdown(secondBrainTrace, !!options.secondBrainTraceDebug)
: '';
const finalAssistantContent = traceMarkdown ? `${assistantContent}\n${traceMarkdown}` : assistantContent;
const assistantMessage: ChatMessage = { role: 'assistant', content: finalAssistantContent, internal: false, rationale };
this.chatHistory.push(assistantMessage);
this.statusBarManager.updateStatus(AgentStatus.Executing);
const report = await this.executeActions(aiResponseText, rootPath, activeBrain);
if (!assistantContent.trim() && report.length === 0) {
this.chatHistory.pop();
logError('Model returned an empty response without actions.', { model: actualModel, engine, apiUrl, loopDepth });
this.webview.postMessage({
type: 'error',
@@ -476,6 +476,8 @@ export class AgentExecutor {
return;
}
const assistantMessage: ChatMessage = { role: 'assistant', content: finalAssistantContent, internal: false, rationale };
this.chatHistory.push(assistantMessage);
this.emitHistoryChanged();
this.statusBarManager.updateStatus(AgentStatus.Success);
this.webview.postMessage({ type: 'streamChunk', value: finalAssistantContent });
@@ -613,6 +615,47 @@ export class AgentExecutor {
return /(second brain|2nd brain|제2뇌|브레인|brain|기억|기록|노트|문서|참고해서|사용해서|검색해서|근거|출처)/i.test(prompt);
}
private isSecondBrainInventoryRequest(prompt: string): boolean {
const normalized = prompt.toLowerCase();
const asksBrain = /(second brain|2nd brain|제2뇌|브레인|brain)/i.test(normalized);
const asksOverview = /(평가|분석|강점|약점|부족|무엇을 할 수|활용|전체|연결된|현재|inside|overview|inventory|strength|weakness)/i.test(normalized);
return asksBrain && asksOverview;
}
private buildSecondBrainInventoryContext(activeBrain: BrainProfile, brainFiles: string[]): string {
const relativeFiles = brainFiles.map((file) => path.relative(activeBrain.localBrainPath, file));
const directoryCounts = new Map<string, number>();
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, 12)
.map(([dir, count]) => `- ${dir}: ${count} markdown files`)
.join('\n');
const samples = relativeFiles
.slice(0, 40)
.map((file) => `- ${file}`)
.join('\n');
return [
'[SECOND BRAIN INVENTORY]',
'The user is asking about the currently selected Second Brain as a knowledge base. Use this inventory as direct evidence.',
`Selected brain name: ${activeBrain.name}`,
`Selected brain path: ${activeBrain.localBrainPath}`,
`Markdown file count: ${brainFiles.length}`,
brainFiles.length > 0
? 'Do not say the Second Brain has no data, no files, or cannot be evaluated because files were not provided.'
: 'No Markdown files were found in the selected Second Brain path.',
topDirectories ? `Top-level distribution:\n${topDirectories}` : 'Top-level distribution: none',
samples ? `Sample files:\n${samples}` : 'Sample files: none',
'For strengths and weaknesses, infer from the inventory and selected note excerpts. Mark broad conclusions as inference when they are not directly proven.'
].join('\n');
}
private isStaleRun(runId: number): boolean {
return runId !== this.activeRunId;
}