mirror of
https://github.com/Aider-AI/aider
synced 2026-04-26 01:25:17 +02:00
Compare commits
210 Commits
v0.63.3.de
...
v0.64.1.de
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
51b181d5fb | ||
|
|
2785b0a857 | ||
|
|
45a113ff9e | ||
|
|
cee59c2ca3 | ||
|
|
5cb9b242e2 | ||
|
|
1ed48de928 | ||
|
|
c4e4bc71ed | ||
|
|
ed0763706b | ||
|
|
1c79d517fc | ||
|
|
1a7a2f3088 | ||
|
|
4199789786 | ||
|
|
c9b0941d1f | ||
|
|
3d544136d2 | ||
|
|
8448eff1eb | ||
|
|
a3dde4599a | ||
|
|
3d7440c673 | ||
|
|
8f41006eba | ||
|
|
7d1379fe9f | ||
|
|
ced4f9f0d9 | ||
|
|
7fba332f58 | ||
|
|
8eda09533d | ||
|
|
6c42ee4edf | ||
|
|
3053595bfe | ||
|
|
6cf78d1a3f | ||
|
|
6c0ee9d917 | ||
|
|
50051dbfd5 | ||
|
|
30a8c5e12e | ||
|
|
4498549783 | ||
|
|
2ce3fedbfc | ||
|
|
8e10be665c | ||
|
|
80636cb8aa | ||
|
|
1b893da07d | ||
|
|
2f8aa3471b | ||
|
|
92a6957f0b | ||
|
|
d7248b11e5 | ||
|
|
6f4ed00105 | ||
|
|
347b299bbc | ||
|
|
614d297f22 | ||
|
|
59d0fe00c3 | ||
|
|
d6ebdff28f | ||
|
|
0ec16d0eab | ||
|
|
3906894fde | ||
|
|
a43772b21d | ||
|
|
cd81c2619b | ||
|
|
5abadc31a3 | ||
|
|
87654b698b | ||
|
|
2a1d2ef294 | ||
|
|
2a387707ef | ||
|
|
ce68062290 | ||
|
|
1b9073b085 | ||
|
|
e94961a14f | ||
|
|
d4e77b3be4 | ||
|
|
b96b36d5ea | ||
|
|
72d559a92c | ||
|
|
9a7bdcb6db | ||
|
|
2e4cf48e7e | ||
|
|
b78f8abeb4 | ||
|
|
7aa4e44317 | ||
|
|
2619b92131 | ||
|
|
28be59582f | ||
|
|
f96cc03587 | ||
|
|
cbd35b0e87 | ||
|
|
443acbe4b5 | ||
|
|
1f0d26e8c7 | ||
|
|
8302e9d0dd | ||
|
|
c797af020a | ||
|
|
1c85afa320 | ||
|
|
eb5317f8e5 | ||
|
|
8b860615b8 | ||
|
|
c15ac341e2 | ||
|
|
c2c7ee1047 | ||
|
|
72c46ccec6 | ||
|
|
dd3bfaee01 | ||
|
|
03206ad90e | ||
|
|
2e00307190 | ||
|
|
b3e29ab20e | ||
|
|
5504ac535b | ||
|
|
4b3dd7f4ea | ||
|
|
8edf9540d5 | ||
|
|
1c62ecd1b5 | ||
|
|
7cf3d9f3ce | ||
|
|
9b5a703307 | ||
|
|
370993cbed | ||
|
|
ddc538cdfa | ||
|
|
062dc43c87 | ||
|
|
7d9b986c04 | ||
|
|
bd2b9a12ed | ||
|
|
2b55707738 | ||
|
|
093540507e | ||
|
|
8f1dcfda07 | ||
|
|
16b319174b | ||
|
|
35115f5707 | ||
|
|
e9e51db9c7 | ||
|
|
ec39f018e2 | ||
|
|
59f4a3bcc7 | ||
|
|
1a8949eea3 | ||
|
|
fa85bdceed | ||
|
|
6b703244ec | ||
|
|
1a1cb0d3f1 | ||
|
|
95c9863d0a | ||
|
|
82187f6a71 | ||
|
|
75f52a1324 | ||
|
|
6e076a40a9 | ||
|
|
ded60036cb | ||
|
|
539a6cde63 | ||
|
|
3a28e74d89 | ||
|
|
c93f3faed9 | ||
|
|
1aaa3d9279 | ||
|
|
a06a9ed7d8 | ||
|
|
18a88596a6 | ||
|
|
2ac077603b | ||
|
|
3bb8b163b8 | ||
|
|
aac45097ca | ||
|
|
788956e86d | ||
|
|
e917424f5d | ||
|
|
1f6a5d04d9 | ||
|
|
dba844c7f9 | ||
|
|
09c11ef8ad | ||
|
|
ff21669bb5 | ||
|
|
a059ca2537 | ||
|
|
f4531b9434 | ||
|
|
05b350ac4b | ||
|
|
cfba315a85 | ||
|
|
12188b6684 | ||
|
|
725b2fc16f | ||
|
|
90a28e31e8 | ||
|
|
c057b00e08 | ||
|
|
b0c0104ba3 | ||
|
|
855b184e91 | ||
|
|
bc88242dc0 | ||
|
|
6357cd623f | ||
|
|
d3e7d20e30 | ||
|
|
7b568c2df3 | ||
|
|
2bff0522e8 | ||
|
|
77e180171c | ||
|
|
1e8fc97ba4 | ||
|
|
a799851832 | ||
|
|
2c81105bfc | ||
|
|
bf99ac56a0 | ||
|
|
8bfb47948a | ||
|
|
b8c41198a3 | ||
|
|
fe138ac05b | ||
|
|
bed62fdcb5 | ||
|
|
f068df0297 | ||
|
|
6a05e34d20 | ||
|
|
8b69b9c6a4 | ||
|
|
10192296fe | ||
|
|
7b98db2f7d | ||
|
|
81696c2e7a | ||
|
|
16a4f823bd | ||
|
|
39bbfc56a4 | ||
|
|
308c49b2d8 | ||
|
|
53e46a9251 | ||
|
|
6075b3dc33 | ||
|
|
860a828973 | ||
|
|
033eaa36c6 | ||
|
|
b3566f5449 | ||
|
|
f1306d3301 | ||
|
|
cc18441435 | ||
|
|
7e787d93e6 | ||
|
|
b08f444e74 | ||
|
|
09c1acdbe2 | ||
|
|
7a4a956eff | ||
|
|
aabbf5a72f | ||
|
|
5ed44bb174 | ||
|
|
92cf2cbd47 | ||
|
|
34aff6c786 | ||
|
|
11f10e586a | ||
|
|
a31feae2bd | ||
|
|
3517d58f01 | ||
|
|
9d13fadd41 | ||
|
|
c1febce528 | ||
|
|
e0aadbd961 | ||
|
|
7b9a76c5ea | ||
|
|
6133fa8384 | ||
|
|
67cc215ed3 | ||
|
|
ea4ad2ea4d | ||
|
|
847454a4f7 | ||
|
|
8cba1fdd71 | ||
|
|
e56112739c | ||
|
|
76988b746f | ||
|
|
32eb365a0b | ||
|
|
2c5feddad5 | ||
|
|
210500ff3e | ||
|
|
7c8f10e832 | ||
|
|
644da2f9e4 | ||
|
|
2a80d9c555 | ||
|
|
76f8791f3c | ||
|
|
c51a013109 | ||
|
|
88c2f95ea5 | ||
|
|
062fa7de78 | ||
|
|
d6c1a41e8d | ||
|
|
20ab5f9326 | ||
|
|
ab5a8b24a5 | ||
|
|
21a28623ca | ||
|
|
06a5fec612 | ||
|
|
46ecb8a663 | ||
|
|
3c9c6eef6e | ||
|
|
72734de376 | ||
|
|
a20ea09a6e | ||
|
|
4bd7bce232 | ||
|
|
8adf42216d | ||
|
|
5f40aaabb5 | ||
|
|
5295abbb83 | ||
|
|
201abe1524 | ||
|
|
6d26051d11 | ||
|
|
4613bf78d5 | ||
|
|
1f8fdc6f5c | ||
|
|
8801fda972 | ||
|
|
d8e9da35d6 |
17
HISTORY.md
17
HISTORY.md
@@ -3,6 +3,23 @@
|
||||
|
||||
### main branch
|
||||
|
||||
- Added [`/editor` command](https://aider.chat/docs/usage/commands.html) to open system editor for writing prompts, by @thehunmonkgroup.
|
||||
- Full support for `gpt-4o-2024-11-20`.
|
||||
- Stream o1 models by default.
|
||||
- `/run` and suggested shell commands are less mysterious and now confirm that they "Added XX lines of output to the chat."
|
||||
- Ask 1% of users if they want to opt-in to [analytics](https://aider.chat/docs/more/analytics.html).
|
||||
- Added support for [optional multiline input tags](https://aider.chat/docs/usage/commands.html#entering-multi-line-chat-messages) with matching closing tags.
|
||||
- Improved [model settings configuration](https://aider.chat/docs/config/adv-model-settings.html#global-extra-params) with support for global `extra_params` for `litellm.completion()`.
|
||||
- Architect mode now asks to add files suggested by the LLM.
|
||||
- Fixed bug in fuzzy model name matching.
|
||||
- Added Timeout exception to handle API provider timeouts.
|
||||
- Added `--show-release-notes` to control release notes display on first run of new version.
|
||||
- Save empty dict to cache file on model metadata download failure, to delay retry.
|
||||
- Improved error handling and code formatting.
|
||||
- Aider wrote 74% of the code in this release.
|
||||
|
||||
### Aider v0.63.2
|
||||
|
||||
- Fixed bug in fuzzy model name matching when litellm provider info is missing.
|
||||
- Modified model metadata file loading to allow override of resource file.
|
||||
- Allow recursive loading of dirs using `--read`.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
try:
|
||||
from aider.__version__ import __version__
|
||||
except Exception:
|
||||
__version__ = "0.63.3.dev"
|
||||
__version__ = "0.64.1.dev"
|
||||
|
||||
__all__ = [__version__]
|
||||
|
||||
@@ -62,8 +62,47 @@ class Analytics:
|
||||
self.permanently_disable = True
|
||||
self.save_data()
|
||||
|
||||
def need_to_ask(self):
|
||||
return not self.asked_opt_in and not self.permanently_disable
|
||||
def need_to_ask(self, args_analytics):
|
||||
if args_analytics is False:
|
||||
return False
|
||||
|
||||
could_ask = not self.asked_opt_in and not self.permanently_disable
|
||||
if not could_ask:
|
||||
return False
|
||||
|
||||
if args_analytics is True:
|
||||
return True
|
||||
|
||||
assert args_analytics is None, args_analytics
|
||||
|
||||
if not self.user_id:
|
||||
return False
|
||||
|
||||
PERCENT = 1
|
||||
return self.is_uuid_in_percentage(self.user_id, PERCENT)
|
||||
|
||||
def is_uuid_in_percentage(self, uuid_str, percent):
|
||||
"""Check if a UUID string falls within the first X percent of the UUID space.
|
||||
|
||||
Args:
|
||||
uuid_str: UUID string to test
|
||||
percent: Percentage threshold (0-100)
|
||||
|
||||
Returns:
|
||||
bool: True if UUID falls within the first X percent
|
||||
"""
|
||||
if not (0 <= percent <= 100):
|
||||
raise ValueError("Percentage must be between 0 and 100")
|
||||
|
||||
if not uuid_str:
|
||||
return False
|
||||
|
||||
# Convert percentage to hex threshold (1% = "04...", 10% = "1a...", etc)
|
||||
# Using first 6 hex digits
|
||||
if percent == 0:
|
||||
return False
|
||||
threshold = format(int(0xFFFFFF * percent / 100), "06x")
|
||||
return uuid_str[:6] <= threshold
|
||||
|
||||
def get_data_file_path(self):
|
||||
data_file = Path.home() / ".aider" / "analytics.json"
|
||||
|
||||
@@ -562,8 +562,8 @@ def get_parser(default_config_files, git_root):
|
||||
group.add_argument(
|
||||
"--analytics",
|
||||
action=argparse.BooleanOptionalAction,
|
||||
default=False,
|
||||
help="Enable/disable analytics for one session (default: False)",
|
||||
default=None,
|
||||
help="Enable/disable analytics for current session (default: random)",
|
||||
)
|
||||
group.add_argument(
|
||||
"--analytics-log",
|
||||
@@ -620,6 +620,12 @@ def get_parser(default_config_files, git_root):
|
||||
help="Check for new aider versions on launch",
|
||||
default=True,
|
||||
)
|
||||
group.add_argument(
|
||||
"--show-release-notes",
|
||||
action=argparse.BooleanOptionalAction,
|
||||
help="Show release notes on first run of new version (default: None, ask user)",
|
||||
default=None,
|
||||
)
|
||||
group.add_argument(
|
||||
"--install-main-branch",
|
||||
action="store_true",
|
||||
@@ -732,6 +738,10 @@ def get_parser(default_config_files, git_root):
|
||||
default=True,
|
||||
help="Enable/disable fancy input with history and completion (default: True)",
|
||||
)
|
||||
group.add_argument(
|
||||
"--editor",
|
||||
help="Specify which editor to use for the /editor command",
|
||||
)
|
||||
|
||||
##########
|
||||
group = parser.add_argument_group("Voice Settings")
|
||||
|
||||
@@ -962,7 +962,7 @@ class Coder:
|
||||
if self.chat_language:
|
||||
language = self.chat_language
|
||||
else:
|
||||
language = "in the same language they are using"
|
||||
language = "the same language they are using"
|
||||
|
||||
prompt = prompt.format(
|
||||
fence=self.fence,
|
||||
@@ -1245,10 +1245,19 @@ class Coder:
|
||||
else:
|
||||
content = ""
|
||||
|
||||
try:
|
||||
self.reply_completed()
|
||||
except KeyboardInterrupt:
|
||||
interrupted = True
|
||||
if not interrupted:
|
||||
add_rel_files_message = self.check_for_file_mentions(content)
|
||||
if add_rel_files_message:
|
||||
if self.reflected_message:
|
||||
self.reflected_message += "\n\n" + add_rel_files_message
|
||||
else:
|
||||
self.reflected_message = add_rel_files_message
|
||||
return
|
||||
|
||||
try:
|
||||
self.reply_completed()
|
||||
except KeyboardInterrupt:
|
||||
interrupted = True
|
||||
|
||||
if interrupted:
|
||||
content += "\n^C KeyboardInterrupt"
|
||||
@@ -1299,13 +1308,6 @@ class Coder:
|
||||
self.update_cur_messages()
|
||||
return
|
||||
|
||||
add_rel_files_message = self.check_for_file_mentions(content)
|
||||
if add_rel_files_message:
|
||||
if self.reflected_message:
|
||||
self.reflected_message += "\n\n" + add_rel_files_message
|
||||
else:
|
||||
self.reflected_message = add_rel_files_message
|
||||
|
||||
def reply_completed(self):
|
||||
pass
|
||||
|
||||
@@ -2059,9 +2061,10 @@ class Coder:
|
||||
if output:
|
||||
accumulated_output += f"Output from {command}\n{output}\n"
|
||||
|
||||
if accumulated_output.strip() and not self.io.confirm_ask(
|
||||
if accumulated_output.strip() and self.io.confirm_ask(
|
||||
"Add command output to the chat?", allow_never=True
|
||||
):
|
||||
accumulated_output = ""
|
||||
|
||||
return accumulated_output
|
||||
num_lines = len(accumulated_output.strip().splitlines())
|
||||
line_plural = "line" if num_lines == 1 else "lines"
|
||||
self.io.tool_output(f"Added {num_lines} {line_plural} of output to the chat.")
|
||||
return accumulated_output
|
||||
|
||||
@@ -14,6 +14,7 @@ from prompt_toolkit.completion import Completion, PathCompleter
|
||||
from prompt_toolkit.document import Document
|
||||
|
||||
from aider import models, prompts, voice
|
||||
from aider.editor import pipe_editor
|
||||
from aider.format_settings import format_settings
|
||||
from aider.help import Help, install_help_extra
|
||||
from aider.llm import litellm
|
||||
@@ -45,7 +46,15 @@ class Commands:
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self, io, coder, voice_language=None, verify_ssl=True, args=None, parser=None, verbose=False
|
||||
self,
|
||||
io,
|
||||
coder,
|
||||
voice_language=None,
|
||||
verify_ssl=True,
|
||||
args=None,
|
||||
parser=None,
|
||||
verbose=False,
|
||||
editor=None,
|
||||
):
|
||||
self.io = io
|
||||
self.coder = coder
|
||||
@@ -60,6 +69,7 @@ class Commands:
|
||||
self.voice_language = voice_language
|
||||
|
||||
self.help = None
|
||||
self.editor = editor
|
||||
|
||||
def cmd_model(self, args):
|
||||
"Switch to a new LLM"
|
||||
@@ -868,7 +878,6 @@ class Commands:
|
||||
exit_status, combined_output = run_cmd(
|
||||
args, verbose=self.verbose, error_print=self.io.tool_error
|
||||
)
|
||||
instructions = None
|
||||
|
||||
if combined_output is None:
|
||||
return
|
||||
@@ -876,36 +885,22 @@ class Commands:
|
||||
if add_on_nonzero_exit:
|
||||
add = exit_status != 0
|
||||
else:
|
||||
self.io.tool_output()
|
||||
response = self.io.prompt_ask(
|
||||
"Add the output to the chat?\n(Y)es/(n)o/message with instructions:",
|
||||
).strip()
|
||||
self.io.tool_output()
|
||||
|
||||
if response.lower() in ["yes", "y"]:
|
||||
add = True
|
||||
elif response.lower() in ["no", "n"]:
|
||||
add = False
|
||||
else:
|
||||
add = True
|
||||
instructions = response
|
||||
if response.strip():
|
||||
self.io.user_input(response, log_only=True)
|
||||
self.io.add_to_input_history(response)
|
||||
add = self.io.confirm_ask("Add command output to the chat?")
|
||||
|
||||
if add:
|
||||
for line in combined_output.splitlines():
|
||||
self.io.tool_output(line, log_only=True)
|
||||
num_lines = len(combined_output.strip().splitlines())
|
||||
line_plural = "line" if num_lines == 1 else "lines"
|
||||
self.io.tool_output(f"Added {num_lines} {line_plural} of output to the chat.")
|
||||
|
||||
msg = prompts.run_output.format(
|
||||
command=args,
|
||||
output=combined_output,
|
||||
)
|
||||
|
||||
if instructions:
|
||||
msg = instructions + "\n\n" + msg
|
||||
|
||||
return msg
|
||||
self.coder.cur_messages += [
|
||||
dict(role="user", content=msg),
|
||||
dict(role="assistant", content="Ok."),
|
||||
]
|
||||
|
||||
def cmd_exit(self, args):
|
||||
"Exit the application"
|
||||
@@ -1366,6 +1361,14 @@ class Commands:
|
||||
|
||||
report_github_issue(issue_text, title=title, confirm=False)
|
||||
|
||||
def cmd_editor(self, initial_content=""):
|
||||
"Open an editor to write a prompt"
|
||||
|
||||
user_input = pipe_editor(initial_content, suffix="md", editor=self.editor)
|
||||
self.io.user_input(user_input, log_only=False)
|
||||
self.io.add_to_input_history(user_input)
|
||||
return user_input
|
||||
|
||||
|
||||
def expand_subdir(file_path):
|
||||
if file_path.is_file():
|
||||
|
||||
@@ -50,7 +50,6 @@ def diff_partial_update(lines_orig, lines_updated, final=False, fname=None):
|
||||
# dump(lines_orig)
|
||||
# dump(lines_updated)
|
||||
|
||||
assert_newlines(lines_orig)
|
||||
assert_newlines(lines_orig)
|
||||
|
||||
num_orig_lines = len(lines_orig)
|
||||
|
||||
146
aider/editor.py
Normal file
146
aider/editor.py
Normal file
@@ -0,0 +1,146 @@
|
||||
"""
|
||||
Editor module for handling system text editor interactions.
|
||||
|
||||
This module provides functionality to:
|
||||
- Discover and launch the system's configured text editor
|
||||
- Create and manage temporary files for editing
|
||||
- Handle editor preferences from environment variables
|
||||
- Support cross-platform editor operations
|
||||
"""
|
||||
|
||||
import os
|
||||
import platform
|
||||
import shlex
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
||||
from rich.console import Console
|
||||
|
||||
DEFAULT_EDITOR_NIX = "vi"
|
||||
DEFAULT_EDITOR_OS_X = "vim"
|
||||
DEFAULT_EDITOR_WINDOWS = "notepad"
|
||||
|
||||
console = Console()
|
||||
|
||||
|
||||
def print_status_message(success, message, style=None):
|
||||
"""
|
||||
Print a status message with appropriate styling.
|
||||
|
||||
:param success: Whether the operation was successful
|
||||
:param message: The message to display
|
||||
:param style: Optional style override. If None, uses green for success and red for failure
|
||||
"""
|
||||
if style is None:
|
||||
style = "bold green" if success else "bold red"
|
||||
console.print(message, style=style)
|
||||
print("")
|
||||
|
||||
|
||||
def write_temp_file(
|
||||
input_data="",
|
||||
suffix=None,
|
||||
prefix=None,
|
||||
dir=None,
|
||||
):
|
||||
"""
|
||||
Create a temporary file with the given input data.
|
||||
|
||||
:param input_data: Content to write to the temporary file
|
||||
:param suffix: Optional file extension (without the dot)
|
||||
:param prefix: Optional prefix for the temporary filename
|
||||
:param dir: Optional directory to create the file in
|
||||
:return: Path to the created temporary file
|
||||
:raises: OSError if file creation or writing fails
|
||||
"""
|
||||
kwargs = {"prefix": prefix, "dir": dir}
|
||||
if suffix:
|
||||
kwargs["suffix"] = f".{suffix}"
|
||||
fd, filepath = tempfile.mkstemp(**kwargs)
|
||||
try:
|
||||
with os.fdopen(fd, "w") as f:
|
||||
f.write(input_data)
|
||||
except Exception:
|
||||
os.close(fd)
|
||||
raise
|
||||
return filepath
|
||||
|
||||
|
||||
def get_environment_editor(default=None):
|
||||
"""
|
||||
Fetches the preferred editor from the environment variables.
|
||||
|
||||
This function checks the following environment variables in order to
|
||||
determine the user's preferred editor:
|
||||
|
||||
- VISUAL
|
||||
- EDITOR
|
||||
|
||||
:param default: The default editor to return if no environment variable is set.
|
||||
:type default: str or None
|
||||
:return: The preferred editor as specified by environment variables or the default value.
|
||||
:rtype: str or None
|
||||
"""
|
||||
editor = os.environ.get("VISUAL", os.environ.get("EDITOR", default))
|
||||
return editor
|
||||
|
||||
|
||||
def discover_editor(editor_override=None):
|
||||
"""
|
||||
Discovers and returns the appropriate editor command as a list of arguments.
|
||||
|
||||
Handles cases where the editor command includes arguments, including quoted arguments
|
||||
with spaces (e.g. 'vim -c "set noswapfile"').
|
||||
|
||||
:return: A list of command parts ready for subprocess execution
|
||||
:rtype: list[str]
|
||||
"""
|
||||
system = platform.system()
|
||||
if system == "Windows":
|
||||
default_editor = DEFAULT_EDITOR_WINDOWS
|
||||
elif system == "Darwin":
|
||||
default_editor = DEFAULT_EDITOR_OS_X
|
||||
else:
|
||||
default_editor = DEFAULT_EDITOR_NIX
|
||||
if editor_override:
|
||||
editor = editor_override
|
||||
else:
|
||||
editor = get_environment_editor(default_editor)
|
||||
try:
|
||||
return shlex.split(editor)
|
||||
except ValueError as e:
|
||||
raise RuntimeError(f"Invalid editor command format '{editor}': {e}")
|
||||
|
||||
|
||||
def pipe_editor(input_data="", suffix=None, editor=None):
|
||||
"""
|
||||
Opens the system editor with optional input data and returns the edited content.
|
||||
|
||||
This function creates a temporary file with the provided input data, opens it in
|
||||
the system editor, waits for the user to make changes and close the editor, then
|
||||
reads and returns the modified content. The temporary file is deleted afterwards.
|
||||
|
||||
:param input_data: Initial content to populate the editor with
|
||||
:type input_data: str
|
||||
:param suffix: Optional file extension for the temporary file (e.g. '.txt', '.md')
|
||||
:type suffix: str or None
|
||||
:return: The edited content after the editor is closed
|
||||
:rtype: str
|
||||
"""
|
||||
filepath = write_temp_file(input_data, suffix)
|
||||
command_parts = discover_editor(editor)
|
||||
command_parts.append(filepath)
|
||||
subprocess.call(command_parts)
|
||||
with open(filepath, "r") as f:
|
||||
output_data = f.read()
|
||||
try:
|
||||
os.remove(filepath)
|
||||
except PermissionError:
|
||||
print_status_message(
|
||||
False,
|
||||
(
|
||||
f"WARNING: Unable to delete temporary file {filepath!r}. You may need to delete it"
|
||||
" manually."
|
||||
),
|
||||
)
|
||||
return output_data
|
||||
@@ -40,6 +40,11 @@ EXCEPTIONS = [
|
||||
ExInfo("ServiceUnavailableError", True, "The API provider's servers are down or overloaded."),
|
||||
ExInfo("UnprocessableEntityError", True, None),
|
||||
ExInfo("UnsupportedParamsError", True, None),
|
||||
ExInfo(
|
||||
"Timeout",
|
||||
True,
|
||||
"The API provider timed out without returning a response. They may be down or overloaded.",
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -7,4 +7,5 @@ exclude_website_pats = [
|
||||
"docs/unified-diffs.md",
|
||||
"docs/leaderboards/index.md",
|
||||
"assets/**",
|
||||
"**/.DS_Store",
|
||||
]
|
||||
|
||||
56
aider/io.py
56
aider/io.py
@@ -441,13 +441,38 @@ class InputOutput:
|
||||
self.tool_error(str(err))
|
||||
return ""
|
||||
|
||||
if line and line[0] == "{" and not multiline_input:
|
||||
multiline_input = True
|
||||
inp += line[1:] + "\n"
|
||||
if line.strip("\r\n") and not multiline_input:
|
||||
stripped = line.strip("\r\n")
|
||||
if stripped == "{":
|
||||
multiline_input = True
|
||||
multiline_tag = None
|
||||
inp += ""
|
||||
elif stripped[0] == "{":
|
||||
# Extract tag if it exists (only alphanumeric chars)
|
||||
tag = "".join(c for c in stripped[1:] if c.isalnum())
|
||||
if stripped == "{" + tag:
|
||||
multiline_input = True
|
||||
multiline_tag = tag
|
||||
inp += ""
|
||||
else:
|
||||
inp = line
|
||||
break
|
||||
else:
|
||||
inp = line
|
||||
break
|
||||
continue
|
||||
elif line and line[-1] == "}" and multiline_input:
|
||||
inp += line[:-1] + "\n"
|
||||
break
|
||||
elif multiline_input and line.strip():
|
||||
if multiline_tag:
|
||||
# Check if line is exactly "tag}"
|
||||
if line.strip("\r\n") == f"{multiline_tag}}}":
|
||||
break
|
||||
else:
|
||||
inp += line + "\n"
|
||||
# Check if line is exactly "}"
|
||||
elif line.strip("\r\n") == "}":
|
||||
break
|
||||
else:
|
||||
inp += line + "\n"
|
||||
elif multiline_input:
|
||||
inp += line + "\n"
|
||||
else:
|
||||
@@ -463,8 +488,8 @@ class InputOutput:
|
||||
return
|
||||
FileHistory(self.input_history_file).append_string(inp)
|
||||
# Also add to the in-memory history if it exists
|
||||
if hasattr(self, "session") and hasattr(self.session, "history"):
|
||||
self.session.history.append_string(inp)
|
||||
if self.prompt_session and self.prompt_session.history:
|
||||
self.prompt_session.history.append_string(inp)
|
||||
|
||||
def get_input_history(self):
|
||||
if not self.input_history_file:
|
||||
@@ -481,14 +506,17 @@ class InputOutput:
|
||||
log_file.write(f"{role.upper()} {timestamp}\n")
|
||||
log_file.write(content + "\n")
|
||||
|
||||
def display_user_input(self, inp):
|
||||
if self.pretty and self.user_input_color:
|
||||
style = dict(style=self.user_input_color)
|
||||
else:
|
||||
style = dict()
|
||||
|
||||
self.console.print(Text(inp), **style)
|
||||
|
||||
def user_input(self, inp, log_only=True):
|
||||
if not log_only:
|
||||
if self.pretty and self.user_input_color:
|
||||
style = dict(style=self.user_input_color)
|
||||
else:
|
||||
style = dict()
|
||||
|
||||
self.console.print(Text(inp), **style)
|
||||
self.display_user_input(inp)
|
||||
|
||||
prefix = "####"
|
||||
if inp:
|
||||
|
||||
@@ -5,6 +5,7 @@ import re
|
||||
import sys
|
||||
import threading
|
||||
import traceback
|
||||
import webbrowser
|
||||
from pathlib import Path
|
||||
|
||||
import git
|
||||
@@ -505,8 +506,8 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||
io.tool_warning("Terminal does not support pretty output (UnicodeDecodeError)")
|
||||
|
||||
analytics = Analytics(logfile=args.analytics_log, permanently_disable=args.analytics_disable)
|
||||
if args.analytics:
|
||||
if analytics.need_to_ask():
|
||||
if args.analytics is not False:
|
||||
if analytics.need_to_ask(args.analytics):
|
||||
io.tool_output(
|
||||
"Aider respects your privacy and never collects your code, chat messages, keys or"
|
||||
" personal info."
|
||||
@@ -612,7 +613,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)
|
||||
is_first_run = is_first_run_of_new_version(io, verbose=args.verbose)
|
||||
check_and_load_imports(io, is_first_run, verbose=args.verbose)
|
||||
|
||||
if args.anthropic_api_key:
|
||||
os.environ["ANTHROPIC_API_KEY"] = args.anthropic_api_key
|
||||
@@ -687,7 +689,13 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||
return 1
|
||||
|
||||
commands = Commands(
|
||||
io, None, verify_ssl=args.verify_ssl, args=args, parser=parser, verbose=args.verbose
|
||||
io,
|
||||
None,
|
||||
verify_ssl=args.verify_ssl,
|
||||
args=args,
|
||||
parser=parser,
|
||||
verbose=args.verbose,
|
||||
editor=args.editor,
|
||||
)
|
||||
|
||||
summarizer = ChatSummary(
|
||||
@@ -797,6 +805,18 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||
|
||||
io.tool_output('Use /help <question> for help, run "aider --help" to see cmd line args')
|
||||
|
||||
show = False
|
||||
if args.show_release_notes is True:
|
||||
show = True
|
||||
elif args.show_release_notes is None and is_first_run:
|
||||
io.tool_output()
|
||||
show = io.confirm_ask("Would you like to see what's new in this version?")
|
||||
|
||||
if show:
|
||||
io.tool_output(f"Opening release notes: {urls.release_notes}")
|
||||
io.tool_output()
|
||||
webbrowser.open(urls.release_notes)
|
||||
|
||||
if git_root and Path.cwd().resolve() != Path(git_root).resolve():
|
||||
io.tool_warning(
|
||||
"Note: in-chat filenames are always relative to the git working dir, not the current"
|
||||
@@ -852,7 +872,8 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||
coder.show_announcements()
|
||||
|
||||
|
||||
def check_and_load_imports(io, verbose=False):
|
||||
def is_first_run_of_new_version(io, verbose=False):
|
||||
"""Check if this is the first run of a new version/executable combination"""
|
||||
installs_file = Path.home() / ".aider" / "installs.json"
|
||||
key = (__version__, sys.executable)
|
||||
|
||||
@@ -873,7 +894,26 @@ def check_and_load_imports(io, verbose=False):
|
||||
if verbose:
|
||||
io.tool_output("Installs file does not exist, creating new dictionary")
|
||||
|
||||
if str(key) not in installs:
|
||||
is_first_run = str(key) not in installs
|
||||
|
||||
if is_first_run:
|
||||
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)
|
||||
|
||||
return is_first_run
|
||||
|
||||
except Exception as e:
|
||||
io.tool_warning(f"Error checking version: {e}")
|
||||
if verbose:
|
||||
io.tool_output(f"Full exception details: {traceback.format_exc()}")
|
||||
return True # Safer to assume it's a first run if we hit an error
|
||||
|
||||
|
||||
def check_and_load_imports(io, is_first_run, verbose=False):
|
||||
try:
|
||||
if is_first_run:
|
||||
if verbose:
|
||||
io.tool_output(
|
||||
"First run for this version and executable, loading imports synchronously"
|
||||
@@ -884,13 +924,8 @@ def check_and_load_imports(io, verbose=False):
|
||||
io.tool_error(str(err))
|
||||
io.tool_output("Error loading required imports. Did you install aider properly?")
|
||||
io.offer_url(urls.install_properly, "Open documentation url for more info?")
|
||||
|
||||
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:
|
||||
@@ -899,8 +934,9 @@ def check_and_load_imports(io, verbose=False):
|
||||
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}")
|
||||
io.tool_warning(f"Error in loading imports: {e}")
|
||||
if verbose:
|
||||
io.tool_output(f"Full exception details: {traceback.format_exc()}")
|
||||
|
||||
|
||||
@@ -161,6 +161,22 @@ MODEL_SETTINGS = [
|
||||
lazy=True,
|
||||
reminder="sys",
|
||||
),
|
||||
ModelSettings(
|
||||
"gpt-4o-2024-11-20",
|
||||
"diff",
|
||||
weak_model_name="gpt-4o-mini",
|
||||
use_repo_map=True,
|
||||
lazy=True,
|
||||
reminder="sys",
|
||||
),
|
||||
ModelSettings(
|
||||
"openai/gpt-4o-2024-11-20",
|
||||
"diff",
|
||||
weak_model_name="gpt-4o-mini",
|
||||
use_repo_map=True,
|
||||
lazy=True,
|
||||
reminder="sys",
|
||||
),
|
||||
ModelSettings(
|
||||
"gpt-4o",
|
||||
"diff",
|
||||
@@ -629,7 +645,6 @@ MODEL_SETTINGS = [
|
||||
reminder="user",
|
||||
use_system_prompt=False,
|
||||
use_temperature=False,
|
||||
streaming=False,
|
||||
),
|
||||
ModelSettings(
|
||||
"azure/o1-mini",
|
||||
@@ -641,7 +656,6 @@ MODEL_SETTINGS = [
|
||||
reminder="user",
|
||||
use_system_prompt=False,
|
||||
use_temperature=False,
|
||||
streaming=False,
|
||||
),
|
||||
ModelSettings(
|
||||
"o1-mini",
|
||||
@@ -653,7 +667,6 @@ MODEL_SETTINGS = [
|
||||
reminder="user",
|
||||
use_system_prompt=False,
|
||||
use_temperature=False,
|
||||
streaming=False,
|
||||
),
|
||||
ModelSettings(
|
||||
"openai/o1-preview",
|
||||
@@ -665,7 +678,6 @@ MODEL_SETTINGS = [
|
||||
reminder="user",
|
||||
use_system_prompt=False,
|
||||
use_temperature=False,
|
||||
streaming=False,
|
||||
),
|
||||
ModelSettings(
|
||||
"azure/o1-preview",
|
||||
@@ -677,7 +689,6 @@ MODEL_SETTINGS = [
|
||||
reminder="user",
|
||||
use_system_prompt=False,
|
||||
use_temperature=False,
|
||||
streaming=False,
|
||||
),
|
||||
ModelSettings(
|
||||
"o1-preview",
|
||||
@@ -689,7 +700,6 @@ MODEL_SETTINGS = [
|
||||
reminder="user",
|
||||
use_system_prompt=False,
|
||||
use_temperature=False,
|
||||
streaming=False,
|
||||
),
|
||||
ModelSettings(
|
||||
"openrouter/openai/o1-mini",
|
||||
@@ -701,7 +711,6 @@ MODEL_SETTINGS = [
|
||||
reminder="user",
|
||||
use_system_prompt=False,
|
||||
use_temperature=False,
|
||||
streaming=False,
|
||||
),
|
||||
ModelSettings(
|
||||
"openrouter/openai/o1-preview",
|
||||
@@ -713,7 +722,6 @@ MODEL_SETTINGS = [
|
||||
reminder="user",
|
||||
use_system_prompt=False,
|
||||
use_temperature=False,
|
||||
streaming=False,
|
||||
),
|
||||
ModelSettings(
|
||||
"openrouter/qwen/qwen-2.5-coder-32b-instruct",
|
||||
@@ -762,6 +770,11 @@ class ModelInfoManager:
|
||||
pass
|
||||
except Exception as ex:
|
||||
print(str(ex))
|
||||
try:
|
||||
# Save empty dict to cache file on failure
|
||||
self.cache_file.write_text("{}")
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def get_model_from_cached_json_db(self, model):
|
||||
if not self.content:
|
||||
@@ -809,6 +822,11 @@ class Model(ModelSettings):
|
||||
self.weak_model = None
|
||||
self.editor_model = None
|
||||
|
||||
# Find the extra settings
|
||||
self.extra_model_settings = next(
|
||||
(ms for ms in MODEL_SETTINGS if ms.name == "aider/extra_params"), None
|
||||
)
|
||||
|
||||
self.info = self.get_model_info(model)
|
||||
|
||||
# Are all needed keys/params available?
|
||||
@@ -836,17 +854,44 @@ class Model(ModelSettings):
|
||||
def get_model_info(self, model):
|
||||
return model_info_manager.get_model_info(model)
|
||||
|
||||
def _copy_fields(self, source):
|
||||
"""Helper to copy fields from a ModelSettings instance to self"""
|
||||
for field in fields(ModelSettings):
|
||||
val = getattr(source, field.name)
|
||||
setattr(self, field.name, val)
|
||||
|
||||
def configure_model_settings(self, model):
|
||||
# Look for exact model match
|
||||
exact_match = False
|
||||
for ms in MODEL_SETTINGS:
|
||||
# direct match, or match "provider/<model>"
|
||||
if model == ms.name:
|
||||
for field in fields(ModelSettings):
|
||||
val = getattr(ms, field.name)
|
||||
setattr(self, field.name, val)
|
||||
return # <--
|
||||
self._copy_fields(ms)
|
||||
exact_match = True
|
||||
break # Continue to apply overrides
|
||||
|
||||
model = model.lower()
|
||||
|
||||
# If no exact match, try generic settings
|
||||
if not exact_match:
|
||||
self.apply_generic_model_settings(model)
|
||||
|
||||
# Apply override settings last if they exist
|
||||
if self.extra_model_settings and self.extra_model_settings.extra_params:
|
||||
# Initialize extra_params if it doesn't exist
|
||||
if not self.extra_params:
|
||||
self.extra_params = {}
|
||||
|
||||
# Deep merge the extra_params dicts
|
||||
for key, value in self.extra_model_settings.extra_params.items():
|
||||
if isinstance(value, dict) and isinstance(self.extra_params.get(key), dict):
|
||||
# For nested dicts, merge recursively
|
||||
self.extra_params[key] = {**self.extra_params[key], **value}
|
||||
else:
|
||||
# For non-dict values, simply update
|
||||
self.extra_params[key] = value
|
||||
|
||||
def apply_generic_model_settings(self, model):
|
||||
if ("llama3" in model or "llama-3" in model) and "70b" in model:
|
||||
self.edit_format = "diff"
|
||||
self.use_repo_map = True
|
||||
@@ -868,17 +913,19 @@ class Model(ModelSettings):
|
||||
|
||||
if "gpt-3.5" in model or "gpt-4" in model:
|
||||
self.reminder = "sys"
|
||||
return # <--
|
||||
|
||||
if "3.5-sonnet" in model or "3-5-sonnet" in model:
|
||||
self.edit_format = "diff"
|
||||
self.use_repo_map = True
|
||||
self.examples_as_sys_msg = True
|
||||
self.reminder = "user"
|
||||
return # <--
|
||||
|
||||
if model.startswith("o1-") or "/o1-" in model:
|
||||
self.use_system_prompt = False
|
||||
self.use_temperature = False
|
||||
self.streaming = False
|
||||
return # <--
|
||||
|
||||
if (
|
||||
"qwen" in model
|
||||
@@ -890,10 +937,12 @@ class Model(ModelSettings):
|
||||
self.edit_format = "diff"
|
||||
self.editor_edit_format = "editor-diff"
|
||||
self.use_repo_map = True
|
||||
return # <--
|
||||
|
||||
# use the defaults
|
||||
if self.edit_format == "diff":
|
||||
self.use_repo_map = True
|
||||
return # <--
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"openrouter/qwen/qwen-2.5-coder-32b-instruct": {
|
||||
"max_tokens": 33792,
|
||||
"max_input_tokens": 33792,
|
||||
"max_output_tokens": 33792,
|
||||
"input_cost_per_token": 0.00000018,
|
||||
"output_cost_per_token": 0.00000018,
|
||||
"litellm_provider": "openrouter",
|
||||
"mode": "chat",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -12,3 +12,4 @@ github_issues = "https://github.com/Aider-AI/aider/issues/new"
|
||||
git_index_version = "https://github.com/Aider-AI/aider/issues/211"
|
||||
install_properly = "https://aider.chat/docs/troubleshooting/imports.html"
|
||||
analytics = "https://aider.chat/docs/more/analytics.html"
|
||||
release_notes = "https://aider.chat/HISTORY.html#release-notes"
|
||||
|
||||
@@ -12,7 +12,9 @@ description: Release notes and stats on aider writing its own code.
|
||||
|
||||
The above
|
||||
[stats are based on the git commit history](/docs/faq.html#how-are-the-aider-wrote-xx-of-code-stats-computed)
|
||||
in the aider repo.
|
||||
of the aider repo.
|
||||
|
||||
## Release notes
|
||||
|
||||
<!--[[[cog
|
||||
# This page is a copy of HISTORY.md, adding the front matter above.
|
||||
@@ -25,6 +27,23 @@ cog.out(text)
|
||||
|
||||
### main branch
|
||||
|
||||
- Added [`/editor` command](https://aider.chat/docs/usage/commands.html) to open system editor for writing prompts, by @thehunmonkgroup.
|
||||
- Full support for `gpt-4o-2024-11-20`.
|
||||
- Stream o1 models by default.
|
||||
- `/run` and suggested shell commands are less mysterious and now confirm that they "Added XX lines of output to the chat."
|
||||
- Ask 1% of users if they want to opt-in to [analytics](https://aider.chat/docs/more/analytics.html).
|
||||
- Added support for [optional multiline input tags](https://aider.chat/docs/usage/commands.html#entering-multi-line-chat-messages) with matching closing tags.
|
||||
- Improved [model settings configuration](https://aider.chat/docs/config/adv-model-settings.html#global-extra-params) with support for global `extra_params` for `litellm.completion()`.
|
||||
- Architect mode now asks to add files suggested by the LLM.
|
||||
- Fixed bug in fuzzy model name matching.
|
||||
- Added Timeout exception to handle API provider timeouts.
|
||||
- Added `--show-release-notes` to control release notes display on first run of new version.
|
||||
- Save empty dict to cache file on model metadata download failure, to delay retry.
|
||||
- Improved error handling and code formatting.
|
||||
- Aider wrote 74% of the code in this release.
|
||||
|
||||
### Aider v0.63.2
|
||||
|
||||
- Fixed bug in fuzzy model name matching when litellm provider info is missing.
|
||||
- Modified model metadata file loading to allow override of resource file.
|
||||
- Allow recursive loading of dirs using `--read`.
|
||||
|
||||
@@ -1801,8 +1801,8 @@
|
||||
Paul Gauthier (aider): 113
|
||||
start_tag: v0.44.0
|
||||
total_lines: 266
|
||||
- aider_percentage: 47.04
|
||||
aider_total: 254
|
||||
- aider_percentage: 53.3
|
||||
aider_total: 339
|
||||
end_date: '2024-07-29'
|
||||
end_tag: v0.46.0
|
||||
file_counts:
|
||||
@@ -1853,6 +1853,9 @@
|
||||
aider/scrape.py:
|
||||
Paul Gauthier: 3
|
||||
Paul Gauthier (aider): 32
|
||||
aider/website/docs/leaderboards/index.md:
|
||||
Paul Gauthier: 11
|
||||
Paul Gauthier (aider): 85
|
||||
benchmark/Dockerfile:
|
||||
Your Name: 1
|
||||
tests/basic/test_coder.py:
|
||||
@@ -1868,13 +1871,13 @@
|
||||
Paul Gauthier (aider): 73
|
||||
grand_total:
|
||||
Charles Joachim: 4
|
||||
Paul Gauthier: 209
|
||||
Paul Gauthier (aider): 204
|
||||
Paul Gauthier: 220
|
||||
Paul Gauthier (aider): 289
|
||||
Your Name: 73
|
||||
Your Name (aider): 50
|
||||
start_tag: v0.45.0
|
||||
total_lines: 540
|
||||
- aider_percentage: 59.12
|
||||
total_lines: 636
|
||||
- aider_percentage: 57.16
|
||||
aider_total: 415
|
||||
end_date: '2024-07-31'
|
||||
end_tag: v0.47.0
|
||||
@@ -1920,6 +1923,8 @@
|
||||
Paul Gauthier (aider): 2
|
||||
aider/utils.py:
|
||||
Paul Gauthier: 7
|
||||
aider/website/docs/leaderboards/index.md:
|
||||
Paul Gauthier: 24
|
||||
docker/Dockerfile:
|
||||
Paul Gauthier: 19
|
||||
Paul Gauthier (aider): 21
|
||||
@@ -1944,10 +1949,10 @@
|
||||
tests/basic/test_repomap.py:
|
||||
Paul Gauthier: 1
|
||||
grand_total:
|
||||
Paul Gauthier: 287
|
||||
Paul Gauthier: 311
|
||||
Paul Gauthier (aider): 415
|
||||
start_tag: v0.46.0
|
||||
total_lines: 702
|
||||
total_lines: 726
|
||||
- aider_percentage: 44.44
|
||||
aider_total: 276
|
||||
end_date: '2024-08-06'
|
||||
@@ -2011,8 +2016,8 @@
|
||||
paul-gauthier: 1
|
||||
start_tag: v0.47.0
|
||||
total_lines: 621
|
||||
- aider_percentage: 61.52
|
||||
aider_total: 478
|
||||
- aider_percentage: 61.2
|
||||
aider_total: 489
|
||||
end_date: '2024-08-10'
|
||||
end_tag: v0.49.0
|
||||
file_counts:
|
||||
@@ -2055,6 +2060,9 @@
|
||||
aider/versioncheck.py:
|
||||
Paul Gauthier: 3
|
||||
Paul Gauthier (aider): 11
|
||||
aider/website/docs/leaderboards/index.md:
|
||||
Paul Gauthier: 11
|
||||
Paul Gauthier (aider): 11
|
||||
docker/Dockerfile:
|
||||
Paul Gauthier: 5
|
||||
Paul Gauthier (aider): 2
|
||||
@@ -2075,10 +2083,10 @@
|
||||
Paul Gauthier: 1
|
||||
Paul Gauthier (aider): 49
|
||||
grand_total:
|
||||
Paul Gauthier: 299
|
||||
Paul Gauthier (aider): 478
|
||||
Paul Gauthier: 310
|
||||
Paul Gauthier (aider): 489
|
||||
start_tag: v0.48.0
|
||||
total_lines: 777
|
||||
total_lines: 799
|
||||
- aider_percentage: 66.05
|
||||
aider_total: 214
|
||||
end_date: '2024-08-13'
|
||||
@@ -2135,7 +2143,7 @@
|
||||
Paul Gauthier (aider): 201
|
||||
start_tag: v0.49.0
|
||||
total_lines: 324
|
||||
- aider_percentage: 56.25
|
||||
- aider_percentage: 56.18
|
||||
aider_total: 450
|
||||
end_date: '2024-08-20'
|
||||
end_tag: v0.51.0
|
||||
@@ -2170,6 +2178,8 @@
|
||||
Paul Gauthier: 3
|
||||
aider/utils.py:
|
||||
Paul Gauthier (aider): 6
|
||||
aider/website/docs/leaderboards/index.md:
|
||||
Paul Gauthier: 1
|
||||
benchmark/benchmark.py:
|
||||
Paul Gauthier: 7
|
||||
benchmark/over_time.py:
|
||||
@@ -2188,11 +2198,11 @@
|
||||
Paul Gauthier: 15
|
||||
Paul Gauthier (aider): 104
|
||||
grand_total:
|
||||
Paul Gauthier: 350
|
||||
Paul Gauthier: 351
|
||||
Paul Gauthier (aider): 450
|
||||
start_tag: v0.50.0
|
||||
total_lines: 800
|
||||
- aider_percentage: 68.19
|
||||
total_lines: 801
|
||||
- aider_percentage: 68.1
|
||||
aider_total: 521
|
||||
end_date: '2024-08-23'
|
||||
end_tag: v0.52.0
|
||||
@@ -2231,6 +2241,8 @@
|
||||
Paul Gauthier (aider): 9
|
||||
aider/versioncheck.py:
|
||||
Paul Gauthier: 2
|
||||
aider/website/docs/leaderboards/index.md:
|
||||
Paul Gauthier: 1
|
||||
benchmark/benchmark.py:
|
||||
Paul Gauthier: 1
|
||||
scripts/blame.py:
|
||||
@@ -2250,11 +2262,11 @@
|
||||
tests/basic/test_wholefile.py:
|
||||
Paul Gauthier: 8
|
||||
grand_total:
|
||||
Paul Gauthier: 242
|
||||
Paul Gauthier: 243
|
||||
Paul Gauthier (aider): 521
|
||||
pcamp: 1
|
||||
start_tag: v0.51.0
|
||||
total_lines: 764
|
||||
total_lines: 765
|
||||
- aider_percentage: 58.61
|
||||
aider_total: 405
|
||||
end_date: '2024-08-27'
|
||||
@@ -2328,7 +2340,7 @@
|
||||
Paul Gauthier (aider): 405
|
||||
start_tag: v0.52.0
|
||||
total_lines: 691
|
||||
- aider_percentage: 63.95
|
||||
- aider_percentage: 63.75
|
||||
aider_total: 204
|
||||
end_date: '2024-08-28'
|
||||
end_tag: v0.54.0
|
||||
@@ -2364,6 +2376,8 @@
|
||||
aider/versioncheck.py:
|
||||
Paul Gauthier: 1
|
||||
Paul Gauthier (aider): 13
|
||||
aider/website/docs/leaderboards/index.md:
|
||||
Paul Gauthier: 1
|
||||
tests/basic/test_coder.py:
|
||||
Paul Gauthier: 36
|
||||
Paul Gauthier (aider): 27
|
||||
@@ -2376,11 +2390,11 @@
|
||||
Paul Gauthier: 1
|
||||
grand_total:
|
||||
Antti Kaihola: 4
|
||||
Paul Gauthier: 111
|
||||
Paul Gauthier: 112
|
||||
Paul Gauthier (aider): 204
|
||||
start_tag: v0.53.0
|
||||
total_lines: 319
|
||||
- aider_percentage: 52.9
|
||||
total_lines: 320
|
||||
- aider_percentage: 52.87
|
||||
aider_total: 811
|
||||
end_date: '2024-09-04'
|
||||
end_tag: v0.55.0
|
||||
@@ -2450,6 +2464,8 @@
|
||||
aider/voice.py:
|
||||
Paul Gauthier: 7
|
||||
Paul Gauthier (aider): 9
|
||||
aider/website/docs/leaderboards/index.md:
|
||||
Paul Gauthier: 1
|
||||
scripts/versionbump.py:
|
||||
Paul Gauthier: 9
|
||||
tests/basic/test_coder.py:
|
||||
@@ -2478,11 +2494,11 @@
|
||||
grand_total:
|
||||
Antti Kaihola: 12
|
||||
Nikolay Sedelnikov: 45
|
||||
Paul Gauthier: 665
|
||||
Paul Gauthier: 666
|
||||
Paul Gauthier (aider): 811
|
||||
start_tag: v0.54.0
|
||||
total_lines: 1533
|
||||
- aider_percentage: 55.6
|
||||
total_lines: 1534
|
||||
- aider_percentage: 55.4
|
||||
aider_total: 154
|
||||
end_date: '2024-09-09'
|
||||
end_tag: v0.56.0
|
||||
@@ -2517,6 +2533,8 @@
|
||||
aider/report.py:
|
||||
Paul Gauthier: 2
|
||||
Paul Gauthier (aider): 20
|
||||
aider/website/docs/leaderboards/index.md:
|
||||
Paul Gauthier: 1
|
||||
benchmark/benchmark.py:
|
||||
Paul Gauthier: 1
|
||||
tests/basic/test_linter.py:
|
||||
@@ -2526,13 +2544,13 @@
|
||||
Paul Gauthier: 2
|
||||
Paul Gauthier (aider): 9
|
||||
grand_total:
|
||||
Paul Gauthier: 108
|
||||
Paul Gauthier: 109
|
||||
Paul Gauthier (aider): 154
|
||||
fry69: 15
|
||||
start_tag: v0.55.0
|
||||
total_lines: 277
|
||||
- aider_percentage: 69.98
|
||||
aider_total: 394
|
||||
total_lines: 278
|
||||
- aider_percentage: 70.36
|
||||
aider_total: 406
|
||||
end_date: '2024-09-21'
|
||||
end_tag: v0.57.0
|
||||
file_counts:
|
||||
@@ -2575,6 +2593,10 @@
|
||||
Paul Gauthier: 3
|
||||
aider/utils.py:
|
||||
Paul Gauthier: 2
|
||||
aider/website/docs/leaderboards/index.md:
|
||||
Anjor Kanekar: 1
|
||||
Paul Gauthier: 1
|
||||
Paul Gauthier (aider): 12
|
||||
benchmark/benchmark.py:
|
||||
Paul Gauthier: 4
|
||||
scripts/issues.py:
|
||||
@@ -2592,15 +2614,16 @@
|
||||
Paul Gauthier: 18
|
||||
Paul Gauthier (aider): 20
|
||||
grand_total:
|
||||
Anjor Kanekar: 1
|
||||
Christian Clauss: 2
|
||||
Jay Alammar: 1
|
||||
Jay Alammar (aider): 13
|
||||
Krazer: 33
|
||||
Paul Gauthier: 133
|
||||
Paul Gauthier (aider): 381
|
||||
Paul Gauthier: 134
|
||||
Paul Gauthier (aider): 393
|
||||
start_tag: v0.56.0
|
||||
total_lines: 563
|
||||
- aider_percentage: 53.45
|
||||
total_lines: 577
|
||||
- aider_percentage: 47.95
|
||||
aider_total: 712
|
||||
end_date: '2024-09-29'
|
||||
end_tag: v0.58.0
|
||||
@@ -2677,6 +2700,8 @@
|
||||
Mike Bailey: 17
|
||||
Paul Gauthier: 2
|
||||
Paul Gauthier (aider): 10
|
||||
aider/website/docs/leaderboards/index.md:
|
||||
Paul Gauthier: 153
|
||||
benchmark/benchmark.py:
|
||||
Paul Gauthier: 25
|
||||
Paul Gauthier (aider): 29
|
||||
@@ -2705,14 +2730,14 @@
|
||||
grand_total:
|
||||
Jonathan Ellis: 2
|
||||
Mike Bailey: 18
|
||||
Paul Gauthier: 376
|
||||
Paul Gauthier: 529
|
||||
Paul Gauthier (aider): 712
|
||||
Stein Martin Hustad: 26
|
||||
fry69: 197
|
||||
rti: 1
|
||||
start_tag: v0.57.0
|
||||
total_lines: 1332
|
||||
- aider_percentage: 76.79
|
||||
total_lines: 1485
|
||||
- aider_percentage: 75.44
|
||||
aider_total: 172
|
||||
end_date: '2024-10-04'
|
||||
end_tag: v0.59.0
|
||||
@@ -2747,6 +2772,8 @@
|
||||
Paul Gauthier: 2
|
||||
aider/versioncheck.py:
|
||||
Paul Gauthier: 1
|
||||
aider/website/docs/leaderboards/index.md:
|
||||
Paul Gauthier: 4
|
||||
scripts/issues.py:
|
||||
Paul Gauthier: 1
|
||||
scripts/update-docs.sh:
|
||||
@@ -2762,11 +2789,11 @@
|
||||
tests/help/test_help.py:
|
||||
Paul Gauthier: 1
|
||||
grand_total:
|
||||
Paul Gauthier: 52
|
||||
Paul Gauthier: 56
|
||||
Paul Gauthier (aider): 172
|
||||
start_tag: v0.58.0
|
||||
total_lines: 224
|
||||
- aider_percentage: 49.12
|
||||
total_lines: 228
|
||||
- aider_percentage: 48.95
|
||||
aider_total: 140
|
||||
end_date: '2024-10-22'
|
||||
end_tag: v0.60.0
|
||||
@@ -2804,6 +2831,8 @@
|
||||
Paul Gauthier: 3
|
||||
aider/sendchat.py:
|
||||
Paul Gauthier: 3
|
||||
aider/website/docs/leaderboards/index.md:
|
||||
Paul Gauthier: 1
|
||||
tests/basic/test_editblock.py:
|
||||
Paul Gauthier: 23
|
||||
tests/basic/test_main.py:
|
||||
@@ -2813,12 +2842,12 @@
|
||||
Paul Gauthier (aider): 46
|
||||
grand_total:
|
||||
Jonathan Ellis: 10
|
||||
Paul Gauthier: 93
|
||||
Paul Gauthier: 94
|
||||
Paul Gauthier (aider): 140
|
||||
Sven Grunewaldt: 24
|
||||
fry69: 18
|
||||
start_tag: v0.59.0
|
||||
total_lines: 285
|
||||
total_lines: 286
|
||||
- aider_percentage: 67.61
|
||||
aider_total: 860
|
||||
end_date: '2024-11-01'
|
||||
@@ -2895,8 +2924,8 @@
|
||||
kAIto47802: 4
|
||||
start_tag: v0.60.0
|
||||
total_lines: 1272
|
||||
- aider_percentage: 84.0
|
||||
aider_total: 63
|
||||
- aider_percentage: 82.42
|
||||
aider_total: 75
|
||||
end_date: '2024-11-04'
|
||||
end_tag: v0.62.0
|
||||
file_counts:
|
||||
@@ -2911,12 +2940,15 @@
|
||||
aider/models.py:
|
||||
Paul Gauthier: 5
|
||||
Paul Gauthier (aider): 45
|
||||
aider/website/docs/leaderboards/index.md:
|
||||
Paul Gauthier: 4
|
||||
Paul Gauthier (aider): 12
|
||||
grand_total:
|
||||
Paul Gauthier: 12
|
||||
Paul Gauthier (aider): 63
|
||||
Paul Gauthier: 16
|
||||
Paul Gauthier (aider): 75
|
||||
start_tag: v0.61.0
|
||||
total_lines: 75
|
||||
- aider_percentage: 55.16
|
||||
total_lines: 91
|
||||
- aider_percentage: 55.08
|
||||
aider_total: 385
|
||||
end_date: '2024-11-13'
|
||||
end_tag: v0.63.0
|
||||
@@ -2952,6 +2984,8 @@
|
||||
aider/sendchat.py:
|
||||
Paul Gauthier: 17
|
||||
Paul Gauthier (aider): 4
|
||||
aider/website/docs/leaderboards/index.md:
|
||||
Paul Gauthier: 1
|
||||
scripts/issues.py:
|
||||
Paul Gauthier: 4
|
||||
Paul Gauthier (aider): 195
|
||||
@@ -2975,7 +3009,7 @@
|
||||
Paul Gauthier: 1
|
||||
grand_total:
|
||||
Logan Attwood: 29
|
||||
Paul Gauthier: 284
|
||||
Paul Gauthier: 285
|
||||
Paul Gauthier (aider): 385
|
||||
start_tag: v0.62.0
|
||||
total_lines: 698
|
||||
total_lines: 699
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
- dirname: 2024-05-01-20-05-59--direct-opus-filenames-outside-fence
|
||||
test_cases: 133
|
||||
model: claude-3-opus-20240229
|
||||
released: 2024-02-29
|
||||
_released: 2024-02-29
|
||||
edit_format: diff
|
||||
commit_hash: f4b1797-dirty, f4b1797
|
||||
pass_rate_1: 53.4
|
||||
@@ -274,7 +274,7 @@
|
||||
- dirname: 2024-05-03-22-24-48--openrouter--llama3-diff-examples-sys-msg
|
||||
test_cases: 132
|
||||
model: llama3-70b-8192
|
||||
released: 2024-04-18
|
||||
_released: 2024-04-18
|
||||
edit_format: diff
|
||||
commit_hash: b5bb453
|
||||
pass_rate_1: 38.6
|
||||
@@ -297,7 +297,7 @@
|
||||
- dirname: 2024-05-06-18-31-08--command-r-plus-whole-final
|
||||
test_cases: 133
|
||||
model: command-r-plus
|
||||
released: 2024-04-04
|
||||
_released: 2024-04-04
|
||||
edit_format: whole
|
||||
commit_hash: fc3a43e-dirty
|
||||
pass_rate_1: 21.8
|
||||
@@ -623,7 +623,7 @@
|
||||
commit_hash: d31eef3-dirty
|
||||
pass_rate_1: 40.6
|
||||
pass_rate_2: 55.6
|
||||
released: 2024-07-18
|
||||
_released: 2024-07-18
|
||||
percent_cases_well_formed: 100.0
|
||||
error_outputs: 1
|
||||
num_malformed_responses: 0
|
||||
@@ -671,7 +671,7 @@
|
||||
commit_hash: f7ce78b-dirty
|
||||
pass_rate_1: 46.6
|
||||
pass_rate_2: 63.9
|
||||
released: 2024-07-23
|
||||
_released: 2024-07-23
|
||||
percent_cases_well_formed: 92.5
|
||||
error_outputs: 84
|
||||
num_malformed_responses: 19
|
||||
@@ -691,6 +691,7 @@
|
||||
- dirname: 2024-07-24-06-30-29--llama-405b-whole
|
||||
test_cases: 133
|
||||
model: llama-3.1-405b-instruct (whole)
|
||||
_released: 2024-07-23
|
||||
edit_format: whole
|
||||
commit_hash: a362dea-dirty
|
||||
pass_rate_1: 48.9
|
||||
@@ -698,7 +699,6 @@
|
||||
percent_cases_well_formed: 100.0
|
||||
error_outputs: 0
|
||||
num_malformed_responses: 0
|
||||
released: 2024-07-23
|
||||
num_with_malformed_responses: 0
|
||||
user_asks: 0
|
||||
lazy_comments: 0
|
||||
@@ -770,7 +770,7 @@
|
||||
percent_cases_well_formed: 100.0
|
||||
error_outputs: 27
|
||||
num_malformed_responses: 0
|
||||
released: 2024-07-23
|
||||
_released: 2024-07-23
|
||||
num_with_malformed_responses: 0
|
||||
user_asks: 23
|
||||
lazy_comments: 8
|
||||
@@ -796,7 +796,7 @@
|
||||
num_malformed_responses: 0
|
||||
num_with_malformed_responses: 0
|
||||
user_asks: 0
|
||||
released: 2024-07-23
|
||||
_released: 2024-07-23
|
||||
lazy_comments: 0
|
||||
syntax_errors: 0
|
||||
indentation_errors: 0
|
||||
@@ -946,7 +946,7 @@
|
||||
versions: 0.54.13.dev
|
||||
seconds_per_case: 8.3
|
||||
total_cost: 0.0000
|
||||
released: 2024-09-04
|
||||
_released: 2024-09-04
|
||||
|
||||
- dirname: 2024-09-04-16-17-33--yi-coder-9b-chat-q4_0-whole
|
||||
test_cases: 133
|
||||
@@ -973,6 +973,7 @@
|
||||
|
||||
- dirname: 2024-09-05-14-50-11--deepseek-sep5-no-shell
|
||||
test_cases: 133
|
||||
released: 2024-09-05
|
||||
model: DeepSeek V2.5
|
||||
edit_format: diff
|
||||
commit_hash: 1279c86
|
||||
@@ -1112,6 +1113,7 @@
|
||||
- dirname: 2024-09-21-16-45-11--o1-preview-flex-sr-markers
|
||||
test_cases: 133
|
||||
model: o1-preview
|
||||
_released: 2024-09-12
|
||||
edit_format: diff
|
||||
commit_hash: 5493654-dirty
|
||||
pass_rate_1: 57.9
|
||||
@@ -1477,6 +1479,7 @@
|
||||
- dirname: 2024-10-04-16-30-08--chatgpt-4o-latest-diff-oct4
|
||||
test_cases: 133
|
||||
model: openai/chatgpt-4o-latest
|
||||
released: 2024-10-04
|
||||
edit_format: diff
|
||||
commit_hash: af10953
|
||||
pass_rate_1: 56.4
|
||||
@@ -1592,6 +1595,7 @@
|
||||
- dirname: 2024-10-22-17-45-28--sonnet-1022-diff-fixed-model-settings
|
||||
test_cases: 133
|
||||
model: claude-3-5-sonnet-20241022
|
||||
released: 2024-10-22
|
||||
edit_format: diff
|
||||
commit_hash: 3b14eb9
|
||||
pass_rate_1: 69.2
|
||||
@@ -1615,6 +1619,7 @@
|
||||
- dirname: 2024-11-04-19-19-32--haiku35-diff-ex-as-sys-false
|
||||
test_cases: 133
|
||||
model: claude-3-5-haiku-20241022
|
||||
released: 2024-10-22
|
||||
edit_format: diff
|
||||
commit_hash: 03bbdb0-dirty
|
||||
pass_rate_1: 61.7
|
||||
@@ -1773,32 +1778,10 @@
|
||||
seconds_per_case: 18.3
|
||||
total_cost: 0.0000
|
||||
|
||||
- dirname: 2024-11-09-10-57-11--Qwen2.5-Coder-32B-Instruct
|
||||
test_cases: 133
|
||||
model: Qwen2.5-Coder-32B-Instruct (whole)
|
||||
edit_format: whole
|
||||
commit_hash: ec9982a
|
||||
pass_rate_1: 60.9
|
||||
pass_rate_2: 73.7
|
||||
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: 0
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 1
|
||||
test_timeouts: 1
|
||||
command: aider --model openai/Qwen2.5-Coder-32B-Instruct
|
||||
date: 2024-11-09
|
||||
versions: 0.59.2.dev
|
||||
seconds_per_case: 26.6
|
||||
total_cost: 0.0000
|
||||
|
||||
- dirname: 2024-11-09-11-09-15--Qwen2.5-Coder-32B-Instruct
|
||||
test_cases: 133
|
||||
model: Qwen2.5-Coder-32B-Instruct (diff)
|
||||
model: Qwen2.5-Coder-32B-Instruct
|
||||
released: 2024-11-12
|
||||
edit_format: diff
|
||||
commit_hash: ec9982a
|
||||
pass_rate_1: 59.4
|
||||
@@ -1818,3 +1801,97 @@
|
||||
versions: 0.59.2.dev
|
||||
seconds_per_case: 22.5
|
||||
total_cost: 0.0000
|
||||
|
||||
- dirname: 2024-11-20-14-57-11--mistral-2411-direct-diff
|
||||
test_cases: 133
|
||||
model: Mistral Large (2411)
|
||||
released: 2024-11-18
|
||||
edit_format: diff
|
||||
commit_hash: dba844c
|
||||
pass_rate_1: 46.6
|
||||
pass_rate_2: 65.4
|
||||
percent_cases_well_formed: 96.2
|
||||
error_outputs: 8
|
||||
num_malformed_responses: 8
|
||||
num_with_malformed_responses: 5
|
||||
user_asks: 5
|
||||
lazy_comments: 0
|
||||
syntax_errors: 0
|
||||
indentation_errors: 1
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 1
|
||||
command: aider --model mistral/mistral-large-latest
|
||||
date: 2024-11-20
|
||||
versions: 0.63.3.dev
|
||||
seconds_per_case: 24.9
|
||||
total_cost: 3.2334
|
||||
|
||||
- dirname: 2024-11-20-19-28-30--gpt-4o-2024-11-20
|
||||
test_cases: 133
|
||||
model: gpt-4o-2024-11-20
|
||||
released: 2024-11-20
|
||||
edit_format: diff
|
||||
commit_hash: 2ac0776-dirty
|
||||
pass_rate_1: 58.6
|
||||
pass_rate_2: 71.4
|
||||
percent_cases_well_formed: 99.2
|
||||
error_outputs: 1
|
||||
num_malformed_responses: 1
|
||||
num_with_malformed_responses: 1
|
||||
user_asks: 4
|
||||
lazy_comments: 0
|
||||
syntax_errors: 0
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 5
|
||||
command: aider --model openai/gpt-4o-2024-11-20
|
||||
date: 2024-11-20
|
||||
versions: 0.63.3.dev
|
||||
seconds_per_case: 6.0
|
||||
total_cost: 0.0000
|
||||
|
||||
- dirname: 2024-09-20-21-47-17--qwen2.5-32b-instruct-q8_0-whole
|
||||
test_cases: 133
|
||||
model: ollama/qwen2.5:32b-instruct-q8_0
|
||||
edit_format: whole
|
||||
commit_hash: 2753ac6
|
||||
pass_rate_1: 46.6
|
||||
pass_rate_2: 58.6
|
||||
percent_cases_well_formed: 100.0
|
||||
error_outputs: 0
|
||||
num_malformed_responses: 0
|
||||
num_with_malformed_responses: 0
|
||||
user_asks: 1
|
||||
lazy_comments: 0
|
||||
syntax_errors: 0
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 2
|
||||
command: aider --model ollama/qwen2.5:32b-instruct-q8_0
|
||||
date: 2024-09-20
|
||||
versions: 0.56.1.dev
|
||||
seconds_per_case: 1763.7
|
||||
total_cost: 0.0000
|
||||
|
||||
- dirname: 2024-11-20-15-17-37--qwen25-32b-or-diff
|
||||
test_cases: 133
|
||||
model: openrouter/qwen/qwen-2.5-coder-32b-instruct
|
||||
edit_format: diff
|
||||
commit_hash: e917424
|
||||
pass_rate_1: 49.6
|
||||
pass_rate_2: 65.4
|
||||
percent_cases_well_formed: 84.2
|
||||
error_outputs: 43
|
||||
num_malformed_responses: 31
|
||||
num_with_malformed_responses: 21
|
||||
user_asks: 43
|
||||
lazy_comments: 0
|
||||
syntax_errors: 2
|
||||
indentation_errors: 2
|
||||
exhausted_context_windows: 12
|
||||
test_timeouts: 2
|
||||
command: aider --model openrouter/qwen/qwen-2.5-coder-32b-instruct
|
||||
date: 2024-11-20
|
||||
versions: 0.63.3.dev
|
||||
seconds_per_case: 40.7
|
||||
total_cost: 0.1497
|
||||
93
aider/website/_data/quant.yml
Normal file
93
aider/website/_data/quant.yml
Normal file
@@ -0,0 +1,93 @@
|
||||
- dirname: 2024-11-09-11-09-15--Qwen2.5-Coder-32B-Instruct
|
||||
test_cases: 133
|
||||
model: HuggingFace weights via glhf.chat
|
||||
released: 2024-11-12
|
||||
edit_format: diff
|
||||
commit_hash: ec9982a
|
||||
pass_rate_1: 59.4
|
||||
pass_rate_2: 71.4
|
||||
percent_cases_well_formed: 94.7
|
||||
error_outputs: 17
|
||||
num_malformed_responses: 17
|
||||
num_with_malformed_responses: 7
|
||||
user_asks: 1
|
||||
lazy_comments: 0
|
||||
syntax_errors: 0
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 3
|
||||
command: aider --model openai/Qwen2.5-Coder-32B-Instruct
|
||||
date: 2024-11-09
|
||||
versions: 0.59.2.dev
|
||||
seconds_per_case: 22.5
|
||||
total_cost: 0.0000
|
||||
|
||||
- dirname: 2024-11-20-15-17-37--qwen25-32b-or-diff
|
||||
test_cases: 133
|
||||
model: openrouter/qwen/qwen-2.5-coder-32b-instruct
|
||||
edit_format: diff
|
||||
commit_hash: e917424
|
||||
pass_rate_1: 49.6
|
||||
pass_rate_2: 65.4
|
||||
percent_cases_well_formed: 84.2
|
||||
error_outputs: 43
|
||||
num_malformed_responses: 31
|
||||
num_with_malformed_responses: 21
|
||||
user_asks: 43
|
||||
lazy_comments: 0
|
||||
syntax_errors: 2
|
||||
indentation_errors: 2
|
||||
exhausted_context_windows: 12
|
||||
test_timeouts: 2
|
||||
command: aider --model openrouter/qwen/qwen-2.5-coder-32b-instruct
|
||||
date: 2024-11-20
|
||||
versions: 0.63.3.dev
|
||||
seconds_per_case: 40.7
|
||||
total_cost: 0.1497
|
||||
|
||||
- dirname: 2024-09-20-21-47-17--qwen2.5-32b-instruct-q8_0-whole
|
||||
test_cases: 133
|
||||
model: ollama/qwen2.5:32b-instruct-q8_0
|
||||
edit_format: whole
|
||||
commit_hash: 2753ac6
|
||||
pass_rate_1: 46.6
|
||||
pass_rate_2: 58.6
|
||||
percent_cases_well_formed: 100.0
|
||||
error_outputs: 0
|
||||
num_malformed_responses: 0
|
||||
num_with_malformed_responses: 0
|
||||
user_asks: 1
|
||||
lazy_comments: 0
|
||||
syntax_errors: 0
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 2
|
||||
command: aider --model ollama/qwen2.5:32b-instruct-q8_0
|
||||
date: 2024-09-20
|
||||
versions: 0.56.1.dev
|
||||
seconds_per_case: 1763.7
|
||||
total_cost: 0.0000
|
||||
|
||||
- dirname: 2024-09-30-14-09-43--qwen2.5-32b-whole-2
|
||||
test_cases: 133
|
||||
model: ollama/qwen2.5:32b
|
||||
edit_format: whole
|
||||
commit_hash: 765c4cb
|
||||
pass_rate_1: 44.4
|
||||
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: 0
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 3
|
||||
command: aider --model ollama/qwen2.5:32b
|
||||
date: 2024-09-30
|
||||
versions: 0.58.1.dev
|
||||
seconds_per_case: 134.9
|
||||
total_cost: 0.0000
|
||||
|
||||
97
aider/website/_includes/edit-leaderboard.js
Normal file
97
aider/website/_includes/edit-leaderboard.js
Normal file
@@ -0,0 +1,97 @@
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
var ctx = document.getElementById('editChart').getContext('2d');
|
||||
const HIGHTLIGHT_MODEL = 'no no no no';
|
||||
var leaderboardData = {
|
||||
labels: [],
|
||||
datasets: [{
|
||||
label: 'Percent completed correctly',
|
||||
data: [],
|
||||
backgroundColor: function(context) {
|
||||
const label = context.chart.data.labels[context.dataIndex] || '';
|
||||
return (label && label.includes(HIGHTLIGHT_MODEL)) ? 'rgba(255, 99, 132, 0.2)' : 'rgba(54, 162, 235, 0.2)';
|
||||
},
|
||||
borderColor: function(context) {
|
||||
const label = context.chart.data.labels[context.dataIndex] || '';
|
||||
return (label && label.includes(HIGHTLIGHT_MODEL)) ? 'rgba(255, 99, 132, 1)' : '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: {
|
||||
y: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
updateChart();
|
||||
|
||||
// Add search functionality for edit table
|
||||
document.getElementById('editSearchInput').addEventListener('keyup', function() {
|
||||
var searchWords = this.value.toLowerCase().split(' ').filter(word => word.length > 0);
|
||||
var tableBody = document.querySelector('table:first-of-type tbody');
|
||||
var rows = tableBody.getElementsByTagName('tr');
|
||||
|
||||
leaderboardData.labels = [];
|
||||
leaderboardData.datasets[0].data = [];
|
||||
|
||||
for (var i = 0; i < rows.length; i++) {
|
||||
var rowText = rows[i].textContent;
|
||||
if (searchWords.every(word => rowText.toLowerCase().includes(word))) {
|
||||
rows[i].style.display = '';
|
||||
leaderboardData.labels.push(allData[i].model);
|
||||
leaderboardData.datasets[0].data.push(allData[i].pass_rate_2);
|
||||
} else {
|
||||
rows[i].style.display = 'none';
|
||||
}
|
||||
}
|
||||
leaderboardChart.update();
|
||||
});
|
||||
});
|
||||
0
aider/website/_includes/leaderboard.js
Normal file
0
aider/website/_includes/leaderboard.js
Normal file
@@ -1,5 +1,15 @@
|
||||
You can send long, multi-line messages in the chat in a few ways:
|
||||
- Paste a multi-line message directly into the chat.
|
||||
- Enter `{` alone on the first line to start a multiline message and `}` alone on the last line to end it.
|
||||
- Or, start with `{tag` (where "tag" is any sequence of letters/numbers) and end with `tag}`. This is useful when you need to include closing braces `}` in your message.
|
||||
- Use Meta-ENTER to start a new line without sending the message (Esc+ENTER in some environments).
|
||||
- Use `/paste` to paste text from the clipboard into the chat.
|
||||
- Use the `/editor` command to open your editor to create the next chat message. See [editor configuration docs](/docs/config/editor.html) for more info.
|
||||
|
||||
Example with a tag:
|
||||
```
|
||||
{python
|
||||
def hello():
|
||||
print("Hello}") # Note: contains a brace
|
||||
python}
|
||||
```
|
||||
|
||||
69
aider/website/_includes/quant-chart.js
Normal file
69
aider/website/_includes/quant-chart.js
Normal file
@@ -0,0 +1,69 @@
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
var ctx = document.getElementById('quantChart').getContext('2d');
|
||||
var chartData = {
|
||||
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 site.data.quant %}
|
||||
allData.push({
|
||||
model: '{{ row.model }}',
|
||||
pass_rate_2: {{ row.pass_rate_2 }}
|
||||
});
|
||||
{% endfor %}
|
||||
|
||||
allData.forEach(function(row) {
|
||||
chartData.labels.push(row.model);
|
||||
chartData.datasets[0].data.push(row.pass_rate_2);
|
||||
});
|
||||
|
||||
new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: chartData,
|
||||
options: {
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false
|
||||
},
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Aider coder editing benchmark',
|
||||
font: {
|
||||
size: 16
|
||||
}
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Percent completed correctly',
|
||||
font: {
|
||||
size: 14
|
||||
}
|
||||
},
|
||||
ticks: {
|
||||
font: {
|
||||
size: 16
|
||||
}
|
||||
}
|
||||
},
|
||||
x: {
|
||||
ticks: {
|
||||
font: {
|
||||
size: 16
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
90
aider/website/_includes/refactor-leaderboard.js
Normal file
90
aider/website/_includes/refactor-leaderboard.js
Normal file
@@ -0,0 +1,90 @@
|
||||
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: {
|
||||
y: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
updateChart();
|
||||
|
||||
// Add search functionality for refactoring table
|
||||
document.getElementById('refacSearchInput').addEventListener('keyup', function() {
|
||||
var searchWords = this.value.toLowerCase().split(' ').filter(word => word.length > 0);
|
||||
var tableBody = document.querySelectorAll('table tbody')[1];
|
||||
var rows = tableBody.getElementsByTagName('tr');
|
||||
|
||||
leaderboardData.labels = [];
|
||||
leaderboardData.datasets[0].data = [];
|
||||
|
||||
for (var i = 0; i < rows.length; i++) {
|
||||
var rowText = rows[i].textContent;
|
||||
if (searchWords.every(word => rowText.toLowerCase().includes(word))) {
|
||||
rows[i].style.display = '';
|
||||
leaderboardData.labels.push(allData[i].model);
|
||||
leaderboardData.datasets[0].data.push(allData[i].pass_rate_1);
|
||||
} else {
|
||||
rows[i].style.display = 'none';
|
||||
}
|
||||
}
|
||||
leaderboardChart.update();
|
||||
});
|
||||
});
|
||||
43
aider/website/_posts/2024-11-21-quantization.md
Normal file
43
aider/website/_posts/2024-11-21-quantization.md
Normal file
@@ -0,0 +1,43 @@
|
||||
---
|
||||
title: Quantization matters
|
||||
excerpt: Open source LLMs are becoming very powerful, but pay attention to how you (or your provider) is quantizing the model. It can strongly affect code editing skill.
|
||||
highlight_image: /assets/quantization.jpg
|
||||
draft: false
|
||||
nav_exclude: true
|
||||
---
|
||||
{% if page.date %}
|
||||
<p class="post-date">{{ page.date | date: "%B %d, %Y" }}</p>
|
||||
{% endif %}
|
||||
|
||||
# Quantization matters
|
||||
|
||||
Open source models like Qwen 2.5 32B are performing very well on
|
||||
aider's code editing benchmark, rivaling closed source frontier models.
|
||||
But pay attention to how your model is being quantized, as it
|
||||
can strongly impact code editing skill.
|
||||
Heavily quantized models are often used by cloud API providers
|
||||
and local model servers like Ollama.
|
||||
|
||||
<canvas id="quantChart" width="800" height="450" style="margin: 20px 0"></canvas>
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
<script>
|
||||
{% include quant-chart.js %}
|
||||
</script>
|
||||
|
||||
The graph above compares 4 different versions of the Qwen 2.5 32B model,
|
||||
served both locally and from cloud providers.
|
||||
|
||||
- The [HuggingFace weights](https://huggingface.co/Qwen/Qwen2.5-Coder-32B-Instruct) served via [glhf.chat](https://glhf.chat).
|
||||
- The results from [OpenRouter's mix of providers](https://openrouter.ai/qwen/qwen-2.5-coder-32b-instruct/providers).
|
||||
- Two Ollama models run locally.
|
||||
|
||||
The best version of the model rivals GPT-4o, while the worst performer
|
||||
is more like GPT-3.5 Turbo.
|
||||
|
||||
|
||||
## Choosing providers with OpenRouter
|
||||
|
||||
OpenRouter allows you to ignore specific providers in your
|
||||
[preferences](https://openrouter.ai/settings/preferences).
|
||||
This can be effective to exclude highly quantized or otherwise
|
||||
undesirable providers.
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 97 KiB |
File diff suppressed because it is too large
Load Diff
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 55 KiB |
BIN
aider/website/assets/quantization.jpg
Normal file
BIN
aider/website/assets/quantization.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 146 KiB |
File diff suppressed because it is too large
Load Diff
@@ -271,8 +271,8 @@
|
||||
############
|
||||
# Analytics:
|
||||
|
||||
## Enable/disable analytics for one session (default: False)
|
||||
#analytics: false
|
||||
## Enable/disable analytics for current session (default: random)
|
||||
#analytics: xxx
|
||||
|
||||
## Specify a file to log analytics events
|
||||
#analytics-log: xxx
|
||||
@@ -314,6 +314,9 @@
|
||||
## Check for new aider versions on launch
|
||||
#check-update: true
|
||||
|
||||
## Show release notes on first run of new version (default: None, ask user)
|
||||
#show-release-notes: xxx
|
||||
|
||||
## Install the latest version from the main branch
|
||||
#install-main-branch: false
|
||||
|
||||
@@ -365,6 +368,9 @@
|
||||
## Enable/disable fancy input with history and completion (default: True)
|
||||
#fancy-input: true
|
||||
|
||||
## Specify which editor to use for the /editor command
|
||||
#editor: xxx
|
||||
|
||||
#################
|
||||
# Voice Settings:
|
||||
|
||||
|
||||
@@ -270,8 +270,8 @@
|
||||
############
|
||||
# Analytics:
|
||||
|
||||
## Enable/disable analytics for one session (default: False)
|
||||
#AIDER_ANALYTICS=false
|
||||
## Enable/disable analytics for current session (default: random)
|
||||
#AIDER_ANALYTICS=
|
||||
|
||||
## Specify a file to log analytics events
|
||||
#AIDER_ANALYTICS_LOG=
|
||||
@@ -300,6 +300,9 @@
|
||||
## Check for new aider versions on launch
|
||||
#AIDER_CHECK_UPDATE=true
|
||||
|
||||
## Show release notes on first run of new version (default: None, ask user)
|
||||
#AIDER_SHOW_RELEASE_NOTES=
|
||||
|
||||
## Install the latest version from the main branch
|
||||
#AIDER_INSTALL_MAIN_BRANCH=false
|
||||
|
||||
@@ -348,6 +351,9 @@
|
||||
## Enable/disable fancy input with history and completion (default: True)
|
||||
#AIDER_FANCY_INPUT=true
|
||||
|
||||
## Specify which editor to use for the /editor command
|
||||
#AIDER_EDITOR=
|
||||
|
||||
#################
|
||||
# Voice Settings:
|
||||
|
||||
|
||||
@@ -55,8 +55,10 @@ These model settings are pre-configured for most popular models.
|
||||
But it can sometimes be helpful to override them or add settings for
|
||||
a model that aider doesn't know about.
|
||||
|
||||
To do that,
|
||||
create a `.aider.model.settings.yml` file in one of these locations:
|
||||
|
||||
### Configuration file locations
|
||||
|
||||
You can override or add settings for any model by creating a `.aider.model.settings.yml` file in one of these locations:
|
||||
|
||||
- Your home directory.
|
||||
- The root if your git repo.
|
||||
@@ -66,9 +68,31 @@ create a `.aider.model.settings.yml` file in one of these locations:
|
||||
If the files above exist, they will be loaded in that order.
|
||||
Files loaded last will take priority.
|
||||
|
||||
The yaml file should be a a list of dictionary objects for each model.
|
||||
For example, below are all the pre-configured model settings
|
||||
to give a sense for the settings which are supported.
|
||||
The yaml file should be a list of dictionary objects for each model.
|
||||
|
||||
|
||||
### Global extra params
|
||||
|
||||
You can use the special model name `aider/extra_params` to define
|
||||
`extra_params` that will be passed to `litellm.completion()` for all models.
|
||||
Only the `extra_params` dict is used from this special model name.
|
||||
|
||||
For example:
|
||||
|
||||
```yaml
|
||||
- name: aider/extra_params
|
||||
extra_params:
|
||||
extra_headers:
|
||||
Custom-Header: value
|
||||
max_tokens: 8192
|
||||
```
|
||||
|
||||
These settings will be merged with any model-specific settings, with the
|
||||
`aider/extra_params` settings taking precedence for any direct conflicts.
|
||||
|
||||
### Example model settings
|
||||
|
||||
Below are all the pre-configured model settings to give a sense for the settings which are supported.
|
||||
|
||||
You can also look at the `ModelSettings` class in
|
||||
[models.py](https://github.com/Aider-AI/aider/blob/main/aider/models.py)
|
||||
@@ -241,6 +265,38 @@ cog.out("```\n")
|
||||
use_system_prompt: true
|
||||
use_temperature: true
|
||||
weak_model_name: gpt-4o-mini
|
||||
- cache_control: false
|
||||
caches_by_default: false
|
||||
edit_format: diff
|
||||
editor_edit_format: null
|
||||
editor_model_name: null
|
||||
examples_as_sys_msg: false
|
||||
extra_params: null
|
||||
lazy: true
|
||||
name: gpt-4o-2024-11-20
|
||||
reminder: sys
|
||||
send_undo_reply: false
|
||||
streaming: true
|
||||
use_repo_map: true
|
||||
use_system_prompt: true
|
||||
use_temperature: true
|
||||
weak_model_name: gpt-4o-mini
|
||||
- cache_control: false
|
||||
caches_by_default: false
|
||||
edit_format: diff
|
||||
editor_edit_format: null
|
||||
editor_model_name: null
|
||||
examples_as_sys_msg: false
|
||||
extra_params: null
|
||||
lazy: true
|
||||
name: openai/gpt-4o-2024-11-20
|
||||
reminder: sys
|
||||
send_undo_reply: false
|
||||
streaming: true
|
||||
use_repo_map: true
|
||||
use_system_prompt: true
|
||||
use_temperature: true
|
||||
weak_model_name: gpt-4o-mini
|
||||
- cache_control: false
|
||||
caches_by_default: false
|
||||
edit_format: diff
|
||||
@@ -1057,7 +1113,7 @@ cog.out("```\n")
|
||||
name: openai/o1-mini
|
||||
reminder: user
|
||||
send_undo_reply: false
|
||||
streaming: false
|
||||
streaming: true
|
||||
use_repo_map: true
|
||||
use_system_prompt: false
|
||||
use_temperature: false
|
||||
@@ -1073,7 +1129,7 @@ cog.out("```\n")
|
||||
name: azure/o1-mini
|
||||
reminder: user
|
||||
send_undo_reply: false
|
||||
streaming: false
|
||||
streaming: true
|
||||
use_repo_map: true
|
||||
use_system_prompt: false
|
||||
use_temperature: false
|
||||
@@ -1089,7 +1145,7 @@ cog.out("```\n")
|
||||
name: o1-mini
|
||||
reminder: user
|
||||
send_undo_reply: false
|
||||
streaming: false
|
||||
streaming: true
|
||||
use_repo_map: true
|
||||
use_system_prompt: false
|
||||
use_temperature: false
|
||||
@@ -1105,7 +1161,7 @@ cog.out("```\n")
|
||||
name: openai/o1-preview
|
||||
reminder: user
|
||||
send_undo_reply: false
|
||||
streaming: false
|
||||
streaming: true
|
||||
use_repo_map: true
|
||||
use_system_prompt: false
|
||||
use_temperature: false
|
||||
@@ -1121,7 +1177,7 @@ cog.out("```\n")
|
||||
name: azure/o1-preview
|
||||
reminder: user
|
||||
send_undo_reply: false
|
||||
streaming: false
|
||||
streaming: true
|
||||
use_repo_map: true
|
||||
use_system_prompt: false
|
||||
use_temperature: false
|
||||
@@ -1137,7 +1193,7 @@ cog.out("```\n")
|
||||
name: o1-preview
|
||||
reminder: user
|
||||
send_undo_reply: false
|
||||
streaming: false
|
||||
streaming: true
|
||||
use_repo_map: true
|
||||
use_system_prompt: false
|
||||
use_temperature: false
|
||||
@@ -1153,7 +1209,7 @@ cog.out("```\n")
|
||||
name: openrouter/openai/o1-mini
|
||||
reminder: user
|
||||
send_undo_reply: false
|
||||
streaming: false
|
||||
streaming: true
|
||||
use_repo_map: true
|
||||
use_system_prompt: false
|
||||
use_temperature: false
|
||||
@@ -1169,7 +1225,7 @@ cog.out("```\n")
|
||||
name: openrouter/openai/o1-preview
|
||||
reminder: user
|
||||
send_undo_reply: false
|
||||
streaming: false
|
||||
streaming: true
|
||||
use_repo_map: true
|
||||
use_system_prompt: false
|
||||
use_temperature: false
|
||||
|
||||
@@ -327,8 +327,8 @@ cog.outl("```")
|
||||
############
|
||||
# Analytics:
|
||||
|
||||
## Enable/disable analytics for one session (default: False)
|
||||
#analytics: false
|
||||
## Enable/disable analytics for current session (default: random)
|
||||
#analytics: xxx
|
||||
|
||||
## Specify a file to log analytics events
|
||||
#analytics-log: xxx
|
||||
@@ -370,6 +370,9 @@ cog.outl("```")
|
||||
## Check for new aider versions on launch
|
||||
#check-update: true
|
||||
|
||||
## Show release notes on first run of new version (default: None, ask user)
|
||||
#show-release-notes: xxx
|
||||
|
||||
## Install the latest version from the main branch
|
||||
#install-main-branch: false
|
||||
|
||||
@@ -421,6 +424,9 @@ cog.outl("```")
|
||||
## Enable/disable fancy input with history and completion (default: True)
|
||||
#fancy-input: true
|
||||
|
||||
## Specify which editor to use for the /editor command
|
||||
#editor: xxx
|
||||
|
||||
#################
|
||||
# Voice Settings:
|
||||
|
||||
|
||||
@@ -312,8 +312,8 @@ cog.outl("```")
|
||||
############
|
||||
# Analytics:
|
||||
|
||||
## Enable/disable analytics for one session (default: False)
|
||||
#AIDER_ANALYTICS=false
|
||||
## Enable/disable analytics for current session (default: random)
|
||||
#AIDER_ANALYTICS=
|
||||
|
||||
## Specify a file to log analytics events
|
||||
#AIDER_ANALYTICS_LOG=
|
||||
@@ -342,6 +342,9 @@ cog.outl("```")
|
||||
## Check for new aider versions on launch
|
||||
#AIDER_CHECK_UPDATE=true
|
||||
|
||||
## Show release notes on first run of new version (default: None, ask user)
|
||||
#AIDER_SHOW_RELEASE_NOTES=
|
||||
|
||||
## Install the latest version from the main branch
|
||||
#AIDER_INSTALL_MAIN_BRANCH=false
|
||||
|
||||
@@ -390,6 +393,9 @@ cog.outl("```")
|
||||
## Enable/disable fancy input with history and completion (default: True)
|
||||
#AIDER_FANCY_INPUT=true
|
||||
|
||||
## Specify which editor to use for the /editor command
|
||||
#AIDER_EDITOR=
|
||||
|
||||
#################
|
||||
# Voice Settings:
|
||||
|
||||
|
||||
127
aider/website/docs/config/editor.md
Normal file
127
aider/website/docs/config/editor.md
Normal file
@@ -0,0 +1,127 @@
|
||||
---
|
||||
parent: Configuration
|
||||
nav_order: 15
|
||||
description: How to configure a custom editor for aider's /editor command
|
||||
---
|
||||
|
||||
# Editor configuration
|
||||
|
||||
Aider allows you to configure your preferred text editor for use with the `/editor` command. The editor must be capable of running in "blocking mode", meaning the command line will wait until you close the editor before proceeding.
|
||||
|
||||
## Using `--editor`
|
||||
|
||||
You can specify the text editor with the `--editor` switch or using
|
||||
`editor:` in aider's
|
||||
[yaml config file](https://aider.chat/docs/config/aider_conf.html).
|
||||
|
||||
## Environment variables
|
||||
|
||||
Aider checks the following environment variables in order to determine which editor to use:
|
||||
|
||||
1. `AIDER_EDITOR`
|
||||
2. `VISUAL`
|
||||
3. `EDITOR`
|
||||
|
||||
## Default behavior
|
||||
|
||||
If no editor is configured, aider will use these platform-specific defaults:
|
||||
|
||||
- Windows: `notepad`
|
||||
- macOS: `vim`
|
||||
- Linux/Unix: `vi`
|
||||
|
||||
## Using a custom editor
|
||||
|
||||
You can set your preferred editor in your shell's configuration file (e.g., `.bashrc`, `.zshrc`):
|
||||
|
||||
```bash
|
||||
export AIDER_EDITOR=vim
|
||||
```
|
||||
|
||||
## Popular Editors by Platform
|
||||
|
||||
### macOS
|
||||
|
||||
1. **vim**
|
||||
```bash
|
||||
export AIDER_EDITOR=vim
|
||||
```
|
||||
|
||||
2. **Emacs**
|
||||
```bash
|
||||
export AIDER_EDITOR=emacs
|
||||
```
|
||||
|
||||
3. **VSCode**
|
||||
```bash
|
||||
export AIDER_EDITOR="code --wait"
|
||||
```
|
||||
|
||||
4. **Sublime Text**
|
||||
```bash
|
||||
export AIDER_EDITOR="subl --wait"
|
||||
```
|
||||
|
||||
5. **BBEdit**
|
||||
```bash
|
||||
export AIDER_EDITOR="bbedit --wait"
|
||||
```
|
||||
|
||||
### Linux
|
||||
|
||||
1. **vim**
|
||||
```bash
|
||||
export AIDER_EDITOR=vim
|
||||
```
|
||||
|
||||
2. **Emacs**
|
||||
```bash
|
||||
export AIDER_EDITOR=emacs
|
||||
```
|
||||
|
||||
3. **nano**
|
||||
```bash
|
||||
export AIDER_EDITOR=nano
|
||||
```
|
||||
|
||||
4. **VSCode**
|
||||
```bash
|
||||
export AIDER_EDITOR="code --wait"
|
||||
```
|
||||
|
||||
5. **Sublime Text**
|
||||
```bash
|
||||
export AIDER_EDITOR="subl --wait"
|
||||
```
|
||||
|
||||
### Windows
|
||||
|
||||
1. **Notepad**
|
||||
```bat
|
||||
set AIDER_EDITOR=notepad
|
||||
```
|
||||
|
||||
2. **VSCode**
|
||||
```bat
|
||||
set AIDER_EDITOR="code --wait"
|
||||
```
|
||||
|
||||
3. **Notepad++**
|
||||
```bat
|
||||
set AIDER_EDITOR="notepad++ -multiInst -notabbar -nosession -noPlugin -waitForClose"
|
||||
```
|
||||
|
||||
## Editor command arguments
|
||||
|
||||
Some editors require specific command-line arguments to operate in blocking mode. The `--wait` flag (or equivalent) is commonly used to make the editor block until the file is closed.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If you encounter issues with your editor not blocking (returning to the prompt immediately), verify that:
|
||||
|
||||
1. Your editor supports blocking mode
|
||||
2. You've included the necessary command-line arguments for blocking mode
|
||||
3. The editor command is properly quoted if it contains spaces or special characters, e.g.:
|
||||
```bash
|
||||
export AIDER_EDITOR="code --wait"
|
||||
```
|
||||
@@ -66,14 +66,15 @@ usage: aider [-h] [--openai-api-key] [--anthropic-api-key] [--model]
|
||||
[--analytics-disable] [--file] [--read] [--vim]
|
||||
[--chat-language] [--version] [--just-check-update]
|
||||
[--check-update | --no-check-update]
|
||||
[--show-release-notes | --no-show-release-notes]
|
||||
[--install-main-branch] [--upgrade] [--apply]
|
||||
[--apply-clipboard-edits] [--yes-always] [-v]
|
||||
[--show-repo-map] [--show-prompts] [--exit] [--message]
|
||||
[--message-file] [--load] [--encoding] [-c]
|
||||
[--gui | --no-gui | --browser | --no-browser]
|
||||
[--suggest-shell-commands | --no-suggest-shell-commands]
|
||||
[--fancy-input | --no-fancy-input] [--voice-format]
|
||||
[--voice-language]
|
||||
[--fancy-input | --no-fancy-input] [--editor]
|
||||
[--voice-format] [--voice-language]
|
||||
|
||||
```
|
||||
|
||||
@@ -510,8 +511,7 @@ Environment variable: `AIDER_TEST`
|
||||
## Analytics:
|
||||
|
||||
### `--analytics`
|
||||
Enable/disable analytics for one session (default: False)
|
||||
Default: False
|
||||
Enable/disable analytics for current session (default: random)
|
||||
Environment variable: `AIDER_ANALYTICS`
|
||||
Aliases:
|
||||
- `--analytics`
|
||||
@@ -561,6 +561,13 @@ Aliases:
|
||||
- `--check-update`
|
||||
- `--no-check-update`
|
||||
|
||||
### `--show-release-notes`
|
||||
Show release notes on first run of new version (default: None, ask user)
|
||||
Environment variable: `AIDER_SHOW_RELEASE_NOTES`
|
||||
Aliases:
|
||||
- `--show-release-notes`
|
||||
- `--no-show-release-notes`
|
||||
|
||||
### `--install-main-branch`
|
||||
Install the latest version from the main branch
|
||||
Default: False
|
||||
@@ -666,6 +673,10 @@ Aliases:
|
||||
- `--fancy-input`
|
||||
- `--no-fancy-input`
|
||||
|
||||
### `--editor VALUE`
|
||||
Specify which editor to use for the /editor command
|
||||
Environment variable: `AIDER_EDITOR`
|
||||
|
||||
## Voice Settings:
|
||||
|
||||
### `--voice-format VOICE_FORMAT`
|
||||
|
||||
@@ -60,6 +60,23 @@ directory you start in.
|
||||
You can also create a `.aiderignore` file to tell aider
|
||||
to ignore parts of the repo that aren't relevant to your task.
|
||||
This file conforms to `.gitignore` syntax and conventions.
|
||||
For example, to focus only on specific directories in a monorepo,
|
||||
you could create a `.aiderignore` file with:
|
||||
|
||||
```
|
||||
# Ignore everything
|
||||
/*
|
||||
|
||||
# Allow specific directories and their contents
|
||||
!foo/
|
||||
!bar/
|
||||
!baz/
|
||||
|
||||
# Allow nested files under these directories
|
||||
!foo/**
|
||||
!bar/**
|
||||
!baz/**
|
||||
```
|
||||
|
||||
You can use `--aiderignore <filename>` to name a specific file
|
||||
to use for ignore patterns.
|
||||
|
||||
@@ -31,6 +31,8 @@ This measures the LLM's coding ability, and whether it can
|
||||
write new code that integrates into existing code.
|
||||
The model also has to successfully apply all its changes to the source file without human intervention.
|
||||
|
||||
<input type="text" id="editSearchInput" placeholder="Search..." style="width: 100%; max-width: 800px; margin: 10px auto; padding: 8px; display: block; border: 1px solid #ddd; border-radius: 4px;">
|
||||
|
||||
<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>
|
||||
@@ -58,81 +60,7 @@ The model also has to successfully apply all its changes to the source file with
|
||||
<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');
|
||||
const HIGHTLIGHT_MODEL = 'no no no no';
|
||||
var leaderboardData = {
|
||||
labels: [],
|
||||
datasets: [{
|
||||
label: 'Percent completed correctly',
|
||||
data: [],
|
||||
backgroundColor: function(context) {
|
||||
const label = context.chart.data.labels[context.dataIndex] || '';
|
||||
return (label && label.includes(HIGHTLIGHT_MODEL)) ? 'rgba(255, 99, 132, 0.2)' : 'rgba(54, 162, 235, 0.2)';
|
||||
},
|
||||
borderColor: function(context) {
|
||||
const label = context.chart.data.labels[context.dataIndex] || '';
|
||||
return (label && label.includes(HIGHTLIGHT_MODEL)) ? 'rgba(255, 99, 132, 1)' : '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: {
|
||||
y: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
updateChart();
|
||||
});
|
||||
{% include edit-leaderboard.js %}
|
||||
</script>
|
||||
<style>
|
||||
tr.selected {
|
||||
@@ -158,6 +86,8 @@ The refactoring benchmark requires a large context window to
|
||||
work with large source files.
|
||||
Therefore, results are available for fewer models.
|
||||
|
||||
<input type="text" id="refacSearchInput" placeholder="Search..." style="width: 100%; max-width: 800px; margin: 10px auto; padding: 8px; display: block; border: 1px solid #ddd; border-radius: 4px;">
|
||||
|
||||
<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>
|
||||
@@ -185,74 +115,7 @@ Therefore, results are available for fewer models.
|
||||
<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: {
|
||||
y: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
updateChart();
|
||||
});
|
||||
{% include refactor-leaderboard.js %}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -318,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.')}")
|
||||
]]]-->
|
||||
November 11, 2024.
|
||||
November 21, 2024.
|
||||
<!--[[[end]]]-->
|
||||
</p>
|
||||
|
||||
24
aider/website/docs/llms/xai.md
Normal file
24
aider/website/docs/llms/xai.md
Normal file
@@ -0,0 +1,24 @@
|
||||
---
|
||||
parent: Connecting to LLMs
|
||||
nav_order: 400
|
||||
---
|
||||
|
||||
# xAI
|
||||
|
||||
You'll need a [xAI API key](https://console.x.ai.).
|
||||
|
||||
To use xAI:
|
||||
|
||||
```
|
||||
python -m pip install -U aider-chat
|
||||
|
||||
export XAI_API_KEY=<key> # Mac/Linux
|
||||
setx XAI_API_KEY <key> # Windows, restart shell after setx
|
||||
|
||||
aider --model xai/groq-beta
|
||||
|
||||
# List models available from xAI
|
||||
aider --list-models groq/
|
||||
```
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ features and commands are most used.
|
||||
It also helps uncover bugs that users are experiencing, so that they can be fixed
|
||||
in upcoming releases.
|
||||
|
||||
## Enabling & disabling analytics
|
||||
## Disabling analytics
|
||||
|
||||
You can opt out of analytics forever by running this command one time:
|
||||
|
||||
@@ -39,10 +39,27 @@ You can opt out of analytics forever by running this command one time:
|
||||
aider --analytics-disable
|
||||
```
|
||||
|
||||
To enable analytics for a single session, you can run aider with `--analytics`.
|
||||
This will *not* have any effect if you have permanently disabled analytics with the previous command.
|
||||
## Enabling analytics
|
||||
|
||||
The first time, you will need to agree to opt-in.
|
||||
The `--[no-]analytics` switch controls whether analytics are enabled for the
|
||||
current session:
|
||||
|
||||
- `--analytics` will turn on analytics for the current session.
|
||||
This will *not* have any effect if you have permanently disabled analytics
|
||||
with `--analytics-disable`.
|
||||
If this is the first time you have enabled analytics, aider
|
||||
will confirm you wish to opt-in to analytics.
|
||||
- `--no-analytics` will turn off analytics for the current session.
|
||||
- By default, if you don't provide `--analytics` or `--no-analytics`,
|
||||
aider will enable analytics for a random subset of users.
|
||||
This will never happen if you have permanently disabled analytics
|
||||
with `--analytics-disable`.
|
||||
Randomly selected users will be asked if they wish to opt-in to analytics.
|
||||
|
||||
|
||||
## Opting in
|
||||
|
||||
The first time analytics are enabled, you will need to agree to opt-in.
|
||||
|
||||
```
|
||||
aider --analytics
|
||||
@@ -53,13 +70,8 @@ For more info: https://aider.chat/docs/more/analytics.html
|
||||
Allow collection of anonymous analytics to help improve aider? (Y)es/(N)o [Yes]:
|
||||
```
|
||||
|
||||
If you've added `analytics: true` to your
|
||||
[yaml config file](/docs/config/aider_conf.html),
|
||||
you can disable analytics for a single session, you can run:
|
||||
If you say "no", analytics will be permanently disabled.
|
||||
|
||||
```
|
||||
aider --no-analytics
|
||||
```
|
||||
|
||||
## Details about data being collected
|
||||
|
||||
|
||||
@@ -57,7 +57,6 @@ cog.out(model_list)
|
||||
]]]-->
|
||||
- anthropic.claude-3-5-haiku-20241022-v1:0
|
||||
- anthropic.claude-3-5-sonnet-20241022-v2:0
|
||||
- anthropic/claude-3-5-sonnet-20241022
|
||||
- claude-3-5-haiku-20241022
|
||||
- claude-3-5-sonnet-20240620
|
||||
- claude-3-5-sonnet-20241022
|
||||
@@ -91,11 +90,17 @@ cog.out(model_list)
|
||||
- openrouter/anthropic/claude-3.5-sonnet
|
||||
- us.anthropic.claude-3-5-haiku-20241022-v1:0
|
||||
- us.anthropic.claude-3-5-sonnet-20241022-v2:0
|
||||
- vertex_ai/claude-3-5-haiku
|
||||
- vertex_ai/claude-3-5-haiku@20241022
|
||||
- vertex_ai/claude-3-5-sonnet
|
||||
- vertex_ai/claude-3-5-sonnet-v2
|
||||
- vertex_ai/claude-3-5-sonnet-v2@20241022
|
||||
- vertex_ai/claude-3-5-sonnet@20240620
|
||||
- vertex_ai/claude-3-haiku
|
||||
- vertex_ai/claude-3-haiku@20240307
|
||||
- vertex_ai/claude-3-opus
|
||||
- vertex_ai/claude-3-opus@20240229
|
||||
- vertex_ai/claude-3-sonnet
|
||||
- vertex_ai/claude-3-sonnet@20240229
|
||||
<!--[[[end]]]-->
|
||||
|
||||
|
||||
@@ -3,7 +3,14 @@ parent: Usage
|
||||
nav_order: 50
|
||||
description: Control aider with in-chat commands like /add, /model, etc.
|
||||
---
|
||||
|
||||
# In-chat commands
|
||||
{: .no_toc }
|
||||
|
||||
- TOC
|
||||
{:toc}
|
||||
|
||||
## Slash commands
|
||||
|
||||
Aider supports commands from within the chat, which all start with `/`.
|
||||
|
||||
@@ -24,6 +31,7 @@ cog.out(get_help_md())
|
||||
| **/copy** | Copy the last assistant message to the clipboard |
|
||||
| **/diff** | Display the diff of changes since the last message |
|
||||
| **/drop** | Remove files from the chat session to free up context space |
|
||||
| **/editor** | Open an editor to write a prompt |
|
||||
| **/exit** | Exit the application |
|
||||
| **/git** | Run a git command (output excluded from chat) |
|
||||
| **/help** | Ask questions about aider |
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
nav_exclude: true
|
||||
---
|
||||
|
||||
<meta http-equiv="Content-Security-Policy"
|
||||
content="default-src 'self';
|
||||
script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://cdnjs.cloudflare.com;
|
||||
connect-src http: https:;
|
||||
style-src 'self' 'unsafe-inline';">
|
||||
|
||||
# Shared aider chat transcript
|
||||
|
||||
A user has shared the following transcript of a pair programming chat session
|
||||
@@ -37,11 +43,29 @@ print("goodbye")
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/dompurify/3.0.6/purify.min.js"></script>
|
||||
<script>
|
||||
function isValidUrl(url) {
|
||||
try {
|
||||
const urlObj = new URL(url);
|
||||
return urlObj.protocol === 'http:' || urlObj.protocol === 'https:';
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Configure marked with secure defaults
|
||||
marked.setOptions({
|
||||
headerIds: false,
|
||||
mangle: false
|
||||
});
|
||||
|
||||
window.onload = function() {
|
||||
var urlParams = new URLSearchParams(window.location.search);
|
||||
var conv = urlParams.get('mdurl');
|
||||
if (!conv) {
|
||||
if (!conv || !isValidUrl(conv)) {
|
||||
document.querySelector('#shared-transcript').innerHTML =
|
||||
'<div style="color: red; padding: 1em;">Error: Invalid or missing URL provided</div>';
|
||||
return;
|
||||
}
|
||||
document.getElementById('mdurl').href = conv;
|
||||
@@ -63,11 +87,14 @@ window.onload = function() {
|
||||
return line;
|
||||
}).join('\n');
|
||||
var html = marked.parse(markdown);
|
||||
var sanitizedHtml = DOMPurify.sanitize(html);
|
||||
var divElement = document.querySelector('#shared-transcript');
|
||||
divElement.innerHTML = html;
|
||||
divElement.innerHTML = sanitizedHtml;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching markdown:', error);
|
||||
document.querySelector('#shared-transcript').innerHTML =
|
||||
'<div style="color: red; padding: 1em;">Error: Failed to load chat transcript</div>';
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -5,6 +5,33 @@ from matplotlib import rc
|
||||
|
||||
from aider.dump import dump # noqa: 401
|
||||
|
||||
LABEL_FONT_SIZE = 16 # Font size for scatter plot dot labels
|
||||
|
||||
|
||||
def get_legend_label(model):
|
||||
model = model.lower()
|
||||
if "claude-3-sonnet" in model:
|
||||
return "Sonnet"
|
||||
if "o1-preview" in model:
|
||||
return "O1 Preview"
|
||||
if "gpt-3.5" in model:
|
||||
return "GPT-3.5 Turbo"
|
||||
if "gpt-4-" in model and "-4o" not in model:
|
||||
return "GPT-4"
|
||||
if "qwen" in model:
|
||||
return "Qwen"
|
||||
if "-4o" in model:
|
||||
return "GPT-4o"
|
||||
if "haiku" in model:
|
||||
return "Haiku"
|
||||
if "deepseek" in model:
|
||||
return "DeepSeek"
|
||||
if "mistral" in model:
|
||||
return "Mistral"
|
||||
if "o1-preview" in model:
|
||||
return "o1-preview"
|
||||
return model
|
||||
|
||||
|
||||
def get_model_color(model):
|
||||
default = "lightblue"
|
||||
@@ -12,6 +39,21 @@ def get_model_color(model):
|
||||
if model == "gpt-4o-mini":
|
||||
return default
|
||||
|
||||
if "qwen" in model.lower():
|
||||
return "darkblue"
|
||||
|
||||
if "mistral" in model.lower():
|
||||
return "cyan"
|
||||
|
||||
if "haiku" in model.lower():
|
||||
return "pink"
|
||||
|
||||
if "deepseek" in model.lower():
|
||||
return "brown"
|
||||
|
||||
if "sonnet" in model.lower():
|
||||
return "orange"
|
||||
|
||||
if "-4o" in model:
|
||||
return "purple"
|
||||
|
||||
@@ -59,7 +101,7 @@ def plot_over_time(yaml_file):
|
||||
rc("font", **{"family": "sans-serif", "sans-serif": ["Helvetica"], "size": 10})
|
||||
plt.rcParams["text.color"] = "#444444"
|
||||
|
||||
fig, ax = plt.subplots(figsize=(12, 6)) # Increase figure size for better visibility
|
||||
fig, ax = plt.subplots(figsize=(12, 8)) # Make figure square
|
||||
|
||||
print("Debug: Figure created. Plotting data...")
|
||||
ax.grid(axis="y", zorder=0, lw=0.2)
|
||||
@@ -73,39 +115,154 @@ def plot_over_time(yaml_file):
|
||||
purple_points = [(d, r) for d, r, c in zip(dates, pass_rates, colors) if c == "purple"]
|
||||
red_points = [(d, r) for d, r, c in zip(dates, pass_rates, colors) if c == "red"]
|
||||
green_points = [(d, r) for d, r, c in zip(dates, pass_rates, colors) if c == "green"]
|
||||
orange_points = [(d, r) for d, r, c in zip(dates, pass_rates, colors) if c == "orange"]
|
||||
brown_points = [(d, r) for d, r, c in zip(dates, pass_rates, colors) if c == "brown"]
|
||||
pink_points = [(d, r) for d, r, c in zip(dates, pass_rates, colors) if c == "pink"]
|
||||
qwen_points = [(d, r) for d, r, c in zip(dates, pass_rates, colors) if c == "darkblue"]
|
||||
mistral_points = [(d, r) for d, r, c in zip(dates, pass_rates, colors) if c == "cyan"]
|
||||
|
||||
# Plot lines for purple, red, and green points
|
||||
# Create a mapping of colors to first points and labels
|
||||
color_to_first_point = {}
|
||||
color_to_label = {}
|
||||
|
||||
for date, rate, color, model in sorted(zip(dates, pass_rates, colors, models)):
|
||||
if color not in color_to_first_point:
|
||||
color_to_first_point[color] = (date, rate)
|
||||
color_to_label[color] = get_legend_label(model)
|
||||
|
||||
# Plot lines and add labels at first points
|
||||
if purple_points:
|
||||
purple_dates, purple_rates = zip(*sorted(purple_points))
|
||||
ax.plot(purple_dates, purple_rates, c="purple", alpha=0.5, linewidth=1)
|
||||
if "purple" in color_to_first_point:
|
||||
date, rate = color_to_first_point["purple"]
|
||||
ax.annotate(
|
||||
color_to_label["purple"],
|
||||
(date, rate),
|
||||
xytext=(10, 5),
|
||||
textcoords="offset points",
|
||||
color="purple",
|
||||
alpha=0.8,
|
||||
fontsize=LABEL_FONT_SIZE,
|
||||
)
|
||||
|
||||
if red_points:
|
||||
red_dates, red_rates = zip(*sorted(red_points))
|
||||
ax.plot(red_dates, red_rates, c="red", alpha=0.5, linewidth=1)
|
||||
if "red" in color_to_first_point:
|
||||
date, rate = color_to_first_point["red"]
|
||||
ax.annotate(
|
||||
color_to_label["red"],
|
||||
(date, rate),
|
||||
xytext=(10, 5),
|
||||
textcoords="offset points",
|
||||
color="red",
|
||||
alpha=0.8,
|
||||
fontsize=LABEL_FONT_SIZE,
|
||||
)
|
||||
|
||||
if green_points:
|
||||
green_dates, green_rates = zip(*sorted(green_points))
|
||||
ax.plot(green_dates, green_rates, c="green", alpha=0.5, linewidth=1)
|
||||
if "green" in color_to_first_point:
|
||||
date, rate = color_to_first_point["green"]
|
||||
ax.annotate(
|
||||
color_to_label["green"],
|
||||
(date, rate),
|
||||
xytext=(10, 5),
|
||||
textcoords="offset points",
|
||||
color="green",
|
||||
alpha=0.8,
|
||||
fontsize=LABEL_FONT_SIZE,
|
||||
)
|
||||
|
||||
# Plot all points
|
||||
ax.scatter(dates, pass_rates, c=colors, alpha=0.5, s=120)
|
||||
if orange_points:
|
||||
orange_dates, orange_rates = zip(*sorted(orange_points))
|
||||
ax.plot(orange_dates, orange_rates, c="orange", alpha=0.5, linewidth=1)
|
||||
if "orange" in color_to_first_point:
|
||||
date, rate = color_to_first_point["orange"]
|
||||
ax.annotate(
|
||||
color_to_label["orange"],
|
||||
(date, rate),
|
||||
xytext=(10, 5),
|
||||
textcoords="offset points",
|
||||
color="orange",
|
||||
alpha=0.8,
|
||||
fontsize=LABEL_FONT_SIZE,
|
||||
)
|
||||
|
||||
for i, model in enumerate(models):
|
||||
ax.annotate(
|
||||
model,
|
||||
(dates[i], pass_rates[i]),
|
||||
fontsize=8,
|
||||
alpha=0.75,
|
||||
xytext=(5, 5),
|
||||
textcoords="offset points",
|
||||
)
|
||||
if brown_points:
|
||||
brown_dates, brown_rates = zip(*sorted(brown_points))
|
||||
ax.plot(brown_dates, brown_rates, c="brown", alpha=0.5, linewidth=1)
|
||||
if "brown" in color_to_first_point:
|
||||
date, rate = color_to_first_point["brown"]
|
||||
ax.annotate(
|
||||
color_to_label["brown"],
|
||||
(date, rate),
|
||||
xytext=(10, -10),
|
||||
textcoords="offset points",
|
||||
color="brown",
|
||||
alpha=0.8,
|
||||
fontsize=LABEL_FONT_SIZE,
|
||||
)
|
||||
|
||||
if pink_points:
|
||||
pink_dates, pink_rates = zip(*sorted(pink_points))
|
||||
ax.plot(pink_dates, pink_rates, c="pink", alpha=0.5, linewidth=1)
|
||||
if "pink" in color_to_first_point:
|
||||
date, rate = color_to_first_point["pink"]
|
||||
ax.annotate(
|
||||
color_to_label["pink"],
|
||||
(date, rate),
|
||||
xytext=(10, 5),
|
||||
textcoords="offset points",
|
||||
color="pink",
|
||||
alpha=0.8,
|
||||
fontsize=LABEL_FONT_SIZE,
|
||||
)
|
||||
|
||||
if qwen_points:
|
||||
qwen_dates, qwen_rates = zip(*sorted(qwen_points))
|
||||
ax.plot(qwen_dates, qwen_rates, c="darkblue", alpha=0.5, linewidth=1)
|
||||
if "darkblue" in color_to_first_point:
|
||||
date, rate = color_to_first_point["darkblue"]
|
||||
ax.annotate(
|
||||
color_to_label["darkblue"],
|
||||
(date, rate),
|
||||
xytext=(10, 5),
|
||||
textcoords="offset points",
|
||||
color="darkblue",
|
||||
alpha=0.8,
|
||||
fontsize=LABEL_FONT_SIZE,
|
||||
)
|
||||
|
||||
if mistral_points:
|
||||
mistral_dates, mistral_rates = zip(*sorted(mistral_points))
|
||||
ax.plot(mistral_dates, mistral_rates, c="cyan", alpha=0.5, linewidth=1)
|
||||
if "cyan" in color_to_first_point:
|
||||
date, rate = color_to_first_point["cyan"]
|
||||
ax.annotate(
|
||||
color_to_label["cyan"],
|
||||
(date, rate),
|
||||
xytext=(10, -10),
|
||||
textcoords="offset points",
|
||||
color="cyan",
|
||||
alpha=0.8,
|
||||
fontsize=LABEL_FONT_SIZE,
|
||||
)
|
||||
|
||||
# Plot points without legend
|
||||
for date, rate, color in zip(dates, pass_rates, colors):
|
||||
ax.scatter([date], [rate], c=[color], alpha=0.5, s=120)
|
||||
|
||||
ax.set_xlabel("Model release date", fontsize=18, color="#555")
|
||||
ax.set_ylabel(
|
||||
"Aider code editing benchmark,\npercent completed correctly", fontsize=18, color="#555"
|
||||
)
|
||||
ax.set_title("LLM code editing skill by model release date", fontsize=20)
|
||||
ax.set_ylim(0, 100) # Adjust y-axis limit to accommodate higher values
|
||||
ax.set_ylim(30, 90) # Adjust y-axis limit to accommodate higher values
|
||||
plt.xticks(fontsize=14, rotation=45, ha="right") # Rotate x-axis labels for better readability
|
||||
plt.tight_layout(pad=3.0)
|
||||
plt.tight_layout(pad=1.0) # Adjust layout since we don't need room for legend anymore
|
||||
|
||||
print("Debug: Saving figures...")
|
||||
plt.savefig("tmp_over_time.png")
|
||||
|
||||
@@ -58,6 +58,7 @@ include = ["aider*", "aider.website"]
|
||||
"docs/unified-diffs.md",
|
||||
"docs/leaderboards/index.md",
|
||||
"assets/**",
|
||||
"**/.DS_Store",
|
||||
# [[[end]]]
|
||||
]
|
||||
|
||||
|
||||
@@ -23,8 +23,10 @@ def blame(start_tag, end_tag=None):
|
||||
files = [
|
||||
f
|
||||
for f in files
|
||||
if f.endswith((".py", ".scm", ".sh", "Dockerfile", "Gemfile"))
|
||||
if f.endswith((".js", ".py", ".scm", ".sh", "Dockerfile", "Gemfile"))
|
||||
or (f.startswith(".github/workflows/") and f.endswith(".yml"))
|
||||
or f == "aider/website/share/index.md"
|
||||
or f == "aider/website/docs/leaderboards/index.md"
|
||||
]
|
||||
files = [f for f in files if not f.endswith("prompts.py")]
|
||||
|
||||
|
||||
@@ -22,15 +22,27 @@ def has_been_reopened(issue_number):
|
||||
# Load environment variables from .env file
|
||||
load_dotenv()
|
||||
|
||||
DUPLICATE_COMMENT = """Thanks for trying aider and filing this issue.
|
||||
BOT_SUFFIX = """Note: A [bot script](https://github.com/Aider-AI/aider/blob/main/scripts/issues.py) made these updates to the issue.
|
||||
""" # noqa
|
||||
|
||||
DUPLICATE_COMMENT = (
|
||||
"""Thanks for trying aider and filing this issue.
|
||||
|
||||
This looks like a duplicate of #{oldest_issue_number}. Please see the comments there for more information, and feel free to continue the discussion within that issue.
|
||||
|
||||
I'm going to close this issue for now. But please let me know if you think this is actually a distinct issue and I will reopen this issue.""" # noqa
|
||||
+ BOT_SUFFIX
|
||||
)
|
||||
|
||||
STALE_COMMENT = """I'm labeling this issue as stale because it has been open for 2 weeks with no activity. If there are no additional comments, it will be closed in 7 days.""" # noqa
|
||||
STALE_COMMENT = (
|
||||
"""I'm labeling this issue as stale because it has been open for 2 weeks with no activity. If there are no additional comments, I will close it in 7 days.""" # noqa
|
||||
+ BOT_SUFFIX
|
||||
)
|
||||
|
||||
CLOSE_STALE_COMMENT = """I'm closing this issue because it has been stalled for 3 weeks with no activity. Feel free to add a comment here and we can re-open it. Or feel free to file a new issue at any time.""" # noqa
|
||||
CLOSE_STALE_COMMENT = (
|
||||
"""I'm closing this issue because it has been stalled for 3 weeks with no activity. Feel free to add a comment here and we can re-open it. Or feel free to file a new issue at any time.""" # noqa
|
||||
+ BOT_SUFFIX
|
||||
)
|
||||
|
||||
# GitHub API configuration
|
||||
GITHUB_API_URL = "https://api.github.com"
|
||||
@@ -279,7 +291,7 @@ def handle_stale_closing(all_issues, auto_yes):
|
||||
continue
|
||||
|
||||
# Add closing comment
|
||||
comment_url = f"{GITHUB_API_URL}/repos/{REPO_OWNER}/{REPO_NAME}/issues/{issue['number']}/comments"
|
||||
comment_url = f"{GITHUB_API_URL}/repos/{REPO_OWNER}/{REPO_NAME}/issues/{issue['number']}/comments" # noqa
|
||||
response = requests.post(
|
||||
comment_url, headers=headers, json={"body": CLOSE_STALE_COMMENT}
|
||||
)
|
||||
|
||||
@@ -124,7 +124,10 @@ def main():
|
||||
for cmd in git_commands:
|
||||
print(f"Running: {' '.join(cmd)}")
|
||||
if not dry_run:
|
||||
subprocess.run(cmd, check=True)
|
||||
subprocess.run(
|
||||
cmd,
|
||||
check=True,
|
||||
)
|
||||
|
||||
new_dev_version = f"{incremented_version}.dev"
|
||||
updated_dev_content = re.sub(
|
||||
|
||||
@@ -91,10 +91,49 @@ def test_system_info(temp_data_dir):
|
||||
|
||||
def test_need_to_ask(temp_data_dir):
|
||||
analytics = Analytics()
|
||||
assert analytics.need_to_ask() is True
|
||||
assert analytics.need_to_ask(True) is True
|
||||
assert analytics.need_to_ask(False) is False
|
||||
|
||||
analytics.user_id = "111"
|
||||
assert analytics.need_to_ask(None) is False
|
||||
|
||||
analytics.user_id = "000"
|
||||
assert analytics.need_to_ask(None) is True
|
||||
|
||||
analytics.asked_opt_in = True
|
||||
assert analytics.need_to_ask() is False
|
||||
assert analytics.need_to_ask(True) is False
|
||||
|
||||
analytics.permanently_disable = True
|
||||
assert analytics.need_to_ask() is False
|
||||
assert analytics.need_to_ask(True) is False
|
||||
|
||||
|
||||
def test_is_uuid_in_percentage():
|
||||
analytics = Analytics()
|
||||
|
||||
# Test basic percentage thresholds
|
||||
assert analytics.is_uuid_in_percentage("00000000000000000000000000000000", 1) is True
|
||||
assert analytics.is_uuid_in_percentage("01999000000000000000000000000000", 1) is True
|
||||
assert analytics.is_uuid_in_percentage("02000000000000000000000000000000", 1) is True
|
||||
assert analytics.is_uuid_in_percentage("02910000000000000000000000000001", 1) is False
|
||||
assert analytics.is_uuid_in_percentage("03000000000000000000000000000000", 1) is False
|
||||
assert analytics.is_uuid_in_percentage("ff000000000000000000000000000000", 1) is False
|
||||
|
||||
assert analytics.is_uuid_in_percentage("00000000000000000000000000000000", 10) is True
|
||||
assert analytics.is_uuid_in_percentage("19000000000000000000000000000000", 10) is True
|
||||
assert analytics.is_uuid_in_percentage("1a000000000000000000000000000000", 10) is False
|
||||
assert analytics.is_uuid_in_percentage("ff000000000000000000000000000000", 10) is False
|
||||
|
||||
# Test edge cases
|
||||
assert analytics.is_uuid_in_percentage("00000000000000000000000000000000", 0) is False
|
||||
assert analytics.is_uuid_in_percentage("00000000000000000000000000000000", 100) is True
|
||||
assert analytics.is_uuid_in_percentage("ffffffffffffffffffffffffffffffff", 100) is True
|
||||
|
||||
# Test invalid inputs
|
||||
with pytest.raises(ValueError):
|
||||
analytics.is_uuid_in_percentage("00000000000000000000000000000000", -1)
|
||||
with pytest.raises(ValueError):
|
||||
analytics.is_uuid_in_percentage("00000000000000000000000000000000", 101)
|
||||
|
||||
# Test empty/None UUID
|
||||
assert analytics.is_uuid_in_percentage("", 50) is False
|
||||
assert analytics.is_uuid_in_percentage(None, 50) is False
|
||||
|
||||
@@ -1068,8 +1068,10 @@ class TestCommands(TestCase):
|
||||
io.prompt_ask = lambda *args, **kwargs: "y"
|
||||
|
||||
# Test the cmd_run method with a command that should not raise an error
|
||||
result = commands.cmd_run("exit 1", add_on_nonzero_exit=True)
|
||||
self.assertIn("I ran this command", result)
|
||||
commands.cmd_run("exit 1", add_on_nonzero_exit=True)
|
||||
|
||||
# Check that the output was added to cur_messages
|
||||
self.assertTrue(any("exit 1" in msg["content"] for msg in coder.cur_messages))
|
||||
|
||||
def test_cmd_add_drop_untracked_files(self):
|
||||
with GitTemporaryDirectory():
|
||||
|
||||
129
tests/basic/test_editor.py
Normal file
129
tests/basic/test_editor.py
Normal file
@@ -0,0 +1,129 @@
|
||||
import os
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from aider.editor import (
|
||||
DEFAULT_EDITOR_NIX,
|
||||
DEFAULT_EDITOR_OS_X,
|
||||
DEFAULT_EDITOR_WINDOWS,
|
||||
discover_editor,
|
||||
get_environment_editor,
|
||||
pipe_editor,
|
||||
print_status_message,
|
||||
write_temp_file,
|
||||
)
|
||||
|
||||
|
||||
def test_get_environment_editor():
|
||||
# Test with no environment variables set
|
||||
with patch.dict(os.environ, {}, clear=True):
|
||||
assert get_environment_editor("default") == "default"
|
||||
|
||||
# Test EDITOR precedence
|
||||
with patch.dict(os.environ, {"EDITOR": "vim"}):
|
||||
assert get_environment_editor() == "vim"
|
||||
|
||||
# Test VISUAL overrides EDITOR
|
||||
with patch.dict(os.environ, {"EDITOR": "vim", "VISUAL": "code"}):
|
||||
assert get_environment_editor() == "code"
|
||||
|
||||
|
||||
def test_discover_editor_defaults():
|
||||
with patch("platform.system") as mock_system:
|
||||
# Test Windows default
|
||||
mock_system.return_value = "Windows"
|
||||
with patch.dict(os.environ, {}, clear=True):
|
||||
assert discover_editor() == [DEFAULT_EDITOR_WINDOWS]
|
||||
|
||||
# Test macOS default
|
||||
mock_system.return_value = "Darwin"
|
||||
with patch.dict(os.environ, {}, clear=True):
|
||||
assert discover_editor() == [DEFAULT_EDITOR_OS_X]
|
||||
|
||||
# Test Linux default
|
||||
mock_system.return_value = "Linux"
|
||||
with patch.dict(os.environ, {}, clear=True):
|
||||
assert discover_editor() == [DEFAULT_EDITOR_NIX]
|
||||
|
||||
|
||||
def test_write_temp_file():
|
||||
# Test basic file creation
|
||||
content = "test content"
|
||||
filepath = write_temp_file(content)
|
||||
assert os.path.exists(filepath)
|
||||
with open(filepath, "r") as f:
|
||||
assert f.read() == content
|
||||
os.remove(filepath)
|
||||
|
||||
# Test with suffix
|
||||
filepath = write_temp_file("content", suffix="txt")
|
||||
assert filepath.endswith(".txt")
|
||||
os.remove(filepath)
|
||||
|
||||
# Test with prefix
|
||||
filepath = write_temp_file("content", prefix="test_")
|
||||
assert os.path.basename(filepath).startswith("test_")
|
||||
os.remove(filepath)
|
||||
|
||||
|
||||
def test_print_status_message(capsys):
|
||||
# Test success message
|
||||
print_status_message(True, "Success!")
|
||||
captured = capsys.readouterr()
|
||||
assert "Success!" in captured.out
|
||||
|
||||
# Test failure message
|
||||
print_status_message(False, "Failed!")
|
||||
captured = capsys.readouterr()
|
||||
assert "Failed!" in captured.out
|
||||
|
||||
|
||||
def test_discover_editor_override():
|
||||
# Test editor override
|
||||
assert discover_editor("code") == ["code"]
|
||||
assert discover_editor('vim -c "set noswapfile"') == ["vim", "-c", "set noswapfile"]
|
||||
|
||||
# Test invalid editor command
|
||||
with pytest.raises(RuntimeError):
|
||||
discover_editor('vim "unclosed quote')
|
||||
|
||||
|
||||
def test_pipe_editor():
|
||||
# Test with default editor
|
||||
test_content = "Initial content"
|
||||
modified_content = "Modified content"
|
||||
|
||||
# Mock the file operations and editor call
|
||||
with (
|
||||
patch("aider.editor.write_temp_file") as mock_write,
|
||||
patch("builtins.open") as mock_open,
|
||||
patch("os.remove") as mock_remove,
|
||||
):
|
||||
# Setup mocks
|
||||
mock_write.return_value = "temp.txt"
|
||||
mock_file = MagicMock()
|
||||
mock_file.__enter__.return_value.read.return_value = modified_content
|
||||
mock_open.return_value = mock_file
|
||||
|
||||
with patch("subprocess.call") as mock_subprocess:
|
||||
# Test with default editor
|
||||
result = pipe_editor(test_content)
|
||||
assert result == modified_content
|
||||
mock_write.assert_called_with(test_content, None)
|
||||
mock_subprocess.assert_called()
|
||||
|
||||
# Test with custom editor
|
||||
result = pipe_editor(test_content, editor="code")
|
||||
assert result == modified_content
|
||||
mock_subprocess.assert_called()
|
||||
|
||||
# Test with suffix
|
||||
result = pipe_editor(test_content, suffix="md")
|
||||
assert result == modified_content
|
||||
mock_write.assert_called_with(test_content, "md")
|
||||
|
||||
# Test cleanup on permission error
|
||||
mock_remove.side_effect = PermissionError
|
||||
result = pipe_editor(test_content)
|
||||
assert result == modified_content
|
||||
@@ -45,7 +45,7 @@ class TestMain(TestCase):
|
||||
self.webbrowser_patcher.stop()
|
||||
|
||||
def test_main_with_empty_dir_no_files_on_command(self):
|
||||
main(["--no-git", "--exit"], input=DummyInput(), output=DummyOutput())
|
||||
main(["--no-git", "--exit", "--yes"], input=DummyInput(), output=DummyOutput())
|
||||
|
||||
def test_main_with_emptqy_dir_new_file(self):
|
||||
main(["foo.txt", "--yes", "--no-git", "--exit"], input=DummyInput(), output=DummyOutput())
|
||||
@@ -332,7 +332,7 @@ class TestMain(TestCase):
|
||||
def test_false_vals_in_env_file(self):
|
||||
self.create_env_file(".env", "AIDER_SHOW_DIFFS=off")
|
||||
with patch("aider.coders.Coder.create") as MockCoder:
|
||||
main(["--no-git"], input=DummyInput(), output=DummyOutput())
|
||||
main(["--no-git", "--yes"], input=DummyInput(), output=DummyOutput())
|
||||
MockCoder.assert_called_once()
|
||||
_, kwargs = MockCoder.call_args
|
||||
self.assertEqual(kwargs["show_diffs"], False)
|
||||
@@ -340,7 +340,7 @@ class TestMain(TestCase):
|
||||
def test_true_vals_in_env_file(self):
|
||||
self.create_env_file(".env", "AIDER_SHOW_DIFFS=on")
|
||||
with patch("aider.coders.Coder.create") as MockCoder:
|
||||
main(["--no-git"], input=DummyInput(), output=DummyOutput())
|
||||
main(["--no-git", "--yes"], input=DummyInput(), output=DummyOutput())
|
||||
MockCoder.assert_called_once()
|
||||
_, kwargs = MockCoder.call_args
|
||||
self.assertEqual(kwargs["show_diffs"], True)
|
||||
@@ -381,7 +381,11 @@ 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", "--exit"], input=DummyInput(), output=DummyOutput())
|
||||
main(
|
||||
["--no-git", "--verbose", "--exit", "--yes"],
|
||||
input=DummyInput(),
|
||||
output=DummyOutput(),
|
||||
)
|
||||
output = mock_stdout.getvalue()
|
||||
relevant_output = "\n".join(
|
||||
line
|
||||
|
||||
@@ -2,8 +2,10 @@ import unittest
|
||||
from unittest.mock import ANY, MagicMock, patch
|
||||
|
||||
from aider.models import (
|
||||
ANTHROPIC_BETA_HEADER,
|
||||
Model,
|
||||
ModelInfoManager,
|
||||
register_models,
|
||||
sanity_check_model,
|
||||
sanity_check_models,
|
||||
)
|
||||
@@ -80,7 +82,9 @@ class TestModels(unittest.TestCase):
|
||||
) # Should return True because there's a problem with the editor model
|
||||
mock_io.tool_warning.assert_called_with(ANY) # Ensure a warning was issued
|
||||
|
||||
warning_messages = [call.args[0] for call in mock_io.tool_warning.call_args_list]
|
||||
warning_messages = [
|
||||
warning_call.args[0] for warning_call in mock_io.tool_warning.call_args_list
|
||||
]
|
||||
print("Warning messages:", warning_messages) # Add this line
|
||||
|
||||
self.assertGreaterEqual(mock_io.tool_warning.call_count, 1) # Expect two warnings
|
||||
@@ -88,6 +92,57 @@ class TestModels(unittest.TestCase):
|
||||
any("bogus-model" in msg for msg in warning_messages)
|
||||
) # Check that one of the warnings mentions the bogus model
|
||||
|
||||
def test_aider_extra_model_settings(self):
|
||||
import tempfile
|
||||
|
||||
import yaml
|
||||
|
||||
# Create temporary YAML file with test settings
|
||||
test_settings = [
|
||||
{
|
||||
"name": "aider/extra_params",
|
||||
"extra_params": {
|
||||
"extra_headers": {"Foo": "bar"},
|
||||
"some_param": "some value",
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
# Write to a regular file instead of NamedTemporaryFile
|
||||
# for better cross-platform compatibility
|
||||
tmp = tempfile.mktemp(suffix=".yml")
|
||||
try:
|
||||
with open(tmp, "w") as f:
|
||||
yaml.dump(test_settings, f)
|
||||
|
||||
# Register the test settings
|
||||
register_models([tmp])
|
||||
|
||||
# Test that defaults are applied when no exact match
|
||||
model = Model("claude-3-5-sonnet-20240620")
|
||||
# Test that both the override and existing headers are present
|
||||
model = Model("claude-3-5-sonnet-20240620")
|
||||
self.assertEqual(model.extra_params["extra_headers"]["Foo"], "bar")
|
||||
self.assertEqual(
|
||||
model.extra_params["extra_headers"]["anthropic-beta"],
|
||||
ANTHROPIC_BETA_HEADER,
|
||||
)
|
||||
self.assertEqual(model.extra_params["some_param"], "some value")
|
||||
self.assertEqual(model.extra_params["max_tokens"], 8192)
|
||||
|
||||
# Test that exact match overrides defaults but not overrides
|
||||
model = Model("gpt-4")
|
||||
self.assertEqual(model.extra_params["extra_headers"]["Foo"], "bar")
|
||||
self.assertEqual(model.extra_params["some_param"], "some value")
|
||||
finally:
|
||||
# Clean up the temporary file
|
||||
import os
|
||||
|
||||
try:
|
||||
os.unlink(tmp)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user