Warum WOS

Langzeitgedächtnis für KI-Agenten.

WOS ist eine Memory-API. Sie speichern die Erinnerungen eines Nutzers einmal, rufen dann zu jeder Abfrage nur die relevanten ab und übergeben sie an den Prompt Ihres Modells.

Der Abruf ist rein semantisch, ohne Keyword- oder BM25-Matching, daher ist die Recall-Qualität in allen Sprachen identisch. Jede Abfrage liefert einen kleinen, begrenzten Kontext zurück, unabhängig davon, wie viel Sie gespeichert haben, und über Ihre gespeicherten Erinnerungen läuft niemals ein Modell.

Kernoperationen

  • store - speichert eine Erinnerung für einen Nutzer.
  • recall - liefert die relevanten Erinnerungen zu einer Abfrage. Dies ist der zentrale Aufruf.
  • search - rohe semantische Suche über gespeicherte Erinnerungen.
  • supersede - aktualisiert oder ersetzt eine veraltete Erinnerung.
  • forget - löscht eine einzelne Erinnerung oder einen ganzen Nutzer (DSGVO).
Wählen Sie links einen Abschnitt für Details zu jedem Thema.
Modell

Drei Modelle, eine Linie.

WOS-Modelle sind danach benannt, wie Menschen im Lauf der Geschichte Wissen bewahrt haben - Tablet, Scroll, Book. Steintafel, Schriftrolle, gebundenes Buch: Jedes leistet mehr für Ihren Agenten als das vorherige.

Tablet

Live
In Stein gemeißelt · store & recall

Eine schlanke, schnelle und kostengünstige Art, Erinnerungen einzuschreiben und abzurufen - das Fundament, auf dem jedes Modell aufbaut.

Scroll

Live
Entrollt · LLM-gestützter Abruf

Ergänzt ein Sprachmodell, das Ihre Frage genauer liest und einen vollständigeren Kontext zurückbringt - verstreute Belege kommen so wieder zusammen, statt dass ein Teil fehlt.

Book

Demnächst
Gebunden & indexiert · selbststeuernd

Schlägt von selbst die richtige Seite auf - wählt in jedem Moment das passende Gedächtnis und die passenden Werkzeuge und wird mit jeder Nutzung schärfer.

Der vollständige Benchmark-Bericht zu Tablet 1 steht auf der Benchmark-Seite.

Kosten

Zahlen Sie uns $2. Sparen Sie ein Vielfaches davon bei Ihrem LLM.

WOS führt Ihrem LLM ~1.200 Tokens pro Abfrage zu - einen begrenzten, relevanten Ausschnitt - statt die gesamte Historie in jeden Prompt zu stopfen. Der Abstand ist enorm und wächst mit Ihrer Historie.

LLM-Kosten pro 1.000 Abfragen Basierend auf Tablet 1
Nutzerhistorie100K
Abfragen / Monat1,000
Ihr LLM
45× günstiger - Sie sparen $244/Monat
Ohne WOS$250.00
Mit WOS$5.50

Jeder für WOS ausgegebene $1 spart ~$98 beim LLM. Größere Historie oder ein teureres Modell → größerer ROI.

Woher die Einsparungen kommen

  • Ohne WOS packen Sie die gesamte Historie in jeden Prompt - 100K tokens × $2.50/1M = $0.25 pro Abfrage, zu GPT-4o-Eingabepreisen (bei Modellen der Opus-Klasse etwa das Doppelte).
  • Mit WOS nehmen Sie die Daten einmal auf ($2/1M); danach ist jede Abfrage ein winziger Abruf ($3/1M × 1,200) plus Ihr LLM auf nur ~1.200 Tokens.
  • Je weniger Tokens Ihr LLM liest, desto weniger zahlen Sie - und WOS hält diese Zahl konstant, während das Gedächtnis wächst.
Kontext-Verkleinerung = Historie ÷ zugeführte Tokens, nicht Kosten (der Rechner oben bepreist jeden Abruf).  25K → 21× · 100K → 83× · 200K → 167×.
Mehrsprachigkeit

Jede Sprache, dieselbe Genauigkeit.

Der Abruf ist rein semantisch - ausschließlich Embeddings, null Keyword- oder BM25-Matching. Die Recall-Qualität ist daher identisch, ob Ihre Nutzer auf 日本語, 中文, Español oder Englisch schreiben.

Lexikalisches Matching wie BM25 ist auf die Gestalt einer bestimmten Sprache abgestimmt - Morphologie, Leerzeichen, Schriftsystem. In einem mehrsprachigen Store heißt das: Die Abrufqualität variiert je nach Sprache. WOS verwendet überhaupt kein lexikalisches Matching, sodass jede Sprache denselben Weg nimmt.

Ein Store, drei Sprachen zugleich

Sie wählen keine Sprache pro Store - mischen Sie frei. Unten enthält das Gedächtnis eines Nutzers gleichzeitig Japanisch, Englisch und Spanisch, und jede Frage findet die richtige Erinnerung, unabhängig von der Sprache. Dies ist ein echter Austausch mit der Live-API:

# 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
Tatsächliche Ergebnisse - jede Frage wechselt in eine andere Sprache
"¿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

Kein Übersetzungsschritt, keine Spracherkennung, keine Konfiguration pro Sprache. Erinnerungen und Fragen werden nach Bedeutung eingeordnet, nicht nach Sprache - passt die Bedeutung, spielt die Sprache keine Rolle.

Drei Sprachen sind hier nur das, was auf eine Seite passt - es gibt keine Liste unterstützter Sprachen, auf der man stehen müsste. Derselbe Live-Test besteht auch mit Erinnerungen auf 中文, Русский und العربية, alle gegen die Produktions-API verifiziert.

Warum wir Keywords bewusst verbannt haben

Lexikalisches Scoring wie BM25 stärkt den Abruf für manche Sprachen mehr als für andere - hinderlich, wenn ein Store viele Sprachen enthält. Wir haben es daher vollständig aus der Engine entfernt und setzen diese Regel im Code-Review durch: Mit jeglichem lexikalischem Scoring im Pfad würde die Recall-Qualität je nach Sprache abweichen.

LongMemEval ist rein englischsprachig und misst daher keinen mehrsprachigen Recall. Die Demo oben zeigt, wie Sie ihn direkt gegen die Live-API verifizieren können.
Architektur

Kein Modell läuft über Ihre Erinnerungen.

Die Speicherung erfolgt wortgetreu, und die Engine sucht über Embeddings - günstig, schnell und deterministisch. Über Ihre gespeicherten Erinnerungen läuft niemals ein Modell. Tablet verwendet gar kein Modell; Scroll und Book setzen für stärkere Ergebnisse eines um die Engine herum ein, doch es sieht immer nur Ihre Abfrage, nie das, was Sie gespeichert haben.

  • Deterministische Engine. Die Engine liefert für dieselbe Abfrage jedes Mal dieselben Erinnerungen - deshalb stammt die Varianz in unserem Benchmark allein vom Reader-Modell.
  • Günstig im großen Maßstab. Keine Generierungskosten beim Speichern oder Abrufen - Ihre Rechnung folgt dem Speicherplatz, nicht der Modellnutzung, während das Gedächtnis wächst.

Ihre Worte, unangetastet

Ein verbreitetes Design lässt beim Schreiben ein Sprachmodell laufen, um "Fakten" aus dem Text zu extrahieren und umzuschreiben. Dieses Design bezahlt dreifach: Generierungskosten bei jedem Schreibvorgang, zusätzliche Latenz und die Speicherung der Paraphrase eines Modells statt der ursprünglichen Worte. WOS trifft die entgegengesetzte Wahl - es speichert das Gesagte unverändert und lässt Ihr LLM die Interpretation zur Lesezeit übernehmen, mit dem Originaltext in der Hand.

Was WOS nicht ist: keine Vektor-Datenbank, die Sie betreiben müssen, und kein RAG-Framework, das Sie zusammenbauen müssen. Über Ihre gespeicherten Daten läuft niemals ein Modell - dieser Pfad besteht rein aus Embeddings. Scroll und Book nutzen zwar ein Sprachmodell für stärkere Ergebnisse, doch es sieht immer nur Ihre Abfrage, nie Ihre gespeicherten Erinnerungen - und es trainiert niemals auf Ihren Daten oder sammelt sie.
Nachweis

67,5 %, gemessen und reproduzierbar.

67,5 % auf BEAM 1M, gemittelt über 5 unabhängige Läufe (σ 0,22 %, keiner handverlesen), bewertet von gpt-4.1-mini mit dem Judging-Prompt des Benchmarks selbst.

Auf demselben Benchmark schwanken die Ergebnisse stark mit dem Bewertungsprotokoll - dem Judge, dem Prompt und dem, was die Abrufschicht tun darf. Wir bewerten mit dem Judge, den das Repository der Autoren selbst mitliefert, verwenden ihren Judging-Prompt wie geschrieben, passen nichts an den Test an und veröffentlichen Harness, Bewertungscode und Reader-Prompt, sodass jeder die 67,5 % exakt reproduzieren kann.

Das Protokoll in einer Tabelle

PunktUnser Vorgehen
DatensatzBEAM 1M - 35 Gespräche, 74.630 Turns, 2,2 Millionen Erinnerungen, 700 Fragen
Judgegpt-4.1-mini bei temperature 0, mit BEAMs eigenem Judging-Prompt - der Standard im Repository der Autoren, kein von uns gewählter Judge
Läufe5 unabhängige Läufe, jeder Wert veröffentlicht, Mittelwert berichtet (σ 0,22 %)
ReaderFestes Reader-Modell und fester Prompt, wortwörtlich veröffentlicht

Was es ehrlich hält: ein Judge von dritter Seite, der unverändert veröffentlichte Reader-Prompt, rein semantischer Abruf und die Veröffentlichung jedes Laufs - nicht nur des besten. Die Abruf-Engine ist deterministisch - führen Sie sie erneut aus, erhalten Sie dieselben Erinnerungen.

Wir erklimmen härtere Benchmarks

Wir testen auf dem härtesten Standard-Benchmark, den wir noch nicht bezwungen haben - und die Zahl ist die Bestmarke über alle WOS-Modelle hinweg, neu geschrieben, sobald ein besseres erscheint. Überschreiten wir klar 94%, steigen wir zu einem härteren Benchmark auf.

BEAM 1MIn Arbeit
Tablet67.5%
gpt-4.1-mini als Judge · Mittelwert aus fünf Durchläufen94% zum Aufstieg
Früherer Benchmark LongMemEval-S Bestanden
Tablet95.7%
Scroll92.3%
GPT-4o-Judge · Bestwert über alle WOS-Modelle94% zum Aufstieg
Vollständigen Bericht ansehen
Preise

Zwei Token-Preise pro Modell,
plus $0.0001 pro Anfrage.

Pro Million Tokens plus pauschal $0.0001 pro Anfrage, Bezahlung nach Verbrauch. Kein Abonnement, keine Speichermiete, keine Gedächtnisgrenzen. Sie zahlen, wenn Ihr Agent schreibt oder liest - nie für das, was er sich merkt.

ModellEingabe / 1MAusgabe / 1M
Tablet$2$3Live
Scroll$4$8Live
Book--Noch offen
  • $0.0001 pro Anfrage. Eine Pauschalgebühr auf jeden API-Aufruf, zusätzlich zur Token-Nutzung.
  • Speicherung ist kostenlos. Die Aufnahme wird einmal bezahlt; das Aufbewahren kostet Sie nichts. Kein Mengenlimit, keine Aufbewahrungsgrenze.
  • Wir speichern es. Wir trainieren nie darauf, verwenden es nicht und sehen es nicht ein. Das Gedächtnis Ihres Agenten gehört Ihnen - wir organisieren es nur, damit Sie es abrufen können.
  • Warum Tablet so günstig ist: Seine Engine führt kein Modell aus, unsere Kosten sind also Embeddings und Festplatten - keine GPUs. Scroll und Book ergänzen ein Modell, und genau das deckt ihr höherer Preis ab.
Andere Abrechnungsmodelle berechnen monatlich das gespeicherte Volumen oder deckeln die Anzahl der Erinnerungen je nach Tarif. WOS berechnet für gespeicherte Daten nichts, unabhängig von Volumen oder Alter.

Rate-Limits nach Nutzungsstufe →

Für Entwickler

Drei Aufrufe: Speichern, Abrufen, Antworten.

Eine API. Der Aufruf recall() liefert Kurzzeit-, Langzeit- und Umgebungskontext in einem einzigen Roundtrip - bereit zum Einfügen in Ihren Prompt.

1

Speichern

add() speichert Fakten und Gespräche: die Worte deines Nutzers, die eigenen des Assistenten (speaker "me") oder die einer benannten Person. Beim Eingang eingebettet, ohne LLM-Aufruf.

2

Abrufen

recall() liefert Kurzzeit + Langzeit + Kontext in einem Aufruf - ein begrenzter Kontext fester Größe.

3

Antworten

Übergeben Sie diesen begrenzten Kontext an Ihr LLM - beliebiger Anbieter, Ihr Schlüssel.

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")

Erinnerungen tragen einen Sprecher. Standard sind die Worte deines Nutzers, speaker "me" speichert, was der Assistent selbst gesagt hat, und ein Name wie "Bob" merkt sich, wer es gesagt hat — Erinnern nach Person.

Sprecher sind explizit, wie Stores. Registriere die Person zuerst, speichere dann unter ihrem Namen: ein Tippfehler wird nie still zu einer neuen Person. Ein Store registriert zunächst bis zu 50 Personen (wir planen mehr), und "me" braucht nie Registrierung und zählt nie.
Schnellstart

Ihr erster Recall in 5 Minuten.

Ein Schlüssel, eine Installationszeile, drei Aufrufe - und Ihr Agent hat ein Gedächtnis. Jedes Snippet auf dieser Seite wurde tatsächlich ausgeführt; die Antworten sind wortwörtlich wiedergegeben.

1

API-Schlüssel erstellen

Erstellen Sie einen in der Konsole. Ein 155 Zeichen langer Schlüssel, der mit wos-live- beginnt, wird einmal angezeigt. Bewahren Sie ihn in einer Umgebungsvariable auf - niemals im Code.

2

Installieren

pip install wontopos        # Python
npm install wontopos        # TypeScript / JavaScript
cargo add wontopos          # Rust
# curl - nothing to install, just set WOS_API_KEY
# latest: SDK v2.2.32 · MCP v1.0.15
3

Store anlegen, dann speichern & abrufen

