fix(sessions): handle list content in AdvancedSQLiteSession browsing helpers#3761
Merged
Conversation
…helpers get_conversation_turns() and find_turns_by_content() assumed a stored user message content was always a str. A valid user message can carry a list of structured parts (multimodal input_text/input_image), which the session stores verbatim. get_conversation_turns() then either crashed with TypeError when the list had more than 100 parts (content[:100] + "..." evaluates list + str, which is not caught by its except clause) or returned the raw list in the 'content' field for shorter lists, violating the documented truncated-preview contract. find_turns_by_content() shared the str-only assumption and returned the raw list. Add a small _content_preview helper that coerces non-string content to a JSON string before truncating, so 'content' is always the documented preview string while 'full_content' keeps the original value. Add regression tests covering both the crash and the contract for list content.
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.
AdvancedSQLiteSession.get_conversation_turns()andfind_turns_by_content()assumed a stored user-message
contentis always astr. That holds forplain-text turns, but a valid user message can also carry a list of structured
parts (for example multimodal
input_text/input_imageitems), and the sessionstores each item verbatim via
json.dumps, sojson.loads(...).get("content")hands these helpers a
list.That leads to two problems in
get_conversation_turns(), whose docstring promises'content': User message content (truncated):content[:100] + "..."evaluateslist + strand raisesTypeError: can only concatenate list (not "str") to list. The surroundingexcept (json.JSONDecodeError, AttributeError)does notcatch
TypeError, so the exception propagates out ofasyncio.to_threadandaborts the whole call.
len(content) > 100check isFalse,so the raw list is returned in the
contentfield, which contradicts thedocumented truncated-preview string.
find_turns_by_content()shares the same string-only assumption and returns theraw list in
contenttoo.The fix adds a small module-level
_content_previewhelper that coerces non-stringcontent to a JSON string (
json.dumps(content, ensure_ascii=False)) before applyingthe existing truncation.
get_conversation_turns()uses it with a 100-characterlimit and
find_turns_by_content()uses it without a limit, so each keeps its priorbehavior for string content exactly while now returning the documented preview
string for list content.
full_contentstill keeps the original value in bothhelpers. This mirrors the defensive handling the sibling
_validate_turnalreadydoes for its own preview slice.
Test plan
Added two regression tests in
tests/extensions/memory/test_advanced_sqlite_session.py(the existing suite onlyexercised plain-string content):
test_get_conversation_turns_with_list_contentadds a short list-content turn anda 101-part list-content turn, then asserts
get_conversation_turns()returnswithout raising, that
contentis astrfor both, that the long one istruncated with a trailing
..., and thatfull_contentkeeps the list.test_find_turns_by_content_with_list_contentasserts a list-content match returnsa
strpreview incontentwhilefull_contentkeeps the list.Verified red -> green: reverting only the source change makes
test_get_conversation_turns_with_list_contentfail with theTypeErrorandtest_find_turns_by_content_with_list_contentfail becausecontentis alist;with the fix both pass. Also confirmed the string path is unchanged with an
equivalence check across empty, short, length-100, length-101, longer, and unicode
inputs.
Local checks:
uv run pytest tests/extensions/memory/test_advanced_sqlite_session.py-> 45passed.
uv run pytest tests/extensions/memory/-> 216 passed, 5 skipped(external-service integrations).
make format(no changes),make lintclean,pyrighton the changed module: 0errors.
Issue number
N/A
Checks
.agents/skills/code-change-verification/scripts/run.sh/reviewbefore submitting this PR