Por que o WOS

Memória de longo prazo para agentes de IA.

O WOS é uma API de memória. Você armazena as memórias de um usuário uma única vez e depois recupera apenas as relevantes para cada consulta, passando-as ao prompt do seu modelo.

A recuperação é puramente semântica, sem correspondência por palavras-chave nem BM25, então a qualidade do recall é idêntica em todos os idiomas. Cada consulta retorna um contexto pequeno e limitado, não importa quanto você tenha armazenado, e nenhum modelo é executado sobre as suas memórias armazenadas.

Operações principais

  • store - salva uma memória para um usuário.
  • recall - obtém as memórias relevantes para uma consulta. Esta é a chamada principal.
  • search - busca semântica bruta sobre as memórias armazenadas.
  • supersede - atualiza ou substitui uma memória desatualizada.
  • forget - exclui uma única memória ou um usuário inteiro (GDPR).
Escolha uma seção à esquerda para ver os detalhes de cada tópico.
Modelo

Três modelos, uma mesma linhagem.

Os modelos WOS recebem nomes das formas como as pessoas preservaram o conhecimento ao longo da história - Tablet, Scroll, Codex. Pedra, pergaminho, livro encadernado: cada um faz mais pelo seu agente do que o anterior.

Tablet

Disponível
Gravado em pedra · store & recall

Uma forma enxuta, rápida e de baixo custo de inscrever e recuperar memória - a base sobre a qual todos os modelos são construídos.

Scroll

Disponível
Desenrolado · recall assistido por LLM

Adiciona um modelo de linguagem para ler sua pergunta com mais atenção e trazer de volta um contexto mais completo, de modo que evidências dispersas voltem reunidas, em vez de faltar uma peça.

Codex

Em breve
Encadernado & indexado · roteamento próprio

Abre sozinho na página certa - escolhendo a memória e as ferramentas de que cada momento precisa, e ficando mais afiado quanto mais é usado.

O relatório completo de benchmark do Tablet 1 está na página de benchmarks.

Custo

Pague $2 para nós. Economize muitas vezes esse valor no seu LLM.

O WOS entrega ao seu LLM ~1,200 tokens por consulta - uma fatia limitada e relevante - em vez de enfiar o histórico completo em cada prompt. A diferença é enorme, e cresce junto com o seu histórico.

Custo do LLM por 1,000 consultas Com base no Tablet 1
Histórico do usuário100K
Consultas / mês1,000
Seu LLM
45× mais barato - você economiza $244/mês
Sem WOS$250.00
Com WOS$5.50

Cada $1 gasto no WOS economiza ~$98 no LLM. Histórico maior ou modelo mais caro → ROI maior.

De onde vem a economia

  • Sem o WOS, você enfia o histórico inteiro em cada prompt - 100K tokens × $2.50/1M = $0.25 por consulta, às tarifas de entrada do GPT-4o (cerca de 2× isso em modelos do nível do Opus).
  • Com o WOS, você ingere uma única vez ($2/1M) e cada consulta passa a ser uma pequena recuperação ($3/1M × 1,200) mais o seu LLM sobre apenas ~1,200 tokens.
  • Quanto menos tokens o seu LLM lê, menos você paga - e o WOS mantém esse número estável conforme a memória cresce.
Redução de contexto = histórico ÷ tokens entregues, não custo (a calculadora acima precifica cada recuperação).  25K → 21× · 100K → 83× · 200K → 167×.
Multilíngue

Todos os idiomas, a mesma precisão.

A recuperação é puramente semântica - apenas embeddings, zero correspondência por palavras-chave ou BM25. Então a qualidade do recall é idêntica, quer seus usuários escrevam em 日本語, 中文, Español ou inglês.

A correspondência lexical, como o BM25, é ajustada ao formato de um idioma específico - morfologia, espaçamento, escrita. Em um store multilíngue, isso significa que a qualidade da recuperação varia por idioma. O WOS não usa nenhuma correspondência lexical, então todos os idiomas passam pelo mesmo caminho.

Um store, três idiomas ao mesmo tempo

Você não escolhe um idioma por store - misture-os livremente. Abaixo, a memória de um único usuário contém japonês, inglês e espanhol ao mesmo tempo, e cada pergunta encontra a memória certa independentemente do idioma. Esta é uma interação real com a API em produção:

# 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
Resultados reais - cada pergunta cruza para um idioma diferente
"¿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

Sem etapa de tradução, sem detecção de idioma, sem configuração por idioma. Memórias e perguntas são posicionadas pelo significado, não pelo idioma - se o significado corresponde, o idioma não importa.

Três idiomas aqui é apenas o que cabe em uma página - não existe uma lista de idiomas suportados da qual fazer parte. O mesmo teste ao vivo também passa com memórias em 中文, Русский e العربية, todas verificadas contra a API de produção.

Por que banimos palavras-chave de propósito

A pontuação lexical, como o BM25, fortalece a recuperação para alguns idiomas mais do que para outros, o que atrapalha quando um store contém muitos idiomas. Por isso, nós a removemos completamente do motor e aplicamos essa regra na revisão de código: com qualquer pontuação lexical no caminho, a qualidade do recall variaria por idioma.

O LongMemEval é somente em inglês, então não mede recall multilíngue. A demonstração acima é como você pode verificar isso diretamente contra a API em produção.
Arquitetura

Nenhum modelo é executado sobre suas memórias.

O armazenamento é literal e o motor busca por embeddings - barato, rápido e determinístico. Um modelo nunca é executado sobre as suas memórias armazenadas. O Tablet não usa modelo algum; o Scroll e o Codex adicionam um ao redor do motor para resultados mais fortes, mas ele só vê a sua consulta, nunca o que você armazenou.

  • Motor determinístico. O motor retorna as mesmas memórias para a mesma consulta, todas as vezes - e é por isso que a variância do nosso benchmark vem apenas do modelo leitor.
  • Barato em escala. Sem custo de geração para armazenar ou recuperar, então sua conta acompanha o armazenamento - não o uso de modelo - conforme a memória cresce.

Suas palavras, intocadas

Um design comum executa um modelo de linguagem no momento da escrita para extrair e reescrever "fatos" do texto. Esse design troca três coisas: custo de geração em cada escrita, latência adicional e o armazenamento da paráfrase de um modelo em vez das palavras originais. O WOS faz a troca oposta - armazena o que foi dito, sem alterações, e deixa que o seu LLM faça a interpretação no momento da leitura, com o texto original em mãos.

O que o WOS não é: não é um banco vetorial que você precisa operar, nem um framework de RAG que você precisa montar. Nenhum modelo é executado sobre seus dados armazenados - esse caminho é puramente embeddings. O Scroll e o Codex usam, sim, um modelo de linguagem para resultados mais fortes, mas ele só vê a sua consulta, nunca suas memórias armazenadas - e ele nunca treina com seus dados nem os coleta.
Prova

90.7%, medido e reproduzível.

90.7% no LongMemEval-S, média de 5 execuções independentes (σ 0.5%, nenhuma escolhida a dedo), avaliado pelo juiz canônico GPT-4o do benchmark.

No mesmo benchmark, as pontuações variam bastante conforme o protocolo de avaliação - o juiz, o prompt e o que a camada de recuperação pode fazer. Usamos o juiz terceiro canônico GPT-4o do benchmark tal como publicado, não mudamos nada para nos ajustar ao teste e publicamos o código de pontuação e o prompt do leitor para que qualquer pessoa possa reproduzir os 90.7% exatamente.

O protocolo, em uma única tabela

ItemO que fazemos
Conjunto de dadosLongMemEval-S (limpo), ~240K tokens de histórico por pergunta
JuizO juiz canônico GPT-4o do benchmark - um terceiro, não nós
Execuções5 execuções independentes, todas as pontuações publicadas, média reportada (σ 0.5%)
LeitorModelo leitor e prompt fixos, publicados na íntegra

O que mantém a honestidade: um juiz terceiro, o prompt do leitor publicado sem alterações, recuperação puramente semântica e todas as execuções reportadas - não apenas a melhor. O motor de recuperação é determinístico - execute de novo e você obtém as mesmas memórias.

Escalamos benchmarks mais difíceis

Testamos no benchmark padrão mais difícil que ainda não conquistamos - e o número é a marca máxima entre todos os modelos WOS, reescrita sempre que um modelo melhor é lançado. Ao superar 94%, avançamos para um benchmark mais difícil.

LongMemEval-SEm andamento
Tablet 185.2%
Scroll 190.7%
Juiz GPT-4o · melhor entre todos os modelos WOS94% para avançar
Veja o relatório completo
Preços

Duas tarifas de token por modelo,
mais $0.0001 por requisição.

Por milhão de tokens mais uma taxa fixa de $0.0001 por requisição, pagamento conforme o uso. Sem assinatura, sem aluguel de armazenamento, sem limites de memória. Você paga quando seu agente escreve ou lê - nunca pelo que ele lembra.

ModeloEntrada / 1MSaída / 1M
Tablet 1$2$3Disponível
Scroll 1$4$8Disponível
Codex 1--A definir
  • $0.0001 por requisição. Uma taxa fixa em cada chamada de API, além do uso de tokens.
  • O armazenamento é gratuito. A ingestão paga uma única vez; manter os dados não custa nada. Sem limite de quantidade, sem limite de retenção.
  • Nós armazenamos. Nunca treinamos com os dados, os usamos ou olhamos para eles. A memória do seu agente é sua - nós apenas a organizamos para que você possa recuperá-la.
  • Por que o Tablet é tão barato: seu motor não executa modelo algum, então nosso custo é embeddings e disco - não GPUs. O Scroll e o Codex adicionam um modelo, e é isso que o preço mais alto deles cobre.
Outros modelos de cobrança cobram mensalmente pelo volume armazenado ou limitam a quantidade de memórias por plano. O WOS não cobra nada pelos dados armazenados, independentemente do volume ou da idade.

Limites de requisições por nível de uso →

Para desenvolvedores

Três chamadas: armazenar, recuperar, responder.

Uma única API. A chamada recall() retorna contexto de curto prazo, de longo prazo e do entorno em uma única ida e volta, pronto para inserir no seu prompt.

1

Armazenar

add() guarda fatos e trocas: as palavras do seu usuário, as do próprio assistente (speaker "me") ou as de uma pessoa nomeada. Incorporado na entrada, sem chamada de LLM.

2

Recuperar

recall() retorna curto prazo + longo prazo + contexto em uma única chamada - um contexto limitado e de tamanho fixo.

3

Responder

Entregue esse contexto limitado ao seu LLM - qualquer provedor, sua chave.

from wontopos import Client
mem = Client(api_key="wos-...")
mem.add("she prefers tea over coffee", user_id="alice")
mem.add("I suggested the jasmine tea", user_id="alice", speaker="me")  # its own words
# one call: short + long + context
ctx = mem.recall("what does alice drink?", user_id="alice")

Memórias carregam um falante. O padrão são as palavras do seu usuário, speaker "me" guarda o que o próprio assistente disse, e um nome como "Bob" lembra quem disse, permitindo lembrar por pessoa.

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.
Início rápido

Seu primeiro recall em 5 minutos.

Uma chave, uma linha de instalação, três chamadas - seu agente tem memória. Cada trecho de código nesta página foi realmente executado; as respostas são mostradas na íntegra.

1

Obtenha uma chave de API

Crie uma no console. Uma chave de 155 caracteres que começa com wos-live- é exibida uma única vez. Guarde-a em uma variável de ambiente - nunca no código.

2

Instale

pip install wontopos        # Python
npm install wontopos        # TypeScript / JavaScript
cargo add wontopos          # Rust
# curl - nothing to install, just set WOS_API_KEY
3

Crie um store, depois armazene & recupere

Um store é o user_id sob o qual você lê e escreve. Stores são explícitos: crie um primeiro (a chamada abaixo), depois armazene e recupere sob ele. Armazenar - embeddings gerados na entrada, sem chamada de LLM. Recuperar - curto prazo + longo prazo + contexto em uma única ida e volta.

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?")
import { Client } from "wontopos";

const mem = new Client({ apiKey: "wos-live-...", userId: "alice" });  // set the store once
await mem.createStore();            // create it (stores are explicit)
await mem.add("she prefers tea over coffee");  // no userId needed

// one call → short-term + long-term + context
const ctx = await mem.recall("what does alice drink?");
use wontopos::Client;

let mem = Client::new("wos-live-...").with_user("alice");  // set the store once
mem.create_store(None).await?;            // create it (stores are explicit)
mem.add("she prefers tea over coffee", None, json!({})).await?;

// one call → short-term + long-term + context
let ctx = mem.recall("what does alice drink?", None).await?;
# 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 - embedded on the way in, no LLM call
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"}'

# one call → short-term + long-term + context
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?"}'
Resposta real - create_store()
{"user_id": "alice", "status": "created"}
Resposta real - add()
{"id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "stored (1 chunks)"}
Defina o store uma vez. Passe user_id ao cliente e todas as chamadas o usam - sem precisar repeti-lo; sobrescreva uma chamada específica passando user_id a ela. Stores são explícitos: armazenar em um store que não existe, ou recuperar dele, retorna 404 - crie-o primeiro. Toda conta começa com um store default, então sem nenhum user_id o caminho de configuração zero simplesmente funciona. Veja Stores para listá-los e gerenciá-los.

recall() retorna quatro blocos - short_term (turnos recentes), long_term (memórias relevantes), context (o que cercava a melhor correspondência) e uma instruction dizendo ao LLM como usá-los. Insira tudo isso no seu prompt.

Funciona em qualquer idioma. Armazene em inglês, pergunte em coreano, japonês ou chinês - a mesma memória volta. Busca por embeddings, não correspondência por palavras-chave.

Todos os métodos, por linguagem →

Stores

Stores - criar, listar, excluir.

Um store é o user_id sob o qual você lê e escreve - um espaço de memória isolado por usuário final, agente ou tópico. Stores são explícitos: crie um antes de armazenar nele ou recuperar dele, ou a chamada retorna 404. Toda conta começa com um store default, então você pode começar sem uma chamada de criação.

Como o isolamento se aninha. Uma conta possui workspaces; cada workspace isola sua própria memória, suas chaves de API e seu uso (a cobrança é compartilhada no nível da conta). Um store vive dentro de um workspace: chaves do mesmo workspace compartilham seus stores, e workspaces diferentes nunca veem a memória uns dos outros. account → workspace → store (user_id) → memories.
mem.create_store("alice")        # create (idempotent)
mem.list_stores()              # [{"user_id","created_at"}, ...]
mem.delete_store("alice")        # delete the store + all its memories
await mem.createStore("alice");
await mem.listStores();          // [{ user_id, created_at }, ...]
await mem.deleteStore("alice");     // store + all its memories
mem.create_store("alice").await?;
let stores = mem.list_stores().await?;
mem.delete_store("alice").await?;
# create
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"}'
# list
curl https://api.wontopos.com/api/v1/memory/collections -H "X-API-Key: $WOS_API_KEY"
# delete (store + all its memories)
curl -X DELETE https://api.wontopos.com/api/v1/memory/collection \
  -H "X-API-Key: $WOS_API_KEY" -H "Content-Type: application/json" -d '{"user_id":"alice"}'
Resposta real - create
{ "user_id": "alice", "status": "created" }   // "exists" if it already did
Resposta real - list
{ "collections": [
  { "user_id": "default", "created_at": "2026-06-26T02:23:14Z" },
  { "user_id": "alice",   "created_at": "2026-06-26T02:24:01Z" }
], "count": 2 }
Recall em um store que não existe
{ "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." } }
Use um store por usuário final ("alice", "user_42") para manter a memória de cada pessoa separada, ou um único store default para um agente pessoal. Você também pode criar e navegar pelos stores no console (Memory ids → Issue) sem escrever código. Excluir um store é permanente - remove todas as memórias sob ele.
Cache de recall

Recalls repetidos, por um décimo do preço.

Ative por solicitação e o WOS armazena em cache o resultado da busca sob o texto da consulta, com as mesmas regras de prefixo do prompt caching dos LLMs. Enquanto o cache está quente, uma consulta repetida ou estendida reutiliza o resultado anterior, e a parte em cache é cobrada a 10% da tarifa normal por token.

Apenas Tablet e Scroll. O cache funciona em todos os modelos Tablet e Scroll, atuais e futuros. O Codex não o suporta: o Codex raciocina sobre suas memórias e aprende entre as chamadas, então a mesma pergunta pode legitimamente voltar com uma resposta diferente, e um resultado em cache seria errado por design. Enviar cache_control ao Codex retorna um 403 claro.

Uma conversa, três turnos

É isto que realmente acontece quando um agente continua conversando com sua memória. Cada turno envia a conversa acumulada como consulta, com cache_control ligado.

writeTurno 1 - “Alice: Eu me mudei para Lisboa na primavera passada.”

A consulta inteira é buscada e armazenada em cache: entrada a 2x (TTL de 5 minutos).

extendTurno 2 - o mesmo texto mais “Bob: Como está o clima aí?”

Só a frase do Bob é transformada em embeddings e buscada. A parte antiga custa 0,1x, a frase nova 2x, e o cache agora termina nela.

hitTurno 3 - exatamente a mesma consulta de novo (um retry, um refresh)

Nenhuma chamada ao motor. Tudo a 0,1x: o desconto de 90%.

As tarifas

OperaçãoCobrança de tokensO que significa
Escrita de cache - TTL 5 minutosA primeira solicitação. Seu resultado é mantido por 5 minutos, e cada leitura desliza a janela para frente.
Escrita de cache - TTL 1 horaA primeira solicitação, mantida por uma hora inteira.
Leitura de cache - acerto ou acerto de prefixo0.1×Toda solicitação após a escrita: a parte em cache custa um décimo da tarifa normal por token.

Quanto isso economiza

Um exemplo concreto: seu agente envia uma conversa de 3.000 tokens como consulta e a repete ou continua 10 vezes em cinco minutos. Sem cache, são 30.000 tokens de entrada a preço cheio. Com um cache de 5 minutos, são 6.000 pela primeira escrita (2x) mais cerca de 2.700 pelas nove leituras em cache: 8.700 tokens cobrados, 71% menos. Quanto mais longa a conversa, maior a economia.

A regra do prefixo

A correspondência é feita no início da consulta. Se o início permanece idêntico e apenas texto novo é acrescentado ao final, a parte em cache é reutilizada e apenas a parte nova é buscada. Se algo muda antes do fim do texto em cache, nada pode ser reutilizado.

prefix match
cached    [ A B C D E F G ]

○   [ A B C D E F G ] E
✗   [ B C D E F G ] E

acerto - o início não mudou, E é a única parte nova
erro - o início mudou, então a consulta inteira é buscada e armazenada em cache novamente

Três regras para lembrar

  • Estender rearmazena até a nova cauda. Depois de [A B C D E F G] + E, o cache agora termina em E: a cauda é cobrada uma vez na tarifa de escrita, e o próximo turno pode casar todo o A..E como prefixo de novo.
  • Um único prefixo contíguo por solicitação. Uma consulta não pode ser dividida em dois segmentos de cache; apenas o seu início pode casar.
  • Escritas invalidam na hora. Qualquer store, store-turn, bulk-store, forget, supersede ou exclusão do store descarta o cache dele, então uma resposta em cache nunca pode ficar obsoleta.

Como ativar

hits = mem.search(
    "...the conversation so far...", user_id="alice",
    cache_control={"ttl": "5m"},   # or "1h"
)
const hits = await mem.search(
  "...the conversation so far...", "alice", 10,
  { cache_control: { ttl: "5m" } },   // or "1h"
);
let hits = mem.search_with(
    "...the conversation so far...", "alice", 10,
    serde_json::json!({"cache_control": {"ttl": "5m"}}),   // or "1h"
).await?;
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":"...the conversation so far...",
       "cache_control":{"ttl":"5m"}}'   # or "1h"
Resposta - o objeto cache informa o que aconteceu
{ "memories": [ ... ],
  "cache": { "status": "hit",              // "write" | "hit" | "extend"
             "ttl": "5m",
             "cache_read_input_tokens": 412,
             "cache_creation_input_tokens": 0 } }

Você não precisa de um SDK para nada disso. O caching é um campo em uma chamada HTTP, então funciona a partir de qualquer linguagem de programação. A aba curl é a receita universal, e os SDKs de Python, TypeScript e Rust são apenas invólucros de conveniência sobre exatamente a mesma chamada.

O cache é isolado por store e por modelo dentro do seu workspace, e vem desligado por padrão: sem cache_control, nada muda nas suas solicitações.
Quem disse

Memória que sabe quem disse.

As pessoas lembram por pessoa: o que o Bob prometeu, o que você disse que faria. Marque cada memória com um falante e seu agente faz o mesmo, em todos os modelos Tablet e Scroll.

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.

Um time, três memórias

Um armazenamento mantém muitas vozes separadas. Registre uma pessoa uma vez, salve cada fala com seu falante e depois pergunte por pessoa.

addRegistre o Bob uma vez: POST /speakers, ou add_speaker("Bob") nos SDKs.

O armazenamento agora conhece o Bob. O limite de 50 é contado aqui, no registro; chamadas de salvamento nunca retornam erro de limite.

BobBob diz que o prazo mudou para terça. Salve com speaker "Bob".

A memória agora é do Bob: toda busca que a devolve indica isso.

meSeu assistente promete o resumo até sexta. Salve as próprias palavras com speaker "me".

A fala do próprio assistente também vira memória, e "me" nunca conta para o limite.

askDepois: "o que o Bob disse sobre o prazo?" Busque com speaker "Bob".

Só as palavras do Bob voltam. As palavras de uma pessoa nunca voltam como as de outra.

Três regras para lembrar

  • "me" é o próprio assistente. Nunca registrado, nunca contado. Reservado e minúsculo: speaker: "Me" ou "ME" retorna 400 invalid_request_error em vez de ser convertido em silêncio.
  • O limite é contado no registro: 50 por armazenamento para começar. Registrar além disso retorna 400 invalid_request_error com speaker_limit: 50 no corpo do erro. Salvar com um nome não registrado também retorna 400 e nada é salvo. Filtrar a busca por um nome não registrado retorna 404 not_found_error. Ramifique pelo status e pelos campos, não pelo texto da mensagem; planejamos aumentar o limite.
  • Rótulos vivem em toda leitura. Resultados de busca, o contexto de longo prazo do recall e resultados de engram carregam seu falante — o modelo sempre sabe de quem são as palavras. Passe speaker numa busca para obter só as de uma pessoa. Um supersede mantém o falante; forget o remove.
  • Nomes são Unicode: qualquer idioma funciona. さくら, Иван e 하늘 são falantes válidos, e a atribuição se comporta igual em todos os idiomas. A correspondência é exata após trim e normalização Unicode, então Bob e bob são duas pessoas. Nomes vão até 80 caracteres.
errors - verbatim
# POST /speakers past the limit
{ "type": "error",
  "error": { "type": "invalid_request_error",
             "message": "This store already has 50 registered speakers, ...",
             "speaker_limit": 50 } }

# store with an unregistered name → 400, nothing stored
{ "type": "error",
  "error": { "type": "invalid_request_error",
             "message": "speaker 'Bob' is not registered in this store. Register it first: ...",
             "speaker": "Bob" } }

# search filtered by an unregistered name → 404
{ "type": "error",
  "error": { "type": "not_found_error",
             "message": "speaker 'Bob' is not registered in this store.",
             "speaker": "Bob" } }

Duas notas de escopo. speaker acompanha add / store: add_turn lembra a troca inteira, e rótulos por pessoa e o filtro vêm de memórias com speaker explícito. E passagens de sessão (expand) são compostos de várias memórias, então não carregam rótulo; um filtro speaker sempre devolve memórias atômicas e rotuladas. E conteúdo idêntico é deduplicado para a primeira memória: esse store retorna status "duplicate" com uma nota explícita, e nenhum falante é anexado.

Testamos do jeito difícil: memórias sem nomes no texto, lembradas por pessoa. A atribuição vem do registro de falantes, não de casamento de palavras, então funciona igual em qualquer idioma.

Como usar

mem.add_speaker("Bob", user_id="alice")  # once per person; "me" needs no registration
mem.add("Bob said the deadline moved to Tuesday", user_id="alice", speaker="Bob")
mem.add("I promised the summary by Friday", user_id="alice", speaker="me")
hits = mem.search("what did Bob say about the deadline?", user_id="alice", speaker="Bob")
mem.list_speakers(user_id="alice")
mem.remove_speaker("Bob", user_id="alice")  # memories stay, the tag goes
await mem.addSpeaker("Bob", "alice");  # once per person; "me" needs no registration
await mem.add("Bob said the deadline moved to Tuesday", "alice", { speaker: "Bob" });
await mem.add("I promised the summary by Friday", "alice", { speaker: "me" });
const hits = await mem.search("what did Bob say about the deadline?", "alice", 10, { speaker: "Bob" });
await mem.listSpeakers("alice");
await mem.removeSpeaker("Bob", "alice");  // memories stay, the tag goes
mem.add_speaker("Bob", "alice").await?;  # once per person; "me" needs no registration
mem.add("Bob said the deadline moved to Tuesday", "alice", json!({"speaker": "Bob"})).await?;
mem.add("I promised the summary by Friday", "alice", json!({"speaker": "me"})).await?;
let hits = mem.search_with("what did Bob say about the deadline?", "alice", 10, json!({"speaker": "Bob"})).await?;
mem.list_speakers("alice").await?;
mem.remove_speaker("Bob", "alice").await?;  // memories stay, the tag goes
curl -X POST https://api.wontopos.com/api/v1/memory/speakers \
  -H "X-API-Key: $WOS_API_KEY" -H "Content-Type: application/json" \
  -d '{"user_id":"alice","speaker":"Bob"}'   # once per person

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":"Bob said the deadline moved to Tuesday","metadata":{"speaker":"Bob"}}'

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 did Bob say about the deadline?","speaker":"Bob"}'

