From 26a3094d608eea3647c4fc7e05d77a1cccb333c3 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 18 Sep 2026 09:05:55 -0400 Subject: [PATCH] Use ToolResult in anthropic (#182542) Co-authored-by: Claude --- homeassistant/components/anthropic/entity.py | 33 +++++++++++-------- .../snapshots/test_conversation.ambr | 15 ++++++--- .../components/anthropic/test_conversation.py | 2 ++ 3 files changed, 31 insertions(+), 19 deletions(-) diff --git a/homeassistant/components/anthropic/entity.py b/homeassistant/components/anthropic/entity.py index 87a4340016f1..89c9aa3d5a5e 100644 --- a/homeassistant/components/anthropic/entity.py +++ b/homeassistant/components/anthropic/entity.py @@ -245,11 +245,11 @@ def _convert_content( # noqa: C901 "tool_use_id": content.tool_call_id, "content": cast( WebSearchToolResultBlockParamContentParam, - content.tool_result["content"] - if "content" in content.tool_result + content.result.data["content"] + if "content" in content.result.data else { "type": "web_search_tool_result_error", - "error_code": content.tool_result.get( + "error_code": content.result.data.get( "error_code", "unavailable" ), }, @@ -261,7 +261,7 @@ def _convert_content( # noqa: C901 "tool_use_id": content.tool_call_id, "content": cast( CodeExecutionToolResultBlockParamContentParam, - content.tool_result, + content.result.data, ), } elif content.tool_name == "bash_code_execution": @@ -270,7 +270,7 @@ def _convert_content( # noqa: C901 "tool_use_id": content.tool_call_id, "content": cast( BashCodeExecutionToolResultBlockParamContentParam, - content.tool_result, + content.result.data, ), } elif content.tool_name == "text_editor_code_execution": @@ -279,7 +279,7 @@ def _convert_content( # noqa: C901 "tool_use_id": content.tool_call_id, "content": cast( TextEditorCodeExecutionToolResultBlockParamContentParam, - content.tool_result, + content.result.data, ), } elif content.tool_name == "tool_search": @@ -288,7 +288,7 @@ def _convert_content( # noqa: C901 "tool_use_id": content.tool_call_id, "content": cast( ToolSearchToolResultBlockParamContentParam, - content.tool_result, + content.result.data, ), } elif content.tool_name == "web_fetch": @@ -297,14 +297,15 @@ def _convert_content( # noqa: C901 "tool_use_id": content.tool_call_id, "content": cast( WebFetchToolResultBlockParamContentParam, - content.tool_result, + content.result.data, ), } else: tool_result_block = { "type": "tool_result", "tool_use_id": content.tool_call_id, - "content": json_dumps(content.tool_result), + "content": json_dumps(content.result.data), + "is_error": content.result.error, } external_tool = False if not messages or messages[-1]["role"] != ( @@ -780,11 +781,15 @@ class AnthropicDeltaStream: "role": "tool_result", "tool_call_id": tool_use_id, "tool_name": tool_name.removesuffix("_tool_result"), - "tool_result": { - "content": cast(JsonArrayType, [x.to_dict() for x in content]) - } - if isinstance(content, list) - else cast(JsonObjectType, content.to_dict()), + "result": llm.ToolResult( + data={ + "content": cast(JsonArrayType, [x.to_dict() for x in content]) + } + if isinstance(content, list) + else cast(JsonObjectType, content.to_dict()), + error=not isinstance(content, list) + and content.type.endswith("_tool_result_error"), + ), } ) self._first_block = True diff --git a/tests/components/anthropic/snapshots/test_conversation.ambr b/tests/components/anthropic/snapshots/test_conversation.ambr index 5f81ce18156e..bfd402739427 100644 --- a/tests/components/anthropic/snapshots/test_conversation.ambr +++ b/tests/components/anthropic/snapshots/test_conversation.ambr @@ -141,7 +141,7 @@ 'error_code': 'unavailable', 'type': 'bash_code_execution_tool_result_error', }), - 'error': False, + 'error': True, }), 'role': 'tool_result', 'tool_call_id': 'srvtoolu_12345ABC', @@ -500,6 +500,7 @@ 'content': list([ dict({ 'content': '"Test response"', + 'is_error': False, 'tool_use_id': 'toolu_0123456789AbCdEfGhIjKlM', 'type': 'tool_result', }), @@ -666,11 +667,13 @@ }), dict({ 'content': '{"success":true,"response":"Lights are off."}', + 'is_error': False, 'tool_use_id': 'mock-tool-call-id', 'type': 'tool_result', }), dict({ 'content': '{"success":false,"response":"Not enough milk."}', + 'is_error': False, 'tool_use_id': 'mock-tool-call-id-2', 'type': 'tool_result', }), @@ -922,6 +925,7 @@ 'content': list([ dict({ 'content': '{"speech_slots":{"time":"14:30:00"},"message":"Current time retrieved"}', + 'is_error': False, 'tool_use_id': 'mock-tool-call-id', 'type': 'tool_result', }), @@ -1008,6 +1012,7 @@ 'content': list([ dict({ 'content': '{"speech":{"plain":{"speech":"The Hygrostat is set to 50%","extra_data":null}},"response_type":"action_done","data":{"success":[],"failed":[]}}', + 'is_error': False, 'tool_use_id': 'toolu_01KNRWb3ZFufCa7WXtzCakhc', 'type': 'tool_result', }), @@ -1439,7 +1444,7 @@ 'error_message': 'Tool response parsing error for view: Failed to parse tool response as JSON: unexpected character: line 1 column 1 (char 0)', 'type': 'text_editor_code_execution_tool_result_error', }), - 'error': False, + 'error': True, }), 'role': 'tool_result', 'tool_call_id': 'srvtoolu_12345ABC', @@ -1696,7 +1701,7 @@ 'error_code': 'too_many_requests', 'type': 'tool_search_tool_result_error', }), - 'error': False, + 'error': True, }), 'role': 'tool_result', 'tool_call_id': 'srvtoolu_12345ABC', @@ -2037,7 +2042,7 @@ 'error_code': 'url_not_allowed', 'type': 'web_fetch_tool_result_error', }), - 'error': False, + 'error': True, }), 'role': 'tool_result', 'tool_call_id': 'srvtoolu_12345ABC', @@ -2574,7 +2579,7 @@ 'error_code': 'too_many_requests', 'type': 'web_search_tool_result_error', }), - 'error': False, + 'error': True, }), 'role': 'tool_result', 'tool_call_id': 'srvtoolu_12345ABC', diff --git a/tests/components/anthropic/test_conversation.py b/tests/components/anthropic/test_conversation.py index 787e81e541c7..b1b409ab052a 100644 --- a/tests/components/anthropic/test_conversation.py +++ b/tests/components/anthropic/test_conversation.py @@ -473,6 +473,7 @@ async def test_function_call( "content": [ { "content": '"Test response"', + "is_error": False, "tool_use_id": "toolu_0123456789AbCdEfGhIjKlM", "type": "tool_result", } @@ -550,6 +551,7 @@ async def test_function_exception( "content": ( '{"error":"HomeAssistantError","error_text":"Test tool exception"}' ), + "is_error": True, "tool_use_id": "toolu_0123456789AbCdEfGhIjKlM", "type": "tool_result", }