Add optional Nanobot plugin controls (#4396)
* feat: add optional nanobot features * test: update azure install hint expectation * fix: validate optional feature extras maintainer edit: verify requested dependency extras before treating optional features as installed, propagate restart state from feature enablement, and align docs with the new plugins enable command. * fix: bound optional feature installs maintainer edit: make optional feature installs time out as a normal install failure instead of leaving the WebUI or CLI action waiting indefinitely. * feat: slim optional channel dependencies * fix: log optional install commands * fix(webui): gate remote feature installs * docs: clarify webhook plugin example * fix(webui): harden optional feature installs * fix: install optional deps without package fallback * fix(cli): refine plugin feature controls * fix(webui): count enabled nanobot features * fix(webui): allow slow feature install routes * fix(webui): allow disabling websocket channel * fix(plugins): simplify optional feature controls * fix(webui): polish apps catalog states * fix(webui): confirm nanobot support installs * fix(webui): polish nanobot install dialog * fix(webui): suppress empty websocket handshakes * fix(webui): clarify apps plugin summary * fix(webui): localize workspace access copy * fix(plugins): polish optional feature controls (#4691) --------- Co-authored-by: Xubin Ren <52506698+Re-bin@users.noreply.github.com>
This commit is contained in:
@@ -11,6 +11,7 @@ if TYPE_CHECKING:
|
||||
from nanobot.channels.base import BaseChannel
|
||||
|
||||
_INTERNAL = frozenset({"base", "manager", "registry"})
|
||||
DEFAULT_ENABLED_CHANNELS = frozenset({"websocket"})
|
||||
|
||||
|
||||
def discover_channel_names() -> list[str]:
|
||||
@@ -57,6 +58,7 @@ def discover_enabled(
|
||||
*,
|
||||
_names: list[str] | None = None,
|
||||
_include_all_external: bool = False,
|
||||
warn_import_errors: bool = False,
|
||||
) -> dict[str, type[BaseChannel]]:
|
||||
"""Return channels whose module names are in *enabled_names*.
|
||||
|
||||
@@ -72,10 +74,14 @@ def discover_enabled(
|
||||
try:
|
||||
result[modname] = load_channel_class(modname)
|
||||
except ImportError as e:
|
||||
logger.debug("Skipping built-in channel '{}': {}", modname, e)
|
||||
message = "Enabled built-in channel '{}' is not available: {}"
|
||||
if warn_import_errors:
|
||||
logger.warning(message, modname, e)
|
||||
else:
|
||||
logger.debug(message, modname, e)
|
||||
|
||||
external = discover_plugins(None if _include_all_external else enabled_names)
|
||||
shadowed = set(external) & set(result)
|
||||
shadowed = set(external) & set(names)
|
||||
if shadowed:
|
||||
logger.warning("Plugin(s) shadowed by built-in channels (ignored): {}", shadowed)
|
||||
if _include_all_external:
|
||||
|
||||
Reference in New Issue
Block a user