Handoff Filters

Filter and transform context when handing off between agents

Handoff filters control what context passes when one agent hands off to another — reducing tokens, focusing relevance, and stripping sensitive data.

python
from praisonaiagents import Agent, Handoff, handoff_filters

coordinator = Agent(
    name="Coordinator",
    instructions="Route tasks to specialists with trimmed context",
    handoffs=[
        Handoff(
            agent=Agent(name="Analyst", instructions="Analyse the handoff payload"),
            input_filter=handoff_filters.compress_history,
        )
    ],
)

coordinator.start("Prepare a focused brief for the analyst")

The user asks the coordinator; filtered context is passed on handoff.

Diagram

Handoff Filters

📋 Full History

🔍 Filters

✅ Clean Context

Overview

Handoff filters let you control what context is passed when one agent hands off to another. This helps:

  • Reduce token usage by removing unnecessary messages
  • Focus context on relevant information
  • Protect privacy by filtering sensitive data

Quick Start

  1. Single filter
    Single Filter
    from praisonaiagents import Agent, Handoff, handoff_filters
    
    analyst = Agent(name="Analyst", instructions="Analyze data")
    
    coordinator = Agent(
        name="Coordinator",
        handoffs=[
            Handoff(
                agent=analyst,
                input_filter=handoff_filters.compress_history
            )
        ]
    )
  2. Chain filters
    Filter Chaining
    from praisonaiagents import Agent, Handoff, handoff_filters
    
    analyst = Agent(name="Analyst", instructions="Analyze data")
    
    coordinator = Agent(
        name="Coordinator",
        handoffs=[
            Handoff(
                agent=analyst,
                input_filter=[
                    handoff_filters.remove_all_tools,
                    handoff_filters.remove_system_messages,
                    handoff_filters.compress_history,
                ]
            )
        ]
    )

Available Filters

compress_history

Compresses all messages into a single summary message. Great for reducing token usage.

python
from praisonaiagents import handoff_filters

# Before: Multiple messages
# [
#   {"role": "user", "content": "Hello"},
#   {"role": "assistant", "content": "Hi there!"},
#   {"role": "user", "content": "How are you?"}
# ]

# After: Single compressed message
# [{"role": "user", "content": "Previous conversation summary:\n[user]: Hello\n[assistant]: Hi there!\n[user]: How are you?"}]

remove_all_tools

Removes all tool-related messages (tool calls and tool results).

python
# Removes:
# - Messages with role="tool"
# - Messages with tool_calls field

keep_last_n_messages

Keeps only the last N messages.

python
# Keep last 5 messages
filter_fn = handoff_filters.keep_last_n_messages(5)

remove_system_messages

Removes all system messages from the history.

python
# Removes all messages where role="system"

Filter Chaining

python
from praisonaiagents import Agent, Handoff, handoff_filters

# Recommended order:
# 1. Remove unwanted content
# 2. Limit message count
# 3. Compress remaining

handoff = Handoff(
    agent=target_agent,
    input_filter=[
        handoff_filters.remove_all_tools,      # First: remove tool noise
        handoff_filters.remove_system_messages, # Second: remove system prompts
        handoff_filters.keep_last_n_messages(10), # Third: limit to recent
        handoff_filters.compress_history,       # Last: compress into one
    ]
)
Diagram

Step 4: compress_history

Step 3: keep_last_n(10)

Step 2: remove_system_messages

Step 1: remove_all_tools

Original History (20 messages)

User + Assistant + Tools + System

User + Assistant + System

User + Assistant only

Last 10 messages

1 summary message

How It Works

The user asks the coordinator; on handoff the input filters run in order and the filtered messages are seeded onto the target agent’s chat_history for the duration of the handoff, then restored on exit.

Diagram
Target Agentinput_filter chainHandoffConfigSource AgentTarget Agentinput_filter chainHandoffConfigSource Agentchat_history restored on exitchat_history + kwargsapply context_policy(FULL / LAST_N / SUMMARY / NONE)filtered messagestransformed messagesseed chat_history(scoped to this handoff)response

