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-08-01 ; 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
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": "tablet-2", "name": "Tablet 2", "available": true, "memory": "shared"},
{"id": "scroll-1", "name": "Scroll 1", "available": true, "memory": "shared"},
{"id": "scroll-1.2", "name": "Scroll 1.2", "available": true, "memory": "shared"}]ping
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
Stocke un souvenir. Aucun appel LLM à l’entrée : vous ne payez que le tarif d’écriture.
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
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
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
Importez un gros bloc de texte. Découpé et indexé côté serveur, idéal pour reprendre 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
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
Recherche sémantique, du plus pertinent au moins pertinent. N’importe quelle langue trouve n’importe quel souvenir, quelle que soit la langue dans laquelle il a été écrit. Le SDK renvoie directement le tableau memories ; le corps HTTP brut est affiché ci-dessous. Certains modèles répondent avec plusieurs ensembles de résultats et le SDK les renvoie fusionnés : le tableau peut donc contenir PLUS que max_results. Dimensionnez votre fenêtre de prompt sur ce que vous recevez, pas sur le nombre demandé.
const r = await mem.search("what does she drink?", "alice", 1);
[{
"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"
}]| Champ | Signification |
|---|---|
| similarity | À quel point ce souvenir est proche de 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
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
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
Compteurs de souvenirs pour un utilisateur.
await mem.stats("alice");
{"short_term_turns": 2, "total_memories": 4, "user_id": "alice"}get
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. 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", "created_at": "2026-07-10T04:20:39Z", "event_date": null,
"is_superseded": false, "superseded_by": null}listMemories
Liste les mémoires d'un espace : uniquement le texte original que vous avez stocké et ses métadonnées. 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", "created_at": "2026-07-10T04:20:39Z", "event_date": null,
"is_superseded": false, "superseded_by": null}
]}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
Supprime un souvenir unique par id.
await mem.delete("alice", "576700aa-...");
{"memory_id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "deleted"}deleteAll
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: ... }
searchSelf
Les deux voies en un seul appel sur un modèle à mémoire de soi (Scroll 1.2+) : ce que les autres ont dit, et les propres mots de l'agent - séparés, pour que le lecteur ne confonde jamais qui a parlé.
const { memories, self_memories } = await mem.searchSelf("what did I promise?", "alice"); // memories = what others said · self_memories = the agent's OWN words
listEngrams
Demandez au service quels engrammes et formes de rendu le modèle sélectionné peut exécuter, au lieu de coder en dur des noms qui deviennent obsolètes dès qu'un nouveau sort.
const { engrams, forms } = await mem.listEngrams(); // ask, never hard-code
filters
Restreint la recherche à une partie du magasin. Appliqué avant le classement : vous obtenez les meilleures correspondances à l'intérieur du filtre, pas un top-N filtré après coup.
await mem.search("what did we decide", "alice", 10, { filters: { categories: ["work"], event_from: "2026-01-01" }, // when it HAPPENED });
idempotencyKey
Rend sûr le fait de répéter une écriture. À utiliser quand la reprise vient de vous - un job interrompu puis relancé, une file qui redélivre.
await mem.add("she prefers tea", "alice", {}, { idempotencyKey: `import:${row.id}` });
import:row-42), jamais une constante : une clé réutilisée pour deux écritures différentes rejoue la première, et la seconde est perdue en silence. Format : 1 à 128 caractères parmi [A-Za-z0-9._:-].withTimeout / withRetries / withDeadline
Ajustez un seul point d'appel sans toucher au client déjà construit : un clone avec un délai plus long pour une grosse reprise, ou sans reprises à l'intérieur de votre propre boucle de retry.
timeout borne une tentative, donc un appel qui réessaie peut lui survivre : avec les valeurs par défaut, un seul appel peut retenir une connexion 30 s, attendre, réessayer, puis réessayer encore. deadline borne l'appel entier : chaque tentative est plafonnée à ce qu'il reste, et aucune attente ne dort au-delà du budget. Réglez-le quand l'appelant a une vraie limite, comme un gestionnaire de requête disposant de cinq secondes.
await mem.withTimeout(120_000).addBulk(bigBlob, "alice"); // this slow call only await mem.withRetries(0).add("...", "alice"); // you retry, not the SDK await mem.withDeadline(5_000).recall("...", "alice"); // 5s for the whole call await mem.withSignal(ctrl.signal).recall("...", "alice"); // caller can cancel