Skip to main content

Walrus Memory

The recommended default client. The relayer handles embeddings, Seal encryption, Walrus upload, and vector indexing.

How it works​

  1. The SDK signs each request with your delegate key
  2. The relayer verifies delegate access
  3. remember(text) takes the memory text and returns an accepted job whose job_id you pass to waitForRememberJob(), while the relayer encrypts, uploads, and indexes in the background
  4. recall({ query, limit }) takes the search query and an optional limit on the number of matches, searches the client's memory space (owner address, namespace, and app ID), and returns decrypted matches
Source: sdk/usage/memwal.md
import { MemWal } from "@mysten-incubation/memwal";

const memwal = MemWal.create({
key: "<your-ed25519-private-key>",
accountId: "<your-memwal-account-id>",
serverUrl: "https://your-relayer-url.com",
namespace: "chatbot-prod",
});

Core methods​

Source: sdk/usage/memwal.md
// Store a memory
const job = await memwal.remember("User prefers dark mode and works in TypeScript.");
await memwal.waitForRememberJob(job.job_id);

// Recall relevant memories
const result = await memwal.recall({ query: "What do we know about this user?", limit: 5 });

// Extract and store facts from longer text
const analyzed = await memwal.analyze(
"I live in Hanoi, prefer dark mode, and usually work late at night."
);
console.log(analyzed.job_ids);

// Check relayer health
await memwal.health();

Restore​

Rebuild missing indexed entries for one namespace. restore() takes the namespace as its first argument and an optional limit as its second, the maximum number of blobs to inspect in that call (default 10), as in restore("chatbot-prod", 10), and returns a result object. Incremental, namespace-scoped, and meant to repair PostgreSQL vector state from Walrus-backed memory.

Source: sdk/usage/memwal.md
const result = await memwal.restore("chatbot-prod", 10);

Lower-level methods​

Use these when you already have a vector or encrypted payload:

  • rememberManual({ encryptedData, vector, namespace? })
  • recallManual({ vector, limit?, namespace? })
  • embed(text)

What analyze() returns​

The relayer extracts facts synchronously and returns one job_id per fact, then embeds, encrypts, uploads, and indexes each fact in the background. The analyze() result contains:

  • job_ids: one polling ID per extracted fact
  • facts: each entry has text (the extracted fact), id (same value as job_id), and job_id
  • fact_count: the number of accepted facts
  • status: usually pending
  • owner: the owner address

To wait until every extracted fact is stored, use analyzeAndWait(text, namespace?, opts?).

Read recall results​

The recall result holds its matches in result.results. Each match carries the decrypted text and a distance, where a smaller number means a closer match:

for (const memory of result.results) {
console.log(memory.distance.toFixed(3), memory.text);
}

recall returns up to limit results, defaulting to 10, and gives no signal when it drops extra matches. Treat a result count equal to limit as a sign that more matches might exist.

Restore limit and pagination​

The limit argument must be a positive integer. Otherwise, restore() throws a TypeError. Restore inspects your onchain blobs newest-first and has no pagination cursor. If you repeat a call at the same limit, it re-inspects the same newest blobs and returns nothing new. To rebuild a large namespace, set limit high enough to cover every blob in the namespace in a single call. A restored count that stops increasing across reruns is not proof that every blob is covered. You can safely run restore more than once, because it skips blobs the relayer already indexed.