We are using livekit workflow multi-agent framework.
We noticed that during the agent transfer, if the user is speaking the state is stuck in speaking.
it never changes to listening after user silence or after agent handoff.
Attaching the transfer_to_agent fn definition,
@function_tool
async def transfer_to_agent(self, target_agent_id: str, run_ctx: RunContext):
“”"
Transfer to another agent.
“”"
# Disable interruptions during transfer
run_ctx.disallow_interruptions()
# Create new chat context (optional)
new_chat_ctx = self.chat_ctx.copy() if self.chat_ctx else None
# Create next agent
factory = self.agents_map[target_agent_id]
next_agent = await factory({"source_agent_id": self._agent_id})
# Apply chat context
if new_chat_ctx:
await next_agent.update_chat_ctx(
new_chat_ctx,
exclude_invalid_function_calls=False
)
# Pause current activity scheduling to avoid race conditions
if (
self.agent_session
and hasattr(self.agent_session, "_activity")
and self.agent_session._activity
):
self.agent_session._activity._scheduling_paused = True
return next_agent, None
livekit-agents = {version = "1.3.9” }
During a handoff, agent and user states are driven by VAD and the active AgentSession. If you call run_ctx.disallow_interruptions() and manually pause _activity._scheduling_paused, you can prevent the session from completing the current turn cycle, which blocks transitions like speaking → listening.
Instead of pausing internal _activity (and I would discourage accessing any internal objects, denoted by the _), let the framework manage the lifecycle and use the built‑in handoff flow.
# Pause current activity scheduling to avoid race conditions
Clearly this code is working around some other issue, I think fixing the race condition that prompted you to add this line is probably the best way forward.
self.agent_session._activity._scheduling_paused = True this was added to solve the below problem -LLM emitted { message , tool } in same turn, the tool was transfer_to_agent tool.
Thought the function_tool is shown success in langfuse, the user interrupted while the “message“ was being spoken.
The current agent activity drained but the new agent activity didn’t come up.
So by adding this line, it solved that problem.
My recommendation hasn’t changed from my original answer. I did also check the Ask AI feature (blue button, above), which is newly added since you asked the original question, but it provides a similar answer.