diff --git a/README.md b/README.md index f593e26ec..85fe2936c 100644 --- a/README.md +++ b/README.md @@ -276,6 +276,7 @@ Connect nanobot to your favorite chat platform. Want to build your own? See the | **Email** | IMAP/SMTP credentials | | **QQ** | App ID + App Secret | | **Wecom** | Bot ID + Bot Secret | +| **Microsoft Teams** | App ID + App Password + public HTTPS endpoint | | **Mochat** | Claw token (auto-setup available) |
@@ -861,6 +862,56 @@ nanobot gateway
+
+Microsoft Teams (MVP — DM only) + +> Direct-message text in/out, tenant-aware OAuth, conversation reference persistence. +> Uses a public HTTPS webhook — no WebSocket; you need a tunnel or reverse proxy. + +**1. Install the optional dependency** + +```bash +pip install nanobot-ai[msteams] +``` + +**2. Create a Teams / Azure bot app registration** + +Create or reuse a Microsoft Teams / Azure bot app registration. Set the bot messaging endpoint to a public HTTPS URL ending in `/api/messages`. + +**3. Configure** + +```json +{ + "channels": { + "msteams": { + "enabled": true, + "appId": "YOUR_APP_ID", + "appPassword": "YOUR_APP_SECRET", + "tenantId": "YOUR_TENANT_ID", + "host": "0.0.0.0", + "port": 3978, + "path": "/api/messages", + "allowFrom": ["*"], + "replyInThread": true, + "mentionOnlyResponse": "Hi — what can I help with?", + "validateInboundAuth": true + } + } +} +``` + +> - `replyInThread: true` replies to the triggering Teams activity when a stored `activity_id` is available. +> - `mentionOnlyResponse` controls what Nanobot receives when a user sends only a bot mention (`Nanobot`). Set to `""` to ignore mention-only messages. +> - `validateInboundAuth: true` (recommended for production) enables inbound Bot Framework bearer-token validation (signature, issuer, audience, lifetime, `serviceUrl`). **Default is `false`** — set explicitly to `true` for production deployments. + +**4. Run** + +```bash +nanobot gateway +``` + +
+ ## 🌐 Agent Social Network 🐈 nanobot is capable of linking to the agent social network (agent community). **Just send one message and your nanobot joins automatically!** diff --git a/docs/MSTEAMS.md b/docs/MSTEAMS.md deleted file mode 100644 index 285553e51..000000000 --- a/docs/MSTEAMS.md +++ /dev/null @@ -1,68 +0,0 @@ -# Microsoft Teams (MVP) - -This repository includes a built-in `msteams` channel MVP for Microsoft Teams direct messages. - -## Current scope - -- Direct-message text in/out -- Tenant-aware OAuth token acquisition -- Conversation reference persistence for replies -- Public HTTPS webhook support through a tunnel or reverse proxy - -## Not yet included - -- Group/channel handling -- Attachments and cards -- Polls -- Richer Teams activity handling - -## Example config - -```json -{ - "channels": { - "msteams": { - "enabled": true, - "appId": "YOUR_APP_ID", - "appPassword": "YOUR_APP_SECRET", - "tenantId": "YOUR_TENANT_ID", - "host": "0.0.0.0", - "port": 3978, - "path": "/api/messages", - "allowFrom": ["*"], - "replyInThread": true, - "mentionOnlyResponse": "Hi — what can I help with?", - "validateInboundAuth": false, - "restartNotifyEnabled": false, - "restartNotifyPreMessage": "Nanobot agent initiated a gateway restart. I will message again when the gateway is back online.", - "restartNotifyPostMessage": "Nanobot gateway is back online." - } - } -} -``` - -## Behavior notes - -- `replyInThread: true` replies to the triggering Teams activity when a stored `activity_id` is available. -- `replyInThread: false` posts replies as normal conversation messages. -- If `replyInThread` is enabled but no `activity_id` is stored, Nanobot falls back to a normal conversation message. -- `mentionOnlyResponse` controls what Nanobot receives when a user sends only a bot mention such as `Nanobot`. -- Set `mentionOnlyResponse` to an empty string to ignore mention-only messages. -- `validateInboundAuth: true` enables inbound Bot Framework bearer-token validation. -- `validateInboundAuth: false` leaves inbound auth unenforced, which is safer while first validating a new relay, tunnel, or proxy path. -- When enabled, Nanobot validates the inbound bearer token signature, issuer, audience, token lifetime, and `serviceUrl` claim when present. -- `restartNotifyEnabled: true` enables optional Teams restart-notification configuration for external wrapper-script driven restarts. -- `restartNotifyPreMessage` and `restartNotifyPostMessage` control the before/after announcement text used by that external wrapper. - -## Setup notes - -1. Create or reuse a Microsoft Teams / Azure bot app registration. -2. Set the bot messaging endpoint to a public HTTPS URL ending in `/api/messages`. -3. Forward that public endpoint to `http://localhost:3978/api/messages`. -4. Start Nanobot with: - -```bash -nanobot gateway -``` - -5. Optional: if you use an external restart wrapper (for example a script that stops and restarts the gateway), you can enable Teams restart announcements with `restartNotifyEnabled: true` and have the wrapper send `restartNotifyPreMessage` before restart and `restartNotifyPostMessage` after the gateway is back online. diff --git a/nanobot/channels/msteams.py b/nanobot/channels/msteams.py index 2987b03f8..06b707f81 100644 --- a/nanobot/channels/msteams.py +++ b/nanobot/channels/msteams.py @@ -32,7 +32,10 @@ from nanobot.channels.base import BaseChannel from nanobot.config.paths import get_workspace_path from nanobot.config.schema import Base -MSTEAMS_AVAILABLE = importlib.util.find_spec("jwt") is not None +MSTEAMS_AVAILABLE = ( + importlib.util.find_spec("jwt") is not None + and importlib.util.find_spec("cryptography") is not None +) if TYPE_CHECKING: import jwt diff --git a/tests/test_msteams.py b/tests/test_msteams.py index 96020adec..67ffb8531 100644 --- a/tests/test_msteams.py +++ b/tests/test_msteams.py @@ -52,6 +52,9 @@ class FakeHttpClient: self.calls.append((url, kwargs)) return FakeResponse(self.payload, should_raise=self.should_raise) + async def aclose(self): + pass + @pytest.fixture def make_channel(tmp_path, monkeypatch):