fix(langchain): neutralize write_todos tool message#37698
fix(langchain): neutralize write_todos tool message#37698Nick Hollon (nick-hollon-lc) wants to merge 2 commits into
write_todos tool message#37698Conversation
Replaces the verbose tool-message dump ("Updated todo list to [...]")
with a neutral "Todo list updated." acknowledgment. The actual state
still lives in the `todos` field of the `Command` update — only the
text payload returned to the model changes.
Why: inlining the full todo list — especially with `status: completed`
entries on the final call — was priming some models to read the tool
result as "everything done, wrap up briefly" and emit a content-free
recap instead of continuing with the substantive answer. Reducing the
tool message to a plain ack removes that prime.
Restores the inline-dump tool message ("Updated todo list to [...]")
and its matching test parametrize. The neutralization to
"Todo list updated." is being landed as its own PR (#37698) so that
the prompt-only and tool-message-only halves of the loop-contract fix
can be reviewed independently.
Merging this PR will not alter performance
Comparing Footnotes
|
`ruff format` wants the now-shorter message text on a single line.
The previous multi-line layout fit the longer "Updated todo list to
{todos}" payload; "Todo list updated." is short enough to inline.
era (avinashkamat48)
left a comment
There was a problem hiding this comment.
This makes the tool result neutral, but the tests still call write_todos.invoke(...) directly. The duplicated/priming behavior this fixes happens when the middleware returns the Command into an agent state update. Could you add one middleware-level test that verifies the visible tool message is the neutral text while the actual todo state is still preserved in result.update["todos"]?
Replaces the
write_todostool message payload from the verbose"Updated todo list to [...]"dump to a neutral"Todo list updated."acknowledgment.The actual todo state still flows through the
todosfield of theCommandupdate — only the text content returned to the model changes. No behavior change for downstream consumers reading state.Why
Inlining the full todo list into the tool message — especially with
status: completedentries on the final call — was priming some models (notably Anthropic Sonnet 4.6) to read the tool result as "everything done, wrap up briefly" and emit a content-free recap in the next turn instead of continuing with the substantive answer the user asked for. Reducing the tool message to a plain ack removes that prime.This is one half of a paired change. The companion prompt updates to
WRITE_TODOS_SYSTEM_PROMPTandWRITE_TODOS_TOOL_DESCRIPTIONare in #37643 and can land in either order.Notes for review
write_todosand_write_todosboth produce the new ack; behavior parity preserved.test_todo_middleware_write_todos_tool_executionno longer asserts on the inline-dump format; it now asserts on the neutral ack string.