From 9ed4655044e181d920123903bf31bdfcc70452da Mon Sep 17 00:00:00 2001 From: Lionel Date: Tue, 19 May 2026 16:32:00 +0200 Subject: [PATCH 1/3] feat(skills-manager): confirm destructive actions before applying Adds a REQUIRE_CONFIRMATION valve (default true) that prompts users via __event_call__ before update_skill, delete_skill, and overwrite paths in create_skill/install_skill. Cancellations return structured results and emit localized status messages; bumps version to 0.3.3 and adds the new strings across all supported locales. --- .../tools/openwebui-skills-manager/README.md | 1 + .../openwebui_skills_manager.py | 334 +++++++++++++++++- 2 files changed, 334 insertions(+), 1 deletion(-) diff --git a/plugins/tools/openwebui-skills-manager/README.md b/plugins/tools/openwebui-skills-manager/README.md index a565478..bfb3d31 100644 --- a/plugins/tools/openwebui-skills-manager/README.md +++ b/plugins/tools/openwebui-skills-manager/README.md @@ -279,6 +279,7 @@ All installations enforce: | Parameter | Default | Description | | --- | --- | --- | | `SHOW_STATUS` | `True` | Show operation status updates in OpenWebUI status bar. | +| `REQUIRE_CONFIRMATION` | `True` | Require an interactive yes/no confirmation before destructive actions (`update_skill`, `delete_skill`, and overwrite on `create_skill`/`install_skill`). Disable to allow these without prompting. | | `ALLOW_OVERWRITE_ON_CREATE` | `False` | Allow `create_skill`/`install_skill` to overwrite same-name skill by default. | | `INSTALL_FETCH_TIMEOUT` | `12.0` | URL fetch timeout in seconds for skill installation. | | `TRUSTED_DOMAINS` | `github.com,huggingface.co,githubusercontent.com` | Comma-separated list of primary trusted domains for downloads (always enforced). Subdomains automatically allowed (e.g., `github.com` allows `api.github.com`). See [Domain Whitelist Guide](https://github.com/Fu-Jie/openwebui-extensions/blob/main/plugins/tools/openwebui-skills-manager/docs/DOMAIN_WHITELIST.md). | diff --git a/plugins/tools/openwebui-skills-manager/openwebui_skills_manager.py b/plugins/tools/openwebui-skills-manager/openwebui_skills_manager.py index 2c13573..500a7c6 100644 --- a/plugins/tools/openwebui-skills-manager/openwebui_skills_manager.py +++ b/plugins/tools/openwebui-skills-manager/openwebui_skills_manager.py @@ -3,7 +3,7 @@ author: Fu-Jie author_url: https://github.com/Fu-Jie/openwebui-extensions funding_url: https://github.com/open-webui -version: 0.3.2 +version: 0.3.3 openwebui_id: b4bce8e4-08e7-4f90-bea7-dc31d463a0bb requirements: description: Standalone OpenWebUI tool for managing native Workspace Skills (list/show/install/create/update/delete) for any model. @@ -71,6 +71,20 @@ "msg_updated": "Skill updated successfully.", "msg_deleted": "Skill deleted successfully.", "msg_installed": "Skill installed successfully.", + "confirm_update_title": "Update skill?", + "confirm_update_message": "Update skill \"{name}\".\nDescription: {description}", + "confirm_delete_title": "Delete skill?", + "confirm_delete_message": "Permanently delete skill \"{name}\". This cannot be undone.\nDescription: {description}", + "status_update_cancelled": "Update cancelled by user.", + "status_delete_cancelled": "Deletion cancelled by user.", + "msg_update_cancelled": "Skill update cancelled by user.", + "msg_delete_cancelled": "Skill deletion cancelled by user.", + "confirm_overwrite_title": "Overwrite existing skill?", + "confirm_overwrite_message": "Overwrite skill \"{name}\". Its description and content will be replaced.\nCurrent description: {description}", + "status_overwrite_cancelled": "Overwrite cancelled by user.", + "msg_overwrite_cancelled": "Skill overwrite cancelled by user.", + "err_confirmation_unavailable": "Cannot prompt for confirmation in this context (no interactive event channel). Disable REQUIRE_CONFIRMATION in valves to proceed without prompting.", + "no_description": "(no description)", } TRANSLATIONS = { @@ -111,6 +125,20 @@ "msg_updated": "技能更新成功。", "msg_deleted": "技能删除成功。", "msg_installed": "技能安装成功。", + "confirm_update_title": "更新技能?", + "confirm_update_message": "更新技能 \"{name}\"。\n描述:{description}", + "confirm_delete_title": "删除技能?", + "confirm_delete_message": "将永久删除技能 \"{name}\"。此操作无法撤销。\n描述:{description}", + "status_update_cancelled": "用户已取消更新。", + "status_delete_cancelled": "用户已取消删除。", + "msg_update_cancelled": "技能更新已由用户取消。", + "msg_delete_cancelled": "技能删除已由用户取消。", + "confirm_overwrite_title": "覆盖已存在的技能?", + "confirm_overwrite_message": "覆盖技能 \"{name}\"。其描述和内容将被替换。\n当前描述:{description}", + "status_overwrite_cancelled": "用户已取消覆盖。", + "msg_overwrite_cancelled": "技能覆盖已由用户取消。", + "err_confirmation_unavailable": "当前上下文无法弹出确认提示(无交互事件通道)。请在阀门设置中关闭 REQUIRE_CONFIRMATION 以跳过确认。", + "no_description": "(无描述)", }, "zh-TW": { "status_listing": "正在列出你的技能...", @@ -147,6 +175,20 @@ "msg_updated": "技能更新成功。", "msg_deleted": "技能刪除成功。", "msg_installed": "技能安裝成功。", + "confirm_update_title": "更新技能?", + "confirm_update_message": "更新技能 \"{name}\"。\n描述:{description}", + "confirm_delete_title": "刪除技能?", + "confirm_delete_message": "將永久刪除技能 \"{name}\"。此操作無法復原。\n描述:{description}", + "status_update_cancelled": "使用者已取消更新。", + "status_delete_cancelled": "使用者已取消刪除。", + "msg_update_cancelled": "技能更新已由使用者取消。", + "msg_delete_cancelled": "技能刪除已由使用者取消。", + "confirm_overwrite_title": "覆寫已存在的技能?", + "confirm_overwrite_message": "覆寫技能 \"{name}\"。其描述和內容將被取代。\n目前描述:{description}", + "status_overwrite_cancelled": "使用者已取消覆寫。", + "msg_overwrite_cancelled": "技能覆寫已由使用者取消。", + "err_confirmation_unavailable": "目前上下文無法彈出確認提示(無互動事件通道)。請在閥門設定中關閉 REQUIRE_CONFIRMATION 以略過確認。", + "no_description": "(無描述)", }, "zh-HK": { "status_listing": "正在列出你的技能...", @@ -183,6 +225,20 @@ "msg_updated": "技能更新成功。", "msg_deleted": "技能刪除成功。", "msg_installed": "技能安裝成功。", + "confirm_update_title": "更新技能?", + "confirm_update_message": "更新技能 \"{name}\"。\n描述:{description}", + "confirm_delete_title": "刪除技能?", + "confirm_delete_message": "將永久刪除技能 \"{name}\"。此操作無法復原。\n描述:{description}", + "status_update_cancelled": "使用者已取消更新。", + "status_delete_cancelled": "使用者已取消刪除。", + "msg_update_cancelled": "技能更新已由使用者取消。", + "msg_delete_cancelled": "技能刪除已由使用者取消。", + "confirm_overwrite_title": "覆寫已存在的技能?", + "confirm_overwrite_message": "覆寫技能 \"{name}\"。其描述和內容將被取代。\n目前描述:{description}", + "status_overwrite_cancelled": "使用者已取消覆寫。", + "msg_overwrite_cancelled": "技能覆寫已由使用者取消。", + "err_confirmation_unavailable": "目前上下文無法彈出確認提示(無互動事件通道)。請在閥門設定中關閉 REQUIRE_CONFIRMATION 以略過確認。", + "no_description": "(無描述)", }, "ja-JP": { "status_listing": "スキル一覧を取得しています...", @@ -219,6 +275,20 @@ "msg_updated": "スキルを更新しました。", "msg_deleted": "スキルを削除しました。", "msg_installed": "スキルをインストールしました。", + "confirm_update_title": "スキルを更新しますか?", + "confirm_update_message": "スキル \"{name}\" を更新します。\n説明: {description}", + "confirm_delete_title": "スキルを削除しますか?", + "confirm_delete_message": "スキル \"{name}\" を完全に削除します。この操作は取り消せません。\n説明: {description}", + "status_update_cancelled": "ユーザーが更新をキャンセルしました。", + "status_delete_cancelled": "ユーザーが削除をキャンセルしました。", + "msg_update_cancelled": "スキルの更新がユーザーによりキャンセルされました。", + "msg_delete_cancelled": "スキルの削除がユーザーによりキャンセルされました。", + "confirm_overwrite_title": "既存のスキルを上書きしますか?", + "confirm_overwrite_message": "スキル \"{name}\" を上書きします。説明と内容が置き換えられます。\n現在の説明: {description}", + "status_overwrite_cancelled": "ユーザーが上書きをキャンセルしました。", + "msg_overwrite_cancelled": "スキルの上書きがユーザーによりキャンセルされました。", + "err_confirmation_unavailable": "現在のコンテキストでは確認プロンプトを表示できません(対話型イベントチャネルなし)。確認なしで実行するにはバルブの REQUIRE_CONFIRMATION を無効にしてください。", + "no_description": "(説明なし)", }, "ko-KR": { "status_listing": "스킬 목록을 불러오는 중...", @@ -255,6 +325,20 @@ "msg_updated": "스킬이 업데이트되었습니다.", "msg_deleted": "스킬이 삭제되었습니다.", "msg_installed": "스킬이 설치되었습니다.", + "confirm_update_title": "스킬을 업데이트하시겠습니까?", + "confirm_update_message": "스킬 \"{name}\"을(를) 업데이트합니다.\n설명: {description}", + "confirm_delete_title": "스킬을 삭제하시겠습니까?", + "confirm_delete_message": "스킬 \"{name}\"을(를) 영구적으로 삭제합니다. 이 작업은 되돌릴 수 없습니다.\n설명: {description}", + "status_update_cancelled": "사용자가 업데이트를 취소했습니다.", + "status_delete_cancelled": "사용자가 삭제를 취소했습니다.", + "msg_update_cancelled": "스킬 업데이트가 사용자에 의해 취소되었습니다.", + "msg_delete_cancelled": "스킬 삭제가 사용자에 의해 취소되었습니다.", + "confirm_overwrite_title": "기존 스킬을 덮어쓰시겠습니까?", + "confirm_overwrite_message": "스킬 \"{name}\"을(를) 덮어씁니다. 설명과 내용이 교체됩니다.\n현재 설명: {description}", + "status_overwrite_cancelled": "사용자가 덮어쓰기를 취소했습니다.", + "msg_overwrite_cancelled": "스킬 덮어쓰기가 사용자에 의해 취소되었습니다.", + "err_confirmation_unavailable": "현재 컨텍스트에서 확인 프롬프트를 표시할 수 없습니다(대화형 이벤트 채널 없음). 확인 없이 진행하려면 밸브에서 REQUIRE_CONFIRMATION을 비활성화하세요.", + "no_description": "(설명 없음)", }, "fr-FR": { "status_listing": "Liste des skills en cours...", @@ -291,6 +375,20 @@ "msg_updated": "Skill mis à jour avec succès.", "msg_deleted": "Skill supprimé avec succès.", "msg_installed": "Skill installé avec succès.", + "confirm_update_title": "Mettre à jour le skill ?", + "confirm_update_message": "Mettre à jour le skill \"{name}\".\nDescription : {description}", + "confirm_delete_title": "Supprimer le skill ?", + "confirm_delete_message": "Supprimer définitivement le skill \"{name}\". Cette action est irréversible.\nDescription : {description}", + "status_update_cancelled": "Mise à jour annulée par l'utilisateur.", + "status_delete_cancelled": "Suppression annulée par l'utilisateur.", + "msg_update_cancelled": "Mise à jour du skill annulée par l'utilisateur.", + "msg_delete_cancelled": "Suppression du skill annulée par l'utilisateur.", + "confirm_overwrite_title": "Écraser le skill existant ?", + "confirm_overwrite_message": "Écraser le skill \"{name}\". Sa description et son contenu seront remplacés.\nDescription actuelle : {description}", + "status_overwrite_cancelled": "Écrasement annulé par l'utilisateur.", + "msg_overwrite_cancelled": "Écrasement du skill annulé par l'utilisateur.", + "err_confirmation_unavailable": "Impossible d'afficher une invite de confirmation dans ce contexte (aucun canal d'événement interactif). Désactivez REQUIRE_CONFIRMATION dans les valves pour continuer sans invite.", + "no_description": "(aucune description)", }, "de-DE": { "status_listing": "Deine Skills werden aufgelistet...", @@ -324,6 +422,20 @@ "msg_updated": "Skill erfolgreich aktualisiert.", "msg_deleted": "Skill erfolgreich gelöscht.", "msg_installed": "Skill erfolgreich installiert.", + "confirm_update_title": "Skill aktualisieren?", + "confirm_update_message": "Skill \"{name}\" aktualisieren.\nBeschreibung: {description}", + "confirm_delete_title": "Skill löschen?", + "confirm_delete_message": "Skill \"{name}\" dauerhaft löschen. Dies kann nicht rückgängig gemacht werden.\nBeschreibung: {description}", + "status_update_cancelled": "Aktualisierung vom Benutzer abgebrochen.", + "status_delete_cancelled": "Löschung vom Benutzer abgebrochen.", + "msg_update_cancelled": "Skill-Aktualisierung vom Benutzer abgebrochen.", + "msg_delete_cancelled": "Skill-Löschung vom Benutzer abgebrochen.", + "confirm_overwrite_title": "Vorhandenen Skill überschreiben?", + "confirm_overwrite_message": "Skill \"{name}\" überschreiben. Seine Beschreibung und sein Inhalt werden ersetzt.\nAktuelle Beschreibung: {description}", + "status_overwrite_cancelled": "Überschreiben vom Benutzer abgebrochen.", + "msg_overwrite_cancelled": "Skill-Überschreiben vom Benutzer abgebrochen.", + "err_confirmation_unavailable": "In diesem Kontext kann keine Bestätigung angezeigt werden (kein interaktiver Ereigniskanal). Deaktiviere REQUIRE_CONFIRMATION in den Valves, um ohne Bestätigung fortzufahren.", + "no_description": "(keine Beschreibung)", }, "es-ES": { "status_listing": "Listando tus skills...", @@ -357,6 +469,20 @@ "msg_updated": "Skill actualizado correctamente.", "msg_deleted": "Skill eliminado correctamente.", "msg_installed": "Skill instalado correctamente.", + "confirm_update_title": "¿Actualizar skill?", + "confirm_update_message": "Actualizar skill \"{name}\".\nDescripción: {description}", + "confirm_delete_title": "¿Eliminar skill?", + "confirm_delete_message": "Eliminar permanentemente el skill \"{name}\". Esta acción no se puede deshacer.\nDescripción: {description}", + "status_update_cancelled": "Actualización cancelada por el usuario.", + "status_delete_cancelled": "Eliminación cancelada por el usuario.", + "msg_update_cancelled": "Actualización del skill cancelada por el usuario.", + "msg_delete_cancelled": "Eliminación del skill cancelada por el usuario.", + "confirm_overwrite_title": "¿Sobrescribir skill existente?", + "confirm_overwrite_message": "Sobrescribir el skill \"{name}\". Su descripción y contenido serán reemplazados.\nDescripción actual: {description}", + "status_overwrite_cancelled": "Sobrescritura cancelada por el usuario.", + "msg_overwrite_cancelled": "Sobrescritura del skill cancelada por el usuario.", + "err_confirmation_unavailable": "No se puede mostrar la confirmación en este contexto (no hay canal de eventos interactivo). Desactiva REQUIRE_CONFIRMATION en las valves para continuar sin confirmación.", + "no_description": "(sin descripción)", }, "it-IT": { "status_listing": "Elenco delle skill in corso...", @@ -390,6 +516,20 @@ "msg_updated": "Skill aggiornata con successo.", "msg_deleted": "Skill eliminata con successo.", "msg_installed": "Skill installata con successo.", + "confirm_update_title": "Aggiornare la skill?", + "confirm_update_message": "Aggiornare la skill \"{name}\".\nDescrizione: {description}", + "confirm_delete_title": "Eliminare la skill?", + "confirm_delete_message": "Eliminare definitivamente la skill \"{name}\". L'operazione non può essere annullata.\nDescrizione: {description}", + "status_update_cancelled": "Aggiornamento annullato dall'utente.", + "status_delete_cancelled": "Eliminazione annullata dall'utente.", + "msg_update_cancelled": "Aggiornamento della skill annullato dall'utente.", + "msg_delete_cancelled": "Eliminazione della skill annullata dall'utente.", + "confirm_overwrite_title": "Sovrascrivere la skill esistente?", + "confirm_overwrite_message": "Sovrascrivere la skill \"{name}\". La descrizione e il contenuto saranno sostituiti.\nDescrizione attuale: {description}", + "status_overwrite_cancelled": "Sovrascrittura annullata dall'utente.", + "msg_overwrite_cancelled": "Sovrascrittura della skill annullata dall'utente.", + "err_confirmation_unavailable": "Impossibile mostrare la conferma in questo contesto (nessun canale di eventi interattivo). Disattiva REQUIRE_CONFIRMATION nelle valvole per procedere senza conferma.", + "no_description": "(nessuna descrizione)", }, "vi-VN": { "status_listing": "Đang liệt kê kỹ năng của bạn...", @@ -423,6 +563,20 @@ "msg_updated": "Cập nhật kỹ năng thành công.", "msg_deleted": "Xóa kỹ năng thành công.", "msg_installed": "Cài đặt kỹ năng thành công.", + "confirm_update_title": "Cập nhật kỹ năng?", + "confirm_update_message": "Cập nhật kỹ năng \"{name}\".\nMô tả: {description}", + "confirm_delete_title": "Xóa kỹ năng?", + "confirm_delete_message": "Xóa vĩnh viễn kỹ năng \"{name}\". Hành động này không thể hoàn tác.\nMô tả: {description}", + "status_update_cancelled": "Người dùng đã hủy cập nhật.", + "status_delete_cancelled": "Người dùng đã hủy xóa.", + "msg_update_cancelled": "Người dùng đã hủy cập nhật kỹ năng.", + "msg_delete_cancelled": "Người dùng đã hủy xóa kỹ năng.", + "confirm_overwrite_title": "Ghi đè kỹ năng đã tồn tại?", + "confirm_overwrite_message": "Ghi đè kỹ năng \"{name}\". Mô tả và nội dung sẽ bị thay thế.\nMô tả hiện tại: {description}", + "status_overwrite_cancelled": "Người dùng đã hủy ghi đè.", + "msg_overwrite_cancelled": "Người dùng đã hủy ghi đè kỹ năng.", + "err_confirmation_unavailable": "Không thể hiển thị xác nhận trong ngữ cảnh này (không có kênh sự kiện tương tác). Tắt REQUIRE_CONFIRMATION trong valves để tiếp tục mà không cần xác nhận.", + "no_description": "(không có mô tả)", }, "id-ID": { "status_listing": "Sedang menampilkan daftar skill Anda...", @@ -456,6 +610,20 @@ "msg_updated": "Skill berhasil diperbarui.", "msg_deleted": "Skill berhasil dihapus.", "msg_installed": "Skill berhasil dipasang.", + "confirm_update_title": "Perbarui skill?", + "confirm_update_message": "Perbarui skill \"{name}\".\nDeskripsi: {description}", + "confirm_delete_title": "Hapus skill?", + "confirm_delete_message": "Hapus skill \"{name}\" secara permanen. Tindakan ini tidak dapat dibatalkan.\nDeskripsi: {description}", + "status_update_cancelled": "Pembaruan dibatalkan oleh pengguna.", + "status_delete_cancelled": "Penghapusan dibatalkan oleh pengguna.", + "msg_update_cancelled": "Pembaruan skill dibatalkan oleh pengguna.", + "msg_delete_cancelled": "Penghapusan skill dibatalkan oleh pengguna.", + "confirm_overwrite_title": "Timpa skill yang ada?", + "confirm_overwrite_message": "Timpa skill \"{name}\". Deskripsi dan kontennya akan diganti.\nDeskripsi saat ini: {description}", + "status_overwrite_cancelled": "Penimpaan dibatalkan oleh pengguna.", + "msg_overwrite_cancelled": "Penimpaan skill dibatalkan oleh pengguna.", + "err_confirmation_unavailable": "Tidak dapat menampilkan konfirmasi dalam konteks ini (tidak ada saluran event interaktif). Nonaktifkan REQUIRE_CONFIRMATION di valves untuk melanjutkan tanpa konfirmasi.", + "no_description": "(tanpa deskripsi)", }, } @@ -614,6 +782,40 @@ async def _emit_status( ) +async def _request_confirmation( + event_call: Optional[Any], + title: str, + message: str, +) -> Optional[bool]: + """Prompt the user for a yes/no confirmation via __event_call__. + Returns True if confirmed, False if the user declined, or None if no + interactive event channel is available (caller decides how to handle). + """ + if not event_call: + return None + try: + result = await event_call( + { + "type": "confirmation", + "data": {"title": title, "message": message}, + } + ) + except Exception as e: + logger.warning(f"Confirmation prompt failed: {e}") + return None + return bool(result) + + +def _format_description_for_prompt(description: Any, lang: str, max_len: int = 200) -> str: + """Render a skill description for inclusion in a confirmation dialog.""" + text = str(description or "").strip() + if not text: + return _t(lang, "no_description") + if len(text) > max_len: + return text[: max_len - 1].rstrip() + "…" + return text + + def _require_skills_model(): """Ensure OpenWebUI Skills model APIs are available.""" if Skills is None or SkillForm is None or SkillMeta is None: @@ -1133,6 +1335,7 @@ async def _install_single_skill( lang: str, overwrite: bool, __event_emitter__: Optional[Any] = None, + __event_call__: Optional[Any] = None, ) -> Dict[str, Any]: """Internal method to install a single skill from URL.""" try: @@ -1208,6 +1411,40 @@ async def _install_single_skill( "error": f"Skill already exists: {final_name}", "hint": "Pass overwrite=true to replace the existing skill.", } + if valves.REQUIRE_CONFIRMATION: + confirmed = await _request_confirmation( + __event_call__, + _t(lang, "confirm_overwrite_title"), + _t( + lang, + "confirm_overwrite_message", + name=final_name, + description=_format_description_for_prompt( + getattr(existing, "description", ""), lang + ), + ), + ) + if confirmed is None: + # Batch caller aggregates per-URL results; do not raise. + return { + "error": _t(lang, "err_confirmation_unavailable"), + "url": url, + } + if not confirmed: + await _emit_status( + valves, + __event_emitter__, + _t(lang, "status_overwrite_cancelled"), + done=True, + ) + return { + "cancelled": True, + "action": "overwrite_cancelled", + "id": sid, + "name": final_name, + "source_url": url, + "message": _t(lang, "msg_overwrite_cancelled"), + } updated = await _call_openwebui_compat( Skills.update_skill_by_id, sid, @@ -1281,6 +1518,10 @@ class Valves(BaseModel): default=True, description="Whether to show operation status updates.", ) + REQUIRE_CONFIRMATION: bool = Field( + default=True, + description="Require an interactive yes/no confirmation before destructive actions (update_skill, delete_skill, and overwrite on create_skill/install_skill). Disable to allow these without prompting.", + ) ALLOW_OVERWRITE_ON_CREATE: bool = Field( default=True, description="Allow create_skill/install_skill to overwrite same-name skill by default.", @@ -1516,6 +1757,7 @@ async def install_skill( lang=lang, overwrite=overwrite, __event_emitter__=__event_emitter__, + __event_call__=__event_call__, ) # Track installed name to detect duplicates @@ -1578,6 +1820,7 @@ async def install_skill( lang=lang, overwrite=overwrite, __event_emitter__=__event_emitter__, + __event_call__=__event_call__, ) return result @@ -1643,6 +1886,35 @@ async def create_skill( } sid = str(getattr(existing, "id", "") or "") + if self.valves.REQUIRE_CONFIRMATION: + confirmed = await _request_confirmation( + __event_call__, + _t(lang, "confirm_overwrite_title"), + _t( + lang, + "confirm_overwrite_message", + name=skill_name, + description=_format_description_for_prompt( + getattr(existing, "description", ""), lang + ), + ), + ) + if confirmed is None: + raise ValueError(_t(lang, "err_confirmation_unavailable")) + if not confirmed: + await _emit_status( + self.valves, + __event_emitter__, + _t(lang, "status_overwrite_cancelled"), + done=True, + ) + return { + "cancelled": True, + "action": "overwrite_cancelled", + "id": sid, + "name": skill_name, + "message": _t(lang, "msg_overwrite_cancelled"), + } updated = await _call_openwebui_compat( Skills.update_skill_by_id, sid, @@ -1766,6 +2038,36 @@ async def update_skill( if not updates: raise ValueError(_t(lang, "err_no_update_fields")) + if self.valves.REQUIRE_CONFIRMATION: + current_name = str(getattr(skill, "name", "") or sid) + confirmed = await _request_confirmation( + __event_call__, + _t(lang, "confirm_update_title"), + _t( + lang, + "confirm_update_message", + name=current_name, + description=_format_description_for_prompt( + getattr(skill, "description", ""), lang + ), + ), + ) + if confirmed is None: + raise ValueError(_t(lang, "err_confirmation_unavailable")) + if not confirmed: + await _emit_status( + self.valves, + __event_emitter__, + _t(lang, "status_update_cancelled"), + done=True, + ) + return { + "cancelled": True, + "id": sid, + "name": current_name, + "message": _t(lang, "msg_update_cancelled"), + } + updated = await _call_openwebui_compat(Skills.update_skill_by_id, sid, updates, prefer_thread_for_sync=True) updated_name = str( getattr(updated, "name", "") @@ -1823,6 +2125,36 @@ async def delete_skill( sid = str(getattr(skill, "id", "") or "") sname = str(getattr(skill, "name", "") or "") + + if self.valves.REQUIRE_CONFIRMATION: + confirmed = await _request_confirmation( + __event_call__, + _t(lang, "confirm_delete_title"), + _t( + lang, + "confirm_delete_message", + name=sname or "unknown", + description=_format_description_for_prompt( + getattr(skill, "description", ""), lang + ), + ), + ) + if confirmed is None: + raise ValueError(_t(lang, "err_confirmation_unavailable")) + if not confirmed: + await _emit_status( + self.valves, + __event_emitter__, + _t(lang, "status_delete_cancelled"), + done=True, + ) + return { + "cancelled": True, + "id": sid, + "name": sname, + "message": _t(lang, "msg_delete_cancelled"), + } + await _call_openwebui_compat(Skills.delete_skill_by_id, sid, prefer_thread_for_sync=True) deleted_name = sname or sid or "unknown" From d60db3c6dac7f070539fcce598382db88f364a08 Mon Sep 17 00:00:00 2001 From: Lionel Date: Tue, 19 May 2026 23:20:40 +0200 Subject: [PATCH 2/3] chore(skills-manager): release prep for v0.3.3 - Route _request_confirmation through _call_openwebui_compat for consistency with other OpenWebUI integration calls. - Sync v0.3.3 across plugin/docs READMEs, docs mirror pages, and root plugin-list badges; bump root updated date to 2026-05-19. - Update What's New blocks in plugin and docs READMEs (EN/CN) and add bilingual v0.3.3 release notes. - Document REQUIRE_CONFIRMATION valve in README_CN.md. --- README.md | 8 +++----- README_CN.md | 4 ++-- docs/plugins/tools/index.md | 2 +- docs/plugins/tools/index.zh.md | 2 +- .../tools/openwebui-skills-manager-tool.md | 7 +++---- .../tools/openwebui-skills-manager-tool.zh.md | 7 +++---- .../plugins/tools/openwebui-skills-manager.md | 7 +++---- .../tools/openwebui-skills-manager.zh.md | 7 +++---- .../tools/openwebui-skills-manager/README.md | 7 +++---- .../openwebui-skills-manager/README_CN.md | 8 ++++---- .../openwebui_skills_manager.py | 5 +++-- .../tools/openwebui-skills-manager/v0.3.3.md | 20 +++++++++++++++++++ .../openwebui-skills-manager/v0.3.3_CN.md | 20 +++++++++++++++++++ 13 files changed, 69 insertions(+), 35 deletions(-) create mode 100644 plugins/tools/openwebui-skills-manager/v0.3.3.md create mode 100644 plugins/tools/openwebui-skills-manager/v0.3.3_CN.md diff --git a/README.md b/README.md index 3cbfc4d..7d0b2e5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # OpenWebUI Extensions -[![All Contributors](https://img.shields.io/badge/all_contributors-7-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-5-orange.svg?style=flat-square)](#contributors-) English | [中文](./README_CN.md) @@ -24,10 +24,10 @@ A collection of enhancements, plugins, and prompts for [open-webui](https://gith | Rank | Plugin | Version | Downloads | Views | 📅 Updated | | :---: | :--- | :---: | :---: | :---: | :---: | | 🥇 | [Smart Mind Map](https://openwebui.com/posts/turn_any_text_into_beautiful_mind_maps_3094c59a) | ![v](https://img.shields.io/badge/v-1.0.1-blue?style=flat) | ![p1_dl](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_p1_dl.json&style=flat) | ![p1_vw](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_p1_vw.json&style=flat) | ![updated](https://img.shields.io/badge/2026--04--24-gray?style=flat) | -| 🥈 | [Async Context Compression](https://openwebui.com/posts/async_context_compression_b1655bc8) | ![v](https://img.shields.io/badge/v-1.6.3-blue?style=flat) | ![p2_dl](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_p2_dl.json&style=flat) | ![p2_vw](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_p2_vw.json&style=flat) | ![updated](https://img.shields.io/badge/2026--05--19-gray?style=flat) | +| 🥈 | [Async Context Compression](https://openwebui.com/posts/async_context_compression_b1655bc8) | ![v](https://img.shields.io/badge/v-1.6.2-blue?style=flat) | ![p2_dl](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_p2_dl.json&style=flat) | ![p2_vw](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_p2_vw.json&style=flat) | ![updated](https://img.shields.io/badge/2026--05--12-gray?style=flat) | | 🥉 | [Smart Infographic](https://openwebui.com/posts/smart_infographic_ad6f0c7f) | ![v](https://img.shields.io/badge/v-1.6.2-blue?style=flat) | ![p3_dl](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_p3_dl.json&style=flat) | ![p3_vw](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_p3_vw.json&style=flat) | ![updated](https://img.shields.io/badge/2026--04--25-gray?style=flat) | | 4️⃣ | [Markdown Normalizer](https://openwebui.com/posts/markdown_normalizer_baaa8732) | ![v](https://img.shields.io/badge/v-1.2.8-blue?style=flat) | ![p4_dl](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_p4_dl.json&style=flat) | ![p4_vw](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_p4_vw.json&style=flat) | ![updated](https://img.shields.io/badge/2026--04--15-gray?style=flat) | -| 5️⃣ | [OpenWebUI Skills Manager Tool](https://openwebui.com/posts/openwebui_skills_manager_tool_b4bce8e4) | ![v](https://img.shields.io/badge/v-0.3.2-blue?style=flat) | ![p5_dl](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_p5_dl.json&style=flat) | ![p5_vw](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_p5_vw.json&style=flat) | ![updated](https://img.shields.io/badge/2026--05--19-gray?style=flat) | +| 5️⃣ | [OpenWebUI Skills Manager Tool](https://openwebui.com/posts/openwebui_skills_manager_tool_b4bce8e4) | ![v](https://img.shields.io/badge/v-0.3.3-blue?style=flat) | ![p5_dl](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_p5_dl.json&style=flat) | ![p5_vw](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_p5_vw.json&style=flat) | ![updated](https://img.shields.io/badge/2026--05--19-gray?style=flat) | | 6️⃣ | [AI Task Instruction Generator](https://openwebui.com/posts/ai_task_instruction_generator_9bab8b37) | ![v](https://img.shields.io/badge/v-N/A-gray?style=flat) | ![p6_dl](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_p6_dl.json&style=flat) | ![p6_vw](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_p6_vw.json&style=flat) | ![updated](https://img.shields.io/badge/2026--03--22-gray?style=flat) | ### 📈 Total Downloads Trend @@ -217,8 +217,6 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d ZOLO
ZOLO

🐛 🤔 Johan Grande
Johan Grande

🤔 Alessandro Baroni
Alessandro Baroni

🤔 - dvystrcil
dvystrcil

💻 - Colin Chen
Colin Chen

🐛 💻 diff --git a/README_CN.md b/README_CN.md index 275eb8d..bf651a2 100644 --- a/README_CN.md +++ b/README_CN.md @@ -21,10 +21,10 @@ OpenWebUI 增强功能集合。包含个人开发与收集的插件、提示词 | 排名 | 插件 | 版本 | 下载 | 浏览 | 📅 更新 | | :---: | :--- | :---: | :---: | :---: | :---: | | 🥇 | [Smart Mind Map](https://openwebui.com/posts/turn_any_text_into_beautiful_mind_maps_3094c59a) | ![v](https://img.shields.io/badge/v-1.0.1-blue?style=flat) | ![p1_dl](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_p1_dl.json&style=flat) | ![p1_vw](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_p1_vw.json&style=flat) | ![updated](https://img.shields.io/badge/2026--04--24-gray?style=flat) | -| 🥈 | [Async Context Compression](https://openwebui.com/posts/async_context_compression_b1655bc8) | ![v](https://img.shields.io/badge/v-1.6.3-blue?style=flat) | ![p2_dl](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_p2_dl.json&style=flat) | ![p2_vw](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_p2_vw.json&style=flat) | ![updated](https://img.shields.io/badge/2026--05--19-gray?style=flat) | +| 🥈 | [Async Context Compression](https://openwebui.com/posts/async_context_compression_b1655bc8) | ![v](https://img.shields.io/badge/v-1.6.2-blue?style=flat) | ![p2_dl](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_p2_dl.json&style=flat) | ![p2_vw](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_p2_vw.json&style=flat) | ![updated](https://img.shields.io/badge/2026--05--12-gray?style=flat) | | 🥉 | [Smart Infographic](https://openwebui.com/posts/smart_infographic_ad6f0c7f) | ![v](https://img.shields.io/badge/v-1.6.2-blue?style=flat) | ![p3_dl](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_p3_dl.json&style=flat) | ![p3_vw](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_p3_vw.json&style=flat) | ![updated](https://img.shields.io/badge/2026--04--25-gray?style=flat) | | 4️⃣ | [Markdown Normalizer](https://openwebui.com/posts/markdown_normalizer_baaa8732) | ![v](https://img.shields.io/badge/v-1.2.8-blue?style=flat) | ![p4_dl](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_p4_dl.json&style=flat) | ![p4_vw](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_p4_vw.json&style=flat) | ![updated](https://img.shields.io/badge/2026--04--15-gray?style=flat) | -| 5️⃣ | [OpenWebUI Skills Manager Tool](https://openwebui.com/posts/openwebui_skills_manager_tool_b4bce8e4) | ![v](https://img.shields.io/badge/v-0.3.2-blue?style=flat) | ![p5_dl](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_p5_dl.json&style=flat) | ![p5_vw](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_p5_vw.json&style=flat) | ![updated](https://img.shields.io/badge/2026--05--19-gray?style=flat) | +| 5️⃣ | [OpenWebUI Skills Manager Tool](https://openwebui.com/posts/openwebui_skills_manager_tool_b4bce8e4) | ![v](https://img.shields.io/badge/v-0.3.3-blue?style=flat) | ![p5_dl](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_p5_dl.json&style=flat) | ![p5_vw](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_p5_vw.json&style=flat) | ![updated](https://img.shields.io/badge/2026--05--19-gray?style=flat) | | 6️⃣ | [AI Task Instruction Generator](https://openwebui.com/posts/ai_task_instruction_generator_9bab8b37) | ![v](https://img.shields.io/badge/v-N/A-gray?style=flat) | ![p6_dl](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_p6_dl.json&style=flat) | ![p6_vw](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_p6_vw.json&style=flat) | ![updated](https://img.shields.io/badge/2026--03--22-gray?style=flat) | ### 📈 总下载量累计趋势 diff --git a/docs/plugins/tools/index.md b/docs/plugins/tools/index.md index b381d8d..a0464ef 100644 --- a/docs/plugins/tools/index.md +++ b/docs/plugins/tools/index.md @@ -5,5 +5,5 @@ OpenWebUI native Tool plugins that can be used across models. ## Available Tool Plugins - [Batch Install Plugins from GitHub](batch-install-plugins-tool.md) (v1.1.0) - One-click batch install plugins from GitHub repositories with an interactive selection dialog and multi-language support. -- [OpenWebUI Skills Manager Tool](openwebui-skills-manager-tool.md) (v0.3.2) - Native skill management with multi-line `SKILL.md` frontmatter description support. +- [OpenWebUI Skills Manager Tool](openwebui-skills-manager-tool.md) (v0.3.3) - Native skill management with multi-line `SKILL.md` frontmatter description support. - [Smart Mind Map Tool](smart-mind-map-tool.md) (v1.0.1) - Intelligently analyzes text content and proactively generates interactive mind maps to help users structure and visualize knowledge. diff --git a/docs/plugins/tools/index.zh.md b/docs/plugins/tools/index.zh.md index c12501e..59bc378 100644 --- a/docs/plugins/tools/index.zh.md +++ b/docs/plugins/tools/index.zh.md @@ -5,5 +5,5 @@ ## 可用 Tool 插件 - [Batch Install Plugins from GitHub](batch-install-plugins-tool.zh.md) (v1.1.0) - 一键从 GitHub 仓库批量安装插件,支持交互式选择对话框和多语言。 -- [OpenWebUI Skills 管理工具](openwebui-skills-manager-tool.zh.md) (v0.3.2) - 支持多行 `SKILL.md` frontmatter 描述的原生技能管理工具。 +- [OpenWebUI Skills 管理工具](openwebui-skills-manager-tool.zh.md) (v0.3.3) - 支持多行 `SKILL.md` frontmatter 描述的原生技能管理工具。 - [智能思维导图工具 (Smart Mind Map Tool)](smart-mind-map-tool.zh.md) (v1.0.1) - 智能分析文本内容并主动生成交互式思维导图,帮助用户结构化与可视化知识。 diff --git a/docs/plugins/tools/openwebui-skills-manager-tool.md b/docs/plugins/tools/openwebui-skills-manager-tool.md index a565478..9dd7d94 100644 --- a/docs/plugins/tools/openwebui-skills-manager-tool.md +++ b/docs/plugins/tools/openwebui-skills-manager-tool.md @@ -1,6 +1,6 @@ # 🧰 OpenWebUI Skills Manager Tool -| By [Fu-Jie](https://github.com/Fu-Jie) · v0.3.2 | [⭐ Star this repo](https://github.com/Fu-Jie/openwebui-extensions) | +| By [Fu-Jie](https://github.com/Fu-Jie) · v0.3.3 | [⭐ Star this repo](https://github.com/Fu-Jie/openwebui-extensions) | | :--- | ---: | | ![followers](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_followers.json&label=%F0%9F%91%A5&style=flat) | ![points](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_points.json&label=%E2%AD%90&style=flat) | ![top](https://img.shields.io/badge/%F0%9F%8F%86-Top%20%3C1%25-10b981?style=flat) | ![contributions](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_contributions.json&label=%F0%9F%93%A6&style=flat) | ![downloads](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_downloads.json&label=%E2%AC%87%EF%B8%8F&style=flat) | ![saves](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_saves.json&label=%F0%9F%92%BE&style=flat) | ![views](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_views.json&label=%F0%9F%91%81%EF%B8%8F&style=flat) | @@ -23,9 +23,8 @@ When the selection dialog opens, search for this plugin, check it, and continue. ## What's New -- **⚡ OpenWebUI 0.9.x Compatibility**: Added runtime async detection and compatibility layer for OpenWebUI 0.9.x+ asynchronous database models (Skills), with graceful sync fallback for older versions. -- **📝 Multi-line Frontmatter Descriptions**: `install_skill` now correctly parses `description: >` and `description: |` blocks in remote `SKILL.md` files, so imported skill descriptions no longer truncate to a single line. -- **↩️ Better Metadata Fallbacks**: If a skill frontmatter provides `title` without `name`, the installer now uses that title before falling back to directory-based names. +- **🛡️ Confirmation Before Destructive Actions**: New `REQUIRE_CONFIRMATION` valve (default `True`) prompts the user via `__event_call__` before `update_skill`, `delete_skill`, and overwrite paths in `create_skill`/`install_skill`. Cancellations return a structured `{cancelled: true, ...}` result with localized status messages. +- **🌐 Localized Confirmation Strings**: All new confirmation titles, messages, and cancellation statuses are translated across the 12 supported locales. > [!TIP] > **💡 Looking to batch install global plugins (Actions, Filters, Pipes, Tools)?** diff --git a/docs/plugins/tools/openwebui-skills-manager-tool.zh.md b/docs/plugins/tools/openwebui-skills-manager-tool.zh.md index 4800519..44acc35 100644 --- a/docs/plugins/tools/openwebui-skills-manager-tool.zh.md +++ b/docs/plugins/tools/openwebui-skills-manager-tool.zh.md @@ -1,6 +1,6 @@ # 🧰 OpenWebUI Skills 管理工具 -| 作者:[Fu-Jie](https://github.com/Fu-Jie) · v0.3.2 | [⭐ 点个 Star 支持项目](https://github.com/Fu-Jie/openwebui-extensions) | +| 作者:[Fu-Jie](https://github.com/Fu-Jie) · v0.3.3 | [⭐ 点个 Star 支持项目](https://github.com/Fu-Jie/openwebui-extensions) | | :--- | ---: | | ![followers](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_followers.json&label=%F0%9F%91%A5&style=flat) | ![points](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_points.json&label=%E2%AD%90&style=flat) | ![top](https://img.shields.io/badge/%F0%9F%8F%86-Top%20%3C1%25-10b981?style=flat) | ![contributions](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_contributions.json&label=%F0%9F%93%A6&style=flat) | ![downloads](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_downloads.json&label=%E2%AC%87%EF%B8%8F&style=flat) | ![saves](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_saves.json&label=%F0%9F%92%BE&style=flat) | ![views](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_views.json&label=%F0%9F%91%81%EF%B8%8F&style=flat) | @@ -23,9 +23,8 @@ ## 最新更新 -- **⚡ OpenWebUI 0.9.x 兼容性**:新增运行时异步检测和兼容性适配层,支持 OpenWebUI 0.9.x 及以上版本的异步数据库模型(Skills),同时完美回退支持旧版本的同步调用。 -- **📝 支持多行 Frontmatter 描述**:`install_skill` 现在可以正确解析远程 `SKILL.md` 里的 `description: >` 和 `description: |`,导入后的技能描述不再被截断成单行。 -- **↩️ 更稳的元数据回退**:当 frontmatter 只有 `title` 没有 `name` 时,安装器会优先使用 `title`,避免退回到通用目录名。 +- **🛡️ 破坏性操作确认**:新增 `REQUIRE_CONFIRMATION` 阀门(默认 `True`),在执行 `update_skill`、`delete_skill` 以及 `create_skill`/`install_skill` 触发覆盖前通过 `__event_call__` 弹出用户确认。取消时返回结构化的 `{cancelled: true, ...}` 结果,并发出本地化的状态消息。 +- **🌐 本地化确认文案**:所有新增的确认标题、提示信息和取消状态文案均已翻译至支持的 12 种语言。 > [!TIP] > **💡 想要批量安装/管理全局插件 (Actions, Filters, Pipes, Tools)?** diff --git a/docs/plugins/tools/openwebui-skills-manager.md b/docs/plugins/tools/openwebui-skills-manager.md index 45aa385..9dd7d94 100644 --- a/docs/plugins/tools/openwebui-skills-manager.md +++ b/docs/plugins/tools/openwebui-skills-manager.md @@ -1,6 +1,6 @@ # 🧰 OpenWebUI Skills Manager Tool -| By [Fu-Jie](https://github.com/Fu-Jie) · v0.3.1 | [⭐ Star this repo](https://github.com/Fu-Jie/openwebui-extensions) | +| By [Fu-Jie](https://github.com/Fu-Jie) · v0.3.3 | [⭐ Star this repo](https://github.com/Fu-Jie/openwebui-extensions) | | :--- | ---: | | ![followers](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_followers.json&label=%F0%9F%91%A5&style=flat) | ![points](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_points.json&label=%E2%AD%90&style=flat) | ![top](https://img.shields.io/badge/%F0%9F%8F%86-Top%20%3C1%25-10b981?style=flat) | ![contributions](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_contributions.json&label=%F0%9F%93%A6&style=flat) | ![downloads](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_downloads.json&label=%E2%AC%87%EF%B8%8F&style=flat) | ![saves](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_saves.json&label=%F0%9F%92%BE&style=flat) | ![views](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_views.json&label=%F0%9F%91%81%EF%B8%8F&style=flat) | @@ -23,9 +23,8 @@ When the selection dialog opens, search for this plugin, check it, and continue. ## What's New -- **📝 Multi-line Frontmatter Descriptions**: `install_skill` now correctly parses `description: >` and `description: |` blocks in remote `SKILL.md` files, so imported skill descriptions no longer truncate to a single line. -- **↩️ Better Metadata Fallbacks**: If a skill frontmatter provides `title` without `name`, the installer now uses that title before falling back to directory-based names. -- **🧪 Regression Coverage**: Added focused tests for folded/literal YAML blocks and CRLF line endings to keep external skill imports stable. +- **🛡️ Confirmation Before Destructive Actions**: New `REQUIRE_CONFIRMATION` valve (default `True`) prompts the user via `__event_call__` before `update_skill`, `delete_skill`, and overwrite paths in `create_skill`/`install_skill`. Cancellations return a structured `{cancelled: true, ...}` result with localized status messages. +- **🌐 Localized Confirmation Strings**: All new confirmation titles, messages, and cancellation statuses are translated across the 12 supported locales. > [!TIP] > **💡 Looking to batch install global plugins (Actions, Filters, Pipes, Tools)?** diff --git a/docs/plugins/tools/openwebui-skills-manager.zh.md b/docs/plugins/tools/openwebui-skills-manager.zh.md index 366266a..44acc35 100644 --- a/docs/plugins/tools/openwebui-skills-manager.zh.md +++ b/docs/plugins/tools/openwebui-skills-manager.zh.md @@ -1,6 +1,6 @@ # 🧰 OpenWebUI Skills 管理工具 -| 作者:[Fu-Jie](https://github.com/Fu-Jie) · v0.3.1 | [⭐ 点个 Star 支持项目](https://github.com/Fu-Jie/openwebui-extensions) | +| 作者:[Fu-Jie](https://github.com/Fu-Jie) · v0.3.3 | [⭐ 点个 Star 支持项目](https://github.com/Fu-Jie/openwebui-extensions) | | :--- | ---: | | ![followers](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_followers.json&label=%F0%9F%91%A5&style=flat) | ![points](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_points.json&label=%E2%AD%90&style=flat) | ![top](https://img.shields.io/badge/%F0%9F%8F%86-Top%20%3C1%25-10b981?style=flat) | ![contributions](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_contributions.json&label=%F0%9F%93%A6&style=flat) | ![downloads](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_downloads.json&label=%E2%AC%87%EF%B8%8F&style=flat) | ![saves](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_saves.json&label=%F0%9F%92%BE&style=flat) | ![views](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_views.json&label=%F0%9F%91%81%EF%B8%8F&style=flat) | @@ -23,9 +23,8 @@ ## 最新更新 -- **📝 支持多行 Frontmatter 描述**:`install_skill` 现在可以正确解析远程 `SKILL.md` 里的 `description: >` 和 `description: |`,导入后的技能描述不再被截断成单行。 -- **↩️ 更稳的元数据回退**:当 frontmatter 只有 `title` 没有 `name` 时,安装器会优先使用 `title`,避免退回到通用目录名。 -- **🧪 回归测试补齐**:新增 folded/literal YAML 块和 CRLF 换行场景测试,保证外部技能导入行为稳定。 +- **🛡️ 破坏性操作确认**:新增 `REQUIRE_CONFIRMATION` 阀门(默认 `True`),在执行 `update_skill`、`delete_skill` 以及 `create_skill`/`install_skill` 触发覆盖前通过 `__event_call__` 弹出用户确认。取消时返回结构化的 `{cancelled: true, ...}` 结果,并发出本地化的状态消息。 +- **🌐 本地化确认文案**:所有新增的确认标题、提示信息和取消状态文案均已翻译至支持的 12 种语言。 > [!TIP] > **💡 想要批量安装/管理全局插件 (Actions, Filters, Pipes, Tools)?** diff --git a/plugins/tools/openwebui-skills-manager/README.md b/plugins/tools/openwebui-skills-manager/README.md index bfb3d31..4548a43 100644 --- a/plugins/tools/openwebui-skills-manager/README.md +++ b/plugins/tools/openwebui-skills-manager/README.md @@ -1,6 +1,6 @@ # 🧰 OpenWebUI Skills Manager Tool -| By [Fu-Jie](https://github.com/Fu-Jie) · v0.3.2 | [⭐ Star this repo](https://github.com/Fu-Jie/openwebui-extensions) | +| By [Fu-Jie](https://github.com/Fu-Jie) · v0.3.3 | [⭐ Star this repo](https://github.com/Fu-Jie/openwebui-extensions) | | :--- | ---: | | ![followers](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_followers.json&label=%F0%9F%91%A5&style=flat) | ![points](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_points.json&label=%E2%AD%90&style=flat) | ![top](https://img.shields.io/badge/%F0%9F%8F%86-Top%20%3C1%25-10b981?style=flat) | ![contributions](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_contributions.json&label=%F0%9F%93%A6&style=flat) | ![downloads](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_downloads.json&label=%E2%AC%87%EF%B8%8F&style=flat) | ![saves](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_saves.json&label=%F0%9F%92%BE&style=flat) | ![views](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_views.json&label=%F0%9F%91%81%EF%B8%8F&style=flat) | @@ -23,9 +23,8 @@ When the selection dialog opens, search for this plugin, check it, and continue. ## What's New -- **⚡ OpenWebUI 0.9.x Compatibility**: Added runtime async detection and compatibility layer for OpenWebUI 0.9.x+ asynchronous database models (Skills), with graceful sync fallback for older versions. -- **📝 Multi-line Frontmatter Descriptions**: `install_skill` now correctly parses `description: >` and `description: |` blocks in remote `SKILL.md` files, so imported skill descriptions no longer truncate to a single line. -- **↩️ Better Metadata Fallbacks**: If a skill frontmatter provides `title` without `name`, the installer now uses that title before falling back to directory-based names. +- **🛡️ Confirmation Before Destructive Actions**: New `REQUIRE_CONFIRMATION` valve (default `True`) prompts the user via `__event_call__` before `update_skill`, `delete_skill`, and overwrite paths in `create_skill`/`install_skill`. Cancellations return a structured `{cancelled: true, ...}` result with localized status messages. +- **🌐 Localized Confirmation Strings**: All new confirmation titles, messages, and cancellation statuses are translated across the 12 supported locales. > [!TIP] > **💡 Looking to batch install global plugins (Actions, Filters, Pipes, Tools)?** diff --git a/plugins/tools/openwebui-skills-manager/README_CN.md b/plugins/tools/openwebui-skills-manager/README_CN.md index 4800519..a14c067 100644 --- a/plugins/tools/openwebui-skills-manager/README_CN.md +++ b/plugins/tools/openwebui-skills-manager/README_CN.md @@ -1,6 +1,6 @@ # 🧰 OpenWebUI Skills 管理工具 -| 作者:[Fu-Jie](https://github.com/Fu-Jie) · v0.3.2 | [⭐ 点个 Star 支持项目](https://github.com/Fu-Jie/openwebui-extensions) | +| 作者:[Fu-Jie](https://github.com/Fu-Jie) · v0.3.3 | [⭐ 点个 Star 支持项目](https://github.com/Fu-Jie/openwebui-extensions) | | :--- | ---: | | ![followers](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_followers.json&label=%F0%9F%91%A5&style=flat) | ![points](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_points.json&label=%E2%AD%90&style=flat) | ![top](https://img.shields.io/badge/%F0%9F%8F%86-Top%20%3C1%25-10b981?style=flat) | ![contributions](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_contributions.json&label=%F0%9F%93%A6&style=flat) | ![downloads](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_downloads.json&label=%E2%AC%87%EF%B8%8F&style=flat) | ![saves](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_saves.json&label=%F0%9F%92%BE&style=flat) | ![views](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_views.json&label=%F0%9F%91%81%EF%B8%8F&style=flat) | @@ -23,9 +23,8 @@ ## 最新更新 -- **⚡ OpenWebUI 0.9.x 兼容性**:新增运行时异步检测和兼容性适配层,支持 OpenWebUI 0.9.x 及以上版本的异步数据库模型(Skills),同时完美回退支持旧版本的同步调用。 -- **📝 支持多行 Frontmatter 描述**:`install_skill` 现在可以正确解析远程 `SKILL.md` 里的 `description: >` 和 `description: |`,导入后的技能描述不再被截断成单行。 -- **↩️ 更稳的元数据回退**:当 frontmatter 只有 `title` 没有 `name` 时,安装器会优先使用 `title`,避免退回到通用目录名。 +- **🛡️ 破坏性操作确认**:新增 `REQUIRE_CONFIRMATION` 阀门(默认 `True`),在执行 `update_skill`、`delete_skill` 以及 `create_skill`/`install_skill` 触发覆盖前通过 `__event_call__` 弹出用户确认。取消时返回结构化的 `{cancelled: true, ...}` 结果,并发出本地化的状态消息。 +- **🌐 本地化确认文案**:所有新增的确认标题、提示信息和取消状态文案均已翻译至支持的 12 种语言。 > [!TIP] > **💡 想要批量安装/管理全局插件 (Actions, Filters, Pipes, Tools)?** @@ -279,6 +278,7 @@ description: "做一些有用的事" | 参数 | 默认值 | 说明 | | --- | --- | --- | | `SHOW_STATUS` | `True` | 是否在 OpenWebUI 状态栏显示操作状态。 | +| `REQUIRE_CONFIRMATION` | `True` | 在执行破坏性操作(`update_skill`、`delete_skill`,以及 `create_skill`/`install_skill` 触发覆盖)前要求用户进行一次是/否确认。关闭后,这些操作将不再弹出提示直接执行。 | | `ALLOW_OVERWRITE_ON_CREATE` | `False` | 是否允许 `create_skill`/`install_skill` 默认覆盖同名技能。 | | `INSTALL_FETCH_TIMEOUT` | `12.0` | 从 URL 安装技能时的请求超时时间(秒)。 | | `TRUSTED_DOMAINS` | `github.com,huggingface.co,githubusercontent.com` | 逗号分隔的主信任域名清单(**必须启用**)。子域名会自动放行(如 `github.com` 允许 `api.github.com`)。详见 [域名白名单指南](https://github.com/Fu-Jie/openwebui-extensions/blob/main/plugins/tools/openwebui-skills-manager/docs/DOMAIN_WHITELIST.md)。 | diff --git a/plugins/tools/openwebui-skills-manager/openwebui_skills_manager.py b/plugins/tools/openwebui-skills-manager/openwebui_skills_manager.py index 500a7c6..bee0599 100644 --- a/plugins/tools/openwebui-skills-manager/openwebui_skills_manager.py +++ b/plugins/tools/openwebui-skills-manager/openwebui_skills_manager.py @@ -794,11 +794,12 @@ async def _request_confirmation( if not event_call: return None try: - result = await event_call( + result = await _call_openwebui_compat( + event_call, { "type": "confirmation", "data": {"title": title, "message": message}, - } + }, ) except Exception as e: logger.warning(f"Confirmation prompt failed: {e}") diff --git a/plugins/tools/openwebui-skills-manager/v0.3.3.md b/plugins/tools/openwebui-skills-manager/v0.3.3.md new file mode 100644 index 0000000..5e826f0 --- /dev/null +++ b/plugins/tools/openwebui-skills-manager/v0.3.3.md @@ -0,0 +1,20 @@ +# OpenWebUI Skills Manager v0.3.3 Release Notes + +This release adds an opt-in confirmation flow for destructive operations and translates all new prompts across the 12 supported locales. It also routes the confirmation event call through the existing OpenWebUI sync/async compatibility wrapper for consistency with the rest of the tool. + +### New Features +- New `REQUIRE_CONFIRMATION` valve (default `True`) prompts the user via `__event_call__` before `update_skill`, `delete_skill`, and overwrite paths in `create_skill` / `install_skill`. +- Cancellations short-circuit cleanly and return a structured `{cancelled: true, action, id, name, message, ...}` result, plus a localized status update so the assistant can report the outcome. +- When no interactive event channel is available, the tool surfaces a localized error pointing operators to the new valve instead of silently proceeding. + +### Bug Fixes +- N/A — this release is feature-only. + +### Enhancements +- Added confirmation/cancellation translations (title, message, status, error, "no description" placeholder) for all 12 supported locales. +- Documented the new valve in both `README.md` and `README_CN.md` valves tables. +- `_request_confirmation` routes through `_call_openwebui_compat` for consistency with the rest of the OpenWebUI integration surface. + +### Migration Notes +- Default behavior changes: existing flows that call `update_skill`, `delete_skill`, or trigger overwrite in `create_skill` / `install_skill` will now show a confirmation prompt by default. Set `REQUIRE_CONFIRMATION` to `False` to restore the previous "execute immediately" behavior. +- No Valve key was renamed or removed. diff --git a/plugins/tools/openwebui-skills-manager/v0.3.3_CN.md b/plugins/tools/openwebui-skills-manager/v0.3.3_CN.md new file mode 100644 index 0000000..eae7637 --- /dev/null +++ b/plugins/tools/openwebui-skills-manager/v0.3.3_CN.md @@ -0,0 +1,20 @@ +# OpenWebUI Skills Manager v0.3.3 版本发布说明 + +本次发布为破坏性操作引入了可选的确认流程,并将所有新增提示翻译至 12 种支持的语言。同时将确认事件调用接入既有的 OpenWebUI 同步/异步兼容封装,保持与工具其余部分的一致性。 + +### 新功能 +- 新增 `REQUIRE_CONFIRMATION` 阀门(默认 `True`),在执行 `update_skill`、`delete_skill` 以及 `create_skill` / `install_skill` 触发覆盖前通过 `__event_call__` 向用户弹出确认。 +- 用户取消时操作立即中断,返回结构化的 `{cancelled: true, action, id, name, message, ...}` 结果,并附带本地化状态信息,便于助手向用户汇报。 +- 当上下文不存在交互式事件通道时,工具会抛出本地化错误提示并指引运维人员关闭该阀门,而不是悄无声息地继续执行。 + +### 问题修复 +- 无 —— 本次为纯功能版本。 + +### 优化提升 +- 新增确认/取消相关翻译(标题、提示、状态、错误、“无描述”占位符)覆盖所有 12 种支持语言。 +- 在 `README.md` 与 `README_CN.md` 的阀门表中补充了对新阀门的说明。 +- `_request_confirmation` 通过 `_call_openwebui_compat` 调度事件回调,与 OpenWebUI 集成层其余部分保持一致。 + +### 迁移说明 +- 默认行为变化:现有调用 `update_skill`、`delete_skill` 或在 `create_skill` / `install_skill` 触发覆盖的流程,将默认弹出确认对话框。如需恢复“直接执行”的旧行为,请将 `REQUIRE_CONFIRMATION` 设为 `False`。 +- 没有重命名或移除任何 Valve 键。 From 140b86512f1b4ede78cc19d3ab4accd6beb57e1e Mon Sep 17 00:00:00 2001 From: fujie Date: Wed, 20 May 2026 06:24:47 +0800 Subject: [PATCH 3/3] fix(skills-manager): strict bool check in _request_confirmation to prevent bypass on channel error When __event_call__ returns a non-bool truthy value (e.g. an error dict on session disconnect), bool(result) was True, which bypassed REQUIRE_CONFIRMATION and continued executing destructive operations (update, delete, overwrite). Replace bool(result) with an isinstance(result, bool) check so that only an explicit True/False from the confirmation dialog is trusted; any other return is treated as unavailable (returns None) and the caller blocks the action. --- .../openwebui-skills-manager/openwebui_skills_manager.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/tools/openwebui-skills-manager/openwebui_skills_manager.py b/plugins/tools/openwebui-skills-manager/openwebui_skills_manager.py index bee0599..2f49f3a 100644 --- a/plugins/tools/openwebui-skills-manager/openwebui_skills_manager.py +++ b/plugins/tools/openwebui-skills-manager/openwebui_skills_manager.py @@ -804,7 +804,12 @@ async def _request_confirmation( except Exception as e: logger.warning(f"Confirmation prompt failed: {e}") return None - return bool(result) + # Only trust an explicit bool True/False from the event channel. + # Any other truthy value (e.g. an error dict returned on channel disconnect) + # must be treated as unavailable so callers can block the destructive action. + if isinstance(result, bool): + return result + return None def _format_description_for_prompt(description: Any, lang: str, max_len: int = 200) -> str: