From 92227dc74878c0ee64611deb49f94720b8907e30 Mon Sep 17 00:00:00 2001 From: openhands Date: Fri, 31 Jan 2025 18:04:20 +0000 Subject: [PATCH] Fix pr #6095: Chore: clean up LLM (prompt caching, supports fn calling), leftover renames --- openhands/llm/exceptions.py | 14 ++++++++++++++ openhands/llm/llm.py | 2 ++ openhands/llm/retry_mixin.py | 10 +++++----- pyproject.toml | 2 ++ 4 files changed, 23 insertions(+), 5 deletions(-) create mode 100644 openhands/llm/exceptions.py diff --git a/openhands/llm/exceptions.py b/openhands/llm/exceptions.py new file mode 100644 index 000000000000..1bf9c3e05b70 --- /dev/null +++ b/openhands/llm/exceptions.py @@ -0,0 +1,14 @@ +from litellm.exceptions import APIError + + +class CloudflareBlockError(APIError): + """Exception raised when Cloudflare blocks the request.""" + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + def __instancecheck__(self, instance): + return ( + super().__instancecheck__(instance) + and 'Attention Required! | Cloudflare' in str(instance) + ) diff --git a/openhands/llm/llm.py b/openhands/llm/llm.py index 080777c63f78..7a3a74d66155 100644 --- a/openhands/llm/llm.py +++ b/openhands/llm/llm.py @@ -30,6 +30,7 @@ from openhands.core.logger import openhands_logger as logger from openhands.core.message import Message from openhands.llm.debug_mixin import DebugMixin +from openhands.llm.exceptions import CloudflareBlockError from openhands.llm.fn_call_converter import ( STOP_WORDS, convert_fncall_messages_to_non_fncall_messages, @@ -147,6 +148,7 @@ def __init__( @self.retry_decorator( num_retries=self.config.num_retries, retry_exceptions=LLM_RETRY_EXCEPTIONS, + exclude_exceptions=(CloudflareBlockError,), retry_min_wait=self.config.retry_min_wait, retry_max_wait=self.config.retry_max_wait, retry_multiplier=self.config.retry_multiplier, diff --git a/openhands/llm/retry_mixin.py b/openhands/llm/retry_mixin.py index 5f83322356f0..742f43e20531 100644 --- a/openhands/llm/retry_mixin.py +++ b/openhands/llm/retry_mixin.py @@ -1,4 +1,3 @@ -from litellm.exceptions import APIError from tenacity import ( retry, retry_if_exception, @@ -19,23 +18,24 @@ def retry_decorator(self, **kwargs): Args: **kwargs: Keyword arguments to override default retry behavior. - Keys: num_retries, retry_exceptions, retry_min_wait, retry_max_wait, retry_multiplier + Keys: num_retries, retry_exceptions, exclude_exceptions, retry_min_wait, retry_max_wait, retry_multiplier Returns: A retry decorator with the parameters customizable in configuration. """ num_retries = kwargs.get('num_retries') retry_exceptions: tuple = kwargs.get('retry_exceptions', ()) + exclude_exceptions: tuple = kwargs.get('exclude_exceptions', ()) retry_min_wait = kwargs.get('retry_min_wait') retry_max_wait = kwargs.get('retry_max_wait') retry_multiplier = kwargs.get('retry_multiplier') def _filter_exceptions(e): - # For Cloudflare blocks, don't retry - just return False - if isinstance(e, APIError) and 'Attention Required! | Cloudflare' in str(e): + # First check if the exception is in the exclude list + if isinstance(e, exclude_exceptions): return False - # Otherwise, return True if we want to retry, which means e is in retry_exceptions + # Then check if it's in the retry list return isinstance(e, retry_exceptions) return retry( diff --git a/pyproject.toml b/pyproject.toml index 44d36520611c..fc0b4d98cb8d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -101,6 +101,7 @@ reportlab = "*" [tool.coverage.run] concurrency = ["gevent"] + [tool.poetry.group.runtime.dependencies] jupyterlab = "*" notebook = "*" @@ -129,6 +130,7 @@ ignore = ["D1"] [tool.ruff.lint.pydocstyle] convention = "google" + [tool.poetry.group.evaluation.dependencies] streamlit = "*" whatthepatch = "*"