claude-conversation-manager
Version:
A CLI tool for managing Claude Code conversation history with parsing and i18n support
71 lines • 3.09 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.MemoryRetrieval = void 0;
class MemoryRetrieval {
search(items, keyword, limit = 10) {
const needle = keyword.trim().toLowerCase();
if (!needle || limit <= 0)
return [];
return items
.filter(item => item.text.toLowerCase().includes(needle) || item.type.toLowerCase().includes(needle))
.map(item => ({ item, score: this.searchScore(item, needle) }))
.sort((a, b) => b.score - a.score)
.slice(0, limit);
}
recall(items, query, limit = 5) {
const documents = items.map(item => this.tokens(item.text));
const queryTokens = this.tokens(query);
if (queryTokens.length === 0 || limit <= 0)
return [];
const vocabulary = new Set([...queryTokens, ...documents.flat()]);
const idf = new Map();
for (const token of vocabulary) {
const containingDocuments = documents.filter(document => document.includes(token)).length;
idf.set(token, Math.log((items.length + 1) / (containingDocuments + 1)) + 1);
}
const queryVector = this.vector(queryTokens, vocabulary, idf);
return items
.map((item, index) => {
const similarity = this.cosine(queryVector, this.vector(documents[index], vocabulary, idf));
const score = similarity > 0 ? similarity + this.recencyBoost(item) * 0.05 : 0;
return { item, score };
})
.filter(result => result.score > 0)
.sort((a, b) => b.score - a.score)
.slice(0, limit);
}
tokens(text) {
return text
.toLowerCase()
.split(/[^a-z0-9_\-/.\\]+/i)
.map(token => token.trim())
.filter(token => token.length > 1);
}
vector(tokens, vocabulary, idf) {
return [...vocabulary].map(token => {
const termFrequency = tokens.filter(current => current === token).length / Math.max(tokens.length, 1);
return termFrequency * (idf.get(token) || 1);
});
}
cosine(a, b) {
const dot = a.reduce((sum, value, index) => sum + value * b[index], 0);
const normA = Math.sqrt(a.reduce((sum, value) => sum + value * value, 0));
const normB = Math.sqrt(b.reduce((sum, value) => sum + value * value, 0));
if (normA === 0 || normB === 0)
return 0;
return dot / (normA * normB);
}
recencyBoost(item) {
const timestamp = new Date(item.timestamp).getTime();
return Number.isFinite(timestamp) ? timestamp / 10000000000000 : 0;
}
searchScore(item, keyword) {
const text = item.text.toLowerCase();
const type = item.type.toLowerCase();
const textMatches = text.split(keyword).length - 1;
const typeMatches = type.includes(keyword) ? 1 : 0;
return textMatches + typeMatches + this.recencyBoost(item) * 0.05;
}
}
exports.MemoryRetrieval = MemoryRetrieval;
//# sourceMappingURL=retrieval.js.map