{"repo":"NousResearch/hermes-agent","public_id":"6889","display_label":"Feishu group chat WebSocket event delivery fixes","summary":"Multiple bug reports and fix attempts addressing Feishu/Lark group chat messages and @mentions not being received or routed through the WebSocket gateway. A minor unrelated gateway fix for file path rejection is also present.","subsystem":"gateway","counts":{"members":8,"open_issues":0,"open_issues_distinct":0,"open_prs":0,"closed_issues":2,"merged_prs":3,"attempt_prs":3},"landed_fix":{"status":"merged_to_main","basis":"structural","pr":7356},"resolution":{"state":"partially_resolved","by":"pr-61770"},"freshness":{"state":"verified","last_verified_at":"2026-07-10T03:31:50+00:00","is_stale":false},"grouping":{"backbone":"STRUCTURAL_PARTIAL","link_density":0.22714285714285712},"fix_edges":[{"issue_number":6889,"pr_number":7356,"tier":"verified","basis":"superseded_ref","confidence":0.9,"recoverable_from_timeline":false},{"issue_number":6889,"pr_number":7423,"tier":"verified","basis":"superseded_ref","confidence":0.9,"recoverable_from_timeline":false},{"issue_number":6976,"pr_number":7356,"tier":"verified","basis":"superseded_ref","confidence":0.9,"recoverable_from_timeline":false},{"issue_number":50656,"pr_number":61770,"tier":"verified","basis":"closing_ref","confidence":0.95,"recoverable_from_timeline":true}],"members":[{"kind":"issue","number":6889,"title":"[Bug]: Feishu group messages never reach gateway — DM works fine but @mention in group produces zero response","url":null,"state":"closed"},{"kind":"issue","number":50656,"title":"[Bug]: Feishu/Lark group @mention messages not delivered — WebSocket never receives group events","url":null,"state":"closed"},{"kind":"pr","number":6975,"title":"fix(feishu): register group chat member event handlers","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#7423","number":7423},{"kind":"pr","value":"#7356","number":7356}],"category":"merged_via","implication":"superseded"},"merged":false},{"kind":"pr","number":7356,"title":"fix(gateway): reject file paths in get_command() + file-drop tests","url":null,"state":"merged","close_reason":{"category":"merged","implication":"superseded"},"merged":true,"is_fix_pr":true,"fix_tier":"verified","files_changed":["gateway/platforms/base.py","tests/test_cli_file_drop.py"]},{"kind":"pr","number":7383,"title":"fix(feishu): register group chat member event handlers","url":null,"state":"closed","close_reason":{"refs":[{"kind":"commit","value":"d8cd7974d86cdfaf1f2bc4684cb233470491b0c8","number":0},{"kind":"pr","value":"#6975","number":6975}],"category":"merged_via","implication":"superseded"},"merged":false},{"kind":"pr","number":7423,"title":"fix(feishu) + feat(matrix): group chat events + DM mention threads","url":null,"state":"merged","close_reason":{"category":"merged","implication":"superseded"},"merged":true,"is_fix_pr":true,"fix_tier":"verified","files_changed":["gateway/config.py","gateway/platforms/feishu.py","gateway/platforms/matrix.py","tests/gateway/test_matrix_mention.py","website/docs/reference/environment-variables.md","website/docs/user-guide/messaging/matrix.md"],"fix_hunks":[{"file":"gateway/config.py","hunks":["@@ -642,6 +642,8 @@ def load_gateway_config() -> GatewayConfig:\n                     os.environ[\"MATRIX_FREE_RESPONSE_ROOMS\"] = str(frc)\n                 if \"auto_thread\" in matrix_cfg and not os.getenv(\"MATRIX_AUTO_THREAD\"):\n                     os.environ[\"MATRIX_AUTO_THREAD\"] = str(matrix_cfg[\"auto_thread\"]).lower()\n+                if \"dm_mention_threads\" in matrix_cfg and not os.getenv(\"MATRIX_DM_MENTION_THREADS\"):\n+                    os.environ[\"MATRIX_DM_MENTION_THREADS\"] = str(matrix_cfg[\"dm_mention_threads\"]).lower()\n \n     except Exception as e:\n         logger.warning("]},{"file":"gateway/platforms/feishu.py","hunks":["@@ -1190,6 +1190,8 @@ def _build_event_handler(self) -> Any:\n                 lambda data: self._on_reaction_event(\"im.message.reaction.deleted_v1\", data)\n             )\n             .register_p2_card_action_trigger(self._on_card_action_trigger)\n+            .register_p2_im_chat_member_bot_added_v1(self._on_bot_added_to_chat)\n+            .register_p2_im_chat_member_bot_deleted_v1(self._on_bot_removed_from_chat)\n             .build()\n         )\n "]},{"file":"gateway/platforms/matrix.py","hunks":["@@ -18,6 +18,7 @@\n     MATRIX_REQUIRE_MENTION      Require @mention in rooms (default: true)\n     MATRIX_FREE_RESPONSE_ROOMS  Comma-separated room IDs exempt from mention requirement\n     MATRIX_AUTO_THREAD          Auto-create threads for room messages (default: true)\n+    MATRIX_DM_MENTION_THREADS   Create a thread when bot is @mentioned in a DM (default: false)\n \"\"\"\n \n from __future__ import annotations","@@ -1043,6 +1044,13 @@ async def _on_room_message(self, room: Any, event: Any) -> None:\n                 if not self._is_bot_mentioned(body, formatted_body):\n                     return\n \n+        # DM mention-thread: when enabled, @mentioning bot in a DM creates a thread.\n+        if is_dm and not thread_id:\n+            dm_mention_threads = os.getenv(\"MATRIX_DM_MENTION_THREADS\", \"false\").lower() in (\"true\", \"1\", \"yes\")\n+            if dm_mention_threads and self._is_bot_mentioned(body, source_content.get(\"formatted_body\")):\n+                thread_id = event.event_id\n+                self._track_thread(thread_id)\n+\n         # Strip mention from body when present (including in DMs).\n         if self._is_bot_mentioned(body, source_content.get(\"formatted_body\")):\n             body = self._strip_mention(body)","@@ -1360,6 +1368,13 @@ def _safe_isinstance(obj, cls_name):\n                 if not self._is_bot_mentioned(body, formatted_body):\n                     return\n \n+        # DM mention-thread: when enabled, @mentioning bot in a DM creates a thread.\n+        if is_dm and not thread_id:\n+            dm_mention_threads = os.getenv(\"MATRIX_DM_MENTION_THREADS\", \"false\").lower() in (\"true\", \"1\", \"yes\")\n+            if dm_mention_threads and self._is_bot_mentioned(body, source_content.get(\"formatted_body\")):\n+                thread_id = event.event_id\n+                self._track_thread(thread_id)\n+\n         # Strip mention from body when present (including in DMs).\n         if self._is_bot_mentioned(body, source_content.get(\"formatted_body\")):\n             body = self._strip_mention(body)"]},{"file":"tests/gateway/test_matrix_mention.py","hunks":["@@ -436,6 +436,95 @@ def test_cap_max_tracked_threads(self, tmp_path, monkeypatch):\n         assert len(data) == 5\n \n \n+# ---------------------------------------------------------------------------\n+# DM mention-thread feature\n+# ---------------------------------------------------------------------------\n+\n+\n[redacted:email]\n+async def test_dm_mention_thread_disabled_by_default(monkeypatch):\n+    \"\"\"Default (dm_mention_threads=false): DM with mention should NOT create a thread.\"\"\"\n+    monkeypatch.delenv(\"MATRIX_DM_MENTION_THREADS\", raising=False)\n+    monkeypatch.setenv(\"MATRIX_AUTO_THREAD\", \"false\")\n+\n+    adapter = _make_adapter()\n+    room = _make_room(member_count=2)\n+    event = _make_event(\"@hermes:example.org help me\", event_id=\"$dm1\")\n+\n+    await adapter._on_room_message(room, event)\n+    adapter.handle_message.assert_awaited_once()\n+    msg = adapter.handle_message.await_args.args[0]\n+    assert msg.source.thread_id is None\n+\n+\n[redacted:email]\n+async def test_dm_mention_thread_creates_thread(monkeypatch):\n+    \"\"\"MATRIX_DM_MENTION_THREADS=true: DM with @mention creates a thread.\"\"\"\n+    monkeypatch.setenv(\"MATRIX_DM_MENTION_THREADS\", \"true\")\n+    monkeypatch.setenv(\"MATRIX_AUTO_THREAD\", \"false\")\n+\n+    adapter = _make_adapter()\n+    room = _make_room(member_count=2)\n+    event = _make_event(\"@hermes:example.org help me\", event_id=\"$dm1\")\n+\n+    with patch.object(adapter, \"_save_participated_threads\"):\n+        await adapter._on_room_message(room, event)\n+\n+    adapter.handle_message.assert_awaited_once()\n+    msg = adapter.handle_message.await_args.args[0]\n+    assert msg.source.thread_id == \"$dm1\"\n+    assert msg.text == \"help me\"\n+\n+\n[redacted:email]\n+async def test_dm_mention_thread_no_mention_no_thread(monkeypatch):\n+    \"\"\"MATRIX_DM_MENTION_THREADS=true: DM without mention does NOT create a thread.\"\"\"\n+    monkeypatch.setenv(\"MATRIX_DM_MENTION_THREADS\", \"true\")\n+    monkeypatch.setenv(\"MATRIX_AUTO_THREAD\", \"false\")\n+\n+    adapter = _make_adapter()\n+    room = _make_room(member_count=2)\n+    event = _make_event(\"hello without mention\", event_id=\"$dm1\")\n+\n+    await adapter._on_room_message(room, event)\n+    adapter.handle_message.assert_awaited_once()\n+    msg = adapter.handle_message.await_args.args[0]\n+    assert msg.source.thread_id is None\n+\n+\n[redacted:email]\n+async def test_dm_mention_thread_preserves_existing_thread(monkeypatch):\n+    \"\"\"MATRIX_DM_MENTION_THREADS=true: DM already in a thread keeps that thread_id.\"\"\"\n+    monkeypatch.setenv(\"MATRIX_DM_MENTION_THREADS\", \"true\")\n+    monkeypatch.setenv(\"MATRIX_AUTO_THREAD\", \"false\")\n+\n+    adapter = _make_adapter()\n+    adapter._bot_participated_threads.add(\"$existing_thread\")\n+    room = _make_room(member_count=2)\n+    event = _make_event(\"@hermes:example.org help me\", thread_id=\"$existing_thread\")\n+\n+    await adapter._on_room_message(room, event)\n+    adapter.handle_message.assert_awaited_once()\n+    msg = adapter.handle_message.await_args.args[0]\n+    assert msg.source.thread_id == \"$existing_thread\"\n+\n+\n[redacted:email]\n+async def test_dm_mention_thread_tracks_participation(monkeypatch):\n+    \"\"\"DM mention-thread tracks the thread in _bot_participated_threads.\"\"\"\n+    monkeypatch.setenv(\"MATRIX_DM_MENTION_THREADS\", \"true\")\n+    monkeypatch.setenv(\"MATRIX_AUTO_THREAD\", \"false\")\n+\n+    adapter = _make_adapter()\n+    room = _make_room(member_count=2)\n+    event = _make_event(\"@hermes:example.org help\", event_id=\"$dm1\")\n+\n+    with patch.object(adapter, \"_save_participated_threads\"):\n+        await adapter._on_room_message(room, event)\n+\n+    assert \"$dm1\" in adapter._bot_participated_threads\n+\n+\n # ---------------------------------------------------------------------------\n # YAML config bridge\n # ---------------------------------------------------------------------------","@@ -480,6 +569,25 @@ def test_yaml_bridge_sets_env_vars(self, monkeypatch, tmp_path):\n         assert os.getenv(\"MATRIX_FREE_RESPONSE_ROOMS\") == \"!room1:example.org,!room2:example.org\"\n         assert os.getenv(\"MATRIX_AUTO_THREAD\") == \"false\"\n \n+    def test_yaml_bridge_sets_dm_mention_threads(self, monkeypatch, tmp_path):\n+        \"\"\"Matrix YAML dm_mention_threads should bridge to env var.\"\"\"\n+        monkeypatch.delenv(\"MATRIX_DM_MENTION_THREADS\", raising=False)\n+\n+        import os\n+        import yaml\n+\n+        yaml_content = {\"matrix\": {\"dm_mention_threads\": True}}\n+        config_file = tmp_path / \"config.yaml\"\n+        config_file.write_text(yaml.dump(yaml_content))\n+\n+        yaml_cfg = yaml.safe_load(config_file.read_text())\n+        matrix_cfg = yaml_cfg.get(\"matrix\", {})\n+        if isinstance(matrix_cfg, dict):\n+            if \"dm_mention_threads\" in matrix_cfg and not os.getenv(\"MATRIX_DM_MENTION_THREADS\"):\n+                monkeypatch.setenv(\"MATRIX_DM_MENTION_THREADS\", str(matrix_cfg[\"dm_mention_threads\"]).lower())\n+\n+        assert os.getenv(\"MATRIX_DM_MENTION_THREADS\") == \"true\"\n+\n     def test_env_vars_take_precedence_over_yaml(self, monkeypatch):\n         \"\"\"Env vars should not be overwritten by YAML values.\"\"\"\n         monkeypatch.setenv(\"MATRIX_REQUIRE_MENTION\", \"true\")"]},{"file":"website/docs/reference/environment-variables.md","hunks":["@@ -262,6 +262,7 @@ For cloud sandbox backends, persistence is filesystem-oriented. `TERMINAL_LIFETI\n | `MATRIX_REQUIRE_MENTION` | Require `@mention` in rooms (default: `true`). Set to `false` to respond to all messages. |\n | `MATRIX_FREE_RESPONSE_ROOMS` | Comma-separated room IDs where bot responds without `@mention` |\n | `MATRIX_AUTO_THREAD` | Auto-create threads for room messages (default: `true`) |\n+| `MATRIX_DM_MENTION_THREADS` | Create a thread when bot is `@mentioned` in a DM (default: `false`) |\n | `HASS_TOKEN` | Home Assistant Long-Lived Access Token (enables HA platform + tools) |\n | `HASS_URL` | Home Assistant URL (default: `http://homeassistant.local:8123`) |\n | `WEBHOOK_ENABLED` | Enable the webhook platform adapter (`true`/`false`) |"]},{"file":"website/docs/user-guide/messaging/matrix.md","hunks":["@@ -16,7 +16,7 @@ Before setup, here's the part most people want to know: how Hermes behaves once\n \n | Context | Behavior |\n |---------|----------|\n-| **DMs** | Hermes responds to every message. No `@mention` needed. Each DM has its own session. |\n+| **DMs** | Hermes responds to every message. No `@mention` needed. Each DM has its own session. Set `MATRIX_DM_MENTION_THREADS=true` to start a thread when the bot is `@mentioned` in a DM. |\n | **Rooms** | By default, Hermes requires an `@mention` to respond. Set `MATRIX_REQUIRE_MENTION=false` or add room IDs to `MATRIX_FREE_RESPONSE_ROOMS` for free-response rooms. Room invites are auto-accepted. |\n | **Threads** | Hermes supports Matrix threads (MSC3440). If you reply in a thread, Hermes keeps the thread context isolated from the main room timeline. Threads where the bot has already participated do not require a mention. |\n | **Auto-threading** | By default, Hermes auto-creates a thread for each message it responds to in a room. This keeps conversations isolated. Set `MATRIX_AUTO_THREAD=false` to disable. |","@@ -62,6 +62,7 @@ matrix:\n   free_response_rooms:            # Rooms exempt from mention requirement\n     - \"!abc123:matrix.org\"\n   auto_thread: true               # Auto-create threads for responses (default: true)\n+  dm_mention_threads: false       # Create thread when @mentioned in DM (default: false)\n ```\n \n Or via environment variables:","@@ -70,6 +71,7 @@ Or via environment variables:\n MATRIX_REQUIRE_MENTION=true\n MATRIX_FREE_RESPONSE_ROOMS=!abc123:matrix.org,!def456:matrix.org\n MATRIX_AUTO_THREAD=true\n+MATRIX_DM_MENTION_THREADS=false\n ```\n \n :::note\n"]}]},{"kind":"pr","number":52908,"title":"fix(feishu): add extra_ua_tags=[\"channel\"] to FeishuWSClient for group @mention delivery","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#61770","number":61770}],"category":"merged_via","implication":"superseded"},"merged":false},{"kind":"pr","number":61770,"title":"fix(feishu): restore group events over WebSocket","url":null,"state":"merged","close_reason":{"category":"merged","implication":"superseded"},"merged":true,"is_fix_pr":true,"fix_tier":"verified","files_changed":["infographic/feishu-group-events/infographic.png","plugins/platforms/feishu/adapter.py","pyproject.toml","scripts/release.py","tests/gateway/test_feishu.py","tools/lazy_deps.py"],"fix_hunks":[{"file":"plugins/platforms/feishu/adapter.py","hunks":["@@ -4730,6 +4730,12 @@ async def _connect_websocket(self) -> None:\n             log_level=lark.LogLevel.INFO,\n             event_handler=self._event_handler,\n             domain=domain,\n+            # Channel SDK signaling tag: without this UA tag the Feishu\n+            # server does not push group @mention events over the WebSocket\n+            # transport.  The tag tells the server to use the Channel protocol\n+            # which enables group-message routing in addition to P2P DM.\n+            # See https://github.com/NousResearch/hermes-agent/issues/50656\n+            extra_ua_tags=[\"channel\"],\n         )\n         self._ws_future = loop.run_in_executor(\n             None,"]},{"file":"pyproject.toml","hunks":["@@ -249,7 +249,7 @@ termux-all = [\n   \"hermes-agent[web]\",\n ]\n dingtalk = [\"dingtalk-stream==0.24.3\", \"alibabacloud-dingtalk==2.2.42\", \"qrcode==7.4.2\"]\n-feishu = [\"lark-oapi==1.5.3\", \"qrcode==7.4.2\"]\n+feishu = [\"lark-oapi==1.6.8\", \"qrcode==7.4.2\"]\n google = [\n   # Required by the google-workspace skill (Gmail, Calendar, Drive, Contacts,\n   # Sheets, Docs).  Declared here so packagers (Nix, Homebrew) ship them with"]},{"file":"scripts/release.py","hunks":["@@ -46,7 +46,7 @@\n # Auto-extracted from noreply emails + manual overrides\n AUTHOR_MAP = {\n     \"[redacted:email]\": \"lemonwan\",  # PR #59430 sibling salvage (adapter reconnect contract guard)\n-    \"[redacted:email]\": \"luxuguang-leo\",  # PR #52966 salvage (QQBot reconnect contract)\n+    \"[redacted:email]\": \"luxuguang-leo\",  # PR #52966 + #52908 salvage (QQBot reconnect + Feishu Channel signaling)\n     \"[redacted:email]\": \"evelynburger\",  # PR #57544 salvage (gateway: webhook payload filters + route scripts; commit under unlinked identity)\n     \"[redacted:email]\": \"SiteupAgencia\",  # PR #57435 salvage (tui_gateway: back off notification poller when session is busy; #55578)\n     \"[redacted:email]\": \"rainbowgore\",  # PR #59405 salvage (mcp: bound stdio initialize handshake to stop subprocess/FD leak; #59349)"]},{"file":"tests/gateway/test_feishu.py","hunks":["@@ -173,6 +173,16 @@ def test_normalize_interactive_card_preserves_title_body_and_actions(self):\n \n \n class TestFeishuAdapterMessaging(unittest.TestCase):\n+    @unittest.skipUnless(_HAS_LARK_OAPI, \"lark-oapi not installed\")\n+    def test_websocket_sdk_accepts_channel_ua_tag(self):\n+        \"\"\"The shipped SDK must support the Channel signaling argument.\"\"\"\n+        import inspect\n+\n+        from lark_oapi.ws import Client as FeishuWSClient\n+\n+        signature = inspect.signature(FeishuWSClient)\n+        self.assertIn(\"extra_ua_tags\", signature.parameters)\n+\n     @patch.dict(os.environ, {\n         \"FEISHU_APP_ID\": \"cli_app\",\n         \"FEISHU_APP_SECRET\": \"secret_app\",","@@ -414,6 +424,65 @@ def is_closed(self):\n         self.assertEqual(sleeps, [1])\n         self.assertEqual(fake_loop.calls, 2)\n \n+    @patch.dict(os.environ, {\n+        \"FEISHU_APP_ID\": \"cli_app\",\n+        \"FEISHU_APP_SECRET\": \"secret_app\",\n+    }, clear=True)\n+    def test_connect_websocket_sets_channel_ua_tag(self):\n+        \"\"\"Verify that FeishuWSClient receives extra_ua_tags=[\"channel\"].\n+\n+        Without this UA tag the Feishu server does not push group @mention\n+        events over the WebSocket transport.  See\n+        https://github.com/NousResearch/hermes-agent/issues/50656\n+        \"\"\"\n+        from gateway.config import PlatformConfig\n+        from plugins.platforms.feishu.adapter import FeishuAdapter\n+\n+        adapter = FeishuAdapter(PlatformConfig())\n+        ws_client = SimpleNamespace()\n+\n+        with (\n+            patch(\"plugins.platforms.feishu.adapter.FEISHU_AVAILABLE\", True),\n+            patch(\"plugins.platforms.feishu.adapter.FEISHU_WEBSOCKET_AVAILABLE\", True),\n+            patch(\"plugins.platforms.feishu.adapter.lark\",\n+                  SimpleNamespace(LogLevel=SimpleNamespace(INFO=\"INFO\", WARNING=\"WARNING\"))),\n+            patch(\"plugins.platforms.feishu.adapter.EventDispatcherHandler\") as mock_handler_class,\n+            patch(\"plugins.platforms.feishu.adapter.FeishuWSClient\") as mock_ws_client,\n+            patch(\"plugins.platforms.feishu.adapter._run_official_feishu_ws_client\"),\n+            patch(\"plugins.platforms.feishu.adapter.acquire_scoped_lock\", return_value=(True, None)),\n+            patch(\"plugins.platforms.feishu.adapter.release_scoped_lock\"),\n+            patch.object(adapter, \"_hydrate_bot_identity\", new=AsyncMock()),\n+            patch.object(adapter, \"_build_lark_client\", return_value=SimpleNamespace()),\n+        ):\n+            _mock_event_dispatcher_builder(mock_handler_class)\n+\n+            loop = asyncio.new_event_loop()\n+            future = loop.create_future()\n+            future.set_result(None)\n+\n+            class _Loop:\n+                def run_in_executor(self, *_args, **_kwargs):\n+                    return future\n+                def is_closed(self):\n+                    return False\n+\n+            try:\n+                with patch(\"plugins.platforms.feishu.adapter.asyncio.get_running_loop\",\n+                           return_value=_Loop()):\n+                    connected = asyncio.run(adapter.connect())\n+            finally:\n+                loop.close()\n+\n+        self.assertTrue(connected)\n+        # Verify the Channel SDK UA tag is present — this is the fix for\n+        # group @mention message delivery over WebSocket.\n+        mock_ws_client.assert_called_once()\n+        call_kwargs = mock_ws_client.call_args.kwargs\n+        self.assertIn(\"extra_ua_tags\", call_kwargs,\n+                      \"FeishuWSClient must receive extra_ua_tags for group @mention delivery\")\n+        self.assertEqual(call_kwargs[\"extra_ua_tags\"], [\"channel\"],\n+                         \"extra_ua_tags must be ['channel'] to enable group event routing\")\n+\n     @patch.dict(os.environ, {}, clear=True)\n     def test_edit_message_updates_existing_feishu_message(self):\n         from gateway.config import PlatformConfig"]},{"file":"tools/lazy_deps.py","hunks":["@@ -188,7 +188,7 @@\n         \"qrcode==7.4.2\",\n     ),\n     \"platform.feishu\": (\n-        \"lark-oapi==1.5.3\",\n+        \"lark-oapi==1.6.8\",\n         \"qrcode==7.4.2\",\n     ),\n     # WeCom callback-mode adapter — parses untrusted XML POST bodies. Pulls"]},{"file":"uv.lock","hunks":["@@ -1794,7 +1794,7 @@ requires-dist = [\n     { name = \"honcho-ai\", marker = \"extra == 'honcho'\", specifier = \"==2.0.1\" },\n     { name = \"httpx\", extras = [\"socks\"], specifier = \"==0.28.1\" },\n     { name = \"jinja2\", specifier = \"==3.1.6\" },\n-    { name = \"lark-oapi\", marker = \"extra == 'feishu'\", specifier = \"==1.5.3\" },\n+    { name = \"lark-oapi\", marker = \"extra == 'feishu'\", specifier = \"==1.6.8\" },\n     { name = \"markdown\", specifier = \"==3.10.2\" },\n     { name = \"mautrix\", extras = [\"encryption\"], marker = \"extra == 'matrix'\", specifier = \"==0.21.0\" },\n     { name = \"mcp\", marker = \"extra == 'computer-use'\", specifier = \"==1.26.0\" },","@@ -2184,7 +2184,7 @@ wheels = [\n \n [[package]]\n name = \"lark-oapi\"\n-version = \"1.5.3\"\n+version = \"1.6.8\"\n source = { registry = \"https://pypi.org/simple\" }\n dependencies = [\n     { name = \"httpx\" },","@@ -2194,7 +2194,7 @@ dependencies = [\n     { name = \"websockets\" },\n ]\n wheels = [\n-    { url = \"https://files.pythonhosted.org/packages/bf/ff/2ece5d735ebfa2af600a53176f2636ae47af2bf934e08effab64f0d1e047/lark_oapi-1.5.3-py3-none-any.whl\", hash = \"sha256:fda6b32bb38d21b6bdaae94979c600b94c7c521e985adade63a54e4b3e20cc36\", size = 6993016, upload-time = \"2026-01-27T08:21:49.307Z\" },\n+    { url = \"https://files.pythonhosted.org/packages/4a/ad/1ab04db5d549ad1a7a2cd33682b1c38dee1d65019cb24fd7a23270e6337d/lark_oapi-1.6.8-py3-none-any.whl\", hash = \"sha256:9b443a5d47a7d204dd42dc40896c8b75087cc35788e45c48c140806d7df7e5e8\", size = 7798300, upload-time = \"2026-06-02T07:40:05.492Z\" },\n ]\n \n [[package]]\n"]}]}],"trust":{"default_tier":"verified","includes_suggested":false}}