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:
co-authored by
Evan Mattson
parent
a4c9e43afb
commit
0521f5bed8
@@ -15,11 +15,11 @@ from typing import TYPE_CHECKING, Any, Generic, TypedDict, cast
|
||||
import httpx
|
||||
from agent_framework import (
|
||||
BaseChatClient,
|
||||
ChatMessage,
|
||||
ChatResponse,
|
||||
ChatResponseUpdate,
|
||||
Content,
|
||||
FunctionTool,
|
||||
Message,
|
||||
ResponseStream,
|
||||
)
|
||||
from agent_framework._middleware import ChatMiddlewareLayer
|
||||
@@ -69,10 +69,10 @@ AGUIChatOptionsT = TypeVar(
|
||||
)
|
||||
|
||||
|
||||
def _apply_server_function_call_unwrap(chat_client: BaseChatClientT) -> BaseChatClientT:
|
||||
def _apply_server_function_call_unwrap(client: BaseChatClientT) -> BaseChatClientT:
|
||||
"""Class decorator that unwraps server-side function calls after tool handling."""
|
||||
|
||||
original_get_response = chat_client.get_response
|
||||
original_get_response = client.get_response
|
||||
|
||||
@wraps(original_get_response)
|
||||
def response_wrapper(
|
||||
@@ -105,8 +105,8 @@ def _apply_server_function_call_unwrap(chat_client: BaseChatClientT) -> BaseChat
|
||||
_unwrap_server_function_call_contents(cast(MutableSequence[Content | dict[str, Any]], update.contents))
|
||||
return update
|
||||
|
||||
chat_client.get_response = response_wrapper # type: ignore[assignment]
|
||||
return chat_client
|
||||
client.get_response = response_wrapper # type: ignore[assignment]
|
||||
return client
|
||||
|
||||
|
||||
@_apply_server_function_call_unwrap
|
||||
@@ -130,8 +130,8 @@ class AGUIChatClient(
|
||||
This client sends exactly the messages it receives to the server. It does NOT
|
||||
automatically maintain conversation history. The server must handle history via thread_id.
|
||||
|
||||
For stateless servers: Use ChatAgent wrapper which will send full message history on each
|
||||
request. However, even with ChatAgent, the server must echo back all context for the
|
||||
For stateless servers: Use Agent wrapper which will send full message history on each
|
||||
request. However, even with Agent, the server must echo back all context for the
|
||||
agent to maintain history across turns.
|
||||
|
||||
Important: Tool Handling (Hybrid Execution - matches .NET)
|
||||
@@ -140,7 +140,7 @@ class AGUIChatClient(
|
||||
3. When LLM calls a client tool, function invocation executes it locally
|
||||
4. Both client and server tools work together (hybrid pattern)
|
||||
|
||||
The wrapping ChatAgent's function invocation handles client tool execution
|
||||
The wrapping Agent's function invocation handles client tool execution
|
||||
automatically when the server's LLM decides to call them.
|
||||
|
||||
Examples:
|
||||
@@ -162,18 +162,18 @@ class AGUIChatClient(
|
||||
metadata={"thread_id": thread_id}
|
||||
)
|
||||
|
||||
Recommended usage with ChatAgent (client manages history):
|
||||
Recommended usage with Agent (client manages history):
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from agent_framework import ChatAgent
|
||||
from agent_framework import Agent
|
||||
from agent_framework.ag_ui import AGUIChatClient
|
||||
|
||||
client = AGUIChatClient(endpoint="http://localhost:8888/")
|
||||
agent = ChatAgent(name="assistant", client=client)
|
||||
agent = Agent(name="assistant", client=client)
|
||||
thread = await agent.get_new_thread()
|
||||
|
||||
# ChatAgent automatically maintains history and sends full context
|
||||
# Agent automatically maintains history and sends full context
|
||||
response = await agent.run("Hello!", thread=thread)
|
||||
response2 = await agent.run("How are you?", thread=thread)
|
||||
|
||||
@@ -282,9 +282,7 @@ class AGUIChatClient(
|
||||
logger = get_logger()
|
||||
logger.debug(f"[AGUIChatClient] Registered server placeholder: {tool_name}")
|
||||
|
||||
def _extract_state_from_messages(
|
||||
self, messages: Sequence[ChatMessage]
|
||||
) -> tuple[list[ChatMessage], dict[str, Any] | None]:
|
||||
def _extract_state_from_messages(self, messages: Sequence[Message]) -> tuple[list[Message], dict[str, Any] | None]:
|
||||
"""Extract state from last message if present.
|
||||
|
||||
Args:
|
||||
@@ -319,11 +317,11 @@ class AGUIChatClient(
|
||||
|
||||
return list(messages), None
|
||||
|
||||
def _convert_messages_to_agui_format(self, messages: list[ChatMessage]) -> list[dict[str, Any]]:
|
||||
def _convert_messages_to_agui_format(self, messages: list[Message]) -> list[dict[str, Any]]:
|
||||
"""Convert Agent Framework messages to AG-UI format.
|
||||
|
||||
Args:
|
||||
messages: List of ChatMessage objects
|
||||
messages: List of Message objects
|
||||
|
||||
Returns:
|
||||
List of AG-UI formatted message dictionaries
|
||||
@@ -353,7 +351,7 @@ class AGUIChatClient(
|
||||
def _inner_get_response(
|
||||
self,
|
||||
*,
|
||||
messages: Sequence[ChatMessage],
|
||||
messages: Sequence[Message],
|
||||
stream: bool = False,
|
||||
options: Mapping[str, Any],
|
||||
**kwargs: Any,
|
||||
@@ -393,7 +391,7 @@ class AGUIChatClient(
|
||||
async def _streaming_impl(
|
||||
self,
|
||||
*,
|
||||
messages: Sequence[ChatMessage],
|
||||
messages: Sequence[Message],
|
||||
options: Mapping[str, Any],
|
||||
**kwargs: Any,
|
||||
) -> AsyncIterable[ChatResponseUpdate]:
|
||||
@@ -415,7 +413,7 @@ class AGUIChatClient(
|
||||
agui_messages = self._convert_messages_to_agui_format(messages_to_send)
|
||||
|
||||
# Send client tools to server so LLM knows about them
|
||||
# Client tools execute via ChatAgent's function invocation wrapper
|
||||
# Client tools execute via Agent's function invocation wrapper
|
||||
agui_tools = convert_tools_to_agui_format(options.get("tools"))
|
||||
|
||||
# Build set of client tool names (matches .NET clientToolSet)
|
||||
|
||||
@@ -9,8 +9,8 @@ import logging
|
||||
from typing import Any, cast
|
||||
|
||||
from agent_framework import (
|
||||
ChatMessage,
|
||||
Content,
|
||||
Message,
|
||||
prepare_function_call_results,
|
||||
)
|
||||
|
||||
@@ -25,9 +25,9 @@ from ._utils import (
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _sanitize_tool_history(messages: list[ChatMessage]) -> list[ChatMessage]:
|
||||
def _sanitize_tool_history(messages: list[Message]) -> list[Message]:
|
||||
"""Normalize tool ordering and inject synthetic results for AG-UI edge cases."""
|
||||
sanitized: list[ChatMessage] = []
|
||||
sanitized: list[Message] = []
|
||||
pending_tool_call_ids: set[str] | None = None
|
||||
pending_confirm_changes_id: str | None = None
|
||||
|
||||
@@ -60,7 +60,7 @@ def _sanitize_tool_history(messages: list[ChatMessage]) -> list[ChatMessage]:
|
||||
]
|
||||
if filtered_contents:
|
||||
# Create a new message without confirm_changes to avoid mutating the input
|
||||
filtered_msg = ChatMessage(role=msg.role, contents=filtered_contents)
|
||||
filtered_msg = Message(role=msg.role, contents=filtered_contents)
|
||||
sanitized.append(filtered_msg)
|
||||
# If no contents left after filtering, don't append anything
|
||||
|
||||
@@ -99,7 +99,7 @@ def _sanitize_tool_history(messages: list[ChatMessage]) -> list[ChatMessage]:
|
||||
|
||||
if pending_confirm_changes_id and approval_accepted is not None:
|
||||
logger.info(f"Injecting synthetic tool result for confirm_changes call_id={pending_confirm_changes_id}")
|
||||
synthetic_result = ChatMessage(
|
||||
synthetic_result = Message(
|
||||
role="tool",
|
||||
contents=[
|
||||
Content.from_function_result(
|
||||
@@ -128,7 +128,7 @@ def _sanitize_tool_history(messages: list[ChatMessage]) -> list[ChatMessage]:
|
||||
logger.info(
|
||||
f"Injecting synthetic tool result for confirm_changes call_id={pending_confirm_changes_id}"
|
||||
)
|
||||
synthetic_result = ChatMessage(
|
||||
synthetic_result = Message(
|
||||
role="tool",
|
||||
contents=[
|
||||
Content.from_function_result(
|
||||
@@ -152,7 +152,7 @@ def _sanitize_tool_history(messages: list[ChatMessage]) -> list[ChatMessage]:
|
||||
)
|
||||
for pending_call_id in pending_tool_call_ids:
|
||||
logger.info(f"Injecting synthetic tool result for pending call_id={pending_call_id}")
|
||||
synthetic_result = ChatMessage(
|
||||
synthetic_result = Message(
|
||||
role="tool",
|
||||
contents=[
|
||||
Content.from_function_result(
|
||||
@@ -196,10 +196,10 @@ def _sanitize_tool_history(messages: list[ChatMessage]) -> list[ChatMessage]:
|
||||
return sanitized
|
||||
|
||||
|
||||
def _deduplicate_messages(messages: list[ChatMessage]) -> list[ChatMessage]:
|
||||
def _deduplicate_messages(messages: list[Message]) -> list[Message]:
|
||||
"""Remove duplicate messages while preserving order."""
|
||||
seen_keys: dict[Any, int] = {}
|
||||
unique_messages: list[ChatMessage] = []
|
||||
unique_messages: list[Message] = []
|
||||
|
||||
for idx, msg in enumerate(messages):
|
||||
role_value = get_role_value(msg)
|
||||
@@ -256,7 +256,7 @@ def _deduplicate_messages(messages: list[ChatMessage]) -> list[ChatMessage]:
|
||||
|
||||
def normalize_agui_input_messages(
|
||||
messages: list[dict[str, Any]],
|
||||
) -> tuple[list[ChatMessage], list[dict[str, Any]]]:
|
||||
) -> tuple[list[Message], list[dict[str, Any]]]:
|
||||
"""Normalize raw AG-UI messages into provider and snapshot formats."""
|
||||
provider_messages = agui_messages_to_agent_framework(messages)
|
||||
provider_messages = _sanitize_tool_history(provider_messages)
|
||||
@@ -265,14 +265,14 @@ def normalize_agui_input_messages(
|
||||
return provider_messages, snapshot_messages
|
||||
|
||||
|
||||
def agui_messages_to_agent_framework(messages: list[dict[str, Any]]) -> list[ChatMessage]:
|
||||
def agui_messages_to_agent_framework(messages: list[dict[str, Any]]) -> list[Message]:
|
||||
"""Convert AG-UI messages to Agent Framework format.
|
||||
|
||||
Args:
|
||||
messages: List of AG-UI messages
|
||||
|
||||
Returns:
|
||||
List of Agent Framework ChatMessage objects
|
||||
List of Agent Framework Message objects
|
||||
"""
|
||||
|
||||
def _update_tool_call_arguments(
|
||||
@@ -367,7 +367,7 @@ def agui_messages_to_agent_framework(messages: list[dict[str, Any]]) -> list[Cha
|
||||
allowed_keys = set(original_args.keys())
|
||||
return {key: value for key, value in modified_args.items() if key in allowed_keys}
|
||||
|
||||
result: list[ChatMessage] = []
|
||||
result: list[Message] = []
|
||||
for msg in messages:
|
||||
# Handle standard tool result messages early (role="tool") to preserve provider invariants
|
||||
# This path maps AG‑UI tool messages to function_result content with the correct tool_call_id
|
||||
@@ -480,7 +480,7 @@ def agui_messages_to_agent_framework(messages: list[dict[str, Any]]) -> list[Cha
|
||||
merged_args["steps"] = merged_steps
|
||||
state_args = merged_args
|
||||
|
||||
# Update the ChatMessage tool call with only enabled steps (for LLM context).
|
||||
# Update the Message tool call with only enabled steps (for LLM context).
|
||||
# The LLM should only see the steps that were actually approved/executed.
|
||||
updated_args_for_llm = (
|
||||
json.dumps(filtered_args)
|
||||
@@ -510,14 +510,14 @@ def agui_messages_to_agent_framework(messages: list[dict[str, Any]]) -> list[Cha
|
||||
function_call=func_call_for_approval,
|
||||
additional_properties={"ag_ui_state_args": state_args} if state_args else None,
|
||||
)
|
||||
chat_msg = ChatMessage(
|
||||
chat_msg = Message(
|
||||
role="user",
|
||||
contents=[approval_response],
|
||||
)
|
||||
else:
|
||||
# No matching function call found - this is likely a confirm_changes approval
|
||||
# Keep the old behavior for backwards compatibility
|
||||
chat_msg = ChatMessage(
|
||||
chat_msg = Message(
|
||||
role="user",
|
||||
contents=[Content.from_text(text=approval_payload_text)],
|
||||
additional_properties={"is_tool_result": True, "tool_call_id": str(tool_call_id or "")},
|
||||
@@ -537,7 +537,7 @@ def agui_messages_to_agent_framework(messages: list[dict[str, Any]]) -> list[Cha
|
||||
func_result = result_content
|
||||
else:
|
||||
func_result = str(result_content)
|
||||
chat_msg = ChatMessage(
|
||||
chat_msg = Message(
|
||||
role="tool",
|
||||
contents=[Content.from_function_result(call_id=str(tool_call_id), result=func_result)],
|
||||
)
|
||||
@@ -553,7 +553,7 @@ def agui_messages_to_agent_framework(messages: list[dict[str, Any]]) -> list[Cha
|
||||
tool_call_id = msg.get("toolCallId") or msg.get("tool_call_id") or msg.get("actionExecutionId", "")
|
||||
result_content = msg.get("result", msg.get("content", ""))
|
||||
|
||||
chat_msg = ChatMessage(
|
||||
chat_msg = Message(
|
||||
role="tool",
|
||||
contents=[Content.from_function_result(call_id=str(tool_call_id), result=result_content)],
|
||||
)
|
||||
@@ -592,7 +592,7 @@ def agui_messages_to_agent_framework(messages: list[dict[str, Any]]) -> list[Cha
|
||||
arguments=arguments,
|
||||
)
|
||||
)
|
||||
chat_msg = ChatMessage(role="assistant", contents=contents)
|
||||
chat_msg = Message(role="assistant", contents=contents)
|
||||
if "id" in msg:
|
||||
chat_msg.message_id = msg["id"]
|
||||
result.append(chat_msg)
|
||||
@@ -622,14 +622,14 @@ def agui_messages_to_agent_framework(messages: list[dict[str, Any]]) -> list[Cha
|
||||
)
|
||||
approval_contents.append(approval_response)
|
||||
|
||||
chat_msg = ChatMessage(role=role, contents=approval_contents) # type: ignore[call-overload]
|
||||
chat_msg = Message(role=role, contents=approval_contents) # type: ignore[call-overload]
|
||||
else:
|
||||
# Regular text message
|
||||
content = msg.get("content", "")
|
||||
if isinstance(content, str):
|
||||
chat_msg = ChatMessage(role=role, contents=[Content.from_text(text=content)]) # type: ignore[call-overload]
|
||||
chat_msg = Message(role=role, contents=[Content.from_text(text=content)]) # type: ignore[call-overload]
|
||||
else:
|
||||
chat_msg = ChatMessage(role=role, contents=[Content.from_text(text=str(content))]) # type: ignore[call-overload]
|
||||
chat_msg = Message(role=role, contents=[Content.from_text(text=str(content))]) # type: ignore[call-overload]
|
||||
|
||||
if "id" in msg:
|
||||
chat_msg.message_id = msg["id"]
|
||||
@@ -639,11 +639,11 @@ def agui_messages_to_agent_framework(messages: list[dict[str, Any]]) -> list[Cha
|
||||
return result
|
||||
|
||||
|
||||
def agent_framework_messages_to_agui(messages: list[ChatMessage] | list[dict[str, Any]]) -> list[dict[str, Any]]:
|
||||
def agent_framework_messages_to_agui(messages: list[Message] | list[dict[str, Any]]) -> list[dict[str, Any]]:
|
||||
"""Convert Agent Framework messages to AG-UI format.
|
||||
|
||||
Args:
|
||||
messages: List of Agent Framework ChatMessage objects or AG-UI dicts (already converted)
|
||||
messages: List of Agent Framework Message objects or AG-UI dicts (already converted)
|
||||
|
||||
Returns:
|
||||
List of AG-UI message dictionaries
|
||||
@@ -672,7 +672,7 @@ def agent_framework_messages_to_agui(messages: list[ChatMessage] | list[dict[str
|
||||
result.append(normalized_msg)
|
||||
continue
|
||||
|
||||
# Convert ChatMessage to AG-UI format
|
||||
# Convert Message to AG-UI format
|
||||
role_value: str = msg.role if hasattr(msg.role, "value") else msg.role # type: ignore[assignment]
|
||||
role = FRAMEWORK_TO_AGUI_ROLE.get(role_value, "user")
|
||||
|
||||
|
||||
@@ -13,8 +13,8 @@ import logging
|
||||
from typing import Any
|
||||
|
||||
from agent_framework import (
|
||||
ChatMessage,
|
||||
Content,
|
||||
Message,
|
||||
)
|
||||
|
||||
from .._utils import get_role_value
|
||||
@@ -22,7 +22,7 @@ from .._utils import get_role_value
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def pending_tool_call_ids(messages: list[ChatMessage]) -> set[str]:
|
||||
def pending_tool_call_ids(messages: list[Message]) -> set[str]:
|
||||
"""Get IDs of tool calls without corresponding results.
|
||||
|
||||
Args:
|
||||
@@ -42,7 +42,7 @@ def pending_tool_call_ids(messages: list[ChatMessage]) -> set[str]:
|
||||
return pending_ids - resolved_ids
|
||||
|
||||
|
||||
def is_state_context_message(message: ChatMessage) -> bool:
|
||||
def is_state_context_message(message: Message) -> bool:
|
||||
"""Check if a message is a state context system message.
|
||||
|
||||
Args:
|
||||
@@ -178,7 +178,7 @@ def build_safe_metadata(thread_metadata: dict[str, Any] | None) -> dict[str, Any
|
||||
return safe_metadata
|
||||
|
||||
|
||||
def latest_approval_response(messages: list[ChatMessage]) -> Content | None:
|
||||
def latest_approval_response(messages: list[Message]) -> Content | None:
|
||||
"""Get the latest approval response from messages.
|
||||
|
||||
Args:
|
||||
|
||||
@@ -39,7 +39,7 @@ def collect_server_tools(agent: SupportsAgentRun) -> list[Any]:
|
||||
functions need to be included for tool execution during approval flows.
|
||||
|
||||
Args:
|
||||
agent: Agent instance to collect tools from. Works with ChatAgent
|
||||
agent: Agent instance to collect tools from. Works with Agent
|
||||
or any agent with default_options and optional mcp_tools attributes.
|
||||
|
||||
Returns:
|
||||
@@ -53,7 +53,7 @@ def collect_server_tools(agent: SupportsAgentRun) -> list[Any]:
|
||||
tools_from_agent = default_options.get("tools") if isinstance(default_options, dict) else None
|
||||
server_tools = list(tools_from_agent) if tools_from_agent else []
|
||||
|
||||
# Include functions from connected MCP tools (only available on ChatAgent)
|
||||
# Include functions from connected MCP tools (only available on Agent)
|
||||
mcp_tools = getattr(agent, "mcp_tools", None)
|
||||
if mcp_tools:
|
||||
server_tools.extend(_collect_mcp_tool_functions(mcp_tools))
|
||||
@@ -70,19 +70,19 @@ def register_additional_client_tools(agent: SupportsAgentRun, client_tools: list
|
||||
"""Register client tools as additional declaration-only tools to avoid server execution.
|
||||
|
||||
Args:
|
||||
agent: Agent instance to register tools on. Works with ChatAgent
|
||||
or any agent with a chat_client attribute.
|
||||
agent: Agent instance to register tools on. Works with Agent
|
||||
or any agent with a client attribute.
|
||||
client_tools: List of client tools to register.
|
||||
"""
|
||||
if not client_tools:
|
||||
return
|
||||
|
||||
chat_client = getattr(agent, "chat_client", None)
|
||||
if chat_client is None:
|
||||
client = getattr(agent, "client", None)
|
||||
if client is None:
|
||||
return
|
||||
|
||||
if isinstance(chat_client, BaseChatClient) and chat_client.function_invocation_configuration is not None: # type: ignore[attr-defined]
|
||||
chat_client.function_invocation_configuration["additional_tools"] = client_tools # type: ignore[attr-defined]
|
||||
if isinstance(client, BaseChatClient) and client.function_invocation_configuration is not None: # type: ignore[attr-defined]
|
||||
client.function_invocation_configuration["additional_tools"] = client_tools # type: ignore[attr-defined]
|
||||
logger.debug(f"[TOOLS] Registered {len(client_tools)} client tools as additional_tools (declaration-only)")
|
||||
|
||||
|
||||
|
||||
@@ -28,8 +28,8 @@ from ag_ui.core import (
|
||||
)
|
||||
from agent_framework import (
|
||||
AgentThread,
|
||||
ChatMessage,
|
||||
Content,
|
||||
Message,
|
||||
SupportsAgentRun,
|
||||
prepare_function_call_results,
|
||||
)
|
||||
@@ -195,7 +195,7 @@ class FlowState:
|
||||
def _create_state_context_message(
|
||||
current_state: dict[str, Any],
|
||||
state_schema: dict[str, Any],
|
||||
) -> ChatMessage | None:
|
||||
) -> Message | None:
|
||||
"""Create a system message with current state context.
|
||||
|
||||
This injects the current state into the conversation so the model
|
||||
@@ -206,13 +206,13 @@ def _create_state_context_message(
|
||||
state_schema: The state schema (used to determine if injection is needed)
|
||||
|
||||
Returns:
|
||||
ChatMessage with state context, or None if not needed
|
||||
Message with state context, or None if not needed
|
||||
"""
|
||||
if not current_state or not state_schema:
|
||||
return None
|
||||
|
||||
state_json = json.dumps(current_state, indent=2)
|
||||
return ChatMessage(
|
||||
return Message(
|
||||
role="system",
|
||||
contents=[
|
||||
Content.from_text(
|
||||
@@ -229,10 +229,10 @@ def _create_state_context_message(
|
||||
|
||||
|
||||
def _inject_state_context(
|
||||
messages: list[ChatMessage],
|
||||
messages: list[Message],
|
||||
current_state: dict[str, Any],
|
||||
state_schema: dict[str, Any],
|
||||
) -> list[ChatMessage]:
|
||||
) -> list[Message]:
|
||||
"""Inject state context message into messages if appropriate.
|
||||
|
||||
The state context is injected before the last user message to give
|
||||
@@ -592,7 +592,7 @@ async def _resolve_approval_responses(
|
||||
Args:
|
||||
messages: List of messages (will be modified in place)
|
||||
tools: List of available tools
|
||||
agent: The agent instance (to get chat_client and config)
|
||||
agent: The agent instance (to get client and config)
|
||||
run_kwargs: Kwargs for tool execution
|
||||
"""
|
||||
fcc_todo = _collect_approval_responses(messages)
|
||||
@@ -605,12 +605,10 @@ async def _resolve_approval_responses(
|
||||
|
||||
# Execute approved tool calls
|
||||
if approved_responses and tools:
|
||||
chat_client = getattr(agent, "chat_client", None)
|
||||
config = normalize_function_invocation_configuration(
|
||||
getattr(chat_client, "function_invocation_configuration", None)
|
||||
)
|
||||
client = getattr(agent, "client", None)
|
||||
config = normalize_function_invocation_configuration(getattr(client, "function_invocation_configuration", None))
|
||||
middleware_pipeline = FunctionMiddlewarePipeline(
|
||||
*getattr(chat_client, "function_middleware", ()),
|
||||
*getattr(client, "function_middleware", ()),
|
||||
*run_kwargs.get("middleware", ()),
|
||||
)
|
||||
# Filter out AG-UI-specific kwargs that should not be passed to tool execution
|
||||
@@ -672,7 +670,7 @@ def _convert_approval_results_to_tool_messages(messages: list[Any]) -> None:
|
||||
This modifies the messages list in place.
|
||||
|
||||
Args:
|
||||
messages: List of ChatMessage objects to process
|
||||
messages: List of Message objects to process
|
||||
"""
|
||||
result: list[Any] = []
|
||||
|
||||
@@ -694,11 +692,11 @@ def _convert_approval_results_to_tool_messages(messages: list[Any]) -> None:
|
||||
|
||||
# Tool messages first (right after the preceding assistant message per OpenAI requirements)
|
||||
for func_result in function_results:
|
||||
result.append(ChatMessage(role="tool", contents=[func_result]))
|
||||
result.append(Message(role="tool", contents=[func_result]))
|
||||
|
||||
# Then user message with remaining content (if any)
|
||||
if other_contents:
|
||||
result.append(ChatMessage(role=msg.role, contents=other_contents))
|
||||
result.append(Message(role=msg.role, contents=other_contents))
|
||||
|
||||
messages[:] = result
|
||||
|
||||
@@ -793,9 +791,9 @@ async def run_agent_stream(
|
||||
# Check for structured output mode (skip text content)
|
||||
skip_text = False
|
||||
response_format = None
|
||||
from agent_framework import ChatAgent
|
||||
from agent_framework import Agent
|
||||
|
||||
if isinstance(agent, ChatAgent):
|
||||
if isinstance(agent, Agent):
|
||||
response_format = agent.default_options.get("response_format")
|
||||
skip_text = response_format is not None
|
||||
|
||||
|
||||
Reference in New Issue
Block a user