From 5834342f8c3d62dd29663392dd3daf7993f0c69c Mon Sep 17 00:00:00 2001 From: Mikei386 <44135113+Mikei386@users.noreply.github.com> Date: Mon, 24 Aug 2026 12:02:03 +0200 Subject: [PATCH] fix: automate cross-source media library audits --- dev/test_openwebui_filters.py | 10 ++++ docs/COMPONENTS.md | 2 +- docs/CURRENT_REFERENCE.md | 8 ++- docs/DISASTER_RECOVERY.md | 3 + docs/OPERATIONS.md | 3 + docs/QWEN_OPERATOR_CONTEXT.md | 2 +- docs/UNRAID_MEDIA_AUDIT_WORKFLOW.md | 57 +++++++++++++++++++ .../openwebui/filters/auto_tool_selector.py | 19 ++++++- platform/openwebui/install-filters.sh | 5 +- 9 files changed, 101 insertions(+), 8 deletions(-) create mode 100644 docs/UNRAID_MEDIA_AUDIT_WORKFLOW.md diff --git a/dev/test_openwebui_filters.py b/dev/test_openwebui_filters.py index ee599eb..b65fe60 100644 --- a/dev/test_openwebui_filters.py +++ b/dev/test_openwebui_filters.py @@ -250,6 +250,16 @@ class AutoToolSelectorTests(unittest.IsolatedAsyncioTestCase): result["tool_ids"], ["server:mcp:mua-readonly-local"] ) + async def test_readonly_unraid_media_audit_does_not_attach_admin_or_arr(self): + result = await self._select( + "Prüfe auf Unraid, welche Folgen meiner Hörspielserie Die drei Fragezeichen fehlen. " + "Nur lesen, ohne Downloads, Umbenennungen oder sonstige Änderungen." + ) + self.assertEqual( + result["tool_ids"], ["server:mcp:mua-readonly-local"] + ) + self.assertIn("unraid_files_inventory", result["messages"][0]["content"]) + 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 23aaaf9..42ca259 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 r019+ auf dem HomeServer, direkter MCP-Endpunkt | read-only Automatik; Verwaltung bei explizitem Änderungsauftrag; idempotente Batch-Updates | Kern | +| Unraid/MUA | MUA r020+ auf dem HomeServer, direkter MCP-Endpunkt | read-only Automatik; begrenzte Datei-/Medieninventare; 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 2e00897..262e803 100644 --- a/docs/CURRENT_REFERENCE.md +++ b/docs/CURRENT_REFERENCE.md @@ -189,8 +189,12 @@ Die Bereitstellung ersetzt niemals die ausdrückliche Änderungsanweisung. 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 +verhindern Neuerstellungen aufgrund eines veralteten Statuscaches. +Ab MUA r020 inventarisiert `unraid_files_inventory` Datei- und Ordnernamen +begrenzt, ohne Dateiinhalte zu lesen. Auto Tool Selector 3.4 hält ausdrücklich +lesende Bibliotheksprüfungen bei MUA read-only und verwechselt Hörspielfolgen +nicht mit Sonarr-Episoden. Der Ablauf steht in +`docs/UNRAID_MEDIA_AUDIT_WORKFLOW.md`. 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 8a6c8dc..d86bee9 100644 --- a/docs/DISASTER_RECOVERY.md +++ b/docs/DISASTER_RECOVERY.md @@ -63,6 +63,9 @@ laufen, sondern alle fachlichen Funktionen geprüft wurden. MUA read-only plus Verwaltung - [ ] MUA r019 oder neuer meldet `unraid_docker_update_verified_batch`; ein Wiederholungstest mit aktuellem Image endet ohne Container-Neuerstellung +- [ ] MUA r020 oder neuer meldet `unraid_files_inventory`; ein lesender + Medienauftrag aktiviert nur MUA read-only und kann einen Sammlungsordner + plus dessen Dateinamen in zwei begrenzten Aufrufen erfassen - [ ] 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 635c051..7d262f0 100644 --- a/docs/OPERATIONS.md +++ b/docs/OPERATIONS.md @@ -18,6 +18,9 @@ Reihenfolge ist absichtlich festgelegt: 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. + Medienbestandsprüfungen verwenden ab MUA r020 zuerst eine gezielte + Verzeichnissuche und danach ein Inventar des exakten relativen Pfads mit + `unraid_files_inventory`; wiederholte `ls`/`find`-Aufrufe sind nur Fallback. 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 3ab6877..2779e58 100644 --- a/docs/QWEN_OPERATOR_CONTEXT.md +++ b/docs/QWEN_OPERATOR_CONTEXT.md @@ -241,7 +241,7 @@ WireGuard-Adresse sind alle Fach-MCPs direkt erreichbar. | Home Assistant | Zustände, Historie, Diagnose, begrenzte YAML-Abläufe | Lesen; Schreiben nur Preview/Approval | | 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 read-only | Host-, Docker-, Array-, Netzwerk-, Log- und begrenzte Datei-/Medieninventare | automatischer Standard | | 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 diff --git a/docs/UNRAID_MEDIA_AUDIT_WORKFLOW.md b/docs/UNRAID_MEDIA_AUDIT_WORKFLOW.md new file mode 100644 index 0000000..9b2ce78 --- /dev/null +++ b/docs/UNRAID_MEDIA_AUDIT_WORKFLOW.md @@ -0,0 +1,57 @@ +# Automatische Medienbestandsprüfung auf Unraid + +Stand: 24. August 2026 + +## Zweck + +Lokale Medienbestände können in einem Open-WebUI-Auftrag mit einer offiziellen +Online-Liste verglichen werden, ohne dass der Benutzer Werkzeuge nachträglich +einschaltet. Der Ablauf bleibt vollständig read-only. + +## Werkzeugwahl + +Der Auto Tool Selector 3.4 erkennt einen ausdrücklich lesenden Unraid-Auftrag +und stellt ausschließlich `mua-readonly-local` bereit. Wörter wie „Folgen +fehlen“ oder „Hörspielserie“ aktivieren nicht mehr fälschlich Sonarr/Radarr. +Formulierungen wie „ohne Änderungen“, „ohne Downloads“ und „keinerlei +Änderungen“ verhindern zuverlässig die Auswahl von MUA-Admin. + +Die öffentliche Recherche erfolgt anschließend mit Open WebUIs nativen +Werkzeugen `search_web` und `fetch_url`. + +## Dateiinventar + +MUA r020 stellt `unraid_files_inventory` bereit. Das Werkzeug liest keine +Dateiinhalte und akzeptiert ausschließlich einen vorhandenen Unraid-Share plus +einen relativen Pfad unterhalb dieses Shares. Pfadtraversal, absolute Pfade und +Symlink-Verfolgung sind gesperrt. Tiefe, Trefferzahl und Zahl der untersuchten +Einträge sind begrenzt. + +Empfohlener Ablauf: + +1. `unraid_shares_list` nur dann verwenden, wenn der Share unbekannt ist. +2. Mit `unraid_files_inventory`, `name_contains` und nur Verzeichnissen die + passende Sammlung lokalisieren. +3. Den exakten zurückgegebenen `relative_path` in einem zweiten Aufruf ohne + Namensfilter inventarisieren. +4. Aus Dateinamen lokale Nummern/Titel extrahieren. +5. Offizielle Liste über native Websuche ermitteln und Differenz bilden. +6. Fehlende Titel beim gewünschten Anbieter gezielt verifizieren. +7. Fakten, Dateinamen-Schlussfolgerungen und Unsicherheiten getrennt ausgeben. + +Die generische Nur-Lese-Shell ist nur ein Fallback, wenn das Inventarwerkzeug +die konkrete Frage nicht beantworten kann. Wiederholte `ls`/`find`-Ketten sind +für Bibliotheksprüfungen nicht vorgesehen. + +## Regressionstest + +Der ursprüngliche Lauf zur Reihe „Die drei ???“ brauchte nach dem Share-Fund +vier einzelne Shell-Aufrufe und verbrauchte das Werkzeugbudget vor dem +eigentlichen Datei- und Webabgleich. Dieser Fall ist der verbindliche +Regressionstest für Selector 3.4 und MUA r020: + +- automatisch nur MUA read-only; +- höchstens zwei Inventaraufrufe für Lokalisierung und Bestand; +- danach native Webrecherche; +- keine Rückfrage, kein Download und keine Dateisystemänderung. + diff --git a/platform/openwebui/filters/auto_tool_selector.py b/platform/openwebui/filters/auto_tool_selector.py index f183946..d6ac009 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.3.0 +version: 3.4.0 description: Selects a small, relevant set of MCP servers for each user request. """ @@ -99,6 +99,16 @@ class Filter: "Do not ask the user to enable another tool: both required MUA " "capabilities are already attached to this request." ) + elif "unraid" in selected: + rule += ( + " For bounded file or media-library inventory on Unraid, prefer " + "unraid_files_inventory over repeated ls/find shell calls. The " + "inventory tool can first locate matching collection directories; " + "then call it once more on the exact returned relative_path with an " + "empty name filter to inventory that collection. It never reads file " + "contents. Use the read-only shell only when that purpose-built tool " + "cannot answer." + ) messages = body.setdefault("messages", []) for message in messages: if message.get("role") == "system" and isinstance(message.get("content"), str): @@ -150,7 +160,9 @@ class Filter: ( r"\bsona(?:rr|r)?\b", r"\brada(?:rr|r)\b", r"\barr[- ]mcp\b", r"\b(?:staffel|episode|folge)(?:n)?\b.*\b" - r"(?:fehl|such|download|indexer|release|serie)\w*", + r"(?:sonarr|radarr|indexer|release|fernsehserie|tv[- ]serie)\w*", + r"\b(?:sonarr|radarr|indexer|release|fernsehserie|tv[- ]serie)\w*\b.*\b" + r"(?:staffel|episode|folge)(?:n)?\b", r"\b(?:serie|film)\b.*\b(?:sonarr|radarr|indexer|release)\b", ), ) @@ -190,7 +202,8 @@ class Filter: 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(?:keine|keinerlei|nichts?)\b.{0,40}\b(?:[aä]nder|update|aktualisier|durchf[uü]hr|installier|download|umbenenn)\w*\b", + r"\bohne\b.{0,50}\b(?:[aä]nder|update|aktualisier|durchf[uü]hr|installier|download|umbenenn)\w*\b", r"\b(?:nicht|nichts?)\b.{0,20}\b(?:durchf[uü]hr|ausf[uü]hr|aktualisier|installier)\w*\b", ), ): diff --git a/platform/openwebui/install-filters.sh b/platform/openwebui/install-filters.sh index 8e7f1d9..835c31d 100755 --- a/platform/openwebui/install-filters.sh +++ b/platform/openwebui/install-filters.sh @@ -216,7 +216,9 @@ with con: "MUA · Unraid-Diagnose (read-only)", "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-, " + "Storage, Shares, kompakte Datei-/Medieninventare und Netzwerkstatus. " + "Für Bibliotheksprüfungen unraid_files_inventory statt wiederholter " + "ls/find-Aufrufe verwenden. Keine Start/Stop-, Installations-, " "Änderungs- oder freie Shell-Funktion. Bei einer ausdrücklich verlangten " "Änderung stellt die automatische Auswahl zusätzlich MUA-Verwaltung bereit.", ), @@ -345,6 +347,7 @@ with con: "unraid_system_health", "unraid_storage_status", "unraid_disk_health", "unraid_notifications_list", "unraid_shares_list", "unraid_share_inspect", + "unraid_files_inventory", "unraid_system_connection_test", "unraid_system_shell_readonly", )) readonly = copy.deepcopy(mua_source)