Version 2.39.0 Release: Second Brain Inventory and empty response fix
This commit is contained in:
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
"name": "g1nation",
|
"name": "g1nation",
|
||||||
"displayName": "G1nation",
|
"displayName": "G1nation",
|
||||||
"description": "High-performance autonomous local AI coding agent for VS Code. Features vectorized inference, asynchronous task management, and 100% offline processing.",
|
"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",
|
"publisher": "connectailab",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"icon": "assets/icon.png",
|
"icon": "assets/icon.png",
|
||||||
|
|||||||
+47
-4
@@ -264,6 +264,9 @@ export class AgentExecutor {
|
|||||||
activeBrain.description ? `Description: ${activeBrain.description}` : '',
|
activeBrain.description ? `Description: ${activeBrain.description}` : '',
|
||||||
brainPreview ? `Available file examples:\n${brainPreview}` : 'Files: none found'
|
brainPreview ? `Available file examples:\n${brainPreview}` : 'Files: none found'
|
||||||
].filter(Boolean).join('\n');
|
].filter(Boolean).join('\n');
|
||||||
|
const brainInventoryCtx = prompt && this.isSecondBrainInventoryRequest(prompt)
|
||||||
|
? `\n\n${this.buildSecondBrainInventoryContext(activeBrain, brainFiles)}`
|
||||||
|
: '';
|
||||||
const editor = vscode.window.activeTextEditor;
|
const editor = vscode.window.activeTextEditor;
|
||||||
if (editor && editor.document.uri.scheme === 'file') {
|
if (editor && editor.document.uri.scheme === 'file') {
|
||||||
const text = editor.document.getText();
|
const text = editor.document.getText();
|
||||||
@@ -332,7 +335,7 @@ export class AgentExecutor {
|
|||||||
: '';
|
: '';
|
||||||
const memoryCtx = this.buildMemoryContext(prompt || '', activeBrain);
|
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[] = [
|
const messagesForRequest: ChatMessage[] = [
|
||||||
{ role: 'system', content: fullSystemPrompt, internal: true },
|
{ role: 'system', content: fullSystemPrompt, internal: true },
|
||||||
...reqMessages
|
...reqMessages
|
||||||
@@ -428,13 +431,10 @@ export class AgentExecutor {
|
|||||||
? renderSecondBrainTraceMarkdown(secondBrainTrace, !!options.secondBrainTraceDebug)
|
? renderSecondBrainTraceMarkdown(secondBrainTrace, !!options.secondBrainTraceDebug)
|
||||||
: '';
|
: '';
|
||||||
const finalAssistantContent = traceMarkdown ? `${assistantContent}\n${traceMarkdown}` : assistantContent;
|
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);
|
this.statusBarManager.updateStatus(AgentStatus.Executing);
|
||||||
const report = await this.executeActions(aiResponseText, rootPath, activeBrain);
|
const report = await this.executeActions(aiResponseText, rootPath, activeBrain);
|
||||||
if (!assistantContent.trim() && report.length === 0) {
|
if (!assistantContent.trim() && report.length === 0) {
|
||||||
this.chatHistory.pop();
|
|
||||||
logError('Model returned an empty response without actions.', { model: actualModel, engine, apiUrl, loopDepth });
|
logError('Model returned an empty response without actions.', { model: actualModel, engine, apiUrl, loopDepth });
|
||||||
this.webview.postMessage({
|
this.webview.postMessage({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
@@ -476,6 +476,8 @@ export class AgentExecutor {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const assistantMessage: ChatMessage = { role: 'assistant', content: finalAssistantContent, internal: false, rationale };
|
||||||
|
this.chatHistory.push(assistantMessage);
|
||||||
this.emitHistoryChanged();
|
this.emitHistoryChanged();
|
||||||
this.statusBarManager.updateStatus(AgentStatus.Success);
|
this.statusBarManager.updateStatus(AgentStatus.Success);
|
||||||
this.webview.postMessage({ type: 'streamChunk', value: finalAssistantContent });
|
this.webview.postMessage({ type: 'streamChunk', value: finalAssistantContent });
|
||||||
@@ -613,6 +615,47 @@ export class AgentExecutor {
|
|||||||
return /(second brain|2nd brain|제2뇌|브레인|brain|기억|기록|노트|문서|참고해서|사용해서|검색해서|근거|출처)/i.test(prompt);
|
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 {
|
private isStaleRun(runId: number): boolean {
|
||||||
return runId !== this.activeRunId;
|
return runId !== this.activeRunId;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user