5.1 KiB
Staging-Freigabe für irreversible Aktionen
Setzt A2 aus der Roadmap um (F-A1 + S4). Irreversible Aktionen werden gestaged statt ausgeführt: Vorschlag → Review im Hauptfenster → Freigabe/Ablehnung. Aufbauend auf dem Taskboard (A1, Fortsetzung nach Freigabe) und dem Audit-Log (A3, Approval-Records).
Sicherheitswirkung: Eine Prompt-Injection (K2) kann dann nur noch einen Vorschlag erzeugen, keine Ausführung.
Das Gate wird zum Durchsetzungspunkt (S4)
Das bisher wirkungslose PermissionGate (es prüfte nur, ob ein Tool zugewiesen ist)
wird zur zentralen Stelle: Policy-Prüfung, Staging-Entscheidung und Audit-Hook an
einer Stelle (AgentEngine.ExecuteToolCallAsync), statt ad-hoc in jedem Tool. S4
geht hier auf.
Policy: auto | approve | deny pro Tool/Aktion
Je (Tool, Aktion) eine Entscheidung:
auto— läuft wie bisher.approve— wird gestaged; die Ausführung wartet auf eine menschliche Freigabe.deny— wird gar nicht erst vorgeschlagen, sondern abgelehnt.
Auflösung vom Speziellen zum Allgemeinen: Tool.Aktion → Tool → Standard (auto).
Die „Aktion" ist das action-Argument des Aufrufs (die meisten Tools haben es).
Eingebaute Standardregeln (nach Sichtung der Tools, überschreibbar per Konfiguration) — genau die in der Roadmap genannten irreversiblen Aktionen:
| Tool.Aktion | Standard |
|---|---|
Mail.send |
approve |
Telegram.send_message |
approve |
Database.insert, Database.upsert |
approve |
FileRW.delete |
approve |
FTP.upload, FTP.delete |
approve |
| alles andere | auto |
Lesende Aktionen (Mail.read_inbox, FileRW.read, Database.query, …) bleiben auto —
Staging soll schützen, nicht lähmen.
Plan-Freeze
Freigegeben wird ein eingefrorener, konkreter Aufruf: Tool, Aktion und die exakten Argumente zum Zeitpunkt des Stagings. Ausgeführt wird genau das Eingefrorene (der gespeicherte Argument-JSON), nie eine nachträglich veränderte Fassung. Jede Änderung wäre eine neue Freigabe.
Das ist auch der Grund, warum der Agent den Aufruf nicht nach der Freigabe erneut formuliert (er könnte etwas anderes bauen) — der eingefrorene JSON wird direkt an das Tool gegeben.
Fortsetzung nach Freigabe — kein pausierter Lauf
Die tragende Architektur-Vorgabe (aus der Roadmap-Einstufung): Kein pausierter, im Speicher gehaltener Lauf. Der Ablauf:
- Vorschlag. Der Agent ruft eine
approve-Aktion auf. Das Gate führt sie nicht aus, sondern legt einen Pending-Datensatz an (eingefrorener Aufruf) und gibt dem Agenten „Zur Freigabe vorgelegt (#id)" als Tool-Ergebnis zurück. Der Lauf endet regulär — der Agent schließt ab, nichts hängt im Speicher. - Review. Ein Mensch sieht die offenen Vorschläge im Hauptfenster und entscheidet.
3a. Freigabe. Der eingefrorene Aufruf wird direkt ausgeführt (standalone, nicht
über einen Chat-Lauf). Das Ergebnis wird festgehalten, und ein Folge-Task (A1)
weckt den Agenten: „Deine Aktion X wurde freigegeben und ausgeführt, Ergebnis: Y —
mach weiter." Der Scanner stellt ihn zu (
ChatAsync, bestehender Kontext). 3b. Ablehnung. Ein Folge-Task weckt den Agenten mit der Ablehnung (samt Grund).
Echtes Suspend/Resume eines laufenden ChatAsync wäre Fable-Terrain — und ist mit dieser
Vereinfachung unnötig.
Approval-Records (A3)
Jede Entscheidung — Freigabe wie Ablehnung — wird an zwei Stellen verankert:
- Im Staging-Datensatz selbst: Status,
DecidedBy,DecidedAt, Ergebnis-Verweis bzw. Ablehnungsgrund. - Als Audit-Eintrag (A3): Tool, Ausgang,
source: approval, „Freigegeben von …" bzw. „Abgelehnt von …". Die Herkunft stempelt auch hier das System, nicht der Agent.
Der Vorschlag selbst wird beim Anlegen als Audit-Eintrag mit Status Staged notiert —
so ist die ganze Kette (Vorschlag → Entscheidung → Ausführung) im Log nachvollziehbar.
Nebenläufigkeit
Zwei Reviewer dürfen nicht denselben Vorschlag doppelt freigeben. Der Übergang
pending → approved/rejected ist ein atomares, bedingtes UPDATE (dieselbe
Claim-Technik wie beim Taskboard): Genau einer gewinnt, der zweite Klick läuft ins Leere.
Erst nach gewonnenem Übergang wird der eingefrorene Aufruf ausgeführt.
Verdrahtung
StagingGate(Policy + Anlegen des Vorschlags) hängt optional an der Engine — ohne es läuft alles wie bisher (auto).- Der eingefrorene Aufruf wird über
IFrozenCallExecutor(von der Engine implementiert) ausgeführt: gültiger Tool-Kontext, aber ohne LLM-Schleife. StagingService(Freigabe/Ablehnung) nutzt Executor, Audit und das Taskboard für den Folge-Task. Es ist die API, die die Review-Oberfläche aufruft.
Offen
- Review-Oberfläche im Hauptfenster (Liste der offenen Vorschläge, Freigeben/Ablehnen) — die Dienst-API steht bereit; die WinForms-Ansicht ist die verbleibende Integration.
- Output-Scrubbing greift auch hier auf den gespeicherten Argument-JSON, sobald es steht (eigener Roadmap-Punkt).
- Orders (Handelsaufträge) reihen sich später als weitere
approve-Aktionen ein.