curl "https://api.wontopos.com/api/v1/memory/speakers?user_id=alice" -H "X-API-Key: $WOS_API_KEY"

curl -X DELETE https://api.wontopos.com/api/v1/memory/speakers \
  -H "X-API-Key: $WOS_API_KEY" -H "Content-Type: application/json" \
  -d '{"user_id":"alice","speaker":"Bob"}'   # memories stay, the tag goes
response
{ "memories": [
    { "content": "Bob said the deadline moved to Tuesday",
      "speaker": "Bob", ... } ] }
GET /speakers
{ "user_id": "alice",
  "speakers": [ { "speaker": "Bob", "memories": 2, "created_at": "2026-07-10T04:20:39Z" } ],
  "count": 1, "limit": 50 }

A lista mostra quem o armazenamento conhece, com contagens por pessoa contra o limite. Remover apaga só o registro: as memórias ficam, apenas o rótulo do nome vai embora.

Complemento · Beta

MCP - memória para ferramentas de IA

O núcleo do WOS é a API e os SDKs. O servidor MCP é um complemento sobre eles: a mesma memória, plugada em ferramentas que você não construiu - Claude Code, Claude Desktop, Cursor.

Uma linha de instalação dá ao agente nove ferramentas de memória que ele usa sozinho. E como a memória vive na sua conta, o que uma ferramenta escreve, todas as outras lembram - inclusive agentes que você constrói com o SDK.

O que dá para fazer com isso

  • Um Claude Code que lembra do seu projeto. Decisões, correções, preferências - lembrados na próxima sessão sem reexplicar nada.
  • Comece no ChatGPT, continue no Claude. Mesmo store, mesma memória - a conversa atravessa ferramentas em vez de recomeçar.
  • Seu próprio agente continua no circuito. O que o Claude Code aprende, um agente do SDK lembra - e o que seu agente guarda, o Claude Code lembra de volta.

Funciona no Claude Code, Claude Desktop, Cursor, Windsurf e qualquer host MCP. O ChatGPT alcança a mesma memória via Actions mais a spec OpenAPI.

Instalação

claude mcp add wontopos --env WONTOPOS_API_KEY=wos-live-... -- npx -y wontopos-mcp

O agente recebe nove ferramentas - recall · remember · search · update · forget · list_memories · engram · stats · create_store - cada uma descrita para que ele saiba sozinho quando usá-las.

O complemento em si é grátis e publicado no npm - você paga só o preço de uso normal pelas chamadas de API que ele faz. Requer Node 18+ e uma chave criada no console.

Abrir a página de desenvolvedor

Complemento

Spec OpenAPI

O mapa completo e legível por máquina da API - cada endpoint, requisição, resposta e erro.

OpenAPI é o formato padrão da indústria para descrever uma API HTTP em um arquivo legível por máquinas.

https://api.wontopos.com/openapi.json

O que dá para fazer com isso

Postman: File → Import → cole a URL e os 16 endpoints viram uma coleção clicável. ChatGPT: crie um GPT, adicione uma Action, cole a mesma URL. Codegen: openapi-generator -i .../openapi.json -g go gera um cliente em uma linguagem que não publicamos.

Importe no Postman, gere um cliente em uma linguagem que não publicamos, conecte ChatGPT Actions ou rode checks de contrato no CI. Um teste a fixa às rotas reais: não há como desviar.

Complemento

llms.txt

Toda a API em uma página de texto que uma IA consegue ler.

llms.txt é uma convenção da web: uma página de texto puro na raiz do site que conta a uma IA tudo o que ela precisa sobre um produto.

https://wontopos.com/llms.txt

Coloque na sua IDE ou agente de código e ele sabe como construir sobre o WOS - auth, endpoints, padrões, erros. Atualizado a cada release.

Os mesmos fatos da spec OpenAPI, público diferente: a spec é estrutura precisa para ferramentas; este arquivo é prosa que uma IA (ou uma pessoa) lê de uma vez. Ambos atualizam a cada release.

Model Context Protocol · Beta

Sua memória dentro de cada ferramenta de IA

Um único comando dá ao Claude Code, Claude Desktop, Cursor ou qualquer host MCP uma memória de longo prazo baseada na sua conta WOS. Sem código de integração: o agente recebe nove ferramentas de memória e decide quando usá-las.

MCP está em beta. As nove ferramentas funcionam hoje e são testadas, mas a superfície ainda pode mudar enquanto a finalizamos. A API e os SDKs por baixo são estáveis e versionados.

Instalação

Claude Code, uma linha (crie antes uma chave no console):

claude mcp add wontopos --env WONTOPOS_API_KEY=wos-live-... -- npx -y wontopos-mcp
# pick which store it remembers into (optional): add --env WONTOPOS_USER_ID=my-project
# ~/.cursor/mcp.json
{ "mcpServers": {
    "wontopos": {
      "command": "npx",
      "args": ["-y", "wontopos-mcp"],
      "env": { "WONTOPOS_API_KEY": "wos-live-...",
               "WONTOPOS_USER_ID": "my-project" }
    } } }
# .vscode/mcp.json
{ "servers": {
    "wontopos": {
      "command": "npx",
      "args": ["-y", "wontopos-mcp"],
      "env": { "WONTOPOS_API_KEY": "wos-live-...",
               "WONTOPOS_USER_ID": "my-project" }
    } } }
# ~/.codeium/windsurf/mcp_config.json
{ "mcpServers": {
    "wontopos": {
      "command": "npx",
      "args": ["-y", "wontopos-mcp"],
      "env": { "WONTOPOS_API_KEY": "wos-live-...",
               "WONTOPOS_USER_ID": "my-project" }
    } } }
# Claude Desktop and any other MCP host
{ "mcpServers": {
    "wontopos": {
      "command": "npx",
      "args": ["-y", "wontopos-mcp"],
      "env": { "WONTOPOS_API_KEY": "wos-live-...",
               "WONTOPOS_USER_ID": "my-project" }
    } } }

Add to Cursor →  ·  Add to VS Code →

Env opcional: WONTOPOS_USER_ID define o store padrão, WONTOPOS_MODEL o motor, WONTOPOS_BASE_URL uma implantação self-hosted. WONTOPOS_READ_ONLY=1 muda para somente leitura (só recall/busca/listagem).

Antes de compartilhar um store

  • Use uma chave dedicada. Chaves carregam seu workspace: uma chave só para MCP delimita o que as ferramentas conectadas podem tocar - e você pode rotacioná-la no console sem mexer nas chaves do app.
  • Modo somente leitura. WONTOPOS_READ_ONLY=1 não registra nenhuma ferramenta de escrita: o agente pode lembrar, buscar, listar memórias, executar engramas e ler estatísticas, mas não guardar, atualizar, esquecer ou apagar. Ideal para agentes que devem consultar a memória, não possuí-la.
  • Mantenha a confirmação de ferramentas ligada. Hosts MCP perguntam antes de rodar ferramentas por padrão - deixe ligada principalmente para forget, pois exclusões valem para todas as ferramentas do store.
  • Tudo o que for guardado pode ser lembrado por qualquer ferramenta com a chave. Nunca guarde segredos - chaves de API, senhas - como memórias.
  • Memórias lembradas são dados, não instruções. As descrições das ferramentas dizem isso explicitamente ao agente. Ainda assim, não guarde texto de terceiros não confiável em um store que um agente autônomo obedece.
  • Exclusões também são compartilhadas. Um forget ou delete_all de uma ferramenta apaga para todas.
  • "me" é o agente que escreve no store. Se vários agentes compartilham um store, as vozes "me" se misturam. Dê a cada agente seu próprio store (WONTOPOS_USER_ID) para identidades separadas.
  • Uma conta paga. Todas as ferramentas conectadas consomem o mesmo saldo e limite de taxa.

Depois, é só conversar

youlembre que lançamos às sextas

O agente chama a ferramenta remember. Fica guardado de forma durável: o fim da sessão não muda nada.

new sessionquando lançamos?

Uma sessão nova não tem histórico. O agente chama recall e responde de memória: às sextas.

Coisas para dizer

  • "Este repo usa pnpm, lembre disso" → remember guarda; a próxima sessão já sabe.
  • "Qual formato de erro combinamos semana passada?" → recall traz a decisão de volta ao contexto.
  • "Na verdade, o prazo passou para sexta" → o agente vê que contradiz o que lembrou e chama update para corrigir essa memória no lugar.
  • "Isso está errado, esqueça" → o agente acha o id e chama forget - seu host pede confirmação antes.
  • "O que você lembra sobre mim?" → list_memories percorre tudo o que está guardado, para o agente responder ou organizar.

Nada de especial para formular: são frases comuns, não comandos. O agente lê a descrição de cada ferramenta e escolhe sozinho.

