Ver código fonte

Announce what the plugin can do at registration

Startup said only that the plugin registered, so what Chatto actually
supports was something you had to read the source to learn. List it at
info level instead.

The list is derived from real overrides rather than hard-coded: a
capability counts only when ChattoAdapter replaces the BasePlatformAdapter
method, so an inherited fallback is never advertised as native support and
removing a method removes its claim.
Paul Klumpp 1 semana atrás
pai
commit
e9893c5031
2 arquivos alterados com 59 adições e 0 exclusões
  1. 43 0
      adapter.py
  2. 16 0
      test_adapter.py

+ 43 - 0
adapter.py

@@ -2048,10 +2048,53 @@ def hermes_env_enablement_fn() -> Optional[dict]:
 # Plugin registration entry point
 # ---------------------------------------------------------------------------
 
+# What each capability is called in the startup banner, keyed by the method
+# that implements it. Derived from real overrides rather than hard-coded, so
+# dropping a method drops its claim from the log instead of leaving a lie.
+_CAPABILITY_LABELS = {
+    "send": "text",
+    "send_image_file": "images",
+    "send_multiple_images": "image batches (bundled into one message)",
+    "send_video": "video",
+    "send_voice": "voice messages",
+    "send_document": "documents",
+    "add_reaction": "reactions",
+    "edit_message": "message editing",
+    "delete_message": "message deletion",
+    "send_typing": "typing indicators",
+    "create_handoff_thread": "threads",
+    "start_dm": "direct messages",
+    "create_room": "room creation",
+}
+
+
+def _capabilities() -> List[str]:
+    """Name the things this adapter genuinely implements itself.
+
+    A capability counts only when ChattoAdapter overrides the base method —
+    inheriting BasePlatformAdapter's fallback means the feature is not
+    natively supported, and announcing it would mislead.
+    """
+    found = [
+        label
+        for name, label in _CAPABILITY_LABELS.items()
+        if getattr(ChattoAdapter, name, None) is not getattr(BasePlatformAdapter, name, None)
+    ]
+    if ChattoAdapter.supports_code_blocks:
+        found.append("code blocks")
+    if ChattoAdapter.supports_status_text:
+        found.append("custom status text")
+    found.append("presence (refreshed while connected)")
+    return found
+
+
 def register(ctx) -> None:
     """Plugin entry point — called by the Hermes plugin system."""
     logger.info("Registering Chatto platform plugin on Hermes Agent")
 
+    for capability in _capabilities():
+        logger.info("Chatto capability: %s", capability)
+
     logger.info("ChattoConfiguration.allowed_users.env_name: %s", ChattoConfiguration.allowed_users.env_name)
 
     ctx.register_platform(

+ 16 - 0
test_adapter.py

@@ -34,6 +34,7 @@ sys.path.insert(0, "/root/.hermes/plugins/platforms/chatto")
 
 from adapter import (
     ChattoAdapter,
+    _capabilities,
     HermesChatType,
     chat_type_for_room_kind,
     hermes_check_fn as check_requirements,
@@ -53,6 +54,7 @@ from chattolib.types import (
 from platform_config import ChattoConstants
 from gateway.config import PlatformConfig
 from gateway.platforms.base import (
+    BasePlatformAdapter,
     CachedMedia,
     MessageEvent,
     MessageType,
@@ -260,6 +262,20 @@ class TestRegistration:
         assert "MEDIA:/absolute/path/to/file" in hint
         assert "![alt](url)" in hint
 
+    def test_startup_logs_the_capabilities(self, caplog):
+        with caplog.at_level("INFO"):
+            register(_MockPluginContext())
+        logged = "\n".join(caplog.messages)
+        assert "images" in logged
+        assert "reactions" in logged
+
+    def test_capabilities_skips_methods_we_do_not_override(self):
+        """An inherited base fallback is not a capability — claiming it would
+        promise the user something the adapter cannot actually do."""
+        assert "video" in _capabilities()
+        with patch.object(ChattoAdapter, "send_video", BasePlatformAdapter.send_video):
+            assert "video" not in _capabilities()
+
     def test_check_requirements(self):
         assert check_requirements() is True