Une mémoire à long terme pour les agents IA.
WOS est une API de mémoire. Vous stockez une fois les souvenirs d'un utilisateur, puis ne rappelez que ceux qui sont pertinents pour chaque requête et les transmettez au prompt de votre modèle.
La récupération est purement sémantique, sans correspondance par mots-clés ni BM25 : la qualité du rappel est donc identique d'une langue à l'autre. Chaque requête renvoie un contexte réduit et borné, quel que soit le volume stocké, et aucun modèle n'est jamais exécuté sur vos souvenirs stockés.
Opérations de base
store- enregistre un souvenir pour un utilisateur.recall- récupère les souvenirs pertinents pour une requête. C'est l'appel principal.search- recherche sémantique brute sur les souvenirs stockés.supersede- met à jour ou remplace un souvenir devenu obsolète.forget- supprime un souvenir unique ou un utilisateur entier (RGPD).
Trois modèles, une même lignée.
Les modèles WOS portent le nom des supports par lesquels l'humanité a conservé le savoir au fil de l'histoire - Tablet, Scroll, Codex. La pierre, le rouleau, le livre relié : chacun apporte davantage à votre agent que le précédent.
Tablet
DisponibleUn moyen sobre, rapide et économique d'inscrire et de rappeler la mémoire - la fondation sur laquelle chaque modèle s'appuie.
Scroll
DisponibleAjoute un modèle de langage qui lit votre question de plus près et ramène un contexte plus complet, pour que les indices dispersés reviennent ensemble au lieu qu'il en manque un.
Codex
À venirS'ouvre de lui-même à la bonne page - il choisit la mémoire et les outils dont chaque instant a besoin, et s'affine à mesure qu'on l'utilise.
Le rapport de benchmark complet de Tablet 1 se trouve sur la page benchmark.
Payez-nous $2. Économisez plusieurs fois ce montant sur votre LLM.
WOS fournit à votre LLM ~1,200 tokens par requête - une tranche bornée et pertinente - au lieu d'entasser l'historique complet dans chaque prompt. L'écart est énorme, et il grandit avec votre historique.
Chaque $1 dépensé sur WOS fait économiser ~$98 sur le LLM. Un historique plus grand ou un modèle plus cher → un ROI plus grand.
D'où viennent les économies
- Sans WOS, vous entassez l'historique entier dans chaque prompt -
100K tokens × $2.50/1M = $0.25par requête, au tarif d'entrée de GPT-4o (environ 2× plus sur les modèles de classe Opus). - Avec WOS, vous ingérez une fois (
$2/1M), puis chaque requête n'est qu'une petite récupération ($3/1M × 1,200) plus votre LLM sur seulement ~1,200 tokens. - Moins votre LLM lit de tokens, moins vous payez - et WOS garde ce nombre constant à mesure que la mémoire grandit.
Toutes les langues, la même précision.
La récupération est purement sémantique - embeddings uniquement, zéro correspondance par mots-clés ou BM25. La qualité du rappel est donc identique que vos utilisateurs écrivent en 日本語, en 中文, en Español ou en anglais.
La correspondance lexicale comme BM25 est calibrée sur la forme d'une langue donnée - morphologie, espacement, écriture. Dans un store multilingue, la qualité de récupération varie alors selon la langue. WOS n'utilise aucune correspondance lexicale : toutes les langues empruntent le même chemin.
Un seul store, trois langues à la fois
Vous ne choisissez pas une langue par store - mélangez-les librement. Ci-dessous, la mémoire d'un même utilisateur contient à la fois du japonais, de l'anglais et de l'espagnol, et chaque question retrouve le bon souvenir quelle que soit la langue. Il s'agit d'un échange réel avec l'API en production :
# one user, three languages stored together mem.add("彼女はコーヒーより紅茶が好き", user_id="alice") # Japanese mem.add("she works at a design studio in Brooklyn", user_id="alice") # English mem.add("A ella le encanta hacer senderismo los sábados", user_id="alice") # Spanish
"¿Qué bebe ella?" -> 彼女はコーヒーより紅茶が好き "what does she do on weekends?" -> A ella le encanta hacer senderismo los sábados "彼女の仕事は?" -> she works at a design studio in Brooklyn
Aucune étape de traduction, aucune détection de langue, aucune configuration par langue. Souvenirs et questions sont placés selon le sens, pas selon la langue - si le sens correspond, la langue n'a pas d'importance.
Pourquoi nous avons banni les mots-clés à dessein
Un scoring lexical tel que BM25 renforce la récupération pour certaines langues plus que pour d'autres, ce qui pose problème quand un même store contient de nombreuses langues. Nous l'avons donc entièrement retiré du moteur et faisons respecter cette règle en revue de code : avec le moindre scoring lexical dans le chemin, la qualité du rappel varierait selon la langue.
Aucun modèle ne s'exécute sur vos souvenirs.
Le stockage est verbatim et le moteur cherche par embeddings - économique, rapide et déterministe. Un modèle n'est jamais exécuté sur vos souvenirs stockés. Tablet n'utilise aucun modèle ; Scroll et Codex en ajoutent un autour du moteur pour de meilleurs résultats, mais il ne voit jamais que votre requête, jamais ce que vous avez stocké.
- Moteur déterministe. Le moteur renvoie les mêmes souvenirs pour la même requête, à chaque fois - c'est pourquoi la variance de notre benchmark provient uniquement du modèle lecteur.
- Économique à grande échelle. Aucun coût de génération pour stocker ou récupérer : votre facture suit le stockage - pas l'usage de modèle - à mesure que la mémoire grandit.
Vos mots, intacts
Une conception courante exécute un modèle de langage à l'écriture pour extraire et réécrire des « faits » à partir du texte. Cette conception sacrifie trois choses : un coût de génération à chaque écriture, une latence supplémentaire, et le stockage d'une paraphrase du modèle plutôt que des mots d'origine. WOS fait le choix inverse - il stocke ce qui a été dit, sans modification, et laisse votre LLM interpréter à la lecture, le texte original en main.
90.7%, mesuré et reproductible.
90.7% sur LongMemEval-S, en moyenne sur 5 runs indépendants (σ 0.5%, aucun trié sur le volet), noté par le juge canonique GPT-4o du benchmark.
Sur le même benchmark, les scores varient fortement selon le protocole de notation - le juge, le prompt, et ce que la couche de récupération est autorisée à faire. Nous utilisons le juge tiers canonique GPT-4o du benchmark tel que publié, ne modifions rien pour coller au test, et publions le code de notation et le prompt du lecteur pour que chacun puisse reproduire exactement les 90.7%.
Le protocole, en un tableau
| Élément | Ce que nous faisons |
|---|---|
| Jeu de données | LongMemEval-S (nettoyé), ~240K tokens d'historique par question |
| Juge | Le juge canonique GPT-4o du benchmark - un tiers, pas nous |
| Runs | 5 runs indépendants, chaque score publié, moyenne rapportée (σ 0.5%) |
| Lecteur | Modèle lecteur et prompt fixes, publiés verbatim |
Ce qui garantit l'honnêteté : un juge tiers, le prompt du lecteur publié tel quel, une récupération purement sémantique, et chaque run rapporté - pas seulement le meilleur. Le moteur de récupération est déterministe - relancez-le et vous obtenez les mêmes souvenirs.
Nous gravissons des benchmarks plus difficiles
Nous testons sur le benchmark standard le plus difficile que nous n'avons pas encore conquis - et le chiffre affiché est le record parmi tous les modèles WOS, réécrit chaque fois qu'un meilleur modèle sort. Passé 94%, nous passons à un benchmark plus difficile.
Deux tarifs de tokens par modèle,
plus $0.0001 par requête.
Par million de tokens plus $0.0001 fixe par requête, à l'usage. Pas d'abonnement, pas de loyer de stockage, pas de plafond de mémoire. Vous payez quand votre agent écrit ou lit - jamais pour ce qu'il retient.
| Modèle | Entrée / 1M | Sortie / 1M | |
|---|---|---|---|
| Tablet 1 | $2 | $3 | Disponible |
| Scroll 1 | $4 | $8 | Disponible |
| Codex 1 | - | - | À définir |
- $0.0001 par requête. Des frais fixes sur chaque appel API, en plus de l'usage en tokens.
- Le stockage est gratuit. L'ingestion se paie une fois ; la conservation ne coûte rien. Aucune limite de nombre, aucune limite de rétention.
- Nous le stockons. Nous ne nous entraînons jamais dessus, ne l'utilisons jamais et ne le regardons jamais. La mémoire de votre agent vous appartient - nous ne faisons que l'organiser pour que vous puissiez la retrouver.
- Pourquoi Tablet est si peu cher : son moteur n'exécute aucun modèle, notre coût se limite donc aux embeddings et au disque - pas aux GPU. Scroll et Codex ajoutent un modèle, et c'est ce que couvre leur prix plus élevé.
Trois appels : store, recall, answer.
Une seule API. L'appel recall() renvoie le court terme, le long terme et le contexte environnant en un seul aller-retour, prêt à être inséré dans votre prompt.
Store
add() enregistre faits et échanges : les mots de votre utilisateur, ceux de l'assistant (speaker "me") ou ceux d'une personne nommée. Encodé à l'entrée, sans appel LLM.
Recall
recall() renvoie court terme + long terme + contexte en un seul appel - un contexte borné, de taille fixe.
Answer
Fournissez ce contexte borné à votre LLM - n'importe quel fournisseur, votre clé.
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")
Les souvenirs portent un locuteur. Par défaut ce sont les mots de votre utilisateur, speaker "me" enregistre ce que l'assistant a dit lui-même, et un nom comme "Bob" retient qui l'a dit, pour se souvenir par personne.
Votre premier recall en 5 minutes.
Une clé, une ligne d'installation, trois appels - votre agent a de la mémoire. Chaque extrait de cette page a réellement été exécuté ; les réponses sont montrées verbatim.
Obtenir une clé API
Créez-en une dans la console. Une clé de 155 caractères commençant par wos-live- est affichée une seule fois. Gardez-la dans une variable d'environnement - jamais dans le code.
Installation
pip install wontopos # Python npm install wontopos # TypeScript / JavaScript cargo add wontopos # Rust # curl - nothing to install, just set WOS_API_KEY
Créez un store, puis store & recall
Un store est le user_id sous lequel vous lisez et écrivez. Les stores sont explicites : créez-en un d'abord (l'appel ci-dessous), puis stockez et rappelez sous celui-ci. Store - encodé en embeddings à l'entrée, aucun appel LLM. Recall - court terme + long terme + contexte en un seul aller-retour.
from wontopos import Client
mem = Client(api_key="wos-live-...", user_id="alice") # set the store once
mem.create_store() # create it (stores are explicit)
mem.add("she prefers tea over coffee") # no user_id needed
# one call → short-term + long-term + context
ctx = mem.recall("what does alice drink?"){"user_id": "alice", "status": "created"}{"id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "stored (1 chunks)"}user_id au client et chaque appel l'utilise - inutile de le répéter ; surchargez un appel isolé en lui passant user_id. Les stores sont explicites : stocker dans un store inexistant ou rappeler depuis celui-ci renvoie 404 - créez-le d'abord. Chaque compte démarre avec un store default : sans aucun user_id, le chemin zéro configuration fonctionne donc tel quel. Voir Stores pour les lister et les gérer.recall() renvoie quatre blocs - short_term (tours récents), long_term (souvenirs pertinents), context (ce qui entourait la meilleure correspondance) et une instruction indiquant au LLM comment les utiliser. Insérez l'ensemble tel quel dans votre prompt.
Stores - créer, lister, supprimer.
Un store est le user_id sous lequel vous lisez et écrivez - un espace mémoire isolé par utilisateur final, agent ou sujet. Les stores sont explicites : créez-en un avant d'y stocker ou d'y rappeler, sinon l'appel renvoie 404. Chaque compte démarre avec un store default, vous pouvez donc commencer sans appel de création.
mem.create_store("alice") # create (idempotent)
mem.list_stores() # [{"user_id","created_at"}, ...]
mem.delete_store("alice") # delete the store + all its memories{ "user_id": "alice", "status": "created" } // "exists" if it already did{ "collections": [
{ "user_id": "default", "created_at": "2026-06-26T02:23:14Z" },
{ "user_id": "alice", "created_at": "2026-06-26T02:24:01Z" }
], "count": 2 }{ "error": { "type": "not_found_error",
"message": "Store 'ghost' does not exist. Create it first with
POST /api/v1/memory/collection {\"user_id\":\"ghost\"}, then store or recall." } }"alice", "user_42") pour garder la mémoire de chaque personne séparée, ou un unique store default pour un agent personnel. Vous pouvez aussi créer et parcourir les stores dans la console (Memory ids → Issue) sans écrire de code. La suppression d'un store est définitive - elle efface tous les souvenirs qu'il contient.Les rappels répétés, au dixième du prix.
Activez-le par requête et WOS met en cache le résultat de recherche sous le texte de la requête, avec les mêmes règles de préfixe que le prompt caching des LLM. Tant que le cache est chaud, une requête répétée ou prolongée réutilise le résultat précédent, et la partie en cache est facturée à 10% du tarif normal par token.
Une conversation, trois tours
Voici ce qui se passe réellement quand un agent continue de parler à sa mémoire. À chaque tour, la conversation accumulée est envoyée comme requête, avec cache_control activé.
La requête complète est recherchée et mise en cache : entrée à 2x (TTL de 5 minutes).
Seule la phrase de Bob est encodée et recherchée. L’ancienne partie coûte 0,1x, la nouvelle phrase 2x, et le cache se termine désormais sur elle.
Aucun appel au moteur. Tout à 0,1x : la remise de 90%.
Les tarifs
| Opération | Facturation des tokens | Signification |
|---|---|---|
| Écriture du cache - TTL 5 minutes | 2× | La première requête. Son résultat est conservé 5 minutes, et chaque lecture fait glisser la fenêtre vers l’avant. |
| Écriture du cache - TTL 1 heure | 3× | La première requête, conservée pendant une heure entière. |
| Lecture du cache - hit ou hit de préfixe | 0.1× | Chaque requête après l’écriture : la partie en cache coûte un dixième du tarif normal par token. |
Ce que ça économise
Un exemple concret : votre agent envoie une conversation de 3 000 tokens comme requête et la répète ou la prolonge 10 fois en cinq minutes. Sans cache, cela fait 30 000 tokens d’entrée au plein tarif. Avec un cache de 5 minutes, c’est 6 000 pour la première écriture (2x) plus environ 2 700 pour les neuf lectures en cache : 8 700 tokens facturés, 71% de moins. Plus la conversation dure, plus l’économie grandit.
La règle du préfixe
La correspondance se fait sur le début de la requête. Si le début reste identique et que du nouveau texte est seulement ajouté à la fin, la partie en cache est réutilisée et seule la nouvelle partie est recherchée. Si quelque chose change avant la fin du texte en cache, rien ne peut être réutilisé.
cached [ A B C D E F G ] ○ [ A B C D E F G ] E ✗ [ B C D E F G ] E
○ hit - le début est inchangé, E est la seule partie nouvelle
✗ miss - le début a changé, toute la requête est donc recherchée et mise en cache à nouveau
Trois règles à retenir
- Prolonger remet en cache jusqu’à la nouvelle fin. Après [A B C D E F G] + E, le cache se termine désormais à E : la fin est facturée une fois au tarif d’écriture, et le tour suivant peut de nouveau faire correspondre tout A..E comme préfixe.
- Un seul préfixe contigu par requête. Une requête ne peut pas être découpée en deux segments de cache ; seul son début peut correspondre.
- Les écritures invalident instantanément. Tout store, store-turn, bulk-store, forget, supersede ou suppression du store jette son cache : une réponse en cache ne peut jamais être périmée.
Comment l’activer
hits = mem.search(
"...the conversation so far...", user_id="alice",
cache_control={"ttl": "5m"}, # or "1h"
){ "memories": [ ... ],
"cache": { "status": "hit", // "write" | "hit" | "extend"
"ttl": "5m",
"cache_read_input_tokens": 412,
"cache_creation_input_tokens": 0 } }Aucun SDK n'est nécessaire pour tout cela. Le caching est un champ sur un appel HTTP, il fonctionne donc depuis n'importe quel langage de programmation. L'onglet curl est la recette universelle, et les SDK Python, TypeScript et Rust ne sont que des enrobages pratiques du même appel.
Une mémoire qui sait qui l'a dit.
On se souvient par personne : ce que Bob a promis, ce que vous avez dit que vous feriez. Étiquetez chaque souvenir avec un locuteur et votre agent fait pareil, sur tous les modèles Tablet et Scroll.
Une équipe, trois souvenirs
Un magasin garde les voix séparées. Enregistrez une personne une fois, sauvegardez chaque propos sous son locuteur, puis demandez par personne.
Le magasin connaît désormais Bob. La limite de 50 se compte ici, à l'enregistrement ; les appels de stockage ne renvoient jamais d'erreur de limite.
Le souvenir appartient désormais à Bob : chaque recherche qui le renvoie l'indique.
Ses propres mots sont aussi mémorisés, et "me" ne compte jamais dans la limite.
Seuls les mots de Bob reviennent. Les mots d'une personne ne reviennent jamais comme ceux d'une autre.
Trois règles à retenir
- "me", c'est l'assistant lui-même. Jamais enregistré, jamais compté. Réservé et en minuscules :
speaker: "Me"ou"ME"renvoie400 invalid_request_errorau lieu d'être converti en silence. - La limite se compte à l'enregistrement : 50 par magasin pour commencer. Au-delà, l'enregistrement renvoie
400 invalid_request_erroravecspeaker_limit: 50dans le corps d'erreur. Stocker avec un nom non enregistré renvoie aussi400et ne stocke rien. Filtrer la recherche par un nom non enregistré renvoie404 not_found_error. Branchez sur le statut et les champs, pas sur le texte du message ; nous comptons relever la limite. - Les étiquettes vivent dans chaque lecture. Les résultats de recherche, le contexte long terme de recall et les résultats d'engram portent leur locuteur : le modèle sait toujours à qui appartiennent les mots qu'il tient. Passez speaker à une recherche pour n'obtenir que les mots d'une personne. Un supersede conserve le locuteur ; forget le supprime.
- Les noms sont en Unicode : toutes les langues fonctionnent. さくら, Иван et 하늘 sont des locuteurs valides, et l'attribution se comporte de la même façon dans toutes les langues. La correspondance est exacte après trim et normalisation Unicode :
Bobetbobsont deux personnes. Les noms vont jusqu'à 80 caractères.
# 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" } }
Deux notes de portée. speaker s'attache à add / store : add_turn mémorise l'échange entier, et les étiquettes par personne et le filtre viennent des souvenirs enregistrés avec un speaker explicite. Et les passages de session (expand) sont des composites de plusieurs souvenirs, donc sans étiquette ; un filtre speaker renvoie toujours des souvenirs atomiques et étiquetés. Et un contenu identique est dédupliqué vers le premier souvenir : ce store renvoie status "duplicate" avec une note explicite, sans locuteur attaché.
Nous testons cela à la dure : des souvenirs sans aucun nom dans le texte, rappelés par personne. L'attribution vient du registre des locuteurs, pas de la correspondance de mots, donc le comportement est identique dans toutes les langues.
L'utiliser
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{ "memories": [
{ "content": "Bob said the deadline moved to Tuesday",
"speaker": "Bob", ... } ] }{ "user_id": "alice",
"speakers": [ { "speaker": "Bob", "memories": 2, "created_at": "2026-07-10T04:20:39Z" } ],
"count": 1, "limit": 50 }La liste montre qui le magasin connaît, avec le nombre de souvenirs par personne face à la limite. Retirer n'efface que l'enregistrement : les souvenirs restent, seule l'étiquette part.
MCP : la mémoire pour les outils d'IA
Le cœur de WOS, c'est l'API et les SDK. Le serveur MCP est un module par-dessus : la même mémoire, branchée sur des outils que vous n'avez pas construits - Claude Code, Claude Desktop, Cursor.
Une ligne d'installation donne à l'agent neuf outils de mémoire qu'il utilise seul. Et comme la mémoire vit dans votre compte, ce qu'un outil écrit, tous les autres s'en souviennent - y compris les agents que vous construisez avec le SDK.
Ce que ça permet
- Un Claude Code qui se souvient de votre projet. Décisions, correctifs, préférences - rappelés à la session suivante sans rien réexpliquer.
- Commencez dans ChatGPT, continuez dans Claude. Même store, même mémoire : la conversation traverse les outils au lieu de repartir de zéro.
- Votre propre agent reste dans la boucle. Ce que Claude Code apprend, un agent SDK s'en souvient - et ce que votre agent stocke, Claude Code le rappelle en retour.
Fonctionne dans Claude Code, Claude Desktop, Cursor, Windsurf et tout hôte MCP. ChatGPT atteint la même mémoire via Actions plus la spec OpenAPI.
Installation
claude mcp add wontopos --env WONTOPOS_API_KEY=wos-live-... -- npx -y wontopos-mcpL'agent reçoit neuf outils - recall · remember · search · update · forget · list_memories · engram · stats · create_store - chacun décrit pour qu'il sache seul quand les utiliser.
Spec OpenAPI
La carte complète et lisible par machine de l'API : chaque endpoint, requête, réponse et erreur.
OpenAPI est le format standard de l'industrie pour décrire une API HTTP dans un fichier lisible par machine.
https://api.wontopos.com/openapi.jsonCe que ça permet
Postman : File → Import → collez l'URL, les 16 endpoints apparaissent en collection cliquable. ChatGPT : créez un GPT, ajoutez une Action, collez la même URL. Codegen : openapi-generator -i .../openapi.json -g go génère un client dans un langage que nous ne publions pas.
Importez-la dans Postman, générez un client dans un langage que nous ne publions pas, branchez ChatGPT Actions ou lancez des checks de contrat en CI. Un test l'épingle aux routes réelles : aucune dérive possible.
llms.txt
Toute l'API sur une page de texte qu'une IA peut lire.
llms.txt est une convention du web : une page en texte brut à la racine du site qui dit à une IA tout ce qu'elle doit savoir d'un produit.
https://wontopos.com/llms.txtDéposez-le dans votre IDE ou agent de code : il sait construire sur WOS - auth, endpoints, patterns, erreurs. Mis à jour à chaque release.
Les mêmes faits que la spec OpenAPI, un autre public : la spec est une structure précise pour les outils ; ce fichier est de la prose qu'une IA (ou une personne) lit d'une traite. Les deux se mettent à jour à chaque release.
Votre mémoire dans chaque outil d'IA
Une seule commande donne à Claude Code, Claude Desktop, Cursor ou tout hôte MCP une mémoire à long terme adossée à votre compte WOS. Aucun code d'intégration : l'agent reçoit neuf outils de mémoire et décide quand les utiliser.
Installation
Claude Code, une ligne (créez d'abord une clé dans la 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-projectAdd to Cursor → · Add to VS Code →
Env optionnel : WONTOPOS_USER_ID fixe le store par défaut, WONTOPOS_MODEL le moteur, WONTOPOS_BASE_URL un déploiement auto-hébergé. WONTOPOS_READ_ONLY=1 passe en lecture seule (recall/recherche/liste uniquement).
Avant de partager un store
- Utilisez une clé dédiée. Les clés portent leur workspace : une clé créée juste pour MCP borne ce que les outils connectés peuvent toucher - et vous pouvez la faire tourner dans la console sans toucher aux clés de votre app.
- Mode lecture seule.
WONTOPOS_READ_ONLY=1n'enregistre aucun outil d'écriture : l'agent peut rappeler, chercher, lister les mémoires, exécuter des engrams et lire les stats, mais ni stocker, ni mettre à jour, ni oublier, ni supprimer. Pour les agents qui doivent consulter la mémoire, pas la posséder. - Gardez la confirmation d'outils activée. Les hôtes MCP demandent avant d'exécuter un outil par défaut - gardez-la surtout pour
forget, car les suppressions sont partagées par tous les outils du store. - Tout ce qui est stocké est rappelable par chaque outil détenant la clé. Ne stockez jamais de secrets - clés d'API, mots de passe - comme mémoires.
- Les mémoires rappelées sont des données, pas des instructions. Les descriptions des outils le disent explicitement à l'agent. Malgré tout, ne stockez pas de texte tiers non fiable dans un store qu'un agent autonome suit.
- Les suppressions aussi sont partagées. Un forget ou delete_all depuis un outil efface pour tous.
- « me » désigne l'agent qui écrit dans le store. Si plusieurs agents partagent un store, leurs voix « me » se mélangent. Donnez à chaque agent son propre store (
WONTOPOS_USER_ID) pour des identités séparées. - Un seul compte paie. Tous les outils connectés puisent dans le même solde et la même limite de débit.
Ensuite, parlez simplement
L'agent appelle l'outil remember. Stocké durablement : la fin de la session ne change rien.
Une nouvelle session n'a aucun historique. L'agent appelle recall et répond de mémoire : le vendredi.
Ce que vous pouvez dire
- « Ce repo utilise pnpm, retiens-le » →
rememberle stocke ; la session suivante le sait déjà. - « Quel format d'erreur avait-on choisi la semaine dernière ? » →
recallramène la décision dans le contexte. - « En fait, la deadline est passée à vendredi » → l'agent voit que cela contredit ce qu'il a rappelé et appelle
updatepour corriger la mémoire sur place. - « C'est faux, oublie ça » → l'agent trouve l'id et appelle
forget- votre hôte demande confirmation d'abord. - « Que retiens-tu de moi ? » →
list_memoriesparcourt tout ce qui est stocké, pour que l'agent réponde ou fasse le ménage.
Rien de spécial à formuler : ce sont des phrases ordinaires, pas des commandes. L'agent lit la description de chaque outil et choisit seul.
Les neuf outils
recall- Le contexte en un appel : tours récents plus mémoires pertinentes. Sa description dit à l'agent de l'appeler en premier dès que le passé compte.remember- Stocke un fait ou une décision durable.speaker: "me"marque les mots de l'agent ; un nom enregistré, qui l'a dit.search- Recherche sémantique, avec filtre optionnel par personne (speaker).forget- Supprime une mémoire par id.speakers- Enregistre, liste ou retire les personnes qu'un store connaît.create_store- Les stores sont explicites : un par utilisateur final, projet ou agent.
SDK ou MCP ?
- Le SDK va dans une app que vous écrivez. Votre code décide exactement quand stocker et quoi rappeler - déterministe, typé, versionné. Vous construisez un produit ? SDK.
- MCP se branche sur un outil d'IA que vous n'avez pas écrit. L'agent décide quand utiliser la mémoire, guidé par les descriptions - zéro code. Pour Claude Code, Claude Desktop, Cursor, ou donner une mémoire à un assistant fini.
Dessous, la même API et les mêmes stores : une app bâtie sur le SDK et une session Claude Code via MCP partagent une seule mémoire. On choisit par surface, pas l'un ou l'autre.
Une mémoire à travers tous les outils
La mémoire appartient au compte, pas à l'outil. Le même store écrit depuis ChatGPT (Actions plus la spec OpenAPI) se rappelle dans Claude Code et dans vos propres agents, et inversement : une conversation commencée dans un outil continue dans un autre.
Et comme c'est un seul store, vous pouvez quitter Claude Code et continuer là où vous construisez : un agent SDK avec la même clé et le même store se souvient de tout ce que Claude Code vient d'apprendre - et ce que votre agent stocke, Claude Code s'en souvient à la session suivante.
npx wontopos-mcp) : votre clé reste dans votre environnement et ne transite par aucun serveur tiers. Il enveloppe le SDK TypeScript : retries automatiques, refus des redirections et masquage de la clé s'appliquent tels quels.Claude Code
La voie principale : une commande dans votre terminal et chaque session démarre avec la mémoire.
- Créez une clé d'API dans la console. La clé porte son workspace : une clé = un espace mémoire.
- Enregistrez le serveur.
--scope userle rend disponible dans tous les projets ; sans lui, seul le projet courant le voit. - Vérifiez : lancez
/mcpdans Claude Code -wontoposdoit apparaître avec neuf outils. - Rendez-le automatique : une ligne dans votre
CLAUDE.md- « quand le passé compte, appelle d'abord wontopos recall » - et chaque session démarre avec la mémoire sans qu'on le demande.
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-projectClaude Desktop
Ajoutez le bloc ci-dessous à claude_desktop_config.json (Réglages → Developer → Edit Config), relancez l'app : les neuf outils apparaissent. Note : claude.ai web et mobile exige un serveur MCP distant, que WOS n'offre pas encore - l'app de bureau est la voie supportée.
# claude_desktop_config.json
{ "mcpServers": {
"wontopos": {
"command": "npx",
"args": ["-y", "wontopos-mcp"],
"env": { "WONTOPOS_API_KEY": "wos-live-...",
"WONTOPOS_USER_ID": "my-project" }
} } }Cursor
Ajoutez le bloc ci-dessous à ~/.cursor/mcp.json - ou pressez le bouton en un clic - et relancez Cursor. L'agent récupère les neuf outils.
# ~/.cursor/mcp.json
{ "mcpServers": {
"wontopos": {
"command": "npx",
"args": ["-y", "wontopos-mcp"],
"env": { "WONTOPOS_API_KEY": "wos-live-...",
"WONTOPOS_USER_ID": "my-project" }
} } }VS Code
VS Code (mode agent Copilot) lit les serveurs MCP dans .vscode/mcp.json du projet : ajoutez le bloc ci-dessous ou pressez le bouton en un clic.
# .vscode/mcp.json
{ "servers": {
"wontopos": {
"command": "npx",
"args": ["-y", "wontopos-mcp"],
"env": { "WONTOPOS_API_KEY": "wos-live-...",
"WONTOPOS_USER_ID": "my-project" }
} } }Windsurf
Windsurf (Cascade) lit ~/.codeium/windsurf/mcp_config.json : ajoutez le bloc ci-dessous et rechargez - les neuf mêmes outils apparaissent.
# ~/.codeium/windsurf/mcp_config.json
{ "mcpServers": {
"wontopos": {
"command": "npx",
"args": ["-y", "wontopos-mcp"],
"env": { "WONTOPOS_API_KEY": "wos-live-...",
"WONTOPOS_USER_ID": "my-project" }
} } }ChatGPT
Les connecteurs MCP de ChatGPT n'acceptent que des serveurs distants ; la voie supportée aujourd'hui est un GPT personnalisé avec une Action : créez un GPT, ajoutez une Action, collez l'URL de la spec OpenAPI ci-dessous et mettez votre clé en en-tête d'auth. Ce GPT appellera la même mémoire que vos autres outils.
# GPT → Configure → Actions → Import from URL
https://api.wontopos.com/openapi.json
# Authentication: API Key · Header name: X-API-KeyMême store, même mémoire : ce que ChatGPT stocke via l'Action, Claude Code le rappelle via MCP - et inversement.
Gemini CLI
Gemini CLI lit les serveurs MCP dans ~/.gemini/settings.json : ajoutez le bloc ci-dessous, relancez la CLI et les neuf mêmes outils apparaissent là aussi.
# ~/.gemini/settings.json
{ "mcpServers": {
"wontopos": {
"command": "npx",
"args": ["-y", "wontopos-mcp"],
"env": { "WONTOPOS_API_KEY": "wos-live-...",
"WONTOPOS_USER_ID": "my-project" }
} } }Python - chaque méthode, en trois groupes.
Écrire, lire, supprimer. Chaque exemple ci-dessous a été exécuté contre l'API en production le 2026-07-10 ; les réponses sont verbatim.
pip install wontopos
from wontopos import Client mem = Client(api_key="wos-live-...") # or read from an env var
Choisir un modèle
La clé API détermine quelle mémoire (votre compte) ; le modèle détermine quel moteur la lit. Tous les modèles partagent une même mémoire : vous pouvez donc stocker avec l'un et rappeler avec un autre. Définissez un défaut sur le client ; surchargez un appel isolé en passant 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
Le catalogue - les ids que vous pouvez passer à model et la disponibilité de chacun. Les modèles memory: "shared" lisent le même store ; "isolated" garde le sien. Aucune clé API requise.
mem.list_models()[{"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
Vérifiez la connexion et que votre clé API fonctionne : un contrôle en une ligne.
mem.ping() # True, or raises AuthenticationError / PaymentRequiredError
Le catalogue ci-dessus reflète toujours les modèles disponibles à l'instant même - passez tout autre id et vous obtenez une erreur claire. Les nouveaux modèles y apparaissent automatiquement dès leur sortie.
Écrire
add ✓ live-tested
Stocke un souvenir. Encodé en embeddings à l'entrée - aucun appel LLM, vous ne payez que les 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
{"id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "stored (1 chunks)"}add_turn ✓ live-tested
Stocke un tour de conversation (utilisateur + assistant) à la fois en mémoire court terme et long terme.
mem.add_turn("hi", "hello!", user_id="alice")
{"status": "ok"}speaker ✓ live-tested
Chaque souvenir peut porter son locuteur. Enregistrez une personne une fois, puis passez son nom comme speaker ; "me" (les mots de l'assistant) n'a jamais besoin d'enregistrement. La recherche accepte aussi speaker, pour ne rappeler que les mots d'une personne.
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")
{"memories": [{"content": "Bob said the deadline moved to Tuesday", "speaker": "Bob", ...}]}add_bulk ✓ live-tested
Importe un gros bloc de texte. Découpé et encodé côté serveur - idéal pour importer un historique existant.
mem.add_bulk("Alice moved to Brooklyn in March. She works at a design studio downtown.", user_id="alice")
{"elapsed_secs": 0.154154944, "status": "ok", "stored": 1, "total_chunks": 1}update ✓ live-tested
Un fait a changé. L'ancien souvenir est marqué superseded (conservé pour l'historique) ; le nouveau prend sa place dans le recall.
mem.update("576700aa-...", "she switched to coffee this year", user_id="alice")
{"new_memory_id": "07e94433-b7cc-4e49-8d8f-f37fc1a392b7",
"old_memory_id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "superseded"}Lire
search ✓ live-tested
Recherche sémantique, du plus pertinent au moins pertinent. Pur embedding - aucune correspondance par mots-clés, n'importe quelle langue trouve donc n'importe quel souvenir. Le SDK renvoie directement le tableau memories ; le corps HTTP brut est montré ci-dessous.
r = mem.search("what does she drink?", user_id="alice", limit=1)
{"memories": [{
"id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624",
"content": "she prefers tea over coffee",
"category": "general",
"time_bucket": "2026-06",
"importance": 0.3,
"similarity": 0.6316057443618774,
"is_superseded": false,
"superseded_by": null,
"created_at": "2026-07-10T04:20:39.688276876Z"
}], "search_ms": 315, "total_found": 1}| Champ | Signification |
|---|---|
| similarity | Similarité d'embedding brute avec votre requête (0–1). |
| is_superseded | Vrai si ce fait a été remplacé par update(). |
| search_ms | Temps de récupération côté serveur. |
recall ✓ live-tested
Un seul aller-retour renvoie tout ce dont votre LLM a besoin - collez le résultat directement dans votre prompt : un contexte borné, de taille fixe, quel que soit le volume stocké.
ctx = mem.recall("what does she drink?", user_id="alice")
{"short_term": {"count": 2, "turns": [{"role": "user", "content": "hi", ...}]},
"long_term": {"count": 4, "memories": [{"content": "she prefers tea over coffee",
"similarity": 0.63, ...}]},
"context": {"count": 4, "around_top_memory": [
"[match] she prefers tea over coffee",
"[after] Alice moved to Brooklyn in March. ..."]},
"instruction": "Use short_term for recent context, long_term for relevant
past memories, context for surrounding conversation of the
most relevant memory."}history ✓ live-tested
Tours de conversation récents (mémoire court terme), du plus ancien au plus récent.
turns = mem.history("alice")
{"count": 2, "turns": [
{"role": "user", "content": "hi", "timestamp": "2026-07-10T04:20:40.989011337Z"},
{"role": "assistant", "content": "hello!", "timestamp": "2026-07-10T04:20:40.989013416Z"}
], "user_id": "alice"}stats ✓ live-tested
Compteurs de souvenirs pour un utilisateur.
mem.stats("alice")
{"short_term_turns": 2, "total_memories": 4, "user_id": "alice"}get ✓ live-tested
Récupère une mémoire par id - l'id renvoyé par add ou list_memories. Uniquement le texte original stocké et ses métadonnées, jamais le vecteur. Un id d'un autre store, ou une mémoire supprimée ou invalidée, renvoie 404.
m = mem.get("alice", memory_id="576700aa-...")
{"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
Liste les mémoires d'un espace : uniquement le texte original que vous avez stocké et ses métadonnées, jamais le vecteur. Paginé par curseur : renvoyez le next_cursor reçu pour la page suivante.
page = mem.list_memories("alice", limit=100)
{"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
Parcourez toutes les mémoires sans gérer le curseur, ou récupérez tout l'espace d'un coup.
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
Supprimer
delete ✓ live-tested
Supprime un souvenir unique par id.
mem.delete("alice", memory_id="576700aa-...")
{"memory_id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "deleted"}delete_all ✓ live-tested
Efface tout pour un utilisateur - un seul appel, conforme RGPD.
mem.delete_all("alice")
{"memories_deleted": 4, "status": "deleted", "user_id": "alice"}Erreurs et fiabilité
Chaque échec est une erreur typée : attrapez le cas précis (limite de débit, authentification, paiement) ou tous avec le WosError de 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
Lisez le quota restant après chaque appel et ralentissez avant d'atteindre la limite.
mem.search("...", user_id="alice") rl = mem.rate_limit # {"limit": 150, "remaining": 3, "reset": ...}
TypeScript - chaque méthode, en trois groupes.
Écrire, lire, supprimer. Chaque exemple ci-dessous a été exécuté contre l'API en production le 2026-07-10 ; les réponses sont verbatim.
npm install wontopos
import { Client } from "wontopos"; const mem = new Client({ apiKey: "wos-live-..." });
Choisir un modèle
La clé API détermine quelle mémoire (votre compte) ; le modèle détermine quel moteur la lit. Tous les modèles partagent une même mémoire : vous pouvez donc stocker avec l'un et rappeler avec un autre. Définissez un défaut dans le constructeur ; surchargez un appel isolé avec 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
Le catalogue - les ids que vous pouvez passer à model et la disponibilité de chacun. Les modèles memory: "shared" lisent le même store ; "isolated" garde le sien. Aucune clé API requise.
await mem.listModels();
[{"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
Vérifiez la connexion et que votre clé API fonctionne : un contrôle en une ligne.
await mem.ping(); // true, or throws AuthenticationError / PaymentRequiredError
Le catalogue ci-dessus reflète toujours les modèles disponibles à l'instant même - passez tout autre id et vous obtenez une erreur claire. Les nouveaux modèles y apparaissent automatiquement dès leur sortie.
Écrire
add ✓ live-tested
Stocke un souvenir. Encodé en embeddings à l'entrée - aucun appel LLM, vous ne payez que les 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
{"id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "stored (1 chunks)"}addTurn ✓ live-tested
Stocke un tour de conversation (utilisateur + assistant) à la fois en mémoire court terme et long terme.
await mem.addTurn("hi", "hello!", "alice");
{"status": "ok"}speaker ✓ live-tested
Chaque souvenir peut porter son locuteur. Enregistrez une personne une fois, puis passez son nom comme speaker ; "me" (les mots de l'assistant) n'a jamais besoin d'enregistrement. La recherche accepte aussi speaker, pour ne rappeler que les mots d'une personne.
await mem.addSpeaker("Bob", "alice"); # once per person; "me" needs no registration await mem.add("I promised to send the report on Friday", "alice", { speaker: "me" }); await mem.add("Bob said the deadline moved to Tuesday", "alice", { speaker: "Bob" }); await mem.search("what did Bob say about deadlines?", "alice", 10, { speaker: "Bob" });
addBulk ✓ live-tested
Importe un gros bloc de texte. Découpé et encodé côté serveur - idéal pour importer un historique existant.
await mem.addBulk("Alice moved to Brooklyn in March. She works at a design studio downtown.", "alice");
{"elapsed_secs": 0.154154944, "status": "ok", "stored": 1, "total_chunks": 1}update ✓ live-tested
Un fait a changé. L'ancien souvenir est marqué superseded (conservé pour l'historique) ; le nouveau prend sa place dans le recall.
await mem.update("576700aa-...", "she switched to coffee this year", "alice");
{"new_memory_id": "07e94433-b7cc-4e49-8d8f-f37fc1a392b7",
"old_memory_id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "superseded"}Lire
search ✓ live-tested
Recherche sémantique, du plus pertinent au moins pertinent. Pur embedding - aucune correspondance par mots-clés, n'importe quelle langue trouve donc n'importe quel souvenir. Le SDK renvoie directement le tableau memories ; le corps HTTP brut est montré ci-dessous.
const r = await mem.search("what does she drink?", "alice", 1);
{"memories": [{
"id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624",
"content": "she prefers tea over coffee",
"category": "general",
"time_bucket": "2026-06",
"importance": 0.3,
"similarity": 0.6316057443618774,
"is_superseded": false,
"superseded_by": null,
"created_at": "2026-07-10T04:20:39.688276876Z"
}], "search_ms": 315, "total_found": 1}| Champ | Signification |
|---|---|
| similarity | Similarité d'embedding brute avec votre requête (0–1). |
| is_superseded | Vrai si ce fait a été remplacé par update(). |
| search_ms | Temps de récupération côté serveur. |
recall ✓ live-tested
Un seul aller-retour renvoie tout ce dont votre LLM a besoin - collez le résultat directement dans votre prompt : un contexte borné, de taille fixe, quel que soit le volume stocké.
const ctx = await mem.recall("what does she drink?", "alice");
{"short_term": {"count": 2, "turns": [{"role": "user", "content": "hi", ...}]},
"long_term": {"count": 4, "memories": [{"content": "she prefers tea over coffee",
"similarity": 0.63, ...}]},
"context": {"count": 4, "around_top_memory": [
"[match] she prefers tea over coffee",
"[after] Alice moved to Brooklyn in March. ..."]},
"instruction": "Use short_term for recent context, long_term for relevant
past memories, context for surrounding conversation of the
most relevant memory."}history ✓ live-tested
Tours de conversation récents (mémoire court terme), du plus ancien au plus récent.
const turns = await mem.history("alice");
{"count": 2, "turns": [
{"role": "user", "content": "hi", "timestamp": "2026-07-10T04:20:40.989011337Z"},
{"role": "assistant", "content": "hello!", "timestamp": "2026-07-10T04:20:40.989013416Z"}
], "user_id": "alice"}stats ✓ live-tested
Compteurs de souvenirs pour un utilisateur.
await mem.stats("alice");
{"short_term_turns": 2, "total_memories": 4, "user_id": "alice"}get ✓ live-tested
Récupère une mémoire par id - l'id renvoyé par add ou list_memories. Uniquement le texte original stocké et ses métadonnées, jamais le vecteur. Un id d'un autre store, ou une mémoire supprimée ou invalidée, renvoie 404.
const m = await mem.get("alice", "576700aa-...");
{"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
Liste les mémoires d'un espace : uniquement le texte original que vous avez stocké et ses métadonnées, jamais le vecteur. Paginé par curseur : renvoyez le next_cursor reçu pour la page suivante.
const page = await mem.listMemories("alice", { limit: 100 });
{"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
Parcourez toutes les mémoires sans gérer le curseur, ou récupérez tout l'espace d'un coup.
for await (const m of mem.iterMemories("alice")) console.log(m.id, m.content); const everything = await mem.exportMemories("alice");
Supprimer
delete ✓ live-tested
Supprime un souvenir unique par id.
await mem.delete("alice", "576700aa-...");
{"memory_id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "deleted"}deleteAll ✓ live-tested
Efface tout pour un utilisateur - un seul appel, conforme RGPD.
await mem.deleteAll("alice");
{"memories_deleted": 4, "status": "deleted", "user_id": "alice"}Erreurs et fiabilité
Chaque échec est une erreur typée : attrapez le cas précis (limite de débit, authentification, paiement) ou tous avec le WosError de 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
Lisez le quota restant après chaque appel et ralentissez avant d'atteindre la limite.
await mem.search("...", "alice"); const rl = mem.rateLimit; // { limit: 150, remaining: 3, reset: ... }
Rust - chaque méthode, en trois groupes.
Écrire, lire, supprimer. Chaque exemple ci-dessous a été exécuté contre l'API en production le 2026-07-10 ; les réponses sont verbatim.
cargo add wontopos
use wontopos::Client; let mem = Client::new("wos-live-...");
Choisir un modèle
La clé API détermine quelle mémoire (votre compte) ; le modèle détermine quel moteur la lit. Tous les modèles partagent une même mémoire : vous pouvez donc stocker avec l'un et rappeler avec un autre. Définissez un défaut avec with_model() ; chaînez-le à nouveau pour surcharger un appel isolé.
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
Le catalogue - les ids que vous pouvez passer à with_model et la disponibilité de chacun. Les modèles memory: "shared" lisent le même store ; "isolated" garde le sien. Aucune clé API requise.
mem.list_models().await?;
[{"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
Vérifiez la connexion et que votre clé API fonctionne : un contrôle en une ligne.
mem.ping().await?; // Ok(true), or Err whose .kind() is Auth / PaymentRequired
Le catalogue ci-dessus reflète toujours les modèles disponibles à l'instant même - passez tout autre id et vous obtenez une erreur claire. Les nouveaux modèles y apparaissent automatiquement dès leur sortie.
Écrire
add ✓ live-tested
Stocke un souvenir. Encodé en embeddings à l'entrée - aucun appel LLM, vous ne payez que les 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
{"id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "stored (1 chunks)"}add_turn ✓ live-tested
Stocke un tour de conversation (utilisateur + assistant) à la fois en mémoire court terme et long terme.
mem.add_turn("hi", "hello!", "alice").await?;
{"status": "ok"}speaker ✓ live-tested
Chaque souvenir peut porter son locuteur. Enregistrez une personne une fois, puis passez son nom comme speaker ; "me" (les mots de l'assistant) n'a jamais besoin d'enregistrement. La recherche accepte aussi speaker, pour ne rappeler que les mots d'une personne.
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?;
add_bulk ✓ live-tested
Importe un gros bloc de texte. Découpé et encodé côté serveur - idéal pour importer un historique existant.
mem.add_bulk("Alice moved to Brooklyn in March...", "alice", "general").await?;
{"elapsed_secs": 0.154154944, "status": "ok", "stored": 1, "total_chunks": 1}update ✓ live-tested
Un fait a changé. L'ancien souvenir est marqué superseded (conservé pour l'historique) ; le nouveau prend sa place dans le recall.
mem.update("576700aa-...", "she switched to coffee this year", "alice").await?;
{"new_memory_id": "07e94433-b7cc-4e49-8d8f-f37fc1a392b7",
"old_memory_id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "superseded"}Lire
search ✓ live-tested
Recherche sémantique, du plus pertinent au moins pertinent. Pur embedding - aucune correspondance par mots-clés, n'importe quelle langue trouve donc n'importe quel souvenir. Le SDK renvoie directement le tableau memories ; le corps HTTP brut est montré ci-dessous.
let r = mem.search("what does she drink?", "alice", 1).await?;
{"memories": [{
"id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624",
"content": "she prefers tea over coffee",
"category": "general",
"time_bucket": "2026-06",
"importance": 0.3,
"similarity": 0.6316057443618774,
"is_superseded": false,
"superseded_by": null,
"created_at": "2026-07-10T04:20:39.688276876Z"
}], "search_ms": 315, "total_found": 1}| Champ | Signification |
|---|---|
| similarity | Similarité d'embedding brute avec votre requête (0–1). |
| is_superseded | Vrai si ce fait a été remplacé par update(). |
| search_ms | Temps de récupération côté serveur. |
recall ✓ live-tested
Un seul aller-retour renvoie tout ce dont votre LLM a besoin - collez le résultat directement dans votre prompt : un contexte borné, de taille fixe, quel que soit le volume stocké.
let ctx = mem.recall("what does she drink?", "alice").await?;
{"short_term": {"count": 2, "turns": [{"role": "user", "content": "hi", ...}]},
"long_term": {"count": 4, "memories": [{"content": "she prefers tea over coffee",
"similarity": 0.63, ...}]},
"context": {"count": 4, "around_top_memory": [
"[match] she prefers tea over coffee",
"[after] Alice moved to Brooklyn in March. ..."]},
"instruction": "Use short_term for recent context, long_term for relevant
past memories, context for surrounding conversation of the
most relevant memory."}history ✓ live-tested
Tours de conversation récents (mémoire court terme), du plus ancien au plus récent.
let turns = mem.history("alice").await?;
{"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
Compteurs de souvenirs pour un utilisateur.
mem.stats("alice").await?;
{"short_term_turns": 2, "total_memories": 4, "user_id": "alice"}get ✓ live-tested
Récupère une mémoire par id - l'id renvoyé par add ou list_memories. Uniquement le texte original stocké et ses métadonnées, jamais le vecteur. Un id d'un autre store, ou une mémoire supprimée ou invalidée, renvoie 404.
let m = mem.get("alice", "576700aa-...").await?;
{"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
Liste les mémoires d'un espace : uniquement le texte original que vous avez stocké et ses métadonnées, jamais le vecteur. Paginé par curseur : renvoyez le next_cursor reçu pour la page suivante.
mem.list_memories("alice", 100, None).await?;
{"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
Parcourez toutes les mémoires sans gérer le curseur, ou récupérez tout l'espace d'un coup.
let all = mem.list_all_memories("alice").await?; // every page, collected
Supprimer
delete ✓ live-tested
Supprime un souvenir unique par id.
mem.delete("alice", "576700aa-...").await?;
{"memory_id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "deleted"}delete_all ✓ live-tested
Efface tout pour un utilisateur - un seul appel, conforme RGPD.
mem.delete_all("alice").await?;
{"memories_deleted": 4, "status": "deleted", "user_id": "alice"}Erreurs et fiabilité
Chaque échec est une erreur typée : attrapez le cas précis (limite de débit, authentification, paiement) ou tous avec le WosError de 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
Lisez le quota restant après chaque appel et ralentissez avant d'atteindre la limite.
mem.search("...", "alice", 10).await?; let rl = mem.rate_limit(); // Some(RateLimit { remaining: Some(3), .. })
curl - aucune installation, mêmes méthodes.
Aucun SDK à installer - n'importe quel client HTTP convient. Définissez votre clé une fois et appelez les mêmes endpoints que les SDK encapsulent. URL de base https://api.wontopos.com, authentification via X-API-Key, JSON en entrée comme en sortie.
# set your key once (never hard-code it) export WOS_API_KEY="wos-live-..."
Écrire
store ✓ live-tested
Stocke un souvenir. Encodé en embeddings à l'entrée - aucun appel LLM.
curl -X POST https://api.wontopos.com/api/v1/memory/store \ -H "X-API-Key: $WOS_API_KEY" -H "Content-Type: application/json" \ -d '{"user_id":"alice","content":"she prefers tea over coffee"}'
{"id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "stored (1 chunks)"}store-turn ✓ live-tested
Stocke un tour de conversation (utilisateur + assistant) à la fois en mémoire court terme et long terme.
curl -X POST https://api.wontopos.com/api/v1/memory/store-turn \ -H "X-API-Key: $WOS_API_KEY" -H "Content-Type: application/json" \ -d '{"user_id":"alice","user_msg":"hi","assistant_msg":"hello!"}'
{"status": "ok"}speaker ✓ live-tested
Chaque souvenir peut porter son locuteur. Enregistrez une personne une fois, puis passez son nom comme speaker ; "me" (les mots de l'assistant) n'a jamais besoin d'enregistrement. La recherche accepte aussi speaker, pour ne rappeler que les mots d'une personne.
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"}'
supersede ✓ live-tested
Un fait a changé - l'ancien souvenir est marqué superseded, le nouveau prend sa place dans le recall.
curl -X POST https://api.wontopos.com/api/v1/memory/supersede \ -H "X-API-Key: $WOS_API_KEY" -H "Content-Type: application/json" \ -d '{"user_id":"alice","old_memory_id":"576700aa-...","new_content":"she switched to coffee this year"}'
{"new_memory_id": "07e94433-...", "old_memory_id": "576700aa-...", "status": "superseded"}Lire
search ✓ live-tested
Recherche sémantique, du plus pertinent au moins pertinent. Pur embedding - n'importe quelle langue trouve n'importe quel souvenir.
curl -X POST https://api.wontopos.com/api/v1/memory/search \ -H "X-API-Key: $WOS_API_KEY" -H "Content-Type: application/json" \ -d '{"user_id":"alice","query":"what does she drink?","max_results":1}'
{"memories": [{"id": "576700aa-...", "content": "she prefers tea over coffee",
"similarity": 0.63, "is_superseded": false}], "search_ms": 315, "total_found": 1}recall ✓ live-tested
Un seul aller-retour renvoie court terme + long terme + contexte + une instruction. Collez-le directement dans votre prompt.
curl -X POST https://api.wontopos.com/api/v1/memory/recall \ -H "X-API-Key: $WOS_API_KEY" -H "Content-Type: application/json" \ -d '{"user_id":"alice","query":"what does she drink?"}'
{"short_term": {"count": 2, "turns": [...]},
"long_term": {"count": 4, "memories": [{"content": "she prefers tea over coffee", "similarity": 0.63}]},
"context": {"count": 4, "around_top_memory": ["[match] she prefers tea over coffee"]},
"instruction": "Use short_term for recent context, long_term for relevant past memories..."}Supprimer
forget ✓ live-tested
Supprime un souvenir par id, ou omettez l'id pour tout supprimer pour un utilisateur (RGPD).
curl -X POST https://api.wontopos.com/api/v1/memory/forget \ -H "X-API-Key: $WOS_API_KEY" -H "Content-Type: application/json" \ -d '{"user_id":"alice"}' # omit memory_id = delete all
{"memories_deleted": 1, "status": "deleted", "user_id": "alice"}Engrams
Des outils de rappel invocables que votre modèle peut appeler - chacun étant une stratégie de récupération différente sur la même mémoire. Utilisez-en un, ou lancez-en plusieurs à la fois.
De nouveaux engrammes sortent régulièrement - cette liste s'allonge.
Memoir & Archive Scroll 1.2+
Celui-ci est une forme de livraison, pas un outil invocable. À partir de Scroll 1.2, choisissez-la à chaque appel - form: "memoir" ou form: "archive" - et ce rappel, simple recherche comprise, revient avec le temps écrit de cette façon.
Time_awareness Scroll 1.2+
Une forme de livraison - choisie à chaque appel. Passez form - memoir ou archive - avec n'importe quel appel sur un modèle compatible (Scroll 1.2 et au-delà), et la réponse revient rendue de cette façon : une simple recherche, un recall ou n'importe quel engramme. Dans les SDK, c'est un champ form, comme tz ; en HTTP, c'est l'en-tête X-WOS-Form. Un Memoir se lit comme une personne se souvient ; une Archive tient un registre exact - la différence se voit surtout dans la façon dont chacun écrit le temps.
Memoir
form: "memoir"Raconte ce qui s'est passé et comment un moment a mené au suivant, avec le sens diffus du temps propre au souvenir humain - à lire comme une expérience, pas comme une liste.
Archive
form: "archive"Renvoie les correspondances comme des enregistrements exacts - temps écoulé précis et ancres absolues, structurés pour qu'un modèle les lise directement.
store / add sous un user_id (ce user_id est le store de cette personne). Stockez d'abord ; ensuite tout rappel - y compris la simple recherche ci-dessous - revient horodaté. Voir Démarrage rapide pour stocker.# 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)")tz est le décalage UTC de l'appelant, en heures - ainsi « ce matin » et la limite de journée à 4 h du matin tombent dans son heure locale. Omettez-le pour UTC ; en HTTP, c'est l'en-tête X-WOS-Timezone. En gros, par région : côte Est des États-Unis -5, Centre -6, côte Ouest -8 · Royaume-Uni / Lisbonne 0 · Europe centrale +1 · Europe de l'Est +2 · Inde +5.5 · Chine / Singapour +8 · Corée / Japon +9 · Sydney +10. (Heure standard - l'heure d'été décale certaines régions de +1 ; passez ce que vos utilisateurs utilisent réellement.)
Même recherche, deux formes - les souvenirs sont identiques, seul time change :
{ "count": 3, "memories": [
{ "content": "Alice prefers tea over coffee", "time": "a couple weeks ago" },
{ "content": "met Alice at the cafe downtown", "time": "yesterday afternoon" },
{ "content": "Alice moved to Brooklyn", "time": "about half a year ago" }
] }{ "count": 3, "memories": [
{ "content": "Alice prefers tea over coffee", "time": "2 weeks ago (Jun 09)" },
{ "content": "met Alice at the cafe downtown", "time": "yesterday at 14:00" },
{ "content": "Alice moved to Brooklyn", "time": "6 months ago (Dec 2025)" }
] }| Écoulé | Memoir | Archive |
|---|---|---|
| 3 min | a few minutes ago | 3 minutes ago |
| 14 min | about 15 minutes ago | 14 minutes ago |
| 30 min | half an hour ago | 30 minutes ago |
| 50 min | about an hour ago | 50 minutes ago |
| 2 h | a couple hours ago | 2 hours ago, at 13:10 |
| 8 h | this morning | 8 hours ago, at 07:10 |
| hier ap.-midi | yesterday afternoon | yesterday at 14:00 |
| la nuit dernière | last night | 17 hours ago, at 22:00 |
| 2 jours | a couple days ago | 2 days ago (Tue 15:10) |
| 6 jours | several days ago | 6 days ago (Fri 15:10) |
| 9 jours | about a week ago | last week (Jun 16) |
| 16 jours | a couple weeks ago | 2 weeks ago (Jun 09) |
| 35 jours | about a month ago | last month (May 21) |
| 60 jours | a couple months ago | 2 months ago (Apr 2026) |
| 180 jours | about half a year ago | 6 months ago (Dec 2025) |
| 380 jours | about a year ago | last year (Jun 2025) |
| 800 jours | a couple years ago | 2 years ago (Apr 2024) |
| 1500 jours | about 4 years ago | 4 years ago (May 2022) |
Chaque valeur ci-dessus est la sortie réelle du moteur de rendu. Regardez les deux lignes « hier » : un Memoir sépare l'après-midi de la nuit dernière - une journée est un sommeil - tandis qu'une Archive écrit une seule heure d'horloge et ne trace aucune frontière entre jour et nuit.
Comment chaque mode lit le temps
Memoir - comme les gens le disent vraiment. Les moments récents restent assez nets (environ 15 minutes, une demi-heure), puis la formulation s'élargit à mesure qu'on remonte - quelques semaines, environ six mois, quelques années - comme la mémoire elle-même se relâche avec la distance. À l'intérieur d'une journée, l'horloge cède la place à un repère : ce matin, la nuit dernière, hier après-midi. Et une journée est un sommeil, pas un tic de calendrier : la frontière se situe vers 4 h du matin, heure locale, si bien qu'une fin de soirée tardive se lit encore comme le même soir, pas déjà comme le lendemain.
Archive - précis, toujours avec une ancre. Chaque ligne porte le temps écoulé exact plus une référence absolue à partir de laquelle un modèle peut calculer, et l'ancre se resserre à mesure qu'on se rapproche : une heure d'horloge pour aujourd'hui (il y a 8 heures, à 07:10), un jour de semaine et une heure cette semaine (il y a 2 jours (mar. 15:10)), une date ce mois-ci (la semaine dernière (16 juin)), un mois et une année au-delà (il y a 6 mois (déc. 2025)). Jamais vague, jamais faux.
deep_recall
Rappel multi-sauts. Cherche votre requête, puis prend la meilleure correspondance et relance une recherche sur son contenu - ramenant du contexte lié qu'une recherche unique manquerait. Idéal quand les souvenirs se référencent entre eux (une personne → ses projets → les détails). Renvoie jusqu'à ~12 résultats.
out = mem.engram("deep_recall", "what should I know about Alice?", user_id="alice"){ "engram": "deep_recall", "hops": 2, "count": 12,
"memories": [ ... ],
"usage": { "input_tokens": 5, "output_tokens": 61 } }usage (entrée + sortie), compté par le même tokenizer que le reste de l'API ; aucun frais caché par engramme. Besoin de plusieurs à la fois ? Appelez-les en parallèle - chaque engramme est une requête indépendante.timeline
Rappel chronologique. Renvoie les souvenirs triés du plus récent au plus ancien selon la date de l'événement, pas selon la pertinence. Pour les questions « quand X a-t-il eu lieu », l'historique et les séquences. Renvoie jusqu'à 15 résultats.
events = mem.engram("timeline", "project milestones", user_id="alice"){ "engram": "timeline", "hops": 1, "count": 15,
"memories": [ ... ],
"usage": { "input_tokens": 4, "output_tokens": 88 } }usage (entrée + sortie), compté par le même tokenizer que le reste de l'API ; aucun frais caché par engramme. Besoin de plusieurs à la fois ? Appelez-les en parallèle - chaque engramme est une requête indépendante.gather
Collecte large. Cherche, puis s'étend autour des trois meilleures correspondances - un filet plus large que deep_recall. Utilisez-le pour ramener tout ce qui touche à une personne, un projet ou un sujet en un seul appel. Renvoie jusqu'à ~18 résultats.
related = mem.engram("gather", "everything about Project Atlas", user_id="alice"){ "engram": "gather", "hops": 4, "count": 18,
"memories": [ ... ],
"usage": { "input_tokens": 6, "output_tokens": 142 } }usage (entrée + sortie), compté par le même tokenizer que le reste de l'API ; aucun frais caché par engramme. Besoin de plusieurs à la fois ? Appelez-les en parallèle - chaque engramme est une requête indépendante.Chaque endpoint, une seule URL de base.
Aucun SDK requis - n'importe quel client HTTP convient. URL de base https://api.wontopos.com, authentification via l'en-tête X-API-Key, JSON en entrée comme en sortie. Les opérations mémoire sont en POST ; la gestion des stores utilise POST / GET / DELETE sur /collection. Un store doit exister au préalable (voir Stores), sinon les opérations dans le store renvoient 404.
| Endpoint | Rôle | Champs du corps |
|---|---|---|
| POST /api/v1/memory/collection | créer un store | user_id |
| GET /api/v1/memory/collections | lister vos stores | (aucun) |
| DELETE /api/v1/memory/collection | supprimer un store + ses souvenirs | user_id |
| /api/v1/memory/store | stocker un souvenir | user_id · content · metadata? (speaker) |
| /api/v1/memory/store-turn | stocker un tour de conversation | user_id · user_msg · assistant_msg |
| POST /api/v1/memory/speakers | enregistrer un locuteur (explicite, 50 max) | user_id · speaker |
| GET /api/v1/memory/speakers | lister les locuteurs enregistrés + compteurs | user_id |
| DELETE /api/v1/memory/speakers | désinscrire un locuteur (souvenirs conservés) | user_id · speaker |
| /api/v1/memory/bulk-store | importer un bloc de texte | user_id · content · category? |
| /api/v1/memory/search | recherche sémantique | user_id · query · max_results? · speaker? |
| /api/v1/memory/recall | court + long + contexte | user_id · query |
| /api/v1/memory/history | tours récents | user_id |
| /api/v1/memory/stats | compteurs de souvenirs | user_id |
| /api/v1/memory/supersede | remplacer un fait modifié | user_id · old_memory_id · new_content |
| /api/v1/memory/forget | en supprimer un (ou tous) | user_id · memory_id? (omis = tout supprimer) |
# create the store once (stores are explicit) curl -X POST https://api.wontopos.com/api/v1/memory/collection \ -H "X-API-Key: $WOS_API_KEY" -H "Content-Type: application/json" \ -d '{"user_id":"alice"}' # store a memory curl -X POST https://api.wontopos.com/api/v1/memory/store \ -H "X-API-Key: $WOS_API_KEY" -H "Content-Type: application/json" \ -d '{"user_id":"alice","content":"she prefers tea over coffee"}' # recall - one call, ready for your prompt curl -X POST https://api.wontopos.com/api/v1/memory/recall \ -H "X-API-Key: $WOS_API_KEY" -H "Content-Type: application/json" \ -d '{"user_id":"alice","query":"what does alice drink?"}'
{"id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "stored (1 chunks)"}Les mêmes fonctionnalités pour tous.
Les paliers ne font que relever vos limites.
Chaque palier exécute le moteur complet - même qualité de rappel, mêmes langues, chaque méthode. Les paliers progressent automatiquement jusqu'au Tier 5 à mesure que vos achats de crédits cumulés augmentent, sans dossier à déposer ni rendez-vous commercial. Enterprise (Tier 6) est la seule exception.
Limites de dépense
Chaque palier plafonne ce que vous pouvez dépenser par mois calendaire. Vous passez immédiatement au palier suivant dès que vos achats de crédits cumulés atteignent le seuil correspondant.
| Palier d'utilisation | Achat de crédits | Limite de dépense mensuelle |
|---|---|---|
| Tier 1 | $5 | $100 |
| Tier 2 | $40 | $500 |
| Tier 3 | $200 | $1,000 |
| Tier 4 | $400 | $5,000 |
| Tier 5 | $1,000 | $25,000 |
| Tier 6 - Enterprise | Contactez-nous | Sans limite |
Limites de débit
Les limites de débit sont par compte - toutes les clés API d'un compte partagent une même limite, qui augmente avec votre palier. La dépasser renvoie un 429 avec un en-tête retry-after ; patientez (1s → 2s → 4s) puis réessayez. Chaque endpoint est compatible avec l'idempotence, les nouvelles tentatives sont donc sans risque.
| Palier | Requêtes par minute |
|---|---|
| Tier 1 | 150 |
| Tier 2 | 300 |
| Tier 3 | 600 |
| Tier 4 | 1,500 |
| Tier 5 | 3,000 |
| Tier 6 - Enterprise | Sur mesure |
Enterprise (Tier 6) bénéficie de limites de débit sur mesure, d'un SLA, d'un support dédié et d'une licence d'auto-hébergement en option - contactez-nous.
Quand quelque chose tourne mal.
Les erreurs reviennent sous forme d'enveloppe JSON avec un type stable, un message lisible et un request_id que vous pouvez nous transmettre pour signaler un problème.
{"type": "error", "error": {
"type": "authentication_error",
"message": "Invalid or revoked API key.",
"request_id": "063f8b83-eee2-4383-a5cf-11e4bcd29d7c"
}}| HTTP | Signification | Que faire |
|---|---|---|
| 401 | Clé API invalide ou révoquée | Vérifiez la clé ; émettez-en une nouvelle dans la console. |
| 422 | Corps malformé (champ manquant ou de mauvais type) | Le message nomme le champ exact - corrigez et réessayez. |
| 429 | Limite de débit atteinte | Patientez de façon exponentielle (1s → 2s → 4s) puis réessayez. Sans risque : tous les endpoints sont compatibles avec l'idempotence. |
| 5xx | Problème côté serveur | Réessayez avec backoff ; joignez le request_id si vous nous contactez. |
# 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
Les limites de débit sont par compte, partagées entre toutes vos clés, et augmentent avec votre palier - voir Paliers d'utilisation. L'usage de votre compte est visible dans la console.
Vos serveurs, vos données.
Le moteur peut tourner dans votre propre infrastructure - même API, mêmes SDK. Pointez le client vers votre hôte et rien d'autre ne change.
mem = Client(api_key="...", base_url="https://wos.your-host.com")- Résidence des données. Les souvenirs ne quittent jamais votre réseau.
- Même surface. Les mêmes méthodes et endpoints fonctionnent à l'identique.
- Licence. Les offres d'auto-hébergement sont définies par déploiement - contactez-nous.
Au-delà de la fenêtre de contexte.
WOS rappelle depuis des historiques de 1.4M tokens - bien au-delà de toute fenêtre de contexte de LLM - et rend toujours une tranche serrée d'environ ~1,470 tokens.
La mémoire de votre agent n'est pas plafonnée par ce qui tient dans un prompt. Elle conserve tout et ne récupère que ce qui compte, quelle que soit la taille de l'historique.
Privé, et à vous.
Vos données restent dans votre store. Nous ne nous entraînons jamais dessus, ne les consultons pas et ne les réutilisons pas - nous ne faisons que les organiser pour que vous puissiez les retrouver.
- BYOK. Votre clé LLM est envoyée à chaque requête et jamais stockée.
- Isolé. Les souvenirs sont cloisonnés par compte, puis par
user_id. - Suppression RGPD & auto-hébergement. Un seul appel efface un utilisateur ; exécutez le moteur dans votre propre environnement si vous préférez.