As nove ferramentas

  • recall - Contexto em uma chamada: turnos recentes mais memórias relevantes. A descrição instrui o agente a chamá-la primeiro sempre que o contexto passado importar.
  • remember - Guarda um fato ou decisão durável. speaker: "me" marca as palavras do próprio agente; um nome registrado, quem disse.
  • search - Busca semântica, com filtro opcional por pessoa (speaker).
  • forget - Apaga uma memória pelo id.
  • speakers - Registra, lista ou remove as pessoas que um store lembra.
  • create_store - Stores são explícitos: um por usuário final, projeto ou agente.

SDK ou MCP?

  • O SDK vai dentro de um app que você escreve. Seu código decide exatamente quando guardar e o que lembrar - determinístico, tipado, versionado. Construindo um produto? SDK.
  • O MCP se pluga em uma ferramenta de IA que você não escreveu. O agente decide quando usar a memória, guiado pelas descrições - zero código. Para Claude Code, Claude Desktop, Cursor ou dar memória a um assistente pronto.

Por baixo, a mesma API e os mesmos stores - um app feito no SDK e uma sessão do Claude Code via MCP compartilham uma memória. Escolha por superfície, não um ou outro.

Uma memória através de todas as ferramentas

A memória pertence à conta, não à ferramenta. O mesmo store escrito do ChatGPT (Actions mais a spec OpenAPI) é lembrado no Claude Code e nos seus próprios agentes, e vice-versa: uma conversa iniciada em uma ferramenta continua em outra.

E como é um único store, você pode sair do Claude Code e continuar a conversa onde constrói: um agente do SDK com a mesma chave e store lembra tudo o que o Claude Code acabou de aprender - e o que seu agente guarda, o Claude Code lembra na próxima sessão.

Roda localmente via stdio (npx wontopos-mcp): sua chave fica no seu ambiente e nunca passa por um servidor de terceiros. Envolve o SDK TypeScript, então retries automáticos, recusa de redirecionamentos e mascaramento da chave valem como estão.
Model Context Protocol · Beta

Claude Code

O caminho principal: um comando no terminal e toda sessão começa com memória.

  1. Crie uma chave de API no console. A chave carrega seu workspace: uma chave = um espaço de memória.
  2. Registre o servidor. --scope user o disponibiliza em todos os projetos; sem ele, só o projeto atual o vê.
  3. Confira: rode /mcp dentro do Claude Code - wontopos deve aparecer com nove ferramentas.
  4. Torne automático: uma linha no seu CLAUDE.md - "quando o contexto passado importar, chame wontopos recall primeiro" - e toda sessão começa com memória sem pedir.
claude mcp add wontopos --scope user \
  --env WONTOPOS_API_KEY=wos-live-... -- npx -y wontopos-mcp
# pick a store (optional): add --env WONTOPOS_USER_ID=my-project
Model Context Protocol · Beta

Claude Desktop

Adicione o bloco abaixo ao claude_desktop_config.json (Configurações → Developer → Edit Config), reinicie o app e as nove ferramentas aparecem. Nota: o claude.ai na web e no celular precisa de um servidor MCP remoto, que o WOS ainda não oferece - o app de desktop é o caminho suportado.

# claude_desktop_config.json
{ "mcpServers": {
    "wontopos": {
      "command": "npx",
      "args": ["-y", "wontopos-mcp"],
      "env": { "WONTOPOS_API_KEY": "wos-live-...",
               "WONTOPOS_USER_ID": "my-project" }
    } } }
Model Context Protocol · Beta

Cursor

Adicione o bloco abaixo ao ~/.cursor/mcp.json - ou aperte o botão de um clique - e reinicie o Cursor. O agente pega as nove ferramentas.

# ~/.cursor/mcp.json
{ "mcpServers": {
    "wontopos": {
      "command": "npx",
      "args": ["-y", "wontopos-mcp"],
      "env": { "WONTOPOS_API_KEY": "wos-live-...",
               "WONTOPOS_USER_ID": "my-project" }
    } } }

Add to Cursor →

Model Context Protocol · Beta

VS Code

O VS Code (modo agente do Copilot) lê servidores MCP de .vscode/mcp.json do projeto - adicione o bloco abaixo ou aperte o botão de um clique.

# .vscode/mcp.json
{ "servers": {
    "wontopos": {
      "command": "npx",
      "args": ["-y", "wontopos-mcp"],
      "env": { "WONTOPOS_API_KEY": "wos-live-...",
               "WONTOPOS_USER_ID": "my-project" }
    } } }

Add to VS Code →

Model Context Protocol · Beta

Windsurf

O Windsurf (Cascade) lê ~/.codeium/windsurf/mcp_config.json: adicione o bloco abaixo e recarregue - as mesmas nove ferramentas aparecem.

# ~/.codeium/windsurf/mcp_config.json
{ "mcpServers": {
    "wontopos": {
      "command": "npx",
      "args": ["-y", "wontopos-mcp"],
      "env": { "WONTOPOS_API_KEY": "wos-live-...",
               "WONTOPOS_USER_ID": "my-project" }
    } } }
Model Context Protocol · Beta

ChatGPT

Os conectores MCP do ChatGPT só aceitam servidores remotos, então o caminho suportado hoje é um GPT personalizado com uma Action: crie um GPT, adicione uma Action, cole a URL da spec OpenAPI abaixo e defina sua chave como header de auth. Esse GPT chamará a mesma memória das suas outras ferramentas.

# GPT → Configure → Actions → Import from URL
https://api.wontopos.com/openapi.json
# Authentication: API Key · Header name: X-API-Key

Mesmo store, mesma memória: o que o ChatGPT guarda pela Action, o Claude Code lembra pelo MCP - e vice-versa.

Model Context Protocol · Beta

Gemini CLI

O Gemini CLI lê servidores MCP de ~/.gemini/settings.json: adicione o bloco abaixo, reinicie a CLI e as mesmas nove ferramentas aparecem lá também.

# ~/.gemini/settings.json
{ "mcpServers": {
    "wontopos": {
      "command": "npx",
      "args": ["-y", "wontopos-mcp"],
      "env": { "WONTOPOS_API_KEY": "wos-live-...",
               "WONTOPOS_USER_ID": "my-project" }
    } } }
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-07-10; 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 ✓ live-tested

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": "scroll-1", "name": "Scroll 1", "available": true, "memory": "shared"},
 {"id": "scroll-1.2", "name": "Scroll 1.2", "available": true, "memory": "shared"}]

ping ✓ live-tested

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 ✓ live-tested

Armazena uma memória. Embeddings gerados na entrada - sem chamada de LLM, você paga apenas embeddings.

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 ✓ live-tested

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 ✓ live-tested

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
{"memories": [{"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 ✓ live-tested

Faz backfill de um grande bloco de texto. Fragmentado e convertido em embeddings no servidor - ideal para importar um 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 ✓ live-tested

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 ✓ live-tested

Busca semântica, os mais relevantes primeiro. Puramente embeddings - sem correspondência por palavras-chave, então qualquer idioma encontra qualquer memória. O SDK retorna o array de memórias diretamente; o corpo HTTP bruto é mostrado abaixo.

r = mem.search("what does she drink?", user_id="alice", limit=1)
Resposta real (corpo HTTP)
{"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-07-10T04:20:39.688276876Z"
 }], "search_ms": 315, "total_found": 1}
CampoSignificado
similaritySimilaridade bruta de embedding com a sua consulta (0–1).
is_supersededVerdadeiro se este fato foi substituído por update().
search_msTempo de recuperação no servidor.

recall ✓ live-tested

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 ✓ live-tested

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 ✓ live-tested

Contagens de memórias de um usuário.

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

get ✓ live-tested

Busca uma memória pelo id - o id que add ou list_memories retornou. Apenas o texto original armazenado e seus metadados, nunca o vetor. 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", "source_type": "user_said",
 "created_at": "2026-07-10T04:20:39Z", "event_date": null, "is_superseded": false}

list_memories ✓ live-tested

Lista as memórias de um armazenamento - apenas o texto original que você guardou e seus metadados, nunca o vetor. 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", "source_type": "user_said",
    "created_at": "2026-07-10T04:20:39Z", "event_date": null, "is_superseded": false}
 ]}

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 ✓ live-tested

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 ✓ live-tested

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": ...}
SDK TypeScript

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

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

npm install wontopos
import { Client } from "wontopos";

const mem = new Client({ apiKey: "wos-live-..." });

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 construtor; sobrescreva uma chamada específica com 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 ✓ live-tested

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.

