Skip to content

Duplicate Events for Handoffs #1862

@bonk1t

Description

@bonk1t

Describe the bug

When using streaming with handoffs, the SDK emits both ToolCallItem and HandoffCallItem with the same call_id for a single handoff. If frameworks persist both events (as they naturally would when processing the stream), this creates duplicate function_call entries in conversation history, causing API errors on subsequent turns.

Debug information

  • Agents SDK version: 0.3.3
  • Python version: 3.13

Repro steps

"""
Minimal reproduction: SDK emits duplicate events for handoffs with same call_id
Run: export OPENAI_API_KEY=your_key && python repro_duplicate_handoff_events.py
"""
import asyncio
import os
from agents import Agent, Runner, set_tracing_disabled

if not os.getenv("OPENAI_API_KEY"):
    exit("Set OPENAI_API_KEY")

set_tracing_disabled(disabled=True)

worker_agent = Agent(name="Worker", instructions="You are helpful.")
coordinator_agent = Agent(
    name="Coordinator",
    instructions="When asked to delegate, transfer to Worker.",
    handoffs=[worker_agent],
)

async def main():
    # Turn 1: Collect streaming events
    persisted_history = []
    result = Runner.run_streamed(coordinator_agent, "Transfer to worker")
    
    async for event in result.stream_events():
        if event.type == "run_item_stream_event":
            persisted_history.append(event.item.to_input_item())
    
    # Turn 2: Use persisted history (will fail with duplicate error)
    persisted_history.append({"role": "user", "content": "What did I ask?"})
    result2 = await Runner.run(coordinator_agent, persisted_history)
    print(result2.final_output)

if __name__ == "__main__":
    asyncio.run(main())

Output:

openai.BadRequestError: Error code: 400 - {'error': {'message': 'Duplicate item found with id fc_... Remove duplicate items from your input and try again.', 'type': 'invalid_request_error', 'param': 'input', 'code': None}}

Root cause: In agents/_run_impl.py:498-505, both ToolCallItem and HandoffCallItem are appended for handoffs, sharing the same call_id.

Expected behavior

Only one event should be emitted per handoff, OR the SDK should deduplicate when converting to input history. Currently, frameworks must implement workarounds to skip one of the events.

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionQuestion about using the SDK

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions