TypeScript - todos los métodos, tres grupos.
Escribir, leer, eliminar. Cada ejemplo de abajo se ejecutó contra la API en vivo el 2026-08-01; las respuestas son textuales.
npm install wontopos
import { Client } from "wontopos"; const mem = new Client({ apiKey: "wos-live-..." });
Elige un modelo
La clave de API elige qué memoria (tu cuenta); el modelo elige qué motor la lee. Todos los modelos comparten una misma memoria, así que puedes almacenar con uno y recuperar con otro. Define un valor por defecto en el constructor; anula una llamada puntual con withModel().
const mem = new Client({ apiKey: "wos-live-...", model: "tablet-1" }); // default mem.recall("...", "alice"); // tablet-1 mem.withModel("scroll-1").recall("...", "alice"); // or pick a model per call
listModels
El catálogo - los ids que puedes pasar a model y si cada uno está disponible. Los modelos con memory: "shared" leen el mismo store; "isolated" mantiene el suyo propio. No requiere clave de API.
await mem.listModels();
[{"id": "tablet-1", "name": "Tablet 1", "available": true, "memory": "shared"},
{"id": "tablet-2", "name": "Tablet 2", "available": true, "memory": "shared"},
{"id": "scroll-1", "name": "Scroll 1", "available": true, "memory": "shared"},
{"id": "scroll-1.2", "name": "Scroll 1.2", "available": true, "memory": "shared"}]ping
Confirma la conexión y que tu clave de API funciona: una comprobación de una línea.
await mem.ping(); // true, or throws AuthenticationError / PaymentRequiredError
El catálogo de arriba siempre refleja los modelos disponibles en este momento - pasa cualquier otro id y obtendrás un error claro. Los modelos nuevos aparecen ahí automáticamente cuando se lanzan.
Escribir
add
Almacena una memoria. Sin llamada a LLM al entrar: pagas solo la tarifa de escritura.
await mem.add("she prefers tea over coffee", "alice"); await mem.add("I promised the summary by Friday", "alice", { speaker: "me" }); // its own words - no registration needed
{"id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "stored (1 chunks)"}addTurn
Almacena un turno de conversación (usuario + asistente) en la memoria de corto y largo plazo a la vez.
await mem.addTurn("hi", "hello!", "alice");
{"status": "ok"}speaker
Cada recuerdo puede llevar quién lo dijo. Registra a una persona una vez y luego pasa su nombre como speaker; "me" (las palabras del propio asistente) nunca necesita registro. La búsqueda también acepta speaker, para recordar solo las palabras de una persona.
await mem.addSpeaker("Bob", "alice"); // once per person; "me" needs no registration await mem.add("I promised to send the report on Friday", "alice", { speaker: "me" }); await mem.add("Bob said the deadline moved to Tuesday", "alice", { speaker: "Bob" }); await mem.search("what did Bob say about deadlines?", "alice", 10, { speaker: "Bob" });
addBulk
Carga un bloque grande de texto. Se divide e indexa en el servidor, ideal para importar historial existente.
await mem.addBulk("Alice moved to Brooklyn in March. She works at a design studio downtown.", "alice");
{"elapsed_secs": 0.154154944, "status": "ok", "stored": 1, "total_chunks": 1}update
Un hecho cambió. La memoria antigua se marca como reemplazada (se conserva como historial); la nueva ocupa su lugar en el recall.
await mem.update("576700aa-...", "she switched to coffee this year", "alice");
{"new_memory_id": "07e94433-b7cc-4e49-8d8f-f37fc1a392b7",
"old_memory_id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "superseded"}Leer
search
Búsqueda semántica, lo más relevante primero. Cualquier idioma encuentra cualquier memoria, sin importar en qué idioma se escribió. El SDK devuelve directamente el array memories; el cuerpo HTTP en bruto se muestra abajo. Algunos modelos responden con más de un conjunto de resultados y el SDK los devuelve fusionados, así que el array puede contener MÁS de max_results. Dimensiona tu ventana de prompt según lo que recibes, no según el número que pediste.
const r = await mem.search("what does she drink?", "alice", 1);
[{
"id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624",
"content": "she prefers tea over coffee",
"category": "general",
"time_bucket": "2026-06",
"importance": 0.3,
"similarity": 0.6316057443618774,
"is_superseded": false,
"superseded_by": null,
"created_at": "2026-07-10T04:20:39.688276876Z"
}]| Campo | Significado |
|---|---|
| similarity | Qué tan cerca está esta memoria de tu consulta (0–1). |
| is_superseded | True si este hecho fue reemplazado por update(). |
| search_ms | Tiempo de recuperación del lado del servidor. |
recall
Un solo viaje de ida y vuelta devuelve todo lo que tu LLM necesita - pega el resultado directamente en tu prompt: un contexto acotado y de tamaño fijo sin importar cuánto hayas almacenado.
const ctx = await mem.recall("what does she drink?", "alice");
{"short_term": {"count": 2, "turns": [{"role": "user", "content": "hi", ...}]},
"long_term": {"count": 4, "memories": [{"content": "she prefers tea over coffee",
"similarity": 0.63, ...}]},
"context": {"count": 4, "around_top_memory": [
"[match] she prefers tea over coffee",
"[after] Alice moved to Brooklyn in March. ..."]},
"instruction": "Use short_term for recent context, long_term for relevant
past memories, context for surrounding conversation of the
most relevant memory."}history
Turnos de conversación recientes (memoria de corto plazo), los más antiguos primero.
const turns = await mem.history("alice");
{"count": 2, "turns": [
{"role": "user", "content": "hi", "timestamp": "2026-07-10T04:20:40.989011337Z"},
{"role": "assistant", "content": "hello!", "timestamp": "2026-07-10T04:20:40.989013416Z"}
], "user_id": "alice"}stats
Conteos de memoria de un usuario.
await mem.stats("alice");
{"short_term_turns": 2, "total_memories": 4, "user_id": "alice"}get
Recupera una memoria por id - el id que devolvió add o list_memories. Solo el texto original almacenado y sus metadatos. Un id de otro store, o una memoria borrada o invalidada, devuelve 404.
const m = await mem.get("alice", "576700aa-...");
{"id": "576700aa-...", "content": "she prefers tea over coffee",
"category": "general", "created_at": "2026-07-10T04:20:39Z", "event_date": null,
"is_superseded": false, "superseded_by": null}listMemories
Lista las memorias de un almacén: solo el texto original que guardaste y sus metadatos. Paginado por cursor: reenvía el next_cursor devuelto para la página siguiente.
const page = await mem.listMemories("alice", { limit: 100 });
{"count": 2, "next_cursor": null, "memories": [
{"id": "576700aa-...", "content": "she prefers tea over coffee",
"category": "general", "created_at": "2026-07-10T04:20:39Z", "event_date": null,
"is_superseded": false, "superseded_by": null}
]}iterMemories · exportMemories
Recorre todas las memorias sin gestionar el cursor, o trae el almacén entero de una vez.
for await (const m of mem.iterMemories("alice")) console.log(m.id, m.content); const everything = await mem.exportMemories("alice");
Eliminar
delete
Elimina una sola memoria por id.
await mem.delete("alice", "576700aa-...");
{"memory_id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "deleted"}deleteAll
Borra todo lo de un usuario - una llamada, lista para GDPR.
await mem.deleteAll("alice");
{"memories_deleted": 4, "status": "deleted", "user_id": "alice"}Errores y fiabilidad
Cada fallo es un error tipado: captura el concreto (límite de tasa, autenticación, pago) o todos con el WosError base.
import { NotFoundError, PaymentRequiredError } from "wontopos"; try { await mem.add("...", "alice"); } catch (e) { if (e instanceof NotFoundError) await mem.createStore("alice"); else if (e instanceof PaymentRequiredError) topUp(); // out of credit else throw e; }
rateLimit
Lee la cuota restante tras cualquier llamada y reduce el ritmo antes de llegar al límite.
await mem.search("...", "alice"); const rl = mem.rateLimit; // { limit: 150, remaining: 3, reset: ... }
searchSelf
Ambos carriles en una sola llamada en un modelo de memoria propia (Scroll 1.2+): lo que dijeron otros y las palabras PROPIAS del agente, separadas para que quien lee nunca confunda quién habló.
const { memories, self_memories } = await mem.searchSelf("what did I promise?", "alice"); // memories = what others said · self_memories = the agent's OWN words
listEngrams
Pregunta al servicio qué engramas y formas de entrega puede ejecutar el modelo seleccionado, en vez de fijar nombres que quedan obsoletos en cuanto sale uno nuevo.
const { engrams, forms } = await mem.listEngrams(); // ask, never hard-code
filters
Acota la búsqueda a una parte del almacén. Se aplica antes del ranking, así que obtienes las mejores coincidencias dentro del filtro, no un top-N filtrado después.
await mem.search("what did we decide", "alice", 10, { filters: { categories: ["work"], event_from: "2026-01-01" }, // when it HAPPENED });
idempotencyKey
Hace segura la repetición de una escritura. Úsala cuando el reintento es tuyo - un trabajo que murió y se relanzó, una cola que reentrega.
await mem.add("she prefers tea", "alice", {}, { idempotencyKey: `import:${row.id}` });
import:row-42), nunca una constante: una clave reutilizada en dos escrituras distintas reproduce la primera y la segunda se pierde en silencio. Formato: 1-128 caracteres de [A-Za-z0-9._:-].withTimeout / withRetries / withDeadline
Ajusta un único punto de llamada sin tocar el cliente que ya construiste: un clon con más tiempo de espera para un backfill grande, o sin reintentos dentro de tu propio bucle de reintento.
timeout acota un intento, así que una llamada que reintenta puede sobrevivirlo: con los valores por defecto una sola llamada puede retener una conexión 30 s, esperar, reintentar y reintentar otra vez. deadline acota la llamada entera: cada intento se limita a lo que queda, y ninguna espera se duerme más allá del presupuesto. Ponlo cuando quien llama tiene un límite real, como un manejador de peticiones con cinco segundos.
await mem.withTimeout(120_000).addBulk(bigBlob, "alice"); // this slow call only await mem.withRetries(0).add("...", "alice"); // you retry, not the SDK await mem.withDeadline(5_000).recall("...", "alice"); // 5s for the whole call await mem.withSignal(ctrl.signal).recall("...", "alice"); // caller can cancel