Spaces:
Runtime error
Runtime error
import asyncio | |
from typing import Any, Dict, cast | |
from collections.abc import Callable | |
from anthropic.types.beta import ( | |
BetaContentBlock, | |
BetaContentBlockParam, | |
BetaImageBlockParam, | |
BetaMessage, | |
BetaMessageParam, | |
BetaTextBlockParam, | |
BetaToolResultBlockParam, | |
) | |
from anthropic.types import TextBlock | |
from anthropic.types.beta import BetaMessage, BetaTextBlock, BetaToolUseBlock | |
from tools import ComputerTool, ToolCollection, ToolResult | |
class AnthropicExecutor: | |
def __init__( | |
self, | |
output_callback: Callable[[BetaContentBlockParam], None], | |
tool_output_callback: Callable[[Any, str], None], | |
): | |
self.tool_collection = ToolCollection( | |
ComputerTool() | |
) | |
self.output_callback = output_callback | |
self.tool_output_callback = tool_output_callback | |
def __call__(self, response: BetaMessage, messages: list[BetaMessageParam]): | |
new_message = { | |
"role": "assistant", | |
"content": cast(list[BetaContentBlockParam], response.content), | |
} | |
if new_message not in messages: | |
messages.append(new_message) | |
else: | |
print("new_message already in messages, there are duplicates.") | |
tool_result_content: list[BetaToolResultBlockParam] = [] | |
for content_block in cast(list[BetaContentBlock], response.content): | |
self.output_callback(content_block, sender="bot") | |
# Execute the tool | |
if content_block.type == "tool_use": | |
# Run the asynchronous tool execution in a synchronous context | |
result = asyncio.run(self.tool_collection.run( | |
name=content_block.name, | |
tool_input=cast(dict[str, Any], content_block.input), | |
)) | |
self.output_callback(result, sender="bot") | |
tool_result_content.append( | |
_make_api_tool_result(result, content_block.id) | |
) | |
# self.tool_output_callback(result, content_block.id) | |
# Craft messages based on the content_block | |
# Note: to display the messages in the gradio, you should organize the messages in the following way (user message, bot message) | |
display_messages = _message_display_callback(messages) | |
# display_messages = [] | |
# Send the messages to the gradio | |
for user_msg, bot_msg in display_messages: | |
# yield [user_msg, bot_msg], tool_result_content | |
yield [None, None], tool_result_content | |
if not tool_result_content: | |
return messages | |
return tool_result_content | |
def _message_display_callback(messages): | |
display_messages = [] | |
for msg in messages: | |
try: | |
if isinstance(msg["content"][0], TextBlock): | |
display_messages.append((msg["content"][0].text, None)) # User message | |
elif isinstance(msg["content"][0], BetaTextBlock): | |
display_messages.append((None, msg["content"][0].text)) # Bot message | |
elif isinstance(msg["content"][0], BetaToolUseBlock): | |
display_messages.append((None, f"Tool Use: {msg['content'][0].name}\nInput: {msg['content'][0].input}")) # Bot message | |
elif isinstance(msg["content"][0], Dict) and msg["content"][0]["content"][-1]["type"] == "image": | |
display_messages.append((None, f'<img src="data:image/png;base64,{msg["content"][0]["content"][-1]["source"]["data"]}">')) # Bot message | |
else: | |
print(msg["content"][0]) | |
except Exception as e: | |
print("error", e) | |
pass | |
return display_messages | |
def _make_api_tool_result( | |
result: ToolResult, tool_use_id: str | |
) -> BetaToolResultBlockParam: | |
"""Convert an agent ToolResult to an API ToolResultBlockParam.""" | |
tool_result_content: list[BetaTextBlockParam | BetaImageBlockParam] | str = [] | |
is_error = False | |
if result.error: | |
is_error = True | |
tool_result_content = _maybe_prepend_system_tool_result(result, result.error) | |
else: | |
if result.output: | |
tool_result_content.append( | |
{ | |
"type": "text", | |
"text": _maybe_prepend_system_tool_result(result, result.output), | |
} | |
) | |
if result.base64_image: | |
tool_result_content.append( | |
{ | |
"type": "image", | |
"source": { | |
"type": "base64", | |
"media_type": "image/png", | |
"data": result.base64_image, | |
}, | |
} | |
) | |
return { | |
"type": "tool_result", | |
"content": tool_result_content, | |
"tool_use_id": tool_use_id, | |
"is_error": is_error, | |
} | |
def _maybe_prepend_system_tool_result(result: ToolResult, result_text: str): | |
if result.system: | |
result_text = f"<system>{result.system}</system>\n{result_text}" | |
return result_text |