Skip to content

Python: Treat a single string passed to Message as one text content - #9327

Merged
Eduard van Valkenburg (eavanvalkenburg) merged 2 commits into
microsoft:mainfrom
Aditya-XR:fix/message-str-contents
Oct 15, 2026
Merged

Eduard van Valkenburg (eavanvalkenburg) merged 2 commits into
microsoft:mainfrom
Aditya-XR:fix/message-str-contents

Conversation

@Aditya-XR

@Aditya-XR Aditya Kumar (Aditya-XR) commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Motivation & Context

Message("user", "Hello") creates one text content per character, because Message.__init__ iterates contents and a str is itself a sequence of strings. The contents type hint accepts a bare string, the docstring says strings are converted to text content, and the repository's own hosted-workflows sample uses this form. With Chat Completions, each character is then sent as a separate user message.

Description & Review Guide

  • What are the major changes?

    _parse_content_list wraps a bare string in a list before iterating, so it becomes a single text content, the same as Message("user", ["Hello"]). Message.__init__ already hands contents to this helper, so the constructor itself is unchanged:

     def _parse_content_list(contents_data: Sequence[Any]) -> list[Content]:
    +    if isinstance(contents_data, str):
    +        contents_data = [contents_data]
         contents: list[Content] = []

    The docstrings of Message.__init__ and _parse_content_list now say a single string is treated as one text item. New tests in test_types.py cover a bare string passed to Message positionally and by keyword, an empty string (one empty text content, as with [""]), and a bare string passed straight to _parse_content_list. They fail without the change: a 19-character string produces 19 contents, and "" produces none.

  • What is the impact of these changes?

    For the repro in the linked issue, Message("user", "Write a slogan.") now has one text content, and Chat Completions receives one user message instead of 15. Lists, None and every other input are unchanged, and Message.__init__ is the helper's only caller. The sample and the 27 test call sites that pass a bare string now get the message they intended.

  • What do you want reviewers to focus on?

    I kept the contents type hint as it is, since str already satisfies Sequence[str]; I can spell out str | Sequence[...] if you'd like it explicit. A single Content or dict passed without a list is still not accepted, as before. Those aren't sequences of items, so type checkers already flag them, and a single Content raises a TypeError.

Related Issue

Fixes #9326

AI Assistance

  • No material AI assistance was used.
  • This is an AI-assisted contribution. I reviewed, understood, and verified all submitted content and accept responsibility for it.

AI assistance details: I used Claude Code as an assistant to help find the bug and to draft the fix, the tests, the linked issue and this description. I did the final review myself: I read and understood every change, checked the repro and test results, and made the final decisions on what to submit.

Contribution Checklist

  • The code builds clean without any errors or warnings
  • All unit tests pass, and I have added new tests where possible
  • The PR follows the Contribution Guidelines
  • This PR links to an agreed issue with no competing open PR, or the Related Issue section documents a trivial-change or repository-automation exception.
  • This is not a breaking change. If it is a breaking change, add the breaking change label (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.

Message(role, contents) iterated contents directly. A bare string is
itself a sequence of strings, and the contents type hint accepts it, so
Message("user", "Hello") produced one text content per character, which
Chat Completions then sent as one user message per character. Wrap a
bare string in a list so it becomes a single text content, the same as
Message("user", ["Hello"]).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@agent-framework-automation agent-framework-automation Bot added the python Usage: [Issues, PRs], Target: Python label Oct 13, 2026
@eavanvalkenburg

Copy link
Copy Markdown
Member

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAF Automated Review — Iteration 1

Result: No findings
Scope: full PR (1 commit(s)): 55e431ec6065
Model: gpt-5.6-sol

Overview

The change narrowly normalizes a bare string into one content item before the existing parser runs, while leaving None, lists, mixed content, metadata, and serialization paths unchanged. The new positional, keyword, and empty-string tests cover the corrected contract, and existing list and serialization tests constrain regressions. No publishable Critical, High, or Medium issue was established.

Reviewed the supplied pull-request change set across correctness, security/reliability, architecture, and failure behavior.
No publishable findings remained after source verification for this scope.

@eavanvalkenburg

Copy link
Copy Markdown
Member

Aditya Kumar (@Aditya-XR) The current PR template requires an AI Assistance disclosure. Please state whether material AI assistance was used and, if it was, briefly identify the assisted areas.

Comment thread python/packages/core/agent_framework/_types.py Outdated
Review feedback: keep all content-shape parsing in the existing helper
instead of normalizing at the Message constructor. _parse_content_list
now treats a bare string as one text item, and Message.__init__ calls
it unchanged. Adds a helper-level test next to the existing ones.
@Aditya-XR

Copy link
Copy Markdown
Contributor Author

Thanks, I've added the AI Assistance section to the description. Yes, this was AI-assisted: I used Claude Code as an assistant to help find the bug and draft the fix, tests, issue and PR description. The final review was mine: I went through every change and the test results myself before submitting, and I'm happy to answer any questions about it.

@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Oct 15, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Oct 15, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Oct 15, 2026
Merged via the queue into microsoft:main with commit c72f5ea Oct 15, 2026
46 checks passed

This branch was successfully deployed

1 active deployment
github-app-auth — e703de66 Deployed Oct 13, 2026 by Aditya-XR via add_label #25107
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python Usage: [Issues, PRs], Target: Python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python: [Bug]: Message("user", "text") creates one text content per character

3 participants