Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions libs/langchain_v1/langchain/agents/middleware/todo.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)],
}
)

Expand All @@ -149,9 +149,7 @@ def _write_todos(
return Command(
update={
"todos": todos,
"messages": [
ToolMessage(f"Updated todo list to {todos}", tool_call_id=runtime.tool_call_id)
],
"messages": [ToolMessage("Todo list updated.", tool_call_id=runtime.tool_call_id)],
}
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -296,43 +296,32 @@ def mock_handler(req: ModelRequest) -> ModelResponse:


@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",
Expand All @@ -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(
Expand Down
Loading