Convert to pip package

- Moved __init__.py and plugin.yaml into hermes_piper_plugin/ package directory
- Added pyproject.toml with build config and entry point registration
- Updated tests to reference new subdirectory paths
- Updated README with pip-based installation instructions

This converts the plugin from a flat layout (loaded via hermes plugins install)
to a proper pip package with the 'hermes_agent.plugins' entry point.
This commit is contained in:
2026-06-17 12:11:37 -04:00
parent c44e65e381
commit cfe9e9c4b9
5 changed files with 35 additions and 12 deletions

View File

@@ -24,19 +24,24 @@ import is safe. The plugin also logs the effective default at session start.
## Installation ## Installation
```bash ```bash
# 1. Ensure piper-tts is installed # Install from the internal Hermes package registry
pip install piper-tts pip install hermes-piper-plugin
# 2. Install the plugin from the internal Hermes repo # Or install in editable mode for development
hermes plugins install ssh://git@code.lazyworkhorse.net:2222/Hermes/hermes-piper-plugin.git git clone https://code.lazyworkhorse.net/gortium/hermes-piper-plugin.git
cd hermes-piper-plugin
# 3. Restart gateways to load the plugin pip install -e .
``` ```
> **Note:** The plugin used to be installed via `hermes plugins install` from the
> old flat layout. It is now a proper pip package. The entry point
> `hermes_agent.plugins` is registered automatically when you install the
> package — Hermes discovers it on next startup.
## Testing ## Testing
```bash ```bash
cd /opt/data/projects/hermes-piper-plugin cd /path/to/hermes-piper-plugin
pip install pytest pyyaml pip install pytest pyyaml
python -m pytest tests/ -v python -m pytest tests/ -v
``` ```

18
pyproject.toml Normal file
View File

@@ -0,0 +1,18 @@
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"
[project]
name = "hermes-piper-plugin"
version = "1.0.0"
description = "Piper TTS plugin for Hermes Agent"
authors = [{name = "@gortium"}]
license = {text = "MIT"}
requires-python = ">=3.11"
dependencies = []
[project.entry-points.'hermes_agent.plugins']
piper = "hermes_piper_plugin:register"
[tool.setuptools.packages.find]
include = ["hermes_piper_plugin*", "tests*"]

View File

@@ -62,7 +62,7 @@ def _clean_tools_tts():
def _load_plugin_module(name: str) -> types.ModuleType: def _load_plugin_module(name: str) -> types.ModuleType:
"""Load the plugin __init__.py as a fresh module with given name.""" """Load the plugin __init__.py as a fresh module with given name."""
source = Path(__file__).resolve().parent.parent / "__init__.py" source = Path(__file__).resolve().parent.parent / "hermes_piper_plugin" / "__init__.py"
assert source.exists(), f"Plugin init not found at {source}" assert source.exists(), f"Plugin init not found at {source}"
spec = importlib.util.spec_from_file_location(name, str(source)) spec = importlib.util.spec_from_file_location(name, str(source))
mod = importlib.util.module_from_spec(spec) mod = importlib.util.module_from_spec(spec)
@@ -85,7 +85,7 @@ def plugin_dir() -> Path:
@pytest.fixture @pytest.fixture
def manifest(plugin_dir: Path) -> dict: def manifest(plugin_dir: Path) -> dict:
manifest_path = plugin_dir / "plugin.yaml" manifest_path = plugin_dir / "hermes_piper_plugin" / "plugin.yaml"
assert manifest_path.exists(), f"plugin.yaml not found at {manifest_path}" assert manifest_path.exists(), f"plugin.yaml not found at {manifest_path}"
with open(manifest_path) as f: with open(manifest_path) as f:
return yaml.safe_load(f) return yaml.safe_load(f)
@@ -274,14 +274,14 @@ class TestPluginStructure:
def test_required_files_exist(self, plugin_dir): def test_required_files_exist(self, plugin_dir):
"""Plugin must have plugin.yaml, __init__.py, and README.md.""" """Plugin must have plugin.yaml, __init__.py, and README.md."""
assert (plugin_dir / "plugin.yaml").exists(), "Missing plugin.yaml" assert (plugin_dir / "hermes_piper_plugin" / "plugin.yaml").exists(), "Missing plugin.yaml"
assert (plugin_dir / "__init__.py").exists(), "Missing __init__.py" assert (plugin_dir / "hermes_piper_plugin" / "__init__.py").exists(), "Missing __init__.py"
assert (plugin_dir / "README.md").exists(), "Missing README.md" assert (plugin_dir / "README.md").exists(), "Missing README.md"
def test_init_has_register_function(self, plugin_dir): def test_init_has_register_function(self, plugin_dir):
"""__init__.py must expose a register() function.""" """__init__.py must expose a register() function."""
spec = importlib.util.spec_from_file_location( spec = importlib.util.spec_from_file_location(
"test_register_check", str(plugin_dir / "__init__.py") "test_register_check", str(plugin_dir / "hermes_piper_plugin" / "__init__.py")
) )
mod = importlib.util.module_from_spec(spec) mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod) spec.loader.exec_module(mod)