mirror of
https://github.com/Aider-AI/aider
synced 2026-04-26 01:25:17 +02:00
Compare commits
258 Commits
v0.55.1.de
...
v0.57.1.de
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6408a9fbf9 | ||
|
|
cf56369410 | ||
|
|
2ca093fb84 | ||
|
|
237c4ab323 | ||
|
|
cfe1d540f1 | ||
|
|
f29825ff22 | ||
|
|
565c305aa6 | ||
|
|
b27738d39a | ||
|
|
412b8e7c3c | ||
|
|
5493654981 | ||
|
|
167b1ed491 | ||
|
|
454a2ebdcf | ||
|
|
7fa1620f58 | ||
|
|
230ec50209 | ||
|
|
2753ac6b62 | ||
|
|
5139594fa0 | ||
|
|
d26fca0bca | ||
|
|
d7051ce736 | ||
|
|
b3e5caf330 | ||
|
|
2a4527a5af | ||
|
|
243be27eb8 | ||
|
|
671c633d8f | ||
|
|
d94c1c0e1f | ||
|
|
88eaf8cf1d | ||
|
|
84ca8dd582 | ||
|
|
8349cd5c15 | ||
|
|
7d766d53ee | ||
|
|
2cabf9718c | ||
|
|
0030d11ac7 | ||
|
|
31655889cf | ||
|
|
851f0653d6 | ||
|
|
c111e7a30e | ||
|
|
7dd0a0f348 | ||
|
|
3d70f88bcc | ||
|
|
215833d326 | ||
|
|
ba257d653c | ||
|
|
99d196d06e | ||
|
|
619127925d | ||
|
|
86dc25d342 | ||
|
|
dd1ae5bd3a | ||
|
|
40202a9cb8 | ||
|
|
08d465c252 | ||
|
|
81bad77fa9 | ||
|
|
ada7b3d7ab | ||
|
|
04aecbe9a9 | ||
|
|
6b9fc86e99 | ||
|
|
1ede98bc07 | ||
|
|
eb078906b3 | ||
|
|
51017d7a5b | ||
|
|
2463cbfd6c | ||
|
|
c13aadaa0e | ||
|
|
e6037140be | ||
|
|
eba845ea51 | ||
|
|
d747a3781d | ||
|
|
9768e84fcd | ||
|
|
72f52bdef0 | ||
|
|
c00ac80909 | ||
|
|
1fbb5079d5 | ||
|
|
752e823da8 | ||
|
|
45474a230e | ||
|
|
af407c4c8f | ||
|
|
b4dad65e9f | ||
|
|
291d3509eb | ||
|
|
84b1c1031a | ||
|
|
71c5fd1372 | ||
|
|
2605d44db6 | ||
|
|
4598a376fd | ||
|
|
9f4d9d801e | ||
|
|
859fc1f184 | ||
|
|
99a75ac213 | ||
|
|
94a2bc5ef5 | ||
|
|
efa0c0e292 | ||
|
|
fb420de09e | ||
|
|
09cb4c4b09 | ||
|
|
1755d2e0f4 | ||
|
|
8aee4d25ed | ||
|
|
71f3f3a22b | ||
|
|
297b51b997 | ||
|
|
6eb993999a | ||
|
|
96587f5f46 | ||
|
|
291b456a45 | ||
|
|
d84a9d6df2 | ||
|
|
13d3b7c9b3 | ||
|
|
94af92c784 | ||
|
|
36fa773376 | ||
|
|
05b3b3df88 | ||
|
|
1603ffa6c2 | ||
|
|
615dc5fe4b | ||
|
|
385f2693c4 | ||
|
|
35588b6984 | ||
|
|
ca43a37567 | ||
|
|
94a609d75e | ||
|
|
13ac0f0968 | ||
|
|
408ecc1bd7 | ||
|
|
ba54e4a6e0 | ||
|
|
b43ed20085 | ||
|
|
007f841328 | ||
|
|
5cdcbb1a26 | ||
|
|
7315624b98 | ||
|
|
0a3b4147fa | ||
|
|
fa49ab09c4 | ||
|
|
d1384e9d5f | ||
|
|
33b11d0efb | ||
|
|
fd18adb072 | ||
|
|
454c2f4d0e | ||
|
|
59bdc45728 | ||
|
|
645252168c | ||
|
|
fb87dd883c | ||
|
|
8da88eef64 | ||
|
|
3685f307c7 | ||
|
|
d5d087123a | ||
|
|
1d312e372d | ||
|
|
13fe2036db | ||
|
|
d4e47bc7e7 | ||
|
|
79a424bc10 | ||
|
|
ed866d33e4 | ||
|
|
04556ef32d | ||
|
|
36553d797f | ||
|
|
2c08cc47e6 | ||
|
|
971fe5017a | ||
|
|
e3e6437dca | ||
|
|
c575bae710 | ||
|
|
13f9685f13 | ||
|
|
00f03d89b9 | ||
|
|
484fdd7aa3 | ||
|
|
c152c96fcc | ||
|
|
89891efbb8 | ||
|
|
43eaf91e8d | ||
|
|
bf3a165961 | ||
|
|
33b69d2ee8 | ||
|
|
766569a278 | ||
|
|
cc94b51a0b | ||
|
|
f1d1d1b37a | ||
|
|
e84caa48a0 | ||
|
|
ab9d9c8429 | ||
|
|
625a49752b | ||
|
|
e5ff5eff75 | ||
|
|
cb42464676 | ||
|
|
5de0a0f7a9 | ||
|
|
765ea801b1 | ||
|
|
1327c1e893 | ||
|
|
4605969921 | ||
|
|
e3b7b80280 | ||
|
|
b8ce472cb6 | ||
|
|
6a0ad9629b | ||
|
|
d99191e07b | ||
|
|
6cddc800f1 | ||
|
|
de84a08924 | ||
|
|
fb1a9254c7 | ||
|
|
5420f67b2b | ||
|
|
fe2e36afda | ||
|
|
b216d57107 | ||
|
|
509c880b68 | ||
|
|
6f2b064f53 | ||
|
|
26c2b2e3ed | ||
|
|
3976d4b8f1 | ||
|
|
964fe7e2dc | ||
|
|
eced076602 | ||
|
|
bd21122e64 | ||
|
|
00f42590c8 | ||
|
|
4e63254704 | ||
|
|
3cd6790d9a | ||
|
|
d82d21b8c1 | ||
|
|
1a6284cb24 | ||
|
|
abf6a9db2e | ||
|
|
73e7d7bd2a | ||
|
|
82f8aa5d6a | ||
|
|
cee348614e | ||
|
|
e40a07a8a1 | ||
|
|
99dc235a00 | ||
|
|
9982f439e4 | ||
|
|
1e9ff842f3 | ||
|
|
aeea629d17 | ||
|
|
b4389f98fb | ||
|
|
f54b6860db | ||
|
|
ed7a9c6562 | ||
|
|
ab35e473f3 | ||
|
|
e526d2890c | ||
|
|
2eae3738ff | ||
|
|
f98b64dd98 | ||
|
|
d2379a6d73 | ||
|
|
84758c6c8d | ||
|
|
f4853d166f | ||
|
|
69b9a4510d | ||
|
|
9d4316b1d5 | ||
|
|
11020c8aee | ||
|
|
df33498cad | ||
|
|
d85979e1fb | ||
|
|
74f1ceff93 | ||
|
|
68bd2b75c6 | ||
|
|
5344052aeb | ||
|
|
304566a914 | ||
|
|
e9c0c82e03 | ||
|
|
2aef59e624 | ||
|
|
74631eec98 | ||
|
|
3a36edb8ec | ||
|
|
795810ffb8 | ||
|
|
2663233b60 | ||
|
|
8d151a3573 | ||
|
|
1c73e7d43a | ||
|
|
8cfdcbd976 | ||
|
|
45855bd96c | ||
|
|
b57468a963 | ||
|
|
34099408a5 | ||
|
|
781996fe84 | ||
|
|
3d73fac84c | ||
|
|
2bcc9a54a9 | ||
|
|
e4cbbb1fa8 | ||
|
|
a35c532211 | ||
|
|
c2b8522e9a | ||
|
|
5123d8c5de | ||
|
|
9b924237b7 | ||
|
|
c04453d282 | ||
|
|
f02da16353 | ||
|
|
6c739d391b | ||
|
|
e3cd9a8f9a | ||
|
|
76bc0e11b8 | ||
|
|
485d5487af | ||
|
|
246ce318d2 | ||
|
|
6e3d8d90de | ||
|
|
2d866418da | ||
|
|
ff15bcdb30 | ||
|
|
e799ada6f5 | ||
|
|
7c5cad74ab | ||
|
|
41e8f4401e | ||
|
|
e271941aa2 | ||
|
|
6152a82513 | ||
|
|
937a1cd847 | ||
|
|
867d19952c | ||
|
|
7c5d999032 | ||
|
|
6d23b22e6f | ||
|
|
168598dad4 | ||
|
|
bd7ff9cca4 | ||
|
|
51f360ab9f | ||
|
|
66ae9ae079 | ||
|
|
65fd6b444c | ||
|
|
15abe6b921 | ||
|
|
d8027030b0 | ||
|
|
edd9b44ad3 | ||
|
|
14fc3e3ad1 | ||
|
|
cd551dbf63 | ||
|
|
ed349b65b5 | ||
|
|
bb5bca5227 | ||
|
|
e98645698b | ||
|
|
376e8617f3 | ||
|
|
a3d585a4b4 | ||
|
|
5853c7fa92 | ||
|
|
18bf3a9f36 | ||
|
|
e7253d819e | ||
|
|
75c27a5dfb | ||
|
|
7598f883f5 | ||
|
|
1b5ef76c18 | ||
|
|
70994cfc5b | ||
|
|
c5ac621da1 | ||
|
|
5c6d4dbbf1 | ||
|
|
9434f99458 | ||
|
|
9988a3ff79 | ||
|
|
9364ce1f15 |
@@ -14,3 +14,9 @@ repos:
|
||||
hooks:
|
||||
- id: flake8
|
||||
args: ["--show-source"]
|
||||
- repo: https://github.com/codespell-project/codespell
|
||||
rev: v2.2.6
|
||||
hooks:
|
||||
- id: codespell
|
||||
additional_dependencies:
|
||||
- tomli
|
||||
|
||||
@@ -20,7 +20,7 @@ See the
|
||||
[benchmark README](https://github.com/paul-gauthier/aider/blob/main/benchmark/README.md)
|
||||
for information on running aider's code editing benchmarks.
|
||||
Submit results by opening a PR with edits to the
|
||||
[benchmark results data files](https://github.com/paul-gauthier/aider/blob/main/_data/).
|
||||
[benchmark results data files](https://github.com/paul-gauthier/aider/blob/main/aider/website/_data/).
|
||||
|
||||
|
||||
## Pull Requests
|
||||
|
||||
32
HISTORY.md
32
HISTORY.md
@@ -1,6 +1,36 @@
|
||||
|
||||
# Release history
|
||||
|
||||
### Aider v0.57.0
|
||||
|
||||
- Support for OpenAI o1 models:
|
||||
- o1-preview now works well with diff edit format.
|
||||
- o1-preview with diff now matches SOTA leaderboard result with whole edit format.
|
||||
- `aider --model o1-mini`
|
||||
- `aider --model o1-preview`
|
||||
- On Windows, `/run` correctly uses PowerShell or cmd.exe.
|
||||
- Support for new 08-2024 Cohere models, by @jalammar.
|
||||
- Can now recursively add directories with `/read-only`.
|
||||
- User input prompts now fall back to simple `input()` if `--no-pretty` or a Windows console is not available.
|
||||
- Improved sanity check of git repo on startup.
|
||||
- Improvements to prompt cache chunking strategy.
|
||||
- Removed "No changes made to git tracked files".
|
||||
- Numerous bug fixes for corner case crashes.
|
||||
- Updated all dependency versions.
|
||||
- Aider wrote 70% of the code in this release.
|
||||
|
||||
### Aider v0.56.0
|
||||
|
||||
- Enables prompt caching for Sonnet via OpenRouter by @fry69
|
||||
- Enables 8k output tokens for Sonnet via VertexAI and DeepSeek V2.5.
|
||||
- New `/report` command to open your browser with a pre-populated GitHub Issue.
|
||||
- New `--chat-language` switch to set the spoken language.
|
||||
- Now `--[no-]suggest-shell-commands` controls both prompting for and offering to execute shell commands.
|
||||
- Check key imports on launch, provide helpful error message if dependencies aren't available.
|
||||
- Renamed `--models` to `--list-models` by @fry69.
|
||||
- Numerous bug fixes for corner case crashes.
|
||||
- Aider wrote 56% of the code in this release.
|
||||
|
||||
### Aider v0.55.0
|
||||
|
||||
- Only print the pip command when self updating on Windows, without running it.
|
||||
@@ -676,7 +706,7 @@
|
||||
|
||||
- Added `/git` command to run git from inside aider chats.
|
||||
- Use Meta-ENTER (Esc+ENTER in some environments) to enter multiline chat messages.
|
||||
- Create a `.gitignore` with `.aider*` to prevent users from accidentaly adding aider files to git.
|
||||
- Create a `.gitignore` with `.aider*` to prevent users from accidentally adding aider files to git.
|
||||
- Check pypi for newer versions and notify user.
|
||||
- Updated keyboard interrupt logic so that 2 ^C in 2 seconds always forces aider to exit.
|
||||
- Provide GPT with detailed error if it makes a bad edit block, ask for a retry.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
try:
|
||||
from aider.__version__ import __version__
|
||||
except Exception:
|
||||
__version__ = "0.55.1.dev"
|
||||
__version__ = "0.57.1.dev"
|
||||
|
||||
__all__ = [__version__]
|
||||
|
||||
@@ -121,6 +121,7 @@ def get_parser(default_config_files, git_root):
|
||||
##########
|
||||
group = parser.add_argument_group("Model Settings")
|
||||
group.add_argument(
|
||||
"--list-models",
|
||||
"--models",
|
||||
metavar="MODEL",
|
||||
help="List known models which match the (partial) MODEL name",
|
||||
@@ -490,6 +491,12 @@ def get_parser(default_config_files, git_root):
|
||||
default="en",
|
||||
help="Specify the language for voice using ISO 639-1 code (default: auto)",
|
||||
)
|
||||
group.add_argument(
|
||||
"--chat-language",
|
||||
metavar="CHAT_LANGUAGE",
|
||||
default=None,
|
||||
help="Specify the language to use in the chat (default: None, uses system settings)",
|
||||
)
|
||||
group.add_argument(
|
||||
"--version",
|
||||
action="version",
|
||||
|
||||
@@ -144,8 +144,12 @@ class YamlHelpFormatter(argparse.HelpFormatter):
|
||||
|
||||
if default:
|
||||
parts.append(f"#{switch}: {default}\n")
|
||||
elif action.nargs in ("*", "+") or isinstance(action, argparse._AppendAction):
|
||||
parts.append(f"#{switch}: xxx")
|
||||
parts.append("## Specify multiple values like this:")
|
||||
parts.append(f"#{switch}: [xxx,yyyy,zzz]\n")
|
||||
else:
|
||||
parts.append(f"#{switch}:\n")
|
||||
parts.append(f"#{switch}: xxx\n")
|
||||
|
||||
###
|
||||
# parts.append(str(action))
|
||||
|
||||
@@ -18,16 +18,12 @@ from datetime import datetime
|
||||
from json.decoder import JSONDecodeError
|
||||
from pathlib import Path
|
||||
|
||||
from rich.console import Console, Text
|
||||
from rich.markdown import Markdown
|
||||
|
||||
from aider import __version__, models, prompts, urls, utils
|
||||
from aider.commands import Commands
|
||||
from aider.history import ChatSummary
|
||||
from aider.io import ConfirmGroup, InputOutput
|
||||
from aider.linter import Linter
|
||||
from aider.llm import litellm
|
||||
from aider.mdstream import MarkdownStream
|
||||
from aider.repo import ANY_GIT_ERROR, GitRepo
|
||||
from aider.repomap import RepoMap
|
||||
from aider.run_cmd import run_cmd
|
||||
@@ -93,6 +89,7 @@ class Coder:
|
||||
num_cache_warming_pings = 0
|
||||
suggest_shell_commands = True
|
||||
ignore_mentions = None
|
||||
chat_language = None
|
||||
|
||||
@classmethod
|
||||
def create(
|
||||
@@ -159,7 +156,9 @@ class Coder:
|
||||
raise ValueError(f"Unknown edit format {edit_format}")
|
||||
|
||||
def clone(self, **kwargs):
|
||||
return Coder.create(from_coder=self, **kwargs)
|
||||
new_coder = Coder.create(from_coder=self, **kwargs)
|
||||
new_coder.ignore_mentions = self.ignore_mentions
|
||||
return new_coder
|
||||
|
||||
def get_announcements(self):
|
||||
lines = []
|
||||
@@ -238,8 +237,6 @@ class Coder:
|
||||
dry_run=False,
|
||||
map_tokens=1024,
|
||||
verbose=False,
|
||||
assistant_output_color="blue",
|
||||
code_theme="default",
|
||||
stream=True,
|
||||
use_git=True,
|
||||
cur_messages=None,
|
||||
@@ -258,7 +255,9 @@ class Coder:
|
||||
cache_prompts=False,
|
||||
num_cache_warming_pings=0,
|
||||
suggest_shell_commands=True,
|
||||
chat_language=None,
|
||||
):
|
||||
self.chat_language = chat_language
|
||||
self.commit_before_message = []
|
||||
self.aider_commit_hashes = set()
|
||||
self.rejected_urls = set()
|
||||
@@ -310,17 +309,10 @@ class Coder:
|
||||
|
||||
self.auto_commits = auto_commits
|
||||
self.dirty_commits = dirty_commits
|
||||
self.assistant_output_color = assistant_output_color
|
||||
self.code_theme = code_theme
|
||||
|
||||
self.dry_run = dry_run
|
||||
self.pretty = self.io.pretty
|
||||
|
||||
if self.pretty:
|
||||
self.console = Console()
|
||||
else:
|
||||
self.console = Console(force_terminal=False, no_color=True)
|
||||
|
||||
self.main_model = main_model
|
||||
|
||||
if cache_prompts and self.main_model.cache_control:
|
||||
@@ -501,9 +493,10 @@ class Coder:
|
||||
if content is not None:
|
||||
all_content += content + "\n"
|
||||
|
||||
lines = all_content.splitlines()
|
||||
good = False
|
||||
for fence_open, fence_close in self.fences:
|
||||
if fence_open in all_content or fence_close in all_content:
|
||||
if any(line.startswith(fence_open) or line.startswith(fence_close) for line in lines):
|
||||
continue
|
||||
good = True
|
||||
break
|
||||
@@ -854,6 +847,9 @@ class Coder:
|
||||
self.cur_messages = []
|
||||
|
||||
def get_user_language(self):
|
||||
if self.chat_language:
|
||||
return self.chat_language
|
||||
|
||||
try:
|
||||
lang = locale.getlocale()[0]
|
||||
if lang:
|
||||
@@ -915,10 +911,21 @@ class Coder:
|
||||
lazy_prompt = self.gpt_prompts.lazy_prompt if self.main_model.lazy else ""
|
||||
platform_text = self.get_platform_info()
|
||||
|
||||
if self.suggest_shell_commands:
|
||||
shell_cmd_prompt = self.gpt_prompts.shell_cmd_prompt.format(platform=platform_text)
|
||||
shell_cmd_reminder = self.gpt_prompts.shell_cmd_reminder.format(platform=platform_text)
|
||||
else:
|
||||
shell_cmd_prompt = self.gpt_prompts.no_shell_cmd_prompt.format(platform=platform_text)
|
||||
shell_cmd_reminder = self.gpt_prompts.no_shell_cmd_reminder.format(
|
||||
platform=platform_text
|
||||
)
|
||||
|
||||
prompt = prompt.format(
|
||||
fence=self.fence,
|
||||
lazy_prompt=lazy_prompt,
|
||||
platform=platform_text,
|
||||
shell_cmd_prompt=shell_cmd_prompt,
|
||||
shell_cmd_reminder=shell_cmd_reminder,
|
||||
)
|
||||
return prompt
|
||||
|
||||
@@ -960,9 +967,16 @@ class Coder:
|
||||
|
||||
chunks = ChatChunks()
|
||||
|
||||
chunks.system = [
|
||||
dict(role="system", content=main_sys),
|
||||
]
|
||||
if self.main_model.use_system_prompt:
|
||||
chunks.system = [
|
||||
dict(role="system", content=main_sys),
|
||||
]
|
||||
else:
|
||||
chunks.system = [
|
||||
dict(role="user", content=main_sys),
|
||||
dict(role="assistant", content="Ok."),
|
||||
]
|
||||
|
||||
chunks.examples = example_messages
|
||||
|
||||
self.summarize_end()
|
||||
@@ -1088,11 +1102,7 @@ class Coder:
|
||||
utils.show_messages(messages, functions=self.functions)
|
||||
|
||||
self.multi_response_content = ""
|
||||
if self.show_pretty() and self.stream:
|
||||
mdargs = dict(style=self.assistant_output_color, code_theme=self.code_theme)
|
||||
self.mdstream = MarkdownStream(mdargs=mdargs)
|
||||
else:
|
||||
self.mdstream = None
|
||||
self.mdstream = self.io.assistant_output("", self.stream)
|
||||
|
||||
retry_delay = 0.125
|
||||
|
||||
@@ -1372,6 +1382,11 @@ class Coder:
|
||||
|
||||
self.io.log_llm_history("TO LLM", format_messages(messages))
|
||||
|
||||
if self.main_model.use_temperature:
|
||||
temp = self.temperature
|
||||
else:
|
||||
temp = None
|
||||
|
||||
completion = None
|
||||
try:
|
||||
hash_object, completion = send_completion(
|
||||
@@ -1379,7 +1394,7 @@ class Coder:
|
||||
messages,
|
||||
functions,
|
||||
self.stream,
|
||||
self.temperature,
|
||||
temp,
|
||||
extra_headers=model.extra_headers,
|
||||
max_tokens=model.max_tokens,
|
||||
)
|
||||
@@ -1444,14 +1459,7 @@ class Coder:
|
||||
raise Exception("No data found in LLM response!")
|
||||
|
||||
show_resp = self.render_incremental_response(True)
|
||||
if self.show_pretty():
|
||||
show_resp = Markdown(
|
||||
show_resp, style=self.assistant_output_color, code_theme=self.code_theme
|
||||
)
|
||||
else:
|
||||
show_resp = Text(show_resp or "<no response>")
|
||||
|
||||
self.io.console.print(show_resp)
|
||||
self.io.assistant_output(show_resp)
|
||||
|
||||
if (
|
||||
hasattr(completion.choices[0], "finish_reason")
|
||||
@@ -1624,7 +1632,10 @@ class Coder:
|
||||
return cur + new
|
||||
|
||||
def get_rel_fname(self, fname):
|
||||
return os.path.relpath(fname, self.root)
|
||||
try:
|
||||
return os.path.relpath(fname, self.root)
|
||||
except ValueError:
|
||||
return fname
|
||||
|
||||
def get_inchat_relative_files(self):
|
||||
files = [self.get_rel_fname(fname) for fname in self.abs_fnames]
|
||||
@@ -1869,7 +1880,6 @@ class Coder:
|
||||
message=commit_message,
|
||||
)
|
||||
|
||||
self.io.tool_output("No changes made to git tracked files.")
|
||||
return self.gpt_prompts.files_content_gpt_no_edits
|
||||
except ANY_GIT_ERROR as err:
|
||||
self.io.tool_error(f"Unable to commit: {str(err)}")
|
||||
|
||||
@@ -43,3 +43,8 @@ If you need to edit any of these files, ask me to *add them to the chat* first.
|
||||
read_only_files_prefix = """Here are some READ ONLY files, provided for your reference.
|
||||
Do not edit these files!
|
||||
"""
|
||||
|
||||
shell_cmd_prompt = ""
|
||||
shell_cmd_reminder = ""
|
||||
no_shell_cmd_prompt = ""
|
||||
no_shell_cmd_reminder = ""
|
||||
|
||||
@@ -31,10 +31,12 @@ class ChatChunks:
|
||||
else:
|
||||
self.add_cache_control(self.system)
|
||||
|
||||
if self.readonly_files:
|
||||
self.add_cache_control(self.readonly_files)
|
||||
else:
|
||||
if self.repo:
|
||||
# this will mark both the readonly_files and repomap chunk as cacheable
|
||||
self.add_cache_control(self.repo)
|
||||
else:
|
||||
# otherwise, just cache readonly_files if there are any
|
||||
self.add_cache_control(self.readonly_files)
|
||||
|
||||
self.add_cache_control(self.chat_files)
|
||||
|
||||
|
||||
@@ -365,9 +365,13 @@ def do_replace(fname, content, before_text, after_text, fence=None):
|
||||
return new_content
|
||||
|
||||
|
||||
HEAD = "<<<<<<< SEARCH"
|
||||
DIVIDER = "======="
|
||||
UPDATED = ">>>>>>> REPLACE"
|
||||
HEAD = r"<{5,9} SEARCH"
|
||||
DIVIDER = r"={5,9}"
|
||||
UPDATED = r">{5,9} REPLACE"
|
||||
|
||||
HEAD_ERR = "<<<<<<< SEARCH"
|
||||
DIVIDER_ERR = "======="
|
||||
UPDATED_ERR = ">>>>>>> REPLACE"
|
||||
|
||||
separators = "|".join([HEAD, DIVIDER, UPDATED])
|
||||
|
||||
@@ -407,6 +411,10 @@ def find_original_update_blocks(content, fence=DEFAULT_FENCE, valid_fnames=None)
|
||||
i = 0
|
||||
current_filename = None
|
||||
|
||||
head_pattern = re.compile(HEAD)
|
||||
divider_pattern = re.compile(DIVIDER)
|
||||
updated_pattern = re.compile(UPDATED)
|
||||
|
||||
while i < len(lines):
|
||||
line = lines[i]
|
||||
|
||||
@@ -425,7 +433,7 @@ def find_original_update_blocks(content, fence=DEFAULT_FENCE, valid_fnames=None)
|
||||
"```csh",
|
||||
"```tcsh",
|
||||
]
|
||||
next_is_editblock = i + 1 < len(lines) and lines[i + 1].rstrip() == HEAD
|
||||
next_is_editblock = i + 1 < len(lines) and head_pattern.match(lines[i + 1].strip())
|
||||
|
||||
if any(line.strip().startswith(start) for start in shell_starts) and not next_is_editblock:
|
||||
shell_content = []
|
||||
@@ -440,15 +448,13 @@ def find_original_update_blocks(content, fence=DEFAULT_FENCE, valid_fnames=None)
|
||||
continue
|
||||
|
||||
# Check for SEARCH/REPLACE blocks
|
||||
if line.strip() == HEAD:
|
||||
if head_pattern.match(line.strip()):
|
||||
try:
|
||||
# if next line after HEAD exists and is DIVIDER, it's a new file
|
||||
if i + 1 < len(lines) and lines[i + 1].strip() == DIVIDER:
|
||||
if i + 1 < len(lines) and divider_pattern.match(lines[i + 1].strip()):
|
||||
filename = find_filename(lines[max(0, i - 3) : i], fence, None)
|
||||
else:
|
||||
filename = find_filename(
|
||||
lines[max(0, i - 3) : i], fence, valid_fnames
|
||||
)
|
||||
filename = find_filename(lines[max(0, i - 3) : i], fence, valid_fnames)
|
||||
|
||||
if not filename:
|
||||
if current_filename:
|
||||
@@ -460,21 +466,27 @@ def find_original_update_blocks(content, fence=DEFAULT_FENCE, valid_fnames=None)
|
||||
|
||||
original_text = []
|
||||
i += 1
|
||||
while i < len(lines) and not lines[i].strip() == DIVIDER:
|
||||
while i < len(lines) and not divider_pattern.match(lines[i].strip()):
|
||||
original_text.append(lines[i])
|
||||
i += 1
|
||||
|
||||
if i >= len(lines) or lines[i].strip() != DIVIDER:
|
||||
raise ValueError(f"Expected `{DIVIDER}`")
|
||||
if i >= len(lines) or not divider_pattern.match(lines[i].strip()):
|
||||
raise ValueError(f"Expected `{DIVIDER_ERR}`")
|
||||
|
||||
updated_text = []
|
||||
i += 1
|
||||
while i < len(lines) and not lines[i].strip() in (UPDATED, DIVIDER):
|
||||
while i < len(lines) and not (
|
||||
updated_pattern.match(lines[i].strip())
|
||||
or divider_pattern.match(lines[i].strip())
|
||||
):
|
||||
updated_text.append(lines[i])
|
||||
i += 1
|
||||
|
||||
if i >= len(lines) or lines[i].strip() not in (UPDATED, DIVIDER):
|
||||
raise ValueError(f"Expected `{UPDATED}` or `{DIVIDER}`")
|
||||
if i >= len(lines) or not (
|
||||
updated_pattern.match(lines[i].strip())
|
||||
or divider_pattern.match(lines[i].strip())
|
||||
):
|
||||
raise ValueError(f"Expected `{UPDATED_ERR}` or `{DIVIDER_ERR}`")
|
||||
|
||||
yield filename, "".join(original_text), "".join(updated_text)
|
||||
|
||||
|
||||
@@ -27,7 +27,10 @@ You can keep asking if you then decide you need to edit more files.
|
||||
|
||||
All changes to files must use this *SEARCH/REPLACE block* format.
|
||||
ONLY EVER RETURN CODE IN A *SEARCH/REPLACE BLOCK*!
|
||||
{shell_cmd_prompt}
|
||||
"""
|
||||
|
||||
shell_cmd_prompt = """
|
||||
4. *Concisely* suggest any shell commands the user might want to run in ```bash blocks.
|
||||
|
||||
Just suggest shell commands this way, not example code.
|
||||
@@ -36,7 +39,6 @@ Only suggest at most a few shell commands at a time, not more than 1-3.
|
||||
|
||||
Use the appropriate shell based on the user's system info:
|
||||
{platform}
|
||||
|
||||
Examples of when to suggest shell commands:
|
||||
|
||||
- If you changed a self-contained html file, suggest an OS-appropriate command to open a browser to view it to see the updated content.
|
||||
@@ -47,6 +49,10 @@ Examples of when to suggest shell commands:
|
||||
- Etc.
|
||||
"""
|
||||
|
||||
no_shell_cmd_prompt = """
|
||||
Keep in mind these details about the user's platform and environment:
|
||||
{platform}
|
||||
"""
|
||||
example_messages = [
|
||||
dict(
|
||||
role="user",
|
||||
@@ -176,7 +182,10 @@ To rename files which have been added to the chat, use shell commands at the end
|
||||
|
||||
{lazy_prompt}
|
||||
ONLY EVER RETURN CODE IN A *SEARCH/REPLACE BLOCK*!
|
||||
{shell_cmd_reminder}
|
||||
"""
|
||||
|
||||
shell_cmd_reminder = """
|
||||
Examples of when to suggest shell commands:
|
||||
|
||||
- If you changed a self-contained html file, suggest an OS-appropriate command to open a browser to view it to see the updated content.
|
||||
|
||||
@@ -562,8 +562,7 @@ class Commands:
|
||||
"HEAD",
|
||||
)
|
||||
|
||||
# don't use io.tool_output() because we don't want to log or further colorize
|
||||
print(diff)
|
||||
self.io.print(diff)
|
||||
|
||||
def quote_fname(self, fname):
|
||||
if " " in fname and '"' not in fname:
|
||||
@@ -1030,9 +1029,9 @@ class Commands:
|
||||
|
||||
if text:
|
||||
self.io.add_to_input_history(text)
|
||||
print()
|
||||
self.io.print()
|
||||
self.io.user_input(text, log_only=False)
|
||||
print()
|
||||
self.io.print()
|
||||
|
||||
return text
|
||||
|
||||
@@ -1088,7 +1087,7 @@ class Commands:
|
||||
def cmd_read_only(self, args):
|
||||
"Add files to the chat that are for reference, not to be edited"
|
||||
if not args.strip():
|
||||
self.io.tool_error("Please provide filenames to read.")
|
||||
self.io.tool_error("Please provide filenames or directories to read.")
|
||||
return
|
||||
|
||||
filenames = parse_quoted_filenames(args)
|
||||
@@ -1098,23 +1097,43 @@ class Commands:
|
||||
abs_path = self.coder.abs_root_path(expanded_path)
|
||||
|
||||
if not os.path.exists(abs_path):
|
||||
self.io.tool_error(f"File not found: {abs_path}")
|
||||
self.io.tool_error(f"Path not found: {abs_path}")
|
||||
continue
|
||||
|
||||
if not os.path.isfile(abs_path):
|
||||
self.io.tool_error(f"Not a file: {abs_path}")
|
||||
continue
|
||||
|
||||
if abs_path in self.coder.abs_fnames:
|
||||
self.io.tool_error(f"{word} is already in the chat as an editable file")
|
||||
continue
|
||||
|
||||
if abs_path in self.coder.abs_read_only_fnames:
|
||||
self.io.tool_error(f"{word} is already in the chat as a read-only file")
|
||||
continue
|
||||
if os.path.isfile(abs_path):
|
||||
self._add_read_only_file(abs_path, word)
|
||||
elif os.path.isdir(abs_path):
|
||||
self._add_read_only_directory(abs_path, word)
|
||||
else:
|
||||
self.io.tool_error(f"Not a file or directory: {abs_path}")
|
||||
|
||||
def _add_read_only_file(self, abs_path, original_name):
|
||||
if abs_path in self.coder.abs_fnames:
|
||||
self.io.tool_error(f"{original_name} is already in the chat as an editable file")
|
||||
elif abs_path in self.coder.abs_read_only_fnames:
|
||||
self.io.tool_error(f"{original_name} is already in the chat as a read-only file")
|
||||
else:
|
||||
self.coder.abs_read_only_fnames.add(abs_path)
|
||||
self.io.tool_output(f"Added {word} to read-only files.")
|
||||
self.io.tool_output(f"Added {original_name} to read-only files.")
|
||||
|
||||
def _add_read_only_directory(self, abs_path, original_name):
|
||||
added_files = 0
|
||||
for root, _, files in os.walk(abs_path):
|
||||
for file in files:
|
||||
file_path = os.path.join(root, file)
|
||||
if (
|
||||
file_path not in self.coder.abs_fnames
|
||||
and file_path not in self.coder.abs_read_only_fnames
|
||||
):
|
||||
self.coder.abs_read_only_fnames.add(file_path)
|
||||
added_files += 1
|
||||
|
||||
if added_files > 0:
|
||||
self.io.tool_output(
|
||||
f"Added {added_files} files from directory {original_name} to read-only files."
|
||||
)
|
||||
else:
|
||||
self.io.tool_output(f"No new files added from directory {original_name}.")
|
||||
|
||||
def cmd_map(self, args):
|
||||
"Print out the current repository map"
|
||||
@@ -1135,6 +1154,20 @@ class Commands:
|
||||
settings = format_settings(self.parser, self.args)
|
||||
self.io.tool_output(settings)
|
||||
|
||||
def cmd_report(self, args):
|
||||
"Report a problem by opening a GitHub Issue"
|
||||
from aider.report import report_github_issue
|
||||
|
||||
announcements = "\n".join(self.coder.get_announcements())
|
||||
issue_text = announcements
|
||||
|
||||
if args.strip():
|
||||
title = args.strip()
|
||||
else:
|
||||
title = None
|
||||
|
||||
report_github_issue(issue_text, title=title, confirm=False)
|
||||
|
||||
|
||||
def expand_subdir(file_path):
|
||||
if file_path.is_file():
|
||||
@@ -1154,11 +1187,7 @@ def parse_quoted_filenames(args):
|
||||
|
||||
|
||||
def get_help_md():
|
||||
from aider.coders import Coder
|
||||
from aider.models import Model
|
||||
|
||||
coder = Coder(Model("gpt-3.5-turbo"), None)
|
||||
md = coder.commands.get_help_md()
|
||||
md = Commands(None, None).get_help_md()
|
||||
return md
|
||||
|
||||
|
||||
|
||||
116
aider/io.py
116
aider/io.py
@@ -5,7 +5,6 @@ from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
from prompt_toolkit import prompt
|
||||
from prompt_toolkit.completion import Completer, Completion, ThreadedCompleter
|
||||
from prompt_toolkit.enums import EditingMode
|
||||
from prompt_toolkit.history import FileHistory
|
||||
@@ -18,6 +17,8 @@ from pygments.token import Token
|
||||
from rich.console import Console
|
||||
from rich.style import Style as RichStyle
|
||||
from rich.text import Text
|
||||
from rich.markdown import Markdown
|
||||
from aider.mdstream import MarkdownStream
|
||||
|
||||
from .dump import dump # noqa: F401
|
||||
from .utils import is_image_file
|
||||
@@ -177,6 +178,8 @@ class InputOutput:
|
||||
tool_output_color=None,
|
||||
tool_error_color="red",
|
||||
tool_warning_color="#FFA500",
|
||||
assistant_output_color="blue",
|
||||
code_theme="default",
|
||||
encoding="utf-8",
|
||||
dry_run=False,
|
||||
llm_history_file=None,
|
||||
@@ -191,6 +194,8 @@ class InputOutput:
|
||||
self.tool_output_color = tool_output_color if pretty else None
|
||||
self.tool_error_color = tool_error_color if pretty else None
|
||||
self.tool_warning_color = tool_warning_color if pretty else None
|
||||
self.assistant_output_color = assistant_output_color
|
||||
self.code_theme = code_theme
|
||||
|
||||
self.input = input
|
||||
self.output = output
|
||||
@@ -211,14 +216,29 @@ class InputOutput:
|
||||
self.encoding = encoding
|
||||
self.dry_run = dry_run
|
||||
|
||||
if pretty:
|
||||
self.console = Console()
|
||||
else:
|
||||
self.console = Console(force_terminal=False, no_color=True)
|
||||
|
||||
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
self.append_chat_history(f"\n# aider chat started at {current_time}\n\n")
|
||||
|
||||
self.prompt_session = None
|
||||
if self.pretty:
|
||||
# Initialize PromptSession
|
||||
session_kwargs = {
|
||||
"input": self.input,
|
||||
"output": self.output,
|
||||
"lexer": PygmentsLexer(MarkdownLexer),
|
||||
"editing_mode": self.editingmode,
|
||||
}
|
||||
if self.input_history_file is not None:
|
||||
session_kwargs["history"] = FileHistory(self.input_history_file)
|
||||
try:
|
||||
self.prompt_session = PromptSession(**session_kwargs)
|
||||
self.console = Console() # pretty console
|
||||
except Exception as err:
|
||||
self.console = Console(force_terminal=False, no_color=True)
|
||||
self.tool_error(f"Can't initialize prompt toolkit: {err}") # non-pretty
|
||||
else:
|
||||
self.console = Console(force_terminal=False, no_color=True) # non-pretty
|
||||
|
||||
def read_image(self, filename):
|
||||
try:
|
||||
with open(str(filename), "rb") as image_file:
|
||||
@@ -317,35 +337,31 @@ class InputOutput:
|
||||
)
|
||||
)
|
||||
|
||||
kb = KeyBindings()
|
||||
|
||||
@kb.add("escape", "c-m", eager=True)
|
||||
def _(event):
|
||||
event.current_buffer.insert_text("\n")
|
||||
|
||||
while True:
|
||||
if multiline_input:
|
||||
show = ". "
|
||||
|
||||
session_kwargs = {
|
||||
"message": show,
|
||||
"completer": completer_instance,
|
||||
"reserve_space_for_menu": 4,
|
||||
"complete_style": CompleteStyle.MULTI_COLUMN,
|
||||
"input": self.input,
|
||||
"output": self.output,
|
||||
"lexer": PygmentsLexer(MarkdownLexer),
|
||||
}
|
||||
if style:
|
||||
session_kwargs["style"] = style
|
||||
|
||||
if self.input_history_file is not None:
|
||||
session_kwargs["history"] = FileHistory(self.input_history_file)
|
||||
|
||||
kb = KeyBindings()
|
||||
|
||||
@kb.add("escape", "c-m", eager=True)
|
||||
def _(event):
|
||||
event.current_buffer.insert_text("\n")
|
||||
|
||||
session = PromptSession(
|
||||
key_bindings=kb, editing_mode=self.editingmode, **session_kwargs
|
||||
)
|
||||
line = session.prompt()
|
||||
try:
|
||||
if self.prompt_session:
|
||||
line = self.prompt_session.prompt(
|
||||
show,
|
||||
completer=completer_instance,
|
||||
reserve_space_for_menu=4,
|
||||
complete_style=CompleteStyle.MULTI_COLUMN,
|
||||
style=style,
|
||||
key_bindings=kb,
|
||||
)
|
||||
else:
|
||||
line = input(show)
|
||||
except UnicodeEncodeError as err:
|
||||
self.tool_error(str(err))
|
||||
return ""
|
||||
|
||||
if line and line[0] == "{" and not multiline_input:
|
||||
multiline_input = True
|
||||
@@ -462,10 +478,14 @@ class InputOutput:
|
||||
self.user_input(f"{question}{res}", log_only=False)
|
||||
else:
|
||||
while True:
|
||||
res = prompt(
|
||||
question,
|
||||
style=Style.from_dict(style),
|
||||
)
|
||||
if self.prompt_session:
|
||||
res = self.prompt_session.prompt(
|
||||
question,
|
||||
style=Style.from_dict(style),
|
||||
)
|
||||
else:
|
||||
res = input(question)
|
||||
|
||||
if not res:
|
||||
res = "y" # Default to Yes if no input
|
||||
break
|
||||
@@ -515,7 +535,10 @@ class InputOutput:
|
||||
elif self.yes is False:
|
||||
res = "no"
|
||||
else:
|
||||
res = prompt(question + " ", default=default, style=style)
|
||||
if self.prompt_session:
|
||||
res = self.prompt_session.prompt(question + " ", default=default, style=style)
|
||||
else:
|
||||
res = input(question + " ")
|
||||
|
||||
hist = f"{question.strip()} {res.strip()}"
|
||||
self.append_chat_history(hist, linebreak=True, blockquote=True)
|
||||
@@ -563,6 +586,27 @@ class InputOutput:
|
||||
style = RichStyle(**style)
|
||||
self.console.print(*messages, style=style)
|
||||
|
||||
def assistant_output(self, message, stream=False):
|
||||
mdStream = None
|
||||
show_resp = message
|
||||
|
||||
if self.pretty:
|
||||
if stream:
|
||||
mdargs = dict(style=self.assistant_output_color, code_theme=self.code_theme)
|
||||
mdStream = MarkdownStream(mdargs=mdargs)
|
||||
else:
|
||||
show_resp = Markdown(
|
||||
message, style=self.assistant_output_color, code_theme=self.code_theme
|
||||
)
|
||||
else:
|
||||
show_resp = Text(message or "<no response>")
|
||||
|
||||
self.console.print(show_resp)
|
||||
return mdStream
|
||||
|
||||
def print(self, message=""):
|
||||
print(message)
|
||||
|
||||
def append_chat_history(self, text, linebreak=False, blockquote=False, strip=True):
|
||||
if blockquote:
|
||||
if strip:
|
||||
|
||||
@@ -35,7 +35,10 @@ class Linter:
|
||||
|
||||
def get_rel_fname(self, fname):
|
||||
if self.root:
|
||||
return os.path.relpath(fname, self.root)
|
||||
try:
|
||||
return os.path.relpath(fname, self.root)
|
||||
except ValueError:
|
||||
return fname
|
||||
else:
|
||||
return fname
|
||||
|
||||
@@ -43,14 +46,18 @@ class Linter:
|
||||
cmd += " " + rel_fname
|
||||
cmd = cmd.split()
|
||||
|
||||
process = subprocess.Popen(
|
||||
cmd,
|
||||
cwd=self.root,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
encoding=self.encoding,
|
||||
errors="replace",
|
||||
)
|
||||
try:
|
||||
process = subprocess.Popen(
|
||||
cmd,
|
||||
cwd=self.root,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
encoding=self.encoding,
|
||||
errors="replace",
|
||||
)
|
||||
except OSError as err:
|
||||
print(f"Unable to execute lint command: {err}")
|
||||
return
|
||||
stdout, _ = process.communicate()
|
||||
errors = stdout
|
||||
if process.returncode == 0:
|
||||
@@ -202,7 +209,12 @@ def basic_lint(fname, code):
|
||||
if lang == "typescript":
|
||||
return
|
||||
|
||||
parser = get_parser(lang)
|
||||
try:
|
||||
parser = get_parser(lang)
|
||||
except OSError as err:
|
||||
print(f"Unable to load parser: {err}")
|
||||
return
|
||||
|
||||
tree = parser.parse(bytes(code, "utf-8"))
|
||||
|
||||
errors = traverse_tree(tree.root_node)
|
||||
|
||||
126
aider/main.py
126
aider/main.py
@@ -1,8 +1,10 @@
|
||||
import configparser
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import threading
|
||||
import traceback
|
||||
from pathlib import Path
|
||||
|
||||
import git
|
||||
@@ -29,7 +31,7 @@ def get_git_root():
|
||||
try:
|
||||
repo = git.Repo(search_parent_directories=True)
|
||||
return repo.working_tree_dir
|
||||
except git.InvalidGitRepositoryError:
|
||||
except (git.InvalidGitRepositoryError, FileNotFoundError):
|
||||
return None
|
||||
|
||||
|
||||
@@ -89,7 +91,7 @@ def setup_git(git_root, io):
|
||||
pass
|
||||
try:
|
||||
user_email = config.get_value("user", "email", None)
|
||||
except configparser.NoSectionError:
|
||||
except (configparser.NoSectionError, configparser.NoOptionError):
|
||||
pass
|
||||
|
||||
if user_name and user_email:
|
||||
@@ -298,25 +300,33 @@ def sanity_check_repo(repo, io):
|
||||
if not repo:
|
||||
return True
|
||||
|
||||
if not repo.repo.working_tree_dir:
|
||||
io.tool_error("The git repo does not seem to have a working tree?")
|
||||
return False
|
||||
|
||||
try:
|
||||
repo.get_tracked_files()
|
||||
return True
|
||||
if not repo.git_repo_error:
|
||||
return True
|
||||
error_msg = str(repo.git_repo_error)
|
||||
except ANY_GIT_ERROR as exc:
|
||||
error_msg = str(exc)
|
||||
bad_ver = "version in (1, 2)" in error_msg
|
||||
except AssertionError as exc:
|
||||
error_msg = str(exc)
|
||||
bad_ver = True
|
||||
|
||||
if "version in (1, 2)" in error_msg:
|
||||
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.tool_output("https://github.com/paul-gauthier/aider/issues/211")
|
||||
return False
|
||||
|
||||
io.tool_error("Unable to read git repository, it may be corrupt?")
|
||||
io.tool_output(error_msg)
|
||||
if bad_ver:
|
||||
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.tool_output("https://github.com/paul-gauthier/aider/issues/211")
|
||||
return False
|
||||
|
||||
io.tool_error("Unable to read git repository, it may be corrupt?")
|
||||
io.tool_output(error_msg)
|
||||
return False
|
||||
|
||||
|
||||
def main(argv=None, input=None, output=None, force_git_root=None, return_coder=False):
|
||||
report_uncaught_exceptions()
|
||||
@@ -395,6 +405,8 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||
user_input_color=args.user_input_color,
|
||||
tool_output_color=args.tool_output_color,
|
||||
tool_error_color=args.tool_error_color,
|
||||
assistant_output_color=args.assistant_output_color,
|
||||
code_theme=args.code_theme,
|
||||
dry_run=args.dry_run,
|
||||
encoding=args.encoding,
|
||||
llm_history_file=args.llm_history_file,
|
||||
@@ -468,8 +480,8 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||
if args.check_update:
|
||||
check_version(io, verbose=args.verbose)
|
||||
|
||||
if args.models:
|
||||
models.print_matching_models(io, args.models)
|
||||
if args.list_models:
|
||||
models.print_matching_models(io, args.list_models)
|
||||
return 0
|
||||
|
||||
if args.git:
|
||||
@@ -485,6 +497,8 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||
cmd_line = scrub_sensitive_info(args, cmd_line)
|
||||
io.tool_output(cmd_line, log_only=True)
|
||||
|
||||
check_and_load_imports(io, verbose=args.verbose)
|
||||
|
||||
if args.anthropic_api_key:
|
||||
os.environ["ANTHROPIC_API_KEY"] = args.anthropic_api_key
|
||||
|
||||
@@ -511,8 +525,7 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||
|
||||
if args.verbose:
|
||||
io.tool_output("Model info:")
|
||||
for key, value in main_model.info.items():
|
||||
io.tool_output(f" {key}: {value}")
|
||||
io.tool_output(json.dumps(main_model.info, indent=4))
|
||||
|
||||
lint_cmds = parse_lint_cmds(args.lint_cmd, io)
|
||||
if lint_cmds is None:
|
||||
@@ -563,6 +576,13 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||
if args.cache_prompts and args.map_refresh == "auto":
|
||||
args.map_refresh = "files"
|
||||
|
||||
if not main_model.streaming:
|
||||
if args.stream:
|
||||
io.tool_warning(
|
||||
"Warning: Streaming is not supported by the selected model. Disabling streaming."
|
||||
)
|
||||
args.stream = False
|
||||
|
||||
try:
|
||||
coder = Coder.create(
|
||||
main_model=main_model,
|
||||
@@ -577,8 +597,6 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||
dry_run=args.dry_run,
|
||||
map_tokens=args.map_tokens,
|
||||
verbose=args.verbose,
|
||||
assistant_output_color=args.assistant_output_color,
|
||||
code_theme=args.code_theme,
|
||||
stream=args.stream,
|
||||
use_git=args.git,
|
||||
restore_chat_history=args.restore_chat_history,
|
||||
@@ -593,6 +611,7 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||
map_mul_no_files=args.map_multiplier_no_files,
|
||||
num_cache_warming_pings=args.cache_keepalive_pings,
|
||||
suggest_shell_commands=args.suggest_shell_commands,
|
||||
chat_language=args.chat_language,
|
||||
)
|
||||
except ValueError as err:
|
||||
io.tool_error(str(err))
|
||||
@@ -685,10 +704,6 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||
if args.exit:
|
||||
return
|
||||
|
||||
thread = threading.Thread(target=load_slow_imports)
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
|
||||
while True:
|
||||
try:
|
||||
coder.run()
|
||||
@@ -705,19 +720,72 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||
coder.show_announcements()
|
||||
|
||||
|
||||
def load_slow_imports():
|
||||
def check_and_load_imports(io, verbose=False):
|
||||
installs_file = Path.home() / ".aider" / "installs.json"
|
||||
key = (__version__, sys.executable)
|
||||
|
||||
if verbose:
|
||||
io.tool_output(
|
||||
f"Checking imports for version {__version__} and executable {sys.executable}"
|
||||
)
|
||||
io.tool_output(f"Installs file: {installs_file}")
|
||||
|
||||
try:
|
||||
if installs_file.exists():
|
||||
with open(installs_file, "r") as f:
|
||||
installs = json.load(f)
|
||||
if verbose:
|
||||
io.tool_output("Installs file exists and loaded")
|
||||
else:
|
||||
installs = {}
|
||||
if verbose:
|
||||
io.tool_output("Installs file does not exist, creating new dictionary")
|
||||
|
||||
if str(key) not in installs:
|
||||
if verbose:
|
||||
io.tool_output(
|
||||
"First run for this version and executable, loading imports synchronously"
|
||||
)
|
||||
try:
|
||||
load_slow_imports(swallow=False)
|
||||
except Exception as err:
|
||||
io.tool_error(str(err))
|
||||
io.tool_output("Error loading required imports. Did you install aider properly?")
|
||||
io.tool_output("https://aider.chat/docs/install/install.html")
|
||||
sys.exit(1)
|
||||
|
||||
installs[str(key)] = True
|
||||
installs_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
with open(installs_file, "w") as f:
|
||||
json.dump(installs, f, indent=4)
|
||||
if verbose:
|
||||
io.tool_output("Imports loaded and installs file updated")
|
||||
else:
|
||||
if verbose:
|
||||
io.tool_output("Not first run, loading imports in background thread")
|
||||
thread = threading.Thread(target=load_slow_imports)
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
except Exception as e:
|
||||
io.tool_warning(f"Error in checking imports: {e}")
|
||||
if verbose:
|
||||
io.tool_output(f"Full exception details: {traceback.format_exc()}")
|
||||
|
||||
|
||||
def load_slow_imports(swallow=True):
|
||||
# These imports are deferred in various ways to
|
||||
# improve startup time.
|
||||
# This func is called in a thread to load them in the background
|
||||
# while we wait for the user to type their first message.
|
||||
# This func is called either synchronously or in a thread
|
||||
# depending on whether it's been run before for this version and executable.
|
||||
|
||||
try:
|
||||
import httpx # noqa: F401
|
||||
import litellm # noqa: F401
|
||||
import networkx # noqa: F401
|
||||
import numpy # noqa: F401
|
||||
except Exception:
|
||||
pass
|
||||
except Exception as e:
|
||||
if not swallow:
|
||||
raise e
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
125
aider/models.py
125
aider/models.py
@@ -18,7 +18,7 @@ from aider.dump import dump # noqa: F401
|
||||
from aider.llm import litellm
|
||||
|
||||
DEFAULT_MODEL_NAME = "gpt-4o"
|
||||
ANTHROPIC_BETA_HEADER = "max-tokens-3-5-sonnet-2024-07-15,prompt-caching-2024-07-31"
|
||||
ANTHROPIC_BETA_HEADER = "prompt-caching-2024-07-31"
|
||||
|
||||
OPENAI_MODELS = """
|
||||
gpt-4
|
||||
@@ -77,6 +77,9 @@ class ModelSettings:
|
||||
max_tokens: Optional[int] = None
|
||||
cache_control: bool = False
|
||||
caches_by_default: bool = False
|
||||
use_system_prompt: bool = True
|
||||
use_temperature: bool = True
|
||||
streaming: bool = True
|
||||
|
||||
|
||||
# https://platform.openai.com/docs/models/gpt-4-and-gpt-4-turbo
|
||||
@@ -306,10 +309,8 @@ MODEL_SETTINGS = [
|
||||
examples_as_sys_msg=True,
|
||||
accepts_images=True,
|
||||
max_tokens=8192,
|
||||
extra_headers={
|
||||
"anthropic-beta": "max-tokens-3-5-sonnet-2024-07-15",
|
||||
},
|
||||
reminder="user",
|
||||
cache_control=True,
|
||||
),
|
||||
# Vertex AI Claude models
|
||||
# Does not yet support 8k token
|
||||
@@ -320,6 +321,7 @@ MODEL_SETTINGS = [
|
||||
use_repo_map=True,
|
||||
examples_as_sys_msg=True,
|
||||
accepts_images=True,
|
||||
max_tokens=8192,
|
||||
reminder="user",
|
||||
),
|
||||
ModelSettings(
|
||||
@@ -340,6 +342,19 @@ MODEL_SETTINGS = [
|
||||
weak_model_name="command-r-plus",
|
||||
use_repo_map=True,
|
||||
),
|
||||
# New Cohere models
|
||||
ModelSettings(
|
||||
"command-r-08-2024",
|
||||
"whole",
|
||||
weak_model_name="command-r-08-2024",
|
||||
use_repo_map=True,
|
||||
),
|
||||
ModelSettings(
|
||||
"command-r-plus-08-2024",
|
||||
"whole",
|
||||
weak_model_name="command-r-plus-08-2024",
|
||||
use_repo_map=True,
|
||||
),
|
||||
# Groq llama3
|
||||
ModelSettings(
|
||||
"groq/llama3-70b-8192",
|
||||
@@ -386,6 +401,7 @@ MODEL_SETTINGS = [
|
||||
use_repo_map=True,
|
||||
examples_as_sys_msg=True,
|
||||
reminder="sys",
|
||||
max_tokens=8192,
|
||||
),
|
||||
ModelSettings(
|
||||
"deepseek/deepseek-coder",
|
||||
@@ -394,6 +410,7 @@ MODEL_SETTINGS = [
|
||||
examples_as_sys_msg=True,
|
||||
reminder="sys",
|
||||
caches_by_default=True,
|
||||
max_tokens=8192,
|
||||
),
|
||||
ModelSettings(
|
||||
"openrouter/deepseek/deepseek-coder",
|
||||
@@ -411,6 +428,66 @@ MODEL_SETTINGS = [
|
||||
lazy=True,
|
||||
reminder="sys",
|
||||
),
|
||||
ModelSettings(
|
||||
"openai/o1-mini",
|
||||
"whole",
|
||||
weak_model_name="openai/gpt-4o-mini",
|
||||
use_repo_map=True,
|
||||
reminder="user",
|
||||
use_system_prompt=False,
|
||||
use_temperature=False,
|
||||
streaming=False,
|
||||
),
|
||||
ModelSettings(
|
||||
"o1-mini",
|
||||
"whole",
|
||||
weak_model_name="gpt-4o-mini",
|
||||
use_repo_map=True,
|
||||
reminder="user",
|
||||
use_system_prompt=False,
|
||||
use_temperature=False,
|
||||
streaming=False,
|
||||
),
|
||||
ModelSettings(
|
||||
"openai/o1-preview",
|
||||
"diff",
|
||||
weak_model_name="openai/gpt-4o-mini",
|
||||
use_repo_map=True,
|
||||
reminder="user",
|
||||
use_system_prompt=False,
|
||||
use_temperature=False,
|
||||
streaming=False,
|
||||
),
|
||||
ModelSettings(
|
||||
"o1-preview",
|
||||
"diff",
|
||||
weak_model_name="gpt-4o-mini",
|
||||
use_repo_map=True,
|
||||
reminder="user",
|
||||
use_system_prompt=False,
|
||||
use_temperature=False,
|
||||
streaming=False,
|
||||
),
|
||||
ModelSettings(
|
||||
"openrouter/openai/o1-mini",
|
||||
"whole",
|
||||
weak_model_name="openrouter/openai/gpt-4o-mini",
|
||||
use_repo_map=True,
|
||||
reminder="user",
|
||||
use_system_prompt=False,
|
||||
use_temperature=False,
|
||||
streaming=False,
|
||||
),
|
||||
ModelSettings(
|
||||
"openrouter/openai/o1-preview",
|
||||
"diff",
|
||||
weak_model_name="openrouter/openai/gpt-4o-mini",
|
||||
use_repo_map=True,
|
||||
reminder="user",
|
||||
use_system_prompt=False,
|
||||
use_temperature=False,
|
||||
streaming=False,
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -437,21 +514,28 @@ def get_model_info(model):
|
||||
if not litellm._lazy_module:
|
||||
cache_dir = Path.home() / ".aider" / "caches"
|
||||
cache_file = cache_dir / "model_prices_and_context_window.json"
|
||||
cache_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
current_time = time.time()
|
||||
cache_age = (
|
||||
current_time - cache_file.stat().st_mtime if cache_file.exists() else float("inf")
|
||||
)
|
||||
try:
|
||||
cache_dir.mkdir(parents=True, exist_ok=True)
|
||||
use_cache = True
|
||||
except OSError:
|
||||
# If we can't create the cache directory, we'll skip using the cache
|
||||
use_cache = False
|
||||
|
||||
if cache_age < 60 * 60 * 24:
|
||||
try:
|
||||
content = json.loads(cache_file.read_text())
|
||||
res = get_model_flexible(model, content)
|
||||
if res:
|
||||
return res
|
||||
except Exception as ex:
|
||||
print(str(ex))
|
||||
if use_cache:
|
||||
current_time = time.time()
|
||||
cache_age = (
|
||||
current_time - cache_file.stat().st_mtime if cache_file.exists() else float("inf")
|
||||
)
|
||||
|
||||
if cache_age < 60 * 60 * 24:
|
||||
try:
|
||||
content = json.loads(cache_file.read_text())
|
||||
res = get_model_flexible(model, content)
|
||||
if res:
|
||||
return res
|
||||
except Exception as ex:
|
||||
print(str(ex))
|
||||
|
||||
import requests
|
||||
|
||||
@@ -459,7 +543,12 @@ def get_model_info(model):
|
||||
response = requests.get(model_info_url, timeout=5)
|
||||
if response.status_code == 200:
|
||||
content = response.json()
|
||||
cache_file.write_text(json.dumps(content, indent=4))
|
||||
if use_cache:
|
||||
try:
|
||||
cache_file.write_text(json.dumps(content, indent=4))
|
||||
except OSError:
|
||||
# If we can't write to the cache file, we'll just skip caching
|
||||
pass
|
||||
res = get_model_flexible(model, content)
|
||||
if res:
|
||||
return res
|
||||
|
||||
@@ -10,7 +10,7 @@ from aider.sendchat import simple_send_with_retries
|
||||
|
||||
from .dump import dump # noqa: F401
|
||||
|
||||
ANY_GIT_ERROR = (git.exc.ODBError, git.exc.GitError)
|
||||
ANY_GIT_ERROR = (git.exc.ODBError, git.exc.GitError, OSError, IndexError, BufferError)
|
||||
|
||||
|
||||
class GitRepo:
|
||||
@@ -21,6 +21,7 @@ class GitRepo:
|
||||
aider_ignore_last_check = 0
|
||||
subtree_only = False
|
||||
ignore_file_cache = {}
|
||||
git_repo_error = None
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -257,15 +258,26 @@ class GitRepo:
|
||||
commit = self.repo.head.commit
|
||||
except ValueError:
|
||||
commit = None
|
||||
except ANY_GIT_ERROR as err:
|
||||
self.git_repo_error = err
|
||||
self.io.tool_error(f"Unable to list files in git repo: {err}")
|
||||
self.io.tool_output("Is your git repo corrupted?")
|
||||
return []
|
||||
|
||||
files = set()
|
||||
if commit:
|
||||
if commit in self.tree_files:
|
||||
files = self.tree_files[commit]
|
||||
else:
|
||||
for blob in commit.tree.traverse():
|
||||
if blob.type == "blob": # blob is a file
|
||||
files.add(blob.path)
|
||||
try:
|
||||
for blob in commit.tree.traverse():
|
||||
if blob.type == "blob": # blob is a file
|
||||
files.add(blob.path)
|
||||
except ANY_GIT_ERROR as err:
|
||||
self.git_repo_error = err
|
||||
self.io.tool_error(f"Unable to list files in git repo: {err}")
|
||||
self.io.tool_output("Is your git repo corrupted?")
|
||||
return []
|
||||
files = set(self.normalize_path(path) for path in files)
|
||||
self.tree_files[commit] = set(files)
|
||||
|
||||
@@ -342,6 +354,8 @@ class GitRepo:
|
||||
def path_in_repo(self, path):
|
||||
if not self.repo:
|
||||
return
|
||||
if not path:
|
||||
return
|
||||
|
||||
tracked_files = set(self.get_tracked_files())
|
||||
return self.normalize_path(path) in tracked_files
|
||||
|
||||
@@ -27,6 +27,9 @@ from tree_sitter_languages import get_language, get_parser # noqa: E402
|
||||
Tag = namedtuple("Tag", "rel_fname fname line name kind".split())
|
||||
|
||||
|
||||
SQLITE_ERRORS = (sqlite3.OperationalError, sqlite3.DatabaseError)
|
||||
|
||||
|
||||
class RepoMap:
|
||||
CACHE_VERSION = 3
|
||||
TAGS_CACHE_DIR = f".aider.tags.cache.v{CACHE_VERSION}"
|
||||
@@ -167,7 +170,7 @@ class RepoMap:
|
||||
path = Path(self.root) / self.TAGS_CACHE_DIR
|
||||
try:
|
||||
self.TAGS_CACHE = Cache(path)
|
||||
except sqlite3.OperationalError:
|
||||
except SQLITE_ERRORS:
|
||||
self.io.tool_warning(f"Unable to use tags cache, delete {path} to resolve.")
|
||||
self.TAGS_CACHE = dict()
|
||||
|
||||
@@ -195,8 +198,12 @@ class RepoMap:
|
||||
data = list(self.get_tags_raw(fname, rel_fname))
|
||||
|
||||
# Update the cache
|
||||
self.TAGS_CACHE[cache_key] = {"mtime": file_mtime, "data": data}
|
||||
self.save_tags_cache()
|
||||
try:
|
||||
self.TAGS_CACHE[cache_key] = {"mtime": file_mtime, "data": data}
|
||||
self.save_tags_cache()
|
||||
except SQLITE_ERRORS:
|
||||
pass
|
||||
|
||||
return data
|
||||
|
||||
def get_tags_raw(self, fname, rel_fname):
|
||||
@@ -316,6 +323,9 @@ class RepoMap:
|
||||
if not file_ok:
|
||||
if fname not in self.warned_files:
|
||||
self.io.tool_warning(f"Repo-map can't include {fname}")
|
||||
self.io.tool_output(
|
||||
"Has it been deleted from the file system but not from git?"
|
||||
)
|
||||
self.warned_files.add(fname)
|
||||
continue
|
||||
|
||||
|
||||
@@ -34,13 +34,14 @@ def get_git_info():
|
||||
return "Git information unavailable"
|
||||
|
||||
|
||||
def report_github_issue(issue_text, title=None):
|
||||
def report_github_issue(issue_text, title=None, confirm=True):
|
||||
"""
|
||||
Compose a URL to open a new GitHub issue with the given text prefilled,
|
||||
and attempt to launch it in the default web browser.
|
||||
|
||||
:param issue_text: The text of the issue to file
|
||||
:param title: The title of the issue (optional)
|
||||
:param confirm: Whether to ask for confirmation before opening the browser (default: True)
|
||||
:return: None
|
||||
"""
|
||||
version_info = f"Aider version: {__version__}\n"
|
||||
@@ -61,16 +62,17 @@ def report_github_issue(issue_text, title=None):
|
||||
params["title"] = title
|
||||
issue_url = f"{github_issues}?{urllib.parse.urlencode(params)}"
|
||||
|
||||
print(f"\n# {title}\n")
|
||||
print(issue_text.strip())
|
||||
print()
|
||||
print("Please consider reporting this bug to help improve aider!")
|
||||
prompt = "Open a GitHub Issue pre-filled with the above error in your browser? (Y/n) "
|
||||
confirmation = input(prompt).strip().lower()
|
||||
if confirm:
|
||||
print(f"\n# {title}\n")
|
||||
print(issue_text.strip())
|
||||
print()
|
||||
print("Please consider reporting this bug to help improve aider!")
|
||||
prompt = "Open a GitHub Issue pre-filled with the above error in your browser? (Y/n) "
|
||||
confirmation = input(prompt).strip().lower()
|
||||
|
||||
yes = not confirmation or confirmation.startswith("y")
|
||||
if not yes:
|
||||
return
|
||||
yes = not confirmation or confirmation.startswith("y")
|
||||
if not yes:
|
||||
return
|
||||
|
||||
print("Attempting to open the issue URL in your default web browser...")
|
||||
try:
|
||||
@@ -79,13 +81,14 @@ def report_github_issue(issue_text, title=None):
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
print()
|
||||
print()
|
||||
print("You can also use this URL to file the GitHub Issue:")
|
||||
print()
|
||||
print(issue_url)
|
||||
print()
|
||||
print()
|
||||
if confirm:
|
||||
print()
|
||||
print()
|
||||
print("You can also use this URL to file the GitHub Issue:")
|
||||
print()
|
||||
print(issue_url)
|
||||
print()
|
||||
print()
|
||||
|
||||
|
||||
def exception_handler(exc_type, exc_value, exc_traceback):
|
||||
|
||||
@@ -5,6 +5,7 @@ import sys
|
||||
from io import BytesIO
|
||||
|
||||
import pexpect
|
||||
import psutil
|
||||
|
||||
|
||||
def run_cmd(command, verbose=False, error_print=None):
|
||||
@@ -22,10 +23,42 @@ def run_cmd(command, verbose=False, error_print=None):
|
||||
return 1, error_message
|
||||
|
||||
|
||||
def get_windows_parent_process_name():
|
||||
try:
|
||||
current_process = psutil.Process()
|
||||
while True:
|
||||
parent = current_process.parent()
|
||||
if parent is None:
|
||||
break
|
||||
parent_name = parent.name().lower()
|
||||
if parent_name in ["powershell.exe", "cmd.exe"]:
|
||||
return parent_name
|
||||
current_process = parent
|
||||
return None
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def run_cmd_subprocess(command, verbose=False):
|
||||
if verbose:
|
||||
print("Using run_cmd_subprocess:", command)
|
||||
|
||||
try:
|
||||
shell = os.environ.get("SHELL", "/bin/sh")
|
||||
parent_process = None
|
||||
|
||||
# Determine the appropriate shell
|
||||
if platform.system() == "Windows":
|
||||
parent_process = get_windows_parent_process_name()
|
||||
if parent_process == "powershell.exe":
|
||||
command = f"powershell -Command {command}"
|
||||
|
||||
if verbose:
|
||||
print("Running command:", command)
|
||||
print("SHELL:", shell)
|
||||
if platform.system() == "Windows":
|
||||
print("Parent process:", parent_process)
|
||||
|
||||
process = subprocess.Popen(
|
||||
command,
|
||||
stdout=subprocess.PIPE,
|
||||
@@ -34,14 +67,17 @@ def run_cmd_subprocess(command, verbose=False):
|
||||
shell=True,
|
||||
encoding=sys.stdout.encoding,
|
||||
errors="replace",
|
||||
bufsize=1,
|
||||
bufsize=0, # Set bufsize to 0 for unbuffered output
|
||||
universal_newlines=True,
|
||||
)
|
||||
|
||||
output = []
|
||||
for line in process.stdout:
|
||||
print(line, end="") # Print the line in real-time
|
||||
output.append(line) # Store the line for later use
|
||||
while True:
|
||||
chunk = process.stdout.read(1)
|
||||
if not chunk:
|
||||
break
|
||||
print(chunk, end="", flush=True) # Print the chunk in real-time
|
||||
output.append(chunk) # Store the chunk for later use
|
||||
|
||||
process.wait()
|
||||
return process.returncode, "".join(output)
|
||||
@@ -90,6 +126,6 @@ def run_cmd_pexpect(command, verbose=False):
|
||||
child.close()
|
||||
return child.exitstatus, output.getvalue().decode("utf-8", errors="replace")
|
||||
|
||||
except (pexpect.ExceptionPexpect, TypeError) as e:
|
||||
except (pexpect.ExceptionPexpect, TypeError, ValueError) as e:
|
||||
error_msg = f"Error running command {command}: {e}"
|
||||
return 1, error_msg
|
||||
|
||||
@@ -27,7 +27,7 @@ def retry_exceptions():
|
||||
litellm.exceptions.ServiceUnavailableError,
|
||||
litellm.exceptions.Timeout,
|
||||
litellm.exceptions.InternalServerError,
|
||||
litellm.llms.anthropic.AnthropicError,
|
||||
litellm.llms.anthropic.chat.AnthropicError,
|
||||
)
|
||||
|
||||
|
||||
@@ -60,9 +60,10 @@ def send_completion(
|
||||
kwargs = dict(
|
||||
model=model_name,
|
||||
messages=messages,
|
||||
temperature=temperature,
|
||||
stream=stream,
|
||||
)
|
||||
if temperature is not None:
|
||||
kwargs["temperature"] = temperature
|
||||
|
||||
if functions is not None:
|
||||
function = functions[0]
|
||||
|
||||
@@ -234,6 +234,8 @@ def run_install(cmd):
|
||||
text=True,
|
||||
bufsize=1,
|
||||
universal_newlines=True,
|
||||
encoding=sys.stdout.encoding,
|
||||
errors="replace",
|
||||
)
|
||||
spinner = Spinner("Installing...")
|
||||
|
||||
|
||||
@@ -16,6 +16,36 @@ cog.out(text)
|
||||
|
||||
# Release history
|
||||
|
||||
### Aider v0.57.0
|
||||
|
||||
- Support for OpenAI o1 models:
|
||||
- o1-preview now works well with diff edit format.
|
||||
- o1-preview with diff now matches SOTA leaderboard result with whole edit format.
|
||||
- `aider --model o1-mini`
|
||||
- `aider --model o1-preview`
|
||||
- On Windows, `/run` correctly uses PowerShell or cmd.exe.
|
||||
- Support for new 08-2024 Cohere models, by @jalammar.
|
||||
- Can now recursively add directories with `/read-only`.
|
||||
- User input prompts now fall back to simple `input()` if `--no-pretty` or a Windows console is not available.
|
||||
- Improved sanity check of git repo on startup.
|
||||
- Improvements to prompt cache chunking strategy.
|
||||
- Removed "No changes made to git tracked files".
|
||||
- Numerous bug fixes for corner case crashes.
|
||||
- Updated all dependency versions.
|
||||
- Aider wrote 70% of the code in this release.
|
||||
|
||||
### Aider v0.56.0
|
||||
|
||||
- Enables prompt caching for Sonnet via OpenRouter by @fry69
|
||||
- Enables 8k output tokens for Sonnet via VertexAI and DeepSeek V2.5.
|
||||
- New `/report` command to open your browser with a pre-populated GitHub Issue.
|
||||
- New `--chat-language` switch to set the spoken language.
|
||||
- Now `--[no-]suggest-shell-commands` controls both prompting for and offering to execute shell commands.
|
||||
- Check key imports on launch, provide helpful error message if dependencies aren't available.
|
||||
- Renamed `--models` to `--list-models` by @fry69.
|
||||
- Numerous bug fixes for corner case crashes.
|
||||
- Aider wrote 56% of the code in this release.
|
||||
|
||||
### Aider v0.55.0
|
||||
|
||||
- Only print the pip command when self updating on Windows, without running it.
|
||||
@@ -691,7 +721,7 @@ cog.out(text)
|
||||
|
||||
- Added `/git` command to run git from inside aider chats.
|
||||
- Use Meta-ENTER (Esc+ENTER in some environments) to enter multiline chat messages.
|
||||
- Create a `.gitignore` with `.aider*` to prevent users from accidentaly adding aider files to git.
|
||||
- Create a `.gitignore` with `.aider*` to prevent users from accidentally adding aider files to git.
|
||||
- Check pypi for newer versions and notify user.
|
||||
- Updated keyboard interrupt logic so that 2 ^C in 2 seconds always forces aider to exit.
|
||||
- Provide GPT with detailed error if it makes a bad edit block, ask for a retry.
|
||||
|
||||
@@ -41,4 +41,8 @@ repository: paul-gauthier/aider
|
||||
callouts:
|
||||
tip:
|
||||
title: Tip
|
||||
color: green
|
||||
color: green
|
||||
note:
|
||||
title: Note
|
||||
color: yellow
|
||||
|
||||
@@ -2380,3 +2380,154 @@
|
||||
Paul Gauthier (aider): 204
|
||||
start_tag: v0.53.0
|
||||
total_lines: 319
|
||||
- aider_percentage: 52.9
|
||||
aider_total: 811
|
||||
end_date: '2024-09-04'
|
||||
end_tag: v0.55.0
|
||||
file_counts:
|
||||
aider/__init__.py:
|
||||
Paul Gauthier: 4
|
||||
Paul Gauthier (aider): 2
|
||||
aider/args.py:
|
||||
Paul Gauthier (aider): 7
|
||||
aider/coders/base_coder.py:
|
||||
Paul Gauthier: 63
|
||||
Paul Gauthier (aider): 42
|
||||
aider/coders/editblock_coder.py:
|
||||
Nikolay Sedelnikov: 8
|
||||
aider/coders/editblock_func_coder.py:
|
||||
Antti Kaihola: 2
|
||||
aider/coders/search_replace.py:
|
||||
Paul Gauthier: 2
|
||||
aider/coders/wholefile_coder.py:
|
||||
Paul Gauthier: 16
|
||||
aider/commands.py:
|
||||
Antti Kaihola: 7
|
||||
Paul Gauthier: 85
|
||||
Paul Gauthier (aider): 27
|
||||
aider/format_settings.py:
|
||||
Paul Gauthier (aider): 26
|
||||
aider/gui.py:
|
||||
Paul Gauthier: 4
|
||||
aider/io.py:
|
||||
Paul Gauthier: 63
|
||||
Paul Gauthier (aider): 13
|
||||
aider/linter.py:
|
||||
Paul Gauthier: 5
|
||||
aider/llm.py:
|
||||
Paul Gauthier: 2
|
||||
aider/main.py:
|
||||
Paul Gauthier: 86
|
||||
Paul Gauthier (aider): 22
|
||||
aider/models.py:
|
||||
Paul Gauthier: 24
|
||||
Paul Gauthier (aider): 2
|
||||
aider/repo.py:
|
||||
Paul Gauthier: 85
|
||||
aider/repomap.py:
|
||||
Paul Gauthier: 32
|
||||
Paul Gauthier (aider): 4
|
||||
aider/report.py:
|
||||
Paul Gauthier: 77
|
||||
Paul Gauthier (aider): 120
|
||||
aider/run_cmd.py:
|
||||
Paul Gauthier: 17
|
||||
Paul Gauthier (aider): 24
|
||||
aider/scrape.py:
|
||||
Paul Gauthier: 7
|
||||
Paul Gauthier (aider): 8
|
||||
aider/special.py:
|
||||
Paul Gauthier: 5
|
||||
Paul Gauthier (aider): 197
|
||||
aider/urls.py:
|
||||
Paul Gauthier (aider): 1
|
||||
aider/utils.py:
|
||||
Paul Gauthier: 31
|
||||
Paul Gauthier (aider): 29
|
||||
aider/versioncheck.py:
|
||||
Paul Gauthier: 32
|
||||
Paul Gauthier (aider): 6
|
||||
aider/voice.py:
|
||||
Paul Gauthier: 7
|
||||
Paul Gauthier (aider): 9
|
||||
scripts/versionbump.py:
|
||||
Paul Gauthier: 9
|
||||
tests/basic/test_coder.py:
|
||||
Paul Gauthier: 3
|
||||
Paul Gauthier (aider): 105
|
||||
tests/basic/test_editblock.py:
|
||||
Antti Kaihola: 3
|
||||
Nikolay Sedelnikov: 37
|
||||
tests/basic/test_io.py:
|
||||
Paul Gauthier: 2
|
||||
Paul Gauthier (aider): 15
|
||||
tests/basic/test_main.py:
|
||||
Paul Gauthier: 2
|
||||
Paul Gauthier (aider): 10
|
||||
tests/basic/test_models.py:
|
||||
Paul Gauthier (aider): 4
|
||||
tests/basic/test_repomap.py:
|
||||
Paul Gauthier (aider): 42
|
||||
tests/basic/test_run_cmd.py:
|
||||
Paul Gauthier (aider): 11
|
||||
tests/basic/test_special.py:
|
||||
Paul Gauthier: 2
|
||||
Paul Gauthier (aider): 74
|
||||
tests/scrape/test_scrape.py:
|
||||
Paul Gauthier (aider): 11
|
||||
grand_total:
|
||||
Antti Kaihola: 12
|
||||
Nikolay Sedelnikov: 45
|
||||
Paul Gauthier: 665
|
||||
Paul Gauthier (aider): 811
|
||||
start_tag: v0.54.0
|
||||
total_lines: 1533
|
||||
- aider_percentage: 55.6
|
||||
aider_total: 154
|
||||
end_date: '2024-09-09'
|
||||
end_tag: v0.56.0
|
||||
file_counts:
|
||||
aider/__init__.py:
|
||||
Paul Gauthier: 1
|
||||
aider/args.py:
|
||||
Paul Gauthier: 2
|
||||
Paul Gauthier (aider): 6
|
||||
aider/coders/base_coder.py:
|
||||
Paul Gauthier: 14
|
||||
Paul Gauthier (aider): 10
|
||||
aider/commands.py:
|
||||
Paul Gauthier: 8
|
||||
Paul Gauthier (aider): 6
|
||||
aider/io.py:
|
||||
Paul Gauthier: 5
|
||||
aider/linter.py:
|
||||
Paul Gauthier: 6
|
||||
Paul Gauthier (aider): 4
|
||||
fry69: 12
|
||||
aider/main.py:
|
||||
Paul Gauthier: 35
|
||||
Paul Gauthier (aider): 48
|
||||
aider/models.py:
|
||||
Paul Gauthier: 2
|
||||
fry69: 3
|
||||
aider/repo.py:
|
||||
Paul Gauthier: 16
|
||||
aider/repomap.py:
|
||||
Paul Gauthier: 13
|
||||
aider/report.py:
|
||||
Paul Gauthier: 2
|
||||
Paul Gauthier (aider): 20
|
||||
benchmark/benchmark.py:
|
||||
Paul Gauthier: 1
|
||||
tests/basic/test_linter.py:
|
||||
Paul Gauthier: 1
|
||||
Paul Gauthier (aider): 51
|
||||
tests/basic/test_main.py:
|
||||
Paul Gauthier: 2
|
||||
Paul Gauthier (aider): 9
|
||||
grand_total:
|
||||
Paul Gauthier: 108
|
||||
Paul Gauthier (aider): 154
|
||||
fry69: 15
|
||||
start_tag: v0.55.0
|
||||
total_lines: 277
|
||||
|
||||
@@ -317,29 +317,6 @@
|
||||
seconds_per_case: 22.9
|
||||
total_cost: 2.7494
|
||||
|
||||
- dirname: 2024-05-09-18-57-52--deepseek-chat-v2-diff-reverted-and-helpful-assistant2
|
||||
test_cases: 133
|
||||
model: DeepSeek Chat V2 (original)
|
||||
released: 2024-05-06
|
||||
edit_format: diff
|
||||
commit_hash: 80a3f6d
|
||||
pass_rate_1: 44.4
|
||||
pass_rate_2: 60.9
|
||||
percent_cases_well_formed: 97.0
|
||||
error_outputs: 14
|
||||
num_malformed_responses: 4
|
||||
user_asks: 2
|
||||
lazy_comments: 0
|
||||
syntax_errors: 13
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 3
|
||||
command: aider --model deepseek/deepseek-chat
|
||||
date: 2024-05-09
|
||||
versions: 0.33.1-dev
|
||||
seconds_per_case: 86.8
|
||||
total_cost: 0.0941
|
||||
|
||||
- dirname: 2024-05-07-20-32-37--qwen1.5-110b-chat-whole
|
||||
test_cases: 133
|
||||
model: qwen1.5-110b-chat
|
||||
@@ -665,7 +642,7 @@
|
||||
|
||||
- dirname: 2024-07-19-08-57-13--openrouter-deepseek-chat-v2-0628
|
||||
test_cases: 133
|
||||
model: DeepSeek Chat V2 0628
|
||||
model: DeepSeek Chat V2 0628 (deprecated)
|
||||
edit_format: diff
|
||||
commit_hash: 96ff06e-dirty
|
||||
pass_rate_1: 60.9
|
||||
@@ -737,7 +714,7 @@
|
||||
|
||||
- dirname: 2024-07-24-07-10-58--deepseek-coder2-0724-diff-direct
|
||||
test_cases: 133
|
||||
model: DeepSeek Coder V2 0724
|
||||
model: DeepSeek Coder V2 0724 (deprecated)
|
||||
edit_format: diff
|
||||
commit_hash: 89965bf
|
||||
pass_rate_1: 57.9
|
||||
@@ -969,4 +946,258 @@
|
||||
date: 2024-08-30
|
||||
versions: 0.54.8-dev
|
||||
seconds_per_case: 38.3
|
||||
total_cost: 0.0000
|
||||
|
||||
- dirname: 2024-09-04-16-08-09--yi-coder-9b-whole
|
||||
test_cases: 133
|
||||
model: Yi Coder 9B Chat
|
||||
edit_format: whole
|
||||
commit_hash: c4e4967
|
||||
pass_rate_1: 46.6
|
||||
pass_rate_2: 54.1
|
||||
percent_cases_well_formed: 100.0
|
||||
error_outputs: 0
|
||||
num_malformed_responses: 0
|
||||
num_with_malformed_responses: 0
|
||||
user_asks: 9
|
||||
lazy_comments: 0
|
||||
syntax_errors: 14
|
||||
indentation_errors: 2
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 4
|
||||
command: aider --model openai/hf:01-ai/Yi-Coder-9B-Chat --openai-api-base https://glhf.chat/api/openai/v1
|
||||
date: 2024-09-04
|
||||
versions: 0.54.13.dev
|
||||
seconds_per_case: 8.3
|
||||
total_cost: 0.0000
|
||||
released: 2024-09-04
|
||||
|
||||
- dirname: 2024-09-04-16-17-33--yi-coder-9b-chat-q4_0-whole
|
||||
test_cases: 133
|
||||
model: yi-coder:9b-chat-q4_0
|
||||
edit_format: whole
|
||||
commit_hash: c4e4967
|
||||
pass_rate_1: 41.4
|
||||
pass_rate_2: 45.1
|
||||
percent_cases_well_formed: 100.0
|
||||
error_outputs: 0
|
||||
num_malformed_responses: 0
|
||||
num_with_malformed_responses: 0
|
||||
user_asks: 48
|
||||
lazy_comments: 1
|
||||
syntax_errors: 1
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 0
|
||||
command: aider --model ollama/yi-coder:9b-chat-q4_0
|
||||
date: 2024-09-04
|
||||
versions: 0.54.13.dev
|
||||
seconds_per_case: 125.3
|
||||
total_cost: 0.0000
|
||||
|
||||
- dirname: 2024-09-05-14-50-11--deepseek-sep5-no-shell
|
||||
test_cases: 133
|
||||
model: DeepSeek V2.5
|
||||
edit_format: diff
|
||||
commit_hash: 1279c86
|
||||
pass_rate_1: 54.9
|
||||
pass_rate_2: 72.2
|
||||
percent_cases_well_formed: 96.2
|
||||
error_outputs: 5
|
||||
num_malformed_responses: 5
|
||||
num_with_malformed_responses: 5
|
||||
user_asks: 4
|
||||
lazy_comments: 0
|
||||
syntax_errors: 1
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 2
|
||||
command: aider --deepseek
|
||||
date: 2024-09-05
|
||||
versions: 0.55.1.dev
|
||||
seconds_per_case: 49.6
|
||||
total_cost: 0.0998
|
||||
|
||||
- dirname: 2024-09-06-19-55-17--reflection-hyperbolic-whole-output2
|
||||
test_cases: 133
|
||||
model: Reflection-70B
|
||||
edit_format: whole
|
||||
commit_hash: 74631ee-dirty, 2aef59e-dirty
|
||||
pass_rate_1: 33.1
|
||||
pass_rate_2: 42.1
|
||||
percent_cases_well_formed: 100.0
|
||||
error_outputs: 2
|
||||
num_malformed_responses: 0
|
||||
num_with_malformed_responses: 0
|
||||
user_asks: 10
|
||||
lazy_comments: 26
|
||||
syntax_errors: 1
|
||||
indentation_errors: 3
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 3
|
||||
command: (not currently supported)
|
||||
date: 2024-09-06
|
||||
versions: 0.55.1.dev
|
||||
seconds_per_case: 61.6
|
||||
total_cost: 0.0000
|
||||
|
||||
- dirname: 2024-09-11-15-42-17--command-r-plus-08-2024-whole
|
||||
test_cases: 133
|
||||
model: Command R+ (08-24)
|
||||
edit_format: whole
|
||||
commit_hash: b43ed20
|
||||
pass_rate_1: 27.1
|
||||
pass_rate_2: 38.3
|
||||
percent_cases_well_formed: 100.0
|
||||
error_outputs: 0
|
||||
num_malformed_responses: 0
|
||||
num_with_malformed_responses: 0
|
||||
user_asks: 7
|
||||
lazy_comments: 10
|
||||
syntax_errors: 0
|
||||
indentation_errors: 3
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 4
|
||||
command: aider --model command-r-plus-08-2024
|
||||
date: 2024-09-11
|
||||
versions: 0.56.1.dev
|
||||
seconds_per_case: 20.3
|
||||
total_cost: 0.0000
|
||||
|
||||
- dirname: 2024-09-11-15-47-02--command-r-08-2024-whole
|
||||
test_cases: 133
|
||||
model: Command R (08-24)
|
||||
edit_format: whole
|
||||
commit_hash: b43ed20-dirty
|
||||
pass_rate_1: 30.1
|
||||
pass_rate_2: 38.3
|
||||
percent_cases_well_formed: 100.0
|
||||
error_outputs: 0
|
||||
num_malformed_responses: 0
|
||||
num_with_malformed_responses: 0
|
||||
user_asks: 4
|
||||
lazy_comments: 0
|
||||
syntax_errors: 1
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 2
|
||||
command: aider --model command-r-08-2024
|
||||
date: 2024-09-11
|
||||
versions: 0.56.1.dev
|
||||
seconds_per_case: 7.6
|
||||
total_cost: 0.0000
|
||||
|
||||
- dirname: 2024-09-12-19-57-35--o1-mini-whole
|
||||
test_cases: 133
|
||||
model: o1-mini (whole)
|
||||
edit_format: whole
|
||||
commit_hash: 36fa773-dirty, 291b456
|
||||
pass_rate_1: 49.6
|
||||
pass_rate_2: 70.7
|
||||
percent_cases_well_formed: 90.0
|
||||
error_outputs: 0
|
||||
num_malformed_responses: 0
|
||||
num_with_malformed_responses: 0
|
||||
user_asks: 17
|
||||
lazy_comments: 0
|
||||
syntax_errors: 0
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 1
|
||||
command: aider --model o1-mini
|
||||
date: 2024-09-12
|
||||
versions: 0.56.1.dev
|
||||
seconds_per_case: 103.0
|
||||
total_cost: 5.3725
|
||||
|
||||
- dirname: 2024-09-12-20-56-22--o1-mini-diff
|
||||
test_cases: 133
|
||||
model: o1-mini (diff)
|
||||
edit_format: diff
|
||||
commit_hash: 4598a37-dirty, 291b456, 752e823-dirty
|
||||
pass_rate_1: 45.1
|
||||
pass_rate_2: 62.4
|
||||
percent_cases_well_formed: 85.7
|
||||
error_outputs: 26
|
||||
num_malformed_responses: 26
|
||||
num_with_malformed_responses: 19
|
||||
user_asks: 2
|
||||
lazy_comments: 0
|
||||
syntax_errors: 0
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 1
|
||||
command: aider --model o1-mini --edit-format diff
|
||||
date: 2024-09-12
|
||||
versions: 0.56.1.dev
|
||||
seconds_per_case: 177.7
|
||||
total_cost: 11.1071
|
||||
|
||||
- dirname: 2024-09-21-16-45-11--o1-preview-flex-sr-markers
|
||||
test_cases: 133
|
||||
model: o1-preview
|
||||
edit_format: diff
|
||||
commit_hash: 5493654-dirty
|
||||
pass_rate_1: 57.9
|
||||
pass_rate_2: 79.7
|
||||
percent_cases_well_formed: 93.2
|
||||
error_outputs: 11
|
||||
num_malformed_responses: 11
|
||||
num_with_malformed_responses: 9
|
||||
user_asks: 3
|
||||
lazy_comments: 0
|
||||
syntax_errors: 10
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 1
|
||||
command: aider --model o1-preview
|
||||
date: 2024-09-21
|
||||
versions: 0.56.1.dev
|
||||
seconds_per_case: 80.9
|
||||
total_cost: 63.9190
|
||||
|
||||
- dirname: 2024-09-19-16-58-29--qwen2.5-coder:7b-instruct-q8_0
|
||||
test_cases: 133
|
||||
model: qwen2.5-coder:7b-instruct-q8_0
|
||||
edit_format: whole
|
||||
commit_hash: 6f2b064-dirty
|
||||
pass_rate_1: 45.1
|
||||
pass_rate_2: 51.9
|
||||
percent_cases_well_formed: 100.0
|
||||
error_outputs: 0
|
||||
num_malformed_responses: 0
|
||||
num_with_malformed_responses: 0
|
||||
user_asks: 4
|
||||
lazy_comments: 0
|
||||
syntax_errors: 0
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 2
|
||||
command: aider --model ollama/qwen2.5-coder:7b-instruct-q8_0
|
||||
date: 2024-09-19
|
||||
versions: 0.56.0
|
||||
seconds_per_case: 9.3
|
||||
total_cost: 0.0000
|
||||
|
||||
- dirname: 2024-09-20-20-20-19--qwen-2.5-72b-instruct-diff
|
||||
test_cases: 133
|
||||
model: qwen-2.5-72b-instruct (bf16)
|
||||
edit_format: diff
|
||||
commit_hash: 5139594
|
||||
pass_rate_1: 53.4
|
||||
pass_rate_2: 65.4
|
||||
percent_cases_well_formed: 96.2
|
||||
error_outputs: 9
|
||||
num_malformed_responses: 9
|
||||
num_with_malformed_responses: 5
|
||||
user_asks: 3
|
||||
lazy_comments: 0
|
||||
syntax_errors: 2
|
||||
indentation_errors: 1
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 3
|
||||
command: aider --model openrouter/qwen/qwen-2.5-72b-instruct
|
||||
date: 2024-09-20
|
||||
versions: 0.56.1.dev
|
||||
seconds_per_case: 39.8
|
||||
total_cost: 0.0000
|
||||
186
aider/website/_data/o1_results.yml
Normal file
186
aider/website/_data/o1_results.yml
Normal file
@@ -0,0 +1,186 @@
|
||||
- dirname: 2024-07-18-18-57-46--gpt-4o-mini-whole
|
||||
test_cases: 133
|
||||
model: gpt-4o-mini (whole)
|
||||
edit_format: whole
|
||||
commit_hash: d31eef3-dirty
|
||||
pass_rate_1: 40.6
|
||||
pass_rate_2: 55.6
|
||||
released: 2024-07-18
|
||||
percent_cases_well_formed: 100.0
|
||||
error_outputs: 1
|
||||
num_malformed_responses: 0
|
||||
num_with_malformed_responses: 0
|
||||
user_asks: 1
|
||||
lazy_comments: 0
|
||||
syntax_errors: 1
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 2
|
||||
command: aider --model gpt-4o-mini
|
||||
date: 2024-07-18
|
||||
versions: 0.44.1-dev
|
||||
seconds_per_case: 7.8
|
||||
total_cost: 0.0916
|
||||
|
||||
- dirname: 2024-07-04-14-32-08--claude-3.5-sonnet-diff-continue
|
||||
test_cases: 133
|
||||
model: claude-3.5-sonnet (diff)
|
||||
edit_format: diff
|
||||
commit_hash: 35f21b5
|
||||
pass_rate_1: 57.1
|
||||
pass_rate_2: 77.4
|
||||
percent_cases_well_formed: 99.2
|
||||
error_outputs: 23
|
||||
released: 2024-06-20
|
||||
num_malformed_responses: 4
|
||||
num_with_malformed_responses: 1
|
||||
user_asks: 2
|
||||
lazy_comments: 0
|
||||
syntax_errors: 1
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 1
|
||||
command: aider --sonnet
|
||||
date: 2024-07-04
|
||||
versions: 0.42.1-dev
|
||||
seconds_per_case: 17.6
|
||||
total_cost: 3.6346
|
||||
|
||||
- dirname: 2024-08-06-18-28-39--gpt-4o-2024-08-06-diff-again
|
||||
test_cases: 133
|
||||
model: gpt-4o-2024-08-06 (diff)
|
||||
edit_format: diff
|
||||
commit_hash: ed9ed89
|
||||
pass_rate_1: 57.1
|
||||
pass_rate_2: 71.4
|
||||
percent_cases_well_formed: 98.5
|
||||
error_outputs: 18
|
||||
num_malformed_responses: 2
|
||||
num_with_malformed_responses: 2
|
||||
user_asks: 10
|
||||
lazy_comments: 0
|
||||
syntax_errors: 6
|
||||
indentation_errors: 2
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 5
|
||||
released: 2024-08-06
|
||||
command: aider --model openai/gpt-4o-2024-08-06
|
||||
date: 2024-08-06
|
||||
versions: 0.48.1-dev
|
||||
seconds_per_case: 6.5
|
||||
total_cost: 0.0000
|
||||
|
||||
- dirname: 2024-09-12-19-57-35--o1-mini-whole
|
||||
test_cases: 133
|
||||
model: o1-mini (whole)
|
||||
edit_format: whole
|
||||
commit_hash: 36fa773-dirty, 291b456
|
||||
pass_rate_1: 49.6
|
||||
pass_rate_2: 70.7
|
||||
percent_cases_well_formed: 90.0
|
||||
error_outputs: 0
|
||||
num_malformed_responses: 0
|
||||
num_with_malformed_responses: 0
|
||||
user_asks: 17
|
||||
lazy_comments: 0
|
||||
syntax_errors: 0
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 1
|
||||
command: aider --model o1-mini
|
||||
date: 2024-09-12
|
||||
versions: 0.56.1.dev
|
||||
seconds_per_case: 103.0
|
||||
total_cost: 5.3725
|
||||
|
||||
- dirname: 2024-09-12-20-56-22--o1-mini-diff
|
||||
test_cases: 133
|
||||
model: o1-mini (diff)
|
||||
edit_format: diff
|
||||
commit_hash: 4598a37-dirty, 291b456, 752e823-dirty
|
||||
pass_rate_1: 45.1
|
||||
pass_rate_2: 62.4
|
||||
percent_cases_well_formed: 85.7
|
||||
error_outputs: 26
|
||||
num_malformed_responses: 26
|
||||
num_with_malformed_responses: 19
|
||||
user_asks: 2
|
||||
lazy_comments: 0
|
||||
syntax_errors: 0
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 1
|
||||
command: aider --model o1-mini --edit-format diff
|
||||
date: 2024-09-12
|
||||
versions: 0.56.1.dev
|
||||
seconds_per_case: 177.7
|
||||
total_cost: 11.1071
|
||||
|
||||
- dirname: 2024-09-05-21-26-49--sonnet-whole-sep5
|
||||
test_cases: 133
|
||||
model: claude-3.5-sonnet (whole)
|
||||
edit_format: whole
|
||||
commit_hash: 8cfdcbd
|
||||
pass_rate_1: 55.6
|
||||
pass_rate_2: 75.2
|
||||
percent_cases_well_formed: 100.0
|
||||
error_outputs: 0
|
||||
num_malformed_responses: 0
|
||||
num_with_malformed_responses: 0
|
||||
user_asks: 0
|
||||
lazy_comments: 0
|
||||
syntax_errors: 0
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 0
|
||||
command: aider --model openrouter/anthropic/claude-3.5-sonnet --edit-format whole
|
||||
date: 2024-09-05
|
||||
versions: 0.55.1.dev
|
||||
seconds_per_case: 15.2
|
||||
total_cost: 2.3502
|
||||
|
||||
- dirname: 2024-09-12-22-44-14--o1-preview-diff
|
||||
test_cases: 133
|
||||
model: o1-preview (diff)
|
||||
edit_format: diff
|
||||
commit_hash: 72f52bd
|
||||
pass_rate_1: 56.4
|
||||
pass_rate_2: 75.2
|
||||
percent_cases_well_formed: 84.2
|
||||
error_outputs: 27
|
||||
num_malformed_responses: 27
|
||||
num_with_malformed_responses: 21
|
||||
user_asks: 8
|
||||
lazy_comments: 0
|
||||
syntax_errors: 7
|
||||
indentation_errors: 3
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 3
|
||||
command: aider --model o1-preview
|
||||
date: 2024-09-12
|
||||
versions: 0.56.1.dev
|
||||
seconds_per_case: 95.8
|
||||
total_cost: 71.7927
|
||||
|
||||
- dirname: 2024-09-13-02-13-59--o1-preview-whole
|
||||
test_cases: 133
|
||||
model: o1-preview (whole)
|
||||
edit_format: whole
|
||||
commit_hash: 72f52bd-dirty
|
||||
pass_rate_1: 58.6
|
||||
pass_rate_2: 79.7
|
||||
percent_cases_well_formed: 100.0
|
||||
error_outputs: 0
|
||||
num_malformed_responses: 0
|
||||
num_with_malformed_responses: 0
|
||||
user_asks: 2
|
||||
lazy_comments: 0
|
||||
syntax_errors: 1
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 2
|
||||
command: aider --model o1-preview
|
||||
date: 2024-09-13
|
||||
versions: 0.56.1.dev
|
||||
seconds_per_case: 47.4
|
||||
total_cost: 38.0612
|
||||
@@ -167,7 +167,7 @@
|
||||
|
||||
- dirname: 2024-07-24-07-49-39--refac-deepseek-coder-v2-0724
|
||||
test_cases: 89
|
||||
model: DeepSeek Coder V2 0724
|
||||
model: DeepSeek Coder V2 0724 (deprecated)
|
||||
edit_format: diff
|
||||
commit_hash: bb6e597
|
||||
pass_rate_1: 32.6
|
||||
@@ -208,4 +208,25 @@
|
||||
versions: 0.48.1-dev
|
||||
seconds_per_case: 16.9
|
||||
total_cost: 4.0873
|
||||
|
||||
|
||||
- dirname: 2024-09-05-15-19-05--refac-deepseek-v2.5-no-shell
|
||||
test_cases: 89
|
||||
model: DeepSeek Chat V2.5
|
||||
edit_format: diff
|
||||
commit_hash: 1279c86, 1279c86-dirty
|
||||
pass_rate_1: 31.5
|
||||
percent_cases_well_formed: 67.4
|
||||
error_outputs: 90
|
||||
num_malformed_responses: 88
|
||||
num_with_malformed_responses: 29
|
||||
user_asks: 8
|
||||
lazy_comments: 7
|
||||
syntax_errors: 0
|
||||
indentation_errors: 6
|
||||
exhausted_context_windows: 2
|
||||
test_timeouts: 0
|
||||
command: aider --deepseek
|
||||
date: 2024-09-05
|
||||
versions: 0.55.1.dev
|
||||
seconds_per_case: 225.4
|
||||
total_cost: 1.0338
|
||||
170
aider/website/_includes/leaderboard_graph.html
Normal file
170
aider/website/_includes/leaderboard_graph.html
Normal file
@@ -0,0 +1,170 @@
|
||||
<canvas id="{{ include.chart_id }}" width="800" height="450" style="margin-top: 20px"></canvas>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
var ctx = document.getElementById('{{ include.chart_id }}').getContext('2d');
|
||||
var leaderboardData = {
|
||||
labels: [],
|
||||
datasets: [{
|
||||
label: 'Percent completed correctly',
|
||||
data: [],
|
||||
backgroundColor: [],
|
||||
borderColor: [],
|
||||
borderWidth: 1
|
||||
}]
|
||||
};
|
||||
|
||||
var allData = [];
|
||||
{% for row in include.data %}
|
||||
allData.push({
|
||||
model: '{{ row.model }}',
|
||||
pass_rate: {{ row[include.pass_rate_key] }},
|
||||
percent_cases_well_formed: {{ row.percent_cases_well_formed }},
|
||||
edit_format: '{{ row.edit_format }}'
|
||||
});
|
||||
{% endfor %}
|
||||
|
||||
function updateChart() {
|
||||
var selectedRows = document.querySelectorAll('tr.selected');
|
||||
var showAll = selectedRows.length === 0;
|
||||
|
||||
leaderboardData.labels = [];
|
||||
leaderboardData.datasets[0].data = [];
|
||||
leaderboardData.datasets[0].backgroundColor = [];
|
||||
leaderboardData.datasets[0].borderColor = [];
|
||||
|
||||
allData.forEach(function(row, index) {
|
||||
var rowElement = document.getElementById('{{ include.row_prefix }}-' + index);
|
||||
if (showAll) {
|
||||
rowElement.classList.remove('selected');
|
||||
}
|
||||
if (showAll || rowElement.classList.contains('selected')) {
|
||||
leaderboardData.labels.push(row.model);
|
||||
leaderboardData.datasets[0].data.push(row.pass_rate);
|
||||
|
||||
switch (row.edit_format) {
|
||||
case 'whole':
|
||||
leaderboardData.datasets[0].backgroundColor.push('rgba(255, 99, 132, 0.2)');
|
||||
leaderboardData.datasets[0].borderColor.push('rgba(255, 99, 132, 1)');
|
||||
break;
|
||||
case 'diff':
|
||||
leaderboardData.datasets[0].backgroundColor.push('rgba(54, 162, 235, 0.2)');
|
||||
leaderboardData.datasets[0].borderColor.push('rgba(54, 162, 235, 1)');
|
||||
break;
|
||||
case 'udiff':
|
||||
leaderboardData.datasets[0].backgroundColor.push('rgba(75, 192, 192, 0.2)');
|
||||
leaderboardData.datasets[0].borderColor.push('rgba(75, 192, 192, 1)');
|
||||
break;
|
||||
case 'diff-fenced':
|
||||
leaderboardData.datasets[0].backgroundColor.push('rgba(153, 102, 255, 0.2)');
|
||||
leaderboardData.datasets[0].borderColor.push('rgba(153, 102, 255, 1)');
|
||||
break;
|
||||
default:
|
||||
leaderboardData.datasets[0].backgroundColor.push('rgba(201, 203, 207, 0.2)');
|
||||
leaderboardData.datasets[0].borderColor.push('rgba(201, 203, 207, 1)');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Apply legend filtering
|
||||
var meta = leaderboardChart.getDatasetMeta(0);
|
||||
meta.data.forEach(function(bar, index) {
|
||||
if (leaderboardData.labels.includes(allData[index].model)) {
|
||||
bar.hidden = (allData[index].edit_format === 'whole' && meta.data[0].hidden) ||
|
||||
(allData[index].edit_format !== 'whole' && meta.data[1].hidden);
|
||||
} else {
|
||||
bar.hidden = true;
|
||||
}
|
||||
});
|
||||
|
||||
leaderboardChart.update();
|
||||
}
|
||||
|
||||
var tableBody = document.querySelector('table tbody');
|
||||
allData.forEach(function(row, index) {
|
||||
var tr = tableBody.children[index];
|
||||
tr.id = '{{ include.row_prefix }}-' + index;
|
||||
tr.style.cursor = 'pointer';
|
||||
tr.onclick = function() {
|
||||
this.classList.toggle('selected');
|
||||
updateChart();
|
||||
};
|
||||
});
|
||||
|
||||
var leaderboardChart = new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: leaderboardData,
|
||||
options: {
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Correct Exercises (%)'
|
||||
}
|
||||
},
|
||||
x: {
|
||||
ticks: {
|
||||
autoSkip: false,
|
||||
maxRotation: 90,
|
||||
minRotation: 0
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
display: true,
|
||||
position: 'top',
|
||||
labels: {
|
||||
generateLabels: function(chart) {
|
||||
var uniqueFormats = [...new Set(allData.map(item => item.edit_format))];
|
||||
return uniqueFormats.map(format => {
|
||||
var color;
|
||||
switch (format) {
|
||||
case 'whole':
|
||||
color = { fill: 'rgba(255, 99, 132, 0.2)', stroke: 'rgba(255, 99, 132, 1)' };
|
||||
break;
|
||||
case 'diff':
|
||||
color = { fill: 'rgba(54, 162, 235, 0.2)', stroke: 'rgba(54, 162, 235, 1)' };
|
||||
break;
|
||||
case 'udiff':
|
||||
color = { fill: 'rgba(75, 192, 192, 0.2)', stroke: 'rgba(75, 192, 192, 1)' };
|
||||
break;
|
||||
case 'diff-fenced':
|
||||
color = { fill: 'rgba(153, 102, 255, 0.2)', stroke: 'rgba(153, 102, 255, 1)' };
|
||||
break;
|
||||
default:
|
||||
color = { fill: 'rgba(201, 203, 207, 0.2)', stroke: 'rgba(201, 203, 207, 1)' };
|
||||
}
|
||||
return {
|
||||
text: format,
|
||||
fillStyle: color.fill,
|
||||
strokeStyle: color.stroke,
|
||||
lineWidth: 1,
|
||||
hidden: false
|
||||
};
|
||||
});
|
||||
}
|
||||
},
|
||||
onClick: function(e, legendItem, legend) {
|
||||
var ci = legend.chart;
|
||||
var clickedFormat = legendItem.text;
|
||||
|
||||
legendItem.hidden = !legendItem.hidden;
|
||||
|
||||
ci.data.datasets[0].data.forEach(function(dataPoint, i) {
|
||||
var meta = ci.getDatasetMeta(0);
|
||||
if (allData[i].edit_format === clickedFormat) {
|
||||
meta.data[i].hidden = legendItem.hidden;
|
||||
}
|
||||
});
|
||||
|
||||
ci.update();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
updateChart();
|
||||
});
|
||||
</script>
|
||||
9
aider/website/_includes/replit-pipx.md
Normal file
9
aider/website/_includes/replit-pipx.md
Normal file
@@ -0,0 +1,9 @@
|
||||
To use aider with pipx on replit, you can run these commands in the replit shell:
|
||||
|
||||
```
|
||||
pip install pipx
|
||||
pipx run aider-chat ...normal aider args...
|
||||
```
|
||||
|
||||
If you install aider with pipx on replit and try and run it as just `aider` it will crash with a missing `libstdc++.so.6` library.
|
||||
|
||||
116
aider/website/_posts/2024-09-12-o1.md
Normal file
116
aider/website/_posts/2024-09-12-o1.md
Normal file
@@ -0,0 +1,116 @@
|
||||
---
|
||||
title: o1-preview is SOTA on the aider leaderboard
|
||||
excerpt: Preliminary benchmark results for the new OpenAI o1 models.
|
||||
nav_exclude: true
|
||||
---
|
||||
{% if page.date %}
|
||||
<p class="post-date">{{ page.date | date: "%B %d, %Y" }}</p>
|
||||
{% endif %}
|
||||
|
||||
# OpenAI o1-preview is SOTA on the aider leaderboard
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
|
||||
{% assign edit_sorted = site.data.o1_results | sort: 'pass_rate_2' | reverse %}
|
||||
{% include leaderboard_graph.html
|
||||
chart_id="editChart"
|
||||
data=edit_sorted
|
||||
row_prefix="edit-row"
|
||||
pass_rate_key="pass_rate_2"
|
||||
%}
|
||||
|
||||
|
||||
## o1-preview
|
||||
|
||||
OpenAI o1-preview scored 79.7% on aider's code editing benchmark,
|
||||
a state of the art result.
|
||||
It achieved this result with the
|
||||
["whole" edit format](/docs/leaderboards/#notes-on-the-edit-format),
|
||||
where the LLM returns a full copy of the source code file with changes.
|
||||
|
||||
It is much more practical to use aider's
|
||||
["diff" edit format](/docs/leaderboards/#notes-on-the-edit-format),
|
||||
which allows the LLM to return search/replace blocks to
|
||||
efficiently edit the source code.
|
||||
This saves significant time and token costs.
|
||||
|
||||
Using the diff edit format the o1-preview model had a strong
|
||||
benchmark score of 75.2%.
|
||||
This likely places o1-preview between Sonnet and GPT-4o for practical use,
|
||||
but at significantly higher cost.
|
||||
|
||||
## o1-mini
|
||||
|
||||
OpenAI o1-mini is priced similarly to GPT-4o and Claude 3.5 Sonnet,
|
||||
but scored below those models.
|
||||
It also works best with the whole edit format.
|
||||
|
||||
|
||||
## Future work
|
||||
|
||||
The o1-preview model had trouble conforming to aider's diff edit format.
|
||||
The o1-mini model had trouble conforming to both the whole and diff edit formats.
|
||||
Aider is extremely permissive and tries hard to accept anything close
|
||||
to the correct formats.
|
||||
|
||||
It is surprising that such strong models had trouble with
|
||||
the syntactic requirements of simple text output formats.
|
||||
It seems likely that aider could optimize its prompts and edit formats to
|
||||
better harness the o1 models.
|
||||
|
||||
|
||||
## Using aider with o1
|
||||
|
||||
OpenAI's new o1 models are supported in v0.57.0 of aider:
|
||||
|
||||
```
|
||||
aider --model o1-mini
|
||||
aider --model o1-preview
|
||||
```
|
||||
|
||||
{: .note }
|
||||
> These are initial benchmark results for the o1 models,
|
||||
> based on aider v0.56.1-dev.
|
||||
> See the [aider leaderboards](/docs/leaderboards/) for up-to-date results
|
||||
> based on the latest aider releases.
|
||||
|
||||
|
||||
<table style="width: 100%; max-width: 800px; margin: auto; border-collapse: collapse; box-shadow: 0 2px 4px rgba(0,0,0,0.1); font-size: 14px;">
|
||||
<thead style="background-color: #f2f2f2;">
|
||||
<tr>
|
||||
<th style="padding: 8px; text-align: left;">Model</th>
|
||||
<th style="padding: 8px; text-align: center;">Percent completed correctly</th>
|
||||
<th style="padding: 8px; text-align: center;">Percent using correct edit format</th>
|
||||
<th style="padding: 8px; text-align: left;">Command</th>
|
||||
<th style="padding: 8px; text-align: center;">Edit format</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for row in edit_sorted %}
|
||||
<tr style="border-bottom: 1px solid #ddd;">
|
||||
<td style="padding: 8px;">{{ row.model }}</td>
|
||||
<td style="padding: 8px; text-align: center;">{{ row.pass_rate_2 }}%</td>
|
||||
<td style="padding: 8px; text-align: center;">{{ row.percent_cases_well_formed }}%</td>
|
||||
<td style="padding: 8px;"><code>{{ row.command }}</code></td>
|
||||
<td style="padding: 8px; text-align: center;">{{ row.edit_format }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
<style>
|
||||
tr.selected {
|
||||
color: #0056b3;
|
||||
}
|
||||
table {
|
||||
table-layout: fixed;
|
||||
}
|
||||
td, th {
|
||||
word-wrap: break-word;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
td:nth-child(3), td:nth-child(4) {
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
@@ -12,19 +12,19 @@
|
||||
# options:
|
||||
|
||||
## show this help message and exit
|
||||
#help:
|
||||
#help: xxx
|
||||
|
||||
#######
|
||||
# Main:
|
||||
|
||||
## Specify the OpenAI API key
|
||||
#openai-api-key:
|
||||
#openai-api-key: xxx
|
||||
|
||||
## Specify the Anthropic API key
|
||||
#anthropic-api-key:
|
||||
#anthropic-api-key: xxx
|
||||
|
||||
## Specify the model to use for the main chat
|
||||
#model:
|
||||
#model: xxx
|
||||
|
||||
## Use claude-3-opus-20240229 model for the main chat
|
||||
#opus: false
|
||||
@@ -54,22 +54,22 @@
|
||||
# Model Settings:
|
||||
|
||||
## List known models which match the (partial) MODEL name
|
||||
#models:
|
||||
#list-models: xxx
|
||||
|
||||
## Specify the api base url
|
||||
#openai-api-base:
|
||||
#openai-api-base: xxx
|
||||
|
||||
## Specify the api_type
|
||||
#openai-api-type:
|
||||
#openai-api-type: xxx
|
||||
|
||||
## Specify the api_version
|
||||
#openai-api-version:
|
||||
#openai-api-version: xxx
|
||||
|
||||
## Specify the deployment_id
|
||||
#openai-api-deployment-id:
|
||||
#openai-api-deployment-id: xxx
|
||||
|
||||
## Specify the OpenAI organization ID
|
||||
#openai-organization-id:
|
||||
#openai-organization-id: xxx
|
||||
|
||||
## Specify a file with aider model settings for unknown models
|
||||
#model-settings-file: .aider.model.settings.yml
|
||||
@@ -81,16 +81,16 @@
|
||||
#verify-ssl: true
|
||||
|
||||
## Specify what edit format the LLM should use (default depends on model)
|
||||
#edit-format:
|
||||
#edit-format: xxx
|
||||
|
||||
## Specify the model to use for commit messages and chat history summarization (default depends on --model)
|
||||
#weak-model:
|
||||
#weak-model: xxx
|
||||
|
||||
## Only work with models that have meta-data available (default: True)
|
||||
#show-model-warnings: true
|
||||
|
||||
## Suggested number of tokens to use for repo map, use 0 to disable (default: 1024)
|
||||
#map-tokens:
|
||||
#map-tokens: xxx
|
||||
|
||||
## Control how often the repo map is refreshed (default: auto)
|
||||
#map-refresh: auto
|
||||
@@ -105,7 +105,7 @@
|
||||
#map-multiplier-no-files: true
|
||||
|
||||
## Maximum number of tokens to use for chat history. If not specified, uses the model's max_chat_history_tokens.
|
||||
#max-chat-history-tokens:
|
||||
#max-chat-history-tokens: xxx
|
||||
|
||||
## Specify the .env file to load (default: .env in git root)
|
||||
#env-file: .env
|
||||
@@ -123,7 +123,7 @@
|
||||
#restore-chat-history: false
|
||||
|
||||
## Log the conversation with the LLM to this file (for example, .aider.llm.history)
|
||||
#llm-history-file:
|
||||
#llm-history-file: xxx
|
||||
|
||||
##################
|
||||
# Output Settings:
|
||||
@@ -144,7 +144,7 @@
|
||||
#user-input-color: #00cc00
|
||||
|
||||
## Set the color for tool output (default: None)
|
||||
#tool-output-color:
|
||||
#tool-output-color: xxx
|
||||
|
||||
## Set the color for tool error messages (default: #FF2222)
|
||||
#tool-error-color: #FF2222
|
||||
@@ -198,7 +198,7 @@
|
||||
#commit: false
|
||||
|
||||
## Specify a custom prompt for generating commit messages
|
||||
#commit-prompt:
|
||||
#commit-prompt: xxx
|
||||
|
||||
## Perform a dry run without modifying files (default: False)
|
||||
#dry-run: false
|
||||
@@ -210,13 +210,15 @@
|
||||
#lint: false
|
||||
|
||||
## Specify lint commands to run for different languages, eg: "python: flake8 --select=..." (can be used multiple times)
|
||||
#lint-cmd:
|
||||
#lint-cmd: xxx
|
||||
## Specify multiple values like this:
|
||||
#lint-cmd: [xxx,yyyy,zzz]
|
||||
|
||||
## Enable/disable automatic linting after changes (default: True)
|
||||
#auto-lint: true
|
||||
|
||||
## Specify command to run tests
|
||||
#test-cmd:
|
||||
#test-cmd: xxx
|
||||
|
||||
## Enable/disable automatic testing after changes (default: False)
|
||||
#auto-test: false
|
||||
@@ -228,10 +230,14 @@
|
||||
# Other Settings:
|
||||
|
||||
## specify a file to edit (can be used multiple times)
|
||||
#file:
|
||||
#file: xxx
|
||||
## Specify multiple values like this:
|
||||
#file: [xxx,yyyy,zzz]
|
||||
|
||||
## specify a read-only file (can be used multiple times)
|
||||
#read:
|
||||
#read: xxx
|
||||
## Specify multiple values like this:
|
||||
#read: [xxx,yyyy,zzz]
|
||||
|
||||
## Use VI editing mode in the terminal (default: False)
|
||||
#vim: false
|
||||
@@ -239,8 +245,11 @@
|
||||
## Specify the language for voice using ISO 639-1 code (default: auto)
|
||||
#voice-language: en
|
||||
|
||||
## Specify the language to use in the chat (default: None, uses system settings)
|
||||
#chat-language: xxx
|
||||
|
||||
## Show the version number and exit
|
||||
#version:
|
||||
#version: xxx
|
||||
|
||||
## Check for updates and return status in the exit code
|
||||
#just-check-update: false
|
||||
@@ -255,7 +264,7 @@
|
||||
#upgrade: false
|
||||
|
||||
## Apply the changes from the given file instead of running the chat (debug)
|
||||
#apply:
|
||||
#apply: xxx
|
||||
|
||||
## Always say yes to every confirmation
|
||||
#yes: false
|
||||
@@ -273,16 +282,16 @@
|
||||
#exit: false
|
||||
|
||||
## Specify a single message to send the LLM, process reply then exit (disables chat mode)
|
||||
#message:
|
||||
#message: xxx
|
||||
|
||||
## Specify a file containing the message to send the LLM, process reply, then exit (disables chat mode)
|
||||
#message-file:
|
||||
#message-file: xxx
|
||||
|
||||
## Specify the encoding for input and output (default: utf-8)
|
||||
#encoding: utf-8
|
||||
|
||||
## Specify the config file (default: search for .aider.conf.yml in git root, cwd or home directory)
|
||||
#config:
|
||||
#config: xxx
|
||||
|
||||
## Run aider in your browser
|
||||
#gui: false
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
# Model Settings:
|
||||
|
||||
## List known models which match the (partial) MODEL name
|
||||
#AIDER_MODELS=
|
||||
#AIDER_LIST_MODELS=
|
||||
|
||||
## Specify the api base url
|
||||
#OPENAI_API_BASE=
|
||||
@@ -243,6 +243,9 @@
|
||||
## Specify the language for voice using ISO 639-1 code (default: auto)
|
||||
#AIDER_VOICE_LANGUAGE=en
|
||||
|
||||
## Specify the language to use in the chat (default: None, uses system settings)
|
||||
#AIDER_CHAT_LANGUAGE=
|
||||
|
||||
## Check for updates and return status in the exit code
|
||||
#AIDER_JUST_CHECK_UPDATE=false
|
||||
|
||||
|
||||
@@ -89,3 +89,8 @@ The yaml file should be a a list of dictionary objects for each model, as follow
|
||||
examples_as_sys_msg: false
|
||||
```
|
||||
|
||||
You can look at the `ModelSettings` class in
|
||||
[models.py](https://github.com/paul-gauthier/aider/blob/main/aider/models.py)
|
||||
file for details about all of the model setting that aider supports.
|
||||
That file also contains the settings for many popular models.
|
||||
|
||||
|
||||
@@ -60,19 +60,19 @@ cog.outl("```")
|
||||
# options:
|
||||
|
||||
## show this help message and exit
|
||||
#help:
|
||||
#help: xxx
|
||||
|
||||
#######
|
||||
# Main:
|
||||
|
||||
## Specify the OpenAI API key
|
||||
#openai-api-key:
|
||||
#openai-api-key: xxx
|
||||
|
||||
## Specify the Anthropic API key
|
||||
#anthropic-api-key:
|
||||
#anthropic-api-key: xxx
|
||||
|
||||
## Specify the model to use for the main chat
|
||||
#model:
|
||||
#model: xxx
|
||||
|
||||
## Use claude-3-opus-20240229 model for the main chat
|
||||
#opus: false
|
||||
@@ -102,22 +102,22 @@ cog.outl("```")
|
||||
# Model Settings:
|
||||
|
||||
## List known models which match the (partial) MODEL name
|
||||
#models:
|
||||
#list-models: xxx
|
||||
|
||||
## Specify the api base url
|
||||
#openai-api-base:
|
||||
#openai-api-base: xxx
|
||||
|
||||
## Specify the api_type
|
||||
#openai-api-type:
|
||||
#openai-api-type: xxx
|
||||
|
||||
## Specify the api_version
|
||||
#openai-api-version:
|
||||
#openai-api-version: xxx
|
||||
|
||||
## Specify the deployment_id
|
||||
#openai-api-deployment-id:
|
||||
#openai-api-deployment-id: xxx
|
||||
|
||||
## Specify the OpenAI organization ID
|
||||
#openai-organization-id:
|
||||
#openai-organization-id: xxx
|
||||
|
||||
## Specify a file with aider model settings for unknown models
|
||||
#model-settings-file: .aider.model.settings.yml
|
||||
@@ -129,16 +129,16 @@ cog.outl("```")
|
||||
#verify-ssl: true
|
||||
|
||||
## Specify what edit format the LLM should use (default depends on model)
|
||||
#edit-format:
|
||||
#edit-format: xxx
|
||||
|
||||
## Specify the model to use for commit messages and chat history summarization (default depends on --model)
|
||||
#weak-model:
|
||||
#weak-model: xxx
|
||||
|
||||
## Only work with models that have meta-data available (default: True)
|
||||
#show-model-warnings: true
|
||||
|
||||
## Suggested number of tokens to use for repo map, use 0 to disable (default: 1024)
|
||||
#map-tokens:
|
||||
#map-tokens: xxx
|
||||
|
||||
## Control how often the repo map is refreshed (default: auto)
|
||||
#map-refresh: auto
|
||||
@@ -153,7 +153,7 @@ cog.outl("```")
|
||||
#map-multiplier-no-files: true
|
||||
|
||||
## Maximum number of tokens to use for chat history. If not specified, uses the model's max_chat_history_tokens.
|
||||
#max-chat-history-tokens:
|
||||
#max-chat-history-tokens: xxx
|
||||
|
||||
## Specify the .env file to load (default: .env in git root)
|
||||
#env-file: .env
|
||||
@@ -171,7 +171,7 @@ cog.outl("```")
|
||||
#restore-chat-history: false
|
||||
|
||||
## Log the conversation with the LLM to this file (for example, .aider.llm.history)
|
||||
#llm-history-file:
|
||||
#llm-history-file: xxx
|
||||
|
||||
##################
|
||||
# Output Settings:
|
||||
@@ -192,7 +192,7 @@ cog.outl("```")
|
||||
#user-input-color: #00cc00
|
||||
|
||||
## Set the color for tool output (default: None)
|
||||
#tool-output-color:
|
||||
#tool-output-color: xxx
|
||||
|
||||
## Set the color for tool error messages (default: #FF2222)
|
||||
#tool-error-color: #FF2222
|
||||
@@ -246,7 +246,7 @@ cog.outl("```")
|
||||
#commit: false
|
||||
|
||||
## Specify a custom prompt for generating commit messages
|
||||
#commit-prompt:
|
||||
#commit-prompt: xxx
|
||||
|
||||
## Perform a dry run without modifying files (default: False)
|
||||
#dry-run: false
|
||||
@@ -258,13 +258,15 @@ cog.outl("```")
|
||||
#lint: false
|
||||
|
||||
## Specify lint commands to run for different languages, eg: "python: flake8 --select=..." (can be used multiple times)
|
||||
#lint-cmd:
|
||||
#lint-cmd: xxx
|
||||
## Specify multiple values like this:
|
||||
#lint-cmd: [xxx,yyyy,zzz]
|
||||
|
||||
## Enable/disable automatic linting after changes (default: True)
|
||||
#auto-lint: true
|
||||
|
||||
## Specify command to run tests
|
||||
#test-cmd:
|
||||
#test-cmd: xxx
|
||||
|
||||
## Enable/disable automatic testing after changes (default: False)
|
||||
#auto-test: false
|
||||
@@ -276,10 +278,14 @@ cog.outl("```")
|
||||
# Other Settings:
|
||||
|
||||
## specify a file to edit (can be used multiple times)
|
||||
#file:
|
||||
#file: xxx
|
||||
## Specify multiple values like this:
|
||||
#file: [xxx,yyyy,zzz]
|
||||
|
||||
## specify a read-only file (can be used multiple times)
|
||||
#read:
|
||||
#read: xxx
|
||||
## Specify multiple values like this:
|
||||
#read: [xxx,yyyy,zzz]
|
||||
|
||||
## Use VI editing mode in the terminal (default: False)
|
||||
#vim: false
|
||||
@@ -287,8 +293,11 @@ cog.outl("```")
|
||||
## Specify the language for voice using ISO 639-1 code (default: auto)
|
||||
#voice-language: en
|
||||
|
||||
## Specify the language to use in the chat (default: None, uses system settings)
|
||||
#chat-language: xxx
|
||||
|
||||
## Show the version number and exit
|
||||
#version:
|
||||
#version: xxx
|
||||
|
||||
## Check for updates and return status in the exit code
|
||||
#just-check-update: false
|
||||
@@ -303,7 +312,7 @@ cog.outl("```")
|
||||
#upgrade: false
|
||||
|
||||
## Apply the changes from the given file instead of running the chat (debug)
|
||||
#apply:
|
||||
#apply: xxx
|
||||
|
||||
## Always say yes to every confirmation
|
||||
#yes: false
|
||||
@@ -321,16 +330,16 @@ cog.outl("```")
|
||||
#exit: false
|
||||
|
||||
## Specify a single message to send the LLM, process reply then exit (disables chat mode)
|
||||
#message:
|
||||
#message: xxx
|
||||
|
||||
## Specify a file containing the message to send the LLM, process reply, then exit (disables chat mode)
|
||||
#message-file:
|
||||
#message-file: xxx
|
||||
|
||||
## Specify the encoding for input and output (default: utf-8)
|
||||
#encoding: utf-8
|
||||
|
||||
## Specify the config file (default: search for .aider.conf.yml in git root, cwd or home directory)
|
||||
#config:
|
||||
#config: xxx
|
||||
|
||||
## Run aider in your browser
|
||||
#gui: false
|
||||
|
||||
@@ -100,7 +100,7 @@ cog.outl("```")
|
||||
# Model Settings:
|
||||
|
||||
## List known models which match the (partial) MODEL name
|
||||
#AIDER_MODELS=
|
||||
#AIDER_LIST_MODELS=
|
||||
|
||||
## Specify the api base url
|
||||
#OPENAI_API_BASE=
|
||||
@@ -285,6 +285,9 @@ cog.outl("```")
|
||||
## Specify the language for voice using ISO 639-1 code (default: auto)
|
||||
#AIDER_VOICE_LANGUAGE=en
|
||||
|
||||
## Specify the language to use in the chat (default: None, uses system settings)
|
||||
#AIDER_CHAT_LANGUAGE=
|
||||
|
||||
## Check for updates and return status in the exit code
|
||||
#AIDER_JUST_CHECK_UPDATE=false
|
||||
|
||||
|
||||
@@ -27,10 +27,11 @@ cog.out(get_md_help())
|
||||
```
|
||||
usage: aider [-h] [--openai-api-key] [--anthropic-api-key] [--model]
|
||||
[--opus] [--sonnet] [--4] [--4o] [--mini] [--4-turbo]
|
||||
[--35turbo] [--deepseek] [--models] [--openai-api-base]
|
||||
[--openai-api-type] [--openai-api-version]
|
||||
[--openai-api-deployment-id] [--openai-organization-id]
|
||||
[--model-settings-file] [--model-metadata-file]
|
||||
[--35turbo] [--deepseek] [--list-models]
|
||||
[--openai-api-base] [--openai-api-type]
|
||||
[--openai-api-version] [--openai-api-deployment-id]
|
||||
[--openai-organization-id] [--model-settings-file]
|
||||
[--model-metadata-file]
|
||||
[--verify-ssl | --no-verify-ssl] [--edit-format]
|
||||
[--weak-model]
|
||||
[--show-model-warnings | --no-show-model-warnings]
|
||||
@@ -57,7 +58,7 @@ usage: aider [-h] [--openai-api-key] [--anthropic-api-key] [--model]
|
||||
[--lint] [--lint-cmd] [--auto-lint | --no-auto-lint]
|
||||
[--test-cmd] [--auto-test | --no-auto-test] [--test]
|
||||
[--file] [--read] [--vim] [--voice-language]
|
||||
[--version] [--just-check-update]
|
||||
[--chat-language] [--version] [--just-check-update]
|
||||
[--check-update | --no-check-update]
|
||||
[--install-main-branch] [--upgrade] [--apply] [--yes]
|
||||
[-v] [--show-repo-map] [--show-prompts] [--exit]
|
||||
@@ -130,9 +131,12 @@ Environment variable: `AIDER_DEEPSEEK`
|
||||
|
||||
## Model Settings:
|
||||
|
||||
### `--models MODEL`
|
||||
### `--list-models MODEL`
|
||||
List known models which match the (partial) MODEL name
|
||||
Environment variable: `AIDER_MODELS`
|
||||
Environment variable: `AIDER_LIST_MODELS`
|
||||
Aliases:
|
||||
- `--list-models MODEL`
|
||||
- `--models MODEL`
|
||||
|
||||
### `--openai-api-base OPENAI_API_BASE`
|
||||
Specify the api base url
|
||||
@@ -464,6 +468,10 @@ Specify the language for voice using ISO 639-1 code (default: auto)
|
||||
Default: en
|
||||
Environment variable: `AIDER_VOICE_LANGUAGE`
|
||||
|
||||
### `--chat-language CHAT_LANGUAGE`
|
||||
Specify the language to use in the chat (default: None, uses system settings)
|
||||
Environment variable: `AIDER_CHAT_LANGUAGE`
|
||||
|
||||
### `--version`
|
||||
Show the version number and exit
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ nav_exclude: true
|
||||
|
||||

|
||||
|
||||
|
||||
## Updated
|
||||
|
||||
Aider no longer uses ctags to build a repo map.
|
||||
@@ -228,7 +229,7 @@ Some possible approaches to reducing the amount of map data are:
|
||||
|
||||
- Distill the global map, to prioritize important symbols and discard "internal" or otherwise less globally relevant identifiers. Possibly enlist `gpt-3.5-turbo` to perform this distillation in a flexible and language agnostic way.
|
||||
- Provide a mechanism for GPT to start with a distilled subset of the global map, and let it ask to see more detail about subtrees or keywords that it feels are relevant to the current coding task.
|
||||
- Attempt to analyize the natural language coding task given by the user and predict which subset of the repo map is relevant. Possibly by analysis of prior coding chats within the specific repo. Work on certain files or types of features may require certain somewhat predictable context from elsewhere in the repo. Vector and keyword search against the chat history, repo map or codebase may help here.
|
||||
- Attempt to analyze the natural language coding task given by the user and predict which subset of the repo map is relevant. Possibly by analysis of prior coding chats within the specific repo. Work on certain files or types of features may require certain somewhat predictable context from elsewhere in the repo. Vector and keyword search against the chat history, repo map or codebase may help here.
|
||||
|
||||
One key goal is to prefer solutions which are language agnostic or
|
||||
which can be easily deployed against most popular code languages.
|
||||
|
||||
@@ -37,7 +37,7 @@ If you still wish to add lots of files to the chat, you can:
|
||||
|
||||
- Use a wildcard when you launch aider: `aider src/*.py`
|
||||
- Use a wildcard with the in-chat `/add` command: `/add src/*.py`
|
||||
- Give the `/add` command a directory name and it will recurisvely add every file under that dir: `/add src`
|
||||
- Give the `/add` command a directory name and it will recursively add every file under that dir: `/add src`
|
||||
|
||||
## Can I use aider in a large (mono) repo?
|
||||
|
||||
|
||||
@@ -29,12 +29,5 @@ pipx install aider-chat
|
||||
|
||||
## pipx on replit
|
||||
|
||||
To use aider with pipx on replit, you can run these commands in the replit shell:
|
||||
|
||||
```
|
||||
pip install pipx
|
||||
pipx run aider-chat ...normal aider args...
|
||||
```
|
||||
|
||||
If you install aider with pipx on replit and try and run it as just `aider` it will crash with a missing `libstdc++.so.6` library.
|
||||
{% include replit-pipx.md %}
|
||||
|
||||
|
||||
@@ -55,83 +55,14 @@ The model also has to successfully apply all its changes to the source file with
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<canvas id="editChart" width="800" height="450" style="margin-top: 20px"></canvas>
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
var ctx = document.getElementById('editChart').getContext('2d');
|
||||
var leaderboardData = {
|
||||
labels: [],
|
||||
datasets: [{
|
||||
label: 'Percent completed correctly',
|
||||
data: [],
|
||||
backgroundColor: 'rgba(54, 162, 235, 0.2)',
|
||||
borderColor: 'rgba(54, 162, 235, 1)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
};
|
||||
|
||||
var allData = [];
|
||||
{% for row in edit_sorted %}
|
||||
allData.push({
|
||||
model: '{{ row.model }}',
|
||||
pass_rate_2: {{ row.pass_rate_2 }},
|
||||
percent_cases_well_formed: {{ row.percent_cases_well_formed }}
|
||||
});
|
||||
{% endfor %}
|
||||
|
||||
function updateChart() {
|
||||
var selectedRows = document.querySelectorAll('tr.selected');
|
||||
var showAll = selectedRows.length === 0;
|
||||
|
||||
leaderboardData.labels = [];
|
||||
leaderboardData.datasets[0].data = [];
|
||||
|
||||
allData.forEach(function(row, index) {
|
||||
var rowElement = document.getElementById('edit-row-' + index);
|
||||
if (showAll) {
|
||||
rowElement.classList.remove('selected');
|
||||
}
|
||||
if (showAll || rowElement.classList.contains('selected')) {
|
||||
leaderboardData.labels.push(row.model);
|
||||
leaderboardData.datasets[0].data.push(row.pass_rate_2);
|
||||
}
|
||||
});
|
||||
|
||||
leaderboardChart.update();
|
||||
}
|
||||
|
||||
var tableBody = document.querySelector('table tbody');
|
||||
allData.forEach(function(row, index) {
|
||||
var tr = tableBody.children[index];
|
||||
tr.id = 'edit-row-' + index;
|
||||
tr.style.cursor = 'pointer';
|
||||
tr.onclick = function() {
|
||||
this.classList.toggle('selected');
|
||||
updateChart();
|
||||
};
|
||||
});
|
||||
|
||||
var leaderboardChart = new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: leaderboardData,
|
||||
options: {
|
||||
scales: {
|
||||
yAxes: [{
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
},
|
||||
ticks: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
updateChart();
|
||||
});
|
||||
</script>
|
||||
{% include leaderboard_graph.html
|
||||
chart_id="editChart"
|
||||
data=edit_sorted
|
||||
row_prefix="edit-row"
|
||||
pass_rate_key="pass_rate_2"
|
||||
%}
|
||||
<style>
|
||||
tr.selected {
|
||||
color: #0056b3;
|
||||
@@ -180,83 +111,12 @@ Therefore, results are available for fewer models.
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<canvas id="refacChart" width="800" height="450" style="margin-top: 20px"></canvas>
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
var ctx = document.getElementById('refacChart').getContext('2d');
|
||||
var leaderboardData = {
|
||||
labels: [],
|
||||
datasets: [{
|
||||
label: 'Percent completed correctly',
|
||||
data: [],
|
||||
backgroundColor: 'rgba(54, 162, 235, 0.2)',
|
||||
borderColor: 'rgba(54, 162, 235, 1)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
};
|
||||
|
||||
var allData = [];
|
||||
{% for row in refac_sorted %}
|
||||
allData.push({
|
||||
model: '{{ row.model }}',
|
||||
pass_rate_1: {{ row.pass_rate_1 }},
|
||||
percent_cases_well_formed: {{ row.percent_cases_well_formed }}
|
||||
});
|
||||
{% endfor %}
|
||||
|
||||
function updateChart() {
|
||||
var selectedRows = document.querySelectorAll('tr.selected');
|
||||
var showAll = selectedRows.length === 0;
|
||||
|
||||
leaderboardData.labels = [];
|
||||
leaderboardData.datasets[0].data = [];
|
||||
|
||||
allData.forEach(function(row, index) {
|
||||
var rowElement = document.getElementById('refac-row-' + index);
|
||||
if (showAll) {
|
||||
rowElement.classList.remove('selected');
|
||||
}
|
||||
if (showAll || rowElement.classList.contains('selected')) {
|
||||
leaderboardData.labels.push(row.model);
|
||||
leaderboardData.datasets[0].data.push(row.pass_rate_1);
|
||||
}
|
||||
});
|
||||
|
||||
leaderboardChart.update();
|
||||
}
|
||||
|
||||
var tableBody = document.querySelectorAll('table tbody')[1];
|
||||
allData.forEach(function(row, index) {
|
||||
var tr = tableBody.children[index];
|
||||
tr.id = 'refac-row-' + index;
|
||||
tr.style.cursor = 'pointer';
|
||||
tr.onclick = function() {
|
||||
this.classList.toggle('selected');
|
||||
updateChart();
|
||||
};
|
||||
});
|
||||
|
||||
var leaderboardChart = new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: leaderboardData,
|
||||
options: {
|
||||
scales: {
|
||||
yAxes: [{
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
},
|
||||
ticks: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
updateChart();
|
||||
});
|
||||
</script>
|
||||
{% include leaderboard_graph.html
|
||||
chart_id="refacChart"
|
||||
data=refac_sorted
|
||||
row_prefix="refac-row"
|
||||
pass_rate_key="pass_rate_1"
|
||||
%}
|
||||
|
||||
|
||||
## LLM code editing skill by model release date
|
||||
@@ -294,7 +154,7 @@ See the
|
||||
[benchmark README](https://github.com/paul-gauthier/aider/blob/main/benchmark/README.md)
|
||||
for information on running aider's code editing benchmarks.
|
||||
Submit results by opening a PR with edits to the
|
||||
[benchmark results data files](https://github.com/paul-gauthier/aider/blob/main/website/_data/).
|
||||
[benchmark results data files](https://github.com/paul-gauthier/aider/blob/main/aider/website/_data/).
|
||||
|
||||
|
||||
<p class="post-date">
|
||||
@@ -321,6 +181,6 @@ mod_dates = [get_last_modified_date(file) for file in files]
|
||||
latest_mod_date = max(mod_dates)
|
||||
cog.out(f"{latest_mod_date.strftime('%B %d, %Y.')}")
|
||||
]]]-->
|
||||
August 30, 2024.
|
||||
September 21, 2024.
|
||||
<!--[[[end]]]-->
|
||||
</p>
|
||||
|
||||
@@ -26,7 +26,7 @@ aider
|
||||
aider --opus
|
||||
|
||||
# List models available from Anthropic
|
||||
aider --models anthropic/
|
||||
aider --list-models anthropic/
|
||||
```
|
||||
|
||||
{: .tip }
|
||||
|
||||
@@ -24,7 +24,7 @@ setx AZURE_API_BASE https://myendpt.openai.azure.com
|
||||
aider --model azure/<your_deployment_name>
|
||||
|
||||
# List models available from Azure
|
||||
aider --models azure/
|
||||
aider --list-models azure/
|
||||
```
|
||||
|
||||
Note that aider will also use environment variables
|
||||
|
||||
@@ -54,7 +54,7 @@ aider --model bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0
|
||||
To see some models available via Bedrock, run:
|
||||
|
||||
```
|
||||
aider --models bedrock/
|
||||
aider --list-models bedrock/
|
||||
```
|
||||
|
||||
Make sure you have access to these models in your AWS account before attempting to use them with Aider.
|
||||
|
||||
@@ -18,8 +18,8 @@ python -m pip install aider-chat
|
||||
export COHERE_API_KEY=<key> # Mac/Linux
|
||||
setx COHERE_API_KEY <key> # Windows, restart shell after setx
|
||||
|
||||
aider --model command-r-plus
|
||||
aider --model command-r-plus-08-2024
|
||||
|
||||
# List models available from Cohere
|
||||
aider --models cohere_chat/
|
||||
aider --list-models cohere_chat/
|
||||
```
|
||||
|
||||
@@ -20,6 +20,6 @@ setx GEMINI_API_KEY <key> # Windows, restart shell after setx
|
||||
aider --model gemini/gemini-1.5-pro-latest
|
||||
|
||||
# List models available from Gemini
|
||||
aider --models gemini/
|
||||
aider --list-models gemini/
|
||||
```
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ setx GROQ_API_KEY <key> # Windows, restart shell after setx
|
||||
aider --model groq/llama3-70b-8192
|
||||
|
||||
# List models available from Groq
|
||||
aider --models groq/
|
||||
aider --list-models groq/
|
||||
```
|
||||
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ aider --4-turbo
|
||||
aider --35-turbo
|
||||
|
||||
# List models available from OpenAI
|
||||
aider --models openai/
|
||||
aider --list-models openai/
|
||||
```
|
||||
|
||||
You can use `aider --model <model-name>` to use any other OpenAI model.
|
||||
|
||||
@@ -18,7 +18,7 @@ setx OPENROUTER_API_KEY <key> # Windows, restart shell after setx
|
||||
aider --model openrouter/<provider>/<model>
|
||||
|
||||
# List models available from OpenRouter
|
||||
aider --models openrouter/
|
||||
aider --list-models openrouter/
|
||||
```
|
||||
|
||||
In particular, many aider users access Sonnet via OpenRouter:
|
||||
|
||||
@@ -9,14 +9,14 @@ Aider uses the [litellm](https://docs.litellm.ai/docs/providers) package
|
||||
to connect to hundreds of other models.
|
||||
You can use `aider --model <model-name>` to use any supported model.
|
||||
|
||||
To explore the list of supported models you can run `aider --models <model-name>`
|
||||
To explore the list of supported models you can run `aider --list-models <model-name>`
|
||||
with a partial model name.
|
||||
If the supplied name is not an exact match for a known model, aider will
|
||||
return a list of possible matching models.
|
||||
For example:
|
||||
|
||||
```
|
||||
$ aider --models turbo
|
||||
$ aider --list-models turbo
|
||||
|
||||
Aider v0.29.3-dev
|
||||
Models which match "turbo":
|
||||
@@ -63,6 +63,7 @@ cog.out(''.join(lines))
|
||||
- AZURE_API_KEY
|
||||
- AZURE_OPENAI_API_KEY
|
||||
- BASETEN_API_KEY
|
||||
- CEREBRAS_API_KEY
|
||||
- CLARIFAI_API_KEY
|
||||
- CLOUDFLARE_API_KEY
|
||||
- CODESTRAL_API_KEY
|
||||
@@ -71,18 +72,14 @@ cog.out(''.join(lines))
|
||||
- DATABRICKS_API_KEY
|
||||
- DEEPINFRA_API_KEY
|
||||
- DEEPSEEK_API_KEY
|
||||
- EMPOWER_API_KEY
|
||||
- FIREWORKSAI_API_KEY
|
||||
- FIREWORKS_AI_API_KEY
|
||||
- FIREWORKS_API_KEY
|
||||
- FRIENDLIAI_API_KEY
|
||||
- GEMINI_API_KEY
|
||||
- GITHUB_API_KEY
|
||||
- GROQ_API_KEY
|
||||
- HUGGINGFACE_API_KEY
|
||||
- MARITALK_API_KEY
|
||||
- MISTRAL_API_KEY
|
||||
- MISTRAL_AZURE_API_KEY
|
||||
- NLP_CLOUD_API_KEY
|
||||
- NVIDIA_NIM_API_KEY
|
||||
- OLLAMA_API_KEY
|
||||
@@ -91,14 +88,11 @@ cog.out(''.join(lines))
|
||||
- OR_API_KEY
|
||||
- PALM_API_KEY
|
||||
- PERPLEXITYAI_API_KEY
|
||||
- PERPLEXITY_API_KEY
|
||||
- PREDIBASE_API_KEY
|
||||
- PROVIDER_API_KEY
|
||||
- QDRANT_API_KEY
|
||||
- REPLICATE_API_KEY
|
||||
- TOGETHERAI_API_KEY
|
||||
- TOGETHER_AI_API_KEY
|
||||
- TOGETHER_API_KEY
|
||||
- VOLCENGINE_API_KEY
|
||||
- VOYAGE_API_KEY
|
||||
- XINFERENCE_API_KEY
|
||||
|
||||
@@ -26,7 +26,9 @@ for FILE in *.py ; do
|
||||
done
|
||||
```
|
||||
|
||||
User `aider --help` to see all the command line options, but these are useful for scripting:
|
||||
Use `aider --help` to see all the
|
||||
[command line options](/docs/config/options.html),
|
||||
but these are useful for scripting:
|
||||
|
||||
```
|
||||
--stream, --no-stream
|
||||
|
||||
51
aider/website/docs/troubleshooting/imports.md
Normal file
51
aider/website/docs/troubleshooting/imports.md
Normal file
@@ -0,0 +1,51 @@
|
||||
---
|
||||
parent: Troubleshooting
|
||||
nav_order: 28
|
||||
---
|
||||
|
||||
# Import errors
|
||||
|
||||
Aider expects to be installed via `pip` or `pipx`, which will install
|
||||
all of its required dependencies.
|
||||
If aider reports `ImportErrors`, this probably means it has been installed
|
||||
incorrectly.
|
||||
|
||||
## Install with pipx
|
||||
|
||||
If you are having problems with import errors you should consider
|
||||
[installing aider using pipx](/docs/install/pipx.html).
|
||||
This will ensure that aider is installed in its own python environment,
|
||||
with the correct set of dependencies.
|
||||
|
||||
## Package managers like Homebrew, AUR, ports
|
||||
|
||||
Package managers often install aider with the wrong dependencies, leading
|
||||
to import errors and other problems.
|
||||
It is not recommended to install aider with these tools.
|
||||
Instead, consider
|
||||
[installing aider using pipx](/docs/install/pipx.html).
|
||||
|
||||
## Dependency versions matter
|
||||
|
||||
Aider pins its dependencies and is tested to work with those specific versions.
|
||||
If you are installing aider with pip (rather than pipx),
|
||||
you should be careful about upgrading or downgrading the python packages that
|
||||
aider uses.
|
||||
|
||||
In particular, be careful with the packages with pinned versions
|
||||
noted at the end of
|
||||
[aider's requirements.in file](https://github.com/paul-gauthier/aider/blob/main/requirements/requirements.in).
|
||||
These versions are pinned because aider is known not to work with the
|
||||
latest versions of these libraries.
|
||||
|
||||
Also be wary of upgrading `litellm`, as it changes versions frequently
|
||||
and sometimes introduces bugs or backwards incompatible changes.
|
||||
|
||||
## Replit
|
||||
|
||||
You can `pip install aider-chat` on replit.
|
||||
|
||||
Or you can install aider with
|
||||
pipx as follows:
|
||||
|
||||
{% include replit-pipx.md %}
|
||||
@@ -13,6 +13,13 @@ Aider supports prompt caching for cost savings and faster coding.
|
||||
Currently Anthropic provides caching for Sonnet and Haiku,
|
||||
and DeepSeek provides caching for Coder.
|
||||
|
||||
Aider organizes the chat history to try and cache:
|
||||
|
||||
- The system prompt.
|
||||
- Read only files added with `--read` or `/read-only`.
|
||||
- The repository map.
|
||||
- The editable files that have been added to the chat.
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ cog.out(get_help_md())
|
||||
| **/models** | Search the list of available models |
|
||||
| **/quit** | Exit the application |
|
||||
| **/read-only** | Add files to the chat that are for reference, not to be edited |
|
||||
| **/report** | Report a problem by opening a GitHub Issue |
|
||||
| **/reset** | Drop all files and clear the chat history |
|
||||
| **/run** | Run a shell command and optionally add the output to the chat (alias: !) |
|
||||
| **/settings** | Print out the current settings |
|
||||
|
||||
@@ -8,6 +8,8 @@ description: Intro and tutorial videos made by aider users.
|
||||
|
||||
Here are some tutorial videos made by aider users:
|
||||
|
||||
- [Using aider to incrementally build a non-trivial app](https://youtu.be/QlUt06XLbJE) -- IndyDevDan
|
||||
- [Aider and Replit on mobile with your voice](https://x.com/itsPaulAi/status/1830987090617831810) -- Paul Couvert
|
||||
- [Aider is the OG AI Coding King (Mermaid Diagram AI Agent)](https://www.youtube.com/watch?v=ag-KxYS8Vuw) -- IndyDevDan
|
||||
- [Installing aider in replit and making a Trello clone](https://x.com/itspaulai/status/1828834199597633724) -- Paul Couvert
|
||||
- [Step-by-Step Development Environment Setup for AI-Assisted Coding](https://www.youtube.com/watch?v=DnBVgfe6ZQM) -- Coding the Future With AI
|
||||
|
||||
@@ -8,7 +8,7 @@ has_toc: false
|
||||
# Example chat transcripts
|
||||
|
||||
Below are some chat transcripts showing what it's like to code with aider.
|
||||
In the chats, you'll see a varity of coding tasks like generating new code, editing existing code, debugging, exploring unfamiliar code, etc.
|
||||
In the chats, you'll see a variety of coding tasks like generating new code, editing existing code, debugging, exploring unfamiliar code, etc.
|
||||
|
||||
* [**Hello World Flask App**](https://aider.chat/examples/hello-world-flask.html): Start from scratch and have aider create a simple Flask app with various endpoints, such as adding two numbers and calculating the Fibonacci sequence.
|
||||
|
||||
|
||||
@@ -549,7 +549,10 @@ def run_test_real(
|
||||
chat_history_file=history_fname,
|
||||
)
|
||||
|
||||
main_model = models.Model(model_name)
|
||||
# weak_model_name = model_name
|
||||
weak_model_name = None
|
||||
|
||||
main_model = models.Model(model_name, weak_model=weak_model_name)
|
||||
edit_format = edit_format or main_model.edit_format
|
||||
|
||||
dump(main_model)
|
||||
@@ -567,6 +570,7 @@ def run_test_real(
|
||||
verbose=verbose,
|
||||
# auto_lint=False, # disabled for code-in-json experiments
|
||||
cache_prompts=True,
|
||||
suggest_shell_commands=False,
|
||||
)
|
||||
coder.max_apply_update_errors = max_apply_update_errors
|
||||
|
||||
|
||||
@@ -67,3 +67,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[tool.setuptools_scm]
|
||||
write_to = "aider/__version__.py"
|
||||
|
||||
[tool.codespell]
|
||||
skip = "*.svg,Gemfile.lock"
|
||||
write-changes = true
|
||||
|
||||
@@ -12,7 +12,7 @@ aiosignal==1.3.1
|
||||
# via aiohttp
|
||||
annotated-types==0.7.0
|
||||
# via pydantic
|
||||
anyio==4.4.0
|
||||
anyio==4.6.0
|
||||
# via
|
||||
# httpx
|
||||
# openai
|
||||
@@ -25,12 +25,12 @@ backoff==2.2.1
|
||||
# via -r requirements/requirements.in
|
||||
beautifulsoup4==4.12.3
|
||||
# via -r requirements/requirements.in
|
||||
certifi==2024.7.4
|
||||
certifi==2024.8.30
|
||||
# via
|
||||
# httpcore
|
||||
# httpx
|
||||
# requests
|
||||
cffi==1.17.0
|
||||
cffi==1.17.1
|
||||
# via
|
||||
# sounddevice
|
||||
# soundfile
|
||||
@@ -46,7 +46,7 @@ diskcache==5.6.3
|
||||
# via -r requirements/requirements.in
|
||||
distro==1.9.0
|
||||
# via openai
|
||||
filelock==3.15.4
|
||||
filelock==3.16.1
|
||||
# via huggingface-hub
|
||||
flake8==7.1.1
|
||||
# via -r requirements/requirements.in
|
||||
@@ -54,7 +54,7 @@ frozenlist==1.4.1
|
||||
# via
|
||||
# aiohttp
|
||||
# aiosignal
|
||||
fsspec==2024.6.1
|
||||
fsspec==2024.9.0
|
||||
# via huggingface-hub
|
||||
gitdb==4.0.11
|
||||
# via gitpython
|
||||
@@ -68,9 +68,9 @@ httpcore==1.0.5
|
||||
# via httpx
|
||||
httpx==0.27.2
|
||||
# via openai
|
||||
huggingface-hub==0.24.6
|
||||
huggingface-hub==0.25.0
|
||||
# via tokenizers
|
||||
idna==3.8
|
||||
idna==3.10
|
||||
# via
|
||||
# anyio
|
||||
# httpx
|
||||
@@ -80,7 +80,7 @@ importlib-metadata==7.2.1
|
||||
# via
|
||||
# -r requirements/requirements.in
|
||||
# litellm
|
||||
importlib-resources==6.4.4
|
||||
importlib-resources==6.4.5
|
||||
# via -r requirements/requirements.in
|
||||
jinja2==3.1.4
|
||||
# via litellm
|
||||
@@ -94,7 +94,7 @@ jsonschema==4.23.0
|
||||
# litellm
|
||||
jsonschema-specifications==2023.12.1
|
||||
# via jsonschema
|
||||
litellm==1.44.7
|
||||
litellm==1.47.0
|
||||
# via -r requirements/requirements.in
|
||||
markdown-it-py==3.0.0
|
||||
# via rich
|
||||
@@ -104,7 +104,7 @@ mccabe==0.7.0
|
||||
# via flake8
|
||||
mdurl==0.1.2
|
||||
# via markdown-it-py
|
||||
multidict==6.0.5
|
||||
multidict==6.1.0
|
||||
# via
|
||||
# aiohttp
|
||||
# yarl
|
||||
@@ -114,13 +114,12 @@ numpy==1.26.4
|
||||
# via
|
||||
# -r requirements/requirements.in
|
||||
# scipy
|
||||
openai==1.42.0
|
||||
openai==1.47.0
|
||||
# via litellm
|
||||
packaging==24.1
|
||||
# via
|
||||
# -r requirements/requirements.in
|
||||
# huggingface-hub
|
||||
# setuptools-scm
|
||||
pathspec==0.12.1
|
||||
# via
|
||||
# -r requirements/requirements.in
|
||||
@@ -131,17 +130,19 @@ pillow==10.4.0
|
||||
# via -r requirements/requirements.in
|
||||
prompt-toolkit==3.0.47
|
||||
# via -r requirements/requirements.in
|
||||
psutil==6.0.0
|
||||
# via -r requirements/requirements.in
|
||||
ptyprocess==0.7.0
|
||||
# via pexpect
|
||||
pycodestyle==2.12.1
|
||||
# via flake8
|
||||
pycparser==2.22
|
||||
# via cffi
|
||||
pydantic==2.8.2
|
||||
pydantic==2.9.2
|
||||
# via
|
||||
# litellm
|
||||
# openai
|
||||
pydantic-core==2.20.1
|
||||
pydantic-core==2.23.4
|
||||
# via pydantic
|
||||
pyflakes==3.2.0
|
||||
# via flake8
|
||||
@@ -161,14 +162,14 @@ referencing==0.35.1
|
||||
# via
|
||||
# jsonschema
|
||||
# jsonschema-specifications
|
||||
regex==2024.7.24
|
||||
regex==2024.9.11
|
||||
# via tiktoken
|
||||
requests==2.32.3
|
||||
# via
|
||||
# huggingface-hub
|
||||
# litellm
|
||||
# tiktoken
|
||||
rich==13.8.0
|
||||
rich==13.8.1
|
||||
# via -r requirements/requirements.in
|
||||
rpds-py==0.20.0
|
||||
# via
|
||||
@@ -176,8 +177,6 @@ rpds-py==0.20.0
|
||||
# referencing
|
||||
scipy==1.13.1
|
||||
# via -r requirements/requirements.in
|
||||
setuptools-scm==8.1.0
|
||||
# via -r requirements/requirements.in
|
||||
smmap==5.0.1
|
||||
# via gitdb
|
||||
sniffio==1.3.1
|
||||
@@ -213,14 +212,11 @@ typing-extensions==4.12.2
|
||||
# openai
|
||||
# pydantic
|
||||
# pydantic-core
|
||||
urllib3==2.2.2
|
||||
urllib3==2.2.3
|
||||
# via requests
|
||||
wcwidth==0.2.13
|
||||
# via prompt-toolkit
|
||||
yarl==1.9.4
|
||||
yarl==1.11.1
|
||||
# via aiohttp
|
||||
zipp==3.20.1
|
||||
zipp==3.20.2
|
||||
# via importlib-metadata
|
||||
|
||||
# The following packages are considered to be unsafe in a requirements file:
|
||||
# setuptools
|
||||
|
||||
@@ -15,7 +15,7 @@ blinker==1.8.2
|
||||
# via streamlit
|
||||
cachetools==5.5.0
|
||||
# via streamlit
|
||||
certifi==2024.7.4
|
||||
certifi==2024.8.30
|
||||
# via
|
||||
# -c requirements/../requirements.txt
|
||||
# requests
|
||||
@@ -35,7 +35,7 @@ gitpython==3.1.43
|
||||
# via
|
||||
# -c requirements/../requirements.txt
|
||||
# streamlit
|
||||
idna==3.8
|
||||
idna==3.10
|
||||
# via
|
||||
# -c requirements/../requirements.txt
|
||||
# requests
|
||||
@@ -64,7 +64,7 @@ mdurl==0.1.2
|
||||
# via
|
||||
# -c requirements/../requirements.txt
|
||||
# markdown-it-py
|
||||
narwhals==1.5.5
|
||||
narwhals==1.8.2
|
||||
# via altair
|
||||
numpy==1.26.4
|
||||
# via
|
||||
@@ -78,13 +78,13 @@ packaging==24.1
|
||||
# -c requirements/../requirements.txt
|
||||
# altair
|
||||
# streamlit
|
||||
pandas==2.2.2
|
||||
pandas==2.2.3
|
||||
# via streamlit
|
||||
pillow==10.4.0
|
||||
# via
|
||||
# -c requirements/../requirements.txt
|
||||
# streamlit
|
||||
protobuf==5.27.4
|
||||
protobuf==5.28.2
|
||||
# via streamlit
|
||||
pyarrow==17.0.0
|
||||
# via streamlit
|
||||
@@ -96,7 +96,7 @@ pygments==2.18.0
|
||||
# rich
|
||||
python-dateutil==2.9.0.post0
|
||||
# via pandas
|
||||
pytz==2024.1
|
||||
pytz==2024.2
|
||||
# via pandas
|
||||
referencing==0.35.1
|
||||
# via
|
||||
@@ -107,7 +107,7 @@ requests==2.32.3
|
||||
# via
|
||||
# -c requirements/../requirements.txt
|
||||
# streamlit
|
||||
rich==13.8.0
|
||||
rich==13.8.1
|
||||
# via
|
||||
# -c requirements/../requirements.txt
|
||||
# streamlit
|
||||
@@ -137,7 +137,7 @@ typing-extensions==4.12.2
|
||||
# streamlit
|
||||
tzdata==2024.1
|
||||
# via pandas
|
||||
urllib3==2.2.2
|
||||
urllib3==2.2.3
|
||||
# via
|
||||
# -c requirements/../requirements.txt
|
||||
# requests
|
||||
|
||||
@@ -12,3 +12,4 @@ imgcat
|
||||
pre-commit
|
||||
cogapp
|
||||
semver
|
||||
codespell
|
||||
|
||||
@@ -8,9 +8,9 @@ alabaster==0.7.16
|
||||
# via sphinx
|
||||
babel==2.16.0
|
||||
# via sphinx
|
||||
build==1.2.1
|
||||
build==1.2.2
|
||||
# via pip-tools
|
||||
certifi==2024.7.4
|
||||
certifi==2024.8.30
|
||||
# via
|
||||
# -c requirements/../requirements.txt
|
||||
# requests
|
||||
@@ -25,6 +25,8 @@ click==8.1.7
|
||||
# -c requirements/../requirements.txt
|
||||
# pip-tools
|
||||
# typer
|
||||
codespell==2.3.0
|
||||
# via -r requirements/requirements-dev.in
|
||||
cogapp==3.4.1
|
||||
# via -r requirements/requirements-dev.in
|
||||
contourpy==1.3.0
|
||||
@@ -41,15 +43,15 @@ docutils==0.20.1
|
||||
# via
|
||||
# sphinx
|
||||
# sphinx-rtd-theme
|
||||
filelock==3.15.4
|
||||
filelock==3.16.1
|
||||
# via
|
||||
# -c requirements/../requirements.txt
|
||||
# virtualenv
|
||||
fonttools==4.53.1
|
||||
# via matplotlib
|
||||
identify==2.6.0
|
||||
identify==2.6.1
|
||||
# via pre-commit
|
||||
idna==3.8
|
||||
idna==3.10
|
||||
# via
|
||||
# -c requirements/../requirements.txt
|
||||
# requests
|
||||
@@ -63,7 +65,7 @@ jinja2==3.1.4
|
||||
# via
|
||||
# -c requirements/../requirements.txt
|
||||
# sphinx
|
||||
kiwisolver==1.4.5
|
||||
kiwisolver==1.4.7
|
||||
# via matplotlib
|
||||
lox==0.12.0
|
||||
# via -r requirements/requirements-dev.in
|
||||
@@ -98,7 +100,7 @@ packaging==24.1
|
||||
# matplotlib
|
||||
# pytest
|
||||
# sphinx
|
||||
pandas==2.2.2
|
||||
pandas==2.2.3
|
||||
# via -r requirements/requirements-dev.in
|
||||
pathos==0.3.2
|
||||
# via lox
|
||||
@@ -108,7 +110,7 @@ pillow==10.4.0
|
||||
# matplotlib
|
||||
pip-tools==7.4.1
|
||||
# via -r requirements/requirements-dev.in
|
||||
platformdirs==4.2.2
|
||||
platformdirs==4.3.6
|
||||
# via virtualenv
|
||||
pluggy==1.5.0
|
||||
# via pytest
|
||||
@@ -129,13 +131,13 @@ pyproject-hooks==1.1.0
|
||||
# via
|
||||
# build
|
||||
# pip-tools
|
||||
pytest==8.3.2
|
||||
pytest==8.3.3
|
||||
# via -r requirements/requirements-dev.in
|
||||
python-dateutil==2.9.0.post0
|
||||
# via
|
||||
# matplotlib
|
||||
# pandas
|
||||
pytz==2024.1
|
||||
pytz==2024.2
|
||||
# via pandas
|
||||
pyyaml==6.0.2
|
||||
# via
|
||||
@@ -145,7 +147,7 @@ requests==2.32.3
|
||||
# via
|
||||
# -c requirements/../requirements.txt
|
||||
# sphinx
|
||||
rich==13.8.0
|
||||
rich==13.8.1
|
||||
# via
|
||||
# -c requirements/../requirements.txt
|
||||
# typer
|
||||
@@ -185,11 +187,11 @@ typing-extensions==4.12.2
|
||||
# typer
|
||||
tzdata==2024.1
|
||||
# via pandas
|
||||
urllib3==2.2.2
|
||||
urllib3==2.2.3
|
||||
# via
|
||||
# -c requirements/../requirements.txt
|
||||
# requests
|
||||
virtualenv==20.26.3
|
||||
virtualenv==20.26.5
|
||||
# via pre-commit
|
||||
wheel==0.44.0
|
||||
# via pip-tools
|
||||
|
||||
@@ -21,7 +21,7 @@ annotated-types==0.7.0
|
||||
# via
|
||||
# -c requirements/../requirements.txt
|
||||
# pydantic
|
||||
anyio==4.4.0
|
||||
anyio==4.6.0
|
||||
# via
|
||||
# -c requirements/../requirements.txt
|
||||
# httpx
|
||||
@@ -29,7 +29,7 @@ attrs==24.2.0
|
||||
# via
|
||||
# -c requirements/../requirements.txt
|
||||
# aiohttp
|
||||
certifi==2024.7.4
|
||||
certifi==2024.8.30
|
||||
# via
|
||||
# -c requirements/../requirements.txt
|
||||
# httpcore
|
||||
@@ -49,7 +49,7 @@ deprecated==1.2.14
|
||||
# via llama-index-core
|
||||
dirtyjson==1.0.8
|
||||
# via llama-index-core
|
||||
filelock==3.15.4
|
||||
filelock==3.16.1
|
||||
# via
|
||||
# -c requirements/../requirements.txt
|
||||
# huggingface-hub
|
||||
@@ -60,13 +60,13 @@ frozenlist==1.4.1
|
||||
# -c requirements/../requirements.txt
|
||||
# aiohttp
|
||||
# aiosignal
|
||||
fsspec==2024.6.1
|
||||
fsspec==2024.9.0
|
||||
# via
|
||||
# -c requirements/../requirements.txt
|
||||
# huggingface-hub
|
||||
# llama-index-core
|
||||
# torch
|
||||
greenlet==3.0.3
|
||||
greenlet==3.1.1
|
||||
# via sqlalchemy
|
||||
h11==0.14.0
|
||||
# via
|
||||
@@ -80,14 +80,14 @@ httpx==0.27.2
|
||||
# via
|
||||
# -c requirements/../requirements.txt
|
||||
# llama-index-core
|
||||
huggingface-hub[inference]==0.24.6
|
||||
huggingface-hub[inference]==0.25.0
|
||||
# via
|
||||
# -c requirements/../requirements.txt
|
||||
# llama-index-embeddings-huggingface
|
||||
# sentence-transformers
|
||||
# tokenizers
|
||||
# transformers
|
||||
idna==3.8
|
||||
idna==3.10
|
||||
# via
|
||||
# -c requirements/../requirements.txt
|
||||
# anyio
|
||||
@@ -102,7 +102,7 @@ joblib==1.4.2
|
||||
# via
|
||||
# nltk
|
||||
# scikit-learn
|
||||
llama-index-core==0.11.2
|
||||
llama-index-core==0.11.11
|
||||
# via
|
||||
# -r requirements/requirements-help.in
|
||||
# llama-index-embeddings-huggingface
|
||||
@@ -118,7 +118,7 @@ minijinja==2.2.0
|
||||
# via huggingface-hub
|
||||
mpmath==1.3.0
|
||||
# via sympy
|
||||
multidict==6.0.5
|
||||
multidict==6.1.0
|
||||
# via
|
||||
# -c requirements/../requirements.txt
|
||||
# aiohttp
|
||||
@@ -140,7 +140,6 @@ numpy==1.26.4
|
||||
# llama-index-core
|
||||
# scikit-learn
|
||||
# scipy
|
||||
# sentence-transformers
|
||||
# transformers
|
||||
packaging==24.1
|
||||
# via
|
||||
@@ -153,11 +152,11 @@ pillow==10.4.0
|
||||
# -c requirements/../requirements.txt
|
||||
# llama-index-core
|
||||
# sentence-transformers
|
||||
pydantic==2.8.2
|
||||
pydantic==2.9.2
|
||||
# via
|
||||
# -c requirements/../requirements.txt
|
||||
# llama-index-core
|
||||
pydantic-core==2.20.1
|
||||
pydantic-core==2.23.4
|
||||
# via
|
||||
# -c requirements/../requirements.txt
|
||||
# pydantic
|
||||
@@ -167,7 +166,7 @@ pyyaml==6.0.2
|
||||
# huggingface-hub
|
||||
# llama-index-core
|
||||
# transformers
|
||||
regex==2024.7.24
|
||||
regex==2024.9.11
|
||||
# via
|
||||
# -c requirements/../requirements.txt
|
||||
# nltk
|
||||
@@ -180,27 +179,27 @@ requests==2.32.3
|
||||
# llama-index-core
|
||||
# tiktoken
|
||||
# transformers
|
||||
safetensors==0.4.4
|
||||
safetensors==0.4.5
|
||||
# via transformers
|
||||
scikit-learn==1.5.1
|
||||
scikit-learn==1.5.2
|
||||
# via sentence-transformers
|
||||
scipy==1.13.1
|
||||
# via
|
||||
# -c requirements/../requirements.txt
|
||||
# scikit-learn
|
||||
# sentence-transformers
|
||||
sentence-transformers==3.0.1
|
||||
sentence-transformers==3.1.1
|
||||
# via llama-index-embeddings-huggingface
|
||||
sniffio==1.3.1
|
||||
# via
|
||||
# -c requirements/../requirements.txt
|
||||
# anyio
|
||||
# httpx
|
||||
sqlalchemy[asyncio]==2.0.32
|
||||
sqlalchemy[asyncio]==2.0.35
|
||||
# via
|
||||
# llama-index-core
|
||||
# sqlalchemy
|
||||
sympy==1.13.2
|
||||
sympy==1.13.3
|
||||
# via torch
|
||||
tenacity==8.5.0
|
||||
# via llama-index-core
|
||||
@@ -240,7 +239,7 @@ typing-inspect==0.9.0
|
||||
# via
|
||||
# dataclasses-json
|
||||
# llama-index-core
|
||||
urllib3==2.2.2
|
||||
urllib3==2.2.3
|
||||
# via
|
||||
# -c requirements/../requirements.txt
|
||||
# requests
|
||||
@@ -248,7 +247,7 @@ wrapt==1.16.0
|
||||
# via
|
||||
# deprecated
|
||||
# llama-index-core
|
||||
yarl==1.9.4
|
||||
yarl==1.11.1
|
||||
# via
|
||||
# -c requirements/../requirements.txt
|
||||
# aiohttp
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
#
|
||||
greenlet==3.0.3
|
||||
# via playwright
|
||||
playwright==1.46.0
|
||||
playwright==1.47.0
|
||||
# via -r requirements/requirements-playwright.in
|
||||
pyee==11.1.0
|
||||
pyee==12.0.0
|
||||
# via playwright
|
||||
typing-extensions==4.12.2
|
||||
# via
|
||||
|
||||
@@ -25,8 +25,9 @@ importlib_resources
|
||||
pyperclip
|
||||
pexpect
|
||||
json5
|
||||
psutil
|
||||
|
||||
# The proper depdendency is networkx[default], but this brings
|
||||
# The proper dependency is networkx[default], but this brings
|
||||
# in matplotlib and a bunch of other deps
|
||||
# https://github.com/networkx/networkx/blob/d7132daa8588f653eacac7a5bae1ee85a183fa43/pyproject.toml#L57
|
||||
# We really only need networkx itself and scipy for the repomap.
|
||||
|
||||
133
scripts/issues.py
Executable file
133
scripts/issues.py
Executable file
@@ -0,0 +1,133 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import re
|
||||
from collections import defaultdict
|
||||
from datetime import datetime
|
||||
|
||||
import requests
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# Load environment variables from .env file
|
||||
load_dotenv()
|
||||
|
||||
# GitHub API configuration
|
||||
GITHUB_API_URL = "https://api.github.com"
|
||||
REPO_OWNER = "paul-gauthier"
|
||||
REPO_NAME = "aider"
|
||||
TOKEN = os.getenv("GITHUB_TOKEN")
|
||||
|
||||
headers = {"Authorization": f"token {TOKEN}", "Accept": "application/vnd.github.v3+json"}
|
||||
|
||||
|
||||
def get_issues(state="open"):
|
||||
issues = []
|
||||
page = 1
|
||||
while True:
|
||||
response = requests.get(
|
||||
f"{GITHUB_API_URL}/repos/{REPO_OWNER}/{REPO_NAME}/issues",
|
||||
headers=headers,
|
||||
params={"state": state, "page": page, "per_page": 100},
|
||||
)
|
||||
response.raise_for_status()
|
||||
page_issues = response.json()
|
||||
if not page_issues:
|
||||
break
|
||||
issues.extend(page_issues)
|
||||
page += 1
|
||||
return issues
|
||||
|
||||
|
||||
def group_issues_by_subject(issues):
|
||||
grouped_issues = defaultdict(list)
|
||||
pattern = r"Uncaught .+ in .+ line \d+"
|
||||
for issue in issues:
|
||||
if re.search(pattern, issue["title"]):
|
||||
subject = issue["title"]
|
||||
grouped_issues[subject].append(issue)
|
||||
return grouped_issues
|
||||
|
||||
|
||||
def find_oldest_issue(subject, all_issues):
|
||||
oldest_issue = None
|
||||
oldest_date = datetime.now()
|
||||
|
||||
for issue in all_issues:
|
||||
if issue["title"] == subject:
|
||||
created_at = datetime.strptime(issue["created_at"], "%Y-%m-%dT%H:%M:%SZ")
|
||||
if created_at < oldest_date:
|
||||
oldest_date = created_at
|
||||
oldest_issue = issue
|
||||
|
||||
return oldest_issue
|
||||
|
||||
|
||||
def comment_and_close_duplicate(issue, oldest_issue):
|
||||
comment_url = (
|
||||
f"{GITHUB_API_URL}/repos/{REPO_OWNER}/{REPO_NAME}/issues/{issue['number']}/comments"
|
||||
)
|
||||
close_url = f"{GITHUB_API_URL}/repos/{REPO_OWNER}/{REPO_NAME}/issues/{issue['number']}"
|
||||
|
||||
comment_body = (
|
||||
f"This looks like a duplicate of #{oldest_issue['number']}, so I'm going to close it so"
|
||||
" discussion can happen there. Please let me know if you think it's actually a distinct"
|
||||
" issue."
|
||||
)
|
||||
|
||||
# Post comment
|
||||
response = requests.post(comment_url, headers=headers, json={"body": comment_body})
|
||||
response.raise_for_status()
|
||||
|
||||
# Close issue
|
||||
response = requests.patch(close_url, headers=headers, json={"state": "closed"})
|
||||
response.raise_for_status()
|
||||
|
||||
print(f" - Commented and closed issue #{issue['number']}")
|
||||
|
||||
|
||||
def main():
|
||||
if not TOKEN:
|
||||
print("Error: Missing GITHUB_TOKEN environment variable. Please check your .env file.")
|
||||
return
|
||||
|
||||
all_issues = get_issues("all")
|
||||
open_issues = [issue for issue in all_issues if issue["state"] == "open"]
|
||||
grouped_open_issues = group_issues_by_subject(open_issues)
|
||||
|
||||
for subject, issues in grouped_open_issues.items():
|
||||
oldest_issue = find_oldest_issue(subject, all_issues)
|
||||
if not oldest_issue:
|
||||
continue
|
||||
|
||||
related_issues = set(issue["number"] for issue in issues)
|
||||
related_issues.add(oldest_issue["number"])
|
||||
if len(related_issues) <= 1:
|
||||
continue
|
||||
|
||||
print(f"\nIssue: {subject}")
|
||||
print(f"Open issues: {len(issues)}")
|
||||
sorted_issues = sorted(issues, key=lambda x: x["number"], reverse=True)
|
||||
for issue in sorted_issues:
|
||||
print(f" - #{issue['number']}: {issue['comments']} comments {issue['html_url']}")
|
||||
|
||||
print(
|
||||
f"Oldest issue: #{oldest_issue['number']}: {oldest_issue['comments']} comments"
|
||||
f" {oldest_issue['html_url']} ({oldest_issue['state']})"
|
||||
)
|
||||
|
||||
# Confirmation prompt
|
||||
confirm = input("Do you want to comment and close duplicate issues? (y/n): ")
|
||||
if confirm.lower() != "y":
|
||||
print("Skipping this group of issues.")
|
||||
continue
|
||||
|
||||
# Comment and close duplicate issues
|
||||
for issue in issues:
|
||||
if issue["number"] != oldest_issue["number"]:
|
||||
comment_and_close_duplicate(issue, oldest_issue)
|
||||
|
||||
print(f"Oldest issue #{oldest_issue['number']} left open")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import argparse
|
||||
import datetime
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
@@ -150,6 +151,13 @@ def main():
|
||||
if not dry_run:
|
||||
subprocess.run(cmd, check=True)
|
||||
|
||||
# Remove aider/__version__.py if it exists
|
||||
version_file = "aider/__version__.py"
|
||||
if os.path.exists(version_file):
|
||||
print(f"Removing {version_file}")
|
||||
if not dry_run:
|
||||
os.remove(version_file)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -353,7 +353,7 @@ class TestCoder(unittest.TestCase):
|
||||
_, file1 = tempfile.mkstemp()
|
||||
|
||||
with open(file1, "wb") as f:
|
||||
f.write(b"this contains ``` backticks")
|
||||
f.write(b"this contains\n```\nbackticks")
|
||||
|
||||
files = [file1]
|
||||
|
||||
|
||||
@@ -213,9 +213,9 @@ aider/coder.py
|
||||
|
||||
aider/coder.py
|
||||
<<<<<<< SEARCH
|
||||
self.console.print("[red]Skipped commmit.")
|
||||
self.console.print("[red]Skipped commit.")
|
||||
=======
|
||||
self.io.tool_error("Skipped commmit.")
|
||||
self.io.tool_error("Skipped commit.")
|
||||
>>>>>>> REPLACE"""
|
||||
|
||||
# Should not raise a ValueError
|
||||
|
||||
@@ -46,12 +46,8 @@ class TestInputOutput(unittest.TestCase):
|
||||
autocompleter = AutoCompleter(root, rel_fnames, addable_rel_fnames, commands, "utf-8")
|
||||
self.assertEqual(autocompleter.words, set(rel_fnames))
|
||||
|
||||
@patch("aider.io.PromptSession")
|
||||
def test_get_input_is_a_directory_error(self, MockPromptSession):
|
||||
# Mock the PromptSession to simulate user input
|
||||
mock_session = MockPromptSession.return_value
|
||||
mock_session.prompt.return_value = "test input"
|
||||
|
||||
@patch("builtins.input", return_value="test input")
|
||||
def test_get_input_is_a_directory_error(self, mock_input):
|
||||
io = InputOutput(pretty=False) # Windows tests throw UnicodeDecodeError
|
||||
root = "/"
|
||||
rel_fnames = ["existing_file.txt"]
|
||||
@@ -62,105 +58,106 @@ class TestInputOutput(unittest.TestCase):
|
||||
with patch("aider.io.open", side_effect=IsADirectoryError):
|
||||
result = io.get_input(root, rel_fnames, addable_rel_fnames, commands)
|
||||
self.assertEqual(result, "test input")
|
||||
mock_input.assert_called_once()
|
||||
|
||||
@patch("aider.io.prompt")
|
||||
def test_confirm_ask_explicit_yes_required(self, mock_prompt):
|
||||
@patch("builtins.input")
|
||||
def test_confirm_ask_explicit_yes_required(self, mock_input):
|
||||
io = InputOutput(pretty=False)
|
||||
|
||||
# Test case 1: explicit_yes_required=True, self.yes=True
|
||||
io.yes = True
|
||||
result = io.confirm_ask("Are you sure?", explicit_yes_required=True)
|
||||
self.assertFalse(result)
|
||||
mock_prompt.assert_not_called()
|
||||
mock_input.assert_not_called()
|
||||
|
||||
# Test case 2: explicit_yes_required=True, self.yes=False
|
||||
io.yes = False
|
||||
result = io.confirm_ask("Are you sure?", explicit_yes_required=True)
|
||||
self.assertFalse(result)
|
||||
mock_prompt.assert_not_called()
|
||||
mock_input.assert_not_called()
|
||||
|
||||
# Test case 3: explicit_yes_required=True, user input required
|
||||
io.yes = None
|
||||
mock_prompt.return_value = "y"
|
||||
mock_input.return_value = "y"
|
||||
result = io.confirm_ask("Are you sure?", explicit_yes_required=True)
|
||||
self.assertTrue(result)
|
||||
mock_prompt.assert_called_once()
|
||||
mock_input.assert_called_once()
|
||||
|
||||
# Reset mock_prompt
|
||||
mock_prompt.reset_mock()
|
||||
# Reset mock_input
|
||||
mock_input.reset_mock()
|
||||
|
||||
# Test case 4: explicit_yes_required=False, self.yes=True
|
||||
io.yes = True
|
||||
result = io.confirm_ask("Are you sure?", explicit_yes_required=False)
|
||||
self.assertTrue(result)
|
||||
mock_prompt.assert_not_called()
|
||||
mock_input.assert_not_called()
|
||||
|
||||
@patch("aider.io.prompt")
|
||||
def test_confirm_ask_with_group(self, mock_prompt):
|
||||
@patch("builtins.input")
|
||||
def test_confirm_ask_with_group(self, mock_input):
|
||||
io = InputOutput(pretty=False)
|
||||
group = ConfirmGroup()
|
||||
|
||||
# Test case 1: No group preference, user selects 'All'
|
||||
mock_prompt.return_value = "a"
|
||||
mock_input.return_value = "a"
|
||||
result = io.confirm_ask("Are you sure?", group=group)
|
||||
self.assertTrue(result)
|
||||
self.assertEqual(group.preference, "all")
|
||||
mock_prompt.assert_called_once()
|
||||
mock_prompt.reset_mock()
|
||||
mock_input.assert_called_once()
|
||||
mock_input.reset_mock()
|
||||
|
||||
# Test case 2: Group preference is 'All', should not prompt
|
||||
result = io.confirm_ask("Are you sure?", group=group)
|
||||
self.assertTrue(result)
|
||||
mock_prompt.assert_not_called()
|
||||
mock_input.assert_not_called()
|
||||
|
||||
# Test case 3: No group preference, user selects 'Skip all'
|
||||
group.preference = None
|
||||
mock_prompt.return_value = "s"
|
||||
mock_input.return_value = "s"
|
||||
result = io.confirm_ask("Are you sure?", group=group)
|
||||
self.assertFalse(result)
|
||||
self.assertEqual(group.preference, "skip")
|
||||
mock_prompt.assert_called_once()
|
||||
mock_prompt.reset_mock()
|
||||
mock_input.assert_called_once()
|
||||
mock_input.reset_mock()
|
||||
|
||||
# Test case 4: Group preference is 'Skip all', should not prompt
|
||||
result = io.confirm_ask("Are you sure?", group=group)
|
||||
self.assertFalse(result)
|
||||
mock_prompt.assert_not_called()
|
||||
mock_input.assert_not_called()
|
||||
|
||||
# Test case 5: explicit_yes_required=True, should not offer 'All' option
|
||||
group.preference = None
|
||||
mock_prompt.return_value = "y"
|
||||
mock_input.return_value = "y"
|
||||
result = io.confirm_ask("Are you sure?", group=group, explicit_yes_required=True)
|
||||
self.assertTrue(result)
|
||||
self.assertIsNone(group.preference)
|
||||
mock_prompt.assert_called_once()
|
||||
self.assertNotIn("(A)ll", mock_prompt.call_args[0][0])
|
||||
mock_prompt.reset_mock()
|
||||
mock_input.assert_called_once()
|
||||
self.assertNotIn("(A)ll", mock_input.call_args[0][0])
|
||||
mock_input.reset_mock()
|
||||
|
||||
@patch("aider.io.prompt")
|
||||
def test_confirm_ask_yes_no(self, mock_prompt):
|
||||
@patch("builtins.input")
|
||||
def test_confirm_ask_yes_no(self, mock_input):
|
||||
io = InputOutput(pretty=False)
|
||||
|
||||
# Test case 1: User selects 'Yes'
|
||||
mock_prompt.return_value = "y"
|
||||
mock_input.return_value = "y"
|
||||
result = io.confirm_ask("Are you sure?")
|
||||
self.assertTrue(result)
|
||||
mock_prompt.assert_called_once()
|
||||
mock_prompt.reset_mock()
|
||||
mock_input.assert_called_once()
|
||||
mock_input.reset_mock()
|
||||
|
||||
# Test case 2: User selects 'No'
|
||||
mock_prompt.return_value = "n"
|
||||
mock_input.return_value = "n"
|
||||
result = io.confirm_ask("Are you sure?")
|
||||
self.assertFalse(result)
|
||||
mock_prompt.assert_called_once()
|
||||
mock_prompt.reset_mock()
|
||||
mock_input.assert_called_once()
|
||||
mock_input.reset_mock()
|
||||
|
||||
# Test case 3: Empty input (default to Yes)
|
||||
mock_prompt.return_value = ""
|
||||
mock_input.return_value = ""
|
||||
result = io.confirm_ask("Are you sure?")
|
||||
self.assertTrue(result)
|
||||
mock_prompt.assert_called_once()
|
||||
mock_prompt.reset_mock()
|
||||
mock_input.assert_called_once()
|
||||
mock_input.reset_mock()
|
||||
|
||||
def test_get_command_completions(self):
|
||||
root = ""
|
||||
|
||||
52
tests/basic/test_linter.py
Normal file
52
tests/basic/test_linter.py
Normal file
@@ -0,0 +1,52 @@
|
||||
import unittest
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from aider.dump import dump # noqa
|
||||
from aider.linter import Linter
|
||||
|
||||
|
||||
class TestLinter(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.linter = Linter(encoding="utf-8", root="/test/root")
|
||||
|
||||
def test_init(self):
|
||||
self.assertEqual(self.linter.encoding, "utf-8")
|
||||
self.assertEqual(self.linter.root, "/test/root")
|
||||
self.assertIn("python", self.linter.languages)
|
||||
|
||||
def test_set_linter(self):
|
||||
self.linter.set_linter("javascript", "eslint")
|
||||
self.assertEqual(self.linter.languages["javascript"], "eslint")
|
||||
|
||||
def test_get_rel_fname(self):
|
||||
import os
|
||||
|
||||
self.assertEqual(self.linter.get_rel_fname("/test/root/file.py"), "file.py")
|
||||
expected_path = os.path.normpath("../../other/path/file.py")
|
||||
actual_path = os.path.normpath(self.linter.get_rel_fname("/other/path/file.py"))
|
||||
self.assertEqual(actual_path, expected_path)
|
||||
|
||||
@patch("subprocess.Popen")
|
||||
def test_run_cmd(self, mock_popen):
|
||||
mock_process = MagicMock()
|
||||
mock_process.returncode = 0
|
||||
mock_process.communicate.return_value = ("", None)
|
||||
mock_popen.return_value = mock_process
|
||||
|
||||
result = self.linter.run_cmd("test_cmd", "test_file.py", "code")
|
||||
self.assertIsNone(result)
|
||||
|
||||
@patch("subprocess.Popen")
|
||||
def test_run_cmd_with_errors(self, mock_popen):
|
||||
mock_process = MagicMock()
|
||||
mock_process.returncode = 1
|
||||
mock_process.communicate.return_value = ("Error message", None)
|
||||
mock_popen.return_value = mock_process
|
||||
|
||||
result = self.linter.run_cmd("test_cmd", "test_file.py", "code")
|
||||
self.assertIsNotNone(result)
|
||||
self.assertIn("Error message", result.text)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -29,6 +29,8 @@ class TestMain(TestCase):
|
||||
# Fake home directory prevents tests from using the real ~/.aider.conf.yml file:
|
||||
self.homedir_obj = IgnorantTemporaryDirectory()
|
||||
os.environ["HOME"] = self.homedir_obj.name
|
||||
self.input_patcher = patch("builtins.input", return_value=None)
|
||||
self.mock_input = self.input_patcher.start()
|
||||
|
||||
def tearDown(self):
|
||||
os.chdir(self.original_cwd)
|
||||
@@ -36,24 +38,25 @@ class TestMain(TestCase):
|
||||
self.homedir_obj.cleanup()
|
||||
os.environ.clear()
|
||||
os.environ.update(self.original_env)
|
||||
self.input_patcher.stop()
|
||||
|
||||
def test_main_with_empty_dir_no_files_on_command(self):
|
||||
main(["--no-git"], input=DummyInput(), output=DummyOutput())
|
||||
main(["--no-git", "--exit"], input=DummyInput(), output=DummyOutput())
|
||||
|
||||
def test_main_with_emptqy_dir_new_file(self):
|
||||
main(["foo.txt", "--yes", "--no-git"], input=DummyInput(), output=DummyOutput())
|
||||
main(["foo.txt", "--yes", "--no-git", "--exit"], input=DummyInput(), output=DummyOutput())
|
||||
self.assertTrue(os.path.exists("foo.txt"))
|
||||
|
||||
@patch("aider.repo.GitRepo.get_commit_message", return_value="mock commit message")
|
||||
def test_main_with_empty_git_dir_new_file(self, _):
|
||||
make_repo()
|
||||
main(["--yes", "foo.txt"], input=DummyInput(), output=DummyOutput())
|
||||
main(["--yes", "foo.txt", "--exit"], input=DummyInput(), output=DummyOutput())
|
||||
self.assertTrue(os.path.exists("foo.txt"))
|
||||
|
||||
@patch("aider.repo.GitRepo.get_commit_message", return_value="mock commit message")
|
||||
def test_main_with_empty_git_dir_new_files(self, _):
|
||||
make_repo()
|
||||
main(["--yes", "foo.txt", "bar.txt"], input=DummyInput(), output=DummyOutput())
|
||||
main(["--yes", "foo.txt", "bar.txt", "--exit"], input=DummyInput(), output=DummyOutput())
|
||||
self.assertTrue(os.path.exists("foo.txt"))
|
||||
self.assertTrue(os.path.exists("bar.txt"))
|
||||
|
||||
@@ -70,7 +73,7 @@ class TestMain(TestCase):
|
||||
subdir.mkdir()
|
||||
make_repo(str(subdir))
|
||||
main(
|
||||
["--yes", str(subdir / "foo.txt"), str(subdir / "bar.txt")],
|
||||
["--yes", str(subdir / "foo.txt"), str(subdir / "bar.txt"), "--exit"],
|
||||
input=DummyInput(),
|
||||
output=DummyOutput(),
|
||||
)
|
||||
@@ -104,7 +107,7 @@ class TestMain(TestCase):
|
||||
# This will throw a git error on windows if get_tracked_files doesn't
|
||||
# properly convert git/posix/paths to git\posix\paths.
|
||||
# Because aider will try and `git add` a file that's already in the repo.
|
||||
main(["--yes", str(fname)], input=DummyInput(), output=DummyOutput())
|
||||
main(["--yes", str(fname), "--exit"], input=DummyInput(), output=DummyOutput())
|
||||
|
||||
def test_setup_git(self):
|
||||
io = InputOutput(pretty=False, yes=True)
|
||||
@@ -269,23 +272,25 @@ class TestMain(TestCase):
|
||||
self.assertEqual(args[1], None)
|
||||
|
||||
def test_dark_mode_sets_code_theme(self):
|
||||
# Mock Coder.create to capture the configuration
|
||||
with patch("aider.coders.Coder.create") as MockCoder:
|
||||
main(["--dark-mode", "--no-git"], input=DummyInput(), output=DummyOutput())
|
||||
# Ensure Coder.create was called
|
||||
MockCoder.assert_called_once()
|
||||
# Mock InputOutput to capture the configuration
|
||||
with patch("aider.main.InputOutput") as MockInputOutput:
|
||||
MockInputOutput.return_value.get_input.return_value = None
|
||||
main(["--dark-mode", "--no-git", "--exit"], input=DummyInput(), output=DummyOutput())
|
||||
# Ensure InputOutput was called
|
||||
MockInputOutput.assert_called_once()
|
||||
# Check if the code_theme setting is for dark mode
|
||||
_, kwargs = MockCoder.call_args
|
||||
_, kwargs = MockInputOutput.call_args
|
||||
self.assertEqual(kwargs["code_theme"], "monokai")
|
||||
|
||||
def test_light_mode_sets_code_theme(self):
|
||||
# Mock Coder.create to capture the configuration
|
||||
with patch("aider.coders.Coder.create") as MockCoder:
|
||||
main(["--light-mode", "--no-git"], input=DummyInput(), output=DummyOutput())
|
||||
# Ensure Coder.create was called
|
||||
MockCoder.assert_called_once()
|
||||
# Mock InputOutput to capture the configuration
|
||||
with patch("aider.main.InputOutput") as MockInputOutput:
|
||||
MockInputOutput.return_value.get_input.return_value = None
|
||||
main(["--light-mode", "--no-git", "--exit"], input=DummyInput(), output=DummyOutput())
|
||||
# Ensure InputOutput was called
|
||||
MockInputOutput.assert_called_once()
|
||||
# Check if the code_theme setting is for light mode
|
||||
_, kwargs = MockCoder.call_args
|
||||
_, kwargs = MockInputOutput.call_args
|
||||
self.assertEqual(kwargs["code_theme"], "default")
|
||||
|
||||
def create_env_file(self, file_name, content):
|
||||
@@ -295,25 +300,29 @@ class TestMain(TestCase):
|
||||
|
||||
def test_env_file_flag_sets_automatic_variable(self):
|
||||
env_file_path = self.create_env_file(".env.test", "AIDER_DARK_MODE=True")
|
||||
with patch("aider.coders.Coder.create") as MockCoder:
|
||||
with patch("aider.main.InputOutput") as MockInputOutput:
|
||||
MockInputOutput.return_value.get_input.return_value = None
|
||||
MockInputOutput.return_value.get_input.confirm_ask = True
|
||||
main(
|
||||
["--env-file", str(env_file_path), "--no-git"],
|
||||
["--env-file", str(env_file_path), "--no-git", "--exit"],
|
||||
input=DummyInput(),
|
||||
output=DummyOutput(),
|
||||
)
|
||||
MockCoder.assert_called_once()
|
||||
MockInputOutput.assert_called_once()
|
||||
# Check if the color settings are for dark mode
|
||||
_, kwargs = MockCoder.call_args
|
||||
_, kwargs = MockInputOutput.call_args
|
||||
self.assertEqual(kwargs["code_theme"], "monokai")
|
||||
|
||||
def test_default_env_file_sets_automatic_variable(self):
|
||||
self.create_env_file(".env", "AIDER_DARK_MODE=True")
|
||||
with patch("aider.coders.Coder.create") as MockCoder:
|
||||
main(["--no-git"], input=DummyInput(), output=DummyOutput())
|
||||
# Ensure Coder.create was called
|
||||
MockCoder.assert_called_once()
|
||||
with patch("aider.main.InputOutput") as MockInputOutput:
|
||||
MockInputOutput.return_value.get_input.return_value = None
|
||||
MockInputOutput.return_value.get_input.confirm_ask = True
|
||||
main(["--no-git", "--exit"], input=DummyInput(), output=DummyOutput())
|
||||
# Ensure InputOutput was called
|
||||
MockInputOutput.assert_called_once()
|
||||
# Check if the color settings are for dark mode
|
||||
_, kwargs = MockCoder.call_args
|
||||
_, kwargs = MockInputOutput.call_args
|
||||
self.assertEqual(kwargs["code_theme"], "monokai")
|
||||
|
||||
def test_false_vals_in_env_file(self):
|
||||
@@ -368,7 +377,7 @@ class TestMain(TestCase):
|
||||
def test_verbose_mode_lists_env_vars(self):
|
||||
self.create_env_file(".env", "AIDER_DARK_MODE=on")
|
||||
with patch("sys.stdout", new_callable=StringIO) as mock_stdout:
|
||||
main(["--no-git", "--verbose"], input=DummyInput(), output=DummyOutput())
|
||||
main(["--no-git", "--verbose", "--exit"], input=DummyInput(), output=DummyOutput())
|
||||
output = mock_stdout.getvalue()
|
||||
relevant_output = "\n".join(
|
||||
line
|
||||
@@ -620,6 +629,17 @@ class TestMain(TestCase):
|
||||
)
|
||||
self.assertTrue(coder.suggest_shell_commands)
|
||||
|
||||
def test_chat_language_spanish(self):
|
||||
with GitTemporaryDirectory():
|
||||
coder = main(
|
||||
["--chat-language", "Spanish", "--exit", "--yes"],
|
||||
input=DummyInput(),
|
||||
output=DummyOutput(),
|
||||
return_coder=True,
|
||||
)
|
||||
system_info = coder.get_platform_info()
|
||||
self.assertIn("Spanish", system_info)
|
||||
|
||||
@patch("git.Repo.init")
|
||||
def test_main_exit_with_git_command_not_found(self, mock_git_init):
|
||||
mock_git_init.side_effect = git.exc.GitCommandNotFound("git", "Command 'git' not found")
|
||||
|
||||
Reference in New Issue
Block a user