Module praisonaiagents.handoff

The handoff module enables seamless task delegation between AI agents, allowing specialized agents to transfer control to other agents based on expertise or task requirements.

Classes

Handoff

The main class that represents a handoff configuration for delegating tasks between agents.

Parameters

  • agent: 'Agent' - The target agent to hand off to
  • tool_name_override: Optional[str] = None - Custom tool name (defaults to transfer_to_<agent_name>)
  • tool_description_override: Optional[str] = None - Custom tool description for the handoff
  • on_handoff: Optional[Callable] = None - Callback function executed during handoff
  • input_type: Optional[type] = None - Type annotation for structured input data
  • input_filter: Optional[Callable[[HandoffInputData], HandoffInputData]] = None - Function to transform input before passing to target

Methods

  • to_tool_function(self, source_agent: 'Agent') → Callable - Converts the handoff configuration into a callable tool function

HandoffInputData

A dataclass that standardises the data passed between agents during handoff.

Fields

  • messages: List[Message] - List of conversation history
  • context: Dict[str, Any] - Dictionary containing additional context (e.g., source agent name)

Functions

handoff

Factory function for creating Handoff instances.
def handoff(
    agent: 'Agent',
    tool_name_override: Optional[str] = None,
    tool_description_override: Optional[str] = None,
    on_handoff: Optional[Callable] = None,
    input_type: Optional[type] = None,
    input_filter: Optional[Callable[[HandoffInputData], HandoffInputData]] = None
) -> Handoff

Usage Examples

Basic Handoff

from praisonaiagents import Agent

# Create specialised agents
billing_agent = Agent(
    name="Billing Agent",
    role="Handle billing inquiries",
    goal="Resolve billing issues"
)

refund_agent = Agent(
    name="Refund Agent",
    role="Process refunds",
    goal="Handle refund requests"
)

# Create triage agent with handoffs
triage_agent = Agent(
    name="Triage Agent",
    role="Route customer inquiries",
    goal="Direct customers to the right specialist",
    handoffs=[billing_agent, refund_agent]
)

Advanced Handoff with Callbacks

from praisonaiagents import Agent, handoff

def log_handoff(source_agent: Agent, input_data: HandoffInputData):
    print(f"Handoff from {source_agent.name} with {len(input_data.messages)} messages")

support_agent = Agent(
    name="Support Agent",
    handoffs=[
        handoff(
            escalation_agent,
            tool_name_override="escalate_to_manager",
            tool_description_override="Escalate complex issues to a manager",
            on_handoff=log_handoff
        )
    ]
)

Handoff with Input Filtering

from praisonaiagents import handoff, handoff_filters

# Remove tool calls from conversation history
handoff_with_filter = handoff(
    technical_agent,
    input_filter=handoff_filters.remove_all_tools
)

# Keep only last 5 messages
handoff_with_limit = handoff(
    summary_agent,
    input_filter=handoff_filters.keep_last_n_messages(5)
)

Structured Input Handoff

from pydantic import BaseModel
from praisonaiagents import Agent, handoff

class EscalationData(BaseModel):
    priority: str
    reason: str
    customer_id: str

escalation_agent = Agent(
    name="Escalation Handler",
    handoffs=[
        handoff(
            manager_agent,
            input_type=EscalationData,
            tool_description_override="Escalate with structured priority data"
        )
    ]
)

Callback Patterns

The on_handoff callback supports three patterns:
  1. No parameters - Simple notification
    def notify_handoff():
        logging.info("Handoff occurred")
    
  2. One parameter - Receives source agent
    def log_source(source_agent: Agent):
        print(f"Handoff from: {source_agent.name}")
    
  3. Two parameters - Receives source agent and input data
    def process_handoff(source_agent: Agent, input_data: HandoffInputData):
        # Access full context and messages
        print(f"Agent: {source_agent.name}")
        print(f"Messages: {len(input_data.messages)}")
    

Built-in Input Filters

The handoff_filters module provides common filtering functions:
  • remove_all_tools - Removes all tool calls from message history
  • keep_last_n_messages(n) - Keeps only the last n messages
  • remove_system_messages - Removes system messages from history

How It Works

  1. Configuration Phase:
    • Agents are created with a handoffs parameter containing target agents
    • The handoff module converts these into callable tool functions
    • Tools are registered with the agent’s LLM for function calling
  2. Runtime Delegation:
    • When an agent determines delegation is needed, it calls the handoff tool
    • The handoff executes any configured callbacks
    • Conversation history is collected and filtered
    • The target agent receives the context and continues the conversation
    • The response is returned to the original caller
  3. Context Preservation:
    • Full conversation history is maintained
    • Source agent identification is preserved
    • Custom context can be passed via structured inputs

Best Practices

  1. Design Clear Agent Boundaries - Each agent should have a specific expertise
  2. Use Descriptive Names - Tool names should clearly indicate the target agent’s role
  3. Implement Callbacks - Use callbacks for logging, monitoring, or custom logic
  4. Filter Appropriately - Remove unnecessary context to stay within token limits
  5. Test Handoff Chains - Ensure agents don’t create infinite delegation loops