agent-framework-copilotstudio 0.0.0a1__py3-none-any.whl → 1.0.0b251001__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.
Potentially problematic release.
This version of agent-framework-copilotstudio might be problematic. Click here for more details.
- agent_framework_copilotstudio/__init__.py +13 -0
- agent_framework_copilotstudio/_acquire_token.py +94 -0
- agent_framework_copilotstudio/_agent.py +318 -0
- agent_framework_copilotstudio-1.0.0b251001.dist-info/METADATA +122 -0
- agent_framework_copilotstudio-1.0.0b251001.dist-info/RECORD +7 -0
- agent_framework/__init__.py +0 -0
- agent_framework/copilotstudio/__init__.py +0 -2
- agent_framework_copilotstudio-0.0.0a1.dist-info/METADATA +0 -10
- agent_framework_copilotstudio-0.0.0a1.dist-info/RECORD +0 -6
- {agent_framework_copilotstudio-0.0.0a1.dist-info → agent_framework_copilotstudio-1.0.0b251001.dist-info}/WHEEL +0 -0
- {agent_framework_copilotstudio-0.0.0a1.dist-info → agent_framework_copilotstudio-1.0.0b251001.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Copyright (c) Microsoft. All rights reserved.
|
|
2
|
+
|
|
3
|
+
import importlib.metadata
|
|
4
|
+
|
|
5
|
+
from ._acquire_token import acquire_token
|
|
6
|
+
from ._agent import CopilotStudioAgent
|
|
7
|
+
|
|
8
|
+
try:
|
|
9
|
+
__version__ = importlib.metadata.version(__name__)
|
|
10
|
+
except importlib.metadata.PackageNotFoundError:
|
|
11
|
+
__version__ = "0.0.0" # Fallback for development mode
|
|
12
|
+
|
|
13
|
+
__all__ = ["CopilotStudioAgent", "__version__", "acquire_token"]
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Copyright (c) Microsoft. All rights reserved.
|
|
2
|
+
# pyright: reportUnknownMemberType = false
|
|
3
|
+
# pyright: reportUnknownVariableType = false
|
|
4
|
+
# pyright: reportUnknownArgumentType = false
|
|
5
|
+
|
|
6
|
+
import logging
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from agent_framework.exceptions import ServiceException
|
|
10
|
+
from msal import PublicClientApplication
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
# Default scopes for Power Platform API
|
|
15
|
+
DEFAULT_SCOPES = ["https://api.powerplatform.com/.default"]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def acquire_token(
|
|
19
|
+
client_id: str,
|
|
20
|
+
tenant_id: str,
|
|
21
|
+
username: str | None = None,
|
|
22
|
+
token_cache: Any | None = None,
|
|
23
|
+
scopes: list[str] | None = None,
|
|
24
|
+
) -> str:
|
|
25
|
+
"""Acquire an authentication token using MSAL Public Client Application.
|
|
26
|
+
|
|
27
|
+
This function attempts to acquire a token silently first (using cached tokens),
|
|
28
|
+
and falls back to interactive authentication if needed.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
client_id: The client ID of the application.
|
|
32
|
+
tenant_id: The tenant ID for authentication.
|
|
33
|
+
username: Optional username to filter accounts.
|
|
34
|
+
token_cache: Optional token cache for storing tokens.
|
|
35
|
+
scopes: Optional list of scopes. Defaults to Power Platform API scopes.
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
The access token string.
|
|
39
|
+
|
|
40
|
+
Raises:
|
|
41
|
+
ServiceException: If authentication token cannot be acquired.
|
|
42
|
+
"""
|
|
43
|
+
if not client_id:
|
|
44
|
+
raise ServiceException("Client ID is required for token acquisition.")
|
|
45
|
+
|
|
46
|
+
if not tenant_id:
|
|
47
|
+
raise ServiceException("Tenant ID is required for token acquisition.")
|
|
48
|
+
|
|
49
|
+
authority = f"https://login.microsoftonline.com/{tenant_id}"
|
|
50
|
+
target_scopes = scopes or DEFAULT_SCOPES
|
|
51
|
+
|
|
52
|
+
pca = PublicClientApplication(client_id=client_id, authority=authority, token_cache=token_cache)
|
|
53
|
+
|
|
54
|
+
accounts = pca.get_accounts(username=username)
|
|
55
|
+
|
|
56
|
+
token: str | None = None
|
|
57
|
+
|
|
58
|
+
# Try silent token acquisition first if we have cached accounts
|
|
59
|
+
if accounts:
|
|
60
|
+
try:
|
|
61
|
+
logger.debug("Attempting silent token acquisition")
|
|
62
|
+
response = pca.acquire_token_silent(scopes=target_scopes, account=accounts[0])
|
|
63
|
+
if response and "access_token" in response:
|
|
64
|
+
token = str(response["access_token"]) # type: ignore[assignment]
|
|
65
|
+
logger.debug("Successfully acquired token silently")
|
|
66
|
+
elif response and "error" in response:
|
|
67
|
+
logger.warning(
|
|
68
|
+
"Silent token acquisition failed: %s - %s", response.get("error"), response.get("error_description")
|
|
69
|
+
)
|
|
70
|
+
except Exception as ex:
|
|
71
|
+
logger.warning("Silent token acquisition failed with exception: %s", ex)
|
|
72
|
+
|
|
73
|
+
# Fall back to interactive authentication if silent acquisition failed
|
|
74
|
+
if not token:
|
|
75
|
+
try:
|
|
76
|
+
logger.debug("Attempting interactive token acquisition")
|
|
77
|
+
response = pca.acquire_token_interactive(scopes=target_scopes)
|
|
78
|
+
if response and "access_token" in response:
|
|
79
|
+
token = str(response["access_token"]) # type: ignore[assignment]
|
|
80
|
+
logger.debug("Successfully acquired token interactively")
|
|
81
|
+
elif response and "error" in response:
|
|
82
|
+
logger.error(
|
|
83
|
+
"Interactive token acquisition failed: %s - %s",
|
|
84
|
+
response.get("error"),
|
|
85
|
+
response.get("error_description"),
|
|
86
|
+
)
|
|
87
|
+
except Exception as ex:
|
|
88
|
+
logger.error("Interactive token acquisition failed with exception: %s", ex)
|
|
89
|
+
raise ServiceException(f"Failed to acquire authentication token: {ex}") from ex
|
|
90
|
+
|
|
91
|
+
if not token:
|
|
92
|
+
raise ServiceException("Authentication token cannot be acquired.")
|
|
93
|
+
|
|
94
|
+
return token
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
# Copyright (c) Microsoft. All rights reserved.
|
|
2
|
+
|
|
3
|
+
from collections.abc import AsyncIterable
|
|
4
|
+
from typing import Any, ClassVar
|
|
5
|
+
|
|
6
|
+
from agent_framework import (
|
|
7
|
+
AgentMiddlewares,
|
|
8
|
+
AgentRunResponse,
|
|
9
|
+
AgentRunResponseUpdate,
|
|
10
|
+
AgentThread,
|
|
11
|
+
AggregateContextProvider,
|
|
12
|
+
BaseAgent,
|
|
13
|
+
ChatMessage,
|
|
14
|
+
ContextProvider,
|
|
15
|
+
Role,
|
|
16
|
+
TextContent,
|
|
17
|
+
)
|
|
18
|
+
from agent_framework._pydantic import AFBaseSettings
|
|
19
|
+
from agent_framework.exceptions import ServiceException, ServiceInitializationError
|
|
20
|
+
from microsoft_agents.copilotstudio.client import AgentType, ConnectionSettings, CopilotClient, PowerPlatformCloud
|
|
21
|
+
from pydantic import ValidationError
|
|
22
|
+
|
|
23
|
+
from ._acquire_token import acquire_token
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class CopilotStudioSettings(AFBaseSettings):
|
|
27
|
+
"""Copilot Studio model settings.
|
|
28
|
+
|
|
29
|
+
The settings are first loaded from environment variables with the prefix 'COPILOTSTUDIOAGENT__'.
|
|
30
|
+
If the environment variables are not found, the settings can be loaded from a .env file
|
|
31
|
+
with the encoding 'utf-8'. If the settings are not found in the .env file, the settings
|
|
32
|
+
are ignored; however, validation will fail alerting that the settings are missing.
|
|
33
|
+
|
|
34
|
+
Attributes:
|
|
35
|
+
environmentid: Environment ID of environment with the Copilot Studio App..
|
|
36
|
+
(Env var COPILOTSTUDIOAGENT__ENVIRONMENTID)
|
|
37
|
+
schemaname: The agent identifier or schema name of the Copilot to use.
|
|
38
|
+
(Env var COPILOTSTUDIOAGENT__SCHEMANAME)
|
|
39
|
+
agentappid: The app ID of the App Registration used to login.
|
|
40
|
+
(Env var COPILOTSTUDIOAGENT__AGENTAPPID)
|
|
41
|
+
tenantid: The tenant ID of the App Registration used to login.
|
|
42
|
+
(Env var COPILOTSTUDIOAGENT__TENANTID)
|
|
43
|
+
Parameters:
|
|
44
|
+
env_file_path: If provided, the .env settings are read from this file path location.
|
|
45
|
+
env_file_encoding: The encoding of the .env file, defaults to 'utf-8'.
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
env_prefix: ClassVar[str] = "COPILOTSTUDIOAGENT__"
|
|
49
|
+
|
|
50
|
+
environmentid: str | None = None
|
|
51
|
+
schemaname: str | None = None
|
|
52
|
+
agentappid: str | None = None
|
|
53
|
+
tenantid: str | None = None
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class CopilotStudioAgent(BaseAgent):
|
|
57
|
+
"""A Copilot Studio Agent."""
|
|
58
|
+
|
|
59
|
+
def __init__(
|
|
60
|
+
self,
|
|
61
|
+
client: CopilotClient | None = None,
|
|
62
|
+
settings: ConnectionSettings | None = None,
|
|
63
|
+
*,
|
|
64
|
+
id: str | None = None,
|
|
65
|
+
name: str | None = None,
|
|
66
|
+
description: str | None = None,
|
|
67
|
+
context_providers: ContextProvider | list[ContextProvider] | AggregateContextProvider | None = None,
|
|
68
|
+
middleware: AgentMiddlewares | list[AgentMiddlewares] | None = None,
|
|
69
|
+
environment_id: str | None = None,
|
|
70
|
+
agent_identifier: str | None = None,
|
|
71
|
+
client_id: str | None = None,
|
|
72
|
+
tenant_id: str | None = None,
|
|
73
|
+
token: str | None = None,
|
|
74
|
+
cloud: PowerPlatformCloud | None = None,
|
|
75
|
+
agent_type: AgentType | None = None,
|
|
76
|
+
custom_power_platform_cloud: str | None = None,
|
|
77
|
+
username: str | None = None,
|
|
78
|
+
token_cache: Any | None = None,
|
|
79
|
+
scopes: list[str] | None = None,
|
|
80
|
+
env_file_path: str | None = None,
|
|
81
|
+
env_file_encoding: str | None = None,
|
|
82
|
+
) -> None:
|
|
83
|
+
"""Initialize the Copilot Studio Agent.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
client: Optional pre-configured CopilotClient instance. If not provided,
|
|
87
|
+
a new client will be created using the other parameters.
|
|
88
|
+
settings: Optional pre-configured ConnectionSettings. If not provided,
|
|
89
|
+
settings will be created from the other parameters.
|
|
90
|
+
id: id of the CopilotAgent
|
|
91
|
+
name: Name of the CopilotAgent
|
|
92
|
+
description: Description of the CopilotAgent
|
|
93
|
+
context_providers: Context Providers, to be used by the copilot agent.
|
|
94
|
+
middleware: Agent middlewares used by the agent.
|
|
95
|
+
environment_id: Environment ID of the Power Platform environment containing
|
|
96
|
+
the Copilot Studio app. Can also be set via COPILOTSTUDIOAGENT__ENVIRONMENTID
|
|
97
|
+
environment variable.
|
|
98
|
+
agent_identifier: The agent identifier or schema name of the Copilot to use.
|
|
99
|
+
Can also be set via COPILOTSTUDIOAGENT__SCHEMANAME environment variable.
|
|
100
|
+
client_id: The app ID of the App Registration used for authentication.
|
|
101
|
+
Can also be set via COPILOTSTUDIOAGENT__AGENTAPPID environment variable.
|
|
102
|
+
tenant_id: The tenant ID of the App Registration used for authentication.
|
|
103
|
+
Can also be set via COPILOTSTUDIOAGENT__TENANTID environment variable.
|
|
104
|
+
token: Optional pre-acquired authentication token. If not provided,
|
|
105
|
+
token acquisition will be attempted using MSAL.
|
|
106
|
+
cloud: The Power Platform cloud to use (Public, GCC, etc.).
|
|
107
|
+
agent_type: The type of Copilot Studio agent (Copilot, Agent, etc.).
|
|
108
|
+
custom_power_platform_cloud: Custom Power Platform cloud URL if using
|
|
109
|
+
a custom environment.
|
|
110
|
+
username: Optional username for token acquisition.
|
|
111
|
+
token_cache: Optional token cache for storing authentication tokens.
|
|
112
|
+
scopes: Optional list of authentication scopes. Defaults to Power Platform
|
|
113
|
+
API scopes if not provided.
|
|
114
|
+
env_file_path: Optional path to .env file for loading configuration.
|
|
115
|
+
env_file_encoding: Encoding of the .env file, defaults to 'utf-8'.
|
|
116
|
+
|
|
117
|
+
Raises:
|
|
118
|
+
ServiceInitializationError: If required configuration is missing or invalid.
|
|
119
|
+
"""
|
|
120
|
+
super().__init__(
|
|
121
|
+
id=id,
|
|
122
|
+
name=name,
|
|
123
|
+
description=description,
|
|
124
|
+
context_providers=context_providers,
|
|
125
|
+
middleware=middleware,
|
|
126
|
+
)
|
|
127
|
+
if not client:
|
|
128
|
+
try:
|
|
129
|
+
copilot_studio_settings = CopilotStudioSettings(
|
|
130
|
+
environmentid=environment_id,
|
|
131
|
+
schemaname=agent_identifier,
|
|
132
|
+
agentappid=client_id,
|
|
133
|
+
tenantid=tenant_id,
|
|
134
|
+
env_file_path=env_file_path,
|
|
135
|
+
env_file_encoding=env_file_encoding,
|
|
136
|
+
)
|
|
137
|
+
except ValidationError as ex:
|
|
138
|
+
raise ServiceInitializationError("Failed to create Copilot Studio settings.", ex) from ex
|
|
139
|
+
|
|
140
|
+
if not settings:
|
|
141
|
+
if not copilot_studio_settings.environmentid:
|
|
142
|
+
raise ServiceInitializationError(
|
|
143
|
+
"Copilot Studio environment ID is required. Set via 'environment_id' parameter "
|
|
144
|
+
"or 'COPILOTSTUDIOAGENT__ENVIRONMENTID' environment variable."
|
|
145
|
+
)
|
|
146
|
+
if not copilot_studio_settings.schemaname:
|
|
147
|
+
raise ServiceInitializationError(
|
|
148
|
+
"Copilot Studio agent identifier/schema name is required. Set via 'agent_identifier' parameter "
|
|
149
|
+
"or 'COPILOTSTUDIOAGENT__SCHEMANAME' environment variable."
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
settings = ConnectionSettings(
|
|
153
|
+
environment_id=copilot_studio_settings.environmentid,
|
|
154
|
+
agent_identifier=copilot_studio_settings.schemaname,
|
|
155
|
+
cloud=cloud,
|
|
156
|
+
copilot_agent_type=agent_type,
|
|
157
|
+
custom_power_platform_cloud=custom_power_platform_cloud,
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
if not token:
|
|
161
|
+
if not copilot_studio_settings.agentappid:
|
|
162
|
+
raise ServiceInitializationError(
|
|
163
|
+
"Copilot Studio client ID is required. Set via 'client_id' parameter "
|
|
164
|
+
"or 'COPILOTSTUDIOAGENT__AGENTAPPID' environment variable."
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
if not copilot_studio_settings.tenantid:
|
|
168
|
+
raise ServiceInitializationError(
|
|
169
|
+
"Copilot Studio tenant ID is required. Set via 'tenant_id' parameter "
|
|
170
|
+
"or 'COPILOTSTUDIOAGENT__TENANTID' environment variable."
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
token = acquire_token(
|
|
174
|
+
client_id=copilot_studio_settings.agentappid,
|
|
175
|
+
tenant_id=copilot_studio_settings.tenantid,
|
|
176
|
+
username=username,
|
|
177
|
+
token_cache=token_cache,
|
|
178
|
+
scopes=scopes,
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
client = CopilotClient(settings=settings, token=token)
|
|
182
|
+
|
|
183
|
+
self.client = client
|
|
184
|
+
self.cloud = cloud
|
|
185
|
+
self.agent_type = agent_type
|
|
186
|
+
self.custom_power_platform_cloud = custom_power_platform_cloud
|
|
187
|
+
self.username = username
|
|
188
|
+
self.token_cache = token_cache
|
|
189
|
+
self.scopes = scopes
|
|
190
|
+
|
|
191
|
+
async def run(
|
|
192
|
+
self,
|
|
193
|
+
messages: str | ChatMessage | list[str] | list[ChatMessage] | None = None,
|
|
194
|
+
*,
|
|
195
|
+
thread: AgentThread | None = None,
|
|
196
|
+
**kwargs: Any,
|
|
197
|
+
) -> AgentRunResponse:
|
|
198
|
+
"""Get a response from the agent.
|
|
199
|
+
|
|
200
|
+
This method returns the final result of the agent's execution
|
|
201
|
+
as a single AgentRunResponse object. The caller is blocked until
|
|
202
|
+
the final result is available.
|
|
203
|
+
|
|
204
|
+
Note: For streaming responses, use the run_stream method, which returns
|
|
205
|
+
intermediate steps and the final result as a stream of AgentRunResponseUpdate
|
|
206
|
+
objects. Streaming only the final result is not feasible because the timing of
|
|
207
|
+
the final result's availability is unknown, and blocking the caller until then
|
|
208
|
+
is undesirable in streaming scenarios.
|
|
209
|
+
|
|
210
|
+
Args:
|
|
211
|
+
messages: The message(s) to send to the agent.
|
|
212
|
+
thread: The conversation thread associated with the message(s).
|
|
213
|
+
kwargs: Additional keyword arguments.
|
|
214
|
+
|
|
215
|
+
Returns:
|
|
216
|
+
An agent response item.
|
|
217
|
+
"""
|
|
218
|
+
if not thread:
|
|
219
|
+
thread = self.get_new_thread()
|
|
220
|
+
thread.service_thread_id = await self._start_new_conversation()
|
|
221
|
+
|
|
222
|
+
input_messages = self._normalize_messages(messages)
|
|
223
|
+
|
|
224
|
+
question = "\n".join([message.text for message in input_messages])
|
|
225
|
+
|
|
226
|
+
activities = self.client.ask_question(question, thread.service_thread_id)
|
|
227
|
+
response_messages: list[ChatMessage] = []
|
|
228
|
+
response_id: str | None = None
|
|
229
|
+
|
|
230
|
+
response_messages = [message async for message in self._process_activities(activities, streaming=False)]
|
|
231
|
+
response_id = response_messages[0].message_id if response_messages else None
|
|
232
|
+
|
|
233
|
+
return AgentRunResponse(messages=response_messages, response_id=response_id)
|
|
234
|
+
|
|
235
|
+
async def run_stream(
|
|
236
|
+
self,
|
|
237
|
+
messages: str | ChatMessage | list[str] | list[ChatMessage] | None = None,
|
|
238
|
+
*,
|
|
239
|
+
thread: AgentThread | None = None,
|
|
240
|
+
**kwargs: Any,
|
|
241
|
+
) -> AsyncIterable[AgentRunResponseUpdate]:
|
|
242
|
+
"""Run the agent as a stream.
|
|
243
|
+
|
|
244
|
+
This method will return the intermediate steps and final results of the
|
|
245
|
+
agent's execution as a stream of AgentRunResponseUpdate objects to the caller.
|
|
246
|
+
|
|
247
|
+
Note: An AgentRunResponseUpdate object contains a chunk of a message.
|
|
248
|
+
|
|
249
|
+
Args:
|
|
250
|
+
messages: The message(s) to send to the agent.
|
|
251
|
+
thread: The conversation thread associated with the message(s).
|
|
252
|
+
kwargs: Additional keyword arguments.
|
|
253
|
+
|
|
254
|
+
Yields:
|
|
255
|
+
An agent response item.
|
|
256
|
+
"""
|
|
257
|
+
if not thread:
|
|
258
|
+
thread = self.get_new_thread()
|
|
259
|
+
thread.service_thread_id = await self._start_new_conversation()
|
|
260
|
+
|
|
261
|
+
input_messages = self._normalize_messages(messages)
|
|
262
|
+
|
|
263
|
+
question = "\n".join([message.text for message in input_messages])
|
|
264
|
+
|
|
265
|
+
activities = self.client.ask_question(question, thread.service_thread_id)
|
|
266
|
+
|
|
267
|
+
async for message in self._process_activities(activities, streaming=True):
|
|
268
|
+
yield AgentRunResponseUpdate(
|
|
269
|
+
role=message.role,
|
|
270
|
+
contents=message.contents,
|
|
271
|
+
author_name=message.author_name,
|
|
272
|
+
raw_representation=message.raw_representation,
|
|
273
|
+
response_id=message.message_id,
|
|
274
|
+
message_id=message.message_id,
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
async def _start_new_conversation(self) -> str:
|
|
278
|
+
"""Start a new conversation with the Copilot Studio agent.
|
|
279
|
+
|
|
280
|
+
Returns:
|
|
281
|
+
The conversation ID for the new conversation.
|
|
282
|
+
|
|
283
|
+
Raises:
|
|
284
|
+
ServiceException: If the conversation could not be started.
|
|
285
|
+
"""
|
|
286
|
+
conversation_id: str | None = None
|
|
287
|
+
|
|
288
|
+
async for activity in self.client.start_conversation(emit_start_conversation_event=True):
|
|
289
|
+
if activity and activity.conversation and activity.conversation.id:
|
|
290
|
+
conversation_id = activity.conversation.id
|
|
291
|
+
|
|
292
|
+
if not conversation_id:
|
|
293
|
+
raise ServiceException("Failed to start a new conversation.")
|
|
294
|
+
|
|
295
|
+
return conversation_id
|
|
296
|
+
|
|
297
|
+
async def _process_activities(self, activities: AsyncIterable[Any], streaming: bool) -> AsyncIterable[ChatMessage]:
|
|
298
|
+
"""Process activities from the Copilot Studio agent.
|
|
299
|
+
|
|
300
|
+
Args:
|
|
301
|
+
activities: Stream of activities from the agent.
|
|
302
|
+
streaming: Whether to process activities for streaming (typing activities)
|
|
303
|
+
or non-streaming (message activities) responses.
|
|
304
|
+
|
|
305
|
+
Yields:
|
|
306
|
+
ChatMessage objects created from the activities.
|
|
307
|
+
"""
|
|
308
|
+
async for activity in activities:
|
|
309
|
+
if activity.text and (
|
|
310
|
+
(activity.type == "message" and not streaming) or (activity.type == "typing" and streaming)
|
|
311
|
+
):
|
|
312
|
+
yield ChatMessage(
|
|
313
|
+
role=Role.ASSISTANT,
|
|
314
|
+
contents=[TextContent(activity.text)],
|
|
315
|
+
author_name=activity.from_property.name if activity.from_property else None,
|
|
316
|
+
message_id=activity.id,
|
|
317
|
+
raw_representation=activity,
|
|
318
|
+
)
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agent-framework-copilotstudio
|
|
3
|
+
Version: 1.0.0b251001
|
|
4
|
+
Summary: Copilot Studio integration for Microsoft Agent Framework.
|
|
5
|
+
Author-email: Microsoft <af-support@microsoft.com>
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Typing :: Typed
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: agent-framework-core
|
|
19
|
+
Requires-Dist: microsoft-agents-copilotstudio-client>=0.3.1
|
|
20
|
+
Project-URL: homepage, https://aka.ms/agent-framework
|
|
21
|
+
Project-URL: issues, https://github.com/microsoft/agent-framework/issues
|
|
22
|
+
Project-URL: release_notes, https://github.com/microsoft/agent-framework/releases?q=tag%3Apython-1&expanded=true
|
|
23
|
+
Project-URL: source, https://github.com/microsoft/agent-framework/tree/main/python
|
|
24
|
+
|
|
25
|
+
# Get Started with Microsoft Agent Framework Copilot Studio
|
|
26
|
+
|
|
27
|
+
Please install this package via pip:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pip install agent-framework-copilotstudio
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Copilot Studio Agent
|
|
34
|
+
|
|
35
|
+
The Copilot Studio agent enables integration with Microsoft Copilot Studio, allowing you to interact with published copilots through the Agent Framework.
|
|
36
|
+
|
|
37
|
+
### Prerequisites
|
|
38
|
+
|
|
39
|
+
Before using the Copilot Studio agent, you need:
|
|
40
|
+
|
|
41
|
+
1. **Copilot Studio Environment**: Access to a Microsoft Copilot Studio environment with a published copilot
|
|
42
|
+
2. **App Registration**: An Azure AD App Registration with appropriate permissions for Power Platform API
|
|
43
|
+
3. **Environment Configuration**: Set the required environment variables or pass them as parameters
|
|
44
|
+
|
|
45
|
+
### Environment Variables
|
|
46
|
+
|
|
47
|
+
The following environment variables are used for configuration:
|
|
48
|
+
|
|
49
|
+
- `COPILOTSTUDIOAGENT__ENVIRONMENTID` - Your Copilot Studio environment ID
|
|
50
|
+
- `COPILOTSTUDIOAGENT__SCHEMANAME` - Your copilot's agent identifier/schema name
|
|
51
|
+
- `COPILOTSTUDIOAGENT__AGENTAPPID` - Your App Registration client ID
|
|
52
|
+
- `COPILOTSTUDIOAGENT__TENANTID` - Your Azure AD tenant ID
|
|
53
|
+
|
|
54
|
+
### Basic Usage Example
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
import asyncio
|
|
58
|
+
from agent_framework.microsoft import CopilotStudioAgent
|
|
59
|
+
|
|
60
|
+
async def main():
|
|
61
|
+
# Create agent using environment variables
|
|
62
|
+
agent = CopilotStudioAgent()
|
|
63
|
+
|
|
64
|
+
# Run a simple query
|
|
65
|
+
result = await agent.run("What is the capital of France?")
|
|
66
|
+
print(result)
|
|
67
|
+
|
|
68
|
+
asyncio.run(main())
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Explicit Configuration Example
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
import asyncio
|
|
75
|
+
import os
|
|
76
|
+
from agent_framework.microsoft import CopilotStudioAgent, acquire_token
|
|
77
|
+
from microsoft_agents.copilotstudio.client import ConnectionSettings, CopilotClient, PowerPlatformCloud, AgentType
|
|
78
|
+
|
|
79
|
+
async def main():
|
|
80
|
+
# Acquire authentication token
|
|
81
|
+
token = acquire_token(
|
|
82
|
+
client_id=os.environ["COPILOTSTUDIOAGENT__AGENTAPPID"],
|
|
83
|
+
tenant_id=os.environ["COPILOTSTUDIOAGENT__TENANTID"]
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
# Create connection settings
|
|
87
|
+
settings = ConnectionSettings(
|
|
88
|
+
environment_id=os.environ["COPILOTSTUDIOAGENT__ENVIRONMENTID"],
|
|
89
|
+
agent_identifier=os.environ["COPILOTSTUDIOAGENT__SCHEMANAME"],
|
|
90
|
+
cloud=PowerPlatformCloud.PROD,
|
|
91
|
+
copilot_agent_type=AgentType.PUBLISHED,
|
|
92
|
+
custom_power_platform_cloud=None
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
# Create client and agent
|
|
96
|
+
client = CopilotClient(settings=settings, token=token)
|
|
97
|
+
agent = CopilotStudioAgent(client=client)
|
|
98
|
+
|
|
99
|
+
# Run a query
|
|
100
|
+
result = await agent.run("What is the capital of Italy?")
|
|
101
|
+
print(result)
|
|
102
|
+
|
|
103
|
+
asyncio.run(main())
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Authentication
|
|
107
|
+
|
|
108
|
+
The package uses MSAL (Microsoft Authentication Library) for authentication with interactive flows when needed. Ensure your App Registration has:
|
|
109
|
+
|
|
110
|
+
- **API Permissions**: Power Platform API permissions (https://api.powerplatform.com/.default)
|
|
111
|
+
- **Redirect URIs**: Configured appropriately for your authentication method
|
|
112
|
+
- **Public Client Flows**: Enabled if using interactive authentication
|
|
113
|
+
|
|
114
|
+
### Examples
|
|
115
|
+
|
|
116
|
+
For more comprehensive examples, see the [Copilot Studio examples](https://github.com/microsoft/agent-framework/tree/main/python/samples/getting_started/agents/copilotstudio/) which demonstrate:
|
|
117
|
+
|
|
118
|
+
- Basic non-streaming and streaming execution
|
|
119
|
+
- Explicit settings and manual token acquisition
|
|
120
|
+
- Different authentication patterns
|
|
121
|
+
- Error handling and troubleshooting
|
|
122
|
+
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
agent_framework_copilotstudio/__init__.py,sha256=n5OgoxpgvDY7Ttcgjcd0UG55d2fDmtWt6NmgvxYQOaU,391
|
|
2
|
+
agent_framework_copilotstudio/_acquire_token.py,sha256=4g92MsaKbs7oPko7eXWFCYcph2HiufjoYAZJ9IqJb7A,3660
|
|
3
|
+
agent_framework_copilotstudio/_agent.py,sha256=vtjGx0JH2FEzL5hsACk-Jd3nRfep65fQib8TBKDTGfo,13808
|
|
4
|
+
agent_framework_copilotstudio-1.0.0b251001.dist-info/licenses/LICENSE,sha256=ws_MuBL-SCEBqPBFl9_FqZkaaydIJmxHrJG2parhU4M,1141
|
|
5
|
+
agent_framework_copilotstudio-1.0.0b251001.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
|
|
6
|
+
agent_framework_copilotstudio-1.0.0b251001.dist-info/METADATA,sha256=tK0NES_3t-rjXNS-Vw2bsuu61EuqEDCfhq0pedUhGCE,4424
|
|
7
|
+
agent_framework_copilotstudio-1.0.0b251001.dist-info/RECORD,,
|
agent_framework/__init__.py
DELETED
|
File without changes
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: agent-framework-copilotstudio
|
|
3
|
-
Version: 0.0.0a1
|
|
4
|
-
Summary: Microsoft Agent Framework Copilot Studio.
|
|
5
|
-
Author-email: Microsoft <af-support@microsoft.com>
|
|
6
|
-
Requires-Python: >=3.10
|
|
7
|
-
Description-Content-Type: text/markdown
|
|
8
|
-
License-File: LICENSE
|
|
9
|
-
|
|
10
|
-
# Microsoft Agent Framework
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
agent_framework/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
agent_framework/copilotstudio/__init__.py,sha256=2QmzeTK86ywELzkXAmeO5e3TReaUUO41BkP3PbPwoos,37
|
|
3
|
-
agent_framework_copilotstudio-0.0.0a1.dist-info/licenses/LICENSE,sha256=ws_MuBL-SCEBqPBFl9_FqZkaaydIJmxHrJG2parhU4M,1141
|
|
4
|
-
agent_framework_copilotstudio-0.0.0a1.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
|
|
5
|
-
agent_framework_copilotstudio-0.0.0a1.dist-info/METADATA,sha256=S4VvRk-wRyTJLMI3gP0766e5viPjE7rGKt9iU-nyLwo,292
|
|
6
|
-
agent_framework_copilotstudio-0.0.0a1.dist-info/RECORD,,
|
|
File without changes
|