await mem.listModels();
Resposta real
[{"id": "tablet-1", "name": "Tablet 1", "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 ✓ live-tested

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

await mem.ping();   // true, or throws 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 ✓ live-tested

Armazena uma memória. Embeddings gerados na entrada - sem chamada de LLM, você paga apenas embeddings.

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

addTurn ✓ live-tested

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

await mem.addTurn("hi", "hello!", "alice");
Resposta real
{"status": "ok"}

speaker ✓ live-tested

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.

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" });
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.

addBulk ✓ live-tested

Faz backfill de um grande bloco de texto. Fragmentado e convertido em embeddings no servidor - ideal para importar um histórico existente.

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

update ✓ live-tested

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

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

Ler

search ✓ live-tested

Busca semântica, os mais relevantes primeiro. Puramente embeddings - sem correspondência por palavras-chave, então qualquer idioma encontra qualquer memória. O SDK retorna o array de memórias diretamente; o corpo HTTP bruto é mostrado abaixo.

const r = await mem.search("what does she drink?", "alice", 1);
Resposta real (corpo HTTP)
{"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-07-10T04:20:39.688276876Z"
 }], "search_ms": 315, "total_found": 1}
CampoSignificado
similaritySimilaridade bruta de embedding com a sua consulta (0–1).
is_supersededVerdadeiro se este fato foi substituído por update().
search_msTempo de recuperação no servidor.

recall ✓ live-tested

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.

const ctx = await mem.recall("what does she drink?", "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 ✓ live-tested

Turnos recentes da conversa (memória de curto prazo), do mais antigo para o mais recente.

const turns = await 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 ✓ live-tested

Contagens de memórias de um usuário.

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

get ✓ live-tested

Busca uma memória pelo id - o id que add ou list_memories retornou. Apenas o texto original armazenado e seus metadados, nunca o vetor. Um id de outro store, ou uma memória apagada ou invalidada, retorna 404.

const m = await mem.get("alice", "576700aa-...");
response
{"id": "576700aa-...", "content": "she prefers tea over coffee",
 "category": "general", "source_type": "user_said",
 "created_at": "2026-07-10T04:20:39Z", "event_date": null, "is_superseded": false}

listMemories ✓ live-tested

Lista as memórias de um armazenamento - apenas o texto original que você guardou e seus metadados, nunca o vetor. Paginado por cursor: reenvie o next_cursor retornado para a próxima página.

const page = await mem.listMemories("alice", { limit: 100 });
response
{"count": 2, "next_cursor": null, "memories": [
   {"id": "576700aa-...", "content": "she prefers tea over coffee",
    "category": "general", "source_type": "user_said",
    "created_at": "2026-07-10T04:20:39Z", "event_date": null, "is_superseded": false}
 ]}

iterMemories · exportMemories

Percorra todas as memórias sem gerenciar o cursor, ou traga o armazenamento inteiro de uma vez.

for await (const m of mem.iterMemories("alice")) console.log(m.id, m.content);
const everything = await mem.exportMemories("alice");

Excluir

delete ✓ live-tested

Exclui uma única memória pelo id.

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

deleteAll ✓ live-tested

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

await mem.deleteAll("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.

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

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

await mem.search("...", "alice");
const rl = mem.rateLimit;   // { limit: 150, remaining: 3, reset: ... }
SDK Rust

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

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

cargo add wontopos
use wontopos::Client;

let mem = Client::new("wos-live-...");

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 com with_model(); encadeie-o novamente para sobrescrever uma chamada específica.

let mem = Client::new("wos-live-...").with_model("tablet-1");  // default
mem.recall("...", "alice").await?;                       // tablet-1
mem.with_model("scroll-1").recall("...", "alice").await?;  // or pick a model per call

list_models ✓ live-tested

O catálogo - os ids que você pode passar em with_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().await?;
Resposta real
[{"id": "tablet-1", "name": "Tablet 1", "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 ✓ live-tested

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

mem.ping().await?;   // Ok(true), or Err whose .kind() is Auth / PaymentRequired

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 ✓ live-tested

Armazena uma memória. Embeddings gerados na entrada - sem chamada de LLM, você paga apenas embeddings.

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

add_turn ✓ live-tested

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!", "alice").await?;
Resposta real
{"status": "ok"}

speaker ✓ live-tested

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", "alice").await?;  # once per person; "me" needs no registration
mem.add("I promised to send the report on Friday", "alice", json!({"speaker": "me"})).await?;
mem.add("Bob said the deadline moved to Tuesday", "alice", json!({"speaker": "Bob"})).await?;
mem.search_with("what did Bob say about deadlines?", "alice", 10, json!({"speaker": "Bob"})).await?;
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 ✓ live-tested

Faz backfill de um grande bloco de texto. Fragmentado e convertido em embeddings no servidor - ideal para importar um histórico existente.

mem.add_bulk("Alice moved to Brooklyn in March...", "alice", "general").await?;
Resposta real
{"elapsed_secs": 0.154154944, "status": "ok", "stored": 1, "total_chunks": 1}

update ✓ live-tested

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", "alice").await?;
Resposta real
{"new_memory_id": "07e94433-b7cc-4e49-8d8f-f37fc1a392b7",
 "old_memory_id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "superseded"}

Ler

search ✓ live-tested

Busca semântica, os mais relevantes primeiro. Puramente embeddings - sem correspondência por palavras-chave, então qualquer idioma encontra qualquer memória. O SDK retorna o array de memórias diretamente; o corpo HTTP bruto é mostrado abaixo.

let r = mem.search("what does she drink?", "alice", 1).await?;
Resposta real (corpo HTTP)
{"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-07-10T04:20:39.688276876Z"
 }], "search_ms": 315, "total_found": 1}
CampoSignificado
similaritySimilaridade bruta de embedding com a sua consulta (0–1).
is_supersededVerdadeiro se este fato foi substituído por update().
search_msTempo de recuperação no servidor.

recall ✓ live-tested

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.

let ctx = mem.recall("what does she drink?", "alice").await?;
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 ✓ live-tested

Turnos recentes da conversa (memória de curto prazo), do mais antigo para o mais recente.

let turns = mem.history("alice").await?;
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 ✓ live-tested

Contagens de memórias de um usuário.

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

get ✓ live-tested

Busca uma memória pelo id - o id que add ou list_memories retornou. Apenas o texto original armazenado e seus metadados, nunca o vetor. Um id de outro store, ou uma memória apagada ou invalidada, retorna 404.

let m = mem.get("alice", "576700aa-...").await?;
response
{"id": "576700aa-...", "content": "she prefers tea over coffee",
 "category": "general", "source_type": "user_said",
 "created_at": "2026-07-10T04:20:39Z", "event_date": null, "is_superseded": false}

list_memories ✓ live-tested

Lista as memórias de um armazenamento - apenas o texto original que você guardou e seus metadados, nunca o vetor. Paginado por cursor: reenvie o next_cursor retornado para a próxima página.

mem.list_memories("alice", 100, None).await?;
response
{"count": 2, "next_cursor": null, "memories": [
   {"id": "576700aa-...", "content": "she prefers tea over coffee",
    "category": "general", "source_type": "user_said",
    "created_at": "2026-07-10T04:20:39Z", "event_date": null, "is_superseded": false}
 ]}

list_all_memories

Percorra todas as memórias sem gerenciar o cursor, ou traga o armazenamento inteiro de uma vez.

let all = mem.list_all_memories("alice").await?;   // every page, collected

Excluir

delete ✓ live-tested

Exclui uma única memória pelo id.

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

delete_all ✓ live-tested

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

mem.delete_all("alice").await?;
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.

use wontopos::ErrorKind;
match mem.search("...", "alice", 10).await {
    Ok(hits) => { /* use hits */ }
    Err(e) if e.kind() == ErrorKind::NotFound => { mem.create_store("alice").await?; }
    Err(e) if e.is_rate_limited() => { /* back off */ }
    Err(e) => return Err(e),
}

rate_limit

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

mem.search("...", "alice", 10).await?;
let rl = mem.rate_limit();   // Some(RateLimit { remaining: Some(3), .. })
curl

curl - sem instalação, os mesmos métodos.

Nenhum SDK para instalar - qualquer cliente HTTP funciona. Defina sua chave uma vez e chame os mesmos endpoints que os SDKs encapsulam. URL base https://api.wontopos.com, autenticação via X-API-Key, JSON na entrada e na saída.

# set your key once (never hard-code it)
export WOS_API_KEY="wos-live-..."

Escrever

store ✓ live-tested

Armazena uma memória. Embeddings gerados na entrada - sem chamada de 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"}'
Resposta real
{"id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "stored (1 chunks)"}

store-turn ✓ live-tested

Armazena um turno de conversa (usuário + assistente) na memória de curto e de longo prazo de uma só 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!"}'
Resposta real
{"status": "ok"}

speaker ✓ live-tested

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.

curl -X POST https://api.wontopos.com/api/v1/memory/speakers \
  -H "X-API-Key: $WOS_API_KEY" -H "Content-Type: application/json" \
  -d '{"user_id":"alice","speaker":"Bob"}'   # once per person

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":"I promised to send the report on Friday","metadata":{"speaker":"me"}}'

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":"Bob said the deadline moved to Tuesday","metadata":{"speaker":"Bob"}}'

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 did Bob say about deadlines?","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.

supersede ✓ live-tested

Um fato mudou - a memória antiga é marcada como substituída, a nova toma o lugar dela no 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"}'
Resposta real
{"new_memory_id": "07e94433-...", "old_memory_id": "576700aa-...", "status": "superseded"}

Ler

search ✓ live-tested

Busca semântica, os mais relevantes primeiro. Puramente embeddings - qualquer idioma encontra qualquer memória.

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}'
Resposta real
{"memories": [{"id": "576700aa-...", "content": "she prefers tea over coffee",
   "similarity": 0.63, "is_superseded": false}], "search_ms": 315, "total_found": 1}

recall ✓ live-tested

Uma única ida e volta retorna curto prazo + longo prazo + contexto + uma instrução. Cole direto no seu 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?"}'
Resposta real (formato)
{"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..."}

Excluir

forget ✓ live-tested

Exclui uma memória pelo id, ou omita-o para excluir tudo de um usuário (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
Resposta real
{"memories_deleted": 1, "status": "deleted", "user_id": "alice"}

Todos os endpoints + campos do corpo →

Engrams

Engrams

Ferramentas de recall invocáveis pelo seu modelo - cada uma é uma estratégia de recuperação diferente sobre a mesma memória. Use uma, ou execute várias ao mesmo tempo.

Já disponível. Os engrams gerais abaixo são pipelines de recuperação sem LLM, então rodam em todos os níveis a partir do Tablet 1. Memoir e Archive, um modo de modelo separado, são cobertos em sua própria seção abaixo.

Novos engrams são lançados regularmente - esta lista cresce.

Memoir & Archive Scroll 1.2+

Esta é uma forma de entrega, não uma ferramenta invocável. No Scroll 1.2 e superiores, escolha por chamada - form: "memoir" ou form: "archive" - e esse recall, incluindo uma busca simples, volta com o tempo escrito dessa forma.

Todos os engrams Engrams

Time_awareness Scroll 1.2+

Uma forma de entrega - escolhida por chamada. Passe form - memoir ou archive - em qualquer chamada de um modelo compatível (Scroll 1.2 e superiores), e a resposta volta renderizada dessa forma: uma busca simples, um recall ou qualquer engram. Nos SDKs é um campo form, como tz; via HTTP é o cabeçalho X-WOS-Form. Um Memoir se lê do jeito que uma pessoa lembra; um Archive mantém um registro exato - a diferença aparece principalmente em como cada um escreve o tempo.

Memoir

form: "memoir"
Lembrado como uma pessoa · uma narrativa

Conta o que aconteceu e como um momento levou ao seguinte, com a noção suave de tempo que uma pessoa recorda - lido como experiência, não como uma lista.

Archive

form: "archive"
Mantido como registro · tempo preciso

Retorna as correspondências como registros exatos - tempo decorrido preciso e âncoras absolutas, estruturados para um modelo ler diretamente.

Ele renderiza memórias que você já armazenou - não as cria. Cada memória é uma chamada store / add sob um user_id (esse user_id é o store daquela pessoa). Armazene primeiro; depois qualquer recall - incluindo a busca simples abaixo - volta com marcação de tempo. Veja o Início rápido para armazenar.
# plain search - no engram - the memoir form on Scroll 1.2
r = mem.search("what does Alice drink?", user_id="alice", model="scroll-1.2", form="memoir", tz=9)
# every hit gets a .time field → "a couple weeks ago"  (form="archive" → "2 weeks ago (Jun 09)")
// plain search - no engram - the memoir form on Scroll 1.2
const r = await mem.withModel("scroll-1.2").search("what does Alice drink?", "alice", 10, { form: "memoir", tz: 9 });
// search_with merges extra fields into the body - form picks the render, tz the local clock
let r = mem.with_model("scroll-1.2").search_with("what does Alice drink?", "alice", 10, json!({"form": "memoir", "tz": 9})).await?;
curl -X POST https://api.wontopos.com/api/v1/memory/search \
  -H "X-API-Key: wos-live-..." -H "X-WOS-Model: scroll-1.2" -H "X-WOS-Form: memoir" -H "X-WOS-Timezone: 9" \
  -d '{"user_id":"alice","query":"what does Alice drink?"}'
# each memory comes back with a "time" field; use X-WOS-Form: archive for exact time

tz é o deslocamento UTC de quem chama, em horas - assim, "esta manhã" e o limite de dia às 4h caem no horário local deles. Omita para UTC; via HTTP, é o cabeçalho X-WOS-Timezone. Aproximadamente, por região: Leste dos EUA -5, Centro dos EUA -6, Oeste dos EUA -8 · Reino Unido / Lisboa 0 · Europa Central +1 · Europa Oriental +2 · Índia +5.5 · China / Cingapura +8 · Coreia / Japão +9 · Sydney +10. (Horário padrão - o horário de verão desloca algumas regiões em +1; passe o que os seus usuários estiverem realmente usando.)

A mesma busca, duas formas - as memórias são idênticas, apenas o time muda:

Resultado · form: memoir
{ "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" }
] }
Resultado · form: archive
{ "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)" }
] }
DecorridoMemoirArchive
3 mina few minutes ago3 minutes ago
14 minabout 15 minutes ago14 minutes ago
30 minhalf an hour ago30 minutes ago
50 minabout an hour ago50 minutes ago
2 ha couple hours ago2 hours ago, at 13:10
8 hthis morning8 hours ago, at 07:10
ontem à tardeyesterday afternoonyesterday at 14:00
ontem à noitelast night17 hours ago, at 22:00
2 diasa couple days ago2 days ago (Tue 15:10)
6 diasseveral days ago6 days ago (Fri 15:10)
9 diasabout a week agolast week (Jun 16)
16 diasa couple weeks ago2 weeks ago (Jun 09)
35 diasabout a month agolast month (May 21)
60 diasa couple months ago2 months ago (Apr 2026)
180 diasabout half a year ago6 months ago (Dec 2025)
380 diasabout a year agolast year (Jun 2025)
800 diasa couple years ago2 years ago (Apr 2024)
1500 diasabout 4 years ago4 years ago (May 2022)

