This commit is contained in:
2026-02-21 19:44:47 -05:00
parent 74737b0f70
commit eb347d6b01
3 changed files with 298 additions and 94 deletions

View File

@@ -417,13 +417,44 @@ def _strip_cache_controls(history: list[dict]):
if isinstance(block, dict):
block.pop("cache_control", None)
def _repair_anthropic_history(history: list[dict]):
"""
If history ends with an assistant message that contains tool_use blocks
without a following user tool_result message, append a synthetic tool_result
message so the history is valid before the next request.
"""
if not history:
return
last = history[-1]
if last.get("role") != "assistant":
return
content = last.get("content", [])
# Find tool_use blocks (content may be a list of dicts or SDK objects)
tool_use_ids = []
for block in content:
if isinstance(block, dict):
if block.get("type") == "tool_use":
tool_use_ids.append(block["id"])
else:
# SDK object
if getattr(block, "type", None) == "tool_use":
tool_use_ids.append(block.id)
if not tool_use_ids:
return
# Append a synthetic tool_result for each dangling tool_use
history.append({
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": tid,
"content": "Tool call was not completed (session interrupted).",
}
for tid in tool_use_ids
],
})
def _send_anthropic(md_content: str, user_message: str, base_dir: str) -> str:
"""
Send via Anthropic using chunked inline text.
Context is split into <=_ANTHROPIC_CHUNK_SIZE char blocks with
cache_control:ephemeral on the last block, then the user message is appended.
"""
try:
_ensure_anthropic_client()
@@ -434,6 +465,7 @@ def _send_anthropic(md_content: str, user_message: str, base_dir: str) -> str:
]
_strip_cache_controls(_anthropic_history)
_repair_anthropic_history(_anthropic_history)
_anthropic_history.append({"role": "user", "content": user_content})
n_chunks = len(context_blocks)
@@ -513,9 +545,25 @@ def _send_anthropic(md_content: str, user_message: str, base_dir: str) -> str:
"tool_use_id": block.id,
"content": output,
})
elif block.type == "tool_use":
# Unknown tool - return an error result so history stays valid
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": f"ERROR: unknown tool '{block.name}'",
})
# Always append tool_results when stop_reason was tool_use,
# even if the list is somehow empty (shouldn't happen, but be safe)
if not tool_results:
break
# Synthesise a result for every tool_use block to keep history valid
for block in response.content:
if block.type == "tool_use":
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": "ERROR: tool could not be executed.",
})
_anthropic_history.append({
"role": "user",