microsoft-agents-hosting-core 0.4.0.dev18__py3-none-any.whl → 0.5.0__py3-none-any.whl

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 (29) hide show
  1. microsoft_agents/hosting/core/_oauth/_flow_state.py +2 -2
  2. microsoft_agents/hosting/core/_oauth/_oauth_flow.py +26 -23
  3. microsoft_agents/hosting/core/activity_handler.py +19 -17
  4. microsoft_agents/hosting/core/app/agent_application.py +37 -13
  5. microsoft_agents/hosting/core/app/input_file.py +15 -11
  6. microsoft_agents/hosting/core/app/oauth/_handlers/_authorization_handler.py +4 -4
  7. microsoft_agents/hosting/core/app/oauth/_handlers/_user_authorization.py +2 -2
  8. microsoft_agents/hosting/core/app/oauth/_handlers/agentic_user_authorization.py +9 -9
  9. microsoft_agents/hosting/core/app/oauth/authorization.py +38 -20
  10. microsoft_agents/hosting/core/app/state/state.py +50 -6
  11. microsoft_agents/hosting/core/app/typing_indicator.py +51 -27
  12. microsoft_agents/hosting/core/authorization/access_token_provider_base.py +1 -1
  13. microsoft_agents/hosting/core/authorization/anonymous_token_provider.py +1 -1
  14. microsoft_agents/hosting/core/authorization/jwt_token_validator.py +6 -4
  15. microsoft_agents/hosting/core/channel_adapter.py +9 -9
  16. microsoft_agents/hosting/core/channel_service_adapter.py +64 -6
  17. microsoft_agents/hosting/core/connector/client/connector_client.py +1 -1
  18. microsoft_agents/hosting/core/connector/client/user_token_client.py +40 -43
  19. microsoft_agents/hosting/core/connector/user_token_base.py +77 -1
  20. microsoft_agents/hosting/core/connector/user_token_client_base.py +3 -0
  21. microsoft_agents/hosting/core/state/agent_state.py +16 -20
  22. microsoft_agents/hosting/core/storage/transcript_file_store.py +1 -5
  23. microsoft_agents/hosting/core/turn_context.py +2 -1
  24. microsoft_agents_hosting_core-0.5.0.dist-info/METADATA +191 -0
  25. {microsoft_agents_hosting_core-0.4.0.dev18.dist-info → microsoft_agents_hosting_core-0.5.0.dist-info}/RECORD +28 -27
  26. microsoft_agents_hosting_core-0.5.0.dist-info/licenses/LICENSE +21 -0
  27. microsoft_agents_hosting_core-0.4.0.dev18.dist-info/METADATA +0 -16
  28. {microsoft_agents_hosting_core-0.4.0.dev18.dist-info → microsoft_agents_hosting_core-0.5.0.dist-info}/WHEEL +0 -0
  29. {microsoft_agents_hosting_core-0.4.0.dev18.dist-info → microsoft_agents_hosting_core-0.5.0.dist-info}/top_level.txt +0 -0
@@ -8,7 +8,12 @@ from typing import Optional
8
8
  from aiohttp import ClientSession
9
9
 
10
10
  from microsoft_agents.hosting.core.connector import UserTokenClientBase
11
- from microsoft_agents.activity import TokenResponse, TokenStatus, SignInResource
11
+ from microsoft_agents.activity import (
12
+ TokenOrSignInResourceResponse,
13
+ TokenResponse,
14
+ TokenStatus,
15
+ SignInResource,
16
+ )
12
17
  from ..get_product_info import get_product_info
13
18
  from ..user_token_base import UserTokenBase
14
19
  from ..agent_sign_in_base import AgentSignInBase
@@ -110,15 +115,6 @@ class UserToken(UserTokenBase):
110
115
  channel_id: Optional[str] = None,
111
116
  code: Optional[str] = None,
112
117
  ) -> TokenResponse:
113
- """
114
- Gets a token for a user and connection.
115
-
116
- :param user_id: ID of the user.
117
- :param connection_name: Name of the connection to use.
118
- :param channel_id: ID of the channel.
119
- :param code: Optional authorization code.
120
- :return: A token response.
121
- """
122
118
  params = {"userId": user_id, "connectionName": connection_name}
123
119
 
124
120
  if channel_id:
