diff --git a/package-lock.json b/package-lock.json index abbcb50..852b17e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "g1nation", - "version": "2.34.1", + "version": "2.36.9", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "g1nation", - "version": "2.34.1", + "version": "2.36.9", "license": "MIT", "dependencies": { "marked": "^18.0.2" diff --git a/package.json b/package.json index b91e3ea..49743f4 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.36.9", + "version": "2.38.0", "publisher": "connectailab", "license": "MIT", "icon": "assets/icon.png", diff --git a/src/agent.ts b/src/agent.ts index fe2ece3..ad73f59 100644 --- a/src/agent.ts +++ b/src/agent.ts @@ -3,11 +3,9 @@ import * as path from 'path'; import * as fs from 'fs'; // axios removed import { - _getBrainDir, findBrainFiles, getSystemPrompt, shouldAutoPushBrain, - getSecondBrainRepo, buildApiUrl, getActiveBrainProfile, logError, @@ -15,7 +13,7 @@ import { resolveEngine, summarizeText } from './utils'; -import { getConfig, EXCLUDED_DIRS } from './config'; +import { BrainProfile, getConfig, EXCLUDED_DIRS } from './config'; import { validatePath, sanitizeCommand } from './security'; import { TransactionManager } from './core/transaction'; import { SessionManager } from './core/session'; @@ -192,7 +190,8 @@ export class AgentExecutor { negativePrompt?: string, designerContext?: string, secondBrainTraceEnabled?: boolean, - secondBrainTraceDebug?: boolean + secondBrainTraceDebug?: boolean, + brainProfileId?: string } ) { const { @@ -241,7 +240,9 @@ export class AgentExecutor { let contextBlock = ''; const config = getConfig(); - const activeBrain = getActiveBrainProfile(); + const activeBrain = options.brainProfileId + ? (config.brainProfiles.find((profile) => profile.id === options.brainProfileId) || getActiveBrainProfile()) + : getActiveBrainProfile(); const brainFiles = findBrainFiles(activeBrain.localBrainPath); let secondBrainTrace: SecondBrainTrace | null = null; if (options.secondBrainTraceEnabled && prompt && loopDepth === 0) { @@ -329,7 +330,7 @@ export class AgentExecutor { const secondBrainTraceCtx = secondBrainTrace ? `\n\n${renderSecondBrainTraceContext(secondBrainTrace)}` : ''; - const memoryCtx = this.buildMemoryContext(prompt || ''); + 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 messagesForRequest: ChatMessage[] = [ @@ -431,7 +432,7 @@ export class AgentExecutor { this.chatHistory.push(assistantMessage); this.statusBarManager.updateStatus(AgentStatus.Executing); - const report = await this.executeActions(aiResponseText, rootPath); + 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 }); @@ -511,7 +512,10 @@ export class AgentExecutor { try { let brainContext = 'No specific context available'; try { - const activeBrain = getActiveBrainProfile(); + const config = getConfig(); + const activeBrain = options.brainProfileId + ? (config.brainProfiles.find((profile) => profile.id === options.brainProfileId) || getActiveBrainProfile()) + : getActiveBrainProfile(); const brainFiles = findBrainFiles(activeBrain.localBrainPath); brainContext = `Brain: ${activeBrain.name}, Files: ${brainFiles.length}`; } catch (ctxErr) { @@ -826,7 +830,7 @@ export class AgentExecutor { }); } - private buildMemoryContext(currentPrompt: string): string { + private buildMemoryContext(currentPrompt: string, activeBrain: BrainProfile): string { const config = getConfig(); if (!config.memoryEnabled) return ''; @@ -848,7 +852,7 @@ export class AgentExecutor { }) .join('\n'); - const longTerm = this.findRelevantBrainMemory(currentPrompt, config.memoryLongTermFiles); + const longTerm = this.findRelevantBrainMemory(currentPrompt, config.memoryLongTermFiles, activeBrain); const sections = [ shortTerm ? `### Short-Term Memory\n${shortTerm}` : '', mediumTerm ? `### Medium-Term Memory\n${mediumTerm}` : '', @@ -865,11 +869,10 @@ export class AgentExecutor { ].join('\n'); } - private findRelevantBrainMemory(currentPrompt: string, limit: number): string { + private findRelevantBrainMemory(currentPrompt: string, limit: number, activeBrain: BrainProfile): string { if (limit <= 0) return ''; try { - const activeBrain = getActiveBrainProfile(); const files = findBrainFiles(activeBrain.localBrainPath); const terms = currentPrompt .toLowerCase() @@ -1043,9 +1046,10 @@ export class AgentExecutor { return candidates; } - private async executeActions(aiMessage: string, rootPath: string): Promise { + private async executeActions(aiMessage: string, rootPath: string, activeBrain: BrainProfile): Promise { const report: string[] = []; let brainModified = false; + const activeBrainDir = activeBrain.localBrainPath; let firstCreatedFile: string | undefined; try { @@ -1066,7 +1070,7 @@ export class AgentExecutor { report.push(`✅ Created: ${relPath}`); if (!firstCreatedFile) firstCreatedFile = absPath; - if (absPath.startsWith(_getBrainDir())) brainModified = true; + if (absPath.startsWith(activeBrainDir)) brainModified = true; } catch (err: any) { throw new FileSystemError(`Failed to create file ${relPath}: ${err.message}`, relPath, err); } @@ -1099,7 +1103,7 @@ export class AgentExecutor { fs.writeFileSync(absPath, editContent, 'utf-8'); report.push(`📝 Updated (Full): ${relPath}`); } - if (absPath.startsWith(_getBrainDir())) brainModified = true; + if (absPath.startsWith(activeBrainDir)) brainModified = true; } else { report.push(`❌ File not found: ${relPath}`); } @@ -1184,7 +1188,7 @@ export class AgentExecutor { while ((match = listBrainRegex.exec(aiMessage)) !== null) { const relPath = match[1].trim() || '.'; try { - const brainDir = _getBrainDir(); + const brainDir = activeBrainDir; const absPath = path.join(brainDir, relPath); if (fs.existsSync(absPath) && fs.statSync(absPath).isDirectory()) { const entries = fs.readdirSync(absPath, { withFileTypes: true }); @@ -1209,7 +1213,7 @@ export class AgentExecutor { while ((match = brainRegex.exec(aiMessage)) !== null) { const fileName = match[1].trim(); try { - const brainDir = _getBrainDir(); + const brainDir = activeBrainDir; const files = findBrainFiles(brainDir); const targetFile = files.find((f: string) => path.basename(f) === fileName || f.endsWith(fileName)); @@ -1242,8 +1246,8 @@ export class AgentExecutor { } // Brain Sync Logic - if (brainModified && shouldAutoPushBrain() && getSecondBrainRepo()) { - this.syncBrain(); + if (brainModified && shouldAutoPushBrain() && activeBrain.secondBrainRepo) { + this.syncBrain(activeBrainDir); } const config = getConfig(); @@ -1262,22 +1266,11 @@ export class AgentExecutor { // We return the report with the failure message instead of throwing // so the agent can see the failure and decide what to do next } - - if (firstCreatedFile) { - vscode.window.showTextDocument(vscode.Uri.file(firstCreatedFile), { preview: false }); - } - - // Brain Sync Logic - if (brainModified && shouldAutoPushBrain() && getSecondBrainRepo()) { - this.syncBrain(); - } - return report; } - private syncBrain() { + private syncBrain(brainDir: string) { try { - const brainDir = _getBrainDir(); const { execSync } = require('child_process'); execSync(`git add .`, { cwd: brainDir }); execSync(`git commit -m "[G1nation] Knowledge Update"`, { cwd: brainDir }); diff --git a/src/sidebarProvider.ts b/src/sidebarProvider.ts index 79d5c7f..7a8c0fc 100644 --- a/src/sidebarProvider.ts +++ b/src/sidebarProvider.ts @@ -1649,9 +1649,12 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn private async _handlePrompt(data: any) { if (!this._view) return; - const { value, model, internet, files, agentFile, negativePrompt, designerGuard, secondBrainTrace, secondBrainTraceDebug } = data; + const { value, model, internet, files, agentFile, negativePrompt, designerGuard, secondBrainTrace, secondBrainTraceDebug, brainProfileId } = data; this._currentNegativePrompt = negativePrompt || ''; - this._currentSessionBrainId = getActiveBrainProfile().id; + const selectedBrainId = typeof brainProfileId === 'string' && brainProfileId && brainProfileId !== 'new' + ? brainProfileId + : getActiveBrainProfile().id; + this._currentSessionBrainId = selectedBrainId; let agentSkillContext = undefined; if (agentFile && fs.existsSync(agentFile)) { @@ -1668,7 +1671,8 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn negativePrompt, designerContext, secondBrainTraceEnabled: secondBrainTrace !== false, - secondBrainTraceDebug: !!secondBrainTraceDebug + secondBrainTraceDebug: !!secondBrainTraceDebug, + brainProfileId: selectedBrainId }); } catch (error: any) { logError('Prompt handling failed in sidebar provider.', { error: error?.message || String(error), promptPreview: summarizeText(value || '', 200) }); @@ -3039,6 +3043,7 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn internet: internetEnabled, files: pendingFiles.length > 0 ? pendingFiles : undefined, agentFile: agentSel.value === 'none' ? undefined : agentSel.value, + brainProfileId: brainSel.value && brainSel.value !== 'new' ? brainSel.value : undefined, negativePrompt: negativePrompt.value.trim() || undefined, designerGuard: designerGuardEnabled, secondBrainTrace: secondBrainTraceEnabled,