mirror of
https://github.com/hwchase17/langchain.git
synced 2026-07-12 02:55:21 +00:00
fix(langchain): neutralize write_todos tool message
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.
This commit is contained in:
@@ -136,7 +136,7 @@ def write_todos(
|
||||
return Command(
|
||||
update={
|
||||
"todos": todos,
|
||||
"messages": [ToolMessage(f"Updated todo list to {todos}", tool_call_id=tool_call_id)],
|
||||
"messages": [ToolMessage("Todo list updated.", tool_call_id=tool_call_id)],
|
||||
}
|
||||
)
|
||||
|
||||
@@ -150,7 +150,7 @@ def _write_todos(
|
||||
update={
|
||||
"todos": todos,
|
||||
"messages": [
|
||||
ToolMessage(f"Updated todo list to {todos}", tool_call_id=runtime.tool_call_id)
|
||||
ToolMessage("Todo list updated.", tool_call_id=runtime.tool_call_id)
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
@@ -296,43 +296,32 @@ def test_todo_middleware_custom_system_prompt_and_tool_description() -> None:
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("todos", "expected_message"),
|
||||
"todos",
|
||||
[
|
||||
([], "Updated todo list to []"),
|
||||
(
|
||||
[{"content": "Task 1", "status": "pending"}],
|
||||
"Updated todo list to [{'content': 'Task 1', 'status': 'pending'}]",
|
||||
),
|
||||
(
|
||||
[
|
||||
{"content": "Task 1", "status": "pending"},
|
||||
{"content": "Task 2", "status": "in_progress"},
|
||||
],
|
||||
(
|
||||
"Updated todo list to ["
|
||||
"{'content': 'Task 1', 'status': 'pending'}, "
|
||||
"{'content': 'Task 2', 'status': 'in_progress'}]"
|
||||
),
|
||||
),
|
||||
(
|
||||
[
|
||||
{"content": "Task 1", "status": "pending"},
|
||||
{"content": "Task 2", "status": "in_progress"},
|
||||
{"content": "Task 3", "status": "completed"},
|
||||
],
|
||||
(
|
||||
"Updated todo list to ["
|
||||
"{'content': 'Task 1', 'status': 'pending'}, "
|
||||
"{'content': 'Task 2', 'status': 'in_progress'}, "
|
||||
"{'content': 'Task 3', 'status': 'completed'}]"
|
||||
),
|
||||
),
|
||||
[],
|
||||
[{"content": "Task 1", "status": "pending"}],
|
||||
[
|
||||
{"content": "Task 1", "status": "pending"},
|
||||
{"content": "Task 2", "status": "in_progress"},
|
||||
],
|
||||
[
|
||||
{"content": "Task 1", "status": "pending"},
|
||||
{"content": "Task 2", "status": "in_progress"},
|
||||
{"content": "Task 3", "status": "completed"},
|
||||
],
|
||||
],
|
||||
)
|
||||
def test_todo_middleware_write_todos_tool_execution(
|
||||
todos: list[dict[str, Any]], expected_message: str
|
||||
todos: list[dict[str, Any]],
|
||||
) -> None:
|
||||
"""Test that the write_todos tool executes correctly."""
|
||||
"""Test that the write_todos tool executes correctly.
|
||||
|
||||
The tool message is a neutral "Todo list updated." ack; the actual
|
||||
state lives in the `todos` field of the Command update. Dumping the
|
||||
full list inline (including `status: completed` entries) was priming
|
||||
some models to interpret the tool result as "everything done, wrap
|
||||
up briefly" instead of continuing to deliver the substantive answer.
|
||||
"""
|
||||
tool_call = {
|
||||
"args": {"todos": todos},
|
||||
"name": "write_todos",
|
||||
@@ -341,7 +330,7 @@ def test_todo_middleware_write_todos_tool_execution(
|
||||
}
|
||||
result = write_todos.invoke(tool_call)
|
||||
assert result.update["todos"] == todos
|
||||
assert result.update["messages"][0].content == expected_message
|
||||
assert result.update["messages"][0].content == "Todo list updated."
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
||||
Reference in New Issue
Block a user