From 5008f3329c112042430af3d9c6f1d218e2e2fccf Mon Sep 17 00:00:00 2001 From: Mikei386 <44135113+Mikei386@users.noreply.github.com> Date: Mon, 24 Aug 2026 11:28:49 +0200 Subject: [PATCH] fix: automate verified Unraid update workflows --- dev/test_openwebui_filters.py | 18 ++++ docs/COMPONENTS.md | 2 +- docs/CURRENT_REFERENCE.md | 17 ++-- docs/DISASTER_RECOVERY.md | 6 +- docs/OPERATIONS.md | 8 +- docs/QWEN_OPERATOR_CONTEXT.md | 13 ++- docs/UNRAID_AUTOMATIC_UPDATE_WORKFLOW.md | 89 +++++++++++++++++++ .../openwebui/filters/auto_tool_selector.py | 59 ++++++++++-- platform/openwebui/install-filters.sh | 11 ++- 9 files changed, 199 insertions(+), 24 deletions(-) create mode 100644 docs/UNRAID_AUTOMATIC_UPDATE_WORKFLOW.md diff --git a/dev/test_openwebui_filters.py b/dev/test_openwebui_filters.py index e1d8e37..ee599eb 100644 --- a/dev/test_openwebui_filters.py +++ b/dev/test_openwebui_filters.py @@ -232,6 +232,24 @@ class AutoToolSelectorTests(unittest.IsolatedAsyncioTestCase): ) self.assertNotIn("server:mcp:mua", result["tool_ids"]) + async def test_explicit_unraid_update_gets_read_and_management_tools(self): + result = await self._select( + "Prüfe auf Unraid alle Docker-Updates, führe die Updates durch und kontrolliere danach den Zustand." + ) + self.assertEqual( + result["tool_ids"], + ["server:mcp:mua-readonly-local", "server:mcp:mua"], + ) + self.assertIn("single batched update workflow", result["messages"][0]["content"]) + + async def test_unraid_update_question_stays_readonly(self): + result = await self._select( + "Gibt es auf Unraid Updates für Docker-Container? Bitte nur prüfen." + ) + self.assertEqual( + result["tool_ids"], ["server:mcp:mua-readonly-local"] + ) + async def test_voice_transcription_variants_select_unraid(self): result = await self._select( "Welche Dacher Contäner laufen aktuell auf dem Anrate Server?" diff --git a/docs/COMPONENTS.md b/docs/COMPONENTS.md index cfc3d67..23aaaf9 100644 --- a/docs/COMPONENTS.md +++ b/docs/COMPONENTS.md @@ -15,7 +15,7 @@ | Platform Context MCP | Athena-/MikeAI-Wissen, begrenzter Laufzeitsnapshot und kontrollierte Dokumentationspflege | eigener Container ohne Docker-Socket, Shell, Egress oder Secrets | Kern | | Athena Operator MCP | Entwicklung und vollständiger Betrieb der KI-Plattform mit gebundenen Freigaben | unprivilegierte MCP-Fassade plus rootseitiger strukturierter Executor; keine freie Shell | Kern | | Operator-Kontext | `docs/QWEN_OPERATOR_CONTEXT.md` plus `config/operator-system-prompt.txt` | versionierte Selbstbeschreibung und Sicherheitsregeln für Qwen | Kern | -| Unraid/MUA | MUA-Plugin auf dem HomeServer, direkter MCP-Endpunkt | read-only Automatik plus bewusst aktivierte Verwaltung in Open WebUI | Kern | +| Unraid/MUA | MUA r019+ auf dem HomeServer, direkter MCP-Endpunkt | read-only Automatik; Verwaltung bei explizitem Änderungsauftrag; idempotente Batch-Updates | Kern | | Whisper | ggml-org/whisper.cpp | Service im Router-Deploy | optional | | XTTS-v2 | Coqui, offizielles CUDA-12.1-Image per Digest | RTX-3060-Container, Stimme `Annmarie Nele`, CPML | Kern | | TTS-Gateway | `platform/docker/tts-gateway/` | interne Queue, stabile deutsche Satzblöcke, automatische Erkennung rein englischer Texte und Piper-Fallback | Kern | diff --git a/docs/CURRENT_REFERENCE.md b/docs/CURRENT_REFERENCE.md index 5a5baaa..2e00897 100644 --- a/docs/CURRENT_REFERENCE.md +++ b/docs/CURRENT_REFERENCE.md @@ -180,14 +180,17 @@ Mehrdomänen-Aufgabe erhält automatisch ein begrenztes mittleres Reasoning- Budget; einfache Aufgaben bleiben schnell. Allgemeine Webrecherche erfolgt über Open WebUIs native `search_web`/`fetch_url`-Werkzeuge; `web-local` ist nur noch manuell für Spezialfälle verfügbar. Dadurch bleiben -Fachkataloge klein und kurze Profile verlieren keinen unnötigen Kontext. MUA -mit erweiterten Verwaltungsrechten bleibt von der Automatik ausgeschlossen; -eine automatisch bereitgestellte Verbindung erteilt niemals Schreibrechte -oder eine Änderungsfreigabe. +Fachkataloge klein und kurze Profile verlieren keinen unnötigen Kontext. Reine +Unraid-Abfragen erhalten nur MUA read-only. Verlangt die aktuelle Nachricht +ausdrücklich eine Unraid-Änderung, stellt die Automatik zusätzlich den +Verwaltungszugang für die feste Kette Prüfen → Ändern → Verifizieren bereit. +Die Bereitstellung ersetzt niemals die ausdrückliche Änderungsanweisung. -Unraid ist ausschließlich über das MUA-Plugin angebunden. Die automatische -Verbindung `mua-readonly-local` und die bewusst aktivierte Verbindung `mua` -nutzen denselben MUA-Endpunkt. Der frühere GraphQL-basierte Unraid-MCP wurde +Unraid ist ausschließlich über das MUA-Plugin angebunden. Die Verbindungen +`mua-readonly-local` und `mua` nutzen denselben MUA-Endpunkt. Mehrere bestätigte +Docker-Updates laufen ab MUA r019 gebündelt und idempotent; echte Image-IDs +verhindern Neuerstellungen aufgrund eines veralteten Statuscaches. Der frühere +GraphQL-basierte Unraid-MCP wurde entfernt und gehört weder zum Start noch zum Recovery. Der GitHub-Container läuft produktiv. Token-Datei, interner diff --git a/docs/DISASTER_RECOVERY.md b/docs/DISASTER_RECOVERY.md index 37409f7..8a6c8dc 100644 --- a/docs/DISASTER_RECOVERY.md +++ b/docs/DISASTER_RECOVERY.md @@ -58,7 +58,11 @@ laufen, sondern alle fachlichen Funktionen geprüft wurden. - [ ] native OpenWebUI-Websuche funktioniert ohne `web-local`; Auto Tool Selector wählt GitHub, Home Assistant, ARR, Navidrome, Unraid read-only, Athena-Plattformwissen und den Athena Operator korrekt -- [ ] normale Unterhaltung erhält kein MCP; MUA wird niemals automatisch gewählt +- [ ] normale Unterhaltung erhält kein MCP; reine Unraid-Abfragen erhalten nur + MUA read-only; ausdrücklich verlangte Unraid-Änderungen erhalten automatisch + MUA read-only plus Verwaltung +- [ ] MUA r019 oder neuer meldet `unraid_docker_update_verified_batch`; ein + Wiederholungstest mit aktuellem Image endet ohne Container-Neuerstellung - [ ] eine synthetische CSV wird lokal ausgewertet; kein Webwerkzeug erhält Dateidaten - [ ] ein rekursiver GitHub-Komplettbaum ist nicht als Werkzeug verfügbar - [ ] der zweite identische Werkzeugaufruf wird gestoppt und eine Abschlussantwort erzeugt diff --git a/docs/OPERATIONS.md b/docs/OPERATIONS.md index be418af..635c051 100644 --- a/docs/OPERATIONS.md +++ b/docs/OPERATIONS.md @@ -13,9 +13,11 @@ Reihenfolge ist absichtlich festgelegt: jüngste Nutzernachricht und stellt pro Anfrage höchstens drei passende MCPs bereit. Er erkennt GitHub, Home Assistant, Sonarr/Radarr, Navidrome, Unraid-Diagnose und Athena-Plattformwissen. Manuell gewählte Werkzeuge - bleiben erhalten. MUA mit erweiterten Verwaltungsrechten wird nie - automatisch zugeschaltet. Die Auswahl eines MCP ist ausdrücklich keine - Freigabe für eine Zustandsänderung. + bleiben erhalten. Bei einer ausdrücklich verlangten Unraid-Änderung werden + MUA-Diagnose und -Verwaltung gemeinsam bereitgestellt; reine Statusfragen + bleiben read-only. Docker-Updates verwenden MUA r019 gebündelt, vergleichen + echte Image-IDs und erhalten den Laufzustand. Die Auswahl eines MCP ist + ausdrücklich keine Freigabe für eine andere Zustandsänderung. 4. `MikeAI Stability Guard`, Priorität 30: begrenzt einzelne und gesamte Werkzeugresultate, verdichtet bei Bedarf zuerst alte Tool-Ausgaben und Dialogteile und stoppt identische beziehungsweise ausufernde Tool-Schleifen. diff --git a/docs/QWEN_OPERATOR_CONTEXT.md b/docs/QWEN_OPERATOR_CONTEXT.md index 70f0ad1..3ab6877 100644 --- a/docs/QWEN_OPERATOR_CONTEXT.md +++ b/docs/QWEN_OPERATOR_CONTEXT.md @@ -242,16 +242,23 @@ WireGuard-Adresse sind alle Fach-MCPs direkt erreichbar. | ARR | Sonarr/Radarr, Indexersuche, kontrollierte Grabs | Lesen; Schreiben nur Preview/Approval | | Navidrome | Bibliothek, Empfehlungen, Playlists/Favoriten | eigener Benutzer; gezielt aktivieren | | MUA read-only | Host-, Docker-, Array-, Netzwerk- und Logdiagnose | automatischer Standard | -| MUA/Admin | eng definierte Unraid-Verwaltung | bewusst aktivieren | +| MUA/Admin | eng definierte Unraid-Verwaltung | bei ausdrücklich verlangter Änderung automatisch zusätzlich bereitgestellt | Für automatische Unraid-Diagnose existiert in Open WebUI zusätzlich `mua-readonly-local`. Diese Verbindung nutzt denselben lokalen MUA-Endpunkt, blendet aber Start/Stop, Installation, Änderungen und die freie Root-Shell -serverseitig in Open WebUI aus. Die vollständige Verbindung `mua` wird niemals -automatisch bereitgestellt. +serverseitig in Open WebUI aus. Die vollständige Verbindung `mua` wird nur bei +einer in der aktuellen Nachricht ausdrücklich verlangten Unraid-Änderung +zusätzlich bereitgestellt. Es gibt keinen zweiten GraphQL-basierten Unraid-MCP. Schlägt MUA fehl, darf nicht auf GraphQL ausgewichen oder dessen API eigenmächtig aktiviert werden. +Für mehrere Docker-Image-Updates ist +`unraid_docker_update_verified_batch` verbindlich. Es ersetzt wiederholte +Einzelaufrufe, vergleicht echte Image-IDs, erhält laufend/gestoppt und +verifiziert das Ergebnis im selben Aufruf. Details stehen in +`docs/UNRAID_AUTOMATIC_UPDATE_WORKFLOW.md`. + Der vorhandene Deemix-Dienst läuft auf Unraid und ist als externe Abhängigkeit im Diensteverzeichnis eingetragen. Für ein Deemix-MCP wird standardmäßig nur ein Relay auf Athena gebaut; ein zweites Deemix-Backend erfordert einen diff --git a/docs/UNRAID_AUTOMATIC_UPDATE_WORKFLOW.md b/docs/UNRAID_AUTOMATIC_UPDATE_WORKFLOW.md new file mode 100644 index 0000000..df78097 --- /dev/null +++ b/docs/UNRAID_AUTOMATIC_UPDATE_WORKFLOW.md @@ -0,0 +1,89 @@ +# Automatischer Unraid-Docker-Updateablauf + +Stand: 24. August 2026 + +## Ziel + +Ein ausdrücklich formulierter Auftrag wie „prüfe die Docker-Updates auf Unraid, +führe bestätigte Updates aus und kontrolliere das Ergebnis“ muss in Open WebUI +ohne manuelles Aktivieren von Werkzeugen vollständig ablaufen. + +## Automatische Werkzeugwahl + +Der `MikeAI Auto Tool Selector` unterscheidet zwischen Lesen und Ändern: + +- reine Status- oder Updatefragen erhalten nur `mua-readonly-local`; +- eine in der aktuellen Nachricht ausdrücklich verlangte Unraid-Änderung erhält + `mua-readonly-local` und `mua` gemeinsam; +- Formulierungen wie „nur prüfen“ oder „keine Änderungen“ unterdrücken den + Verwaltungszugang; +- die bereitgestellten Verbindungen sind keine allgemeine Freigabe. Der Auftrag + muss die konkrete Änderung selbst enthalten. + +Der vorgesehene Ablauf lautet immer: + +1. Zustand und Kandidaten read-only erfassen. +2. Die engste gebündelte Änderung ausführen. +3. Das Ergebnis read-only oder durch die gebündelte technische Verifikation + kontrollieren. + +## Verbindliches Batch-Werkzeug + +MUA r019 stellt `unraid_docker_update_verified_batch` bereit. Das Werkzeug +akzeptiert 1 bis 25 exakte, mit `|` getrennte Containernamen. + +Für jeden Container liest es zunächst Container-ID, Image-ID und Laufzustand. +Danach zieht es das im Unraid-Benutzertemplate konfigurierte Image und +vergleicht die unveränderliche lokale Image-ID. Bereits aktuelle Container +werden vollständig übersprungen – auch wenn Unraids Statuscache noch ein Update +meldet. Nur bei tatsächlich geänderter Image-ID wird neu erstellt. Laufend +bleibt laufend, gestoppt bleibt gestoppt. + +Die kompakte Nachkontrolle enthält Container- und Image-ID-Änderung, +Endzustand, RestartCount und Healthcheck-Status. Templates, Ports, Volumes und +Netzwerke werden nicht verändert. Eine vorhandene Freigabe des bisherigen +Einzelwerkzeugs `unraid_docker_update` aktiviert nach dem Upgrade automatisch +auch die sicherere Batch-Variante. + +## Idempotenz + +Der Cache `/var/lib/docker/unraid-update-status.json` ist nur ein +Kandidatenhinweis. Er darf nie allein eine Neuerstellung auslösen. Autoritativ +ist der Image-ID-Vergleich nach dem Pull. + +Ein wiederholter Lauf muss bei einem aktuellen Image folgendes melden: + +```text +result: already-current +recreated: false +container_id_changed: false +image_id_changed: false +``` + +## Produktiver Regressionstest vom 24. August 2026 + +Ein neuer Open-WebUI-Chat erhielt ohne manuelle Werkzeugauswahl den Auftrag, +Unraid-Docker-Updates zu prüfen, bestätigt auszuführen und nachzukontrollieren. + +- automatisch bereitgestellt: MUA read-only plus MUA-Verwaltung; +- zwei read-only-Aufrufe für Update-Status und Containerbestand; +- genau ein gebündelter Aufruf für fünf Kandidaten; +- alle fünf als `already-current` erkannt; +- null Neuerstellungen und null Container-/Image-ID-Änderungen; +- AirConnect blieb laufend; Virtual-DSM, AzuraCast, WindowsXP und Windows11 + blieben gestoppt; +- `all_verified: true`. + +Der vorherige Ablauf benötigte mehrere Benutzernachrichten und vier bis fünf +einzelne Update-Aufrufe. Dieser Pfad ist ersetzt. + +## Recovery-Prüfung + +1. MUA-Health muss r019 oder neuer melden. +2. Open WebUI muss den Auto Tool Selector 3.3.0 oder neuer enthalten. +3. „Gibt es Docker-Updates auf Unraid? Nur prüfen“ darf nur MUA read-only + bereitstellen. +4. Ein ausdrücklich schreibender synthetischer Auftrag muss beide MUA-Zugänge + bereitstellen und das Batch-Werkzeug wählen. +5. Ein Wiederholungstest mit aktuellem Image darf keine Neuerstellung auslösen. + diff --git a/platform/openwebui/filters/auto_tool_selector.py b/platform/openwebui/filters/auto_tool_selector.py index 396b9f6..f183946 100644 --- a/platform/openwebui/filters/auto_tool_selector.py +++ b/platform/openwebui/filters/auto_tool_selector.py @@ -1,7 +1,7 @@ """ title: MikeAI Auto Tool Selector author: MikeAI -version: 3.2.0 +version: 3.3.0 description: Selects a small, relevant set of MCP servers for each user request. """ @@ -27,6 +27,7 @@ class Filter: "homeassistant": "server:mcp:homeassistant-local", "arr": "server:mcp:arr-local", "unraid": "server:mcp:mua-readonly-local", + "unraid_admin": "server:mcp:mua", "navidrome": "server:mcp:navidrome-local", "platform": "server:mcp:athena-platform", "operator": "server:mcp:athena-operator-local", @@ -37,6 +38,7 @@ class Filter: "homeassistant": "Home Assistant", "arr": "Sonarr/Radarr", "unraid": "Unraid-Diagnose (MUA read-only)", + "unraid_admin": "Unraid-Verwaltung (MUA)", "navidrome": "Navidrome", "platform": "Athena-Plattformwissen", "operator": "Athena Operator", @@ -73,7 +75,7 @@ class Filter: return "" @staticmethod - def _add_system_rule(body: dict, labels: list[str]) -> None: + def _add_system_rule(body: dict, labels: list[str], selected: list[str]) -> None: rule = ( "MikeAI automatic tool selection made these capabilities available for " f"this request: {', '.join(labels)}. Availability is not authorization. " @@ -86,6 +88,17 @@ class Filter: "does not exist. Never compensate by planning or installing a duplicate backend; " "stop and request clarification." ) + if "unraid" in selected and "unraid_admin" in selected: + rule += ( + " This request explicitly asks for an Unraid state change. Use the " + "read-only MUA tools to establish evidence, then the narrowest MUA " + "management tool for the requested change, and finally read-only " + "verification. For multiple verified Docker image updates, prefer " + "the single batched update workflow; it preserves each container's " + "original running/stopped state and skips images already current. " + "Do not ask the user to enable another tool: both required MUA " + "capabilities are already attached to this request." + ) messages = body.setdefault("messages", []) for message in messages: if message.get("role") == "system" and isinstance(message.get("content"), str): @@ -161,6 +174,27 @@ class Filter: r"(?:unraid|unreid|unrate|anrate|homeserver|nas)\b", ), ) + unraid_write = unraid and self._matches( + text, + ( + r"\b(?:update|updates|aktualisier\w*|upgrade\w*)\b.*\b(?:docker|cont[aä]iner|image|unraid)\b", + r"\b(?:docker|cont[aä]iner|image|unraid)\b.*\b(?:update|updates|aktualisier\w*|upgrade\w*)\b", + r"\b(?:start|stop|restart|starte|stoppe|beende|rebuild|reinitialisier|neu\s+erstell)\w*\b.*\bcont[aä]iner\b", + r"\bcont[aä]iner\b.*\b(?:start|stop|restart|starte|stoppe|beende|rebuild|reinitialisier|neu\s+erstell)\w*\b", + r"\b(?:installier|entfern|l[oö]sch|[aä]nder|modifizier)\w*\b.*\b(?:unraid|docker|cont[aä]iner)\b", + r"\b(?:unraid|docker|cont[aä]iner)\b.*\b(?:installier|entfern|l[oö]sch|[aä]nder|modifizier)\w*\b", + r"\bf[uü]hr\w*\b.*\bupdates?\b.*\b(?:durch|aus)\b", + ), + ) + if unraid_write and self._matches( + text, + ( + r"\b(?:nur|lediglich|ausschlie(?:ß|ss)lich)\b.{0,30}\b(?:pr[uü]f|anzeig|auflist|status|nachseh)\w*\b", + r"\b(?:keine|nichts?)\b.{0,30}\b(?:[aä]nder|update|aktualisier|durchf[uü]hr|installier)\w*\b", + r"\b(?:nicht|nichts?)\b.{0,20}\b(?:durchf[uü]hr|ausf[uü]hr|aktualisier|installier)\w*\b", + ), + ): + unraid_write = False github = self._matches( text, ( @@ -174,12 +208,27 @@ class Filter: # trust domains (for example GitHub source + Unraid runtime + Home # Assistant configuration). Attach each relevant specialist once; # the evidence-plan rule keeps the model breadth-first and bounded. - if operator: - selected.append("operator") if github: selected.append("github") + # If a referenced backend already runs on Unraid, inventory that + # existing service before proposing Athena deployment. This keeps a + # generic "build an MCP" phrase from creating a duplicate backend. + if operator and not ( + unraid + and self._matches( + text, + ( + r"\bl[aä]uft\b.{0,60}\b(?:auf|in)\b.{0,30}\bunraid\b", + r"\b(?:auf|in)\b.{0,30}\bunraid\b.{0,60}\bl[aä]uft\b", + r"\bbereits\b.{0,80}\b(?:cont[aä]iner|dienst|backend)\b", + ), + ) + ): + selected.append("operator") if unraid: selected.append("unraid") + if unraid_write: + selected.append("unraid_admin") if homeassistant: selected.append("homeassistant") if arr: @@ -244,6 +293,6 @@ class Filter: body["reasoning_budget"] = self.valves.multidomain_reasoning_budget labels = [self.LABELS[category] for category in selected] - self._add_system_rule(body, labels) + self._add_system_rule(body, labels, selected) await self._notify(__event_emitter__, labels) return body diff --git a/platform/openwebui/install-filters.sh b/platform/openwebui/install-filters.sh index 81c4aa1..8e7f1d9 100755 --- a/platform/openwebui/install-filters.sh +++ b/platform/openwebui/install-filters.sh @@ -217,13 +217,16 @@ with con: "Automatisch verwendbarer, serverseitig in Open WebUI auf reine Lese- und " "Diagnosewerkzeuge begrenzter MUA-Zugang. Für Containerbestand, Logs, System, " "Storage, Shares und Netzwerkstatus. Keine Start/Stop-, Installations-, " - "Änderungs- oder freie Shell-Funktion. Für bewusste Verwaltung MUA separat wählen.", + "Änderungs- oder freie Shell-Funktion. Bei einer ausdrücklich verlangten " + "Änderung stellt die automatische Auswahl zusätzlich MUA-Verwaltung bereit.", ), "mua": ( "MUA (Unraid-Verwaltung)", - "Nur für ausdrücklich benötigte MUA-spezifische oder freigegebene Unraid-" - "Verwaltungsaktionen. Für reine Statusabfragen und Diagnosen die read-only-" - "MUA-Verbindung verwenden; niemals beide parallel ausprobieren.", + "Nur für vom Benutzer in der aktuellen Nachricht ausdrücklich verlangte " + "Unraid-Verwaltungsaktionen. Gemeinsam mit MUA read-only als geordnete " + "Kette verwenden: Zustand prüfen, engste Änderung ausführen, Ergebnis " + "read-only verifizieren. Für mehrere bestätigte Image-Updates immer den " + "gebündelten, zustandserhaltenden Updateablauf verwenden.", ), "navidrome-local": ( "Navidrome (Musikbibliothek)",