Todos os valores acima são a saída real do renderizador. Observe as duas linhas de "ontem": um Memoir separa a tarde da noite anterior - um dia é um sono - enquanto um Archive escreve um único horário de relógio e não traça linha entre dia e noite.

Como cada modo lê o tempo

Memoir - do jeito que as pessoas realmente falam. Momentos recentes permanecem razoavelmente nítidos (uns 15 minutos, meia hora), e depois a formulação vai se alargando quanto mais para trás se vai - algumas semanas, cerca de meio ano, uns dois anos - do mesmo jeito que a própria memória se afrouxa com a distância. Dentro de um dia, ele troca o relógio por um marco: esta manhã, ontem à noite, ontem à tarde. E um dia é um sono, não um tique de calendário: o limite fica por volta das 4h no horário local, então uma madrugada ainda é lida como a mesma noite, não como o dia seguinte.

Archive - preciso, sempre com uma âncora. Cada linha traz o tempo decorrido exato mais uma referência absoluta a partir da qual um modelo pode calcular, e a âncora fica mais precisa conforme se aproxima do presente: um horário de relógio para hoje (8 horas atrás, às 07:10), um dia da semana e horário nesta semana (2 dias atrás (ter 15:10)), uma data neste mês (semana passada (16 jun)), um mês e ano além disso (6 meses atrás (dez 2025)). Nunca vago, nunca errado.

Memoir e Archive renderizam todo recall da resposta - uma busca simples, um recall ou um engram. O nível do modelo (Tablet → Scroll → Codex) define quanto o motor faz; a forma (memoir / archive) define como ele escreve o tempo. Disponível no Scroll 1.2 e superiores.
Todos os engrams Engrams

deep_recall

Recall multi-hop. Busca a sua consulta, depois pega a melhor correspondência e busca de novo sobre o conteúdo dela - trazendo contexto vinculado que uma busca única deixaria passar. Ideal quando as memórias referenciam umas às outras (uma pessoa → seus projetos → detalhes). Retorna até ~12.

out = mem.engram("deep_recall", "what should I know about Alice?", user_id="alice")
const out = await mem.engram("deep_recall", "what should I know about Alice?", "alice");
let out = mem.engram("deep_recall", "what should I know about Alice?", "alice").await?;
curl -X POST https://api.wontopos.com/api/v1/engram/run \
  -H "X-API-Key: wos-live-..." -H "Content-Type: application/json" \
  -d '{"name":"deep_recall","user_id":"alice","query":"what should I know about Alice?"}'
