Description
Summary
HandoffAgentExecutor._clone_chat_agent() passes agent.agent_middleware (agent-level only) instead of agent.middleware (all types) when constructing the cloned agent. This silently drops any @function_middleware registered on the original agent, so function-level middleware never executes during handoff workflows.
Environment
- agent-framework version: 1.0.0
- Python version: 3.13
- OS: macOS (arm64)
Steps to Reproduce
from agent_framework import Agent, function_middleware, FunctionInvocationContext
from agent_framework.orchestrations import HandoffBuilder
# 1. Define a function middleware
@function_middleware
async def my_logging_middleware(context: FunctionInvocationContext, call_next):
print(f"TOOL CALLED: {context.function.name}")
await call_next()
print(f"TOOL RESULT: {context.result}")
# 2. Create agents with function middleware
agent_a = Agent(
client=client,
name="AgentA",
instructions="You are agent A.",
tools=[some_tool],
middleware=[my_logging_middleware],
)
agent_b = Agent(
client=client,
name="AgentB",
instructions="You are agent B.",
tools=[some_tool],
middleware=[my_logging_middleware],
)
# 3. Verify middleware is present on the original agent
print(agent_a.middleware) # [my_logging_middleware] ✓
print(agent_a.agent_middleware) # [] ← only agent-level
# 4. Build a handoff workflow
workflow = (
HandoffBuilder(participants=[agent_a, agent_b])
.with_start_agent(agent_a)
.add_handoff(agent_a, [agent_b])
.add_handoff(agent_b, [agent_a])
.build()
)
# 5. Run the workflow — my_logging_middleware never fires
async for event in workflow.run("Do something", stream=True):
pass
Expected Behavior
Function-level middleware registered on agents should be preserved when agents are cloned for handoff workflows. Tool call logging (or any custom function middleware) should execute normally during handoff execution.
Actual Behavior
Function-level middleware is silently dropped. No error is raised. Tool calls execute but the middleware is never invoked.
Root Cause
In agent_framework_orchestrations/_handoff.py, the _clone_chat_agent method uses agent.agent_middleware which only returns agent-level middleware:
# _handoff.py, HandoffAgentExecutor._clone_chat_agent()
def _clone_chat_agent(self, agent: Agent[Any]) -> Agent[Any]:
options = agent.default_options
# ...
return Agent(
client=agent.client,
id=agent.id,
name=agent.name,
description=agent.description,
context_providers=agent.context_providers,
middleware=agent.agent_middleware, # ← BUG: only agent-level middleware
require_per_service_call_history_persistence=agent.require_per_service_call_history_persistence,
default_options=cloned_options,
)
The Agent class separates middleware into buckets during __init__ via categorize_middleware() in agent_framework/_middleware.py:
agent.middleware → full original list (all types)
agent.agent_middleware → only @agent_middleware items
- Function middleware → stored separately for runtime invocation
Since _clone_chat_agent reads from agent.agent_middleware, any @function_middleware is lost.
Notably, _prepare_agent_with_handoffs() does later append _AutoHandoffMiddleware (itself a FunctionMiddleware) to cloned_agent.middleware, so the framework's own function middleware works — but user-provided function middleware is already gone by that point.
Code Sample
Error Messages / Stack Traces
Package Versions
agent-framework-core:1.0.0
Python Version
Python 3.13
Additional Context
No response
Description
Summary
HandoffAgentExecutor._clone_chat_agent()passesagent.agent_middleware(agent-level only) instead ofagent.middleware(all types) when constructing the cloned agent. This silently drops any@function_middlewareregistered on the original agent, so function-level middleware never executes during handoff workflows.Environment
Steps to Reproduce
Expected Behavior
Function-level middleware registered on agents should be preserved when agents are cloned for handoff workflows. Tool call logging (or any custom function middleware) should execute normally during handoff execution.
Actual Behavior
Function-level middleware is silently dropped. No error is raised. Tool calls execute but the middleware is never invoked.
Root Cause
In
agent_framework_orchestrations/_handoff.py, the_clone_chat_agentmethod usesagent.agent_middlewarewhich only returns agent-level middleware:The
Agentclass separates middleware into buckets during__init__viacategorize_middleware()inagent_framework/_middleware.py:agent.middleware→ full original list (all types)agent.agent_middleware→ only@agent_middlewareitemsSince
_clone_chat_agentreads fromagent.agent_middleware, any@function_middlewareis lost.Notably,
_prepare_agent_with_handoffs()does later append_AutoHandoffMiddleware(itself aFunctionMiddleware) tocloned_agent.middleware, so the framework's own function middleware works — but user-provided function middleware is already gone by that point.Code Sample
Error Messages / Stack Traces
Package Versions
agent-framework-core:1.0.0
Python Version
Python 3.13
Additional Context
No response