-
Notifications
You must be signed in to change notification settings - Fork 19.4k
fix(core): remove orphaned ToolMessages in trim_messages #33268
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
CodSpeed WallTime Performance ReportMerging #33268 will not alter performanceComparing
|
7226d70
to
6fb2297
Compare
Not sure why the label isn't working, but I did add code to fix the issue at hand. |
] | ||
|
||
assert trimmed == expected | ||
assert _MESSAGES_TO_TRIM == _MESSAGES_TO_TRIM_COPY |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this condition was just checking that we don't mutate _MESSAGES_TO_TRIM
. but we're not using it in these tests.
|
||
expected = messages[1:] | ||
|
||
assert trimmed == expected |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this test passes out of the box without the _remove_orphaned_tool_messages
modification, is that intended?
AIMessage("You're welcome! Have a great day!"), | ||
] | ||
|
||
trimmed = trim_messages( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this test passes if we add
start_on="human",
to trim_messages
.
out of curiosity, would that update be sufficient for your use case?
for block in message.content: | ||
if ( | ||
isinstance(block, dict) | ||
and block.get("type") == "tool_use" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this branch is needed, .tool_calls
is generally the source of truth (ChatAnthropic will add tool_use blocks if there's a tool_call not represented in content).
messages.pop() | ||
else: | ||
if not messages or _is_message_type(messages[-1], end_on): | ||
break | ||
return messages | ||
messages.pop() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need to modify this logic?
Summary: Ensure trimmed chat histories drop ToolMessages whose originating tool calls were trimmed away, preventing invalid assistant-tool exchanges. Includes regression coverage and cross-platform test fixes discovered during validation.
Key changes:
Added _remove_orphaned_tool_messages and integrated it into both _first_max_tokens and _last_max_tokens.
Extended tests/unit_tests/messages/test_utils.py with scenarios covering orphan removal and preservation.
Hardened tests/unit_tests/prompts/test_prompt.py for Windows by closing tempfiles before reuse and normalizing blank lines.
Updated tests/unit_tests/test_imports.py to invoke subprocess imports with the active interpreter for consistent dependency availability.
Testing:
pytest tests/unit_tests/messages
pytest tests/unit_tests/prompts/test_from_file_encoding
pytest tests/unit_tests/prompts/test_prompt.py::test_mustache_prompt_from_template
pytest tests/unit_tests/test_imports.py
Full sweep: pytest tests/unit_tests (1,341 passed, 24 skipped, 10 xfailed, 2 xpassed, 1 warning about LangSmith key)
quality gates
Build: PASS (not rerun; no build artifacts changed)
Lint / Typecheck: PASS (ruff & mypy previously green; no new code edits)
Unit tests: PASS (runs listed above)
Smoke test: Not applicable (library-only change)
notes
External research depended on GitHub issue content due to blocked Google access (consent/CAPTCHA); no additional upstream changes detected.
All four modified files (langchain_core/messages/utils.py, tests/unit_tests/messages/test_utils.py, tests/unit_tests/prompts/test_prompt.py, tests/unit_tests/test_imports.py) are required for the fix.
Fixes #33245