{"repo":"NousResearch/hermes-agent","public_id":"22015","display_label":"Microsoft Teams plugin packaging and Python version issues","summary":"These issues and PRs concern the Microsoft Teams platform plugin failing to load due to Python version constraints and packaging problems. Work focuses on making the Teams SDK an installable extra, documenting local installation, and adding clear error messaging for version incompatibilities.","subsystem":"docs","counts":{"members":6,"open_issues":0,"open_issues_distinct":0,"open_prs":0,"closed_issues":2,"merged_prs":1,"attempt_prs":3},"landed_fix":{"status":"merged_to_main","basis":"structural","pr":46764},"resolution":{"state":"unresolved","by":null},"freshness":{"state":"verified","last_verified_at":"2026-06-15T18:35:16+00:00","is_stale":false},"grouping":{"backbone":"STRUCTURAL_PARTIAL","link_density":0.29066666666666663},"fix_edges":[{"issue_number":22015,"pr_number":46764,"tier":"verified","basis":"superseded_ref","confidence":0.9,"recoverable_from_timeline":false}],"members":[{"kind":"issue","number":22015,"title":"[Bug]: microsoft-teams-apps Python package only available in Nous Docker image","url":null,"state":"closed"},{"kind":"issue","number":26083,"title":"Microsoft Teams platform plugin fails to load on bundled Python 3.11 — microsoft-teams-apps requires Python ≥ 3.12","url":null,"state":"closed"},{"kind":"pr","number":22229,"title":"fix: document local Microsoft Teams gateway install","url":null,"state":"closed","close_reason":{"refs":[{"kind":"commit","value":"5f6be7f31bd7ef53f92d030b060325783f84f169","number":0}],"category":"implemented_elsewhere","implication":"superseded"},"merged":false},{"kind":"pr","number":26094,"title":"fix(teams): add Python version check and clear error message for Teams plugin","url":null,"state":"closed","close_reason":{"category":"uncategorized","implication":"needs_llm"},"merged":false},{"kind":"pr","number":43945,"title":"fix(teams): package Microsoft Teams SDK as an installable extra","url":null,"state":"closed","close_reason":{"refs":[{"kind":"commit","value":"5f6be7f31","number":0},{"kind":"pr","value":"#46764","number":46764}],"category":"merged_via","implication":"superseded"},"merged":false},{"kind":"pr","number":46764,"title":"fix(teams): package Microsoft Teams SDK as an installable extra (salvage #43945)","url":null,"state":"merged","close_reason":{"category":"merged","implication":"superseded"},"merged":true,"is_fix_pr":true,"fix_tier":"verified","files_changed":["plugins/platforms/teams/adapter.py","pyproject.toml","scripts/release.py","tests/gateway/test_teams.py","tools/lazy_deps.py","website/docs/user-guide/messaging/teams.md"],"fix_hunks":[{"file":"plugins/platforms/teams/adapter.py","hunks":["@@ -617,7 +617,74 @@ async def _standalone_send(\n \n \n # Keep the old name as an alias so existing test imports don't break.\n-check_teams_requirements = check_requirements\n+# NOTE: ``check_requirements`` is the PASSIVE probe (used as the registry\n+# ``check_fn`` and by ``gateway status``) — it must never trigger a pip\n+# install. ``check_teams_requirements`` is the ACTIVE lazy-installer called\n+# from ``connect()``; it installs ``platform.teams`` on demand and rebinds the\n+# SDK globals, mirroring ``check_slack_requirements`` in gateway/platforms/slack.py.\n+def check_teams_requirements() -> bool:\n+    \"\"\"Ensure the Teams SDK is importable, lazy-installing it on first use.\n+\n+    Lazy-installs ``microsoft-teams-apps`` via\n+    ``tools.lazy_deps.ensure(\"platform.teams\")`` if not present, then rebinds\n+    all module-level SDK globals on success. Returns True once the SDK (and\n+    aiohttp) are importable, False if they couldn't be installed/imported.\n+    \"\"\"\n+    if TEAMS_SDK_AVAILABLE and AIOHTTP_AVAILABLE:\n+        return True\n+\n+    def _import() -> dict:\n+        from aiohttp import web as _web\n+        from microsoft_teams.apps import App, ActivityContext\n+        from microsoft_teams.common.http.client import ClientOptions\n+        from microsoft_teams.api import MessageActivity, ConversationReference\n+        from microsoft_teams.api.activities.typing import TypingActivityInput\n+        from microsoft_teams.api.activities.invoke.adaptive_card import (\n+            AdaptiveCardInvokeActivity,\n+        )\n+        from microsoft_teams.api.models.adaptive_card import (\n+            AdaptiveCardActionCardResponse,\n+            AdaptiveCardActionMessageResponse,\n+        )\n+        from microsoft_teams.api.models.invoke_response import (\n+            InvokeResponse,\n+            AdaptiveCardInvokeResponse,\n+        )\n+        from microsoft_teams.apps.http.adapter import (\n+            HttpMethod,\n+            HttpRequest,\n+            HttpResponse,\n+            HttpRouteHandler,\n+        )\n+        from microsoft_teams.cards import AdaptiveCard, ExecuteAction, TextBlock\n+\n+        return {\n+            \"web\": _web,\n+            \"AIOHTTP_AVAILABLE\": True,\n+            \"App\": App,\n+            \"ActivityContext\": ActivityContext,\n+            \"ClientOptions\": ClientOptions,\n+            \"MessageActivity\": MessageActivity,\n+            \"ConversationReference\": ConversationReference,\n+            \"TypingActivityInput\": TypingActivityInput,\n+            \"AdaptiveCardInvokeActivity\": AdaptiveCardInvokeActivity,\n+            \"AdaptiveCardActionCardResponse\": AdaptiveCardActionCardResponse,\n+            \"AdaptiveCardActionMessageResponse\": AdaptiveCardActionMessageResponse,\n+            \"InvokeResponse\": InvokeResponse,\n+            \"AdaptiveCardInvokeResponse\": AdaptiveCardInvokeResponse,\n+            \"HttpMethod\": HttpMethod,\n+            \"HttpRequest\": HttpRequest,\n+            \"HttpResponse\": HttpResponse,\n+            \"HttpRouteHandler\": HttpRouteHandler,\n+            \"AdaptiveCard\": AdaptiveCard,\n+            \"ExecuteAction\": ExecuteAction,\n+            \"TextBlock\": TextBlock,\n+            \"TEAMS_SDK_AVAILABLE\": True,\n+        }\n+\n+    from tools.lazy_deps import ensure_and_bind\n+\n+    return ensure_and_bind(\"platform.teams\", _import, globals(), prompt=False)\n \n \n class TeamsAdapter(BasePlatformAdapter):","@@ -642,10 +709,13 @@ def __init__(self, config: PlatformConfig):\n         self._conv_refs: Dict[str, Any] = {}\n \n     async def connect(self) -> bool:\n+        # Lazy-install the Teams SDK on demand (parity with Slack/Discord/etc.),\n+        # then re-check the module globals it rebinds.\n+        check_teams_requirements()\n         if not TEAMS_SDK_AVAILABLE:\n             self._set_fatal_error(\n                 \"MISSING_SDK\",\n-                \"microsoft-teams-apps not installed. Run: pip install microsoft-teams-apps\",\n+                \"microsoft-teams-apps could not be installed. Run: pip install microsoft-teams-apps\",\n                 retryable=False,\n             )\n             return False"]},{"file":"pyproject.toml","hunks":["@@ -179,6 +179,7 @@ mcp = [\"mcp==1.26.0\", \"starlette==1.0.1\"]  # starlette: CVE-2026-48710\n nemo-relay = [\"nemo-relay==0.3\"]\n homeassistant = [\"aiohttp==3.13.4\"]\n sms = [\"aiohttp==3.13.4\"]\n+teams = [\"microsoft-teams-apps==2.0.13.4\", \"aiohttp==3.13.4\"]\n # Computer use — macOS background desktop control via cua-driver (MCP stdio).\n # The cua-driver binary itself is installed via `hermes tools` post-setup\n # (curl install script); this extra just pins the MCP client used to talk"]},{"file":"scripts/release.py","hunks":["@@ -45,6 +45,7 @@\n \n # Auto-extracted from noreply emails + manual overrides\n AUTHOR_MAP = {\n+    \"[redacted:email]\": \"rio-jeong\",\n     \"[redacted:email]\": \"ArcanePivot\",\n     \"[redacted:email]\": \"benegessarit\",\n     \"[redacted:email]\": \"Kenmege\","]},{"file":"tests/gateway/test_teams.py","hunks":["@@ -211,10 +211,39 @@ def test_returns_true_when_deps_available(self, monkeypatch):\n         monkeypatch.setattr(_teams_mod, \"AIOHTTP_AVAILABLE\", True)\n         assert check_requirements() is True\n \n-    def test_alias_matches(self, monkeypatch):\n+    def test_check_teams_requirements_shortcircuits_when_present(self, monkeypatch):\n+        # When the SDK + aiohttp are already importable, the active lazy-\n+        # installer returns True immediately without attempting an install.\n         monkeypatch.setattr(_teams_mod, \"TEAMS_SDK_AVAILABLE\", True)\n         monkeypatch.setattr(_teams_mod, \"AIOHTTP_AVAILABLE\", True)\n+        called = {\"ensure_and_bind\": 0}\n+\n+        def _fake_ensure_and_bind(*_args, **_kwargs):\n+            called[\"ensure_and_bind\"] += 1\n+            return True\n+\n+        monkeypatch.setattr(\n+            \"tools.lazy_deps.ensure_and_bind\", _fake_ensure_and_bind\n+        )\n+        assert check_teams_requirements() is True\n+        assert called[\"ensure_and_bind\"] == 0\n+\n+    def test_check_teams_requirements_lazy_installs_when_missing(self, monkeypatch):\n+        # When deps are missing, the active installer delegates to\n+        # ensure_and_bind(\"platform.teams\", ...) — parity with Slack/Discord.\n+        monkeypatch.setattr(_teams_mod, \"TEAMS_SDK_AVAILABLE\", False)\n+        monkeypatch.setattr(_teams_mod, \"AIOHTTP_AVAILABLE\", False)\n+        seen = {}\n+\n+        def _fake_ensure_and_bind(feature, importer, target_globals, **kwargs):\n+            seen[\"feature\"] = feature\n+            return True\n+\n+        monkeypatch.setattr(\n+            \"tools.lazy_deps.ensure_and_bind\", _fake_ensure_and_bind\n+        )\n         assert check_teams_requirements() is True\n+        assert seen[\"feature\"] == \"platform.teams\"\n \n     def test_validate_config_with_env(self, monkeypatch):\n         monkeypatch.setenv(\"TEAMS_CLIENT_ID\", \"test-id\")","@@ -371,6 +400,13 @@ class TestTeamsConnect:\n     @pytest.mark.anyio\n     async def test_connect_fails_without_sdk(self, monkeypatch):\n         monkeypatch.setattr(_teams_mod, \"TEAMS_SDK_AVAILABLE\", False)\n+        # Simulate the SDK being unavailable AND not installable (offline /\n+        # locked-down env): the lazy-installer can't rebind the globals, so\n+        # TEAMS_SDK_AVAILABLE stays False and connect() must fail.\n+        monkeypatch.setattr(\n+            \"tools.lazy_deps.ensure_and_bind\",\n+            lambda *_a, **_k: False,\n+        )\n         adapter = TeamsAdapter(_make_config(\n             client_id=\"id\", client_secret=\"[redacted:secret-assignment]\", tenant_id=\"tenant\",\n         ))"]},{"file":"tools/lazy_deps.py","hunks":["@@ -152,6 +152,11 @@\n     # defusedxml only; aiohttp/httpx are core dependencies of every messaging\n     # adapter and ship via `platform.discord` / `platform.slack` / etc.\n     \"platform.wecom_callback\": (\"defusedxml==0.7.1\",),\n+    # Microsoft Teams adapter — microsoft-teams-apps pulls a heavy tree\n+    # (microsoft-teams-api/cards/common, dependency-injector, msal). Lazy-\n+    # installed on demand like every other messaging platform; also exposed\n+    # as the `teams` extra in pyproject for packagers / explicit installs.\n+    \"platform.teams\": (\"microsoft-teams-apps==2.0.13.4\", \"aiohttp==3.13.4\"),\n \n     # ─── Terminal backends ─────────────────────────────────────────────────\n     \"terminal.modal\": (\"modal==1.3.4\",),"]},{"file":"uv.lock","hunks":["@@ -960,6 +960,28 @@ wheels = [\n     { url = \"https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl\", hash = \"sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61\", size = 25604, upload-time = \"2021-03-08T10:59:24.45Z\" },\n ]\n \n+[[package]]\n+name = \"dependency-injector\"\n+version = \"4.49.0\"\n+source = { registry = \"https://pypi.org/simple\" }\n+dependencies = [\n+    { name = \"typing-extensions\", marker = \"python_full_version < '3.13'\" },\n+]\n+sdist = { url = \"https://files.pythonhosted.org/packages/f3/be/26bb530d06618fb0bb34244d46b0d0ccc53d0974e680d8653f1b1b313a0e/dependency_injector-4.49.0.tar.gz\", hash = \"sha256:17a04dbfaa8159f1dc068fc26bc2fa0af9774cdd87f99e3b61bd74c9e7171589\", size = 1168930, upload-time = \"2026-03-22T21:20:05.524Z\" }\n+wheels = [\n+    { url = \"https://files.pythonhosted.org/packages/5c/5d/cc49fb34e0c03aa56d7583de00e2f8f5aa1b8a878b695e970dcdb751a477/dependency_injector-4.49.0-cp310-abi3-macosx_11_0_arm64.whl\", hash = \"sha256:9690192fd5aed07f21dfdfae07696fef12c68bf98e4c0e1af8f8128b255a74a7\", size = 1769395, upload-time = \"2026-03-22T21:19:14.163Z\" },\n+    { url = \"https://files.pythonhosted.org/packages/7f/97/b3b144c96e1f7fff0a7e2e83eb0767bd23b6bacffd0ac8cff397d350e94d/dependency_injector-4.49.0-cp310-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl\", hash = \"sha256:f91f2a191bdb17bd3068f32fe65f04128bc162c6237ea554c117b303c22aaabb\", size = 1852089, upload-time = \"2026-03-22T21:19:16.354Z\" },\n+    { url = \"https://files.pythonhosted.org/packages/4c/e7/33061f427bcb56c8936d5db464d757d926bf752a874683fb64b2ee225463/dependency_injector-4.49.0-cp310-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl\", hash = \"sha256:733c0d88b26be17a48e5741cc3e3956080112e40c07a38ff38e99dfa772f9772\", size = 1765608, upload-time = \"2026-03-22T21:19:19.217Z\" },\n+    { url = \"https://files.pythonhosted.org/packages/1e/4d/2751a6c055de4a200d65af297ecd926d6b6107f66f3849e8122928abf461/dependency_injector-4.49.0-cp310-abi3-musllinux_1_2_aarch64.whl\", hash = \"sha256:45720b30a2a3df6e5e2320e242f6dd94540ba27c3da57cafdc37fdeec59d5ce3\", size = 1746555, upload-time = \"2026-03-22T21:19:21.231Z\" },\n+    { url = \"https://files.pythonhosted.org/packages/02/6f/f74fee9629528f0879295b9f89a5c751d3ad931eca0c78407f715e5472a6/dependency_injector-4.49.0-cp310-abi3-musllinux_1_2_x86_64.whl\", hash = \"sha256:3b5d2f1be2dc971db47b1305a83b5a8c24d0eba7fb4cea7845679f9c9f24a0a9\", size = 1843223, upload-time = \"2026-03-22T21:19:23.356Z\" },\n+    { url = \"https://files.pythonhosted.org/packages/c5/f0/45948c7c933f063039a44afb4bd61747a7bafd50693e6ccdc972fac0839c/dependency_injector-4.49.0-cp310-abi3-win32.whl\", hash = \"sha256:0593c8aaade651a5a88ff8ba1271a8364773e76d3aa2efbeacc3be4969cafd1c\", size = 1546172, upload-time = \"2026-03-22T21:19:25.392Z\" },\n+    { url = \"https://files.pythonhosted.org/packages/e2/b5/1d8e5627137cb9a6812ecaa468eaf39154f6605c5088da4749e5a8579483/dependency_injector-4.49.0-cp310-abi3-win_amd64.whl\", hash = \"sha256:fa4b587158b0d65a1f9681ca648da3f9bf90f312f68c2f2e73cc58296ec2bf45\", size = 1674743, upload-time = \"2026-03-22T21:19:27.018Z\" },\n+    { url = \"https://files.pythonhosted.org/packages/92/35/ca21ab897fc193dcdbad1f856361e7614b8e2b69f9f9351e9a87a3c58e51/dependency_injector-4.49.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl\", hash = \"sha256:6c4b49df30f13f5e4361719b21c79445db11869a7a00d80a0486c03fd764ba8f\", size = 1744444, upload-time = \"2026-03-22T21:19:57.332Z\" },\n+    { url = \"https://files.pythonhosted.org/packages/25/44/d108aeee8f2edd3e725ac0e32d16e4339a034a07da9ddaf07f772f425140/dependency_injector-4.49.0-pp311-pypy311_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl\", hash = \"sha256:4b0c637ba230e390631da13bb80c955a9f85487f78c9772c0f6a3b50bfbff3a6\", size = 1822320, upload-time = \"2026-03-22T21:19:59.334Z\" },\n+    { url = \"https://files.pythonhosted.org/packages/35/32/6243ef32c384dda156b053c3df5c8b6c3ac42250ec089a09915f015d38a1/dependency_injector-4.49.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl\", hash = \"sha256:a5857b2672512654110dd0371fa965b98255e2f0507dd4732a066767b72e23c4\", size = 1741215, upload-time = \"2026-03-22T21:20:01.523Z\" },\n+    { url = \"https://files.pythonhosted.org/packages/b9/52/a1957d4ef87a52c13f2b790c1cc5fae17eb385fbe2e978c7fd8c1ebb4ea9/dependency_injector-4.49.0-pp311-pypy311_pp73-win_amd64.whl\", hash = \"sha256:8ffa2ac9297446f73bd28ada81aadf4494a52d869159d58923435bcd88b5ef60\", size = 1652017, upload-time = \"2026-03-22T21:20:03.653Z\" },\n+]\n+\n [[package]]\n name = \"deprecated\"\n version = \"1.3.1\"","@@ -1542,6 +1564,10 @@ slack = [\n sms = [\n     { name = \"aiohttp\" },\n ]\n+teams = [\n+    { name = \"aiohttp\" },\n+    { name = \"microsoft-teams-apps\" },\n+]\n termux = [\n     { name = \"agent-client-protocol\" },\n     { name = \"honcho-ai\" },","@@ -1591,6 +1617,7 @@ requires-dist = [\n     { name = \"aiohttp\", marker = \"extra == 'messaging'\", specifier = \"==3.13.4\" },\n     { name = \"aiohttp\", marker = \"extra == 'slack'\", specifier = \"==3.13.4\" },\n     { name = \"aiohttp\", marker = \"extra == 'sms'\", specifier = \"==3.13.4\" },\n+    { name = \"aiohttp\", marker = \"extra == 'teams'\", specifier = \"==3.13.4\" },\n     { name = \"aiohttp-socks\", marker = \"extra == 'matrix'\", specifier = \"==0.11.0\" },\n     { name = \"aiosqlite\", marker = \"extra == 'matrix'\", specifier = \"==0.22.1\" },\n     { name = \"alibabacloud-dingtalk\", marker = \"extra == 'dingtalk'\", specifier = \"==2.2.42\" },","@@ -1649,6 +1676,7 @@ requires-dist = [\n     { name = \"mcp\", marker = \"extra == 'computer-use'\", specifier = \"==1.26.0\" },\n     { name = \"mcp\", marker = \"extra == 'dev'\", specifier = \"==1.26.0\" },\n     { name = \"mcp\", marker = \"extra == 'mcp'\", specifier = \"==1.26.0\" },\n+    { name = \"microsoft-teams-apps\", marker = \"extra == 'teams'\", specifier = \"==2.0.13.4\" },\n     { name = \"mistralai\", marker = \"extra == 'mistral'\", specifier = \"==2.4.8\" },\n     { name = \"modal\", marker = \"extra == 'modal'\", specifier = \"==1.3.4\" },\n     { name = \"nemo-relay\", marker = \"extra == 'nemo-relay'\", specifier = \"==0.3\" },","@@ -1697,7 +1725,7 @@ requires-dist = [\n     { name = \"websockets\", specifier = \"==15.0.1\" },\n     { name = \"youtube-transcript-api\", marker = \"extra == 'youtube'\", specifier = \"==1.2.4\" },\n ]\n-provides-extras = [\"anthropic\", \"exa\", \"firecrawl\", \"parallel-web\", \"fal\", \"edge-tts\", \"modal\", \"daytona\", \"hindsight\", \"dev\", \"messaging\", \"cron\", \"slack\", \"matrix\", \"wecom\", \"cli\", \"tts-premium\", \"voice\", \"pty\", \"honcho\", \"vision\", \"mcp\", \"nemo-relay\", \"homeassistant\", \"sms\", \"computer-use\", \"acp\", \"mistral\", \"bedrock\", \"azure-identity\", \"termux\", \"termux-all\", \"dingtalk\", \"feishu\", \"google\", \"youtube\", \"web\", \"all\"]\n+provides-extras = [\"anthropic\", \"exa\", \"firecrawl\", \"parallel-web\", \"fal\", \"edge-tts\", \"modal\", \"daytona\", \"hindsight\", \"dev\", \"messaging\", \"cron\", \"slack\", \"matrix\", \"wecom\", \"cli\", \"tts-premium\", \"voice\", \"pty\", \"honcho\", \"vision\", \"mcp\", \"nemo-relay\", \"homeassistant\", \"sms\", \"teams\", \"computer-use\", \"acp\", \"mistral\", \"bedrock\", \"azure-identity\", \"termux\", \"termux-all\", \"dingtalk\", \"feishu\", \"google\", \"youtube\", \"web\", \"all\"]\n \n [[package]]\n name = \"hf-xet\"","@@ -2176,6 +2204,63 @@ wheels = [\n     { url = \"https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl\", hash = \"sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8\", size = 9979, upload-time = \"2022-08-14T12:40:09.779Z\" },\n ]\n \n+[[package]]\n+name = \"microsoft-teams-api\"\n+version = \"2.0.13.4\"\n+source = { registry = \"https://pypi.org/simple\" }\n+dependencies = [\n+    { name = \"microsoft-teams-cards\" },\n+    { name = \"microsoft-teams-common\" },\n+    { name = \"pydantic\" },\n+    { name = \"pyjwt\", extra = [\"crypto\"] },\n+]\n+sdist = { url = \"https://files.pythonhosted.org/packages/e1/7f/dc1995f72a8d23e723b168db20bac67b819ef2fa734bc23f63bc8086c41b/microsoft_teams_api-2.0.13.4.tar.gz\", hash = \"sha256:d16f88ae90f65bcce83ede9ecc57773f7b1a19cbecde63be624b586b59e34fc9\", size = 51779, upload-time = \"2026-06-08T19:24:02.661Z\" }\n+wheels = [\n+    { url = \"https://files.pythonhosted.org/packages/27/15/e1a1369a22c265b52da3ac4b3ee67b5c02911300db045894868bd7be932f/microsoft_teams_api-2.0.13.4-py3-none-any.whl\", hash = \"sha256:be52ef7765ea5851e0982de1ff6b1192869c85fc74e890ae20029bd99064b532\", size = 149825, upload-time = \"2026-06-08T19:24:13.202Z\" },\n+]\n+\n+[[package]]\n+name = \"microsoft-teams-apps\"\n+version = \"2.0.13.4\"\n+source = { registry = \"https://pypi.org/simple\" }\n+dependencies = [\n+    { name = \"cryptography\" },\n+    { name = \"dependency-injector\" },\n+    { name = \"fastapi\" },\n+    { name = \"microsoft-teams-api\" },\n+    { name = \"microsoft-teams-common\" },\n+    { name = \"msal\" },\n+    { name = \"pydantic-settings\" },\n+    { name = \"pyjwt\", extra = [\"crypto\"] },\n+    { name = \"python-dotenv\" },\n+    { name = \"uvicorn\" },\n+]\n+sdist = { url = \"https://files.pythonhosted.org/packages/61/0a/733f05f8decee2da6e53ee38757e742520ae56363bc2d006b309cdbf9cfe/microsoft_teams_apps-2.0.13.4.tar.gz\", hash = \"sha256:d0b12e5e82024cffd3739b329b098b98a08803753eb5484bf96dbb6ce1237e04\", size = 91366, upload-time = \"2026-06-08T19:24:04.591Z\" }\n+wheels = [\n+    { url = \"https://files.pythonhosted.org/packages/3a/d4/3c4205258642035d160c09f598a302260776dcb6d5bdf659eea7c6066d5e/microsoft_teams_apps-2.0.13.4-py3-none-any.whl\", hash = \"sha256:db16f714ec658b592929c6386a29792e90bb73840732f8ae65a198cda1fea96c\", size = 71406, upload-time = \"2026-06-08T19:24:15.034Z\" },\n+]\n+\n+[[package]]\n+name = \"microsoft-teams-cards\"\n+version = \"2.0.13.4\"\n+source = { registry = \"https://pypi.org/simple\" }\n+sdist = { url = \"https://files.pythonhosted.org/packages/ef/7f/cce9633f635d9e1b2318ce2146a804a14a46c9e34e855c3784beb8ab39b3/microsoft_teams_cards-2.0.13.4.tar.gz\", hash = \"sha256:de54956a2afbbcf187f2531459967515b4f4743fa784bd0f454eaff1ac675c90\", size = 28108, upload-time = \"2026-06-08T19:24:07.841Z\" }\n+wheels = [\n+    { url = \"https://files.pythonhosted.org/packages/20/09/95cad44d4417e33df11a15c82ca1bde442c1f1f77396f936f18896f116c1/microsoft_teams_cards-2.0.13.4-py3-none-any.whl\", hash = \"sha256:b8b887466c8144675ff5704064daf05ec3ebdf4d322658ab9a25bfc1373d7909\", size = 29617, upload-time = \"2026-06-08T19:24:17.373Z\" },\n+]\n+\n+[[package]]\n+name = \"microsoft-teams-common\"\n+version = \"2.0.13.4\"\n+source = { registry = \"https://pypi.org/simple\" }\n+dependencies = [\n+    { name = \"httpx\" },\n+]\n+sdist = { url = \"https://files.pythonhosted.org/packages/6c/f1/a32821cfdde6c0d33a1e4022492a2211af670a81ec1fab727c49cddd4f7a/microsoft_teams_common-2.0.13.4.tar.gz\", hash = \"sha256:ed3175316f77f083a500da0a84ddf53ac31c6de008a252f0cfd86bdb70120bf3\", size = 11122, upload-time = \"2026-06-08T19:24:09.694Z\" }\n+wheels = [\n+    { url = \"https://files.pythonhosted.org/packages/cb/04/859b3d7fadd1d61ab581f79afb6125c16c60cecf2a2e6bbb2ebbcfd34f80/microsoft_teams_common-2.0.13.4-py3-none-any.whl\", hash = \"sha256:19524ec75587d797d07c5a78e9b72921b6d58f33d39512ca2d33468160fd0d82\", size = 16588, upload-time = \"2026-06-08T19:24:18.325Z\" },\n+]\n+\n [[package]]\n name = \"mistralai\"\n version = \"2.4.8\""]},{"file":"website/docs/user-guide/messaging/teams.md","hunks":["@@ -24,6 +24,15 @@ Teams delivers @mentions as regular messages with `<at>BotName</at>` tags, which\n \n ---\n \n+For source or local installs, include the Teams extra so the bundled adapter can\n+import the Microsoft Teams SDK:\n+\n+```bash\n+uv sync --extra teams\n+# or, for editable installs:\n+uv pip install -e \".[teams]\"\n+```\n+\n ## Step 1: Install the Teams CLI\n \n The `@microsoft/teams.cli` automates bot registration — no Azure portal needed.\n"]}]}],"trust":{"default_tier":"verified","includes_suggested":false}}