microsoft-agents-hosting-core 0.7.0.dev10__py3-none-any.whl → 0.7.0.dev16__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/__init__.py +0 -1
  2. microsoft_agents/hosting/core/app/agent_application.py +12 -24
  3. microsoft_agents/hosting/core/app/oauth/__init__.py +2 -0
  4. microsoft_agents/hosting/core/app/oauth/_handlers/__init__.py +2 -0
  5. microsoft_agents/hosting/core/app/oauth/_handlers/agentic_user_authorization.py +5 -2
  6. microsoft_agents/hosting/core/app/oauth/_handlers/connector_user_authorization.py +240 -0
  7. microsoft_agents/hosting/core/app/oauth/authorization.py +18 -8
  8. microsoft_agents/hosting/core/authorization/access_token_provider_base.py +7 -3
  9. microsoft_agents/hosting/core/authorization/agent_auth_configuration.py +29 -0
  10. microsoft_agents/hosting/core/authorization/anonymous_token_provider.py +7 -3
  11. microsoft_agents/hosting/core/authorization/claims_identity.py +16 -0
  12. microsoft_agents/hosting/core/authorization/jwt_token_validator.py +2 -2
  13. microsoft_agents/hosting/core/channel_service_adapter.py +1 -3
  14. microsoft_agents/hosting/core/connector/__init__.py +4 -0
  15. microsoft_agents/hosting/core/connector/client/connector_client.py +0 -1
  16. microsoft_agents/hosting/core/connector/client/user_token_client.py +0 -1
  17. microsoft_agents/hosting/core/connector/mcs/__init__.py +3 -0
  18. microsoft_agents/hosting/core/connector/mcs/mcs_connector_client.py +249 -0
  19. microsoft_agents/hosting/core/errors/error_resources.py +15 -0
  20. microsoft_agents/hosting/core/http/_http_adapter_base.py +3 -6
  21. microsoft_agents/hosting/core/rest_channel_service_client_factory.py +17 -3
  22. microsoft_agents/hosting/core/storage/memory_storage.py +0 -1
  23. microsoft_agents/hosting/core/storage/storage.py +0 -1
  24. microsoft_agents/hosting/core/storage/transcript_logger.py +0 -1
  25. {microsoft_agents_hosting_core-0.7.0.dev10.dist-info → microsoft_agents_hosting_core-0.7.0.dev16.dist-info}/METADATA +2 -2
  26. {microsoft_agents_hosting_core-0.7.0.dev10.dist-info → microsoft_agents_hosting_core-0.7.0.dev16.dist-info}/RECORD +29 -26
  27. {microsoft_agents_hosting_core-0.7.0.dev10.dist-info → microsoft_agents_hosting_core-0.7.0.dev16.dist-info}/WHEEL +1 -1
  28. {microsoft_agents_hosting_core-0.7.0.dev10.dist-info → microsoft_agents_hosting_core-0.7.0.dev16.dist-info}/licenses/LICENSE +0 -0
  29. {microsoft_agents_hosting_core-0.7.0.dev10.dist-info → microsoft_agents_hosting_core-0.7.0.dev16.dist-info}/top_level.txt +0 -0
@@ -101,7 +101,6 @@ from .storage.memory_storage import MemoryStorage
101
101
  # Error Resources
102
102
  from .errors import error_resources, ErrorMessage, ErrorResources
103
103
 
104
-
105
104
  # Define the package's public interface
106
105
  __all__ = [
107
106
  "ActivityHandler",
@@ -120,11 +120,9 @@ class AgentApplication(Agent, Generic[StateT]):
120
120
  "ApplicationOptions.storage is required and was not configured.",
121
121
  stack_info=True,
122
122
  )
123
- raise ApplicationError(
124
- """
123
+ raise ApplicationError("""
125
124
  The `ApplicationOptions.storage` property is required and was not configured.
126
- """
127
- )
125
+ """)
128
126
 
129
127
  if options.long_running_messages and (
130
128
  not options.adapter or not options.bot_app_id
@@ -133,12 +131,10 @@ class AgentApplication(Agent, Generic[StateT]):
133
131
  "ApplicationOptions.long_running_messages requires an adapter and bot_app_id.",
134
132
  stack_info=True,
135
133
  )
136
- raise ApplicationError(
137
- """
134
+ raise ApplicationError("""
138
135
  The `ApplicationOptions.long_running_messages` property is unavailable because
139
136
  no adapter or `bot_app_id` was configured.
140
- """
141
- )
137
+ """)
142
138
 
143
139
  if options.adapter:
144
140
  self._adapter = options.adapter
@@ -180,12 +176,10 @@ class AgentApplication(Agent, Generic[StateT]):
180
176
  "AgentApplication.adapter(): self._adapter is not configured.",
181
177
  stack_info=True,
182
178
  )
183
- raise ApplicationError(
184
- """
179
+ raise ApplicationError("""
185
180
  The AgentApplication.adapter property is unavailable because it was
186
181
  not configured when creating the AgentApplication.
187
- """
188
- )
182
+ """)
189
183
 
190
184
  return self._adapter
191
185
 
@@ -203,12 +197,10 @@ class AgentApplication(Agent, Generic[StateT]):
203
197
  "AgentApplication.auth(): self._auth is not configured.",
204
198
  stack_info=True,
205
199
  )
206
- raise ApplicationError(
207
- """
200
+ raise ApplicationError("""
208
201
  The `AgentApplication.auth` property is unavailable because
209
202
  no Auth options were configured.
210
- """
211
- )
203
+ """)
212
204
 
213
205
  return self._auth
214
206
 
@@ -592,12 +584,10 @@ class AgentApplication(Agent, Generic[StateT]):
592
584
  f"Failed to register sign-in success handler for route handler {func.__name__}",
593
585
  stack_info=True,
594
586
  )
595
- raise ApplicationError(
596
- """
587
+ raise ApplicationError("""
597
588
  The `AgentApplication.on_sign_in_success` method is unavailable because
598
589
  no Auth options were configured.
599
- """
600
- )
590
+ """)
601
591
  return func
602
592
 
603
593
  def on_sign_in_failure(
@@ -628,12 +618,10 @@ class AgentApplication(Agent, Generic[StateT]):
628
618
  f"Failed to register sign-in failure handler for route handler {func.__name__}",
629
619
  stack_info=True,
630
620
  )
631
- raise ApplicationError(
632
- """
621
+ raise ApplicationError("""
633
622
  The `AgentApplication.on_sign_in_failure` method is unavailable because
634
623
  no Auth options were configured.
635
- """
636
- )
624
+ """)
637
625
  return func
638
626
 
