fix(cli): TypeError concatenating queued note onto multimodal (image) message#37173
Merged
Conversation
Sending an image to a vision model turns the user message into a list of
OpenAI-style content parts. When a /model or /reload-skills note was queued
for the same turn, the CLI did `note + "\n\n" + agent_message`, crashing the
agent thread with:
TypeError: can only concatenate str (not "list") to str
Repro: `/model gpt-5.5 --provider openai-codex`, then paste+send an image.
Add _prepend_note_to_message(), which folds the note into the first text
part of a content-parts list (or inserts a leading text part for image-only
messages) and keeps the plain-string path unchanged. Used for both the
model-switch and skills-reload notes.
Regression coverage for the multimodal-message TypeError: note folding into text parts, image-only insertion, empty-note passthrough, and unknown-shape fail-open.
Adopt the cleaner handling from PR #37080: coerce/strip the note and skip the extra newlines when the underlying message (or text part) is empty, while keeping the safer fail-open behavior for unknown shapes.
Contributor
🔎 Lint report:
|
| Rule | Count |
|---|---|
invalid-argument-type |
1 |
First entries
cli.py:2143: [invalid-argument-type] invalid-argument-type: Argument to bound method `dict.get` is incorrect: Expected `Never`, found `Literal["type"]`
✅ Fixed issues: none
Unchanged: 4984 pre-existing issues carried over.
Diagnostics are surfaced as warnings — this check never fails the build.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The interactive CLI no longer crashes when a queued
/modelor/reload-skillsnote is prepended to a message that has an attached image.Root cause: the two prepend sites did
note + "\n\n" + agent_message, butagent_messagebecomes a list of OpenAI content parts (text +image_url) when an image is attached to a vision-capable model — raisingTypeError: can only concatenate str (not "list") to strin the agent thread.Changes
cli.py: new_prepend_note_to_message(message, note)helper — string → prepend; multimodal list → fold note into first text part (or insert a leading text block when image-only); unknown shapes returned unchanged (fail-open). Both prepend sites now route through it.tests/cli/test_prepend_note_to_message.py: 9 tests covering string, empty note, image-only, text+image, empty-text-part, no-mutation, and the exact repro shape.Validation
/model …+ pasted image same turnTypeErrorcrash in agent threadTargeted tests: 9/9 pass. E2E confirmed the old line raises the exact reported
TypeErrorand the helper handles the image-only repro without mutating the original message. The_voice_prefixconcat site is alreadyisinstance(message, str)-guarded, so these were the only two vulnerable sites.Salvage of #37081 by @xxxigm (cherry-picked, authorship preserved). Also fixes the same crash reported in #37080 by @helix4u, who closed his own PR in favor of this one's fuller test coverage — both contributors credited.
Infographic