SDK de Python

Python - 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.

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="scroll-1")  # or pick a model per call

list_models

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()
Respuesta real
[{"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.

mem.ping()   # True, or raises 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.

mem.add("she prefers tea over coffee", user_id="alice")
mem.add("I promised the summary by Friday", user_id="alice", speaker="me")  # its own words - no registration needed
Respuesta real
{"id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "stored (1 chunks)"}

add_turn

Almacena un turno de conversación (usuario + asistente) en la memoria de corto y largo plazo a la vez.

mem.add_turn("hi", "hello!", user_id="alice")
Respuesta real
{"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.

mem.add_speaker("Bob", user_id="alice")  # once per person; "me" needs no registration
mem.add("I promised to send the report on Friday", user_id="alice", speaker="me")
mem.add("Bob said the deadline moved to Tuesday", user_id="alice", speaker="Bob")
mem.search("what did Bob say about deadlines?", user_id="alice", speaker="Bob")
response
[{"content": "Bob said the deadline moved to Tuesday", "speaker": "Bob", ...}]
Los hablantes son explícitos, como los almacenes. Registra primero a la persona y luego guarda bajo su nombre: una errata nunca se convierte en silencio en una persona nueva. Un almacén registra hasta 50 personas para empezar (pensamos subirlo), y "me" nunca necesita registro ni cuenta.

add_bulk

Carga un bloque grande de texto. Se divide e indexa en el 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")
Respuesta real
{"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.

mem.update("576700aa-...", "she switched to coffee this year", user_id="alice")
Respuesta real
{"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.

r = mem.search("what does she drink?", user_id="alice", limit=1)
Respuesta real (cuerpo HTTP)
[{
   "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"
 }]
CampoSignificado
similarityQué tan cerca está esta memoria de tu consulta (0–1).
is_supersededTrue si este hecho fue reemplazado por update().
search_msTiempo 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.

ctx = mem.recall("what does she drink?", user_id="alice")
Respuesta real (forma - listas acortadas)
{"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.

turns = mem.history("alice")
Respuesta real (cuerpo HTTP)
{"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.

mem.stats("alice")
Respuesta real
{"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.

m = mem.get("alice", memory_id="576700aa-...")
response
{"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}
Respuesta real
{"memory": {"id": "8bd090de-...", "content": "the office moved to the seventh floor in June",
  "category": "general", "created_at": "2026-07-31T18:20:30.531518060+00:00", "event_date": null,
  "is_superseded": false, "superseded_by": null}, "user_id": "docs_livetest"}

list_memories

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.

page = mem.list_memories("alice", limit=100)
response
{"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}
 ]}

iter_memories · export_memories

Recorre todas las memorias sin gestionar el cursor, o trae el almacén entero de una vez.

for m in mem.iter_memories("alice"):   # every page, no cursor bookkeeping
    print(m["id"], m["content"])
everything = mem.export_memories("alice")   # the whole store as a list

Eliminar

delete

Elimina una sola memoria por id.

mem.delete("alice", memory_id="576700aa-...")
Respuesta real
{"memory_id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "deleted"}

delete_all

Borra todo lo de un usuario - una llamada, lista para GDPR.

mem.delete_all("alice")
Respuesta real
{"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.

from wontopos import PaymentRequiredError, NotFoundError
try:
    mem.add("...", user_id="alice")
except NotFoundError:
    mem.create_store("alice")   # store didn't exist yet
except PaymentRequiredError:
    top_up()                       # out of credit - don't retry

rate_limit

Lee la cuota restante tras cualquier llamada y reduce el ritmo antes de llegar al límite.

mem.search("...", user_id="alice")
rl = mem.rate_limit   # {"limit": 150, "remaining": 3, "reset": ...}

search_self

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ó.

r = mem.search_self("what did I promise?", user_id="alice")
r["memories"]       # what others said / general memories
r["self_memories"]  # the agent's OWN words (speaker "me")

list_engrams

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.

cat = mem.list_engrams()
[e["name"] for e in cat["engrams"]]   # 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.

mem.search("what did we decide", user_id="alice", filters={
    "categories": ["work"],
    "event_from": "2026-01-01",   # when it HAPPENED
})
Claves: categories · event_from / event_to (cuándo OCURRIÓ el contenido - metadata.event_date) · time_from / time_to (cuándo se escribió) · min_importance. Las claves no listadas se descartan, no se rechazan, así que una errata amplía la búsqueda en silencio.

idempotency_key

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.

mem.add("she prefers tea", "alice", idempotency_key=f"import:{row.id}")
Deriva la clave de aquello que se almacena (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._:-].

with_timeout / with_retries / with_deadline

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.

mem.with_timeout(120).add_bulk(big_blob, "alice")  # this slow call only
mem.with_retries(0).add("...", "alice")              # you retry, not the SDK
mem.with_deadline(5).recall("...", "alice")             # 5s for the whole call