Skip to main content
Glama
memory-augmented-reasoning.ts10.5 kB
/** * Memory-Augmented Reasoning Component * * Integrates memory retrieval with cognitive tools to provide contextually * relevant insights based on stored memories. * * Requirements: 13.1, 13.2, 13.5, 13.6 */ import { truncateContent } from "../memory/content-validator"; import type { MemoryRepository } from "../memory/memory-repository"; import type { Memory, MemorySectorType, SearchQuery } from "../memory/types"; import { Logger } from "../utils/logger"; /** * Configuration for memory-augmented reasoning * * Requirements: 3.1, 3.2, 3.4 */ export interface MemoryAugmentedReasoningConfig { /** Minimum salience score for retrieved memories (default: 0.5) */ minSalience: number; /** Maximum number of memories to retrieve (default: 5) */ maxMemories: number; /** Memory sectors to search (default: all sectors) */ sectors?: MemorySectorType[]; /** Minimum strength for retrieved memories (default: 0.3) */ minStrength: number; /** Minimum relevance score for retrieved memories (default: 0.5) - Requirements: 3.1, 3.2 */ minRelevance: number; /** Maximum content length for display truncation (default: 500) - Requirements: 3.4 */ maxContentLength: number; } /** * Default configuration values * * Requirements: 3.1, 3.2, 3.4 */ const DEFAULT_CONFIG: MemoryAugmentedReasoningConfig = { minSalience: 0.5, maxMemories: 5, // Changed from 10 to 5 per Requirements 3.4 minStrength: 0.3, minRelevance: 0.5, // Requirements 3.1, 3.2 maxContentLength: 500, // Requirements 3.4 }; /** * Retrieved memory context for reasoning */ export interface MemoryContext { /** Retrieved memories relevant to the problem */ memories: RetrievedMemory[]; /** Total number of memories found */ totalFound: number; /** Time taken to retrieve memories in milliseconds */ retrievalTime: number; } /** * Simplified memory representation for reasoning context * * Requirements: 3.3, 4.1 */ export interface RetrievedMemory { /** Memory ID */ id: string; /** Memory content (may be truncated for display, full content used for reasoning) */ content: string; /** Primary sector of the memory */ primarySector: MemorySectorType; /** Salience score */ salience: number; /** Strength score */ strength: number; /** Relevance score from search */ relevanceScore: number; /** Keywords from metadata */ keywords: string[]; /** Whether the content was truncated for display - Requirements: 4.1 */ isTruncated: boolean; /** Original content length if truncated - Requirements: 4.1 */ originalLength?: number; } /** * Augmented problem context with memory information */ export interface AugmentedProblemContext { /** Original problem description */ originalProblem: string; /** Augmented problem with memory context */ augmentedProblem: string; /** Background information from memories */ memoryBackground: string; /** Memories used for augmentation */ memoriesUsed: RetrievedMemory[]; /** Whether memories were found and used */ hasMemoryContext: boolean; } /** * Memory-Augmented Reasoning Component * * Retrieves relevant memories and augments problem context for cognitive tools. */ export class MemoryAugmentedReasoning { private config: MemoryAugmentedReasoningConfig; constructor( private memoryRepository: MemoryRepository, config?: Partial<MemoryAugmentedReasoningConfig> ) { this.config = { ...DEFAULT_CONFIG, ...config }; } /** * Retrieve relevant memories for a problem * * Uses vector similarity search with the problem text as the query. * Filters by minSalience of 0.5 to ensure quality context. * Filters by minRelevance threshold and limits results. * * Requirements: 3.1, 3.2, 3.4, 3.5, 13.5, 13.6 * * @param problemText - The problem description to find relevant memories for * @param userId - User ID for memory isolation * @returns Memory context with retrieved memories */ async retrieveContext(problemText: string, userId: string): Promise<MemoryContext> { const startTime = Date.now(); try { // Build search query with vector similarity const searchQuery: SearchQuery = { text: problemText, userId, minSalience: this.config.minSalience, minStrength: this.config.minStrength, sectors: this.config.sectors, limit: this.config.maxMemories, }; // Execute search const searchResult = await this.memoryRepository.search(searchQuery); // Convert to retrieved memory format with relevance filtering // Requirements: 3.1, 3.2 - Filter by minRelevance threshold const memories: RetrievedMemory[] = searchResult.memories .map((memory: Memory) => { const score = searchResult.scores.get(memory.id); const relevanceScore = score?.total ?? 0; // Apply truncation for display (not for reasoning input) // Requirements: 3.3, 4.1 const truncationResult = truncateContent(memory.content, this.config.maxContentLength); return { id: memory.id, content: truncationResult.content, primarySector: memory.primarySector, salience: memory.salience, strength: memory.strength, relevanceScore, keywords: memory.metadata.keywords ?? [], isTruncated: truncationResult.isTruncated, originalLength: truncationResult.isTruncated ? truncationResult.originalLength : undefined, }; }) // Filter by relevance threshold - Requirements: 3.1, 3.2 .filter((memory: RetrievedMemory) => memory.relevanceScore >= this.config.minRelevance) // Sort by relevance descending - Requirements: 3.2 .sort((a: RetrievedMemory, b: RetrievedMemory) => b.relevanceScore - a.relevanceScore) // Limit results - Requirements: 3.4 .slice(0, this.config.maxMemories); const retrievalTime = Date.now() - startTime; Logger.debug( `Retrieved ${memories.length} memories for problem context in ${retrievalTime}ms (filtered from ${searchResult.memories.length})` ); // Requirements: 3.5 - Return empty context when no memories meet threshold return { memories, totalFound: searchResult.totalCount, retrievalTime, }; } catch (error) { Logger.error("Failed to retrieve memory context:", error); // Return empty context on error - reasoning should continue without memories return { memories: [], totalFound: 0, retrievalTime: Date.now() - startTime, }; } } /** * Augment problem context with relevant memories * * Retrieves relevant memories and injects them into the problem context * to provide additional background information for reasoning. * * Requirements: 13.1, 13.2 * * @param problemText - The original problem description * @param userId - User ID for memory isolation * @returns Augmented problem context with memory information */ async augmentProblemContext( problemText: string, userId: string ): Promise<AugmentedProblemContext> { // Retrieve relevant memories const memoryContext = await this.retrieveContext(problemText, userId); // If no memories found, return original problem without augmentation if (memoryContext.memories.length === 0) { return { originalProblem: problemText, augmentedProblem: problemText, memoryBackground: "", memoriesUsed: [], hasMemoryContext: false, }; } // Build memory background from retrieved memories const memoryBackground = this.buildMemoryBackground(memoryContext.memories); // Create augmented problem with memory context const augmentedProblem = this.buildAugmentedProblem(problemText, memoryBackground); return { originalProblem: problemText, augmentedProblem, memoryBackground, memoriesUsed: memoryContext.memories, hasMemoryContext: true, }; } /** * Build memory background text from retrieved memories * * Formats memories into a readable background section that can be * injected into the problem context. * * @param memories - Retrieved memories to format * @returns Formatted memory background text */ private buildMemoryBackground(memories: RetrievedMemory[]): string { if (memories.length === 0) { return ""; } // Sort by relevance score (highest first) const sortedMemories = [...memories].sort((a, b) => b.relevanceScore - a.relevanceScore); // Build background sections const sections: string[] = []; for (const memory of sortedMemories) { const sectorLabel = this.getSectorLabel(memory.primarySector); const keywordsStr = memory.keywords.length > 0 ? ` [Keywords: ${memory.keywords.join(", ")}]` : ""; sections.push(`- ${sectorLabel}: ${memory.content}${keywordsStr}`); } return `Relevant context from previous interactions:\n${sections.join("\n")}`; } /** * Build augmented problem text with memory context * * @param originalProblem - Original problem description * @param memoryBackground - Formatted memory background * @returns Augmented problem text */ private buildAugmentedProblem(originalProblem: string, memoryBackground: string): string { if (!memoryBackground) { return originalProblem; } return `${memoryBackground}\n\nCurrent problem:\n${originalProblem}`; } /** * Get human-readable label for memory sector * * @param sector - Memory sector type * @returns Human-readable sector label */ private getSectorLabel(sector: MemorySectorType): string { const labels: Record<MemorySectorType, string> = { episodic: "Past experience", semantic: "Known fact", procedural: "Learned procedure", emotional: "Emotional context", reflective: "Previous insight", }; return labels[sector] ?? "Memory"; } /** * Update configuration * * @param config - Partial configuration to update */ updateConfig(config: Partial<MemoryAugmentedReasoningConfig>): void { this.config = { ...this.config, ...config }; } /** * Get current configuration * * @returns Current configuration */ getConfig(): MemoryAugmentedReasoningConfig { return { ...this.config }; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/keyurgolani/ThoughtMcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server