feat(memory): add experimental qmd search backend

This commit is contained in:
William Valentin
2026-02-15 19:33:43 -08:00
parent c6e3d09ecc
commit 81c97a9df1
14 changed files with 340 additions and 29 deletions
+3 -3
View File
@@ -30,8 +30,8 @@ export { createGtasksTools } from './gtasks.js';
import type { Tool } from '../types.js';
import type { MemoryStore } from '../../memory/store.js';
import type { HybridSearch } from '../../memory/hybrid-search.js';
import type { WebSearchConfig } from './web-search.js';
import type { MemorySearchBackend } from './memory-search.js';
import { shellExecTool } from './shell.js';
import { fileReadTool } from './file-read.js';
import { fileWriteTool } from './file-write.js';
@@ -60,11 +60,11 @@ export const allBuiltinTools: Tool[] = [
];
/** Create memory tools that require a MemoryStore instance. */
export function createMemoryTools(store: MemoryStore, hybridSearch?: HybridSearch): Tool[] {
export function createMemoryTools(store: MemoryStore, searchBackend?: MemorySearchBackend): Tool[] {
return [
createMemoryReadTool(store),
createMemoryWriteTool(store),
createMemorySearchTool(store, hybridSearch),
createMemorySearchTool(store, searchBackend),
];
}
+16 -11
View File
@@ -1,22 +1,26 @@
import type { Tool, ToolResult } from '../types.js';
import type { MemoryStore } from '../../memory/store.js';
import type { HybridSearch } from '../../memory/hybrid-search.js';
import type { HybridSearchResult } from '../../memory/hybrid-search.js';
interface MemorySearchArgs {
query: string;
}
export interface MemorySearchBackend {
search(query: string, topK?: number): Promise<HybridSearchResult[]>;
}
/**
* Creates a memory.search tool bound to the given MemoryStore instance.
* When a HybridSearch instance is provided, uses vector + keyword search;
* When a search backend is provided, uses backend-assisted search;
* otherwise falls back to keyword-only search.
*/
export function createMemorySearchTool(store: MemoryStore, hybridSearch?: HybridSearch): Tool {
export function createMemorySearchTool(store: MemoryStore, searchBackend?: MemorySearchBackend): Tool {
return {
name: 'memory.search',
description:
'Search across all memory files for a keyword or phrase. Returns matching lines with surrounding context from every namespace.' +
(hybridSearch ? ' Uses semantic vector search combined with keyword matching for better results.' : '') +
(searchBackend ? ' Uses an enhanced search backend (hybrid vector/keyword or QMD) when configured.' : '') +
' Category namespaces (facts/preferences/decisions/projects) are searchable through the namespace path.',
inputSchema: {
type: 'object',
@@ -32,10 +36,10 @@ export function createMemorySearchTool(store: MemoryStore, hybridSearch?: Hybrid
const args = rawArgs as MemorySearchArgs;
try {
// Try hybrid search first if available
if (hybridSearch) {
// Try enhanced search backend first if available
if (searchBackend) {
try {
const results = await hybridSearch.search(args.query);
const results = await searchBackend.search(args.query);
if (results.length === 0) {
return { success: true, output: `No matches found for "${args.query}".` };
@@ -44,7 +48,8 @@ export function createMemorySearchTool(store: MemoryStore, hybridSearch?: Hybrid
const formatted = results.map((result) => {
const sourceLabel = result.source === 'both' ? 'keyword+vector'
: result.source === 'vector' ? 'vector'
: 'keyword';
: result.source === 'qmd' ? 'qmd'
: 'keyword';
return `[${result.namespace}:${result.line}] (${sourceLabel}, score: ${result.score.toFixed(3)}) ${result.content}\n context: ${result.context}`;
}).join('\n\n');
@@ -52,9 +57,9 @@ export function createMemorySearchTool(store: MemoryStore, hybridSearch?: Hybrid
success: true,
output: `Found ${results.length} match${results.length === 1 ? '' : 'es'} for "${args.query}":\n\n${formatted}`,
};
} catch (hybridError) {
// Fall back to keyword search on hybrid failure
console.error('Hybrid search failed, falling back to keyword search:', hybridError);
} catch (backendError) {
// Fall back to keyword search on backend failure
console.error('Enhanced memory search backend failed, falling back to keyword search:', backendError);
}
}