npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

anansi-memory

v0.3.1

Published

The memory layer for AI apps — persistent, synthesized context for any LLM application

Readme

anansi-memory

Persistent memory for AI apps, backed by a bi-temporal knowledge graph — every fact carries when it was true and when you learned it. Give any LLM app long-term memory in two API calls. MIT-licensed and self-hostable.

npm install anansi-memory

Usage

import AnansiMemory from "anansi-memory";

const memory = new AnansiMemory({ apiKey: process.env.ANANSI_API_KEY });

// Store a conversation turn
await memory.ingest({
  userId: "user_123",
  content: "User is building a voice agent. Prefers TypeScript. Team of 4.",
  sourceType: "conversation",
});

// Before your next LLM call — inject synthesized context into the system prompt
const ctx = await memory.context({ userId: "user_123", q: "what is the user building?" });
const systemPrompt = `You are a helpful assistant.\n\n${memory.formatForPrompt(ctx)}`;

context() returns a synthesized profile — static facts and dynamic context arrays that drop straight into a prompt, plus relevant chunks when you pass q. No chunks to dedupe, rank, or trim yourself.

API

new AnansiMemory(options)

| Option | Type | Description | |---|---|---| | apiKey | string | Your API key (ans_...) | | baseUrl | string | Override API base URL (default: https://anansimemory.com) |

memory.ingest(options)

Store content in a user's memory. Returns { id, queued: true } (202 — embedding runs off the request path).

| Option | Type | Required | Description | |---|---|---|---| | userId | string | ✓ | Your internal user ID | | content | string | ✓ | Text to remember, max 100 KB | | sourceType | string | | conversation, document, note, meeting, custom | | sourceId | string | | Idempotency key — re-ingesting the same ID is a no-op | | metadata | object | | title, author, timestamp, any custom fields (all filterable) | | embedding | number[] | | Pre-computed embedding — skips the internal embedding provider | | sessionId | string | | Scope this ingest to a conversation session | | agentId | string | | Scope this ingest to a specific agent |

memory.context(options)

Retrieve synthesized memory for a user. Returns { static, dynamic, relevant, temporal, entities }.

| Option | Type | Required | Description | |---|---|---|---| | userId | string | ✓ | Your internal user ID | | q | string | | Optional query to retrieve relevant chunks |

memory.formatForPrompt(ctx)

Format a context result into a ready-to-inject system-prompt block.

Also available

const results  = await memory.search({ userId, query, searchMode, alpha, limit, filters });
const chunks   = await memory.listMemories({ userId, q, sourceType, limit, offset });
const entities = await memory.listEntities({ userId, asOf, asOfKnowledge }); // bi-temporal point queries
await memory.deleteUser(userId); // GDPR hard-delete

listEntities accepts asOf (the graph as it was valid at an instant) and asOfKnowledge (the graph as we knew it at an instant). The entity graph is a Pro+ feature.

Handling API Responses

Error Handling

The Anansi SDK throws an AnansiError for non-successful API responses. You can use the statusCode property to handle different types of errors programmatically.

import AnansiMemory, { AnansiError } from "anansi-memory";

try {
  await memory.ingest({ userId, content });
} catch (err) {
  if (err instanceof AnansiError) {
    console.error(`Anansi API Error (Status ${err.statusCode}): ${err.message}`);
    switch (err.statusCode) {
      case 401:
        // Handle invalid API key
        break;
      case 402:
        // Handle monthly quota exceeded (don't retry)
        break;
      case 429:
        // Handle rate limit exceeded (retry with backoff, e.g., after 60s)
        break;
      case 413:
        // Handle content too large
        break;
      default:
        // Handle other client or server errors
        break;
    }
  }
}

Rate Limiting and Quotas

The API enforces both rate limits (requests per minute) and monthly quotas.

  • Rate Limits (429): If you exceed the rate limit, the API will return a 429 Too Many Requests error. The SDK will throw an AnansiError with this status code. It is safe to retry these requests after a short delay (e.g., using exponential backoff).
  • Quotas (402): If your monthly usage quota is exceeded, the API will return a 402 Payment Required error. These requests should not be retried automatically. Instead, this indicates that you need to upgrade your plan.

Idempotency

The ingest method supports a sourceId parameter. You can use this to provide a unique identifier for each piece of content you ingest. If you try to ingest content with a sourceId that has already been used, Anansi will recognize it as a duplicate and will not re-ingest the content, effectively making the ingest operation idempotent for that sourceId. This is useful for preventing duplicate memories from being created due to retries or redundant processing.

// If this is called multiple times, the content will only be ingested once.
await memory.ingest({
  userId: "user_123",
  content: "This is a unique piece of information.",
  sourceId: "my-unique-source-id-123",
});

Pagination

The listMemories method supports pagination through limit and offset parameters.

const pageSize = 20;
let currentPage = 0;

async function fetchMemoriesPage(page: number) {
  const { memories, total } = await memory.listMemories({
    userId: "user_123",
    limit: pageSize,
    offset: page * pageSize,
  });
  console.log(`Page ${page + 1}: Found ${memories.length} of ${total} total memories.`);
  return memories;
}

// Fetch the first page
const firstPageMemories = await fetchMemoriesPage(currentPage);

Links

MIT licensed.