feat(memorycore): add tags system, session summaries, hook injection, tag filtering, and solidify compress mode

Implement 5 interconnected memorycore enhancements:

1. Tags backend: add tags TEXT column to memories table with migration,
   JSON array storage, full CRUD support via upsertMemory/getMemory/getMemories
2. LLM auto-tag extraction: extend extraction prompt to produce tags,
   parse and validate in pipeline, create CMEM from extraction results
3. Session summary API: expose rollout_summary via new REST endpoints
   GET /api/core-memory/sessions/summaries and sessions/:id/summary
4. Hook injection: increase SESSION_START_LIMIT to 1500, add Component 5
   (Recent Sessions) to UnifiedContextBuilder with 300-char budget
5. Tag filtering: add getMemoriesByTags() with json_each() for safe
   SQL matching, wire through MCP tool, CLI --tags flag, REST ?tags= param
6. Solidify compress mode: add --type compress to solidify.md with
   getRecentMemories(), archiveMemories(), buildCompressionMetadata()

Security fixes: safeParseTags() for corrupt DB data, json_each() instead
of LIKE injection, ESCAPE clause for searchSessionsByKeyword, singleton
store in unified-context-builder.
This commit is contained in:
catlog22
2026-02-23 22:56:25 +08:00
parent ab0e25895c
commit 5cae3cb3c8
10 changed files with 582 additions and 62 deletions

View File

@@ -38,6 +38,8 @@ const ParamsSchema = z.object({
force: z.boolean().optional().default(false),
// V2 extract parameters
max_sessions: z.number().optional(),
// Tags filter parameter
tags: z.array(z.string()).optional(),
// V2 jobs parameters
kind: z.string().optional(),
status_filter: z.enum(['pending', 'running', 'done', 'error']).optional(),
@@ -60,6 +62,7 @@ interface CoreMemoryCompact {
preview: string; // Truncated content/summary preview
archived: boolean;
updated_at: string;
tags: string[];
}
interface ListResult {
@@ -182,9 +185,13 @@ const PREVIEW_MAX_LENGTH = 100;
* List all memories with compact output
*/
function executeList(params: Params): ListResult {
const { limit, path } = params;
const { limit, path, tags } = params;
const store = getCoreMemoryStore(getProjectPath(path));
const memories = store.getMemories({ limit }) as CoreMemory[];
// Use tag filter if tags provided, otherwise get all
const memories = tags && tags.length > 0
? store.getMemoriesByTags(tags, { limit }) as CoreMemory[]
: store.getMemories({ limit }) as CoreMemory[];
// Convert to compact format with truncated preview
const compactMemories: CoreMemoryCompact[] = memories.map((m) => {
@@ -198,6 +205,7 @@ function executeList(params: Params): ListResult {
preview,
archived: m.archived,
updated_at: m.updated_at,
tags: (m as any).tags || [],
};
});
@@ -584,6 +592,7 @@ export const schema: ToolSchema = {
Usage:
core_memory(operation="list") # List all memories
core_memory(operation="list", tags=["auth","api"]) # List memories with specific tags
core_memory(operation="import", text="important context") # Import text as new memory
core_memory(operation="export", id="CMEM-xxx") # Export memory as plain text
core_memory(operation="summary", id="CMEM-xxx") # Generate AI summary
@@ -674,6 +683,11 @@ Memory IDs use format: CMEM-YYYYMMDD-HHMMSS`,
enum: ['pending', 'running', 'done', 'error'],
description: 'Filter jobs by status (for jobs operation)',
},
tags: {
type: 'array',
items: { type: 'string' },
description: 'Filter memories by tags (AND logic - must contain ALL specified tags). Used with list operation.',
},
},
required: ['operation'],
},