from abc import ABC, abstractmethod from typing import Any from pydantic import BaseModel, Field from .logger import belief_scope # #region PluginBase [TYPE Class] [SEMANTICS plugin, interface, base, abstract] # @BRIEF Defines the abstract base class that all plugins must implement to be recognized by the system. It enforces a common structure for plugin metadata and execution. # @LAYER Core # @PURPOSE PluginLoader scans for subclasses of PluginBase. # @INVARIANT All plugins MUST inherit from this class. class PluginBase(ABC): """ Base class for all plugins. Plugins must inherit from this class and implement the abstract methods. """ @property @abstractmethod # #region id [TYPE Function] # @PURPOSE: Returns the unique identifier for the plugin. # @PRE Plugin instance exists. # @POST Returns string ID. # @RETURN str - Plugin ID. def id(self) -> str: """A unique identifier for the plugin.""" with belief_scope("id"): pass # #endregion id @property @abstractmethod # #region name [TYPE Function] # @PURPOSE: Returns the human-readable name of the plugin. # @PRE Plugin instance exists. # @POST Returns string name. # @RETURN str - Plugin name. def name(self) -> str: """A human-readable name for the plugin.""" with belief_scope("name"): pass # #endregion name @property @abstractmethod # #region description [TYPE Function] # @PURPOSE: Returns a brief description of the plugin. # @PRE Plugin instance exists. # @POST Returns string description. # @RETURN str - Plugin description. def description(self) -> str: """A brief description of what the plugin does.""" with belief_scope("description"): pass # #endregion description @property @abstractmethod # #region version [TYPE Function] # @PURPOSE: Returns the version of the plugin. # @PRE Plugin instance exists. # @POST Returns string version. # @RETURN str - Plugin version. def version(self) -> str: """The version of the plugin.""" with belief_scope("version"): pass # #endregion version @property # #region required_permission [TYPE Function] # @PURPOSE: Returns the required permission string to execute this plugin. # @PRE Plugin instance exists. # @POST Returns string permission. # @RETURN str - Required permission (e.g., "plugin:backup:execute"). def required_permission(self) -> str: """The permission string required to execute this plugin.""" with belief_scope("required_permission"): return f"plugin:{self.id}:execute" # #endregion required_permission @property # #region ui_route [TYPE Function] # @PURPOSE: Returns the frontend route for the plugin's UI, if applicable. # @PRE Plugin instance exists. # @POST Returns string route or None. # @RETURN Optional[str] - Frontend route. def ui_route(self) -> str | None: """ The frontend route for the plugin's UI. Returns None if the plugin does not have a dedicated UI page. """ with belief_scope("ui_route"): return None # #endregion ui_route @abstractmethod # #region get_schema [TYPE Function] # @PURPOSE: Returns the JSON schema for the plugin's input parameters. # @PRE Plugin instance exists. # @POST Returns dict schema. # @RETURN Dict[str, Any] - JSON schema. def get_schema(self) -> dict[str, Any]: """ Returns the JSON schema for the plugin's input parameters. This schema will be used to generate the frontend form. """ with belief_scope("get_schema"): pass # #endregion get_schema @abstractmethod # #region execute [TYPE Function] # @PURPOSE: Executes the plugin's core logic. # @PARAM params (Dict[str, Any]) - Validated input parameters. # @PRE params must be a dictionary. # @POST Plugin execution is completed. async def execute(self, params: dict[str, Any]): with belief_scope("execute"): pass """ Executes the plugin's logic. The `params` argument will be validated against the schema returned by `get_schema()`. """ pass # #endregion execute # #endregion PluginBase # #region PluginConfig [TYPE Class] [SEMANTICS plugin, config, schema, pydantic] # @BRIEF A Pydantic model used to represent the validated configuration and metadata of a loaded plugin. This object is what gets exposed to the API layer. # @LAYER Core # @PURPOSE Validated PluginConfig exposed to API layer. class PluginConfig(BaseModel): """Pydantic model for plugin configuration.""" id: str = Field(..., description="Unique identifier for the plugin") name: str = Field(..., description="Human-readable name for the plugin") description: str = Field(..., description="Brief description of what the plugin does") version: str = Field(..., description="Version of the plugin") ui_route: str | None = Field(None, description="Frontend route for the plugin UI") input_schema: dict[str, Any] = Field(..., description="JSON schema for input parameters", alias="schema") # #endregion PluginConfig