Skip to content

Comments

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

Merged
eavanvalkenburg merged 16 commits intomicrosoft:mainfrom
eavanvalkenburg:edvan/rename-chat-agent-message
Feb 10, 2026
Merged

Python: [BREAKING] Simplify API: ChatAgent -> Agent, ChatMessage -> Message#3747
eavanvalkenburg merged 16 commits intomicrosoft:mainfrom
eavanvalkenburg:edvan/rename-chat-agent-message

Conversation

@eavanvalkenburg
Copy link
Member

@eavanvalkenburg eavanvalkenburg commented Feb 7, 2026

Summary

This PR simplifies the public API by removing redundant Chat prefix from core types that users interact with most frequently.

Motivation

Why Agent instead of ChatAgent

While the .NET side of Agent Framework favors globally unique type names (and has a relatively limited number of orchestration packages to contend with), the Python ecosystem is fundamentally different. Python has a large and growing number of agent-focused packages — LangChain/LangGraph, CrewAI, AutoGen, PydanticAI, Smolagents, and others — and virtually all of them use Agent as their primary class name. By staying with ChatAgent, we miss the opportunity for naming parity with the broader ecosystem, making our API feel less natural to Python developers coming from (or evaluating against) other frameworks. Agent is the name Python developers expect.

Why Message instead of ChatMessage

Renaming to Message better emphasizes the generic, multimodal nature of what can be passed through a message. Messages in Agent Framework are not limited to text chat — they carry structured content including images, function calls, function results, and other content types. The Chat prefix incorrectly implies a text-only chat paradigm and undersells the capability of the type.

Breaking Changes

Before After
ChatAgent Agent
RawChatAgent RawAgent
ChatMessage Message
ChatClientProtocol SupportsChatGetResponse

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

API Examples

Creating an Agent (Before)

from agent_framework import ChatAgent, ChatMessage
from agent_framework.openai import OpenAIChatClient

client = OpenAIChatClient()
agent = ChatAgent(
    chat_client=client,
    name="assistant",
    instructions="You are a helpful assistant."
)

response = await agent.run("Hello!")

Creating an Agent (After)

from agent_framework import Agent, Message
from agent_framework.openai import OpenAIChatClient

client = OpenAIChatClient()
agent = Agent(
    client=client,
    name="assistant",
    instructions="You are a helpful assistant."
)

response = await agent.run("Hello!")

Working with Messages (Before)

from agent_framework import ChatMessage, Content

# Create a message
message = ChatMessage(role="user", contents=[Content.from_text("Hello")])

# Or with text shorthand
message = ChatMessage("user", ["Hello, how are you?"])

# Access message properties
print(message.role)    # "user"
print(message.text)    # "Hello, how are you?"

Working with Messages (After)

from agent_framework import Message, Content

# Create a message
message = Message(role="user", contents=[Content.from_text("Hello")])

# Or with text shorthand
message = Message("user", ["Hello, how are you?"])

# Access message properties
print(message.role)    # "user"
print(message.text)    # "Hello, how are you?"

Multi-turn Conversations (After)

from agent_framework import Agent, Message, AgentThread
from agent_framework.azure import AzureOpenAIChatClient

client = AzureOpenAIChatClient()
agent = Agent(chat_client=client, name="assistant")

# Use threads for conversation history
thread = AgentThread()
response = await agent.run("What is Python?", thread=thread)
response = await agent.run("Give me an example", thread=thread)

Using Tools (After)

from agent_framework import Agent, tool
from agent_framework.openai import OpenAIChatClient

@tool
def get_weather(city: str) -> str:
    """Get current weather for a city."""
    return f"Weather in {city}: Sunny, 72F"

client = OpenAIChatClient()
agent = Agent(
    chat=client,
    name="weather_bot",
    tools=[get_weather]
)

response = await agent.run("What is the weather in Seattle?")

Streaming Responses (After)

from agent_framework import Agent
from agent_framework.openai import OpenAIChatClient

client = OpenAIChatClient()
agent = Agent(chat_client=client, name="assistant")

async for event in agent.run("Tell me a story", stream=True):
    if event.type == "response_update":
        print(event.data.text, end="", flush=True)

Custom Chat Client Protocol (After)

from agent_framework import SupportsChatGetResponse, Message, ChatResponse
from collections.abc import Sequence

class MyCustomClient:
    """Implement the protocol to create custom chat clients."""
    
    additional_properties: dict = {}
    
    def get_response(
        self,
        messages: Sequence[Message],
        *,
        stream: bool = False,
        **kwargs
    ):
        # Your implementation here
        ...

Internal Changes

  • Renamed Message in _workflows/_runner_context.py to WorkflowMessage to avoid collision with the new Message type

Migration Guide

  1. Find and replace in your codebase:

    • ChatAgentAgent
    • RawChatAgentRawAgent
    • ChatMessageMessage
    • ChatClientProtocolSupportsChatGetResponse
  2. Update imports:

    # Before
    from agent_framework import ChatAgent, ChatMessage
    
    # After
    from agent_framework import Agent, Message

@markwallace-microsoft markwallace-microsoft added documentation Improvements or additions to documentation python lab Agent Framework Lab labels Feb 7, 2026
@github-actions github-actions bot changed the title [BREAKING] Simplify API: ChatAgent -> Agent, ChatMessage -> Message Python: [BREAKING] Simplify API: ChatAgent -> Agent, ChatMessage -> Message Feb 7, 2026
@eavanvalkenburg eavanvalkenburg force-pushed the edvan/rename-chat-agent-message branch from 3d8cb28 to 0681218 Compare February 7, 2026 17:50
Copy link
Contributor

@moonbox3 moonbox3 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Can approve once CI/CD is green.

@markwallace-microsoft
Copy link
Member

markwallace-microsoft commented Feb 9, 2026

Python Test Coverage

Python Test Coverage Report •
FileStmtsMissCoverMissing
packages/a2a/agent_framework_a2a
   _agent.py169994%357, 378, 451–452, 493–494, 523–525
packages/ag-ui/agent_framework_ag_ui
   _client.py1511788%85–86, 90–94, 98–102, 265, 295, 464–466
   _message_adapters.py4559579%91, 101–102, 111–114, 117–121, 123–128, 131, 140–146, 149, 153–155, 164–166, 186, 192–194, 224, 237–238, 248–249, 286, 289, 291, 294, 297, 313, 330, 352, 383, 388, 399–400, 451, 467–468, 534–537, 539, 545, 553–554, 556, 560–563, 576, 665–668, 670, 736, 771–773, 775–778, 781–782, 784, 790, 793, 795, 798, 800, 806–807, 809
   _run.py48212174%157–164, 307, 326–327, 342–343, 358, 386–388, 413, 416–419, 421–422, 425–431, 434–436, 439, 455–457, 464, 470–472, 476, 481–483, 485–486, 502–506, 517, 530, 532–533, 549, 570–571, 626–628, 640–642, 840, 851–852, 859, 877–879, 913–915, 932, 938, 946, 948, 984–990, 993–996, 998–1007, 1010, 1018–1021, 1028, 1031–1032, 1037, 1043–1045, 1049, 1054–1057, 1071–1073
packages/ag-ui/agent_framework_ag_ui/_orchestration
   _helpers.py1080100% 
   _tooling.py580100% 
packages/anthropic/agent_framework_anthropic
   _chat_client.py36415058%373, 405, 407, 422, 444–447, 456, 458, 495–499, 501, 503–504, 506, 511–512, 514, 547–548, 557, 559–560, 565, 582–583, 625, 640, 644–645, 661, 670, 672, 676–677, 720–722, 724, 737–738, 745–747, 751–753, 757–760, 771, 773, 795, 805, 827–833, 840–841, 849–850, 858–861, 868–869, 875–876, 882–883, 889, 897–899, 903, 910–911, 917–918, 924–925, 931, 939–942, 949–950, 969, 976–977, 996, 1018, 1020, 1029–1030, 1036, 1058–1059, 1065–1066, 1075–1085, 1092–1098, 1105–1111, 1118–1127, 1134–1137
