Merge branch 'main' into indent-bad-edit

This commit is contained in:
Paul Gauthier 2023-08-08 12:43:57 -03:00
commit 77be993708
14 changed files with 150 additions and 49 deletions

View file

@ -1,8 +1,13 @@
# Release history # Release history
### main branch ### v0.11.1
- Fixed /commit bug from repo refactor, added test coverage - Added a progress bar when initially creating a repo map.
- Fixed bad commit message when adding new file to empty repo.
- Fixed corner case of pending chat history summarization when dirty committing.
- Fixed corner case of undefined `text` when using `--no-pretty`.
- Fixed /commit bug from repo refactor, added test coverage.
- [Benchmarked](https://aider.chat/docs/benchmarks.html) at 53.4% for gpt-3.5/whole (no regression).
### v0.11.0 ### v0.11.0

View file

@ -1,12 +1,14 @@
# aider is GPT powered coding in your terminal # aider is AI pair programming in your terminal
`aider` is a command-line chat tool that allows you to write and edit Aider is a command line tool that lets you pair program with GPT-3.5/GPT-4,
code with OpenAI's GPT models. You can ask GPT to help you start to edit code stored in your local git repository.
a new project, or modify code in your existing git repo. You can start a new project or work with an existing repo.
Aider makes it easy to And you can fluidly switch back and forth between the aider chat where you ask
[git commit, diff & undo changes](https://aider.chat/docs/faq.html#how-does-aider-use-git) GPT to edit the code and your own editor to make changes yourself.
proposed by GPT without copy/pasting. Aider makes sure edits from you and GPT are
It also has features that [help GPT-4 understand and modify larger codebases](https://aider.chat/docs/ctags.html). [committed to git](https://aider.chat/docs/faq.html#how-does-aider-use-git)
with sensible commit messages.
Aider is unique in that it [works well with pre-existing, larger codebases](https://aider.chat/docs/ctags.html).
<p align="center"> <p align="center">
<img src="assets/screencast.svg" alt="aider screencast"> <img src="assets/screencast.svg" alt="aider screencast">
@ -43,7 +45,7 @@ $ aider hello.js
Using git repo: .git Using git repo: .git
Added hello.js to the chat. Added hello.js to the chat.
hello.js> write a js app that prints hello world hello.js> write a js script that prints hello world
``` ```
## Example chat transcripts ## Example chat transcripts

View file

@ -20,7 +20,7 @@
<header class="page-header" role="banner"> <header class="page-header" role="banner">
{% if page.url == "/" %} {% if page.url == "/" %}
<h1 class="project-name">aider</h1> <h1 class="project-name">aider</h1>
<h2 class="project-tagline">GPT powered coding in your terminal</h2> <h2 class="project-tagline">AI pair programming in your terminal</h2>
{% else %} {% else %}
<h1 class="project-name">{{ page.title | default: site.title | default: site.github.repository_name }}</h1> <h1 class="project-name">{{ page.title | default: site.title | default: site.github.repository_name }}</h1>
<h2 class="project-tagline">{{ page.description | default: site.description | default: site.github.project_tagline }}</h2> <h2 class="project-tagline">{{ page.description | default: site.description | default: site.github.project_tagline }}</h2>

View file

@ -1 +1 @@
__version__ = "0.11.1-dev" __version__ = "0.11.2-dev"

View file

@ -365,8 +365,8 @@ class Coder:
if not self.summarizer.too_big(self.done_messages): if not self.summarizer.too_big(self.done_messages):
return return
assert self.summarizer_thread is None self.summarize_end()
assert self.summarized_done_messages is None
if self.verbose: if self.verbose:
self.io.tool_output("Starting to summarize chat history.") self.io.tool_output("Starting to summarize chat history.")
@ -653,6 +653,9 @@ class Coder:
live.start() live.start()
for chunk in completion: for chunk in completion:
if len(chunk.choices) == 0:
continue
if chunk.choices[0].finish_reason == "length": if chunk.choices[0].finish_reason == "length":
raise ExhaustedContextWindow() raise ExhaustedContextWindow()
@ -672,11 +675,11 @@ class Coder:
if text: if text:
self.partial_response_content += text self.partial_response_content += text
except AttributeError: except AttributeError:
pass text = None
if self.pretty: if self.pretty:
self.live_incremental_response(live, False) self.live_incremental_response(live, False)
else: elif text:
sys.stdout.write(text) sys.stdout.write(text)
sys.stdout.flush() sys.stdout.flush()
finally: finally:

View file

@ -350,8 +350,9 @@ class Commands:
combined_output = None combined_output = None
try: try:
parsed_args = shlex.split("git " + args) parsed_args = shlex.split("git " + args)
env = dict(GIT_EDITOR="true", **subprocess.os.environ)
result = subprocess.run( result = subprocess.run(
parsed_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True parsed_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, env=env
) )
combined_output = result.stdout combined_output = result.stdout
except Exception as e: except Exception as e:

View file

@ -126,19 +126,11 @@ class GitRepo:
return commit_message return commit_message
def get_diffs(self, pretty, *args): def get_diffs(self, pretty, *args):
try: # we always want diffs of working-dir + index versus repo
commits = self.repo.iter_commits(self.repo.active_branch) args = ["--cached"] + list(args)
current_branch_has_commits = any(commits)
except git.exc.GitCommandError:
current_branch_has_commits = False
if not current_branch_has_commits:
return ""
if pretty: if pretty:
args = ["--color"] + list(args) args = ["--color"] + list(args)
if not args:
args = ["HEAD"]
diffs = self.repo.git.diff(*args) diffs = self.repo.git.diff(*args)
return diffs return diffs

View file

@ -307,6 +307,10 @@ class RepoMap:
self.cache_missing = False self.cache_missing = False
for fname in fnames: for fname in fnames:
if not Path(fname).is_file():
self.io.tool_error(f"Repo-map can't include {fname}")
continue
# dump(fname) # dump(fname)
rel_fname = os.path.relpath(fname, self.root) rel_fname = os.path.relpath(fname, self.root)

View file

@ -41,6 +41,10 @@
color: #00FFFF; color: #00FFFF;
} }
.chat-transcript h1 {
display: none;
}
.chat-transcript h4 { .chat-transcript h4 {
color: #32FF32; color: #32FF32;
border-top: 1px solid #32FF32; border-top: 1px solid #32FF32;

View file

@ -107,41 +107,30 @@ In these cases, here are some things you might try:
## Can I use aider with other LLMs, local LLMs, etc? ## Can I use aider with other LLMs, local LLMs, etc?
Aider does not officially support use with LLMs other than OpenAI's gpt-3.5-turbo and gpt-4 Aider only has experimental support for LLMs other than OpenAI's GPT-3.5 and GPT-4. This is for two reasons:
and their variants.
This is because while it's "easy" to connect aider to a new LLM, it's "hard"
to actually teach new LLMs to *edit* code.
GPT-3.5 is just barely able to understand how to modify existing source code files, - GPT-3.5 is just barely capable of *editing code* to provide aider's interactive "pair programming" style workflow. None of the other models seem to be as capable as GPT-3.5.
and GPT-4 is quite good at it. - Just "hooking up" aider to a new model by connecting to its API is almost certainly not enough to get it working in a useful way. Getting aider working well with GPT-3.5 and GPT-4 was a significant undertaking, involving [specific code editing prompts and backends for each model and extensive benchmarking](https://aider.chat/docs/benchmarks.html). Officially supporting each new LLM will probably require a similar effort to tailor the prompts and editing backends.
Getting them working that well was a significant undertaking, involving
[specific code editing prompts and backends for each model and extensive benchmarking](https://aider.chat/docs/benchmarks.html).
Officially supporting new LLMs will probably require a similar effort to tailor the
prompts and editing backends.
That said, aider does provide some features to experiment with other models. That said, aider does provide features to experiment with other models. Numerous users have already done experiments with numerous models. None of these experiments have yet identified other models that look like they are capable of working with aider.
Numerous users have already done experiments with numerous models.
So far, no one has reported much success in working with them the way aider
can work with GPT-3.5 and GPT-4.
Once we see signs that a *particular* model is capable of code editing, Once we see signs that a *particular* model is capable of code editing, it would be reasonable for aider to attempt to officially support such a model. Until then, aider will simply maintain experimental support for using alternative models.
it would be reasonable for aider to attempt to officially support such a model.
Until then, aider will simply maintain experimental support for using alternative models. There are ongoing discussions about [LLM integrations in the aider discord](https://discord.com/channels/1131200896827654144/1133060780649087048).
Here are some [GitHub issues which may contain relevant information](https://github.com/paul-gauthier/aider/issues?q=is%3Aissue+%23172).
### OpenAI API compatible LLMs ### OpenAI API compatible LLMs
If you can make the model accessible via an OpenAI compatible API, If you can make the model accessible via an OpenAI compatible API,
you can use `--openai-api-base` to connect to a different API endpoint. you can use `--openai-api-base` to connect to a different API endpoint.
Here are some
[GitHub issues which may contain relevant information](https://github.com/paul-gauthier/aider/issues?q=is%3Aissue+%22openai-api-base%22+).
### Local LLMs ### Local LLMs
[LocalAI](https://github.com/go-skynet/LocalAI) [LocalAI](https://github.com/go-skynet/LocalAI)
and and
[SimpleAI](https://github.com/lhenault/simpleAI) [SimpleAI](https://github.com/lhenault/simpleAI)
look like relevant tools to serve local models via a compatible API: look like relevant tools to serve local models via a compatible API.
### Azure ### Azure

0
hello.py Normal file
View file

69
share/index.md Normal file
View file

@ -0,0 +1,69 @@
# Shared aider chat transcript
A user has shared the following transcript of a pair programming chat session
created using <a href="https://aider.chat">aider</a>.
Aider is a command line tool that lets you pair program with GPT-3.5 or
GPT-4, to edit code stored in your local git repository.
## Transcript format
<div class="chat-transcript" markdown="1">
> This is output from the aider tool.
#### These are chat messages written by the user.
Chat responses from GPT are in a blue font like this,
and often include colorized "diffs" where GPT is editing code:
```python
hello.py
<<<<<<< ORIGINAL
print("hello")
=======
print("goodbye")
>>>>>>> UPDATED
```
</div>
## Shared chat transcript
<div class="chat-transcript" id="shared-transcript">
</div>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script>
window.onload = function() {
var urlParams = new URLSearchParams(window.location.search);
var conv = urlParams.get('mdurl');
if (!conv) {
return;
}
// Check if the URL is a non-raw GitHub gist
var gistRegex = /^https:\/\/gist\.github\.com\/([^\/]+)\/([a-f0-9]+)$/;
var match = gistRegex.exec(conv);
if (match) {
// If it is, convert it into a raw URL
conv = 'https://gist.githubusercontent.com/' + match[1] + '/' + match[2] + '/raw';
}
fetch(conv)
.then(response => response.text())
.then(markdown => {
// Ensure every line that starts with '>' ends with exactly 2 spaces
markdown = markdown.split('\n').map(function(line) {
if (line.startsWith('>')) {
return line.trimEnd() + ' ';
}
return line;
}).join('\n');
var html = marked.parse(markdown);
var divElement = document.querySelector('#shared-transcript');
divElement.innerHTML = html;
})
.catch(error => {
console.error('Error fetching markdown:', error);
});
}
</script>

View file

@ -22,6 +22,25 @@ class TestCoder(unittest.TestCase):
def tearDown(self): def tearDown(self):
self.patcher.stop() self.patcher.stop()
def test_new_file_commit_message(self):
with GitTemporaryDirectory():
repo = git.Repo()
fname = Path("foo.txt")
io = InputOutput(yes=True)
# Initialize the Coder object with the mocked IO and mocked repo
coder = Coder.create(models.GPT4, None, io, fnames=[str(fname)])
self.assertTrue(fname.exists())
# Mock the get_commit_message method to return "I added str(fname)"
repo.get_commit_message = MagicMock(return_value=f"I added {str(fname)}")
# Get the latest commit message
commit_message = repo.get_commit_message()
# Check that the latest commit message is "I added str(fname)"
self.assertEqual(commit_message, f"I added {str(fname)}")
def test_allowed_to_edit(self): def test_allowed_to_edit(self):
with GitTemporaryDirectory(): with GitTemporaryDirectory():
repo = git.Repo(Path.cwd()) repo = git.Repo(Path.cwd())

View file

@ -13,6 +13,19 @@ from tests.utils import GitTemporaryDirectory
class TestRepo(unittest.TestCase): class TestRepo(unittest.TestCase):
def test_diffs_empty_repo(self):
with GitTemporaryDirectory():
repo = git.Repo()
fname = Path("foo.txt")
fname.touch()
repo.git.add(str(fname))
git_repo = GitRepo(InputOutput(), None, ".")
diffs = git_repo.get_diffs(False)
self.assertNotEqual(diffs, "")
self.assertIsNotNone(diffs)
@patch("aider.repo.simple_send_with_retries") @patch("aider.repo.simple_send_with_retries")
def test_get_commit_message(self, mock_send): def test_get_commit_message(self, mock_send):
mock_send.return_value = "a good commit message" mock_send.return_value = "a good commit message"