Python: [BREAKING] Simplify API: ChatAgent -> Agent, ChatMessage -> Message (#3747)

* [BREAKING] Rename ChatAgent -> Agent, ChatMessage -> Message, ChatClientProtocol -> SupportsChatGetResponse

Simplify the public API by removing redundant 'Chat' prefix from core types:
- ChatAgent -> Agent
- RawChatAgent -> RawAgent
- ChatMessage -> Message
- ChatClientProtocol -> SupportsChatGetResponse

Also renamed internal WorkflowMessage (was Message in _runner_context) to avoid collision.

No backward compatibility aliases - this is a clean breaking change.

* [BREAKING] Rename Agent chat_client parameter to client

* Fix rebase issues: WorkflowMessage references and broken markdown links

* Fix formatting and lint issues from code quality checks

* Fix import ordering in workflow sample files

* fixed rebase

* Fix test failures: use WorkflowMessage and A2AMessage after ChatMessage→Message rename

- Replace Message(data=..., source_id=...) with WorkflowMessage(...) in workflow tests
- Fix isinstance check in A2A agent to use A2AMessage instead of Message
- Fix import in test_workflow_observability.py (Message→WorkflowMessage)

* Fix lint, fmt, and sample errors after ChatMessage→Message rename

- Auto-fix 70+ ruff lint issues across samples (ChatMessage→Message refs)
- Fix HostedVectorStoreContent→Content.from_hosted_vector_store in file search sample
- Fix _normalize_messages→normalize_messages in custom agent sample
- Fix context.terminate→raise MiddlewareTermination in middleware samples
- Fix with_update_hook→with_transform_hook in override middleware sample
- Add TOptions_co import back to custom_chat_client sample
- Add noqa for FastAPI File() default in chatkit sample
- Fix B023 loop variable capture in weather agent sample

* fix: update Agent constructor calls from chat_client to client in declaration-only tool tests

* fix: add register_cleanup to devui lazy-loading proxy and type stub

* fixed tests and updated new pieces

* fix agui typevar

* fix merge errors

* fix merge conflicts

* fiux merge

* Remove unused links

---------

Co-authored-by: Evan Mattson <evan.mattson@microsoft.com>
This commit is contained in:
Eduard van Valkenburg
2026-02-11 00:04:32 +01:00
committed by GitHub
Unverified
parent a4c9e43afb
commit 0521f5bed8
418 changed files with 5385 additions and 5389 deletions
+2 -2
View File
@@ -6,7 +6,7 @@ This gallery helps AutoGen developers move to the Microsoft Agent Framework (AF)
### Single-Agent Parity
- [01_basic_assistant_agent.py](single_agent/01_basic_assistant_agent.py) — Minimal AutoGen `AssistantAgent` and AF `ChatAgent` comparison.
- [01_basic_assistant_agent.py](single_agent/01_basic_assistant_agent.py) — Minimal AutoGen `AssistantAgent` and AF `Agent` comparison.
- [02_assistant_agent_with_tool.py](single_agent/02_assistant_agent_with_tool.py) — Function tool integration in both SDKs.
- [03_assistant_agent_thread_and_stream.py](single_agent/03_assistant_agent_thread_and_stream.py) — Thread management and streaming responses.
- [04_agent_as_tool.py](single_agent/04_agent_as_tool.py) — Using agents as tools (hierarchical agent pattern) and streaming with tools.
@@ -51,7 +51,7 @@ python samples/autogen-migration/orchestrations/04_magentic_one.py
## Tips for Migration
- **Default behavior differences**: AutoGen's `AssistantAgent` is single-turn by default (`max_tool_iterations=1`), while AF's `ChatAgent` is multi-turn and continues tool execution automatically.
- **Default behavior differences**: AutoGen's `AssistantAgent` is single-turn by default (`max_tool_iterations=1`), while AF's `Agent` is multi-turn and continues tool execution automatically.
- **Thread management**: AF agents are stateless by default. Use `agent.get_new_thread()` and pass it to `run()` to maintain conversation state, similar to AutoGen's conversation context.
- **Tools**: AutoGen uses `FunctionTool` wrappers; AF uses `@tool` decorators with automatic schema inference.
- **Orchestration patterns**:
@@ -21,7 +21,7 @@ from typing import cast
from agent_framework import (
AgentResponseUpdate,
ChatMessage,
Message,
WorkflowEvent,
)
from agent_framework.orchestrations import MagenticProgressLedger
@@ -129,7 +129,7 @@ async def run_agent_framework() -> None:
elif event.type == "magentic_orchestrator":
print(f"\n[Magentic Orchestrator Event] Type: {event.data.event_type.name}")
if isinstance(event.data.content, ChatMessage):
if isinstance(event.data.content, Message):
print(f"Please review the plan:\n{event.data.content.text}")
elif isinstance(event.data.content, MagenticProgressLedger):
print(f"Please review progress ledger:\n{json.dumps(event.data.content.to_dict(), indent=2)}")
@@ -150,7 +150,7 @@ async def run_agent_framework() -> None:
print("Final Output:")
# The output of the Magentic workflow is a list of ChatMessages with only one final message
# generated by the orchestrator.
output_messages = cast(list[ChatMessage], output_event.data)
output_messages = cast(list[Message], output_event.data)
if output_messages:
output = output_messages[-1].text
print(output)
@@ -9,7 +9,7 @@
# uv run samples/autogen-migration/single_agent/01_basic_assistant_agent.py
# Copyright (c) Microsoft. All rights reserved.
"""Basic AutoGen AssistantAgent vs Agent Framework ChatAgent.
"""Basic AutoGen AssistantAgent vs Agent Framework Agent.
Both samples expect OpenAI-compatible environment variables (OPENAI_API_KEY or
Azure OpenAI configuration). Update the prompts or client wiring to match your
@@ -38,10 +38,10 @@ async def run_autogen() -> None:
async def run_agent_framework() -> None:
"""Call Agent Framework's ChatAgent created from OpenAIChatClient."""
"""Call Agent Framework's Agent created from OpenAIChatClient."""
from agent_framework.openai import OpenAIChatClient
# AF constructs a lightweight ChatAgent backed by OpenAIChatClient
# AF constructs a lightweight Agent backed by OpenAIChatClient
client = OpenAIChatClient(model_id="gpt-4.1-mini")
agent = client.as_agent(
name="assistant",
@@ -10,7 +10,7 @@
# uv run samples/autogen-migration/single_agent/02_assistant_agent_with_tool.py
# Copyright (c) Microsoft. All rights reserved.
"""AutoGen AssistantAgent vs Agent Framework ChatAgent with function tools.
"""AutoGen AssistantAgent vs Agent Framework Agent with function tools.
Demonstrates how to create and attach tools to agents in both frameworks.
"""
@@ -2,7 +2,7 @@
import asyncio
from agent_framework import ChatAgent
from agent_framework import Agent
from agent_framework.openai import OpenAIResponsesClient
"""Background Responses Sample.
@@ -22,10 +22,10 @@ Prerequisites:
# 1. Create the agent with an OpenAI Responses client.
agent = ChatAgent(
agent = Agent(
name="researcher",
instructions="You are a helpful research assistant. Be concise.",
chat_client=OpenAIResponsesClient(model_id="o3"),
client=OpenAIResponsesClient(model_id="o3"),
)
+6 -6
View File
@@ -94,9 +94,9 @@ final = await response_stream.get_final_response() # Get the aggregated result
=== Chaining with .map() and .with_finalizer() ===
When building a ChatAgent on top of a ChatClient, we face a challenge:
When building a Agent on top of a ChatClient, we face a challenge:
- The ChatClient returns a ResponseStream[ChatResponseUpdate, ChatResponse]
- The ChatAgent needs to return a ResponseStream[AgentResponseUpdate, AgentResponse]
- The Agent needs to return a ResponseStream[AgentResponseUpdate, AgentResponse]
- We can't iterate the ChatClient's stream twice!
The `.map()` and `.with_finalizer()` methods solve this by creating new ResponseStreams that:
@@ -123,8 +123,8 @@ provider notifications, telemetry, thread updates) are still executed even when
stream is wrapped/mapped.
```python
# ChatAgent does something like this internally:
chat_stream = chat_client.get_response(messages, stream=True)
# Agent does something like this internally:
chat_stream = client.get_response(messages, stream=True)
agent_stream = (
chat_stream
.map(_to_agent_update, _to_agent_response)
@@ -135,7 +135,7 @@ agent_stream = (
This ensures:
- The underlying ChatClient stream is only consumed once
- The agent can add its own transform hooks, result hooks, and cleanup logic
- Each layer (ChatClient, ChatAgent, middleware) can add independent behavior
- Each layer (ChatClient, Agent, middleware) can add independent behavior
- Inner stream post-processing (like context provider notification) still runs
- Types flow naturally through the chain
"""
@@ -281,7 +281,7 @@ async def main() -> None:
# Simulate what ChatClient returns
inner_stream = ResponseStream(generate_updates(), finalizer=combine_updates)
# Simulate what ChatAgent does: wrap the inner stream
# Simulate what Agent does: wrap the inner stream
def to_agent_format(update: ChatResponseUpdate) -> ChatResponseUpdate:
"""Map ChatResponseUpdate to agent format (simulated transformation)."""
# In real code, this would convert to AgentResponseUpdate
+12 -12
View File
@@ -20,7 +20,7 @@ sequenceDiagram
participant Agent as Agent.run()
participant AML as AgentMiddlewareLayer
participant AMP as AgentMiddlewarePipeline
participant RawAgent as RawChatAgent.run()
participant RawAgent as RawAgent.run()
participant CML as ChatMiddlewareLayer
participant CMP as ChatMiddlewarePipeline
participant FIL as FunctionInvocationLayer
@@ -46,14 +46,14 @@ sequenceDiagram
alt Non-Streaming (stream=False)
RawAgent->>RawAgent: _prepare_run_context() [async]
Note right of RawAgent: Builds: thread_messages, chat_options, tools
RawAgent->>CML: chat_client.get_response(stream=False)
RawAgent->>CML: client.get_response(stream=False)
else Streaming (stream=True)
RawAgent->>RawAgent: ResponseStream.from_awaitable()
Note right of RawAgent: Defers async prep to stream consumption
RawAgent-->>User: Returns ResponseStream immediately
Note over RawAgent,CML: Async work happens on iteration
RawAgent->>RawAgent: _prepare_run_context() [deferred]
RawAgent->>CML: chat_client.get_response(stream=True)
RawAgent->>CML: client.get_response(stream=True)
end
Note over CML,CMP: Chat Middleware Layer
@@ -132,7 +132,7 @@ sequenceDiagram
| Field | Type | Description |
|-------|------|-------------|
| `agent` | `SupportsAgentRun` | The agent being invoked |
| `messages` | `list[ChatMessage]` | Input messages (mutable) |
| `messages` | `list[Message]` | Input messages (mutable) |
| `thread` | `AgentThread \| None` | Conversation thread |
| `options` | `Mapping[str, Any]` | Chat options dict |
| `stream` | `bool` | Whether streaming is enabled |
@@ -142,9 +142,9 @@ sequenceDiagram
**Key Operations:**
1. `categorize_middleware()` separates middleware by type (agent, chat, function)
2. Chat and function middleware are forwarded to `chat_client`
2. Chat and function middleware are forwarded to `client`
3. `AgentMiddlewarePipeline.execute()` runs the agent middleware chain
4. Final handler calls `RawChatAgent.run()`
4. Final handler calls `RawAgent.run()`
**What Can Be Modified:**
- `context.messages` - Add, remove, or modify input messages
@@ -154,14 +154,14 @@ sequenceDiagram
### 2. Chat Middleware Layer (`ChatMiddlewareLayer`)
**Entry Point:** `chat_client.get_response(messages, options)`
**Entry Point:** `client.get_response(messages, options)`
**Context Object:** `ChatContext`
| Field | Type | Description |
|-------|------|-------------|
| `chat_client` | `ChatClientProtocol` | The chat client |
| `messages` | `Sequence[ChatMessage]` | Messages to send |
| `client` | `SupportsChatGetResponse` | The chat client |
| `messages` | `Sequence[Message]` | Messages to send |
| `options` | `Mapping[str, Any]` | Chat options |
| `stream` | `bool` | Whether streaming |
| `metadata` | `dict` | Shared data between middleware |
@@ -275,7 +275,7 @@ class TerminatingMiddleware(FunctionMiddleware):
### Agent Layer → Chat Layer
```python
# RawChatAgent._prepare_run_context() builds:
# RawAgent._prepare_run_context() builds:
{
"thread": AgentThread, # Validated/created thread
"input_messages": [...], # Normalized input messages
@@ -463,7 +463,7 @@ Returns `Awaitable[AgentResponse]`:
```python
async def _run_non_streaming():
ctx = await self._prepare_run_context(...) # Async preparation
response = await self.chat_client.get_response(stream=False, ...)
response = await self.client.get_response(stream=False, ...)
await self._finalize_response_and_update_thread(...)
return AgentResponse(...)
```
@@ -476,7 +476,7 @@ Returns `ResponseStream[AgentResponseUpdate, AgentResponse]` **synchronously**:
# Async preparation is deferred using ResponseStream.from_awaitable()
async def _get_stream():
ctx = await self._prepare_run_context(...) # Deferred until iteration
return self.chat_client.get_response(stream=True, ...)
return self.client.get_response(stream=True, ...)
return (
ResponseStream.from_awaitable(_get_stream())
+11 -11
View File
@@ -3,13 +3,13 @@
import asyncio
from typing import Literal
from agent_framework import ChatAgent
from agent_framework import Agent
from agent_framework.anthropic import AnthropicClient
from agent_framework.openai import OpenAIChatClient, OpenAIChatOptions
"""TypedDict-based Chat Options.
In Agent Framework, we have made ChatClient and ChatAgent generic over a ChatOptions typeddict, this means that
In Agent Framework, we have made ChatClient and Agent generic over a ChatOptions typeddict, this means that
you can override which options are available for a given client or agent by providing your own TypedDict subclass.
And we include the most common options for all ChatClient providers out of the box.
@@ -21,7 +21,7 @@ which provides:
including overriding unsupported options.
The sample shows usage with both OpenAI and Anthropic clients, demonstrating
how provider-specific options work for ChatClient and ChatAgent. But the same approach works for other providers too.
how provider-specific options work for ChatClient and Agent. But the same approach works for other providers too.
"""
@@ -49,14 +49,14 @@ async def demo_anthropic_chat_client() -> None:
async def demo_anthropic_agent() -> None:
"""Demonstrate ChatAgent with Anthropic client and typed options."""
print("\n=== ChatAgent with Anthropic and Typed Options ===\n")
"""Demonstrate Agent with Anthropic client and typed options."""
print("\n=== Agent with Anthropic and Typed Options ===\n")
client = AnthropicClient(model_id="claude-sonnet-4-5-20250929")
# Create a typed agent for Anthropic - IDE knows Anthropic-specific options!
agent = ChatAgent(
chat_client=client,
agent = Agent(
client=client,
name="claude-assistant",
instructions="You are a helpful assistant powered by Claude. Be concise.",
default_options={
@@ -132,15 +132,15 @@ async def demo_openai_chat_client_reasoning_models() -> None:
async def demo_openai_agent() -> None:
"""Demonstrate ChatAgent with OpenAI client and typed options."""
print("\n=== ChatAgent with OpenAI and Typed Options ===\n")
"""Demonstrate Agent with OpenAI client and typed options."""
print("\n=== Agent with OpenAI and Typed Options ===\n")
# Create a typed agent - IDE will autocomplete options!
# The type annotation can be done either on the agent like below,
# or on the client when constructing the client instance:
# client = OpenAIChatClient[OpenAIReasoningChatOptions]()
agent = ChatAgent[OpenAIReasoningChatOptions](
chat_client=OpenAIChatClient(),
agent = Agent[OpenAIReasoningChatOptions](
client=OpenAIChatClient(),
name="weather-assistant",
instructions="You are a helpful assistant. Answer concisely.",
# Options can be set at construction time
@@ -38,7 +38,7 @@ graph TB
subgraph Integration["Agent Framework Integration"]
Converter[ThreadItemConverter]
Streamer[stream_agent_response]
Agent[ChatAgent]
Agent[Agent]
end
Widgets[Widget Rendering<br/>render_weather_widget<br/>render_city_selector_widget]
@@ -61,7 +61,7 @@ graph TB
AttStore -.->|save files| Files
AttStore -.->|save metadata| SQLite
Converter -->|ChatMessage array| Agent
Converter -->|Message array| Agent
Agent -->|AgentResponseUpdate| Streamer
Streamer -->|ThreadStreamEvent| ChatKit
@@ -88,7 +88,7 @@ The sample implements a ChatKit server using the `ChatKitServer` base class from
- **`WeatherChatKitServer`**: Custom ChatKit server implementation that:
- Extends `ChatKitServer[dict[str, Any]]`
- Uses Agent Framework's `ChatAgent` with Azure OpenAI
- Uses Agent Framework's `Agent` with Azure OpenAI
- Converts ChatKit messages to Agent Framework format using `ThreadItemConverter`
- Streams responses back to ChatKit using `stream_agent_response`
- Creates and streams interactive widgets after agent responses
+12 -11
View File
@@ -28,7 +28,7 @@ from typing import Annotated, Any
import uvicorn
# Agent Framework imports
from agent_framework import AgentResponseUpdate, ChatAgent, ChatMessage, tool
from agent_framework import Agent, AgentResponseUpdate, FunctionResultContent, Message, Role, tool
from agent_framework.azure import AzureOpenAIChatClient
# Agent Framework ChatKit integration
@@ -217,8 +217,8 @@ class WeatherChatKitServer(ChatKitServer[dict[str, Any]]):
# Create Agent Framework agent with Azure OpenAI
# For authentication, run `az login` command in terminal
try:
self.weather_agent = ChatAgent(
chat_client=AzureOpenAIChatClient(credential=AzureCliCredential()),
self.weather_agent = Agent(
client=AzureOpenAIChatClient(credential=AzureCliCredential()),
instructions=(
"You are a helpful weather assistant with image analysis capabilities. "
"You can provide weather information for any location, tell the current time, "
@@ -290,8 +290,8 @@ class WeatherChatKitServer(ChatKitServer[dict[str, Any]]):
conversation_context = "\n".join(user_messages[:3])
title_prompt = [
ChatMessage(
role="user",
Message(
role=Role.USER,
text=(
f"Generate a very short, concise title (max 40 characters) for a conversation "
f"that starts with:\n\n{conversation_context}\n\n"
@@ -301,7 +301,7 @@ class WeatherChatKitServer(ChatKitServer[dict[str, Any]]):
]
# Use the chat client directly for a quick, lightweight call
response = await self.weather_agent.chat_client.get_response(
response = await self.weather_agent.client.get_response(
messages=title_prompt,
options={
"temperature": 0.3,
@@ -342,6 +342,7 @@ class WeatherChatKitServer(ChatKitServer[dict[str, Any]]):
runs the agent, converts the response back to ChatKit events using stream_agent_response,
and creates interactive weather widgets when weather data is queried.
"""
from agent_framework import FunctionResultContent
if input_user_message is None:
logger.debug("Received None user message, skipping")
@@ -384,7 +385,7 @@ class WeatherChatKitServer(ChatKitServer[dict[str, Any]]):
# Check for function results in the update
if update.contents:
for content in update.contents:
if content.type == "function_result":
if isinstance(content, FunctionResultContent):
result = content.result
# Check if it's a WeatherResponse (string subclass with weather_data attribute)
@@ -467,7 +468,7 @@ class WeatherChatKitServer(ChatKitServer[dict[str, Any]]):
weather_data: WeatherData | None = None
# Create an agent message asking about the weather
agent_messages = [ChatMessage(role="user", text=f"What's the weather in {city_label}?")]
agent_messages = [Message(role=Role.USER, text=f"What's the weather in {city_label}?")]
logger.debug(f"Processing weather query: {agent_messages[0].text}")
@@ -481,7 +482,7 @@ class WeatherChatKitServer(ChatKitServer[dict[str, Any]]):
# Check for function results in the update
if update.contents:
for content in update.contents:
if content.type == "function_result":
if isinstance(content, FunctionResultContent):
result = content.result
# Check if it's a WeatherResponse (string subclass with weather_data attribute)
@@ -572,7 +573,7 @@ async def chatkit_endpoint(request: Request):
@app.post("/upload/{attachment_id}")
async def upload_file(attachment_id: str, file: Annotated[UploadFile, File()]):
async def upload_file(attachment_id: str, file: UploadFile = File(...)): # noqa: B008
"""Handle file upload for two-phase upload.
The client POSTs the file bytes here after creating the attachment
@@ -594,7 +595,7 @@ async def upload_file(attachment_id: str, file: Annotated[UploadFile, File()]):
attachment = await data_store.load_attachment(attachment_id, {"user_id": DEFAULT_USER_ID})
# Clear the upload_url since upload is complete
attachment.upload_url = None # type: ignore[union-attr]
attachment.upload_url = None
# Save the updated attachment back to the store
await data_store.save_attachment(attachment, {"user_id": DEFAULT_USER_ID})
@@ -6,7 +6,7 @@ from collections.abc import MutableSequence
from dataclasses import dataclass
from typing import Any
from agent_framework import ChatMessage, Context, ContextProvider
from agent_framework import Context, ContextProvider, Message
from agent_framework.azure import AzureOpenAIChatClient
from azure.ai.agentserver.agentframework import from_agent_framework # pyright: ignore[reportUnknownVariableType]
from azure.identity import DefaultAzureCredential
@@ -27,16 +27,16 @@ class TextSearchResult:
class TextSearchContextProvider(ContextProvider):
"""A simple context provider that simulates text search results based on keywords in the user's message."""
def _get_most_recent_message(self, messages: ChatMessage | MutableSequence[ChatMessage]) -> ChatMessage:
def _get_most_recent_message(self, messages: Message | MutableSequence[Message]) -> Message:
"""Helper method to extract the most recent message from the input."""
if isinstance(messages, ChatMessage):
if isinstance(messages, Message):
return messages
if messages:
return messages[-1]
raise ValueError("No messages provided")
@override
async def invoking(self, messages: ChatMessage | MutableSequence[ChatMessage], **kwargs: Any) -> Context:
async def invoking(self, messages: Message | MutableSequence[Message], **kwargs: Any) -> Context:
message = self._get_most_recent_message(messages)
query = message.text.lower()
@@ -84,7 +84,7 @@ class TextSearchContextProvider(ContextProvider):
return Context(
messages=[
ChatMessage(
Message(
role="user", text="\n\n".join(json.dumps(result.__dict__, indent=2) for result in results)
)
]
@@ -18,7 +18,7 @@ from dataclasses import dataclass
from random import randint
from typing import Annotated
from agent_framework import ChatAgent, tool
from agent_framework import Agent, tool
from agent_framework.openai import OpenAIChatClient
from aiohttp import web
from aiohttp.web_middlewares import middleware
@@ -95,7 +95,7 @@ def get_weather(
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C."
def build_agent() -> ChatAgent:
def build_agent() -> Agent:
"""Create and return the chat agent instance with weather tool registered."""
return OpenAIChatClient().as_agent(
name="WeatherAgent", instructions="You are a helpful weather agent.", tools=get_weather
@@ -48,8 +48,8 @@ from _tools import (
from agent_framework import (
AgentExecutorResponse,
AgentResponseUpdate,
ChatMessage,
Executor,
Message,
WorkflowBuilder,
WorkflowContext,
executor,
@@ -65,17 +65,17 @@ load_dotenv()
@executor(id="start_executor")
async def start_executor(input: str, ctx: WorkflowContext[list[ChatMessage]]) -> None:
async def start_executor(input: str, ctx: WorkflowContext[list[Message]]) -> None:
"""Initiates the workflow by sending the user query to all specialized agents."""
await ctx.send_message([ChatMessage("user", [input])])
await ctx.send_message([Message("user", [input])])
class ResearchLead(Executor):
"""Aggregates and summarizes travel planning findings from all specialized agents."""
def __init__(self, chat_client: AzureAIClient, id: str = "travel-planning-coordinator"):
def __init__(self, client: AzureAIClient, id: str = "travel-planning-coordinator"):
# store=True to preserve conversation history for evaluation
self.agent = chat_client.as_agent(
self.agent = client.as_agent(
id="travel-planning-coordinator",
instructions=(
"You are the final coordinator. You will receive responses from multiple agents: "
@@ -102,11 +102,11 @@ class ResearchLead(Executor):
# Generate comprehensive travel plan summary
messages = [
ChatMessage(
Message(
role="system",
text="You are a travel planning coordinator. Summarize findings from multiple specialized travel agents and provide a clear, comprehensive travel plan based on the user's query.",
),
ChatMessage(
Message(
role="user",
text=f"Original query: {user_query}\n\nFindings from specialized travel agents:\n{summary_text}\n\nPlease provide a comprehensive travel plan based on these findings.",
),
@@ -142,17 +142,17 @@ class ResearchLead(Executor):
return agent_findings
async def run_workflow_with_response_tracking(query: str, chat_client: AzureAIClient | None = None) -> dict:
async def run_workflow_with_response_tracking(query: str, client: AzureAIClient | None = None) -> dict:
"""Run multi-agent workflow and track conversation IDs, response IDs, and interaction sequence.
Args:
query: The user query to process through the multi-agent workflow
chat_client: Optional AzureAIClient instance
client: Optional AzureAIClient instance
Returns:
Dictionary containing interaction sequence, conversation/response IDs, and conversation analysis
"""
if chat_client is None:
if client is None:
try:
async with DefaultAzureCredential() as credential:
# Create AIProjectClient with the correct API version for V2 prompt agents
@@ -171,10 +171,10 @@ async def run_workflow_with_response_tracking(query: str, chat_client: AzureAICl
print(f"Error during workflow execution: {e}")
raise
else:
return await _run_workflow_with_client(query, chat_client)
return await _run_workflow_with_client(query, client)
async def _run_workflow_with_client(query: str, chat_client: AzureAIClient) -> dict:
async def _run_workflow_with_client(query: str, client: AzureAIClient) -> dict:
"""Execute workflow with given client and track all interactions."""
# Initialize tracking variables - use lists to track multiple responses per agent
@@ -184,7 +184,7 @@ async def _run_workflow_with_client(query: str, chat_client: AzureAIClient) -> d
# Create workflow components and keep agent references
# Pass project_client and credential to create separate client instances per agent
workflow, agent_map = await _create_workflow(chat_client.project_client, chat_client.credential)
workflow, agent_map = await _create_workflow(client.project_client, client.credential)
# Process workflow events
events = workflow.run(query, stream=True)
@@ -210,7 +210,7 @@ async def _create_workflow(project_client, credential):
final_coordinator_client = AzureAIClient(
project_client=project_client, credential=credential, agent_name="final-coordinator"
)
final_coordinator = ResearchLead(chat_client=final_coordinator_client, id="final-coordinator")
final_coordinator = ResearchLead(client=final_coordinator_client, id="final-coordinator")
# Agent 1: Travel Request Handler (initial coordinator)
# Create separate client with unique agent_name
@@ -23,7 +23,7 @@ This sample demonstrates the three main methods of AzureAIProjectAgentProvider:
It also shows how to use a single provider instance to spawn multiple agents
with different configurations, which is efficient for multi-agent scenarios.
Each method returns a ChatAgent that can be used for conversations.
Each method returns a Agent that can be used for conversations.
"""
@@ -41,7 +41,7 @@ async def create_agent_example() -> None:
"""Example of using provider.create_agent() to create a new agent.
This method creates a new agent version on the Azure AI service and returns
a ChatAgent. Use this when you want to create a fresh agent with
a Agent. Use this when you want to create a fresh agent with
specific configuration.
"""
print("=== provider.create_agent() Example ===")
@@ -199,7 +199,7 @@ async def multiple_agents_example() -> None:
async def as_agent_example() -> None:
"""Example of using provider.as_agent() to wrap an SDK object without HTTP calls.
This method wraps an existing AgentVersionDetails into a ChatAgent without
This method wraps an existing AgentVersionDetails into a Agent without
making additional HTTP calls. Use this when you already have the full
AgentVersionDetails from a previous SDK operation.
"""
@@ -3,7 +3,7 @@
import asyncio
import os
from agent_framework import ChatAgent
from agent_framework import Agent
from agent_framework.azure import AzureAIClient
from azure.ai.projects.aio import AIProjectClient
from azure.identity.aio import AzureCliCredential
@@ -23,8 +23,8 @@ async def main() -> None:
# Endpoint here should be application endpoint with format:
# /api/projects/<project-name>/applications/<application-name>/protocols
AIProjectClient(endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], credential=credential) as project_client,
ChatAgent(
chat_client=AzureAIClient(
Agent(
client=AzureAIClient(
project_client=project_client,
),
) as agent,
@@ -5,9 +5,9 @@ import tempfile
from pathlib import Path
from agent_framework import (
Agent,
AgentResponseUpdate,
Annotation,
ChatAgent,
Content,
HostedCodeInterpreterTool,
)
@@ -33,7 +33,7 @@ QUERY = (
)
async def download_container_files(file_contents: list[Annotation | Content], agent: ChatAgent) -> list[Path]:
async def download_container_files(file_contents: list[Annotation | Content], agent: Agent) -> list[Path]:
"""Download container files using the OpenAI containers API.
Code interpreter generates files in containers, which require both file_id
@@ -45,7 +45,7 @@ async def download_container_files(file_contents: list[Annotation | Content], ag
Args:
file_contents: List of Annotation or Content objects
containing file_id and container_id.
agent: The ChatAgent instance with access to the AzureAIClient.
agent: The Agent instance with access to the AzureAIClient.
Returns:
List of Path objects for successfully downloaded files.
@@ -61,7 +61,7 @@ async def download_container_files(file_contents: list[Annotation | Content], ag
print(f"\nDownloading {len(file_contents)} container file(s) to {output_dir.absolute()}...")
# Access the OpenAI client from AzureAIClient
openai_client = agent.chat_client.client # type: ignore[attr-defined]
openai_client = agent.client.client # type: ignore[attr-defined]
downloaded_files: list[Path] = []
@@ -139,7 +139,7 @@ async def non_streaming_example() -> None:
# Check for annotations in the response
annotations_found: list[Annotation] = []
# AgentResponse has messages property, which contains ChatMessage objects
# AgentResponse has messages property, which contains Message objects
for message in result.messages:
for content in message.contents:
if content.type == "text" and content.annotations:
@@ -44,7 +44,7 @@ async def non_streaming_example() -> None:
# Check for annotations in the response
annotations_found: list[str] = []
# AgentResponse has messages property, which contains ChatMessage objects
# AgentResponse has messages property, which contains Message objects
for message in result.messages:
for content in message.contents:
if content.type == "text" and content.annotations:
@@ -36,7 +36,7 @@ async def using_provider_get_agent() -> None:
)
try:
# Get newly created agent as ChatAgent by using provider.get_agent()
# Get newly created agent as Agent by using provider.get_agent()
provider = AzureAIProjectAgentProvider(project_client=project_client)
agent = await provider.get_agent(name=azure_ai_agent.name)
@@ -3,7 +3,7 @@
import asyncio
from typing import Any
from agent_framework import AgentResponse, AgentThread, ChatMessage, HostedMCPTool, SupportsAgentRun
from agent_framework import AgentResponse, AgentThread, HostedMCPTool, Message, SupportsAgentRun
from agent_framework.azure import AzureAIProjectAgentProvider
from azure.identity.aio import AzureCliCredential
@@ -25,10 +25,10 @@ async def handle_approvals_without_thread(query: str, agent: "SupportsAgentRun")
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(ChatMessage("assistant", [user_input_needed]))
new_inputs.append(Message("assistant", [user_input_needed]))
user_approval = input("Approve function call? (y/n): ")
new_inputs.append(
ChatMessage("user", [user_input_needed.to_function_approval_response(user_approval.lower() == "y")])
Message("user", [user_input_needed.to_function_approval_response(user_approval.lower() == "y")])
)
result = await agent.run(new_inputs, store=False)
@@ -48,7 +48,7 @@ async def handle_approvals_with_thread(query: str, agent: "SupportsAgentRun", th
)
user_approval = input("Approve function call? (y/n): ")
new_input.append(
ChatMessage(
Message(
role="user",
contents=[user_input_needed.to_function_approval_response(user_approval.lower() == "y")],
)
@@ -8,7 +8,7 @@ All examples in this folder use the `AzureAIAgentsProvider` class which provides
- **`create_agent()`** - Create a new agent on the Azure AI service
- **`get_agent()`** - Retrieve an existing agent by ID or from a pre-fetched Agent object
- **`as_agent()`** - Wrap an SDK Agent object as a ChatAgent without HTTP calls
- **`as_agent()`** - Wrap an SDK Agent object as a Agent without HTTP calls
```python
from agent_framework.azure import AzureAIAgentsProvider
@@ -17,7 +17,7 @@ servers, including user approval workflows for function call security.
async def handle_approvals_with_thread(query: str, agent: "SupportsAgentRun", thread: "AgentThread") -> AgentResponse:
"""Here we let the thread deal with the previous responses, and we just rerun with the approval."""
from agent_framework import ChatMessage
from agent_framework import Message
result = await agent.run(query, thread=thread, store=True)
while len(result.user_input_requests) > 0:
@@ -29,7 +29,7 @@ async def handle_approvals_with_thread(query: str, agent: "SupportsAgentRun", th
)
user_approval = input("Approve function call? (y/n): ")
new_input.append(
ChatMessage(
Message(
role="user",
contents=[user_input_needed.to_function_approval_response(user_approval.lower() == "y")],
)
@@ -51,7 +51,7 @@ async def mcp_tools_on_agent_level() -> None:
print("=== Tools Defined on Agent Level ===")
# Tools are provided when creating the agent
# The ChatAgent will connect to the MCP server through its context manager
# The Agent will connect to the MCP server through its context manager
# and discover tools at runtime
async with (
AzureCliCredential() as credential,
@@ -45,7 +45,7 @@ def get_time() -> str:
async def handle_approvals_with_thread(query: str, agent: "SupportsAgentRun", thread: "AgentThread"):
"""Here we let the thread deal with the previous responses, and we just rerun with the approval."""
from agent_framework import ChatMessage
from agent_framework import Message
result = await agent.run(query, thread=thread, store=True)
while len(result.user_input_requests) > 0:
@@ -57,7 +57,7 @@ async def handle_approvals_with_thread(query: str, agent: "SupportsAgentRun", th
)
user_approval = input("Approve function call? (y/n): ")
new_input.append(
ChatMessage(
Message(
role="user",
contents=[user_input_needed.to_function_approval_response(user_approval.lower() == "y")],
)
@@ -6,17 +6,17 @@ This folder contains examples demonstrating different ways to create and use age
| File | Description |
|------|-------------|
| [`azure_assistants_basic.py`](azure_assistants_basic.py) | The simplest way to create an agent using `ChatAgent` with `AzureOpenAIAssistantsClient`. Shows both streaming and non-streaming responses with automatic assistant creation and cleanup. |
| [`azure_assistants_basic.py`](azure_assistants_basic.py) | The simplest way to create an agent using `Agent` with `AzureOpenAIAssistantsClient`. Shows both streaming and non-streaming responses with automatic assistant creation and cleanup. |
| [`azure_assistants_with_code_interpreter.py`](azure_assistants_with_code_interpreter.py) | Shows how to use the HostedCodeInterpreterTool with Azure agents to write and execute Python code. Includes helper methods for accessing code interpreter data from response chunks. |
| [`azure_assistants_with_existing_assistant.py`](azure_assistants_with_existing_assistant.py) | Shows how to work with a pre-existing assistant by providing the assistant ID to the Azure Assistants client. Demonstrates proper cleanup of manually created assistants. |
| [`azure_assistants_with_explicit_settings.py`](azure_assistants_with_explicit_settings.py) | Shows how to initialize an agent with a specific assistants client, configuring settings explicitly including endpoint and deployment name. |
| [`azure_assistants_with_function_tools.py`](azure_assistants_with_function_tools.py) | Demonstrates how to use function tools with agents. Shows both agent-level tools (defined when creating the agent) and query-level tools (provided with specific queries). |
| [`azure_assistants_with_thread.py`](azure_assistants_with_thread.py) | Demonstrates thread management with Azure agents, including automatic thread creation for stateless conversations and explicit thread management for maintaining conversation context across multiple interactions. |
| [`azure_chat_client_basic.py`](azure_chat_client_basic.py) | The simplest way to create an agent using `ChatAgent` with `AzureOpenAIChatClient`. Shows both streaming and non-streaming responses for chat-based interactions with Azure OpenAI models. |
| [`azure_chat_client_basic.py`](azure_chat_client_basic.py) | The simplest way to create an agent using `Agent` with `AzureOpenAIChatClient`. Shows both streaming and non-streaming responses for chat-based interactions with Azure OpenAI models. |
| [`azure_chat_client_with_explicit_settings.py`](azure_chat_client_with_explicit_settings.py) | Shows how to initialize an agent with a specific chat client, configuring settings explicitly including endpoint and deployment name. |
| [`azure_chat_client_with_function_tools.py`](azure_chat_client_with_function_tools.py) | Demonstrates how to use function tools with agents. Shows both agent-level tools (defined when creating the agent) and query-level tools (provided with specific queries). |
| [`azure_chat_client_with_thread.py`](azure_chat_client_with_thread.py) | Demonstrates thread management with Azure agents, including automatic thread creation for stateless conversations and explicit thread management for maintaining conversation context across multiple interactions. |
| [`azure_responses_client_basic.py`](azure_responses_client_basic.py) | The simplest way to create an agent using `ChatAgent` with `AzureOpenAIResponsesClient`. Shows both streaming and non-streaming responses for structured response generation with Azure OpenAI models. |
| [`azure_responses_client_basic.py`](azure_responses_client_basic.py) | The simplest way to create an agent using `Agent` with `AzureOpenAIResponsesClient`. Shows both streaming and non-streaming responses for structured response generation with Azure OpenAI models. |
| [`azure_responses_client_code_interpreter_files.py`](azure_responses_client_code_interpreter_files.py) | Demonstrates using HostedCodeInterpreterTool with file uploads for data analysis. Shows how to create, upload, and analyze CSV files using Python code execution with Azure OpenAI Responses. |
| [`azure_responses_client_image_analysis.py`](azure_responses_client_image_analysis.py) | Shows how to use Azure OpenAI Responses for image analysis and vision tasks. Demonstrates multi-modal messages combining text and image content using remote URLs. |
| [`azure_responses_client_with_code_interpreter.py`](azure_responses_client_with_code_interpreter.py) | Shows how to use the HostedCodeInterpreterTool with Azure agents to write and execute Python code. Includes helper methods for accessing code interpreter data from response chunks. |
@@ -2,7 +2,7 @@
import asyncio
from agent_framework import AgentResponseUpdate, ChatAgent, ChatResponseUpdate, HostedCodeInterpreterTool
from agent_framework import Agent, AgentResponseUpdate, ChatResponseUpdate, HostedCodeInterpreterTool
from agent_framework.azure import AzureOpenAIAssistantsClient
from azure.identity import AzureCliCredential
from openai.types.beta.threads.runs import (
@@ -46,8 +46,8 @@ async def main() -> None:
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
async with ChatAgent(
chat_client=AzureOpenAIAssistantsClient(credential=AzureCliCredential()),
async with Agent(
client=AzureOpenAIAssistantsClient(credential=AzureCliCredential()),
instructions="You are a helpful assistant that can write and execute Python code to solve problems.",
tools=HostedCodeInterpreterTool(),
) as agent:
@@ -5,7 +5,7 @@ import os
from random import randint
from typing import Annotated
from agent_framework import ChatAgent, tool
from agent_framework import Agent, tool
from agent_framework.azure import AzureOpenAIAssistantsClient
from azure.identity import AzureCliCredential, get_bearer_token_provider
from openai import AsyncAzureOpenAI
@@ -46,8 +46,8 @@ async def main() -> None:
)
try:
async with ChatAgent(
chat_client=AzureOpenAIAssistantsClient(async_client=client, assistant_id=created_assistant.id),
async with Agent(
client=AzureOpenAIAssistantsClient(async_client=client, assistant_id=created_assistant.id),
instructions="You are a helpful weather agent.",
tools=get_weather,
) as agent:
@@ -5,7 +5,7 @@ from datetime import datetime, timezone
from random import randint
from typing import Annotated
from agent_framework import ChatAgent, tool
from agent_framework import Agent, tool
from agent_framework.azure import AzureOpenAIAssistantsClient
from azure.identity import AzureCliCredential
from pydantic import Field
@@ -43,8 +43,8 @@ async def tools_on_agent_level() -> None:
# 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.
async with ChatAgent(
chat_client=AzureOpenAIAssistantsClient(credential=AzureCliCredential()),
async with Agent(
client=AzureOpenAIAssistantsClient(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
) as agent:
@@ -74,8 +74,8 @@ async def tools_on_run_level() -> None:
# Agent created without tools
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
async with ChatAgent(
chat_client=AzureOpenAIAssistantsClient(credential=AzureCliCredential()),
async with Agent(
client=AzureOpenAIAssistantsClient(credential=AzureCliCredential()),
instructions="You are a helpful assistant.",
# No tools defined here
) as agent:
@@ -105,8 +105,8 @@ async def mixed_tools_example() -> None:
# Agent created with some base tools
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
async with ChatAgent(
chat_client=AzureOpenAIAssistantsClient(credential=AzureCliCredential()),
async with Agent(
client=AzureOpenAIAssistantsClient(credential=AzureCliCredential()),
instructions="You are a comprehensive assistant that can help with various information requests.",
tools=[get_weather], # Base tool available for all queries
) as agent:
@@ -4,7 +4,7 @@ import asyncio
from random import randint
from typing import Annotated
from agent_framework import AgentThread, ChatAgent, tool
from agent_framework import Agent, AgentThread, tool
from agent_framework.azure import AzureOpenAIAssistantsClient
from azure.identity import AzureCliCredential
from pydantic import Field
@@ -33,8 +33,8 @@ async def example_with_automatic_thread_creation() -> None:
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
async with ChatAgent(
chat_client=AzureOpenAIAssistantsClient(credential=AzureCliCredential()),
async with Agent(
client=AzureOpenAIAssistantsClient(credential=AzureCliCredential()),
instructions="You are a helpful weather agent.",
tools=get_weather,
) as agent:
@@ -59,8 +59,8 @@ async def example_with_thread_persistence() -> None:
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
async with ChatAgent(
chat_client=AzureOpenAIAssistantsClient(credential=AzureCliCredential()),
async with Agent(
client=AzureOpenAIAssistantsClient(credential=AzureCliCredential()),
instructions="You are a helpful weather agent.",
tools=get_weather,
) as agent:
@@ -97,8 +97,8 @@ async def example_with_existing_thread_id() -> None:
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
async with ChatAgent(
chat_client=AzureOpenAIAssistantsClient(credential=AzureCliCredential()),
async with Agent(
client=AzureOpenAIAssistantsClient(credential=AzureCliCredential()),
instructions="You are a helpful weather agent.",
tools=get_weather,
) as agent:
@@ -117,8 +117,8 @@ async def example_with_existing_thread_id() -> None:
print("\n--- Continuing with the same thread ID in a new agent instance ---")
# Create a new agent instance but use the existing thread ID
async with ChatAgent(
chat_client=AzureOpenAIAssistantsClient(thread_id=existing_thread_id, credential=AzureCliCredential()),
async with Agent(
client=AzureOpenAIAssistantsClient(thread_id=existing_thread_id, credential=AzureCliCredential()),
instructions="You are a helpful weather agent.",
tools=get_weather,
) as agent:
@@ -5,7 +5,7 @@ from datetime import datetime, timezone
from random import randint
from typing import Annotated
from agent_framework import ChatAgent, tool
from agent_framework import Agent, tool
from agent_framework.azure import AzureOpenAIChatClient
from azure.identity import AzureCliCredential
from pydantic import Field
@@ -43,8 +43,8 @@ async def tools_on_agent_level() -> None:
# 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 = ChatAgent(
chat_client=AzureOpenAIChatClient(credential=AzureCliCredential()),
agent = Agent(
client=AzureOpenAIChatClient(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
)
@@ -75,8 +75,8 @@ async def tools_on_run_level() -> None:
# Agent created without tools
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
agent = ChatAgent(
chat_client=AzureOpenAIChatClient(credential=AzureCliCredential()),
agent = Agent(
client=AzureOpenAIChatClient(credential=AzureCliCredential()),
instructions="You are a helpful assistant.",
# No tools defined here
)
@@ -107,8 +107,8 @@ async def mixed_tools_example() -> None:
# Agent created with some base tools
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
agent = ChatAgent(
chat_client=AzureOpenAIChatClient(credential=AzureCliCredential()),
agent = Agent(
client=AzureOpenAIChatClient(credential=AzureCliCredential()),
instructions="You are a comprehensive assistant that can help with various information requests.",
tools=[get_weather], # Base tool available for all queries
)
@@ -4,7 +4,7 @@ import asyncio
from random import randint
from typing import Annotated
from agent_framework import AgentThread, ChatAgent, ChatMessageStore, tool
from agent_framework import Agent, AgentThread, ChatMessageStore, tool
from agent_framework.azure import AzureOpenAIChatClient
from azure.identity import AzureCliCredential
from pydantic import Field
@@ -33,8 +33,8 @@ async def example_with_automatic_thread_creation() -> None:
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
agent = ChatAgent(
chat_client=AzureOpenAIChatClient(credential=AzureCliCredential()),
agent = Agent(
client=AzureOpenAIChatClient(credential=AzureCliCredential()),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
@@ -60,8 +60,8 @@ async def example_with_thread_persistence() -> None:
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
agent = ChatAgent(
chat_client=AzureOpenAIChatClient(credential=AzureCliCredential()),
agent = Agent(
client=AzureOpenAIChatClient(credential=AzureCliCredential()),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
@@ -95,8 +95,8 @@ async def example_with_existing_thread_messages() -> None:
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
agent = ChatAgent(
chat_client=AzureOpenAIChatClient(credential=AzureCliCredential()),
agent = Agent(
client=AzureOpenAIChatClient(credential=AzureCliCredential()),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
@@ -117,8 +117,8 @@ async def example_with_existing_thread_messages() -> None:
print("\n--- Continuing with the same thread in a new agent instance ---")
# Create a new agent instance but use the existing thread with its message history
new_agent = ChatAgent(
chat_client=AzureOpenAIChatClient(credential=AzureCliCredential()),
new_agent = Agent(
client=AzureOpenAIChatClient(credential=AzureCliCredential()),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
@@ -4,7 +4,7 @@ import asyncio
import os
import tempfile
from agent_framework import ChatAgent, HostedCodeInterpreterTool
from agent_framework import Agent, HostedCodeInterpreterTool
from agent_framework.azure import AzureOpenAIResponsesClient
from azure.identity import AzureCliCredential
from openai import AsyncAzureOpenAI
@@ -76,8 +76,8 @@ async def main() -> None:
temp_file_path, file_id = await create_sample_file_and_upload(openai_client)
# Create agent using Azure OpenAI Responses client
agent = ChatAgent(
chat_client=AzureOpenAIResponsesClient(credential=credential),
agent = Agent(
client=AzureOpenAIResponsesClient(credential=credential),
instructions="You are a helpful assistant that can analyze data files using Python code.",
tools=HostedCodeInterpreterTool(inputs=[{"file_id": file_id}]),
)
@@ -2,7 +2,7 @@
import asyncio
from agent_framework import ChatMessage, Content
from agent_framework import Content, Message
from agent_framework.azure import AzureOpenAIResponsesClient
from azure.identity import AzureCliCredential
@@ -24,7 +24,7 @@ async def main():
)
# 2. Create a simple message with both text and image content
user_message = ChatMessage(
user_message = Message(
role="user",
contents=[
Content.from_text(text="What do you see in this image?"),
@@ -2,7 +2,7 @@
import asyncio
from agent_framework import ChatAgent, ChatResponse, HostedCodeInterpreterTool
from agent_framework import Agent, ChatResponse, HostedCodeInterpreterTool
from agent_framework.azure import AzureOpenAIResponsesClient
from azure.identity import AzureCliCredential
from openai.types.responses.response import Response as OpenAIResponse
@@ -22,8 +22,8 @@ async def main() -> None:
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
agent = ChatAgent(
chat_client=AzureOpenAIResponsesClient(credential=AzureCliCredential()),
agent = Agent(
client=AzureOpenAIResponsesClient(credential=AzureCliCredential()),
instructions="You are a helpful assistant that can write and execute Python code to solve problems.",
tools=HostedCodeInterpreterTool(),
)
@@ -2,7 +2,7 @@
import asyncio
from agent_framework import ChatAgent, Content, HostedFileSearchTool
from agent_framework import Agent, Content, HostedFileSearchTool
from agent_framework.azure import AzureOpenAIResponsesClient
from azure.identity import AzureCliCredential
@@ -53,8 +53,8 @@ async def main() -> None:
file_id, vector_store = await create_vector_store(client)
agent = ChatAgent(
chat_client=client,
agent = Agent(
client=client,
instructions="You are a helpful assistant that can search through files to find information.",
tools=[HostedFileSearchTool(inputs=vector_store)],
)
@@ -5,7 +5,7 @@ from datetime import datetime, timezone
from random import randint
from typing import Annotated
from agent_framework import ChatAgent, tool
from agent_framework import Agent, tool
from agent_framework.azure import AzureOpenAIResponsesClient
from azure.identity import AzureCliCredential
from pydantic import Field
@@ -43,8 +43,8 @@ async def tools_on_agent_level() -> None:
# 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 = ChatAgent(
chat_client=AzureOpenAIResponsesClient(credential=AzureCliCredential()),
agent = Agent(
client=AzureOpenAIResponsesClient(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
)
@@ -75,8 +75,8 @@ async def tools_on_run_level() -> None:
# Agent created without tools
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
agent = ChatAgent(
chat_client=AzureOpenAIResponsesClient(credential=AzureCliCredential()),
agent = Agent(
client=AzureOpenAIResponsesClient(credential=AzureCliCredential()),
instructions="You are a helpful assistant.",
# No tools defined here
)
@@ -107,8 +107,8 @@ async def mixed_tools_example() -> None:
# Agent created with some base tools
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
agent = ChatAgent(
chat_client=AzureOpenAIResponsesClient(credential=AzureCliCredential()),
agent = Agent(
client=AzureOpenAIResponsesClient(credential=AzureCliCredential()),
instructions="You are a comprehensive assistant that can help with various information requests.",
tools=[get_weather], # Base tool available for all queries
)
@@ -3,7 +3,7 @@
import asyncio
from typing import TYPE_CHECKING, Any
from agent_framework import ChatAgent, HostedMCPTool
from agent_framework import Agent, HostedMCPTool
from agent_framework.azure import AzureOpenAIResponsesClient
from azure.identity import AzureCliCredential
@@ -20,7 +20,7 @@ if TYPE_CHECKING:
async def handle_approvals_without_thread(query: str, agent: "SupportsAgentRun"):
"""When we don't have a thread, we need to ensure we return with the input, approval request and approval."""
from agent_framework import ChatMessage
from agent_framework import Message
result = await agent.run(query)
while len(result.user_input_requests) > 0:
@@ -30,10 +30,10 @@ async def handle_approvals_without_thread(query: str, agent: "SupportsAgentRun")
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(ChatMessage(role="assistant", contents=[user_input_needed]))
new_inputs.append(Message(role="assistant", contents=[user_input_needed]))
user_approval = input("Approve function call? (y/n): ")
new_inputs.append(
ChatMessage(role="user", contents=[user_input_needed.to_function_approval_response(user_approval.lower() == "y")])
Message(role="user", contents=[user_input_needed.to_function_approval_response(user_approval.lower() == "y")])
)
result = await agent.run(new_inputs)
@@ -42,7 +42,7 @@ async def handle_approvals_without_thread(query: str, agent: "SupportsAgentRun")
async def handle_approvals_with_thread(query: str, agent: "SupportsAgentRun", thread: "AgentThread"):
"""Here we let the thread deal with the previous responses, and we just rerun with the approval."""
from agent_framework import ChatMessage
from agent_framework import Message
result = await agent.run(query, thread=thread, store=True)
while len(result.user_input_requests) > 0:
@@ -54,7 +54,7 @@ async def handle_approvals_with_thread(query: str, agent: "SupportsAgentRun", th
)
user_approval = input("Approve function call? (y/n): ")
new_input.append(
ChatMessage(
Message(
role="user",
contents=[user_input_needed.to_function_approval_response(user_approval.lower() == "y")],
)
@@ -65,13 +65,13 @@ async def handle_approvals_with_thread(query: str, agent: "SupportsAgentRun", th
async def handle_approvals_with_thread_streaming(query: str, agent: "SupportsAgentRun", thread: "AgentThread"):
"""Here we let the thread deal with the previous responses, and we just rerun with the approval."""
from agent_framework import ChatMessage
from agent_framework import Message
new_input: list[ChatMessage] = []
new_input: list[Message] = []
new_input_added = True
while new_input_added:
new_input_added = False
new_input.append(ChatMessage(role="user", text=query))
new_input.append(Message(role="user", text=query))
async for update in agent.run(new_input, thread=thread, options={"store": True}, stream=True):
if update.user_input_requests:
for user_input_needed in update.user_input_requests:
@@ -81,7 +81,7 @@ async def handle_approvals_with_thread_streaming(query: str, agent: "SupportsAge
)
user_approval = input("Approve function call? (y/n): ")
new_input.append(
ChatMessage(
Message(
role="user", contents=[user_input_needed.to_function_approval_response(user_approval.lower() == "y")]
)
)
@@ -96,8 +96,8 @@ async def run_hosted_mcp_without_thread_and_specific_approval() -> None:
credential = AzureCliCredential()
# Tools are provided when creating the agent
# The agent can use these tools for any query during its lifetime
async with ChatAgent(
chat_client=AzureOpenAIResponsesClient(
async with Agent(
client=AzureOpenAIResponsesClient(
credential=credential,
),
name="DocsAgent",
@@ -129,8 +129,8 @@ async def run_hosted_mcp_without_approval() -> None:
credential = AzureCliCredential()
# Tools are provided when creating the agent
# The agent can use these tools for any query during its lifetime
async with ChatAgent(
chat_client=AzureOpenAIResponsesClient(
async with Agent(
client=AzureOpenAIResponsesClient(
credential=credential,
),
name="DocsAgent",
@@ -163,8 +163,8 @@ async def run_hosted_mcp_with_thread() -> None:
credential = AzureCliCredential()
# Tools are provided when creating the agent
# The agent can use these tools for any query during its lifetime
async with ChatAgent(
chat_client=AzureOpenAIResponsesClient(
async with Agent(
client=AzureOpenAIResponsesClient(
credential=credential,
),
name="DocsAgent",
@@ -196,8 +196,8 @@ async def run_hosted_mcp_with_thread_streaming() -> None:
credential = AzureCliCredential()
# Tools are provided when creating the agent
# The agent can use these tools for any query during its lifetime
async with ChatAgent(
chat_client=AzureOpenAIResponsesClient(
async with Agent(
client=AzureOpenAIResponsesClient(
credential=credential,
),
name="DocsAgent",
@@ -3,7 +3,7 @@
import asyncio
import os
from agent_framework import ChatAgent, MCPStreamableHTTPTool
from agent_framework import Agent, MCPStreamableHTTPTool
from agent_framework.azure import AzureOpenAIResponsesClient
from azure.identity import AzureCliCredential
@@ -37,7 +37,7 @@ async def main():
credential=credential,
)
agent: ChatAgent = responses_client.as_agent(
agent: Agent = responses_client.as_agent(
name="DocsAgent",
instructions=("You are a helpful assistant that can help with Microsoft documentation questions."),
)
@@ -4,7 +4,7 @@ import asyncio
from random import randint
from typing import Annotated
from agent_framework import AgentThread, ChatAgent, tool
from agent_framework import Agent, AgentThread, tool
from agent_framework.azure import AzureOpenAIResponsesClient
from azure.identity import AzureCliCredential
from pydantic import Field
@@ -33,8 +33,8 @@ async def example_with_automatic_thread_creation() -> None:
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
agent = ChatAgent(
chat_client=AzureOpenAIResponsesClient(credential=AzureCliCredential()),
agent = Agent(
client=AzureOpenAIResponsesClient(credential=AzureCliCredential()),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
@@ -62,8 +62,8 @@ async def example_with_thread_persistence_in_memory() -> None:
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
agent = ChatAgent(
chat_client=AzureOpenAIResponsesClient(credential=AzureCliCredential()),
agent = Agent(
client=AzureOpenAIResponsesClient(credential=AzureCliCredential()),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
@@ -103,8 +103,8 @@ async def example_with_existing_thread_id() -> None:
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
agent = ChatAgent(
chat_client=AzureOpenAIResponsesClient(credential=AzureCliCredential()),
agent = Agent(
client=AzureOpenAIResponsesClient(credential=AzureCliCredential()),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
@@ -125,8 +125,8 @@ async def example_with_existing_thread_id() -> None:
if existing_thread_id:
print("\n--- Continuing with the same thread ID in a new agent instance ---")
agent = ChatAgent(
chat_client=AzureOpenAIResponsesClient(credential=AzureCliCredential()),
agent = Agent(
client=AzureOpenAIResponsesClient(credential=AzureCliCredential()),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
@@ -7,7 +7,7 @@ This folder contains examples demonstrating how to implement custom agents and c
| 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 thread 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 `ChatAgent` using the `as_agent()` method. |
| [`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
@@ -20,7 +20,7 @@ This folder contains examples demonstrating how to implement custom agents and c
### 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 `ChatAgent` to leverage all agent framework features
- 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.
@@ -9,8 +9,8 @@ from agent_framework import (
AgentResponseUpdate,
AgentThread,
BaseAgent,
ChatMessage,
Content,
Message,
Role,
normalize_messages,
)
@@ -57,7 +57,7 @@ class EchoAgent(BaseAgent):
def run(
self,
messages: str | ChatMessage | list[str] | list[ChatMessage] | None = None,
messages: str | Message | list[str] | list[Message] | None = None,
*,
stream: bool = False,
thread: AgentThread | None = None,
@@ -81,7 +81,7 @@ class EchoAgent(BaseAgent):
async def _run(
self,
messages: str | ChatMessage | list[str] | list[ChatMessage] | None = None,
messages: str | Message | list[str] | list[Message] | None = None,
*,
thread: AgentThread | None = None,
**kwargs: Any,
@@ -91,11 +91,9 @@ class EchoAgent(BaseAgent):
normalized_messages = normalize_messages(messages)
if not normalized_messages:
response_message = ChatMessage(
response_message = Message(
role=Role.ASSISTANT,
contents=[
Content.from_text(text="Hello! I'm a custom echo agent. Send me a message and I'll echo it back.")
],
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
@@ -105,7 +103,7 @@ class EchoAgent(BaseAgent):
else:
echo_text = f"{self.echo_prefix}[Non-text message received]"
response_message = ChatMessage(role=Role.ASSISTANT, contents=[Content.from_text(text=echo_text)])
response_message = Message(role=Role.ASSISTANT, contents=[Content.from_text(text=echo_text)])
# Notify the thread of new messages if provided
if thread is not None:
@@ -115,7 +113,7 @@ class EchoAgent(BaseAgent):
async def _run_stream(
self,
messages: str | ChatMessage | list[str] | list[ChatMessage] | None = None,
messages: str | Message | list[str] | list[Message] | None = None,
*,
thread: AgentThread | None = None,
**kwargs: Any,
@@ -150,7 +148,7 @@ class EchoAgent(BaseAgent):
# Notify the thread of the complete response if provided
if thread is not None:
complete_response = ChatMessage(role=Role.ASSISTANT, contents=[Content.from_text(text=response_text)])
complete_response = Message(role=Role.ASSISTANT, contents=[Content.from_text(text=response_text)])
await self._notify_thread_of_new_messages(thread, normalized_messages, complete_response)
@@ -2,7 +2,7 @@
import asyncio
from agent_framework import ChatMessage, Content
from agent_framework import Content, Message
from agent_framework.ollama import OllamaChatClient
"""
@@ -32,7 +32,7 @@ async def test_image() -> None:
image_uri = create_sample_image()
message = ChatMessage(
message = Message(
role="user",
contents=[
Content.from_text(text="What's in this image?"),
@@ -15,14 +15,14 @@ This folder contains examples demonstrating different ways to create and use age
| [`openai_assistants_with_function_tools.py`](openai_assistants_with_function_tools.py) | Function tools with `OpenAIAssistantProvider` at both agent-level and query-level. |
| [`openai_assistants_with_response_format.py`](openai_assistants_with_response_format.py) | Structured outputs with `OpenAIAssistantProvider` using Pydantic models. |
| [`openai_assistants_with_thread.py`](openai_assistants_with_thread.py) | Thread management with `OpenAIAssistantProvider` for conversation context persistence. |
| [`openai_chat_client_basic.py`](openai_chat_client_basic.py) | The simplest way to create an agent using `ChatAgent` with `OpenAIChatClient`. Shows both streaming and non-streaming responses for chat-based interactions with OpenAI models. |
| [`openai_chat_client_basic.py`](openai_chat_client_basic.py) | The simplest way to create an agent using `Agent` with `OpenAIChatClient`. Shows both streaming and non-streaming responses for chat-based interactions with OpenAI models. |
| [`openai_chat_client_with_explicit_settings.py`](openai_chat_client_with_explicit_settings.py) | Shows how to initialize an agent with a specific chat client, configuring settings explicitly including API key and model ID. |
| [`openai_chat_client_with_function_tools.py`](openai_chat_client_with_function_tools.py) | Demonstrates how to use function tools with agents. Shows both agent-level tools (defined when creating the agent) and query-level tools (provided with specific queries). |
| [`openai_chat_client_with_local_mcp.py`](openai_chat_client_with_local_mcp.py) | Shows how to integrate OpenAI agents with local Model Context Protocol (MCP) servers for enhanced functionality and tool integration. |
| [`openai_chat_client_with_thread.py`](openai_chat_client_with_thread.py) | Demonstrates thread management with OpenAI agents, including automatic thread creation for stateless conversations and explicit thread management for maintaining conversation context across multiple interactions. |
| [`openai_chat_client_with_web_search.py`](openai_chat_client_with_web_search.py) | Shows how to use web search capabilities with OpenAI agents to retrieve and use information from the internet in responses. |
| [`openai_chat_client_with_runtime_json_schema.py`](openai_chat_client_with_runtime_json_schema.py) | Shows how to supply a runtime JSON Schema via `additional_chat_options` for structured output without defining a Pydantic model. |
| [`openai_responses_client_basic.py`](openai_responses_client_basic.py) | The simplest way to create an agent using `ChatAgent` with `OpenAIResponsesClient`. Shows both streaming and non-streaming responses for structured response generation with OpenAI models. |
| [`openai_responses_client_basic.py`](openai_responses_client_basic.py) | The simplest way to create an agent using `Agent` with `OpenAIResponsesClient`. Shows both streaming and non-streaming responses for structured response generation with OpenAI models. |
| [`openai_responses_client_image_analysis.py`](openai_responses_client_image_analysis.py) | Demonstrates how to use vision capabilities with agents to analyze images. |
| [`openai_responses_client_image_generation.py`](openai_responses_client_image_generation.py) | Demonstrates how to use image generation capabilities with OpenAI agents to create images based on text descriptions. Requires PIL (Pillow) for image display. |
| [`openai_responses_client_reasoning.py`](openai_responses_client_reasoning.py) | Demonstrates how to use reasoning capabilities with OpenAI agents, showing how the agent can provide detailed reasoning for its responses. |
@@ -5,7 +5,7 @@ from datetime import datetime, timezone
from random import randint
from typing import Annotated
from agent_framework import ChatAgent, tool
from agent_framework import Agent, tool
from agent_framework.openai import OpenAIChatClient
from pydantic import Field
@@ -40,8 +40,8 @@ async def tools_on_agent_level() -> None:
# Tools are provided when creating the agent
# The agent can use these tools for any query during its lifetime
agent = ChatAgent(
chat_client=OpenAIChatClient(),
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
)
@@ -70,8 +70,8 @@ async def tools_on_run_level() -> None:
print("=== Tools Passed to Run Method ===")
# Agent created without tools
agent = ChatAgent(
chat_client=OpenAIChatClient(),
agent = Agent(
client=OpenAIChatClient(),
instructions="You are a helpful assistant.",
# No tools defined here
)
@@ -100,8 +100,8 @@ async def mixed_tools_example() -> None:
print("=== Mixed Tools Example (Agent + Run Method) ===")
# Agent created with some base tools
agent = ChatAgent(
chat_client=OpenAIChatClient(),
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
)
@@ -2,7 +2,7 @@
import asyncio
from agent_framework import ChatAgent, MCPStreamableHTTPTool
from agent_framework import Agent, MCPStreamableHTTPTool
from agent_framework.openai import OpenAIChatClient
"""
@@ -29,8 +29,8 @@ async def mcp_tools_on_run_level() -> None:
name="Microsoft Learn MCP",
url="https://learn.microsoft.com/api/mcp",
) as mcp_server,
ChatAgent(
chat_client=OpenAIChatClient(),
Agent(
client=OpenAIChatClient(),
name="DocsAgent",
instructions="You are a helpful assistant that can help with microsoft documentation questions.",
) as agent,
@@ -4,7 +4,7 @@ import asyncio
from random import randint
from typing import Annotated
from agent_framework import AgentThread, ChatAgent, ChatMessageStore, tool
from agent_framework import Agent, AgentThread, ChatMessageStore, tool
from agent_framework.openai import OpenAIChatClient
from pydantic import Field
@@ -30,8 +30,8 @@ async def example_with_automatic_thread_creation() -> None:
"""Example showing automatic thread creation (service-managed thread)."""
print("=== Automatic Thread Creation Example ===")
agent = ChatAgent(
chat_client=OpenAIChatClient(),
agent = Agent(
client=OpenAIChatClient(),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
@@ -55,8 +55,8 @@ async def example_with_thread_persistence() -> None:
print("=== Thread Persistence Example ===")
print("Using the same thread across multiple conversations to maintain context.\n")
agent = ChatAgent(
chat_client=OpenAIChatClient(),
agent = Agent(
client=OpenAIChatClient(),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
@@ -88,8 +88,8 @@ async def example_with_existing_thread_messages() -> None:
"""Example showing how to work with existing thread messages for OpenAI."""
print("=== Existing Thread Messages Example ===")
agent = ChatAgent(
chat_client=OpenAIChatClient(),
agent = Agent(
client=OpenAIChatClient(),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
@@ -110,8 +110,8 @@ async def example_with_existing_thread_messages() -> None:
print("\n--- Continuing with the same thread in a new agent instance ---")
# Create a new agent instance but use the existing thread with its message history
new_agent = ChatAgent(
chat_client=OpenAIChatClient(),
new_agent = Agent(
client=OpenAIChatClient(),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
@@ -2,7 +2,7 @@
import asyncio
from agent_framework import ChatAgent, HostedWebSearchTool
from agent_framework import Agent, HostedWebSearchTool
from agent_framework.openai import OpenAIChatClient
"""
@@ -22,8 +22,8 @@ async def main() -> None:
}
}
agent = ChatAgent(
chat_client=OpenAIChatClient(model_id="gpt-4o-search-preview"),
agent = Agent(
client=OpenAIChatClient(model_id="gpt-4o-search-preview"),
instructions="You are a helpful assistant that can search the web for current information.",
tools=[HostedWebSearchTool(additional_properties=additional_properties)],
)
@@ -6,11 +6,12 @@ from random import randint
from typing import Annotated
from agent_framework import (
ChatAgent,
Agent,
ChatContext,
ChatMessage,
ChatResponse,
Message,
MiddlewareTermination,
Role,
chat_middleware,
tool,
)
@@ -46,8 +47,8 @@ async def security_and_override_middleware(
# Override the response instead of calling AI
context.result = ChatResponse(
messages=[
ChatMessage(
role="assistant",
Message(
role=Role.ASSISTANT,
text="I cannot process requests containing sensitive information. "
"Please rephrase your question without including passwords, secrets, or other "
"sensitive data.",
@@ -55,8 +56,8 @@ async def security_and_override_middleware(
]
)
# Set terminate flag to stop execution
raise MiddlewareTermination
# Terminate middleware execution with the blocked response
raise MiddlewareTermination(result=context.result)
# Continue to next middleware or AI execution
await call_next(context)
@@ -79,8 +80,8 @@ async def non_streaming_example() -> None:
"""Example of non-streaming response (get the complete result at once)."""
print("=== Non-streaming Response Example ===")
agent = ChatAgent(
chat_client=OpenAIResponsesClient(),
agent = Agent(
client=OpenAIResponsesClient(),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
@@ -95,8 +96,8 @@ async def streaming_example() -> None:
"""Example of streaming response (get results as they are generated)."""
print("=== Streaming Response Example ===")
agent = ChatAgent(
chat_client=OpenAIResponsesClient(
agent = Agent(
client=OpenAIResponsesClient(
middleware=[security_and_override_middleware],
),
instructions="You are a helpful weather agent.",
@@ -2,7 +2,7 @@
import asyncio
from agent_framework import ChatMessage, Content
from agent_framework import Content, Message
from agent_framework.openai import OpenAIResponsesClient
"""
@@ -23,7 +23,7 @@ async def main():
)
# 2. Create a simple message with both text and image content
user_message = ChatMessage(
user_message = Message(
role="user",
contents=[
Content.from_text(text="What do you see in this image?"),
@@ -3,7 +3,7 @@
import asyncio
from agent_framework import (
ChatAgent,
Agent,
HostedCodeInterpreterTool,
)
from agent_framework.openai import OpenAIResponsesClient
@@ -20,8 +20,8 @@ async def main() -> None:
"""Example showing how to use the HostedCodeInterpreterTool with OpenAI Responses."""
print("=== OpenAI Responses Agent with Code Interpreter Example ===")
agent = ChatAgent(
chat_client=OpenAIResponsesClient(),
agent = Agent(
client=OpenAIResponsesClient(),
instructions="You are a helpful assistant that can write and execute Python code to solve problems.",
tools=HostedCodeInterpreterTool(),
)
@@ -4,7 +4,7 @@ import asyncio
import os
import tempfile
from agent_framework import ChatAgent, HostedCodeInterpreterTool
from agent_framework import Agent, HostedCodeInterpreterTool
from agent_framework.openai import OpenAIResponsesClient
from openai import AsyncOpenAI
@@ -66,8 +66,8 @@ async def main() -> None:
temp_file_path, file_id = await create_sample_file_and_upload(openai_client)
# Create agent using OpenAI Responses client
agent = ChatAgent(
chat_client=OpenAIResponsesClient(),
agent = Agent(
client=OpenAIResponsesClient(),
instructions="You are a helpful assistant that can analyze data files using Python code.",
tools=HostedCodeInterpreterTool(inputs=[{"file_id": file_id}]),
)
@@ -2,7 +2,7 @@
import asyncio
from agent_framework import ChatAgent, Content, HostedFileSearchTool
from agent_framework import Agent, Content, HostedFileSearchTool
from agent_framework.openai import OpenAIResponsesClient
"""
@@ -47,8 +47,8 @@ async def main() -> None:
print(f"User: {message}")
file_id, vector_store = await create_vector_store(client)
agent = ChatAgent(
chat_client=client,
agent = Agent(
client=client,
instructions="You are a helpful assistant that can search through files to find information.",
tools=[HostedFileSearchTool(inputs=vector_store)],
)
@@ -5,7 +5,7 @@ from datetime import datetime, timezone
from random import randint
from typing import Annotated
from agent_framework import ChatAgent, tool
from agent_framework import Agent, tool
from agent_framework.openai import OpenAIResponsesClient
from pydantic import Field
@@ -40,8 +40,8 @@ async def tools_on_agent_level() -> None:
# Tools are provided when creating the agent
# The agent can use these tools for any query during its lifetime
agent = ChatAgent(
chat_client=OpenAIResponsesClient(),
agent = Agent(
client=OpenAIResponsesClient(),
instructions="You are a helpful assistant that can provide weather and time information.",
tools=[get_weather, get_time], # Tools defined at agent creation
)
@@ -70,8 +70,8 @@ async def tools_on_run_level() -> None:
print("=== Tools Passed to Run Method ===")
# Agent created without tools
agent = ChatAgent(
chat_client=OpenAIResponsesClient(),
agent = Agent(
client=OpenAIResponsesClient(),
instructions="You are a helpful assistant.",
# No tools defined here
)
@@ -100,8 +100,8 @@ async def mixed_tools_example() -> None:
print("=== Mixed Tools Example (Agent + Run Method) ===")
# Agent created with some base tools
agent = ChatAgent(
chat_client=OpenAIResponsesClient(),
agent = Agent(
client=OpenAIResponsesClient(),
instructions="You are a comprehensive assistant that can help with various information requests.",
tools=[get_weather], # Base tool available for all queries
)
@@ -3,7 +3,7 @@
import asyncio
from typing import TYPE_CHECKING, Any
from agent_framework import ChatAgent, HostedMCPTool
from agent_framework import Agent, HostedMCPTool
from agent_framework.openai import OpenAIResponsesClient
"""
@@ -19,7 +19,7 @@ if TYPE_CHECKING:
async def handle_approvals_without_thread(query: str, agent: "SupportsAgentRun"):
"""When we don't have a thread, we need to ensure we return with the input, approval request and approval."""
from agent_framework import ChatMessage
from agent_framework import Message
result = await agent.run(query)
while len(result.user_input_requests) > 0:
@@ -29,10 +29,10 @@ async def handle_approvals_without_thread(query: str, agent: "SupportsAgentRun")
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(ChatMessage(role="assistant", contents=[user_input_needed]))
new_inputs.append(Message(role="assistant", contents=[user_input_needed]))
user_approval = input("Approve function call? (y/n): ")
new_inputs.append(
ChatMessage(role="user", contents=[user_input_needed.to_function_approval_response(user_approval.lower() == "y")])
Message(role="user", contents=[user_input_needed.to_function_approval_response(user_approval.lower() == "y")])
)
result = await agent.run(new_inputs)
@@ -41,7 +41,7 @@ async def handle_approvals_without_thread(query: str, agent: "SupportsAgentRun")
async def handle_approvals_with_thread(query: str, agent: "SupportsAgentRun", thread: "AgentThread"):
"""Here we let the thread deal with the previous responses, and we just rerun with the approval."""
from agent_framework import ChatMessage
from agent_framework import Message
result = await agent.run(query, thread=thread, store=True)
while len(result.user_input_requests) > 0:
@@ -53,7 +53,7 @@ async def handle_approvals_with_thread(query: str, agent: "SupportsAgentRun", th
)
user_approval = input("Approve function call? (y/n): ")
new_input.append(
ChatMessage(
Message(
role="user",
contents=[user_input_needed.to_function_approval_response(user_approval.lower() == "y")],
)
@@ -64,13 +64,13 @@ async def handle_approvals_with_thread(query: str, agent: "SupportsAgentRun", th
async def handle_approvals_with_thread_streaming(query: str, agent: "SupportsAgentRun", thread: "AgentThread"):
"""Here we let the thread deal with the previous responses, and we just rerun with the approval."""
from agent_framework import ChatMessage
from agent_framework import Message
new_input: list[ChatMessage] = []
new_input: list[Message] = []
new_input_added = True
while new_input_added:
new_input_added = False
new_input.append(ChatMessage(role="user", text=query))
new_input.append(Message(role="user", text=query))
async for update in agent.run(new_input, thread=thread, stream=True, options={"store": True}):
if update.user_input_requests:
for user_input_needed in update.user_input_requests:
@@ -80,7 +80,7 @@ async def handle_approvals_with_thread_streaming(query: str, agent: "SupportsAge
)
user_approval = input("Approve function call? (y/n): ")
new_input.append(
ChatMessage(
Message(
role="user", contents=[user_input_needed.to_function_approval_response(user_approval.lower() == "y")]
)
)
@@ -95,8 +95,8 @@ async def run_hosted_mcp_without_thread_and_specific_approval() -> None:
# Tools are provided when creating the agent
# The agent can use these tools for any query during its lifetime
async with ChatAgent(
chat_client=OpenAIResponsesClient(),
async with Agent(
client=OpenAIResponsesClient(),
name="DocsAgent",
instructions="You are a helpful assistant that can help with microsoft documentation questions.",
tools=HostedMCPTool(
@@ -126,8 +126,8 @@ async def run_hosted_mcp_without_approval() -> None:
# Tools are provided when creating the agent
# The agent can use these tools for any query during its lifetime
async with ChatAgent(
chat_client=OpenAIResponsesClient(),
async with Agent(
client=OpenAIResponsesClient(),
name="DocsAgent",
instructions="You are a helpful assistant that can help with microsoft documentation questions.",
tools=HostedMCPTool(
@@ -158,8 +158,8 @@ async def run_hosted_mcp_with_thread() -> None:
# Tools are provided when creating the agent
# The agent can use these tools for any query during its lifetime
async with ChatAgent(
chat_client=OpenAIResponsesClient(),
async with Agent(
client=OpenAIResponsesClient(),
name="DocsAgent",
instructions="You are a helpful assistant that can help with microsoft documentation questions.",
tools=HostedMCPTool(
@@ -189,8 +189,8 @@ async def run_hosted_mcp_with_thread_streaming() -> None:
# Tools are provided when creating the agent
# The agent can use these tools for any query during its lifetime
async with ChatAgent(
chat_client=OpenAIResponsesClient(),
async with Agent(
client=OpenAIResponsesClient(),
name="DocsAgent",
instructions="You are a helpful assistant that can help with microsoft documentation questions.",
tools=HostedMCPTool(
@@ -2,7 +2,7 @@
import asyncio
from agent_framework import ChatAgent, MCPStreamableHTTPTool
from agent_framework import Agent, MCPStreamableHTTPTool
from agent_framework.openai import OpenAIResponsesClient
"""
@@ -22,8 +22,8 @@ async def streaming_with_mcp(show_raw_stream: bool = False) -> None:
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 ChatAgent(
chat_client=OpenAIResponsesClient(),
async with Agent(
client=OpenAIResponsesClient(),
name="DocsAgent",
instructions="You are a helpful assistant that can help with microsoft documentation questions.",
tools=MCPStreamableHTTPTool( # Tools defined at agent creation
@@ -60,8 +60,8 @@ async def run_with_mcp() -> None:
# Tools are provided when creating the agent
# The agent can use these tools for any query during its lifetime
async with ChatAgent(
chat_client=OpenAIResponsesClient(),
async with Agent(
client=OpenAIResponsesClient(),
name="DocsAgent",
instructions="You are a helpful assistant that can help with microsoft documentation questions.",
tools=MCPStreamableHTTPTool( # Tools defined at agent creation
@@ -4,7 +4,7 @@ import asyncio
from random import randint
from typing import Annotated
from agent_framework import AgentThread, ChatAgent, tool
from agent_framework import Agent, AgentThread, tool
from agent_framework.openai import OpenAIResponsesClient
from pydantic import Field
@@ -30,8 +30,8 @@ async def example_with_automatic_thread_creation() -> None:
"""Example showing automatic thread creation."""
print("=== Automatic Thread Creation Example ===")
agent = ChatAgent(
chat_client=OpenAIResponsesClient(),
agent = Agent(
client=OpenAIResponsesClient(),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
@@ -57,8 +57,8 @@ async def example_with_thread_persistence_in_memory() -> None:
"""
print("=== Thread Persistence Example (In-Memory) ===")
agent = ChatAgent(
chat_client=OpenAIResponsesClient(),
agent = Agent(
client=OpenAIResponsesClient(),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
@@ -96,8 +96,8 @@ async def example_with_existing_thread_id() -> None:
# First, create a conversation and capture the thread ID
existing_thread_id = None
agent = ChatAgent(
chat_client=OpenAIResponsesClient(),
agent = Agent(
client=OpenAIResponsesClient(),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
@@ -117,8 +117,8 @@ async def example_with_existing_thread_id() -> None:
if existing_thread_id:
print("\n--- Continuing with the same thread ID in a new agent instance ---")
agent = ChatAgent(
chat_client=OpenAIResponsesClient(),
agent = Agent(
client=OpenAIResponsesClient(),
instructions="You are a helpful weather agent.",
tools=get_weather,
)
@@ -2,7 +2,7 @@
import asyncio
from agent_framework import ChatAgent, HostedWebSearchTool
from agent_framework import Agent, HostedWebSearchTool
from agent_framework.openai import OpenAIResponsesClient
"""
@@ -22,8 +22,8 @@ async def main() -> None:
}
}
agent = ChatAgent(
chat_client=OpenAIResponsesClient(),
agent = Agent(
client=OpenAIResponsesClient(),
instructions="You are a helpful assistant that can search the web for current information.",
tools=[HostedWebSearchTool(additional_properties=additional_properties)],
)
@@ -76,8 +76,8 @@ Expected response:
{
"status": "healthy",
"agents": [
{"name": "WeatherAgent", "type": "ChatAgent"},
{"name": "MathAgent", "type": "ChatAgent"}
{"name": "WeatherAgent", "type": "Agent"},
{"name": "MathAgent", "type": "Agent"}
],
"agent_count": 2
}
@@ -56,15 +56,15 @@ def calculate_tip(bill_amount: float, tip_percentage: float = 15.0) -> dict[str,
# 1. Create multiple agents, each with its own instruction set and tools.
chat_client = AzureOpenAIChatClient(credential=AzureCliCredential())
client = AzureOpenAIChatClient(credential=AzureCliCredential())
weather_agent = chat_client.as_agent(
weather_agent = client.as_agent(
name="WeatherAgent",
instructions="You are a helpful weather assistant. Provide current weather information.",
tools=[get_weather],
)
math_agent = chat_client.as_agent(
math_agent = client.as_agent(
name="MathAgent",
instructions="You are a helpful math assistant. Help users with calculations like tip calculations.",
tools=[calculate_tip],
@@ -30,14 +30,14 @@ CHEMIST_AGENT_NAME = "ChemistAgent"
# 2. Instantiate both agents that the orchestration will run concurrently.
def _create_agents() -> list[Any]:
chat_client = AzureOpenAIChatClient(credential=AzureCliCredential())
client = AzureOpenAIChatClient(credential=AzureCliCredential())
physicist = chat_client.as_agent(
physicist = client.as_agent(
name=PHYSICIST_AGENT_NAME,
instructions="You are an expert in physics. You answer questions from a physics perspective.",
)
chemist = chat_client.as_agent(
chemist = client.as_agent(
name=CHEMIST_AGENT_NAME,
instructions="You are an expert in chemistry. You answer questions from a chemistry perspective.",
)
@@ -45,14 +45,14 @@ class EmailPayload(BaseModel):
# 2. Instantiate both agents so they can be registered with AgentFunctionApp.
def _create_agents() -> list[Any]:
chat_client = AzureOpenAIChatClient(credential=AzureCliCredential())
client = AzureOpenAIChatClient(credential=AzureCliCredential())
spam_agent = chat_client.as_agent(
spam_agent = client.as_agent(
name=SPAM_AGENT_NAME,
instructions="You are a spam detection assistant that identifies spam emails.",
)
email_agent = chat_client.as_agent(
email_agent = client.as_agent(
name=EMAIL_AGENT_NAME,
instructions="You are an email assistant that helps users draft responses to emails with professionalism.",
)
@@ -142,20 +142,20 @@ The sample shows how to enable MCP tool triggers with flexible agent configurati
from agent_framework.azure import AgentFunctionApp, AzureOpenAIChatClient
# Create Azure OpenAI Chat Client
chat_client = AzureOpenAIChatClient()
client = AzureOpenAIChatClient()
# Define agents with different roles
joker_agent = chat_client.as_agent(
joker_agent = client.as_agent(
name="Joker",
instructions="You are good at telling jokes.",
)
stock_agent = chat_client.as_agent(
stock_agent = client.as_agent(
name="StockAdvisor",
instructions="Check stock prices.",
)
plant_agent = chat_client.as_agent(
plant_agent = client.as_agent(
name="PlantAdvisor",
instructions="Recommend plants.",
description="Get plant recommendations.",
@@ -28,23 +28,23 @@ from agent_framework.azure import AgentFunctionApp, AzureOpenAIChatClient
# Create Azure OpenAI Chat Client
# This uses AzureCliCredential for authentication (requires 'az login')
chat_client = AzureOpenAIChatClient()
client = AzureOpenAIChatClient()
# Define three AI agents with different roles
# Agent 1: Joker - HTTP trigger only (default)
agent1 = chat_client.as_agent(
agent1 = client.as_agent(
name="Joker",
instructions="You are good at telling jokes.",
)
# Agent 2: StockAdvisor - MCP tool trigger only
agent2 = chat_client.as_agent(
agent2 = client.as_agent(
name="StockAdvisor",
instructions="Check stock prices.",
)
# Agent 3: PlantAdvisor - Both HTTP and MCP tool triggers
agent3 = chat_client.as_agent(
agent3 = client.as_agent(
name="PlantAdvisor",
instructions="Recommend plants.",
description="Get plant recommendations.",
@@ -14,7 +14,7 @@ This folder contains simple examples demonstrating direct usage of various chat
| [`openai_assistants_client.py`](openai_assistants_client.py) | Direct usage of OpenAI Assistants Client for basic chat interactions with OpenAI assistants. |
| [`openai_chat_client.py`](openai_chat_client.py) | Direct usage of OpenAI Chat Client for chat interactions with OpenAI models. |
| [`openai_responses_client.py`](openai_responses_client.py) | Direct usage of OpenAI Responses Client for structured response generation with OpenAI models. |
| [`custom_chat_client.py`](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 `ChatAgent` using the `as_agent()` method. |
| [`custom_chat_client.py`](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. |
## Environment Variables
@@ -21,10 +21,10 @@ async def main() -> None:
- OpenAI model ID: Use "model_id" parameter or "OPENAI_CHAT_MODEL_ID" environment variable
- OpenAI API key: Use "api_key" parameter or "OPENAI_API_KEY" environment variable
"""
chat_client = OpenAIChatClient()
client = OpenAIChatClient()
try:
task = asyncio.create_task(chat_client.get_response(messages=["Tell me a fantasy story."]))
task = asyncio.create_task(client.get_response(messages=["Tell me a fantasy story."]))
await asyncio.sleep(1)
task.cancel()
await task
@@ -8,12 +8,12 @@ from typing import Any, ClassVar, Generic
from agent_framework import (
BaseChatClient,
ChatMessage,
ChatMiddlewareLayer,
ChatResponse,
ChatResponseUpdate,
Content,
FunctionInvocationLayer,
Message,
ResponseStream,
Role,
)
@@ -61,7 +61,7 @@ class EchoingChatClient(BaseChatClient[OptionsCoT], Generic[OptionsCoT]):
def _inner_get_response(
self,
*,
messages: Sequence[ChatMessage],
messages: Sequence[Message],
stream: bool = False,
options: Mapping[str, Any],
**kwargs: Any,
@@ -82,7 +82,7 @@ class EchoingChatClient(BaseChatClient[OptionsCoT], Generic[OptionsCoT]):
else:
response_text = f"{self.prefix} [No text message found]"
response_message = ChatMessage(role=Role.ASSISTANT, contents=[Content.from_text(response_text)])
response_message = Message(role=Role.ASSISTANT, contents=[Content.from_text(response_text)])
response = ChatResponse(
messages=[response_message],
@@ -124,7 +124,7 @@ class EchoingChatClientWithLayers( # type: ignore[misc,type-var]
async def main() -> None:
"""Demonstrates how to implement and use a custom chat client with ChatAgent."""
"""Demonstrates how to implement and use a custom chat client with Agent."""
print("=== Custom Chat Client Example ===\n")
# Create the custom chat client
@@ -139,14 +139,14 @@ Different agents with isolated or shared memory configurations.
To create a custom context provider, implement the `ContextProvider` protocol:
```python
from agent_framework import ContextProvider, Context, ChatMessage
from agent_framework import ContextProvider, Context, Message
from collections.abc import MutableSequence, Sequence
from typing import Any
class MyContextProvider(ContextProvider):
async def invoking(
self,
messages: ChatMessage | MutableSequence[ChatMessage],
messages: Message | MutableSequence[Message],
**kwargs: Any
) -> Context:
"""Provide context before the agent processes the request."""
@@ -155,8 +155,8 @@ class MyContextProvider(ContextProvider):
async def invoked(
self,
request_messages: ChatMessage | Sequence[ChatMessage],
response_messages: ChatMessage | Sequence[ChatMessage] | None = None,
request_messages: Message | Sequence[Message],
response_messages: Message | Sequence[Message] | None = None,
invoke_exception: Exception | None = None,
**kwargs: Any,
) -> None:
@@ -17,7 +17,7 @@ from contextlib import AsyncExitStack
from types import TracebackType
from typing import TYPE_CHECKING, Any, cast
from agent_framework import ChatAgent, ChatMessage, Context, ContextProvider
from agent_framework import Agent, Context, ContextProvider, Message
from agent_framework.azure import AzureAIClient
from azure.identity.aio import AzureCliCredential
@@ -47,7 +47,7 @@ class AggregateContextProvider(ContextProvider):
Examples:
.. code-block:: python
from agent_framework import ChatAgent
from agent_framework import Agent
# Create multiple context providers
provider1 = CustomContextProvider1()
@@ -58,7 +58,7 @@ class AggregateContextProvider(ContextProvider):
aggregate = AggregateContextProvider([provider1, provider2, provider3])
# Pass the aggregate to the agent
agent = ChatAgent(chat_client=client, name="assistant", context_provider=aggregate)
agent = Agent(client=client, name="assistant", context_provider=aggregate)
# You can also add more providers later
provider4 = CustomContextProvider4()
@@ -90,10 +90,10 @@ class AggregateContextProvider(ContextProvider):
await asyncio.gather(*[x.thread_created(thread_id) for x in self.providers])
@override
async def invoking(self, messages: ChatMessage | MutableSequence[ChatMessage], **kwargs: Any) -> Context:
async def invoking(self, messages: Message | MutableSequence[Message], **kwargs: Any) -> Context:
contexts = await asyncio.gather(*[provider.invoking(messages, **kwargs) for provider in self.providers])
instructions: str = ""
return_messages: list[ChatMessage] = []
return_messages: list[Message] = []
tools: list["ToolProtocol"] = []
for ctx in contexts:
if ctx.instructions:
@@ -107,8 +107,8 @@ class AggregateContextProvider(ContextProvider):
@override
async def invoked(
self,
request_messages: ChatMessage | Sequence[ChatMessage],
response_messages: ChatMessage | Sequence[ChatMessage] | None = None,
request_messages: Message | Sequence[Message],
response_messages: Message | Sequence[Message] | None = None,
invoke_exception: Exception | None = None,
**kwargs: Any,
) -> None:
@@ -167,7 +167,7 @@ class TimeContextProvider(ContextProvider):
"""A simple context provider that adds time-related instructions."""
@override
async def invoking(self, messages: ChatMessage | MutableSequence[ChatMessage], **kwargs: Any) -> Context:
async def invoking(self, messages: Message | MutableSequence[Message], **kwargs: Any) -> Context:
from datetime import datetime
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
@@ -181,7 +181,7 @@ class PersonaContextProvider(ContextProvider):
self.persona = persona
@override
async def invoking(self, messages: ChatMessage | MutableSequence[ChatMessage], **kwargs: Any) -> Context:
async def invoking(self, messages: Message | MutableSequence[Message], **kwargs: Any) -> Context:
return Context(instructions=f"Your persona: {self.persona}. ")
@@ -192,7 +192,7 @@ class PreferencesContextProvider(ContextProvider):
self.preferences: dict[str, str] = {}
@override
async def invoking(self, messages: ChatMessage | MutableSequence[ChatMessage], **kwargs: Any) -> Context:
async def invoking(self, messages: Message | MutableSequence[Message], **kwargs: Any) -> Context:
if not self.preferences:
return Context()
prefs_str = ", ".join(f"{k}: {v}" for k, v in self.preferences.items())
@@ -201,14 +201,14 @@ class PreferencesContextProvider(ContextProvider):
@override
async def invoked(
self,
request_messages: ChatMessage | Sequence[ChatMessage],
response_messages: ChatMessage | Sequence[ChatMessage] | None = None,
request_messages: Message | Sequence[Message],
response_messages: Message | Sequence[Message] | None = None,
invoke_exception: Exception | None = None,
**kwargs: Any,
) -> None:
# Simple example: extract and store preferences from user messages
# In a real implementation, you might use structured extraction
msgs = [request_messages] if isinstance(request_messages, ChatMessage) else list(request_messages)
msgs = [request_messages] if isinstance(request_messages, Message) else list(request_messages)
for msg in msgs:
content = msg.text if hasattr(msg, "text") else ""
@@ -230,7 +230,7 @@ class PreferencesContextProvider(ContextProvider):
async def main():
"""Demonstrate using AggregateContextProvider to combine multiple providers."""
async with AzureCliCredential() as credential:
chat_client = AzureAIClient(credential=credential)
client = AzureAIClient(credential=credential)
# Create individual context providers
time_provider = TimeContextProvider()
@@ -245,8 +245,8 @@ async def main():
])
# Create the agent with the aggregate provider
async with ChatAgent(
chat_client=chat_client,
async with Agent(
client=client,
instructions="You are a helpful assistant.",
context_provider=aggregate_provider,
) as agent:
@@ -126,7 +126,7 @@ AZURE_OPENAI_RESOURCE_URL=https://myresource.openai.azure.com
### Semantic Mode
```python
from agent_framework import ChatAgent
from agent_framework import Agent
from agent_framework.azure import AzureAIAgentClient, AzureAISearchContextProvider
from azure.identity.aio import DefaultAzureCredential
@@ -141,8 +141,8 @@ search_provider = AzureAISearchContextProvider(
# Create agent with search context
async with AzureAIAgentClient(credential=DefaultAzureCredential()) as client:
async with ChatAgent(
chat_client=client,
async with Agent(
client=client,
model=model_deployment,
context_provider=search_provider,
) as agent:
@@ -166,8 +166,8 @@ search_provider = AzureAISearchContextProvider(
)
# Use with agent (same as semantic mode)
async with ChatAgent(
chat_client=client,
async with Agent(
client=client,
model=model_deployment,
context_provider=search_provider,
) as agent:
@@ -3,7 +3,7 @@
import asyncio
import os
from agent_framework import ChatAgent
from agent_framework import Agent
from agent_framework.azure import AzureAIAgentClient, AzureAISearchContextProvider
from azure.identity.aio import AzureCliCredential
from dotenv import load_dotenv
@@ -112,8 +112,8 @@ async def main() -> None:
model_deployment_name=model_deployment,
credential=AzureCliCredential(),
) as client,
ChatAgent(
chat_client=client,
Agent(
client=client,
name="SearchAgent",
instructions=(
"You are a helpful assistant with advanced reasoning capabilities. "
@@ -3,7 +3,7 @@
import asyncio
import os
from agent_framework import ChatAgent
from agent_framework import Agent
from agent_framework.azure import AzureAIAgentClient, AzureAISearchContextProvider
from azure.identity.aio import AzureCliCredential
from dotenv import load_dotenv
@@ -69,8 +69,8 @@ async def main() -> None:
model_deployment_name=model_deployment,
credential=AzureCliCredential(),
) as client,
ChatAgent(
chat_client=client,
Agent(
client=client,
name="SearchAgent",
instructions=(
"You are a helpful assistant. Use the provided context from the "
@@ -30,7 +30,7 @@ Run:
import asyncio
import os
from agent_framework import ChatMessage, tool
from agent_framework import Message, tool
from agent_framework.openai import OpenAIChatClient
from agent_framework_redis._provider import RedisProvider
from redisvl.extensions.cache.embeddings import EmbeddingsCache
@@ -128,9 +128,9 @@ async def main() -> None:
# Build sample chat messages to persist to Redis
messages = [
ChatMessage("user", ["runA CONVO: User Message"]),
ChatMessage("assistant", ["runA CONVO: Assistant Message"]),
ChatMessage("system", ["runA CONVO: System Message"]),
Message("user", ["runA CONVO: User Message"]),
Message("assistant", ["runA CONVO: Assistant Message"]),
Message("system", ["runA CONVO: System Message"]),
]
# Declare/start a conversation/thread and write messages under 'runA'.
@@ -142,7 +142,7 @@ async def main() -> None:
# Retrieve relevant memories for a hypothetical model call. The provider uses
# the current request messages as the retrieval query and returns context to
# be injected into the model's instructions.
ctx = await provider.invoking([ChatMessage("system", ["B: Assistant Message"])])
ctx = await provider.invoking([Message("system", ["B: Assistant Message"])])
# Inspect retrieved memories that would be injected into instructions
# (Debug-only output so you can verify retrieval works as expected.)
@@ -4,7 +4,7 @@ import asyncio
from collections.abc import MutableSequence, Sequence
from typing import Any
from agent_framework import ChatAgent, ChatClientProtocol, ChatMessage, Context, ContextProvider
from agent_framework import Agent, Context, ContextProvider, Message, SupportsChatGetResponse
from agent_framework.azure import AzureAIClient
from azure.identity.aio import AzureCliCredential
from pydantic import BaseModel
@@ -16,13 +16,13 @@ class UserInfo(BaseModel):
class UserInfoMemory(ContextProvider):
def __init__(self, chat_client: ChatClientProtocol, user_info: UserInfo | None = None, **kwargs: Any):
def __init__(self, client: SupportsChatGetResponse, user_info: UserInfo | None = None, **kwargs: Any):
"""Create the memory.
If you pass in kwargs, they will be attempted to be used to create a UserInfo object.
"""
self._chat_client = chat_client
self._chat_client = client
if user_info:
self.user_info = user_info
elif kwargs:
@@ -32,8 +32,8 @@ class UserInfoMemory(ContextProvider):
async def invoked(
self,
request_messages: ChatMessage | Sequence[ChatMessage],
response_messages: ChatMessage | Sequence[ChatMessage] | None = None,
request_messages: Message | Sequence[Message],
response_messages: Message | Sequence[Message] | None = None,
invoke_exception: Exception | None = None,
**kwargs: Any,
) -> None:
@@ -64,7 +64,7 @@ class UserInfoMemory(ContextProvider):
except Exception:
pass # Failed to extract, continue without updating
async def invoking(self, messages: ChatMessage | MutableSequence[ChatMessage], **kwargs: Any) -> Context:
async def invoking(self, messages: Message | MutableSequence[Message], **kwargs: Any) -> Context:
"""Provide user information context before each agent call."""
instructions: list[str] = []
@@ -92,14 +92,14 @@ class UserInfoMemory(ContextProvider):
async def main():
async with AzureCliCredential() as credential:
chat_client = AzureAIClient(credential=credential)
client = AzureAIClient(credential=credential)
# Create the memory provider
memory_provider = UserInfoMemory(chat_client)
memory_provider = UserInfoMemory(client)
# Create the agent with memory
async with ChatAgent(
chat_client=chat_client,
async with Agent(
client=client,
instructions="You are a friendly assistant. Always address the user by their name.",
context_provider=memory_provider,
) as agent:
@@ -175,7 +175,7 @@ agent = agent_factory.create_agent_from_yaml_path(Path("custom_provider.yaml"))
This allows you to extend the declarative framework with custom chat client implementations. The mapping requires:
- **package**: The Python package/module to import from
- **name**: The class name of your ChatClientProtocol implementation
- **name**: The class name of your SupportsChatGetResponse implementation
- **model_id_field**: The constructor parameter name that accepts the value of the `model.id` field from the YAML
You can reference your custom provider using either `Provider.ApiType` format or just `Provider` in your YAML configuration, as long as it matches the registered mapping.
@@ -26,7 +26,7 @@ async def main():
# create the AgentFactory with a chat client and bindings
agent_factory = AgentFactory(
chat_client=AzureOpenAIResponsesClient(credential=AzureCliCredential()),
client=AzureOpenAIResponsesClient(credential=AzureCliCredential()),
bindings={"get_weather": get_weather},
)
# create the agent from the yaml
@@ -44,7 +44,7 @@ Each agent/workflow follows a strict structure required by DevUI's discovery sys
```
agent_name/
├── __init__.py # Must export: agent = ChatAgent(...)
├── __init__.py # Must export: agent = Agent(...)
├── agent.py # Agent implementation
└── .env.example # Example environment variables
```
@@ -100,13 +100,13 @@ Example:
```python
# my_agent/__init__.py
from agent_framework import ChatAgent
from agent_framework import Agent
from agent_framework.openai import OpenAIChatClient
agent = ChatAgent(
agent = Agent(
name="MyAgent",
description="My custom agent",
chat_client=OpenAIChatClient(),
client=OpenAIChatClient(),
# ... your configuration
)
```
@@ -21,7 +21,7 @@ import logging
import os
from typing import Annotated
from agent_framework import ChatAgent, tool
from agent_framework import Agent, tool
from agent_framework.azure import AzureOpenAIResponsesClient
logger = logging.getLogger(__name__)
@@ -68,7 +68,7 @@ def extract_key_points(
# Agent using Azure OpenAI Responses API (supports PDF uploads!)
agent = ChatAgent(
agent = Agent(
name="AzureResponsesAgent",
description="An agent that can analyze PDFs, images, and other documents using Azure OpenAI Responses API",
instructions="""
@@ -85,7 +85,7 @@ agent = ChatAgent(
For PDFs, you can read and understand the text, tables, and structure.
For images, you can describe what you see and extract any text.
""",
chat_client=AzureOpenAIResponsesClient(
client=AzureOpenAIResponsesClient(
deployment_name=_deployment_name,
endpoint=_endpoint,
api_version="2025-03-01-preview", # Required for Responses API
@@ -8,7 +8,7 @@ Make sure to run 'az login' before starting devui.
import os
from typing import Annotated
from agent_framework import ChatAgent, tool
from agent_framework import Agent, tool
from agent_framework.azure import AzureAIAgentClient
from azure.identity.aio import AzureCliCredential
from pydantic import Field
@@ -43,9 +43,9 @@ def get_forecast(
# Agent instance following Agent Framework conventions
agent = ChatAgent(
agent = Agent(
name="FoundryWeatherAgent",
chat_client=AzureAIAgentClient(
client=AzureAIAgentClient(
project_endpoint=os.environ.get("AZURE_AI_PROJECT_ENDPOINT"),
model_deployment_name=os.environ.get("FOUNDRY_MODEL_DEPLOYMENT_NAME"),
credential=AzureCliCredential(),
@@ -10,7 +10,7 @@ import logging
import os
from typing import Annotated
from agent_framework import ChatAgent, Executor, WorkflowBuilder, WorkflowContext, handler, tool
from agent_framework import Agent, Executor, WorkflowBuilder, WorkflowContext, handler, tool
from agent_framework.azure import AzureOpenAIChatClient
from agent_framework.devui import serve
from typing_extensions import Never
@@ -68,7 +68,7 @@ def main():
logger = logging.getLogger(__name__)
# Create Azure OpenAI chat client
chat_client = AzureOpenAIChatClient(
client = AzureOpenAIChatClient(
api_key=os.environ.get("AZURE_OPENAI_API_KEY"),
azure_endpoint=os.environ.get("AZURE_OPENAI_ENDPOINT"),
api_version=os.environ.get("AZURE_OPENAI_API_VERSION", "2024-10-21"),
@@ -76,22 +76,22 @@ def main():
)
# Create agents
weather_agent = ChatAgent(
weather_agent = Agent(
name="weather-assistant",
description="Provides weather information and time",
instructions=(
"You are a helpful weather and time assistant. Use the available tools to "
"provide accurate weather information and current time for any location."
),
chat_client=chat_client,
client=client,
tools=[get_weather, get_time],
)
simple_agent = ChatAgent(
simple_agent = Agent(
name="general-assistant",
description="A simple conversational agent",
instructions="You are a helpful assistant.",
chat_client=chat_client,
client=client,
)
# Create a basic workflow: Input -> UpperCase -> AddExclamation -> Output
@@ -7,15 +7,16 @@ from collections.abc import AsyncIterable, Awaitable, Callable
from typing import Annotated
from agent_framework import (
ChatAgent,
Agent,
ChatContext,
ChatMessage,
ChatResponse,
ChatResponseUpdate,
Content,
FunctionInvocationContext,
Message,
MiddlewareTermination,
ResponseStream,
Role,
chat_middleware,
function_middleware,
tool,
@@ -44,7 +45,7 @@ async def security_filter_middleware(
# Check only the last message (most recent user input)
last_message = context.messages[-1] if context.messages else None
if last_message and last_message.role == "user" and last_message.text:
if last_message and last_message.role == Role.USER and last_message.text:
message_lower = last_message.text.lower()
for term in blocked_terms:
if term in message_lower:
@@ -55,26 +56,29 @@ async def security_filter_middleware(
)
if context.stream:
# Streaming mode: return async generator
# Streaming mode: wrap in ResponseStream
async def blocked_stream(msg: str = error_message) -> AsyncIterable[ChatResponseUpdate]:
yield ChatResponseUpdate(
contents=[Content.from_text(text=msg)],
role="assistant",
role=Role.ASSISTANT,
)
context.result = ResponseStream(blocked_stream(), finalizer=ChatResponse.from_updates)
response = ChatResponse(
messages=[Message(role=Role.ASSISTANT, text=error_message)]
)
context.result = ResponseStream(blocked_stream(), finalizer=lambda _, r=response: r)
else:
# Non-streaming mode: return complete response
context.result = ChatResponse(
messages=[
ChatMessage(
role="assistant",
Message(
role=Role.ASSISTANT,
text=error_message,
)
]
)
raise MiddlewareTermination
raise MiddlewareTermination(result=context.result)
await call_next(context)
@@ -92,7 +96,7 @@ async def atlantis_location_filter_middleware(
"Blocked! Hold up right there!! Tell the user that "
"'Atlantis is a special place, we must never ask about the weather there!!'"
)
raise MiddlewareTermination
raise MiddlewareTermination(result=context.result)
await call_next(context)
@@ -136,7 +140,7 @@ def send_email(
# Agent instance following Agent Framework conventions
agent = ChatAgent(
agent = Agent(
name="AzureWeatherAgent",
description="A helpful agent that provides weather information and forecasts",
instructions="""
@@ -144,7 +148,7 @@ agent = ChatAgent(
and forecasts for any location. Always be helpful and provide detailed
weather information when asked.
""",
chat_client=AzureOpenAIChatClient(
client=AzureOpenAIChatClient(
api_key=os.environ.get("AZURE_OPENAI_API_KEY", ""),
),
tools=[get_weather, get_forecast, send_email],
@@ -59,10 +59,10 @@ def is_approved(message: Any) -> bool:
# Create Azure OpenAI chat client
chat_client = AzureOpenAIChatClient(api_key=os.environ.get("AZURE_OPENAI_API_KEY", ""))
client = AzureOpenAIChatClient(api_key=os.environ.get("AZURE_OPENAI_API_KEY", ""))
# Create Writer agent - generates content
writer = chat_client.as_agent(
writer = client.as_agent(
name="Writer",
instructions=(
"You are an excellent content writer. "
@@ -72,7 +72,7 @@ writer = chat_client.as_agent(
)
# Create Reviewer agent - evaluates and provides structured feedback
reviewer = chat_client.as_agent(
reviewer = client.as_agent(
name="Reviewer",
instructions=(
"You are an expert content reviewer. "
@@ -90,7 +90,7 @@ reviewer = chat_client.as_agent(
)
# Create Editor agent - improves content based on feedback
editor = chat_client.as_agent(
editor = client.as_agent(
name="Editor",
instructions=(
"You are a skilled editor. "
@@ -101,7 +101,7 @@ editor = chat_client.as_agent(
)
# Create Publisher agent - formats content for publication
publisher = chat_client.as_agent(
publisher = client.as_agent(
name="Publisher",
instructions=(
"You are a publishing agent. "
@@ -111,7 +111,7 @@ publisher = chat_client.as_agent(
)
# Create Summarizer agent - creates final publication report
summarizer = chat_client.as_agent(
summarizer = client.as_agent(
name="Summarizer",
instructions=(
"You are a summarizer agent. "
@@ -15,7 +15,7 @@ import asyncio
import logging
import os
from agent_framework import ChatAgent
from agent_framework import Agent
from agent_framework.azure import AzureOpenAIChatClient, DurableAIAgentWorker
from azure.identity import AzureCliCredential, DefaultAzureCredential
from durabletask.azuremanaged.worker import DurableTaskSchedulerWorker
@@ -25,11 +25,11 @@ logging.basicConfig(level=logging.WARNING)
logger = logging.getLogger(__name__)
def create_joker_agent() -> ChatAgent:
def create_joker_agent() -> Agent:
"""Create the Joker agent using Azure OpenAI.
Returns:
ChatAgent: The configured Joker agent
Agent: The configured Joker agent
"""
return AzureOpenAIChatClient(credential=AzureCliCredential()).as_agent(
name="Joker",
@@ -65,7 +65,7 @@ def create_weather_agent():
"""Create the Weather agent using Azure OpenAI.
Returns:
ChatAgent: The configured Weather agent with weather tool
Agent: The configured Weather agent with weather tool
"""
return AzureOpenAIChatClient(credential=AzureCliCredential()).as_agent(
name=WEATHER_AGENT_NAME,
@@ -78,7 +78,7 @@ def create_math_agent():
"""Create the Math agent using Azure OpenAI.
Returns:
ChatAgent: The configured Math agent with calculation tools
Agent: The configured Math agent with calculation tools
"""
return AzureOpenAIChatClient(credential=AzureCliCredential()).as_agent(
name=MATH_AGENT_NAME,
@@ -18,7 +18,7 @@ import os
from datetime import timedelta
import redis.asyncio as aioredis
from agent_framework import AgentResponseUpdate, ChatAgent
from agent_framework import Agent, AgentResponseUpdate
from agent_framework.azure import (
AgentCallbackContext,
AgentResponseCallbackProtocol,
@@ -143,11 +143,11 @@ class RedisStreamCallback(AgentResponseCallbackProtocol):
logger.error(f"Error writing end-of-stream marker: {ex}", exc_info=True)
def create_travel_agent() -> "ChatAgent":
def create_travel_agent() -> "Agent":
"""Create the TravelPlanner agent using Azure OpenAI.
Returns:
ChatAgent: The configured TravelPlanner agent with travel planning tools.
Agent: The configured TravelPlanner agent with travel planning tools.
"""
return AzureOpenAIChatClient(credential=AzureCliCredential()).as_agent(
name="TravelPlanner",
@@ -17,7 +17,7 @@ import logging
import os
from collections.abc import Generator
from agent_framework import AgentResponse, ChatAgent
from agent_framework import Agent, AgentResponse
from agent_framework.azure import AzureOpenAIChatClient, DurableAIAgentOrchestrationContext, DurableAIAgentWorker
from azure.identity import AzureCliCredential, DefaultAzureCredential
from durabletask.azuremanaged.worker import DurableTaskSchedulerWorker
@@ -31,14 +31,14 @@ logger = logging.getLogger(__name__)
WRITER_AGENT_NAME = "WriterAgent"
def create_writer_agent() -> "ChatAgent":
def create_writer_agent() -> "Agent":
"""Create the Writer agent using Azure OpenAI.
This agent refines short pieces of text, enhancing initial sentences
and polishing improved versions further.
Returns:
ChatAgent: The configured Writer agent
Agent: The configured Writer agent
"""
instructions = (
"You refine short pieces of text. When given an initial sentence you enhance it;\n"
@@ -18,7 +18,7 @@ import os
from collections.abc import Generator
from typing import Any
from agent_framework import AgentResponse, ChatAgent
from agent_framework import Agent, AgentResponse
from agent_framework.azure import AzureOpenAIChatClient, DurableAIAgentOrchestrationContext, DurableAIAgentWorker
from azure.identity import AzureCliCredential, DefaultAzureCredential
from durabletask.azuremanaged.worker import DurableTaskSchedulerWorker
@@ -33,11 +33,11 @@ PHYSICIST_AGENT_NAME = "PhysicistAgent"
CHEMIST_AGENT_NAME = "ChemistAgent"
def create_physicist_agent() -> "ChatAgent":
def create_physicist_agent() -> "Agent":
"""Create the Physicist agent using Azure OpenAI.
Returns:
ChatAgent: The configured Physicist agent
Agent: The configured Physicist agent
"""
return AzureOpenAIChatClient(credential=AzureCliCredential()).as_agent(
name=PHYSICIST_AGENT_NAME,
@@ -45,11 +45,11 @@ def create_physicist_agent() -> "ChatAgent":
)
def create_chemist_agent() -> "ChatAgent":
def create_chemist_agent() -> "Agent":
"""Create the Chemist agent using Azure OpenAI.
Returns:
ChatAgent: The configured Chemist agent
Agent: The configured Chemist agent
"""
return AzureOpenAIChatClient(credential=AzureCliCredential()).as_agent(
name=CHEMIST_AGENT_NAME,
@@ -18,7 +18,7 @@ import os
from collections.abc import Generator
from typing import Any, cast
from agent_framework import AgentResponse, ChatAgent
from agent_framework import Agent, AgentResponse
from agent_framework.azure import AzureOpenAIChatClient, DurableAIAgentOrchestrationContext, DurableAIAgentWorker
from azure.identity import AzureCliCredential, DefaultAzureCredential
from durabletask.azuremanaged.worker import DurableTaskSchedulerWorker
@@ -51,11 +51,11 @@ class EmailPayload(BaseModel):
email_content: str
def create_spam_agent() -> "ChatAgent":
def create_spam_agent() -> "Agent":
"""Create the Spam Detection agent using Azure OpenAI.
Returns:
ChatAgent: The configured Spam Detection agent
Agent: The configured Spam Detection agent
"""
return AzureOpenAIChatClient(credential=AzureCliCredential()).as_agent(
name=SPAM_AGENT_NAME,
@@ -63,11 +63,11 @@ def create_spam_agent() -> "ChatAgent":
)
def create_email_agent() -> "ChatAgent":
def create_email_agent() -> "Agent":
"""Create the Email Assistant agent using Azure OpenAI.
Returns:
ChatAgent: The configured Email Assistant agent
Agent: The configured Email Assistant agent
"""
return AzureOpenAIChatClient(credential=AzureCliCredential()).as_agent(
name=EMAIL_AGENT_NAME,
@@ -19,7 +19,7 @@ from collections.abc import Generator
from datetime import timedelta
from typing import Any, cast
from agent_framework import AgentResponse, ChatAgent
from agent_framework import Agent, AgentResponse
from agent_framework.azure import AzureOpenAIChatClient, DurableAIAgentOrchestrationContext, DurableAIAgentWorker
from azure.identity import AzureCliCredential, DefaultAzureCredential
from durabletask.azuremanaged.worker import DurableTaskSchedulerWorker
@@ -54,11 +54,11 @@ class HumanApproval(BaseModel):
feedback: str = ""
def create_writer_agent() -> "ChatAgent":
def create_writer_agent() -> "Agent":
"""Create the Writer agent using Azure OpenAI.
Returns:
ChatAgent: The configured Writer agent
Agent: The configured Writer agent
"""
instructions = (
"You are a professional content writer who creates high-quality articles on various topics. "
@@ -17,7 +17,7 @@ from typing import Any
import openai
import pandas as pd
from agent_framework import ChatAgent, ChatMessage
from agent_framework import Agent, Message
from agent_framework.azure import AzureOpenAIChatClient
from azure.ai.projects import AIProjectClient
from azure.identity import AzureCliCredential
@@ -142,7 +142,7 @@ def run_eval(
async def execute_query_with_self_reflection(
*,
client: openai.OpenAI,
agent: ChatAgent,
agent: Agent,
eval_object: openai.types.EvalCreateResponse,
full_user_query: str,
context: str,
@@ -152,7 +152,7 @@ async def execute_query_with_self_reflection(
Execute a query with self-reflection loop.
Args:
agent: ChatAgent instance to use for generating responses
agent: Agent instance to use for generating responses
full_user_query: Complete prompt including system prompt, user request, and context
context: Context document for groundedness evaluation
evaluator: Groundedness evaluator function
@@ -170,7 +170,7 @@ async def execute_query_with_self_reflection(
- total_groundedness_eval_time: Time spent on evaluations (seconds)
- total_end_to_end_time: Total execution time (seconds)
"""
messages = [ChatMessage("user", [full_user_query])]
messages = [Message("user", [full_user_query])]
best_score = 0
max_score = 5
@@ -223,14 +223,14 @@ async def execute_query_with_self_reflection(
print(f" → No improvement (score: {score}/{max_score}). Trying again...")
# Add to conversation history
messages.append(ChatMessage("assistant", [agent_response]))
messages.append(Message("assistant", [agent_response]))
# Request improvement
reflection_prompt = (
f"The groundedness score of your response is {score}/{max_score}. "
f"Reflect on your answer and improve it to get the maximum score of {max_score} "
)
messages.append(ChatMessage("user", [reflection_prompt]))
messages.append(Message("user", [reflection_prompt]))
end_time = time.time()
latency = end_time - start_time
@@ -2,7 +2,7 @@
import os
from agent_framework import ChatAgent, MCPStreamableHTTPTool
from agent_framework import Agent, MCPStreamableHTTPTool
from agent_framework.openai import OpenAIResponsesClient
from httpx import AsyncClient
@@ -43,8 +43,8 @@ async def api_key_auth_example() -> None:
url=mcp_server_url,
http_client=http_client, # Pass HTTP client with authentication headers
) as mcp_tool,
ChatAgent(
chat_client=OpenAIResponsesClient(),
Agent(
client=OpenAIResponsesClient(),
name="Agent",
instructions="You are a helpful assistant.",
tools=mcp_tool,
@@ -3,7 +3,7 @@
import asyncio
import os
from agent_framework import ChatAgent, HostedMCPTool
from agent_framework import Agent, HostedMCPTool
from agent_framework.openai import OpenAIResponsesClient
from dotenv import load_dotenv
@@ -54,8 +54,8 @@ async def github_mcp_example() -> None:
)
# 5. Create agent with the GitHub MCP tool
async with ChatAgent(
chat_client=OpenAIResponsesClient(),
async with Agent(
client=OpenAIResponsesClient(),
name="GitHubAgent",
instructions=(
"You are a helpful assistant that can help users interact with GitHub. "
@@ -7,9 +7,9 @@ from typing import Annotated
from agent_framework import (
ChatContext,
ChatMessage,
ChatMiddleware,
ChatResponse,
Message,
MiddlewareTermination,
chat_middleware,
tool,
@@ -69,7 +69,7 @@ class InputObserverMiddleware(ChatMiddleware):
print(f"[InputObserverMiddleware] Total messages: {len(context.messages)}")
# Modify user messages by creating new messages with enhanced text
modified_messages: list[ChatMessage] = []
modified_messages: list[Message] = []
modified_count = 0
for message in context.messages:
@@ -81,7 +81,7 @@ class InputObserverMiddleware(ChatMiddleware):
updated_text = self.replacement
print(f"[InputObserverMiddleware] Updated: '{original_text}' -> '{updated_text}'")
modified_message = ChatMessage(message.role, [updated_text])
modified_message = Message(message.role, [updated_text])
modified_messages.append(modified_message)
modified_count += 1
else:
@@ -118,7 +118,7 @@ async def security_and_override_middleware(
# Override the response instead of calling AI
context.result = ChatResponse(
messages=[
ChatMessage(
Message(
role="assistant",
text="I cannot process requests containing sensitive information. "
"Please rephrase your question without including passwords, secrets, or other "
@@ -10,9 +10,9 @@ from agent_framework import (
AgentContext,
AgentMiddleware,
AgentResponse,
ChatMessage,
FunctionInvocationContext,
FunctionMiddleware,
Message,
tool,
)
from agent_framework.azure import AzureAIAgentClient
@@ -61,7 +61,7 @@ class SecurityAgentMiddleware(AgentMiddleware):
print("[SecurityAgentMiddleware] Security Warning: Detected sensitive information, blocking request.")
# Override the result with warning message
context.result = AgentResponse(
messages=[ChatMessage("assistant", ["Detected sensitive information, the request is blocked."])]
messages=[Message("assistant", ["Detected sensitive information, the request is blocked."])]
)
# Simply don't call call_next() to prevent execution
return
@@ -9,7 +9,7 @@ from agent_framework import (
AgentContext,
AgentMiddleware,
AgentResponse,
ChatMessage,
Message,
MiddlewareTermination,
tool,
)
@@ -62,7 +62,7 @@ class PreTerminationMiddleware(AgentMiddleware):
# Set a custom response
context.result = AgentResponse(
messages=[
ChatMessage(
Message(
role="assistant",
text=(
f"Sorry, I cannot process requests containing '{blocked_word}'. "
@@ -72,8 +72,8 @@ class PreTerminationMiddleware(AgentMiddleware):
]
)
# Set terminate flag to prevent further processing
raise MiddlewareTermination
# Terminate to prevent further processing
raise MiddlewareTermination(result=context.result)
await call_next(context)
@@ -11,10 +11,11 @@ from agent_framework import (
AgentResponse,
AgentResponseUpdate,
ChatContext,
ChatMessage,
ChatResponse,
ChatResponseUpdate,
Message,
ResponseStream,
Role,
tool,
)
from agent_framework.openai import OpenAIResponsesClient
@@ -78,9 +79,9 @@ async def weather_override_middleware(context: ChatContext, call_next: Callable[
context.result.with_transform_hook(_update_hook)
else:
# For non-streaming: just replace with a new message
current_text = context.result.text or "" # type: ignore
current_text = context.result.text if isinstance(context.result, ChatResponse) else ""
custom_message = f"Weather Advisory: [0] {''.join(chunks)} Original message was: {current_text}"
context.result = ChatResponse(messages=[ChatMessage(role="assistant", text=custom_message)])
context.result = ChatResponse(messages=[Message(role=Role.ASSISTANT, text=custom_message)])
async def validate_weather_middleware(context: ChatContext, call_next: Callable[[ChatContext], Awaitable[None]]) -> None:
@@ -95,12 +96,12 @@ async def validate_weather_middleware(context: ChatContext, call_next: Callable[
if context.stream and isinstance(context.result, ResponseStream):
def _append_validation_note(response: ChatResponse) -> ChatResponse:
response.messages.append(ChatMessage(role="assistant", text=validation_note))
response.messages.append(Message(role=Role.ASSISTANT, text=validation_note))
return response
context.result.with_result_hook(_append_validation_note)
context.result.with_finalizer(_append_validation_note)
elif isinstance(context.result, ChatResponse):
context.result.messages.append(ChatMessage(role="assistant", text=validation_note))
context.result.messages.append(Message(role=Role.ASSISTANT, text=validation_note))
async def agent_cleanup_middleware(context: AgentContext, call_next: Callable[[AgentContext], Awaitable[None]]) -> None:
@@ -117,7 +118,7 @@ async def agent_cleanup_middleware(context: AgentContext, call_next: Callable[[A
def _sanitize(response: AgentResponse) -> AgentResponse:
found_prefix = state["found_prefix"]
found_validation = False
cleaned_messages: list[ChatMessage] = []
cleaned_messages: list[Message] = []
for message in response.messages:
text = message.text
@@ -138,7 +139,7 @@ async def agent_cleanup_middleware(context: AgentContext, call_next: Callable[[A
text = re.sub(r"\[\d+\]\s*", "", text)
cleaned_messages.append(
ChatMessage(
Message(
role=message.role,
text=text.strip(),
author_name=message.author_name,
@@ -153,7 +154,7 @@ async def agent_cleanup_middleware(context: AgentContext, call_next: Callable[[A
if not found_validation:
raise RuntimeError("Expected validation note not found in agent response.")
cleaned_messages.append(ChatMessage(role="assistant", text=" Agent: OK"))
cleaned_messages.append(Message(role=Role.ASSISTANT, text=" Agent: OK"))
response.messages = cleaned_messages
return response
@@ -172,7 +173,7 @@ async def agent_cleanup_middleware(context: AgentContext, call_next: Callable[[A
return update
context.result.with_transform_hook(_clean_update)
context.result.with_result_hook(_sanitize)
context.result.with_finalizer(_sanitize)
elif isinstance(context.result, AgentResponse):
context.result = _sanitize(context.result)
@@ -191,19 +192,6 @@ async def main() -> None:
tools=get_weather,
middleware=[agent_cleanup_middleware],
)
# Streaming example
print("\n--- Streaming Example ---")
query = "What's the weather like in Portland?"
print(f"User: {query}")
print("Agent: ", end="", flush=True)
response = agent.run(query, stream=True)
# add the hooks to print what you want to see
response.with_transform_hook(lambda chunk: print(chunk.text, end="", flush=True)).with_result_hook(
lambda final: print(f"\nFinal streamed response: {final.text}", flush=True)
)
# consume the stream to trigger the hooks
await response.get_final_response()
# Non-streaming example
print("\n--- Non-streaming Example ---")
query = "What's the weather like in Seattle?"
@@ -211,6 +199,18 @@ async def main() -> None:
result = await agent.run(query)
print(f"Agent: {result}")
# Streaming example
print("\n--- Streaming Example ---")
query = "What's the weather like in Portland?"
print(f"User: {query}")
print("Agent: ", end="", flush=True)
response = agent.run(query, stream=True)
async for chunk in response:
if chunk.text:
print(chunk.text, end="", flush=True)
print("\n")
print(f"Final Result: {(await response.get_final_response()).text}")
if __name__ == "__main__":
asyncio.run(main())
@@ -2,7 +2,7 @@
import asyncio
from agent_framework import ChatMessage, Content
from agent_framework import Content, Message
from agent_framework.azure import AzureOpenAIChatClient
from azure.identity import AzureCliCredential
@@ -24,7 +24,7 @@ async def test_image() -> None:
client = AzureOpenAIChatClient(credential=AzureCliCredential())
image_uri = create_sample_image()
message = ChatMessage(
message = Message(
role="user",
contents=[
Content.from_text(text="What's in this image?"),
@@ -3,7 +3,7 @@
import asyncio
from pathlib import Path
from agent_framework import ChatMessage, Content
from agent_framework import Content, Message
from agent_framework.azure import AzureOpenAIResponsesClient
from azure.identity import AzureCliCredential
@@ -33,7 +33,7 @@ async def test_image() -> None:
client = AzureOpenAIResponsesClient(credential=AzureCliCredential())
image_uri = create_sample_image()
message = ChatMessage(
message = Message(
role="user",
contents=[
Content.from_text(text="What's in this image?"),
@@ -50,7 +50,7 @@ async def test_pdf() -> None:
client = AzureOpenAIResponsesClient(credential=AzureCliCredential())
pdf_bytes = load_sample_pdf()
message = ChatMessage(
message = Message(
role="user",
contents=[
Content.from_text(text="What information can you extract from this document?"),
@@ -5,7 +5,7 @@ import base64
import struct
from pathlib import Path
from agent_framework import ChatMessage, Content
from agent_framework import Content, Message
from agent_framework.openai import OpenAIChatClient
ASSETS_DIR = Path(__file__).resolve().parent.parent / "sample_assets"
@@ -45,7 +45,7 @@ async def test_image() -> None:
client = OpenAIChatClient(model_id="gpt-4o")
image_uri = create_sample_image()
message = ChatMessage(
message = Message(
role="user",
contents=[
Content.from_text(text="What's in this image?"),
@@ -62,7 +62,7 @@ async def test_audio() -> None:
client = OpenAIChatClient(model_id="gpt-4o-audio-preview")
audio_uri = create_sample_audio()
message = ChatMessage(
message = Message(
role="user",
contents=[
Content.from_text(text="What do you hear in this audio?"),
@@ -79,7 +79,7 @@ async def test_pdf() -> None:
client = OpenAIChatClient(model_id="gpt-4o")
pdf_bytes = load_sample_pdf()
message = ChatMessage(
message = Message(
role="user",
contents=[
Content.from_text(text="What information can you extract from this document?"),
@@ -12,7 +12,7 @@ from opentelemetry.trace.span import format_trace_id
from pydantic import Field
if TYPE_CHECKING:
from agent_framework import ChatClientProtocol
from agent_framework import SupportsChatGetResponse
"""
@@ -51,7 +51,7 @@ async def get_weather(
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C."
async def run_chat_client(client: "ChatClientProtocol", stream: bool = False) -> None:
async def run_chat_client(client: "SupportsChatGetResponse", stream: bool = False) -> None:
"""Run an AI service.
This function runs an AI service and prints the output.
@@ -4,7 +4,7 @@ import asyncio
from random import randint
from typing import Annotated
from agent_framework import ChatAgent, tool
from agent_framework import Agent, tool
from agent_framework.observability import configure_otel_providers, get_tracer
from agent_framework.openai import OpenAIChatClient
from opentelemetry.trace import SpanKind
@@ -39,8 +39,8 @@ async def main():
with get_tracer().start_as_current_span("Scenario: Agent Chat", kind=SpanKind.CLIENT) as current_span:
print(f"Trace ID: {format_trace_id(current_span.get_span_context().trace_id)}")
agent = ChatAgent(
chat_client=OpenAIChatClient(),
agent = Agent(
client=OpenAIChatClient(),
tools=get_weather,
name="WeatherAgent",
instructions="You are a weather assistant.",
@@ -16,7 +16,7 @@ from random import randint
from typing import Annotated
import dotenv
from agent_framework import ChatAgent, tool
from agent_framework import Agent, tool
from agent_framework.observability import create_resource, enable_instrumentation, get_tracer
from agent_framework.openai import OpenAIResponsesClient
from azure.ai.projects.aio import AIProjectClient
@@ -30,7 +30,7 @@ from pydantic import Field
This sample shows you can can setup telemetry in Microsoft Foundry for a custom agent.
First ensure you have a Foundry workspace with Application Insights enabled.
And use the Operate tab to Register an Agent.
Set the OpenTelemetry agent ID to the value used below in the ChatAgent creation: `weather-agent` (or change both).
Set the OpenTelemetry agent ID to the value used below in the Agent creation: `weather-agent` (or change both).
The sample uses the Azure Monitor OpenTelemetry exporter to send traces to Application Insights.
So ensure you have the `azure-monitor-opentelemetry` package installed.
"""
@@ -85,8 +85,8 @@ async def main():
with get_tracer().start_as_current_span("Weather Agent Chat", kind=SpanKind.CLIENT) as current_span:
print(f"Trace ID: {format_trace_id(current_span.get_span_context().trace_id)}")
agent = ChatAgent(
chat_client=OpenAIResponsesClient(),
agent = Agent(
client=OpenAIResponsesClient(),
tools=get_weather,
name="WeatherAgent",
instructions="You are a weather assistant.",

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