double-context
Version:
Intelligently optimize and compress context for LLM prompts to greatly increase effective context window
131 lines • 5.65 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.prioritize = prioritize;
const embeddings_1 = require("./embeddings");
async function prioritize(chunks, userPrompt, strategy = "hybrid", embeddingProvider) {
if (!chunks || chunks.length === 0)
return [];
// Create chunk metadata with timestamps
const chunkMetadata = chunks.map((text, index) => ({
index,
text,
timestamp: new Date(Date.now() - (chunks.length - index) * 60000) // Simulate recency
}));
// Use semantic prioritization if embeddings are available
if (embeddingProvider) {
return await prioritizeWithEmbeddings(chunkMetadata, userPrompt, strategy, embeddingProvider);
}
// Fallback to keyword-based prioritization
switch (strategy) {
case "recency":
return prioritizeByRecency(chunkMetadata);
case "relevance":
return prioritizeByKeywordRelevance(chunkMetadata, userPrompt);
case "hybrid":
default:
return prioritizeKeywordHybrid(chunkMetadata, userPrompt);
}
}
function prioritizeByRecency(chunks) {
return chunks
.sort((a, b) => (b.timestamp?.getTime() || 0) - (a.timestamp?.getTime() || 0))
.map(chunk => chunk.text);
}
function prioritizeByKeywordRelevance(chunks, userPrompt) {
// Simple keyword-based relevance for Phase 1
const promptWords = userPrompt.toLowerCase().split(/\s+/);
const scored = chunks.map(chunk => {
const chunkWords = chunk.text.toLowerCase().split(/\s+/);
const relevanceScore = promptWords.reduce((score, word) => {
return score + (chunkWords.includes(word) ? 1 : 0);
}, 0) / promptWords.length;
return { ...chunk, relevanceScore };
});
return scored
.sort((a, b) => (b.relevanceScore || 0) - (a.relevanceScore || 0))
.map(chunk => chunk.text);
}
function prioritizeKeywordHybrid(chunks, userPrompt) {
// Combine relevance and recency with 70/30 weighting
const promptWords = userPrompt.toLowerCase().split(/\s+/);
const now = Date.now();
const scored = chunks.map(chunk => {
const chunkWords = chunk.text.toLowerCase().split(/\s+/);
const relevanceScore = promptWords.reduce((score, word) => {
return score + (chunkWords.includes(word) ? 1 : 0);
}, 0) / promptWords.length;
const ageMs = now - (chunk.timestamp?.getTime() || 0);
const recencyScore = Math.max(0, 1 - (ageMs / (24 * 60 * 60 * 1000))); // Decay over 24 hours
const hybridScore = (relevanceScore * 0.7) + (recencyScore * 0.3);
return { ...chunk, relevanceScore: hybridScore };
});
return scored
.sort((a, b) => (b.relevanceScore || 0) - (a.relevanceScore || 0))
.map(chunk => chunk.text);
}
// Semantic prioritization functions
async function prioritizeWithEmbeddings(chunks, userPrompt, strategy, embeddingProvider) {
try {
// Generate embeddings for the user prompt and all chunks
const texts = [userPrompt, ...chunks.map(c => c.text)];
const embeddings = await embeddingProvider.getEmbeddings(texts);
const promptEmbedding = embeddings[0];
const chunkEmbeddings = embeddings.slice(1);
// Add embeddings to chunk metadata
const chunksWithEmbeddings = chunks.map((chunk, index) => ({
...chunk,
embedding: chunkEmbeddings[index]
}));
switch (strategy) {
case "recency":
return prioritizeByRecency(chunksWithEmbeddings);
case "relevance":
return prioritizeBySemanticRelevance(chunksWithEmbeddings, promptEmbedding);
case "hybrid":
default:
return prioritizeSemanticHybrid(chunksWithEmbeddings, promptEmbedding);
}
}
catch (error) {
console.warn('Semantic prioritization failed, falling back to keyword-based:', error);
// Fallback to keyword-based prioritization
switch (strategy) {
case "recency":
return prioritizeByRecency(chunks);
case "relevance":
return prioritizeByKeywordRelevance(chunks, userPrompt);
case "hybrid":
default:
return prioritizeKeywordHybrid(chunks, userPrompt);
}
}
}
function prioritizeBySemanticRelevance(chunks, promptEmbedding) {
const scored = chunks.map(chunk => {
if (!chunk.embedding) {
return { ...chunk, relevanceScore: 0 };
}
const similarity = (0, embeddings_1.cosineSimilarity)(promptEmbedding, chunk.embedding);
return { ...chunk, relevanceScore: similarity };
});
return scored
.sort((a, b) => (b.relevanceScore || 0) - (a.relevanceScore || 0))
.map(chunk => chunk.text);
}
function prioritizeSemanticHybrid(chunks, promptEmbedding) {
const now = Date.now();
const scored = chunks.map(chunk => {
let relevanceScore = 0;
if (chunk.embedding) {
relevanceScore = (0, embeddings_1.cosineSimilarity)(promptEmbedding, chunk.embedding);
}
const ageMs = now - (chunk.timestamp?.getTime() || 0);
const recencyScore = Math.max(0, 1 - (ageMs / (24 * 60 * 60 * 1000))); // Decay over 24 hours
const hybridScore = (relevanceScore * 0.7) + (recencyScore * 0.3);
return { ...chunk, relevanceScore: hybridScore };
});
return scored
.sort((a, b) => (b.relevanceScore || 0) - (a.relevanceScore || 0))
.map(chunk => chunk.text);
}
//# sourceMappingURL=prioritizer.js.map
;