diff --git a/python/packages/core/agent_framework/_types.py b/python/packages/core/agent_framework/_types.py index 6ffebae8700..9e054e0b360 100644 --- a/python/packages/core/agent_framework/_types.py +++ b/python/packages/core/agent_framework/_types.py @@ -56,11 +56,16 @@ def _parse_content_list(contents_data: Sequence[Any]) -> list[Content]: """Parse a list of content data into appropriate Content objects. Args: - contents_data: List of content data (strings, dicts, or already constructed objects) + contents_data: List of content data (strings, dicts, or already constructed objects). + A single string is treated as one text item. Returns: List of Content objects with unknown types logged and ignored """ + if isinstance(contents_data, str): + # A string is itself a sequence of strings, so iterating it would create one text + # content per character. + contents_data = [contents_data] contents: list[Content] = [] for content_data in contents_data: if content_data is None: @@ -2072,7 +2077,8 @@ def __init__( Args: role: The role of the author of the message (e.g., "user", "assistant", "system", "tool"). contents: A sequence of content items. Can be Content objects, strings (auto-converted - to TextContent), or dicts (parsed via Content.from_dict). Defaults to empty list. + to TextContent), or dicts (parsed via Content.from_dict). A single string is + treated as one text item. Defaults to empty list. Keyword Args: author_name: Optional name of the author of the message. diff --git a/python/packages/core/tests/core/test_types.py b/python/packages/core/tests/core/test_types.py index 2c41acd93b4..b3e77dd3b9d 100644 --- a/python/packages/core/tests/core/test_types.py +++ b/python/packages/core/tests/core/test_types.py @@ -1167,6 +1167,25 @@ def test_chat_message_text(): assert isinstance(message.contents[0], Content) +@pytest.mark.parametrize( + "message", + [Message("user", "Hello, how are you?"), Message(role="user", contents="Hello, how are you?")], + ids=["positional", "keyword"], +) +def test_chat_message_with_single_string_contents(message: Message) -> None: + """A bare string is one text content, not a sequence of single-character contents.""" + assert len(message.contents) == 1 + assert message.contents[0].type == "text" + assert message.text == "Hello, how are you?" + + +def test_chat_message_with_empty_string_contents() -> None: + message = Message("user", "") + + assert len(message.contents) == 1 + assert message.text == "" + + def test_chat_message_contents(): """Test the Message class to ensure it initializes correctly with contents.""" # Create a Message with a role and multiple contents @@ -4553,6 +4572,15 @@ def test_parse_content_list_with_dicts(): assert result[0].text == "hello" +def test_parse_content_list_with_single_string(): + """Test _parse_content_list treats a bare string as one text item, not one per character.""" + result = _parse_content_list("hello") + + assert len(result) == 1 + assert result[0].type == "text" + assert result[0].text == "hello" + + def test_parse_content_list_with_mixed_content_and_dict(): """Test _parse_content_list handles a mix of Content objects and dicts.""" content = Content(type="text", text="hello")