microsoft-agents-hosting-msteams 1.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. microsoft_agents_hosting_msteams-1.2.0/LICENSE +21 -0
  2. microsoft_agents_hosting_msteams-1.2.0/MANIFEST.in +1 -0
  3. microsoft_agents_hosting_msteams-1.2.0/PKG-INFO +536 -0
  4. microsoft_agents_hosting_msteams-1.2.0/VERSION.txt +1 -0
  5. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/__init__.py +39 -0
  6. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/_graph.py +86 -0
  7. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/_teams_api_client.py +78 -0
  8. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/_utils.py +148 -0
  9. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/channel/__init__.py +8 -0
  10. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/channel/channel.py +392 -0
  11. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/channel/route_handlers.py +35 -0
  12. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/config/__init__.py +8 -0
  13. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/config/config.py +133 -0
  14. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/config/route_handlers.py +35 -0
  15. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/errors/__init__.py +13 -0
  16. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/errors/error_resources.py +65 -0
  17. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/file_consent/__init__.py +8 -0
  18. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/file_consent/file_consent.py +147 -0
  19. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/file_consent/route_handlers.py +35 -0
  20. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/meeting/__init__.py +8 -0
  21. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/meeting/meeting.py +268 -0
  22. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/meeting/route_handlers.py +72 -0
  23. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/message/__init__.py +10 -0
  24. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/message/message.py +294 -0
  25. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/message/route_handlers.py +51 -0
  26. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/message_extension/__init__.py +8 -0
  27. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/message_extension/message_extension.py +643 -0
  28. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/message_extension/route_handlers.py +222 -0
  29. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/proactive_service_endpoints.py +22 -0
  30. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/route_handlers.py +88 -0
  31. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/task_module/__init__.py +8 -0
  32. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/task_module/route_handlers.py +51 -0
  33. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/task_module/task_module.py +139 -0
  34. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/team/__init__.py +8 -0
  35. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/team/route_handlers.py +30 -0
  36. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/team/team.py +303 -0
  37. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/teams_activity.py +123 -0
  38. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/teams_agent_extension.py +309 -0
  39. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/teams_turn_context.py +124 -0
  40. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/type_defs.py +37 -0
  41. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents_hosting_msteams.egg-info/PKG-INFO +536 -0
  42. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents_hosting_msteams.egg-info/SOURCES.txt +47 -0
  43. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents_hosting_msteams.egg-info/dependency_links.txt +1 -0
  44. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents_hosting_msteams.egg-info/requires.txt +4 -0
  45. microsoft_agents_hosting_msteams-1.2.0/microsoft_agents_hosting_msteams.egg-info/top_level.txt +1 -0
  46. microsoft_agents_hosting_msteams-1.2.0/pyproject.toml +24 -0
  47. microsoft_agents_hosting_msteams-1.2.0/readme.md +513 -0
  48. microsoft_agents_hosting_msteams-1.2.0/setup.cfg +4 -0
  49. microsoft_agents_hosting_msteams-1.2.0/setup.py +20 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) Microsoft Corporation.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE
@@ -0,0 +1 @@
1
+ include VERSION.txt
@@ -0,0 +1,536 @@
1
+ Metadata-Version: 2.4
2
+ Name: microsoft-agents-hosting-msteams
3
+ Version: 1.2.0
4
+ Summary: Integration library for Microsoft Agents with Teams
5
+ Author: Microsoft Corporation
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/microsoft/Agents
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.11
10
+ Classifier: Programming Language :: Python :: 3.12
11
+ Classifier: Programming Language :: Python :: 3.13
12
+ Classifier: Programming Language :: Python :: 3.14
13
+ Classifier: Operating System :: OS Independent
14
+ Requires-Python: >=3.11
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Requires-Dist: microsoft-agents-hosting-core==1.2.0
18
+ Requires-Dist: aiohttp>=3.11.11
19
+ Requires-Dist: microsoft-teams-api<3,>=2.0.0
20
+ Requires-Dist: msgraph-sdk>=1.58.0
21
+ Dynamic: license-file
22
+ Dynamic: requires-dist
23
+
24
+ # microsoft-agents-hosting-msteams
25
+
26
+ [![PyPI version](https://img.shields.io/pypi/v/microsoft-agents-hosting-msteams)](https://pypi.org/project/microsoft-agents-hosting-msteams/)
27
+
28
+ Teams-specific extension for the Microsoft 365 Agents SDK for Python. Provides the `TeamsAgentExtension` and a full set of typed, decorator-based route registrars for every Teams invoke and event activity — messaging extensions, task modules, meeting lifecycle events, channel and team management, file consent, config invokes, and more.
29
+
30
+ All handlers receive a `TeamsTurnContext`, a Teams-aware wrapper around the base `TurnContext` that surfaces the Teams API client and typed activity helpers.
31
+
32
+ ## What is this?
33
+
34
+ This library is part of the **Microsoft 365 Agents SDK for Python** — a comprehensive framework for building enterprise-grade conversational AI agents. The SDK enables developers to create intelligent agents that work across Microsoft Teams, M365 Copilot, Copilot Studio, and web chat.
35
+
36
+ ## Release Notes
37
+
38
+ <table style="width:100%">
39
+ <tr>
40
+ <th style="width:20%">Version</th>
41
+ <th style="width:20%">Date</th>
42
+ <th style="width:60%">Release Notes</th>
43
+ </tr>
44
+ <tr>
45
+ <td>1.2.0</td>
46
+ <td>2026-07-17</td>
47
+ <td>
48
+ <a href="https://github.com/microsoft/Agents-for-python/blob/main/changelog.md#microsoft-365-agents-sdk-for-python---release-notes-v120">
49
+ 1.2.0 Release Notes
50
+ </a>
51
+ </td>
52
+ </tr>
53
+ <tr>
54
+ <td>1.1.0</td>
55
+ <td>2026-06-19</td>
56
+ <td>
57
+ <a href="https://github.com/microsoft/Agents-for-python/blob/main/changelog.md#microsoft-365-agents-sdk-for-python---release-notes-v110">
58
+ 1.1.0 Release Notes
59
+ </a>
60
+ </td>
61
+ </tr>
62
+ <tr>
63
+ <td>1.0.0</td>
64
+ <td>2026-05-22</td>
65
+ <td>
66
+ <a href="https://github.com/microsoft/Agents-for-python/blob/main/changelog.md#microsoft-365-agents-sdk-for-python---release-notes-v100">
67
+ 1.0.0 Release Notes
68
+ </a>
69
+ </td>
70
+ </tr>
71
+ <tr>
72
+ <td>0.9.1</td>
73
+ <td>2026-05-04</td>
74
+ <td>
75
+ <a href="https://github.com/microsoft/Agents-for-python/blob/main/changelog.md#microsoft-365-agents-sdk-for-python---release-notes-v091">
76
+ 0.9.1 Release Notes
77
+ </a>
78
+ </td>
79
+ </tr>
80
+ <tr>
81
+ <td>0.9.0</td>
82
+ <td>2026-04-15</td>
83
+ <td>
84
+ <a href="https://github.com/microsoft/Agents-for-python/blob/main/changelog.md#microsoft-365-agents-sdk-for-python---release-notes-v090">
85
+ 0.9.0 Release Notes
86
+ </a>
87
+ </td>
88
+ </tr>
89
+ <tr>
90
+ <td>0.8.0</td>
91
+ <td>2026-02-23</td>
92
+ <td>
93
+ <a href="https://github.com/microsoft/Agents-for-python/blob/main/changelog.md#microsoft-365-agents-sdk-for-python---release-notes-v080">
94
+ 0.8.0 Release Notes
95
+ </a>
96
+ </td>
97
+ </tr>
98
+ <tr>
99
+ <td>0.7.0</td>
100
+ <td>2026-01-21</td>
101
+ <td>
102
+ <a href="https://github.com/microsoft/Agents-for-python/blob/main/changelog.md#microsoft-365-agents-sdk-for-python---release-notes-v070">
103
+ 0.7.0 Release Notes
104
+ </a>
105
+ </td>
106
+ </tr>
107
+ <tr>
108
+ <td>0.6.1</td>
109
+ <td>2025-12-01</td>
110
+ <td>
111
+ <a href="https://github.com/microsoft/Agents-for-python/blob/main/changelog.md#microsoft-365-agents-sdk-for-python---release-notes-v061">
112
+ 0.6.1 Release Notes
113
+ </a>
114
+ </td>
115
+ </tr>
116
+ <tr>
117
+ <td>0.6.0</td>
118
+ <td>2025-11-18</td>
119
+ <td>
120
+ <a href="https://github.com/microsoft/Agents-for-python/blob/main/changelog.md#microsoft-365-agents-sdk-for-python---release-notes-v060">
121
+ 0.6.0 Release Notes
122
+ </a>
123
+ </td>
124
+ </tr>
125
+ <tr>
126
+ <td>0.5.0</td>
127
+ <td>2025-10-22</td>
128
+ <td>
129
+ <a href="https://github.com/microsoft/Agents-for-python/blob/main/changelog.md#microsoft-365-agents-sdk-for-python---release-notes-v050">
130
+ 0.5.0 Release Notes
131
+ </a>
132
+ </td>
133
+ </tr>
134
+ </table>
135
+
136
+ ## Packages Overview
137
+
138
+ | Package Name | PyPI Version | Description |
139
+ |--------------|-------------|-------------|
140
+ | `microsoft-agents-activity` | [![PyPI](https://img.shields.io/pypi/v/microsoft-agents-activity)](https://pypi.org/project/microsoft-agents-activity/) | Types and validators implementing the Activity protocol spec. |
141
+ | `microsoft-agents-hosting-core` | [![PyPI](https://img.shields.io/pypi/v/microsoft-agents-hosting-core)](https://pypi.org/project/microsoft-agents-hosting-core/) | Core library for Microsoft Agents hosting. |
142
+ | `microsoft-agents-hosting-aiohttp` | [![PyPI](https://img.shields.io/pypi/v/microsoft-agents-hosting-aiohttp)](https://pypi.org/project/microsoft-agents-hosting-aiohttp/) | Configures aiohttp to run the Agent. |
143
+ | `microsoft-agents-hosting-msteams` | [![PyPI](https://img.shields.io/pypi/v/microsoft-agents-hosting-msteams)](https://pypi.org/project/microsoft-agents-hosting-msteams/) | Provides classes to host an Agent for Teams. |
144
+ | `microsoft-agents-hosting-dialogs` | [![PyPI](https://img.shields.io/pypi/v/microsoft-agents-hosting-dialogs)](https://pypi.org/project/microsoft-agents-hosting-dialogs/) | Dialog system with waterfall dialogs, prompts, and multi-turn conversation management. |
145
+ | `microsoft-agents-storage-blob` | [![PyPI](https://img.shields.io/pypi/v/microsoft-agents-storage-blob)](https://pypi.org/project/microsoft-agents-storage-blob/) | Extension to use Azure Blob as storage. |
146
+ | `microsoft-agents-storage-cosmos` | [![PyPI](https://img.shields.io/pypi/v/microsoft-agents-storage-cosmos)](https://pypi.org/project/microsoft-agents-storage-cosmos/) | Extension to use CosmosDB as storage. |
147
+ | `microsoft-agents-authentication-msal` | [![PyPI](https://img.shields.io/pypi/v/microsoft-agents-authentication-msal)](https://pypi.org/project/microsoft-agents-authentication-msal/) | MSAL-based authentication for Microsoft Agents. |
148
+
149
+ Additionally we provide a Copilot Studio Client, to interact with Agents created in CopilotStudio:
150
+
151
+ | Package Name | PyPI Version | Description |
152
+ |--------------|-------------|-------------|
153
+ | `microsoft-agents-copilotstudio-client` | [![PyPI](https://img.shields.io/pypi/v/microsoft-agents-copilotstudio-client)](https://pypi.org/project/microsoft-agents-copilotstudio-client/) | Direct to Engine client to interact with Agents created in CopilotStudio |
154
+
155
+ ## Installation
156
+
157
+ ```bash
158
+ pip install microsoft-agents-hosting-msteams
159
+ ```
160
+
161
+ ## Key Classes
162
+
163
+ | Class | Description |
164
+ |-------|-------------|
165
+ | `TeamsAgentExtension` | Attaches to an `AgentApplication` and exposes all Teams route registrars as typed properties. |
166
+ | `TeamsTurnContext` | Teams-aware context passed to every handler. Provides the Teams API client and typed `TeamsActivity` helpers. |
167
+ | `MessageExtension` | Route registrar for all `composeExtension/*` invokes (query, fetch action, submit, link unfurling, settings, etc.). |
168
+ | `TaskModule` | Route registrar for `task/fetch` and `task/submit` invokes. |
169
+ | `Meeting` | Route registrar for meeting start/end and participant join/leave events. |
170
+ | `Channel` | Route registrar for channel created/deleted/renamed/shared events. |
171
+ | `Team` | Route registrar for team archived/renamed/restored/deleted events. |
172
+ | `FileConsent` | Route registrar for file consent accept/decline invokes. |
173
+ | `Config` | Route registrar for `config/fetch` and `config/submit` invokes. |
174
+ | `Message` | Route registrar for message edit, delete, undelete, read receipts, and actionable message execute. |
175
+
176
+ ## Usage
177
+
178
+ ### Setup
179
+
180
+ Wrap your `AgentApplication` with `TeamsAgentExtension` to access all Teams-specific route registrars:
181
+
182
+ ```python
183
+ from microsoft_agents.hosting.core import AgentApplication, TurnState
184
+ from microsoft_agents.hosting.msteams import TeamsAgentExtension
185
+
186
+ app = AgentApplication[TurnState]()
187
+ teams = TeamsAgentExtension(app)
188
+ ```
189
+
190
+ `TeamsAgentExtension` registers a `before_turn` hook that deserializes `activity.channel_data` into a typed `ChannelData` object and creates a pre-authenticated Teams API client on the turn state for every Teams activity.
191
+
192
+ ### The Teams context
193
+
194
+ Every handler registered through `TeamsAgentExtension` receives a `TeamsTurnContext` instead of a plain `TurnContext`.
195
+
196
+ #### `context.activity` → `TeamsActivity`
197
+
198
+ The activity is upgraded to `TeamsActivity`, which adds helper methods on top of the standard `Activity`:
199
+
200
+ ```python
201
+ # Get the Teams channel the activity came from
202
+ channel_id = context.activity.get_channel_id()
203
+
204
+ # Get the team info embedded in channel_data
205
+ team = context.activity.get_team_info()
206
+
207
+ # Get the meeting the activity was sent in
208
+ meeting = context.activity.get_meeting_info()
209
+
210
+ # Mark the outgoing reply to target a specific user in a meeting
211
+ context.activity.notify_user(alert_in_meeting=True)
212
+
213
+ # Attach a feedback loop to a message being sent (Copilot scenarios)
214
+ context.activity.enable_feedback_loop()
215
+ ```
216
+
217
+ #### `context.api_client` → `ApiClient`
218
+
219
+ Direct access to the Teams REST API client, pre-authenticated for the current turn. See [Teams API client](#teams-api-client) below.
220
+
221
+ #### Sending targeted activities
222
+
223
+ `TeamsTurnContext` adds two methods for sending activities that target a specific user in a meeting:
224
+
225
+ ```python
226
+ await context.send_targeted_activity(activity)
227
+ await context.send_targeted_activities([activity1, activity2])
228
+ ```
229
+
230
+ ### Messaging Extensions
231
+
232
+ ```python
233
+ from microsoft_teams.api.models import (
234
+ MessagingExtensionQuery,
235
+ MessagingExtensionResponse,
236
+ MessagingExtensionAction,
237
+ MessagingExtensionActionResponse,
238
+ AppBasedLinkQuery,
239
+ )
240
+
241
+ # Search-based extension
242
+ @teams.message_extensions.query("searchCmd")
243
+ async def on_search(context: TeamsTurnContext, state, query: MessagingExtensionQuery):
244
+ return MessagingExtensionResponse(...)
245
+
246
+ # Action-based extension — open a task module to collect input
247
+ @teams.message_extensions.fetch_action("myCmd")
248
+ async def on_fetch_action(context: TeamsTurnContext, state, action: MessagingExtensionAction):
249
+ return MessagingExtensionActionResponse(...)
250
+
251
+ # Handle submission from the task module
252
+ @teams.message_extensions.submit_action("myCmd")
253
+ async def on_submit(context: TeamsTurnContext, state, action: MessagingExtensionAction):
254
+ return MessagingExtensionResponse(...)
255
+
256
+ # Link unfurling
257
+ @teams.message_extensions.query_link
258
+ async def on_query_link(context: TeamsTurnContext, state, query: AppBasedLinkQuery):
259
+ return MessagingExtensionResponse(...)
260
+
261
+ # Anonymous link unfurling (before the user has authenticated)
262
+ @teams.message_extensions.anonymous_query_link
263
+ async def on_anon_link(context: TeamsTurnContext, state, query: AppBasedLinkQuery):
264
+ return MessagingExtensionResponse(...)
265
+
266
+ # Bot message preview — edit stage
267
+ @teams.message_extensions.message_preview_edit("myCmd")
268
+ async def on_preview_edit(context: TeamsTurnContext, state, preview: Activity):
269
+ return MessagingExtensionResponse(...)
270
+
271
+ # Bot message preview — send stage
272
+ @teams.message_extensions.message_preview_send("myCmd")
273
+ async def on_preview_send(context: TeamsTurnContext, state, preview: Activity):
274
+ return MessagingExtensionResponse(...)
275
+
276
+ # Select item from search results
277
+ @teams.message_extensions.select_item
278
+ async def on_select_item(context: TeamsTurnContext, state, item):
279
+ return MessagingExtensionResponse(...)
280
+
281
+ # Card button clicked
282
+ @teams.message_extensions.card_button_clicked
283
+ async def on_card_click(context: TeamsTurnContext, state, card):
284
+ ...
285
+ ```
286
+
287
+ All `command_id` arguments accept a plain string, a compiled `re.Pattern`, or `None` to match all commands.
288
+
289
+ #### Settings page
290
+
291
+ ```python
292
+ @teams.message_extensions.query_setting_url
293
+ async def on_settings_url(context: TeamsTurnContext, state, query: MessagingExtensionQuery):
294
+ return MessagingExtensionResponse(
295
+ compose_extension=MessagingExtensionResult(type="config", suggested_actions=...)
296
+ )
297
+
298
+ @teams.message_extensions.setting
299
+ async def on_settings_submit(context: TeamsTurnContext, state, query: MessagingExtensionQuery):
300
+ await save_settings(context, query.state)
301
+ ```
302
+
303
+ ### Task Modules
304
+
305
+ ```python
306
+ from microsoft_teams.api.models import TaskModuleRequest, TaskModuleResponse
307
+
308
+ @teams.task_modules.fetch("myVerb")
309
+ async def on_task_fetch(context: TeamsTurnContext, state, request: TaskModuleRequest):
310
+ return TaskModuleResponse(...)
311
+
312
+ @teams.task_modules.submit("myVerb")
313
+ async def on_task_submit(context: TeamsTurnContext, state, request: TaskModuleRequest):
314
+ return TaskModuleResponse(...)
315
+ ```
316
+
317
+ The first argument is a verb — a string or regex matched against `activity.value.data.verb`. Omit it to match all `task/fetch` or `task/submit` invokes.
318
+
319
+ ### Meeting Events
320
+
321
+ ```python
322
+ from microsoft_teams.api.models import MeetingDetails
323
+ from microsoft_agents.activity.teams import MeetingParticipantsEventDetails
324
+
325
+ @teams.meetings.start
326
+ async def on_meeting_start(context: TeamsTurnContext, state, meeting: MeetingDetails):
327
+ ...
328
+
329
+ @teams.meetings.end
330
+ async def on_meeting_end(context: TeamsTurnContext, state, meeting: MeetingDetails):
331
+ ...
332
+
333
+ @teams.meetings.participants_join
334
+ async def on_participants_join(context: TeamsTurnContext, state, details: MeetingParticipantsEventDetails):
335
+ ...
336
+
337
+ @teams.meetings.participants_leave
338
+ async def on_participants_leave(context: TeamsTurnContext, state, details: MeetingParticipantsEventDetails):
339
+ ...
340
+ ```
341
+
342
+ ### Channel Events
343
+
344
+ ```python
345
+ from microsoft_teams.api.models import ChannelInfo
346
+
347
+ @teams.channels.created
348
+ async def on_channel_created(context: TeamsTurnContext, state, channel: ChannelInfo):
349
+ print(f"New channel: {channel.name}")
350
+
351
+ @teams.channels.renamed
352
+ async def on_channel_renamed(context: TeamsTurnContext, state, channel: ChannelInfo):
353
+ ...
354
+
355
+ # Also available: deleted, shared, unshared, restored, members_added, members_removed
356
+ ```
357
+
358
+ `teams.channels.event()` is a catch-all that matches any `channel.*` event type via regex.
359
+
360
+ ### Team Events
361
+
362
+ ```python
363
+ from microsoft_teams.api.models import TeamInfo
364
+
365
+ @teams.teams.renamed
366
+ async def on_team_renamed(context: TeamsTurnContext, state, team: TeamInfo): ...
367
+
368
+ # Also available: archived, unarchived, deleted, hard_deleted, restored
369
+ ```
370
+
371
+ `teams.teams.event()` is a catch-all matching any `team.*` event type.
372
+
373
+ ### File Consent
374
+
375
+ ```python
376
+ from microsoft_teams.api.models import FileConsentCardResponse
377
+
378
+ @teams.file_consent.accept
379
+ async def on_file_accept(context: TeamsTurnContext, state, consent: FileConsentCardResponse):
380
+ await upload_file(consent.upload_info)
381
+
382
+ @teams.file_consent.decline
383
+ async def on_file_decline(context: TeamsTurnContext, state, consent: FileConsentCardResponse):
384
+ ...
385
+ ```
386
+
387
+ Teams expects a 200 OK with no body for both; the routing layer sends that automatically.
388
+
389
+ ### Config Invokes
390
+
391
+ ```python
392
+ from microsoft_teams.api.models import ConfigResponse
393
+
394
+ @teams.config.fetch
395
+ async def on_config_fetch(context: TeamsTurnContext, state, config_data):
396
+ return ConfigResponse(...)
397
+
398
+ @teams.config.submit
399
+ async def on_config_submit(context: TeamsTurnContext, state, config_data):
400
+ return ConfigResponse(...)
401
+ ```
402
+
403
+ `config_data` is the raw `activity.value` payload.
404
+
405
+ ### Message Updates
406
+
407
+ ```python
408
+ from microsoft_teams.api.models import O365ConnectorCardActionQuery
409
+
410
+ @teams.messages.edit
411
+ async def on_message_edit(context: TeamsTurnContext, state):
412
+ ...
413
+
414
+ @teams.messages.delete
415
+ async def on_message_delete(context: TeamsTurnContext, state):
416
+ ...
417
+
418
+ @teams.messages.undelete
419
+ async def on_message_undelete(context: TeamsTurnContext, state):
420
+ ...
421
+
422
+ @teams.messages.read_receipt
423
+ async def on_read_receipt(context: TeamsTurnContext, state, data: dict):
424
+ last_read_id = data.get("lastReadMessageId")
425
+ ...
426
+
427
+ @teams.messages.execute_action
428
+ async def on_execute_action(context: TeamsTurnContext, state, query: O365ConnectorCardActionQuery):
429
+ ...
430
+ ```
431
+
432
+ ### Generic Teams routes
433
+
434
+ `TeamsAgentExtension` also wraps the underlying `AgentApplication` route methods so all handlers automatically receive a `TeamsTurnContext`:
435
+
436
+ ```python
437
+ from microsoft_agents.activity import ActivityTypes, ConversationUpdateTypes
438
+
439
+ @teams.activity(ActivityTypes.message)
440
+ async def on_any_message(context: TeamsTurnContext, state):
441
+ await context.send_activity(f"Echo: {context.activity.text}")
442
+
443
+ @teams.message(r"^hello")
444
+ async def on_hello(context: TeamsTurnContext, state):
445
+ await context.send_activity("Hi there!")
446
+
447
+ @teams.conversation_update(ConversationUpdateTypes.members_added)
448
+ async def on_members_added(context: TeamsTurnContext, state):
449
+ for member in context.activity.members_added:
450
+ if member.id != context.activity.recipient.id:
451
+ await context.send_activity(f"Welcome, {member.name}!")
452
+ ```
453
+
454
+ ## Teams API client
455
+
456
+ `context.api_client` is a pre-authenticated `ApiClient` pointing at the Teams connector service for the current turn. It wraps the Teams REST API and is the right tool for operations on channels, conversations, and members.
457
+
458
+ ```python
459
+ # Get the list of members in the current conversation
460
+ members = await context.api_client.conversations.get_conversation_members(
461
+ context.activity.conversation.id
462
+ )
463
+
464
+ # Send a proactive message to a specific conversation
465
+ await context.api_client.conversations.send_to_conversation(
466
+ context.activity.conversation.id,
467
+ activity,
468
+ )
469
+ ```
470
+
471
+ You can also get the client directly from the extension if you have a context but aren't inside a Teams handler:
472
+
473
+ ```python
474
+ client = teams.get_teams_api_client(context)
475
+ ```
476
+
477
+ ## Microsoft Graph client
478
+
479
+ For operations that go beyond the Teams connector service — user profiles, SharePoint, calendar, etc. — use the Graph client:
480
+
481
+ ```python
482
+ @teams.message(r"^profile")
483
+ async def on_profile(context: TeamsTurnContext, state):
484
+ graph = teams.get_graph_client(context, handler_name="UserAuth")
485
+ user = await graph.users.by_user_id(context.activity.from_.aad_object_id).get()
486
+ await context.send_activity(f"Display name: {user.display_name}")
487
+ ```
488
+
489
+ The `handler_name` argument names an OAuth connection configured in the app's `auth` settings. If omitted, the app's default auth handler is used.
490
+
491
+ ## Invoke response conventions
492
+
493
+ Teams expects a synchronous HTTP response for all invoke activities. The routing layer handles this automatically — return a value from your handler and the framework serializes and sends it.
494
+
495
+ | Namespace | Sends response? | Response type |
496
+ |---|---|---|
497
+ | `task_modules.fetch/submit` | If handler returns non-`None` | `TaskModuleResponse` |
498
+ | `message_extensions.query/select_item/fetch_action/submit_action/message_preview_*` | If handler returns non-`None` | `MessagingExtensionResponse` / `MessagingExtensionActionResponse` |
499
+ | `message_extensions.query_link/anonymous_query_link/query_setting_url` | If handler returns non-`None` | `MessagingExtensionResponse` |
500
+ | `message_extensions.setting` | Always | `MessagingExtensionResponse` (or 200 with no body if handler returns `None`) |
501
+ | `message_extensions.card_button_clicked` | Always | empty 200 |
502
+ | `config.fetch/submit` | If handler returns non-`None` | `ConfigResponse` |
503
+ | `file_consent.accept/decline` | Always | empty 200 |
504
+ | `messages.execute_action` | Always | empty 200 |
505
+ | `meetings`, `channels`, `teams`, `messages.edit/undelete/delete` | Never — not invokes | — |
506
+
507
+ ## Features Supported
508
+
509
+ - **Messaging Extensions** — query, fetch action, submit action, link unfurling, anonymous link unfurling, settings URL, configure settings, card button clicked, bot message preview (edit/send)
510
+ - **Task Modules** — fetch and submit with optional verb matching
511
+ - **Meeting Lifecycle** — start, end, participant join/leave
512
+ - **Channel Management** — created, deleted, renamed, shared, unshared, restored, members added/removed
513
+ - **Team Management** — archived, unarchived, deleted, hard deleted, renamed, restored
514
+ - **File Consent** — accept and decline flows
515
+ - **Config Invokes** — `config/fetch` and `config/submit`
516
+ - **Message Updates** — edit, delete, undelete, read receipts, actionable message execute
517
+ - **TeamsAgentExtension routing** — wraps any `AgentApplication` with zero configuration
518
+
519
+ # Quick Links
520
+
521
+ - 📦 [All SDK Packages on PyPI](https://pypi.org/search/?q=microsoft-agents)
522
+ - 📖 [Complete Documentation](https://aka.ms/agents)
523
+ - 💡 [Python Samples Repository](https://github.com/microsoft/Agents/tree/main/samples/python)
524
+ - 🐛 [Report Issues](https://github.com/microsoft/Agents-for-python/issues)
525
+
526
+ # Sample Applications
527
+
528
+ |Name|Description|README|
529
+ |----|----|----|
530
+ |Quickstart|Simplest agent|[Quickstart](https://github.com/microsoft/Agents/blob/main/samples/python/quickstart/README.md)|
531
+ |Auto Sign In|Simple OAuth agent using Graph and GitHub|[auto-signin](https://github.com/microsoft/Agents/blob/main/samples/python/auto-signin/README.md)|
532
+ |OBO Authorization|OBO flow to access a Copilot Studio Agent|[obo-authorization](https://github.com/microsoft/Agents/blob/main/samples/python/obo-authorization/README.md)|
533
+ |Semantic Kernel Integration|A weather agent built with Semantic Kernel|[semantic-kernel-multiturn](https://github.com/microsoft/Agents/blob/main/samples/python/semantic-kernel-multiturn/README.md)|
534
+ |Streaming Agent|Streams OpenAI responses|[azure-ai-streaming](https://github.com/microsoft/Agents/blob/main/samples/python/azureai-streaming/README.md)|
535
+ |Copilot Studio Client|Console app to consume a Copilot Studio Agent|[copilotstudio-client](https://github.com/microsoft/Agents/blob/main/samples/python/copilotstudio-client/README.md)|
536
+ |Cards Agent|Agent that uses rich cards to enhance conversation design|[cards](https://github.com/microsoft/Agents/blob/main/samples/python/cards/README.md)|
@@ -0,0 +1 @@
1
+ 1.2.0
@@ -0,0 +1,39 @@
1
+ # Copyright (c) Microsoft Corporation. All rights reserved.
2
+ # Licensed under the MIT License.
3
+
4
+ """Microsoft 365 Agents SDK -- Microsoft Teams hosting extension.
5
+
6
+ This package layers Teams-specific functionality on top of an
7
+ :class:`~microsoft_agents.hosting.core.AgentApplication`. Its entry point is
8
+ :class:`TeamsAgentExtension`, which exposes namespaced route registration for
9
+ Teams events (channels, teams, meetings, messages, message extensions, task
10
+ modules, configuration, and file consent). It also provides the Teams-aware
11
+ :class:`TeamsTurnContext` and :class:`TeamsActivity` helpers.
12
+ """
13
+
14
+ from .teams_agent_extension import TeamsAgentExtension
15
+ from .channel import Channel
16
+ from .config import Config
17
+ from .file_consent import FileConsent
18
+ from .meeting import Meeting
19
+ from .message import Message
20
+ from .message_extension import MessageExtension
21
+ from .task_module import TaskModule
22
+ from .team import Team
23
+
24
+ from .teams_activity import TeamsActivity
25
+ from .teams_turn_context import TeamsTurnContext
26
+
27
+ __all__ = [
28
+ "TeamsAgentExtension",
29
+ "Channel",
30
+ "Config",
31
+ "FileConsent",
32
+ "Meeting",
33
+ "Message",
34
+ "MessageExtension",
35
+ "TaskModule",
36
+ "Team",
37
+ "TeamsActivity",
38
+ "TeamsTurnContext",
39
+ ]
@@ -0,0 +1,86 @@
1
+ # Copyright (c) Microsoft Corporation. All rights reserved.
2
+ # Licensed under the MIT License.
3
+
4
+ """Microsoft Graph client integration for the Teams hosting layer.
5
+
6
+ Builds a :class:`msgraph.GraphServiceClient` whose requests are authenticated
7
+ with tokens obtained from the agent's configured authorization, so handlers can
8
+ call Microsoft Graph on behalf of the current turn.
9
+ """
10
+
11
+ from typing import Any
12
+
13
+ from kiota_abstractions.request_information import RequestInformation
14
+ from kiota_abstractions.authentication import AuthenticationProvider
15
+
16
+ from msgraph import GraphServiceClient, GraphRequestAdapter
17
+
18
+ from microsoft_agents.hosting.core import (
19
+ AgentApplication,
20
+ TurnContext,
21
+ )
22
+
23
+
24
+ class _SDKAuthenticationProvider(AuthenticationProvider):
25
+ """Kiota authentication provider backed by the agent's authorization.
26
+
27
+ Acquires an access token for the current turn via
28
+ :meth:`AgentApplication.auth.get_token` and attaches it to outgoing Graph
29
+ requests as a bearer token.
30
+ """
31
+
32
+ def __init__(
33
+ self,
34
+ app: AgentApplication,
35
+ context: TurnContext,
36
+ handler_name: str | None = None,
37
+ ):
38
+ """Capture the context needed to resolve a token at request time.
39
+
40
+ :param app: The agent application whose authorization issues tokens.
41
+ :param context: The current turn context.
42
+ :param handler_name: The auth handler name used to acquire the token.
43
+ """
44
+ self._app = app
45
+ self._context = context
46
+ self._handler_name = handler_name
47
+
48
+ async def authenticate_request(
49
+ self,
50
+ request: RequestInformation,
51
+ additional_authentication_context: dict[str, Any] | None = None,
52
+ ) -> None:
53
+ """Attach a bearer token to the outgoing Graph request.
54
+
55
+ :param request: The request to authenticate.
56
+ :param additional_authentication_context: Optional Kiota authentication
57
+ context; unused but accepted to satisfy the provider interface.
58
+ """
59
+ if additional_authentication_context is None:
60
+ additional_authentication_context = {}
61
+
62
+ token_response = await self._app.auth.get_token(
63
+ self._context, self._handler_name
64
+ )
65
+ if token_response:
66
+ request.headers["Authorization"] = f"Bearer {token_response.token}"
67
+
68
+
69
+ def _create_graph_service_client(
70
+ app: AgentApplication,
71
+ context: TurnContext,
72
+ handler_name: str | None = None,
73
+ ) -> GraphServiceClient:
74
+ """Create a Graph client authenticated for the current turn.
75
+
76
+ :param app: The agent application whose authorization issues tokens.
77
+ :param context: The current turn context.
78
+ :param handler_name: Optional auth handler name used to acquire the token.
79
+ :return: A :class:`GraphServiceClient` that authenticates each request via
80
+ the agent's authorization.
81
+ """
82
+ return GraphServiceClient(
83
+ request_adapter=GraphRequestAdapter(
84
+ _SDKAuthenticationProvider(app, context, handler_name)
85
+ )
86
+ )