Skip to content

Python: Bug: streaming chunk merge adds an item to every matching item, duplicating text #14786

Open

Description

Describe the bug

When two streaming chunks are added, StreamingContentMixin._merge_items_lists merges each incoming item into every compatible item in the list, not just the first one. The inner loop sets added = True after a successful item + other_item, but it doesn't break, so it keeps going and adds the same incoming item to every later item of the same type that accepts it.

for other_item in other_items:
added = False
for id, item in enumerate(new_items_list):
if type(item) is type(other_item) and hasattr(item, "__add__"):
try:
new_item = item + other_item # type: ignore
new_items_list[id] = new_item
added = True
except (ValueError, ContentAdditionException) as ex:
logger.debug(f"Could not add item {other_item} to {item}.", exc_info=ex)
continue
if not added:
logger.debug(f"Could not add item {other_item} to any item in the list. Adding it as a new item.")
new_items_list.append(other_item)

This happens whenever a merged message holds two items of the same type that can both take the next chunk. One case is two StreamingTextContent items with the same choice_index, which the Google AI connector builds when a candidate has more than one text part (google_ai_chat_completion.py#L366-L376). Another is two FunctionCallContent items whose id/index don't tell them apart. Then the next chunk's text or arguments are copied into both.

To Reproduce

semantic-kernel 1.47.0. The file is the same on main (25bd1bb).

from semantic_kernel.contents import AuthorRole, StreamingChatMessageContent, StreamingTextContent

c1 = StreamingChatMessageContent(role=AuthorRole.ASSISTANT, choice_index=0, items=[
    StreamingTextContent(choice_index=0, text="Part one. "),
    StreamingTextContent(choice_index=0, text="Part two. "),
])
c2 = StreamingChatMessageContent(role=AuthorRole.ASSISTANT, choice_index=0, items=[
    StreamingTextContent(choice_index=0, text="tail"),
])
print([i.text for i in (c1 + c2).items])

Output:

['Part one. tail', 'Part two. tail']

Expected behavior

The incoming item is merged into one item only, so the text isn't duplicated: ['Part one. tail', 'Part two. '].

Platform

  • Language: Python
  • Source: semantic-kernel 1.47.0 (pip) / main at 25bd1bb
  • AI model: n/a (no model call needed)
  • IDE: n/a
  • OS: Windows 11, Python 3.12

Additional context

The fix is a break after added = True. I have it with a regression test in tests/unit/contents/test_streaming_chat_message_content.py and will open a PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    pythonPull requests for the Python Semantic Kerneltriage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions