microsoft-agents-hosting-msteams 1.7.0.dev9__tar.gz → 1.8.0.dev0__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.7.0.dev9/microsoft_agents_hosting_msteams.egg-info → microsoft_agents_hosting_msteams-1.8.0.dev0}/PKG-INFO +48 -5
- microsoft_agents_hosting_msteams-1.8.0.dev0/VERSION.txt +1 -0
- microsoft_agents_hosting_msteams-1.8.0.dev0/microsoft_agents/hosting/msteams/_teams_api_client.py +132 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents/hosting/msteams/_utils.py +40 -0
- microsoft_agents_hosting_msteams-1.8.0.dev0/microsoft_agents/hosting/msteams/models/__init__.py +7 -0
- microsoft_agents_hosting_msteams-1.8.0.dev0/microsoft_agents/hosting/msteams/models/quoted_reply.py +24 -0
- microsoft_agents_hosting_msteams-1.8.0.dev0/microsoft_agents/hosting/msteams/models/targeted_message_info.py +12 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents/hosting/msteams/teams_activity.py +55 -1
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents/hosting/msteams/teams_agent_extension.py +8 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents/hosting/msteams/teams_turn_context.py +77 -24
- microsoft_agents_hosting_msteams-1.7.0.dev9/readme.md → microsoft_agents_hosting_msteams-1.8.0.dev0/microsoft_agents_hosting_msteams.egg-info/PKG-INFO +69 -3
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents_hosting_msteams.egg-info/SOURCES.txt +3 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents_hosting_msteams.egg-info/requires.txt +1 -1
- microsoft_agents_hosting_msteams-1.7.0.dev9/PKG-INFO → microsoft_agents_hosting_msteams-1.8.0.dev0/readme.md +46 -26
- microsoft_agents_hosting_msteams-1.7.0.dev9/VERSION.txt +0 -1
- microsoft_agents_hosting_msteams-1.7.0.dev9/microsoft_agents/hosting/msteams/_teams_api_client.py +0 -76
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/LICENSE +0 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/MANIFEST.in +0 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents/hosting/msteams/__init__.py +0 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents/hosting/msteams/_graph.py +0 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents/hosting/msteams/channel/__init__.py +0 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents/hosting/msteams/channel/channel.py +0 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents/hosting/msteams/channel/route_handlers.py +0 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents/hosting/msteams/config/__init__.py +0 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents/hosting/msteams/config/config.py +0 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents/hosting/msteams/config/route_handlers.py +0 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents/hosting/msteams/errors/__init__.py +0 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents/hosting/msteams/errors/error_resources.py +0 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents/hosting/msteams/file_consent/__init__.py +0 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents/hosting/msteams/file_consent/file_consent.py +0 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents/hosting/msteams/file_consent/route_handlers.py +0 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents/hosting/msteams/meeting/__init__.py +0 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents/hosting/msteams/meeting/meeting.py +0 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents/hosting/msteams/meeting/route_handlers.py +0 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents/hosting/msteams/message/__init__.py +0 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents/hosting/msteams/message/message.py +0 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents/hosting/msteams/message/route_handlers.py +0 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents/hosting/msteams/message_extension/__init__.py +0 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents/hosting/msteams/message_extension/message_extension.py +0 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents/hosting/msteams/message_extension/route_handlers.py +0 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents/hosting/msteams/proactive_service_endpoints.py +0 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents/hosting/msteams/py.typed +0 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents/hosting/msteams/route_handlers.py +0 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents/hosting/msteams/task_module/__init__.py +0 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents/hosting/msteams/task_module/route_handlers.py +0 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents/hosting/msteams/task_module/task_module.py +0 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents/hosting/msteams/team/__init__.py +0 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents/hosting/msteams/team/route_handlers.py +0 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents/hosting/msteams/team/team.py +0 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents/hosting/msteams/type_defs.py +0 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents_hosting_msteams.egg-info/dependency_links.txt +0 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/microsoft_agents_hosting_msteams.egg-info/top_level.txt +0 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/pyproject.toml +0 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/setup.cfg +0 -0
- {microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: microsoft-agents-hosting-msteams
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.8.0.dev0
|
|
4
4
|
Summary: Integration library for Microsoft Agents with Teams
|
|
5
5
|
Author: Microsoft Corporation
|
|
6
6
|
License-Expression: MIT
|
|
@@ -14,7 +14,7 @@ Classifier: Operating System :: OS Independent
|
|
|
14
14
|
Requires-Python: >=3.11
|
|
15
15
|
Description-Content-Type: text/markdown
|
|
16
16
|
License-File: LICENSE
|
|
17
|
-
Requires-Dist: microsoft-agents-hosting-core==1.
|
|
17
|
+
Requires-Dist: microsoft-agents-hosting-core==1.8.0.dev0
|
|
18
18
|
Requires-Dist: aiohttp>=3.11.11
|
|
19
19
|
Requires-Dist: microsoft-teams-api==2.1.0
|
|
20
20
|
Requires-Dist: msgraph-sdk>=1.58.0
|
|
@@ -41,6 +41,15 @@ This library is part of the **Microsoft 365 Agents SDK for Python** — a compre
|
|
|
41
41
|
<th style="width:20%">Date</th>
|
|
42
42
|
<th style="width:60%">Release Notes</th>
|
|
43
43
|
</tr>
|
|
44
|
+
<tr>
|
|
45
|
+
<td>1.8.0</td>
|
|
46
|
+
<td>2026-10-01</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-v180">
|
|
49
|
+
1.8.0 Release Notes
|
|
50
|
+
</a>
|
|
51
|
+
</td>
|
|
52
|
+
</tr>
|
|
44
53
|
<tr>
|
|
45
54
|
<td>1.7.0</td>
|
|
46
55
|
<td>2026-09-17</td>
|
|
@@ -253,6 +262,10 @@ context.activity.notify_user(alert_in_meeting=True)
|
|
|
253
262
|
|
|
254
263
|
# Attach a feedback loop to a message being sent (Copilot scenarios)
|
|
255
264
|
context.activity.enable_feedback_loop()
|
|
265
|
+
|
|
266
|
+
# Inspect quoted messages or targeted-message metadata
|
|
267
|
+
quoted_messages = context.activity.get_quoted_messages()
|
|
268
|
+
targeted_message = context.activity.get_targeted_message_info()
|
|
256
269
|
```
|
|
257
270
|
|
|
258
271
|
#### `context.api_client` → `ApiClient`
|
|
@@ -261,13 +274,43 @@ Direct access to the Teams REST API client, pre-authenticated for the current tu
|
|
|
261
274
|
|
|
262
275
|
#### Sending targeted activities
|
|
263
276
|
|
|
264
|
-
`TeamsTurnContext`
|
|
277
|
+
Use `TeamsTurnContext.send_targeted_activity()` to send a private activity to a
|
|
278
|
+
specific user in a meeting or group conversation. Pass either the recipient ID
|
|
279
|
+
or a `ChannelAccount`:
|
|
265
280
|
|
|
266
281
|
```python
|
|
267
|
-
await context.send_targeted_activity(
|
|
268
|
-
|
|
282
|
+
await context.send_targeted_activity(
|
|
283
|
+
"Only you can see this message.",
|
|
284
|
+
recipient.id,
|
|
285
|
+
)
|
|
269
286
|
```
|
|
270
287
|
|
|
288
|
+
Replies to inbound targeted activities automatically include the prompt-preview
|
|
289
|
+
metadata required by Teams.
|
|
290
|
+
|
|
291
|
+
#### Sending quoted replies
|
|
292
|
+
|
|
293
|
+
Use `TeamsActivity.add_quoted_reply()` to quote an existing message:
|
|
294
|
+
|
|
295
|
+
```python
|
|
296
|
+
from microsoft_agents.activity import ActivityTypes
|
|
297
|
+
from microsoft_agents.hosting.msteams import TeamsActivity
|
|
298
|
+
|
|
299
|
+
message_id = context.activity.id
|
|
300
|
+
if not message_id:
|
|
301
|
+
raise ValueError("Message ID is required for a quoted reply.")
|
|
302
|
+
|
|
303
|
+
reply = TeamsActivity(type=ActivityTypes.message)
|
|
304
|
+
reply.add_quoted_reply(
|
|
305
|
+
message_id,
|
|
306
|
+
"This response includes a quote of your message.",
|
|
307
|
+
)
|
|
308
|
+
await context.send_activity(reply)
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
Use `context.activity.get_quoted_messages()` to inspect quoted messages on an
|
|
312
|
+
incoming activity.
|
|
313
|
+
|
|
271
314
|
### Messaging Extensions
|
|
272
315
|
|
|
273
316
|
```python
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1.8.0.dev0
|
microsoft_agents_hosting_msteams-1.8.0.dev0/microsoft_agents/hosting/msteams/_teams_api_client.py
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation. All rights reserved.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
|
|
4
|
+
"""Construction and caching of the Teams :class:`ApiClient` for a turn.
|
|
5
|
+
|
|
6
|
+
The client is cached on turn context services so it is built at most once per turn, and
|
|
7
|
+
is configured with a token factory derived from the turn's identity when one is
|
|
8
|
+
available.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import ssl
|
|
12
|
+
import certifi
|
|
13
|
+
|
|
14
|
+
from typing import Callable, Awaitable
|
|
15
|
+
|
|
16
|
+
import httpx
|
|
17
|
+
|
|
18
|
+
from microsoft_teams.common import Client, ClientOptions
|
|
19
|
+
from microsoft_teams.api import ApiClient
|
|
20
|
+
|
|
21
|
+
from microsoft_agents.hosting.core import (
|
|
22
|
+
Connections,
|
|
23
|
+
TurnContext,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
_ssl_context: ssl.SSLContext | None = None
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _get_ssl_context() -> ssl.SSLContext:
|
|
30
|
+
"""Get or create the SSL context for verifying HTTPS requests.
|
|
31
|
+
|
|
32
|
+
httpx by default creates a new SSL context for each new client instance. This can be
|
|
33
|
+
inefficient. For example, at the time of writing this, without caching the SSL context,
|
|
34
|
+
the hosting_msteams unit tests took 32 seconds to complete. With caching, the total
|
|
35
|
+
time for the unit tests dropped to 7 seconds. For an agent with lots of traffic,
|
|
36
|
+
caching the SSL context may significantly improve performance and avoid extra io operations.
|
|
37
|
+
"""
|
|
38
|
+
global _ssl_context
|
|
39
|
+
|
|
40
|
+
if _ssl_context is None:
|
|
41
|
+
_ssl_context = ssl.create_default_context(cafile=certifi.where())
|
|
42
|
+
return _ssl_context
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _client(
|
|
46
|
+
base_url: str,
|
|
47
|
+
headers: dict,
|
|
48
|
+
token_factory: Callable[[], Awaitable[str]] | None = None,
|
|
49
|
+
) -> Client:
|
|
50
|
+
"""
|
|
51
|
+
Create a new Client instance configured with the given base URL, headers, and token factory.
|
|
52
|
+
|
|
53
|
+
:param base_url: The base URL for the client.
|
|
54
|
+
:param headers: The headers to include in the client requests.
|
|
55
|
+
:param token_factory: A callable that returns an access token asynchronously, or None if no token is required.
|
|
56
|
+
:return: A configured Client instance.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
options = ClientOptions(
|
|
60
|
+
base_url=base_url,
|
|
61
|
+
headers=headers,
|
|
62
|
+
token=token_factory,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
return Client(
|
|
66
|
+
options,
|
|
67
|
+
_http=httpx.AsyncClient(
|
|
68
|
+
base_url=base_url,
|
|
69
|
+
headers=headers,
|
|
70
|
+
timeout=options.timeout,
|
|
71
|
+
verify=_get_ssl_context(),
|
|
72
|
+
),
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _get_teams_api_client(context: TurnContext) -> ApiClient:
|
|
77
|
+
"""
|
|
78
|
+
Get the cached Teams API client from the context.
|
|
79
|
+
|
|
80
|
+
:param context: The turn context.
|
|
81
|
+
:return: The cached Teams API client.
|
|
82
|
+
:raises ValueError: If the Teams API client is not found.
|
|
83
|
+
"""
|
|
84
|
+
api_client = context.services.get(ApiClient)
|
|
85
|
+
if isinstance(api_client, ApiClient):
|
|
86
|
+
return api_client
|
|
87
|
+
raise ValueError("Unable to retrieve Teams API client.")
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _set_teams_api_client(
|
|
91
|
+
context: TurnContext, connection_manager: Connections
|
|
92
|
+
) -> None:
|
|
93
|
+
"""
|
|
94
|
+
Set the Teams API client in the context if it is not already set.
|
|
95
|
+
|
|
96
|
+
:param context: The turn context.
|
|
97
|
+
:param connection_manager: The connection manager.
|
|
98
|
+
"""
|
|
99
|
+
|
|
100
|
+
if context.services.has(ApiClient):
|
|
101
|
+
return
|
|
102
|
+
|
|
103
|
+
headers = {
|
|
104
|
+
"Accept": "application/json",
|
|
105
|
+
"Content-Type": "application/json",
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
token_factory: Callable[[], Awaitable[str]] | None = None
|
|
109
|
+
|
|
110
|
+
if context.identity:
|
|
111
|
+
provider = connection_manager.get_token_provider(
|
|
112
|
+
context.identity, context.activity.service_url
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
async def _token_factory() -> str:
|
|
116
|
+
return await provider.get_access_token(
|
|
117
|
+
"https://api.botframework.com",
|
|
118
|
+
["https://api.botframework.com/.default"],
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
token_factory = _token_factory
|
|
122
|
+
|
|
123
|
+
api_client = ApiClient(
|
|
124
|
+
context.activity.service_url,
|
|
125
|
+
options=_client(
|
|
126
|
+
base_url=context.activity.service_url,
|
|
127
|
+
headers=headers,
|
|
128
|
+
token_factory=token_factory,
|
|
129
|
+
),
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
context.services.set(ApiClient, api_client)
|
|
@@ -14,10 +14,12 @@ from microsoft_teams.api.models.channel_data import ChannelData, ChannelInfo, Te
|
|
|
14
14
|
from microsoft_agents.activity import (
|
|
15
15
|
Activity,
|
|
16
16
|
ActivityTypes,
|
|
17
|
+
Entity,
|
|
17
18
|
InvokeResponse,
|
|
18
19
|
)
|
|
19
20
|
from microsoft_agents.hosting.core import TurnContext
|
|
20
21
|
|
|
22
|
+
from .models import TargetedMessageInfo
|
|
21
23
|
from .type_defs import CommandSelector
|
|
22
24
|
|
|
23
25
|
|
|
@@ -146,3 +148,41 @@ async def _send_invoke_response(context: TurnContext, body: Any = None) -> None:
|
|
|
146
148
|
value=InvokeResponse(status=int(HTTPStatus.OK), body=serialized_body),
|
|
147
149
|
)
|
|
148
150
|
)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def _apply_prompt_preview_normalizer(activity: Activity, message_id: str) -> None:
|
|
154
|
+
"""Normalize the prompt preview for the given activity.
|
|
155
|
+
|
|
156
|
+
:param activity: The activity to normalize.
|
|
157
|
+
:param message_id: The message ID to associate with the targeted message info.
|
|
158
|
+
:return: None
|
|
159
|
+
"""
|
|
160
|
+
pattern = re.compile(r"<quoted messageId=\"[^\"]*\"/>")
|
|
161
|
+
target_type = "quotedreply"
|
|
162
|
+
if activity.entities:
|
|
163
|
+
|
|
164
|
+
def _keep(entity: Entity) -> bool:
|
|
165
|
+
return entity.type.lower() != target_type
|
|
166
|
+
|
|
167
|
+
activity.entities[:] = [entity for entity in activity.entities if _keep(entity)]
|
|
168
|
+
|
|
169
|
+
if activity.text:
|
|
170
|
+
text_without_placeholder = pattern.sub("", activity.text)
|
|
171
|
+
if len(text_without_placeholder) != len(activity.text):
|
|
172
|
+
activity.text = text_without_placeholder.strip()
|
|
173
|
+
|
|
174
|
+
if not activity._get_entities_by_type("targetedmessageinfo"):
|
|
175
|
+
activity.entities = activity.entities or []
|
|
176
|
+
activity.entities.append(TargetedMessageInfo(message_id=message_id))
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def _is_recipient_targeted(activity: Activity) -> bool:
|
|
180
|
+
"""Check if the recipient is targeted in the given activity.
|
|
181
|
+
|
|
182
|
+
:param activity: The activity to check.
|
|
183
|
+
:return: True if the recipient is targeted, False otherwise.
|
|
184
|
+
"""
|
|
185
|
+
recipient = activity.recipient
|
|
186
|
+
if recipient is None:
|
|
187
|
+
return False
|
|
188
|
+
return recipient and getattr(recipient, "isTargeted", None) is True
|
microsoft_agents_hosting_msteams-1.8.0.dev0/microsoft_agents/hosting/msteams/models/__init__.py
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation. All rights reserved.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
|
|
4
|
+
from .quoted_reply import QuotedReply, QuotedReplyData
|
|
5
|
+
from .targeted_message_info import TargetedMessageInfo
|
|
6
|
+
|
|
7
|
+
__all__ = ["QuotedReply", "QuotedReplyData", "TargetedMessageInfo"]
|
microsoft_agents_hosting_msteams-1.8.0.dev0/microsoft_agents/hosting/msteams/models/quoted_reply.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation. All rights reserved.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
|
|
4
|
+
from typing import Literal
|
|
5
|
+
from microsoft_agents.activity import AgentsModel, Entity
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class QuotedReplyData(AgentsModel):
|
|
9
|
+
"""Represents a quoted reply in a Teams activity."""
|
|
10
|
+
|
|
11
|
+
message_id: str
|
|
12
|
+
sender_id: str | None = None
|
|
13
|
+
sender_name: str | None = None
|
|
14
|
+
preview: str | None = None
|
|
15
|
+
time: str | None = None
|
|
16
|
+
is_reply_deleted: bool | None = None
|
|
17
|
+
validated_message_reference: bool | None = None
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class QuotedReply(Entity):
|
|
21
|
+
"""Contains the metadata for a quoted Teams message."""
|
|
22
|
+
|
|
23
|
+
type: Literal["quotedReply"] = "quotedReply"
|
|
24
|
+
quoted_reply: QuotedReplyData | None = None
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation. All rights reserved.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
|
|
4
|
+
from typing import Literal
|
|
5
|
+
from microsoft_agents.activity import Entity
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TargetedMessageInfo(Entity):
|
|
9
|
+
"""Identifies the inbound targeted message associated with a Prompt Preview response."""
|
|
10
|
+
|
|
11
|
+
type: Literal["targetedMessageInfo"] = "targetedMessageInfo"
|
|
12
|
+
message_id: str
|
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
|
|
4
4
|
"""Teams-aware :class:`Activity` subclass exposing Teams channel data helpers."""
|
|
5
5
|
|
|
6
|
+
import html
|
|
7
|
+
|
|
6
8
|
from typing import Literal
|
|
9
|
+
from typing_extensions import Self
|
|
7
10
|
|
|
8
11
|
from microsoft_teams.api.models import (
|
|
9
12
|
ChannelData,
|
|
@@ -15,7 +18,8 @@ from microsoft_teams.api.models import (
|
|
|
15
18
|
|
|
16
19
|
from microsoft_agents.activity import Activity
|
|
17
20
|
|
|
18
|
-
from .
|
|
21
|
+
from .models import QuotedReply, QuotedReplyData, TargetedMessageInfo
|
|
22
|
+
from ._utils import _try_get_channel_data, _is_recipient_targeted
|
|
19
23
|
|
|
20
24
|
|
|
21
25
|
class TeamsActivity(Activity):
|
|
@@ -121,3 +125,53 @@ class TeamsActivity(Activity):
|
|
|
121
125
|
feedback_loop=FeedbackLoop(type=feedback_loop_type)
|
|
122
126
|
)
|
|
123
127
|
return True
|
|
128
|
+
|
|
129
|
+
def is_recipient_targeted(self) -> bool:
|
|
130
|
+
"""Check if the recipient is targeted in the activity.
|
|
131
|
+
|
|
132
|
+
:return: True if the recipient is targeted, False otherwise.
|
|
133
|
+
"""
|
|
134
|
+
return _is_recipient_targeted(self)
|
|
135
|
+
|
|
136
|
+
def get_targeted_message_info(self) -> TargetedMessageInfo | None:
|
|
137
|
+
"""Get the targeted message information from the activity.
|
|
138
|
+
|
|
139
|
+
:return: The targeted message information if available, None otherwise.
|
|
140
|
+
"""
|
|
141
|
+
res = self._get_entity_by_type("targetedMessageInfo")
|
|
142
|
+
if res:
|
|
143
|
+
return self._convert_entity(res, entity_cls=TargetedMessageInfo)
|
|
144
|
+
return None
|
|
145
|
+
|
|
146
|
+
def get_quoted_messages(self) -> list[QuotedReply]:
|
|
147
|
+
"""Get the quoted messages from the activity.
|
|
148
|
+
|
|
149
|
+
:return: A list of quoted messages.
|
|
150
|
+
"""
|
|
151
|
+
return self._convert_entity_list(
|
|
152
|
+
self._get_entities_by_type("quotedReply"), entity_cls=QuotedReply
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
def add_quoted_reply(self, message_id: str, text: str | None = None) -> Self:
|
|
156
|
+
"""Add a quoted reply to the activity.
|
|
157
|
+
|
|
158
|
+
:param message_id: The ID of the message being quoted.
|
|
159
|
+
:param text: The text of the quoted reply.
|
|
160
|
+
:return: The updated activity instance.
|
|
161
|
+
"""
|
|
162
|
+
self.entities = self.entities or []
|
|
163
|
+
self.entities.append(
|
|
164
|
+
QuotedReply(
|
|
165
|
+
type="quotedReply",
|
|
166
|
+
quoted_reply=QuotedReplyData(
|
|
167
|
+
message_id=message_id,
|
|
168
|
+
),
|
|
169
|
+
)
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
placeholder = f'<quoted messageId="{html.escape(message_id, quote=True)}"/>'
|
|
173
|
+
self.text = f"{self.text or ''}{placeholder}"
|
|
174
|
+
if text is not None:
|
|
175
|
+
self.text = f"{self.text} {text}"
|
|
176
|
+
|
|
177
|
+
return self
|
|
@@ -123,9 +123,17 @@ class TeamsAgentExtension(Generic[StateT]):
|
|
|
123
123
|
def _configure_app(self):
|
|
124
124
|
"""Configure the underlying AgentApplication with Teams-specific routes."""
|
|
125
125
|
|
|
126
|
+
async def on_close_turn(context: TurnContext) -> None:
|
|
127
|
+
if context.activity.channel_id == Channels.ms_teams:
|
|
128
|
+
api_client = context.services.get(ApiClient)
|
|
129
|
+
if api_client is not None:
|
|
130
|
+
await api_client.http.http.aclose()
|
|
131
|
+
|
|
126
132
|
async def on_before_turn(context: TurnContext, state: StateT) -> bool:
|
|
127
133
|
if context.activity.channel_id == Channels.ms_teams:
|
|
128
134
|
_set_teams_api_client(context, self._app.connection_manager)
|
|
135
|
+
context._on_aclose(on_close_turn)
|
|
136
|
+
|
|
129
137
|
# caches the deserialized version of ChannelData
|
|
130
138
|
context.activity.channel_data = _try_get_channel_data(context.activity)
|
|
131
139
|
return True
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
from __future__ import annotations
|
|
7
7
|
|
|
8
|
+
import warnings
|
|
8
9
|
from typing import cast
|
|
9
10
|
|
|
10
11
|
from msgraph import GraphServiceClient
|
|
@@ -13,8 +14,9 @@ from microsoft_teams.api import ApiClient
|
|
|
13
14
|
|
|
14
15
|
from microsoft_agents.activity import (
|
|
15
16
|
Activity,
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
ActivityTypes,
|
|
18
|
+
ChannelAccount,
|
|
19
|
+
InputHints,
|
|
18
20
|
ResourceResponse,
|
|
19
21
|
)
|
|
20
22
|
from microsoft_agents.hosting.core import (
|
|
@@ -30,6 +32,7 @@ from ._graph import (
|
|
|
30
32
|
)
|
|
31
33
|
from ._teams_api_client import _get_teams_api_client, _set_teams_api_client
|
|
32
34
|
from .teams_activity import TeamsActivity
|
|
35
|
+
from ._utils import _apply_prompt_preview_normalizer, _is_recipient_targeted
|
|
33
36
|
|
|
34
37
|
|
|
35
38
|
class TeamsTurnContext(TurnContext):
|
|
@@ -98,42 +101,92 @@ class TeamsTurnContext(TurnContext):
|
|
|
98
101
|
"""Get the API client for the Teams turn context."""
|
|
99
102
|
return _get_teams_api_client(self)
|
|
100
103
|
|
|
101
|
-
|
|
102
|
-
def _make_targeted_activity(activity: Activity) -> None:
|
|
104
|
+
def _apply_prompt_preview(self, activity: Activity) -> None:
|
|
103
105
|
"""
|
|
104
|
-
|
|
106
|
+
Apply the prompt preview to the given activity.
|
|
105
107
|
|
|
106
|
-
:param activity: The activity to
|
|
108
|
+
:param activity: The activity to apply the prompt preview to.
|
|
107
109
|
:return: None
|
|
108
110
|
"""
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
111
|
+
if (
|
|
112
|
+
activity.type == ActivityTypes.message
|
|
113
|
+
and _is_recipient_targeted(self.activity)
|
|
114
|
+
and self.activity.id
|
|
115
|
+
):
|
|
116
|
+
_apply_prompt_preview_normalizer(activity, self.activity.id)
|
|
117
|
+
|
|
118
|
+
async def send_activity(
|
|
119
|
+
self,
|
|
120
|
+
activity_or_text: Activity | str,
|
|
121
|
+
speak: str | None = None,
|
|
122
|
+
input_hint: str | None = None,
|
|
123
|
+
) -> ResourceResponse:
|
|
124
|
+
"""Send an activity after applying the prompt preview.
|
|
125
|
+
|
|
126
|
+
:param activity_or_text: The activity or text to send.
|
|
127
|
+
:param speak: Optional speech text for the activity.
|
|
128
|
+
:param input_hint: Optional input hint for the activity.
|
|
129
|
+
:return: The resource response for the sent activity.
|
|
130
|
+
"""
|
|
131
|
+
|
|
132
|
+
if isinstance(activity_or_text, str):
|
|
133
|
+
activity_or_text = Activity(
|
|
134
|
+
type=ActivityTypes.message,
|
|
135
|
+
text=activity_or_text,
|
|
136
|
+
input_hint=input_hint or InputHints.accepting_input,
|
|
137
|
+
)
|
|
138
|
+
if speak:
|
|
139
|
+
activity_or_text.speak = speak
|
|
140
|
+
|
|
141
|
+
self._apply_prompt_preview(activity_or_text)
|
|
142
|
+
return await TurnContext.send_activity(self._original, activity_or_text)
|
|
143
|
+
|
|
144
|
+
async def send_activities(
|
|
145
|
+
self, activities: list[Activity]
|
|
146
|
+
) -> list[ResourceResponse]:
|
|
147
|
+
"""Send multiple activities after applying the prompt preview to each.
|
|
148
|
+
|
|
149
|
+
:param activities: A list of activities to send.
|
|
150
|
+
:return: A list of resource responses for the sent activities.
|
|
151
|
+
"""
|
|
152
|
+
|
|
153
|
+
for activity in activities:
|
|
154
|
+
self._apply_prompt_preview(activity)
|
|
155
|
+
|
|
156
|
+
return await TurnContext.send_activities(
|
|
157
|
+
self._original,
|
|
158
|
+
activities,
|
|
112
159
|
)
|
|
113
160
|
|
|
114
|
-
async def send_targeted_activity(
|
|
161
|
+
async def send_targeted_activity(
|
|
162
|
+
self,
|
|
163
|
+
activity: str | Activity,
|
|
164
|
+
recipient: str | ChannelAccount | None = None,
|
|
165
|
+
) -> ResourceResponse:
|
|
115
166
|
"""
|
|
116
167
|
Send a targeted activity.
|
|
117
168
|
|
|
118
169
|
:param activity: The activity to send.
|
|
170
|
+
:param recipient: The recipient to target the activity to. Can be a string or a ChannelAccount instance.
|
|
119
171
|
:return: The resource response.
|
|
120
172
|
"""
|
|
121
|
-
|
|
173
|
+
if recipient is None:
|
|
174
|
+
warnings.warn(
|
|
175
|
+
"Using an empty recipient is deprecated and will be removed in a future release.",
|
|
176
|
+
DeprecationWarning,
|
|
177
|
+
stacklevel=2,
|
|
178
|
+
)
|
|
179
|
+
if isinstance(activity, str) or not activity.recipient:
|
|
180
|
+
raise ValueError(
|
|
181
|
+
"Cannot infer the recipient from the passed-in activity."
|
|
182
|
+
)
|
|
183
|
+
recipient = activity.recipient
|
|
184
|
+
|
|
185
|
+
if isinstance(activity, str):
|
|
186
|
+
activity = Activity(type=ActivityTypes.message, text=activity)
|
|
187
|
+
activity.with_targeted_recipient(recipient)
|
|
122
188
|
return await self.send_activity(activity)
|
|
123
189
|
|
|
124
|
-
async def send_targeted_activities(
|
|
125
|
-
self, activities: list[Activity]
|
|
126
|
-
) -> list[ResourceResponse]:
|
|
127
|
-
"""
|
|
128
|
-
Send a list of targeted activities.
|
|
129
|
-
|
|
130
|
-
:param activities: The list of activities to send.
|
|
131
|
-
:return: A list of resource responses.
|
|
132
|
-
"""
|
|
133
|
-
for activity in activities:
|
|
134
|
-
TeamsTurnContext._make_targeted_activity(activity)
|
|
135
|
-
return await self.send_activities(activities)
|
|
136
|
-
|
|
137
190
|
def get_graph_client(
|
|
138
191
|
self,
|
|
139
192
|
handler_name: str | None = None,
|
|
@@ -1,3 +1,26 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: microsoft-agents-hosting-msteams
|
|
3
|
+
Version: 1.8.0.dev0
|
|
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.8.0.dev0
|
|
18
|
+
Requires-Dist: aiohttp>=3.11.11
|
|
19
|
+
Requires-Dist: microsoft-teams-api==2.1.0
|
|
20
|
+
Requires-Dist: msgraph-sdk>=1.58.0
|
|
21
|
+
Dynamic: license-file
|
|
22
|
+
Dynamic: requires-dist
|
|
23
|
+
|
|
1
24
|
# microsoft-agents-hosting-msteams
|
|
2
25
|
|
|
3
26
|
[](https://pypi.org/project/microsoft-agents-hosting-msteams/)
|
|
@@ -18,6 +41,15 @@ This library is part of the **Microsoft 365 Agents SDK for Python** — a compre
|
|
|
18
41
|
<th style="width:20%">Date</th>
|
|
19
42
|
<th style="width:60%">Release Notes</th>
|
|
20
43
|
</tr>
|
|
44
|
+
<tr>
|
|
45
|
+
<td>1.8.0</td>
|
|
46
|
+
<td>2026-10-01</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-v180">
|
|
49
|
+
1.8.0 Release Notes
|
|
50
|
+
</a>
|
|
51
|
+
</td>
|
|
52
|
+
</tr>
|
|
21
53
|
<tr>
|
|
22
54
|
<td>1.7.0</td>
|
|
23
55
|
<td>2026-09-17</td>
|
|
@@ -230,6 +262,10 @@ context.activity.notify_user(alert_in_meeting=True)
|
|
|
230
262
|
|
|
231
263
|
# Attach a feedback loop to a message being sent (Copilot scenarios)
|
|
232
264
|
context.activity.enable_feedback_loop()
|
|
265
|
+
|
|
266
|
+
# Inspect quoted messages or targeted-message metadata
|
|
267
|
+
quoted_messages = context.activity.get_quoted_messages()
|
|
268
|
+
targeted_message = context.activity.get_targeted_message_info()
|
|
233
269
|
```
|
|
234
270
|
|
|
235
271
|
#### `context.api_client` → `ApiClient`
|
|
@@ -238,13 +274,43 @@ Direct access to the Teams REST API client, pre-authenticated for the current tu
|
|
|
238
274
|
|
|
239
275
|
#### Sending targeted activities
|
|
240
276
|
|
|
241
|
-
`TeamsTurnContext`
|
|
277
|
+
Use `TeamsTurnContext.send_targeted_activity()` to send a private activity to a
|
|
278
|
+
specific user in a meeting or group conversation. Pass either the recipient ID
|
|
279
|
+
or a `ChannelAccount`:
|
|
280
|
+
|
|
281
|
+
```python
|
|
282
|
+
await context.send_targeted_activity(
|
|
283
|
+
"Only you can see this message.",
|
|
284
|
+
recipient.id,
|
|
285
|
+
)
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
Replies to inbound targeted activities automatically include the prompt-preview
|
|
289
|
+
metadata required by Teams.
|
|
290
|
+
|
|
291
|
+
#### Sending quoted replies
|
|
292
|
+
|
|
293
|
+
Use `TeamsActivity.add_quoted_reply()` to quote an existing message:
|
|
242
294
|
|
|
243
295
|
```python
|
|
244
|
-
|
|
245
|
-
|
|
296
|
+
from microsoft_agents.activity import ActivityTypes
|
|
297
|
+
from microsoft_agents.hosting.msteams import TeamsActivity
|
|
298
|
+
|
|
299
|
+
message_id = context.activity.id
|
|
300
|
+
if not message_id:
|
|
301
|
+
raise ValueError("Message ID is required for a quoted reply.")
|
|
302
|
+
|
|
303
|
+
reply = TeamsActivity(type=ActivityTypes.message)
|
|
304
|
+
reply.add_quoted_reply(
|
|
305
|
+
message_id,
|
|
306
|
+
"This response includes a quote of your message.",
|
|
307
|
+
)
|
|
308
|
+
await context.send_activity(reply)
|
|
246
309
|
```
|
|
247
310
|
|
|
311
|
+
Use `context.activity.get_quoted_messages()` to inspect quoted messages on an
|
|
312
|
+
incoming activity.
|
|
313
|
+
|
|
248
314
|
### Messaging Extensions
|
|
249
315
|
|
|
250
316
|
```python
|
|
@@ -35,6 +35,9 @@ microsoft_agents/hosting/msteams/message/route_handlers.py
|
|
|
35
35
|
microsoft_agents/hosting/msteams/message_extension/__init__.py
|
|
36
36
|
microsoft_agents/hosting/msteams/message_extension/message_extension.py
|
|
37
37
|
microsoft_agents/hosting/msteams/message_extension/route_handlers.py
|
|
38
|
+
microsoft_agents/hosting/msteams/models/__init__.py
|
|
39
|
+
microsoft_agents/hosting/msteams/models/quoted_reply.py
|
|
40
|
+
microsoft_agents/hosting/msteams/models/targeted_message_info.py
|
|
38
41
|
microsoft_agents/hosting/msteams/task_module/__init__.py
|
|
39
42
|
microsoft_agents/hosting/msteams/task_module/route_handlers.py
|
|
40
43
|
microsoft_agents/hosting/msteams/task_module/task_module.py
|
|
@@ -1,26 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: microsoft-agents-hosting-msteams
|
|
3
|
-
Version: 1.7.0.dev9
|
|
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.7.0.dev9
|
|
18
|
-
Requires-Dist: aiohttp>=3.11.11
|
|
19
|
-
Requires-Dist: microsoft-teams-api==2.1.0
|
|
20
|
-
Requires-Dist: msgraph-sdk>=1.58.0
|
|
21
|
-
Dynamic: license-file
|
|
22
|
-
Dynamic: requires-dist
|
|
23
|
-
|
|
24
1
|
# microsoft-agents-hosting-msteams
|
|
25
2
|
|
|
26
3
|
[](https://pypi.org/project/microsoft-agents-hosting-msteams/)
|
|
@@ -41,6 +18,15 @@ This library is part of the **Microsoft 365 Agents SDK for Python** — a compre
|
|
|
41
18
|
<th style="width:20%">Date</th>
|
|
42
19
|
<th style="width:60%">Release Notes</th>
|
|
43
20
|
</tr>
|
|
21
|
+
<tr>
|
|
22
|
+
<td>1.8.0</td>
|
|
23
|
+
<td>2026-10-01</td>
|
|
24
|
+
<td>
|
|
25
|
+
<a href="https://github.com/microsoft/Agents-for-python/blob/main/changelog.md#microsoft-365-agents-sdk-for-python---release-notes-v180">
|
|
26
|
+
1.8.0 Release Notes
|
|
27
|
+
</a>
|
|
28
|
+
</td>
|
|
29
|
+
</tr>
|
|
44
30
|
<tr>
|
|
45
31
|
<td>1.7.0</td>
|
|
46
32
|
<td>2026-09-17</td>
|
|
@@ -253,6 +239,10 @@ context.activity.notify_user(alert_in_meeting=True)
|
|
|
253
239
|
|
|
254
240
|
# Attach a feedback loop to a message being sent (Copilot scenarios)
|
|
255
241
|
context.activity.enable_feedback_loop()
|
|
242
|
+
|
|
243
|
+
# Inspect quoted messages or targeted-message metadata
|
|
244
|
+
quoted_messages = context.activity.get_quoted_messages()
|
|
245
|
+
targeted_message = context.activity.get_targeted_message_info()
|
|
256
246
|
```
|
|
257
247
|
|
|
258
248
|
#### `context.api_client` → `ApiClient`
|
|
@@ -261,13 +251,43 @@ Direct access to the Teams REST API client, pre-authenticated for the current tu
|
|
|
261
251
|
|
|
262
252
|
#### Sending targeted activities
|
|
263
253
|
|
|
264
|
-
`TeamsTurnContext`
|
|
254
|
+
Use `TeamsTurnContext.send_targeted_activity()` to send a private activity to a
|
|
255
|
+
specific user in a meeting or group conversation. Pass either the recipient ID
|
|
256
|
+
or a `ChannelAccount`:
|
|
257
|
+
|
|
258
|
+
```python
|
|
259
|
+
await context.send_targeted_activity(
|
|
260
|
+
"Only you can see this message.",
|
|
261
|
+
recipient.id,
|
|
262
|
+
)
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
Replies to inbound targeted activities automatically include the prompt-preview
|
|
266
|
+
metadata required by Teams.
|
|
267
|
+
|
|
268
|
+
#### Sending quoted replies
|
|
269
|
+
|
|
270
|
+
Use `TeamsActivity.add_quoted_reply()` to quote an existing message:
|
|
265
271
|
|
|
266
272
|
```python
|
|
267
|
-
|
|
268
|
-
|
|
273
|
+
from microsoft_agents.activity import ActivityTypes
|
|
274
|
+
from microsoft_agents.hosting.msteams import TeamsActivity
|
|
275
|
+
|
|
276
|
+
message_id = context.activity.id
|
|
277
|
+
if not message_id:
|
|
278
|
+
raise ValueError("Message ID is required for a quoted reply.")
|
|
279
|
+
|
|
280
|
+
reply = TeamsActivity(type=ActivityTypes.message)
|
|
281
|
+
reply.add_quoted_reply(
|
|
282
|
+
message_id,
|
|
283
|
+
"This response includes a quote of your message.",
|
|
284
|
+
)
|
|
285
|
+
await context.send_activity(reply)
|
|
269
286
|
```
|
|
270
287
|
|
|
288
|
+
Use `context.activity.get_quoted_messages()` to inspect quoted messages on an
|
|
289
|
+
incoming activity.
|
|
290
|
+
|
|
271
291
|
### Messaging Extensions
|
|
272
292
|
|
|
273
293
|
```python
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
1.7.0.dev9
|
microsoft_agents_hosting_msteams-1.7.0.dev9/microsoft_agents/hosting/msteams/_teams_api_client.py
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
# Copyright (c) Microsoft Corporation. All rights reserved.
|
|
2
|
-
# Licensed under the MIT License.
|
|
3
|
-
|
|
4
|
-
"""Construction and caching of the Teams :class:`ApiClient` for a turn.
|
|
5
|
-
|
|
6
|
-
The client is cached on turn context services so it is built at most once per turn, and
|
|
7
|
-
is configured with a token factory derived from the turn's identity when one is
|
|
8
|
-
available.
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
from microsoft_teams.common import ClientOptions
|
|
12
|
-
from microsoft_teams.api import ApiClient
|
|
13
|
-
|
|
14
|
-
from microsoft_agents.hosting.core import (
|
|
15
|
-
Connections,
|
|
16
|
-
TurnContext,
|
|
17
|
-
)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def _get_teams_api_client(context: TurnContext) -> ApiClient:
|
|
21
|
-
"""
|
|
22
|
-
Get the cached Teams API client from the context.
|
|
23
|
-
|
|
24
|
-
:param context: The turn context.
|
|
25
|
-
:return: The cached Teams API client.
|
|
26
|
-
:raises ValueError: If the Teams API client is not found.
|
|
27
|
-
"""
|
|
28
|
-
api_client = context.services.get(ApiClient)
|
|
29
|
-
if isinstance(api_client, ApiClient):
|
|
30
|
-
return api_client
|
|
31
|
-
raise ValueError("Unable to retrieve Teams API client.")
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def _set_teams_api_client(
|
|
35
|
-
context: TurnContext, connection_manager: Connections
|
|
36
|
-
) -> None:
|
|
37
|
-
"""
|
|
38
|
-
Set the Teams API client in the context if it is not already set.
|
|
39
|
-
|
|
40
|
-
:param context: The turn context.
|
|
41
|
-
:param connection_manager: The connection manager.
|
|
42
|
-
"""
|
|
43
|
-
|
|
44
|
-
if context.services.has(ApiClient):
|
|
45
|
-
return
|
|
46
|
-
|
|
47
|
-
headers = {
|
|
48
|
-
"Accept": "application/json",
|
|
49
|
-
"Content-Type": "application/json",
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
options: ClientOptions
|
|
53
|
-
|
|
54
|
-
if context.identity:
|
|
55
|
-
provider = connection_manager.get_token_provider(
|
|
56
|
-
context.identity, context.activity.service_url
|
|
57
|
-
)
|
|
58
|
-
|
|
59
|
-
async def token_factory() -> str:
|
|
60
|
-
return await provider.get_access_token(
|
|
61
|
-
"https://api.botframework.com",
|
|
62
|
-
["https://api.botframework.com/.default"],
|
|
63
|
-
)
|
|
64
|
-
|
|
65
|
-
options = ClientOptions(
|
|
66
|
-
base_url=context.activity.service_url, headers=headers, token=token_factory
|
|
67
|
-
)
|
|
68
|
-
else:
|
|
69
|
-
options = ClientOptions(base_url=context.activity.service_url, headers=headers)
|
|
70
|
-
|
|
71
|
-
api_client = ApiClient(
|
|
72
|
-
context.activity.service_url,
|
|
73
|
-
options,
|
|
74
|
-
)
|
|
75
|
-
|
|
76
|
-
context.services.set(ApiClient, api_client)
|
{microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/LICENSE
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{microsoft_agents_hosting_msteams-1.7.0.dev9 → microsoft_agents_hosting_msteams-1.8.0.dev0}/setup.py
RENAMED
|
File without changes
|