chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
# Semantic Kernel - CopilotStudioAgent Quickstart
|
||||
|
||||
This README provides an overview on how to use the [CopilotStudioAgent](../../../semantic_kernel/agents/copilot_studio/copilot_studio_agent.py) within Semantic Kernel.
|
||||
This agent allows you to interact with Microsoft Copilot Studio agents through programmatic APIs.
|
||||
|
||||
> ℹ️ **Note:** Knowledge sources must be configured **within** Microsoft Copilot Studio first. Streaming responses are **not currently supported**.
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Prerequisites
|
||||
|
||||
1. Python 3.10+
|
||||
2. Install Semantic Kernel with Copilot Studio dependencies:
|
||||
```bash
|
||||
pip install semantic-kernel
|
||||
pip install microsoft-agents-hosting-core microsoft-agents-copilotstudio-client
|
||||
```
|
||||
3. An agent created in **Microsoft Copilot Studio**
|
||||
4. Ability to create an application identity in Azure for a **Public Client/Native App Registration**,
|
||||
or access to an existing app registration with the `CopilotStudio.Copilots.Invoke` API permission assigned.
|
||||
|
||||
## Create a Copilot Agent in Copilot Studio
|
||||
|
||||
1. Go to [Microsoft Copilot Studio](https://copilotstudio.microsoft.com).
|
||||
2. Create a new **Agent**.
|
||||
3. Publish your newly created Agent.
|
||||
4. In Copilot Studio, navigate to:
|
||||
`Settings` → `Advanced` → `Metadata`
|
||||
|
||||
Save the following values:
|
||||
- `Schema Name` (maps to `agent_identifier`)
|
||||
- `Environment ID`
|
||||
|
||||
## Create an Application Registration in Entra ID – User Interactive Login
|
||||
|
||||
> This step requires permissions to create application identities in your Azure tenant.
|
||||
|
||||
You will create a **Native Client Application Identity** (no client secret required).
|
||||
|
||||
1. Open [Azure Portal](https://portal.azure.com)
|
||||
2. Navigate to **Entra ID**
|
||||
3. Go to **App registrations** → **New registration**
|
||||
4. Fill out:
|
||||
- **Name**: Any name you like
|
||||
- **Supported account types**: `Accounts in this organization directory only`
|
||||
- **Redirect URI**:
|
||||
- Platform: `Public client/native (mobile & desktop)`
|
||||
- URI: `http://localhost`
|
||||
5. Click **Register**
|
||||
6. From the **Overview** page, note:
|
||||
- `Application (client) ID`
|
||||
- `Directory (tenant) ID`
|
||||
7. Go to: `Manage` → `API permissions`
|
||||
- Click **Add permission**
|
||||
- Choose **APIs my organization uses**
|
||||
- Search for: **Power Platform API**
|
||||
|
||||
If it's not listed, see **Tip** below.
|
||||
|
||||
8. Choose:
|
||||
- **Delegated Permissions**
|
||||
- Expand `CopilotStudio`
|
||||
- Select `CopilotStudio.Copilots.Invoke`
|
||||
9. Click **Add permissions**
|
||||
10. (Optional) Click **Grant admin consent**
|
||||
|
||||
### Tip
|
||||
|
||||
If you **do not see Power Platform API**, follow [Step 2 in Power Platform API Authentication](https://learn.microsoft.com/en-us/power-platform/admin/programmability-authentication-v2) to add the API to your tenant.
|
||||
|
||||
---
|
||||
|
||||
### Configure the Example Application - User Interactive Login
|
||||
|
||||
Once you've collected all required values:
|
||||
|
||||
1. Set the following environment variables in your terminal or .env file:
|
||||
|
||||
```env
|
||||
COPILOT_STUDIO_AGENT_APP_CLIENT_ID=<your-app-client-id>
|
||||
COPILOT_STUDIO_AGENT_TENANT_ID=<your-tenant-id>
|
||||
COPILOT_STUDIO_AGENT_ENVIRONMENT_ID=<your-env-id>
|
||||
COPILOT_STUDIO_AGENT_AGENT_IDENTIFIER=<your-agent-id>
|
||||
COPILOT_STUDIO_AGENT_AUTH_MODE=interactive
|
||||
```
|
||||
|
||||
## Create an Application Registration in Entra ID – Service Principal Login
|
||||
|
||||
> **Warning**: Service Principal login is **not yet supported** in the current version of the `CopilotStudioClient`.
|
||||
|
||||
## Creating a `CopilotStudioAgent` Client
|
||||
|
||||
If all required environment variables are set correctly, you don't need to manually create or pass a `client`. Semantic Kernel will automatically construct the client using the environment configuration.
|
||||
|
||||
However, if you need to override any environment variables—such as when specifying custom credentials or cloud settings—you should create the `client` explicitly using `CopilotStudioAgent.create_client(...)` and then pass it to the agent constructor.
|
||||
|
||||
```python
|
||||
client: CopilotClient = CopilotStudioAgent.create_client(
|
||||
auth_mode: CopilotStudioAgentAuthMode | Literal["interactive", "service"] | None = None,
|
||||
agent_identifier: str | None = None,
|
||||
app_client_id: str | None = None,
|
||||
client_secret: str | None = None,
|
||||
client_certificate: str | None = None,
|
||||
cloud: PowerPlatformCloud | None = None,
|
||||
copilot_agent_type: AgentType | None = None,
|
||||
custom_power_platform_cloud: str | None = None,
|
||||
env_file_encoding: str | None = None,
|
||||
env_file_path: str | None = None,
|
||||
environment_id: str | None = None,
|
||||
tenant_id: str | None = None,
|
||||
user_assertion: str | None = None,
|
||||
)
|
||||
|
||||
agent = CopilotStudioAgent(
|
||||
client=client,
|
||||
name="<name>",
|
||||
instructions="<instructions>",
|
||||
)
|
||||
```
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from semantic_kernel.agents import CopilotStudioAgent
|
||||
|
||||
"""
|
||||
This sample demonstrates how to use the Copilot Studio agent to answer questions about physics.
|
||||
It does not use a thread to maintain context between user inputs.
|
||||
"""
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
# 1. Create the agent
|
||||
agent = CopilotStudioAgent(
|
||||
name="PhysicsAgent",
|
||||
instructions="You help answer questions about physics. ",
|
||||
)
|
||||
|
||||
# 2. Create a list of user inputs
|
||||
USER_INPUTS = [
|
||||
"Why is the sky blue?",
|
||||
"What is the speed of light?",
|
||||
]
|
||||
|
||||
# 3. Loop through the user inputs and get responses from the agent
|
||||
for user_input in USER_INPUTS:
|
||||
print(f"# User: {user_input}")
|
||||
response = await agent.get_response(messages=user_input)
|
||||
print(f"# {response.name}: {response}")
|
||||
|
||||
"""
|
||||
Sample output:
|
||||
|
||||
# User: Why is the sky blue?
|
||||
# PhysicsAgent: The sky appears blue because of the way Earth's atmosphere scatters sunlight.
|
||||
When sunlight enters the atmosphere, it is made up of different colors, each with different wavelengths.
|
||||
Blue light has shorter wavelengths and is scattered in all directions by the gases and particles in the
|
||||
atmosphere more than other colors. This scattered blue light is what we see when we look up at the sky.
|
||||
This phenomenon is known as Rayleigh scattering.
|
||||
AI-generated content may be incorrect
|
||||
# User: What is the speed of light?
|
||||
# PhysicsAgent: The speed of light in a vacuum is approximately 299,792,458 meters per second (m/s). This is often
|
||||
rounded to 300,000 kilometers per second (km/s) for simplicity.
|
||||
AI-generated content may be incorrect
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from microsoft_agents.copilotstudio.client import (
|
||||
CopilotClient,
|
||||
)
|
||||
|
||||
from semantic_kernel.agents import CopilotStudioAgent, CopilotStudioAgentThread
|
||||
|
||||
"""
|
||||
This sample demonstrates how to use the Copilot Studio agent to answer questions from the user.
|
||||
It demonstrates how to use a thread to maintain context between user inputs.
|
||||
"""
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
# As an example, manually create the client and pass it in to the agent
|
||||
# 1. Create the client
|
||||
client: CopilotClient = CopilotStudioAgent.create_client(auth_mode="interactive")
|
||||
|
||||
# 2. Create the agent
|
||||
agent = CopilotStudioAgent(
|
||||
client=client,
|
||||
name="PhysicsAgent",
|
||||
instructions="You are help answer questions about physics.",
|
||||
)
|
||||
|
||||
# 3. Create a list of user inputs
|
||||
USER_INPUTS = [
|
||||
"Hello! Who are you? My name is John Doe.",
|
||||
"What is the speed of light?",
|
||||
"What have we been talking about?",
|
||||
"What is my name?",
|
||||
]
|
||||
|
||||
# 4. Create a thread to maintain context between user inputs
|
||||
# If no thread is provided, a new thread will be created
|
||||
# and returned in the response
|
||||
thread: CopilotStudioAgentThread | None = None
|
||||
|
||||
# 5. Loop through the user inputs and get responses from the agent
|
||||
for user_input in USER_INPUTS:
|
||||
print(f"# User: {user_input}")
|
||||
response = await agent.get_response(messages=user_input, thread=thread)
|
||||
print(f"# {response.name}: {response}")
|
||||
thread = response.thread
|
||||
|
||||
# 6. If a thread was created, delete it when done
|
||||
if thread:
|
||||
await thread.delete()
|
||||
|
||||
"""
|
||||
Sample output:
|
||||
|
||||
# User: Hello! Who are you? My name is John Doe.
|
||||
# PhysicsAgent: Hello, John! I'm an AI assistant here to help you with any questions you might have.
|
||||
How can I assist you today?
|
||||
AI-generated content may be incorrect
|
||||
# User: What is the speed of light?
|
||||
# PhysicsAgent: The speed of light in a vacuum is approximately 299,792,458 meters per second (m/s).
|
||||
This is often rounded to 300,000 kilometers per second (km/s) for simplicity. If you have any more questions,
|
||||
feel free to ask!
|
||||
AI-generated content may be incorrect
|
||||
# User: What have we been talking about?
|
||||
# PhysicsAgent: Sure, John! So far, we've had the following conversation:
|
||||
|
||||
1. You introduced yourself and asked who I am.
|
||||
2. I introduced myself as an AI assistant and asked how I could assist you.
|
||||
3. You asked about the speed of light, and I provided the information that it is approximately 299,792,458 meters
|
||||
per second in a vacuum.
|
||||
|
||||
If you have any more questions or need further assistance, feel free to ask!
|
||||
AI-generated content may be incorrect
|
||||
# User: What is my name?
|
||||
# PhysicsAgent: Based on our conversation, your name is John Doe. How can I assist you further today?
|
||||
AI-generated content may be incorrect
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from semantic_kernel.agents import CopilotStudioAgent, CopilotStudioAgentThread
|
||||
from semantic_kernel.contents import ChatMessageContent
|
||||
from semantic_kernel.functions import KernelArguments
|
||||
from semantic_kernel.prompt_template import PromptTemplateConfig
|
||||
|
||||
"""
|
||||
This sample demonstrates how to use the Copilot Studio agent to answer questions from the user.
|
||||
It demonstrates how to use a thread to maintain context between user inputs.
|
||||
It also demonstrates how to use a custom prompt template.
|
||||
"""
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
# 1. Create the agent
|
||||
agent = CopilotStudioAgent(
|
||||
name="JokeAgent",
|
||||
instructions="You are a joker. Tell kid-friendly jokes.",
|
||||
prompt_template_config=PromptTemplateConfig(template="Craft jokes about {{$topic}}"),
|
||||
)
|
||||
|
||||
# 2. Create a list of user inputs
|
||||
USER_INPUTS = [ChatMessageContent(role="user", content="Tell me a joke to make me laugh.")]
|
||||
|
||||
# 3. Create a thread to maintain context between user inputs
|
||||
thread: CopilotStudioAgentThread | None = None
|
||||
|
||||
# 4. Loop through the user inputs and get responses from the agent
|
||||
for user_input in USER_INPUTS:
|
||||
print(f"# User: {user_input}")
|
||||
response = await agent.get_response(
|
||||
messages=user_input, thread=thread, arguments=KernelArguments(topic="pirate")
|
||||
)
|
||||
print(f"# {response.name}: {response}")
|
||||
thread = response.thread
|
||||
|
||||
# 5. If a thread was created, delete it when done
|
||||
if thread:
|
||||
await thread.delete()
|
||||
|
||||
"""
|
||||
# User: Tell me a joke to make me laugh.
|
||||
# JokeAgent: Sure, here are a few pirate jokes for you:
|
||||
|
||||
1. Why don't pirates shower before they walk the plank?
|
||||
Because they'll just wash up on shore later!
|
||||
|
||||
2. How do pirates prefer to communicate?
|
||||
Aye to aye!
|
||||
|
||||
3. What's a pirate's favorite letter?
|
||||
You might think it's "R," but their true love is the "C"!
|
||||
|
||||
Hope these made you smile!
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from semantic_kernel.agents import CopilotStudioAgent, CopilotStudioAgentThread
|
||||
|
||||
"""
|
||||
This sample demonstrates how to use the Copilot Studio agent to perform a web search.
|
||||
In Copilot Studio, for the specified agent, you must enable the "Web Search" capability.
|
||||
If not already enabled, make sure to (re-)publish the agent so the changes take effect.
|
||||
"""
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
# 1. Create the agent
|
||||
agent = CopilotStudioAgent(
|
||||
name="WebSearchAgent",
|
||||
instructions="Help answer the user's questions by searching the web.",
|
||||
)
|
||||
|
||||
# 2. Create a list of user inputs
|
||||
USER_INPUTS = [
|
||||
"Which team won the 2025 NCAA Basketball championship?",
|
||||
]
|
||||
|
||||
# 3. Create a thread to maintain context between user inputs
|
||||
thread: CopilotStudioAgentThread | None = None
|
||||
|
||||
# 4. Loop through the user inputs and get responses from the agent
|
||||
for user_input in USER_INPUTS:
|
||||
print(f"# User: {user_input}")
|
||||
async for response in agent.invoke(messages=user_input, thread=thread):
|
||||
print(f"# {response.name}: {response}")
|
||||
thread = response.thread
|
||||
|
||||
# 5. If a thread was created, delete it when done
|
||||
if thread:
|
||||
await thread.delete()
|
||||
"""
|
||||
Sample output:
|
||||
|
||||
# User: Which team won the 2025 NCAA Basketball championship?
|
||||
# WebSearchAgent: The Florida Gators won the 2025 NCAA Basketball championship by defeating the Houston Cougars
|
||||
with a score of 65-63 [1].
|
||||
|
||||
[1]: https://www.ncaa.com/news/basketball-men/mml-official-bracket/2025-04-06/latest-bracket-schedule-and-scores-2025-ncaa-mens-tournament
|
||||
"Latest bracket, schedule and scores for the 2025 NCAA men's tournament"
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
Reference in New Issue
Block a user