mirror of
https://github.com/Aider-AI/aider
synced 2026-05-05 06:32:04 +02:00
Compare commits
254 Commits
v0.70.1.de
...
v0.72.1.de
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
03652a0030 | ||
|
|
1c3e0ba656 | ||
|
|
48f80b947b | ||
|
|
d7873de4e8 | ||
|
|
32d025bcf2 | ||
|
|
61ab5d1652 | ||
|
|
f5fd6833e2 | ||
|
|
163e6f56df | ||
|
|
5650697475 | ||
|
|
2968087d37 | ||
|
|
e7ec80f58a | ||
|
|
f0ba699463 | ||
|
|
06d5b14b86 | ||
|
|
dff544cd5d | ||
|
|
73bc0f6258 | ||
|
|
7e5e180000 | ||
|
|
fc431df2b4 | ||
|
|
bb61be630a | ||
|
|
cdc9ec2854 | ||
|
|
21d3703b69 | ||
|
|
c395be252e | ||
|
|
293c350fb7 | ||
|
|
a777f336e1 | ||
|
|
5b6c186125 | ||
|
|
6451d59deb | ||
|
|
c912b66a8f | ||
|
|
d62c43bc95 | ||
|
|
3b7b9b6ed1 | ||
|
|
9822a6ed5d | ||
|
|
a06f4dfad6 | ||
|
|
b92df87400 | ||
|
|
d7921c0111 | ||
|
|
af09c3e62a | ||
|
|
0ed42f657d | ||
|
|
ed7fbabd1c | ||
|
|
bd03563fcb | ||
|
|
05ffc7f8d6 | ||
|
|
ebc475d278 | ||
|
|
2813437515 | ||
|
|
ea2e885505 | ||
|
|
a7fadc3a45 | ||
|
|
8040a20f71 | ||
|
|
0e87854819 | ||
|
|
3bc6c641de | ||
|
|
4abb6e17ba | ||
|
|
1986f08cf9 | ||
|
|
620ae5cf1d | ||
|
|
590ee5a248 | ||
|
|
a08326ab60 | ||
|
|
63cf99361d | ||
|
|
1e54ca82b8 | ||
|
|
2ec576e110 | ||
|
|
4251e976b3 | ||
|
|
d831e2f3a4 | ||
|
|
21f20417d6 | ||
|
|
e1c914d9bb | ||
|
|
4b03b0a93a | ||
|
|
bbcde55a9e | ||
|
|
0cba898280 | ||
|
|
b9edec069a | ||
|
|
939cb7958a | ||
|
|
ebb38c6518 | ||
|
|
fa80d2f3cc | ||
|
|
869f37cd89 | ||
|
|
c22202585d | ||
|
|
f28c912d5a | ||
|
|
a0e56c5282 | ||
|
|
de7da1e806 | ||
|
|
add2f6f669 | ||
|
|
b06e765e68 | ||
|
|
c3952cb985 | ||
|
|
ac26fc6d5f | ||
|
|
122088712d | ||
|
|
9fb09ce14d | ||
|
|
392fb21946 | ||
|
|
e94b05851f | ||
|
|
571a5962b7 | ||
|
|
8b6863dc40 | ||
|
|
01af629399 | ||
|
|
4ece6d2a9b | ||
|
|
18d1d7af33 | ||
|
|
5ada250a66 | ||
|
|
308c7ab670 | ||
|
|
89d35e020a | ||
|
|
6729570799 | ||
|
|
f72f5f6438 | ||
|
|
a02e11e0bc | ||
|
|
9ff15e1506 | ||
|
|
fdddfc6b1f | ||
|
|
78ebb6295d | ||
|
|
73c89e8c00 | ||
|
|
fcc499e401 | ||
|
|
6e8efe22aa | ||
|
|
f9c5cb73a2 | ||
|
|
c939521f5f | ||
|
|
2640e05307 | ||
|
|
c1a371e3d3 | ||
|
|
5a4871155a | ||
|
|
d8e6dbf788 | ||
|
|
7ea69ae4b4 | ||
|
|
d238ead451 | ||
|
|
e6b449f24d | ||
|
|
41018d05a8 | ||
|
|
d48008e13d | ||
|
|
a9cf438100 | ||
|
|
6c7a0d21d2 | ||
|
|
d887db4c18 | ||
|
|
e6be69ec6d | ||
|
|
c1ba7db8a1 | ||
|
|
dc5b5896a9 | ||
|
|
38678fafc1 | ||
|
|
7611211d1c | ||
|
|
0d9c2cd902 | ||
|
|
1a84c109fc | ||
|
|
cbedf3f8cc | ||
|
|
50436e3106 | ||
|
|
62498ec867 | ||
|
|
91b94bb16c | ||
|
|
c2bbdc503c | ||
|
|
babae0fa6e | ||
|
|
f047882ac1 | ||
|
|
b818d6a921 | ||
|
|
ba631c8451 | ||
|
|
2c963b389c | ||
|
|
8437fbc314 | ||
|
|
76404004a4 | ||
|
|
1b64514c2c | ||
|
|
6efea7d365 | ||
|
|
e1a3b77d67 | ||
|
|
cfc7ad5627 | ||
|
|
b3cbf14ad6 | ||
|
|
51cfbe6b00 | ||
|
|
155f397d0b | ||
|
|
4b53b8b6a1 | ||
|
|
dbea4a1787 | ||
|
|
5b6da85e68 | ||
|
|
61671e9d3f | ||
|
|
f94e05e04e | ||
|
|
b5cad9a8cc | ||
|
|
3a97d8cc82 | ||
|
|
3c099465da | ||
|
|
fcdb2591b6 | ||
|
|
b67a16e9af | ||
|
|
1d672616be | ||
|
|
ed9d70903d | ||
|
|
8a9bab8a46 | ||
|
|
fdc6a08eb4 | ||
|
|
154309912d | ||
|
|
a84fea86b8 | ||
|
|
609998bc18 | ||
|
|
891868b061 | ||
|
|
3fc5cf8b9f | ||
|
|
6048ed5bc1 | ||
|
|
a1a007134c | ||
|
|
d82f9fa432 | ||
|
|
c0074301a3 | ||
|
|
9c2c05ad44 | ||
|
|
fad230c02e | ||
|
|
ad3c95f273 | ||
|
|
684fdb6095 | ||
|
|
8e64f171b8 | ||
|
|
d616c3fed7 | ||
|
|
e07e6cd2a3 | ||
|
|
f1bd5cdb52 | ||
|
|
be82b6bed9 | ||
|
|
37ad4758a1 | ||
|
|
e4a238a05c | ||
|
|
e5ca922ce8 | ||
|
|
6a1f4431d0 | ||
|
|
d67eda24d2 | ||
|
|
bba0cc8dc5 | ||
|
|
884b52b710 | ||
|
|
01ef2351b3 | ||
|
|
de1d566e9e | ||
|
|
19114a61ae | ||
|
|
36e5599ead | ||
|
|
f5a82e575c | ||
|
|
1851de323d | ||
|
|
f9408640a3 | ||
|
|
73837730fa | ||
|
|
9b46991721 | ||
|
|
606cd0368f | ||
|
|
d9ef23ad99 | ||
|
|
48b8f54c12 | ||
|
|
cec9f90c1c | ||
|
|
44d36f140a | ||
|
|
f88adcfa85 | ||
|
|
c5919f0c15 | ||
|
|
ac160cac12 | ||
|
|
867aaa5864 | ||
|
|
0b26505a20 | ||
|
|
98ad513621 | ||
|
|
591edbb003 | ||
|
|
a17b1c2ab7 | ||
|
|
648f14d95b | ||
|
|
2e4c2422b1 | ||
|
|
463fdb1ed9 | ||
|
|
d6b612a4a3 | ||
|
|
d24376608e | ||
|
|
ff41f9bd9a | ||
|
|
6d3dd5c484 | ||
|
|
f0bc8983b8 | ||
|
|
729354b038 | ||
|
|
c0be857f37 | ||
|
|
98b0e88ace | ||
|
|
3d501df21f | ||
|
|
1b4abb747d | ||
|
|
b1d418f7fb | ||
|
|
a702b4752b | ||
|
|
684ba7c0cb | ||
|
|
1bcc27d2be | ||
|
|
50d3b305d4 | ||
|
|
a341c98ec6 | ||
|
|
fa5c8a00e4 | ||
|
|
42f6c20ada | ||
|
|
787738094d | ||
|
|
a44ebfe99f | ||
|
|
c5959664e4 | ||
|
|
9b581268de | ||
|
|
acf654c984 | ||
|
|
94f83eb9e3 | ||
|
|
07c675ed06 | ||
|
|
f292e01980 | ||
|
|
61f9123147 | ||
|
|
60708a7fd7 | ||
|
|
761fb93aba | ||
|
|
20bc718bdc | ||
|
|
07337d2f41 | ||
|
|
3d2de00f49 | ||
|
|
a7242ca846 | ||
|
|
d3298ac5f2 | ||
|
|
e486243c06 | ||
|
|
8eaefb57d3 | ||
|
|
c21f7afdcb | ||
|
|
d734dee589 | ||
|
|
f035c4c01a | ||
|
|
8fcdcecf36 | ||
|
|
3f9ee1ac2e | ||
|
|
188e1f788d | ||
|
|
98a0f1cf5b | ||
|
|
1467a673b9 | ||
|
|
889eb86d89 | ||
|
|
125da0e2db | ||
|
|
14b274c707 | ||
|
|
dedbc20ac6 | ||
|
|
36cf2348d0 | ||
|
|
a19f8996b8 | ||
|
|
7293263773 | ||
|
|
ed5b07374d | ||
|
|
07b96bef95 | ||
|
|
5c3cca157d | ||
|
|
f1f66a9b9d | ||
|
|
7c86dc9ac6 | ||
|
|
b68f34eb9e |
53
.github/workflows/docker-build-test.yml
vendored
53
.github/workflows/docker-build-test.yml
vendored
@@ -4,23 +4,25 @@ on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- 'aider/website/**'
|
||||
- README.md
|
||||
- HISTORY.md
|
||||
- 'README.md'
|
||||
- 'HISTORY.md'
|
||||
- '.github/workflows/*'
|
||||
- '!.github/workflows/docker-build-test.yml'
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- 'aider/website/**'
|
||||
- README.md
|
||||
- 'README.md'
|
||||
- 'HISTORY.md'
|
||||
- '.github/workflows/*'
|
||||
- '!.github/workflows/docker-build-test.yml'
|
||||
branches:
|
||||
- main
|
||||
|
||||
# copy most of these steps from release.yml, but push: false and no tags:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
docker_build_and_push:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
@@ -29,11 +31,19 @@ jobs:
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Build Docker standard image
|
||||
- name: Login to DockerHub
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||
|
||||
- name: Build Docker images (PR)
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
@@ -42,7 +52,19 @@ jobs:
|
||||
push: false
|
||||
target: aider
|
||||
|
||||
- name: Build Docker full image
|
||||
- name: Build Docker images (Push)
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ./docker/Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: ${{ secrets.DOCKERHUB_USERNAME }}/aider:dev
|
||||
target: aider
|
||||
|
||||
- name: Build Docker full image (PR)
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
@@ -50,3 +72,14 @@ jobs:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: false
|
||||
target: aider-full
|
||||
|
||||
- name: Build Docker full image (Push)
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ./docker/Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: ${{ secrets.DOCKERHUB_USERNAME }}/aider-full:dev
|
||||
target: aider-full
|
||||
|
||||
8
.github/workflows/pages.yml
vendored
8
.github/workflows/pages.yml
vendored
@@ -12,6 +12,7 @@ on:
|
||||
- "main"
|
||||
paths:
|
||||
- "aider/website/**"
|
||||
- ".github/workflows/pages.yml"
|
||||
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
@@ -55,10 +56,9 @@ jobs:
|
||||
env:
|
||||
JEKYLL_ENV: production
|
||||
- name: Upload artifact
|
||||
# Automatically uploads an artifact from the './_site' directory by default
|
||||
uses: actions/upload-pages-artifact@v1
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: "aider/website/_site/"
|
||||
path: "aider/website/_site"
|
||||
|
||||
# Deployment job
|
||||
deploy:
|
||||
@@ -70,7 +70,7 @@ jobs:
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v2
|
||||
uses: actions/deploy-pages@v4
|
||||
|
||||
- name: Set up Python 3.12
|
||||
uses: actions/setup-python@v5
|
||||
|
||||
11
.github/workflows/ubuntu-tests.yml
vendored
11
.github/workflows/ubuntu-tests.yml
vendored
@@ -4,14 +4,19 @@ on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- 'aider/website/**'
|
||||
- README.md
|
||||
- HISTORY.md
|
||||
- 'README.md'
|
||||
- 'HISTORY.md'
|
||||
- '.github/workflows/*'
|
||||
- '!.github/workflows/ubuntu-tests.yml'
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- 'aider/website/**'
|
||||
- README.md
|
||||
- 'README.md'
|
||||
- 'HISTORY.md'
|
||||
- '.github/workflows/*'
|
||||
- '!.github/workflows/ubuntu-tests.yml'
|
||||
branches:
|
||||
- main
|
||||
|
||||
|
||||
11
.github/workflows/windows-tests.yml
vendored
11
.github/workflows/windows-tests.yml
vendored
@@ -4,14 +4,19 @@ on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- 'aider/website/**'
|
||||
- README.md
|
||||
- HISTORY.md
|
||||
- 'README.md'
|
||||
- 'HISTORY.md'
|
||||
- '.github/workflows/*'
|
||||
- '!.github/workflows/windows-tests.yml'
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- 'aider/website/**'
|
||||
- README.md
|
||||
- 'README.md'
|
||||
- 'HISTORY.md'
|
||||
- '.github/workflows/*'
|
||||
- '!.github/workflows/windows-tests.yml'
|
||||
branches:
|
||||
- main
|
||||
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -15,3 +15,4 @@ aider/_version.py
|
||||
.venv/
|
||||
.#*
|
||||
.gitattributes
|
||||
tmp.benchmarks/
|
||||
@@ -56,13 +56,6 @@ It is recommended to create a virtual environment outside of the repository to k
|
||||
python -m venv /path/to/venv
|
||||
```
|
||||
|
||||
#### Using `virtualenv` (for older Python versions)
|
||||
|
||||
```
|
||||
pip install virtualenv
|
||||
virtualenv /path/to/venv
|
||||
```
|
||||
|
||||
### Activate the Virtual Environment
|
||||
|
||||
#### On Windows
|
||||
|
||||
49
HISTORY.md
49
HISTORY.md
@@ -2,13 +2,56 @@
|
||||
|
||||
### main branch
|
||||
|
||||
- Support for DeepSeek R1.
|
||||
- Use shortcut: `--model r1`
|
||||
- Also via OpenRouter: `--model openrouter/deepseek/deepseek-r1`
|
||||
- Added Kotlin syntax support to repo map, by Paul Walker.
|
||||
- Added `--line-endings` for file writing, by Titusz Pan.
|
||||
- Added examples_as_sys_msg=True for GPT-4o models, improves benchmark scores.
|
||||
- Bumped all dependencies, to pick up litellm support for o1 system messages.
|
||||
- Bugfix for turn taking when reflecting lint/test errors.
|
||||
- Improved message validation with better error reporting for malformed chat turns.
|
||||
- Disabled summarization by default to improve chat stability.
|
||||
- Aider wrote 52% of the code in this release.
|
||||
|
||||
### Aider v0.71.1
|
||||
|
||||
- Fix permissions issue in Docker images.
|
||||
- Added read-only file announcements.
|
||||
- Bugfix: ASCII fallback for unicode errors.
|
||||
- Bugfix: integer indices for list slicing in repomap calculations.
|
||||
|
||||
### Aider v0.71.0
|
||||
|
||||
- Prompts to help DeepSeek work better when alternating between `/ask` and `/code`.
|
||||
- Streaming pretty LLM responses is smoother and faster for long replies.
|
||||
- Streaming automatically turns of for model that don't support it
|
||||
- Can now switch to/from `/model o1` and a streaming model
|
||||
- Pretty output remains enabled even when editing files with triple-backtick fences
|
||||
- Bare `/ask`, `/code` and `/architect` commands now switch the chat mode.
|
||||
- Increased default size of the repomap.
|
||||
- Increased max chat history tokens limit from 4k to 8k.
|
||||
- Turn off fancy input and watch files if terminal is dumb.
|
||||
- Added support for custom voice format and input device settings.
|
||||
- Disabled Streamlit email prompt, by apaz-cli.
|
||||
- Docker container runs as non-root user.
|
||||
- Fixed lint command handling of nested spaced strings, by Aaron Weisberg.
|
||||
- Added token count feedback when adding command output to chat.
|
||||
- Improved error handling for large audio files with automatic format conversion.
|
||||
- Improved handling of git repo index errors, by Krazer.
|
||||
- Improved unicode handling in console output with ASCII fallback.
|
||||
- Added AssertionError, AttributeError to git error handling.
|
||||
- Aider wrote 60% of the code in this release.
|
||||
|
||||
### Aider v0.70.0
|
||||
|
||||
- Full support for o1 models.
|
||||
- Watch files now honors `--subtree-only`, and only watches that sub tree.
|
||||
- Watch files now honors `--subtree-only`, and only watches that subtree.
|
||||
- Improved prompting for watch files, to work more reliably with more models.
|
||||
- New install methods via uv, including one-liners.
|
||||
- Support for openrouter/deepseek/deepseek-chat model.
|
||||
- Better error handling when non-interactive commands are attempted via `/load` or `--load`.
|
||||
- Display read-only files with abs path if it's shorter than rel path.
|
||||
- Better error handling when interactive commands are attempted via `/load` or `--load`.
|
||||
- Display read-only files with abs path if its shorter than rel path.
|
||||
- Ask 10% of users to opt-in to analytics.
|
||||
- Bugfix for auto-suggest.
|
||||
- Gracefully handle unicode errors in git path names.
|
||||
|
||||
11
README.md
11
README.md
@@ -5,9 +5,9 @@
|
||||
|
||||
Aider lets you pair program with LLMs,
|
||||
to edit code in your local git repository.
|
||||
Start a new project or work with an existing git repo.
|
||||
Aider works best with GPT-4o & Claude 3.5 Sonnet and can
|
||||
[connect to almost any LLM](https://aider.chat/docs/llms.html).
|
||||
Start a new project or work with an existing code base.
|
||||
Aider works best with Claude 3.5 Sonnet, DeepSeek V3, o1 & GPT-4o and can [connect to almost any LLM](https://aider.chat/docs/llms.html).
|
||||
|
||||
|
||||
<!-- SCREENCAST START -->
|
||||
<p align="center">
|
||||
@@ -77,16 +77,17 @@ for more details.
|
||||
- Update docs.
|
||||
- Aider will edit your files to complete your request.
|
||||
- Aider [automatically git commits](https://aider.chat/docs/git.html) changes with a sensible commit message.
|
||||
- [Use aider inside your favorite editor or IDE](https://aider.chat/docs/usage/watch.html).
|
||||
- Aider works with [most popular languages](https://aider.chat/docs/languages.html): python, javascript, typescript, php, html, css, and more...
|
||||
- Aider works best with GPT-4o & Claude 3.5 Sonnet and can [connect to almost any LLM](https://aider.chat/docs/llms.html).
|
||||
- Aider can edit multiple files at once for complex requests.
|
||||
- Aider uses a [map of your entire git repo](https://aider.chat/docs/repomap.html), which helps it work well in larger codebases.
|
||||
- Edit files in your editor while chatting with aider,
|
||||
- Edit files in your editor or IDE while chatting with aider,
|
||||
and it will always use the latest version.
|
||||
Pair program with AI.
|
||||
- [Add images to the chat](https://aider.chat/docs/usage/images-urls.html) (GPT-4o, Claude 3.5 Sonnet, etc).
|
||||
- [Add URLs to the chat](https://aider.chat/docs/usage/images-urls.html) and aider will read their content.
|
||||
- [Code with your voice](https://aider.chat/docs/usage/voice.html).
|
||||
- Aider works best with Claude 3.5 Sonnet, DeepSeek V3, o1 & GPT-4o and can [connect to almost any LLM](https://aider.chat/docs/llms.html).
|
||||
|
||||
|
||||
## Top tier performance
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from packaging import version
|
||||
|
||||
__version__ = "0.70.1.dev"
|
||||
__version__ = "0.72.1.dev"
|
||||
safe_version = __version__
|
||||
|
||||
try:
|
||||
|
||||
@@ -106,7 +106,7 @@ def get_parser(default_config_files, git_root):
|
||||
const=gpt_3_model_name,
|
||||
help=f"Use {gpt_3_model_name} model for the main chat",
|
||||
)
|
||||
deepseek_model = "deepseek/deepseek-coder"
|
||||
deepseek_model = "deepseek/deepseek-chat"
|
||||
group.add_argument(
|
||||
"--deepseek",
|
||||
action="store_const",
|
||||
@@ -287,7 +287,7 @@ def get_parser(default_config_files, git_root):
|
||||
"--map-tokens",
|
||||
type=int,
|
||||
default=None,
|
||||
help="Suggested number of tokens to use for repo map, use 0 to disable (default: 1024)",
|
||||
help="Suggested number of tokens to use for repo map, use 0 to disable",
|
||||
)
|
||||
group.add_argument(
|
||||
"--map-refresh",
|
||||
@@ -766,6 +766,12 @@ def get_parser(default_config_files, git_root):
|
||||
default="utf-8",
|
||||
help="Specify the encoding for input and output (default: utf-8)",
|
||||
)
|
||||
group.add_argument(
|
||||
"--line-endings",
|
||||
choices=["platform", "lf", "crlf"],
|
||||
default="platform",
|
||||
help="Line endings to use when writing files (default: platform)",
|
||||
)
|
||||
group.add_argument(
|
||||
"-c",
|
||||
"--config",
|
||||
|
||||
@@ -7,6 +7,8 @@ class AskPrompts(CoderPrompts):
|
||||
main_system = """Act as an expert code analyst.
|
||||
Answer questions about the supplied code.
|
||||
Always reply to the user in {language}.
|
||||
|
||||
Describe code changes however you like. Don't use SEARCH/REPLACE blocks!
|
||||
"""
|
||||
|
||||
example_messages = []
|
||||
|
||||
@@ -59,7 +59,8 @@ def wrap_fence(name):
|
||||
|
||||
|
||||
all_fences = [
|
||||
("``" + "`", "``" + "`"),
|
||||
("`" * 3, "`" * 3),
|
||||
("`" * 4, "`" * 4),
|
||||
wrap_fence("source"),
|
||||
wrap_fence("code"),
|
||||
wrap_fence("pre"),
|
||||
@@ -230,10 +231,10 @@ class Coder:
|
||||
if map_tokens > 0:
|
||||
refresh = self.repo_map.refresh
|
||||
lines.append(f"Repo-map: using {map_tokens} tokens, {refresh} refresh")
|
||||
max_map_tokens = 2048
|
||||
max_map_tokens = self.main_model.get_repo_map_tokens() * 2
|
||||
if map_tokens > max_map_tokens:
|
||||
lines.append(
|
||||
f"Warning: map-tokens > {max_map_tokens} is not recommended as too much"
|
||||
f"Warning: map-tokens > {max_map_tokens} is not recommended. Too much"
|
||||
" irrelevant code can confuse LLMs."
|
||||
)
|
||||
else:
|
||||
@@ -245,6 +246,10 @@ class Coder:
|
||||
for fname in self.get_inchat_relative_files():
|
||||
lines.append(f"Added {fname} to the chat.")
|
||||
|
||||
for fname in self.abs_read_only_fnames:
|
||||
rel_fname = self.get_rel_fname(fname)
|
||||
lines.append(f"Added {rel_fname} to the chat (read-only).")
|
||||
|
||||
if self.done_messages:
|
||||
lines.append("Restored previous conversation history.")
|
||||
|
||||
@@ -348,7 +353,6 @@ class Coder:
|
||||
self.done_messages = []
|
||||
|
||||
self.io = io
|
||||
self.stream = stream
|
||||
|
||||
self.shell_commands = []
|
||||
|
||||
@@ -363,6 +367,8 @@ class Coder:
|
||||
|
||||
self.main_model = main_model
|
||||
|
||||
self.stream = stream and main_model.streaming
|
||||
|
||||
if cache_prompts and self.main_model.cache_control:
|
||||
self.add_cache_headers = True
|
||||
|
||||
@@ -453,6 +459,7 @@ class Coder:
|
||||
|
||||
self.summarizer_thread = None
|
||||
self.summarized_done_messages = []
|
||||
self.summarizing_messages = None
|
||||
|
||||
if not self.done_messages and restore_chat_history:
|
||||
history_md = self.io.read_text(self.io.chat_history_file)
|
||||
@@ -519,7 +526,7 @@ class Coder:
|
||||
return False
|
||||
|
||||
# only show pretty output if fences are the normal triple-backtick
|
||||
if self.fence != self.fences[0]:
|
||||
if self.fence[0][0] != "`":
|
||||
return False
|
||||
|
||||
return True
|
||||
@@ -613,9 +620,19 @@ class Coder:
|
||||
def get_ident_filename_matches(self, idents):
|
||||
all_fnames = defaultdict(set)
|
||||
for fname in self.get_all_relative_files():
|
||||
base = Path(fname).with_suffix("").name.lower()
|
||||
if len(base) >= 5:
|
||||
all_fnames[base].add(fname)
|
||||
# Skip empty paths or just '.'
|
||||
if not fname or fname == ".":
|
||||
continue
|
||||
|
||||
try:
|
||||
# Handle dotfiles properly
|
||||
path = Path(fname)
|
||||
base = path.stem.lower() # Use stem instead of with_suffix("").name
|
||||
if len(base) >= 5:
|
||||
all_fnames[base].add(fname)
|
||||
except ValueError:
|
||||
# Skip paths that can't be processed
|
||||
continue
|
||||
|
||||
matches = set()
|
||||
for ident in idents:
|
||||
@@ -926,8 +943,9 @@ class Coder:
|
||||
self.summarizer_thread.start()
|
||||
|
||||
def summarize_worker(self):
|
||||
self.summarizing_messages = list(self.done_messages)
|
||||
try:
|
||||
self.summarized_done_messages = self.summarizer.summarize(self.done_messages)
|
||||
self.summarized_done_messages = self.summarizer.summarize(self.summarizing_messages)
|
||||
except ValueError as err:
|
||||
self.io.tool_warning(err.args[0])
|
||||
|
||||
@@ -941,7 +959,9 @@ class Coder:
|
||||
self.summarizer_thread.join()
|
||||
self.summarizer_thread = None
|
||||
|
||||
self.done_messages = self.summarized_done_messages
|
||||
if self.summarizing_messages == self.done_messages:
|
||||
self.done_messages = self.summarized_done_messages
|
||||
self.summarizing_messages = None
|
||||
self.summarized_done_messages = []
|
||||
|
||||
def move_back_cur_messages(self, message):
|
||||
@@ -1311,6 +1331,8 @@ class Coder:
|
||||
self.num_exhausted_context_windows += 1
|
||||
return
|
||||
|
||||
self.add_assistant_reply_to_cur_messages()
|
||||
|
||||
if self.partial_response_function_call:
|
||||
args = self.parse_partial_args()
|
||||
if args:
|
||||
@@ -1343,8 +1365,6 @@ class Coder:
|
||||
|
||||
edited = self.apply_updates()
|
||||
|
||||
self.update_cur_messages()
|
||||
|
||||
if edited:
|
||||
self.aider_edited_files.update(edited)
|
||||
saved_message = self.auto_commit(edited)
|
||||
@@ -1365,7 +1385,6 @@ class Coder:
|
||||
ok = self.io.confirm_ask("Attempt to fix lint errors?")
|
||||
if ok:
|
||||
self.reflected_message = lint_errors
|
||||
self.update_cur_messages()
|
||||
return
|
||||
|
||||
shared_output = self.run_shell_commands()
|
||||
@@ -1382,7 +1401,6 @@ class Coder:
|
||||
ok = self.io.confirm_ask("Attempt to fix test errors?")
|
||||
if ok:
|
||||
self.reflected_message = test_errors
|
||||
self.update_cur_messages()
|
||||
return
|
||||
|
||||
def reply_completed(self):
|
||||
@@ -1458,7 +1476,7 @@ class Coder:
|
||||
|
||||
return res
|
||||
|
||||
def update_cur_messages(self):
|
||||
def add_assistant_reply_to_cur_messages(self):
|
||||
if self.partial_response_content:
|
||||
self.cur_messages += [dict(role="assistant", content=self.partial_response_content)]
|
||||
if self.partial_response_function_call:
|
||||
|
||||
@@ -183,6 +183,9 @@ If you want to put code in a new file, use a *SEARCH/REPLACE block* with:
|
||||
|
||||
To rename files which have been added to the chat, use shell commands at the end of your response.
|
||||
|
||||
If the user just says something like "ok" or "go ahead" or "do that" they probably want you to make SEARCH/REPLACE blocks for the code changes you just proposed.
|
||||
The user will say when they've applied your edits. If they haven't explicitly confirmed the edits have been applied, they probably want proper SEARCH/REPLACE blocks.
|
||||
|
||||
{lazy_prompt}
|
||||
ONLY EVER RETURN CODE IN A *SEARCH/REPLACE BLOCK*!
|
||||
{shell_cmd_reminder}
|
||||
|
||||
@@ -38,7 +38,7 @@ class SingleWholeFileFunctionCoder(Coder):
|
||||
self.gpt_prompts = SingleWholeFileFunctionPrompts()
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def update_cur_messages(self, edited):
|
||||
def add_assistant_reply_to_cur_messages(self, edited):
|
||||
if edited:
|
||||
self.cur_messages += [
|
||||
dict(role="assistant", content=self.gpt_prompts.redacted_edit_message)
|
||||
|
||||
@@ -49,7 +49,7 @@ class WholeFileFunctionCoder(Coder):
|
||||
self.gpt_prompts = WholeFileFunctionPrompts()
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def update_cur_messages(self, edited):
|
||||
def add_assistant_reply_to_cur_messages(self, edited):
|
||||
if edited:
|
||||
self.cur_messages += [
|
||||
dict(role="assistant", content=self.gpt_prompts.redacted_edit_message)
|
||||
|
||||
@@ -7,7 +7,6 @@ import tempfile
|
||||
from collections import OrderedDict
|
||||
from os.path import expanduser
|
||||
from pathlib import Path
|
||||
from unittest import mock
|
||||
|
||||
import pyperclip
|
||||
from PIL import Image, ImageGrab
|
||||
@@ -18,12 +17,11 @@ 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.io import InputOutput
|
||||
from aider.llm import litellm
|
||||
from aider.repo import ANY_GIT_ERROR
|
||||
from aider.run_cmd import run_cmd
|
||||
from aider.scrape import Scraper, install_playwright
|
||||
from aider.utils import GitTemporaryDirectory, is_image_file
|
||||
from aider.utils import is_image_file
|
||||
|
||||
from .dump import dump # noqa: F401
|
||||
|
||||
@@ -54,6 +52,8 @@ class Commands:
|
||||
io,
|
||||
coder,
|
||||
voice_language=None,
|
||||
voice_input_device=None,
|
||||
voice_format=None,
|
||||
verify_ssl=True,
|
||||
args=None,
|
||||
parser=None,
|
||||
@@ -71,6 +71,8 @@ class Commands:
|
||||
voice_language = None
|
||||
|
||||
self.voice_language = voice_language
|
||||
self.voice_format = voice_format
|
||||
self.voice_input_device = voice_input_device
|
||||
|
||||
self.help = None
|
||||
self.editor = editor
|
||||
@@ -916,10 +918,14 @@ class Commands:
|
||||
if combined_output is None:
|
||||
return
|
||||
|
||||
# Calculate token count of output
|
||||
token_count = self.coder.main_model.token_count(combined_output)
|
||||
k_tokens = token_count / 1000
|
||||
|
||||
if add_on_nonzero_exit:
|
||||
add = exit_status != 0
|
||||
else:
|
||||
add = self.io.confirm_ask("Add command output to the chat?")
|
||||
add = self.io.confirm_ask(f"Add {k_tokens:.1f}k tokens of command output to the chat?")
|
||||
|
||||
if add:
|
||||
num_lines = len(combined_output.strip().splitlines())
|
||||
@@ -937,7 +943,7 @@ class Commands:
|
||||
]
|
||||
|
||||
if add and exit_status != 0:
|
||||
self.io.placeholder = "Fix that"
|
||||
self.io.placeholder = "What's wrong? Fix"
|
||||
|
||||
def cmd_exit(self, args):
|
||||
"Exit the application"
|
||||
@@ -1055,21 +1061,21 @@ class Commands:
|
||||
)
|
||||
|
||||
def cmd_ask(self, args):
|
||||
"Ask questions about the code base without editing any files"
|
||||
"""Ask questions about the code base without editing any files. If no prompt provided, switches to ask mode.""" # noqa
|
||||
return self._generic_chat_command(args, "ask")
|
||||
|
||||
def cmd_code(self, args):
|
||||
"Ask for changes to your code"
|
||||
"""Ask for changes to your code. If no prompt provided, switches to code mode.""" # noqa
|
||||
return self._generic_chat_command(args, self.coder.main_model.edit_format)
|
||||
|
||||
def cmd_architect(self, args):
|
||||
"Enter architect mode to discuss high-level design and architecture"
|
||||
"""Enter architect/editor mode using 2 different models. If no prompt provided, switches to architect/editor mode.""" # noqa
|
||||
return self._generic_chat_command(args, "architect")
|
||||
|
||||
def _generic_chat_command(self, args, edit_format):
|
||||
if not args.strip():
|
||||
self.io.tool_error(f"Please provide a question or topic for the {edit_format} chat.")
|
||||
return
|
||||
# Switch to the corresponding chat mode if no args provided
|
||||
return self.cmd_chat_mode(edit_format)
|
||||
|
||||
from aider.coders.base_coder import Coder
|
||||
|
||||
@@ -1119,7 +1125,7 @@ class Commands:
|
||||
return
|
||||
try:
|
||||
self.voice = voice.Voice(
|
||||
audio_format=self.args.voice_format, device_name=self.args.voice_input_device
|
||||
audio_format=self.voice_format or "wav", device_name=self.voice_input_device
|
||||
)
|
||||
except voice.SoundDeviceError:
|
||||
self.io.tool_error(
|
||||
@@ -1318,36 +1324,6 @@ class Commands:
|
||||
f"Command '{cmd}' is only supported in interactive mode, skipping."
|
||||
)
|
||||
|
||||
def test_cmd_load_with_switch_coder(self):
|
||||
with GitTemporaryDirectory() as repo_dir:
|
||||
io = InputOutput(pretty=False, fancy_input=False, yes=True)
|
||||
coder = Coder.create(self.GPT35, None, io)
|
||||
commands = Commands(io, coder)
|
||||
|
||||
# Create a temporary file with commands
|
||||
commands_file = Path(repo_dir) / "test_commands.txt"
|
||||
commands_file.write_text("/ask Tell me about the code\n/model gpt-4\n")
|
||||
|
||||
# Mock run to raise SwitchCoder for /ask and /model
|
||||
def mock_run(cmd):
|
||||
if cmd.startswith(("/ask", "/model")):
|
||||
raise SwitchCoder()
|
||||
return None
|
||||
|
||||
with mock.patch.object(commands, "run", side_effect=mock_run):
|
||||
# Capture tool_error output
|
||||
with mock.patch.object(io, "tool_error") as mock_tool_error:
|
||||
commands.cmd_load(str(commands_file))
|
||||
|
||||
# Check that appropriate error messages were shown
|
||||
mock_tool_error.assert_any_call(
|
||||
"Command '/ask Tell me about the code' is only supported in interactive"
|
||||
" mode, skipping."
|
||||
)
|
||||
mock_tool_error.assert_any_call(
|
||||
"Command '/model gpt-4' is only supported in interactive mode, skipping."
|
||||
)
|
||||
|
||||
def completions_raw_save(self, document, complete_event):
|
||||
return self.completions_raw_read_only(document, complete_event)
|
||||
|
||||
|
||||
@@ -26,6 +26,12 @@ class ChatSummary:
|
||||
return sized
|
||||
|
||||
def summarize(self, messages, depth=0):
|
||||
messages = self.summarize_real(messages)
|
||||
if messages and messages[-1]["role"] != "assistant":
|
||||
messages.append(dict(role="assistant", content="Ok."))
|
||||
return messages
|
||||
|
||||
def summarize_real(self, messages, depth=0):
|
||||
if not self.models:
|
||||
raise ValueError("No models available for summarization")
|
||||
|
||||
@@ -88,7 +94,7 @@ class ChatSummary:
|
||||
if summary_tokens + tail_tokens < self.max_tokens:
|
||||
return result
|
||||
|
||||
return self.summarize(result, depth + 1)
|
||||
return self.summarize_real(result, depth + 1)
|
||||
|
||||
def summarize_all(self, messages):
|
||||
content = ""
|
||||
|
||||
43
aider/io.py
43
aider/io.py
@@ -17,6 +17,7 @@ from prompt_toolkit.history import FileHistory
|
||||
from prompt_toolkit.key_binding import KeyBindings
|
||||
from prompt_toolkit.keys import Keys
|
||||
from prompt_toolkit.lexers import PygmentsLexer
|
||||
from prompt_toolkit.output.vt100 import is_dumb_terminal
|
||||
from prompt_toolkit.shortcuts import CompleteStyle, PromptSession
|
||||
from prompt_toolkit.styles import Style
|
||||
from pygments.lexers import MarkdownLexer, guess_lexer_for_filename
|
||||
@@ -197,6 +198,7 @@ class InputOutput:
|
||||
completion_menu_current_bg_color=None,
|
||||
code_theme="default",
|
||||
encoding="utf-8",
|
||||
line_endings="platform",
|
||||
dry_run=False,
|
||||
llm_history_file=None,
|
||||
editingmode=EditingMode.EMACS,
|
||||
@@ -243,14 +245,29 @@ class InputOutput:
|
||||
self.chat_history_file = None
|
||||
|
||||
self.encoding = encoding
|
||||
valid_line_endings = {"platform", "lf", "crlf"}
|
||||
if line_endings not in valid_line_endings:
|
||||
raise ValueError(
|
||||
f"Invalid line_endings value: {line_endings}. "
|
||||
f"Must be one of: {', '.join(valid_line_endings)}"
|
||||
)
|
||||
self.newline = (
|
||||
None if line_endings == "platform" else "\n" if line_endings == "lf" else "\r\n"
|
||||
)
|
||||
self.dry_run = dry_run
|
||||
|
||||
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
self.append_chat_history(f"\n# aider chat started at {current_time}\n\n")
|
||||
|
||||
self.prompt_session = None
|
||||
self.is_dumb_terminal = is_dumb_terminal()
|
||||
|
||||
if self.is_dumb_terminal:
|
||||
self.pretty = False
|
||||
fancy_input = False
|
||||
|
||||
if fancy_input:
|
||||
# Initialize PromptSession
|
||||
# Initialize PromptSession only if we have a capable terminal
|
||||
session_kwargs = {
|
||||
"input": self.input,
|
||||
"output": self.output,
|
||||
@@ -269,6 +286,8 @@ class InputOutput:
|
||||
self.tool_error(f"Can't initialize prompt toolkit: {err}") # non-pretty
|
||||
else:
|
||||
self.console = Console(force_terminal=False, no_color=True) # non-pretty
|
||||
if self.is_dumb_terminal:
|
||||
self.tool_output("Detected dumb terminal, disabling fancy input and pretty output.")
|
||||
|
||||
self.file_watcher = file_watcher
|
||||
self.root = root
|
||||
@@ -333,10 +352,6 @@ class InputOutput:
|
||||
try:
|
||||
with open(str(filename), "r", encoding=self.encoding) as f:
|
||||
return f.read()
|
||||
except OSError as err:
|
||||
if not silent:
|
||||
self.tool_error(f"{filename}: unable to read: {err}")
|
||||
return
|
||||
except FileNotFoundError:
|
||||
if not silent:
|
||||
self.tool_error(f"{filename}: file not found error")
|
||||
@@ -345,6 +360,10 @@ class InputOutput:
|
||||
if not silent:
|
||||
self.tool_error(f"{filename}: is a directory")
|
||||
return
|
||||
except OSError as err:
|
||||
if not silent:
|
||||
self.tool_error(f"{filename}: unable to read: {err}")
|
||||
return
|
||||
except UnicodeError as e:
|
||||
if not silent:
|
||||
self.tool_error(f"{filename}: {e}")
|
||||
@@ -366,7 +385,7 @@ class InputOutput:
|
||||
delay = initial_delay
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
with open(str(filename), "w", encoding=self.encoding) as f:
|
||||
with open(str(filename), "w", encoding=self.encoding, newline=self.newline) as f:
|
||||
f.write(content)
|
||||
return # Successfully wrote the file
|
||||
except PermissionError as err:
|
||||
@@ -804,9 +823,17 @@ class InputOutput:
|
||||
hist = message.strip() if strip else message
|
||||
self.append_chat_history(hist, linebreak=True, blockquote=True)
|
||||
|
||||
message = Text(message)
|
||||
if not isinstance(message, Text):
|
||||
message = Text(message)
|
||||
style = dict(style=color) if self.pretty and color else dict()
|
||||
self.console.print(message, **style)
|
||||
try:
|
||||
self.console.print(message, **style)
|
||||
except UnicodeEncodeError:
|
||||
# Fallback to ASCII-safe output
|
||||
if isinstance(message, Text):
|
||||
message = message.plain
|
||||
message = str(message).encode("ascii", errors="replace").decode("ascii")
|
||||
self.console.print(message, **style)
|
||||
|
||||
def tool_error(self, message="", strip=True):
|
||||
self.num_error_outputs += 1
|
||||
|
||||
@@ -11,6 +11,7 @@ from grep_ast import TreeContext, filename_to_lang
|
||||
from tree_sitter_languages import get_parser # noqa: E402
|
||||
|
||||
from aider.dump import dump # noqa: F401
|
||||
from aider.run_cmd import run_cmd_subprocess # noqa: F401
|
||||
|
||||
# tree_sitter is throwing a FutureWarning
|
||||
warnings.simplefilter("ignore", category=FutureWarning)
|
||||
@@ -44,26 +45,22 @@ class Linter:
|
||||
|
||||
def run_cmd(self, cmd, rel_fname, code):
|
||||
cmd += " " + rel_fname
|
||||
cmd = cmd.split()
|
||||
|
||||
returncode = 0
|
||||
stdout = ""
|
||||
try:
|
||||
process = subprocess.Popen(
|
||||
returncode, stdout = run_cmd_subprocess(
|
||||
cmd,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
encoding=self.encoding,
|
||||
errors="replace",
|
||||
cwd=self.root,
|
||||
encoding=self.encoding,
|
||||
)
|
||||
except OSError as err:
|
||||
print(f"Unable to execute lint command: {err}")
|
||||
return
|
||||
stdout, _ = process.communicate()
|
||||
errors = stdout
|
||||
if process.returncode == 0:
|
||||
if returncode == 0:
|
||||
return # zero exit status
|
||||
|
||||
cmd = " ".join(cmd)
|
||||
res = f"## Running: {cmd}\n\n"
|
||||
res += errors
|
||||
|
||||
|
||||
@@ -113,7 +113,9 @@ def setup_git(git_root, io):
|
||||
except ANY_GIT_ERROR:
|
||||
pass
|
||||
elif cwd == Path.home():
|
||||
io.tool_warning("You should probably run aider in your project's directory, not your home dir.")
|
||||
io.tool_warning(
|
||||
"You should probably run aider in your project's directory, not your home dir."
|
||||
)
|
||||
return
|
||||
elif cwd and io.confirm_ask(
|
||||
"No git repo found, create one to track aider's changes (recommended)?"
|
||||
@@ -173,7 +175,7 @@ def check_gitignore(git_root, io, ask=True):
|
||||
existing_lines = content.splitlines()
|
||||
for pat in patterns:
|
||||
if pat not in existing_lines:
|
||||
if '*' in pat or (Path(git_root) / pat).exists():
|
||||
if "*" in pat or (Path(git_root) / pat).exists():
|
||||
patterns_to_add.append(pat)
|
||||
except OSError as e:
|
||||
io.tool_error(f"Error when trying to read {gitignore_file}: {e}")
|
||||
@@ -213,6 +215,22 @@ def check_streamlit_install(io):
|
||||
)
|
||||
|
||||
|
||||
def write_streamlit_credentials():
|
||||
from streamlit.file_util import get_streamlit_file_path
|
||||
|
||||
# See https://github.com/Aider-AI/aider/issues/772
|
||||
|
||||
credential_path = Path(get_streamlit_file_path()) / "credentials.toml"
|
||||
if not os.path.exists(credential_path):
|
||||
empty_creds = '[general]\nemail = ""\n'
|
||||
|
||||
os.makedirs(os.path.dirname(credential_path), exist_ok=True)
|
||||
with open(credential_path, "w") as f:
|
||||
f.write(empty_creds)
|
||||
else:
|
||||
print("Streamlit credentials already exist.")
|
||||
|
||||
|
||||
def launch_gui(args):
|
||||
from streamlit.web import cli
|
||||
|
||||
@@ -221,6 +239,9 @@ def launch_gui(args):
|
||||
print()
|
||||
print("CONTROL-C to exit...")
|
||||
|
||||
# Necessary so streamlit does not prompt the user for an email address.
|
||||
write_streamlit_credentials()
|
||||
|
||||
target = gui.__file__
|
||||
|
||||
st_args = ["run", target]
|
||||
@@ -358,18 +379,18 @@ def load_dotenv_files(git_root, dotenv_fname, encoding="utf-8"):
|
||||
|
||||
|
||||
def register_litellm_models(git_root, model_metadata_fname, io, verbose=False):
|
||||
model_metatdata_files = []
|
||||
model_metadata_files = []
|
||||
|
||||
# Add the resource file path
|
||||
resource_metadata = importlib_resources.files("aider.resources").joinpath("model-metadata.json")
|
||||
model_metatdata_files.append(str(resource_metadata))
|
||||
model_metadata_files.append(str(resource_metadata))
|
||||
|
||||
model_metatdata_files += generate_search_path_list(
|
||||
model_metadata_files += generate_search_path_list(
|
||||
".aider.model.metadata.json", git_root, model_metadata_fname
|
||||
)
|
||||
|
||||
try:
|
||||
model_metadata_files_loaded = models.register_litellm_models(model_metatdata_files)
|
||||
model_metadata_files_loaded = models.register_litellm_models(model_metadata_files)
|
||||
if len(model_metadata_files_loaded) > 0 and verbose:
|
||||
io.tool_output("Loaded model metadata from:")
|
||||
for model_metadata_file in model_metadata_files_loaded:
|
||||
@@ -395,8 +416,8 @@ def sanity_check_repo(repo, io):
|
||||
error_msg = str(repo.git_repo_error)
|
||||
except UnicodeDecodeError as exc:
|
||||
error_msg = (
|
||||
f"Failed to read the Git repository. This issue is likely caused by a path encoded "
|
||||
f"in a format different from the expected encoding \"{sys.getfilesystemencoding()}\".\n"
|
||||
"Failed to read the Git repository. This issue is likely caused by a path encoded "
|
||||
f'in a format different from the expected encoding "{sys.getfilesystemencoding()}".\n'
|
||||
f"Internal error: {str(exc)}"
|
||||
)
|
||||
except ANY_GIT_ERROR as exc:
|
||||
@@ -531,6 +552,7 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||
code_theme=args.code_theme,
|
||||
dry_run=args.dry_run,
|
||||
encoding=args.encoding,
|
||||
line_endings=args.line_endings,
|
||||
llm_history_file=args.llm_history_file,
|
||||
editingmode=editing_mode,
|
||||
fancy_input=args.fancy_input,
|
||||
@@ -802,6 +824,9 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||
commands = Commands(
|
||||
io,
|
||||
None,
|
||||
voice_language=args.voice_language,
|
||||
voice_input_device=args.voice_input_device,
|
||||
voice_format=args.voice_format,
|
||||
verify_ssl=args.verify_ssl,
|
||||
args=args,
|
||||
parser=parser,
|
||||
@@ -824,6 +849,11 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||
)
|
||||
args.stream = False
|
||||
|
||||
if args.map_tokens is None:
|
||||
map_tokens = main_model.get_repo_map_tokens()
|
||||
else:
|
||||
map_tokens = args.map_tokens
|
||||
|
||||
try:
|
||||
coder = Coder.create(
|
||||
main_model=main_model,
|
||||
@@ -836,7 +866,7 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||
auto_commits=args.auto_commits,
|
||||
dirty_commits=args.dirty_commits,
|
||||
dry_run=args.dry_run,
|
||||
map_tokens=args.map_tokens,
|
||||
map_tokens=map_tokens,
|
||||
verbose=args.verbose,
|
||||
stream=args.stream,
|
||||
use_git=args.git,
|
||||
|
||||
@@ -10,10 +10,17 @@ from rich.text import Text
|
||||
|
||||
from aider.dump import dump # noqa: F401
|
||||
|
||||
_text = """
|
||||
_text_prefix = """
|
||||
# Header
|
||||
|
||||
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
|
||||
Lorem Ipsum is simply dummy text of the printing and typesetting industry.
|
||||
Lorem Ipsum has been the industry's standard dummy text ever since the 1500s,
|
||||
when an unknown printer took a galley of type and scrambled it to make a type
|
||||
specimen book. It has survived not only five centuries, but also the leap into
|
||||
electronic typesetting, remaining essentially unchanged. It was popularised in
|
||||
the 1960s with the release of Letraset sheets containing Lorem Ipsum passages,
|
||||
and more recently with desktop publishing software like Aldus PageMaker
|
||||
including versions of Lorem Ipsum.
|
||||
|
||||
|
||||
|
||||
@@ -27,10 +34,9 @@ Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem
|
||||
|
||||
|
||||
```python
|
||||
import sys
|
||||
"""
|
||||
|
||||
def greeting():
|
||||
print("Hello world!")
|
||||
_text_suffix = """
|
||||
```
|
||||
|
||||
## Sub header too
|
||||
@@ -41,81 +47,146 @@ The end.
|
||||
|
||||
|
||||
class MarkdownStream:
|
||||
live = None
|
||||
when = 0
|
||||
min_delay = 0.050
|
||||
live_window = 6
|
||||
"""Streaming markdown renderer that progressively displays content with a live updating window.
|
||||
|
||||
Uses rich.console and rich.live to render markdown content with smooth scrolling
|
||||
and partial updates. Maintains a sliding window of visible content while streaming
|
||||
in new markdown text.
|
||||
"""
|
||||
|
||||
live = None # Rich Live display instance
|
||||
when = 0 # Timestamp of last update
|
||||
min_delay = 1.0 / 20 # Minimum time between updates (20fps)
|
||||
live_window = 6 # Number of lines to keep visible at bottom during streaming
|
||||
|
||||
def __init__(self, mdargs=None):
|
||||
self.printed = []
|
||||
"""Initialize the markdown stream.
|
||||
|
||||
Args:
|
||||
mdargs (dict, optional): Additional arguments to pass to rich Markdown renderer
|
||||
"""
|
||||
self.printed = [] # Stores lines that have already been printed
|
||||
|
||||
if mdargs:
|
||||
self.mdargs = mdargs
|
||||
else:
|
||||
self.mdargs = dict()
|
||||
|
||||
# Initialize rich Live display with empty text
|
||||
self.live = Live(Text(""), refresh_per_second=1.0 / self.min_delay)
|
||||
self.live.start()
|
||||
|
||||
def _render_markdown_to_lines(self, text):
|
||||
"""Render markdown text to a list of lines.
|
||||
|
||||
Args:
|
||||
text (str): Markdown text to render
|
||||
|
||||
Returns:
|
||||
list: List of rendered lines with line endings preserved
|
||||
"""
|
||||
# Render the markdown to a string buffer
|
||||
string_io = io.StringIO()
|
||||
console = Console(file=string_io, force_terminal=True)
|
||||
markdown = Markdown(text, **self.mdargs)
|
||||
console.print(markdown)
|
||||
output = string_io.getvalue()
|
||||
|
||||
# Split rendered output into lines
|
||||
return output.splitlines(keepends=True)
|
||||
|
||||
def __del__(self):
|
||||
"""Destructor to ensure Live display is properly cleaned up."""
|
||||
if self.live:
|
||||
try:
|
||||
self.live.stop()
|
||||
except Exception:
|
||||
pass
|
||||
pass # Ignore any errors during cleanup
|
||||
|
||||
def update(self, text, final=False):
|
||||
"""Update the displayed markdown content.
|
||||
|
||||
Args:
|
||||
text (str): The markdown text received so far
|
||||
final (bool): If True, this is the final update and we should clean up
|
||||
|
||||
Splits the output into "stable" older lines and the "last few" lines
|
||||
which aren't considered stable. They may shift around as new chunks
|
||||
are appended to the markdown text.
|
||||
|
||||
The stable lines emit to the console above the Live window.
|
||||
The unstable lines emit into the Live window so they can be repainted.
|
||||
|
||||
Markdown going to the console works better in terminal scrollback buffers.
|
||||
The live window doesn't play nice with terminal scrollback.
|
||||
"""
|
||||
now = time.time()
|
||||
# Throttle updates to maintain smooth rendering
|
||||
if not final and now - self.when < self.min_delay:
|
||||
return
|
||||
self.when = now
|
||||
|
||||
string_io = io.StringIO()
|
||||
console = Console(file=string_io, force_terminal=True)
|
||||
# Measure render time and adjust min_delay to maintain smooth rendering
|
||||
start = time.time()
|
||||
lines = self._render_markdown_to_lines(text)
|
||||
render_time = time.time() - start
|
||||
|
||||
markdown = Markdown(text, **self.mdargs)
|
||||
# Set min_delay to render time plus a small buffer
|
||||
self.min_delay = min(max(render_time * 10, 1.0 / 20), 2)
|
||||
|
||||
console.print(markdown)
|
||||
output = string_io.getvalue()
|
||||
|
||||
lines = output.splitlines(keepends=True)
|
||||
num_lines = len(lines)
|
||||
|
||||
# How many lines have "left" the live window and are now considered stable?
|
||||
# Or if final, consider all lines to be stable.
|
||||
if not final:
|
||||
num_lines -= self.live_window
|
||||
|
||||
# If we have stable content to display...
|
||||
if final or num_lines > 0:
|
||||
# How many stable lines do we need to newly show above the live window?
|
||||
num_printed = len(self.printed)
|
||||
|
||||
show = num_lines - num_printed
|
||||
|
||||
# Skip if no new lines to show above live window
|
||||
if show <= 0:
|
||||
return
|
||||
|
||||
# Get the new lines and display them
|
||||
show = lines[num_printed:num_lines]
|
||||
show = "".join(show)
|
||||
show = Text.from_ansi(show)
|
||||
self.live.console.print(show)
|
||||
self.live.console.print(show) # to the console above the live area
|
||||
|
||||
# Update our record of printed lines
|
||||
self.printed = lines[:num_lines]
|
||||
|
||||
# Handle final update cleanup
|
||||
if final:
|
||||
self.live.update(Text(""))
|
||||
self.live.stop()
|
||||
self.live = None
|
||||
else:
|
||||
rest = lines[num_lines:]
|
||||
rest = "".join(rest)
|
||||
# rest = '...\n' + rest
|
||||
rest = Text.from_ansi(rest)
|
||||
self.live.update(rest)
|
||||
return
|
||||
|
||||
# Update the live window with remaining lines
|
||||
rest = lines[num_lines:]
|
||||
rest = "".join(rest)
|
||||
rest = Text.from_ansi(rest)
|
||||
self.live.update(rest)
|
||||
|
||||
def find_minimal_suffix(self, text, match_lines=50):
|
||||
"""
|
||||
Splits text into chunks on blank lines "\n\n".
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
_text = 5 * _text
|
||||
with open("aider/io.py", "r") as f:
|
||||
code = f.read()
|
||||
_text = _text_prefix + code + _text_suffix
|
||||
_text = _text * 10
|
||||
|
||||
pm = MarkdownStream()
|
||||
for i in range(6, len(_text)):
|
||||
for i in range(6, len(_text), 5):
|
||||
pm.update(_text[:i])
|
||||
time.sleep(0.01)
|
||||
|
||||
|
||||
@@ -75,7 +75,8 @@ MODEL_ALIASES = {
|
||||
"35-turbo": "gpt-3.5-turbo",
|
||||
"3": "gpt-3.5-turbo",
|
||||
# Other models
|
||||
"deepseek": "deepseek/deepseek-coder",
|
||||
"deepseek": "deepseek/deepseek-chat",
|
||||
"r1": "deepseek/deepseek-reasoner",
|
||||
"flash": "gemini/gemini-2.0-flash-exp",
|
||||
}
|
||||
|
||||
@@ -162,6 +163,7 @@ MODEL_SETTINGS = [
|
||||
lazy=True,
|
||||
reminder="sys",
|
||||
editor_edit_format="editor-diff",
|
||||
examples_as_sys_msg=True,
|
||||
),
|
||||
ModelSettings(
|
||||
"openai/gpt-4o-2024-08-06",
|
||||
@@ -170,6 +172,7 @@ MODEL_SETTINGS = [
|
||||
use_repo_map=True,
|
||||
lazy=True,
|
||||
reminder="sys",
|
||||
examples_as_sys_msg=True,
|
||||
),
|
||||
ModelSettings(
|
||||
"gpt-4o-2024-08-06",
|
||||
@@ -178,6 +181,7 @@ MODEL_SETTINGS = [
|
||||
use_repo_map=True,
|
||||
lazy=True,
|
||||
reminder="sys",
|
||||
examples_as_sys_msg=True,
|
||||
),
|
||||
ModelSettings(
|
||||
"gpt-4o-2024-11-20",
|
||||
@@ -186,6 +190,7 @@ MODEL_SETTINGS = [
|
||||
use_repo_map=True,
|
||||
lazy=True,
|
||||
reminder="sys",
|
||||
examples_as_sys_msg=True,
|
||||
),
|
||||
ModelSettings(
|
||||
"openai/gpt-4o-2024-11-20",
|
||||
@@ -194,6 +199,7 @@ MODEL_SETTINGS = [
|
||||
use_repo_map=True,
|
||||
lazy=True,
|
||||
reminder="sys",
|
||||
examples_as_sys_msg=True,
|
||||
),
|
||||
ModelSettings(
|
||||
"gpt-4o",
|
||||
@@ -203,6 +209,7 @@ MODEL_SETTINGS = [
|
||||
lazy=True,
|
||||
reminder="sys",
|
||||
editor_edit_format="editor-diff",
|
||||
examples_as_sys_msg=True,
|
||||
),
|
||||
ModelSettings(
|
||||
"gpt-4o-mini",
|
||||
@@ -616,12 +623,43 @@ MODEL_SETTINGS = [
|
||||
use_repo_map=True,
|
||||
send_undo_reply=False,
|
||||
),
|
||||
ModelSettings(
|
||||
"openrouter/deepseek/deepseek-r1",
|
||||
"diff",
|
||||
weak_model_name="openrouter/deepseek/deepseek-chat",
|
||||
editor_model_name="openrouter/deepseek/deepseek-chat",
|
||||
editor_edit_format="editor-diff",
|
||||
use_repo_map=True,
|
||||
examples_as_sys_msg=True,
|
||||
use_temperature=False,
|
||||
reminder="user",
|
||||
caches_by_default=True,
|
||||
extra_params={
|
||||
"max_tokens": 8192,
|
||||
},
|
||||
),
|
||||
ModelSettings(
|
||||
"deepseek/deepseek-reasoner",
|
||||
"diff",
|
||||
weak_model_name="deepseek/deepseek-chat",
|
||||
editor_model_name="deepseek/deepseek-chat",
|
||||
editor_edit_format="editor-diff",
|
||||
use_repo_map=True,
|
||||
examples_as_sys_msg=True,
|
||||
use_temperature=False,
|
||||
reminder="user",
|
||||
caches_by_default=True,
|
||||
extra_params={
|
||||
"max_tokens": 8192,
|
||||
},
|
||||
),
|
||||
ModelSettings(
|
||||
"deepseek/deepseek-chat",
|
||||
"diff",
|
||||
use_repo_map=True,
|
||||
examples_as_sys_msg=True,
|
||||
reminder="sys",
|
||||
caches_by_default=True,
|
||||
extra_params={
|
||||
"max_tokens": 8192,
|
||||
},
|
||||
@@ -680,6 +718,7 @@ MODEL_SETTINGS = [
|
||||
lazy=True,
|
||||
reminder="sys",
|
||||
editor_edit_format="editor-diff",
|
||||
examples_as_sys_msg=True,
|
||||
),
|
||||
ModelSettings(
|
||||
"openai/o1-mini",
|
||||
@@ -920,10 +959,9 @@ class Model(ModelSettings):
|
||||
self.keys_in_environment = res.get("keys_in_environment")
|
||||
|
||||
max_input_tokens = self.info.get("max_input_tokens") or 0
|
||||
if max_input_tokens < 32 * 1024:
|
||||
self.max_chat_history_tokens = 1024
|
||||
else:
|
||||
self.max_chat_history_tokens = 2 * 1024
|
||||
# Calculate max_chat_history_tokens as 1/16th of max_input_tokens,
|
||||
# with minimum 1k and maximum 8k
|
||||
self.max_chat_history_tokens = min(max(max_input_tokens / 16, 1024), 8192)
|
||||
|
||||
self.configure_model_settings(model)
|
||||
if weak_model is False:
|
||||
@@ -1178,6 +1216,15 @@ class Model(ModelSettings):
|
||||
|
||||
return res
|
||||
|
||||
def get_repo_map_tokens(self):
|
||||
map_tokens = 1024
|
||||
max_inp_tokens = self.info.get("max_input_tokens")
|
||||
if max_inp_tokens:
|
||||
map_tokens = max_inp_tokens / 8
|
||||
map_tokens = min(map_tokens, 4096)
|
||||
map_tokens = max(map_tokens, 1024)
|
||||
return map_tokens
|
||||
|
||||
|
||||
def register_models(model_settings_fnames):
|
||||
files_loaded = []
|
||||
|
||||
27
aider/queries/tree-sitter-kotlin-tags.scm
Normal file
27
aider/queries/tree-sitter-kotlin-tags.scm
Normal file
@@ -0,0 +1,27 @@
|
||||
; Definitions
|
||||
|
||||
(class_declaration
|
||||
(type_identifier) @name.definition.class) @definition.class
|
||||
|
||||
(function_declaration
|
||||
(simple_identifier) @name.definition.function) @definition.function
|
||||
|
||||
(object_declaration
|
||||
(type_identifier) @name.definition.object) @definition.object
|
||||
|
||||
; References
|
||||
|
||||
(call_expression
|
||||
[
|
||||
(simple_identifier) @name.reference.call
|
||||
(navigation_expression
|
||||
(navigation_suffix
|
||||
(simple_identifier) @name.reference.call))
|
||||
]) @reference.call
|
||||
|
||||
(delegation_specifier
|
||||
[
|
||||
(user_type) @name.reference.type
|
||||
(constructor_invocation
|
||||
(user_type) @name.reference.type)
|
||||
]) @reference.type
|
||||
@@ -8,6 +8,7 @@ try:
|
||||
ANY_GIT_ERROR = [
|
||||
git.exc.ODBError,
|
||||
git.exc.GitError,
|
||||
git.exc.InvalidGitRepositoryError,
|
||||
]
|
||||
except ImportError:
|
||||
git = None
|
||||
@@ -26,6 +27,8 @@ ANY_GIT_ERROR += [
|
||||
BufferError,
|
||||
TypeError,
|
||||
ValueError,
|
||||
AttributeError,
|
||||
AssertionError,
|
||||
]
|
||||
ANY_GIT_ERROR = tuple(ANY_GIT_ERROR)
|
||||
|
||||
@@ -285,9 +288,17 @@ class GitRepo:
|
||||
files = self.tree_files[commit]
|
||||
else:
|
||||
try:
|
||||
for blob in commit.tree.traverse():
|
||||
if blob.type == "blob": # blob is a file
|
||||
files.add(blob.path)
|
||||
iterator = commit.tree.traverse()
|
||||
while True:
|
||||
try:
|
||||
blob = next(iterator)
|
||||
if blob.type == "blob": # blob is a file
|
||||
files.add(blob.path)
|
||||
except IndexError:
|
||||
self.io.tool_warning(f"GitRepo: read error skipping {blob.path}")
|
||||
continue
|
||||
except StopIteration:
|
||||
break
|
||||
except ANY_GIT_ERROR as err:
|
||||
self.git_repo_error = err
|
||||
self.io.tool_error(f"Unable to list files in git repo: {err}")
|
||||
@@ -359,8 +370,8 @@ class GitRepo:
|
||||
|
||||
def ignored_file_raw(self, fname):
|
||||
if self.subtree_only:
|
||||
fname_path = Path(self.normalize_path(fname))
|
||||
try:
|
||||
fname_path = Path(self.normalize_path(fname))
|
||||
cwd_path = Path.cwd().resolve().relative_to(Path(self.root).resolve())
|
||||
except ValueError:
|
||||
# Issue #1524
|
||||
|
||||
@@ -605,7 +605,7 @@ class RepoMap:
|
||||
|
||||
self.tree_cache = dict()
|
||||
|
||||
middle = min(max_map_tokens // 25, num_tags)
|
||||
middle = min(int(max_map_tokens // 25), num_tags)
|
||||
while lower_bound <= upper_bound:
|
||||
# dump(lower_bound, middle, upper_bound)
|
||||
|
||||
@@ -628,7 +628,7 @@ class RepoMap:
|
||||
else:
|
||||
upper_bound = middle - 1
|
||||
|
||||
middle = (lower_bound + upper_bound) // 2
|
||||
middle = int((lower_bound + upper_bound) // 2)
|
||||
|
||||
spin.end()
|
||||
return best_tree
|
||||
|
||||
@@ -1,27 +1,34 @@
|
||||
{
|
||||
"openrouter/openai/o1": {
|
||||
"max_tokens": 100000,
|
||||
"max_input_tokens": 200000,
|
||||
"max_output_tokens": 100000,
|
||||
"input_cost_per_token": 0.000015,
|
||||
"output_cost_per_token": 0.00006,
|
||||
"cache_read_input_token_cost": 0.0000075,
|
||||
"litellm_provider": "openrouter",
|
||||
"mode": "chat",
|
||||
"supports_function_calling": true,
|
||||
"supports_parallel_function_calling": true,
|
||||
"supports_vision": true,
|
||||
"supports_prompt_caching": true,
|
||||
"supports_system_messages": true,
|
||||
"supports_response_schema": true
|
||||
},
|
||||
"openrouter/deepseek/deepseek-chat": {
|
||||
"deepseek-reasoner": {
|
||||
"max_tokens": 8192,
|
||||
"max_input_tokens": 66000,
|
||||
"max_output_tokens": 4096,
|
||||
"input_cost_per_token": 0.00000014,
|
||||
"output_cost_per_token": 0.00000028,
|
||||
"litellm_provider": "openrouter",
|
||||
"mode": "chat"
|
||||
"max_input_tokens": 64000,
|
||||
"max_output_tokens": 8192,
|
||||
"input_cost_per_token": 0.00000055,
|
||||
"input_cost_per_token_cache_hit": 0.00000014,
|
||||
"cache_read_input_token_cost": 0.00000014,
|
||||
"cache_creation_input_token_cost": 0.0,
|
||||
"output_cost_per_token": 0.00000219,
|
||||
"litellm_provider": "deepseek",
|
||||
"mode": "chat",
|
||||
//"supports_function_calling": true,
|
||||
"supports_assistant_prefill": true,
|
||||
//"supports_tool_choice": true,
|
||||
"supports_prompt_caching": true
|
||||
},
|
||||
"openrouter/deepseek/deepseek-r1": {
|
||||
"max_tokens": 8192,
|
||||
"max_input_tokens": 64000,
|
||||
"max_output_tokens": 8192,
|
||||
"input_cost_per_token": 0.00000055,
|
||||
"input_cost_per_token_cache_hit": 0.00000014,
|
||||
"cache_read_input_token_cost": 0.00000014,
|
||||
"cache_creation_input_token_cost": 0.0,
|
||||
"output_cost_per_token": 0.00000219,
|
||||
"litellm_provider": "deepseek",
|
||||
"mode": "chat",
|
||||
//"supports_function_calling": true,
|
||||
"supports_assistant_prefill": true,
|
||||
//"supports_tool_choice": true,
|
||||
"supports_prompt_caching": true
|
||||
},
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ def get_windows_parent_process_name():
|
||||
return None
|
||||
|
||||
|
||||
def run_cmd_subprocess(command, verbose=False, cwd=None):
|
||||
def run_cmd_subprocess(command, verbose=False, cwd=None, encoding=sys.stdout.encoding):
|
||||
if verbose:
|
||||
print("Using run_cmd_subprocess:", command)
|
||||
|
||||
@@ -65,7 +65,7 @@ def run_cmd_subprocess(command, verbose=False, cwd=None):
|
||||
stderr=subprocess.STDOUT,
|
||||
text=True,
|
||||
shell=True,
|
||||
encoding=sys.stdout.encoding,
|
||||
encoding=encoding,
|
||||
errors="replace",
|
||||
bufsize=0, # Set bufsize to 0 for unbuffered output
|
||||
universal_newlines=True,
|
||||
|
||||
@@ -5,6 +5,7 @@ import time
|
||||
from aider.dump import dump # noqa: F401
|
||||
from aider.exceptions import LiteLLMExceptions
|
||||
from aider.llm import litellm
|
||||
from aider.utils import format_messages
|
||||
|
||||
# from diskcache import Cache
|
||||
|
||||
@@ -16,6 +17,30 @@ CACHE = None
|
||||
RETRY_TIMEOUT = 60
|
||||
|
||||
|
||||
def sanity_check_messages(messages):
|
||||
"""Check if messages alternate between user and assistant roles.
|
||||
System messages can be interspersed anywhere.
|
||||
Also verifies the last non-system message is from the user.
|
||||
Returns True if valid, False otherwise."""
|
||||
last_role = None
|
||||
last_non_system_role = None
|
||||
|
||||
for msg in messages:
|
||||
role = msg.get("role")
|
||||
if role == "system":
|
||||
continue
|
||||
|
||||
if last_role and role == last_role:
|
||||
turns = format_messages(messages)
|
||||
raise ValueError("Messages don't properly alternate user/assistant:\n\n" + turns)
|
||||
|
||||
last_role = role
|
||||
last_non_system_role = role
|
||||
|
||||
# Ensure last non-system message is from user
|
||||
return last_non_system_role == "user"
|
||||
|
||||
|
||||
def send_completion(
|
||||
model_name,
|
||||
messages,
|
||||
@@ -24,6 +49,12 @@ def send_completion(
|
||||
temperature=0,
|
||||
extra_params=None,
|
||||
):
|
||||
#
|
||||
#
|
||||
# sanity_check_messages(messages)
|
||||
#
|
||||
#
|
||||
|
||||
kwargs = dict(
|
||||
model=model_name,
|
||||
messages=messages,
|
||||
|
||||
@@ -112,7 +112,7 @@ def format_messages(messages, title=None):
|
||||
output.append(f"{title.upper()} {'*' * 50}")
|
||||
|
||||
for msg in messages:
|
||||
output.append("")
|
||||
output.append("-------")
|
||||
role = msg["role"].upper()
|
||||
content = msg.get("content")
|
||||
if isinstance(content, list): # Handle list content (e.g., image messages)
|
||||
@@ -300,12 +300,15 @@ class Spinner:
|
||||
|
||||
|
||||
def find_common_root(abs_fnames):
|
||||
if len(abs_fnames) == 1:
|
||||
return safe_abs_path(os.path.dirname(list(abs_fnames)[0]))
|
||||
elif abs_fnames:
|
||||
return safe_abs_path(os.path.commonpath(list(abs_fnames)))
|
||||
else:
|
||||
return safe_abs_path(os.getcwd())
|
||||
try:
|
||||
if len(abs_fnames) == 1:
|
||||
return safe_abs_path(os.path.dirname(list(abs_fnames)[0]))
|
||||
elif abs_fnames:
|
||||
return safe_abs_path(os.path.commonpath(list(abs_fnames)))
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
return safe_abs_path(os.getcwd())
|
||||
|
||||
|
||||
def format_tokens(count):
|
||||
|
||||
@@ -18,6 +18,7 @@ warnings.filterwarnings("ignore", category=SyntaxWarning)
|
||||
|
||||
|
||||
from pydub import AudioSegment # noqa
|
||||
from pydub.exceptions import CouldntDecodeError, CouldntEncodeError # noqa
|
||||
|
||||
try:
|
||||
import soundfile as sf
|
||||
@@ -140,13 +141,28 @@ class Voice:
|
||||
while not self.q.empty():
|
||||
file.write(self.q.get())
|
||||
|
||||
if self.audio_format != "wav":
|
||||
filename = tempfile.mktemp(suffix=f".{self.audio_format}")
|
||||
audio = AudioSegment.from_wav(temp_wav)
|
||||
audio.export(filename, format=self.audio_format)
|
||||
os.remove(temp_wav)
|
||||
else:
|
||||
filename = temp_wav
|
||||
use_audio_format = self.audio_format
|
||||
|
||||
# Check file size and offer to convert to mp3 if too large
|
||||
file_size = os.path.getsize(temp_wav)
|
||||
if file_size > 24.9 * 1024 * 1024 and self.audio_format == "wav":
|
||||
print("\nWarning: {temp_wav} is too large, switching to mp3 format.")
|
||||
use_audio_format = "mp3"
|
||||
|
||||
filename = temp_wav
|
||||
if use_audio_format != "wav":
|
||||
try:
|
||||
new_filename = tempfile.mktemp(suffix=f".{use_audio_format}")
|
||||
audio = AudioSegment.from_wav(temp_wav)
|
||||
audio.export(new_filename, format=use_audio_format)
|
||||
os.remove(temp_wav)
|
||||
filename = new_filename
|
||||
except (CouldntDecodeError, CouldntEncodeError) as e:
|
||||
print(f"Error converting audio: {e}")
|
||||
except (OSError, FileNotFoundError) as e:
|
||||
print(f"File system error during conversion: {e}")
|
||||
except Exception as e:
|
||||
print(f"Unexpected error during audio conversion: {e}")
|
||||
|
||||
with open(filename, "rb") as fh:
|
||||
try:
|
||||
@@ -157,7 +173,7 @@ class Voice:
|
||||
print(f"Unable to transcribe {filename}: {err}")
|
||||
return
|
||||
|
||||
if self.audio_format != "wav":
|
||||
if filename != temp_wav:
|
||||
os.remove(filename)
|
||||
|
||||
text = transcript.text
|
||||
|
||||
@@ -25,13 +25,56 @@ cog.out(text)
|
||||
|
||||
### main branch
|
||||
|
||||
- Support for DeepSeek R1.
|
||||
- Use shortcut: `--model r1`
|
||||
- Also via OpenRouter: `--model openrouter/deepseek/deepseek-r1`
|
||||
- Added Kotlin syntax support to repo map, by Paul Walker.
|
||||
- Added `--line-endings` for file writing, by Titusz Pan.
|
||||
- Added examples_as_sys_msg=True for GPT-4o models, improves benchmark scores.
|
||||
- Bumped all dependencies, to pick up litellm support for o1 system messages.
|
||||
- Bugfix for turn taking when reflecting lint/test errors.
|
||||
- Improved message validation with better error reporting for malformed chat turns.
|
||||
- Disabled summarization by default to improve chat stability.
|
||||
- Aider wrote 52% of the code in this release.
|
||||
|
||||
### Aider v0.71.1
|
||||
|
||||
- Fix permissions issue in Docker images.
|
||||
- Added read-only file announcements.
|
||||
- Bugfix: ASCII fallback for unicode errors.
|
||||
- Bugfix: integer indices for list slicing in repomap calculations.
|
||||
|
||||
### Aider v0.71.0
|
||||
|
||||
- Prompts to help DeepSeek work better when alternating between `/ask` and `/code`.
|
||||
- Streaming pretty LLM responses is smoother and faster for long replies.
|
||||
- Streaming automatically turns of for model that don't support it
|
||||
- Can now switch to/from `/model o1` and a streaming model
|
||||
- Pretty output remains enabled even when editing files with triple-backtick fences
|
||||
- Bare `/ask`, `/code` and `/architect` commands now switch the chat mode.
|
||||
- Increased default size of the repomap.
|
||||
- Increased max chat history tokens limit from 4k to 8k.
|
||||
- Turn off fancy input and watch files if terminal is dumb.
|
||||
- Added support for custom voice format and input device settings.
|
||||
- Disabled Streamlit email prompt, by apaz-cli.
|
||||
- Docker container runs as non-root user.
|
||||
- Fixed lint command handling of nested spaced strings, by Aaron Weisberg.
|
||||
- Added token count feedback when adding command output to chat.
|
||||
- Improved error handling for large audio files with automatic format conversion.
|
||||
- Improved handling of git repo index errors, by Krazer.
|
||||
- Improved unicode handling in console output with ASCII fallback.
|
||||
- Added AssertionError, AttributeError to git error handling.
|
||||
- Aider wrote 60% of the code in this release.
|
||||
|
||||
### Aider v0.70.0
|
||||
|
||||
- Full support for o1 models.
|
||||
- Watch files now honors `--subtree-only`, and only watches that sub tree.
|
||||
- Watch files now honors `--subtree-only`, and only watches that subtree.
|
||||
- Improved prompting for watch files, to work more reliably with more models.
|
||||
- New install methods via uv, including one-liners.
|
||||
- Support for openrouter/deepseek/deepseek-chat model.
|
||||
- Better error handling when non-interactive commands are attempted via `/load` or `--load`.
|
||||
- Display read-only files with abs path if it's shorter than rel path.
|
||||
- Better error handling when interactive commands are attempted via `/load` or `--load`.
|
||||
- Display read-only files with abs path if its shorter than rel path.
|
||||
- Ask 10% of users to opt-in to analytics.
|
||||
- Bugfix for auto-suggest.
|
||||
- Gracefully handle unicode errors in git path names.
|
||||
|
||||
@@ -3457,3 +3457,91 @@
|
||||
Paul Gauthier (aider): 207
|
||||
start_tag: v0.68.0
|
||||
total_lines: 305
|
||||
- aider_percentage: 74.22
|
||||
aider_total: 875
|
||||
end_date: '2024-12-26'
|
||||
end_tag: v0.70.0
|
||||
file_counts:
|
||||
aider/__init__.py:
|
||||
Paul Gauthier: 1
|
||||
aider/analytics.py:
|
||||
Paul Gauthier: 6
|
||||
Paul Gauthier (aider): 41
|
||||
aider/args.py:
|
||||
Evan Johnson: 2
|
||||
aider/coders/search_replace.py:
|
||||
Paul Gauthier: 5
|
||||
aider/commands.py:
|
||||
Paul Gauthier (aider): 41
|
||||
aider/help_pats.py:
|
||||
Paul Gauthier: 3
|
||||
aider/io.py:
|
||||
Paul Gauthier: 7
|
||||
Paul Gauthier (aider): 9
|
||||
aider/main.py:
|
||||
Paul Gauthier: 15
|
||||
Paul Gauthier (aider): 5
|
||||
apaz-cli: 3
|
||||
mdk: 6
|
||||
aider/models.py:
|
||||
Paul Gauthier: 29
|
||||
aider/repo.py:
|
||||
Paul Gauthier: 14
|
||||
aider/utils.py:
|
||||
Paul Gauthier: 2
|
||||
aider/watch.py:
|
||||
Paul Gauthier: 13
|
||||
aider/website/_includes/head_custom.html:
|
||||
Paul Gauthier (aider): 4
|
||||
aider/website/_includes/leaderboard.js:
|
||||
Paul Gauthier (aider): 14
|
||||
aider/website/docs/leaderboards/index.md:
|
||||
Paul Gauthier: 28
|
||||
Paul Gauthier (aider): 2
|
||||
benchmark/Dockerfile:
|
||||
Paul Gauthier: 8
|
||||
Paul Gauthier (aider): 43
|
||||
benchmark/benchmark.py:
|
||||
Paul Gauthier: 69
|
||||
Paul Gauthier (aider): 153
|
||||
benchmark/clone-exercism.sh:
|
||||
Paul Gauthier: 2
|
||||
Paul Gauthier (aider): 18
|
||||
benchmark/cpp-test.sh:
|
||||
Paul Gauthier: 10
|
||||
Paul Gauthier (aider): 1
|
||||
benchmark/docker.sh:
|
||||
Paul Gauthier (aider): 4
|
||||
benchmark/install-docker-ubuntu.sh:
|
||||
Paul Gauthier (aider): 63
|
||||
benchmark/npm-test.sh:
|
||||
Paul Gauthier: 10
|
||||
Paul Gauthier (aider): 3
|
||||
benchmark/problem_stats.py:
|
||||
Paul Gauthier: 35
|
||||
Paul Gauthier (aider): 318
|
||||
benchmark/rsync.sh:
|
||||
Paul Gauthier: 7
|
||||
Paul Gauthier (aider): 26
|
||||
scripts/blame.py:
|
||||
Paul Gauthier (aider): 6
|
||||
scripts/my_models.py:
|
||||
Paul Gauthier (aider): 95
|
||||
scripts/update-blame.sh:
|
||||
Paul Gauthier (aider): 3
|
||||
scripts/update-docs.sh:
|
||||
Paul Gauthier: 1
|
||||
tests/basic/test_analytics.py:
|
||||
Paul Gauthier (aider): 19
|
||||
tests/basic/test_main.py:
|
||||
Paul Gauthier (aider): 7
|
||||
tests/basic/test_sanity_check_repo.py:
|
||||
mdk: 28
|
||||
grand_total:
|
||||
Evan Johnson: 2
|
||||
Paul Gauthier: 265
|
||||
Paul Gauthier (aider): 875
|
||||
apaz-cli: 3
|
||||
mdk: 34
|
||||
start_tag: v0.69.0
|
||||
total_lines: 1179
|
||||
|
||||
@@ -24,58 +24,84 @@
|
||||
seconds_per_case: 17.3
|
||||
total_cost: 0.3236
|
||||
|
||||
- dirname: 2024-12-21-18-44-28--polyglot-sonnet
|
||||
- dirname: 2025-01-17-19-44-33--sonnet-baseline-jan-17
|
||||
test_cases: 225
|
||||
model: claude-3-5-sonnet-20241022
|
||||
edit_format: diff
|
||||
commit_hash: a755079-dirty
|
||||
pass_rate_1: 18.7
|
||||
pass_rate_2: 45.3
|
||||
pass_num_1: 42
|
||||
pass_num_2: 102
|
||||
percent_cases_well_formed: 100.0
|
||||
error_outputs: 1
|
||||
num_malformed_responses: 0
|
||||
num_with_malformed_responses: 0
|
||||
user_asks: 14
|
||||
commit_hash: 6451d59
|
||||
pass_rate_1: 22.2
|
||||
pass_rate_2: 51.6
|
||||
pass_num_1: 50
|
||||
pass_num_2: 116
|
||||
percent_cases_well_formed: 99.6
|
||||
error_outputs: 2
|
||||
num_malformed_responses: 1
|
||||
num_with_malformed_responses: 1
|
||||
user_asks: 11
|
||||
lazy_comments: 0
|
||||
syntax_errors: 0
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 1
|
||||
test_timeouts: 12
|
||||
test_timeouts: 8
|
||||
total_tests: 225
|
||||
command: aider --model claude-3-5-sonnet-20241022
|
||||
date: 2024-12-21
|
||||
versions: 0.69.2.dev
|
||||
seconds_per_case: 30.8
|
||||
total_cost: 13.4847
|
||||
|
||||
- dirname: 2024-12-21-18-52-34--polyglot-gpt-4o-diff
|
||||
date: 2025-01-17
|
||||
versions: 0.71.2.dev
|
||||
seconds_per_case: 21.4
|
||||
total_cost: 14.4063
|
||||
|
||||
- dirname: 2024-12-30-20-57-12--gpt-4o-2024-11-20-ex-as-sys
|
||||
test_cases: 225
|
||||
model: gpt-4o-2024-11-20
|
||||
edit_format: diff
|
||||
commit_hash: a755079-dirty
|
||||
commit_hash: 09ee197-dirty
|
||||
pass_rate_1: 4.9
|
||||
pass_rate_2: 15.1
|
||||
pass_rate_2: 18.2
|
||||
pass_num_1: 11
|
||||
pass_num_2: 34
|
||||
percent_cases_well_formed: 96.0
|
||||
pass_num_2: 41
|
||||
percent_cases_well_formed: 95.1
|
||||
error_outputs: 12
|
||||
num_malformed_responses: 11
|
||||
num_with_malformed_responses: 9
|
||||
user_asks: 34
|
||||
num_malformed_responses: 12
|
||||
num_with_malformed_responses: 11
|
||||
user_asks: 53
|
||||
lazy_comments: 0
|
||||
syntax_errors: 0
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 1
|
||||
test_timeouts: 19
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 12
|
||||
total_tests: 225
|
||||
command: aider --model gpt-4o-2024-11-20
|
||||
date: 2024-12-21
|
||||
versions: 0.69.2.dev
|
||||
seconds_per_case: 22.2
|
||||
total_cost: 7.1835
|
||||
|
||||
date: 2024-12-30
|
||||
versions: 0.70.1.dev
|
||||
seconds_per_case: 12.1
|
||||
total_cost: 6.7351
|
||||
|
||||
- dirname: 2024-12-30-20-44-54--gpt4o-ex-as-sys-clean-prompt
|
||||
test_cases: 225
|
||||
model: gpt-4o-2024-08-06
|
||||
edit_format: diff
|
||||
commit_hash: 09ee197-dirty
|
||||
pass_rate_1: 4.9
|
||||
pass_rate_2: 23.1
|
||||
pass_num_1: 11
|
||||
pass_num_2: 52
|
||||
percent_cases_well_formed: 94.2
|
||||
error_outputs: 21
|
||||
num_malformed_responses: 21
|
||||
num_with_malformed_responses: 13
|
||||
user_asks: 65
|
||||
lazy_comments: 0
|
||||
syntax_errors: 0
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 3
|
||||
total_tests: 225
|
||||
command: aider --model gpt-4o-2024-08-06
|
||||
date: 2024-12-30
|
||||
versions: 0.70.1.dev
|
||||
seconds_per_case: 16.0
|
||||
total_cost: 7.0286
|
||||
|
||||
- dirname: 2024-12-21-19-23-03--polyglot-o1-hard-diff
|
||||
test_cases: 224
|
||||
model: o1-2024-12-17 (high)
|
||||
@@ -286,7 +312,7 @@
|
||||
|
||||
- dirname: 2024-12-25-13-31-51--deepseekv3preview-diff2
|
||||
test_cases: 225
|
||||
model: DeepSeek Chat V3 Preview
|
||||
model: DeepSeek Chat V3
|
||||
edit_format: diff
|
||||
commit_hash: 0a23c4a-dirty
|
||||
pass_rate_1: 22.7
|
||||
@@ -310,3 +336,80 @@
|
||||
seconds_per_case: 34.8
|
||||
total_cost: 0.3369
|
||||
|
||||
- dirname: 2024-12-26-00-55-20--Qwen2.5-Coder-32B-Instruct
|
||||
test_cases: 225
|
||||
model: Qwen2.5-Coder-32B-Instruct
|
||||
edit_format: whole
|
||||
commit_hash: b51768b0
|
||||
pass_rate_1: 4.9
|
||||
pass_rate_2: 16.4
|
||||
pass_num_1: 11
|
||||
pass_num_2: 37
|
||||
percent_cases_well_formed: 99.6
|
||||
error_outputs: 1
|
||||
num_malformed_responses: 1
|
||||
num_with_malformed_responses: 1
|
||||
user_asks: 33
|
||||
lazy_comments: 0
|
||||
syntax_errors: 0
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 6
|
||||
total_tests: 225
|
||||
command: aider --model openai/Qwen2.5-Coder-32B-Instruct
|
||||
date: 2024-12-26
|
||||
versions: 0.69.2.dev
|
||||
seconds_per_case: 42.0
|
||||
total_cost: 0.0000
|
||||
|
||||
- dirname: 2025-01-13-18-17-25--codestral-whole2
|
||||
test_cases: 225
|
||||
model: Codestral 25.01
|
||||
edit_format: whole
|
||||
commit_hash: 0cba898-dirty
|
||||
pass_rate_1: 4.0
|
||||
pass_rate_2: 11.1
|
||||
pass_num_1: 9
|
||||
pass_num_2: 25
|
||||
percent_cases_well_formed: 100.0
|
||||
error_outputs: 0
|
||||
num_malformed_responses: 0
|
||||
num_with_malformed_responses: 0
|
||||
user_asks: 47
|
||||
lazy_comments: 0
|
||||
syntax_errors: 0
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 4
|
||||
total_tests: 225
|
||||
command: aider --model mistral/codestral-latest
|
||||
date: 2025-01-13
|
||||
versions: 0.71.2.dev
|
||||
seconds_per_case: 9.3
|
||||
total_cost: 1.9834
|
||||
|
||||
- dirname: 2025-01-20-19-11-38--ds-turns-upd-cur-msgs-fix-with-summarizer
|
||||
test_cases: 225
|
||||
model: DeepSeek R1
|
||||
edit_format: diff
|
||||
commit_hash: 5650697-dirty
|
||||
pass_rate_1: 26.7
|
||||
pass_rate_2: 56.9
|
||||
pass_num_1: 60
|
||||
pass_num_2: 128
|
||||
percent_cases_well_formed: 96.9
|
||||
error_outputs: 8
|
||||
num_malformed_responses: 7
|
||||
num_with_malformed_responses: 7
|
||||
user_asks: 15
|
||||
lazy_comments: 0
|
||||
syntax_errors: 0
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 1
|
||||
test_timeouts: 5
|
||||
total_tests: 225
|
||||
command: aider --model deepseek/deepseek-reasoner
|
||||
date: 2025-01-20
|
||||
versions: 0.71.2.dev
|
||||
seconds_per_case: 113.7
|
||||
total_cost: 5.4193
|
||||
@@ -1,5 +1,18 @@
|
||||
<canvas id="blameChart" width="800" height="360" style="margin-top: 20px"></canvas>
|
||||
<canvas id="linesChart" width="800" height="360" style="margin-top: 20px"></canvas>
|
||||
<div class="chart-container">
|
||||
<canvas id="blameChart" style="margin-top: 20px"></canvas>
|
||||
</div>
|
||||
<div class="chart-container">
|
||||
<canvas id="linesChart" style="margin-top: 20px"></canvas>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.chart-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/moment"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-moment"></script>
|
||||
@@ -24,10 +37,17 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
var linesData = {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
label: 'Aider\'s lines of new code',
|
||||
label: 'Aider',
|
||||
data: [{% for row in site.data.blame %}{ x: '{{ row.end_tag }}', y: {{ row.aider_total }} },{% endfor %}],
|
||||
backgroundColor: 'rgba(255, 99, 132, 0.8)',
|
||||
borderColor: 'rgba(255, 99, 132, 1)',
|
||||
backgroundColor: 'rgba(54, 162, 235, 0.8)',
|
||||
borderColor: 'rgba(54, 162, 235, 1)',
|
||||
borderWidth: 1
|
||||
},
|
||||
{
|
||||
label: 'Human',
|
||||
data: [{% for row in site.data.blame %}{ x: '{{ row.end_tag }}', y: {{ row.total_lines | minus: row.aider_total }} },{% endfor %}],
|
||||
backgroundColor: 'rgba(200, 200, 200, 0.8)',
|
||||
borderColor: 'rgba(200, 200, 200, 1)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
};
|
||||
@@ -36,6 +56,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
type: 'bar',
|
||||
data: blameData,
|
||||
options: {
|
||||
maintainAspectRatio: false,
|
||||
scales: {
|
||||
x: {
|
||||
type: 'category',
|
||||
@@ -85,9 +106,11 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
type: 'bar',
|
||||
data: linesData,
|
||||
options: {
|
||||
maintainAspectRatio: false,
|
||||
scales: {
|
||||
x: {
|
||||
type: 'category',
|
||||
stacked: true,
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Version'
|
||||
@@ -98,6 +121,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
}
|
||||
},
|
||||
y: {
|
||||
stacked: true,
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Lines of new code'
|
||||
@@ -107,12 +131,14 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false
|
||||
display: true,
|
||||
position: 'chartArea',
|
||||
reverse: true
|
||||
},
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
label: function(context) {
|
||||
var label = 'New lines of code by aider';
|
||||
var label = context.dataset.label;
|
||||
var value = context.parsed.y || 0;
|
||||
return `${label}: ${value}`;
|
||||
}
|
||||
@@ -120,7 +146,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
},
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Lines of new code written by aider, by release',
|
||||
text: 'Lines of new code, by release',
|
||||
font: {
|
||||
size: 16
|
||||
}
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
Aider works best with GPT-4o & Claude 3.5 Sonnet and can
|
||||
[connect to almost any LLM](https://aider.chat/docs/llms.html).
|
||||
Aider works best with Claude 3.5 Sonnet, DeepSeek V3, o1 & GPT-4o and can [connect to almost any LLM](https://aider.chat/docs/llms.html).
|
||||
|
||||
102
aider/website/_posts/2025-01-15-uv.md
Normal file
102
aider/website/_posts/2025-01-15-uv.md
Normal file
@@ -0,0 +1,102 @@
|
||||
---
|
||||
title: Using uv as an installer
|
||||
excerpt: Reliably packaging & distributing python CLI tools is hard. Aider uses uv in novel ways to make it easy to install the aider CLI, its dependencies and python 3.12. All in an isolated env.
|
||||
draft: false
|
||||
nav_exclude: true
|
||||
---
|
||||
{% if page.date %}
|
||||
<p class="post-date">{{ page.date | date: "%B %d, %Y" }}</p>
|
||||
{% endif %}
|
||||
|
||||
# Using uv as an installer
|
||||
{: .no_toc }
|
||||
|
||||
It's hard to reliably
|
||||
package and distribute python command line tools
|
||||
to end users.
|
||||
Users frequently encounter challenges:
|
||||
dependency version conflicts, virtual environment management,
|
||||
needing to install python or a specific version of python, etc.
|
||||
|
||||
Aider employs [uv](https://github.com/astral-sh/uv)
|
||||
in a couple of novel ways to streamline the installation process:
|
||||
|
||||
1. Install aider with
|
||||
`curl https://aider.chat/install.sh | sh` even if python isn't already installed.
|
||||
|
||||
2. Users who have python 3.8+ installed can `pip install aider-install && aider-install`.
|
||||
|
||||
Both methods use uv to **globally** install the `aider` command line program,
|
||||
with all of its dependencies in an **isolated environment**.
|
||||
They ensure that aider will run with **python 3.12**, and install that version
|
||||
if it is not already available.
|
||||
|
||||
These uv install methods are especially helpful for aider, because it
|
||||
has a large set of very specific dependencies.
|
||||
Since not all of aider's dependencies are available on all python versions,
|
||||
it requires python 3.9-3.12.
|
||||
|
||||
Most users don't want to worry about these details --
|
||||
they just want a quick way to install and run aider.
|
||||
|
||||
|
||||
## One-liners
|
||||
|
||||
Users can install aider with a shell one-liner, without even having python previously installed:
|
||||
|
||||
```bash
|
||||
curl -LsSf https://aider.chat/install.sh | sh
|
||||
```
|
||||
|
||||
This installs uv, then uses it to install python 3.12,
|
||||
install the `aider` command line tool
|
||||
and update the user's shell path.
|
||||
Under the hood, it is simply a copy of
|
||||
uv's own install script `https://astral.sh/uv/install.sh`
|
||||
with [one line added](https://github.com/Aider-AI/aider/blob/4251e976b3aa52c2a3af08da4b203d4d524c8e92/aider/website/install.sh#L1181), to install aider as a tool:
|
||||
|
||||
```
|
||||
ensure "${_install_dir}/uv" tool install --force --python python3.12 aider-chat@latest
|
||||
```
|
||||
|
||||
|
||||
## aider-install
|
||||
|
||||
The aider-install python package allows quick global installation of aider
|
||||
for users who already have python 3.8+ installed.
|
||||
It simply provides the `aider-install` command line program,
|
||||
which users just need to run once.
|
||||
|
||||
```bash
|
||||
pip install aider-install
|
||||
aider-install
|
||||
```
|
||||
|
||||
The `pip install aider-install` installs only two packages:
|
||||
aider-install and the [uv python package](https://pypi.org/project/uv/).
|
||||
This ensures that uv is available
|
||||
in the user's environment.
|
||||
Everything else is installed in a stand-alone environment created by uv.
|
||||
|
||||
When the user runs `aider-install`, it runs uv
|
||||
to install aider as a tool and update the user's shell path if needed:
|
||||
|
||||
```bash
|
||||
uv tool install --force --python python3.12 aider-chat
|
||||
uv tool update-shell
|
||||
```
|
||||
|
||||
|
||||
## Benefits
|
||||
|
||||
These uv install methods have been popular with users,
|
||||
providing a hassle free way to install aider and quickly get started.
|
||||
Installs are also extremely fast, much faster than pip or pipx installs
|
||||
even when uv is also installing python 3.12!
|
||||
|
||||
There are also a number of benefits from the perspective of the tool developer/publisher.
|
||||
Since providing these install methods, far fewer users report dependency problems and
|
||||
version conflicts as compared to users who `pip install aider-chat`.
|
||||
There is also less pressure to rapidly support the newest python versions,
|
||||
since aider always installs with python 3.12.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -44,7 +44,7 @@
|
||||
## Use gpt-3.5-turbo model for the main chat
|
||||
#35turbo: false
|
||||
|
||||
## Use deepseek/deepseek-coder model for the main chat
|
||||
## Use deepseek/deepseek-chat model for the main chat
|
||||
#deepseek: false
|
||||
|
||||
## Use o1-mini model for the main chat
|
||||
@@ -152,7 +152,7 @@
|
||||
###################
|
||||
# Repomap settings:
|
||||
|
||||
## Suggested number of tokens to use for repo map, use 0 to disable (default: 1024)
|
||||
## Suggested number of tokens to use for repo map, use 0 to disable
|
||||
#map-tokens: xxx
|
||||
|
||||
## Control how often the repo map is refreshed. Options: auto, always, files, manual (default: auto)
|
||||
@@ -410,6 +410,9 @@
|
||||
## Specify the encoding for input and output (default: utf-8)
|
||||
#encoding: utf-8
|
||||
|
||||
## Line endings to use when writing files (default: platform)
|
||||
#line-endings: platform
|
||||
|
||||
## Specify the config file (default: search for .aider.conf.yml in git root, cwd or home directory)
|
||||
#config: xxx
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
## Use gpt-3.5-turbo model for the main chat
|
||||
#AIDER_35TURBO=
|
||||
|
||||
## Use deepseek/deepseek-coder model for the main chat
|
||||
## Use deepseek/deepseek-chat model for the main chat
|
||||
#AIDER_DEEPSEEK=
|
||||
|
||||
## Use o1-mini model for the main chat
|
||||
@@ -141,7 +141,7 @@
|
||||
###################
|
||||
# Repomap settings:
|
||||
|
||||
## Suggested number of tokens to use for repo map, use 0 to disable (default: 1024)
|
||||
## Suggested number of tokens to use for repo map, use 0 to disable
|
||||
#AIDER_MAP_TOKENS=
|
||||
|
||||
## Control how often the repo map is refreshed. Options: auto, always, files, manual (default: auto)
|
||||
@@ -381,6 +381,9 @@
|
||||
## Specify the encoding for input and output (default: utf-8)
|
||||
#AIDER_ENCODING=utf-8
|
||||
|
||||
## Line endings to use when writing files (default: platform)
|
||||
#AIDER_LINE_ENDINGS=platform
|
||||
|
||||
## Specify the .env file to load (default: .env in git root)
|
||||
#AIDER_ENV_FILE=.env
|
||||
|
||||
|
||||
@@ -235,7 +235,7 @@ cog.out("```\n")
|
||||
edit_format: diff
|
||||
editor_edit_format: editor-diff
|
||||
editor_model_name: null
|
||||
examples_as_sys_msg: false
|
||||
examples_as_sys_msg: true
|
||||
extra_params: null
|
||||
lazy: true
|
||||
name: openai/gpt-4o
|
||||
@@ -251,7 +251,7 @@ cog.out("```\n")
|
||||
edit_format: diff
|
||||
editor_edit_format: null
|
||||
editor_model_name: null
|
||||
examples_as_sys_msg: false
|
||||
examples_as_sys_msg: true
|
||||
extra_params: null
|
||||
lazy: true
|
||||
name: openai/gpt-4o-2024-08-06
|
||||
@@ -267,7 +267,7 @@ cog.out("```\n")
|
||||
edit_format: diff
|
||||
editor_edit_format: null
|
||||
editor_model_name: null
|
||||
examples_as_sys_msg: false
|
||||
examples_as_sys_msg: true
|
||||
extra_params: null
|
||||
lazy: true
|
||||
name: gpt-4o-2024-08-06
|
||||
@@ -283,7 +283,7 @@ cog.out("```\n")
|
||||
edit_format: diff
|
||||
editor_edit_format: null
|
||||
editor_model_name: null
|
||||
examples_as_sys_msg: false
|
||||
examples_as_sys_msg: true
|
||||
extra_params: null
|
||||
lazy: true
|
||||
name: gpt-4o-2024-11-20
|
||||
@@ -299,7 +299,7 @@ cog.out("```\n")
|
||||
edit_format: diff
|
||||
editor_edit_format: null
|
||||
editor_model_name: null
|
||||
examples_as_sys_msg: false
|
||||
examples_as_sys_msg: true
|
||||
extra_params: null
|
||||
lazy: true
|
||||
name: openai/gpt-4o-2024-11-20
|
||||
@@ -315,7 +315,7 @@ cog.out("```\n")
|
||||
edit_format: diff
|
||||
editor_edit_format: editor-diff
|
||||
editor_model_name: null
|
||||
examples_as_sys_msg: false
|
||||
examples_as_sys_msg: true
|
||||
extra_params: null
|
||||
lazy: true
|
||||
name: gpt-4o
|
||||
@@ -1080,7 +1080,41 @@ cog.out("```\n")
|
||||
use_temperature: true
|
||||
weak_model_name: null
|
||||
- cache_control: false
|
||||
caches_by_default: false
|
||||
caches_by_default: true
|
||||
edit_format: diff
|
||||
editor_edit_format: editor-diff
|
||||
editor_model_name: openrouter/deepseek/deepseek-chat
|
||||
examples_as_sys_msg: true
|
||||
extra_params:
|
||||
max_tokens: 8192
|
||||
lazy: false
|
||||
name: openrouter/deepseek/deepseek-r1
|
||||
reminder: user
|
||||
send_undo_reply: false
|
||||
streaming: true
|
||||
use_repo_map: true
|
||||
use_system_prompt: true
|
||||
use_temperature: false
|
||||
weak_model_name: openrouter/deepseek/deepseek-chat
|
||||
- cache_control: false
|
||||
caches_by_default: true
|
||||
edit_format: diff
|
||||
editor_edit_format: editor-diff
|
||||
editor_model_name: deepseek/deepseek-chat
|
||||
examples_as_sys_msg: true
|
||||
extra_params:
|
||||
max_tokens: 8192
|
||||
lazy: false
|
||||
name: deepseek/deepseek-reasoner
|
||||
reminder: user
|
||||
send_undo_reply: false
|
||||
streaming: true
|
||||
use_repo_map: true
|
||||
use_system_prompt: true
|
||||
use_temperature: false
|
||||
weak_model_name: deepseek/deepseek-chat
|
||||
- cache_control: false
|
||||
caches_by_default: true
|
||||
edit_format: diff
|
||||
editor_edit_format: null
|
||||
editor_model_name: null
|
||||
@@ -1184,7 +1218,7 @@ cog.out("```\n")
|
||||
edit_format: diff
|
||||
editor_edit_format: editor-diff
|
||||
editor_model_name: null
|
||||
examples_as_sys_msg: false
|
||||
examples_as_sys_msg: true
|
||||
extra_params: null
|
||||
lazy: true
|
||||
name: openrouter/openai/gpt-4o
|
||||
|
||||
@@ -7,13 +7,15 @@ description: How to configure aider with a yaml config file.
|
||||
# YAML config file
|
||||
|
||||
Most of aider's options can be set in an `.aider.conf.yml` file.
|
||||
Aider will look for a this file in these locations and
|
||||
load whichever is found first.
|
||||
Aider will look for a this file in these locations:
|
||||
|
||||
- As specified with the `--config <filename>` parameter.
|
||||
- The current directory.
|
||||
- The root of your git repo.
|
||||
- Your home directory.
|
||||
- The root of your git repo.
|
||||
- The current directory.
|
||||
|
||||
If the files above exist, they will be loaded in that order. Files loaded last will take priority.
|
||||
|
||||
You can also specify the `--config <filename>` parameter, which will only load the one config file.
|
||||
|
||||
{% include keys.md %}
|
||||
|
||||
@@ -96,7 +98,7 @@ cog.outl("```")
|
||||
## Use gpt-3.5-turbo model for the main chat
|
||||
#35turbo: false
|
||||
|
||||
## Use deepseek/deepseek-coder model for the main chat
|
||||
## Use deepseek/deepseek-chat model for the main chat
|
||||
#deepseek: false
|
||||
|
||||
## Use o1-mini model for the main chat
|
||||
@@ -204,7 +206,7 @@ cog.outl("```")
|
||||
###################
|
||||
# Repomap settings:
|
||||
|
||||
## Suggested number of tokens to use for repo map, use 0 to disable (default: 1024)
|
||||
## Suggested number of tokens to use for repo map, use 0 to disable
|
||||
#map-tokens: xxx
|
||||
|
||||
## Control how often the repo map is refreshed. Options: auto, always, files, manual (default: auto)
|
||||
@@ -462,6 +464,9 @@ cog.outl("```")
|
||||
## Specify the encoding for input and output (default: utf-8)
|
||||
#encoding: utf-8
|
||||
|
||||
## Line endings to use when writing files (default: platform)
|
||||
#line-endings: platform
|
||||
|
||||
## Specify the config file (default: search for .aider.conf.yml in git root, cwd or home directory)
|
||||
#config: xxx
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ cog.outl("```")
|
||||
## Use gpt-3.5-turbo model for the main chat
|
||||
#AIDER_35TURBO=
|
||||
|
||||
## Use deepseek/deepseek-coder model for the main chat
|
||||
## Use deepseek/deepseek-chat model for the main chat
|
||||
#AIDER_DEEPSEEK=
|
||||
|
||||
## Use o1-mini model for the main chat
|
||||
@@ -181,7 +181,7 @@ cog.outl("```")
|
||||
###################
|
||||
# Repomap settings:
|
||||
|
||||
## Suggested number of tokens to use for repo map, use 0 to disable (default: 1024)
|
||||
## Suggested number of tokens to use for repo map, use 0 to disable
|
||||
#AIDER_MAP_TOKENS=
|
||||
|
||||
## Control how often the repo map is refreshed. Options: auto, always, files, manual (default: auto)
|
||||
@@ -421,6 +421,9 @@ cog.outl("```")
|
||||
## Specify the encoding for input and output (default: utf-8)
|
||||
#AIDER_ENCODING=utf-8
|
||||
|
||||
## Line endings to use when writing files (default: platform)
|
||||
#AIDER_LINE_ENDINGS=platform
|
||||
|
||||
## Specify the .env file to load (default: .env in git root)
|
||||
#AIDER_ENV_FILE=.env
|
||||
|
||||
|
||||
@@ -55,10 +55,11 @@ for alias, model in sorted(MODEL_ALIASES.items()):
|
||||
- `4`: gpt-4-0613
|
||||
- `4-turbo`: gpt-4-1106-preview
|
||||
- `4o`: gpt-4o
|
||||
- `deepseek`: deepseek/deepseek-coder
|
||||
- `deepseek`: deepseek/deepseek-chat
|
||||
- `flash`: gemini/gemini-2.0-flash-exp
|
||||
- `haiku`: claude-3-5-haiku-20241022
|
||||
- `opus`: claude-3-opus-20240229
|
||||
- `r1`: deepseek/deepseek-reasoner
|
||||
- `sonnet`: claude-3-5-sonnet-20241022
|
||||
<!--[[[end]]]-->
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ usage: aider [-h] [--model] [--opus] [--sonnet] [--haiku] [--4]
|
||||
[--show-prompts] [--voice-format] [--voice-language]
|
||||
[--voice-input-device] [--file] [--read] [--vim]
|
||||
[--chat-language] [--yes-always] [-v] [--load]
|
||||
[--encoding] [-c] [--env-file]
|
||||
[--encoding] [--line-endings] [-c] [--env-file]
|
||||
[--suggest-shell-commands | --no-suggest-shell-commands]
|
||||
[--fancy-input | --no-fancy-input]
|
||||
[--multiline | --no-multiline]
|
||||
@@ -136,7 +136,7 @@ Aliases:
|
||||
- `-3`
|
||||
|
||||
### `--deepseek`
|
||||
Use deepseek/deepseek-coder model for the main chat
|
||||
Use deepseek/deepseek-chat model for the main chat
|
||||
Environment variable: `AIDER_DEEPSEEK`
|
||||
|
||||
### `--o1-mini`
|
||||
@@ -275,7 +275,7 @@ Environment variable: `AIDER_CACHE_KEEPALIVE_PINGS`
|
||||
## Repomap settings:
|
||||
|
||||
### `--map-tokens VALUE`
|
||||
Suggested number of tokens to use for repo map, use 0 to disable (default: 1024)
|
||||
Suggested number of tokens to use for repo map, use 0 to disable
|
||||
Environment variable: `AIDER_MAP_TOKENS`
|
||||
|
||||
### `--map-refresh VALUE`
|
||||
@@ -705,6 +705,11 @@ Specify the encoding for input and output (default: utf-8)
|
||||
Default: utf-8
|
||||
Environment variable: `AIDER_ENCODING`
|
||||
|
||||
### `--line-endings VALUE`
|
||||
Line endings to use when writing files (default: platform)
|
||||
Default: platform
|
||||
Environment variable: `AIDER_LINE_ENDINGS`
|
||||
|
||||
### `--config CONFIG_FILE`
|
||||
Specify the config file (default: search for .aider.conf.yml in git root, cwd or home directory)
|
||||
Aliases:
|
||||
|
||||
@@ -141,6 +141,18 @@ When starting a fresh aider session, you can include recent git history in the c
|
||||
|
||||
Remember, the chat history already includes recent changes made during the current session, so this tip is most useful when starting a new aider session and you want to provide context about recent work.
|
||||
|
||||
You can also use aider to review PR branches:
|
||||
|
||||
```
|
||||
/run git diff one-branch..another-branch
|
||||
|
||||
...
|
||||
|
||||
Add 6.9k tokens of command output to the chat? (Y)es/(N)o [Yes]: Yes
|
||||
|
||||
/ask Are there any problems with the way this change works with the FooBar class?
|
||||
```
|
||||
|
||||
{: .tip }
|
||||
The `/git` command will not work for this purpose, as its output is not included in the chat.
|
||||
|
||||
@@ -237,11 +249,15 @@ tr:hover { background-color: #f5f5f5; }
|
||||
</style>
|
||||
<table>
|
||||
<tr><th>Model Name</th><th class='right'>Total Tokens</th><th class='right'>Percent</th></tr>
|
||||
<tr><td>claude-3-5-sonnet-20241022</td><td class='right'>1,951,105</td><td class='right'>99.0%</td></tr>
|
||||
<tr><td>claude-3-5-haiku-20241022</td><td class='right'>14,008</td><td class='right'>0.7%</td></tr>
|
||||
<tr><td>gpt-4o</td><td class='right'>4,273</td><td class='right'>0.2%</td></tr>
|
||||
<tr><td>openrouter/REDACTED</td><td class='right'>1,234</td><td class='right'>0.1%</td></tr>
|
||||
<tr><td>openai/gpt-4o-mini</td><td class='right'>141</td><td class='right'>0.0%</td></tr>
|
||||
<tr><td>deepseek/deepseek-chat</td><td class='right'>1,123,602</td><td class='right'>59.6%</td></tr>
|
||||
<tr><td>claude-3-5-sonnet-20241022</td><td class='right'>699,676</td><td class='right'>37.1%</td></tr>
|
||||
<tr><td>o1</td><td class='right'>25,121</td><td class='right'>1.3%</td></tr>
|
||||
<tr><td>claude-3-5-haiku-20241022</td><td class='right'>10,083</td><td class='right'>0.5%</td></tr>
|
||||
<tr><td>gemini/gemini-exp-1206</td><td class='right'>10,068</td><td class='right'>0.5%</td></tr>
|
||||
<tr><td>mistral/codestral-latest</td><td class='right'>8,137</td><td class='right'>0.4%</td></tr>
|
||||
<tr><td>deepseek/REDACTED</td><td class='right'>7,432</td><td class='right'>0.4%</td></tr>
|
||||
<tr><td>gpt-4o</td><td class='right'>1,775</td><td class='right'>0.1%</td></tr>
|
||||
<tr><td>o1-preview</td><td class='right'>175</td><td class='right'>0.0%</td></tr>
|
||||
</table>
|
||||
|
||||
{: .note :}
|
||||
|
||||
@@ -81,7 +81,7 @@ cog.out(get_supported_languages_md())
|
||||
| jsdoc | .jsdoc | | ✓ |
|
||||
| json | .json | | ✓ |
|
||||
| julia | .jl | | ✓ |
|
||||
| kotlin | .kt | | ✓ |
|
||||
| kotlin | .kt | ✓ | ✓ |
|
||||
| lua | .lua | | ✓ |
|
||||
| make | .mk | | ✓ |
|
||||
| objc | .m | | ✓ |
|
||||
|
||||
@@ -113,9 +113,8 @@ import subprocess
|
||||
import datetime
|
||||
|
||||
files = [
|
||||
'aider/website/docs/leaderboards/index.md',
|
||||
'aider/website/docs/leaderboards/edit.md',
|
||||
'aider/website/_data/edit_leaderboard.yml',
|
||||
'aider/website/_data/refactor_leaderboard.yml'
|
||||
]
|
||||
|
||||
def get_last_modified_date(file):
|
||||
@@ -129,6 +128,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.')}")
|
||||
]]]-->
|
||||
December 16, 2024.
|
||||
January 16, 2025.
|
||||
<!--[[[end]]]-->
|
||||
</p>
|
||||
|
||||
@@ -107,8 +107,7 @@ import datetime
|
||||
|
||||
files = [
|
||||
'aider/website/docs/leaderboards/index.md',
|
||||
'aider/website/_data/edit_leaderboard.yml',
|
||||
'aider/website/_data/refactor_leaderboard.yml'
|
||||
'aider/website/_data/polyglot_leaderboard.yml',
|
||||
]
|
||||
|
||||
def get_last_modified_date(file):
|
||||
@@ -122,6 +121,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.')}")
|
||||
]]]-->
|
||||
December 26, 2024.
|
||||
January 20, 2025.
|
||||
<!--[[[end]]]-->
|
||||
</p>
|
||||
|
||||
@@ -50,3 +50,29 @@ Therefore, results are available for fewer models.
|
||||
</script>
|
||||
|
||||
|
||||
<p class="post-date">
|
||||
By Paul Gauthier,
|
||||
last updated
|
||||
<!--[[[cog
|
||||
import subprocess
|
||||
import datetime
|
||||
|
||||
files = [
|
||||
'aider/website/docs/leaderboards/refactor.md',
|
||||
'aider/website/_data/refactor_leaderboard.yml',
|
||||
]
|
||||
|
||||
def get_last_modified_date(file):
|
||||
result = subprocess.run(['git', 'log', '-1', '--format=%ct', file], capture_output=True, text=True)
|
||||
if result.returncode == 0:
|
||||
timestamp = int(result.stdout.strip())
|
||||
return datetime.datetime.fromtimestamp(timestamp)
|
||||
return datetime.datetime.min
|
||||
|
||||
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.')}")
|
||||
]]]-->
|
||||
January 16, 2025.
|
||||
<!--[[[end]]]-->
|
||||
</p>
|
||||
|
||||
@@ -53,6 +53,12 @@ To use aider installed via `pipx` with AWS Bedrock, you must add the `boto3` dep
|
||||
pipx inject aider-chat boto3
|
||||
```
|
||||
|
||||
You must install `boto3` dependency to aider's virtual environment installed via one-liner or uv by running
|
||||
|
||||
```bash
|
||||
uv tool run --from aider-chat pip install boto3
|
||||
```
|
||||
|
||||
|
||||
## Running Aider with Bedrock
|
||||
|
||||
|
||||
@@ -65,14 +65,16 @@ cog.out(model_list)
|
||||
- claude-3-sonnet-20240229
|
||||
- codestral/codestral-2405
|
||||
- codestral/codestral-latest
|
||||
- deepseek-chat
|
||||
- deepseek-coder
|
||||
- deepseek/deepseek-chat
|
||||
- deepseek/deepseek-coder
|
||||
- eu.anthropic.claude-3-5-haiku-20241022-v1:0
|
||||
- eu.anthropic.claude-3-5-sonnet-20241022-v2:0
|
||||
- mistral/codestral-2405
|
||||
- mistral/codestral-latest
|
||||
- mistral/codestral-mamba-latest
|
||||
- mistral/mistral-large-2402
|
||||
- mistral/mistral-large-2407
|
||||
- mistral/mistral-large-2411
|
||||
- mistral/mistral-large-latest
|
||||
- mistral/mistral-medium
|
||||
- mistral/mistral-medium-2312
|
||||
@@ -87,6 +89,8 @@ cog.out(model_list)
|
||||
- mistral/open-mixtral-8x22b
|
||||
- mistral/open-mixtral-8x7b
|
||||
- mistral/pixtral-12b-2409
|
||||
- mistral/pixtral-large-2411
|
||||
- mistral/pixtral-large-latest
|
||||
- openrouter/anthropic/claude-3.5-sonnet
|
||||
- us.anthropic.claude-3-5-haiku-20241022-v1:0
|
||||
- us.anthropic.claude-3-5-sonnet-20241022-v2:0
|
||||
|
||||
@@ -62,6 +62,12 @@ Aider v0.50.2-dev
|
||||
Models: claude-3-5-sonnet-20240620 with ♾️ diff edit format
|
||||
```
|
||||
|
||||
## Try architect mode
|
||||
|
||||
Run aider with `--architect` or `/chat-mode architect` to enable [architect mode](../usage/modes.md#architect-mode-and-the-editor-model).
|
||||
This mode first proposes changes, then uses a separate model to handle the file edits.
|
||||
This two-step process often produces more reliable edits, especially with models that have trouble
|
||||
following edit format instructions.
|
||||
|
||||
## More help
|
||||
|
||||
|
||||
@@ -22,11 +22,11 @@ cog.out(get_help_md())
|
||||
|Command|Description|
|
||||
|:------|:----------|
|
||||
| **/add** | Add files to the chat so aider can edit them or review them in detail |
|
||||
| **/architect** | Enter architect mode to discuss high-level design and architecture |
|
||||
| **/ask** | Ask questions about the code base without editing any files |
|
||||
| **/architect** | Enter architect/editor mode using 2 different models. If no prompt provided, switches to architect/editor mode. |
|
||||
| **/ask** | Ask questions about the code base without editing any files. If no prompt provided, switches to ask mode. |
|
||||
| **/chat-mode** | Switch to a new chat mode |
|
||||
| **/clear** | Clear the chat history |
|
||||
| **/code** | Ask for changes to your code |
|
||||
| **/code** | Ask for changes to your code. If no prompt provided, switches to code mode. |
|
||||
| **/commit** | Commit edits to the repo made outside the chat (commit message optional) |
|
||||
| **/copy** | Copy the last assistant message to the clipboard |
|
||||
| **/copy-context** | Copy the current chat context as markdown, suitable to paste into a web UI |
|
||||
|
||||
@@ -29,6 +29,14 @@ with the `/chat-mode <mode>` command:
|
||||
/chat-mode help
|
||||
```
|
||||
|
||||
Or you can switch between coding modes using these commands without arguments:
|
||||
|
||||
```
|
||||
/code
|
||||
/architect
|
||||
/ask
|
||||
```
|
||||
|
||||
Or you can launch aider in one of the modes with the `--chat-mode <mode>` switch.
|
||||
There is also a special shortcut `--architect` to launch in `--chat-mode architect`.
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ title: Aider in your IDE
|
||||
#highlight_image: /assets/browser.jpg
|
||||
parent: Usage
|
||||
nav_order: 750
|
||||
description: Aider can run in your browser, not just on the command line.
|
||||
description: Aider can watch your files and respond to AI comments you add in your favorite IDE or text editor.
|
||||
---
|
||||
|
||||
# Aider in your IDE
|
||||
@@ -34,7 +34,7 @@ description: Aider can run in your browser, not just on the command line.
|
||||
|
||||
## AI comments
|
||||
|
||||
If you run aider with `--watch-files`, it will watch all files in your repo
|
||||
If you run aider with `--watch-files`, it will watch all files in your repo
|
||||
and look for any AI coding instructions you add using your favorite IDE or text editor.
|
||||
|
||||
Specifically, aider looks for one-liner comments (# ... or // ...) that either start or end with `AI`, `AI!` or `AI?` like these:
|
||||
@@ -52,14 +52,14 @@ Or in `//` comment languages...
|
||||
|
||||
Aider will take note of all the comments that start or end with `AI`.
|
||||
Comments that include `AI!` with an exclamation point or `AI?` with a question
|
||||
mark are special.
|
||||
They triggers aider to take action to collect *all* the AI comments and use them
|
||||
mark are special.
|
||||
They triggers aider to take action to collect *all* the AI comments and use them
|
||||
as your instructions.
|
||||
|
||||
- `AI!` triggers aider to make changes to your code.
|
||||
- `AI?` triggers aider to answer your question.
|
||||
|
||||
See the demo video above that shows aider working with AI comments in VSCode.
|
||||
See the demo video above that shows aider working with AI comments in VSCode.
|
||||
|
||||
|
||||
## Example
|
||||
@@ -88,8 +88,8 @@ Aider only watches for these types of **one-liner** comments:
|
||||
|
||||
```
|
||||
# Python and bash style
|
||||
// Javascript style
|
||||
-- SQL style
|
||||
// Javascript style
|
||||
-- SQL style
|
||||
```
|
||||
|
||||
Aider will look for those comment types in all files.
|
||||
@@ -102,7 +102,7 @@ This capability is quite flexible and powerful, and can be used in many ways.
|
||||
|
||||
### In-context instructions
|
||||
|
||||
You can add an AI comment in the function you want changed,
|
||||
You can add an AI comment in the function you want changed,
|
||||
explaining the change request in-context right where you want the changes.
|
||||
|
||||
```javascript
|
||||
@@ -129,15 +129,15 @@ Just use `AI!` last, to trigger aider.
|
||||
def factorial(n):
|
||||
if n < 0:
|
||||
return jsonify(error="Factorial is not defined for negative numbers"), 400
|
||||
|
||||
|
||||
# AI: Refactor this code...
|
||||
|
||||
|
||||
result = 1
|
||||
for i in range(1, n + 1):
|
||||
result *= i
|
||||
|
||||
|
||||
# ... into to a compute_factorial() function. AI!
|
||||
|
||||
|
||||
return jsonify(result=result)
|
||||
```
|
||||
|
||||
@@ -180,7 +180,7 @@ many of aider's more advanced features:
|
||||
- Use `/undo` to revert changes you don't like. Although you may also be able to use your IDE's undo function to step back in the file history.
|
||||
- Use [chat modes](https://aider.chat/docs/usage/modes.html) to ask questions or get help.
|
||||
- Manage the chat context with `/tokens`, `/clear`, `/drop`, `/reset`.
|
||||
Adding an AI comment will add the file to the chat.
|
||||
Adding an AI comment will add the file to the chat.
|
||||
Periodically, you may want remove extra context that is no longer needed.
|
||||
- [Fix lint and test errors](https://aider.chat/docs/usage/lint-test.html).
|
||||
- Run shell commands.
|
||||
@@ -194,14 +194,14 @@ comments with full sentences, proper capitalization, punctuation, etc.
|
||||
This was done to help explain how AI comments work, but is not needed in practice.
|
||||
|
||||
Most LLMs are perfectly capable of dealing with ambiguity and
|
||||
inferring implied intent.
|
||||
inferring implied intent.
|
||||
This often allows you to be quite lazy with your AI comments.
|
||||
In particular, you can start and end comments with lowercase `ai` and `ai!`,
|
||||
but you can also be much more terse with the request itself.
|
||||
Below are simpler versions of some of the examples given above.
|
||||
|
||||
When the context clearly implies the needed action, `ai!` might be all you
|
||||
need. For example, to implement a factorial function
|
||||
need. For example, to implement a factorial function
|
||||
in a program full of other math functions either of these
|
||||
approaches would probably work:
|
||||
|
||||
@@ -237,15 +237,15 @@ Similarly, this refactor probably could have been requested with fewer words, li
|
||||
def factorial(n):
|
||||
if n < 0:
|
||||
return jsonify(error="Factorial is not defined for negative numbers"), 400
|
||||
|
||||
|
||||
# ai refactor...
|
||||
|
||||
|
||||
result = 1
|
||||
for i in range(1, n + 1):
|
||||
result *= i
|
||||
|
||||
|
||||
# ... to compute_factorial() ai!
|
||||
|
||||
|
||||
return jsonify(result=result)
|
||||
```
|
||||
|
||||
@@ -289,7 +289,6 @@ todo_app.py:
|
||||
|
||||
#### Credits
|
||||
|
||||
*This feature was inspired by
|
||||
*This feature was inspired by
|
||||
the way [Override](https://github.com/oi-overide) watches for file changes
|
||||
to find prompts embedded within `//> a specific set of delimiters <//`.*
|
||||
|
||||
|
||||
@@ -32,9 +32,9 @@ cog.out(text)
|
||||
|
||||
Aider lets you pair program with LLMs,
|
||||
to edit code in your local git repository.
|
||||
Start a new project or work with an existing git repo.
|
||||
Aider works best with GPT-4o & Claude 3.5 Sonnet and can
|
||||
[connect to almost any LLM](https://aider.chat/docs/llms.html).
|
||||
Start a new project or work with an existing code base.
|
||||
Aider works best with Claude 3.5 Sonnet, DeepSeek V3, o1 & GPT-4o and can [connect to almost any LLM](https://aider.chat/docs/llms.html).
|
||||
|
||||
|
||||
<!--
|
||||
<p align="center">
|
||||
@@ -104,16 +104,17 @@ for more details.
|
||||
- Update docs.
|
||||
- Aider will edit your files to complete your request.
|
||||
- Aider [automatically git commits](https://aider.chat/docs/git.html) changes with a sensible commit message.
|
||||
- [Use aider inside your favorite editor or IDE](https://aider.chat/docs/usage/watch.html).
|
||||
- Aider works with [most popular languages](https://aider.chat/docs/languages.html): python, javascript, typescript, php, html, css, and more...
|
||||
- Aider works best with GPT-4o & Claude 3.5 Sonnet and can [connect to almost any LLM](https://aider.chat/docs/llms.html).
|
||||
- Aider can edit multiple files at once for complex requests.
|
||||
- Aider uses a [map of your entire git repo](https://aider.chat/docs/repomap.html), which helps it work well in larger codebases.
|
||||
- Edit files in your editor while chatting with aider,
|
||||
- Edit files in your editor or IDE while chatting with aider,
|
||||
and it will always use the latest version.
|
||||
Pair program with AI.
|
||||
- [Add images to the chat](https://aider.chat/docs/usage/images-urls.html) (GPT-4o, Claude 3.5 Sonnet, etc).
|
||||
- [Add URLs to the chat](https://aider.chat/docs/usage/images-urls.html) and aider will read their content.
|
||||
- [Code with your voice](https://aider.chat/docs/usage/voice.html).
|
||||
- Aider works best with Claude 3.5 Sonnet, DeepSeek V3, o1 & GPT-4o and can [connect to almost any LLM](https://aider.chat/docs/llms.html).
|
||||
|
||||
|
||||
## Top tier performance
|
||||
|
||||
@@ -11,6 +11,7 @@ RUN apt-get update && apt-get install -y \
|
||||
python3.11-venv \
|
||||
python3.11-dev \
|
||||
python3-pip \
|
||||
ca-certificates-java \
|
||||
openjdk-21-jdk \
|
||||
libtbb-dev \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
@@ -18,10 +19,18 @@ RUN apt-get update && apt-get install -y \
|
||||
# Make python3.11 the default python3
|
||||
RUN update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.11 1
|
||||
|
||||
# Install Go
|
||||
RUN curl -OL https://golang.org/dl/go1.21.5.linux-amd64.tar.gz && \
|
||||
tar -C /usr/local -xzf go1.21.5.linux-amd64.tar.gz && \
|
||||
rm go1.21.5.linux-amd64.tar.gz
|
||||
# Install Go with architecture detection
|
||||
RUN ARCH=$(uname -m) && \
|
||||
if [ "$ARCH" = "x86_64" ]; then \
|
||||
GOARCH="amd64"; \
|
||||
elif [ "$ARCH" = "aarch64" ]; then \
|
||||
GOARCH="arm64"; \
|
||||
else \
|
||||
false; \
|
||||
fi && \
|
||||
curl -L "https://golang.org/dl/go1.21.5.linux-$GOARCH.tar.gz" -o go.tar.gz && \
|
||||
tar -C /usr/local -xzf go.tar.gz && \
|
||||
rm go.tar.gz
|
||||
ENV PATH="/usr/local/go/bin:${PATH}"
|
||||
|
||||
# Install Rust
|
||||
|
||||
@@ -16,6 +16,7 @@ from types import SimpleNamespace
|
||||
from typing import List, Optional
|
||||
|
||||
import git
|
||||
import importlib_resources
|
||||
import lox
|
||||
import pandas as pd
|
||||
import prompts
|
||||
@@ -31,7 +32,7 @@ from aider.io import InputOutput
|
||||
|
||||
BENCHMARK_DNAME = Path(os.environ.get("AIDER_BENCHMARK_DIR", "tmp.benchmarks"))
|
||||
|
||||
EXERCISES_DIR_DEFAULT = "exercism-python"
|
||||
EXERCISES_DIR_DEFAULT = "polyglot-benchmark"
|
||||
|
||||
app = typer.Typer(add_completion=False, pretty_exceptions_enable=False)
|
||||
|
||||
@@ -176,11 +177,6 @@ def main(
|
||||
"--replay",
|
||||
help="Replay previous .aider.chat.history.md responses from previous benchmark run",
|
||||
),
|
||||
max_apply_update_errors: int = typer.Option(
|
||||
3,
|
||||
"--max-apply-update-errors",
|
||||
help="Maximum number of apply update errors before stopping the test",
|
||||
),
|
||||
keywords: str = typer.Option(
|
||||
None, "--keywords", "-k", help="Only run tests that contain keywords (comma sep)"
|
||||
),
|
||||
@@ -342,7 +338,6 @@ def main(
|
||||
verbose,
|
||||
commit_hash,
|
||||
replay,
|
||||
max_apply_update_errors,
|
||||
editor_model,
|
||||
editor_edit_format,
|
||||
num_ctx,
|
||||
@@ -367,7 +362,6 @@ def main(
|
||||
verbose,
|
||||
commit_hash,
|
||||
replay,
|
||||
max_apply_update_errors,
|
||||
editor_model,
|
||||
editor_edit_format,
|
||||
)
|
||||
@@ -645,7 +639,6 @@ def run_test_real(
|
||||
verbose,
|
||||
commit_hash,
|
||||
replay,
|
||||
max_apply_update_errors,
|
||||
editor_model,
|
||||
editor_edit_format,
|
||||
num_ctx=None,
|
||||
@@ -701,7 +694,7 @@ def run_test_real(
|
||||
ignore_files.update(example_files)
|
||||
|
||||
# Remove any ignore files from the solution set that LLM will edit
|
||||
solution_files.discard(ignore_files)
|
||||
solution_files.difference_update(ignore_files)
|
||||
|
||||
# Copy all solution files
|
||||
for file_path in solution_files:
|
||||
@@ -725,17 +718,6 @@ def run_test_real(
|
||||
else:
|
||||
print(f"Warning: Solution file not found: {src}")
|
||||
|
||||
# Copy all test files
|
||||
for file_path in test_files:
|
||||
src = testdir / Path(file_path)
|
||||
if src.exists():
|
||||
original_fname = original_dname / testdir.name / file_path
|
||||
if original_fname.exists():
|
||||
os.makedirs(src.parent, exist_ok=True)
|
||||
shutil.copy(original_fname, src)
|
||||
else:
|
||||
print(f"Warning: Test file not found: {src}")
|
||||
|
||||
file_list = " ".join(fname.name for fname in fnames)
|
||||
|
||||
instructions = ""
|
||||
@@ -756,6 +738,10 @@ def run_test_real(
|
||||
chat_history_file=history_fname,
|
||||
)
|
||||
|
||||
resource_metadata = importlib_resources.files("aider.resources").joinpath("model-metadata.json")
|
||||
model_metadata_files_loaded = models.register_litellm_models([resource_metadata])
|
||||
dump(model_metadata_files_loaded)
|
||||
|
||||
# weak_model_name = model_name
|
||||
weak_model_name = None
|
||||
|
||||
@@ -766,6 +752,8 @@ def run_test_real(
|
||||
editor_edit_format=editor_edit_format,
|
||||
)
|
||||
|
||||
dump(main_model.max_chat_history_tokens)
|
||||
|
||||
if num_ctx:
|
||||
if not main_model.extra_params:
|
||||
main_model.extra_params = {}
|
||||
@@ -792,8 +780,8 @@ def run_test_real(
|
||||
)
|
||||
dump(coder.ignore_mentions)
|
||||
|
||||
coder.max_apply_update_errors = max_apply_update_errors
|
||||
coder.show_announcements()
|
||||
coder.get_file_mentions = lambda x: set() # No loading of any other files
|
||||
|
||||
timeouts = 0
|
||||
|
||||
@@ -805,6 +793,7 @@ def run_test_real(
|
||||
test_outcomes = []
|
||||
for i in range(tries):
|
||||
start = time.time()
|
||||
|
||||
if no_aider:
|
||||
pass
|
||||
elif replay:
|
||||
@@ -818,6 +807,7 @@ def run_test_real(
|
||||
coder.apply_updates()
|
||||
else:
|
||||
response = coder.run(with_message=instructions, preproc=False)
|
||||
|
||||
dur += time.time() - start
|
||||
|
||||
if not no_aider:
|
||||
@@ -861,6 +851,40 @@ def run_test_real(
|
||||
instructions = errors
|
||||
instructions += prompts.test_failures.format(file_list=file_list)
|
||||
|
||||
# Clean up build directories after all attempts
|
||||
# Rust target/debug
|
||||
target_dir = testdir / "target" / "debug"
|
||||
if target_dir.exists():
|
||||
try:
|
||||
shutil.rmtree(target_dir)
|
||||
if verbose:
|
||||
print(f"Cleaned up Rust target/debug directory: {target_dir}")
|
||||
except (OSError, shutil.Error, PermissionError) as e:
|
||||
if verbose:
|
||||
print(f"Failed to clean up Rust target/debug directory: {e}")
|
||||
|
||||
# Java build directories
|
||||
java_build_dir = testdir / "build"
|
||||
if java_build_dir.exists():
|
||||
try:
|
||||
shutil.rmtree(java_build_dir)
|
||||
if verbose:
|
||||
print(f"Cleaned up Java build directory: {java_build_dir}")
|
||||
except (OSError, shutil.Error, PermissionError) as e:
|
||||
if verbose:
|
||||
print(f"Failed to clean up Java build directory: {e}")
|
||||
|
||||
# Node.js node_modules directories
|
||||
node_modules_dir = testdir / "node_modules"
|
||||
if node_modules_dir.exists():
|
||||
try:
|
||||
shutil.rmtree(node_modules_dir)
|
||||
if verbose:
|
||||
print(f"Cleaned up Node.js node_modules directory: {node_modules_dir}")
|
||||
except (OSError, shutil.Error, PermissionError) as e:
|
||||
if verbose:
|
||||
print(f"Failed to clean up Node.js node_modules directory: {e}")
|
||||
|
||||
results = dict(
|
||||
testdir=str(testdir),
|
||||
testcase=testdir.name,
|
||||
@@ -899,15 +923,6 @@ def run_test_real(
|
||||
def run_unit_tests(original_dname, testdir, history_fname, test_files):
|
||||
timeout = 60 * 3
|
||||
|
||||
# Remove @Disabled annotations from Java test files
|
||||
for file_path in test_files:
|
||||
if file_path.endswith(".java"):
|
||||
test_file = testdir / file_path
|
||||
if test_file.exists():
|
||||
content = test_file.read_text()
|
||||
content = re.sub(r"@Disabled\([^)]*\)\s*\n", "", content)
|
||||
test_file.write_text(content)
|
||||
|
||||
# Map of file extensions to test commands
|
||||
TEST_COMMANDS = {
|
||||
".py": ["pytest"],
|
||||
@@ -939,6 +954,15 @@ def run_unit_tests(original_dname, testdir, history_fname, test_files):
|
||||
os.makedirs(dst.parent, exist_ok=True)
|
||||
shutil.copy(src, dst)
|
||||
|
||||
# Remove @Disabled annotations from Java test files
|
||||
for file_path in test_files:
|
||||
if file_path.endswith(".java"):
|
||||
test_file = testdir / file_path
|
||||
if test_file.exists():
|
||||
content = test_file.read_text()
|
||||
content = re.sub(r"@Disabled\([^)]*\)\s*\n", "", content)
|
||||
test_file.write_text(content)
|
||||
|
||||
print(" ".join(command))
|
||||
|
||||
result = subprocess.run(
|
||||
|
||||
@@ -205,16 +205,18 @@ def analyze_exercise_solutions(dirs=None, topn=None, copy_hard_set=False):
|
||||
|
||||
# Distribution table of how many models solved each exercise
|
||||
print("\nDistribution of solutions:")
|
||||
print("Models Exercises Cumulative")
|
||||
print("-" * 35)
|
||||
print("Models Exercises Cumulative RevCumulative")
|
||||
print("-" * 50)
|
||||
counts = [0] * (total_models + 1)
|
||||
for ex, models in exercise_solutions.items():
|
||||
counts[len(models)] += 1
|
||||
|
||||
cumsum = 0
|
||||
revcumsum = sum(counts) # Start with total number of exercises
|
||||
for i, count in enumerate(counts):
|
||||
cumsum += count
|
||||
print(f"{i:>6d} {count:>9d} {cumsum:>10d}")
|
||||
print(f"{i:>6d} {count:>9d} {cumsum:>10d} {revcumsum:>12d}")
|
||||
revcumsum -= count # Decrement the reverse cumulative sum
|
||||
|
||||
# Count parse errors per exercise
|
||||
parse_error_counts = defaultdict(int)
|
||||
|
||||
@@ -19,15 +19,27 @@ git -C "$REPO_ROOT" ls-files --exclude-standard --others --ignored --directory >
|
||||
# Create remote directory if needed
|
||||
ssh "$DEST" "mkdir -p ~/aider"
|
||||
|
||||
# Sync the repository
|
||||
rsync -avz --delete \
|
||||
--exclude-from="$EXCLUDE_FILE" \
|
||||
"$REPO_ROOT/" \
|
||||
"$DEST:~/aider/"
|
||||
sync_repo() {
|
||||
# Sync the repository
|
||||
rsync -avz --delete \
|
||||
--exclude-from="$EXCLUDE_FILE" \
|
||||
"$REPO_ROOT/" \
|
||||
"$DEST:~/aider/" || true
|
||||
|
||||
rsync -a .env .gitignore "$DEST:~/aider/." || true
|
||||
|
||||
rsync -a .env .gitignore "$DEST:~/aider/."
|
||||
echo Done syncing, waiting.
|
||||
}
|
||||
|
||||
sync_repo
|
||||
|
||||
rsync -a ~/dotfiles/screenrc "$DEST:.screenrc"
|
||||
while true; do
|
||||
fswatch -o $REPO_ROOT | while read ; do
|
||||
sync_repo
|
||||
done
|
||||
done
|
||||
|
||||
|
||||
# Clean up
|
||||
rm "$EXCLUDE_FILE"
|
||||
|
||||
|
||||
@@ -1,23 +1,26 @@
|
||||
FROM python:3.10-slim AS base
|
||||
|
||||
# Install system dependencies
|
||||
RUN apt-get update && \
|
||||
apt-get install --no-install-recommends -y build-essential git libportaudio2 pandoc && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Create app user with UID 1000
|
||||
RUN useradd -m -u 1000 -s /bin/bash appuser
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Create virtual environment
|
||||
RUN python -m venv /venv
|
||||
ENV PATH="/venv/bin:$PATH"
|
||||
|
||||
# https://playwright.dev/python/docs/browsers
|
||||
ENV PLAYWRIGHT_BROWSERS_PATH=/pw-browsers
|
||||
# Playwright browser settings
|
||||
ENV PLAYWRIGHT_BROWSERS_PATH=/home/appuser/pw-browsers
|
||||
ENV PLAYWRIGHT_SKIP_BROWSER_GC=1
|
||||
|
||||
# Permission kludges to support `docker run --user xxx`
|
||||
RUN chmod a+rwx /venv /venv/bin /venv/include /venv/lib /venv/lib/python3.10/site-packages
|
||||
|
||||
RUN mkdir /.aider /.cache /pw-browsers
|
||||
RUN chmod a+rwx /.aider /.cache /pw-browsers
|
||||
# Create directories with proper permissions
|
||||
RUN mkdir -p /home/appuser/.aider /home/appuser/.cache /home/appuser/pw-browsers && \
|
||||
chown -R appuser:appuser /home/appuser /app /venv
|
||||
|
||||
# So git doesn't complain about unusual permissions
|
||||
RUN git config --system --add safe.directory /app
|
||||
@@ -28,14 +31,22 @@ FROM base AS aider-full
|
||||
ENV AIDER_DOCKER_IMAGE=paulgauthier/aider-full
|
||||
|
||||
COPY . /tmp/aider
|
||||
RUN /venv/bin/python -m pip install --upgrade --no-cache-dir pip \
|
||||
&& /venv/bin/python -m pip install --no-cache-dir /tmp/aider[help,browser,playwright] \
|
||||
--extra-index-url https://download.pytorch.org/whl/cpu \
|
||||
&& rm -rf /tmp/aider
|
||||
|
||||
# Install dependencies as root
|
||||
RUN /venv/bin/python -m pip install --upgrade --no-cache-dir pip && \
|
||||
/venv/bin/python -m pip install --no-cache-dir /tmp/aider[help,browser,playwright] \
|
||||
--extra-index-url https://download.pytorch.org/whl/cpu && \
|
||||
rm -rf /tmp/aider
|
||||
|
||||
# Install playwright browsers
|
||||
RUN /venv/bin/python -m playwright install --with-deps chromium
|
||||
|
||||
# Fix site-packages permissions
|
||||
RUN find /venv/lib/python3.10/site-packages \( -type d -exec chmod a+rwx {} + \) -o \( -type f -exec chmod a+rw {} + \)
|
||||
|
||||
# Switch to appuser
|
||||
USER appuser
|
||||
|
||||
ENTRYPOINT ["/venv/bin/aider"]
|
||||
|
||||
#########################
|
||||
@@ -44,12 +55,20 @@ FROM base AS aider
|
||||
ENV AIDER_DOCKER_IMAGE=paulgauthier/aider
|
||||
|
||||
COPY . /tmp/aider
|
||||
RUN /venv/bin/python -m pip install --upgrade --no-cache-dir pip \
|
||||
&& /venv/bin/python -m pip install --no-cache-dir /tmp/aider[playwright] \
|
||||
--extra-index-url https://download.pytorch.org/whl/cpu \
|
||||
&& rm -rf /tmp/aider
|
||||
|
||||
# Install dependencies as root
|
||||
RUN /venv/bin/python -m pip install --upgrade --no-cache-dir pip && \
|
||||
/venv/bin/python -m pip install --no-cache-dir /tmp/aider[playwright] \
|
||||
--extra-index-url https://download.pytorch.org/whl/cpu && \
|
||||
rm -rf /tmp/aider
|
||||
|
||||
# Install playwright browsers
|
||||
RUN /venv/bin/python -m playwright install --with-deps chromium
|
||||
|
||||
# Fix site-packages permissions
|
||||
RUN find /venv/lib/python3.10/site-packages \( -type d -exec chmod a+rwx {} + \) -o \( -type f -exec chmod a+rw {} + \)
|
||||
|
||||
# Switch to appuser
|
||||
USER appuser
|
||||
|
||||
ENTRYPOINT ["/venv/bin/aider"]
|
||||
|
||||
@@ -6,18 +6,18 @@
|
||||
#
|
||||
aiohappyeyeballs==2.4.4
|
||||
# via aiohttp
|
||||
aiohttp==3.11.10
|
||||
aiohttp==3.11.11
|
||||
# via litellm
|
||||
aiosignal==1.3.1
|
||||
aiosignal==1.3.2
|
||||
# via aiohttp
|
||||
annotated-types==0.7.0
|
||||
# via pydantic
|
||||
anyio==4.7.0
|
||||
anyio==4.8.0
|
||||
# via
|
||||
# httpx
|
||||
# openai
|
||||
# watchfiles
|
||||
attrs==24.2.0
|
||||
attrs==24.3.0
|
||||
# via
|
||||
# aiohttp
|
||||
# jsonschema
|
||||
@@ -28,7 +28,7 @@ backoff==2.2.1
|
||||
# posthog
|
||||
beautifulsoup4==4.12.3
|
||||
# via -r requirements/requirements.in
|
||||
certifi==2024.8.30
|
||||
certifi==2024.12.14
|
||||
# via
|
||||
# httpcore
|
||||
# httpx
|
||||
@@ -37,9 +37,9 @@ cffi==1.17.1
|
||||
# via
|
||||
# sounddevice
|
||||
# soundfile
|
||||
charset-normalizer==3.4.0
|
||||
charset-normalizer==3.4.1
|
||||
# via requests
|
||||
click==8.1.7
|
||||
click==8.1.8
|
||||
# via litellm
|
||||
configargparse==1.7
|
||||
# via -r requirements/requirements.in
|
||||
@@ -57,11 +57,11 @@ frozenlist==1.5.0
|
||||
# via
|
||||
# aiohttp
|
||||
# aiosignal
|
||||
fsspec==2024.10.0
|
||||
fsspec==2024.12.0
|
||||
# via huggingface-hub
|
||||
gitdb==4.0.11
|
||||
gitdb==4.0.12
|
||||
# via gitpython
|
||||
gitpython==3.1.43
|
||||
gitpython==3.1.44
|
||||
# via -r requirements/requirements.in
|
||||
grep-ast==0.4.1
|
||||
# via -r requirements/requirements.in
|
||||
@@ -73,7 +73,7 @@ httpx==0.27.2
|
||||
# via
|
||||
# litellm
|
||||
# openai
|
||||
huggingface-hub==0.26.5
|
||||
huggingface-hub==0.27.1
|
||||
# via tokenizers
|
||||
idna==3.10
|
||||
# via
|
||||
@@ -85,11 +85,11 @@ importlib-metadata==7.2.1
|
||||
# via
|
||||
# -r requirements/requirements.in
|
||||
# litellm
|
||||
importlib-resources==6.4.5
|
||||
importlib-resources==6.5.2
|
||||
# via -r requirements/requirements.in
|
||||
jinja2==3.1.4
|
||||
jinja2==3.1.5
|
||||
# via litellm
|
||||
jiter==0.8.0
|
||||
jiter==0.8.2
|
||||
# via openai
|
||||
json5==0.10.0
|
||||
# via -r requirements/requirements.in
|
||||
@@ -99,7 +99,7 @@ jsonschema==4.23.0
|
||||
# litellm
|
||||
jsonschema-specifications==2024.10.1
|
||||
# via jsonschema
|
||||
litellm==1.53.9
|
||||
litellm==1.58.2
|
||||
# via -r requirements/requirements.in
|
||||
markdown-it-py==3.0.0
|
||||
# via rich
|
||||
@@ -123,7 +123,8 @@ numpy==1.26.4
|
||||
# via
|
||||
# -r requirements/requirements.in
|
||||
# scipy
|
||||
openai==1.57.0
|
||||
# soundfile
|
||||
openai==1.59.7
|
||||
# via litellm
|
||||
packaging==24.2
|
||||
# via
|
||||
@@ -137,7 +138,7 @@ pexpect==4.9.0
|
||||
# via -r requirements/requirements.in
|
||||
pillow==10.4.0
|
||||
# via -r requirements/requirements.in
|
||||
posthog==3.7.4
|
||||
posthog==3.8.3
|
||||
# via -r requirements/requirements.in
|
||||
prompt-toolkit==3.0.48
|
||||
# via -r requirements/requirements.in
|
||||
@@ -145,7 +146,7 @@ propcache==0.2.1
|
||||
# via
|
||||
# aiohttp
|
||||
# yarl
|
||||
psutil==6.1.0
|
||||
psutil==6.1.1
|
||||
# via -r requirements/requirements.in
|
||||
ptyprocess==0.7.0
|
||||
# via pexpect
|
||||
@@ -153,19 +154,19 @@ pycodestyle==2.12.1
|
||||
# via flake8
|
||||
pycparser==2.22
|
||||
# via cffi
|
||||
pydantic==2.10.3
|
||||
pydantic==2.10.5
|
||||
# via
|
||||
# litellm
|
||||
# openai
|
||||
pydantic-core==2.27.1
|
||||
pydantic-core==2.27.2
|
||||
# via pydantic
|
||||
pydub==0.25.1
|
||||
# via -r requirements/requirements.in
|
||||
pyflakes==3.2.0
|
||||
# via flake8
|
||||
pygments==2.18.0
|
||||
pygments==2.19.1
|
||||
# via rich
|
||||
pypandoc==1.14
|
||||
pypandoc==1.15
|
||||
# via -r requirements/requirements.in
|
||||
pyperclip==1.9.0
|
||||
# via -r requirements/requirements.in
|
||||
@@ -177,7 +178,7 @@ pyyaml==6.0.2
|
||||
# via
|
||||
# -r requirements/requirements.in
|
||||
# huggingface-hub
|
||||
referencing==0.35.1
|
||||
referencing==0.36.0
|
||||
# via
|
||||
# jsonschema
|
||||
# jsonschema-specifications
|
||||
@@ -186,7 +187,6 @@ regex==2024.11.6
|
||||
requests==2.32.3
|
||||
# via
|
||||
# huggingface-hub
|
||||
# litellm
|
||||
# mixpanel
|
||||
# posthog
|
||||
# tiktoken
|
||||
@@ -203,7 +203,7 @@ six==1.17.0
|
||||
# mixpanel
|
||||
# posthog
|
||||
# python-dateutil
|
||||
smmap==5.0.1
|
||||
smmap==5.0.2
|
||||
# via gitdb
|
||||
sniffio==1.3.1
|
||||
# via
|
||||
@@ -212,7 +212,7 @@ sniffio==1.3.1
|
||||
# openai
|
||||
sounddevice==0.5.1
|
||||
# via -r requirements/requirements.in
|
||||
soundfile==0.12.1
|
||||
soundfile==0.13.0
|
||||
# via -r requirements/requirements.in
|
||||
soupsieve==2.6
|
||||
# via beautifulsoup4
|
||||
@@ -239,11 +239,12 @@ typing-extensions==4.12.2
|
||||
# openai
|
||||
# pydantic
|
||||
# pydantic-core
|
||||
urllib3==2.2.3
|
||||
# referencing
|
||||
urllib3==2.3.0
|
||||
# via
|
||||
# mixpanel
|
||||
# requests
|
||||
watchfiles==1.0.0
|
||||
watchfiles==1.0.4
|
||||
# via -r requirements/requirements.in
|
||||
wcwidth==0.2.13
|
||||
# via prompt-toolkit
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#
|
||||
altair==5.5.0
|
||||
# via streamlit
|
||||
attrs==24.2.0
|
||||
attrs==24.3.0
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
@@ -17,33 +17,33 @@ blinker==1.9.0
|
||||
# via streamlit
|
||||
cachetools==5.5.0
|
||||
# via streamlit
|
||||
certifi==2024.8.30
|
||||
certifi==2024.12.14
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# -c requirements/requirements-help.txt
|
||||
# requests
|
||||
charset-normalizer==3.4.0
|
||||
charset-normalizer==3.4.1
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# -c requirements/requirements-help.txt
|
||||
# requests
|
||||
click==8.1.7
|
||||
click==8.1.8
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# -c requirements/requirements-help.txt
|
||||
# streamlit
|
||||
gitdb==4.0.11
|
||||
gitdb==4.0.12
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# gitpython
|
||||
gitpython==3.1.43
|
||||
gitpython==3.1.44
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
@@ -55,7 +55,7 @@ idna==3.10
|
||||
# -c requirements/requirements-dev.txt
|
||||
# -c requirements/requirements-help.txt
|
||||
# requests
|
||||
jinja2==3.1.4
|
||||
jinja2==3.1.5
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
@@ -92,7 +92,7 @@ mdurl==0.1.2
|
||||
# -c requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# markdown-it-py
|
||||
narwhals==1.16.0
|
||||
narwhals==1.22.0
|
||||
# via altair
|
||||
numpy==1.26.4
|
||||
# via
|
||||
@@ -122,13 +122,13 @@ pillow==10.4.0
|
||||
# -c requirements/requirements-dev.txt
|
||||
# -c requirements/requirements-help.txt
|
||||
# streamlit
|
||||
protobuf==5.29.1
|
||||
protobuf==5.29.3
|
||||
# via streamlit
|
||||
pyarrow==18.1.0
|
||||
pyarrow==19.0.0
|
||||
# via streamlit
|
||||
pydeck==0.9.1
|
||||
# via streamlit
|
||||
pygments==2.18.0
|
||||
pygments==2.19.1
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
@@ -144,7 +144,7 @@ pytz==2024.2
|
||||
# via
|
||||
# -c requirements/requirements-dev.txt
|
||||
# pandas
|
||||
referencing==0.35.1
|
||||
referencing==0.36.0
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
@@ -175,14 +175,14 @@ six==1.17.0
|
||||
# -c requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# python-dateutil
|
||||
smmap==5.0.1
|
||||
smmap==5.0.2
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# gitdb
|
||||
streamlit==1.40.2
|
||||
streamlit==1.41.1
|
||||
# via -r requirements/requirements-browser.in
|
||||
tenacity==8.5.0
|
||||
tenacity==9.0.0
|
||||
# via
|
||||
# -c requirements/requirements-help.txt
|
||||
# streamlit
|
||||
@@ -197,12 +197,13 @@ typing-extensions==4.12.2
|
||||
# -c requirements/requirements-dev.txt
|
||||
# -c requirements/requirements-help.txt
|
||||
# altair
|
||||
# referencing
|
||||
# streamlit
|
||||
tzdata==2024.2
|
||||
# via
|
||||
# -c requirements/requirements-dev.txt
|
||||
# pandas
|
||||
urllib3==2.2.3
|
||||
urllib3==2.3.0
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
|
||||
@@ -10,19 +10,19 @@ babel==2.16.0
|
||||
# via sphinx
|
||||
build==1.2.2.post1
|
||||
# via pip-tools
|
||||
certifi==2024.8.30
|
||||
certifi==2024.12.14
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# requests
|
||||
cfgv==3.4.0
|
||||
# via pre-commit
|
||||
charset-normalizer==3.4.0
|
||||
charset-normalizer==3.4.1
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# requests
|
||||
click==8.1.7
|
||||
click==8.1.8
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
@@ -51,9 +51,9 @@ filelock==3.16.1
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# virtualenv
|
||||
fonttools==4.55.2
|
||||
fonttools==4.55.3
|
||||
# via matplotlib
|
||||
identify==2.6.3
|
||||
identify==2.6.5
|
||||
# via pre-commit
|
||||
idna==3.10
|
||||
# via
|
||||
@@ -66,12 +66,12 @@ imgcat==0.6.0
|
||||
# via -r requirements/requirements-dev.in
|
||||
iniconfig==2.0.0
|
||||
# via pytest
|
||||
jinja2==3.1.4
|
||||
jinja2==3.1.5
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# sphinx
|
||||
kiwisolver==1.4.7
|
||||
kiwisolver==1.4.8
|
||||
# via matplotlib
|
||||
lox==0.12.0
|
||||
# via -r requirements/requirements-dev.in
|
||||
@@ -85,7 +85,7 @@ markupsafe==3.0.2
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# jinja2
|
||||
matplotlib==3.9.3
|
||||
matplotlib==3.10.0
|
||||
# via -r requirements/requirements-dev.in
|
||||
mdurl==0.1.2
|
||||
# via
|
||||
@@ -132,13 +132,13 @@ ppft==1.7.6.9
|
||||
# via pathos
|
||||
pre-commit==4.0.1
|
||||
# via -r requirements/requirements-dev.in
|
||||
pygments==2.18.0
|
||||
pygments==2.19.1
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# rich
|
||||
# sphinx
|
||||
pyparsing==3.2.0
|
||||
pyparsing==3.2.1
|
||||
# via matplotlib
|
||||
pyproject-hooks==1.2.0
|
||||
# via
|
||||
@@ -213,12 +213,12 @@ typing-extensions==4.12.2
|
||||
# typer
|
||||
tzdata==2024.2
|
||||
# via pandas
|
||||
urllib3==2.2.3
|
||||
urllib3==2.3.0
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# requests
|
||||
virtualenv==20.28.0
|
||||
virtualenv==20.29.0
|
||||
# via pre-commit
|
||||
wheel==0.45.1
|
||||
# via pip-tools
|
||||
@@ -229,5 +229,5 @@ pip==24.3.1
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# pip-tools
|
||||
setuptools==75.6.0
|
||||
setuptools==75.8.0
|
||||
# via pip-tools
|
||||
|
||||
@@ -9,13 +9,13 @@ aiohappyeyeballs==2.4.4
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# aiohttp
|
||||
aiohttp==3.11.10
|
||||
aiohttp==3.11.11
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# huggingface-hub
|
||||
# llama-index-core
|
||||
aiosignal==1.3.1
|
||||
aiosignal==1.3.2
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
@@ -25,17 +25,17 @@ annotated-types==0.7.0
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# pydantic
|
||||
anyio==4.7.0
|
||||
anyio==4.8.0
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# httpx
|
||||
attrs==24.2.0
|
||||
attrs==24.3.0
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# aiohttp
|
||||
certifi==2024.8.30
|
||||
certifi==2024.12.14
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
@@ -43,13 +43,13 @@ certifi==2024.8.30
|
||||
# httpcore
|
||||
# httpx
|
||||
# requests
|
||||
charset-normalizer==3.4.0
|
||||
charset-normalizer==3.4.1
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# requests
|
||||
click==8.1.7
|
||||
click==8.1.8
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
@@ -77,7 +77,7 @@ frozenlist==1.5.0
|
||||
# -c requirements.txt
|
||||
# aiohttp
|
||||
# aiosignal
|
||||
fsspec==2024.10.0
|
||||
fsspec==2024.12.0
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
@@ -103,7 +103,7 @@ httpx==0.27.2
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# llama-index-core
|
||||
huggingface-hub[inference]==0.26.5
|
||||
huggingface-hub[inference]==0.27.1
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
@@ -120,7 +120,7 @@ idna==3.10
|
||||
# httpx
|
||||
# requests
|
||||
# yarl
|
||||
jinja2==3.1.4
|
||||
jinja2==3.1.5
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
@@ -130,11 +130,11 @@ joblib==1.4.2
|
||||
# via
|
||||
# nltk
|
||||
# scikit-learn
|
||||
llama-index-core==0.12.0
|
||||
llama-index-core==0.12.11
|
||||
# via
|
||||
# -r requirements/requirements-help.in
|
||||
# llama-index-embeddings-huggingface
|
||||
llama-index-embeddings-huggingface==0.4.0
|
||||
llama-index-embeddings-huggingface==0.5.0
|
||||
# via -r requirements/requirements-help.in
|
||||
markupsafe==3.0.2
|
||||
# via
|
||||
@@ -142,7 +142,7 @@ markupsafe==3.0.2
|
||||
# -c requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# jinja2
|
||||
marshmallow==3.23.1
|
||||
marshmallow==3.25.1
|
||||
# via dataclasses-json
|
||||
mpmath==1.3.0
|
||||
# via sympy
|
||||
@@ -194,12 +194,12 @@ propcache==0.2.1
|
||||
# -c requirements.txt
|
||||
# aiohttp
|
||||
# yarl
|
||||
pydantic==2.10.3
|
||||
pydantic==2.10.5
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# llama-index-core
|
||||
pydantic-core==2.27.1
|
||||
pydantic-core==2.27.2
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
@@ -228,9 +228,9 @@ requests==2.32.3
|
||||
# llama-index-core
|
||||
# tiktoken
|
||||
# transformers
|
||||
safetensors==0.4.5
|
||||
safetensors==0.5.2
|
||||
# via transformers
|
||||
scikit-learn==1.5.2
|
||||
scikit-learn==1.6.1
|
||||
# via sentence-transformers
|
||||
scipy==1.13.1
|
||||
# via
|
||||
@@ -246,13 +246,13 @@ sniffio==1.3.1
|
||||
# -c requirements.txt
|
||||
# anyio
|
||||
# httpx
|
||||
sqlalchemy[asyncio]==2.0.36
|
||||
sqlalchemy[asyncio]==2.0.37
|
||||
# via
|
||||
# llama-index-core
|
||||
# sqlalchemy
|
||||
sympy==1.13.3
|
||||
# via torch
|
||||
tenacity==8.5.0
|
||||
tenacity==9.0.0
|
||||
# via llama-index-core
|
||||
threadpoolctl==3.5.0
|
||||
# via scikit-learn
|
||||
@@ -296,13 +296,13 @@ typing-inspect==0.9.0
|
||||
# via
|
||||
# dataclasses-json
|
||||
# llama-index-core
|
||||
urllib3==2.2.3
|
||||
urllib3==2.3.0
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# requests
|
||||
wrapt==1.17.0
|
||||
wrapt==1.17.2
|
||||
# via
|
||||
# deprecated
|
||||
# llama-index-core
|
||||
|
||||
@@ -8,9 +8,13 @@ Do NOT add duplicate entries for changes that have existing history entries.
|
||||
|
||||
End each bullet with a period.
|
||||
|
||||
If the change was made by someone other than Paul Gauthier note it at the end of the bullet point as ", by XXX."
|
||||
|
||||
Be sure to attribute changes to the proper .x version.
|
||||
Changes in the .x-dev version should be listed under a "### main branch" heading
|
||||
|
||||
Start a new "### main branch" section at the top of the file if needed.
|
||||
|
||||
Also, add this as the last bullet under the "### main branch" section:
|
||||
{aider_line}
|
||||
""" # noqa
|
||||
|
||||
@@ -18,7 +18,10 @@ def collect_model_stats(n_lines=1000):
|
||||
if event["event"] == "message_send":
|
||||
properties = event["properties"]
|
||||
main_model = properties.get("main_model")
|
||||
|
||||
total_tokens = properties.get("total_tokens", 0)
|
||||
if main_model == "deepseek/deepseek-coder":
|
||||
main_model = "deepseek/deepseek-chat"
|
||||
if main_model:
|
||||
model_stats[main_model] += total_tokens
|
||||
except json.JSONDecodeError:
|
||||
|
||||
@@ -27,6 +27,8 @@ cog $ARG \
|
||||
aider/website/docs/config/adv-model-settings.md \
|
||||
aider/website/docs/config/model-aliases.md \
|
||||
aider/website/docs/leaderboards/index.md \
|
||||
aider/website/docs/leaderboards/edit.md \
|
||||
aider/website/docs/leaderboards/refactor.md \
|
||||
aider/website/docs/llms/other.md \
|
||||
aider/website/docs/more/infinite-output.md \
|
||||
aider/website/docs/legal/privacy.md
|
||||
|
||||
@@ -24,6 +24,7 @@ def run_git_log():
|
||||
"git",
|
||||
"log",
|
||||
"-p",
|
||||
"--pretty=full",
|
||||
f"v{base_ver}..HEAD",
|
||||
"--",
|
||||
"aider/",
|
||||
|
||||
@@ -1721,3 +1721,33 @@ class TestCommands(TestCase):
|
||||
|
||||
del coder
|
||||
del commands
|
||||
|
||||
def test_cmd_load_with_switch_coder(self):
|
||||
with GitTemporaryDirectory() as repo_dir:
|
||||
io = InputOutput(pretty=False, fancy_input=False, yes=True)
|
||||
coder = Coder.create(self.GPT35, None, io)
|
||||
commands = Commands(io, coder)
|
||||
|
||||
# Create a temporary file with commands
|
||||
commands_file = Path(repo_dir) / "test_commands.txt"
|
||||
commands_file.write_text("/ask Tell me about the code\n/model gpt-4\n")
|
||||
|
||||
# Mock run to raise SwitchCoder for /ask and /model
|
||||
def mock_run(cmd):
|
||||
if cmd.startswith(("/ask", "/model")):
|
||||
raise SwitchCoder()
|
||||
return None
|
||||
|
||||
with mock.patch.object(commands, "run", side_effect=mock_run):
|
||||
# Capture tool_error output
|
||||
with mock.patch.object(io, "tool_error") as mock_tool_error:
|
||||
commands.cmd_load(str(commands_file))
|
||||
|
||||
# Check that appropriate error messages were shown
|
||||
mock_tool_error.assert_any_call(
|
||||
"Command '/ask Tell me about the code' is only supported in interactive"
|
||||
" mode, skipping."
|
||||
)
|
||||
mock_tool_error.assert_any_call(
|
||||
"Command '/model gpt-4' is only supported in interactive mode, skipping."
|
||||
)
|
||||
|
||||
@@ -12,11 +12,35 @@ from aider.utils import ChdirTemporaryDirectory
|
||||
|
||||
|
||||
class TestInputOutput(unittest.TestCase):
|
||||
def test_line_endings_validation(self):
|
||||
# Test valid line endings
|
||||
for ending in ["platform", "lf", "crlf"]:
|
||||
io = InputOutput(line_endings=ending)
|
||||
self.assertEqual(
|
||||
io.newline, None if ending == "platform" else "\n" if ending == "lf" else "\r\n"
|
||||
)
|
||||
|
||||
# Test invalid line endings
|
||||
with self.assertRaises(ValueError) as cm:
|
||||
io = InputOutput(line_endings="invalid")
|
||||
self.assertIn("Invalid line_endings value: invalid", str(cm.exception))
|
||||
# Check each valid option is in the error message
|
||||
self.assertIn("platform", str(cm.exception))
|
||||
self.assertIn("crlf", str(cm.exception))
|
||||
self.assertIn("lf", str(cm.exception))
|
||||
|
||||
def test_no_color_environment_variable(self):
|
||||
with patch.dict(os.environ, {"NO_COLOR": "1"}):
|
||||
io = InputOutput(fancy_input=False)
|
||||
self.assertFalse(io.pretty)
|
||||
|
||||
def test_dumb_terminal(self):
|
||||
with patch.dict(os.environ, {"TERM": "dumb"}):
|
||||
io = InputOutput(fancy_input=True)
|
||||
self.assertTrue(io.is_dumb_terminal)
|
||||
self.assertFalse(io.pretty)
|
||||
self.assertIsNone(io.prompt_session)
|
||||
|
||||
def test_autocompleter_get_command_completions(self):
|
||||
# Step 3: Mock the commands object
|
||||
commands = MagicMock()
|
||||
@@ -278,6 +302,29 @@ class TestInputOutputMultilineMode(unittest.TestCase):
|
||||
self.io.toggle_multiline_mode()
|
||||
self.assertFalse(self.io.multiline_mode)
|
||||
|
||||
def test_tool_message_unicode_fallback(self):
|
||||
"""Test that Unicode messages are properly converted to ASCII with replacement"""
|
||||
io = InputOutput(pretty=False, fancy_input=False)
|
||||
|
||||
# Create a message with invalid Unicode that can't be encoded in UTF-8
|
||||
# Using a surrogate pair that's invalid in UTF-8
|
||||
invalid_unicode = "Hello \ud800World"
|
||||
|
||||
# Mock console.print to capture the output
|
||||
with patch.object(io.console, "print") as mock_print:
|
||||
# First call will raise UnicodeEncodeError
|
||||
mock_print.side_effect = [UnicodeEncodeError("utf-8", "", 0, 1, "invalid"), None]
|
||||
|
||||
io._tool_message(invalid_unicode)
|
||||
|
||||
# Verify that the message was converted to ASCII with replacement
|
||||
self.assertEqual(mock_print.call_count, 2)
|
||||
args, kwargs = mock_print.call_args
|
||||
converted_message = args[0]
|
||||
|
||||
# The invalid Unicode should be replaced with '?'
|
||||
self.assertEqual(converted_message, "Hello ?World")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
@@ -30,7 +30,7 @@ class TestLinter(unittest.TestCase):
|
||||
def test_run_cmd(self, mock_popen):
|
||||
mock_process = MagicMock()
|
||||
mock_process.returncode = 0
|
||||
mock_process.communicate.return_value = ("", None)
|
||||
mock_process.stdout.read.side_effect = ("", None)
|
||||
mock_popen.return_value = mock_process
|
||||
|
||||
result = self.linter.run_cmd("test_cmd", "test_file.py", "code")
|
||||
@@ -40,7 +40,7 @@ class TestLinter(unittest.TestCase):
|
||||
def test_run_cmd_with_errors(self, mock_popen):
|
||||
mock_process = MagicMock()
|
||||
mock_process.returncode = 1
|
||||
mock_process.communicate.return_value = ("Error message", None)
|
||||
mock_process.stdout.read.side_effect = ("Error message", None)
|
||||
mock_popen.return_value = mock_process
|
||||
|
||||
result = self.linter.run_cmd("test_cmd", "test_file.py", "code")
|
||||
|
||||
@@ -132,6 +132,31 @@ class TestModels(unittest.TestCase):
|
||||
self.assertEqual(model.name, "github/o1-preview")
|
||||
self.assertEqual(model.use_temperature, False)
|
||||
|
||||
def test_get_repo_map_tokens(self):
|
||||
# Test default case (no max_input_tokens in info)
|
||||
model = Model("gpt-4")
|
||||
model.info = {}
|
||||
self.assertEqual(model.get_repo_map_tokens(), 1024)
|
||||
|
||||
# Test minimum boundary (max_input_tokens < 8192)
|
||||
model.info = {"max_input_tokens": 4096}
|
||||
self.assertEqual(model.get_repo_map_tokens(), 1024)
|
||||
|
||||
# Test middle range (max_input_tokens = 16384)
|
||||
model.info = {"max_input_tokens": 16384}
|
||||
self.assertEqual(model.get_repo_map_tokens(), 2048)
|
||||
|
||||
# Test maximum boundary (max_input_tokens > 32768)
|
||||
model.info = {"max_input_tokens": 65536}
|
||||
self.assertEqual(model.get_repo_map_tokens(), 4096)
|
||||
|
||||
# Test exact boundary values
|
||||
model.info = {"max_input_tokens": 8192}
|
||||
self.assertEqual(model.get_repo_map_tokens(), 1024)
|
||||
|
||||
model.info = {"max_input_tokens": 32768}
|
||||
self.assertEqual(model.get_repo_map_tokens(), 4096)
|
||||
|
||||
def test_aider_extra_model_settings(self):
|
||||
import tempfile
|
||||
|
||||
|
||||
@@ -290,6 +290,7 @@ class TestRepoMapAllLanguages(unittest.TestCase):
|
||||
"elixir": ("ex", "Greeter"),
|
||||
"java": ("java", "Greeting"),
|
||||
"javascript": ("js", "Person"),
|
||||
"kotlin": ("kt", "Greeting"),
|
||||
"ocaml": ("ml", "Greeter"),
|
||||
"php": ("php", "greet"),
|
||||
"python": ("py", "Person"),
|
||||
|
||||
16
tests/fixtures/languages/kotlin/test.kt
vendored
Normal file
16
tests/fixtures/languages/kotlin/test.kt
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
interface Greeting {
|
||||
fun greet(name: String): String
|
||||
}
|
||||
|
||||
class Test : Greeting {
|
||||
private val prefix = "Hello"
|
||||
|
||||
override fun greet(name: String): String {
|
||||
return "$prefix, $name!"
|
||||
}
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val greeter = Test()
|
||||
println(greeter.greet("World"))
|
||||
}
|
||||
Reference in New Issue
Block a user