Merge pull request #6 from Athemis/feat/matrix-improvements
feat(matrix): E2E, typing, markdown/HTML, group policy, inbound+outbound media, thread replies
This commit is contained in:
67
README.md
67
README.md
@@ -301,6 +301,73 @@ nanobot gateway
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>Matrix (Element)</b></summary>
|
||||
|
||||
Uses Matrix sync via `matrix-nio` (inbound media + outbound file attachments).
|
||||
|
||||
**1. Create/choose a Matrix account**
|
||||
|
||||
- Create or reuse a Matrix account on your homeserver (for example `matrix.org`).
|
||||
- Confirm you can log in with Element.
|
||||
|
||||
**2. Get credentials**
|
||||
|
||||
- You need:
|
||||
- `userId` (example: `@nanobot:matrix.org`)
|
||||
- `accessToken`
|
||||
- `deviceId` (recommended so sync tokens can be restored across restarts)
|
||||
- You can obtain these from your homeserver login API (`/_matrix/client/v3/login`) or from your client's advanced session settings.
|
||||
|
||||
**3. Configure**
|
||||
|
||||
```json
|
||||
{
|
||||
"channels": {
|
||||
"matrix": {
|
||||
"enabled": true,
|
||||
"homeserver": "https://matrix.org",
|
||||
"userId": "@nanobot:matrix.org",
|
||||
"accessToken": "syt_xxx",
|
||||
"deviceId": "NANOBOT01",
|
||||
"e2eeEnabled": true,
|
||||
"allowFrom": [],
|
||||
"groupPolicy": "open",
|
||||
"groupAllowFrom": [],
|
||||
"allowRoomMentions": false,
|
||||
"maxMediaBytes": 20971520
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> `allowFrom`: Empty allows all senders; set user IDs to restrict access.
|
||||
> `groupPolicy`: `open`, `mention`, or `allowlist`.
|
||||
> `groupAllowFrom`: Room allowlist used when `groupPolicy` is `allowlist`.
|
||||
> `allowRoomMentions`: If `true`, accepts `@room` (`m.mentions.room`) in mention mode.
|
||||
> `e2eeEnabled`: Enables Matrix E2EE support (default `true`); set `false` only for plaintext-only setups.
|
||||
> `maxMediaBytes`: Max attachment size in bytes (default `20MB`) for inbound and outbound media handling; set to `0` to block all inbound and outbound attachment uploads.
|
||||
|
||||
> [!NOTE]
|
||||
> Matrix E2EE implications:
|
||||
>
|
||||
> - Keep a persistent `matrix-store` and stable `deviceId`; otherwise encrypted session state can be lost after restart.
|
||||
> - In newly joined encrypted rooms, initial messages may fail until Olm/Megolm sessions are established.
|
||||
> - With `e2eeEnabled=false`, encrypted room messages may be undecryptable and E2EE send safeguards are not applied.
|
||||
> - With `e2eeEnabled=true`, the bot sends with `ignore_unverified_devices=true` (more compatible, less strict than verified-only sending).
|
||||
> - Changing `accessToken`/`deviceId` effectively creates a new device and may require session re-establishment.
|
||||
> - Outbound attachments are sent from `OutboundMessage.media`.
|
||||
> - Effective media limit (inbound + outbound) uses the stricter value of local `maxMediaBytes` and homeserver `m.upload.size` (if advertised).
|
||||
> - If `tools.restrictToWorkspace=true`, Matrix outbound attachments are limited to files inside the workspace.
|
||||
|
||||
**4. Run**
|
||||
|
||||
```bash
|
||||
nanobot gateway
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>WhatsApp</b></summary>
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,8 @@
|
||||
"""Configuration schema using Pydantic."""
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Literal
|
||||
|
||||
from pydantic import BaseModel, Field, ConfigDict
|
||||
from pydantic.alias_generators import to_camel
|
||||
from pydantic_settings import BaseSettings
|
||||
@@ -60,6 +62,26 @@ class DiscordConfig(Base):
|
||||
intents: int = 37377 # GUILDS + GUILD_MESSAGES + DIRECT_MESSAGES + MESSAGE_CONTENT
|
||||
|
||||
|
||||
class MatrixConfig(Base):
|
||||
"""Matrix (Element) channel configuration."""
|
||||
|
||||
enabled: bool = False
|
||||
homeserver: str = "https://matrix.org"
|
||||
access_token: str = ""
|
||||
user_id: str = "" # @bot:matrix.org
|
||||
device_id: str = ""
|
||||
# Enable Matrix E2EE support (encryption + encrypted room handling).
|
||||
e2ee_enabled: bool = True
|
||||
# Max seconds to wait for sync_forever to stop gracefully before cancellation fallback.
|
||||
sync_stop_grace_seconds: int = 2
|
||||
# Max attachment size accepted for Matrix media handling (inbound + outbound).
|
||||
max_media_bytes: int = 20 * 1024 * 1024
|
||||
allow_from: list[str] = Field(default_factory=list)
|
||||
group_policy: Literal["open", "mention", "allowlist"] = "open"
|
||||
group_allow_from: list[str] = Field(default_factory=list)
|
||||
allow_room_mentions: bool = False
|
||||
|
||||
|
||||
class EmailConfig(Base):
|
||||
"""Email channel configuration (IMAP inbound + SMTP outbound)."""
|
||||
|
||||
@@ -176,6 +198,7 @@ class ChannelsConfig(Base):
|
||||
email: EmailConfig = Field(default_factory=EmailConfig)
|
||||
slack: SlackConfig = Field(default_factory=SlackConfig)
|
||||
qq: QQConfig = Field(default_factory=QQConfig)
|
||||
matrix: MatrixConfig = Field(default_factory=MatrixConfig)
|
||||
|
||||
|
||||
class AgentDefaults(Base):
|
||||
|
||||
@@ -42,6 +42,9 @@ dependencies = [
|
||||
"prompt-toolkit>=3.0.50,<4.0.0",
|
||||
"mcp>=1.26.0,<2.0.0",
|
||||
"json-repair>=0.57.0,<1.0.0",
|
||||
"matrix-nio[e2e]>=0.25.2",
|
||||
"mistune>=3.0.0,<4.0.0",
|
||||
"nh3>=0.2.17,<1.0.0",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
|
||||
1279
tests/test_matrix_channel.py
Normal file
1279
tests/test_matrix_channel.py
Normal file
File diff suppressed because it is too large
Load Diff
10
tests/test_message_tool.py
Normal file
10
tests/test_message_tool.py
Normal file
@@ -0,0 +1,10 @@
|
||||
import pytest
|
||||
|
||||
from nanobot.agent.tools.message import MessageTool
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_message_tool_returns_error_when_no_target_context() -> None:
|
||||
tool = MessageTool()
|
||||
result = await tool.execute(content="test")
|
||||
assert result == "Error: No target channel/chat specified"
|
||||
Reference in New Issue
Block a user