Files
ClawdDotNet/docs/Agentenkommunikation-Konzept.md
T
RichardandClaude Opus 5 740649789e Eine Roadmap statt neun verteilter Listen
Der Stand lag ueber eine Bestandsaufnahme, drei Konzeptpapiere, vier
Umsetzungsplaene und zwei Deploymentcenter-Dokumente verteilt - jedes mit
eigener Reihenfolge, teils widersprueglich. Alle offenen Punkte daraus sind
in docs/Roadmap.md zusammengefuehrt.

Aufbau der neuen Roadmap
- Statusvokabular: erledigt / beschlossen-offen / Entscheidung noetig /
  zurueckgestellt / Idee. Damit steht das Geparkte sichtbar drin, statt in
  einem Konzeptpapier zu verschwinden.
- Herkunft-Spalte traegt das alte Kuerzel (S4, K2, B9, T4, F-A1, C1, DC1),
  damit die archivierten Papiere auffindbar bleiben, ohne sie zu lesen.
- Abschnitt 1 Reihenfolge, 2 offene Entscheidungen, 3 die Vorhaben nach
  Bereich, 4 Ideenspeicher, 5 Chronik des Erledigten, 6 Modell-Einstufung,
  7 Herkunftskarte.

Was dabei sichtbar wurde
- Neun Entscheidungen blockieren Arbeit, ohne dass sie Aufwand kosten -
  allen voran Matrix oder Rocket.Chat. Sie stehen jetzt gesammelt in
  Abschnitt 2 statt verstreut in den Diskussionsteilen der Konzepte.
- B8 (keine Tiefenbegrenzung bei AgentComm) ist unveraendert offen. Das ist
  keine Theorie: A haelt sein Gate, waehrend es auf B wartet - ruft B nun A,
  warten beide bis zum Timeout. Der Testfall A13 dafuer fehlt bis heute.
- Die vier Umsetzungsplaene vom 2026-08-05 sind alle unumgesetzt und waren
  in keiner Roadmap verzeichnet.

Archiv
Sechs Dokumente ziehen nach docs/archiv/: Bestandsaufnahme, Konzepte
Backup/Finanz/Analyse, Linux-Portierung-Analyse, Lizenz-HardwareId-v2
(gegenstandslos - LicenseLabrador ist ersetzt), Deploymentcenter-Review und
der 2.4-Integrationsplan. Sie bleiben als Begruendung lesbar, werden aber
nicht mehr fortgeschrieben; das README ordnet jedes einzeln ein und warnt,
dass ihre Quelltext-Verweise ins Leere gehen koennen.

Bauplan bleibt Bauplan
Taskboard, Audit, Staging, Memory, Agentenkommunikation, RocketChat und
Deploymentcenter-Integration bleiben in docs/ - sie sind die Detailvorgabe
fuer die Umsetzung, nicht Vorhabenlisten. Jedes bekommt oben eine Zeile,
die seine Rolle und den Umsetzungsstand nennt und auf die Roadmap zeigt.
Dasselbe fuer die vier Umsetzungsplaene: die Reihenfolge gilt in der
Roadmap, nicht im Plan.

Nebenbei repariert: Taskboard-Konzept und Teststrategie verwiesen auf
AgentScheduler und ToolJobScheduler, die seit der Scanner-Konsolidierung
geloescht sind. Alle Dokument-Verweise in docs/ sind geprueft.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 18:31:06 +02:00

16 KiB

Agentenkommunikation — Erfassung, Ansicht, Auswertung

Bauplan — noch nicht gebaut. Die fünf Phasen sind in der Roadmap 3.3 einzeln eingeordnet; die Tiefenbegrenzung (B8) ist dort Punkt 4 der Reihenfolge. Die Ansicht aus Phase 4 steht bereits und wartet auf den Speicher aus Phase 2.

Ziel: Die gesamte Kommunikation zwischen Agenten wird erfasst, ist im WhatsApp-Stil paarweise nachlesbar und lässt sich von einem Agenten automatisiert auswerten — um zu finden, wo die Zusammenarbeit klemmt.

Abgegrenzt davon: Rocket.Chat (siehe RocketChat-Nextcloud-Konzept) trägt ausschließlich das, was ein Mensch wissen soll. Interne Absprachen der Agenten gehen dort nie hin.

Aufbauend auf Audit-Konzept (A3) und Taskboard-Konzept (A1).


1 — Beschlüsse (August 2026)

# Beschluss
1 Korrelation: ParentRunId + RootRunId in Audit-Log und Receipts. Eine Delegationskette wird damit zu einer Abfrage.
2 Nachrichtenspeicher: eigene Tabelle AgentMessages, die alle Wege gleich behandelt und beide Richtungen festhält.
3 Rocket.Chat bleibt außen vor — kein Spiegeln der Agentenkommunikation dorthin. Ein Gruppenchat mit allem drin wäre unlesbar.
4 Ansicht: Paar auswählen (Agent A / Agent B), Verlauf im Chat-Stil scrollen.
5 Auswertung: ein Analyse-Tool, das ein dafür vorgesehener Agent bekommt.

2 — AgentComm behalten oder durch das Taskboard ersetzen?

Das war die offene Frage. Der Befund zuerst, die Empfehlung danach.

2.1 Was heute passiert

AgentComm.send_message ist ein synchroner Aufruf: A ruft, SendMessageAsync startet ChatAsync(B), wartet auf den vollständigen Lauf von B und gibt dessen Schlussnachricht als Tool-Ergebnis an A zurück. Drei Eigenschaften folgen daraus:

  • Es gibt keine Tiefenbegrenzung (B8). A→B→A→B… läuft, bis ein Timeout greift.
  • Es kann echt verklemmen. Seit B2 serialisiert ein Gate je Agent alle Läufe. A hält sein Gate, während es auf B wartet. Ruft B nun send_message(A), wartet B auf As Gate — das A hält, während es auf B wartet. Das löst nur der Timeout auf. Der Selbstaufruf A→A wurde damals abgefangen, der Zweierzyklus nicht.
  • Der Fehler ist teuer: Jeder Hop ist ein vollständiger, bezahlter Lauf.

2.2 Was ein Task nicht kann

Trotzdem ist „einfach alles über Tasks" nicht ohne Verlust. Zwei Dinge kann der asynchrone Weg strukturell nicht:

  • Antwort im selben Lauf. Bei send_message kommt die Antwort als Tool-Ergebnis zurück, und A arbeitet damit sofort weiter. Über einen Task endet As Lauf; die Antwort kommt später als neuer Weckvorgang, und A muss seinen Gedankengang neu aufnehmen. Für eine Rückfrage sind das zwei Läufe statt einem — der asynchrone Weg ist hier also nicht nur langsamer, sondern teurer.
  • Antwortzeit. Der Scanner tickt im Minutentakt. Eine Rückfrage „hast du die Datei schon abgelegt?" braucht damit im Mittel eine halbe Minute plus den Lauf des anderen.

2.3 Empfehlung: nach Zweck trennen, nicht beides parallel führen

Der Fehler in der jetzigen Lage ist nicht, dass es zwei Mechanismen gibt — es ist, dass beide dasselbe können. Ein Agent kann Arbeit sowohl per Task delegieren als auch per send_message „mal eben" abschieben, und der zweite Weg ist der gefährliche.

Vorschlag:

Delegation gehört ausschließlich ins Taskboard. AgentComm verliert diese Rolle vollständig — kein „mach du mal", kein Auftrag, kein Arbeitspaket.

Die kurze Rückfrage bleibt, aber als eigenes, eng gefasstes Werkzeug: ask_agent.

ask_agent mit harten Grenzen:

Grenze Begründung
Tiefe 1 — wer gerade eine Rückfrage beantwortet, darf selbst keine stellen Beendet die Rekursion an der Wurzel. Prüfbar, sobald ParentRunId steht (Punkt 1) — die Synergie ist der Grund, warum das jetzt fast umsonst zu haben ist
Zyklusprüfung — Ziel darf nicht im aktuellen Aufrufpfad liegen Schließt den Deadlock aus 2.1 aus, statt auf den Timeout zu hoffen
Kurzer Timeout + kleines Schrittbudget (z. B. 60 s, 5 Schritte) Eine Rückfrage, die fünf Schritte braucht, war keine Rückfrage, sondern ein Auftrag
Eigene Beschreibung im Prompt: „für kurze Fragen an einen Kollegen, nicht um Arbeit abzugeben" Der häufigste Missbrauch ist der falsche Griff, nicht die böse Absicht

Damit gibt es weiterhin zwei Wege, aber sie überschneiden sich nicht mehr: Der eine ist ein Auftrag (dauerhaft, nachvollziehbar, mit Abnahme), der andere eine Frage (flüchtig, sofort, begrenzt).

