mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-17 09:41:58 +00:00
* fix(teams): package Microsoft Teams SDK as an installable extra The Teams adapter imports the microsoft-teams-apps SDK, but it was never declared as a dependency, so source/local installs hit ImportError and the adapter silently reported the SDK as unavailable. Add a 'teams' extra (microsoft-teams-apps==2.0.13.4 + aiohttp) and document 'uv sync --extra teams'. Per the 2026-05-12 [all] policy, opt-in messaging-platform SDKs are NOT added to [all] (they would break every fresh install on a quarantined release); the teams extra is installed on demand like the other platform backends. Co-authored-by: rio-jeong <rio.jeong@thebytesize.ai> * chore: map rio-jeong contributor email for attribution (#43945) * feat(teams): lazy-install the Teams SDK on demand (parity with other channels) The teams extra alone left Teams as the only messaging platform that wouldn't auto-install its SDK — every other channel (telegram, discord, slack, matrix, dingtalk, feishu) lazy-installs via tools.lazy_deps on first connect. Bring Teams to parity: - Add 'platform.teams' to LAZY_DEPS (microsoft-teams-apps + aiohttp). - Replace the passive 'check_teams_requirements = check_requirements' alias with a real lazy-installer that calls ensure_and_bind('platform.teams', ...), rebinding all Teams SDK globals on success (mirrors check_slack_requirements). - Call check_teams_requirements() at the top of TeamsAdapter.connect() so enabling Teams installs the SDK on demand. - Keep the passive check_requirements() as the registry check_fn so 'gateway status' probes never trigger a pip install. The 'teams' extra remains for packagers / explicit 'uv sync --extra teams'. Tests: rework the alias test into shortcircuit + lazy-install assertions, and update test_connect_fails_without_sdk to simulate an uninstallable SDK. --------- Co-authored-by: rio-jeong <rio.jeong@thebytesize.ai> Co-authored-by: Teknium <127238744+teknium1@users.noreply.github.com>
This commit is contained in:
parent
0bbf325a8f
commit
5f6be7f31b
7 changed files with 211 additions and 4 deletions
|
|
@ -617,7 +617,74 @@ async def _standalone_send(
|
|||
|
||||
|
||||
# Keep the old name as an alias so existing test imports don't break.
|
||||
check_teams_requirements = check_requirements
|
||||
# NOTE: ``check_requirements`` is the PASSIVE probe (used as the registry
|
||||
# ``check_fn`` and by ``gateway status``) — it must never trigger a pip
|
||||
# install. ``check_teams_requirements`` is the ACTIVE lazy-installer called
|
||||
# from ``connect()``; it installs ``platform.teams`` on demand and rebinds the
|
||||
# SDK globals, mirroring ``check_slack_requirements`` in gateway/platforms/slack.py.
|
||||
def check_teams_requirements() -> bool:
|
||||
"""Ensure the Teams SDK is importable, lazy-installing it on first use.
|
||||
|
||||
Lazy-installs ``microsoft-teams-apps`` via
|
||||
``tools.lazy_deps.ensure("platform.teams")`` if not present, then rebinds
|
||||
all module-level SDK globals on success. Returns True once the SDK (and
|
||||
aiohttp) are importable, False if they couldn't be installed/imported.
|
||||
"""
|
||||
if TEAMS_SDK_AVAILABLE and AIOHTTP_AVAILABLE:
|
||||
return True
|
||||
|
||||
def _import() -> dict:
|
||||
from aiohttp import web as _web
|
||||
from microsoft_teams.apps import App, ActivityContext
|
||||
from microsoft_teams.common.http.client import ClientOptions
|
||||
from microsoft_teams.api import MessageActivity, ConversationReference
|
||||
from microsoft_teams.api.activities.typing import TypingActivityInput
|
||||
from microsoft_teams.api.activities.invoke.adaptive_card import (
|
||||
AdaptiveCardInvokeActivity,
|
||||
)
|
||||
from microsoft_teams.api.models.adaptive_card import (
|
||||
AdaptiveCardActionCardResponse,
|
||||
AdaptiveCardActionMessageResponse,
|
||||
)
|
||||
from microsoft_teams.api.models.invoke_response import (
|
||||
InvokeResponse,
|
||||
AdaptiveCardInvokeResponse,
|
||||
)
|
||||
from microsoft_teams.apps.http.adapter import (
|
||||
HttpMethod,
|
||||
HttpRequest,
|
||||
HttpResponse,
|
||||
HttpRouteHandler,
|
||||
)
|
||||
from microsoft_teams.cards import AdaptiveCard, ExecuteAction, TextBlock
|
||||
|
||||
return {
|
||||
"web": _web,
|
||||
"AIOHTTP_AVAILABLE": True,
|
||||
"App": App,
|
||||
"ActivityContext": ActivityContext,
|
||||
"ClientOptions": ClientOptions,
|
||||
"MessageActivity": MessageActivity,
|
||||
"ConversationReference": ConversationReference,
|
||||
"TypingActivityInput": TypingActivityInput,
|
||||
"AdaptiveCardInvokeActivity": AdaptiveCardInvokeActivity,
|
||||
"AdaptiveCardActionCardResponse": AdaptiveCardActionCardResponse,
|
||||
"AdaptiveCardActionMessageResponse": AdaptiveCardActionMessageResponse,
|
||||
"InvokeResponse": InvokeResponse,
|
||||
"AdaptiveCardInvokeResponse": AdaptiveCardInvokeResponse,
|
||||
"HttpMethod": HttpMethod,
|
||||
"HttpRequest": HttpRequest,
|
||||
"HttpResponse": HttpResponse,
|
||||
"HttpRouteHandler": HttpRouteHandler,
|
||||
"AdaptiveCard": AdaptiveCard,
|
||||
"ExecuteAction": ExecuteAction,
|
||||
"TextBlock": TextBlock,
|
||||
"TEAMS_SDK_AVAILABLE": True,
|
||||
}
|
||||
|
||||
from tools.lazy_deps import ensure_and_bind
|
||||
|
||||
return ensure_and_bind("platform.teams", _import, globals(), prompt=False)
|
||||
|
||||
|
||||
class TeamsAdapter(BasePlatformAdapter):
|
||||
|
|
@ -642,10 +709,13 @@ class TeamsAdapter(BasePlatformAdapter):
|
|||
self._conv_refs: Dict[str, Any] = {}
|
||||
|
||||
async def connect(self) -> bool:
|
||||
# Lazy-install the Teams SDK on demand (parity with Slack/Discord/etc.),
|
||||
# then re-check the module globals it rebinds.
|
||||
check_teams_requirements()
|
||||
if not TEAMS_SDK_AVAILABLE:
|
||||
self._set_fatal_error(
|
||||
"MISSING_SDK",
|
||||
"microsoft-teams-apps not installed. Run: pip install microsoft-teams-apps",
|
||||
"microsoft-teams-apps could not be installed. Run: pip install microsoft-teams-apps",
|
||||
retryable=False,
|
||||
)
|
||||
return False
|
||||
|
|
|
|||
|
|
@ -179,6 +179,7 @@ mcp = ["mcp==1.26.0", "starlette==1.0.1"] # starlette: CVE-2026-48710
|
|||
nemo-relay = ["nemo-relay==0.3"]
|
||||
homeassistant = ["aiohttp==3.13.4"]
|
||||
sms = ["aiohttp==3.13.4"]
|
||||
teams = ["microsoft-teams-apps==2.0.13.4", "aiohttp==3.13.4"]
|
||||
# Computer use — macOS background desktop control via cua-driver (MCP stdio).
|
||||
# The cua-driver binary itself is installed via `hermes tools` post-setup
|
||||
# (curl install script); this extra just pins the MCP client used to talk
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ ACP_REGISTRY_MANIFEST = REPO_ROOT / "acp_registry" / "agent.json"
|
|||
|
||||
# Auto-extracted from noreply emails + manual overrides
|
||||
AUTHOR_MAP = {
|
||||
"rio.jeong@thebytesize.ai": "rio-jeong",
|
||||
"yehaotian@xuanshudeMac-mini.local": "ArcanePivot",
|
||||
"dbeyer7@gmail.com": "benegessarit",
|
||||
"kenmege@yahoo.com": "Kenmege",
|
||||
|
|
|
|||
|
|
@ -211,10 +211,39 @@ class TestTeamsRequirements:
|
|||
monkeypatch.setattr(_teams_mod, "AIOHTTP_AVAILABLE", True)
|
||||
assert check_requirements() is True
|
||||
|
||||
def test_alias_matches(self, monkeypatch):
|
||||
def test_check_teams_requirements_shortcircuits_when_present(self, monkeypatch):
|
||||
# When the SDK + aiohttp are already importable, the active lazy-
|
||||
# installer returns True immediately without attempting an install.
|
||||
monkeypatch.setattr(_teams_mod, "TEAMS_SDK_AVAILABLE", True)
|
||||
monkeypatch.setattr(_teams_mod, "AIOHTTP_AVAILABLE", True)
|
||||
called = {"ensure_and_bind": 0}
|
||||
|
||||
def _fake_ensure_and_bind(*_args, **_kwargs):
|
||||
called["ensure_and_bind"] += 1
|
||||
return True
|
||||
|
||||
monkeypatch.setattr(
|
||||
"tools.lazy_deps.ensure_and_bind", _fake_ensure_and_bind
|
||||
)
|
||||
assert check_teams_requirements() is True
|
||||
assert called["ensure_and_bind"] == 0
|
||||
|
||||
def test_check_teams_requirements_lazy_installs_when_missing(self, monkeypatch):
|
||||
# When deps are missing, the active installer delegates to
|
||||
# ensure_and_bind("platform.teams", ...) — parity with Slack/Discord.
|
||||
monkeypatch.setattr(_teams_mod, "TEAMS_SDK_AVAILABLE", False)
|
||||
monkeypatch.setattr(_teams_mod, "AIOHTTP_AVAILABLE", False)
|
||||
seen = {}
|
||||
|
||||
def _fake_ensure_and_bind(feature, importer, target_globals, **kwargs):
|
||||
seen["feature"] = feature
|
||||
return True
|
||||
|
||||
monkeypatch.setattr(
|
||||
"tools.lazy_deps.ensure_and_bind", _fake_ensure_and_bind
|
||||
)
|
||||
assert check_teams_requirements() is True
|
||||
assert seen["feature"] == "platform.teams"
|
||||
|
||||
def test_validate_config_with_env(self, monkeypatch):
|
||||
monkeypatch.setenv("TEAMS_CLIENT_ID", "test-id")
|
||||
|
|
@ -371,6 +400,13 @@ class TestTeamsConnect:
|
|||
@pytest.mark.anyio
|
||||
async def test_connect_fails_without_sdk(self, monkeypatch):
|
||||
monkeypatch.setattr(_teams_mod, "TEAMS_SDK_AVAILABLE", False)
|
||||
# Simulate the SDK being unavailable AND not installable (offline /
|
||||
# locked-down env): the lazy-installer can't rebind the globals, so
|
||||
# TEAMS_SDK_AVAILABLE stays False and connect() must fail.
|
||||
monkeypatch.setattr(
|
||||
"tools.lazy_deps.ensure_and_bind",
|
||||
lambda *_a, **_k: False,
|
||||
)
|
||||
adapter = TeamsAdapter(_make_config(
|
||||
client_id="id", client_secret="secret", tenant_id="tenant",
|
||||
))
|
||||
|
|
|
|||
|
|
@ -152,6 +152,11 @@ LAZY_DEPS: dict[str, tuple[str, ...]] = {
|
|||
# defusedxml only; aiohttp/httpx are core dependencies of every messaging
|
||||
# adapter and ship via `platform.discord` / `platform.slack` / etc.
|
||||
"platform.wecom_callback": ("defusedxml==0.7.1",),
|
||||
# Microsoft Teams adapter — microsoft-teams-apps pulls a heavy tree
|
||||
# (microsoft-teams-api/cards/common, dependency-injector, msal). Lazy-
|
||||
# installed on demand like every other messaging platform; also exposed
|
||||
# as the `teams` extra in pyproject for packagers / explicit installs.
|
||||
"platform.teams": ("microsoft-teams-apps==2.0.13.4", "aiohttp==3.13.4"),
|
||||
|
||||
# ─── Terminal backends ─────────────────────────────────────────────────
|
||||
"terminal.modal": ("modal==1.3.4",),
|
||||
|
|
|
|||
87
uv.lock
generated
87
uv.lock
generated
|
|
@ -960,6 +960,28 @@ wheels = [
|
|||
{ 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" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dependency-injector"
|
||||
version = "4.49.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
||||
]
|
||||
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" }
|
||||
wheels = [
|
||||
{ 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" },
|
||||
{ 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" },
|
||||
{ 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" },
|
||||
{ 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" },
|
||||
{ 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" },
|
||||
{ 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" },
|
||||
{ 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" },
|
||||
{ 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" },
|
||||
{ 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" },
|
||||
{ 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" },
|
||||
{ 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" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deprecated"
|
||||
version = "1.3.1"
|
||||
|
|
@ -1542,6 +1564,10 @@ slack = [
|
|||
sms = [
|
||||
{ name = "aiohttp" },
|
||||
]
|
||||
teams = [
|
||||
{ name = "aiohttp" },
|
||||
{ name = "microsoft-teams-apps" },
|
||||
]
|
||||
termux = [
|
||||
{ name = "agent-client-protocol" },
|
||||
{ name = "honcho-ai" },
|
||||
|
|
@ -1591,6 +1617,7 @@ requires-dist = [
|
|||
{ name = "aiohttp", marker = "extra == 'messaging'", specifier = "==3.13.4" },
|
||||
{ name = "aiohttp", marker = "extra == 'slack'", specifier = "==3.13.4" },
|
||||
{ name = "aiohttp", marker = "extra == 'sms'", specifier = "==3.13.4" },
|
||||
{ name = "aiohttp", marker = "extra == 'teams'", specifier = "==3.13.4" },
|
||||
{ name = "aiohttp-socks", marker = "extra == 'matrix'", specifier = "==0.11.0" },
|
||||
{ name = "aiosqlite", marker = "extra == 'matrix'", specifier = "==0.22.1" },
|
||||
{ name = "alibabacloud-dingtalk", marker = "extra == 'dingtalk'", specifier = "==2.2.42" },
|
||||
|
|
@ -1649,6 +1676,7 @@ requires-dist = [
|
|||
{ name = "mcp", marker = "extra == 'computer-use'", specifier = "==1.26.0" },
|
||||
{ name = "mcp", marker = "extra == 'dev'", specifier = "==1.26.0" },
|
||||
{ name = "mcp", marker = "extra == 'mcp'", specifier = "==1.26.0" },
|
||||
{ name = "microsoft-teams-apps", marker = "extra == 'teams'", specifier = "==2.0.13.4" },
|
||||
{ name = "mistralai", marker = "extra == 'mistral'", specifier = "==2.4.8" },
|
||||
{ name = "modal", marker = "extra == 'modal'", specifier = "==1.3.4" },
|
||||
{ name = "nemo-relay", marker = "extra == 'nemo-relay'", specifier = "==0.3" },
|
||||
|
|
@ -1697,7 +1725,7 @@ requires-dist = [
|
|||
{ name = "websockets", specifier = "==15.0.1" },
|
||||
{ name = "youtube-transcript-api", marker = "extra == 'youtube'", specifier = "==1.2.4" },
|
||||
]
|
||||
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"]
|
||||
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"]
|
||||
|
||||
[[package]]
|
||||
name = "hf-xet"
|
||||
|
|
@ -2176,6 +2204,63 @@ wheels = [
|
|||
{ 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" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "microsoft-teams-api"
|
||||
version = "2.0.13.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "microsoft-teams-cards" },
|
||||
{ name = "microsoft-teams-common" },
|
||||
{ name = "pydantic" },
|
||||
{ name = "pyjwt", extra = ["crypto"] },
|
||||
]
|
||||
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" }
|
||||
wheels = [
|
||||
{ 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" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "microsoft-teams-apps"
|
||||
version = "2.0.13.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "cryptography" },
|
||||
{ name = "dependency-injector" },
|
||||
{ name = "fastapi" },
|
||||
{ name = "microsoft-teams-api" },
|
||||
{ name = "microsoft-teams-common" },
|
||||
{ name = "msal" },
|
||||
{ name = "pydantic-settings" },
|
||||
{ name = "pyjwt", extra = ["crypto"] },
|
||||
{ name = "python-dotenv" },
|
||||
{ name = "uvicorn" },
|
||||
]
|
||||
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" }
|
||||
wheels = [
|
||||
{ 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" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "microsoft-teams-cards"
|
||||
version = "2.0.13.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
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" }
|
||||
wheels = [
|
||||
{ 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" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "microsoft-teams-common"
|
||||
version = "2.0.13.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "httpx" },
|
||||
]
|
||||
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" }
|
||||
wheels = [
|
||||
{ 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" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mistralai"
|
||||
version = "2.4.8"
|
||||
|
|
|
|||
|
|
@ -24,6 +24,15 @@ Teams delivers @mentions as regular messages with `<at>BotName</at>` tags, which
|
|||
|
||||
---
|
||||
|
||||
For source or local installs, include the Teams extra so the bundled adapter can
|
||||
import the Microsoft Teams SDK:
|
||||
|
||||
```bash
|
||||
uv sync --extra teams
|
||||
# or, for editable installs:
|
||||
uv pip install -e ".[teams]"
|
||||
```
|
||||
|
||||
## Step 1: Install the Teams CLI
|
||||
|
||||
The `@microsoft/teams.cli` automates bot registration — no Azure portal needed.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue