Skip to content

Commit 0521f5b

Browse files
Python: [BREAKING] Simplify API: ChatAgent -> Agent, ChatMessage -> Message (microsoft#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>
1 parent a4c9e43 commit 0521f5b

418 files changed

Lines changed: 5386 additions & 5390 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

python/.github/skills/python-development/SKILL.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ def equal(arg1: str, arg2: str) -> bool:
6969

7070
```python
7171
# Core
72-
from agent_framework import ChatAgent, ChatMessage, tool
72+
from agent_framework import ChatAgent, Message, tool
7373

7474
# Components
7575
from agent_framework.observability import enable_instrumentation
@@ -84,10 +84,10 @@ from agent_framework.azure import AzureOpenAIChatClient
8484
Define `__all__` in each module. Avoid `from module import *` in `__init__.py` files:
8585

8686
```python
87-
__all__ = ["ChatAgent", "ChatMessage", "ChatResponse"]
87+
__all__ = ["ChatAgent", "Message", "ChatResponse"]
8888

8989
from ._agents import ChatAgent
90-
from ._types import ChatMessage, ChatResponse
90+
from ._types import Message, ChatResponse
9191
```
9292

9393
## Performance Guidelines

python/CHANGELOG.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
### Added
1111

1212
- **agent-framework-core**: Add long-running agents and background responses support with `ContinuationToken` TypedDict, `background` option in `OpenAIResponsesOptions`, and continuation token propagation through response types ([#2478](https://github.com/microsoft/agent-framework/issues/2478))
13+
### Changed
14+
15+
- **agent-framework-core**: [BREAKING] Renamed core types for simpler API:
16+
- `ChatAgent``Agent`
17+
- `RawChatAgent``RawAgent`
18+
- `ChatMessage``Message`
19+
- `ChatClientProtocol``SupportsChatGetResponse`
1320

1421
## [1.0.0b260130] - 2026-01-30
1522

@@ -272,7 +279,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
272279
### Changed
273280

274281
- **agent-framework-core**: [BREAKING] Support Magentic agent tool call approvals and plan stalling HITL behavior (#2569)
275-
- **agent-framework-core**: [BREAKING] Standardize orchestration outputs as list of `ChatMessage`; allow agent as group chat manager (#2291)
282+
- **agent-framework-core**: [BREAKING] Standardize orchestration outputs as list of `Message`; allow agent as group chat manager (#2291)
276283
- **agent-framework-core**: [BREAKING] Respond with `AgentRunResponse` including serialized structured output (#2285)
277284
- **observability**: Use `executor_id` and `edge_group_id` as span names for clearer traces (#2538)
278285
- **agent-framework-devui**: Add multimodal input support for workflows and refactor chat input (#2593)
@@ -318,7 +325,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
318325
- **agent-framework-core**: Fix tool execution bleed-over in aiohttp/Bot Framework scenarios ([#2314](https://github.com/microsoft/agent-framework/pull/2314))
319326
- **agent-framework-core**: `@ai_function` now correctly handles `self` parameter ([#2266](https://github.com/microsoft/agent-framework/pull/2266))
320327
- **agent-framework-core**: Resolve string annotations in `FunctionExecutor` ([#2308](https://github.com/microsoft/agent-framework/pull/2308))
321-
- **agent-framework-core**: Langfuse observability captures ChatAgent system instructions ([#2316](https://github.com/microsoft/agent-framework/pull/2316))
328+
- **agent-framework-core**: Langfuse observability captures Agent system instructions ([#2316](https://github.com/microsoft/agent-framework/pull/2316))
322329
- **agent-framework-core**: Incomplete URL substring sanitization fix ([#2274](https://github.com/microsoft/agent-framework/pull/2274))
323330
- **observability**: Handle datetime serialization in tool results ([#2248](https://github.com/microsoft/agent-framework/pull/2248))
324331

python/CODING_STANDARD.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,10 @@ Prefer attributes over inheritance when parameters are mostly the same:
118118

119119
```python
120120
# ✅ Preferred - using attributes
121-
from agent_framework import ChatMessage
121+
from agent_framework import Message
122122

123-
user_msg = ChatMessage("user", ["Hello, world!"])
124-
asst_msg = ChatMessage("assistant", ["Hello, world!"])
123+
user_msg = Message("user", ["Hello, world!"])
124+
asst_msg = Message("assistant", ["Hello, world!"])
125125

126126
# ❌ Not preferred - unnecessary inheritance
127127
from agent_framework import UserMessage, AssistantMessage
@@ -157,7 +157,7 @@ The package follows a flat import structure:
157157

158158
- **Core**: Import directly from `agent_framework`
159159
```python
160-
from agent_framework import ChatAgent, tool
160+
from agent_framework import Agent, tool
161161
```
162162

163163
- **Components**: Import from `agent_framework.<component>`
@@ -381,12 +381,12 @@ def create_client(
381381
Use Google-style docstrings for all public APIs:
382382

383383
```python
384-
def create_agent(name: str, chat_client: ChatClientProtocol) -> Agent:
384+
def create_agent(name: str, client: SupportsChatGetResponse) -> Agent:
385385
"""Create a new agent with the specified configuration.
386386
387387
Args:
388388
name: The name of the agent.
389-
chat_client: The chat client to use for communication.
389+
client: The chat client to use for communication.
390390
391391
Returns:
392392
True if the strings are the same, False otherwise.
@@ -409,10 +409,10 @@ Define `__all__` in each module to explicitly declare the public API. Avoid usin
409409

410410
```python
411411
# ✅ Preferred - explicit __all__ and imports
412-
__all__ = ["ChatAgent", "ChatMessage", "ChatResponse"]
412+
__all__ = ["Agent", "Message", "ChatResponse"]
413413

414-
from ._agents import ChatAgent
415-
from ._types import ChatMessage, ChatResponse
414+
from ._agents import Agent
415+
from ._types import Message, ChatResponse
416416

417417
# ❌ Avoid - star imports
418418
from ._agents import *

python/DEV_SETUP.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ You will then configure the ChatClient class with the keyword argument `env_file
116116
```python
117117
from agent_framework.openai import OpenAIChatClient
118118

119-
chat_client = OpenAIChatClient(env_file_path="openai.env")
119+
client = OpenAIChatClient(env_file_path="openai.env")
120120
```
121121

122122
## Tests

python/README.md

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ You can also override environment variables by explicitly passing configuration
6262
```python
6363
from agent_framework.azure import AzureOpenAIChatClient
6464

65-
chat_client = AzureOpenAIChatClient(
65+
client = AzureOpenAIChatClient(
6666
api_key='',
6767
endpoint='',
6868
deployment_name='',
@@ -78,12 +78,12 @@ Create agents and invoke them directly:
7878

7979
```python
8080
import asyncio
81-
from agent_framework import ChatAgent
81+
from agent_framework import Agent
8282
from agent_framework.openai import OpenAIChatClient
8383

8484
async def main():
85-
agent = ChatAgent(
86-
chat_client=OpenAIChatClient(),
85+
agent = Agent(
86+
client=OpenAIChatClient(),
8787
instructions="""
8888
1) A robot may not injure a human being...
8989
2) A robot must obey orders given it by human beings...
@@ -106,15 +106,15 @@ You can use the chat client classes directly for advanced workflows:
106106

107107
```python
108108
import asyncio
109-
from agent_framework import ChatMessage
109+
from agent_framework import Message
110110
from agent_framework.openai import OpenAIChatClient
111111

112112
async def main():
113113
client = OpenAIChatClient()
114114

115115
messages = [
116-
ChatMessage("system", ["You are a helpful assistant."]),
117-
ChatMessage("user", ["Write a haiku about Agent Framework."])
116+
Message("system", ["You are a helpful assistant."]),
117+
Message("user", ["Write a haiku about Agent Framework."])
118118
]
119119

120120
response = await client.get_response(messages)
@@ -140,7 +140,7 @@ import asyncio
140140
from typing import Annotated
141141
from random import randint
142142
from pydantic import Field
143-
from agent_framework import ChatAgent
143+
from agent_framework import Agent
144144
from agent_framework.openai import OpenAIChatClient
145145

146146

@@ -162,8 +162,8 @@ def get_menu_specials() -> str:
162162

163163

164164
async def main():
165-
agent = ChatAgent(
166-
chat_client=OpenAIChatClient(),
165+
agent = Agent(
166+
client=OpenAIChatClient(),
167167
instructions="You are a helpful assistant that can provide weather and restaurant information.",
168168
tools=[get_weather, get_menu_specials]
169169
)
@@ -189,20 +189,20 @@ Coordinate multiple agents to collaborate on complex tasks using orchestration p
189189

190190
```python
191191
import asyncio
192-
from agent_framework import ChatAgent
192+
from agent_framework import Agent
193193
from agent_framework.openai import OpenAIChatClient
194194

195195

196196
async def main():
197197
# Create specialized agents
198-
writer = ChatAgent(
199-
chat_client=OpenAIChatClient(),
198+
writer = Agent(
199+
client=OpenAIChatClient(),
200200
name="Writer",
201201
instructions="You are a creative content writer. Generate and refine slogans based on feedback."
202202
)
203203

204-
reviewer = ChatAgent(
205-
chat_client=OpenAIChatClient(),
204+
reviewer = Agent(
205+
client=OpenAIChatClient(),
206206
name="Reviewer",
207207
instructions="You are a critical reviewer. Provide detailed feedback on proposed slogans."
208208
)

python/packages/a2a/agent_framework_a2a/_agent.py

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
FilePart,
1919
FileWithBytes,
2020
FileWithUri,
21-
Message,
2221
Task,
2322
TaskIdParams,
2423
TaskQueryParams,
@@ -34,9 +33,9 @@
3433
AgentResponseUpdate,
3534
AgentThread,
3635
BaseAgent,
37-
ChatMessage,
3836
Content,
3937
ContinuationToken,
38+
Message,
4039
ResponseStream,
4140
normalize_messages,
4241
prepend_agent_framework_to_user_agent,
@@ -83,7 +82,7 @@ class A2AAgent(AgentTelemetryLayer, BaseAgent):
8382
"""Agent2Agent (A2A) protocol implementation.
8483
8584
Wraps an A2A Client to connect the Agent Framework with external A2A-compliant agents
86-
via HTTP/JSON-RPC. Converts framework ChatMessages to A2A Messages on send, and converts
85+
via HTTP/JSON-RPC. Converts framework Messages to A2A Messages on send, and converts
8786
A2A responses (Messages/Tasks) back to framework types. Inherits BaseAgent capabilities
8887
while managing the underlying A2A protocol communication.
8988
@@ -209,7 +208,7 @@ async def __aexit__(
209208
@overload
210209
def run(
211210
self,
212-
messages: str | ChatMessage | Sequence[str | ChatMessage] | None = None,
211+
messages: str | Message | Sequence[str | Message] | None = None,
213212
*,
214213
stream: Literal[False] = ...,
215214
thread: AgentThread | None = None,
@@ -221,7 +220,7 @@ def run(
221220
@overload
222221
def run(
223222
self,
224-
messages: str | ChatMessage | Sequence[str | ChatMessage] | None = None,
223+
messages: str | Message | Sequence[str | Message] | None = None,
225224
*,
226225
stream: Literal[True],
227226
thread: AgentThread | None = None,
@@ -232,7 +231,7 @@ def run(
232231

233232
def run(
234233
self,
235-
messages: str | ChatMessage | Sequence[str | ChatMessage] | None = None,
234+
messages: str | Message | Sequence[str | Message] | None = None,
236235
*,
237236
stream: bool = False,
238237
thread: AgentThread | None = None,
@@ -268,7 +267,7 @@ def run(
268267

269268
response = ResponseStream(
270269
self._map_a2a_stream(a2a_stream, background=background),
271-
finalizer=lambda updates: AgentResponse.from_updates(list(updates)),
270+
finalizer=AgentResponse.from_updates,
272271
)
273272
if stream:
274273
return response
@@ -291,7 +290,8 @@ async def _map_a2a_stream(
291290
When True, they are yielded with a continuation token.
292291
"""
293292
async for item in a2a_stream:
294-
if isinstance(item, Message):
293+
if isinstance(item, A2AMessage):
294+
# Process A2A Message
295295
contents = self._parse_contents_from_a2a(item.parts)
296296
yield AgentResponseUpdate(
297297
contents=contents,
@@ -377,10 +377,10 @@ async def poll_task(self, continuation_token: A2AContinuationToken) -> AgentResp
377377
return AgentResponse.from_updates(updates)
378378
return AgentResponse(messages=[], response_id=task.id, raw_representation=task)
379379

380-
def _prepare_message_for_a2a(self, message: ChatMessage) -> A2AMessage:
381-
"""Prepare a ChatMessage for the A2A protocol.
380+
def _prepare_message_for_a2a(self, message: Message) -> A2AMessage:
381+
"""Prepare a Message for the A2A protocol.
382382
383-
Transforms Agent Framework ChatMessage objects into A2A protocol Messages by:
383+
Transforms Agent Framework Message objects into A2A protocol Messages by:
384384
- Converting all message contents to appropriate A2A Part types
385385
- Mapping text content to TextPart objects
386386
- Converting file references (URI/data/hosted_file) to FilePart objects
@@ -389,7 +389,7 @@ def _prepare_message_for_a2a(self, message: ChatMessage) -> A2AMessage:
389389
"""
390390
parts: list[A2APart] = []
391391
if not message.contents:
392-
raise ValueError("ChatMessage.contents is empty; cannot convert to A2AMessage.")
392+
raise ValueError("Message.contents is empty; cannot convert to A2AMessage.")
393393

394394
# Process ALL contents
395395
for content in message.contents:
@@ -511,9 +511,9 @@ def _parse_contents_from_a2a(self, parts: Sequence[A2APart]) -> list[Content]:
511511
raise ValueError(f"Unknown Part kind: {inner_part.kind}")
512512
return contents
513513

514-
def _parse_messages_from_task(self, task: Task) -> list[ChatMessage]:
515-
"""Parse A2A Task artifacts into ChatMessages with ASSISTANT role."""
516-
messages: list[ChatMessage] = []
514+
def _parse_messages_from_task(self, task: Task) -> list[Message]:
515+
"""Parse A2A Task artifacts into Messages with ASSISTANT role."""
516+
messages: list[Message] = []
517517

518518
if task.artifacts is not None:
519519
for artifact in task.artifacts:
@@ -523,7 +523,7 @@ def _parse_messages_from_task(self, task: Task) -> list[ChatMessage]:
523523
history_item = task.history[-1]
524524
contents = self._parse_contents_from_a2a(history_item.parts)
525525
messages.append(
526-
ChatMessage(
526+
Message(
527527
role="assistant" if history_item.role == A2ARole.agent else "user",
528528
contents=contents,
529529
raw_representation=history_item,
@@ -532,10 +532,10 @@ def _parse_messages_from_task(self, task: Task) -> list[ChatMessage]:
532532

533533
return messages
534534

535-
def _parse_message_from_artifact(self, artifact: Artifact) -> ChatMessage:
536-
"""Parse A2A Artifact into ChatMessage using part contents."""
535+
def _parse_message_from_artifact(self, artifact: Artifact) -> Message:
536+
"""Parse A2A Artifact into Message using part contents."""
537537
contents = self._parse_contents_from_a2a(artifact.parts)
538-
return ChatMessage(
538+
return Message(
539539
role="assistant",
540540
contents=contents,
541541
raw_representation=artifact,

0 commit comments

Comments
 (0)