chore: import upstream snapshot with attribution
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
dotnet-build-and-test / dotnet-test-functions (push) Has been cancelled
dotnet-build-and-test / paths-filter (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Debug, windows-latest, net9.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net8.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-foundry-hosted-it (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test-check (push) Has been cancelled
dotnet-build-and-test / Integration Test Report (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:39:25 +08:00
commit db620d33df
5151 changed files with 925932 additions and 0 deletions
@@ -0,0 +1,17 @@
# Provider Samples Overview
This directory groups provider-specific samples for Agent Framework.
| Folder | What you will find |
| --- | --- |
| [`anthropic/`](anthropic/) | Anthropic Claude samples using both `AnthropicClient` and `ClaudeAgent`, including tools, MCP, sessions, and Foundry Anthropic integration. |
| [`amazon/`](amazon/) | AWS Bedrock samples using `BedrockChatClient`, including tool-enabled agent usage. |
| [`azure/`](azure/) | Azure OpenAI chat completion samples using `OpenAIChatCompletionClient`, including basic usage, explicit configuration, tools, and sessions. |
| [`copilotstudio/`](copilotstudio/) | Microsoft Copilot Studio agent samples, including required environment/app registration setup and explicit authentication patterns. |
| [`custom/`](custom/) | Framework extensibility samples for building custom `BaseAgent` and `BaseChatClient` implementations, including layer-composition guidance. |
| [`foundry/`](foundry/) | Microsoft Foundry and Foundry Local samples using `FoundryChatClient`, `FoundryAgent`, `RawFoundryAgentChatClient`, and `FoundryLocalClient` for hosted agents, Responses API, local inference, tools, MCP, and sessions. |
| [`github_copilot/`](github_copilot/) | `GitHubCopilotAgent` samples showing basic usage, session handling, permission-scoped shell/file/url access, and MCP integration. |
| [`ollama/`](ollama/) | Local Ollama samples using `OllamaChatClient` (recommended) plus OpenAI-compatible Ollama setup, including reasoning and multimodal examples. |
| [`openai/`](openai/) | OpenAI provider samples for Chat and Chat Completion clients, including tools, structured output, sessions, MCP, web search, and multimodal tasks. |
Each folder has its own README with setup requirements and file-by-file details.
@@ -0,0 +1,17 @@
# Bedrock Examples
This folder contains examples demonstrating how to use AWS Bedrock models with the Agent Framework. The sample
uses `BEDROCK_CHAT_MODEL`, `BEDROCK_REGION`, and AWS credentials (`AWS_ACCESS_KEY_ID`,
`AWS_SECRET_ACCESS_KEY`, optional `AWS_SESSION_TOKEN`).
## Examples
| File | Description |
|------|-------------|
| [`bedrock_chat_client.py`](bedrock_chat_client.py) | Uses `BedrockChatClient` with a simple tool-enabled `Agent` to demonstrate direct Bedrock chat integration. |
## Environment Variables
- `BEDROCK_CHAT_MODEL`: Bedrock model ID (for example, `anthropic.claude-3-5-sonnet-20240620-v1:0`)
- `BEDROCK_REGION`: AWS region (defaults to `us-east-1` if unset)
- AWS credentials via standard variables (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, optional `AWS_SESSION_TOKEN`)
@@ -0,0 +1,65 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from typing import Annotated
from agent_framework import Agent, tool
from agent_framework.amazon import BedrockChatClient, BedrockChatOptions
from dotenv import load_dotenv
from pydantic import Field
# Load environment variables from .env file
load_dotenv()
"""
Bedrock Chat Client Example
This sample demonstrates using `BedrockChatClient` with an agent and a simple tool.
Environment variables used:
- `BEDROCK_CHAT_MODEL`
- `BEDROCK_REGION` (defaults to `us-east-1` if unset)
- AWS credentials via standard variables (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`,
optional `AWS_SESSION_TOKEN`)
"""
# NOTE: approval_mode="never_require" is for sample brevity.
# Use "always_require" in production; see samples/02-agents/tools/function_tool_with_approval.py
# and samples/02-agents/tools/function_tool_with_approval_and_sessions.py.
@tool(approval_mode="never_require")
def get_weather(
city: Annotated[str, Field(description="The city to get the weather for.")],
) -> dict[str, str]:
"""Return a mock forecast for the requested city."""
normalized_city = city.strip() or "New York"
return {"city": normalized_city, "forecast": "72F and sunny"}
async def main() -> None:
"""Run a Bedrock-backed agent with one tool call."""
# 1. Create an agent with Bedrock chat client and one tool.
agent = Agent(
client=BedrockChatClient(),
instructions="You are a concise travel assistant.",
name="BedrockWeatherAgent",
tools=[get_weather],
default_options=BedrockChatOptions(tool_choice="auto"),
)
# 2. Run a query that uses the weather tool.
query = "Use the weather tool to check the forecast for New York."
print(f"User: {query}")
response = await agent.run(query)
print(f"Assistant: {response.text}")
if __name__ == "__main__":
asyncio.run(main())
"""
Sample output:
User: Use the weather tool to check the forecast for New York.
Assistant: The forecast for New York is 72F and sunny.
"""
@@ -0,0 +1,47 @@
# Anthropic Examples
This folder contains examples demonstrating how to use Anthropic's Claude models with the Agent Framework.
## Anthropic Client Examples
| File | Description |
|------|-------------|
| [`anthropic_basic.py`](anthropic_basic.py) | Demonstrates how to setup a simple agent using the AnthropicClient, with both streaming and non-streaming responses. |
| [`anthropic_advanced.py`](anthropic_advanced.py) | Shows advanced usage of the AnthropicClient, including hosted tools and `thinking`. |
| [`anthropic_skills.py`](anthropic_skills.py) | Illustrates how to use Anthropic-managed Skills with an agent, including the Code Interpreter tool and file generation and saving. |
| [`anthropic_foundry.py`](anthropic_foundry.py) | Example of using Foundry's Anthropic integration with the Agent Framework. |
## Claude Agent Examples
| File | Description |
|------|-------------|
| [`anthropic_claude_basic.py`](anthropic_claude_basic.py) | Basic usage of ClaudeAgent with streaming, non-streaming, and custom tools. |
| [`anthropic_claude_with_tools.py`](anthropic_claude_with_tools.py) | Using built-in tools (Read, Glob, Grep, etc.). |
| [`anthropic_claude_with_shell.py`](anthropic_claude_with_shell.py) | Shell command execution with interactive permission handling. |
| [`anthropic_claude_with_multiple_permissions.py`](anthropic_claude_with_multiple_permissions.py) | Combining multiple tools (Bash, Read, Write) with permission prompts. |
| [`anthropic_claude_with_url.py`](anthropic_claude_with_url.py) | Fetching and processing web content with WebFetch. |
| [`anthropic_claude_with_mcp.py`](anthropic_claude_with_mcp.py) | Local (stdio) and remote (HTTP) MCP server configuration. |
| [`anthropic_claude_with_session.py`](anthropic_claude_with_session.py) | Session management, persistence, and resumption. |
## Environment Variables
### Anthropic Client
- `ANTHROPIC_API_KEY`: Your Anthropic API key (get one from [Anthropic Console](https://console.anthropic.com/))
- `ANTHROPIC_CHAT_MODEL`: The Claude model to use (e.g., `claude-haiku-4-5`, `claude-sonnet-4-5-20250929`)
### Foundry
- `ANTHROPIC_FOUNDRY_API_KEY`: Your Foundry Anthropic API key
- `ANTHROPIC_FOUNDRY_RESOURCE`: Your Foundry resource name (for example `my-foundry-resource`)
- `ANTHROPIC_FOUNDRY_BASE_URL`: Optional full Foundry Anthropic base URL alternative to `ANTHROPIC_FOUNDRY_RESOURCE`
- `ANTHROPIC_CHAT_MODEL`: The Claude model to use in Foundry (e.g., `claude-haiku-4-5`)
### Claude Agent
- `CLAUDE_AGENT_CLI_PATH`: Path to the Claude Code CLI executable
- `CLAUDE_AGENT_MODEL`: Model to use (sonnet, opus, haiku)
- `CLAUDE_AGENT_CWD`: Working directory for Claude CLI
- `CLAUDE_AGENT_PERMISSION_MODE`: Permission mode (default, acceptEdits, plan, bypassPermissions)
- `CLAUDE_AGENT_MAX_TURNS`: Maximum number of conversation turns
- `CLAUDE_AGENT_MAX_BUDGET_USD`: Maximum budget in USD
@@ -0,0 +1,72 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from agent_framework import Agent
from agent_framework.anthropic import AnthropicClient
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
"""
Anthropic Chat Agent Example
This sample demonstrates using Anthropic with:
- Setting up an Anthropic-based agent with hosted tools.
- Using the `thinking` feature.
- Displaying both thinking and usage information during streaming responses.
Environment variables:
ANTHROPIC_API_KEY — Your Anthropic API key
ANTHROPIC_CHAT_MODEL — The Anthropic model to use (e.g., "claude-sonnet-4-6")
"""
async def main() -> None:
"""Example of streaming response (get results as they are generated)."""
client = AnthropicClient(
api_key=os.getenv("ANTHROPIC_API_KEY"),
model=os.getenv("ANTHROPIC_CHAT_MODEL"),
)
# Create MCP tool configuration using instance method
mcp_tool = client.get_mcp_tool(
name="Microsoft_Learn_MCP",
url="https://learn.microsoft.com/api/mcp",
)
# Create web search tool configuration using instance method
web_search_tool = client.get_web_search_tool()
agent = Agent(
client=client,
name="DocsAgent",
instructions="You are a helpful agent for both Microsoft docs questions and general questions.",
tools=[mcp_tool, web_search_tool],
default_options={
# anthropic needs a value for the max_tokens parameter
# we set it to 1024, but you can override like this:
"max_tokens": 20000,
"thinking": {"type": "enabled", "budget_tokens": 10000},
},
)
query = "Can you compare Python decorators with C# attributes?"
print(f"User: {query}")
print("Agent: ", end="", flush=True)
async for chunk in agent.run(query, stream=True):
for content in chunk.contents:
if content.type == "text_reasoning" and content.text:
print(f"\033[32m{content.text}\033[0m", end="", flush=True)
if content.type == "usage":
print(f"\n\033[34m[Usage so far: {content.usage_details}]\033[0m\n", end="", flush=True)
if chunk.text:
print(chunk.text, end="", flush=True)
print("\n")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,78 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from random import randint
from typing import Annotated
from agent_framework import Agent, tool
from agent_framework.anthropic import AnthropicClient
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
"""
Anthropic Chat Agent Example
This sample demonstrates using Anthropic with an agent and a single custom tool.
"""
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production;
# see samples/02-agents/tools/function_tool_with_approval.py
# and samples/02-agents/tools/function_tool_with_approval_and_sessions.py.
@tool(approval_mode="never_require")
def get_weather(
location: Annotated[str, "The location to get the weather for."],
) -> str:
"""Get the weather for a given location."""
conditions = ["sunny", "cloudy", "rainy", "stormy"]
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C."
async def non_streaming_example() -> None:
"""Example of non-streaming response (get the complete result at once)."""
print("=== Non-streaming Response Example ===")
agent = Agent(
client=AnthropicClient(model="claude-sonnet-4-5-20250929"),
name="WeatherAgent",
instructions="You are a helpful weather agent.",
tools=get_weather,
)
query = "What's the weather like in Seattle?"
print(f"User: {query}")
result = await agent.run(query)
print(f"Result: {result}\n")
async def streaming_example() -> None:
"""Example of streaming response (get results as they are generated)."""
print("=== Streaming Response Example ===")
agent = Agent(
client=AnthropicClient(model="claude-sonnet-4-5-20250929"),
name="WeatherAgent",
instructions="You are a helpful weather agent.",
tools=get_weather,
)
query = "What's the weather like in Portland and in Paris?"
print(f"User: {query}")
print("Agent: ", end="", flush=True)
async for chunk in agent.run(query, stream=True):
if chunk.text:
print(chunk.text, end="", flush=True)
print("\n")
async def main() -> None:
print("=== Anthropic Example ===")
await streaming_example()
await non_streaming_example()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,80 @@
# Copyright (c) Microsoft. All rights reserved.
"""
Claude Agent Basic Example
This sample demonstrates using ClaudeAgent for basic interactions
with Claude Agent SDK.
Prerequisites:
- Claude Code CLI must be installed and configured
- pip install agent-framework-claude
Environment variables:
- CLAUDE_AGENT_MODEL: Model to use (sonnet, opus, haiku)
- CLAUDE_AGENT_PERMISSION_MODE: Permission mode (default, acceptEdits, bypassPermissions)
"""
import asyncio
from typing import Annotated
from agent_framework import tool
from agent_framework.anthropic import ClaudeAgent
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
@tool
def get_weather(location: Annotated[str, "The city name"]) -> str:
"""Get the current weather for a location."""
return f"The weather in {location} is sunny with a high of 25C."
async def non_streaming_example() -> None:
"""Example of non-streaming response."""
print("=== Non-streaming Example ===")
agent = ClaudeAgent(
name="BasicAgent",
instructions="You are a helpful assistant. Keep responses concise.",
tools=[get_weather],
)
async with agent:
query = "What's the weather in Seattle?"
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result.text}\n")
async def streaming_example() -> None:
"""Example of streaming response."""
print("=== Streaming Example ===")
agent = ClaudeAgent(
name="StreamingAgent",
instructions="You are a helpful assistant.",
tools=[get_weather],
)
async with agent:
query = "What's the weather in Paris?"
print(f"User: {query}")
print("Agent: ", end="", flush=True)
async for chunk in agent.run(query, stream=True):
if chunk.text:
print(chunk.text, end="", flush=True)
print("\n")
async def main() -> None:
print("=== Claude Agent Basic Example ===\n")
await non_streaming_example()
await streaming_example()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,129 @@
# Copyright (c) Microsoft. All rights reserved.
"""
Claude Agent with Function Approval
This sample demonstrates how to enforce ``approval_mode="always_require"`` on a
``FunctionTool`` when using ``ClaudeAgent``. Because the Claude Agent SDK runs
its own tool-calling loop, the standard agent-framework approval round-trip
(``FunctionApprovalRequestContent`` → ``FunctionApprovalResponseContent``) is
not available — the agent instead awaits an ``on_function_approval`` callback
inside the tool handler before executing the tool.
Key points:
- ``on_function_approval`` is set on ``ClaudeAgentOptions`` and receives a
``FunctionCallContent`` describing the pending call. It must return ``True``
to allow execution or ``False`` to deny it. Async callbacks are also
supported.
- If no callback is configured, calls to ``always_require`` tools are denied
by default and the model receives an explanatory error so it can react.
- This callback is independent of Claude's built-in ``permission_mode`` /
``can_use_tool`` features, which gate the SDK's own shell/file actions.
Environment variables:
- ANTHROPIC_API_KEY: Your Anthropic API key.
"""
import asyncio
from random import randrange
from typing import Annotated
from agent_framework import Content, tool
from agent_framework.anthropic import ClaudeAgent
from dotenv import load_dotenv
load_dotenv()
# Always-require tool: execution must be gated by on_function_approval.
@tool(approval_mode="always_require")
def get_weather_detail(location: Annotated[str, "The city and state, e.g. San Francisco, CA"]) -> str:
"""Get a detailed weather report for a location."""
conditions = ["sunny", "cloudy", "rainy", "stormy"]
return (
f"The weather in {location} is {conditions[randrange(0, len(conditions))]} "
f"with a high of {randrange(10, 30)}C and humidity of 88%."
)
def prompt_for_approval(call: Content) -> bool:
"""Synchronous approval prompt.
The callback receives a ``FunctionCallContent`` so the operator can review
the tool name and arguments before deciding. Returning ``True`` allows the
call; returning ``False`` denies it and a tool-error is returned to the
model.
"""
print(f"\n[Function Approval Request]\n Tool: {call.name}\n Arguments: {call.arguments}")
response = input("Approve this tool call? (y/n): ").strip().lower()
return response in ("y", "yes")
async def prompt_for_approval_async(call: Content) -> bool:
"""Async approval prompt.
Use an async callback when approval requires I/O (e.g. an HTTP call to a
review service or queueing the request to a UI). ``input()`` is wrapped
with ``asyncio.to_thread`` so the event loop is not blocked.
"""
print(f"\n[Function Approval Request - async]\n Tool: {call.name}\n Arguments: {call.arguments}")
response = await asyncio.to_thread(input, "Approve this tool call? (y/n): ")
return response.strip().lower() in ("y", "yes")
async def run_with_sync_callback() -> None:
print("\n=== Claude Agent: synchronous approval callback ===")
agent = ClaudeAgent(
instructions="You are a helpful weather assistant.",
tools=[get_weather_detail],
default_options={"on_function_approval": prompt_for_approval},
)
async with agent:
query = "Give me the detailed weather for Seattle."
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result.text}")
async def run_with_async_callback() -> None:
print("\n=== Claude Agent: asynchronous approval callback ===")
agent = ClaudeAgent(
instructions="You are a helpful weather assistant.",
tools=[get_weather_detail],
default_options={"on_function_approval": prompt_for_approval_async},
)
async with agent:
query = "Give me the detailed weather for Tokyo."
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result.text}")
async def run_without_callback() -> None:
"""Default-deny demonstration.
With no ``on_function_approval`` configured, the always-require tool is
refused and the model receives an explanatory error, so it can apologise
or try a different approach instead of silently failing.
"""
print("\n=== Claude Agent: no callback configured (deny by default) ===")
agent = ClaudeAgent(
instructions="You are a helpful weather assistant.",
tools=[get_weather_detail],
)
async with agent:
query = "Give me the detailed weather for Paris."
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result.text}")
async def main() -> None:
print("=== Claude Agent: Function approval enforcement ===")
await run_with_sync_callback()
await run_with_async_callback()
await run_without_callback()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,88 @@
# Copyright (c) Microsoft. All rights reserved.
"""
Claude Agent with MCP Servers
This sample demonstrates how to configure MCP (Model Context Protocol) servers
with ClaudeAgent. It shows both local (stdio) and remote (HTTP) server
configurations, giving the agent access to external tools and data sources.
Supported MCP server types:
- "stdio": Local process-based server
- "http": Remote HTTP server
- "sse": Remote SSE (Server-Sent Events) server
Environment variables:
- ANTHROPIC_API_KEY: Your Anthropic API key
SECURITY NOTE: MCP servers can expose powerful capabilities. Only configure
servers you trust. Use permission handlers to control what actions are allowed.
"""
import asyncio
from typing import Any
from agent_framework.anthropic import ClaudeAgent
from claude_agent_sdk import PermissionResultAllow, PermissionResultDeny
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
async def prompt_permission(
tool_name: str,
tool_input: dict[str, Any],
context: object,
) -> PermissionResultAllow | PermissionResultDeny:
"""Permission handler that prompts the user for approval."""
print(f"\n[Permission Request: {tool_name}]")
response = input("Approve? (y/n): ").strip().lower()
if response in ("y", "yes"):
return PermissionResultAllow()
return PermissionResultDeny(message="Denied by user")
async def main() -> None:
print("=== Claude Agent with MCP Servers ===\n")
# Configure both local and remote MCP servers
mcp_servers: dict[str, Any] = {
# Local stdio server: provides filesystem access tools
"filesystem": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "."],
},
# Remote HTTP server: Microsoft Learn documentation
"microsoft-learn": {
"type": "http",
"url": "https://learn.microsoft.com/api/mcp",
},
}
agent = ClaudeAgent(
instructions="You are a helpful assistant with access to the local filesystem and Microsoft Learn.",
default_options={
"can_use_tool": prompt_permission,
"mcp_servers": mcp_servers,
},
)
async with agent:
# Query that exercises the local filesystem MCP server
query1 = "List the first three files in the current directory"
print(f"User: {query1}")
result1 = await agent.run(query1)
print(f"Agent: {result1.text}\n")
# Query that exercises the remote Microsoft Learn MCP server
query2 = "Search Microsoft Learn for 'Azure Functions Python' and summarize the top result"
print(f"User: {query2}")
result2 = await agent.run(query2)
print(f"Agent: {result2.text}\n")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,76 @@
# Copyright (c) Microsoft. All rights reserved.
"""
Claude Agent with Multiple Permissions
This sample demonstrates how to enable multiple permission types with ClaudeAgent.
By combining different tools and using a permission handler, the agent can perform
complex tasks that require multiple capabilities.
Available built-in tools:
- "Bash": Execute shell commands
- "Read": Read files from the filesystem
- "Write": Write files to the filesystem
- "Edit": Edit existing files
- "Glob": Search for files by pattern
- "Grep": Search file contents
Environment variables:
- ANTHROPIC_API_KEY: Your Anthropic API key
SECURITY NOTE: Only enable permissions that are necessary for your use case.
More permissions mean more potential for unintended actions.
"""
import asyncio
from typing import Any
from agent_framework.anthropic import ClaudeAgent
from claude_agent_sdk import PermissionResultAllow, PermissionResultDeny
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
async def prompt_permission(
tool_name: str,
tool_input: dict[str, Any],
context: object,
) -> PermissionResultAllow | PermissionResultDeny:
"""Permission handler that prompts the user for approval."""
print(f"\n[Permission Request: {tool_name}]")
if "command" in tool_input:
print(f" Command: {tool_input.get('command')}")
if "file_path" in tool_input:
print(f" Path: {tool_input.get('file_path')}")
if "pattern" in tool_input:
print(f" Pattern: {tool_input.get('pattern')}")
response = input("Approve? (y/n): ").strip().lower()
if response in ("y", "yes"):
return PermissionResultAllow()
return PermissionResultDeny(message="Denied by user")
async def main() -> None:
print("=== Claude Agent with Multiple Permissions ===\n")
agent = ClaudeAgent(
instructions="You are a helpful development assistant that can read, write files and run commands.",
tools=["Bash", "Read", "Write", "Glob"],
default_options={
"can_use_tool": prompt_permission,
},
)
async with agent:
query = "List the first 3 Python files, then read the first one and create a summary in summary.txt"
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result.text}\n")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,152 @@
# Copyright (c) Microsoft. All rights reserved.
"""
Claude Agent with Session Management
This sample demonstrates session management with ClaudeAgent, showing
persistent conversation capabilities. Sessions are automatically persisted
by the Claude Code CLI.
Environment variables:
- ANTHROPIC_API_KEY: Your Anthropic API key
"""
import asyncio
from random import randint
from typing import Annotated
from agent_framework import tool
from agent_framework.anthropic import ClaudeAgent
from dotenv import load_dotenv
from pydantic import Field
# Load environment variables from .env file
load_dotenv()
@tool
def get_weather(
location: Annotated[str, Field(description="The location to get the weather for.")],
) -> str:
"""Get the weather for a given location."""
conditions = ["sunny", "cloudy", "rainy", "stormy"]
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C."
async def example_with_automatic_session_creation() -> None:
"""Each agent instance creates a new session."""
print("=== Automatic Session Creation Example ===")
# First agent - first session
agent1 = ClaudeAgent(
instructions="You are a helpful weather agent.",
tools=[get_weather],
)
async with agent1:
query1 = "What's the weather like in Seattle?"
print(f"User: {query1}")
result1 = await agent1.run(query1)
print(f"Agent: {result1.text}")
# Second agent - new session, no memory of previous conversation
agent2 = ClaudeAgent(
instructions="You are a helpful weather agent.",
tools=[get_weather],
)
async with agent2:
query2 = "What was the last city I asked about?"
print(f"\nUser: {query2}")
result2 = await agent2.run(query2)
print(f"Agent: {result2.text}")
print("Note: Each agent instance creates a separate session, so the agent doesn't remember previous context.\n")
async def example_with_session_persistence() -> None:
"""Reuse session via thread object for multi-turn conversations."""
print("=== Session Persistence Example ===")
agent = ClaudeAgent(
instructions="You are a helpful weather agent.",
tools=[get_weather],
)
async with agent:
# Create a session to maintain conversation context
session = agent.create_session()
# First query
query1 = "What's the weather like in Tokyo?"
print(f"User: {query1}")
result1 = await agent.run(query1, session=session)
print(f"Agent: {result1.text}")
# Second query - using same thread maintains context
query2 = "How about London?"
print(f"\nUser: {query2}")
result2 = await agent.run(query2, session=session)
print(f"Agent: {result2.text}")
# Third query - agent should remember both previous cities
query3 = "Which of the cities I asked about has better weather?"
print(f"\nUser: {query3}")
result3 = await agent.run(query3, session=session)
print(f"Agent: {result3.text}")
print("Note: The agent remembers context from previous messages in the same session.\n")
async def example_with_existing_session_id() -> None:
"""Resume session in new agent instance using service_session_id."""
print("=== Existing Session ID Example ===")
existing_session_id = None
# First agent instance - start a conversation
agent1 = ClaudeAgent(
instructions="You are a helpful weather agent.",
tools=[get_weather],
)
async with agent1:
session = agent1.create_session()
query1 = "What's the weather in Paris?"
print(f"User: {query1}")
result1 = await agent1.run(query1, session=session)
print(f"Agent: {result1.text}")
# Capture the session ID for later use
existing_session_id = session.service_session_id
print(f"Session ID: {existing_session_id}")
if existing_session_id:
print("\n--- Continuing with the same session ID in a new agent instance ---")
# Second agent instance - resume the conversation
agent2 = ClaudeAgent(
instructions="You are a helpful weather agent.",
tools=[get_weather],
)
async with agent2:
# Get session with existing session ID
session = agent2.get_session(service_session_id=existing_session_id)
query2 = "What was the last city I asked about?"
print(f"User: {query2}")
result2 = await agent2.run(query2, session=session)
print(f"Agent: {result2.text}")
print("Note: The agent continues the conversation using the session ID.\n")
async def main() -> None:
print("=== Claude Agent Session Management Examples ===\n")
await example_with_automatic_session_creation()
await example_with_session_persistence()
await example_with_existing_session_id()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,64 @@
# Copyright (c) Microsoft. All rights reserved.
"""
Claude Agent with Shell Permissions
This sample demonstrates how to enable shell command execution with ClaudeAgent.
By providing a permission handler via `can_use_tool`, the agent can execute
shell commands to perform tasks like listing files, running scripts, or executing system commands.
Environment variables:
- ANTHROPIC_API_KEY: Your Anthropic API key
SECURITY NOTE: Only enable shell permissions when you trust the agent's actions.
Shell commands have full access to your system within the permissions of the running process.
"""
import asyncio
from typing import Any
from agent_framework.anthropic import ClaudeAgent
from claude_agent_sdk import PermissionResultAllow, PermissionResultDeny
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
async def prompt_permission(
tool_name: str,
tool_input: dict[str, Any],
context: object,
) -> PermissionResultAllow | PermissionResultDeny:
"""Permission handler that prompts the user for approval."""
print(f"\n[Permission Request: {tool_name}]")
if "command" in tool_input:
print(f" Command: {tool_input.get('command')}")
response = input("Approve? (y/n): ").strip().lower()
if response in ("y", "yes"):
return PermissionResultAllow()
return PermissionResultDeny(message="Denied by user")
async def main() -> None:
print("=== Claude Agent with Shell Permissions ===\n")
agent = ClaudeAgent(
instructions="You are a helpful assistant that can execute shell commands.",
tools=["Bash"],
default_options={
"can_use_tool": prompt_permission,
},
)
async with agent:
query = "List the first 3 markdown (.md) files in the current directory"
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result.text}\n")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,47 @@
# Copyright (c) Microsoft. All rights reserved.
"""
Claude Agent with Built-in Tools
This sample demonstrates using ClaudeAgent with built-in tools for file operations.
Built-in tools are specified as strings in the tools parameter.
Available built-in tools:
- "Bash": Execute shell commands
- "Read": Read files from the filesystem
- "Write": Write files to the filesystem
- "Edit": Edit existing files
- "Glob": Search for files by pattern
- "Grep": Search file contents
Environment variables:
- ANTHROPIC_API_KEY: Your Anthropic API key
"""
import asyncio
from agent_framework.anthropic import ClaudeAgent
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
async def main() -> None:
print("=== Claude Agent with Built-in Tools ===\n")
# Built-in tools can be specified as strings in the tools parameter
agent = ClaudeAgent(
instructions="You are a helpful assistant that can read files.",
tools=["Read", "Glob"],
)
async with agent:
query = "List the first 3 Python files in the current directory"
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result.text}\n")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,45 @@
# Copyright (c) Microsoft. All rights reserved.
"""
Claude Agent with URL Fetching
This sample demonstrates how to enable URL fetching with ClaudeAgent.
By enabling the WebFetch tool, the agent can fetch and process content from web URLs.
Available web tools:
- "WebFetch": Fetch content from URLs
- "WebSearch": Search the web
Environment variables:
- ANTHROPIC_API_KEY: Your Anthropic API key
SECURITY NOTE: Only enable URL permissions when you trust the agent's actions.
URL fetching allows the agent to access any URL accessible from your network.
"""
import asyncio
from agent_framework.anthropic import ClaudeAgent
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
async def main() -> None:
print("=== Claude Agent with URL Fetching ===\n")
agent = ClaudeAgent(
instructions="You are a helpful assistant that can fetch and summarize web content.",
tools=["WebFetch"],
)
async with agent:
query = "Fetch https://learn.microsoft.com/agent-framework/tutorials/quick-start and summarize its contents"
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result.text}\n")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,76 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from agent_framework import Agent
from agent_framework.foundry import AnthropicFoundryClient
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
"""
Anthropic Foundry Chat Agent Example
This sample demonstrates using Anthropic with:
- Setting up an Anthropic-based agent with hosted tools.
- Using the `thinking` feature.
- Displaying both thinking and usage information during streaming responses.
This example requires `anthropic>=0.74.0` and an endpoint in Foundry for Anthropic.
To use the Foundry integration ensure you have the following environment variables set:
- ANTHROPIC_FOUNDRY_API_KEY
Alternatively you can pass in a azure_ad_token_provider function to the AsyncAnthropicFoundry constructor.
- ANTHROPIC_FOUNDRY_RESOURCE
Should be the resource name portion of your Foundry Anthropic URL, such as <your-resource-name>.
- ANTHROPIC_FOUNDRY_BASE_URL
Optional alternative to ANTHROPIC_FOUNDRY_RESOURCE. Should be something like
https://<your-resource-name>.services.ai.azure.com/anthropic/
- ANTHROPIC_CHAT_MODEL
Should be something like claude-haiku-4-5
"""
async def main() -> None:
"""Example of streaming response (get results as they are generated)."""
client = AnthropicFoundryClient()
# Create MCP tool configuration using instance method
mcp_tool = client.get_mcp_tool(
name="Microsoft_Learn_MCP",
url="https://learn.microsoft.com/api/mcp",
)
# Create web search tool configuration using instance method
web_search_tool = client.get_web_search_tool()
agent = Agent(
client=client,
name="DocsAgent",
instructions="You are a helpful agent for both Microsoft docs questions and general questions.",
tools=[mcp_tool, web_search_tool],
default_options={
# anthropic needs a value for the max_tokens parameter
# we set it to 1024, but you can override like this:
"max_tokens": 20000,
"thinking": {"type": "enabled", "budget_tokens": 10000},
},
)
query = "Can you compare Python decorators with C# attributes?"
print(f"User: {query}")
print("Agent: ", end="", flush=True)
async for chunk in agent.run(query, stream=True):
for content in chunk.contents:
if content.type == "text_reasoning":
print(f"\033[32m{content.text}\033[0m", end="", flush=True)
if content.type == "usage":
print(f"\n\033[34m[Usage so far: {content.usage_details}]\033[0m\n", end="", flush=True)
if chunk.text:
print(chunk.text, end="", flush=True)
print("\n")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,99 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import logging
from pathlib import Path
from agent_framework import Agent, Content
from agent_framework.anthropic import AnthropicChatOptions, AnthropicClient
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
logger = logging.getLogger(__name__)
"""
Anthropic Skills Agent Example
This sample demonstrates using Anthropic with:
- Listing and using Anthropic-managed Skills.
- One approach to add additional beta flags.
You can also set additonal_chat_options with "additional_beta_flags" per request.
- Creating an agent with the Code Interpreter tool and a Skill.
- Catching and downloading generated files from the agent.
Environment variables:
- ANTHROPIC_API_KEY: Your Anthropic API key
- ANTHROPIC_CHAT_MODEL_ID: The Anthropic model to use, such as "claude-sonnet-4-5-20250929"
"""
async def main() -> None:
"""Example of streaming response (get results as they are generated)."""
client = AnthropicClient[AnthropicChatOptions](additional_beta_flags=["skills-2025-10-02"])
# List Anthropic-managed Skills
skills = await client.anthropic_client.beta.skills.list(source="anthropic", betas=["skills-2025-10-02"]) # type: ignore
for skill in skills.data:
print(f"{skill.source}: {skill.id} (version: {skill.latest_version})")
# Create a agent with the pptx skill enabled
# Skills also need the code interpreter tool to function
agent = Agent(
client=client,
name="DocsAgent",
instructions="You are a helpful agent for creating powerpoint presentations.",
tools=client.get_code_interpreter_tool(),
default_options={
"max_tokens": 4096,
"thinking": {"type": "enabled", "budget_tokens": 2000},
"container": {"skills": [{"type": "anthropic", "skill_id": "pptx", "version": "latest"}]},
},
)
print(
"The agent output will use the following colors:\n"
"\033[0mUser: (default)\033[0m\n"
"\033[0mAgent: (default)\033[0m\n"
"\033[32mAgent Reasoning: (green)\033[0m\n"
"\033[34mUsage: (blue)\033[0m\n"
)
query = "Create a simple presentation with 2 slides about Python programming"
print(f"User: {query}")
print("Agent: ", end="", flush=True)
files: list[Content] = []
async for chunk in agent.run(query, stream=True):
for content in chunk.contents:
match content.type:
case "text":
print(content.text, end="", flush=True)
case "text_reasoning":
print(f"\033[32m{content.text}\033[0m", end="", flush=True)
case "usage":
print(f"\n\033[34m[Usage so far: {content.usage_details}]\033[0m\n", end="", flush=True)
case "hosted_file":
# Catch generated files
files.append(content)
case _:
logger.debug("Unhandled content type: %s", content.type)
pass
print("\n")
if files:
# Save to a new file (will be in the folder where you are running this script)
# When running this sample multiple times, the files will be overritten
# Since I'm using the pptx skill, the files will be PowerPoint presentations
print("Generated files:")
for idx, file in enumerate(files):
if file.file_id is None:
continue
file_content = await client.anthropic_client.beta.files.download( # type: ignore
file_id=file.file_id, betas=["files-api-2025-04-14"]
)
with open(Path(__file__).parent / f"python_programming-{idx}.pptx", "wb") as f:
await file_content.write_to_file(f.name)
print(f"File {idx}: python_programming-{idx}.pptx saved to disk.")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,102 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import subprocess
from typing import Any
from agent_framework import Agent, Message, tool
from agent_framework.anthropic import AnthropicClient
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
"""
Anthropic Client with Shell Tool Example
This sample demonstrates using @tool(approval_mode=...) with AnthropicClient
for executing bash commands locally. The bash tool tells the model it can
request shell commands, while the actual execution happens on YOUR machine
via a user-provided function.
SECURITY NOTE: This example executes real commands on your local machine.
Only enable this when you trust the agent's actions. Consider implementing
allowlists, sandboxing, or approval workflows for production use.
"""
@tool(approval_mode="always_require")
def run_bash(command: str) -> str:
"""Execute a bash command using subprocess and return the output."""
try:
result = subprocess.run(
command,
shell=True,
capture_output=True,
text=True,
timeout=30,
)
parts: list[str] = []
if result.stdout:
parts.append(result.stdout)
if result.stderr:
parts.append(f"stderr: {result.stderr}")
parts.append(f"exit_code: {result.returncode}")
return "\n".join(parts)
except subprocess.TimeoutExpired:
return "Command timed out after 30 seconds"
except Exception as e:
return f"Error executing command: {e}"
async def main() -> None:
"""Example showing how to use the shell tool with AnthropicClient."""
print("=== Anthropic Agent with Shell Tool Example ===")
print("NOTE: Commands will execute on your local machine.\n")
client = AnthropicClient()
shell = client.get_shell_tool(func=run_bash)
agent = Agent(
client=client,
instructions="You are a helpful assistant that can execute bash commands to answer questions.",
tools=[shell],
)
query = "Use bash to print 'Hello from Anthropic shell!' and show the current working directory"
print(f"User: {query}")
result = await run_with_approvals(query, agent)
print(f"Result: {result}\n")
async def run_with_approvals(query: str, agent: Agent[Any]) -> Any:
"""Run the agent and handle shell approvals outside tool execution."""
current_input: str | list[Any] = query
while True:
result = await agent.run(current_input)
if not result.user_input_requests:
return result
next_input: list[Any] = [query]
rejected = False
for user_input_needed in result.user_input_requests:
if user_input_needed.function_call is None:
continue
print(
f"\nShell request: {user_input_needed.function_call.name}"
f"\nArguments: {user_input_needed.function_call.arguments}"
)
user_approval = await asyncio.to_thread(input, "\nApprove shell command? (y/n): ")
approved = user_approval.strip().lower() == "y"
next_input.append(Message("assistant", [user_input_needed]))
next_input.append(Message("user", [user_input_needed.to_function_approval_response(approved)]))
if not approved:
rejected = True
break
if rejected:
print("\nShell command rejected. Stopping without additional approval prompts.")
return "Shell command execution was rejected by user."
current_input = next_input
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,48 @@
# Azure Provider Samples
This folder contains Azure-backed samples for the generic OpenAI clients in
`agent_framework.openai`.
## Chat Completions API samples (`OpenAIChatCompletionClient`)
| File | Description |
|------|-------------|
| [`openai_chat_completion_client_basic.py`](openai_chat_completion_client_basic.py) | Basic Azure chat completions sample using explicit Azure settings and `credential=AzureCliCredential()`. |
| [`openai_chat_completion_client_with_explicit_settings.py`](openai_chat_completion_client_with_explicit_settings.py) | Azure chat completions sample with explicit settings. |
| [`openai_chat_completion_client_with_function_tools.py`](openai_chat_completion_client_with_function_tools.py) | Azure chat completions sample with function tools. |
| [`openai_chat_completion_client_with_session.py`](openai_chat_completion_client_with_session.py) | Azure chat completions sample with session management. |
## Responses API samples (`OpenAIChatClient`)
| File | Description |
|------|-------------|
| [`openai_client_basic.py`](openai_client_basic.py) | Basic Azure responses sample using explicit settings and `credential=AzureCliCredential()`. |
| [`openai_client_with_function_tools.py`](openai_client_with_function_tools.py) | Azure responses sample with function tools. |
| [`openai_client_with_session.py`](openai_client_with_session.py) | Azure responses sample with session management. |
| [`openai_client_with_structured_output.py`](openai_client_with_structured_output.py) | Azure responses sample with structured output. |
## Environment Variables
Set these before running the Azure provider samples:
- `AZURE_OPENAI_ENDPOINT`
- `AZURE_OPENAI_MODEL`
Optionally, you can also set:
- `AZURE_OPENAI_API_KEY`
- `AZURE_OPENAI_API_VERSION`
- `AZURE_OPENAI_BASE_URL`
These Azure samples are written around explicit Azure inputs such as
`credential=AzureCliCredential()`, so they stay on Azure even if `OPENAI_API_KEY` is also present.
## Optional Dependencies
Credential-based samples require `azure-identity`:
```bash
pip install azure-identity
```
Run `az login` before executing the credential-based samples.
@@ -0,0 +1,90 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from random import randint
from typing import Annotated
from agent_framework import Agent, tool
from agent_framework.openai import OpenAIChatCompletionClient
from azure.identity import AzureCliCredential
from dotenv import load_dotenv
from pydantic import Field
# Load environment variables from .env file
load_dotenv()
"""
Azure OpenAI Chat Client Basic Example
This sample demonstrates basic usage of OpenAIChatCompletionClient with explicit Azure
settings and a credential, showing both streaming and non-streaming responses.
"""
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production.
@tool(approval_mode="never_require")
def get_weather(
location: Annotated[str, Field(description="The location to get the weather for.")],
) -> str:
"""Get the weather for a given location."""
conditions = ["sunny", "cloudy", "rainy", "stormy"]
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C."
async def non_streaming_example() -> None:
"""Example of non-streaming response (get the complete result at once)."""
print("=== Non-streaming Response Example ===")
agent = Agent(
client=OpenAIChatCompletionClient(
model=os.getenv("AZURE_OPENAI_MODEL"),
azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT"),
api_version=os.getenv("AZURE_OPENAI_API_VERSION"),
credential=AzureCliCredential(),
),
name="WeatherAgent",
instructions="You are a helpful weather agent.",
tools=get_weather,
)
query = "What's the weather like in Seattle?"
print(f"User: {query}")
result = await agent.run(query)
print(f"Result: {result}\n")
async def streaming_example() -> None:
"""Example of streaming response (get results as they are generated)."""
print("=== Streaming Response Example ===")
agent = Agent(
client=OpenAIChatCompletionClient(
model=os.getenv("AZURE_OPENAI_MODEL"),
azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT"),
api_version=os.getenv("AZURE_OPENAI_API_VERSION"),
credential=AzureCliCredential(),
),
name="WeatherAgent",
instructions="You are a helpful weather agent.",
tools=get_weather,
)
query = "What's the weather like in Portland?"
print(f"User: {query}")
print("Agent: ", end="", flush=True)
async for chunk in agent.run(query, stream=True):
if chunk.text:
print(chunk.text, end="", flush=True)
print("\n")
async def main() -> None:
print("=== Basic Azure Chat Completion Client Agent Example ===")
await non_streaming_example()
await streaming_example()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,57 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from random import randint
from typing import Annotated
from agent_framework import Agent, tool
from agent_framework.openai import OpenAIChatCompletionClient
from azure.identity import AzureCliCredential
from dotenv import load_dotenv
from pydantic import Field
# Load environment variables from .env file
load_dotenv()
"""
OpenAI Chat Completion Client with Explicit Settings Example
This samples connects to Azure OpenAI.
This sample demonstrates creating OpenAI Chat Completion Client with explicit configuration
settings rather than relying on environment variable defaults.
"""
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production.
@tool(approval_mode="never_require")
def get_weather(
location: Annotated[str, Field(description="The location to get the weather for.")],
) -> str:
"""Get the weather for a given location."""
conditions = ["sunny", "cloudy", "rainy", "stormy"]
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C."
async def main() -> None:
print("=== Azure Chat Client with Explicit Settings ===")
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
agent = Agent(
client=OpenAIChatCompletionClient(
model=os.environ["AZURE_OPENAI_MODEL"],
azure_endpoint=os.environ["AZURE_OPENAI_ENDPOINT"],
credential=AzureCliCredential(),
),
instructions="You are a helpful weather agent.",
tools=[get_weather],
)
result = await agent.run("What's the weather like in New York?")
print(f"Result: {result}\n")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,143 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from datetime import datetime, timezone
from random import randint
from typing import Annotated
from agent_framework import Agent, tool
from agent_framework.openai import OpenAIChatCompletionClient
from azure.identity import AzureCliCredential
from dotenv import load_dotenv
from pydantic import Field
# Load environment variables from .env file
load_dotenv()
"""
Azure OpenAI Chat Client with Function Tools Example
This sample demonstrates function tool integration with Azure OpenAI Chat Client,
showing both agent-level and query-level tool configuration patterns.
"""
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production;
# see samples/02-agents/tools/function_tool_with_approval.py
# and samples/02-agents/tools/function_tool_with_approval_and_sessions.py.
@tool(approval_mode="never_require")
def get_weather(
location: Annotated[str, Field(description="The location to get the weather for.")],
) -> str:
"""Get the weather for a given location."""
conditions = ["sunny", "cloudy", "rainy", "stormy"]
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C."
@tool(approval_mode="never_require")
def get_time() -> str:
"""Get the current UTC time."""
current_time = datetime.now(timezone.utc)
return f"The current UTC time is {current_time.strftime('%Y-%m-%d %H:%M:%S')}."
async def tools_on_agent_level() -> None:
"""Example showing tools defined when creating the agent."""
print("=== Tools Defined on Agent Level ===")
# Tools are provided when creating the agent
# The agent can use these tools for any query during its lifetime
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
agent = Agent(
client=OpenAIChatCompletionClient(credential=AzureCliCredential()),
instructions="You are a helpful assistant that can provide weather and time information.",
tools=[get_weather, get_time], # Tools defined at agent creation
)
# First query - agent can use weather tool
query1 = "What's the weather like in New York?"
print(f"User: {query1}")
result1 = await agent.run(query1)
print(f"Agent: {result1}\n")
# Second query - agent can use time tool
query2 = "What's the current UTC time?"
print(f"User: {query2}")
result2 = await agent.run(query2)
print(f"Agent: {result2}\n")
# Third query - agent can use both tools if needed
query3 = "What's the weather in London and what's the current UTC time?"
print(f"User: {query3}")
result3 = await agent.run(query3)
print(f"Agent: {result3}\n")
async def tools_on_run_level() -> None:
"""Example showing tools passed to the run method."""
print("=== Tools Passed to Run Method ===")
# Agent created without tools
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
agent = Agent(
client=OpenAIChatCompletionClient(credential=AzureCliCredential()),
instructions="You are a helpful assistant.",
# No tools defined here
)
# First query with weather tool
query1 = "What's the weather like in Seattle?"
print(f"User: {query1}")
result1 = await agent.run(query1, tools=[get_weather]) # Tool passed to run method
print(f"Agent: {result1}\n")
# Second query with time tool
query2 = "What's the current UTC time?"
print(f"User: {query2}")
result2 = await agent.run(query2, tools=[get_time]) # Different tool for this query
print(f"Agent: {result2}\n")
# Third query with multiple tools
query3 = "What's the weather in Chicago and what's the current UTC time?"
print(f"User: {query3}")
result3 = await agent.run(query3, tools=[get_weather, get_time]) # Multiple tools
print(f"Agent: {result3}\n")
async def mixed_tools_example() -> None:
"""Example showing both agent-level tools and run-method tools."""
print("=== Mixed Tools Example (Agent + Run Method) ===")
# Agent created with some base tools
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
agent = Agent(
client=OpenAIChatCompletionClient(credential=AzureCliCredential()),
instructions="You are a comprehensive assistant that can help with various information requests.",
tools=[get_weather], # Base tool available for all queries
)
# Query using both agent tool and additional run-method tools
query = "What's the weather in Denver and what's the current UTC time?"
print(f"User: {query}")
# Agent has access to get_weather (from creation) + additional tools from run method
result = await agent.run(
query,
tools=[get_time], # Additional tools for this specific query
)
print(f"Agent: {result}\n")
async def main() -> None:
print("=== Azure Chat Client Agent with Function Tools Examples ===\n")
await tools_on_agent_level()
await tools_on_run_level()
await mixed_tools_example()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,161 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from random import randint
from typing import Annotated
from agent_framework import Agent, AgentSession, InMemoryHistoryProvider, tool
from agent_framework.openai import OpenAIChatCompletionClient
from azure.identity import AzureCliCredential
from dotenv import load_dotenv
from pydantic import Field
# Load environment variables from .env file
load_dotenv()
"""
Azure OpenAI Chat Client with Session Management Example
This sample demonstrates session management with Azure OpenAI Chat Client, comparing
automatic session creation with explicit session management for persistent context.
"""
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production;
# see samples/02-agents/tools/function_tool_with_approval.py
# and samples/02-agents/tools/function_tool_with_approval_and_sessions.py.
@tool(approval_mode="never_require")
def get_weather(
location: Annotated[str, Field(description="The location to get the weather for.")],
) -> str:
"""Get the weather for a given location."""
conditions = ["sunny", "cloudy", "rainy", "stormy"]
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C."
async def example_with_automatic_session_creation() -> None:
"""Example showing automatic session creation (service-managed session)."""
print("=== Automatic Session Creation Example ===")
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
agent = Agent(
client=OpenAIChatCompletionClient(credential=AzureCliCredential()),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
# First conversation - no session provided, will be created automatically
query1 = "What's the weather like in Seattle?"
print(f"User: {query1}")
result1 = await agent.run(query1)
print(f"Agent: {result1.text}")
# Second conversation - still no session provided, will create another new session
query2 = "What was the last city I asked about?"
print(f"\nUser: {query2}")
result2 = await agent.run(query2)
print(f"Agent: {result2.text}")
print("Note: Each call creates a separate session, so the agent doesn't remember previous context.\n")
async def example_with_session_persistence() -> None:
"""Example showing session persistence across multiple conversations."""
print("=== Session Persistence Example ===")
print("Using the same session across multiple conversations to maintain context.\n")
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
agent = Agent(
client=OpenAIChatCompletionClient(credential=AzureCliCredential()),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
# Create a new session that will be reused
session = agent.create_session()
# First conversation
query1 = "What's the weather like in Tokyo?"
print(f"User: {query1}")
result1 = await agent.run(query1, session=session)
print(f"Agent: {result1.text}")
# Second conversation using the same session - maintains context
query2 = "How about London?"
print(f"\nUser: {query2}")
result2 = await agent.run(query2, session=session)
print(f"Agent: {result2.text}")
# Third conversation - agent should remember both previous cities
query3 = "Which of the cities I asked about has better weather?"
print(f"\nUser: {query3}")
result3 = await agent.run(query3, session=session)
print(f"Agent: {result3.text}")
print("Note: The agent remembers context from previous messages in the same session.\n")
async def example_with_existing_session_messages() -> None:
"""Example showing how to work with existing session messages for Azure."""
print("=== Existing Session Messages Example ===")
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
agent = Agent(
client=OpenAIChatCompletionClient(credential=AzureCliCredential()),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
# Start a conversation and build up message history
session = agent.create_session()
query1 = "What's the weather in Paris?"
print(f"User: {query1}")
result1 = await agent.run(query1, session=session)
print(f"Agent: {result1.text}")
# The session now contains the conversation history in state
memory_state = session.state.get(InMemoryHistoryProvider.DEFAULT_SOURCE_ID, {})
messages = memory_state.get("messages", [])
if messages:
print(f"Session contains {len(messages)} messages")
print("\n--- Continuing with the same session in a new agent instance ---")
# Create a new agent instance but use the existing session with its message history
new_agent = Agent(
client=OpenAIChatCompletionClient(credential=AzureCliCredential()),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
# Use the same session object which contains the conversation history
query2 = "What was the last city I asked about?"
print(f"User: {query2}")
result2 = await new_agent.run(query2, session=session)
print(f"Agent: {result2.text}")
print("Note: The agent continues the conversation using the local message history.\n")
print("\n--- Alternative: Creating a new session from existing messages ---")
# You can also create a new session from existing messages
new_session = AgentSession()
query3 = "How does the Paris weather compare to London?"
print(f"User: {query3}")
result3 = await new_agent.run(query3, session=new_session)
print(f"Agent: {result3.text}")
print("Note: This creates a new session with the same conversation history.\n")
async def main() -> None:
print("=== Azure Chat Client Agent Session Management Examples ===\n")
await example_with_automatic_session_creation()
await example_with_session_persistence()
await example_with_existing_session_messages()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,90 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from random import randint
from typing import Annotated
from agent_framework import Agent, tool
from agent_framework.openai import OpenAIChatClient
from azure.identity import AzureCliCredential
from dotenv import load_dotenv
from pydantic import Field
# Load environment variables from .env file
load_dotenv()
"""
Azure OpenAI Chat Client Basic Example
This sample demonstrates basic usage of OpenAIChatClient with explicit Azure
settings and a credential, showing both streaming and non-streaming responses.
"""
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production.
@tool(approval_mode="never_require")
def get_weather(
location: Annotated[str, Field(description="The location to get the weather for.")],
) -> str:
"""Get the weather for a given location."""
conditions = ["sunny", "cloudy", "rainy", "stormy"]
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C."
async def non_streaming_example() -> None:
"""Example of non-streaming response (get the complete result at once)."""
print("=== Non-streaming Response Example ===")
agent = Agent(
client=OpenAIChatClient(
model=os.getenv("AZURE_OPENAI_MODEL"),
azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT"),
api_version=os.getenv("AZURE_OPENAI_API_VERSION"),
credential=AzureCliCredential(),
),
name="WeatherAgent",
instructions="You are a helpful weather agent.",
tools=get_weather,
)
query = "What's the weather in Seattle?"
print(f"User: {query}")
result = await agent.run(query)
print(f"Result: {result}\n")
async def streaming_example() -> None:
"""Example of streaming response (get results as they are generated)."""
print("=== Streaming Response Example ===")
agent = Agent(
client=OpenAIChatClient(
model=os.getenv("AZURE_OPENAI_MODEL"),
azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT"),
api_version=os.getenv("AZURE_OPENAI_API_VERSION"),
credential=AzureCliCredential(),
),
name="WeatherAgent",
instructions="You are a helpful weather agent.",
tools=get_weather,
)
query = "What's the weather in Portland?"
print(f"User: {query}")
print("Agent: ", end="", flush=True)
async for chunk in agent.run(query, stream=True):
if chunk.text:
print(chunk.text, end="", flush=True)
print("\n")
async def main() -> None:
print("=== Basic Azure OpenAI Chat Client Agent Example ===")
await non_streaming_example()
await streaming_example()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,137 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from datetime import datetime, timezone
from random import randint
from typing import Annotated
from agent_framework import Agent, tool
from agent_framework.openai import OpenAIChatClient
from azure.identity import AzureCliCredential
from dotenv import load_dotenv
from pydantic import Field
# Load environment variables from .env file
load_dotenv()
"""
Azure OpenAI Chat Client with Function Tools Example
This sample demonstrates function tool integration with Azure OpenAI Chat Client,
showing both agent-level and query-level tool configuration patterns.
"""
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production;
# see samples/02-agents/tools/function_tool_with_approval.py
# and samples/02-agents/tools/function_tool_with_approval_and_sessions.py.
@tool(approval_mode="never_require")
def get_weather(
location: Annotated[str, Field(description="The location to get the weather for.")],
) -> str:
"""Get the weather for a given location."""
conditions = ["sunny", "cloudy", "rainy", "stormy"]
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C."
@tool(approval_mode="never_require")
def get_time() -> str:
"""Get the current UTC time."""
current_time = datetime.now(timezone.utc)
return f"The current UTC time is {current_time.strftime('%Y-%m-%d %H:%M:%S')}."
async def tools_on_agent_level() -> None:
"""Example showing tools defined when creating the agent."""
print("=== Tools Defined on Agent Level ===")
# Tools are provided when creating the agent
# The agent can use these tools for any query during its lifetime
agent = Agent(
client=OpenAIChatClient(credential=AzureCliCredential()),
instructions="You are a helpful assistant that can provide weather and time information.",
tools=[get_weather, get_time], # Tools defined at agent creation
)
# First query - agent can use weather tool
query1 = "What's the weather like in New York?"
print(f"User: {query1}")
result1 = await agent.run(query1)
print(f"Agent: {result1}\n")
# Second query - agent can use time tool
query2 = "What's the current UTC time?"
print(f"User: {query2}")
result2 = await agent.run(query2)
print(f"Agent: {result2}\n")
# Third query - agent can use both tools if needed
query3 = "What's the weather in London and what's the current UTC time?"
print(f"User: {query3}")
result3 = await agent.run(query3)
print(f"Agent: {result3}\n")
async def tools_on_run_level() -> None:
"""Example showing tools passed to the run method."""
print("=== Tools Passed to Run Method ===")
# Agent created without tools
agent = Agent(
client=OpenAIChatClient(credential=AzureCliCredential()),
instructions="You are a helpful assistant.",
# No tools defined here
)
# First query with weather tool
query1 = "What's the weather like in Seattle?"
print(f"User: {query1}")
result1 = await agent.run(query1, tools=[get_weather]) # Tool passed to run method
print(f"Agent: {result1}\n")
# Second query with time tool
query2 = "What's the current UTC time?"
print(f"User: {query2}")
result2 = await agent.run(query2, tools=[get_time]) # Different tool for this query
print(f"Agent: {result2}\n")
# Third query with multiple tools
query3 = "What's the weather in Chicago and what's the current UTC time?"
print(f"User: {query3}")
result3 = await agent.run(query3, tools=[get_weather, get_time]) # Multiple tools
print(f"Agent: {result3}\n")
async def mixed_tools_example() -> None:
"""Example showing both agent-level tools and run-method tools."""
print("=== Mixed Tools Example (Agent + Run Method) ===")
# Agent created with some base tools
agent = Agent(
client=OpenAIChatClient(credential=AzureCliCredential()),
instructions="You are a comprehensive assistant that can help with various information requests.",
tools=[get_weather], # Base tool available for all queries
)
# Query using both agent tool and additional run-method tools
query = "What's the weather in Denver and what's the current UTC time?"
print(f"User: {query}")
# Agent has access to get_weather (from creation) + additional tools from run method
result = await agent.run(
query,
tools=[get_time], # Additional tools for this specific query
)
print(f"Agent: {result}\n")
async def main() -> None:
print("=== Azure OpenAI Chat Client Agent with Function Tools Examples ===\n")
await tools_on_agent_level()
await tools_on_run_level()
await mixed_tools_example()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,152 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from random import randint
from typing import Annotated
from agent_framework import Agent, AgentSession, tool
from agent_framework.openai import OpenAIChatClient
from azure.identity import AzureCliCredential
from dotenv import load_dotenv
from pydantic import Field
# Load environment variables from .env file
load_dotenv()
"""
Azure OpenAI Chat Client with Session Management Example
This sample demonstrates session management with Azure OpenAI Chat Client, showing
persistent conversation context and simplified response handling.
"""
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production;
# see samples/02-agents/tools/function_tool_with_approval.py
# and samples/02-agents/tools/function_tool_with_approval_and_sessions.py.
@tool(approval_mode="never_require")
def get_weather(
location: Annotated[str, Field(description="The location to get the weather for.")],
) -> str:
"""Get the weather for a given location."""
conditions = ["sunny", "cloudy", "rainy", "stormy"]
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C."
async def example_with_automatic_session_creation() -> None:
"""Example showing automatic session creation."""
print("=== Automatic Session Creation Example ===")
agent = Agent(
client=OpenAIChatClient(credential=AzureCliCredential()),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
# First conversation - no session provided, will be created automatically
query1 = "What's the weather like in Seattle?"
print(f"User: {query1}")
result1 = await agent.run(query1)
print(f"Agent: {result1.text}")
# Second conversation - still no session provided, will create another new session
query2 = "What was the last city I asked about?"
print(f"\nUser: {query2}")
result2 = await agent.run(query2)
print(f"Agent: {result2.text}")
print("Note: Each call creates a separate session, so the agent doesn't remember previous context.\n")
async def example_with_session_persistence_in_memory() -> None:
"""
Example showing session persistence across multiple conversations.
In this example, messages are stored in-memory.
"""
print("=== Session Persistence Example (In-Memory) ===")
agent = Agent(
client=OpenAIChatClient(credential=AzureCliCredential()),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
# Create a new session that will be reused
session = agent.create_session()
# First conversation
query1 = "What's the weather like in Tokyo?"
print(f"User: {query1}")
result1 = await agent.run(query1, session=session, options={"store": False})
print(f"Agent: {result1.text}")
# Second conversation using the same session - maintains context
query2 = "How about London?"
print(f"\nUser: {query2}")
result2 = await agent.run(query2, session=session, options={"store": False})
print(f"Agent: {result2.text}")
# Third conversation - agent should remember both previous cities
query3 = "Which of the cities I asked about has better weather?"
print(f"\nUser: {query3}")
result3 = await agent.run(query3, session=session, options={"store": False})
print(f"Agent: {result3.text}")
print("Note: The agent remembers context from previous messages in the same session.\n")
async def example_with_existing_session_id() -> None:
"""
Example showing how to work with an existing session ID from the service.
In this example, messages are stored on the server using OpenAI conversation state.
"""
print("=== Existing Session ID Example ===")
# First, create a conversation and capture the session ID
existing_session_id = None
agent = Agent(
client=OpenAIChatClient(credential=AzureCliCredential()),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
# Start a conversation and get the session ID
session = agent.create_session()
query1 = "What's the weather in Paris?"
print(f"User: {query1}")
result1 = await agent.run(query1, session=session, options={"store": False})
print(f"Agent: {result1.text}")
# The session ID is set after the first response
existing_session_id = session.service_session_id
print(f"Session ID: {existing_session_id}")
if existing_session_id:
print("\n--- Continuing with the same session ID in a new agent instance ---")
agent = Agent(
client=OpenAIChatClient(credential=AzureCliCredential()),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
# Create a session with the existing ID
session = AgentSession(service_session_id=existing_session_id)
query2 = "What was the last city I asked about?"
print(f"User: {query2}")
result2 = await agent.run(query2, session=session)
print(f"Agent: {result2.text}")
print("Note: The agent continues the conversation from the previous session by using session ID.\n")
async def main() -> None:
print("=== Azure OpenAI Chat Client Session Management Examples ===\n")
await example_with_automatic_session_creation()
await example_with_session_persistence_in_memory()
await example_with_existing_session_id()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,93 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from agent_framework import Agent, AgentResponse
from agent_framework.openai import OpenAIChatClient
from azure.identity import AzureCliCredential
from dotenv import load_dotenv
from pydantic import BaseModel
# Load environment variables from .env file
load_dotenv()
"""
Azure OpenAI Chat Client with Structured Output Example
This sample demonstrates using structured output capabilities with Azure OpenAI Chat Client,
showing Pydantic model integration for type-safe response parsing and data extraction.
"""
class OutputStruct(BaseModel):
"""A structured output for testing purposes."""
city: str
description: str
async def non_streaming_example() -> None:
print("=== Non-streaming example ===")
# Create an Azure OpenAI Chat agent
agent = Agent(
client=OpenAIChatClient(credential=AzureCliCredential()),
name="CityAgent",
instructions="You are a helpful agent that describes cities in a structured format.",
)
# Ask the agent about a city
query = "Tell me about Paris, France"
print(f"User: {query}")
# Get structured response from the agent using response_format parameter
result = await agent.run(query, options={"response_format": OutputStruct})
# Access the structured output using the parsed value
if structured_data := result.value:
print("Structured Output Agent:")
print(f"City: {structured_data.city}")
print(f"Description: {structured_data.description}")
else:
print(f"Failed to parse response: {result.text}")
async def streaming_example() -> None:
print("=== Streaming example ===")
# Create an Azure OpenAI Chat agent
agent = Agent(
client=OpenAIChatClient(credential=AzureCliCredential()),
name="CityAgent",
instructions="You are a helpful agent that describes cities in a structured format.",
)
# Ask the agent about a city
query = "Tell me about Tokyo, Japan"
print(f"User: {query}")
# Get structured response from streaming agent using AgentResponse.from_update_generator
# This method collects all streaming updates and combines them into a single AgentResponse
result = await AgentResponse.from_update_generator(
agent.run(query, stream=True, options={"response_format": OutputStruct}),
output_format_type=OutputStruct,
)
# Access the structured output using the parsed value
if structured_data := result.value:
print("Structured Output (from streaming with AgentResponse.from_update_generator):")
print(f"City: {structured_data.city}")
print(f"Description: {structured_data.description}")
else:
print(f"Failed to parse response: {result.text}")
async def main() -> None:
print("=== Azure OpenAI Chat Client Agent with Structured Output ===")
await non_streaming_example()
await streaming_example()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,105 @@
# Copilot Studio Agent Examples
This folder contains examples demonstrating how to create and use agents with Microsoft Copilot Studio using the Agent Framework.
## Prerequisites
Before running these examples, you need:
1. **Copilot Studio Environment**: Access to a Microsoft Copilot Studio environment with a published copilot
2. **App Registration**: An Azure AD App Registration with appropriate permissions
3. **Environment Variables**: Set the following environment variables:
- `COPILOTSTUDIOAGENT__ENVIRONMENTID` - Your Copilot Studio environment ID
- `COPILOTSTUDIOAGENT__SCHEMANAME` - Your copilot's agent identifier/schema name
- `COPILOTSTUDIOAGENT__AGENTAPPID` - Your App Registration client ID
- `COPILOTSTUDIOAGENT__TENANTID` - Your Azure AD tenant ID
## Examples
| Example | Description |
|---------|-------------|
| **[`copilotstudio_basic.py`](copilotstudio_basic.py)** | Basic non-streaming and streaming execution with simple questions |
| **[`copilotstudio_with_explicit_settings.py`](copilotstudio_with_explicit_settings.py)** | Example with explicit settings and manual token acquisition |
## Authentication
The examples use MSAL (Microsoft Authentication Library) for authentication. The first time you run an example, you may need to complete an interactive authentication flow in your browser.
### App Registration Setup
Your Azure AD App Registration should have:
1. **API Permissions**:
- Power Platform API permissions (https://api.powerplatform.com/.default)
- Appropriate delegated permissions for your organization
2. **Redirect URIs**:
- For public client flows: `http://localhost`
- Configure as appropriate for your authentication method
3. **Authentication**:
- Enable "Allow public client flows" if using interactive authentication
## Usage Patterns
### Basic Usage with Environment Variables
```python
import asyncio
from agent_framework.microsoft import CopilotStudioAgent
# Uses environment variables for configuration
async def main():
# Create agent using environment variables
agent = CopilotStudioAgent()
# Run a simple query
result = await agent.run("What is the capital of France?")
print(result)
asyncio.run(main())
```
### Explicit Configuration
```python
from agent_framework.microsoft import CopilotStudioAgent, acquire_token
from microsoft_agents.copilotstudio.client import ConnectionSettings, CopilotClient, PowerPlatformCloud, AgentType
# Acquire token manually
token = acquire_token(
client_id="your-client-id",
tenant_id="your-tenant-id"
)
# Create settings and client
settings = ConnectionSettings(
environment_id="your-environment-id",
agent_identifier="your-agent-schema-name",
cloud=PowerPlatformCloud.PROD,
copilot_agent_type=AgentType.PUBLISHED,
custom_power_platform_cloud=None
)
client = CopilotClient(settings=settings, token=token)
agent = CopilotStudioAgent(client=client)
```
## Troubleshooting
### Common Issues
1. **Authentication Errors**:
- Verify your App Registration has correct permissions
- Ensure environment variables are set correctly
- Check that your tenant ID and client ID are valid
2. **Environment/Agent Not Found**:
- Verify your environment ID is correct
- Ensure your copilot is published and the schema name is correct
- Check that you have access to the specified environment
3. **Token Acquisition Failures**:
- Interactive authentication may require browser access
- Corporate firewalls may block authentication flows
- Try running with appropriate proxy settings if needed
@@ -0,0 +1,59 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from agent_framework.microsoft import CopilotStudioAgent
from dotenv import load_dotenv
"""
Copilot Studio Agent Basic Example
This sample demonstrates basic usage of CopilotStudioAgent with automatic configuration
from environment variables, showing both streaming and non-streaming responses.
"""
# Environment variables needed:
# COPILOTSTUDIOAGENT__ENVIRONMENTID - Environment ID where your copilot is deployed
# COPILOTSTUDIOAGENT__SCHEMANAME - Agent identifier/schema name of your copilot
# COPILOTSTUDIOAGENT__AGENTAPPID - Client ID for authentication
# COPILOTSTUDIOAGENT__TENANTID - Tenant ID for authentication
# Load environment variables from .env file
load_dotenv()
async def non_streaming_example() -> None:
"""Example of non-streaming response (get the complete result at once)."""
print("=== Non-streaming Response Example ===")
agent = CopilotStudioAgent()
query = "What is the capital of France?"
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result}\n")
async def streaming_example() -> None:
"""Example of streaming response (get results as they are generated)."""
print("=== Streaming Response Example ===")
agent = CopilotStudioAgent()
query = "What is the capital of Spain?"
print(f"User: {query}")
print("Agent: ", end="", flush=True)
async for chunk in agent.run(query, stream=True):
if chunk.text:
print(chunk.text, end="", flush=True)
print("\n")
async def main() -> None:
await non_streaming_example()
await streaming_example()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,109 @@
# /// script
# requires-python = ">=3.10"
# dependencies = [
# "agent-framework-copilotstudio",
# "microsoft-agents",
# ]
# ///
# Run with any PEP 723 compatible runner, e.g.:
# uv run samples/02-agents/providers/copilotstudio/copilotstudio_with_explicit_settings.py
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from agent_framework.microsoft import CopilotStudioAgent, acquire_token
from dotenv import load_dotenv
from microsoft_agents.copilotstudio.client import AgentType, ConnectionSettings, CopilotClient, PowerPlatformCloud
"""
Copilot Studio Agent with Explicit Settings Example
This sample demonstrates explicit configuration of CopilotStudioAgent with manual
token management and custom ConnectionSettings for production environments.
"""
# Environment variables needed:
# COPILOTSTUDIOAGENT__ENVIRONMENTID - Environment ID where your copilot is deployed
# COPILOTSTUDIOAGENT__SCHEMANAME - Agent identifier/schema name of your copilot
# COPILOTSTUDIOAGENT__AGENTAPPID - Client ID for authentication
# COPILOTSTUDIOAGENT__TENANTID - Tenant ID for authentication
# Load environment variables from .env file
load_dotenv()
async def example_with_connection_settings() -> None:
"""Example using explicit ConnectionSettings and CopilotClient."""
print("=== Copilot Studio Agent with Connection Settings ===")
# Configuration from environment variables
environment_id = os.environ["COPILOTSTUDIOAGENT__ENVIRONMENTID"]
agent_identifier = os.environ["COPILOTSTUDIOAGENT__SCHEMANAME"]
client_id = os.environ["COPILOTSTUDIOAGENT__AGENTAPPID"]
tenant_id = os.environ["COPILOTSTUDIOAGENT__TENANTID"]
# Acquire token using the acquire_token function
token = acquire_token(
client_id=client_id,
tenant_id=tenant_id,
)
# Create connection settings
settings = ConnectionSettings(
environment_id=environment_id,
agent_identifier=agent_identifier,
cloud=PowerPlatformCloud.PROD, # Or PowerPlatformCloud.GOV, PowerPlatformCloud.HIGH, etc.
copilot_agent_type=AgentType.PUBLISHED, # Or AgentType.PREBUILT
custom_power_platform_cloud=None, # Optional: for custom cloud endpoints
)
# Create CopilotClient with explicit settings
client = CopilotClient(settings=settings, token=token)
# Create agent with explicit client
agent = CopilotStudioAgent(client=client)
# Run a simple query
query = "What is the capital of Italy?"
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result}")
async def example_with_explicit_parameters() -> None:
"""Example using CopilotStudioAgent with all parameters explicitly provided."""
print("\n=== Copilot Studio Agent with All Explicit Parameters ===")
# Configuration from environment variables
environment_id = os.environ["COPILOTSTUDIOAGENT__ENVIRONMENTID"]
agent_identifier = os.environ["COPILOTSTUDIOAGENT__SCHEMANAME"]
client_id = os.environ["COPILOTSTUDIOAGENT__AGENTAPPID"]
tenant_id = os.environ["COPILOTSTUDIOAGENT__TENANTID"]
# Create agent with all parameters explicitly
agent = CopilotStudioAgent(
environment_id=environment_id,
agent_identifier=agent_identifier,
client_id=client_id,
tenant_id=tenant_id,
cloud=PowerPlatformCloud.PROD,
agent_type=AgentType.PUBLISHED,
)
# Run a simple query
query = "What is the capital of Japan?"
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result}")
async def main() -> None:
await example_with_connection_settings()
await example_with_explicit_parameters()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,69 @@
# Custom Agent and Chat Client Examples
This folder contains examples demonstrating how to implement custom agents and chat clients using the Microsoft Agent Framework.
## Examples
| File | Description |
|------|-------------|
| [`custom_agent.py`](custom_agent.py) | Shows how to create custom agents by extending the `BaseAgent` class. Demonstrates the `EchoAgent` implementation with both streaming and non-streaming responses, proper session management, and message history handling. |
| [`custom_chat_client.py`](../../chat_client/custom_chat_client.py) | Demonstrates how to create custom chat clients by extending the `BaseChatClient` class. Shows a `EchoingChatClient` implementation and how to integrate it with `Agent` using the `as_agent()` method. |
## Key Takeaways
### Custom Agents
- Custom agents give you complete control over the agent's behavior
- You must implement both `run()` for both the `stream=True` and `stream=False` cases
- Use `self._normalize_messages()` to handle different input message formats
- Store messages in `session.state` to properly manage conversation history
### Custom Chat Clients
- Custom chat clients allow you to integrate any backend service or create new LLM providers
- You must implement `_inner_get_response()` with a stream parameter to handle both streaming and non-streaming responses
- Custom chat clients can be used with `Agent` to leverage all agent framework features
- Use the `as_agent()` method to easily create agents from your custom chat clients
Both approaches allow you to extend the framework for your specific use cases while maintaining compatibility with the broader Agent Framework ecosystem.
## Understanding Raw Client Classes
The framework provides `Raw...Client` classes (e.g., `RawOpenAIChatClient`, `RawOpenAIChatCompletionClient`, `RawFoundryChatClient`) that are intermediate implementations without middleware, telemetry, or function invocation support.
### Warning: Raw Clients Should Not Normally Be Used Directly
**The `Raw...Client` classes should not normally be used directly.** They do not include the middleware, telemetry, or function invocation support that you most likely need. If you do use them, you should carefully consider which additional layers to apply.
### Layer Ordering
There is a defined ordering for applying layers that you should follow:
1. **FunctionInvocationLayer** - Handles the tool/function calling loop and should stay outermost
2. **ChatMiddlewareLayer** - Wraps each model call in the loop and stays outside telemetry
3. **ChatTelemetryLayer** - Must be inside the function calling loop so each model call gets its own telemetry span
4. **Raw...Client** - The base implementation (e.g., `RawOpenAIChatClient`)
Example of correct layer composition:
```python
class MyCustomClient(
FunctionInvocationLayer[TOptions],
ChatMiddlewareLayer[TOptions],
ChatTelemetryLayer[TOptions],
RawOpenAIChatClient[TOptions], # or BaseChatClient for custom implementations
Generic[TOptions],
):
"""Custom client with all layers correctly applied."""
pass
```
### Use Fully-Featured Clients Instead
For most use cases, use the fully-featured public client classes which already have all layers correctly composed:
- `OpenAIChatCompletionClient` - OpenAI Chat Completions API with all layers
- `OpenAIChatClient` - OpenAI Responses API with all layers
- `OpenAIChatCompletionClient` - Azure OpenAI Chat Completions with all layers
- `OpenAIChatClient` - Azure OpenAI Responses with all layers
- `FoundryChatClient` - Azure AI Foundry project-backed chat with all layers
These clients handle the layer composition correctly and provide the full feature set out of the box.
@@ -0,0 +1,235 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from collections.abc import AsyncIterable, Awaitable
from typing import Any, Literal, overload
from agent_framework import (
AgentResponse,
AgentResponseUpdate,
AgentSession,
BaseAgent,
Content,
InMemoryHistoryProvider,
Message,
normalize_messages,
)
"""
Custom Agent Implementation Example
This sample demonstrates implementing a custom agent by extending BaseAgent class,
showing the minimal requirements for both streaming and non-streaming responses.
"""
class EchoAgent(BaseAgent):
"""A simple custom agent that echoes user messages with a prefix.
This demonstrates how to create a fully custom agent by extending BaseAgent
and implementing the required run() method with stream support.
"""
echo_prefix: str = "Echo: "
def __init__(
self,
*,
name: str | None = None,
description: str | None = None,
echo_prefix: str = "Echo: ",
**kwargs: Any,
) -> None:
"""Initialize the EchoAgent.
Args:
name: The name of the agent.
description: The description of the agent.
echo_prefix: The prefix to add to echoed messages.
**kwargs: Additional keyword arguments passed to BaseAgent.
"""
super().__init__(
name=name,
description=description,
**kwargs,
)
self.echo_prefix = echo_prefix
@overload
def run(
self,
messages: str | Message | list[str] | list[Message] | None = None,
*,
stream: Literal[False] = False,
session: AgentSession | None = None,
**kwargs: Any,
) -> asyncio.Future[AgentResponse]: ...
@overload
def run(
self,
messages: str | Message | list[str] | list[Message] | None = None,
*,
stream: Literal[True],
session: AgentSession | None = None,
**kwargs: Any,
) -> AsyncIterable[AgentResponseUpdate]: ...
def run(
self,
messages: str | Message | list[str] | list[Message] | None = None,
*,
stream: bool = False,
session: AgentSession | None = None,
**kwargs: Any,
) -> "AsyncIterable[AgentResponseUpdate] | Awaitable[AgentResponse]":
"""Execute the agent and return a response.
Args:
messages: The message(s) to process.
stream: If True, return an async iterable of updates. If False, return an awaitable response.
session: The conversation session (optional).
**kwargs: Additional keyword arguments.
Returns:
When stream=False: An awaitable AgentResponse containing the agent's reply.
When stream=True: An async iterable of AgentResponseUpdate objects.
"""
if stream:
return self._run_stream(messages=messages, session=session, **kwargs)
return self._run(messages=messages, session=session, **kwargs)
async def _run(
self,
messages: str | Message | list[str] | list[Message] | None = None,
*,
session: AgentSession | None = None,
**kwargs: Any,
) -> AgentResponse:
"""Non-streaming implementation."""
# Normalize input messages to a list
normalized_messages = normalize_messages(messages)
if not normalized_messages:
response_message = Message(
role="assistant",
contents=[
Content.from_text(text="Hello! I'm a custom echo agent. Send me a message and I'll echo it back.")
],
)
else:
# For simplicity, echo the last user message
last_message = normalized_messages[-1]
if last_message.text:
echo_text = f"{self.echo_prefix}{last_message.text}"
else:
echo_text = f"{self.echo_prefix}[Non-text message received]"
response_message = Message(role="assistant", contents=[Content.from_text(text=echo_text)])
# Store messages in session state if provided
if session is not None:
stored = session.state.setdefault(InMemoryHistoryProvider.DEFAULT_SOURCE_ID, {}).setdefault("messages", [])
stored.extend(normalized_messages)
stored.append(response_message)
return AgentResponse(messages=[response_message])
async def _run_stream(
self,
messages: str | Message | list[str] | list[Message] | None = None,
*,
session: AgentSession | None = None,
**kwargs: Any,
) -> AsyncIterable[AgentResponseUpdate]:
"""Streaming implementation."""
# Normalize input messages to a list
normalized_messages = normalize_messages(messages)
if not normalized_messages:
response_text = "Hello! I'm a custom echo agent. Send me a message and I'll echo it back."
else:
# For simplicity, echo the last user message
last_message = normalized_messages[-1]
if last_message.text:
response_text = f"{self.echo_prefix}{last_message.text}"
else:
response_text = f"{self.echo_prefix}[Non-text message received]"
# Simulate streaming by yielding the response word by word
words = response_text.split()
for i, word in enumerate(words):
# Add space before word except for the first one
chunk_text = f" {word}" if i > 0 else word
yield AgentResponseUpdate(
contents=[Content.from_text(text=chunk_text)],
role="assistant",
)
# Small delay to simulate streaming
await asyncio.sleep(0.1)
# Store messages in session state if provided
if session is not None:
complete_response = Message(role="assistant", contents=[Content.from_text(text=response_text)])
stored = session.state.setdefault(InMemoryHistoryProvider.DEFAULT_SOURCE_ID, {}).setdefault("messages", [])
stored.extend(normalized_messages)
stored.append(complete_response)
async def main() -> None:
"""Demonstrates how to use the custom EchoAgent."""
print("=== Custom Agent Example ===\n")
# Create EchoAgent
print("--- EchoAgent Example ---")
echo_agent = EchoAgent(
name="EchoBot", description="A simple agent that echoes messages with a prefix", echo_prefix="🔊 Echo: "
)
# Test non-streaming
print(f"Agent Name: {echo_agent.name}")
print(f"Agent ID: {echo_agent.id}")
query = "Hello, custom agent!"
print(f"\nUser: {query}")
result = await echo_agent.run(query)
print(f"Agent: {result.messages[0].text}")
# Test streaming
query2 = "This is a streaming test"
print(f"\nUser: {query2}")
print("Agent: ", end="", flush=True)
stream = echo_agent.run(query2, stream=True)
assert isinstance(stream, AsyncIterable)
async for chunk in stream:
if chunk.text:
print(chunk.text, end="", flush=True)
print()
# Example with sessions
print("\n--- Using Custom Agent with Session ---")
session = echo_agent.create_session()
# First message
result1 = await echo_agent.run("First message", session=session)
print("User: First message")
print(f"Agent: {result1.messages[0].text}")
# Second message in same thread
result2 = await echo_agent.run("Second message", session=session)
print("User: Second message")
print(f"Agent: {result2.messages[0].text}")
# Check conversation history
memory_state = session.state.get(InMemoryHistoryProvider.DEFAULT_SOURCE_ID, {})
messages = memory_state.get("messages", [])
if messages:
print(f"\nSession contains {len(messages)} messages in history")
else:
print("\nSession has no messages stored")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,49 @@
# Foundry Provider Samples
This folder contains Azure AI Foundry and Foundry Local samples for Agent Framework.
## FoundryAgent Samples
| File | Description |
|------|-------------|
| [`foundry_agent_basic.py`](foundry_agent_basic.py) | Foundry Agent basic example |
| [`foundry_agent_custom_client.py`](foundry_agent_custom_client.py) | Foundry Agent custom client configuration |
| [`foundry_agent_hosted.py`](foundry_agent_hosted.py) | Foundry Agent for hosted agents |
| [`foundry_agent_with_function_tools.py`](foundry_agent_with_function_tools.py) | Foundry Agent with local function tools |
## FoundryChatClient Samples
| File | Description |
|------|-------------|
| [`foundry_chat_client.py`](foundry_chat_client.py) | Foundry Chat Client with project endpoint example |
| [`foundry_chat_client_basic.py`](foundry_chat_client_basic.py) | Foundry Chat Client basic example |
| [`foundry_chat_client_code_interpreter_files.py`](foundry_chat_client_code_interpreter_files.py) | Foundry Chat Client with code interpreter and files |
| [`foundry_chat_client_image_analysis.py`](foundry_chat_client_image_analysis.py) | Foundry Chat Client with image analysis |
| [`foundry_chat_client_with_code_interpreter.py`](foundry_chat_client_with_code_interpreter.py) | Foundry Chat Client with code interpreter |
| [`foundry_chat_client_with_explicit_settings.py`](foundry_chat_client_with_explicit_settings.py) | Foundry Chat Client with explicit settings |
| [`foundry_chat_client_with_file_search.py`](foundry_chat_client_with_file_search.py) | Foundry Chat Client with file search |
| [`foundry_chat_client_with_function_tools.py`](foundry_chat_client_with_function_tools.py) | Foundry Chat Client with function tools |
| [`foundry_chat_client_with_hosted_mcp.py`](foundry_chat_client_with_hosted_mcp.py) | Foundry Chat Client with hosted MCP |
| [`foundry_chat_client_with_local_mcp.py`](foundry_chat_client_with_local_mcp.py) | Foundry Chat Client with local MCP |
| [`foundry_chat_client_with_session.py`](foundry_chat_client_with_session.py) | Foundry Chat Client with session management |
| [`foundry_chat_client_with_toolbox.py`](foundry_chat_client_with_toolbox.py) | Foundry Chat Client connected to a toolbox via its MCP endpoint using `MCPStreamableHTTPTool` |
| [`foundry_chat_client_with_toolbox_skills.py`](foundry_chat_client_with_toolbox_skills.py) | Foundry Chat Client that discovers MCP-based skills from a Foundry Toolbox endpoint via `MCPSkillsSource` (uses an Azure AD bearer token and the toolbox preview header) |
## FoundryLocalClient Samples
### Prerequisites
1. Install Foundry Local and required local runtime components.
2. Install the connector package:
```bash
pip install agent-framework-foundry-local --pre
```
| File | Description |
|------|-------------|
| [`foundry_local_agent.py`](foundry_local_agent.py) | Basic Foundry Local agent usage with streaming and non-streaming responses, plus function tool calling. |
### Environment Variables
- `FOUNDRY_LOCAL_MODEL`: Optional model alias/ID to use by default when `model` is not passed to `FoundryLocalClient`.
@@ -0,0 +1,42 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from agent_framework.foundry import FoundryAgent
from azure.identity import AzureCliCredential
"""
Foundry Agent — Connect to a pre-configured agent in Microsoft Foundry
This sample shows the simplest way to connect to an existing PromptAgent
in Azure AI Foundry and run it. The agent's instructions, model, and hosted
tools are all configured on the service — you just connect and run.
Environment variables:
FOUNDRY_PROJECT_ENDPOINT — Azure AI Foundry project endpoint
FOUNDRY_AGENT_NAME — Name of the agent in Foundry
FOUNDRY_AGENT_VERSION — Version of the agent (for PromptAgents)
"""
async def main() -> None:
agent = FoundryAgent(
project_endpoint="https://your-project.services.ai.azure.com",
agent_name="my-prompt-agent",
agent_version="1.0",
credential=AzureCliCredential(),
)
result = await agent.run("What is the capital of France?")
print(f"Agent: {result}")
# Streaming
print("Agent (streaming): ", end="", flush=True)
async for chunk in agent.run("Tell me a fun fact.", stream=True):
if chunk.text:
print(chunk.text, end="", flush=True)
print()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,63 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from agent_framework import Agent
from agent_framework.foundry import FoundryAgent, RawFoundryAgentChatClient
from azure.identity import AzureCliCredential
from dotenv import load_dotenv
load_dotenv()
"""
Foundry Agent — Custom client configuration
This sample demonstrates three ways to customize the FoundryAgent client layer:
1. Default: FoundryAgent creates a RawFoundryAgentChatClient (full middleware) internally
2. client_type: Pass RawFoundryAgentChatClient for no client middleware
3. Composition: Use Agent(client=RawFoundryAgentChatClient(...)) directly
Environment variables:
FOUNDRY_PROJECT_ENDPOINT — Azure AI Foundry project endpoint
FOUNDRY_AGENT_NAME — Name of the agent in Foundry
FOUNDRY_AGENT_VERSION — Version of the agent
"""
async def main() -> None:
# Option 1: Default — full middleware on both agent and client
agent = FoundryAgent(
project_endpoint=os.getenv("FOUNDRY_PROJECT_ENDPOINT"),
agent_name=os.getenv("FOUNDRY_AGENT_NAME"),
agent_version=os.getenv("FOUNDRY_AGENT_VERSION"),
credential=AzureCliCredential(),
)
result = await agent.run("Hello from the default setup!")
print(f"Default: {result}\n")
# Option 2: Raw client — no client-level middleware (agent middleware still active)
agent_raw_client = FoundryAgent(
project_endpoint=os.getenv("FOUNDRY_PROJECT_ENDPOINT"),
agent_name=os.getenv("FOUNDRY_AGENT_NAME"),
agent_version=os.getenv("FOUNDRY_AGENT_VERSION"),
credential=AzureCliCredential(),
client_type=RawFoundryAgentChatClient,
)
result = await agent_raw_client.run("Hello from raw client!")
print(f"Raw client: {result}\n")
# Option 3: Composition — use Agent(client=...) directly
# this will not run the checks that the `FoundryAgent` does on things like tools.
client = RawFoundryAgentChatClient(
project_endpoint=os.getenv("FOUNDRY_PROJECT_ENDPOINT"),
agent_name=os.getenv("FOUNDRY_AGENT_NAME"),
agent_version=os.getenv("FOUNDRY_AGENT_VERSION"),
credential=AzureCliCredential(),
)
agent_composed = Agent(client=client)
result = await agent_composed.run("Hello from composed setup!")
print(f"Composed: {result}")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,37 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from agent_framework.foundry import FoundryAgent
from azure.identity import AzureCliCredential
from dotenv import load_dotenv
load_dotenv()
"""
Foundry Agent — Connect to a HostedAgent (no version needed)
HostedAgents in Azure AI Foundry are pre-deployed agents that don't require
a version number. You only need the agent name to connect.
Environment variables:
FOUNDRY_PROJECT_ENDPOINT — Azure AI Foundry project endpoint
FOUNDRY_AGENT_NAME — Name of the hosted agent
"""
async def main() -> None:
# HostedAgents don't need agent_version
agent = FoundryAgent(
project_endpoint=os.getenv("FOUNDRY_PROJECT_ENDPOINT"),
agent_name=os.getenv("FOUNDRY_AGENT_NAME"),
credential=AzureCliCredential(),
)
result = await agent.run("Summarize the latest news about AI.")
print(f"Agent: {result}")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,50 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from typing import Annotated
from agent_framework.foundry import FoundryAgent
from azure.identity import AzureCliCredential
from dotenv import load_dotenv
load_dotenv()
"""
Foundry Agent with Local Function Tools
This sample shows how to connect to a Foundry agent and provide local function
tools. The Foundry agent must already have these tools defined in its configuration
(as declaration-only tools). The local implementations are matched by name.
Only FunctionTool objects are accepted — hosted tools (code interpreter, file search,
web search, etc.) must be configured on the agent definition in the service.
Environment variables:
FOUNDRY_PROJECT_ENDPOINT — Azure AI Foundry project endpoint
FOUNDRY_AGENT_NAME — Name of the agent in Foundry
FOUNDRY_AGENT_VERSION — Version of the agent
"""
def get_weather(
location: Annotated[str, "The city to get weather for."],
) -> str:
"""Get the current weather for a location."""
return f"The weather in {location} is sunny, 22°C."
async def main() -> None:
agent = FoundryAgent(
project_endpoint=os.getenv("FOUNDRY_PROJECT_ENDPOINT"),
agent_name=os.getenv("FOUNDRY_AGENT_NAME"),
agent_version=os.getenv("FOUNDRY_AGENT_VERSION"),
credential=AzureCliCredential(),
tools=get_weather,
)
result = await agent.run("What's the weather in Paris?")
print(f"Agent: {result}")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,115 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from random import randint
from typing import Annotated
from agent_framework import Agent, tool
from agent_framework.foundry import FoundryChatClient
from azure.identity import AzureCliCredential
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
"""
Foundry Chat Client with Project Endpoint Example
This sample demonstrates how to create a FoundryChatClient using a
Foundry project endpoint. Instead of providing a service endpoint
directly, you provide a Foundry project endpoint and the client is created via
the Azure AI Foundry project SDK.
This requires:
- The `FOUNDRY_PROJECT_ENDPOINT` environment variable set to your Foundry project endpoint.
- The `FOUNDRY_MODEL` environment variable set to the model deployment name.
"""
@tool(approval_mode="never_require")
def get_weather(
location: Annotated[str, "The location to get the weather for."],
) -> str:
"""Get the weather for a given location."""
conditions = ["sunny", "cloudy", "rainy", "stormy"]
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C."
async def non_streaming_example() -> None:
"""Example of non-streaming response (get the complete result at once)."""
print("=== Non-streaming Response Example ===")
# 1. Create the FoundryChatClient using a Foundry project endpoint.
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
credential = AzureCliCredential()
_client = FoundryChatClient(
project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
model=os.environ["FOUNDRY_MODEL"],
credential=credential,
)
agent = Agent(
client=_client,
instructions="You are a helpful weather agent.",
tools=get_weather,
)
# 2. Run a query and print the result.
query = "What's the weather like in Seattle?"
print(f"User: {query}")
result = await agent.run(query)
print(f"Result: {result}\n")
async def streaming_example() -> None:
"""Example of streaming response (get results as they are generated)."""
print("=== Streaming Response Example ===")
# 1. Create the FoundryChatClient using a Foundry project endpoint.
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
credential = AzureCliCredential()
_client = FoundryChatClient(
project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
model=os.environ["FOUNDRY_MODEL"],
credential=credential,
)
agent = Agent(
client=_client,
instructions="You are a helpful weather agent.",
tools=get_weather,
)
# 2. Stream the response and print each chunk as it arrives.
query = "What's the weather like in Portland?"
print(f"User: {query}")
print("Agent: ", end="", flush=True)
async for chunk in agent.run(query, stream=True):
if chunk.text:
print(chunk.text, end="", flush=True)
print("\n")
async def main() -> None:
print("=== Foundry Chat Client with Project Endpoint Example ===")
await non_streaming_example()
await streaming_example()
if __name__ == "__main__":
asyncio.run(main())
"""
Sample output:
=== Foundry Chat Client with Project Endpoint Example ===
=== Non-streaming Response Example ===
User: What's the weather like in Seattle?
Result: The weather in Seattle is cloudy with a high of 18°C.
=== Streaming Response Example ===
User: What's the weather like in Portland?
Agent: The weather in Portland is sunny with a high of 25°C.
"""
@@ -0,0 +1,86 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from random import randint
from typing import Annotated
from agent_framework import Agent, tool
from agent_framework.foundry import FoundryChatClient
from azure.identity import AzureCliCredential
from dotenv import load_dotenv
from pydantic import Field
# Load environment variables from .env file
load_dotenv()
"""
Foundry Chat Client Basic Example
This sample demonstrates basic usage of FoundryChatClient for structured
response generation, showing both streaming and non-streaming responses.
This uses a deployed model in Foundry, with the Responses API endpoint of Foundry.
The client has full support for tools, response formats, etc.
"""
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production;
# see samples/02-agents/tools/function_tool_with_approval.py
# and samples/02-agents/tools/function_tool_with_approval_and_sessions.py.
@tool(approval_mode="never_require")
def get_weather(
location: Annotated[str, Field(description="The location to get the weather for.")],
) -> str:
"""Get the weather for a given location."""
conditions = ["sunny", "cloudy", "rainy", "stormy"]
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C."
async def non_streaming_example() -> None:
"""Example of non-streaming response (get the complete result at once)."""
print("=== Non-streaming Response Example ===")
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
agent = Agent(
client=FoundryChatClient(credential=AzureCliCredential()),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
query = "What's the weather like in Seattle?"
print(f"User: {query}")
result = await agent.run(query)
print(f"Result: {result}\n")
async def streaming_example() -> None:
"""Example of streaming response (get results as they are generated)."""
print("=== Streaming Response Example ===")
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
agent = Agent(
client=FoundryChatClient(credential=AzureCliCredential()),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
query = "What's the weather like in Portland?"
print(f"User: {query}")
print("Agent: ", end="", flush=True)
async for chunk in agent.run(query, stream=True):
if chunk.text:
print(chunk.text, end="", flush=True)
print("\n")
async def main() -> None:
print("=== Foundry Chat Client Basic Example ===")
await non_streaming_example()
await streaming_example()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,97 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
import tempfile
from agent_framework import Agent
from agent_framework.foundry import FoundryChatClient
from azure.identity import AzureCliCredential
from dotenv import load_dotenv
from openai import AsyncOpenAI
load_dotenv()
"""
Foundry Chat Client with Code Interpreter and Files Example
This sample demonstrates using get_code_interpreter_tool() with Responses on Foundry
for Python code execution and data analysis with uploaded files.
Environment variables:
FOUNDRY_PROJECT_ENDPOINT — Foundry project endpoint
FOUNDRY_MODEL — Foundry model to use (e.g. "gpt-4o-mini")
"""
# Helper functions
async def create_sample_file_and_upload(openai_client: AsyncOpenAI) -> tuple[str, str]:
"""Create a sample CSV file and upload it for Foundry code interpreter use."""
csv_data = """name,department,salary,years_experience
Alice Johnson,Engineering,95000,5
Bob Smith,Sales,75000,3
Carol Williams,Engineering,105000,8
David Brown,Marketing,68000,2
Emma Davis,Sales,82000,4
Frank Wilson,Engineering,88000,6
"""
# Create temporary CSV file
with tempfile.NamedTemporaryFile(mode="w", suffix=".csv", delete=False) as temp_file:
temp_file.write(csv_data)
temp_file_path = temp_file.name
# Upload file for the code interpreter tool
print("Uploading file for code interpreter...")
with open(temp_file_path, "rb") as file:
uploaded_file = await openai_client.files.create(
file=file,
purpose="assistants", # Required for code interpreter
)
print(f"File uploaded with ID: {uploaded_file.id}")
return temp_file_path, uploaded_file.id
async def cleanup_files(openai_client: AsyncOpenAI, temp_file_path: str, file_id: str) -> None:
"""Clean up both local temporary file and uploaded file."""
# Clean up: delete the uploaded file
await openai_client.files.delete(file_id)
print(f"Cleaned up uploaded file: {file_id}")
# Clean up temporary local file
os.unlink(temp_file_path)
print(f"Cleaned up temporary file: {temp_file_path}")
async def main() -> None:
print("=== Foundry Chat Client with Code Interpreter and File Upload ===")
# Create the FoundryChatClient
client = FoundryChatClient(
project_endpoint=os.getenv("FOUNDRY_PROJECT_ENDPOINT"),
model=os.getenv("FOUNDRY_MODEL"),
credential=AzureCliCredential(),
)
# use the openai client from the foundry client to upload files for the code interpreter tool
openai_client = getattr(client.project_client, "get_openai_client")() # noqa: B009
temp_file_path, file_id = await create_sample_file_and_upload(openai_client)
# Create agent with code interpreter tool with file access
agent = Agent(
client=client,
instructions="You are a helpful assistant that can analyze data files using Python code.",
tools=FoundryChatClient.get_code_interpreter_tool(file_ids=[file_id]),
)
try:
# Test the code interpreter with the uploaded file
query = "Analyze the employee data in the uploaded CSV file. Calculate average salary by department."
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result.text}")
finally:
await cleanup_files(openai_client, temp_file_path, file_id)
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,44 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from agent_framework import Agent, Content
from agent_framework.foundry import FoundryChatClient
from azure.identity import AzureCliCredential
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
"""
Foundry Chat Client with Image Analysis Example
This sample demonstrates using FoundryChatClient for image analysis and vision tasks,
showing multi-modal messages combining text and image content.
"""
async def main():
print("=== Foundry Chat Client with Image Analysis ===")
# 1. Create a Foundry-backed agent with vision capabilities
agent = Agent(
client=FoundryChatClient(credential=AzureCliCredential()),
name="VisionAgent",
instructions="You are a image analysist, you get a image and need to respond with what you see in the picture.",
)
# 2. Get the agent's response
print("User: What do you see in this image? [Image provided]")
result = await agent.run(
Content.from_uri(
uri="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=800",
media_type="image/jpeg",
)
)
print(f"Agent: {result.text}")
print()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,57 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from agent_framework import Agent, ChatResponse
from agent_framework.foundry import FoundryChatClient
from azure.identity import AzureCliCredential
from dotenv import load_dotenv
from openai.types.responses.response import Response as OpenAIResponse
from openai.types.responses.response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall
# Load environment variables from .env file
load_dotenv()
"""
Foundry Chat Client with Code Interpreter Example
This sample demonstrates using get_code_interpreter_tool() with FoundryChatClient
for Python code execution and mathematical problem solving.
"""
async def main() -> None:
"""Example showing how to use the code interpreter tool with FoundryChatClient."""
print("=== Foundry Chat Client with Code Interpreter Example ===")
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
client = FoundryChatClient(credential=AzureCliCredential())
# Create code interpreter tool using instance method
code_interpreter_tool = client.get_code_interpreter_tool()
agent = Agent(
client=client,
instructions="You are a helpful assistant that can write and execute Python code to solve problems.",
tools=[code_interpreter_tool],
)
query = "Use code to calculate the factorial of 100?"
print(f"User: {query}")
result = await agent.run(query)
print(f"Result: {result}\n")
if (
isinstance(result.raw_representation, ChatResponse)
and isinstance(result.raw_representation.raw_representation, OpenAIResponse)
and len(result.raw_representation.raw_representation.output) > 0
and isinstance(result.raw_representation.raw_representation.output[0], ResponseCodeInterpreterToolCall)
):
generated_code = result.raw_representation.raw_representation.output[0].code
print(f"Generated code:\n{generated_code}")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,58 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from random import randint
from typing import Annotated
from agent_framework import Agent, tool
from agent_framework.foundry import FoundryChatClient
from azure.identity import AzureCliCredential
from dotenv import load_dotenv
from pydantic import Field
# Load environment variables from .env file
load_dotenv()
"""
Foundry Chat Client with Explicit Settings Example
This sample demonstrates creating FoundryChatClient with explicit project endpoint and
model settings rather than relying on environment variable defaults.
"""
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production;
# see samples/02-agents/tools/function_tool_with_approval.py
# and samples/02-agents/tools/function_tool_with_approval_and_sessions.py.
@tool(approval_mode="never_require")
def get_weather(
location: Annotated[str, Field(description="The location to get the weather for.")],
) -> str:
"""Get the weather for a given location."""
conditions = ["sunny", "cloudy", "rainy", "stormy"]
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C."
async def main() -> None:
print("=== Foundry Chat Client with Explicit Settings ===")
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
_client = FoundryChatClient(
model=os.environ["FOUNDRY_MODEL"],
project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
credential=AzureCliCredential(),
)
agent = Agent(
client=_client,
instructions="You are a helpful weather agent.",
tools=[get_weather],
)
result = await agent.run("What's the weather like in New York?")
print(f"Result: {result}\n")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,81 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import contextlib
from agent_framework import Agent
from agent_framework.foundry import FoundryChatClient
from azure.identity import AzureCliCredential
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
"""
Foundry Chat Client with File Search Example
This sample demonstrates using get_file_search_tool() with FoundryChatClient
for direct document-based question answering and information retrieval.
Prerequisites:
- Set environment variables:
- FOUNDRY_PROJECT_ENDPOINT: Your Foundry project endpoint URL
- FOUNDRY_MODEL: Your Responses API deployment name
- Authenticate via 'az login' for AzureCliCredential
"""
# Helper functions
async def create_vector_store(client: FoundryChatClient) -> tuple[str, str]:
"""Create a vector store with sample documents."""
file = await client.client.files.create(
file=("todays_weather.txt", b"The weather today is sunny with a high of 75F."), purpose="assistants"
)
vector_store = await client.client.vector_stores.create(
name="knowledge_base",
expires_after={"anchor": "last_active_at", "days": 1},
)
result = await client.client.vector_stores.files.create_and_poll(vector_store_id=vector_store.id, file_id=file.id)
if result.last_error is not None:
raise Exception(f"Vector store file processing failed with status: {result.last_error.message}")
return file.id, vector_store.id
async def delete_vector_store(client: FoundryChatClient, file_id: str, vector_store_id: str) -> None:
"""Delete the vector store after using it."""
with contextlib.suppress(Exception):
await client.client.vector_stores.delete(vector_store_id=vector_store_id)
with contextlib.suppress(Exception):
await client.client.files.delete(file_id=file_id)
async def main() -> None:
print("=== Foundry Chat Client with File Search Example ===\n")
# Initialize the Foundry chat client
# Make sure you're logged in via 'az login' before running this sample
client = FoundryChatClient(credential=AzureCliCredential())
file_id, vector_store_id = await create_vector_store(client)
# Create file search tool using instance method
file_search_tool = client.get_file_search_tool(vector_store_ids=[vector_store_id])
agent = Agent(
client=client,
instructions="You are a helpful assistant that can search through files to find information.",
tools=[file_search_tool],
)
query = "What is the weather today? Do a file search to find the answer."
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result}\n")
await delete_vector_store(client, file_id, vector_store_id)
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,143 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from datetime import datetime, timezone
from random import randint
from typing import Annotated
from agent_framework import Agent, tool
from agent_framework.foundry import FoundryChatClient
from azure.identity import AzureCliCredential
from dotenv import load_dotenv
from pydantic import Field
# Load environment variables from .env file
load_dotenv()
"""
Foundry Chat Client with Function Tools Example
This sample demonstrates function tool integration with FoundryChatClient,
showing both agent-level and query-level tool configuration patterns.
"""
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production;
# see samples/02-agents/tools/function_tool_with_approval.py
# and samples/02-agents/tools/function_tool_with_approval_and_sessions.py.
@tool(approval_mode="never_require")
def get_weather(
location: Annotated[str, Field(description="The location to get the weather for.")],
) -> str:
"""Get the weather for a given location."""
conditions = ["sunny", "cloudy", "rainy", "stormy"]
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C."
@tool(approval_mode="never_require")
def get_time() -> str:
"""Get the current UTC time."""
current_time = datetime.now(timezone.utc)
return f"The current UTC time is {current_time.strftime('%Y-%m-%d %H:%M:%S')}."
async def tools_on_agent_level() -> None:
"""Example showing tools defined when creating the agent."""
print("=== Tools Defined on Agent Level ===")
# Tools are provided when creating the agent
# The agent can use these tools for any query during its lifetime
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
agent = Agent(
client=FoundryChatClient(credential=AzureCliCredential()),
instructions="You are a helpful assistant that can provide weather and time information.",
tools=[get_weather, get_time], # Tools defined at agent creation
)
# First query - agent can use weather tool
query1 = "What's the weather like in New York?"
print(f"User: {query1}")
result1 = await agent.run(query1)
print(f"Agent: {result1}\n")
# Second query - agent can use time tool
query2 = "What's the current UTC time?"
print(f"User: {query2}")
result2 = await agent.run(query2)
print(f"Agent: {result2}\n")
# Third query - agent can use both tools if needed
query3 = "What's the weather in London and what's the current UTC time?"
print(f"User: {query3}")
result3 = await agent.run(query3)
print(f"Agent: {result3}\n")
async def tools_on_run_level() -> None:
"""Example showing tools passed to the run method."""
print("=== Tools Passed to Run Method ===")
# Agent created without tools
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
agent = Agent(
client=FoundryChatClient(credential=AzureCliCredential()),
instructions="You are a helpful assistant.",
# No tools defined here
)
# First query with weather tool
query1 = "What's the weather like in Seattle?"
print(f"User: {query1}")
result1 = await agent.run(query1, tools=[get_weather]) # Tool passed to run method
print(f"Agent: {result1}\n")
# Second query with time tool
query2 = "What's the current UTC time?"
print(f"User: {query2}")
result2 = await agent.run(query2, tools=[get_time]) # Different tool for this query
print(f"Agent: {result2}\n")
# Third query with multiple tools
query3 = "What's the weather in Chicago and what's the current UTC time?"
print(f"User: {query3}")
result3 = await agent.run(query3, tools=[get_weather, get_time]) # Multiple tools
print(f"Agent: {result3}\n")
async def mixed_tools_example() -> None:
"""Example showing both agent-level tools and run-method tools."""
print("=== Mixed Tools Example (Agent + Run Method) ===")
# Agent created with some base tools
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
agent = Agent(
client=FoundryChatClient(credential=AzureCliCredential()),
instructions="You are a comprehensive assistant that can help with various information requests.",
tools=[get_weather], # Base tool available for all queries
)
# Query using both agent tool and additional run-method tools
query = "What's the weather in Denver and what's the current UTC time?"
print(f"User: {query}")
# Agent has access to get_weather (from creation) + additional tools from run method
result = await agent.run(
query,
tools=[get_time], # Additional tools for this specific query
)
print(f"Agent: {result}\n")
async def main() -> None:
print("=== Foundry Chat Client with Function Tools Examples ===\n")
await tools_on_agent_level()
await tools_on_run_level()
await mixed_tools_example()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,271 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from typing import TYPE_CHECKING, Any
from agent_framework import Agent
from agent_framework.foundry import FoundryChatClient
from azure.identity import AzureCliCredential
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
"""
Foundry Chat Client with Hosted MCP Example
This sample demonstrates integrating hosted Model Context Protocol (MCP) tools with
FoundryChatClient, including user approval workflows for function call security.
"""
if TYPE_CHECKING:
from agent_framework import AgentSession
async def handle_approvals_without_session(query: str, agent: Agent[Any]):
"""When we don't have a session, we need to ensure we return with the input, approval request and approval."""
from agent_framework import Message
result = await agent.run(query)
while len(result.user_input_requests) > 0:
new_inputs: list[Any] = [query]
for user_input_needed in result.user_input_requests:
if user_input_needed.function_call is None:
continue
print(
f"User Input Request for function from {agent.name}: {user_input_needed.function_call.name}"
f" with arguments: {user_input_needed.function_call.arguments}"
)
new_inputs.append(Message(role="assistant", contents=[user_input_needed]))
user_approval = input("Approve function call? (y/n): ")
new_inputs.append(
Message(
role="user",
contents=[user_input_needed.to_function_approval_response(user_approval.lower() == "y")],
)
)
result = await agent.run(new_inputs)
return result
async def handle_approvals_with_session(query: str, agent: Agent[Any], session: "AgentSession"):
"""Here we let the session deal with the previous responses, and we just rerun with the approval."""
from agent_framework import ChatOptions, Message
result = await agent.run(query, session=session, options=ChatOptions(store=True))
while len(result.user_input_requests) > 0:
new_input: list[Any] = []
for user_input_needed in result.user_input_requests:
if user_input_needed.function_call is None:
continue
print(
f"User Input Request for function from {agent.name}: {user_input_needed.function_call.name}"
f" with arguments: {user_input_needed.function_call.arguments}"
)
user_approval = input("Approve function call? (y/n): ")
new_input.append(
Message(
role="user",
contents=[user_input_needed.to_function_approval_response(user_approval.lower() == "y")],
)
)
result = await agent.run(new_input, session=session, options=ChatOptions(store=True))
return result
async def handle_approvals_with_session_streaming(query: str, agent: Agent[Any], session: "AgentSession"):
"""Here we let the session deal with the previous responses, and we just rerun with the approval."""
from agent_framework import ChatOptions, Message
new_input: list[Message | str] = [query]
new_input_added = True
while new_input_added:
new_input_added = False
async for update in agent.run(new_input, session=session, options=ChatOptions(store=True), stream=True):
if update.user_input_requests:
# Reset input to only contain new approval responses for the next iteration
new_input = []
for user_input_needed in update.user_input_requests:
if user_input_needed.function_call is None:
continue
print(
f"User Input Request for function from {agent.name}: {user_input_needed.function_call.name}"
f" with arguments: {user_input_needed.function_call.arguments}"
)
user_approval = input("Approve function call? (y/n): ")
new_input.append(
Message(
role="user",
contents=[user_input_needed.to_function_approval_response(user_approval.lower() == "y")],
)
)
new_input_added = True
else:
yield update
async def run_hosted_mcp_without_session_and_specific_approval() -> None:
"""Example showing Mcp Tools with approvals without using a session."""
print("=== Mcp with approvals and without session ===")
credential = AzureCliCredential()
client = FoundryChatClient(credential=credential)
# Create MCP tool with specific approval settings
mcp_tool = client.get_mcp_tool(
name="Microsoft Learn MCP",
url="https://learn.microsoft.com/api/mcp",
# we don't require approval for microsoft_docs_search tool calls
# but we do for any other tool
approval_mode={"never_require_approval": ["microsoft_docs_search"]},
)
# Tools are provided when creating the agent
# The agent can use these tools for any query during its lifetime
async with Agent(
client=client,
name="DocsAgent",
instructions="You are a helpful assistant that uses your MCP tool "
"to help with microsoft documentation questions.",
tools=[mcp_tool],
) as agent:
# First query
query1 = "How to create an Azure storage account using az cli?"
print(f"User: {query1}")
result1 = await handle_approvals_without_session(query1, agent)
print(f"{agent.name}: {result1}\n")
print("\n=======================================\n")
# Second query
query2 = "What is Microsoft Agent Framework?"
print(f"User: {query2}")
result2 = await handle_approvals_without_session(query2, agent)
print(f"{agent.name}: {result2}\n")
async def run_hosted_mcp_without_approval() -> None:
"""Example showing Mcp Tools without approvals."""
print("=== Mcp without approvals ===")
credential = AzureCliCredential()
client = FoundryChatClient(credential=credential)
# Create MCP tool without approval requirements
mcp_tool = client.get_mcp_tool(
name="Microsoft Learn MCP",
url="https://learn.microsoft.com/api/mcp",
# we don't require approval for any function calls
# this means we will not see the approval messages,
# it is fully handled by the service and a final response is returned.
approval_mode="never_require",
)
# Tools are provided when creating the agent
# The agent can use these tools for any query during its lifetime
async with Agent(
client=client,
name="DocsAgent",
instructions="You are a helpful assistant that uses your MCP tool "
"to help with Microsoft documentation questions.",
tools=[mcp_tool],
) as agent:
# First query
query1 = "How to create an Azure storage account using az cli?"
print(f"User: {query1}")
result1 = await handle_approvals_without_session(query1, agent)
print(f"{agent.name}: {result1}\n")
print("\n=======================================\n")
# Second query
query2 = "What is Microsoft Agent Framework?"
print(f"User: {query2}")
result2 = await handle_approvals_without_session(query2, agent)
print(f"{agent.name}: {result2}\n")
async def run_hosted_mcp_with_session() -> None:
"""Example showing Mcp Tools with approvals using a session."""
print("=== Mcp with approvals and with session ===")
credential = AzureCliCredential()
client = FoundryChatClient(credential=credential)
# Create MCP tool with always require approval
mcp_tool = client.get_mcp_tool(
name="Microsoft Learn MCP",
url="https://learn.microsoft.com/api/mcp",
# we require approval for all function calls
approval_mode="always_require",
)
# Tools are provided when creating the agent
# The agent can use these tools for any query during its lifetime
async with Agent(
client=client,
name="DocsAgent",
instructions="You are a helpful assistant that uses your MCP tool "
"to help with microsoft documentation questions.",
tools=[mcp_tool],
) as agent:
# First query
session = agent.create_session()
query1 = "How to create an Azure storage account using az cli?"
print(f"User: {query1}")
result1 = await handle_approvals_with_session(query1, agent, session)
print(f"{agent.name}: {result1}\n")
print("\n=======================================\n")
# Second query
query2 = "What is Microsoft Agent Framework?"
print(f"User: {query2}")
result2 = await handle_approvals_with_session(query2, agent, session)
print(f"{agent.name}: {result2}\n")
async def run_hosted_mcp_with_session_streaming() -> None:
"""Example showing Mcp Tools with approvals using a session."""
print("=== Mcp with approvals and with session ===")
credential = AzureCliCredential()
client = FoundryChatClient(credential=credential)
# Create MCP tool with always require approval
mcp_tool = client.get_mcp_tool(
name="Microsoft Learn MCP",
url="https://learn.microsoft.com/api/mcp",
# we require approval for all function calls
approval_mode="always_require",
)
# Tools are provided when creating the agent
# The agent can use these tools for any query during its lifetime
async with Agent(
client=client,
name="DocsAgent",
instructions="You are a helpful assistant that uses your MCP tool "
"to help with microsoft documentation questions.",
tools=[mcp_tool],
) as agent:
# First query
session = agent.create_session()
query1 = "How to create an Azure storage account using az cli?"
print(f"User: {query1}")
print(f"{agent.name}: ", end="")
async for update in handle_approvals_with_session_streaming(query1, agent, session):
print(update, end="")
print("\n")
print("\n=======================================\n")
# Second query
query2 = "What is Microsoft Agent Framework?"
print(f"User: {query2}")
print(f"{agent.name}: ", end="")
async for update in handle_approvals_with_session_streaming(query2, agent, session):
print(update, end="")
print("\n")
async def main() -> None:
print("=== Foundry Chat Client with Hosted MCP Examples ===\n")
await run_hosted_mcp_without_approval()
await run_hosted_mcp_without_session_and_specific_approval()
await run_hosted_mcp_with_session()
await run_hosted_mcp_with_session_streaming()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,66 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from agent_framework import Agent, MCPStreamableHTTPTool
from agent_framework.foundry import FoundryChatClient
from azure.identity import AzureCliCredential
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
"""
Foundry Chat Client with Local Model Context Protocol (MCP) Example
This sample demonstrates integration of FoundryChatClient with local Model Context Protocol (MCP)
servers.
"""
# --- Below code uses Microsoft Learn MCP server over Streamable HTTP ---
# --- Users can set these environment variables, or just edit the values below to their desired local MCP server
MCP_NAME = os.environ.get("MCP_NAME", "Microsoft Learn MCP") # example name
MCP_URL = os.environ.get("MCP_URL", "https://learn.microsoft.com/api/mcp") # example endpoint
# Environment variables for FoundryChatClient authentication
# FOUNDRY_PROJECT_ENDPOINT="<your-foundry-project-endpoint>"
# FOUNDRY_MODEL="<your-deployment-name>"
async def main():
"""Example showing local MCP tools for a Foundry Chat Client agent."""
# AuthN: use Azure CLI
credential = AzureCliCredential()
# Build an agent backed by FoundryChatClient
# (project endpoint and model can also come from env vars above)
responses_client = FoundryChatClient(
credential=credential,
)
agent: Agent = Agent(
client=responses_client,
name="DocsAgent",
instructions=("You are a helpful assistant that can help with Microsoft documentation questions."),
)
# Connect to the MCP server (Streamable HTTP)
async with MCPStreamableHTTPTool(
name=MCP_NAME,
url=MCP_URL,
) as mcp_tool:
# First query — expect the agent to use the MCP tool if it helps
first_query = "How to create an Azure storage account using az cli?"
first_response = await agent.run(first_query, tools=mcp_tool)
print("\n=== Answer 1 ===\n", first_response.text)
# Follow-up query (connection is reused)
second_query = "What is Microsoft Agent Framework?"
second_response = await agent.run(second_query, tools=mcp_tool)
print("\n=== Answer 2 ===\n", second_response.text)
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,161 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from random import randint
from typing import Annotated
from agent_framework import Agent, AgentSession, InMemoryHistoryProvider, tool
from agent_framework.foundry import FoundryChatClient
from azure.identity import AzureCliCredential
from dotenv import load_dotenv
from pydantic import Field
# Load environment variables from .env file
load_dotenv()
"""
Foundry Chat Client with Session Management Example
This sample demonstrates session management with FoundryChatClient, comparing
automatic session creation with explicit session management for persistent context.
"""
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production;
# see samples/02-agents/tools/function_tool_with_approval.py
# and samples/02-agents/tools/function_tool_with_approval_and_sessions.py.
@tool(approval_mode="never_require")
def get_weather(
location: Annotated[str, Field(description="The location to get the weather for.")],
) -> str:
"""Get the weather for a given location."""
conditions = ["sunny", "cloudy", "rainy", "stormy"]
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C."
async def example_with_automatic_session_creation() -> None:
"""Example showing automatic session creation (service-managed session)."""
print("=== Automatic Session Creation Example ===")
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
agent = Agent(
client=FoundryChatClient(credential=AzureCliCredential()),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
# First conversation - no session provided, will be created automatically
query1 = "What's the weather like in Seattle?"
print(f"User: {query1}")
result1 = await agent.run(query1)
print(f"Agent: {result1.text}")
# Second conversation - still no session provided, will create another new session
query2 = "What was the last city I asked about?"
print(f"\nUser: {query2}")
result2 = await agent.run(query2)
print(f"Agent: {result2.text}")
print("Note: Each call creates a separate session, so the agent doesn't remember previous context.\n")
async def example_with_session_persistence() -> None:
"""Example showing session persistence across multiple conversations."""
print("=== Session Persistence Example ===")
print("Using the same session across multiple conversations to maintain context.\n")
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
agent = Agent(
client=FoundryChatClient(credential=AzureCliCredential()),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
# Create a new session that will be reused
session = agent.create_session()
# First conversation
query1 = "What's the weather like in Tokyo?"
print(f"User: {query1}")
result1 = await agent.run(query1, session=session)
print(f"Agent: {result1.text}")
# Second conversation using the same session - maintains context
query2 = "How about London?"
print(f"\nUser: {query2}")
result2 = await agent.run(query2, session=session)
print(f"Agent: {result2.text}")
# Third conversation - agent should remember both previous cities
query3 = "Which of the cities I asked about has better weather?"
print(f"\nUser: {query3}")
result3 = await agent.run(query3, session=session)
print(f"Agent: {result3.text}")
print("Note: The agent remembers context from previous messages in the same session.\n")
async def example_with_existing_session_messages() -> None:
"""Example showing how to work with existing session messages for Foundry-backed agents."""
print("=== Existing Session Messages Example ===")
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
agent = Agent(
client=FoundryChatClient(credential=AzureCliCredential()),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
# Start a conversation and build up message history
session = agent.create_session()
query1 = "What's the weather in Paris?"
print(f"User: {query1}")
result1 = await agent.run(query1, session=session)
print(f"Agent: {result1.text}")
# The session now contains the conversation history in state
memory_state = session.state.get(InMemoryHistoryProvider.DEFAULT_SOURCE_ID, {})
messages = memory_state.get("messages", [])
if messages:
print(f"Session contains {len(messages)} messages")
print("\n--- Continuing with the same session in a new agent instance ---")
# Create a new agent instance but use the existing session with its message history
new_agent = Agent(
client=FoundryChatClient(credential=AzureCliCredential()),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
# Use the same session object which contains the conversation history
query2 = "What was the last city I asked about?"
print(f"User: {query2}")
result2 = await new_agent.run(query2, session=session)
print(f"Agent: {result2.text}")
print("Note: The agent continues the conversation using the local message history.\n")
print("\n--- Alternative: Creating a new session from existing messages ---")
# You can also create a new session from existing messages
new_session = AgentSession()
query3 = "How does the Paris weather compare to London?"
print(f"User: {query3}")
result3 = await new_agent.run(query3, session=new_session)
print(f"Agent: {result3.text}")
print("Note: This creates a new session with the same conversation history.\n")
async def main() -> None:
print("=== Foundry Chat Client Session Management Examples ===\n")
await example_with_automatic_session_creation()
await example_with_session_persistence()
await example_with_existing_session_messages()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,118 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from collections.abc import Callable
from typing import Any
from agent_framework import Agent, MCPStreamableHTTPTool
from agent_framework.foundry import FoundryChatClient
from azure.core.credentials import TokenCredential
from azure.identity import AzureCliCredential, DefaultAzureCredential, get_bearer_token_provider
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
"""
Foundry Toolbox via MAF ``MCPStreamableHTTPTool``
Instead of fetching the toolbox and fanning out individual tool specs, point
MAF's ``MCPStreamableHTTPTool`` at the toolbox's MCP endpoint. The agent
discovers and calls the toolbox's tools over MCP at runtime.
Prerequisites:
- A Microsoft Foundry project with a toolbox configured
- FOUNDRY_PROJECT_ENDPOINT and FOUNDRY_MODEL environment variables set
- FOUNDRY_TOOLBOX_ENDPOINT: the toolbox's MCP endpoint URL, e.g.
``https://<account>.services.ai.azure.com/api/projects/<project>/toolsets/<name>/mcp?api-version=v1``
- Azure CLI authentication (``az login``)
"""
# Must match the ``<name>`` segment of FOUNDRY_TOOLBOX_ENDPOINT.
TOOLBOX_NAME = "research_toolbox"
def create_sample_toolbox(name: str) -> str:
"""Create (or replace) a toolbox version in the Foundry project.
Toolboxes are normally configured in the Foundry portal or a deployment
script, not the application itself. This helper exists so the sample can
be run end-to-end without first setting a toolbox up by hand — delete any
existing toolbox under ``name``, then create a fresh version containing a
single MCP tool. Returns the created version identifier.
"""
from azure.ai.projects import AIProjectClient
from azure.ai.projects.models import MCPTool, Tool
from azure.core.exceptions import ResourceNotFoundError
with (
AzureCliCredential() as credential,
AIProjectClient(credential=credential, endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"]) as project_client,
):
try:
project_client.beta.toolboxes.delete(name)
print(f"Toolbox `{name}` deleted")
except ResourceNotFoundError:
pass
tools: list[Tool] = [
MCPTool(
server_label="api_specs",
server_url="https://gitmcp.io/Azure/azure-rest-api-specs",
require_approval="never",
)
]
created = project_client.beta.toolboxes.create_version(
name=name,
description="Toolbox version with MCP require_approval set to 'never'.",
tools=tools,
)
print(f"Created toolbox {created.name}@{created.version} ({len(created.tools)} tool(s))")
return created.version
def make_toolbox_header_provider(credential: TokenCredential) -> Callable[[dict[str, Any]], dict[str, str]]:
"""Build a header_provider that injects a fresh Azure AI bearer token on every MCP request."""
get_token = get_bearer_token_provider(credential, "https://ai.azure.com/.default")
def provide(_kwargs: dict[str, Any]) -> dict[str, str]:
return {
"Authorization": f"Bearer {get_token()}",
}
return provide
async def main() -> None:
credential = DefaultAzureCredential()
# Comment out if the toolbox already exists in your Foundry project.
create_sample_toolbox(TOOLBOX_NAME)
toolbox_tool = MCPStreamableHTTPTool(
name="foundry_toolbox",
description="Tools exposed by the configured Foundry toolbox",
url=os.environ["FOUNDRY_TOOLBOX_ENDPOINT"],
header_provider=make_toolbox_header_provider(credential),
load_prompts=False,
)
async with Agent(
client=FoundryChatClient(
project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
model=os.environ["FOUNDRY_MODEL"],
credential=credential,
),
instructions="You are a helpful assistant. Use the available toolbox tools to answer the user.",
tools=toolbox_tool,
) as agent:
query = "What tools do you have access to?"
print(f"User: {query}")
result = await agent.run(query)
print(f"Assistant: {result}")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,88 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from collections.abc import Generator
import httpx
from agent_framework import Agent, MCPSkillsSource, SkillsProvider, ToolApprovalMiddleware
from agent_framework.foundry import FoundryChatClient
from azure.core.credentials import TokenCredential
from azure.identity import AzureCliCredential, get_bearer_token_provider
from dotenv import load_dotenv
from mcp.client.session import ClientSession
from mcp.client.streamable_http import streamable_http_client
# Load environment variables from .env file
load_dotenv()
"""
Foundry Chat Client with Toolbox-Hosted Skills
Discover Agent Skills served by a Microsoft Foundry Toolbox MCP endpoint
and inject them into a ``FoundryChatClient`` agent via ``MCPSkillsSource``.
The toolbox's discovery document (``skill://index.json``) is read once at
startup; SKILL.md bodies are fetched on demand as the agent uses them.
Prerequisites:
- A Microsoft Foundry project with a toolbox that exposes
``skill://index.json`` with ``skill-md`` entries
- FOUNDRY_PROJECT_ENDPOINT and FOUNDRY_MODEL environment variables set
- FOUNDRY_TOOLBOX_MCP_SERVER_URL: the toolbox's MCP endpoint URL, e.g.
``https://<account>.services.ai.azure.com/api/projects/<project>/toolboxes/<name>/mcp?api-version=v1``
- Azure CLI authentication (``az login``)
"""
class _BearerAuth(httpx.Auth):
"""Attach a fresh Foundry bearer token to every request."""
def __init__(self, credential: TokenCredential) -> None:
self._get_token = get_bearer_token_provider(credential, "https://ai.azure.com/.default")
def auth_flow(self, request: httpx.Request) -> Generator[httpx.Request, httpx.Response, None]:
request.headers["Authorization"] = f"Bearer {self._get_token()}"
yield request
async def main() -> None:
"""Example showing toolbox-hosted MCP skills for a Foundry Chat Client agent."""
credential = AzureCliCredential()
# HTTP client that signs every request with a fresh Foundry bearer token
# and advertises the toolbox preview feature flag, plus the MCP streamable
# HTTP transport that uses it.
async with (
httpx.AsyncClient(
auth=_BearerAuth(credential),
timeout=httpx.Timeout(30.0, read=300.0),
follow_redirects=True,
) as http_client,
streamable_http_client(
url=os.environ["FOUNDRY_TOOLBOX_MCP_SERVER_URL"],
http_client=http_client,
) as (read, write, _),
ClientSession(read, write) as session,
):
await session.initialize()
# Discover skills served by the toolbox and inject them as a context provider.
skills_provider = SkillsProvider(MCPSkillsSource(client=session))
async with Agent(
client=FoundryChatClient(credential=credential),
name="ToolboxMCPSkillsAgent",
instructions="You are a helpful assistant. Use available skills to answer the user.",
context_providers=[skills_provider],
middleware=[ToolApprovalMiddleware(auto_approval_rules=[SkillsProvider.all_tools_auto_approval_rule])],
) as agent:
query = input("User: ").strip() # noqa: ASYNC250
if not query:
return
session = agent.create_session()
response = await agent.run(query, session=session)
print(f"Assistant: {response.text}")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,79 @@
# Copyright (c) Microsoft. All rights reserved.
# ruff: noqa
from __future__ import annotations
import asyncio
from random import randint
from typing import Annotated, Any
from agent_framework import Agent
from agent_framework.foundry import FoundryLocalClient
"""
This sample demonstrates basic usage of the FoundryLocalClient.
Shows both streaming and non-streaming responses with function tools.
Running this sample the first time will be slow, as the model needs to be
downloaded and initialized.
Also, not every model supports function calling, so be sure to check the
model capabilities in the Foundry catalog, or pick one from the list printed
when running this sample.
"""
def get_weather(
location: Annotated[str, "The location to get the weather for."],
) -> str:
"""Get the weather for a given location."""
conditions = ["sunny", "cloudy", "rainy", "stormy"]
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C."
async def non_streaming_example(agent: Agent[Any]) -> None:
"""Example of non-streaming response (get the complete result at once)."""
print("=== Non-streaming Response Example ===")
query = "What's the weather like in Seattle?"
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result}\n")
async def streaming_example(agent: Agent[Any]) -> None:
"""Example of streaming response (get results as they are generated)."""
print("=== Streaming Response Example ===")
query = "What's the weather like in Amsterdam?"
print(f"User: {query}")
print("Agent: ", end="", flush=True)
async for chunk in agent.run(query, stream=True):
if chunk.text:
print(chunk.text, end="", flush=True)
print("\n")
async def main() -> None:
print("=== Basic Foundry Local Client Agent Example ===")
client = FoundryLocalClient(model="phi-4-mini")
print(f"Client Model ID: {client.model}\n")
print("Other available models (tool calling supported only):")
for model in client.manager.list_catalog_models():
if model.supports_tool_calling:
print(
f"- {model.alias} for {model.task} - id={model.id} - {(model.file_size_mb / 1000):.2f} GB - {model.license}"
)
agent = Agent(
client=client,
name="LocalAgent",
instructions="You are a helpful agent.",
tools=get_weather,
)
await non_streaming_example(agent)
await streaming_example(agent)
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,152 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from random import randint
from typing import Annotated
from agent_framework import Agent, tool
from agent_framework.foundry import FoundryAgent, FoundryChatClient, to_prompt_agent
from azure.ai.projects.aio import AIProjectClient
from azure.identity.aio import AzureCliCredential
from dotenv import load_dotenv
from pydantic import Field
load_dotenv()
"""
Foundry Prompt Agent: Convert, Publish, Connect, and Run
This sample shows the end-to-end loop:
1. Build an ``Agent`` backed by ``FoundryChatClient`` with a local ``@tool``
function and Foundry-hosted tools.
2. Run the local ``Agent`` directly against the Foundry Responses API.
3. Convert it with ``to_prompt_agent(agent)`` and publish via
``AIProjectClient.agents.create_version(...)``.
4. Connect to the deployed prompt agent with ``FoundryAgent`` and pass the
*same* ``book_hotel`` callable through ``tools=`` so the server-side prompt
agent and the client share a single tool definition.
The Foundry prompt agent only receives the ``book_hotel`` *declaration* (its
JSON schema). When the deployed agent decides to call the tool, ``FoundryAgent``
executes the local Python implementation by matching tool names — keeping the
schema on the server and the implementation on the client in sync.
Local ``Agent`` vs deployed prompt agent — compare & contrast when calling
``run`` on each:
* **Runtime / latency.** ``Agent.run`` issues a single ``responses.create``
call against the Foundry Responses API. ``FoundryAgent.run`` against a
published prompt agent goes through the Foundry Agents service, which
resolves the stored ``PromptAgentDefinition`` (instructions, tools,
generation parameters, RAI config) on every call before forwarding to the
model. Expect a small per-call overhead on the deployed path in exchange
for centrally managed configuration.
* **Configurability.** With the local ``Agent``, model, instructions, tools,
``default_options``, etc. live in your process — change them, restart, and
the next ``run`` picks them up. With the deployed prompt agent, those same
fields are versioned server-side: publishing a new version updates every
consumer at once and you keep an audit trail of previous versions, but you
must call ``create_version`` (or pin ``agent_version``) to roll changes
out or back.
* **Persistence / sharing.** A local ``Agent`` instance only exists for the
lifetime of the process that created it; tools and instructions are not
discoverable by anything else. A published prompt agent is a first-class
Foundry resource — other services, other languages, and the Foundry portal
can all bind to it by ``agent_name`` (+ optional ``agent_version``) and get
the same behaviour. Local ``@tool`` callables stay on the client; only
their JSON schema is persisted, so the implementation must be supplied
again at connection time via ``FoundryAgent(tools=[...])``.
``to_prompt_agent`` is experimental
(``ExperimentalFeature.TO_PROMPT_AGENT``) and may change before being released.
"""
@tool
def book_hotel(
city: Annotated[str, Field(description="The city to book the hotel in.")],
nights: Annotated[int, Field(description="Number of nights to stay.")],
) -> str:
"""Book a hotel room for the given city and number of nights."""
return f"Booked a hotel in {city} for {nights} nights. Confirmation #CTX-{randint(1000, 9999)}."
async def main() -> None:
print("=== Foundry Prompt Agent: Convert, Publish, Connect, and Run ===\n")
project_endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"]
model = os.environ["FOUNDRY_MODEL"]
# Use ``async with`` so the credential and project client are closed even if the
# body below raises. The ``try/finally`` around ``delete`` further guarantees we
# don't leave an orphaned prompt agent in the Foundry project after a failure.
async with (
AzureCliCredential() as credential,
AIProjectClient(endpoint=project_endpoint, credential=credential) as project_client,
):
# 1) Define the Agent. `name` / `description` set here become the Foundry agent identity
# on publish; `book_hotel` is the local implementation that backs the published declaration.
agent = Agent(
client=FoundryChatClient(
project_endpoint=project_endpoint,
model=model,
credential=credential,
),
name="travel-agent",
description="Helps Contoso employees book travel.",
instructions="You are a helpful travel assistant. Use the booking tool when asked.",
tools=[
FoundryChatClient.get_web_search_tool(),
book_hotel,
],
default_options={"reasoning": {"effort": "medium"}},
)
query = "Book me a hotel in Seattle for 3 nights."
# 2) Run the local Agent. This calls the Foundry Responses API directly — instructions,
# tools, and generation parameters live in this process only.
print(f"User (local Agent): {query}")
local_result = await agent.run(query)
print(f"Local Agent: {local_result}\n")
# 3) Convert and publish. The version returned by Foundry includes the version label
# we need when connecting back to that specific deployment.
if agent.name is None:
raise ValueError("Agent name is required to create a prompt agent version.")
created = await project_client.agents.create_version(
agent_name=agent.name,
# note this line:
definition=to_prompt_agent(agent),
description=agent.description,
)
print(f"Published prompt agent: {created.name} v{created.version}\n")
try:
# 4) Connect to the deployed prompt agent with FoundryAgent and pass the *same* callable
# tool. FoundryAgent runs the local function when the server-side agent invokes the tool,
# matching by name. Compared to step 2, instructions/tools/generation parameters now
# come from the stored PromptAgentDefinition rather than this process.
deployed = FoundryAgent(
project_endpoint=project_endpoint,
agent_name=created.name,
agent_version=created.version,
credential=credential,
tools=[book_hotel],
)
print(f"User (deployed agent): {query}")
deployed_result = await deployed.run(query)
print(f"Deployed Agent: {deployed_result}")
finally:
# 5) Cleanup: delete the deployed prompt agent (and all its versions) even if step 4
# raised, so re-running the sample stays idempotent and we don't leak resources in
# the Foundry project.
await project_client.agents.delete(agent_name=created.name)
print(f"\nDeleted prompt agent {created.name!r} and all its versions.")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,55 @@
# GitHub Copilot Agent Examples
This directory contains examples demonstrating how to use the `GitHubCopilotAgent` from the Microsoft Agent Framework.
> **Security Note**: These examples demonstrate various permission types (shell, read, write, url). Only enable permissions that are necessary for your use case. Each permission grants the agent additional capabilities that could affect your system.
## Prerequisites
1. **GitHub Copilot CLI**: Install and authenticate the Copilot CLI
2. **GitHub Copilot Subscription**: An active GitHub Copilot subscription
3. **Install the package**:
```bash
pip install agent-framework-github-copilot --pre
```
## Environment Variables
The following environment variables can be configured:
| Variable | Description | Default |
|----------|-------------|---------|
| `GITHUB_COPILOT_CLI_PATH` | Path to the Copilot CLI executable | `copilot` |
| `GITHUB_COPILOT_MODEL` | Model to use (e.g., "gpt-5", "claude-sonnet-4") | Server default |
| `GITHUB_COPILOT_TIMEOUT` | Request timeout in seconds | `60` |
| `GITHUB_COPILOT_LOG_LEVEL` | CLI log level | `info` |
| `GITHUB_COPILOT_BASE_DIRECTORY` | Directory for CLI session state and config | `~/.copilot` |
## Observability
`GitHubCopilotAgent` has OpenTelemetry tracing built-in. To enable it, call `configure_otel_providers()` before running the agent:
```python
from agent_framework.observability import configure_otel_providers
from agent_framework.github import GitHubCopilotAgent
configure_otel_providers(enable_console_exporters=True)
async with GitHubCopilotAgent() as agent:
response = await agent.run("Hello!")
```
See the [observability samples](../../../02-agents/observability/) for full examples with OTLP exporters.
## Examples
| File | Description |
|------|-------------|
| [`github_copilot_basic.py`](github_copilot_basic.py) | The simplest way to create an agent using `GitHubCopilotAgent`. Demonstrates both streaming and non-streaming responses with function tools. |
| [`github_copilot_with_session.py`](github_copilot_with_session.py) | Shows session management with automatic creation, persistence via session objects, and resuming sessions by ID. |
| [`github_copilot_with_shell.py`](github_copilot_with_shell.py) | Shows how to enable shell command execution permissions. Demonstrates running system commands like listing files and getting system information. |
| [`github_copilot_with_file_operations.py`](github_copilot_with_file_operations.py) | Shows how to enable file read and write permissions. Demonstrates reading file contents and creating new files. |
| [`github_copilot_with_url.py`](github_copilot_with_url.py) | Shows how to enable URL fetching permissions. Demonstrates fetching and processing web content. |
| [`github_copilot_with_mcp.py`](github_copilot_with_mcp.py) | Shows how to configure MCP (Model Context Protocol) servers, including local (stdio) and remote (HTTP) servers. |
| [`github_copilot_with_instruction_directories.py`](github_copilot_with_instruction_directories.py) | Shows how to configure custom instruction directories for project-specific or team-shared guidelines. |
| [`github_copilot_with_multiple_permissions.py`](github_copilot_with_multiple_permissions.py) | Shows how to combine multiple permission types for complex tasks that require shell, read, and write access. |
@@ -0,0 +1,123 @@
# Copyright (c) Microsoft. All rights reserved.
"""
GitHub Copilot Agent Basic Example
This sample demonstrates basic usage of GitHubCopilotAgent.
Shows both streaming and non-streaming responses with function tools.
Environment variables (optional):
- GITHUB_COPILOT_CLI_PATH - Path to the Copilot CLI executable
- GITHUB_COPILOT_MODEL - Model to use (e.g., "gpt-5", "claude-sonnet-4")
- GITHUB_COPILOT_TIMEOUT - Request timeout in seconds
- GITHUB_COPILOT_LOG_LEVEL - CLI log level
"""
import asyncio
from random import randint
from typing import Annotated
from agent_framework import tool
from agent_framework.github import GitHubCopilotAgent, GitHubCopilotOptions
from copilot.session import PermissionHandler
from dotenv import load_dotenv
from pydantic import Field
# Load environment variables from .env file
load_dotenv()
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production;
# see samples/02-agents/tools/function_tool_with_approval.py
# and samples/02-agents/tools/function_tool_with_approval_and_sessions.py.
@tool(approval_mode="never_require")
def get_weather(
location: Annotated[str, Field(description="The location to get the weather for.")],
) -> str:
"""Get the weather for a given location."""
conditions = ["sunny", "cloudy", "rainy", "stormy"]
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}C."
async def non_streaming_example() -> None:
"""Example of non-streaming response (get the complete result at once)."""
print("=== Non-streaming Response Example ===")
agent: GitHubCopilotAgent[GitHubCopilotOptions] = GitHubCopilotAgent(
instructions="You are a helpful weather agent.",
tools=[get_weather],
default_options=GitHubCopilotOptions(on_permission_request=PermissionHandler.approve_all),
)
async with agent:
query = "What's the weather like in Seattle?"
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result}\n")
async def streaming_example() -> None:
"""Example of streaming response (get results as they are generated)."""
print("=== Streaming Response Example ===")
agent: GitHubCopilotAgent[GitHubCopilotOptions] = GitHubCopilotAgent(
instructions="You are a helpful weather agent.",
tools=[get_weather],
default_options=GitHubCopilotOptions(on_permission_request=PermissionHandler.approve_all),
)
async with agent:
query = "What's the weather like in Tokyo?"
print(f"User: {query}")
print("Agent: ", end="", flush=True)
async for chunk in agent.run(query, stream=True):
if chunk.text:
print(chunk.text, end="", flush=True)
print("\n")
async def runtime_options_example() -> None:
"""Example of overriding system message at runtime."""
print("=== Runtime Options Example ===")
agent: GitHubCopilotAgent[GitHubCopilotOptions] = GitHubCopilotAgent(
instructions="Always respond in exactly 3 words.",
tools=[get_weather],
default_options=GitHubCopilotOptions(on_permission_request=PermissionHandler.approve_all),
)
async with agent:
query = "What's the weather like in Paris?"
# First call uses default instructions (3 words response)
print("Using default instructions (3 words):")
print(f"User: {query}")
result1 = await agent.run(query)
print(f"Agent: {result1}\n")
# Second call overrides with runtime system_message in replace mode
print("Using runtime system_message with replace mode (detailed response):")
print(f"User: {query}")
result2 = await agent.run( # pyright: ignore[reportCallIssue]
query,
options=GitHubCopilotOptions( # pyright: ignore[reportArgumentType]
system_message={
"mode": "replace",
"content": "You are a weather expert. Provide detailed weather information "
"with temperature, and recommendations.",
}
),
)
print(f"Agent: {result2}\n")
async def main() -> None:
print("=== Basic GitHub Copilot Agent Example ===")
await non_streaming_example()
await streaming_example()
await runtime_options_example()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,47 @@
# Copyright (c) Microsoft. All rights reserved.
"""
GitHub Copilot Agent with File Operation Permissions
This sample demonstrates how to enable file read and write operations with GitHubCopilotAgent.
By providing a permission handler, the agent can read from and write to files on the filesystem.
SECURITY NOTE: Only enable file permissions when you trust the agent's actions.
- "read" allows the agent to read any accessible file
- "write" allows the agent to create or modify files
"""
import asyncio
from agent_framework.github import GitHubCopilotAgent, GitHubCopilotOptions
from copilot.generated.rpc import PermissionDecisionDeniedInteractivelyByUser
from copilot.session import PermissionHandler, PermissionRequestResult
from copilot.session_events import PermissionRequest
async def prompt_permission(request: PermissionRequest, context: dict[str, str]) -> PermissionRequestResult:
"""Permission handler that prompts the user for approval."""
print(f"\n[Permission Request: {request.kind}]")
response = (await asyncio.to_thread(input, "Approve? (y/n): ")).strip().lower()
if response in ("y", "yes"):
return PermissionHandler.approve_all(request, context)
return PermissionDecisionDeniedInteractivelyByUser()
async def main() -> None:
print("=== GitHub Copilot Agent with File Operation Permissions ===\n")
agent: GitHubCopilotAgent[GitHubCopilotOptions] = GitHubCopilotAgent(
instructions="You are a helpful assistant that can read and write files.",
default_options=GitHubCopilotOptions(on_permission_request=prompt_permission),
)
async with agent:
query = "Read the contents of README.md and summarize it"
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result}\n")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,148 @@
# Copyright (c) Microsoft. All rights reserved.
"""
GitHub Copilot Agent with Function Approval
This sample demonstrates how ``approval_mode="always_require"`` on a
``FunctionTool`` is enforced when using ``GitHubCopilotAgent``. Because the
Copilot CLI runs its own tool-calling loop, approval is enforced through the
Copilot SDK's native pre-execution hook (``on_pre_tool_use``) rather than the
standard agent-framework approval round-trip.
How it works:
- When you register a tool declared with ``approval_mode="always_require"`` and
you do **not** supply your own ``on_pre_tool_use`` hook, the agent installs a
default ``on_pre_tool_use`` hook that returns ``"ask"`` for that tool and
defers (``None``) for all other tools.
- The ``"ask"`` decision routes to your ``on_permission_request`` handler, where
you approve or deny the call. With the default deny-all permission handler,
such a tool is therefore denied unless you wire an approving handler.
- If you supply your own ``on_pre_tool_use`` hook, it takes precedence and you
are responsible for enforcing approval; the agent logs a warning naming any
approval-required tool that your hook must handle.
Environment variables (optional):
- GITHUB_COPILOT_CLI_PATH: Path to the Copilot CLI executable.
- GITHUB_COPILOT_MODEL: Model to use.
"""
import asyncio
from random import randrange
from typing import Annotated
from agent_framework import tool
from agent_framework.github import GitHubCopilotAgent, GitHubCopilotOptions
from copilot.generated.rpc import PermissionDecisionReject
from copilot.session import (
PermissionHandler,
PermissionRequestResult,
PreToolUseHookInput,
PreToolUseHookOutput,
)
from copilot.session_events import PermissionRequest
from dotenv import load_dotenv
load_dotenv()
INSTRUCTIONS = (
"You are a helpful weather assistant. Always answer weather questions by calling the "
"get_weather_detail tool. Do not browse the web or use any other source."
)
# Always-require tool: execution is gated by the default on_pre_tool_use hook,
# which routes the decision to on_permission_request.
@tool(approval_mode="always_require")
def get_weather_detail(location: Annotated[str, "The city and state, e.g. San Francisco, CA"]) -> str:
"""Get a detailed weather report for a location."""
conditions = ["sunny", "cloudy", "rainy", "stormy"]
return (
f"The weather in {location} is {conditions[randrange(0, len(conditions))]} "
f"with a high of {randrange(10, 30)}C and humidity of 88%."
)
def approve_all_requests(request: PermissionRequest, context: dict[str, str]) -> PermissionRequestResult:
"""Permission handler that approves every request, including the gated tool."""
print(f"\n [Permission requested: {request.kind}] -> approved")
return PermissionHandler.approve_all(request, context)
def deny_all_requests(request: PermissionRequest, _context: dict[str, str]) -> PermissionRequestResult:
"""Permission handler that denies every request."""
print(f"\n [Permission requested: {request.kind}] -> denied")
return PermissionDecisionReject(feedback="Denied by the operator's policy.")
async def run_with_approval() -> None:
"""The approval-required tool runs because on_permission_request approves it."""
print("\n=== GitHub Copilot Agent: approval-required tool (approved) ===")
agent: GitHubCopilotAgent[GitHubCopilotOptions] = GitHubCopilotAgent(
instructions=INSTRUCTIONS,
tools=[get_weather_detail],
default_options=GitHubCopilotOptions(on_permission_request=approve_all_requests),
)
async with agent:
query = "Give me the detailed weather for Seattle."
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result}")
async def run_with_denial() -> None:
"""The approval-required tool is blocked because on_permission_request denies it."""
print("\n=== GitHub Copilot Agent: approval-required tool (denied) ===")
agent: GitHubCopilotAgent[GitHubCopilotOptions] = GitHubCopilotAgent(
instructions=INSTRUCTIONS,
tools=[get_weather_detail],
default_options=GitHubCopilotOptions(on_permission_request=deny_all_requests),
)
async with agent:
query = "Give me the detailed weather for Paris."
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result}")
async def run_with_custom_hook() -> None:
"""A caller-supplied on_pre_tool_use hook takes precedence over the default.
When you provide your own hook you own approval enforcement entirely, so the
agent does not install its default ask-hook and logs a warning naming any
``always_require`` tool it will no longer auto-gate. Here the custom hook
approves the tool directly by returning ``"allow"`` — note that, unlike the
default ``"ask"`` flow, this does not route through ``on_permission_request``
(so no permission request is raised for the tool).
"""
print("\n=== GitHub Copilot Agent: custom on_pre_tool_use hook (takes precedence) ===")
def my_pre_tool_use(hook_input: PreToolUseHookInput, _context: dict[str, str]) -> PreToolUseHookOutput | None:
if hook_input.get("toolName") == "get_weather_detail":
return {"permissionDecision": "allow", "permissionDecisionReason": "Allowed by custom policy."}
return None
agent: GitHubCopilotAgent[GitHubCopilotOptions] = GitHubCopilotAgent(
instructions=INSTRUCTIONS,
tools=[get_weather_detail],
default_options=GitHubCopilotOptions(
on_pre_tool_use=my_pre_tool_use,
on_permission_request=approve_all_requests,
),
)
async with agent:
query = "Give me the detailed weather for Tokyo."
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result}")
async def main() -> None:
print("=== GitHub Copilot Agent: Function approval enforcement ===")
await run_with_approval()
await run_with_denial()
await run_with_custom_hook()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,126 @@
# Copyright (c) Microsoft. All rights reserved.
"""
GitHub Copilot Agent with Instruction Directories
This sample demonstrates how to configure custom instruction directories with
GitHubCopilotAgent. Instruction directories let the CLI load project-specific
or team-shared instruction files that shape the agent's behavior beyond the
default system message.
Use cases:
- Point the agent at a team-shared set of coding conventions.
- Load project-specific guidelines from a local `.copilot/instructions/` folder.
- Override or augment default instructions per session at runtime.
Environment variables (optional):
- GITHUB_COPILOT_CLI_PATH - Path to the Copilot CLI executable
- GITHUB_COPILOT_MODEL - Model to use (e.g., "gpt-5", "claude-sonnet-4")
"""
import asyncio
from pathlib import Path
from agent_framework.github import GitHubCopilotAgent, GitHubCopilotOptions
from copilot.session import PermissionHandler
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
async def default_instructions_example() -> None:
"""Example of pointing the agent at project-specific instruction directories."""
print("=== Instruction Directories (Default) ===\n")
# 1. Define instruction directories.
# These paths contain custom instruction files the CLI will load
# alongside its built-in instructions.
project_root = Path.cwd()
instruction_dirs = [
str(project_root / ".copilot" / "instructions"),
str(project_root / "docs" / "agent-guidelines"),
]
# 2. Create the agent with instruction directories in default_options.
# These directories apply to every session created by this agent.
agent: GitHubCopilotAgent[GitHubCopilotOptions] = GitHubCopilotAgent(
instructions="You are a helpful coding assistant.",
default_options=GitHubCopilotOptions(
on_permission_request=PermissionHandler.approve_all,
instruction_directories=instruction_dirs,
),
)
# 3. Run the agent — instruction files from those directories are loaded
# automatically by the CLI when the session starts.
async with agent:
query = "Summarize the coding conventions I should follow in this project."
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result}\n")
async def runtime_override_example() -> None:
"""Example of overriding instruction directories at runtime."""
print("=== Instruction Directories (Runtime Override) ===\n")
agent: GitHubCopilotAgent[GitHubCopilotOptions] = GitHubCopilotAgent(
instructions="You are a helpful assistant.",
default_options=GitHubCopilotOptions(
on_permission_request=PermissionHandler.approve_all,
instruction_directories=["/team/shared/instructions"],
),
)
async with agent:
# First call uses the default instruction directories
query = "What instructions are you following?"
print(f"User: {query}")
result1 = await agent.run(query)
print(f"Agent: {result1}\n")
# Second call overrides with different instruction directories at runtime.
# Runtime options take precedence over the defaults for that session.
print("Overriding with project-specific instructions...\n")
query2 = "Now what instructions are you following?"
print(f"User: {query2}")
result2 = await agent.run( # pyright: ignore[reportCallIssue]
query2,
options=GitHubCopilotOptions( # pyright: ignore[reportArgumentType]
instruction_directories=["/project/specific/instructions"],
),
)
print(f"Agent: {result2}\n")
async def main() -> None:
print("=== GitHub Copilot Agent with Instruction Directories ===\n")
await default_instructions_example()
await runtime_override_example()
if __name__ == "__main__":
asyncio.run(main())
"""
Sample output:
=== GitHub Copilot Agent with Instruction Directories ===
=== Instruction Directories (Default) ===
User: Summarize the coding conventions I should follow in this project.
Agent: Based on the project instructions, you should follow these conventions...
=== Instruction Directories (Runtime Override) ===
User: What instructions are you following?
Agent: I'm following the team-shared coding guidelines which include...
Overriding with project-specific instructions...
User: Now what instructions are you following?
Agent: I'm now following the project-specific instructions which include...
"""
@@ -0,0 +1,72 @@
# Copyright (c) Microsoft. All rights reserved.
"""
GitHub Copilot Agent with MCP Servers
This sample demonstrates how to configure MCP (Model Context Protocol) servers
with GitHubCopilotAgent. It shows both local (stdio) and remote (HTTP) server
configurations, giving the agent access to external tools and data sources.
SECURITY NOTE: MCP servers can expose powerful capabilities. Only configure
servers you trust. The permission handler below prompts the user for approval
of MCP-related actions.
"""
import asyncio
from agent_framework.github import GitHubCopilotAgent, GitHubCopilotOptions
from copilot.session import MCPServerConfig, PermissionHandler
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
async def main() -> None:
print("=== GitHub Copilot Agent with MCP Servers ===\n")
# Configure both local and remote MCP servers
mcp_servers: dict[str, MCPServerConfig] = {
# Local stdio server: provides filesystem access tools
"filesystem": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "."],
"tools": ["*"],
},
# Remote HTTP server: Microsoft Learn documentation
"microsoft-learn": {
"type": "http",
"url": "https://learn.microsoft.com/api/mcp",
"tools": ["*"],
},
}
agent: GitHubCopilotAgent[GitHubCopilotOptions] = GitHubCopilotAgent(
instructions="You are a helpful assistant with access to the local filesystem and Microsoft Learn.",
default_options=GitHubCopilotOptions(
on_permission_request=PermissionHandler.approve_all,
mcp_servers=mcp_servers,
),
)
async with agent:
# Query that exercises the local filesystem MCP server
query1 = "List the files in the current directory"
print(f"User: {query1}")
result1 = await agent.run(query1)
print(f"Agent: {result1}\n")
# Query that exercises the remote Microsoft Learn MCP server
# Remote MCP calls may take longer, so increase the timeout
query2 = "Search Microsoft Learn for 'Azure Functions Python' and summarize the top result"
print(f"User: {query2}")
result2 = await agent.run( # pyright: ignore[reportCallIssue]
query2,
options=GitHubCopilotOptions(timeout=120), # pyright: ignore[reportArgumentType]
)
print(f"Agent: {result2}\n")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,49 @@
# Copyright (c) Microsoft. All rights reserved.
"""
GitHub Copilot Agent with Multiple Permissions
This sample demonstrates how multiple permission types are requested when GitHubCopilotAgent
performs complex tasks that require different capabilities.
Available permission kinds:
- "shell": Execute shell commands
- "read": Read files from the filesystem
- "write": Write files to the filesystem
- "mcp": Use MCP (Model Context Protocol) servers
- "url": Fetch content from URLs
SECURITY NOTE: Only enable permissions that are necessary for your use case.
More permissions mean more potential for unintended actions.
"""
import asyncio
from agent_framework.github import GitHubCopilotAgent, GitHubCopilotOptions
from copilot.session import PermissionHandler, PermissionRequestResult
from copilot.session_events import PermissionRequest
def approve_and_log(request: PermissionRequest, context: dict[str, str]) -> PermissionRequestResult:
"""Permission handler that auto-approves and logs each permission kind."""
print(f" [Permission: {request.kind}]", flush=True)
return PermissionHandler.approve_all(request, context)
async def main() -> None:
print("=== GitHub Copilot Agent with Multiple Permissions ===\n")
agent: GitHubCopilotAgent[GitHubCopilotOptions] = GitHubCopilotAgent(
instructions="You are a helpful development assistant that can read, write files and run commands.",
default_options=GitHubCopilotOptions(on_permission_request=approve_and_log),
)
async with agent:
query = "List the first 3 Python files, then read the first one and create a summary in summary.txt"
print(f"User: {query}\n")
result = await agent.run(query)
print(f"\nAgent: {result}\n")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,147 @@
# Copyright (c) Microsoft. All rights reserved.
"""
GitHub Copilot Agent with Session Management
This sample demonstrates session management with GitHubCopilotAgent, showing
persistent conversation capabilities. Sessions are automatically persisted
server-side by the Copilot CLI.
"""
import asyncio
from random import randint
from typing import Annotated
from agent_framework import tool
from agent_framework.github import GitHubCopilotAgent, GitHubCopilotOptions
from copilot.session import PermissionHandler
from pydantic import Field
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production;
# see samples/02-agents/tools/function_tool_with_approval.py
# and samples/02-agents/tools/function_tool_with_approval_and_sessions.py.
@tool(approval_mode="never_require")
def get_weather(
location: Annotated[str, Field(description="The location to get the weather for.")],
) -> str:
"""Get the weather for a given location."""
conditions = ["sunny", "cloudy", "rainy", "stormy"]
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C."
async def example_with_automatic_session_creation() -> None:
"""Each run() without thread creates a new session."""
print("=== Automatic Session Creation Example ===")
agent: GitHubCopilotAgent[GitHubCopilotOptions] = GitHubCopilotAgent(
instructions="You are a helpful weather agent.",
tools=[get_weather],
default_options=GitHubCopilotOptions(on_permission_request=PermissionHandler.approve_all),
)
async with agent:
# First query - creates a new session
query1 = "What's the weather like in Seattle?"
print(f"User: {query1}")
result1 = await agent.run(query1)
print(f"Agent: {result1}")
# Second query - without thread, creates another new session
query2 = "What was the last city I asked about?"
print(f"\nUser: {query2}")
result2 = await agent.run(query2)
print(f"Agent: {result2}")
print("Note: Each call creates a separate session, so the agent may not remember previous context.\n")
async def example_with_session_persistence() -> None:
"""Reuse session via thread object for multi-turn conversations."""
print("=== Session Persistence Example ===")
agent: GitHubCopilotAgent[GitHubCopilotOptions] = GitHubCopilotAgent(
instructions="You are a helpful weather agent.",
tools=[get_weather],
default_options=GitHubCopilotOptions(on_permission_request=PermissionHandler.approve_all),
)
async with agent:
# Create a session to maintain conversation context
session = agent.create_session()
# First query
query1 = "What's the weather like in Tokyo?"
print(f"User: {query1}")
result1 = await agent.run(query1, session=session)
print(f"Agent: {result1}")
# Second query - using same thread maintains context
query2 = "How about London?"
print(f"\nUser: {query2}")
result2 = await agent.run(query2, session=session)
print(f"Agent: {result2}")
# Third query - agent should remember both previous cities
query3 = "Which of the cities I asked about has better weather?"
print(f"\nUser: {query3}")
result3 = await agent.run(query3, session=session)
print(f"Agent: {result3}")
print("Note: The agent remembers context from previous messages in the same session.\n")
async def example_with_existing_session_id() -> None:
"""Resume session in new agent instance using service_session_id."""
print("=== Existing Session ID Example ===")
existing_session_id = None
# First agent instance - start a conversation
agent1 = GitHubCopilotAgent(
instructions="You are a helpful weather agent.",
tools=[get_weather],
default_options=GitHubCopilotOptions(on_permission_request=PermissionHandler.approve_all),
)
async with agent1:
session = agent1.create_session()
query1 = "What's the weather in Paris?"
print(f"User: {query1}")
result1 = await agent1.run(query1, session=session)
print(f"Agent: {result1}")
# Capture the session ID for later use
existing_session_id = session.service_session_id
print(f"Session ID: {existing_session_id}")
if existing_session_id:
print("\n--- Continuing with the same session ID in a new agent instance ---")
# Second agent instance - resume the conversation
agent2 = GitHubCopilotAgent(
instructions="You are a helpful weather agent.",
tools=[get_weather],
default_options=GitHubCopilotOptions(on_permission_request=PermissionHandler.approve_all),
)
async with agent2:
# Get session with existing session ID
session = agent2.get_session(service_session_id=existing_session_id)
query2 = "What was the last city I asked about?"
print(f"User: {query2}")
result2 = await agent2.run(query2, session=session)
print(f"Agent: {result2}")
print("Note: The agent continues the conversation using the session ID.\n")
async def main() -> None:
print("=== GitHub Copilot Agent Session Management Examples ===\n")
await example_with_automatic_session_creation()
await example_with_session_persistence()
await example_with_existing_session_id()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,49 @@
# Copyright (c) Microsoft. All rights reserved.
"""
GitHub Copilot Agent with Shell Permissions
This sample demonstrates how to enable shell command execution with GitHubCopilotAgent.
By providing a permission handler that approves "shell" requests, the agent can execute
shell commands to perform tasks like listing files, running scripts, or executing system commands.
SECURITY NOTE: Only enable shell permissions when you trust the agent's actions.
Shell commands have full access to your system within the permissions of the running process.
"""
import asyncio
from agent_framework.github import GitHubCopilotAgent, GitHubCopilotOptions
from copilot.generated.rpc import PermissionDecisionUserNotAvailable
from copilot.session import PermissionHandler, PermissionRequestResult
from copilot.session_events import PermissionRequest
def approve_and_log(request: PermissionRequest, context: dict[str, str]) -> PermissionRequestResult:
"""Permission handler that approves only shell commands and logs them."""
if request.kind == "shell":
print(f"\n [Permission: {request.kind}]", flush=True)
command = getattr(request, "full_command_text", None)
if command is not None:
print(f" Command: {command}", flush=True)
return PermissionHandler.approve_all(request, context)
return PermissionDecisionUserNotAvailable()
async def main() -> None:
print("=== GitHub Copilot Agent with Shell Permissions ===\n")
agent: GitHubCopilotAgent[GitHubCopilotOptions] = GitHubCopilotAgent(
instructions="You are a helpful assistant that can execute shell commands.",
default_options=GitHubCopilotOptions(on_permission_request=approve_and_log),
)
async with agent:
query = "List the first 3 Python files in the current directory"
print(f"User: {query}")
result = await agent.run(query)
print(f"\nAgent: {result}\n")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,49 @@
# Copyright (c) Microsoft. All rights reserved.
"""
GitHub Copilot Agent with URL Fetching
This sample demonstrates how to enable URL fetching with GitHubCopilotAgent.
By providing a permission handler that approves "url" requests, the agent can
fetch and process content from web URLs.
SECURITY NOTE: Only enable URL permissions when you trust the agent's actions.
URL fetching allows the agent to access any URL accessible from your network.
"""
import asyncio
from agent_framework.github import GitHubCopilotAgent, GitHubCopilotOptions
from copilot.generated.rpc import PermissionDecisionUserNotAvailable
from copilot.session import PermissionHandler, PermissionRequestResult
from copilot.session_events import PermissionRequest
def approve_and_log(request: PermissionRequest, context: dict[str, str]) -> PermissionRequestResult:
"""Permission handler that approves only URL requests and logs them."""
if request.kind == "url":
print(f"\n [Permission: {request.kind}]", flush=True)
url = getattr(request, "url", None)
if url is not None:
print(f" URL: {url}", flush=True)
return PermissionHandler.approve_all(request, context)
return PermissionDecisionUserNotAvailable()
async def main() -> None:
print("=== GitHub Copilot Agent with URL Fetching ===\n")
agent: GitHubCopilotAgent[GitHubCopilotOptions] = GitHubCopilotAgent(
instructions="You are a helpful assistant that can fetch and summarize web content.",
default_options=GitHubCopilotOptions(on_permission_request=approve_and_log),
)
async with agent:
query = "Fetch https://learn.microsoft.com/agent-framework/tutorials/quick-start and summarize its contents"
print(f"User: {query}")
result = await agent.run(query)
print(f"\nAgent: {result}\n")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,56 @@
# Ollama Examples
This folder contains examples demonstrating how to use Ollama models with the Agent Framework.
## Prerequisites
1. **Install Ollama**: Download and install Ollama from [ollama.com](https://ollama.com/)
2. **Start Ollama**: Ensure Ollama is running on your local machine
3. **Pull a model**: Run `ollama pull mistral` (or any other model you prefer)
- For function calling examples, use models that support tool calling like `mistral` or `qwen2.5`
- For reasoning examples, use models that support reasoning like `qwen3:8b`
- For multimodal examples, use models like `gemma3:4b`
> **Note**: Not all models support all features. Function calling, reasoning, and multimodal capabilities depend on the specific model you're using.
## Recommended Approach
The recommended way to use Ollama with Agent Framework is via the native `OllamaChatClient` from the `agent-framework-ollama` package. This provides full support for Ollama-specific features like reasoning mode.
Alternatively, you can use the `OpenAIChatClient` configured to point to your local Ollama server, which may be useful if you're already familiar with the OpenAI client interface.
## Examples
| File | Description |
|------|-------------|
| [`ollama_agent_basic.py`](ollama_agent_basic.py) | Basic Ollama agent with tool calling using native Ollama Chat Client. Shows both streaming and non-streaming responses. |
| [`ollama_agent_reasoning.py`](ollama_agent_reasoning.py) | Ollama agent with reasoning capabilities using native Ollama Chat Client. Shows how to enable thinking/reasoning mode. |
| [`ollama_chat_client.py`](ollama_chat_client.py) | Direct usage of the native Ollama Chat Client with tool calling. |
| [`ollama_chat_multimodal.py`](ollama_chat_multimodal.py) | Ollama Chat Client with multimodal (image) input capabilities. |
| [`ollama_with_openai_chat_client.py`](ollama_with_openai_chat_client.py) | Alternative approach using OpenAI Chat Client configured to use local Ollama models. |
## Configuration
The examples use environment variables for configuration. Set the appropriate variables based on which example you're running:
### For Native Ollama Examples
Set the following environment variables:
- `OLLAMA_HOST`: The base URL for your Ollama server (optional, defaults to `http://localhost:11434`)
- Example: `export OLLAMA_HOST="http://localhost:11434"`
- `OLLAMA_MODEL`: The model name to use
- Example: `export OLLAMA_MODEL="qwen2.5:8b"`
- Must be a model you have pulled with Ollama
### For OpenAI Client with Ollama (`ollama_with_openai_chat_client.py`)
Set the following environment variables:
- `OLLAMA_ENDPOINT`: The base URL for your Ollama server with `/v1/` suffix
- Example: `export OLLAMA_ENDPOINT="http://localhost:11434/v1/"`
- `OLLAMA_MODEL`: The model name to use
- Example: `export OLLAMA_MODEL="mistral"`
- Must be a model you have pulled with Ollama
@@ -0,0 +1,79 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from datetime import datetime
from agent_framework import Agent, tool
from agent_framework.ollama import OllamaChatClient
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
"""
Ollama Agent Basic Example
This sample demonstrates implementing a Ollama agent with basic tool usage.
Ensure to install Ollama and have a model running locally before running the sample
Not all Models support function calling, to test function calling try llama3.2 or qwen3:4b
Set the model to use via the OLLAMA_MODEL environment variable or modify the code below.
https://ollama.com/
"""
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production;
# see samples/02-agents/tools/function_tool_with_approval.py
# and samples/02-agents/tools/function_tool_with_approval_and_sessions.py.
@tool(approval_mode="never_require")
def get_time(location: str) -> str:
"""Get the current time."""
return f"The current time in {location} is {datetime.now().strftime('%I:%M %p')}."
async def non_streaming_example() -> None:
"""Example of non-streaming response (get the complete result at once)."""
print("=== Non-streaming Response Example ===")
agent = Agent(
client=OllamaChatClient(),
name="TimeAgent",
instructions="You are a helpful time agent answer in one sentence.",
tools=get_time,
)
query = "What time is it in Seattle? Use a tool call"
print(f"User: {query}")
result = await agent.run(query)
print(f"Result: {result}\n")
async def streaming_example() -> None:
"""Example of streaming response (get results as they are generated)."""
print("=== Streaming Response Example ===")
agent = Agent(
client=OllamaChatClient(),
name="TimeAgent",
instructions="You are a helpful time agent answer in one sentence.",
tools=get_time,
)
query = "What time is it in San Francisco? Use a tool call"
print(f"User: {query}")
print("Agent: ", end="", flush=True)
async for chunk in agent.run(query, stream=True):
if chunk.text:
print(chunk.text, end="", flush=True)
print("\n")
async def main() -> None:
print("=== Basic Ollama Chat Client Agent Example ===")
await non_streaming_example()
await streaming_example()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,44 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from agent_framework import Agent
from agent_framework.ollama import OllamaChatClient
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
"""
Ollama Agent Reasoning Example
This sample demonstrates implementing a Ollama agent with reasoning.
Ensure to install Ollama and have a model running locally before running the sample
Not all Models support reasoning, to test reasoning try qwen3:8b
Set the model to use via the OLLAMA_MODEL environment variable or modify the code below.
https://ollama.com/
"""
async def main() -> None:
print("=== Response Reasoning Example ===")
agent = Agent(
client=OllamaChatClient(),
name="TimeAgent",
instructions="You are a helpful agent answer in one sentence.",
default_options={"think": True}, # Enable Reasoning on agent level
)
query = "Hey what is 3+4? Can you explain how you got to that answer?"
print(f"User: {query}")
# Enable Reasoning on per request level
result = await agent.run(query)
reasoning = "".join((c.text or "") for c in result.messages[-1].contents if c.type == "text_reasoning")
print(f"Reasoning: {reasoning}")
print(f"Answer: {result}\n")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,53 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from datetime import datetime
from agent_framework import Message, tool
from agent_framework.ollama import OllamaChatClient
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
"""
Ollama Chat Client Example
This sample demonstrates using the native Ollama Chat Client directly.
Ensure to install Ollama and have a model running locally before running the sample.
Not all Models support function calling, to test function calling try llama3.2
Set the model to use via the OLLAMA_MODEL environment variable or modify the code below.
https://ollama.com/
"""
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production;
# see samples/02-agents/tools/function_tool_with_approval.py
# and samples/02-agents/tools/function_tool_with_approval_and_sessions.py.
@tool(approval_mode="never_require")
def get_time():
"""Get the current time."""
return f"The current time is {datetime.now().strftime('%I:%M %p')}."
async def main() -> None:
client = OllamaChatClient()
message = "What time is it? Use a tool call"
messages = [Message(role="user", contents=[message])]
stream = False
print(f"User: {message}")
if stream:
print("Assistant: ", end="")
async for chunk in client.get_response(messages, options={"tools": [get_time]}, stream=True):
if str(chunk):
print(str(chunk), end="")
print("")
else:
response = await client.get_response(messages, options={"tools": [get_time]})
print(f"Assistant: {response}")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,57 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from agent_framework import Content, Message
from agent_framework.ollama import OllamaChatClient
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
"""
Ollama Agent Multimodal Example
This sample demonstrates implementing a Ollama agent with multimodal input capabilities.
Ensure to install Ollama and have a model running locally before running the sample
Not all Models support multimodal input, to test multimodal input try gemma3:4b
Set the model to use via the OLLAMA_MODEL environment variable or modify the code below.
https://ollama.com/
"""
def create_sample_image() -> str:
"""Create a simple 1x1 pixel PNG image for testing."""
# This is a tiny red pixel in PNG format
png_data = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg=="
return f"data:image/png;base64,{png_data}"
async def test_image() -> None:
"""Test image analysis with Ollama."""
client = OllamaChatClient()
image_uri = create_sample_image()
message = Message(
role="user",
contents=[
Content.from_text(text="What's in this image?"),
Content.from_uri(uri=image_uri, media_type="image/png"),
],
)
response = await client.get_response([message])
print(f"Image Response: {response}")
async def main() -> None:
print("=== Testing Ollama Multimodal ===")
await test_image()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,95 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from random import randint
from typing import Annotated
from agent_framework import Agent, tool
from agent_framework.openai import OpenAIChatClient
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
"""
Ollama with OpenAI Chat Client Example
This sample demonstrates using Ollama models through OpenAI Chat Client by
configuring the base URL to point to your local Ollama server for local AI inference.
Ollama allows you to run large language models locally on your machine.
Environment Variables:
- OLLAMA_ENDPOINT: The base URL for your Ollama server (e.g., "http://localhost:11434/v1/")
- OLLAMA_MODEL: The model name to use (e.g., "mistral", "llama3.2", "phi3")
"""
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production;
# see samples/02-agents/tools/function_tool_with_approval.py
# and samples/02-agents/tools/function_tool_with_approval_and_sessions.py.
@tool(approval_mode="never_require")
def get_weather(
location: Annotated[str, "The location to get the weather for."],
) -> str:
"""Get the weather for a given location."""
conditions = ["sunny", "cloudy", "rainy", "stormy"]
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C."
async def non_streaming_example() -> None:
"""Example of non-streaming response (get the complete result at once)."""
print("=== Non-streaming Response Example ===")
_client = OpenAIChatClient(
api_key="ollama", # Just a placeholder, Ollama doesn't require API key
base_url=os.getenv("OLLAMA_ENDPOINT"),
model=os.getenv("OLLAMA_MODEL"),
)
agent = Agent(
client=_client,
name="WeatherAgent",
instructions="You are a helpful weather agent.",
tools=[get_weather],
)
query = "What's the weather like in Seattle?"
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result}\n")
async def streaming_example() -> None:
"""Example of streaming response (get results as they are generated)."""
print("=== Streaming Response Example ===")
_client = OpenAIChatClient(
api_key="ollama", # Just a placeholder, Ollama doesn't require API key
base_url=os.getenv("OLLAMA_ENDPOINT"),
model=os.getenv("OLLAMA_MODEL"),
)
agent = Agent(
client=_client,
name="WeatherAgent",
instructions="You are a helpful weather agent.",
tools=[get_weather],
)
query = "What's the weather like in Portland?"
print(f"User: {query}")
print("Agent: ", end="", flush=True)
async for chunk in agent.run(query, stream=True):
if chunk.text:
print(chunk.text, end="", flush=True)
print("\n")
async def main() -> None:
print("=== Ollama with OpenAI Chat Client Agent Example ===")
await non_streaming_example()
await streaming_example()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,64 @@
# OpenAI Provider Samples
This folder contains OpenAI provider samples for the generic clients in
`agent_framework.openai`.
## Chat Completions API samples (`OpenAIChatCompletionClient`)
| File | Description |
|------|-------------|
| [`chat_completion_client_basic.py`](chat_completion_client_basic.py) | Basic non-streaming and streaming chat completion sample with an explicit `gpt-5.4-nano` model and API key. |
| [`chat_completion_client_with_explicit_settings.py`](chat_completion_client_with_explicit_settings.py) | Chat completion sample with explicit model and API key settings. |
| [`chat_completion_client_with_function_tools.py`](chat_completion_client_with_function_tools.py) | Function tools with agent-level and run-level patterns. |
| [`chat_completion_client_with_local_mcp.py`](chat_completion_client_with_local_mcp.py) | Local MCP integration with the chat completions client. |
| [`chat_completion_client_with_runtime_json_schema.py`](chat_completion_client_with_runtime_json_schema.py) | Runtime JSON schema output with the chat completions client. |
| [`chat_completion_client_with_session.py`](chat_completion_client_with_session.py) | Session management with the chat completions client. |
| [`chat_completion_client_with_web_search.py`](chat_completion_client_with_web_search.py) | Web search with the chat completions client. |
## Responses API samples (`OpenAIChatClient`)
| File | Description |
|------|-------------|
| [`client_basic.py`](client_basic.py) | Basic non-streaming and streaming responses sample with an explicit `gpt-5.4-nano` model and API key. |
| [`client_image_analysis.py`](client_image_analysis.py) | Analyze images with the responses client. |
| [`client_image_generation.py`](client_image_generation.py) | Generate images from text prompts. |
| [`client_reasoning.py`](client_reasoning.py) | Reasoning-focused sample for models such as `gpt-5`. |
| [`client_streaming_image_generation.py`](client_streaming_image_generation.py) | Streaming image generation sample. |
| [`client_verbosity.py`](client_verbosity.py) | GPT-5 `verbosity` option (`low`/`medium`/`high`) with default and per-call overrides. |
| [`client_with_agent_as_tool.py`](client_with_agent_as_tool.py) | Agent-as-tool orchestration pattern. |
| [`client_with_code_interpreter.py`](client_with_code_interpreter.py) | Code interpreter sample. |
| [`client_with_code_interpreter_files.py`](client_with_code_interpreter_files.py) | Code interpreter sample with uploaded files. |
| [`client_with_explicit_settings.py`](client_with_explicit_settings.py) | Responses client with explicit model and API key settings. |
| [`client_with_file_search.py`](client_with_file_search.py) | Hosted file search sample. |
| [`client_with_function_tools.py`](client_with_function_tools.py) | Function tools with agent-level and run-level patterns. |
| [`client_with_hosted_mcp.py`](client_with_hosted_mcp.py) | Hosted MCP tools and approval workflows. |
| [`client_with_local_mcp.py`](client_with_local_mcp.py) | Local MCP integration with the responses client. |
| [`client_with_local_shell.py`](client_with_local_shell.py) | Local shell tool sample. |
| [`client_with_runtime_json_schema.py`](client_with_runtime_json_schema.py) | Runtime JSON schema output with the responses client. |
| [`client_with_session.py`](client_with_session.py) | Session management with the responses client. |
| [`client_with_shell.py`](client_with_shell.py) | Hosted shell tool sample. |
| [`client_with_structured_output.py`](client_with_structured_output.py) | Structured output with Pydantic models. |
| [`client_with_web_search.py`](client_with_web_search.py) | Web search with the responses client. |
## Environment Variables
Set these before running the OpenAI provider samples:
- `OPENAI_API_KEY`
- `OPENAI_MODEL`
Optionally, you can also set:
- `OPENAI_ORG_ID`
- `OPENAI_BASE_URL`
If your shell also contains `AZURE_OPENAI_*` variables, these samples still stay on OpenAI as long as
`OPENAI_API_KEY` is present. To force Azure routing with the generic clients, pass an explicit Azure
input such as `credential`, `azure_endpoint`, or `api_version`, or use the Azure provider samples.
## Optional Dependencies
Some samples need extra packages:
- `client_image_generation.py` and `client_streaming_image_generation.py` use Pillow for image display.
- MCP samples require the relevant MCP server/tooling you configure locally.
@@ -0,0 +1,85 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from random import randint
from typing import Annotated
from agent_framework import Agent, tool
from agent_framework.openai import OpenAIChatCompletionClient
from dotenv import load_dotenv
from pydantic import Field
# Load environment variables from .env file
load_dotenv()
"""
OpenAI Chat Completion Client Basic Example
This sample demonstrates basic usage of OpenAIChatCompletionClient with explicit model and
API key settings, showing both streaming and non-streaming responses.
"""
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production.
@tool(approval_mode="never_require")
def get_weather(
location: Annotated[str, Field(description="The location to get the weather for.")],
) -> str:
"""Get the weather for a given location."""
conditions = ["sunny", "cloudy", "rainy", "stormy"]
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C."
async def non_streaming_example() -> None:
"""Example of non-streaming response (get the complete result at once)."""
print("=== Non-streaming Response Example ===")
agent = Agent(
client=OpenAIChatCompletionClient(
model="gpt-5.4-nano",
api_key=os.getenv("OPENAI_API_KEY"),
),
name="WeatherAgent",
instructions="You are a helpful weather agent.",
tools=get_weather,
)
query = "What's the weather like in Seattle?"
print(f"User: {query}")
result = await agent.run(query)
print(f"Result: {result}\n")
async def streaming_example() -> None:
"""Example of streaming response (get results as they are generated)."""
print("=== Streaming Response Example ===")
agent = Agent(
client=OpenAIChatCompletionClient(
model="gpt-5.4-nano",
api_key=os.getenv("OPENAI_API_KEY"),
),
name="WeatherAgent",
instructions="You are a helpful weather agent.",
tools=get_weather,
)
query = "What's the weather like in Portland?"
print(f"User: {query}")
print("Agent: ", end="", flush=True)
async for chunk in agent.run(query, stream=True):
if chunk.text:
print(chunk.text, end="", flush=True)
print("\n")
async def main() -> None:
print("=== Basic OpenAI Chat Completion Client Agent Example ===")
await non_streaming_example()
await streaming_example()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,53 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from random import randint
from typing import Annotated
from agent_framework import Agent, tool
from agent_framework.openai import OpenAIChatCompletionClient
from dotenv import load_dotenv
from pydantic import Field
# Load environment variables from .env file
load_dotenv()
"""
OpenAI Chat Completion Client with Explicit Settings Example
This sample demonstrates creating OpenAI Chat Completion Client with explicit configuration
settings rather than relying on environment variable defaults.
"""
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production;
# see samples/02-agents/tools/function_tool_with_approval.py
# and samples/02-agents/tools/function_tool_with_approval_and_sessions.py.
@tool(approval_mode="never_require")
def get_weather(
location: Annotated[str, Field(description="The location to get the weather for.")],
) -> str:
"""Get the weather for a given location."""
conditions = ["sunny", "cloudy", "rainy", "stormy"]
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C."
async def main() -> None:
print("=== OpenAI Chat Completion Client with Explicit Settings ===")
agent = Agent(
client=OpenAIChatCompletionClient(
model=os.environ["OPENAI_MODEL"],
api_key=os.environ["OPENAI_API_KEY"],
),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
result = await agent.run("What's the weather like in New York?")
print(f"Result: {result}\n")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,136 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from datetime import datetime, timezone
from random import randint
from typing import Annotated
from agent_framework import Agent, tool
from agent_framework.openai import OpenAIChatCompletionClient
from dotenv import load_dotenv
from pydantic import Field
# Load environment variables from .env file
load_dotenv()
"""
OpenAI Chat Completion Client with Function Tools Example
This sample demonstrates function tool integration with OpenAI Chat Completion Client,
showing both agent-level and query-level tool configuration patterns.
"""
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production;
# see samples/02-agents/tools/function_tool_with_approval.py
# and samples/02-agents/tools/function_tool_with_approval_and_sessions.py.
@tool(approval_mode="never_require")
def get_weather(
location: Annotated[str, Field(description="The location to get the weather for.")],
) -> str:
"""Get the weather for a given location."""
conditions = ["sunny", "cloudy", "rainy", "stormy"]
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C."
@tool(approval_mode="never_require")
def get_time() -> str:
"""Get the current UTC time."""
current_time = datetime.now(timezone.utc)
return f"The current UTC time is {current_time.strftime('%Y-%m-%d %H:%M:%S')}."
async def tools_on_agent_level() -> None:
"""Example showing tools defined when creating the agent."""
print("=== Tools Defined on Agent Level ===")
# Tools are provided when creating the agent
# The agent can use these tools for any query during its lifetime
agent = Agent(
client=OpenAIChatCompletionClient(),
instructions="You are a helpful assistant that can provide weather and time information.",
tools=[get_weather, get_time], # Tools defined at agent creation
)
# First query - agent can use weather tool
query1 = "What's the weather like in New York?"
print(f"User: {query1}")
result1 = await agent.run(query1)
print(f"Agent: {result1}\n")
# Second query - agent can use time tool
query2 = "What's the current UTC time?"
print(f"User: {query2}")
result2 = await agent.run(query2)
print(f"Agent: {result2}\n")
# Third query - agent can use both tools if needed
query3 = "What's the weather in London and what's the current UTC time?"
print(f"User: {query3}")
result3 = await agent.run(query3)
print(f"Agent: {result3}\n")
async def tools_on_run_level() -> None:
"""Example showing tools passed to the run method."""
print("=== Tools Passed to Run Method ===")
# Agent created without tools
agent = Agent(
client=OpenAIChatCompletionClient(),
instructions="You are a helpful assistant.",
# No tools defined here
)
# First query with weather tool
query1 = "What's the weather like in Seattle?"
print(f"User: {query1}")
result1 = await agent.run(query1, tools=[get_weather]) # Tool passed to run method
print(f"Agent: {result1}\n")
# Second query with time tool
query2 = "What's the current UTC time?"
print(f"User: {query2}")
result2 = await agent.run(query2, tools=[get_time]) # Different tool for this query
print(f"Agent: {result2}\n")
# Third query with multiple tools
query3 = "What's the weather in Chicago and what's the current UTC time?"
print(f"User: {query3}")
result3 = await agent.run(query3, tools=[get_weather, get_time]) # Multiple tools
print(f"Agent: {result3}\n")
async def mixed_tools_example() -> None:
"""Example showing both agent-level tools and run-method tools."""
print("=== Mixed Tools Example (Agent + Run Method) ===")
# Agent created with some base tools
agent = Agent(
client=OpenAIChatCompletionClient(),
instructions="You are a comprehensive assistant that can help with various information requests.",
tools=[get_weather], # Base tool available for all queries
)
# Query using both agent tool and additional run-method tools
query = "What's the weather in Denver and what's the current UTC time?"
print(f"User: {query}")
# Agent has access to get_weather (from creation) + additional tools from run method
result = await agent.run(
query,
tools=[get_time], # Additional tools for this specific query
)
print(f"Agent: {result}\n")
async def main() -> None:
print("=== OpenAI Chat Completion Client Agent with Function Tools Examples ===\n")
await tools_on_agent_level()
await tools_on_run_level()
await mixed_tools_example()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,92 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from agent_framework import Agent, MCPStreamableHTTPTool
from agent_framework.openai import OpenAIChatCompletionClient
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
"""
OpenAI Chat Completion Client with Local MCP Example
This sample demonstrates integrating Model Context Protocol (MCP) tools with
OpenAI Chat Completion Client for extended functionality and external service access.
The Agent Framework now supports enhanced metadata extraction from MCP tool
results, including error states, token usage, costs, and other arbitrary
metadata through the _meta field of CallToolResult objects.
"""
async def mcp_tools_on_run_level() -> None:
"""Example showing MCP tools defined when running the agent."""
print("=== Tools Defined on Run Level ===")
# Tools are provided when running the agent
# This means we have to ensure we connect to the MCP server before running the agent
# and pass the tools to the run method.
async with (
MCPStreamableHTTPTool(
name="Microsoft Learn MCP",
url="https://learn.microsoft.com/api/mcp",
) as mcp_server,
Agent(
client=OpenAIChatCompletionClient(),
name="DocsAgent",
instructions="You are a helpful assistant that can help with microsoft documentation questions.",
) as agent,
):
# First query
query1 = "How to create an Azure storage account using az cli?"
print(f"User: {query1}")
result1 = await agent.run(query1, tools=mcp_server)
print(f"{agent.name}: {result1}\n")
print("\n=======================================\n")
# Second query
query2 = "What is Microsoft Agent Framework?"
print(f"User: {query2}")
result2 = await agent.run(query2, tools=mcp_server)
print(f"{agent.name}: {result2}\n")
async def mcp_tools_on_agent_level() -> None:
"""Example showing tools defined when creating the agent."""
print("=== Tools Defined on Agent Level ===")
# Tools are provided when creating the agent
# The agent can use these tools for any query during its lifetime
# The agent will connect to the MCP server through its context manager.
async with Agent(
client=OpenAIChatCompletionClient(),
name="DocsAgent",
instructions="You are a helpful assistant that can help with microsoft documentation questions.",
tools=MCPStreamableHTTPTool( # Tools defined at agent creation
name="Microsoft Learn MCP",
url="https://learn.microsoft.com/api/mcp",
),
) as agent:
# First query
query1 = "How to create an Azure storage account using az cli?"
print(f"User: {query1}")
result1 = await agent.run(query1)
print(f"{agent.name}: {result1}\n")
print("\n=======================================\n")
# Second query
query2 = "What is Microsoft Agent Framework?"
print(f"User: {query2}")
result2 = await agent.run(query2)
print(f"{agent.name}: {result2}\n")
async def main() -> None:
print("=== OpenAI Chat Completion Client Agent with MCP Tools Examples ===\n")
await mcp_tools_on_agent_level()
await mcp_tools_on_run_level()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,118 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import json
from agent_framework import Agent
from agent_framework.openai import OpenAIChatCompletionClient, OpenAIChatOptions
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
"""
OpenAI Chat Completion Client Runtime JSON Schema Example
Demonstrates structured outputs when the schema is only known at runtime.
Uses additional_chat_options to pass a JSON Schema payload directly to OpenAI
without defining a Pydantic model up front.
"""
runtime_schema = {
"title": "WeatherDigest",
"type": "object",
"properties": {
"location": {"type": "string"},
"conditions": {"type": "string"},
"temperature_c": {"type": "number"},
"advisory": {"type": "string"},
},
# OpenAI strict mode requires every property to appear in required.
"required": ["location", "conditions", "temperature_c", "advisory"],
"additionalProperties": False,
}
async def non_streaming_example() -> None:
print("=== Non-streaming runtime JSON schema example ===")
agent = Agent(
client=OpenAIChatCompletionClient[OpenAIChatOptions](),
name="RuntimeSchemaAgent",
instructions="Return only JSON that matches the provided schema. Do not add commentary.",
)
query = "Give a brief weather digest for Seattle."
print(f"User: {query}")
response = await agent.run(
query,
options={
"response_format": {
"type": "json_schema",
"json_schema": {
"name": runtime_schema["title"],
"strict": True,
"schema": runtime_schema,
},
},
},
)
print("Model output:")
print(response.text)
parsed = json.loads(response.text)
print("Parsed dict:")
print(parsed)
async def streaming_example() -> None:
print("=== Streaming runtime JSON schema example ===")
agent = Agent(
client=OpenAIChatCompletionClient(),
name="RuntimeSchemaAgent",
instructions="Return only JSON that matches the provided schema. Do not add commentary.",
)
query = "Give a brief weather digest for Portland."
print(f"User: {query}")
chunks: list[str] = []
async for chunk in agent.run(
query,
stream=True,
options={
"response_format": {
"type": "json_schema",
"json_schema": {
"name": runtime_schema["title"],
"strict": True,
"schema": runtime_schema,
},
},
},
):
if chunk.text:
chunks.append(chunk.text)
raw_text = "".join(chunks)
print("Model output:")
print(raw_text)
parsed = json.loads(raw_text)
print("Parsed dict:")
print(parsed)
async def main() -> None:
print("=== OpenAI Chat Completion Client with runtime JSON Schema ===")
await non_streaming_example()
await streaming_example()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,153 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from random import randint
from typing import Annotated
from agent_framework import Agent, AgentSession, InMemoryHistoryProvider, tool
from agent_framework.openai import OpenAIChatCompletionClient
from dotenv import load_dotenv
from pydantic import Field
# Load environment variables from .env file
load_dotenv()
"""
OpenAI Chat Completion Client with Session Management Example
This sample demonstrates session management with OpenAI Chat Completion Client, showing
conversation sessions and message history preservation across interactions.
"""
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production;
# see samples/02-agents/tools/function_tool_with_approval.py
# and samples/02-agents/tools/function_tool_with_approval_and_sessions.py.
@tool(approval_mode="never_require")
def get_weather(
location: Annotated[str, Field(description="The location to get the weather for.")],
) -> str:
"""Get the weather for a given location."""
conditions = ["sunny", "cloudy", "rainy", "stormy"]
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C."
async def example_with_automatic_session_creation() -> None:
"""Example showing automatic session creation (service-managed session)."""
print("=== Automatic Session Creation Example ===")
agent = Agent(
client=OpenAIChatCompletionClient(),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
# First conversation - no session provided, will be created automatically
query1 = "What's the weather like in Seattle?"
print(f"User: {query1}")
result1 = await agent.run(query1)
print(f"Agent: {result1.text}")
# Second conversation - still no session provided, will create another new session
query2 = "What was the last city I asked about?"
print(f"\nUser: {query2}")
result2 = await agent.run(query2)
print(f"Agent: {result2.text}")
print("Note: Each call creates a separate session, so the agent doesn't remember previous context.\n")
async def example_with_session_persistence() -> None:
"""Example showing session persistence across multiple conversations."""
print("=== Session Persistence Example ===")
print("Using the same session across multiple conversations to maintain context.\n")
agent = Agent(
client=OpenAIChatCompletionClient(),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
# Create a new session that will be reused
session = agent.create_session()
# First conversation
query1 = "What's the weather like in Tokyo?"
print(f"User: {query1}")
result1 = await agent.run(query1, session=session)
print(f"Agent: {result1.text}")
# Second conversation using the same session - maintains context
query2 = "How about London?"
print(f"\nUser: {query2}")
result2 = await agent.run(query2, session=session)
print(f"Agent: {result2.text}")
# Third conversation - agent should remember both previous cities
query3 = "Which of the cities I asked about has better weather?"
print(f"\nUser: {query3}")
result3 = await agent.run(query3, session=session)
print(f"Agent: {result3.text}")
print("Note: The agent remembers context from previous messages in the same session.\n")
async def example_with_existing_session_messages() -> None:
"""Example showing how to work with existing session messages for OpenAI."""
print("=== Existing Session Messages Example ===")
agent = Agent(
client=OpenAIChatCompletionClient(),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
# Start a conversation and build up message history
session = agent.create_session()
query1 = "What's the weather in Paris?"
print(f"User: {query1}")
result1 = await agent.run(query1, session=session)
print(f"Agent: {result1.text}")
# The session now contains the conversation history in state
memory_state = session.state.get(InMemoryHistoryProvider.DEFAULT_SOURCE_ID, {})
messages = memory_state.get("messages", [])
if messages:
print(f"Session contains {len(messages)} messages")
print("\n--- Continuing with the same session in a new agent instance ---")
# Create a new agent instance but use the existing session with its message history
new_agent = Agent(
client=OpenAIChatCompletionClient(),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
# Use the same session object which contains the conversation history
query2 = "What was the last city I asked about?"
print(f"User: {query2}")
result2 = await new_agent.run(query2, session=session)
print(f"Agent: {result2.text}")
print("Note: The agent continues the conversation using the local message history.\n")
print("\n--- Alternative: Creating a new session from existing messages ---")
new_session = AgentSession()
query3 = "How does the Paris weather compare to London?"
print(f"User: {query3}")
result3 = await new_agent.run(query3, session=new_session)
print(f"Agent: {result3.text}")
print("Note: This creates a new session with the same conversation history.\n")
async def main() -> None:
print("=== OpenAI Chat Completion Client Agent Session Management Examples ===\n")
await example_with_automatic_session_creation()
await example_with_session_persistence()
await example_with_existing_session_messages()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,55 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from agent_framework import Agent
from agent_framework.openai import OpenAIChatCompletionClient
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
"""
OpenAI Chat Completion Client with Web Search Example
This sample demonstrates using get_web_search_tool() with OpenAI Chat Completion Client
for real-time information retrieval and current data access.
"""
async def main() -> None:
client = OpenAIChatCompletionClient(model="gpt-4o-search-preview")
# Create web search tool with location context
web_search_tool = client.get_web_search_tool(
web_search_options={
"user_location": {
"type": "approximate",
"approximate": {"city": "Seattle", "country": "US"},
},
},
)
agent = Agent(
client=client,
instructions="You are a helpful assistant that can search the web for current information.",
tools=[web_search_tool],
)
message = "What is the current weather? Do not ask for my current location."
stream = False
print(f"User: {message}")
if stream:
print("Assistant: ", end="")
async for chunk in agent.run(message, stream=True):
if chunk.text:
print(chunk.text, end="")
print("")
else:
response = await agent.run(message)
print(f"Assistant: {response}")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,85 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from random import randint
from typing import Annotated
from agent_framework import Agent, tool
from agent_framework.openai import OpenAIChatClient
from dotenv import load_dotenv
from pydantic import Field
# Load environment variables from .env file
load_dotenv()
"""
OpenAI Chat Client Basic Example
This sample demonstrates basic usage of OpenAIChatClient with explicit model and
API key settings, showing both streaming and non-streaming responses.
"""
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production.
@tool(approval_mode="never_require")
def get_weather(
location: Annotated[str, Field(description="The location to get the weather for.")],
) -> str:
"""Get the weather for a given location."""
conditions = ["sunny", "cloudy", "rainy", "stormy"]
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C."
async def non_streaming_example() -> None:
"""Example of non-streaming response (get the complete result at once)."""
print("=== Non-streaming Response Example ===")
agent = Agent(
client=OpenAIChatClient(
model="gpt-5.4-nano",
api_key=os.getenv("OPENAI_API_KEY"),
),
name="WeatherAgent",
instructions="You are a helpful weather agent.",
tools=get_weather,
)
query = "What's the weather in Seattle?"
print(f"User: {query}")
result = await agent.run(query)
print(f"Result: {result}\n")
async def streaming_example() -> None:
"""Example of streaming response (get results as they are generated)."""
print("=== Streaming Response Example ===")
agent = Agent(
client=OpenAIChatClient(
model="gpt-5.4-nano",
api_key=os.getenv("OPENAI_API_KEY"),
),
name="WeatherAgent",
instructions="You are a helpful weather agent.",
tools=get_weather,
)
query = "What's the weather in Portland?"
print(f"User: {query}")
print("Agent: ", end="", flush=True)
async for chunk in agent.run(query, stream=True):
if chunk.text:
print(chunk.text, end="", flush=True)
print("\n")
async def main() -> None:
print("=== Basic OpenAI Chat Client Agent Example ===")
await non_streaming_example()
await streaming_example()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,43 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from agent_framework import Agent, Content
from agent_framework.openai import OpenAIChatClient
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
"""
OpenAI Chat Client Image Analysis Example
This sample demonstrates using OpenAI Chat Client for image analysis and vision tasks,
showing multi-modal content handling with text and images.
"""
async def main():
print("=== OpenAI Chat Client Agent with Image Analysis ===")
# 1. Create an OpenAI Chat agent with vision capabilities
agent = Agent(
client=OpenAIChatClient(),
name="VisionAgent",
instructions="You are a image analysist, you get a image and need to respond with what you see in the picture.",
)
# 2. Get the agent's response
print("User: What do you see in this image? [Image provided]")
result = await agent.run(
Content.from_uri(
uri="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=800",
media_type="image/jpeg",
)
)
print(f"Agent: {result.text}")
print()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,107 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import base64
import tempfile
import urllib.request as urllib_request
from pathlib import Path
from agent_framework import Agent, Content
from agent_framework.openai import OpenAIChatClient
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
"""
OpenAI Chat Client Image Generation Example
This sample demonstrates how to generate images using OpenAI's DALL-E models
through the Chat Client. Image generation capabilities enable AI to create visual content from text,
making it ideal for creative applications, content creation, design prototyping,
and automated visual asset generation.
"""
def save_image(output: Content) -> None:
"""Save the generated image to a temporary directory.
This sample is simplified, usually a async aware storing method would be better.
"""
filename = "generated_image.webp"
file_path = Path(tempfile.gettempdir()) / filename
data_bytes: bytes | None = None
uri = getattr(output, "uri", None)
if isinstance(uri, str):
if ";base64," in uri:
try:
b64 = uri.split(";base64,", 1)[1]
data_bytes = base64.b64decode(b64)
except Exception:
data_bytes = None
else:
try:
data_bytes = urllib_request.urlopen(uri).read()
except Exception:
data_bytes = None
if data_bytes is None:
raise RuntimeError("Image output present but could not retrieve bytes.")
with open(file_path, "wb") as f:
f.write(data_bytes)
print(f"Image downloaded and saved to: {file_path}")
async def main() -> None:
print("=== OpenAI Chat Image Generation Agent Example ===")
# Create an agent with customized image generation options
client = OpenAIChatClient()
agent = Agent(
client=client,
instructions="You are a helpful AI that can generate images.",
tools=[
client.get_image_generation_tool(
size="1024x1024",
output_format="webp",
)
],
)
query = "Generate a black furry cat."
print(f"User: {query}")
print("Generating image with parameters: 1024x1024 size, WebP format...")
result = await agent.run(query)
print(f"Agent: {result.text}")
# Find and save the generated image
image_saved = False
for message in result.messages:
for content in message.contents:
if content.type == "image_generation_tool_result" and content.outputs:
output = content.outputs
if isinstance(output, Content) and output.uri:
save_image(output)
image_saved = True
elif isinstance(output, list):
for out in output:
if isinstance(out, Content) and out.uri:
save_image(out)
image_saved = True
break
if image_saved:
break
if image_saved:
break
if not image_saved:
print("No image data found in the agent response.")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,86 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from agent_framework import Agent
from agent_framework.openai import OpenAIChatClient, OpenAIChatOptions
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
"""
OpenAI Chat Client Reasoning Example
This sample demonstrates advanced reasoning capabilities using OpenAI's gpt-5 models,
showing step-by-step reasoning process visualization and complex problem-solving.
This uses the default_options parameter to enable reasoning with high effort and detailed summaries.
You can also set these options at the run level using the options parameter.
Since these are api and/or provider specific, you will need to lookup
the correct values for your provider, as they are passed through as-is.
In this case they are here: https://platform.openai.com/docs/api-reference/responses/create#responses-create-reasoning
"""
agent = Agent(
client=OpenAIChatClient[OpenAIChatOptions](model="gpt-5"),
name="MathHelper",
instructions="You are a personal math tutor. When asked a math question, "
"reason over how best to approach the problem and share your thought process.",
default_options={"reasoning": {"effort": "high", "summary": "detailed"}},
)
async def reasoning_example() -> None:
"""Example of reasoning response (get results as they are generated)."""
print("\033[92m=== Reasoning Example ===\033[0m")
query = "I need to solve the equation 3x + 11 = 14 and I need to prove the pythagorean theorem. Can you help me?"
print(f"User: {query}")
print(f"{agent.name}: ", end="", flush=True)
response = await agent.run(query)
for msg in response.messages:
if msg.contents:
for content in msg.contents:
if content.type == "text_reasoning":
print(f"\033[94m{content.text}\033[0m", end="", flush=True)
elif content.type == "text":
print(content.text, end="", flush=True)
print("\n")
if response.usage_details:
print(f"Usage: {response.usage_details}")
async def streaming_reasoning_example() -> None:
"""Example of reasoning response (get results as they are generated)."""
print("\033[92m=== Streaming Reasoning Example ===\033[0m")
query = "I need to solve the equation 3x + 11 = 14 and I need to prove the pythagorean theorem. Can you help me?"
print(f"User: {query}")
print(f"{agent.name}: ", end="", flush=True)
usage = None
async for chunk in agent.run(query, stream=True):
if chunk.contents:
for content in chunk.contents:
if content.type == "text_reasoning":
print(f"\033[94m{content.text}\033[0m", end="", flush=True)
elif content.type == "text":
print(content.text, end="", flush=True)
elif content.type == "usage":
usage = content
print("\n")
if usage:
print(f"Usage: {usage.usage_details}")
async def main() -> None:
print("\033[92m=== Basic OpenAI Chat Reasoning Agent Example ===\033[0m")
await reasoning_example()
await streaming_reasoning_example()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,92 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import base64
import tempfile
from pathlib import Path
import anyio
from agent_framework import Agent, Content
from agent_framework.openai import OpenAIChatClient
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
"""OpenAI Chat Client Streaming Image Generation Example
Demonstrates streaming partial image generation using OpenAI's image generation tool.
Shows progressive image rendering with partial images for improved user experience.
Note: The number of partial images received depends on generation speed:
- High quality/complex images: More partials (generation takes longer)
- Low quality/simple images: Fewer partials (generation completes quickly)
- You may receive fewer partial images than requested if generation is fast
Important: The final partial image IS the complete, full-quality image. Each partial
represents a progressive refinement, with the last one being the finished result.
"""
async def save_image_from_data_uri(data_uri: str, filename: str) -> None:
"""Save an image from a data URI to a file."""
try:
if data_uri.startswith("data:image/"):
# Extract base64 data
base64_data = data_uri.split(",", 1)[1]
image_bytes = base64.b64decode(base64_data)
# Save to file
await anyio.Path(filename).write_bytes(image_bytes)
print(f" Saved: {filename} ({len(image_bytes) / 1024:.1f} KB)")
except Exception as e:
print(f" Error saving {filename}: {e}")
async def main():
"""Demonstrate streaming image generation with partial images."""
print("=== OpenAI Streaming Image Generation Example ===\n")
# Create agent with streaming image generation enabled
client = OpenAIChatClient()
agent = Agent(
client=client,
instructions="You are a helpful agent that can generate images.",
tools=[
client.get_image_generation_tool(
size="1024x1024",
quality="high",
partial_images=3,
)
],
)
query = "Draw a beautiful sunset over a calm ocean with sailboats"
print(f" User: {query}")
print()
# Track partial images
image_count = 0
# Use temp directory for output
output_dir = Path(tempfile.gettempdir()) / "generated_images"
output_dir.mkdir(exist_ok=True)
print(" Streaming response:")
async for update in agent.run(query, stream=True):
for content in update.contents:
# Handle partial images
# The final partial image IS the complete, full-quality image. Each partial
# represents a progressive refinement, with the last one being the finished result.
if content.type == "image_generation_tool_result" and isinstance(content.outputs, Content):
image_output: Content = content.outputs
if image_output.type == "data" and image_output.additional_properties.get("is_partial_image"):
print(f" Image {image_count} received")
# Extract file extension from media_type (e.g., "image/png" -> "png")
extension = "png" # Default fallback
if image_output.media_type and "/" in image_output.media_type:
extension = image_output.media_type.split("/")[-1]
# Save images with correct extension
filename = output_dir / f"image{image_count}.{extension}"
if image_output.uri is not None:
await save_image_from_data_uri(image_output.uri, str(filename))
image_count += 1
# Summary
print("\n Summary:")
print(f" Images received: {image_count}")
print(f" Output directory: {output_dir}")
print("\n Streaming image generation completed!")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,73 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from typing import Literal
from agent_framework import Agent
from agent_framework.openai import OpenAIChatClient, OpenAIChatOptions
from dotenv import load_dotenv
Verbosity = Literal["low", "medium", "high"]
load_dotenv()
"""
OpenAI Chat Client Verbosity Example
Demonstrates the GPT-5 ``verbosity`` parameter on the Responses API. ``verbosity``
controls how concise or detailed the model's natural-language output is and accepts
``"low"``, ``"medium"``, or ``"high"``.
The framework exposes ``verbosity`` as a top-level option on ``OpenAIChatOptions``
(parallel to ``reasoning``) and translates it to ``text.verbosity`` when calling the
Responses API.
"""
PROMPT = "Explain in your own words what photosynthesis is and why it matters."
async def run_with_verbosity(level: Verbosity) -> None:
"""Run the same prompt with a different verbosity setting and print the output length."""
agent = Agent(
client=OpenAIChatClient[OpenAIChatOptions](model="gpt-5"),
name=f"Explainer-{level}",
instructions="You are a friendly science explainer.",
default_options={"verbosity": level},
)
print(f"\033[92m=== verbosity={level!r} ===\033[0m")
response = await agent.run(PROMPT)
text = response.text or ""
print(text)
print(f"\n[chars: {len(text)}]\n")
async def run_per_call_override() -> None:
"""Show that verbosity can be overridden per ``run`` call."""
agent = Agent(
client=OpenAIChatClient[OpenAIChatOptions](model="gpt-5"),
name="Explainer-default",
instructions="You are a friendly science explainer.",
default_options={"verbosity": "high"},
)
print("\033[92m=== per-call override: verbosity='low' ===\033[0m")
response = await agent.run(PROMPT, options={"verbosity": "low"})
text = response.text or ""
print(text)
print(f"\n[chars: {len(text)}]\n")
async def main() -> None:
print("\033[92m=== OpenAI Chat Client Verbosity Example ===\033[0m\n")
levels: tuple[Verbosity, ...] = ("low", "medium", "high")
for level in levels:
await run_with_verbosity(level)
await run_per_call_override()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,73 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from collections.abc import Awaitable, Callable
from agent_framework import Agent, FunctionInvocationContext
from agent_framework.openai import OpenAIChatClient
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
"""
OpenAI Chat Client Agent-as-Tool Example
Demonstrates hierarchical agent architectures where one agent delegates
work to specialized sub-agents wrapped as tools using as_tool().
This pattern is useful when you want a coordinator agent to orchestrate
multiple specialized agents, each focusing on specific tasks.
"""
async def logging_middleware(
context: FunctionInvocationContext,
call_next: Callable[[], Awaitable[None]],
) -> None:
"""MiddlewareTypes that logs tool invocations to show the delegation flow."""
print(f"[Calling tool: {context.function.name}]")
print(f"[Request: {context.arguments}]")
await call_next()
print(f"[Response: {context.result}]")
async def main() -> None:
print("=== OpenAI Chat Client Agent-as-Tool Pattern ===")
client = OpenAIChatClient()
# Create a specialized writer agent
writer = Agent(
client=client,
name="WriterAgent",
instructions="You are a creative writer. Write short, engaging content.",
)
# Convert writer agent to a tool using as_tool()
writer_tool = writer.as_tool(
name="creative_writer",
description="Generate creative content like taglines, slogans, or short copy",
arg_name="request",
arg_description="What to write",
)
# Create coordinator agent with writer as a tool
coordinator = Agent(
client=client,
name="CoordinatorAgent",
instructions="You coordinate with specialized agents. Delegate writing tasks to the creative_writer tool.",
tools=[writer_tool],
middleware=[logging_middleware],
)
query = "Create a tagline for a coffee shop"
print(f"User: {query}")
result = await coordinator.run(query)
print(f"Coordinator: {result}\n")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,57 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from agent_framework import (
Agent,
Content,
)
from agent_framework.openai import OpenAIChatClient
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
"""
OpenAI Chat Client with Code Interpreter Example
This sample demonstrates using get_code_interpreter_tool() with OpenAI Chat Client
for Python code execution and mathematical problem solving.
"""
async def main() -> None:
"""Example showing how to use the code interpreter tool with OpenAI Chat."""
print("=== OpenAI Chat Client Agent with Code Interpreter Example ===")
client = OpenAIChatClient()
agent = Agent(
client=client,
instructions="You are a helpful assistant that can write and execute Python code to solve problems.",
tools=client.get_code_interpreter_tool(),
)
query = "Use code to get the factorial of 100?"
print(f"User: {query}")
result = await agent.run(query)
print(f"Result: {result}\n")
for message in result.messages:
code_blocks = [c for c in message.contents if c.type == "code_interpreter_tool_call"]
outputs = [c for c in message.contents if c.type == "code_interpreter_tool_result"]
if code_blocks:
code_inputs = code_blocks[0].inputs or []
for content in code_inputs:
if isinstance(content, Content) and content.type == "text":
print(f"Generated code:\n{content.text}")
break
if outputs:
print("Execution outputs:")
for out in outputs[0].outputs or []:
if isinstance(out, Content) and out.type == "text":
print(out.text)
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,90 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
import tempfile
from agent_framework import Agent
from agent_framework.openai import OpenAIChatClient
from dotenv import load_dotenv
from openai import AsyncOpenAI
# Load environment variables from .env file
load_dotenv()
"""
OpenAI Chat Client with Code Interpreter and Files Example
This sample demonstrates using get_code_interpreter_tool() with OpenAI Chat Client
for Python code execution and data analysis with uploaded files.
"""
# Helper functions
async def create_sample_file_and_upload(openai_client: AsyncOpenAI) -> tuple[str, str]:
"""Create a sample CSV file and upload it to OpenAI."""
csv_data = """name,department,salary,years_experience
Alice Johnson,Engineering,95000,5
Bob Smith,Sales,75000,3
Carol Williams,Engineering,105000,8
David Brown,Marketing,68000,2
Emma Davis,Sales,82000,4
Frank Wilson,Engineering,88000,6
"""
# Create temporary CSV file
with tempfile.NamedTemporaryFile(mode="w", suffix=".csv", delete=False) as temp_file:
temp_file.write(csv_data)
temp_file_path = temp_file.name
# Upload file to OpenAI
print("Uploading file to OpenAI...")
with open(temp_file_path, "rb") as file:
uploaded_file = await openai_client.files.create(
file=file,
purpose="assistants", # Required for code interpreter
)
print(f"File uploaded with ID: {uploaded_file.id}")
return temp_file_path, uploaded_file.id
async def cleanup_files(openai_client: AsyncOpenAI, temp_file_path: str, file_id: str) -> None:
"""Clean up both local temporary file and uploaded file."""
# Clean up: delete the uploaded file
await openai_client.files.delete(file_id)
print(f"Cleaned up uploaded file: {file_id}")
# Clean up temporary local file
os.unlink(temp_file_path)
print(f"Cleaned up temporary file: {temp_file_path}")
async def main() -> None:
"""Complete example of uploading a file to OpenAI and using it with code interpreter."""
print("=== OpenAI Code Interpreter with File Upload ===")
openai_client = AsyncOpenAI()
temp_file_path, file_id = await create_sample_file_and_upload(openai_client)
# Create agent using OpenAI Chat client
client = OpenAIChatClient()
agent = Agent(
client=client,
instructions="You are a helpful assistant that can analyze data files using Python code.",
tools=client.get_code_interpreter_tool(file_ids=[file_id]),
)
# Test the code interpreter with the uploaded file
query = "Analyze the employee data in the uploaded CSV file. Calculate average salary by department."
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result.text}")
await cleanup_files(openai_client, temp_file_path, file_id)
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,55 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from random import randint
from typing import Annotated
from agent_framework import Agent, tool
from agent_framework.openai import OpenAIChatClient
from dotenv import load_dotenv
from pydantic import Field
# Load environment variables from .env file
load_dotenv()
"""
OpenAI Chat Client with Explicit Settings Example
This sample demonstrates creating OpenAI Chat Client with explicit configuration
settings rather than relying on environment variable defaults.
"""
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production;
# see samples/02-agents/tools/function_tool_with_approval.py
# and samples/02-agents/tools/function_tool_with_approval_and_sessions.py.
@tool(approval_mode="never_require")
def get_weather(
location: Annotated[str, Field(description="The location to get the weather for.")],
) -> str:
"""Get the weather for a given location."""
conditions = ["sunny", "cloudy", "rainy", "stormy"]
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C."
async def main() -> None:
print("=== OpenAI Chat Client with Explicit Settings ===")
_client = OpenAIChatClient(
model=os.environ["OPENAI_MODEL"],
api_key=os.environ["OPENAI_API_KEY"],
)
agent = Agent(
client=_client,
instructions="You are a helpful weather agent.",
tools=get_weather,
)
result = await agent.run("What's the weather like in New York?")
print(f"Result: {result}\n")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,72 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from agent_framework import Agent
from agent_framework.openai import OpenAIChatClient
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
"""
OpenAI Chat Client with File Search Example
This sample demonstrates using get_file_search_tool() with OpenAI Chat Client
for direct document-based question answering and information retrieval.
"""
# Helper functions
async def create_vector_store(client: OpenAIChatClient) -> tuple[str, str]:
"""Create a vector store with sample documents."""
file = await client.client.files.create(
file=("todays_weather.txt", b"The weather today is sunny with a high of 75F."), purpose="user_data"
)
vector_store = await client.client.vector_stores.create(
name="knowledge_base",
expires_after={"anchor": "last_active_at", "days": 1},
)
result = await client.client.vector_stores.files.create_and_poll(vector_store_id=vector_store.id, file_id=file.id)
if result.last_error is not None:
raise Exception(f"Vector store file processing failed with status: {result.last_error.message}")
return file.id, vector_store.id
async def delete_vector_store(client: OpenAIChatClient, file_id: str, vector_store_id: str) -> None:
"""Delete the vector store after using it."""
await client.client.vector_stores.delete(vector_store_id=vector_store_id)
await client.client.files.delete(file_id=file_id)
async def main() -> None:
client = OpenAIChatClient()
message = "What is the weather today? Do a file search to find the answer."
stream = False
print(f"User: {message}")
file_id, vector_store_id = await create_vector_store(client)
agent = Agent(
client=client,
instructions="You are a helpful assistant that can search through files to find information.",
tools=[client.get_file_search_tool(vector_store_ids=[vector_store_id])],
)
if stream:
print("Agent: ", end="")
async for chunk in agent.run(message, stream=True):
if chunk.text:
print(chunk.text, end="")
print("")
else:
response = await agent.run(message)
print(f"Agent: {response}")
await delete_vector_store(client, file_id, vector_store_id)
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,136 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from datetime import datetime, timezone
from random import randint
from typing import Annotated
from agent_framework import Agent, tool
from agent_framework.openai import OpenAIChatClient
from dotenv import load_dotenv
from pydantic import Field
# Load environment variables from .env file
load_dotenv()
"""
OpenAI Chat Client with Function Tools Example
This sample demonstrates function tool integration with OpenAI Chat Client,
showing both agent-level and query-level tool configuration patterns.
"""
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production;
# see samples/02-agents/tools/function_tool_with_approval.py
# and samples/02-agents/tools/function_tool_with_approval_and_sessions.py.
@tool(approval_mode="never_require")
def get_weather(
location: Annotated[str, Field(description="The location to get the weather for.")],
) -> str:
"""Get the weather for a given location."""
conditions = ["sunny", "cloudy", "rainy", "stormy"]
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C."
@tool(approval_mode="never_require")
def get_time() -> str:
"""Get the current UTC time."""
current_time = datetime.now(timezone.utc)
return f"The current UTC time is {current_time.strftime('%Y-%m-%d %H:%M:%S')}."
async def tools_on_agent_level() -> None:
"""Example showing tools defined when creating the agent."""
print("=== Tools Defined on Agent Level ===")
# Tools are provided when creating the agent
# The agent can use these tools for any query during its lifetime
agent = Agent(
client=OpenAIChatClient(),
instructions="You are a helpful assistant that can provide weather and time information.",
tools=[get_weather, get_time], # Tools defined at agent creation
)
# First query - agent can use weather tool
query1 = "What's the weather like in New York?"
print(f"User: {query1}")
result1 = await agent.run(query1)
print(f"Agent: {result1}\n")
# Second query - agent can use time tool
query2 = "What's the current UTC time?"
print(f"User: {query2}")
result2 = await agent.run(query2)
print(f"Agent: {result2}\n")
# Third query - agent can use both tools if needed
query3 = "What's the weather in London and what's the current UTC time?"
print(f"User: {query3}")
result3 = await agent.run(query3)
print(f"Agent: {result3}\n")
async def tools_on_run_level() -> None:
"""Example showing tools passed to the run method."""
print("=== Tools Passed to Run Method ===")
# Agent created without tools
agent = Agent(
client=OpenAIChatClient(),
instructions="You are a helpful assistant.",
# No tools defined here
)
# First query with weather tool
query1 = "What's the weather like in Seattle?"
print(f"User: {query1}")
result1 = await agent.run(query1, tools=[get_weather]) # Tool passed to run method
print(f"Agent: {result1}\n")
# Second query with time tool
query2 = "What's the current UTC time?"
print(f"User: {query2}")
result2 = await agent.run(query2, tools=[get_time]) # Different tool for this query
print(f"Agent: {result2}\n")
# Third query with multiple tools
query3 = "What's the weather in Chicago and what's the current UTC time?"
print(f"User: {query3}")
result3 = await agent.run(query3, tools=[get_weather, get_time]) # Multiple tools
print(f"Agent: {result3}\n")
async def mixed_tools_example() -> None:
"""Example showing both agent-level tools and run-method tools."""
print("=== Mixed Tools Example (Agent + Run Method) ===")
# Agent created with some base tools
agent = Agent(
client=OpenAIChatClient(),
instructions="You are a comprehensive assistant that can help with various information requests.",
tools=[get_weather], # Base tool available for all queries
)
# Query using both agent tool and additional run-method tools
query = "What's the weather in Denver and what's the current UTC time?"
print(f"User: {query}")
# Agent has access to get_weather (from creation) + additional tools from run method
result = await agent.run(
query,
tools=[get_time], # Additional tools for this specific query
)
print(f"Agent: {result}\n")
async def main() -> None:
print("=== OpenAI Chat Client Agent with Function Tools Examples ===\n")
await tools_on_agent_level()
await tools_on_run_level()
await mixed_tools_example()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,252 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from typing import TYPE_CHECKING, Any
from agent_framework import Agent
from agent_framework.openai import OpenAIChatClient
from dotenv import load_dotenv
if TYPE_CHECKING:
from agent_framework import AgentSession
# Load environment variables from .env file
load_dotenv()
"""
OpenAI Chat Client with Hosted MCP Example
This sample demonstrates integrating hosted Model Context Protocol (MCP) tools with
OpenAI Chat Client, including user approval workflows for function call security.
"""
async def handle_approvals_without_session(query: str, agent: Agent[Any]):
"""When we don't have a session, we need to ensure we return with the input, approval request and approval."""
from agent_framework import Message
result = await agent.run(query)
while len(result.user_input_requests) > 0:
new_inputs: list[Any] = [query]
for user_input_needed in result.user_input_requests:
if user_input_needed.function_call is None:
continue
print(
f"User Input Request for function from {agent.name}: {user_input_needed.function_call.name}"
f" with arguments: {user_input_needed.function_call.arguments}"
)
new_inputs.append(Message(role="assistant", contents=[user_input_needed]))
user_approval = input("Approve function call? (y/n): ")
new_inputs.append(
Message(
role="user",
contents=[user_input_needed.to_function_approval_response(user_approval.lower() == "y")],
)
)
result = await agent.run(new_inputs)
return result
async def handle_approvals_with_session(query: str, agent: Agent[Any], session: "AgentSession"):
"""Here we let the session deal with the previous responses, and we just rerun with the approval."""
from agent_framework import ChatOptions, Message
result = await agent.run(query, session=session, options=ChatOptions(store=True))
while len(result.user_input_requests) > 0:
new_input: list[Any] = []
for user_input_needed in result.user_input_requests:
if user_input_needed.function_call is None:
continue
print(
f"User Input Request for function from {agent.name}: {user_input_needed.function_call.name}"
f" with arguments: {user_input_needed.function_call.arguments}"
)
user_approval = input("Approve function call? (y/n): ")
new_input.append(
Message(
role="user",
contents=[user_input_needed.to_function_approval_response(user_approval.lower() == "y")],
)
)
result = await agent.run(new_input, session=session, options=ChatOptions(store=True))
return result
async def handle_approvals_with_session_streaming(query: str, agent: Agent[Any], session: "AgentSession"):
"""Here we let the session deal with the previous responses, and we just rerun with the approval."""
from agent_framework import ChatOptions, Message
new_input: list[Message | str] = [query]
new_input_added = True
while new_input_added:
new_input_added = False
async for update in agent.run(new_input, session=session, stream=True, options=ChatOptions(store=True)):
if update.user_input_requests:
# Reset input to only contain new approval responses for the next iteration
new_input = []
for user_input_needed in update.user_input_requests:
if user_input_needed.function_call is None:
continue
print(
f"User Input Request for function from {agent.name}: {user_input_needed.function_call.name}"
f" with arguments: {user_input_needed.function_call.arguments}"
)
user_approval = input("Approve function call? (y/n): ")
new_input.append(
Message(
role="user",
contents=[user_input_needed.to_function_approval_response(user_approval.lower() == "y")],
)
)
new_input_added = True
else:
yield update
async def run_hosted_mcp_without_session_and_specific_approval() -> None:
"""Example showing Mcp Tools with approvals without using a session."""
print("=== Mcp with approvals and without session ===")
client = OpenAIChatClient()
# Create MCP tool with specific approval mode
mcp_tool = client.get_mcp_tool(
name="Microsoft Learn MCP",
url="https://learn.microsoft.com/api/mcp",
# we don't require approval for microsoft_docs_search tool calls
# but we do for any other tool
approval_mode={"never_require_approval": ["microsoft_docs_search"]},
)
async with Agent(
client=client,
name="DocsAgent",
instructions="You are a helpful assistant that can help with microsoft documentation questions.",
tools=mcp_tool,
) as agent:
# First query
query1 = "How to create an Azure storage account using az cli?"
print(f"User: {query1}")
result1 = await handle_approvals_without_session(query1, agent)
print(f"{agent.name}: {result1}\n")
print("\n=======================================\n")
# Second query
query2 = "What is Microsoft Agent Framework?"
print(f"User: {query2}")
result2 = await handle_approvals_without_session(query2, agent)
print(f"{agent.name}: {result2}\n")
async def run_hosted_mcp_without_approval() -> None:
"""Example showing Mcp Tools without approvals."""
print("=== Mcp without approvals ===")
client = OpenAIChatClient()
# Create MCP tool that never requires approval
mcp_tool = client.get_mcp_tool(
name="Microsoft Learn MCP",
url="https://learn.microsoft.com/api/mcp",
# we don't require approval for any function calls
approval_mode="never_require",
)
async with Agent(
client=client,
name="DocsAgent",
instructions="You are a helpful assistant that can help with microsoft documentation questions.",
tools=mcp_tool,
) as agent:
# First query
query1 = "How to create an Azure storage account using az cli?"
print(f"User: {query1}")
result1 = await handle_approvals_without_session(query1, agent)
print(f"{agent.name}: {result1}\n")
print("\n=======================================\n")
# Second query
query2 = "What is Microsoft Agent Framework?"
print(f"User: {query2}")
result2 = await handle_approvals_without_session(query2, agent)
print(f"{agent.name}: {result2}\n")
async def run_hosted_mcp_with_session() -> None:
"""Example showing Mcp Tools with approvals using a session."""
print("=== Mcp with approvals and with session ===")
client = OpenAIChatClient()
# Create MCP tool that always requires approval
mcp_tool = client.get_mcp_tool(
name="Microsoft Learn MCP",
url="https://learn.microsoft.com/api/mcp",
# we require approval for all function calls
approval_mode="always_require",
)
async with Agent(
client=client,
name="DocsAgent",
instructions="You are a helpful assistant that can help with microsoft documentation questions.",
tools=mcp_tool,
) as agent:
# First query
session = agent.create_session()
query1 = "How to create an Azure storage account using az cli?"
print(f"User: {query1}")
result1 = await handle_approvals_with_session(query1, agent, session)
print(f"{agent.name}: {result1}\n")
print("\n=======================================\n")
# Second query
query2 = "What is Microsoft Agent Framework?"
print(f"User: {query2}")
result2 = await handle_approvals_with_session(query2, agent, session)
print(f"{agent.name}: {result2}\n")
async def run_hosted_mcp_with_session_streaming() -> None:
"""Example showing Mcp Tools with approvals using a session."""
print("=== Mcp with approvals and with session ===")
client = OpenAIChatClient()
# Create MCP tool that always requires approval
mcp_tool = client.get_mcp_tool(
name="Microsoft Learn MCP",
url="https://learn.microsoft.com/api/mcp",
# we require approval for all function calls
approval_mode="always_require",
)
async with Agent(
client=client,
name="DocsAgent",
instructions="You are a helpful assistant that can help with microsoft documentation questions.",
tools=mcp_tool,
) as agent:
# First query
session = agent.create_session()
query1 = "How to create an Azure storage account using az cli?"
print(f"User: {query1}")
print(f"{agent.name}: ", end="")
async for update in handle_approvals_with_session_streaming(query1, agent, session):
print(update, end="")
print("\n")
print("\n=======================================\n")
# Second query
query2 = "What is Microsoft Agent Framework?"
print(f"User: {query2}")
print(f"{agent.name}: ", end="")
async for update in handle_approvals_with_session_streaming(query2, agent, session):
print(update, end="")
print("\n")
async def main() -> None:
print("=== OpenAI Chat Client Agent with Hosted Mcp Tools Examples ===\n")
await run_hosted_mcp_without_approval()
await run_hosted_mcp_without_session_and_specific_approval()
await run_hosted_mcp_with_session()
await run_hosted_mcp_with_session_streaming()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,97 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from agent_framework import Agent, MCPStreamableHTTPTool
from agent_framework.openai import OpenAIChatClient
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
"""
OpenAI Chat Client with Local MCP Example
This sample demonstrates integrating local Model Context Protocol (MCP) tools with
OpenAI Chat Client for direct response generation with external capabilities.
"""
async def streaming_with_mcp(show_raw_stream: bool = False) -> None:
"""Example showing tools defined when creating the agent.
If you want to access the full stream of events that has come from the model, you can access it,
through the raw_representation. You can view this, by setting the show_raw_stream parameter to True.
"""
print("=== Tools Defined on Agent Level ===")
# Tools are provided when creating the agent
# The agent can use these tools for any query during its lifetime
async with Agent(
client=OpenAIChatClient(),
name="DocsAgent",
instructions="You are a helpful assistant that can help with microsoft documentation questions.",
tools=MCPStreamableHTTPTool( # Tools defined at agent creation
name="Microsoft Learn MCP",
url="https://learn.microsoft.com/api/mcp",
),
) as agent:
# First query
query1 = "How to create an Azure storage account using az cli?"
print(f"User: {query1}")
print(f"{agent.name}: ", end="")
async for chunk in agent.run(query1, stream=True):
if show_raw_stream:
print("Streamed event: ", chunk.raw_representation.raw_representation) # type:ignore
elif chunk.text:
print(chunk.text, end="")
print("")
print("\n=======================================\n")
# Second query
query2 = "What is Microsoft Agent Framework?"
print(f"User: {query2}")
print(f"{agent.name}: ", end="")
async for chunk in agent.run(query2, stream=True):
if show_raw_stream:
print("Streamed event: ", chunk.raw_representation.raw_representation) # type:ignore
elif chunk.text:
print(chunk.text, end="")
print("\n\n")
async def run_with_mcp() -> None:
"""Example showing tools defined when creating the agent."""
print("=== Tools Defined on Agent Level ===")
# Tools are provided when creating the agent
# The agent can use these tools for any query during its lifetime
async with Agent(
client=OpenAIChatClient(),
name="DocsAgent",
instructions="You are a helpful assistant that can help with microsoft documentation questions.",
tools=MCPStreamableHTTPTool( # Tools defined at agent creation
name="Microsoft Learn MCP",
url="https://learn.microsoft.com/api/mcp",
),
) as agent:
# First query
query1 = "How to create an Azure storage account using az cli?"
print(f"User: {query1}")
result1 = await agent.run(query1)
print(f"{agent.name}: {result1}\n")
print("\n=======================================\n")
# Second query
query2 = "What is Microsoft Agent Framework?"
print(f"User: {query2}")
result2 = await agent.run(query2)
print(f"{agent.name}: {result2}\n")
async def main() -> None:
print("=== OpenAI Chat Client Agent with Function Tools Examples ===\n")
await run_with_mcp()
await streaming_with_mcp()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,97 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from typing import Any
from agent_framework import Agent, Message
from agent_framework.openai import OpenAIChatClient
from agent_framework_tools.shell import LocalShellTool
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
"""
OpenAI Chat Client with Local Shell Tool Example
This sample uses ``LocalShellTool`` from ``agent-framework-tools`` — the
framework-supplied cross-OS shell executor with safe defaults (approval
required, timeout, output truncation, workdir confinement). Operators
can additionally supply a ``ShellPolicy`` with allow/deny patterns as a
UX pre-filter; the tool ships with no default deny patterns.
Currently not all models support the shell tool. Refer to the OpenAI
documentation for the list of supported models:
https://developers.openai.com/api/docs/models/
SECURITY NOTE: This example executes real commands on your local machine.
``LocalShellTool`` requires approval by default; only accept commands you
understand.
"""
async def main() -> None:
print("=== OpenAI Agent with LocalShellTool Example ===")
print("NOTE: Commands will execute on your local machine.\n")
client = OpenAIChatClient(model="gpt-5.4-nano")
async with LocalShellTool() as shell:
agent = Agent(
client=client,
instructions="You are a helpful assistant that can run shell commands to help the user.",
tools=[client.get_shell_tool(func=shell.as_function())],
)
query = "Use the shell tool to execute `python --version` and show only the command output."
print(f"User: {query}")
result = await run_with_approvals(query, agent)
if isinstance(result, str):
print(f"Agent: {result}\n")
return
if result.text:
print(f"Agent: {result.text}\n")
else:
printed = False
for message in result.messages:
for content in message.contents:
if content.type == "function_result" and content.result:
print(f"Agent (tool output): {content.result}\n")
printed = True
if not printed:
print("Agent: (no text output returned)\n")
async def run_with_approvals(query: str, agent: Agent) -> Any:
"""Run the agent and handle shell approvals outside tool execution."""
current_input: str | list[Any] = query
while True:
result = await agent.run(current_input)
if not result.user_input_requests:
return result
next_input: list[Any] = [query]
rejected = False
for user_input_needed in result.user_input_requests:
if user_input_needed.function_call is None:
continue
print(
f"\nShell request: {user_input_needed.function_call.name}"
f"\nArguments: {user_input_needed.function_call.arguments}"
)
user_approval = await asyncio.to_thread(input, "\nApprove shell command? (y/n): ")
approved = user_approval.strip().lower() == "y"
next_input.append(Message("assistant", [user_input_needed]))
next_input.append(Message("user", [user_input_needed.to_function_approval_response(approved)]))
if not approved:
rejected = True
break
if rejected:
print("\nShell command rejected. Stopping without additional approval prompts.")
return "Shell command execution was rejected by user."
current_input = next_input
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,118 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import json
from agent_framework import Agent
from agent_framework.openai import OpenAIChatClient
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
"""
OpenAI Chat Client Runtime JSON Schema Example
Demonstrates structured outputs when the schema is only known at runtime.
Uses additional_chat_options to pass a JSON Schema payload directly to OpenAI
without defining a Pydantic model up front.
"""
runtime_schema = {
"title": "WeatherDigest",
"type": "object",
"properties": {
"location": {"type": "string"},
"conditions": {"type": "string"},
"temperature_c": {"type": "number"},
"advisory": {"type": "string"},
},
# OpenAI strict mode requires every property to appear in required.
"required": ["location", "conditions", "temperature_c", "advisory"],
"additionalProperties": False,
}
async def non_streaming_example() -> None:
print("=== Non-streaming runtime JSON schema example ===")
agent = Agent(
client=OpenAIChatClient(),
name="RuntimeSchemaAgent",
instructions="Return only JSON that matches the provided schema. Do not add commentary.",
)
query = "Give a brief weather digest for Seattle."
print(f"User: {query}")
response = await agent.run(
query,
options={
"response_format": {
"type": "json_schema",
"json_schema": {
"name": runtime_schema["title"],
"strict": True,
"schema": runtime_schema,
},
},
},
)
print("Model output:")
print(response.text)
parsed = json.loads(response.text)
print("Parsed dict:")
print(parsed)
async def streaming_example() -> None:
print("=== Streaming runtime JSON schema example ===")
agent = Agent(
client=OpenAIChatClient(),
name="RuntimeSchemaAgent",
instructions="Return only JSON that matches the provided schema. Do not add commentary.",
)
query = "Give a brief weather digest for Portland."
print(f"User: {query}")
chunks: list[str] = []
async for chunk in agent.run(
query,
stream=True,
options={
"response_format": {
"type": "json_schema",
"json_schema": {
"name": runtime_schema["title"],
"strict": True,
"schema": runtime_schema,
},
},
},
):
if chunk.text:
chunks.append(chunk.text)
raw_text = "".join(chunks)
print("Model output:")
print(raw_text)
parsed = json.loads(raw_text)
print("Parsed dict:")
print(parsed)
async def main() -> None:
print("=== OpenAI Chat Client with runtime JSON Schema ===")
await non_streaming_example()
await streaming_example()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,154 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from random import randint
from typing import Annotated
from agent_framework import Agent, AgentSession, tool
from agent_framework.openai import OpenAIChatClient
from dotenv import load_dotenv
from pydantic import Field
# Load environment variables from .env file
load_dotenv()
"""
OpenAI Chat Client with Session Management Example
This sample demonstrates session management with OpenAI Chat Client, showing
persistent conversation context and simplified response handling.
"""
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production;
# see samples/02-agents/tools/function_tool_with_approval.py
# and samples/02-agents/tools/function_tool_with_approval_and_sessions.py.
@tool(approval_mode="never_require")
def get_weather(
location: Annotated[str, Field(description="The location to get the weather for.")],
) -> str:
"""Get the weather for a given location."""
conditions = ["sunny", "cloudy", "rainy", "stormy"]
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C."
async def example_with_automatic_session_creation() -> None:
"""Example showing automatic session creation."""
print("=== Automatic Session Creation Example ===")
agent = Agent(
client=OpenAIChatClient(),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
# First conversation - no session provided, will be created automatically
query1 = "What's the weather like in Seattle?"
print(f"User: {query1}")
result1 = await agent.run(query1)
print(f"Agent: {result1.text}")
# Second conversation - still no session provided, will create another new session
query2 = "What was the last city I asked about?"
print(f"\nUser: {query2}")
result2 = await agent.run(query2)
print(f"Agent: {result2.text}")
print("Note: Each call creates a separate session, so the agent doesn't remember previous context.\n")
async def example_with_session_persistence_in_memory() -> None:
"""
Example showing session persistence across multiple conversations.
In this example, messages are stored in-memory.
"""
print("=== Session Persistence Example (In-Memory) ===")
agent = Agent(
client=OpenAIChatClient(),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
# Create a new session that will be reused
session = agent.create_session()
# First conversation
query1 = "What's the weather like in Tokyo?"
print(f"User: {query1}")
result1 = await agent.run(query1, session=session, options={"store": False})
print(f"Agent: {result1.text}")
# Second conversation using the same session - maintains context
query2 = "How about London?"
print(f"\nUser: {query2}")
result2 = await agent.run(query2, session=session, options={"store": False})
print(f"Agent: {result2.text}")
# Third conversation - agent should remember both previous cities
query3 = "Which of the cities I asked about has better weather?"
print(f"\nUser: {query3}")
result3 = await agent.run(query3, session=session, options={"store": False})
print(f"Agent: {result3.text}")
print("Note: The agent remembers context from previous messages in the same session.\n")
async def example_with_existing_session_id() -> None:
"""
Example showing how to work with an existing session ID from the service.
In this example, messages are stored on the server using OpenAI conversation state.
"""
print("=== Existing Session ID Example ===")
# First, create a conversation and capture the session ID
existing_session_id = None
agent = Agent(
client=OpenAIChatClient(),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
# Start a conversation and get the session ID
session = agent.create_session()
query1 = "What's the weather in Paris?"
print(f"User: {query1}")
result1 = await agent.run(query1, session=session)
print(f"Agent: {result1.text}")
# The session ID is set after the first response
existing_session_id = session.service_session_id
print(f"Session ID: {existing_session_id}")
if existing_session_id:
print("\n--- Continuing with the same session ID in a new agent instance ---")
# In a hosted multi-user app, do not echo this service session ID to clients
# and accept it back unscoped. OpenAI scopes it to the API key/project, so
# store it server-side and verify it belongs to the authenticated user or tenant.
agent = Agent(
client=OpenAIChatClient(),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
# Create a session with the existing ID
session = AgentSession(service_session_id=existing_session_id)
query2 = "What was the last city I asked about?"
print(f"User: {query2}")
result2 = await agent.run(query2, session=session)
print(f"Agent: {result2.text}")
print("Note: The agent continues the conversation from the previous session by using session ID.\n")
async def main() -> None:
print("=== OpenAI Response Client Agent Session Management Examples ===\n")
await example_with_automatic_session_creation()
await example_with_session_persistence_in_memory()
await example_with_existing_session_id()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,67 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from agent_framework import Agent
from agent_framework.openai import OpenAIChatClient
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
"""
OpenAI Chat Client with Shell Tool Example
This sample demonstrates using get_shell_tool() with OpenAI Chat Client
for executing shell commands in a managed container environment hosted by OpenAI.
The shell tool allows the model to run commands like listing files, running scripts,
or performing system operations within a secure, sandboxed container.
Currently not all models support the shell tool. Refer to the OpenAI documentation
for the list of supported models: https://developers.openai.com/api/docs/models/
"""
async def main() -> None:
"""Example showing how to use the shell tool with OpenAI Chat."""
print("=== OpenAI Chat Client Agent with Shell Tool Example ===")
# Currently not all models support the shell tool. Refer to the OpenAI
# documentation for the list of supported models:
# https://developers.openai.com/api/docs/models/
client = OpenAIChatClient(model="gpt-5.4-nano")
# Create a hosted shell tool with the default auto container environment
shell_tool = client.get_shell_tool()
agent = Agent(
client=client,
instructions="You are a helpful assistant that can execute shell commands to answer questions.",
tools=shell_tool,
)
query = "Use a shell command to show the current date and time"
print(f"User: {query}")
result = await agent.run(query)
print(f"Result: {result}\n")
# Print shell-specific content details
for message in result.messages:
shell_calls = [c for c in message.contents if c.type == "shell_tool_call"]
shell_results = [c for c in message.contents if c.type == "shell_tool_result"]
if shell_calls:
print(f"Shell commands: {shell_calls[0].commands}")
if shell_results and shell_results[0].outputs:
for output in shell_results[0].outputs:
if output.stdout:
print(f"Stdout: {output.stdout}")
if output.stderr:
print(f"Stderr: {output.stderr}")
if output.exit_code is not None:
print(f"Exit code: {output.exit_code}")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,92 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from agent_framework import Agent, AgentResponse
from agent_framework.openai import OpenAIChatClient
from dotenv import load_dotenv
from pydantic import BaseModel
# Load environment variables from .env file
load_dotenv()
"""
OpenAI Chat Client with Structured Output Example
This sample demonstrates using structured output capabilities with OpenAI Chat Client,
showing Pydantic model integration for type-safe response parsing and data extraction.
"""
class OutputStruct(BaseModel):
"""A structured output for testing purposes."""
city: str
description: str
async def non_streaming_example() -> None:
print("=== Non-streaming example ===")
# Create an OpenAI Chat agent
agent = Agent(
client=OpenAIChatClient(),
name="CityAgent",
instructions="You are a helpful agent that describes cities in a structured format.",
)
# Ask the agent about a city
query = "Tell me about Paris, France"
print(f"User: {query}")
# Get structured response from the agent using response_format parameter
result = await agent.run(query, options={"response_format": OutputStruct})
# Access the structured output using the parsed value
if structured_data := result.value:
print("Structured Output Agent:")
print(f"City: {structured_data.city}")
print(f"Description: {structured_data.description}")
else:
print(f"Failed to parse response: {result.text}")
async def streaming_example() -> None:
print("=== Streaming example ===")
# Create an OpenAI Chat agent
agent = Agent(
client=OpenAIChatClient(),
name="CityAgent",
instructions="You are a helpful agent that describes cities in a structured format.",
)
# Ask the agent about a city
query = "Tell me about Tokyo, Japan"
print(f"User: {query}")
# Get structured response from streaming agent using AgentResponse.from_update_generator
# This method collects all streaming updates and combines them into a single AgentResponse
result = await AgentResponse.from_update_generator(
agent.run(query, stream=True, options={"response_format": OutputStruct}),
output_format_type=OutputStruct,
)
# Access the structured output using the parsed value
if structured_data := result.value:
print("Structured Output (from streaming with AgentResponse.from_update_generator):")
print(f"City: {structured_data.city}")
print(f"Description: {structured_data.description}")
else:
print(f"Failed to parse response: {result.text}")
async def main() -> None:
print("=== OpenAI Chat Client Agent with Structured Output ===")
await non_streaming_example()
await streaming_example()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,50 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from agent_framework import Agent
from agent_framework.openai import OpenAIChatClient
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
"""
OpenAI Chat Client with Web Search Example
This sample demonstrates using get_web_search_tool() with OpenAI Chat Client
for direct real-time information retrieval and current data access.
"""
async def main() -> None:
client = OpenAIChatClient()
# Create web search tool with location context
web_search_tool = client.get_web_search_tool(
user_location={"city": "Seattle", "country": "US"},
)
agent = Agent(
client=client,
instructions="You are a helpful assistant that can search the web for current information.",
tools=[web_search_tool],
)
message = "What is the current weather? Do not ask for my current location."
stream = False
print(f"User: {message}")
if stream:
print("Assistant: ", end="")
async for chunk in agent.run(message, stream=True):
if chunk.text:
print(chunk.text, end="")
print("")
else:
response = await agent.run(message)
print(f"Assistant: {response}")
if __name__ == "__main__":
asyncio.run(main())