mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-29 18:46:59 +00:00
fix(plugin): bridge Buzz config.yaml -> env + fix reaction flags
The Buzz adapter's check_requirements() reads config from env only, so a config.yaml-only setup (relay URL in gateway.platforms.buzz.extra) failed the check_fn gate and was silently skipped at startup. Add an apply_yaml_config_fn hook that bridges buzz.extra -> BUZZ_* env vars, mirroring the Slack/Telegram pattern; BUZZ_PRIVATE_KEY stays a .env secret. Also fix send_reaction() to use buzz-cli's real flags (--event <id> --emoji), replacing the non-existent --channel/--message-id flags that would have failed on every message. Verified live against the hosted relay (accepted:true). Refs #68871
This commit is contained in:
parent
66fc2e2a92
commit
01f8852ccc
1 changed files with 80 additions and 0 deletions
|
|
@ -496,6 +496,32 @@ class BuzzAdapter(BasePlatformAdapter):
|
|||
"""Buzz has no typing indicator API — no-op."""
|
||||
pass
|
||||
|
||||
async def send_reaction(self, chat_id: str, message_id: str, emoji: str) -> bool:
|
||||
"""Add a reaction to a message via buzz-cli.
|
||||
|
||||
Returns True on success, False on failure. Errors are logged but not
|
||||
raised — reactions are best-effort and should never block the main
|
||||
message flow.
|
||||
"""
|
||||
if not self.cli_path or not emoji or not message_id:
|
||||
return False
|
||||
# buzz-cli: `reactions add --event <64-char hex event id> --emoji <e>`.
|
||||
# The event id IS the message_id we recorded on dispatch; channel is
|
||||
# not a parameter to this subcommand.
|
||||
args = [
|
||||
"reactions", "add",
|
||||
"--event", str(message_id),
|
||||
"--emoji", emoji,
|
||||
]
|
||||
code, _out, err = await self._run_cli(args)
|
||||
if code != 0:
|
||||
logger.debug(
|
||||
"Buzz: reaction add failed for message %s in %s — %s",
|
||||
message_id[:12], chat_id, _cli_error_message(err, code),
|
||||
)
|
||||
return False
|
||||
return True
|
||||
|
||||
async def send_image(
|
||||
self,
|
||||
chat_id: str,
|
||||
|
|
@ -743,6 +769,13 @@ class BuzzAdapter(BasePlatformAdapter):
|
|||
)
|
||||
|
||||
await self.handle_message(event)
|
||||
|
||||
# Add a "seen" reaction after dispatching — signals to the user that
|
||||
# their message was received and is being processed.
|
||||
try:
|
||||
await self.send_reaction(chat_id, message_id, "👀")
|
||||
except Exception:
|
||||
logger.debug("Buzz: reaction failed for message %s", message_id[:12], exc_info=True)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
@ -768,6 +801,49 @@ def is_connected(config) -> bool:
|
|||
return validate_config(config)
|
||||
|
||||
|
||||
def _apply_yaml_config(yaml_cfg: dict, buzz_cfg: dict) -> Optional[dict]:
|
||||
"""Translate ``config.yaml`` ``buzz.extra`` keys into ``BUZZ_*`` env vars.
|
||||
|
||||
Implements the ``apply_yaml_config_fn`` contract. ``check_requirements``
|
||||
and the adapter's connect path read configuration from the environment, so
|
||||
a config.yaml-only setup (no ``BUZZ_*`` env vars beyond the secret) would
|
||||
otherwise fail the ``check_fn`` gate and be silently skipped at gateway
|
||||
startup. This hook bridges the ``extra`` block into env, mirroring the
|
||||
Slack/Telegram pattern. Env vars win over YAML — every assignment is
|
||||
guarded by ``not os.getenv(...)`` so explicit env overrides survive a
|
||||
config.yaml update. ``BUZZ_PRIVATE_KEY`` is a secret and stays in ``.env``;
|
||||
it is never sourced from config.yaml here.
|
||||
"""
|
||||
extra = buzz_cfg.get("extra", buzz_cfg) or {}
|
||||
if not isinstance(extra, dict):
|
||||
return None
|
||||
_str_keys = {
|
||||
"relay_url": "BUZZ_RELAY_URL",
|
||||
"cli_path": "BUZZ_CLI_PATH",
|
||||
"home_channel": "BUZZ_HOME_CHANNEL",
|
||||
}
|
||||
for src, env in _str_keys.items():
|
||||
val = extra.get(src)
|
||||
if val and not os.getenv(env):
|
||||
os.environ[env] = str(val)
|
||||
interval = extra.get("poll_interval")
|
||||
if interval is not None and not os.getenv("BUZZ_POLL_INTERVAL"):
|
||||
os.environ["BUZZ_POLL_INTERVAL"] = str(interval)
|
||||
channels = extra.get("channels")
|
||||
if channels is not None and not os.getenv("BUZZ_CHANNELS"):
|
||||
if isinstance(channels, (list, tuple)):
|
||||
channels = ",".join(str(c) for c in channels)
|
||||
os.environ["BUZZ_CHANNELS"] = str(channels)
|
||||
allowed = extra.get("allowed_users")
|
||||
if allowed is not None and not os.getenv("BUZZ_ALLOWED_USERS"):
|
||||
if isinstance(allowed, (list, tuple)):
|
||||
allowed = ",".join(str(a) for a in allowed)
|
||||
os.environ["BUZZ_ALLOWED_USERS"] = str(allowed)
|
||||
if "allow_all_users" in extra and not os.getenv("BUZZ_ALLOW_ALL_USERS"):
|
||||
os.environ["BUZZ_ALLOW_ALL_USERS"] = str(extra["allow_all_users"]).lower()
|
||||
return None
|
||||
|
||||
|
||||
def _env_enablement() -> Optional[dict]:
|
||||
"""Seed ``PlatformConfig.extra`` from env vars during gateway config load.
|
||||
|
||||
|
|
@ -949,6 +1025,10 @@ def register(ctx):
|
|||
# relay/channels/poll interval + home_channel so env-only setups show
|
||||
# up in gateway status without instantiating the adapter.
|
||||
env_enablement_fn=_env_enablement,
|
||||
# Bridge config.yaml buzz.extra -> BUZZ_* env vars so check_fn and the
|
||||
# env-driven connect path work for config.yaml-only setups (secret stays
|
||||
# in .env). Without this the check_fn gate skips Buzz at startup.
|
||||
apply_yaml_config_fn=_apply_yaml_config,
|
||||
# Cron home-channel delivery support (deliver=buzz).
|
||||
cron_deliver_env_var="BUZZ_HOME_CHANNEL",
|
||||
# Out-of-process cron delivery. Without this hook, deliver=buzz
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue