feat: standardize long-running tool workflows
This commit is contained in:
+1
-1
@@ -714,7 +714,7 @@ services:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: platform/openwebui/Dockerfile
|
||||
image: ${OPENWEBUI_IMAGE:-mike-ai/openwebui:main-01f4282-agent-loop-v8}
|
||||
image: ${OPENWEBUI_IMAGE:-mike-ai/openwebui:main-01f4282-agent-loop-v9}
|
||||
container_name: mike-ai-open-webui
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
# Merge this block into ~/.hermes/config.yaml on any VPN-connected client.
|
||||
# Hermes discovers the tools from each HTTP MCP server automatically at startup.
|
||||
mcp_servers:
|
||||
athena_operator:
|
||||
url: "http://192.168.1.212:8202/mcp"
|
||||
timeout: 3600
|
||||
connect_timeout: 30
|
||||
enabled: true
|
||||
supports_parallel_tool_calls: false
|
||||
web:
|
||||
url: "http://192.168.1.212:8203/mcp"
|
||||
timeout: 180
|
||||
connect_timeout: 30
|
||||
enabled: true
|
||||
supports_parallel_tool_calls: true
|
||||
athena_context:
|
||||
url: "http://192.168.1.212:8201/mcp"
|
||||
timeout: 120
|
||||
connect_timeout: 30
|
||||
enabled: true
|
||||
supports_parallel_tool_calls: true
|
||||
@@ -289,6 +289,56 @@ class AutoToolSelectorTests(unittest.IsolatedAsyncioTestCase):
|
||||
self.assertIn("search_web/fetch_url", result["messages"][0]["content"])
|
||||
self.assertEqual(result["reasoning_effort"], "medium")
|
||||
|
||||
async def test_unraid_media_write_gets_portable_operator_and_web(self):
|
||||
result = await self._select(
|
||||
"Ermittle online das neueste Video, lade es mit yt-dlp auf dem Unraid-Host "
|
||||
"in einen temporären Ordner, konvertiere es mit ffmpeg und lege die fertige "
|
||||
"Datei im Share Transfer ab."
|
||||
)
|
||||
self.assertEqual(
|
||||
result["tool_ids"],
|
||||
[
|
||||
"server:mcp:athena-operator-local",
|
||||
"server:mcp:mua-readonly-local",
|
||||
"server:mcp:mua",
|
||||
"server:mcp:web-general-local",
|
||||
],
|
||||
)
|
||||
self.assertIn("direct MUA management or shell tool", result["messages"][0]["content"])
|
||||
self.assertIn("Do not ask the user to enable another tool", result["messages"][0]["content"])
|
||||
self.assertIn("start-status-result pattern", result["messages"][0]["content"])
|
||||
self.assertTrue(result["metadata"]["mikeai_long_operator_task"])
|
||||
|
||||
async def test_generic_remote_host_file_operation_gets_operator(self):
|
||||
result = await self._select(
|
||||
"Führe auf dem Server ein vorhandenes Skript aus und speichere die neue Datei unter /data/export."
|
||||
)
|
||||
self.assertEqual(result["tool_ids"], ["server:mcp:athena-operator-local"])
|
||||
self.assertTrue(result["metadata"]["mikeai_long_operator_task"])
|
||||
|
||||
async def test_readonly_diagnostics_do_not_get_long_operator_budget(self):
|
||||
result = await self._select("Prüfe nur lesend den Zustand von Unraid.")
|
||||
self.assertNotIn("mikeai_long_operator_task", result["metadata"])
|
||||
|
||||
async def test_narrow_safety_clause_does_not_cancel_authorized_unraid_write(self):
|
||||
result = await self._select(
|
||||
"Lade das Video auf dem Unraid-Host herunter, konvertiere es und lege es "
|
||||
"im Transfer-Share ab. Installiere dabei kein Paket dauerhaft und ändere "
|
||||
"keine Unraid-Systemkonfiguration."
|
||||
)
|
||||
self.assertEqual(
|
||||
result["tool_ids"],
|
||||
[
|
||||
"server:mcp:athena-operator-local",
|
||||
"server:mcp:mua-readonly-local",
|
||||
"server:mcp:mua",
|
||||
],
|
||||
)
|
||||
|
||||
async def test_plain_download_advice_does_not_attach_operator(self):
|
||||
result = await self._select("Erkläre mir, wie ein Browser einen Download technisch durchführt.")
|
||||
self.assertNotIn("tool_ids", result)
|
||||
|
||||
async def test_voice_transcription_variants_select_unraid(self):
|
||||
result = await self._select(
|
||||
"Welche Dacher Contäner laufen aktuell auf dem Anrate Server?"
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
# Client-unabhängiger Werkzeugstandard
|
||||
|
||||
## Ziel
|
||||
|
||||
Eine Aufgabe darf nicht nur deshalb scheitern, weil sie in Hermes oder Pi statt
|
||||
in OpenWebUI gestellt wurde. OpenWebUI-Filter sind eine Komfort- und
|
||||
Kontextoptimierung, aber niemals die eigentliche Berechtigungs- oder
|
||||
Fähigkeitsschicht.
|
||||
|
||||
## Kernfähigkeiten für jeden vertrauenswürdigen VPN-Client
|
||||
|
||||
| Fähigkeit | MCP-Endpunkt | Zweck |
|
||||
|---|---|---|
|
||||
| Breiter Operator | `http://192.168.1.212:8202/mcp` | Terminal, Dateien, Docker, Git, Downloads, Konvertierung, APIs und SSH zu konfigurierten Systemen |
|
||||
| Allgemeines Web | `http://192.168.1.212:8203/mcp` | Site-unabhängige Suche und Seitenabruf |
|
||||
| Plattformwissen | `http://192.168.1.212:8201/mcp` | Aufbau, Ist-Zustand, Quellen und Änderungsablauf von Athena |
|
||||
|
||||
Diese drei Server bilden das tragfähige Minimum. Fach-MCPs wie Home Assistant,
|
||||
MUA, ARR, Navidrome und GitHub ergänzen kurze strukturierte Operationen. Sie
|
||||
sind der bevorzugte Weg, aber keine Voraussetzung: Fehlt eine Spezialfunktion,
|
||||
bleiben allgemeines Web und Operator verfügbar.
|
||||
|
||||
## Client-Verhalten
|
||||
|
||||
- **OpenWebUI:** Native Websuche bleibt grundsätzlich verfügbar. Der Auto Tool
|
||||
Selector hängt Fach-MCPs und den Operator anhand allgemeiner
|
||||
Fähigkeitsklassen an. Allgemeine Hostarbeit wird anhand von Ausführungs- oder
|
||||
Änderungsabsicht plus Host-, Datei-, Kommando- oder Dienstkontext erkannt;
|
||||
nicht anhand einzelner Programme oder Websites.
|
||||
- **Hermes:** Die drei Kernendpunkte werden in `~/.hermes/config.yaml`
|
||||
eingetragen. Hermes verbindet sie beim Start, ruft MCP `tools/list` auf und
|
||||
stellt die entdeckten Werkzeuge in jedem Gespräch bereit. Vorlage:
|
||||
`config/hermes-mcp-core.yaml.example`.
|
||||
- **Pi und weitere MCP-Clients:** Dieselben Streamable-HTTP-Endpunkte direkt
|
||||
konfigurieren. Es ist kein OpenWebUI-Filter und kein zusätzlicher Proxy
|
||||
erforderlich.
|
||||
|
||||
## Verbindliche Sicherheitsgrenze
|
||||
|
||||
Toolbeschreibungen und Systemprompts helfen dem Modell bei der Wahl, sind aber
|
||||
keine Sicherheitsgrenze. Unverzichtbare Verbote, Ausgabelimits,
|
||||
Schreibabläufe und Schutz vor dem Verlust der Remote-Erreichbarkeit werden im
|
||||
MCP beziehungsweise im Athena-Operator-Dienst erzwungen. Dadurch gelten sie
|
||||
identisch für OpenWebUI, Hermes, Pi und zukünftige Clients.
|
||||
|
||||
## Lange operative Aufgaben
|
||||
|
||||
Lange Arbeiten verwenden clientunabhängig das Muster
|
||||
`Start -> kompakter Status -> Ergebnis/Verifikation`. Recherche wird vor der
|
||||
Mutation abgeschlossen; Hilfsmittel werden gebündelt vorbereitet und lange
|
||||
Kommandos asynchron gestartet, wenn ein synchroner Werkzeugaufruf in ein
|
||||
Zeitlimit laufen könnte. OpenWebUI gewährt dieser allgemeinen Aufgabenklasse
|
||||
ein höheres, aber weiterhin endliches Ausführungsbudget: 64 Aufrufe insgesamt
|
||||
und 24 je Werkzeug. Normale Recherche bleibt bei 40 beziehungsweise 12. Das
|
||||
ist keine Sonderregel für YouTube, ffmpeg, MUA oder einen bestimmten Server.
|
||||
|
||||
## Community-Bezug
|
||||
|
||||
Das folgt dem MCP-Modell: Ein Client verbindet einen vertrauenswürdigen
|
||||
Streamable-HTTP-Server und entdeckt dessen Werkzeuge über `tools/list`.
|
||||
Hermes registriert konfigurierte HTTP-MCPs beim Start als normale Werkzeuge;
|
||||
OpenWebUI registriert Remote-MCPs global und kann sie pro Anfrage über
|
||||
`tool_ids` aktivieren. Clientseitige Auswahl optimiert Kontext und Bedienung,
|
||||
serverseitige Regeln bleiben maßgeblich.
|
||||
+1
-1
@@ -16,7 +16,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 | strukturierte Operationen plus breites, begrenztes Terminal; Erreichbarkeitsänderungen blockiert | 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 r020+ auf dem HomeServer, direkter MCP-Endpunkt | read-only Automatik; begrenzte Datei-/Medieninventare; Verwaltung bei explizitem Änderungsauftrag; idempotente Batch-Updates | Kern |
|
||||
| Unraid/MUA | MUA r022+ auf dem HomeServer, direkter MCP-Endpunkt | read-only Automatik; begrenzte Datei-/Medieninventare; Verwaltung bei explizitem Änderungsauftrag; idempotente Batch-Updates; asynchrone Jobs mit Start/Status/Aufräumen für lange Arbeiten | 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 |
|
||||
|
||||
@@ -197,6 +197,21 @@ aktiviert er zusätzlich die native Websuche. 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.
|
||||
|
||||
Ab MUA r022 stehen für lange, explizit autorisierte Arbeiten zusätzlich
|
||||
`unraid_system_job_start`, `unraid_system_job_status` und
|
||||
`unraid_system_job_cleanup` bereit. Der Start kehrt sofort mit einer Job-ID
|
||||
zurück; Statusabfragen liefern nur kompakte, redigierte Ausgaben. Damit blockiert
|
||||
ein Download, Transcode oder vergleichbarer Auftrag weder Open WebUI noch Hermes
|
||||
oder Pi bis zum Prozessende. Die drei Werkzeuge erben dieselbe ausdrücklich
|
||||
erteilte Berechtigung wie die uneingeschränkte Shell.
|
||||
|
||||
Auto Tool Selector 4.5 kennzeichnet allgemeine lange Operator-Aufgaben
|
||||
produktunabhängig. Der OpenWebUI-Agentenloop stellt dafür bis zu 64
|
||||
Werkzeugausführungen insgesamt und 24 je Werkzeug bereit; normale Aufgaben
|
||||
bleiben bei 40/12. Zusätzlich verlangt der Systemhinweis das generische
|
||||
Start-Status-Ergebnis-Muster und reserviert den Abschluss für Verifikation,
|
||||
Zielablage und Aufräumen.
|
||||
|
||||
Der GitHub-Container läuft produktiv. Token-Datei, interner
|
||||
Streamable-HTTP-Handshake, fehlende Host-Portfreigabe und exakt drei
|
||||
read-only Werkzeuge wurden am 24. August 2026 verifiziert.
|
||||
@@ -204,14 +219,15 @@ Die Transportbrücke verwendet den OpenWebUI-kompatiblen `mcp-proxy` 0.12.0 im
|
||||
stateless Betrieb. Supergateway wurde nach reproduzierbaren HTTP-400-Fehlern
|
||||
bei `notifications/initialized` aus diesem Pfad entfernt.
|
||||
|
||||
Die agentische OpenWebUI-Schleife führt höchstens 40 einzelne Werkzeuge aus,
|
||||
höchstens zwölf Aufrufe desselben Werkzeugnamens und höchstens zweimal exakt
|
||||
dieselbe Signatur. Nach Ende des Budgets stehen zusätzliche interne Runden ausschließlich
|
||||
für eine sichtbare werkzeugfreie Schlussantwort bereit. Das produktive
|
||||
OpenWebUI-Derivat trägt den Tag
|
||||
`mike-ai/openwebui:main-01f4282-agent-loop-v8`.
|
||||
Die agentische OpenWebUI-Schleife führt bei normalen Aufgaben höchstens 40
|
||||
einzelne Werkzeuge und höchstens zwölf Aufrufe desselben Werkzeugnamens aus.
|
||||
Allgemeine lange Operator-Aufgaben erhalten 64 beziehungsweise 24. Exakt
|
||||
dieselbe Signatur bleibt stets auf zwei Wiederholungen begrenzt. Nach Ende des
|
||||
Budgets stehen zusätzliche interne Runden ausschließlich für eine sichtbare
|
||||
werkzeugfreie Schlussantwort bereit. Das produktive OpenWebUI-Derivat trägt
|
||||
den Tag `mike-ai/openwebui:main-01f4282-agent-loop-v9`.
|
||||
|
||||
Das in V8 enthaltene Verhalten aus V7 begrenzt zusätzlich die
|
||||
Das in V9 enthaltene Verhalten aus V8 begrenzt zusätzlich die
|
||||
Werkzeugantworten in OpenWebUIs internen Fortsetzungsrunden auf 12.000 Zeichen
|
||||
je Ergebnis und 64.000 Zeichen pro Antwortlauf. Damit greift die Begrenzung
|
||||
auch bei Ergebnissen, die erst nach dem ersten Request entstehen.
|
||||
@@ -238,6 +254,22 @@ Angebote und sortierte Notebook, Zubehör sowie ein Ersatzteilgerät aus. Das
|
||||
belegt sowohl die technische Grenze als auch eine brauchbare Synthese; ein
|
||||
eBay-spezifischer MCP war nicht erforderlich.
|
||||
|
||||
Auto Tool Selector 4.5 erkennt zusätzlich allgemeine operative Arbeit über
|
||||
Fähigkeitsklassen: Eine ausdrückliche Ausführungs- oder Änderungsabsicht in
|
||||
Verbindung mit Host, Dateisystem, Kommando, Dienst, Pfad oder typischen
|
||||
Kommandozeilenwerkzeugen stellt den Athena Operator bereit. Dadurch benötigen
|
||||
neue Programme wie Download- oder Medienwerkzeuge keine eigene Selector-Regel.
|
||||
Bei Unraid-Arbeit werden MUA für kompakte Bestandsaufnahme und der Operator für
|
||||
die ausdrücklich verlangte allgemeine Schreibarbeit gemeinsam angeboten.
|
||||
Lange Operator-Aufgaben werden dabei produktunabhängig markiert und folgen dem
|
||||
Start-Status-Ergebnis-Muster, damit Recherche und Vorbereitung nicht das
|
||||
Budget für Ausführung, Verifikation und Aufräumen verbrauchen.
|
||||
|
||||
Für andere Clients gilt `docs/CLIENT_TOOL_STANDARD.md`. Hermes lädt die drei
|
||||
Kern-MCPs Web, Operator und Plattformwissen direkt per Streamable HTTP; die
|
||||
Vorlage liegt unter `config/hermes-mcp-core.yaml.example`. Damit hängt die
|
||||
Fähigkeit nicht vom OpenWebUI-Filter ab.
|
||||
|
||||
Der Platform Context MCP läuft ohne Docker-Socket, Shell, Egress oder Secrets.
|
||||
Ein root-eigener Minutentimer erzeugt nur einen begrenzten Laufzeitsnapshot.
|
||||
Der Schreibpfad ist auf `docs/*.md`, Vorschau, ausdrückliche Freigabe, atomare
|
||||
|
||||
@@ -31,6 +31,13 @@ bereit und hängt anhand der Anfrage passende Fachkataloge an. Er verweigert
|
||||
keine Fähigkeit und erfordert keine Site-spezifischen Regeln. Alle zentralen
|
||||
MCPs sind über feste WireGuard-Ports auch für Hermes und Pi erreichbar.
|
||||
|
||||
Der verbindliche client-unabhängige Mindeststandard ist in
|
||||
`docs/CLIENT_TOOL_STANDARD.md` festgelegt: allgemeines Web, Athena Operator und
|
||||
Plattformwissen werden in jedem vertrauenswürdigen VPN-Client konfiguriert.
|
||||
OpenWebUI darf diese Grundfähigkeiten zur Kontextoptimierung automatisch
|
||||
auswählen; Hermes und Pi entdecken sie direkt über die MCP-Endpunkte. Die
|
||||
Sicherheitsgrenze liegt immer serverseitig und hängt nicht von einem Filter ab.
|
||||
|
||||
Marketplace-Recherche bleibt ebenfalls allgemein: Der Selector erkennt
|
||||
Kauf-, Angebots-, Preis- und Versandsuchen unabhängig von einer einzelnen
|
||||
Website. Qwen beginnt mit einer fokussierten Suche, nutzt höchstens zwei
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""
|
||||
title: MikeAI Auto Tool Selector
|
||||
author: MikeAI
|
||||
version: 4.3.0
|
||||
version: 4.5.0
|
||||
description: Keeps broad web access available and adds relevant portable MCP domains without acting as a gate.
|
||||
"""
|
||||
|
||||
@@ -109,6 +109,48 @@ class Filter:
|
||||
)
|
||||
return search_intent and marketplace_context
|
||||
|
||||
def _is_explicitly_readonly(self, raw_text: str) -> bool:
|
||||
"""Recognise a global read-only request, not a narrow safety exception."""
|
||||
text = self._normalise(raw_text)
|
||||
return self._matches(
|
||||
text,
|
||||
(
|
||||
r"\b(?:nur|ausschlie(?:ß|ss)lich|lediglich)\s+(?:lesen|pr[uü]fen|anzeigen|auflisten)\b",
|
||||
r"\bread[- ]only\b",
|
||||
r"\bohne\s+(?:downloads?|umbenennungen?|schreibzugriff|[aä]nderungen?)\b",
|
||||
r"\bohne\s+downloads?\b.{0,80}\b(?:[aä]nderungen?|umbenennungen?)\b",
|
||||
r"\b(?:nichts|keinerlei)\s+(?:ver[aä]ndern|[aä]ndern|schreiben)\b",
|
||||
r"\b(?:[aä]ndere|ver[aä]ndere)\s+nichts\b",
|
||||
),
|
||||
)
|
||||
|
||||
def _needs_general_operator(self, raw_text: str) -> bool:
|
||||
"""Detect broad host work by capability, not product or website name."""
|
||||
text = self._normalise(raw_text)
|
||||
if self._is_explicitly_readonly(raw_text):
|
||||
return False
|
||||
action_intent = self._matches(
|
||||
text,
|
||||
(
|
||||
r"\b(?:ausf[uü]hr|starte?|stoppe?|restart|installier|deploy|bau|erstell|"
|
||||
r"schreib|speicher|leg|kopier|verschieb|umbenenn|l[oö]sch|entfern|"
|
||||
r"download|herunterlad|konvertier|transkodier|komprimier|extrahier|"
|
||||
r"bearbeit|[aä]nder|modifizier|aktualisier|reparier|fix)\w*\b",
|
||||
r"\b(?:f[uü]hre|lass)\b.{0,80}\b(?:befehl|kommando|skript|command)\b",
|
||||
),
|
||||
)
|
||||
operational_context = self._matches(
|
||||
text,
|
||||
(
|
||||
r"\b(?:host|server|unraid|unreid|unrate|anrate|nas|linux|debian|docker|"
|
||||
r"container|terminal|shell|kommando|befehl|datei(?:system)?|ordner|"
|
||||
r"verzeichnis|pfad|share|freigabe|repository|repo|mcp|api)\b",
|
||||
r"\b(?:ffmpeg|ffprobe|yt-dlp|youtube-dl|curl|wget|git|docker\s+compose)\b",
|
||||
r"(?:^|\s)/(?:tmp|data|mnt|opt|srv|var|etc|home)(?:/|\b)",
|
||||
),
|
||||
)
|
||||
return action_intent and operational_context
|
||||
|
||||
@staticmethod
|
||||
def _add_system_rule(
|
||||
body: dict,
|
||||
@@ -129,7 +171,25 @@ class Filter:
|
||||
"the Athena Operator terminal when it can answer the unresolved question. Never "
|
||||
"duplicate an existing backend; integrate or relay it and report any remaining gap."
|
||||
)
|
||||
if "unraid" in selected and "unraid_admin" in selected:
|
||||
if "unraid" in selected and "unraid_admin" in selected and "operator" in selected:
|
||||
rule += (
|
||||
" This request explicitly authorizes general work on Unraid. Use "
|
||||
"read-only MUA first for compact evidence, then use the direct MUA "
|
||||
"management or shell tool for commands and writes on Unraid. Use "
|
||||
"the Athena Operator only for orchestration on Athena or as a "
|
||||
"fallback when the target MCP cannot perform the required operation; "
|
||||
"do not spend repeated calls inventing a second SSH path. Do not ask "
|
||||
"the user to enable another tool: all three capabilities are attached. "
|
||||
"Do not install persistent packages unless explicitly requested; "
|
||||
"prefer an existing binary or task-local temporary copy. Avoid "
|
||||
"overwrites unless authorized and verify the final artifact."
|
||||
" For long-running work, finish discovery before mutation, then use "
|
||||
"a generic start-status-result pattern: prepare prerequisites in as few "
|
||||
"calls as possible, start the long command asynchronously when the tool "
|
||||
"timeout might be exceeded, poll only compact progress, and reserve "
|
||||
"enough calls for verification, final placement, and cleanup."
|
||||
)
|
||||
elif "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 "
|
||||
@@ -140,6 +200,19 @@ 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 and "operator" in selected:
|
||||
rule += (
|
||||
" This request requires general filesystem, command, download, "
|
||||
"conversion or other host work on Unraid. Use read-only MUA first "
|
||||
"for compact inventory and runtime evidence, then use the Athena "
|
||||
"Operator terminal for the exact user-authorized command sequence. "
|
||||
"Do not ask the user to enable another tool: both capabilities are "
|
||||
"already attached. Do not install persistent packages unless the "
|
||||
"user explicitly requested installation; prefer an existing binary "
|
||||
"or a task-local temporary copy. Write only to the requested target, "
|
||||
"avoid overwrites unless explicitly authorized, and verify the final "
|
||||
"artifact independently before reporting success."
|
||||
)
|
||||
elif "unraid" in selected:
|
||||
rule += (
|
||||
" For bounded file or media-library inventory on Unraid, prefer "
|
||||
@@ -193,7 +266,8 @@ class Filter:
|
||||
|
||||
selected: list[str] = []
|
||||
|
||||
operator = self._matches(
|
||||
general_operator = self._needs_general_operator(raw_text)
|
||||
operator = general_operator or self._matches(
|
||||
text,
|
||||
(
|
||||
r"\bathena[- ]operator\b",
|
||||
@@ -260,25 +334,19 @@ class Filter:
|
||||
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",
|
||||
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",
|
||||
r"\b(?:lad(?:e|en)?|download|herunterlad|konvertier|transkodier|kopier|verschieb|speicher|schreib|leg|umbenenn|l[oö]sch)\w*\b.{0,160}\b(?:unraid|unreid|unrate|anrate|nas|share|freigabe)\b",
|
||||
r"\b(?:unraid|unreid|unrate|anrate|nas|share|freigabe)\b.{0,160}\b(?:lad(?:e|en)?|download|herunterlad|konvertier|transkodier|kopier|verschieb|speicher|schreib|leg|umbenenn|l[oö]sch)\w*\b",
|
||||
r"\b(?:kommando|befehl|shell[- ]befehl)\w*\b.{0,100}\b(?:auf|in)\b.{0,30}\b(?:unraid|unreid|unrate|anrate|nas)\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|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",
|
||||
r"\b(?:[aä]nder|erstell|installier|l[oö]sch|entfern|download|umbenenn)\w*\b.{0,25}\b(?:nichts?|keine[nrms]?|keinerlei)\b",
|
||||
),
|
||||
):
|
||||
if unraid_write and self._is_explicitly_readonly(raw_text):
|
||||
unraid_write = False
|
||||
github = self._matches(
|
||||
text,
|
||||
@@ -365,6 +433,11 @@ class Filter:
|
||||
# Consumed by the versioned Open WebUI continuation patch.
|
||||
# This is a request-local execution policy, not a site rule.
|
||||
metadata["mikeai_marketplace_research"] = True
|
||||
# Long operational tasks need more executions than bounded research.
|
||||
# This is a capability-class policy, not a rule for any product, site,
|
||||
# command or MCP. The patched Open WebUI loop consumes this marker.
|
||||
if self._needs_general_operator(latest_text):
|
||||
metadata["mikeai_long_operator_task"] = True
|
||||
|
||||
if not selected:
|
||||
return body
|
||||
|
||||
@@ -31,8 +31,14 @@ replacement = """ tool_call_iterations = 0
|
||||
# Per-tool and exact-repeat limits below prevent one low-level MCP
|
||||
# operation from consuming the whole turn.
|
||||
tool_call_executions = 0
|
||||
max_tool_call_executions = 40
|
||||
max_executions_per_tool = 12
|
||||
long_operator_task = bool(
|
||||
(metadata or {}).get('mikeai_long_operator_task', False)
|
||||
)
|
||||
# Research stays tightly bounded. Explicit long-running host work
|
||||
# receives a larger, still finite budget so discovery cannot consume
|
||||
# the calls needed for execution, verification and cleanup.
|
||||
max_tool_call_executions = 64 if long_operator_task else 40
|
||||
max_executions_per_tool = 24 if long_operator_task else 12
|
||||
# Inlet filters only see the first request, not later internal
|
||||
# tool continuations. Bound the evidence injected into those
|
||||
# continuations so one broad inventory cannot consume context.
|
||||
|
||||
Reference in New Issue
Block a user