Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion aider/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from packaging import version

__version__ = "0.88.0.dev"
__version__ = "0.88.1.dev"
safe_version = __version__

try:
Expand Down
12 changes: 6 additions & 6 deletions aider/coders/base_coder.py
Original file line number Diff line number Diff line change
Expand Up @@ -1248,7 +1248,7 @@ async def run_one(self, user_message, preproc):
else:
message = self.reflected_message

def check_and_open_urls(self, exc, friendly_msg=None):
async def check_and_open_urls(self, exc, friendly_msg=None):
"""Check exception for URLs, offer to open in a browser, with user-friendly error msgs."""
text = str(exc)

Expand All @@ -1264,7 +1264,7 @@ def check_and_open_urls(self, exc, friendly_msg=None):
urls = list(set(url_pattern.findall(text)))
for url in urls:
url = url.rstrip(".',\"}") # Added } to the characters to strip
self.io.offer_url(url)
await self.io.offer_url(url)
return urls

async def check_for_urls(self, inp: str) -> List[str]:
Expand Down Expand Up @@ -1841,7 +1841,7 @@ async def send_message(self, inp):

if not should_retry:
self.mdstream = None
self.check_and_open_urls(err, ex_info.description)
await self.check_and_open_urls(err, ex_info.description)
break

err_msg = str(err)
Expand Down Expand Up @@ -1906,7 +1906,7 @@ async def send_message(self, inp):
),
]

self.show_exhausted_error()
await self.show_exhausted_error()
self.num_exhausted_context_windows += 1
return

Expand Down Expand Up @@ -2402,7 +2402,7 @@ def get_tool_list(self):
async def reply_completed(self):
pass

def show_exhausted_error(self):
async def show_exhausted_error(self):
output_tokens = 0
if self.partial_response_content:
output_tokens = self.main_model.token_count(self.partial_response_content)
Expand Down Expand Up @@ -2453,7 +2453,7 @@ def show_exhausted_error(self):

res = "".join([line + "\n" for line in res])
self.io.tool_error(res)
self.io.offer_url(urls.token_limits)
await self.io.offer_url(urls.token_limits)

def lint_edited(self, fnames):
res = ""
Expand Down
1 change: 1 addition & 0 deletions aider/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class ExInfo:
"The API provider has refused the request due to a safety policy about the content.",
),
ExInfo("ContextWindowExceededError", False, None), # special case handled in base_coder
ExInfo("ErrorEventError", True, None),
ExInfo("ImageFetchError", True, "The API cannot fetch an image"),
ExInfo("InternalServerError", True, "The API provider's servers are down or overloaded."),
ExInfo("InvalidRequestError", True, None),
Expand Down
20 changes: 10 additions & 10 deletions aider/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ def register_litellm_models(git_root, model_metadata_fname, io, verbose=False):
return 1


def sanity_check_repo(repo, io):
async def sanity_check_repo(repo, io):
if not repo:
return True

Expand Down Expand Up @@ -443,7 +443,7 @@ def sanity_check_repo(repo, io):
io.tool_error("Aider only works with git repos with version number 1 or 2.")
io.tool_output("You may be able to convert your repo: git update-index --index-version=2")
io.tool_output("Or run aider --no-git to proceed without using git.")
io.offer_url(urls.git_index_version, "Open documentation url for more info?")
await io.offer_url(urls.git_index_version, "Open documentation url for more info?")
return False

io.tool_error("Unable to read git repository, it may be corrupt?")
Expand Down Expand Up @@ -783,7 +783,7 @@ def get_io(pretty):
io.tool_output(cmd_line, log_only=True)

is_first_run = is_first_run_of_new_version(io, verbose=args.verbose)
check_and_load_imports(io, is_first_run, verbose=args.verbose)
await check_and_load_imports(io, is_first_run, verbose=args.verbose)

