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
@@ -9,14 +9,14 @@ from typing import Any, Literal, cast
|
||||
|
||||
import yaml
|
||||
from agent_framework import (
|
||||
ChatAgent,
|
||||
ChatClientProtocol,
|
||||
Agent,
|
||||
Content,
|
||||
HostedCodeInterpreterTool,
|
||||
HostedFileSearchTool,
|
||||
HostedMCPSpecificApproval,
|
||||
HostedMCPTool,
|
||||
HostedWebSearchTool,
|
||||
SupportsChatGetResponse,
|
||||
ToolProtocol,
|
||||
)
|
||||
from agent_framework import (
|
||||
@@ -124,10 +124,10 @@ class ProviderLookupError(DeclarativeLoaderError):
|
||||
|
||||
|
||||
class AgentFactory:
|
||||
"""Factory for creating ChatAgent instances from declarative YAML definitions.
|
||||
"""Factory for creating Agent instances from declarative YAML definitions.
|
||||
|
||||
AgentFactory parses YAML agent definitions (PromptAgent kind) and creates
|
||||
configured ChatAgent instances with the appropriate chat client, tools,
|
||||
configured Agent instances with the appropriate chat client, tools,
|
||||
and response format.
|
||||
|
||||
Examples:
|
||||
@@ -150,7 +150,7 @@ class AgentFactory:
|
||||
|
||||
# With pre-configured chat client
|
||||
client = AzureOpenAIChatClient()
|
||||
factory = AgentFactory(chat_client=client)
|
||||
factory = AgentFactory(client=client)
|
||||
agent = factory.create_agent_from_yaml_path("agent.yaml")
|
||||
|
||||
.. code-block:: python
|
||||
@@ -174,7 +174,7 @@ class AgentFactory:
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
chat_client: ChatClientProtocol | None = None,
|
||||
client: SupportsChatGetResponse | None = None,
|
||||
bindings: Mapping[str, Any] | None = None,
|
||||
connections: Mapping[str, Any] | None = None,
|
||||
client_kwargs: Mapping[str, Any] | None = None,
|
||||
@@ -187,8 +187,8 @@ class AgentFactory:
|
||||
"""Create the agent factory.
|
||||
|
||||
Args:
|
||||
chat_client: An optional ChatClientProtocol instance to use as a dependency.
|
||||
This will be passed to the ChatAgent that gets created.
|
||||
client: An optional SupportsChatGetResponse instance to use as a dependency.
|
||||
This will be passed to the Agent that gets created.
|
||||
If you need to create multiple agents with different chat clients,
|
||||
do not pass this and instead provide the chat client in the YAML definition.
|
||||
bindings: An optional dictionary of bindings to use when creating agents.
|
||||
@@ -210,9 +210,9 @@ class AgentFactory:
|
||||
|
||||
Here, "Provider.ApiType" is the lookup key used when both provider and apiType are specified in the
|
||||
model, "Provider" is also allowed.
|
||||
Package refers to which model needs to be imported, Name is the class name of the ChatClientProtocol
|
||||
implementation, and model_id_field is the name of the field in the constructor
|
||||
that accepts the model.id value.
|
||||
Package refers to which model needs to be imported, Name is the class name of the
|
||||
SupportsChatGetResponse implementation, and model_id_field is the name of the field in the
|
||||
constructor that accepts the model.id value.
|
||||
default_provider: The default provider used when model.provider is not specified,
|
||||
default is "AzureAIClient".
|
||||
safe_mode: Whether to run in safe mode, default is True.
|
||||
@@ -241,7 +241,7 @@ class AgentFactory:
|
||||
# With shared chat client
|
||||
client = AzureOpenAIChatClient()
|
||||
factory = AgentFactory(
|
||||
chat_client=client,
|
||||
client=client,
|
||||
env_file_path=".env",
|
||||
)
|
||||
|
||||
@@ -260,7 +260,7 @@ class AgentFactory:
|
||||
},
|
||||
)
|
||||
"""
|
||||
self.chat_client = chat_client
|
||||
self.client = client
|
||||
self.bindings = bindings
|
||||
self.connections = connections
|
||||
self.client_kwargs = client_kwargs or {}
|
||||
@@ -269,8 +269,8 @@ class AgentFactory:
|
||||
self.safe_mode = safe_mode
|
||||
load_dotenv(dotenv_path=env_file_path, encoding=env_file_encoding)
|
||||
|
||||
def create_agent_from_yaml_path(self, yaml_path: str | Path) -> ChatAgent:
|
||||
"""Create a ChatAgent from a YAML file path.
|
||||
def create_agent_from_yaml_path(self, yaml_path: str | Path) -> Agent:
|
||||
"""Create a Agent from a YAML file path.
|
||||
|
||||
This method does the following things:
|
||||
|
||||
@@ -278,13 +278,13 @@ class AgentFactory:
|
||||
2. Validates that the loaded object is a PromptAgent.
|
||||
3. Creates the appropriate ChatClient based on the model provider and apiType.
|
||||
4. Parses the tools, options, and response format from the PromptAgent.
|
||||
5. Creates and returns a ChatAgent instance with the configured properties.
|
||||
5. Creates and returns a Agent instance with the configured properties.
|
||||
|
||||
Args:
|
||||
yaml_path: Path to the YAML file representation of a PromptAgent.
|
||||
|
||||
Returns:
|
||||
The ``ChatAgent`` instance created from the YAML file.
|
||||
The ``Agent`` instance created from the YAML file.
|
||||
|
||||
Raises:
|
||||
DeclarativeLoaderError: If the YAML does not represent a PromptAgent.
|
||||
@@ -323,8 +323,8 @@ class AgentFactory:
|
||||
yaml_str = f.read()
|
||||
return self.create_agent_from_yaml(yaml_str)
|
||||
|
||||
def create_agent_from_yaml(self, yaml_str: str) -> ChatAgent:
|
||||
"""Create a ChatAgent from a YAML string.
|
||||
def create_agent_from_yaml(self, yaml_str: str) -> Agent:
|
||||
"""Create a Agent from a YAML string.
|
||||
|
||||
This method does the following things:
|
||||
|
||||
@@ -332,13 +332,13 @@ class AgentFactory:
|
||||
2. Validates that the loaded object is a PromptAgent.
|
||||
3. Creates the appropriate ChatClient based on the model provider and apiType.
|
||||
4. Parses the tools, options, and response format from the PromptAgent.
|
||||
5. Creates and returns a ChatAgent instance with the configured properties.
|
||||
5. Creates and returns a Agent instance with the configured properties.
|
||||
|
||||
Args:
|
||||
yaml_str: YAML string representation of a PromptAgent.
|
||||
|
||||
Returns:
|
||||
The ``ChatAgent`` instance created from the YAML string.
|
||||
The ``Agent`` instance created from the YAML string.
|
||||
|
||||
Raises:
|
||||
DeclarativeLoaderError: If the YAML does not represent a PromptAgent.
|
||||
@@ -396,8 +396,8 @@ class AgentFactory:
|
||||
"""
|
||||
return self.create_agent_from_dict(yaml.safe_load(yaml_str))
|
||||
|
||||
def create_agent_from_dict(self, agent_def: dict[str, Any]) -> ChatAgent:
|
||||
"""Create a ChatAgent from a dictionary definition.
|
||||
def create_agent_from_dict(self, agent_def: dict[str, Any]) -> Agent:
|
||||
"""Create a Agent from a dictionary definition.
|
||||
|
||||
This method does the following things:
|
||||
|
||||
@@ -405,13 +405,13 @@ class AgentFactory:
|
||||
2. Validates that the loaded object is a PromptAgent.
|
||||
3. Creates the appropriate ChatClient based on the model provider and apiType.
|
||||
4. Parses the tools, options, and response format from the PromptAgent.
|
||||
5. Creates and returns a ChatAgent instance with the configured properties.
|
||||
5. Creates and returns a Agent instance with the configured properties.
|
||||
|
||||
Args:
|
||||
agent_def: Dictionary representation of a PromptAgent.
|
||||
|
||||
Returns:
|
||||
The `ChatAgent` instance created from the dictionary.
|
||||
The `Agent` instance created from the dictionary.
|
||||
|
||||
Raises:
|
||||
DeclarativeLoaderError: If the dictionary does not represent a PromptAgent.
|
||||
@@ -454,16 +454,16 @@ class AgentFactory:
|
||||
if output_schema := prompt_agent.outputSchema:
|
||||
chat_options["response_format"] = _create_model_from_json_schema("agent", output_schema.to_json_schema())
|
||||
# Step 3: Create the agent instance
|
||||
return ChatAgent(
|
||||
chat_client=client,
|
||||
return Agent(
|
||||
client=client,
|
||||
name=prompt_agent.name,
|
||||
description=prompt_agent.description,
|
||||
instructions=prompt_agent.instructions,
|
||||
**chat_options,
|
||||
)
|
||||
|
||||
async def create_agent_from_yaml_path_async(self, yaml_path: str | Path) -> ChatAgent:
|
||||
"""Async version: Create a ChatAgent from a YAML file path.
|
||||
async def create_agent_from_yaml_path_async(self, yaml_path: str | Path) -> Agent:
|
||||
"""Async version: Create a Agent from a YAML file path.
|
||||
|
||||
Use this method when the provider requires async initialization, such as
|
||||
AzureAI.ProjectProvider which creates agents on the Azure AI Agent Service.
|
||||
@@ -472,7 +472,7 @@ class AgentFactory:
|
||||
yaml_path: Path to the YAML file representation of a PromptAgent.
|
||||
|
||||
Returns:
|
||||
The ``ChatAgent`` instance created from the YAML file.
|
||||
The ``Agent`` instance created from the YAML file.
|
||||
|
||||
Examples:
|
||||
.. code-block:: python
|
||||
@@ -492,8 +492,8 @@ class AgentFactory:
|
||||
yaml_str = yaml_path.read_text()
|
||||
return await self.create_agent_from_yaml_async(yaml_str)
|
||||
|
||||
async def create_agent_from_yaml_async(self, yaml_str: str) -> ChatAgent:
|
||||
"""Async version: Create a ChatAgent from a YAML string.
|
||||
async def create_agent_from_yaml_async(self, yaml_str: str) -> Agent:
|
||||
"""Async version: Create a Agent from a YAML string.
|
||||
|
||||
Use this method when the provider requires async initialization, such as
|
||||
AzureAI.ProjectProvider which creates agents on the Azure AI Agent Service.
|
||||
@@ -502,7 +502,7 @@ class AgentFactory:
|
||||
yaml_str: YAML string representation of a PromptAgent.
|
||||
|
||||
Returns:
|
||||
The ``ChatAgent`` instance created from the YAML string.
|
||||
The ``Agent`` instance created from the YAML string.
|
||||
|
||||
Examples:
|
||||
.. code-block:: python
|
||||
@@ -523,8 +523,8 @@ class AgentFactory:
|
||||
"""
|
||||
return await self.create_agent_from_dict_async(yaml.safe_load(yaml_str))
|
||||
|
||||
async def create_agent_from_dict_async(self, agent_def: dict[str, Any]) -> ChatAgent:
|
||||
"""Async version: Create a ChatAgent from a dictionary definition.
|
||||
async def create_agent_from_dict_async(self, agent_def: dict[str, Any]) -> Agent:
|
||||
"""Async version: Create a Agent from a dictionary definition.
|
||||
|
||||
Use this method when the provider requires async initialization, such as
|
||||
AzureAI.ProjectProvider which creates agents on the Azure AI Agent Service.
|
||||
@@ -533,7 +533,7 @@ class AgentFactory:
|
||||
agent_def: Dictionary representation of a PromptAgent.
|
||||
|
||||
Returns:
|
||||
The ``ChatAgent`` instance created from the dictionary.
|
||||
The ``Agent`` instance created from the dictionary.
|
||||
|
||||
Examples:
|
||||
.. code-block:: python
|
||||
@@ -571,20 +571,20 @@ class AgentFactory:
|
||||
chat_options["tools"] = tools
|
||||
if output_schema := prompt_agent.outputSchema:
|
||||
chat_options["response_format"] = _create_model_from_json_schema("agent", output_schema.to_json_schema())
|
||||
return ChatAgent(
|
||||
chat_client=client,
|
||||
return Agent(
|
||||
client=client,
|
||||
name=prompt_agent.name,
|
||||
description=prompt_agent.description,
|
||||
instructions=prompt_agent.instructions,
|
||||
**chat_options,
|
||||
)
|
||||
|
||||
async def _create_agent_with_provider(self, prompt_agent: PromptAgent, mapping: ProviderTypeMapping) -> ChatAgent:
|
||||
"""Create a ChatAgent using AzureAIProjectAgentProvider.
|
||||
async def _create_agent_with_provider(self, prompt_agent: PromptAgent, mapping: ProviderTypeMapping) -> Agent:
|
||||
"""Create a Agent using AzureAIProjectAgentProvider.
|
||||
|
||||
This method handles the special case where we use a provider that creates
|
||||
agents on a remote service (like Azure AI Agent Service) and returns
|
||||
ChatAgent instances directly.
|
||||
Agent instances directly.
|
||||
"""
|
||||
# Import the provider class
|
||||
module_name = mapping["package"]
|
||||
@@ -618,9 +618,9 @@ class AgentFactory:
|
||||
response_format = _create_model_from_json_schema("agent", prompt_agent.outputSchema.to_json_schema())
|
||||
|
||||
# Create the agent using the provider
|
||||
# The provider's create_agent returns a ChatAgent directly
|
||||
# The provider's create_agent returns a Agent directly
|
||||
return cast(
|
||||
ChatAgent,
|
||||
Agent,
|
||||
await provider.create_agent(
|
||||
name=prompt_agent.name,
|
||||
model=prompt_agent.model.id if prompt_agent.model else None,
|
||||
@@ -631,12 +631,12 @@ class AgentFactory:
|
||||
),
|
||||
)
|
||||
|
||||
def _get_client(self, prompt_agent: PromptAgent) -> ChatClientProtocol:
|
||||
"""Create the ChatClientProtocol instance based on the PromptAgent model."""
|
||||
def _get_client(self, prompt_agent: PromptAgent) -> SupportsChatGetResponse:
|
||||
"""Create the SupportsChatGetResponse instance based on the PromptAgent model."""
|
||||
if not prompt_agent.model:
|
||||
# if no model is defined, use the supplied chat_client
|
||||
if self.chat_client:
|
||||
return self.chat_client
|
||||
# if no model is defined, use the supplied client
|
||||
if self.client:
|
||||
return self.client
|
||||
raise DeclarativeLoaderError(
|
||||
"ChatClient must be provided to create agent from PromptAgent, "
|
||||
"alternatively define a model in the PromptAgent."
|
||||
@@ -670,9 +670,9 @@ class AgentFactory:
|
||||
|
||||
# Any client we create, needs a model.id
|
||||
if not prompt_agent.model.id:
|
||||
# if prompt_agent.model is defined, but no id, use the supplied chat_client
|
||||
if self.chat_client:
|
||||
return self.chat_client
|
||||
# if prompt_agent.model is defined, but no id, use the supplied client
|
||||
if self.client:
|
||||
return self.client
|
||||
# or raise, since we cannot create a client without model id
|
||||
raise DeclarativeLoaderError(
|
||||
"ChatClient must be provided to create agent from PromptAgent, or define model.id in the PromptAgent."
|
||||
|
||||
+16
-16
@@ -14,7 +14,7 @@ from collections.abc import AsyncGenerator
|
||||
from typing import Any, cast
|
||||
|
||||
from agent_framework import get_logger
|
||||
from agent_framework._types import AgentResponse, ChatMessage
|
||||
from agent_framework._types import AgentResponse, Message
|
||||
|
||||
from ._handlers import (
|
||||
ActionContext,
|
||||
@@ -162,7 +162,7 @@ def _extract_json_from_response(text: str) -> Any:
|
||||
raise json.JSONDecodeError("No valid JSON found in response", text, 0)
|
||||
|
||||
|
||||
def _build_messages_from_state(ctx: ActionContext) -> list[ChatMessage]:
|
||||
def _build_messages_from_state(ctx: ActionContext) -> list[Message]:
|
||||
"""Build the message list to send to an agent.
|
||||
|
||||
This collects messages from:
|
||||
@@ -174,9 +174,9 @@ def _build_messages_from_state(ctx: ActionContext) -> list[ChatMessage]:
|
||||
ctx: The action context
|
||||
|
||||
Returns:
|
||||
List of ChatMessage objects to send to the agent
|
||||
List of Message objects to send to the agent
|
||||
"""
|
||||
messages: list[ChatMessage] = []
|
||||
messages: list[Message] = []
|
||||
|
||||
# Get conversation history
|
||||
history = ctx.state.get("conversation.messages", [])
|
||||
@@ -287,23 +287,23 @@ async def handle_invoke_azure_agent(ctx: ActionContext) -> AsyncGenerator[Workfl
|
||||
evaluated_input = ctx.state.eval_if_expression(input_messages)
|
||||
if evaluated_input:
|
||||
if isinstance(evaluated_input, str):
|
||||
messages.append(ChatMessage(role="user", text=evaluated_input))
|
||||
messages.append(Message(role="user", text=evaluated_input))
|
||||
elif isinstance(evaluated_input, list):
|
||||
for msg_item in evaluated_input: # type: ignore
|
||||
if isinstance(msg_item, str):
|
||||
messages.append(ChatMessage(role="user", text=msg_item))
|
||||
elif isinstance(msg_item, ChatMessage):
|
||||
messages.append(Message(role="user", text=msg_item))
|
||||
elif isinstance(msg_item, Message):
|
||||
messages.append(msg_item)
|
||||
elif isinstance(msg_item, dict) and "content" in msg_item:
|
||||
item_dict = cast(dict[str, Any], msg_item)
|
||||
role: str = str(item_dict.get("role", "user"))
|
||||
content: str = str(item_dict.get("content", ""))
|
||||
if role == "user":
|
||||
messages.append(ChatMessage(role="user", text=content))
|
||||
messages.append(Message(role="user", text=content))
|
||||
elif role == "assistant":
|
||||
messages.append(ChatMessage(role="assistant", text=content))
|
||||
messages.append(Message(role="assistant", text=content))
|
||||
elif role == "system":
|
||||
messages.append(ChatMessage(role="system", text=content))
|
||||
messages.append(Message(role="system", text=content))
|
||||
|
||||
# Evaluate and include input arguments
|
||||
evaluated_args: dict[str, Any] = {}
|
||||
@@ -365,7 +365,7 @@ async def handle_invoke_azure_agent(ctx: ActionContext) -> AsyncGenerator[Workfl
|
||||
|
||||
# Add to conversation history
|
||||
if text:
|
||||
ctx.state.add_conversation_message(ChatMessage(role="assistant", text=text))
|
||||
ctx.state.add_conversation_message(Message(role="assistant", text=text))
|
||||
|
||||
# Store in output variables (.NET style)
|
||||
if output_messages_var:
|
||||
@@ -418,7 +418,7 @@ async def handle_invoke_azure_agent(ctx: ActionContext) -> AsyncGenerator[Workfl
|
||||
|
||||
# Add to conversation history
|
||||
if text:
|
||||
ctx.state.add_conversation_message(ChatMessage(role="assistant", text=text))
|
||||
ctx.state.add_conversation_message(Message(role="assistant", text=text))
|
||||
|
||||
# Store in output variables (.NET style)
|
||||
if output_messages_var:
|
||||
@@ -564,8 +564,8 @@ async def handle_invoke_prompt_agent(ctx: ActionContext) -> AsyncGenerator[Workf
|
||||
# Add input as user message if provided
|
||||
if input_value:
|
||||
if isinstance(input_value, str):
|
||||
messages.append(ChatMessage(role="user", text=input_value))
|
||||
elif isinstance(input_value, ChatMessage):
|
||||
messages.append(Message(role="user", text=input_value))
|
||||
elif isinstance(input_value, Message):
|
||||
messages.append(input_value)
|
||||
|
||||
logger.debug(f"InvokePromptAgent: calling '{agent_name}' with {len(messages)} messages")
|
||||
@@ -594,7 +594,7 @@ async def handle_invoke_prompt_agent(ctx: ActionContext) -> AsyncGenerator[Workf
|
||||
ctx.state.set_agent_result(text=text, messages=response_messages)
|
||||
|
||||
if text:
|
||||
ctx.state.add_conversation_message(ChatMessage(role="assistant", text=text))
|
||||
ctx.state.add_conversation_message(Message(role="assistant", text=text))
|
||||
|
||||
if output_path:
|
||||
ctx.state.set(output_path, text)
|
||||
@@ -614,7 +614,7 @@ async def handle_invoke_prompt_agent(ctx: ActionContext) -> AsyncGenerator[Workf
|
||||
ctx.state.set_agent_result(text=text, messages=response_messages)
|
||||
|
||||
if text:
|
||||
ctx.state.add_conversation_message(ChatMessage(role="assistant", text=text))
|
||||
ctx.state.add_conversation_message(Message(role="assistant", text=text))
|
||||
|
||||
if output_path:
|
||||
ctx.state.set(output_path, text)
|
||||
|
||||
+3
-3
@@ -102,7 +102,7 @@ def _make_powerfx_safe(value: Any) -> Any:
|
||||
"""Convert a value to a PowerFx-serializable form.
|
||||
|
||||
PowerFx can only serialize primitive types, dicts, and lists.
|
||||
Custom objects (like ChatMessage) must be converted to dicts or excluded.
|
||||
Custom objects (like Message) must be converted to dicts or excluded.
|
||||
|
||||
Args:
|
||||
value: Any Python value
|
||||
@@ -558,8 +558,8 @@ class DeclarativeWorkflowState:
|
||||
# Try "text" key first (simple dict format)
|
||||
if "text" in last_msg:
|
||||
return str(last_msg["text"])
|
||||
# Try extracting from "contents" (ChatMessage dict format)
|
||||
# ChatMessage.text concatenates text from all TextContent items
|
||||
# Try extracting from "contents" (Message dict format)
|
||||
# Message.text concatenates text from all TextContent items
|
||||
contents = last_msg.get("contents", [])
|
||||
if isinstance(contents, list):
|
||||
text_parts = []
|
||||
|
||||
+11
-11
@@ -20,8 +20,8 @@ from dataclasses import dataclass, field
|
||||
from typing import Any, cast
|
||||
|
||||
from agent_framework import (
|
||||
ChatMessage,
|
||||
Content,
|
||||
Message,
|
||||
WorkflowContext,
|
||||
handler,
|
||||
response_handler,
|
||||
@@ -170,7 +170,7 @@ def _extract_json_from_response(text: str) -> Any:
|
||||
raise json.JSONDecodeError("No valid JSON found in response", text, 0)
|
||||
|
||||
|
||||
def _validate_conversation_history(messages: list[ChatMessage], agent_name: str) -> None:
|
||||
def _validate_conversation_history(messages: list[Message], agent_name: str) -> None:
|
||||
"""Validate that conversation history has matching tool calls and results.
|
||||
|
||||
This helps catch issues where tool call messages are stored without their
|
||||
@@ -263,7 +263,7 @@ class AgentResult:
|
||||
success: bool
|
||||
response: str
|
||||
agent_name: str
|
||||
messages: list[ChatMessage] = field(default_factory=lambda: cast(list[ChatMessage], []))
|
||||
messages: list[Message] = field(default_factory=lambda: cast(list[Message], []))
|
||||
tool_calls: list[Content] = field(default_factory=lambda: cast(list[Content], []))
|
||||
error: str | None = None
|
||||
|
||||
@@ -309,7 +309,7 @@ class AgentExternalInputRequest:
|
||||
agent_name: str
|
||||
agent_response: str
|
||||
iteration: int = 0
|
||||
messages: list[ChatMessage] = field(default_factory=lambda: cast(list[ChatMessage], []))
|
||||
messages: list[Message] = field(default_factory=lambda: cast(list[Message], []))
|
||||
function_calls: list[Content] = field(default_factory=lambda: cast(list[Content], []))
|
||||
|
||||
|
||||
@@ -340,7 +340,7 @@ class AgentExternalInputResponse:
|
||||
"""
|
||||
|
||||
user_input: str
|
||||
messages: list[ChatMessage] = field(default_factory=lambda: cast(list[ChatMessage], []))
|
||||
messages: list[Message] = field(default_factory=lambda: cast(list[Message], []))
|
||||
function_results: dict[str, Content] = field(default_factory=lambda: cast(dict[str, Content], {}))
|
||||
|
||||
|
||||
@@ -637,20 +637,20 @@ class InvokeAzureAgentExecutor(DeclarativeActionExecutor):
|
||||
Tuple of (accumulated_response, all_messages, tool_calls)
|
||||
"""
|
||||
accumulated_response = ""
|
||||
all_messages: list[ChatMessage] = []
|
||||
all_messages: list[Message] = []
|
||||
tool_calls: list[Content] = []
|
||||
|
||||
# Add user input to conversation history first (via state.append only)
|
||||
if input_text:
|
||||
user_message = ChatMessage(role="user", text=input_text)
|
||||
user_message = Message(role="user", text=input_text)
|
||||
state.append(messages_path, user_message)
|
||||
|
||||
# Get conversation history from state AFTER adding user message
|
||||
# Note: We get a fresh copy to avoid mutation issues
|
||||
conversation_history: list[ChatMessage] = state.get(messages_path) or []
|
||||
conversation_history: list[Message] = state.get(messages_path) or []
|
||||
|
||||
# Build messages list for agent (use history if available, otherwise just input)
|
||||
messages_for_agent: list[ChatMessage] | str = conversation_history if conversation_history else input_text
|
||||
messages_for_agent: list[Message] | str = conversation_history if conversation_history else input_text
|
||||
|
||||
# Validate conversation history before invoking agent
|
||||
if isinstance(messages_for_agent, list) and messages_for_agent:
|
||||
@@ -672,7 +672,7 @@ class InvokeAzureAgentExecutor(DeclarativeActionExecutor):
|
||||
if not isinstance(result, str):
|
||||
result_messages: Any = getattr(result, "messages", None)
|
||||
if result_messages is not None:
|
||||
all_messages = list(cast(list[ChatMessage], result_messages))
|
||||
all_messages = list(cast(list[Message], result_messages))
|
||||
result_tool_calls: Any = getattr(result, "tool_calls", None)
|
||||
if result_tool_calls is not None:
|
||||
tool_calls = list(cast(list[Content], result_tool_calls))
|
||||
@@ -707,7 +707,7 @@ class InvokeAzureAgentExecutor(DeclarativeActionExecutor):
|
||||
"Agent '%s': No messages in response, creating simple assistant message",
|
||||
agent_name,
|
||||
)
|
||||
assistant_message = ChatMessage(role="assistant", text=accumulated_response)
|
||||
assistant_message = Message(role="assistant", text=accumulated_response)
|
||||
state.append(messages_path, assistant_message)
|
||||
|
||||
# Store results in state - support both schema formats:
|
||||
|
||||
@@ -73,8 +73,8 @@ class WorkflowFactory:
|
||||
from agent_framework.declarative import WorkflowFactory
|
||||
|
||||
# Pre-register agents for InvokeAzureAgent actions
|
||||
chat_client = AzureOpenAIChatClient()
|
||||
agent = chat_client.as_agent(name="MyAgent", instructions="You are helpful.")
|
||||
client = AzureOpenAIChatClient()
|
||||
agent = client.as_agent(name="MyAgent", instructions="You are helpful.")
|
||||
|
||||
factory = WorkflowFactory(agents={"MyAgent": agent})
|
||||
workflow = factory.create_workflow_from_yaml_path("workflow.yaml")
|
||||
@@ -517,7 +517,7 @@ class WorkflowFactory:
|
||||
Args:
|
||||
name: The name to register the agent under. Must match the agent name
|
||||
referenced in InvokeAzureAgent actions.
|
||||
agent: The agent instance (typically a ChatAgent or similar).
|
||||
agent: The agent instance (typically a Agent or similar).
|
||||
|
||||
Returns:
|
||||
Self for method chaining.
|
||||
|
||||
@@ -314,7 +314,7 @@ class WorkflowState:
|
||||
"""Add a message to the conversation history.
|
||||
|
||||
Args:
|
||||
message: The message to add (typically a ChatMessage or similar)
|
||||
message: The message to add (typically a Message or similar)
|
||||
"""
|
||||
self._conversation["messages"].append(message)
|
||||
self._conversation["history"].append(message)
|
||||
|
||||
Reference in New Issue
Block a user