Please read this first
- Have you read the docs? Yes. This is about the SDK's
nest_handoff_history behavior during chained handoffs.
- Have you searched for related issues? Yes. No duplicate was found.
Describe the bug
When a nest_handoff_history summary is passed through another nested handoff, _extract_nested_history_transcript reconstructs the prior transcript by splitting the summary block into lines and parsing role: content text.
That parsing loses information:
- Multiline string content is truncated to the first line.
- Structured role content such as a list of input content parts is converted into a plain string.
Impact: chained handoffs and custom handoff_history_mapper implementations can receive a corrupted transcript. User content after the first newline is dropped, and structured input parts such as multimodal content descriptors no longer have their original shape.
Debug information
- Agents SDK version: upstream
main at bc3607ba
- Python version: Python 3.12.1
Repro steps
Run this script against current upstream main:
from __future__ import annotations
import json
from agents.handoffs import HandoffInputData, nest_handoff_history
from agents.items import TResponseInputItem
def capture_second_pass(item: TResponseInputItem) -> list[TResponseInputItem]:
captured: list[TResponseInputItem] = []
def mapper(transcript: list[TResponseInputItem]) -> list[TResponseInputItem]:
captured.extend(transcript)
return transcript
first = HandoffInputData(input_history=(item,), pre_handoff_items=(), new_items=())
first_nested = nest_handoff_history(first)
second = HandoffInputData(
input_history=first_nested.input_history,
pre_handoff_items=(),
new_items=(),
)
nest_handoff_history(second, history_mapper=mapper)
return captured
multiline = capture_second_pass(
{"role": "user", "content": "first line\nsecond line"}
)
structured = capture_second_pass(
{
"role": "user",
"content": [
{"type": "input_text", "text": "look at this"},
{"type": "input_image", "image_url": "https://example.com/image.png"},
],
}
)
print("multiline:")
print(json.dumps(multiline, ensure_ascii=False, indent=2))
print("structured_content_type:", type(structured[0].get("content")).__name__)
print("structured:")
print(json.dumps(structured, ensure_ascii=False, indent=2))
Actual result:
multiline:
[
{
"role": "user",
"content": "first line"
}
]
structured_content_type: str
structured:
[
{
"role": "user",
"content": "[{\"type\": \"input_text\", \"text\": \"look at this\"}, {\"type\": \"input_image\", \"image_url\": \"https://example.com/image.png\"}]"
}
]
Expected behavior
Flattening an already nested handoff summary should preserve transcript item content across chained handoffs:
- Multiline content should remain
"first line\nsecond line".
- Structured content should remain a list, not be converted to a string.
- Legacy simple summary lines should continue to parse for existing saved histories.
Please read this first
nest_handoff_historybehavior during chained handoffs.Describe the bug
When a
nest_handoff_historysummary is passed through another nested handoff,_extract_nested_history_transcriptreconstructs the prior transcript by splitting the summary block into lines and parsingrole: contenttext.That parsing loses information:
Impact: chained handoffs and custom
handoff_history_mapperimplementations can receive a corrupted transcript. User content after the first newline is dropped, and structured input parts such as multimodal content descriptors no longer have their original shape.Debug information
mainatbc3607baRepro steps
Run this script against current upstream
main:Actual result:
Expected behavior
Flattening an already nested handoff summary should preserve transcript item content across chained handoffs:
"first line\nsecond line".