From 82217241829d45b504d8186b9cc51078cb7e42be Mon Sep 17 00:00:00 2001 From: Christopher Hertel Date: Sun, 18 May 2025 16:06:52 +0200 Subject: [PATCH] fix: flaky anthropic tool calls with empty text --- src/Bridge/Anthropic/ModelHandler.php | 9 ++--- tests/Bridge/Anthropic/ModelHandlerTest.php | 39 +++++++++++++++++++++ 2 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 tests/Bridge/Anthropic/ModelHandlerTest.php diff --git a/src/Bridge/Anthropic/ModelHandler.php b/src/Bridge/Anthropic/ModelHandler.php index 07f631f8..7beaeea0 100644 --- a/src/Bridge/Anthropic/ModelHandler.php +++ b/src/Bridge/Anthropic/ModelHandler.php @@ -121,16 +121,17 @@ public function convert(ResponseInterface $response, array $options = []): LlmRe throw new RuntimeException('Response does not contain any content'); } - if (!isset($data['content'][0]['text'])) { - throw new RuntimeException('Response content does not contain any text'); - } - $toolCalls = []; foreach ($data['content'] as $content) { if ('tool_use' === $content['type']) { $toolCalls[] = new ToolCall($content['id'], $content['name'], $content['input']); } } + + if (!isset($data['content'][0]['text']) && 0 === count($toolCalls)) { + throw new RuntimeException('Response content does not contain any text nor tool calls.'); + } + if (!empty($toolCalls)) { return new ToolCallResponse(...$toolCalls); } diff --git a/tests/Bridge/Anthropic/ModelHandlerTest.php b/tests/Bridge/Anthropic/ModelHandlerTest.php new file mode 100644 index 00000000..48a27e74 --- /dev/null +++ b/tests/Bridge/Anthropic/ModelHandlerTest.php @@ -0,0 +1,39 @@ + [ + [ + 'type' => 'tool_use', + 'id' => 'toolu_01UM4PcTjC1UDiorSXVHSVFM', + 'name' => 'xxx_tool', + 'input' => ['action' => 'get_data'], + ], + ], + ])); + $httpResponse = $httpClient->request('POST', 'https://api.anthropic.com/v1/messages'); + $handler = new ModelHandler($httpClient, 'test-api-key'); + + $response = $handler->convert($httpResponse); + self::assertInstanceOf(ToolCallResponse::class, $response); + self::assertCount(1, $response->getContent()); + self::assertSame('toolu_01UM4PcTjC1UDiorSXVHSVFM', $response->getContent()[0]->id); + self::assertSame('xxx_tool', $response->getContent()[0]->name); + self::assertSame(['action' => 'get_data'], $response->getContent()[0]->arguments); + } +}