diff --git a/plugins/platforms/line/adapter.py b/plugins/platforms/line/adapter.py index 1bec8c64eb..fbfae12433 100644 --- a/plugins/platforms/line/adapter.py +++ b/plugins/platforms/line/adapter.py @@ -262,7 +262,6 @@ class _LineClient: logger.debug("LINE loading indicator failed: %s", exc) async def fetch_content(self, message_id: str) -> bytes: - """Download an inbound media message's binary content.""" async with self._session(30.0) as session: url = LINE_CONTENT_URL_FMT.format(message_id=message_id) async with session.get(url, headers={"Authorization": f"Bearer {self._token}"}) as resp: @@ -380,10 +379,13 @@ class LineAdapter(BasePlatformAdapter): # Slow-LLM postback button threshold + user-overridable copy threshold = env_or("LINE_SLOW_RESPONSE_THRESHOLD", "slow_response_threshold", DEFAULT_SLOW_RESPONSE_THRESHOLD) self.slow_response_threshold = _coerce(float, threshold, DEFAULT_SLOW_RESPONSE_THRESHOLD) - self.pending_text = env_or("LINE_PENDING_TEXT", "pending_text", DEFAULT_PENDING_REPLY_TEXT) - self.button_label = env_or("LINE_BUTTON_LABEL", "button_label", DEFAULT_BUTTON_LABEL) - self.delivered_text = env_or("LINE_DELIVERED_TEXT", "delivered_text", DEFAULT_DELIVERED_TEXT) - self.interrupted_text = env_or("LINE_INTERRUPTED_TEXT", "interrupted_text", DEFAULT_INTERRUPTED_TEXT) + for attr, env, default in ( + ("pending_text", "LINE_PENDING_TEXT", DEFAULT_PENDING_REPLY_TEXT), + ("button_label", "LINE_BUTTON_LABEL", DEFAULT_BUTTON_LABEL), + ("delivered_text", "LINE_DELIVERED_TEXT", DEFAULT_DELIVERED_TEXT), + ("interrupted_text", "LINE_INTERRUPTED_TEXT", DEFAULT_INTERRUPTED_TEXT), + ): + setattr(self, attr, env_or(env, attr, default)) # Runtime state self._client: Optional[_LineClient] = None self._app = self._runner = self._site = None # aiohttp web.Application / AppRunner / TCPSite @@ -398,7 +400,6 @@ class LineAdapter(BasePlatformAdapter): self._pending_buttons: Dict[str, str] = {} # one outstanding button per chat: chat_id → request_id def _fail(self, code: str, detail: str, *, retryable: bool = False) -> bool: - """Record a fatal connect error and return False.""" self._set_fatal_error(code, detail, retryable=retryable) return False @@ -713,7 +714,6 @@ class LineAdapter(BasePlatformAdapter): return token def _media_url(self, token: str, filename: str) -> str: - """Build the public HTTPS URL for a media token.""" if self.public_base_url: base = self.public_base_url else: @@ -724,7 +724,6 @@ class LineAdapter(BasePlatformAdapter): return f"{base}{DEFAULT_MEDIA_PATH_PREFIX}/{token}/{_urlquote(filename, safe='')}" def _serve_file(self, path: Path) -> str: - """Register ``path`` for serving and return its public URL.""" return self._media_url(self._register_media(str(path.resolve())), path.name) def _missing_public_url(self) -> bool: @@ -949,7 +948,6 @@ def interactive_setup() -> None: def register(ctx) -> None: - """Plugin entry point — called by the Hermes plugin system at startup.""" ctx.register_platform( name="line", label="LINE", adapter_factory=lambda cfg: LineAdapter(cfg), check_fn=check_requirements, validate_config=validate_config, is_connected=is_connected, diff --git a/plugins/platforms/simplex/adapter.py b/plugins/platforms/simplex/adapter.py index 508b9737c7..55a17eb604 100644 --- a/plugins/platforms/simplex/adapter.py +++ b/plugins/platforms/simplex/adapter.py @@ -43,12 +43,10 @@ _MEDIA_KIND_PRECEDENCE = (("audio/", MessageType.VOICE), ("image/", MessageType. def _parse_comma_list(value: str) -> List[str]: - """Split a comma-separated string into a stripped list.""" return [v.strip() for v in value.split(",") if v.strip()] def _redact_id(contact_id: str) -> str: - """Redact a contact/group ID for logging.""" if not contact_id: return "" s = str(contact_id) @@ -129,7 +127,6 @@ class SimplexAdapter(BasePlatformAdapter): self.ws_url, self.auto_accept, "enabled" if self.group_allow_from else "disabled") async def connect(self, *, is_reconnect: bool = False) -> bool: - """Connect to the simplex-chat daemon and start the WebSocket listener.""" try: import websockets as _wsclient except ImportError: @@ -154,7 +151,6 @@ class SimplexAdapter(BasePlatformAdapter): return True async def disconnect(self) -> None: - """Stop WebSocket listener and clean up.""" self._running = False await _cancel_task(self._ws_task) await _cancel_task(self._health_task) @@ -175,7 +171,6 @@ class SimplexAdapter(BasePlatformAdapter): logger.info("SimpleX: disconnected") async def _ws_listener(self) -> None: - """Maintain a persistent WebSocket connection to the daemon.""" import websockets as _wsclient from websockets.exceptions import ConnectionClosed backoff = WS_RETRY_DELAY_INITIAL @@ -223,7 +218,6 @@ class SimplexAdapter(BasePlatformAdapter): logger.debug("SimpleX: WS application-idle for %.0fs", elapsed) async def _handle_event(self, event: dict) -> None: - """Dispatch a daemon event to the appropriate handler.""" # Usually {"corrId": ..., "resp": {"type": ...}}, but some daemons put the # response fields at top level — normalize both. resp = event.get("resp") if isinstance(event.get("resp"), dict) else event @@ -296,7 +290,6 @@ class SimplexAdapter(BasePlatformAdapter): logger.exception(err_msg) async def _handle_chat_item(self, chat_item: dict) -> None: - """Process a single chat item from a newChatItems event.""" chat_info = chat_item.get("chatInfo", {}) or {} chat_item_data = chat_item.get("chatItem", {}) or {} chat_type = chat_info.get("type", "") @@ -421,7 +414,6 @@ class SimplexAdapter(BasePlatformAdapter): logger.warning("SimpleX: WS send error: %s", e) async def _send_command(self, command: str, timeout: float = 30.0) -> Optional[dict]: - """Send a command and await the correlated response.""" ws = self._ws if not ws: logger.warning("SimpleX: command sent but WebSocket not connected") @@ -694,7 +686,6 @@ def interactive_setup() -> None: def register(ctx) -> None: - """Plugin entry point — called by the Hermes plugin system at startup.""" ctx.register_platform( name="simplex", label="SimpleX Chat", adapter_factory=lambda cfg: SimplexAdapter(cfg), check_fn=check_requirements, validate_config=validate_config, is_connected=is_connected, diff --git a/plugins/platforms/teams/adapter.py b/plugins/platforms/teams/adapter.py index cd3db59308..208f89c0a5 100644 --- a/plugins/platforms/teams/adapter.py +++ b/plugins/platforms/teams/adapter.py @@ -150,12 +150,10 @@ def _credentials(config) -> tuple[str, str, str]: def validate_config(config) -> bool: - """True when the config has the minimum required credentials.""" return bool(all(_credentials(config))) def is_connected(config) -> bool: - """Check whether Teams is configured (env or config.yaml).""" return validate_config(config) @@ -451,7 +449,6 @@ class TeamsAdapter(BasePlatformAdapter): return await _read_httpx_body_with_limit(response, media_type="attachment") async def _on_message(self, ctx: ActivityContext[MessageActivity]) -> None: - """Process an incoming Teams message and dispatch to the gateway.""" activity = ctx.activity bot_id = self._app.id if self._app else None if bot_id and getattr(activity.from_, "id", None) == bot_id: @@ -570,7 +567,6 @@ class TeamsAdapter(BasePlatformAdapter): async def _on_card_action( self, ctx: "ActivityContext[AdaptiveCardInvokeActivity]" ) -> "InvokeResponse[AdaptiveCardActionMessageResponse]": - """Handle an Adaptive Card Action.Execute button click.""" from tools.approval import resolve_gateway_approval, has_blocking_approval data = ctx.activity.value.action.data or {} @@ -615,7 +611,6 @@ class TeamsAdapter(BasePlatformAdapter): self, chat_id: str, command: str, session_key: str, description: str = "dangerous command", metadata: Optional[Dict[str, Any]] = None, allow_permanent: bool = True, allow_session: bool = True, smart_denied: bool = False) -> SendResult: - """Send an Adaptive Card approval prompt with Allow/Deny buttons.""" if not self._app: return SendResult(success=False, error="Teams app not initialized") # Button data carries a truncated cmd — just enough to reconstruct the card body. @@ -739,7 +734,6 @@ _SETUP_INTRO = ( # "" → blank line def interactive_setup() -> None: - """Guide the user through Teams setup using the Teams CLI.""" from hermes_cli.config import get_env_value, save_env_value from hermes_cli.cli_output import prompt, prompt_yes_no, print_info, print_success, print_warning existing_id = get_env_value("TEAMS_CLIENT_ID") @@ -787,7 +781,6 @@ def _install_hint() -> str: def register(ctx) -> None: - """Plugin entry point — called by the Hermes plugin system.""" ctx.register_platform( name="teams", label="Microsoft Teams", adapter_factory=lambda cfg: TeamsAdapter(cfg), check_fn=check_requirements, # PASSIVE probe — never installs