microsoft-agents-copilotstudio-client 1.9.0.dev5__tar.gz → 1.9.0.dev10__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_copilotstudio_client-1.9.0.dev5/microsoft_agents_copilotstudio_client.egg-info → microsoft_agents_copilotstudio_client-1.9.0.dev10}/PKG-INFO +24 -2
- microsoft_agents_copilotstudio_client-1.9.0.dev10/VERSION.txt +1 -0
- microsoft_agents_copilotstudio_client-1.9.0.dev10/microsoft_agents/copilotstudio/client/_conversation_endpoint_discovery.py +106 -0
- {microsoft_agents_copilotstudio_client-1.9.0.dev5 → microsoft_agents_copilotstudio_client-1.9.0.dev10}/microsoft_agents/copilotstudio/client/copilot_client.py +100 -16
- {microsoft_agents_copilotstudio_client-1.9.0.dev5 → microsoft_agents_copilotstudio_client-1.9.0.dev10}/microsoft_agents/copilotstudio/client/errors/error_resources.py +25 -0
- {microsoft_agents_copilotstudio_client-1.9.0.dev5 → microsoft_agents_copilotstudio_client-1.9.0.dev10}/microsoft_agents/copilotstudio/client/power_platform_environment.py +1 -0
- microsoft_agents_copilotstudio_client-1.9.0.dev5/readme.md → microsoft_agents_copilotstudio_client-1.9.0.dev10/microsoft_agents_copilotstudio_client.egg-info/PKG-INFO +44 -1
- {microsoft_agents_copilotstudio_client-1.9.0.dev5 → microsoft_agents_copilotstudio_client-1.9.0.dev10}/microsoft_agents_copilotstudio_client.egg-info/SOURCES.txt +1 -0
- microsoft_agents_copilotstudio_client-1.9.0.dev10/microsoft_agents_copilotstudio_client.egg-info/requires.txt +1 -0
- microsoft_agents_copilotstudio_client-1.9.0.dev5/PKG-INFO → microsoft_agents_copilotstudio_client-1.9.0.dev10/readme.md +23 -22
- microsoft_agents_copilotstudio_client-1.9.0.dev5/VERSION.txt +0 -1
- microsoft_agents_copilotstudio_client-1.9.0.dev5/microsoft_agents_copilotstudio_client.egg-info/requires.txt +0 -1
- {microsoft_agents_copilotstudio_client-1.9.0.dev5 → microsoft_agents_copilotstudio_client-1.9.0.dev10}/LICENSE +0 -0
- {microsoft_agents_copilotstudio_client-1.9.0.dev5 → microsoft_agents_copilotstudio_client-1.9.0.dev10}/MANIFEST.in +0 -0
- {microsoft_agents_copilotstudio_client-1.9.0.dev5 → microsoft_agents_copilotstudio_client-1.9.0.dev10}/microsoft_agents/copilotstudio/client/__init__.py +0 -0
- {microsoft_agents_copilotstudio_client-1.9.0.dev5 → microsoft_agents_copilotstudio_client-1.9.0.dev10}/microsoft_agents/copilotstudio/client/agent_type.py +0 -0
- {microsoft_agents_copilotstudio_client-1.9.0.dev5 → microsoft_agents_copilotstudio_client-1.9.0.dev10}/microsoft_agents/copilotstudio/client/connection_settings.py +0 -0
- {microsoft_agents_copilotstudio_client-1.9.0.dev5 → microsoft_agents_copilotstudio_client-1.9.0.dev10}/microsoft_agents/copilotstudio/client/copilot_client_protocol.py +0 -0
- {microsoft_agents_copilotstudio_client-1.9.0.dev5 → microsoft_agents_copilotstudio_client-1.9.0.dev10}/microsoft_agents/copilotstudio/client/direct_to_engine_connection_settings_protocol.py +0 -0
- {microsoft_agents_copilotstudio_client-1.9.0.dev5 → microsoft_agents_copilotstudio_client-1.9.0.dev10}/microsoft_agents/copilotstudio/client/errors/__init__.py +0 -0
- {microsoft_agents_copilotstudio_client-1.9.0.dev5 → microsoft_agents_copilotstudio_client-1.9.0.dev10}/microsoft_agents/copilotstudio/client/execute_turn_request.py +0 -0
- {microsoft_agents_copilotstudio_client-1.9.0.dev5 → microsoft_agents_copilotstudio_client-1.9.0.dev10}/microsoft_agents/copilotstudio/client/power_platform_cloud.py +0 -0
- {microsoft_agents_copilotstudio_client-1.9.0.dev5 → microsoft_agents_copilotstudio_client-1.9.0.dev10}/microsoft_agents/copilotstudio/client/py.typed +0 -0
- {microsoft_agents_copilotstudio_client-1.9.0.dev5 → microsoft_agents_copilotstudio_client-1.9.0.dev10}/microsoft_agents/copilotstudio/client/start_request.py +0 -0
- {microsoft_agents_copilotstudio_client-1.9.0.dev5 → microsoft_agents_copilotstudio_client-1.9.0.dev10}/microsoft_agents/copilotstudio/client/subscribe_event.py +0 -0
- {microsoft_agents_copilotstudio_client-1.9.0.dev5 → microsoft_agents_copilotstudio_client-1.9.0.dev10}/microsoft_agents/copilotstudio/client/subscribe_request.py +0 -0
- {microsoft_agents_copilotstudio_client-1.9.0.dev5 → microsoft_agents_copilotstudio_client-1.9.0.dev10}/microsoft_agents/copilotstudio/client/subscribe_response.py +0 -0
- {microsoft_agents_copilotstudio_client-1.9.0.dev5 → microsoft_agents_copilotstudio_client-1.9.0.dev10}/microsoft_agents/copilotstudio/client/user_agent_helper.py +0 -0
- {microsoft_agents_copilotstudio_client-1.9.0.dev5 → microsoft_agents_copilotstudio_client-1.9.0.dev10}/microsoft_agents_copilotstudio_client.egg-info/dependency_links.txt +0 -0
- {microsoft_agents_copilotstudio_client-1.9.0.dev5 → microsoft_agents_copilotstudio_client-1.9.0.dev10}/microsoft_agents_copilotstudio_client.egg-info/top_level.txt +0 -0
- {microsoft_agents_copilotstudio_client-1.9.0.dev5 → microsoft_agents_copilotstudio_client-1.9.0.dev10}/pyproject.toml +0 -0
- {microsoft_agents_copilotstudio_client-1.9.0.dev5 → microsoft_agents_copilotstudio_client-1.9.0.dev10}/setup.cfg +0 -0
- {microsoft_agents_copilotstudio_client-1.9.0.dev5 → microsoft_agents_copilotstudio_client-1.9.0.dev10}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: microsoft-agents-copilotstudio-client
|
|
3
|
-
Version: 1.9.0.
|
|
3
|
+
Version: 1.9.0.dev10
|
|
4
4
|
Summary: A client 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-hosting-core==1.9.0.
|
|
18
|
+
Requires-Dist: microsoft-agents-hosting-core==1.9.0.dev10
|
|
19
19
|
Dynamic: license-file
|
|
20
20
|
Dynamic: requires-dist
|
|
21
21
|
|
|
@@ -230,6 +230,28 @@ def create_client():
|
|
|
230
230
|
return copilot_client
|
|
231
231
|
```
|
|
232
232
|
|
|
233
|
+
#### Conversation Endpoint Discovery
|
|
234
|
+
|
|
235
|
+
For published agents without a `direct_connect_url`, the client first sends an
|
|
236
|
+
authenticated `GET` to
|
|
237
|
+
`https://<environment-host>/copilotstudio/agents/<escaped-schema-name>/conversation-endpoints`.
|
|
238
|
+
The host is selected from the configured environment and cloud. Discovery uses the
|
|
239
|
+
client's bearer token and the configured `client_session_settings`.
|
|
240
|
+
|
|
241
|
+
The client validates all advertised endpoints before storing them and uses each
|
|
242
|
+
operation URL as returned, preserving its query string and escaping conversation
|
|
243
|
+
IDs when substituting `{conversationId}`. `createConversation`, `executeTurn`, and
|
|
244
|
+
`continueTurn` are required; `subscribe` is optional and subscription fails
|
|
245
|
+
explicitly when the agent does not advertise it. The client has no continue-turn
|
|
246
|
+
operation.
|
|
247
|
+
|
|
248
|
+
Successful discovery is reused for the lifetime of the client, with concurrent
|
|
249
|
+
calls coordinated to avoid duplicate initialization. Failures and cancellation
|
|
250
|
+
allow a later call to retry. The discovered create URL is written to
|
|
251
|
+
`settings.direct_connect_url`; clearing that value triggers discovery again.
|
|
252
|
+
Assigning a different explicit URL switches back to legacy direct-URL routing.
|
|
253
|
+
Explicit direct URLs and prebuilt agents bypass discovery entirely.
|
|
254
|
+
|
|
233
255
|
#### DirectConnect URL Mode (Simplified Setup)
|
|
234
256
|
|
|
235
257
|
For simplified setup, you can use a DirectConnect URL instead of environment-based configuration:
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1.9.0.dev10
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation. All rights reserved.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from typing import Literal, Optional
|
|
6
|
+
from urllib.parse import quote, urlsplit, urlunsplit
|
|
7
|
+
|
|
8
|
+
from .connection_settings import ConnectionSettings
|
|
9
|
+
from .errors import copilot_studio_errors
|
|
10
|
+
from .power_platform_environment import PowerPlatformEnvironment
|
|
11
|
+
|
|
12
|
+
ConversationOperation = Literal["createConversation", "executeTurn", "subscribe"]
|
|
13
|
+
_CONVERSATION_ID = "{conversationId}"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def get_discovery_url(settings: ConnectionSettings) -> str:
|
|
17
|
+
url = urlsplit(PowerPlatformEnvironment.get_copilot_studio_connection_url(settings))
|
|
18
|
+
return urlunsplit(
|
|
19
|
+
(
|
|
20
|
+
url.scheme,
|
|
21
|
+
url.netloc,
|
|
22
|
+
f"/copilotstudio/agents/{quote(settings.agent_identifier, safe='')}/conversation-endpoints",
|
|
23
|
+
"",
|
|
24
|
+
"",
|
|
25
|
+
)
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _validate_url(
|
|
30
|
+
value: object, discovery_url: str, requires_conversation_id: bool
|
|
31
|
+
) -> str:
|
|
32
|
+
error = str(copilot_studio_errors.InvalidDiscoveryOperationUrl)
|
|
33
|
+
if not isinstance(value, str) or not value.strip():
|
|
34
|
+
raise ValueError(error)
|
|
35
|
+
|
|
36
|
+
remainder = value.replace(_CONVERSATION_ID, "")
|
|
37
|
+
if (
|
|
38
|
+
requires_conversation_id != (_CONVERSATION_ID in value)
|
|
39
|
+
or "{" in remainder
|
|
40
|
+
or "}" in remainder
|
|
41
|
+
or "\\" in value
|
|
42
|
+
or any(character.isspace() or ord(character) < 32 for character in value)
|
|
43
|
+
):
|
|
44
|
+
raise ValueError(error)
|
|
45
|
+
|
|
46
|
+
try:
|
|
47
|
+
discovery = urlsplit(discovery_url)
|
|
48
|
+
url = urlsplit(value.replace(_CONVERSATION_ID, "conversation"))
|
|
49
|
+
host = discovery.hostname or ""
|
|
50
|
+
suffix_index = host.find(".environment.")
|
|
51
|
+
suffix = host[suffix_index:] if suffix_index >= 0 else "." + host
|
|
52
|
+
valid = (
|
|
53
|
+
url.scheme == "https"
|
|
54
|
+
and (url.port if url.port is not None else 443)
|
|
55
|
+
== (discovery.port if discovery.port is not None else 443)
|
|
56
|
+
and bool(url.hostname)
|
|
57
|
+
and url.hostname.endswith(suffix)
|
|
58
|
+
and url.username is None
|
|
59
|
+
and url.password is None
|
|
60
|
+
and not url.fragment
|
|
61
|
+
)
|
|
62
|
+
except ValueError as exc:
|
|
63
|
+
raise ValueError(error) from exc
|
|
64
|
+
if not valid:
|
|
65
|
+
raise ValueError(error)
|
|
66
|
+
return value
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@dataclass(frozen=True)
|
|
70
|
+
class ConversationEndpoints:
|
|
71
|
+
create_conversation: str
|
|
72
|
+
execute_turn: str
|
|
73
|
+
continue_turn: str
|
|
74
|
+
subscribe: Optional[str]
|
|
75
|
+
|
|
76
|
+
@classmethod
|
|
77
|
+
def from_response(cls, data: object, discovery_url: str) -> "ConversationEndpoints":
|
|
78
|
+
if not isinstance(data, dict):
|
|
79
|
+
raise ValueError(str(copilot_studio_errors.InvalidDiscoveryResponse))
|
|
80
|
+
|
|
81
|
+
return cls(
|
|
82
|
+
create_conversation=_validate_url(
|
|
83
|
+
data.get("createConversation"), discovery_url, False
|
|
84
|
+
),
|
|
85
|
+
execute_turn=_validate_url(data.get("executeTurn"), discovery_url, True),
|
|
86
|
+
continue_turn=_validate_url(data.get("continueTurn"), discovery_url, True),
|
|
87
|
+
subscribe=(
|
|
88
|
+
_validate_url(data["subscribe"], discovery_url, True)
|
|
89
|
+
if data.get("subscribe") is not None
|
|
90
|
+
else None
|
|
91
|
+
),
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
def get_url(
|
|
95
|
+
self, operation: ConversationOperation, conversation_id: Optional[str] = None
|
|
96
|
+
) -> str:
|
|
97
|
+
if operation == "createConversation":
|
|
98
|
+
return self.create_conversation
|
|
99
|
+
if not conversation_id:
|
|
100
|
+
raise ValueError(str(copilot_studio_errors.DiscoveryConversationIdRequired))
|
|
101
|
+
url = self.execute_turn if operation == "executeTurn" else self.subscribe
|
|
102
|
+
if url is None:
|
|
103
|
+
raise NotImplementedError(
|
|
104
|
+
str(copilot_studio_errors.DiscoverySubscribeNotSupported)
|
|
105
|
+
)
|
|
106
|
+
return url.replace(_CONVERSATION_ID, quote(conversation_id, safe=""))
|
|
@@ -1,13 +1,23 @@
|
|
|
1
1
|
# Copyright (c) Microsoft Corporation. All rights reserved.
|
|
2
2
|
# Licensed under the MIT License.
|
|
3
3
|
|
|
4
|
-
import
|
|
4
|
+
import asyncio
|
|
5
|
+
import json
|
|
5
6
|
import logging
|
|
6
7
|
from typing import AsyncIterable, Optional
|
|
7
8
|
|
|
9
|
+
import aiohttp
|
|
10
|
+
|
|
8
11
|
from microsoft_agents.activity import Activity, ActivityTypes, ConversationAccount
|
|
9
12
|
|
|
13
|
+
from ._conversation_endpoint_discovery import (
|
|
14
|
+
ConversationEndpoints,
|
|
15
|
+
ConversationOperation,
|
|
16
|
+
get_discovery_url,
|
|
17
|
+
)
|
|
18
|
+
from .agent_type import AgentType
|
|
10
19
|
from .connection_settings import ConnectionSettings
|
|
20
|
+
from .errors import copilot_studio_errors
|
|
11
21
|
from .execute_turn_request import ExecuteTurnRequest
|
|
12
22
|
from .power_platform_environment import PowerPlatformEnvironment
|
|
13
23
|
from .start_request import StartRequest
|
|
@@ -34,6 +44,91 @@ class CopilotClient:
|
|
|
34
44
|
self._logger = logging.getLogger(__name__)
|
|
35
45
|
self.conversation_id = ""
|
|
36
46
|
self._island_experimental_url = ""
|
|
47
|
+
self._discovery_lock = asyncio.Lock()
|
|
48
|
+
self._discovered_direct_connect_url: Optional[str] = None
|
|
49
|
+
self._discovered_endpoints: Optional[ConversationEndpoints] = None
|
|
50
|
+
|
|
51
|
+
async def _resolve_connection_url(
|
|
52
|
+
self, conversation_id: Optional[str] = None, subscribe: bool = False
|
|
53
|
+
) -> str:
|
|
54
|
+
if (
|
|
55
|
+
self.settings.copilot_agent_type != AgentType.PREBUILT
|
|
56
|
+
and not self.settings.direct_connect_url
|
|
57
|
+
):
|
|
58
|
+
async with self._discovery_lock:
|
|
59
|
+
if (
|
|
60
|
+
self.settings.copilot_agent_type != AgentType.PREBUILT
|
|
61
|
+
and not self.settings.direct_connect_url
|
|
62
|
+
):
|
|
63
|
+
endpoints = await self._discover_endpoints()
|
|
64
|
+
if (
|
|
65
|
+
self.settings.copilot_agent_type != AgentType.PREBUILT
|
|
66
|
+
and not self.settings.direct_connect_url
|
|
67
|
+
):
|
|
68
|
+
self._discovered_endpoints = endpoints
|
|
69
|
+
self._discovered_direct_connect_url = (
|
|
70
|
+
endpoints.create_conversation
|
|
71
|
+
)
|
|
72
|
+
self.settings.direct_connect_url = endpoints.create_conversation
|
|
73
|
+
|
|
74
|
+
if (
|
|
75
|
+
self.settings.copilot_agent_type != AgentType.PREBUILT
|
|
76
|
+
and self._discovered_endpoints is not None
|
|
77
|
+
and self.settings.direct_connect_url == self._discovered_direct_connect_url
|
|
78
|
+
):
|
|
79
|
+
operation: ConversationOperation = (
|
|
80
|
+
"subscribe"
|
|
81
|
+
if subscribe
|
|
82
|
+
else "executeTurn" if conversation_id else "createConversation"
|
|
83
|
+
)
|
|
84
|
+
return self._discovered_endpoints.get_url(operation, conversation_id)
|
|
85
|
+
return PowerPlatformEnvironment.get_copilot_studio_connection_url(
|
|
86
|
+
settings=self.settings,
|
|
87
|
+
conversation_id=conversation_id,
|
|
88
|
+
create_subscribe_link=subscribe,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
async def _discover_endpoints(self) -> ConversationEndpoints:
|
|
92
|
+
if not self._token or not self._token.strip():
|
|
93
|
+
raise ValueError(str(copilot_studio_errors.DiscoveryAccessTokenRequired))
|
|
94
|
+
|
|
95
|
+
url = get_discovery_url(self.settings)
|
|
96
|
+
headers = {
|
|
97
|
+
"Authorization": f"Bearer {self._token}",
|
|
98
|
+
"Accept": self.APPLICATION_JSON_TYPE,
|
|
99
|
+
"User-Agent": UserAgentHelper.get_user_agent_header(),
|
|
100
|
+
}
|
|
101
|
+
if self.settings.enable_diagnostics:
|
|
102
|
+
self._logger.debug(">>> SEND TO %s", url)
|
|
103
|
+
|
|
104
|
+
async with aiohttp.ClientSession(
|
|
105
|
+
**self.settings.client_session_settings
|
|
106
|
+
) as session:
|
|
107
|
+
async with session.get(
|
|
108
|
+
url, headers=headers, allow_redirects=False
|
|
109
|
+
) as response:
|
|
110
|
+
if response.status != 200:
|
|
111
|
+
self._logger.error(
|
|
112
|
+
"Error discovering conversation endpoints: %s", response.status
|
|
113
|
+
)
|
|
114
|
+
raise aiohttp.ClientResponseError(
|
|
115
|
+
response.request_info,
|
|
116
|
+
response.history,
|
|
117
|
+
status=response.status,
|
|
118
|
+
message="Error discovering conversation endpoints",
|
|
119
|
+
headers=response.headers,
|
|
120
|
+
)
|
|
121
|
+
try:
|
|
122
|
+
data = await response.json()
|
|
123
|
+
except (
|
|
124
|
+
json.JSONDecodeError,
|
|
125
|
+
UnicodeDecodeError,
|
|
126
|
+
aiohttp.ContentTypeError,
|
|
127
|
+
) as exc:
|
|
128
|
+
raise ValueError(
|
|
129
|
+
str(copilot_studio_errors.InvalidDiscoveryResponse)
|
|
130
|
+
) from exc
|
|
131
|
+
return ConversationEndpoints.from_response(data, url)
|
|
37
132
|
|
|
38
133
|
async def post_request(
|
|
39
134
|
self, url: str, data: dict, headers: dict
|
|
@@ -112,9 +207,7 @@ class CopilotClient:
|
|
|
112
207
|
:return: An asynchronous iterable of Activity objects received in the response.
|
|
113
208
|
"""
|
|
114
209
|
|
|
115
|
-
url =
|
|
116
|
-
settings=self.settings
|
|
117
|
-
)
|
|
210
|
+
url = await self._resolve_connection_url()
|
|
118
211
|
data = {"emitStartConversationEvent": emit_start_conversation_event}
|
|
119
212
|
headers = {
|
|
120
213
|
"Content-Type": self.APPLICATION_JSON_TYPE,
|
|
@@ -164,9 +257,7 @@ class CopilotClient:
|
|
|
164
257
|
activity.conversation.id or self._current_conversation_id
|
|
165
258
|
)
|
|
166
259
|
|
|
167
|
-
url =
|
|
168
|
-
settings=self.settings, conversation_id=local_conversation_id
|
|
169
|
-
)
|
|
260
|
+
url = await self._resolve_connection_url(local_conversation_id)
|
|
170
261
|
data = ExecuteTurnRequest(activity=activity).model_dump(
|
|
171
262
|
mode="json", by_alias=True, exclude_unset=True
|
|
172
263
|
)
|
|
@@ -188,9 +279,7 @@ class CopilotClient:
|
|
|
188
279
|
:return: An asynchronous iterable of Activity objects received in the response.
|
|
189
280
|
"""
|
|
190
281
|
|
|
191
|
-
url =
|
|
192
|
-
settings=self.settings
|
|
193
|
-
)
|
|
282
|
+
url = await self._resolve_connection_url()
|
|
194
283
|
data = start_request.model_dump(mode="json", by_alias=True, exclude_unset=True)
|
|
195
284
|
headers = {
|
|
196
285
|
"Content-Type": self.APPLICATION_JSON_TYPE,
|
|
@@ -249,12 +338,7 @@ class CopilotClient:
|
|
|
249
338
|
if not conversation_id:
|
|
250
339
|
raise ValueError("CopilotClient.subscribe: conversation_id cannot be None")
|
|
251
340
|
|
|
252
|
-
|
|
253
|
-
url = PowerPlatformEnvironment.get_copilot_studio_connection_url(
|
|
254
|
-
settings=self.settings,
|
|
255
|
-
conversation_id=conversation_id,
|
|
256
|
-
create_subscribe_link=True,
|
|
257
|
-
)
|
|
341
|
+
url = await self._resolve_connection_url(conversation_id, subscribe=True)
|
|
258
342
|
headers = {
|
|
259
343
|
"Content-Type": self.APPLICATION_JSON_TYPE,
|
|
260
344
|
"Authorization": f"Bearer {self._token}",
|
|
@@ -52,6 +52,31 @@ class CopilotStudioErrorResources:
|
|
|
52
52
|
-65006,
|
|
53
53
|
)
|
|
54
54
|
|
|
55
|
+
InvalidDiscoveryResponse = ErrorMessage(
|
|
56
|
+
"Conversation endpoint discovery returned an invalid JSON object.",
|
|
57
|
+
-65007,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
InvalidDiscoveryOperationUrl = ErrorMessage(
|
|
61
|
+
"Conversation endpoint discovery returned an invalid operation URL.",
|
|
62
|
+
-65008,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
DiscoveryConversationIdRequired = ErrorMessage(
|
|
66
|
+
"A conversation ID is required for this operation.",
|
|
67
|
+
-65009,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
DiscoverySubscribeNotSupported = ErrorMessage(
|
|
71
|
+
"The agent does not advertise a subscribe endpoint.",
|
|
72
|
+
-65010,
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
DiscoveryAccessTokenRequired = ErrorMessage(
|
|
76
|
+
"A non-empty access token is required for conversation endpoint discovery.",
|
|
77
|
+
-65011,
|
|
78
|
+
)
|
|
79
|
+
|
|
55
80
|
def __init__(self):
|
|
56
81
|
"""Initialize CopilotStudioErrorResources."""
|
|
57
82
|
pass
|
|
@@ -322,6 +322,7 @@ class PowerPlatformEnvironment:
|
|
|
322
322
|
if cloud == PowerPlatformCloud.OTHER and not cloud_base_address:
|
|
323
323
|
raise ValueError(str(copilot_studio_errors.CloudBaseAddressRequired))
|
|
324
324
|
cloud_base_address = cloud_base_address or "api.unknown.powerplatform.com"
|
|
325
|
+
cloud_base_address = urlparse(cloud_base_address).netloc or cloud_base_address
|
|
325
326
|
normalized_resource_id = environment_id.lower().replace("-", "")
|
|
326
327
|
id_suffix_length = PowerPlatformEnvironment.get_id_suffix_length(cloud)
|
|
327
328
|
hex_prefix = normalized_resource_id[:-id_suffix_length]
|
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: microsoft-agents-copilotstudio-client
|
|
3
|
+
Version: 1.9.0.dev10
|
|
4
|
+
Summary: A client 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-hosting-core==1.9.0.dev10
|
|
19
|
+
Dynamic: license-file
|
|
20
|
+
Dynamic: requires-dist
|
|
21
|
+
|
|
1
22
|
# Microsoft Agents Copilot Studio Client
|
|
2
23
|
|
|
3
24
|
[](https://pypi.org/project/microsoft-agents-copilotstudio-client/)
|
|
@@ -209,6 +230,28 @@ def create_client():
|
|
|
209
230
|
return copilot_client
|
|
210
231
|
```
|
|
211
232
|
|
|
233
|
+
#### Conversation Endpoint Discovery
|
|
234
|
+
|
|
235
|
+
For published agents without a `direct_connect_url`, the client first sends an
|
|
236
|
+
authenticated `GET` to
|
|
237
|
+
`https://<environment-host>/copilotstudio/agents/<escaped-schema-name>/conversation-endpoints`.
|
|
238
|
+
The host is selected from the configured environment and cloud. Discovery uses the
|
|
239
|
+
client's bearer token and the configured `client_session_settings`.
|
|
240
|
+
|
|
241
|
+
The client validates all advertised endpoints before storing them and uses each
|
|
242
|
+
operation URL as returned, preserving its query string and escaping conversation
|
|
243
|
+
IDs when substituting `{conversationId}`. `createConversation`, `executeTurn`, and
|
|
244
|
+
`continueTurn` are required; `subscribe` is optional and subscription fails
|
|
245
|
+
explicitly when the agent does not advertise it. The client has no continue-turn
|
|
246
|
+
operation.
|
|
247
|
+
|
|
248
|
+
Successful discovery is reused for the lifetime of the client, with concurrent
|
|
249
|
+
calls coordinated to avoid duplicate initialization. Failures and cancellation
|
|
250
|
+
allow a later call to retry. The discovered create URL is written to
|
|
251
|
+
`settings.direct_connect_url`; clearing that value triggers discovery again.
|
|
252
|
+
Assigning a different explicit URL switches back to legacy direct-URL routing.
|
|
253
|
+
Explicit direct URLs and prebuilt agents bypass discovery entirely.
|
|
254
|
+
|
|
212
255
|
#### DirectConnect URL Mode (Simplified Setup)
|
|
213
256
|
|
|
214
257
|
For simplified setup, you can use a DirectConnect URL instead of environment-based configuration:
|
|
@@ -555,4 +598,4 @@ audience = PowerPlatformEnvironment.get_token_audience(
|
|
|
555
598
|
|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)|
|
|
556
599
|
|Streaming Agent|Streams OpenAI responses|[azure-ai-streaming](https://github.com/microsoft/Agents/blob/main/samples/python/azureai-streaming/README.md)|
|
|
557
600
|
|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)|
|
|
558
|
-
|Cards Agent|Agent that uses rich cards to enhance conversation design |[cards](https://github.com/microsoft/Agents/blob/main/samples/python/cards/README.md)|
|
|
601
|
+
|Cards Agent|Agent that uses rich cards to enhance conversation design |[cards](https://github.com/microsoft/Agents/blob/main/samples/python/cards/README.md)|
|
|
@@ -5,6 +5,7 @@ pyproject.toml
|
|
|
5
5
|
readme.md
|
|
6
6
|
setup.py
|
|
7
7
|
microsoft_agents/copilotstudio/client/__init__.py
|
|
8
|
+
microsoft_agents/copilotstudio/client/_conversation_endpoint_discovery.py
|
|
8
9
|
microsoft_agents/copilotstudio/client/agent_type.py
|
|
9
10
|
microsoft_agents/copilotstudio/client/connection_settings.py
|
|
10
11
|
microsoft_agents/copilotstudio/client/copilot_client.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
microsoft-agents-hosting-core==1.9.0.dev10
|
|
@@ -1,24 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: microsoft-agents-copilotstudio-client
|
|
3
|
-
Version: 1.9.0.dev5
|
|
4
|
-
Summary: A client 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-hosting-core==1.9.0.dev5
|
|
19
|
-
Dynamic: license-file
|
|
20
|
-
Dynamic: requires-dist
|
|
21
|
-
|
|
22
1
|
# Microsoft Agents Copilot Studio Client
|
|
23
2
|
|
|
24
3
|
[](https://pypi.org/project/microsoft-agents-copilotstudio-client/)
|
|
@@ -230,6 +209,28 @@ def create_client():
|
|
|
230
209
|
return copilot_client
|
|
231
210
|
```
|
|
232
211
|
|
|
212
|
+
#### Conversation Endpoint Discovery
|
|
213
|
+
|
|
214
|
+
For published agents without a `direct_connect_url`, the client first sends an
|
|
215
|
+
authenticated `GET` to
|
|
216
|
+
`https://<environment-host>/copilotstudio/agents/<escaped-schema-name>/conversation-endpoints`.
|
|
217
|
+
The host is selected from the configured environment and cloud. Discovery uses the
|
|
218
|
+
client's bearer token and the configured `client_session_settings`.
|
|
219
|
+
|
|
220
|
+
The client validates all advertised endpoints before storing them and uses each
|
|
221
|
+
operation URL as returned, preserving its query string and escaping conversation
|
|
222
|
+
IDs when substituting `{conversationId}`. `createConversation`, `executeTurn`, and
|
|
223
|
+
`continueTurn` are required; `subscribe` is optional and subscription fails
|
|
224
|
+
explicitly when the agent does not advertise it. The client has no continue-turn
|
|
225
|
+
operation.
|
|
226
|
+
|
|
227
|
+
Successful discovery is reused for the lifetime of the client, with concurrent
|
|
228
|
+
calls coordinated to avoid duplicate initialization. Failures and cancellation
|
|
229
|
+
allow a later call to retry. The discovered create URL is written to
|
|
230
|
+
`settings.direct_connect_url`; clearing that value triggers discovery again.
|
|
231
|
+
Assigning a different explicit URL switches back to legacy direct-URL routing.
|
|
232
|
+
Explicit direct URLs and prebuilt agents bypass discovery entirely.
|
|
233
|
+
|
|
233
234
|
#### DirectConnect URL Mode (Simplified Setup)
|
|
234
235
|
|
|
235
236
|
For simplified setup, you can use a DirectConnect URL instead of environment-based configuration:
|
|
@@ -576,4 +577,4 @@ audience = PowerPlatformEnvironment.get_token_audience(
|
|
|
576
577
|
|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)|
|
|
577
578
|
|Streaming Agent|Streams OpenAI responses|[azure-ai-streaming](https://github.com/microsoft/Agents/blob/main/samples/python/azureai-streaming/README.md)|
|
|
578
579
|
|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)|
|
|
579
|
-
|Cards Agent|Agent that uses rich cards to enhance conversation design |[cards](https://github.com/microsoft/Agents/blob/main/samples/python/cards/README.md)|
|
|
580
|
+
|Cards Agent|Agent that uses rich cards to enhance conversation design |[cards](https://github.com/microsoft/Agents/blob/main/samples/python/cards/README.md)|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
1.9.0.dev5
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
microsoft-agents-hosting-core==1.9.0.dev5
|
|
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
|