639
627
  def error(
@@ -9,6 +9,7 @@ from ._sign_in_response import _SignInResponse
9
9
  from ._handlers import (
10
10
  _UserAuthorization,
11
11
  AgenticUserAuthorization,
12
+ ConnectorUserAuthorization,
12
13
  _AuthorizationHandler,
13
14
  )
14
15
 
@@ -20,4 +21,5 @@ __all__ = [
20
21
  "_SignInResponse",
21
22
  "_UserAuthorization",
22
23
  "AgenticUserAuthorization",
24
+ "ConnectorUserAuthorization",
23
25
  ]
@@ -4,11 +4,13 @@ Licensed under the MIT License.
4
4
  """
5
5
 
6
6
  from .agentic_user_authorization import AgenticUserAuthorization
7
+ from .connector_user_authorization import ConnectorUserAuthorization
7
8
  from ._user_authorization import _UserAuthorization
8
9
  from ._authorization_handler import _AuthorizationHandler
9
10
 
10
11
  __all__ = [
11
12
  "AgenticUserAuthorization",
13
+ "ConnectorUserAuthorization",
12
14
  "_UserAuthorization",
13
15
  "_AuthorizationHandler",
14
16
  ]
@@ -75,7 +75,7 @@ class AgenticUserAuthorization(_AuthorizationHandler):
75
75
  agentic_instance_id = context.activity.get_agentic_instance_id()
76
76
  assert agentic_instance_id
77
77
  instance_token, _ = await connection.get_agentic_instance_token(
78
- agentic_instance_id
78
+ context.activity.get_agentic_tenant_id(), agentic_instance_id
79
79
  )
80
80
  return (
81
81
  TokenResponse(token=instance_token) if instance_token else TokenResponse()
@@ -131,7 +131,10 @@ class AgenticUserAuthorization(_AuthorizationHandler):
131
131
  )
132
132
 
133
133
  token = await connection.get_agentic_user_token(
134
- agentic_instance_id, agentic_user_id, scopes
134
+ context.activity.get_agentic_tenant_id(),
135
+ agentic_instance_id,
136
+ agentic_user_id,
137
+ scopes,
135
138
  )
136
139
  return TokenResponse(token=token) if token else TokenResponse()
137
140
 
@@ -0,0 +1,240 @@
1
+ """
2
+ Copyright (c) Microsoft Corporation. All rights reserved.
3
+ Licensed under the MIT License.
4
+ """
5
+
6
+ import logging
7
+ import jwt
8
+ from datetime import datetime, timezone
9
+ from typing import Optional
10
+
11
+ from microsoft_agents.activity import TokenResponse
12
+ from microsoft_agents.hosting.core.errors import ErrorResources
13
+
14
+ from ...._oauth._flow_state import _FlowStateTag
15
+ from ....turn_context import TurnContext
16
+ from ....storage import Storage
17
+ from ....authorization import Connections
18
+ from ..auth_handler import AuthHandler
19
+ from ._authorization_handler import _AuthorizationHandler
20
+ from .._sign_in_response import _SignInResponse
21
+
22
+ logger = logging.getLogger(__name__)
23
+
24
+
25
+ class ConnectorUserAuthorization(_AuthorizationHandler):
26
+ """
27
+ User Authorization handling for Copilot Studio Connector requests.
28
+ Extracts token from the identity and performs OBO token exchange.
29
+ """
30
+
31
+ def __init__(
32
+ self,
33
+ storage: Storage,
34
+ connection_manager: Connections,
35
+ auth_handler: Optional[AuthHandler] = None,
36
+ *,
37
+ auth_handler_id: Optional[str] = None,
38
+ auth_handler_settings: Optional[dict] = None,
39
+ **kwargs,
40
+ ) -> None:
41
+ """
42
+ Creates a new instance of ConnectorUserAuthorization.
43
+
44
+ :param storage: The storage system to use for state management.
45
+ :type storage: Storage
46
+ :param connection_manager: The connection manager for OAuth providers.
47
+ :type connection_manager: Connections
48
+ :param auth_handler: Configuration for OAuth provider.
49
+ :type auth_handler: AuthHandler, Optional
50
+ :param auth_handler_id: Optional ID of the auth handler.
51
+ :type auth_handler_id: str, Optional
52
+ :param auth_handler_settings: Optional settings dict for the auth handler.
53
+ :type auth_handler_settings: dict, Optional
54
+ """
55
+ super().__init__(
56
+ storage,
57
+ connection_manager,
58
+ auth_handler,
59
+ auth_handler_id=auth_handler_id,
60
+ auth_handler_settings=auth_handler_settings,
61
+ **kwargs,
62
+ )
63
+
64
+ async def _sign_in(
65
+ self,
66
+ context: TurnContext,
67
+ exchange_connection: Optional[str] = None,
68
+ exchange_scopes: Optional[list[str]] = None,
69
+ ) -> _SignInResponse:
70
+ """
71
+ For connector requests, there is no separate sign-in flow.
72
+ The token is extracted from the identity.
73
+
74
+ :param context: The turn context for the current turn of conversation.
75
+ :type context: TurnContext
76
+ :param exchange_connection: Optional connection name for token exchange.
77
+ :type exchange_connection: Optional[str]
78
+ :param exchange_scopes: Optional list of scopes (unused for connector auth).
79
+ :type exchange_scopes: Optional[list[str]]
80
+ :return: A SignInResponse with the extracted token.
81
+ :rtype: _SignInResponse
82
+ """
83
+ # Connector auth uses the token from the request, not a separate sign-in flow
84
+ token_response = await self.get_refreshed_token(context)
85
+ return _SignInResponse(
86
+ token_response=token_response, tag=_FlowStateTag.COMPLETE
87
+ )
88
+
89
+ async def get_refreshed_token(
90
+ self,
91
+ context: TurnContext,
92
+ exchange_connection: Optional[str] = None,
93
+ exchange_scopes: Optional[list[str]] = None,
94
+ ) -> TokenResponse:
95
+ """
96
+ Gets the connector user token and optionally exchanges it via OBO.
97
+
98
+ :param context: The turn context for the current turn of conversation.
99
+ :type context: TurnContext
100
+ :param exchange_connection: Optional name of the connection to use for token exchange.
101
+ :type exchange_connection: Optional[str], Optional
102
+ :param exchange_scopes: Optional list of scopes to request during token exchange.
103
+ :type exchange_scopes: Optional[list[str]], Optional
104
+ :return: The token response, potentially after OBO exchange.
105
+ :rtype: TokenResponse
106
+ """
107
+ token_response = self._create_token_response(context)
108
+
109
+ # Check if token is expired
110
+ if token_response.expiration:
111
+ try:
112
+ # Parse ISO 8601 format
113
+ expiration = datetime.fromisoformat(
114
+ token_response.expiration.replace("Z", "+00:00")
115
+ )
116
+ if expiration <= datetime.now(timezone.utc):
117
+ raise ValueError(
118
+ f"Unexpected connector token expiration for handler: {self._id}"
119
+ )
120
+ except (ValueError, AttributeError) as ex:
121
+ logger.error(
122
+ f"Error checking token expiration for handler {self._id}: {ex}"
123
+ )
124
+ raise
125
+
126
+ # Perform OBO exchange if configured
127
+ try:
128
+ return await self._handle_obo(
129
+ context, token_response, exchange_connection, exchange_scopes
130
+ )
131
+ except Exception:
132
+ await self._sign_out(context)
133
+ raise
134
+
135
+ async def _sign_out(self, context: TurnContext) -> None:
136
+ """
137
+ Sign-out is a no-op for connector authorization.
138
+
139
+ :param context: The turn context for the current turn of conversation.
140
+ :type context: TurnContext
141
+ """
142
+ # No concept of sign-out with ConnectorAuth
143
+ logger.debug("Sign-out called for ConnectorUserAuthorization (no-op)")
144
+
145
+ async def _handle_obo(
146
+ self,
147
+ context: TurnContext,
148
+ input_token_response: TokenResponse,
149
+ exchange_connection: Optional[str] = None,
150
+ exchange_scopes: Optional[list[str]] = None,
151
+ ) -> TokenResponse:
152
+ """
153
+ Exchanges a token for another token with different scopes via OBO flow.
154
+
155
+ :param context: The context object for the current turn.
156
+ :type context: TurnContext
157
+ :param input_token_response: The input token to exchange.
158
+ :type input_token_response: TokenResponse
159
+ :param exchange_connection: Optional connection name for exchange.
160
+ :type exchange_connection: Optional[str]
161
+ :param exchange_scopes: Optional scopes for the exchanged token.
162
+ :type exchange_scopes: Optional[list[str]]
163
+ :return: The token response after exchange, or the original if exchange not configured.
164
+ :rtype: TokenResponse
165
+ """
166
+ if not input_token_response:
167
+ return input_token_response
168
+
169
+ connection_name = exchange_connection or self._handler.obo_connection_name
170
+ scopes = exchange_scopes or self._handler.scopes
171
+
172
+ # If OBO is not configured, return token as-is
173
+ if not connection_name or not scopes:
174
+ return input_token_response
175
+
176
+ # Check if token is exchangeable
177
+ if not input_token_response.is_exchangeable():
178
+ raise ValueError(
179
+ str(ErrorResources.OboNotExchangeableToken.format(self._id))
180
+ )
181
+
182
+ # Get the connection that supports OBO
183
+ token_provider = self._connection_manager.get_connection(connection_name)
184
+ if not token_provider:
185
+ raise ValueError(
186
+ str(
187
+ ErrorResources.ResourceNotFound.format(
188
+ f"Connection '{connection_name}'"
189
+ )
190
+ )
191
+ )
192
+
193
+ # Perform the OBO exchange
194
+ # Note: In Python, the acquire_token_on_behalf_of method is on the AccessTokenProviderBase
195
+ token = await token_provider.acquire_token_on_behalf_of(
196
+ scopes=scopes,
197
+ user_assertion=input_token_response.token,
198
+ )
199
+ return TokenResponse(token=token) if token else None
200
+
201
+ def _create_token_response(self, context: TurnContext) -> TokenResponse:
202
+ """
203
+ Creates a TokenResponse from the security token in the turn context identity.
204
+
205
+ :param context: The turn context for the current turn of conversation.
206
+ :type context: TurnContext
207
+ :return: A TokenResponse containing the extracted token.
208
+ :rtype: TokenResponse
209
+ :raises ValueError: If the identity doesn't have a security token.
210
+ """
211
+ if not context.identity or not hasattr(context.identity, "security_token"):
212
+ raise ValueError(
213
+ f"Unexpected connector request - no security token found for handler: {self._id}"
214
+ )
215
+
216
+ security_token = context.identity.security_token
217
+ if not security_token:
218
+ raise ValueError(
219
+ f"Unexpected connector request - security token is None for handler: {self._id}"
220
+ )
221
+
222
+ token_response = TokenResponse(token=security_token)
223
+
224
+ # Try to extract expiration and check if exchangeable
225
+ try:
226
+ # TODO: (connector) validate this decoding
227
+ jwt_token = jwt.decode(security_token, options={"verify_signature": False})
228
+
229
+ # Set expiration if present
230
+ if "exp" in jwt_token:
231
+ # JWT exp is in Unix timestamp (seconds since epoch)
232
+ expiration = datetime.fromtimestamp(jwt_token["exp"], tz=timezone.utc)
233
+ # Convert to ISO 8601 format
234
+ token_response.expiration = expiration.isoformat()
235
+
236
+ except Exception as ex:
237
+ logger.warning(f"Failed to parse JWT token for handler {self._id}: {ex}")
238
+ raise ex
239
+
240
+ return token_response
@@ -20,6 +20,7 @@ from ._sign_in_state import _SignInState
20
20
  from ._sign_in_response import _SignInResponse
21
21
  from ._handlers import (
22
22
  AgenticUserAuthorization,
23
+ ConnectorUserAuthorization,
23
24
  _UserAuthorization,
24
25
  _AuthorizationHandler,
25
26
  )
@@ -29,6 +30,7 @@ logger = logging.getLogger(__name__)
29
30
  AUTHORIZATION_TYPE_MAP = {
30
31
  "userauthorization": _UserAuthorization,
31
32
  "agenticuserauthorization": AgenticUserAuthorization,
33
+ "connectoruserauthorization": ConnectorUserAuthorization,
32
34
  }
33
35
 
34
36
 
@@ -44,7 +46,7 @@ class Authorization:
44
46
  storage: Storage,
45
47
  connection_manager: Connections,
46
48
  auth_handlers: Optional[dict[str, AuthHandler]] = None,
47
- auto_signin: bool = False,
49
+ auto_sign_in: bool = False,
48
50
  use_cache: bool = False,
49
51
  **kwargs,
50
52
  ):
@@ -77,21 +79,26 @@ class Authorization:
77
79
 
78
80
  self._handlers = {}
79
81
 
82
+ auth_configuration: dict = kwargs.get("AGENTAPPLICATION", {}).get(
83
+ "USERAUTHORIZATION", {}
84
+ )
80
85
  if not auth_handlers:
81
86
  # get from config
82
- auth_configuration: dict = kwargs.get("AGENTAPPLICATION", {}).get(
83
- "USERAUTHORIZATION", {}
84
- )
85
87
  handlers_config: dict[str, dict] = auth_configuration.get("HANDLERS")
86
88
  if not auth_handlers and handlers_config:
87
89
  auth_handlers = {
88
90
  handler_name: AuthHandler(
89
- name=handler_name, **config.get("SETTINGS", {})
91
+ name=handler_name,
92
+ auth_type=config.get("TYPE", None),
93
+ **config.get("SETTINGS", {}),
90
94
  )
91
95
  for handler_name, config in handlers_config.items()
92
96
  }
93
97
 
94
98
  self._handler_settings = auth_handlers
99
+ self._auto_sign_in = auto_sign_in or bool(
100
+ auth_configuration.get("AUTO_SIGN_IN", False)
101
+ )
95
102
 
96
103
  # operations default to the first handler if none specified
97
104
  if self._handler_settings:
@@ -296,13 +303,16 @@ class Authorization:
296
303
  """
297
304
  sign_in_state = await self._load_sign_in_state(context)
298
305
 
299
- if sign_in_state:
300
- auth_handler_id = sign_in_state.active_handler_id
301
- if auth_handler_id:
306
+ if sign_in_state or self._auto_sign_in:
307
+ auth_handler_id = sign_in_state.active_handler_id if sign_in_state else None
308
+ if auth_handler_id or self._auto_sign_in:
302
309
  sign_in_response = await self._start_or_continue_sign_in(
303
310
  context, state, auth_handler_id
304
311
  )
305
312
  if sign_in_response.tag == _FlowStateTag.COMPLETE:
313
+ if not sign_in_state:
314
+ # flow just completed, no continuation activity
315
+ return False, None
306
316
  assert sign_in_state.continuation_activity is not None
307
317
  continuation_activity = (
308
318
  sign_in_state.continuation_activity.model_copy()
@@ -33,16 +33,20 @@ class AccessTokenProviderBase(Protocol):
33
33
  raise NotImplementedError()
34
34
 
35
35
  async def get_agentic_application_token(
36
- self, agent_app_instance_id: str
36
+ self, tenant_id: str, agent_app_instance_id: str
37
37
  ) -> Optional[str]:
38
38
  raise NotImplementedError()
39
39
 
40
40
  async def get_agentic_instance_token(
41
- self, agent_app_instance_id: str
41
+ self, tenant_id: str, agent_app_instance_id: str
42
42
  ) -> tuple[str, str]:
43
43
  raise NotImplementedError()
44
44
 
45
45
  async def get_agentic_user_token(
46
- self, agent_app_instance_id: str, agentic_user_id: str, scopes: list[str]
46
+ self,
47
+ tenant_id: str,
48
+ agent_app_instance_id: str,
49
+ agentic_user_id: str,
50
+ scopes: list[str],
47
51
  ) -> Optional[str]:
48
52
  raise NotImplementedError()
@@ -1,6 +1,7 @@
1
1
  # Copyright (c) Microsoft Corporation. All rights reserved.
2
2
  # Licensed under the MIT License.
3
3
 
4
+ from __future__ import annotations
4
5
  from typing import Optional
5
6
 
6
7
  from microsoft_agents.hosting.core.authorization.auth_types import AuthTypes
@@ -32,6 +33,16 @@ class AgentAuthConfiguration:
32
33
  SCOPES: Optional[list[str]]
33
34
  AUTHORITY: Optional[str]
34
35
  ALT_BLUEPRINT_ID: Optional[str]
36
+ ANONYMOUS_ALLOWED: bool = False
37
+
38
+ # Multi-connection support: Maintains a map of all configured connections
39
+ # to enable JWT validation across connections. This allows tokens issued
40
+ # for any configured connection to be validated, supporting multi-tenant
41
+ # scenarios where connections share a security boundary.
42
+ #
43
+ # Note: This is an internal implementation detail. External code should
44
+ # not directly access _connections.
45
+ _connections: dict[str, AgentAuthConfiguration]
35
46
 
36
47
  def __init__(
37
48
  self,
@@ -44,6 +55,7 @@ class AgentAuthConfiguration:
44
55
  connection_name: Optional[str] = None,
45
56
  authority: Optional[str] = None,
46
57
  scopes: Optional[list[str]] = None,
58
+ anonymous_allowed: bool = False,
47
59
  **kwargs: Optional[dict[str, str]],
48
60
  ):
49
61
 
@@ -57,6 +69,12 @@ class AgentAuthConfiguration:
57
69
  self.CONNECTION_NAME = connection_name or kwargs.get("CONNECTIONNAME", None)
58
70
  self.SCOPES = scopes or kwargs.get("SCOPES", None)
59
71
  self.ALT_BLUEPRINT_ID = kwargs.get("ALT_BLUEPRINT_NAME", None)
72
+ self.ANONYMOUS_ALLOWED = anonymous_allowed or kwargs.get(
73
+ "ANONYMOUS_ALLOWED", False
74
+ )
75
+
76
+ # JWT-patch: always at least include self for backward compat
77
+ self._connections = {str(self.CONNECTION_NAME): self}
60
78
 
61
79
  @property
62
80
  def ISSUERS(self) -> list[str]:
@@ -68,3 +86,14 @@ class AgentAuthConfiguration:
68
86
  f"https://sts.windows.net/{self.TENANT_ID}/",
69
87
  f"https://login.microsoftonline.com/{self.TENANT_ID}/v2.0",
70
88
  ]
89
+
90
+ def _jwt_patch_is_valid_aud(self, aud: str) -> bool:
91
+ """
92
+ JWT-patch: Checks if the given audience is valid for any of the connections.
93
+ """
94
+ for conn in self._connections.values():
95
+ if not conn.CLIENT_ID:
96
+ continue
97
+ if aud.lower() == conn.CLIENT_ID.lower():
98
+ return True
99
+ return False
@@ -23,16 +23,20 @@ class AnonymousTokenProvider(AccessTokenProviderBase):
23
23
  return ""
24
24
 
25
25
  async def get_agentic_application_token(
26
- self, agent_app_instance_id: str
26
+ self, tenant_id: str, agent_app_instance_id: str
27
27
  ) -> Optional[str]:
28
28
  return ""
29
29
 
30
30
  async def get_agentic_instance_token(
31
- self, agent_app_instance_id: str
31
+ self, tenant_id: str, agent_app_instance_id: str
32
32
  ) -> tuple[str, str]:
33
33
  return "", ""
34
34
 
35
35
  async def get_agentic_user_token(
36
- self, agent_app_instance_id: str, agentic_user_id: str, scopes: list[str]
36
+ self,
37
+ tenant_id: str,
38
+ agent_app_instance_id: str,
39
+ agentic_user_id: str,
40
+ scopes: list[str],
37
41
  ) -> Optional[str]:
38
42
  return ""
@@ -11,10 +11,12 @@ class ClaimsIdentity:
11
11
  claims: dict[str, str],
12
12
  is_authenticated: bool,
13
13
  authentication_type: Optional[str] = None,
14
+ security_token: Optional[str] = None,
14
15
  ):
15
16
  self.claims = claims
16
17
  self.is_authenticated = is_authenticated
17
18
  self.authentication_type = authentication_type
19
+ self.security_token = security_token
18
20
 
19
21
  def get_claim_value(self, claim_type: str) -> Optional[str]:
20
22
  return self.claims.get(claim_type)
@@ -83,3 +85,17 @@ class ClaimsIdentity:
83
85
  if self.is_agent_claim()
84
86
  else AuthenticationConstants.AGENTS_SDK_SCOPE
85
87
  )
88
+
89
+ def get_token_scope(self) -> list[str]:
90
+ """
91
+ Gets the token scope from current claims.
92
+
93
+ :return: The token scope.
94
+ """
95
+ return [
96
+ (
97
+ f"{self.get_outgoing_app_id()}/.default"
98
+ if self.is_agent_claim()
99
+ else AuthenticationConstants.AGENTS_SDK_SCOPE + "/.default"
100
+ )
101
+ ]
@@ -28,13 +28,13 @@ class JwtTokenValidator:
28
28
  leeway=300.0,
29
29
  options={"verify_aud": False},
30
30
  )
31
- if decoded_token["aud"] != self.configuration.CLIENT_ID:
31
+ if not self.configuration._jwt_patch_is_valid_aud(decoded_token["aud"]):
32
32
  logger.error(f"Invalid audience: {decoded_token['aud']}", stack_info=True)
33
33
  raise ValueError("Invalid audience.")
34
34
 
35
35
  # This probably should return a ClaimsIdentity
36
36
  logger.debug("JWT token validated successfully.")
37
- return ClaimsIdentity(decoded_token, True)
37
+ return ClaimsIdentity(decoded_token, True, security_token=token)
38
38
 
39
39
  def get_anonymous_claims(self) -> ClaimsIdentity:
40
40
  logger.debug("Returning anonymous claims identity.")
@@ -381,16 +381,14 @@ class ChannelServiceAdapter(ChannelAdapter, ABC):
381
381
  If the task completes successfully, then an :class:`microsoft_agents.activity.InvokeResponse` is returned;
382
382
  otherwise, `None` is returned.
383
383
  """
384
- scopes: list[str] = None
384
+ scopes: list[str] = claims_identity.get_token_scope()
385
385
  outgoing_audience: str = None
386
386
 
387
387
  if claims_identity.is_agent_claim():
388
388
  outgoing_audience = claims_identity.get_token_audience()
389
- scopes = [f"{claims_identity.get_outgoing_app_id()}/.default"]
390
389
  activity.caller_id = f"{CallerIdConstants.agent_to_agent_prefix}{claims_identity.get_outgoing_app_id()}"
391
390
  else:
392
391
  outgoing_audience = AuthenticationConstants.AGENTS_SDK_SCOPE
393
- scopes = [f"{AuthenticationConstants.AGENTS_SDK_SCOPE}/.default"]
394
392
 
395
393
  use_anonymous_auth_callback = False
396
394
  if (
@@ -9,11 +9,15 @@ from .client.user_token_client import UserTokenClient
9
9
  # Teams API
10
10
  from .teams.teams_connector_client import TeamsConnectorClient
11
11
 
12
+ # MCS API
13
+ from .mcs.mcs_connector_client import MCSConnectorClient
14
+
12
15
  __all__ = [
13
16
  "ConnectorClient",
14
17
  "UserTokenClient",
15
18
  "UserTokenClientBase",
16
19
  "TeamsConnectorClient",
20
+ "MCSConnectorClient",
17
21
  "ConnectorClientBase",
18
22
  "get_product_info",
19
23
  ]
@@ -22,7 +22,6 @@ from ..attachments_base import AttachmentsBase
22
22
  from ..conversations_base import ConversationsBase
23
23
  from ..get_product_info import get_product_info
24
24
 
25
-
26
25
  logger = logging.getLogger(__name__)
27
26
 
28
27
 
@@ -18,7 +18,6 @@ from ..get_product_info import get_product_info
18
18
  from ..user_token_base import UserTokenBase
19
19
  from ..agent_sign_in_base import AgentSignInBase
20
20
 
21
-
22
21
  logger = logging.getLogger(__name__)
23
22
 
24
23
 
@@ -0,0 +1,3 @@
1
+ from .mcs_connector_client import MCSConnectorClient
2
+
3
+ __all__ = ["MCSConnectorClient"]
@@ -0,0 +1,249 @@
1
+ # Copyright (c) Microsoft Corporation. All rights reserved.
2
+ # Licensed under the MIT License.
3
+
4
+ """MCS Connector Client for Microsoft Copilot Studio via Power Apps Connector."""
5
+
6
+ import logging
7
+ from typing import Optional
8
+ from aiohttp import ClientSession
9
+
10
+ from microsoft_agents.activity import Activity, ResourceResponse
11
+ from ..connector_client_base import ConnectorClientBase
12
+ from ..attachments_base import AttachmentsBase
13
+ from ..conversations_base import ConversationsBase
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ class MCSConversations(ConversationsBase):
19
+ """
20
+ Conversations implementation for Microsoft Copilot Studio Connector.
21
+
22
+ Only supports SendToConversation and ReplyToActivity operations.
23
+ """
24
+
25
+ def __init__(self, client: ClientSession, endpoint: str):
26
+ self._client = client
27
+ self._endpoint = endpoint
28
+
29
+ async def send_to_conversation(
30
+ self,
31
+ conversation_id: str,
32
+ activity: Activity,
33
+ **kwargs,
34
+ ) -> ResourceResponse:
35
+ """
36
+ Send an activity to a conversation.
37
+
38
+ :param conversation_id: The conversation ID (not used for MCS connector).
39
+ :param activity: The activity to send.
40
+ :return: A resource response.
41
+ """
42
+ if activity is None:
43
+ raise ValueError("activity is required")
44
+
45
+ logger.info(
46
+ "MCS Connector: Sending activity to conversation: %s. Activity type is %s",
47
+ conversation_id,
48
+ activity.type,
49
+ )
50
+
51
+ async with self._client.post(
52
+ self._endpoint,
53
+ json=activity.model_dump(by_alias=True, exclude_unset=True, mode="json"),
54
+ headers={"Accept": "application/json", "Content-Type": "application/json"},
55
+ ) as response:
56
+ if response.status >= 300:
57
+ logger.error(
58
+ "MCS Connector: Error sending activity: %s",
59
+ response.status,
60
+ stack_info=True,
61
+ )
62
+ response.raise_for_status()
63
+
64
+ data = await response.json()
65
+ return ResourceResponse.model_validate(data)
66
+
67
+ async def reply_to_activity(
68
+ self,
69
+ conversation_id: str,
70
+ activity_id: str,
71
+ activity: Activity,
72
+ **kwargs,
73
+ ) -> ResourceResponse:
74
+ """
75
+ Reply to an activity in a conversation.
76
+
77
+ For MCS Connector, this falls back to send_to_conversation.
78
+
79
+ :param conversation_id: The conversation ID.
80
+ :param activity_id: The activity ID to reply to.
81
+ :param activity: The activity to send.
82
+ :return: A resource response.
83
+ """
84
+ return await self.send_to_conversation(conversation_id, activity, **kwargs)
85
+
86
+ async def update_activity(
87
+ self,
88
+ conversation_id: str,
89
+ activity_id: str,
90
+ activity: Activity,
91
+ **kwargs,
92
+ ) -> ResourceResponse:
93
+ """Not supported for MCS Connector."""
94
+ raise NotImplementedError(
95
+ "UpdateActivity is not supported for Microsoft Copilot Studio Connector"
96
+ )
97
+
98
+ async def delete_activity(
99
+ self, conversation_id: str, activity_id: str, **kwargs
100
+ ) -> None:
101
+ """Not supported for MCS Connector."""
102
+ raise NotImplementedError(
103
+ "DeleteActivity is not supported for Microsoft Copilot Studio Connector"
104
+ )
105
+
106
+ async def get_conversation_member(
107
+ self, conversation_id: str, member_id: str, **kwargs
108
+ ) -> list:
109
+ """Not supported for MCS Connector."""
110
+ raise NotImplementedError(
111
+ "GetConversationMember is not supported for Microsoft Copilot Studio Connector"
112
+ )
113
+
114
+ async def get_conversation_members(self, conversation_id: str, **kwargs) -> list:
115
+ """Not supported for MCS Connector."""
116
+ raise NotImplementedError(
117
+ "GetConversationMembers is not supported for Microsoft Copilot Studio Connector"
118
+ )
119
+
120
+ async def get_activity_members(
121
+ self, conversation_id: str, activity_id: str, **kwargs
122
+ ) -> list:
123
+ """Not supported for MCS Connector."""
124
+ raise NotImplementedError(
125
+ "GetActivityMembers is not supported for Microsoft Copilot Studio Connector"
126
+ )
127
+
128
+ async def delete_conversation_member(
129
+ self, conversation_id: str, member_id: str, **kwargs
130
+ ) -> None:
131
+ """Not supported for MCS Connector."""
132
+ raise NotImplementedError(
133
+ "DeleteConversationMember is not supported for Microsoft Copilot Studio Connector"
134
+ )
135
+
136
+ async def send_conversation_history(
137
+ self, conversation_id: str, transcript: dict, **kwargs
138
+ ) -> ResourceResponse:
139
+ """Not supported for MCS Connector."""
140
+ raise NotImplementedError(
141
+ "SendConversationHistory is not supported for Microsoft Copilot Studio Connector"
142
+ )
143
+
144
+ async def upload_attachment(
145
+ self, conversation_id: str, attachment_upload: dict, **kwargs
146
+ ) -> ResourceResponse:
147
+ """Not supported for MCS Connector."""
148
+ raise NotImplementedError(
149
+ "UploadAttachment is not supported for Microsoft Copilot Studio Connector"
150
+ )
151
+
152
+ async def create_conversation(self, parameters: dict, **kwargs) -> dict:
153
+ """Not supported for MCS Connector."""
154
+ raise NotImplementedError(
155
+ "CreateConversation is not supported for Microsoft Copilot Studio Connector"
156
+ )
157
+
158
+ async def get_conversations(
159
+ self, continuation_token: Optional[str] = None, **kwargs
160
+ ) -> dict:
161
+ """Not supported for MCS Connector."""
162
+ raise NotImplementedError(
163
+ "GetConversations is not supported for Microsoft Copilot Studio Connector"
164
+ )
165
+
166
+ async def get_conversation_paged_members(
167
+ self,
168
+ conversation_id: str,
169
+ page_size: Optional[int] = None,
170
+ continuation_token: Optional[str] = None,
171
+ **kwargs,
172
+ ) -> dict:
173
+ """Not supported for MCS Connector."""
174
+ raise NotImplementedError(
175
+ "GetConversationPagedMembers is not supported for Microsoft Copilot Studio Connector"
176
+ )
177
+
178
+
179
+ class MCSAttachments(AttachmentsBase):
180
+ """
181
+ Attachments implementation for Microsoft Copilot Studio Connector.
182
+
183
+ Attachments operations are not supported.
184
+ """
185
+
186
+ async def get_attachment_info(self, attachment_id: str, **kwargs) -> dict:
187
+ """Not supported for MCS Connector."""
188
+ raise NotImplementedError(
189
+ "GetAttachmentInfo is not supported for Microsoft Copilot Studio Connector"
190
+ )
191
+
192
+ async def get_attachment(self, attachment_id: str, *args, **kwargs) -> bytes:
193
+ """Not supported for MCS Connector."""
194
+ raise NotImplementedError(
195
+ "GetAttachment is not supported for Microsoft Copilot Studio Connector"
196
+ )
197
+
198
+
199
+ class MCSConnectorClient(ConnectorClientBase):
200
+ """
201
+ Connector client suited for communicating with Microsoft Copilot Studio
202
+ via a Power Apps Connector request.
203
+
204
+ Only supports SendToConversation and ReplyToActivity operations.
205
+ All other operations will raise NotImplementedError.
206
+ """
207
+
208
+ def __init__(self, endpoint: str, client: Optional[ClientSession] = None):
209
+ """
210
+ Initialize the MCS Connector Client.
211
+
212
+ :param endpoint: The endpoint URL for the MCS connector.
213
+ :param client: Optional aiohttp ClientSession. If not provided, one will be created.
214
+ """
215
+ if not endpoint:
216
+ raise ValueError("endpoint is required")
217
+
218
+ self._endpoint = endpoint
219
+ self._client = client or ClientSession()
220
+ self._conversations = MCSConversations(self._client, self._endpoint)
221
+ self._attachments = MCSAttachments()
222
+
223
+ @property
224
+ def base_uri(self) -> str:
225
+ """Get the base URI for this connector client."""
226
+ return self._endpoint
227
+
228
+ @property
229
+ def attachments(self) -> AttachmentsBase:
230
+ """Get the attachments operations (not supported for MCS)."""
231
+ return self._attachments
232
+
233
+ @property
234
+ def conversations(self) -> ConversationsBase:
235
+ """Get the conversations operations."""
236
+ return self._conversations
237
+
238
+ async def close(self):
239
+ """Close the client session."""
240
+ if self._client:
241
+ await self._client.close()
242
+
243
+ async def __aenter__(self):
244
+ """Async context manager entry."""
245
+ return self
246
+
247
+ async def __aexit__(self, exc_type, exc_val, exc_tb):
248
+ """Async context manager exit."""
249
+ await self.close()
@@ -112,6 +112,21 @@ class ErrorResources:
112
112
  -63017,
113
113
  )
114
114
 
115
+ UnexpectedConnectorRequestToken = ErrorMessage(
116
+ "Connector request did not contain a valid security token for handler: {0}",
117
+ -63018,
118
+ )
119
+
120
+ UnexpectedConnectorTokenExpiration = ErrorMessage(
121
+ "Connector token has expired for handler: {0}",
122
+ -63019,
123
+ )
124
+
125
+ OboNotExchangeableToken = ErrorMessage(
126
+ "The provided token is not exchangeable for handler: {0}",
127
+ -63020,
128
+ )
129
+
115
130
  # General/Validation Errors (-66000 to -66999)
116
131
  InvalidConfiguration = ErrorMessage(
117
132
  "Invalid configuration: {0}",
@@ -87,15 +87,12 @@ class HttpAdapterBase(ChannelServiceAdapter, ABC):
87
87
  if request.method != "POST":
88
88
  return HttpResponseFactory.method_not_allowed()
89
89
 
90
- # Deserialize the incoming Activity
91
- content_type = request.headers.get("Content-Type", "")
92
- if "application/json" not in content_type:
93
- return HttpResponseFactory.unsupported_media_type()
94
-
95
90
  try:
96
91
  body = await request.json()
97
92
  except Exception:
98
- return HttpResponseFactory.bad_request("Invalid JSON")
93
+ return HttpResponseFactory.bad_request(
94
+ "Invalid JSON or unsupported Content-Type"
95
+ )
99
96
 
100
97
  activity: Activity = Activity.model_validate(body)
101
98
 
@@ -15,6 +15,7 @@ from microsoft_agents.hosting.core.authorization import AccessTokenProviderBase
15
15
  from microsoft_agents.hosting.core.connector import ConnectorClientBase
16
16
  from microsoft_agents.hosting.core.connector.client import UserTokenClient
17
17
  from microsoft_agents.hosting.core.connector.teams import TeamsConnectorClient
18
+ from microsoft_agents.hosting.core.connector.mcs import MCSConnectorClient
18
19
 
19
20
  from .channel_service_client_factory_base import ChannelServiceClientFactoryBase
20
21
  from .turn_context import TurnContext
@@ -66,12 +67,15 @@ class RestChannelServiceClientFactory(ChannelServiceClientFactoryBase):
66
67
  raise ValueError("Agent instance ID is required for agentic identity role")
67
68
 
68
69
  if context.activity.recipient.role == RoleTypes.agentic_identity:
69
- token, _ = await connection.get_agentic_instance_token(agent_instance_id)
70
+ token, _ = await connection.get_agentic_instance_token(
71
+ context.activity.get_agentic_tenant_id(), agent_instance_id
72
+ )
70
73
  else:
71
74
  agentic_user = context.activity.get_agentic_user()
72
75
  if not agentic_user:
73
76
  raise ValueError("Agentic user is required for agentic user role")
74
77
  token = await connection.get_agentic_user_token(
78
+ context.activity.get_agentic_tenant_id(),
75
79
  agent_instance_id,
76
80
  agentic_user,
77
81
  [AuthenticationConstants.APX_PRODUCTION_SCOPE],
@@ -113,7 +117,17 @@ class RestChannelServiceClientFactory(ChannelServiceClientFactoryBase):
113
117
  )
114
118
 
115
119
  token = await token_provider.get_access_token(
116
- audience, scopes or [f"{audience}/.default"]
120
+ audience, scopes or claims_identity.get_token_scope()
121
+ )
122
+
123
+ # Check if this is a connector request (e.g., from Copilot Studio)
124
+ if (
125
+ context
126
+ and context.activity.recipient
127
+ and context.activity.recipient.role == RoleTypes.connector_user
128
+ ) or service_url.startswith("https://pvaruntime"):
129
+ return MCSConnectorClient(
130
+ endpoint=service_url,
117
131
  )
118
132
 
119
133
  return TeamsConnectorClient(
@@ -142,7 +156,7 @@ class RestChannelServiceClientFactory(ChannelServiceClientFactoryBase):
142
156
  if context.activity.is_agentic_request():
143
157
  token = await self._get_agentic_token(context, self._token_service_endpoint)
144
158
  else:
145
- scopes = [f"{self._token_service_audience}/.default"]
159
+ scopes = claims_identity.get_token_scope()
146
160
 
147
161
  token_provider = self._connection_manager.get_token_provider(
148
162
  claims_identity, self._token_service_endpoint
@@ -8,7 +8,6 @@ from ._type_aliases import JSON
8
8
  from .storage import Storage
9
9
  from .store_item import StoreItem
10
10
 
11
-
12
11
  StoreItemT = TypeVar("StoreItemT", bound=StoreItem)
13
12
 
14
13
 
@@ -8,7 +8,6 @@ from asyncio import gather
8
8
  from ._type_aliases import JSON
9
9
  from .store_item import StoreItem
10
10
 
11
-
12
11
  StoreItemT = TypeVar("StoreItemT", bound=StoreItem)
13
12
 
14
13
 
@@ -19,7 +19,6 @@ from microsoft_agents.activity.conversation_reference import ActivityEventNames
19
19
  from microsoft_agents.hosting.core.middleware_set import Middleware, TurnContext
20
20
  from typing import Generic, TypeVar
21
21
 
22
-
23
22
  T = TypeVar("T")
24
23
 
25
24
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: microsoft-agents-hosting-core
3
- Version: 0.7.0.dev10
3
+ Version: 0.7.0.dev16
4
4
  Summary: Core library for Microsoft Agents
5
5
  Author: Microsoft Corporation
6
6
  License-Expression: MIT
@@ -15,7 +15,7 @@ Classifier: Operating System :: OS Independent
15
15
  Requires-Python: >=3.10
16
16
  Description-Content-Type: text/markdown
17
17
  License-File: LICENSE
18
- Requires-Dist: microsoft-agents-activity==0.7.0.dev10
18
+ Requires-Dist: microsoft-agents-activity==0.7.0.dev16
19
19
  Requires-Dist: pyjwt>=2.10.1
20
20
  Requires-Dist: isodate>=0.6.1
21
21
  Requires-Dist: azure-core>=1.30.0
@@ -1,14 +1,14 @@
1
- microsoft_agents/hosting/core/__init__.py,sha256=iPlMZNnfGWwNe52937iqpDx40szMXzcYm_T2E6iFkag,5459
1
+ microsoft_agents/hosting/core/__init__.py,sha256=bpUnDxIdWHzcta50KQ0GVul9b7Y5-o4VxFJ20CQm4hQ,5458
2
2
  microsoft_agents/hosting/core/activity_handler.py,sha256=1hsSmVCnQLS44RK05v8j6mlmV38_JGmJTPR9LkogQuc,27779
3
3
  microsoft_agents/hosting/core/agent.py,sha256=K8v84y8ULP7rbcMKg8LxaM3haAq7f1oHFCLy3AAphQE,574
4
4
  microsoft_agents/hosting/core/card_factory.py,sha256=UDmPEpOk2SpEr9ShN9Q0CiaI_GTD3qjHgkDMOWinW9I,6926
5
5
  microsoft_agents/hosting/core/channel_adapter.py,sha256=MqES9gHGS0nrKBR7u8zLQCsuIksl-hScZy_jg4LTTHo,10669
6
6
  microsoft_agents/hosting/core/channel_api_handler_protocol.py,sha256=RO59hiOYx7flQVWhX6VGvfpFPoKVkdT_la-7WhUl8UM,4506
7
- microsoft_agents/hosting/core/channel_service_adapter.py,sha256=L3XQQSnWuF-8_1MAyZTsI7RRn9TfYv0UW1Dj6nyOuAQ,21598
7
+ microsoft_agents/hosting/core/channel_service_adapter.py,sha256=9wUrCGLO4WiHt_NLrSwUShHQAHxNsIefndOXZxKZu8M,21474
8
8
  microsoft_agents/hosting/core/channel_service_client_factory_base.py,sha256=9LcpxiWMXmWAdGQt6lRzvY9ybF_5mGc5Focd1Z7f9MY,1711
9
9
  microsoft_agents/hosting/core/message_factory.py,sha256=F9QJBF4yBupHXxOW984ZzZomVEG57t9IUnTHwub-lX0,7822
10
10
  microsoft_agents/hosting/core/middleware_set.py,sha256=TBsBs4KwAfKyHlQTlG4bl1y5UjkBzeMDs5w7LNB-Bi4,2585
11
- microsoft_agents/hosting/core/rest_channel_service_client_factory.py,sha256=NY9Pj9-jR2Oq-Crqm7as41FsVX3PLWsM-JEw3RTjyhE,6208
11
+ microsoft_agents/hosting/core/rest_channel_service_client_factory.py,sha256=yk_UhFiXm_-shkQYo731JHNGi4fElfiRshsHo1-bgWI,6789
12
12
  microsoft_agents/hosting/core/turn_context.py,sha256=muA8S4R6Xxja5it7DiFqr5J5zmttwDN-Mj5_SDdxZ4A,14874
13
13
  microsoft_agents/hosting/core/_oauth/__init__.py,sha256=sU1HsIXbETRYwnudtFc6GrNbM6C3oYjmruqXc6kIAFw,405
14
14
  microsoft_agents/hosting/core/_oauth/_flow_state.py,sha256=BQbXn0a3Fw4aozS-WSjL0Y7vEdb4eua1ZitSr0qZ6bE,2207
@@ -16,7 +16,7 @@ microsoft_agents/hosting/core/_oauth/_flow_storage_client.py,sha256=1MLD8m_qw0jS
16
16
  microsoft_agents/hosting/core/_oauth/_oauth_flow.py,sha256=vgg_sQLYr83YA0F7aQ1K5j8vEATw7ZS151ODkpCGYAM,12211
17
17
  microsoft_agents/hosting/core/app/__init__.py,sha256=GZQdog7BBMA8uD9iaRMNeRJf12rJZB3bAKFAD8Y8dVo,1228
18
18
  microsoft_agents/hosting/core/app/_type_defs.py,sha256=b5VZFWnQ5ONUZMtFxw7Q-mbbxIUSJ7RXcCXjqdHwSQw,438
19
- microsoft_agents/hosting/core/app/agent_application.py,sha256=iqcsLM4k_BWY0KKI1Ia-W11geuIHF8TP3mRc3D1eVF0,33984
19
+ microsoft_agents/hosting/core/app/agent_application.py,sha256=24WjroVgiHavWdJTsfyOgQTjRR8H-jF98JVLfkwWcXo,33804
20
20
  microsoft_agents/hosting/core/app/app_error.py,sha256=JgYBgv2EKe9Q2TFi5FeG_RneulBEa5SyBpWSF-duBzE,301
21
21
  microsoft_agents/hosting/core/app/app_options.py,sha256=P3XTFFuQCnEcHixfdmr5RPG-Wli4c1VSmCMRKVBBLsw,2792
22
22
  microsoft_agents/hosting/core/app/input_file.py,sha256=AEzVAnAPO1V7MWDI_uoZfcYY8Oog3XgvEpAeO-tATeY,1546
@@ -26,15 +26,16 @@ microsoft_agents/hosting/core/app/_routes/__init__.py,sha256=faz05Hk5Z1IGIXUwXlj
26
26
  microsoft_agents/hosting/core/app/_routes/_route.py,sha256=gs5XVi74H1wzDShpZd9ZXVDrREjricFYVPz10XrK06c,2669
27
27
  microsoft_agents/hosting/core/app/_routes/_route_list.py,sha256=fe1-wmFaJJqYkWFcbNhJ9OMH954TneQR0-uoxyKQVlU,874
28
28
  microsoft_agents/hosting/core/app/_routes/route_rank.py,sha256=-UwmLMCtgLT2cWnWvLfE2puV0RuQfI2m3WyEvkBkSBg,324
29
- microsoft_agents/hosting/core/app/oauth/__init__.py,sha256=eHx-vmW2Ew8HULSfvAmV8F9TBXXLcTPsBe3XP4JEDdY,556
29
+ microsoft_agents/hosting/core/app/oauth/__init__.py,sha256=IBfDWU5JHl9KuPI2JnOfkoCpDtQM80EdeWqTxebZq8A,622
30
30
  microsoft_agents/hosting/core/app/oauth/_sign_in_response.py,sha256=H5VBX69WiYXGALzCDVnF_-Y0brbafbJgfF4mS2wZSr0,851
31
31
  microsoft_agents/hosting/core/app/oauth/_sign_in_state.py,sha256=gtrLa_BgQq-yrTu8ItVwQ8fntfSKjlng2lCj6A8mCrc,897
32
32
  microsoft_agents/hosting/core/app/oauth/auth_handler.py,sha256=KyhEfpKtoVKcapOt4szpDdbgk_KSwXF46GGOeJrmsRI,3464
33
- microsoft_agents/hosting/core/app/oauth/authorization.py,sha256=_sdCZcZ7iciwTZqXTHFOK4vWWbCgSIDv3it30fzPI8w,18246
34
- microsoft_agents/hosting/core/app/oauth/_handlers/__init__.py,sha256=ZQuXF-IZrJv_hOgt-sdRFAUyIpRXaYqYBuyEJWJRcfU,376
33
+ microsoft_agents/hosting/core/app/oauth/authorization.py,sha256=gNiCYg9ETKczxwfxrg9UdxQxeig7c37jX9JzZ5gtagY,18761
34
+ microsoft_agents/hosting/core/app/oauth/_handlers/__init__.py,sha256=ZfUCRGb55A8RVNNKLKe0o_BkkvcOFgynxIrXmVfGuD4,479
35
35
  microsoft_agents/hosting/core/app/oauth/_handlers/_authorization_handler.py,sha256=W36Y1m0zFaRmdt-cL3ZKoHxx95y0O7YJF9D0cXx_s24,4185
36
36
  microsoft_agents/hosting/core/app/oauth/_handlers/_user_authorization.py,sha256=o_pn5ZO7O-YvcC5NGlUgcCmVLD-f6KwQ5CRIsPp8zQE,10186
37
- microsoft_agents/hosting/core/app/oauth/_handlers/agentic_user_authorization.py,sha256=4EgZxSMoymgap54xhoEQH0UIEBap-mMCiP6eFeanr3A,7253
37
+ microsoft_agents/hosting/core/app/oauth/_handlers/agentic_user_authorization.py,sha256=3B4Ph2L0VFE6cVPKgHSAuHnmPNfsgDjtjdAAmpjFDMs,7374
38
+ microsoft_agents/hosting/core/app/oauth/_handlers/connector_user_authorization.py,sha256=lnVD4xSjWKVX3gAi1Xux2xkdbui9jgTgFVDTlJojfFg,9387
38
39
  microsoft_agents/hosting/core/app/state/__init__.py,sha256=aL_8GB7_de8LUSEOgTJQFRx1kvgvJHHJVv7nWAoRPmU,331
39
40
  microsoft_agents/hosting/core/app/state/conversation_state.py,sha256=LfcSwvhaU0JeAahwg9YA9uz0kKHa9c6Y3XBAWqwuMg0,1593
40
41
  microsoft_agents/hosting/core/app/state/state.py,sha256=mbNrHuAc7d9vJep3PtExbLFtfKxZoAUX3Jr45GT3SuA,7373
@@ -45,14 +46,14 @@ microsoft_agents/hosting/core/app/streaming/citation.py,sha256=ZGaMUOWxxoMplwRrk
45
46
  microsoft_agents/hosting/core/app/streaming/citation_util.py,sha256=c95c3Y3genmFc0vSXppPaD1-ShFohAV1UABZnyJS_BQ,2478
46
47
  microsoft_agents/hosting/core/app/streaming/streaming_response.py,sha256=uwNYaVJ8cghdjHS_Y8ZeOiYnpyeQGHt0rQQlay6a-C8,13799
47
48
  microsoft_agents/hosting/core/authorization/__init__.py,sha256=pOTmTJFS5CMPEcHRadBTgrbWUP5lOIxsPMgTreFq7mw,634
48
- microsoft_agents/hosting/core/authorization/access_token_provider_base.py,sha256=Z0nGkfOUSIBvJSFjGGNQEd1-upqZVjT6eSXsqsFa2Cc,1646
49
- microsoft_agents/hosting/core/authorization/agent_auth_configuration.py,sha256=meLUO0Mwb9SBr01dLvYS9q3xuZyndCsb_gIx0r7__Sk,2944
50
- microsoft_agents/hosting/core/authorization/anonymous_token_provider.py,sha256=44XKaSLJFZj4hCSAdWAtW1R31M5QCZVaFKJaxcwx5h4,1076
49
+ microsoft_agents/hosting/core/authorization/access_token_provider_base.py,sha256=a3nyMsN539akjT3srdOmi0PShDJAJNXzcMpfFfzXj48,1727
50
+ microsoft_agents/hosting/core/authorization/agent_auth_configuration.py,sha256=JgyudvnJicU7pqdChnrv3hiULROKiQNdY4ZbNJ881fU,4150
51
+ microsoft_agents/hosting/core/authorization/anonymous_token_provider.py,sha256=N60FVEXCFJDSgwqJPQHZQYlbgVldzOIpwdn7aArj0dA,1157
51
52
  microsoft_agents/hosting/core/authorization/auth_types.py,sha256=Fg_ywEItm3xL_DBUNzi0QsfDPVY5S3HlAiNw6I2SW64,374
52
53
  microsoft_agents/hosting/core/authorization/authentication_constants.py,sha256=ABEwosDCMYhubDiGrD8QULboTkACqDvNp_x_XBPt6dQ,4618
53
- microsoft_agents/hosting/core/authorization/claims_identity.py,sha256=z2Ql7CMPgioYOw970ynxfKWHyk5lqPwMgSrNh4bUfNo,2620
54
+ microsoft_agents/hosting/core/authorization/claims_identity.py,sha256=KPcWbrFmlGwv1T493asolyiERuxq6Y2l77o7oDzvTzs,3094
54
55
  microsoft_agents/hosting/core/authorization/connections.py,sha256=f_NQpuJzhCBNZLk56SK4kvb_V_g2x2XMnFwWbYyDX_s,1247
55
- microsoft_agents/hosting/core/authorization/jwt_token_validator.py,sha256=b440T7y1tM7gPUQZ27EA3SgNiaEupxz56E6773gL5Zo,2025
56
+ microsoft_agents/hosting/core/authorization/jwt_token_validator.py,sha256=HQqs8pNVrysBWB9EgLbhVtm70rqrf7w5mh7DIGHCWWM,2063
56
57
  microsoft_agents/hosting/core/client/__init__.py,sha256=HMWtSUXu1akaX6qtDx412Lr8vLi5SEslc-DYrvZAPWs,1299
57
58
  microsoft_agents/hosting/core/client/agent_conversation_reference.py,sha256=3Zf3IGbJVWv4pF6kA6vtWkpV3Ap3z6jVkimeEtFMvJI,288
58
59
  microsoft_agents/hosting/core/client/channel_factory_protocol.py,sha256=r270WJwySugnzY4AITT8oSRQHKqeqYAknkmD2eq_CqA,394
@@ -67,7 +68,7 @@ microsoft_agents/hosting/core/client/conversation_id_factory_options.py,sha256=r
67
68
  microsoft_agents/hosting/core/client/conversation_id_factory_protocol.py,sha256=fjQawuVwiQm-pdDMDZBUIdlnKyPe1gg-0tN3fNxrMr8,1323
68
69
  microsoft_agents/hosting/core/client/http_agent_channel.py,sha256=2D2sjw8HtZvp_43xDjTLXp6_DLNrXziYhNmob14RwCM,3634
69
70
  microsoft_agents/hosting/core/client/http_agent_channel_factory.py,sha256=ESY2EJwZMdSAa5I06pFHc89vO5Lflp86O6wJAnfz2qI,523
70
- microsoft_agents/hosting/core/connector/__init__.py,sha256=Dkc1GAviMYXw5BFvP6xgVhrb1UJUuLiHbfEkjminnOc,522
71
+ microsoft_agents/hosting/core/connector/__init__.py,sha256=Fn5SgrVhm7ZaolXHDy8qmVt7uYBRbS3H-svpzj7ZzVM,616
71
72
  microsoft_agents/hosting/core/connector/agent_sign_in_base.py,sha256=Bk3Ssg3ilk1Ld2mSjsCYgfqvy6pq1us9Ja2j4lF7CTc,647
72
73
  microsoft_agents/hosting/core/connector/attachments_base.py,sha256=eqr5dbrc7oE77xeFfr-5UIi4gkDvOp5zWbZ02Qb4IDI,507
73
74
  microsoft_agents/hosting/core/connector/connector_client_base.py,sha256=DKog6C1Z8V9r_Lp-IvXUiAbJN_iJMFary5FvejjHlaw,583
@@ -76,15 +77,17 @@ microsoft_agents/hosting/core/connector/get_product_info.py,sha256=SDxPqBCzzQLEU
76
77
  microsoft_agents/hosting/core/connector/user_token_base.py,sha256=h_l5D1SghN2RrUkFcKWQhCHlO9r7akMbzsm2x8MvomI,3639
77
78
  microsoft_agents/hosting/core/connector/user_token_client_base.py,sha256=dfUTUsBNOzWze9_JldAeLe73sydSDzlKyMKMvj48g2E,471
78
79
  microsoft_agents/hosting/core/connector/client/__init__.py,sha256=6JdKhmm7btmo0omxMBd8PJbtGFk0cnMwVUoStyW7Ft0,143
79
- microsoft_agents/hosting/core/connector/client/connector_client.py,sha256=9oF_x_LffOIKjTLMdPf3Biq3vvWn8r8e0NBJkHBn684,23866
80
- microsoft_agents/hosting/core/connector/client/user_token_client.py,sha256=qxYxvdUcvYinCzaR4YiIucEEAb8TjYYtPsmXKZRbxv4,10536
80
+ microsoft_agents/hosting/core/connector/client/connector_client.py,sha256=S0JzWkOCgsVKLUi0KGplXT0SCbQ0HEahhTe3ex2iO_E,23865
81
+ microsoft_agents/hosting/core/connector/client/user_token_client.py,sha256=rtQ5GivBhCOpDeUkAdI0_R5c0RE-FbLxzTttopxOH2o,10535
82
+ microsoft_agents/hosting/core/connector/mcs/__init__.py,sha256=fXHQt7WCkJ4bio5h7IAhH2vP6VE8WBf9IOeHwBnT0cA,87
83
+ microsoft_agents/hosting/core/connector/mcs/mcs_connector_client.py,sha256=MAmgkbbzh7pPG92YwaCp3QZTfWd7KvyKCNaTiisfrlA,8517
81
84
  microsoft_agents/hosting/core/connector/teams/__init__.py,sha256=3ZMPGYyZ15EwvfQzfJJQy1J58oIt4InSxibl3BN6R54,100
82
85
  microsoft_agents/hosting/core/connector/teams/teams_connector_client.py,sha256=XGQDTYHrA_I9n9JlxGST5eesjsFhz2dnSaMSuyoFnKU,12676
83
86
  microsoft_agents/hosting/core/errors/__init__.py,sha256=kcfwDGDaopWfLyvYsNXM6j4cYt2oGKysjCRDezcVY0A,500
84
- microsoft_agents/hosting/core/errors/error_resources.py,sha256=_nyvPQaX3gpi9kziajVdzGWCzMa6JcTntK__zQJlGMo,3922
87
+ microsoft_agents/hosting/core/errors/error_resources.py,sha256=A8UdgOsM55XJFlscfkHjGQiXpw0C-OTT7HloN_H8r1U,4350
85
88
  microsoft_agents/hosting/core/http/__init__.py,sha256=Jh6lIivBN9YsNaLPzYvzvbhLAwJbeQTSRHtFupfSy-I,532
86
89
  microsoft_agents/hosting/core/http/_channel_service_routes.py,sha256=80IWoUDKywUurXnh7vmG0QMxu3sk7W38zgHsw0eJ2DA,8436
87
- microsoft_agents/hosting/core/http/_http_adapter_base.py,sha256=qRqAwMl1Wsq_A1J6asMMcS9jUGjlLD3HF-0Sioba5IM,4561
90
+ microsoft_agents/hosting/core/http/_http_adapter_base.py,sha256=L8cPsPluPOUVu42aXFq4hugxbJ3gDzSALQgDvb9-2bA,4396
88
91
  microsoft_agents/hosting/core/http/_http_request_protocol.py,sha256=YTfcp_K1IswAIWVQ5QFBTyX-ssuUo6BChdlPHEh-t4Q,1002
89
92
  microsoft_agents/hosting/core/http/_http_response.py,sha256=e_bY0bJJXx--Zb_Yd-f9iDPFbK4bWkFi92a0nq1A6us,1862
90
93
  microsoft_agents/hosting/core/state/__init__.py,sha256=yckKi1wg_86ng-DL9Q3R49QiWKvNjPkVNk6HClWgVrY,208
@@ -94,16 +97,16 @@ microsoft_agents/hosting/core/state/user_state.py,sha256=zEigX-sroNAyoQAxQjG1Ogm
94
97
  microsoft_agents/hosting/core/storage/__init__.py,sha256=Df_clI0uMRgcr4Td-xkP83bU_mGae7_gRMhtVDPZDmE,729
95
98
  microsoft_agents/hosting/core/storage/_type_aliases.py,sha256=VCKtjiCBrhEsGSm3zVVSSccdoiY02GYhABvrLjhAcz8,72
96
99
  microsoft_agents/hosting/core/storage/error_handling.py,sha256=kTMQ68GxL4GgVKpo3SexzyRARLw6UbsVhHU723XxIck,1360
97
- microsoft_agents/hosting/core/storage/memory_storage.py,sha256=5AZ2QQ3TagVCHCKp0GEVAIuDswDGHgbgnUZgS9YbPAI,2448
98
- microsoft_agents/hosting/core/storage/storage.py,sha256=bt93jItMQKC9NJlcmxPtcE67MvnibolcFwvV1LFwliI,3322
100
+ microsoft_agents/hosting/core/storage/memory_storage.py,sha256=VUKFWc6aAfUzwfH_hiPvFsbESGY78qCCTkBnpoNZUe4,2447
101
+ microsoft_agents/hosting/core/storage/storage.py,sha256=zHnQNaLYgzjLP_XWfL3e-Dlw7eQbNgXUYbnT_26rYvM,3321
99
102
  microsoft_agents/hosting/core/storage/store_item.py,sha256=rjtzB5yufsKuY1O5PjCqWHjjmO6UiORwkzpwbsaxp_4,371
100
103
  microsoft_agents/hosting/core/storage/transcript_file_store.py,sha256=eJdcU6BgMbvFYunWul2CZURH762HmUr11iUN7NgvZek,10045
101
104
  microsoft_agents/hosting/core/storage/transcript_info.py,sha256=5VN32j99tshChAffvuZ6D3GH3ABCZsQGHC_bYDAwFOk,328
102
- microsoft_agents/hosting/core/storage/transcript_logger.py,sha256=_atDk3CJ05fIVMhlWGNa91IiM9bGLmOhasFko8Lxjhk,8237
105
+ microsoft_agents/hosting/core/storage/transcript_logger.py,sha256=rgFeghzyRd9M3IUtI9n5y_rdAOL9s6qgGVD4OTOjkEg,8236
103
106
  microsoft_agents/hosting/core/storage/transcript_memory_store.py,sha256=v1Ud9LSs8m5c9_Fa8i49SuAjw80dX1hDciqbRduDEOE,6444
104
107
  microsoft_agents/hosting/core/storage/transcript_store.py,sha256=ka74o0WvI5GhMZcFqSxVdamBhGzZcDZe6VNkG-sMy74,1944
105
- microsoft_agents_hosting_core-0.7.0.dev10.dist-info/licenses/LICENSE,sha256=ws_MuBL-SCEBqPBFl9_FqZkaaydIJmxHrJG2parhU4M,1141
106
- microsoft_agents_hosting_core-0.7.0.dev10.dist-info/METADATA,sha256=pfoy9NvG0Pi6-Ku0-vyEIXFqsrkHusA0zhPUbqRxchM,9821
107
- microsoft_agents_hosting_core-0.7.0.dev10.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
108
- microsoft_agents_hosting_core-0.7.0.dev10.dist-info/top_level.txt,sha256=lWKcT4v6fTA_NgsuHdNvuMjSrkiBMXohn64ApY7Xi8A,17
109
- microsoft_agents_hosting_core-0.7.0.dev10.dist-info/RECORD,,
108
+ microsoft_agents_hosting_core-0.7.0.dev16.dist-info/licenses/LICENSE,sha256=ws_MuBL-SCEBqPBFl9_FqZkaaydIJmxHrJG2parhU4M,1141
109
+ microsoft_agents_hosting_core-0.7.0.dev16.dist-info/METADATA,sha256=wHXiJtG1nuxuYpXFlY_ze9P3fnaUND2SEnnhJ8g8h6Y,9821
110
+ microsoft_agents_hosting_core-0.7.0.dev16.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
111
+ microsoft_agents_hosting_core-0.7.0.dev16.dist-info/top_level.txt,sha256=lWKcT4v6fTA_NgsuHdNvuMjSrkiBMXohn64ApY7Xi8A,17
112
+ microsoft_agents_hosting_core-0.7.0.dev16.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (80.10.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5