Add comprehensive tests for query parsing and Reciprocal Rank Fusion

- Implemented tests for the QueryParser class, covering various identifier splitting methods (CamelCase, snake_case, kebab-case), OR expansion, and FTS5 operator preservation.
- Added parameterized tests to validate expected token outputs for different query formats.
- Created edge case tests to ensure robustness against unusual input scenarios.
- Developed tests for the Reciprocal Rank Fusion (RRF) algorithm, including score computation, weight handling, and result ranking across multiple sources.
- Included tests for normalization of BM25 scores and tagging search results with source metadata.
This commit is contained in:
catlog22
2025-12-16 10:20:19 +08:00
parent 35485bbbb1
commit 3da0ef2adb
39 changed files with 6171 additions and 240 deletions

View File

@@ -212,7 +212,7 @@ export async function handleCliRoutes(ctx: RouteContext): Promise<boolean> {
const status = url.searchParams.get('status') || null;
const category = url.searchParams.get('category') as 'user' | 'internal' | 'insight' | null;
const search = url.searchParams.get('search') || null;
const recursive = url.searchParams.get('recursive') !== 'false';
const recursive = url.searchParams.get('recursive') === 'true';
getExecutionHistoryAsync(projectPath, { limit, tool, status, category, search, recursive })
.then(history => {

View File

@@ -222,21 +222,30 @@ export async function handleMemoryRoutes(ctx: RouteContext): Promise<boolean> {
const projectPath = url.searchParams.get('path') || initialPath;
const limit = parseInt(url.searchParams.get('limit') || '50', 10);
const search = url.searchParams.get('search') || null;
const recursive = url.searchParams.get('recursive') === 'true';
try {
const memoryStore = getMemoryStore(projectPath);
let prompts;
if (search) {
prompts = memoryStore.searchPrompts(search, limit);
// Recursive mode: aggregate prompts from parent and child projects
if (recursive && !search) {
const { getAggregatedPrompts } = await import('../memory-store.js');
prompts = getAggregatedPrompts(projectPath, limit);
} else {
// Get all recent prompts (we'll need to add this method to MemoryStore)
const stmt = memoryStore['db'].prepare(`
SELECT * FROM prompt_history
ORDER BY timestamp DESC
LIMIT ?
`);
prompts = stmt.all(limit);
// Non-recursive mode or search mode: query only current project
const memoryStore = getMemoryStore(projectPath);
if (search) {
prompts = memoryStore.searchPrompts(search, limit);
} else {
// Get all recent prompts (we'll need to add this method to MemoryStore)
const stmt = memoryStore['db'].prepare(`
SELECT * FROM prompt_history
ORDER BY timestamp DESC
LIMIT ?
`);
prompts = stmt.all(limit);
}
}
res.writeHead(200, { 'Content-Type': 'application/json' });
@@ -506,8 +515,23 @@ Return ONLY valid JSON in this exact format (no markdown, no code blocks, just p
const projectPath = url.searchParams.get('path') || initialPath;
const filter = url.searchParams.get('filter') || 'all'; // today, week, all
const limit = parseInt(url.searchParams.get('limit') || '10', 10);
const recursive = url.searchParams.get('recursive') === 'true';
try {
// If requesting aggregated stats, use the aggregated function
if (url.searchParams.has('aggregated') || recursive) {
const { getAggregatedStats } = await import('../memory-store.js');
const aggregatedStats = getAggregatedStats(projectPath);
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
stats: aggregatedStats,
aggregated: true
}));
return true;
}
// Original hotspot statistics (non-recursive)
const memoryStore = getMemoryStore(projectPath);
const hotEntities = memoryStore.getHotEntities(limit * 4);