Resposta
{ "engram": "deep_recall", "hops": 2, "count": 12,
  "memories": [ ... ],
  "usage": { "input_tokens": 5, "output_tokens": 61 } }
Medido em tokens - toda chamada retorna usage (entrada + saída), contado pelo mesmo tokenizador do restante da API; sem taxa oculta por engram. Precisa de vários de uma vez? Chame-os simultaneamente - cada engram é uma requisição independente.
Todos os engrams Engrams

timeline

Recall em ordem temporal. Retorna memórias ordenadas do mais recente para o mais antigo por quando o evento aconteceu, não por relevância. Para perguntas de "quando foi X", histórico e sequência. Retorna até 15.

events = mem.engram("timeline", "project milestones", user_id="alice")
const events = await mem.engram("timeline", "project milestones", "alice");
let events = mem.engram("timeline", "project milestones", "alice").await?;
curl -X POST https://api.wontopos.com/api/v1/engram/run \
  -H "X-API-Key: wos-live-..." -H "Content-Type: application/json" \
  -d '{"name":"timeline","user_id":"alice","query":"project milestones"}'
Resposta
{ "engram": "timeline", "hops": 1, "count": 15,
  "memories": [ ... ],
  "usage": { "input_tokens": 4, "output_tokens": 88 } }
Medido em tokens - toda chamada retorna usage (entrada + saída), contado pelo mesmo tokenizador do restante da API; sem taxa oculta por engram. Precisa de vários de uma vez? Chame-os simultaneamente - cada engram é uma requisição independente.
Todos os engrams Engrams

gather

Coleta ampla. Busca e depois expande ao redor das três melhores correspondências - uma rede mais ampla que o deep_recall. Use-o para trazer tudo relacionado a uma pessoa, projeto ou tópico em uma única chamada. Retorna até ~18.

related = mem.engram("gather", "everything about Project Atlas", user_id="alice")
const related = await mem.engram("gather", "everything about Project Atlas", "alice");
let related = mem.engram("gather", "everything about Project Atlas", "alice").await?;
curl -X POST https://api.wontopos.com/api/v1/engram/run \
  -H "X-API-Key: wos-live-..." -H "Content-Type: application/json" \
  -d '{"name":"gather","user_id":"alice","query":"everything about Project Atlas"}'
Resposta
{ "engram": "gather", "hops": 4, "count": 18,
  "memories": [ ... ],
  "usage": { "input_tokens": 6, "output_tokens": 142 } }
Medido em tokens - toda chamada retorna usage (entrada + saída), contado pelo mesmo tokenizador do restante da API; sem taxa oculta por engram. Precisa de vários de uma vez? Chame-os simultaneamente - cada engram é uma requisição independente.
API HTTP

Todos os endpoints, uma única URL base.

Nenhum SDK necessário - qualquer cliente HTTP funciona. URL base https://api.wontopos.com, autenticação via o cabeçalho X-API-Key, JSON na entrada e na saída. As operações de memória são POST; gerenciar stores usa POST / GET / DELETE em /collection. Um store precisa existir primeiro (veja Stores), ou as operações dentro do store retornam 404.

EndpointFinalidadeCampos do corpo
POST /api/v1/memory/collectioncriar um storeuser_id
GET /api/v1/memory/collectionslistar seus stores(nenhum)
DELETE /api/v1/memory/collectionexcluir um store + suas memóriasuser_id
/api/v1/memory/storearmazenar uma memóriauser_id · content · metadata? (speaker)
/api/v1/memory/store-turnarmazenar um turno de conversauser_id · user_msg · assistant_msg
POST /api/v1/memory/speakersregistrar um falante (explícito, até 50)user_id · speaker
GET /api/v1/memory/speakerslistar falantes registrados + contagensuser_id
DELETE /api/v1/memory/speakersremover um falante (memórias ficam)user_id · speaker
/api/v1/memory/bulk-storebackfill de um bloco de textouser_id · content · category?
/api/v1/memory/searchbusca semânticauser_id · query · max_results? · speaker?
/api/v1/memory/recallcurto + longo + contextouser_id · query
/api/v1/memory/historyturnos recentesuser_id
/api/v1/memory/statscontagens de memóriasuser_id
/api/v1/memory/supersedesubstituir um fato que mudouuser_id · old_memory_id · new_content
/api/v1/memory/forgetexcluir uma (ou todas)user_id · memory_id? (omitir = excluir tudo)
# 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?"}'
Resposta real - store
{"id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "stored (1 chunks)"}
Níveis de uso

Os mesmos recursos para todos.
Os níveis só aumentam seus limites.

Todo nível executa o motor completo - mesma qualidade de recall, mesmos idiomas, todos os métodos. Os níveis avançam automaticamente até o Nível 5 conforme suas compras acumuladas de créditos crescem, sem solicitação nem contato com vendas. Enterprise (Nível 6) é a única exceção.

Limites de gasto

Cada nível limita quanto você pode gastar por mês-calendário. Você avança imediatamente quando suas compras acumuladas de créditos atingem o próximo patamar.

Nível de usoCompra de créditosLimite mensal de gasto
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 - EnterpriseFale conoscoSem limite

Limites de requisições

Os limites de requisições são por conta - todas as chaves de API de uma conta compartilham um mesmo limite, que escala com o seu nível. Excedê-lo retorna um 429 com um cabeçalho retry-after; recue (1s → 2s → 4s) e tente novamente. Todos os endpoints são compatíveis com idempotência, então repetir requisições é seguro.

NívelRequisições por minuto
Tier 1150
Tier 2300
Tier 3600
Tier 41,500
Tier 53,000
Tier 6 - EnterprisePersonalizado

O Enterprise (Nível 6) recebe limites de requisições personalizados, um SLA, suporte dedicado e uma licença opcional de self-host - fale conosco.

O preço é baseado no uso: tokens mais uma taxa fixa de $0.0001 por requisição. O Tablet custa $2 por 1M de tokens de entrada, $3 por 1M de saída. O armazenamento é gratuito e sem limites. Veja por que precificamos desta forma.
Erros & limites

Quando algo dá errado.

Os erros retornam como um envelope JSON com um type estável, uma mensagem legível e um request_id que você pode nos enviar ao relatar um problema.

Resposta real - chave inválida (HTTP 401)
{"type": "error", "error": {
   "type": "authentication_error",
   "message": "Invalid or revoked API key.",
   "request_id": "063f8b83-eee2-4383-a5cf-11e4bcd29d7c"
 }}
HTTPSignificadoO que fazer
401Chave de API inválida ou revogadaVerifique a chave; emita uma nova no console.
422Corpo malformado (campo ausente ou de tipo errado)A mensagem indica o campo exato - corrija e tente novamente.
429Limite de requisições excedidoRecue exponencialmente (1s → 2s → 4s) e tente novamente. Seguro: todos os endpoints são compatíveis com idempotência.
5xxProblema no servidorTente novamente com recuo; inclua o request_id se entrar em contato conosco.
# 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
Segurança da chave. Sua chave é exibida uma única vez na criação e armazenada apenas como hash do nosso lado. Guarde-a em uma variável de ambiente; se vazar, revogue-a no console - a revogação é imediata.

Os limites de requisições são por conta, compartilhados entre todas as suas chaves, e escalam com o seu nível - veja Níveis de uso. O uso da sua conta é exibido no console.

Self-host

Seus servidores, seus dados.

O motor pode rodar dentro da sua própria infraestrutura - mesma API, mesmos SDKs. Aponte o cliente para o seu host e nada mais muda.

mem = Client(api_key="...", base_url="https://wos.your-host.com")
const mem = new Client({ apiKey: "...", baseUrl: "https://wos.your-host.com" });
let mem = Client::with_base_url("...", "https://wos.your-host.com");
  • Residência de dados. As memórias nunca saem da sua rede.
  • Mesma superfície. Os mesmos métodos e endpoints funcionam de forma idêntica.
  • Licenciamento. Os pacotes de self-host são negociados por implantação - entre em contato.
Escala

Além da janela de contexto.

O WOS recupera de históricos de 1.4M tokens - muito maiores que qualquer janela de contexto de LLM - e ainda assim devolve uma fatia enxuta de ~1,470 tokens.

A memória do seu agente não é limitada pelo que cabe em um prompt. Ela guarda tudo e recupera apenas o que importa, não importa o quanto o histórico cresça.

Privacidade

Privado, e seu.

Seus dados permanecem no seu store. Nunca treinamos com eles, os visualizamos ou os reutilizamos - apenas os organizamos para que você possa recuperá-los.

  • BYOK. Sua chave de LLM é enviada a cada requisição e nunca armazenada.
  • Isolado. As memórias têm escopo por conta e, depois, por user_id.
  • Exclusão GDPR & self-host. Uma única chamada apaga um usuário; execute o motor no seu próprio ambiente, se preferir.