packages/azure-ai/agent_framework_azure_ai
   _agent_provider.py117397%122–123, 251
   _chat_client.py4867584%386, 391–392, 394–395, 398, 401, 403, 408, 669–670, 672, 675, 678, 681–686, 689, 691, 699, 711–713, 717, 720–721, 729–732, 742, 750–753, 755–756, 758–759, 766, 774–775, 783–784, 789–790, 794–801, 806, 809, 817, 823, 831–833, 836, 858–859, 992, 1020, 1035, 1154, 1180, 1189, 1198, 1331
   _client.py1961393%362, 364, 413, 442–447, 490, 525, 527, 603
   _project_provider.py116694%134–135, 213, 311, 355, 388
packages/chatkit/agent_framework_chatkit
   _converter.py1344665%117, 122, 170, 172, 340, 393, 395, 414–416, 418, 436, 438, 440, 443, 455, 465, 483, 503–527, 529–531
packages/copilotstudio/agent_framework_copilotstudio
   _agent.py84594%156–157, 192, 200, 317
packages/core/agent_framework
   _agents.py3203589%475, 883, 920, 1019–1021, 1134, 1175, 1177, 1186–1191, 1197, 1199, 1209–1210, 1217, 1219–1220, 1228–1232, 1240–1241, 1243, 1248, 1250, 1284, 1324, 1344
   _clients.py53394%296, 497, 499
   _mcp.py3895386%113, 175, 184, 247, 255, 276, 366, 433, 468, 470, 474–475, 477–478, 532, 547, 565, 606, 712, 725–730, 752, 773, 776–778, 793–794, 800–802, 821, 830, 833–835, 850–851, 855–859, 876–880, 1020
   _memory.py27196%154
   _middleware.py3291695%80, 83, 88, 797, 799, 801, 922, 949, 951, 976, 1057, 1061, 1185, 1189, 1250, 1324
   _serialization.py106496%518, 534, 544, 612
   _sessions.py150696%197–200, 505, 519
   _threads.py137397%345, 476–477
   _tools.py7978589%232, 278, 329, 331, 359, 529, 564–565, 676, 678, 698, 716, 730, 742, 747, 749, 756, 789, 860–862, 903, 925–953, 988, 996, 1237, 1489, 1546, 1550, 1629–1633, 1651, 1653–1654, 1766, 1770, 1820, 1822, 1838, 1840, 1904, 1931, 1988, 2056, 2235–2236, 2263, 2271, 2284, 2294–2295, 2330, 2386, 2418
   _types.py10459690%83, 92–93, 147, 152, 171, 173, 177, 181, 183, 185, 187, 205, 209, 235, 257, 262, 267, 271, 297, 301, 647–648, 1019, 1081, 1098, 1116, 1121, 1139, 1149, 1166–1167, 1169, 1187–1188, 1190, 1197–1198, 1200, 1235, 1246–1247, 1249, 1287, 1544, 1597, 1604, 1626, 1632, 1680, 1723–1728, 1750, 1755, 1921, 1933, 2176, 2185, 2206, 2301, 2526, 2733, 2803, 2815, 2822, 2833, 3037–3039, 3042–3044, 3048, 3053, 3057, 3169–3171, 3199, 3253, 3257–3259, 3261, 3272–3273, 3276–3280, 3286
   observability.py6118486%334, 336–338, 341–343, 348–349, 355–356, 362–363, 370, 372–374, 377–379, 384–385, 391–392, 398–399, 406, 662, 665, 673–674, 677–680, 682, 685–687, 690–691, 719, 721, 732–734, 736–739, 743, 751, 852, 854, 1003, 1005, 1009–1014, 1016, 1019–1023, 1025, 1137–1138, 1140, 1197–1198, 1333, 1387–1388, 1504–1506, 1565, 1735, 1889, 1891
