feat: integrate unified RAG pipeline and bump version to 2.60.0
This commit is contained in:
+64
-75
@@ -37,6 +37,8 @@ import {
|
||||
renderSecondBrainTraceMarkdown,
|
||||
SecondBrainTrace
|
||||
} from './features/secondBrainTrace';
|
||||
import { MemoryManager } from './memory';
|
||||
import { RetrievalOrchestrator } from './retrieval';
|
||||
|
||||
export interface ChatMessage {
|
||||
role: 'user' | 'assistant' | 'system';
|
||||
@@ -80,6 +82,8 @@ export class AgentExecutor {
|
||||
private transactionManager: TransactionManager;
|
||||
private sessionManager: SessionManager;
|
||||
private statusBarManager: StatusBarManager;
|
||||
private memoryManager: MemoryManager;
|
||||
private retrievalOrchestrator: RetrievalOrchestrator;
|
||||
private currentTaskId: string = 'default_session';
|
||||
|
||||
constructor(
|
||||
@@ -88,6 +92,17 @@ export class AgentExecutor {
|
||||
this.transactionManager = new TransactionManager();
|
||||
this.sessionManager = new SessionManager(this.context);
|
||||
this.statusBarManager = new StatusBarManager();
|
||||
|
||||
// Initialize 5-Layer Cognitive Memory System
|
||||
const activeBrain = getActiveBrainProfile();
|
||||
this.memoryManager = new MemoryManager(activeBrain.localBrainPath, {
|
||||
enabled: getConfig().memoryEnabled,
|
||||
shortTermLimit: getConfig().memoryShortTermMessages,
|
||||
});
|
||||
|
||||
// Initialize RAG Pipeline Orchestrator
|
||||
this.retrievalOrchestrator = new RetrievalOrchestrator();
|
||||
|
||||
this.restoreLastSession();
|
||||
}
|
||||
|
||||
@@ -142,6 +157,10 @@ export class AgentExecutor {
|
||||
}
|
||||
|
||||
public clearHistory() {
|
||||
// Extract memories before clearing
|
||||
if (this.chatHistory.length > 2) {
|
||||
this.onSessionEnd();
|
||||
}
|
||||
this.chatHistory = [];
|
||||
this.emitHistoryChanged();
|
||||
}
|
||||
@@ -156,6 +175,10 @@ export class AgentExecutor {
|
||||
|
||||
public resetConversation() {
|
||||
this.stop();
|
||||
// Extract memories before resetting
|
||||
if (this.chatHistory.length > 2) {
|
||||
this.onSessionEnd();
|
||||
}
|
||||
this.chatHistory = [];
|
||||
this.emitHistoryChanged();
|
||||
}
|
||||
@@ -1692,84 +1715,30 @@ export class AgentExecutor {
|
||||
const config = getConfig();
|
||||
if (!config.memoryEnabled) return '';
|
||||
|
||||
// Update memory manager config in case settings changed
|
||||
this.memoryManager.updateConfig({
|
||||
enabled: config.memoryEnabled,
|
||||
shortTermLimit: config.memoryShortTermMessages,
|
||||
});
|
||||
|
||||
const visibleHistory = this.chatHistory.filter((message) => !message.internal);
|
||||
const shortTerm = visibleHistory
|
||||
.slice(-config.memoryShortTermMessages)
|
||||
.map((message) => `- ${message.role}: ${summarizeText(message.content, 260)}`)
|
||||
.join('\n');
|
||||
const workspaceFolders = vscode.workspace.workspaceFolders;
|
||||
const workspacePath = workspaceFolders ? workspaceFolders[0].uri.fsPath : undefined;
|
||||
|
||||
const savedSessions = this.context.globalState.get<any[]>('chat_sessions', []) || [];
|
||||
const mediumTerm = savedSessions
|
||||
.slice(0, config.memoryMediumTermSessions)
|
||||
.map((session: any) => {
|
||||
const title = summarizeText(String(session?.title || 'Untitled session'), 120);
|
||||
const lastMessage = Array.isArray(session?.history)
|
||||
? session.history[session.history.length - 1]?.content || ''
|
||||
: '';
|
||||
return `- ${title}: ${summarizeText(String(lastMessage), 220)}`;
|
||||
})
|
||||
.join('\n');
|
||||
// Use the Unified RAG Pipeline
|
||||
const result = this.retrievalOrchestrator.retrieve(currentPrompt, {
|
||||
brain: activeBrain,
|
||||
memoryManager: this.memoryManager,
|
||||
workspacePath,
|
||||
chatHistory: visibleHistory,
|
||||
contextBudget: {
|
||||
totalBudget: 8000,
|
||||
retrievalRatio: 0.4
|
||||
},
|
||||
brainFileLimit: config.memoryLongTermFiles
|
||||
});
|
||||
|
||||
const longTerm = this.findRelevantBrainMemory(currentPrompt, config.memoryLongTermFiles, activeBrain);
|
||||
const sections = [
|
||||
shortTerm ? `### Short-Term Memory\n${shortTerm}` : '',
|
||||
mediumTerm ? `### Medium-Term Memory\n${mediumTerm}` : '',
|
||||
longTerm ? `### Long-Term Memory\n${longTerm}` : ''
|
||||
].filter(Boolean).join('\n\n');
|
||||
|
||||
if (!sections) return '';
|
||||
|
||||
return [
|
||||
'',
|
||||
'[MEMORY CONTEXT]',
|
||||
'Review this layered memory before preparing the answer. Use it only when relevant, and prefer the current user request when there is conflict.',
|
||||
sections
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
private findRelevantBrainMemory(currentPrompt: string, limit: number, activeBrain: BrainProfile): string {
|
||||
if (limit <= 0) return '';
|
||||
|
||||
try {
|
||||
const files = findBrainFiles(activeBrain.localBrainPath);
|
||||
const terms = currentPrompt
|
||||
.toLowerCase()
|
||||
.split(/[^a-z0-9가-힣_]+/g)
|
||||
.filter((term) => term.length >= 2)
|
||||
.slice(0, 24);
|
||||
|
||||
const scored = files.map((file) => {
|
||||
let score = 0;
|
||||
const basename = path.basename(file).toLowerCase();
|
||||
for (const term of terms) {
|
||||
if (basename.includes(term)) score += 4;
|
||||
}
|
||||
|
||||
let preview = '';
|
||||
try {
|
||||
const content = fs.readFileSync(file, 'utf8');
|
||||
const lower = content.toLowerCase();
|
||||
for (const term of terms) {
|
||||
if (lower.includes(term)) score += 1;
|
||||
}
|
||||
preview = summarizeText(content, 360);
|
||||
} catch {
|
||||
preview = '';
|
||||
}
|
||||
|
||||
const stat = fs.existsSync(file) ? fs.statSync(file) : undefined;
|
||||
return { file, score, preview, mtime: stat?.mtimeMs || 0 };
|
||||
});
|
||||
|
||||
return scored
|
||||
.sort((a, b) => (b.score - a.score) || (b.mtime - a.mtime))
|
||||
.slice(0, limit)
|
||||
.map((entry) => `- ${path.relative(activeBrain.localBrainPath, entry.file)}: ${entry.preview}`)
|
||||
.join('\n');
|
||||
} catch (error: any) {
|
||||
logError('Failed to build long-term memory context.', { error: error?.message || String(error) });
|
||||
return '';
|
||||
}
|
||||
return this.retrievalOrchestrator.buildContextString(result);
|
||||
}
|
||||
|
||||
private emitHistoryChanged() {
|
||||
@@ -1787,6 +1756,26 @@ export class AgentExecutor {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 세션 종료 시 5-Layer Memory에 자동 추출을 수행합니다.
|
||||
* 새 채팅 시작 또는 Extension 비활성화 시 호출됩니다.
|
||||
*/
|
||||
public onSessionEnd(): void {
|
||||
try {
|
||||
const workspaceFolders = vscode.workspace.workspaceFolders;
|
||||
const workspacePath = workspaceFolders ? workspaceFolders[0].uri.fsPath : undefined;
|
||||
|
||||
this.memoryManager.onSessionEnd(
|
||||
this.currentTaskId,
|
||||
this.chatHistory.filter((m) => !m.internal),
|
||||
workspacePath
|
||||
);
|
||||
logInfo('Memory extraction completed for session end.', { taskId: this.currentTaskId });
|
||||
} catch (error: any) {
|
||||
logError('Memory extraction failed on session end.', { error: error?.message || String(error) });
|
||||
}
|
||||
}
|
||||
|
||||
private async createStreamingRequest(params: {
|
||||
baseUrl: string;
|
||||
modelName: string;
|
||||
|
||||
Reference in New Issue
Block a user