mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Python: Fix HandoffBuilder dropping function-level middleware when cloning agents (#5220)
* Fix HandoffBuilder dropping function-level middleware when cloning agents (#5173) _clone_chat_agent() was using agent.agent_middleware (agent-level only) instead of agent.middleware (all types), which silently dropped any function middleware registered on the original agent. Changed to use agent.middleware to preserve all middleware types (agent, function, and chat) during cloning. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: Fix HandoffBuilder dropping function-level middleware when cloning agents Fixes #5173 * Fix false-positive middleware regression test (#5173) The test used isinstance(m, FunctionMiddleware) which matched _AutoHandoffMiddleware (always appended during build) instead of the user's @function_middleware decorator. Assert directly that tracking_middleware is present in the cloned agent's middleware list. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address review feedback for #5173: Python: [Bug]: HandoffBuilder drops function-level middleware when cloning agents --------- Co-authored-by: Copilot <copilot@github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
Unverified
parent
1b95e8585d
commit
3c31ac28b5
@@ -287,7 +287,7 @@ class HandoffAgentExecutor(AgentExecutor):
|
||||
name=agent.name,
|
||||
description=agent.description,
|
||||
context_providers=agent.context_providers,
|
||||
middleware=agent.agent_middleware,
|
||||
middleware=agent.middleware,
|
||||
require_per_service_call_history_persistence=agent.require_per_service_call_history_persistence,
|
||||
default_options=cloned_options, # type: ignore[assignment]
|
||||
)
|
||||
|
||||
@@ -18,11 +18,16 @@ from agent_framework import (
|
||||
ResponseStream,
|
||||
WorkflowEvent,
|
||||
WorkflowRunState,
|
||||
function_middleware,
|
||||
resolve_agent_id,
|
||||
tool,
|
||||
)
|
||||
from agent_framework._clients import BaseChatClient
|
||||
from agent_framework._middleware import ChatMiddlewareLayer, FunctionInvocationContext, MiddlewareTermination
|
||||
from agent_framework._middleware import (
|
||||
ChatMiddlewareLayer,
|
||||
FunctionInvocationContext,
|
||||
MiddlewareTermination,
|
||||
)
|
||||
from agent_framework._tools import FunctionInvocationLayer, FunctionTool
|
||||
from agent_framework.orchestrations import HandoffAgentUserRequest, HandoffBuilder, HandoffSentEvent
|
||||
from pytest import param
|
||||
@@ -745,6 +750,42 @@ async def test_handoff_clone_preserves_per_service_call_history_persistence() ->
|
||||
assert all(message.role != "tool" for message in stored_messages)
|
||||
|
||||
|
||||
async def test_handoff_clone_preserves_all_middleware_types() -> None:
|
||||
"""Handoff clones should preserve function and agent middleware from the original agent."""
|
||||
|
||||
@function_middleware
|
||||
async def tracking_middleware(context: FunctionInvocationContext, call_next):
|
||||
await call_next()
|
||||
|
||||
agent_a = Agent(
|
||||
id="agent_a",
|
||||
name="agent_a",
|
||||
client=MockChatClient(name="agent_a", handoff_to="agent_b"),
|
||||
middleware=[tracking_middleware],
|
||||
require_per_service_call_history_persistence=True,
|
||||
)
|
||||
agent_b = Agent(
|
||||
id="agent_b",
|
||||
name="agent_b",
|
||||
client=MockChatClient(name="agent_b"),
|
||||
default_options={"tool_choice": "none"},
|
||||
require_per_service_call_history_persistence=True,
|
||||
)
|
||||
|
||||
workflow = (
|
||||
HandoffBuilder(participants=[agent_a, agent_b], termination_condition=lambda _: False)
|
||||
.with_start_agent(agent_a)
|
||||
.add_handoff(agent_a, [agent_b])
|
||||
.add_handoff(agent_b, [agent_a])
|
||||
.build()
|
||||
)
|
||||
|
||||
executor = workflow.executors[resolve_agent_id(agent_a)]
|
||||
assert isinstance(executor, HandoffAgentExecutor)
|
||||
cloned_middleware = executor._agent.middleware or []
|
||||
assert tracking_middleware in cloned_middleware, "User function middleware should be preserved on cloned agent"
|
||||
|
||||
|
||||
def test_clean_conversation_for_handoff_keeps_text_only_history() -> None:
|
||||
"""Tool-control messages must be excluded from persisted handoff history."""
|
||||
function_call = Content.from_function_call(
|
||||
|
||||
Reference in New Issue
Block a user