packages/core/agent_framework/_workflows
   _agent.py3466581%59, 67–73, 107–108, 350–351, 357–358, 364, 366, 371, 454–455, 464, 471, 497, 530–532, 534, 536, 538, 543, 548, 595, 625, 642, 681–684, 690, 696, 700–701, 704–710, 714–715, 721, 782, 789, 795–796, 807, 839, 846, 867, 876, 880, 882–884, 891
   _agent_executor.py1672286%98, 146, 164–165, 219–220, 222–223, 255–257, 265–267, 277–279, 281, 285, 289, 293–294
   _conversation_history.py11110%9, 11, 14, 16–20, 23, 25–26
   _conversation_state.py36586%40, 45, 47, 49, 64
   _edge_runner.py1621391%53, 58, 71, 138–139, 143, 150, 206, 211, 355–356, 360, 401
   _executor.py1761293%210, 334, 336, 345, 365, 368, 475, 480, 490, 649, 730–731
   _message_utils.py18383%22, 33, 37
   _runner.py2183285%132–133, 176–179, 183, 224–226, 251–252, 254, 289–291, 315–319, 323, 358, 362, 364, 370, 378–381, 394, 430
   _runner_context.py172795%86, 89, 385, 405, 482, 495, 499
   _typing_utils.py1463377%153, 177, 219–223, 304, 306–307, 316, 318, 325, 327, 347, 349, 351, 356–363, 366–367, 369–373, 375
   _workflow.py2682690%87, 265–267, 269–270, 288, 292, 320, 422, 597, 618, 644, 671, 673–674, 679–680, 686, 692, 697, 717–719, 732, 809
   _workflow_context.py157994%57–58, 66, 70, 84, 160, 185, 296, 415
   _workflow_executor.py1823083%94, 444, 468, 470, 478–479, 484, 486, 491, 493, 546, 574–580, 584–586, 594, 599, 610, 620, 624, 630, 634, 644, 648
packages/core/agent_framework/openai
   _assistant_provider.py1111190%158–159, 171, 296, 362, 477–482
   _assistants_client.py2763587%360, 362, 364, 367, 371–372, 375, 378, 383–384, 386, 389–391, 396, 407, 432, 434, 436, 438, 440, 445, 448, 451, 455, 466, 551, 636, 673, 710–713, 765, 782
   _chat_client.py2682192%181–182, 186, 300, 307, 388–395, 397–400, 410, 495, 532, 548
   _responses_client.py6047787%298–301, 305–306, 309–310, 316–317, 322, 335–341, 362, 370, 393, 455, 487, 512, 518, 536–537, 559, 564, 621, 635, 652, 665, 720, 799, 804, 808–810, 814–815, 838, 907, 929–930, 945–946, 964–965, 1096–1097, 1113, 1115, 1194–1202, 1297, 1352, 1367, 1403–1404, 1406–1408, 1422–1424, 1434–1435, 1441, 1456
packages/mem0/agent_framework_mem0
   _context_provider.py75198%128
   _provider.py86693%69–70, 92, 174–175, 178
packages/orchestrations/agent_framework_orchestrations
   _base_group_chat_orchestrator.py1661292%109, 277, 292, 326–328, 332, 351, 412, 458–460
   _concurrent.py1552782%51, 60–61, 69–70, 87–88, 93, 120, 125, 130–131, 137, 159, 169, 176, 243, 259, 262, 319, 349, 351–352, 354, 359, 372, 376
   _group_chat.py2856278%173, 336, 343, 372, 383–384, 390, 395, 411, 438–443, 445, 478–481, 483, 488–492, 580, 583, 622, 625, 628, 631, 639, 651–652, 654–655, 657–658, 660, 665, 668, 677, 683, 727–728, 732–733, 747–748, 750–751, 782–783, 849, 868, 876, 881–883, 890, 900
   _handoff.py3265682%104–105, 107, 136–137, 159–169, 171, 173, 175, 180, 278, 332, 357, 385, 393–394, 408, 459–460, 492, 532–534, 539–541, 657, 660, 667, 672, 734, 739, 746, 756, 758, 777, 779, 861–862, 894–895, 977, 984, 1056–1057, 1059
   _magentic.py5859683%63–72, 77, 81–92, 257, 268, 272, 292, 353, 362, 364, 406, 423, 432–433, 435–437, 439, 450, 592, 594, 634, 682, 718–720, 722, 730–733, 737–740, 801–804, 895, 901, 907, 949, 987, 1019, 1036, 1047, 1102–1103, 1107–1109, 1133, 1157–1158, 1171, 1187, 1209, 1257–1258, 1296–1297, 1460, 1463, 1472, 1475, 1480, 1531–1532, 1573–1574, 1622, 1652, 1710, 1724, 1735
   _orchestration_request_info.py540100% 
   _orchestration_state.py29582%22, 30, 70, 87–88
   _orchestrator_helpers.py21290%90–91
   _sequential.py861187%73, 166, 177, 183, 214, 216–217, 219, 224, 237, 241