register_models(git_root, args.model_settings_file, io, verbose=args.verbose)
register_litellm_models(git_root, args.model_metadata_file, io, verbose=args.verbose)
Expand Down Expand Up @@ -844,7 +844,7 @@ def get_io(pretty):
io.tool_error(
f"Unable to proceed without an OpenRouter API key for model '{args.model}'."
)
io.offer_url(urls.models_and_keys, "Open documentation URL for more info?")
await io.offer_url(urls.models_and_keys, "Open documentation URL for more info?")
analytics.event(
"exit",
reason="OpenRouter key missing for specified model and OAuth failed/declined",
Expand Down Expand Up @@ -926,7 +926,7 @@ def get_io(pretty):
io.tool_output("You can skip this check with --no-show-model-warnings")

try:
io.offer_url(urls.model_warnings, "Open documentation url for more info?")
await io.offer_url(urls.model_warnings, "Open documentation url for more info?")
io.tool_output()
except KeyboardInterrupt:
analytics.event("exit", reason="Keyboard interrupt during model warnings")
Expand Down Expand Up @@ -954,7 +954,7 @@ def get_io(pretty):
pass

if not args.skip_sanity_check_repo:
if not sanity_check_repo(repo, io):
if not await sanity_check_repo(repo, io):
analytics.event("exit", reason="Repository sanity check failed")
return 1

Expand Down Expand Up @@ -1059,7 +1059,7 @@ def get_io(pretty):
)
except UnknownEditFormat as err:
io.tool_error(str(err))
io.offer_url(urls.edit_formats, "Open documentation about edit formats?")
await io.offer_url(urls.edit_formats, "Open documentation about edit formats?")
analytics.event("exit", reason="Unknown edit format")
return 1
except ValueError as err:
Expand Down Expand Up @@ -1152,7 +1152,7 @@ def get_io(pretty):
webbrowser.open(urls.release_notes)
elif args.show_release_notes is None and is_first_run:
io.tool_output()
io.offer_url(
await io.offer_url(
urls.release_notes,
"Would you like to see what's new in this version?",
allow_never=False,
Expand Down Expand Up @@ -1276,7 +1276,7 @@ def is_first_run_of_new_version(io, verbose=False):
return True # Safer to assume it's a first run if we hit an error


def check_and_load_imports(io, is_first_run, verbose=False):
async def check_and_load_imports(io, is_first_run, verbose=False):
try:
if is_first_run:
if verbose:
Expand All @@ -1288,7 +1288,7 @@ def check_and_load_imports(io, is_first_run, verbose=False):
except Exception as err:
io.tool_error(str(err))
io.tool_output("Error loading required imports. Did you install aider properly?")
io.offer_url(urls.install_properly, "Open documentation url for more info?")
await io.offer_url(urls.install_properly, "Open documentation url for more info?")
sys.exit(1)

if verbose:
Expand Down
2 changes: 1 addition & 1 deletion aider/onboarding.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ async def select_default_model(args, io, analytics):
if model:
return model

io.offer_url(urls.models_and_keys, "Open documentation URL for more info?")
await io.offer_url(urls.models_and_keys, "Open documentation URL for more info?")


# Helper function to find an available port
Expand Down
25 changes: 15 additions & 10 deletions tests/basic/test_sanity_check_repo.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import asyncio
import os
import shutil
import struct
Expand Down Expand Up @@ -81,7 +82,7 @@ def get_tracked_files_side_effect():
return mock_repo


def test_detached_head_state(create_repo, mock_io):
async def test_detached_head_state(create_repo, mock_io):
repo_path, repo = create_repo
# Detach the HEAD
detach_head(repo)
Expand All @@ -90,7 +91,7 @@ def test_detached_head_state(create_repo, mock_io):
mock_repo_obj = mock_repo_wrapper(repo)

# Call the function
result = sanity_check_repo(mock_repo_obj, mock_io)
result = await sanity_check_repo(mock_repo_obj, mock_io)

# Assert that the function returns True
assert result is True
Expand All @@ -101,7 +102,7 @@ def test_detached_head_state(create_repo, mock_io):


@mock.patch("webbrowser.open")
def test_git_index_version_greater_than_2(mock_browser, create_repo, mock_io):
async def test_git_index_version_greater_than_2(mock_browser, create_repo, mock_io):
repo_path, repo = create_repo
# Set the git index version to 3
set_git_index_version(str(repo_path), 3)
Expand All @@ -110,8 +111,12 @@ def test_git_index_version_greater_than_2(mock_browser, create_repo, mock_io):
git_error = GitError("index version in (1, 2) is required")
mock_repo_obj = mock_repo_wrapper(repo, git_repo_error=git_error)

# Configure the mock to return an async mock for offer_url
mock_io.offer_url.return_value = asyncio.Future()
mock_io.offer_url.return_value.set_result(False)

# Call the function
result = sanity_check_repo(mock_repo_obj, mock_io)
result = await sanity_check_repo(mock_repo_obj, mock_io)

# Assert that the function returns False
assert result is False
Expand All @@ -133,7 +138,7 @@ def test_git_index_version_greater_than_2(mock_browser, create_repo, mock_io):
)


def test_bare_repository(create_repo, mock_io, tmp_path):
async def test_bare_repository(create_repo, mock_io, tmp_path):
# Initialize a bare repository
bare_repo_path = tmp_path / "bare_repo.git"
bare_repo = Repo.init(bare_repo_path, bare=True)
Expand All @@ -142,7 +147,7 @@ def test_bare_repository(create_repo, mock_io, tmp_path):
mock_repo_obj = mock_repo_wrapper(bare_repo)

# Call the function
result = sanity_check_repo(mock_repo_obj, mock_io)
result = await sanity_check_repo(mock_repo_obj, mock_io)

# Assert that the function returns False
assert result is False
Expand All @@ -152,7 +157,7 @@ def test_bare_repository(create_repo, mock_io, tmp_path):
mock_io.tool_output.assert_not_called()


def test_sanity_check_repo_with_corrupt_repo(create_repo, mock_io):
async def test_sanity_check_repo_with_corrupt_repo(create_repo, mock_io):
repo_path, repo = create_repo
# Simulate a corrupt repository by removing the .git directory
shutil.rmtree(os.path.join(repo_path, ".git"))
Expand All @@ -162,7 +167,7 @@ def test_sanity_check_repo_with_corrupt_repo(create_repo, mock_io):
mock_repo_obj = mock_repo_wrapper(repo, git_repo_error=git_error)

# Call the function
result = sanity_check_repo(mock_repo_obj, mock_io)
result = await sanity_check_repo(mock_repo_obj, mock_io)

# Assert that the function returns False
assert result is False
Expand All @@ -172,9 +177,9 @@ def test_sanity_check_repo_with_corrupt_repo(create_repo, mock_io):
mock_io.tool_output.assert_called_with(str(git_error))


def test_sanity_check_repo_with_no_repo(mock_io):
async def test_sanity_check_repo_with_no_repo(mock_io):
# Call the function with repo=None
result = sanity_check_repo(None, mock_io)
result = await sanity_check_repo(None, mock_io)

# Assert that the function returns True
assert result is True
Expand Down
Loading