Wenn Hermes sagt, es habe die Datei angehängt, und deine Plattform nichts bekommt


Die schlimmste Art von Bug ist die, bei der der Agent selbstsicher ist und der Nutzer nichts sieht. Du bittest Hermes, einen Report an deine eigene Chat-Plattform zu schicken — eine Mobile-App, ein internes Tool, eine Bridge, die du selbst geschrieben hast —, und die Antwort lautet „gesendet, die Datei ist angehängt“. Es kommt nichts an. Du fragst erneut, der Agent entschuldigt sich und schickt noch einmal, und immer noch kommt nichts an, weil der Assistent keine Möglichkeit hat zu wissen, dass das Attachment irgendwo unter ihm fallengelassen wurde.

Das Symptom und der exakte Fehler

Die betreffende Plattform ist nicht kaputt. Sie implementiert send_document, send_image_file und send_video, und ihr Sender verarbeitet media_files. Sie liegt schlicht außerhalb der Menge an Plattformen, die das Tool send_message als media-fähig behandelt. Bittest du es, ausschließlich Medien zuzustellen, verweigert das Tool rundheraus:

send_message MEDIA delivery is currently only supported for telegram, discord, matrix, weixin, signal, yuanbao, feishu, whatsapp, slack and qqbot; target mobile had only media attachments

Schickst du Text und eine Datei, bekommst du den leiseren Fehler: Der Text geht durch, die Attachments werden verworfen, mit einer Warnung, die nur im Tool-Result auftaucht. Aus Nutzersicht sieht die Nachricht gesendet aus — genau deshalb beschrieb der meldende Maintainer das Ergebnis damit, dass sein Agent einem Nutzer wiederholt sagte, „die Datei ist angehängt“, während nichts ankam.

Wo die Entscheidung fällt

tools/send_message_tool.py beantwortet die Frage „kann diese Plattform Dateien empfangen?“ an zwei Stellen, und nur eine davon betrifft dein Plugin:

  • Ein für Menschen lesbarer Hinweis, der in jener Fehlermeldung verwendet wird: telegram, discord, matrix, weixin, signal, yuanbao, feishu, whatsapp, slack and qqbot.
  • Ein Dict, das den Plugin-Pfad tatsächlich aktiviert und deutlich kürzer ist:
_PLUGIN_STANDALONE_MEDIA = {
    "discord": ("Discord", False, True, [], False),
    "feishu": ("Feishu", True, False, None, False),
    "slack": ("Slack", True, True, [], False),
    "whatsapp": ("WhatsApp", True, True, None, True),
}

Jeder Wert ist ein Tuple aus (label, discover_plugins_first, caption_capable, media_files_sentinel, pass_force_document), wie der Kommentar darüber sagt. Die Liste existiert, weil das Einbauen von Dateien in die Payloads dieser vier Plattformen Wissen erfordert, das der generische Sender nicht hat — erzwungene Discovery der Plugin-Registry, Caption-Handling oder eine bestimmte Form für nicht-finale Media-Chunks.

Jede Plugin-Plattform, die nicht in diesem Dict steht, fällt auf den generischen Text-Only-Pfad zurück: Text überlebt, Attachments werden verworfen, und ein Media-Only-Aufruf schlägt fehl, wie oben gezeigt. Nichts im Code des Plugins selbst wird herangezogen — und das ist der schmerzhafte Teil: Die Plattform kann voll leistungsfähig sein und bleibt für die Entscheidung trotzdem unsichtbar.

Warum „einfach die Plattform hinzufügen“ nicht der ganze Fix ist

Der meldende Maintainer machte das naheliegende Experiment: lokal ein Tuple für seine Plattform hinzufügen (("Mobile App", True, True, [], False)) — und das Tool leitet das Attachment durch die standalone_sender_fn des Plugins. Die Datei kam als Media-Frame an — kind=document, mime=text/markdown, byte-identisch zum Original. Die Verkabelung funktioniert also; es ist das Gate, das nicht funktioniert.

