Add auto-capture system (Milestone 2)

- Add capture configuration system with modes: always, manual, decisions, off
- Add Ollama-based conversation summarization and extraction
- Add deduplication via embedding similarity (merge >0.90, link 0.75-0.90)
- Add CLI commands: capture, capture-hook, config
- Add MCP tools: memory_capture, memory_remember, memory_capture_config
- Include summary.ts (previously uncommitted)
This commit is contained in:
2026-02-03 09:59:49 +01:00
parent 999c748d3d
commit 7a4dc07038
8 changed files with 941 additions and 0 deletions

View File

@@ -385,6 +385,69 @@ server.tool(
}
);
// --- memory_capture ---
import { captureConversation, captureText, getCaptureConfig, setCaptureConfig, CaptureMode } from '../core/capture';
server.tool(
'memory_capture',
'Capture a conversation or context as a memory node. Uses AI to summarize and extract key information.',
{
conversation: z.string().describe('The conversation or context to capture'),
sessionId: z.string().optional().describe('Session identifier'),
filesChanged: z.array(z.string()).optional().describe('List of files that were changed'),
source: z.string().optional().describe('Source identifier (default: claude-code)'),
},
async ({ conversation, sessionId, filesChanged, source }) => {
const result = await captureConversation({
conversation,
sessionId,
filesChanged,
source: source || 'claude-code',
});
return { content: [{ type: 'text' as const, text: serialize(result) }] };
}
);
server.tool(
'memory_remember',
'Remember a piece of text for later. Simpler than memory_capture - for quick notes and facts.',
{
text: z.string().describe('The text to remember'),
tags: z.array(z.string()).optional().describe('Tags to apply'),
},
async ({ text, tags }) => {
const result = await captureText(text, { tags, source: 'remember' });
return { content: [{ type: 'text' as const, text: serialize(result) }] };
}
);
server.tool(
'memory_capture_config',
'Get or set auto-capture configuration',
{
action: z.enum(['get', 'set']).describe('Action to perform'),
mode: z.enum(['always', 'manual', 'decisions', 'off']).optional().describe('Capture mode (for set)'),
minLength: z.number().optional().describe('Minimum conversation length (for set)'),
autoTag: z.boolean().optional().describe('Auto-generate tags (for set)'),
linkRelated: z.boolean().optional().describe('Auto-link related nodes (for set)'),
},
async ({ action, mode, minLength, autoTag, linkRelated }) => {
if (action === 'get') {
const config = getCaptureConfig();
return { content: [{ type: 'text' as const, text: serialize(config) }] };
}
const updates: Partial<{ mode: CaptureMode; minLength: number; autoTag: boolean; linkRelated: boolean }> = {};
if (mode !== undefined) updates.mode = mode;
if (minLength !== undefined) updates.minLength = minLength;
if (autoTag !== undefined) updates.autoTag = autoTag;
if (linkRelated !== undefined) updates.linkRelated = linkRelated;
const config = setCaptureConfig(updates);
return { content: [{ type: 'text' as const, text: serialize({ updated: true, config }) }] };
}
);
// --- memory_prompt ---
import { interpretAndExecute } from '../core/prompt/interpreter';