mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
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:
committed by
GitHub
Unverified
parent
a4c9e43afb
commit
0521f5bed8
@@ -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())
|
||||
|
||||
Reference in New Issue
Block a user