Aber ein hartkodiertes Dict bedeutet, dass jede künftige Plugin-Plattform einen Core-Edit braucht, bevor sie eine Datei senden kann — und die Person, die weiß, dass die Plattform media-fähig ist, ist nie die Person, die den Core bearbeitet. Das Issue schlägt den naheliegenden Ausweg vor: Das Plugin soll es in seinem Registry-Eintrag deklarieren — etwa media_files_supported und ein Captionable-Flag, gelesen dort, wo _plugin_standalone_sender den Sender auflöst —, damit die Fähigkeit mit dem Plugin reist, statt in einer Core-Allow-List zu leben.

Dieser Bug-Hunt hatte eine zweite Ebene, und das ist eine nützliche Erinnerung für alle, die einen Plugin-Adapter schreiben: Der Maintainer fand außerdem zwei Fehler auf der Adapter-Seite, behoben in Version 1.1.1 seines Adapters. Media-Descriptors kommen als (path, is_voice)-Tuples an, und ihr Sender hatte sie als einfache Strings behandelt, sodass keine Datei aufgegriffen wurde. Mit anderen Worten: „meine Plattform ist media-fähig“ muss durchgängig stimmen — das Tool muss das Attachment weiterleiten und der Adapter muss verstehen, was er bekommt.

Wenn du heute darauf stößt

  • Lies das Tool-Result, nicht den Chat. Wenn ein Agent eine Datei als gesendet meldet, steht der Grund für ein verschwundenes Attachment im Tool-Result von send_message, nicht in der Antwort des Assistenten. Wenn du deine eigene Bridge debuggst, ist dieser String das Erste, was du lesen solltest.
  • Halte Text und Medien bei der Arbeit getrennt. Text-Only-Nachrichten funktionieren auf einer Plugin-Plattform immer; ein Media-Only-Versand schlägt laut fehl, was für die Diagnose sogar nützlicher ist.
  • Für Plugin-Autoren: Verfolge die Frage der Fähigkeit in deiner Registry, statt sie anzunehmen, und stelle sicher, dass deine standalone_sender_fn die Tuple-Form verarbeitet, die sie bekommt. Brauchst du heute Attachments, bleiben dir ein lokaler Patch am Dict in deinem eigenen Hermes-Checkout oder das Warten auf eine Core-Änderung — keins von beidem sollten Nutzer still erledigen müssen.
  • Für alle anderen: Wenn du eine Plugin-Plattform nutzt und Dateizustellung wichtig ist, melde das Registry-deklarierte Flag oder stimme dafür. Ein Eintrag pro Plattform in einem Core-Dict ist eine Wartungslast, die eine deklarierte Fähigkeit beseitigt.

Status

Gemeldet als Issue #139354 am 15. Oktober 2026, mit einem reproduzierbaren Fall gegen ein Mobile-Plugin und dem oben beschriebenen lokal verifizierten Fix. Zum Zeitpunkt des Schreibens ist das Core-Verhalten unverändert: Es entscheidet das Vier-Plattformen-Dict, und das im Issue vorgeschlagene Design — eine vom Plugin deklarierte Fähigkeit — ist ein Vorschlag, keine ausgelieferte Änderung.

Man sollte das in Perspektive halten: send_message ist ein Tool, und dies ist eines seiner Gates. Wenn du eine Plugin-Plattform breiter aufbaust, ist der hermes-mobile-Ecosystem-Eintrag ein funktionierendes Beispiel für einen Adapter, der diese Klasse von Problemen von der Plattformseite aus beheben musste, und die hermes send-Befehlsreferenz deckt die CLI-Oberfläche ab, die das Tool umhüllt.


Quellen: Issue #139354 im Hermes Agent Repository (inklusive der lokalen Verifikation des Reporters und der Adapter-Fixes in Version 1.1.1); tools/send_message_tool.py auf main für _PLUGIN_STANDALONE_MEDIA und den in der Fehlermeldung verwendeten Media-Plattform-Hinweis.