# Trustee Tooling Overhaul & PWG Demo Preparation ## Beschreibung und Kontext Für den PWG-Inspirationsworkshop (16. April 2026) werden drei Use Cases in PORTA demonstriert. Use Case 1 (Belegverarbeitung + Budgetkontrolle) und Use Case 3 (Datenneutralisierung) erfordern Code-Anpassungen im Trustee-Feature und im Agent-Tooling. **Business-Treiber:** PWG AG (gemeinnützige Wohnungsstiftung Zürich, 200+ Liegenschaften, Abacus als Hauptsystem) evaluiert PORTA. Der Workshop ist die erste Live-Demo — Plattform-Tiefgang und funktionierende Schnittstellen sind entscheidend. **Risiko bei Nicht-Umsetzung:** Demo scheitert an fehlenden Tools (Agent kann keine Buchhaltungsdaten lesen), langsamer Performance (jede Query startet neuen Sub-Agent-Loop) oder fehlendem Workflow im Graphical Editor. Parallel zur Demo-Vorbereitung wird das Trustee-Tooling grundlegend überarbeitet. Die aktuelle Architektur hat strukturelle Schwächen, die auch im Produktivbetrieb problematisch sind. **Hinweis:** Die Automation Unification (v1/v2 → Graphical Editor) ist abgeschlossen (siehe `c-work/3-validate/2026-04-automation-unification.md`, Status: done). Dieses Dokument baut auf dem konsolidierten System auf: Feature `graphicalEditor`, DB `poweron_graphicaleditor`, konsolidierter Scheduler. ## Fokus und kritische Details ### Ist-Zustand Trustee-Tooling (Analyse) | Fähigkeit | Status | Problem | |-----------|--------|---------| | **Daten lesen (Agent)** | `queryFeatureInstance` → Sub-Agent mit `browseTable`/`queryTable` | Jeder Call öffnet neue DB-Connection + startet 5-Runden-Agent-Loop mit AI-Calls. Kein Caching. Langsam (~5-15s pro Query). | | **Daten aus Buchhaltung importieren** | `AccountingDataSync.importData()` via REST-Endpoint | Full-clear + Full-write bei jedem Import. Kein inkrementeller Sync. Kein Agent-Zugriff (nur REST). | | **Daten schreiben (Agent)** | Nicht vorhanden | Agent kann keine Trustee-Positionen erstellen oder ändern. | | **Daten aggregieren** | Nicht vorhanden | Sub-Agent hat nur row-level Tools. Keine SQL-Aggregationen (SUM, GROUP BY). Für Budgetvergleiche muss der Agent alle Rows laden und selbst rechnen. | | **Chart of Accounts** | `AccountingBridge.getChartOfAccounts()` mit Cache auf `TrusteeAccountingConfig` | Funktioniert, aber nur für Bridge-interne Nutzung. Agent hat keinen direkten Zugriff. | | **Graph-Editor Nodes (Trustee)** | 3 Nodes in `nodeDefinitions/trustee.py`: `extractFromFiles`, `processDocuments`, `syncToAccounting` | Alle `dynamicMode=False` — nicht als Agent-Tools verfügbar. Für Graph-Editor nutzbar. Kein Node für `refreshAccountingData` / Datenimport. | | **Graph-Editor Nodes (SharePoint)** | 6 Nodes in `nodeDefinitions/sharepoint.py`: findFile, readFile, uploadFile, listFiles, downloadFile, copyFile | Vorhanden und funktional. `listFiles` + `downloadFile` reichen für den Demo-Flow. | | **Graph-Editor Nodes (Flow)** | 5 Nodes: ifElse, switch, loop, merge, delay | Loop-Node vorhanden (`flow.loop`). Nötig für "für jede Datei aus SharePoint → Trustee-Pipeline". | | **Node-Kategorie `trustee`** | Nodes nutzen `category: "trustee"` | **Fehlt in `nodeRegistry.getNodeTypesForApi()` Categories-Liste** (Zeile 63-73) — Trustee-Nodes werden im Editor nicht unter eigener Kategorie angezeigt. | | **Toolbox `trustee`** | Nicht vorhanden | Die Toolbox Registry (`toolboxRegistry.py`) hat Toolboxes für email, sharepoint, clickup, jira, workflow — aber keine für Trustee. Für den Agent-Zugriff auf Trustee-Actions (`dynamicMode=True`) wäre eine Toolbox sinnvoll. | ### Performance-Problem `queryFeatureInstance` Der Hauptgrund für die langsame Query-Performance: 1. **Neuer Sub-Agent pro Call** — `runFeatureDataAgent` startet einen eigenen Agent-Loop (max 5 Runden, je ein AI-Call) für jede Frage. Das bedeutet: Main-Agent stellt Frage → Sub-Agent macht 1-3 AI-Calls um SQL zu generieren → Sub-Agent antwortet → Main-Agent verarbeitet. 2. **Neue DB-Connection pro Call** — `DatabaseConnector` wird jedes Mal neu instanziiert und geschlossen. 3. **Kein Result-Cache** — Identische Fragen werden jedes Mal neu beantwortet. ## Ziel und Nicht-Ziele **Ziel:** - Agent kann Trustee-Buchhaltungsdaten lesen (gecacht oder frisch vom externen System) - Agent kann Aggregationen auf Trustee-Daten ausführen (SUM, GROUP BY für Budgetvergleiche) - Graphical-Editor-Workflow für Belegverarbeitung (SharePoint → Trustee Import+Sync) funktioniert - Performance von Feature-Data-Queries deutlich verbessert - Demo für PWG-Workshop läuft stabil end-to-end **Explizit NICHT:** - Kein vollständiger Umbau des Sub-Agent-Patterns - Keine neuen Abacus-API-Endpoints (nutzen bestehenden Connector) - Keine Frontend-Änderungen am Trustee-UI ## Betroffene Module - Gateway: `features/trustee/`, `serviceCenter/services/serviceAgent/` (inkl. `toolboxRegistry.py`), `workflows/methods/methodTrustee/`, `features/graphicalEditor/nodeDefinitions/`, `features/graphicalEditor/nodeRegistry.py` - Frontend: keine Änderungen - DB-Migration: nein (nutzt bestehende `TrusteeData*`-Tabellen in Feature-DB `poweron_trustee`) - Graphical Editor: Node-Definitionen + Kategorie-Registry + Workflow-Konfiguration für Demo ## Entscheidungen | Datum | Entscheidung | Begründung | |-------|-------------|------------| | 2026-04-07 | Neues Tool `refreshTrusteeData` statt Erweiterung von `queryFeatureInstance` | Separation of Concerns: Sync ist eine schreibende Operation, Query ist lesend. Agent entscheidet selbst, ob er zuerst refreshen muss. | | 2026-04-07 | `aggregateTable`-Tool im Sub-Agent statt SQL in `queryTable` | Saubere Trennung: row-level vs. aggregate. Verhindert SQL-Injection-Risiko bei freien GROUP BY-Ausdrücken. | | 2026-04-07 | DB-Connection-Pooling für Feature-Data-Agent statt Connection-per-Call | Grösster Performance-Hebel. Connection-Aufbau ist teuer (~200ms), Pool eliminiert das. | | 2026-04-07 | Result-Cache auf WorkflowMemory-Ebene | Nutzt bestehendes Konzept (WorkflowMemory mit Embedding). Agent kann gecachte Ergebnisse aus früheren Runden wiederverwenden. | ## Umsetzungs-Checkliste ### Phase 1: Trustee Agent-Tools (Prio: hoch — Blocker für Demo UC1 Teil B) - [x] **`refreshTrusteeData`** — Neue Workflow-Action `trustee.refreshAccountingData` mit `dynamicMode=True` - Prüft `TrusteeAccountingConfig.lastSyncAt` — wenn älter als Schwellwert (z.B. 1h) oder Daten leer → triggert `AccountingDataSync.importData()` - Parameter: `featureInstanceId` (required), `forceRefresh` (optional, default false), `dateFrom`/`dateTo` (optional) - Rückgabe: Summary (Anzahl Records pro Tabelle, Sync-Dauer, ob frisch oder gecacht) - Registrierung in `MethodTrustee.__init__` analog zu bestehenden Actions - [x] **`aggregateTable`** — Neues Tool im Feature-Data-Sub-Agent (`featureDataAgent.py`) - SQL-Aggregationen: `SUM`, `COUNT`, `AVG`, `MIN`, `MAX` - `GROUP BY` auf vordefinierte Felder (Whitelist pro Tabelle) - Scope-Filter wie bei `queryTable` (featureInstanceId + mandateId) - Beispiel: `aggregateTable(tableName="TrusteeDataJournalLine", aggregate="SUM", field="debitAmount", groupBy="costCenter")` ### Phase 2: Graphical-Editor Node-Definitionen (Prio: hoch — Blocker für Demo UC1 Teil A) **Ist-Zustand Node-Registry (`features/graphicalEditor/nodeDefinitions/`):** | Datei | Nodes | Status | |-------|-------|--------| | `trustee.py` | `extractFromFiles`, `processDocuments`, `syncToAccounting` | Vorhanden, aber kein Node für Datenimport/Refresh | | `sharepoint.py` | `findFile`, `readFile`, `uploadFile`, `listFiles`, `downloadFile`, `copyFile` | Vorhanden, ausreichend für Demo | | `flow.py` | `ifElse`, `switch`, `loop`, `merge`, `delay` | Vorhanden, Loop-Node nötig für Demo | **Anpassungen:** - [x] **Kategorie `trustee` in `nodeRegistry.py` ergänzen** - In `getNodeTypesForApi()` → `categories`-Liste (Zeile 63-73) fehlt `{"id": "trustee", "label": {"en": "Trustee", "de": "Treuhand", "fr": "Fiduciaire"}}` - Ohne diese Kategorie werden die Trustee-Nodes in der Node-Palette des Graphical Editors nicht unter einer eigenen Gruppe angezeigt - [x] **Neuer Node `trustee.refreshAccountingData`** in `nodeDefinitions/trustee.py` - Mapped auf neue Workflow-Action `trustee.refreshAccountingData` (Phase 1) - Parameter: `featureInstanceId` (required), `forceRefresh` (optional), `dateFrom`/`dateTo` (optional) - Kategorie: `trustee`, Icon: `mdi-database-refresh`, Color: `#4CAF50` - Damit kann der Datenimport auch als Flow-Node genutzt werden (z.B. "Jeden Morgen Daten aus Abacus importieren") - [~] **Neuer Node `trustee.importAndProcess`** in `nodeDefinitions/trustee.py` (optional, Convenience) — **übersprungen**: bestehende 3 Nodes funktionieren dank Output-Chaining-Fix (s.u.) - Kombiniert die Pipeline `extractFromFiles` → `processDocuments` → `syncToAccounting` in einem einzigen Node - Vereinfacht den Demo-Flow auf 2 Nodes statt 4 (SharePoint Download → Trustee Import+Process+Sync) - Parameter: `connectionId`, `sharepointFolder`, `featureInstanceId`, `prompt` - Falls zu aufwändig: bestehende 3 Nodes einzeln im Flow verketten (funktioniert, ist aber visuell weniger eindrucksvoll) - [x] **Toolbox `trustee` in `toolboxRegistry.py` registrieren** (für Agent-Zugriff) - Analog zu `sharepoint`, `email`, `clickup` — Toolbox mit `requiresConnection: false` (Trustee hat eigene Config) - Enthält `refreshTrusteeData` (Phase 1) und ggf. weitere Trustee-Actions wenn `dynamicMode=True` - Ermöglicht dem Agent, Trustee-Tools via `requestToolbox("trustee")` zu aktivieren - [x] **Bestehende Trustee-Nodes prüfen und angepasst** - `trustee.extractFromFiles`: `_paramMap` korrekt (`connectionId` → `connectionReference`), Output = `ActionDocument`-Liste → wird via `model_dump()` serialisiert - `trustee.processDocuments`: **Fix implementiert** — neue `_resolveDocumentList()` Funktion erkennt sowohl Graph-Editor-Output (Liste von Dicts mit `documentData`) als auch Chat-Referenzen (Fallback). Kein Chat-Service im Graph-Editor nötig. - `trustee.syncToAccounting`: **Fix implementiert** — neue `_resolveFirstDocument()` Funktion mit gleicher Dual-Path-Logik - [x] **Output-Chaining verifiziert und gefixt:** - `actionNodeExecutor.py` Zeile 828: `ActionDocument` → `model_dump()` → Dict mit `documentName`, `documentData`, `mimeType` - `actionNodeExecutor.py` Zeile 836-837: Output enthält `documents` + `documentList` (identisch) - `_getDocumentsFromUpstream()` (Zeile 237) liest `documents` oder `documentList` aus dem Output-Dict - Zeile 569: `resolvedParams.setdefault("documentList", docs)` mergt die Dicts in den nächsten Node - **Problem war:** `processDocuments` und `syncToAccounting` nutzten `DocumentReferenceList.from_string_list()` + `chat.getChatDocumentsFromDocumentList()` — funktioniert nur im Chat-Kontext, nicht im Graph-Editor - **Lösung:** Beide Actions erkennen jetzt direkt übergebene Dicts (Graph-Editor-Pfad) und nutzen Chat nur als Fallback — **manuell testen** ### Phase 3: Performance (Prio: hoch — spürbar in jeder Demo) - [x] **DB-Connection-Pooling** für Feature-Data-Agent - Singleton `DatabaseConnector` pro Feature-DB (z.B. `poweron_trustee`) statt Connection-per-Call - Pool in `_featureSubAgentTools.py` oder zentral im ServiceCenter - Connection-Reuse über `featureDbConnPool[featureDbName]` - [x] **Sub-Agent Result-Caching** - Cache-Key: `(featureInstanceId, question_hash, lastSyncAt)` - Invalidierung bei neuem Sync (`lastSyncAt` ändert sich) - TTL: 5 Minuten (konfigurierbar) - Speicherort: In-Memory Dict im Agent-Kontext (pro Workflow-Session) ### Phase 4: Graphical-Editor Workflow für Demo (Prio: hoch — nötig für UC1 Teil A) - [ ] **Workflow im Graphical Editor bauen:** SharePoint Read Files Loop → Trustee Import+Sync - Trigger: `trigger.manual` (mit Hinweis "könnte automatisch laufen") - Node 1: `sharepoint.listFiles` → Ordner mit Belegen - Node 2: `flow.loop` über die Dateiliste - Node 3 (im Loop): `sharepoint.downloadFile` → PDF herunterladen - Node 4 (im Loop): `trustee.extractFromFiles` → Belege extrahieren - Node 5 (im Loop): `trustee.processDocuments` → Buchungen erstellen - Node 6 (nach Loop): `trustee.syncToAccounting` → Sync mit Abacus - Alternativ: `trustee.importAndProcess` Convenience-Node (Phase 2) statt Nodes 4-6 - Testen mit 3-4 Musterbelegen - Workflow als System-Template speichern (`templateScope: system`) - [ ] **Musterbelege erstellen:** Handwerkerrechnung, Nebenkostenabrechnung, Bankbeleg, Versicherungsbeleg (PDFs) ### Phase 5: Demo-Daten & Testläufe (Prio: mittel) - [ ] Budget-Excel erstellen (Soll-Werte 2026 pro Kostenstelle/Liegenschaft) - [ ] Demo-Prompt für Budgetkontrolle vorbereiten und testen - [ ] CommCoach-Personas für Immobilien-Kontext erstellen - [ ] Neutralisierungs-Demo mit fiktivem Mieterdossier testen - [ ] Demo-Mandant "PWG Demo" sauber aufsetzen - [ ] Alle 3 Use Cases end-to-end durchspielen ## Akzeptanzkriterien | # | Kriterium (Given-When-Then) | Prio | |---|---------------------------|------| | 1 | Given Trustee-Instanz mit Abacus-Config, When Agent `refreshTrusteeData` aufruft, Then werden Daten aus Abacus in `TrusteeData*`-Tabellen importiert und Summary zurückgegeben | must | | 2 | Given gecachte Daten (lastSyncAt < 1h), When Agent `refreshTrusteeData` ohne `forceRefresh` aufruft, Then wird kein externer Sync ausgelöst und gecachte Counts zurückgegeben | must | | 3 | Given Trustee-Daten in DB, When Sub-Agent `aggregateTable` mit SUM/GROUP BY aufruft, Then kommen korrekte Aggregationen zurück (verifiziert gegen manuelle Berechnung) | must | | 4 | Given identische Query innerhalb 5 Min, When `queryFeatureInstance` erneut aufgerufen wird, Then wird gecachtes Ergebnis zurückgegeben (kein neuer Sub-Agent-Loop) | should | | 5 | Given Graphical Editor geöffnet, When Node-Palette geladen wird, Then erscheint Kategorie "Treuhand" mit allen Trustee-Nodes (inkl. neuem `refreshAccountingData`) | must | | 6 | Given Workflow im Graphical Editor mit trigger.manual → sharepoint.listFiles → flow.loop → trustee.extractFromFiles → processDocuments → syncToAccounting, When Workflow manuell gestartet wird, Then werden PDFs aus SharePoint geladen, extrahiert und als Positionen mit Sync-Status im Trustee angezeigt | must | | 7 | Given Trustee-Pipeline im Flow (extract → process → sync), When Node A Output an Node B weitergereicht wird, Then wird `documentList`-Referenz korrekt aufgelöst (Output-Chaining funktioniert) | must | | 8 | Given Budget-Excel im Workspace + Trustee-Daten, When Budgetkontrolle-Prompt ausgeführt wird, Then erstellt Agent Soll/Ist-Vergleich mit Charts und sendet per Mail | must | ## Testplan | ID | AC | Art | Automatisiert | Repo-Pfad | Status | |----|----|-----|--------------|-----------|--------| | T1 | 1 | api | nein (manuell mit Abacus-Sandbox) | — | pending | | T2 | 2 | api | ja | gateway/tests/features/trustee/test_refresh_tool.py | pending | | T3 | 3 | api | ja | gateway/tests/features/trustee/test_aggregate_table.py | pending | | T4 | 4 | api | ja | gateway/tests/serviceAgent/test_feature_data_cache.py | pending | | T5 | 5 | ui | nein (manuell) | — | pending | | T6 | 6 | e2e | nein (manuell) | — | pending | | T7 | 7 | api | ja | gateway/tests/workflows/graphicalEditor/test_node_chaining.py | pending | | T8 | 8 | e2e | nein (manuell) | — | pending | ## Links - Use Cases: `pamocreate/projects/poweron/customer-pwg/20260407 use-cases-workshop.md` - Automation Unification (done): `wiki/c-work/3-validate/2026-04-automation-unification.md` - Trustee Accounting Bridge: `gateway/modules/features/trustee/accounting/accountingBridge.py` - Accounting Data Sync: `gateway/modules/features/trustee/accounting/accountingDataSync.py` - Feature Data Agent: `gateway/modules/serviceCenter/services/serviceAgent/featureDataAgent.py` - Feature Data Provider: `gateway/modules/serviceCenter/services/serviceAgent/featureDataProvider.py` - Feature Sub-Agent Tool: `gateway/modules/serviceCenter/services/serviceAgent/coreTools/_featureSubAgentTools.py` - Toolbox Registry: `gateway/modules/serviceCenter/services/serviceAgent/toolboxRegistry.py` - Abacus Connector: `gateway/modules/features/trustee/accounting/connectors/accountingConnectorAbacus.py` - Node Registry: `gateway/modules/features/graphicalEditor/nodeRegistry.py` - Trustee Nodes: `gateway/modules/features/graphicalEditor/nodeDefinitions/trustee.py` - SharePoint Nodes: `gateway/modules/features/graphicalEditor/nodeDefinitions/sharepoint.py` - Flow Nodes: `gateway/modules/features/graphicalEditor/nodeDefinitions/flow.py` - Action Node Executor: `gateway/modules/workflows/automation2/executors/actionNodeExecutor.py` - Execution Engine: `gateway/modules/workflows/automation2/executionEngine.py` - Scheduler: `gateway/modules/workflows/scheduler/mainScheduler.py` - Trustee Workflow Method: `gateway/modules/workflows/methods/methodTrustee/methodTrustee.py` - Graphical Editor Feature: `gateway/modules/features/graphicalEditor/mainGraphicalEditor.py` - Graphical Editor Datenmodell: `gateway/modules/features/graphicalEditor/datamodelFeatureGraphicalEditor.py` ## Abschluss - [x] b-reference/gateway/workflow.md aktualisiert (neue Action `trustee.refreshAccountingData`) - [x] b-reference/gateway/ai-agent.md aktualisiert (`aggregateTable` Tool im Sub-Agent, Trustee-Toolbox) - [x] b-reference/gateway/automation.md aktualisiert (neue Trustee-Nodes + Kategorie in Node-Palette) - [ ] TOPICS.md aktualisiert (falls neues Thema) - [ ] Dieses Dokument → z-archive/ verschoben