Die Gegenposition, fairerweise: Man kann AgentComm auch ersatzlos streichen und die Rückfrage über einen Task mit hoher Priorität abbilden. Das wäre die konsequentere Umsetzung des „alles ist ein Task"-Prinzips und spart ein Tool. Der Preis sind die zwei Läufe je Rückfrage und die Minute Wartezeit. Meine Empfehlung ist die Trennung, weil Rückfragen im Mehr-Agenten-Betrieb häufig sind und der Aufpreis sich dann summiert — aber das ist eine Abwägung, keine technische Notwendigkeit.

AgentSpawn geht in beiden Varianten im Taskboard auf (assignee: @new:<agent> ist genau das) und wird zurückgebaut.


3 — Korrelation: ParentRunId und RootRunId

Heute erzeugt jeder Lauf eine frische runId; der Lauf des Empfängers weiß nichts vom Lauf des Absenders. Eine Kette A→B→C ist deshalb nur über Zeitstempel zu erraten.

Zwei Felder auf AuditEntry und RunReceipt:

  • ParentRunId — der Lauf, aus dem dieser hervorging. null bei einem Lauf, den ein Mensch oder der Scanner auslöst.
  • RootRunId — die Wurzel der Kette. Das ist faktisch die Vorgangs-Id: Alles, was aus einer Anweisung entstand, trägt denselben Wert.

Regeln:

  • Die Engine stempelt. Wie beim Audit gilt: Herkunft wird nie vom Agenten behauptet.
  • Ein Lauf ohne Vorgänger ist seine eigene Wurzel (RootRunId = RunId).
  • Weitergereicht wird über die Aufrufstellen, an denen ein Lauf einen anderen auslöst: ask_agent, Task-Dispatch, Staging-Folgetask.
  • Migration: Bestandszeilen bekommen RootRunId = RunId und ParentRunId = NULL. Das ist nicht rückwirkend korrekt, aber ehrlich — alte Ketten bleiben unbekannt, statt falsch zusammengesetzt zu werden.

Der Nutzen reicht über die Analyse hinaus: Was eine Delegationskette insgesamt gekostet hat, ist danach ein SUM über RunReceipts gruppiert nach RootRunId. Damit fällt ein Teil von C7 nebenbei ab.


4 — Der Nachrichtenspeicher

4.1 Tabelle

Neue Tabelle in der Instanz-DB, neben AuditLog und RunReceipts:

CREATE TABLE IF NOT EXISTS AgentMessages (
    Id          INTEGER PRIMARY KEY AUTOINCREMENT,
    PairKey     TEXT NOT NULL,   -- sortiertes Paar: "agentA|agentB"
    FromAgentId TEXT NOT NULL,
    ToAgentId   TEXT NOT NULL,
    Channel     TEXT NOT NULL,   -- ask | task | task_comment | task_result
    Direction   TEXT NOT NULL,   -- request | response
    Content     TEXT NOT NULL,   -- vollständig, nach Scrubbing
    RunId       TEXT NOT NULL,
    ParentRunId TEXT,
    RootRunId   TEXT NOT NULL,
    TaskId      TEXT,
    Status      TEXT NOT NULL,   -- delivered | failed | timeout | denied
    OccurredAt  TEXT NOT NULL
);
CREATE INDEX IX_AgentMessages_Pair ON AgentMessages(PairKey, OccurredAt);
CREATE INDEX IX_AgentMessages_Root ON AgentMessages(RootRunId, OccurredAt);

Dazu ein FTS5-Index auf Content — dieselbe Technik wie beim geplanten Historien-Umzug (K6), damit die Suche in der Ansicht und im Analyse-Tool nicht über LIKE läuft.

4.2 Die Entscheidungen dahinter

