Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ def _clone_chat_agent(self, agent: Agent[Any]) -> Agent[Any]:
name=agent.name,
description=agent.description,
context_providers=agent.context_providers,
middleware=agent.agent_middleware,
middleware=agent.middleware,
Comment thread
moonbox3 marked this conversation as resolved.
Comment thread
moonbox3 marked this conversation as resolved.
require_per_service_call_history_persistence=agent.require_per_service_call_history_persistence,
default_options=cloned_options, # type: ignore[assignment]
)
Expand Down
43 changes: 42 additions & 1 deletion python/packages/orchestrations/tests/test_handoff.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,16 @@
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
Expand Down Expand Up @@ -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(
Expand Down
Loading