Skip to content

feat(gateway): add Microsoft Teams platform integration#17683

Closed
heyitsaamir wants to merge 6 commits into
NousResearch:mainfrom
heyitsaamir:feat/teams-platform
Closed

feat(gateway): add Microsoft Teams platform integration#17683
heyitsaamir wants to merge 6 commits into
NousResearch:mainfrom
heyitsaamir:feat/teams-platform

Conversation

@heyitsaamir

@heyitsaamir heyitsaamir commented Apr 30, 2026

Copy link
Copy Markdown

What does this PR do?

Hello! I am the maintainer of the Teams SDK SDK (I maintain TS, Py, and .net) and I'm adding Microsoft Teams as a fully supported messaging platform in Hermes.

The gateway connects via a webhook server (aiohttp on port 3978) authenticated through the Azure Bot Framework, using the microsoft-teams-apps Python SDK.

Key highlights:

  • Interactive approval cards — instead of a plain-text /approve prompt, dangerous command approvals are delivered as Adaptive Cards with 4 buttons (Allow Once / Allow Session / Always Allow / Deny). Clicking a button resolves the approval inline and replaces the card with the decision, preventing double-clicks.
  • Correct send routing — stores the ConversationReference from each incoming message so cards (and future sends) work correctly in group chats and channels, not just DMs.
  • aiohttp bridge — avoids pulling in FastAPI/uvicorn; SDK routes are wired into a lightweight aiohttp server.

Related Issue

Fixes #

Type of Change

  • ✨ New feature (non-breaking change that adds functionality)
  • 📝 Documentation update

Changes Made

  • gateway/platforms/teams.py — new Teams adapter: webhook server, message handler, send_exec_approval() with Adaptive Cards, on_card_action handler, _send_card() with stored ConversationReference
  • gateway/config.py — add Platform.TEAMS enum value
  • gateway/run.py — wire up Teams adapter instantiation and TEAMS_ALLOWED_USERS allowlist check
  • hermes_cli/platforms.py — add "teams" entry to PLATFORMS registry
  • hermes_cli/gateway.py — add Teams to setup wizard
  • hermes_cli/status.py — add Teams home channel display
  • cron/scheduler.py — add "teams" delivery platform
  • tools/send_message_tool.py — add Teams dispatch
  • toolsets.py — add hermes-teams toolset
  • pyproject.toml — add microsoft-teams-apps>=2.0.0a1,<3 and aiohttp to messaging extra
  • docker-compose.yml — expose port 3978 for Teams webhook delivery
  • .env.example / cli-config.yaml.example — add Teams env vars and platform_toolsets entry
  • website/docs/user-guide/messaging/teams.md — full setup guide (tunnel options, Teams CLI, Docker, troubleshooting, security)
  • website/docs/user-guide/messaging/index.md — add Teams to platform comparison and toolset tables

How to Test

  1. Install Teams CLI: npm install -g @microsoft/teams.cli@preview && teams login
  2. Start a tunnel: ngrok http 3978 (or devtunnel / cloudflared)
  3. Create bot: teams app create --name "Hermes" --endpoint "https://<tunnel>/api/messages"
  4. Set TEAMS_CLIENT_ID, TEAMS_CLIENT_SECRET, TEAMS_TENANT_ID in ~/.hermes/.env
  5. HERMES_UID=$(id -u) HERMES_GID=$(id -g) docker compose up -d gateway
  6. teams app install --id <teamsAppId>
  7. DM the bot in Teams — it should respond
  8. Ask the bot to run a dangerous command (e.g. rm -rf /tmp/test) — an Adaptive Card with 4 approval buttons should appear

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this feature
  • I've run pytest tests/ -q and all tests pass — or N/A (no existing Teams tests to break)
  • I've tested on my platform: Windows 11 (WSL2 + Docker Desktop)

Documentation & Housekeeping

  • I've updated relevant documentation (website/docs/user-guide/messaging/teams.md)
  • I've updated cli-config.yaml.example with new config keys
  • I've considered cross-platform impact — N/A, the adapter is pure Python and runs on any platform Hermes supports

Screenshots / Logs

image

heyitsaamir and others added 5 commits April 30, 2026 00:57
Wire Teams as a new messaging platform using the microsoft-teams-apps SDK.
Uses an aiohttp webhook server (consistent with other webhook adapters)
and the SDK's App.initialize() + handle_request() for JWT validation
and activity dispatching. Proactive messaging via App.send().

All 16 ADDING_A_PLATFORM checklist items implemented:
- Platform enum, config loading (all 3 creds required: client_id, secret, tenant_id)
- Core adapter with aiohttp server on configurable port
- Factory, authorization maps (3), platform hints, toolset
- Cron delivery, send_message tool routing + standalone _send_teams()
- CLI status display, gateway setup wizard (Teams CLI instructions)
- 36 tests covering requirements, config, auth, routing, send, message handling
- Env vars documented
- Implement send_exec_approval() with 4-button Adaptive Card (Allow
  Once / Allow Session / Always Allow / Deny) replacing plain-text
  /approve prompt
- Register on_card_action handler that resolves gateway approval and
  replaces the card in-place with the decision (no double-click)
- Store ConversationReference per chat_id so cards send correctly in
  group chats and channels, not just DMs
- Add TEAMS_ALLOWED_USERS to allowlist check in run.py
- Add 'teams' entry to PLATFORMS registry in hermes_cli/platforms.py
- Fix pyproject.toml Teams SDK version constraint (>=2.0.0a1,<3)
- Expose Teams webhook port in docker-compose.yml
- Add Teams setup guide and platform comparison docs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add behavior table, Features section (approval cards, images), security
warning, troubleshooting table, and fix incorrect network_mode: host
reference. Aligns with Slack/Discord guide quality.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@heyitsaamir heyitsaamir marked this pull request as draft April 30, 2026 01:10
Add `from __future__ import annotations` to teams.py so type annotations
are evaluated lazily, avoiding `TypeError` when SDK classes are mocked
as MagicMock. Extend `_ensure_teams_mock()` in test_teams.py to cover
all new imports added for adaptive card support (invoke activity,
card/invoke response models, cards module, ConversationReference,
on_card_action) so the try-block in teams.py never falls to the
except-ImportError branch during testing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/gateway Gateway runner, session dispatch, delivery labels Apr 30, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Related to #9512 (original feature request), #10037, #13767, #16639 (prior Teams PRs). This appears to be the latest iteration from the Teams SDK maintainer.

@alt-glitch

Copy link
Copy Markdown
Collaborator

Related to #9512 (original feature request), #10037, #13767, #16639 (prior Teams PRs).

@heyitsaamir heyitsaamir marked this pull request as ready for review April 30, 2026 04:08
@heyitsaamir

Copy link
Copy Markdown
Author

Closing in favor of #17764

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery P3 Low — cosmetic, nice to have type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants