From 3e4b4d1b0da8a84e1340ba65fa38c07a7ad753c0 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Wed, 26 Jul 2023 07:40:36 -0300 Subject: [PATCH 1/7] retry on APIConnectionError --- aider/sendchat.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/aider/sendchat.py b/aider/sendchat.py index 441447863..56b46bd4a 100644 --- a/aider/sendchat.py +++ b/aider/sendchat.py @@ -4,7 +4,13 @@ import json import backoff import openai import requests -from openai.error import APIError, RateLimitError, ServiceUnavailableError, Timeout +from openai.error import ( + APIConnectionError, + APIError, + RateLimitError, + ServiceUnavailableError, + Timeout, +) @backoff.on_exception( @@ -14,6 +20,7 @@ from openai.error import APIError, RateLimitError, ServiceUnavailableError, Time APIError, ServiceUnavailableError, RateLimitError, + APIConnectionError, requests.exceptions.ConnectionError, ), max_tries=10, From 08ee61617f3c87321586407c82bd442c1b829415 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Wed, 26 Jul 2023 15:52:13 -0300 Subject: [PATCH 2/7] Updated discord link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f62b0b9db..9017d84c8 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ It also has features that [help GPT-4 understand and modify larger codebases](ht

- +

From 35ccfac3fd0b3913d402c319f81d8cfce62d4744 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Wed, 26 Jul 2023 17:34:50 -0300 Subject: [PATCH 3/7] aider: Updated the output of `/tokens` to include the total cost. # Aider chat conversation: USER: udpate the output of /tokens to include the total $ cost ASSISTANT: To include the total cost in the output of the `/tokens` command, we need to modify the `cmd_tokens` method in the `Commands` class in the `aider/commands.py` file. We will add a new variable `total_cost` to keep track of the total cost. For each token count, we will calculate the cost by multiplying the token count by the model's `completion_price` (since we're considering the cost of generating these tokens). We will then add this cost to `total_cost`. Finally, we will add a line to the output to display the total cost. Here are the changes: python aider/commands.py <<<<<<< ORIGINAL total = 0 for tk, msg, tip in res: total += tk msg = msg.ljust(col_width) self.io.tool_output(f"{fmt(tk)} {msg} {tip}") self.io.tool_output("=" * width) self.io.tool_output(f"{fmt(total)} tokens total") ======= total = 0 total_cost = 0.0 for tk, msg, tip in res: total += tk cost = tk * self.coder.main_model.completion_price total_cost += cost msg = msg.ljust(col_width) self.io.tool_output(f"{fmt(tk)} {msg} {tip} (cost: ${cost:.2f})") self.io.tool_output("=" * width) self.io.tool_output(f"{fmt(total)} tokens total (cost: ${total_cost:.2f})") >>>>>>> UPDATED --- aider/commands.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/aider/commands.py b/aider/commands.py index 6fd5fa594..8f8e4ac26 100644 --- a/aider/commands.py +++ b/aider/commands.py @@ -142,13 +142,16 @@ class Commands: col_width = max(len(row[1]) for row in res) total = 0 + total_cost = 0.0 for tk, msg, tip in res: total += tk + cost = tk * self.coder.main_model.completion_price + total_cost += cost msg = msg.ljust(col_width) - self.io.tool_output(f"{fmt(tk)} {msg} {tip}") + self.io.tool_output(f"{fmt(tk)} {msg} {tip} (cost: ${cost:.2f})") self.io.tool_output("=" * width) - self.io.tool_output(f"{fmt(total)} tokens total") + self.io.tool_output(f"{fmt(total)} tokens total (cost: ${total_cost:.2f})") limit = self.coder.main_model.max_context_tokens remaining = limit - total From 2094b3176bd69ca94d1e70400db3c1ce2a0b43b1 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Wed, 26 Jul 2023 17:35:42 -0300 Subject: [PATCH 4/7] aider: Adjusted the calculation of the cost in the `cmd_tokens` method to account for the prices in `Model` being per 1k tokens. # Aider chat conversation: USER: the prices in `Model` are per 1k tokens ASSISTANT: I see, the prices in the `Model` class are per 1k tokens. Therefore, we need to adjust the calculation of the cost in the `cmd_tokens` method in the `Commands` class in the `aider/commands.py` file. We will divide the `completion_price` by 1000 before multiplying it with the token count to get the cost. Here are the changes: python aider/commands.py <<<<<<< ORIGINAL total = 0 total_cost = 0.0 for tk, msg, tip in res: total += tk cost = tk * self.coder.main_model.completion_price total_cost += cost msg = msg.ljust(col_width) self.io.tool_output(f"{fmt(tk)} {msg} {tip} (cost: ${cost:.2f})") self.io.tool_output("=" * width) self.io.tool_output(f"{fmt(total)} tokens total (cost: ${total_cost:.2f})") ======= total = 0 total_cost = 0.0 for tk, msg, tip in res: total += tk cost = tk * (self.coder.main_model.completion_price / 1000) total_cost += cost msg = msg.ljust(col_width) self.io.tool_output(f"{fmt(tk)} {msg} {tip} (cost: ${cost:.2f})") self.io.tool_output("=" * width) self.io.tool_output(f"{fmt(total)} tokens total (cost: ${total_cost:.2f})") >>>>>>> UPDATED --- aider/commands.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aider/commands.py b/aider/commands.py index 8f8e4ac26..ebb5c4fb9 100644 --- a/aider/commands.py +++ b/aider/commands.py @@ -145,7 +145,7 @@ class Commands: total_cost = 0.0 for tk, msg, tip in res: total += tk - cost = tk * self.coder.main_model.completion_price + cost = tk * (self.coder.main_model.completion_price / 1000) total_cost += cost msg = msg.ljust(col_width) self.io.tool_output(f"{fmt(tk)} {msg} {tip} (cost: ${cost:.2f})") From ecd37b1ad55b26ca8018497f593437661f3533fb Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Wed, 26 Jul 2023 17:43:16 -0300 Subject: [PATCH 5/7] prettier cost output in /tokens --- aider/commands.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/aider/commands.py b/aider/commands.py index ebb5c4fb9..0eae3a8b1 100644 --- a/aider/commands.py +++ b/aider/commands.py @@ -135,36 +135,38 @@ class Commands: self.io.tool_output() width = 8 + cost_width = 7 def fmt(v): return format(int(v), ",").rjust(width) col_width = max(len(row[1]) for row in res) + cost_pad = " " * cost_width total = 0 total_cost = 0.0 for tk, msg, tip in res: total += tk - cost = tk * (self.coder.main_model.completion_price / 1000) + cost = tk * (self.coder.main_model.prompt_price / 1000) total_cost += cost msg = msg.ljust(col_width) - self.io.tool_output(f"{fmt(tk)} {msg} {tip} (cost: ${cost:.2f})") + self.io.tool_output(f"${cost:5.2f} {fmt(tk)} {msg} {tip}") - self.io.tool_output("=" * width) - self.io.tool_output(f"{fmt(total)} tokens total (cost: ${total_cost:.2f})") + self.io.tool_output("=" * (width + cost_width + 1)) + self.io.tool_output(f"${total_cost:5.2f} {fmt(total)} tokens total") limit = self.coder.main_model.max_context_tokens remaining = limit - total if remaining > 1024: - self.io.tool_output(f"{fmt(remaining)} tokens remaining in context window") + self.io.tool_output(f"{cost_pad}{fmt(remaining)} tokens remaining in context window") elif remaining > 0: self.io.tool_error( - f"{fmt(remaining)} tokens remaining in context window (use /drop or /clear to make" - " space)" + f"{cost_pad}{fmt(remaining)} tokens remaining in context window (use /drop or" + " /clear to make space)" ) else: - self.io.tool_error(f"{fmt(remaining)} tokens remaining, window exhausted!") - self.io.tool_output(f"{fmt(limit)} tokens max context window size") + self.io.tool_error(f"{cost_pad}{fmt(remaining)} tokens remaining, window exhausted!") + self.io.tool_output(f"{cost_pad}{fmt(limit)} tokens max context window size") def cmd_undo(self, args): "Undo the last git commit if it was done by aider" From c6f99c9b66fef34df6fa3d376ee5ce79cdcc4c17 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Thu, 27 Jul 2023 06:47:47 -0300 Subject: [PATCH 6/7] Updated discord link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9017d84c8..a32d8661d 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ It also has features that [help GPT-4 understand and modify larger codebases](ht

- +

From 832259b55b19d7f5229a8f713dd9446329d1740f Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Thu, 27 Jul 2023 06:55:06 -0300 Subject: [PATCH 7/7] Bugfix reference to self.get_tracked_files, plus test coverage --- aider/coders/base_coder.py | 4 ++-- tests/test_coder.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/aider/coders/base_coder.py b/aider/coders/base_coder.py index 6fc81c8f2..a3129ae15 100755 --- a/aider/coders/base_coder.py +++ b/aider/coders/base_coder.py @@ -712,11 +712,11 @@ class Coder: # Check if the file is already in the repo if self.repo: - tracked_files = set(self.get_tracked_files()) + tracked_files = set(self.repo.get_tracked_files()) relative_fname = self.get_rel_fname(full_path) if relative_fname not in tracked_files and self.io.confirm_ask(f"Add {path} to git?"): if not self.dry_run: - self.repo.git.add(full_path) + self.repo.repo.git.add(full_path) if write_content: self.io.write_text(full_path, write_content) diff --git a/tests/test_coder.py b/tests/test_coder.py index a9ffaeca5..72b247727 100644 --- a/tests/test_coder.py +++ b/tests/test_coder.py @@ -22,6 +22,37 @@ class TestCoder(unittest.TestCase): def tearDown(self): self.patcher.stop() + def test_allowed_to_edit(self): + with GitTemporaryDirectory(): + repo = git.Repo(Path.cwd()) + fname = Path("foo.txt") + fname.touch() + repo.git.add(str(fname)) + repo.git.commit("-m", "init") + + io = InputOutput(yes=True) + # Initialize the Coder object with the mocked IO and mocked repo + coder = Coder.create(models.GPT4, None, io, fnames=["foo.txt"]) + + self.assertTrue(coder.allowed_to_edit("foo.txt")) + self.assertTrue(coder.allowed_to_edit("new.txt")) + + def test_allowed_to_edit_no(self): + with GitTemporaryDirectory(): + repo = git.Repo(Path.cwd()) + fname = Path("foo.txt") + fname.touch() + repo.git.add(str(fname)) + repo.git.commit("-m", "init") + + # say NO + io = InputOutput(yes=False) + + coder = Coder.create(models.GPT4, None, io, fnames=["foo.txt"]) + + self.assertTrue(coder.allowed_to_edit("foo.txt")) + self.assertFalse(coder.allowed_to_edit("new.txt")) + def test_get_last_modified(self): # Mock the IO object mock_io = MagicMock()