diff --git a/pdm.lock b/pdm.lock index d9bd873e..7e8b0377 100644 --- a/pdm.lock +++ b/pdm.lock @@ -5,7 +5,7 @@ groups = ["default", "chat", "test"] strategy = ["inherit_metadata"] lock_version = "4.5.0" -content_hash = "sha256:1ed4e4370d0912416cc65444a7f6c59a6a9f78ce3d85166859bab162b9cd2e6b" +content_hash = "sha256:0a776bcb0858c92a70bc0221f9adafacdc5af3bc2dd86282aaeb4fce12ed32ac" [[metadata.targets]] requires_python = ">=3.10" diff --git a/pyproject.toml b/pyproject.toml index 62fc1c7d..2639b819 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ dependencies = [ "requests>=2.32.3", "Jinja2>=3.1.4", "pydantic-settings>=2.7.0", - "tenacity>=9.0.0", + "tenacity>=9.1.2", "python-dateutil>=2.9.0.post0", "openai>=1.61.1", "segment-analytics-python>=2.3.4", diff --git a/src/askui/models/askui/askui_computer_agent.py b/src/askui/models/askui/askui_computer_agent.py index 59fe781e..d7970d66 100644 --- a/src/askui/models/askui/askui_computer_agent.py +++ b/src/askui/models/askui/askui_computer_agent.py @@ -13,6 +13,7 @@ BetaToolResultBlockParam, BetaToolUseBlockParam, ) +from tenacity import retry, retry_if_exception, stop_after_attempt, wait_exponential from askui.models.askui.settings import AskUiComputerAgentSettings from askui.reporting import Reporter @@ -163,6 +164,13 @@ """ # noqa: DTZ002, E501 +def is_retryable_error(exception: BaseException) -> bool: + """Check if the exception is a retryable error (status codes 429 or 529).""" + if isinstance(exception, httpx.HTTPStatusError): + return exception.response.status_code in (429, 529) + return False + + class AskUiComputerAgent: def __init__( self, @@ -184,6 +192,12 @@ def __init__( }, ) + @retry( + stop=stop_after_attempt(3), + wait=wait_exponential(multiplier=1, min=30, max=240), + retry=retry_if_exception(is_retryable_error), + reraise=True, + ) def step(self, messages: list[BetaMessageParam]) -> list[BetaMessageParam]: if self._settings.only_n_most_recent_images: self._maybe_filter_to_n_most_recent_images( @@ -203,14 +217,15 @@ def step(self, messages: list[BetaMessageParam]) -> list[BetaMessageParam]: } logger.debug(request_body) response = self._client.post( - "/act/inference", json=request_body, timeout=120.0 + "/act/inference", json=request_body, timeout=300.0 ) response.raise_for_status() response_data = response.json() beta_message = BetaMessage.model_validate(response_data) except Exception as e: # noqa: BLE001 - logger.error(e) - return messages + if is_retryable_error(e): + logger.debug(e) + raise response_params = self._response_to_params(beta_message) new_message: BetaMessageParam = {