PairKey als sortiertes Paar. Die geforderte Ansicht („A und B auswählen, scrollen") wird damit zu WHERE PairKey = ? ORDER BY OccurredAt — eine Abfrage auf einem Index, unabhängig davon, wer gerade wen anspricht.

Beide Richtungen als eigene Zeilen. Eine Rückfrage erzeugt zwei Zeilen (request A→B, response B→A) mit derselben RootRunId. Nur so entsteht ein Verlauf, der sich wie ein Chat liest. Das Audit-Log kann das nicht leisten: Es speichert nur Arguments, die Antwort landet dort nirgends.

Inhalt ungekappt. Das Audit kappt bei 4.000 Zeichen — richtig, denn es dient der Nachvollziehbarkeit. Für die Auswertung braucht es den vollen Text. Gekappt wird erst dort, wo Text in einen LLM-Kontext zurückfließt (Abschnitt 6).

Alle Wege in einer Tabelle. ask_agent, Task-Delegation, task_comment und das Ergebnis eines Tasks landen im selben Format. Sonst müsste die Auswertung drei Quellen zusammensuchen — und genau daran scheitert sie heute.

Fan-out statt Sammelzeile. Eine Nachricht an mehrere Empfänger wird zu mehreren Zeilen. Etwas redundant, dafür bleibt jede Zeile paarweise auswertbar.

4.3 Wer schreibt

Ein IAgentMessageLog im Core, aufgerufen an genau den Stellen, an denen eine Nachricht eine Agentengrenze überschreitet:

Aufrufstelle Zeilen
AgentEngineask_agent request beim Absenden, response beim Rückgabewert (auch bei Fehler/Timeout, mit passendem Status)
Taskboard — task_create mit fremdem Assignee request
Taskboard — task_comment request bzw. response, je nach Richtung
Taskboard — Task abgeschlossen/geblockt response mit Ergebnis oder Blocker-Grund

Drei bis vier Stellen, alle im Core. Kein Tool schreibt selbst — sonst könnte ein Agent seine eigene Kommunikationsakte färben.

Fehlschläge werden mitgeschrieben. Eine nicht zugestellte Nachricht ist für die Analyse wertvoller als eine erfolgreiche.

4.4 Was hier nicht hineingehört

  • Mensch↔Agent-Chat. Das ist die Chat-Historie, ein anderer Gegenstand mit anderem Umzugsplan (K6). Ausnahme mit gutem Preis-Leistungs-Verhältnis: Tasks mit assignee: @human durchlaufen dieselben Aufrufstellen — man kann sie als Paar (Agent, @human) mitschreiben und bekommt die Ansicht dafür geschenkt. Vorschlag: ja, aber als Nachzügler, nicht als Teil der ersten Fassung.
  • Tool-Aufrufe. Die stehen im Audit-Log und gehören nicht in einen Gesprächsverlauf.
  • Rocket.Chat-Nachrichten. Anderer Gegenstand, andere Vertrauensgrenze.

4.5 Zwei Pflichten

  • Output-Scrubbing vor dem Schreiben. Nachrichteninhalte enthalten Tool-Ergebnisse. Ohne Maskierung bekannter Geheimnisse wird dieser Speicher zur zweiten Fundstelle für Zugangsdaten — und über den MySQL-Spiegel (A6) verlässt er sogar die Maschine. Der Roadmap-Punkt „Output-Scrubbing" ist damit Voraussetzung, nicht Beiwerk.
  • Aufbewahrung. Die Tabelle wächst unbegrenzt. Ein Instanz-Wert (agentMessageRetentionDays, 0 = unbegrenzt) plus ein Aufräum-Task gehören von Anfang an dazu, nicht erst, wenn die DB groß ist.

5 — Die Ansicht

Neuer Reiter im Hauptfenster: Agentenkommunikation.

Bedienung: zwei Auswahlfelder (Agent A, Agent B) — dazu „alle" für einen Agenten, um zu sehen, mit wem er überhaupt spricht. Zeitraum, Kanalfilter, Freitextsuche.

Darstellung: Chat-Stil, A rechts, B links, Zeitstempel, Tagestrenner. Jede Blase trägt eine kleine Kennzeichnung des Kanals (Rückfrage / Auftrag / Kommentar / Ergebnis) und, wo vorhanden, die anklickbare Task-Id.

Technisch: damals über den WebView2-Unterbau von frm_chat gedacht. Beides gibt es seit der Avalonia-Portierung nicht mehr — der Abschnitt ist als Entwurfsstand von damals zu lesen; die Ansicht wäre heute eine Avalonia-Seite wie AgentChatsPageView (inkl. Virtual-Host-Mapping auf einen lokalen Ordner). Der Verlauf wird als HTML gerendert. Handgezeichnete Sprechblasen wären dort ein Vielfaches an Aufwand für ein schlechteres Ergebnis.

Paging: die jüngsten ~200 Nachrichten, „ältere laden" nach oben. Ein Paar mit 50.000 Zeilen darf die Oberfläche nicht am Start blockieren.

Der eigentliche Mehrwert liegt über dem flachen Verlauf: Ein Klick auf eine Nachricht zeigt die ganze Kette zu ihrer RootRunId — also den Vorgang von der auslösenden Anweisung bis zum letzten Beitrag, über alle beteiligten Agenten hinweg, mit den Kosten aus den Receipts. Das ist die Ansicht, die die Frage „warum hat das drei Stunden und vier Dollar gekostet" tatsächlich beantwortet.


6 — Automatisierte Auswertung

Ein Tool AgentCommAnalysis, das bewusst nur einem dafür vorgesehenen Agenten zugewiesen wird (die Zuweisung je Agent gibt es ohnehin).

Aktion Zweck
list_pairs Wer spricht mit wem, wie oft, seit wann — der Einstieg
stats Kennzahlen je Paar/Kanal/Zeitraum (siehe unten)
read_conversation Verlauf eines Paares, gekappt und seitenweise
chain Ein kompletter Vorgang über RootRunId, inkl. Kosten
search Volltext über FTS5

Fragen, die das beantworten soll — sie sind der Grund für den Schnitt des Schemas:

  • Wie viele Delegationen führen zu einem Ergebnis, und wie viele versanden?
  • Wie tief werden Ketten, und ab welcher Tiefe steigt die Fehlerquote?
  • Welche Paare stellen sich wiederholt dieselbe Rückfrage? (Ein Hinweis auf unklare Zuständigkeit oder einen fehlenden Skill — genau die Art Problem, die man sucht.)
  • Was kostet ein Vorgang von der Anweisung bis zum Ergebnis?
  • Wo häufen sich failed/timeout?

Drei Sicherungen, weil ein Agent hier fremde Kommunikation liest:

  1. Ergebnisse werden als <untrusted_content> gerahmt. Der Inhalt stammt aus anderen Läufen und kann Anweisungen enthalten — auch ohne böse Absicht.
  2. Standardmäßig liefert das Tool Kennzahlen, Rohtext nur auf ausdrückliche Anfrage und mit harter Obergrenze. Ein unbedachtes „lies mir alles vor" ist sonst ein Kontext-Überlauf mit Rechnung.
  3. Das Tool ist lesend. Es gibt keine Schreibaktion.

7 — Verhältnis zu Rocket.Chat

Klargestellt, weil es die vorherige Überlegung ablöst:

  • Agentenkommunikation wird nicht nach Rocket.Chat gespiegelt. Ein Raum, in dem jede interne Absprache mitläuft, ist nach einer Woche unlesbar und verdeckt genau das, was man sehen soll.
  • Nach Rocket.Chat geht nur, was ein Mensch wissen soll oder muss — über den ChannelRouter bzw. eine bewusste Handlung des Agenten.
  • Wer den internen Verlauf sehen will, nimmt die Ansicht aus Abschnitt 5. Die ist dafür gebaut; ein Gruppenchat ist es nicht.

8 — Schnitt

Phase Inhalt Abhängigkeit
1 ParentRunId + RootRunId in AuditLog/RunReceipts, Migration, Stempelung in der Engine
2 AgentMessages + FTS5 + IAgentMessageLog, Schreiben an den Aufrufstellen 1
3 ask_agent (Tiefe 1, Zyklusprüfung), Rückbau von AgentComm/AgentSpawn 1 — die Tiefe kommt aus der Kette
4 Ansicht (WebView2-Reiter) 2
5 AgentCommAnalysis-Tool 2
Output-Scrubbing vor 2

Phase 1 zuerst, weil Phase 3 die Kette braucht und Phase 2 die Felder mitschreibt. Das Scrubbing muss vor Phase 2 stehen — sonst legen wir einen Speicher an, der erst nachträglich bereinigt werden müsste.

Zur Einstufung: Phasen 1, 2, 4 und 5 sind gut spezifizierbar. Phase 3 fasst das Agent-Gate an, an dem schon einmal ein Deadlock lauerte (B2/B8) — dafür gehören die Tests aus der Teststrategie mit dazu, insbesondere der dort vorgesehene, bis heute fehlende Fall A13 (A→B→A wird begrenzt statt zu verklemmen).


9 — Offene Punkte

  1. ask_agent behalten oder ersatzlos streichen? Meine Empfehlung steht in 2.3 (behalten, eng gefasst) — die Gegenposition ist dort ebenfalls notiert.
  2. @human-Tasks mitschreiben? Gibt die Paar-Ansicht auch für Mensch↔Agent, fast ohne Zusatzaufwand. Vorschlag: ja, aber nach Phase 4.
  3. Aufbewahrungsdauer — Vorgabewert? (Vorschlag: unbegrenzt, bis der Spiegel aus A6 steht; dann 180 Tage lokal.)
  4. Wer bekommt AgentCommAnalysis? Ein eigener Analyse-Agent oder ein bestehender?