From patchwork Sat Apr 4 21:28:52 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 2131 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1775338320; bh=72v8ozrKeQBGCp15J/I2XoEb/9PRdMfr4ohXEDMRPzI=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=YXRqqn6SyAyhRAGqVK8C4E3gtNKpi0k3o02qTcxN9fEpQmd/GsUykms5pByVzx/+3 6kRhuJQaTxDe/ez/nL/HH5Svn+0e0qlw6ERuIydelb7cxoPAYxQxaPsl2hWFAS1FGr G/vBg6seQ1iCw94lrWlxb+OPTBi4Wlom+1D8SGM0cq3VSgbqW8m+mIIwFr/BArPHzQ y8qyjvwhyGMLIb1/VACBx5sPLkyZxHSifupQCuXmTrheC8P7YqTFvXMgK/Y1HzBaZX lspr+P9aR9pKJdER+Wl7sFyxxK0RmOtCGa9cVEDms0Iq9VO19ir7xT6FwtiRP4413R 28eLfk9HQITgw== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 4B1E96A382 for ; Sat, 4 Apr 2026 15:32:00 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id P9DN97pZCldW for ; Sat, 4 Apr 2026 15:32:00 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1775338320; bh=72v8ozrKeQBGCp15J/I2XoEb/9PRdMfr4ohXEDMRPzI=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=YXRqqn6SyAyhRAGqVK8C4E3gtNKpi0k3o02qTcxN9fEpQmd/GsUykms5pByVzx/+3 6kRhuJQaTxDe/ez/nL/HH5Svn+0e0qlw6ERuIydelb7cxoPAYxQxaPsl2hWFAS1FGr G/vBg6seQ1iCw94lrWlxb+OPTBi4Wlom+1D8SGM0cq3VSgbqW8m+mIIwFr/BArPHzQ y8qyjvwhyGMLIb1/VACBx5sPLkyZxHSifupQCuXmTrheC8P7YqTFvXMgK/Y1HzBaZX lspr+P9aR9pKJdER+Wl7sFyxxK0RmOtCGa9cVEDms0Iq9VO19ir7xT6FwtiRP4413R 28eLfk9HQITgw== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 39C766A375 for ; Sat, 4 Apr 2026 15:32:00 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1775338318; bh=kC9azy48FzeQxHtKOMHR/155ingUG/VbevbC01SUFNs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Uv2/Hqqo1xKG7fymr258fNLoQ21myZ6pQjd/owW/asMJmjIlVgq1AGlOyw51Ykl1d RxlHWz9ldgXrTPlVulRF5P+M1bC/hwCBqszIsf3jMcD2/t8IhvnwptGn6IcgY6rI3M RPaQLTOoXRS0by6fvzE+w+ZPVe7BUvrIEHxUEt+0+JayIKmAFpIvLcSz4xt58IZPsZ Sn7zdzKdX8AEDWPQ/Oc8mE8W3bj/yxsqaGjjj2DVFwyt5c8NwXAv0C1d6PR9g/DC1V /Zjy0YpYKHw++R1yQecgHPDenDaTZDskrNgs8F7MfJPVOl22MK5PTosLSQXeIQCotp ccPwJDV640Bzg== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 3AFB06A369; Sat, 4 Apr 2026 15:31:58 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10026) with ESMTP id BG5ut5yZM13x; Sat, 4 Apr 2026 15:31:58 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1775338314; bh=Rno+Cy1qzqg/RLx7F/7iH8vKfRyEUhowJLCjZbe8V1A=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=KJ77d5NsN19nwxu6mAxaMYUOttaA/+MtHcVGM/tZEBOMoQbkZDAUZnwgMf/Vj6jzW aftlJa8GwstFaW09GCegTQpVWt5M/dSHzLjESC3MdQCw8SmbF2YErKq/rSaoB9FPkO 3piat4cWZICdT3oxSNk2tjWo3247YpnmaWR44mdTI7pHou7MtD6dpzbisRs5+mQjSl urV/B46rSD83nOl3WJMzkJUXI40w2guVKayXksXUtOIC0Zj23alhHDWhOzOSNRWlqA pnChDBk964B5w7ZFJOoKXqg5yJAbKIA/7Tg87Q2s4dxEeoaPcZ3Uch3bl2WlLHHT/4 6LkWTJ3jcyP5g== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id F34A86869D; Sat, 4 Apr 2026 15:31:53 -0600 (MDT) From: Simon Glass To: U-Boot Concept Date: Sat, 4 Apr 2026 15:28:52 -0600 Message-ID: <20260404213020.372253-17-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260404213020.372253-1-sjg@u-boot.org> References: <20260404213020.372253-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: S2DIIN5JDJDMHNX44EXBAY2FSFB3TQGW X-Message-ID-Hash: S2DIIN5JDJDMHNX44EXBAY2FSFB3TQGW X-MailFrom: sjg@u-boot.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Simon Glass X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 16/37] u_boot_pylib: Catch API errors from the Claude Agent SDK List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Simon Glass The Claude Agent SDK raises a bare Exception on API errors (e.g. 500 Internal Server Error), but run_agent_collect() only catches RuntimeError, ValueError and OSError. This causes the entire review to crash when a single agent call fails, even though the review loop already handles the failure gracefully with a placeholder message. Catch bare Exceptions whose message indicates an API or process error (containing 'API Error' or 'exit code') while re-raising unexpected exceptions that indicate real bugs. Signed-off-by: Simon Glass --- tools/u_boot_pylib/claude.py | 5 +++++ tools/u_boot_pylib/test_claude.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/tools/u_boot_pylib/claude.py b/tools/u_boot_pylib/claude.py index 29dff1d1d4b..6ba980b6b2e 100644 --- a/tools/u_boot_pylib/claude.py +++ b/tools/u_boot_pylib/claude.py @@ -62,3 +62,8 @@ async def run_agent_collect(prompt, options): except (RuntimeError, ValueError, OSError) as exc: tout.error(f'Agent failed: {exc}') return False, '\n\n'.join(conversation_log) + except Exception as exc: + if 'API Error' in str(exc) or 'exit code' in str(exc): + tout.error(f'Agent failed: {exc}') + return False, '\n\n'.join(conversation_log) + raise diff --git a/tools/u_boot_pylib/test_claude.py b/tools/u_boot_pylib/test_claude.py index c564dddb70e..2a666e6c396 100644 --- a/tools/u_boot_pylib/test_claude.py +++ b/tools/u_boot_pylib/test_claude.py @@ -83,6 +83,37 @@ class TestClaude(unittest.TestCase): self.assertFalse(success) + def test_run_agent_collect_handles_api_error(self): + """run_agent_collect() catches SDK API errors""" + # pylint: disable=W0613,W0719 + async def mock_query(**kwargs): + raise Exception( + 'Command failed with exit code 1 (exit code: 1)') + yield # pylint: disable=W0101 + + self._setup_claude_with_mock_query(mock_query) + loop = asyncio.new_event_loop() + with terminal.capture(): + success, _ = loop.run_until_complete( + claude.run_agent_collect('test prompt', MagicMock())) + loop.close() + + self.assertFalse(success) + + def test_run_agent_collect_reraises_unknown(self): + """run_agent_collect() re-raises unexpected exceptions""" + # pylint: disable=W0613 + async def mock_query(**kwargs): + raise TypeError('unexpected bug') + yield # pylint: disable=W0101 + + self._setup_claude_with_mock_query(mock_query) + loop = asyncio.new_event_loop() + with self.assertRaises(TypeError): + loop.run_until_complete( + claude.run_agent_collect('test prompt', MagicMock())) + loop.close() + def test_run_agent_collect_skips_non_text_blocks(self): """run_agent_collect() ignores blocks without text attribute""" text_block = MagicMock()