@@ -137,6 +133,40 @@ class UserToken(UserTokenBase):
137
133
  data = await response.json()
138
134
  return TokenResponse.model_validate(data)
139
135
 
136
+ async def _get_token_or_sign_in_resource(
137
+ self,
138
+ user_id: str,
139
+ connection_name: str,
140
+ channel_id: str,
141
+ state: str,
142
+ code: str = "",
143
+ final_redirect: str = "",
144
+ fwd_url: str = "",
145
+ ) -> TokenOrSignInResourceResponse:
146
+
147
+ params = {
148
+ "userId": user_id,
149
+ "connectionName": connection_name,
150
+ "channelId": channel_id,
151
+ "state": state,
152
+ "code": code,
153
+ "finalRedirect": final_redirect,
154
+ "fwdUrl": fwd_url,
155
+ }
156
+
157
+ logger.info("Getting token or sign-in resource with params: %s", params)
158
+ async with self.client.get(
159
+ "/api/usertoken/GetTokenOrSignInResource", params=params
160
+ ) as response:
161
+ if response.status != 200:
162
+ logger.error(
163
+ "Error getting token or sign-in resource: %s", response.status
164
+ )
165
+ response.raise_for_status()
166
+
167
+ data = await response.json()
168
+ return TokenOrSignInResourceResponse.model_validate(data)
169
+
140
170
  async def get_aad_tokens(
141
171
  self,
142
172
  user_id: str,
@@ -144,15 +174,6 @@ class UserToken(UserTokenBase):
144
174
  channel_id: Optional[str] = None,
145
175
  body: Optional[dict] = None,
146
176
  ) -> dict[str, TokenResponse]:
147
- """
148
- Gets Azure Active Directory tokens for a user and connection.
149
-
150
- :param user_id: ID of the user.
151
- :param connection_name: Name of the connection to use.
152
- :param channel_id: ID of the channel.
153
- :param body: An optional dictionary containing resource URLs.
154
- :return: A dictionary of tokens.
155
- """
156
177
  params = {"userId": user_id, "connectionName": connection_name}
157
178
 
158
179
  if channel_id:
@@ -175,13 +196,6 @@ class UserToken(UserTokenBase):
175
196
  connection_name: Optional[str] = None,
176
197
  channel_id: Optional[str] = None,
177
198
  ) -> None:
178
- """
179
- Signs the user out from the specified connection.
180
-
181
- :param user_id: ID of the user.
182
- :param connection_name: Name of the connection to use.
183
- :param channel_id: ID of the channel.
184
- """
185
199
  params = {"userId": user_id}
186
200
 
187
201
  if connection_name:
@@ -203,14 +217,6 @@ class UserToken(UserTokenBase):
203
217
  channel_id: Optional[str] = None,
204
218
  include: Optional[str] = None,
205
219
  ) -> list[TokenStatus]:
206
- """
207
- Gets token status for the user.
208
-
209
- :param user_id: ID of the user.
210
- :param channel_id: ID of the channel.
211
- :param include: Optional filter.
212
- :return: A list of token status objects.
213
- """
214
220
  params = {"userId": user_id}
215
221
 
216
222
  if channel_id:
@@ -236,15 +242,6 @@ class UserToken(UserTokenBase):
236
242
  channel_id: str,
237
243
  body: Optional[dict] = None,
238
244
  ) -> TokenResponse:
239
- """
240
- Exchanges a token.
241
-
242
- :param user_id: ID of the user.
243
- :param connection_name: Name of the connection to use.
244
- :param channel_id: ID of the channel.
245
- :param body: An optional token exchange request body.
246
- :return: A token response.
247
- """
248
245
  params = {
249
246
  "userId": user_id,
250
247
  "connectionName": connection_name,
@@ -1,10 +1,19 @@
1
+ # Copyright (c) Microsoft Corporation. All rights reserved.
2
+ # Licensed under the MIT License.
3
+
1
4
  from abc import abstractmethod
2
5
  from typing import Protocol
3
6
 
4
- from microsoft_agents.activity import TokenResponse, TokenStatus
7
+ from microsoft_agents.activity import (
8
+ TokenResponse,
9
+ TokenStatus,
10
+ TokenOrSignInResourceResponse,
11
+ )
5
12
 
6
13
 
7
14
  class UserTokenBase(Protocol):
15
+ """Base class for user token operations."""
16
+
8
17
  @abstractmethod
9
18
  async def get_token(
10
19
  self,
@@ -13,6 +22,40 @@ class UserTokenBase(Protocol):
13
22
  channel_id: str = None,
14
23
  code: str = None,
15
24
  ) -> TokenResponse:
25
+ """
26
+ Get sign-in URL.
27
+
28
+ :param state: State parameter for OAuth flow.
29
+ :param code_challenge: Code challenge for PKCE.
30
+ :param emulator_url: Emulator URL if used.
31
+ :param final_redirect: Final redirect URL.
32
+ :return: The sign-in URL.
33
+ """
34
+ raise NotImplementedError()
35
+
36
+ @abstractmethod
37
+ async def _get_token_or_sign_in_resource(
38
+ self,
39
+ user_id: str,
40
+ connection_name: str,
41
+ channel_id: str,
42
+ state: str,
43
+ code: str = "",
44
+ final_redirect: str = "",
45
+ fwd_url: str = "",
46
+ ) -> TokenOrSignInResourceResponse:
47
+ """
48
+ Gets a token or a sign-in resource for a user and connection.
49
+
50
+ :param user_id: ID of the user.
51
+ :param connection_name: Name of the connection to use.
52
+ :param channel_id: ID of the channel.
53
+ :param state: State parameter for OAuth flow.
54
+ :param code: Optional authorization code.
55
+ :param final_redirect: Final redirect URL.
56
+ :param fwd_url: Forward URL.
57
+ :return: A token or sign-in resource response.
58
+ """
16
59
  raise NotImplementedError()
17
60
 
18
61
  @abstractmethod
@@ -23,22 +66,55 @@ class UserTokenBase(Protocol):
23
66
  channel_id: str = None,
24
67
  body: dict = None,
25
68
  ) -> dict[str, TokenResponse]:
69
+ """
70
+ Gets Azure Active Directory tokens for a user and connection.
71
+
72
+ :param user_id: ID of the user.
73
+ :param connection_name: Name of the connection to use.
74
+ :param channel_id: ID of the channel.
75
+ :param body: An optional dictionary containing resource URLs.
76
+ :return: A dictionary of tokens.
77
+ """
26
78
  raise NotImplementedError()
27
79
 
28
80
  @abstractmethod
29
81
  async def sign_out(
30
82
  self, user_id: str, connection_name: str = None, channel_id: str = None
31
83
  ) -> None:
84
+ """
85
+ Signs the user out from the specified connection.
86
+
87
+ :param user_id: ID of the user.
88
+ :param connection_name: Name of the connection to use.
89
+ :param channel_id: ID of the channel.
90
+ """
32
91
  raise NotImplementedError()
33
92
 
34
93
  @abstractmethod
35
94
  async def get_token_status(
36
95
  self, user_id: str, channel_id: str = None, include: str = None
37
96
  ) -> list[TokenStatus]:
97
+ """
98
+ Gets token status for the user.
99
+
100
+ :param user_id: ID of the user.
101
+ :param channel_id: ID of the channel.
102
+ :param include: Optional filter.
103
+ :return: A list of token status objects.
104
+ """
38
105
  raise NotImplementedError()
39
106
 
40
107
  @abstractmethod
41
108
  async def exchange_token(
42
109
  self, user_id: str, connection_name: str, channel_id: str, body: dict = None
43
110
  ) -> TokenResponse:
111
+ """
112
+ Exchanges a token.
113
+
114
+ :param user_id: ID of the user.
115
+ :param connection_name: Name of the connection to use.
116
+ :param channel_id: ID of the channel.
117
+ :param body: An optional token exchange request body.
118
+ :return: A token response.
119
+ """
44
120
  raise NotImplementedError()
@@ -1,3 +1,6 @@
1
+ # Copyright (c) Microsoft Corporation. All rights reserved.
2
+ # Licensed under the MIT License.
3
+
1
4
  from abc import abstractmethod
2
5
  from typing import Protocol
3
6
 
@@ -68,11 +68,11 @@ class AgentState:
68
68
 
69
69
  def __init__(self, storage: Storage, context_service_key: str):
70
70
  """
71
- Initializes a new instance of the :class:`AgentState` class.
71
+ Initializes a new instance of the :class:`microsoft_agents.hosting.core.state.agent_state.AgentState` class.
72
72
 
73
73
  :param storage: The storage layer this state management object will use to store and retrieve state
74
74
  :type storage: :class:`microsoft_agents.hosting.core.storage.Storage`
75
- :param context_service_key: The key for the state cache for this :class:`AgentState`
75
+ :param context_service_key: The key for the state cache for this :class:`microsoft_agents.hosting.core.state.agent_state.AgentState`
76
76
  :type context_service_key: str
77
77
 
78
78
  .. remarks::
@@ -93,19 +93,19 @@ class AgentState:
93
93
  from the turn context.
94
94
 
95
95
  :param turn_context: The context object for this turn.
96
- :type turn_context: :class:`TurnContext`
96
+ :type turn_context: :class:`microsoft_agents.hosting.core.turn_context.TurnContext`
97
97
  :return: The cached agent state instance.
98
98
  """
99
99
  return turn_context.turn_state.get(self._context_service_key)
100
100
 
101
101
  def create_property(self, name: str) -> StatePropertyAccessor:
102
102
  """
103
- Creates a property definition and registers it with this :class:`AgentState`.
103
+ Creates a property definition and registers it with this :class:`microsoft_agents.hosting.core.state.agent_state.AgentState`.
104
104
 
105
105
  :param name: The name of the property
106
106
  :type name: str
107
107
  :return: If successful, the state property accessor created
108
- :rtype: :class:`StatePropertyAccessor`
108
+ :rtype: :class:`microsoft_agents.hosting.core.state.state_property_accessor.StatePropertyAccessor`
109
109
  """
110
110
  if not name or not name.strip():