Ein Store ist die user_id, unter der Sie lesen und schreiben. Stores sind explizit: Legen Sie zuerst einen an (der Aufruf unten), dann speichern Sie hinein und rufen daraus ab. Speichern - beim Eingang eingebettet, kein LLM-Aufruf. Abrufen - Kurzzeit + Langzeit + Kontext in einem Roundtrip.

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?"}'
Tatsächliche Antwort - create_store()
{"user_id": "alice", "status": "created"}
Tatsächliche Antwort - add()
{"id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "stored (1 chunks)"}
Store einmal setzen. Übergeben Sie user_id an den Client, und jeder Aufruf verwendet sie - kein Wiederholen nötig; überschreiben Sie einen einzelnen Aufruf, indem Sie ihm user_id übergeben. Stores sind explizit: Das Speichern in einen oder Abrufen aus einem Store, der nicht existiert, liefert 404 - legen Sie ihn zuerst an. Jedes Konto startet mit einem default-Store, sodass der Pfad ganz ohne user_id ohne jede Einrichtung funktioniert. Siehe Stores zum Auflisten und Verwalten.

recall() liefert vier Blöcke - short_term (jüngste Gesprächszüge), long_term (relevante Erinnerungen), context (das Umfeld des besten Treffers) und eine instruction, die dem LLM sagt, wie es sie verwenden soll. Fügen Sie das Ganze in Ihren Prompt ein.

Funktioniert in jeder Sprache. Speichern Sie auf Englisch, fragen Sie auf Koreanisch, Japanisch oder Chinesisch - dieselbe Erinnerung kommt zurück. Embedding-Suche, kein Keyword-Matching.

Jede Methode, pro Sprache →

Ein Client, andere Einstellungen

mem = Client.from_env()                 # reads WONTOPOS_API_KEY
scroll = mem.with_model("scroll-1.2")  # this copy only: another engine
alice  = mem.with_user("alice")       # this copy only: another default store
const alice = mem.withUser("alice");
const scroll = mem.withModel("scroll-1.2");
let alice = mem.with_user("alice");
let scroll = mem.with_model("scroll-1.2");
# curl has no copies — send model and user_id with each request
curl ... -d '{"user_id":"alice","model":"scroll-1.2","query":"…"}'
Stores

Stores - anlegen, auflisten, löschen.

Ein Store ist die user_id, unter der Sie lesen und schreiben - ein isolierter Gedächtnisraum pro Endnutzer, Agent oder Thema. Stores sind explizit: Legen Sie einen an, bevor Sie hineinspeichern oder daraus abrufen, sonst liefert der Aufruf 404. Jedes Konto startet mit einem default-Store, Sie können also ohne Create-Aufruf beginnen.

Wie die Isolation verschachtelt ist. Ein Konto besitzt Workspaces; jeder Workspace isoliert sein eigenes Gedächtnis, seine API-Schlüssel und seine Nutzung (die Abrechnung erfolgt gemeinsam auf Kontoebene). Ein Store liegt innerhalb eines Workspace: Schlüssel im selben Workspace teilen sich dessen Stores, und verschiedene Workspaces sehen niemals das Gedächtnis des jeweils anderen. 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"}'
Tatsächliche Antwort - create
{ "user_id": "alice", "status": "created" }   // "exists" if it already did
Tatsächliche Antwort - 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 auf einen Store, der nicht existiert
{ "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." } }
Verwenden Sie einen Store pro Endnutzer ("alice", "user_42"), um die Erinnerungen jeder Person getrennt zu halten, oder einen einzelnen default-Store für einen persönlichen Agenten. Stores lassen sich auch in der Konsole anlegen und durchsehen (Memory ids → Issue), ganz ohne Code. Das Löschen eines Stores ist endgültig - es entfernt jede Erinnerung darin. Store-Ids werden vor der Speicherung zusammengefaltet - kleingeschrieben, alles außerhalb von [a-z0-9_] wird zu _ -, sodass Alice.Smith und alice-smith denselben Store bezeichnen. Eine zweite Id, die auf eine vorhandene fällt, wird mit 409 abgelehnt statt stillschweigend geteilt. Die Id muss außerdem [A-Za-z0-9][A-Za-z0-9._-]{0,63} entsprechen; eine E-Mail-Adresse oder ein nicht-lateinischer Name kann daher keine Store-Id sein - verwenden Sie stattdessen eine interne Id.

Stores auflisten und löschen

mem.list_stores()                # [{"user_id","created_at"}, …]
mem.delete_store("alice")      # the store and every memory in it
await mem.listStores();
await mem.deleteStore("alice");
let stores = mem.list_stores().await?;
mem.delete_store("alice").await?;
curl -X POST   .../api/v1/memory/collections -d '{}'
curl -X DELETE .../api/v1/memory/collection  -d '{"user_id":"alice"}'
Recall-Caching

Wiederholte Abrufe, zum Zehntel des Preises.

Aktiviere es pro Anfrage, und WOS cached das Suchergebnis unter dem Abfragetext, mit denselben Präfixregeln wie beim Prompt Caching von LLMs. Solange der Cache warm ist, nutzt eine wiederholte oder erweiterte Abfrage das vorherige Ergebnis wieder, und der gecachte Teil wird mit 10% des normalen Token-Preises berechnet.

Nur Tablet und Scroll. Caching funktioniert auf jedem Tablet- und Scroll-Modell, heute und in Zukunft. Book unterstützt es nicht: Book denkt über deine Erinnerungen nach und lernt zwischen den Aufrufen, dieselbe Frage kann also berechtigt eine andere Antwort ergeben, und ein gecachtes Ergebnis wäre konstruktionsbedingt falsch. Wer cache_control an Book sendet, bekommt ein klares 403.

Ein Gespräch, drei Runden

So sieht es wirklich aus, wenn ein Agent immer weiter mit seinem Gedächtnis spricht. Jede Runde schickt das bisherige Gespräch als Abfrage, mit aktiviertem cache_control.

writeRunde 1 - „Alice: Ich bin letzten Frühling nach Lissabon gezogen.“

Die gesamte Abfrage wird gesucht und gecacht: Eingabe zum 2-fachen (TTL 5 Minuten).

extendRunde 2 - derselbe Text plus „Bob: Wie ist das Wetter dort?“

Nur Bobs Satz wird eingebettet und gesucht. Der alte Teil kostet 0,1x, der neue Satz 2x, und der Cache endet jetzt dort.

hitRunde 3 - exakt dieselbe Abfrage noch einmal (ein Retry, ein Refresh)

Gar kein Engine-Aufruf. Alles zu 0,1x: der 90%-Rabatt.

Die Preise

VorgangToken-AbrechnungBedeutung
Cache-Schreiben - TTL 5 MinutenDie erste Anfrage. Ihr Ergebnis wird 5 Minuten aufbewahrt, und jedes Lesen verschiebt das Fenster nach vorn.
Cache-Schreiben - TTL 1 StundeDie erste Anfrage, eine volle Stunde aufbewahrt.
Cache-Lesen - Treffer oder Präfix-Treffer0.1×Jede Anfrage nach dem Schreiben: Der gecachte Teil kostet ein Zehntel des normalen Token-Preises.

Was es spart

Ein konkretes Beispiel: Dein Agent schickt ein Gespräch mit 3.000 Tokens als Abfrage und wiederholt oder verlängert es 10-mal innerhalb von fünf Minuten. Ohne Caching sind das 30.000 Eingabe-Tokens zum vollen Preis. Mit einem 5-Minuten-Cache sind es 6.000 für das erste Schreiben (2x) plus rund 2.700 für die neun Cache-Lesevorgänge: 8.700 abgerechnete Tokens, 71% weniger. Je länger das Gespräch läuft, desto größer die Ersparnis.

Die Präfixregel

Der Abgleich erfolgt am Anfang der Abfrage. Bleibt der Anfang identisch und wird nur neuer Text angehängt, wird der gecachte Teil wiederverwendet und nur der neue Teil gesucht. Ändert sich etwas vor dem Ende des gecachten Textes, kann nichts wiederverwendet werden.

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

Treffer - der Anfang ist unverändert, nur E ist neu
Fehltreffer - der Anfang hat sich geändert, die gesamte Abfrage wird neu gesucht und neu gecacht

Drei Regeln zum Merken

  • Erweitern cached bis zum neuen Ende neu. Nach [A B C D E F G] + E endet der Cache jetzt bei E: Das Ende wird einmal zum Schreibtarif berechnet, und die nächste Runde kann wieder ganz A..E als Präfix abgleichen.
  • Ein zusammenhängendes Präfix pro Anfrage. Eine Abfrage kann nicht in zwei Cache-Segmente geteilt werden; nur ihr Anfang kann übereinstimmen.
  • Schreibvorgänge invalidieren sofort. Jedes store, store-turn, bulk-store, forget, supersede oder Löschen des Stores verwirft dessen Cache. Eine gecachte Antwort kann nie veraltet sein.

So wird es aktiviert

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"
Antwort - das cache-Objekt meldet, was passiert ist
{ "memories": [ ... ],
  "cache": { "status": "hit",              // "write" | "hit" | "extend"
             "ttl": "5m",
             "cache_read_input_tokens": 412,
             "cache_creation_input_tokens": 0 } }

Für all das brauchst du kein SDK. Caching ist ein Feld in einem HTTP-Aufruf und funktioniert daher aus jeder Programmiersprache. Der curl-Tab ist das universelle Rezept, und die Python-, TypeScript- und Rust-SDKs sind bequeme Hüllen um genau denselben Aufruf.

Das Caching ist innerhalb deines Workspace pro Store und pro Modell isoliert und standardmäßig aus: Ohne cache_control ändert sich an deinen Anfragen nichts.
Wer es gesagt hat

Gedächtnis, das weiß, wer es gesagt hat.

Menschen erinnern sich nach Person: was Bob versprochen hat, was du zugesagt hast. Gib jeder Erinnerung einen Sprecher und dein Agent tut dasselbe, auf jedem Tablet- und Scroll-Modell.

Sprecher sind explizit, wie Stores. Registriere die Person zuerst, speichere dann unter ihrem Namen: ein Tippfehler wird nie still zu einer neuen Person. Ein Store registriert zunächst bis zu 50 Personen (wir planen mehr), und "me" braucht nie Registrierung und zählt nie.

Ein Team, drei Erinnerungen

Ein Store hält viele Stimmen auseinander. Registriere eine Person einmal, speichere jede Äußerung unter ihrem Sprecher und frage später nach Person.

addRegistriere Bob einmal: POST /speakers, oder add_speaker("Bob") in den SDKs.

Der Store kennt Bob jetzt. Das 50er-Limit wird hier bei der Registrierung gezählt; Speicheraufrufe liefern nie einen Limit-Fehler.

BobBob sagt, die Deadline sei auf Dienstag gerutscht. Speichere es mit speaker "Bob".

Die Erinnerung gehört jetzt Bob: jede Suche, die sie zurückgibt, sagt das auch.

meDein Assistent verspricht die Zusammenfassung bis Freitag. Speichere seine eigenen Worte mit speaker "me".

Auch die eigenen Worte werden erinnert, und "me" zählt nie gegen das Limit.

askSpäter: "Was hat Bob zur Deadline gesagt?" Suche mit speaker "Bob".

Nur Bobs Worte kommen zurück. Die Worte einer Person kommen nie als die einer anderen zurück.

Drei Regeln zum Merken

  • "me" ist der Assistent selbst. Nie registriert, nie gezählt. Reserviert und kleingeschrieben: speaker: "Me" oder "ME" liefert 400 invalid_request_error statt stiller Umdeutung.
  • Das Limit zählt bei der Registrierung: zunächst 50 pro Store. Darüber hinaus liefert die Registrierung 400 invalid_request_error mit speaker_limit: 50 im Fehlerbody. Speichern mit unregistriertem Namen liefert ebenfalls 400 und speichert nichts. Suche mit unregistriertem Namen im Filter liefert 404 not_found_error. Verzweige auf Status und Felder, nicht auf den Meldungstext; wir planen, das Limit anzuheben.
  • Labels leben in jeder Leseoperation. Suchergebnisse, der Langzeit-Kontext von recall und Engram-Ergebnisse tragen ihren Sprecher — das Modell weiß immer, wessen Worte es hält. Mit speaker in der Suche kommen nur die Worte einer Person zurück. Ein supersede behält den Sprecher; forget entfernt ihn.
  • Namen sind Unicode: jede Sprache funktioniert. さくら, Иван und 하늘 sind gültige Sprecher, und die Zuordnung verhält sich in jeder Sprache identisch. Der Abgleich ist exakt nach Trim und Unicode-Normalisierung, also sind Bob und bob zwei Personen. Namen sind bis 80 Zeichen lang.
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" } }

Zwei Randnotizen. speaker gehört zu add / store: add_turn merkt sich den ganzen Austausch, Personen-Labels und der Filter kommen aus Erinnerungen mit explizitem speaker. Und Sitzungspassagen (expand) sind Komposite mehrerer Erinnerungen, tragen also kein Label; ein speaker-Filter liefert immer atomare, gelabelte Erinnerungen. Und ein Schreibvorgang, dessen Bedeutung einer gespeicherten Erinnerung nahe genug kommt, wird verworfen - entscheidend ist die Bedeutung, nicht der Wortlaut: ein solcher store liefert status "duplicate" mit expliziter note, speichert nichts und hängt keinen Sprecher an. Auch eine wirklich neue Tatsache, die sich nur in einem Detail von einer vorhandenen unterscheidet ("Schalentierallergie" nach "Erdnussallergie"), fällt unter dieselbe Regel - lesen Sie also status, statt anzunehmen, der Schreibvorgang sei angekommen.

Wir testen das auf die harte Tour: Erinnerungen ohne Namen im Text, abgerufen pro Person. Die Zuordnung kommt aus dem Sprecher-Register, nicht aus Wortabgleich, und verhält sich daher in jeder Sprache gleich.

So nutzt du es

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 }

Die Liste zeigt, wen der Store kennt, mit Erinnerungszahl pro Person gegen das Limit. Entfernen löscht nur die Registrierung: die Erinnerungen bleiben, nur das Namenslabel geht.

Die Erinnerungen einer einzelnen Person lesen

by_speaker gibt zurück, was eine Person gesagt hat, neueste zuerst, ohne Suchanfrage. "me" liefert die eigenen Äußerungen des Assistenten. Gleiche Cursor-Paginierung wie bei Bilder: Geben Sie next_before und next_skip_ids zurück.

page = mem.by_speaker("Bob", limit=50)
page["memories"], page["chunks"]
const page = await mem.bySpeaker("Bob", undefined, { limit: 50 });
let page = mem.by_speaker("Bob", None, 50, None, None).await?;
curl -X POST https://api.wontopos.com/api/v1/memory/by-speaker \
  -H "X-API-Key: $WOS_KEY" \
  -d '{"user_id":"alice","speaker":"Bob","limit":50}'
FeldWas er tut
memoriesDie Erinnerungen, neueste zuerst. Gleiche Struktur, wie eine Suche sie zurückgibt.
chunksFragmente auf Satzebene hinter diesen Erinnerungen - was ein Löschvorgang tatsächlich entfernen würde. Üblicherweise größer als die Anzahl der Erinnerungen und vor einer Bestätigung anzuzeigen. Wird auch als points_to_delete gemeldet.
next_beforeCursor für die nächste Seite, zusammen mit next_skip_ids. Beides ist nötig, weil Erinnerungen denselben Zeitstempel haben können.
speaker ist hier die beim Speichern geschriebene Markierung, keine Suche über den Text. Eine ohne Sprecher gespeicherte Erinnerung ist über die Suche erreichbar, aber nie über by_speaker, auch nicht unter "me".

Sprecher auflisten, durchsehen und entfernen

