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.
- microsoft_agents_hosting_msteams-1.2.0/LICENSE +21 -0
- microsoft_agents_hosting_msteams-1.2.0/MANIFEST.in +1 -0
- microsoft_agents_hosting_msteams-1.2.0/PKG-INFO +536 -0
- microsoft_agents_hosting_msteams-1.2.0/VERSION.txt +1 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/__init__.py +39 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/_graph.py +86 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/_teams_api_client.py +78 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/_utils.py +148 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/channel/__init__.py +8 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/channel/channel.py +392 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/channel/route_handlers.py +35 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/config/__init__.py +8 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/config/config.py +133 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/config/route_handlers.py +35 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/errors/__init__.py +13 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/errors/error_resources.py +65 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/file_consent/__init__.py +8 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/file_consent/file_consent.py +147 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/file_consent/route_handlers.py +35 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/meeting/__init__.py +8 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/meeting/meeting.py +268 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/meeting/route_handlers.py +72 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/message/__init__.py +10 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/message/message.py +294 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/message/route_handlers.py +51 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/message_extension/__init__.py +8 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/message_extension/message_extension.py +643 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/message_extension/route_handlers.py +222 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/proactive_service_endpoints.py +22 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/route_handlers.py +88 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/task_module/__init__.py +8 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/task_module/route_handlers.py +51 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/task_module/task_module.py +139 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/team/__init__.py +8 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/team/route_handlers.py +30 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/team/team.py +303 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/teams_activity.py +123 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/teams_agent_extension.py +309 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/teams_turn_context.py +124 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents/hosting/msteams/type_defs.py +37 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents_hosting_msteams.egg-info/PKG-INFO +536 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents_hosting_msteams.egg-info/SOURCES.txt +47 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents_hosting_msteams.egg-info/dependency_links.txt +1 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents_hosting_msteams.egg-info/requires.txt +4 -0
- microsoft_agents_hosting_msteams-1.2.0/microsoft_agents_hosting_msteams.egg-info/top_level.txt +1 -0
- microsoft_agents_hosting_msteams-1.2.0/pyproject.toml +24 -0
- microsoft_agents_hosting_msteams-1.2.0/readme.md +513 -0
- microsoft_agents_hosting_msteams-1.2.0/setup.cfg +4 -0
- 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
|
+
[](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` | [](https://pypi.org/project/microsoft-agents-activity/) | Types and validators implementing the Activity protocol spec. |
|
|
141
|
+
| `microsoft-agents-hosting-core` | [](https://pypi.org/project/microsoft-agents-hosting-core/) | Core library for Microsoft Agents hosting. |
|
|
142
|
+
| `microsoft-agents-hosting-aiohttp` | [](https://pypi.org/project/microsoft-agents-hosting-aiohttp/) | Configures aiohttp to run the Agent. |
|
|
143
|
+
| `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` | [](https://pypi.org/project/microsoft-agents-hosting-dialogs/) | Dialog system with waterfall dialogs, prompts, and multi-turn conversation management. |
|
|
145
|
+
| `microsoft-agents-storage-blob` | [](https://pypi.org/project/microsoft-agents-storage-blob/) | Extension to use Azure Blob as storage. |
|
|
146
|
+
| `microsoft-agents-storage-cosmos` | [](https://pypi.org/project/microsoft-agents-storage-cosmos/) | Extension to use CosmosDB as storage. |
|
|
147
|
+
| `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` | [](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
|
+
)
|