packages/purview/agent_framework_purview
   _middleware.py1120100% 
   _processor.py1671094%173, 250–253, 258, 286, 288, 294, 296
packages/redis/agent_framework_redis
   _chat_message_store.py1491490%199, 232, 322–323, 326, 329, 485, 575–579, 588, 592
   _context_provider.py1785668%227, 245, 248, 254–255, 257–258, 260–262, 264–266, 268–270, 272–283, 285–286, 288–294, 322, 324, 328–333, 354, 365, 375–376, 389–390, 414, 416–417, 421–422
   _history_provider.py58198%181
   _provider.py189995%257, 259, 267, 272–273, 276, 331, 388, 400
TOTAL16901210987% 

Python Unit Test Overview

Tests Skipped Failures Errors Time
4015 225 💤 0 ❌ 0 🔥 1m 6s ⏱️

@eavanvalkenburg eavanvalkenburg force-pushed the edvan/rename-chat-agent-message branch from d85dfc7 to 12ee5b7 Compare February 10, 2026 07:37
@eavanvalkenburg eavanvalkenburg force-pushed the edvan/rename-chat-agent-message branch from 12ee5b7 to 1c313a4 Compare February 10, 2026 13:03
@eavanvalkenburg eavanvalkenburg marked this pull request as ready for review February 10, 2026 15:49
@eavanvalkenburg eavanvalkenburg requested a review from a team as a code owner February 10, 2026 15:49
Copilot AI review requested due to automatic review settings February 10, 2026 15:49
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copy link
Member

@dmytrostruk dmytrostruk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on PR description, I had a comment about chat parameter in this example:

agent = Agent(
    chat=client,
    name="assistant",
    instructions="You are a helpful assistant."
)

But I wasn't able to find it in code changes. Other than that, LGTM.

@eavanvalkenburg
Copy link
Member Author

Based on PR description, I had a comment about chat parameter in this example:

agent = Agent(
    chat=client,
    name="assistant",
    instructions="You are a helpful assistant."
)

But I wasn't able to find it in code changes. Other than that, LGTM.

That should be client instead. I'll doublecheck

@eavanvalkenburg eavanvalkenburg force-pushed the edvan/rename-chat-agent-message branch from 143b140 to 31d7fb6 Compare February 10, 2026 19:57
@eavanvalkenburg eavanvalkenburg force-pushed the edvan/rename-chat-agent-message branch 2 times, most recently from d105ac7 to 53f0414 Compare February 10, 2026 20:28
@eavanvalkenburg eavanvalkenburg added this pull request to the merge queue Feb 10, 2026
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to a conflict with the base branch Feb 10, 2026
@eavanvalkenburg eavanvalkenburg added this pull request to the merge queue Feb 10, 2026
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to a conflict with the base branch Feb 10, 2026
@eavanvalkenburg eavanvalkenburg force-pushed the edvan/rename-chat-agent-message branch from 53f0414 to a8f7b4c Compare February 10, 2026 20:55
@eavanvalkenburg eavanvalkenburg force-pushed the edvan/rename-chat-agent-message branch from 368f296 to 5e9769e Compare February 10, 2026 21:56
@eavanvalkenburg eavanvalkenburg added this pull request to the merge queue Feb 10, 2026
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to a conflict with the base branch Feb 10, 2026
@eavanvalkenburg eavanvalkenburg added this pull request to the merge queue Feb 10, 2026
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to a conflict with the base branch Feb 10, 2026
…entProtocol -> 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.
…ge→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)
- 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
@eavanvalkenburg eavanvalkenburg force-pushed the edvan/rename-chat-agent-message branch from 132b0a4 to 58c4f9b Compare February 10, 2026 22:37
@eavanvalkenburg eavanvalkenburg added this pull request to the merge queue Feb 10, 2026
Merged via the queue into microsoft:main with commit 0521f5b Feb 10, 2026
37 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation lab Agent Framework Lab python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants