修复完成。主要改动: 1. 新增 _clean_content_blocks 方法:专门处理 content 字段的清理 - 当 content 是列表格式时,过滤掉 type: 'tool_use' 的块(如果 id 不在 valid_tool_call_ids 中) - 返回清理后的 content 和是否有文本内容的标志 2. 更新 _cleanup_tool_use_messages 方法: - 调用 _clean_content_blocks 来清理 content - 使用清理后的 cleaned_content 创建新的 AIMessage 问题根源:之前的代码只清空了 tool_calls=[],但没有从 content 列表中移除 type: 'tool_use' 的块。Anthropic API 会检查这两个地方,导致报错。
This commit is contained in:
parent
584f10b5e4
commit
b8e00d403c
@ -66,6 +66,45 @@ class ToolUseCleanupMiddleware(AgentMiddleware):
|
|||||||
# Other types, treat as having content if it's truthy
|
# Other types, treat as having content if it's truthy
|
||||||
return bool(content)
|
return bool(content)
|
||||||
|
|
||||||
|
def _clean_content_blocks(self, content: Any, valid_tool_call_ids: set[str]) -> tuple[Any, bool]:
|
||||||
|
"""
|
||||||
|
Clean up content blocks by removing orphaned tool_use blocks.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
content: The content to clean (can be str, list, or other)
|
||||||
|
valid_tool_call_ids: Set of valid tool_call_ids to keep
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Tuple of (cleaned_content, has_meaningful_content)
|
||||||
|
"""
|
||||||
|
if isinstance(content, str):
|
||||||
|
return content, bool(content.strip())
|
||||||
|
elif isinstance(content, list):
|
||||||
|
# Filter out tool_use blocks that don't have valid ids
|
||||||
|
cleaned_blocks = []
|
||||||
|
has_text_content = False
|
||||||
|
|
||||||
|
for block in content:
|
||||||
|
if isinstance(block, dict):
|
||||||
|
block_type = block.get('type')
|
||||||
|
if block_type == 'tool_use':
|
||||||
|
# Only keep tool_use blocks with valid ids
|
||||||
|
tool_id = block.get('id')
|
||||||
|
if tool_id in valid_tool_call_ids:
|
||||||
|
cleaned_blocks.append(block)
|
||||||
|
elif block_type == 'text' and block.get('text', '').strip():
|
||||||
|
cleaned_blocks.append(block)
|
||||||
|
has_text_content = True
|
||||||
|
else:
|
||||||
|
# Keep other block types (images, etc.)
|
||||||
|
cleaned_blocks.append(block)
|
||||||
|
else:
|
||||||
|
cleaned_blocks.append(block)
|
||||||
|
|
||||||
|
return cleaned_blocks, has_text_content
|
||||||
|
else:
|
||||||
|
return content, bool(content)
|
||||||
|
|
||||||
def _cleanup_tool_use_messages(self, messages: list[AnyMessage]) -> list[AnyMessage]:
|
def _cleanup_tool_use_messages(self, messages: list[AnyMessage]) -> list[AnyMessage]:
|
||||||
"""
|
"""
|
||||||
Clean up messages by removing tool_use blocks that don't have corresponding tool_results.
|
Clean up messages by removing tool_use blocks that don't have corresponding tool_results.
|
||||||
@ -98,21 +137,25 @@ class ToolUseCleanupMiddleware(AgentMiddleware):
|
|||||||
]
|
]
|
||||||
|
|
||||||
removed_count = len(current_msg.tool_calls) - len(filtered_tool_calls)
|
removed_count = len(current_msg.tool_calls) - len(filtered_tool_calls)
|
||||||
|
removed_ids = [tc.get('id') for tc in current_msg.tool_calls if tc.get('id') not in valid_tool_call_ids]
|
||||||
|
|
||||||
if removed_count > 0:
|
if removed_count > 0:
|
||||||
self.stats['removed_tool_calls'] += removed_count
|
self.stats['removed_tool_calls'] += removed_count
|
||||||
logger.warning(
|
logger.warning(
|
||||||
f"Removed {removed_count} orphaned tool_use(s) from AIMessage. "
|
f"Removed {removed_count} orphaned tool_use(s) from AIMessage. "
|
||||||
f"tool_call_ids: {[tc.get('id') for tc in current_msg.tool_calls]}, "
|
f"tool_call_ids: {removed_ids}, "
|
||||||
f"valid_ids: {valid_tool_call_ids}"
|
f"valid_ids: {valid_tool_call_ids}"
|
||||||
)
|
)
|
||||||
|
|
||||||
has_content = self._has_meaningful_content(current_msg)
|
# Clean content blocks to remove orphaned tool_use blocks
|
||||||
|
cleaned_content, has_meaningful_content = self._clean_content_blocks(
|
||||||
|
current_msg.content, valid_tool_call_ids
|
||||||
|
)
|
||||||
|
|
||||||
if filtered_tool_calls:
|
if filtered_tool_calls:
|
||||||
# Has valid tool_calls, keep the message
|
# Has valid tool_calls, keep the message
|
||||||
cleaned_msg = AIMessage(
|
cleaned_msg = AIMessage(
|
||||||
content=current_msg.content,
|
content=cleaned_content,
|
||||||
tool_calls=filtered_tool_calls,
|
tool_calls=filtered_tool_calls,
|
||||||
additional_kwargs=current_msg.additional_kwargs,
|
additional_kwargs=current_msg.additional_kwargs,
|
||||||
response_metadata=current_msg.response_metadata,
|
response_metadata=current_msg.response_metadata,
|
||||||
@ -120,10 +163,10 @@ class ToolUseCleanupMiddleware(AgentMiddleware):
|
|||||||
name=current_msg.name,
|
name=current_msg.name,
|
||||||
)
|
)
|
||||||
cleaned_messages.append(cleaned_msg)
|
cleaned_messages.append(cleaned_msg)
|
||||||
elif has_content:
|
elif has_meaningful_content:
|
||||||
# No valid tool_calls but has meaningful content, keep without tool_calls
|
# No valid tool_calls but has meaningful content, keep without tool_calls
|
||||||
cleaned_msg = AIMessage(
|
cleaned_msg = AIMessage(
|
||||||
content=current_msg.content,
|
content=cleaned_content,
|
||||||
tool_calls=[],
|
tool_calls=[],
|
||||||
additional_kwargs=current_msg.additional_kwargs,
|
additional_kwargs=current_msg.additional_kwargs,
|
||||||
response_metadata=current_msg.response_metadata,
|
response_metadata=current_msg.response_metadata,
|
||||||
@ -134,14 +177,14 @@ class ToolUseCleanupMiddleware(AgentMiddleware):
|
|||||||
self.stats['cleaned_ai_messages'] += 1
|
self.stats['cleaned_ai_messages'] += 1
|
||||||
logger.info(
|
logger.info(
|
||||||
f"Removed all tool_calls from AIMessage but kept content. "
|
f"Removed all tool_calls from AIMessage but kept content. "
|
||||||
f"Content preview: {current_msg.content[:50]}..."
|
f"Content preview: {str(cleaned_content)[:200]}..."
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
# No valid tool_calls and no meaningful content, completely remove this message
|
# No valid tool_calls and no meaningful content, completely remove this message
|
||||||
self.stats['removed_ai_messages'] += 1
|
self.stats['removed_ai_messages'] += 1
|
||||||
logger.info(
|
logger.info(
|
||||||
f"Removed entire AIMessage with orphaned tool_calls (no meaningful content). "
|
f"Removed entire AIMessage with orphaned tool_calls (no meaningful content). "
|
||||||
f"Removed tool_call_ids: {[tc.get('id') for tc in current_msg.tool_calls]}"
|
f"Removed tool_call_ids: {removed_ids}"
|
||||||
)
|
)
|
||||||
# Don't add to cleaned_messages - skip this message entirely
|
# Don't add to cleaned_messages - skip this message entirely
|
||||||
else:
|
else:
|
||||||
|
|||||||
14
mcp/mcp_settings_deep_agent.json
Normal file
14
mcp/mcp_settings_deep_agent.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"rag_retrieve": {
|
||||||
|
"transport": "stdio",
|
||||||
|
"command": "python",
|
||||||
|
"args": [
|
||||||
|
"./mcp/rag_retrieve_server.py",
|
||||||
|
"{bot_id}"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
Loading…
Reference in New Issue
Block a user