updating and refining plugin system refactor

This commit is contained in:
2026-04-28 22:20:54 -07:00
parent 8685fbb723
commit 323c24f4f4
33 changed files with 4287 additions and 3312 deletions
+28 -28
View File
@@ -22,10 +22,10 @@ from SYS.config import (
from SYS.database import db
from SYS.logger import log, debug
from SYS.plugin_config import (
build_default_provider_config,
build_default_plugin_config,
build_default_store_config,
build_default_tool_config,
get_configurable_provider_types,
get_configurable_plugin_types,
get_configurable_store_types,
get_configurable_tool_types,
get_global_schema,
@@ -161,7 +161,7 @@ class ConfigModal(ModalScreen):
# Load config from the workspace root (parent of SYS)
self.config_data = load_config()
self.current_category = "globals"
self.editing_item_type = None # 'store' or 'provider'
self.editing_item_type = None # 'store' or 'plugin'
self.editing_item_name = None
self._button_id_map = {}
self._provider_button_map: Dict[str, tuple[str, str]] = {}
@@ -598,14 +598,14 @@ class ConfigModal(ModalScreen):
row.mount(Button("Paste", id=f"paste-{inp_id}", classes="paste-btn"))
idx += 1
if item_type == "provider" and isinstance(item_name, str):
provider = self._instantiate_provider_for_editor(item_name, self.config_data)
if item_type == "plugin" and isinstance(item_name, str):
provider = self._instantiate_plugin_for_editor(item_name, self.config_data)
if provider is not None:
provider_actions = provider.config_actions() or []
if provider_actions:
container.mount(Rule())
container.mount(Label(f"{provider.label} helpers", classes="config-label"))
helper_text = str(provider.config_helper_text() or "Use these helpers to validate provider settings.").strip()
helper_text = str(provider.config_helper_text() or "Use these helpers to validate plugin settings.").strip()
status = Static(helper_text, id="provider-status")
container.mount(status)
self._provider_status = status
@@ -626,7 +626,7 @@ class ConfigModal(ModalScreen):
)
if (
item_type == "provider"
item_type == "plugin"
and isinstance(item_name, str)
and item_name.strip().lower() == "matrix"
):
@@ -870,12 +870,12 @@ class ConfigModal(ModalScreen):
self.refresh_view()
elif bid in self._provider_button_map:
provider_name, action_id = self._provider_button_map[bid]
self._request_provider_action(provider_name, action_id)
self._request_plugin_action(provider_name, action_id)
elif bid == "add-store-btn":
options = get_configurable_store_types()
self.app.push_screen(SelectionModal("Select Store Type", options), callback=self.on_store_type_selected)
elif bid == "add-provider-btn":
options = get_configurable_provider_types()
options = get_configurable_plugin_types()
self.app.push_screen(SelectionModal("Select Plugin Type", options), callback=self.on_provider_type_selected)
elif bid == "add-tool-btn":
options = get_configurable_tool_types() or ["ytdlp"]
@@ -971,46 +971,46 @@ class ConfigModal(ModalScreen):
else:
self.notify("Clipboard not supported in this terminal", severity="warning")
def _instantiate_provider_for_editor(self, provider_name: str, config_data: Optional[Dict[str, Any]] = None) -> Optional[Any]:
def _instantiate_plugin_for_editor(self, provider_name: str, config_data: Optional[Dict[str, Any]] = None) -> Optional[Any]:
try:
provider_class = get_plugin_class(provider_name)
plugin_class = get_plugin_class(provider_name)
except Exception:
provider_class = None
if provider_class is None:
plugin_class = None
if plugin_class is None:
return None
try:
return provider_class(config_data or self.config_data)
return plugin_class(config_data or self.config_data)
except Exception:
logger.exception("Failed to instantiate provider '%s' for config helper", provider_name)
logger.exception("Failed to instantiate plugin '%s' for config helper", provider_name)
return None
def _request_provider_action(self, provider_name: str, action_id: str) -> None:
def _request_plugin_action(self, provider_name: str, action_id: str) -> None:
if self._provider_action_running:
return
self._synchronize_inputs_to_config()
self._provider_action_running = True
if self._provider_status is not None:
self._provider_status.update(f"Running {action_id.replace('_', ' ')}")
self._provider_action_background(provider_name, action_id, deepcopy(self.config_data))
self._plugin_action_background(provider_name, action_id, deepcopy(self.config_data))
@work(thread=True)
def _provider_action_background(self, provider_name: str, action_id: str, config_snapshot: Dict[str, Any]) -> None:
def _plugin_action_background(self, provider_name: str, action_id: str, config_snapshot: Dict[str, Any]) -> None:
try:
provider = self._instantiate_provider_for_editor(provider_name, config_snapshot)
provider = self._instantiate_plugin_for_editor(provider_name, config_snapshot)
if provider is None:
raise RuntimeError(f"Provider '{provider_name}' is unavailable")
raise RuntimeError(f"Plugin '{provider_name}' is unavailable")
result = provider.run_config_action(action_id)
if not isinstance(result, dict):
result = {"ok": False, "message": f"Provider '{provider_name}' returned an invalid config action result."}
result = {"ok": False, "message": f"Plugin '{provider_name}' returned an invalid config action result."}
except Exception as exc:
result = {"ok": False, "message": str(exc) or f"Provider action '{action_id}' failed."}
result = {"ok": False, "message": str(exc) or f"Plugin action '{action_id}' failed."}
try:
self.app.call_from_thread(self._provider_action_complete, provider_name, action_id, result)
self.app.call_from_thread(self._plugin_action_complete, provider_name, action_id, result)
except Exception:
self._provider_action_complete(provider_name, action_id, result)
self._plugin_action_complete(provider_name, action_id, result)
def _provider_action_complete(self, provider_name: str, action_id: str, result: Dict[str, Any]) -> None:
def _plugin_action_complete(self, provider_name: str, action_id: str, result: Dict[str, Any]) -> None:
self._provider_action_running = False
ok = bool(result.get("ok"))
message = str(result.get("message") or f"Provider action '{action_id}' finished.")
@@ -1075,11 +1075,11 @@ class ConfigModal(ModalScreen):
if "provider" not in self.config_data:
self.config_data["provider"] = {}
# For providers, they are usually top-level entries in 'provider' dict
# Plugins are configured under the top-level 'provider' dict for now.
if ptype not in self.config_data["provider"]:
self.config_data["provider"][ptype] = build_default_provider_config(ptype)
self.config_data["provider"][ptype] = build_default_plugin_config(ptype)
self.editing_item_type = "provider"
self.editing_item_type = "plugin"
self.editing_item_name = ptype
self.refresh_view()
+3 -3
View File
@@ -16,7 +16,7 @@ import asyncio
sys.path.insert(0, str(Path(__file__).parent.parent))
from SYS.config import load_config, resolve_output_dir
from SYS.result_table import Table
from ProviderCore.registry import get_search_plugin
from ProviderCore.registry import get_plugin_with_capability
logger = logging.getLogger(__name__)
@@ -174,7 +174,7 @@ class SearchModal(ModalScreen):
self.current_worker.log_step(f"Connecting to {source}...")
try:
provider = get_search_plugin(source)
provider = get_plugin_with_capability(source, "search")
if not provider:
logger.error(f"[search-modal] Provider not available: {source}")
if self.current_worker:
@@ -380,7 +380,7 @@ class SearchModal(ModalScreen):
config = load_config()
output_dir = resolve_output_dir(config)
provider = get_search_plugin("openlibrary", config=config)
provider = get_plugin_with_capability("openlibrary", "search", config=config)
if not provider:
logger.error("[search-modal] Provider not available: openlibrary")
return