mem.list_speakers()                    # who is registered
mem.by_speaker("Bob")                 # what Bob said, newest first
mem.remove_speaker("Bob")             # unregister; the memories stay
await mem.listSpeakers();
await mem.bySpeaker("Bob");
await mem.removeSpeaker("Bob");
mem.list_speakers(None).await?;
mem.by_speaker("Bob", None, None, None, None).await?;
mem.remove_speaker("Bob", None).await?;
curl -X GET    .../api/v1/memory/speakers   -d '{"user_id":"alice"}'
curl -X POST   .../api/v1/memory/by-speaker -d '{"user_id":"alice","speaker":"Bob"}'
curl -X DELETE .../api/v1/memory/speakers   -d '{"user_id":"alice","speaker":"Bob"}'
Entwickler

Bilder

Eine Erinnerung kann ein Bild enthalten. Die Engine indexiert das Bild, sodass eine Textanfrage in jeder Sprache darauf passt, auch wenn der Datensatz keine Bildunterschrift, keinen Titel und keinen Alt-Text hat.

Unterstützt ab Tablet 2. Eine Engine, die Bilder nicht implementiert, meldet das namentlich, statt mit einem bloßen 404 zu antworten, sodass Sie ein fehlendes Feature von einer fehlenden Erinnerung unterscheiden können. JPEG, PNG, GIF und WebP.

Ein Bild speichern

Übergeben Sie ein image-Objekt an den normalen add-Aufruf. content darf leer sein; das Bild ist dann für sich allein durchsuchbar.

mem.add("at the beach", image={"data": b64})   # caption + image
mem.add("", image={"data": b64})               # the image IS the memory
// the image rides in the 4th argument; the 3rd is metadata
await mem.add("at the beach", undefined, {}, { image: { data: b64 } });
await mem.add("", undefined, {}, { image: { data: b64 } });   // the image IS the memory
let img = json!({"image": {"data": b64}});
mem.add_with("at the beach", None, json!({}), img.clone()).await?;
mem.add_with("", None, json!({}), img).await?;
curl -X POST https://api.wontopos.com/api/v1/memory/store \
  -H "X-API-Key: $WOS_KEY" -H "Content-Type: application/json" \
  -d '{"user_id":"alice","content":"","image":{"data":"<base64>"}}'

data ist erforderlich. Ein Präfix data:image/jpeg;base64, sowie die von base64 und openssl eingefügten Zeilenumbrüche werden für Sie entfernt.

FeldWas er tut
dataBase64 des Bildes. Erforderlich. Die Größenobergrenze ist eine Servereinstellung, keine SDK-Konstante - /health meldet sie als memory.images.max_bytes.
referenceWo Ihre eigene Kopie des Originals liegt. Wird als Zeichenkette gespeichert und von uns nie abgerufen.
taken_atRFC3339, üblicherweise aus EXIF. Füllt event_date, wenn dieses leer ist, sodass die Erinnerung nach dem Aufnahmezeitpunkt sortiert wird und nicht nach dem Zeitpunkt des Hochladens.

Ein Bild finden

Es gibt keine separate Bildsuche. search und recall geben Bilder zusammen mit Text zurück, gemeinsam gerankt.

Mit vorhandenen Bilder arbeiten

data, mime = mem.get_image(memory_id=mid)
page       = mem.list_images(limit=50)      # page["count"] = store total
mem.forget_image(memory_id=mid, preview=True)
const { bytes, contentType } = await mem.getImage(undefined, mid);
const page = await mem.listImages(undefined, { limit: 50 });
await mem.forgetImage(undefined, mid, { preview: true });
let (bytes, mime) = mem.get_image(None, mid).await?;
let page = mem.list_images(None, 50, None, None).await?;
mem.forget_image(None, mid, true).await?;
# original bytes — the one call on this plane that is not JSON
curl -X POST   .../api/v1/memory/image  -d '{"user_id":"alice","memory_id":"m_1"}'
curl -X POST   .../api/v1/memory/images -d '{"user_id":"alice","limit":50}'
curl -X DELETE .../api/v1/memory/image  -d '{"user_id":"alice","memory_id":"m_1","preview":true}'
AufrufWas er tut
get_imageDie Originalbytes, als (bytes, content_type). Der Typ wird aus den Bytes ermittelt, nicht aus dem Namen, unter dem hochgeladen wurde. Eine Erinnerung ohne Bild löst einen Fehler aus, statt etwas Leeres zurückzugeben.
list_imagesEine Seite, neueste zuerst, plus count - die Gesamtzahl im Store, nicht die Seitengröße. Die Paginierung läuft über einen Cursor: Geben Sie next_before und next_skip_ids zurück. Beides ist nötig, weil Bilder denselben Zeitstempel haben können.
forget_imageEntfernt das Bild und behält den Text. Ein ohne Bildunterschrift gespeichertes Bild ist die Erinnerung, dort wird also auch die Erinnerung gelöscht.

Übergeben Sie preview=True an forget_image, um memory_kept zu erhalten, ohne etwas zu ändern. iter_images übernimmt die Paginierung für Sie.

Was ein Bild kostet

Ein Bild wird in Token abgerechnet, derselben Einheit wie Text. Token = Fläche in Pixeln / 556,7. Ab 1.568 px an der langen Kante wird mit 1.568 px gerechnet, ein Bild mit 2.500 px kostet also so viel wie eines mit 1.568 px.

BildGezählt beiTokens
700 × 700as sent881
1000 × 1000as sent1,797
1568 × 1568as sent4,417
1920 × 10801568 × 8822,485
2500 × 18751568 × 11763,313
2500 × 25001568 × 15684,417

Obergrenze: 4.417 Token pro Bild. Wir reservieren diese Obergrenze vor dem Aufruf von Ihrem Guthaben und rechnen danach den gemessenen Wert ab, der nie höher ausfällt.

Zu große und zu kleine Bilder werden mit einem 400 abgelehnt. Wir skalieren sie nicht für Sie. Beide Kanten müssen ≥ 700 px sein, die lange Kante ≤ 2.500 px. Unterhalb von 700 px berechnet der Embedder einen pauschalen Mindestbetrag, ein kleineres Bild kostet in der Speicherung also gleich viel. Skalieren Sie vor dem Senden; der Fehler nennt sowohl die empfangene als auch die erforderliche Größe.

Wie viele zurückkommen

Standard 1, maximal 5 Bilder pro Antwort. Fünf Bilder sind knapp 20.000 Tokens.

FeldWas er tut
max_images0 bis 5. Bilder, die eine einzelne Antwort enthalten darf. Standard 1. 0 gibt nur Text zurück. Werte außerhalb des Bereichs werden abgelehnt, nicht begrenzt.
Eine englische Bildunterschrift an einem Bild verbessert Anfragen auf Englisch und verschlechtert Anfragen in anderen Sprachen - im Mittel über vierzehn Sprachen 11,4 Punkte recall@5. Speichern Sie Bilder ohne Bildunterschrift, wenn Ihre Nutzer in mehr als einer Sprache suchen.
Entwickler

verify

verify erlaubt einer Suche zusätzliche Durchläufe. Jeder Durchlauf schließt aus, was frühere Durchläufe zurückgegeben haben, sodass ein zweiter Durchlauf Erinnerungen erreicht, die der erste nicht erreicht hat.

Unterstützt ab Tablet 2. Eine Anfrage an eine Engine, die es nicht implementiert, wird abgelehnt, bevor der Aufruf erfolgt, sodass Ihnen nie ein Durchlauf berechnet wird, der stillschweigend nichts getan hat.

Eine Ganzzahl 0-3 bei search und recall. Es ist die Anzahl der zusätzlichen Durchläufe, 3 erlaubt also vier Abrufe. Standard 0.

hits = mem.search("what did I eat", verify=3)
# the SDKs hand back the memories; `verify_used` is on the HTTP response (curl tab)
const hits = await mem.search("what did I eat", undefined, 10, { verify: 3 });
// the SDKs hand back the memories; `verify_used` is on the HTTP response (curl tab)
let hits = mem.search_opts("what did I eat", None, 10,
                            &SearchOpts { verify: Some(3), ..Default::default() }).await?;
// the SDKs hand back the memories; `verify_used` is on the HTTP response (curl tab)
curl -X POST https://api.wontopos.com/api/v1/memory/search \
  -H "X-API-Key: $WOS_KEY" -H "Content-Type: application/json" \
  -d '{"user_id":"alice","query":"what did I eat","verify":3}'
# → {"memories":[…], "verify_used":1}

In dieser Schleife läuft kein Sprachmodell

Die Durchläufe führen die bereits zurückgegebenen IDs mit; die Engine schließt sie aus und sucht darüber hinaus. Die Anfrage wird nicht umformuliert, die Ergebnisse sind für eine gegebene Anfrage also deterministisch, und es sind keine Modell-Zugangsdaten beteiligt. Ihr Code entscheidet, ob ein weiterer Durchlauf aufgewendet wird.

Was Sie senden und was zurückkommt

AufrufWas er tut
verify0 bis 3. Zulässige zusätzliche Durchläufe. Werte außerhalb des Bereichs werden mit einem 400 abgelehnt, statt stillschweigend begrenzt zu werden.
verify_usedWie viele zusätzliche Durchläufe tatsächlich ausgeführt wurden. Kann niedriger sein als angefordert.

Die Durchläufe brechen vorzeitig ab, sobald einer nichts Neues zurückgibt; nicht genutzte Durchläufe werden nicht berechnet. Schlägt ein späterer Durchlauf fehl, werden die bis dahin gesammelten Ergebnisse zurückgegeben.

Zusätzliche Durchläufe können die Genauigkeit senken, wenn der erste Durchlauf die Antwort bereits enthielt - Fragen vom Typ single-session-user fallen bei LongMemEval-S um 4,2 Punkte. Der Gewinn skaliert damit, wie oft ein einzelner Abruf danebenliegt, und ist bei großen Stores daher größer.
Add-on · Beta

MCP - Gedächtnis für KI-Tools

Der Kern von WOS sind API und SDKs. Der MCP-Server ist ein Add-on darüber: dasselbe Gedächtnis, eingesteckt in Tools, die du nicht gebaut hast - Claude Code, Claude Desktop, Cursor.

Eine Installationszeile gibt dem Agenten neun Gedächtnis-Tools, die er selbstständig nutzt. Und weil das Gedächtnis im Konto lebt, erinnert jedes andere Tool, was eines schreibt - auch Agenten, die du mit dem SDK baust.

Was damit möglich ist

  • Ein Claude Code, der sich an dein Projekt erinnert. Entscheidungen, Bugfixes, Vorlieben - in der nächsten Sitzung abgerufen, ohne etwas neu zu erklären.
  • In ChatGPT anfangen, in Claude weitermachen. Gleicher Store, gleiches Gedächtnis - das Gespräch wechselt das Tool, statt neu zu starten.
  • Dein eigener Agent bleibt im Kreis. Was Claude Code lernt, ruft ein SDK-Agent ab - und was dein Agent speichert, erinnert Claude Code zurück.

Läuft in Claude Code, Claude Desktop, Cursor, Windsurf und jedem MCP-Host. ChatGPT erreicht dasselbe Gedächtnis über Actions plus die OpenAPI-Spec.

Installation

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

Der Agent bekommt neun Tools - recall · remember · search · update · forget · list_memories · engram · stats · create_store - jedes so beschrieben, dass er selbst weiß, wann er sie nutzt.

Das Add-on selbst ist gratis und auf npm veröffentlicht - du zahlst nur die normalen Nutzungspreise für seine API-Aufrufe. Braucht Node 18+ und einen API-Key aus der Konsole.

Entwicklerseite öffnen

Add-on

OpenAPI-Spec

Die vollständige maschinenlesbare Karte der API - jeder Endpoint, Request, Response und Fehler.

OpenAPI ist das Industriestandard-Format, um eine HTTP-API in einer maschinenlesbaren Datei zu beschreiben.

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

Was damit möglich ist

Postman: File → Import → URL einfügen - alle Endpoints erscheinen als klickbare Collection. ChatGPT: GPT erstellen, Action hinzufügen, dieselbe URL einfügen. Codegen: openapi-generator -i .../openapi.json -g go baut einen Client in einer Sprache, die wir nicht ausliefern.

In Postman importieren, einen Client in einer Sprache generieren, die wir nicht ausliefern, ChatGPT Actions anbinden oder Contract-Checks in CI fahren. Ein Test pinnt sie an die echten Routen - sie kann nicht driften.

Add-on

llms.txt

Die ganze API auf einer Textseite, die eine KI lesen kann.

llms.txt ist eine Web-Konvention: eine Klartextseite an der Site-Root, die einer KI alles Nötige über ein Produkt sagt.

https://wontopos.com/llms.txt

In die IDE oder den Coding-Agenten legen - er weiß sofort, wie man auf WOS baut: Auth, Endpoints, Patterns, Fehler. Mit jedem Release aktualisiert.

Dieselben Fakten wie die OpenAPI-Spec, anderes Publikum: Die Spec ist präzise Struktur für Tools, diese Datei ist Prosa, die eine KI (oder ein Mensch) in einem Zug liest. Beide aktualisieren sich mit jedem Release.

Model Context Protocol · Beta

Dein Gedächtnis in jedem KI-Tool

Ein Befehl gibt Claude Code, Claude Desktop, Cursor oder jedem MCP-Host ein Langzeitgedächtnis auf Basis deines WOS-Kontos. Kein Integrationscode: Der Agent bekommt neun Gedächtnis-Tools und entscheidet selbst, wann er sie nutzt.

MCP ist Beta. Die neun Tools funktionieren heute und sind getestet, aber die Oberfläche kann sich noch ändern, während wir sie fertigstellen. API und SDKs darunter sind stabil und versioniert.

Installation

Claude Code, eine Zeile (Key vorher in der Konsole erstellen):

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 →

Optionale Env: WONTOPOS_USER_ID setzt den Standard-Store, WONTOPOS_MODEL die Engine, WONTOPOS_BASE_URL ein Self-Hosted-Deployment. WONTOPOS_READ_ONLY=1 schaltet auf Nur-Lesen (nur Recall/Suche/Liste).

Bevor du einen Store teilst

  • Nutze einen eigenen Key. Keys tragen ihren Workspace: Ein nur für MCP erstellter Key begrenzt, was verbundene Tools überhaupt erreichen - und lässt sich in der Konsole rotieren, ohne die App-Keys anzufassen.
  • Nur-Lese-Modus. WONTOPOS_READ_ONLY=1 registriert gar keine Schreib-Tools: Der Agent kann erinnern, suchen, Erinnerungen auflisten, Engrams ausführen und Statistiken lesen, aber nichts speichern, aktualisieren, vergessen oder löschen. Richtig für Agenten, die Gedächtnis nutzen, nicht besitzen sollen.
  • Tool-Bestätigung anlassen. MCP-Hosts fragen standardmäßig vor jedem Tool-Lauf - lass das besonders für forget an, denn Löschungen teilen sich alle Tools des Stores.
  • Alles Gespeicherte kann jedes Tool mit dem Key abrufen. Speichere niemals Geheimnisse - API-Keys, Passwörter - als Erinnerungen.
  • Erinnerte Inhalte sind Daten, keine Anweisungen. Die Tool-Beschreibungen sagen das dem Agenten explizit. Speichere trotzdem keinen nicht vertrauenswürdigen Fremdtext in einem Store, dem ein autonomer Agent folgt.
  • Löschungen werden ebenfalls geteilt. Ein forget oder delete_all aus einem Tool löscht für alle.
  • "me" meint den Agenten, der in den Store schreibt. Teilen sich mehrere Agenten einen Store, verschmelzen ihre "me"-Stimmen. Gib jedem Agenten einen eigenen Store (WONTOPOS_USER_ID) für getrennte Identitäten.
  • Ein Konto zahlt. Alle verbundenen Tools ziehen vom selben Guthaben und Rate-Limit.

Dann einfach reden

youmerk dir, dass wir freitags releasen

Der Agent ruft das Tool remember auf. Dauerhaft im Store gespeichert: Das Sitzungsende ändert nichts.

new sessionwann releasen wir?

Eine neue Sitzung hat null Verlauf. Der Agent ruft recall auf und antwortet aus dem Gedächtnis: freitags.

Sag einfach

  • "Dieses Repo nutzt pnpm, merk dir das" → remember speichert es; die nächste Sitzung weiß es schon.
  • "Welches Fehlerformat hatten wir letzte Woche festgelegt?" → recall holt die Entscheidung zurück in den Kontext.
  • „Die Deadline ist jetzt Freitag.“ → der Agent merkt, dass es dem widerspricht, was er abgerufen hat, und ruft update auf, um die Erinnerung an Ort und Stelle zu korrigieren.
  • "Das ist falsch, vergiss es" → der Agent findet die Memory-Id und ruft forget auf - dein Host fragt vorher nach.
  • „Was weißt du über mich?“ → list_memories blättert durch alles Gespeicherte, damit der Agent antworten oder aufräumen kann.

Nichts Besonderes zu formulieren - das sind normale Sätze, keine Befehle. Der Agent liest die Tool-Beschreibungen und wählt selbst.

Die neun Tools

  • recall - Kontext in einem Aufruf: jüngste Turns plus relevante Langzeiterinnerungen. Die Tool-Beschreibung weist den Agenten an, es zuerst aufzurufen, wenn Vergangenes zählt.
  • remember - Speichert einen dauerhaften Fakt oder Beschluss. speaker: "me" markiert die eigenen Worte des Agenten; ein registrierter Name, wer es gesagt hat.
  • search - Semantische Suche, mit optionalem speaker-Filter je Person — und filters, um sie zeitlich oder thematisch einzugrenzen ("Was haben wir im Juni entschieden?"), die eine Achse, die Bedeutung allein nicht eingrenzen kann.
  • update - Ersetzt eine Erinnerung, deren Fakt sich geändert hat, und behält die Spur, statt sie zu löschen.
  • forget - Löscht eine Erinnerung per id.
  • list_memories - Blättert durch alles Gespeicherte, damit der Agent "Was weißt du über mich?" beantworten oder aufräumen kann.
  • engram - Führt eine eingebaute Multi-Hop-Pipeline aus (deep_recall, timeline, gather), wenn eine einzelne Suche nicht reicht.
  • stats - Wie viel in einem Store liegt - nützlich vor dem Aufräumen und um zu bestätigen, dass ein Schreibvorgang angekommen ist.
  • create_store - Stores sind explizit: einer pro Endnutzer, Projekt oder Agent.

SDK oder MCP?

  • Das SDK gehört in eine App, die du schreibst. Dein Code entscheidet exakt, wann gespeichert und was erinnert wird - deterministisch, typisiert, versioniert. Du baust ein Produkt? SDK.
  • MCP steckt man in ein KI-Tool, das du nicht geschrieben hast. Der Agent entscheidet anhand der Tool-Beschreibungen, wann er Gedächtnis nutzt - null Code. Richtig für Claude Code, Claude Desktop, Cursor oder um einem fertigen Assistenten Gedächtnis zu geben.

Darunter dieselbe API, dieselben Stores - eine SDK-App und eine Claude-Code-Sitzung über MCP teilen ein Gedächtnis. Man wählt pro Oberfläche, nicht entweder-oder.

Ein Gedächtnis über alle Tools hinweg

Das Gedächtnis gehört dem Konto, nicht dem Tool. Derselbe Store, aus ChatGPT (Actions plus OpenAPI-Spec) geschrieben, wird in Claude Code und in deinen eigenen Agenten erinnert, und umgekehrt: Ein Gespräch, das in einem Tool beginnt, geht in einem anderen weiter.

Und weil es ein Store ist, kannst du Claude Code verlassen und dort weiterreden, wo du baust: Ein SDK-Agent mit demselben Key und Store erinnert alles, was Claude Code gerade gelernt hat - und was dein Agent speichert, erinnert Claude Code in der nächsten Sitzung.

Läuft lokal über stdio (npx wontopos-mcp): Bei dieser Methode bleibt dein Key in deiner Umgebung und wird nie als Teil einer MCP-Sitzung an uns gesendet. Es umschließt das TypeScript-SDK, sodass automatische Wiederholungen, Redirect-Verweigerung und Key-Maskierung unverändert gelten.
Model Context Protocol · Beta

Claude Code

Der Hauptweg: ein Befehl im Terminal, und jede Sitzung startet mit Gedächtnis.

  1. Erstelle einen API-Key in der Konsole. Der Key trägt seinen Workspace: ein Key = ein Gedächtnisraum.
  2. Registriere den Server. --scope user macht ihn in jedem Projekt verfügbar; ohne sieht ihn nur das aktuelle Projekt.
  3. Prüfen: /mcp in Claude Code ausführen - wontopos sollte mit neun Tools gelistet sein.
  4. Mach es automatisch: eine Zeile in deiner CLAUDE.md - "wenn Vergangenes zählt, zuerst wontopos recall aufrufen" - und jede Sitzung startet ungefragt mit Gedächtnis.
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

Füge den Block unten in claude_desktop_config.json ein (Einstellungen → Developer → Edit Config), starte die App neu - die neun Tools erscheinen. Hinweis: claude.ai im Web und mobil braucht einen Remote-MCP-Server, den WOS noch nicht anbietet - die Desktop-App ist der unterstützte Weg.

# 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

Füge den Block unten in ~/.cursor/mcp.json ein - oder nutze den Ein-Klick-Button - und starte Cursor neu. Der Agent übernimmt die neun Tools.

# ~/.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

VS Code (Copilot-Agentenmodus) liest MCP-Server aus .vscode/mcp.json im Projekt - füge den Block unten ein oder nutze den Ein-Klick-Button.

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

Windsurf (Cascade) liest ~/.codeium/windsurf/mcp_config.json: Block unten einfügen und neu laden - dieselben neun Tools erscheinen.

# ~/.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

ChatGPTs MCP-Konnektoren akzeptieren nur Remote-Server; der unterstützte Weg ist heute ein Custom GPT mit einer Action: GPT erstellen, Action hinzufügen, die OpenAPI-Spec-URL unten einfügen und den API-Key als Auth-Header setzen. Dieses GPT ruft dann dasselbe Gedächtnis auf wie deine anderen Tools.

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

Gleicher Store, gleiches Gedächtnis: Was ChatGPT über die Action speichert, erinnert Claude Code über MCP - und umgekehrt.

Model Context Protocol · Beta

Gemini CLI

Gemini CLI liest MCP-Server aus ~/.gemini/settings.json: Block unten einfügen, CLI neu starten - dieselben neun Tools erscheinen auch dort.

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

Python - jede Methode, drei Gruppen.

Schreiben, Lesen, Löschen. Jedes Beispiel unten wurde am 2026-08-01 gegen die Live-API ausgeführt; die Antworten sind wortwörtlich wiedergegeben.

pip install wontopos
from wontopos import Client

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

Modell wählen

Der API-Schlüssel bestimmt, welches Gedächtnis (Ihr Konto); das Modell bestimmt, welche Engine es liest. Alle Modelle teilen sich ein Gedächtnis, Sie können also mit einem speichern und mit einem anderen abrufen. Setzen Sie einen Standard am Client; überschreiben Sie einen einzelnen Aufruf, indem Sie ihm model= übergeben.

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

Der Katalog - die IDs, die Sie an model übergeben können, und ob sie jeweils live sind. Modelle mit memory: "shared" lesen denselben Store; "isolated" führt einen eigenen. Benötigt keinen API-Schlüssel.

