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
@@ -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: