- Bm25Ranker: Okapi BM25 scoring (pure TS, no deps) - Embedding module: ONNX-based local embeddings via onnxruntime-node - Hybrid recall: BM25 (30%) + cosine similarity (70%) weighted merge - Falls back to keyword-only via MEMORY_SEARCH=keyword env var - extract_memory agent tool for persisting memory entries
45 lines
1.8 KiB
TypeScript
45 lines
1.8 KiB
TypeScript
import { z } from 'zod';
|
|
import type { ToolDef } from '../tools/types.js';
|
|
import { ensureMemoryScaffold, getMemoryRoot } from '../memory/paths.js';
|
|
import { writeEntry } from '../memory/store.js';
|
|
|
|
const ExtractMemoryInput = z.object({
|
|
topic: z.enum(['project', 'user', 'reference']).describe('Memory topic category'),
|
|
title: z.string().min(1).max(200).describe('Entry title (will be normalized to filename)'),
|
|
content: z.string().min(1).describe('Memory content body'),
|
|
tags: z.array(z.string()).optional().describe('Optional tags for search'),
|
|
});
|
|
|
|
type InputT = z.infer<typeof ExtractMemoryInput>;
|
|
|
|
export const extractMemoryTool: ToolDef<InputT> = {
|
|
name: 'extract_memory',
|
|
description: 'Persist a memory entry to .boocode/memory/ for cross-session recall. Use for project conventions, user preferences, and architectural decisions.',
|
|
inputSchema: ExtractMemoryInput,
|
|
jsonSchema: {
|
|
type: 'function',
|
|
function: {
|
|
name: 'extract_memory',
|
|
description: 'Persist a memory entry for cross-session recall',
|
|
parameters: {
|
|
type: 'object',
|
|
properties: {
|
|
topic: { type: 'string', enum: ['project', 'user', 'reference'] },
|
|
title: { type: 'string', description: 'Entry title' },
|
|
content: { type: 'string', description: 'Memory content' },
|
|
tags: { type: 'array', items: { type: 'string' }, description: 'Search tags' },
|
|
},
|
|
required: ['topic', 'title', 'content'],
|
|
},
|
|
},
|
|
},
|
|
async execute(input: InputT, projectRoot: string): Promise<unknown> {
|
|
const root = getMemoryRoot(projectRoot);
|
|
await ensureMemoryScaffold(root);
|
|
await writeEntry(root, input.topic, input.title, input.content, input.tags ?? []);
|
|
return {
|
|
result: `Memory entry "${input.title}" saved to .boocode/memory/${input.topic}/`,
|
|
};
|
|
},
|
|
};
|