Added slash command handling

This commit is contained in:
ARIA committed 2026-08-21 10:18:48 +02:00
1 parent 10e9565e2e
commit 1bcadcf950
16 files changed
+567 -21

No files matched your search

+72
View File
@@ -126,6 +126,66 @@ from .pairing import ( # noqa: E402
from .ws_server import WsServer # noqa: E402
# ---------------------------------------------------------------------------
# Slash-command catalog (the app's "/" drawer)
#
# Derived from hermes' central ``COMMAND_REGISTRY`` (``hermes_cli/commands.py``)
# — the same source the gateway help text and the Telegram command menu use —
# restricted to commands available on gateway surfaces, plus plugin-registered
# commands. Never raises: any import/attribute problem (code skew between the
# plugin and the hermes checkout) degrades to an empty catalog, so the app's
# drawer simply stays closed.
# ---------------------------------------------------------------------------
def _slash_command_catalog() -> List[Dict[str, Any]]:
try:
from hermes_cli import commands as hermes_commands
except Exception:
logger.warning(
"android: slash catalog unavailable (hermes_cli.commands import failed)",
exc_info=True,
)
return []
def _entry(name: str, description: str, args_hint: str, category: str,
aliases: List[str]) -> Dict[str, Any]:
return {
"name": f"/{name}",
"description": description,
"args_hint": args_hint or "",
"category": category,
"aliases": [f"/{a}" for a in aliases],
}
entries: List[Dict[str, Any]] = []
try:
overrides = hermes_commands._resolve_config_gates()
for cmd in hermes_commands.COMMAND_REGISTRY:
if not hermes_commands._is_gateway_available(cmd, overrides):
continue
entries.append(
_entry(cmd.name, cmd.description, cmd.args_hint, cmd.category,
list(cmd.aliases))
)
except Exception:
# Code skew: the private helpers moved. Fall back to the plain
# cli_only filter (config-gated commands are dropped, acceptable).
logger.warning("android: slash catalog fell back to cli_only filter",
exc_info=True)
entries = [
_entry(cmd.name, cmd.description, cmd.args_hint, cmd.category,
list(cmd.aliases))
for cmd in hermes_commands.COMMAND_REGISTRY
if not cmd.cli_only
]
try:
for name, description, args_hint in hermes_commands._iter_plugin_command_entries():
entries.append(_entry(name, description, args_hint, "Plugin", []))
except Exception:
pass
return entries
# ---------------------------------------------------------------------------
# M2 — reasoning capture (streaming)
#
@@ -2244,6 +2304,17 @@ class AndroidAdapter(BasePlatformAdapter):
resp.id = frame.id
await self._ws_server.send_to(device_id, resp)
# ── Slash-command catalog (app's "/" drawer) ──────────────────────────
async def on_commands_catalog(self, frame: protocol.Frame, device_id: str) -> None:
"""Handle an inbound ``commands.catalog`` request: reply with the
gateway's slash-command catalog (hermes ``COMMAND_REGISTRY``,
gateway-available subset + plugin commands). The app fuzzy-matches
the typed prefix client-side; the catalog is static per gateway run,
so no caching is needed here."""
resp = protocol.commands_catalog(_slash_command_catalog(), id=frame.id)
await self._ws_server.send_to(device_id, resp)
# ── M3: search (app -> agent) ─────────────────────────────────────────
async def on_search(self, frame: protocol.Frame, device_id: str) -> None:
@@ -2562,6 +2633,7 @@ class AndroidAdapter(BasePlatformAdapter):
"tools": True, # M2: tool.start/progress/end
"media": True, # M4: media.upload/offer/pull
"search": True, # M3: search frame
"commands_catalog": True, # commands.catalog frame (the "/" drawer)
"push": self.push_backend,
# M5: ntfy server URL (app listener discovery; "" when not ntfy).
"push_ntfy_server": (