Use the memory API

In shortStore, search, and manage long-term memories across agent conversations with the 10xGraph TypeScript client.

  • 6 min read
  • 12 sections
  • Updated
  • v0.10.0
  • Markdown

The memory API lets you store facts, preferences, and conversation history that persists across threads and sessions. Agents can search this long-term context during conversation to provide personalized, informed responses. This guide shows you how to build agents that learn and remember.

Why memory matters

Without memory, each thread starts fresh: the agent sees no history, no preferences, no facts about the user. With memory, you can:

  • Personalize responses based on learned user preferences.
  • Accumulate context that grows richer over time.
  • Build continuity across separate conversations and days.
  • Let agents refer to prior decisions and past interactions.

The memory API handles the storage and retrieval; you control what to remember and how to use it.

Prerequisites

  • A configured TenxGraphClient. See create the client.
  • The API server running with a memory store configured in 10xgraph.json.

Store a memory

Use storeMemory() to save any piece of information. Each memory has a type (semantic, episodic, etc.) and a category (like “preferences” or “history”).

TypeScript
import { MemoryType } from '10xgraph-client';

const response = await client.storeMemory({
  content: 'User works in healthcare and prefers technical explanations.',
  memory_type: MemoryType.SEMANTIC,
  category: 'user_profile',
  metadata: { source: 'inferred', confidence: 0.9 },
});

const memoryId = response.data.memory_id;
console.log('Stored memory with ID:', memoryId);

The response includes memory_id, which you can use later to update or delete the memory. Save it if you need to reference the memory later.


Search memories to build context

Vector similarity search finds memories that relate to your current query, even if the wording differs. This is the core value of the memory API: you ask a question, and the store returns relevant past facts.

TypeScript
import { MemoryType, RetrievalStrategy } from '10xgraph-client';

const results = await client.searchMemory({
  query: 'What is the user\'s background?',
  memory_type: MemoryType.SEMANTIC,
  category: 'user_profile',
  limit: 3,
  score_threshold: 0.6,
  retrieval_strategy: RetrievalStrategy.SIMILARITY,
});

for (const result of results.data.results) {
  console.log(`Match (score ${result.score.toFixed(2)}): ${result.content}`);
}

Each result carries a score; higher means a closer match. The score_threshold filters out low-scoring matches. Score scale depends on your store backend and distance metric.


Build an agent that uses memory

The full pattern is: search for relevant memories, build a system prompt with them, then invoke the agent. This way, the agent always has context.

TypeScript
import { TenxGraphClient, Message, MemoryType, RetrievalStrategy } from '10xgraph-client';

const client = new TenxGraphClient({ baseUrl: 'http://localhost:8000' });
const THREAD_ID = 'user-session-123';

async function respondWithMemory(userQuestion: string) {
  // 1. Search for relevant memories
  const memories = await client.searchMemory({
    query: userQuestion,
    memory_type: MemoryType.SEMANTIC,
    limit: 5,
    score_threshold: 0.65,
  });

  // 2. Build context from the top matches
  const context = memories.data.results
    .map(r => `- ${r.content}`)
    .join('\n');

  const systemPrompt = context
    ? `You are a helpful assistant with knowledge of the user:\n${context}`
    : 'You are a helpful assistant.';

  // 3. Invoke the agent with memory context
  const response = await client.invoke(
    [
      Message.text_message(systemPrompt, 'system'),
      Message.text_message(userQuestion),
    ],
    {
      config: { thread_id: THREAD_ID },
      response_granularity: 'low',
    }
  );

  // 4. Store this interaction for future reference
  const last = response.messages[response.messages.length - 1];
  const answer = last.content
    .filter((b) => b.type === 'text')
    .map((b) => (b as { text: string }).text)
    .join('');
  await client.storeMemory({
    content: `User asked: "${userQuestion}". Agent responded with: "${answer}"`,
    memory_type: MemoryType.EPISODIC,
    category: 'conversations',
    metadata: { timestamp: new Date().toISOString(), thread_id: THREAD_ID },
  });

  return response;
}

// Use it
const result = await respondWithMemory('How should I approach this project?');
console.log(result.messages);

This pattern ensures every conversation is stored for learning, and every new question is informed by past context.


Organize memories with types and categories

Choosing the right MemoryType makes searches more precise. See memory reference for the full list, but here are the main types:

  • Semantic: Facts, preferences, knowledge. Best for agent learning.
  • Episodic: Specific conversations, events, interactions. Builds a history.
  • Procedural: How-to workflows, recurring processes.
  • Entity: Information about people, places, or things.
  • Relationship, Declarative and Custom are also available.

Use categories to group related memories (like "user_profile", "conversations", "work_history"). When searching, you can filter by category to avoid irrelevant results.

TypeScript
// Store different types
await client.storeMemory({
  content: 'User is a software engineer interested in Rust.',
  memory_type: MemoryType.SEMANTIC,
  category: 'user_profile',
});

await client.storeMemory({
  content: 'Discussed deployment architecture for microservices.',
  memory_type: MemoryType.EPISODIC,
  category: 'conversations',
});

// Search only semantic memories in the profile
const facts = await client.searchMemory({
  query: 'What does the user do?',
  memory_type: MemoryType.SEMANTIC,
  category: 'user_profile',
  limit: 3,
});

Retrieve and update a specific memory

If you have a memory_id, you can fetch a single memory by ID:

TypeScript
const memory = await client.getMemory(memoryId);
console.log('Content:', memory.data.memory.content);
console.log('Type:', memory.data.memory.memory_type);
console.log('Stored at:', memory.data.memory.timestamp);

To update a memory’s content or metadata:

TypeScript
await client.updateMemory(
  memoryId,
  'User works in healthcare, prefers technical explanations, and uses Python daily.',
  {
    metadata: { updated_at: new Date().toISOString(), reason: 'user_correction' },
  }
);

Advanced search options

The memory API supports multiple retrieval strategies and distance metrics. Most use cases work well with the defaults (similarity and cosine distance), but for specialized scenarios, you have options.

For detailed tables of retrieval strategies and distance metrics, see memory reference and distance metric reference.

Common advanced patterns:

TypeScript
// Temporal retrieval: get the most recent memories
const recent = await client.searchMemory({
  query: 'recent activity',
  limit: 10,
  retrieval_strategy: RetrievalStrategy.TEMPORAL,
});

// Hybrid search: combined retrieval approaches
const hybrid = await client.searchMemory({
  query: 'user preferences',
  limit: 5,
  retrieval_strategy: RetrievalStrategy.HYBRID,
  score_threshold: 0.5,
});

// Cap results by tokens to avoid oversized context
const limited = await client.searchMemory({
  query: 'project history',
  limit: 20,
  max_tokens: 2000,  // Cap the total tokens of returned results
});

List and manage memory lifecycle

List all stored memories:

TypeScript
const response = await client.listMemories({ limit: 100 });
console.log(`Total memories: ${response.data.memories.length}`);

for (const mem of response.data.memories) {
  console.log(`[${mem.memory_type}] ${mem.content.slice(0, 60)}`);
}

Delete a single memory by ID:

TypeScript
await client.deleteMemory(memoryId);
console.log('Memory deleted');

Bulk-delete memories matching a filter (more efficient than deleting one by one):

TypeScript
// Clear all session-temporary memories
await client.forgetMemories({
  memory_type: MemoryType.EPISODIC,
  category: 'session_temp',
});

// Clear memories with a custom filter
await client.forgetMemories({
  filters: { archived: true },
});

Common errors and fixes

Problem Cause Solution
TenxGraphError status 404 on getMemory() Memory ID not found or deleted. Verify the ID is correct. Use listMemories() to check what exists.
TenxGraphError status 503 Store not configured or unreachable. Check the store field in 10xgraph.json and ensure the store backend is running.
Empty search results Score threshold too high, or no memories match the type/category. Lower score_threshold, remove the type filter, or store more memories.
Irrelevant search results Query is too vague, or memories are poorly written. Use specific queries. Store memories with clear, descriptive content.

What you learned

  • Use storeMemory() to save facts, preferences, and interactions with a type and category.
  • searchMemory() finds related memories using vector similarity; higher scores mean stronger matches.
  • Build agent context by searching memories before invoking the agent.
  • Store agent interactions as episodic memories to build a conversation history.
  • Organize memories with types and categories to make searches more precise.
  • Use updateMemory(), deleteMemory(), and forgetMemories() to manage the memory lifecycle.

Next step

See files and multimodal to learn how to upload and reference images, audio, and documents in your agents.

Last updated for v0.10.0Edit this page on GitHubReport an issue