Custom Filters

Create your own filter function:

python
from praisonaiagents import HandoffInputData

def my_custom_filter(data: HandoffInputData) -> HandoffInputData:
    """Remove messages containing sensitive keywords."""
    sensitive_words = ["password", "secret", "api_key"]

    filtered = []
    for msg in data.messages:
        if isinstance(msg, dict):
            content = msg.get("content", "").lower()
            if not any(word in content for word in sensitive_words):
                filtered.append(msg)

    data.messages = filtered
    return data

# Use with handoff
handoff = Handoff(
    agent=target_agent,
    input_filter=[
        my_custom_filter,
        handoff_filters.compress_history,
    ]
)

API Reference

HandoffInputData

The data structure passed to filter functions:

python
@dataclass
class HandoffInputData:
    messages: List[Dict[str, Any]]  # Conversation messages
    context: Dict[str, Any]         # Additional context
    source_agent: str               # Name of source agent
    handoff_depth: int = 0          # Current handoff depth
    handoff_chain: List[str] = []   # Chain of agent names

Filter Function Signature

python
def filter_function(data: HandoffInputData) -> HandoffInputData:
    # Modify data.messages as needed
    return data

Examples

Token-Efficient Handoff
python
from praisonaiagents import Agent, Handoff, handoff_filters

# Minimize tokens passed to specialist
specialist = Agent(name="Specialist", instructions="Handle complex tasks")

coordinator = Agent(
    name="Coordinator",
    handoffs=[
        Handoff(
            agent=specialist,
            input_filter=[
                handoff_filters.remove_all_tools,
                handoff_filters.keep_last_n_messages(3),
                handoff_filters.compress_history,
            ]
        )
    ]
)
Privacy-Aware Handoff
python
from praisonaiagents import Agent, Handoff, handoff_filters
from praisonaiagents import HandoffInputData

def remove_pii(data: HandoffInputData) -> HandoffInputData:
    """Remove personally identifiable information."""
    import re

    for msg in data.messages:
        if isinstance(msg, dict) and "content" in msg:
            # Remove email addresses
            msg["content"] = re.sub(
                r'\b[\w.-]+@[\w.-]+\.\w+\b',
                '[EMAIL REDACTED]',
                msg["content"]
            )
            # Remove phone numbers
            msg["content"] = re.sub(
                r'\b\d{3}[-.]?\d{3}[-.]?\d{4}\b',
                '[PHONE REDACTED]',
                msg["content"]
            )

    return data

external_agent = Agent(name="External", instructions="Process request")

internal_agent = Agent(
    name="Internal",
    handoffs=[
        Handoff(
            agent=external_agent,
            input_filter=[remove_pii, handoff_filters.compress_history]
        )
    ]
)
Focus on Recent Context
python
from praisonaiagents import Agent, Handoff, handoff_filters

# Only pass last 5 messages, no tools
analyst = Agent(name="Analyst", instructions="Analyze recent conversation")

coordinator = Agent(
    name="Coordinator",
    handoffs=[
        Handoff(
            agent=analyst,
            input_filter=[
                handoff_filters.remove_all_tools,
                handoff_filters.keep_last_n_messages(5),
            ]
        )
    ]
)

Best Practices

Compress history before large handoffs

Passing a full conversation to a specialist wastes tokens on context it doesn’t need. Use handoff_filters.compress_history (or a custom trim) so the receiving agent gets a focused brief, not the entire transcript.

Strip tool calls the next agent can't use

Tool-call messages from the source agent are noise to a specialist with different tools. Filter them out (remove_tools) so the receiving model reasons over content, not stale tool invocations it will never repeat.

Redact sensitive data at the boundary

Handoffs are the natural place to drop secrets, PII, or credentials before another agent sees them. Add a redaction filter to the chain so sensitive fields never cross into an agent that doesn’t need them.

Chain filters in order of intent

Filters compose left to right, each receiving the previous filter’s output. Order them so structural cuts (remove tools) run before compression, and redaction runs last, so nothing sensitive slips through a later transform.

Related