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
@@ -10,9 +10,9 @@ from agent_framework import (
AgentResponseUpdate,
AgentThread,
BaseAgent,
ChatMessage,
Content,
Executor,
Message,
TypeCompatibilityError,
WorkflowContext,
WorkflowRunState,
@@ -27,7 +27,7 @@ class _EchoAgent(BaseAgent):
def run( # type: ignore[override]
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,
@@ -37,7 +37,7 @@ class _EchoAgent(BaseAgent):
return self._run_stream()
async def _run() -> AgentResponse:
return AgentResponse(messages=[ChatMessage("assistant", [f"{self.name} reply"])])
return AgentResponse(messages=[Message("assistant", [f"{self.name} reply"])])
return _run()
@@ -50,11 +50,11 @@ class _SummarizerExec(Executor):
"""Custom executor that summarizes by appending a short assistant message."""
@handler
async def summarize(self, agent_response: AgentExecutorResponse, ctx: WorkflowContext[list[ChatMessage]]) -> None:
async def summarize(self, agent_response: AgentExecutorResponse, ctx: WorkflowContext[list[Message]]) -> None:
conversation = agent_response.full_conversation or []
user_texts = [m.text for m in conversation if m.role == "user"]
agents = [m.author_name or m.role for m in conversation if m.role == "assistant"]
summary = ChatMessage("assistant", [f"Summary of users:{len(user_texts)} agents:{len(agents)}"])
summary = Message("assistant", [f"Summary of users:{len(user_texts)} agents:{len(agents)}"])
await ctx.send_message(list(conversation) + [summary])
@@ -62,7 +62,7 @@ class _InvalidExecutor(Executor):
"""Invalid executor that does not have a handler that accepts a list of chat messages"""
@handler
async def summarize(self, conversation: list[str], ctx: WorkflowContext[list[ChatMessage]]) -> None:
async def summarize(self, conversation: list[str], ctx: WorkflowContext[list[Message]]) -> None:
pass
@@ -84,7 +84,7 @@ async def test_sequential_agents_append_to_context() -> None:
wf = SequentialBuilder(participants=[a1, a2]).build()
completed = False
output: list[ChatMessage] | None = None
output: list[Message] | None = None
async for ev in wf.run("hello sequential", stream=True):
if ev.type == "status" and ev.state == WorkflowRunState.IDLE:
completed = True
@@ -96,7 +96,7 @@ async def test_sequential_agents_append_to_context() -> None:
assert completed
assert output is not None
assert isinstance(output, list)
msgs: list[ChatMessage] = output
msgs: list[Message] = output
assert len(msgs) == 3
assert msgs[0].role == "user" and "hello sequential" in msgs[0].text
assert msgs[1].role == "assistant" and (msgs[1].author_name == "A1" or True)
@@ -112,7 +112,7 @@ async def test_sequential_with_custom_executor_summary() -> None:
wf = SequentialBuilder(participants=[a1, summarizer]).build()
completed = False
output: list[ChatMessage] | None = None
output: list[Message] | None = None
async for ev in wf.run("topic X", stream=True):
if ev.type == "status" and ev.state == WorkflowRunState.IDLE:
completed = True
@@ -123,7 +123,7 @@ async def test_sequential_with_custom_executor_summary() -> None:
assert completed
assert output is not None
msgs: list[ChatMessage] = output
msgs: list[Message] = output
# Expect: [user, A1 reply, summary]
assert len(msgs) == 3
assert msgs[0].role == "user"
@@ -137,7 +137,7 @@ async def test_sequential_checkpoint_resume_round_trip() -> None:
initial_agents = (_EchoAgent(id="agent1", name="A1"), _EchoAgent(id="agent2", name="A2"))
wf = SequentialBuilder(participants=list(initial_agents), checkpoint_storage=storage).build()
baseline_output: list[ChatMessage] | None = None
baseline_output: list[Message] | None = None
async for ev in wf.run("checkpoint sequential", stream=True):
if ev.type == "output":
baseline_output = ev.data # type: ignore[assignment]
@@ -158,7 +158,7 @@ async def test_sequential_checkpoint_resume_round_trip() -> None:
resumed_agents = (_EchoAgent(id="agent1", name="A1"), _EchoAgent(id="agent2", name="A2"))
wf_resume = SequentialBuilder(participants=list(resumed_agents), checkpoint_storage=storage).build()
resumed_output: list[ChatMessage] | None = None
resumed_output: list[Message] | None = None
async for ev in wf_resume.run(checkpoint_id=resume_checkpoint.checkpoint_id, stream=True):
if ev.type == "output":
resumed_output = ev.data # type: ignore[assignment]
@@ -180,7 +180,7 @@ async def test_sequential_checkpoint_runtime_only() -> None:
agents = (_EchoAgent(id="agent1", name="A1"), _EchoAgent(id="agent2", name="A2"))
wf = SequentialBuilder(participants=list(agents)).build()
baseline_output: list[ChatMessage] | None = None
baseline_output: list[Message] | None = None
async for ev in wf.run("runtime checkpoint test", checkpoint_storage=storage, stream=True):
if ev.type == "output":
baseline_output = ev.data # type: ignore[assignment]
@@ -201,7 +201,7 @@ async def test_sequential_checkpoint_runtime_only() -> None:
resumed_agents = (_EchoAgent(id="agent1", name="A1"), _EchoAgent(id="agent2", name="A2"))
wf_resume = SequentialBuilder(participants=list(resumed_agents)).build()
resumed_output: list[ChatMessage] | None = None
resumed_output: list[Message] | None = None
async for ev in wf_resume.run(
checkpoint_id=resume_checkpoint.checkpoint_id, checkpoint_storage=storage, stream=True
):
@@ -231,7 +231,7 @@ async def test_sequential_checkpoint_runtime_overrides_buildtime() -> None:
agents = (_EchoAgent(id="agent1", name="A1"), _EchoAgent(id="agent2", name="A2"))
wf = SequentialBuilder(participants=list(agents), checkpoint_storage=buildtime_storage).build()
baseline_output: list[ChatMessage] | None = None
baseline_output: list[Message] | None = None
async for ev in wf.run("override test", checkpoint_storage=runtime_storage, stream=True):
if ev.type == "output":
baseline_output = ev.data # type: ignore[assignment]