Skip to content

feat: add Microsoft Teams gateway adapter with OpenClaw parity#10037

Open
shuwenjunn wants to merge 2 commits into
NousResearch:mainfrom
shuwenjunn:feat/msteams-openclaw-parity
Open

feat: add Microsoft Teams gateway adapter with OpenClaw parity#10037
shuwenjunn wants to merge 2 commits into
NousResearch:mainfrom
shuwenjunn:feat/msteams-openclaw-parity

Conversation

@shuwenjunn

Copy link
Copy Markdown

Summary

  • add a native Microsoft Teams gateway adapter with Bot Framework ingress and Microsoft Graph helpers
  • implement OpenClaw-parity Teams messaging flows: mentions, cards, polls, direct sends, FileConsentCard DM uploads, SharePoint group/channel uploads, Graph fallback media recovery, and core message actions
  • wire Teams through Hermes gateway config, CLI surfaces, toolsets, send_message delivery, tests, and user docs

What’s included

  • new Teams platform modules:
    • gateway/platforms/msteams.py
    • gateway/platforms/msteams_graph.py
    • gateway/platforms/msteams_mentions.py
    • gateway/platforms/msteams_state.py
  • gateway/config/runtime integration for msteams
  • send_message and cron delivery support for Teams proactive sends
  • Graph-backed actions and enrichments:
    • read / edit / delete
    • pin / unpin / list-pins
    • react / unreact / reactions
    • search
    • member-info
    • channel-list / channel-info
  • docs:
    • Teams messaging guide
    • environment variable reference
    • messaging index updates
  • comprehensive Teams regression tests

Validation

python -m pytest tests/gateway/test_msteams.py tests/gateway/test_send_image_file.py tests/gateway/test_webhook_adapter.py tests/cli/test_cli_init.py -q -o addopts=

Result:

  • 168 passed

Notes

  • proactive/direct Teams sends require a persisted conversation reference for the target conversation
  • reaction operations follow the current OpenClaw/Graph beta behavior

@wupatrick2025-code

Copy link
Copy Markdown

tested this branch in my environment and it works for text chat, but not support attachment like picture or file.

@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 26, 2026
satscryption added a commit to satscryption/Hermes-A365 that referenced this pull request May 5, 2026
Bot Framework / A365 channel infra retries deliveries on 5xx and slow
ACK; without a dedupe the operator webhook is hit multiple times for
the same activity. Add a TTL-keyed in-memory cache on
`(conversationId, activityId)` so duplicate POSTs short-circuit
before touching the webhook.

`_IdempotencyCache` is a small TTL-pruned dict (matching the
`_JwksCache` pattern), driven by `BridgeConfig.idempotency_ttl_seconds`
(default 1h). Activities without either id (channel-control flows
sometimes lack `id`) bypass dedupe — better to over-deliver than to
risk dropping legitimate traffic on missing-id alone.

Pattern adapted from NousResearch/hermes-agent#10037
(`gateway/platforms/msteams.py::_is_duplicate_delivery`). Their
adapter is classic-BF shaped (issue #7) so we re-implement in our
idiom rather than vendor.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
satscryption added a commit to satscryption/Hermes-A365 that referenced this pull request May 5, 2026
The bridge's outbound reply path POSTs the inbound activity's
`serviceUrl` plus a freshly minted user-FIC bearer for the Messaging
Bot API SP. JWT validation (slice 19f) ties that bearer to our
tenant + audience, but once we POST to the URL the destination has
full control over the bearer's traffic. A forged or malformed
activity could redirect us anywhere.

Gate the messages handler on `_is_trusted_service_url(activity.serviceUrl,
cfg.trusted_service_url_suffixes)` — must be `https`, must have a
hostname, and the hostname must end with one of the configured DNS
suffixes. Untrusted: 403 with `untrusted serviceUrl: <repr>`.

Default suffixes adapted from NousResearch/hermes-agent#10037's
`TRUSTED_SERVICE_URL_HOST_SUFFIXES`. The round-3 walkthrough pinned
real Teams traffic at `*.trafficmanager.net` so that's the
load-bearing entry; `.botframework.com`, `.botframework.us`,
`.cloud.microsoft`, `.azure.com` cover cross-channel and Bot
Service-hosted endpoints.

The DNS-boundary detail matters: each suffix carries a leading `.`
so `evil-trafficmanager.net` doesn't slip through a naive endswith.
Tested.

Empty `cfg.trusted_service_url_suffixes` is treated as a config bug
and 403s every request, matching the empty-allowlist behaviour from
slice 19f.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
satscryption pushed a commit to satscryption/Hermes-A365 that referenced this pull request May 12, 2026
After the 2026-05-12 walkthrough surfaced Azure Bot Service as a
hard prerequisite for Custom Engine Agent / Copilot Chat
surfacing, the project's value props sharpen materially:

- Path A (AI Teammate): agent-as-M365-tenant-directory-identity.
  Teams 1:1 chat with M365-native identity. No Azure subscription.
- Path B (Custom Engine Agent + Azure Bot Service): Copilot Chat
  agents picker + side-panels in Word/Excel/PowerPoint/Outlook.
  Requires Azure subscription.

Both are structurally distinct from Hermes' sibling Teams adapter
at plugins/platforms/teams/adapter.py (classic Bot Framework,
shipped v2026.4.30; in-flight in NousResearch/hermes-agent#10037
and #13767). The sibling has none of:
- M365 tenant directory identity (Path A's value prop)
- Copilot Chat fabric surfacing (Path B's value prop)

And Hermes-A365 has none of the sibling's:
- Generic Teams chat reach (group, channel, threading,
  attachments without M365 directory presence)

So no overlap. The reframe makes that explicit.

Changes:
- references/m365-surface-coverage.md -- new "Positioning"
  section with two-path table, sibling-plugin signposts, when-
  to-pick-what guidance. Coverage matrix rewritten to attribute
  each surface to its right home (Hermes-A365 Path A / Path B /
  sibling / separate skill). Validation status updated for
  round-8 + slice 19u-a. Highest-value walkthroughs ranked
  against unique Hermes-A365 lane.
- README.md -- new "Hermes-A365 vs sibling Teams plugins"
  section near the top. Surface table reworked for path
  attribution. Known limitations refreshed (streaming shipped,
  wizard shipped, Path B Azure prerequisite documented, #25 +
  #26 follow-ups listed).
- SKILL.md -- frontmatter description and Overview rewritten
  with two-path framing + sibling-plugin distinction. When/
  Don't-Use sections clarified. Surfaces-that-work-today
  refreshed for round-8 + slice 19u-a + Path B Azure
  prerequisite.

Issue cleanup:
- #17 (Teams group + channel walkthrough) closed -- explicitly
  sibling-plugin lane under reframe.
- #18 (invoke activities umbrella) scope-narrowed via comment
  -- composeExtension invokes move to sibling lane; Path
  B-relevant invokes (Outlook task/* via Copilot, search,
  signin/verifyState) stay.
- #16 (Copilot Chat walkthrough) classified as Path B's
  primary validation in comment.
- Upstream comment posted on NousResearch/hermes-agent#20133
  to clarify the non-overlap to maintainers.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

3 participants