Skip to content

fix(core): render list content in BaseMessage.pretty_repr()#35402

Open
Balaji Seshadri (gitbalaji) wants to merge 1 commit intolangchain-ai:masterfrom
gitbalaji:fix/core-pretty-repr-list-content
Open

fix(core): render list content in BaseMessage.pretty_repr()#35402
Balaji Seshadri (gitbalaji) wants to merge 1 commit intolangchain-ai:masterfrom
gitbalaji:fix/core-pretty-repr-list-content

Conversation

@gitbalaji
Copy link
Contributor

Summary

Fixes #34875.

  • pretty_repr() used f"{title}\n\n{self.content}" directly. When content is a list (a valid and documented type for BaseMessage.content), Python's list.__repr__() was used, producing raw output like ['First', 'Second', 'Third'] instead of the actual text.
  • A # TODO: handle non-string content. comment in the code already acknowledged this gap.
  • Fix: add _render_content_blocks() helper that extracts text from string items, {"type": "text", "text": "..."} dicts, and renders other block types (images, tool_use, etc.) as [type] placeholders. pretty_repr() now dispatches to this helper when content is a list.
  • No behavior change for string content or for html=True (title bolding is unaffected).

Areas requiring careful review

  • _render_content_blocks joins blocks with "\n". An alternative would be "" (no separator), matching the behavior of text property. Newline separation feels more readable for a pretty-print method.
  • Non-text blocks render as [type] placeholders (e.g. [image_url], [tool_use]). This is intentionally minimal — pretty_repr is a human-readable summary, not a full serialization.

Test plan

  • test_pretty_repr_list_of_strings — list of strings joined, no Python repr leak
  • test_pretty_repr_list_with_text_blocks{"type": "text"} dicts render their text
  • test_pretty_repr_list_with_non_text_blocks — non-text blocks render as [type]
  • test_pretty_repr_mixed_list_content — mixed string + dict blocks all render
  • test_pretty_repr_with_name — name field still included with list content
  • test_pretty_repr_html_list_contenthtml=True unaffected
  • test_pretty_repr_empty_list_content — empty list renders without error
  • test_pretty_repr_string_content / test_pretty_repr_html_does_not_regress_string_content — no regression for string content

AI disclaimer: This PR was developed with assistance from Claude Code (Anthropic).

🤖 Generated with Claude Code

@github-actions github-actions bot added core `langchain-core` package issues & PRs fix For PRs that implement a fix external labels Feb 22, 2026
@codspeed-hq
Copy link

codspeed-hq bot commented Feb 22, 2026

Merging this PR will degrade performance by 22.16%

⚠️ Unknown Walltime execution environment detected

Using the Walltime instrument on standard Hosted Runners will lead to inconsistent data.

For the most accurate results, we recommend using CodSpeed Macro Runners: bare-metal machines fine-tuned for performance measurement consistency.

❌ 11 regressed benchmarks
✅ 2 untouched benchmarks
⏩ 23 skipped benchmarks1

⚠️ Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
WallTime test_import_time[PydanticOutputParser] 477.6 ms 554.8 ms -13.92%
WallTime test_import_time[HumanMessage] 239.3 ms 267.6 ms -10.58%
WallTime test_import_time[tool] 473.5 ms 553.9 ms -14.53%
WallTime test_async_callbacks_in_sync 18.4 ms 23.6 ms -22.16%
WallTime test_import_time[RunnableLambda] 442 ms 504.5 ms -12.39%
WallTime test_import_time[CallbackManager] 286.4 ms 327.9 ms -12.67%
WallTime test_import_time[BaseChatModel] 482.7 ms 538.3 ms -10.33%
WallTime test_import_time[Runnable] 444.5 ms 500.2 ms -11.14%
WallTime test_import_time[ChatPromptTemplate] 549.8 ms 656.6 ms -16.27%
WallTime test_import_time[InMemoryRateLimiter] 158.6 ms 177.5 ms -10.61%
WallTime test_import_time[LangChainTracer] 410.6 ms 459.3 ms -10.59%

Comparing gitbalaji:fix/core-pretty-repr-list-content (57393d2) with master (2d1492a)2

Open in CodSpeed

Footnotes

  1. 23 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

  2. No successful run was found on master (0b975d4) during the generation of this report, so 2d1492a was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@gitbalaji
Copy link
Contributor Author

CodSpeed regression is a false positive

The flagged benchmark test_async_callbacks_in_sync (18.4ms → 24.3ms) has no relationship to this change.

Why it cannot be caused by our fix:

  • The benchmark creates AIMessage(content=" ".join(["hello", "goodbye"] * 5)) — plain string content
  • It benchmarks async callback streaming via model.stream()
  • It never calls pretty_repr() at all

Our change only touches pretty_repr() (adds a list branch) and adds _render_content_blocks() as a module-level helper. Neither is on any import or call path exercised by this benchmark.

The ~6ms variance on a ~20ms walltime measurement on shared GitHub Actions runners is well within noise. CodSpeed itself warns: "Using the Walltime instrument on standard Hosted Runners will lead to inconsistent data."

Previously, `pretty_repr()` used `f"{title}\n\n{self.content}"` which
fell back to Python's `list.__repr__()` when `content` was a list,
producing output like `['First', 'Second', 'Third']` instead of the
actual text. A `# TODO: handle non-string content.` comment acknowledged
this gap.

Fixes langchain-ai#34875.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@gitbalaji Balaji Seshadri (gitbalaji) force-pushed the fix/core-pretty-repr-list-content branch from 57393d2 to 03af237 Compare February 27, 2026 19:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core `langchain-core` package issues & PRs external fix For PRs that implement a fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

pretty_repr(html=True) does not always return HTML-formatted output for non-string content

2 participants