agent-memory-systems

Design and implement memory systems that give agents persistent knowledge and context.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "agent-memory-systems" with this command: npx skills add latestaiagents/agent-skills/latestaiagents-agent-skills-agent-memory-systems

Agent Memory Systems

Design and implement memory systems that give agents persistent knowledge and context.

When to Use

  • Agents need to remember across sessions

  • Multiple agents share knowledge

  • Long-running tasks require state persistence

  • Building agents that learn from experience

Memory Types

┌─────────────────────────────────────────────────────────────┐ │ AGENT MEMORY TAXONOMY │ ├─────────────────────────────────────────────────────────────┤ │ │ │ Working Memory (Active Context) │ │ └─ Current conversation, immediate task state │ │ │ │ Short-Term Memory (Session) │ │ └─ Recent interactions, temporary facts │ │ │ │ Long-Term Memory (Persistent) │ │ ├─ Episodic: Past events, experiences │ │ ├─ Semantic: Facts, knowledge, learned info │ │ └─ Procedural: How to do things, skills │ │ │ └─────────────────────────────────────────────────────────────┘

Working Memory

The agent's current context window.

interface WorkingMemory { // Current task context task: { description: string; requirements: string[]; progress: string[]; };

// Active entities being discussed entities: Map<string, Entity>;

// Recent messages conversationWindow: Message[];

// Scratchpad for reasoning scratchpad: string; }

class WorkingMemoryManager { private memory: WorkingMemory; private MAX_MESSAGES = 20;

addMessage(message: Message) { this.memory.conversationWindow.push(message);

// Evict old messages
if (this.memory.conversationWindow.length > this.MAX_MESSAGES) {
  const evicted = this.memory.conversationWindow.shift();
  // Optionally summarize and store
  this.summarizeToShortTerm(evicted);
}

}

updateEntity(id: string, entity: Entity) { this.memory.entities.set(id, entity); }

getContext(): string { return Task: ${this.memory.task.description} Progress: ${this.memory.task.progress.join(', ')} Key Entities: ${[...this.memory.entities.values()].map(e => e.summary).join('\n')} Recent Discussion: ${this.memory.conversationWindow.slice(-5).map(m => m.content).join('\n')} ; } }

Short-Term Memory

Session-scoped, expires after inactivity.

interface ShortTermMemory { sessionId: string; startedAt: Date; lastAccessedAt: Date; expiresAt: Date;

// Conversation summary summary: string;

// Key facts learned this session facts: Fact[];

// Decisions made decisions: Decision[];

// Files accessed touchedFiles: string[]; }

class ShortTermStore { private store = new Map<string, ShortTermMemory>(); private TTL_MS = 30 * 60 * 1000; // 30 minutes

async get(sessionId: string): Promise<ShortTermMemory | null> { const memory = this.store.get(sessionId);

if (!memory) return null;
if (Date.now() > memory.expiresAt.getTime()) {
  // Expired - archive to long-term
  await this.archiveToLongTerm(memory);
  this.store.delete(sessionId);
  return null;
}

// Touch
memory.lastAccessedAt = new Date();
memory.expiresAt = new Date(Date.now() + this.TTL_MS);

return memory;

}

async addFact(sessionId: string, fact: Fact) { const memory = await this.getOrCreate(sessionId); memory.facts.push(fact);

// Check if fact should be promoted to long-term
if (this.shouldPromote(fact)) {
  await this.promoteToLongTerm(fact);
}

} }

Long-Term Memory

Episodic Memory (Events/Experiences)

interface Episode { id: string; timestamp: Date; type: 'task_completed' | 'error_resolved' | 'user_feedback' | 'learning';

// What happened description: string; context: Record<string, unknown>;

// Outcome outcome: 'success' | 'failure' | 'partial'; lessons: string[];

// For retrieval embedding: number[]; tags: string[]; }

class EpisodicMemory { private vectorStore: VectorStore;

async remember(episode: Episode): Promise<void> { // Generate embedding for semantic search episode.embedding = await this.embed( ${episode.description} ${episode.lessons.join(' ')} );

await this.vectorStore.insert(episode);

}

async recall(query: string, limit: number = 5): Promise<Episode[]> { const queryEmbedding = await this.embed(query);

return this.vectorStore.similaritySearch(queryEmbedding, {
  limit,
  threshold: 0.7
});

}

async recallByType(type: Episode['type'], limit: number = 10): Promise<Episode[]> { return this.vectorStore.filter({ type }, { limit, orderBy: 'timestamp DESC' }); } }

Semantic Memory (Facts/Knowledge)

interface Fact { id: string; subject: string; predicate: string; object: string; confidence: number; source: string; learnedAt: Date; lastVerified: Date; embedding: number[]; }

class SemanticMemory { private facts: VectorStore<Fact>;

async learn(fact: Omit<Fact, 'id' | 'embedding'>): Promise<void> { // Check for conflicts const existing = await this.findRelated(fact.subject, fact.predicate);

if (existing.length > 0) {
  // Handle contradiction or update
  await this.resolveConflict(existing, fact);
  return;
}

// Store new fact
await this.facts.insert({
  ...fact,
  id: generateId(),
  embedding: await this.embed(`${fact.subject} ${fact.predicate} ${fact.object}`)
});

}

async query(question: string): Promise<Fact[]> { // Semantic search for relevant facts const embedding = await this.embed(question); return this.facts.similaritySearch(embedding, { limit: 10 }); }

async getFactsAbout(subject: string): Promise<Fact[]> { return this.facts.filter({ subject }); } }

Procedural Memory (Skills/How-To)

interface Procedure { id: string; name: string; description: string; trigger: string; // When to use this steps: string[]; examples: Example[]; successRate: number; usageCount: number; }

class ProceduralMemory { private procedures: Map<string, Procedure> = new Map();

async findProcedure(task: string): Promise<Procedure | null> { // Match task to known procedures const candidates = await this.matchProcedures(task);

if (candidates.length === 0) return null;

// Return best match by success rate and relevance
return candidates.sort((a, b) =>
  (b.successRate * b.relevanceScore) - (a.successRate * a.relevanceScore)
)[0];

}

async recordOutcome(procedureId: string, success: boolean): Promise<void> { const proc = this.procedures.get(procedureId); if (!proc) return;

// Update success rate with exponential moving average
const alpha = 0.1;
proc.successRate = alpha * (success ? 1 : 0) + (1 - alpha) * proc.successRate;
proc.usageCount++;

}

async learnProcedure( name: string, steps: string[], fromEpisode: Episode ): Promise<void> { // Create new procedure from successful episode this.procedures.set(generateId(), { id: generateId(), name, description: fromEpisode.description, trigger: this.extractTrigger(fromEpisode), steps, examples: [{ input: fromEpisode.context, output: fromEpisode.outcome }], successRate: 1.0, usageCount: 1 }); } }

Shared Memory (Multi-Agent)

interface SharedMemory { // Namespace for isolation namespace: string;

// Read/write with locking read(key: string): Promise<unknown>; write(key: string, value: unknown): Promise<void>;

// Atomic operations compareAndSwap(key: string, expected: unknown, newValue: unknown): Promise<boolean>;

// Subscriptions subscribe(pattern: string, callback: (key: string, value: unknown) => void): void; }

class RedisSharedMemory implements SharedMemory { constructor( private redis: Redis, public namespace: string ) {}

private key(k: string): string { return ${this.namespace}:${k}; }

async read(key: string): Promise<unknown> { const value = await this.redis.get(this.key(key)); return value ? JSON.parse(value) : null; }

async write(key: string, value: unknown): Promise<void> { await this.redis.set(this.key(key), JSON.stringify(value)); await this.redis.publish(${this.namespace}:updates, JSON.stringify({ key, value })); }

subscribe(pattern: string, callback: (key: string, value: unknown) => void): void { const subscriber = this.redis.duplicate(); subscriber.psubscribe(${this.namespace}:${pattern}); subscriber.on('pmessage', (_, channel, message) => { const { key, value } = JSON.parse(message); callback(key, value); }); } }

Memory Retrieval Strategies

Strategy 1: Recency-Weighted

function recencyWeightedRetrieval( memories: Memory[], query: string, recencyWeight: number = 0.3 ): Memory[] { const now = Date.now();

return memories .map(m => ({ memory: m, score: (1 - recencyWeight) * m.relevanceScore + recencyWeight * Math.exp(-(now - m.timestamp.getTime()) / TIME_DECAY) })) .sort((a, b) => b.score - a.score) .map(x => x.memory); }

Strategy 2: Importance-Based

function importanceBasedRetrieval( memories: Memory[], query: string ): Memory[] { return memories .map(m => ({ memory: m, score: m.relevanceScore * m.importance * (m.accessCount / 10) })) .sort((a, b) => b.score - a.score) .map(x => x.memory); }

Strategy 3: Contextual (RAG)

async function contextualRetrieval( query: string, currentContext: Context ): Promise<Memory[]> { // Expand query with context const expandedQuery = ${query} Current task: ${currentContext.task} Related entities: ${currentContext.entities.join(', ')} ;

// Vector search const candidates = await vectorStore.search(expandedQuery, { limit: 20 });

// Rerank with cross-encoder return reranker.rerank(query, candidates, { limit: 5 }); }

Memory Maintenance

class MemoryMaintenance { // Consolidate short-term to long-term async consolidate(): Promise<void> { const sessions = await shortTermStore.getExpired();

for (const session of sessions) {
  // Extract key learnings
  const learnings = await this.extractLearnings(session);

  // Store in appropriate long-term stores
  for (const learning of learnings) {
    if (learning.type === 'fact') {
      await semanticMemory.learn(learning);
    } else if (learning.type === 'procedure') {
      await proceduralMemory.learnProcedure(learning);
    } else {
      await episodicMemory.remember(learning);
    }
  }
}

}

// Forget outdated/irrelevant memories async forget(): Promise<void> { // Remove low-value memories await episodicMemory.prune({ olderThan: days(90), accessCountBelow: 2, importanceBelow: 0.2 });

// Update fact confidence based on verification
await semanticMemory.decayUnverified({
  olderThan: days(30),
  decayRate: 0.1
});

} }

Best Practices

  • Separate concerns - Different memory types for different purposes

  • Index wisely - Use embeddings for semantic search

  • Expire aggressively - Don't let memory grow unbounded

  • Version memories - Track when facts were learned/updated

  • Handle conflicts - New information may contradict old

  • Secure sensitive data - Some memories shouldn't be shared

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Automation

graphrag-patterns

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

agentic-rag

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

production-rag-checklist

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

rag-evaluation

No summary provided by upstream source.

Repository SourceNeeds Review