"""Pheby — Hermes Agent platform adapter/plugin for the Pheby Android client. A third-party Hermes platform plugin. Install this package directory as ``~/.hermes/plugins/pheby/`` (HERMES_HOME/plugins/pheby), enable it in config.yaml (``plugins.enabled: [pheby]``, ``platforms.pheby.enabled: true``), set ``PHEBY_SECRET`` in ``~/.hermes/.env``, and restart the gateway. """ from __future__ import annotations import logging from typing import Any logger = logging.getLogger(__name__) __version__ = "1.0.1" def register(ctx: Any) -> None: """Plugin entry point — called by the Hermes plugin system at startup.""" from .adapter import PhebyAdapter from .config import ( check_requirements, env_enablement, is_connected, validate_config, ) adapter_holder: dict = {"adapter": None} def _factory(cfg: Any) -> PhebyAdapter: adapter = PhebyAdapter(cfg) adapter_holder["adapter"] = adapter return adapter ctx.register_platform( name="pheby", label="Pheby", adapter_factory=_factory, check_fn=check_requirements, validate_config=validate_config, is_connected=is_connected, required_env=["PHEBY_SECRET"], install_hint="pip install aiohttp # already a Hermes dependency; " "set PHEBY_SECRET in ~/.hermes/.env", env_enablement_fn=env_enablement, # Home channel for cron / notification delivery when configured. cron_deliver_env_var="PHEBY_HOME_CHANNEL", emoji="🐱", pii_safe=True, # single-user private platform; no PII in routing IDs allow_update_command=True, platform_hint=( "You are communicating with the user via Pheby, a private " "native Android client over WebSocket. Respond in normal " "markdown; the client renders it natively. Attachments you " "produce via MEDIA: tags are delivered as downloadable files " "and inline image previews." ), ) # Tool observers provide authoritative session_id + tool_call_id values. # The adapter's presentation-only format_tool_event hook deliberately eats # Hermes's generic tool chrome to avoid duplicate/ambiguous events. def _pre_tool_call(**kwargs: Any) -> None: adapter = adapter_holder.get("adapter") if adapter is not None: adapter.on_pre_tool_call(**kwargs) def _post_tool_call(**kwargs: Any) -> None: adapter = adapter_holder.get("adapter") if adapter is not None: adapter.on_post_tool_call(**kwargs) try: ctx.register_hook("pre_tool_call", _pre_tool_call) ctx.register_hook("post_tool_call", _post_tool_call) except Exception: logger.debug("[pheby] post_tool_call hook registration failed", exc_info=True) logger.info("[pheby] plugin registered (platform 'pheby')") __all__ = ["register", "__version__"]