diff --git a/src/google/adk/models/anthropic_llm.py b/src/google/adk/models/anthropic_llm.py index a3a0e096..15d78d72 100644 --- a/src/google/adk/models/anthropic_llm.py +++ b/src/google/adk/models/anthropic_llm.py @@ -16,6 +16,7 @@ from __future__ import annotations +import base64 from functools import cached_property import logging import os @@ -45,7 +46,7 @@ __all__ = ["Claude"] logger = logging.getLogger("google_adk." + __name__) -MAX_TOKEN = 1024 +MAX_TOKEN = 8192 class ClaudeRequest(BaseModel): @@ -70,6 +71,14 @@ def to_google_genai_finish_reason( return "FINISH_REASON_UNSPECIFIED" +def _is_image_part(part: types.Part) -> bool: + return ( + part.inline_data + and part.inline_data.mime_type + and part.inline_data.mime_type.startswith("image") + ) + + def part_to_message_block( part: types.Part, ) -> Union[ @@ -80,7 +89,7 @@ def part_to_message_block( ]: if part.text: return anthropic_types.TextBlockParam(text=part.text, type="text") - if part.function_call: + elif part.function_call: assert part.function_call.name return anthropic_types.ToolUseBlockParam( @@ -89,7 +98,7 @@ def part_to_message_block( input=part.function_call.args, type="tool_use", ) - if part.function_response: + elif part.function_response: content = "" if ( "result" in part.function_response.response @@ -105,15 +114,45 @@ def part_to_message_block( content=content, is_error=False, ) - raise NotImplementedError("Not supported yet.") + elif _is_image_part(part): + data = base64.b64encode(part.inline_data.data).decode() + return anthropic_types.ImageBlockParam( + type="image", + source=dict( + type="base64", media_type=part.inline_data.mime_type, data=data + ), + ) + elif part.executable_code: + return anthropic_types.TextBlockParam( + type="text", + text="Code:```python\n" + part.executable_code.code + "\n```", + ) + elif part.code_execution_result: + return anthropic_types.TextBlockParam( + text="Execution Result:```code_output\n" + + part.code_execution_result.output + + "\n```", + type="text", + ) + + raise NotImplementedError(f"Not supported yet: {part}") def content_to_message_param( content: types.Content, ) -> anthropic_types.MessageParam: + message_block = [] + for part in content.parts or []: + # Image data is not supported in Claude for model turns. + if _is_image_part(part): + logger.warning("Image data is not supported in Claude for model turns.") + continue + + message_block.append(part_to_message_block(part)) + return { "role": to_claude_role(content.role), - "content": [part_to_message_block(part) for part in content.parts or []], + "content": message_block, }