Skip to content
Closed
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
19 changes: 12 additions & 7 deletions instructor/v2/providers/anthropic/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -426,31 +426,36 @@ def handle_reask(
return kwargs

assistant_content = []
tool_use_id = None
# Anthropic requires a tool_result for *every* tool_use in the prior turn.
# Collect all ids — overwriting a single id drops results for PARALLEL_TOOLS
# and makes the reask request fail with 400 (issue #2485).
tool_use_ids: list[str] = []
for content in response.content:
try:
dumped_content = content.model_dump(exclude_none=True) # type: ignore[attr-defined]
except TypeError:
dumped_content = content.model_dump() # type: ignore[attr-defined]
assistant_content.append(dumped_content)
if content.type == "tool_use":
tool_use_id = content.id
tool_use_ids.append(content.id)

reask_msgs = [{"role": "assistant", "content": assistant_content}]
if tool_use_id is not None:
if tool_use_ids:
error_content = (
"Validation Error found:\n"
f"{exception}\nRecall the function correctly, fix the errors"
)
reask_msgs.append(
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": tool_use_id,
"content": (
"Validation Error found:\n"
f"{exception}\nRecall the function correctly, fix the errors"
),
"content": error_content,
"is_error": True,
}
for tool_use_id in tool_use_ids
],
}
)
Expand Down
9 changes: 8 additions & 1 deletion tests/coverage/test_anthropic_handlers_coverage.py
Original file line number Diff line number Diff line change
Expand Up @@ -580,7 +580,14 @@ def test_parallel_tools_prepare_reask_and_parse_real_tool_blocks() -> None:
assert list(handler.parse_response(None, parallel_type)) == []
assert list(handler.parse_response(object(), parallel_type)) == []
reask = handler.handle_reask({"messages": []}, response, ValueError("bad job"))
assert reask["messages"][-1]["content"][0]["tool_use_id"] == "toolu_three"
# Anthropic requires a tool_result for *every* tool_use block (#2485).
reask_results = reask["messages"][-1]["content"]
assert [block["tool_use_id"] for block in reask_results] == [
"toolu_one",
"toolu_two",
"toolu_three",
]
assert all(block.get("is_error") is True for block in reask_results)


def test_json_prepare_reask_and_parse_anthropic_and_openai_shaped_responses() -> None:
Expand Down