-
Notifications
You must be signed in to change notification settings - Fork 646
Python: Add Handoff orchestration pattern support #1469
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR introduces a new handoff orchestration pattern for Python workflows that allows triage agents to route conversations to specialists and maintain cyclical user interaction. The handoff pattern provides structured routing between agents with full conversation context preservation and configurable termination conditions.
Key Changes:
- Added
HandoffBuilderAPI for creating triage-to-specialist workflows with automatic context management - Implemented conversation state persistence utilities that preserve message metadata across agent handoffs
- Created comprehensive samples demonstrating basic usage, context windows, and custom routing resolvers
Reviewed Changes
Copilot reviewed 9 out of 10 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
python/packages/core/agent_framework/_workflows/_handoff.py |
Core handoff workflow implementation with coordinator, gateway, and builder classes |
python/packages/core/agent_framework/_workflows/_conversation_state.py |
Utilities for serializing/deserializing chat conversations with metadata preservation |
python/packages/core/agent_framework/_workflows/__init__.py |
Export new handoff classes in public API |
python/packages/core/tests/workflow/test_handoff.py |
Comprehensive test coverage for handoff functionality and metadata preservation |
python/samples/getting_started/workflows/orchestration/handoff_agents.py |
Basic handoff workflow sample with triage and specialist agents |
python/samples/getting_started/workflows/orchestration/handoff_with_context_window.py |
Sample demonstrating rolling context window for token efficiency |
python/samples/getting_started/workflows/orchestration/handoff_with_custom_resolver.py |
Advanced sample using Pydantic models for structured output routing |
python/samples/getting_started/workflows/README.md |
Documentation updates describing handoff pattern and usage tips |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
python/samples/getting_started/workflows/orchestration/handoff_with_custom_resolver.py
Outdated
Show resolved
Hide resolved
Python Test Coverage Report •
Python Unit Test Overview
|
||||||||||||||||||||||||||||||||||||||||
python/samples/getting_started/workflows/orchestration/handoff_simple.py
Show resolved
Hide resolved
python/samples/getting_started/workflows/orchestration/handoff_simple.py
Outdated
Show resolved
Hide resolved
python/samples/getting_started/workflows/orchestration/handoff_simple.py
Outdated
Show resolved
Hide resolved
python/samples/getting_started/workflows/orchestration/handoff_with_context_window.py
Outdated
Show resolved
Hide resolved
python/samples/getting_started/workflows/orchestration/handoff_with_context_window.py
Outdated
Show resolved
Hide resolved
python/samples/getting_started/workflows/orchestration/handoff_with_context_window.py
Outdated
Show resolved
Hide resolved
python/samples/getting_started/workflows/orchestration/handoff_with_custom_resolver.py
Outdated
Show resolved
Hide resolved
python/samples/getting_started/workflows/orchestration/handoff_specialist_to_specialist.py
Outdated
Show resolved
Hide resolved
Proposal: Lazy Intent Classification for Handoff WorkflowsThe Key IdeaI'd like to propose an alternative handoff pattern that uses lazy intent classification—only triggered when a specialist agent signals they can't help—rather than having a coordinator mediate every turn. The core insight: specialists know their own boundaries through their system prompt and signal when they're out of scope. The system then classifies intent and routes to the appropriate specialist. How It WorksEach specialist has boundary instructions in their prompt: When the system detects this phrase in a response:
Otherwise, the specialist communicates directly with the user. No intermediary, no overhead. Classification only happens when needed (first message or handoff signal). Why This ScalesThe critical advantage here is scalability. Each specialist only needs to know their own boundaries—not the capabilities of other specialists. When you add a new specialist, you just define their domain and tools. No need to update coordination logic or make other specialists aware of the new addition. This makes the system scalable to a large number of specialist agents without growing complexity. Other benefits:
Flow ComparisonCurrent pattern (coordinator-mediated): Every turn goes through coordinator. Proposed pattern (lazy classification): Classification only on entry and handoff signals. When to Use Each?Coordinator-mediated works well for:
Lazy classification works well for:
Implementation QuestionShould this be added as an optional mode to HandoffBuilder? workflow = (
HandoffBuilder(participants=[billing, security, products])
.coordinator("billing") # Starting agent
.with_routing_mode("lazy_classification") # vs "coordinator_mediated"
.with_handoff_phrase("This is outside my area") # Configurable
.with_context_transfer(turns=3) # How much history on handoff
.build()
)Or should it be a separate builder class altogether? Real Results and Reference ImplementationI've implemented this pattern for customer support with 3 domain specialists and seen:
For reference, here is my implementation which does not use the workflow framework: DiscussionWould love feedback on:
The key advantage is simplicity. Most of the time, specialists just talk directly to users. No third-party monitoring system needed. Adding new specialists doesn't require updating coordination logic—just define their domain and boundaries. What do you think? Does this resonate with use cases you're working on? |
python/samples/getting_started/workflows/orchestration/handoff_specialist_to_specialist.py
Outdated
Show resolved
Hide resolved
python/samples/getting_started/workflows/orchestration/handoff_specialist_to_specialist.py
Outdated
Show resolved
Hide resolved
python/samples/getting_started/workflows/orchestration/handoff_simple.py
Outdated
Show resolved
Hide resolved
Thanks for the suggestion, @james-tn. We appreciate it. It looks like this can be an improvement around the current coordinator-style that we're looking to introduce. We wanted to get the "easiest" pattern out first for feedback, and then we can look at evolving it further via improvements like the one you suggested. |
…-framework into workflow-handoff-20251014
python/packages/core/agent_framework/_workflows/_conversation_state.py
Outdated
Show resolved
Hide resolved
* Add Handoff orchestration pattern support * PR feedback * Use AOAI client in samples * Adjust to tool * Handoff to sub-agent via ai function * PR feedback * More cleanup * Improvements * PR feedback cleanup * Add handoff migration sample. * Remove type ignore * fix markdown link formatting * Remove readme link for non-existent sample
Motivation and Context
Description
HandoffBuilder: Fluent API for building cyclical workflows with.coordinator(),.add_handoff(), and.with_termination_condition()methods.handoff_to_<agent>tools and intercepts their invocation via middleware to route between agents.ChatMessage.additional_properties) is maintained across all hops, with automatic tool call cleanup during agent transitions to avoid OpenAI API errors..add_handoff()configuration enables specialist-to-specialist handoffs for complex workflows.starting_agent()method in favor of clearer.coordinator()terminology.handoff_simple.pyandhandoff_specialist_to_specialist.pydemonstrating single-tier and multi-tier patterns with scripted response loops.Contribution Checklist