SDK Python

Python - todos os métodos, três grupos.

Escrever, ler, excluir. Todos os exemplos abaixo foram executados contra a API em produção em 2026-08-01; as respostas estão na íntegra.

pip install wontopos
from wontopos import Client

mem = Client(api_key="wos-live-...")  # or read from an env var

Escolha um modelo

A chave de API escolhe qual memória (sua conta); o modelo escolhe qual motor a lê. Todos os modelos compartilham uma mesma memória, então você pode armazenar com um e recuperar com outro. Defina um padrão no cliente; sobrescreva uma chamada específica passando 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

O catálogo - os ids que você pode passar em model e se cada um está disponível. Modelos com memory: "shared" leem o mesmo store; "isolated" mantém o seu próprio. Não requer chave de API.

mem.list_models()
Resposta 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

Confirme a conexão e que sua chave de API funciona: uma verificação de uma linha.

mem.ping()   # True, or raises AuthenticationError / PaymentRequiredError

O catálogo acima sempre reflete os modelos disponíveis neste momento - passe qualquer outro id e você recebe um erro claro. Novos modelos aparecem nele automaticamente quando são lançados.

Escrever

add

Armazena uma memória. Sem chamada de LLM na entrada: você paga apenas a tarifa de escrita.

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
Resposta real
{"id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "stored (1 chunks)"}

add_turn

Armazena um turno de conversa (usuário + assistente) na memória de curto e de longo prazo de uma só vez.

mem.add_turn("hi", "hello!", user_id="alice")
Resposta real
{"status": "ok"}

speaker

Cada memória pode carregar quem a disse. Registre uma pessoa uma vez e depois passe o nome como speaker; "me" (as palavras do próprio assistente) nunca precisa de registro. A busca também aceita speaker, para lembrar só as palavras de uma pessoa.

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", ...}]
Falantes são explícitos, como armazenamentos. Registre a pessoa primeiro e depois salve sob o nome dela: um erro de digitação nunca vira silenciosamente uma pessoa nova. Um armazenamento registra até 50 pessoas para começar (planejamos aumentar), e "me" nunca precisa de registro nem conta.

add_bulk

Faça backfill de um bloco grande de texto. Dividido e indexado no servidor, ideal para importar histórico existente.

mem.add_bulk("Alice moved to Brooklyn in March. She works at a design studio downtown.", user_id="alice")
Resposta real
{"elapsed_secs": 0.154154944, "status": "ok", "stored": 1, "total_chunks": 1}

update

Um fato mudou. A memória antiga é marcada como substituída (mantida para histórico); a nova toma o lugar dela no recall.

mem.update("576700aa-...", "she switched to coffee this year", user_id="alice")
Resposta real
{"new_memory_id": "07e94433-b7cc-4e49-8d8f-f37fc1a392b7",
 "old_memory_id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "superseded"}

Ler

search

Busca semântica, os mais relevantes primeiro. Qualquer idioma encontra qualquer memória, seja qual for o idioma em que foi escrita. O SDK retorna o array memories diretamente; o corpo HTTP bruto aparece abaixo. Alguns modelos respondem com mais de um conjunto de resultados e o SDK os devolve mesclados, então o array pode conter MAIS do que max_results. Dimensione sua janela de prompt pelo que você recebe, não pelo número que pediu.

r = mem.search("what does she drink?", user_id="alice", limit=1)
Resposta real (corpo 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ão próxima esta memória está da sua consulta (0–1).
is_supersededVerdadeiro se este fato foi substituído por update().
search_msTempo de recuperação no servidor.

recall

Uma única ida e volta retorna tudo o que o seu LLM precisa - cole o resultado direto no seu prompt: um contexto limitado e de tamanho fixo, não importa quanto você tenha armazenado.

ctx = mem.recall("what does she drink?", user_id="alice")
Resposta real (formato - listas encurtadas)
{"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 recentes da conversa (memória de curto prazo), do mais antigo para o mais recente.

turns = mem.history("alice")
Resposta real (corpo 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

Contagens de memórias de um usuário.

mem.stats("alice")
Resposta real
{"short_term_turns": 2, "total_memories": 4, "user_id": "alice"}

get

Busca uma memória pelo id - o id que add ou list_memories retornou. Apenas o texto original armazenado e seus metadados. Um id de outro store, ou uma memória apagada ou invalidada, retorna 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}
Resposta 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 as memórias de um armazenamento - apenas o texto original que você guardou e seus metadados. Paginado por cursor: reenvie o next_cursor retornado para a próxima página.

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

Percorra todas as memórias sem gerenciar o cursor, ou traga o armazenamento inteiro de uma 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

Excluir

delete

Exclui uma única memória pelo id.

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

delete_all

Apaga tudo de um usuário - uma única chamada, pronta para o GDPR.

mem.delete_all("alice")
Resposta real
{"memories_deleted": 4, "status": "deleted", "user_id": "alice"}

Erros e confiabilidade

Cada falha é um erro tipado - capture o específico (limite de taxa, autenticação, pagamento) ou todos com o 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

Leia a cota restante após qualquer chamada e desacelere antes de bater no limite.

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

search_self

As duas trilhas em uma única chamada num modelo de memória própria (Scroll 1.2+): o que os outros disseram e as palavras do PRÓPRIO agente - separadas, para que quem lê nunca confunda quem falou.

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

Pergunte ao serviço quais engramas e formas de entrega o modelo selecionado consegue executar, em vez de fixar nomes que ficam desatualizados assim que um novo é lançado.

cat = mem.list_engrams()
[e["name"] for e in cat["engrams"]]   # ask, never hard-code

filters

Restringe a busca a parte do repositório. Aplicado antes da ordenação, então você recebe as melhores correspondências dentro do filtro - não um top-N filtrado depois.

mem.search("what did we decide", user_id="alice", filters={
    "categories": ["work"],
    "event_from": "2026-01-01",   # when it HAPPENED
})
Chaves: categories · event_from / event_to (quando o conteúdo ACONTECEU - metadata.event_date) · time_from / time_to (quando foi escrito) · min_importance. Chaves não listadas são descartadas, não rejeitadas, então um erro de digitação amplia a busca em silêncio.

idempotency_key

Torna seguro repetir uma escrita. Use quando a repetição é sua - um job que caiu e foi reexecutado, uma fila que reentrega.

mem.add("she prefers tea", "alice", idempotency_key=f"import:{row.id}")
Derive a chave do que está sendo armazenado (import:row-42), nunca uma constante: uma chave reutilizada em duas escritas diferentes repete a primeira e a segunda se perde em silêncio. Formato: 1-128 caracteres de [A-Za-z0-9._:-].

with_timeout / with_retries / with_deadline

Ajuste um único ponto de chamada sem mexer no cliente já construído: um clone com timeout maior para um backfill grande, ou sem retentativas dentro do seu próprio laço de retry.

timeout limita uma tentativa, então uma chamada que repete pode durar mais que ele: nos valores padrão uma única chamada pode segurar uma conexão por 30 s, recuar, tentar de novo e de novo. deadline limita a chamada inteira: cada tentativa é cortada no que sobrou, e nenhuma espera dorme além do orçamento. Defina quando quem chama tem um limite real, como um handler de requisição com 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