Skip to main content

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

IntentResolve from Memory?Why
cheaper_alternativesYesCan re-rank stored products by price
show_more_productsNoNeed NEW products
budget_alternativesYes (if budget widens)May include previously excluded
author_searchNoNeed specific author products
product_searchNoNeed 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) &lt;= 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

MetricMemory HitMemory MissSavings
Response Time47ms1200ms96% faster
API Calls03-5$0.15/1K queries
User Satisfaction+23%baselineBetter UX