Das Recall deines Memory-Providers wurde abgeschnitten: Opt-in-Spilling und zwei weitere stille Fehler


Du verdrahtest einen externen Memory-Provider in Hermes — Hindsight, Mem0, Honcho, irgendeinen davon. Ein paar Wochen lang erinnert er sich tatsächlich an dich. Dann erwähnst du eines Tages den API-Contract, auf den ihr euch letzte Woche geeinigt habt, und er antwortet, als hätte er nie davon gehört. Du gibst dem Modell die Schuld oder nimmst an, der Provider habe das Write verloren. Die wahre Geschichte ist ärgerlicher: Der Recall wurde geholt, und dann hat Hermes selbst ihn durch die ersten paar Absätze, die letzten paar Absätze und einen Dateipfad ersetzt.

Dieses Verhalten hat sich am 9. Oktober geändert, in drei gemergten Fixes zu drei stillen Fehlern rund um externe Memory-Plugins: abgeschnittener Recall, Provider, die aus hermes memory status verschwinden, und eine Installation, die bei jedem einzelnen Start erneut versucht wird. Hier kommt jedes Symptom, sein Mechanismus und was man dagegen tun kann.

Symptom eins: Der Recall wird ohne Warnung abgeschnitten

Hermes hat einen allgemeinen „Spill“-Mechanismus: Wenn die Ausgabe eines Hooks eine Größen-Schwelle überschreitet, wird der volle Text nicht in den Context gestellt. Eine Head-und-Tail-Vorschau nimmt seinen Platz ein, mit einem Dateipfad für den Rest. Für normale Plugin-Hooks ist dieser Standard sinnvoll — ein geschwätziges Plugin sollte dein Context-Window nicht auffressen.

Der Haken war, dass derselbe Mechanismus auf externen Memory-Prefetch-Recall angewandt wurde. Ein Provider, der bereits sein eigenes Recall-Budget angewandt hatte, wurde also von Hermes ein zweites Mal gestutzt: Die nach Relevanz sortierte Mitte verschwand aus dem Blick, und das Modell sah nur Anfang und Ende.

Der Fix macht daraus eine explizite Wahl (PR #135157):

# ~/.hermes/config.yaml
memory:
  prefetch_spill_enabled: false   # Standard: externer Recall bleibt intakt

Die Details sind wissenswert:

  • Standard false. Externer Recall erreicht das Modell vollständig. Eine Sicherheitsobergrenze existiert weiterhin: Recall über 10× hooks.output_spill.max_chars (mindestens 100.000 Zeichen) wird weiterhin gespillt, damit ein außer Kontrolle geratener Provider das Context-Window nicht überlaufen kann.
  • Setze es auf true, und du bekommst das alte Verhalten zurück: überdimensionierter Recall wird zu einer Head/Tail-Vorschau plus einem Dateipfad. Es nutzt die geteilte hooks.output_spill-Schwelle, die Vorschaulängen und das Verzeichnis weiter — und hooks.output_spill.enabled: false überschreibt weiterhin alles.
  • Normales Plugin-Hook-Spilling ist unverändert und bleibt standardmäßig aktiv, unabhängig von dieser Memory-Einstellung.
  • Die Einstellung wird festgehalten, wenn sich der Provider registriert, starte Hermes also nach einer Änderung neu; eine laufende Konversation ändert ihr Verhalten nicht mitten im Turn.
  • Die offiziellen Docs sagen es klar: Wenn dein Provider sein eigenes Recall-Budget hat, bevorzuge dieses. Er weiß besser als eine Truncation-Regel, was zu behalten ist.

Ein ehrlicher Trade-off: Vollständigen Recall zu behalten macht die Prompts größer. Wenn du auf abgerechneten Tokens sitzt und einen redseligen Memory-Service fährst, kann das Wieder-Einschalten von prefetch_spill_enabled Geld sparen — solange du akzeptierst, dass die Mitte des Recalls weniger sichtbar ist.

Symptom zwei: Dein Provider verschwindet aus hermes memory status

Der zweite Fix (PR #135524) ist eine geänderte Zeile plus eine Docstring-Zeile, und er zählt mehr, als seine Größe vermuten lässt.

Um zu entscheiden, ob ein Plugin-Ordner ein Memory-Provider ist, sucht Hermes in seiner __init__.py nach register_memory_provider oder MemoryProvider. Das ist ein billiger Scan ohne Imports — aber er las nur die ersten 8 KB der Datei. Ein einwandfrei funktionierender Provider mit einem langen Modul-Docstring wurde übersprungen: fehlend in hermes memory status, und hermes memory setup <name> sagte „not found“.

Das Katalog-Plugin excel_line traf genau das, und der damalige Workaround war übel: den Docstring kürzen, damit der Registrierungscode in die ersten 8 KB fiel (#135442 / #135473). Dieser Workaround ist nicht mehr nötig. Der schnelle Pfad bleibt (weiterhin ein billiger 8-KB-Textcheck); nur wenn er nichts findet, fällt er auf das bestehende _defines_memory_provider zurück, das die Top-Level-Module des Pakets parst, ohne sie zu importieren. Provider, die bereits gematcht haben, zahlen nichts extra — nur Ordner, die danebenliegen, zahlen für einen AST-Parse.

Wenn du ein Plugin geschrieben hast, das sich installiert, aber nie erkannt wird: Hör auf, deine Docs zu löschen, und update stattdessen.

Symptom drei: Der Provider installiert sich bei jedem Start neu

Der dritte Fix (PR #135529) adressiert eine lawinenartige Retry-Schleife.

Die automatische Installation eines Memory-Providers läuft beim Agent-Start — hermes chat, ein Cron-Lauf, ein Gateway-Agent, ein Desktop-Neustart, jeder zählt. Vor dem Fix wurde eine fehlgeschlagene Installation bei jedem dieser Starts erneut versucht, und jeder Retry wurde als frischer Fehler erfasst. Die Telemetrie des PR (14 Tage, dedupliziert) zeigt, was das produzierte:

Plugin ok fehlgeschlagen fehlschlagende Install-Tage Fehlschläge pro fehlschlagendem Install-Tag
hindsight 130 1048 204 5.1
mnemosyne 47 288 83 3.5

Hindshights tägliche Fehler stiegen zwischen dem 29.09. und dem 02.10. von 8 → 47 → 170 → 204, größtenteils dieselbe Handvoll Fehler, immer wieder gezählt, oben drauf ein kleinerer Satz echter Netzwerkfehler (PMs uv lock, git clone). Die Schlussfolgerung im PR ist deutlich: Das ist eine Retry-Schleife, keine 1.048 unterschiedlichen Fehler.

Die Semantik ist jetzt sauber: STARTUP_RETRY_SECONDS = 3600.0 in hermes_cli/memory_provider_migration.py — ein Provider, dessen automatische Installation fehlgeschlagen ist, wird eine Stunde lang von keinem Prozess erneut versucht. Wenn er doch wieder auftaucht, sagt er dir, was du ausführen sollst:

Its automatic install failed less than an hour ago: run `hermes plugins install hindsight`

Derselbe PR behob eine verwandte Fehldiagnose: Wenn plugins/<name> bereits als Symlink irgendwohin existiert, sagt eine Katalog-Installation jetzt, der Slot sei belegt, statt das Manifest des Plugins zu beschuldigen.

So überprüfst du dein eigenes Setup

hermes memory status     # welcher externe Provider aktiv ist und ob er installiert ist
hermes memory setup      # einen Provider wählen oder konfigurieren (erwähnt auch eine fehlende Installation)
hermes memory off        # den externen Provider deaktivieren
hermes plugins list      # ist das Plugin vorhanden?

Eine praktische Triage-Reihenfolge für „es hat etwas vergessen“: Bestätige mit hermes memory status, dass der Provider vorhanden ist, lies dann memory.provider und prefetch_spill_enabled in config.yaml und entscheide dann, ob das Modell den Recall nie erhalten hat (Konfiguration) oder der Provider ihn nie gespeichert hat (Service). Für Hintergrund zur Wahl eines Memory-Backends siehe unseren Semantic-Memory-Durchgang und das Dreaming-/Memory-Consolidation-Feature; die vollständige Befehlsoberfläche steht in der hermes-memory-Referenz.

Release-Status

Alle drei Fixes wurden am 2026-10-09 gemergt, nachdem v0.21.6 am 8. Oktober ausgeliefert wurde, also sind sie vorerst nur auf origin/main — warte auf das nächste Release oder führe hermes update aus. Wie Plugins überhaupt reviewt und gepinnt werden, steht im Plugin-Katalog-Guide.

Das Fazit

Alle drei sind stille Fehler: kein Fehler, keine Log-Zeile, nur still schlechteres Verhalten — Recall gestutzt, ein Plugin übersprungen, ein Fehler tausendmal gezählt. Sie haben so lange überlebt, weil jeder in einer Schicht lebt, die Nutzer nicht sehen können. Wenn du einen externen Memory-Provider betreibst, ist das einzig Nützlichste, was du heute tun kannst: öffne config.yaml, schau dir memory.prefetch_spill_enabled an und entscheide, ob du vollständigen Recall oder einen kleineren Prompt willst.