Add structured memory system for persistent agent context

Implements `StructuredMemoryManager` to track conversation summaries,
user preferences, and learned facts across sessions. Includes:
- Configurable storage limits with automatic enforcement
- Heuristic extraction of preferences and facts from messages
- Memory context injection into system prompts
- Full test coverage for all manager operations
This commit is contained in:
2026-05-20 22:18:33 +02:00
parent 9d4eb9a62a
commit fbb744ba6b
7 changed files with 1201 additions and 39 deletions
+57 -5
View File
@@ -25,6 +25,7 @@ import {
} from './types';
import { ConversationStateManager } from './conversation-state';
import { ErrorHandler } from './error-handler';
import { StructuredMemoryManager } from './structured-memory';
export const VIEW_TYPE_OLLAMA_CHAT = 'ollama-chat-view';
@@ -42,7 +43,12 @@ export class ChatView extends ItemView {
return this.newChatButtonClickHandler;
}
constructor(leaf: WorkspaceLeaf, settings: PluginSettings, vectorStore?: VaultVectorStore) {
constructor(
leaf: WorkspaceLeaf,
settings: PluginSettings,
vectorStore?: VaultVectorStore,
structuredMemoryManager?: StructuredMemoryManager
) {
super(leaf);
this.messages = [];
this.lastMessageEl = null;
@@ -70,6 +76,7 @@ export class ChatView extends ItemView {
this.actionPreviewBuilder = new ActionPreviewBuilder(this.app.vault, this.app);
this.noteContextBuilder = new NoteContextBuilder(this.app.vault, this.app, this.vaultIndexer);
this.conversationStateManager = new ConversationStateManager();
this.structuredMemoryManager = structuredMemoryManager;
this.workflowEngine = new WorkflowEngine(
this.app.vault,
this.app,
@@ -380,7 +387,6 @@ export class ChatView extends ItemView {
getTools(): OllamaTool[] {
const allTools: OllamaTool[] = [
{
type: 'function',
function: {
@@ -600,17 +606,30 @@ export class ChatView extends ItemView {
buildMessages(userMessageContent: string, tools?: OllamaTool[]): OllamaMessage[] {
const systemContent = getSystemPromptForMode(this.currentAgentMode);
const systemMessage: OllamaMessage = {
const messages: OllamaMessage[] = [];
// Inject structured memory as a preceding system message if available
if (this.structuredMemoryManager) {
const memoryContext = this.structuredMemoryManager.buildMemoryContext();
if (memoryContext) {
messages.push({
role: 'system',
content: memoryContext,
});
}
}
messages.push({
role: 'system',
content: systemContent,
};
});
const userMessage: OllamaMessage = {
role: 'user',
content: userMessageContent,
};
const messages: OllamaMessage[] = [systemMessage, userMessage];
messages.push(userMessage);
if (tools && tools.length > 0) {
messages.push({
@@ -1059,6 +1078,38 @@ export class ChatView extends ItemView {
content: fullResponse,
});
// Update structured memory with preferences, facts, and a conversation summary
if (this.structuredMemoryManager) {
const prefs = this.structuredMemoryManager.extractPreferencesFromMessage(userMessage);
for (const pref of prefs) {
this.structuredMemoryManager.addUserPreference(pref);
}
const facts = this.structuredMemoryManager.extractFactsFromMessage(userMessage);
for (const fact of facts) {
this.structuredMemoryManager.addLearnedFact(fact);
}
// Also extract from assistant response
const assistantFacts = this.structuredMemoryManager.extractFactsFromMessage(fullResponse);
for (const fact of assistantFacts) {
this.structuredMemoryManager.addLearnedFact(fact);
}
const { topic, keyPoints } = this.structuredMemoryManager.summarizeConversation(
this.conversationStateManager.getShortTermContext()
);
if (keyPoints.length > 0) {
this.structuredMemoryManager.addConversationSummary({
id: crypto.randomUUID?.() ?? `summary-${Date.now()}-${Math.random()}`,
timestamp: Date.now(),
topic,
summary: keyPoints.join('; ').slice(0, 300),
keyPoints,
});
}
}
// Limit conversation history to prevent memory issues
if (this.messages.length > this.settings.maxMessageHistory) {
this.messages = this.messages.slice(-this.settings.maxMessageHistory);
@@ -1100,6 +1151,7 @@ export class ChatView extends ItemView {
private noteContextBuilder: NoteContextBuilder;
private workflowEngine: WorkflowEngine;
private conversationStateManager: ConversationStateManager;
private structuredMemoryManager?: StructuredMemoryManager;
private vectorStore?: VaultVectorStore;
private modeSelectorEl: HTMLSelectElement | null = null;