chore: import upstream snapshot with attribution
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run

This commit is contained in:
wehub-resource-sync
2026-07-13 13:21:23 +08:00
commit b957a53def
5423 changed files with 863745 additions and 0 deletions
+284
View File
@@ -0,0 +1,284 @@
# Semantic Kernel Concepts by Feature
## Table of Contents
### Agents - Creating and using [agents](../../semantic_kernel/agents/) in Semantic Kernel
#### [Azure AI Agent](../../semantic_kernel/agents/azure_ai/azure_ai_agent.py)
- [Azure AI Agent as Kernel Function](./agents/azure_ai_agent/azure_ai_agent_as_kernel_function.py)
- [Azure AI Agent with Auto Function Invocation Filter Streaming](./agents/azure_ai_agent/azure_ai_agent_auto_func_invocation_filter_streaming.py)
- [Azure AI Agent with Auto Function Invocation Filter](./agents/azure_ai_agent/azure_ai_agent_auto_func_invocation_filter.py)
- [Azure AI Agent with Azure AI Search](./agents/azure_ai_agent/azure_ai_agent_azure_ai_search.py)
- [Azure AI Agent with Bing Grounding Streaming with Message Callback](./agents/azure_ai_agent/azure_ai_agent_bing_grounding_streaming_with_message_callback.py)
- [Azure AI Agent with Bing Grounding](./agents/azure_ai_agent/azure_ai_agent_bing_grounding.py)
- [Azure AI Agent with Code Interpreter Streaming with Message Callback](./agents/azure_ai_agent/azure_ai_agent_code_interpreter_streaming_with_message_callback.py)
- [Azure AI Agent Declarative with Azure AI Search](./agents/azure_ai_agent/azure_ai_agent_declarative_azure_ai_search.py)
- [Azure AI Agent Declarative with Bing Grounding](./agents/azure_ai_agent/azure_ai_agent_declarative_bing_grounding.py)
- [Azure AI Agent Declarative with Code Interpreter](./agents/azure_ai_agent/azure_ai_agent_declarative_code_interpreter.py)
- [Azure AI Agent Declarative with File Search](./agents/azure_ai_agent/azure_ai_agent_declarative_file_search.py)
- [Azure AI Agent Declarative with Function Calling From File](./agents/azure_ai_agent/azure_ai_agent_declarative_function_calling_from_file.py)
- [Azure AI Agent Declarative with OpenAPI Interpreter](./agents/azure_ai_agent/azure_ai_agent_declarative_openapi.py)
- [Azure AI Agent Declarative with Existing Agent ID](./agents/azure_ai_agent/azure_ai_agent_declarative_with_existing_agent_id.py)
- [Azure AI Agent File Manipulation](./agents/azure_ai_agent/azure_ai_agent_file_manipulation.py)
- [Azure AI Agent MCP Streaming](./agents/azure_ai_agent/azure_ai_agent_mcp_streaming.py)
- [Azure AI Agent Prompt Templating](./agents/azure_ai_agent/azure_ai_agent_prompt_templating.py)
- [Azure AI Agent Message Callback Streaming](./agents/azure_ai_agent/azure_ai_agent_message_callback_streaming.py)
- [Azure AI Agent Message Callback](./agents/azure_ai_agent/azure_ai_agent_message_callback.py)
- [Azure AI Agent Retrieve Messages from Thread](./agents/azure_ai_agent/azure_ai_agent_retrieve_messages_from_thread.py)
- [Azure AI Agent Streaming](./agents/azure_ai_agent/azure_ai_agent_streaming.py)
- [Azure AI Agent Structured Outputs](./agents/azure_ai_agent/azure_ai_agent_structured_outputs.py)
- [Azure AI Agent Truncation Strategy](./agents/azure_ai_agent/azure_ai_agent_truncation_strategy.py)
#### [Bedrock Agent](../../semantic_kernel/agents/bedrock/bedrock_agent.py)
- [Bedrock Agent Simple Chat Streaming](./agents/bedrock_agent/bedrock_agent_simple_chat_streaming.py)
- [Bedrock Agent Simple Chat](./agents/bedrock_agent/bedrock_agent_simple_chat.py)
- [Bedrock Agent With Code Interpreter Streaming](./agents/bedrock_agent/bedrock_agent_with_code_interpreter_streaming.py)
- [Bedrock Agent With Code Interpreter](./agents/bedrock_agent/bedrock_agent_with_code_interpreter.py)
- [Bedrock Agent With Kernel Function Simple](./agents/bedrock_agent/bedrock_agent_with_kernel_function_simple.py)
- [Bedrock Agent With Kernel Function Streaming](./agents/bedrock_agent/bedrock_agent_with_kernel_function_streaming.py)
- [Bedrock Agent With Kernel Function](./agents/bedrock_agent/bedrock_agent_with_kernel_function.py)
- [Bedrock Agent Mixed Chat Agents Streaming](./agents/bedrock_agent/bedrock_mixed_chat_agents_streaming.py)
- [Bedrock Agent Mixed Chat Agents](./agents/bedrock_agent/bedrock_mixed_chat_agents.py)
#### [Chat Completion Agent](../../semantic_kernel/agents/chat_completion/chat_completion_agent.py)
- [Chat Completion Agent as Kernel Function](./agents/chat_completion_agent/chat_completion_agent_as_kernel_function.py)
- [Chat Completion Agent Function Termination](./agents/chat_completion_agent/chat_completion_agent_function_termination.py)
- [Chat Completion Agent Message Callback Streaming](./agents/chat_completion_agent/chat_completion_agent_message_callback_streaming.py)
- [Chat Completion Agent Message Callback](./agents/chat_completion_agent/chat_completion_agent_message_callback.py)
- [Chat Completion Agent Templating](./agents/chat_completion_agent/chat_completion_agent_prompt_templating.py)
- [Chat Completion Agent Streaming Token Usage](./agents/chat_completion_agent/chat_completion_agent_streaming_token_usage.py)
- [Chat Completion Agent Summary History Reducer Agent Chat](./agents/chat_completion_agent/chat_completion_agent_summary_history_reducer_agent_chat.py)
- [Chat Completion Agent Summary History Reducer Single Agent](./agents/chat_completion_agent/chat_completion_agent_summary_history_reducer_single_agent.py)
- [Chat Completion Agent Token Usage](./agents/chat_completion_agent/chat_completion_agent_token_usage.py)
- [Chat Completion Agent Truncate History Reducer Agent Chat](./agents/chat_completion_agent/chat_completion_agent_truncate_history_reducer_agent_chat.py)
- [Chat Completion Agent Truncate History Reducer Single Agent](./agents/chat_completion_agent/chat_completion_agent_truncate_history_reducer_single_agent.py)
#### [Mixed Agent Group Chat](../../semantic_kernel/agents/group_chat/agent_group_chat.py)
- [Mixed Chat Agents Plugins](./agents/mixed_chat/mixed_chat_agents_plugins.py)
- [Mixed Chat Agents](./agents/mixed_chat/mixed_chat_agents.py)
- [Mixed Chat Files](./agents/mixed_chat/mixed_chat_files.py)
- [Mixed Chat Images](./agents/mixed_chat/mixed_chat_images.py)
- [Mixed Chat Reset](./agents/mixed_chat/mixed_chat_reset.py)
- [Mixed Chat Streaming](./agents/mixed_chat/mixed_chat_streaming.py)
#### [OpenAI Assistant Agent](../../semantic_kernel/agents/open_ai/openai_assistant_agent.py)
- [Azure OpenAI Assistant Declarative Code Interpreter](./agents/openai_assistant/azure_openai_assistant_declarative_code_interpreter.py)
- [Azure OpenAI Assistant Declarative File Search](./agents/openai_assistant/azure_openai_assistant_declarative_file_search.py)
- [Azure OpenAI Assistant Declarative Function Calling From File](./agents/openai_assistant/azure_openai_assistant_declarative_function_calling_from_file.py)
- [Azure OpenAI Assistant Declarative Templating](./agents/openai_assistant/azure_openai_assistant_declarative_templating.py)
- [Azure OpenAI Assistant Declarative With Existing Agent ID](./agents/openai_assistant/azure_openai_assistant_declarative_with_existing_agent_id.py)
- [OpenAI Assistant Auto Function Invocation Filter Streaming](./agents/openai_assistant/openai_assistant_auto_func_invocation_filter_streaming.py)
- [OpenAI Assistant Auto Function Invocation Filter](./agents/openai_assistant/openai_assistant_auto_func_invocation_filter.py)
- [OpenAI Assistant Chart Maker Streaming](./agents/openai_assistant/openai_assistant_chart_maker_streaming.py)
- [OpenAI Assistant Chart Maker](./agents/openai_assistant/openai_assistant_chart_maker.py)
- [OpenAI Assistant Declarative Code Interpreter](./agents/openai_assistant/openai_assistant_declarative_code_interpreter.py)
- [OpenAI Assistant Declarative File Search](./agents/openai_assistant/openai_assistant_declarative_file_search.py)
- [OpenAI Assistant Declarative Function Calling From File](./agents/openai_assistant/openai_assistant_declarative_function_calling_from_file.py)
- [OpenAI Assistant Declarative Templating](./agents/openai_assistant/openai_assistant_declarative_templating.py)
- [OpenAI Assistant Declarative With Existing Agent ID](./agents/openai_assistant/openai_assistant_declarative_with_existing_agent_id.py)
- [OpenAI Assistant File Manipulation Streaming](./agents/openai_assistant/openai_assistant_file_manipulation_streaming.py)
- [OpenAI Assistant File Manipulation](./agents/openai_assistant/openai_assistant_file_manipulation.py)
- [OpenAI Assistant Retrieval](./agents/openai_assistant/openai_assistant_retrieval.py)
- [OpenAI Assistant Message Callback Streaming](./agents/openai_assistant/openai_assistant_message_callback_streaming.py)
- [OpenAI Assistant Message Callback](./agents/openai_assistant/openai_assistant_message_callback.py)
- [OpenAI Assistant Streaming](./agents/openai_assistant/openai_assistant_streaming.py)
- [OpenAI Assistant Structured Outputs](./agents/openai_assistant/openai_assistant_structured_outputs.py)
- [OpenAI Assistant Templating Streaming](./agents/openai_assistant/openai_assistant_templating_streaming.py)
- [OpenAI Assistant Vision Streaming](./agents/openai_assistant/openai_assistant_vision_streaming.py)
#### [OpenAI Responses Agent](../../semantic_kernel/agents/open_ai/openai_responses_agent.py)
- [Azure OpenAI Responses Agent Declarative File Search](./agents/openai_responses/azure_openai_responses_agent_declarative_file_search.py)
- [Azure OpenAI Responses Agent Declarative Function Calling From File](./agents/openai_responses/azure_openai_responses_agent_declarative_function_calling_from_file.py)
- [Azure OpenAI Responses Agent Declarative Templating](./agents/openai_responses/azure_openai_responses_agent_declarative_templating.py)
- [OpenAI Responses Agent Declarative File Search](./agents/openai_responses/openai_responses_agent_declarative_file_search.py)
- [OpenAI Responses Agent Declarative Function Calling From File](./agents/openai_responses/openai_responses_agent_declarative_function_calling_from_file.py)
- [OpenAI Responses Agent Declarative Web Search](./agents/openai_responses/openai_responses_agent_declarative_web_search.py)
- [OpenAI Responses Binary Content Upload](./agents/openai_responses/responses_agent_binary_content_upload.py)
- [OpenAI Responses Message Callback Streaming](./agents/openai_responses/responses_agent_message_callback_streaming.py)
- [OpenAI Responses Message Callback](./agents/openai_responses/responses_agent_message_callback.py)
- [OpenAI Responses File Search Streaming](./agents/openai_responses/responses_agent_file_search_streaming.py)
- [OpenAI Responses Plugins Streaming](./agents/openai_responses/responses_agent_plugins_streaming.py)
- [OpenAI Responses Reuse Existing Thread ID](./agents/openai_responses/responses_agent_reuse_existing_thread_id.py)
- [OpenAI Responses Web Search Streaming](./agents/openai_responses/responses_agent_web_search_streaming.py)
### Audio - Using services that support audio-to-text and text-to-audio conversion
- [Chat with Audio Input](./audio/01-chat_with_audio_input.py)
- [Chat with Audio Output](./audio/02-chat_with_audio_output.py)
- [Chat with Audio Input and Output](./audio/03-chat_with_audio_input_output.py)
- [Audio Player](./audio/audio_player.py)
- [Audio Recorder](./audio/audio_recorder.py)
### AutoFunctionCalling - Using `Auto Function Calling` to allow function call capable models to invoke Kernel Functions automatically
- [Azure Python Code Interpreter Function Calling](./auto_function_calling/azure_python_code_interpreter_function_calling.py)
- [Function Calling with Required Type](./auto_function_calling/function_calling_with_required_type.py)
- [Parallel Function Calling](./auto_function_calling/parallel_function_calling.py)
- [Chat Completion with Auto Function Calling Streaming](./auto_function_calling/chat_completion_with_auto_function_calling_streaming.py)
- [Functions Defined in JSON Prompt](./auto_function_calling/functions_defined_in_json_prompt.py)
- [Chat Completion with Manual Function Calling Streaming](./auto_function_calling/chat_completion_with_manual_function_calling_streaming.py)
- [Functions Defined in YAML Prompt](./auto_function_calling/functions_defined_in_yaml_prompt.py)
- [Chat Completion with Auto Function Calling](./auto_function_calling/chat_completion_with_auto_function_calling.py)
- [Chat Completion with Manual Function Calling](./auto_function_calling/chat_completion_with_manual_function_calling.py)
- [Nexus Raven](./auto_function_calling/nexus_raven.py)
### ChatCompletion - Using [`ChatCompletion`](https://github.com/microsoft/semantic-kernel/blob/main/python/semantic_kernel/connectors/ai/chat_completion_client_base.py) messaging capable service with models
- [Simple Chatbot](./chat_completion/simple_chatbot.py)
- [Simple Chatbot Kernel Function](./chat_completion/simple_chatbot_kernel_function.py)
- [Simple Chatbot Logit Bias](./chat_completion/simple_chatbot_logit_bias.py)
- [Simple Chatbot Store Metadata](./chat_completion/simple_chatbot_store_metadata.py)
- [Simple Chatbot Streaming](./chat_completion/simple_chatbot_streaming.py)
- [Simple Chatbot with Image](./chat_completion/simple_chatbot_with_image.py)
- [Simple Chatbot with Summary History Reducer Keeping Function Content](./chat_completion/simple_chatbot_with_summary_history_reducer_keep_func_content.py)
- [Simple Chatbot with Summary History Reducer](./chat_completion/simple_chatbot_with_summary_history_reducer.py)
- [Simple Chatbot with Truncation History Reducer](./chat_completion/simple_chatbot_with_truncation_history_reducer.py)
- [Simple Chatbot with Summary History Reducer using Auto Reduce](./chat_completion/simple_chatbot_with_summary_history_reducer_autoreduce.py)
- [Simple Chatbot with Truncation History Reducer using Auto Reduce](./chat_completion/simple_chatbot_with_truncation_history_reducer_autoreduce.py)
### ChatHistory - Using and serializing the [`ChatHistory`](https://github.com/microsoft/semantic-kernel/blob/main/python/semantic_kernel/contents/chat_history.py)
- [Serialize Chat History](./chat_history/serialize_chat_history.py)
- [Store Chat History in CosmosDB](./chat_history/store_chat_history_in_cosmosdb.py)
### Filtering - Creating and using Filters
- [Auto Function Invoke Filters](./filtering/auto_function_invoke_filters.py)
- [Function Invocation Filters](./filtering/function_invocation_filters.py)
- [Function Invocation Filters Stream](./filtering/function_invocation_filters_stream.py)
- [Prompt Filters](./filtering/prompt_filters.py)
- [Retry with Filters](./filtering/retry_with_filters.py)
### Functions - Invoking [`Method`](https://github.com/microsoft/semantic-kernel/blob/main/python/semantic_kernel/functions/kernel_function_from_method.py) or [`Prompt`](https://github.com/microsoft/semantic-kernel/blob/main/python/semantic_kernel/functions/kernel_function_from_prompt.py) functions with [`Kernel`](https://github.com/microsoft/semantic-kernel/blob/main/python/semantic_kernel/kernel.py)
- [Kernel Arguments](./functions/kernel_arguments.py)
### Grounding - An example of how to perform LLM grounding
- [Grounded](./grounding/grounded.py)
### Local Models - Using the [`OpenAI connector`](https://github.com/microsoft/semantic-kernel/blob/main/python/semantic_kernel/connectors/ai/open_ai/services/open_ai_chat_completion.py) and [`OnnxGenAI connector`](https://github.com/microsoft/semantic-kernel/blob/main/python/semantic_kernel/connectors/ai/onnx/services/onnx_gen_ai_chat_completion.py) to talk to models hosted locally in Ollama, OnnxGenAI, and LM Studio
- [ONNX Chat Completion](./local_models/onnx_chat_completion.py)
- [LM Studio Text Embedding](./local_models/lm_studio_text_embedding.py)
- [LM Studio Chat Completion](./local_models/lm_studio_chat_completion.py)
- [ONNX Phi3 Vision Completion](./local_models/onnx_phi3_vision_completion.py)
- [Ollama Chat Completion](./local_models/ollama_chat_completion.py)
- [ONNX Text Completion](./local_models/onnx_text_completion.py)
### Logging - Showing how to set up logging
- [Setup Logging](./logging/setup_logging.py)
### Memory - Using [`Memory`](https://learn.microsoft.com/en-us/semantic-kernel/concepts/vector-store-connectors/?pivots=programming-language-python) AI concepts
- [Simple Memory](./memory/simple_memory.py)
- [Memory Data Models](./memory/data_models.py)
- [Memory with Pandas Dataframes](./memory/memory_with_pandas.py)
- [Complex memory](./memory/complex_memory.py)
- [Full sample with Azure AI Search including function calling](./memory/azure_ai_search_hotel_samples/README.md)
### Model-as-a-Service - Using models deployed as [`serverless APIs on Azure AI Studio`](https://learn.microsoft.com/en-us/azure/ai-studio/how-to/deploy-models-serverless?tabs=azure-ai-studio) to benchmark model performance against open-source datasets
- [MMLU Model Evaluation](./model_as_a_service/mmlu_model_eval.py)
### On Your Data - Examples of using AzureOpenAI [`On Your Data`](https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/use-your-data?tabs=mongo-db)
- [Azure Chat GPT with Data API](./on_your_data/azure_chat_gpt_with_data_api.py)
- [Azure Chat GPT with Data API Function Calling](./on_your_data/azure_chat_gpt_with_data_api_function_calling.py)
- [Azure Chat GPT with Data API Vector Search](./on_your_data/azure_chat_gpt_with_data_api_vector_search.py)
### Plugins - Different ways of creating and using [`Plugins`](https://github.com/microsoft/semantic-kernel/blob/main/python/semantic_kernel/functions/kernel_plugin.py)
- [Azure Key Vault Settings](./plugins/azure_key_vault_settings.py)
- [Azure Python Code Interpreter](./plugins/azure_python_code_interpreter.py)
- [OpenAI Function Calling with Custom Plugin](./plugins/openai_function_calling_with_custom_plugin.py)
- [Plugins from Directory](./plugins/plugins_from_dir.py)
### Processes - Examples of using the [`Process Framework`](../../semantic_kernel/processes/)
- [Cycles with Fan-In](./processes/cycles_with_fan_in.py)
- [Nested Process](./processes/nested_process.py)
- [Plan and Execute](./processes/plan_and_execute.py)
### PromptTemplates - Using [`Templates`](https://github.com/microsoft/semantic-kernel/blob/main/python/semantic_kernel/prompt_template/prompt_template_base.py) with parametrization for `Prompt` rendering
- [Template Language](./prompt_templates/template_language.py)
- [Azure Chat GPT API Jinja2](./prompt_templates/azure_chat_gpt_api_jinja2.py)
- [Load YAML Prompt](./prompt_templates/load_yaml_prompt.py)
- [Azure Chat GPT API Handlebars](./prompt_templates/azure_chat_gpt_api_handlebars.py)
- [Configuring Prompts](./prompt_templates/configuring_prompts.py)
### RAG - Different ways of `RAG` (Retrieval-Augmented Generation)
- [RAG with Vector Collection](./rag/rag_with_vector_collection.py)
- [Self-Critique RAG](./rag/self_critique_rag.py)
### Reasoning - Using [`ChatCompletion`](https://github.com/microsoft/semantic-kernel/blob/main/python/semantic_kernel/connectors/ai/chat_completion_client_base.py) to reason with OpenAI Reasoning
- [Simple Chatbot](./reasoning/simple_reasoning.py)
- [Simple Function Calling](./reasoning/simple_reasoning_function_calling.py)
### Search - Using [`Search`](https://github.com/microsoft/semantic-kernel/tree/main/python/semantic_kernel/connectors/search) services information
- [Bing Text Search as Plugin](./search/bing_text_search_as_plugin.py)
- [Brave Text Search as Plugin](./search/brave_text_search_as_plugin.py)
- [Google Text Search as Plugin](./search/google_text_search_as_plugin.py)
### Service Selector - Shows how to create and use a custom service selector class
- [Custom Service Selector](./service_selector/custom_service_selector.py)
### Setup - How to set up environment variables for Semantic Kernel
- [OpenAI Environment Setup](./setup/openai_env_setup.py)
- [Chat Completion Services](./setup/chat_completion_services.py)
### Structured Outputs - How to leverage OpenAI's json_schema [`Structured Outputs`](https://platform.openai.com/docs/guides/structured-outputs) functionality
- [JSON Structured Outputs](./structured_outputs/json_structured_outputs.py)
- [JSON Structured Outputs Function Calling](./structured_outputs/json_structured_outputs_function_calling.py)
### TextGeneration - Using [`TextGeneration`](https://github.com/microsoft/semantic-kernel/blob/main/python/semantic_kernel/connectors/ai/text_completion_client_base.py) capable service with models
- [Text Completion Client](./local_models/onnx_text_completion.py)
# Configuring the Kernel
In Semantic Kernel for Python, we leverage Pydantic Settings to manage configurations for AI and Memory Connectors, among other components. Heres a clear guide on how to configure your settings effectively:
## Steps for Configuration
1. **Reading Environment Variables:**
- **Primary Source:** Pydantic first attempts to read the required settings from environment variables.
2. **Using a .env File:**
- **Fallback Source:** If the required environment variables are not set, Pydantic will look for a `.env` file in the current working directory.
- **Custom Path (Optional):** You can specify an alternative path for the `.env` file via `env_file_path`. This can be either a relative or an absolute path.
3. **Direct Constructor Input:**
- As an alternative to environment variables and `.env` files, you can pass the required settings directly through the constructor of the AI Connector or Memory Connector.
## Azure Authentication
To authenticate to your Azure resources, you must provide one of the following authentication methods to successfully authenticate:
1. **AsyncTokenCredential** - provide one of the `AsyncTokenCredential` types (e.g. `AzureCliCredential`, `ManagedIdentityCredential`). More information here: [Credentials for asynchronous Azure SDK clients]("https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.aio?view=azure-python").
2. **Custom AsyncAzureOpenAI client** - Pass a pre-configured client instance.
3. **Access Token (`ad_token`)** - Provide a valid Microsoft Entra access token directly.
4. **Token Provider (`ad_token_provider`)** - Provide a callable that returns a valid access token.
5. **API Key** - Provide through an environment variable, a `.env` file, or the constructor.
To successfully retrieve and use the Entra Auth Token, you need the `Cognitive Services OpenAI Contributor` role assigned to your Azure OpenAI resource. By default, the `https://cognitiveservices.azure.com` token endpoint is used. You can override this endpoint by setting an environment variable `.env` variable as `AZURE_OPENAI_TOKEN_ENDPOINT` or by passing a new value to the `AzureChatCompletion` constructor as part of the `AzureOpenAISettings`.
## Best Practices
- **.env File Placement:** We highly recommend placing the `.env` file in the `semantic-kernel/python` root directory. This is a common practice when developing in the Semantic Kernel repository.
By following these guidelines, you can ensure that your settings for various components are configured correctly, enabling seamless functionality and integration of Semantic Kernel in your Python projects.
+123
View File
@@ -0,0 +1,123 @@
# Semantic Kernel: Agent concept examples
This project contains a step by step guide to get started with _Semantic Kernel Agents_ in Python.
## PyPI
- For the use of Chat Completion agents, the minimum allowed Semantic Kernel pypi version is 1.3.0.
- For the use of OpenAI Assistant agents, the minimum allowed Semantic Kernel pypi version is 1.4.0.
- For the use of Agent Group Chat, the minimum allowed Semantic kernel pypi version is 1.6.0.
- For the use of Streaming OpenAI Assistant agents, the minimum allowed Semantic Kernel pypi version is 1.11.0.
- For the use of AzureAI and Bedrock agents, the minimum allowed Semantic Kernel pypi version is 1.21.0.
- For the use of Crew.AI as a plugin, the minimum allowed Semantic Kernel pypi version is 1.21.1.
- For the use of OpenAI Responses agents, the minimum allowed Semantic Kernel pypi version is 1.27.0.
## Source
- [Semantic Kernel Agent Framework](../../../semantic_kernel/agents/)
## Examples
The concept agents examples are grouped by prefix:
Prefix|Description
---|---
autogen_conversable_agent| How to use [AutoGen 0.2 Conversable Agents](https://microsoft.github.io/autogen/0.2/docs/Getting-Started) within Semantic Kernel.
azure_ai_agent|How to use an [Azure AI Agent](https://learn.microsoft.com/en-us/azure/ai-services/agents/quickstart?pivots=programming-language-python-azure) within Semantic Kernel.
chat_completion_agent|How to use Semantic Kernel Chat Completion agents that leverage AI Connector Chat Completion APIs.
bedrock|How to use [AWS Bedrock agents](https://aws.amazon.com/bedrock/agents/) in Semantic Kernel.
mixed_chat|How to combine different agent types.
openai_assistant|How to use [OpenAI Assistants](https://platform.openai.com/docs/assistants/overview) in Semantic Kernel.
openai_responses|How to use [OpenAI Responses](https://platform.openai.com/docs/api-reference/responses) in Semantic Kernel.
## Configuring the Kernel
Similar to the Semantic Kernel Python concept samples, it is necessary to configure the secrets
and keys used by the kernel. See the follow "Configuring the Kernel" [guide](../README.md#configuring-the-kernel) for
more information.
## Running Concept Samples
Concept samples can be run in an IDE or via the command line. After setting up the required api key or token authentication
for your AI connector, the samples run without any extra command line arguments.
## Managing Conversation Threads with AgentThread
This section explains how to manage conversation context using the `AgentThread` base class. Each agent has its own thread implementation that preserves the context of a conversation. If you invoke an agent without specifying a thread, a new one is created automatically and returned as part of the `AgentItemResponse` object—which includes both the message (of type `ChatMessageContent`) and the thread (`AgentThread`). You also have the option to create a custom thread for a specific agent by providing a unique `thread_id`.
## Overview
**Automatic Thread Creation:**
When an agent is invoked without a provided thread, it creates a new thread to manage the conversation context automatically.
**Manual Thread Management:**
You can explicitly create a specific implementation for the desired `Agent` that derives from the base class `AgentThread`. You have the option to assign a `thread_id` to manage the conversation session. This is particularly useful in complex scenarios or multi-user environments.
## Code Example
Below is a sample code snippet demonstrating thread management:
```python
from semantic_kernel.agents import ChatCompletionAgent
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
USER_INPUTS = [
"Why is the sky blue?",
]
# 1. Create the agent by specifying the service
agent = ChatCompletionAgent(
service=AzureChatCompletion(),
name="Assistant",
instructions="Answer the user's questions.",
)
# 2. Create a thread to hold the conversation
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread = None
for user_input in USER_INPUTS:
print(f"# User: {user_input}")
# 3. Invoke the agent for a response
response = await agent.get_response(
message=user_input,
thread=thread,
)
print(f"# {response.name}: {response}")
thread = response.thread
# 4. Cleanup: Clear the thread
await thread.end() if thread else None
"""
Sample output:
# User: Hello, I am John Doe.
# Assistant: Hello, John Doe! How can I assist you today?
# User: What is your name?
# Assistant: I don't have a personal name like a human does, but you can call me Assistant.?
# User: What is my name?
# Assistant: You mentioned that your name is John Doe. How can I assist you further, John?
"""
```
## Detailed Explanation
**Thread Initialization:**
The thread is initially set to `None`. If no thread is provided, the agent creates a new one and includes it in the response.
**Processing User Inputs:**
A list of `user_inputs` simulates a conversation. For each input:
- The code prints the user's message.
- The agent is invoked using the `get_response` method, which returns the response asynchronously.
**Handling Responses:**
- The thread is updated with each response to maintain the conversation context.
**Cleanup:**
The code safely ends the thread if it exists.
By leveraging the `AgentThread`, you ensure that each conversation maintains its context seamlessly -- whether the thread is automatically created or manually managed with a custom `thread_id`. This approach is crucial for developing agents that deliver coherent and context-aware interactions.
@@ -0,0 +1,19 @@
## AutoGen Conversable Agent (v0.2.X)
Semantic Kernel Python supports running AutoGen Conversable Agents provided in the 0.2.X package.
### Limitations
Currently, there are some limitations to note:
- AutoGen Conversable Agents in Semantic Kernel run asynchronously and do not support streaming of agent inputs or responses.
### Installation
Install the `semantic-kernel` package with the `autogen` extra:
```bash
pip install semantic-kernel[autogen]
```
For an example of how to integrate an AutoGen Conversable Agent using the Semantic Kernel Agent abstraction, please refer to [`autogen_conversable_agent_simple_convo.py`](autogen_conversable_agent_simple_convo.py).
@@ -0,0 +1,71 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from autogen import ConversableAgent
from autogen.coding import LocalCommandLineCodeExecutor
from semantic_kernel.agents import AutoGenConversableAgent, AutoGenConversableAgentThread
"""
The following sample demonstrates how to use the AutoGenConversableAgent to create a reply from an agent
to a message with a code block. The agent executes the code block and replies with the output.
The sample follows the AutoGen flow outlined here:
https://microsoft.github.io/autogen/0.2/docs/tutorial/code-executors#local-execution
"""
async def main():
thread: AutoGenConversableAgentThread = None
# Create a temporary directory to store the code files.
import os
# Configure the temporary directory to be where the script is located.
temp_dir = os.path.dirname(os.path.realpath(__file__))
# Create a local command line code executor.
executor = LocalCommandLineCodeExecutor(
timeout=10, # Timeout for each code execution in seconds.
work_dir=temp_dir, # Use the temporary directory to store the code files.
)
# Create an agent with code executor configuration.
code_executor_agent = ConversableAgent(
"code_executor_agent",
llm_config=False, # Turn off LLM for this agent.
code_execution_config={"executor": executor}, # Use the local command line code executor.
human_input_mode="ALWAYS", # Always take human input for this agent for safety.
)
autogen_agent = AutoGenConversableAgent(conversable_agent=code_executor_agent)
message_with_code_block = """This is a message with code block.
The code block is below:
```python
def generate_fibonacci(max_val):
a, b = 0, 1
fibonacci_numbers = []
while a <= max_val:
fibonacci_numbers.append(a)
a, b = b, a + b
return fibonacci_numbers
if __name__ == "__main__":
fib_numbers = generate_fibonacci(101)
print(fib_numbers)
```
This is the end of the message.
"""
async for response in autogen_agent.invoke(messages=message_with_code_block, thread=thread):
print(f"# {response.role} - {response.name or '*'}: '{response}'")
thread = response.thread
# Cleanup: Delete the thread and agent
await thread.delete() if thread else None
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,105 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from typing import Annotated, Literal
from autogen import ConversableAgent, register_function
from semantic_kernel.agents import AutoGenConversableAgent, AutoGenConversableAgentThread
from semantic_kernel.contents.function_call_content import FunctionCallContent
from semantic_kernel.contents.function_result_content import FunctionResultContent
"""
The following sample demonstrates how to use the AutoGenConversableAgent to create a conversation between two agents
where one agent suggests a tool function call and the other agent executes the tool function call.
In this example, the assistant agent suggests a calculator tool function call to the user proxy agent. The user proxy
agent executes the calculator tool function call. The assistant agent and the user proxy agent are created using the
ConversableAgent class. The calculator tool function is registered with the assistant agent and the user proxy agent.
This sample follows the AutoGen flow outlined here:
https://microsoft.github.io/autogen/0.2/docs/tutorial/tool-use
"""
Operator = Literal["+", "-", "*", "/"]
async def main():
def calculator(a: int, b: int, operator: Annotated[Operator, "operator"]) -> int:
if operator == "+":
return a + b
if operator == "-":
return a - b
if operator == "*":
return a * b
if operator == "/":
return int(a / b)
raise ValueError("Invalid operator")
assistant = ConversableAgent(
name="Assistant",
system_message="You are a helpful AI assistant. "
"You can help with simple calculations. "
"Return 'TERMINATE' when the task is done.",
# Note: the model "gpt-4o" leads to a "division by zero" error that doesn't occur with "gpt-4o-mini"
# or even "gpt-4".
llm_config={
"config_list": [{"model": os.environ["OPENAI_CHAT_MODEL_ID"], "api_key": os.environ["OPENAI_API_KEY"]}]
},
)
# Create a thread for use with the agent.
thread: AutoGenConversableAgentThread = None
# Create a Semantic Kernel AutoGenConversableAgent based on the AutoGen ConversableAgent.
assistant_agent = AutoGenConversableAgent(conversable_agent=assistant)
user_proxy = ConversableAgent(
name="User",
llm_config=False,
is_termination_msg=lambda msg: msg.get("content") is not None and "TERMINATE" in msg["content"],
human_input_mode="NEVER",
)
assistant.register_for_llm(name="calculator", description="A simple calculator")(calculator)
# Register the tool function with the user proxy agent.
user_proxy.register_for_execution(name="calculator")(calculator)
register_function(
calculator,
caller=assistant, # The assistant agent can suggest calls to the calculator.
executor=user_proxy, # The user proxy agent can execute the calculator calls.
name="calculator", # By default, the function name is used as the tool name.
description="A simple calculator", # A description of the tool.
)
# Create a Semantic Kernel AutoGenConversableAgent based on the AutoGen ConversableAgent.
user_proxy_agent = AutoGenConversableAgent(conversable_agent=user_proxy)
async for response in user_proxy_agent.invoke(
thread=thread,
recipient=assistant_agent,
messages="What is (44232 + 13312 / (232 - 32)) * 5?",
max_turns=10,
):
for item in response.items:
match item:
case FunctionResultContent(result=r):
print(f"# {response.role} - {response.name or '*'}: '{r}'")
case FunctionCallContent(function_name=fn, arguments=arguments):
print(
f"# {response.role} - {response.name or '*'}: Function Name: '{fn}', Arguments: '{arguments}'" # noqa: E501
)
case _:
print(f"# {response.role} - {response.name or '*'}: '{response}'")
thread = response.thread
# Cleanup: Delete the thread and agent
await thread.delete() if thread else None
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,67 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from autogen import ConversableAgent
from semantic_kernel.agents import AutoGenConversableAgent, AutoGenConversableAgentThread
"""
The following sample demonstrates how to use the AutoGenConversableAgent to create a conversation between two agents
where one agent suggests a joke and the other agent generates a joke.
The sample follows the AutoGen flow outlined here:
https://microsoft.github.io/autogen/0.2/docs/tutorial/introduction#roles-and-conversations
"""
async def main():
thread: AutoGenConversableAgentThread = None
cathy = ConversableAgent(
"cathy",
system_message="Your name is Cathy and you are a part of a duo of comedians.",
llm_config={
"config_list": [
{
"model": os.environ["OPENAI_CHAT_MODEL_ID"],
"temperature": 0.9,
"api_key": os.environ.get("OPENAI_API_KEY"),
}
]
},
human_input_mode="NEVER", # Never ask for human input.
)
cathy_autogen_agent = AutoGenConversableAgent(conversable_agent=cathy)
joe = ConversableAgent(
"joe",
system_message="Your name is Joe and you are a part of a duo of comedians.",
llm_config={
"config_list": [
{
"model": os.environ["OPENAI_CHAT_MODEL_ID"],
"temperature": 0.7,
"api_key": os.environ.get("OPENAI_API_KEY"),
}
]
},
human_input_mode="NEVER", # Never ask for human input.
)
joe_autogen_agent = AutoGenConversableAgent(conversable_agent=joe)
async for response in cathy_autogen_agent.invoke(
recipient=joe_autogen_agent, message="Tell me a joke about the stock market.", thread=thread, max_turns=3
):
print(f"# {response.role} - {response.name or '*'}: '{response}'")
thread = response.thread
# Cleanup: Delete the thread and agent
await thread.delete() if thread else None
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,6 @@
AZURE_AI_AGENT_PROJECT_CONNECTION_STRING = "<example-connection-string>"
AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME = "<example-model-deployment-name>"
AZURE_AI_AGENT_ENDPOINT = "<example-endpoint>"
AZURE_AI_AGENT_SUBSCRIPTION_ID = "<example-subscription-id>"
AZURE_AI_AGENT_RESOURCE_GROUP_NAME = "<example-resource-group-name>"
AZURE_AI_AGENT_PROJECT_NAME = "<example-project-name>"
@@ -0,0 +1,13 @@
## Azure AI Agents
For details on using Azure AI Agents within Semantic Kernel, see the [README](../../../getting_started_with_agents/azure_ai_agent/README.md) in the `getting_started_with_agents/azure_ai_agent` directory.
### Running the `azure_ai_agent_ai_search.py` Sample
Before running this sample, ensure you have a valid index configured in your Azure AI Search resource. This sample queries hotel data using the sample Azure AI Search hotels index.
For configuration details, refer to the comments in the sample script. For additional guidance, consult the [README](../../memory/azure_ai_search_hotel_samples/README.md), which provides step-by-step instructions for creating the sample index and generating vectors. This is one approach to setting up the index; you can also follow other tutorials, such as those on "Import and Vectorize Data" in your Azure AI Search resource.
### Requests and Rate Limits
For information on configuring rate limits or adjusting polling, refer [here](../../../getting_started_with_agents/azure_ai_agent/README.md#requests-and-rate-limits)
@@ -0,0 +1,160 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity import AzureCliCredential
from semantic_kernel import Kernel
from semantic_kernel.agents import (
AzureAIAgent,
AzureAIAgentSettings,
ChatCompletionAgent,
ChatHistoryAgentThread,
)
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
from semantic_kernel.filters import FunctionInvocationContext
"""
The following sample demonstrates how to create an Azure AI Agent Agent
and a ChatCompletionAgent use them as tools available for a Triage Agent
to delegate requests to the appropriate agent. A Function Invocation Filter
is used to show the function call content and the function result content so the caller
can see which agent was called and what the response was.
"""
# Define the auto function invocation filter that will be used by the kernel
async def function_invocation_filter(context: FunctionInvocationContext, next):
"""A filter that will be called for each function call in the response."""
if "messages" not in context.arguments:
await next(context)
return
print(f" Agent [{context.function.name}] called with messages: {context.arguments['messages']}")
await next(context)
print(f" Response from agent [{context.function.name}]: {context.result.value}")
async def chat(triage_agent: ChatCompletionAgent, thread: ChatHistoryAgentThread = None) -> bool:
"""
Continuously prompt the user for input and show the assistant's response.
Type 'exit' to exit.
"""
try:
user_input = input("User:> ")
except (KeyboardInterrupt, EOFError):
print("\n\nExiting chat...")
return False
if user_input.lower().strip() == "exit":
print("\n\nExiting chat...")
return False
response = await triage_agent.get_response(
messages=user_input,
thread=thread,
)
if response:
print(f"Agent :> {response}")
return True
async def main() -> None:
# Create and configure the kernel.
kernel = Kernel()
# The filter is used for demonstration purposes to show the function invocation.
kernel.add_filter("function_invocation", function_invocation_filter)
ai_agent_settings = AzureAIAgentSettings()
credential = AzureCliCredential()
async with (
AzureAIAgent.create_client(credential=credential, endpoint=ai_agent_settings.endpoint) as client,
):
# Create the agent definition
agent_definition = await client.agents.create_agent(
model=ai_agent_settings.model_deployment_name,
name="BillingAgent",
instructions=(
"You specialize in handling customer questions related to billing issues. "
"This includes clarifying invoice charges, payment methods, billing cycles, "
"explaining fees, addressing discrepancies in billed amounts, updating payment details, "
"assisting with subscription changes, and resolving payment failures. "
"Your goal is to clearly communicate and resolve issues specifically about payments and charges."
),
)
# Create the AzureAI Agent
billing_agent = AzureAIAgent(
client=client,
definition=agent_definition,
)
refund_agent = ChatCompletionAgent(
service=AzureChatCompletion(credential=credential),
name="RefundAgent",
instructions=(
"You specialize in addressing customer inquiries regarding refunds. "
"This includes evaluating eligibility for refunds, explaining refund policies, "
"processing refund requests, providing status updates on refunds, handling complaints related to "
"refunds, and guiding customers through the refund claim process. "
"Your goal is to assist users clearly and empathetically to successfully resolve their refund-related "
"concerns."
),
)
triage_agent = ChatCompletionAgent(
service=AzureChatCompletion(credential=credential),
kernel=kernel,
name="TriageAgent",
instructions=(
"Your role is to evaluate the user's request and forward it to the appropriate agent based on the "
"nature of the query. Forward requests about charges, billing cycles, payment methods, fees, or "
"payment issues to the BillingAgent. Forward requests concerning refunds, refund eligibility, "
"refund policies, or the status of refunds to the RefundAgent. Your goal is accurate identification "
"of the appropriate specialist to ensure the user receives targeted assistance."
),
plugins=[billing_agent, refund_agent],
)
thread: ChatHistoryAgentThread = None
print("Welcome to the chat bot!\n Type 'exit' to exit.\n Try to get some billing or refund help.")
chatting = True
while chatting:
chatting = await chat(triage_agent, thread)
"""
Sample Output:
I canceled my subscription but I was still charged.
Agent [BillingAgent] called with messages: I canceled my subscription but I was still charged.
Response from agent [BillingAgent]: I understand how concerning that can be. It's possible that the charge you
received is for a billing cycle that was initiated before your cancellation was processed. Here are a few
steps you can take:
1. **Check Cancellation Confirmation**: Make sure you received a confirmation of your cancellation.
This usually comes via email.
2. **Billing Cycle**: Review your billing cycle to confirm whether the charge aligns with your subscription terms.
If your billing is monthly, charges can occur even if you cancel before the period ends.
3. **Contact Support**: If you believe the charge was made in error, please reach out to customer support for
further clarification and to rectify the situation.
If you can provide more details about the subscription and when you canceled it, I can help you further understand
the charges.
Agent :> It's possible that the charge you received is for a billing cycle initiated before your cancellation was
processed. Please check if you received a cancellation confirmation, review your billing cycle, and contact
support for further clarification if you believe the charge was made in error. If you have more details,
I can help you understand the charges better.
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,178 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from typing import Annotated
from azure.identity.aio import AzureCliCredential
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings, AzureAIAgentThread
from semantic_kernel.contents import ChatMessageContent, FunctionCallContent, FunctionResultContent
from semantic_kernel.filters import (
AutoFunctionInvocationContext,
FilterTypes,
)
from semantic_kernel.functions import FunctionResult, kernel_function
from semantic_kernel.kernel import Kernel
"""
The following sample demonstrates how to create an Azure AI agent that answers
user questions. This sample demonstrates the basic steps to create an agent
and simulate a conversation with the agent.
This sample demonstrates how to create a filter that will be called for each
function call in the response. The filter can be used to modify the function
result or to terminate the function call. The filter can also be used to
log the function call or to perform any other action before or after the
function call.
"""
class MenuPlugin:
"""A sample Menu Plugin used for the concept sample."""
@kernel_function(description="Provides a list of specials from the menu.")
def get_specials(self) -> Annotated[str, "Returns the specials from the menu."]:
return """
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
"""
@kernel_function(description="Provides the price of the requested menu item.")
def get_item_price(
self, menu_item: Annotated[str, "The name of the menu item."]
) -> Annotated[str, "Returns the price of the menu item."]:
return "$9.99"
# Define a kernel instance so we can attach the filter to it
kernel = Kernel()
# Define a list to store intermediate steps
intermediate_steps: list[ChatMessageContent] = []
# Define a callback function to handle intermediate step content messages
async def handle_intermediate_steps(message: ChatMessageContent) -> None:
intermediate_steps.append(message)
@kernel.filter(FilterTypes.AUTO_FUNCTION_INVOCATION)
async def auto_function_invocation_filter(context: AutoFunctionInvocationContext, next):
"""A filter that will be called for each function call in the response."""
print("\nAuto function invocation filter")
print(f"Function: {context.function.name}")
# if we don't call next, it will skip this function, and go to the next one
await next(context)
"""
Note: to simply return the unaltered function results, uncomment the `context.terminate = True` line and
comment out the lines starting with `result = context.function_result` through `context.terminate = True`.
context.terminate = True
For this sample, simply setting `context.terminate = True` will return the unaltered function result:
Auto function invocation filter
Function: get_specials
# Assistant: MenuPlugin-get_specials -
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
"""
result = context.function_result
if "menu" in context.function.plugin_name.lower():
print("Altering the Menu plugin function result...\n")
context.function_result = FunctionResult(
function=result.function,
value="We are sold out, sorry!",
)
context.terminate = True
# Simulate a conversation with the agent
USER_INPUTS = ["What's the special food on the menu?", "What should I do then?"]
async def main() -> None:
ai_agent_settings = AzureAIAgentSettings.create()
async with (
AzureCliCredential() as creds,
AzureAIAgent.create_client(credential=creds) as client,
):
# 1. Create an agent on the Azure AI agent service
agent_definition = await client.agents.create_agent(
model=ai_agent_settings.model_deployment_name,
name="Host",
instructions="Answer the user's questions about the menu.",
)
# 2. Create a Semantic Kernel agent for the Azure AI agent
agent = AzureAIAgent(
kernel=kernel,
client=client,
definition=agent_definition,
plugins=[MenuPlugin()], # Add the plugin to the agent
)
# 3. Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: AzureAIAgentThread = None
try:
for user_input in USER_INPUTS:
print(f"# User: {user_input}")
# 4. Invoke the agent with the specified message for response
async for response in agent.invoke(
messages=user_input, thread=thread, on_intermediate_message=handle_intermediate_steps
):
# 5. Print the response
print(f"# {response.name}: {response}")
thread = response.thread
finally:
# 6. Cleanup: Delete the thread and agent
await thread.delete() if thread else None
await client.agents.delete_agent(agent.id)
# Print the intermediate steps
print("\nIntermediate Steps:")
for msg in intermediate_steps:
if any(isinstance(item, FunctionResultContent) for item in msg.items):
for fr in msg.items:
if isinstance(fr, FunctionResultContent):
print(f"Function Result:> {fr.result} for function: {fr.name}")
elif any(isinstance(item, FunctionCallContent) for item in msg.items):
for fcc in msg.items:
if isinstance(fcc, FunctionCallContent):
print(f"Function Call:> {fcc.name} with arguments: {fcc.arguments}")
else:
print(f"{msg.role}: {msg.content}")
"""
Sample Output:
# User: What's the special food on the menu?
Auto function invocation filter
Function: get_specials
Altering the Menu plugin function result...
# Host: I'm sorry, but all the specials on the menu are currently sold out. If there's anything else you're
looking for, please let me know!
# User: What should I do then?
# Host: You might consider ordering from the regular menu items instead. If you need any recommendations or
information about specific items, such as prices or ingredients, feel free to ask!
Intermediate Steps:
Function Call:> MenuPlugin-get_specials with arguments: {}
Function Result:> We are sold out, sorry! for function: MenuPlugin-get_specials
AuthorRole.ASSISTANT: I'm sorry, but all the specials on the menu are currently sold out. If there's anything
else you're looking for, please let me know!
AuthorRole.ASSISTANT: You might consider ordering from the regular menu items instead. If you need any
recommendations or information about specific items, such as prices or ingredients, feel free to ask!
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,183 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from typing import Annotated
from azure.identity.aio import AzureCliCredential
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings, AzureAIAgentThread
from semantic_kernel.contents import ChatMessageContent, FunctionCallContent, FunctionResultContent
from semantic_kernel.filters import (
AutoFunctionInvocationContext,
FilterTypes,
)
from semantic_kernel.functions import FunctionResult, kernel_function
from semantic_kernel.kernel import Kernel
"""
The following sample demonstrates how to create an Azure AI agent that answers
user questions. This sample demonstrates the basic steps to create an agent
and simulate a streaming conversation with the agent.
This sample demonstrates how to create a filter that will be called for each
function call in the response. The filter can be used to modify the function
result or to terminate the function call. The filter can also be used to
log the function call or to perform any other action before or after the
function call.
"""
class MenuPlugin:
"""A sample Menu Plugin used for the concept sample."""
@kernel_function(description="Provides a list of specials from the menu.")
def get_specials(self) -> Annotated[str, "Returns the specials from the menu."]:
return """
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
"""
@kernel_function(description="Provides the price of the requested menu item.")
def get_item_price(
self, menu_item: Annotated[str, "The name of the menu item."]
) -> Annotated[str, "Returns the price of the menu item."]:
return "$9.99"
# Define a kernel instance so we can attach the filter to it
kernel = Kernel()
# Define a list to store intermediate steps
intermediate_steps: list[ChatMessageContent] = []
# Define a callback function to handle intermediate step content messages
async def handle_intermediate_steps(message: ChatMessageContent) -> None:
intermediate_steps.append(message)
@kernel.filter(FilterTypes.AUTO_FUNCTION_INVOCATION)
async def auto_function_invocation_filter(context: AutoFunctionInvocationContext, next):
"""A filter that will be called for each function call in the response."""
print("\nAuto function invocation filter")
print(f"Function: {context.function.name}")
# if we don't call next, it will skip this function, and go to the next one
await next(context)
"""
Note: to simply return the unaltered function results, uncomment the `context.terminate = True` line and
comment out the lines starting with `result = context.function_result` through `context.terminate = True`.
context.terminate = True
For this sample, simply setting `context.terminate = True` will return the unaltered function result:
Auto function invocation filter
Function: get_specials
# Assistant: MenuPlugin-get_specials -
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
"""
result = context.function_result
if "menu" in context.function.plugin_name.lower():
print("Altering the Menu plugin function result...\n")
context.function_result = FunctionResult(
function=result.function,
value="We are sold out, sorry!",
)
context.terminate = True
# Simulate a conversation with the agent
USER_INPUTS = ["What's the special food on the menu?", "What should I do then?"]
async def main() -> None:
ai_agent_settings = AzureAIAgentSettings.create()
async with (
AzureCliCredential() as creds,
AzureAIAgent.create_client(credential=creds) as client,
):
# 1. Create an agent on the Azure AI agent service
agent_definition = await client.agents.create_agent(
model=ai_agent_settings.model_deployment_name,
name="Host",
instructions="Answer the user's questions about the menu.",
)
# 2. Create a Semantic Kernel agent for the Azure AI agent
agent = AzureAIAgent(
kernel=kernel,
client=client,
definition=agent_definition,
plugins=[MenuPlugin()], # Add the plugin to the agent
)
# 3. Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: AzureAIAgentThread = None
try:
for user_input in USER_INPUTS:
print(f"# User: {user_input}")
# 4. Invoke the agent with the specified message for response
first_chunk = True
async for response in agent.invoke_stream(
messages=user_input, thread=thread, on_intermediate_message=handle_intermediate_steps
):
# 5. Print the response
if first_chunk:
print(f"# {response.name}: ", end="", flush=True)
first_chunk = False
print(f"{response}", end="", flush=True)
thread = response.thread
print()
finally:
# 6. Cleanup: Delete the thread and agent
await thread.delete() if thread else None
await client.agents.delete_agent(agent.id)
# Print the intermediate steps
print("\nIntermediate Steps:")
for msg in intermediate_steps:
if any(isinstance(item, FunctionResultContent) for item in msg.items):
for fr in msg.items:
if isinstance(fr, FunctionResultContent):
print(f"Function Result:> {fr.result} for function: {fr.name}")
elif any(isinstance(item, FunctionCallContent) for item in msg.items):
for fcc in msg.items:
if isinstance(fcc, FunctionCallContent):
print(f"Function Call:> {fcc.name} with arguments: {fcc.arguments}")
else:
print(f"{msg.role}: {msg.content}")
"""
Sample Output:
# User: What's the special food on the menu?
Auto function invocation filter
Function: get_specials
Altering the Menu plugin function result...
# Host: I'm sorry, but all the specials on the menu are currently sold out. If there's anything else you're
looking for, please let me know!
# User: What should I do then?
# Host: You might consider ordering from the regular menu items instead. If you need any recommendations or
information about specific items, such as prices or ingredients, feel free to ask!
Intermediate Steps:
Function Call:> MenuPlugin-get_specials with arguments: {}
Function Result:> We are sold out, sorry! for function: MenuPlugin-get_specials
AuthorRole.ASSISTANT: I'm sorry, but all the specials on the menu are currently sold out. If there's anything
else you're looking for, please let me know!
AuthorRole.ASSISTANT: You might consider ordering from the regular menu items instead. If you need any
recommendations or information about specific items, such as prices or ingredients, feel free to ask!
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,139 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import logging
from azure.ai.agents.models import AzureAISearchTool
from azure.ai.projects.models import ConnectionType
from azure.identity.aio import AzureCliCredential
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings, AzureAIAgentThread
logging.basicConfig(level=logging.WARNING)
"""
The following sample demonstrates how to create a simple,
Azure AI agent that uses the Azure AI Search tool and the demo
hotels-sample-index to answer questions about hotels.
This sample requires:
- A "Standard" Agent Setup (choose the Python (Azure SDK) tab):
https://learn.microsoft.com/en-us/azure/ai-services/agents/quickstart
- An Azure AI Search index named 'hotels-sample-index' created in your
Azure AI Search service. You may follow this guide to create the index:
https://learn.microsoft.com/azure/search/search-get-started-portal
- You will need to make sure your Azure AI Agent project is set up with
the required Knowledge Source to be able to use the Azure AI Search tool.
Refer to the following link for information on how to do this:
https://learn.microsoft.com/en-us/azure/ai-services/agents/how-to/tools/azure-ai-search
Refer to the README for information about configuring the index to work
with the sample data model in Azure AI Search.
"""
# The name of the Azure AI Search index, rename as needed
AZURE_AI_SEARCH_INDEX_NAME = "hotels-sample-index"
async def main() -> None:
ai_agent_settings = AzureAIAgentSettings()
async with (
AzureCliCredential() as creds,
AzureAIAgent.create_client(credential=creds, endpoint=ai_agent_settings.endpoint) as client,
):
ai_search_conn_id = ""
async for connection in client.connections.list():
if connection.type == ConnectionType.AZURE_AI_SEARCH:
ai_search_conn_id = connection.id
break
ai_search = AzureAISearchTool(index_connection_id=ai_search_conn_id, index_name=AZURE_AI_SEARCH_INDEX_NAME)
# Create agent definition
agent_definition = await client.agents.create_agent(
model=ai_agent_settings.model_deployment_name,
instructions="Answer questions about hotels using your index.",
tools=ai_search.definitions,
tool_resources=ai_search.resources,
headers={"x-ms-enable-preview": "true"},
)
# Create the AzureAI Agent
agent = AzureAIAgent(
client=client,
definition=agent_definition,
)
# Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: AzureAIAgentThread = None
user_inputs = [
"Which hotels are available with full-sized kitchens in Nashville, TN?",
"Fun hotels with free WiFi.",
]
try:
for user_input in user_inputs:
print(f"# User: '{user_input}'\n")
# Invoke the agent for the specified thread
async for response in agent.invoke(messages=user_input, thread=thread):
print(f"# Agent: {response}\n")
thread = response.thread
finally:
# Cleanup: Delete the thread and agent
await thread.delete() if thread else None
await client.agents.delete_agent(agent.id)
"""
Sample output:
# User: 'Which hotels are available with full-sized kitchens in Nashville, TN?'
# Agent: In Nashville, TN, there are several hotels available that feature full-sized kitchens:
1. **Extended-Stay Hotel Options**:
- Many extended-stay hotels offer suites equipped with full-sized kitchens, which include cookware and
appliances. These hotels are designed for longer stays, making them a great option for those needing more space
and kitchen facilities【3:0†source】【3:1†source】.
2. **Amenities Included**:
- Most of these hotels provide additional amenities like free Wi-Fi, laundry services, fitness centers, and some
have on-site dining options【3:1†source】【3:2†source】.
3. **Location**:
- The extended-stay hotels are often located near downtown Nashville, making it convenient for guests to
explore the vibrant local music scene while enjoying the comfort of a home-like
environment【3:0†source】【3:4†source】.
If you are looking for specific names or more detailed options, I can further assist you with that!
# User: 'Fun hotels with free WiFi.'
# Agent: Here are some fun hotels that offer free WiFi:
1. **Vibrant Downtown Hotel**:
- Located near the heart of downtown, this hotel offers a warm atmosphere with free WiFi and even provides a
delightful milk and cookies treat【7:2†source】.
2. **Extended-Stay Options**:
- These hotels often feature fun amenities such as a bowling alley, fitness center, and themed rooms. They also
provide free WiFi and are well-situated near local attractions【7:0†source】【7:1†source】.
3. **Luxury Hotel**:
- Ranked highly by Traveler magazine, this 5-star luxury hotel boasts the biggest rooms in the city, free WiFi,
espresso in the room, and flexible check-in/check-out options【7:1†source】.
4. **Budget-Friendly Hotels**:
- Several budget hotels offer free WiFi, breakfast, and shuttle services to nearby attractions and airports
while still providing a fun stay【7:3†source】.
These options ensure you stay connected while enjoying your visit! If you need more specific recommendations or
details, feel free to ask!
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,110 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.ai.agents.models import BingGroundingTool
from azure.identity.aio import AzureCliCredential
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings, AzureAIAgentThread
from semantic_kernel.contents import (
AnnotationContent,
ChatMessageContent,
FunctionCallContent,
FunctionResultContent,
)
"""
The following sample demonstrates how to create an Azure AI agent that
uses the Bing grounding tool to answer a user's question.
Note: Please visit the following link to learn more about the Bing grounding tool:
https://learn.microsoft.com/en-us/azure/ai-services/agents/how-to/tools/bing-grounding?tabs=python&pivots=overview
"""
TASK = "Which team won the 2025 NCAA basketball championship?"
async def handle_intermediate_steps(message: ChatMessageContent) -> None:
for item in message.items or []:
if isinstance(item, FunctionResultContent):
print(f"Function Result:> {item.result} for function: {item.name}")
elif isinstance(item, FunctionCallContent):
print(f"Function Call:> {item.name} with arguments: {item.arguments}")
else:
print(f"{item}")
async def main() -> None:
async with (
AzureCliCredential() as creds,
AzureAIAgent.create_client(credential=creds) as client,
):
# 1. Enter your Bing Grounding Connection Name
bing_connection = await client.connections.get(name="<your-bing-grounding-connection-name>")
conn_id = bing_connection.id
# 2. Initialize agent bing tool and add the connection id
bing_grounding = BingGroundingTool(connection_id=conn_id)
# 3. Create an agent with Bing grounding on the Azure AI agent service
agent_definition = await client.agents.create_agent(
name="BingGroundingAgent",
instructions="Use the Bing grounding tool to answer the user's question.",
model=AzureAIAgentSettings().model_deployment_name,
tools=bing_grounding.definitions,
)
# 4. Create a Semantic Kernel agent for the Azure AI agent
agent = AzureAIAgent(
client=client,
definition=agent_definition,
)
# 5. Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: AzureAIAgentThread | None = None
try:
print(f"# User: '{TASK}'")
# 6. Invoke the agent for the specified thread for response
async for response in agent.invoke(
messages=TASK, thread=thread, on_intermediate_message=handle_intermediate_steps
):
print(f"# {response.name}: {response}")
thread = response.thread
# 7. Show annotations
if any(isinstance(item, AnnotationContent) for item in response.items):
for annotation in response.items:
if isinstance(annotation, AnnotationContent):
print(
f"Annotation :> {annotation.url}, source={annotation.quote}, with "
f"start_index={annotation.start_index} and end_index={annotation.end_index}"
)
finally:
# 8. Cleanup: Delete the thread and agent
await thread.delete() if thread else None
await client.agents.delete_agent(agent.id)
"""
Sample Output:
# User: 'Which team won the 2025 NCAA basketball championship?'
Function Call:> bing_grounding with arguments:
{
'requesturl': 'https://api.bing.microsoft.com/v7.0/search?q=search(query:2025 NCAA basketball championship winner)',
'response_metadata': "{'market': 'en-US', 'num_docs_retrieved': 5, 'num_docs_actually_used': 5}"
}
# BingGroundingAgent: The team that won the 2025 NCAA men's basketball championship was the Florida Gators. They defeated the Houston Cougars with a final score of 65-63.
The championship game took place in San Antonio, Texas, and the Florida team was coached by Todd Golden. This victory made Florida the national champion for the 2024-25
NCAA Division I men's basketball season【3:0†source】【3:1†source】【3:2†source】.
Annotation :> https://en.wikipedia.org/wiki/2025_NCAA_Division_I_men%27s_basketball_championship_game, source=【3:0†source】, with start_index=357 and end_index=369
Annotation :> https://www.ncaa.com/history/basketball-men/d1, source=【3:1†source】, with start_index=369 and end_index=381
Annotation :> https://sports.yahoo.com/article/won-march-madness-2025-ncaa-100551421.html, source=【3:2†source】, with start_index=381 and end_index=393
""" # noqa: E501
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,117 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.ai.agents.models import BingGroundingTool
from azure.identity.aio import AzureCliCredential
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings, AzureAIAgentThread
from semantic_kernel.contents import (
ChatMessageContent,
FunctionCallContent,
FunctionResultContent,
StreamingAnnotationContent,
)
"""
The following sample demonstrates how to create an Azure AI agent that
uses the Bing grounding tool to answer a user's question.
Additionally, the `on_intermediate_message` callback is used to handle intermediate messages
from the agent.
Note: Please visit the following link to learn more about the Bing grounding tool:
https://learn.microsoft.com/en-us/azure/ai-services/agents/how-to/tools/bing-grounding?tabs=python&pivots=overview
"""
TASK = "Which team won the 2025 NCAA basketball championship?"
intermediate_steps: list[ChatMessageContent] = []
async def handle_streaming_intermediate_steps(message: ChatMessageContent) -> None:
for item in message.items or []:
if isinstance(item, FunctionResultContent):
print(f"Function Result:> {item.result} for function: {item.name}")
elif isinstance(item, FunctionCallContent):
print(f"Function Call:> {item.name} with arguments: {item.arguments}")
else:
print(f"{item}")
async def main() -> None:
async with (
AzureCliCredential() as creds,
AzureAIAgent.create_client(credential=creds) as client,
):
# 1. Enter your Bing Grounding Connection Name
bing_connection = await client.connections.get(name="<your-bing-grounding-connection-name>")
conn_id = bing_connection.id
# 2. Initialize agent bing tool and add the connection id
bing_grounding = BingGroundingTool(connection_id=conn_id)
# 3. Create an agent with Bing grounding on the Azure AI agent service
agent_definition = await client.agents.create_agent(
name="BingGroundingAgent",
instructions="Use the Bing grounding tool to answer the user's question.",
model=AzureAIAgentSettings().model_deployment_name,
tools=bing_grounding.definitions,
)
# 4. Create a Semantic Kernel agent for the Azure AI agent
agent = AzureAIAgent(
client=client,
definition=agent_definition,
)
# 5. Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: AzureAIAgentThread | None = None
try:
print(f"# User: '{TASK}'")
# 6. Invoke the agent for the specified thread for response
first_chunk = True
async for response in agent.invoke_stream(
messages=TASK, thread=thread, on_intermediate_message=handle_streaming_intermediate_steps
):
if first_chunk:
print(f"# {response.name}: ", end="", flush=True)
first_chunk = False
print(f"{response}", end="", flush=True)
thread = response.thread
# 7. Show annotations
if any(isinstance(item, StreamingAnnotationContent) for item in response.items):
print()
for annotation in response.items:
if isinstance(annotation, StreamingAnnotationContent):
print(
f"Annotation :> {annotation.url}, source={annotation.quote}, with "
f"start_index={annotation.start_index} and end_index={annotation.end_index}"
)
finally:
# 8. Cleanup: Delete the thread and agent
await thread.delete() if thread else None
await client.agents.delete_agent(agent.id)
"""
Sample Output:
# User: 'Which team won the 2025 NCAA basketball championship?'
Function Call:> bing_grounding with arguments: {'requesturl': 'https://api.bing.microsoft.com/v7.0/search?q=search(query: 2025 NCAA basketball championship winner)'}
Function Call:> bing_grounding with arguments: {'response_metadata': "{'market': 'en-US', 'num_docs_retrieved': 5, 'num_docs_actually_used': 5}"}
# BingGroundingAgent: The Florida Gators won the 2025 NCAA men's basketball championship. They defeated the Houston Cougars with a close score of 65-63 in the championship game held in San Antonio, Texas. This victory marked their third national title. Florida overcame a 12-point deficit during the game to claim the championship【3:0†source】
Annotation :> https://en.wikipedia.org/wiki/2025_NCAA_Division_I_men%27s_basketball_championship_game, source=None, with start_index=308 and end_index=320
【3:1†source】
Annotation :> https://www.ncaa.com/history/basketball-men/d1, source=None, with start_index=320 and end_index=332
【3:2†source】
Annotation :> https://sports.yahoo.com/article/florida-gators-win-2025-ncaa-034021303.html, source=None, with start_index=332 and end_index=344.
""" # noqa: E501
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,139 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from functools import reduce
from azure.ai.agents.models import CodeInterpreterTool
from azure.identity.aio import AzureCliCredential
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings, AzureAIAgentThread
from semantic_kernel.contents import ChatMessageContent, StreamingChatMessageContent
"""
The following sample demonstrates how to create an Azure AI agent that
uses the code interpreter tool and returns streaming responses to answer a coding question.
Additionally, the `on_intermediate_message` callback is used to handle intermediate messages
from the agent.
"""
TASK = "Use code to determine the values in the Fibonacci sequence that that are less then the value of 101."
intermediate_steps: list[ChatMessageContent] = []
async def handle_streaming_intermediate_steps(message: ChatMessageContent) -> None:
intermediate_steps.append(message)
async def main() -> None:
async with (
AzureCliCredential() as creds,
AzureAIAgent.create_client(credential=creds) as client,
):
# 1. Create an agent with a code interpreter on the Azure AI agent service
code_interpreter = CodeInterpreterTool()
agent_definition = await client.agents.create_agent(
model=AzureAIAgentSettings().model_deployment_name,
tools=code_interpreter.definitions,
tool_resources=code_interpreter.resources,
)
# 2. Create a Semantic Kernel agent for the Azure AI agent
agent = AzureAIAgent(
client=client,
definition=agent_definition,
)
# 3. Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: AzureAIAgentThread | None = None
try:
print(f"# User: '{TASK}'")
# 4. Invoke the agent for the specified thread for response
is_code = False
last_role = None
async for response in agent.invoke_stream(
messages=TASK, thread=thread, on_intermediate_message=handle_streaming_intermediate_steps
):
current_is_code = response.metadata.get("code", False)
if current_is_code:
if not is_code:
print("\n\n```python")
is_code = True
print(response.content, end="", flush=True)
else:
if is_code:
print("\n```")
is_code = False
last_role = None
if hasattr(response, "role") and response.role is not None and last_role != response.role:
print(f"\n# {response.role}: ", end="", flush=True)
last_role = response.role
print(response.content, end="", flush=True)
thread = response.thread
if is_code:
print("```\n")
print()
finally:
# 6. Cleanup: Delete the thread and agent
await thread.delete() if thread else None
await client.agents.delete_agent(agent.id)
print("====================================================")
print("\nResponse complete:\n")
# Combine the intermediate `StreamingChatMessageContent` chunks into a single message
filtered_steps = [step for step in intermediate_steps if isinstance(step, StreamingChatMessageContent)]
streaming_full_completion: StreamingChatMessageContent = reduce(lambda x, y: x + y, filtered_steps)
# Grab the other messages that are not `StreamingChatMessageContent`
other_steps = [s for s in intermediate_steps if not isinstance(s, StreamingChatMessageContent)]
final_msgs = [streaming_full_completion] + other_steps
for msg in final_msgs:
print(f"{msg.content}")
r"""
Sample Output:
# User: 'Use code to determine the values in the Fibonacci sequence that that are less then the value of 101.'
```python
def fibonacci_sequence(limit):
fib_sequence = []
a, b = 0, 1
while a < limit:
fib_sequence.append(a)
a, b = b, a + b
return fib_sequence
# Get Fibonacci sequence values less than 101
fibonacci_values = fibonacci_sequence(101)
fibonacci_values
```
# AuthorRole.ASSISTANT: The values in the Fibonacci sequence that are less than 101 are:
\[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89\]
====================================================
Response complete:
def fibonacci_sequence(limit):
fib_sequence = []
a, b = 0, 1
while a < limit:
fib_sequence.append(a)
a, b = b, a + b
return fib_sequence
# Get Fibonacci sequence values less than 101
fibonacci_values = fibonacci_sequence(101)
fibonacci_values
The values in the Fibonacci sequence that are less than 101 are:
\[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89\]
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,94 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity.aio import AzureCliCredential
from semantic_kernel.agents import AgentRegistry, AzureAIAgent, AzureAIAgentSettings
from semantic_kernel.contents.chat_message_content import ChatMessageContent
from semantic_kernel.contents.function_call_content import FunctionCallContent
from semantic_kernel.contents.function_result_content import FunctionResultContent
"""
The following sample demonstrates how to create an Azure AI agent that answers
user questions using the Azure AI Search tool.
The agent is created using a YAML declarative spec that configures the
Azure AI Search tool. The agent is then used to answer user questions
that required grounding context from the Azure AI Search index.
Note: the `AzureAISearchConnectionId` is in the format of:
/subscriptions/<sub-id>/resourceGroups/<rg>/providers/Microsoft.MachineLearningServices/workspaces/<workspace>/connections/AzureAISearch
It can either be configured as an env var `AZURE_AI_AGENT_BING_CONNECTION_ID` or passed in as an extra to
`create_from_yaml`: extras={
"AzureAISearchConnectionId": "<azure_ai_search_connection_id>",
"AzureAISearchIndexName": "<azure_ai_search_index_name>"
}
"""
# Define the YAML string for the sample
spec = """
type: foundry_agent
name: AzureAISearchAgent
instructions: Answer questions using your index to provide grounding context.
description: This agent answers questions using AI Search to provide grounding context.
model:
id: ${AzureAI:ChatModelId}
options:
temperature: 0.4
tools:
- type: azure_ai_search
options:
tool_connections:
- ${AzureAI:AzureAISearchConnectionId}
index_name: ${AzureAI:AzureAISearchIndexName}
"""
settings = AzureAIAgentSettings() # ChatModelId comes from .env/env vars
async def main():
async with (
AzureCliCredential() as creds,
AzureAIAgent.create_client(credential=creds) as client,
):
try:
# Create the AzureAI Agent from the YAML spec
# Note: the extras can be provided in the short-format (shown below) or
# in the long-format (as shown in the YAML spec, with the `AzureAI:` prefix).
# The short-format is used here for brevity
agent: AzureAIAgent = await AgentRegistry.create_from_yaml(
yaml_str=spec,
client=client,
settings=settings,
extras={
"AzureAISearchConnectionId": "<azure-ai-search-connection-id>",
"AzureAISearchIndexName": "<azure-ai-search-index-name>",
},
)
# Define the task for the agent
TASK = "What is Semantic Kernel?"
print(f"# User: '{TASK}'")
# Define a callback function to handle intermediate messages
async def on_intermediate_message(message: ChatMessageContent):
if message.items:
for item in message.items:
if isinstance(item, FunctionCallContent):
print(f"# FunctionCallContent: arguments={item.arguments}")
elif isinstance(item, FunctionResultContent):
print(f"# FunctionResultContent: result={item.result}")
# Invoke the agent for the specified task
async for response in agent.invoke(messages=TASK, on_intermediate_message=on_intermediate_message):
print(f"# {response.name}: {response}")
finally:
# Cleanup: Delete the agent
await client.agents.delete_agent(agent.id)
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,82 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity.aio import AzureCliCredential
from semantic_kernel.agents import AgentRegistry, AzureAIAgent, AzureAIAgentSettings
"""
The following sample demonstrates how to create an Azure AI agent that answers
user questions using the Bing Grounding tool.
The agent is created using a YAML declarative spec that configures the
Bing Grounding tool. The agent is then used to answer user questions
that require web search to answer correctly.
Note: the `BingConnectionId` is in the format of:
/subscriptions/<sub_id>/resourceGroups/<rg>/providers/Microsoft.MachineLearningServices/workspaces/<workspace>/connections/<bing_connection_id>
It can either be configured as an env var `AZURE_AI_AGENT_BING_CONNECTION_ID` or passed in as an extra to
`create_from_yaml`: extras={"BingConnectionId": "<bing_connection_id>"}
"""
# Define the YAML string for the sample
spec = """
type: foundry_agent
name: BingAgent
instructions: Answer questions using Bing to provide grounding context.
description: This agent answers questions using Bing to provide grounding context.
model:
id: ${AzureAI:ChatModelId}
options:
temperature: 0.4
tools:
- type: bing_grounding
options:
tool_connections:
- ${AzureAI:BingConnectionId}
"""
settings = AzureAIAgentSettings() # ChatModelId & BingConnectionId come from .env/env vars
async def main():
async with (
AzureCliCredential() as creds,
AzureAIAgent.create_client(credential=creds) as client,
):
try:
# Create the AzureAI Agent from the YAML spec
agent: AzureAIAgent = await AgentRegistry.create_from_yaml(
yaml_str=spec,
client=client,
settings=settings,
)
# Define the task for the agent
TASK = "Who won the 2025 NCAA basketball championship?"
print(f"# User: '{TASK}'")
# Invoke the agent for the specified task
async for response in agent.invoke(
messages=TASK,
):
print(f"# {response.name}: {response}")
finally:
# Cleanup: Delete the thread and agent
await client.agents.delete_agent(agent.id)
"""
Sample output:
# User: 'Who won the 2025 NCAA basketball championship?'
# BingAgent: The Florida Gators won the 2025 NCAA men's basketball championship, narrowly defeating the Houston
Cougars 65-63 in the final game. This marked Florida's first national title since
2007【3:5†source】【3:9†source】.
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,149 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from azure.ai.agents.models import FilePurpose
from azure.identity.aio import AzureCliCredential
from semantic_kernel.agents import AgentRegistry, AzureAIAgent, AzureAIAgentSettings
"""
The following sample demonstrates how to create an Azure AI agent that answers
user questions using the code interpreter tool.
The agent is then used to answer user questions that require code to be generated and
executed. The responses are handled in a streaming manner.
"""
# Define the YAML string for the sample
spec = """
type: foundry_agent
name: CodeInterpreterAgent
description: Agent with code interpreter tool.
instructions: >
Use the code interpreter tool to answer questions that require code to be generated
and executed.
model:
id: ${AzureAI:ChatModelId}
connection:
endpoint: ${AzureAI:Endpoint}
tools:
- type: code_interpreter
options:
file_ids:
- ${AzureAI:FileId1}
"""
settings = AzureAIAgentSettings() # ChatModelId & Endpoint come from env vars
async def main():
async with (
AzureCliCredential() as creds,
AzureAIAgent.create_client(credential=creds) as client,
):
# Create the CSV file path for the sample
csv_file_path = os.path.join(
os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))),
"resources",
"agent_assistant_file_manipulation",
"sales.csv",
)
try:
# Upload the CSV file to the agent service
file = await client.agents.files.upload_and_poll(file_path=csv_file_path, purpose=FilePurpose.AGENTS)
# Create the AzureAI Agent from the YAML spec
# Note: the extras can be provided in the short-format (shown below) or
# in the long-format (as shown in the YAML spec, with the `AzureAI:` prefix).
# The short-format is used here for brevity
agent: AzureAIAgent = await AgentRegistry.create_from_yaml(
yaml_str=spec,
client=client,
settings=settings,
extras={"FileId1": file.id},
)
# Define the task for the agent
TASK = "Give me the code to calculate the total sales for all segments."
print(f"# User: '{TASK}'")
# Invoke the agent for the specified task
is_code = False
last_role = None
async for response in agent.invoke_stream(
messages=TASK,
):
current_is_code = response.metadata.get("code", False)
if current_is_code:
if not is_code:
print("\n\n```python")
is_code = True
print(response.content, end="", flush=True)
else:
if is_code:
print("\n```")
is_code = False
last_role = None
if hasattr(response, "role") and response.role is not None and last_role != response.role:
print(f"\n# {response.role}: ", end="", flush=True)
last_role = response.role
print(response.content, end="", flush=True)
if is_code:
print("```\n")
print()
finally:
# Cleanup: Delete the thread and agent
await client.agents.delete_agent(agent.id)
await client.agents.files.delete(file.id)
"""
Sample output:
# User: 'Give me the code to calculate the total sales for all segments.'
# AuthorRole.ASSISTANT: Let me first examine the contents of the uploaded file to determine its structure. This
will allow me to create the appropriate code for calculating the total sales for all segments. Hang tight!
```python
import pandas as pd
# Load the uploaded file to examine its contents
file_path = '/mnt/data/assistant-3nXizu2EX2EwXikUz71uNc'
data = pd.read_csv(file_path)
# Display the first few rows and column names to understand the structure of the dataset
data.head(), data.columns
```
# AuthorRole.ASSISTANT: The dataset contains several columns, including `Segment`, `Sales`, and others such as
`Country`, `Product`, and date-related information. To calculate the total sales for all segments, we will:
1. Group the data by the `Segment` column.
2. Sum the `Sales` column for each segment.
3. Calculate the grand total of all sales across all segments.
Here is the code snippet for this task:
```python
# Group by 'Segment' and sum up 'Sales'
segment_sales = data.groupby('Segment')['Sales'].sum()
# Calculate the total sales across all segments
total_sales = segment_sales.sum()
print("Total Sales per Segment:")
print(segment_sales)
print(f"\nGrand Total Sales: {total_sales}")
```
Would you like me to execute this directly for the uploaded data?
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,96 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from azure.ai.agents.models import VectorStore
from azure.identity.aio import AzureCliCredential
from semantic_kernel.agents import AgentRegistry, AzureAIAgent, AzureAIAgentSettings
"""
The following sample demonstrates how to create an Azure AI agent that answers
user questions using the file search tool from a declarative spec.
"""
# Define the YAML string for the sample
spec = """
type: foundry_agent
name: FileSearchAgent
description: Agent with file search tool.
instructions: >
Use the file search tool to answer questions from the user.
model:
id: ${AzureAI:ChatModelId}
connection:
endpoint: ${AzureAI:Endpoint}
tools:
- type: file_search
options:
vector_store_ids:
- ${AzureAI:VectorStoreId}
"""
settings = AzureAIAgentSettings() # ChatModelId & Endpoint come from .env/env vars
async def main():
async with (
AzureCliCredential() as creds,
AzureAIAgent.create_client(credential=creds) as client,
):
# Read and upload the file to the Azure AI agent service
pdf_file_path = os.path.join(
os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))),
"resources",
"file_search",
"employees.pdf",
)
# Upload the pdf file to the agent service
file = await client.agents.files.upload_and_poll(file_path=pdf_file_path, purpose="assistants")
vector_store: VectorStore = await client.agents.vector_stores.create(file_ids=[file.id], name="my_vectorstore")
try:
# Create the AzureAI Agent from the YAML spec
# Note: the extras can be provided in the short-format (shown below) or
# in the long-format (as shown in the YAML spec, with the `AzureAI:` prefix).
# The short-format is used here for brevity
agent: AzureAIAgent = await AgentRegistry.create_from_yaml(
yaml_str=spec,
client=client,
settings=settings,
extras={"VectorStoreId": vector_store.id},
)
# Define the task for the agent
TASK = "Who can help me if I have a sales question?"
print(f"# User: '{TASK}'")
# Invoke the agent for the specified task
async for response in agent.invoke(
messages=TASK,
):
print(f"# {response.name}: {response}")
finally:
# Cleanup: Delete the agent, vector store, and file
await client.agents.delete_agent(agent.id)
await client.agents.vector_stores.delete(vector_store.id)
await client.agents.files.delete(file.id)
"""
Sample output:
# User: 'Who can help me if I have a sales question?'
# FileSearchAgent: If you have a sales question, you may contact the following individuals:
1. **Hicran Bea** - Sales Manager
2. **Mariam Jaslyn** - Sales Representative
3. **Angelino Embla** - Sales Representative
This information comes from the employee records【4:0†source】.
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,90 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from typing import Annotated
from azure.identity.aio import AzureCliCredential
from semantic_kernel.agents import AgentRegistry, AzureAIAgent, AzureAIAgentSettings, AzureAIAgentThread
from semantic_kernel.functions.kernel_function_decorator import kernel_function
"""
The following sample demonstrates how to create an Azure AI agent that answers
user questions. The sample shows how to load a declarative spec from a file.
The plugins/functions must already exist in the kernel.
They are not created declaratively via the spec.
"""
class MenuPlugin:
"""A sample Menu Plugin used for the concept sample."""
@kernel_function(description="Provides a list of specials from the menu.")
def get_specials(self) -> Annotated[str, "Returns the specials from the menu."]:
return """
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
"""
@kernel_function(description="Provides the price of the requested menu item.")
def get_item_price(
self, menu_item: Annotated[str, "The name of the menu item."]
) -> Annotated[str, "Returns the price of the menu item."]:
return "$9.99"
async def main():
async with (
AzureCliCredential() as creds,
AzureAIAgent.create_client(credential=creds) as client,
):
try:
# Define the YAML file path for the sample
file_path = os.path.join(
os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))),
"resources",
"declarative_spec",
"spec.yaml",
)
# Create the AzureAI Agent from the YAML spec
agent: AzureAIAgent = await AgentRegistry.create_from_file(
file_path,
plugins=[MenuPlugin()],
client=client,
settings=AzureAIAgentSettings(), # The Spec's ChatModelId & Endpoint come from .env/env vars
)
# Create the agent
user_inputs = [
"Hello",
"What is the special soup?",
"How much does that cost?",
"Thank you",
]
# Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: AzureAIAgentThread | None = None
for user_input in user_inputs:
print(f"# User: '{user_input}'")
# Invoke the agent for the specified task
async for response in agent.invoke(
messages=user_input,
thread=thread,
):
print(f"# {response.name}: {response}")
# Store the thread for the next iteration
thread = response.thread
finally:
# Cleanup: Delete the thread and agent
await client.agents.delete_agent(agent.id) if agent else None
await thread.delete() if thread else None
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,196 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity.aio import AzureCliCredential
from semantic_kernel.agents import AgentRegistry, AzureAIAgent, AzureAIAgentSettings
"""
The following sample demonstrates how to create an Azure AI agent that answers
user questions using the OpenAPI tool. The agent is then used to answer user
questions that leverage a free weather API.
"""
# Toggle between a JSON or a YAML OpenAPI spec
USE_JSON_OPENAPI_SPEC = True
json_openapi_spec = """
type: foundry_agent
name: WeatherAgent
instructions: Answer questions about the weather. For all other questions politely decline to answer.
description: This agent answers question about the weather.
model:
id: ${AzureAI:ChatModelId}
connection:
endpoint: ${AzureAI:Endpoint}
options:
temperature: 0.4
tools:
- type: openapi
id: GetCurrentWeather
description: Retrieves current weather data for a location based on wttr.in.
options:
specification: |
{
"openapi": "3.1.0",
"info": {
"title": "Get Weather Data",
"description": "Retrieves current weather data for a location based on wttr.in.",
"version": "v1.0.0"
},
"servers": [
{
"url": "https://wttr.in"
}
],
"auth": [],
"paths": {
"/{location}": {
"get": {
"description": "Get weather information for a specific location",
"operationId": "GetCurrentWeather",
"parameters": [
{
"name": "location",
"in": "path",
"description": "City or location to retrieve the weather for",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "format",
"in": "query",
"description": "Always use j1 value for this parameter",
"required": true,
"schema": {
"type": "string",
"default": "j1"
}
}
],
"responses": {
"200": {
"description": "Successful response",
"content": {
"text/plain": {
"schema": {
"type": "string"
}
}
}
},
"404": {
"description": "Location not found"
}
},
"deprecated": false
}
}
},
"components": {
"schemes": {}
}
}
"""
yaml_openapi_spec = """
type: foundry_agent
name: WeatherAgent
instructions: Answer questions about the weather. For all other questions politely decline to answer.
description: This agent answers question about the weather.
model:
id: ${AzureAI:ChatModelId}
options:
temperature: 0.4
tools:
- type: openapi
id: GetCurrentWeather
description: Retrieves current weather data for a location based on wttr.in.
options:
specification:
openapi: "3.1.0"
info:
title: "Get Weather Data"
description: "Retrieves current weather data for a location based on wttr.in."
version: "v1.0.0"
servers:
- url: "https://wttr.in"
auth: []
paths:
"/{location}":
get:
description: "Get weather information for a specific location"
operationId: "GetCurrentWeather"
parameters:
- name: "location"
in: "path"
description: "City or location to retrieve the weather for"
required: true
schema:
type: "string"
- name: "format"
in: "query"
description: "Always use j1 value for this parameter"
required: true
schema:
type: "string"
default: "j1"
responses:
"200":
description: "Successful response"
content:
text/plain:
schema:
type: "string"
"404":
description: "Location not found"
deprecated: false
components:
schemes: {}
"""
settings = AzureAIAgentSettings() # ChatModelId & Endpoint come from .env/env vars
async def main():
async with (
AzureCliCredential() as creds,
AzureAIAgent.create_client(credential=creds) as client,
):
try:
# Create the AzureAI Agent from the YAML spec
agent: AzureAIAgent = await AgentRegistry.create_from_yaml(
yaml_str=json_openapi_spec if USE_JSON_OPENAPI_SPEC else yaml_openapi_spec,
client=client,
settings=settings,
)
# Define the task for the agent
TASK = "What is the current weather in Seoul?"
print(f"# User: '{TASK}'")
# Invoke the agent for the specified task
async for response in agent.invoke(
messages=TASK,
):
print(f"# {response.name}: {response}")
finally:
# Cleanup: Delete the agent, vector store, and file
await client.agents.delete_agent(agent.id)
"""
Sample output:
# User: 'What is the current weather in Seoul?'
# WeatherAgent: The current weather in Seoul is 14°C (57°F) with "light drizzle." It feels like 13°C (55°F).
The humidity is at 81%, and there is heavy cloud cover (99%). The visibility is reduced to 2 km (1 mile),
and the wind is coming from the east at 11 km/h (7 mph)
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,72 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity.aio import AzureCliCredential
from semantic_kernel.agents import AgentRegistry, AzureAIAgent
"""
The following sample demonstrates how to create an Azure AI Agent that invokes
a story generation task using a prompt template and a declarative spec.
"""
# Define the YAML string for the sample
spec = """
type: foundry_agent
name: StoryAgent
description: An agent that generates a story about a topic.
instructions: Tell a story about {{$topic}} that is {{$length}} sentences long.
model:
id: ${AzureAI:ChatModelId}
connection:
connection_string: ${AzureAI:Endpoint}
inputs:
topic:
description: The topic of the story.
required: true
default: Cats
length:
description: The number of sentences in the story.
required: true
default: 2
outputs:
output1:
description: The generated story.
template:
format: semantic-kernel
"""
async def main():
async with (
AzureCliCredential() as creds,
AzureAIAgent.create_client(credential=creds) as client,
):
try:
# Create the AzureAI Agent from the YAML spec
agent: AzureAIAgent = await AgentRegistry.create_from_yaml(
yaml_str=spec,
client=client,
)
# Invoke the agent for the specified task
async for response in agent.invoke(
messages=None,
):
print(f"# {response.name}: {response}")
finally:
# Cleanup: Delete the agent, vector store, and file
await client.agents.delete_agent(agent.id)
"""
Sample output:
# StoryAgent: Under the silvery moon, three mischievous cats tiptoed across the rooftop, chasing
shadows and sharing secret whispers. By dawn, they curled up together, purring softly, dreaming
of adventures yet to come.
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,69 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity.aio import AzureCliCredential
from semantic_kernel.agents import AgentRegistry, AzureAIAgent
"""
The following sample demonstrates how to create an Azure AI agent based
on an existing agent ID.
"""
# Define the YAML string for the sample
spec = """
id: ${AzureAI:AgentId}
type: foundry_agent
instructions: You are helpful agent who always responds in French.
"""
async def main():
async with (
AzureCliCredential() as creds,
AzureAIAgent.create_client(credential=creds) as client,
):
try:
# Create the AzureAI Agent from the YAML spec
# Note: the extras can be provided in the short-format (shown below) or
# in the long-format (as shown in the YAML spec, with the `AzureAI:` prefix).
# The short-format is used here for brevity
agent: AzureAIAgent = await AgentRegistry.create_from_yaml(
yaml_str=spec,
client=client,
extras={"AgentId": "<my-agent-id>"}, # Specify the existing agent ID
)
# Define the task for the agent
TASK = "Why is the sky blue?"
print(f"# User: '{TASK}'")
# Invoke the agent for the specified task
async for response in agent.invoke(
messages=TASK,
):
print(f"# {response.name}: {response}")
finally:
# Cleanup: Delete the thread and agent
await client.agents.delete_agent(agent.id)
"""
Sample output:
# User: 'Why is the sky blue?'
# WeatherAgent: Le ciel est bleu à cause d'un phénomène appelé **diffusion de Rayleigh**. La lumière du
Soleil est composée de toutes les couleurs du spectre visible, mais lorsqu'elle traverse l'atmosphère
terrestre, elle entre en contact avec les molécules d'air et les particules présentes.
Les couleurs à courtes longueurs d'onde, comme le bleu et le violet, sont diffusées dans toutes les directions
beaucoup plus efficacement que les couleurs à longues longueurs d'onde, comme le rouge et l'orange. Bien que le
violet ait une longueur d'onde encore plus courte que le bleu, nos yeux sont moins sensibles à cette couleur,
et une partie du violet est également absorbée par la haute atmosphère. Ainsi, le bleu domine, donnant au ciel
sa couleur caractéristique.
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,155 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.ai.agents.models import DeepResearchTool
from azure.identity.aio import AzureCliCredential
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings, AzureAIAgentThread
from semantic_kernel.contents import (
ChatMessageContent,
FunctionCallContent,
FunctionResultContent,
StreamingAnnotationContent,
)
"""
The following sample demonstrates how to create an AzureAIAgent along
with the Deep Research Tool. Please visit the following documentation for more info
on what is required to run the sample: https://aka.ms/agents-deep-research. Please pay
attention to the purple `Note` boxes in the Azure docs.
Note that when you use your Bing Connection ID, it needs to be the connection ID from the project, not the resource.
It has the following format:
'/subscriptions/<sub_id>/resourceGroups/<rg_name>/providers/<provider_name>/accounts/<account_name>/projects/<project_name>/connections/<connection_name>'
"""
TASK = (
"Research the current state of studies on orca intelligence and orca language, "
"including what is currently known about orcas' cognitive capabilities and communication systems."
)
async def handle_intermediate_messages(message: ChatMessageContent) -> None:
for item in message.items or []:
if isinstance(item, FunctionResultContent):
print(f"Function Result:> {item.result} for function: {item.name}")
elif isinstance(item, FunctionCallContent):
print(f"Function Call:> {item.name} with arguments: {item.arguments}")
elif isinstance(item, StreamingAnnotationContent):
label = item.title or item.url or "Annotation"
print(f"Annotation:> {label} ({item.citation_type}) -> {item.url}")
else:
print(f"{item}")
async def main() -> None:
async with (
AzureCliCredential() as creds,
AzureAIAgent.create_client(credential=creds) as client,
):
azure_ai_agent_settings = AzureAIAgentSettings()
# 1. Define the Deep Research tool
deep_research_tool = DeepResearchTool(
bing_grounding_connection_id=azure_ai_agent_settings.bing_connection_id,
deep_research_model=azure_ai_agent_settings.deep_research_model,
)
# 2. Create an agent with the tool on the Azure AI agent service
agent_definition = await client.agents.create_agent(
model="gpt-4o", # Deep Research requires the use of gpt-4o for scope clarification.
tools=deep_research_tool.definitions,
instructions="You are a helpful Agent that assists in researching scientific topics.",
)
# 3. Create a Semantic Kernel agent for the Azure AI agent
agent = AzureAIAgent(client=client, definition=agent_definition, name="DeepResearchAgent")
# 4. Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: AzureAIAgentThread | None = None
try:
print(f"# User: '{TASK}'")
# 5. Invoke the agent for the specified thread for response
first_chunk = True
async for response in agent.invoke_stream(
messages=TASK,
thread=thread,
on_intermediate_message=handle_intermediate_messages,
):
if first_chunk:
print(f"# {response.name}: ", end="", flush=True)
first_chunk = False
# Print the text chunk
print(f"{response}", end="", flush=True)
# Print any streaming annotations that may arrive in this chunk
for item in response.items or []:
if isinstance(item, StreamingAnnotationContent):
label = item.title or item.url or (item.quote or "Annotation")
print(f"\n[Annotation] {label} -> {item.url}")
thread = response.thread
print()
finally:
# 6. Cleanup: Delete the thread, agent, and file
await thread.delete() if thread else None
await client.agents.delete_agent(agent.id)
"""
Sample Output:
# User: 'Research the current state of studies on orca intelligence and orca language, including what is
currently known about orcas' cognitive capabilities and communication systems.'
Function Call:> deep_research with arguments: {'input': '{"prompt": "Research the current state of studies on
orca intelligence and orca communication, focusing on their cognitive capabilities and language systems.
Provide an overview of key discoveries, critical experiments, and major conclusions about their
intelligence and communication systems. Prioritize primary research papers, reputable academic sources,
and recent updates in the field (from the past 5 years if available). Format as a structured report with
appropriate headings for clarity, and respond in English."}'}
# azure_agent_QhTQHlUs: Title: Current Studies on Orca Intelligence and Communication
Starting deep research...
The user's task is to research orca intelligence, focusing on cognitive capabilities and communication.
【1†Bing Search】
[Annotation] Bing Search: 'orca communication research 2020 killer whale cognitive study' -> https://www.bing.com/search?q=orca%20communication%20research%202020%20killer%20whale%20cognitive%20study
**Weighing options**
I'm examining the research on orca social dynamics, comparing a potential review to a recent journal article
on large-scale unsupervised clustering of orca calls.
**Investigating orca datasets**
OK, let me see. PDF, Interspeech 2020, "ORCA-CLEAN: A Deep Denoising Toolkit for Killer Whale Communication"
seems relevant. They focus on cognitive capabilities, language systems, and communication.
I'm considering if the PDF is relevant and may not need it. ResearchGate's content might need a login
to access. 【1†Bing Search】
[Annotation] Bing Search: '"Social Dynamics and Intelligence of Killer Whales (Orcinus orca)"' -> https://www.bing.com/search?q=%22Social%20Dynamics%20and%20Intelligence%20of%20Killer%20Whales%20%28Orcinus%20orca%29%22
**Evaluating sources**
I'm gathering info on "Social Dynamics and Intelligence of Killer Whales," weighing access to PDFs through
ResearchGate, and considering associated online references for credibility.
**Considering capabilities**
I'm piecing together the intricacies of killer whale creativity under chemical stimuli, as explored
in "Manitzas, Hill, et al 2022." Would love to learn more about their findings.
**Exploring external options**
I'm weighing opening the PDF directly or using an external search. 【1†Bing Search】
[Annotation] Bing Search: 'Manitzas Hill 2022 killer whale creativity cognitive abilities' -> https://www.bing.com/search?q=Manitzas%20Hill%202022%20killer%20whale%20creativity%20cognitive%20abilities
...
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,88 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from azure.ai.agents.models import CodeInterpreterTool, FilePurpose
from azure.identity.aio import AzureCliCredential
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings, AzureAIAgentThread
from semantic_kernel.contents.annotation_content import AnnotationContent
from semantic_kernel.contents.utils.author_role import AuthorRole
"""
The following sample demonstrates how to create a simple,
Azure AI agent that uses the code interpreter tool to answer
a coding question.
"""
async def main() -> None:
ai_agent_settings = AzureAIAgentSettings()
async with (
AzureCliCredential() as creds,
AzureAIAgent.create_client(credential=creds, endpoint=ai_agent_settings.endpoint) as client,
):
csv_file_path = os.path.join(
os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))),
"resources",
"agent_assistant_file_manipulation",
"sales.csv",
)
file = await client.agents.files.upload_and_poll(file_path=csv_file_path, purpose=FilePurpose.AGENTS)
code_interpreter = CodeInterpreterTool(file_ids=[file.id])
# Create agent definition
agent_definition = await client.agents.create_agent(
model=ai_agent_settings.model_deployment_name,
tools=code_interpreter.definitions,
tool_resources=code_interpreter.resources,
)
# Create the AzureAI Agent
agent = AzureAIAgent(
client=client,
definition=agent_definition,
)
# Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: AzureAIAgentThread = None
user_inputs = [
"Which segment had the most sales?",
"List the top 5 countries that generated the most profit.",
"Create a tab delimited file report of profit by each country per month.",
]
try:
for user_input in user_inputs:
print(f"# User: '{user_input}'")
# Invoke the agent for the specified user input
async for response in agent.invoke(messages=user_input, thread=thread):
if response.role != AuthorRole.TOOL:
print(f"# Agent: {response}")
if len(response.items) > 0:
for item in response.items:
# Show Annotation Content if it exist
if isinstance(item, AnnotationContent):
print(f"\n`{item.quote}` => {item.file_id}")
response_content = await client.agents.get_file_content(file_id=item.file_id)
content_bytes = bytearray()
async for chunk in response_content:
content_bytes.extend(chunk)
tab_delimited_text = content_bytes.decode("utf-8")
print(tab_delimited_text)
thread = response.thread
finally:
# Cleanup: Delete the thread and agent
await thread.delete() if thread else None
await client.agents.delete_agent(agent.id)
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,121 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.ai.agents.models import McpTool
from azure.identity.aio import AzureCliCredential
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings, AzureAIAgentThread
from semantic_kernel.contents import ChatMessageContent, FunctionCallContent, FunctionResultContent
"""
The following sample demonstrates how to create a simple, Azure AI agent that
uses the mcp tool to connect to an mcp server with streaming responses.
"""
TASK = "Please summarize the Azure REST API specifications Readme"
async def handle_intermediate_messages(message: ChatMessageContent) -> None:
for item in message.items or []:
if isinstance(item, FunctionResultContent):
print(f"Function Result:> {item.result} for function: {item.name}")
elif isinstance(item, FunctionCallContent):
print(f"Function Call:> {item.name} with arguments: {item.arguments}")
else:
print(f"{item}")
async def main() -> None:
async with (
AzureCliCredential() as creds,
AzureAIAgent.create_client(credential=creds) as client,
):
# 1. Define the MCP tool with the server URL
mcp_tool = McpTool(
server_label="github",
server_url="https://gitmcp.io/Azure/azure-rest-api-specs",
allowed_tools=[], # Specify allowed tools if needed
)
# Optionally you may configure to require approval
# Allowed values are "never" or "always"
mcp_tool.set_approval_mode("never")
# 2. Create an agent with the MCP tool on the Azure AI agent service
agent_definition = await client.agents.create_agent(
model=AzureAIAgentSettings().model_deployment_name,
tools=mcp_tool.definitions,
instructions="You are a helpful agent that can use MCP tools to assist users.",
)
# 3. Create a Semantic Kernel agent for the Azure AI agent
agent = AzureAIAgent(
client=client,
definition=agent_definition,
)
# 4. Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: AzureAIAgentThread | None = None
try:
print(f"# User: '{TASK}'")
# 5. Invoke the agent for the specified thread for response
async for response in agent.invoke_stream(
messages=TASK,
thread=thread,
on_intermediate_message=handle_intermediate_messages,
):
print(f"{response}", end="", flush=True)
thread = response.thread
finally:
# 6. Cleanup: Delete the thread, agent, and file
await thread.delete() if thread else None
await client.agents.delete_agent(agent.id)
"""
Sample Output:
# User: 'Please summarize the Azure REST API specifications Readme'
Function Call:> fetch_azure_rest_api_docs with arguments: {}
The Azure REST API specifications Readme provides comprehensive documentation and guidelines for designing,
authoring, validating, and evolving Azure REST APIs. It covers key areas including:
1. Breaking changes and versioning: Guidelines to manage API changes that break backward compatibility, when to
increment API versions, and how to maintain smooth API evolution.
2. OpenAPI/Swagger specifications: How to author REST APIs using OpenAPI specification 2.0 (Swagger), including
structure, conventions, validation tools, and extensions used by AutoRest for generating client SDKs.
3. TypeSpec language: Introduction to TypeSpec, a powerful language for describing and generating REST API
specifications and client SDKs with extensibility to other API styles.
4. Directory structure and uniform versioning: Organizing service specifications by teams, resource provider
namespaces, and following uniform versioning to keep API versions consistent across documentation and SDKs.
5. Validation and tooling: Tools and processes like OAV, AutoRest, RESTler, and CI checks used to validate API
specs, generate SDKs, detect breaking changes, lint specifications, and test service contract accuracy.
6. Authoring best practices: Manual and automated guidelines for quality API spec authoring, including writing
effective descriptions, resource modeling, naming conventions, and examples.
7. Code generation configurations: How to configure readme files to generate SDKs for various languages
including .NET, Java, Python, Go, Typescript, and Azure CLI using AutoRest.
8. API Scenarios and testing: Defining API scenario test files for end-to-end REST API workflows, including
variables, ARM template integration, and usage of test-proxy for recording traffic.
9. SDK automation and release requests: Workflows for SDK generation validation, suppressing breaking change
warnings, and requesting official Azure SDK releases.
Overall, the Readme acts as a central hub providing references, guidelines, examples, and tools for maintaining
high-quality Azure REST API specifications and seamless SDK generation across multiple languages and
platforms. It ensures consistent API design, versioning, validation, and developer experience in the Azure
ecosystem.
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,132 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from typing import Annotated
from azure.identity.aio import AzureCliCredential
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings, AzureAIAgentThread
from semantic_kernel.contents import FunctionCallContent, FunctionResultContent
from semantic_kernel.contents.chat_message_content import ChatMessageContent
from semantic_kernel.functions import kernel_function
"""
This sample demonstrates how to create an Azure AI Agent and invoke it using the non-streaming `invoke()` method.
While `invoke()` returns only the final assistant message, the agent can optionally emit intermediate messages
(e.g., function calls and results) via a callback by supplying `on_intermediate_message`.
In this example, the agent is configured with a plugin that provides menu specials and item pricing. As the user
asks about the menu, the agent performs tool calls mid-invocation, and those intermediate steps are surfaced
via the callback function while the invocation is still in progress.
"""
# Define a sample plugin for the sample
class MenuPlugin:
"""A sample Menu Plugin used for the concept sample."""
@kernel_function(description="Provides a list of specials from the menu.")
def get_specials(self) -> Annotated[str, "Returns the specials from the menu."]:
return """
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
"""
@kernel_function(description="Provides the price of the requested menu item.")
def get_item_price(
self, menu_item: Annotated[str, "The name of the menu item."]
) -> Annotated[str, "Returns the price of the menu item."]:
return "$9.99"
# This callback function will be called for each intermediate message,
# which will allow one to handle FunctionCallContent and FunctionResultContent.
# If the callback is not provided, the agent will return the final response
# with no intermediate tool call steps.
async def handle_intermediate_steps(message: ChatMessageContent) -> None:
for item in message.items or []:
if isinstance(item, FunctionResultContent):
print(f"Function Result:> {item.result} for function: {item.name}")
elif isinstance(item, FunctionCallContent):
print(f"Function Call:> {item.name} with arguments: {item.arguments}")
else:
print(f"{item}")
async def main() -> None:
ai_agent_settings = AzureAIAgentSettings()
async with (
AzureCliCredential() as creds,
AzureAIAgent.create_client(credential=creds, endpoint=ai_agent_settings.endpoint) as client,
):
AGENT_NAME = "Host"
AGENT_INSTRUCTIONS = "Answer questions about the menu."
# Create agent definition
agent_definition = await client.agents.create_agent(
model=ai_agent_settings.model_deployment_name,
name=AGENT_NAME,
instructions=AGENT_INSTRUCTIONS,
)
# Create the AzureAI Agent
agent = AzureAIAgent(
client=client,
definition=agent_definition,
plugins=[MenuPlugin()], # add the sample plugin to the agent
)
# Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: AzureAIAgentThread = None
user_inputs = [
"Hello",
"What is the special soup?",
"How much does that cost?",
"Thank you",
]
try:
for user_input in user_inputs:
print(f"# User: '{user_input}'")
async for response in agent.invoke(
messages=user_input,
thread=thread,
on_intermediate_message=handle_intermediate_steps,
):
print(f"# Agent: {response}")
thread = response.thread
finally:
# Cleanup: Delete the thread and agent
await thread.delete() if thread else None
await client.agents.delete_agent(agent.id)
"""
Sample Output:
# User: 'Hello'
# Agent: Hi there! How can I assist you today?
# User: 'What is the special soup?'
Function Call:> MenuPlugin-get_specials with arguments: {}
Function Result:>
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
for function: MenuPlugin-get_specials
# Agent: The special soup is Clam Chowder. Would you like to know anything else about the menu?
# User: 'How much does that cost?'
Function Call:> MenuPlugin-get_item_price with arguments: {"menu_item":"Clam Chowder"}
Function Result:> $9.99 for function: MenuPlugin-get_item_price
# Agent: The Clam Chowder costs $9.99. Let me know if you'd like assistance with anything else!
# User: 'Thank you'
# Agent: You're welcome! Enjoy your meal! 😊
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,134 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import logging
from typing import Annotated
from azure.identity.aio import AzureCliCredential
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings, AzureAIAgentThread
from semantic_kernel.contents import ChatMessageContent, FunctionCallContent, FunctionResultContent
from semantic_kernel.core_plugins import MathPlugin
from semantic_kernel.functions import kernel_function
"""
This sample demonstrates how to create an Azure AI Agent and use it with the streaming `invoke_stream()` method.
The agent returns assistant messages as a stream of incremental chunks. In addition, you can specify
an `on_intermediate_message` callback to receive fully-formed tool-related messages — such as function
calls and their results — while the assistant response is still being streamed.
In this example, the agent is configured with a plugin that provides menu specials and item pricing.
As the user interacts with the agent, tool messages (like function calls) are emitted via the callback,
while assistant replies stream back incrementally through the main response loop.
"""
logging.basicConfig(level=logging.DEBUG)
# Define a sample plugin for the sample
class MenuPlugin:
"""A sample Menu Plugin used for the concept sample."""
@kernel_function(description="Provides a list of specials from the menu.")
def get_specials(self) -> Annotated[str, "Returns the specials from the menu."]:
return """
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
"""
@kernel_function(description="Provides the price of the requested menu item.")
def get_item_price(
self, menu_item: Annotated[str, "The name of the menu item."]
) -> Annotated[str, "Returns the price of the menu item."]:
return "$9.99"
# This callback function will be called for each intermediate message,
# which will allow one to handle FunctionCallContent and FunctionResultContent.
# If the callback is not provided, the agent will return the final response
# with no intermediate tool call steps.
async def handle_streaming_intermediate_steps(message: ChatMessageContent) -> None:
for item in message.items or []:
if isinstance(item, FunctionResultContent):
print(f"Function Result:> {item.result} for function: {item.name}")
elif isinstance(item, FunctionCallContent):
print(f"Function Call:> {item.name} with arguments: {item.arguments}")
else:
print(f"{item}")
async def main() -> None:
ai_agent_settings = AzureAIAgentSettings()
async with (
AzureCliCredential() as creds,
AzureAIAgent.create_client(credential=creds, endpoint=ai_agent_settings.endpoint) as client,
):
# Create agent definition
agent_definition = await client.agents.create_agent(
model=ai_agent_settings.model_deployment_name,
name="Host",
instructions="Answer questions from the user using your provided functions. You must invoke multiple functions to answer the user's questions. ", # noqa: E501
)
# Create the AzureAI Agent
agent = AzureAIAgent(
client=client,
definition=agent_definition,
plugins=[MenuPlugin(), MathPlugin()],
)
# Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: AzureAIAgentThread = None
user_inputs = [
"What is the price of the special drink and the special food item added together?",
]
try:
for user_input in user_inputs:
print(f"# User: '{user_input}'")
first_chunk = True
async for response in agent.invoke_stream(
messages=user_input,
thread=thread,
on_intermediate_message=handle_streaming_intermediate_steps,
):
if first_chunk:
print(f"# {response.role}: ", end="", flush=True)
first_chunk = False
print(response.content, end="", flush=True)
thread = response.thread
print()
finally:
# Cleanup: Delete the thread and agent
await thread.delete() if thread else None
await client.agents.delete_agent(agent.id)
"""
Sample Output:
# User: 'What is the price of the special drink and then special food item added together?'
Function Call:> MenuPlugin-get_specials with arguments: {}
Function Result:>
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
for function: MenuPlugin-get_specials
Function Call:> MenuPlugin-get_item_price with arguments: {"menu_item": "Chai Tea"}
Function Call:> MenuPlugin-get_item_price with arguments: {"menu_item": "Clam Chowder"}
Function Result:> $9.99 for function: MenuPlugin-get_item_price
Function Result:> $9.99 for function: MenuPlugin-get_item_price
Function Call:> MathPlugin-Add with arguments: {"input":9.99,"amount":9.99}
Function Result:> 19.98 for function: MathPlugin-Add
# AuthorRole.ASSISTANT: The price of the special drink, Chai Tea, is $9.99 and the price of the special food
item, Clam Chowder, is $9.99. Added together, the total price is $19.98.
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,111 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity.aio import AzureCliCredential
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings
from semantic_kernel.functions import KernelArguments
from semantic_kernel.prompt_template import PromptTemplateConfig
"""
The following sample demonstrates how to create an Azure AI
agent using Azure OpenAI within Semantic Kernel.
It uses parameterized prompts and shows how to swap between
"semantic-kernel," "jinja2," and "handlebars" template formats,
This sample highlights the agent's prompt templates are managed
and how kernel arguments are passed in and used.
"""
# Define the inputs and styles to be used in the agent
inputs = [
("Home cooking is great.", None),
("Talk about world peace.", "iambic pentameter"),
("Say something about doing your best.", "e. e. cummings"),
("What do you think about having fun?", "old school rap"),
]
async def invoke_chat_completion_agent(agent: AzureAIAgent, inputs):
"""Invokes the given agent with each (input, style) in inputs."""
thread = None
for user_input, style in inputs:
print(f"[USER]: {user_input}\n")
# If style is specified, override the 'style' argument
argument_overrides = None
if style:
argument_overrides = KernelArguments(style=style)
# Stream agent responses
async for response in agent.invoke_stream(messages=user_input, thread=thread, arguments=argument_overrides):
print(f"{response.content}", end="", flush=True)
thread = response.thread
print("\n")
async def invoke_agent_with_template(template_str: str, template_format: str, default_style: str = "haiku"):
"""Creates an agent with the specified template and format, then invokes it using invoke_chat_completion_agent."""
# Configure the prompt template
prompt_config = PromptTemplateConfig(template=template_str, template_format=template_format)
ai_agent_settings = AzureAIAgentSettings()
async with (
AzureCliCredential() as creds,
AzureAIAgent.create_client(credential=creds, endpoint=ai_agent_settings.endpoint) as client,
):
# Create agent definition
agent_definition = await client.agents.create_agent(
model=ai_agent_settings.model_deployment_name,
name="MyPoetAgent",
)
# Create the AzureAI Agent
agent = AzureAIAgent(
client=client,
definition=agent_definition,
prompt_template_config=prompt_config,
arguments=KernelArguments(style=default_style),
)
await invoke_chat_completion_agent(agent, inputs)
async def main():
# 1) Using "semantic-kernel" format
print("\n===== SEMANTIC-KERNEL FORMAT =====\n")
semantic_kernel_template = """
Write a one verse poem on the requested topic in the style of {{$style}}.
Always state the requested style of the poem.
"""
await invoke_agent_with_template(
template_str=semantic_kernel_template,
template_format="semantic-kernel",
default_style="haiku",
)
# 2) Using "jinja2" format
print("\n===== JINJA2 FORMAT =====\n")
jinja2_template = """
Write a one verse poem on the requested topic in the style of {{style}}.
Always state the requested style of the poem.
"""
await invoke_agent_with_template(template_str=jinja2_template, template_format="jinja2", default_style="haiku")
# 3) Using "handlebars" format
print("\n===== HANDLEBARS FORMAT =====\n")
handlebars_template = """
Write a one verse poem on the requested topic in the style of {{style}}.
Always state the requested style of the poem.
"""
await invoke_agent_with_template(
template_str=handlebars_template, template_format="handlebars", default_style="haiku"
)
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,122 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from typing import Annotated
from azure.identity.aio import AzureCliCredential
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings, AzureAIAgentThread
from semantic_kernel.functions import kernel_function
"""
The following sample demonstrates how to create an Azure AI agent that answers
questions about a sample menu using a Semantic Kernel Plugin. After all questions
are answered, it retrieves and prints the messages from the thread.
"""
# Define a sample plugin for the sample
class MenuPlugin:
"""A sample Menu Plugin used for the concept sample."""
@kernel_function(description="Provides a list of specials from the menu.")
def get_specials(self) -> Annotated[str, "Returns the specials from the menu."]:
return """
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
"""
@kernel_function(description="Provides the price of the requested menu item.")
def get_item_price(
self, menu_item: Annotated[str, "The name of the menu item."]
) -> Annotated[str, "Returns the price of the menu item."]:
return "$9.99"
# Simulate a conversation with the agent
USER_INPUTS = [
"Hello",
"What is the special soup?",
"How much does that cost?",
"Thank you",
]
async def main() -> None:
async with (
AzureCliCredential() as creds,
AzureAIAgent.create_client(credential=creds) as client,
):
# 1. Create an agent on the Azure AI agent service
agent_definition = await client.agents.create_agent(
model=AzureAIAgentSettings().model_deployment_name,
name="Host",
instructions="Answer questions about the menu.",
)
# 2. Create a Semantic Kernel agent for the Azure AI agent
agent = AzureAIAgent(
client=client,
definition=agent_definition,
plugins=[MenuPlugin()], # Add the plugin to the agent
)
# 3. Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: AzureAIAgentThread | None = None
try:
for user_input in USER_INPUTS:
print(f"# User: {user_input}")
# 4. Invoke the agent for the specified thread for response
async for response in agent.invoke(
messages=user_input,
thread=thread,
):
print(f"# {response.name}: {response}")
thread = response.thread
finally:
# 5. Cleanup: Delete the thread and agent
# await thread.delete() if thread else None
await client.agents.delete_agent(agent.id)
print("*" * 50)
print("# Messages in the thread (asc order):\n")
async for msg in thread.get_messages(sort_order="asc"):
print(f"# {msg.role} for name={msg.name}: {msg.content}")
print("*" * 50)
await thread.delete() if thread else None
"""
# User: Hello
# Host: Hello! How can I assist you with the menu today?
# User: What is the special soup?
# Host: The special soup today is Clam Chowder. Would you like to know more about it or anything else
on the menu?
# User: How much does that cost?
# Host: The Clam Chowder costs $9.99. Would you like to order it or need information on other items?
# User: Thank you
# Host: You're welcome! If you have any more questions or need assistance with the menu, feel free to ask.
Enjoy your meal!
**************************************************
# Messages in the thread (asc order):
# AuthorRole.USER for name=asst_mXwZOwyJLxXGtaYKHizRH6Ip: Hello
# AuthorRole.ASSISTANT for name=asst_mXwZOwyJLxXGtaYKHizRH6Ip: Hello! How can I assist you with the menu today?
# AuthorRole.USER for name=asst_mXwZOwyJLxXGtaYKHizRH6Ip: What is the special soup?
# AuthorRole.ASSISTANT for name=asst_mXwZOwyJLxXGtaYKHizRH6Ip: The special soup today is Clam Chowder. Would
you like to know more about it or anything else on the menu?
# AuthorRole.USER for name=asst_mXwZOwyJLxXGtaYKHizRH6Ip: How much does that cost?
# AuthorRole.ASSISTANT for name=asst_mXwZOwyJLxXGtaYKHizRH6Ip: The Clam Chowder costs $9.99. Would you like to
order it or need information on other items?
# AuthorRole.USER for name=asst_mXwZOwyJLxXGtaYKHizRH6Ip: Thank you
# AuthorRole.ASSISTANT for name=asst_mXwZOwyJLxXGtaYKHizRH6Ip: You're welcome! If you have any more questions
or need assistance with the menu, feel free to ask. Enjoy your meal!
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,120 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from typing import Annotated
from azure.identity.aio import AzureCliCredential
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings, AzureAIAgentThread
from semantic_kernel.functions import kernel_function
"""
The following sample demonstrates how to create an Azure AI Agent
and use it with streaming responses. The agent is configured to use
a plugin that provides a list of specials from the menu and the price
of the requested menu item. The thread message ID is also printed as each
message is processed.
"""
# Define a sample plugin for the sample
class MenuPlugin:
"""A sample Menu Plugin used for the concept sample."""
@kernel_function(description="Provides a list of specials from the menu.")
def get_specials(self) -> Annotated[str, "Returns the specials from the menu."]:
return """
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
"""
@kernel_function(description="Provides the price of the requested menu item.")
def get_item_price(
self, menu_item: Annotated[str, "The name of the menu item."]
) -> Annotated[str, "Returns the price of the menu item."]:
return "$9.99"
async def main() -> None:
ai_agent_settings = AzureAIAgentSettings()
async with (
AzureCliCredential() as creds,
AzureAIAgent.create_client(credential=creds, endpoint=ai_agent_settings.endpoint) as client,
):
AGENT_NAME = "Host"
AGENT_INSTRUCTIONS = "Answer questions about the menu."
# Create agent definition
agent_definition = await client.agents.create_agent(
model=ai_agent_settings.model_deployment_name,
name=AGENT_NAME,
instructions=AGENT_INSTRUCTIONS,
)
# Create the AzureAI Agent
agent = AzureAIAgent(
client=client,
definition=agent_definition,
plugins=[MenuPlugin()], # add the sample plugin to the agent
)
# Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: AzureAIAgentThread = None
user_inputs = [
"Hello",
"What is the special soup?",
"How much does that cost?",
"Thank you",
]
try:
last_thread_msg_id = None
for user_input in user_inputs:
print(f"# User: '{user_input}'")
first_chunk = True
async for response in agent.invoke_stream(
messages=user_input,
thread=thread,
):
if first_chunk:
print(f"# {response.role}: ", end="", flush=True)
# Show the thread message id before the first text chunk
if "thread_message_id" in response.content.metadata:
current_id = response.content.metadata["thread_message_id"]
if current_id != last_thread_msg_id:
print(f"(thread message id: {current_id}) ", end="", flush=True)
last_thread_msg_id = current_id
first_chunk = False
print(response.content, end="", flush=True)
thread = response.thread
print()
finally:
# Cleanup: Delete the thread and agent
await thread.delete() if thread else None
await client.agents.delete_agent(agent.id)
"""
Sample Output:
# User: 'Hello'
# AuthorRole.ASSISTANT: (thread message id: msg_HZ2h4Wzbj7GEcnVCjnyEuYWT) Hello! How can I assist you with
the menu today?
# User: 'What is the special soup?'
# AuthorRole.ASSISTANT: (thread message id: msg_TSjkJK6hHJojIkPvF6uUofHD) The special soup today is
Clam Chowder. Would you like to know more about it or anything else from the menu?
# User: 'How much does that cost?'
# AuthorRole.ASSISTANT: (thread message id: msg_liwTpBFrB9JpCM1oM9EXKiwq) The Clam Chowder costs $9.99.
Is there anything else you'd like to know?
# User: 'Thank you'
# AuthorRole.ASSISTANT: (thread message id: msg_K6lpR3gYIHethXq17T6gJcxi) You're welcome!
If you have any more questions or need assistance, feel free to ask. Enjoy your meal!
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,93 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from enum import Enum
from azure.ai.agents.models import (
ResponseFormatJsonSchema,
ResponseFormatJsonSchemaType,
)
from azure.identity.aio import AzureCliCredential
from pydantic import BaseModel
from semantic_kernel.agents import (
AzureAIAgent,
AzureAIAgentSettings,
)
"""
The following sample demonstrates how to create an Azure AI Agent
and leverage the agent's ability to return structured outputs,
based on a user-defined Pydantic model.
"""
# Define a Pydantic model that represents the structured output from the agent
class Planets(str, Enum):
Earth = "Earth"
Mars = "Mars"
Jupyter = "Jupyter"
class Planet(BaseModel):
planet: Planets
mass: float
async def main():
ai_agent_settings = AzureAIAgentSettings()
async with (
AzureCliCredential() as creds,
AzureAIAgent.create_client(credential=creds, endpoint=ai_agent_settings.endpoint) as client,
):
# Create the agent definition
agent_definition = await client.agents.create_agent(
model=ai_agent_settings.model_deployment_name,
name="Assistant",
instructions="Extract the information about planets.",
response_format=ResponseFormatJsonSchemaType(
json_schema=ResponseFormatJsonSchema(
name="planet_mass",
description="Extract planet mass.",
schema=Planet.model_json_schema(),
)
),
)
# Create the AzureAI Agent
agent = AzureAIAgent(
client=client,
definition=agent_definition,
)
# Create a new thread for use with the assistant
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread = None
user_inputs = ["The mass of the Mars is 6.4171E23 kg; the mass of the Earth is 5.972168E24 kg;"]
try:
for user_input in user_inputs:
print(f"# User: '{user_input}'")
async for response in agent.invoke(messages=user_input, thread=thread):
# The response returned is a Pydantic Model, so we can validate it using the
# model_validate_json method
response_model = Planet.model_validate_json(str(response.content))
print(f"# {response.role}: {response_model}")
thread = response.thread
finally:
await thread.delete() if thread else None
await client.agents.delete_agent(agent_definition.id)
"""
Sample Output:
# User: 'The mass of the Mars is 6.4171E23 kg; the mass of the Earth is 5.972168E24 kg;'
# AuthorRole.ASSISTANT: planet=<Planets.Earth: 'Earth'> mass=5.972168e+24
# AuthorRole.ASSISTANT: planet=<Planets.Mars: 'Mars'> mass=6.4171e+23
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,82 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.ai.agents.models import TruncationObject
from azure.identity.aio import AzureCliCredential
from semantic_kernel.agents import (
AzureAIAgent,
AzureAIAgentSettings,
AzureAIAgentThread,
)
"""
The following sample demonstrates how to create an Azure AI Agent Agent
and configure a truncation strategy for the agent.
"""
USER_INPUTS = [
"Why is the sky blue?",
"What is the speed of light?",
"What have we been talking about?",
]
async def main() -> None:
ai_agent_settings = AzureAIAgentSettings.create()
async with (
AzureCliCredential() as creds,
AzureAIAgent.create_client(credential=creds, endpoint=ai_agent_settings.endpoint) as client,
):
# Create the agent definition
agent_definition = await client.agents.create_agent(
model=ai_agent_settings.model_deployment_name,
name="TruncateAgent",
instructions="You are a helpful assistant that answers user questions in one sentence.",
)
# Create the AzureAI Agent
agent = AzureAIAgent(
client=client,
definition=agent_definition,
)
thread: AzureAIAgentThread | None = None
# Options are "auto" or "last_messages"
# If using "last_messages", specify the number of messages to keep with `last_messages` kwarg
truncation_strategy = TruncationObject(type="last_messages", last_messages=2)
try:
for user_input in USER_INPUTS:
print(f"# User: {user_input}")
# 4. Invoke the agent with the specified message for response
response = await agent.get_response(
messages=user_input, thread=thread, truncation_strategy=truncation_strategy
)
print(f"# {response.name}: {response}")
thread = response.thread
finally:
# 6. Cleanup: Delete the thread and agent
await thread.delete() if thread else None
await client.agents.delete_agent(agent.id)
"""
Sample Output:
# User: Why is the sky blue?
# TruncateAgent: The sky appears blue because molecules in the Earth's atmosphere scatter sunlight in all
directions, and blue light is scattered more than other colors due to its shorter wavelength.
# User: What is the speed of light?
# TruncateAgent: The speed of light in a vacuum is approximately 299,792,458 meters per second
(or about 186,282 miles per second).
# User: What have we been talking about?
# TruncateAgent: I'm sorry, but I don't have access to previous interactions. Could you remind me what
we've been discussing?
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,2 @@
BEDROCK_AGENT_AGENT_RESOURCE_ROLE_ARN=[YOUR_AGENT_ROLE_AMAZON_RESOURCE_NAME]
BEDROCK_AGENT_FOUNDATION_MODEL=[YOUR_FOUNDATION_MODEL]
@@ -0,0 +1,74 @@
# Concept samples on how to use AWS Bedrock agents
## Pre-requisites
1. You need to have an AWS account and [access to the foundation models](https://docs.aws.amazon.com/bedrock/latest/userguide/model-access-permissions.html)
2. [AWS CLI installed](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) and [configured](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html#configuration)
### Configuration
Follow this [guide](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html#configuration) to configure your environment to use the Bedrock API.
Please configure the `aws_access_key_id`, `aws_secret_access_key`, and `region` otherwise you will need to create custom clients for the services. For example:
```python
runtime_client=boto.client(
"bedrock-runtime",
aws_access_key_id="your_access_key",
aws_secret_access_key="your_secret_key",
region_name="your_region",
[...other parameters you may need...]
)
client=boto.client(
"bedrock",
aws_access_key_id="your_access_key",
aws_secret_access_key="your_secret_key",
region_name="your_region",
[...other parameters you may need...]
)
bedrock_agent = BedrockAgent.create_and_prepare_agent(
name="your_agent_name",
instructions="your_instructions",
runtime_client=runtime_client,
client=client,
[...other parameters you may need...]
)
```
## Samples
| Sample | Description |
|--------|-------------|
| [bedrock_agent_simple_chat.py](bedrock_agent_simple_chat.py) | Demonstrates basic usage of the Bedrock agent. |
| [bedrock_agent_simple_chat_streaming.py](bedrock_agent_simple_chat_streaming.py) | Demonstrates basic usage of the Bedrock agent with streaming. |
| [bedrock_agent_with_kernel_function.py](bedrock_agent_with_kernel_function.py) | Shows how to use the Bedrock agent with a kernel function. |
| [bedrock_agent_with_kernel_function_streaming.py](bedrock_agent_with_kernel_function_streaming.py) | Shows how to use the Bedrock agent with a kernel function with streaming. |
| [bedrock_agent_with_code_interpreter.py](bedrock_agent_with_code_interpreter.py) | Example of using the Bedrock agent with a code interpreter. |
| [bedrock_agent_with_code_interpreter_streaming.py](bedrock_agent_with_code_interpreter_streaming.py) | Example of using the Bedrock agent with a code interpreter and streaming. |
| [bedrock_mixed_chat_agents.py](bedrock_mixed_chat_agents.py) | Example of using multiple chat agents in a single script. |
| [bedrock_mixed_chat_agents_streaming.py](bedrock_mixed_chat_agents_streaming.py) | Example of using multiple chat agents in a single script with streaming. |
## Before running the samples
You need to set up some environment variables to run the samples. Please refer to the [.env.example](.env.example) file for the required environment variables.
### `BEDROCK_AGENT_AGENT_RESOURCE_ROLE_ARN`
On your AWS console, go to the IAM service and go to **Roles**. Find the role you want to use and click on it. You will find the ARN in the summary section.
### `BEDROCK_AGENT_FOUNDATION_MODEL`
You need to make sure you have permission to access the foundation model. You can find the model ID in the [AWS documentation](https://docs.aws.amazon.com/bedrock/latest/userguide/models-supported.html). To see the models you have access to, find the policy attached to your role you should see a list of models you have access to under the `Resource` section.
### How to add the `bedrock:InvokeModelWithResponseStream` action to an IAM policy
1. Open the [IAM console](https://console.aws.amazon.com/iam/).
2. On the left navigation pane, choose `Roles` under `Access management`.
3. Find the role you want to edit and click on it.
4. Under the `Permissions policies` tab, click on the policy you want to edit.
5. Under the `Permissions defined in this policy` section, click on the service. You should see **Bedrock** if you already have access to the Bedrock agent service.
6. Click on the service, and then click `Edit`.
7. On the right, you will be able to add an action. Find the service and search for `InvokeModelWithResponseStream`.
8. Check the box next to the action and then scroll all the way down and click `Next`.
9. Follow the prompts to save the changes.
@@ -0,0 +1,62 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import boto3
from semantic_kernel.agents import BedrockAgent, BedrockAgentThread
"""
The following sample demonstrates how to use an already existing
Bedrock Agent within Semantic Kernel. This sample requires that you
have an existing agent created either previously in code or via the
AWS Console.
This sample uses the following main component(s):
- a Bedrock agent
You will learn how to retrieve a Bedrock agent and talk to it.
"""
# Replace "your-agent-id" with the ID of the agent you want to use
AGENT_ID = "your-agent-id"
async def main():
client = boto3.client("bedrock-agent")
agent_model = client.get_agent(agentId=AGENT_ID)["agent"]
bedrock_agent = BedrockAgent(agent_model)
thread: BedrockAgentThread = None
try:
while True:
user_input = input("User:> ")
if user_input == "exit":
print("\n\nExiting chat...")
break
# Invoke the agent
# The chat history is maintained in the session
async for response in bedrock_agent.invoke(
messages=user_input,
thread=thread,
):
print(f"Bedrock agent: {response}")
thread = response.thread
except KeyboardInterrupt:
print("\n\nExiting chat...")
return False
except EOFError:
print("\n\nExiting chat...")
return False
finally:
# Cleanup: Delete the thread
await thread.delete() if thread else None
# Sample output (using anthropic.claude-3-haiku-20240307-v1:0):
# User:> Hi, my name is John.
# Bedrock agent: Hello John. How can I help you?
# User:> What is my name?
# Bedrock agent: Your name is John.
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,60 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from semantic_kernel.agents import BedrockAgent, BedrockAgentThread
"""
This sample shows how to interact with a Bedrock agent in the simplest way.
This sample uses the following main component(s):
- a Bedrock agent
You will learn how to create a new Bedrock agent and talk to it.
"""
AGENT_NAME = "semantic-kernel-bedrock-agent"
INSTRUCTION = "You are a friendly assistant. You help people find information."
async def main():
bedrock_agent = await BedrockAgent.create_and_prepare_agent(AGENT_NAME, instructions=INSTRUCTION)
# Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: BedrockAgentThread = None
try:
while True:
user_input = input("User:> ")
if user_input == "exit":
print("\n\nExiting chat...")
break
# Invoke the agent
# The chat history is maintained in the session
response = await bedrock_agent.get_response(
messages=user_input,
thread=thread,
)
print(f"Bedrock agent: {response}")
thread = response.thread
except KeyboardInterrupt:
print("\n\nExiting chat...")
return False
except EOFError:
print("\n\nExiting chat...")
return False
finally:
# Delete the agent
await bedrock_agent.delete_agent()
await thread.delete() if thread else None
# Sample output (using anthropic.claude-3-haiku-20240307-v1:0):
# User:> Hi, my name is John.
# Bedrock agent: Hello John. How can I help you?
# User:> What is my name?
# Bedrock agent: Your name is John.
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,55 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from semantic_kernel.agents import BedrockAgent, BedrockAgentThread
"""
This sample shows how to interact with a Bedrock agent via streaming in the simplest way.
This sample uses the following main component(s):
- a Bedrock agent
You will learn how to create a new Bedrock agent and talk to it.
"""
AGENT_NAME = "semantic-kernel-bedrock-agent"
INSTRUCTION = "You are a friendly assistant. You help people find information."
async def main():
bedrock_agent = await BedrockAgent.create_and_prepare_agent(AGENT_NAME, instructions=INSTRUCTION)
thread: BedrockAgentThread = None
try:
while True:
user_input = input("User:> ")
if user_input == "exit":
print("\n\nExiting chat...")
break
# Invoke the agent
# The chat history is maintained in the thread
print("Bedrock agent: ", end="")
async for response in bedrock_agent.invoke_stream(messages=user_input, thread=thread):
print(response, end="")
thread = response.thread
print()
except KeyboardInterrupt:
print("\n\nExiting chat...")
return False
except EOFError:
print("\n\nExiting chat...")
return False
finally:
# Delete the agent
await bedrock_agent.delete_agent()
await thread.delete() if thread else None
# Sample output (using anthropic.claude-3-haiku-20240307-v1:0):
# User:> Hi, my name is John.
# Bedrock agent: Hello John. How can I help you?
# User:> What is my name?
# Bedrock agent: Your name is John.
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,85 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from pathlib import Path
from semantic_kernel.agents import BedrockAgent, BedrockAgentThread
from semantic_kernel.contents.binary_content import BinaryContent
"""
This sample shows how to interact with a Bedrock agent that is capable of writing and executing code.
This sample uses the following main component(s):
- a Bedrock agent
You will learn how to create a new Bedrock agent and ask it a question that requires coding to answer.
After running this sample, a bar chart will be generated and saved to a file in the same directory
as this script.
"""
AGENT_NAME = "semantic-kernel-bedrock-agent"
INSTRUCTION = "You are a friendly assistant. You help people find information."
ASK = """
Create a bar chart for the following data:
Panda 5
Tiger 8
Lion 3
Monkey 6
Dolphin 2
"""
async def main():
bedrock_agent = await BedrockAgent.create_and_prepare_agent(AGENT_NAME, instructions=INSTRUCTION)
await bedrock_agent.create_code_interpreter_action_group()
thread: BedrockAgentThread = None
# Placeholder for the file generated by the code interpreter
binary_item: BinaryContent | None = None
try:
# Invoke the agent
async for response in bedrock_agent.invoke(
messages=ASK,
thread=thread,
):
print(f"Response:\n{response}")
thread = response.thread
if not binary_item:
binary_item = next((item for item in response.items if isinstance(item, BinaryContent)), None)
finally:
# Delete the agent
await bedrock_agent.delete_agent()
await thread.delete() if thread else None
# Save the chart to a file
if not binary_item:
raise RuntimeError("No chart generated")
# Securely assemble the file path and validate it's within the expected directory
# This is a defense-in-depth measure against directory traversal attacks
output_dir = Path(__file__).parent.resolve()
file_path = (output_dir / binary_item.metadata["name"]).resolve()
# Verify the resolved path is within the expected directory
if not file_path.is_relative_to(output_dir):
raise RuntimeError("Invalid filename: would write outside the expected directory")
binary_item.write_to_file(file_path)
print(f"Chart saved to {file_path}")
# Sample output (using anthropic.claude-3-haiku-20240307-v1:0):
# Response:
# Here is the bar chart for the given data:
# [A bar chart showing the following data:
# Panda 5
# Tiger 8
# Lion 3
# Monkey 6
# Dolpin 2]
# Chart saved to ...
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,87 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from pathlib import Path
from semantic_kernel.agents import BedrockAgent, BedrockAgentThread
from semantic_kernel.contents.binary_content import BinaryContent
"""
This sample shows how to interact with a Bedrock agent that is capable of writing and executing code.
This sample uses the following main component(s):
- a Bedrock agent
You will learn how to create a new Bedrock agent and ask it a question that requires coding to answer.
After running this sample, a bar chart will be generated and saved to a file in the same directory
as this script.
"""
AGENT_NAME = "semantic-kernel-bedrock-agent"
INSTRUCTION = "You are a friendly assistant. You help people find information."
ASK = """
Create a bar chart for the following data:
Panda 5
Tiger 8
Lion 3
Monkey 6
Dolphin 2
"""
async def main():
bedrock_agent = await BedrockAgent.create_and_prepare_agent(AGENT_NAME, instructions=INSTRUCTION)
await bedrock_agent.create_code_interpreter_action_group()
thread: BedrockAgentThread = None
# Placeholder for the file generated by the code interpreter
binary_item: BinaryContent | None = None
try:
# Invoke the agent
print("Response: ")
async for response in bedrock_agent.invoke_stream(
messages=ASK,
thread=thread,
):
print(response, end="")
thread = response.thread
if not binary_item:
binary_item = next((item for item in response.items if isinstance(item, BinaryContent)), None)
print()
finally:
# Delete the agent
await bedrock_agent.delete_agent()
await thread.delete() if thread else None
# Save the chart to a file
if not binary_item:
raise RuntimeError("No chart generated")
# Securely assemble the file path and validate it's within the expected directory
# This is a defense-in-depth measure against directory traversal attacks
output_dir = Path(__file__).parent.resolve()
file_path = (output_dir / binary_item.metadata["name"]).resolve()
# Verify the resolved path is within the expected directory
if not file_path.is_relative_to(output_dir):
raise RuntimeError("Invalid filename: would write outside the expected directory")
binary_item.write_to_file(file_path)
print(f"Chart saved to {file_path}")
# Sample output (using anthropic.claude-3-haiku-20240307-v1:0):
# Response:
# Here is the bar chart for the given data:
# [A bar chart showing the following data:
# Panda 5
# Tiger 8
# Lion 3
# Monkey 6
# Dolpin 2]
# Chart saved to ...
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,72 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from typing import Annotated
from semantic_kernel.agents import BedrockAgent, BedrockAgentThread
from semantic_kernel.functions.kernel_function_decorator import kernel_function
from semantic_kernel.kernel import Kernel
"""
This sample shows how to interact with a Bedrock agent that is capable of using kernel functions.
This sample uses the following main component(s):
- a Bedrock agent
- a kernel function
- a kernel
You will learn how to create a new Bedrock agent and ask it a question that requires a kernel function to answer.
"""
AGENT_NAME = "semantic-kernel-bedrock-agent"
INSTRUCTION = "You are a friendly assistant. You help people find information."
class WeatherPlugin:
"""Mock weather plugin."""
@kernel_function(description="Get real-time weather information.")
def current(self, location: Annotated[str, "The location to get the weather"]) -> str:
"""Returns the current weather."""
return f"The weather in {location} is sunny."
def get_kernel() -> Kernel:
kernel = Kernel()
kernel.add_plugin(WeatherPlugin(), plugin_name="weather")
return kernel
async def main():
# Create a kernel
kernel = get_kernel()
bedrock_agent = await BedrockAgent.create_and_prepare_agent(
AGENT_NAME,
INSTRUCTION,
kernel=kernel,
)
# Note: We still need to create the kernel function action group on the service side.
await bedrock_agent.create_kernel_function_action_group()
thread: BedrockAgentThread = None
try:
# Invoke the agent
async for response in bedrock_agent.invoke(
messages="What is the weather in Seattle?",
thread=thread,
):
print(f"Response:\n{response}")
thread = response.thread
finally:
# Delete the agent
await bedrock_agent.delete_agent()
await thread.delete() if thread else None
# Sample output (using anthropic.claude-3-haiku-20240307-v1:0):
# Response:
# The current weather in Seattle is sunny.
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,63 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from typing import Annotated
from semantic_kernel.agents import BedrockAgent, BedrockAgentThread
from semantic_kernel.functions.kernel_function_decorator import kernel_function
"""
This sample shows how to interact with a Bedrock agent that is capable of using kernel functions.
Instead of creating a kernel and adding plugins to it, you can directly pass the plugins to the
agent when creating it.
This sample uses the following main component(s):
- a Bedrock agent
- a kernel function
- a kernel
You will learn how to create a new Bedrock agent and ask it a question that requires a kernel function to answer.
"""
AGENT_NAME = "semantic-kernel-bedrock-agent"
INSTRUCTION = "You are a friendly assistant. You help people find information."
class WeatherPlugin:
"""Mock weather plugin."""
@kernel_function(description="Get real-time weather information.")
def current(self, location: Annotated[str, "The location to get the weather"]) -> str:
"""Returns the current weather."""
return f"The weather in {location} is sunny."
async def main():
bedrock_agent = await BedrockAgent.create_and_prepare_agent(
AGENT_NAME,
INSTRUCTION,
plugins=[WeatherPlugin()],
)
# Note: We still need to create the kernel function action group on the service side.
await bedrock_agent.create_kernel_function_action_group()
thread: BedrockAgentThread = None
try:
# Invoke the agent
async for response in bedrock_agent.invoke(
messages="What is the weather in Seattle?",
thread=thread,
):
print(f"Response:\n{response}")
thread = response.thread
finally:
# Delete the agent
await bedrock_agent.delete_agent()
await thread.delete() if thread else None
# Sample output (using anthropic.claude-3-haiku-20240307-v1:0):
# Response:
# The current weather in Seattle is sunny.
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,73 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from typing import Annotated
from semantic_kernel.agents import BedrockAgent, BedrockAgentThread
from semantic_kernel.functions.kernel_function_decorator import kernel_function
from semantic_kernel.kernel import Kernel
"""
This sample shows how to interact with a Bedrock agent that is capable of using kernel functions.
This sample uses the following main component(s):
- a Bedrock agent
- a kernel function
- a kernel
You will learn how to create a new Bedrock agent and ask it a question that requires a kernel function to answer.
"""
AGENT_NAME = "semantic-kernel-bedrock-agent"
INSTRUCTION = "You are a friendly assistant. You help people find information."
class WeatherPlugin:
"""Mock weather plugin."""
@kernel_function(description="Get real-time weather information.")
def current(self, location: Annotated[str, "The location to get the weather"]) -> str:
"""Returns the current weather."""
return f"The weather in {location} is sunny."
def get_kernel() -> Kernel:
kernel = Kernel()
kernel.add_plugin(WeatherPlugin(), plugin_name="weather")
return kernel
async def main():
# Create a kernel
kernel = get_kernel()
bedrock_agent = await BedrockAgent.create_and_prepare_agent(
AGENT_NAME,
INSTRUCTION,
kernel=kernel,
)
# Note: We still need to create the kernel function action group on the service side.
await bedrock_agent.create_kernel_function_action_group()
thread: BedrockAgentThread = None
try:
# Invoke the agent
print("Response: ")
async for response in bedrock_agent.invoke_stream(
messages="What is the weather in Seattle?",
thread=thread,
):
print(response, end="")
thread = response.thread
finally:
# Delete the agent
await bedrock_agent.delete_agent()
await thread.delete() if thread else None
# Sample output (using anthropic.claude-3-haiku-20240307-v1:0):
# Response:
# The current weather in Seattle is sunny.
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,113 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity import AzureCliCredential
from semantic_kernel.agents import AgentGroupChat, BedrockAgent, ChatCompletionAgent
from semantic_kernel.agents.strategies.termination.termination_strategy import TerminationStrategy
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
from semantic_kernel.contents.utils.author_role import AuthorRole
from semantic_kernel.kernel import Kernel
"""
This sample shows how to use a bedrock agent in a group chat that includes multiple agents of different roles.
This sample uses the following main component(s):
- a Bedrock agent
- a ChatCompletionAgent
- an AgentGroupChat
You will learn how to create a new or connect to an existing Bedrock agent and put it in a group chat with
another agent.
Note: This sample use the `AgentGroupChat` feature of Semantic Kernel, which is
no longer maintained. For a replacement, consider using the `GroupChatOrchestration`.
Read more about the `GroupChatOrchestration` here:
https://learn.microsoft.com/semantic-kernel/frameworks/agent/agent-orchestration/group-chat?pivots=programming-language-python
Here is a migration guide from `AgentGroupChat` to `GroupChatOrchestration`:
https://learn.microsoft.com/semantic-kernel/support/migration/group-chat-orchestration-migration-guide?pivots=programming-language-python
"""
# This will be a chat completion agent
REVIEWER_NAME = "ArtDirector"
REVIEWER_INSTRUCTIONS = """
You are an art director who has opinions about copywriting born of a love for David Ogilvy.
The goal is to determine if the given copy is acceptable to print.
If so, state that it is approved. Only include the word "approved" if it is so.
If not, provide insight on how to refine suggested copy without example.
"""
# This will be a bedrock agent
COPYWRITER_NAME = "CopyWriter"
COPYWRITER_INSTRUCTIONS = """
You are a copywriter with ten years of experience and are known for brevity and a dry humor.
The goal is to refine and decide on the single best copy as an expert in the field.
Only provide a single proposal per response.
You're laser focused on the goal at hand.
Don't waste time with chit chat.
Consider suggestions when refining an idea.
"""
class ApprovalTerminationStrategy(TerminationStrategy):
"""A strategy for determining when an agent should terminate."""
async def should_agent_terminate(self, agent, history):
"""Check if the agent should terminate."""
return "approved" in history[-1].content.lower()
def _create_kernel_with_chat_completion() -> Kernel:
kernel = Kernel()
kernel.add_service(AzureChatCompletion(credential=AzureCliCredential()))
return kernel
async def main():
agent_reviewer = ChatCompletionAgent(
kernel=_create_kernel_with_chat_completion(),
name=REVIEWER_NAME,
instructions=REVIEWER_INSTRUCTIONS,
)
agent_writer = await BedrockAgent.create_and_prepare_agent(
COPYWRITER_NAME,
instructions=COPYWRITER_INSTRUCTIONS,
)
chat = AgentGroupChat(
agents=[agent_writer, agent_reviewer],
termination_strategy=ApprovalTerminationStrategy(
agents=[agent_reviewer],
maximum_iterations=10,
),
)
input = "A slogan for a new line of electric cars."
await chat.add_chat_message(message=input)
print(f"# {AuthorRole.USER}: '{input}'")
try:
async for message in chat.invoke():
print(f"# {message.role} - {message.name or '*'}: '{message.content}'")
print(f"# IS COMPLETE: {chat.is_complete}")
finally:
# Delete the agent
await agent_writer.delete_agent()
# Sample output (using anthropic.claude-3-haiku-20240307-v1:0):
# AuthorRole.USER: 'A slogan for a new line of electric cars.'
# AuthorRole.ASSISTANT - CopyWriter: 'Charge Ahead: The Future of Driving'
# AuthorRole.ASSISTANT - ArtDirector: 'The slogan "Charge Ahead: The Future of Driving" is compelling but could be
# made even more impactful. Consider clarifying the unique selling proposition of the electric cars. Focus on what
# sets them apart in terms of performance, eco-friendliness, or innovation. This will help create an emotional
# connection and a clearer message for the audience.'
# AuthorRole.ASSISTANT - CopyWriter: 'Charge Forward: The Electrifying Future of Driving'
# AuthorRole.ASSISTANT - ArtDirector: 'Approved'
# IS COMPLETE: True
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,118 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity import AzureCliCredential
from semantic_kernel.agents import AgentGroupChat, BedrockAgent, ChatCompletionAgent
from semantic_kernel.agents.strategies.termination.termination_strategy import TerminationStrategy
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
from semantic_kernel.contents.utils.author_role import AuthorRole
from semantic_kernel.kernel import Kernel
"""
This sample shows how to use a bedrock agent in a group chat that includes multiple agents of different roles.
This sample uses the following main component(s):
- a Bedrock agent
- a ChatCompletionAgent
- an AgentGroupChat
You will learn how to create a new or connect to an existing Bedrock agent and put it in a group chat with
another agent.
Note: This sample use the `AgentGroupChat` feature of Semantic Kernel, which is
no longer maintained. For a replacement, consider using the `GroupChatOrchestration`.
Read more about the `GroupChatOrchestration` here:
https://learn.microsoft.com/semantic-kernel/frameworks/agent/agent-orchestration/group-chat?pivots=programming-language-python
Here is a migration guide from `AgentGroupChat` to `GroupChatOrchestration`:
https://learn.microsoft.com/semantic-kernel/support/migration/group-chat-orchestration-migration-guide?pivots=programming-language-python
"""
# This will be a chat completion agent
REVIEWER_NAME = "ArtDirector"
REVIEWER_INSTRUCTIONS = """
You are an art director who has opinions about copywriting born of a love for David Ogilvy.
The goal is to determine if the given copy is acceptable to print.
If so, state that it is approved. Only include the word "approved" if it is so.
If not, provide insight on how to refine suggested copy without example.
"""
# This will be a bedrock agent
COPYWRITER_NAME = "CopyWriter"
COPYWRITER_INSTRUCTIONS = """
You are a copywriter with ten years of experience and are known for brevity and a dry humor.
The goal is to refine and decide on the single best copy as an expert in the field.
Only provide a single proposal per response.
You're laser focused on the goal at hand.
Don't waste time with chit chat.
Consider suggestions when refining an idea.
"""
class ApprovalTerminationStrategy(TerminationStrategy):
"""A strategy for determining when an agent should terminate."""
async def should_agent_terminate(self, agent, history):
"""Check if the agent should terminate."""
return "approved" in history[-1].content.lower()
def _create_kernel_with_chat_completion() -> Kernel:
kernel = Kernel()
kernel.add_service(AzureChatCompletion(credential=AzureCliCredential()))
return kernel
async def main():
agent_reviewer = ChatCompletionAgent(
kernel=_create_kernel_with_chat_completion(),
name=REVIEWER_NAME,
instructions=REVIEWER_INSTRUCTIONS,
)
agent_writer = await BedrockAgent.create_and_prepare_agent(
COPYWRITER_NAME,
instructions=COPYWRITER_INSTRUCTIONS,
)
chat = AgentGroupChat(
agents=[agent_writer, agent_reviewer],
termination_strategy=ApprovalTerminationStrategy(
agents=[agent_reviewer],
maximum_iterations=10,
),
)
input = "A slogan for a new line of electric cars."
await chat.add_chat_message(message=input)
print(f"# {AuthorRole.USER}: '{input}'")
try:
current_agent = "*"
async for message_chunk in chat.invoke_stream():
if current_agent != message_chunk.name:
current_agent = message_chunk.name or "*"
print(f"\n# {message_chunk.role} - {current_agent}: ", end="")
print(message_chunk.content, end="")
print()
print(f"# IS COMPLETE: {chat.is_complete}")
finally:
# Delete the agent
await agent_writer.delete_agent()
# Sample output (using anthropic.claude-3-haiku-20240307-v1:0):
# AuthorRole.USER: 'A slogan for a new line of electric cars.'
# AuthorRole.ASSISTANT - CopyWriter: 'Charge Ahead: The Future of Driving'
# AuthorRole.ASSISTANT - ArtDirector: 'The slogan "Charge Ahead: The Future of Driving" is compelling but could be
# made even more impactful. Consider clarifying the unique selling proposition of the electric cars. Focus on what
# sets them apart in terms of performance, eco-friendliness, or innovation. This will help create an emotional
# connection and a clearer message for the audience.'
# AuthorRole.ASSISTANT - CopyWriter: 'Charge Forward: The Electrifying Future of Driving'
# AuthorRole.ASSISTANT - ArtDirector: 'Approved'
# IS COMPLETE: True
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,45 @@
# Chat Completion Agent Samples
The following samples demonstrate advanced usage of the `ChatCompletionAgent`.
---
## Chat History Reduction Strategies
When configuring chat history management, there are two important settings to consider:
### `reducer_msg_count`
- **Purpose:** Defines the target number of messages to retain after applying truncation or summarization.
- **Controls:** Determines how much recent conversation history is preserved, while older messages are either discarded or summarized.
- **Recommendations for adjustment:**
- **Smaller values:** Ideal for memory-constrained environments or scenarios where brief context is sufficient.
- **Larger values:** Useful when retaining extensive conversational context is critical for accurate responses or complex dialogue.
### `reducer_threshold`
- **Purpose:** Provides a buffer to prevent premature reduction when the message count slightly exceeds `reducer_msg_count`.
- **Controls:** Ensures essential message pairs (e.g., a user query and the assistants response) aren't unintentionally truncated.
- **Recommendations for adjustment:**
- **Smaller values:** Use to enforce stricter message reduction criteria, potentially truncating older message pairs sooner.
- **Larger values:** Recommended for preserving critical conversation segments, particularly in sensitive interactions involving API function calls or detailed responses.
### Interaction Between Parameters
The combination of these parameters determines **when** history reduction occurs and **how much** of the conversation is retained.
**Example:**
- If `reducer_msg_count = 10` and `reducer_threshold = 5`, message history won't be truncated until the total message count exceeds 15. This strategy maintains conversational context flexibility while respecting memory limitations.
---
## Recommendations for Effective Configuration
- **Performance-focused environments:**
- Lower `reducer_msg_count` to conserve memory and accelerate processing.
- **Context-sensitive scenarios:**
- Higher `reducer_msg_count` and `reducer_threshold` help maintain continuity across multiple interactions, crucial for multi-turn conversations or complex workflows.
- **Iterative Experimentation:**
- Start with default values (`reducer_msg_count = 10`, `reducer_threshold = 10`), and adjust according to the specific behavior and response quality required by your application.
@@ -0,0 +1,151 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity import AzureCliCredential
from semantic_kernel import Kernel
from semantic_kernel.agents import ChatCompletionAgent, ChatHistoryAgentThread
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
from semantic_kernel.filters import FunctionInvocationContext
"""
The following sample demonstrates how to create Chat Completion Agents
and use them as tools available for a Triage Agent to delegate requests
to the appropriate agent. A Function Invocation Filter is used to show
the function call content and the function result content so the caller
can see which agent was called and what the response was.
"""
# Define the auto function invocation filter that will be used by the kernel
async def function_invocation_filter(context: FunctionInvocationContext, next):
"""A filter that will be called for each function call in the response."""
if "messages" not in context.arguments:
await next(context)
return
print(f" Agent [{context.function.name}] called with messages: {context.arguments['messages']}")
await next(context)
print(f" Response from agent [{context.function.name}]: {context.result.value}")
# Create and configure the kernel.
kernel = Kernel()
# The filter is used for demonstration purposes to show the function invocation.
kernel.add_filter("function_invocation", function_invocation_filter)
credential = AzureCliCredential()
billing_agent = ChatCompletionAgent(
service=AzureChatCompletion(credential=credential),
name="BillingAgent",
instructions=(
"You specialize in handling customer questions related to billing issues. "
"This includes clarifying invoice charges, payment methods, billing cycles, "
"explaining fees, addressing discrepancies in billed amounts, updating payment details, "
"assisting with subscription changes, and resolving payment failures. "
"Your goal is to clearly communicate and resolve issues specifically about payments and charges."
),
)
refund_agent = ChatCompletionAgent(
service=AzureChatCompletion(credential=credential),
name="RefundAgent",
instructions=(
"You specialize in addressing customer inquiries regarding refunds. "
"This includes evaluating eligibility for refunds, explaining refund policies, "
"processing refund requests, providing status updates on refunds, handling complaints related to refunds, "
"and guiding customers through the refund claim process. "
"Your goal is to assist users clearly and empathetically to successfully resolve their refund-related concerns."
),
)
triage_agent = ChatCompletionAgent(
service=AzureChatCompletion(credential=credential),
kernel=kernel,
name="TriageAgent",
instructions=(
"Your role is to evaluate the user's request and forward it to the appropriate agent based on the nature of "
"the query. Forward requests about charges, billing cycles, payment methods, fees, or payment issues to the "
"BillingAgent. Forward requests concerning refunds, refund eligibility, refund policies, or the status of "
"refunds to the RefundAgent. Your goal is accurate identification of the appropriate specialist to ensure the "
"user receives targeted assistance."
),
plugins=[billing_agent, refund_agent],
)
thread: ChatHistoryAgentThread = None
async def chat() -> bool:
"""
Continuously prompt the user for input and show the assistant's response.
Type 'exit' to exit.
"""
try:
user_input = input("User:> ")
except (KeyboardInterrupt, EOFError):
print("\n\nExiting chat...")
return False
if user_input.lower().strip() == "exit":
print("\n\nExiting chat...")
return False
response = await triage_agent.get_response(
messages=user_input,
thread=thread,
)
if response:
print(f"Agent :> {response}")
return True
"""
Sample Output:
User:> I was charged twice for my subscription last month, can I get one of those payments refunded?
Agent [BillingAgent] called with messages: I was charged twice for my subscription last month.
Agent [RefundAgent] called with messages: Can I get one of those payments refunded?
Response from agent RefundAgent: Of course, I'll be happy to help you with your refund inquiry. Could you please
provide a bit more detail about the specific payment you are referring to? For instance, the item or service
purchased, the transaction date, and the reason why you're seeking a refund? This will help me understand your
situation better and provide you with accurate guidance regarding our refund policy and process.
Response from agent BillingAgent: I'm sorry to hear about the duplicate charge. To resolve this issue, could
you please provide the following details:
1. The date(s) of the transaction(s).
2. The last four digits of the card used for the transaction or any other payment method details.
3. The subscription plan you are on.
Once I have this information, I can look into the charges and help facilitate a refund for the duplicate transaction.
Let me know if you have any questions in the meantime!
Agent :> To address your concern about being charged twice and seeking a refund for one of those payments, please
provide the following information:
1. **Duplicate Charge Details**: Please share the date(s) of the transaction(s), the last four digits of the card used
or details of any other payment method, and the subscription plan you are on. This information will help us verify
the duplicate charge and assist you with a refund.
2. **Refund Inquiry Details**: Please specify the transaction date, the item or service related to the payment you want
refunded, and the reason why you're seeking a refund. This will allow us to provide accurate guidance concerning
our refund policy and process.
Once we have these details, we can proceed with resolving the duplicate charge and consider your refund request. If you
have any more questions, feel free to ask!
"""
async def main() -> None:
print("Welcome to the chat bot!\n Type 'exit' to exit.\n Try to get some billing or refund help.")
chatting = True
while chatting:
chatting = await chat()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,144 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from typing import Annotated
from azure.identity import AzureCliCredential
from semantic_kernel.agents import ChatCompletionAgent, ChatHistoryAgentThread
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
from semantic_kernel.contents import ChatMessageContent, FunctionCallContent, FunctionResultContent
from semantic_kernel.filters import AutoFunctionInvocationContext
from semantic_kernel.functions import kernel_function
from semantic_kernel.kernel import Kernel
"""
The following sample demonstrates how to configure the auto
function invocation filter while using a ChatCompletionAgent.
This allows the developer or user to view the function call content
and the function result content.
"""
# Define the auto function invocation filter that will be used by the kernel
async def auto_function_invocation_filter(context: AutoFunctionInvocationContext, next):
"""A filter that will be called for each function call in the response."""
# if we don't call next, it will skip this function, and go to the next one
await next(context)
if context.function.plugin_name == "menu":
context.terminate = True
# Define a sample plugin for the sample
class MenuPlugin:
"""A sample Menu Plugin used for the concept sample."""
@kernel_function(description="Provides a list of specials from the menu.")
def get_specials(self) -> Annotated[str, "Returns the specials from the menu."]:
return """
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
"""
@kernel_function(description="Provides the price of the requested menu item.")
def get_item_price(
self, menu_item: Annotated[str, "The name of the menu item."]
) -> Annotated[str, "Returns the price of the menu item."]:
return "$9.99"
def _create_kernel_with_chat_completionand_filter() -> Kernel:
"""A helper function to create a kernel with a chat completion service and a filter."""
kernel = Kernel()
kernel.add_service(AzureChatCompletion(credential=AzureCliCredential()))
kernel.add_filter("auto_function_invocation", auto_function_invocation_filter)
kernel.add_plugin(plugin=MenuPlugin(), plugin_name="menu")
return kernel
def _write_content(content: ChatMessageContent) -> None:
"""Write the content to the console based on the content type."""
last_item_type = type(content.items[-1]).__name__ if content.items else "(empty)"
message_content = ""
if isinstance(last_item_type, FunctionCallContent):
message_content = f"tool request = {content.items[-1].function_name}"
elif isinstance(last_item_type, FunctionResultContent):
message_content = f"function result = {content.items[-1].result}"
else:
message_content = str(content.items[-1])
print(f"[{last_item_type}] {content.role} : '{message_content}'")
async def main():
# 1. Create the agent with a kernel instance that contains
# the auto function invocation filter and the AI service
agent = ChatCompletionAgent(
kernel=_create_kernel_with_chat_completionand_filter(),
name="Host",
instructions="Answer questions about the menu.",
)
# 2. Define the thread
thread: ChatHistoryAgentThread = None
user_inputs = [
"Hello",
"What is the special soup?",
"What is the special drink?",
"Thank you",
]
for user_input in user_inputs:
print(f"# User: '{user_input}'")
# 3. Get the response from the agent
response = await agent.get_response(messages=user_input, thread=thread)
thread = response.thread
_write_content(response)
print("================================")
print("CHAT HISTORY")
print("================================")
# 4. Print out the chat history to view the different types of messages
async for message in thread.get_messages():
_write_content(message)
"""
Sample output:
# AuthorRole.USER: 'Hello'
[TextContent] AuthorRole.ASSISTANT : 'Hello! How can I assist you today?'
# AuthorRole.USER: 'What is the special soup?'
[FunctionResultContent] AuthorRole.TOOL : '
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
'
# AuthorRole.USER: 'What is the special drink?'
[TextContent] AuthorRole.ASSISTANT : 'The special drink is Chai Tea.'
# AuthorRole.USER: 'Thank you'
[TextContent] AuthorRole.ASSISTANT : 'You're welcome! If you have any more questions or need assistance with
anything else, feel free to ask!'
================================
CHAT HISTORY
================================
[TextContent] AuthorRole.USER : 'Hello'
[TextContent] AuthorRole.ASSISTANT : 'Hello! How can I assist you today?'
[TextContent] AuthorRole.USER : 'What is the special soup?'
[FunctionCallContent] AuthorRole.ASSISTANT : 'menu-get_specials({})'
[FunctionResultContent] AuthorRole.TOOL : '
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
'
[TextContent] AuthorRole.USER : 'What is the special drink?'
[TextContent] AuthorRole.ASSISTANT : 'The special drink is Chai Tea.'
[TextContent] AuthorRole.USER : 'Thank you'
[TextContent] AuthorRole.ASSISTANT : 'You're welcome! If you have any more questions or need assistance with
anything else, feel free to ask!'
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,112 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from typing import Annotated
from azure.identity import AzureCliCredential
from semantic_kernel.agents.chat_completion.chat_completion_agent import ChatCompletionAgent, ChatHistoryAgentThread
from semantic_kernel.connectors.ai.open_ai.services.azure_chat_completion import AzureChatCompletion
from semantic_kernel.contents import FunctionCallContent, FunctionResultContent
from semantic_kernel.contents.chat_message_content import ChatMessageContent
from semantic_kernel.functions import kernel_function
"""
The following sample demonstrates how to create a chat completion agent
and use it with functions. In order to answer user questions, the
agent internally uses the functions. These internal steps are returned
to the user as part of the agent's response. Thus, the invoke method
configures a message callback to receive the agent's internal messages.
The agent is configured to use a plugin that provides a list of
specials from the menu and the price of the requested menu item.
"""
# Define a sample plugin for the sample
class MenuPlugin:
"""A sample Menu Plugin used for the concept sample."""
@kernel_function(description="Provides a list of specials from the menu.")
def get_specials(self) -> Annotated[str, "Returns the specials from the menu."]:
return """
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
"""
@kernel_function(description="Provides the price of the requested menu item.")
def get_item_price(
self, menu_item: Annotated[str, "The name of the menu item."]
) -> Annotated[str, "Returns the price of the menu item."]:
return "$9.99"
# This callback function will be called for each intermediate message
# Which will allow one to handle FunctionCallContent and FunctionResultContent
# If the callback is not provided, the agent will return the final response
# with no intermediate tool call steps.
async def handle_intermediate_steps(message: ChatMessageContent) -> None:
for item in message.items or []:
if isinstance(item, FunctionCallContent):
print(f"Function Call:> {item.name} with arguments: {item.arguments}")
elif isinstance(item, FunctionResultContent):
print(f"Function Result:> {item.result} for function: {item.name}")
else:
print(f"{message.role}: {message.content}")
async def main() -> None:
agent = ChatCompletionAgent(
service=AzureChatCompletion(credential=AzureCliCredential()),
name="Assistant",
instructions="Answer questions about the menu.",
plugins=[MenuPlugin()],
)
# Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: ChatHistoryAgentThread = None
user_inputs = [
"Hello",
"What is the special soup?",
"How much does that cost?",
"Thank you",
]
for user_input in user_inputs:
print(f"# User: '{user_input}'")
async for response in agent.invoke(
messages=user_input,
thread=thread,
on_intermediate_message=handle_intermediate_steps,
):
print(f"# {response.role}: {response}")
thread = response.thread
"""
Sample Output:
# User: 'Hello'
# AuthorRole.ASSISTANT: Hi there! How can I assist you today?
# User: 'What is the special soup?'
Function Call:> MenuPlugin-get_specials with arguments: {}
Function Result:>
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
for function: MenuPlugin-get_specials
# AuthorRole.ASSISTANT: The special soup today is Clam Chowder. Would you like to know anything else from the menu?
# User: 'How much does that cost?'
Function Call:> MenuPlugin-get_item_price with arguments: {"menu_item":"Clam Chowder"}
Function Result:> $9.99 for function: MenuPlugin-get_item_price
# AuthorRole.ASSISTANT: The Clam Chowder costs $9.99. Would you like to know more about the menu or anything else?
# User: 'Thank you'
# AuthorRole.ASSISTANT: You're welcome! If you have any more questions, feel free to ask. Enjoy your day!
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,114 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from typing import Annotated
from azure.identity import AzureCliCredential
from semantic_kernel.agents import ChatCompletionAgent, ChatHistoryAgentThread
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
from semantic_kernel.contents import ChatMessageContent, FunctionCallContent, FunctionResultContent
from semantic_kernel.functions import kernel_function
"""
The following sample demonstrates how to create a chat completion agent
and use it with streaming responses. Additionally, the invoke_stream
configures a message callback to receive fully formed messages once
the streaming invocation is complete. The agent is configured to use
a plugin that provides a list of specials from the menu and the price
of the requested menu item.
"""
# Define a sample plugin for the sample
class MenuPlugin:
"""A sample Menu Plugin used for the concept sample."""
@kernel_function(description="Provides a list of specials from the menu.")
def get_specials(self) -> Annotated[str, "Returns the specials from the menu."]:
return """
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
"""
@kernel_function(description="Provides the price of the requested menu item.")
def get_item_price(
self, menu_item: Annotated[str, "The name of the menu item."]
) -> Annotated[str, "Returns the price of the menu item."]:
return "$9.99"
# This callback function will be called for each intermediate message
# Which will allow one to handle FunctionCallContent and FunctionResultContent
# If the callback is not provided, the agent will return the final response
# with no intermediate tool call steps.
async def handle_streaming_intermediate_steps(message: ChatMessageContent) -> None:
for item in message.items or []:
if isinstance(item, FunctionCallContent):
print(f"Function Call:> {item.name} with arguments: {item.arguments}")
elif isinstance(item, FunctionResultContent):
print(f"Function Result:> {item.result} for function: {item.name}")
else:
print(f"{message.role}: {message.content}")
async def main() -> None:
agent = ChatCompletionAgent(
service=AzureChatCompletion(credential=AzureCliCredential()),
name="Assistant",
instructions="Answer questions about the menu.",
plugins=[MenuPlugin()],
)
# Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: ChatHistoryAgentThread = None
user_inputs = [
"Hello",
"What is the special soup?",
"How much does that cost?",
"Thank you",
]
for user_input in user_inputs:
print(f"\n# User: '{user_input}'")
async for response in agent.invoke_stream(
messages=user_input,
thread=thread,
on_intermediate_message=handle_streaming_intermediate_steps,
):
if response.content:
print(response.content, end="", flush=True)
thread = response.thread
print()
"""
Sample Output:
# User: 'Hello'
Hello! How can I assist you today?
# User: 'What is the special soup?'
Function Call:> MenuPlugin-get_specials with arguments: {}
Function Result:>
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
for function: MenuPlugin-get_specials
The special soup today is Clam Chowder. Is there anything else you'd like to know?
# User: 'How much does that cost?'
Function Call:> MenuPlugin-get_item_price with arguments: {"menu_item":"Clam Chowder"}
Function Result:> $9.99 for function: MenuPlugin-get_item_price
The Clam Chowder costs $9.99. Would you like to know anything else about the menu?
# User: 'Thank you'
You're welcome! If you have any more questions, feel free to ask. Have a great day!
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,99 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity import AzureCliCredential
from semantic_kernel.agents import ChatCompletionAgent, ChatHistoryAgentThread
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
from semantic_kernel.functions import KernelArguments
from semantic_kernel.prompt_template import PromptTemplateConfig
"""
The following sample demonstrates how to create a chat completion
agent using Azure OpenAI within Semantic Kernel.
It uses parameterized prompts and shows how to swap between
"semantic-kernel," "jinja2," and "handlebars" template formats,
This sample highlights the agent's chat history conversation
is managed and how kernel arguments are passed in and used.
"""
# Define the inputs and styles to be used in the agent
inputs = [
("Home cooking is great.", None),
("Talk about world peace.", "iambic pentameter"),
("Say something about doing your best.", "e. e. cummings"),
("What do you think about having fun?", "old school rap"),
]
async def invoke_chat_completion_agent(agent: ChatCompletionAgent, inputs):
"""Invokes the given agent with each (input, style) in inputs."""
thread: ChatHistoryAgentThread = None
for user_input, style in inputs:
print(f"[USER]: {user_input}\n")
# If style is specified, override the 'style' argument
argument_overrides = None
if style:
argument_overrides = KernelArguments(style=style)
# Stream agent responses
async for response in agent.invoke_stream(messages=user_input, thread=thread, arguments=argument_overrides):
print(f"{response.content}", end="", flush=True)
thread = response.thread
print()
async def invoke_agent_with_template(template_str: str, template_format: str, default_style: str = "haiku"):
"""Creates an agent with the specified template and format, then invokes it using invoke_chat_completion_agent."""
# Configure the prompt template
prompt_config = PromptTemplateConfig(template=template_str, template_format=template_format)
agent = ChatCompletionAgent(
service=AzureChatCompletion(credential=AzureCliCredential()),
name="MyPoetAgent",
prompt_template_config=prompt_config,
arguments=KernelArguments(style=default_style),
)
await invoke_chat_completion_agent(agent, inputs)
async def main():
# 1) Using "semantic-kernel" format
print("\n===== SEMANTIC-KERNEL FORMAT =====\n")
semantic_kernel_template = """
Write a one verse poem on the requested topic in the style of {{$style}}.
Always state the requested style of the poem.
"""
await invoke_agent_with_template(
template_str=semantic_kernel_template,
template_format="semantic-kernel",
default_style="haiku",
)
# 2) Using "jinja2" format
print("\n===== JINJA2 FORMAT =====\n")
jinja2_template = """
Write a one verse poem on the requested topic in the style of {{style}}.
Always state the requested style of the poem.
"""
await invoke_agent_with_template(template_str=jinja2_template, template_format="jinja2", default_style="haiku")
# 3) Using "handlebars" format
print("\n===== HANDLEBARS FORMAT =====\n")
handlebars_template = """
Write a one verse poem on the requested topic in the style of {{style}}.
Always state the requested style of the poem.
"""
await invoke_agent_with_template(
template_str=handlebars_template, template_format="handlebars", default_style="haiku"
)
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,112 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from typing import Annotated
from azure.identity import AzureCliCredential
from semantic_kernel.agents import ChatCompletionAgent, ChatHistoryAgentThread
from semantic_kernel.connectors.ai.completion_usage import CompletionUsage
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
from semantic_kernel.functions import kernel_function
"""
The following sample demonstrates how to create a chat completion agent
and use it with streaming responses. It also shows how to track token
usage during the streaming process.
"""
# Define a sample plugin for the sample
class MenuPlugin:
"""A sample Menu Plugin used for the concept sample."""
@kernel_function(description="Provides a list of specials from the menu.")
def get_specials(self) -> Annotated[str, "Returns the specials from the menu."]:
return """
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
"""
@kernel_function(description="Provides the price of the requested menu item.")
def get_item_price(
self, menu_item: Annotated[str, "The name of the menu item."]
) -> Annotated[str, "Returns the price of the menu item."]:
return "$9.99"
async def main() -> None:
agent = ChatCompletionAgent(
service=AzureChatCompletion(credential=AzureCliCredential()),
name="Assistant",
instructions="Answer questions about the menu.",
plugins=[MenuPlugin()],
)
# Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: ChatHistoryAgentThread = None
user_inputs = [
"Hello",
"What is the special soup?",
"How much does that cost?",
"Thank you",
]
completion_usage = CompletionUsage()
for user_input in user_inputs:
print(f"\n# User: '{user_input}'")
async for response in agent.invoke_stream(
messages=user_input,
thread=thread,
):
if response.content:
print(response.content, end="", flush=True)
if response.metadata.get("usage"):
completion_usage += response.metadata["usage"]
print(f"\nStreaming Usage: {response.metadata['usage']}")
thread = response.thread
print()
# Print the completion usage
print(f"\nStreaming Total Completion Usage: {completion_usage.model_dump_json(indent=4)}")
"""
Sample Output:
# User: 'Hello'
Hello! How can I help you with the menu today?
# User: 'What is the special soup?'
The special soup today is Clam Chowder. Would you like more details or are you interested in something else from
the menu?
# User: 'How much does that cost?'
The Clam Chowder special soup costs $9.99. Would you like to add it to your order or ask about something else?
# User: 'Thank you'
You're welcome! If you have any more questions or need help with the menu, just let me know. Enjoy your meal!
Streaming Total Completion Usage: {
"prompt_tokens": 1150,
"prompt_tokens_details": {
"audio_tokens": 0,
"cached_tokens": 0
},
"completion_tokens": 134,
"completion_tokens_details": {
"accepted_prediction_tokens": 0,
"audio_tokens": 0,
"reasoning_tokens": 0,
"rejected_prediction_tokens": 0
}
}
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,90 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity import AzureCliCredential
from semantic_kernel.agents import AgentGroupChat, ChatCompletionAgent
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
from semantic_kernel.contents import ChatHistorySummarizationReducer
"""
The following sample demonstrates how to implement a chat history
reducer as part of the Semantic Kernel Agent Framework. For this sample,
the ChatCompletionAgent with an AgentGroupChat is used. The Chat History
Reducer is a Summary Reducer. View the README for more information on
how to use the reducer and what each parameter does.
Note: This sample use the `AgentGroupChat` feature of Semantic Kernel, which is
no longer maintained. For a replacement, consider using the `GroupChatOrchestration`.
Read more about the `GroupChatOrchestration` here:
https://learn.microsoft.com/semantic-kernel/frameworks/agent/agent-orchestration/group-chat?pivots=programming-language-python
Here is a migration guide from `AgentGroupChat` to `GroupChatOrchestration`:
https://learn.microsoft.com/semantic-kernel/support/migration/group-chat-orchestration-migration-guide?pivots=programming-language-python
"""
async def main():
"""
Single-function approach that shows the same chat reducer behavior
while preserving all original logic and code lines (now commented).
"""
# Setup necessary parameters
reducer_msg_count = 10
reducer_threshold = 10
credential = AzureCliCredential()
# Create a summarization reducer and clear its history
history_summarization_reducer = ChatHistorySummarizationReducer(
service=AzureChatCompletion(credential=credential),
target_count=reducer_msg_count,
threshold_count=reducer_threshold,
)
history_summarization_reducer.clear()
# Create our agent
agent = ChatCompletionAgent(
name="NumeroTranslator",
instructions="Add one to the latest user number and spell it in Spanish without explanation.",
service=AzureChatCompletion(credential=credential),
)
# Create a group chat using the reducer
chat = AgentGroupChat(chat_history=history_summarization_reducer)
# Simulate user messages
message_count = 50 # Number of messages to simulate
for index in range(1, message_count, 2):
# Add user message to the chat
await chat.add_chat_message(message=str(index))
print(f"# User: '{index}'")
# Attempt to reduce history
is_reduced = await chat.reduce_history()
if is_reduced:
print(f"@ History reduced to {len(history_summarization_reducer.messages)} messages.")
# Invoke the agent and display responses
async for message in chat.invoke(agent):
print(f"# {message.role} - {message.name or '*'}: '{message.content}'")
# Retrieve messages
msgs = []
async for m in chat.get_chat_messages(agent):
msgs.append(m)
print(f"@ Message Count: {len(msgs)}\n")
# If a reduction happened and we use summarization, print the summary
if is_reduced:
for msg in msgs:
if msg.metadata and msg.metadata.get("__summary__"):
print(f"\tSummary: {msg.content}")
break
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,72 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import logging
from azure.identity import AzureCliCredential
from semantic_kernel.agents import ChatCompletionAgent, ChatHistoryAgentThread
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
from semantic_kernel.contents import ChatHistorySummarizationReducer
"""
The following sample demonstrates how to implement a truncation chat
history reducer as part of the Semantic Kernel Agent Framework. For
this sample, a single ChatCompletionAgent is used.
"""
# Initialize the logger for debugging and information messages
logger = logging.getLogger(__name__)
async def main():
# Setup necessary parameters
reducer_msg_count = 10
reducer_threshold = 10
credential = AzureCliCredential()
# Create a summarization reducer
history_summarization_reducer = ChatHistorySummarizationReducer(
service=AzureChatCompletion(credential=credential),
target_count=reducer_msg_count,
threshold_count=reducer_threshold,
)
thread: ChatHistoryAgentThread = ChatHistoryAgentThread(chat_history=history_summarization_reducer)
# Create our agent
agent = ChatCompletionAgent(
name="NumeroTranslator",
instructions="Add one to the latest user number and spell it in Spanish without explanation.",
service=AzureChatCompletion(credential=credential),
)
# Number of messages to simulate
message_count = 50
for index in range(1, message_count + 1, 2):
print(f"# User: '{index}'")
# Get agent response and store it
response = await agent.get_response(messages=str(index), thread=thread)
thread = response.thread
print(f"# Agent - {response.name}: '{response.content}'")
# Attempt reduction
is_reduced = await thread.reduce()
if is_reduced:
print(f"@ History reduced to {len(thread)} messages.")
print(f"@ Message Count: {len(thread)}\n")
# If reduced, print summary if present
if is_reduced:
async for msg in thread.get_messages():
if msg.metadata and msg.metadata.get("__summary__"):
print(f"\tSummary: {msg.content}")
break
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,113 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from typing import Annotated
from azure.identity import AzureCliCredential
from semantic_kernel.agents import ChatCompletionAgent, ChatHistoryAgentThread
from semantic_kernel.connectors.ai.completion_usage import CompletionUsage
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
from semantic_kernel.functions import kernel_function
"""
The following sample demonstrates how to create a chat completion agent
and use it with non-streaming responses. It also shows how to track token
usage during agent invoke.
"""
# Define a sample plugin for the sample
class MenuPlugin:
"""A sample Menu Plugin used for the concept sample."""
@kernel_function(description="Provides a list of specials from the menu.")
def get_specials(self) -> Annotated[str, "Returns the specials from the menu."]:
return """
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
"""
@kernel_function(description="Provides the price of the requested menu item.")
def get_item_price(
self, menu_item: Annotated[str, "The name of the menu item."]
) -> Annotated[str, "Returns the price of the menu item."]:
return "$9.99"
async def main() -> None:
agent = ChatCompletionAgent(
service=AzureChatCompletion(credential=AzureCliCredential()),
name="Assistant",
instructions="Answer questions about the menu.",
plugins=[MenuPlugin()],
)
# Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: ChatHistoryAgentThread = None
user_inputs = [
"Hello",
"What is the special soup?",
"How much does that cost?",
"Thank you",
]
completion_usage = CompletionUsage()
for user_input in user_inputs:
print(f"\n# User: '{user_input}'")
async for response in agent.invoke(
messages=user_input,
thread=thread,
):
if response.content:
print(response.content)
if response.metadata.get("usage"):
completion_usage += response.metadata["usage"]
thread = response.thread
print()
# Print the completion usage
print(f"\nNon-Streaming Total Completion Usage: {completion_usage.model_dump_json(indent=4)}")
"""
Sample Output:
# User: 'Hello'
Hello! How can I help you with the menu today?
# User: 'What is the special soup?'
The special soup today is Clam Chowder. Would you like to know more about it or see the other specials?
# User: 'How much does that cost?'
The Clam Chowder special costs $9.99. Would you like to add that to your order or need more information?
# User: 'Thank you'
You're welcome! If you have any more questions or need help with the menu, just let me know. Enjoy your day!
Non-Streaming Total Completion Usage: {
"prompt_tokens": 772,
"prompt_tokens_details": {
"audio_tokens": 0,
"cached_tokens": 0
},
"completion_tokens": 92,
"completion_tokens_details": {
"accepted_prediction_tokens": 0,
"audio_tokens": 0,
"reasoning_tokens": 0,
"rejected_prediction_tokens": 0
}
}
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,84 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import logging
from azure.identity import AzureCliCredential
from semantic_kernel.agents import AgentGroupChat, ChatCompletionAgent
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
from semantic_kernel.contents import ChatHistoryTruncationReducer
"""
The following sample demonstrates how to implement a chat history
reducer as part of the Semantic Kernel Agent Framework. For this sample,
the ChatCompletionAgent with an AgentGroupChat is used. The Chat History
Reducer is a Truncation Reducer. View the README for more information on
how to use the reducer and what each parameter does.
Note: This sample use the `AgentGroupChat` feature of Semantic Kernel, which is
no longer maintained. For a replacement, consider using the `GroupChatOrchestration`.
Read more about the `GroupChatOrchestration` here:
https://learn.microsoft.com/semantic-kernel/frameworks/agent/agent-orchestration/group-chat?pivots=programming-language-python
Here is a migration guide from `AgentGroupChat` to `GroupChatOrchestration`:
https://learn.microsoft.com/semantic-kernel/support/migration/group-chat-orchestration-migration-guide?pivots=programming-language-python
"""
# Initialize the logger for debugging and information messages
logger = logging.getLogger(__name__)
async def main():
"""
Single-function approach that shows the same chat reducer behavior
while preserving all original logic and code lines (now commented).
"""
# Setup necessary parameters
reducer_msg_count = 10
reducer_threshold = 10
# Create a truncation reducer and clear its history
history_truncation_reducer = ChatHistoryTruncationReducer(
target_count=reducer_msg_count, threshold_count=reducer_threshold
)
history_truncation_reducer.clear()
# Create our agent
agent = ChatCompletionAgent(
name="NumeroTranslator",
instructions="Add one to the latest user number and spell it in Spanish without explanation.",
service=AzureChatCompletion(credential=AzureCliCredential()),
)
# Create a group chat using the reducer
chat = AgentGroupChat(chat_history=history_truncation_reducer)
# Simulate user messages
message_count = 50 # Number of messages to simulate
for index in range(1, message_count, 2):
# Add user message to the chat
await chat.add_chat_message(message=str(index))
print(f"# User: '{index}'")
# Attempt to reduce history
is_reduced = await chat.reduce_history()
if is_reduced:
print(f"@ History reduced to {len(history_truncation_reducer.messages)} messages.")
# Invoke the agent and display responses
async for message in chat.invoke(agent):
print(f"# {message.role} - {message.name or '*'}: '{message.content}'")
# Retrieve messages
msgs = []
async for m in chat.get_chat_messages(agent):
msgs.append(m)
print(f"@ Message Count: {len(msgs)}\n")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,67 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import logging
from azure.identity import AzureCliCredential
from semantic_kernel.agents import (
ChatCompletionAgent,
)
from semantic_kernel.agents.chat_completion.chat_completion_agent import ChatHistoryAgentThread
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
from semantic_kernel.contents import (
ChatHistoryTruncationReducer,
)
"""
The following sample demonstrates how to implement a truncation chat
history reducer as part of the Semantic Kernel Agent Framework. For
this sample, a single ChatCompletionAgent is used.
"""
# Initialize the logger for debugging and information messages
logger = logging.getLogger(__name__)
async def main():
# Setup necessary parameters
reducer_msg_count = 10
reducer_threshold = 10
# Create a truncation reducer
history_truncation_reducer = ChatHistoryTruncationReducer(
target_count=reducer_msg_count,
threshold_count=reducer_threshold,
)
thread: ChatHistoryAgentThread = ChatHistoryAgentThread(chat_history=history_truncation_reducer)
# Create our agent
agent = ChatCompletionAgent(
name="NumeroTranslator",
instructions="Add one to the latest user number and spell it in Spanish without explanation.",
service=AzureChatCompletion(credential=AzureCliCredential()),
)
# Number of messages to simulate
message_count = 50
for index in range(1, message_count + 1, 2):
print(f"# User: '{index}'")
# Get agent response and store it
response = await agent.get_response(messages=str(index), thread=thread)
thread = response.thread
print(f"# Agent - {response.name}: '{response.content}'")
# Attempt reduction
is_reduced = await thread.reduce()
if is_reduced:
print(f"@ History reduced to {len(thread)} messages.")
print(f"@ Message Count: {len(history_truncation_reducer.messages)}\n")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,96 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity import AzureCliCredential
from semantic_kernel.agents import AgentGroupChat, AzureAIAgent, AzureAIAgentSettings, ChatCompletionAgent
from semantic_kernel.agents.strategies import TerminationStrategy
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
from semantic_kernel.contents import AuthorRole
"""
The following sample demonstrates how to create a Azure AI Foundry Agent,
a chat completion agent and have them participate in a group chat to work towards
the user's requirement.
Note: This sample use the `AgentGroupChat` feature of Semantic Kernel, which is
no longer maintained. For a replacement, consider using the `GroupChatOrchestration`.
Read more about the `GroupChatOrchestration` here:
https://learn.microsoft.com/semantic-kernel/frameworks/agent/agent-orchestration/group-chat?pivots=programming-language-python
Here is a migration guide from `AgentGroupChat` to `GroupChatOrchestration`:
https://learn.microsoft.com/semantic-kernel/support/migration/group-chat-orchestration-migration-guide?pivots=programming-language-python
"""
class ApprovalTerminationStrategy(TerminationStrategy):
"""A strategy for determining when an agent should terminate."""
async def should_agent_terminate(self, agent, history):
"""Check if the agent should terminate."""
return "approved" in history[-1].content.lower()
REVIEWER_NAME = "ArtDirector"
REVIEWER_INSTRUCTIONS = """
You are an art director who has opinions about copywriting born of a love for David Ogilvy.
The goal is to determine if the given copy is acceptable to print.
If so, state that it is approved. Only include the word "approved" if it is so.
If not, provide insight on how to refine suggested copy without example.
"""
COPYWRITER_NAME = "CopyWriter"
COPYWRITER_INSTRUCTIONS = """
You are a copywriter with ten years of experience and are known for brevity and a dry humor.
The goal is to refine and decide on the single best copy as an expert in the field.
Only provide a single proposal per response.
You're laser focused on the goal at hand.
Don't waste time with chit chat.
Consider suggestions when refining an idea.
"""
async def main():
credential = AzureCliCredential()
async with (
# 1. Login to Azure and create a Azure AI Project Client
AzureAIAgent.create_client(credential=credential) as client,
):
# 2. Create agents
agent_writer = AzureAIAgent(
client=client,
definition=await client.agents.create_agent(
model=AzureAIAgentSettings().model_deployment_name,
name=COPYWRITER_NAME,
instructions=COPYWRITER_INSTRUCTIONS,
),
)
agent_reviewer = ChatCompletionAgent(
service=AzureChatCompletion(service_id="artdirector", credential=credential),
name=REVIEWER_NAME,
instructions=REVIEWER_INSTRUCTIONS,
)
# 3. Create the AgentGroupChat object and specify the list of agents along with the termination strategy
chat = AgentGroupChat(
agents=[agent_writer, agent_reviewer],
termination_strategy=ApprovalTerminationStrategy(agents=[agent_reviewer], maximum_iterations=10),
)
# 4. Provide the task an start running
input = "a slogan for a new line of electric cars."
await chat.add_chat_message(input)
print(f"# {AuthorRole.USER}: '{input}'")
async for content in chat.invoke():
print(f"# {content.role} - {content.name or '*'}: '{content.content}'")
# 5. Done and remove the Auzre AI Foundry Agent.
print(f"# IS COMPLETE: {chat.is_complete}")
await client.agents.delete_agent(agent_writer.definition.id)
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,133 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from typing import Annotated
from azure.core.credentials import TokenCredential
from azure.identity import AzureCliCredential
from semantic_kernel.agents import AgentGroupChat, AzureAssistantAgent, ChatCompletionAgent
from semantic_kernel.agents.strategies import TerminationStrategy
from semantic_kernel.connectors.ai import FunctionChoiceBehavior
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion, AzureOpenAISettings
from semantic_kernel.contents import AuthorRole
from semantic_kernel.functions import KernelArguments, kernel_function
from semantic_kernel.kernel import Kernel
"""
The following sample demonstrates how to create an OpenAI
assistant using either Azure OpenAI or OpenAI, a chat completion
agent and have them participate in a group chat to work towards
the user's requirement. The ChatCompletionAgent uses a plugin
that is part of the agent group chat.
Note: This sample use the `AgentGroupChat` feature of Semantic Kernel, which is
no longer maintained. For a replacement, consider using the `GroupChatOrchestration`.
Read more about the `GroupChatOrchestration` here:
https://learn.microsoft.com/semantic-kernel/frameworks/agent/agent-orchestration/group-chat?pivots=programming-language-python
Here is a migration guide from `AgentGroupChat` to `GroupChatOrchestration`:
https://learn.microsoft.com/semantic-kernel/support/migration/group-chat-orchestration-migration-guide?pivots=programming-language-python
"""
class ApprovalTerminationStrategy(TerminationStrategy):
"""A strategy for determining when an agent should terminate."""
async def should_agent_terminate(self, agent, history):
"""Check if the agent should terminate."""
return "approved" in history[-1].content.lower()
REVIEWER_NAME = "ArtDirector"
REVIEWER_INSTRUCTIONS = """
You are an art director who has opinions about copywriting born of a love for David Ogilvy.
The goal is to determine if the given copy is acceptable to print.
If so, state that it is approved. Only include the word "approved" if it is so.
If not, provide insight on how to refine suggested copy without example.
You should always tie the conversation back to the food specials offered by the plugin.
"""
COPYWRITER_NAME = "CopyWriter"
COPYWRITER_INSTRUCTIONS = """
You are a copywriter with ten years of experience and are known for brevity and a dry humor.
The goal is to refine and decide on the single best copy as an expert in the field.
Only provide a single proposal per response.
You're laser focused on the goal at hand.
Don't waste time with chit chat.
Consider suggestions when refining an idea.
"""
class MenuPlugin:
"""A sample Menu Plugin used for the concept sample."""
@kernel_function(description="Provides a list of specials from the menu.")
def get_specials(self) -> Annotated[str, "Returns the specials from the menu."]:
return """
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
"""
@kernel_function(description="Provides the price of the requested menu item.")
def get_item_price(
self, menu_item: Annotated[str, "The name of the menu item."]
) -> Annotated[str, "Returns the price of the menu item."]:
return "$9.99"
def _create_kernel_with_chat_completion(service_id: str, credential: TokenCredential) -> Kernel:
kernel = Kernel()
kernel.add_service(AzureChatCompletion(service_id=service_id, credential=credential))
kernel.add_plugin(plugin=MenuPlugin(), plugin_name="menu")
return kernel
async def main():
credential = AzureCliCredential()
kernel = _create_kernel_with_chat_completion("artdirector", credential)
settings = kernel.get_prompt_execution_settings_from_service_id(service_id="artdirector")
# Configure the function choice behavior to auto invoke kernel functions
settings.function_choice_behavior = FunctionChoiceBehavior.Auto()
agent_reviewer = ChatCompletionAgent(
kernel=kernel,
name=REVIEWER_NAME,
instructions=REVIEWER_INSTRUCTIONS,
arguments=KernelArguments(settings=settings),
)
# Create the Assistant Agent using Azure OpenAI resources
client = AzureAssistantAgent.create_client(credential=credential)
# Create the assistant definition
definition = await client.beta.assistants.create(
model=AzureOpenAISettings().chat_deployment_name,
name=COPYWRITER_NAME,
instructions=COPYWRITER_INSTRUCTIONS,
)
# Create the AzureAssistantAgent instance using the client and the assistant definition
agent_writer = AzureAssistantAgent(client=client, definition=definition)
chat = AgentGroupChat(
agents=[agent_writer, agent_reviewer],
termination_strategy=ApprovalTerminationStrategy(agents=[agent_reviewer], maximum_iterations=10),
)
input = "Write copy based on the food specials."
try:
await chat.add_chat_message(input)
print(f"# {AuthorRole.USER}: '{input}'")
async for content in chat.invoke():
print(f"# {content.role} - {content.name or '*'}: '{content.content}'")
print(f"# IS COMPLETE: {chat.is_complete}")
finally:
await agent_writer.client.beta.assistants.delete(agent_writer.id)
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,117 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from azure.core.credentials import TokenCredential
from azure.identity import AzureCliCredential
from semantic_kernel.agents import AgentGroupChat, AzureAssistantAgent, ChatCompletionAgent
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion, AzureOpenAISettings
from semantic_kernel.contents import AnnotationContent, AuthorRole
from semantic_kernel.kernel import Kernel
"""
The following sample demonstrates how to create an OpenAI
assistant using either Azure OpenAI or OpenAI, a chat completion
agent and have them participate in a group chat working on
an uploaded file.
Note: This sample use the `AgentGroupChat` feature of Semantic Kernel, which is
no longer maintained. For a replacement, consider using the `GroupChatOrchestration`.
Read more about the `GroupChatOrchestration` here:
https://learn.microsoft.com/semantic-kernel/frameworks/agent/agent-orchestration/group-chat?pivots=programming-language-python
Here is a migration guide from `AgentGroupChat` to `GroupChatOrchestration`:
https://learn.microsoft.com/semantic-kernel/support/migration/group-chat-orchestration-migration-guide?pivots=programming-language-python
"""
def _create_kernel_with_chat_completion(service_id: str, credential: TokenCredential) -> Kernel:
kernel = Kernel()
kernel.add_service(AzureChatCompletion(service_id=service_id, credential=credential))
return kernel
async def main():
credential = AzureCliCredential()
file_path = os.path.join(
os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))),
"resources",
"mixed_chat_files",
"user-context.txt",
)
# Create the client using Azure OpenAI resources and configuration
client = AzureAssistantAgent.create_client(credential=credential)
# If desired, create using OpenAI resources
# client = OpenAIAssistantAgent.create_client()
# Load the text file as a FileObject
with open(file_path, "rb") as file:
file = await client.files.create(file=file, purpose="assistants")
code_interpreter_tool, code_interpreter_tool_resource = AzureAssistantAgent.configure_code_interpreter_tool(
file_ids=file.id
)
definition = await client.beta.assistants.create(
model=AzureOpenAISettings().chat_deployment_name,
instructions="Create charts as requested without explanation.",
name="ChartMaker",
tools=code_interpreter_tool,
tool_resources=code_interpreter_tool_resource,
)
# Create the AzureAssistantAgent instance using the client and the assistant definition
analyst_agent = AzureAssistantAgent(client=client, definition=definition)
service_id = "summary"
summary_agent = ChatCompletionAgent(
kernel=_create_kernel_with_chat_completion(service_id=service_id, credential=credential),
instructions="Summarize the entire conversation for the user in natural language.",
name="SummaryAgent",
)
# Create the AgentGroupChat object, which will manage the chat between the agents
# We don't always need to specify the agents in the chat up front
# As shown below, calling `chat.invoke(agent=<agent>)` will automatically add the
# agent to the chat
chat = AgentGroupChat()
try:
user_and_agent_inputs = (
(
"Create a tab delimited file report of the ordered (descending) frequency distribution of "
"words in the file 'user-context.txt' for any words used more than once.",
analyst_agent,
),
(None, summary_agent),
)
for input, agent in user_and_agent_inputs:
if input:
await chat.add_chat_message(input)
print(f"# {AuthorRole.USER}: '{input}'")
async for content in chat.invoke(agent=agent):
print(f"# {content.role} - {content.name or '*'}: '{content.content}'")
if len(content.items) > 0:
for item in content.items:
if (
isinstance(agent, AzureAssistantAgent)
and isinstance(item, AnnotationContent)
and item.file_id
):
print(f"\n`{item.quote}` => {item.file_id}")
response_content = await agent.client.files.content(item.file_id)
print(response_content.text)
finally:
await client.files.delete(file_id=file.id)
await client.beta.assistants.delete(analyst_agent.id)
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,116 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.core.credentials import TokenCredential
from azure.identity import AzureCliCredential
from semantic_kernel.agents import AgentGroupChat, AzureAssistantAgent, ChatCompletionAgent
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion, AzureOpenAISettings
from semantic_kernel.contents import AnnotationContent
from semantic_kernel.contents.utils.author_role import AuthorRole
from semantic_kernel.kernel import Kernel
"""
The following sample demonstrates how to create an OpenAI
assistant using either Azure OpenAI or OpenAI, a chat completion
agent and have them participate in a group chat working with
image content.
Note: This sample use the `AgentGroupChat` feature of Semantic Kernel, which is
no longer maintained. For a replacement, consider using the `GroupChatOrchestration`.
Read more about the `GroupChatOrchestration` here:
https://learn.microsoft.com/semantic-kernel/frameworks/agent/agent-orchestration/group-chat?pivots=programming-language-python
Here is a migration guide from `AgentGroupChat` to `GroupChatOrchestration`:
https://learn.microsoft.com/semantic-kernel/support/migration/group-chat-orchestration-migration-guide?pivots=programming-language-python
"""
def _create_kernel_with_chat_completion(service_id: str, credential: TokenCredential) -> Kernel:
kernel = Kernel()
kernel.add_service(AzureChatCompletion(service_id=service_id, credential=credential))
return kernel
async def main():
credential = AzureCliCredential()
# Create the client using Azure OpenAI resources and configuration
client = AzureAssistantAgent.create_client(credential=credential)
# Get the code interpreter tool and resources
code_interpreter_tool, code_interpreter_resources = AzureAssistantAgent.configure_code_interpreter_tool()
# Create the assistant definition
definition = await client.beta.assistants.create(
model=AzureOpenAISettings().chat_deployment_name,
name="Analyst",
instructions="Create charts as requested without explanation",
tools=code_interpreter_tool,
tool_resources=code_interpreter_resources,
)
# Create the AzureAssistantAgent instance using the client and the assistant definition
analyst_agent = AzureAssistantAgent(client=client, definition=definition)
service_id = "summary"
summary_agent = ChatCompletionAgent(
kernel=_create_kernel_with_chat_completion(service_id=service_id),
instructions="Summarize the entire conversation for the user in natural language.",
name="Summarizer",
)
# Create the AgentGroupChat object, which will manage the chat between the agents
# We don't always need to specify the agents in the chat up front
# As shown below, calling `chat.invoke(agent=<agent>)` will automatically add the
# agent to the chat
chat = AgentGroupChat()
try:
user_and_agent_inputs = (
(
"""
Graph the percentage of storm events by state using a pie chart:
State, StormCount
TEXAS, 4701
KANSAS, 3166
IOWA, 2337
ILLINOIS, 2022
MISSOURI, 2016
GEORGIA, 1983
MINNESOTA, 1881
WISCONSIN, 1850
NEBRASKA, 1766
NEW YORK, 1750
""".strip(),
analyst_agent,
),
(None, summary_agent),
)
for input, agent in user_and_agent_inputs:
if input:
await chat.add_chat_message(input)
print(f"# {AuthorRole.USER}: '{input}'")
async for content in chat.invoke(agent=agent):
print(f"# {content.role} - {content.name or '*'}: '{content.content}'")
if len(content.items) > 0:
for item in content.items:
if (
isinstance(agent, AzureAssistantAgent)
and isinstance(item, AnnotationContent)
and item.file_id
):
print(f"\n`{item.quote}` => {item.file_id}")
response_content = await agent.client.files.content(item.file_id)
print(response_content.text)
finally:
await client.beta.assistants.delete(analyst_agent.id)
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,116 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from typing import TYPE_CHECKING
from azure.core.credentials import TokenCredential
from azure.identity import AzureCliCredential
from semantic_kernel.agents import AgentGroupChat, AzureAssistantAgent, ChatCompletionAgent
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion, AzureOpenAISettings
from semantic_kernel.contents import AuthorRole
from semantic_kernel.kernel import Kernel
if TYPE_CHECKING:
pass
"""
The following sample demonstrates how to create an OpenAI
assistant using either Azure OpenAI or OpenAI, a chat completion
agent and have them participate in a group chat to work towards
the user's requirement. It also demonstrates how the underlying
agent reset method is used to clear the current state of the chat
Note: This sample use the `AgentGroupChat` feature of Semantic Kernel, which is
no longer maintained. For a replacement, consider using the `GroupChatOrchestration`.
Read more about the `GroupChatOrchestration` here:
https://learn.microsoft.com/semantic-kernel/frameworks/agent/agent-orchestration/group-chat?pivots=programming-language-python
Here is a migration guide from `AgentGroupChat` to `GroupChatOrchestration`:
https://learn.microsoft.com/semantic-kernel/support/migration/group-chat-orchestration-migration-guide?pivots=programming-language-python
"""
def _create_kernel_with_chat_completion(service_id: str, credential: TokenCredential) -> Kernel:
kernel = Kernel()
kernel.add_service(AzureChatCompletion(service_id=service_id, credential=credential))
return kernel
async def main():
credential = AzureCliCredential()
# First create the ChatCompletionAgent
chat_agent = ChatCompletionAgent(
kernel=_create_kernel_with_chat_completion("chat", credential),
name="chat_agent",
instructions="""
The user may either provide information or query on information previously provided.
If the query does not correspond with information provided, inform the user that their query
cannot be answered.
""",
)
# Next, we will create the AzureAssistantAgent
# Create the client using Azure OpenAI resources and configuration
client = AzureAssistantAgent.create_client(credential=credential)
# Create the assistant definition
definition = await client.beta.assistants.create(
model=AzureOpenAISettings().chat_deployment_name,
name="copywriter",
instructions="""
The user may either provide information or query on information previously provided.
If the query does not correspond with information provided, inform the user that their query
cannot be answered.
""",
)
# Create the AzureAssistantAgent instance using the client and the assistant definition
assistant_agent = AzureAssistantAgent(
client=client,
definition=definition,
)
# Create the AgentGroupChat object, which will manage the chat between the agents
# We don't always need to specify the agents in the chat up front
# As shown below, calling `chat.invoke(agent=<agent>)` will automatically add the
# agent to the chat
chat = AgentGroupChat()
try:
user_inputs = [
"What is my favorite color?",
"I like green.",
"What is my favorite color?",
"[RESET]",
"What is my favorite color?",
]
for user_input in user_inputs:
# Check for reset indicator
if user_input == "[RESET]":
print("\nResetting chat...")
await chat.reset()
continue
# First agent (assistant_agent) receives the user input
await chat.add_chat_message(user_input)
print(f"\n{AuthorRole.USER}: '{user_input}'")
async for message in chat.invoke(agent=assistant_agent):
if message.content is not None:
print(f"\n# {message.role} - {message.name or '*'}: '{message.content}'")
# Second agent (chat_agent) just responds without new user input
async for message in chat.invoke(agent=chat_agent):
if message.content is not None:
print(f"\n# {message.role} - {message.name or '*'}: '{message.content}'")
finally:
await chat.reset()
await assistant_agent.client.beta.assistants.delete(assistant_agent.id)
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,112 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.core.credentials import TokenCredential
from azure.identity import AzureCliCredential
from semantic_kernel.agents import AgentGroupChat, AzureAssistantAgent, ChatCompletionAgent
from semantic_kernel.agents.strategies import TerminationStrategy
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion, AzureOpenAISettings
from semantic_kernel.contents import AuthorRole
from semantic_kernel.kernel import Kernel
"""
The following sample demonstrates how to create an OpenAI
assistant using either Azure OpenAI or OpenAI, a chat completion
agent and have them participate in a group chat to work towards
the user's requirement.
Note: This sample use the `AgentGroupChat` feature of Semantic Kernel, which is
no longer maintained. For a replacement, consider using the `GroupChatOrchestration`.
Read more about the `GroupChatOrchestration` here:
https://learn.microsoft.com/semantic-kernel/frameworks/agent/agent-orchestration/group-chat?pivots=programming-language-python
Here is a migration guide from `AgentGroupChat` to `GroupChatOrchestration`:
https://learn.microsoft.com/semantic-kernel/support/migration/group-chat-orchestration-migration-guide?pivots=programming-language-python
"""
class ApprovalTerminationStrategy(TerminationStrategy):
"""A strategy for determining when an agent should terminate."""
async def should_agent_terminate(self, agent, history):
"""Check if the agent should terminate."""
return "approved" in history[-1].content.lower()
def _create_kernel_with_chat_completion(service_id: str, credential: TokenCredential) -> Kernel:
kernel = Kernel()
kernel.add_service(AzureChatCompletion(service_id=service_id, credential=credential))
return kernel
async def main():
credential = AzureCliCredential()
# First create a ChatCompletionAgent
agent_reviewer = ChatCompletionAgent(
kernel=_create_kernel_with_chat_completion("artdirector", credential),
name="ArtDirector",
instructions="""
You are an art director who has opinions about copywriting born of a love for David Ogilvy.
The goal is to determine if the given copy is acceptable to print.
If so, state that it is approved. Only include the word "approved" if it is so.
If not, provide insight on how to refine suggested copy without example.
""",
)
# Next, we will create the AzureAssistantAgent
# Create the client using Azure OpenAI resources and configuration
client = AzureAssistantAgent.create_client(credential=credential)
# Create the assistant definition
definition = await client.beta.assistants.create(
model=AzureOpenAISettings().chat_deployment_name,
name="CopyWriter",
instructions="""
You are a copywriter with ten years of experience and are known for brevity and a dry humor.
The goal is to refine and decide on the single best copy as an expert in the field.
Only provide a single proposal per response.
You're laser focused on the goal at hand.
Don't waste time with chit chat.
Consider suggestions when refining an idea.
""",
)
# Create the AzureAssistantAgent instance using the client and the assistant definition
agent_writer = AzureAssistantAgent(
client=client,
definition=definition,
)
# Create the AgentGroupChat object, which will manage the chat between the agents
chat = AgentGroupChat(
agents=[agent_writer, agent_reviewer],
termination_strategy=ApprovalTerminationStrategy(agents=[agent_reviewer], maximum_iterations=10),
)
input = "a slogan for a new line of electric cars."
try:
await chat.add_chat_message(input)
print(f"# {AuthorRole.USER}: '{input}'")
last_agent = None
async for message in chat.invoke_stream():
if message.content is not None:
if last_agent != message.name:
print(f"\n# {message.name}: ", end="", flush=True)
last_agent = message.name
print(f"{message.content}", end="", flush=True)
print()
print(f"# IS COMPLETE: {chat.is_complete}")
finally:
await agent_writer.client.beta.assistants.delete(agent_writer.id)
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,99 @@
## OpenAI Assistant Agents
The following getting started samples show how to use OpenAI Assistant agents with Semantic Kernel.
## Assistants API Overview
The Assistants API is a robust solution from OpenAI that empowers developers to integrate powerful, purpose-built AI assistants into their applications. It streamlines the development process by handling conversation histories, managing threads, and providing seamless access to advanced tools.
### Key Features
- **Purpose-Built AI Assistants:**
Assistants are specialized AIs that leverage OpenAIs models to interact with users, access files, maintain persistent threads, and call additional tools. This enables highly tailored and effective user interactions.
- **Simplified Conversation Management:**
The concept of a **thread** -- a dedicated conversation session between an assistant and a user -- ensures that message history is managed automatically. Threads optimize the conversation context by storing and truncating messages as needed.
- **Integrated Tool Access:**
The API provides built-in tools such as:
- **Code Interpreter:** Allows the assistant to execute code, enhancing its ability to solve complex tasks.
- **File Search:** Implements best practices for retrieving data from uploaded files, including advanced chunking and embedding techniques.
- **Enhanced Function Calling:**
With improved support for third-party tool integration, the Assistants API enables assistants to extend their capabilities beyond native functions.
For more detailed technical information, refer to the [Assistants API](https://platform.openai.com/docs/assistants/overview).
### Semantic Kernel OpenAI Assistant Agents
OpenAI Assistant Agents are created in the following way:
```python
from semantic_kernel.agents import OpenAIAssistantAgent
# Create the client using OpenAI resources and configuration
client = OpenAIAssistantAgent.create_client()
# Create the assistant definition
definition = await client.beta.assistants.create(
model=AzureOpenAISettings().chat_deployment_name
instructions="<instructions>",
name="<name>",
)
# Define the Semantic Kernel OpenAI Assistant Agent
agent = OpenAIAssistantAgent(
client=client,
definition=definition,
)
# Define a thread
thread = None
# Invoke the agent
async for content in agent.invoke(messages="user input", thread=thread):
print(f"# {content.role}: {content.content}")
# Grab the thread from the response to continue with the current context
thread = response.thread
```
### Semantic Kernel Azure Assistant Agents
Azure Assistant Agents are currently in preview and require a `-preview` API version (minimum version: `2024-05-01-preview`). As new features are introduced, API versions will be updated accordingly. For the latest versioning details, please refer to the [Azure OpenAI API preview lifecycle](https://learn.microsoft.com/azure/ai-services/openai/api-version-deprecation).
To specify the correct API version, set the following environment variable (for example, in your `.env` file):
```bash
AZURE_OPENAI_API_VERSION="2025-01-01-preview"
```
Alternatively, you can pass the `api_version` parameter when creating an `AzureAssistantAgent`:
```python
from semantic_kernel.agents import AzureAssistantAgent
# Create the client using Azure OpenAI resources and configuration
client = AzureAssistantAgent.create_client()
# Create the assistant definition
definition = await client.beta.assistants.create(
model=AzureOpenAISettings().chat_deployment_name
instructions="<instructions>",
name="<name>",
)
# Define the Semantic Kernel Azure OpenAI Assistant Agent
agent = AzureAssistantAgent(
client=client,
definition=definition,
)
# Define a thread
thread = None
# Invoke the agent
async for content in agent.invoke(messages="user input", thread=thread):
print(f"# {content.role}: {content.content}")
# Grab the thread from the response to continue with the current context
thread = response.thread
```
@@ -0,0 +1,143 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from azure.identity import AzureCliCredential
from semantic_kernel.agents import AgentRegistry, AzureAssistantAgent
"""
The following sample demonstrates how to create an Azure Assistant Agent that answers
user questions using the code interpreter tool.
The agent is then used to answer user questions that require code to be generated and
executed. The responses are handled in a streaming manner.
"""
# Define the YAML string for the sample
spec = """
type: azure_assistant
name: CodeInterpreterAgent
description: Agent with code interpreter tool.
instructions: >
Use the code interpreter tool to answer questions that require code to be generated
and executed.
model:
id: ${AzureOpenAI:ChatModelId}
connection:
api_key: ${AzureOpenAI:ApiKey}
tools:
- type: code_interpreter
options:
file_ids:
- ${AzureOpenAI:FileId1}
"""
async def main():
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
csv_file_path = os.path.join(
os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))),
"resources",
"agent_assistant_file_manipulation",
"sales.csv",
)
# Load the employees PDF file as a FileObject
with open(csv_file_path, "rb") as file:
file = await client.files.create(file=file, purpose="assistants")
try:
# Create the Assistant Agent from the YAML spec
# Note: the extras can be provided in the short-format (shown below) or
# in the long-format (as shown in the YAML spec, with the `AzureOpenAI:` prefix).
# The short-format is used here for brevity
agent: AzureAssistantAgent = await AgentRegistry.create_from_yaml(
yaml_str=spec,
client=client,
extras={"AzureOpenAI:FileId1": file.id},
)
# Define the task for the agent
TASK = "Give me the code to calculate the total sales for all segments."
print(f"# User: '{TASK}'")
# Invoke the agent for the specified task
is_code = False
last_role = None
async for response in agent.invoke_stream(
messages=TASK,
):
current_is_code = response.metadata.get("code", False)
if current_is_code:
if not is_code:
print("\n\n```python")
is_code = True
print(response.content, end="", flush=True)
else:
if is_code:
print("\n```")
is_code = False
last_role = None
if hasattr(response, "role") and response.role is not None and last_role != response.role:
print(f"\n# {response.role}: ", end="", flush=True)
last_role = response.role
print(response.content, end="", flush=True)
if is_code:
print("```\n")
print()
finally:
# Cleanup: Delete the thread and agent
await client.beta.assistants.delete(agent.id)
await client.files.delete(file.id)
"""
Sample output:
# User: 'Give me the code to calculate the total sales for all segments.'
# AuthorRole.ASSISTANT: Let me first examine the contents of the uploaded file to determine its structure. This
will allow me to create the appropriate code for calculating the total sales for all segments. Hang tight!
```python
import pandas as pd
# Load the uploaded file to examine its contents
file_path = '/mnt/data/assistant-3nXizu2EX2EwXikUz71uNc'
data = pd.read_csv(file_path)
# Display the first few rows and column names to understand the structure of the dataset
data.head(), data.columns
```
# AuthorRole.ASSISTANT: The dataset contains several columns, including `Segment`, `Sales`, and others such as
`Country`, `Product`, and date-related information. To calculate the total sales for all segments, we will:
1. Group the data by the `Segment` column.
2. Sum the `Sales` column for each segment.
3. Calculate the grand total of all sales across all segments.
Here is the code snippet for this task:
```python
# Group by 'Segment' and sum up 'Sales'
segment_sales = data.groupby('Segment')['Sales'].sum()
# Calculate the total sales across all segments
total_sales = segment_sales.sum()
print("Total Sales per Segment:")
print(segment_sales)
print(f"\nGrand Total Sales: {total_sales}")
```
Would you like me to execute this directly for the uploaded data?
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,99 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from azure.identity import AzureCliCredential
from semantic_kernel.agents import AgentRegistry, AzureAssistantAgent
"""
The following sample demonstrates how to create an Azure Assistant Agent that answers
user questions using the file search tool.
The agent is used to answer user questions that require file search to help ground
answers from the model.
"""
# Define the YAML string for the sample
spec = """
type: azure_assistant
name: FileSearchAgent
description: Agent with file search tool.
instructions: >
Use the file search tool to answer questions from the user.
model:
id: ${AzureOpenAI:ChatModelId}
connection:
api_key: ${AzureOpenAI:ApiKey}
tools:
- type: file_search
options:
vector_store_ids:
- ${AzureOpenAI:VectorStoreId}
"""
async def main():
# Setup the OpenAI Assistant client
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
# Read and upload the file to the OpenAI AI service
pdf_file_path = os.path.join(
os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))),
"resources",
"file_search",
"employees.pdf",
)
# Upload the pdf file to the assistant service
with open(pdf_file_path, "rb") as file:
file = await client.files.create(file=file, purpose="assistants")
vector_store = await client.vector_stores.create(
name="assistant_file_search",
file_ids=[file.id],
)
try:
# Create the Assistant Agent from the YAML spec
# Note: the extras can be provided in the short-format (shown below) or
# in the long-format (as shown in the YAML spec, with the `AzureOpenAI:` prefix).
# The short-format is used here for brevity
agent: AzureAssistantAgent = await AgentRegistry.create_from_yaml(
yaml_str=spec,
client=client,
extras={"AzureOpenAI:VectorStoreId": vector_store.id},
)
# Define the task for the agent
TASK = "Who can help me if I have a sales question?"
print(f"# User: '{TASK}'")
# Invoke the agent for the specified task
async for response in agent.invoke(
messages=TASK,
):
print(f"# {response.name}: {response}")
finally:
# Cleanup: Delete the agent, vector store, and file
await client.beta.assistants.delete(agent.id)
await client.vector_stores.delete(vector_store.id)
await client.files.delete(file.id)
"""
Sample output:
# User: 'Who can help me if I have a sales question?'
# FileSearchAgent: If you have a sales question, you may contact the following individuals:
1. **Hicran Bea** - Sales Manager
2. **Mariam Jaslyn** - Sales Representative
3. **Angelino Embla** - Sales Representative
This information comes from the employee records【4:0†source】.
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,102 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from typing import Annotated
from azure.identity import AzureCliCredential
from semantic_kernel.agents import AgentRegistry, AzureAssistantAgent
from semantic_kernel.functions import kernel_function
"""
The following sample demonstrates how to create an Azure Assistant Agent that answers
user questions. The sample shows how to load a declarative spec from a file.
The plugins/functions must already exist in the kernel.
They are not created declaratively via the spec.
"""
class MenuPlugin:
"""A sample Menu Plugin used for the concept sample."""
@kernel_function(description="Provides a list of specials from the menu.")
def get_specials(self) -> Annotated[str, "Returns the specials from the menu."]:
return """
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
"""
@kernel_function(description="Provides the price of the requested menu item.")
def get_item_price(
self, menu_item: Annotated[str, "The name of the menu item."]
) -> Annotated[str, "Returns the price of the menu item."]:
return "$9.99"
async def main():
try:
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
# Define the YAML file path for the sample
file_path = os.path.join(
os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))),
"resources",
"declarative_spec",
"azure_assistant_spec.yaml",
)
# Create the Assistant Agent from the YAML spec
agent: AzureAssistantAgent = await AgentRegistry.create_from_file(
file_path,
plugins=[MenuPlugin()],
client=client,
)
# Create the agent
user_inputs = [
"Hello",
"What is the special soup?",
"How much does that cost?",
"Thank you",
]
# Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread = None
for user_input in user_inputs:
print(f"# User: '{user_input}'")
# Invoke the agent for the specified task
async for response in agent.invoke(
messages=user_input,
thread=thread,
):
print(f"# {response.name}: {response}")
# Store the thread for the next iteration
thread = response.thread
finally:
# Cleanup: Delete the thread and agent
await client.beta.assistants.delete(agent.id) if agent else None
await thread.delete() if thread else None
"""
Sample Output:
# User: 'Hello'
# Host: Hi there! How can I assist you today?
# User: 'What is the special soup?'
# Host: The special soup is Clam Chowder.
# User: 'What is the special drink?'
# Host: The special drink is Chai Tea.
# User: 'How much is it?'
# Host: The Chai Tea costs $9.99.
# User: 'Thank you'
# Host: You're welcome! If you have any more questions, feel free to ask.
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,74 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity import AzureCliCredential
from semantic_kernel.agents import AgentRegistry, AzureAssistantAgent
"""
The following sample demonstrates how to create an Azure Assistant Agent that invokes
a story generation task using a prompt template and a declarative spec.
"""
# Define the YAML string for the sample
spec = """
type: azure_assistant
name: StoryAgent
description: An agent that generates a story about a topic.
instructions: Tell a story about {{$topic}} that is {{$length}} sentences long.
model:
id: ${AzureOpenAI:ChatModelId}
connection:
endpoint: ${AzureOpenAI:Endpoint}
inputs:
topic:
description: The topic of the story.
required: true
default: Cats
length:
description: The number of sentences in the story.
required: true
default: 2
outputs:
output1:
description: The generated story.
template:
format: semantic-kernel
"""
async def main():
# Setup the OpenAI Assistant client
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
try:
# Create the Assistant Agent from the YAML spec
# Note: the extras can be provided in the short-format (shown below) or
# in the long-format (as shown in the YAML spec, with the `AzureOpenAI:` prefix).
# The short-format is used here for brevity
agent: AzureAssistantAgent = await AgentRegistry.create_from_yaml(
yaml_str=spec,
client=client,
)
# Invoke the agent for the specified task
async for response in agent.invoke(
messages=None,
):
print(f"# {response.name}: {response}")
finally:
# Cleanup: Delete the agent, vector store, and file
await client.beta.assistants.delete(agent.id)
"""
Sample output:
# StoryAgent: Under the silvery moon, three mischievous cats tiptoed across the rooftop, chasing
shadows and sharing secret whispers. By dawn, they curled up together, purring softly, dreaming
of adventures yet to come.
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,66 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity import AzureCliCredential
from semantic_kernel.agents import AgentRegistry, AzureAssistantAgent
"""
The following sample demonstrates how to create an Azure Assistant Agent based
on an existing agent ID.
"""
# Define the YAML string for the sample
spec = """
id: ${AzureOpenAI:AgentId}
type: azure_assistant
instructions: You are helpful agent who always responds in French.
"""
async def main():
try:
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
# Create the Assistant Agent from the YAML spec
# Note: the extras can be provided in the short-format (shown below) or
# in the long-format (as shown in the YAML spec, with the `AzureOpenAI:` prefix).
# The short-format is used here for brevity
agent: AzureAssistantAgent = await AgentRegistry.create_from_yaml(
yaml_str=spec,
client=client,
extras={"AgentId": "<my-agent-id>"}, # Specify the existing agent ID
)
# Define the task for the agent
TASK = "Why is the sky blue?"
print(f"# User: '{TASK}'")
# Invoke the agent for the specified task
async for response in agent.invoke(
messages=TASK,
):
print(f"# {response.name}: {response}")
finally:
# Cleanup: Delete the thread and agent
await client.beta.assistants.delete(agent.id)
"""
Sample output:
# User: 'Why is the sky blue?'
# WeatherAgent: Le ciel est bleu à cause d'un phénomène appelé **diffusion de Rayleigh**. La lumière du
Soleil est composée de toutes les couleurs du spectre visible, mais lorsqu'elle traverse l'atmosphère
terrestre, elle entre en contact avec les molécules d'air et les particules présentes.
Les couleurs à courtes longueurs d'onde, comme le bleu et le violet, sont diffusées dans toutes les directions
beaucoup plus efficacement que les couleurs à longues longueurs d'onde, comme le rouge et l'orange. Bien que le
violet ait une longueur d'onde encore plus courte que le bleu, nos yeux sont moins sensibles à cette couleur,
et une partie du violet est également absorbée par la haute atmosphère. Ainsi, le bleu domine, donnant au ciel
sa couleur caractéristique.
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,176 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from typing import Annotated
from azure.identity import AzureCliCredential
from semantic_kernel.agents import AzureAssistantAgent
from semantic_kernel.connectors.ai.open_ai import AzureOpenAISettings
from semantic_kernel.contents import ChatMessageContent, FunctionCallContent, FunctionResultContent
from semantic_kernel.filters import (
AutoFunctionInvocationContext,
FilterTypes,
)
from semantic_kernel.functions import FunctionResult, kernel_function
from semantic_kernel.kernel import Kernel
"""
The following sample demonstrates how to create an OpenAI Assistant agent that
answers user questions. This sample demonstrates the basic steps to create an agent
and simulate a conversation with the agent.
This sample demonstrates how to create a filter that will be called for each
function call in the response. The filter can be used to modify the function
result or to terminate the function call. The filter can also be used to
log the function call or to perform any other action before or after the
function call.
"""
class MenuPlugin:
"""A sample Menu Plugin used for the concept sample."""
@kernel_function(description="Provides a list of specials from the menu.")
def get_specials(self) -> Annotated[str, "Returns the specials from the menu."]:
return """
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
"""
@kernel_function(description="Provides the price of the requested menu item.")
def get_item_price(
self, menu_item: Annotated[str, "The name of the menu item."]
) -> Annotated[str, "Returns the price of the menu item."]:
return "$9.99"
# Define a kernel instance so we can attach the filter to it
kernel = Kernel()
# Define a list to store intermediate steps
intermediate_steps: list[ChatMessageContent] = []
# Define a callback function to handle intermediate step content messages
async def handle_intermediate_steps(message: ChatMessageContent) -> None:
intermediate_steps.append(message)
@kernel.filter(FilterTypes.AUTO_FUNCTION_INVOCATION)
async def auto_function_invocation_filter(context: AutoFunctionInvocationContext, next):
"""A filter that will be called for each function call in the response."""
print("\nAuto function invocation filter")
print(f"Function: {context.function.name}")
# if we don't call next, it will skip this function, and go to the next one
await next(context)
"""
Note: to simply return the unaltered function results, uncomment the `context.terminate = True` line and
comment out the lines starting with `result = context.function_result` through `context.terminate = True`.
context.terminate = True
For this sample, simply setting `context.terminate = True` will return the unaltered function result:
Auto function invocation filter
Function: get_specials
# Assistant: MenuPlugin-get_specials -
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
"""
result = context.function_result
if "menu" in context.function.plugin_name.lower():
print("Altering the Menu plugin function result...\n")
context.function_result = FunctionResult(
function=result.function,
value="We are sold out, sorry!",
)
context.terminate = True
# Simulate a conversation with the agent
USER_INPUTS = ["What's the special food on the menu?", "What should I do then?"]
async def main() -> None:
# 1. Create the client using Azure OpenAI resources and configuration
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
# 2. Define the assistant definition
definition = await client.beta.assistants.create(
model=AzureOpenAISettings().chat_deployment_name,
name="Host",
instructions="Answer questions about the menu.",
)
# 3. Create the AzureAssistantAgent instance using the client and the assistant definition and the defined plugin
agent = AzureAssistantAgent(
client=client,
definition=definition,
plugins=[MenuPlugin()],
kernel=kernel,
)
# 4. Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread = None
try:
for user_input in USER_INPUTS:
print(f"# User: {user_input}")
# 5. Invoke the agent with the specified message for response
async for response in agent.invoke(
messages=user_input, thread=thread, on_intermediate_message=handle_intermediate_steps
):
# 6. Print the response from the agent
print(f"# {response.name}: {response}")
thread = response.thread
finally:
# 7. Cleanup: Delete the thread and agent
await thread.delete() if thread else None
await client.beta.assistants.delete(assistant_id=agent.id)
# Print the intermediate steps
print("\nIntermediate Steps:")
for msg in intermediate_steps:
if any(isinstance(item, FunctionResultContent) for item in msg.items):
for fr in msg.items:
if isinstance(fr, FunctionResultContent):
print(f"Function Result:> {fr.result} for function: {fr.name}")
elif any(isinstance(item, FunctionCallContent) for item in msg.items):
for fcc in msg.items:
if isinstance(fcc, FunctionCallContent):
print(f"Function Call:> {fcc.name} with arguments: {fcc.arguments}")
else:
print(f"{msg.role}: {msg.content}")
"""
Sample Output:
# User: What's the special food on the menu?
Auto function invocation filter
Function: get_specials
Altering the Menu plugin function result...
# Host: I'm sorry, but all the specials on the menu are currently sold out. If there's anything else you're
looking for, please let me know!
# User: What should I do then?
# Host: You might consider ordering from the regular menu items instead. If you need any recommendations or
information about specific items, such as prices or ingredients, feel free to ask!
Intermediate Steps:
Function Call:> MenuPlugin-get_specials with arguments: {}
Function Result:> We are sold out, sorry! for function: MenuPlugin-get_specials
AuthorRole.ASSISTANT: I'm sorry, but all the specials on the menu are currently sold out. If there's anything
else you're looking for, please let me know!
AuthorRole.ASSISTANT: You might consider ordering from the regular menu items instead. If you need any
recommendations or information about specific items, such as prices or ingredients, feel free to ask!
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,181 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from typing import Annotated
from azure.identity import AzureCliCredential
from semantic_kernel.agents import AzureAssistantAgent
from semantic_kernel.connectors.ai.open_ai import AzureOpenAISettings
from semantic_kernel.contents import ChatMessageContent, FunctionCallContent, FunctionResultContent
from semantic_kernel.filters import (
AutoFunctionInvocationContext,
FilterTypes,
)
from semantic_kernel.functions import FunctionResult, kernel_function
from semantic_kernel.kernel import Kernel
"""
The following sample demonstrates how to create an OpenAI Assistant agent that
answers user questions. This sample demonstrates the basic steps to create an agent
and simulate a conversation with the agent.
This sample demonstrates how to create a filter that will be called for each
function call in the response. The filter can be used to modify the function
result or to terminate the function call. The filter can also be used to
log the function call or to perform any other action before or after the
function call.
"""
class MenuPlugin:
"""A sample Menu Plugin used for the concept sample."""
@kernel_function(description="Provides a list of specials from the menu.")
def get_specials(self) -> Annotated[str, "Returns the specials from the menu."]:
return """
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
"""
@kernel_function(description="Provides the price of the requested menu item.")
def get_item_price(
self, menu_item: Annotated[str, "The name of the menu item."]
) -> Annotated[str, "Returns the price of the menu item."]:
return "$9.99"
# Define a kernel instance so we can attach the filter to it
kernel = Kernel()
# Define a list to store intermediate steps
intermediate_steps: list[ChatMessageContent] = []
# Define a callback function to handle intermediate step content messages
async def handle_intermediate_steps(message: ChatMessageContent) -> None:
intermediate_steps.append(message)
@kernel.filter(FilterTypes.AUTO_FUNCTION_INVOCATION)
async def auto_function_invocation_filter(context: AutoFunctionInvocationContext, next):
"""A filter that will be called for each function call in the response."""
print("\nAuto function invocation filter")
print(f"Function: {context.function.name}")
# if we don't call next, it will skip this function, and go to the next one
await next(context)
"""
Note: to simply return the unaltered function results, uncomment the `context.terminate = True` line and
comment out the lines starting with `result = context.function_result` through `context.terminate = True`.
context.terminate = True
For this sample, simply setting `context.terminate = True` will return the unaltered function result:
Auto function invocation filter
Function: get_specials
# Assistant: MenuPlugin-get_specials -
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
"""
result = context.function_result
if "menu" in context.function.plugin_name.lower():
print("Altering the Menu plugin function result...\n")
context.function_result = FunctionResult(
function=result.function,
value="We are sold out, sorry!",
)
context.terminate = True
# Simulate a conversation with the agent
USER_INPUTS = ["What's the special food on the menu?", "What should I do then?"]
async def main() -> None:
# 1. Create the client using Azure OpenAI resources and configuration
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
# 2. Define the assistant definition
definition = await client.beta.assistants.create(
model=AzureOpenAISettings().chat_deployment_name,
name="Host",
instructions="Answer questions about the menu.",
)
# 3. Create the AzureAssistantAgent instance using the client and the assistant definition and the defined plugin
agent = AzureAssistantAgent(
client=client,
definition=definition,
plugins=[MenuPlugin()],
kernel=kernel,
)
# 4. Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread = None
try:
for user_input in USER_INPUTS:
print(f"# User: {user_input}")
# 5. Invoke the agent with the specified message for response
first_chunk = True
async for response in agent.invoke_stream(
messages=user_input, thread=thread, on_intermediate_message=handle_intermediate_steps
):
# 6. Print the response
if first_chunk:
print(f"# {response.name}: ", end="", flush=True)
first_chunk = False
print(f"{response}", end="", flush=True)
thread = response.thread
print()
finally:
# 7. Cleanup: Delete the thread and agent
await thread.delete() if thread else None
await client.beta.assistants.delete(assistant_id=agent.id)
# Print the intermediate steps
print("\nIntermediate Steps:")
for msg in intermediate_steps:
if any(isinstance(item, FunctionResultContent) for item in msg.items):
for fr in msg.items:
if isinstance(fr, FunctionResultContent):
print(f"Function Result:> {fr.result} for function: {fr.name}")
elif any(isinstance(item, FunctionCallContent) for item in msg.items):
for fcc in msg.items:
if isinstance(fcc, FunctionCallContent):
print(f"Function Call:> {fcc.name} with arguments: {fcc.arguments}")
else:
print(f"{msg.role}: {msg.content}")
"""
Sample Output:
# User: What's the special food on the menu?
Auto function invocation filter
Function: get_specials
Altering the Menu plugin function result...
# Host: I'm sorry, but all the specials on the menu are currently sold out. If there's anything else you're
looking for, please let me know!
# User: What should I do then?
# Host: You might consider ordering from the regular menu items instead. If you need any recommendations or
information about specific items, such as prices or ingredients, feel free to ask!
Intermediate Steps:
Function Call:> MenuPlugin-get_specials with arguments: {}
Function Result:> We are sold out, sorry! for function: MenuPlugin-get_specials
AuthorRole.ASSISTANT: I'm sorry, but all the specials on the menu are currently sold out. If there's anything
else you're looking for, please let me know!
AuthorRole.ASSISTANT: You might consider ordering from the regular menu items instead. If you need any
recommendations or information about specific items, such as prices or ingredients, feel free to ask!
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,86 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity import AzureCliCredential
from samples.concepts.agents.openai_assistant.openai_assistant_sample_utils import download_response_images
from semantic_kernel.agents import AssistantAgentThread, AzureAssistantAgent
from semantic_kernel.connectors.ai.open_ai import AzureOpenAISettings
from semantic_kernel.contents import FileReferenceContent
"""
The following sample demonstrates how to create an OpenAI
assistant using either Azure OpenAI or OpenAI and leverage the
assistant and leverage the assistant's code interpreter tool
in a streaming fashion.
"""
async def main():
# Create the client using Azure OpenAI resources and configuration
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
# Get the code interpreter tool and resources
code_interpreter_tool, code_interpreter_resource = AzureAssistantAgent.configure_code_interpreter_tool()
# Define the assistant definition
definition = await client.beta.assistants.create(
model=AzureOpenAISettings().chat_deployment_name,
instructions="Create charts as requested without explanation.",
name="ChartMaker",
tools=code_interpreter_tool,
tool_resources=code_interpreter_resource,
)
# Create the AzureAssistantAgent instance using the client and the assistant definition
agent = AzureAssistantAgent(
client=client,
definition=definition,
)
# Create a new thread for use with the assistant
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: AssistantAgentThread = None
user_inputs = [
"""
Display this data using a bar-chart:
Banding Brown Pink Yellow Sum
X00000 339 433 126 898
X00300 48 421 222 691
X12345 16 395 352 763
Others 23 373 156 552
Sum 426 1622 856 2904
""",
"Can you regenerate this same chart using the category names as the bar colors?",
]
try:
for user_input in user_inputs:
file_ids = []
async for response in agent.invoke(messages=user_input, thread=thread):
thread = response.thread
if response.content:
print(f"# {response.role}: {response}")
if len(response.items) > 0:
for item in response.items:
if isinstance(item, FileReferenceContent):
file_ids.extend([
item.file_id
for item in response.items
if isinstance(item, FileReferenceContent) and item.file_id is not None
])
# Use a sample utility method to download the files to the current working directory
await download_response_images(agent, file_ids)
finally:
await thread.delete() if thread else None
await client.beta.assistants.delete(assistant_id=agent.id)
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,103 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity import AzureCliCredential
from samples.concepts.agents.openai_assistant.openai_assistant_sample_utils import download_response_images
from semantic_kernel.agents import AssistantAgentThread, AzureAssistantAgent
from semantic_kernel.connectors.ai.open_ai import AzureOpenAISettings
from semantic_kernel.contents import StreamingFileReferenceContent
"""
The following sample demonstrates how to create an OpenAI
assistant using either Azure OpenAI or OpenAI and leverage the
assistant and leverage the assistant's code interpreter tool
in a streaming fashion.
"""
async def main():
# Create the client using Azure OpenAI resources and configuration
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
# Get the code interpreter tool and resources
code_interpreter_tool, code_interpreter_resource = AzureAssistantAgent.configure_code_interpreter_tool()
# Define the assistant definition
definition = await client.beta.assistants.create(
model=AzureOpenAISettings().chat_deployment_name,
instructions="Create charts as requested without explanation.",
name="ChartMaker",
tools=code_interpreter_tool,
tool_resources=code_interpreter_resource,
)
# Create the AzureAssistantAgent instance using the client and the assistant definition
agent = AzureAssistantAgent(
client=client,
definition=definition,
)
# Create a new thread for use with the assistant
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: AssistantAgentThread = None
user_inputs = [
"""
Display this data using a bar-chart:
Banding Brown Pink Yellow Sum
X00000 339 433 126 898
X00300 48 421 222 691
X12345 16 395 352 763
Others 23 373 156 552
Sum 426 1622 856 2904
""",
"Can you regenerate this same chart using the category names as the bar colors?",
]
try:
for user_input in user_inputs:
print(f"# User: '{user_input}'")
file_ids: list[str] = []
is_code = False
last_role = None
async for response in agent.invoke_stream(messages=user_input, thread=thread):
thread = response.thread
current_is_code = response.metadata.get("code", False)
if current_is_code:
if not is_code:
print("\n\n```python")
is_code = True
print(response.content, end="", flush=True)
else:
if is_code:
print("\n```")
is_code = False
last_role = None
if hasattr(response, "role") and response.role is not None and last_role != response.role:
print(f"\n# {response.role}: ", end="", flush=True)
last_role = response.role
print(response.content, end="", flush=True)
file_ids.extend([
item.file_id
for item in response.items
if isinstance(item, StreamingFileReferenceContent) and item.file_id is not None
])
if is_code:
print("```\n")
# Use a sample utility method to download the files to the current working directory
await download_response_images(agent, file_ids)
file_ids.clear()
finally:
await thread.delete() if thread else None
await client.beta.assistants.delete(assistant_id=agent.id)
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,141 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from semantic_kernel.agents import AgentRegistry, OpenAIAssistantAgent
"""
The following sample demonstrates how to create an OpenAI Assistant Agent that answers
user questions using the code interpreter tool.
The agent is then used to answer user questions that require code to be generated and
executed. The responses are handled in a streaming manner.
"""
# Define the YAML string for the sample
spec = """
type: openai_assistant
name: CodeInterpreterAgent
description: Agent with code interpreter tool.
instructions: >
Use the code interpreter tool to answer questions that require code to be generated
and executed.
model:
id: ${OpenAI:ChatModelId}
connection:
api_key: ${OpenAI:ApiKey}
tools:
- type: code_interpreter
options:
file_ids:
- ${OpenAI:FileId1}
"""
async def main():
client = OpenAIAssistantAgent.create_client()
csv_file_path = os.path.join(
os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))),
"resources",
"agent_assistant_file_manipulation",
"sales.csv",
)
# Load the employees PDF file as a FileObject
with open(csv_file_path, "rb") as file:
file = await client.files.create(file=file, purpose="assistants")
try:
# Create the Assistant Agent from the YAML spec
# Note: the extras can be provided in the short-format (shown below) or
# in the long-format (as shown in the YAML spec, with the `OpenAI:` prefix).
# The short-format is used here for brevity
agent: OpenAIAssistantAgent = await AgentRegistry.create_from_yaml(
yaml_str=spec,
client=client,
extras={"OpenAI:FileId1": file.id},
)
# Define the task for the agent
TASK = "Give me the code to calculate the total sales for all segments."
print(f"# User: '{TASK}'")
# Invoke the agent for the specified task
is_code = False
last_role = None
async for response in agent.invoke_stream(
messages=TASK,
):
current_is_code = response.metadata.get("code", False)
if current_is_code:
if not is_code:
print("\n\n```python")
is_code = True
print(response.content, end="", flush=True)
else:
if is_code:
print("\n```")
is_code = False
last_role = None
if hasattr(response, "role") and response.role is not None and last_role != response.role:
print(f"\n# {response.role}: ", end="", flush=True)
last_role = response.role
print(response.content, end="", flush=True)
if is_code:
print("```\n")
print()
finally:
# Cleanup: Delete the thread and agent
await client.beta.assistants.delete(agent.id)
await client.files.delete(file.id)
"""
Sample output:
# User: 'Give me the code to calculate the total sales for all segments.'
# AuthorRole.ASSISTANT: Let me first examine the contents of the uploaded file to determine its structure. This
will allow me to create the appropriate code for calculating the total sales for all segments. Hang tight!
```python
import pandas as pd
# Load the uploaded file to examine its contents
file_path = '/mnt/data/assistant-3nXizu2EX2EwXikUz71uNc'
data = pd.read_csv(file_path)
# Display the first few rows and column names to understand the structure of the dataset
data.head(), data.columns
```
# AuthorRole.ASSISTANT: The dataset contains several columns, including `Segment`, `Sales`, and others such as
`Country`, `Product`, and date-related information. To calculate the total sales for all segments, we will:
1. Group the data by the `Segment` column.
2. Sum the `Sales` column for each segment.
3. Calculate the grand total of all sales across all segments.
Here is the code snippet for this task:
```python
# Group by 'Segment' and sum up 'Sales'
segment_sales = data.groupby('Segment')['Sales'].sum()
# Calculate the total sales across all segments
total_sales = segment_sales.sum()
print("Total Sales per Segment:")
print(segment_sales)
print(f"\nGrand Total Sales: {total_sales}")
```
Would you like me to execute this directly for the uploaded data?
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,94 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from semantic_kernel.agents import AgentRegistry, OpenAIAssistantAgent
"""
The following sample demonstrates how to create an OpenAI Assistant Agent that answers
user questions using the file search tool.
The agent is used to answer user questions that require file search to help ground
answers from the model.
"""
# Define the YAML string for the sample
spec = """
type: openai_assistant
name: FileSearchAgent
description: Agent with code interpreter tool.
instructions: >
Use the code interpreter tool to answer questions that require code to be generated
and executed.
model:
id: ${OpenAI:ChatModelId}
connection:
api_key: ${OpenAI:ApiKey}
tools:
- type: file_search
options:
vector_store_ids:
- ${OpenAI:VectorStoreId}
"""
async def main():
# Setup the OpenAI Assistant client
client = OpenAIAssistantAgent.create_client()
# Read and upload the file to the OpenAI AI service
pdf_file_path = os.path.join(
os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))),
"resources",
"file_search",
"employees.pdf",
)
# Upload the pdf file to the assistant service
with open(pdf_file_path, "rb") as file:
file = await client.files.create(file=file, purpose="assistants")
vector_store = await client.vector_stores.create(
name="assistant_file_search",
file_ids=[file.id],
)
try:
# Create the Assistant Agent from the YAML spec
# Note: the extras can be provided in the short-format (shown below) or
# in the long-format (as shown in the YAML spec, with the `OpenAI:` prefix).
# The short-format is used here for brevity
agent: OpenAIAssistantAgent = await AgentRegistry.create_from_yaml(
yaml_str=spec,
client=client,
extras={"OpenAI:VectorStoreId": vector_store.id},
)
# Define the task for the agent
TASK = "Who can help me if I have a sales question?"
print(f"# User: '{TASK}'")
# Invoke the agent for the specified task
async for response in agent.invoke(
messages=TASK,
):
print(f"# {response.name}: {response}")
finally:
# Cleanup: Delete the agent, vector store, and file
await client.beta.assistants.delete(agent.id)
await client.vector_stores.delete(vector_store.id)
await client.files.delete(file.id)
"""
Sample output:
# User: 'Who can help me if I have a sales question?'
# FileSearchAgent: If you have a sales question, you can contact either Mariam Jaslyn or Angelino Embla, who
are both listed as Sales Representatives. Alternatively, you may also reach out to Hicran Bea,
the Sales Manager【4:0†employees.pdf】.
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,100 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from typing import Annotated
from semantic_kernel.agents import AgentRegistry, OpenAIAssistantAgent
from semantic_kernel.functions import kernel_function
"""
The following sample demonstrates how to create an OpenAI Assistant Agent that answers
user questions. The sample shows how to load a declarative spec from a file.
The plugins/functions must already exist in the kernel.
They are not created declaratively via the spec.
"""
class MenuPlugin:
"""A sample Menu Plugin used for the concept sample."""
@kernel_function(description="Provides a list of specials from the menu.")
def get_specials(self) -> Annotated[str, "Returns the specials from the menu."]:
return """
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
"""
@kernel_function(description="Provides the price of the requested menu item.")
def get_item_price(
self, menu_item: Annotated[str, "The name of the menu item."]
) -> Annotated[str, "Returns the price of the menu item."]:
return "$9.99"
async def main():
try:
client = OpenAIAssistantAgent.create_client()
# Define the YAML file path for the sample
file_path = os.path.join(
os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))),
"resources",
"declarative_spec",
"openai_assistant_spec.yaml",
)
# Create the Assistant Agent from the YAML spec
agent: OpenAIAssistantAgent = await AgentRegistry.create_from_file(
file_path,
plugins=[MenuPlugin()],
client=client,
)
# Create the agent
user_inputs = [
"Hello",
"What is the special soup?",
"How much does that cost?",
"Thank you",
]
# Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread = None
for user_input in user_inputs:
print(f"# User: '{user_input}'")
# Invoke the agent for the specified task
async for response in agent.invoke(
messages=user_input,
thread=thread,
):
print(f"# {response.name}: {response}")
# Store the thread for the next iteration
thread = response.thread
finally:
# Cleanup: Delete the thread and agent
await client.beta.assistants.delete(agent.id) if agent else None
await thread.delete() if thread else None
"""
Sample Output:
# User: 'Hello'
# Host: Hi there! How can I assist you today?
# User: 'What is the special soup?'
# Host: The special soup is Clam Chowder.
# User: 'What is the special drink?'
# Host: The special drink is Chai Tea.
# User: 'How much is it?'
# Host: The Chai Tea costs $9.99.
# User: 'Thank you'
# Host: You're welcome! If you have any more questions, feel free to ask.
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,70 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from semantic_kernel.agents import AgentRegistry, OpenAIAssistantAgent
"""
The following sample demonstrates how to create an OpenAI Assistant Agent that invokes
a story generation task using a prompt template and a declarative spec.
"""
# Define the YAML string for the sample
spec = """
type: openai_assistant
name: StoryAgent
description: An agent that generates a story about a topic.
instructions: Tell a story about {{$topic}} that is {{$length}} sentences long.
model:
id: ${OpenAI:ChatModelId}
inputs:
topic:
description: The topic of the story.
required: true
default: Cats
length:
description: The number of sentences in the story.
required: true
default: 2
outputs:
output1:
description: The generated story.
template:
format: semantic-kernel
"""
async def main():
# Setup the OpenAI Assistant client
client = OpenAIAssistantAgent.create_client()
try:
# Create the Assistant Agent from the YAML spec
# Note: the extras can be provided in the short-format (shown below) or
# in the long-format (as shown in the YAML spec, with the `OpenAI:` prefix).
# The short-format is used here for brevity
agent: OpenAIAssistantAgent = await AgentRegistry.create_from_yaml(
yaml_str=spec,
client=client,
)
# Invoke the agent for the specified task
async for response in agent.invoke(
messages=None,
):
print(f"# {response.name}: {response}")
finally:
# Cleanup: Delete the agent, vector store, and file
await client.beta.assistants.delete(agent.id)
"""
Sample output:
# StoryAgent: Under the silvery moon, three mischievous cats tiptoed across the rooftop, chasing
shadows and sharing secret whispers. By dawn, they curled up together, purring softly, dreaming
of adventures yet to come.
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,65 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from semantic_kernel.agents import AgentRegistry, OpenAIAssistantAgent
"""
The following sample demonstrates how to create an OpenAI Assistant Agent based
on an existing agent ID.
"""
# Define the YAML string for the sample
spec = """
id: ${OpenAI:AgentId}
type: openai_assistant
instructions: You are helpful agent who always responds in French.
"""
async def main():
client = OpenAIAssistantAgent.create_client()
try:
# Create the Assistant Agent from the YAML spec
# Note: the extras can be provided in the short-format (shown below) or
# in the long-format (as shown in the YAML spec, with the `OpenAI:` prefix).
# The short-format is used here for brevity
agent: OpenAIAssistantAgent = await AgentRegistry.create_from_yaml(
yaml_str=spec,
client=client,
extras={"AgentId": "<my-agent-id>"}, # Specify the existing agent ID
)
# Define the task for the agent
TASK = "Why is the sky blue?"
print(f"# User: '{TASK}'")
# Invoke the agent for the specified task
async for response in agent.invoke(
messages=TASK,
):
print(f"# {response.name}: {response}")
finally:
# Cleanup: Delete the thread and agent
await client.agents.delete_agent(agent.id)
"""
Sample output:
# User: 'Why is the sky blue?'
# WeatherAgent: Le ciel est bleu à cause d'un phénomène appelé **diffusion de Rayleigh**. La lumière du
Soleil est composée de toutes les couleurs du spectre visible, mais lorsqu'elle traverse l'atmosphère
terrestre, elle entre en contact avec les molécules d'air et les particules présentes.
Les couleurs à courtes longueurs d'onde, comme le bleu et le violet, sont diffusées dans toutes les directions
beaucoup plus efficacement que les couleurs à longues longueurs d'onde, comme le rouge et l'orange. Bien que le
violet ait une longueur d'onde encore plus courte que le bleu, nos yeux sont moins sensibles à cette couleur,
et une partie du violet est également absorbée par la haute atmosphère. Ainsi, le bleu domine, donnant au ciel
sa couleur caractéristique.
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,87 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from azure.identity import AzureCliCredential
from samples.concepts.agents.openai_assistant.openai_assistant_sample_utils import download_response_files
from semantic_kernel.agents import AssistantAgentThread, AzureAssistantAgent
from semantic_kernel.connectors.ai.open_ai import AzureOpenAISettings
from semantic_kernel.contents import AnnotationContent
"""
The following sample demonstrates how to create an OpenAI
assistant using either Azure OpenAI or OpenAI and leverage the
assistant's ability to have the code interpreter work with
uploaded files. This sample uses non-streaming responses.
"""
async def main():
# Create the client using Azure OpenAI resources and configuration
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
csv_file_path = os.path.join(
os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))),
"resources",
"agent_assistant_file_manipulation",
"sales.csv",
)
# Load the employees PDF file as a FileObject
with open(csv_file_path, "rb") as file:
file = await client.files.create(file=file, purpose="assistants")
# Get the code interpreter tool and resources
code_interpreter_tool, code_interpreter_tool_resource = AzureAssistantAgent.configure_code_interpreter_tool(file.id)
# Create the assistant definition
definition = await client.beta.assistants.create(
model=AzureOpenAISettings().chat_deployment_name,
name="FileManipulation",
instructions="Find answers to the user's questions in the provided file.",
tools=code_interpreter_tool,
tool_resources=code_interpreter_tool_resource,
)
# Create the AzureAssistantAgent instance using the client and the assistant definition
agent = AzureAssistantAgent(
client=client,
definition=definition,
)
# Create a new thread for use with the assistant
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: AssistantAgentThread = None
try:
user_inputs = [
"Which segment had the most sales?",
"List the top 5 countries that generated the most profit.",
"Create a tab delimited file report of profit by each country per month.",
]
for user_input in user_inputs:
print(f"# User: '{user_input}'")
async for response in agent.invoke(messages=user_input, thread=thread):
thread = response.thread
if response.metadata.get("code", False):
print(f"# {response.role}:\n\n```python")
print(response)
print("```")
else:
print(f"# {response.role}: {response}")
if response.items:
for item in response.items:
if isinstance(item, AnnotationContent):
await download_response_files(agent, [item])
finally:
await client.files.delete(file.id)
await thread.delete() if thread else None
await client.beta.assistants.delete(agent.id)
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,107 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from azure.identity import AzureCliCredential
from samples.concepts.agents.openai_assistant.openai_assistant_sample_utils import download_response_files
from semantic_kernel.agents import AssistantAgentThread, AzureAssistantAgent
from semantic_kernel.connectors.ai.open_ai import AzureOpenAISettings
from semantic_kernel.contents import ChatMessageContent, StreamingAnnotationContent
"""
The following sample demonstrates how to create an Azure Assistant Agent
to leverage the assistant's ability to have the code interpreter work with
uploaded files. This sample uses streaming responses.
"""
async def main():
# Create the client using Azure OpenAI resources and configuration
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
csv_file_path = os.path.join(
os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))),
"resources",
"agent_assistant_file_manipulation",
"sales.csv",
)
# Load the employees PDF file as a FileObject
with open(csv_file_path, "rb") as file:
file = await client.files.create(file=file, purpose="assistants")
# Get the code interpreter tool and resources
code_interpreter_tools, code_interpreter_tool_resources = AzureAssistantAgent.configure_code_interpreter_tool(
file.id
)
# Create the assistant definition
definition = await client.beta.assistants.create(
model=AzureOpenAISettings().chat_deployment_name,
name="FileManipulation",
instructions="Find answers to the user's questions in the provided file.",
tools=code_interpreter_tools,
tool_resources=code_interpreter_tool_resources,
)
# Create the AzureAssistantAgent instance using the client and the assistant definition
agent = AzureAssistantAgent(
client=client,
definition=definition,
)
# Create a new thread for use with the assistant
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: AssistantAgentThread = None
try:
user_inputs = [
# "Which segment had the most sales?",
# "List the top 5 countries that generated the most profit.",
"Create a tab delimited file report of profit by each country per month.",
]
for user_input in user_inputs:
print(f"# User: '{user_input}'")
annotations: list[StreamingAnnotationContent] = []
messages: list[ChatMessageContent] = []
is_code = False
last_role = None
async for response in agent.invoke_stream(messages=user_input, thread=thread):
thread = response.thread
current_is_code = response.metadata.get("code", False)
if current_is_code:
if not is_code:
print("\n\n```python")
is_code = True
print(response.content, end="", flush=True)
else:
if is_code:
print("\n```")
is_code = False
last_role = None
if hasattr(response, "role") and response.role is not None and last_role != response.role:
print(f"\n# {response.role}: ", end="", flush=True)
last_role = response.role
print(response.content, end="", flush=True)
if is_code:
print("```\n")
else:
print()
# Use a sample utility method to download the files to the current working directory
annotations.extend(
item for message in messages for item in message.items if isinstance(item, StreamingAnnotationContent)
)
await download_response_files(agent, annotations)
annotations.clear()
finally:
await client.files.delete(file.id)
await thread.delete() if thread else None
await client.beta.assistants.delete(agent.id)
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,131 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from typing import Annotated
from azure.identity import AzureCliCredential
from semantic_kernel.agents import AssistantAgentThread, AzureAssistantAgent
from semantic_kernel.connectors.ai.open_ai import AzureOpenAISettings
from semantic_kernel.contents import AuthorRole, FunctionCallContent, FunctionResultContent
from semantic_kernel.contents.chat_message_content import ChatMessageContent
from semantic_kernel.functions import kernel_function
"""
This sample demonstrates how to create an AzureAssistantAgent/OpenAIAssistantAgent and invoke it using the
non-streaming `invoke()` method. While `invoke()` returns only the final assistant message, the agent can
optionally emit intermediate messages (e.g., function calls and results) via a callback by supplying
`on_intermediate_message`.
In this example, the agent is configured with a plugin that provides menu specials and item pricing. As the user
asks about the menu, the agent performs tool calls mid-invocation, and those intermediate steps are surfaced
via the callback function while the invocation is still in progress.
"""
# Define a sample plugin for the sample
class MenuPlugin:
"""A sample Menu Plugin used for the concept sample."""
@kernel_function(description="Provides a list of specials from the menu.")
def get_specials(self) -> Annotated[str, "Returns the specials from the menu."]:
return """
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
"""
@kernel_function(description="Provides the price of the requested menu item.")
def get_item_price(
self, menu_item: Annotated[str, "The name of the menu item."]
) -> Annotated[str, "Returns the price of the menu item."]:
return "$9.99"
# This callback function will be called for each intermediate message,
# which will allow one to handle FunctionCallContent and FunctionResultContent.
# If the callback is not provided, the agent will return the final response
# with no intermediate tool call steps.
async def handle_intermediate_steps(message: ChatMessageContent) -> None:
for item in message.items or []:
if isinstance(item, FunctionResultContent):
print(f"Function Result:> {item.result} for function: {item.name}")
elif isinstance(item, FunctionCallContent):
print(f"Function Call:> {item.name} with arguments: {item.arguments}")
else:
print(f"{item}")
async def main():
# Create the client using Azure OpenAI resources and configuration
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
# Define the assistant definition
definition = await client.beta.assistants.create(
model=AzureOpenAISettings().chat_deployment_name,
name="Host",
instructions="Answer questions about the menu.",
)
# Create the AzureAssistantAgent instance using the client and the assistant definition and the defined plugin
agent = AzureAssistantAgent(
client=client,
definition=definition,
plugins=[MenuPlugin()],
)
# Create a new thread for use with the assistant
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: AssistantAgentThread = None
user_inputs = [
"Hello",
"What is the special soup?",
"What is the special drink?",
"How much is that?",
"Thank you",
]
try:
for user_input in user_inputs:
print(f"# {AuthorRole.USER}: '{user_input}'")
async for response in agent.invoke(
messages=user_input,
thread=thread,
on_intermediate_message=handle_intermediate_steps,
):
print(f"# {response.role}: {response}")
thread = response.thread
finally:
await thread.delete() if thread else None
await client.beta.assistants.delete(assistant_id=agent.id)
"""
Sample Output:
# AuthorRole.USER: 'Hello'
# AuthorRole.ASSISTANT: Hello! How can I assist you today?
# AuthorRole.USER: 'What is the special soup?'
Function Call:> MenuPlugin-get_specials with arguments: {}
Function Result:>
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
for function: MenuPlugin-get_specials
# AuthorRole.ASSISTANT: The special soup is Clam Chowder. Would you like to know more about the specials or
anything else?
# AuthorRole.USER: 'What is the special drink?'
# AuthorRole.ASSISTANT: The special drink is Chai Tea. If you have any more questions, feel free to ask!
# AuthorRole.USER: 'How much is that?'
Function Call:> MenuPlugin-get_item_price with arguments: {"menu_item":"Chai Tea"}
Function Result:> $9.99 for function: MenuPlugin-get_item_price
# AuthorRole.ASSISTANT: The Chai Tea is priced at $9.99. If there's anything else you'd like to know,
just let me know!
# AuthorRole.USER: 'Thank you'
# AuthorRole.ASSISTANT: You're welcome! If you have any more questions or need further assistance, feel free to
ask. Enjoy your day!
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,138 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from typing import Annotated
from azure.identity import AzureCliCredential
from semantic_kernel.agents import AssistantAgentThread, AzureAssistantAgent
from semantic_kernel.connectors.ai.open_ai import AzureOpenAISettings
from semantic_kernel.contents import AuthorRole, FunctionCallContent, FunctionResultContent
from semantic_kernel.contents.chat_message_content import ChatMessageContent
from semantic_kernel.functions import kernel_function
"""
This sample demonstrates how to create an AzureAssistantAgent/OpenAIAssistantAgent and use it with the
streaming `invoke_stream()` method. The agent returns assistant messages as a stream of incremental chunks.
In addition, you can specify an `on_intermediate_message` callback to receive fully-formed tool-related
messages — such as function calls and their results — while the assistant response is still being streamed.
In this example, the agent is configured with a plugin that provides menu specials and item pricing.
As the user interacts with the agent, tool messages (like function calls) are emitted via the callback,
while assistant replies stream back incrementally through the main response loop.
"""
# Define a sample plugin for the sample
class MenuPlugin:
"""A sample Menu Plugin used for the concept sample."""
@kernel_function(description="Provides a list of specials from the menu.")
def get_specials(self) -> Annotated[str, "Returns the specials from the menu."]:
return """
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
"""
@kernel_function(description="Provides the price of the requested menu item.")
def get_item_price(
self, menu_item: Annotated[str, "The name of the menu item."]
) -> Annotated[str, "Returns the price of the menu item."]:
return "$9.99"
# This callback function will be called for each intermediate message,
# which will allow one to handle FunctionCallContent and FunctionResultContent.
# If the callback is not provided, the agent will return the final response
# with no intermediate tool call steps.
async def handle_streaming_intermediate_steps(message: ChatMessageContent) -> None:
for item in message.items or []:
if isinstance(item, FunctionResultContent):
print(f"Function Result:> {item.result} for function: {item.name}")
elif isinstance(item, FunctionCallContent):
print(f"Function Call:> {item.name} with arguments: {item.arguments}")
else:
print(f"{item}")
async def main():
# Create the client using Azure OpenAI resources and configuration
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
# Define the assistant definition
definition = await client.beta.assistants.create(
model=AzureOpenAISettings().chat_deployment_name,
name="Host",
instructions="Answer questions about the menu.",
)
# Create the AzureAssistantAgent instance using the client and the assistant definition and the defined plugin
agent = AzureAssistantAgent(
client=client,
definition=definition,
plugins=[MenuPlugin()],
)
# Create a new thread for use with the assistant
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: AssistantAgentThread = None
user_inputs = [
"Hello",
"What is the special soup?",
"What is the special drink?",
"How much is that?",
"Thank you",
]
try:
for user_input in user_inputs:
print(f"# {AuthorRole.USER}: '{user_input}'")
first_chunk = True
async for response in agent.invoke_stream(
messages=user_input,
thread=thread,
on_intermediate_message=handle_streaming_intermediate_steps,
):
thread = response.thread
if first_chunk:
print(f"# {response.role}: ", end="", flush=True)
first_chunk = False
print(response.content, end="", flush=True)
print()
finally:
await thread.delete() if thread else None
await client.beta.assistants.delete(assistant_id=agent.id)
"""
Sample Output:
# AuthorRole.USER: 'Hello'
# AuthorRole.ASSISTANT: Hello! How can I help you with the menu today?
# AuthorRole.USER: 'What is the special soup?'
Function Call:> MenuPlugin-get_specials with arguments: {}
Function Result:>
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
for function: MenuPlugin-get_specials
# AuthorRole.ASSISTANT: The special soup today is Clam Chowder. Would you like to know more about it or see other
specials?
# AuthorRole.USER: 'What is the special drink?'
# AuthorRole.ASSISTANT: The special drink is Chai Tea. Would you like more information about it or the other
specials?
# AuthorRole.USER: 'How much is that?'
Function Call:> MenuPlugin-get_item_price with arguments: {"menu_item":"Chai Tea"}
Function Result:> $9.99 for function: MenuPlugin-get_item_price
# AuthorRole.ASSISTANT: The special drink, Chai Tea, is $9.99. Would you like to order one or have questions about
something else on the menu?
# AuthorRole.USER: 'Thank you'
# AuthorRole.ASSISTANT: You're welcome! If you have any more questions or need help with the menu, just let me
know. Enjoy your meal!
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,60 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity import AzureCliCredential
from semantic_kernel.agents import AssistantAgentThread, AzureAssistantAgent
from semantic_kernel.connectors.ai.open_ai import AzureOpenAISettings
"""
The following sample demonstrates how to create an OpenAI
assistant using either Azure OpenAI or OpenAI and retrieve it from
the server to create a new instance of the assistant. This is done by
retrieving the assistant definition from the server using the Assistant's
ID and creating a new instance of the assistant using the retrieved definition.
"""
async def main():
# Create the client using Azure OpenAI resources and configuration
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
# Create the assistant definition
definition = await client.beta.assistants.create(
model=AzureOpenAISettings().chat_deployment_name,
name="Assistant",
instructions="You are a helpful assistant answering questions about the world in one sentence.",
)
# Store the assistant ID
assistant_id = definition.id
# Retrieve the assistant definition from the server based on the assistant ID
new_asst_definition = await client.beta.assistants.retrieve(assistant_id)
# Create the AzureAssistantAgent instance using the client and the assistant definition
agent = AzureAssistantAgent(
client=client,
definition=new_asst_definition,
)
# Create a new thread for use with the assistant
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: AssistantAgentThread = None
user_inputs = ["Why is the sky blue?"]
try:
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.role}: {response.content}")
thread = response.thread
finally:
await thread.delete() if thread else None
await client.beta.assistants.delete(agent.id)
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,54 @@
# Copyright (c) Microsoft. All rights reserved.
import os
from collections.abc import Sequence
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from semantic_kernel.agents import OpenAIAssistantAgent
from semantic_kernel.contents import AnnotationContent, StreamingAnnotationContent
async def download_file_content(agent: "OpenAIAssistantAgent", file_id: str, file_extension: str):
"""A sample utility method to download the content of a file."""
try:
# Fetch the content of the file using the provided method
response_content = await agent.client.files.content(file_id)
# Get the current working directory of the file
current_directory = os.path.dirname(os.path.abspath(__file__))
# Define the path to save the image in the current directory
file_path = os.path.join(
current_directory, # Use the current directory of the file
f"{file_id}.{file_extension}", # You can modify this to use the actual filename with proper extension
)
# Save content to a file asynchronously
with open(file_path, "wb") as file:
file.write(response_content.content)
print(f"\n\nFile saved to: {file_path}")
except Exception as e:
print(f"An error occurred while downloading file {file_id}: {str(e)}")
async def download_response_images(agent: "OpenAIAssistantAgent", file_ids: list[str]):
"""A sample utility method to download the content of a list of files."""
if file_ids:
# Iterate over file_ids and download each one
for file_id in file_ids:
await download_file_content(agent, file_id, "png")
async def download_response_files(
agent: "OpenAIAssistantAgent", annotations: Sequence["StreamingAnnotationContent | AnnotationContent"]
):
"""A sample utility method to download the content of a file."""
if annotations:
# Iterate over file_ids and download each one
for ann in annotations:
if ann.quote is None or ann.file_id is None:
continue
extension = os.path.splitext(ann.quote)[1].lstrip(".")
await download_file_content(agent, ann.file_id, extension)
@@ -0,0 +1,85 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from typing import Annotated
from azure.identity import AzureCliCredential
from semantic_kernel.agents import AssistantAgentThread, AzureAssistantAgent
from semantic_kernel.connectors.ai.open_ai import AzureOpenAISettings
from semantic_kernel.contents import AuthorRole
from semantic_kernel.functions import kernel_function
"""
The following sample demonstrates how to create an OpenAI
assistant using either Azure OpenAI or OpenAI. OpenAI Assistants
allow for function calling, the use of file search and a
code interpreter. Assistant Threads are used to manage the
conversation state, similar to a Semantic Kernel Chat History.
This sample also demonstrates the Assistants Streaming
capability and how to manage an Assistants chat history.
"""
# Define a sample plugin for the sample
class MenuPlugin:
"""A sample Menu Plugin used for the concept sample."""
@kernel_function(description="Provides a list of specials from the menu.")
def get_specials(self) -> Annotated[str, "Returns the specials from the menu."]:
return """
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
"""
@kernel_function(description="Provides the price of the requested menu item.")
def get_item_price(
self, menu_item: Annotated[str, "The name of the menu item."]
) -> Annotated[str, "Returns the price of the menu item."]:
return "$9.99"
async def main():
# Create the client using Azure OpenAI resources and configuration
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
# Define the assistant definition
definition = await client.beta.assistants.create(
model=AzureOpenAISettings().chat_deployment_name,
name="Host",
instructions="Answer questions about the menu.",
)
# Create the AzureAssistantAgent instance using the client and the assistant definition and the defined plugin
agent = AzureAssistantAgent(
client=client,
definition=definition,
plugins=[MenuPlugin()],
)
# Create a new thread for use with the assistant
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: AssistantAgentThread = None
user_inputs = ["Hello", "What is the special soup?", "What is the special drink?", "How much is that?", "Thank you"]
try:
for user_input in user_inputs:
print(f"# {AuthorRole.USER}: '{user_input}'")
first_chunk = True
async for response in agent.invoke_stream(messages=user_input, thread=thread):
thread = response.thread
if first_chunk:
print(f"# {response.role}: ", end="", flush=True)
first_chunk = False
print(response.content, end="", flush=True)
print()
finally:
await thread.delete() if thread else None
await client.beta.assistants.delete(assistant_id=agent.id)
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,94 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity import AzureCliCredential
from pydantic import BaseModel
from semantic_kernel.agents import AssistantAgentThread, AzureAssistantAgent
from semantic_kernel.connectors.ai.open_ai import AzureOpenAISettings
"""
The following sample demonstrates how to create an OpenAI
assistant using either Azure OpenAI or OpenAI and leverage the
assistant's ability to returned structured outputs, based on a user-defined
Pydantic model. This could also be a non-Pydantic model. Use the convenience
method on the OpenAIAssistantAgent class to configure the response format,
as shown below.
Note, you may specify your own JSON Schema. You'll need to make sure it is correct
if not using the convenience method, per the following format:
json_schema = {
"type": "json_schema",
"json_schema": {
"schema": {
"properties": {
"response": {"title": "Response", "type": "string"},
"items": {"items": {"type": "string"}, "title": "Items", "type": "array"},
},
"required": ["response", "items"],
"title": "ResponseModel",
"type": "object",
"additionalProperties": False,
},
"name": "ResponseModel",
"strict": True,
},
}
# Create the assistant definition
definition = await client.beta.assistants.create(
model=AzureOpenAISettings().chat_deployment_name
name="Assistant",
instructions="You are a helpful assistant answering questions about the world in one sentence.",
response_format=json_schema,
)
"""
# Define a Pydantic model that represents the structured output from the OpenAI service
class ResponseModel(BaseModel):
response: str
items: list[str]
async def main():
# Create the client using Azure OpenAI resources and configuration
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
# Create the assistant definition
definition = await client.beta.assistants.create(
model=AzureOpenAISettings().chat_deployment_name,
name="Assistant",
instructions="You are a helpful assistant answering questions about the world in one sentence.",
response_format=AzureAssistantAgent.configure_response_format(ResponseModel),
)
# Create the AzureAssistantAgent instance using the client and the assistant definition
agent = AzureAssistantAgent(
client=client,
definition=definition,
)
# Create a new thread for use with the assistant
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: AssistantAgentThread = None
user_inputs = ["Why is the sky blue?"]
try:
for user_input in user_inputs:
print(f"# User: '{user_input}'")
async for response in agent.invoke(messages=user_input, thread=thread):
# The response returned is a Pydantic Model, so we can validate it using the model_validate_json method
response_model = ResponseModel.model_validate_json(str(response.content))
print(f"# {response.role}: {response_model}")
thread = response.thread
finally:
await thread.delete() if thread else None
await client.beta.assistants.delete(agent.id)
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,117 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity import AzureCliCredential
from semantic_kernel.agents import AssistantAgentThread, AzureAssistantAgent
from semantic_kernel.connectors.ai.open_ai import AzureOpenAISettings
from semantic_kernel.functions import KernelArguments
from semantic_kernel.prompt_template import PromptTemplateConfig
from semantic_kernel.prompt_template.const import TEMPLATE_FORMAT_TYPES
"""
The following sample demonstrates how to create an assistant
agent using either Azure OpenAI or OpenAI within Semantic Kernel.
It uses parameterized prompts and shows how to swap between
"semantic-kernel," "jinja2," and "handlebars" template formats,
This sample highlights how the agent's threaded conversation
state parallels the Chat History in Semantic Kernel, ensuring
all responses and parameters remain consistent throughout the
session.
"""
inputs = [
("Home cooking is great.", None),
("Talk about world peace.", "iambic pentameter"),
("Say something about doing your best.", "e. e. cummings"),
("What do you think about having fun?", "old school rap"),
]
async def invoke_agent_with_template(
template_str: str, template_format: TEMPLATE_FORMAT_TYPES, default_style: str = "haiku"
):
# Create the client using Azure OpenAI resources and configuration
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
# Configure the prompt template
prompt_template_config = PromptTemplateConfig(template=template_str, template_format=template_format)
# Create the assistant definition
definition = await client.beta.assistants.create(
model=AzureOpenAISettings().chat_deployment_name,
name="MyPoetAgent",
)
# Create the AzureAssistantAgent instance using the client, the assistant definition,
# the prompt template config, and the constructor-level Kernel Arguments
agent = AzureAssistantAgent(
client=client,
definition=definition,
prompt_template_config=prompt_template_config, # type: ignore
arguments=KernelArguments(style=default_style),
)
# Create a new thread for use with the assistant
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: AssistantAgentThread = None
try:
for user_input, style in inputs:
print(f"# User: {user_input}\n")
# If style is specified, override the 'style' argument
argument_overrides = None
if style:
# Arguments passed in at invocation time take precedence over
# the default arguments that were added via the constructor.
argument_overrides = KernelArguments(style=style)
# Stream agent responses
async for response in agent.invoke_stream(messages=user_input, thread=thread, arguments=argument_overrides):
if response.content:
print(f"{response.content}", flush=True, end="")
thread = response.thread
print("\n")
finally:
# Clean up
await thread.delete() if thread else None
await client.beta.assistants.delete(agent.id)
async def main():
# 1) Using "semantic-kernel" format
print("\n===== SEMANTIC-KERNEL FORMAT =====\n")
semantic_kernel_template = """
Write a one verse poem on the requested topic in the style of {{$style}}.
Always state the requested style of the poem. Write appropriate G-rated content.
"""
await invoke_agent_with_template(
template_str=semantic_kernel_template,
template_format="semantic-kernel",
default_style="haiku",
)
# 2) Using "jinja2" format
print("\n===== JINJA2 FORMAT =====\n")
jinja2_template = """
Write a one verse poem on the requested topic in the style of {{style}}.
Always state the requested style of the poem. Write appropriate G-rated content.
"""
await invoke_agent_with_template(template_str=jinja2_template, template_format="jinja2", default_style="haiku")
# 3) Using "handlebars" format
print("\n===== HANDLEBARS FORMAT =====\n")
handlebars_template = """
Write a one verse poem on the requested topic in the style of {{style}}.
Always state the requested style of the poem. Write appropriate G-rated content.
"""
await invoke_agent_with_template(
template_str=handlebars_template, template_format="handlebars", default_style="haiku"
)
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,97 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from azure.identity import AzureCliCredential
from semantic_kernel.agents import AssistantAgentThread, AzureAssistantAgent
from semantic_kernel.connectors.ai.open_ai import AzureOpenAISettings
from semantic_kernel.contents import AuthorRole, ChatMessageContent, FileReferenceContent, ImageContent, TextContent
"""
The following sample demonstrates how to create an OpenAI
assistant using either Azure OpenAI or OpenAI and leverage the
multi-modal content types to have the assistant describe images
and answer questions about them and provide streaming responses.
"""
async def main():
# Create the client using Azure OpenAI resources and configuration
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
file_path = os.path.join(
os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))), "resources", "cat.jpg"
)
with open(file_path, "rb") as file:
file = await client.files.create(file=file, purpose="assistants")
# Create the assistant definition
definition = await client.beta.assistants.create(
model=AzureOpenAISettings().chat_deployment_name,
instructions="Answer questions about the menu.",
name="Host",
)
# Create the AzureAssistantAgent instance using the client and the assistant definition
agent = AzureAssistantAgent(
client=client,
definition=definition,
)
# Create a new thread for use with the assistant
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: AssistantAgentThread = None
# Define a series of message with either ImageContent or FileReferenceContent
user_inputs = {
ChatMessageContent(
role=AuthorRole.USER,
items=[
TextContent(text="Describe this image."),
ImageContent(
uri="https://upload.wikimedia.org/wikipedia/commons/thumb/4/47/New_york_times_square-terabass.jpg/1200px-New_york_times_square-terabass.jpg"
),
],
),
ChatMessageContent(
role=AuthorRole.USER,
items=[
TextContent(text="What is the main color in this image?"),
ImageContent(uri="https://upload.wikimedia.org/wikipedia/commons/5/56/White_shark.jpg"),
],
),
ChatMessageContent(
role=AuthorRole.USER,
items=[
TextContent(text="Is there an animal in this image?"),
FileReferenceContent(file_id=file.id),
],
),
}
try:
for user_input in user_inputs:
print(f"# User: '{user_input.items[0].text}'") # type: ignore
first_chunk = True
async for response in agent.invoke_stream(messages=user_input, thread=thread):
if response.role != AuthorRole.TOOL:
if first_chunk:
print("# Agent: ", end="", flush=True)
first_chunk = False
print(response.content, end="", flush=True)
thread = response.thread
print("\n")
finally:
await client.files.delete(file.id)
await thread.delete() if thread else None
await agent.client.beta.assistants.delete(assistant_id=agent.id)
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,95 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from azure.identity import AzureCliCredential
from semantic_kernel.agents import AgentRegistry, AzureResponsesAgent
"""
The following sample demonstrates how to create an Azure Responses Agent that answers
user questions using the file search tool.
"""
# Define the YAML string for the sample
spec = """
type: azure_responses
name: FileSearchAgent
description: Agent with file search tool.
instructions: >
Use the file search tool to answer questions from the user.
model:
id: ${AzureOpenAI:ChatModelId}
connection:
endpoint: ${AzureOpenAI:Endpoint}
tools:
- type: file_search
options:
vector_store_ids:
- ${AzureOpenAI:VectorStoreId}
"""
async def main():
# Setup the Azure OpenAI client
client = AzureResponsesAgent.create_client(credential=AzureCliCredential())
# Read and upload the file to the OpenAI AI service
pdf_file_path = os.path.join(
os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))),
"resources",
"file_search",
"employees.pdf",
)
# Upload the pdf file to the server
with open(pdf_file_path, "rb") as file:
file = await client.files.create(file=file, purpose="assistants")
vector_store = await client.vector_stores.create(
name="responses_file_search",
file_ids=[file.id],
)
try:
# Create the Responses Agent from the YAML spec
# Note: the extras can be provided in the short-format (shown below) or
# in the long-format (as shown in the YAML spec, with the `AzureOpenAI:` prefix).
# The short-format is used here for brevity
agent: AzureResponsesAgent = await AgentRegistry.create_from_yaml(
yaml_str=spec,
client=client,
extras={"AzureOpenAI:VectorStoreId": vector_store.id},
)
# Define the task for the agent
TASK = "Who can help me if I have a sales question?"
print(f"# User: '{TASK}'")
# Invoke the agent for the specified task
async for response in agent.invoke(
messages=TASK,
):
print(f"# {response.name}: {response}")
finally:
# Cleanup: Delete the agent, vector store, and file
await client.vector_stores.delete(vector_store.id)
await client.files.delete(file.id)
"""
Sample output:
# User: 'Who can help me if I have a sales question?'
# FileSearchAgent: If you have a sales question, you may contact the following individuals:
1. **Hicran Bea** - Sales Manager
2. **Mariam Jaslyn** - Sales Representative
3. **Angelino Embla** - Sales Representative
This information comes from the employee records【4:0†source】.
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,101 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from typing import Annotated
from azure.identity import AzureCliCredential
from semantic_kernel.agents import AgentRegistry, AzureResponsesAgent
from semantic_kernel.functions import kernel_function
"""
The following sample demonstrates how to create an Azure Responses Agent that answers
user questions. The sample shows how to load a declarative spec from a file.
The plugins/functions must already exist in the kernel.
They are not created declaratively via the spec.
"""
class MenuPlugin:
"""A sample Menu Plugin used for the concept sample."""
@kernel_function(description="Provides a list of specials from the menu.")
def get_specials(self) -> Annotated[str, "Returns the specials from the menu."]:
return """
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
"""
@kernel_function(description="Provides the price of the requested menu item.")
def get_item_price(
self, menu_item: Annotated[str, "The name of the menu item."]
) -> Annotated[str, "Returns the price of the menu item."]:
return "$9.99"
async def main():
try:
client = AzureResponsesAgent.create_client(credential=AzureCliCredential())
# Define the YAML file path for the sample
file_path = os.path.join(
os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))),
"resources",
"declarative_spec",
"azure_responses_spec.yaml",
)
# Create the Responses Agent from the YAML spec
agent: AzureResponsesAgent = await AgentRegistry.create_from_file(
file_path,
plugins=[MenuPlugin()],
client=client,
)
# Create the agent
user_inputs = [
"Hello",
"What is the special soup?",
"How much does that cost?",
"Thank you",
]
# Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread = None
for user_input in user_inputs:
print(f"# User: '{user_input}'")
# Invoke the agent for the specified task
async for response in agent.invoke(
messages=user_input,
thread=thread,
):
print(f"# {response.name}: {response}")
# Store the thread for the next iteration
thread = response.thread
finally:
# Cleanup: Delete the thread
await thread.delete() if thread else None
"""
Sample Output:
# User: 'Hello'
# Host: Hi there! How can I assist you today?
# User: 'What is the special soup?'
# Host: The special soup is Clam Chowder.
# User: 'What is the special drink?'
# Host: The special drink is Chai Tea.
# User: 'How much is it?'
# Host: The Chai Tea costs $9.99.
# User: 'Thank you'
# Host: You're welcome! If you have any more questions, feel free to ask.
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,77 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity import AzureCliCredential
from semantic_kernel.agents import AgentRegistry, AzureResponsesAgent
"""
The following sample demonstrates how to create an Azure Responses Agent that invokes
a story generation task using a prompt template and a declarative spec.
"""
# Define the YAML string for the sample
spec = """
type: azure_responses
name: StoryAgent
description: An agent that generates a story about a topic.
instructions: Tell a story about {{$topic}} that is {{$length}} sentences long.
model:
id: ${AzureOpenAI:ChatModelId}
connection:
endpoint: ${AzureOpenAI:Endpoint}
inputs:
topic:
description: The topic of the story.
required: true
default: Cats
length:
description: The number of sentences in the story.
required: true
default: 2
outputs:
output1:
description: The generated story.
template:
format: semantic-kernel
"""
async def main():
# Setup the Azure OpenAI client
client = AzureResponsesAgent.create_client(credential=AzureCliCredential())
# Create the Responses Agent from the YAML spec
# Note: the extras can be provided in the short-format (shown below) or
# in the long-format (as shown in the YAML spec, with the `AzureOpenAI:` prefix).
# The short-format is used here for brevity
agent: AzureResponsesAgent = await AgentRegistry.create_from_yaml(
yaml_str=spec,
client=client,
)
USER_INPUTS = ["Tell me a fun story."]
# Invoke the agent for the specified task
for user_input in USER_INPUTS:
# Print the user input
print(f"# User: '{user_input}'")
# Invoke the agent for the specified task
async for response in agent.invoke(
messages=user_input,
):
print(f"# {response.name}: {response}")
"""
Sample output:
# User: 'Tell me a fun story.'
# StoryAgent: Late at night, a mischievous cat named Whiskers tiptoed across the piano keys,
accidentally composing a tune so catchy that all the neighborhood felines gathered outside
to dance. By morning, the humans awoke to find a crowd of cats meowing for an encore performance.
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,100 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from semantic_kernel.agents import AgentRegistry, OpenAIResponsesAgent
"""
The following sample demonstrates how to create an OpenAI Responses Agent that answers
user questions using the file search tool based on a declarative spec.
"""
# Define the YAML string for the sample
spec = """
type: openai_responses
name: FileSearchAgent
description: Agent with file search tool.
instructions: >
Find answers to the user's questions in the provided file.
model:
id: ${OpenAI:ChatModelId}
connection:
api_key: ${OpenAI:ApiKey}
tools:
- type: file_search
description: File search for document retrieval.
options:
vector_store_ids:
- ${OpenAI:VectorStoreId}
"""
async def main():
# Setup the OpenAI Responses client
client = OpenAIResponsesAgent.create_client()
# Read and upload the file to the OpenAI AI service
pdf_file_path = os.path.join(
os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))),
"resources",
"file_search",
"employees.pdf",
)
# Upload the pdf file to the assistant service
with open(pdf_file_path, "rb") as file:
file = await client.files.create(file=file, purpose="assistants")
vector_store = await client.vector_stores.create(
name="assistant_file_search",
file_ids=[file.id],
)
try:
# Create the Responses Agent from the YAML spec
# Note: the extras can be provided in the short-format (shown below) or
# in the long-format (as shown in the YAML spec, with the `OpenAI:` prefix).
# The short-format is used here for brevity
agent: OpenAIResponsesAgent = await AgentRegistry.create_from_yaml(
yaml_str=spec,
client=client,
extras={"OpenAI:VectorStoreId": vector_store.id},
)
# Define the task for the agent
USER_INPUTS = ["Who can help me if I have a sales question?", "Who works in sales?"]
thread = None
for user_input in USER_INPUTS:
# Print the user input
print(f"# User: '{user_input}'")
# Invoke the agent for the specified task
async for response in agent.invoke(
messages=user_input,
thread=thread,
):
print(f"# {response.name}: {response}")
thread = response.thread
finally:
# Cleanup: Delete the vector store, and file
await client.vector_stores.delete(vector_store.id)
await client.files.delete(file.id)
"""
Sample output:
# User: 'Who can help me if I have a sales question?'
# FileSearchAgent: If you have a sales question, you may contact the following individuals:
1. **Hicran Bea** - Sales Manager
2. **Mariam Jaslyn** - Sales Representative
3. **Angelino Embla** - Sales Representative
This information comes from the employee records【4:0†source】.
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,99 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from typing import Annotated
from semantic_kernel.agents import AgentRegistry, OpenAIResponsesAgent
from semantic_kernel.functions import kernel_function
"""
The following sample demonstrates how to create an OpenAI Responses Agent that answers
user questions. The sample shows how to load a declarative spec from a file.
The plugins/functions must already exist in the kernel.
They are not created declaratively via the spec.
"""
class MenuPlugin:
"""A sample Menu Plugin used for the concept sample."""
@kernel_function(description="Provides a list of specials from the menu.")
def get_specials(self) -> Annotated[str, "Returns the specials from the menu."]:
return """
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
"""
@kernel_function(description="Provides the price of the requested menu item.")
def get_item_price(
self, menu_item: Annotated[str, "The name of the menu item."]
) -> Annotated[str, "Returns the price of the menu item."]:
return "$9.99"
async def main():
try:
client = OpenAIResponsesAgent.create_client()
# Define the YAML file path for the sample
file_path = os.path.join(
os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))),
"resources",
"declarative_spec",
"openai_responses_spec.yaml",
)
# Create the Responses Agent from the YAML spec
agent: OpenAIResponsesAgent = await AgentRegistry.create_from_file(
file_path,
plugins=[MenuPlugin()],
client=client,
)
# Create the agent
user_inputs = [
"Hello",
"What is the special soup?",
"How much does that cost?",
"Thank you",
]
# Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread = None
for user_input in user_inputs:
print(f"# User: '{user_input}'")
# Invoke the agent for the specified task
async for response in agent.invoke(
messages=user_input,
thread=thread,
):
print(f"# {response.name}: {response}")
# Store the thread for the next iteration
thread = response.thread
finally:
# Cleanup: Delete the thread
await thread.delete() if thread else None
"""
Sample Output:
# User: 'Hello'
# Host: Hi there! How can I assist you today?
# User: 'What is the special soup?'
# Host: The special soup is Clam Chowder.
# User: 'What is the special drink?'
# Host: The special drink is Chai Tea.
# User: 'How much is it?'
# Host: The Chai Tea costs $9.99.
# User: 'Thank you'
# Host: You're welcome! If you have any more questions, feel free to ask.
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,73 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from semantic_kernel.agents import AgentRegistry, OpenAIResponsesAgent
"""
The following sample demonstrates how to create an OpenAI Responses Agent that invokes
a story generation task using a prompt template and a declarative spec.
"""
# Define the YAML string for the sample
spec = """
type: openai_responses
name: StoryAgent
description: An agent that generates a story about a topic.
instructions: Tell a story about {{$topic}} that is {{$length}} sentences long.
model:
id: ${OpenAI:ChatModelId}
inputs:
topic:
description: The topic of the story.
required: true
default: Cats
length:
description: The number of sentences in the story.
required: true
default: 2
outputs:
output1:
description: The generated story.
template:
format: semantic-kernel
"""
async def main():
# Setup the OpenAI client
client = OpenAIResponsesAgent.create_client()
# Create the Responses Agent from the YAML spec
# Note: the extras can be provided in the short-format (shown below) or
# in the long-format (as shown in the YAML spec, with the `OpenAI:` prefix).
# The short-format is used here for brevity
agent: OpenAIResponsesAgent = await AgentRegistry.create_from_yaml(
yaml_str=spec,
client=client,
)
USER_INPUTS = ["Tell me a fun story."]
# Invoke the agent for the specified task
for user_input in USER_INPUTS:
# Print the user input
print(f"# User: '{user_input}'")
# Invoke the agent for the specified task
async for response in agent.invoke(
messages=user_input,
):
print(f"# {response.name}: {response}")
"""
Sample output:
# User: 'Tell me a fun story.'
# StoryAgent: Late at night, a mischievous cat named Whiskers tiptoed across the piano keys,
accidentally composing a tune so catchy that all the neighborhood felines gathered outside
to dance. By morning, the humans awoke to find a crowd of cats meowing for an encore performance.
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,86 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from semantic_kernel.agents import AgentRegistry, OpenAIResponsesAgent
"""
The following sample demonstrates how to create an OpenAI Responses Agent that answers
user questions using the web search tool based on a declarative spec.
"""
# Define the YAML string for the sample
spec = """
type: openai_responses
name: WebSearchAgent
description: Agent with web search tool.
instructions: >
Find answers to the user's questions using the provided tool.
model:
id: ${OpenAI:ChatModelId}
connection:
api_key: ${OpenAI:ApiKey}
tools:
- type: web_search
description: Search the internet for recent information.
options:
search_context_size: high
"""
async def main():
# Setup the OpenAI client
client = OpenAIResponsesAgent.create_client()
try:
# Create the Responses Agent from the YAML spec
# Note: the extras can be provided in the short-format (shown below) or
# in the long-format (as shown in the YAML spec, with the `OpenAI:` prefix).
# The short-format is used here for brevity
agent: OpenAIResponsesAgent = await AgentRegistry.create_from_yaml(
yaml_str=spec,
client=client,
)
# Define the task for the agent
USER_INPUTS = ["Who won the 2025 NCAA basketball championship?"]
thread = None
for user_input in USER_INPUTS:
# Print the user input
print(f"# User: '{user_input}'")
# Invoke the agent for the specified task
async for response in agent.invoke(
messages=user_input,
thread=thread,
):
print(f"# {response.name}: {response}")
thread = response.thread
finally:
await thread.delete() if thread else None
"""
Sample output:
# User: 'Who won the 2025 NCAA basketball championship?'
# WebSearchAgent: The Florida Gators won the 2025 NCAA men's basketball championship, defeating the Houston
Cougars 65-63 on April 7, 2025, at the Alamodome in San Antonio, Texas. This victory marked Florida's
third national title and their first since 2007. ([reuters.com](https://www.reuters.com/sports/basketball/florida-beat-houston-claim-third-ncaa-mens-basketball-title-2025-04-08/?utm_source=openai))
In the championship game, Florida overcame a 12-point deficit in the second half. Senior guard Walter Clayton
Jr. was instrumental in the comeback, scoring all 11 of his points in the second half and delivering a
crucial defensive stop in the final seconds to secure the win. Will Richard led the Gators with 18 points. ([apnews.com](https://apnews.com/article/74a9c790277595ce53ca130c5ec64429?utm_source=openai))
Head coach Todd Golden, in his third season, became the youngest coach to win the NCAA title since 1983. ([reuters.com](https://www.reuters.com/sports/basketball/florida-beat-houston-claim-third-ncaa-mens-basketball-title-2025-04-08/?utm_source=openai))
## Florida Gators' 2025 NCAA Championship Victory:
- [Florida overcome Houston in massive comeback to claim third NCAA title](https://www.reuters.com/sports/basketball/florida-beat-houston-claim-third-ncaa-mens-basketball-title-2025-04-08/?utm_source=openai)
- [Walter Clayton Jr.'s defensive stop gives Florida its 3rd national title with 65-63 win over Houston](https://apnews.com/article/74a9c790277595ce53ca130c5ec64429?utm_source=openai)
- [Reports: National champion Florida sets White House visit](https://www.reuters.com/sports/reports-national-champion-florida-sets-white-house-visit-2025-05-18/?utm_source=openai)
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,188 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
import tempfile
from semantic_kernel.agents import OpenAIResponsesAgent
from semantic_kernel.connectors.ai.open_ai import OpenAISettings
from semantic_kernel.contents.binary_content import BinaryContent
from semantic_kernel.contents.chat_message_content import ChatMessageContent
from semantic_kernel.contents.text_content import TextContent
from semantic_kernel.contents.utils.author_role import AuthorRole
"""
The following sample demonstrates how to upload PDF and text files using BinaryContent
with an OpenAI Responses Agent. This shows how to create BinaryContent objects from files
and compose multi-modal messages that combine text and binary content.
The sample demonstrates:
1. Creating BinaryContent from a PDF file
2. Creating BinaryContent from a text file
3. Composing multi-modal messages with mixed content types (text + binary)
4. Sending complex messages directly to the agent via the messages parameter
5. Having the agent process and respond to questions about the uploaded files
This approach differs from simple string-based interactions by showing how to combine
multiple content types within a single message, which is useful for rich media interactions.
Note: This sample uses the existing employees.pdf file from the resources directory.
"""
# Sample follow-up questions to demonstrate continued conversation
USER_INPUTS = [
"What specific types of files did I just upload?",
"Can you tell me about the content in the PDF file?",
"What does the text file contain?",
"Can you provide a summary of both documents?",
]
def create_sample_text_content() -> str:
"""Create sample text content for demonstration purposes.
Returns:
str: A sample company policy document in text format.
"""
return """Company Policy Document - Remote Work Guidelines
This document outlines our company's remote work policies and procedures.
Remote Work Eligibility:
- Full-time employees with at least 6 months tenure
- Managers approval required
- Home office setup must meet security requirements
Work Schedule:
- Core hours: 10 AM - 3 PM local time
- Flexible start/end times outside core hours
- Maximum 3 remote days per week for hybrid roles
Communication Requirements:
- Daily check-ins with team lead
- Weekly video conference participation
- Response time: within 4 hours during business hours
Equipment and Security:
- Company-provided laptop and VPN access
- Secure Wi-Fi connection required
- No public Wi-Fi for work activities
For questions about remote work policies, contact HR at hr@company.com
"""
async def main():
# 1. Initialize the OpenAI client
client = OpenAIResponsesAgent.create_client()
# 2. Prepare file paths and create sample content
pdf_file_path = os.path.join(
os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))),
"resources",
"file_search",
"employees.pdf",
)
# Create a temporary text file for demonstration purposes
with tempfile.NamedTemporaryFile(mode="w", suffix=".txt", delete=False) as text_file:
text_content = create_sample_text_content()
text_file.write(text_content)
text_file_path = text_file.name
try:
# 3. Create BinaryContent objects from files using different methods
print("Creating BinaryContent from files...")
# Method 1: Create BinaryContent from an existing PDF file
pdf_binary_content = BinaryContent.from_file(file_path=pdf_file_path, mime_type="application/pdf")
print(f"Created PDF BinaryContent: {pdf_binary_content.mime_type}, can_read: {pdf_binary_content.can_read}")
# Method 2: Create BinaryContent from the temporary text file
text_binary_content = BinaryContent.from_file(file_path=text_file_path, mime_type="text/plain")
print(f"Created text BinaryContent: {text_binary_content.mime_type}, can_read: {text_binary_content.can_read}")
# Method 3: Create BinaryContent directly from in-memory data
# This approach allows creating BinaryContent without file I/O operations
alternative_text_content = BinaryContent(
data=text_content.encode("utf-8"), mime_type="text/plain", data_format="base64"
)
print(f"Alternative text BinaryContent: {alternative_text_content.mime_type}")
# 4. Initialize the OpenAI Responses Agent with file analysis capabilities
# Configure the AI model for responses
settings = OpenAISettings()
responses_model = settings.responses_model_id or "gpt-4o"
agent = OpenAIResponsesAgent(
ai_model_id=responses_model,
client=client,
instructions=(
"You are a helpful assistant that can analyze uploaded files. "
"When users upload files, examine their content and provide helpful insights. "
"You can identify file types, summarize content, and answer questions about the files."
),
name="FileAnalyzer",
)
# 5. Demonstrate multi-modal message composition
# This showcases combining text and binary content in a single message
# Compose a message containing both text instructions and file attachments
# This pattern is ideal for scenarios requiring rich, mixed-content interactions
initial_message = ChatMessageContent(
role=AuthorRole.USER,
items=[
TextContent(text="I'm uploading a PDF document and a text file for you to analyze."),
pdf_binary_content,
text_binary_content,
],
)
# 6. Conduct a conversation with the agent about the uploaded files
thread = None
# Send the initial multi-modal message containing file uploads
print("\n# User: 'I'm uploading a PDF document and a text file for you to analyze.'")
first_chunk = True
async for response in agent.invoke_stream(messages=initial_message, thread=thread):
thread = response.thread
if first_chunk:
print(f"# {response.name}: ", end="", flush=True)
first_chunk = False
print(response.content, end="", flush=True)
print() # New line after response
# Continue the conversation with text-based follow-up questions
for user_input in USER_INPUTS:
print(f"\n# User: '{user_input}'")
# Process follow-up questions using standard text input
first_chunk = True
async for response in agent.invoke_stream(messages=user_input, thread=thread):
thread = response.thread
if first_chunk:
print(f"# {response.name}: ", end="", flush=True)
first_chunk = False
print(response.content, end="", flush=True)
print() # New line after response
finally:
# 7. Clean up temporary resources
if os.path.exists(text_file_path):
os.unlink(text_file_path)
print("\n" + "=" * 60)
print("Sample completed!")
print("\nKey points about BinaryContent:")
print("1. Use BinaryContent.from_file() to create from existing files")
print("2. Use BinaryContent(data=...) to create from bytes/string data")
print("3. Specify appropriate mime_type for proper handling")
print("4. BinaryContent can be included in chat messages alongside text")
print("5. The OpenAI Responses API will process supported file types")
print("\nSupported file types include:")
print("- PDF documents (application/pdf)")
print("- Text files (text/plain)")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,95 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from semantic_kernel.agents import OpenAIResponsesAgent
from semantic_kernel.connectors.ai.open_ai import OpenAISettings
from semantic_kernel.contents.streaming_chat_message_content import StreamingChatMessageContent
"""
The following sample demonstrates how to create an OpenAI Responses Agent.
The sample shows how to have the agent answer questions about the provided
document with streaming responses.
The interaction with the agent is via the `get_response` method, which sends a
user input to the agent and receives a response from the agent. The conversation
history is maintained by the agent service, i.e. the responses are automatically
associated with the thread. Therefore, client code does not need to maintain the
conversation history.
"""
# Simulate a conversation with the agent
USER_INPUTS = [
"By birthday, who is the youngest employee?",
"Who works in sales?",
"I have a customer request, who can help me?",
]
async def main():
# 1. Create the client using OpenAI resources and configuration
client = OpenAIResponsesAgent.create_client()
pdf_file_path = os.path.join(
os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "resources", "employees.pdf"
)
with open(pdf_file_path, "rb") as file:
file = await client.files.create(file=file, purpose="assistants")
vector_store = await client.vector_stores.create(
name="step4_assistant_file_search",
file_ids=[file.id],
)
file_search_tool = OpenAIResponsesAgent.configure_file_search_tool(vector_store.id)
# 2. Create a Semantic Kernel agent for the OpenAI Responses API
agent = OpenAIResponsesAgent(
ai_model_id=OpenAISettings().chat_model_id,
client=client,
instructions="Find answers to the user's questions in the provided file.",
name="FileSearch",
tools=[file_search_tool],
)
# 3. Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread = None
response_chunks: list[StreamingChatMessageContent] = []
for user_input in USER_INPUTS:
print(f"# User: '{user_input}'")
# 4. Invoke the agent for the current message and print the response
first_chunk = True
async for response in agent.invoke_stream(messages=user_input, thread=thread):
thread = response.thread
response_chunks.append(response)
if first_chunk:
print(f"# {response.name}: ", end="", flush=True)
first_chunk = False
print(response.content, end="", flush=True)
print()
"""
# User: 'By birthday, who is the youngest employee?'
# Agent: The youngest employee by birthday is Teodor Britton, born on January 9, 1997.
# User: 'Who works in sales?'
# Agent: The employees who work in sales are:
- Mariam Jaslyn, Sales Representative
- Hicran Bea, Sales Manager
- Angelino Embla, Sales Representative.
# User: 'I have a customer request, who can help me?'
# Agent: For a customer request, you could reach out to the following people in the sales department:
- Mariam Jaslyn, Sales Representative
- Hicran Bea, Sales Manager
- Angelino Embla, Sales Representative.
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,115 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from typing import Annotated
from azure.identity import AzureCliCredential
from semantic_kernel.agents import AzureResponsesAgent
from semantic_kernel.connectors.ai.open_ai import AzureOpenAISettings
from semantic_kernel.contents import AuthorRole, FunctionCallContent, FunctionResultContent
from semantic_kernel.contents.chat_message_content import ChatMessageContent
from semantic_kernel.functions import kernel_function
"""
The following sample demonstrates how to create an OpenAI
Responses Agent using either Azure OpenAI or OpenAI. The
Responses Agent allow for function calling, the use of file search and a
web search tool. Responses Agent Threads are used to manage the
conversation state, similar to a Semantic Kernel Chat History.
Additionally, the invoke configures a message callback
to receive the conversation messages during invocation.
"""
# Define a sample plugin for the sample
class MenuPlugin:
"""A sample Menu Plugin used for the concept sample."""
@kernel_function(description="Provides a list of specials from the menu.")
def get_specials(self) -> Annotated[str, "Returns the specials from the menu."]:
return """
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
"""
@kernel_function(description="Provides the price of the requested menu item.")
def get_item_price(
self, menu_item: Annotated[str, "The name of the menu item."]
) -> Annotated[str, "Returns the price of the menu item."]:
return "$9.99"
# This callback function will be called for each intermediate message,
# which will allow one to handle FunctionCallContent and FunctionResultContent.
# If the callback is not provided, the agent will return the final response
# with no intermediate tool call steps.
async def handle_intermediate_steps(message: ChatMessageContent) -> None:
for item in message.items or []:
if isinstance(item, FunctionResultContent):
print(f"Function Result:> {item.result} for function: {item.name}")
elif isinstance(item, FunctionCallContent):
print(f"Function Call:> {item.name} with arguments: {item.arguments}")
else:
print(f"{item}")
async def main():
# 1. Create the client using Azure OpenAI resources and configuration
client = AzureResponsesAgent.create_client(credential=AzureCliCredential())
# 2. Create a Semantic Kernel agent for the OpenAI Responses API
agent = AzureResponsesAgent(
ai_model_id=AzureOpenAISettings().chat_deployment_name,
client=client,
name="Host",
instructions="Answer questions about the menu.",
plugins=[MenuPlugin()],
)
# 3. Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread = None
user_inputs = ["Hello", "What is the special soup?", "What is the special drink?", "How much is that?", "Thank you"]
try:
for user_input in user_inputs:
print(f"# {AuthorRole.USER}: '{user_input}'")
async for response in agent.invoke(
messages=user_input,
thread=thread,
on_intermediate_message=handle_intermediate_steps,
):
thread = response.thread
print(f"# {response.name}: {response.content}")
finally:
await thread.delete() if thread else None
"""
Sample Output:
# AuthorRole.USER: 'Hello'
# Host: Hi there! How can I assist you with the menu today?
# AuthorRole.USER: 'What is the special soup?'
Function Call:> MenuPlugin-get_specials with arguments: {}
Function Result:>
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
for function: MenuPlugin-get_specials
# Host: The special soup is Clam Chowder. Would you like to know more about any other specials?
# AuthorRole.USER: 'What is the special drink?'
# Host: The special drink is Chai Tea. Would you like any more information?
# AuthorRole.USER: 'How much is that?'
Function Call:> MenuPlugin-get_item_price with arguments: {"menu_item":"Chai Tea"}
Function Result:> $9.99 for function: MenuPlugin-get_item_price
# Host: The Chai Tea is $9.99. Is there anything else you'd like to know?
# AuthorRole.USER: 'Thank you'
# Host: You're welcome! If you have any more questions, feel free to ask. Enjoy your day!
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,121 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from typing import Annotated
from semantic_kernel.agents import OpenAIResponsesAgent
from semantic_kernel.connectors.ai.open_ai import OpenAISettings
from semantic_kernel.contents import AuthorRole, FunctionCallContent, FunctionResultContent
from semantic_kernel.contents.chat_message_content import ChatMessageContent
from semantic_kernel.functions import kernel_function
"""
The following sample demonstrates how to create an OpenAI
Responses Agent using either Azure OpenAI or OpenAI. The
Responses Agent allow for function calling, the use of file search and a
web search tool. Responses Agent Threads are used to manage the
conversation state, similar to a Semantic Kernel Chat History.
Additionally, the invoke_stream configures a message callback
to receive the conversation messages during streaming invocation.
This sample also demonstrates the Responses Agent Streaming
capability and how to manage a Responses Agent chat history.
"""
# Define a sample plugin for the sample
class MenuPlugin:
"""A sample Menu Plugin used for the concept sample."""
@kernel_function(description="Provides a list of specials from the menu.")
def get_specials(self) -> Annotated[str, "Returns the specials from the menu."]:
return """
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
"""
@kernel_function(description="Provides the price of the requested menu item.")
def get_item_price(
self, menu_item: Annotated[str, "The name of the menu item."]
) -> Annotated[str, "Returns the price of the menu item."]:
return "$9.99"
# This callback function will be called for each intermediate message,
# which will allow one to handle FunctionCallContent and FunctionResultContent.
# If the callback is not provided, the agent will return the final response
# with no intermediate tool call steps.
async def handle_streaming_intermediate_steps(message: ChatMessageContent) -> None:
for item in message.items or []:
if isinstance(item, FunctionResultContent):
print(f"Function Result:> {item.result} for function: {item.name}")
elif isinstance(item, FunctionCallContent):
print(f"Function Call:> {item.name} with arguments: {item.arguments}")
else:
print(f"{item}")
async def main():
# 1. Create the client using Azure OpenAI resources and configuration
client = OpenAIResponsesAgent.create_client()
# 2. Create a Semantic Kernel agent for the OpenAI Responses API
agent = OpenAIResponsesAgent(
ai_model_id=OpenAISettings().chat_model_id,
client=client,
name="Host",
instructions="Answer questions about the menu.",
plugins=[MenuPlugin()],
)
# 3. Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread = None
user_inputs = ["Hello", "What is the special soup?", "What is the special drink?", "How much is that?", "Thank you"]
try:
for user_input in user_inputs:
print(f"# {AuthorRole.USER}: '{user_input}'")
first_chunk = True
async for response in agent.invoke_stream(
messages=user_input,
thread=thread,
on_intermediate_message=handle_streaming_intermediate_steps,
):
thread = response.thread
if first_chunk:
print(f"# {response.name}: ", end="", flush=True)
first_chunk = False
print(response.content, end="", flush=True)
print()
finally:
await thread.delete() if thread else None
"""
Sample Output:
# AuthorRole.USER: 'Hello'
# Host: Hello! How can I assist you with the menu today?
# AuthorRole.USER: 'What is the special soup?'
Function Call:> MenuPlugin-get_specials with arguments: {}
Function Result:>
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
for function: MenuPlugin-get_specials
# Host: The special soup today is Clam Chowder. Would you like to know more about it or hear about other specials?
# AuthorRole.USER: 'What is the special drink?'
# Host: The special drink today is Chai Tea. Would you like more details or are you interested in ordering it?
# AuthorRole.USER: 'How much is that?'
Function Call:> MenuPlugin-get_item_price with arguments: {"menu_item":"Chai Tea"}
Function Result:> $9.99 for function: MenuPlugin-get_item_price
# Host: The special drink, Chai Tea, is $9.99. Would you like to order one or need information on something else?
# AuthorRole.USER: 'Thank you'
# Host: You're welcome! If you have any more questions or need help with the menu, just let me know. Enjoy your day!
"""
if __name__ == "__main__":
asyncio.run(main())

Some files were not shown because too many files have changed in this diff Show More