Memoria a largo plazo para agentes de IA.
WOS es una API de memoria. Almacenas las memorias de un usuario una sola vez, luego recuperas solo las relevantes para cada consulta y las pasas al prompt de tu modelo.
La recuperación es puramente semántica, sin coincidencia de palabras clave ni BM25, por lo que la calidad del recall es idéntica en todos los idiomas. Cada consulta devuelve un contexto pequeño y acotado sin importar cuánto hayas almacenado, y nunca se ejecuta un modelo sobre tus memorias almacenadas.
Operaciones principales
store- guarda una memoria de un usuario.recall- obtiene las memorias relevantes para una consulta. Esta es la llamada principal.search- búsqueda semántica directa sobre las memorias almacenadas.supersede- actualiza o reemplaza una memoria desactualizada.forget- elimina una sola memoria o un usuario completo (GDPR).
Tres modelos, un mismo linaje.
Los modelos de WOS llevan el nombre de cómo la humanidad ha conservado el conocimiento a lo largo de la historia - Tablet, Scroll, Codex. Piedra, pergamino, libro encuadernado: cada uno hace más por tu agente que el anterior.
Tablet
DisponibleUna forma ligera, rápida y de bajo costo de inscribir y recuperar memoria - la base sobre la que se construye cada modelo.
Scroll
DisponibleAñade un modelo de lenguaje que lee tu pregunta con más detenimiento y trae de vuelta un contexto más completo, de modo que la evidencia dispersa regresa reunida en lugar de llegar con una pieza de menos.
Codex
PróximamenteSe abre solo en la página correcta - eligiendo la memoria y las herramientas que cada momento necesita, y afinándose cuanto más se usa.
El informe completo del benchmark de Tablet 1 está en la página de benchmarks.
Páganos $2. Ahorra muchas veces eso en tu LLM.
WOS entrega a tu LLM ~1,200 tokens por consulta - un fragmento acotado y relevante - en lugar de meter todo el historial en cada prompt. La diferencia es enorme, y crece con tu historial.
Cada $1 gastado en WOS ahorra ~$98 en el LLM. Un historial más grande o un modelo más caro → mayor ROI.
De dónde viene el ahorro
- Sin WOS metes todo el historial en cada prompt -
100K tokens × $2.50/1M = $0.25por consulta, a tarifas de entrada de GPT-4o (aproximadamente el doble en modelos de nivel Opus). - Con WOS ingieres una sola vez (
$2/1M), y luego cada consulta es una recuperación diminuta ($3/1M × 1,200) más tu LLM sobre apenas ~1,200 tokens. - Cuantos menos tokens lea tu LLM, menos pagas - y WOS mantiene esa cifra estable a medida que la memoria crece.
Todos los idiomas, la misma precisión.
La recuperación es puramente semántica - solo embeddings, cero coincidencia de palabras clave o BM25. Así que la calidad del recall es idéntica ya sea que tus usuarios escriban en 日本語, 中文, Español o English.
La coincidencia léxica como BM25 está ajustada a la forma de un idioma en particular - morfología, espaciado, escritura. En un store multilingüe eso significa que la calidad de la recuperación varía según el idioma. WOS no usa ninguna coincidencia léxica, así que todos los idiomas pasan por el mismo camino.
Un store, tres idiomas a la vez
No eliges un idioma por store - mézclalos libremente. Abajo, la memoria de un usuario contiene japonés, inglés y español al mismo tiempo, y cada pregunta encuentra la memoria correcta sin importar el idioma. Este es un intercambio real contra la API en vivo:
# one user, three languages stored together mem.add("彼女はコーヒーより紅茶が好き", user_id="alice") # Japanese mem.add("she works at a design studio in Brooklyn", user_id="alice") # English mem.add("A ella le encanta hacer senderismo los sábados", user_id="alice") # Spanish
"¿Qué bebe ella?" -> 彼女はコーヒーより紅茶が好き "what does she do on weekends?" -> A ella le encanta hacer senderismo los sábados "彼女の仕事は?" -> she works at a design studio in Brooklyn
Sin paso de traducción, sin detección de idioma, sin configuración por idioma. Las memorias y las preguntas se ubican por significado, no por idioma - si el significado coincide, el idioma no importa.
Por qué prohibimos las palabras clave a propósito
La puntuación léxica como BM25 refuerza la recuperación en unos idiomas más que en otros, lo cual estorba cuando un store contiene muchos idiomas. Así que la eliminamos del motor por completo y hacemos cumplir esa regla en la revisión de código: con cualquier puntuación léxica en el camino, la calidad del recall diferiría según el idioma.
Ningún modelo se ejecuta sobre tus memorias.
El almacenamiento es literal y el motor busca por embeddings - barato, rápido y determinista. Nunca se ejecuta un modelo sobre tus memorias almacenadas. Tablet no usa ningún modelo; Scroll y Codex añaden uno alrededor del motor para obtener mejores resultados, pero solo ve tu consulta, nunca lo que almacenaste.
- Motor determinista. El motor devuelve las mismas memorias para la misma consulta, siempre - por eso la varianza de nuestro benchmark proviene únicamente del modelo lector.
- Barato a escala. Sin costo de generación al almacenar o recuperar, así que tu factura sigue al almacenamiento - no al uso de modelos - a medida que la memoria crece.
Tus palabras, intactas
Un diseño común ejecuta un modelo de lenguaje al momento de escribir para extraer y reescribir "hechos" del texto. Ese diseño sacrifica tres cosas: costo de generación en cada escritura, latencia añadida y el almacenamiento de la paráfrasis de un modelo en lugar de las palabras originales. WOS hace el intercambio opuesto - almacena lo que se dijo, sin cambios, y deja que tu LLM haga la interpretación al momento de leer, con el texto original en mano.
90.7%, medido y reproducible.
90.7% en LongMemEval-S, promediado sobre 5 ejecuciones independientes (σ 0.5%, ninguna seleccionada a conveniencia), calificado por el juez GPT-4o canónico del benchmark.
En el mismo benchmark, los puntajes varían ampliamente según el protocolo de calificación - el juez, el prompt y lo que se le permite hacer a la capa de recuperación. Usamos el juez GPT-4o canónico y de terceros del benchmark tal como fue publicado, no cambiamos nada para ajustarnos a la prueba, y publicamos el código de puntuación y el prompt del lector para que cualquiera pueda reproducir el 90.7% exactamente.
El protocolo, en una tabla
| Elemento | Qué hacemos |
|---|---|
| Dataset | LongMemEval-S (depurado), ~240K tokens de historial por pregunta |
| Juez | El juez GPT-4o canónico del benchmark - un tercero, no nosotros |
| Ejecuciones | 5 ejecuciones independientes, todos los puntajes publicados, se reporta la media (σ 0.5%) |
| Lector | Modelo lector y prompt fijos, publicados textualmente |
Lo que lo mantiene honesto: un juez de terceros, el prompt del lector publicado sin cambios, recuperación puramente semántica, y cada ejecución reportada - no solo la mejor. El motor de recuperación es determinista - ejecútalo de nuevo y obtienes las mismas memorias.
Escalamos benchmarks más difíciles
Probamos en el benchmark estándar más difícil que aún no hemos conquistado - y la cifra es la marca máxima entre todos los modelos de WOS, reescrita cada vez que sale uno mejor. Al superar el 94%, nos graduamos a un benchmark más difícil.
Dos tarifas de tokens por modelo,
más $0.0001 por solicitud.
Por millón de tokens más una tarifa fija de $0.0001 por solicitud, pago por uso. Sin suscripción, sin renta de almacenamiento, sin topes de memoria. Pagas cuando tu agente escribe o lee - nunca por lo que recuerda.
| Modelo | Entrada / 1M | Salida / 1M | |
|---|---|---|---|
| Tablet 1 | $2 | $3 | Disponible |
| Scroll 1 | $4 | $8 | Disponible |
| Codex 1 | - | - | Por definir |
- $0.0001 por solicitud. Una tarifa fija en cada llamada a la API, además del uso de tokens.
- El almacenamiento es gratis. La ingesta se paga una vez; conservarlo no te cuesta nada. Sin límite de cantidad, sin límite de retención.
- Nosotros lo almacenamos. Nunca entrenamos con él, lo usamos ni lo miramos. La memoria de tu agente es tuya - solo la organizamos para que puedas recuperarla.
- Por qué Tablet es tan barato: su motor no ejecuta ningún modelo, así que nuestro costo son embeddings y disco - no GPUs. Scroll y Codex añaden un modelo, y eso es lo que cubre su precio más alto.
Tres llamadas: store, recall, responder.
Una sola API. La llamada recall() devuelve el contexto de corto plazo, largo plazo y entorno en un solo viaje de ida y vuelta, listo para insertar en tu prompt.
Store
add() guarda los hechos y turnos de tu usuario. Embebido al entrar - sin LLM.
Recall
recall() devuelve corto plazo + largo plazo + contexto en una sola llamada - un contexto acotado y de tamaño fijo.
Responder
Entrega ese contexto acotado a tu LLM - cualquier proveedor, tu clave.
from wontopos import Client mem = Client(api_key="wos-...") mem.add("she prefers tea over coffee", user_id="alice") # one call: short + long + context ctx = mem.recall("what does alice drink?", user_id="alice")
Tu primer recall en 5 minutos.
Una clave, una línea de instalación, tres llamadas - tu agente ya tiene memoria. Cada fragmento de esta página se ejecutó de verdad; las respuestas se muestran textualmente.
Obtén una clave de API
Crea una en la consola. Una clave de 155 caracteres que empieza con wos-live- se muestra una sola vez. Guárdala en una variable de entorno - nunca en el código.
Instalar
pip install wontopos # Python npm install wontopos # TypeScript / JavaScript cargo add wontopos # Rust # curl - nothing to install, just set WOS_API_KEY
Crea un store, luego almacena & recupera
Un store es el user_id bajo el cual lees y escribes. Los stores son explícitos: crea uno primero (la llamada de abajo), luego almacena y recupera bajo él. Store - embebido al entrar, sin llamada a LLM. Recall - corto plazo + largo plazo + contexto en un solo viaje de ida y vuelta.
from wontopos import Client
mem = Client(api_key="wos-live-...", user_id="alice") # set the store once
mem.create_store() # create it (stores are explicit)
mem.add("she prefers tea over coffee") # no user_id needed
# one call → short-term + long-term + context
ctx = mem.recall("what does alice drink?"){"user_id": "alice", "status": "created"}{"id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "stored (1 chunks)"}user_id al cliente y todas las llamadas lo usarán - no hace falta repetirlo; anula una llamada puntual pasándole user_id. Los stores son explícitos: almacenar en o recuperar de un store que no existe devuelve 404 - créalo primero. Toda cuenta empieza con un store default, así que sin ningún user_id la ruta sin configuración simplemente funciona. Consulta Stores para listarlos y administrarlos.recall() devuelve cuatro bloques - short_term (turnos recientes), long_term (memorias relevantes), context (lo que rodeaba a la mejor coincidencia) y una instruction que le dice al LLM cómo usarlos. Inserta el conjunto completo en tu prompt.
Stores - crear, listar, eliminar.
Un store es el user_id bajo el cual lees y escribes - un espacio de memoria aislado por usuario final, agente o tema. Los stores son explícitos: crea uno antes de almacenar en él o recuperar de él, o la llamada devuelve 404. Toda cuenta empieza con un store default, así que puedes comenzar sin una llamada de creación.
mem.create_store("alice") # create (idempotent)
mem.list_stores() # [{"user_id","created_at"}, ...]
mem.delete_store("alice") # delete the store + all its memories{ "user_id": "alice", "status": "created" } // "exists" if it already did{ "collections": [
{ "user_id": "default", "created_at": "2026-06-26T02:23:14Z" },
{ "user_id": "alice", "created_at": "2026-06-26T02:24:01Z" }
], "count": 2 }{ "error": { "type": "not_found_error",
"message": "Store 'ghost' does not exist. Create it first with
POST /api/v1/memory/collection {\"user_id\":\"ghost\"}, then store or recall." } }"alice", "user_42") para mantener separada la memoria de cada persona, o un único store default para un agente personal. También puedes crear y explorar stores en la consola (Memory ids → Issue) sin escribir código. Eliminar un store es permanente - borra todas las memorias que contiene.Python - todos los métodos, tres grupos.
Escribir, leer, eliminar. Cada ejemplo de abajo se ejecutó contra la API en vivo el 2026-06-10; las respuestas son textuales.
pip install wontopos
from wontopos import Client mem = Client(api_key="wos-live-...") # or read from an env var
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 cliente; anula una llamada puntual pasando model=.
mem = Client(api_key="wos-live-...", model="tablet-1") # default engine mem.recall("...", user_id="alice") # tablet-1 mem.recall("...", user_id="alice", model="tablet-1") # or pick a model per call
list_models ✓ live-tested
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.
mem.list_models()[{"id": "tablet-1", "name": "Tablet 1", "available": true, "memory": "shared"}]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 ✓ live-tested
Almacena una memoria. Embebida al entrar - sin llamada a LLM, pagas solo embeddings.
mem.add("she prefers tea over coffee", user_id="alice")
{"id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "stored (1 chunks)"}add_turn ✓ live-tested
Almacena un turno de conversación (usuario + asistente) en la memoria de corto y largo plazo a la vez.
mem.add_turn("alice", "hi", "hello!")
{"status": "ok"}add_bulk ✓ live-tested
Rellena un bloque grande de texto. Se trocea y embebe del lado del servidor - ideal para importar historial existente.
mem.add_bulk("Alice moved to Brooklyn in March. She works at a design studio downtown.", user_id="alice")
{"elapsed_secs": 0.154154944, "status": "ok", "stored": 1, "total_chunks": 1}update ✓ live-tested
Un hecho cambió. La memoria antigua se marca como reemplazada (se conserva como historial); la nueva ocupa su lugar en el recall.
mem.update("alice", old_memory_id="576700aa-...", new_content="she switched to coffee this year")
{"new_memory_id": "07e94433-b7cc-4e49-8d8f-f37fc1a392b7",
"old_memory_id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "superseded"}Leer
search ✓ live-tested
Búsqueda semántica, lo más relevante primero. Embedding puro - sin coincidencia de palabras clave, así que cualquier idioma encuentra cualquier memoria. El SDK devuelve directamente el arreglo de memorias; el cuerpo HTTP sin procesar se muestra abajo.
r = mem.search("what does she drink?", user_id="alice", limit=1)
{"memories": [{
"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-06-10T04:20:39.688276876Z"
}], "search_ms": 315, "total_found": 1}| Campo | Significado |
|---|---|
| similarity | Similitud de embedding bruta con 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 ✓ live-tested
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.
ctx = mem.recall("what does she drink?", user_id="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 ✓ live-tested
Turnos de conversación recientes (memoria de corto plazo), los más antiguos primero.
turns = mem.history("alice")
{"count": 2, "turns": [
{"role": "user", "content": "hi", "timestamp": "2026-06-10T04:20:40.989011337Z"},
{"role": "assistant", "content": "hello!", "timestamp": "2026-06-10T04:20:40.989013416Z"}
], "user_id": "alice"}stats ✓ live-tested
Conteos de memoria de un usuario.
mem.stats("alice")
{"short_term_turns": 2, "total_memories": 4, "user_id": "alice"}Eliminar
delete ✓ live-tested
Elimina una sola memoria por id.
mem.delete("alice", memory_id="576700aa-...")
{"memory_id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "deleted"}delete_all ✓ live-tested
Borra todo lo de un usuario - una llamada, lista para GDPR.
mem.delete_all("alice")
{"memories_deleted": 4, "status": "deleted", "user_id": "alice"}TypeScript - todos los métodos, tres grupos.
Escribir, leer, eliminar. Cada ejemplo de abajo se ejecutó contra la API en vivo el 2026-06-10; 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("tablet-1").recall("...", "alice"); // or pick a model per call
listModels ✓ live-tested
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"}]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 ✓ live-tested
Almacena una memoria. Embebida al entrar - sin llamada a LLM, pagas solo embeddings.
await mem.add("she prefers tea over coffee", "alice");
{"id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "stored (1 chunks)"}addTurn ✓ live-tested
Almacena un turno de conversación (usuario + asistente) en la memoria de corto y largo plazo a la vez.
await mem.addTurn("alice", "hi", "hello!");
{"status": "ok"}addBulk ✓ live-tested
Rellena un bloque grande de texto. Se trocea y embebe del lado del 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 ✓ live-tested
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("alice", "576700aa-...", "she switched to coffee this year");
{"new_memory_id": "07e94433-b7cc-4e49-8d8f-f37fc1a392b7",
"old_memory_id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "superseded"}Leer
search ✓ live-tested
Búsqueda semántica, lo más relevante primero. Embedding puro - sin coincidencia de palabras clave, así que cualquier idioma encuentra cualquier memoria. El SDK devuelve directamente el arreglo de memorias; el cuerpo HTTP sin procesar se muestra abajo.
const r = await mem.search("what does she drink?", "alice", 1);
{"memories": [{
"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-06-10T04:20:39.688276876Z"
}], "search_ms": 315, "total_found": 1}| Campo | Significado |
|---|---|
| similarity | Similitud de embedding bruta con 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 ✓ live-tested
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 ✓ live-tested
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-06-10T04:20:40.989011337Z"},
{"role": "assistant", "content": "hello!", "timestamp": "2026-06-10T04:20:40.989013416Z"}
], "user_id": "alice"}stats ✓ live-tested
Conteos de memoria de un usuario.
await mem.stats("alice");
{"short_term_turns": 2, "total_memories": 4, "user_id": "alice"}Eliminar
delete ✓ live-tested
Elimina una sola memoria por id.
await mem.delete("alice", "576700aa-...");
{"memory_id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "deleted"}deleteAll ✓ live-tested
Borra todo lo de un usuario - una llamada, lista para GDPR.
await mem.deleteAll("alice");
{"memories_deleted": 4, "status": "deleted", "user_id": "alice"}Rust - todos los métodos, tres grupos.
Escribir, leer, eliminar. Cada ejemplo de abajo se ejecutó contra la API en vivo el 2026-06-10; las respuestas son textuales.
cargo add wontopos
use wontopos::Client; let mem = Client::new("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 con with_model(); encadénalo de nuevo para anular una llamada puntual.
let mem = Client::new("wos-live-...").with_model("tablet-1"); // default mem.recall("...", "alice").await?; // tablet-1 mem.with_model("tablet-1").recall("...", "alice").await?; // or pick a model per call
list_models ✓ live-tested
El catálogo - los ids que puedes pasar a with_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.
mem.list_models().await?;
[{"id": "tablet-1", "name": "Tablet 1", "available": true, "memory": "shared"}]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 ✓ live-tested
Almacena una memoria. Embebida al entrar - sin llamada a LLM, pagas solo embeddings.
mem.add("she prefers tea over coffee", "alice", json!({})).await?;
{"id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "stored (1 chunks)"}add_turn ✓ live-tested
Almacena un turno de conversación (usuario + asistente) en la memoria de corto y largo plazo a la vez.
mem.add_turn("alice", "hi", "hello!").await?;
{"status": "ok"}add_bulk ✓ live-tested
Rellena un bloque grande de texto. Se trocea y embebe del lado del servidor - ideal para importar historial existente.
mem.add_bulk("Alice moved to Brooklyn in March...", "alice", "general").await?;
{"elapsed_secs": 0.154154944, "status": "ok", "stored": 1, "total_chunks": 1}update ✓ live-tested
Un hecho cambió. La memoria antigua se marca como reemplazada (se conserva como historial); la nueva ocupa su lugar en el recall.
mem.update("alice", "576700aa-...", "she switched to coffee this year").await?;
{"new_memory_id": "07e94433-b7cc-4e49-8d8f-f37fc1a392b7",
"old_memory_id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "superseded"}Leer
search ✓ live-tested
Búsqueda semántica, lo más relevante primero. Embedding puro - sin coincidencia de palabras clave, así que cualquier idioma encuentra cualquier memoria. El SDK devuelve directamente el arreglo de memorias; el cuerpo HTTP sin procesar se muestra abajo.
let r = mem.search("what does she drink?", "alice", 1).await?;
{"memories": [{
"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-06-10T04:20:39.688276876Z"
}], "search_ms": 315, "total_found": 1}| Campo | Significado |
|---|---|
| similarity | Similitud de embedding bruta con 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 ✓ live-tested
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.
let ctx = mem.recall("what does she drink?", "alice").await?;
{"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 ✓ live-tested
Turnos de conversación recientes (memoria de corto plazo), los más antiguos primero.
let turns = mem.history("alice").await?;
{"count": 2, "turns": [
{"role": "user", "content": "hi", "timestamp": "2026-06-10T04:20:40.989011337Z"},
{"role": "assistant", "content": "hello!", "timestamp": "2026-06-10T04:20:40.989013416Z"}
], "user_id": "alice"}stats ✓ live-tested
Conteos de memoria de un usuario.
mem.stats("alice").await?;
{"short_term_turns": 2, "total_memories": 4, "user_id": "alice"}Eliminar
delete ✓ live-tested
Elimina una sola memoria por id.
mem.delete("alice", "576700aa-...").await?;
{"memory_id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "deleted"}delete_all ✓ live-tested
Borra todo lo de un usuario - una llamada, lista para GDPR.
mem.delete_all("alice").await?;
{"memories_deleted": 4, "status": "deleted", "user_id": "alice"}curl - sin instalación, los mismos métodos.
No hay SDK que instalar - cualquier cliente HTTP funciona. Configura tu clave una vez y llama a los mismos endpoints que envuelven los SDK. URL base https://api.wontopos.com, autenticación vía X-API-Key, JSON de entrada y salida.
# set your key once (never hard-code it) export WOS_API_KEY="wos-live-..."
Escribir
store ✓ live-tested
Almacena una memoria. Embebida al entrar - sin llamada a LLM.
curl -X POST https://api.wontopos.com/api/v1/memory/store \ -H "X-API-Key: $WOS_API_KEY" -H "Content-Type: application/json" \ -d '{"user_id":"alice","content":"she prefers tea over coffee"}'
{"id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "stored (1 chunks)"}store-turn ✓ live-tested
Almacena un turno de conversación (usuario + asistente) en la memoria de corto y largo plazo a la vez.
curl -X POST https://api.wontopos.com/api/v1/memory/store-turn \ -H "X-API-Key: $WOS_API_KEY" -H "Content-Type: application/json" \ -d '{"user_id":"alice","user_msg":"hi","assistant_msg":"hello!"}'
{"status": "ok"}supersede ✓ live-tested
Un hecho cambió - la memoria antigua se marca como reemplazada, la nueva ocupa su lugar en el recall.
curl -X POST https://api.wontopos.com/api/v1/memory/supersede \ -H "X-API-Key: $WOS_API_KEY" -H "Content-Type: application/json" \ -d '{"user_id":"alice","old_memory_id":"576700aa-...","new_content":"she switched to coffee this year"}'
{"new_memory_id": "07e94433-...", "old_memory_id": "576700aa-...", "status": "superseded"}Leer
search ✓ live-tested
Búsqueda semántica, lo más relevante primero. Embedding puro - cualquier idioma encuentra cualquier memoria.
curl -X POST https://api.wontopos.com/api/v1/memory/search \ -H "X-API-Key: $WOS_API_KEY" -H "Content-Type: application/json" \ -d '{"user_id":"alice","query":"what does she drink?","max_results":1}'
{"memories": [{"id": "576700aa-...", "content": "she prefers tea over coffee",
"similarity": 0.63, "is_superseded": false}], "search_ms": 315, "total_found": 1}recall ✓ live-tested
Un solo viaje de ida y vuelta devuelve corto plazo + largo plazo + contexto + una instrucción. Pégalo directamente en tu prompt.
curl -X POST https://api.wontopos.com/api/v1/memory/recall \ -H "X-API-Key: $WOS_API_KEY" -H "Content-Type: application/json" \ -d '{"user_id":"alice","query":"what does she drink?"}'
{"short_term": {"count": 2, "turns": [...]},
"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"]},
"instruction": "Use short_term for recent context, long_term for relevant past memories..."}Eliminar
forget ✓ live-tested
Elimina una memoria por id, u omítelo para eliminar todo lo de un usuario (GDPR).
curl -X POST https://api.wontopos.com/api/v1/memory/forget \ -H "X-API-Key: $WOS_API_KEY" -H "Content-Type: application/json" \ -d '{"user_id":"alice"}' # omit memory_id = delete all
{"memories_deleted": 1, "status": "deleted", "user_id": "alice"}Engrams
Herramientas de recall invocables que tu modelo puede llamar - cada una es una estrategia de recuperación distinta sobre la misma memoria. Usa una, o ejecuta varias a la vez.
Regularmente se lanzan más engramas - esta lista crece.
Memoir & Archive Próximamente
Este es un modo de modelo, no una herramienta invocable. Elígelo en el modelo y cada recall, incluida una búsqueda simple, vuelve con el tiempo escrito de esa manera. Próximamente.
Time_awareness Próximamente
Un modo de modelo, no una opción por llamada. Elige el modelo - Time_awareness-memoir o Time_awareness-archive - y cada recall vuelve renderizado de esa manera: una búsqueda simple, un recall o cualquier engrama, sin parámetro extra. Un Memoir se lee como recuerda una persona; un Archive conserva un registro exacto - la diferencia se nota sobre todo en cómo escribe el tiempo cada uno. El prefijo Time_awareness- deja espacio para más capacidades en el futuro.
Memoir
Time_awareness-memoirCuenta lo que pasó y cómo un momento llevó al siguiente, con esa noción suave del tiempo que recuerda una persona - se lee como experiencia, no como una lista.
Archive
Time_awareness-archiveDevuelve las coincidencias como registros exactos - tiempo transcurrido preciso y anclas absolutas, estructurado para que un modelo lo lea de inmediato.
store / add bajo un user_id (ese user_id es el store de esa persona). Almacena primero; después cualquier recall - incluida la búsqueda simple de abajo - vuelve etiquetado con el tiempo. Consulta el Inicio rápido para almacenar.# plain search - no engram - on a memoir model
r = mem.search("what does Alice drink?", user_id="alice", model="Time_awareness-memoir", tz=9)
# every hit gets a .time field → "a couple weeks ago" (archive model → "2 weeks ago (Jun 09)")tz es el desplazamiento UTC del llamador en horas - para que "esta mañana" y el límite de día de las 4am caigan en su hora local. Omítelo para UTC; por HTTP es el encabezado X-WOS-Timezone. A grandes rasgos, por región: EE. UU. Este -5, EE. UU. Centro -6, EE. UU. Oeste -8 · Reino Unido / Lisboa 0 · Europa Central +1 · Europa Oriental +2 · India +5.5 · China / Singapur +8 · Corea / Japón +9 · Sídney +10. (Hora estándar - el horario de verano desplaza algunas regiones en +1; pasa el que tus usuarios realmente usen.)
La misma búsqueda, dos modelos - las memorias son idénticas, solo cambia time:
{ "count": 3, "memories": [
{ "content": "Alice prefers tea over coffee", "time": "a couple weeks ago" },
{ "content": "met Alice at the cafe downtown", "time": "yesterday afternoon" },
{ "content": "Alice moved to Brooklyn", "time": "about half a year ago" }
] }{ "count": 3, "memories": [
{ "content": "Alice prefers tea over coffee", "time": "2 weeks ago (Jun 09)" },
{ "content": "met Alice at the cafe downtown", "time": "yesterday at 14:00" },
{ "content": "Alice moved to Brooklyn", "time": "6 months ago (Dec 2025)" }
] }| Transcurrido | Memoir | Archive |
|---|---|---|
| 3 min | a few minutes ago | 3 minutes ago |
| 14 min | about 15 minutes ago | 14 minutes ago |
| 30 min | half an hour ago | 30 minutes ago |
| 50 min | about an hour ago | 50 minutes ago |
| 2 h | a couple hours ago | 2 hours ago, at 13:10 |
| 8 h | this morning | 8 hours ago, at 07:10 |
| ayer p. m. | yesterday afternoon | yesterday at 14:00 |
| anoche | last night | 17 hours ago, at 22:00 |
| 2 días | a couple days ago | 2 days ago (Tue 15:10) |
| 6 días | several days ago | 6 days ago (Fri 15:10) |
| 9 días | about a week ago | last week (Jun 16) |
| 16 días | a couple weeks ago | 2 weeks ago (Jun 09) |
| 35 días | about a month ago | last month (May 21) |
| 60 días | a couple months ago | 2 months ago (Apr 2026) |
| 180 días | about half a year ago | 6 months ago (Dec 2025) |
| 380 días | about a year ago | last year (Jun 2025) |
| 800 días | a couple years ago | 2 years ago (Apr 2024) |
| 1500 días | about 4 years ago | 4 years ago (May 2022) |
Cada valor de arriba es la salida real del renderizador. Mira las dos filas de "ayer": un Memoir separa la tarde de la noche anterior - un día es un sueño - mientras que un Archive escribe una sola hora de reloj y no traza ninguna línea entre día y noche.
Cómo lee el tiempo cada modo
Memoir - como la gente realmente lo dice. Los momentos recientes se mantienen bastante nítidos (unos 15 minutos, media hora), y luego la redacción se ensancha cuanto más atrás vas - un par de semanas, cerca de medio año, un par de años - igual que la memoria misma se afloja con la distancia. Dentro de un día deja el reloj por un punto de referencia: esta mañana, anoche, ayer por la tarde. Y un día es un sueño, no un tic del calendario: el límite se sitúa alrededor de las 4am hora local, así que una noche larga todavía se lee como la misma velada, no como si ya fuera mañana.
Archive - preciso, siempre con un ancla. Cada línea lleva el tiempo transcurrido exacto más una referencia absoluta desde la que un modelo puede calcular, y el ancla se afina cuanto más cerca está: una hora de reloj para hoy (hace 8 horas, a las 07:10), un día de la semana y hora esta semana (hace 2 días (mar 15:10)), una fecha este mes (la semana pasada (16 jun)), y mes y año más allá (hace 6 meses (dic 2025)). Nunca vago, nunca equivocado.
deep_recall
Recall multisalto. Busca tu consulta, luego toma la mejor coincidencia y vuelve a buscar sobre su contenido - trayendo contexto enlazado que una sola búsqueda pasaría por alto. Ideal cuando las memorias se referencian entre sí (una persona → sus proyectos → los detalles). Devuelve hasta ~12.
out = mem.engram("deep_recall", "what should I know about Alice?", user_id="alice"){ "engram": "deep_recall", "hops": 2, "count": 12,
"memories": [ ... ],
"usage": { "input_tokens": 5, "output_tokens": 61 } }usage (entrada + salida), contado con el mismo tokenizador que el resto de la API; sin tarifas ocultas por engrama. ¿Necesitas varios a la vez? Llámalos de forma concurrente - cada engrama es una solicitud independiente.timeline
Recall ordenado por tiempo. Devuelve las memorias ordenadas de más reciente a más antigua según cuándo ocurrió el evento, no por relevancia. Para preguntas de "cuándo pasó X", historial y secuencia. Devuelve hasta 15.
events = mem.engram("timeline", "project milestones", user_id="alice"){ "engram": "timeline", "hops": 1, "count": 15,
"memories": [ ... ],
"usage": { "input_tokens": 4, "output_tokens": 88 } }usage (entrada + salida), contado con el mismo tokenizador que el resto de la API; sin tarifas ocultas por engrama. ¿Necesitas varios a la vez? Llámalos de forma concurrente - cada engrama es una solicitud independiente.gather
Recolección amplia. Busca y luego se expande alrededor de las tres mejores coincidencias - una red más amplia que deep_recall. Úsala para traer todo lo relacionado con una persona, proyecto o tema en una sola llamada. Devuelve hasta ~18.
related = mem.engram("gather", "everything about Project Atlas", user_id="alice"){ "engram": "gather", "hops": 4, "count": 18,
"memories": [ ... ],
"usage": { "input_tokens": 6, "output_tokens": 142 } }usage (entrada + salida), contado con el mismo tokenizador que el resto de la API; sin tarifas ocultas por engrama. ¿Necesitas varios a la vez? Llámalos de forma concurrente - cada engrama es una solicitud independiente.Todos los endpoints, una URL base.
No se requiere SDK - cualquier cliente HTTP funciona. URL base https://api.wontopos.com, autenticación vía el encabezado X-API-Key, JSON de entrada y salida. Las operaciones de memoria son POST; la administración de stores usa POST / GET / DELETE sobre /collection. El store debe existir primero (ver Stores) o las operaciones dentro del store devuelven 404.
| Endpoint | Propósito | Campos del cuerpo |
|---|---|---|
| POST /api/v1/memory/collection | crear un store | user_id |
| GET /api/v1/memory/collections | listar tus stores | (ninguno) |
| DELETE /api/v1/memory/collection | eliminar un store + sus memorias | user_id |
| /api/v1/memory/store | almacenar una memoria | user_id · content · metadata? |
| /api/v1/memory/store-turn | almacenar un turno de conversación | user_id · user_msg · assistant_msg |
| /api/v1/memory/bulk-store | rellenar un bloque de texto | user_id · content · category? |
| /api/v1/memory/search | búsqueda semántica | user_id · query · max_results? |
| /api/v1/memory/recall | corto + largo + contexto | user_id · query |
| /api/v1/memory/history | turnos recientes | user_id |
| /api/v1/memory/stats | conteos de memoria | user_id |
| /api/v1/memory/supersede | reemplazar un hecho que cambió | user_id · old_memory_id · new_content |
| /api/v1/memory/forget | eliminar una (o todas) | user_id · memory_id? (omitir = eliminar todo) |
# create the store once (stores are explicit) curl -X POST https://api.wontopos.com/api/v1/memory/collection \ -H "X-API-Key: $WOS_API_KEY" -H "Content-Type: application/json" \ -d '{"user_id":"alice"}' # store a memory curl -X POST https://api.wontopos.com/api/v1/memory/store \ -H "X-API-Key: $WOS_API_KEY" -H "Content-Type: application/json" \ -d '{"user_id":"alice","content":"she prefers tea over coffee"}' # recall - one call, ready for your prompt curl -X POST https://api.wontopos.com/api/v1/memory/recall \ -H "X-API-Key: $WOS_API_KEY" -H "Content-Type: application/json" \ -d '{"user_id":"alice","query":"what does alice drink?"}'
{"id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "stored (1 chunks)"}Las mismas funciones para todos.
Los niveles solo elevan tus límites.
Todos los niveles ejecutan el motor completo - la misma calidad de recall, los mismos idiomas, todos los métodos. Los niveles avanzan automáticamente hasta el Nivel 5 a medida que crecen tus compras acumuladas de crédito, sin solicitudes ni llamadas de ventas. Enterprise (Nivel 6) es la única excepción.
Límites de gasto
Cada nivel limita cuánto puedes gastar por mes calendario. Avanzas de inmediato cuando tus compras acumuladas de crédito alcanzan el siguiente umbral.
| Nivel de uso | Compra de crédito | Límite de gasto mensual |
|---|---|---|
| Tier 1 | $5 | $100 |
| Tier 2 | $40 | $500 |
| Tier 3 | $200 | $1,000 |
| Tier 4 | $400 | $5,000 |
| Tier 5 | $1,000 | $25,000 |
| Tier 6 - Enterprise | Habla con nosotros | Sin límite |
Límites de velocidad
Los límites de velocidad son por cuenta - todas las claves de API de una cuenta comparten un mismo límite, que escala con tu nivel. Excederlo devuelve un 429 con un encabezado retry-after; espera (1s → 2s → 4s) y reintenta. Todos los endpoints son compatibles con la idempotencia, así que reintentar es seguro.
| Nivel | Solicitudes por minuto |
|---|---|
| Tier 1 | 150 |
| Tier 2 | 300 |
| Tier 3 | 600 |
| Tier 4 | 1,500 |
| Tier 5 | 3,000 |
| Tier 6 - Enterprise | Personalizado |
Enterprise (Nivel 6) obtiene límites de velocidad personalizados, un SLA, soporte dedicado y una licencia opcional de autoalojamiento - habla con nosotros.
Cuando algo sale mal.
Los errores vuelven como un sobre JSON con un type estable, un mensaje legible y un request_id que puedes enviarnos al reportar un problema.
{"type": "error", "error": {
"type": "authentication_error",
"message": "Invalid or revoked API key.",
"request_id": "063f8b83-eee2-4383-a5cf-11e4bcd29d7c"
}}| HTTP | Significado | Qué hacer |
|---|---|---|
| 401 | Clave de API inválida o revocada | Verifica la clave; emite una nueva en la consola. |
| 422 | Cuerpo mal formado (campo faltante o de tipo incorrecto) | El mensaje indica el campo exacto - corrige y reintenta. |
| 429 | Límite de velocidad excedido | Espera de forma exponencial (1s → 2s → 4s) y reintenta. Es seguro: todos los endpoints son compatibles con la idempotencia. |
| 5xx | Problema del lado del servidor | Reintenta con espera exponencial; incluye el request_id si nos contactas. |
# SDK error handling (Python) from wontopos import Client, WosError try: mem.search("...", user_id="alice") except WosError as e: if e.status == 401: ... # bad key elif e.status == 429: ... # back off and retry
Los límites de velocidad son por cuenta, se comparten entre todas tus claves y escalan con tu nivel - consulta Niveles de uso. El uso de tu cuenta se muestra en la consola.
Tus servidores, tus datos.
El motor puede ejecutarse dentro de tu propia infraestructura - la misma API, los mismos SDK. Apunta el cliente a tu host y nada más cambia.
mem = Client(api_key="...", base_url="https://wos.your-host.com")- Residencia de datos. Las memorias nunca salen de tu red.
- La misma superficie. Los mismos métodos y endpoints funcionan de forma idéntica.
- Licenciamiento. Los paquetes de autoalojamiento se acuerdan por despliegue - contáctanos.
Más allá de la ventana de contexto.
WOS recupera de historiales de 1.4M tokens - mucho más grandes que cualquier ventana de contexto de un LLM - y aun así entrega un fragmento compacto de ~1,470 tokens.
La memoria de tu agente no está limitada por lo que cabe en un prompt. Lo conserva todo y recupera solo lo que importa, sin importar cuánto crezca el historial.
Privado, y tuyo.
Tus datos permanecen en tu store. Nunca entrenamos con ellos, los vemos ni los reutilizamos - solo los organizamos para que puedas recuperarlos.
- BYOK. Tu clave de LLM se envía por solicitud y nunca se almacena.
- Aislado. Las memorias tienen alcance por cuenta y luego por
user_id. - Borrado GDPR & autoalojamiento. Una llamada borra a un usuario; ejecuta el motor en tu propio entorno si lo prefieres.