feat(core): add command, intent, and routing primitives
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
import type { SessionStore } from './store.js';
|
||||
import { tokenize } from './indexer.js';
|
||||
|
||||
export interface HistorySearchResult {
|
||||
sessionId: string;
|
||||
messageId: number;
|
||||
role: 'user' | 'assistant';
|
||||
content: string;
|
||||
score: number;
|
||||
createdAt: number;
|
||||
}
|
||||
|
||||
export interface HistorySearchConfig {
|
||||
limit: number;
|
||||
minScore: number;
|
||||
}
|
||||
|
||||
export class SessionSearch {
|
||||
private readonly store: SessionStore;
|
||||
private readonly config: HistorySearchConfig;
|
||||
|
||||
constructor(store: SessionStore, config: HistorySearchConfig) {
|
||||
this.store = store;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
search(query: string, opts?: { limit?: number; sessionId?: string }): HistorySearchResult[] {
|
||||
const queryTokens = new Set(tokenize(query));
|
||||
if (queryTokens.size === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const rows = opts?.sessionId
|
||||
? this.store.getMessagesWithMetadata(opts.sessionId)
|
||||
: this.store.getAllMessagesWithMetadata();
|
||||
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const results: HistorySearchResult[] = [];
|
||||
|
||||
for (const row of rows) {
|
||||
const keywords = row.metadata?.keywords ?? [];
|
||||
if (keywords.length === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const overlapCount = keywords.filter(keyword => queryTokens.has(keyword)).length;
|
||||
if (overlapCount === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const overlapScore = overlapCount / queryTokens.size;
|
||||
const ageSeconds = Math.max(0, now - row.createdAt);
|
||||
const recencyScore = Math.max(0, 1 - ageSeconds / (30 * 24 * 3600)) * 0.2;
|
||||
const totalScore = overlapScore + recencyScore;
|
||||
|
||||
if (totalScore < this.config.minScore) {
|
||||
continue;
|
||||
}
|
||||
|
||||
results.push({
|
||||
sessionId: row.sessionId,
|
||||
messageId: row.id,
|
||||
role: row.role,
|
||||
content: row.content,
|
||||
score: totalScore,
|
||||
createdAt: row.createdAt,
|
||||
});
|
||||
}
|
||||
|
||||
results.sort((a, b) => b.score - a.score || b.createdAt - a.createdAt);
|
||||
return results.slice(0, opts?.limit ?? this.config.limit);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user