mem.list_models()
Tatsächliche Antwort
[{"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

Verbindung und Gültigkeit des API-Schlüssels in einer Zeile prüfen.

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

Der Katalog oben spiegelt stets die aktuell verfügbaren Modelle wider - übergeben Sie eine andere ID, erhalten Sie einen klaren Fehler. Neue Modelle erscheinen dort automatisch, sobald sie ausgeliefert werden.

Schreiben

add

Eine Erinnerung speichern. Beim Eingang eingebettet - kein LLM-Aufruf, Sie zahlen nur 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
Tatsächliche Antwort
{"id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "stored (1 chunks)"}

add_turn

Einen Gesprächszug (Nutzer + Assistent) zugleich ins Kurzzeit- und Langzeitgedächtnis speichern.

mem.add_turn("hi", "hello!", user_id="alice")
Tatsächliche Antwort
{"status": "ok"}

speaker

Jede Erinnerung kann tragen, wer sie gesagt hat. Registriere eine Person einmal und übergib danach ihren Namen als speaker; "me" (die eigenen Worte des Assistenten) braucht nie eine Registrierung. Auch die Suche akzeptiert speaker, um nur die Worte einer Person zu holen.

mem.add_speaker("Bob", user_id="alice")  # once per person; "me" needs no registration
mem.add("I promised to send the report on Friday", user_id="alice", speaker="me")
mem.add("Bob said the deadline moved to Tuesday", user_id="alice", speaker="Bob")
mem.search("what did Bob say about deadlines?", user_id="alice", speaker="Bob")
response
[{"content": "Bob said the deadline moved to Tuesday", "speaker": "Bob", ...}]
Sprecher sind explizit, wie Stores. Registriere die Person zuerst, speichere dann unter ihrem Namen: ein Tippfehler wird nie still zu einer neuen Person. Ein Store registriert zunächst bis zu 50 Personen (wir planen mehr), und "me" braucht nie Registrierung und zählt nie.

add_bulk

Einen großen Textblock nachladen. Serverseitig zerlegt und eingebettet - ideal zum Import bestehender Historie.

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

update

Ein Fakt hat sich geändert. Die alte Erinnerung wird als ersetzt markiert (für die Historie behalten); die neue nimmt ihren Platz im Recall ein.

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

Lesen

search

Semantische Suche, das Relevanteste zuerst. Reines Embedding - kein Keyword-Matching, jede Sprache findet also jede Erinnerung. Das SDK gibt das memories-Array direkt zurück; der rohe HTTP-Body ist unten abgebildet. Bei einem Modell mit eigener Spur (Scroll 1.2+) antwortet der Dienst in zwei Spuren und das SDK gibt beide zusammengeführt zurück - das Array kann also MEHR als max_results enthalten. Bemessen Sie Ihr Prompt-Fenster an dem, was Sie erhalten, nicht an der angeforderten Zahl.

r = mem.search("what does she drink?", user_id="alice", limit=1)
Tatsächliche Antwort (HTTP-Body)
[{
   "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"
 }]
FeldBedeutung
similarityRohe Embedding-Ähnlichkeit zu Ihrer Abfrage (0–1).
is_supersededTrue, wenn dieser Fakt durch update() ersetzt wurde.
search_msServerseitige Abrufzeit.

recall

Ein Roundtrip liefert alles, was Ihr LLM braucht - fügen Sie das Ergebnis direkt in Ihren Prompt ein: ein begrenzter Kontext fester Größe, egal wie viel Sie gespeichert haben.

ctx = mem.recall("what does she drink?", user_id="alice")
Tatsächliche Antwort (Struktur - Listen gekürzt)
{"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

Jüngste Gesprächszüge (Kurzzeitgedächtnis), älteste zuerst.

turns = mem.history("alice")
Tatsächliche Antwort (HTTP-Body)
{"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

Anzahl der Erinnerungen für einen Nutzer.

mem.stats("alice")
Tatsächliche Antwort
{"short_term_turns": 2, "total_memories": 4, "user_id": "alice"}

get

Ruft eine einzelne Erinnerung per id ab - die id, die add oder list_memories zurückgegeben hat. Nur der gespeicherte Originaltext plus Metadaten, nie der Vektor. Eine id aus einem anderen Store oder eine gelöschte/invalidierte Erinnerung ergibt 404.

m = mem.get("alice", memory_id="576700aa-...")
response
{"id": "576700aa-...", "content": "she prefers tea over coffee",
 "category": "general", "created_at": "2026-07-10T04:20:39Z", "event_date": null,
 "is_superseded": false, "superseded_by": null}
Tatsächliche Antwort
{"memory": {"id": "8bd090de-...", "content": "the office moved to the seventh floor in June",
  "category": "general", "created_at": "2026-07-31T18:20:30.531518060+00:00", "event_date": null,
  "is_superseded": false, "superseded_by": null}, "user_id": "docs_livetest"}

list_memories

Listet die Erinnerungen eines Stores auf - nur der gespeicherte Originaltext und seine Metadaten, nie der Vektor. Seitenweise per Cursor: den zurückgegebenen next_cursor für die nächste Seite mitgeben.

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

iter_memories · export_memories

Alle Erinnerungen ohne Cursor-Verwaltung durchlaufen oder den ganzen Store auf einmal holen.

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

Löschen

delete

Eine einzelne Erinnerung per ID löschen.

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

delete_all

Alles für einen Nutzer löschen - ein Aufruf, DSGVO-bereit.

mem.delete_all("alice")
Tatsächliche Antwort
{"memories_deleted": 4, "status": "deleted", "user_id": "alice"}

Fehler und Zuverlässigkeit

Jeder Fehler ist typisiert - fange den konkreten (Rate-Limit, Auth, Zahlung) oder alle mit dem Basis-WosError.

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

Lies das verbleibende Kontingent nach jedem Aufruf und drossle, bevor du das Limit erreichst.

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

search_self

Beide Spuren aus einem Aufruf bei einem Selbstgedächtnis-Modell (Scroll 1.2+): was andere sagten und die EIGENEN Worte des Agenten - getrennt gehalten, damit der Leser nie verwechselt, wer was gesagt hat.

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

list_engrams

Frag den Dienst, welche Engramme und Delivery-Formen das gewählte Modell ausführen kann, statt Namen fest zu verdrahten, die veralten, sobald ein neues erscheint.

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

filters

Grenzt die Suche auf einen Teil des Stores ein. Wird vor dem Ranking angewendet, du bekommst also die besten Treffer innerhalb des Filters - kein nachträglich gefiltertes Top-N.

mem.search("what did we decide", user_id="alice", filters={
    "categories": ["work"],
    "event_from": "2026-01-01",   # when it HAPPENED
})
Schlüssel: categories · event_from / event_to (wann der Inhalt GESCHAH - metadata.event_date) · time_from / time_to (wann er geschrieben wurde) · min_importance. Nicht aufgeführte Schlüssel werden verworfen, nicht abgelehnt - ein Tippfehler erweitert die Suche also stillschweigend.

idempotency_key

Macht das Wiederholen eines Schreibvorgangs sicher. Nutze ihn, wenn der Retry von dir kommt - ein Job, der abgebrochen und neu gestartet wurde, eine Queue, die erneut zustellt.

mem.add("she prefers tea", "alice", idempotency_key=f"import:{row.id}")
Leite den Schlüssel aus dem ab, was gespeichert wird (import:row-42), nie eine Konstante: ein Schlüssel, der für zwei verschiedene Schreibvorgänge wiederverwendet wird, spielt den ersten erneut ab - der zweite geht stillschweigend verloren. Format: 1-128 Zeichen aus [A-Za-z0-9._:-].

with_timeout / with_retries

Stelle eine einzelne Aufrufstelle ein, ohne den bereits gebauten Client anzufassen: ein Klon mit längerem Timeout für einen großen Backfill oder mit abgeschalteten Retries innerhalb deiner eigenen Retry-Schleife.

mem.with_timeout(120).add_bulk(big_blob, "alice")  # this slow call only
mem.with_retries(0).add("...", "alice")              # you retry, not the SDK
TypeScript-SDK

TypeScript - jede Methode, drei Gruppen.

Schreiben, Lesen, Löschen. Jedes Beispiel unten wurde am 2026-08-01 gegen die Live-API ausgeführt; die Antworten sind wortwörtlich wiedergegeben.

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

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

Modell wählen

Der API-Schlüssel bestimmt, welches Gedächtnis (Ihr Konto); das Modell bestimmt, welche Engine es liest. Alle Modelle teilen sich ein Gedächtnis, Sie können also mit einem speichern und mit einem anderen abrufen. Setzen Sie einen Standard im Konstruktor; überschreiben Sie einen einzelnen Aufruf mit 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

Der Katalog - die IDs, die Sie an model übergeben können, und ob sie jeweils live sind. Modelle mit memory: "shared" lesen denselben Store; "isolated" führt einen eigenen. Benötigt keinen API-Schlüssel.

await mem.listModels();
Tatsächliche Antwort
[{"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

Verbindung und Gültigkeit des API-Schlüssels in einer Zeile prüfen.

await mem.ping();   // true, or throws AuthenticationError / PaymentRequiredError

Der Katalog oben spiegelt stets die aktuell verfügbaren Modelle wider - übergeben Sie eine andere ID, erhalten Sie einen klaren Fehler. Neue Modelle erscheinen dort automatisch, sobald sie ausgeliefert werden.

Schreiben

add

Eine Erinnerung speichern. Beim Eingang eingebettet - kein LLM-Aufruf, Sie zahlen nur 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
Tatsächliche Antwort
{"id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "stored (1 chunks)"}

addTurn

Einen Gesprächszug (Nutzer + Assistent) zugleich ins Kurzzeit- und Langzeitgedächtnis speichern.

await mem.addTurn("hi", "hello!", "alice");
Tatsächliche Antwort
{"status": "ok"}

speaker

Jede Erinnerung kann tragen, wer sie gesagt hat. Registriere eine Person einmal und übergib danach ihren Namen als speaker; "me" (die eigenen Worte des Assistenten) braucht nie eine Registrierung. Auch die Suche akzeptiert speaker, um nur die Worte einer Person zu holen.

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" });
Sprecher sind explizit, wie Stores. Registriere die Person zuerst, speichere dann unter ihrem Namen: ein Tippfehler wird nie still zu einer neuen Person. Ein Store registriert zunächst bis zu 50 Personen (wir planen mehr), und "me" braucht nie Registrierung und zählt nie.

addBulk

Einen großen Textblock nachladen. Serverseitig zerlegt und eingebettet - ideal zum Import bestehender Historie.

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

update

Ein Fakt hat sich geändert. Die alte Erinnerung wird als ersetzt markiert (für die Historie behalten); die neue nimmt ihren Platz im Recall ein.

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

Lesen

search

Semantische Suche, das Relevanteste zuerst. Reines Embedding - kein Keyword-Matching, jede Sprache findet also jede Erinnerung. Das SDK gibt das memories-Array direkt zurück; der rohe HTTP-Body ist unten abgebildet. Bei einem Modell mit eigener Spur (Scroll 1.2+) antwortet der Dienst in zwei Spuren und das SDK gibt beide zusammengeführt zurück - das Array kann also MEHR als max_results enthalten. Bemessen Sie Ihr Prompt-Fenster an dem, was Sie erhalten, nicht an der angeforderten Zahl.

const r = await mem.search("what does she drink?", "alice", 1);
Tatsächliche Antwort (HTTP-Body)
[{
   "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"
 }]
FeldBedeutung
similarityRohe Embedding-Ähnlichkeit zu Ihrer Abfrage (0–1).
is_supersededTrue, wenn dieser Fakt durch update() ersetzt wurde.
search_msServerseitige Abrufzeit.

recall

Ein Roundtrip liefert alles, was Ihr LLM braucht - fügen Sie das Ergebnis direkt in Ihren Prompt ein: ein begrenzter Kontext fester Größe, egal wie viel Sie gespeichert haben.

const ctx = await mem.recall("what does she drink?", "alice");
Tatsächliche Antwort (Struktur - Listen gekürzt)
{"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

Jüngste Gesprächszüge (Kurzzeitgedächtnis), älteste zuerst.

const turns = await mem.history("alice");
Tatsächliche Antwort (HTTP-Body)
{"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

Anzahl der Erinnerungen für einen Nutzer.

await mem.stats("alice");
Tatsächliche Antwort
{"short_term_turns": 2, "total_memories": 4, "user_id": "alice"}

get

Ruft eine einzelne Erinnerung per id ab - die id, die add oder list_memories zurückgegeben hat. Nur der gespeicherte Originaltext plus Metadaten, nie der Vektor. Eine id aus einem anderen Store oder eine gelöschte/invalidierte Erinnerung ergibt 404.

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

listMemories

Listet die Erinnerungen eines Stores auf - nur der gespeicherte Originaltext und seine Metadaten, nie der Vektor. Seitenweise per Cursor: den zurückgegebenen next_cursor für die nächste Seite mitgeben.

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", "created_at": "2026-07-10T04:20:39Z", "event_date": null,
 "is_superseded": false, "superseded_by": null}
 ]}

iterMemories · exportMemories

Alle Erinnerungen ohne Cursor-Verwaltung durchlaufen oder den ganzen Store auf einmal holen.

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

Löschen

delete

Eine einzelne Erinnerung per ID löschen.

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

deleteAll

Alles für einen Nutzer löschen - ein Aufruf, DSGVO-bereit.

await mem.deleteAll("alice");
Tatsächliche Antwort
{"memories_deleted": 4, "status": "deleted", "user_id": "alice"}

Fehler und Zuverlässigkeit

Jeder Fehler ist typisiert - fange den konkreten (Rate-Limit, Auth, Zahlung) oder alle mit dem Basis-WosError.

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

Lies das verbleibende Kontingent nach jedem Aufruf und drossle, bevor du das Limit erreichst.

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

searchSelf

Beide Spuren aus einem Aufruf bei einem Selbstgedächtnis-Modell (Scroll 1.2+): was andere sagten und die EIGENEN Worte des Agenten - getrennt gehalten, damit der Leser nie verwechselt, wer was gesagt hat.

const { memories, self_memories } = await mem.searchSelf("what did I promise?", "alice");
// memories = what others said · self_memories = the agent's OWN words

listEngrams

Frag den Dienst, welche Engramme und Delivery-Formen das gewählte Modell ausführen kann, statt Namen fest zu verdrahten, die veralten, sobald ein neues erscheint.

const { engrams, forms } = await mem.listEngrams();  // ask, never hard-code

filters

Grenzt die Suche auf einen Teil des Stores ein. Wird vor dem Ranking angewendet, du bekommst also die besten Treffer innerhalb des Filters - kein nachträglich gefiltertes Top-N.

await mem.search("what did we decide", "alice", 10, {
  filters: { categories: ["work"], event_from: "2026-01-01" },  // when it HAPPENED
});
Schlüssel: categories · event_from / event_to (wann der Inhalt GESCHAH - metadata.event_date) · time_from / time_to (wann er geschrieben wurde) · min_importance. Nicht aufgeführte Schlüssel werden verworfen, nicht abgelehnt - ein Tippfehler erweitert die Suche also stillschweigend.

idempotencyKey

Macht das Wiederholen eines Schreibvorgangs sicher. Nutze ihn, wenn der Retry von dir kommt - ein Job, der abgebrochen und neu gestartet wurde, eine Queue, die erneut zustellt.

await mem.add("she prefers tea", "alice", {}, { idempotencyKey: `import:${row.id}` });
Leite den Schlüssel aus dem ab, was gespeichert wird (import:row-42), nie eine Konstante: ein Schlüssel, der für zwei verschiedene Schreibvorgänge wiederverwendet wird, spielt den ersten erneut ab - der zweite geht stillschweigend verloren. Format: 1-128 Zeichen aus [A-Za-z0-9._:-].

withTimeout / withRetries

Stelle eine einzelne Aufrufstelle ein, ohne den bereits gebauten Client anzufassen: ein Klon mit längerem Timeout für einen großen Backfill oder mit abgeschalteten Retries innerhalb deiner eigenen Retry-Schleife.

await mem.withTimeout(120_000).addBulk(bigBlob, "alice");  // this slow call only
await mem.withRetries(0).add("...", "alice");            // you retry, not the SDK
Rust-SDK

Rust - jede Methode, drei Gruppen.

Schreiben, Lesen, Löschen. Jedes Beispiel unten wurde am 2026-08-01 gegen die Live-API ausgeführt; die Antworten sind wortwörtlich wiedergegeben.

cargo add wontopos
use wontopos::Client;

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

Modell wählen

Der API-Schlüssel bestimmt, welches Gedächtnis (Ihr Konto); das Modell bestimmt, welche Engine es liest. Alle Modelle teilen sich ein Gedächtnis, Sie können also mit einem speichern und mit einem anderen abrufen. Setzen Sie einen Standard mit with_model(); verketten Sie es erneut, um einen einzelnen Aufruf zu überschreiben.

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

Der Katalog - die IDs, die Sie an with_model übergeben können, und ob sie jeweils live sind. Modelle mit memory: "shared" lesen denselben Store; "isolated" führt einen eigenen. Benötigt keinen API-Schlüssel.

mem.list_models().await?;
Tatsächliche Antwort
[{"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

Verbindung und Gültigkeit des API-Schlüssels in einer Zeile prüfen.

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

Der Katalog oben spiegelt stets die aktuell verfügbaren Modelle wider - übergeben Sie eine andere ID, erhalten Sie einen klaren Fehler. Neue Modelle erscheinen dort automatisch, sobald sie ausgeliefert werden.

Schreiben

add

Eine Erinnerung speichern. Beim Eingang eingebettet - kein LLM-Aufruf, Sie zahlen nur 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
Tatsächliche Antwort
{"id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "stored (1 chunks)"}

add_turn

Einen Gesprächszug (Nutzer + Assistent) zugleich ins Kurzzeit- und Langzeitgedächtnis speichern.

mem.add_turn("hi", "hello!", "alice").await?;
Tatsächliche Antwort
{"status": "ok"}

speaker

Jede Erinnerung kann tragen, wer sie gesagt hat. Registriere eine Person einmal und übergib danach ihren Namen als speaker; "me" (die eigenen Worte des Assistenten) braucht nie eine Registrierung. Auch die Suche akzeptiert speaker, um nur die Worte einer Person zu holen.

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?;
Sprecher sind explizit, wie Stores. Registriere die Person zuerst, speichere dann unter ihrem Namen: ein Tippfehler wird nie still zu einer neuen Person. Ein Store registriert zunächst bis zu 50 Personen (wir planen mehr), und "me" braucht nie Registrierung und zählt nie.

add_bulk

Einen großen Textblock nachladen. Serverseitig zerlegt und eingebettet - ideal zum Import bestehender Historie.

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

update

Ein Fakt hat sich geändert. Die alte Erinnerung wird als ersetzt markiert (für die Historie behalten); die neue nimmt ihren Platz im Recall ein.

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

Lesen

search

Semantische Suche, das Relevanteste zuerst. Reines Embedding - kein Keyword-Matching, jede Sprache findet also jede Erinnerung. Das SDK gibt das memories-Array direkt zurück; der rohe HTTP-Body ist unten abgebildet. Bei einem Modell mit eigener Spur (Scroll 1.2+) antwortet der Dienst in zwei Spuren und das SDK gibt beide zusammengeführt zurück - das Array kann also MEHR als max_results enthalten. Bemessen Sie Ihr Prompt-Fenster an dem, was Sie erhalten, nicht an der angeforderten Zahl.

let r = mem.search("what does she drink?", "alice", 1).await?;
Tatsächliche Antwort (HTTP-Body)
[{
   "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"
 }]
FeldBedeutung
similarityRohe Embedding-Ähnlichkeit zu Ihrer Abfrage (0–1).
is_supersededTrue, wenn dieser Fakt durch update() ersetzt wurde.
search_msServerseitige Abrufzeit.

recall

Ein Roundtrip liefert alles, was Ihr LLM braucht - fügen Sie das Ergebnis direkt in Ihren Prompt ein: ein begrenzter Kontext fester Größe, egal wie viel Sie gespeichert haben.

let ctx = mem.recall("what does she drink?", "alice").await?;
Tatsächliche Antwort (Struktur - Listen gekürzt)
{"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

Jüngste Gesprächszüge (Kurzzeitgedächtnis), älteste zuerst.

let turns = mem.history("alice").await?;
Tatsächliche Antwort (HTTP-Body)
{"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

Anzahl der Erinnerungen für einen Nutzer.

mem.stats("alice").await?;
Tatsächliche Antwort
{"short_term_turns": 2, "total_memories": 4, "user_id": "alice"}

get

Ruft eine einzelne Erinnerung per id ab - die id, die add oder list_memories zurückgegeben hat. Nur der gespeicherte Originaltext plus Metadaten, nie der Vektor. Eine id aus einem anderen Store oder eine gelöschte/invalidierte Erinnerung ergibt 404.

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

list_memories

Listet die Erinnerungen eines Stores auf - nur der gespeicherte Originaltext und seine Metadaten, nie der Vektor. Seitenweise per Cursor: den zurückgegebenen next_cursor für die nächste Seite mitgeben.

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

list_all_memories

Alle Erinnerungen ohne Cursor-Verwaltung durchlaufen oder den ganzen Store auf einmal holen.

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

Löschen

delete

Eine einzelne Erinnerung per ID löschen.

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

delete_all

Alles für einen Nutzer löschen - ein Aufruf, DSGVO-bereit.

mem.delete_all("alice").await?;
Tatsächliche Antwort
{"memories_deleted": 4, "status": "deleted", "user_id": "alice"}

Fehler und Zuverlässigkeit

Jeder Fehler ist typisiert - fange den konkreten (Rate-Limit, Auth, Zahlung) oder alle mit dem Basis-WosError.

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

Lies das verbleibende Kontingent nach jedem Aufruf und drossle, bevor du das Limit erreichst.

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

search_self

Beide Spuren aus einem Aufruf bei einem Selbstgedächtnis-Modell (Scroll 1.2+): was andere sagten und die EIGENEN Worte des Agenten - getrennt gehalten, damit der Leser nie verwechselt, wer was gesagt hat.

let r = mem.search_self("what did I promise?", "alice", 10).await?;
// r.memories = what others said · r.self_memories = the agent's OWN words

list_engrams

Frag den Dienst, welche Engramme und Delivery-Formen das gewählte Modell ausführen kann, statt Namen fest zu verdrahten, die veralten, sobald ein neues erscheint.

let cat = mem.list_engrams().await?;  // ask, never hard-code

filters

Grenzt die Suche auf einen Teil des Stores ein. Wird vor dem Ranking angewendet, du bekommst also die besten Treffer innerhalb des Filters - kein nachträglich gefiltertes Top-N.

mem.search_with("what did we decide", "alice", 10, json!({"filters": {
    "categories": ["work"], "event_from": "2026-01-01"   // when it HAPPENED
}})).await?;
Schlüssel: categories · event_from / event_to (wann der Inhalt GESCHAH - metadata.event_date) · time_from / time_to (wann er geschrieben wurde) · min_importance. Nicht aufgeführte Schlüssel werden verworfen, nicht abgelehnt - ein Tippfehler erweitert die Suche also stillschweigend.

add_idempotent

Macht das Wiederholen eines Schreibvorgangs sicher. Nutze ihn, wenn der Retry von dir kommt - ein Job, der abgebrochen und neu gestartet wurde, eine Queue, die erneut zustellt.

mem.add_idempotent("she prefers tea", "alice", json!({}), &format!("import:{}", row.id)).await?;
Leite den Schlüssel aus dem ab, was gespeichert wird (import:row-42), nie eine Konstante: ein Schlüssel, der für zwei verschiedene Schreibvorgänge wiederverwendet wird, spielt den ersten erneut ab - der zweite geht stillschweigend verloren. Format: 1-128 Zeichen aus [A-Za-z0-9._:-].

with_timeout / with_retries

Stelle eine einzelne Aufrufstelle ein, ohne den bereits gebauten Client anzufassen: ein Klon mit längerem Timeout für einen großen Backfill oder mit abgeschalteten Retries innerhalb deiner eigenen Retry-Schleife.

mem.with_timeout(120).add_bulk(big_blob, "alice", "general").await?;
mem.with_retries(0).add("...", "alice", json!({})).await?;
curl

curl - keine Installation, dieselben Methoden.

Kein SDK zu installieren - jeder HTTP-Client funktioniert. Setzen Sie Ihren Schlüssel einmal und rufen Sie dieselben Endpunkte auf, die die SDKs kapseln. Basis-URL https://api.wontopos.com, Authentifizierung über X-API-Key, JSON rein und raus.

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

Schreiben

store

Eine Erinnerung speichern. Beim Eingang eingebettet - kein LLM-Aufruf.

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

store-turn

Einen Gesprächszug (Nutzer + Assistent) zugleich ins Kurzzeit- und Langzeitgedächtnis speichern.

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!"}'
Tatsächliche Antwort
{"status": "ok"}

speaker

Jede Erinnerung kann tragen, wer sie gesagt hat. Registriere eine Person einmal und übergib danach ihren Namen als speaker; "me" (die eigenen Worte des Assistenten) braucht nie eine Registrierung. Auch die Suche akzeptiert speaker, um nur die Worte einer Person zu holen.

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"}'
Sprecher sind explizit, wie Stores. Registriere die Person zuerst, speichere dann unter ihrem Namen: ein Tippfehler wird nie still zu einer neuen Person. Ein Store registriert zunächst bis zu 50 Personen (wir planen mehr), und "me" braucht nie Registrierung und zählt nie.

supersede

Ein Fakt hat sich geändert - die alte Erinnerung wird als ersetzt markiert, die neue nimmt ihren Platz im Recall ein.

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"}'
Tatsächliche Antwort
{"new_memory_id": "07e94433-...", "old_memory_id": "576700aa-...", "status": "superseded"}

bulk-store

Eine lange Historie in einem Aufruf nachladen - serverseitig aufgeteilt und eingebettet.

curl -X POST https://api.wontopos.com/api/v1/memory/bulk-store \
  -H "X-API-Key: $WOS_API_KEY" -H "Content-Type: application/json" \
  -d '{"user_id":"alice","content":"...a long history...","category":"general"}'
Tatsächliche Antwort
{"elapsed_secs": 0.138589761, "status": "ok", "stored": 1, "total_chunks": 1}

Idempotency-Key

Macht das Wiederholen eines Schreibvorgangs sicher. Nutze ihn, wenn der Retry von dir kommt - ein Job, der abgebrochen und neu gestartet wurde, eine Queue, die erneut zustellt.

# same key + same body = the FIRST response is replayed, nothing is stored twice
curl -X POST https://api.wontopos.com/api/v1/memory/store \
  -H "X-API-Key: $WOS_API_KEY" -H "Content-Type: application/json" \
  -H "Idempotency-Key: import:row-42" \
  -d '{"user_id":"alice","content":"she prefers tea over coffee"}'
Leite den Schlüssel aus dem ab, was gespeichert wird (import:row-42), nie eine Konstante: ein Schlüssel, der für zwei verschiedene Schreibvorgänge wiederverwendet wird, spielt den ersten erneut ab - der zweite geht stillschweigend verloren. Format: 1-128 Zeichen aus [A-Za-z0-9._:-].

Lesen

search

Semantische Suche, das Relevanteste zuerst. Reines Embedding - jede Sprache findet jede Erinnerung.

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

search + filters

Grenzt die Suche auf einen Teil des Stores ein. Wird vor dem Ranking angewendet, du bekommst also die besten Treffer innerhalb des Filters - kein nachträglich gefiltertes Top-N.

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 we decide",
       "filters":{"categories":["work"],"event_from":"2026-01-01","event_to":"2026-06-30"}}'
Schlüssel: categories · event_from / event_to (wann der Inhalt GESCHAH - metadata.event_date) · time_from / time_to (wann er geschrieben wurde) · min_importance. Nicht aufgeführte Schlüssel werden verworfen, nicht abgelehnt - ein Tippfehler erweitert die Suche also stillschweigend.

get

Liest eine Erinnerung anhand der id, die store oder list zurückgab - Originaltext und Metadaten, keine Vektoren.

curl -X POST https://api.wontopos.com/api/v1/memory/get \
  -H "X-API-Key: $WOS_API_KEY" -H "Content-Type: application/json" \
  -d '{"user_id":"alice","memory_id":"576700aa-f0e0-4c26-99a0-10e2d5b0d624"}'

list

Blättert Cursor für Cursor durch alles in einem Store - zum Durchsehen oder Exportieren.

curl -X POST https://api.wontopos.com/api/v1/memory/list \
  -H "X-API-Key: $WOS_API_KEY" -H "Content-Type: application/json" \
  -d '{"user_id":"alice","limit":100}'   # pass next_cursor back for the next page
Tatsächliche Antwort
{"count": 3, "memories": [{"id": "1a1cfc47-...", "content": "...", "category": "general",
   "created_at": "2026-07-31T18:04:51.937117314+00:00", "event_date": null, "is_superseded": false}],
 "next_cursor": "722c08e5-8998-4882-979e-d71995b5b4af", "user_id": "docs_livetest"}

recall

Ein Roundtrip liefert Kurzzeit + Langzeit + Kontext + eine Instruktion. Fügen Sie es direkt in Ihren Prompt ein.

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?"}'
Tatsächliche Antwort (Struktur)
{"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..."}

Löschen

forget

Eine Erinnerung per ID löschen - oder die ID weglassen, um alles für einen Nutzer zu löschen (DSGVO).

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
Tatsächliche Antwort
{"memories_deleted": 1, "status": "deleted", "user_id": "alice"}

Jeder Endpunkt + Body-Felder →

Varianten nur in Rust

Python und TypeScript nehmen diese als optionale Argumente entgegen. Stable Rust kennt keine Standard- oder Schlüsselwortargumente, daher ist jede Variante eine eigene Methode und kein Builder, den Sie abschließen müssen.

mem.add_with(text, None, json!({}), extra)   // add + extra body fields
mem.search_opts(q, None, 10, &opts)            // search + verify / max_images
mem.search_with(q, None, 10, extra)            // search + any other field
mem.recall_with(q, None, extra)                // recall + extra
mem.search_self_with(q, None, 10, extra)       // self lane + extra
mem.engram_with(name, q, None, extra)          // engram + extra
mem.update_idempotent(old, new, None, key)     // update + Idempotency-Key
mem.add_turn_idempotent(u, a, None, key)
mem.add_bulk_idempotent(text, None, cat, key)
mem.revisions_page(None, "revised", 20, None, None)
mem.list_all_images(None, None)              // = iter_images, collected

list_all_images wird zusätzlich als iter_images exportiert, passend zu dem Namen, den die beiden anderen SDKs verwenden - wer aus jener Dokumentation kommt, tippt zuerst diesen Namen.

Engramme

Engrams

Aufrufbare Recall-Werkzeuge, die Ihr Modell einsetzen kann - jedes eine eigene Abrufstrategie über dasselbe Gedächtnis. Nutzen Sie eines oder führen Sie mehrere zugleich aus.

Ab sofort verfügbar. Die allgemeinen Engramme unten sind Abruf-Pipelines ohne LLM und laufen daher auf jeder Stufe ab Tablet 1. Memoir und Archive, ein separater Modellmodus, werden weiter unten in einem eigenen Abschnitt behandelt.

Regelmäßig erscheinen weitere Engramme - diese Liste wächst.

Memoir & Archive Scroll 1.2+

Dies ist eine Auslieferungs-Form, kein aufrufbares Werkzeug. Ab Scroll 1.2 wählen Sie sie pro Aufruf - form: "memoir" oder form: "archive" - und dieser Recall, eine einfache Suche eingeschlossen, kommt mit entsprechend geschriebener Zeit zurück.

Alle Engramme Engramme

Time_awareness Scroll 1.2+

Eine Auslieferungsform - pro Aufruf gewählt. Übergeben Sie form - memoir oder archive - bei einem beliebigen Aufruf eines formfähigen Modells (ab Scroll 1.2), und die Antwort kommt entsprechend gerendert zurück: eine einfache Suche, ein Recall oder jedes Engramm. In den SDKs ist es ein form-Feld wie tz; über HTTP der Header X-WOS-Form. Ein Memoir liest sich, wie ein Mensch sich erinnert; ein Archive führt ein exaktes Protokoll - der Unterschied zeigt sich am deutlichsten darin, wie beide die Zeit schreiben.

Memoir

form: "memoir"
Erinnert wie ein Mensch · eine Erzählung

Erzählt, was geschah und wie ein Moment zum nächsten führte, mit dem weichen Zeitgefühl menschlicher Erinnerung - liest sich als Erlebnis, nicht als Liste.

Archive

form: "archive"
Geführt als Protokoll · präzise Zeit

Liefert Treffer als exakte Datensätze - präzise verstrichene Zeit und absolute Anker, so strukturiert, dass ein Modell sie direkt ablesen kann.

Es rendert Erinnerungen, die Sie bereits gespeichert haben - es erzeugt keine. Jede Erinnerung ist ein store-/add-Aufruf unter einer user_id (diese user_id ist der Store dieser Person). Zuerst speichern; danach kommt jeder Recall - die einfache Suche unten eingeschlossen - mit Zeitmarkierung zurück. Siehe Schnellstart zum Speichern.
# the memoir form on a plain search — and on recall, the LLM's one-call context
r   = mem.search("what does Alice drink?", user_id="alice", model="scroll-1.2", form="memoir", tz=9)
ctx = mem.recall("what does Alice drink?", user_id="alice", model="scroll-1.2", form="memoir", tz=9)
# every memory's .time reads "a couple weeks ago" (archive → "2 weeks ago (Jun 09)") — the LLM sees human time
// the memoir form on search — and on recall, the LLM's one-call context
const s = await mem.withModel("scroll-1.2").search("what does Alice drink?", "alice", 10, { form: "memoir", tz: 9 });
const ctx = await mem.withModel("scroll-1.2").recall("what does Alice drink?", "alice", { form: "memoir", tz: 9 });
// form on search AND recall — the _with helpers merge extra fields into the body
let s = mem.with_model("scroll-1.2").search_with("what does Alice drink?", "alice", 10, json!({"form": "memoir", "tz": 9})).await?;
let ctx = mem.with_model("scroll-1.2").recall_with("what does Alice drink?", "alice", json!({"form": "memoir", "tz": 9})).await?;
# same X-WOS-Form header on /search, /recall, or /engram/run
curl -X POST https://api.wontopos.com/api/v1/memory/recall \
  -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?"}'
# every memory comes back with a "time" field; use X-WOS-Form: archive for exact time

tz ist der UTC-Versatz des Aufrufers in Stunden - damit "heute Morgen" und die 4-Uhr-Tagesgrenze in dessen Ortszeit landen. Weglassen für UTC; über HTTP ist es der X-WOS-Timezone-Header. Grob nach Region: US-Ostküste -5, US-Zentral -6, US-Westküste -8 · UK / Lissabon 0 · Mitteleuropa +1 · Osteuropa +2 · Indien +5.5 · China / Singapur +8 · Korea / Japan +9 · Sydney +10. (Normalzeit - die Sommerzeit verschiebt manche Regionen um +1; übergeben Sie, was für Ihre Nutzer tatsächlich gilt.)

Dieselbe Suche, zwei Formen - die Erinnerungen sind identisch, nur time ändert sich:

Ergebnis · 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" }
] }
Ergebnis · 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)" }
] }
VerstrichenMemoirArchive
3 Min.a few minutes ago3 minutes ago
14 Min.about 15 minutes ago14 minutes ago
30 Min.half an hour ago30 minutes ago
50 Min.about an hour ago50 minutes ago
2 Std.a couple hours ago2 hours ago, at 13:10
8 Std.this morning8 hours ago, at 07:10
gestern Nachm.yesterday afternoonyesterday at 14:00
letzte Nachtlast night17 hours ago, at 22:00
2 Tagea couple days ago2 days ago (Tue 15:10)
6 Tageseveral days ago6 days ago (Fri 15:10)
9 Tageabout a week agolast week (Jun 16)
16 Tagea couple weeks ago2 weeks ago (Jun 09)
35 Tageabout a month agolast month (May 21)
60 Tagea couple months ago2 months ago (Apr 2026)
180 Tageabout half a year ago6 months ago (Dec 2025)
380 Tageabout a year agolast year (Jun 2025)
800 Tagea couple years ago2 years ago (Apr 2024)
1500 Tageabout 4 years ago4 years ago (May 2022)

Jeder Wert oben ist die tatsächliche Ausgabe des Renderers. Betrachten Sie die beiden "gestern"-Zeilen: Ein Memoir trennt den Nachmittag von der letzten Nacht - ein Tag ist ein Schlaf - während ein Archive eine einzelne Uhrzeit schreibt und keine Tag-Nacht-Grenze zieht.

Wie jeder Modus die Zeit liest

Memoir - so, wie Menschen es tatsächlich sagen. Jüngste Momente bleiben recht scharf (etwa 15 Minuten, eine halbe Stunde), dann weitet sich die Formulierung, je weiter man zurückgeht - ein paar Wochen, etwa ein halbes Jahr, ein paar Jahre - so, wie sich Erinnerung selbst mit der Entfernung lockert. Innerhalb eines Tages weicht die Uhr einem Orientierungspunkt: heute Morgen, letzte Nacht, gestern Nachmittag. Und ein Tag ist ein Schlaf, kein Kalendersprung: Die Grenze liegt bei etwa 4 Uhr Ortszeit, sodass eine späte Nacht noch als derselbe Abend gilt, nicht schon als morgen.

Archive - präzise, stets mit Anker. Jede Zeile trägt die exakte verstrichene Zeit plus eine absolute Referenz, mit der ein Modell rechnen kann, und der Anker wird enger, je näher es rückt: eine Uhrzeit für heute (vor 8 Stunden, um 07:10), Wochentag und Uhrzeit für diese Woche (vor 2 Tagen (Di 15:10)), ein Datum für diesen Monat (letzte Woche (16. Jun)), Monat und Jahr darüber hinaus (vor 6 Monaten (Dez 2025)). Nie vage, nie falsch.

Memoir und Archive rendern jeden Recall der Antwort - eine einfache Suche, ein Recall oder ein Engramm. Die Modellstufe (Tablet → Scroll → Book) bestimmt, wie viel die Engine leistet; die Form (memoir / archive) bestimmt, wie sie die Zeit schreibt. Verfügbar ab Scroll 1.2.
Alle Engramme Engramme

deep_recall

Multi-Hop-Recall. Sucht nach Ihrer Abfrage, nimmt dann den besten Treffer und sucht erneut nach dessen Inhalt - und holt so verknüpften Kontext ein, den eine einzelne Suche übersehen würde. Am stärksten, wenn Erinnerungen aufeinander verweisen (eine Person → ihre Projekte → Details). Liefert bis zu ~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?"}'
Antwort
{ "engram": "deep_recall", "hops": 2, "count": 12,
  "memories": [ ... ],
  "usage": { "input_tokens": 200, "output_tokens": 589 } }
Abgerechnet nach Tokens - jeder Aufruf liefert usage (Eingabe + Ausgabe), gezählt mit demselben Tokenizer wie der Rest der API; keine versteckte Gebühr pro Engramm. Mehrere zugleich nötig? Rufen Sie sie parallel auf - jedes Engramm ist eine unabhängige Anfrage.
Alle Engramme Engramme

timeline

Zeitlich geordneter Recall. Liefert Erinnerungen neueste zuerst, sortiert nach dem Zeitpunkt des Ereignisses, nicht nach Relevanz. Für "Wann war X", Verlauf und Reihenfolgefragen. Liefert bis zu 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"}'
Antwort
{ "engram": "timeline", "hops": 1, "count": 15,
  "memories": [ ... ],
  "usage": { "input_tokens": 100, "output_tokens": 736 } }
Abgerechnet nach Tokens - jeder Aufruf liefert usage (Eingabe + Ausgabe), gezählt mit demselben Tokenizer wie der Rest der API; keine versteckte Gebühr pro Engramm. Mehrere zugleich nötig? Rufen Sie sie parallel auf - jedes Engramm ist eine unabhängige Anfrage.
Alle Engramme Engramme

gather

Breites Sammeln. Sucht und erweitert dann um die besten drei Treffer herum - ein weiteres Netz als deep_recall. Damit holen Sie alles zu einer Person, einem Projekt oder einem Thema in einem Aufruf ein. Liefert bis zu ~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"}'
Antwort
{ "engram": "gather", "hops": 4, "count": 18,
  "memories": [ ... ],
  "usage": { "input_tokens": 400, "output_tokens": 637 } }
Abgerechnet nach Tokens - jeder Aufruf liefert usage (Eingabe + Ausgabe), gezählt mit demselben Tokenizer wie der Rest der API; keine versteckte Gebühr pro Engramm. Mehrere zugleich nötig? Rufen Sie sie parallel auf - jedes Engramm ist eine unabhängige Anfrage.
Alle Engramme Engramme

equilibrium

Driftkorrektur. Semantische Suche verengt sich im Verlauf einer Sitzung: die Anfrage trägt den aktuellen Zustand, holt Erinnerungen desselben Zustands und der nächste Zug neigt sich weiter dorthin. Dieses Engram weitet das Ergebnis entlang dreier Achsen, die die Anfrage nicht kontrolliert: Streuung über die Zeit, Assoziation weg von der Anfrage und der inhaltlich tragende Teil des Speichers. Nutzen Sie es, wenn Antworten kreisen oder flach werden. Für einen konkreten Fakt passen deep_recall oder gather besser, die näher an der Anfrage bleiben. Liefert bis zu 12.

wide = mem.engram("equilibrium", "how have things been lately?", user_id="alice")
const wide = await mem.engram("equilibrium", "how have things been lately?", "alice");
let wide = mem.engram("equilibrium", "how have things been lately?", "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":"equilibrium","user_id":"alice","query":"how have things been lately?"}'
Antwort
{ "engram": "equilibrium", "hops": 3, "count": 12,
  "memories": [ ... ],
  "usage": { "input_tokens": 300, "output_tokens": 293 } }
Abgerechnet nach Tokens - jeder Aufruf liefert usage (Eingabe + Ausgabe), gezählt mit demselben Tokenizer wie der Rest der API; keine versteckte Gebühr pro Engramm. Mehrere zugleich nötig? Rufen Sie sie parallel auf - jedes Engramm ist eine unabhängige Anfrage.
Alle Engramme Engramme

tone_stabilizer

Die eigene Stimme. Lange Sitzungen ziehen einen Assistenten aus seiner Tonlage: Antworten werden länger, geraten zum Bericht oder nehmen die Stimmung der letzten Strecke an. Gewöhnliches Selbst-Recall verschlimmert das, weil es den aktuellen Zustand trifft und die neuesten Zeilen zurückgibt, als wären sie der Charakter. Dieses Engram liefert stattdessen die eigenen Worte von vor dieser Strecke. Es braucht Beiträge, die mit speaker me gespeichert wurden; ohne solche gibt es nichts zurück statt zu raten. Liefert bis zu 10.

# store the assistant's turns as speaker "me", then pull its own register back
mem.add("I keep answers short unless you ask for detail.", user_id="alice", speaker="me")
mine = mem.engram("tone_stabilizer", "how do I usually answer?", user_id="alice")
await mem.add("I keep answers short unless you ask for detail.", "alice", { speaker: "me" });
const mine = await mem.engram("tone_stabilizer", "how do I usually answer?", "alice");
mem.add("I keep answers short unless you ask for detail.", "alice", json!({"speaker": "me"})).await?;
let mine = mem.engram("tone_stabilizer", "how do I usually answer?", "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":"tone_stabilizer","user_id":"alice","query":"how do I usually answer?"}'
Antwort
{ "engram": "tone_stabilizer", "hops": 2, "count": 10,
  "memories": [ { "content": "I keep answers short unless you ask for detail.", "speaker": "me" }, ... ],
  "usage": { "input_tokens": 200, "output_tokens": 442 } }
Abgerechnet nach Tokens - jeder Aufruf liefert usage (Eingabe + Ausgabe), gezählt mit demselben Tokenizer wie der Rest der API; keine versteckte Gebühr pro Engramm. Mehrere zugleich nötig? Rufen Sie sie parallel auf - jedes Engramm ist eine unabhängige Anfrage.
HTTP-API

Jeder Endpunkt, eine Basis-URL.

Kein SDK erforderlich - jeder HTTP-Client funktioniert. Basis-URL https://api.wontopos.com, Authentifizierung über den X-API-Key-Header, JSON rein und raus. Memory-Operationen sind POST; die Verwaltung von Stores nutzt POST / GET / DELETE auf /collection. Ein Store muss zuerst existieren (siehe Stores), sonst liefern Operationen im Store 404.

Header

HeaderWozu er dient
X-API-KeyBei jedem Aufruf erforderlich. Ihr Schlüssel, in der Konsole ausgestellt.
X-WOS-ModelOptional. Legt fest, welche Engine antwortet. Lassen Sie ihn weg, wird der Standard des Kontos verwendet. GET /api/v1/models listet die Modelle auf, die Ihr Schlüssel wählen darf; ein Endpunkt, den eine ältere Engine nicht bedienen kann, antwortet mit 501 und nennt dieses Modell.
Idempotency-KeyOptional, bei Schreibvorgängen. Derselbe Schlüssel mit demselben Body spielt die erste Antwort erneut ab, statt erneut zu speichern - siehe den Hinweis unten.

Endpunkt

EndpunktZweckBody-Felder
POST /api/v1/memory/collectionStore anlegenuser_id
GET /api/v1/memory/collectionsIhre Stores auflisten(keine)
DELETE /api/v1/memory/collectionStore + seine Erinnerungen löschenuser_id
/api/v1/memory/storeeine Erinnerung speichernuser_id · content · metadata? (event_date · speaker) · image?
/api/v1/memory/store-turneinen Gesprächszug speichernuser_id · user_msg · assistant_msg
POST /api/v1/memory/speakersSprecher registrieren (explizit, bis 50)user_id · speaker
GET /api/v1/memory/speakersregistrierte Sprecher + Zähler auflistenuser_id
DELETE /api/v1/memory/speakersSprecher abmelden (Erinnerungen bleiben)user_id · speaker
/api/v1/memory/by-speakerwas eine Person gesagt hat, neueste zuerst („me“ = der Agent)user_id · speaker · limit? · before? · skip_ids?
POST /api/v1/memory/imagedie Originalbytes einer Bild-Erinnerunguser_id · memory_id
DELETE /api/v1/memory/imagedas Bild entfernen, die Bildunterschrift behaltenuser_id · memory_id · preview?
/api/v1/memory/imagesdie Bilder eines Stores, neueste zuerst (+ Gesamtzahl)user_id · limit? · before? · skip_ids?
/api/v1/memory/lineagedie Änderungskette einer Erinnerung, älteste zuerstuser_id · memory_id
/api/v1/won/revisionswie viel eines Stores überschrieben wurde. Kostenlosuser_id · include? · limit? · before? · skip_ids?
/api/v1/memory/revisionsderselbe Aufruf unter der Memory-Ebene. Kostenlosuser_id · include? · limit? · before? · skip_ids?
/api/v1/memory/bulk-storeeinen Textblock nachladenuser_id · content · category? · timestamp?
/api/v1/memory/searchsemantische Sucheuser_id · query · max_results? · speaker? · cache_control? · filters? · verify? · max_images?
/api/v1/memory/recallKurzzeit + Langzeit + Kontextuser_id · query · limit? · context_limit?
/api/v1/memory/geteine Erinnerung per iduser_id · memory_id
/api/v1/memory/listeinen Store durchblätternuser_id · limit? · cursor?
/api/v1/memory/historyjüngste Gesprächszügeuser_id
/api/v1/memory/statsAnzahl der Erinnerungenuser_id
/api/v1/memory/supersedeeinen geänderten Fakt ersetzenuser_id · old_memory_id · new_content
/api/v1/memory/forgeteine (oder alle) löschenuser_id · memory_id? (weglassen = alle löschen)
GET /api/v1/engramEngramme, die dieses Modell ausführen kann(keine)
POST /api/v1/engram/runein Engramm ausführenname · user_id · query · form? · tz?
GET /api/v1/modelsverfügbare Modelle(keine)
Schreibvorgänge akzeptieren einen Idempotency-Key-Header. Derselbe Schlüssel mit demselben Body spielt die erste Antwort erneut ab, statt erneut zu speichern (10 Minuten); derselbe Schlüssel mit einem anderen Body antwortet mit 422. Nur 2xx werden zwischengespeichert, ein fehlgeschlagener Aufruf ist also sofort wiederholbar.
# 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?"}'
Tatsächliche Antwort - store
{"id": "576700aa-f0e0-4c26-99a0-10e2d5b0d624", "status": "stored (1 chunks)"}
Nutzungsstufen

Dieselben Funktionen für alle.
Stufen erhöhen nur Ihre Limits.

Jede Stufe nutzt die vollständige Engine - dieselbe Recall-Qualität, dieselben Sprachen, jede Methode. Die Stufen steigen automatisch bis Stufe 5, während Ihre kumulierten Guthabenkäufe wachsen - ohne Antrag oder Vertriebsgespräch. Enterprise (Stufe 6) ist die einzige Ausnahme.

Ausgabenlimits

Jede Stufe begrenzt, wie viel Sie pro Kalendermonat ausgeben können. Sie steigen sofort auf, sobald Ihre kumulierten Guthabenkäufe die nächste Schwelle erreichen.

NutzungsstufeGuthabenkaufMonatliches Ausgabenlimit
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 - EnterpriseSprechen Sie mit unsKein Limit

Rate-Limits

Rate-Limits gelten pro Konto - alle API-Schlüssel eines Kontos teilen sich ein Limit, das mit Ihrer Stufe skaliert. Bei Überschreitung kommt ein 429 mit einem retry-after-Header zurück; warten Sie gestaffelt (1s → 2s → 4s) und versuchen Sie es erneut. Jeder Endpunkt ist idempotenzfreundlich, Wiederholungen sind also sicher.

StufeAnfragen pro Minute
Tier 1150
Tier 2300
Tier 3600
Tier 41,500
Tier 53,000
Tier 6 - EnterpriseIndividuell

Enterprise (Stufe 6) erhält individuelle Rate-Limits, ein SLA, dedizierten Support und optional eine Self-Host-Lizenz - sprechen Sie mit uns.

Kostenlose Aufrufe

Ein paar Endpunkte kosten überhaupt nichts - sie sind unter Won zusammengefasst. Statt eines Preises haben sie zwei Limits.

  • 10 Anfragen pro Minute, pro Endpunkt. Jeder kostenlose Endpunkt hat seinen eigenen Bucket, das Verbrauchen des einen verbraucht also nicht den anderen.
  • 300 Anfragen pro Stunde, gemeinsam. Alle kostenlosen Endpunkte schöpfen aus einem Stundenkontingent pro Konto.

Beides wird im normalen Betrieb nicht erreicht, und beides berührt die oben genannten kostenpflichtigen Limits nicht.

Die Preise sind nutzungsbasiert: Tokens plus pauschal $0.0001 pro Anfrage. Tablet kostet $2 pro 1M Eingabe-Tokens, $3 pro 1M Ausgabe-Tokens. Speicherung ist kostenlos und ohne Obergrenzen. Siehe warum wir so bepreisen.
Fehler & Limits

Wenn etwas schiefgeht.

Fehler kommen als JSON-Umschlag zurück, mit einem stabilen type, einer menschenlesbaren Meldung und einer request_id, die Sie uns bei der Meldung eines Problems mitschicken können.

Tatsächliche Antwort - ungültiger Schlüssel (HTTP 401)
{"type": "error", "error": {
   "type": "authentication_error",
   "message": "Invalid or revoked API key.",
   "request_id": "063f8b83-eee2-4383-a5cf-11e4bcd29d7c"
 }}
HTTPBedeutungWas zu tun ist
400Fehlerhafter Body (fehlendes Feld oder falscher Typ)Die Meldung nennt das genaue Feld - korrigieren und erneut versuchen.
401Ungültiger oder widerrufener API-SchlüsselPrüfen Sie den Schlüssel; stellen Sie in der Konsole einen neuen aus.
402Guthaben aufgebraucht, keine Karte hinterlegt oder Stufenlimit erreichtLaden Sie in der Konsole Guthaben auf oder hinterlegen Sie eine Karte. Die Antwort enthält balance_cents und floor_cents, sodass Sie erkennen, was Sie gestoppt hat.
404Erinnerung, Store oder Bild existiert nichtPrüfen Sie die id. get_image antwortet auch dann mit 404, wenn die Erinnerung zwar existiert, aber kein Bild trägt.
409Dieser Name ist bereits vergebenStore- und Workspace-Namen sind innerhalb eines Kontos eindeutig - wählen Sie einen anderen.
413Request-Body über 10MBBase64 ist rund 33% größer als die Datei, die es kodiert - verkleinern Sie das Bild also, bevor Sie es kodieren.
429Rate-Limit erreichtDas SDK wiederholt diese Anfragen bereits für Sie, mit Backoff und Jitter, und beachtet dabei Retry-After. Wenn Sie einen solchen Fehler erhalten, sind die Wiederholungen aufgebraucht - senken Sie die Zahl gleichzeitiger Anfragen, statt eine eigene Schleife darum zu legen.
501Die Engine dieses Modells implementiert diesen Endpunkt nichtBilder und Revisionsverlauf benötigen eine neuere Engine. GET /api/v1/models listet auf, welches Modell was bedient.
5xxServerseitiges ProblemMit Backoff erneut versuchen, aber nicht blind. Das SDK wiederholt einen 5xx hier nicht automatisch, denn jeder Aufruf dieser API ist ein POST und der Server hat Ihre Anfrage möglicherweise bereits gespeichert. Senden Sie sie mit einem Idempotenzschlüssel erneut, damit eine Wiederholung nicht doppelt schreiben kann, und geben Sie die request_id an, wenn Sie uns kontaktieren.

Jeder Fehler ist ein WosError, und jeder Status hat zusätzlich eine eigene Klasse - BadRequestError, AuthenticationError, PaymentRequiredError, NotFoundError, ConflictError, RateLimitError, ServerError, APIConnectionError. Fangen Sie die ab, die Sie behandeln wollen, statt Zahlen zu vergleichen.

# SDK error handling (Python)
from wontopos import Client, WosError, RateLimitError, PaymentRequiredError

try:
    mem.search("...", user_id="alice")
except PaymentRequiredError: ...      # 402 - top up
except RateLimitError: ...            # 429 - the SDK already retried; slow down
except WosError as e: ...            # e.status, e.message, e.request_id
except (ValueError, TypeError): ...    # never left the client

Manche Fehler erreichen uns nie. Der API-Schlüssel, die Store-id, der Idempotenzschlüssel und das Bild werden alle geprüft, bevor die Anfrage hinausgeht, und dabei wird ValueError oder TypeError ausgelöst - nicht WosError. Ein except WosError allein fängt sie nicht ab.

Schlüsselsicherheit. Ihr Schlüssel wird bei der Erstellung einmal angezeigt und bei uns nur als Hash gespeichert. Bewahren Sie ihn in einer Umgebungsvariable auf; falls er durchsickert, widerrufen Sie ihn in der Konsole - der Widerruf wirkt sofort.

Rate-Limits gelten pro Konto, geteilt über alle Ihre Schlüssel, und skalieren mit Ihrer Stufe - siehe Nutzungsstufen. Die Nutzung Ihres Kontos sehen Sie in der Konsole.

Entwickler

lineage

Die Kette der Änderungen hinter einer Erinnerung, älteste zuerst. revisions gibt an, wie stark sich ein Store verändert hat; dies gibt an, was mit einer einzelnen Tatsache geschehen ist.

Unterstützt ab Tablet 2. Nur lesend. Anders als revisions ist dies ein normal abgerechneter Aufruf, da er Inhalte von Erinnerungen zurückgibt.

Übergeben Sie die ID einer beliebigen Erinnerung in der Kette. Ersetzte Versionen werden aufbewahrt statt gelöscht, sodass eine Suche, die nur die aktuelle Tatsache zurückgibt, weiterhin zurückverfolgt werden kann.

chain = mem.lineage(memory_id=mid)["chain"]
for step in chain:
    print(step["changed_at"], step["action"], step["content"])
const { chain } = await mem.lineage(undefined, mid);
for (const step of chain) {
  console.log(step.changed_at, step.action, step.content);
}
let r = mem.lineage(None, mid).await?;
for step in r["chain"].as_array().unwrap_or(&vec![]) {
    println!("{} {} {}", step["changed_at"], step["action"], step["content"]);
}
curl -X POST https://api.wontopos.com/api/v1/memory/lineage \
  -H "X-API-Key: $WOS_KEY" -H "Content-Type: application/json" \
  -d '{"user_id":"alice","memory_id":"m_9"}'
200
{ "memory_id": "m_9", "count": 3, "truncated": false,
  "chain": [
    { "memory_id": "m_3", "content": "lives in Seoul",
      "created_at": "2026-03-02T…", "changed_at": "2026-06-11T…",
      "action": "replaced", "confidence": 0.94,
      "superseded_by": "m_7", "is_current": false },
    { "memory_id": "m_7", "content": "moved to Busan",   … },
    { "memory_id": "m_9", "content": "Haeundae, specifically",
      "changed_at": null, "superseded_by": null, "is_current": true }
  ] }
FeldWas er tut
chainDie Versionen, älteste zuerst. Jede enthält dieselben Felder wie eine Erinnerung, dazu die vier folgenden.
changed_atWann diese Version ersetzt wurde (RFC3339), oder null, solange sie noch gilt.
actionWas an diesem Kettenglied geschah - wie die Ersetzung zu dieser Version stand.
confidenceWie sicher sich die Engine bei dieser Beziehung war, 0-1.
is_currentTrue für die eine Version, die noch gilt. Genau eine pro Kette.
truncatedTrue, wenn die Kette länger war, als der Dienst sie verfolgt. Die zurückgegebenen Schritte sind weiterhin die ältesten.

Wofür es gedacht ist

Zwei Anwendungsfälle. Debugging: warum eine Erinnerung heute so lautet, wie sie lautet. Und einem Assistenten den Blick auf seine eigene Historie zu ermöglichen - eine dreimal korrigierte Tatsache ist eine andere Art von Tatsache als eine einmal geschriebene, und nur die Kette zeigt das.

Won

Won ist für diejenigen gedacht, die die Erinnerung lesen.

Der größte Teil dieser API antwortet mit Erinnerung. Won antwortet über sie: wie viel von einem Store neu geschrieben wurde und wie weit man ihm vertrauen kann. Gedacht ist das für die lesende Seite, meist für den Assistenten, den Sie bauen, und nicht für die Person, von der die Erinnerungen handeln.

Wontopos ist Won + Topos, ein Ort, an dem Erinnerung wohnt. Won ist der Teil dieses Ortes, der über die Erinnerung Auskunft gibt, statt sie zurückzugeben. Diese Aufrufe sind kostenlos, nur lesend, und rühren den Abruf nie an: Das Fragen kostet Ihre Nutzer nichts und ändert nichts an dem, was gespeichert ist.

Was es heute umfasst

Heute ein Aufruf.

AufrufWas er tut
POST /won/revisionsWie viel von diesem Store seit dem Schreiben verändert wurde. Zwei Zahlen und zwei Sätze, die sie erläutern.

Ein durchgerechnetes Beispiel

Verwenden Sie das Verhältnis, nicht die absolute Zahl. 3 von 40 und 30 von 40 erfordern eine unterschiedliche Behandlung.

r = mem.revisions()
# {"revised": 3, "total": 40, "counts": "…", "excludes": "…"}

if r["revised"] / r["total"] > 0.1:
    system += "Some of what you remember here has been corrected since."
const r = await mem.revisions();
// { revised: 3, total: 40, counts: "…", excludes: "…" }

if (r.revised / r.total > 0.1) {
  system += "Some of what you remember here has been corrected since.";
}
let r = mem.revisions(None).await?;
let (rev, tot) = (r["revised"].as_f64().unwrap_or(0.0),
                r["total"].as_f64().unwrap_or(1.0));
if rev / tot > 0.1 { /* say so in the system prompt */ }
curl -X POST https://api.wontopos.com/api/v1/won/revisions \
  -H "X-API-Key: $WOS_KEY" -H "Content-Type: application/json" \
  -d '{"user_id":"alice"}'

# → {"user_id":"alice","revised":3,"total":40,
#     "counts":"memories a transform has touched (supersede, update, retract, image removed)",
#     "excludes":"deletions — a deleted memory leaves nothing to count"}

counts und excludes werden als Sätze zurückgegeben, nicht als Flags, da der Aufrufer oft ein Modell ist. Löschungen werden nicht gezählt.

Preis und Limits

RegelWert
PreisKeiner. Kostenlose Aufrufe umgehen die Abrechnungsschranken - keine Token-Berechnung, keine Gebühr pro Anfrage und keine erfasste Nutzung.
Pro Minute10 pro Minute, pro Konto und pro Endpunkt. Die Minute eines Endpunkts zu verbrauchen, verbraucht nicht die eines anderen.
Pro Stunde300 pro Stunde, pro Konto, geteilt von allen kostenlosen Aufrufen. Dieses Limit ignoriert den Pfad, zusätzliche kostenlose Endpunkte erhöhen also nicht die Gesamtmenge, die ein Konto verbrauchen kann.
Gegenüber kostenpflichtigem TrafficIn beide Richtungen getrennt. Diese Aufrufe können Ihre Suchen nicht verlangsamen, und Ihre Suchen können diese nicht aufbrauchen. Schlüssel eines Kontos teilen sich die Buckets, mehr Schlüssel vervielfachen das Kontingent also nicht.

Beide Obergrenzen antworten mit 429 und Retry-After in Sekunden sowie einer Meldung, die nennt, welche davon erreicht wurde.

429 rate_limit_error
Retry-After: 41

{ "error": { "type": "rate_limit_error",
    "message": "This endpoint is free and limited to 10 requests per
                minute, counted per endpoint. Retry in 41s." } }
Derselbe Aufruf antwortet auch unter /api/v1/memory/revisions, für Clients, die vor der Won-Oberfläche veröffentlicht wurden. Es sind derselbe Handler und dasselbe Budget, kein zweites Kontingent. Neuer Code sollte die Won-Adresse verwenden.
Won · revisions

Wie viel von einem Store neu geschrieben wurde

revisions antwortet mit revised von total: wie viele Erinnerungen in einem Store nach dem Schreiben verändert wurden. Es lohnt sich, danach zu fragen, bevor Sie sich bei etwas Wichtigem auf das Gedächtnis stützen, oder wenn ein abgerufener Fakt nicht zu dem passt, was der Nutzer gerade sagt. Ein Store, in dem drei von zehn Fakten ersetzt wurden, verdient weniger Vertrauen als einer, den niemand bearbeitet hat.

Unterstützt ab Tablet 2. Aufrufbar über die HTTP-API, aus den Python-, TypeScript- und Rust-SDKs sowie als MCP-Tool. Ältere Engines antworten mit 501 und nennen das Modell, das dies nicht leisten kann.

Anzahlen

Gezählt wird, was eine Transformation berührt hat - ersetzt, aktualisiert, zurückgezogen sowie entfernte Bilder.

mem.revisions()
# {"revised": 3, "unrevised": 37, "total": 40, …}
await mem.revisions();
mem.revisions(None).await?;
curl -X POST https://api.wontopos.com/api/v1/won/revisions \
  -H "X-API-Key: $WOS_KEY" -d '{"user_id":"alice"}'
FeldBedeutung
revisedErinnerungen, die eine Transformation berührt hat.
unrevisedErinnerungen, die seit dem Schreiben nichts verändert hat. revised + unrevised ergibt immer total - der Wert ist abgeleitet und wird nicht separat gezählt, ein gleichzeitiger Schreibvorgang kann die drei also nicht in Widerspruch bringen.
totalErinnerungen im Store.
counts / excludesEinfache Sätze, keine Flags, die ausformulieren, was die Zahlen abdecken. Der Aufrufer ist oft ein Modell.

Die Liste lesen

Übergeben Sie include, um die Erinnerungen selbst zu erhalten, nicht nur deren Anzahl. Ohne diesen Parameter erhalten Sie nur die Zählwerte, was der günstige Aufruf ist.

page = mem.revisions(include="revised", limit=20)
page["memories"], page["matched"], page["has_more"]
const page = await mem.revisions(undefined, { include: "revised", limit: 20 });
let page = mem.revisions_page(None, "revised", 20, None, None).await?;
curl -X POST https://api.wontopos.com/api/v1/won/revisions \
  -H "X-API-Key: $WOS_KEY" \
  -d '{"user_id":"alice","include":"revised","limit":20}'
FeldWas er tut
include"revised" oder "unrevised". Jeder andere Wert wird mit einem 400 abgelehnt, statt auf die Zählwerte zurückzufallen - ein Tippfehler, der die Liste stillschweigend weglässt, sieht genau wie ein leerer Store aus.
limit5 bis 20, Standard 20. Werte außerhalb des Bereichs oder mit falschem Typ werden abgelehnt, nicht begrenzt.
matchedGesamtzahl der Zeilen hinter dieser Seite, nicht die Größe der Seite.
ordered_byDer Dienst nennt seine eigene Sortierung: zuletzt gespeichert zuerst, nicht zuletzt bearbeitet.
next_beforeCursor für die nächste Seite, zusammen mit next_skip_ids. Geben Sie beides zurück; die IDs sammeln sich über die Seiten hinweg an.
Die Liste ist danach sortiert, wann eine Erinnerung gespeichert wurde, nicht wann sie geändert wurde. Wer "zuletzt bearbeitet zuerst" annimmt, liest die Seite falsch; deshalb nennt die Antwort ausdrücklich, welche Sortierung gilt.
Löschungen werden nicht gezählt. Eine gelöschte Erinnerung lässt nichts übrig, was sich zählen ließe, daher meldet auch ein stark ausgedünnter Store weiterhin ein niedriges revised. Diese Zahl sagt Ihnen, wie viel neu geschrieben wurde, nicht wie viel verschwunden ist.
Skalierung

Jenseits des Kontextfensters.

WOS ruft aus Historien von 1.4M Tokens ab - weit größer als jedes LLM-Kontextfenster - und liefert dennoch einen kompakten Ausschnitt von ~1.470 Tokens zurück.

Das Gedächtnis Ihres Agenten ist nicht dadurch begrenzt, was in einen Prompt passt. Es behält alles und ruft nur das Wesentliche ab, egal wie groß die Historie wird.

Datenschutz

Privat, und Ihr Eigentum.

Ihre Daten bleiben in Ihrem Store. Wir trainieren nie darauf, sehen sie nicht ein und verwenden sie nicht weiter - wir organisieren sie nur, damit Sie sie abrufen können.

  • BYOK. Ihr LLM-Schlüssel wird pro Anfrage gesendet und nie gespeichert.
  • Isoliert. Erinnerungen sind pro Konto und darin pro user_id abgegrenzt.
  • DSGVO-Löschung & Self-Hosting. Ein Aufruf löscht einen Nutzer vollständig; auf Wunsch betreiben Sie die Engine in Ihrer eigenen Umgebung.