111
111
  raise ValueError(
@@ -123,7 +123,7 @@ class AgentState:
123
123
  Reads the current state object and caches it in the context object for this turn.
124
124
 
125
125
  :param turn_context: The context object for this turn
126
- :type turn_context: :class:`TurnContext`
126
+ :type turn_context: :class:`microsoft_agents.hosting.core.turn_context.TurnContext`
127
127
  :param force: Optional, true to bypass the cache
128
128
  :type force: bool
129
129
  """
@@ -141,7 +141,7 @@ class AgentState:
141
141
  If the state has changed, it saves the state cached in the current context for this turn.
142
142
 
143
143
  :param turn_context: The context object for this turn
144
- :type turn_context: :class:`TurnContext`
144
+ :type turn_context: :class:`microsoft_agents.hosting.core.turn_context.TurnContext`
145
145
  :param force: Optional, true to save state to storage whether or not there are changes
146
146
  :type force: bool
147
147
  """
@@ -157,7 +157,7 @@ class AgentState:
157
157
  Clears any state currently stored in this state scope.
158
158
 
159
159
  :param turn_context: The context object for this turn
160
- :type turn_context: :class:`TurnContext`
160
+ :type turn_context: :class:`microsoft_agents.hosting.core.turn_context.TurnContext`
161
161
 
162
162
  :return: None
163
163
 
@@ -174,7 +174,7 @@ class AgentState:
174
174
  Deletes any state currently stored in this state scope.
175
175
 
176
176
  :param turn_context: The context object for this turn
177
- :type turn_context: :class:`TurnContext`
177
+ :type turn_context: :class:`microsoft_agents.hosting.core.turn_context.TurnContext`
178
178
 
179
179
  :return: None
180
180
  """
@@ -200,7 +200,7 @@ class AgentState:
200
200
  Gets the value of the specified property in the turn context.
201
201
 
202
202
  :param turn_context: The context object for this turn
203
- :type turn_context: :class:`TurnContext`
203
+ :type turn_context: :class:`microsoft_agents.hosting.core.turn_context.TurnContext`
204
204
  :param property_name: The property name
205
205
  :type property_name: str
206
206
 
@@ -235,8 +235,6 @@ class AgentState:
235
235
  """
236
236
  Deletes a property from the state cache in the turn context.
237
237
 
238
- :param turn_context: The context object for this turn
239
- :type turn_context: :class:`TurnContext`
240
238
  :param property_name: The name of the property to delete
241
239
  :type property_name: str
242
240
 
@@ -254,8 +252,6 @@ class AgentState:
254
252
  """
255
253
  Sets a property to the specified value in the turn context.
256
254
 
257
- :param turn_context: The context object for this turn
258
- :type turn_context: :class:`TurnContext`
259
255
  :param property_name: The property name
260
256
  :type property_name: str
261
257
  :param value: The value to assign to the property
@@ -272,15 +268,15 @@ class AgentState:
272
268
 
273
269
  class BotStatePropertyAccessor(StatePropertyAccessor):
274
270
  """
275
- Defines methods for accessing a state property created in a :class:`AgentState` object.
271
+ Defines methods for accessing a state property created in a :class:`microsoft_agents.hosting.core.state.agent_state.AgentState` object.
276
272
  """
277
273
 
278
274
  def __init__(self, agent_state: AgentState, name: str):
279
275
  """
280
- Initializes a new instance of the :class:`BotStatePropertyAccessor` class.
276
+ Initializes a new instance of the :class:`microsoft_agents.hosting.core.state.agent_state.BotStatePropertyAccessor` class.
281
277
 
282
278
  :param agent_state: The state object to access
283
- :type agent_state: :class:`AgentState`
279
+ :type agent_state: :class:`microsoft_agents.hosting.core.state.agent_state.AgentState`
284
280
  :param name: The name of the state property to access
285
281
  :type name: str
286
282
 
@@ -304,7 +300,7 @@ class BotStatePropertyAccessor(StatePropertyAccessor):
304
300
  Deletes the property.
305
301
 
306
302
  :param turn_context: The context object for this turn
307
- :type turn_context: :class:`TurnContext`
303
+ :type turn_context: :class:`microsoft_agents.hosting.core.turn_context.TurnContext`
308
304
  """
309
305
  await self._agent_state.load(turn_context, False)
310
306
  self._agent_state.delete_value(self._name)
@@ -320,7 +316,7 @@ class BotStatePropertyAccessor(StatePropertyAccessor):
320
316
  Gets the property value.
321
317
 
322
318
  :param turn_context: The context object for this turn
323
- :type turn_context: :class:`TurnContext`
319
+ :type turn_context: :class:`microsoft_agents.hosting.core.turn_context.TurnContext`
324
320
  :param default_value_or_factory: Defines the default value for the property
325
321
  """
326
322
  await self._agent_state.load(turn_context, False)
@@ -355,7 +351,7 @@ class BotStatePropertyAccessor(StatePropertyAccessor):
355
351
  Sets the property value.
356
352
 
357
353
  :param turn_context: The context object for this turn
358
- :type turn_context: :class:`TurnContext`
354
+ :type turn_context: :class:`microsoft_agents.hosting.core.turn_context.TurnContext`
359
355
 
360
356
  :param value: The value to assign to the property
361
357
  """
@@ -71,7 +71,7 @@ class FileTranscriptStore(TranscriptLogger):
71
71
  def _write() -> None:
72
72
  # Normalize to a dict to ensure json serializable content.
73
73
  if not activity.timestamp:
74
- activity.timestamp = _utc_iso_now()
74
+ activity.timestamp = datetime.now(timezone.utc)
75
75
 
76
76
  with open(file_path, "a", encoding="utf-8", newline="\n") as f:
77
77
  f.write(activity.model_dump_json(exclude_none=True, exclude_unset=True))
@@ -261,7 +261,3 @@ def _to_plain_dict(activity: Activity) -> Dict[str, Any]:
261
261
  "conversation": {"id": conversation_id},
262
262
  "text": getattr(activity, "text", None),
263
263
  }
264
-
265
-
266
- def _utc_iso_now() -> str:
267
- return datetime.now(timezone.utc).isoformat()
@@ -18,6 +18,7 @@ from microsoft_agents.activity import (
18
18
  ResourceResponse,
19
19
  DeliveryModes,
20
20
  )
21
+ from microsoft_agents.activity.entity.entity_types import EntityTypes
21
22
  from microsoft_agents.hosting.core.authorization.claims_identity import ClaimsIdentity
22
23
 
23
24
 
@@ -428,7 +429,7 @@ class TurnContext(TurnContextProtocol):
428
429
  result: list[Mention] = []
429
430
  if activity.entities is not None:
430
431
  for entity in activity.entities:
431
- if entity.type.lower() == "mention":
432
+ if entity.type.lower() == EntityTypes.MENTION:
432
433
  result.append(entity)
433
434
 
434
435
  return result
@@ -0,0 +1,191 @@
1
+ Metadata-Version: 2.4
2
+ Name: microsoft-agents-hosting-core
3
+ Version: 0.5.0
4
+ Summary: Core library for Microsoft Agents
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.10
10
+ Classifier: Programming Language :: Python :: 3.11
11
+ Classifier: Programming Language :: Python :: 3.12
12
+ Classifier: Programming Language :: Python :: 3.13
13
+ Classifier: Programming Language :: Python :: 3.14
14
+ Classifier: Operating System :: OS Independent
15
+ Requires-Python: >=3.10
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE
18
+ Requires-Dist: microsoft-agents-activity==0.5.0
19
+ Requires-Dist: pyjwt>=2.10.1
20
+ Requires-Dist: isodate>=0.6.1
21
+ Requires-Dist: azure-core>=1.30.0
22
+ Requires-Dist: python-dotenv>=1.1.1
23
+ Dynamic: license-file
24
+ Dynamic: requires-dist
25
+
26
+ # Microsoft Agents Hosting Core
27
+
28
+ [![PyPI version](https://img.shields.io/pypi/v/microsoft-agents-hosting-core)](https://pypi.org/project/microsoft-agents-hosting-core/)
29
+
30
+ The core hosting library for Microsoft 365 Agents SDK. This library provides the fundamental building blocks for creating conversational AI agents, including activity processing, state management, authentication, and channel communication.
31
+
32
+ This is the heart of the Microsoft 365 Agents SDK - think of it as the engine that powers your conversational agents. It handles the complex orchestration of conversations, manages state across turns, and provides the infrastructure needed to build production-ready agents that work across Microsoft 365 platforms.
33
+
34
+ # What is this?
35
+ 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 multiple platforms including Microsoft Teams, M365 Copilot, Copilot Studio, and web chat, with support for third-party integrations like Slack, Facebook Messenger, and Twilio.
36
+
37
+ ## Release Notes
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>0.5.0</td>
46
+ <td>2025-10-22</td>
47
+ <td>
48
+ <a href="https://github.com/microsoft/Agents-for-python/blob/main/changelog.md">
49
+ 0.5.0 Release Notes
50
+ </a>
51
+ </td>
52
+ </tr>
53
+ </table>
54
+
55
+ ## Packages Overview
56
+
57
+ We offer the following PyPI packages to create conversational experiences based on Agents:
58
+
59
+ | Package Name | PyPI Version | Description |
60
+ |--------------|-------------|-------------|
61
+ | `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. |
62
+ | `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. |
63
+ | `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. |
64
+ | `microsoft-agents-hosting-teams` | [![PyPI](https://img.shields.io/pypi/v/microsoft-agents-hosting-teams)](https://pypi.org/project/microsoft-agents-hosting-teams/) | Provides classes to host an Agent for Teams. |
65
+ | `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. |
66
+ | `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. |
67
+ | `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. |
68
+
69
+ Additionally we provide a Copilot Studio Client, to interact with Agents created in CopilotStudio:
70
+
71
+ | Package Name | PyPI Version | Description |
72
+ |--------------|-------------|-------------|
73
+ | `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 |
74
+
75
+
76
+ ## Installation
77
+
78
+ ```bash
79
+ pip install microsoft-agents-hosting-core
80
+ ```
81
+ ## Simple Echo Agent
82
+ See the [Quickstart sample](https://github.com/microsoft/Agents/tree/main/samples/python/quickstart) for full working code.
83
+
84
+ ```python
85
+ agents_sdk_config = load_configuration_from_env(environ)
86
+
87
+ STORAGE = MemoryStorage()
88
+ CONNECTION_MANAGER = MsalConnectionManager(**agents_sdk_config)
89
+ ADAPTER = CloudAdapter(connection_manager=CONNECTION_MANAGER)
90
+ AUTHORIZATION = Authorization(STORAGE, CONNECTION_MANAGER, **agents_sdk_config)
91
+
92
+ AGENT_APP = AgentApplication[TurnState](
93
+ storage=STORAGE, adapter=ADAPTER, authorization=AUTHORIZATION, **agents_sdk_config
94
+ )
95
+
96
+ @AGENT_APP.activity("message")
97
+ async def on_message(context: TurnContext, state: TurnState):
98
+ await context.send_activity(f"You said: {context.activity.text}")
99
+
100
+ ...
101
+
102
+ start_server(
103
+ agent_application=AGENT_APP,
104
+ auth_configuration=CONNECTION_MANAGER.get_default_connection_configuration(),
105
+ )
106
+ ```
107
+
108
+ ## Core Concepts
109
+
110
+ ### AgentApplication vs ActivityHandler
111
+
112
+ **AgentApplication** - Modern, fluent API for building agents:
113
+ - Decorator-based routing (`@agent_app.activity("message")`)
114
+ - Built-in state management and middleware
115
+ - AI-ready with authorization support
116
+ - Type-safe with generics
117
+
118
+ **ActivityHandler** - Traditional inheritance-based approach:
119
+ - Override methods for different activity types
120
+ - More familiar to Bot Framework developers
121
+ - Lower-level control over activity processing
122
+
123
+ ### Route-based Message Handling
124
+
125
+ ```python
126
+ @AGENT_APP.message(re.compile(r"^hello$"))
127
+ async def on_hello(context: TurnContext, _state: TurnState):
128
+ await context.send_activity("Hello!")
129
+
130
+
131
+ @AGENT_APP.activity("message")
132
+ async def on_message(context: TurnContext, _state: TurnState):
133
+ await context.send_activity(f"you said: {context.activity.text}")
134
+ ```
135
+
136
+ ### Error Handling
137
+
138
+ ```python
139
+ @AGENT_APP.error
140
+ async def on_error(context: TurnContext, error: Exception):
141
+ # NOTE: In production environment, you should consider logging this to Azure
142
+ # application insights.
143
+ print(f"\n [on_turn_error] unhandled error: {error}", file=sys.stderr)
144
+ traceback.print_exc()
145
+
146
+ # Send a message to the user
147
+ await context.send_activity("The bot encountered an error or bug.")
148
+ ```
149
+
150
+
151
+ ## Key Classes Reference
152
+
153
+ ### Core Classes
154
+ - **`AgentApplication`** - Main application class with fluent API
155
+ - **`ActivityHandler`** - Base class for inheritance-based agents
156
+ - **`TurnContext`** - Context for each conversation turn
157
+ - **`TurnState`** - State management across conversation turns
158
+
159
+ ### State Management
160
+ - **`ConversationState`** - Conversation-scoped state
161
+ - **`UserState`** - User-scoped state across conversations
162
+ - **`TempState`** - Temporary state for current turn
163
+ - **`MemoryStorage`** - In-memory storage (development)
164
+
165
+ ### Messaging
166
+ - **`MessageFactory`** - Create different types of messages
167
+ - **`CardFactory`** - Create rich card attachments
168
+ - **`InputFile`** - Handle file attachments
169
+
170
+ ### Authorization
171
+ - **`Authorization`** - Authentication and authorization manager
172
+ - **`ClaimsIdentity`** - User identity and claims
173
+
174
+ # Quick Links
175
+
176
+ - 📦 [All SDK Packages on PyPI](https://pypi.org/search/?q=microsoft-agents)
177
+ - 📖 [Complete Documentation](https://aka.ms/agents)
178
+ - 💡 [Python Samples Repository](https://github.com/microsoft/Agents/tree/main/samples/python)
179
+ - 🐛 [Report Issues](https://github.com/microsoft/Agents-for-python/issues)
180
+
181
+ # Sample Applications
182
+
183
+ |Name|Description|README|
184
+ |----|----|----|
185
+ |Quickstart|Simplest agent|[Quickstart](https://github.com/microsoft/Agents/blob/main/samples/python/quickstart/README.md)|
186
+ |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)|
187
+ |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)|
188
+ |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)|
189
+ |Streaming Agent|Streams OpenAI responses|[azure-ai-streaming](https://github.com/microsoft/Agents/blob/main/samples/python/azureai-streaming/README.md)|
190
+ |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)|
191
+ |Cards Agent|Agent that uses rich cards to enhance conversation design |[cards](https://github.com/microsoft/Agents/blob/main/samples/python/cards/README.md)|