Merge branch 'main' into async

This commit is contained in:
Paul Gauthier 2024-08-08 15:23:19 -03:00
commit 4abb2e78b6
3 changed files with 41 additions and 55 deletions

View file

@ -30,7 +30,7 @@ from aider.llm import litellm
from aider.mdstream import MarkdownStream from aider.mdstream import MarkdownStream
from aider.repo import GitRepo from aider.repo import GitRepo
from aider.repomap import RepoMap from aider.repomap import RepoMap
from aider.sendchat import send_with_retries from aider.sendchat import retry_exceptions, send_completion
from aider.utils import format_content, format_messages, is_image_file from aider.utils import format_content, format_messages, is_image_file
from ..dump import dump # noqa: F401 from ..dump import dump # noqa: F401
@ -70,6 +70,7 @@ class Coder:
lint_outcome = None lint_outcome = None
test_outcome = None test_outcome = None
multi_response_content = "" multi_response_content = ""
partial_response_content = ""
partial_response_content = None partial_response_content = None
@ -895,6 +896,8 @@ class Coder:
else: else:
self.mdstream = None self.mdstream = None
retry_delay = 0.125
self.usage_report = None self.usage_report = None
exhausted = False exhausted = False
interrupted = False interrupted = False
@ -903,6 +906,14 @@ class Coder:
try: try:
yield from self.send(messages, functions=self.functions) yield from self.send(messages, functions=self.functions)
break break
except retry_exceptions() as err:
self.io.tool_error(str(err))
retry_delay *= 2
if retry_delay > 60:
break
self.io.tool_output(f"Retrying in {retry_delay:.1f} seconds...")
time.sleep(retry_delay)
continue
except KeyboardInterrupt: except KeyboardInterrupt:
interrupted = True interrupted = True
break break
@ -1165,7 +1176,7 @@ class Coder:
interrupted = False interrupted = False
try: try:
hash_object, completion = send_with_retries( hash_object, completion = send_completion(
model.name, model.name,
messages, messages,
functions, functions,

View file

@ -14,53 +14,28 @@ CACHE = None
# CACHE = Cache(CACHE_PATH) # CACHE = Cache(CACHE_PATH)
def retry_exceptions():
import httpx
return (
httpx.ConnectError,
httpx.RemoteProtocolError,
httpx.ReadTimeout,
litellm.exceptions.APIConnectionError,
litellm.exceptions.APIError,
litellm.exceptions.RateLimitError,
litellm.exceptions.ServiceUnavailableError,
litellm.exceptions.Timeout,
litellm.exceptions.InternalServerError,
litellm.llms.anthropic.AnthropicError,
)
def lazy_litellm_retry_decorator(func): def lazy_litellm_retry_decorator(func):
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
import httpx
def should_giveup(e):
if not hasattr(e, "status_code"):
return False
if type(e) in (
httpx.ConnectError,
httpx.RemoteProtocolError,
httpx.ReadTimeout,
litellm.exceptions.APIConnectionError,
litellm.exceptions.APIError,
litellm.exceptions.RateLimitError,
litellm.exceptions.ServiceUnavailableError,
litellm.exceptions.Timeout,
litellm.exceptions.InternalServerError,
litellm.llms.anthropic.AnthropicError,
):
return False
# These seem to return .status_code = ""
# litellm._should_retry() expects an int and throws a TypeError
#
# litellm.llms.anthropic.AnthropicError
# litellm.exceptions.APIError
if not e.status_code:
return False
return not litellm._should_retry(e.status_code)
decorated_func = backoff.on_exception( decorated_func = backoff.on_exception(
backoff.expo, backoff.expo,
( retry_exceptions(),
httpx.ConnectError,
httpx.RemoteProtocolError,
httpx.ReadTimeout,
litellm.exceptions.APIConnectionError,
litellm.exceptions.APIError,
litellm.exceptions.RateLimitError,
litellm.exceptions.ServiceUnavailableError,
litellm.exceptions.Timeout,
litellm.exceptions.InternalServerError,
litellm.llms.anthropic.AnthropicError,
),
giveup=should_giveup,
max_time=60, max_time=60,
on_backoff=lambda details: print( on_backoff=lambda details: print(
f"{details.get('exception', 'Exception')}\nRetry in {details['wait']:.1f} seconds." f"{details.get('exception', 'Exception')}\nRetry in {details['wait']:.1f} seconds."
@ -71,8 +46,7 @@ def lazy_litellm_retry_decorator(func):
return wrapper return wrapper
@lazy_litellm_retry_decorator def send_completion(
def send_with_retries(
model_name, messages, functions, stream, temperature=0, extra_headers=None, max_tokens=None model_name, messages, functions, stream, temperature=0, extra_headers=None, max_tokens=None
): ):
from aider.llm import litellm from aider.llm import litellm
@ -108,9 +82,10 @@ def send_with_retries(
return hash_object, res return hash_object, res
@lazy_litellm_retry_decorator
def simple_send_with_retries(model_name, messages): def simple_send_with_retries(model_name, messages):
try: try:
_hash, response = send_with_retries( _hash, response = send_completion(
model_name=model_name, model_name=model_name,
messages=messages, messages=messages,
functions=None, functions=None,

View file

@ -4,7 +4,7 @@ from unittest.mock import MagicMock, patch
import httpx import httpx
from aider.llm import litellm from aider.llm import litellm
from aider.sendchat import send_with_retries from aider.sendchat import simple_send_with_retries
class PrintCalled(Exception): class PrintCalled(Exception):
@ -14,7 +14,7 @@ class PrintCalled(Exception):
class TestSendChat(unittest.TestCase): class TestSendChat(unittest.TestCase):
@patch("litellm.completion") @patch("litellm.completion")
@patch("builtins.print") @patch("builtins.print")
def test_send_with_retries_rate_limit_error(self, mock_print, mock_completion): def test_simple_send_with_retries_rate_limit_error(self, mock_print, mock_completion):
mock = MagicMock() mock = MagicMock()
mock.status_code = 500 mock.status_code = 500
@ -29,19 +29,19 @@ class TestSendChat(unittest.TestCase):
None, None,
] ]
# Call the send_with_retries method # Call the simple_send_with_retries method
send_with_retries("model", ["message"], None, False) simple_send_with_retries("model", ["message"])
mock_print.assert_called_once() mock_print.assert_called_once()
@patch("litellm.completion") @patch("litellm.completion")
@patch("builtins.print") @patch("builtins.print")
def test_send_with_retries_connection_error(self, mock_print, mock_completion): def test_simple_send_with_retries_connection_error(self, mock_print, mock_completion):
# Set up the mock to raise # Set up the mock to raise
mock_completion.side_effect = [ mock_completion.side_effect = [
httpx.ConnectError("Connection error"), httpx.ConnectError("Connection error"),
None, None,
] ]
# Call the send_with_retries method # Call the simple_send_with_retries method
send_with_retries("model", ["message"], None, False) simple_send_with_retries("model", ["message"])
mock_print.assert_called_once() mock_print.assert_called_once()