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

agentram-sdk

v0.2.0

Published

Persistent memory for AI agents in two API calls. The official TypeScript/JavaScript SDK for AgentRAM.

Readme

AgentRAM TypeScript SDK

Persistent memory for AI agents, in two API calls. The official TypeScript/JavaScript client for AgentRAM - a simple, credit-based HTTP API that gives your agents long-term memory. No vector database, no embeddings, no infrastructure to run.

Zero dependencies - uses the built-in fetch (Node 18+, browsers, and edge runtimes). Ships with full TypeScript types.

Install

npm install agentram-sdk

Get a key

Sign up at agentram.dev for an API key. New accounts start with 1,000 free credits, no card required.

Quickstart

import { AgentRAM } from "agentram-sdk";

const ram = new AgentRAM({ apiKey: "agentram_...", agentId: "agent-01" });

// Store something (1 credit)
await ram.store("user_language", "French");

// Read it back later, even in a brand-new session (1 credit)
const lang = await ram.recall("user_language"); // "French" | null

One call to remember, one to recall.

Everything you can do

// Personal memory (scoped to an agentId)
await ram.store("tone", "formal", { ttlDays: 30 }); // auto-expire after 30 days
await ram.recall("tone");                           // "formal" | null
await ram.delete("tone");                           // true | false
await ram.list({ limit: 50 });                      // MemoryRecord[]
await ram.search("lang");                           // text search, no embeddings

// Shared memory (several agents reading/writing one pool)
const ns = await ram.createNamespace("team-alpha"); // { namespace_key, label }
await ram.storeShared(ns.namespace_key, "goal", "ship v1");
await ram.recallShared(ns.namespace_key, "goal");   // "ship v1" | null
await ram.listShared(ns.namespace_key);

// Temporal memory: facts that change over time, with history
await ram.updateFact("invoice_number", "1044"); // replaces what's current (2 credits)
await ram.current("invoice_number");            // the assertion true now | null
await ram.retire("invoice_number");             // true | false (ends it, keeps the trail)
await ram.listFacts();                          // everything currently true, one per key
await ram.history("invoice_number");            // every version, newest first

// Account
await ram.credits();      // current balance (free)
ram.creditsRemaining;     // last known balance, updated after every call

Override the agent per call: ram.store("k", "v", { agentId: "agent-02" }).

Temporal memory: facts that change

store() and recall() overwrite in place. That is the right shape for most things, but some facts have a history that matters: the last invoice number, the model an agent is currently using, the deploy target for a project. When one of those changes you often want to know what it used to be, who changed it, and when.

Assertions are an append-only log for exactly that. Each write records a value plus who wrote it and which earlier value it replaced.

await ram.updateFact("invoice_number", "1043", { writtenBy: "billing-agent" });
await ram.updateFact("invoice_number", "1044", { writtenBy: "billing-agent" });

const fact = await ram.current("invoice_number");
fact.value;        // "1044"
fact.written_by;   // "billing-agent"
fact.written_at;   // "2026-07-31T..."

for (const a of await ram.history("invoice_number")) {
  console.log(a.written_at, a.value, a.state); // live / superseded / retired
}

updateFact() is the everyday call: it reads what is current and links the new value to it, so the chain stays intact. It costs 2 credits because it is a read plus a write.

Seeing everything at once

listFacts() returns one entry per key, with the value and who wrote it:

for (const fact of await ram.listFacts()) {
  if (fact.contested) console.log(fact.key, "needs resolving");
  else console.log(fact.key, "=", fact.value, "by", fact.written_by);
}

A contested key comes back flagged and without a value, for the same reason current() refuses one: guessing across a list is the same mistake as guessing on a single read. Pass resolve: LAST_WRITE_WINS to fill those in with the newest value. Retired and expired keys do not appear.

When two writers disagree

If two agents write the same key without either knowing about the other, the key is contested: there are two live values and neither replaced the other. The store will not pick one for you, because silently returning whichever came back first is the exact bug this is meant to prevent. It tells you instead:

import { ConflictError, LAST_WRITE_WINS } from "agentram-sdk";

try {
  const fact = await ram.current("invoice_number");
} catch (e) {
  if (e instanceof ConflictError) {
    for (const a of e.assertions) {          // newest first
      console.log(a.value, "from", a.written_by, "at", a.written_at);
    }
    const winner = e.assertions[0];
    await ram.assertFact("invoice_number", "1045", { supersedes: winner.assertion_id });
  }
}

Asserting a value that supersedes one of them resolves the conflict: the others stop being current too.

If you would rather never handle this and just take the newest value, ask for it explicitly:

const fact = await ram.current("invoice_number", { resolve: LAST_WRITE_WINS });

That is safe to pass on every call, since it does nothing unless there is an actual conflict. It is spelled out in full on purpose. It is last-write-wins, with last-write-wins's failure mode, and that should be a decision you made rather than a default you inherited.

retire() is not delete()

delete() erases a flat memory and leaves nothing behind. retire() ends a fact while keeping its history: current() returns null afterwards, but the retirement is itself recorded, with who did it and when, so the trail survives.

A separate keyspace

Assertions and flat memories do not see each other. An assertion called "invoice_number" and a memory called "invoice_number" are two unrelated things. Use store()/recall() for facts you are happy to overwrite, and assertions for facts whose history you care about.

Errors

Everything extends AgentRAMError, so one catch handles all of it:

import { AgentRAM, InsufficientCreditsError, RateLimitError, AgentRAMError } from "agentram-sdk";

try {
  await ram.store("k", "v");
} catch (e) {
  if (e instanceof InsufficientCreditsError) { /* top up */ }
  else if (e instanceof RateLimitError)      { /* back off */ }
  else if (e instanceof AgentRAMError)       { console.log(e.statusCode, e.message); }
}

recall() and recallShared() return null for a missing/expired memory instead of throwing, and delete() returns false - so the common "not there" case stays out of your try/catch. current() and retire() behave the same way for assertions.

ConflictError is the one error carrying extra data: .assertions holds every competing value when a key is contested, which is what you need to resolve it. See Temporal memory above.

Notes

  • Rate limit: 60 requests/minute per API key. The client auto-retries 429 and 5xx a couple of times with backoff.
  • Credits: writes and reads cost 1 credit; updateFact() costs 2 (a read plus a write); createNamespace() and credits() are free. Pricing at agentram.dev.
  • Runtimes: anything with a global fetch - Node 18+, Deno, Bun, browsers, Cloudflare Workers, Vercel Edge.

Build (for contributors)

npm install
npm run build   # compiles src/ to dist/ with type declarations

License

MIT