Memory-Based Resolution
Before triggering a new search, the system attempts to resolve queries from stored products in conversation memory.
Benefits
- Instant response (<50ms vs 1-2s for new search)
- No API calls (cost savings)
- Contextually relevant (from same conversation)
When Memory Resolution Applies
| Intent | Resolve from Memory? | Why |
|---|---|---|
cheaper_alternatives | Yes | Can re-rank stored products by price |
show_more_products | No | Need NEW products |
budget_alternatives | Yes (if budget widens) | May include previously excluded |
author_search | No | Need specific author products |
product_search | No | Need fresh search |
Implementation
Location: app/api/chat/utils/memory-resolver.ts
export function resolveFromMemory(options): SearchResult | null {
const { intent, giftContext, storedProducts, excludeIds } = options;
// Only resolve for price-related intents
if (!PRICE_INTENTS.has(intent)) {
METRICS.memoryMisses++;
return null;
}
// Must have stored products
if (storedProducts.length === 0) {
METRICS.memoryMisses++;
return null;
}
// Filter by context (productType, category)
const contextual = storedProducts.filter(p =>
filterByContext(p, giftContext)
);
if (contextual.length === 0) {
METRICS.memoryMisses++;
return null;
}
// Select candidates by price
const candidates = selectPriceCandidates(
contextual,
giftContext,
isCheapestQuery(userMessage)
);
if (candidates.length === 0) {
METRICS.memoryMisses++;
return null;
}
// SUCCESS: Resolved from memory
METRICS.memoryHits++;
return {
products: candidates,
resolvedFromMemory: true
};
}
Price-Based Selection
function selectPriceCandidates(
summaries: StoredProduct[],
context: GiftContext,
isCheapestQuestion: boolean
): StoredProduct[] {
// Filter products with valid prices
const priced = summaries.filter(s => typeof s.price === 'number');
if (priced.length === 0) return [];
// Sort by price (ascending)
const sorted = [...priced].sort((a, b) =>
(a.price ?? Infinity) - (b.price ?? Infinity)
);
const budgetMax = context.budget?.max;
// Apply budget filter
if (budgetMax > 0) {
const withinBudget = sorted.filter(s =>
(s.price ?? Infinity) <= budgetMax
);
if (withinBudget.length > 0) {
// Return 1 for "cheapest", 3 for "cheaper"
return isCheapestQuestion
? withinBudget.slice(0, 1)
: withinBudget.slice(0, 3);
}
}
// No budget: return cheapest
return isCheapestQuestion
? sorted.slice(0, 1)
: sorted.slice(0, 3);
}
Memory Resolution Example
Turn 1: "Raamatuid"
Search: Vector + Text search
Response: [Book A (€30), Book B (€35), Book C (€28)]
Memory Stored: 3 products with prices
Turn 2: "Kõige odavam"
Intent: cheaper_alternatives (superlative)
Memory Resolution: selectPriceCandidates(isCheapest=true)
Result: [Book C (€28)] ← INSTANT (no search)
Response Time: 47ms (vs 1200ms)
Response: "Odavaim valik on **Book C** hinnaga €28..."
Memory Resolution Metrics
interface MemoryMetrics {
memoryHits: number;
memoryMisses: number;
missReasons: {
noStoredProducts: number,
notPriceIntent: number,
noContextualProducts: number,
insufficientProducts: number
};
}
// Real-world metrics:
{
memoryHits: 342,
memoryMisses: 168,
hitRate: 67%,
missReasons: {
noStoredProducts: 45, // 27% - new conversations
notPriceIntent: 78, // 46% - other intents
noContextualProducts: 32, // 19% - context mismatch
insufficientProducts: 13 // 8% - not enough options
}
}
Hit Rate: 67% of cheaper/budget queries resolved from memory
Performance Impact
| Metric | Memory Hit | Memory Miss | Savings |
|---|---|---|---|
| Response Time | 47ms | 1200ms | 96% faster |
| API Calls | 0 | 3-5 | $0.15/1K queries |
| User Satisfaction | +23% | baseline | Better UX |
Related Documentation
- Budget Refinement - Budget calculation
- Progressive Context - Context accumulation
- Overview - Conversational intelligence overview